#pragma once #include "../../Minecraft.World/Level/Events/LevelListener.h" #include "../../Minecraft.World/Util/Definitions.h" #include "OffsettedRenderList.h" #include "../../Minecraft.World/Util/JavaIntHash.h" #include "../../Minecraft.World/Level/Level.h" #ifndef __linux__ #include #endif // __linux__ #ifdef __PS3__ #include "../Platform/PS3/PS3Extras/C4JSpursJob.h" #endif class MultiPlayerLevel; class Textures; class Chunk; class Minecraft; class TileRenderer; class Culler; class Entity; class TileEntity; class Mob; class Vec3; class Particle; class BlockDestructionProgress; class IconRegister; class Tesselator; // AP - this is a system that works out which chunks actually need to be grouped // together via the deferral system when doing chunk::rebuild. Doing this will // reduce the number of chunks built in a single group and reduce the chance of // seeing through the landscape when digging near the edges/corners of a chunk. // I've added another chunk flag to mark a chunk critical so it swipes a bit // from the reference count value (goes to 3 bits to 2). This works on Vita // because it doesn't have split screen reference counting. #ifdef __PSVITA__ #define _CRITICAL_CHUNKS #endif class LevelRenderer : public LevelListener { friend class Chunk; private: static ResourceLocation MOON_LOCATION; static ResourceLocation MOON_PHASES_LOCATION; static ResourceLocation SUN_LOCATION; static ResourceLocation CLOUDS_LOCATION; static ResourceLocation END_SKY_LOCATION; public: static const int CHUNK_XZSIZE = 16; #ifdef _LARGE_WORLDS static const int CHUNK_SIZE = 16; #else static const int CHUNK_SIZE = 16; #endif static const int CHUNK_Y_COUNT = Level::maxBuildHeight / CHUNK_SIZE; #if (defined _XBOX_ONE || defined _WINDOWS64) static const int MAX_COMMANDBUFFER_ALLOCATIONS = 512 * 1024 * 1024; // 4J - added #elif defined __ORBIS__ static const int MAX_COMMANDBUFFER_ALLOCATIONS = 448 * 1024 * 1024; // 4J - added - hard limit is 512 so giving a lot of headroom // here for fragmentation (have seen 16MB lost to fragmentation // in multiplayer crash dump before) #elif defined __PS3__ static const int MAX_COMMANDBUFFER_ALLOCATIONS = 110 * 1024 * 1024; // 4J - added #else static const int MAX_COMMANDBUFFER_ALLOCATIONS = 55 * 1024 * 1024; // 4J - added #endif public: LevelRenderer(Minecraft* mc, Textures* textures); private: void renderStars(); void createCloudMesh(); // 4J added public: void setLevel(int playerIndex, MultiPlayerLevel* level); void allChanged(); void allChanged(int playerIndex); // 4J-PB added void AddDLCSkinsToMemTextures(); public: void renderEntities(Vec3* cam, Culler* culler, float a); std::wstring gatherStats1(); std::wstring gatherStats2(); private: void resortChunks(int xc, int yc, int zc); public: int render(std::shared_ptr player, int layer, double alpha, bool updateChunks); private: int renderChunks(int from, int to, int layer, double alpha); public: int activePlayers(); // 4J - added public: void renderSameAsLast(int layer, double alpha); void tick(); void renderSky(float alpha); void renderHaloRing(float alpha); void renderClouds(float alpha); bool isInCloud(double x, double y, double z, float alpha); void renderAdvancedClouds(float alpha); bool updateDirtyChunks(); public: void renderHit(std::shared_ptr player, HitResult* h, int mode, std::shared_ptr inventoryItem, float a); void renderDestroyAnimation(Tesselator* t, std::shared_ptr player, float a); void renderHitOutline(std::shared_ptr player, HitResult* h, int mode, float a); void render(AABB* b); void setDirty(int x0, int y0, int z0, int x1, int y1, int z1, Level* level); // 4J - added level param void tileChanged(int x, int y, int z); void tileLightChanged(int x, int y, int z); void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1, Level* level); // 4J - added level param #ifdef __PS3__ void cull_SPU(int playerIndex, Culler* culler, float a); void waitForCull_SPU(); C4JSpursJobQueue::Port* m_jobPort_CullSPU; C4JSpursJobQueue::Port* m_jobPort_FindNearestChunk; bool m_bSPUCullStarted[4]; #endif // __PS3__ void cull(Culler* culler, float a); void playStreamingMusic(const std::wstring& name, int x, int y, int z); void playSound(int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist = 16.0f); void playSound(std::shared_ptr entity, int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist = 16.0f); void playSoundExceptPlayer(std::shared_ptr player, int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist = 16.0f); void addParticle(ePARTICLE_TYPE eParticleType, double x, double y, double z, double xa, double ya, double za); // 4J added std::shared_ptr addParticleInternal(ePARTICLE_TYPE eParticleType, double x, double y, double z, double xa, double ya, double za); // 4J added void entityAdded(std::shared_ptr entity); void entityRemoved(std::shared_ptr entity); void playerRemoved(std::shared_ptr entity) { } // 4J added - for when a player is removed from the level's player array, // not just the entity storage void skyColorChanged(); void clear(); void globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, int data); void levelEvent(std::shared_ptr source, int type, int x, int y, int z, int data); void destroyTileProgress(int id, int x, int y, int z, int progress); void registerTextures(IconRegister* iconRegister); typedef std::unordered_map >, IntKeyHash, IntKeyEq> rteMap; private: // debug int m_freezeticks; // used to freeze the clouds // 4J - this block of declarations was scattered round the code but have // gathered everything into one place rteMap renderableTileEntities; // 4J - changed - was // std::vector, // now hashed by chunk so we can find them CRITICAL_SECTION m_csRenderableTileEntities; MultiPlayerLevel* level[4]; // 4J - now one per player Textures* textures; // std::vector *sortedChunks[4]; // 4J - removed - not // sorting our chunks anymore ClipChunkArray chunks[4]; // 4J - now one per player int lastPlayerCount[4]; // 4J - added int xChunks, yChunks, zChunks; int chunkLists; Minecraft* mc; TileRenderer* tileRenderer[4]; // 4J - now one per player int ticks; int starList, skyList, darkList, haloRingList; int cloudList; // 4J added int xMinChunk, yMinChunk, zMinChunk; int xMaxChunk, yMaxChunk, zMaxChunk; int lastViewDistance; int noEntityRenderFrames; int totalEntities; int renderedEntities; int culledEntities; int chunkFixOffs; std::vector _renderChunks; int frame; int repeatList; double xOld[4]; // 4J - now one per player double yOld[4]; // 4J - now one per player double zOld[4]; // 4J - now one per player int totalChunks, offscreenChunks, occludedChunks, renderedChunks, emptyChunks; static const int RENDERLISTS_LENGTH = 4; // 4J - added OffsettedRenderList renderLists[RENDERLISTS_LENGTH]; std::unordered_map destroyingBlocks; Icon** breakingTextures; public: void fullyFlagRenderableTileEntitiesToBeRemoved(); // 4J added CRITICAL_SECTION m_csDirtyChunks; bool m_nearDirtyChunk; // 4J - Destroyed Tile Management - these things added so we can track tiles // which have been recently destroyed, and provide temporary collision for // them until the render data has been updated to reflect this change class DestroyedTileManager { private: class RecentTile { public: int x; int y; int z; Level* level; AABBList boxes; int timeout_ticks; bool rebuilt; RecentTile(int x, int y, int z, Level* level); ~RecentTile(); }; CRITICAL_SECTION m_csDestroyedTiles; std::vector m_destroyedTiles; public: void destroyingTileAt( Level* level, int x, int y, int z); // For game to let this manager know that a tile is about // to be destroyed (must be called before it actually is) void updatedChunkAt( Level* level, int x, int y, int z, int veryNearCount); // For chunk rebuilding to inform the manager // that a chunk (a 16x16x16 tile render chunk) // has been updated void addAABBs(Level* level, AABB* box, AABBList* boxes); // For game to get any AABBs that the // user should be colliding with as // render data has not yet been updated void tick(); DestroyedTileManager(); ~DestroyedTileManager(); }; DestroyedTileManager* destroyedTileManager; float destroyProgress; // 4J - added for new render list handling // This defines the maximum size of renderable level, must be big enough to // cope with actual size of level + view distance at each side so that we // can render the "infinite" sea at the edges static const int MAX_LEVEL_RENDER_SIZE[3]; static const int DIMENSION_OFFSETS[3]; // This is the TOTAL area of columns of chunks to be allocated for render // round the players. So for one player, it would be a region of // sqrt(PLAYER_RENDER_AREA) x sqrt(PLAYER_RENDER_AREA) #ifdef _LARGE_WORLDS static const int PLAYER_VIEW_DISTANCE = 18; // Straight line distance from centre to extent of visible world static const int PLAYER_RENDER_AREA = (PLAYER_VIEW_DISTANCE * PLAYER_VIEW_DISTANCE * 4); #else static const int PLAYER_RENDER_AREA = 400; #endif static int getDimensionIndexFromId(int id); static int getGlobalIndexForChunk(int x, int y, int z, Level* level); static int getGlobalIndexForChunk(int x, int y, int z, int dimensionId); static bool isGlobalIndexInSameDimension(int idx, Level* level); static int getGlobalChunkCount(); static int getGlobalChunkCountForOverworld(); // Get/set/clear individual flags bool getGlobalChunkFlag(int x, int y, int z, Level* level, unsigned char flag, unsigned char shift = 0); void setGlobalChunkFlag(int x, int y, int z, Level* level, unsigned char flag, unsigned char shift = 0); void setGlobalChunkFlag(int index, unsigned char flag, unsigned char shift = 0); void clearGlobalChunkFlag(int x, int y, int z, Level* level, unsigned char flag, unsigned char shift = 0); // Get/set whole byte of flags unsigned char getGlobalChunkFlags(int x, int y, int z, Level* level); void setGlobalChunkFlags(int x, int y, int z, Level* level, unsigned char flags); // Reference counting unsigned char incGlobalChunkRefCount(int x, int y, int z, Level* level); unsigned char decGlobalChunkRefCount(int x, int y, int z, Level* level); // Actual storage for flags unsigned char* globalChunkFlags; // The flag definitions static const int CHUNK_FLAG_COMPILED = 0x01; static const int CHUNK_FLAG_DIRTY = 0x02; static const int CHUNK_FLAG_EMPTY0 = 0x04; static const int CHUNK_FLAG_EMPTY1 = 0x08; static const int CHUNK_FLAG_EMPTYBOTH = 0x0c; static const int CHUNK_FLAG_NOTSKYLIT = 0x10; #ifdef _CRITICAL_CHUNKS static const int CHUNK_FLAG_CRITICAL = 0x20; static const int CHUNK_FLAG_CUT_OUT = 0x40; static const int CHUNK_FLAG_REF_MASK = 0x01; static const int CHUNK_FLAG_REF_SHIFT = 7; #else static const int CHUNK_FLAG_REF_MASK = 0x07; static const int CHUNK_FLAG_REF_SHIFT = 5; #endif XLockFreeStack dirtyChunksLockFreeStack; bool dirtyChunkPresent; int64_t lastDirtyChunkFound; static const int FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS = 250; #ifdef _LARGE_WORLDS static const int MAX_CONCURRENT_CHUNK_REBUILDS = 4; static const int MAX_CHUNK_REBUILD_THREADS = MAX_CONCURRENT_CHUNK_REBUILDS - 1; static Chunk permaChunk[MAX_CONCURRENT_CHUNK_REBUILDS]; static C4JThread* rebuildThreads[MAX_CHUNK_REBUILD_THREADS]; static C4JThread::EventArray* s_rebuildCompleteEvents; static C4JThread::Event* s_activationEventA[MAX_CHUNK_REBUILD_THREADS]; static void staticCtor(); static int rebuildChunkThreadProc(void* lpParam); CRITICAL_SECTION m_csChunkFlags; #endif void nonStackDirtyChunksAdded(); int checkAllPresentChunks(bool* faultFound); // 4J - added for testing };