the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 4854 lines 129 kB view raw
1#include "stdafx.h" 2#include "System.h" 3#include "BasicTypeContainers.h" 4#include "File.h" 5#include "ProgressListener.h" 6#include "net.minecraft.h" 7#include "net.minecraft.world.h" 8#include "net.minecraft.world.entity.ai.village.h" 9#include "net.minecraft.world.entity.h" 10#include "net.minecraft.world.entity.global.h" 11#include "net.minecraft.world.entity.player.h" 12#include "net.minecraft.world.level.biome.h" 13#include "net.minecraft.world.level.chunk.h" 14#include "net.minecraft.world.level.dimension.h" 15#include "net.minecraft.world.level.tile.h" 16#include "net.minecraft.world.level.tile.entity.h" 17#include "net.minecraft.world.level.h" 18#include "net.minecraft.world.level.levelgen.h" 19#include "net.minecraft.world.level.storage.h" 20#include "net.minecraft.world.level.pathfinder.h" 21#include "net.minecraft.world.level.redstone.h" 22#include "net.minecraft.world.scores.h" 23#include "net.minecraft.world.phys.h" 24#include "Explosion.h" 25#include "LevelListener.h" 26#include "Level.h" 27#include "ThreadName.h" 28#include "WeighedRandom.h" 29 30#include "ConsoleSaveFile.h" 31#include <xuiapp.h> 32#include "..\Minecraft.Client\Minecraft.h" 33#include "..\Minecraft.Client\LevelRenderer.h" 34#include "SoundTypes.h" 35#include "SparseLightStorage.h" 36#include "..\Minecraft.Client\Textures.h" 37#include "..\Minecraft.Client\TexturePackRepository.h" 38#include "..\Minecraft.Client\DLCTexturePack.h" 39#include "..\Minecraft.Client\Common\DLC\DLCPack.h" 40#include "..\Minecraft.Client\PS3\PS3Extras\ShutdownManager.h" 41#include "..\Minecraft.Client\MinecraftServer.h" 42 43 44DWORD Level::tlsIdx = TlsAlloc(); 45DWORD Level::tlsIdxLightCache = TlsAlloc(); 46 47// 4J : WESTY : Added for time played stats. 48#include "net.minecraft.stats.h" 49 50// 4J - Caching of lighting data added. This is implemented as a 16x16x16 cache of ints (ie 16K storage in total). The index of the element to be used in the array is determined by the lower 51// four bits of each x/y/z position, and the upper 7/4/7 bits of the x/y/z positions are stored within the element itself along with the cached values etc. The cache can be enabled per thread by 52// calling enableLightingCache, otherwise standard non-cached accesses are performed. General method for using caching if enabled on a thread is: 53// (1) Call initCache, this invalidates any previous data in the cache 54// (2) Use setBrightnessCached, getBrightnessCached, getEmissionCached, getBlockingCached methods to get and set data 55// (3) Call flushCache, which writes through any dirty values in cache 56 57#ifdef _LARGE_WORLDS 58// Packing for cache entries in large worlds is as follows ( 64 bits per entry) 59// Add the extra x and z data into the top 32 bits, to keep all the masks and code for everything else the same 60// xxxxxxxxxxxxxxxxzzzzzzzzzzzzzzzzWEBLllllbbbbeeeexxxxxxyyyyzzzzzz 61// 62// xxxxxx - middle 6 bits of x position 63// yyyy - top 4 bits of y position 64// zzzzzz - middle 6 bits of z position 65// eeee - light emission 66// bbbb - light blocking 67// llll - light level 68// L - light value valid 69// B - blocking value valid 70// E - emission value valid 71// W - lighting value requires write 72// xxxxxxxxxxxxxxxx - top 16 bits of x position 73// zzzzzzzzzzzzzzzz - top 16 bits of z position 74#else 75// Packing for cache entries is as follows ( 32 bits per entry) 76// WEBLllllbbbbeeeexxxxxxyyyyzzzzzz 77// 78// xxxxxx - top 6 bits of x position 79// yyyy - top 4 bits of y position 80// zzzzzz - top 6 bits of z position 81// eeee - light emission 82// bbbb - light blocking 83// llll - light level 84// L - light value valid 85// B - blocking value valid 86// E - emission value valid 87// W - lighting value requires write 88#endif 89 90 91void Level::enableLightingCache() 92{ 93 // Allocate 16K (needs 32K for large worlds) for a 16x16x16x4 byte cache of results, plus 128K required for toCheck array. Rounding up to 256 to keep as multiple of alignement - aligning to 128K boundary for possible cache locking. 94 void *cache = (unsigned char *)XPhysicalAlloc(256 * 1024, MAXULONG_PTR, 128 * 1024, PAGE_READWRITE | MEM_LARGE_PAGES); 95 TlsSetValue(tlsIdxLightCache,cache); 96} 97 98void Level::destroyLightingCache() 99{ 100 lightCache_t *cache = (lightCache_t *)TlsGetValue(tlsIdxLightCache); 101 XPhysicalFree(cache); 102} 103 104inline int GetIndex(int x, int y, int z) 105{ 106 return ( ( x & 15 ) << 8 ) | ( ( y & 15 ) << 4 ) | ( z & 15 ); 107} 108 109void Level::initCachePartial(lightCache_t *cache, int xc, int yc, int zc) 110{ 111 cachewritten = false; 112 if( cache == NULL ) return; 113 114 int idx; 115 if( !(yc & 0xffffff00) ) 116 { 117 idx = GetIndex(xc, yc, zc); 118 cache[idx] = 0; 119 idx = GetIndex(xc - 1, yc, zc); 120 cache[idx] = 0; 121 idx = GetIndex(xc + 1, yc, zc); 122 cache[idx] = 0; 123 idx = GetIndex(xc, yc, zc - 1); 124 cache[idx] = 0; 125 idx = GetIndex(xc, yc, zc + 1); 126 cache[idx] = 0; 127 } 128 if( !((yc-1) & 0xffffff00) ) 129 { 130 idx = GetIndex(xc, yc - 1, zc); 131 cache[idx] = 0; 132 } 133 if( !((yc+1) & 0xffffff00) ) 134 { 135 idx = GetIndex(xc, yc + 1, zc); 136 cache[idx] = 0; 137 } 138} 139 140void Level::initCacheComplete(lightCache_t *cache, int xc, int yc, int zc) 141{ 142 lightCache_t old[7]; 143 if( !(yc & 0xffffff00) ) 144 { 145 old[0] = cache[GetIndex(xc, yc, zc)]; 146 old[1] = cache[GetIndex(xc - 1, yc, zc)]; 147 old[2] = cache[GetIndex(xc + 1, yc, zc)]; 148 old[5] = cache[GetIndex(xc, yc, zc - 1)]; 149 old[6] = cache[GetIndex(xc, yc, zc + 1)]; 150 } 151 if( !((yc-1) & 0xffffff00) ) 152 { 153 old[3] = cache[GetIndex(xc, yc - 1, zc)]; 154 } 155 if( !((yc+1) & 0xffffff00) ) 156 { 157 old[4] = cache[GetIndex(xc, yc + 1, zc)]; 158 } 159 160 XMemSet128(cache,0,16*16*16*sizeof(lightCache_t)); 161 162 if( !(yc & 0xffffff00) ) 163 { 164 cache[GetIndex(xc, yc, zc)] = old[0]; 165 cache[GetIndex(xc - 1, yc, zc)] = old[1]; 166 cache[GetIndex(xc + 1, yc, zc)] = old[2]; 167 cache[GetIndex(xc, yc, zc - 1)] = old[5]; 168 cache[GetIndex(xc, yc, zc + 1)] = old[6]; 169 } 170 if( !((yc-1) & 0xffffff00) ) 171 { 172 cache[GetIndex(xc, yc - 1, zc)] = old[3]; 173 } 174 if( !((yc+1) & 0xffffff00) ) 175 { 176 cache[GetIndex(xc, yc + 1, zc)] = old[4]; 177 } 178} 179 180// Set a brightness value, going through the cache if enabled for this thread 181void inline Level::setBrightnessCached(lightCache_t *cache, __uint64 *cacheUse, LightLayer::variety layer, int x, int y, int z, int brightness) 182{ 183 if( cache == NULL ) 184 { 185 setBrightness(layer, x, y, z, brightness, true); 186 return; 187 } 188 if( y & 0xffffff00 ) return; // Eliminate -ve ys and values > 255 189 190 int idx = ( ( x & 15 ) << 8 ) | 191 ( ( y & 15 ) << 4 ) | 192 ( z & 15 ); 193 lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | 194 ( ( y & 0x0f0 ) << 2 ) | 195 ( ( z & 0x3f0 ) >> 4 ); 196#ifdef _LARGE_WORLDS 197 // Add in the higher bits for x and z 198 posbits |= ( ( ((__uint64)x) & 0x3FFFC00L) << 38) | 199 ( ( ((__uint64)z) & 0x3FFFC00L) << 22); 200#endif 201 202 lightCache_t cacheValue = cache[idx]; 203 204 // If this cache entry doesn't refer to the same thing... 205 if( ( cacheValue & POSITION_MASK ) != posbits ) 206 { 207 /// and it has been written to... 208 if( cacheValue & LIGHTING_WRITEBACK ) 209 { 210 // Then we need to flush 211 int val = ( cacheValue >> LIGHTING_SHIFT ) & 15; 212 int xx = ( (cacheValue >> 6 ) & 0x3f0 ) | ( x & 15 ); 213#ifdef _LARGE_WORLDS 214 xx |= ( (cacheValue >> 38) & 0x3FFFC00); 215 xx = ( xx << 6 ) >> 6; // sign extend 216#else 217 xx = ( xx << 22 ) >> 22; // sign extend 218#endif 219 int yy = ( (cacheValue >> 2 ) & 0x0f0 ) | ( y & 15 ); 220 int zz = ( (cacheValue << 4 ) & 0x3f0 ) | ( z & 15 ); 221#ifdef _LARGE_WORLDS 222 zz |= ( (cacheValue >> 22) & 0x3FFFC00); 223 zz = ( zz << 6 ) >> 6; // sign extend 224#else 225 zz = ( zz << 22 ) >> 22; // sign extend 226#endif 227 setBrightness(layer, xx, yy, zz, val, true); 228 } 229 cacheValue = posbits; 230 } 231 232 // Just written to it, so value is valid & requires writing back 233 cacheValue &= ~(15 << LIGHTING_SHIFT ); 234 cacheValue |= brightness << LIGHTING_SHIFT; 235 cacheValue |= ( LIGHTING_WRITEBACK | LIGHTING_VALID ); 236 237 // cacheUse has a single bit for each x, y and z to say whether anything with that x, y or z has been written to 238 (*cacheUse) |= ( ( 1LL << ( x & 15 ) ) | ( 0x10000LL << ( y & 15 ) ) | ( 0x100000000LL << ( z & 15 ) ) ); 239 240 cache[idx] = cacheValue; 241} 242 243// Get a brightness value, going through the cache if enabled for this thread 244inline int Level::getBrightnessCached(lightCache_t *cache, LightLayer::variety layer, int x, int y, int z) 245{ 246 if( cache == NULL ) return getBrightness(layer, x, y, z); 247 if( y & 0xffffff00 ) return getBrightness(layer, x, y, z); // Fall back on original method for out-of-bounds y 248 249 int idx = ( ( x & 15 ) << 8 ) | 250 ( ( y & 15 ) << 4 ) | 251 ( z & 15 ); 252 lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | 253 ( ( y & 0x0f0 ) << 2 ) | 254 ( ( z & 0x3f0 ) >> 4 ); 255#ifdef _LARGE_WORLDS 256 // Add in the higher bits for x and z 257 posbits |= ( ( ((__uint64)x) & 0x3FFFC00L) << 38) | 258 ( ( ((__uint64)z) & 0x3FFFC00L) << 22); 259#endif 260 261 lightCache_t cacheValue = cache[idx]; 262 263 if( ( cacheValue & POSITION_MASK ) != posbits ) 264 { 265 // Position differs - need to evict this cache entry 266 if( cacheValue & LIGHTING_WRITEBACK ) 267 { 268 // Then we need to flush 269 int val = ( cacheValue >> LIGHTING_SHIFT ) & 15; 270 int xx = ( (cacheValue >> 6 ) & 0x3f0 ) | ( x & 15 ); 271#ifdef _LARGE_WORLDS 272 xx |= ( (cacheValue >> 38) & 0x3FFFC00); 273 xx = ( xx << 6 ) >> 6; // sign extend 274#else 275 xx = ( xx << 22 ) >> 22; // sign extend 276#endif 277 int yy = ( (cacheValue >> 2 ) & 0x0f0 ) | ( y & 15 ); 278 int zz = ( (cacheValue << 4 ) & 0x3f0 ) | ( z & 15 ); 279#ifdef _LARGE_WORLDS 280 zz |= ( (cacheValue >> 22) & 0x3FFFC00); 281 zz = ( zz << 6 ) >> 6; // sign extend 282#else 283 zz = ( zz << 22 ) >> 22; // sign extend 284#endif 285 setBrightness(layer, xx, yy, zz, val, true); 286 } 287 cacheValue = posbits | LIGHTING_VALID; 288 int val = getBrightness(layer, x, y, z); 289 cacheValue |= val << LIGHTING_SHIFT; 290 } 291 else 292 { 293 // The position matches - will incurr a read miss if the lighting value isn't valid 294 if( ( cacheValue & LIGHTING_VALID ) == 0 ) 295 { 296 int val = getBrightness(layer, x, y, z); 297 cacheValue |= val << LIGHTING_SHIFT; 298 cacheValue |= LIGHTING_VALID; 299 } 300 else 301 { 302 // All valid - just return value 303 return ( cacheValue >> LIGHTING_SHIFT ) & 15; 304 } 305 } 306 307 cache[idx] = cacheValue; 308 return ( cacheValue >> LIGHTING_SHIFT ) & 15; 309} 310 311// Get a block emission value, going through the cache if enabled for this thread 312inline int Level::getEmissionCached(lightCache_t *cache, int ct, int x, int y, int z) 313{ 314 if( cache == NULL ) return Tile::lightEmission[ct]; 315 316 int idx = ( ( x & 15 ) << 8 ) | 317 ( ( y & 15 ) << 4 ) | 318 ( z & 15 ); 319 lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | 320 ( ( y & 0x0f0 ) << 2 ) | 321 ( ( z & 0x3f0 ) >> 4 ); 322#ifdef _LARGE_WORLDS 323 // Add in the higher bits for x and z 324 posbits |= ( ( ((__uint64)x) & 0x3FFFC00) << 38) | 325 ( ( ((__uint64)z) & 0x3FFFC00) << 22); 326#endif 327 328 lightCache_t cacheValue = cache[idx]; 329 330 if( ( cacheValue & POSITION_MASK ) != posbits ) 331 { 332 // Position differs - need to evict this cache entry 333 if( cacheValue & LIGHTING_WRITEBACK ) 334 { 335 // Then we need to flush 336 int val = ( cacheValue >> LIGHTING_SHIFT ) & 15; 337 int xx = ( (cacheValue >> 6 ) & 0x3f0 ) | ( x & 15 ); 338#ifdef _LARGE_WORLDS 339 xx |= ( (cacheValue >> 38) & 0x3FFFC00); 340 xx = ( xx << 6 ) >> 6; // sign extend 341#else 342 xx = ( xx << 22 ) >> 22; // sign extend 343#endif 344 int yy = ( (cacheValue >> 2 ) & 0x0f0 ) | ( y & 15 ); 345 int zz = ( (cacheValue << 4 ) & 0x3f0 ) | ( z & 15 ); 346#ifdef _LARGE_WORLDS 347 zz |= ( (cacheValue >> 22) & 0x3FFFC00); 348 zz = ( zz << 6 ) >> 6; // sign extend 349#else 350 zz = ( zz << 22 ) >> 22; // sign extend 351#endif 352 setBrightness(LightLayer::Block, xx, yy, zz, val, true); 353 } 354 355 // Update both emission & blocking values whilst we are here 356 cacheValue = posbits | EMISSION_VALID | BLOCKING_VALID; 357 int t = getTile(x,y,z); 358 cacheValue |= ( Tile::lightEmission[t] & 15 ) << EMISSION_SHIFT; 359 cacheValue |= ( Tile::lightBlock[t] & 15 ) << BLOCKING_SHIFT; 360 } 361 else 362 { 363 // The position matches - will incurr a read miss if the lighting value isn't valid 364 if( ( cacheValue & EMISSION_VALID ) == 0 ) 365 { 366 // Update both emission & blocking values whilst we are here 367 cacheValue |= EMISSION_VALID | BLOCKING_VALID; 368 int t = getTile(x,y,z); 369 cacheValue |= ( Tile::lightEmission[t] & 15 ) << EMISSION_SHIFT; 370 cacheValue |= ( Tile::lightBlock[t] & 15 ) << BLOCKING_SHIFT; 371 } 372 else 373 { 374 // All valid - just return value 375 return ( cacheValue >> EMISSION_SHIFT ) & 15; 376 } 377 } 378 cache[idx] = cacheValue; 379 return ( cacheValue >> EMISSION_SHIFT ) & 15; 380} 381 382// Get a tile light blocking value, going through cache if enabled for this thread 383inline int Level::getBlockingCached(lightCache_t *cache, LightLayer::variety layer, int *ct, int x, int y, int z) 384{ 385 if( cache == NULL ) 386 { 387 int t = getTile(x,y,z); 388 if(ct) *ct = t; 389 return Tile::lightBlock[t]; 390 } 391 392 int idx = ( ( x & 15 ) << 8 ) | 393 ( ( y & 15 ) << 4 ) | 394 ( z & 15 ); 395 lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | 396 ( ( y & 0x0f0 ) << 2 ) | 397 ( ( z & 0x3f0 ) >> 4 ); 398#ifdef _LARGE_WORLDS 399 // Add in the higher bits for x and z 400 posbits |= ( ( ((__uint64)x) & 0x3FFFC00L) << 38) | 401 ( ( ((__uint64)z) & 0x3FFFC00L) << 22); 402#endif 403 404 lightCache_t cacheValue = cache[idx]; 405 406 if( ( cacheValue & POSITION_MASK ) != posbits ) 407 { 408 // Position differs - need to evict this cache entry 409 if( cacheValue & LIGHTING_WRITEBACK ) 410 { 411 // Then we need to flush 412 int val = ( cacheValue >> LIGHTING_SHIFT ) & 15; 413 int xx = ( (cacheValue >> 6 ) & 0x3f0 ) | ( x & 15 ); 414#ifdef _LARGE_WORLDS 415 xx |= ( (cacheValue >> 38) & 0x3FFFC00); 416 xx = ( xx << 6 ) >> 6; // sign extend 417#else 418 xx = ( xx << 22 ) >> 22; // sign extend 419#endif 420 int yy = ( (cacheValue >> 2 ) & 0x0f0 ) | ( y & 15 ); 421 int zz = ( (cacheValue << 4 ) & 0x3f0 ) | ( z & 15 ); 422#ifdef _LARGE_WORLDS 423 zz |= ( (cacheValue >> 22) & 0x3FFFC00); 424 zz = ( zz << 6 ) >> 6; // sign extend 425#else 426 zz = ( zz << 22 ) >> 22; // sign extend 427#endif 428 setBrightness(layer, xx, yy, zz, val, true); 429 } 430 431 // Update both emission & blocking values whilst we are here 432 cacheValue = posbits | EMISSION_VALID | BLOCKING_VALID; 433 int t = getTile(x,y,z); 434 cacheValue |= ( Tile::lightEmission[t] & 15 ) << EMISSION_SHIFT; 435 cacheValue |= ( Tile::lightBlock[t] & 15 ) << BLOCKING_SHIFT; 436 } 437 else 438 { 439 // The position matches - will incurr a read miss if the lighting value isn't valid 440 if( ( cacheValue & EMISSION_VALID ) == 0 ) 441 { 442 // Update both emission & blocking values whilst we are here 443 cacheValue |= EMISSION_VALID | BLOCKING_VALID; 444 int t = getTile(x,y,z); 445 cacheValue |= ( Tile::lightEmission[t] & 15 ) << EMISSION_SHIFT; 446 cacheValue |= ( Tile::lightBlock[t] & 15 ) << BLOCKING_SHIFT; 447 } 448 else 449 { 450 // All valid - just return value 451 return ( cacheValue >> BLOCKING_SHIFT ) & 15; 452 } 453 } 454 455 cache[idx] = cacheValue; 456 return ( cacheValue >> BLOCKING_SHIFT ) & 15; 457} 458 459// Write back any dirty entries in the lighting cache. Also calls the setTilesDirty method on the region which has been updated during this lighting update, since 460// this hasn't been updated (for client threads) for each individual lighting update as would have been the case with the non-cached lighting. There's two reasons for this 461// (1) it's more efficient, since we aren't doing so many individual calls to the level listener to let the renderer know what has been updated 462// (2) it lets the lighting actually complete before we get any visual representation of the update, otherwise we end up seeing some strange partial updates 463void Level::flushCache(lightCache_t *cache, __uint64 cacheUse, LightLayer::variety layer) 464{ 465 // cacheUse has a single bit for each x, y and z to say whether anything with that x, y or z has been written to 466 if( cacheUse == 0 ) return; 467 if( cache ) 468 { 469 lightCache_t *pcache = cache; 470 for( int x = 0; x < 16; x++ ) 471 { 472 if( ( cacheUse & ( 1LL << x ) ) == 0 ) 473 { 474 pcache += 16 * 16; 475 continue; 476 } 477 for( int y = 0; y < 16; y++ ) 478 { 479 if( ( cacheUse & ( 0x10000LL << y ) ) == 0 ) 480 { 481 pcache += 16; 482 continue; 483 } 484 for( int z = 0; z < 16; z++ ) 485 { 486 if( ( cacheUse & ( 0x100000000LL << z ) ) == 0 ) 487 { 488 pcache++; 489 continue; 490 } 491 lightCache_t cacheValue = *pcache++; 492 if( cacheValue & LIGHTING_WRITEBACK ) 493 { 494 int val = ( cacheValue >> LIGHTING_SHIFT ) & 15; 495 int xx = ( (cacheValue >> 6 ) & 0x3f0 ) | ( x & 15 ); 496#ifdef _LARGE_WORLDS 497 xx |= ( (cacheValue >> 38) & 0x3FFFC00); 498 xx = ( xx << 6 ) >> 6; // sign extend 499#else 500 xx = ( xx << 22 ) >> 22; // sign extend 501#endif 502 int yy = ( (cacheValue >> 2 ) & 0x0f0 ) | ( y & 15 ); 503 int zz = ( (cacheValue << 4 ) & 0x3f0 ) | ( z & 15 ); 504#ifdef _LARGE_WORLDS 505 zz |= ( (cacheValue >> 22) & 0x3FFFC00); 506 zz = ( zz << 6 ) >> 6; // sign extend 507#else 508 zz = ( zz << 22 ) >> 22; // sign extend 509#endif 510 setBrightness(layer, xx, yy, zz, val, true); 511 } 512 } 513 } 514 } 515 } 516 // For client side (which has the renderer attached) we haven't been updating with each individual update, but have been gathering them up. 517 // Let the renderer know now the region that has been updated. 518 if( isClientSide && cachewritten) 519 { 520 setTilesDirty(cacheminx, cacheminy, cacheminz,cachemaxx,cachemaxy,cachemaxz); 521 } 522} 523 524// 4J - added following 2 functions to move instaBuild flag from being a class member, to TLS 525bool Level::getInstaTick() 526{ 527 return ((size_t)TlsGetValue(tlsIdx)) != 0; 528} 529 530void Level::setInstaTick(bool enable) 531{ 532 void *value = 0; 533 if( enable ) value = (void *)1; 534 TlsSetValue(tlsIdx,value); 535} 536 537// 4J - added 538bool Level::hasEntitiesToRemove() 539{ 540 return !entitiesToRemove.empty(); 541} 542 543void Level::_init() 544{ 545 cloudColor = 0xffffff; 546 547 skyDarken = 0; 548 549 randValue = (new Random())->nextInt(); 550 551 addend = 1013904223; 552 553 oRainLevel = rainLevel = 0.0f; 554 555 oThunderLevel = thunderLevel = 0.0f; 556 557 skyFlashTime = 0; 558 559 difficulty = 0; 560 561 random = new Random(); 562 isNew = false; 563 564 dimension = NULL; 565 566 chunkSource = NULL; 567 568 levelStorage = nullptr; 569 570 levelData = NULL; 571 572 isFindingSpawn = false; 573 574 savedDataStorage = NULL; 575 576 spawnEnemies = true; 577 578 spawnFriendlies = true; 579 580 delayUntilNextMoodSound = random->nextInt(20 * 60 * 10); 581 582 isClientSide = false; 583 584 InitializeCriticalSection(&m_entitiesCS); 585 InitializeCriticalSection(&m_tileEntityListCS); 586 587 updatingTileEntities = false; 588 589 villageSiege = new VillageSiege(this); 590 scoreboard = new Scoreboard(); 591 592 toCheckLevel = new int[ 32 * 32 * 32]; // 4J - brought forward from 1.8.2 593 InitializeCriticalSectionAndSpinCount(&m_checkLightCS, 5120); // 4J - added for 1.8.2 lighting 594 595 // 4J Added 596 m_bDisableAddNewTileEntities = false; 597 m_iHighestY=-1000; 598 m_unsavedChunkCount = 0; 599} 600 601// 4J - brought forward from 1.8.2 602Biome *Level::getBiome(int x, int z) 603{ 604 if (hasChunkAt(x, 0, z)) 605 { 606 LevelChunk *lc = getChunkAt(x, z); 607 if (lc != NULL) 608 { 609 // Water chunks at the edge of the world return NULL for their biome as they can't store it, so should fall back on the normal method below 610 Biome *biome = lc->getBiome(x & 0xf, z & 0xf, dimension->biomeSource); 611 if( biome ) return biome; 612 } 613 } 614 return dimension->biomeSource->getBiome(x, z); 615} 616 617BiomeSource *Level::getBiomeSource() 618{ 619 return dimension->biomeSource; 620} 621 622Level::Level(shared_ptr<LevelStorage> levelStorage, const wstring& name, Dimension *dimension, LevelSettings *levelSettings, bool doCreateChunkSource) 623 : seaLevel(constSeaLevel) 624{ 625 _init(); 626 this->levelStorage = levelStorage;//shared_ptr<LevelStorage>(levelStorage); 627 this->dimension = dimension; 628 levelData = new LevelData(levelSettings, name); 629 if( !this->levelData->useNewSeaLevel() ) seaLevel = Level::genDepth / 2; // 4J added - sea level is one unit lower since 1.8.2, maintain older height for old levels 630 savedDataStorage = new SavedDataStorage(levelStorage.get()); 631 632 shared_ptr<Villages> savedVillages = dynamic_pointer_cast<Villages>(savedDataStorage->get(typeid(Villages), Villages::VILLAGE_FILE_ID)); 633 if (savedVillages == NULL) 634 { 635 villages = shared_ptr<Villages>(new Villages(this)); 636 savedDataStorage->set(Villages::VILLAGE_FILE_ID, villages); 637 } 638 else 639 { 640 villages = savedVillages; 641 villages->setLevel(this); 642 } 643 644 dimension->init(this); 645 chunkSource = NULL; // 4J - added flag so chunk source can be called from derived class instead 646 647 updateSkyBrightness(); 648 prepareWeather(); 649} 650 651Level::Level(shared_ptr<LevelStorage>levelStorage, const wstring& levelName, LevelSettings *levelSettings) 652 : seaLevel( constSeaLevel ) 653{ 654 _init(levelStorage, levelName, levelSettings, NULL, true); 655} 656 657 658Level::Level(shared_ptr<LevelStorage>levelStorage, const wstring& levelName, LevelSettings *levelSettings, Dimension *fixedDimension, bool doCreateChunkSource) 659 : seaLevel( constSeaLevel ) 660{ 661 _init( levelStorage, levelName, levelSettings, fixedDimension, doCreateChunkSource ); 662} 663 664void Level::_init(shared_ptr<LevelStorage>levelStorage, const wstring& levelName, LevelSettings *levelSettings, Dimension *fixedDimension, bool doCreateChunkSource) 665{ 666 _init(); 667 this->levelStorage = levelStorage;//shared_ptr<LevelStorage>(levelStorage); 668 savedDataStorage = new SavedDataStorage(levelStorage.get()); 669 670 shared_ptr<Villages> savedVillages = dynamic_pointer_cast<Villages>(savedDataStorage->get(typeid(Villages), Villages::VILLAGE_FILE_ID)); 671 if (savedVillages == NULL) 672 { 673 villages = shared_ptr<Villages>(new Villages(this)); 674 savedDataStorage->set(Villages::VILLAGE_FILE_ID, villages); 675 } 676 else 677 { 678 villages = savedVillages; 679 villages->setLevel(this); 680 } 681 682 levelData = levelStorage->prepareLevel(); 683 isNew = levelData == NULL; 684 685 if (fixedDimension != NULL) 686 { 687 dimension = fixedDimension; 688 } 689 // 4J Remove TU9 as getDimensions was never accurate. This path was never used anyway as we always set fixedDimension 690 //else if (levelData != NULL && levelData->getDimension() != 0) 691 //{ 692 // dimension = Dimension::getNew(levelData->getDimension()); 693 //} 694 else 695 { 696 dimension = Dimension::getNew(0); 697 } 698 699 if (levelData == NULL) 700 { 701 levelData = new LevelData(levelSettings, levelName); 702 } 703 else 704 { 705 levelData->setLevelName(levelName); 706 } 707 if( !this->levelData->useNewSeaLevel() ) seaLevel = Level::genDepth / 2; // 4J added - sea level is one unit lower since 1.8.2, maintain older height for old levels 708 709 ((Dimension *) dimension)->init( this ); 710 711 chunkSource = doCreateChunkSource ? createChunkSource() : NULL; // 4J - added flag so chunk source can be called from derived class instead 712 713 // 4J Stu- Moved to derived classes 714 //if (!levelData->isInitialized()) 715 //{ 716 // initializeLevel(levelSettings); 717 // levelData->setInitialized(true); 718 //} 719 720 updateSkyBrightness(); 721 prepareWeather(); 722 723} 724 725Level::~Level() 726{ 727 delete random; 728 delete dimension; 729 delete chunkSource; 730 delete levelData; 731 delete toCheckLevel; 732 delete scoreboard; 733 delete villageSiege; 734 735 if( !isClientSide ) 736 { 737 NotGateTile::removeLevelReferences(this); // 4J added 738 } 739 740 DeleteCriticalSection(&m_checkLightCS); 741 742 // 4J-PB - savedDataStorage is shared between overworld and nether levels in the server, so it will already have been deleted on the first level delete 743 if(savedDataStorage!=NULL) delete savedDataStorage; 744 745 DeleteCriticalSection(&m_entitiesCS); 746 DeleteCriticalSection(&m_tileEntityListCS); 747 748 // 4J Stu - At least one of the listeners is something we cannot delete, the LevelRenderer 749 /* 750 for(int i = 0; i < listeners.size(); i++) 751 delete listeners[i]; 752 */ 753} 754 755void Level::initializeLevel(LevelSettings *settings) 756{ 757 levelData->setInitialized(true); 758} 759 760void Level::validateSpawn() 761{ 762 setSpawnPos(8, 64, 8); 763} 764 765int Level::getTopTile(int x, int z) 766{ 767 // 4J added - was breaking spawning as not finding ground in superflat worlds 768 if( levelData->getGenerator() == LevelType::lvl_flat ) 769 { 770 return Tile::grass_Id; 771 } 772 773 int y = seaLevel; 774 while (!isEmptyTile(x, y + 1, z)) 775 { 776 y++; 777 } 778 return getTile(x, y, z); 779} 780int Level::getTile(int x, int y, int z) 781{ 782 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 783 { 784 return 0; 785 } 786 if (y < minBuildHeight) return 0; 787 if (y >= maxBuildHeight) return 0; 788 return getChunk(x >> 4, z >> 4)->getTile(x & 15, y, z & 15); 789} 790 791int Level::getTileLightBlock(int x, int y, int z) 792{ 793 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 794 { 795 return 0; 796 } 797 if (y < minBuildHeight) return 0; 798 if (y >= maxBuildHeight) return 0; 799 return getChunk(x >> 4, z >> 4)->getTileLightBlock(x & 15, y, z & 15); 800} 801 802bool Level::isEmptyTile(int x, int y, int z) 803{ 804 return getTile(x, y, z) == 0; 805} 806 807bool Level::isEntityTile(int x, int y, int z) 808{ 809 int t = getTile(x, y, z); 810 if (Tile::tiles[t] != NULL && Tile::tiles[t]->isEntityTile()) 811 { 812 return true; 813 } 814 return false; 815} 816 817int Level::getTileRenderShape(int x, int y, int z) 818{ 819 int t = getTile(x, y, z); 820 if (Tile::tiles[t] != NULL) 821 { 822 return Tile::tiles[t]->getRenderShape(); 823 } 824 return Tile::SHAPE_INVISIBLE; 825} 826 827// 4J Added to slightly optimise and avoid getTile call if we already know the tile 828int Level::getTileRenderShape(int t) 829{ 830 if (Tile::tiles[t] != NULL) 831 { 832 return Tile::tiles[t]->getRenderShape(); 833 } 834 return Tile::SHAPE_INVISIBLE; 835} 836 837bool Level::hasChunkAt(int x, int y, int z) 838{ 839 if (y < minBuildHeight || y >= maxBuildHeight) return false; 840 return hasChunk(x >> 4, z >> 4); 841} 842 843// 4J added 844bool Level::reallyHasChunkAt(int x, int y, int z) 845{ 846 if (y < minBuildHeight || y >= maxBuildHeight) return false; 847 return reallyHasChunk(x >> 4, z >> 4); 848} 849 850bool Level::hasChunksAt(int x, int y, int z, int r) 851{ 852 return hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r); 853} 854 855// 4J added 856bool Level::reallyHasChunksAt(int x, int y, int z, int r) 857{ 858 return reallyHasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r); 859} 860 861 862bool Level::hasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1) 863{ 864 if (y1 < minBuildHeight || y0 >= maxBuildHeight) return false; 865 866 x0 >>= 4; 867 z0 >>= 4; 868 x1 >>= 4; 869 z1 >>= 4; 870 871 for (int x = x0; x <= x1; x++) 872 for (int z = z0; z <= z1; z++) 873 if (!hasChunk(x, z)) return false; 874 875 return true; 876} 877 878// 4J added 879bool Level::reallyHasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1) 880{ 881 x0 >>= 4; 882 z0 >>= 4; 883 x1 >>= 4; 884 z1 >>= 4; 885 886 for (int x = x0; x <= x1; x++) 887 for (int z = z0; z <= z1; z++) 888 if (!reallyHasChunk(x, z)) return false; 889 890 return true; 891} 892 893bool Level::hasChunk(int x, int z) 894{ 895 return this->chunkSource->hasChunk(x, z); 896} 897 898// 4J added 899bool Level::reallyHasChunk(int x, int z) 900{ 901 return this->chunkSource->reallyHasChunk(x, z); 902} 903 904 905LevelChunk *Level::getChunkAt(int x, int z) 906{ 907 return getChunk(x >> 4, z >> 4); 908} 909 910 911LevelChunk *Level::getChunk(int x, int z) 912{ 913 return this->chunkSource->getChunk(x, z); 914} 915 916bool Level::setTileAndData(int x, int y, int z, int tile, int data, int updateFlags) 917{ 918 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 919 { 920 return false; 921 } 922 if (y < 0) return false; 923 if (y >= maxBuildHeight) return false; 924 LevelChunk *c = getChunk(x >> 4, z >> 4); 925 926 int oldTile = 0; 927 if ((updateFlags & Tile::UPDATE_NEIGHBORS) != 0) 928 { 929 oldTile = c->getTile(x & 15, y, z & 15); 930 } 931 bool result; 932#ifndef _CONTENT_PACKAGE 933 int old = c->getTile(x & 15, y, z & 15); 934 int olddata = c->getData( x & 15, y, z & 15); 935#endif 936 result = c->setTileAndData(x & 15, y, z & 15, tile, data); 937 if( updateFlags != Tile::UPDATE_INVISIBLE_NO_LIGHT) 938 { 939#ifndef _CONTENT_PACKAGE 940 PIXBeginNamedEvent(0,"Checking light %d %d %d",x,y,z); 941 PIXBeginNamedEvent(0,"was %d, %d now %d, %d",old,olddata,tile,data); 942#endif 943 checkLight(x, y, z); 944 PIXEndNamedEvent(); 945 PIXEndNamedEvent(); 946 } 947 if (result) 948 { 949 if ((updateFlags & Tile::UPDATE_CLIENTS) != 0 && !(isClientSide && (updateFlags & Tile::UPDATE_INVISIBLE) != 0)) 950 { 951 sendTileUpdated(x, y, z); 952 } 953 if (!isClientSide && (updateFlags & Tile::UPDATE_NEIGHBORS) != 0) 954 { 955 tileUpdated(x, y, z, oldTile); 956 Tile *tobj = Tile::tiles[tile]; 957 if (tobj != NULL && tobj->hasAnalogOutputSignal()) updateNeighbourForOutputSignal(x, y, z, tile); 958 } 959 } 960 return result; 961} 962 963Material *Level::getMaterial(int x, int y, int z) 964{ 965 int t = getTile(x, y, z); 966 if (t == 0) return Material::air; 967 return Tile::tiles[t]->material; 968} 969 970int Level::getData(int x, int y, int z) 971{ 972 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 973 { 974 return 0; 975 } 976 if (y < 0) return 0; 977 if (y >= maxBuildHeight) return 0; 978 LevelChunk *c = getChunk(x >> 4, z >> 4); 979 x &= 15; 980 z &= 15; 981 return c->getData(x, y, z); 982} 983 984bool Level::setData(int x, int y, int z, int data, int updateFlags, bool forceUpdate/*=false*/) // 4J added forceUpdate) 985{ 986 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 987 { 988 return false; 989 } 990 if (y < 0) return false; 991 if (y >= maxBuildHeight) return false; 992 LevelChunk *c = getChunk(x >> 4, z >> 4); 993 int cx = x & 15; 994 int cz = z & 15; 995 // 4J - have changed _sendTileData to encode a bitfield of which bits are important to be sent. This will be zero where the original flag was false, and non-zero where the original 996 // flag was true - hence recreating the original flag as sendTileData here. For nearly all tiles this will be 15 for the case where this used to be true (ie all bits are important) so 997 // there should be absolutely to change in behaviour. However, for leaf tiles, bits have been masked so we don't bother doing sendTileUpdated if a non-visual thing has changed in the data 998 unsigned char importantMask = Tile::_sendTileData[c->getTile(cx, y, cz) & Tile::TILE_NUM_MASK]; 999 bool sendTileData = importantMask != 0; 1000 1001 bool maskedBitsChanged; 1002 bool result = c->setData(cx, y, cz, data, importantMask, &maskedBitsChanged); 1003 if (result || forceUpdate) 1004 { 1005 int tile = c->getTile(cx, y, cz); 1006 if (forceUpdate || ((updateFlags & Tile::UPDATE_CLIENTS) != 0 && !(isClientSide && (updateFlags & Tile::UPDATE_INVISIBLE) != 0))) 1007 { 1008 sendTileUpdated(x, y, z); 1009 } 1010 if (!isClientSide && (forceUpdate || (updateFlags & Tile::UPDATE_NEIGHBORS) != 0) ) 1011 { 1012 tileUpdated(x, y, z, tile); 1013 Tile *tobj = Tile::tiles[tile]; 1014 if (tobj != NULL && tobj->hasAnalogOutputSignal()) updateNeighbourForOutputSignal(x, y, z, tile); 1015 } 1016 } 1017 return result; 1018} 1019 1020/** 1021* Sets a tile to air without dropping resources or showing any animation. 1022* 1023* @param x 1024* @param y 1025* @param z 1026* @return 1027*/ 1028bool Level::removeTile(int x, int y, int z) 1029{ 1030 return setTileAndData(x, y, z, 0, 0, Tile::UPDATE_ALL); 1031} 1032 1033/** 1034* Sets a tile to air and plays a destruction animation, with option to also 1035* drop resources. 1036* 1037* @param x 1038* @param y 1039* @param z 1040* @param dropResources 1041* @return True if anything was changed 1042*/ 1043bool Level::destroyTile(int x, int y, int z, bool dropResources) 1044{ 1045 int tile = getTile(x, y, z); 1046 if (tile > 0) 1047 { 1048 int data = getData(x, y, z); 1049 levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, tile + (data << Tile::TILE_NUM_SHIFT)); 1050 if (dropResources) 1051 { 1052 Tile::tiles[tile]->spawnResources(this, x, y, z, data, 0); 1053 } 1054 return setTileAndData(x, y, z, 0, 0, Tile::UPDATE_ALL); 1055 } 1056 return false; 1057} 1058 1059bool Level::setTileAndUpdate(int x, int y, int z, int tile) 1060{ 1061 return setTileAndData(x, y, z, tile, 0, Tile::UPDATE_ALL); 1062} 1063 1064void Level::sendTileUpdated(int x, int y, int z) 1065{ 1066 AUTO_VAR(itEnd, listeners.end()); 1067 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1068 { 1069 (*it)->tileChanged(x, y, z); 1070 } 1071} 1072 1073void Level::tileUpdated(int x, int y, int z, int tile) 1074{ 1075 updateNeighborsAt(x, y, z, tile); 1076} 1077 1078void Level::lightColumnChanged(int x, int z, int y0, int y1) 1079{ 1080 PIXBeginNamedEvent(0,"LightColumnChanged (%d,%d) %d to %d",x,z,y0,y1); 1081 if (y0 > y1) 1082 { 1083 int tmp = y1; 1084 y1 = y0; 1085 y0 = tmp; 1086 } 1087 1088 if (!dimension->hasCeiling) 1089 { 1090 PIXBeginNamedEvent(0,"Checking lights"); 1091 for (int y = y0; y <= y1; y++) 1092 { 1093 PIXBeginNamedEvent(0,"Checking light %d", y); 1094 checkLight(LightLayer::Sky, x, y, z); 1095 PIXEndNamedEvent(); 1096 } 1097 PIXEndNamedEvent(); 1098 } 1099 PIXBeginNamedEvent(0,"Setting tiles dirty"); 1100 setTilesDirty(x, y0, z, x, y1, z); 1101 PIXEndNamedEvent(); 1102 PIXEndNamedEvent(); 1103} 1104 1105 1106void Level::setTileDirty(int x, int y, int z) 1107{ 1108 AUTO_VAR(itEnd, listeners.end()); 1109 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1110 { 1111 (*it)->setTilesDirty(x, y, z, x, y, z, this); 1112 } 1113} 1114 1115 1116void Level::setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1) 1117{ 1118 AUTO_VAR(itEnd, listeners.end()); 1119 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1120 { 1121 (*it)->setTilesDirty(x0, y0, z0, x1, y1, z1, this); 1122 } 1123} 1124 1125void Level::updateNeighborsAt(int x, int y, int z, int tile) 1126{ 1127 neighborChanged(x - 1, y, z, tile); 1128 neighborChanged(x + 1, y, z, tile); 1129 neighborChanged(x, y - 1, z, tile); 1130 neighborChanged(x, y + 1, z, tile); 1131 neighborChanged(x, y, z - 1, tile); 1132 neighborChanged(x, y, z + 1, tile); 1133} 1134 1135void Level::updateNeighborsAtExceptFromFacing(int x, int y, int z, int tile, int skipFacing) 1136{ 1137 if (skipFacing != Facing::WEST) neighborChanged(x - 1, y, z, tile); 1138 if (skipFacing != Facing::EAST) neighborChanged(x + 1, y, z, tile); 1139 if (skipFacing != Facing::DOWN) neighborChanged(x, y - 1, z, tile); 1140 if (skipFacing != Facing::UP) neighborChanged(x, y + 1, z, tile); 1141 if (skipFacing != Facing::NORTH) neighborChanged(x, y, z - 1, tile); 1142 if (skipFacing != Facing::SOUTH) neighborChanged(x, y, z + 1, tile); 1143} 1144 1145void Level::neighborChanged(int x, int y, int z, int type) 1146{ 1147 if (isClientSide) return; 1148 int id = getTile(x, y, z); 1149 Tile *tile = Tile::tiles[id]; 1150 1151 if (tile != NULL) 1152 { 1153 tile->neighborChanged(this, x, y, z, type); 1154 } 1155} 1156 1157bool Level::isTileToBeTickedAt(int x, int y, int z, int tileId) 1158{ 1159 return false; 1160} 1161 1162bool Level::canSeeSky(int x, int y, int z) 1163{ 1164 return getChunk(x >> 4, z >> 4)->isSkyLit(x & 15, y, z & 15); 1165} 1166 1167 1168int Level::getDaytimeRawBrightness(int x, int y, int z) 1169{ 1170 if (y < 0) return 0; 1171 if (y >= maxBuildHeight) y = maxBuildHeight - 1; 1172 return getChunk(x >> 4, z >> 4)->getRawBrightness(x & 15, y, z & 15, 0); 1173} 1174 1175 1176int Level::getRawBrightness(int x, int y, int z) 1177{ 1178 return getRawBrightness(x, y, z, true); 1179} 1180 1181 1182int Level::getRawBrightness(int x, int y, int z, bool propagate) 1183{ 1184 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 1185 { 1186 return MAX_BRIGHTNESS; 1187 } 1188 1189 if (propagate) 1190 { 1191 int id = getTile(x, y, z); 1192 if (Tile::propagate[id]) 1193 { 1194 int br = getRawBrightness(x, y + 1, z, false); 1195 int br1 = getRawBrightness(x + 1, y, z, false); 1196 int br2 = getRawBrightness(x - 1, y, z, false); 1197 int br3 = getRawBrightness(x, y, z + 1, false); 1198 int br4 = getRawBrightness(x, y, z - 1, false); 1199 if (br1 > br) br = br1; 1200 if (br2 > br) br = br2; 1201 if (br3 > br) br = br3; 1202 if (br4 > br) br = br4; 1203 return br; 1204 } 1205 } 1206 1207 if (y < 0) return 0; 1208 if (y >= maxBuildHeight) y = maxBuildHeight - 1; 1209 1210 LevelChunk *c = getChunk(x >> 4, z >> 4); 1211 x &= 15; 1212 z &= 15; 1213 return c->getRawBrightness(x, y, z, skyDarken); 1214} 1215 1216 1217bool Level::isSkyLit(int x, int y, int z) 1218{ 1219 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 1220 { 1221 return false; 1222 } 1223 if (dimension->hasCeiling) return false; 1224 1225 if (y < 0) return false; 1226 if (y >= maxBuildHeight) return true; 1227 if (!hasChunk(x >> 4, z >> 4)) return false; 1228 1229 LevelChunk *c = getChunk(x >> 4, z >> 4); 1230 x &= 15; 1231 z &= 15; 1232 return c->isSkyLit(x, y, z); 1233} 1234 1235 1236int Level::getHeightmap(int x, int z) 1237{ 1238 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 1239 { 1240 return 0; 1241 } 1242 if (!hasChunk(x >> 4, z >> 4)) return 0; 1243 1244 LevelChunk *c = getChunk(x >> 4, z >> 4); 1245 return c->getHeightmap(x & 15, z & 15); 1246} 1247 1248int Level::getLowestHeightmap(int x, int z) 1249{ 1250 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 1251 { 1252 return 0; 1253 } 1254 if (!hasChunk(x >> 4, z >> 4)) return 0; 1255 1256 LevelChunk *c = getChunk(x >> 4, z >> 4); 1257 return c->lowestHeightmap; 1258} 1259 1260void Level::updateLightIfOtherThan(LightLayer::variety layer, int x, int y, int z, int expected) 1261{ 1262 if (dimension->hasCeiling && layer == LightLayer::Sky) return; 1263 1264 if (!hasChunkAt(x, y, z)) return; 1265 1266 if (layer == LightLayer::Sky) 1267 { 1268 if (isSkyLit(x, y, z)) expected = 15; 1269 } 1270 else if (layer == LightLayer::Block) 1271 { 1272 int t = getTile(x, y, z); 1273 if (Tile::lightEmission[t] > expected) expected = Tile::lightEmission[t]; 1274 } 1275 1276 if (getBrightness(layer, x, y, z) != expected) 1277 { 1278 setBrightness(layer, x, y, z, expected); 1279 } 1280} 1281 1282// 4J - update brought forward from 1.8.2 1283int Level::getBrightnessPropagate(LightLayer::variety layer, int x, int y, int z, int tileId) 1284{ 1285 if (dimension->hasCeiling && layer == LightLayer::Sky) return 0; 1286 1287 if (y < 0) y = 0; 1288 if (y >= maxBuildHeight && layer == LightLayer::Sky) 1289 { 1290 // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we 1291 // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast 1292 // it to an int 1293 return (int)layer; 1294 } 1295 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 1296 { 1297 // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we 1298 // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast 1299 // it to an int 1300 return (int)layer; 1301 } 1302 int xc = x >> 4; 1303 int zc = z >> 4; 1304 if (!hasChunk(xc, zc)) return (int)layer; 1305 1306 { 1307 int id = tileId > -1 ? tileId : getTile(x,y,z); 1308 if (Tile::propagate[id]) 1309 { 1310 int br = getBrightness(layer, x, y + 1, z); 1311 int br1 = getBrightness(layer, x + 1, y, z); 1312 int br2 = getBrightness(layer, x - 1, y, z); 1313 int br3 = getBrightness(layer, x, y, z + 1); 1314 int br4 = getBrightness(layer, x, y, z - 1); 1315 if (br1 > br) br = br1; 1316 if (br2 > br) br = br2; 1317 if (br3 > br) br = br3; 1318 if (br4 > br) br = br4; 1319 return br; 1320 } 1321 } 1322 1323 LevelChunk *c = getChunk(xc, zc); 1324 return c->getBrightness(layer, x & 15, y, z & 15); 1325} 1326 1327int Level::getBrightness(LightLayer::variety layer, int x, int y, int z) 1328{ 1329 // 4J - optimised. Not doing checks on x/z that are no longer necessary, and directly checking the cache within 1330 // the ServerChunkCache/MultiplayerChunkCache rather than going through wrappers & virtual functions. 1331 int xc = x >> 4; 1332 int zc = z >> 4; 1333 1334 int ix = xc + (chunkSourceXZSize/2); 1335 int iz = zc + (chunkSourceXZSize/2); 1336 1337 if( ( ix < 0 ) || ( ix >= chunkSourceXZSize ) ) return 0; 1338 if( ( iz < 0 ) || ( iz >= chunkSourceXZSize ) ) return 0; 1339 int idx = ix * chunkSourceXZSize + iz; 1340 LevelChunk *c = chunkSourceCache[idx]; 1341 1342 if( c == NULL ) return (int)layer; 1343 1344 if (y < 0) y = 0; 1345 if (y >= maxBuildHeight) y = maxBuildHeight - 1; 1346 1347 return c->getBrightness(layer, x & 15, y, z & 15); 1348} 1349 1350// 4J added as optimisation - if all the neighbouring brightesses are going to be in the one chunk, just get 1351// the level chunk once 1352void Level::getNeighbourBrightnesses(int *brightnesses, LightLayer::variety layer, int x, int y, int z) 1353{ 1354 if( ( ( ( x & 15 ) == 0 ) || ( ( x & 15 ) == 15 ) ) || 1355 ( ( ( z & 15 ) == 0 ) || ( ( z & 15 ) == 15 ) ) || 1356 ( ( y <= 0 ) || ( y >= 127 ) ) ) 1357 { 1358 // We're spanning more than one chunk, just fall back on original java method here 1359 brightnesses[0] = getBrightness(layer, x - 1, y, z); 1360 brightnesses[1] = getBrightness(layer, x + 1, y, z); 1361 brightnesses[2] = getBrightness(layer, x, y - 1, z); 1362 brightnesses[3] = getBrightness(layer, x, y + 1, z); 1363 brightnesses[4] = getBrightness(layer, x, y, z - 1); 1364 brightnesses[5] = getBrightness(layer, x, y, z + 1); 1365 } 1366 else 1367 { 1368 // All in one chunk - just get the chunk once, and do a single call to get the results 1369 int xc = x >> 4; 1370 int zc = z >> 4; 1371 1372 int ix = xc + (chunkSourceXZSize/2); 1373 int iz = zc + (chunkSourceXZSize/2); 1374 1375 // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we 1376 // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast 1377 // it to an int 1378 if( ( ( ix < 0 ) || ( ix >= chunkSourceXZSize ) ) || 1379 ( ( iz < 0 ) || ( iz >= chunkSourceXZSize ) ) ) 1380 { 1381 for( int i = 0; i < 6; i++ ) 1382 { 1383 brightnesses[i] = (int)layer; 1384 } 1385 return; 1386 } 1387 1388 int idx = ix * chunkSourceXZSize + iz; 1389 LevelChunk *c = chunkSourceCache[idx]; 1390 1391 // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we 1392 // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast 1393 // it to an int 1394 if( c == NULL ) 1395 { 1396 for( int i = 0; i < 6; i++ ) 1397 { 1398 brightnesses[i] = (int)layer; 1399 } 1400 return; 1401 } 1402 1403 // Single call to the levelchunk too to avoid overhead of virtual fn calls 1404 c->getNeighbourBrightnesses(brightnesses, layer, x & 15, y, z & 15); 1405 } 1406} 1407 1408void Level::setBrightness(LightLayer::variety layer, int x, int y, int z, int brightness, bool noUpdateOnClient/*=false*/) // 4J added noUpdateOnClient 1409{ 1410 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 1411 { 1412 return; 1413 } 1414 if (y < 0) return; 1415 if (y >= maxBuildHeight) return; 1416 if (!hasChunk(x >> 4, z >> 4)) return; 1417 LevelChunk *c = getChunk(x >> 4, z >> 4); 1418 1419 c->setBrightness(layer, x & 15, y, z & 15, brightness); 1420 1421 // 4J added 1422 if( isClientSide && noUpdateOnClient ) 1423 { 1424 if( cachewritten ) 1425 { 1426 if( x < cacheminx ) cacheminx = x; 1427 if( x > cachemaxx ) cachemaxx = x; 1428 if( y < cacheminy ) cacheminy = y; 1429 if( y > cachemaxy ) cachemaxy = y; 1430 if( z < cacheminz ) cacheminz = z; 1431 if( z > cachemaxz ) cachemaxz = z; 1432 } 1433 else 1434 { 1435 cachewritten = true; 1436 cacheminx = x; 1437 cachemaxx = x; 1438 cacheminy = y; 1439 cachemaxy = y; 1440 cacheminz = z; 1441 cachemaxz = z; 1442 } 1443 } 1444 else 1445 { 1446 AUTO_VAR(itEnd, listeners.end()); 1447 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1448 { 1449 (*it)->tileLightChanged(x, y, z); 1450 } 1451 } 1452} 1453 1454void Level::setTileBrightnessChanged(int x, int y, int z) 1455{ 1456 AUTO_VAR(itEnd, listeners.end()); 1457 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1458 { 1459 (*it)->tileLightChanged(x, y, z); 1460 } 1461} 1462 1463int Level::getLightColor(int x, int y, int z, int emitt, int tileId/*=-1*/) 1464{ 1465 int s = getBrightnessPropagate(LightLayer::Sky, x, y, z, tileId); 1466 int b = getBrightnessPropagate(LightLayer::Block, x, y, z, tileId); 1467 if (b < emitt) b = emitt; 1468 return s << 20 | b << 4; 1469} 1470 1471float Level::getBrightness(int x, int y, int z, int emitt) 1472{ 1473 int n = getRawBrightness(x, y, z); 1474 if (n < emitt) n = emitt; 1475 return dimension->brightnessRamp[n]; 1476} 1477 1478 1479float Level::getBrightness(int x, int y, int z) 1480{ 1481 return dimension->brightnessRamp[getRawBrightness(x, y, z)]; 1482} 1483 1484 1485bool Level::isDay() 1486{ 1487 return skyDarken < 4; 1488} 1489 1490 1491HitResult *Level::clip(Vec3 *a, Vec3 *b) 1492{ 1493 return clip(a, b, false, false); 1494} 1495 1496 1497HitResult *Level::clip(Vec3 *a, Vec3 *b, bool liquid) 1498{ 1499 return clip(a, b, liquid, false); 1500} 1501 1502 1503HitResult *Level::clip(Vec3 *a, Vec3 *b, bool liquid, bool solidOnly) 1504{ 1505 if (Double::isNaN(a->x) || Double::isNaN(a->y) || Double::isNaN(a->z)) return NULL; 1506 if (Double::isNaN(b->x) || Double::isNaN(b->y) || Double::isNaN(b->z)) return NULL; 1507 1508 int xTile1 = Mth::floor(b->x); 1509 int yTile1 = Mth::floor(b->y); 1510 int zTile1 = Mth::floor(b->z); 1511 1512 int xTile0 = Mth::floor(a->x); 1513 int yTile0 = Mth::floor(a->y); 1514 int zTile0 = Mth::floor(a->z); 1515 1516 { 1517 int t = getTile(xTile0, yTile0, zTile0); 1518 int data = getData(xTile0, yTile0, zTile0); 1519 Tile *tile = Tile::tiles[t]; 1520 if (solidOnly && tile != NULL && tile->getAABB(this, xTile0, yTile0, zTile0) == NULL) 1521 { 1522 // No collision 1523 1524 } 1525 else if (t > 0 && tile->mayPick(data, liquid)) 1526 { 1527 HitResult *r = tile->clip(this, xTile0, yTile0, zTile0, a, b); 1528 if (r != NULL) return r; 1529 } 1530 } 1531 1532 int maxIterations = 200; 1533 while (maxIterations-- >= 0) 1534 { 1535 if (Double::isNaN(a->x) || Double::isNaN(a->y) || Double::isNaN(a->z)) return NULL; 1536 if (xTile0 == xTile1 && yTile0 == yTile1 && zTile0 == zTile1) return NULL; 1537 1538 bool xClipped = true; 1539 bool yClipped = true; 1540 bool zClipped = true; 1541 1542 double xClip = 999; 1543 double yClip = 999; 1544 double zClip = 999; 1545 1546 if (xTile1 > xTile0) xClip = xTile0 + 1.000; 1547 else if (xTile1 < xTile0) xClip = xTile0 + 0.000; 1548 else xClipped = false; 1549 1550 if (yTile1 > yTile0) yClip = yTile0 + 1.000; 1551 else if (yTile1 < yTile0) yClip = yTile0 + 0.000; 1552 else yClipped = false; 1553 1554 if (zTile1 > zTile0) zClip = zTile0 + 1.000; 1555 else if (zTile1 < zTile0) zClip = zTile0 + 0.000; 1556 else zClipped = false; 1557 1558 double xDist = 999; 1559 double yDist = 999; 1560 double zDist = 999; 1561 1562 double xd = b->x - a->x; 1563 double yd = b->y - a->y; 1564 double zd = b->z - a->z; 1565 1566 if (xClipped) xDist = (xClip - a->x) / xd; 1567 if (yClipped) yDist = (yClip - a->y) / yd; 1568 if (zClipped) zDist = (zClip - a->z) / zd; 1569 1570 int face = 0; 1571 if (xDist < yDist && xDist < zDist) 1572 { 1573 if (xTile1 > xTile0) face = 4; 1574 else face = 5; 1575 1576 a->x = xClip; 1577 a->y += yd * xDist; 1578 a->z += zd * xDist; 1579 } 1580 else if (yDist < zDist) 1581 { 1582 if (yTile1 > yTile0) face = 0; 1583 else face = 1; 1584 1585 a->x += xd * yDist; 1586 a->y = yClip; 1587 a->z += zd * yDist; 1588 } 1589 else 1590 { 1591 if (zTile1 > zTile0) face = 2; 1592 else face = 3; 1593 1594 a->x += xd * zDist; 1595 a->y += yd * zDist; 1596 a->z = zClip; 1597 } 1598 1599 Vec3 *tPos = Vec3::newTemp(a->x, a->y, a->z); 1600 xTile0 = (int) (tPos->x = floor(a->x)); 1601 if (face == 5) 1602 { 1603 xTile0--; 1604 tPos->x++; 1605 } 1606 yTile0 = (int) (tPos->y = floor(a->y)); 1607 if (face == 1) 1608 { 1609 yTile0--; 1610 tPos->y++; 1611 } 1612 zTile0 = (int) (tPos->z = floor(a->z)); 1613 if (face == 3) 1614 { 1615 zTile0--; 1616 tPos->z++; 1617 } 1618 1619 int t = getTile(xTile0, yTile0, zTile0); 1620 int data = getData(xTile0, yTile0, zTile0); 1621 Tile *tile = Tile::tiles[t]; 1622 if (solidOnly && tile != NULL && tile->getAABB(this, xTile0, yTile0, zTile0) == NULL) 1623 { 1624 // No collision 1625 1626 } 1627 else if (t > 0 && tile->mayPick(data, liquid)) 1628 { 1629 HitResult *r = tile->clip(this, xTile0, yTile0, zTile0, a, b); 1630 if (r != NULL) return r; 1631 } 1632 } 1633 return NULL; 1634} 1635 1636 1637void Level::playEntitySound(shared_ptr<Entity> entity, int iSound, float volume, float pitch) 1638{ 1639 if(entity == NULL) return; 1640 AUTO_VAR(itEnd, listeners.end()); 1641 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1642 { 1643 // 4J-PB - if the entity is a local player, don't play the sound 1644 if(entity->GetType() == eTYPE_SERVERPLAYER) 1645 { 1646 //app.DebugPrintf("ENTITY is serverplayer\n"); 1647 1648 (*it)->playSound(iSound, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); 1649 } 1650 else 1651 { 1652 (*it)->playSound(iSound, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); 1653 } 1654 } 1655} 1656 1657void Level::playPlayerSound(shared_ptr<Player> entity, int iSound, float volume, float pitch) 1658{ 1659 if (entity == NULL) return; 1660 AUTO_VAR(itEnd, listeners.end()); 1661 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1662 { 1663 (*it)->playSoundExceptPlayer(entity, iSound, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); 1664 } 1665} 1666 1667//void Level::playSound(double x, double y, double z, const wstring& name, float volume, float pitch) 1668void Level::playSound(double x, double y, double z, int iSound, float volume, float pitch, float fClipSoundDist) 1669{ 1670 AUTO_VAR(itEnd, listeners.end()); 1671 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1672 { 1673 (*it)->playSound(iSound, x, y, z, volume, pitch, fClipSoundDist); 1674 } 1675} 1676 1677void Level::playLocalSound(double x, double y, double z, int iSound, float volume, float pitch, bool distanceDelay, float fClipSoundDist) 1678{ 1679} 1680 1681void Level::playStreamingMusic(const wstring& name, int x, int y, int z) 1682{ 1683 AUTO_VAR(itEnd, listeners.end()); 1684 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1685 { 1686 (*it)->playStreamingMusic(name, x, y, z); 1687 } 1688} 1689 1690 1691void Level::playMusic(double x, double y, double z, const wstring& string, float volume) 1692{ 1693} 1694 1695// 4J removed - 1696/* 1697void Level::addParticle(const wstring& id, double x, double y, double z, double xd, double yd, double zd) 1698{ 1699AUTO_VAR(itEnd, listeners.end()); 1700for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1701(*it)->addParticle(id, x, y, z, xd, yd, zd); 1702} 1703*/ 1704 1705// 4J-PB added 1706void Level::addParticle(ePARTICLE_TYPE id, double x, double y, double z, double xd, double yd, double zd) 1707{ 1708 AUTO_VAR(itEnd, listeners.end()); 1709 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1710 (*it)->addParticle(id, x, y, z, xd, yd, zd); 1711} 1712 1713bool Level::addGlobalEntity(shared_ptr<Entity> e) 1714{ 1715 globalEntities.push_back(e); 1716 return true; 1717} 1718 1719#pragma optimize( "", off ) 1720 1721bool Level::addEntity(shared_ptr<Entity> e) 1722{ 1723 int xc = Mth::floor(e->x / 16); 1724 int zc = Mth::floor(e->z / 16); 1725 1726 if(e == NULL) 1727 { 1728 return false; 1729 } 1730 1731 bool forced = e->forcedLoading; 1732 if (e->instanceof(eTYPE_PLAYER)) 1733 { 1734 forced = true; 1735 } 1736 1737 if (forced || hasChunk(xc, zc)) 1738 { 1739 if (e->instanceof(eTYPE_PLAYER)) 1740 { 1741 shared_ptr<Player> player = dynamic_pointer_cast<Player>(e); 1742 1743 // 4J Stu - Added so we don't continually add the player to the players list while they are dead 1744 if( find( players.begin(), players.end(), e ) == players.end() ) 1745 { 1746 players.push_back(player); 1747 } 1748 1749 updateSleepingPlayerList(); 1750 } 1751 MemSect(42); 1752 getChunk(xc, zc)->addEntity(e); 1753 MemSect(0); 1754 EnterCriticalSection(&m_entitiesCS); 1755 MemSect(43); 1756 entities.push_back(e); 1757 MemSect(0); 1758 LeaveCriticalSection(&m_entitiesCS); 1759 MemSect(44); 1760 entityAdded(e); 1761 MemSect(0); 1762 return true; 1763 } 1764 return false; 1765} 1766 1767#pragma optimize( "", on ) 1768 1769void Level::entityAdded(shared_ptr<Entity> e) 1770{ 1771 AUTO_VAR(itEnd, listeners.end()); 1772 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1773 { 1774 (*it)->entityAdded(e); 1775 } 1776} 1777 1778 1779void Level::entityRemoved(shared_ptr<Entity> e) 1780{ 1781 AUTO_VAR(itEnd, listeners.end()); 1782 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1783 { 1784 (*it)->entityRemoved(e); 1785 } 1786} 1787 1788// 4J added 1789void Level::playerRemoved(shared_ptr<Entity> e) 1790{ 1791 AUTO_VAR(itEnd, listeners.end()); 1792 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 1793 { 1794 (*it)->playerRemoved(e); 1795 } 1796} 1797 1798void Level::removeEntity(shared_ptr<Entity> e) 1799{ 1800 if (e->rider.lock() != NULL) 1801 { 1802 e->rider.lock()->ride(nullptr); 1803 } 1804 if (e->riding != NULL) 1805 { 1806 e->ride(nullptr); 1807 } 1808 e->remove(); 1809 if (e->instanceof(eTYPE_PLAYER)) 1810 { 1811 vector<shared_ptr<Player> >::iterator it = players.begin(); 1812 vector<shared_ptr<Player> >::iterator itEnd = players.end(); 1813 while( it != itEnd && *it != dynamic_pointer_cast<Player>(e) ) 1814 it++; 1815 1816 if( it != itEnd ) 1817 { 1818 players.erase( it ); 1819 } 1820 1821 updateSleepingPlayerList(); 1822 playerRemoved(e); // 4J added - this will let the entity tracker know that we have actually removed the player from the level's player list 1823 } 1824} 1825 1826 1827void Level::removeEntityImmediately(shared_ptr<Entity> e) 1828{ 1829 e->remove(); 1830 1831 if (e->instanceof(eTYPE_PLAYER)) 1832 { 1833 vector<shared_ptr<Player> >::iterator it = players.begin(); 1834 vector<shared_ptr<Player> >::iterator itEnd = players.end(); 1835 while( it != itEnd && *it != dynamic_pointer_cast<Player>(e) ) 1836 it++; 1837 1838 if( it != itEnd ) 1839 { 1840 players.erase( it ); 1841 } 1842 1843 updateSleepingPlayerList(); 1844 playerRemoved(e); // 4J added - this will let the entity tracker know that we have actually removed the player from the level's player list 1845 } 1846 1847 int xc = e->xChunk; 1848 int zc = e->zChunk; 1849 if (e->inChunk && hasChunk(xc, zc)) 1850 { 1851 getChunk(xc, zc)->removeEntity(e); 1852 } 1853 1854 EnterCriticalSection(&m_entitiesCS); 1855 vector<shared_ptr<Entity> >::iterator it = entities.begin(); 1856 vector<shared_ptr<Entity> >::iterator endIt = entities.end(); 1857 while( it != endIt && *it != e) 1858 it++; 1859 1860 if( it != endIt ) 1861 { 1862 entities.erase( it ); 1863 } 1864 LeaveCriticalSection(&m_entitiesCS); 1865 entityRemoved(e); 1866} 1867 1868 1869void Level::addListener(LevelListener *listener) 1870{ 1871 listeners.push_back(listener); 1872} 1873 1874 1875void Level::removeListener(LevelListener *listener) 1876{ 1877 vector<LevelListener *>::iterator it = listeners.begin(); 1878 vector<LevelListener *>::iterator itEnd = listeners.end(); 1879 while( it != itEnd && *it != listener ) 1880 it++; 1881 1882 if( it != itEnd ) 1883 listeners.erase( it ); 1884} 1885 1886 1887// 4J - added noEntities and blockAtEdge parameter 1888AABBList *Level::getCubes(shared_ptr<Entity> source, AABB *box, bool noEntities/* = false*/, bool blockAtEdge/* = false*/) 1889{ 1890 boxes.clear(); 1891 int x0 = Mth::floor(box->x0); 1892 int x1 = Mth::floor(box->x1 + 1); 1893 int y0 = Mth::floor(box->y0); 1894 int y1 = Mth::floor(box->y1 + 1); 1895 int z0 = Mth::floor(box->z0); 1896 int z1 = Mth::floor(box->z1 + 1); 1897 1898 int maxxz = ( dimension->getXZSize() * 16 ) / 2; 1899 int minxz = -maxxz; 1900 for (int x = x0; x < x1; x++) 1901 for (int z = z0; z < z1; z++) 1902 { 1903 // 4J - If we are outside the map, return solid AABBs (rock is a bit of an arbitrary choice here, just need a correct AABB) 1904 if( blockAtEdge && ( ( x < minxz ) || ( x >= maxxz ) || ( z < minxz ) || ( z >= maxxz ) ) ) 1905 { 1906 for (int y = y0 - 1; y < y1; y++) 1907 { 1908 Tile::stone->addAABBs(this, x, y, z, box, &boxes, source); 1909 } 1910 } 1911 else 1912 { 1913 if (hasChunkAt(x, 64, z)) 1914 { 1915 for (int y = y0 - 1; y < y1; y++) 1916 { 1917 Tile *tile = Tile::tiles[getTile(x, y, z)]; 1918 if (tile != NULL) 1919 { 1920 tile->addAABBs(this, x, y, z, box, &boxes, source); 1921 } 1922 } 1923 } 1924 } 1925 } 1926 // 4J - also stop player falling out of the bottom of the map if blockAtEdge is true. Again, rock is an arbitrary choice here 1927 // 4J Stu - Don't stop entities falling into the void while in The End (it has no bedrock) 1928 if( blockAtEdge && ( ( y0 - 1 ) < 0 ) && dimension->id != 1 ) 1929 { 1930 for (int y = y0 - 1; y < 0; y++) 1931 { 1932 for (int x = x0; x < x1; x++) 1933 for (int z = z0; z < z1; z++) 1934 { 1935 Tile::stone->addAABBs(this, x, y, z, box, &boxes, source ); 1936 } 1937 } 1938 } 1939 // 4J - final bounds check - limit vertical movement so we can't move above maxMovementHeight 1940 if( blockAtEdge && ( y1 > maxMovementHeight ) ) 1941 { 1942 for (int y = maxMovementHeight; y < y1; y++) 1943 { 1944 for (int x = x0; x < x1; x++) 1945 for (int z = z0; z < z1; z++) 1946 { 1947 Tile::stone->addAABBs(this, x, y, z, box, &boxes, source ); 1948 } 1949 } 1950 } 1951 // 4J - now add in collision for any blocks which have actually been removed, but haven't had their render data updated to reflect this yet. This is to stop the player 1952 // being able to move the view position inside a tile which is (visually) still there, and see out of the world. This is particularly a problem when moving upwards in 1953 // creative mode as the player can get very close to the edge of tiles whilst looking upwards and can therefore very quickly move inside one. 1954 Minecraft::GetInstance()->levelRenderer->destroyedTileManager->addAABBs( this, box, &boxes); 1955 1956 // 4J - added 1957 if( noEntities ) return &boxes; 1958 1959 double r = 0.25; 1960 vector<shared_ptr<Entity> > *ee = getEntities(source, box->grow(r, r, r)); 1961 vector<shared_ptr<Entity> >::iterator itEnd = ee->end(); 1962 for (AUTO_VAR(it, ee->begin()); it != itEnd; it++) 1963 { 1964 AABB *collideBox = (*it)->getCollideBox(); 1965 if (collideBox != NULL && collideBox->intersects(box)) 1966 { 1967 boxes.push_back(collideBox); 1968 } 1969 1970 collideBox = source->getCollideAgainstBox(*it); 1971 if (collideBox != NULL && collideBox->intersects(box)) 1972 { 1973 boxes.push_back(collideBox); 1974 } 1975 } 1976 1977 return &boxes; 1978} 1979 1980// 4J Stu - Brought forward from 12w36 to fix #46282 - TU5: Gameplay: Exiting the minecart in a tight corridor damages the player 1981AABBList *Level::getTileCubes(AABB *box, bool blockAtEdge/* = false */) 1982{ 1983 return getCubes(nullptr, box, true, blockAtEdge); 1984 //boxes.clear(); 1985 //int x0 = Mth::floor(box->x0); 1986 //int x1 = Mth::floor(box->x1 + 1); 1987 //int y0 = Mth::floor(box->y0); 1988 //int y1 = Mth::floor(box->y1 + 1); 1989 //int z0 = Mth::floor(box->z0); 1990 //int z1 = Mth::floor(box->z1 + 1); 1991 1992 //for (int x = x0; x < x1; x++) 1993 //{ 1994 // for (int z = z0; z < z1; z++) 1995 // { 1996 // if (hasChunkAt(x, 64, z)) 1997 // { 1998 // for (int y = y0 - 1; y < y1; y++) 1999 // { 2000 // Tile *tile = Tile::tiles[getTile(x, y, z)]; 2001 2002 // if (tile != NULL) 2003 // { 2004 // tile->addAABBs(this, x, y, z, box, &boxes); 2005 // } 2006 // } 2007 // } 2008 // } 2009 //} 2010 2011 //return boxes; 2012} 2013 2014//4J - change brought forward from 1.8.2 2015int Level::getOldSkyDarken(float a) 2016{ 2017 float td = getTimeOfDay(a); 2018 2019 float br = 1 - (Mth::cos(td * PI * 2) * 2 + 0.5f); 2020 if (br < 0.0f) br = 0.0f; 2021 if (br > 1.0f) br = 1.0f; 2022 2023 br = 1 - br; 2024 2025 br *= 1 - (getRainLevel(a) * 5 / 16.0f); 2026 br *= 1 - (getThunderLevel(a) * 5 / 16.0f); 2027 br = 1 - br; 2028 return ((int) (br * 11)); 2029} 2030 2031//4J - change brought forward from 1.8.2 2032float Level::getSkyDarken(float a) 2033{ 2034 float td = getTimeOfDay(a); 2035 2036 float br = 1 - (Mth::cos(td * PI * 2) * 2 + 0.2f); 2037 if (br < 0.0f) br = 0.0f; 2038 if (br > 1.0f) br = 1.0f; 2039 2040 br = 1.0f - br; 2041 2042 br *= 1.0f - (getRainLevel(a) * 5.0f / 16.0f); 2043 br *= 1.0f - (getThunderLevel(a) * 5.0f / 16.0f); 2044 // return ((int) (br * 13)); 2045 2046 return br * 0.8f + 0.2f; 2047} 2048 2049 2050 2051Vec3 *Level::getSkyColor(shared_ptr<Entity> source, float a) 2052{ 2053 float td = getTimeOfDay(a); 2054 2055 float br = Mth::cos(td * PI * 2) * 2 + 0.5f; 2056 if (br < 0.0f) br = 0.0f; 2057 if (br > 1.0f) br = 1.0f; 2058 2059 int xx = Mth::floor(source->x); 2060 int zz = Mth::floor(source->z); 2061 Biome *biome = getBiome(xx, zz); 2062 float temp = biome->getTemperature(); 2063 int skyColor = biome->getSkyColor(temp); 2064 2065 float r = ((skyColor >> 16) & 0xff) / 255.0f; 2066 float g = ((skyColor >> 8) & 0xff) / 255.0f; 2067 float b = ((skyColor) & 0xff) / 255.0f; 2068 r *= br; 2069 g *= br; 2070 b *= br; 2071 2072 float rainLevel = getRainLevel(a); 2073 if (rainLevel > 0) 2074 { 2075 float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.6f; 2076 2077 float ba = 1 - rainLevel * 0.75f; 2078 r = r * ba + mid * (1 - ba); 2079 g = g * ba + mid * (1 - ba); 2080 b = b * ba + mid * (1 - ba); 2081 } 2082 float thunderLevel = getThunderLevel(a); 2083 if (thunderLevel > 0) 2084 { 2085 float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.2f; 2086 2087 float ba = 1 - thunderLevel * 0.75f; 2088 r = r * ba + mid * (1 - ba); 2089 g = g * ba + mid * (1 - ba); 2090 b = b * ba + mid * (1 - ba); 2091 } 2092 2093 if (skyFlashTime > 0) 2094 { 2095 float f = (skyFlashTime - a); 2096 if (f > 1) f = 1; 2097 f = f * 0.45f; 2098 r = r * (1 - f) + 0.8f * f; 2099 g = g * (1 - f) + 0.8f * f; 2100 b = b * (1 - f) + 1 * f; 2101 } 2102 2103 return Vec3::newTemp(r, g, b); 2104} 2105 2106 2107float Level::getTimeOfDay(float a) 2108{ 2109 /* 2110 * 4J-PB removed line below - notch committed 1.6.6 with the incorrect 2111 * getTimeOfDay and changed it before releasing (without 2112 * re-committing)... that should be the only difference // jeb 2113 */ 2114 /* if (this != NULL) return 0.5f; */ 2115 2116 // 4J Added if so we can override timeOfDay without changing the time that affects ticking of things 2117 return dimension->getTimeOfDay(levelData->getDayTime(), a);; 2118} 2119 2120int Level::getMoonPhase() 2121{ 2122 return dimension->getMoonPhase(levelData->getDayTime()); 2123} 2124 2125float Level::getMoonBrightness() 2126{ 2127 return Dimension::MOON_BRIGHTNESS_PER_PHASE[dimension->getMoonPhase(levelData->getDayTime())]; 2128} 2129 2130float Level::getSunAngle(float a) 2131{ 2132 float td = getTimeOfDay(a); 2133 return td * PI * 2; 2134} 2135 2136 2137Vec3 *Level::getCloudColor(float a) 2138{ 2139 float td = getTimeOfDay(a); 2140 2141 float br = Mth::cos(td * PI * 2) * 2.0f + 0.5f; 2142 if (br < 0.0f) br = 0.0f; 2143 if (br > 1.0f) br = 1.0f; 2144 2145 int baseCloudColour = Minecraft::GetInstance()->getColourTable()->getColor( eMinecraftColour_In_Cloud_Base_Colour ); 2146 2147 float r = ((baseCloudColour >> 16) & 0xff) / 255.0f; 2148 float g = ((baseCloudColour >> 8) & 0xff) / 255.0f; 2149 float b = ((baseCloudColour) & 0xff) / 255.0f; 2150 2151 float rainLevel = getRainLevel(a); 2152 if (rainLevel > 0) 2153 { 2154 float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.6f; 2155 2156 float ba = 1 - rainLevel * 0.95f; 2157 r = r * ba + mid * (1 - ba); 2158 g = g * ba + mid * (1 - ba); 2159 b = b * ba + mid * (1 - ba); 2160 } 2161 2162 r *= br * 0.90f + 0.10f; 2163 g *= br * 0.90f + 0.10f; 2164 b *= br * 0.85f + 0.15f; 2165 2166 float thunderLevel = getThunderLevel(a); 2167 if (thunderLevel > 0) 2168 { 2169 float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.2f; 2170 2171 float ba = 1 - thunderLevel * 0.95f; 2172 r = r * ba + mid * (1 - ba); 2173 g = g * ba + mid * (1 - ba); 2174 b = b * ba + mid * (1 - ba); 2175 } 2176 2177 return Vec3::newTemp(r, g, b); 2178} 2179 2180 2181Vec3 *Level::getFogColor(float a) 2182{ 2183 float td = getTimeOfDay(a); 2184 return dimension->getFogColor(td, a); 2185} 2186 2187 2188int Level::getTopRainBlock(int x, int z) 2189{ 2190 // 4J - optimisation brought forward from 1.8.2 - used to do full calculation here but result is now cached in LevelChunk 2191 return getChunkAt(x, z)->getTopRainBlock(x & 15, z & 15); 2192} 2193 2194// 4J added 2195bool Level::biomeHasRain(int x, int z) 2196{ 2197 return getChunkAt(x, z)->biomeHasRain(x & 15, z & 15); 2198} 2199 2200// 4J added 2201bool Level::biomeHasSnow(int x, int z) 2202{ 2203 return getChunkAt(x, z)->biomeHasSnow(x & 15, z & 15); 2204} 2205 2206int Level::getTopSolidBlock(int x, int z) 2207{ 2208 LevelChunk *levelChunk = getChunkAt(x, z); 2209 2210 int y = levelChunk->getHighestSectionPosition() + 15; 2211 2212 x &= 15; 2213 z &= 15; 2214 2215 while (y > 0) 2216 { 2217 int t = levelChunk->getTile(x, y, z); 2218 if (t == 0 || !(Tile::tiles[t]->material->blocksMotion()) || Tile::tiles[t]->material == Material::leaves) 2219 { 2220 y--; 2221 } 2222 else 2223 { 2224 return y + 1; 2225 } 2226 } 2227 return -1; 2228} 2229 2230 2231int Level::getLightDepth(int x, int z) 2232{ 2233 return getChunkAt(x, z)->getHeightmap(x & 15, z & 15); 2234} 2235 2236 2237float Level::getStarBrightness(float a) 2238{ 2239 float td = getTimeOfDay(a); 2240 2241 float br = 1 - (Mth::cos(td * PI * 2) * 2 + 0.25f); 2242 if (br < 0.0f) br = 0.0f; 2243 if (br > 1.0f) br = 1.0f; 2244 2245 return br * br * 0.5f; 2246} 2247 2248void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay) 2249{ 2250} 2251 2252void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay, int priorityTilt) 2253{ 2254} 2255 2256void Level::forceAddTileTick(int x, int y, int z, int tileId, int tickDelay, int prioTilt) 2257{ 2258} 2259 2260void Level::tickEntities() 2261{ 2262 vector<shared_ptr<Entity> >::iterator itGE = globalEntities.begin(); 2263 while( itGE != globalEntities.end() ) 2264 { 2265 shared_ptr<Entity> e = *itGE; 2266 e->tickCount++; 2267 e->tick(); 2268 if (e->removed) 2269 { 2270 itGE = globalEntities.erase( itGE ); 2271 } 2272 else 2273 { 2274 itGE++; 2275 } 2276 } 2277 2278 EnterCriticalSection(&m_entitiesCS); 2279 2280 for( AUTO_VAR(it, entities.begin()); it != entities.end(); ) 2281 { 2282 bool found = false; 2283 for( AUTO_VAR(it2, entitiesToRemove.begin()); it2 != entitiesToRemove.end(); it2++ ) 2284 { 2285 if( (*it) == (*it2) ) 2286 { 2287 found = true; 2288 break; 2289 } 2290 } 2291 if( found ) 2292 { 2293 it = entities.erase(it); 2294 } 2295 else 2296 { 2297 it++; 2298 } 2299 } 2300 LeaveCriticalSection(&m_entitiesCS); 2301 2302 AUTO_VAR(itETREnd, entitiesToRemove.end()); 2303 for (AUTO_VAR(it, entitiesToRemove.begin()); it != itETREnd; it++) 2304 { 2305 shared_ptr<Entity> e = *it;//entitiesToRemove.at(j); 2306 int xc = e->xChunk; 2307 int zc = e->zChunk; 2308 if (e->inChunk && hasChunk(xc, zc)) 2309 { 2310 getChunk(xc, zc)->removeEntity(e); 2311 } 2312 } 2313 2314 itETREnd = entitiesToRemove.end(); 2315 for (AUTO_VAR(it, entitiesToRemove.begin()); it != itETREnd; it++) 2316 { 2317 entityRemoved(*it); 2318 } 2319 // 2320 entitiesToRemove.clear(); 2321 2322 //for (int i = 0; i < entities.size(); i++) 2323 2324 /* 4J Jev, using an iterator causes problems here as 2325 * the vector is modified from inside this loop. 2326 */ 2327 EnterCriticalSection(&m_entitiesCS); 2328 2329 for (unsigned int i = 0; i < entities.size(); ) 2330 { 2331 shared_ptr<Entity> e = entities.at(i); 2332 2333 if (e->riding != NULL) 2334 { 2335 if (e->riding->removed || e->riding->rider.lock() != e) 2336 { 2337 e->riding->rider = weak_ptr<Entity>(); 2338 e->riding = nullptr; 2339 } 2340 else 2341 { 2342 i++; 2343 continue; 2344 } 2345 } 2346 2347 if (!e->removed) 2348 { 2349#ifndef _FINAL_BUILD 2350 if ( !( app.DebugSettingsOn() && app.GetMobsDontTickEnabled() && e->instanceof(eTYPE_MOB) && !e->instanceof(eTYPE_PLAYER)) ) 2351#endif 2352 { 2353 tick(e); 2354 } 2355 } 2356 2357 if (e->removed) 2358 { 2359 int xc = e->xChunk; 2360 int zc = e->zChunk; 2361 if (e->inChunk && hasChunk(xc, zc)) 2362 { 2363 getChunk(xc, zc)->removeEntity(e); 2364 } 2365 //entities.remove(i--); 2366 //itE = entities.erase( itE ); 2367 2368 // 4J Find the entity again before deleting, as things might have moved in the entity array eg 2369 // from the explosion created by tnt 2370 AUTO_VAR(it, find(entities.begin(), entities.end(), e)); 2371 if( it != entities.end() ) 2372 { 2373 entities.erase(it); 2374 } 2375 2376 entityRemoved(e); 2377 } 2378 else 2379 { 2380 i++; 2381 } 2382 } 2383 LeaveCriticalSection(&m_entitiesCS); 2384 2385 EnterCriticalSection(&m_tileEntityListCS); 2386 2387 updatingTileEntities = true; 2388 for (AUTO_VAR(it, tileEntityList.begin()); it != tileEntityList.end();) 2389 { 2390 shared_ptr<TileEntity> te = *it;//tilevector<shared_ptr<Entity> >.at(i); 2391 if( !te->isRemoved() && te->hasLevel() ) 2392 { 2393 if (hasChunkAt(te->x, te->y, te->z)) 2394 { 2395#ifdef _LARGE_WORLDS 2396 LevelChunk *lc = getChunk(te->x >> 4, te->z >> 4); 2397 if(!isClientSide || !lc->isUnloaded()) 2398#endif 2399 { 2400 te->tick(); 2401 } 2402 } 2403 } 2404 2405 if( te->isRemoved() ) 2406 { 2407 it = tileEntityList.erase(it); 2408 if (hasChunk(te->x >> 4, te->z >> 4)) 2409 { 2410 LevelChunk *lc = getChunk(te->x >> 4, te->z >> 4); 2411 if (lc != NULL) lc->removeTileEntity(te->x & 15, te->y, te->z & 15); 2412 } 2413 } 2414 else 2415 { 2416 it++; 2417 } 2418 } 2419 updatingTileEntities = false; 2420 2421 // 4J-PB - Stuart - check this is correct here 2422 2423 if (!tileEntitiesToUnload.empty()) 2424 { 2425 //tileEntityList.removeAll(tileEntitiesToUnload); 2426 2427 for( AUTO_VAR(it, tileEntityList.begin()); it != tileEntityList.end(); ) 2428 { 2429 bool found = false; 2430 for( AUTO_VAR(it2, tileEntitiesToUnload.begin()); it2 != tileEntitiesToUnload.end(); it2++ ) 2431 { 2432 if( (*it) == (*it2) ) 2433 { 2434 found = true; 2435 break; 2436 } 2437 } 2438 if( found ) 2439 { 2440 if(isClientSide) 2441 { 2442 __debugbreak(); 2443 } 2444 it = tileEntityList.erase(it); 2445 } 2446 else 2447 { 2448 it++; 2449 } 2450 } 2451 tileEntitiesToUnload.clear(); 2452 } 2453 2454 if( !pendingTileEntities.empty() ) 2455 { 2456 for( AUTO_VAR(it, pendingTileEntities.begin()); it != pendingTileEntities.end(); it++ ) 2457 { 2458 shared_ptr<TileEntity> e = *it; 2459 if( !e->isRemoved() ) 2460 { 2461 if( find(tileEntityList.begin(),tileEntityList.end(),e) == tileEntityList.end() ) 2462 { 2463 tileEntityList.push_back(e); 2464 } 2465 if (hasChunk(e->x >> 4, e->z >> 4)) 2466 { 2467 LevelChunk *lc = getChunk(e->x >> 4, e->z >> 4); 2468 if (lc != NULL) lc->setTileEntity(e->x & 15, e->y, e->z & 15, e); 2469 } 2470 2471 sendTileUpdated(e->x, e->y, e->z); 2472 } 2473 } 2474 pendingTileEntities.clear(); 2475 } 2476 LeaveCriticalSection(&m_tileEntityListCS); 2477} 2478 2479void Level::addAllPendingTileEntities(vector< shared_ptr<TileEntity> >& entities) 2480{ 2481 EnterCriticalSection(&m_tileEntityListCS); 2482 if( updatingTileEntities ) 2483 { 2484 for( AUTO_VAR(it, entities.begin()); it != entities.end(); it++ ) 2485 { 2486 pendingTileEntities.push_back(*it); 2487 } 2488 } 2489 else 2490 { 2491 for( AUTO_VAR(it, entities.begin()); it != entities.end(); it++ ) 2492 { 2493 tileEntityList.push_back(*it); 2494 } 2495 } 2496 LeaveCriticalSection(&m_tileEntityListCS); 2497} 2498 2499void Level::tick(shared_ptr<Entity> e) 2500{ 2501 tick(e, true); 2502} 2503 2504 2505void Level::tick(shared_ptr<Entity> e, bool actual) 2506{ 2507 int xc = Mth::floor(e->x); 2508 int zc = Mth::floor(e->z); 2509 int r = 32; 2510#ifdef __PSVITA__ 2511 // AP - make sure the dragon ticks all the time, even when there aren't any chunks. 2512 if (actual && e->GetType() != eTYPE_ENDERDRAGON && !hasChunksAt(xc - r, 0, zc - r, xc + r, 0, zc + r)) 2513#else 2514 if (actual && !hasChunksAt(xc - r, 0, zc - r, xc + r, 0, zc + r)) 2515#endif 2516 { 2517 return; 2518 } 2519 2520 e->xOld = e->x; 2521 e->yOld = e->y; 2522 e->zOld = e->z; 2523 e->yRotO = e->yRot; 2524 e->xRotO = e->xRot; 2525 2526#ifdef __PSVITA__ 2527 // AP - make sure the dragon ticks all the time, even when there aren't any chunks. 2528 if (actual && (e->GetType() == eTYPE_ENDERDRAGON || e->inChunk) ) 2529#else 2530 if (actual && e->inChunk ) 2531#endif 2532 { 2533 e->tickCount++; 2534 if (e->riding != NULL) 2535 { 2536 e->rideTick(); 2537 } 2538 else 2539 { 2540 e->tick(); 2541 } 2542 } 2543 2544 // SANTITY!! 2545 if (Double::isNaN(e->x) || Double::isInfinite(e->x)) e->x = e->xOld; 2546 if (Double::isNaN(e->y) || Double::isInfinite(e->y)) e->y = e->yOld; 2547 if (Double::isNaN(e->z) || Double::isInfinite(e->z)) e->z = e->zOld; 2548 if (Double::isNaN(e->xRot) || Double::isInfinite(e->xRot)) e->xRot = e->xRotO; 2549 if (Double::isNaN(e->yRot) || Double::isInfinite(e->yRot)) e->yRot = e->yRotO; 2550 2551 int xcn = Mth::floor(e->x / 16); 2552 int ycn = Mth::floor(e->y / 16); 2553 int zcn = Mth::floor(e->z / 16); 2554 2555 2556 2557 if (!e->inChunk || (e->xChunk != xcn || e->yChunk != ycn || e->zChunk != zcn)) 2558 { 2559 if (e->inChunk && hasChunk(e->xChunk, e->zChunk)) 2560 { 2561 getChunk(e->xChunk, e->zChunk)->removeEntity(e, e->yChunk); 2562 } 2563 2564 if (hasChunk(xcn, zcn)) 2565 { 2566 2567 e->inChunk = true; 2568 MemSect(39); 2569 getChunk(xcn, zcn)->addEntity(e); 2570 MemSect(0); 2571 } 2572 else 2573 { 2574 e->inChunk = false; 2575 // e.remove(); 2576 } 2577 } 2578 2579 if (actual && e->inChunk) 2580 { 2581 if (e->rider.lock() != NULL) 2582 { 2583 if (e->rider.lock()->removed || e->rider.lock()->riding != e) 2584 { 2585 e->rider.lock()->riding = nullptr; 2586 e->rider = weak_ptr<Entity>(); 2587 } 2588 else 2589 { 2590 tick(e->rider.lock()); 2591 } 2592 } 2593 } 2594} 2595 2596 2597bool Level::isUnobstructed(AABB *aabb) 2598{ 2599 return isUnobstructed(aabb, nullptr); 2600} 2601 2602bool Level::isUnobstructed(AABB *aabb, shared_ptr<Entity> ignore) 2603{ 2604 vector<shared_ptr<Entity> > *ents = getEntities(nullptr, aabb); 2605 AUTO_VAR(itEnd, ents->end()); 2606 for (AUTO_VAR(it, ents->begin()); it != itEnd; it++) 2607 { 2608 shared_ptr<Entity> e = *it; 2609 if (!e->removed && e->blocksBuilding && e != ignore) return false; 2610 } 2611 return true; 2612} 2613 2614 2615bool Level::containsAnyBlocks(AABB *box) 2616{ 2617 int x0 = Mth::floor(box->x0); 2618 int x1 = Mth::floor(box->x1 + 1); 2619 int y0 = Mth::floor(box->y0); 2620 int y1 = Mth::floor(box->y1 + 1); 2621 int z0 = Mth::floor(box->z0); 2622 int z1 = Mth::floor(box->z1 + 1); 2623 2624 if (box->x0 < 0) x0--; 2625 if (box->y0 < 0) y0--; 2626 if (box->z0 < 0) z0--; 2627 2628 for (int x = x0; x < x1; x++) 2629 for (int y = y0; y < y1; y++) 2630 for (int z = z0; z < z1; z++) 2631 { 2632 Tile *tile = Tile::tiles[getTile(x, y, z)]; 2633 if (tile != NULL) 2634 { 2635 return true; 2636 } 2637 } 2638 return false; 2639} 2640 2641 2642bool Level::containsAnyLiquid(AABB *box) 2643{ 2644 int x0 = Mth::floor(box->x0); 2645 int x1 = Mth::floor(box->x1 + 1); 2646 int y0 = Mth::floor(box->y0); 2647 int y1 = Mth::floor(box->y1 + 1); 2648 int z0 = Mth::floor(box->z0); 2649 int z1 = Mth::floor(box->z1 + 1); 2650 2651 if (box->x0 < 0) x0--; 2652 if (box->y0 < 0) y0--; 2653 if (box->z0 < 0) z0--; 2654 2655 for (int x = x0; x < x1; x++) 2656 for (int y = y0; y < y1; y++) 2657 for (int z = z0; z < z1; z++) 2658 { 2659 Tile *tile = Tile::tiles[getTile(x, y, z)]; 2660 if (tile != NULL && tile->material->isLiquid()) 2661 { 2662 return true; 2663 } 2664 } 2665 return false; 2666} 2667 2668// 4J - added this to be used during mob spawning, and it returns true if there's any liquid in the bounding box, or might be because 2669// we don't have a loaded chunk that we'd need to determine whether it really did. The overall aim is to not load or create any chunk 2670// we haven't already got, and be cautious about placing the mob's. 2671bool Level::containsAnyLiquid_NoLoad(AABB *box) 2672{ 2673 int x0 = Mth::floor(box->x0); 2674 int x1 = Mth::floor(box->x1 + 1); 2675 int y0 = Mth::floor(box->y0); 2676 int y1 = Mth::floor(box->y1 + 1); 2677 int z0 = Mth::floor(box->z0); 2678 int z1 = Mth::floor(box->z1 + 1); 2679 2680 if (box->x0 < 0) x0--; 2681 if (box->y0 < 0) y0--; 2682 if (box->z0 < 0) z0--; 2683 2684 for (int x = x0; x < x1; x++) 2685 for (int y = y0; y < y1; y++) 2686 for (int z = z0; z < z1; z++) 2687 { 2688 if( !hasChunkAt(x,y,z) ) return true; // If we don't have it, it might be liquid... 2689 Tile *tile = Tile::tiles[getTile(x, y, z)]; 2690 if (tile != NULL && tile->material->isLiquid()) 2691 { 2692 return true; 2693 } 2694 } 2695 return false; 2696} 2697 2698 2699bool Level::containsFireTile(AABB *box) 2700{ 2701 int x0 = Mth::floor(box->x0); 2702 int x1 = Mth::floor(box->x1 + 1); 2703 int y0 = Mth::floor(box->y0); 2704 int y1 = Mth::floor(box->y1 + 1); 2705 int z0 = Mth::floor(box->z0); 2706 int z1 = Mth::floor(box->z1 + 1); 2707 2708 if (hasChunksAt(x0, y0, z0, x1, y1, z1)) 2709 { 2710 for (int x = x0; x < x1; x++) 2711 for (int y = y0; y < y1; y++) 2712 for (int z = z0; z < z1; z++) 2713 { 2714 int t = getTile(x, y, z); 2715 2716 if (t == Tile::fire_Id || t == Tile::lava_Id || t == Tile::calmLava_Id) return true; 2717 } 2718 } 2719 return false; 2720} 2721 2722 2723bool Level::checkAndHandleWater(AABB *box, Material *material, shared_ptr<Entity> e) 2724{ 2725 int x0 = Mth::floor(box->x0); 2726 int x1 = Mth::floor(box->x1 + 1); 2727 2728 int y0 = Mth::floor(box->y0); 2729 int y1 = Mth::floor(box->y1 + 1); 2730 2731 int z0 = Mth::floor(box->z0); 2732 int z1 = Mth::floor(box->z1 + 1); 2733 2734 if (!hasChunksAt(x0, y0, z0, x1, y1, z1)) 2735 { 2736 return false; 2737 } 2738 2739 bool ok = false; 2740 Vec3 *current = Vec3::newTemp(0, 0, 0); 2741 for (int x = x0; x < x1; x++) 2742 { 2743 for (int y = y0; y < y1; y++) 2744 { 2745 for (int z = z0; z < z1; z++) 2746 { 2747 Tile *tile = Tile::tiles[getTile(x, y, z)]; 2748 if (tile != NULL && tile->material == material) 2749 { 2750 double yt0 = y + 1 - LiquidTile::getHeight(getData(x, y, z)); 2751 if (y1 >= yt0) 2752 { 2753 ok = true; 2754 tile->handleEntityInside(this, x, y, z, e, current); 2755 } 2756 } 2757 } 2758 } 2759 } 2760 if (current->length() > 0 && e->isPushedByWater()) 2761 { 2762 current = current->normalize(); 2763 double pow = 0.014; 2764 e->xd += current->x * pow; 2765 e->yd += current->y * pow; 2766 e->zd += current->z * pow; 2767 } 2768 return ok; 2769} 2770 2771 2772bool Level::containsMaterial(AABB *box, Material *material) 2773{ 2774 int x0 = Mth::floor(box->x0); 2775 int x1 = Mth::floor(box->x1 + 1); 2776 int y0 = Mth::floor(box->y0); 2777 int y1 = Mth::floor(box->y1 + 1); 2778 int z0 = Mth::floor(box->z0); 2779 int z1 = Mth::floor(box->z1 + 1); 2780 2781 for (int x = x0; x < x1; x++) 2782 { 2783 for (int y = y0; y < y1; y++) 2784 { 2785 for (int z = z0; z < z1; z++) 2786 { 2787 Tile *tile = Tile::tiles[getTile(x, y, z)]; 2788 if (tile != NULL && tile->material == material) 2789 { 2790 return true; 2791 } 2792 } 2793 } 2794 } 2795 return false; 2796} 2797 2798 2799bool Level::containsLiquid(AABB *box, Material *material) 2800{ 2801 int x0 = Mth::floor(box->x0); 2802 int x1 = Mth::floor(box->x1 + 1); 2803 int y0 = Mth::floor(box->y0); 2804 int y1 = Mth::floor(box->y1 + 1); 2805 int z0 = Mth::floor(box->z0); 2806 int z1 = Mth::floor(box->z1 + 1); 2807 2808 for (int x = x0; x < x1; x++) 2809 { 2810 for (int y = y0; y < y1; y++) 2811 { 2812 for (int z = z0; z < z1; z++) 2813 { 2814 Tile *tile = Tile::tiles[getTile(x, y, z)]; 2815 if (tile != NULL && tile->material == material) 2816 { 2817 int data = getData(x, y, z); 2818 double yh1 = y + 1; 2819 if (data < 8) 2820 { 2821 yh1 = y + 1 - data / 8.0; 2822 } 2823 if (yh1 >= box->y0) 2824 { 2825 return true; 2826 } 2827 } 2828 } 2829 } 2830 } 2831 return false; 2832} 2833 2834 2835shared_ptr<Explosion> Level::explode(shared_ptr<Entity> source, double x, double y, double z, float r, bool destroyBlocks) 2836{ 2837 return explode(source, x, y, z, r, false, destroyBlocks); 2838} 2839 2840 2841shared_ptr<Explosion> Level::explode(shared_ptr<Entity> source, double x, double y, double z, float r, bool fire, bool destroyBlocks) 2842{ 2843 shared_ptr<Explosion> explosion = shared_ptr<Explosion>( new Explosion(this, source, x, y, z, r) ); 2844 explosion->fire = fire; 2845 explosion->destroyBlocks = destroyBlocks; 2846 explosion->explode(); 2847 explosion->finalizeExplosion(true); 2848 return explosion; 2849} 2850 2851 2852float Level::getSeenPercent(Vec3 *center, AABB *bb) 2853{ 2854 double xs = 1.0 / ((bb->x1 - bb->x0) * 2 + 1); 2855 double ys = 1.0 / ((bb->y1 - bb->y0) * 2 + 1); 2856 double zs = 1.0 / ((bb->z1 - bb->z0) * 2 + 1); 2857 int hits = 0; 2858 int count = 0; 2859 for (double xx = 0; xx <= 1; xx += xs) // 4J Stu - xx, yy and zz were floats, made them doubles to remove warnings 2860 for (double yy = 0; yy <= 1; yy += ys) 2861 for (double zz = 0; zz <= 1; zz += zs) 2862 { 2863 double x = bb->x0 + (bb->x1 - bb->x0) * xx; 2864 double y = bb->y0 + (bb->y1 - bb->y0) * yy; 2865 double z = bb->z0 + (bb->z1 - bb->z0) * zz; 2866 HitResult *res = clip(Vec3::newTemp(x, y, z), center); 2867 if ( res == NULL) hits++; 2868 delete res; 2869 count++; 2870 } 2871 2872 return hits / (float) count; 2873} 2874 2875 2876bool Level::extinguishFire(shared_ptr<Player> player, int x, int y, int z, int face) 2877{ 2878 if (face == 0) y--; 2879 if (face == 1) y++; 2880 if (face == 2) z--; 2881 if (face == 3) z++; 2882 if (face == 4) x--; 2883 if (face == 5) x++; 2884 2885 if (getTile(x, y, z) == Tile::fire_Id) 2886 { 2887 levelEvent(player, LevelEvent::SOUND_FIZZ, x, y, z, 0); 2888 removeTile(x, y, z); 2889 return true; 2890 } 2891 return false; 2892} 2893 2894/* 2895shared_ptr<Entity> Level::findSubclassOf(Entity::Class *entityClass) 2896{ 2897return shared_ptr<Entity>(); 2898} 2899*/ 2900 2901 2902wstring Level::gatherStats() 2903{ 2904 wchar_t buf[64]; 2905 EnterCriticalSection(&m_entitiesCS); 2906 swprintf(buf,64,L"All:%d",entities.size()); 2907 LeaveCriticalSection(&m_entitiesCS); 2908 return wstring(buf); 2909} 2910 2911 2912wstring Level::gatherChunkSourceStats() 2913{ 2914 return chunkSource->gatherStats(); 2915} 2916 2917 2918shared_ptr<TileEntity> Level::getTileEntity(int x, int y, int z) 2919{ 2920 if (y < minBuildHeight || y >= maxBuildHeight) 2921 { 2922 return nullptr; 2923 } 2924 shared_ptr<TileEntity> tileEntity = nullptr; 2925 2926 if (updatingTileEntities) 2927 { 2928 EnterCriticalSection(&m_tileEntityListCS); 2929 for (int i = 0; i < pendingTileEntities.size(); i++) 2930 { 2931 shared_ptr<TileEntity> e = pendingTileEntities.at(i); 2932 if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) 2933 { 2934 tileEntity = e; 2935 break; 2936 } 2937 } 2938 LeaveCriticalSection(&m_tileEntityListCS); 2939 } 2940 2941 if (tileEntity == NULL) 2942 { 2943 LevelChunk *lc = getChunk(x >> 4, z >> 4); 2944 if (lc != NULL) 2945 { 2946 tileEntity = lc->getTileEntity(x & 15, y, z & 15); 2947 } 2948 } 2949 2950 if (tileEntity == NULL) 2951 { 2952 EnterCriticalSection(&m_tileEntityListCS); 2953 for( AUTO_VAR(it, pendingTileEntities.begin()); it != pendingTileEntities.end(); it++ ) 2954 { 2955 shared_ptr<TileEntity> e = *it; 2956 2957 if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) 2958 { 2959 tileEntity = e; 2960 break; 2961 } 2962 } 2963 LeaveCriticalSection(&m_tileEntityListCS); 2964 } 2965 return tileEntity; 2966} 2967 2968 2969void Level::setTileEntity(int x, int y, int z, shared_ptr<TileEntity> tileEntity) 2970{ 2971 if (tileEntity != NULL && !tileEntity->isRemoved()) 2972 { 2973 EnterCriticalSection(&m_tileEntityListCS); 2974 if (updatingTileEntities) 2975 { 2976 tileEntity->x = x; 2977 tileEntity->y = y; 2978 tileEntity->z = z; 2979 2980 // avoid adding duplicates 2981 for( AUTO_VAR(it, pendingTileEntities.begin()); it != pendingTileEntities.end();) 2982 { 2983 shared_ptr<TileEntity> next = *it; 2984 if (next->x == x && next->y == y && next->z == z) 2985 { 2986 next->setRemoved(); 2987 it = pendingTileEntities.erase(it); 2988 } 2989 else 2990 { 2991 ++it; 2992 } 2993 } 2994 2995 pendingTileEntities.push_back(tileEntity); 2996 } 2997 else 2998 { 2999 tileEntityList.push_back(tileEntity); 3000 3001 LevelChunk *lc = getChunk(x >> 4, z >> 4); 3002 if (lc != NULL) lc->setTileEntity(x & 15, y, z & 15, tileEntity); 3003 } 3004 LeaveCriticalSection(&m_tileEntityListCS); 3005 } 3006} 3007 3008void Level::removeTileEntity(int x, int y, int z) 3009{ 3010 EnterCriticalSection(&m_tileEntityListCS); 3011 shared_ptr<TileEntity> te = getTileEntity(x, y, z); 3012 if (te != NULL && updatingTileEntities) 3013 { 3014 te->setRemoved(); 3015 AUTO_VAR(it, find(pendingTileEntities.begin(), pendingTileEntities.end(), te )); 3016 if( it != pendingTileEntities.end() ) 3017 { 3018 pendingTileEntities.erase(it); 3019 } 3020 } 3021 else 3022 { 3023 if (te != NULL) 3024 { 3025 AUTO_VAR(it, find(pendingTileEntities.begin(), pendingTileEntities.end(), te )); 3026 if( it != pendingTileEntities.end() ) 3027 { 3028 pendingTileEntities.erase(it); 3029 } 3030 AUTO_VAR(it2, find(tileEntityList.begin(), tileEntityList.end(), te)); 3031 if( it2 != tileEntityList.end() ) 3032 { 3033 tileEntityList.erase(it2); 3034 } 3035 } 3036 LevelChunk *lc = getChunk(x >> 4, z >> 4); 3037 if (lc != NULL) lc->removeTileEntity(x & 15, y, z & 15); 3038 } 3039 LeaveCriticalSection(&m_tileEntityListCS); 3040} 3041 3042void Level::markForRemoval(shared_ptr<TileEntity> entity) 3043{ 3044 tileEntitiesToUnload.push_back(entity); 3045} 3046 3047bool Level::isSolidRenderTile(int x, int y, int z) 3048{ 3049 Tile *tile = Tile::tiles[getTile(x, y, z)]; 3050 if (tile == NULL) return false; 3051 3052 // 4J - addition here to make rendering big blocks of leaves more efficient. Normally leaves never consider themselves as solid, so 3053 // blocks of leaves will have all sides of each block completely visible. Changing to consider as solid if this block is surrounded by 3054 // other leaves (or solid things). This is paired with another change in Tile::getTexture which makes such solid tiles actually visibly solid (these 3055 // textures exist already for non-fancy graphics). Note: this tile-specific code is here rather than making some new virtual method in the tiles, 3056 // for the sake of efficiency - I don't imagine we'll be doing much more of this sort of thing 3057 3058 if( tile->id == Tile::leaves_Id ) 3059 { 3060 int axo[6] = { 1,-1, 0, 0, 0, 0}; 3061 int ayo[6] = { 0, 0, 1,-1, 0, 0}; 3062 int azo[6] = { 0, 0, 0, 0, 1,-1}; 3063 for( int i = 0; i < 6; i++ ) 3064 { 3065 int t = getTile(x + axo[i], y + ayo[i] , z + azo[i]); 3066 if( ( t != Tile::leaves_Id ) && ( ( Tile::tiles[t] == NULL ) || !Tile::tiles[t]->isSolidRender() ) ) 3067 { 3068 return false; 3069 } 3070 } 3071 3072 return true; 3073 } 3074 return tile->isSolidRender(!isClientSide); 3075} 3076 3077 3078bool Level::isSolidBlockingTile(int x, int y, int z) 3079{ 3080 return Tile::isSolidBlockingTile(getTile(x, y, z)); 3081} 3082 3083/** 3084* This method does the same as isSolidBlockingTile, except it will not 3085* check the tile if the coordinates is in an unloaded or empty chunk. This 3086* is to help vs the problem of "popping" torches in SMP. 3087*/ 3088 3089bool Level::isSolidBlockingTileInLoadedChunk(int x, int y, int z, bool valueIfNotLoaded) 3090{ 3091 if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) 3092 { 3093 return valueIfNotLoaded; 3094 } 3095 LevelChunk *chunk = chunkSource->getChunk(x >> 4, z >> 4); 3096 if (chunk == NULL || chunk->isEmpty()) 3097 { 3098 return valueIfNotLoaded; 3099 } 3100 3101 Tile *tile = Tile::tiles[getTile(x, y, z)]; 3102 if (tile == NULL) return false; 3103 return tile->material->isSolidBlocking() && tile->isCubeShaped(); 3104} 3105 3106bool Level::isFullAABBTile(int x, int y, int z) 3107{ 3108 int tile = getTile(x, y, z); 3109 if (tile == 0 || Tile::tiles[tile] == NULL) 3110 { 3111 return false; 3112 } 3113 AABB *aabb = Tile::tiles[tile]->getAABB(this, x, y, z); 3114 return aabb != NULL && aabb->getSize() >= 1; 3115} 3116 3117bool Level::isTopSolidBlocking(int x, int y, int z) 3118{ 3119 // Temporary workaround until tahgs per-face solidity is finished 3120 Tile *tile = Tile::tiles[getTile(x, y, z)]; 3121 return isTopSolidBlocking(tile, getData(x, y, z)); 3122} 3123 3124bool Level::isTopSolidBlocking(Tile *tile, int data) 3125{ 3126 if (tile == NULL) return false; 3127 3128 if (tile->material->isSolidBlocking() && tile->isCubeShaped()) return true; 3129 if (dynamic_cast<StairTile *>(tile) != NULL) 3130 { 3131 return (data & StairTile::UPSIDEDOWN_BIT) == StairTile::UPSIDEDOWN_BIT; 3132 } 3133 if (dynamic_cast<HalfSlabTile *>(tile) != NULL) 3134 { 3135 return (data & HalfSlabTile::TOP_SLOT_BIT) == HalfSlabTile::TOP_SLOT_BIT; 3136 } 3137 if (dynamic_cast<HopperTile *>(tile) != NULL) return true; 3138 if (dynamic_cast<TopSnowTile *>(tile) != NULL) return (data & TopSnowTile::HEIGHT_MASK) == TopSnowTile::MAX_HEIGHT + 1; 3139 return false; 3140} 3141 3142void Level::updateSkyBrightness() 3143{ 3144 int newDark = getOldSkyDarken(1); 3145 if (newDark != skyDarken) 3146 { 3147 skyDarken = newDark; 3148 } 3149} 3150 3151void Level::setSpawnSettings(bool spawnEnemies, bool spawnFriendlies) 3152{ 3153 this->spawnEnemies = spawnEnemies; 3154 this->spawnFriendlies = spawnFriendlies; 3155} 3156 3157void Level::tick() 3158{ 3159 PIXBeginNamedEvent(0,"Weather tick"); 3160 tickWeather(); 3161 PIXEndNamedEvent(); 3162} 3163 3164void Level::prepareWeather() 3165{ 3166 if (levelData->isRaining()) 3167 { 3168 rainLevel = 1; 3169 if (levelData->isThundering()) 3170 { 3171 thunderLevel = 1; 3172 } 3173 } 3174} 3175 3176 3177void Level::tickWeather() 3178{ 3179 if (dimension->hasCeiling) return; 3180 3181#ifndef _FINAL_BUILD 3182 // debug setting added to disable weather 3183 if(app.DebugSettingsOn()) 3184 { 3185 if(app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_DisableWeather)) 3186 { 3187 levelData->setThundering(false); 3188 levelData->setThunderTime(random->nextInt(TICKS_PER_DAY * 7) + TICKS_PER_DAY / 2); 3189 levelData->setRaining(false); 3190 levelData->setRainTime(random->nextInt(TICKS_PER_DAY * 7) + TICKS_PER_DAY / 2); 3191 } 3192 } 3193#endif 3194 3195 int thunderTime = levelData->getThunderTime(); 3196 if (thunderTime <= 0) 3197 { 3198 if (levelData->isThundering()) 3199 { 3200 levelData->setThunderTime(random->nextInt(20 * 60 * 10) + 20 * 60 * 3); 3201 } 3202 else 3203 { 3204 levelData->setThunderTime(random->nextInt(TICKS_PER_DAY * 7) + TICKS_PER_DAY / 2); 3205 } 3206 } 3207 else 3208 { 3209 thunderTime--; 3210 levelData->setThunderTime(thunderTime); 3211 if (thunderTime <= 0) 3212 { 3213 levelData->setThundering(!levelData->isThundering()); 3214 } 3215 } 3216 3217 int rainTime = levelData->getRainTime(); 3218 if (rainTime <= 0) 3219 { 3220 if (levelData->isRaining()) 3221 { 3222 levelData->setRainTime(random->nextInt(TICKS_PER_DAY / 2) + TICKS_PER_DAY / 2); 3223 } 3224 else 3225 { 3226 levelData->setRainTime(random->nextInt(TICKS_PER_DAY * 7) + TICKS_PER_DAY / 2); 3227 } 3228 } 3229 else 3230 { 3231 rainTime--; 3232 levelData->setRainTime(rainTime); 3233 if (rainTime <= 0) 3234 { 3235 levelData->setRaining(!levelData->isRaining()); 3236 } 3237 /* if( !levelData->isRaining() ) 3238 { 3239 levelData->setRaining(true); 3240 }*/ 3241 } 3242 3243 oRainLevel = rainLevel; 3244 if (levelData->isRaining()) 3245 { 3246 rainLevel += 0.01; 3247 } 3248 else 3249 { 3250 rainLevel -= 0.01; 3251 } 3252 if (rainLevel < 0) rainLevel = 0; 3253 if (rainLevel > 1) rainLevel = 1; 3254 3255 oThunderLevel = thunderLevel; 3256 if (levelData->isThundering()) 3257 { 3258 thunderLevel += 0.01; 3259 } 3260 else 3261 { 3262 thunderLevel -= 0.01; 3263 } 3264 if (thunderLevel < 0) thunderLevel = 0; 3265 if (thunderLevel > 1) thunderLevel = 1; 3266} 3267 3268void Level::toggleDownfall() 3269{ 3270 // this will trick the tickWeather method to toggle rain next tick 3271 levelData->setRainTime(1); 3272} 3273 3274void Level::buildAndPrepareChunksToPoll() 3275{ 3276#if 0 3277 AUTO_VAR(itEnd, players.end()); 3278 for (AUTO_VAR(it, players.begin()); it != itEnd; it++) 3279 { 3280 shared_ptr<Player> player = *it; 3281 int xx = Mth::floor(player->x / 16); 3282 int zz = Mth::floor(player->z / 16); 3283 3284 int r = CHUNK_POLL_RANGE; 3285 for (int x = -r; x <= r; x++) 3286 for (int z = -r; z <= r; z++) 3287 { 3288 chunksToPoll.insert(ChunkPos(x + xx, z + zz)); 3289 } 3290 } 3291#else 3292 // 4J - rewritten to add chunks interleaved by player, and to add them from the centre outwards. We're going to be 3293 // potentially adding less creatures than the original so that our count stays consistent with number of players added, so 3294 // we want to make sure as best we can that the ones we do add are near the active players 3295 int playerCount = (int)players.size(); 3296 int *xx = new int[playerCount]; 3297 int *zz = new int[playerCount]; 3298 for (int i = 0; i < playerCount; i++) 3299 { 3300 shared_ptr<Player> player = players[i]; 3301 xx[i] = Mth::floor(player->x / 16); 3302 zz[i] = Mth::floor(player->z / 16); 3303 chunksToPoll.insert(ChunkPos(xx[i], zz[i] )); 3304 } 3305 3306 for( int r = 1; r <= 9; r++ ) 3307 { 3308 for( int l = 0; l < ( r * 2 ) ; l++ ) 3309 { 3310 for( int i = 0; i < playerCount; i++ ) 3311 { 3312 chunksToPoll.insert(ChunkPos( ( xx[i] - r ) + l , ( zz[i] - r ) ) ); 3313 chunksToPoll.insert(ChunkPos( ( xx[i] + r ) , ( zz[i] - r ) + l ) ); 3314 chunksToPoll.insert(ChunkPos( ( xx[i] + r ) - l , ( zz[i] + r ) ) ); 3315 chunksToPoll.insert(ChunkPos( ( xx[i] - r ) , ( zz[i] + r ) - l ) ); 3316 } 3317 } 3318 } 3319 delete [] xx; 3320 delete [] zz; 3321#endif 3322 3323 if (delayUntilNextMoodSound > 0) delayUntilNextMoodSound--; 3324 3325 // 4J Stu - Added 1.2.3, but not sure if we want to do it 3326 //util.Timer.push("playerCheckLight"); 3327 //// randomly check areas around the players 3328 //if (!players.isEmpty()) { 3329 // int select = random.nextInt(players.size()); 3330 // Player player = players.get(select); 3331 // int px = Mth.floor(player.x) + random.nextInt(11) - 5; 3332 // int py = Mth.floor(player.y) + random.nextInt(11) - 5; 3333 // int pz = Mth.floor(player.z) + random.nextInt(11) - 5; 3334 // checkLight(px, py, pz); 3335 //} 3336 //util.Timer.pop(); 3337} 3338 3339void Level::tickClientSideTiles(int xo, int zo, LevelChunk *lc) 3340{ 3341 //lc->tick(); // 4J - brought this lighting update forward from 1.8.2 3342 3343 if (delayUntilNextMoodSound == 0 && !isClientSide) 3344 { 3345 randValue = randValue * 3 + addend; 3346 int val = (randValue >> 2); 3347 int x = (val & 15); 3348 int z = ((val >> 8) & 15); 3349 int y = ((val >> 16) & genDepthMinusOne); 3350 3351 int id = lc->getTile(x, y, z); 3352 x += xo; 3353 z += zo; 3354 if (id == 0 && this->getDaytimeRawBrightness(x, y, z) <= random->nextInt(8) && getBrightness(LightLayer::Sky, x, y, z) <= 0) 3355 { 3356 shared_ptr<Player> player = getNearestPlayer(x + 0.5, y + 0.5, z + 0.5, 8); 3357 if (player != NULL && player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 2 * 2) 3358 { 3359 // 4J-PB - Fixed issue with cave audio event having 2 sounds at 192k 3360#ifdef _XBOX 3361 this->playSound(x + 0.5, y + 0.5, z + 0.5,eSoundType_AMBIENT_CAVE_CAVE2, 0.7f, 0.8f + random->nextFloat() * 0.2f); 3362#else 3363 this->playSound(x + 0.5, y + 0.5, z + 0.5,eSoundType_AMBIENT_CAVE_CAVE, 0.7f, 0.8f + random->nextFloat() * 0.2f); 3364#endif 3365 delayUntilNextMoodSound = random->nextInt(SharedConstants::TICKS_PER_SECOND * 60 * 10) + SharedConstants::TICKS_PER_SECOND * 60 * 5; 3366 } 3367 } 3368 } 3369 3370 // 4J Stu - Added 1.2.3, but do we need it? 3371 //lc->checkNextLight(); 3372} 3373 3374void Level::tickTiles() 3375{ 3376 buildAndPrepareChunksToPoll(); 3377} 3378 3379bool Level::shouldFreezeIgnoreNeighbors(int x, int y, int z) 3380{ 3381 return shouldFreeze(x, y, z, false); 3382} 3383 3384bool Level::shouldFreeze(int x, int y, int z) 3385{ 3386 return shouldFreeze(x, y, z, true); 3387} 3388 3389bool Level::shouldFreeze(int x, int y, int z, bool checkNeighbors) 3390{ 3391 Biome *biome = getBiome(x, z); 3392 float temp = biome->getTemperature(); 3393 if (temp > 0.15f) return false; 3394 3395 if (y >= 0 && y < maxBuildHeight && getBrightness(LightLayer::Block, x, y, z) < 10) 3396 { 3397 int current = getTile(x, y, z); 3398 if ((current == Tile::calmWater_Id || current == Tile::water_Id) && getData(x, y, z) == 0) 3399 { 3400 if (!checkNeighbors) return true; 3401 3402 bool surroundedByWater = true; 3403 if (surroundedByWater && getMaterial(x - 1, y, z) != Material::water) surroundedByWater = false; 3404 if (surroundedByWater && getMaterial(x + 1, y, z) != Material::water) surroundedByWater = false; 3405 if (surroundedByWater && getMaterial(x, y, z - 1) != Material::water) surroundedByWater = false; 3406 if (surroundedByWater && getMaterial(x, y, z + 1) != Material::water) surroundedByWater = false; 3407 if (!surroundedByWater) return true; 3408 } 3409 } 3410 return false; 3411} 3412 3413bool Level::shouldSnow(int x, int y, int z) 3414{ 3415 Biome *biome = getBiome(x, z); 3416 float temp = biome->getTemperature(); 3417 if (temp > 0.15f) return false; 3418 3419 3420 if (y >= 0 && y < maxBuildHeight && getBrightness(LightLayer::Block, x, y, z) < 10) 3421 { 3422 int below = getTile(x, y - 1, z); 3423 int current = getTile(x, y, z); 3424 if (current == 0) 3425 { 3426 if (Tile::topSnow->mayPlace(this, x, y, z) && (below != 0 && below != Tile::ice_Id && Tile::tiles[below]->material->blocksMotion())) 3427 { 3428 return true; 3429 } 3430 } 3431 } 3432 3433 return false; 3434} 3435 3436void Level::checkLight(int x, int y, int z, bool force, bool rootOnlyEmissive) // 4J added force, rootOnlyEmissive parameters 3437{ 3438 if (!dimension->hasCeiling) checkLight(LightLayer::Sky, x, y, z, force, false); 3439 checkLight(LightLayer::Block, x, y, z, force, rootOnlyEmissive); 3440} 3441 3442int Level::getExpectedLight(lightCache_t *cache, int x, int y, int z, LightLayer::variety layer, bool propagatedOnly) 3443{ 3444 if (layer == LightLayer::Sky && canSeeSky(x, y, z)) return MAX_BRIGHTNESS; 3445 int id = getTile(x, y, z); 3446 int result = layer == LightLayer::Sky ? 0 : Tile::lightEmission[id]; 3447 int block = Tile::lightBlock[id]; 3448 if (block >= MAX_BRIGHTNESS && Tile::lightEmission[id] > 0) block = 1; 3449 if (block < 1) block = 1; 3450 if (block >= MAX_BRIGHTNESS) 3451 { 3452 return propagatedOnly ? 0 : getEmissionCached(cache, 0, x, y, z); 3453 } 3454 3455 if (result >= MAX_BRIGHTNESS - 1) return result; 3456 3457 for (int face = 0; face < 6; face++) 3458 { 3459 int xx = x + Facing::STEP_X[face]; 3460 int yy = y + Facing::STEP_Y[face]; 3461 int zz = z + Facing::STEP_Z[face]; 3462 int brightness = getBrightnessCached(cache, layer, xx, yy, zz) - block; 3463 3464 if (brightness > result) result = brightness; 3465 if (result >= MAX_BRIGHTNESS - 1) return result; 3466 } 3467 3468 return result; 3469} 3470 3471// 4J - Made changes here so that lighting goes through a cache, if enabled for this thread 3472void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool force, bool rootOnlyEmissive) 3473{ 3474 lightCache_t *cache = (lightCache_t *)TlsGetValue(tlsIdxLightCache); 3475 __uint64 cacheUse = 0; 3476 3477 if( force ) 3478 { 3479 // 4J - special mode added so we can do lava lighting updates without having all neighbouring chunks loaded in 3480 if (!hasChunksAt(xc, yc, zc, 0)) return; 3481 } 3482 else 3483 { 3484 // 4J - this is normal java behaviour 3485 if (!hasChunksAt(xc, yc, zc, 17)) return; 3486 } 3487 3488#if 0 3489 ///////////////////////////////////////////////////////////////////////////////////////////// 3490 // Get the frequency of the timer 3491 LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime1, qwDeltaTime2; 3492 float fElapsedTime1 = 0.0f; 3493 float fElapsedTime2 = 0.0f; 3494 QueryPerformanceFrequency( &qwTicksPerSec ); 3495 float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart; 3496 3497 QueryPerformanceCounter( &qwTime ); 3498 ///////////////////////////////////////////////////////////////////////////////////////////// 3499#endif 3500 3501 EnterCriticalSection(&m_checkLightCS); 3502 3503 initCachePartial(cache, xc, yc, zc); 3504 3505 // If we're in cached mode, then use memory allocated after the cached data itself for the toCheck array, in an attempt to make both that & the other cached data sit on the CPU L2 cache better. 3506 3507 int *toCheck; 3508 if( cache == NULL ) 3509 { 3510 toCheck = toCheckLevel; 3511 } 3512 else 3513 { 3514 toCheck = (int *)(cache + (16*16*16)); 3515 } 3516 3517 int checkedPosition = 0; 3518 int toCheckCount = 0; 3519 //int darktcc = 0; 3520 3521 3522 // 4J - added 3523 int minXZ = - (dimension->getXZSize() * 16 ) / 2; 3524 int maxXZ = (dimension->getXZSize() * 16 ) / 2 - 1; 3525 if( ( xc > maxXZ ) || ( xc < minXZ ) || ( zc > maxXZ ) || ( zc < minXZ ) ) 3526 { 3527 LeaveCriticalSection(&m_checkLightCS); 3528 return; 3529 } 3530 3531 // Lock 128K of cache (containing all the lighting cache + first 112K of toCheck array) on L2 to try and stop any cached data getting knocked out of L2 by other non-cached reads (or vice-versa) 3532 // if( cache ) XLockL2(XLOCKL2_INDEX_TITLE, cache, 128 * 1024, XLOCKL2_LOCK_SIZE_1_WAY, 0 ); 3533 3534 { 3535 int centerCurrent = getBrightnessCached(cache, layer, xc, yc, zc); 3536 int centerExpected = getExpectedLight(cache, xc, yc, zc, layer, false); 3537 3538 if( centerExpected != centerCurrent && cache ) 3539 { 3540 initCacheComplete(cache, xc, yc, zc); 3541 } 3542 3543 if (centerExpected > centerCurrent) 3544 { 3545 toCheck[toCheckCount++] = 32 | (32 << 6) | (32 << 12); 3546 } 3547 else if (centerExpected < centerCurrent) 3548 { 3549 // 4J - added tcn. This is the code that is run when checkLight has been called for a light source that has got darker / turned off. 3550 // In the original version, after zeroing tiles brightnesses that are deemed to come from this light source, all the zeroed tiles are then passed to the next 3551 // stage of the function to potentially have their brightnesses put back up again. We shouldn't need to consider All these tiles as starting points for this process, now just 3552 // considering the edge tiles (defined as a tile where we have a neighbour that is brightner than can be explained by the original light source we are turning off) 3553 int tcn = 0; 3554 if (layer == LightLayer::Block || true) 3555 { 3556 toCheck[toCheckCount++] = 32 | (32 << 6) | (32 << 12) | (centerCurrent << 18); 3557 while (checkedPosition < toCheckCount) 3558 { 3559 int p = toCheck[checkedPosition++]; 3560 int x = ((p) & 63) - 32 + xc; 3561 int y = ((p >> 6) & 63) - 32 + yc; 3562 int z = ((p >> 12) & 63) - 32 + zc; 3563 int expected = ((p >> 18) & 15); 3564 int current = getBrightnessCached(cache, layer, x, y, z); 3565 if (current == expected) 3566 { 3567 setBrightnessCached(cache, &cacheUse, layer, x, y, z, 0); 3568 // cexp--; // 4J - removed, change from 1.2.3 3569 if (expected > 0) 3570 { 3571 int xd = Mth::abs(x - xc); 3572 int yd = Mth::abs(y - yc); 3573 int zd = Mth::abs(z - zc); 3574 if (xd + yd + zd < 17) 3575 { 3576 bool edge = false; 3577 for (int face = 0; face < 6; face++) 3578 { 3579 int xx = x + Facing::STEP_X[face]; 3580 int yy = y + Facing::STEP_Y[face]; 3581 int zz = z + Facing::STEP_Z[face]; 3582 3583 // 4J - added - don't let this lighting creep out of the normal fixed world and into the infinite water chunks beyond 3584 if( ( xx > maxXZ ) || ( xx < minXZ ) || ( zz > maxXZ ) || ( zz < minXZ ) ) continue; 3585 if( ( yy < 0 ) || ( yy >= maxBuildHeight ) ) continue; 3586 3587 // 4J - some changes here brought forward from 1.2.3 3588 int block = max(1, getBlockingCached(cache, layer, NULL, xx, yy, zz) ); 3589 current = getBrightnessCached(cache, layer, xx, yy, zz); 3590 if ((current == expected - block) && (toCheckCount < (32 * 32 * 32))) // 4J - 32 * 32 * 32 was toCheck.length 3591 { 3592 toCheck[toCheckCount++] = (xx - xc + 32) | ((yy - yc + 32) << 6) | ((zz - zc + 32) << 12) | ((expected - block) << 18); 3593 } 3594 else 3595 { 3596 // 4J - added - keep track of which tiles form the edge of the region we are zeroing 3597 if( current > ( expected - block ) ) 3598 { 3599 edge = true; 3600 } 3601 } 3602 } 3603 // 4J - added - keep track of which tiles form the edge of the region we are zeroing - can store over the original elements in the array because tcn must be <= tcp 3604 if( edge == true ) 3605 { 3606 toCheck[tcn++] = p; 3607 } 3608 } 3609 } 3610 3611 } 3612 } 3613 } 3614 checkedPosition = 0; 3615 // darktcc = tcc; /////////////////////////////////////////////////// 3616 toCheckCount = tcn; // 4J added - we've moved all the edge tiles to the start of the array, so only need to process these now. The original processes all tcc tiles again in the next section 3617 } 3618 } 3619 3620 while (checkedPosition < toCheckCount) 3621 { 3622 int p = toCheck[checkedPosition++]; 3623 int x = ((p) & 63) - 32 + xc; 3624 int y = ((p >> 6) & 63) - 32 + yc; 3625 int z = ((p >> 12) & 63) - 32 + zc; 3626 3627 // If force is set, then this is being used to in a special mode to try and light lava tiles as chunks are being loaded in. In this case, we 3628 // don't want a lighting update to drag in any neighbouring chunks that aren't loaded yet. 3629 if( force ) 3630 { 3631 if( !hasChunkAt(x,y,z) ) 3632 { 3633 continue; 3634 } 3635 } 3636 int current = getBrightnessCached(cache, layer, x, y, z); 3637 3638 // If rootOnlyEmissive flag is set, then only consider the starting tile to be possibly emissive. 3639 bool propagatedOnly = false; 3640 if (layer == LightLayer::Block) 3641 { 3642 if( rootOnlyEmissive ) 3643 { 3644 propagatedOnly = ( x != xc ) || ( y != yc ) || ( z != zc ); 3645 } 3646 } 3647 int expected = getExpectedLight(cache, x, y, z, layer, propagatedOnly); 3648 3649 if (expected != current) 3650 { 3651 setBrightnessCached(cache, &cacheUse, layer, x, y, z, expected); 3652 3653 if (expected > current) 3654 { 3655 int xd = abs(x - xc); 3656 int yd = abs(y - yc); 3657 int zd = abs(z - zc); 3658 bool withinBounds = toCheckCount < (32 * 32 * 32) - 6; // 4J - 32 * 32 * 32 was toCheck.length 3659 if (xd + yd + zd < 17 && withinBounds) 3660 { 3661 // 4J - added extra checks here to stop lighting updates moving out of the actual fixed world and into the infinite water chunks 3662 if( ( x - 1 ) >= minXZ ) { if (getBrightnessCached(cache, layer, x - 1, y, z) < expected) toCheck[toCheckCount++] = (((x - 1 - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - zc) + 32) << 12); } 3663 if( ( x + 1 ) <= maxXZ ) { if (getBrightnessCached(cache, layer, x + 1, y, z) < expected) toCheck[toCheckCount++] = (((x + 1 - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - zc) + 32) << 12); } 3664 if( ( y - 1 ) >= 0 ) { if (getBrightnessCached(cache, layer, x, y - 1, z) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y - 1 - yc) + 32) << 6) + (((z - zc) + 32) << 12); } 3665 if( ( y + 1 ) < maxBuildHeight ) { if (getBrightnessCached(cache, layer, x, y + 1, z) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y + 1 - yc) + 32) << 6) + (((z - zc) + 32) << 12); } 3666 if( ( z - 1 ) >= minXZ ) { if (getBrightnessCached(cache, layer, x, y, z - 1) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - 1 - zc) + 32) << 12); } 3667 if( ( z + 1 ) <= maxXZ ) { if (getBrightnessCached(cache, layer, x, y, z + 1) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y - yc) + 32) << 6) + (((z + 1 - zc) + 32) << 12); } 3668 } 3669 } 3670 } 3671 } 3672 // if( cache ) XUnlockL2(XLOCKL2_INDEX_TITLE); 3673#if 0 3674 QueryPerformanceCounter( &qwNewTime ); 3675 qwDeltaTime1.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; 3676 qwTime = qwNewTime; 3677#endif 3678 3679 flushCache(cache, cacheUse, layer); 3680#if 0 3681 ///////////////////////////////////////////////////////////////// 3682 if( cache ) 3683 { 3684 QueryPerformanceCounter( &qwNewTime ); 3685 qwDeltaTime2.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; 3686 fElapsedTime1 = fSecsPerTick * ((FLOAT)(qwDeltaTime1.QuadPart)); 3687 fElapsedTime2 = fSecsPerTick * ((FLOAT)(qwDeltaTime2.QuadPart)); 3688 if( ( darktcc > 0 ) | ( tcc > 0 ) ) 3689 { 3690 printf("%d %d %d %f + %f = %f\n", darktcc, tcc, darktcc + tcc, fElapsedTime1 * 1000.0f, fElapsedTime2 * 1000.0f, ( fElapsedTime1 + fElapsedTime2 ) * 1000.0f); 3691 } 3692 } 3693 ///////////////////////////////////////////////////////////////// 3694#endif 3695 LeaveCriticalSection(&m_checkLightCS); 3696 3697} 3698 3699 3700bool Level::tickPendingTicks(bool force) 3701{ 3702 return false; 3703} 3704 3705vector<TickNextTickData> *Level::fetchTicksInChunk(LevelChunk *chunk, bool remove) 3706{ 3707 return NULL; 3708} 3709 3710 3711vector<shared_ptr<Entity> > *Level::getEntities(shared_ptr<Entity> except, AABB *bb) 3712{ 3713 return getEntities(except, bb, NULL); 3714} 3715 3716vector<shared_ptr<Entity> > *Level::getEntities(shared_ptr<Entity> except, AABB *bb, const EntitySelector *selector) 3717{ 3718 MemSect(40); 3719 es.clear(); 3720 int xc0 = Mth::floor((bb->x0 - 2) / 16); 3721 int xc1 = Mth::floor((bb->x1 + 2) / 16); 3722 int zc0 = Mth::floor((bb->z0 - 2) / 16); 3723 int zc1 = Mth::floor((bb->z1 + 2) / 16); 3724 3725#ifdef __PSVITA__ 3726#ifdef _ENTITIES_RW_SECTION 3727 // AP - RW critical sections are expensive so enter it here so we only have to call it once instead of X times 3728 EnterCriticalRWSection(&LevelChunk::m_csEntities, false); 3729#else 3730 EnterCriticalSection(&LevelChunk::m_csEntities); 3731#endif 3732#endif 3733 3734 for (int xc = xc0; xc <= xc1; xc++) 3735 for (int zc = zc0; zc <= zc1; zc++) 3736 { 3737 if (hasChunk(xc, zc)) 3738 { 3739 getChunk(xc, zc)->getEntities(except, bb, es, selector); 3740 } 3741 } 3742 MemSect(0); 3743 3744#ifdef __PSVITA__ 3745#ifdef _ENTITIES_RW_SECTION 3746 LeaveCriticalRWSection(&LevelChunk::m_csEntities, false); 3747#else 3748 LeaveCriticalSection(&LevelChunk::m_csEntities); 3749#endif 3750#endif 3751 3752 return &es; 3753} 3754 3755vector<shared_ptr<Entity> > *Level::getEntitiesOfClass(const type_info& baseClass, AABB *bb) 3756{ 3757 return getEntitiesOfClass(baseClass, bb, NULL); 3758} 3759 3760vector<shared_ptr<Entity> > *Level::getEntitiesOfClass(const type_info& baseClass, AABB *bb, const EntitySelector *selector) 3761{ 3762 int xc0 = Mth::floor((bb->x0 - 2) / 16); 3763 int xc1 = Mth::floor((bb->x1 + 2) / 16); 3764 int zc0 = Mth::floor((bb->z0 - 2) / 16); 3765 int zc1 = Mth::floor((bb->z1 + 2) / 16); 3766 vector<shared_ptr<Entity> > *es = new vector<shared_ptr<Entity> >(); 3767 3768#ifdef __PSVITA__ 3769#ifdef _ENTITIES_RW_SECTION 3770 // AP - RW critical sections are expensive so enter it here so we only have to call it once instead of X times 3771 EnterCriticalRWSection(&LevelChunk::m_csEntities, false); 3772#else 3773 EnterCriticalSection(&LevelChunk::m_csEntities); 3774#endif 3775#endif 3776 3777 for (int xc = xc0; xc <= xc1; xc++) 3778 { 3779 for (int zc = zc0; zc <= zc1; zc++) 3780 { 3781 if (hasChunk(xc, zc)) 3782 { 3783 getChunk(xc, zc)->getEntitiesOfClass(baseClass, bb, *es, selector); 3784 } 3785 } 3786 } 3787 3788#ifdef __PSVITA__ 3789#ifdef _ENTITIES_RW_SECTION 3790 LeaveCriticalRWSection(&LevelChunk::m_csEntities, false); 3791#else 3792 LeaveCriticalSection(&LevelChunk::m_csEntities); 3793#endif 3794#endif 3795 3796 return es; 3797} 3798 3799shared_ptr<Entity> Level::getClosestEntityOfClass(const type_info& baseClass, AABB *bb, shared_ptr<Entity> source) 3800{ 3801 vector<shared_ptr<Entity> > *entities = getEntitiesOfClass(baseClass, bb); 3802 shared_ptr<Entity> closest = nullptr; 3803 double closestDistSqr = Double::MAX_VALUE; 3804 //for (Entity entity : entities) 3805 for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) 3806 { 3807 shared_ptr<Entity> entity = *it; 3808 if (entity == source) continue; 3809 double distSqr = source->distanceToSqr(entity); 3810 if (distSqr > closestDistSqr) continue; 3811 closest = entity; 3812 closestDistSqr = distSqr; 3813 } 3814 delete entities; 3815 return closest; 3816} 3817 3818vector<shared_ptr<Entity> > Level::getAllEntities() 3819{ 3820 EnterCriticalSection(&m_entitiesCS); 3821 vector<shared_ptr<Entity> > retVec = entities; 3822 LeaveCriticalSection(&m_entitiesCS); 3823 return retVec; 3824} 3825 3826 3827void Level::tileEntityChanged(int x, int y, int z, shared_ptr<TileEntity> te) 3828{ 3829 if (this->hasChunkAt(x, y, z)) 3830 { 3831 getChunkAt(x, z)->markUnsaved(); 3832 } 3833} 3834 3835#if 0 3836unsigned int Level::countInstanceOf(BaseObject::Class *clas) 3837{ 3838 unsigned int count = 0; 3839 EnterCriticalSection(&m_entitiesCS); 3840 AUTO_VAR(itEnd, entities.end()); 3841 for (AUTO_VAR(it, entities.begin()); it != itEnd; it++) 3842 { 3843 shared_ptr<Entity> e = *it;//entities.at(i); 3844 if (clas->isAssignableFrom(e->getClass())) count++; 3845 } 3846 LeaveCriticalSection(&m_entitiesCS); 3847 3848 return count; 3849} 3850#endif 3851 3852// 4J - added - more limited (but faster) version of above, used to count water animals, animals, monsters for the mob spawner 3853// singleType flag should be true if we are just trying to match eINSTANCEOF exactly, and false if it is a eINSTANCEOF from a group (eTYPE_WATERANIMAL, eTYPE_ANIMAL, eTYPE_MONSTER) 3854unsigned int Level::countInstanceOf(eINSTANCEOF clas, bool singleType, unsigned int *protectedCount/* = NULL*/, unsigned int *couldWanderCount/* = NULL*/) 3855{ 3856 unsigned int count = 0; 3857 if( protectedCount ) *protectedCount = 0; 3858 if( couldWanderCount ) *couldWanderCount = 0; 3859 EnterCriticalSection(&m_entitiesCS); 3860 AUTO_VAR(itEnd, entities.end()); 3861 for (AUTO_VAR(it, entities.begin()); it != itEnd; it++) 3862 { 3863 shared_ptr<Entity> e = *it;//entities.at(i); 3864 if( singleType ) 3865 { 3866 if (e->GetType() == clas) 3867 { 3868 if ( protectedCount && e->isDespawnProtected() ) 3869 { 3870 (*protectedCount)++; 3871 } 3872 3873 if ( couldWanderCount && e->couldWander() ) 3874 { 3875 (*couldWanderCount)++; 3876 } 3877 3878 count++; 3879 } 3880 } 3881 else 3882 { 3883 if (e->instanceof(clas)) count++; 3884 } 3885 } 3886 LeaveCriticalSection(&m_entitiesCS); 3887 3888 return count; 3889} 3890 3891unsigned int Level::countInstanceOfInRange(eINSTANCEOF clas, bool singleType, int range, int x, int y, int z) 3892{ 3893 unsigned int count = 0; 3894 EnterCriticalSection(&m_entitiesCS); 3895 AUTO_VAR(itEnd, entities.end()); 3896 for (AUTO_VAR(it, entities.begin()); it != itEnd; it++) 3897 { 3898 shared_ptr<Entity> e = *it;//entities.at(i); 3899 3900 float sd = e->distanceTo(x,y,z); 3901 if (sd * sd > range * range) 3902 { 3903 continue; 3904 } 3905 3906 if( singleType ) 3907 { 3908 if (e->GetType() == clas) 3909 { 3910 count++; 3911 } 3912 } 3913 else 3914 { 3915 if (e->instanceof(clas)) count++; 3916 } 3917 } 3918 LeaveCriticalSection(&m_entitiesCS); 3919 3920 return count; 3921} 3922 3923void Level::addEntities(vector<shared_ptr<Entity> > *list) 3924{ 3925 //entities.addAll(list); 3926 EnterCriticalSection(&m_entitiesCS); 3927 entities.insert(entities.end(), list->begin(), list->end()); 3928 AUTO_VAR(itEnd, list->end()); 3929 bool deleteDragons = false; 3930 for (AUTO_VAR(it, list->begin()); it != itEnd; it++) 3931 { 3932 entityAdded(*it); 3933 3934 // 4J Stu - Special change to remove duplicate enderdragons that a previous bug might have produced 3935 if( (*it)->GetType() == eTYPE_ENDERDRAGON) 3936 { 3937 deleteDragons = true; 3938 } 3939 } 3940 3941 if(deleteDragons) 3942 { 3943 deleteDragons = false; 3944 for(AUTO_VAR(it, entities.begin()); it != entities.end(); ++it) 3945 { 3946 // 4J Stu - Special change to remove duplicate enderdragons that a previous bug might have produced 3947 if( (*it)->GetType() == eTYPE_ENDERDRAGON) 3948 { 3949 if(deleteDragons) 3950 { 3951 (*it)->remove(); 3952 } 3953 else 3954 { 3955 deleteDragons = true; 3956 } 3957 } 3958 } 3959 } 3960 LeaveCriticalSection(&m_entitiesCS); 3961} 3962 3963 3964void Level::removeEntities(vector<shared_ptr<Entity> > *list) 3965{ 3966 //entitiesToRemove.addAll(list); 3967 entitiesToRemove.insert(entitiesToRemove.end(), list->begin(), list->end()); 3968} 3969 3970bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, int face, shared_ptr<Entity> ignoreEntity, shared_ptr<ItemInstance> item) 3971{ 3972 int targetType = getTile(x, y, z); 3973 Tile *targetTile = Tile::tiles[targetType]; 3974 3975 Tile *tile = Tile::tiles[tileId]; 3976 3977 AABB *aabb = tile->getAABB(this, x, y, z); 3978 if (ignoreEntities) aabb = NULL; 3979 if (aabb != NULL && !isUnobstructed(aabb, ignoreEntity)) return false; 3980 if (targetTile != NULL && 3981 (targetTile == Tile::water || targetTile == Tile::calmWater || targetTile == Tile::lava || 3982 targetTile == Tile::calmLava || targetTile == Tile::fire || targetTile->material->isReplaceable())) 3983 { 3984 targetTile = NULL; 3985 } 3986 if (targetTile != NULL && targetTile->material == Material::decoration && tile == Tile::anvil) return true; 3987 if (tileId > 0 && targetTile == NULL) 3988 { 3989 if (tile->mayPlace(this, x, y, z, face, item)) 3990 { 3991 return true; 3992 } 3993 } 3994 return false; 3995} 3996 3997 3998int Level::getSeaLevel() 3999{ 4000 return seaLevel; 4001} 4002 4003 4004Path *Level::findPath(shared_ptr<Entity> from, shared_ptr<Entity> to, float maxDist, bool canPassDoors, bool canOpenDoors, bool avoidWater, bool canFloat) 4005{ 4006 int x = Mth::floor(from->x); 4007 int y = Mth::floor(from->y + 1); 4008 int z = Mth::floor(from->z); 4009 4010 int r = (int) (maxDist + 16); 4011 int x1 = x - r; 4012 int y1 = y - r; 4013 int z1 = z - r; 4014 int x2 = x + r; 4015 int y2 = y + r; 4016 int z2 = z + r; 4017 Region region = Region(this, x1, y1, z1, x2, y2, z2, 0); 4018 Path *path = (PathFinder(&region, canPassDoors, canOpenDoors, avoidWater, canFloat)).findPath(from.get(), to.get(), maxDist); 4019 return path; 4020} 4021 4022 4023Path *Level::findPath(shared_ptr<Entity> from, int xBest, int yBest, int zBest, float maxDist, bool canPassDoors, bool canOpenDoors, bool avoidWater, bool canFloat) 4024{ 4025 int x = Mth::floor(from->x); 4026 int y = Mth::floor(from->y); 4027 int z = Mth::floor(from->z); 4028 4029 int r = (int) (maxDist + 8); 4030 int x1 = x - r; 4031 int y1 = y - r; 4032 int z1 = z - r; 4033 int x2 = x + r; 4034 int y2 = y + r; 4035 int z2 = z + r; 4036 Region region = Region(this, x1, y1, z1, x2, y2, z2, 0); 4037 Path *path = (PathFinder(&region, canPassDoors, canOpenDoors, avoidWater, canFloat)).findPath(from.get(), xBest, yBest, zBest, maxDist); 4038 return path; 4039} 4040 4041 4042int Level::getDirectSignal(int x, int y, int z, int dir) 4043{ 4044 int t = getTile(x, y, z); 4045 if (t == 0) return Redstone::SIGNAL_NONE; 4046 return Tile::tiles[t]->getDirectSignal(this, x, y, z, dir); 4047} 4048 4049int Level::getDirectSignalTo(int x, int y, int z) 4050{ 4051 int result = Redstone::SIGNAL_NONE; 4052 result = max(result, getDirectSignal(x, y - 1, z, 0)); 4053 if (result >= Redstone::SIGNAL_MAX) return result; 4054 result = max(result, getDirectSignal(x, y + 1, z, 1)); 4055 if (result >= Redstone::SIGNAL_MAX) return result; 4056 result = max(result, getDirectSignal(x, y, z - 1, 2)); 4057 if (result >= Redstone::SIGNAL_MAX) return result; 4058 result = max(result, getDirectSignal(x, y, z + 1, 3)); 4059 if (result >= Redstone::SIGNAL_MAX) return result; 4060 result = max(result, getDirectSignal(x - 1, y, z, 4)); 4061 if (result >= Redstone::SIGNAL_MAX) return result; 4062 result = max(result, getDirectSignal(x + 1, y, z, 5)); 4063 if (result >= Redstone::SIGNAL_MAX) return result; 4064 return result; 4065} 4066 4067bool Level::hasSignal(int x, int y, int z, int dir) 4068{ 4069 return getSignal(x, y, z, dir) > Redstone::SIGNAL_NONE; 4070} 4071 4072int Level::getSignal(int x, int y, int z, int dir) 4073{ 4074 if (isSolidBlockingTile(x, y, z)) 4075 { 4076 return getDirectSignalTo(x, y, z); 4077 } 4078 int t = getTile(x, y, z); 4079 if (t == 0) return Redstone::SIGNAL_NONE; 4080 return Tile::tiles[t]->getSignal(this, x, y, z, dir); 4081} 4082 4083bool Level::hasNeighborSignal(int x, int y, int z) 4084{ 4085 if (getSignal(x, y - 1, z, 0) > 0) return true; 4086 if (getSignal(x, y + 1, z, 1) > 0) return true; 4087 if (getSignal(x, y, z - 1, 2) > 0) return true; 4088 if (getSignal(x, y, z + 1, 3) > 0) return true; 4089 if (getSignal(x - 1, y, z, 4) > 0) return true; 4090 if (getSignal(x + 1, y, z, 5) > 0) return true; 4091 return false; 4092} 4093 4094int Level::getBestNeighborSignal(int x, int y, int z) 4095{ 4096 int best = Redstone::SIGNAL_NONE; 4097 4098 for (int i = 0; i < 6; i++) 4099 { 4100 int signal = getSignal(x + Facing::STEP_X[i], y + Facing::STEP_Y[i], z + Facing::STEP_Z[i], i); 4101 4102 if (signal >= Redstone::SIGNAL_MAX) return Redstone::SIGNAL_MAX; 4103 if (signal > best) best = signal; 4104 } 4105 4106 return best; 4107} 4108 4109// 4J Stu - Added maxYDist param 4110shared_ptr<Player> Level::getNearestPlayer(shared_ptr<Entity> source, double maxDist, double maxYDist /*= -1*/) 4111{ 4112 return getNearestPlayer(source->x, source->y, source->z, maxDist, maxYDist); 4113} 4114 4115// 4J Stu - Added maxYDist param 4116shared_ptr<Player> Level::getNearestPlayer(double x, double y, double z, double maxDist, double maxYDist /*= -1*/) 4117{ 4118 MemSect(21); 4119 double best = -1; 4120 shared_ptr<Player> result = nullptr; 4121 AUTO_VAR(itEnd, players.end()); 4122 for (AUTO_VAR(it, players.begin()); it != itEnd; it++) 4123 { 4124 shared_ptr<Player> p = *it;//players.at(i); 4125 double dist = p->distanceToSqr(x, y, z); 4126 4127 // Allow specifying shorter distances in the vertical 4128 if(maxYDist > 0 && abs(p->y - y) > maxYDist) continue; 4129 4130 // 4J Stu - Added check that this player is still alive 4131 if ((maxDist < 0 || dist < maxDist * maxDist) && (best == -1 || dist < best) && p->isAlive() ) 4132 { 4133 best = dist; 4134 result = p; 4135 } 4136 } 4137 MemSect(0); 4138 return result; 4139} 4140 4141shared_ptr<Player> Level::getNearestPlayer(double x, double z, double maxDist) 4142{ 4143 double best = -1; 4144 shared_ptr<Player> result = nullptr; 4145 AUTO_VAR(itEnd, players.end()); 4146 for (AUTO_VAR(it, players.begin()); it != itEnd; it++) 4147 { 4148 shared_ptr<Player> p = *it; 4149 double dist = p->distanceToSqr(x, p->y, z); 4150 if ((maxDist < 0 || dist < maxDist * maxDist) && (best == -1 || dist < best)) 4151 { 4152 best = dist; 4153 result = p; 4154 } 4155 } 4156 return result; 4157} 4158 4159shared_ptr<Player> Level::getNearestAttackablePlayer(shared_ptr<Entity> source, double maxDist) 4160{ 4161 return getNearestAttackablePlayer(source->x, source->y, source->z, maxDist); 4162} 4163 4164shared_ptr<Player> Level::getNearestAttackablePlayer(double x, double y, double z, double maxDist) 4165{ 4166 double best = -1; 4167 4168 shared_ptr<Player> result = nullptr; 4169 AUTO_VAR(itEnd, players.end()); 4170 for (AUTO_VAR(it, players.begin()); it != itEnd; it++) 4171 { 4172 shared_ptr<Player> p = *it; 4173 4174 // 4J Stu - Added privilege check 4175 if (p->abilities.invulnerable || !p->isAlive() || p->hasInvisiblePrivilege() ) 4176 { 4177 continue; 4178 } 4179 4180 double dist = p->distanceToSqr(x, y, z); 4181 double visibleDist = maxDist; 4182 4183 // decrease the max attackable distance if the target player 4184 // is sneaking or invisible 4185 if (p->isSneaking()) 4186 { 4187 visibleDist *= .8f; 4188 } 4189 if (p->isInvisible()) 4190 { 4191 float coverPercentage = p->getArmorCoverPercentage(); 4192 if (coverPercentage < .1f) 4193 { 4194 coverPercentage = .1f; 4195 } 4196 visibleDist *= (.7f * coverPercentage); 4197 } 4198 4199 if ((visibleDist < 0 || dist < visibleDist * visibleDist) && (best == -1 || dist < best)) 4200 { 4201 best = dist; 4202 result = p; 4203 } 4204 } 4205 return result; 4206} 4207 4208shared_ptr<Player> Level::getPlayerByName(const wstring& name) 4209{ 4210 AUTO_VAR(itEnd, players.end()); 4211 for (AUTO_VAR(it, players.begin()); it != itEnd; it++) 4212 { 4213 if (name.compare( (*it)->getName()) == 0) 4214 { 4215 return *it; //players.at(i); 4216 } 4217 } 4218 return shared_ptr<Player>(); 4219} 4220 4221shared_ptr<Player> Level::getPlayerByUUID(const wstring& name) 4222{ 4223 AUTO_VAR(itEnd, players.end()); 4224 for (AUTO_VAR(it, players.begin()); it != itEnd; it++) 4225 { 4226 if (name.compare( (*it)->getUUID() ) == 0) 4227 { 4228 return *it; //players.at(i); 4229 } 4230 } 4231 return shared_ptr<Player>(); 4232} 4233 4234// 4J Stu - Removed in 1.2.3 ? 4235byteArray Level::getBlocksAndData(int x, int y, int z, int xs, int ys, int zs, bool includeLighting/* = true*/) 4236{ 4237 byteArray result( xs * ys * zs * 5 / 2 ); 4238 int xc0 = x >> 4; 4239 int zc0 = z >> 4; 4240 int xc1 = (x + xs - 1) >> 4; 4241 int zc1 = (z + zs - 1) >> 4; 4242 4243 int p = 0; 4244 4245 int y0 = y; 4246 int y1 = y + ys; 4247 if (y0 < 0) y0 = 0; 4248 if (y1 > Level::maxBuildHeight) y1 = Level::maxBuildHeight; 4249 for (int xc = xc0; xc <= xc1; xc++) 4250 { 4251 int x0 = x - xc * 16; 4252 int x1 = x + xs - xc * 16; 4253 if (x0 < 0) x0 = 0; 4254 if (x1 > 16) x1 = 16; 4255 for (int zc = zc0; zc <= zc1; zc++) 4256 { 4257 int z0 = z - zc * 16; 4258 int z1 = z + zs - zc * 16; 4259 if (z0 < 0) z0 = 0; 4260 if (z1 > 16) z1 = 16; 4261 p = getChunk(xc, zc)->getBlocksAndData(&result, x0, y0, z0, x1, y1, z1, p, includeLighting); 4262 } 4263 } 4264 4265 return result; 4266} 4267 4268// 4J Stu - Removed in 1.2.3 ? 4269void Level::setBlocksAndData(int x, int y, int z, int xs, int ys, int zs, byteArray data, bool includeLighting/* = true*/) 4270{ 4271 int xc0 = x >> 4; 4272 int zc0 = z >> 4; 4273 int xc1 = (x + xs - 1) >> 4; 4274 int zc1 = (z + zs - 1) >> 4; 4275 4276 int p = 0; 4277 4278 int y0 = y; 4279 int y1 = y + ys; 4280 if (y0 < 0) y0 = 0; 4281 if (y1 > Level::maxBuildHeight) y1 = Level::maxBuildHeight; 4282 for (int xc = xc0; xc <= xc1; xc++) 4283 { 4284 int x0 = x - xc * 16; 4285 int x1 = x + xs - xc * 16; 4286 if (x0 < 0) x0 = 0; 4287 if (x1 > 16) x1 = 16; 4288 for (int zc = zc0; zc <= zc1; zc++) 4289 { 4290 int z0 = z - zc * 16; 4291 int z1 = z + zs - zc * 16; 4292 if (z0 < 0) z0 = 0; 4293 if (z1 > 16) z1 = 16; 4294 LevelChunk *lc = getChunk(xc, zc); 4295 // 4J Stu - Unshare before we make any changes incase the server is already another step ahead of us 4296 // Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water. 4297 // This is quite expensive so only actually do it if we are hosting, online, and the update will actually 4298 // change something 4299 bool forceUnshare = false; 4300 if( g_NetworkManager.IsHost() && isClientSide ) 4301 { 4302 forceUnshare = lc->testSetBlocksAndData(data, x0, y0, z0, x1, y1, z1, p); 4303 } 4304 if( forceUnshare ) 4305 { 4306 int size = (x1 - x0 ) * ( y1 - y0 ) * ( z1 - z0 ); 4307 PIXBeginNamedEvent(0,"Chunk data unsharing %d\n", size); 4308 lc->stopSharingTilesAndData(); 4309 PIXEndNamedEvent(); 4310 } 4311 if(p < data.length) p = lc->setBlocksAndData(data, x0, y0, z0, x1, y1, z1, p, includeLighting); 4312 setTilesDirty(xc * 16 + x0, y0, zc * 16 + z0, xc * 16 + x1, y1, zc * 16 + z1); 4313 4314 PIXBeginNamedEvent(0,"Chunk data sharing\n"); 4315 if( g_NetworkManager.IsHost() && isClientSide ) 4316 { 4317 lc->startSharingTilesAndData(); 4318 } 4319 PIXEndNamedEvent(); 4320 } 4321 } 4322} 4323 4324 4325void Level::disconnect(bool sendDisconnect /*= true*/) 4326{ 4327} 4328 4329 4330void Level::checkSession() 4331{ 4332 levelStorage->checkSession(); 4333} 4334 4335 4336void Level::setGameTime(__int64 time) 4337{ 4338 // 4J : WESTY : Added to track game time played by players for other awards. 4339 if (time != 0) // Ignore setting time to 0, done at level start and during tutorial. 4340 { 4341 // Determine step in time and ensure it is reasonable ( we only have an int to store the player stat). 4342 __int64 timeDiff = time - levelData->getGameTime(); 4343 4344 if (timeDiff < 0) 4345 { 4346 timeDiff = 0; 4347 } 4348 else if (timeDiff > 100) 4349 { 4350 // Time differences of more than ~5 seconds are generally not real time passing so ignore (moving dimensions does this) 4351 app.DebugPrintf("Level::setTime: Massive time difference, ignoring for time passed stat (%lli)\n", timeDiff); 4352 timeDiff = 0; 4353 } 4354 4355 // Apply stat to each player. 4356 if ( timeDiff > 0 && levelData->getGameTime() != -1 ) 4357 { 4358 AUTO_VAR(itEnd, players.end()); 4359 for (vector<shared_ptr<Player> >::iterator it = players.begin(); it != itEnd; it++) 4360 { 4361 (*it)->awardStat( GenericStats::timePlayed(), GenericStats::param_time(timeDiff) ); 4362 } 4363 } 4364 } 4365 4366 levelData->setGameTime(time); 4367} 4368 4369__int64 Level::getSeed() 4370{ 4371 return levelData->getSeed(); 4372} 4373 4374__int64 Level::getGameTime() 4375{ 4376 return levelData->getGameTime(); 4377} 4378 4379__int64 Level::getDayTime() 4380{ 4381 return levelData->getDayTime(); 4382} 4383 4384void Level::setDayTime(__int64 newTime) 4385{ 4386 levelData->setDayTime(newTime); 4387} 4388 4389Pos *Level::getSharedSpawnPos() 4390{ 4391 return new Pos(levelData->getXSpawn(), levelData->getYSpawn(), levelData->getZSpawn()); 4392} 4393 4394void Level::setSpawnPos(int x, int y, int z) 4395{ 4396 levelData->setSpawn(x, y, z); 4397} 4398 4399void Level::setSpawnPos(Pos *spawnPos) 4400{ 4401 setSpawnPos(spawnPos->x, spawnPos->y, spawnPos->z); 4402} 4403 4404void Level::ensureAdded(shared_ptr<Entity> entity) 4405{ 4406 int xc = Mth::floor(entity->x / 16); 4407 int zc = Mth::floor(entity->z / 16); 4408 int r = 2; 4409 for (int x = xc - r; x <= xc + r; x++) 4410 { 4411 for (int z = zc - r; z <= zc + r; z++) 4412 { 4413 getChunk(x, z); 4414 } 4415 } 4416 4417 //if (!entities.contains(entity)) 4418 EnterCriticalSection(&m_entitiesCS); 4419 if( find(entities.begin(), entities.end(), entity) == entities.end() ) 4420 { 4421 entities.push_back(entity); 4422 } 4423 LeaveCriticalSection(&m_entitiesCS); 4424} 4425 4426 4427bool Level::mayInteract(shared_ptr<Player> player, int xt, int yt, int zt, int content) 4428{ 4429 return true; 4430} 4431 4432 4433void Level::broadcastEntityEvent(shared_ptr<Entity> e, byte event) 4434{ 4435} 4436 4437ChunkSource *Level::getChunkSource() 4438{ 4439 return chunkSource; 4440} 4441 4442 4443void Level::tileEvent(int x, int y, int z, int tile, int b0, int b1) 4444{ 4445 if (tile > 0) Tile::tiles[tile]->triggerEvent(this, x, y, z, b0, b1); 4446} 4447 4448 4449LevelStorage *Level::getLevelStorage() 4450{ 4451 return levelStorage.get(); 4452} 4453 4454 4455LevelData *Level::getLevelData() 4456{ 4457 return levelData; 4458} 4459 4460GameRules *Level::getGameRules() 4461{ 4462 return levelData->getGameRules(); 4463} 4464 4465void Level::updateSleepingPlayerList() 4466{ 4467} 4468 4469float Level::getThunderLevel(float a) 4470{ 4471 return (oThunderLevel + (thunderLevel - oThunderLevel) * a) * getRainLevel(a); 4472} 4473 4474 4475float Level::getRainLevel(float a) 4476{ 4477 return oRainLevel + (rainLevel - oRainLevel) * a; 4478} 4479 4480 4481void Level::setRainLevel(float rainLevel) 4482{ 4483 oRainLevel = rainLevel; 4484 this->rainLevel = rainLevel; 4485} 4486 4487 4488bool Level::isThundering() 4489{ 4490 return getThunderLevel(1) > 0.9; 4491} 4492 4493 4494bool Level::isRaining() 4495{ 4496 return getRainLevel(1) > 0.2; 4497} 4498 4499 4500bool Level::isRainingAt(int x, int y, int z) 4501{ 4502 if (!isRaining()) return false; 4503 if (!canSeeSky(x, y, z)) return false; 4504 if (getTopRainBlock(x, z) > y) return false; 4505 4506 // 4J - changed to use new method of getting biomedata that caches results of rain & snow 4507 if (biomeHasSnow(x, z)) return false; 4508 return biomeHasRain(x, z); 4509} 4510 4511bool Level::isHumidAt(int x, int y, int z) 4512{ 4513 Biome *biome = getBiome(x, z); 4514 return biome->isHumid(); 4515} 4516 4517 4518void Level::setSavedData(const wstring& id, shared_ptr<SavedData> data) 4519{ 4520 savedDataStorage->set(id, data); 4521} 4522 4523 4524shared_ptr<SavedData> Level::getSavedData(const type_info& clazz, const wstring& id) 4525{ 4526 return savedDataStorage->get(clazz, id); 4527} 4528 4529 4530int Level::getFreeAuxValueFor(const wstring& id) 4531{ 4532 return savedDataStorage->getFreeAuxValueFor(id); 4533} 4534 4535// 4J Added 4536int Level::getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, int centreZC, int scale) 4537{ 4538 return savedDataStorage->getAuxValueForMap(xuid, dimension, centreXC, centreZC, scale); 4539} 4540 4541void Level::globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, int data) 4542{ 4543 AUTO_VAR(itEnd, listeners.end()); 4544 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 4545 { 4546 (*it)->globalLevelEvent(type, sourceX, sourceY, sourceZ, data); 4547 } 4548} 4549 4550void Level::levelEvent(int type, int x, int y, int z, int data) 4551{ 4552 levelEvent(nullptr, type, x, y, z, data); 4553} 4554 4555 4556void Level::levelEvent(shared_ptr<Player> source, int type, int x, int y, int z, int data) 4557{ 4558 AUTO_VAR(itEnd, listeners.end()); 4559 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 4560 { 4561 (*it)->levelEvent(source, type, x, y, z, data); 4562 } 4563} 4564 4565int Level::getMaxBuildHeight() 4566{ 4567 return maxBuildHeight; 4568} 4569 4570int Level::getHeight() 4571{ 4572 return dimension->hasCeiling ? genDepth : maxBuildHeight; 4573} 4574 4575Tickable *Level::makeSoundUpdater(shared_ptr<Minecart> minecart) 4576{ 4577 return NULL; 4578} 4579 4580Random *Level::getRandomFor(int x, int z, int blend) 4581{ 4582 __int64 seed = (x * 341873128712l + z * 132897987541l) + getLevelData()->getSeed() + blend; 4583 random->setSeed(seed); 4584 return random; 4585} 4586 4587TilePos *Level::findNearestMapFeature(const wstring& featureName, int x, int y, int z) 4588{ 4589 return getChunkSource()->findNearestMapFeature(this, featureName, x, y, z); 4590} 4591 4592bool Level::isAllEmpty() 4593{ 4594 return false; 4595} 4596 4597double Level::getHorizonHeight() 4598{ 4599 if (levelData->getGenerator() == LevelType::lvl_flat) 4600 { 4601 return 0.0; 4602 } 4603 return 63.0; 4604} 4605 4606void Level::destroyTileProgress(int id, int x, int y, int z, int progress) 4607{ 4608 AUTO_VAR(itEnd, listeners.end()); 4609 for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) 4610 { 4611 (*it)->destroyTileProgress(id, x, y, z, progress); 4612 } 4613} 4614 4615void Level::createFireworks(double x, double y, double z, double xd, double yd, double zd, CompoundTag *infoTag) 4616{ 4617 4618} 4619 4620Scoreboard *Level::getScoreboard() 4621{ 4622 return scoreboard; 4623} 4624 4625void Level::updateNeighbourForOutputSignal(int x, int y, int z, int source) 4626{ 4627 for (int dir = 0; dir < 4; dir++) 4628 { 4629 int xx = x + Direction::STEP_X[dir]; 4630 int zz = z + Direction::STEP_Z[dir]; 4631 int id = getTile(xx, y, zz); 4632 if (id == 0) continue; 4633 Tile *tile = Tile::tiles[id]; 4634 4635 if (Tile::comparator_off->isSameDiode(id)) 4636 { 4637 tile->neighborChanged(this, xx, y, zz, source); 4638 } 4639 else if (Tile::isSolidBlockingTile(id)) 4640 { 4641 xx += Direction::STEP_X[dir]; 4642 zz += Direction::STEP_Z[dir]; 4643 id = getTile(xx, y, zz); 4644 tile = Tile::tiles[id]; 4645 4646 if (Tile::comparator_off->isSameDiode(id)) 4647 { 4648 tile->neighborChanged(this, xx, y, zz, source); 4649 } 4650 } 4651 } 4652} 4653 4654float Level::getDifficulty(double x, double y, double z) 4655{ 4656 return getDifficulty(Mth::floor(x), Mth::floor(y), Mth::floor(z)); 4657} 4658 4659/** 4660* Returns a difficulty scaled from 0 (easiest) to 1 (normal), may overflow 4661* to 1.5 (hardest) if allowed by player. 4662*/ 4663float Level::getDifficulty(int x, int y, int z) 4664{ 4665 float result = 0; 4666 bool isHard = difficulty == Difficulty::HARD; 4667 4668 if (hasChunkAt(x, y, z)) 4669 { 4670 float moonBrightness = getMoonBrightness(); 4671 4672 result += Mth::clamp(getChunkAt(x, z)->inhabitedTime / (TICKS_PER_DAY * 150.0f), 0.0f, 1.0f) * (isHard ? 1.0f : 0.75f); 4673 result += moonBrightness * 0.25f; 4674 } 4675 4676 if (difficulty < Difficulty::NORMAL) 4677 { 4678 result *= difficulty / 2.0f; 4679 } 4680 4681 return Mth::clamp(result, 0.0f, isHard ? 1.5f : 1.0f);; 4682} 4683 4684bool Level::useNewSeaLevel() 4685{ 4686 return levelData->useNewSeaLevel(); 4687} 4688 4689bool Level::getHasBeenInCreative() 4690{ 4691 return levelData->getHasBeenInCreative(); 4692} 4693 4694bool Level::isGenerateMapFeatures() 4695{ 4696 return levelData->isGenerateMapFeatures(); 4697} 4698 4699int Level::getSaveVersion() 4700{ 4701 return getLevelStorage()->getSaveFile()->getSaveVersion(); 4702} 4703 4704int Level::getOriginalSaveVersion() 4705{ 4706 return getLevelStorage()->getSaveFile()->getOriginalSaveVersion(); 4707} 4708 4709// 4J - determine if a chunk has been done the post-post-processing stage. This happens when *its* neighbours have each been post-processed, and does some final lighting that can 4710// only really be done when the post-processing has placed all possible tiles into this chunk. 4711bool Level::isChunkPostPostProcessed(int x, int z) 4712{ 4713 if( !hasChunk(x, z) ) return false; // This will occur for non-loaded chunks, not for edge chunks 4714 4715 LevelChunk *lc = getChunk(x, z); 4716 if( lc->isEmpty() ) return true; // Since we've already eliminated non-loaded chunks, this should only occur for edge chunks. Consider those as fully processed 4717 4718 return (( lc->terrainPopulated & LevelChunk::sTerrainPostPostProcessed ) == LevelChunk::sTerrainPostPostProcessed); 4719} 4720 4721// 4J added - returns true if a chunk is fully, fully finalised - in that it can be sent to another machine. This is the case when all 8 neighbours of this chunk 4722// have not only been post-processed, but also had the post-post-processing done that they themselves can only do once Their 8 neighbours have been post-processed. 4723bool Level::isChunkFinalised(int x, int z) 4724{ 4725 for( int xo = -1; xo <= 1; xo++ ) 4726 for( int zo = -1; zo <= 1; zo++ ) 4727 { 4728 if( !isChunkPostPostProcessed(x + xo, z + zo) ) return false; 4729 } 4730 4731 return true; 4732} 4733 4734int Level::getUnsavedChunkCount() 4735{ 4736 return m_unsavedChunkCount; 4737} 4738 4739void Level::incrementUnsavedChunkCount() 4740{ 4741 ++m_unsavedChunkCount; 4742} 4743 4744void Level::decrementUnsavedChunkCount() 4745{ 4746 --m_unsavedChunkCount; 4747} 4748 4749bool Level::canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType) 4750{ 4751 int count = 0; 4752 int max = 0; 4753 if(spawnType == eSpawnType_Egg || spawnType == eSpawnType_Portal) 4754 { 4755 switch(type) 4756 { 4757 case eTYPE_VILLAGER: 4758 count = countInstanceOf( eTYPE_VILLAGER, true); 4759 max = MobCategory::MAX_XBOX_VILLAGERS_WITH_SPAWN_EGG; 4760 break; 4761 case eTYPE_CHICKEN: 4762 count = countInstanceOf( eTYPE_CHICKEN, true); 4763 max = MobCategory::MAX_XBOX_CHICKENS_WITH_SPAWN_EGG; 4764 break; 4765 case eTYPE_WOLF: 4766 count = countInstanceOf( eTYPE_WOLF, true); 4767 max = MobCategory::MAX_XBOX_WOLVES_WITH_SPAWN_EGG; 4768 break; 4769 case eTYPE_MUSHROOMCOW: 4770 count = countInstanceOf( eTYPE_MUSHROOMCOW, true); 4771 max = MobCategory::MAX_XBOX_MUSHROOMCOWS_WITH_SPAWN_EGG; 4772 break; 4773 case eTYPE_SQUID: 4774 count = countInstanceOf( eTYPE_SQUID, true); 4775 max = MobCategory::MAX_XBOX_SQUIDS_WITH_SPAWN_EGG; 4776 break; 4777 case eTYPE_SNOWMAN: 4778 count = countInstanceOf( eTYPE_SNOWMAN, true); 4779 max = MobCategory::MAX_XBOX_SNOWMEN; 4780 break; 4781 case eTYPE_VILLAGERGOLEM: 4782 count = countInstanceOf( eTYPE_VILLAGERGOLEM, true); 4783 max = MobCategory::MAX_XBOX_IRONGOLEM; 4784 break; 4785 case eTYPE_WITHERBOSS: 4786 count = countInstanceOf(eTYPE_WITHERBOSS, true) + countInstanceOf(eTYPE_ENDERDRAGON, true); 4787 max = MobCategory::MAX_CONSOLE_BOSS; 4788 break; 4789 default: 4790 if((type & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) == eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) 4791 { 4792 count = countInstanceOf( eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, false); 4793 max = MobCategory::MAX_XBOX_ANIMALS_WITH_SPAWN_EGG; 4794 } 4795 // 4J: Use eTYPE_ENEMY instead of monster (slimes and ghasts aren't monsters) 4796 else if(Entity::instanceof(type, eTYPE_ENEMY)) 4797 { 4798 count = countInstanceOf(eTYPE_ENEMY, false); 4799 max = MobCategory::MAX_XBOX_MONSTERS_WITH_SPAWN_EGG; 4800 } 4801 else if( (type & eTYPE_AMBIENT) == eTYPE_AMBIENT) 4802 { 4803 count = countInstanceOf( eTYPE_AMBIENT, false); 4804 max = MobCategory::MAX_AMBIENT_WITH_SPAWN_EGG; 4805 } 4806 // 4J: Added minecart and boats 4807 else if (Entity::instanceof(type, eTYPE_MINECART)) 4808 { 4809 count = countInstanceOf(eTYPE_MINECART, false); 4810 max = Level::MAX_CONSOLE_MINECARTS; 4811 } 4812 else if (Entity::instanceof(type, eTYPE_BOAT)) 4813 { 4814 count = countInstanceOf(eTYPE_BOAT, true); 4815 max = Level::MAX_XBOX_BOATS; 4816 } 4817 }; 4818 } 4819 else if(spawnType == eSpawnType_Breed) 4820 { 4821 switch(type) 4822 { 4823 case eTYPE_VILLAGER: 4824 count = countInstanceOf( eTYPE_VILLAGER, true); 4825 max = MobCategory::MAX_VILLAGERS_WITH_BREEDING; 4826 break; 4827 case eTYPE_CHICKEN: 4828 count = countInstanceOf( eTYPE_CHICKEN, true); 4829 max = MobCategory::MAX_XBOX_CHICKENS_WITH_BREEDING; 4830 break; 4831 case eTYPE_WOLF: 4832 count = countInstanceOf( eTYPE_WOLF, true); 4833 max = MobCategory::MAX_XBOX_WOLVES_WITH_BREEDING; 4834 break; 4835 case eTYPE_MUSHROOMCOW: 4836 count = countInstanceOf( eTYPE_MUSHROOMCOW, true); 4837 max = MobCategory::MAX_XBOX_MUSHROOMCOWS_WITH_BREEDING; 4838 break; 4839 default: 4840 if((type & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) == eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) 4841 { 4842 count = countInstanceOf( eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, false); 4843 max = MobCategory::MAX_XBOX_ANIMALS_WITH_BREEDING; 4844 } 4845 else if( (type & eTYPE_MONSTER) == eTYPE_MONSTER) 4846 { 4847 4848 } 4849 break; 4850 } 4851 } 4852 // 4J: Interpret 0 as no limit 4853 return max == 0 || count < max; 4854}