Merge branch 'smartcmd:main' into main

This commit is contained in:
Alexandra-Myers 2026-03-13 13:49:54 -04:00 committed by GitHub
commit 6645cbc553
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 514 additions and 420 deletions

View file

@ -149,8 +149,56 @@ bool ClientConnection::isPrimaryConnection() const
return g_NetworkManager.IsHost() || m_userIndex == ProfileManager.GetPrimaryPad();
}
ClientConnection* ClientConnection::findPrimaryConnection() const
{
if (level == nullptr) return nullptr;
int primaryPad = ProfileManager.GetPrimaryPad();
MultiPlayerLevel* mpLevel = (MultiPlayerLevel*)level;
for (ClientConnection* conn : mpLevel->connections)
{
if (conn != this && conn->m_userIndex == primaryPad)
return conn;
}
return nullptr;
}
bool ClientConnection::shouldProcessForEntity(int entityId) const
{
if (g_NetworkManager.IsHost()) return true;
if (m_userIndex == ProfileManager.GetPrimaryPad()) return true;
ClientConnection* primary = findPrimaryConnection();
if (primary == nullptr) return true;
return !primary->isTrackingEntity(entityId);
}
bool ClientConnection::shouldProcessForPosition(int blockX, int blockZ) const
{
if (g_NetworkManager.IsHost()) return true;
if (m_userIndex == ProfileManager.GetPrimaryPad()) return true;
ClientConnection* primary = findPrimaryConnection();
if (primary == nullptr) return true;
return !primary->m_visibleChunks.count(chunkKey(blockX >> 4, blockZ >> 4));
}
bool ClientConnection::anyOtherConnectionHasChunk(int x, int z) const
{
if (level == nullptr) return false;
MultiPlayerLevel* mpLevel = (MultiPlayerLevel*)level;
int64_t key = chunkKey(x, z);
for (ClientConnection* conn : mpLevel->connections)
{
if (conn != this && conn->m_visibleChunks.count(key))
return true;
}
return false;
}
ClientConnection::~ClientConnection()
{
m_trackedEntityIds.clear();
m_visibleChunks.clear();
delete connection;
delete random;
delete savedDataStorage;
@ -664,6 +712,7 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
}
e->entityId = packet->id;
level->putEntity(packet->id, e);
m_trackedEntityIds.insert(packet->id);
if (packet->data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
{
@ -712,6 +761,7 @@ void ClientConnection::handleAddExperienceOrb(shared_ptr<AddExperienceOrbPacket>
e->xRot = 0;
e->entityId = packet->id;
level->putEntity(packet->id, e);
m_trackedEntityIds.insert(packet->id);
}
void ClientConnection::handleAddGlobalEntity(shared_ptr<AddGlobalEntityPacket> packet)
@ -738,13 +788,13 @@ void ClientConnection::handleAddPainting(shared_ptr<AddPaintingPacket> packet)
{
shared_ptr<Painting> painting = std::make_shared<Painting>(level, packet->x, packet->y, packet->z, packet->dir, packet->motive);
level->putEntity(packet->id, painting);
m_trackedEntityIds.insert(packet->id);
}
void ClientConnection::handleSetEntityMotion(shared_ptr<SetEntityMotionPacket> packet)
{
if (!isPrimaryConnection())
if (!shouldProcessForEntity(packet->id))
{
// Secondary connection: only accept motion for our own local player (knockback)
if (minecraft->localplayers[m_userIndex] == NULL ||
packet->id != minecraft->localplayers[m_userIndex]->entityId)
return;
@ -939,6 +989,7 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
app.DebugPrintf("Custom cape for player %ls is %ls\n",player->name.c_str(),player->customTextureUrl2.c_str());
level->putEntity(packet->id, player);
m_trackedEntityIds.insert(packet->id);
vector<shared_ptr<SynchedEntityData::DataItem> > *unpackedData = packet->getUnpackedData();
if (unpackedData != nullptr)
@ -979,7 +1030,7 @@ void ClientConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> pac
void ClientConnection::handleMoveEntity(shared_ptr<MoveEntityPacket> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForEntity(packet->id)) return;
shared_ptr<Entity> e = getEntity(packet->id);
if (e == nullptr) return;
e->xp += packet->xa;
@ -1009,7 +1060,7 @@ void ClientConnection::handleRotateMob(shared_ptr<RotateHeadPacket> packet)
void ClientConnection::handleMoveEntitySmall(shared_ptr<MoveEntityPacketSmall> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForEntity(packet->id)) return;
shared_ptr<Entity> e = getEntity(packet->id);
if (e == nullptr) return;
e->xp += packet->xa;
@ -1068,6 +1119,7 @@ void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packe
#endif
for (int i = 0; i < packet->ids.length; i++)
{
m_trackedEntityIds.erase(packet->ids[i]);
level->removeEntity(packet->ids[i]);
}
}
@ -1136,19 +1188,35 @@ void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaP
{
if (level == NULL) return;
for(int z = packet->m_minZ; z <= packet->m_maxZ; ++z)
{
for(int x = packet->m_minX; x <= packet->m_maxX; ++x)
{
m_visibleChunks.insert(chunkKey(x, z));
level->setChunkVisible(x, z, true);
}
}
}
void ClientConnection::handleChunkVisibility(shared_ptr<ChunkVisibilityPacket> packet)
{
if (level == NULL) return;
level->setChunkVisible(packet->x, packet->z, packet->visible);
if (packet->visible)
{
m_visibleChunks.insert(chunkKey(packet->x, packet->z));
level->setChunkVisible(packet->x, packet->z, true);
}
else
{
m_visibleChunks.erase(chunkKey(packet->x, packet->z));
if (!anyOtherConnectionHasChunk(packet->x, packet->z))
{
level->setChunkVisible(packet->x, packet->z, false);
}
}
}
void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
// 4J - changed to encode level in packet
MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx];
if( dimensionLevel )
@ -1218,7 +1286,6 @@ void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket>
void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
// 4J - changed to encode level in packet
MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx];
if( dimensionLevel )
@ -1279,7 +1346,6 @@ void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacke
void ClientConnection::handleTileUpdate(shared_ptr<TileUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
// 4J added - using a block of 255 to signify that this is a packet for destroying a tile, where we need to inform the level renderer that we are about to do so.
// This is used in creative mode as the point where a tile is first destroyed at the client end of things. Packets formed like this are potentially sent from
// ServerPlayerGameMode::destroyBlock
@ -1394,7 +1460,7 @@ void ClientConnection::send(shared_ptr<Packet> packet)
void ClientConnection::handleTakeItemEntity(shared_ptr<TakeItemEntityPacket> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForEntity(packet->itemId)) return;
shared_ptr<Entity> from = getEntity(packet->itemId);
shared_ptr<LivingEntity> to = dynamic_pointer_cast<LivingEntity>(getEntity(packet->playerId));
@ -2414,6 +2480,8 @@ void ClientConnection::close()
// If it's already done, then we don't need to do anything here. And in fact trying to do something could cause a crash
if(done) return;
done = true;
m_trackedEntityIds.clear();
m_visibleChunks.clear();
connection->flush();
connection->close(DisconnectPacket::eDisconnect_Closed);
}
@ -2453,6 +2521,7 @@ void ClientConnection::handleAddMob(shared_ptr<AddMobPacket> packet)
mob->yd = packet->yd / 8000.0f;
mob->zd = packet->zd / 8000.0f;
level->putEntity(packet->id, mob);
m_trackedEntityIds.insert(packet->id);
vector<shared_ptr<SynchedEntityData::DataItem> > *unpackedData = packet->getUnpackedData();
if (unpackedData != nullptr)
@ -2792,6 +2861,9 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
// so it doesn't leak into the new dimension
level->playStreamingMusic(L"", 0, 0, 0);
m_trackedEntityIds.clear();
m_visibleChunks.clear();
// Remove client connection from this level
level->removeClientConnection(this, false);
@ -2899,8 +2971,7 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
void ClientConnection::handleExplosion(shared_ptr<ExplodePacket> packet)
{
// World modification (block destruction) must only happen once
if (isPrimaryConnection())
if (shouldProcessForPosition((int)packet->x, (int)packet->z))
{
if(!packet->m_bKnockbackOnly)
{
@ -3244,7 +3315,6 @@ void ClientConnection::handleTileEditorOpen(shared_ptr<TileEditorOpenPacket> pac
void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
app.DebugPrintf("ClientConnection::handleSignUpdate - ");
if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z))
{
@ -3278,7 +3348,6 @@ void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
void ClientConnection::handleTileEntityData(shared_ptr<TileEntityDataPacket> packet)
{
if (!isPrimaryConnection()) return;
if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z))
{
shared_ptr<TileEntity> te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z);
@ -3331,7 +3400,6 @@ void ClientConnection::handleContainerClose(shared_ptr<ContainerClosePacket> pac
void ClientConnection::handleTileEvent(shared_ptr<TileEventPacket> packet)
{
if (!isPrimaryConnection()) return;
PIXBeginNamedEvent(0,"Handle tile event\n");
minecraft->level->tileEvent(packet->x, packet->y, packet->z, packet->tile, packet->b0, packet->b1);
PIXEndNamedEvent();
@ -3339,7 +3407,6 @@ void ClientConnection::handleTileEvent(shared_ptr<TileEventPacket> packet)
void ClientConnection::handleTileDestruction(shared_ptr<TileDestructionPacket> packet)
{
if (!isPrimaryConnection()) return;
minecraft->level->destroyTileProgress(packet->getEntityId(), packet->getX(), packet->getY(), packet->getZ(), packet->getState());
}
@ -3421,7 +3488,6 @@ void ClientConnection::handleGameEvent(shared_ptr<GameEventPacket> gameEventPack
void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> packet)
{
if (!isPrimaryConnection()) return;
if (packet->itemType == Item::map->id)
{
MapItem::getSavedData(packet->itemId, minecraft->level)->handleComplexItemData(packet->data);
@ -3436,7 +3502,7 @@ void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> p
void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForPosition(packet->x, packet->z)) return;
if (packet->type == LevelEvent::SOUND_DRAGON_DEATH)
{
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
@ -3456,8 +3522,6 @@ void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet)
{
minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data);
}
minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data);
}
void ClientConnection::handleAwardStat(shared_ptr<AwardStatPacket> packet)
@ -3660,7 +3724,6 @@ void ClientConnection::handlePlayerAbilities(shared_ptr<PlayerAbilitiesPacket> p
void ClientConnection::handleSoundEvent(shared_ptr<LevelSoundPacket> packet)
{
if (!isPrimaryConnection()) return;
minecraft->level->playLocalSound(packet->getX(), packet->getY(), packet->getZ(), packet->getSound(), packet->getVolume(), packet->getPitch(), false);
}
@ -3973,7 +4036,6 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket>
void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet)
{
if (!isPrimaryConnection()) return;
for (int i = 0; i < packet->getCount(); i++)
{
double xVarience = random->nextGaussian() * packet->getXDist();

View file

@ -1,4 +1,5 @@
#pragma once
#include <unordered_set>
#include "..\Minecraft.World\net.minecraft.network.h"
class Minecraft;
class MultiPlayerLevel;
@ -44,6 +45,20 @@ public:
private:
DWORD m_userIndex; // 4J Added
bool isPrimaryConnection() const;
std::unordered_set<int> m_trackedEntityIds;
std::unordered_set<int64_t> m_visibleChunks;
static int64_t chunkKey(int x, int z) { return ((int64_t)x << 32) | ((int64_t)z & 0xFFFFFFFF); }
ClientConnection* findPrimaryConnection() const;
bool shouldProcessForEntity(int entityId) const;
bool shouldProcessForPosition(int blockX, int blockZ) const;
bool anyOtherConnectionHasChunk(int x, int z) const;
public:
bool isTrackingEntity(int entityId) const { return m_trackedEntityIds.count(entityId) > 0; }
public:
SavedDataStorage *savedDataStorage;
ClientConnection(Minecraft *minecraft, const wstring& ip, int port);

View file

@ -260,9 +260,9 @@ void SoundEngine::updateMiniAudio()
continue;
}
float finalVolume = s->info.volume * m_MasterEffectsVolume;
if (finalVolume > 1.0f)
finalVolume = 1.0f;
float finalVolume = s->info.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, s->info.pitch);
@ -557,10 +557,13 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume, floa
}
ma_sound_set_spatialization_enabled(&s->sound, MA_TRUE);
ma_sound_set_min_distance(&s->sound, SFX_3D_MIN_DISTANCE);
ma_sound_set_max_distance(&s->sound, SFX_3D_MAX_DISTANCE);
ma_sound_set_rolloff(&s->sound, SFX_3D_ROLLOFF);
float finalVolume = volume * m_MasterEffectsVolume;
if (finalVolume > 1.0f)
finalVolume = 1.0f;
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);

View file

@ -6,6 +6,12 @@ using namespace std;
#include "miniaudio.h"
constexpr float SFX_3D_MIN_DISTANCE = 1.0f;
constexpr float SFX_3D_MAX_DISTANCE = 16.0f;
constexpr float SFX_3D_ROLLOFF = 0.5f;
constexpr float SFX_VOLUME_MULTIPLIER = 1.5f;
constexpr float SFX_MAX_GAIN = 1.5f;
enum eMUSICFILES
{
eStream_Overworld_Calm1 = 0,

View file

@ -455,6 +455,74 @@ unordered_map<wstring, ConsoleSchematicFile *> *LevelGenerationOptions::getUnfin
void LevelGenerationOptions::loadBaseSaveData()
{
#ifdef _WINDOWS64
int gameRulesCount = m_parentDLCPack ? m_parentDLCPack->getDLCItemsCount(DLCManager::e_DLCType_GameRulesHeader) : 0;
wstring baseSave = getBaseSavePath();
wstring packName = baseSave.substr(0, baseSave.find(L'.'));
for (int i = 0; i < gameRulesCount; ++i)
{
DLCGameRulesHeader* dlcFile = static_cast<DLCGameRulesHeader*>(m_parentDLCPack->getFile(DLCManager::e_DLCType_GameRulesHeader, i));
if (!dlcFile->getGrfPath().empty())
{
File grf(L"Windows64Media\\DLC\\" + packName + L"\\Data\\" + dlcFile->getGrfPath());
if (grf.exists())
{
wstring path = grf.getPath();
HANDLE fileHandle = CreateFileW(path.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
if (fileHandle != INVALID_HANDLE_VALUE)
{
DWORD dwFileSize = grf.length();
DWORD bytesRead;
PBYTE pbData = new BYTE[dwFileSize];
BOOL bSuccess = ReadFile(fileHandle, pbData, dwFileSize, &bytesRead, nullptr);
CloseHandle(fileHandle);
if (bSuccess)
{
dlcFile->setGrfData(pbData, dwFileSize, m_stringTable);
app.m_gameRules.setLevelGenerationOptions(dlcFile->lgo);
}
delete[] pbData;
}
}
}
}
if (requiresBaseSave() && !getBaseSavePath().empty())
{
File save(L"Windows64Media\\DLC\\" + packName + L"\\Data\\" + baseSave);
if (save.exists())
{
wstring path = save.getPath();
HANDLE fileHandle = CreateFileW(path.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
if (fileHandle != INVALID_HANDLE_VALUE)
{
DWORD dwFileSize = GetFileSize(fileHandle, nullptr);
DWORD bytesRead;
PBYTE pbData = new BYTE[dwFileSize];
BOOL bSuccess = ReadFile(fileHandle, pbData, dwFileSize, &bytesRead, nullptr);
CloseHandle(fileHandle);
if (bSuccess)
setBaseSaveData(pbData, dwFileSize);
else
delete[] pbData;
}
}
}
setLoadedData();
app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ReloadTexturePack);
#else
int mountIndex = -1;
if(m_parentDLCPack != nullptr) mountIndex = m_parentDLCPack->GetDLCMountIndex();
@ -481,6 +549,7 @@ void LevelGenerationOptions::loadBaseSaveData()
setLoadedData();
app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ReloadTexturePack);
}
#endif
}
int LevelGenerationOptions::packMounted(LPVOID pParam,int iPad,DWORD dwErr,DWORD dwLicenceMask)

View file

@ -942,13 +942,18 @@ int CGameNetworkManager::ServerThreadProc( void* lpParameter )
app.SetGameHostOption(eGameHostOption_All,param->settings);
// 4J Stu - If we are loading a DLC save that's separate from the texture pack, load
if( param->levelGen != nullptr && (param->texturePackId == 0 || param->levelGen->getRequiredTexturePackId() != param->texturePackId) )
if (param != nullptr && param->levelGen != nullptr && param->levelGen->isFromDLC())
{
while((Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()))
{
Sleep(1);
}
param->levelGen->loadBaseSaveData();
while (!param->levelGen->hasLoadedData())
{
Sleep(1);
}
}
}

