mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-04-24 16:08:43 +00:00
commit b40530fa5e12bdd0e2d03686b111964f9c5b3359
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Wed Apr 15 19:59:46 2026 -0700
Implemented skin offsets in UI
Added code to render skin offsets in the skin select UI.
commit a8384d984089b989a162550705dee7a505412e22
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Wed Apr 15 19:38:08 2026 -0700
Partially implemented offsets
Added code that visually shifts the player's model parts, but only in game not in the skin select UI.
commit 875100cf9afe7df258dc653a4b33857d3cd285c1
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Wed Apr 15 16:48:03 2026 -0700
Minor change
Simplified redundant conditions in HumanoidModel.cpp
commit 96f683d1fb93d09a49987460ef698e0d125c2c93
Merge: db685a74 24c74aa2
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Tue Apr 14 16:37:30 2026 -0700
Merge branch 'feat/64x64-skins' into feat/skin-offsets
commit db685a74f34d02cc83e33ab97c5a7ad9a62ef023
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Tue Apr 14 15:35:38 2026 -0700
Fixed skin offset data
Fixed skin offsets so they now return the actual data instead of the defaults, added a few minor tweaks, and added code in PlayerRenderer.cpp to access offsets (Can read the offsets but can not apply them).
commit aa769d54adb8f5bf96c75d10766422d23cc9129a
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Sat Apr 11 19:36:52 2026 -0700
Fixed crashes
Fixed code for offsets preventing crashes. The amount of offsets is correctly obtain, but lacks the actual data.
commit f18ac12cc072db74ed9b8da937e00c2e15f889a0
Merge: 8e76763a fd2fd659
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Fri Apr 10 16:06:57 2026 -0700
Merge branch 'feat/64x64-skins' into feat/skin-offsets
commit 8e76763a3ddeaff943243fd0469d6c4a7b12b6c1
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Tue Apr 7 16:50:43 2026 -0700
Made more changes
Made more changes in files to support skin offsets. The game still crashes when trying to load skins.
commit 1a8f3532979033717044e74e6ceb766e23e35032
Merge: a1d9ae59 bb5fa506
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Tue Apr 7 13:12:39 2026 -0700
Merge branch 'feat/64x64-skins' into feat/skin-offsets
commit a1d9ae591ac27117626aac708a4204a9e2451684
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Fri Apr 3 21:50:42 2026 -0700
Added small additions
Added more code referencing skin offsets. Still doesn't work correctly.
commit d28a751d9ca0527854e40be82e7841a650c2f189
Merge: 3888de7a 8bf03435
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Thu Apr 2 17:09:08 2026 -0700
Merge branch 'smartcmd:main' into feat/skin-offsets
commit 3888de7ab401d9562b7b922eca8b898aa73ba024
Author: Langtanium <94726057+Langtanium@users.noreply.github.com>
Date: Thu Apr 2 17:07:48 2026 -0700
Added code for skin offsets
Added code to the file which have the functionality to get skin boxes and duplicated the functionality for skin offsets. The code causes the game to crash when switching to third person. The error occurs with the skin offsets returning as an empty class object.
1703 lines
48 KiB
C++
1703 lines
48 KiB
C++
#include "stdafx.h"
|
|
#include "LocalPlayer.h"
|
|
#include "User.h"
|
|
#include "Input.h"
|
|
#include "StatsCounter.h"
|
|
#include "ParticleEngine.h"
|
|
#include "TakeAnimationParticle.h"
|
|
#include "Options.h"
|
|
#include "TextEditScreen.h"
|
|
#include "ContainerScreen.h"
|
|
#include "CraftingScreen.h"
|
|
#include "FurnaceScreen.h"
|
|
#include "TrapScreen.h"
|
|
|
|
#include "MultiPlayerLocalPlayer.h"
|
|
#include "CreativeMode.h"
|
|
#include "GameRenderer.h"
|
|
#include "ItemInHandRenderer.h"
|
|
#include "..\Minecraft.World\AttributeInstance.h"
|
|
#include "..\Minecraft.World\LevelData.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.damagesource.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.item.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.food.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.effect.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.entity.monster.h"
|
|
#include "..\Minecraft.World\ItemEntity.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.level.tile.entity.h"
|
|
#include "..\Minecraft.World\net.minecraft.world.phys.h"
|
|
#include "..\Minecraft.World\net.minecraft.stats.h"
|
|
#include "..\Minecraft.World\com.mojang.nbt.h"
|
|
#include "..\Minecraft.World\Random.h"
|
|
#include "..\Minecraft.World\TileEntity.h"
|
|
#include "..\Minecraft.World\Mth.h"
|
|
#include "AchievementPopup.h"
|
|
#include "CritParticle.h"
|
|
|
|
// 4J : WESTY : Added for new achievements.
|
|
#include "..\Minecraft.World\item.h"
|
|
#include "..\Minecraft.World\mapitem.h"
|
|
#include "..\Minecraft.World\tile.h"
|
|
|
|
// 4J Stu - Added for tutorial callbacks
|
|
#include "Minecraft.h"
|
|
|
|
#include "..\Minecraft.World\Minecart.h"
|
|
#include "..\Minecraft.World\Boat.h"
|
|
#include "..\Minecraft.World\Pig.h"
|
|
|
|
#include "..\Minecraft.World\StringHelpers.h"
|
|
|
|
#include "Options.h"
|
|
#include "..\Minecraft.World\Dimension.h"
|
|
|
|
#ifndef _DURANGO
|
|
#include "..\Minecraft.World\CommonStats.h"
|
|
#endif
|
|
extern ConsoleUIController ui;
|
|
|
|
|
|
LocalPlayer::LocalPlayer(Minecraft *minecraft, Level *level, User *user, int dimension) : Player(level, user->name)
|
|
{
|
|
flyX = flyY = flyZ = 0.0f; // 4J added
|
|
m_awardedThisSession = 0;
|
|
|
|
sprintTriggerTime = 0;
|
|
sprintTriggerRegisteredReturn = false;
|
|
twoJumpsRegistered = false;
|
|
sprintTime = 0;
|
|
m_uiInactiveTicks=0;
|
|
portalTime = 0.0f;
|
|
oPortalTime = 0.0f;
|
|
jumpRidingTicks = 0;
|
|
jumpRidingScale = 0.0f;
|
|
|
|
yBob = xBob = yBobO = xBobO = 0.0f;
|
|
|
|
this->minecraft = minecraft;
|
|
this->dimension = dimension;
|
|
|
|
if (user != nullptr && user->name.length() > 0)
|
|
{
|
|
customTextureUrl = L"http://s3.amazonaws.com/MinecraftSkins/" + user->name + L".png";
|
|
}
|
|
if( user != nullptr )
|
|
{
|
|
this->name = user->name;
|
|
//wprintf(L"Created LocalPlayer with name %ls\n", name.c_str() );
|
|
// check to see if this player's xuid is in the list of special players
|
|
MOJANG_DATA *pMojangData=app.GetMojangDataForXuid(getOnlineXuid());
|
|
if(pMojangData)
|
|
{
|
|
customTextureUrl=pMojangData->wchSkin;
|
|
}
|
|
|
|
}
|
|
input = nullptr;
|
|
m_iPad = -1;
|
|
m_iScreenSection=C4JRender::VIEWPORT_TYPE_FULLSCREEN; // assume singleplayer default
|
|
m_bPlayerRespawned=false;
|
|
ullButtonsPressed=0LL;
|
|
ullDpad_last = ullDpad_this = ullDpad_filtered = 0;
|
|
|
|
// 4J-PB - moved in from the minecraft structure
|
|
//ticks=0;
|
|
missTime=0;
|
|
lastClickTick[0] = 0;
|
|
lastClickTick[1] = 0;
|
|
isRaining=false;
|
|
|
|
m_bIsIdle = false;
|
|
m_iThirdPersonView=0;
|
|
|
|
// 4J Stu - Added for telemetry
|
|
SetSessionTimerStart();
|
|
|
|
// 4J - added for auto repeat in creative mode
|
|
lastClickState = lastClick_invalid;
|
|
lastClickTolerance = 0.0f;
|
|
|
|
m_bHasAwardedStayinFrosty = false;
|
|
}
|
|
|
|
LocalPlayer::~LocalPlayer()
|
|
{
|
|
if( this->input != nullptr )
|
|
delete input;
|
|
}
|
|
|
|
void LocalPlayer::calculateFlight(float xa, float ya, float za)
|
|
{
|
|
xa = xa * minecraft->options->flySpeed;
|
|
ya = 0;
|
|
za = za * minecraft->options->flySpeed;
|
|
|
|
flyX = smoothFlyX.getNewDeltaValue(xa, .35f * minecraft->options->sensitivity);
|
|
flyY = smoothFlyY.getNewDeltaValue(ya, .35f * minecraft->options->sensitivity);
|
|
flyZ = smoothFlyZ.getNewDeltaValue(za, .35f * minecraft->options->sensitivity);
|
|
}
|
|
|
|
void LocalPlayer::serverAiStep()
|
|
{
|
|
Player::serverAiStep();
|
|
|
|
this->xxa = input->xa;
|
|
this->yya = input->ya;
|
|
this->jumping = input->jumping;
|
|
|
|
yBobO = yBob;
|
|
xBobO = xBob;
|
|
xBob += (xRot - xBob) * 0.5;
|
|
yBob += (yRot - yBob) * 0.5;
|
|
|
|
// TODO 4J - Remove
|
|
//if (input->jumping)
|
|
// mapPlayerChunk(8);
|
|
}
|
|
|
|
bool LocalPlayer::isEffectiveAi()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void LocalPlayer::aiStep()
|
|
{
|
|
if (sprintTime > 0)
|
|
{
|
|
sprintTime--;
|
|
if (sprintTime == 0)
|
|
{
|
|
setSprinting(false);
|
|
}
|
|
}
|
|
if (sprintTriggerTime > 0) sprintTriggerTime--;
|
|
if (minecraft->gameMode->isCutScene())
|
|
{
|
|
x = z = 0.5;
|
|
x = 0;
|
|
z = 0;
|
|
yRot = tickCount / 12.0f;
|
|
xRot = 10;
|
|
y = 68.5;
|
|
return;
|
|
}
|
|
oPortalTime = portalTime;
|
|
if (isInsidePortal)
|
|
{
|
|
if (!level->isClientSide)
|
|
{
|
|
if (riding != nullptr) this->ride(nullptr);
|
|
}
|
|
if (minecraft->screen != nullptr) minecraft->setScreen(nullptr);
|
|
|
|
if (portalTime == 0)
|
|
{
|
|
minecraft->soundEngine->playUI(eSoundType_PORTAL_TRIGGER, 1, random->nextFloat() * 0.4f + 0.8f);
|
|
}
|
|
portalTime += 1 / 80.0f;
|
|
if (portalTime >= 1)
|
|
{
|
|
portalTime = 1;
|
|
}
|
|
isInsidePortal = false;
|
|
}
|
|
else if (hasEffect(MobEffect::confusion) && getEffect(MobEffect::confusion)->getDuration() > (SharedConstants::TICKS_PER_SECOND * 3))
|
|
{
|
|
portalTime += 1 / 150.0f;
|
|
if (portalTime > 1)
|
|
{
|
|
portalTime = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (portalTime > 0) portalTime -= 1 / 20.0f;
|
|
if (portalTime < 0) portalTime = 0;
|
|
}
|
|
|
|
if (changingDimensionDelay > 0) changingDimensionDelay--;
|
|
bool wasJumping = input->jumping;
|
|
float runTreshold = 0.8f;
|
|
bool wasRunning = input->ya >= runTreshold;
|
|
//input->tick( dynamic_pointer_cast<Player>( shared_from_this() ) );
|
|
// 4J-PB - make it a localplayer
|
|
input->tick( this );
|
|
if (isUsingItem() && !isRiding())
|
|
{
|
|
input->xa *= 0.2f;
|
|
input->ya *= 0.2f;
|
|
sprintTriggerTime = 0;
|
|
}
|
|
// this.heightOffset = input.sneaking?1.30f:1.62f; // 4J - this was already commented out
|
|
if (input->sneaking) // 4J - removed - TODO replace
|
|
{
|
|
if (ySlideOffset < 0.2f) ySlideOffset = 0.2f;
|
|
}
|
|
|
|
checkInTile(x - bbWidth * 0.35, bb->y0 + 0.5, z + bbWidth * 0.35);
|
|
checkInTile(x - bbWidth * 0.35, bb->y0 + 0.5, z - bbWidth * 0.35);
|
|
checkInTile(x + bbWidth * 0.35, bb->y0 + 0.5, z - bbWidth * 0.35);
|
|
checkInTile(x + bbWidth * 0.35, bb->y0 + 0.5, z + bbWidth * 0.35);
|
|
|
|
bool enoughFoodToSprint = getFoodData()->getFoodLevel() > FoodConstants::MAX_FOOD * FoodConstants::FOOD_SATURATION_LOW;
|
|
|
|
// 4J Stu - If we can fly, then we should be able to sprint without requiring food. This is particularly a problem for people who save a survival
|
|
// world with low food, then reload it in creative.
|
|
if(abilities.mayfly || isAllowedToFly() ) enoughFoodToSprint = true;
|
|
|
|
bool forwardEnoughToTriggerSprint = input->ya >= runTreshold;
|
|
bool forwardReturnedToDeadzone = input->ya == 0.0f;
|
|
bool forwardEnoughToContinueSprint = input->ya >= runTreshold;
|
|
|
|
// 4J - altered this slightly to make sure that the joypad returns to below returnTreshold in between registering two movements up to runThreshold
|
|
if (onGround && !isSprinting() && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness))
|
|
{
|
|
if( !wasRunning && forwardEnoughToTriggerSprint )
|
|
{
|
|
if (sprintTriggerTime == 0)
|
|
{
|
|
sprintTriggerTime = 7;
|
|
sprintTriggerRegisteredReturn = false;
|
|
}
|
|
else
|
|
{
|
|
if( sprintTriggerRegisteredReturn )
|
|
{
|
|
setSprinting(true);
|
|
sprintTriggerTime = 0;
|
|
sprintTriggerRegisteredReturn = false;
|
|
}
|
|
}
|
|
}
|
|
else if( ( sprintTriggerTime > 0 ) && forwardReturnedToDeadzone ) // zero sprintForward here signifies that we have returned to the deadzone
|
|
{
|
|
sprintTriggerRegisteredReturn = true;
|
|
}
|
|
}
|
|
if (isSneaking()) sprintTriggerTime = 0;
|
|
#ifdef _WINDOWS64
|
|
if (input->sprinting && !isSprinting() && onGround && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && !isSneaking())
|
|
{
|
|
setSprinting(true);
|
|
}
|
|
#endif
|
|
// 4J-PB - try not stopping sprint on collision
|
|
//if (isSprinting() && (input->ya < runTreshold || horizontalCollision || !enoughFoodToSprint))
|
|
if (isSprinting() && (!forwardEnoughToContinueSprint || !enoughFoodToSprint || isSneaking() || isUsingItem()))
|
|
{
|
|
setSprinting(false);
|
|
}
|
|
|
|
// 4J Stu - Fix for #52705 - Customer Encountered: Player can fly in bed while being in Creative mode.
|
|
if (!isSleeping() && (abilities.mayfly || isAllowedToFly() ))
|
|
{
|
|
// 4J altered to require jump button to released after being tapped twice to trigger move between flying / not flying
|
|
if (!wasJumping && input->jumping)
|
|
{
|
|
if (jumpTriggerTime == 0)
|
|
{
|
|
jumpTriggerTime = 7; // the 4J team changed it to 10 because of additional requirements to initiate flight
|
|
twoJumpsRegistered = false;
|
|
}
|
|
else
|
|
{
|
|
twoJumpsRegistered = true;
|
|
}
|
|
}
|
|
else if(jumpTriggerTime > 0 && twoJumpsRegistered) //the 4J team checked if the player was NOT jumping after the two jumps, aka had let go of the jump button
|
|
{
|
|
#ifndef _CONTENT_PACKAGE
|
|
printf("flying was %s\n", abilities.flying ? "on" : "off");
|
|
#endif
|
|
abilities.flying = !abilities.flying;
|
|
#ifndef _CONTENT_PACKAGE
|
|
printf("flying is %s\n", abilities.flying ? "on" : "off");
|
|
#endif
|
|
jumpTriggerTime = 0;
|
|
twoJumpsRegistered = false;
|
|
if( abilities.flying ) input->sneaking = false; // 4J added - would we ever intentially want to go into flying mode whilst sneaking?
|
|
}
|
|
}
|
|
else if(abilities.flying)
|
|
{
|
|
#ifdef _DEBUG_MENUS_ENABLED
|
|
if(!abilities.debugflying)
|
|
#endif
|
|
{
|
|
abilities.flying = false;
|
|
}
|
|
}
|
|
|
|
|
|
if (abilities.flying)
|
|
{
|
|
// yd = 0;
|
|
// 4J - note that the 0.42 added for going down is to make it match with what happens when you jump - jumping itself adds 0.42 to yd in Mob::jumpFromGround
|
|
if (ullButtonsPressed & (1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE) ) yd -= ( 0.15 + 0.42 ); // 4J - for flying mode, MINECRAFT_ACTION_SNEAK_TOGGLE isn't a toggle but just indicates that this button is down
|
|
if (input->jumping)
|
|
{
|
|
noJumpDelay = 0;
|
|
yd += 0.15;
|
|
}
|
|
|
|
// snap y rotation to nearest 90 degree axis aligned value
|
|
float yRotSnapped = floorf((yRot / 90.0f) + 0.5f) * 90.0f;
|
|
|
|
if(InputManager.GetJoypadMapVal(m_iPad) == 0)
|
|
{
|
|
if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_RIGHT))
|
|
{
|
|
xd = -0.15 * cos(yRotSnapped * PI / 180);
|
|
zd = -0.15 * sin(yRotSnapped * PI / 180);
|
|
}
|
|
else if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_LEFT))
|
|
{
|
|
xd = 0.15 * cos(yRotSnapped * PI / 180);
|
|
zd = 0.15 * sin(yRotSnapped * PI / 180);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isRidingJumpable())
|
|
{
|
|
if (jumpRidingTicks < 0)
|
|
{
|
|
jumpRidingTicks++;
|
|
if (jumpRidingTicks == 0)
|
|
{
|
|
// reset scale (for gui)
|
|
jumpRidingScale = 0;
|
|
}
|
|
}
|
|
if (wasJumping && !input->jumping)
|
|
{
|
|
// jump release
|
|
jumpRidingTicks = -10;
|
|
sendRidingJump();
|
|
}
|
|
else if (!wasJumping && input->jumping)
|
|
{
|
|
// jump press
|
|
jumpRidingTicks = 0;
|
|
jumpRidingScale = 0;
|
|
}
|
|
else if (wasJumping)
|
|
{
|
|
// calc jump scale
|
|
jumpRidingTicks++;
|
|
if (jumpRidingTicks < 10)
|
|
{
|
|
jumpRidingScale = static_cast<float>(jumpRidingTicks) * .1f;
|
|
}
|
|
else
|
|
{
|
|
jumpRidingScale = .8f + (2.f / static_cast<float>(jumpRidingTicks - 9)) * .1f;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
jumpRidingScale = 0;
|
|
}
|
|
|
|
Player::aiStep();
|
|
|
|
// 4J-PB - If we're in Creative Mode, allow flying on ground
|
|
if(!abilities.mayfly && !isAllowedToFly() )
|
|
{
|
|
if (onGround && abilities.flying)
|
|
{
|
|
#ifdef _DEBUG_MENUS_ENABLED
|
|
if(!abilities.debugflying)
|
|
#endif
|
|
{
|
|
abilities.flying = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( abilities.flying )//minecraft->options->isFlying )
|
|
{
|
|
Vec3* viewVector = getViewVector(1.0f);
|
|
|
|
// 4J-PB - To let the player build easily while flying, we need to change this
|
|
|
|
#ifdef _DEBUG_MENUS_ENABLED
|
|
if(abilities.debugflying)
|
|
{
|
|
flyX = static_cast<float>(viewVector->x) * input->ya;
|
|
flyY = static_cast<float>(viewVector->y) * input->ya;
|
|
flyZ = static_cast<float>(viewVector->z) * input->ya;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if( isSprinting() )
|
|
{
|
|
// Accelrate up to full speed if we are sprinting, moving in the direction of the view vector
|
|
flyX = static_cast<float>(viewVector->x) * input->ya;
|
|
flyY = static_cast<float>(viewVector->y) * input->ya;
|
|
flyZ = static_cast<float>(viewVector->z) * input->ya;
|
|
|
|
float scale = static_cast<float>(SPRINT_DURATION - sprintTime)/10.0f;
|
|
scale = scale * scale;
|
|
if ( scale > 1.0f ) scale = 1.0f;
|
|
flyX *= scale;
|
|
flyY *= scale;
|
|
flyZ *= scale;
|
|
}
|
|
else
|
|
{
|
|
flyX = 0.0f;
|
|
flyY = 0.0f;
|
|
flyZ = 0.0f;
|
|
if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_UP))
|
|
{
|
|
flyY = 0.1f;
|
|
}
|
|
if( ullDpad_filtered & (1LL<<MINECRAFT_ACTION_DPAD_DOWN))
|
|
{
|
|
flyY = -0.1f;
|
|
}
|
|
}
|
|
}
|
|
|
|
Player::move(flyX, flyY, flyZ);
|
|
|
|
fallDistance = 0.0f;
|
|
yd = 0.0f;
|
|
onGround = true;
|
|
}
|
|
|
|
// Check if the player is idle and the rich presence needs updated
|
|
if( !m_bIsIdle && InputManager.GetIdleSeconds( m_iPad ) > PLAYER_IDLE_TIME )
|
|
{
|
|
ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_IDLE,false);
|
|
m_bIsIdle = true;
|
|
}
|
|
else if ( m_bIsIdle && InputManager.GetIdleSeconds( m_iPad ) < PLAYER_IDLE_TIME )
|
|
{
|
|
// Are we offline or online, and how many players are there
|
|
if(g_NetworkManager.GetPlayerCount()>1)
|
|
{
|
|
// only do it for this player here - each player will run this code
|
|
if(g_NetworkManager.IsLocalGame())
|
|
{
|
|
ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false);
|
|
}
|
|
else
|
|
{
|
|
ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYER,false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(g_NetworkManager.IsLocalGame())
|
|
{
|
|
ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false);
|
|
}
|
|
else
|
|
{
|
|
ProfileManager.SetCurrentGameActivity(m_iPad,CONTEXT_PRESENCE_MULTIPLAYER_1P,false);
|
|
}
|
|
}
|
|
updateRichPresence();
|
|
m_bIsIdle = false;
|
|
}
|
|
}
|
|
|
|
void LocalPlayer::changeDimension(int i)
|
|
{
|
|
if (!level->isClientSide)
|
|
{
|
|
if (dimension == 1 && i == 1)
|
|
{
|
|
awardStat(GenericStats::winGame(), GenericStats::param_noArgs());
|
|
//minecraft.setScreen(new WinScreen());
|
|
#ifndef _CONTENT_PACKAGE
|
|
app.DebugPrintf("LocalPlayer::changeDimension from 1 to 1 but WinScreen has not been implemented.\n");
|
|
__debugbreak();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
awardStat(GenericStats::theEnd(), GenericStats::param_theEnd());
|
|
|
|
minecraft->soundEngine->playUI(eSoundType_PORTAL_TRAVEL, 1, random->nextFloat() * 0.4f + 0.8f);
|
|
}
|
|
}
|
|
}
|
|
|
|
float LocalPlayer::getFieldOfViewModifier()
|
|
{
|
|
float targetFov = 1.0f;
|
|
|
|
// modify for movement
|
|
if (abilities.flying) targetFov *= 1.1f;
|
|
|
|
AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
|
|
targetFov *= (speed->getValue() / abilities.getWalkingSpeed() + 1) / 2;
|
|
|
|
// modify for bow =)
|
|
if (isUsingItem() && getUseItem()->id == Item::bow->id)
|
|
{
|
|
int ticksHeld = getTicksUsingItem();
|
|
float scale = static_cast<float>(ticksHeld) / BowItem::MAX_DRAW_DURATION;
|
|
if (scale > 1)
|
|
{
|
|
scale = 1;
|
|
}
|
|
else
|
|
{
|
|
scale *= scale;
|
|
}
|
|
targetFov *= 1.0f - scale * .15f;
|
|
}
|
|
|
|
return targetFov;
|
|
}
|
|
|
|
void LocalPlayer::addAdditonalSaveData(CompoundTag *entityTag)
|
|
{
|
|
Player::addAdditonalSaveData(entityTag);
|
|
//entityTag->putInt(L"Score", score);
|
|
}
|
|
|
|
void LocalPlayer::readAdditionalSaveData(CompoundTag *entityTag)
|
|
{
|
|
Player::readAdditionalSaveData(entityTag);
|
|
//score = entityTag->getInt(L"Score");
|
|
}
|
|
|
|
void LocalPlayer::closeContainer()
|
|
{
|
|
Player::closeContainer();
|
|
minecraft->setScreen(nullptr);
|
|
|
|
// 4J - Close any xui here
|
|
// Fix for #9164 - CRASH: MP: Title crashes upon opening a chest and having another user destroy it.
|
|
ui.PlayUISFX(eSFX_Back);
|
|
ui.CloseUIScenes( m_iPad );
|
|
}
|
|
|
|
void LocalPlayer::openTextEdit(shared_ptr<TileEntity> tileEntity)
|
|
{
|
|
bool success;
|
|
|
|
if (tileEntity->GetType() == eTYPE_SIGNTILEENTITY)
|
|
{
|
|
success = app.LoadSignEntryMenu(GetXboxPad(), dynamic_pointer_cast<SignTileEntity>(tileEntity));
|
|
}
|
|
else if (tileEntity->GetType() == eTYPE_COMMANDBLOCKTILEENTITY)
|
|
{
|
|
success = app.LoadCommandBlockMenu(GetXboxPad(), dynamic_pointer_cast<CommandBlockEntity>(tileEntity));
|
|
}
|
|
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft->setScreen(new TextEditScreen(sign));
|
|
}
|
|
|
|
bool LocalPlayer::openContainer(shared_ptr<Container> container)
|
|
{
|
|
bool success = app.LoadContainerMenu(GetXboxPad(), inventory, container );
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft->setScreen(new ContainerScreen(inventory, container));
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openHopper(shared_ptr<HopperTileEntity> container)
|
|
{
|
|
//minecraft->setScreen(new HopperScreen(inventory, container));
|
|
bool success = app.LoadHopperMenu(GetXboxPad(), inventory, container );
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openHopper(shared_ptr<MinecartHopper> container)
|
|
{
|
|
//minecraft->setScreen(new HopperScreen(inventory, container));
|
|
bool success = app.LoadHopperMenu(GetXboxPad(), inventory, container );
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openHorseInventory(shared_ptr<EntityHorse> horse, shared_ptr<Container> container)
|
|
{
|
|
//minecraft->setScreen(new HorseInventoryScreen(inventory, container, horse));
|
|
bool success = app.LoadHorseMenu(GetXboxPad(), inventory, container, horse);
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::startCrafting(int x, int y, int z)
|
|
{
|
|
bool success = app.LoadCrafting3x3Menu(GetXboxPad(), dynamic_pointer_cast<LocalPlayer>( shared_from_this() ), x, y, z );
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//app.LoadXuiCraftMenu(0,inventory, level, x, y, z);
|
|
//minecraft->setScreen(new CraftingScreen(inventory, level, x, y, z));
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openFireworks(int x, int y, int z)
|
|
{
|
|
bool success = app.LoadFireworksMenu(GetXboxPad(), dynamic_pointer_cast<LocalPlayer>( shared_from_this() ), x, y, z );
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::startEnchanting(int x, int y, int z, const wstring &name)
|
|
{
|
|
bool success = app.LoadEnchantingMenu(GetXboxPad(), inventory, x, y, z, level, name);
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft.setScreen(new EnchantmentScreen(inventory, level, x, y, z));
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::startRepairing(int x, int y, int z)
|
|
{
|
|
bool success = app.LoadRepairingMenu(GetXboxPad(), inventory, level, x, y, z );
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft.setScreen(new RepairScreen(inventory, level, x, y, z));
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openFurnace(shared_ptr<FurnaceTileEntity> furnace)
|
|
{
|
|
bool success = app.LoadFurnaceMenu(GetXboxPad(),inventory, furnace);
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft->setScreen(new FurnaceScreen(inventory, furnace));
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openBrewingStand(shared_ptr<BrewingStandTileEntity> brewingStand)
|
|
{
|
|
bool success = app.LoadBrewingStandMenu(GetXboxPad(),inventory, brewingStand);
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft.setScreen(new BrewingStandScreen(inventory, brewingStand));
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openBeacon(shared_ptr<BeaconTileEntity> beacon)
|
|
{
|
|
//minecraft->setScreen(new BeaconScreen(inventory, beacon));
|
|
bool success = app.LoadBeaconMenu(GetXboxPad(), inventory, beacon);
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openTrap(shared_ptr<DispenserTileEntity> trap)
|
|
{
|
|
bool success = app.LoadTrapMenu(GetXboxPad(),inventory, trap);
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft->setScreen(new TrapScreen(inventory, trap));
|
|
return success;
|
|
}
|
|
|
|
bool LocalPlayer::openTrading(shared_ptr<Merchant> traderTarget, const wstring &name)
|
|
{
|
|
bool success = app.LoadTradingMenu(GetXboxPad(),inventory, traderTarget, level, name);
|
|
if( success ) ui.PlayUISFX(eSFX_Press);
|
|
//minecraft.setScreen(new MerchantScreen(inventory, traderTarget, level));
|
|
return success;
|
|
}
|
|
|
|
void LocalPlayer::crit(shared_ptr<Entity> e)
|
|
{
|
|
shared_ptr<CritParticle> critParticle = std::make_shared<CritParticle>(reinterpret_cast<Level*>(minecraft->level), e);
|
|
critParticle->CritParticlePostConstructor();
|
|
minecraft->particleEngine->add(critParticle);
|
|
}
|
|
|
|
void LocalPlayer::magicCrit(shared_ptr<Entity> e)
|
|
{
|
|
shared_ptr<CritParticle> critParticle = std::make_shared<CritParticle>(reinterpret_cast<Level*>(minecraft->level), e, eParticleType_magicCrit);
|
|
critParticle->CritParticlePostConstructor();
|
|
minecraft->particleEngine->add(critParticle);
|
|
}
|
|
|
|
void LocalPlayer::take(shared_ptr<Entity> e, int orgCount)
|
|
{
|
|
minecraft->particleEngine->add(std::make_shared<TakeAnimationParticle>(reinterpret_cast<Level*>(minecraft->level), e, shared_from_this(), -0.5f));
|
|
}
|
|
|
|
void LocalPlayer::chat(const wstring& message)
|
|
{
|
|
}
|
|
|
|
bool LocalPlayer::isSneaking()
|
|
{
|
|
return input->sneaking && !m_isSleeping;
|
|
}
|
|
|
|
void LocalPlayer::hurtTo(float newHealth, ETelemetryChallenges damageSource)
|
|
{
|
|
float dmg = getHealth() - newHealth;
|
|
if (dmg <= 0)
|
|
{
|
|
setHealth(newHealth);
|
|
if (dmg < 0)
|
|
{
|
|
invulnerableTime = invulnerableDuration / 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lastHurt = dmg;
|
|
setHealth(getHealth());
|
|
invulnerableTime = invulnerableDuration;
|
|
actuallyHurt(DamageSource::genericSource,dmg);
|
|
hurtTime = hurtDuration = 10;
|
|
}
|
|
|
|
|
|
if( this->getHealth() <= 0)
|
|
{
|
|
int deathTime = static_cast<int>(level->getGameTime() % Level::TICKS_PER_DAY)/1000;
|
|
int carriedId = inventory->getSelected() == nullptr ? 0 : inventory->getSelected()->id;
|
|
TelemetryManager->RecordPlayerDiedOrFailed(GetXboxPad(), 0, y, 0, 0, carriedId, 0, damageSource);
|
|
|
|
// if there are any xuiscenes up for this player, close them
|
|
if(ui.GetMenuDisplayed(GetXboxPad()))
|
|
{
|
|
ui.CloseUIScenes(GetXboxPad());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void LocalPlayer::respawn()
|
|
{
|
|
// Select the right payer to respawn
|
|
minecraft->respawnPlayer(GetXboxPad(), 0, 0);
|
|
}
|
|
|
|
void LocalPlayer::animateRespawn()
|
|
{
|
|
// Player.animateRespawn(this, level);
|
|
}
|
|
|
|
void LocalPlayer::displayClientMessage(int messageId)
|
|
{
|
|
minecraft->gui->displayClientMessage(messageId, GetXboxPad());
|
|
}
|
|
|
|
void LocalPlayer::awardStat(Stat *stat, byteArray param)
|
|
{
|
|
#ifdef _DURANGO
|
|
// 4J-JEV: Maybe we want to fine tune this later? #TODO
|
|
if ( !ProfileManager.IsGuest(GetXboxPad())
|
|
&& app.CanRecordStatsAndAchievements()
|
|
&& ProfileManager.IsFullVersion()
|
|
)
|
|
{
|
|
stat->handleParamBlob(dynamic_pointer_cast<LocalPlayer>(shared_from_this()), param);
|
|
}
|
|
delete [] param.data;
|
|
#else
|
|
int count = CommonStats::readParam(param);
|
|
delete [] param.data;
|
|
|
|
if (!app.CanRecordStatsAndAchievements()) return;
|
|
if (stat == nullptr) return;
|
|
|
|
if (stat->isAchievement())
|
|
{
|
|
Achievement *ach = static_cast<Achievement *>(stat);
|
|
// 4J-PB - changed to attempt to award everytime - the award may need a storage device, so needs a primary player, and the player may not have been a primary player when they first 'got' the award
|
|
// so let the award manager figure it out
|
|
//if (!minecraft->stats[m_iPad]->hasTaken(ach))
|
|
{
|
|
// 4J-PB - Don't display the java popup
|
|
//minecraft->achievementPopup->popup(ach);
|
|
|
|
// 4J Stu - Added this function in the libraries as some achievements don't get awarded to all players
|
|
// e.g. Splitscreen players cannot get theme/avatar/gamerpic and Trial players cannot get any
|
|
// This causes some extreme flooding of some awards
|
|
if(ProfileManager.CanBeAwarded(m_iPad, ach->getAchievementID() ) )
|
|
{
|
|
// 4J Stu - We don't (currently) care about the gamerscore, so setting to a default of 0 points
|
|
TelemetryManager->RecordAchievementUnlocked(m_iPad,ach->getAchievementID(),0);
|
|
|
|
// 4J Stu - Some awards cause a menu to popup. This can be bad, especially if you are surrounded by mobs!
|
|
// We cannot pause the game unless in offline single player, but lets at least do it then
|
|
if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 && ProfileManager.GetAwardType(ach->getAchievementID() ) != eAwardType_Achievement )
|
|
{
|
|
ui.CloseUIScenes(m_iPad);
|
|
ui.NavigateToScene(m_iPad,eUIScene_PauseMenu);
|
|
}
|
|
}
|
|
|
|
// 4J-JEV: To stop spamming trophies.
|
|
unsigned long long achBit = static_cast<unsigned long long>(1) << ach->getAchievementID();
|
|
if ( !(achBit & m_awardedThisSession) )
|
|
{
|
|
ProfileManager.Award(m_iPad, ach->getAchievementID());
|
|
if (ProfileManager.IsFullVersion())
|
|
m_awardedThisSession |= achBit;
|
|
}
|
|
}
|
|
minecraft->stats[m_iPad]->award(stat, level->difficulty, count);
|
|
}
|
|
else
|
|
{
|
|
// 4J : WESTY : Added for new achievements.
|
|
StatsCounter* pStats = minecraft->stats[m_iPad];
|
|
pStats->award(stat, level->difficulty, count);
|
|
|
|
// 4J-JEV: Check achievements for unlocks.
|
|
|
|
// LEADER OF THE PACK
|
|
if ( stat == GenericStats::tamedEntity(eTYPE_WOLF) )
|
|
{
|
|
// Check to see if we have befriended 5 wolves! Is this really the best place to do this??!!
|
|
if ( pStats->getTotalValue(GenericStats::tamedEntity(eTYPE_WOLF)) >= 5 )
|
|
{
|
|
awardStat(GenericStats::leaderOfThePack(), GenericStats::param_noArgs());
|
|
}
|
|
}
|
|
|
|
// MOAR TOOLS
|
|
{
|
|
Stat *toolStats[4][5];
|
|
toolStats[0][0] = GenericStats::itemsCrafted(Item::shovel_wood->id);
|
|
toolStats[0][1] = GenericStats::itemsCrafted(Item::shovel_stone->id);
|
|
toolStats[0][2] = GenericStats::itemsCrafted(Item::shovel_iron->id);
|
|
toolStats[0][3] = GenericStats::itemsCrafted(Item::shovel_diamond->id);
|
|
toolStats[0][4] = GenericStats::itemsCrafted(Item::shovel_gold->id);
|
|
toolStats[1][0] = GenericStats::itemsCrafted(Item::pickAxe_wood->id);
|
|
toolStats[1][1] = GenericStats::itemsCrafted(Item::pickAxe_stone->id);
|
|
toolStats[1][2] = GenericStats::itemsCrafted(Item::pickAxe_iron->id);
|
|
toolStats[1][3] = GenericStats::itemsCrafted(Item::pickAxe_diamond->id);
|
|
toolStats[1][4] = GenericStats::itemsCrafted(Item::pickAxe_gold->id);
|
|
toolStats[2][0] = GenericStats::itemsCrafted(Item::hatchet_wood->id);
|
|
toolStats[2][1] = GenericStats::itemsCrafted(Item::hatchet_stone->id);
|
|
toolStats[2][2] = GenericStats::itemsCrafted(Item::hatchet_iron->id);
|
|
toolStats[2][3] = GenericStats::itemsCrafted(Item::hatchet_diamond->id);
|
|
toolStats[2][4] = GenericStats::itemsCrafted(Item::hatchet_gold->id);
|
|
toolStats[3][0] = GenericStats::itemsCrafted(Item::hoe_wood->id);
|
|
toolStats[3][1] = GenericStats::itemsCrafted(Item::hoe_stone->id);
|
|
toolStats[3][2] = GenericStats::itemsCrafted(Item::hoe_iron->id);
|
|
toolStats[3][3] = GenericStats::itemsCrafted(Item::hoe_diamond->id);
|
|
toolStats[3][4] = GenericStats::itemsCrafted(Item::hoe_gold->id);
|
|
|
|
bool justCraftedTool = false;
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
for (int j=0; j<5; j++)
|
|
{
|
|
if ( stat == toolStats[i][j] )
|
|
{
|
|
justCraftedTool = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (justCraftedTool)
|
|
{
|
|
bool awardNow = true;
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
bool craftedThisTool = false;
|
|
for (int j=0; j<5; j++)
|
|
{
|
|
if ( pStats->getTotalValue(toolStats[i][j]) > 0 )
|
|
craftedThisTool = true;
|
|
}
|
|
|
|
if (!craftedThisTool)
|
|
{
|
|
awardNow = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (awardNow)
|
|
{
|
|
awardStat(GenericStats::MOARTools(), GenericStats::param_noArgs());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef _XBOX
|
|
// AWARD: Have we killed 10 creepers?
|
|
if ( pStats->getTotalValue( GenericStats::killsCreeper() ) >= 10 )
|
|
{
|
|
awardStat( GenericStats::kill10Creepers(), GenericStats::param_noArgs());
|
|
}
|
|
|
|
// AWARD : Have we been playing for 100 game days?
|
|
if ( pStats->getTotalValue( GenericStats::timePlayed() ) >= ( Level::TICKS_PER_DAY * 100 ) )
|
|
{
|
|
awardStat( GenericStats::play100Days(), GenericStats::param_noArgs());
|
|
}
|
|
// AWARD : Have we mined 100 blocks?
|
|
if ( pStats->getTotalValue( GenericStats::totalBlocksMined() ) >= 100 )
|
|
{
|
|
awardStat( GenericStats::mine100Blocks(), GenericStats::param_noArgs());
|
|
}
|
|
#endif
|
|
|
|
#ifdef _EXTENDED_ACHIEVEMENTS
|
|
|
|
// AWARD : Porkchop, cook and eat a porkchop.
|
|
{
|
|
Stat *cookPorkchop, *eatPorkchop;
|
|
cookPorkchop = GenericStats::itemsCrafted(Item::porkChop_cooked_Id);
|
|
eatPorkchop = GenericStats::itemsUsed(Item::porkChop_cooked_Id);
|
|
|
|
if ( stat == cookPorkchop || stat == eatPorkchop )
|
|
{
|
|
int numCookPorkchop, numEatPorkchop;
|
|
numCookPorkchop = pStats->getTotalValue(cookPorkchop);
|
|
numEatPorkchop = pStats->getTotalValue(eatPorkchop);
|
|
|
|
app.DebugPrintf(
|
|
"[AwardStat] Check unlock 'Porkchop': "
|
|
"pork_cooked=%i, pork_eaten=%i.\n",
|
|
numCookPorkchop, numEatPorkchop
|
|
);
|
|
|
|
if ( (0 < numCookPorkchop) && (0 < numEatPorkchop) )
|
|
{
|
|
awardStat( GenericStats::porkChop(), GenericStats::param_porkChop() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// AWARD : Passing the Time, play for 100 minecraft days.
|
|
{
|
|
Stat *timePlayed = GenericStats::timePlayed();
|
|
|
|
if ( stat == timePlayed )
|
|
{
|
|
int iPlayedTicks, iRequiredTicks;
|
|
iPlayedTicks = pStats->getTotalValue(timePlayed);
|
|
iRequiredTicks = Level::TICKS_PER_DAY * 100;
|
|
|
|
/* app.DebugPrintf(
|
|
"[AwardStat] Check unlock 'Passing the Time': "
|
|
"total_ticks=%i, req=%i.\n",
|
|
iPlayedTicks, iRequiredTicks
|
|
); */
|
|
|
|
if (iPlayedTicks >= iRequiredTicks)
|
|
{
|
|
awardStat( GenericStats::passingTheTime(), GenericStats::param_passingTheTime() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// AWARD : The Haggler, Acquire 30 emeralds.
|
|
{
|
|
Stat *emeraldMined, *emeraldBought;
|
|
emeraldMined = GenericStats::blocksMined(Tile::emeraldOre_Id);
|
|
emeraldBought = GenericStats::itemsBought(Item::emerald_Id);
|
|
|
|
if ( stat == emeraldMined || stat == emeraldBought )
|
|
{
|
|
int numEmeraldMined, numEmeraldBought, totalSum;
|
|
numEmeraldMined = pStats->getTotalValue(emeraldMined);
|
|
numEmeraldBought = pStats->getTotalValue(emeraldBought);
|
|
totalSum = numEmeraldMined + numEmeraldBought;
|
|
|
|
app.DebugPrintf(
|
|
"[AwardStat] Check unlock 'The Haggler': "
|
|
"emerald_mined=%i, emerald_bought=%i, sum=%i.\n",
|
|
numEmeraldMined, numEmeraldBought, totalSum
|
|
);
|
|
|
|
if (totalSum >= 30) awardStat( GenericStats::theHaggler(), GenericStats::param_theHaggler() );
|
|
}
|
|
}
|
|
|
|
// AWARD : Pot Planter, craft and place a flowerpot.
|
|
{
|
|
Stat *craftFlowerpot, *placeFlowerpot;
|
|
craftFlowerpot = GenericStats::itemsCrafted(Item::flowerPot_Id);
|
|
placeFlowerpot = GenericStats::blocksPlaced(Tile::flowerPot_Id);
|
|
|
|
if ( stat == craftFlowerpot || stat == placeFlowerpot )
|
|
{
|
|
if ( (pStats->getTotalValue(craftFlowerpot) > 0) && (pStats->getTotalValue(placeFlowerpot) > 0) )
|
|
{
|
|
awardStat( GenericStats::potPlanter(), GenericStats::param_potPlanter() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// AWARD : It's a Sign, craft and place a sign.
|
|
{
|
|
Stat *craftSign, *placeWallsign, *placeSignpost;
|
|
craftSign = GenericStats::itemsCrafted(Item::sign_Id);
|
|
placeWallsign = GenericStats::blocksPlaced(Tile::wallSign_Id);
|
|
placeSignpost = GenericStats::blocksPlaced(Tile::sign_Id);
|
|
|
|
if ( stat == craftSign || stat == placeWallsign || stat == placeSignpost )
|
|
{
|
|
int numCraftedSigns, numPlacedWallSign, numPlacedSignpost;
|
|
numCraftedSigns = pStats->getTotalValue(craftSign);
|
|
numPlacedWallSign = pStats->getTotalValue(placeWallsign);
|
|
numPlacedSignpost = pStats->getTotalValue(placeSignpost);
|
|
|
|
app.DebugPrintf(
|
|
"[AwardStat] Check unlock 'It's a Sign': "
|
|
"crafted=%i, placedWallSigns=%i, placedSignposts=%i.\n",
|
|
numCraftedSigns, numPlacedWallSign, numPlacedSignpost
|
|
);
|
|
|
|
if ( (numCraftedSigns>0) && ((numPlacedWallSign+numPlacedSignpost)>0) )
|
|
{
|
|
awardStat( GenericStats::itsASign(), GenericStats::param_itsASign());
|
|
}
|
|
}
|
|
}
|
|
|
|
// AWARD : Rainbow Collection, collect all different colours of wool.
|
|
{
|
|
bool justPickedupWool = false;
|
|
|
|
for (int i=0; i<16; i++)
|
|
if ( stat == GenericStats::itemsCollected(Tile::wool_Id, i) )
|
|
justPickedupWool = true;
|
|
|
|
if (justPickedupWool)
|
|
{
|
|
unsigned int woolCount = 0;
|
|
|
|
for (unsigned int i = 0; i < 16; i++)
|
|
{
|
|
if (pStats->getTotalValue(GenericStats::itemsCollected(Tile::wool_Id, i)) > 0)
|
|
woolCount++;
|
|
}
|
|
|
|
if (woolCount >= 16) awardStat( GenericStats::rainbowCollection(), GenericStats::param_rainbowCollection() );
|
|
}
|
|
}
|
|
|
|
// AWARD : Adventuring Time, visit at least 17 biomes
|
|
{
|
|
bool justEnteredBiome = false;
|
|
|
|
for (int i=0; i<23; i++)
|
|
if ( stat == GenericStats::enteredBiome(i) )
|
|
justEnteredBiome = true;
|
|
|
|
if (justEnteredBiome)
|
|
{
|
|
unsigned int biomeCount = 0;
|
|
|
|
for (unsigned int i = 0; i < 23; i++)
|
|
{
|
|
if (pStats->getTotalValue(GenericStats::enteredBiome(i)) > 0)
|
|
biomeCount++;
|
|
}
|
|
|
|
if (biomeCount >= 17) awardStat( GenericStats::adventuringTime(), GenericStats::param_adventuringTime() );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool LocalPlayer::isSolidBlock(int x, int y, int z)
|
|
{
|
|
return level->isSolidBlockingTile(x, y, z);
|
|
}
|
|
|
|
bool LocalPlayer::checkInTile(double x, double y, double z)
|
|
{
|
|
int xTile = Mth::floor(x);
|
|
int yTile = Mth::floor(y);
|
|
int zTile = Mth::floor(z);
|
|
|
|
double xd = x - xTile;
|
|
double zd = z - zTile;
|
|
|
|
if (isSolidBlock(xTile, yTile, zTile) || isSolidBlock(xTile, yTile + 1, zTile))
|
|
{
|
|
bool west = !isSolidBlock(xTile - 1, yTile, zTile) && !isSolidBlock(xTile - 1, yTile + 1, zTile);
|
|
bool east = !isSolidBlock(xTile + 1, yTile, zTile) && !isSolidBlock(xTile + 1, yTile + 1, zTile);
|
|
bool north = !isSolidBlock(xTile, yTile, zTile - 1) && !isSolidBlock(xTile, yTile + 1, zTile - 1);
|
|
bool south = !isSolidBlock(xTile, yTile, zTile + 1) && !isSolidBlock(xTile, yTile + 1, zTile + 1);
|
|
|
|
int dir = -1;
|
|
double closest = 9999;
|
|
if (west && xd < closest)
|
|
{
|
|
closest = xd;
|
|
dir = 0;
|
|
}
|
|
if (east && 1 - xd < closest)
|
|
{
|
|
closest = 1 - xd;
|
|
dir = 1;
|
|
}
|
|
if (north && zd < closest)
|
|
{
|
|
closest = zd;
|
|
dir = 4;
|
|
}
|
|
if (south && 1 - zd < closest)
|
|
{
|
|
closest = 1 - zd;
|
|
dir = 5;
|
|
}
|
|
|
|
float speed = 0.1f;
|
|
if (dir == 0) this->xd = -speed;
|
|
if (dir == 1) this->xd = +speed;
|
|
if (dir == 4) this->zd = -speed;
|
|
if (dir == 5) this->zd = +speed;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
void LocalPlayer::setSprinting(bool value)
|
|
{
|
|
Player::setSprinting(value);
|
|
if (value == false) sprintTime = 0;
|
|
else sprintTime = SPRINT_DURATION;
|
|
}
|
|
|
|
void LocalPlayer::setExperienceValues(float experienceProgress, int totalExp, int experienceLevel)
|
|
{
|
|
this->experienceProgress = experienceProgress;
|
|
this->totalExperience = totalExp;
|
|
this->experienceLevel = experienceLevel;
|
|
}
|
|
|
|
// 4J: removed
|
|
//void LocalPlayer::sendMessage(ChatMessageComponent *message)
|
|
//{
|
|
// minecraft->gui->getChat()->addMessage(message.toString(true));
|
|
//}
|
|
|
|
Pos LocalPlayer::getCommandSenderWorldPosition()
|
|
{
|
|
return new Pos(floor(x + .5), floor(y + .5), floor(z + .5));
|
|
}
|
|
|
|
shared_ptr<ItemInstance> LocalPlayer::getCarriedItem()
|
|
{
|
|
return inventory->getSelected();
|
|
}
|
|
|
|
void LocalPlayer::playSound(int soundId, float volume, float pitch)
|
|
{
|
|
level->playLocalSound(x, y - heightOffset, z, soundId, volume, pitch, false);
|
|
}
|
|
|
|
bool LocalPlayer::isRidingJumpable()
|
|
{
|
|
return riding != nullptr && riding->GetType() == eTYPE_HORSE;
|
|
}
|
|
|
|
float LocalPlayer::getJumpRidingScale()
|
|
{
|
|
return jumpRidingScale;
|
|
}
|
|
|
|
void LocalPlayer::sendRidingJump()
|
|
{
|
|
}
|
|
|
|
bool LocalPlayer::hasPermission(EGameCommand command)
|
|
{
|
|
return level->getLevelData()->getAllowCommands();
|
|
}
|
|
|
|
void LocalPlayer::onCrafted(shared_ptr<ItemInstance> item)
|
|
{
|
|
if( minecraft->localgameModes[m_iPad] != nullptr )
|
|
{
|
|
TutorialMode *gameMode = static_cast<TutorialMode *>(minecraft->localgameModes[m_iPad]);
|
|
gameMode->getTutorial()->onCrafted(item);
|
|
}
|
|
}
|
|
|
|
void LocalPlayer::setAndBroadcastCustomSkin(DWORD skinId)
|
|
{
|
|
setCustomSkin(skinId);
|
|
}
|
|
|
|
void LocalPlayer::setAndBroadcastCustomCape(DWORD capeId)
|
|
{
|
|
setCustomCape(capeId);
|
|
}
|
|
|
|
// 4J TODO - Remove
|
|
#include "..\Minecraft.World\LevelChunk.h"
|
|
void LocalPlayer::mapPlayerChunk(const unsigned int flagTileType)
|
|
{
|
|
int cx = this->xChunk;
|
|
int cz = this->zChunk;
|
|
|
|
int pZ = static_cast<int>(floor(this->z)) %16;
|
|
int pX = static_cast<int>(floor(this->x)) %16;
|
|
|
|
cout<<"player in chunk ("<<cx<<","<<cz<<") at ("
|
|
<<this->x<<","<<this->y<<","<<this->z<<")\n";
|
|
|
|
for (int v = -1; v < 2; v++)
|
|
for (unsigned int z = 0; z < 16; z++)
|
|
{
|
|
for (int u = -1; u < 2; u++)
|
|
for (unsigned int x = 0; x < 16; x++)
|
|
{
|
|
LevelChunk *cc = level->getChunk(cx+u, cz+v);
|
|
if ( x==pX && z==pZ && u==0 && v==0)
|
|
cout << "O";
|
|
else for (unsigned int y = 127; y > 0; y--)
|
|
{
|
|
int t = cc->getTile(x,y,z);
|
|
if (flagTileType != 0 && t == flagTileType) { cout << "@"; break; }
|
|
else if (t != 0 && t < 10) { cout << t; break; }
|
|
else if (t > 0) { cout << "#"; break; }
|
|
}
|
|
}
|
|
cout << "\n";
|
|
}
|
|
|
|
cout << "\n";
|
|
}
|
|
|
|
|
|
void LocalPlayer::handleMouseDown(int button, bool down)
|
|
{
|
|
// 4J Stu - We should not accept any input while asleep, except the above to wake up
|
|
if(isSleeping() && level != nullptr && level->isClientSide)
|
|
{
|
|
return;
|
|
}
|
|
if (!down) missTime = 0;
|
|
if (button == 0 && missTime > 0) return;
|
|
|
|
if (down && minecraft->hitResult != nullptr && minecraft->hitResult->type == HitResult::TILE && button == 0)
|
|
{
|
|
int x = minecraft->hitResult->x;
|
|
int y = minecraft->hitResult->y;
|
|
int z = minecraft->hitResult->z;
|
|
|
|
// 4J - addition to stop layer mining out of the top or bottom of the world
|
|
// 4J Stu - Allow this for The End
|
|
if( ( ( y == 0 ) || ( ( y == 127 ) && level->dimension->hasCeiling ) ) && level->dimension->id != 1 ) return;
|
|
|
|
minecraft->gameMode->continueDestroyBlock(x, y, z, minecraft->hitResult->f);
|
|
|
|
if(mayDestroyBlockAt(x,y,z))
|
|
{
|
|
minecraft->particleEngine->crack(x, y, z, minecraft->hitResult->f);
|
|
swing();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
minecraft->gameMode->stopDestroyBlock();
|
|
}
|
|
}
|
|
|
|
bool LocalPlayer::creativeModeHandleMouseClick(int button, bool buttonPressed)
|
|
{
|
|
if( buttonPressed )
|
|
{
|
|
if( lastClickState == lastClick_oldRepeat )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Are we in an auto-repeat situation? - If so only tell the game that we've clicked if we move more than a unit away from our last
|
|
// click position in any axis
|
|
if( lastClickState != lastClick_invalid )
|
|
{
|
|
// If we're in disabled mode already (set when sprinting) then don't do anything - if we're sprinting, we don't auto-repeat at all.
|
|
// With auto repeat on, we can quickly place fires causing photosensitivity issues due to rapid flashing
|
|
if( lastClickState == lastClick_disabled ) return false;
|
|
// If we've started sprinting, go into this mode & also don't do anything
|
|
// Ignore repeate when sleeping
|
|
if( isSprinting() )
|
|
{
|
|
lastClickState = lastClick_disabled;
|
|
return false;
|
|
}
|
|
|
|
// Get distance from last click point in each axis
|
|
float dX = static_cast<float>(x) - lastClickX;
|
|
float dY = static_cast<float>(y) - lastClickY;
|
|
float dZ = static_cast<float>(z) - lastClickZ;
|
|
bool newClick = false;
|
|
|
|
float ddx = dX - lastClickdX;
|
|
float ddy = dY - lastClickdY;
|
|
float ddz = dZ - lastClickdZ;
|
|
|
|
if( lastClickState == lastClick_moving )
|
|
{
|
|
float deltaChange = sqrtf(ddx * ddx + ddy * ddy + ddz * ddz );
|
|
if( deltaChange < 0.01f )
|
|
{
|
|
lastClickState = lastClick_stopped;
|
|
lastClickTolerance = 0.0f;
|
|
}
|
|
}
|
|
else if( lastClickState == lastClick_stopped )
|
|
{
|
|
float deltaChange = sqrtf(ddx * ddx + ddy * ddy + ddz * ddz );
|
|
if( deltaChange >= 0.01f )
|
|
{
|
|
lastClickState = lastClick_moving;
|
|
lastClickTolerance = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
lastClickTolerance += 0.1f;
|
|
if( lastClickTolerance > 0.7f )
|
|
{
|
|
lastClickTolerance = 0.0f;
|
|
lastClickState = lastClick_init;
|
|
}
|
|
}
|
|
}
|
|
|
|
lastClickdX = dX;
|
|
lastClickdY = dY;
|
|
lastClickdZ = dZ;
|
|
|
|
// If we have moved more than one unit in any one axis, then register a new click
|
|
// The new click position is normalised at one unit in the direction of movement, so that we don't gradually drift away if we detect the movement a fraction over
|
|
// the unit distance each time
|
|
|
|
if( fabsf(dX) >= 1.0f )
|
|
{
|
|
dX= ( dX < 0.0f ) ? ceilf(dX) : floorf(dX);
|
|
newClick = true;
|
|
}
|
|
else if( fabsf(dY) >= 1.0f )
|
|
{
|
|
dY= ( dY < 0.0f ) ? ceilf(dY) : floorf(dY);
|
|
newClick = true;
|
|
}
|
|
else if( fabsf(dZ) >= 1.0f )
|
|
{
|
|
dZ= ( dZ < 0.0f ) ? ceilf(dZ) : floorf(dZ);
|
|
newClick = true;
|
|
}
|
|
|
|
if( ( !newClick ) && ( lastClickTolerance > 0.0f ) )
|
|
{
|
|
float fTarget = 1.0f - lastClickTolerance;
|
|
|
|
if( fabsf(dX) >= fTarget ) newClick = true;
|
|
if( fabsf(dY) >= fTarget ) newClick = true;
|
|
if( fabsf(dZ) >= fTarget ) newClick = true;
|
|
}
|
|
|
|
if( newClick )
|
|
{
|
|
lastClickX += dX;
|
|
lastClickY += dY;
|
|
lastClickZ += dZ;
|
|
|
|
// Get a more accurate pick from the position where the new click should ideally have come from, rather than
|
|
// where we happen to be now (ie a rounded number of units from the last Click position)
|
|
double oldX = x;
|
|
double oldY = y;
|
|
double oldZ = z;
|
|
x = lastClickX;
|
|
y = lastClickY;
|
|
z = lastClickZ;
|
|
|
|
minecraft->gameRenderer->pick(1);
|
|
|
|
x = oldX;
|
|
y = oldY;
|
|
z = oldZ;
|
|
|
|
handleMouseClick(button);
|
|
|
|
if( lastClickState == lastClick_stopped )
|
|
{
|
|
lastClickState = lastClick_init;
|
|
lastClickTolerance = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
lastClickState = lastClick_moving;
|
|
lastClickTolerance = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// First click - just record position & handle
|
|
lastClickX = static_cast<float>(x);
|
|
lastClickY = static_cast<float>(y);
|
|
lastClickZ = static_cast<float>(z);
|
|
// If we actually placed an item, then move into the init state as we are going to be doing the special creative mode auto repeat
|
|
bool itemPlaced = handleMouseClick(button);
|
|
// If we're sprinting or riding, don't auto-repeat at all. With auto repeat on, we can quickly place fires causing photosensitivity issues due to rapid flashing
|
|
// Also ignore repeats when the player is sleeping
|
|
if( isSprinting() || isRiding() || isSleeping() )
|
|
{
|
|
lastClickState = lastClick_disabled;
|
|
}
|
|
else
|
|
{
|
|
if( itemPlaced )
|
|
{
|
|
lastClickState = lastClick_init;
|
|
lastClickTolerance = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
// Didn't place an item - might actually be activating a switch or door or something - just do a standard auto repeat in this case
|
|
lastClickState = lastClick_oldRepeat;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lastClickState = lastClick_invalid;
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
bool LocalPlayer::handleMouseClick(int button)
|
|
{
|
|
bool returnItemPlaced = false;
|
|
|
|
if (button == 0 && missTime > 0) return false;
|
|
if (button == 0)
|
|
{
|
|
//app.DebugPrintf("handleMouseClick - Player %d is swinging\n",GetXboxPad());
|
|
swing();
|
|
}
|
|
|
|
bool mayUse = true;
|
|
|
|
// 4J-PB - Adding a special case in here for sleeping in a bed in a multiplayer game - we need to wake up, and we don't have the inbedchatscreen with a button
|
|
|
|
if(button==1 && (isSleeping() && level != nullptr && level->isClientSide))
|
|
{
|
|
if(lastClickState == lastClick_oldRepeat) return false;
|
|
|
|
|
|
shared_ptr<MultiplayerLocalPlayer> mplp = dynamic_pointer_cast<MultiplayerLocalPlayer>( shared_from_this() );
|
|
|
|
if(mplp && mplp->connection) mplp->StopSleeping();
|
|
|
|
}
|
|
// 4J Stu - We should not accept any input while asleep, except the above to wake up
|
|
if(isSleeping() && level != nullptr && level->isClientSide)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
shared_ptr<ItemInstance> oldItem = inventory->getSelected();
|
|
|
|
if (minecraft->hitResult == nullptr)
|
|
{
|
|
if (button == 0 && minecraft->localgameModes[GetXboxPad()]->hasMissTime()) missTime = 10;
|
|
}
|
|
else if (minecraft->hitResult->type == HitResult::ENTITY)
|
|
{
|
|
if (button == 0)
|
|
{
|
|
minecraft->gameMode->attack(minecraft->localplayers[GetXboxPad()], minecraft->hitResult->entity);
|
|
}
|
|
if (button == 1)
|
|
{
|
|
// 4J-PB - if we milk a cow here, and end up with a bucket of milk, the if (mayUse && button == 1) further down will
|
|
// then empty our bucket if we're pointing at a tile
|
|
// It looks like interact really should be returning a result so we can check this, but it's possibly just the
|
|
// milk bucket that causes a problem
|
|
|
|
if(minecraft->hitResult->entity->GetType()==eTYPE_COW)
|
|
{
|
|
// If I have an empty bucket in my hand, it's going to be filled with milk, so turn off mayUse
|
|
shared_ptr<ItemInstance> item = inventory->getSelected();
|
|
if(item && (item->id==Item::bucket_empty_Id))
|
|
{
|
|
mayUse=false;
|
|
}
|
|
}
|
|
if( minecraft->gameMode->interact(minecraft->localplayers[GetXboxPad()], minecraft->hitResult->entity) )
|
|
{
|
|
mayUse = false;
|
|
}
|
|
}
|
|
}
|
|
else if (minecraft->hitResult->type == HitResult::TILE)
|
|
{
|
|
int x = minecraft->hitResult->x;
|
|
int y = minecraft->hitResult->y;
|
|
int z = minecraft->hitResult->z;
|
|
int face = minecraft->hitResult->f;
|
|
|
|
if (button == 0)
|
|
{
|
|
// 4J - addition to stop layer mining out of the top or bottom of the world
|
|
// 4J Stu - Allow this for The End
|
|
if( !( ( y == 0 ) || ( ( y == 127 ) && level->dimension->hasCeiling ) ) || level->dimension->id == 1 )
|
|
{
|
|
minecraft->gameMode->startDestroyBlock(x, y, z, minecraft->hitResult->f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
shared_ptr<ItemInstance> item = oldItem;
|
|
int oldCount = item != nullptr ? item->count : 0;
|
|
bool usedItem = false;
|
|
if (minecraft->gameMode->useItemOn(minecraft->localplayers[GetXboxPad()], level, item, x, y, z, face, minecraft->hitResult->pos, false, &usedItem))
|
|
{
|
|
// Presume that if we actually used the held item, then we've placed it
|
|
if( usedItem )
|
|
{
|
|
returnItemPlaced = true;
|
|
}
|
|
mayUse = false;
|
|
//app.DebugPrintf("Player %d is swinging\n",GetXboxPad());
|
|
swing();
|
|
}
|
|
if (item == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (item->count == 0)
|
|
{
|
|
inventory->items[inventory->selected] = nullptr;
|
|
}
|
|
else if (item->count != oldCount || minecraft->localgameModes[GetXboxPad()]->hasInfiniteItems())
|
|
{
|
|
minecraft->gameRenderer->itemInHandRenderer->itemPlaced();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mayUse && button == 1)
|
|
{
|
|
shared_ptr<ItemInstance> item = inventory->getSelected();
|
|
if (item != nullptr)
|
|
{
|
|
if (minecraft->gameMode->useItem(minecraft->localplayers[GetXboxPad()], level, item))
|
|
{
|
|
minecraft->gameRenderer->itemInHandRenderer->itemUsed();
|
|
}
|
|
}
|
|
}
|
|
return returnItemPlaced;
|
|
}
|
|
|
|
void LocalPlayer::updateRichPresence()
|
|
{
|
|
if((m_iPad!=-1)/* && !ui.GetMenuDisplayed(m_iPad)*/ )
|
|
{
|
|
shared_ptr<ItemInstance> selectedItem = inventory->getSelected();
|
|
if(selectedItem != nullptr && selectedItem->id == Item::fishingRod_Id)
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_FISHING);
|
|
}
|
|
else if(selectedItem != nullptr && selectedItem->id == Item::map_Id)
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_MAP);
|
|
}
|
|
else if ( (riding != nullptr) && riding->instanceof(eTYPE_MINECART) )
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_RIDING_MINECART);
|
|
}
|
|
else if ( (riding != nullptr) && riding->instanceof(eTYPE_BOAT) )
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_BOATING);
|
|
}
|
|
else if ( (riding != nullptr) && riding->instanceof(eTYPE_PIG) )
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_RIDING_PIG);
|
|
}
|
|
else if( this->dimension == -1 )
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_NETHER);
|
|
}
|
|
else if( minecraft->soundEngine->GetIsPlayingStreamingCDMusic() )
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_CD);
|
|
}
|
|
else
|
|
{
|
|
app.SetRichPresenceContext(m_iPad,CONTEXT_GAME_STATE_BLANK);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 4J Stu - Added for telemetry
|
|
void LocalPlayer::SetSessionTimerStart(void)
|
|
{
|
|
m_sessionTimeStart=app.getAppTime();
|
|
m_dimensionTimeStart=m_sessionTimeStart;
|
|
}
|
|
|
|
float LocalPlayer::getSessionTimer(void)
|
|
{
|
|
return app.getAppTime()-m_sessionTimeStart;
|
|
}
|
|
|
|
float LocalPlayer::getAndResetChangeDimensionTimer()
|
|
{
|
|
float appTime = app.getAppTime();
|
|
float returnVal = appTime - m_dimensionTimeStart;
|
|
m_dimensionTimeStart = appTime;
|
|
return returnVal;
|
|
}
|
|
|
|
void LocalPlayer::handleCollectItem(shared_ptr<ItemInstance> item)
|
|
{
|
|
if(item != nullptr)
|
|
{
|
|
unsigned int itemCountAnyAux = 0;
|
|
unsigned int itemCountThisAux = 0;
|
|
for (unsigned int k = 0; k < inventory->items.length; ++k)
|
|
{
|
|
if (inventory->items[k] != nullptr)
|
|
{
|
|
// do they have the item
|
|
if(inventory->items[k]->id == item->id)
|
|
{
|
|
unsigned int quantity = inventory->items[k]->GetCount();
|
|
|
|
itemCountAnyAux += quantity;
|
|
|
|
if( inventory->items[k]->getAuxValue() == item->getAuxValue() )
|
|
{
|
|
itemCountThisAux += quantity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
TutorialMode *gameMode = static_cast<TutorialMode *>(minecraft->localgameModes[m_iPad]);
|
|
gameMode->getTutorial()->onTake(item, itemCountAnyAux, itemCountThisAux);
|
|
}
|
|
|
|
if(ui.IsContainerMenuDisplayed(m_iPad))
|
|
{
|
|
ui.HandleInventoryUpdated(m_iPad);
|
|
}
|
|
}
|
|
|
|
void LocalPlayer::SetPlayerAdditionalModelParts(vector<ModelPart *>pAdditionalModelParts)
|
|
{
|
|
m_pAdditionalModelParts=pAdditionalModelParts;
|
|
}
|
|
void LocalPlayer::SetPlayerModelOffsets(vector<SKIN_OFFSET *>pModelOffsets)
|
|
{
|
|
m_pModelOffsets=pModelOffsets;
|
|
}
|