diff options
Diffstat (limited to 'Minecraft.Client/ClientConnection.cpp')
| -rw-r--r-- | Minecraft.Client/ClientConnection.cpp | 94 |
1 files changed, 73 insertions, 21 deletions
diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index c9e7bac2..0aa9735d 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -142,6 +142,13 @@ ClientConnection::ClientConnection(Minecraft *minecraft, Socket *socket, int iUs deferredEntityLinkPackets = vector<DeferredEntityLinkPacket>(); } +bool ClientConnection::isPrimaryConnection() const +{ + // On host, all connections are primary (server is authoritative). + // On non-host, only the primary pad processes shared entity state. + return g_NetworkManager.IsHost() || m_userIndex == ProfileManager.GetPrimaryPad(); +} + ClientConnection::~ClientConnection() { delete connection; @@ -304,6 +311,10 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet) level->isClientSide = true; minecraft->setLevel(level); } + else + { + level = (MultiPlayerLevel *)dimensionLevel; + } minecraft->player->setPlayerIndex( packet->m_playerIndex ); minecraft->player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) ); @@ -705,6 +716,7 @@ void ClientConnection::handleAddExperienceOrb(shared_ptr<AddExperienceOrbPacket> void ClientConnection::handleAddGlobalEntity(shared_ptr<AddGlobalEntityPacket> packet) { + if (!isPrimaryConnection()) return; double x = packet->x / 32.0; double y = packet->y / 32.0; double z = packet->z / 32.0; @@ -730,6 +742,13 @@ void ClientConnection::handleAddPainting(shared_ptr<AddPaintingPacket> packet) void ClientConnection::handleSetEntityMotion(shared_ptr<SetEntityMotionPacket> packet) { + if (!isPrimaryConnection()) + { + // 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; + } shared_ptr<Entity> e = getEntity(packet->id); if (e == NULL) return; e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0); @@ -953,6 +972,7 @@ void ClientConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> pac void ClientConnection::handleMoveEntity(shared_ptr<MoveEntityPacket> packet) { + if (!isPrimaryConnection()) return; shared_ptr<Entity> e = getEntity(packet->id); if (e == NULL) return; e->xp += packet->xa; @@ -982,6 +1002,7 @@ void ClientConnection::handleRotateMob(shared_ptr<RotateHeadPacket> packet) void ClientConnection::handleMoveEntitySmall(shared_ptr<MoveEntityPacketSmall> packet) { + if (!isPrimaryConnection()) return; shared_ptr<Entity> e = getEntity(packet->id); if (e == NULL) return; e->xp += packet->xa; @@ -1106,6 +1127,7 @@ void ClientConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet) // 4J Added void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaPacket> packet) { + 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) level->setChunkVisible(x, z, true); @@ -1113,11 +1135,13 @@ void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaP void ClientConnection::handleChunkVisibility(shared_ptr<ChunkVisibilityPacket> packet) { + if (level == NULL) return; level->setChunkVisible(packet->x, packet->z, packet->visible); } 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 ) @@ -1187,16 +1211,29 @@ 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 ) { PIXBeginNamedEvent(0,"Handle block region update"); + if(packet->bIsFullChunk && packet->ys == 0) + { + app.DebugPrintf("[BRUP-CLIENT] *** EMPTY FULL CHUNK received at (%d,%d)! Buffer length=%d\n", + packet->x>>4, packet->z>>4, packet->buffer.length); + } + int y1 = packet->y + packet->ys; if(packet->bIsFullChunk) { y1 = Level::maxBuildHeight; + + // Ensure the chunk exists in the cache before writing data. + // The ChunkVisibilityAreaPacket that creates chunks can arrive AFTER the first BRUP, + // causing getChunk() to return EmptyLevelChunk (whose setBlocksAndData is a no-op). + dimensionLevel->setChunkVisible(packet->x >> 4, packet->z >> 4, true); + if(packet->buffer.length > 0) { PIXBeginNamedEvent(0, "Reordering to XZY"); @@ -1235,6 +1272,7 @@ 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 @@ -1349,6 +1387,7 @@ void ClientConnection::send(shared_ptr<Packet> packet) void ClientConnection::handleTakeItemEntity(shared_ptr<TakeItemEntityPacket> packet) { + if (!isPrimaryConnection()) return; shared_ptr<Entity> from = getEntity(packet->itemId); shared_ptr<LivingEntity> to = dynamic_pointer_cast<LivingEntity>(getEntity(packet->playerId)); @@ -2847,31 +2886,34 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet) void ClientConnection::handleExplosion(shared_ptr<ExplodePacket> packet) { - if(!packet->m_bKnockbackOnly) - { - //app.DebugPrintf("Received ExplodePacket with explosion data\n"); - PIXBeginNamedEvent(0,"Handling explosion"); - Explosion *e = new Explosion(minecraft->level, nullptr, packet->x, packet->y, packet->z, packet->r); - PIXBeginNamedEvent(0,"Finalizing"); - - // Fix for #81758 - TCR 006 BAS Non-Interactive Pause: TU9: Performance: Gameplay: After detonating bunch of TNT, game enters unresponsive state for couple of seconds. - // The changes we are making here have been decided by the server, so we don't need to add them to the vector that resets tiles changes made - // on the client as we KNOW that the server is matching these changes - MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)minecraft->level; - mpLevel->enableResetChanges(false); - // 4J - now directly pass a pointer to the toBlow array in the packet rather than copying around - e->finalizeExplosion(true, &packet->toBlow); - mpLevel->enableResetChanges(true); - PIXEndNamedEvent(); - PIXEndNamedEvent(); - delete e; - } - else + // World modification (block destruction) must only happen once + if (isPrimaryConnection()) { - //app.DebugPrintf("Received ExplodePacket with knockback only data\n"); + if(!packet->m_bKnockbackOnly) + { + //app.DebugPrintf("Received ExplodePacket with explosion data\n"); + PIXBeginNamedEvent(0,"Handling explosion"); + Explosion *e = new Explosion(minecraft->level, nullptr, packet->x, packet->y, packet->z, packet->r); + PIXBeginNamedEvent(0,"Finalizing"); + + // Fix for #81758 - TCR 006 BAS Non-Interactive Pause: TU9: Performance: Gameplay: After detonating bunch of TNT, game enters unresponsive state for couple of seconds. + // The changes we are making here have been decided by the server, so we don't need to add them to the vector that resets tiles changes made + // on the client as we KNOW that the server is matching these changes + MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)minecraft->level; + mpLevel->enableResetChanges(false); + // 4J - now directly pass a pointer to the toBlow array in the packet rather than copying around + e->finalizeExplosion(true, &packet->toBlow); + mpLevel->enableResetChanges(true); + PIXEndNamedEvent(); + PIXEndNamedEvent(); + delete e; + } } + // Per-player knockback — each connection applies to its own local player //app.DebugPrintf("Adding knockback (%f,%f,%f) for player %d\n", packet->getKnockbackX(), packet->getKnockbackY(), packet->getKnockbackZ(), m_userIndex); + if (minecraft->localplayers[m_userIndex] == NULL) + return; minecraft->localplayers[m_userIndex]->xd += packet->getKnockbackX(); minecraft->localplayers[m_userIndex]->yd += packet->getKnockbackY(); minecraft->localplayers[m_userIndex]->zd += packet->getKnockbackZ(); @@ -2881,6 +2923,8 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe { bool failed = false; shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex]; + if (player == NULL) + return; switch(packet->type) { case ContainerOpenPacket::BONUS_CHEST: @@ -3187,6 +3231,7 @@ 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)) { @@ -3220,6 +3265,7 @@ 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); @@ -3272,6 +3318,7 @@ 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(); @@ -3279,6 +3326,7 @@ 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()); } @@ -3360,6 +3408,7 @@ 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); @@ -3374,6 +3423,7 @@ void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> p void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet) { + if (!isPrimaryConnection()) return; if (packet->type == LevelEvent::SOUND_DRAGON_DEATH) { for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) @@ -3597,6 +3647,7 @@ 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); } @@ -3909,6 +3960,7 @@ 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(); |