View file

@ -240,7 +240,7 @@ void CPlatformNetworkManagerStub::DoWork()
qnetPlayer->m_resolvedXuid = INVALID_XUID;
qnetPlayer->m_gamertag[0] = 0;
qnetPlayer->SetCustomDataValue(0);
if (IQNet::s_playerCount > 1)
while (IQNet::s_playerCount > 1 && IQNet::m_player[IQNet::s_playerCount - 1].GetCustomDataValue() == 0)
IQNet::s_playerCount--;
}
// NOTE: Do NOT call PushFreeSmallId here. The old PlayerConnection's

View file

@ -1298,10 +1298,8 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
}
}
vPointerPos.x = floor(vPointerPos.x);
vPointerPos.x += ( static_cast<int>(vPointerPos.x)%2);
vPointerPos.y = floor(vPointerPos.y);
vPointerPos.y += ( static_cast<int>(vPointerPos.y)%2);
vPointerPos.x = static_cast<float>(floor(vPointerPos.x + 0.5f));
vPointerPos.y = static_cast<float>(floor(vPointerPos.y + 0.5f));
m_pointerPos = vPointerPos;
adjustPointerForSafeZone();

View file

@ -93,18 +93,22 @@ void UIComponent_Tooltips::updateSafeZone()
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
safeBottom = getSafeZoneHalfHeight();
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
safeLeft = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
safeBottom = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
safeRight = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
safeBottom = getSafeZoneHalfHeight();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
safeTop = getSafeZoneHalfHeight();
@ -112,22 +116,22 @@ void UIComponent_Tooltips::updateSafeZone()
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
safeTop = getSafeZoneHalfHeight();
safeRight = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
safeBottom = getSafeZoneHalfHeight();
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
safeBottom = getSafeZoneHalfHeight();
safeRight = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
break;
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
default:
safeTop = getSafeZoneHalfHeight();
safeBottom = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
safeRight = getSafeZoneHalfWidth();
break;
}
setSafeZone(safeTop, safeBottom, safeLeft, safeRight);

