mirror of
https://github.com/neoStudiosLCE/neoLegacy.git
synced 2026-06-09 02:13:09 +00:00
Elytra
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:
parent
7db8860ea4
commit
4b6e9f8eb2
|
|
@ -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)
|
||||
|
|
|
|||
BIN
Minecraft.Client/Common/res/1_2_2/item/elytra.png
Normal file
BIN
Minecraft.Client/Common/res/1_2_2/item/elytra.png
Normal file
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 |
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ ArmorRecipes::_eArmorType ArmorRecipes::GetArmorType(int iId)
|
|||
case Item::chestplate_iron_Id:
|
||||
case Item::chestplate_diamond_Id:
|
||||
case Item::chestplate_gold_Id:
|
||||
case Item::elytra_Id:
|
||||
|
||||
return eArmorType_Chestplate;
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ bool ArmorSlot::mayPlace(shared_ptr<ItemInstance> item)
|
|||
{
|
||||
return slotNum == 0;
|
||||
}
|
||||
if (item->getItem()->id == Item::elytra_Id)
|
||||
{
|
||||
return slotNum == ArmorItem::SLOT_TORSO;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
92
Minecraft.World/ElytraItem.cpp
Normal file
92
Minecraft.World/ElytraItem.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#include "stdafx.h"
|
||||
#include "net.minecraft.world.h"
|
||||
#include "net.minecraft.world.level.h"
|
||||
#include "net.minecraft.world.entity.h"
|
||||
#include "net.minecraft.world.entity.player.h"
|
||||
#include "net.minecraft.world.item.h"
|
||||
#include "ElytraItem.h"
|
||||
|
||||
// Internal item ID: 187 → public item ID: 443 (256 + 187)
|
||||
ElytraItem::ElytraItem() : Item(187)
|
||||
{
|
||||
maxStackSize = 1;
|
||||
setMaxDamage(432);
|
||||
}
|
||||
|
||||
bool ElytraItem::isFlyEnabled(shared_ptr<ItemInstance> item)
|
||||
{
|
||||
return item->getDamageValue() < item->getMaxDamage() - 1;
|
||||
}
|
||||
|
||||
bool ElytraItem::TestUse(shared_ptr<ItemInstance> instance, Level* level, shared_ptr<Player> player)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
shared_ptr<ItemInstance> ElytraItem::use(shared_ptr<ItemInstance> instance, Level* level, shared_ptr<Player> player)
|
||||
{
|
||||
// Elytra equips to the chest slot (SLOT_CHEST = 3, armor array index = SLOT_CHEST - 1 = 2)
|
||||
const int chestSlot = LivingEntity::SLOT_CHEST - 1;
|
||||
|
||||
ItemInstance copy = *instance->copy_not_shared();
|
||||
|
||||
if (!player->abilities.instabuild)
|
||||
{
|
||||
if (player->inventory->armor[chestSlot] == nullptr)
|
||||
{
|
||||
player->inventory->armor[chestSlot] = make_shared<ItemInstance>(copy);
|
||||
player->inventory->removeItemNoUpdate(player->inventory->selected);
|
||||
instance->count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->inventory->setItem(player->inventory->selected, player->inventory->armor[chestSlot]);
|
||||
player->inventory->armor[chestSlot] = make_shared<ItemInstance>(copy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->inventory->armor[chestSlot] == nullptr)
|
||||
{
|
||||
player->inventory->armor[chestSlot] = make_shared<ItemInstance>(copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->inventory->setItem(player->inventory->selected, player->inventory->armor[chestSlot]);
|
||||
player->inventory->armor[chestSlot] = make_shared<ItemInstance>(copy);
|
||||
}
|
||||
}
|
||||
|
||||
// Play cloth armor equip sound (range 194–199)
|
||||
player->playSound(194, 0.5f, 1.0f);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool ElytraItem::isValidRepairItem(shared_ptr<ItemInstance> source, shared_ptr<ItemInstance> repairItem)
|
||||
{
|
||||
return repairItem->id == Item::leather_Id;
|
||||
}
|
||||
|
||||
void ElytraItem::registerIcons(IconRegister* iconRegister)
|
||||
{
|
||||
Item::registerIcons(iconRegister);
|
||||
m_brokenElytraIcon = iconRegister->registerIcon(L"broken_elytra");
|
||||
}
|
||||
|
||||
Icon* ElytraItem::getLayerIcon(int auxValue, int spriteLayer)
|
||||
{
|
||||
// auxValue may be the damage value in certain render paths
|
||||
if (auxValue < getMaxDamage() - 1)
|
||||
return icon;
|
||||
else
|
||||
return m_brokenElytraIcon;
|
||||
}
|
||||
|
||||
Icon* ElytraItem::getIcon(int auxValue)
|
||||
{
|
||||
if (auxValue < getMaxDamage() - 1)
|
||||
return icon;
|
||||
else
|
||||
return m_brokenElytraIcon;
|
||||
}
|
||||
20
Minecraft.World/ElytraItem.h
Normal file
20
Minecraft.World/ElytraItem.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
class ElytraItem : public Item
|
||||
{
|
||||
public:
|
||||
ElytraItem();
|
||||
|
||||
static bool isFlyEnabled(shared_ptr<ItemInstance> item);
|
||||
|
||||
virtual bool TestUse(shared_ptr<ItemInstance> instance, Level* level, shared_ptr<Player> player) override;
|
||||
virtual shared_ptr<ItemInstance> use(shared_ptr<ItemInstance> instance, Level* level, shared_ptr<Player> player) override;
|
||||
virtual bool isValidRepairItem(shared_ptr<ItemInstance> source, shared_ptr<ItemInstance> repairItem) override;
|
||||
virtual void registerIcons(IconRegister* iconRegister) override;
|
||||
virtual Icon* getLayerIcon(int auxValue, int spriteLayer) override;
|
||||
virtual Icon* getIcon(int auxValue) override;
|
||||
|
||||
Icon* m_brokenElytraIcon = nullptr;
|
||||
};
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
#include "Item.h"
|
||||
#include "HangingEntityItem.h"
|
||||
#include "HtmlString.h"
|
||||
#include "ElytraItem.h"
|
||||
|
||||
typedef Item::Tier _Tier;
|
||||
|
||||
|
|
@ -271,6 +272,8 @@ Item* Item::rabbitStew = nullptr;
|
|||
Item* Item::prismarine_crystal = nullptr;
|
||||
Item* Item::prismarine_shard = nullptr;
|
||||
|
||||
Item* Item::elytra = nullptr;
|
||||
|
||||
|
||||
void Item::staticCtor()
|
||||
{
|
||||
|
|
@ -537,9 +540,11 @@ void Item::staticCtor()
|
|||
Item::armor_stand = (new ArmorStandItem(160)) ->setBaseItemTypeAndMaterial(eBaseItemType_HangingItem,eMaterial_cloth)->setIconName(L"armorStand")->setDescriptionId(IDS_ITEM_ARMOR_STAND)->setUseDescriptionId(IDS_DESC_ARMOR_STAND);
|
||||
Item::prismarine_crystal = (new Item(154))->setIconName(L"prismarineCrystal")->setDescriptionId(IDS_ITEM_PRISMARINE_CRYSTAL)->setUseDescriptionId(IDS_ITEM_PRISMARINE_CRYSTAL_DESC);
|
||||
Item::prismarine_shard = (new Item(153))->setIconName(L"prismarineShard")->setDescriptionId(IDS_ITEM_PRISMARINE_SHARD)->setUseDescriptionId(IDS_ITEM_PRISMARINE_SHARD_DESC);
|
||||
Item::elytra = (new ElytraItem())->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_cloth)->setIconName(L"elytra")->setDescriptionId(IDS_ITEM_ELYTRA)->setUseDescriptionId(IDS_ITEM_ELYTRA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 4J Stu - We need to do this after the staticCtor AND after staticCtors for other class
|
||||
// eg Recipes
|
||||
void Item::staticInit()
|
||||
|
|
|
|||
|
|
@ -436,6 +436,7 @@ public:
|
|||
|
||||
static Item* prismarine_crystal;
|
||||
static Item* prismarine_shard;
|
||||
static Item* elytra;
|
||||
|
||||
|
||||
static const int shovel_iron_Id = 256;
|
||||
|
|
@ -667,6 +668,8 @@ public:
|
|||
static const int door_acacia_Id = 430;
|
||||
static const int door_dark_Id = 431;
|
||||
|
||||
|
||||
static const int elytra_Id = 443;
|
||||
//TU31
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "../Minecraft.Client/LocalPlayer.h"
|
||||
#include "../Minecraft.Client/HumanoidModel.h"
|
||||
#include "SoundTypes.h"
|
||||
#include "ElytraItem.h"
|
||||
|
||||
|
||||
|
||||
|
|
@ -83,6 +84,14 @@ void Player::_init()
|
|||
m_uiDebugOptions=0L;
|
||||
|
||||
jumpTriggerTime = 0;
|
||||
ticksElytraFlying = 0;
|
||||
rotateElytraX = 0.2617994f;
|
||||
rotateElytraY = 0.0f;
|
||||
rotateElytraZ = -0.2617994f;
|
||||
m_elytraImpactYd = 0.0f;
|
||||
m_wasElytraFlying = false;
|
||||
m_elytraFallProtectTicks = 0;
|
||||
|
||||
takeXpDelay = 0;
|
||||
experienceLevel = totalExperience = 0;
|
||||
experienceProgress = 0.0f;
|
||||
|
|
@ -1000,6 +1009,8 @@ void Player::serverAiStep()
|
|||
void Player::aiStep()
|
||||
{
|
||||
if (jumpTriggerTime > 0) jumpTriggerTime--;
|
||||
if (m_elytraFallProtectTicks > 0) m_elytraFallProtectTicks--;
|
||||
|
||||
|
||||
if (level->difficulty == Difficulty::PEACEFUL && getHealth() < getMaxHealth() && level->getGameRules()->getBoolean(GameRules::RULE_NATURAL_REGENERATION))
|
||||
{
|
||||
|
|
@ -1008,8 +1019,43 @@ void Player::aiStep()
|
|||
inventory->tick();
|
||||
oBob = bob;
|
||||
|
||||
if (jumping && !onGround && yd < 0.0 && !isElytraFlying() && !abilities.flying && jumpTriggerTime == 0)
|
||||
{
|
||||
shared_ptr<ItemInstance> chestItem = inventory->armor[LivingEntity::SLOT_CHEST - 1];
|
||||
if (chestItem != nullptr && chestItem->getItem() != nullptr)
|
||||
{
|
||||
ElytraItem* elytra = dynamic_cast<ElytraItem*>(chestItem->getItem());
|
||||
if (elytra != nullptr && ElytraItem::isFlyEnabled(chestItem))
|
||||
setElytraFlying(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LivingEntity::aiStep();
|
||||
|
||||
if (isElytraFlying() && !onGround)
|
||||
{
|
||||
ticksElytraFlying++;
|
||||
|
||||
if (!level->isClientSide && ticksElytraFlying % 20 == 0)
|
||||
{
|
||||
shared_ptr<ItemInstance> chestItem = inventory->armor[LivingEntity::SLOT_CHEST - 1];
|
||||
if (chestItem != nullptr && dynamic_cast<ElytraItem*>(chestItem->getItem()) != nullptr)
|
||||
{
|
||||
chestItem->hurtAndBreak(1, dynamic_pointer_cast<LivingEntity>(shared_from_this()));
|
||||
if (!ElytraItem::isFlyEnabled(chestItem))
|
||||
setElytraFlying(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
setElytraFlying(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
|
||||
if (!level->isClientSide) speed->setBaseValue(abilities.getWalkingSpeed());
|
||||
flyingSpeed = defaultFlySpeed;
|
||||
|
|
@ -1389,6 +1435,8 @@ bool Player::hurt(DamageSource *source, float dmg)
|
|||
|
||||
if ( hasInvulnerablePrivilege() || (abilities.invulnerable && !source->isBypassInvul()) ) return false;
|
||||
|
||||
|
||||
|
||||
// 4J-JEV: Fix for PSVita: #3987 - [IN GAME] The user can take damage/die, when attempting to re-enter fly mode when falling from a height.
|
||||
if ( source == DamageSource::fall && isAllowedToFly() && abilities.flying ) return false;
|
||||
|
||||
|
|
@ -2110,7 +2158,90 @@ void Player::travel(float xa, float ya)
|
|||
{
|
||||
double preX = x, preY = y, preZ = z;
|
||||
|
||||
if (abilities.flying && riding == nullptr)
|
||||
m_elytraImpactYd = (float)yd;
|
||||
|
||||
if (isElytraFlying() && riding == nullptr)
|
||||
{
|
||||
double preHorizSpeed = Mth::sqrt(xd * xd + zd * zd);
|
||||
|
||||
|
||||
if (yd > -0.5)
|
||||
fallDistance = 1.0f;
|
||||
|
||||
Vec3* look = getLookAngle();
|
||||
float pitchRad = xRot * (PI / 180.0f);
|
||||
double horizLookLen = Mth::sqrt(look->x * look->x + look->z * look->z);
|
||||
double horizSpeed = Mth::sqrt(xd * xd + zd * zd);
|
||||
|
||||
|
||||
float cosPitch = Mth::cos(pitchRad);
|
||||
cosPitch = cosPitch * cosPitch;
|
||||
|
||||
|
||||
yd += -0.08 + (double)cosPitch * 0.06;
|
||||
|
||||
if (yd < 0.0 && horizLookLen > 0.0)
|
||||
{
|
||||
double thrust = yd * -0.1 * (double)cosPitch;
|
||||
yd += thrust;
|
||||
xd += look->x * thrust / horizLookLen;
|
||||
zd += look->z * thrust / horizLookLen;
|
||||
}
|
||||
|
||||
if (pitchRad < 0.0f && horizLookLen > 0.0)
|
||||
{
|
||||
double boost = horizSpeed * (double)(-Mth::sin(pitchRad)) * 0.04;
|
||||
yd += boost * 3.2;
|
||||
xd -= look->x * boost / horizLookLen;
|
||||
zd -= look->z * boost / horizLookLen;
|
||||
}
|
||||
|
||||
|
||||
if (horizLookLen > 0.0)
|
||||
{
|
||||
xd += (look->x / horizLookLen * horizSpeed - xd) * 0.1;
|
||||
zd += (look->z / horizLookLen * horizSpeed - zd) * 0.1;
|
||||
}
|
||||
|
||||
// Air drag
|
||||
xd *= 0.99;
|
||||
yd *= 0.98;
|
||||
zd *= 0.99;
|
||||
|
||||
if (jumping && abilities.instabuild)
|
||||
yd += (double)abilities.getFlyingSpeed() * 3.0;
|
||||
|
||||
m_elytraImpactYd = (float)yd;
|
||||
move(xd, yd, zd);
|
||||
|
||||
if (horizontalCollision && !verticalCollision)
|
||||
{
|
||||
double postHorizSpeed = Mth::sqrt(xd * xd + zd * zd);
|
||||
double speedLost = preHorizSpeed - postHorizSpeed;
|
||||
float damage = (float)(speedLost * 10.0 - 3.0);
|
||||
|
||||
if (damage > 0.0f)
|
||||
onElytraKineticDamage(damage);
|
||||
}
|
||||
|
||||
if (onGround)
|
||||
{
|
||||
bool canStandUp = true;
|
||||
if (level != nullptr)
|
||||
{
|
||||
float halfW = bbWidth / 2.0f;
|
||||
AABB* standingBB = AABB::newTemp(
|
||||
x - halfW, bb->y0, z - halfW,
|
||||
x + halfW, bb->y0 + 1.8, z + halfW);
|
||||
AABBList* collisions = level->getCubes(shared_from_this(), standingBB, true);
|
||||
canStandUp = collisions->empty();
|
||||
}
|
||||
if (canStandUp)
|
||||
setElytraFlying(false);
|
||||
}
|
||||
}
|
||||
else if (abilities.flying && riding == nullptr)
|
||||
|
||||
{
|
||||
double ydo = yd;
|
||||
float ofs = flyingSpeed;
|
||||
|
|
@ -2278,6 +2409,13 @@ void Player::checkRidingStatistiscs(double dx, double dy, double dz)
|
|||
}
|
||||
}
|
||||
}
|
||||
void Player::checkFallDamage(double ya, bool onGround)
|
||||
{
|
||||
LivingEntity::checkFallDamage(ya, onGround);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void Player::causeFallDamage(float distance)
|
||||
|
|
@ -2686,6 +2824,37 @@ bool Player::isCapeHidden()
|
|||
{
|
||||
return getPlayerFlag(FLAG_HIDE_CAPE);
|
||||
}
|
||||
bool Player::isElytraFlying()
|
||||
{
|
||||
return getPlayerFlag(FLAG_ELYTRA_FLYING);
|
||||
}
|
||||
|
||||
void Player::onElytraKineticDamage(float damage)
|
||||
{
|
||||
hurt(DamageSource::fall, damage);
|
||||
}
|
||||
|
||||
void Player::setElytraFlying(bool flying)
|
||||
{
|
||||
setPlayerFlag(FLAG_ELYTRA_FLYING, flying);
|
||||
if (flying)
|
||||
{
|
||||
m_wasElytraFlying = false;
|
||||
setSize(0.6f, 0.6f);
|
||||
fallDistance = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
ticksElytraFlying = 0;
|
||||
|
||||
m_wasElytraFlying = true;
|
||||
m_elytraFallProtectTicks = 60;
|
||||
setSize(0.6f, 1.8f);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Player::isPushedByWater()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ private:
|
|||
|
||||
protected:
|
||||
static const int FLAG_HIDE_CAPE = 1;
|
||||
static const int FLAG_ELYTRA_FLYING = 2; // bit 2 of DATA_PLAYER_FLAGS_ID
|
||||
|
||||
|
||||
public:
|
||||
shared_ptr<Inventory> inventory;
|
||||
|
|
@ -79,6 +81,20 @@ protected:
|
|||
int jumpTriggerTime;
|
||||
|
||||
public:
|
||||
int ticksElytraFlying;
|
||||
float rotateElytraX;
|
||||
float rotateElytraY;
|
||||
float rotateElytraZ;
|
||||
float m_elytraImpactYd;
|
||||
bool m_wasElytraFlying;
|
||||
int m_elytraFallProtectTicks;
|
||||
bool isElytraFlying();
|
||||
virtual void setElytraFlying(bool flying);
|
||||
|
||||
virtual void onElytraKineticDamage(float damage);
|
||||
|
||||
public:
|
||||
|
||||
BYTE userType;
|
||||
float oBob, bob;
|
||||
|
||||
|
|
@ -351,6 +367,7 @@ private:
|
|||
bool m_bAwardedOnARail;
|
||||
|
||||
protected:
|
||||
virtual void checkFallDamage(double ya, bool onGround) override;
|
||||
virtual void causeFallDamage(float distance);
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -261,6 +261,8 @@ enum eSOUND_TYPE
|
|||
eSoundType_ITEM_ARMOR_equipGeneric6,
|
||||
|
||||
eSoundType_DAMAGE_CRITICAL,
|
||||
eSoundType_ITEM_ELYTRA_FLYING,
|
||||
|
||||
|
||||
eSoundType_MAX
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1077,6 +1077,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_WORLD_ITEM
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/DyePowderItem.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EggItem.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EggItem.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/ElytraItem.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/ElytraItem.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EmptyMapItem.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EmptyMapItem.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/EnchantedBookItem.cpp"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "ArmorItem.h"
|
||||
#include "ElytraItem.h"
|
||||
#include "BedItem.h"
|
||||
#include "BoatItem.h"
|
||||
#include "BowItem.h"
|
||||
|
|
|
|||
Loading…
Reference in a new issue