Merge remote-tracking branch 'origin/main' into experimental

This commit is contained in:
github-actions
2026-05-03 15:01:11 +00:00
42 changed files with 456 additions and 54 deletions

View File

@@ -272,7 +272,23 @@ const WCHAR *ConsoleSoundEngine::wchSoundNames[eSoundType_MAX]=
L"item.armor.equip_generic6",
L"damage.critical", //eSoundType_DAMAGE_CRITICAL,
L"item.elytra.flying" // eSoundType_ITEM_ELYTRA_FLYING
L"item.elytra.flying", // eSoundType_ITEM_ELYTRA_FLYING
L"mob.guardian.attack_loop",
L"mob.guardian.guardian_death",
L"mob.guardian.guardian_hit",
L"mob.guardian.flop",
L"mob.guardian.land_death",
L"mob.guardian.land_hit",
L"mob.guardian.land_idle",
L"mob.guardian.curse",
L"mob.guardian.elder_death",
L"mob.guardian.elder_hit",
L"mob.guardian.elder_idle"
};

View File

@@ -3,6 +3,7 @@
#include "../Minecraft.World/Mth.h"
#include "ModelPart.h"
#include "../Minecraft.World/Guardian.h"
#include <EntityRenderDispatcher.h>
@@ -70,34 +71,41 @@ void GuardianModel::setupAnim(float time, float r, float bob, float yRot, float
float afloat4[] = {-8.0f, -8.0f, -8.0f, -8.0f, 0.0f, 0.0f, 0.0f, 0.0f, 8.0f, 8.0f, 8.0f, 8.0f };
float afloat5[] = { 8.0f, -8.0f, 0.0f, 0.0f,-8.0f,-8.0f, 8.0f, 8.0f, 8.0f, -8.0f, 0.0f, 0.0f };
// Body orientation
guardianBody->yRot = yRot / (180.0f / (float)PI);
guardianBody->xRot = xRot / (180.0f / (float)PI);
guardianEye->z = -8.25f;
shared_ptr<LivingEntity> eyeTarget = nullptr;
if (guardian->hasTargetedEntity())
{
shared_ptr<LivingEntity> target = guardian->getTargetedEntity();
if (target)
{
double d0 = (guardian->y + guardian->getEyeHeight())
- (target->y + target->getEyeHeight());
guardianEye->y = (d0 > 0.0) ? 0.0f : 1.0f;
eyeTarget = guardian->getTargetedEntity();
}
double dx = target->x - guardian->x;
double dz = target->z - guardian->z;
float targetYaw = (float)(atan2(dz, dx) * 180.0 / PI) - 90.0f;
float diff = Mth::wrapDegrees(targetYaw - guardian->yRot);
float clamped = diff / 45.0f;
if (clamped < -2.0f) clamped = -2.0f;
if (clamped > 2.0f) clamped = 2.0f;
guardianEye->x = clamped;
}
if (eyeTarget == nullptr && EntityRenderDispatcher::instance != nullptr)
{
eyeTarget = EntityRenderDispatcher::instance->cameraEntity;
}
if (eyeTarget != nullptr)
{
double d0 = (guardian->y + guardian->getEyeHeight())
- (eyeTarget->y + eyeTarget->getEyeHeight());
guardianEye->y = (d0 > 0.0) ? 0.0f : 1.0f;
double dx = eyeTarget->x - guardian->x;
double dz = eyeTarget->z - guardian->z;
float targetYaw = (float)(atan2(dz, dx) * 180.0 / PI) - 90.0f;
float diff = Mth::wrapDegrees(targetYaw - guardian->yRot);
float clamped = diff / 45.0f;
if (clamped < -2.0f) clamped = -2.0f;
if (clamped > 2.0f) clamped = 2.0f;
guardianEye->x = clamped;
}
else
{
@@ -106,6 +114,7 @@ void GuardianModel::setupAnim(float time, float r, float bob, float yRot, float
}
float f1 = (1.0f - guardian->getSpikesAnimation(0.0f)) * 0.55f;
for (int i = 0; i < 12; ++i)

View File

@@ -110,8 +110,6 @@ void GuardianRenderer::render(shared_ptr<Entity> _mob, double x, double y, doubl
float time = (float)mob->tickCount + a;
float texVOff = -time * 0.2f - floor(-time * 0.1f);
float eyeHeight = mob->getEyeHeight();
if (mob && mob->isElder())
eyeHeight = mob->bbHeight * 0.5f * 2.35f;
double targetX = target->xo + (target->x - target->xo) * a;
@@ -138,8 +136,8 @@ void GuardianRenderer::render(shared_ptr<Entity> _mob, double x, double y, doubl
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDepthMask(false);
glPushMatrix();
glTranslatef((float)x, (float)y + eyeHeight, (float)z);
@@ -214,11 +212,22 @@ void GuardianRenderer::render(shared_ptr<Entity> _mob, double x, double y, doubl
glDepthMask(true);
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LIGHTING);
glEnable(GL_CULL_FACE);
glPopMatrix();
}
void GuardianRenderer::scale(shared_ptr<LivingEntity> mob, float a)
{
shared_ptr<Guardian> guardian = dynamic_pointer_cast<Guardian>(mob);
if (guardian && guardian->isElder())
{
glScalef(2.35f, 2.35f, 2.35f);
}
}
void GuardianRenderer::renderModel(shared_ptr<LivingEntity> mob, float wp, float ws, float bob,
float headRotMinusBodyRot, float headRotx, float scale)
{
@@ -226,10 +235,11 @@ void GuardianRenderer::renderModel(shared_ptr<LivingEntity> mob, float wp, float
if (guardian && guardian->isElder())
{
glPushMatrix();
glTranslatef(0.0f, -2.0f, 0.0f);
glScalef(2.35f, 2.35f, 2.35f);
LivingEntityRenderer::renderModel(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale);
glPopMatrix();
}
else

View File

@@ -20,7 +20,7 @@ private:
public:
GuardianRenderer(Model *model, float shadow);
void scale(shared_ptr<LivingEntity> mob, float a)override;
virtual bool shouldRender(shared_ptr<Entity> mob, float camX, float camY, float camZ) override;

View File

@@ -28,6 +28,7 @@
#include "BreakingItemParticle.h"
#include "SnowShovelParticle.h"
#include "BreakingItemParticle.h"
#include "MobAppearanceParticle.h"
#include "HeartParticle.h"
#include "HugeExplosionParticle.h"
#include "HugeExplosionSeedParticle.h"
@@ -822,6 +823,7 @@ void LevelRenderer::renderChunksDirect(int layer, double alpha)
#ifdef __PSVITA__
#include <stdlib.h>
// this is need to sort the chunks by depth
typedef struct
{
@@ -2859,7 +2861,7 @@ shared_ptr<Particle> LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticle
// 4J - the java code doesn't distance cull these two particle types, we need to implement this behaviour differently as our distance check is
// mixed up with other things
bool distCull = true;
if ( (eParticleType == eParticleType_hugeexplosion) || (eParticleType == eParticleType_largeexplode) || (eParticleType == eParticleType_dragonbreath) || (eParticleType == eParticleType_wake))
if ( (eParticleType == eParticleType_hugeexplosion) || (eParticleType == eParticleType_largeexplode) || (eParticleType == eParticleType_dragonbreath) || (eParticleType == eParticleType_wake)||(eParticleType == eParticleType_mobAppearance))
{
distCull = false;
}
@@ -3075,6 +3077,10 @@ shared_ptr<Particle> LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticle
case eParticleType_barrier:
particle = std::make_shared<BarrierParticle>(lev, x, y, z, xa, ya, za);
break;
case eParticleType_mobAppearance:
particle = std::make_shared<MobAppearanceParticle>(lev, x, y, z);
break;
default:
if( ( eParticleType >= eParticleType_iconcrack_base ) && ( eParticleType <= eParticleType_iconcrack_last ) )
{

View File

@@ -0,0 +1,151 @@
#include "stdafx.h"
#include "MobAppearanceParticle.h"
#include "EntityRenderDispatcher.h"
#include "../Minecraft.World/Guardian.h"
#include "../Minecraft.World/Level.h"
MobAppearanceParticle::MobAppearanceParticle(Level* level, double x, double y, double z)
: Particle(level, x, y, z, 0.0, 0.0, 0.0)
{
this->rCol = 1.0f;
this->gCol = 1.0f;
this->bCol = 1.0f;
this->xd = 0.0;
this->yd = 0.0;
this->zd = 0.0;
this->gravity = 0.0f;
this->lifetime = 30;
this->alpha = 0.5;
}
MobAppearanceParticle::~MobAppearanceParticle() {}
int MobAppearanceParticle::getParticleTexture()
{
return 3;
}
eINSTANCEOF MobAppearanceParticle::GetType()
{
return (eINSTANCEOF)eTYPE_ELDER_GUARDIAN;
}
void MobAppearanceParticle::tick()
{
if (guardianEntity == nullptr)
{
auto g = std::make_shared<Guardian>(level);
g->setElderClient();
guardianEntity = g;
}
Particle::tick();
}
void MobAppearanceParticle::render(
Tesselator* /*t*/,
float partialTicks,
float /*xa*/,
float /*ya*/,
float /*za*/,
float /*xa2*/,
float /*za2*/)
{
if (guardianEntity == nullptr)
return;
shared_ptr<LivingEntity> cameraEntity = EntityRenderDispatcher::instance->cameraEntity;
if (cameraEntity == nullptr)
return;
{
double dx = cameraEntity->x - x;
double dy = cameraEntity->y - y;
double dz = cameraEntity->z - z;
if (dx*dx + dy*dy + dz*dz > 4.0 * 4.0)
return;
}
float progress = ((float)age + partialTicks) / (float)lifetime;
float alpha = 0.05f + 0.5f * sinf(progress * (float)PI);
const float scale = 1.0f / 2.35f;
const float fullBright = 240.0f;
double camX = cameraEntity->xOld + (cameraEntity->x - cameraEntity->xOld) * partialTicks;
double camY = cameraEntity->yOld + (cameraEntity->y - cameraEntity->yOld) * partialTicks;
double camZ = cameraEntity->zOld + (cameraEntity->z - cameraEntity->zOld) * partialTicks;
float camYaw = cameraEntity->yRotO + (cameraEntity->yRot - cameraEntity->yRotO) * partialTicks;
float camPitch = cameraEntity->xRotO + (cameraEntity->xRot - cameraEntity->xRotO) * partialTicks;
double savedXOff = EntityRenderDispatcher::xOff;
double savedYOff = EntityRenderDispatcher::yOff;
double savedZOff = EntityRenderDispatcher::zOff;
EntityRenderDispatcher::xOff = camX;
EntityRenderDispatcher::yOff = camY;
EntityRenderDispatcher::zOff = camZ;
glMultiTexCoord2f(GL_TEXTURE1, fullBright, fullBright);
glDepthMask(true);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPushMatrix();
float px = (float)(camX - Particle::xOff);
float py = (float)(camY - Particle::yOff);
float pz = (float)(camZ - Particle::zOff);
glTranslatef(px, py, pz);
glColor4f(1.0f, 1.0f, 1.0f, alpha);
glTranslatef(0.0f, 0.0f, 0.0f);
glRotatef(180.0f - camYaw, 0.0f, 1.0f, 0.0f);
glRotatef(60.0f - 150.0f * progress - camPitch, 1.0f, 0.0f, 0.0f);
glTranslatef(0.0f, -0.4f, -1.5f);
glScalef(scale, scale, scale);
guardianEntity->yRot = guardianEntity->yRotO = 0.0f;
guardianEntity->xRot = guardianEntity->xRotO = 0.0f;
EntityRenderDispatcher::instance->render(
guardianEntity,
0.0, 0.0, 0.0,
0.0f,
partialTicks);
glPopMatrix();
EntityRenderDispatcher::xOff = savedXOff;
EntityRenderDispatcher::yOff = savedYOff;
EntityRenderDispatcher::zOff = savedZOff;
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
}
shared_ptr<Particle> MobAppearanceParticle::Provider::createParticle(
ePARTICLE_TYPE /*type*/,
Level* level,
double x,
double y,
double z,
arrayWithLength<int> /*params*/)
{
return std::make_shared<MobAppearanceParticle>(level, x, y, z);
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include "Particle.h"
#include "Tesselator.h"
#include "../Minecraft.World/Guardian.h"
class MobAppearanceParticle : public Particle
{
public:
class Provider
{
public:
shared_ptr<Particle> createParticle(
ePARTICLE_TYPE type,
Level* level,
double x,
double y,
double z,
arrayWithLength<int> params);
};
MobAppearanceParticle(Level* level, double x, double y, double z);
virtual ~MobAppearanceParticle();
virtual int getParticleTexture() override;
virtual eINSTANCEOF GetType() override;
virtual void tick() override;
virtual void render(
Tesselator* t,
float a,
float xa,
float ya,
float za,
float xa2,
float za2) override;
private:
shared_ptr<Guardian> guardianEntity;
};

View File

@@ -748,6 +748,8 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_PARTICLE
"${CMAKE_CURRENT_SOURCE_DIR}/WaterDropParticle.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ParticleType.h"
"${CMAKE_CURRENT_SOURCE_DIR}/ParticleType.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MobAppearanceParticle.h"
"${CMAKE_CURRENT_SOURCE_DIR}/MobAppearanceParticle.cpp"
)
source_group("net/minecraft/client/particle" FILES ${_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_PARTICLE})

View File

@@ -4,6 +4,8 @@
get_filename_component(_MS_SRC "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(_MINECRAFT_SERVER_COMMON_ROOT
"${_MS_SRC}/../Minecraft.Client/MobAppearanceParticle.h"
"${_MS_SRC}/../Minecraft.Client/MobAppearanceParticle.cpp"
"${_MS_SRC}/../Minecraft.Client/AbstractTexturePack.cpp"
"${_MS_SRC}/../Minecraft.Client/AchievementPopup.cpp"
"${_MS_SRC}/../Minecraft.Client/AchievementScreen.cpp"

View File

@@ -202,12 +202,7 @@ float Guardian::getSpikesAnimation(float partialTicks)
int Guardian::getAmbientSound() { return -1; }
int Guardian::getHurtSound() { return -1; }
int Guardian::getDeathSound() { return -1; }
float Guardian::getSoundVolume() { return 1.0f; }
int Guardian::getDeathLoot() { return 0; }
bool Guardian::makeStepSound() { return false; }
void Guardian::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
{
@@ -261,31 +256,36 @@ void Guardian::serverAiStep()
{
WaterAnimal::serverAiStep();
if (isElder() && !level->isClientSide)
if (isElder() && !level->isClientSide)
{
bool periodicTick = ((tickCount + entityId) % 1200 == 0);
auto& players = level->players;
for (int i = 0; i < (int)players.size(); i++)
{
if (((tickCount + entityId) % 1200 == 0))
shared_ptr<Player> player = players[i];
if (!player) continue;
if (distanceToSqr(player) >= 2500.0) continue;
if (player->abilities.invulnerable) continue;
MobEffectInstance* existing = player->getEffect(MobEffect::digSlowdown);
bool noEffect = (existing == nullptr);
bool weakEffect = (existing != nullptr && existing->getAmplifier() < 2);
bool shortEffect= (existing != nullptr && existing->getDuration() < 1200);
bool applyNow = noEffect || weakEffect || (periodicTick && shortEffect);
if (applyNow)
{
auto& players = level->players;
for (int i = 0; i < (int)players.size(); i++)
{
shared_ptr<Player> player = players[i];
if (!player) continue;
player->addEffect(new MobEffectInstance(MobEffect::digSlowdown->id, 6000, 2));
if (distanceToSqr(player) >= 2500.0)
continue;
if (player->abilities.invulnerable)
continue;
MobEffectInstance *existing = player->getEffect(MobEffect::digSlowdown);
if (existing == nullptr || existing->getAmplifier() < 2 || existing->getDuration() < 1200)
{
player->addEffect(new MobEffectInstance(MobEffect::digSlowdown->id, 6000, 2));
}
}
level->broadcastEntityEvent(shared_from_this(), (byte)8);
playCurseSound();
}
}
}
if (!hasTargetedEntity())
@@ -320,6 +320,7 @@ void Guardian::serverAiStep()
if (attackTimer == 1)
{
level->broadcastEntityEvent(shared_from_this(), 21);
playAttackSound();
}
else if (attackTimer >= getAttackDuration())
{
@@ -379,6 +380,15 @@ void Guardian::aiStep()
updateSize(isElder());
clientSideTailAnimationO = clientSideTailAnimation;
if (!isInWater() && onGround)
{
if (clientSideTouchedGround)
{
playFlopSound();
clientSideTouchedGround = false;
}
}
if (!isInWater())
{
clientSideTailAnimation = 2.0f;
@@ -478,4 +488,140 @@ MobGroupData *Guardian::finalizeMobSpawn(MobGroupData *groupData, int extraData)
if (extraData == 1)
setElder(true);
return groupData;
}
void Guardian::handleEntityEvent(byte eventId)
{
if (eventId == 8 && level->isClientSide && isElder())
{
shared_ptr<Player> localPlayer = level->getNearestPlayer(x, y, z, 64.0);
if (localPlayer != nullptr)
{
level->addParticle(
eParticleType_mobAppearance,
localPlayer->x,
localPlayer->bb->y0,
localPlayer->z,
0.0, 0.0, 0.0);
}
}
WaterAnimal::handleEntityEvent(eventId);
}
int Guardian::getAmbientSound()
{
if (!isInWater())
{
if (isElder())
{
return eSoundType_MOB_ELDER_GUARDIAN_IDLE;
}
else
{
return eSoundType_MOB_GUARDIAN_LAND_IDLE;
}
}
return -1;
}
int Guardian::getHurtSound()
{
if (!isInWater())
{
if (isElder())
{
return eSoundType_MOB_ELDER_GUARDIAN_HIT;
}
else
{
return eSoundType_MOB_GUARDIAN_LAND_HIT;
}
}
else
{
if (isElder())
{
return eSoundType_MOB_ELDER_GUARDIAN_HIT;
}
else
{
return eSoundType_MOB_GUARDIAN_HIT;
}
}
}
int Guardian::getDeathSound()
{
if (!isInWater())
{
if (isElder())
return eSoundType_MOB_ELDER_GUARDIAN_DEATH;
else
return eSoundType_MOB_GUARDIAN_LAND_DEATH;
}
else
{
if (isElder())
return eSoundType_MOB_ELDER_GUARDIAN_DEATH;
else
return eSoundType_MOB_GUARDIAN_DEATH;
}
}
bool Guardian::makeStepSound()
{
return false;
}
void Guardian::playFlopSound()
{
level->playSound(x, y, z, eSoundType_MOB_GUARDIAN_FLOP, getSoundVolume(), 1.0f);
}
void Guardian::playAttackSound()
{
level->playSound(x, y, z, eSoundType_MOB_GUARDIAN_ATTACK_LOOP, getSoundVolume(), 1.0f);
}
void Guardian::playCurseSound()
{
level->playSound(x, y, z, eSoundType_MOB_ELDER_GUARDIAN_CURSE, getSoundVolume(), 1.0f);
}
float Guardian::getSoundVolume()
{
return 1.0f;
}
int Guardian::getDeathLoot()
{
return 0;
}

View File

@@ -36,6 +36,9 @@ protected:
virtual float getSoundVolume();
virtual int getDeathLoot();
virtual bool makeStepSound();
void playFlopSound();
void playAttackSound();
void playCurseSound();
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
virtual void serverAiStep();
@@ -66,6 +69,7 @@ public:
float getTailAnimation(float partialTicks);
float getSpikesAnimation(float partialTicks);
float getAttackAnimationScale(float partialTicks);
virtual void handleEntityEvent(byte eventId) override;
protected:
void lookAt(shared_ptr<Entity> e, float yMax, float xMax);
@@ -76,4 +80,5 @@ private:
float tx, ty, tz;
int attackTimer;
shared_ptr<LivingEntity> targetedEntity;
};

View File

@@ -41,6 +41,7 @@ enum ePARTICLE_TYPE
eParticleType_angryVillager,
eParticleType_happyVillager,
eParticleType_fireworksspark,
eParticleType_mobAppearance,
// 4J-JEV: In the java, the particle name was used to sneak parameters in for the Terrain and IconCrack particle constructors.

View File

@@ -263,7 +263,19 @@ enum eSOUND_TYPE
eSoundType_DAMAGE_CRITICAL,
eSoundType_ITEM_ELYTRA_FLYING,
eSoundType_MOB_GUARDIAN_ATTACK_LOOP,
eSoundType_MOB_GUARDIAN_DEATH,
eSoundType_MOB_GUARDIAN_HIT,
eSoundType_MOB_GUARDIAN_FLOP,
eSoundType_MOB_GUARDIAN_LAND_DEATH,
eSoundType_MOB_GUARDIAN_LAND_HIT,
eSoundType_MOB_GUARDIAN_LAND_IDLE,
eSoundType_MOB_ELDER_GUARDIAN_CURSE,
eSoundType_MOB_ELDER_GUARDIAN_DEATH,
eSoundType_MOB_ELDER_GUARDIAN_HIT,
eSoundType_MOB_ELDER_GUARDIAN_IDLE,
eSoundType_MAX
};