View file

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "UI.h"
#include "UIComponent_TutorialPopup.h"
#include "UISplitScreenHelpers.h"
#include "..\..\Common\Tutorial\Tutorial.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\MultiplayerLocalPlayer.h"
@ -474,27 +475,17 @@ void UIComponent_TutorialPopup::render(S32 width, S32 height, C4JRender::eViewpo
{
if(viewport != C4JRender::VIEWPORT_TYPE_FULLSCREEN)
{
S32 xPos = 0;
S32 yPos = 0;
switch( viewport )
{
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
xPos = static_cast<S32>(ui.getScreenWidth() / 2);
yPos = static_cast<S32>(ui.getScreenHeight() / 2);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
yPos = static_cast<S32>(ui.getScreenHeight() / 2);
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
xPos = static_cast<S32>(ui.getScreenWidth() / 2);
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
xPos = static_cast<S32>(ui.getScreenWidth() / 2);
yPos = static_cast<S32>(ui.getScreenHeight() / 2);
break;
}
// Derive the viewport origin and fit a 16:9 box inside it (same as UIScene::render),
// then apply safezone nudges so the popup stays clear of screen edges.
F32 originX, originY, viewW, viewH;
GetViewportRect(ui.getScreenWidth(), ui.getScreenHeight(), viewport, originX, originY, viewW, viewH);
S32 fitW, fitH, offsetX, offsetY;
Fit16x9(viewW, viewH, fitW, fitH, offsetX, offsetY);
S32 xPos = static_cast<S32>(originX) + offsetX;
S32 yPos = static_cast<S32>(originY) + offsetY;
//Adjust for safezone
switch( viewport )
{
@ -505,6 +496,7 @@ void UIComponent_TutorialPopup::render(S32 width, S32 height, C4JRender::eViewpo
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
yPos += getSafeZoneHalfHeight();
break;
default: break;
}
switch( viewport )
{
@ -515,10 +507,11 @@ void UIComponent_TutorialPopup::render(S32 width, S32 height, C4JRender::eViewpo
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
xPos -= getSafeZoneHalfWidth();
break;
default: break;
}
ui.setupRenderPosition(xPos, yPos);
IggyPlayerSetDisplaySize( getMovie(), width, height );
IggyPlayerSetDisplaySize( getMovie(), fitW, fitH );
IggyPlayerDraw( getMovie() );
}
else

View file

@ -172,15 +172,22 @@ void UIScene::updateSafeZone()
{
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
safeBottom = getSafeZoneHalfHeight();
// safeTop mirrors SPLIT_TOP for visual symmetry. safeBottom omitted.
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
safeRight = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
safeTop = getSafeZoneHalfHeight();
@ -188,22 +195,22 @@ void UIScene::updateSafeZone()
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
safeTop = getSafeZoneHalfHeight();
safeRight = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
safeBottom = getSafeZoneHalfHeight();
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
safeBottom = getSafeZoneHalfHeight();
safeRight = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
break;
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
default:
safeTop = getSafeZoneHalfHeight();
safeBottom = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
safeRight = getSafeZoneHalfWidth();
break;
}
setSafeZone(safeTop, safeBottom, safeLeft, safeRight);

View file

@ -278,7 +278,7 @@ void UIScene_FullscreenProgress::handleInput(int iPad, int key, bool repeat, boo
#ifdef __ORBIS__
case ACTION_MENU_TOUCHPAD_PRESS:
#endif
if(pressed)
if(pressed && m_threadCompleted)
{
sendInputToMovie(key, repeat, pressed, released);
}
@ -292,6 +292,7 @@ void UIScene_FullscreenProgress::handleInput(int iPad, int key, bool repeat, boo
}
break;
}
handled = true;
}
}

View file

@ -65,22 +65,26 @@ void UIScene_HUD::updateSafeZone()
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
safeRight = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
safeBottom = getSafeZoneHalfHeight();
// safeTop mirrors SPLIT_TOP so both players have the same vertical inset
// from their viewport's top edge (split divider), keeping GUI symmetrical.
// safeBottom is intentionally omitted: it would shift m_Hud.y upward in
// ActionScript, placing the hotbar too high relative to SPLIT_TOP.
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
safeRight = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
safeLeft = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
safeBottom = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
safeRight = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
safeBottom = getSafeZoneHalfHeight();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
safeTop = getSafeZoneHalfHeight();
@ -88,22 +92,22 @@ void UIScene_HUD::updateSafeZone()
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
safeTop = getSafeZoneHalfHeight();
safeRight = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
safeBottom = getSafeZoneHalfHeight();
safeTop = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
safeBottom = getSafeZoneHalfHeight();
safeRight = getSafeZoneHalfWidth();
safeTop = getSafeZoneHalfHeight();
break;
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
default:
safeTop = getSafeZoneHalfHeight();
safeBottom = getSafeZoneHalfHeight();
safeLeft = getSafeZoneHalfWidth();
safeRight = getSafeZoneHalfWidth();
break;
}
setSafeZone(safeTop, safeBottom, safeLeft, safeRight);
@ -734,7 +738,7 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor
IggyPlayerSetDisplaySize( getMovie(), (S32)(m_movieWidth * scale), (S32)(m_movieHeight * scale) );
repositionHud(tileWidth, tileHeight, scale);
repositionHud(tileWidth, tileHeight, scale, needsYTile);
m_renderWidth = tileWidth;
m_renderHeight = tileHeight;
@ -805,7 +809,7 @@ void UIScene_HUD::handleTimerComplete(int id)
//setVisible(anyVisible);
}
void UIScene_HUD::repositionHud(S32 tileWidth, S32 tileHeight, F32 scale)
void UIScene_HUD::repositionHud(S32 tileWidth, S32 tileHeight, F32 scale, bool needsYTile)
{
if(!m_bSplitscreen) return;

View file

@ -176,5 +176,5 @@ protected:
#endif
private:
void repositionHud(S32 tileWidth, S32 tileHeight, F32 scale);
void repositionHud(S32 tileWidth, S32 tileHeight, F32 scale, bool needsYTile);
};

