diff --git a/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp b/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp index 5b10e8cf..ead86c3d 100644 --- a/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp +++ b/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp @@ -50,13 +50,18 @@ UIScene_EndPoem::UIScene_EndPoem(int iPad, void *initData, UILayer *parentLayer) Minecraft *pMinecraft = Minecraft::GetInstance(); wstring playerName = L""; - if(pMinecraft->localplayers[ui.GetWinUserIndex()] != nullptr) + unsigned int winIdx = ui.GetWinUserIndex(); + if(winIdx < XUSER_MAX_COUNT && pMinecraft->localplayers[winIdx] != nullptr) { - playerName = escapeXML( pMinecraft->localplayers[ui.GetWinUserIndex()]->getDisplayName() ); + playerName = escapeXML( pMinecraft->localplayers[winIdx]->getDisplayName() ); + } + else if(pMinecraft->localplayers[ProfileManager.GetPrimaryPad()] != nullptr) + { + playerName = escapeXML( pMinecraft->localplayers[ProfileManager.GetPrimaryPad()]->getDisplayName() ); } else { - playerName = escapeXML( pMinecraft->localplayers[ProfileManager.GetPrimaryPad()]->getDisplayName() ); + playerName = L"Player"; } noNoiseString = replaceAll(noNoiseString,L"{*PLAYER*}",playerName); diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp index 43cd8f34..01116a2c 100644 --- a/Minecraft.Client/PlayerConnection.cpp +++ b/Minecraft.Client/PlayerConnection.cpp @@ -825,9 +825,7 @@ void PlayerConnection::handleInteract(shared_ptr packet) { if ((target->GetType() == eTYPE_ITEMENTITY) || (target->GetType() == eTYPE_EXPERIENCEORB) || (target->GetType() == eTYPE_ARROW) || target == player) { - //disconnect("Attempting to attack an invalid entity"); - //server.warn("Player " + player.getName() + " tried to attack an invalid entity"); - return; + return; } player->attack(target); } diff --git a/Minecraft.Client/PlayerList.cpp b/Minecraft.Client/PlayerList.cpp index 6c131357..da232688 100644 --- a/Minecraft.Client/PlayerList.cpp +++ b/Minecraft.Client/PlayerList.cpp @@ -965,15 +965,16 @@ void PlayerList::repositionAcrossDimension(shared_ptr entity, int lastDi addPlayerToReceiving(player); } - if (lastDimension != 1) + xt = static_cast(Mth::clamp(static_cast(xt), -Level::MAX_LEVEL_SIZE + 128, Level::MAX_LEVEL_SIZE - 128)); + zt = static_cast(Mth::clamp(static_cast(zt), -Level::MAX_LEVEL_SIZE + 128, Level::MAX_LEVEL_SIZE - 128)); + if (entity->isAlive()) { - xt = static_cast(Mth::clamp(static_cast(xt), -Level::MAX_LEVEL_SIZE + 128, Level::MAX_LEVEL_SIZE - 128)); - zt = static_cast(Mth::clamp(static_cast(zt), -Level::MAX_LEVEL_SIZE + 128, Level::MAX_LEVEL_SIZE - 128)); - if (entity->isAlive()) + newLevel->addEntity(entity); + entity->moveTo(xt, entity->y, zt, entity->yRot, entity->xRot); + newLevel->tick(entity, false); + // Portal forcing only for non-End exits (End exits go to spawn, not a portal) + if (lastDimension != 1) { - newLevel->addEntity(entity); - entity->moveTo(xt, entity->y, zt, entity->yRot, entity->xRot); - newLevel->tick(entity, false); newLevel->cache->autoCreate = true; newLevel->getPortalForcer()->force(entity, xOriginal, yOriginal, zOriginal, yRotOriginal); newLevel->cache->autoCreate = false; diff --git a/Minecraft.Client/ServerLevel.cpp b/Minecraft.Client/ServerLevel.cpp index 9d5ec908..80a12c99 100644 --- a/Minecraft.Client/ServerLevel.cpp +++ b/Minecraft.Client/ServerLevel.cpp @@ -1052,9 +1052,14 @@ void ServerLevel::entityAdded(shared_ptr e) vector > *es = e->getSubEntities(); if (es) { + // Reassign sub-entity IDs to be sequential from the parent's ID. + // The client assumes this layout when it applies an offset in handleAddMob. + int offset = 1; for(auto& i : *es) { + i->entityId = e->entityId + offset; entitiesById.emplace(i->entityId, i); + offset++; } } entityAddedExtra(e); // 4J added diff --git a/Minecraft.World/EnderDragon.cpp b/Minecraft.World/EnderDragon.cpp index f8e4871f..bc4cd969 100644 --- a/Minecraft.World/EnderDragon.cpp +++ b/Minecraft.World/EnderDragon.cpp @@ -1118,15 +1118,6 @@ bool EnderDragon::hurt(shared_ptr MultiEntityMobPart, Damage damage = damage / 4 + 1; } - //float rot1 = yRot * PI / 180; - //float ss1 = sin(rot1); - //float cc1 = cos(rot1); - - //xTarget = x + ss1 * 5 + (random->nextFloat() - 0.5f) * 2; - //yTarget = y + random->nextFloat() * 3 + 1; - //zTarget = z - cc1 * 5 + (random->nextFloat() - 0.5f) * 2; - //attackTarget = nullptr; - if ( source->getEntity() != nullptr && source->getEntity()->instanceof(eTYPE_PLAYER) || source->isExplosion() ) { int healthBefore = getHealth(); diff --git a/README.md b/README.md index e5ab35f3..cd637141 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ This project is based on source code of Minecraft Legacy Console Edition v1.6.05 ## Latest: +End dimension fixes for dedicated servers: +- Fixed the Ender Dragon being immune to melee damage on dedicated servers. The server's entity ID allocator (smallId pool) assigned non-sequential IDs to the dragon's body parts, but the client assumed sequential offsets. Melee attacks targeted IDs the server didn't recognize, so hits were silently dropped. The server now reassigns sub-entity IDs to be sequential from the parent when an entity with parts is added to the level +- Fixed entering the End exit portal after defeating the dragon crashing the game. The player entity was never added to the Overworld level during the dimension transition, leaving the player as a ghost entity that caused a crash on the next interaction +- Fixed the End Poem crashing the client on dedicated servers due to an out-of-bounds player index lookup in the WIN_GAME event handler + Dedicated server player list fix: - The Tab player list now correctly shows all connected players on dedicated servers. Previously only the local player was visible because remote players were never registered in the client's network player tracking when their `AddPlayerPacket` arrived - The dedicated server's phantom host entry (slot 0, empty name) is now filtered from the list