the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 3901 lines 134 kB view raw
1#include "stdafx.h" 2#include "ClientConnection.h" 3#include "MultiPlayerLevel.h" 4#include "MultiPlayerLocalPlayer.h" 5#include "StatsCounter.h" 6#include "ReceivingLevelScreen.h" 7#include "RemotePlayer.h" 8#include "DisconnectedScreen.h" 9#include "TakeAnimationParticle.h" 10#include "CritParticle.h" 11#include "User.h" 12#include "..\Minecraft.World\net.minecraft.world.level.storage.h" 13#include "..\Minecraft.World\net.minecraft.world.level.chunk.h" 14#include "..\Minecraft.World\net.minecraft.stats.h" 15#include "..\Minecraft.World\net.minecraft.world.entity.h" 16#include "..\Minecraft.World\net.minecraft.world.entity.ai.attributes.h" 17#include "..\Minecraft.World\net.minecraft.world.entity.player.h" 18#include "..\Minecraft.World\net.minecraft.world.entity.animal.h" 19#include "..\Minecraft.World\net.minecraft.world.entity.npc.h" 20#include "..\Minecraft.World\net.minecraft.world.entity.item.h" 21#include "..\Minecraft.World\net.minecraft.world.entity.projectile.h" 22#include "..\Minecraft.World\net.minecraft.world.entity.global.h" 23#include "..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h" 24#include "..\Minecraft.World\net.minecraft.world.entity.monster.h" 25#include "..\Minecraft.World\net.minecraft.world.level.tile.entity.h" 26#include "..\Minecraft.World\net.minecraft.world.item.h" 27#include "..\Minecraft.World\net.minecraft.world.item.trading.h" 28#include "..\Minecraft.World\net.minecraft.world.level.tile.h" 29#include "..\Minecraft.World\net.minecraft.world.inventory.h" 30#include "..\Minecraft.World\net.minecraft.world.h" 31#include "..\Minecraft.World\net.minecraft.world.level.saveddata.h" 32#include "..\Minecraft.World\net.minecraft.world.level.dimension.h" 33#include "..\Minecraft.World\net.minecraft.world.effect.h" 34#include "..\Minecraft.World\net.minecraft.world.food.h" 35#include "..\Minecraft.World\SharedConstants.h" 36#include "..\Minecraft.World\AABB.h" 37#include "..\Minecraft.World\Pos.h" 38#include "..\Minecraft.World\Socket.h" 39#include "Minecraft.h" 40#include "ProgressRenderer.h" 41#include "LevelRenderer.h" 42#include "Options.h" 43#include "MinecraftServer.h" 44#include "ClientConstants.h" 45#include "..\Minecraft.World\SoundTypes.h" 46#include "..\Minecraft.World\BasicTypeContainers.h" 47#include "TexturePackRepository.h" 48#ifdef _XBOX 49#include "Common\XUI\XUI_Scene_Trading.h" 50#else 51#include "Common\UI\UI.h" 52#endif 53#ifdef __PS3__ 54#include "PS3/Network/SonyVoiceChat.h" 55#endif 56#include "DLCTexturePack.h" 57 58#ifdef _DURANGO 59#include "..\Minecraft.World\DurangoStats.h" 60#include "..\Minecraft.World\GenericStats.h" 61#endif 62 63ClientConnection::ClientConnection(Minecraft *minecraft, const wstring& ip, int port) 64{ 65 // 4J Stu - No longer used as we use the socket version below. 66 assert(FALSE); 67#if 0 68 // 4J - added initiliasers 69 random = new Random(); 70 done = false; 71 level = false; 72 started = false; 73 74 this->minecraft = minecraft; 75 76 Socket *socket; 77 if( gNetworkManager.IsHost() ) 78 { 79 socket = new Socket(); // 4J - Local connection 80 } 81 else 82 { 83 socket = new Socket(ip); // 4J - Connection over xrnm - hardcoded IP at present 84 } 85 createdOk = socket->createdOk; 86 if( createdOk ) 87 { 88 connection = new Connection(socket, L"Client", this); 89 } 90 else 91 { 92 connection = NULL; 93 delete socket; 94 } 95#endif 96} 97 98ClientConnection::ClientConnection(Minecraft *minecraft, Socket *socket, int iUserIndex /*= -1*/) 99{ 100 // 4J - added initiliasers 101 random = new Random(); 102 done = false; 103 level = NULL; 104 started = false; 105 savedDataStorage = new SavedDataStorage(NULL); 106 maxPlayers = 20; 107 108 this->minecraft = minecraft; 109 110 if( iUserIndex < 0 ) 111 { 112 m_userIndex = ProfileManager.GetPrimaryPad(); 113 } 114 else 115 { 116 m_userIndex = iUserIndex; 117 } 118 119 if( socket == NULL ) 120 { 121 socket = new Socket(); // 4J - Local connection 122 } 123 124 createdOk = socket->createdOk; 125 if( createdOk ) 126 { 127 connection = new Connection(socket, L"Client", this); 128 } 129 else 130 { 131 connection = NULL; 132 // TODO 4J Stu - This will cause issues since the session player owns the socket 133 //delete socket; 134 } 135 136 deferredEntityLinkPackets = vector<DeferredEntityLinkPacket>(); 137} 138 139ClientConnection::~ClientConnection() 140{ 141 delete connection; 142 delete random; 143 delete savedDataStorage; 144} 145 146void ClientConnection::tick() 147{ 148 if (!done) connection->tick(); 149 connection->flush(); 150} 151 152INetworkPlayer *ClientConnection::getNetworkPlayer() 153{ 154 if( connection != NULL && connection->getSocket() != NULL) return connection->getSocket()->getPlayer(); 155 else return NULL; 156} 157 158void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet) 159{ 160 if (done) return; 161 162 PlayerUID OnlineXuid; 163 ProfileManager.GetXUID(m_userIndex,&OnlineXuid,true); // online xuid 164 MOJANG_DATA *pMojangData = NULL; 165 166 if(!g_NetworkManager.IsLocalGame()) 167 { 168 pMojangData=app.GetMojangDataForXuid(OnlineXuid); 169 } 170 171 if(!g_NetworkManager.IsHost() ) 172 { 173 Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCLoginReceived * 100)/ (eCCConnected)); 174 } 175 176 // 4J-PB - load the local player skin (from the global title user storage area) if there is one 177 // the primary player on the host machine won't have a qnet player from the socket 178 INetworkPlayer *networkPlayer = connection->getSocket()->getPlayer(); 179 int iUserID=-1; 180 181 if( m_userIndex == ProfileManager.GetPrimaryPad() ) 182 { 183 iUserID=m_userIndex; 184 185 TelemetryManager->SetMultiplayerInstanceId(packet->m_multiplayerInstanceId); 186 } 187 else 188 { 189 if(!networkPlayer->IsGuest() && networkPlayer->IsLocal()) 190 { 191 // find the pad number of this local player 192 for(int i=0;i<XUSER_MAX_COUNT;i++) 193 { 194 INetworkPlayer *networkLocalPlayer=g_NetworkManager.GetLocalPlayerByUserIndex(i); 195 if(networkLocalPlayer==networkPlayer) 196 { 197 iUserID=i; 198 } 199 } 200 } 201 } 202 203 if(iUserID!=-1) 204 { 205 BYTE *pBuffer=NULL; 206 DWORD dwSize=0; 207 bool bRes; 208 209 // if there's a special skin or cloak for this player, add it in 210 if(pMojangData) 211 { 212 // a skin? 213 if(pMojangData->wchSkin[0]!=0L) 214 { 215 wstring wstr=pMojangData->wchSkin; 216 // check the file is not already in 217 bRes=app.IsFileInMemoryTextures(wstr); 218 if(!bRes) 219 { 220#ifdef _XBOX 221 C4JStorage::ETMSStatus eTMSStatus; 222 eTMSStatus=StorageManager.ReadTMSFile(iUserID,C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic,pMojangData->wchSkin,&pBuffer, &dwSize); 223 224 bRes=(eTMSStatus==C4JStorage::ETMSStatus_Idle); 225#endif 226 } 227 228 if(bRes) 229 { 230 app.AddMemoryTextureFile(wstr,pBuffer,dwSize); 231 } 232 } 233 234 // a cloak? 235 if(pMojangData->wchCape[0]!=0L) 236 { 237 wstring wstr=pMojangData->wchCape; 238 // check the file is not already in 239 bRes=app.IsFileInMemoryTextures(wstr); 240 if(!bRes) 241 { 242#ifdef _XBOX 243 C4JStorage::ETMSStatus eTMSStatus; 244 eTMSStatus=StorageManager.ReadTMSFile(iUserID,C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic,pMojangData->wchCape,&pBuffer, &dwSize); 245 bRes=(eTMSStatus==C4JStorage::ETMSStatus_Idle); 246#endif 247 } 248 249 if(bRes) 250 { 251 app.AddMemoryTextureFile(wstr,pBuffer,dwSize); 252 } 253 } 254 } 255 256 // If we're online, read the banned game list 257 app.ReadBannedList(iUserID); 258 // mark the level as not checked against banned levels - it'll be checked once the level starts 259 app.SetBanListCheck(iUserID,false); 260 } 261 262 if( m_userIndex == ProfileManager.GetPrimaryPad() ) 263 { 264 if( app.GetTutorialMode() ) 265 { 266 minecraft->gameMode = new FullTutorialMode(ProfileManager.GetPrimaryPad(), minecraft, this); 267 } 268 // check if we're in the trial version 269 else if(ProfileManager.IsFullVersion()==false) 270 { 271 minecraft->gameMode = new TrialMode(ProfileManager.GetPrimaryPad(), minecraft, this); 272 } 273 else 274 { 275 MemSect(13); 276 minecraft->gameMode = new ConsoleGameMode(ProfileManager.GetPrimaryPad(), minecraft, this); 277 MemSect(0); 278 } 279 280 281 Level *dimensionLevel = minecraft->getLevel( packet->dimension ); 282 if( dimensionLevel == NULL ) 283 { 284 level = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, false, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty); 285 286 // 4J Stu - We want to share the SavedDataStorage between levels 287 int otherDimensionId = packet->dimension == 0 ? -1 : 0; 288 Level *activeLevel = minecraft->getLevel(otherDimensionId); 289 if( activeLevel != NULL ) 290 { 291 // Don't need to delete it here as it belongs to a client connection while will delete it when it's done 292 //if( level->savedDataStorage != NULL ) delete level->savedDataStorage; 293 level->savedDataStorage = activeLevel->savedDataStorage; 294 } 295 296 app.DebugPrintf("ClientConnection - DIFFICULTY --- %d\n",packet->difficulty); 297 level->difficulty = packet->difficulty; // 4J Added 298 level->isClientSide = true; 299 minecraft->setLevel(level); 300 } 301 302 minecraft->player->setPlayerIndex( packet->m_playerIndex ); 303 minecraft->player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) ); 304 minecraft->player->setCustomCape( app.GetPlayerCapeId(m_userIndex) ); 305 306 307 minecraft->createPrimaryLocalPlayer(ProfileManager.GetPrimaryPad()); 308 309 minecraft->player->dimension = packet->dimension; 310 //minecraft->setScreen(new ReceivingLevelScreen(this)); 311 minecraft->player->entityId = packet->clientVersion; 312 313 BYTE networkSmallId = getSocket()->getSmallId(); 314 app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges); 315 minecraft->player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges); 316 317 // Assume all privileges are on, so that the first message we see only indicates things that have been turned off 318 unsigned int startingPrivileges = 0; 319 Player::enableAllPlayerPrivileges(startingPrivileges,true); 320 321 if(networkPlayer->IsHost()) 322 { 323 Player::setPlayerGamePrivilege(startingPrivileges, Player::ePlayerGamePrivilege_HOST,1); 324 } 325 326 displayPrivilegeChanges(minecraft->player,startingPrivileges); 327 328 // update the debugoptions 329 app.SetGameSettingsDebugMask(ProfileManager.GetPrimaryPad(),app.GetGameSettingsDebugMask(-1,true)); 330 } 331 else 332 { 333 // 4J-PB - this isn't the level we want 334 //level = (MultiPlayerLevel *)minecraft->level; 335 level = (MultiPlayerLevel *)minecraft->getLevel( packet->dimension ); 336 shared_ptr<Player> player; 337 338 if(level==NULL) 339 { 340 int otherDimensionId = packet->dimension == 0 ? -1 : 0; 341 MultiPlayerLevel *activeLevel = minecraft->getLevel(otherDimensionId); 342 343 if(activeLevel == NULL) 344 { 345 otherDimensionId = packet->dimension == 0 ? 1 : (packet->dimension == -1 ? 1 : -1); 346 activeLevel = minecraft->getLevel(otherDimensionId); 347 } 348 349 MultiPlayerLevel *dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, false, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty); 350 351 dimensionLevel->savedDataStorage = activeLevel->savedDataStorage; 352 353 dimensionLevel->difficulty = packet->difficulty; // 4J Added 354 dimensionLevel->isClientSide = true; 355 level = dimensionLevel; 356 // 4J Stu - At time of writing ProfileManager.GetGamertag() does not always return the correct name, 357 // if sign-ins are turned off while the player signed in. Using the qnetPlayer instead. 358 // need to have a level before create extra local player 359 MultiPlayerLevel *levelpassedin=(MultiPlayerLevel *)level; 360 player = minecraft->createExtraLocalPlayer(m_userIndex, networkPlayer->GetOnlineName(), m_userIndex, packet->dimension, this,levelpassedin); 361 362 // need to have a player before the setlevel 363 shared_ptr<MultiplayerLocalPlayer> lastPlayer = minecraft->player; 364 minecraft->player = minecraft->localplayers[m_userIndex]; 365 minecraft->setLevel(level); 366 minecraft->player = lastPlayer; 367 } 368 else 369 { 370 player = minecraft->createExtraLocalPlayer(m_userIndex, networkPlayer->GetOnlineName(), m_userIndex, packet->dimension, this); 371 } 372 373 374 //level->addClientConnection( this ); 375 player->dimension = packet->dimension; 376 player->entityId = packet->clientVersion; 377 378 player->setPlayerIndex( packet->m_playerIndex ); 379 player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) ); 380 player->setCustomCape( app.GetPlayerCapeId(m_userIndex) ); 381 382 383 BYTE networkSmallId = getSocket()->getSmallId(); 384 app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges); 385 player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges); 386 387 // Assume all privileges are on, so that the first message we see only indicates things that have been turned off 388 unsigned int startingPrivileges = 0; 389 Player::enableAllPlayerPrivileges(startingPrivileges,true); 390 391 displayPrivilegeChanges(minecraft->localplayers[m_userIndex],startingPrivileges); 392 } 393 394 maxPlayers = packet->maxPlayers; 395 396 // need to have a player before the setLocalCreativeMode 397 shared_ptr<MultiplayerLocalPlayer> lastPlayer = minecraft->player; 398 minecraft->player = minecraft->localplayers[m_userIndex]; 399 ((MultiPlayerGameMode *)minecraft->localgameModes[m_userIndex])->setLocalMode(GameType::byId(packet->gameType)); 400 minecraft->player = lastPlayer; 401 402 // make sure the UI offsets for this player are set correctly 403 if(iUserID!=-1) 404 { 405 ui.UpdateSelectedItemPos(iUserID); 406 } 407 408 TelemetryManager->RecordLevelStart(m_userIndex, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, Minecraft::GetInstance()->getLevel(packet->dimension)->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount()); 409} 410 411void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet) 412{ 413 double x = packet->x / 32.0; 414 double y = packet->y / 32.0; 415 double z = packet->z / 32.0; 416 shared_ptr<Entity> e; 417 bool setRot = true; 418 419 // 4J-PB - replacing this massive if nest with switch 420 switch(packet->type) 421 { 422 case AddEntityPacket::MINECART: 423 e = Minecart::createMinecart(level, x, y, z, packet->data); 424 break; 425 case AddEntityPacket::FISH_HOOK: 426 { 427 // 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing 428 shared_ptr<Entity> owner = getEntity(packet->data); 429 430 // 4J - check all local players to find match 431 if( owner == NULL ) 432 { 433 for( int i = 0; i < XUSER_MAX_COUNT; i++ ) 434 { 435 if( minecraft->localplayers[i] ) 436 { 437 if( minecraft->localplayers[i]->entityId == packet->data ) 438 { 439 440 owner = minecraft->localplayers[i]; 441 break; 442 } 443 } 444 } 445 } 446 447 if (owner->instanceof(eTYPE_PLAYER)) 448 { 449 shared_ptr<Player> player = dynamic_pointer_cast<Player>(owner); 450 shared_ptr<FishingHook> hook = shared_ptr<FishingHook>( new FishingHook(level, x, y, z, player) ); 451 e = hook; 452 // 4J Stu - Move the player->fishing out of the ctor as we cannot reference 'this' 453 player->fishing = hook; 454 } 455 packet->data = 0; 456 } 457 break; 458 case AddEntityPacket::ARROW: 459 e = shared_ptr<Entity>( new Arrow(level, x, y, z) ); 460 break; 461 case AddEntityPacket::SNOWBALL: 462 e = shared_ptr<Entity>( new Snowball(level, x, y, z) ); 463 break; 464 case AddEntityPacket::ITEM_FRAME: 465 { 466 int ix=(int) x; 467 int iy=(int) y; 468 int iz = (int) z; 469 app.DebugPrintf("ClientConnection ITEM_FRAME xyz %d,%d,%d\n",ix,iy,iz); 470 } 471 e = shared_ptr<Entity>(new ItemFrame(level, (int) x, (int) y, (int) z, packet->data)); 472 packet->data = 0; 473 setRot = false; 474 break; 475 case AddEntityPacket::THROWN_ENDERPEARL: 476 e = shared_ptr<Entity>( new ThrownEnderpearl(level, x, y, z) ); 477 break; 478 case AddEntityPacket::EYEOFENDERSIGNAL: 479 e = shared_ptr<Entity>( new EyeOfEnderSignal(level, x, y, z) ); 480 break; 481 case AddEntityPacket::FIREBALL: 482 e = shared_ptr<Entity>( new LargeFireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); 483 packet->data = 0; 484 break; 485 case AddEntityPacket::SMALL_FIREBALL: 486 e = shared_ptr<Entity>( new SmallFireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); 487 packet->data = 0; 488 break; 489 case AddEntityPacket::DRAGON_FIRE_BALL: 490 e = shared_ptr<Entity>( new DragonFireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); 491 packet->data = 0; 492 break; 493 case AddEntityPacket::EGG: 494 e = shared_ptr<Entity>( new ThrownEgg(level, x, y, z) ); 495 break; 496 case AddEntityPacket::THROWN_POTION: 497 e = shared_ptr<Entity>( new ThrownPotion(level, x, y, z, packet->data) ); 498 packet->data = 0; 499 break; 500 case AddEntityPacket::THROWN_EXPBOTTLE: 501 e = shared_ptr<Entity>( new ThrownExpBottle(level, x, y, z) ); 502 packet->data = 0; 503 break; 504 case AddEntityPacket::BOAT: 505 e = shared_ptr<Entity>( new Boat(level, x, y, z) ); 506 break; 507 case AddEntityPacket::PRIMED_TNT: 508 e = shared_ptr<Entity>( new PrimedTnt(level, x, y, z, nullptr) ); 509 break; 510 case AddEntityPacket::ENDER_CRYSTAL: 511 e = shared_ptr<Entity>( new EnderCrystal(level, x, y, z) ); 512 break; 513 case AddEntityPacket::ITEM: 514 e = shared_ptr<Entity>( new ItemEntity(level, x, y, z) ); 515 break; 516 case AddEntityPacket::FALLING: 517 e = shared_ptr<Entity>( new FallingTile(level, x, y, z, packet->data & 0xFFFF, packet->data >> 16) ); 518 packet->data = 0; 519 break; 520 case AddEntityPacket::WITHER_SKULL: 521 e = shared_ptr<Entity>(new WitherSkull(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0)); 522 packet->data = 0; 523 break; 524 case AddEntityPacket::FIREWORKS: 525 e = shared_ptr<Entity>(new FireworksRocketEntity(level, x, y, z, nullptr)); 526 break; 527 case AddEntityPacket::LEASH_KNOT: 528 e = shared_ptr<Entity>(new LeashFenceKnotEntity(level, (int) x, (int) y, (int) z)); 529 packet->data = 0; 530 break; 531#ifndef _FINAL_BUILD 532 default: 533 // Not a known entity (?) 534 assert(0); 535#endif 536 } 537 538 /* if (packet->type == AddEntityPacket::MINECART_RIDEABLE) e = shared_ptr<Entity>( new Minecart(level, x, y, z, Minecart::RIDEABLE) ); 539 if (packet->type == AddEntityPacket::MINECART_CHEST) e = shared_ptr<Entity>( new Minecart(level, x, y, z, Minecart::CHEST) ); 540 if (packet->type == AddEntityPacket::MINECART_FURNACE) e = shared_ptr<Entity>( new Minecart(level, x, y, z, Minecart::FURNACE) ); 541 if (packet->type == AddEntityPacket::FISH_HOOK) 542 { 543 // 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing 544 shared_ptr<Entity> owner = getEntity(packet->data); 545 546 // 4J - check all local players to find match 547 if( owner == NULL ) 548 { 549 for( int i = 0; i < XUSER_MAX_COUNT; i++ ) 550 { 551 if( minecraft->localplayers[i] ) 552 { 553 if( minecraft->localplayers[i]->entityId == packet->data ) 554 { 555 556 owner = minecraft->localplayers[i]; 557 break; 558 } 559 } 560 } 561 } 562 shared_ptr<Player> player = dynamic_pointer_cast<Player>(owner); 563 if (player != NULL) 564 { 565 shared_ptr<FishingHook> hook = shared_ptr<FishingHook>( new FishingHook(level, x, y, z, player) ); 566 e = hook; 567 // 4J Stu - Move the player->fishing out of the ctor as we cannot reference 'this' 568 player->fishing = hook; 569 } 570 packet->data = 0; 571 } 572 573 if (packet->type == AddEntityPacket::ARROW) e = shared_ptr<Entity>( new Arrow(level, x, y, z) ); 574 if (packet->type == AddEntityPacket::SNOWBALL) e = shared_ptr<Entity>( new Snowball(level, x, y, z) ); 575 if (packet->type == AddEntityPacket::THROWN_ENDERPEARL) e = shared_ptr<Entity>( new ThrownEnderpearl(level, x, y, z) ); 576 if (packet->type == AddEntityPacket::EYEOFENDERSIGNAL) e = shared_ptr<Entity>( new EyeOfEnderSignal(level, x, y, z) ); 577 if (packet->type == AddEntityPacket::FIREBALL) 578 { 579 e = shared_ptr<Entity>( new Fireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); 580 packet->data = 0; 581 } 582 if (packet->type == AddEntityPacket::SMALL_FIREBALL) 583 { 584 e = shared_ptr<Entity>( new SmallFireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); 585 packet->data = 0; 586 } 587 if (packet->type == AddEntityPacket::EGG) e = shared_ptr<Entity>( new ThrownEgg(level, x, y, z) ); 588 if (packet->type == AddEntityPacket::THROWN_POTION) 589 { 590 e = shared_ptr<Entity>( new ThrownPotion(level, x, y, z, packet->data) ); 591 packet->data = 0; 592 } 593 if (packet->type == AddEntityPacket::THROWN_EXPBOTTLE) 594 { 595 e = shared_ptr<Entity>( new ThrownExpBottle(level, x, y, z) ); 596 packet->data = 0; 597 } 598 if (packet->type == AddEntityPacket::BOAT) e = shared_ptr<Entity>( new Boat(level, x, y, z) ); 599 if (packet->type == AddEntityPacket::PRIMED_TNT) e = shared_ptr<Entity>( new PrimedTnt(level, x, y, z) ); 600 if (packet->type == AddEntityPacket::ENDER_CRYSTAL) e = shared_ptr<Entity>( new EnderCrystal(level, x, y, z) ); 601 if (packet->type == AddEntityPacket::FALLING_SAND) e = shared_ptr<Entity>( new FallingTile(level, x, y, z, Tile::sand->id) ); 602 if (packet->type == AddEntityPacket::FALLING_GRAVEL) e = shared_ptr<Entity>( new FallingTile(level, x, y, z, Tile::gravel->id) ); 603 if (packet->type == AddEntityPacket::FALLING_EGG) e = shared_ptr<Entity>( new FallingTile(level, x, y, z, Tile::dragonEgg_Id) ); 604 605 */ 606 607 if (e != NULL) 608 { 609 e->xp = packet->x; 610 e->yp = packet->y; 611 e->zp = packet->z; 612 613 float yRot = packet->yRot * 360 / 256.0f; 614 float xRot = packet->xRot * 360 / 256.0f; 615 e->yRotp = packet->yRot; 616 e->xRotp = packet->xRot; 617 618 if (setRot) 619 { 620 e->yRot = 0.0f; 621 e->xRot = 0.0f; 622 } 623 624 vector<shared_ptr<Entity> > *subEntities = e->getSubEntities(); 625 if (subEntities != NULL) 626 { 627 int offs = packet->id - e->entityId; 628 //for (int i = 0; i < subEntities.length; i++) 629 for(AUTO_VAR(it, subEntities->begin()); it != subEntities->end(); ++it) 630 { 631 (*it)->entityId += offs; 632 //subEntities[i].entityId += offs; 633 //System.out.println(subEntities[i].entityId); 634 } 635 } 636 637 if (packet->type == AddEntityPacket::LEASH_KNOT) 638 { 639 // 4J: "Move" leash knot to it's current position, this sets old position (like frame, leash has adjusted position) 640 e->absMoveTo(e->x, e->y, e->z, yRot, xRot); 641 } 642 else if(packet->type == AddEntityPacket::ITEM_FRAME) 643 { 644 // Not doing this move for frame, as the ctor for these objects does some adjustments on the position based on direction to move the object out slightly from what it is attached to, and this just overwrites it 645 } 646 else 647 { 648 // For everything else, set position 649 e->absMoveTo(x, y, z, yRot, xRot); 650 } 651 e->entityId = packet->id; 652 level->putEntity(packet->id, e); 653 654 if (packet->data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0 655 { 656 657 if (packet->type == AddEntityPacket::ARROW) 658 { 659 shared_ptr<Entity> owner = getEntity(packet->data); 660 661 // 4J - check all local players to find match 662 if( owner == NULL ) 663 { 664 for( int i = 0; i < XUSER_MAX_COUNT; i++ ) 665 { 666 if( minecraft->localplayers[i] ) 667 { 668 if( minecraft->localplayers[i]->entityId == packet->data ) 669 { 670 owner = minecraft->localplayers[i]; 671 break; 672 } 673 } 674 } 675 } 676 677 if ( owner != NULL && owner->instanceof(eTYPE_LIVINGENTITY) ) 678 { 679 dynamic_pointer_cast<Arrow>(e)->owner = dynamic_pointer_cast<LivingEntity>(owner); 680 } 681 } 682 683 e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0); 684 } 685 686 // 4J: Check our deferred entity link packets 687 checkDeferredEntityLinkPackets(e->entityId); 688 } 689} 690 691void ClientConnection::handleAddExperienceOrb(shared_ptr<AddExperienceOrbPacket> packet) 692{ 693 shared_ptr<Entity> e = shared_ptr<ExperienceOrb>( new ExperienceOrb(level, packet->x / 32.0, packet->y / 32.0, packet->z / 32.0, packet->value) ); 694 e->xp = packet->x; 695 e->yp = packet->y; 696 e->zp = packet->z; 697 e->yRot = 0; 698 e->xRot = 0; 699 e->entityId = packet->id; 700 level->putEntity(packet->id, e); 701} 702 703void ClientConnection::handleAddGlobalEntity(shared_ptr<AddGlobalEntityPacket> packet) 704{ 705 double x = packet->x / 32.0; 706 double y = packet->y / 32.0; 707 double z = packet->z / 32.0; 708 shared_ptr<Entity> e;// = nullptr; 709 if (packet->type == AddGlobalEntityPacket::LIGHTNING) e = shared_ptr<LightningBolt>( new LightningBolt(level, x, y, z) ); 710 if (e != NULL) 711 { 712 e->xp = packet->x; 713 e->yp = packet->y; 714 e->zp = packet->z; 715 e->yRot = 0; 716 e->xRot = 0; 717 e->entityId = packet->id; 718 level->addGlobalEntity(e); 719 } 720} 721 722void ClientConnection::handleAddPainting(shared_ptr<AddPaintingPacket> packet) 723{ 724 shared_ptr<Painting> painting = shared_ptr<Painting>( new Painting(level, packet->x, packet->y, packet->z, packet->dir, packet->motive) ); 725 level->putEntity(packet->id, painting); 726} 727 728void ClientConnection::handleSetEntityMotion(shared_ptr<SetEntityMotionPacket> packet) 729{ 730 shared_ptr<Entity> e = getEntity(packet->id); 731 if (e == NULL) return; 732 e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0); 733} 734 735void ClientConnection::handleSetEntityData(shared_ptr<SetEntityDataPacket> packet) 736{ 737 shared_ptr<Entity> e = getEntity(packet->id); 738 if (e != NULL && packet->getUnpackedData() != NULL) 739 { 740 e->getEntityData()->assignValues(packet->getUnpackedData()); 741 } 742} 743 744void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet) 745{ 746 // Some remote players could actually be local players that are already added 747 for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) 748 { 749 // need to use the XUID here 750 PlayerUID playerXUIDOnline = INVALID_XUID, playerXUIDOffline = INVALID_XUID; 751 ProfileManager.GetXUID(idx,&playerXUIDOnline,true); 752 ProfileManager.GetXUID(idx,&playerXUIDOffline,false); 753 if( (playerXUIDOnline != INVALID_XUID && ProfileManager.AreXUIDSEqual(playerXUIDOnline,packet->xuid) ) || 754 (playerXUIDOffline != INVALID_XUID && ProfileManager.AreXUIDSEqual(playerXUIDOffline,packet->xuid) ) ) 755 { 756 app.DebugPrintf("AddPlayerPacket received with XUID of local player\n"); 757 return; 758 } 759 } 760/*#ifdef _WINDOWS64 761 // On Windows64 all XUIDs are INVALID_XUID so the XUID check above never fires. 762 // packet->m_playerIndex is the server-assigned sequential index (set via LoginPacket), 763 // NOT the controller slot — so we must scan all local player slots and match by 764 // their stored server index rather than using it directly as an array subscript. 765 for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) 766 { 767 if(minecraft->localplayers[idx] != NULL && 768 minecraft->localplayers[idx]->getPlayerIndex() == packet->m_playerIndex) 769 { 770 app.DebugPrintf("AddPlayerPacket received for local player (controller %d, server index %d), skipping RemotePlayer creation\n", idx, packet->m_playerIndex); 771 return; 772 } 773 } 774#endif*/ 775 776 double x = packet->x / 32.0; 777 double y = packet->y / 32.0; 778 double z = packet->z / 32.0; 779 float yRot = packet->yRot * 360 / 256.0f; 780 float xRot = packet->xRot * 360 / 256.0f; 781 shared_ptr<RemotePlayer> player = shared_ptr<RemotePlayer>( new RemotePlayer(minecraft->level, packet->name) ); 782 player->xo = player->xOld = player->xp = packet->x; 783 player->yo = player->yOld = player->yp = packet->y; 784 player->zo = player->zOld = player->zp = packet->z; 785 player->xRotp = packet->xRot; 786 player->yRotp = packet->yRot; 787 player->yHeadRot = packet->yHeadRot * 360 / 256.0f; 788 player->setXuid(packet->xuid); 789 790#ifdef _DURANGO 791 // On Durango request player display name from network manager 792 INetworkPlayer *networkPlayer = g_NetworkManager.GetPlayerByXuid(player->getXuid()); 793 if (networkPlayer != NULL) player->m_displayName = networkPlayer->GetDisplayName(); 794#else 795 // On all other platforms display name is just gamertag so don't check with the network manager 796 player->m_displayName = player->name; 797#endif 798 799 // printf("\t\t\t\t%d: Add player\n",packet->id,packet->yRot); 800 801 int item = packet->carriedItem; 802 if (item == 0) 803 { 804 player->inventory->items[player->inventory->selected] = shared_ptr<ItemInstance>(); // NULL; 805 } 806 else 807 { 808 player->inventory->items[player->inventory->selected] = shared_ptr<ItemInstance>( new ItemInstance(item, 1, 0) ); 809 } 810 player->absMoveTo(x, y, z, yRot, xRot); 811 812 player->setPlayerIndex( packet->m_playerIndex ); 813 player->setCustomSkin( packet->m_skinId ); 814 player->setCustomCape( packet->m_capeId ); 815 player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges); 816 817 if(!player->customTextureUrl.empty() && player->customTextureUrl.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl)) 818 { 819 if( minecraft->addPendingClientTextureRequest(player->customTextureUrl) ) 820 { 821 app.DebugPrintf("Client sending TextureAndGeometryPacket to get custom skin %ls for player %ls\n",player->customTextureUrl.c_str(), player->name.c_str()); 822 823 send(shared_ptr<TextureAndGeometryPacket>( new TextureAndGeometryPacket(player->customTextureUrl,NULL,0) ) ); 824 } 825 } 826 else if(!player->customTextureUrl.empty() && app.IsFileInMemoryTextures(player->customTextureUrl)) 827 { 828 // Update the ref count on the memory texture data 829 app.AddMemoryTextureFile(player->customTextureUrl,NULL,0); 830 } 831 832 app.DebugPrintf("Custom skin for player %ls is %ls\n",player->name.c_str(),player->customTextureUrl.c_str()); 833 834 if(!player->customTextureUrl2.empty() && player->customTextureUrl2.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl2)) 835 { 836 if( minecraft->addPendingClientTextureRequest(player->customTextureUrl2) ) 837 { 838 app.DebugPrintf("Client sending texture packet to get custom cape %ls for player %ls\n",player->customTextureUrl2.c_str(), player->name.c_str()); 839 send(shared_ptr<TexturePacket>( new TexturePacket(player->customTextureUrl2,NULL,0) ) ); 840 } 841 } 842 else if(!player->customTextureUrl2.empty() && app.IsFileInMemoryTextures(player->customTextureUrl2)) 843 { 844 // Update the ref count on the memory texture data 845 app.AddMemoryTextureFile(player->customTextureUrl2,NULL,0); 846 } 847 848 app.DebugPrintf("Custom cape for player %ls is %ls\n",player->name.c_str(),player->customTextureUrl2.c_str()); 849 850 level->putEntity(packet->id, player); 851 852 vector<shared_ptr<SynchedEntityData::DataItem> > *unpackedData = packet->getUnpackedData(); 853 if (unpackedData != NULL) 854 { 855 player->getEntityData()->assignValues(unpackedData); 856 } 857 858} 859 860void ClientConnection::handleTeleportEntity(shared_ptr<TeleportEntityPacket> packet) 861{ 862 shared_ptr<Entity> e = getEntity(packet->id); 863 if (e == NULL) return; 864 e->xp = packet->x; 865 e->yp = packet->y; 866 e->zp = packet->z; 867 double x = e->xp / 32.0; 868 double y = e->yp / 32.0 + 1 / 64.0f; 869 double z = e->zp / 32.0; 870 // 4J - make sure xRot stays within -90 -> 90 range 871 int ixRot = packet->xRot; 872 if( ixRot >= 128 ) ixRot -= 256; 873 float yRot = packet->yRot * 360 / 256.0f; 874 float xRot = ixRot * 360 / 256.0f; 875 e->yRotp = packet->yRot; 876 e->xRotp = ixRot; 877 878// printf("\t\t\t\t%d: Teleport to %d (lerp to %f)\n",packet->id,packet->yRot,yRot); 879 e->lerpTo(x, y, z, yRot, xRot, 3); 880} 881 882void ClientConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> packet) 883{ 884 if (packet->slot >= 0 && packet->slot < Inventory::getSelectionSize()) { 885 Minecraft::GetInstance()->localplayers[m_userIndex].get()->inventory->selected = packet->slot; 886 } 887} 888 889void ClientConnection::handleMoveEntity(shared_ptr<MoveEntityPacket> packet) 890{ 891 shared_ptr<Entity> e = getEntity(packet->id); 892 if (e == NULL) return; 893 e->xp += packet->xa; 894 e->yp += packet->ya; 895 e->zp += packet->za; 896 double x = e->xp / 32.0; 897 // 4J - The original code did not add the 1/64.0f like the teleport above did, which caused minecarts to fall through the ground 898 double y = e->yp / 32.0 + 1 / 64.0f; 899 double z = e->zp / 32.0; 900 // 4J - have changed rotation to be relative here too 901 e->yRotp += packet->yRot; 902 e->xRotp += packet->xRot; 903 float yRot = ( e->yRotp * 360 ) / 256.0f; 904 float xRot = ( e->xRotp * 360 ) / 256.0f; 905// float yRot = packet->hasRot ? packet->yRot * 360 / 256.0f : e->yRot; 906// float xRot = packet->hasRot ? packet->xRot * 360 / 256.0f : e->xRot; 907 e->lerpTo(x, y, z, yRot, xRot, 3); 908} 909 910void ClientConnection::handleRotateMob(shared_ptr<RotateHeadPacket> packet) 911{ 912 shared_ptr<Entity> e = getEntity(packet->id); 913 if (e == NULL) return; 914 float yHeadRot = packet->yHeadRot * 360 / 256.f; 915 e->setYHeadRot(yHeadRot); 916} 917 918void ClientConnection::handleMoveEntitySmall(shared_ptr<MoveEntityPacketSmall> packet) 919{ 920 shared_ptr<Entity> e = getEntity(packet->id); 921 if (e == NULL) return; 922 e->xp += packet->xa; 923 e->yp += packet->ya; 924 e->zp += packet->za; 925 double x = e->xp / 32.0; 926 // 4J - The original code did not add the 1/64.0f like the teleport above did, which caused minecarts to fall through the ground 927 double y = e->yp / 32.0 + 1 / 64.0f; 928 double z = e->zp / 32.0; 929 // 4J - have changed rotation to be relative here too 930 e->yRotp += packet->yRot; 931 e->xRotp += packet->xRot; 932 float yRot = ( e->yRotp * 360 ) / 256.0f; 933 float xRot = ( e->xRotp * 360 ) / 256.0f; 934// float yRot = packet->hasRot ? packet->yRot * 360 / 256.0f : e->yRot; 935// float xRot = packet->hasRot ? packet->xRot * 360 / 256.0f : e->xRot; 936 e->lerpTo(x, y, z, yRot, xRot, 3); 937} 938 939void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packet) 940{ 941 for (int i = 0; i < packet->ids.length; i++) 942 { 943 level->removeEntity(packet->ids[i]); 944 } 945} 946 947void ClientConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet) 948{ 949 shared_ptr<Player> player = minecraft->localplayers[m_userIndex]; //minecraft->player; 950 951 double x = player->x; 952 double y = player->y; 953 double z = player->z; 954 float yRot = player->yRot; 955 float xRot = player->xRot; 956 957 if (packet->hasPos) 958 { 959 x = packet->x; 960 y = packet->y; 961 z = packet->z; 962 } 963 if (packet->hasRot) 964 { 965 yRot = packet->yRot; 966 xRot = packet->xRot; 967 } 968 969 player->ySlideOffset = 0; 970 player->xd = player->yd = player->zd = 0; 971 player->absMoveTo(x, y, z, yRot, xRot); 972 packet->x = player->x; 973 packet->y = player->bb->y0; 974 packet->z = player->z; 975 packet->yView = player->y; 976 connection->send(packet); 977 if (!started) 978 { 979 980 if(!g_NetworkManager.IsHost() ) 981 { 982 Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCConnected * 100)/ (eCCConnected)); 983 } 984 player->xo = player->x; 985 player->yo = player->y; 986 player->zo = player->z; 987 // 4J - added setting xOld/yOld/zOld here too, as otherwise at the start of the game we interpolate the player position from the origin to wherever its first position really is 988 player->xOld = player->x; 989 player->yOld = player->y; 990 player->zOld = player->z; 991 992 started = true; 993 minecraft->setScreen(NULL); 994 995 // Fix for #105852 - TU12: Content: Gameplay: Local splitscreen Players are spawned at incorrect places after re-joining previously saved and loaded "Mass Effect World". 996 // Move this check from Minecraft::createExtraLocalPlayer 997 // 4J-PB - can't call this when this function is called from the qnet thread (GetGameStarted will be false) 998 if(app.GetGameStarted()) 999 { 1000 ui.CloseUIScenes(m_userIndex); 1001 } 1002 } 1003 1004} 1005 1006// 4J Added 1007void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaPacket> packet) 1008{ 1009 for(int z = packet->m_minZ; z <= packet->m_maxZ; ++z) 1010 for(int x = packet->m_minX; x <= packet->m_maxX; ++x) 1011 level->setChunkVisible(x, z, true); 1012} 1013 1014void ClientConnection::handleChunkVisibility(shared_ptr<ChunkVisibilityPacket> packet) 1015{ 1016 level->setChunkVisible(packet->x, packet->z, packet->visible); 1017} 1018 1019void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket> packet) 1020{ 1021 // 4J - changed to encode level in packet 1022 MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; 1023 if( dimensionLevel ) 1024 { 1025 PIXBeginNamedEvent(0,"Handle chunk tiles update"); 1026 LevelChunk *lc = dimensionLevel->getChunk(packet->xc, packet->zc); 1027 int xo = packet->xc * 16; 1028 int zo = packet->zc * 16; 1029 // 4J Stu - Unshare before we make any changes incase the server is already another step ahead of us 1030 // Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water. 1031 // This is quite expensive to do, so only consider unsharing if this tile setting is going to actually 1032 // change something 1033 bool forcedUnshare = false; 1034 for (int i = 0; i < packet->count; i++) 1035 { 1036 int pos = packet->positions[i]; 1037 int tile = packet->blocks[i] & 0xff; 1038 int data = packet->data[i]; 1039 1040 1041 int x = (pos >> 12) & 15; 1042 int z = (pos >> 8) & 15; 1043 int y = ((pos) & 255); 1044 1045 // If this is going to actually change a tile, we'll need to unshare 1046 int prevTile = lc->getTile(x, y, z); 1047 if( ( tile != prevTile && !forcedUnshare ) ) 1048 { 1049 PIXBeginNamedEvent(0,"Chunk data unsharing\n"); 1050 dimensionLevel->unshareChunkAt(xo,zo); 1051 PIXEndNamedEvent(); 1052 forcedUnshare = true; 1053 } 1054 1055 // 4J - Changes now that lighting is done at the client side of things... 1056 // Note - the java version now calls the doSetTileAndData method from the level here rather than the levelchunk, which ultimately ends up 1057 // calling checkLight for the altered tile. For us this doesn't always work as when sharing tile data between a local server & client, the 1058 // tile might not be considered to be being changed on the client as the server already has changed the shared data, and so the checkLight 1059 // doesn't happen. Hence doing an explicit checkLight here instead. 1060 lc->setTileAndData(x, y, z, tile, data); 1061 dimensionLevel->checkLight(x + xo, y, z + zo); 1062 1063 dimensionLevel->clearResetRegion(x + xo, y, z + zo, x + xo, y, z + zo); 1064 1065 // Don't bother setting this to dirty if it isn't going to visually change - we get a lot of 1066 // water changing from static to dynamic for instance 1067 if(!( ( ( prevTile == Tile::water_Id ) && ( tile == Tile::calmWater_Id ) ) || 1068 ( ( prevTile == Tile::calmWater_Id ) && ( tile == Tile::water_Id ) ) || 1069 ( ( prevTile == Tile::lava_Id ) && ( tile == Tile::calmLava_Id ) ) || 1070 ( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::calmLava_Id ) ) || 1071 ( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::lava_Id ) ) ) ) 1072 { 1073 dimensionLevel->setTilesDirty(x + xo, y, z + zo, x + xo, y, z + zo); 1074 } 1075 1076 // 4J - remove any tite entities in this region which are associated with a tile that is now no longer a tile entity. Without doing this we end up with stray 1077 // tile entities kicking round, which leads to a bug where chests can't be properly placed again in a location after (say) a chest being removed by TNT 1078 dimensionLevel->removeUnusedTileEntitiesInRegion(xo + x, y, zo + z, xo + x+1, y+1, zo + z+1); 1079 } 1080 PIXBeginNamedEvent(0,"Chunk data sharing\n"); 1081 dimensionLevel->shareChunkAt(xo,zo); // 4J - added - only shares if chunks are same on server & client 1082 PIXEndNamedEvent(); 1083 1084 PIXEndNamedEvent(); 1085 } 1086} 1087 1088void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacket> packet) 1089{ 1090 // 4J - changed to encode level in packet 1091 MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; 1092 if( dimensionLevel ) 1093 { 1094 PIXBeginNamedEvent(0,"Handle block region update"); 1095 1096 int y1 = packet->y + packet->ys; 1097 if(packet->bIsFullChunk) 1098 { 1099 y1 = Level::maxBuildHeight; 1100 if(packet->buffer.length > 0) 1101 { 1102 PIXBeginNamedEvent(0, "Reordering to XZY"); 1103 LevelChunk::reorderBlocksAndDataToXZY(packet->y, packet->xs, packet->ys, packet->zs, &packet->buffer); 1104 PIXEndNamedEvent(); 1105 } 1106 } 1107 PIXBeginNamedEvent(0,"Clear rest region"); 1108 dimensionLevel->clearResetRegion(packet->x, packet->y, packet->z, packet->x + packet->xs - 1, y1 - 1, packet->z + packet->zs - 1); 1109 PIXEndNamedEvent(); 1110 1111 PIXBeginNamedEvent(0,"setBlocksAndData"); 1112 // Only full chunks send lighting information now - added flag to end of this call 1113 dimensionLevel->setBlocksAndData(packet->x, packet->y, packet->z, packet->xs, packet->ys, packet->zs, packet->buffer, packet->bIsFullChunk); 1114 PIXEndNamedEvent(); 1115 1116// OutputDebugString("END BRU\n"); 1117 1118 PIXBeginNamedEvent(0,"removeUnusedTileEntitiesInRegion"); 1119 // 4J - remove any tite entities in this region which are associated with a tile that is now no longer a tile entity. Without doing this we end up with stray 1120 // tile entities kicking round, which leads to a bug where chests can't be properly placed again in a location after (say) a chest being removed by TNT 1121 dimensionLevel->removeUnusedTileEntitiesInRegion(packet->x, packet->y, packet->z, packet->x + packet->xs, y1, packet->z + packet->zs ); 1122 PIXEndNamedEvent(); 1123 1124 // If this is a full packet for a chunk, make sure that the cache now considers that it has data for this chunk - this is used to determine whether to bother 1125 // rendering mobs or not, so we don't have them in crazy positions before the data is there 1126 if( packet->bIsFullChunk ) 1127 { 1128 PIXBeginNamedEvent(0,"dateReceivedForChunk"); 1129 dimensionLevel->dataReceivedForChunk( packet->x >> 4, packet->z >> 4 ); 1130 PIXEndNamedEvent(); 1131 } 1132 PIXEndNamedEvent(); 1133 } 1134} 1135 1136void ClientConnection::handleTileUpdate(shared_ptr<TileUpdatePacket> packet) 1137{ 1138 // 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. 1139 // 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 1140 // ServerPlayerGameMode::destroyBlock 1141 bool destroyTilePacket = false; 1142 if( packet->block == 255 ) 1143 { 1144 packet->block = 0; 1145 destroyTilePacket = true; 1146 } 1147 // 4J - changed to encode level in packet 1148 MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; 1149 if( dimensionLevel ) 1150 { 1151 PIXBeginNamedEvent(0,"Handle tile update"); 1152 1153 if( g_NetworkManager.IsHost() ) 1154 { 1155 // 4J Stu - Unshare before we make any changes incase the server is already another step ahead of us 1156 // Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water. 1157 // This is quite expensive to do, so only consider unsharing if this tile setting is going to actually 1158 // change something 1159 int prevTile = dimensionLevel->getTile(packet->x, packet->y, packet->z); 1160 int prevData = dimensionLevel->getData(packet->x, packet->y, packet->z); 1161 if( packet->block != prevTile || packet->data != prevData ) 1162 { 1163 PIXBeginNamedEvent(0,"Chunk data unsharing\n"); 1164 dimensionLevel->unshareChunkAt(packet->x,packet->z); 1165 PIXEndNamedEvent(); 1166 } 1167 } 1168 1169 // 4J - In creative mode, we don't update the tile locally then get it confirmed by the server - the first point that we know we are about to destroy a tile is here. Let 1170 // the rendering side of thing know so we can synchronise collision with async render data upates. 1171 if( destroyTilePacket ) 1172 { 1173 minecraft->levelRenderer->destroyedTileManager->destroyingTileAt(dimensionLevel, packet->x, packet->y, packet->z); 1174 } 1175 1176 PIXBeginNamedEvent(0,"Setting data\n"); 1177 bool tileWasSet = dimensionLevel->doSetTileAndData(packet->x, packet->y, packet->z, packet->block, packet->data); 1178 1179 PIXEndNamedEvent(); 1180 1181 // 4J - remove any tite entities in this region which are associated with a tile that is now no longer a tile entity. Without doing this we end up with stray 1182 // tile entities kicking round, which leads to a bug where chests can't be properly placed again in a location after (say) a chest being removed by TNT 1183 dimensionLevel->removeUnusedTileEntitiesInRegion(packet->x, packet->y, packet->z, packet->x+1, packet->y+1, packet->z+1 ); 1184 1185 PIXBeginNamedEvent(0,"Sharing data\n"); 1186 dimensionLevel->shareChunkAt(packet->x,packet->z); // 4J - added - only shares if chunks are same on server & client 1187 PIXEndNamedEvent(); 1188 1189 PIXEndNamedEvent(); 1190 } 1191} 1192 1193void ClientConnection::handleDisconnect(shared_ptr<DisconnectPacket> packet) 1194{ 1195 connection->close(DisconnectPacket::eDisconnect_Kicked); 1196 done = true; 1197 1198 Minecraft *pMinecraft = Minecraft::GetInstance(); 1199 pMinecraft->connectionDisconnected( m_userIndex , packet->reason ); 1200 app.SetDisconnectReason( packet->reason ); 1201 1202 app.SetAction(m_userIndex,eAppAction_ExitWorld,(void *)TRUE); 1203 //minecraft->setLevel(NULL); 1204 //minecraft->setScreen(new DisconnectedScreen(L"disconnect.disconnected", L"disconnect.genericReason", &packet->reason)); 1205 1206} 1207 1208void ClientConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason, void *reasonObjects) 1209{ 1210 if (done) return; 1211 done = true; 1212 1213 Minecraft *pMinecraft = Minecraft::GetInstance(); 1214 pMinecraft->connectionDisconnected( m_userIndex , reason ); 1215 1216 // 4J Stu - TU-1 hotfix 1217 // Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost 1218 // In the (now unlikely) event that the host connections times out, allow the player to save their game 1219 if(g_NetworkManager.IsHost() && 1220 (reason == DisconnectPacket::eDisconnect_TimeOut || reason == DisconnectPacket::eDisconnect_Overflow) && 1221 m_userIndex == ProfileManager.GetPrimaryPad() && 1222 !MinecraftServer::saveOnExitAnswered() ) 1223 { 1224 UINT uiIDA[1]; 1225 uiIDA[0]=IDS_CONFIRM_OK; 1226 ui.RequestErrorMessage(IDS_EXITING_GAME, IDS_GENERIC_ERROR, uiIDA, 1, ProfileManager.GetPrimaryPad(),&ClientConnection::HostDisconnectReturned,NULL); 1227 } 1228 else 1229 { 1230 app.SetAction(m_userIndex,eAppAction_ExitWorld,(void *)TRUE); 1231 } 1232 1233 //minecraft->setLevel(NULL); 1234 //minecraft->setScreen(new DisconnectedScreen(L"disconnect.lost", reason, reasonObjects)); 1235} 1236 1237void ClientConnection::sendAndDisconnect(shared_ptr<Packet> packet) 1238{ 1239 if (done) return; 1240 connection->send(packet); 1241 connection->sendAndQuit(); 1242} 1243 1244void ClientConnection::send(shared_ptr<Packet> packet) 1245{ 1246 if (done) return; 1247 connection->send(packet); 1248} 1249 1250void ClientConnection::handleTakeItemEntity(shared_ptr<TakeItemEntityPacket> packet) 1251{ 1252 shared_ptr<Entity> from = getEntity(packet->itemId); 1253 shared_ptr<LivingEntity> to = dynamic_pointer_cast<LivingEntity>(getEntity(packet->playerId)); 1254 1255 // 4J - the original game could assume that if getEntity didn't find the player, it must be the local player. We 1256 // need to search all local players 1257 bool isLocalPlayer = false; 1258 for( int i = 0; i < XUSER_MAX_COUNT; i++ ) 1259 { 1260 if( minecraft->localplayers[i] ) 1261 { 1262 if( minecraft->localplayers[i]->entityId == packet->playerId ) 1263 { 1264 isLocalPlayer = true; 1265 to = minecraft->localplayers[i]; 1266 break; 1267 } 1268 } 1269 } 1270 1271 if (to == NULL) 1272 { 1273 // Don't know if this should ever really happen, but seems safest to try and remove the entity that has been collected even if we can't 1274 // create a particle as we don't know what really collected it 1275 level->removeEntity(packet->itemId); 1276 return; 1277 } 1278 1279 if (from != NULL) 1280 { 1281 // If this is a local player, then we only want to do processing for it if this connection is associated with the player it is for. In 1282 // particular, we don't want to remove the item entity until we are processing it for the right connection, or else we won't have a valid 1283 // "from" reference if we've already removed the item for an earlier processed connection 1284 if( isLocalPlayer ) 1285 { 1286 shared_ptr<LocalPlayer> player = dynamic_pointer_cast<LocalPlayer>(to); 1287 1288 // 4J Stu - Fix for #10213 - UI: Local clients cannot progress through the tutorial normally. 1289 // We only send this packet once if many local players can see the event, so make sure we update 1290 // the tutorial for the player that actually picked up the item 1291 int playerPad = player->GetXboxPad(); 1292 1293 if( minecraft->localgameModes[playerPad] != NULL ) 1294 { 1295 // 4J-PB - add in the XP orb sound 1296 if(from->GetType() == eTYPE_EXPERIENCEORB) 1297 { 1298 float fPitch=((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f; 1299 app.DebugPrintf("XP Orb with pitch %f\n",fPitch); 1300 level->playSound(from, eSoundType_RANDOM_ORB, 0.2f, fPitch); 1301 } 1302 else 1303 { 1304 level->playSound(from, eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); 1305 } 1306 1307 minecraft->particleEngine->add( shared_ptr<TakeAnimationParticle>( new TakeAnimationParticle(minecraft->level, from, to, -0.5f) ) ); 1308 level->removeEntity(packet->itemId); 1309 } 1310 else 1311 { 1312 // Don't know if this should ever really happen, but seems safest to try and remove the entity that has been collected even if it 1313 // somehow isn't an itementity 1314 level->removeEntity(packet->itemId); 1315 } 1316 } 1317 else 1318 { 1319 level->playSound(from, eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); 1320 minecraft->particleEngine->add( shared_ptr<TakeAnimationParticle>( new TakeAnimationParticle(minecraft->level, from, to, -0.5f) ) ); 1321 level->removeEntity(packet->itemId); 1322 } 1323 } 1324 1325} 1326 1327void ClientConnection::handleChat(shared_ptr<ChatPacket> packet) 1328{ 1329 wstring message; 1330 int iPos; 1331 bool displayOnGui = true; 1332 1333 bool replacePlayer = false; 1334 bool replaceEntitySource = false; 1335 bool replaceItem = false; 1336 1337 wstring playerDisplayName = L""; 1338 wstring sourceDisplayName = L""; 1339 1340 // On platforms other than Xbox One this just sets display name to gamertag 1341 if (packet->m_stringArgs.size() >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]); 1342 if (packet->m_stringArgs.size() >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]); 1343 1344 switch(packet->m_messageType) 1345 { 1346 case ChatPacket::e_ChatBedOccupied: 1347 message = app.GetString(IDS_TILE_BED_OCCUPIED); 1348 break; 1349 case ChatPacket::e_ChatBedNoSleep: 1350 message = app.GetString(IDS_TILE_BED_NO_SLEEP); 1351 break; 1352 case ChatPacket::e_ChatBedNotValid: 1353 message = app.GetString(IDS_TILE_BED_NOT_VALID); 1354 break; 1355 case ChatPacket::e_ChatBedNotSafe: 1356 message = app.GetString(IDS_TILE_BED_NOTSAFE); 1357 break; 1358 case ChatPacket::e_ChatBedPlayerSleep: 1359 message=app.GetString(IDS_TILE_BED_PLAYERSLEEP); 1360 iPos=message.find(L"%s"); 1361 message.replace(iPos,2,playerDisplayName); 1362 break; 1363 case ChatPacket::e_ChatBedMeSleep: 1364 message=app.GetString(IDS_TILE_BED_MESLEEP); 1365 break; 1366 case ChatPacket::e_ChatPlayerJoinedGame: 1367 message=app.GetString(IDS_PLAYER_JOINED); 1368 iPos=message.find(L"%s"); 1369 message.replace(iPos,2,playerDisplayName); 1370 break; 1371 case ChatPacket::e_ChatPlayerLeftGame: 1372 message=app.GetString(IDS_PLAYER_LEFT); 1373 iPos=message.find(L"%s"); 1374 message.replace(iPos,2,playerDisplayName); 1375 break; 1376 case ChatPacket::e_ChatPlayerKickedFromGame: 1377 message=app.GetString(IDS_PLAYER_KICKED); 1378 iPos=message.find(L"%s"); 1379 message.replace(iPos,2,playerDisplayName); 1380 break; 1381 case ChatPacket::e_ChatCannotPlaceLava: 1382 displayOnGui = false; 1383 app.SetGlobalXuiAction(eAppAction_DisplayLavaMessage); 1384 break; 1385 case ChatPacket::e_ChatDeathInFire: 1386 message=app.GetString(IDS_DEATH_INFIRE); 1387 replacePlayer = true; 1388 break; 1389 case ChatPacket::e_ChatDeathOnFire: 1390 message=app.GetString(IDS_DEATH_ONFIRE); 1391 replacePlayer = true; 1392 break; 1393 case ChatPacket::e_ChatDeathLava: 1394 message=app.GetString(IDS_DEATH_LAVA); 1395 replacePlayer = true; 1396 break; 1397 case ChatPacket::e_ChatDeathInWall: 1398 message=app.GetString(IDS_DEATH_INWALL); 1399 replacePlayer = true; 1400 break; 1401 case ChatPacket::e_ChatDeathDrown: 1402 message=app.GetString(IDS_DEATH_DROWN); 1403 replacePlayer = true; 1404 break; 1405 case ChatPacket::e_ChatDeathStarve: 1406 message=app.GetString(IDS_DEATH_STARVE); 1407 replacePlayer = true; 1408 break; 1409 case ChatPacket::e_ChatDeathCactus: 1410 message=app.GetString(IDS_DEATH_CACTUS); 1411 replacePlayer = true; 1412 break; 1413 case ChatPacket::e_ChatDeathFall: 1414 message=app.GetString(IDS_DEATH_FALL); 1415 replacePlayer = true; 1416 break; 1417 case ChatPacket::e_ChatDeathOutOfWorld: 1418 message=app.GetString(IDS_DEATH_OUTOFWORLD); 1419 replacePlayer = true; 1420 break; 1421 case ChatPacket::e_ChatDeathGeneric: 1422 message=app.GetString(IDS_DEATH_GENERIC); 1423 replacePlayer = true; 1424 break; 1425 case ChatPacket::e_ChatDeathExplosion: 1426 message=app.GetString(IDS_DEATH_EXPLOSION); 1427 replacePlayer = true; 1428 break; 1429 case ChatPacket::e_ChatDeathMagic: 1430 message=app.GetString(IDS_DEATH_MAGIC); 1431 replacePlayer = true; 1432 break; 1433 case ChatPacket::e_ChatDeathAnvil: 1434 message=app.GetString(IDS_DEATH_FALLING_ANVIL); 1435 replacePlayer = true; 1436 break; 1437 case ChatPacket::e_ChatDeathFallingBlock: 1438 message=app.GetString(IDS_DEATH_FALLING_TILE); 1439 replacePlayer = true; 1440 break; 1441 case ChatPacket::e_ChatDeathDragonBreath: 1442 message=app.GetString(IDS_DEATH_DRAGON_BREATH); 1443 replacePlayer = true; 1444 break; 1445 case ChatPacket::e_ChatDeathMob: 1446 message=app.GetString(IDS_DEATH_MOB); 1447 replacePlayer = true; 1448 replaceEntitySource = true; 1449 break; 1450 case ChatPacket::e_ChatDeathPlayer: 1451 message=app.GetString(IDS_DEATH_PLAYER); 1452 replacePlayer = true; 1453 replaceEntitySource = true; 1454 break; 1455 case ChatPacket::e_ChatDeathArrow: 1456 message=app.GetString(IDS_DEATH_ARROW); 1457 replacePlayer = true; 1458 replaceEntitySource = true; 1459 break; 1460 case ChatPacket::e_ChatDeathFireball: 1461 message=app.GetString(IDS_DEATH_FIREBALL); 1462 replacePlayer = true; 1463 replaceEntitySource = true; 1464 break; 1465 case ChatPacket::e_ChatDeathThrown: 1466 message=app.GetString(IDS_DEATH_THROWN); 1467 replacePlayer = true; 1468 replaceEntitySource = true; 1469 break; 1470 case ChatPacket::e_ChatDeathIndirectMagic: 1471 message=app.GetString(IDS_DEATH_INDIRECT_MAGIC); 1472 replacePlayer = true; 1473 replaceEntitySource = true; 1474 break; 1475 case ChatPacket::e_ChatDeathThorns: 1476 message=app.GetString(IDS_DEATH_THORNS); 1477 replacePlayer = true; 1478 replaceEntitySource = true; 1479 break; 1480 1481 1482 case ChatPacket::e_ChatDeathFellAccidentLadder: 1483 message=app.GetString(IDS_DEATH_FELL_ACCIDENT_LADDER); 1484 replacePlayer = true; 1485 break; 1486 case ChatPacket::e_ChatDeathFellAccidentVines: 1487 message=app.GetString(IDS_DEATH_FELL_ACCIDENT_VINES); 1488 replacePlayer = true; 1489 break; 1490 case ChatPacket::e_ChatDeathFellAccidentWater: 1491 message=app.GetString(IDS_DEATH_FELL_ACCIDENT_WATER); 1492 replacePlayer = true; 1493 break; 1494 case ChatPacket::e_ChatDeathFellAccidentGeneric: 1495 message=app.GetString(IDS_DEATH_FELL_ACCIDENT_GENERIC); 1496 replacePlayer = true; 1497 break; 1498 case ChatPacket::e_ChatDeathFellKiller: 1499 //message=app.GetString(IDS_DEATH_FELL_KILLER); 1500 //replacePlayer = true; 1501 //replaceEntitySource = true; 1502 1503 // 4J Stu - The correct string for here, IDS_DEATH_FELL_KILLER is incorrect. We can't change localisation, so use a different string for now 1504 message=app.GetString(IDS_DEATH_FALL); 1505 replacePlayer = true; 1506 break; 1507 case ChatPacket::e_ChatDeathFellAssist: 1508 message=app.GetString(IDS_DEATH_FELL_ASSIST); 1509 replacePlayer = true; 1510 replaceEntitySource = true; 1511 break; 1512 case ChatPacket::e_ChatDeathFellAssistItem: 1513 message=app.GetString(IDS_DEATH_FELL_ASSIST_ITEM); 1514 replacePlayer = true; 1515 replaceEntitySource = true; 1516 replaceItem = true; 1517 break; 1518 case ChatPacket::e_ChatDeathFellFinish: 1519 message=app.GetString(IDS_DEATH_FELL_FINISH); 1520 replacePlayer = true; 1521 replaceEntitySource = true; 1522 break; 1523 case ChatPacket::e_ChatDeathFellFinishItem: 1524 message=app.GetString(IDS_DEATH_FELL_FINISH_ITEM); 1525 replacePlayer = true; 1526 replaceEntitySource = true; 1527 replaceItem = true; 1528 break; 1529 case ChatPacket::e_ChatDeathInFirePlayer: 1530 message=app.GetString(IDS_DEATH_INFIRE_PLAYER); 1531 replacePlayer = true; 1532 replaceEntitySource = true; 1533 break; 1534 case ChatPacket::e_ChatDeathOnFirePlayer: 1535 message=app.GetString(IDS_DEATH_ONFIRE_PLAYER); 1536 replacePlayer = true; 1537 replaceEntitySource = true; 1538 break; 1539 case ChatPacket::e_ChatDeathLavaPlayer: 1540 message=app.GetString(IDS_DEATH_LAVA_PLAYER); 1541 replacePlayer = true; 1542 replaceEntitySource = true; 1543 break; 1544 case ChatPacket::e_ChatDeathDrownPlayer: 1545 message=app.GetString(IDS_DEATH_DROWN_PLAYER); 1546 replacePlayer = true; 1547 replaceEntitySource = true; 1548 break; 1549 case ChatPacket::e_ChatDeathCactusPlayer: 1550 message=app.GetString(IDS_DEATH_CACTUS_PLAYER); 1551 replacePlayer = true; 1552 replaceEntitySource = true; 1553 break; 1554 case ChatPacket::e_ChatDeathExplosionPlayer: 1555 message=app.GetString(IDS_DEATH_EXPLOSION_PLAYER); 1556 replacePlayer = true; 1557 replaceEntitySource = true; 1558 break; 1559 case ChatPacket::e_ChatDeathWither: 1560 message=app.GetString(IDS_DEATH_WITHER); 1561 replacePlayer = true; 1562 break; 1563 case ChatPacket::e_ChatDeathPlayerItem: 1564 message=app.GetString(IDS_DEATH_PLAYER_ITEM); 1565 replacePlayer = true; 1566 replaceEntitySource = true; 1567 replaceItem = true; 1568 break; 1569 case ChatPacket::e_ChatDeathArrowItem: 1570 message=app.GetString(IDS_DEATH_ARROW_ITEM); 1571 replacePlayer = true; 1572 replaceEntitySource = true; 1573 replaceItem = true; 1574 break; 1575 case ChatPacket::e_ChatDeathFireballItem: 1576 message=app.GetString(IDS_DEATH_FIREBALL_ITEM); 1577 replacePlayer = true; 1578 replaceEntitySource = true; 1579 replaceItem = true; 1580 break; 1581 case ChatPacket::e_ChatDeathThrownItem: 1582 message=app.GetString(IDS_DEATH_THROWN_ITEM); 1583 replacePlayer = true; 1584 replaceEntitySource = true; 1585 replaceItem = true; 1586 break; 1587 case ChatPacket::e_ChatDeathIndirectMagicItem: 1588 message=app.GetString(IDS_DEATH_INDIRECT_MAGIC_ITEM); 1589 replacePlayer = true; 1590 replaceEntitySource = true; 1591 replaceItem = true; 1592 break; 1593 1594 case ChatPacket::e_ChatPlayerEnteredEnd: 1595 message=app.GetString(IDS_PLAYER_ENTERED_END); 1596 iPos=message.find(L"%s"); 1597 message.replace(iPos,2,playerDisplayName); 1598 break; 1599 case ChatPacket::e_ChatPlayerLeftEnd: 1600 message=app.GetString(IDS_PLAYER_LEFT_END); 1601 iPos=message.find(L"%s"); 1602 message.replace(iPos,2,playerDisplayName); 1603 break; 1604 1605 case ChatPacket::e_ChatPlayerMaxEnemies: 1606 message=app.GetString(IDS_MAX_ENEMIES_SPAWNED); 1607 break; 1608 // Spawn eggs 1609 case ChatPacket::e_ChatPlayerMaxVillagers: 1610 message=app.GetString(IDS_MAX_VILLAGERS_SPAWNED); 1611 break; 1612 case ChatPacket::e_ChatPlayerMaxPigsSheepCows: 1613 message=app.GetString(IDS_MAX_PIGS_SHEEP_COWS_CATS_SPAWNED); 1614 break; 1615 case ChatPacket::e_ChatPlayerMaxChickens: 1616 message=app.GetString(IDS_MAX_CHICKENS_SPAWNED); 1617 break; 1618 case ChatPacket::e_ChatPlayerMaxSquid: 1619 message=app.GetString(IDS_MAX_SQUID_SPAWNED); 1620 break; 1621 case ChatPacket::e_ChatPlayerMaxMooshrooms: 1622 message=app.GetString(IDS_MAX_MOOSHROOMS_SPAWNED); 1623 break; 1624 case ChatPacket::e_ChatPlayerMaxWolves: 1625 message=app.GetString(IDS_MAX_WOLVES_SPAWNED); 1626 break; 1627 case ChatPacket::e_ChatPlayerMaxBats: 1628 message=app.GetString(IDS_MAX_BATS_SPAWNED); 1629 break; 1630 1631 // Breeding 1632 case ChatPacket::e_ChatPlayerMaxBredPigsSheepCows: 1633 message=app.GetString(IDS_MAX_PIGS_SHEEP_COWS_CATS_BRED); 1634 break; 1635 case ChatPacket::e_ChatPlayerMaxBredChickens: 1636 message=app.GetString(IDS_MAX_CHICKENS_BRED); 1637 break; 1638 case ChatPacket::e_ChatPlayerMaxBredMooshrooms: 1639 message=app.GetString(IDS_MAX_MUSHROOMCOWS_BRED); 1640 break; 1641 1642 case ChatPacket::e_ChatPlayerMaxBredWolves: 1643 message=app.GetString(IDS_MAX_WOLVES_BRED); 1644 break; 1645 1646 // can't shear the mooshroom 1647 case ChatPacket::e_ChatPlayerCantShearMooshroom: 1648 message=app.GetString(IDS_CANT_SHEAR_MOOSHROOM); 1649 break; 1650 1651 // Paintings/Item Frames 1652 case ChatPacket::e_ChatPlayerMaxHangingEntities: 1653 message=app.GetString(IDS_MAX_HANGINGENTITIES); 1654 break; 1655 // Enemy spawn eggs in peaceful 1656 case ChatPacket::e_ChatPlayerCantSpawnInPeaceful: 1657 message=app.GetString(IDS_CANT_SPAWN_IN_PEACEFUL); 1658 break; 1659 1660 // Enemy spawn eggs in peaceful 1661 case ChatPacket::e_ChatPlayerMaxBoats: 1662 message=app.GetString(IDS_MAX_BOATS); 1663 break; 1664 1665 case ChatPacket::e_ChatCommandTeleportSuccess: 1666 message=app.GetString(IDS_COMMAND_TELEPORT_SUCCESS); 1667 replacePlayer = true; 1668 if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) 1669 { 1670 message = replaceAll(message,L"{*DESTINATION*}", sourceDisplayName); 1671 } 1672 else 1673 { 1674 message = replaceAll(message,L"{*DESTINATION*}", app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); 1675 } 1676 break; 1677 case ChatPacket::e_ChatCommandTeleportMe: 1678 message=app.GetString(IDS_COMMAND_TELEPORT_ME); 1679 replacePlayer = true; 1680 break; 1681 case ChatPacket::e_ChatCommandTeleportToMe: 1682 message=app.GetString(IDS_COMMAND_TELEPORT_TO_ME); 1683 replacePlayer = true; 1684 break; 1685 1686 default: 1687 message = playerDisplayName; 1688 break; 1689 } 1690 1691 1692 if(replacePlayer) 1693 { 1694 message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); 1695 } 1696 1697 if(replaceEntitySource) 1698 { 1699 if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) 1700 { 1701 message = replaceAll(message,L"{*SOURCE*}", sourceDisplayName); 1702 } 1703 else 1704 { 1705 wstring entityName; 1706 1707 // Check for a custom mob name 1708 if (packet->m_stringArgs.size() >= 2 && !packet->m_stringArgs[1].empty()) 1709 { 1710 entityName = packet->m_stringArgs[1]; 1711 } 1712 else 1713 { 1714 entityName = app.getEntityName((eINSTANCEOF) packet->m_intArgs[0]); 1715 } 1716 1717 message = replaceAll(message,L"{*SOURCE*}", entityName); 1718 } 1719 } 1720 1721 if (replaceItem) 1722 { 1723 message = replaceAll(message,L"{*ITEM*}", packet->m_stringArgs[2]); 1724 } 1725 1726 // flag that a message is a death message 1727 bool bIsDeathMessage = (packet->m_messageType>=ChatPacket::e_ChatDeathInFire) && (packet->m_messageType<=ChatPacket::e_ChatDeathIndirectMagicItem); 1728 1729 if( displayOnGui ) minecraft->gui->addMessage(message,m_userIndex, bIsDeathMessage); 1730} 1731 1732void ClientConnection::handleAnimate(shared_ptr<AnimatePacket> packet) 1733{ 1734 shared_ptr<Entity> e = getEntity(packet->id); 1735 if (e == NULL) return; 1736 if (packet->action == AnimatePacket::SWING) 1737 { 1738 if (e->instanceof(eTYPE_LIVINGENTITY)) dynamic_pointer_cast<LivingEntity>(e)->swing(); 1739 } 1740 else if (packet->action == AnimatePacket::HURT) 1741 { 1742 e->animateHurt(); 1743 } 1744 else if (packet->action == AnimatePacket::WAKE_UP) 1745 { 1746 if (e->instanceof(eTYPE_PLAYER)) dynamic_pointer_cast<Player>(e)->stopSleepInBed(false, false, false); 1747 } 1748 else if (packet->action == AnimatePacket::RESPAWN) 1749 { 1750 } 1751 else if (packet->action == AnimatePacket::CRITICAL_HIT) 1752 { 1753 shared_ptr<CritParticle> critParticle = shared_ptr<CritParticle>( new CritParticle(minecraft->level, e) ); 1754 critParticle->CritParticlePostConstructor(); 1755 minecraft->particleEngine->add( critParticle ); 1756 } 1757 else if (packet->action == AnimatePacket::MAGIC_CRITICAL_HIT) 1758 { 1759 shared_ptr<CritParticle> critParticle = shared_ptr<CritParticle>( new CritParticle(minecraft->level, e, eParticleType_magicCrit) ); 1760 critParticle->CritParticlePostConstructor(); 1761 minecraft->particleEngine->add(critParticle); 1762 } 1763 else if ( (packet->action == AnimatePacket::EAT) && e->instanceof(eTYPE_REMOTEPLAYER) ) 1764 { 1765 1766 } 1767} 1768 1769void ClientConnection::handleEntityActionAtPosition(shared_ptr<EntityActionAtPositionPacket> packet) 1770{ 1771 shared_ptr<Entity> e = getEntity(packet->id); 1772 if (e == NULL) return; 1773 if (packet->action == EntityActionAtPositionPacket::START_SLEEP) 1774 { 1775 shared_ptr<Player> player = dynamic_pointer_cast<Player>(e); 1776 player->startSleepInBed(packet->x, packet->y, packet->z); 1777 1778 if( player == minecraft->localplayers[m_userIndex] ) 1779 { 1780 TelemetryManager->RecordEnemyKilledOrOvercome(m_userIndex, 0, player->y, 0, 0, 0, 0, eTelemetryInGame_UseBed); 1781 } 1782 } 1783} 1784 1785void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet) 1786{ 1787// printf("Client: handlePreLogin\n"); 1788#if 1 1789 // 4J - Check that we can play with all the players already in the game who have Friends-Only UGC set 1790 BOOL canPlay = TRUE; 1791 BOOL canPlayLocal = TRUE; 1792 BOOL isAtLeastOneFriend = g_NetworkManager.IsHost(); 1793 BOOL isFriendsWithHost = TRUE; 1794 BOOL cantPlayContentRestricted = FALSE; 1795 1796 if(!g_NetworkManager.IsHost()) 1797 { 1798 // set the game host settings 1799 app.SetGameHostOption(eGameHostOption_All,packet->m_serverSettings); 1800 1801 // 4J-PB - if we go straight in from the menus via an invite, we won't have the DLC info 1802 if(app.GetTMSGlobalFileListRead()==false) 1803 { 1804 app.SetTMSAction(ProfileManager.GetPrimaryPad(),eTMSAction_TMSPP_RetrieveFiles_RunPlayGame); 1805 } 1806 } 1807 1808#ifdef _XBOX 1809 if(!g_NetworkManager.IsHost() && !app.GetGameHostOption(eGameHostOption_FriendsOfFriends)) 1810 { 1811 if(m_userIndex == ProfileManager.GetPrimaryPad() ) 1812 { 1813 for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx) 1814 { 1815 if(ProfileManager.IsSignedIn(m_userIndex) && ProfileManager.IsGuest(idx)) 1816 { 1817 canPlay = FALSE; 1818 isFriendsWithHost = FALSE; 1819 } 1820 else 1821 { 1822 PlayerUID playerXuid = INVALID_XUID; 1823 if( ProfileManager.IsSignedInLive(idx) ) 1824 { 1825 ProfileManager.GetXUID(idx,&playerXuid,true); 1826 } 1827 if( playerXuid != INVALID_XUID ) 1828 { 1829 // Is this user friends with the host player? 1830 BOOL result; 1831 DWORD error; 1832 error = XUserAreUsersFriends(idx,&packet->m_playerXuids[packet->m_hostIndex],1,&result,NULL); 1833 if(error == ERROR_SUCCESS && result != TRUE) 1834 { 1835 canPlay = FALSE; 1836 isFriendsWithHost = FALSE; 1837 } 1838 } 1839 } 1840 if(!canPlay) break; 1841 } 1842 } 1843 else 1844 { 1845 if(ProfileManager.IsSignedIn(m_userIndex) && ProfileManager.IsGuest(m_userIndex)) 1846 { 1847 canPlay = FALSE; 1848 isFriendsWithHost = FALSE; 1849 } 1850 else 1851 { 1852 PlayerUID playerXuid = INVALID_XUID; 1853 if( ProfileManager.IsSignedInLive(m_userIndex) ) 1854 { 1855 ProfileManager.GetXUID(m_userIndex,&playerXuid,true); 1856 } 1857 if( playerXuid != INVALID_XUID ) 1858 { 1859 // Is this user friends with the host player? 1860 BOOL result; 1861 DWORD error; 1862 error = XUserAreUsersFriends(m_userIndex,&packet->m_playerXuids[packet->m_hostIndex],1,&result,NULL); 1863 if(error == ERROR_SUCCESS && result != TRUE) 1864 { 1865 canPlay = FALSE; 1866 isFriendsWithHost = FALSE; 1867 } 1868 } 1869 } 1870 } 1871 } 1872 1873 if( canPlay ) 1874 { 1875 for(DWORD i = 0; i < packet->m_dwPlayerCount; ++i) 1876 { 1877 bool localPlayer = false; 1878 for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx) 1879 { 1880 if( ProfileManager.IsSignedInLive(idx) ) 1881 { 1882 // need to use the XUID here 1883 PlayerUID playerXUID = INVALID_XUID; 1884 if( !ProfileManager.IsGuest( idx ) ) 1885 { 1886 // Guest don't have an offline XUID as they cannot play offline, so use their online one 1887 ProfileManager.GetXUID(idx,&playerXUID,true); 1888 } 1889 if( ProfileManager.AreXUIDSEqual(playerXUID,packet->m_playerXuids[i]) ) localPlayer = true; 1890 } 1891 else if (ProfileManager.IsSignedIn(idx)) 1892 { 1893 // If we aren't signed into live then they have to be a local player 1894 localPlayer = true; 1895 } 1896 } 1897 if(!localPlayer) 1898 { 1899 // First check our own permissions to see if we can play with this player 1900 if(m_userIndex == ProfileManager.GetPrimaryPad() ) 1901 { 1902 canPlayLocal = ProfileManager.CanViewPlayerCreatedContent(m_userIndex,false,&packet->m_playerXuids[i],1); 1903 1904 // 4J Stu - Everyone joining needs to have at least one friend in the game 1905 // Local players are implied friends 1906 if( isAtLeastOneFriend != TRUE ) 1907 { 1908 BOOL result; 1909 DWORD error; 1910 for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx) 1911 { 1912 if( ProfileManager.IsSignedIn(idx) && !ProfileManager.IsGuest(idx) ) 1913 { 1914 error = XUserAreUsersFriends(idx,&packet->m_playerXuids[i],1,&result,NULL); 1915 if(error == ERROR_SUCCESS && result == TRUE) isAtLeastOneFriend = TRUE; 1916 } 1917 } 1918 } 1919 } 1920 else 1921 { 1922 // Friends with the primary player on this system 1923 isAtLeastOneFriend = true; 1924 1925 canPlayLocal = ProfileManager.CanViewPlayerCreatedContent(m_userIndex,true,&packet->m_playerXuids[i],1); 1926 } 1927 1928 // If we can play with them, then check if they can play with us 1929 if( canPlayLocal && ( packet->m_friendsOnlyBits & (1<<i) ) ) 1930 { 1931 // If this is the primary pad then check all local players against the list in the packet (this happens when joining the game for the first time) 1932 // If not the primary pad, then just check against this index. It happens on joining at the start, but more importantly players trying to join during the game 1933 bool thisQuadrantOnly = true; 1934 if( m_userIndex == ProfileManager.GetPrimaryPad() ) thisQuadrantOnly = false; 1935 1936 BOOL result; 1937 DWORD error; 1938 for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx) 1939 { 1940 if( (!thisQuadrantOnly || m_userIndex == idx) && ProfileManager.IsSignedIn(idx) && !ProfileManager.IsGuest(idx) ) 1941 { 1942 error = XUserAreUsersFriends(idx,&packet->m_playerXuids[i],1,&result,NULL); 1943 if(error == ERROR_SUCCESS) canPlay &= result; 1944 } 1945 if(!canPlay) break; 1946 } 1947 } 1948 if(!canPlay || !canPlayLocal) break; 1949 } 1950 } 1951 } 1952#else 1953 // TODO - handle this kind of things for non-360 platforms 1954 canPlay = TRUE; 1955 canPlayLocal = TRUE; 1956 isAtLeastOneFriend = TRUE; 1957 cantPlayContentRestricted= FALSE; 1958 1959#if ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__) 1960 1961 if(!g_NetworkManager.IsHost() && !app.GetGameHostOption(eGameHostOption_FriendsOfFriends)) 1962 { 1963 bool bChatRestricted=false; 1964 1965 ProfileManager.GetChatAndContentRestrictions(m_userIndex,true,&bChatRestricted,NULL,NULL); 1966 1967 // Chat restricted orbis players can still play online 1968#ifndef __ORBIS__ 1969 canPlay = !bChatRestricted; 1970#endif 1971 1972 if(m_userIndex == ProfileManager.GetPrimaryPad() ) 1973 { 1974 // Is this user friends with the host player? 1975 bool isFriend = true; 1976 unsigned int friendCount = 0; 1977#ifdef __PS3__ 1978 int ret = sceNpBasicGetFriendListEntryCount(&friendCount); 1979#elif defined __PSVITA__ 1980 sce::Toolkit::NP::Utilities::Future<sce::Toolkit::NP::FriendsList> friendList; 1981 int ret = -1; 1982 if(!CGameNetworkManager::usingAdhocMode()) // we don't need to be friends in PSN for adhoc mode 1983 { 1984 int ret = sce::Toolkit::NP::Friends::Interface::getFriendslist(&friendList, false); 1985 if(ret == SCE_TOOLKIT_NP_SUCCESS) 1986 { 1987 if( friendList.hasResult() ) 1988 { 1989 friendCount = friendList.get()->size(); 1990 } 1991 } 1992 } 1993#else // __ORBIS__ 1994 1995 sce::Toolkit::NP::Utilities::Future<sce::Toolkit::NP::FriendsList> friendList; 1996 1997 sce::Toolkit::NP::FriendInfoRequest requestParam; 1998 memset(&requestParam,0,sizeof(requestParam)); 1999 requestParam.flag = SCE_TOOLKIT_NP_FRIENDS_LIST_ALL; 2000 requestParam.limit = 0; 2001 requestParam.offset = 0; 2002 requestParam.userInfo.userId = ProfileManager.getUserID(ProfileManager.GetPrimaryPad()); 2003 2004 int ret = sce::Toolkit::NP::Friends::Interface::getFriendslist(&friendList, &requestParam, false); 2005 if( ret == 0 ) 2006 { 2007 if( friendList.hasResult() ) 2008 { 2009 friendCount = friendList.get()->size(); 2010 } 2011 } 2012#endif 2013 if( ret == 0 ) 2014 { 2015 isFriend = false; 2016 SceNpId npid; 2017 for( unsigned int i = 0; i < friendCount; i++ ) 2018 { 2019#ifdef __PS3__ 2020 ret = sceNpBasicGetFriendListEntry( i, &npid ); 2021#else 2022 npid = friendList.get()->at(i).npid; 2023#endif 2024 if( ret == 0 ) 2025 { 2026 if(strcmp(npid.handle.data, packet->m_playerXuids[packet->m_hostIndex].getOnlineID()) == 0) 2027 { 2028 isFriend = true; 2029 break; 2030 } 2031 } 2032 } 2033 } 2034 2035 if( !isFriend ) 2036 { 2037 canPlay = FALSE; 2038 isFriendsWithHost = FALSE; 2039 } 2040 } 2041 } 2042 // is it an online game, and a player has chat restricted? 2043 else if(!g_NetworkManager.IsLocalGame()) 2044 { 2045 // if the player is chat restricted, then they can't play an online game 2046 bool bChatRestricted=false; 2047 bool bContentRestricted=false; 2048 2049 // If this is a pre-login packet for the first player on the machine, then accumulate up these flags for everyone signed in. We can handle exiting the game 2050 // much more cleanly at this point by exiting the level, rather than waiting for a prelogin packet for the other players, when we have to exit the player 2051 // which seems to be very unstable at the point of starting up the game 2052 if(m_userIndex == ProfileManager.GetPrimaryPad()) 2053 { 2054 ProfileManager.GetChatAndContentRestrictions(m_userIndex,false,&bChatRestricted,&bContentRestricted,NULL); 2055 } 2056 else 2057 { 2058 ProfileManager.GetChatAndContentRestrictions(m_userIndex,true,&bChatRestricted,&bContentRestricted,NULL); 2059 } 2060 2061 // Chat restricted orbis players can still play online 2062#ifndef __ORBIS__ 2063 canPlayLocal = !bChatRestricted; 2064#endif 2065 2066 cantPlayContentRestricted = bContentRestricted ? 1 : 0; 2067 } 2068 2069 2070#endif 2071 2072#ifdef _XBOX_ONE 2073 if(!g_NetworkManager.IsHost() && m_userIndex == ProfileManager.GetPrimaryPad()) 2074 { 2075 long long startTime = System::currentTimeMillis(); 2076 2077 auto friendsXuids = DQRNetworkManager::GetFriends(); 2078 2079 if (app.GetGameHostOption(eGameHostOption_FriendsOfFriends)) 2080 { 2081 // Check that the user has at least one friend in the game 2082 isAtLeastOneFriend = false; 2083 2084 for (int i = 0; i < friendsXuids->Size; i++) 2085 { 2086 auto friendsXuid = friendsXuids->GetAt(i); 2087 2088 // Check this friend against each player, if we find them we have at least one friend 2089 for (int j = 0; j < g_NetworkManager.GetPlayerCount(); j++) 2090 { 2091 Platform::String^ xboxUserId = ref new Platform::String(g_NetworkManager.GetPlayerByIndex(j)->GetUID().toString().data()); 2092 if (friendsXuid == xboxUserId) 2093 { 2094 isAtLeastOneFriend = true; 2095 break; 2096 } 2097 } 2098 } 2099 2100 app.DebugPrintf("ClientConnection::handlePreLogin: User has at least one friend? %s\n", isAtLeastOneFriend ? "Yes" : "No"); 2101 } 2102 else 2103 { 2104 // Check that the user is friends with the host 2105 bool isFriend = false; 2106 2107 Platform::String^ hostXboxUserId = ref new Platform::String(g_NetworkManager.GetHostPlayer()->GetUID().toString().data()); 2108 2109 for (int i = 0; i < friendsXuids->Size; i++) 2110 { 2111 if (friendsXuids->GetAt(i) == hostXboxUserId) 2112 { 2113 isFriend = true; 2114 break; 2115 } 2116 } 2117 2118 if( !isFriend ) 2119 { 2120 canPlay = FALSE; 2121 isFriendsWithHost = FALSE; 2122 } 2123 2124 app.DebugPrintf("ClientConnection::handlePreLogin: User is friends with the host? %s\n", isFriendsWithHost ? "Yes" : "No"); 2125 } 2126 2127 app.DebugPrintf("ClientConnection::handlePreLogin: Friendship checks took %i ms\n", System::currentTimeMillis() - startTime); 2128 } 2129#endif 2130 2131#endif // _XBOX 2132 2133 if(!canPlay || !canPlayLocal || !isAtLeastOneFriend || cantPlayContentRestricted) 2134 { 2135#ifndef __PS3__ 2136 DisconnectPacket::eDisconnectReason reason = DisconnectPacket::eDisconnect_NoUGC_Remote; 2137#else 2138 DisconnectPacket::eDisconnectReason reason = DisconnectPacket::eDisconnect_None; 2139#endif 2140 if(m_userIndex == ProfileManager.GetPrimaryPad()) 2141 { 2142 if(!isFriendsWithHost) reason = DisconnectPacket::eDisconnect_NotFriendsWithHost; 2143 else if(!isAtLeastOneFriend) reason = DisconnectPacket::eDisconnect_NoFriendsInGame; 2144 else if(!canPlayLocal) reason = DisconnectPacket::eDisconnect_NoUGC_AllLocal; 2145 else if(cantPlayContentRestricted) reason = DisconnectPacket::eDisconnect_ContentRestricted_AllLocal; 2146 2147 app.DebugPrintf("Exiting world on handling Pre-Login packet due UGC privileges: %d\n", reason); 2148 app.SetDisconnectReason( reason ); 2149 app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitWorld,(void *)TRUE); 2150 } 2151 else 2152 { 2153 if(!isFriendsWithHost) reason = DisconnectPacket::eDisconnect_NotFriendsWithHost; 2154 else if(!canPlayLocal) reason = DisconnectPacket::eDisconnect_NoUGC_Single_Local; 2155 else if(cantPlayContentRestricted) reason = DisconnectPacket::eDisconnect_ContentRestricted_Single_Local; 2156 2157 app.DebugPrintf("Exiting player %d on handling Pre-Login packet due UGC privileges: %d\n", m_userIndex, reason); 2158 UINT uiIDA[1]; 2159 uiIDA[0]=IDS_CONFIRM_OK; 2160 if(!isFriendsWithHost) ui.RequestErrorMessage( IDS_CANTJOIN_TITLE, IDS_NOTALLOWED_FRIENDSOFFRIENDS, uiIDA,1,m_userIndex); 2161 else ui.RequestErrorMessage( IDS_CANTJOIN_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL, uiIDA,1,m_userIndex); 2162 2163 app.SetDisconnectReason( reason ); 2164 2165 // 4J-PB - this locks up on the read and write threads not closing down, because they are trying to lock the incoming critsec when it's already locked by this thread 2166// Minecraft::GetInstance()->connectionDisconnected( m_userIndex , reason ); 2167// done = true; 2168// connection->flush(); 2169// connection->close(reason); 2170// app.SetAction(m_userIndex,eAppAction_ExitPlayer); 2171 2172 // 4J-PB - doing this instead 2173 app.SetAction(m_userIndex,eAppAction_ExitPlayerPreLogin); 2174 } 2175 } 2176 else 2177 { 2178 // Texture pack handling 2179 // If we have the texture pack for the game, load it 2180 // If we don't then send a packet to the host to request it. We need to send this before the LoginPacket so that it gets handled first, 2181 // as once the LoginPacket is received on the client the game is close to starting 2182 if(m_userIndex == ProfileManager.GetPrimaryPad()) 2183 { 2184 Minecraft *pMinecraft = Minecraft::GetInstance(); 2185 if( pMinecraft->skins->selectTexturePackById(packet->m_texturePackId) ) 2186 { 2187 app.DebugPrintf("Selected texture pack %d from Pre-Login packet\n", packet->m_texturePackId); 2188 } 2189 else 2190 { 2191 app.DebugPrintf("Could not select texture pack %d from Pre-Login packet, requesting from host\n", packet->m_texturePackId); 2192 2193 // 4J-PB - we need to upsell the texture pack to the player 2194#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ 2195 app.SetAction(m_userIndex,eAppAction_TexturePackRequired); 2196#endif 2197 // Let the player go into the game, and we'll check that they are using the right texture pack when in 2198 } 2199 } 2200 2201 if(!g_NetworkManager.IsHost() ) 2202 { 2203 Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCPreLoginReceived * 100)/ (eCCConnected)); 2204 } 2205 // need to use the XUID here 2206 PlayerUID offlineXUID = INVALID_XUID; 2207 PlayerUID onlineXUID = INVALID_XUID; 2208 if( ProfileManager.IsSignedInLive(m_userIndex) ) 2209 { 2210 // Guest don't have an offline XUID as they cannot play offline, so use their online one 2211 ProfileManager.GetXUID(m_userIndex,&onlineXUID,true); 2212 } 2213#ifdef __PSVITA__ 2214 if(CGameNetworkManager::usingAdhocMode() && onlineXUID.getOnlineID()[0] == 0) 2215 { 2216 // player doesn't have an online UID, set it from the player name 2217 onlineXUID.setForAdhoc(); 2218 } 2219#endif 2220 2221 // On PS3, all non-signed in players (even guests) can get a useful offlineXUID 2222#if !(defined __PS3__ || defined _DURANGO ) 2223 if( !ProfileManager.IsGuest( m_userIndex ) ) 2224#endif 2225 { 2226 // All other players we use their offline XUID so that they can play the game offline 2227 ProfileManager.GetXUID(m_userIndex,&offlineXUID,false); 2228 } 2229 BOOL allAllowed, friendsAllowed; 2230 ProfileManager.AllowedPlayerCreatedContent(m_userIndex,true,&allAllowed,&friendsAllowed); 2231 send( shared_ptr<LoginPacket>( new LoginPacket(minecraft->user->name, SharedConstants::NETWORK_PROTOCOL_VERSION, offlineXUID, onlineXUID, (allAllowed!=TRUE && friendsAllowed==TRUE), 2232 packet->m_ugcPlayersVersion, app.GetPlayerSkinId(m_userIndex), app.GetPlayerCapeId(m_userIndex), ProfileManager.IsGuest( m_userIndex )))); 2233 2234 if(!g_NetworkManager.IsHost() ) 2235 { 2236 Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCLoginSent * 100)/ (eCCConnected)); 2237 } 2238 } 2239#else 2240 // 4J - removed 2241 if (packet->loginKey.equals("-")) { 2242 send(new LoginPacket(minecraft->user.name, SharedConstants.NETWORK_PROTOCOL_VERSION)); 2243 } else { 2244 try { 2245 URL url = new URL("http://www.minecraft->net/game/joinserver.jsp?user=" + minecraft->user.name + "&sessionId=" + minecraft->user.sessionId + "&serverId=" + packet->loginKey); 2246 BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream())); 2247 String msg = br.readLine(); 2248 br.close(); 2249 2250 if (msg.equalsIgnoreCase("ok")) { 2251 send(new LoginPacket(minecraft->user.name, SharedConstants.NETWORK_PROTOCOL_VERSION)); 2252 } else { 2253 connection.close("disconnect.loginFailedInfo", msg); 2254 } 2255 } catch (Exception e) { 2256 e.printStackTrace(); 2257 connection.close("disconnect.genericReason", "Internal client error: " + e.toString()); 2258 } 2259 } 2260#endif 2261} 2262 2263void ClientConnection::close() 2264{ 2265 // 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 2266 if(done) return; 2267 done = true; 2268 connection->flush(); 2269 connection->close(DisconnectPacket::eDisconnect_Closed); 2270} 2271 2272void ClientConnection::handleAddMob(shared_ptr<AddMobPacket> packet) 2273{ 2274 double x = packet->x / 32.0; 2275 double y = packet->y / 32.0; 2276 double z = packet->z / 32.0; 2277 float yRot = packet->yRot * 360 / 256.0f; 2278 float xRot = packet->xRot * 360 / 256.0f; 2279 2280 shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(EntityIO::newById(packet->type, level)); 2281 mob->xp = packet->x; 2282 mob->yp = packet->y; 2283 mob->zp = packet->z; 2284 mob->yHeadRot = packet->yHeadRot * 360 / 256.0f; 2285 mob->yRotp = packet->yRot; 2286 mob->xRotp = packet->xRot; 2287 2288 vector<shared_ptr<Entity> > *subEntities = mob->getSubEntities(); 2289 if (subEntities != NULL) 2290 { 2291 int offs = packet->id - mob->entityId; 2292 //for (int i = 0; i < subEntities.length; i++) 2293 for(AUTO_VAR(it, subEntities->begin()); it != subEntities->end(); ++it) 2294 { 2295 //subEntities[i].entityId += offs; 2296 (*it)->entityId += offs; 2297 } 2298 } 2299 2300 mob->entityId = packet->id; 2301 2302// printf("\t\t\t\t%d: Add mob rot %d\n",packet->id,packet->yRot); 2303 2304 mob->absMoveTo(x, y, z, yRot, xRot); 2305 mob->xd = packet->xd / 8000.0f; 2306 mob->yd = packet->yd / 8000.0f; 2307 mob->zd = packet->zd / 8000.0f; 2308 level->putEntity(packet->id, mob); 2309 2310 vector<shared_ptr<SynchedEntityData::DataItem> > *unpackedData = packet->getUnpackedData(); 2311 if (unpackedData != NULL) 2312 { 2313 mob->getEntityData()->assignValues(unpackedData); 2314 } 2315 2316 // Fix for #65236 - TU8: Content: Gameplay: Magma Cubes' have strange hit boxes. 2317 // 4J Stu - Slimes have a different BB depending on their size which is set in the entity data, so update the BB 2318 if(mob->GetType() == eTYPE_SLIME || mob->GetType() == eTYPE_LAVASLIME) 2319 { 2320 shared_ptr<Slime> slime = dynamic_pointer_cast<Slime>(mob); 2321 slime->setSize( slime->getSize() ); 2322 } 2323} 2324 2325void ClientConnection::handleSetTime(shared_ptr<SetTimePacket> packet) 2326{ 2327 minecraft->level->setGameTime(packet->gameTime); 2328 minecraft->level->setDayTime(packet->dayTime); 2329} 2330 2331void ClientConnection::handleSetSpawn(shared_ptr<SetSpawnPositionPacket> packet) 2332{ 2333 //minecraft->player->setRespawnPosition(new Pos(packet->x, packet->y, packet->z)); 2334 minecraft->localplayers[m_userIndex]->setRespawnPosition(new Pos(packet->x, packet->y, packet->z), true); 2335 minecraft->level->getLevelData()->setSpawn(packet->x, packet->y, packet->z); 2336 2337} 2338 2339void ClientConnection::handleEntityLinkPacket(shared_ptr<SetEntityLinkPacket> packet) 2340{ 2341 shared_ptr<Entity> sourceEntity = getEntity(packet->sourceId); 2342 shared_ptr<Entity> destEntity = getEntity(packet->destId); 2343 2344 // 4J: If the destination entity couldn't be found, defer handling of this packet 2345 // This was added to support leashing (the entity link packet is sent before the add entity packet) 2346 if (destEntity == NULL && packet->destId >= 0) 2347 { 2348 // We don't handle missing source entities because it shouldn't happen 2349 assert(!(sourceEntity == NULL && packet->sourceId >= 0)); 2350 2351 deferredEntityLinkPackets.push_back(DeferredEntityLinkPacket(packet)); 2352 return; 2353 } 2354 2355 if (packet->type == SetEntityLinkPacket::RIDING) 2356 { 2357 bool displayMountMessage = false; 2358 if (packet->sourceId == Minecraft::GetInstance()->localplayers[m_userIndex].get()->entityId) 2359 { 2360 sourceEntity = Minecraft::GetInstance()->localplayers[m_userIndex]; 2361 2362 if (destEntity != NULL && destEntity->instanceof(eTYPE_BOAT)) (dynamic_pointer_cast<Boat>(destEntity))->setDoLerp(false); 2363 2364 displayMountMessage = (sourceEntity->riding == NULL && destEntity != NULL); 2365 } 2366 else if (destEntity != NULL && destEntity->instanceof(eTYPE_BOAT)) 2367 { 2368 (dynamic_pointer_cast<Boat>(destEntity))->setDoLerp(true); 2369 } 2370 2371 if (sourceEntity == NULL) return; 2372 2373 sourceEntity->ride(destEntity); 2374 2375 // 4J TODO: pretty sure this message is a tooltip so not needed 2376 /* 2377 if (displayMountMessage) { 2378 Options options = minecraft.options; 2379 minecraft.gui.setOverlayMessage(I18n.get("mount.onboard", Options.getTranslatedKeyMessage(options.keySneak.key)), false); 2380 } 2381 */ 2382 } 2383 else if (packet->type == SetEntityLinkPacket::LEASH) 2384 { 2385 if ( (sourceEntity != NULL) && sourceEntity->instanceof(eTYPE_MOB) ) 2386 { 2387 if (destEntity != NULL) 2388 { 2389 2390 (dynamic_pointer_cast<Mob>(sourceEntity))->setLeashedTo(destEntity, false); 2391 } 2392 else 2393 { 2394 (dynamic_pointer_cast<Mob>(sourceEntity))->dropLeash(false, false); 2395 } 2396 } 2397 } 2398} 2399 2400void ClientConnection::handleEntityEvent(shared_ptr<EntityEventPacket> packet) 2401{ 2402 shared_ptr<Entity> e = getEntity(packet->entityId); 2403 if (e != NULL) e->handleEntityEvent(packet->eventId); 2404} 2405 2406shared_ptr<Entity> ClientConnection::getEntity(int entityId) 2407{ 2408 //if (entityId == minecraft->player->entityId) 2409 if(entityId == minecraft->localplayers[m_userIndex]->entityId) 2410 { 2411 //return minecraft->player; 2412 return minecraft->localplayers[m_userIndex]; 2413 } 2414 return level->getEntity(entityId); 2415} 2416 2417void ClientConnection::handleSetHealth(shared_ptr<SetHealthPacket> packet) 2418{ 2419 //minecraft->player->hurtTo(packet->health); 2420 minecraft->localplayers[m_userIndex]->hurtTo(packet->health,packet->damageSource); 2421 minecraft->localplayers[m_userIndex]->getFoodData()->setFoodLevel(packet->food); 2422 minecraft->localplayers[m_userIndex]->getFoodData()->setSaturation(packet->saturation); 2423 2424 // We need food 2425 if(packet->food < FoodConstants::HEAL_LEVEL - 1) 2426 { 2427 if(minecraft->localgameModes[m_userIndex] != NULL && !minecraft->localgameModes[m_userIndex]->hasInfiniteItems() ) 2428 { 2429 minecraft->localgameModes[m_userIndex]->getTutorial()->changeTutorialState(e_Tutorial_State_Food_Bar); 2430 } 2431 } 2432} 2433 2434void ClientConnection::handleSetExperience(shared_ptr<SetExperiencePacket> packet) 2435{ 2436 minecraft->localplayers[m_userIndex]->setExperienceValues(packet->experienceProgress, packet->totalExperience, packet->experienceLevel); 2437} 2438 2439void ClientConnection::handleTexture(shared_ptr<TexturePacket> packet) 2440{ 2441 // Both PlayerConnection and ClientConnection should handle this mostly the same way 2442 // Server side also needs to store a list of those clients waiting to get a texture the server doesn't have yet 2443 // so that it can send it out to them when it comes in 2444 2445 if(packet->dwBytes==0) 2446 { 2447 // Request for texture 2448#ifndef _CONTENT_PACKAGE 2449 wprintf(L"Client received request for custom texture %ls\n",packet->textureName.c_str()); 2450#endif 2451 PBYTE pbData=NULL; 2452 DWORD dwBytes=0; 2453 app.GetMemFileDetails(packet->textureName,&pbData,&dwBytes); 2454 2455 if(dwBytes!=0) 2456 { 2457 send( shared_ptr<TexturePacket>( new TexturePacket(packet->textureName,pbData,dwBytes) ) ); 2458 } 2459 } 2460 else 2461 { 2462 // Response with texture data 2463#ifndef _CONTENT_PACKAGE 2464 wprintf(L"Client received custom texture %ls\n",packet->textureName.c_str()); 2465#endif 2466 app.AddMemoryTextureFile(packet->textureName,packet->pbData,packet->dwBytes); 2467 Minecraft::GetInstance()->handleClientTextureReceived(packet->textureName); 2468 } 2469} 2470 2471void ClientConnection::handleTextureAndGeometry(shared_ptr<TextureAndGeometryPacket> packet) 2472{ 2473 // Both PlayerConnection and ClientConnection should handle this mostly the same way 2474 // Server side also needs to store a list of those clients waiting to get a texture the server doesn't have yet 2475 // so that it can send it out to them when it comes in 2476 2477 if(packet->dwTextureBytes==0) 2478 { 2479 // Request for texture 2480#ifndef _CONTENT_PACKAGE 2481 wprintf(L"Client received request for custom texture and geometry %ls\n",packet->textureName.c_str()); 2482#endif 2483 PBYTE pbData=NULL; 2484 DWORD dwBytes=0; 2485 app.GetMemFileDetails(packet->textureName,&pbData,&dwBytes); 2486 DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(packet->textureName); 2487 2488 if(dwBytes!=0) 2489 { 2490 if(pDLCSkinFile) 2491 { 2492 if(pDLCSkinFile->getAdditionalBoxesCount()!=0) 2493 { 2494 send( shared_ptr<TextureAndGeometryPacket>( new TextureAndGeometryPacket(packet->textureName,pbData,dwBytes,pDLCSkinFile) ) ); 2495 } 2496 else 2497 { 2498 send( shared_ptr<TextureAndGeometryPacket>( new TextureAndGeometryPacket(packet->textureName,pbData,dwBytes) ) ); 2499 } 2500 } 2501 else 2502 { 2503 unsigned int uiAnimOverrideBitmask= app.GetAnimOverrideBitmask(packet->dwSkinID); 2504 2505 send( shared_ptr<TextureAndGeometryPacket>( new TextureAndGeometryPacket(packet->textureName,pbData,dwBytes,app.GetAdditionalSkinBoxes(packet->dwSkinID),uiAnimOverrideBitmask) ) ); 2506 } 2507 } 2508 } 2509 else 2510 { 2511 // Response with texture data 2512#ifndef _CONTENT_PACKAGE 2513 wprintf(L"Client received custom TextureAndGeometry %ls\n",packet->textureName.c_str()); 2514#endif 2515 // Add the texture data 2516 app.AddMemoryTextureFile(packet->textureName,packet->pbData,packet->dwTextureBytes); 2517 // Add the geometry data 2518 if(packet->dwBoxC!=0) 2519 { 2520 app.SetAdditionalSkinBoxes(packet->dwSkinID,packet->BoxDataA,packet->dwBoxC); 2521 } 2522 // Add the anim override 2523 app.SetAnimOverrideBitmask(packet->dwSkinID,packet->uiAnimOverrideBitmask); 2524 2525 // clear out the pending texture request 2526 Minecraft::GetInstance()->handleClientTextureReceived(packet->textureName); 2527 } 2528} 2529 2530void ClientConnection::handleTextureChange(shared_ptr<TextureChangePacket> packet) 2531{ 2532 shared_ptr<Entity> e = getEntity(packet->id); 2533 if ( (e == NULL) || !e->instanceof(eTYPE_PLAYER) ) return; 2534 shared_ptr<Player> player = dynamic_pointer_cast<Player>(e); 2535 2536 bool isLocalPlayer = false; 2537 for( int i = 0; i < XUSER_MAX_COUNT; i++ ) 2538 { 2539 if( minecraft->localplayers[i] ) 2540 { 2541 if( minecraft->localplayers[i]->entityId == packet->id ) 2542 { 2543 isLocalPlayer = true; 2544 break; 2545 } 2546 } 2547 } 2548 if(isLocalPlayer) return; 2549 2550 switch(packet->action) 2551 { 2552 case TextureChangePacket::e_TextureChange_Skin: 2553 player->setCustomSkin( app.getSkinIdFromPath( packet->path ) ); 2554#ifndef _CONTENT_PACKAGE 2555 wprintf(L"Skin for remote player %ls has changed to %ls (%d)\n", player->name.c_str(), player->customTextureUrl.c_str(), player->getPlayerDefaultSkin() ); 2556#endif 2557 break; 2558 case TextureChangePacket::e_TextureChange_Cape: 2559 player->setCustomCape( Player::getCapeIdFromPath( packet->path ) ); 2560 //player->customTextureUrl2 = packet->path; 2561#ifndef _CONTENT_PACKAGE 2562 wprintf(L"Cape for remote player %ls has changed to %ls\n", player->name.c_str(), player->customTextureUrl2.c_str() ); 2563#endif 2564 break; 2565 } 2566 2567 if(!packet->path.empty() && packet->path.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(packet->path)) 2568 { 2569 if( minecraft->addPendingClientTextureRequest(packet->path) ) 2570 { 2571#ifndef _CONTENT_PACKAGE 2572 wprintf(L"handleTextureChange - Client sending texture packet to get custom skin %ls for player %ls\n",packet->path.c_str(), player->name.c_str()); 2573#endif 2574 send(shared_ptr<TexturePacket>( new TexturePacket(packet->path,NULL,0) ) ); 2575 } 2576 } 2577 else if(!packet->path.empty() && app.IsFileInMemoryTextures(packet->path)) 2578 { 2579 // Update the ref count on the memory texture data 2580 app.AddMemoryTextureFile(packet->path,NULL,0); 2581 } 2582} 2583 2584void ClientConnection::handleTextureAndGeometryChange(shared_ptr<TextureAndGeometryChangePacket> packet) 2585{ 2586 shared_ptr<Entity> e = getEntity(packet->id); 2587 if (e == NULL) return; 2588 shared_ptr<Player> player = dynamic_pointer_cast<Player>(e); 2589 if( e == NULL) return; 2590 2591 bool isLocalPlayer = false; 2592 for( int i = 0; i < XUSER_MAX_COUNT; i++ ) 2593 { 2594 if( minecraft->localplayers[i] ) 2595 { 2596 if( minecraft->localplayers[i]->entityId == packet->id ) 2597 { 2598 isLocalPlayer = true; 2599 break; 2600 } 2601 } 2602 } 2603 if(isLocalPlayer) return; 2604 2605 2606 player->setCustomSkin( app.getSkinIdFromPath( packet->path ) ); 2607 2608#ifndef _CONTENT_PACKAGE 2609 wprintf(L"Skin for remote player %ls has changed to %ls (%d)\n", player->name.c_str(), player->customTextureUrl.c_str(), player->getPlayerDefaultSkin() ); 2610#endif 2611 2612 if(!packet->path.empty() && packet->path.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(packet->path)) 2613 { 2614 if( minecraft->addPendingClientTextureRequest(packet->path) ) 2615 { 2616#ifndef _CONTENT_PACKAGE 2617 wprintf(L"handleTextureAndGeometryChange - Client sending TextureAndGeometryPacket to get custom skin %ls for player %ls\n",packet->path.c_str(), player->name.c_str()); 2618#endif 2619 send(shared_ptr<TextureAndGeometryPacket>( new TextureAndGeometryPacket(packet->path,NULL,0) ) ); 2620 } 2621 } 2622 else if(!packet->path.empty() && app.IsFileInMemoryTextures(packet->path)) 2623 { 2624 // Update the ref count on the memory texture data 2625 app.AddMemoryTextureFile(packet->path,NULL,0); 2626 2627 } 2628} 2629 2630void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet) 2631{ 2632 //if (packet->dimension != minecraft->player->dimension) 2633 if( packet->dimension != minecraft->localplayers[m_userIndex]->dimension || packet->mapSeed != minecraft->localplayers[m_userIndex]->level->getSeed() ) 2634 { 2635 int oldDimension = minecraft->localplayers[m_userIndex]->dimension; 2636 started = false; 2637 2638 // Remove client connection from this level 2639 level->removeClientConnection(this, false); 2640 2641 MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->getLevel( packet->dimension ); 2642 if( dimensionLevel == NULL ) 2643 { 2644 dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->mapSeed, packet->playerGameType, false, minecraft->level->getLevelData()->isHardcore(), packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty); 2645 2646 // 4J Stu - We want to shared the savedDataStorage between both levels 2647 //if( dimensionLevel->savedDataStorage != NULL ) 2648 //{ 2649 // Don't need to delete it here as it belongs to a client connection while will delete it when it's done 2650 // delete dimensionLevel->savedDataStorage;+ 2651 //} 2652 dimensionLevel->savedDataStorage = level->savedDataStorage; 2653 2654 dimensionLevel->difficulty = packet->difficulty; // 4J Added 2655 app.DebugPrintf("dimensionLevel->difficulty - Difficulty = %d\n",packet->difficulty); 2656 2657 dimensionLevel->isClientSide = true; 2658 } 2659 else 2660 { 2661 dimensionLevel->addClientConnection(this); 2662 } 2663 2664 // Remove the player entity from the current level 2665 level->removeEntity( shared_ptr<Entity>(minecraft->localplayers[m_userIndex]) ); 2666 2667 level = dimensionLevel; 2668 2669 // Whilst calling setLevel, make sure that minecraft::player is set up to be correct for this 2670 // connection 2671 shared_ptr<MultiplayerLocalPlayer> lastPlayer = minecraft->player; 2672 minecraft->player = minecraft->localplayers[m_userIndex]; 2673 minecraft->setLevel(dimensionLevel); 2674 minecraft->player = lastPlayer; 2675 2676 TelemetryManager->RecordLevelExit(m_userIndex, eSen_LevelExitStatus_Succeeded); 2677 2678 //minecraft->player->dimension = packet->dimension; 2679 minecraft->localplayers[m_userIndex]->dimension = packet->dimension; 2680 //minecraft->setScreen(new ReceivingLevelScreen(this)); 2681// minecraft->addPendingLocalConnection(m_userIndex, this); 2682 2683#ifdef _XBOX 2684 TelemetryManager->RecordLevelStart(m_userIndex, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, Minecraft::GetInstance()->getLevel(packet->dimension)->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount()); 2685#endif 2686 2687 if( minecraft->localgameModes[m_userIndex] != NULL ) 2688 { 2689 TutorialMode *gameMode = (TutorialMode *)minecraft->localgameModes[m_userIndex]; 2690 gameMode->getTutorial()->showTutorialPopup(false); 2691 } 2692 2693 // 4J-JEV: Fix for Durango #156334 - Content: UI: Rich Presence 'In the Nether' message is updating with a 3 to 10 minute delay. 2694 minecraft->localplayers[m_userIndex]->updateRichPresence(); 2695 2696 ConnectionProgressParams *param = new ConnectionProgressParams(); 2697 param->iPad = m_userIndex; 2698 if( packet->dimension == -1) 2699 { 2700 param->stringId = IDS_PROGRESS_ENTERING_NETHER; 2701 } 2702 else if( oldDimension == -1) 2703 { 2704 param->stringId = IDS_PROGRESS_LEAVING_NETHER; 2705 } 2706 else if( packet->dimension == 1) 2707 { 2708 param->stringId = IDS_PROGRESS_ENTERING_END; 2709 } 2710 else if( oldDimension == 1) 2711 { 2712 param->stringId = IDS_PROGRESS_LEAVING_END; 2713 } 2714 param->showTooltips = false; 2715 param->setFailTimer = false; 2716 2717 // 4J Stu - Fix for #13543 - Crash: Game crashes if entering a portal with the inventory menu open 2718 ui.CloseUIScenes( m_userIndex ); 2719 2720 if(app.GetLocalPlayerCount()>1) 2721 { 2722 ui.NavigateToScene(m_userIndex, eUIScene_ConnectingProgress, param); 2723 } 2724 else 2725 { 2726 ui.NavigateToScene(m_userIndex, eUIScene_ConnectingProgress, param); 2727 } 2728 2729 app.SetAction( m_userIndex, eAppAction_WaitForDimensionChangeComplete); 2730 } 2731 2732 //minecraft->respawnPlayer(minecraft->player->GetXboxPad(),true, packet->dimension); 2733 2734 // Wrap respawnPlayer call up in code to set & restore the player/gamemode etc. as some things 2735 // in there assume that we are set up for the player that the respawn is coming in for 2736 int oldIndex = minecraft->getLocalPlayerIdx(); 2737 minecraft->setLocalPlayerIdx(m_userIndex); 2738 minecraft->respawnPlayer(minecraft->localplayers[m_userIndex]->GetXboxPad(),packet->dimension,packet->m_newEntityId); 2739 ((MultiPlayerGameMode *) minecraft->localgameModes[m_userIndex])->setLocalMode(packet->playerGameType); 2740 minecraft->setLocalPlayerIdx(oldIndex); 2741} 2742 2743void ClientConnection::handleExplosion(shared_ptr<ExplodePacket> packet) 2744{ 2745 if(!packet->m_bKnockbackOnly) 2746 { 2747 //app.DebugPrintf("Received ExplodePacket with explosion data\n"); 2748 PIXBeginNamedEvent(0,"Handling explosion"); 2749 Explosion *e = new Explosion(minecraft->level, nullptr, packet->x, packet->y, packet->z, packet->r); 2750 PIXBeginNamedEvent(0,"Finalizing"); 2751 2752 // 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. 2753 // 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 2754 // on the client as we KNOW that the server is matching these changes 2755 MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)minecraft->level; 2756 mpLevel->enableResetChanges(false); 2757 // 4J - now directly pass a pointer to the toBlow array in the packet rather than copying around 2758 e->finalizeExplosion(true, &packet->toBlow); 2759 mpLevel->enableResetChanges(true); 2760 PIXEndNamedEvent(); 2761 PIXEndNamedEvent(); 2762 delete e; 2763 } 2764 else 2765 { 2766 //app.DebugPrintf("Received ExplodePacket with knockback only data\n"); 2767 } 2768 2769 //app.DebugPrintf("Adding knockback (%f,%f,%f) for player %d\n", packet->getKnockbackX(), packet->getKnockbackY(), packet->getKnockbackZ(), m_userIndex); 2770 minecraft->localplayers[m_userIndex]->xd += packet->getKnockbackX(); 2771 minecraft->localplayers[m_userIndex]->yd += packet->getKnockbackY(); 2772 minecraft->localplayers[m_userIndex]->zd += packet->getKnockbackZ(); 2773} 2774 2775void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packet) 2776{ 2777 bool failed = false; 2778 shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex]; 2779 switch(packet->type) 2780 { 2781 case ContainerOpenPacket::BONUS_CHEST: 2782 case ContainerOpenPacket::LARGE_CHEST: 2783 case ContainerOpenPacket::ENDER_CHEST: 2784 case ContainerOpenPacket::CONTAINER: 2785 case ContainerOpenPacket::MINECART_CHEST: 2786 { 2787 int chestString; 2788 switch (packet->type) 2789 { 2790 case ContainerOpenPacket::MINECART_CHEST: chestString = IDS_ITEM_MINECART; break; 2791 case ContainerOpenPacket::BONUS_CHEST: chestString = IDS_BONUS_CHEST; break; 2792 case ContainerOpenPacket::LARGE_CHEST: chestString = IDS_CHEST_LARGE; break; 2793 case ContainerOpenPacket::ENDER_CHEST: chestString = IDS_TILE_ENDERCHEST; break; 2794 case ContainerOpenPacket::CONTAINER: chestString = IDS_CHEST; break; 2795 default: assert(false); chestString = -1; break; 2796 } 2797 2798 if( player->openContainer(shared_ptr<SimpleContainer>( new SimpleContainer(chestString, packet->title, packet->customName, packet->size) ))) 2799 { 2800 player->containerMenu->containerId = packet->containerId; 2801 } 2802 else 2803 { 2804 failed = true; 2805 } 2806 } 2807 break; 2808 case ContainerOpenPacket::HOPPER: 2809 { 2810 shared_ptr<HopperTileEntity> hopper = shared_ptr<HopperTileEntity>(new HopperTileEntity()); 2811 if (packet->customName) hopper->setCustomName(packet->title); 2812 if(player->openHopper(hopper)) 2813 { 2814 player->containerMenu->containerId = packet->containerId; 2815 } 2816 else 2817 { 2818 failed = true; 2819 } 2820 } 2821 break; 2822 case ContainerOpenPacket::FURNACE: 2823 { 2824 shared_ptr<FurnaceTileEntity> furnace = shared_ptr<FurnaceTileEntity>(new FurnaceTileEntity()); 2825 if (packet->customName) furnace->setCustomName(packet->title); 2826 if(player->openFurnace(furnace)) 2827 { 2828 player->containerMenu->containerId = packet->containerId; 2829 } 2830 else 2831 { 2832 failed = true; 2833 } 2834 } 2835 break; 2836 case ContainerOpenPacket::BREWING_STAND: 2837 { 2838 shared_ptr<BrewingStandTileEntity> brewingStand = shared_ptr<BrewingStandTileEntity>(new BrewingStandTileEntity()); 2839 if (packet->customName) brewingStand->setCustomName(packet->title); 2840 2841 if( player->openBrewingStand(brewingStand)) 2842 { 2843 player->containerMenu->containerId = packet->containerId; 2844 } 2845 else 2846 { 2847 failed = true; 2848 } 2849 } 2850 break; 2851 case ContainerOpenPacket::DROPPER: 2852 { 2853 shared_ptr<DropperTileEntity> dropper = shared_ptr<DropperTileEntity>(new DropperTileEntity()); 2854 if (packet->customName) dropper->setCustomName(packet->title); 2855 2856 if( player->openTrap(dropper)) 2857 { 2858 player->containerMenu->containerId = packet->containerId; 2859 } 2860 else 2861 { 2862 failed = true; 2863 } 2864 } 2865 break; 2866 case ContainerOpenPacket::TRAP: 2867 { 2868 shared_ptr<DispenserTileEntity> dispenser = shared_ptr<DispenserTileEntity>(new DispenserTileEntity()); 2869 if (packet->customName) dispenser->setCustomName(packet->title); 2870 2871 if( player->openTrap(dispenser)) 2872 { 2873 player->containerMenu->containerId = packet->containerId; 2874 } 2875 else 2876 { 2877 failed = true; 2878 } 2879 } 2880 break; 2881 case ContainerOpenPacket::WORKBENCH: 2882 { 2883 if( player->startCrafting(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)) ) 2884 { 2885 player->containerMenu->containerId = packet->containerId; 2886 } 2887 else 2888 { 2889 failed = true; 2890 } 2891 } 2892 break; 2893 case ContainerOpenPacket::ENCHANTMENT: 2894 { 2895 if( player->startEnchanting(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z), packet->customName ? packet->title : L"") ) 2896 { 2897 player->containerMenu->containerId = packet->containerId; 2898 } 2899 else 2900 { 2901 failed = true; 2902 } 2903 } 2904 break; 2905 case ContainerOpenPacket::TRADER_NPC: 2906 { 2907 shared_ptr<ClientSideMerchant> csm = shared_ptr<ClientSideMerchant>(new ClientSideMerchant(player, packet->title)); 2908 csm->createContainer(); 2909 if(player->openTrading(csm, packet->customName ? packet->title : L"")) 2910 { 2911 player->containerMenu->containerId = packet->containerId; 2912 } 2913 else 2914 { 2915 failed = true; 2916 } 2917 } 2918 break; 2919 case ContainerOpenPacket::BEACON: 2920 { 2921 shared_ptr<BeaconTileEntity> beacon = shared_ptr<BeaconTileEntity>(new BeaconTileEntity()); 2922 if (packet->customName) beacon->setCustomName(packet->title); 2923 2924 if(player->openBeacon(beacon)) 2925 { 2926 player->containerMenu->containerId = packet->containerId; 2927 } 2928 else 2929 { 2930 failed = true; 2931 } 2932 } 2933 break; 2934 case ContainerOpenPacket::REPAIR_TABLE: 2935 { 2936 if(player->startRepairing(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z))) 2937 { 2938 player->containerMenu->containerId = packet->containerId; 2939 } 2940 else 2941 { 2942 failed = true; 2943 } 2944 } 2945 break; 2946 case ContainerOpenPacket::HORSE: 2947 { 2948 shared_ptr<EntityHorse> entity = dynamic_pointer_cast<EntityHorse>( getEntity(packet->entityId) ); 2949 int iTitle = IDS_CONTAINER_ANIMAL; 2950 switch(entity->getType()) 2951 { 2952 case EntityHorse::TYPE_DONKEY: 2953 iTitle = IDS_DONKEY; 2954 break; 2955 case EntityHorse::TYPE_MULE: 2956 iTitle = IDS_MULE; 2957 break; 2958 }; 2959 if(player->openHorseInventory(dynamic_pointer_cast<EntityHorse>(entity), shared_ptr<AnimalChest>(new AnimalChest(iTitle, packet->title, packet->customName, packet->size)))) 2960 { 2961 player->containerMenu->containerId = packet->containerId; 2962 } 2963 else 2964 { 2965 failed = true; 2966 } 2967 } 2968 break; 2969 case ContainerOpenPacket::FIREWORKS: 2970 { 2971 if( player->openFireworks(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)) ) 2972 { 2973 player->containerMenu->containerId = packet->containerId; 2974 } 2975 else 2976 { 2977 failed = true; 2978 } 2979 } 2980 break; 2981 } 2982 2983 if(failed) 2984 { 2985 // Failed - if we've got a non-inventory container currently here, close that, which locally should put us back 2986 // to not having a container open, and should send a containerclose to the server so it doesn't have a container open. 2987 // If we don't have a non-inventory container open, just send the packet, and again we ought to be in sync with the server. 2988 if( player->containerMenu != player->inventoryMenu ) 2989 { 2990 ui.CloseUIScenes(m_userIndex); 2991 } 2992 else 2993 { 2994 send(shared_ptr<ContainerClosePacket>(new ContainerClosePacket(packet->containerId))); 2995 } 2996 } 2997} 2998 2999void ClientConnection::handleContainerSetSlot(shared_ptr<ContainerSetSlotPacket> packet) 3000{ 3001 shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex]; 3002 if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_CARRIED ) 3003 { 3004 player->inventory->setCarried(packet->item); 3005 } 3006 else 3007 { 3008 if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY) 3009 { 3010 // 4J Stu - Reworked a bit to fix a bug where things being collected while the creative menu was up replaced items in the creative menu 3011 if(packet->slot >= 36 && packet->slot < 36 + 9) 3012 { 3013 shared_ptr<ItemInstance> lastItem = player->inventoryMenu->getSlot(packet->slot)->getItem(); 3014 if (packet->item != NULL) 3015 { 3016 if (lastItem == NULL || lastItem->count < packet->item->count) 3017 { 3018 packet->item->popTime = Inventory::POP_TIME_DURATION; 3019 } 3020 } 3021 } 3022 player->inventoryMenu->setItem(packet->slot, packet->item); 3023 } 3024 else if (packet->containerId == player->containerMenu->containerId) 3025 { 3026 player->containerMenu->setItem(packet->slot, packet->item); 3027 } 3028 } 3029} 3030 3031void ClientConnection::handleContainerAck(shared_ptr<ContainerAckPacket> packet) 3032{ 3033 shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex]; 3034 AbstractContainerMenu *menu = NULL; 3035 if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY) 3036 { 3037 menu = player->inventoryMenu; 3038 } 3039 else if (packet->containerId == player->containerMenu->containerId) 3040 { 3041 menu = player->containerMenu; 3042 } 3043 if (menu != NULL) 3044 { 3045 if (!packet->accepted) 3046 { 3047 send( shared_ptr<ContainerAckPacket>( new ContainerAckPacket(packet->containerId, packet->uid, true) )); 3048 } 3049 } 3050} 3051 3052void ClientConnection::handleContainerContent(shared_ptr<ContainerSetContentPacket> packet) 3053{ 3054 shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex]; 3055 if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY) 3056 { 3057 player->inventoryMenu->setAll(&packet->items); 3058 } 3059 else if (packet->containerId == player->containerMenu->containerId) 3060 { 3061 player->containerMenu->setAll(&packet->items); 3062 } 3063} 3064 3065void ClientConnection::handleTileEditorOpen(shared_ptr<TileEditorOpenPacket> packet) 3066{ 3067 shared_ptr<TileEntity> tileEntity = level->getTileEntity(packet->x, packet->y, packet->z); 3068 if (tileEntity != NULL) 3069 { 3070 minecraft->localplayers[m_userIndex]->openTextEdit(tileEntity); 3071 } 3072 else if (packet->editorType == TileEditorOpenPacket::SIGN) 3073 { 3074 shared_ptr<SignTileEntity> localSignDummy = shared_ptr<SignTileEntity>(new SignTileEntity()); 3075 localSignDummy->setLevel(level); 3076 localSignDummy->x = packet->x; 3077 localSignDummy->y = packet->y; 3078 localSignDummy->z = packet->z; 3079 minecraft->player->openTextEdit(localSignDummy); 3080 } 3081} 3082 3083void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet) 3084{ 3085 app.DebugPrintf("ClientConnection::handleSignUpdate - "); 3086 if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z)) 3087 { 3088 shared_ptr<TileEntity> te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z); 3089 3090 // 4J-PB - on a client connecting, the line below fails 3091 if (dynamic_pointer_cast<SignTileEntity>(te) != NULL) 3092 { 3093 shared_ptr<SignTileEntity> ste = dynamic_pointer_cast<SignTileEntity>(te); 3094 for (int i = 0; i < MAX_SIGN_LINES; i++) 3095 { 3096 ste->SetMessage(i,packet->lines[i]); 3097 } 3098 3099 app.DebugPrintf("verified = %d\tCensored = %d\n",packet->m_bVerified,packet->m_bCensored); 3100 ste->SetVerified(packet->m_bVerified); 3101 ste->SetCensored(packet->m_bCensored); 3102 3103 ste->setChanged(); 3104 } 3105 else 3106 { 3107 app.DebugPrintf("dynamic_pointer_cast<SignTileEntity>(te) == NULL\n"); 3108 } 3109 } 3110 else 3111 { 3112 app.DebugPrintf("hasChunkAt failed\n"); 3113 } 3114} 3115 3116void ClientConnection::handleTileEntityData(shared_ptr<TileEntityDataPacket> packet) 3117{ 3118 if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z)) 3119 { 3120 shared_ptr<TileEntity> te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z); 3121 3122 if (te != NULL) 3123 { 3124 if (packet->type == TileEntityDataPacket::TYPE_MOB_SPAWNER && dynamic_pointer_cast<MobSpawnerTileEntity>(te) != NULL) 3125 { 3126 dynamic_pointer_cast<MobSpawnerTileEntity>(te)->load(packet->tag); 3127 } 3128 else if (packet->type == TileEntityDataPacket::TYPE_ADV_COMMAND && dynamic_pointer_cast<CommandBlockEntity>(te) != NULL) 3129 { 3130 dynamic_pointer_cast<CommandBlockEntity>(te)->load(packet->tag); 3131 } 3132 else if (packet->type == TileEntityDataPacket::TYPE_BEACON && dynamic_pointer_cast<BeaconTileEntity>(te) != NULL) 3133 { 3134 dynamic_pointer_cast<BeaconTileEntity>(te)->load(packet->tag); 3135 } 3136 else if (packet->type == TileEntityDataPacket::TYPE_SKULL && dynamic_pointer_cast<SkullTileEntity>(te) != NULL) 3137 { 3138 dynamic_pointer_cast<SkullTileEntity>(te)->load(packet->tag); 3139 } 3140 } 3141 } 3142} 3143 3144void ClientConnection::handleContainerSetData(shared_ptr<ContainerSetDataPacket> packet) 3145{ 3146 onUnhandledPacket(packet); 3147 if (minecraft->localplayers[m_userIndex]->containerMenu != NULL && minecraft->localplayers[m_userIndex]->containerMenu->containerId == packet->containerId) 3148 { 3149 minecraft->localplayers[m_userIndex]->containerMenu->setData(packet->id, packet->value); 3150 } 3151} 3152 3153void ClientConnection::handleSetEquippedItem(shared_ptr<SetEquippedItemPacket> packet) 3154{ 3155 shared_ptr<Entity> entity = getEntity(packet->entity); 3156 if (entity != NULL) 3157 { 3158 // 4J Stu - Brought forward change from 1.3 to fix #64688 - Customer Encountered: TU7: Content: Art: Aura of enchanted item is not displayed for other players in online game 3159 entity->setEquippedSlot(packet->slot, packet->getItem() ); 3160 } 3161} 3162 3163void ClientConnection::handleContainerClose(shared_ptr<ContainerClosePacket> packet) 3164{ 3165 minecraft->localplayers[m_userIndex]->clientSideCloseContainer(); 3166} 3167 3168void ClientConnection::handleTileEvent(shared_ptr<TileEventPacket> packet) 3169{ 3170 PIXBeginNamedEvent(0,"Handle tile event\n"); 3171 minecraft->level->tileEvent(packet->x, packet->y, packet->z, packet->tile, packet->b0, packet->b1); 3172 PIXEndNamedEvent(); 3173} 3174 3175void ClientConnection::handleTileDestruction(shared_ptr<TileDestructionPacket> packet) 3176{ 3177 minecraft->level->destroyTileProgress(packet->getEntityId(), packet->getX(), packet->getY(), packet->getZ(), packet->getState()); 3178} 3179 3180bool ClientConnection::canHandleAsyncPackets() 3181{ 3182 return minecraft != NULL && minecraft->level != NULL && minecraft->localplayers[m_userIndex] != NULL && level != NULL; 3183} 3184 3185void ClientConnection::handleGameEvent(shared_ptr<GameEventPacket> gameEventPacket) 3186{ 3187 int event = gameEventPacket->_event; 3188 int param = gameEventPacket->param; 3189 if (event >= 0 && event < GameEventPacket::EVENT_LANGUAGE_ID_LENGTH) 3190 { 3191 if (GameEventPacket::EVENT_LANGUAGE_ID[event] > 0) // 4J - was NULL check 3192 { 3193 minecraft->localplayers[m_userIndex]->displayClientMessage(GameEventPacket::EVENT_LANGUAGE_ID[event]); 3194 } 3195 } 3196 if (event == GameEventPacket::START_RAINING) 3197 { 3198 level->getLevelData()->setRaining(true); 3199 level->setRainLevel(1); 3200 } 3201 else if (event == GameEventPacket::STOP_RAINING) 3202 { 3203 level->getLevelData()->setRaining(false); 3204 level->setRainLevel(0); 3205 } 3206 else if (event == GameEventPacket::CHANGE_GAME_MODE) 3207 { 3208 minecraft->localgameModes[m_userIndex]->setLocalMode(GameType::byId(param)); 3209 } 3210 else if (event == GameEventPacket::WIN_GAME) 3211 { 3212 ui.SetWinUserIndex( (BYTE)gameEventPacket->param ); 3213 3214#ifdef _XBOX 3215 3216 // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen 3217 ui.HideAllGameUIElements(); 3218 3219 // Hide the other players scenes 3220 ui.ShowOtherPlayersBaseScene(ProfileManager.GetPrimaryPad(), false); 3221 3222 // This just allows it to be shown 3223 if(minecraft->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) minecraft->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(false); 3224 // Temporarily make this scene fullscreen 3225 CXuiSceneBase::SetPlayerBaseScenePosition( ProfileManager.GetPrimaryPad(), CXuiSceneBase::e_BaseScene_Fullscreen ); 3226 3227 app.CloseXuiScenesAndNavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_EndPoem); 3228#else 3229 app.DebugPrintf("handleGameEvent packet for WIN_GAME - %d\n", m_userIndex); 3230 // This just allows it to be shown 3231 if(minecraft->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) minecraft->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(false); 3232 ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_EndPoem, NULL, eUILayer_Scene, eUIGroup_Fullscreen); 3233#endif 3234 } 3235 else if( event == GameEventPacket::START_SAVING ) 3236 { 3237 if(!g_NetworkManager.IsHost()) 3238 { 3239 // Move app started to here so that it happens immediately otherwise back-to-back START/STOP packets 3240 // leave the client stuck in the loading screen 3241 app.SetGameStarted(false); 3242 app.SetAction( ProfileManager.GetPrimaryPad(), eAppAction_RemoteServerSave ); 3243 } 3244 } 3245 else if( event == GameEventPacket::STOP_SAVING ) 3246 { 3247 if(!g_NetworkManager.IsHost() ) app.SetGameStarted(true); 3248 } 3249 else if ( event == GameEventPacket::SUCCESSFUL_BOW_HIT ) 3250 { 3251 shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex]; 3252 level->playLocalSound(player->x, player->y + player->getHeadHeight(), player->z, eSoundType_RANDOM_BOW_HIT , 0.18f, 0.45f, false); 3253 } 3254} 3255 3256void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> packet) 3257{ 3258 if (packet->itemType == Item::map->id) 3259 { 3260 MapItem::getSavedData(packet->itemId, minecraft->level)->handleComplexItemData(packet->data); 3261 } 3262 else 3263 { 3264// System.out.println("Unknown itemid: " + packet->itemId); // 4J removed 3265 } 3266} 3267 3268 3269 3270void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet) 3271{ 3272 if (packet->type == LevelEvent::SOUND_DRAGON_DEATH) 3273 { 3274 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) 3275 { 3276 if(minecraft->localplayers[i] != NULL && minecraft->localplayers[i]->level != NULL && minecraft->localplayers[i]->level->dimension->id == 1) 3277 { 3278 minecraft->localplayers[i]->awardStat(GenericStats::completeTheEnd(),GenericStats::param_noArgs()); 3279 } 3280 } 3281 } 3282 3283 if (packet->isGlobalEvent()) 3284 { 3285 minecraft->level->globalLevelEvent(packet->type, packet->x, packet->y, packet->z, packet->data); 3286 } 3287 else 3288 { 3289 minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data); 3290 } 3291 3292 minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data); 3293} 3294 3295void ClientConnection::handleAwardStat(shared_ptr<AwardStatPacket> packet) 3296{ 3297 minecraft->localplayers[m_userIndex]->awardStatFromServer(GenericStats::stat(packet->statId), packet->getParamData()); 3298} 3299 3300void ClientConnection::handleUpdateMobEffect(shared_ptr<UpdateMobEffectPacket> packet) 3301{ 3302 shared_ptr<Entity> e = getEntity(packet->entityId); 3303 if ( (e == NULL) || !e->instanceof(eTYPE_LIVINGENTITY) ) return; 3304 3305 //( dynamic_pointer_cast<LivingEntity>(e) )->addEffect(new MobEffectInstance(packet->effectId, packet->effectDurationTicks, packet->effectAmplifier)); 3306 3307 MobEffectInstance *mobEffectInstance = new MobEffectInstance(packet->effectId, packet->effectDurationTicks, packet->effectAmplifier); 3308 mobEffectInstance->setNoCounter(packet->isSuperLongDuration()); 3309 dynamic_pointer_cast<LivingEntity>(e)->addEffect(mobEffectInstance); 3310} 3311 3312void ClientConnection::handleRemoveMobEffect(shared_ptr<RemoveMobEffectPacket> packet) 3313{ 3314 shared_ptr<Entity> e = getEntity(packet->entityId); 3315 if ( (e == NULL) || !e->instanceof(eTYPE_LIVINGENTITY) ) return; 3316 3317 ( dynamic_pointer_cast<LivingEntity>(e) )->removeEffectNoUpdate(packet->effectId); 3318} 3319 3320bool ClientConnection::isServerPacketListener() 3321{ 3322 return false; 3323} 3324 3325void ClientConnection::handlePlayerInfo(shared_ptr<PlayerInfoPacket> packet) 3326{ 3327 unsigned int startingPrivileges = app.GetPlayerPrivileges(packet->m_networkSmallId); 3328 3329 INetworkPlayer *networkPlayer = g_NetworkManager.GetPlayerBySmallId(packet->m_networkSmallId); 3330 3331 if(networkPlayer != NULL && networkPlayer->IsHost()) 3332 { 3333 // Some settings should always be considered on for the host player 3334 Player::enableAllPlayerPrivileges(startingPrivileges,true); 3335 Player::setPlayerGamePrivilege(startingPrivileges,Player::ePlayerGamePrivilege_HOST,1); 3336 } 3337 3338 // 4J Stu - Repurposed this packet for player info that we want 3339 app.UpdatePlayerInfo(packet->m_networkSmallId, packet->m_playerColourIndex, packet->m_playerPrivileges); 3340 3341 shared_ptr<Entity> entity = getEntity(packet->m_entityId); 3342 if(entity != NULL && entity->instanceof(eTYPE_PLAYER)) 3343 { 3344 shared_ptr<Player> player = dynamic_pointer_cast<Player>(entity); 3345 player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_playerPrivileges); 3346 } 3347 if(networkPlayer != NULL && networkPlayer->IsLocal()) 3348 { 3349 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) 3350 { 3351 shared_ptr<MultiplayerLocalPlayer> localPlayer = minecraft->localplayers[i]; 3352 if(localPlayer != NULL && localPlayer->connection != NULL && localPlayer->connection->getNetworkPlayer() == networkPlayer ) 3353 { 3354 localPlayer->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All,packet->m_playerPrivileges); 3355 displayPrivilegeChanges(localPlayer,startingPrivileges); 3356 break; 3357 } 3358 } 3359 } 3360 3361 // 4J Stu - I don't think we care about this, so not converting it (came from 1.8.2) 3362#if 0 3363 PlayerInfo pi = playerInfoMap.get(packet.name); 3364 if (pi == null && packet.add) { 3365 pi = new PlayerInfo(packet.name); 3366 playerInfoMap.put(packet.name, pi); 3367 playerInfos.add(pi); 3368 } 3369 if (pi != null && !packet.add) { 3370 playerInfoMap.remove(packet.name); 3371 playerInfos.remove(pi); 3372 } 3373 if (packet.add && pi != null) { 3374 pi.latency = packet.latency; 3375 } 3376#endif 3377} 3378 3379 3380void ClientConnection::displayPrivilegeChanges(shared_ptr<MultiplayerLocalPlayer> player, unsigned int oldPrivileges) 3381{ 3382 int userIndex = player->GetXboxPad(); 3383 unsigned int newPrivileges = player->getAllPlayerGamePrivileges(); 3384 Player::EPlayerGamePrivileges priv = (Player::EPlayerGamePrivileges)0; 3385 bool privOn = false; 3386 for(unsigned int i = 0; i < Player::ePlayerGamePrivilege_MAX; ++i) 3387 { 3388 priv = (Player::EPlayerGamePrivileges) i; 3389 if( Player::getPlayerGamePrivilege(newPrivileges,priv) != Player::getPlayerGamePrivilege(oldPrivileges,priv)) 3390 { 3391 privOn = Player::getPlayerGamePrivilege(newPrivileges,priv); 3392 wstring message = L""; 3393 if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) 3394 { 3395 switch(priv) 3396 { 3397 case Player::ePlayerGamePrivilege_CannotMine: 3398 if(privOn) message = app.GetString(IDS_PRIV_MINE_TOGGLE_ON); 3399 else message = app.GetString(IDS_PRIV_MINE_TOGGLE_OFF); 3400 break; 3401 case Player::ePlayerGamePrivilege_CannotBuild: 3402 if(privOn) message = app.GetString(IDS_PRIV_BUILD_TOGGLE_ON); 3403 else message = app.GetString(IDS_PRIV_BUILD_TOGGLE_OFF); 3404 break; 3405 case Player::ePlayerGamePrivilege_CanUseDoorsAndSwitches: 3406 if(privOn) message = app.GetString(IDS_PRIV_USE_DOORS_TOGGLE_ON); 3407 else message = app.GetString(IDS_PRIV_USE_DOORS_TOGGLE_OFF); 3408 break; 3409 case Player::ePlayerGamePrivilege_CanUseContainers: 3410 if(privOn) message = app.GetString(IDS_PRIV_USE_CONTAINERS_TOGGLE_ON); 3411 else message = app.GetString(IDS_PRIV_USE_CONTAINERS_TOGGLE_OFF); 3412 break; 3413 case Player::ePlayerGamePrivilege_CannotAttackAnimals: 3414 if(privOn) message = app.GetString(IDS_PRIV_ATTACK_ANIMAL_TOGGLE_ON); 3415 else message = app.GetString(IDS_PRIV_ATTACK_ANIMAL_TOGGLE_OFF); 3416 break; 3417 case Player::ePlayerGamePrivilege_CannotAttackMobs: 3418 if(privOn) message = app.GetString(IDS_PRIV_ATTACK_MOB_TOGGLE_ON); 3419 else message = app.GetString(IDS_PRIV_ATTACK_MOB_TOGGLE_OFF); 3420 break; 3421 case Player::ePlayerGamePrivilege_CannotAttackPlayers: 3422 if(privOn) message = app.GetString(IDS_PRIV_ATTACK_PLAYER_TOGGLE_ON); 3423 else message = app.GetString(IDS_PRIV_ATTACK_PLAYER_TOGGLE_OFF); 3424 break; 3425 }; 3426 } 3427 switch(priv) 3428 { 3429 case Player::ePlayerGamePrivilege_Op: 3430 if(privOn) message = app.GetString(IDS_PRIV_MODERATOR_TOGGLE_ON); 3431 else message = app.GetString(IDS_PRIV_MODERATOR_TOGGLE_OFF); 3432 break; 3433 }; 3434 if(app.GetGameHostOption(eGameHostOption_CheatsEnabled) != 0) 3435 { 3436 switch(priv) 3437 { 3438 case Player::ePlayerGamePrivilege_CanFly: 3439 if(privOn) message = app.GetString(IDS_PRIV_FLY_TOGGLE_ON); 3440 else message = app.GetString(IDS_PRIV_FLY_TOGGLE_OFF); 3441 break; 3442 case Player::ePlayerGamePrivilege_ClassicHunger: 3443 if(privOn) message = app.GetString(IDS_PRIV_EXHAUSTION_TOGGLE_ON); 3444 else message = app.GetString(IDS_PRIV_EXHAUSTION_TOGGLE_OFF); 3445 break; 3446 case Player::ePlayerGamePrivilege_Invisible: 3447 if(privOn) message = app.GetString(IDS_PRIV_INVISIBLE_TOGGLE_ON); 3448 else message = app.GetString(IDS_PRIV_INVISIBLE_TOGGLE_OFF); 3449 break; 3450 case Player::ePlayerGamePrivilege_Invulnerable: 3451 if(privOn) message = app.GetString(IDS_PRIV_INVULNERABLE_TOGGLE_ON); 3452 else message = app.GetString(IDS_PRIV_INVULNERABLE_TOGGLE_OFF); 3453 break; 3454 case Player::ePlayerGamePrivilege_CanToggleInvisible: 3455 if(privOn) message = app.GetString(IDS_PRIV_CAN_INVISIBLE_TOGGLE_ON); 3456 else message = app.GetString(IDS_PRIV_CAN_INVISIBLE_TOGGLE_OFF); 3457 break; 3458 case Player::ePlayerGamePrivilege_CanToggleFly: 3459 if(privOn) message = app.GetString(IDS_PRIV_CAN_FLY_TOGGLE_ON); 3460 else message = app.GetString(IDS_PRIV_CAN_FLY_TOGGLE_OFF); 3461 break; 3462 case Player::ePlayerGamePrivilege_CanToggleClassicHunger: 3463 if(privOn) message = app.GetString(IDS_PRIV_CAN_EXHAUSTION_TOGGLE_ON); 3464 else message = app.GetString(IDS_PRIV_CAN_EXHAUSTION_TOGGLE_OFF); 3465 break; 3466 case Player::ePlayerGamePrivilege_CanTeleport: 3467 if(privOn) message = app.GetString(IDS_PRIV_CAN_TELEPORT_TOGGLE_ON); 3468 else message = app.GetString(IDS_PRIV_CAN_TELEPORT_TOGGLE_OFF); 3469 break; 3470 }; 3471 } 3472 if(!message.empty()) minecraft->gui->addMessage(message,userIndex); 3473 } 3474 } 3475} 3476 3477void ClientConnection::handleKeepAlive(shared_ptr<KeepAlivePacket> packet) 3478{ 3479 send(shared_ptr<KeepAlivePacket>(new KeepAlivePacket(packet->id))); 3480} 3481 3482void ClientConnection::handlePlayerAbilities(shared_ptr<PlayerAbilitiesPacket> playerAbilitiesPacket) 3483{ 3484 shared_ptr<Player> player = minecraft->localplayers[m_userIndex]; 3485 player->abilities.flying = playerAbilitiesPacket->isFlying(); 3486 player->abilities.instabuild = playerAbilitiesPacket->canInstabuild(); 3487 player->abilities.invulnerable = playerAbilitiesPacket->isInvulnerable(); 3488 player->abilities.mayfly = playerAbilitiesPacket->canFly(); 3489 player->abilities.setFlyingSpeed(playerAbilitiesPacket->getFlyingSpeed()); 3490 player->abilities.setWalkingSpeed(playerAbilitiesPacket->getWalkingSpeed()); 3491} 3492 3493void ClientConnection::handleSoundEvent(shared_ptr<LevelSoundPacket> packet) 3494{ 3495 minecraft->level->playLocalSound(packet->getX(), packet->getY(), packet->getZ(), packet->getSound(), packet->getVolume(), packet->getPitch(), false); 3496} 3497 3498void ClientConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> customPayloadPacket) 3499{ 3500 if (CustomPayloadPacket::TRADER_LIST_PACKET.compare(customPayloadPacket->identifier) == 0) 3501 { 3502 ByteArrayInputStream bais(customPayloadPacket->data); 3503 DataInputStream input(&bais); 3504 int containerId = input.readInt(); 3505 if (ui.IsSceneInStack(m_userIndex, eUIScene_TradingMenu) && containerId == minecraft->localplayers[m_userIndex]->containerMenu->containerId) 3506 { 3507 shared_ptr<Merchant> trader = nullptr; 3508 3509#ifdef _XBOX 3510 HXUIOBJ scene = app.GetCurrentScene(m_userIndex); 3511 HXUICLASS thisClass = XuiFindClass( L"CXuiSceneTrading" ); 3512 HXUICLASS objClass = XuiGetObjectClass( scene ); 3513 3514 // Also returns TRUE if they are the same (which is what we want) 3515 if( XuiClassDerivesFrom( objClass, thisClass ) ) 3516 { 3517 CXuiSceneTrading *screen; 3518 HRESULT hr = XuiObjectFromHandle(scene, (void **) &screen); 3519 if (FAILED(hr)) return; 3520 trader = screen->getMerchant(); 3521 } 3522#else 3523 UIScene *scene = ui.GetTopScene(m_userIndex, eUILayer_Scene); 3524 UIScene_TradingMenu *screen = (UIScene_TradingMenu *)scene; 3525 trader = screen->getMerchant(); 3526#endif 3527 3528 MerchantRecipeList *recipeList = MerchantRecipeList::createFromStream(&input); 3529 trader->overrideOffers(recipeList); 3530 } 3531 } 3532} 3533 3534Connection *ClientConnection::getConnection() 3535{ 3536 return connection; 3537} 3538 3539// 4J Added 3540void ClientConnection::handleServerSettingsChanged(shared_ptr<ServerSettingsChangedPacket> packet) 3541{ 3542 if(packet->action==ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS) 3543 { 3544 app.SetGameHostOption(eGameHostOption_All, packet->data); 3545 } 3546 else if(packet->action==ServerSettingsChangedPacket::HOST_DIFFICULTY) 3547 { 3548 for(unsigned int i = 0; i < minecraft->levels.length; ++i) 3549 { 3550 if( minecraft->levels[i] != NULL ) 3551 { 3552 app.DebugPrintf("ClientConnection::handleServerSettingsChanged - Difficulty = %d",packet->data); 3553 minecraft->levels[i]->difficulty = packet->data; 3554 } 3555 } 3556 } 3557 else 3558 { 3559 //options 3560 //minecraft->options->SetGamertagSetting((packet->data==0)?false:true); 3561 app.SetGameHostOption(eGameHostOption_Gamertags, packet->data); 3562 } 3563 3564} 3565 3566void ClientConnection::handleXZ(shared_ptr<XZPacket> packet) 3567{ 3568 if(packet->action==XZPacket::STRONGHOLD) 3569 { 3570 minecraft->levels[0]->getLevelData()->setXStronghold(packet->x); 3571 minecraft->levels[0]->getLevelData()->setZStronghold(packet->z); 3572 minecraft->levels[0]->getLevelData()->setHasStronghold(); 3573 } 3574} 3575 3576void ClientConnection::handleUpdateProgress(shared_ptr<UpdateProgressPacket> packet) 3577{ 3578 if(!g_NetworkManager.IsHost() ) Minecraft::GetInstance()->progressRenderer->progressStagePercentage( packet->m_percentage ); 3579} 3580 3581void ClientConnection::handleUpdateGameRuleProgressPacket(shared_ptr<UpdateGameRuleProgressPacket> packet) 3582{ 3583 LPCWSTR string = app.GetGameRulesString(packet->m_messageId); 3584 if(string != NULL) 3585 { 3586 wstring message(string); 3587 message = GameRuleDefinition::generateDescriptionString(packet->m_definitionType,message,packet->m_data.data,packet->m_data.length); 3588 if(minecraft->localgameModes[m_userIndex]!=NULL) 3589 { 3590 minecraft->localgameModes[m_userIndex]->getTutorial()->setMessage(message, packet->m_icon, packet->m_auxValue); 3591 } 3592 } 3593 // If this rule has a data tag associated with it, then we save that in user profile data 3594 if(packet->m_dataTag > 0 && packet->m_dataTag <= 32) 3595 { 3596 app.DebugPrintf("handleUpdateGameRuleProgressPacket: Data tag is in range, so updating profile data\n"); 3597 app.SetSpecialTutorialCompletionFlag(m_userIndex, packet->m_dataTag - 1); 3598 } 3599 delete [] packet->m_data.data; 3600} 3601 3602// 4J Stu - TU-1 hotfix 3603// Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost 3604int ClientConnection::HostDisconnectReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) 3605{ 3606 // 4J-PB - if they have a trial texture pack, they don't get to save the world 3607 if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) 3608 { 3609 TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); 3610 DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; 3611 3612 DLCPack *pDLCPack=pDLCTexPack->getDLCInfoParentPack();//tPack->getDLCPack(); 3613 if(!pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) 3614 { 3615 // no upsell, we're about to quit 3616 MinecraftServer::getInstance()->setSaveOnExit( false ); 3617 // flag a app action of exit game 3618 app.SetAction(iPad,eAppAction_ExitWorld); 3619 } 3620 } 3621 3622#if defined(_XBOX_ONE) || defined(__ORBIS__) 3623 // Give the player the option to save their game 3624 // does the save exist? 3625 bool bSaveExists; 3626 StorageManager.DoesSaveExist(&bSaveExists); 3627 // 4J-PB - we check if the save exists inside the libs 3628 // we need to ask if they are sure they want to overwrite the existing game 3629 if(bSaveExists && StorageManager.GetSaveDisabled()) 3630 { 3631 UINT uiIDA[2]; 3632 uiIDA[0]=IDS_CONFIRM_CANCEL; 3633 uiIDA[1]=IDS_CONFIRM_OK; 3634 ui.RequestErrorMessage(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&ClientConnection::ExitGameAndSaveReturned,NULL); 3635 } 3636 else 3637#else 3638 // Give the player the option to save their game 3639 // does the save exist? 3640 bool bSaveExists; 3641 StorageManager.DoesSaveExist(&bSaveExists); 3642 // 4J-PB - we check if the save exists inside the libs 3643 // we need to ask if they are sure they want to overwrite the existing game 3644 if(bSaveExists) 3645 { 3646 UINT uiIDA[2]; 3647 uiIDA[0]=IDS_CONFIRM_CANCEL; 3648 uiIDA[1]=IDS_CONFIRM_OK; 3649 ui.RequestErrorMessage(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&ClientConnection::ExitGameAndSaveReturned,NULL); 3650 } 3651 else 3652#endif 3653 { 3654#if defined(_XBOX_ONE) || defined(__ORBIS__) 3655 StorageManager.SetSaveDisabled(false); 3656#endif 3657 MinecraftServer::getInstance()->setSaveOnExit( true ); 3658 // flag a app action of exit game 3659 app.SetAction(iPad,eAppAction_ExitWorld); 3660 } 3661 3662 return 0; 3663} 3664 3665int ClientConnection::ExitGameAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) 3666{ 3667 // results switched for this dialog 3668 if(result==C4JStorage::EMessage_ResultDecline) 3669 { 3670 //INT saveOrCheckpointId = 0; 3671 //bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); 3672 //SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), saveOrCheckpointId); 3673#if defined(_XBOX_ONE) || defined(__ORBIS__) 3674 StorageManager.SetSaveDisabled(false); 3675#endif 3676 MinecraftServer::getInstance()->setSaveOnExit( true ); 3677 } 3678 else 3679 { 3680 MinecraftServer::getInstance()->setSaveOnExit( false ); 3681 } 3682 // flag a app action of exit game 3683 app.SetAction(iPad,eAppAction_ExitWorld); 3684 return 0; 3685} 3686 3687// 3688wstring ClientConnection::GetDisplayNameByGamertag(wstring gamertag) 3689{ 3690#ifdef _DURANGO 3691 wstring displayName = g_NetworkManager.GetDisplayNameByGamertag(gamertag); 3692 return displayName; 3693#else 3694 return gamertag; 3695#endif 3696} 3697 3698void ClientConnection::handleAddObjective(shared_ptr<SetObjectivePacket> packet) 3699{ 3700#if 0 3701 Scoreboard scoreboard = level->getScoreboard(); 3702 3703 if (packet->method == SetObjectivePacket::METHOD_ADD) 3704 { 3705 Objective objective = scoreboard->addObjective(packet->objectiveName, ObjectiveCriteria::DUMMY); 3706 objective->setDisplayName(packet->displayName); 3707 } 3708 else 3709 { 3710 Objective objective = scoreboard->getObjective(packet->objectiveName); 3711 3712 if (packet->method == SetObjectivePacket::METHOD_REMOVE) 3713 { 3714 scoreboard->removeObjective(objective); 3715 } 3716 else if (packet->method == SetObjectivePacket::METHOD_CHANGE) 3717 { 3718 objective->setDisplayName(packet->displayName); 3719 } 3720 } 3721#endif 3722} 3723 3724void ClientConnection::handleSetScore(shared_ptr<SetScorePacket> packet) 3725{ 3726#if 0 3727 Scoreboard scoreboard = level->getScoreboard(); 3728 Objective objective = scoreboard->getObjective(packet->objectiveName); 3729 3730 if (packet->method == SetScorePacket::METHOD_CHANGE) 3731 { 3732 Score score = scoreboard->getPlayerScore(packet->owner, objective); 3733 score->setScore(packet->score); 3734 } 3735 else if (packet->method == SetScorePacket::METHOD_REMOVE) 3736 { 3737 scoreboard->resetPlayerScore(packet->owner); 3738 } 3739#endif 3740} 3741 3742void ClientConnection::handleSetDisplayObjective(shared_ptr<SetDisplayObjectivePacket> packet) 3743{ 3744#if 0 3745 Scoreboard scoreboard = level->getScoreboard(); 3746 3747 if (packet->objectiveName->length() == 0) 3748 { 3749 scoreboard->setDisplayObjective(packet->slot, null); 3750 } 3751 else 3752 { 3753 Objective objective = scoreboard->getObjective(packet->objectiveName); 3754 scoreboard->setDisplayObjective(packet->slot, objective); 3755 } 3756#endif 3757} 3758 3759void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket> packet) 3760{ 3761#if 0 3762 Scoreboard scoreboard = level->getScoreboard(); 3763 PlayerTeam *team; 3764 3765 if (packet->method == SetPlayerTeamPacket::METHOD_ADD) 3766 { 3767 team = scoreboard->addPlayerTeam(packet->name); 3768 } 3769 else 3770 { 3771 team = scoreboard->getPlayerTeam(packet->name); 3772 } 3773 3774 if (packet->method == SetPlayerTeamPacket::METHOD_ADD || packet->method == SetPlayerTeamPacket::METHOD_CHANGE) 3775 { 3776 team->setDisplayName(packet->displayName); 3777 team->setPrefix(packet->prefix); 3778 team->setSuffix(packet->suffix); 3779 team->unpackOptions(packet->options); 3780 } 3781 3782 if (packet->method == SetPlayerTeamPacket::METHOD_ADD || packet->method == SetPlayerTeamPacket::METHOD_JOIN) 3783 { 3784 for (int i = 0; i < packet->players.size(); i++) 3785 { 3786 scoreboard->addPlayerToTeam(packet->players[i], team); 3787 } 3788 } 3789 3790 if (packet->method == SetPlayerTeamPacket::METHOD_LEAVE) 3791 { 3792 for (int i = 0; i < packet->players.size(); i++) 3793 { 3794 scoreboard->removePlayerFromTeam(packet->players[i], team); 3795 } 3796 } 3797 3798 if (packet->method == SetPlayerTeamPacket::METHOD_REMOVE) 3799 { 3800 scoreboard->removePlayerTeam(team); 3801 } 3802#endif 3803} 3804 3805void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet) 3806{ 3807 for (int i = 0; i < packet->getCount(); i++) 3808 { 3809 double xVarience = random->nextGaussian() * packet->getXDist(); 3810 double yVarience = random->nextGaussian() * packet->getYDist(); 3811 double zVarience = random->nextGaussian() * packet->getZDist(); 3812 double xa = random->nextGaussian() * packet->getMaxSpeed(); 3813 double ya = random->nextGaussian() * packet->getMaxSpeed(); 3814 double za = random->nextGaussian() * packet->getMaxSpeed(); 3815 3816 // TODO: determine particle ID from name 3817 assert(0); 3818 ePARTICLE_TYPE particleId = eParticleType_heart; 3819 3820 level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za); 3821 } 3822} 3823 3824void ClientConnection::handleUpdateAttributes(shared_ptr<UpdateAttributesPacket> packet) 3825{ 3826 shared_ptr<Entity> entity = getEntity(packet->getEntityId()); 3827 if (entity == NULL) return; 3828 3829 if ( !entity->instanceof(eTYPE_LIVINGENTITY) ) 3830 { 3831 // Entity is not a living entity! 3832 assert(0); 3833 } 3834 3835 BaseAttributeMap *attributes = (dynamic_pointer_cast<LivingEntity>(entity))->getAttributes(); 3836 unordered_set<UpdateAttributesPacket::AttributeSnapshot *> attributeSnapshots = packet->getValues(); 3837 for (AUTO_VAR(it,attributeSnapshots.begin()); it != attributeSnapshots.end(); ++it) 3838 { 3839 UpdateAttributesPacket::AttributeSnapshot *attribute = *it; 3840 AttributeInstance *instance = attributes->getInstance(attribute->getId()); 3841 3842 if (instance == NULL) 3843 { 3844 // 4J - TODO: revisit, not familiar with the attribute system, why are we passing in MIN_NORMAL (Java's smallest non-zero value conforming to IEEE Standard 754 (?)) and MAX_VALUE 3845 instance = attributes->registerAttribute(new RangedAttribute(attribute->getId(), 0, Double::MIN_NORMAL, Double::MAX_VALUE)); 3846 } 3847 3848 instance->setBaseValue(attribute->getBase()); 3849 instance->removeModifiers(); 3850 3851 unordered_set<AttributeModifier *> *modifiers = attribute->getModifiers(); 3852 3853 for (AUTO_VAR(it2,modifiers->begin()); it2 != modifiers->end(); ++it2) 3854 { 3855 AttributeModifier* modifier = *it2; 3856 instance->addModifier(new AttributeModifier(modifier->getId(), modifier->getAmount(), modifier->getOperation() ) ); 3857 } 3858 } 3859} 3860 3861// 4J: Check for deferred entity link packets related to this entity ID and handle them 3862void ClientConnection::checkDeferredEntityLinkPackets(int newEntityId) 3863{ 3864 if (deferredEntityLinkPackets.empty()) return; 3865 3866 for (int i = 0; i < deferredEntityLinkPackets.size(); i++) 3867 { 3868 DeferredEntityLinkPacket *deferred = &deferredEntityLinkPackets[i]; 3869 3870 bool remove = false; 3871 3872 // Only consider recently deferred packets 3873 int tickInterval = GetTickCount() - deferred->m_recievedTick; 3874 if (tickInterval < MAX_ENTITY_LINK_DEFERRAL_INTERVAL) 3875 { 3876 // Note: we assume it's the destination entity 3877 if (deferred->m_packet->destId == newEntityId) 3878 { 3879 handleEntityLinkPacket(deferred->m_packet); 3880 remove = true; 3881 } 3882 } 3883 else 3884 { 3885 // This is an old packet, remove (shouldn't really come up but seems prudent) 3886 remove = true; 3887 } 3888 3889 if (remove) 3890 { 3891 deferredEntityLinkPackets.erase(deferredEntityLinkPackets.begin() + i); 3892 i--; 3893 } 3894 } 3895} 3896 3897ClientConnection::DeferredEntityLinkPacket::DeferredEntityLinkPacket(shared_ptr<SetEntityLinkPacket> packet) 3898{ 3899 m_recievedTick = GetTickCount(); 3900 m_packet = packet; 3901}