fix: particles

This commit is contained in:
Fireblade
2026-06-29 16:55:53 -04:00
parent d2365c8dd4
commit b21faebb45
5 changed files with 195 additions and 25 deletions
+68 -6
View File
@@ -66,6 +66,7 @@
#include "FrustumCuller.h"
#include "../Minecraft.World/BasicTypeContainers.h"
#include "Common/UI/UIScene_SettingsGraphicsMenu.h"
#include "ParticleUtils.h"
#include <unordered_set>
//#define DISABLE_SPU_CODE
@@ -2853,7 +2854,7 @@ void LevelRenderer::addParticle(ePARTICLE_TYPE eParticleType, double x, double y
shared_ptr<Particle> LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticleType, double x, double y, double z, double xa, double ya, double za)
{
if (mc == nullptr || mc->cameraTargetPlayer == nullptr || mc->particleEngine == nullptr)
if (mc == nullptr || mc->cameraTargetPlayer == nullptr || mc->particleEngine == nullptr || mc->options == nullptr)
{
return nullptr;
}
@@ -2863,18 +2864,46 @@ shared_ptr<Particle> LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticle
if( Double::isNaN(x) ) return nullptr;
if( Double::isNaN(y) ) return nullptr;
if( Double::isNaN(z) ) return nullptr;
if( Double::isNaN(xa) ) return nullptr;
if( Double::isNaN(ya) ) return nullptr;
if( Double::isNaN(za) ) return nullptr;
int particleLevel = mc->options->particles;
Level *lev;
int playerIndex = mc->player->GetXboxPad(); // 4J added
lev = level[playerIndex];
Level *lev = nullptr;
int playerIndex = -1;
if (particleLevel == 1)
shared_ptr<LocalPlayer> sourcePlayer = mc->player;
if (sourcePlayer == nullptr && mc->cameraTargetPlayer != nullptr)
{
sourcePlayer = dynamic_pointer_cast<LocalPlayer>(mc->cameraTargetPlayer);
}
if (sourcePlayer != nullptr)
{
playerIndex = sourcePlayer->GetXboxPad();
if (playerIndex >= 0 && playerIndex < XUSER_MAX_COUNT && isReasonableLevelPointer(level[playerIndex]) && level[playerIndex]->dimension != nullptr)
{
lev = level[playerIndex];
}
}
if (lev == nullptr)
{
for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
{
if (mc->localplayers[i] != nullptr && isReasonableLevelPointer(mc->localplayers[i]->level) && mc->localplayers[i]->level->dimension != nullptr)
{
lev = mc->localplayers[i]->level;
break;
}
}
}
if (particleLevel == 1 && lev != nullptr)
{
// when playing at "decreased" particle level, randomly filter
// particles by setting the level to "minimal"
if (level[playerIndex]->random->nextInt(3) == 0)
if (lev->random->nextInt(3) == 0)
{
particleLevel = 2;
}
@@ -2924,6 +2953,39 @@ shared_ptr<Particle> LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticle
if (lev == nullptr)
return nullptr;
if (!isReasonableLevelPointer(lev) || !isReasonableDimensionPointer(lev->dimension))
return nullptr;
bool levIsKnown = false;
if (lev == mc->level || lev == mc->animateTickLevel)
{
levIsKnown = true;
}
else
{
for (unsigned int i = 0; i < XUSER_MAX_COUNT && !levIsKnown; ++i)
{
if (mc->localplayers[i] != nullptr && mc->localplayers[i]->level == lev && isReasonableLevelPointer(mc->localplayers[i]->level) && mc->localplayers[i]->level->dimension != nullptr)
{
levIsKnown = true;
}
}
for (int i = 0; i < 4 && !levIsKnown; ++i)
{
if (this->level[i] == lev && isReasonableLevelPointer(this->level[i]) && this->level[i]->dimension != nullptr)
{
levIsKnown = true;
}
}
}
if (!levIsKnown)
{
return nullptr;
}
if (lev->dimension == nullptr)
return nullptr;
if (particleLevel > 1)
{
// TODO: If any of the particles below are necessary even if
+64 -2
View File
@@ -1,10 +1,50 @@
#include "stdafx.h"
#include "Particle.h"
#include "Tesselator.h"
#include "../Minecraft.Client/Minecraft.h"
#include "../Minecraft.Client/MultiPlayerLevel.h"
#include "../Minecraft.Client/MultiPlayerLocalPlayer.h"
#include "../Minecraft.World/Level.h"
#include "../Minecraft.World/net.minecraft.world.level.dimension.h"
#include "../Minecraft.World/Random.h"
#include "../Minecraft.World/Mth.h"
#include "../Minecraft.World/JavaMath.h"
#include "../Minecraft.World/net.minecraft.world.h"
#include "ParticleUtils.h"
static bool isKnownParticleLevel(Level *lev, Minecraft *mc)
{
if (lev == nullptr || mc == nullptr)
return false;
if (lev == mc->level || lev == mc->animateTickLevel || lev == mc->oldLevel)
return true;
for (unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
{
if (mc->localplayers[i] != nullptr && mc->localplayers[i]->level == lev)
return true;
}
return false;
}
static Level *safeParticleLevel(Level *level)
{
Minecraft *mc = Minecraft::GetInstance();
if (level != nullptr && isReasonableLevelPointer(level) && isKnownParticleLevel(level, mc) && isReasonableDimensionPointer(level->dimension))
{
return level;
}
if (mc != nullptr && mc->level != nullptr && isReasonableLevelPointer(mc->level) && isReasonableDimensionPointer(mc->level->dimension))
{
return static_cast<Level *>(mc->level);
}
return nullptr;
}
/*
protected int tex;
@@ -42,15 +82,37 @@ void Particle::_init(Level *level, double x, double y, double z)
texY = 0;
}
Particle::Particle(Level *level, double x, double y, double z) : Entity(level, false)
Particle::Particle(Level *level, double x, double y, double z) : Entity(nullptr, false)
{
_init(level,x,y,z);
Level *safeLevel = safeParticleLevel(level);
if (safeLevel != nullptr && isReasonableDimensionPointer(safeLevel->dimension))
{
this->level = safeLevel;
dimension = safeLevel->dimension->id;
}
else
{
this->level = nullptr;
}
}
Particle::Particle(Level *level, double x, double y, double z, double xa, double ya, double za) : Entity(level, false)
Particle::Particle(Level *level, double x, double y, double z, double xa, double ya, double za) : Entity(nullptr, false)
{
_init(level,x,y,z);
Level *safeLevel = safeParticleLevel(level);
if (safeLevel != nullptr && isReasonableDimensionPointer(safeLevel->dimension))
{
this->level = safeLevel;
dimension = safeLevel->dimension->id;
}
else
{
this->level = nullptr;
}
xd = xa + static_cast<float>(Math::random() * 2 - 1) * 0.4f;
yd = ya + static_cast<float>(Math::random() * 2 - 1) * 0.4f;
zd = za + static_cast<float>(Math::random() * 2 - 1) * 0.4f;
+28 -15
View File
@@ -34,9 +34,11 @@ ParticleEngine::~ParticleEngine()
void ParticleEngine::add(shared_ptr<Particle> p)
{
if (p == nullptr || p->level == nullptr || p->level->dimension == nullptr) return;
if (p->level != level) return;
int t = p->getParticleTexture();
if (p->level == nullptr || p->level->dimension == nullptr) return;
int l = p->level->dimension->id == 0 ? 0 : ( p->level->dimension->id == -1 ? 1 : 2);
int l = p->level->dimension->id == 0 ? 0 : ( p->level->dimension->id == -1 ? 1 : 2);
int maxParticles;
switch(p->GetType())
{
@@ -69,6 +71,13 @@ void ParticleEngine::tick()
for (unsigned int i = 0; i < particles[l][tt][list].size(); i++)
{
shared_ptr<Particle> p = particles[l][tt][list][i];
if (p == nullptr || p->level == nullptr || p->level != level || p->level->dimension == nullptr)
{
particles[l][tt][list][i] = particles[l][tt][list].back();
particles[l][tt][list].pop_back();
i--;
continue;
}
p->tick();
if (p->removed)
{
@@ -88,6 +97,10 @@ void ParticleEngine::render(shared_ptr<Entity> player, float a, int list)
{
return;
}
if (level == nullptr || level->dimension == nullptr)
{
return;
}
// 4J - change brought forward from 1.2.3
float xa = Camera::xa;
@@ -195,19 +208,19 @@ void ParticleEngine::setLevel(Level *level)
{
this->level = level;
// 4J - we've now got a set of particle vectors for each dimension, and only clearing them when its game over & the level is set to nullptr
if( level == nullptr )
{
for( int l = 0; l < 3; l++ )
{
for (int tt = 0; tt < TEXTURE_COUNT; tt++)
{
for( int list = 0; list < LIST_COUNT; list++ )
{
particles[l][tt][list].clear();
}
}
}
}
if (level == nullptr)
{
for (int l = 0; l < 3; l++)
{
for (int tt = 0; tt < TEXTURE_COUNT; tt++)
{
for (int list = 0; list < LIST_COUNT; list++)
{
particles[l][tt][list].clear();
}
}
}
}
}
void ParticleEngine::destroy(int x, int y, int z, int tid, int data)
+29
View File
@@ -0,0 +1,29 @@
#pragma once
class Level;
class Dimension;
inline bool isReasonablePointer(const void *ptr)
{
if (ptr == nullptr)
return false;
unsigned long long addr = reinterpret_cast<unsigned long long>(ptr);
if (addr <= 0x10000ULL || addr > 0x00007FFFFFFFFFFFULL)
return false;
if ((addr & 0x7ULL) != 0ULL)
return false;
if ((addr & 0xFFFFFFFFULL) == 0ULL)
return false;
return true;
}
inline bool isReasonableLevelPointer(Level *lev)
{
return isReasonablePointer(lev);
}
inline bool isReasonableDimensionPointer(Dimension *dim)
{
return isReasonablePointer(dim);
}
+6 -2
View File
@@ -372,9 +372,13 @@ Entity::Entity(Level *level, bool useSmallId) // 4J - added useSmallId parameter
// resetPos();
setPos(0, 0, 0);
if (level != nullptr && level->dimension != nullptr)
if (level != nullptr)
{
dimension = level->dimension->id;
auto dimensionPtr = level->dimension;
if (dimensionPtr != nullptr)
{
dimension = dimensionPtr->id;
}
}
if( entityData )