mfeat: added early access elytra in creative for bug testing/accuracy comparison
TODO: replace temporary atlas, Properly implement 3d skulls
This commit is contained in:
Tranqlmao
2026-04-24 20:00:35 -04:00
parent 7db8860ea4
commit 4b6e9f8eb2
31 changed files with 889 additions and 97 deletions
+85 -1
View File
@@ -607,7 +607,91 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume, floa
/////////////////////////////////////////////
//
// playUI
//
// startElytraSound / stopElytraSound
// Manages a single persistent looping sound for elytra gliding.
// Call startElytraSound every tick while gliding (it no-ops if already running,
// just updates volume). Call stopElytraSound when gliding ends.
//
// IMPORTANT: m_elytraLoopingSound is NOT added to m_activeSounds.
// The tick() cleanup loop deletes sounds where is_playing()==false.
// A looping sound briefly reports is_playing()==false at the loop point,
// which would cause tick() to free it and leave m_elytraLoopingSound dangling.
//
/////////////////////////////////////////////
void SoundEngine::startElytraSound(float x, float y, float z, float volume, float pitch)
{
// If already initialized just update volume and pitch - never reinitialize mid-flight.
if (m_elytraLoopingSound != nullptr)
{
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN) finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&m_elytraLoopingSound->sound, finalVolume);
ma_sound_set_pitch(&m_elytraLoopingSound->sound, pitch);
return;
}
// Resolve file path using the same logic as play().
wstring name = wchSoundNames[eSoundType_ITEM_ELYTRA_FLYING];
char* soundName = ConvertSoundPathToName(name);
char basePath[256];
sprintf_s(basePath, "Windows64Media/Sound/Minecraft/%s", soundName);
const char* extensions[] = { ".ogg", ".wav", ".mp3" };
char finalPath[256] = {};
bool found = false;
for (auto& ext : extensions)
{
char candidate[256];
sprintf_s(candidate, "%s%s", basePath, ext);
DWORD attr = GetFileAttributesA(candidate);
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
{
sprintf_s(finalPath, "%s", candidate);
found = true;
break;
}
}
if (!found) return;
MiniAudioSound* s = new MiniAudioSound();
memset(&s->info, 0, sizeof(AUDIO_INFO));
s->info.volume = volume; s->info.pitch = pitch;
s->info.bIs3D = false;
s->info.iSound = eSoundType_ITEM_ELYTRA_FLYING + eSFX_MAX;
// Synchronous load so the sound is immediately ready - no ASYNC gap.
if (ma_sound_init_from_file(&m_engine, finalPath, 0,
nullptr, nullptr, &s->sound) != MA_SUCCESS)
{
delete s;
return;
}
ma_sound_set_spatialization_enabled(&s->sound, MA_FALSE);
ma_sound_set_looping(&s->sound, MA_TRUE);
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN) finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&s->sound, finalVolume);
ma_sound_set_pitch(&s->sound, pitch);
ma_sound_start(&s->sound);
// NOT added to m_activeSounds - tick() cleanup would delete it at loop boundaries.
m_elytraLoopingSound = s;
}
void SoundEngine::stopElytraSound()
{
if (m_elytraLoopingSound == nullptr) return;
ma_sound_stop(&m_elytraLoopingSound->sound);
ma_sound_uninit(&m_elytraLoopingSound->sound);
delete m_elytraLoopingSound;
m_elytraLoopingSound = nullptr;
}
/////////////////////////////////////////////
// playUI
//
/////////////////////////////////////////////
void SoundEngine::playUI(int iSound, float volume, float pitch)
@@ -127,6 +127,8 @@ public:
void GetSoundName(char *szSoundName,int iSound);
#endif
void play(int iSound, float x, float y, float z, float volume, float pitch) override;
void startElytraSound(float x, float y, float z, float volume, float pitch);
void stopElytraSound();
void playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay=true) override;
void playUI(int iSound, float volume, float pitch) override;
void playMusicTick() override;
@@ -159,6 +161,9 @@ private:
int GetRandomishTrack(int iStart,int iEnd);
MiniAudioSound* m_elytraLoopingSound = nullptr;
ma_engine m_engine;
ma_engine_config m_engineConfig;
ma_sound m_musicStream;
@@ -272,6 +272,8 @@ 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
};
@@ -1273,6 +1273,10 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
case Item::chestplate_gold_Id:
case Item::leggings_gold_Id:
case Item::boots_gold_Id:
case Item::elytra_Id:
buttonY=eToolTipQuickMoveArmor;
break;
@@ -383,6 +383,7 @@ void IUIScene_CreativeMenu::staticCtor()
ITEM(Item::minecart_tnt_Id)
ITEM(Item::saddle_Id)
ITEM(Item::boat_Id)
ITEM(Item::elytra_Id)
// Miscellaneous
DEF(eCreativeInventory_Misc)
Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 111 KiB

