Files
MinecraftConsoles/Minecraft.Client/LevelRenderer.h
2026-03-07 03:31:30 +07:00

293 lines
12 KiB
C++

#pragma once
#include "..\Minecraft.World\LevelListener.h"
#include "..\Minecraft.World\Definitions.h"
#include "OffsettedRenderList.h"
#include "..\Minecraft.World\JavaIntHash.h"
#include "..\Minecraft.World\Level.h"
#include "ResourceLocation.h"
#include <xmcore.h>
#ifdef __PS3__
#include "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;
using namespace std;
// 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 _WINDOWS64
static const int MAX_COMMANDBUFFER_ALLOCATIONS = 2047 * 1024 * 1024; // Changed to 2047. 4J had set to 512.
#elif defined _XBOX_ONE
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);
wstring gatherStats1();
wstring gatherStats2();
private:
void resortChunks(int xc, int yc, int zc);
public:
int render(shared_ptr<LivingEntity> 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(shared_ptr<Player> player, HitResult *h, int mode, shared_ptr<ItemInstance> inventoryItem, float a);
void renderDestroyAnimation(Tesselator *t, shared_ptr<Player> player, float a);
void renderHitOutline(shared_ptr<Player> 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 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(shared_ptr<Entity> entity,int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist=16.0f);
void playSoundExceptPlayer(shared_ptr<Player> 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
shared_ptr<Particle> addParticleInternal(ePARTICLE_TYPE eParticleType, double x, double y, double z, double xa, double ya, double za); // 4J added
void entityAdded(shared_ptr<Entity> entity);
void entityRemoved(shared_ptr<Entity> entity);
void playerRemoved(shared_ptr<Entity> 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(shared_ptr<Player> 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 unordered_map<int, vector<shared_ptr<TileEntity> >, 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 vector<shared_ptr<TileEntity>, now hashed by chunk so we can find them
CRITICAL_SECTION m_csRenderableTileEntities;
MultiPlayerLevel *level[4]; // 4J - now one per player
Textures *textures;
// vector<Chunk *> *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;
vector<Chunk *> _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];
unordered_map<int, BlockDestructionProgress *> 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;
vector<RecentTile *> 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<int> dirtyChunksLockFreeStack;
bool dirtyChunkPresent;
int64_t lastDirtyChunkFound;
static const int FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS = 125; // decreased from 250 to 125 - updated by detectiveren
#ifdef _LARGE_WORLDS
static const int MAX_CONCURRENT_CHUNK_REBUILDS = 8; // increased from 4 to 8 - updated by detectiveren
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(LPVOID lpParam);
CRITICAL_SECTION m_csChunkFlags;
#endif
void nonStackDirtyChunksAdded();
int checkAllPresentChunks(bool *faultFound); // 4J - added for testing
};