View file

@ -150,8 +150,6 @@ void UIScene_InGameInfoMenu::updateTooltips()
void UIScene_InGameInfoMenu::handleDestroy()
{
g_NetworkManager.UnRegisterPlayerChangedCallback(m_iPad, &UIScene_InGameInfoMenu::OnPlayerChanged, this);
m_parentLayer->removeComponent(eUIComponent_MenuBackground);
}
void UIScene_InGameInfoMenu::handleGainFocus(bool navBack)

View file

@ -1,3 +0,0 @@
<Contributor ComponentSource="c:\users\paddy\work\tfs\minecraft\dev-cu2-xb1-ps4-x360\commonmedia.vcxproj">
<Configuration Name="Debug" />
</Contributor>

View file

@ -1,113 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:mx="http://schemas.microsoft.com/appx/2013/xbox/manifest" IgnorableNamespaces="mx">
<Identity Name="Minecraft" Publisher="CN=Publisher" Version="1.0.406.0" ProcessorArchitecture="x64" />
<Properties>
<DisplayName>Minecraft: Xbox One Edition</DisplayName>
<PublisherDisplayName>Microsoft Studios</PublisherDisplayName>
<Logo>StoreLogo.png</Logo>
<Description>Minecraft</Description>
</Properties>
<Prerequisites>
<OSMinVersion>6.2</OSMinVersion>
<OSMaxVersionTested>6.2</OSMaxVersionTested>
<mx:ApplicationEnvironment>title</mx:ApplicationEnvironment>
<mx:OSName>era</mx:OSName>
</Prerequisites>
<Resources>
<Resource Language="en-us" />
<Resource Language="en-gb" />
<Resource Language="de-de" />
<Resource Language="es-es" />
<Resource Language="es-mx" />
<Resource Language="fr-fr" />
<Resource Language="it-it" />
<Resource Language="pt-br" />
<Resource Language="pt-pt" />
<Resource Language="ja-jp" />
<Resource Language="ko-kr" />
<Resource Language="zh-tw" />
<Resource Language="zh-hk" />
</Resources>
<Applications>
<Application Id="App" Executable="Minecraft.Client.exe" EntryPoint="Minecraft.App">
<VisualElements DisplayName="Minecraft: Xbox One Edition" Logo="StoreLogo.png" SmallLogo="SmallLogo.png" Description="Minecraft" ForegroundText="light" BackgroundColor="#464646">
<SplashScreen Image="SplashScreen.png" />
</VisualElements>
<Extensions>
<mx:Extension Category="xbox.live">
<mx:XboxLive TitleId="149E11AE" PrimaryServiceConfigId="05c20100-6e60-45d5-878a-4903149e11ae">
<mx:ConnectedStorage MaxMegabytesPerUser="1024" />
</mx:XboxLive>
</mx:Extension>
<mx:Extension Category="windows.xbox.networking">
<mx:XboxNetworkingManifest>
<mx:SocketDescriptions>
<mx:SocketDescription Name="MultiplayerSocketUdp" SecureIpProtocol="Udp" BoundPort="8700">
<mx:AllowedUsages>
<mx:SecureDeviceSocketUsage Type="Initiate" />
<mx:SecureDeviceSocketUsage Type="Accept" />
<mx:SecureDeviceSocketUsage Type="SendGameData" />
<mx:SecureDeviceSocketUsage Type="ReceiveGameData" />
<mx:SecureDeviceSocketUsage Type="SendChat" />
<mx:SecureDeviceSocketUsage Type="ReceiveChat" />
</mx:AllowedUsages>
</mx:SocketDescription>
</mx:SocketDescriptions>
<mx:SecureDeviceAssociationTemplates>
<mx:SecureDeviceAssociationTemplate Name="MultiplayerUdp" InitiatorSocketDescription="MultiplayerSocketUdp" AcceptorSocketDescription="MultiplayerSocketUdp" MultiplayerSessionRequirement="Required">
<mx:AllowedUsages>
<mx:SecureDeviceAssociationUsage Type="Default" />
</mx:AllowedUsages>
</mx:SecureDeviceAssociationTemplate>
</mx:SecureDeviceAssociationTemplates>
</mx:XboxNetworkingManifest>
</mx:Extension>
</Extensions>
</Application>
</Applications>
<Extensions>
<mx:PackageExtension Category="xbox.store">
<mx:XboxStore>
<mx:RelatedProducts>
<mx:RelatedProduct Id="582e7bcc-11bc-4702-ab1b-b31566f8e327" />
</mx:RelatedProducts>
</mx:XboxStore>
</mx:PackageExtension>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>windows.xbox.networking.realtimesession.dll</Path>
<ActivatableClass ActivatableClassId="Windows.Xbox.Networking.RealtimeSession.Session" ThreadingModel="both" />
</InProcessServer>
</Extension>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>Microsoft.Xbox.GameChat.dll</Path>
<ActivatableClass ActivatableClassId="Microsoft.Xbox.GameChat.ChatManager" ThreadingModel="both" />
</InProcessServer>
</Extension>
<Extension Category="windows.activatableClass.inProcessServer">
<InProcessServer>
<Path>Microsoft.Xbox.Services.dll</Path>
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.XboxLiveContext" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Configuration" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Multiplayer.MultiplayerQualityOfServiceMeasurements" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Multiplayer.MultiplayerSessionReference" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Multiplayer.MultiplayerSessionCapabilities" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Multiplayer.MultiplayerSession" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Matchmaking.CreateMatchTicketResponse" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Matchmaking.HopperStatisticsResponse" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Matchmaking.MatchTicketDetailsResponse" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Presence.PresenceData" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.TitleStorage.TitleStorageBlobMetadata" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.UserStatistics.RequestedStatistics" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Privacy.PermissionIdConstants" ThreadingModel="both" />
<ActivatableClass ActivatableClassId="Microsoft.Xbox.Services.Social.SocialGroupConstants" ThreadingModel="both" />
</InProcessServer>
</Extension>
</Extensions>
<Capabilities>
<Capability Name="internetClient" />
<mx:Capability Name="kinectAudio" />
<mx:Capability Name="kinectGamechat" />
</Capabilities>
</Package>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