+3 -1
View File
@@ -189,7 +189,9 @@ EntityRenderDispatcher::EntityRenderDispatcher()
it.second->init(this);
}
isGuiRender = false; // 4J added
isGuiRender = false; // 4J added
isInventoryRender = false;
}
EntityRenderer *EntityRenderDispatcher::getRenderer(eINSTANCEOF e)
@@ -32,6 +32,8 @@ public:
float playerRotX;
Options *options;
bool isGuiRender; // 4J added
bool isInventoryRender;
double xPlayer, yPlayer, zPlayer;
+94 -3
View File
@@ -47,6 +47,8 @@
#include "../Minecraft.World/compression.h"
#include "PS3/PS3Extras/ShutdownManager.h"
#include "BossMobGuiInfo.h"
#include "../Minecraft.World/LivingEntity.h"
#include "TexturePackRepository.h"
#include "TexturePack.h"
@@ -96,6 +98,10 @@ GameRenderer::GameRenderer(Minecraft *mc)
fovOffsetO = 0;
cameraRoll = 0;
cameraRollO = 0;
m_yBob = 0.0f;
m_yBobO = 0.0f;
m_elytaCamShift = 0.0f;
for( int i = 0; i < 4; i++ )
{
fov[i] = 0.0f;
@@ -197,6 +203,20 @@ void GameRenderer::tick(bool first) // 4J - add bFirst
fovOffsetO = fovOffset;
cameraRollO = cameraRoll;
m_yBobO = m_yBob;
{
shared_ptr<Player> yBobPlayer = dynamic_pointer_cast<Player>(mc->cameraTargetPlayer);
float target = 0.0f;
if (yBobPlayer != nullptr && !yBobPlayer->onGround
&& !(yBobPlayer->abilities.mayfly && yBobPlayer->abilities.flying))
{
target = (float)(atan(-yBobPlayer->yd * 0.2) * 15.0);
}
m_yBob += (target - m_yBob) * 0.8f;
}
if (mc->options->smoothCamera)
{
// update player view in tick() instead of render() to maintain
@@ -455,6 +475,11 @@ void GameRenderer::bobView(float a)
glRotatef((float) Mth::sin(b * PI) * bob * 3, 0, 0, 1);
glRotatef((float) abs(Mth::cos(b * PI - 0.2f) * bob) * 5, 1, 0, 0);
glRotatef((float) tilt, 1, 0, 0);
float yBobAngle = m_yBobO + (m_yBob - m_yBobO) * a;
if (fabsf(yBobAngle) > 0.001f)
glRotatef(yBobAngle, 1, 0, 0);
}
void GameRenderer::moveCameraToPlayer(float a)
@@ -468,7 +493,71 @@ void GameRenderer::moveCameraToPlayer(float a)
double z = player->zo + (player->z - player->zo) * a;
glRotatef(cameraRollO + (cameraRoll - cameraRollO) * a, 0, 0, 1);
{
shared_ptr<Player> elytraPlayer = dynamic_pointer_cast<Player>(player);
bool elytraFlying = (elytraPlayer != nullptr && elytraPlayer->isElytraFlying());
float targetShift = elytraFlying ? -1.22f : 0.0f;
m_elytaCamShift += (targetShift - m_elytaCamShift) * 0.15f;
if (fabsf(m_elytaCamShift) < 0.001f) m_elytaCamShift = 0.0f;
y += m_elytaCamShift;
}
if (localplayer != nullptr && !player->isSleeping())
{
shared_ptr<Player> rollPlayer = dynamic_pointer_cast<Player>(player);
if (rollPlayer != nullptr && rollPlayer->isElytraFlying())
{
double velX = rollPlayer->xd;
double velZ = rollPlayer->zd;
double horizVelSq = velX * velX + velZ * velZ;
Vec3* look = rollPlayer->getLookAngle();
double horizLookSq = look->x * look->x + look->z * look->z;
float targetRoll = 0.0f;
if (horizVelSq > 1.0e-6 && horizLookSq > 1.0e-6)
{
double dot = velX * look->x + velZ * look->z;
double cosAngle = dot / sqrt(horizVelSq * horizLookSq);
if (cosAngle > 1.0) cosAngle = 1.0;
if (cosAngle < -1.0) cosAngle = -1.0;
double angle = acos(cosAngle) / 2.5;
if (angle > PI / 8.0) angle = PI / 8.0;
double cross = velX * look->z - velZ * look->x;
float sign = (cross < 0.0) ? -1.0f : 1.0f;
targetRoll = sign * (float)(angle * (180.0 / PI));
}
cameraRoll += (targetRoll - cameraRoll) * 0.1f;
}
else
{
if (fabsf(cameraRoll) > 0.01f)
{
cameraRoll += (0.0f - cameraRoll) * 0.15f;
if (fabsf(cameraRoll) < 0.01f) cameraRoll = 0.0f;
}
}
if (fabsf(cameraRoll) > 0.01f)
glRotatef(cameraRoll, 0, 0, 1);
}
if (player->isSleeping())
{
@@ -574,10 +663,12 @@ void GameRenderer::moveCameraToPlayer(float a)
}
}
glTranslatef(0, heightOffset, 0);
glTranslatef(0, heightOffset - m_elytaCamShift, 0);
x = player->xo + (player->x - player->xo) * a;
y = player->yo + (player->y - player->yo) * a - heightOffset;
y = player->yo + (player->y - player->yo) * a - heightOffset + m_elytaCamShift;
z = player->zo + (player->z - player->zo) * a;
isInClouds = mc->levelRenderer->isInCloud(x, y, z, a);
+7
View File
@@ -64,6 +64,13 @@ private:
float cameraRoll;
float cameraRollO;
float m_yBob;
float m_yBobO;
float m_elytaCamShift;
// 4J - changes brought forward from 1.8.2
static const int NUM_LIGHT_TEXTURES = 4;// * 3;
int lightTexture[NUM_LIGHT_TEXTURES]; // 4J - changed so that we have one lightTexture per level, to support split screen
+72
View File
@@ -88,6 +88,17 @@ void HumanoidModel::_init(float g, float yOffset, int texWidth, int texHeight, b
cloak = new ModelPart(this, 0, 0);
cloak->addHumanoidBox(-5, -0, -1, 10, 16, 1, g); // Cloak
elytraRight = new ModelPart(this, 22, 0);
elytraRight->addHumanoidBox(-10.0f, 0.0f, 0.0f, 10, 20, 2, 0.0f);
elytraRight->setPos(5.0f, 0.0f + yOffset, 0.0f); // Wing Left
elytraLeft = new ModelPart(this, 22, 0);
elytraLeft->bMirror = true;
elytraLeft->addHumanoidBox(0.0f, 0.0f, 0.0f, 10, 20, 2, 0.0f);
elytraLeft->setPos(-5.0f, 0.0f + yOffset, 0.0f); // Wing Right
ear = new ModelPart(this, 24, 0);
ear->addHumanoidBox(-3, -6, -1, 6, 6, 1, g); // Ear
@@ -186,6 +197,8 @@ void HumanoidModel::_init(float g, float yOffset, int texWidth, int texHeight, b
// 4J added - compile now to avoid random performance hit first time cubes are rendered
// 4J Stu - Not just performance, but alpha+depth tests don't work right unless we compile here
cloak->compile(1.0f/16.0f);
elytraLeft->compile(1.0f / 16.0f);
elytraRight->compile(1.0f / 16.0f);
ear->compile(1.0f/16.0f);
head->compile(1.0f/16.0f);
body->compile(1.0f/16.0f);
@@ -211,6 +224,9 @@ void HumanoidModel::_init(float g, float yOffset, int texWidth, int texHeight, b
sneaking=false;
idle=false;
bowAndArrow=false;
elytraFlying = false;
elytraCrouching = false;
// 4J added
eating = false;
@@ -881,6 +897,57 @@ void HumanoidModel::setupAnim(float time, float r, float bob, float yRot, float
}
}
}
if (elytraFlying)
{
if (elytraCrouching)
{
arm0->xRot = PI; arm0->yRot = 0.0f; arm0->zRot = 0.0f; arm0->y = 2.0f;
if (sleeve0) { sleeve0->xRot = PI; sleeve0->yRot = 0.0f; sleeve0->zRot = 0.0f; sleeve0->y = 2.0f; }
arm1->xRot = 0.0f; arm1->yRot = 0.0f; arm1->zRot = 0.0f; arm1->y = 2.0f;
if (sleeve1) { sleeve1->xRot = 0.0f; sleeve1->yRot = 0.0f; sleeve1->zRot = 0.0f; sleeve1->y = 2.0f; }
leg0->xRot = 0.0f; leg0->yRot = 0.0f; leg0->zRot = 0.0f;
leg1->xRot = 0.0f; leg1->yRot = 0.0f; leg1->zRot = 0.0f;
if (pants0) { pants0->xRot = 0.0f; pants0->yRot = 0.0f; pants0->zRot = 0.0f; }
if (pants1) { pants1->xRot = 0.0f; pants1->yRot = 0.0f; pants1->zRot = 0.0f; }
}
else
{
float elytraTime = (float)(entity->tickCount) * 0.3f;
float spd2 = (float)(entity->xd * entity->xd + entity->yd * entity->yd + entity->zd * entity->zd);
float fDamp = spd2 / 0.2f;
fDamp = fDamp * fDamp * fDamp;
if (fDamp < 1.0f) fDamp = 1.0f;
float armAmp = 2.0f * r * 0.5f / fDamp;
float legAmp = 1.4f * r / fDamp;
arm0->xRot = Mth::cos(elytraTime + PI) * armAmp;
arm0->yRot = 0.0f; arm0->zRot = 0.0f; arm0->y = 2.0f;
if (sleeve0) { sleeve0->xRot = arm0->xRot; sleeve0->yRot = 0.0f; sleeve0->zRot = 0.0f; sleeve0->y = 2.0f; }
arm1->xRot = Mth::cos(elytraTime) * armAmp;
arm1->yRot = 0.0f; arm1->zRot = 0.0f; arm1->y = 2.0f;
if (sleeve1) { sleeve1->xRot = arm1->xRot; sleeve1->yRot = 0.0f; sleeve1->zRot = 0.0f; sleeve1->y = 2.0f; }
leg0->xRot = Mth::cos(elytraTime) * legAmp;
leg0->yRot = 0.0f; leg0->zRot = 0.0f;
leg1->xRot = Mth::cos(elytraTime + PI) * legAmp;
leg1->yRot = 0.0f; leg1->zRot = 0.0f;
if (pants0) { pants0->xRot = leg0->xRot; pants0->yRot = 0.0f; pants0->zRot = 0.0f; }
if (pants1) { pants1->xRot = leg1->xRot; pants1->yRot = 0.0f; pants1->zRot = 0.0f; }
}
body->xRot = 0.0f;
body->z = 0.0f;
head->xRot = -(float)(PI / 4.0f);
hair->xRot = head->xRot;
}
}
void HumanoidModel::renderHair(float scale,bool usecompiled)
@@ -903,6 +970,11 @@ void HumanoidModel::renderCloak(float scale,bool usecompiled)
{
cloak->render(scale,usecompiled);
}
void HumanoidModel::renderElytra(float scale, bool usecompiled)
{
elytraRight->render(scale, usecompiled);
elytraLeft->render(scale, usecompiled);
}
void HumanoidModel::render(HumanoidModel *model, float scale, bool usecompiled)
{
+15 -10
View File
@@ -3,30 +3,32 @@
class HumanoidModel : public Model
{
public:
ModelPart *head, *hair, *body, *jacket, *arm0, *sleeve0, *arm1, *sleeve1, *leg0, *pants0, *leg1, *pants1, *ear, *cloak;
ModelPart* head, * hair, * body, * jacket, * arm0, * sleeve0, * arm1, * sleeve1, * leg0, * pants0, * leg1, * pants1, * ear, * cloak;
ModelPart* elytraLeft, * elytraRight;
int holdingLeftHand;
int holdingRightHand;
bool idle;
bool sneaking;
bool bowAndArrow;
bool eating;
float eating_t;
float eating_swing;
unsigned int m_uiAnimOverrideBitmask;
bool eating;
float eating_t;
float eating_swing;
bool elytraFlying;
bool elytraCrouching;
unsigned int m_uiAnimOverrideBitmask;
float m_fYOffset;
enum animbits
{
eAnim_ArmsDown = 0,
eAnim_ArmsOutFront,
eAnim_NoLegAnim,
eAnim_HasIdle,
eAnim_ForceAnim,
eAnim_ForceAnim,
eAnim_SingleLegs,
eAnim_SingleArms,
eAnim_StatueOfLiberty,
eAnim_DontRenderArmour,
eAnim_NoBobbing,
eAnim_StatueOfLiberty,
eAnim_DontRenderArmour,
eAnim_NoBobbing,
eAnim_DisableRenderHead,
eAnim_DisableRenderArm0,
eAnim_DisableRenderArm1,
@@ -42,6 +44,7 @@ public:
eAnim_DisableRenderPants1
};
static const unsigned int m_staticBitmaskIgnorePlayerCustomAnimSetting =
(1 << HumanoidModel::eAnim_ForceAnim) |
(1 << HumanoidModel::eAnim_DisableRenderArm0) |
@@ -75,6 +78,8 @@ public:
void renderHair(float scale, bool usecompiled);
void renderEars(float scale, bool usecompiled);
void renderCloak(float scale, bool usecompiled);
void renderElytra(float scale, bool usecompiled);
void render(HumanoidModel* model, float scale, bool usecompiled);
ModelPart* AddOrRetrievePart(SKIN_BOX* pBox);
+23
View File
@@ -11,6 +11,8 @@
#include "MultiPlayerLocalPlayer.h"
#include "Minimap.h"
#include "MultiPlayerLevel.h"
#include "SkullTileRenderer.h"
#include "../Minecraft.World/Facing.h"
#include "../Minecraft.World/net.minecraft.world.item.h"
#include "../Minecraft.World/net.minecraft.world.level.tile.h"
#include "../Minecraft.World/net.minecraft.world.entity.h"
@@ -237,6 +239,17 @@ void ItemInHandRenderer::renderItem(shared_ptr<LivingEntity> mob, shared_ptr<Ite
}
glPushMatrix();
/*if (item->id == Item::skull_Id && SkullTileRenderer::instance != nullptr)
{
wstring extra = L"";
if (item->hasTag() && item->getTag()->contains(L"SkullOwner"))
extra = item->getTag()->getString(L"SkullOwner");
SkullTileRenderer::instance->renderSkull(-0.5f, 0.0f, -0.5f, Facing::UP, 0.0f, item->getAuxValue(), extra);
glPopMatrix();
return;
}*/
Tile *tile = Tile::tiles[item->id];
if (item->getIconType() == Icon::TYPE_TERRAIN && tile != nullptr && TileRenderer::canRender(tile->getRenderShape()))
{
@@ -680,6 +693,16 @@ void ItemInHandRenderer::render(float a)
renderItem(player, item, 1, false);
}
//else if (item->id == Item::skull_Id && SkullTileRenderer::instance != nullptr)
//{
// wstring extra = L"";
// if (item->hasTag() && item->getTag()->contains(L"SkullOwner"))
// extra = item->getTag()->getString(L"SkullOwner");
// glEnable(GL_RESCALE_NORMAL);
// glScalef(2.0f, 2.0f, 2.0f);
// SkullTileRenderer::instance->renderSkull(-0.5f, 0.0f, -0.5f, Facing::UP, 0.0f, item->getAuxValue(), extra);
// glDisable(GL_RESCALE_NORMAL);
//}
else
{
renderItem(player, item, 0, false);
+55
View File
@@ -67,6 +67,9 @@ LocalPlayer::LocalPlayer(Minecraft *minecraft, Level *level, User *user, int dim
sprintTriggerTime = 0;
sprintTriggerRegisteredReturn = false;
twoJumpsRegistered = false;
m_elytraCancelPressCount = 0;
m_elytraCancelWindow = 0;
m_elytraSoundTicks = 0;
sprintTime = 0;
m_uiInactiveTicks=0;
portalTime = 0.0f;
@@ -331,6 +334,58 @@ void LocalPlayer::aiStep()
}
if (isElytraFlying())
{
if (m_elytraCancelWindow > 0) m_elytraCancelWindow--;
if (!wasJumping && input->jumping)
{
m_elytraCancelPressCount++;
if (m_elytraCancelPressCount == 1)
{
m_elytraCancelWindow = 15;
}
else if (m_elytraCancelPressCount >= 2 && m_elytraCancelWindow > 0)
{
setElytraFlying(false);
jumpTriggerTime = 10;
m_elytraCancelPressCount = 0;
m_elytraCancelWindow = 0;
}
}
if (m_elytraCancelWindow == 0 && m_elytraCancelPressCount > 0)
m_elytraCancelPressCount = 0;
m_elytraSoundTicks++;
float vol = 0.0f;
float pitch = 1.0f;
if (m_elytraSoundTicks >= 20)
{
float totalSpeed = (float)Mth::sqrt(xd * xd + yd * yd + zd * zd);
float f1 = totalSpeed / 2.0f;
float speedVol = f1 * f1;
if (speedVol > 1.0f) speedVol = 1.0f;
float fadeFactor = (m_elytraSoundTicks < 40)
? (float)(m_elytraSoundTicks - 20) / 20.0f
: 1.0f;
vol = speedVol * fadeFactor;
if (vol > 0.8f)
pitch = 1.0f + (vol - 0.8f);
}
if (vol > 0.01f)
minecraft->soundEngine->startElytraSound((float)x, (float)y, (float)z, vol, pitch);
}
else
{
m_elytraCancelPressCount = 0;
m_elytraCancelWindow = 0;
m_elytraSoundTicks = 0;
minecraft->soundEngine->stopElytraSound();
}
if (abilities.flying)
{
// yd = 0;
+4
View File
@@ -31,6 +31,10 @@ protected:
int sprintTriggerTime;
bool sprintTriggerRegisteredReturn; // 4J added
bool twoJumpsRegistered; // 4J added
int m_elytraCancelPressCount;
int m_elytraCancelWindow;
int m_elytraSoundTicks;
unsigned int m_uiInactiveTicks; // To measure time for idle anims
+193 -81
View File
@@ -288,14 +288,21 @@ void PlayerRenderer::render(shared_ptr<Entity> _mob, double x, double y, double
{
armorParts1->eating = armorParts2->eating = resModel->eating = false;
}
// Suppress crouch pose while elytra flying (superman pose is applied instead)
bool effectiveSneaking = mob->isSneaking() && !mob->isElytraFlying();
armorParts1->sneaking = armorParts2->sneaking = resModel->sneaking = effectiveSneaking;
// Signal models: elytraFlying suppresses walk/bob; elytraCrouching adds superman arms
// Suppress elytra pose in the inventory screen (isInventoryRender=true during that pass).
bool elytraFlying = mob->isElytraFlying() && !EntityRenderDispatcher::instance->isInventoryRender;
bool elytraCrouch = elytraFlying && mob->isSneaking();
armorParts1->elytraFlying = armorParts2->elytraFlying = resModel->elytraFlying = elytraFlying;
armorParts1->elytraCrouching = armorParts2->elytraCrouching = resModel->elytraCrouching = elytraCrouch;
armorParts1->sneaking = armorParts2->sneaking = resModel->sneaking = mob->isSneaking();
double yp = y - mob->heightOffset;
if (mob->isSneaking())
if (mob->isSneaking() && !mob->instanceof(eTYPE_LOCALPLAYER))
{
yp -= 2 / 16.0f;
}
if (mob->getAnimOverrideBitmask() & (1 << HumanoidModel::eAnim_SmallModel))
{
if (mob->isRiding())
@@ -357,6 +364,8 @@ void PlayerRenderer::render(shared_ptr<Entity> _mob, double x, double y, double
}
armorParts1->bowAndArrow = armorParts2->bowAndArrow = resModel->bowAndArrow = false;
armorParts1->sneaking = armorParts2->sneaking = resModel->sneaking = false;
armorParts1->elytraFlying = armorParts2->elytraFlying = resModel->elytraFlying = false;
armorParts1->elytraCrouching = armorParts2->elytraCrouching = resModel->elytraCrouching = false;
armorParts1->holdingRightHand = armorParts2->holdingRightHand = resModel->holdingRightHand = 0;
}
@@ -497,8 +506,6 @@ void PlayerRenderer::additionalRendering(shared_ptr<LivingEntity> _mob, float a)
// 4J Stu - Fix for sprint-flying causing the cape to rotate up by 180 degrees or more
float xRot = 6.0f + lean / 2 + flap;
if (xRot > 64.0f) xRot = 64.0f;
glRotatef(xRot, 1, 0, 0);
glRotatef(lean2 / 2, 0, 0, 1);
glRotatef(-lean2 / 2, 0, 1, 0);
@@ -507,101 +514,182 @@ void PlayerRenderer::additionalRendering(shared_ptr<LivingEntity> _mob, float a)
glPopMatrix();
}
shared_ptr<ItemInstance> item = mob->inventory->getSelected();
if (item != nullptr)
{
glPushMatrix();
resModel->arm0->translateTo(1 / 16.0f);
glTranslatef(-1 / 16.0f, 7 / 16.0f, 1 / 16.0f);
shared_ptr<ItemInstance> chestItem = mob->inventory->armor[LivingEntity::SLOT_CHEST - 1];
if (chestItem != nullptr && dynamic_cast<ElytraItem*>(chestItem->getItem()) != nullptr && !mob->isInvisible())
{
static ResourceLocation elytraTexture(L"item/elytra.png");
bindTexture(&elytraTexture);
if (mob->fishing != nullptr)
{
item = std::make_shared<ItemInstance>(Item::stick);
}
float brightness2 = SharedConstants::TEXTURE_LIGHTING ? 1 : mob->getBrightness(a);
glColor3f(brightness2, brightness2, brightness2);
UseAnim anim = UseAnim_none;//null;
if (mob->getUseItemDuration() > 0)
{
anim = item->getUseAnimation();
}
if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape()))
{
float s = 8 / 16.0f;
glTranslatef(-0 / 16.0f, 3 / 16.0f, -5 / 16.0f);
s *= 0.75f;
glRotatef(20, 1, 0, 0);
glRotatef(45, 0, 1, 0);
glScalef(-s, -s, s);
}
else if (item->id == Item::bow->id)
{
float s = 10 / 16.0f;
glTranslatef(0 / 16.0f, 2 / 16.0f, 5 / 16.0f);
glRotatef(-20, 0, 1, 0);
glScalef(s, -s, s);
glRotatef(-100, 1, 0, 0);
glRotatef(45, 0, 1, 0);
}
else if (Item::items[item->id]->isHandEquipped())
{
float s = 10 / 16.0f;
if (Item::items[item->id]->isMirroredArt())
float wf = 0.2617994f;
float wf1 = -0.2617994f;
float wf2 = resModel->body->y;
float wf3 = 0.0f;
if (mob->isElytraFlying() && !EntityRenderDispatcher::instance->isInventoryRender)
{
glRotatef(180, 0, 0, 1);
glTranslatef(0, -2 / 16.0f, 0);
float f4 = 1.0f;
if (mob->yd < 0.0)
{
double speed = sqrt(mob->xd * mob->xd + mob->yd * mob->yd + mob->zd * mob->zd);
if (speed > 0.0)
{
double normY = mob->yd / speed;
f4 = 1.0f - (float)pow(-normY, 1.5);
if (f4 < 0.0f) f4 = 0.0f;
if (f4 > 1.0f) f4 = 1.0f;
}
}
wf = f4 * 0.34906584f + (1.0f - f4) * wf;
wf1 = f4 * (-(float)(PI / 2.0)) + (1.0f - f4) * wf1;
}
else if (mob->isSneaking())
{
wf = (float)(PI * 2.0 / 9.0);
wf1 = -(float)(PI / 4.0);
wf2 = 0.0f;
wf3 = 0.08726646f;
}
if (EntityRenderDispatcher::instance->isInventoryRender)
{
mob->rotateElytraX = wf;
mob->rotateElytraY = wf3;
mob->rotateElytraZ = wf1;
}
else
{
mob->rotateElytraX += (wf - mob->rotateElytraX) * 0.3f;
mob->rotateElytraY += (wf3 - mob->rotateElytraY) * 0.3f;
mob->rotateElytraZ += (wf1 - mob->rotateElytraZ) * 0.3f;
}
humanoidModel->elytraRight->y = wf2;
humanoidModel->elytraRight->xRot = mob->rotateElytraX;
humanoidModel->elytraRight->yRot = mob->rotateElytraY;
humanoidModel->elytraRight->zRot = mob->rotateElytraZ;
humanoidModel->elytraLeft->y = wf2;
humanoidModel->elytraLeft->xRot = mob->rotateElytraX;
humanoidModel->elytraLeft->yRot = -mob->rotateElytraY;
humanoidModel->elytraLeft->zRot = -mob->rotateElytraZ;
glPushMatrix();
glTranslatef(0, 0.0f, (2.0f + 0.125f) / 16.0f);
humanoidModel->renderElytra(1 / 16.0f, true);
glPopMatrix();
}
shared_ptr<ItemInstance> item = mob->inventory->getSelected();
if (item != nullptr)
{
glPushMatrix();
resModel->arm0->translateTo(1 / 16.0f);
glTranslatef(-1 / 16.0f, 7 / 16.0f, 1 / 16.0f);
if (mob->fishing != nullptr)
{
item = std::make_shared<ItemInstance>(Item::stick);
}
UseAnim anim = UseAnim_none;//null;
if (mob->getUseItemDuration() > 0)
{
if (anim == UseAnim_block)
anim = item->getUseAnimation();
}
if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape()))
{
float s = 8 / 16.0f;
glTranslatef(-0 / 16.0f, 3 / 16.0f, -5 / 16.0f);
s *= 0.75f;
glRotatef(20, 1, 0, 0);
glRotatef(45, 0, 1, 0);
glScalef(-s, -s, s);
}
else if (item->id == Item::bow->id)
{
float s = 10 / 16.0f;
glTranslatef(0 / 16.0f, 2 / 16.0f, 5 / 16.0f);
glRotatef(-20, 0, 1, 0);
glScalef(s, -s, s);
glRotatef(-100, 1, 0, 0);
glRotatef(45, 0, 1, 0);
}
else if (Item::items[item->id]->isHandEquipped())
{
float s = 10 / 16.0f;
if (Item::items[item->id]->isMirroredArt())
{
glTranslatef(0.05f, 0, -0.1f);
glRotatef(-50, 0, 1, 0);
glRotatef(-10, 1, 0, 0);
glRotatef(-60, 0, 0, 1);
glRotatef(180, 0, 0, 1);
glTranslatef(0, -2 / 16.0f, 0);
}
if (mob->getUseItemDuration() > 0)
{
if (anim == UseAnim_block)
{
glTranslatef(0.05f, 0, -0.1f);
glRotatef(-50, 0, 1, 0);
glRotatef(-10, 1, 0, 0);
glRotatef(-60, 0, 0, 1);
}
}
glTranslatef(0, 3 / 16.0f, 0);
glScalef(s, -s, s);
glRotatef(-100, 1, 0, 0);
glRotatef(45, 0, 1, 0);
}
else if (item->id == Item::skull_Id)
{
float s = 0.5f;
glTranslatef(0, -3 / 16.0f, -4 / 16.0f);
glRotatef(45, 1, 0, 0);
glRotatef(45, 0, 1, 0);
glScalef(-s, -s, s);
}
else
{
float s = 6 / 16.0f;
glTranslatef(+4 / 16.0f, +3 / 16.0f, -3 / 16.0f);
glScalef(s, s, s);
glRotatef(60, 0, 0, 1);
glRotatef(-90, 1, 0, 0);
glRotatef(20, 0, 0, 1);
}
if (item->getItem()->hasMultipleSpriteLayers())
{
for (int layer = 0; layer <= 1; layer++)
{
int col = item->getItem()->getColor(item, layer);
float red = ((col >> 16) & 0xff) / 255.0f;
float g = ((col >> 8) & 0xff) / 255.0f;
float b = ((col) & 0xff) / 255.0f;
glColor4f(red, g, b, 1);
this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, layer, false);
}
}
glTranslatef(0, 3 / 16.0f, 0);
glScalef(s, -s, s);
glRotatef(-100, 1, 0, 0);
glRotatef(45, 0, 1, 0);
}
else
{
float s = 6 / 16.0f;
glTranslatef(+4 / 16.0f, +3 / 16.0f, -3 / 16.0f);
glScalef(s, s, s);
glRotatef(60, 0, 0, 1);
glRotatef(-90, 1, 0, 0);
glRotatef(20, 0, 0, 1);
}
if (item->getItem()->hasMultipleSpriteLayers())
{
for (int layer = 0; layer <= 1; layer++)
else
{
int col = item->getItem()->getColor(item, layer);
int col = item->getItem()->getColor(item, 0);
float red = ((col >> 16) & 0xff) / 255.0f;
float g = ((col >> 8) & 0xff) / 255.0f;
float b = ((col) & 0xff) / 255.0f;
glColor4f(red, g, b, 1);
this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, layer, false);
this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, 0);
}
}
else
{
int col = item->getItem()->getColor(item, 0);
float red = ((col >> 16) & 0xff) / 255.0f;
float g = ((col >> 8) & 0xff) / 255.0f;
float b = ((col) & 0xff) / 255.0f;
glColor4f(red, g, b, 1);
this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, 0);
glPopMatrix();
}
glPopMatrix();
}
}
@@ -746,10 +834,34 @@ void PlayerRenderer::setupRotations(shared_ptr<LivingEntity> _mob, float bob, fl
glRotatef(getFlipDegrees(mob), 0, 0, 1);
glRotatef(270, 0, 1, 0);
}
else
else if (mob->isElytraFlying() && !EntityRenderDispatcher::instance->isInventoryRender)
{
LivingEntityRenderer::setupRotations(mob, bob, bodyRot, a);
float f = (float)mob->ticksElytraFlying + a;
float f1 = Mth::clamp(f * f / 100.0f, 0.0f, 1.0f);
glRotatef(f1 * (-90.0f - mob->xRot), 1.0f, 0.0f, 0.0f);
Vec3* look = mob->getLookAngle();
double d0 = mob->xd * mob->xd + mob->zd * mob->zd;
double d1 = look->x * look->x + look->z * look->z;
if (d0 > 0.0 && d1 > 0.0)
{
double d2 = (mob->xd * look->x + mob->zd * look->z) / (sqrt(d0) * sqrt(d1));
if (d2 > 1.0) d2 = 1.0;
if (d2 < -1.0) d2 = -1.0;
double d3 = mob->xd * look->z - mob->zd * look->x;
float sign = (d3 >= 0.0) ? 1.0f : -1.0f;
glRotatef(sign * (float)(acos(d2) * 180.0 / PI), 0.0f, 1.0f, 0.0f);
}
}
else
{
LivingEntityRenderer::setupRotations(mob, bob, bodyRot, a);
}
}
// 4J Added override to stop rendering shadow if player is invisible
@@ -570,6 +570,8 @@ void PreStitchedTextureMap::loadUVs()
ADD_ICON(14, 6, L"rabbitHide")
ADD_ICON(13, 14, L"prismarineCrystal");
ADD_ICON(13, 13, L"prismarineShard");
ADD_ICON(13, 12, L"elytra");
ADD_ICON(13, 11, L"broken_elytra");
ADD_ICON_WITH_NAME(14, 7, L"compassP0", L"compass") // 4J Added
ADD_ICON_WITH_NAME(14, 8, L"compassP1", L"compass") // 4J Added
@@ -9393,4 +9393,7 @@ All Ender Chests in a world are linked. Items placed into an Ender Chest are acc
<data name="IDS_TILE_STONESLAB_REDSAND">
<value>Red Sandstone Slab</value>
</data>
<data name="IDS_ITEM_ELYTRA">
<value>Elytra</value>
</data>
</root>