View file

@ -443,7 +443,8 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
double maxHealth = minecraft->localplayers[iPad]->getAttribute(SharedMonsterAttributes.MAX_HEALTH);
double totalAbsorption = minecraft->localplayers[iPad]->getAbsorptionAmount();
int numHealthRows = Mth.ceil((maxHealth + totalAbsorption) / 2 / (float) NUM_HEARTS_PER_ROW);
const double healthHalves = (maxHealth + totalAbsorption) / 2.0;
int numHealthRows = Mth.ceil(healthHalves / (float) NUM_HEARTS_PER_ROW);
int healthRowHeight = Math.max(10 - (numHealthRows - 2), 3);
int yLine2 = yLine1 - (numHealthRows - 1) * healthRowHeight - 10;
absorption = totalAbsorption;
@ -469,7 +470,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
}
//minecraft.profiler.popPush("health");
for (int i = Mth.ceil((maxHealth + totalAbsorption) / 2) - 1; i >= 0; i--)
for (int i = (int)Mth.ceil(healthHalves) - 1; i >= 0; i--)
{
int healthTexBaseX = 16;
if (minecraft.player.hasEffect(MobEffect.poison))
@ -607,8 +608,11 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
// render air bubbles
if (minecraft->player->isUnderLiquid(Material::water))
{
int count = (int) ceil((minecraft->player->getAirSupply() - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY);
int extra = (int) ceil((minecraft->player->getAirSupply()) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count;
const int airSupply = minecraft->player->getAirSupply();
const float airScale = 10.0f / Player::TOTAL_AIR_SUPPLY;
const float airSupplyScaled = airSupply * airScale;
int count = (int) ceil((airSupply - 2) * airScale);
int extra = (int) ceil(airSupplyScaled) - count;
for (int i = 0; i < count + extra; i++)
{
// Air bubbles
@ -725,7 +729,8 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
Lighting::turnOn();
glRotatef(-45 - 90, 0, 1, 0);
glRotatef(-(float) atan(yd / 40.0f ) * 20, 1, 0, 0);
const float xRotAngle = -(float) atan(yd / 40.0f) * 20;
glRotatef(xRotAngle, 1, 0, 0);
float bodyRot = (minecraft->player->yBodyRotO + (minecraft->player->yBodyRot - minecraft->player->yBodyRotO));
// Fixed rotation angle of degrees, adjusted by bodyRot to negate the rotation that occurs in the renderer
// bodyRot in the rotation below is a simplification of "180 - (180 - bodyRot)" where the first 180 is EntityRenderDispatcher::instance->playerRotY that we set below
@ -736,7 +741,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
// Set head rotation to body rotation to make head static
minecraft->player->yRot = bodyRot;
minecraft->player->yRotO = minecraft->player->yRot;
minecraft->player->xRot = -(float) atan(yd / 40.0f) * 20;
minecraft->player->xRot = xRotAngle;
minecraft->player->onFire = 0;
minecraft->player->setSharedFlag(Entity::FLAG_ONFIRE, false);
@ -849,207 +854,6 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
// font.draw(str, x + 1, y, 0xffffff);
// }
#ifndef _FINAL_BUILD
MemSect(31);
// temporarily render overlay at all times so version is more obvious in bug reports
// we can turn this off once things stabilize
if (true)// minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
{
const int debugLeft = 1;
const int debugTop = 1;
const float maxContentWidth = 1200.f;
const float maxContentHeight = 420.f;
float scale = static_cast<float>(screenWidth - debugLeft - 8) / maxContentWidth;
float scaleV = static_cast<float>(screenHeight - debugTop - 80) / maxContentHeight;
if (scaleV < scale) scale = scaleV;
if (scale > 1.f) scale = 1.f;
if (scale < 0.5f) scale = 0.5f;
glPushMatrix();
glTranslatef(static_cast<float>(debugLeft), static_cast<float>(debugTop), 0.f);
glScalef(scale, scale, 1.f);
glTranslatef(static_cast<float>(-debugLeft), static_cast<float>(-debugTop), 0.f);
vector<wstring> lines;
lines.push_back(ClientConstants::VERSION_STRING);
lines.push_back(ClientConstants::BRANCH_STRING);
if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
{
lines.push_back(minecraft->fpsString);
lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size())); // Could maybe use entity::shouldRender to work out how many are rendered but thats like expensive
// TODO Add server information with packet counts - once multiplayer is more stable
int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance);
// Calculate the chunk sections using 16 * (2n + 1)^2
lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance));
lines.push_back(minecraft->gatherStats4()); // Chunk Cache
// Dimension
wstring dimension = L"unknown";
switch (minecraft->player->dimension)
{
case -1:
dimension = L"minecraft:the_nether";
break;
case 0:
dimension = L"minecraft:overworld";
break;
case 1:
dimension = L"minecraft:the_end";
break;
}
lines.push_back(dimension);
lines.push_back(L""); // Spacer
// Players block pos
int xBlockPos = Mth::floor(minecraft->player->x);
int yBlockPos = Mth::floor(minecraft->player->y);
int zBlockPos = Mth::floor(minecraft->player->z);
// Chunk player is in
int xChunkPos = xBlockPos >> 4;
int yChunkPos = yBlockPos >> 4;
int zChunkPos = zBlockPos >> 4;
// Players offset within the chunk
int xChunkOffset = xBlockPos & 15;
int yChunkOffset = yBlockPos & 15;
int zChunkOffset = zBlockPos & 15;
// Format the position like java with limited decumal places
WCHAR posString[44]; // Allows upto 7 digit positions (+-9_999_999)
swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z);
lines.push_back(L"XYZ: " + std::wstring(posString));
lines.push_back(L"Block: " + std::to_wstring(static_cast<int>(xBlockPos)) + L" " + std::to_wstring(static_cast<int>(yBlockPos)) + L" " + std::to_wstring(static_cast<int>(zBlockPos)));
lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos));
// Wrap the yRot to 360 then adjust to (-180 to 180) range to match java
float yRotDisplay = fmod(minecraft->player->yRot, 360.0f);
if (yRotDisplay > 180.0f)
{
yRotDisplay -= 360.0f;
}
if (yRotDisplay < -180.0f)
{
yRotDisplay += 360.0f;
}
// Generate the angle string in the format "yRot / xRot" with one decimal place, similar to java edition
WCHAR angleString[16];
swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot);
// Work out the named direction
int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3;
wstring cardinalDirection;
switch (direction)
{
case 0:
cardinalDirection = L"south";
break;
case 1:
cardinalDirection = L"west";
break;
case 2:
cardinalDirection = L"north";
break;
case 3:
cardinalDirection = L"east";
break;
}
lines.push_back(L"Facing: " + cardinalDirection + L" (" + angleString + L")");
// We have to limit y to 256 as we don't get any information past that
if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos))
{
LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos);
if (chunkAt != NULL)
{
int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset);
int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset);
int maxLight = fmax(skyLight, blockLight);
lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)");
lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset)));
Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource());
lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")");
lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")");
}
}
// This is all LCE only stuff, it was never on java
lines.push_back(L""); // Spacer
lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed()));
lines.push_back(minecraft->gatherStats1()); // Time to autosave
lines.push_back(minecraft->gatherStats2()); // Empty currently - CPlatformNetworkManagerStub::GatherStats()
lines.push_back(minecraft->gatherStats3()); // RTT
}
#ifdef _DEBUG // Only show terrain features in debug builds not release
// TERRAIN FEATURES
if (minecraft->level->dimension->id == 0)
{
wstring wfeature[eTerrainFeature_Count];
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: ";
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: ";
wfeature[eTerrainFeature_Village] = L"Village: ";
wfeature[eTerrainFeature_Ravine] = L"Ravine: ";
float maxW = static_cast<float>(screenWidth - debugLeft - 8) / scale;
float maxWForContent = maxW - static_cast<float>(font->width(L"..."));
bool truncated[eTerrainFeature_Count] = {};
for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++)
{
FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i];
int type = pFeatureData->eTerrainFeature;
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine)
{
continue;
}
if (truncated[type])
{
continue;
}
wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] ";
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
{
wfeature[type] += itemInfo;
}
else
{
wfeature[type] += L"...";
truncated[type] = true;
}
}
lines.push_back(L""); // Add a spacer line
for (int i = eTerrainFeature_Stronghold; i <= static_cast<int>(eTerrainFeature_Ravine); i++)
{
lines.push_back(wfeature[i]);
}
lines.push_back(L"");
}
#endif
// Loop through the lines and draw them all on screen
int yPos = debugTop;
for (const auto &line : lines)
{
drawString(font, line, debugLeft, yPos, 0xffffff);
yPos += 10;
}
glPopMatrix();
}
MemSect(0);
#endif
lastTickA = a;
// 4J Stu - This is now displayed in a xui scene
#if 0
@ -1203,6 +1007,190 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
glPopMatrix();
}
#ifndef _FINAL_BUILD
MemSect(31);
if (true)
{
// Real window dimensions updated on every WM_SIZE — always current
extern int g_rScreenWidth;
extern int g_rScreenHeight;
// Set up a fresh projection using physical pixel coordinates so the debug
// text is never distorted regardless of aspect ratio, splitscreen layout,
// or menu state. 1 coordinate unit = 1 physical pixel.
// Compute the actual viewport dimensions for this player's screen section.
// glOrtho must match the viewport exactly for 1 unit = 1 physical pixel.
int vpW = g_rScreenWidth;
int vpH = g_rScreenHeight;
switch (minecraft->player->m_iScreenSection)
{
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
vpH /= 2;
break;
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
vpW /= 2;
break;
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
vpW /= 2;
vpH /= 2;
break;
default: // VIEWPORT_TYPE_FULLSCREEN
break;
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, vpW, vpH, 0, 1000, 3000);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(0, 0, -2000);
// Font was designed for guiScale px/unit; scale up so characters appear
// at the same physical size as the rest of the HUD at 0.5x.
const float fontScale = static_cast<float>(guiScale) * 1.0f;
const int debugLeft = 1;
const int debugTop = 1;
glTranslatef(static_cast<float>(debugLeft), static_cast<float>(debugTop), 0.f);
glScalef(fontScale, fontScale, 1.f);
glTranslatef(static_cast<float>(-debugLeft), static_cast<float>(-debugTop), 0.f);
vector<wstring> lines;
// Only show version/branch for player 0 to avoid cluttering each splitscreen viewport
if (iPad == 0)
{
lines.push_back(ClientConstants::VERSION_STRING);
lines.push_back(ClientConstants::BRANCH_STRING);
}
if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
{
lines.push_back(minecraft->fpsString);
lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size()));
int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance);
lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance));
lines.push_back(minecraft->gatherStats4());
wstring dimension = L"unknown";
switch (minecraft->player->dimension)
{
case -1: dimension = L"minecraft:the_nether"; break;
case 0: dimension = L"minecraft:overworld"; break;
case 1: dimension = L"minecraft:the_end"; break;
}
lines.push_back(dimension);
lines.push_back(L"");
int xBlockPos = Mth::floor(minecraft->player->x);
int yBlockPos = Mth::floor(minecraft->player->y);
int zBlockPos = Mth::floor(minecraft->player->z);
int xChunkPos = xBlockPos >> 4;
int yChunkPos = yBlockPos >> 4;
int zChunkPos = zBlockPos >> 4;
int xChunkOffset = xBlockPos & 15;
int yChunkOffset = yBlockPos & 15;
int zChunkOffset = zBlockPos & 15;
WCHAR posString[44];
swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z);
lines.push_back(L"XYZ: " + std::wstring(posString));
lines.push_back(L"Block: " + std::to_wstring(xBlockPos) + L" " + std::to_wstring(yBlockPos) + L" " + std::to_wstring(zBlockPos));
lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos));
float yRotDisplay = fmod(minecraft->player->yRot, 360.0f);
if (yRotDisplay > 180.0f) yRotDisplay -= 360.0f;
if (yRotDisplay < -180.0f) yRotDisplay += 360.0f;
WCHAR angleString[16];
swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot);
int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3;
const wchar_t* cardinals[] = { L"south", L"west", L"north", L"east" };
lines.push_back(L"Facing: " + std::wstring(cardinals[direction]) + L" (" + angleString + L")");
if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos))
{
LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos);
if (chunkAt != NULL)
{
int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset);
int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset);
int maxLight = fmax(skyLight, blockLight);
lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)");
lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset)));
Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource());
lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")");
lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")");
}
}
lines.push_back(L"");
lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed()));
lines.push_back(minecraft->gatherStats1());
lines.push_back(minecraft->gatherStats2());
lines.push_back(minecraft->gatherStats3());
}
#ifdef _DEBUG
if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr && minecraft->level->dimension->id == 0)
{
wstring wfeature[eTerrainFeature_Count];
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: ";
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: ";
wfeature[eTerrainFeature_Village] = L"Village: ";
wfeature[eTerrainFeature_Ravine] = L"Ravine: ";
// maxW in font units: physical width divided by font scale
float maxW = (static_cast<float>(g_rScreenWidth) - debugLeft - 8) / fontScale;
float maxWForContent = maxW - static_cast<float>(font->width(L"..."));
bool truncated[eTerrainFeature_Count] = {};
for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++)
{
FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i];
int type = pFeatureData->eTerrainFeature;
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine) continue;
if (truncated[type]) continue;
wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] ";
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
wfeature[type] += itemInfo;
else
{
wfeature[type] += L"...";
truncated[type] = true;
}
}
lines.push_back(L"");
for (int i = eTerrainFeature_Stronghold; i <= static_cast<int>(eTerrainFeature_Ravine); i++)
lines.push_back(wfeature[i]);
lines.push_back(L"");
}
#endif
int yPos = debugTop;
for (const auto &line : lines)
{
drawString(font, line, debugLeft, yPos, 0xffffff);
yPos += 10;
}
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
MemSect(0);
#endif
glColor4f(1, 1, 1, 1);
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST);

View file

@ -228,7 +228,7 @@ void ItemInHandRenderer::renderItem(shared_ptr<LivingEntity> mob, shared_ptr<Ite
// by texture lighting. This is for colourising things held in 3rd person view.
if ( (setColor) && (item != nullptr) )
{
int col = Item::items[item->id]->getColor(item,0);
int col = Item::items[item->id]->getColor(item, layer);
float red = ((col >> 16) & 0xff) / 255.0f;
float g = ((col >> 8) & 0xff) / 255.0f;
float b = ((col) & 0xff) / 255.0f;

View file

@ -1629,7 +1629,7 @@ void Minecraft::run_middle()
s_prevXButtons[i] = xCurButtons;
}
bool startJustPressed = s_startPressLatch[i] > 0;
bool tryJoin = !pause && !ui.IsIgnorePlayerJoinMenuDisplayed(ProfileManager.GetPrimaryPad()) && g_NetworkManager.SessionHasSpace() && xCurButtons != 0;
bool tryJoin = !pause && !ui.IsIgnorePlayerJoinMenuDisplayed(ProfileManager.GetPrimaryPad()) && g_NetworkManager.SessionHasSpace() && xCurButtons != 0 && g_KBMInput.IsWindowFocused();
#else
bool tryJoin = !pause && !ui.IsIgnorePlayerJoinMenuDisplayed(ProfileManager.GetPrimaryPad()) && g_NetworkManager.SessionHasSpace() && RenderManager.IsHiDef() && InputManager.ButtonPressed(i);
#endif
@ -3706,7 +3706,9 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
app.EnableDebugOverlay(options->renderDebug,iPad);
#else
// 4J Stu - The xbox uses a completely different way of navigating to this scene
ui.NavigateToScene(0, eUIScene_DebugOverlay, nullptr, eUILayer_Debug);
// Always open in the fullscreen group so the overlay spans the full window
// regardless of split-screen viewport configuration.
ui.NavigateToScene(0, eUIScene_DebugOverlay, nullptr, eUILayer_Debug, eUIGroup_Fullscreen);
#endif
#endif
}

View file

@ -938,7 +938,11 @@ bool MinecraftServer::loadLevel(LevelStorageSource *storageSource, const wstring
storage = shared_ptr<McRegionLevelStorage>(new McRegionLevelStorage(newFormatSave, File(L"."), name, true));
#else
storage = std::make_shared<McRegionLevelStorage>(new ConsoleSaveFileOriginal(L""), File(L"."), name, true);
ConsoleSaveFileOriginal* pSave = new ConsoleSaveFileOriginal(L"");
pSave->ConvertToLocalPlatform();
storage = std::make_shared<McRegionLevelStorage>(pSave, File(L"."), name, true);
#endif
}

View file

@ -12,6 +12,7 @@ using namespace std;
class MultiPlayerLevel : public Level
{
friend class ClientConnection;
private:
static const int TICKS_BEFORE_RESET = 20 * 4;

View file

@ -392,6 +392,11 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port)
}
s_localSmallId = assignedSmallId;
// Save the host IP and port so JoinSplitScreen can connect to the same host
// regardless of how the connection was initiated (UI vs command line).
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), ip, _TRUNCATE);
g_Win64MultiplayerPort = port;
app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
s_active = true;
@ -733,6 +738,11 @@ bool WinsockNetLayer::PopDisconnectedSmallId(BYTE* outSmallId)
void WinsockNetLayer::PushFreeSmallId(BYTE smallId)
{
// SmallIds 0..(XUSER_MAX_COUNT-1) are permanently reserved for the host's
// local pads and must never be recycled to remote clients.
if (smallId < (BYTE)XUSER_MAX_COUNT)
return;
EnterCriticalSection(&s_freeSmallIdLock);
// Guard against double-recycle: the reconnect path (queueSmallIdForRecycle) and
// the DoWork disconnect path can both push the same smallId. If we allow duplicates,

View file

@ -1222,6 +1222,30 @@ void LevelChunk::addEntity(shared_ptr<Entity> e)
#endif
}
void LevelChunk::addRidingEntities(shared_ptr<Entity> rider, CompoundTag *riderTag)
{
#ifdef _LARGE_WORLDS #This shouldnt be called when we dont have large worlds enabled
CompoundTag *mountTag = riderTag;
shared_ptr<Entity> ridingEntity = rider;
while (mountTag != NULL && mountTag->contains(Entity::RIDING_TAG))
{
CompoundTag *nextMountTag = mountTag->getCompound(Entity::RIDING_TAG);
shared_ptr<Entity> mount = EntityIO::loadStatic(nextMountTag, level);
if (mount == NULL)
{
break;
}
mount->onLoadedFromSave();
addEntity(mount);
ridingEntity->ride(mount);
ridingEntity = mount;
mountTag = nextMountTag;
}
#endif
};
void LevelChunk::removeEntity(shared_ptr<Entity> e)
{
@ -1431,6 +1455,7 @@ void LevelChunk::load()
{
ent->onLoadedFromSave();
addEntity(ent);
addRidingEntities(ent, teTag);
}
}
}
@ -1628,18 +1653,18 @@ void LevelChunk::getEntities(shared_ptr<Entity> except, AABB *bb, vector<shared_
for (auto& e : *entities)
{
if ( e && e != except && e->bb->intersects(bb) && (selector == nullptr || selector->matches(e)))
if (e && e != except && e->bb->intersects(bb) && (selector == nullptr || selector->matches(e)))
{
es.push_back(e);
vector<shared_ptr<Entity> > *subs = e->getSubEntities();
if (subs != nullptr)
{
for (const auto& sub : *subs)
for (const auto& subEntity : *subs)
{
e = sub;
if ( e && e != except && e->bb->intersects(bb) && (selector == nullptr || selector->matches(e)))
if (subEntity && subEntity != except && subEntity->bb->intersects(bb) && (selector == nullptr || selector->matches(subEntity)))
{
es.push_back(e);
es.push_back(subEntity);
}
}
}

View file

@ -192,6 +192,7 @@ public:
virtual void setBrightness(LightLayer::variety layer, int x, int y, int z, int brightness);
virtual int getRawBrightness(int x, int y, int z, int skyDampen);
virtual void addEntity(shared_ptr<Entity> e);
virtual void addRidingEntities(shared_ptr<Entity> rider, CompoundTag *riderTag);
virtual void removeEntity(shared_ptr<Entity> e);
virtual void removeEntity(shared_ptr<Entity> e, int yc);
virtual bool isSkyLit(int x, int y, int z);

View file

@ -1354,6 +1354,10 @@ bool LivingEntity::shouldShowName()
Icon *LivingEntity::getItemInHandIcon(shared_ptr<ItemInstance> item, int layer)
{
if (item->getItem()->hasMultipleSpriteLayers())
{
return item->getItem()->getLayerIcon(item->getAuxValue(), layer);
}
return item->getIcon();
}
@ -1999,4 +2003,4 @@ bool LivingEntity::isAlliedTo(Team *other)
return getTeam()->isAlliedTo(other);
}
return false;
}
}

View file

@ -403,6 +403,7 @@ void OldChunkStorage::loadEntities(LevelChunk *lc, Level *level, CompoundTag *ta
if (te != nullptr)
{
lc->addEntity(te);
lc->addRidingEntities(te, teTag);
}
}
}

View file

@ -12,6 +12,11 @@ bool RegionFileCache::useSplitSaves(ESavePlatform platform)
case SAVE_FILE_PLATFORM_XBONE:
case SAVE_FILE_PLATFORM_PS4:
return true;
case SAVE_FILE_PLATFORM_WIN64:
{
LevelGenerationOptions* lgo = app.getLevelGenerationOptions();
return (lgo != nullptr && lgo->isFromDLC());
}
default:
return false;
};

View file

@ -194,7 +194,11 @@ void ZonedChunkStorage::loadEntities(Level *level, LevelChunk *lc)
if (type == 0)
{
shared_ptr<Entity> e = EntityIO::loadStatic(tag, level);
if (e != nullptr) lc->addEntity(e);
if (e != nullptr)
{
lc->addEntity(e);
lc->addRidingEntities(e, tag);
}
}
else if (type == 1)
{