the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 1640 lines 57 kB view raw
1#include "stdafx.h" 2#include "PlayerList.h" 3#include "PlayerChunkMap.h" 4#include "MinecraftServer.h" 5#include "Settings.h" 6#include "ServerLevel.h" 7#include "ServerChunkCache.h" 8#include "ServerPlayer.h" 9#include "ServerPlayerGameMode.h" 10#include "ServerConnection.h" 11#include "PendingConnection.h" 12#include "PlayerConnection.h" 13#include "EntityTracker.h" 14#include "..\Minecraft.World\net.minecraft.world.level.storage.h" 15#include "..\Minecraft.World\net.minecraft.world.level.dimension.h" 16#include "..\Minecraft.World\ArrayWithLength.h" 17#include "..\Minecraft.World\net.minecraft.network.packet.h" 18#include "..\Minecraft.World\net.minecraft.network.h" 19#include "..\Minecraft.World\Pos.h" 20#include "..\Minecraft.World\ProgressListener.h" 21#include "..\Minecraft.World\HellRandomLevelSource.h" 22#include "..\Minecraft.World\net.minecraft.world.phys.h" 23#include "..\Minecraft.World\net.minecraft.world.item.h" 24#include "..\Minecraft.World\net.minecraft.world.level.storage.h" 25#include "..\Minecraft.World\net.minecraft.world.level.saveddata.h" 26#include "..\Minecraft.World\JavaMath.h" 27#include "..\Minecraft.World\EntityIO.h" 28#if defined(_XBOX) || defined(_WINDOWS64) 29#include "Xbox\Network\NetworkPlayerXbox.h" 30#elif defined(__PS3__) || defined(__ORBIS__) 31#include "Common\Network\Sony\NetworkPlayerSony.h" 32#endif 33 34// 4J - this class is fairly substantially altered as there didn't seem any point in porting code for banning, whitelisting, ops etc. 35 36PlayerList::PlayerList(MinecraftServer *server) 37{ 38 playerIo = NULL; 39 40 this->server = server; 41 42 sendAllPlayerInfoIn = 0; 43 overrideGameMode = NULL; 44 allowCheatsForAllPlayers = false; 45 46#ifdef __PSVITA__ 47 viewDistance = 3; 48#elif defined _LARGE_WORLDS 49 viewDistance = 16; 50#else 51 viewDistance = 10; 52#endif 53 54 //int viewDistance = server->settings->getInt(L"view-distance", 10); 55 56 maxPlayers = server->settings->getInt(L"max-players", 20); 57 doWhiteList = false; 58 59#ifdef _WINDOWS64 60 maxPlayers = MINECRAFT_NET_MAX_PLAYERS; 61#else 62 maxPlayers = server->settings->getInt(L"max-players", 20); 63#endif 64 InitializeCriticalSection(&m_kickPlayersCS); 65 InitializeCriticalSection(&m_closePlayersCS); 66} 67 68PlayerList::~PlayerList() 69{ 70 for( AUTO_VAR(it, players.begin()); it < players.end(); it++ ) 71 { 72 (*it)->connection = nullptr; // Must remove reference to connection, or else there is a circular dependency 73 delete (*it)->gameMode; // Gamemode also needs deleted as it references back to this player 74 (*it)->gameMode = NULL; 75 } 76 77 DeleteCriticalSection(&m_kickPlayersCS); 78 DeleteCriticalSection(&m_closePlayersCS); 79} 80 81void PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer> player, shared_ptr<LoginPacket> packet) 82{ 83 CompoundTag *playerTag = load(player); 84 85 bool newPlayer = playerTag == NULL; 86 87 player->setLevel(server->getLevel(player->dimension)); 88 player->gameMode->setLevel((ServerLevel *)player->level); 89 90 // Make sure these privileges are always turned off for the host player 91 INetworkPlayer *networkPlayer = connection->getSocket()->getPlayer(); 92 if(networkPlayer != NULL && networkPlayer->IsHost()) 93 { 94 player->enableAllPlayerPrivileges(true); 95 player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_HOST,1); 96 } 97 98#if defined(__PS3__) || defined(__ORBIS__) 99 // PS3 networking library doesn't automatically assign PlayerUIDs to the network players for anything remote, so need to tell it what to set from the data in this packet now 100 if( !g_NetworkManager.IsLocalGame() ) 101 { 102 if( networkPlayer != NULL ) 103 { 104 ((NetworkPlayerSony *)networkPlayer)->SetUID( packet->m_onlineXuid ); 105 } 106 } 107#endif 108#ifdef _WINDOWS64 109 if (networkPlayer != NULL && !networkPlayer->IsLocal()) 110 { 111 NetworkPlayerXbox* nxp = (NetworkPlayerXbox*)networkPlayer; 112 IQNetPlayer* qnp = nxp->GetQNetPlayer(); 113 wcsncpy_s(qnp->m_gamertag, 32, player->name.c_str(), _TRUNCATE); 114 } 115#endif 116 // 4J Stu - TU-1 hotfix 117 // Fix for #13150 - When a player loads/joins a game after saving/leaving in the nether, sometimes they are spawned on top of the nether and cannot mine down 118 validatePlayerSpawnPosition(player); 119 120 // logger.info(getName() + " logged in with entity id " + playerEntity.entityId + " at (" + playerEntity.x + ", " + playerEntity.y + ", " + playerEntity.z + ")"); 121 122 ServerLevel *level = server->getLevel(player->dimension); 123 124 DWORD playerIndex = 0; 125 { 126 bool usedIndexes[MINECRAFT_NET_MAX_PLAYERS]; 127 ZeroMemory( &usedIndexes, MINECRAFT_NET_MAX_PLAYERS * sizeof(bool) ); 128 for(AUTO_VAR(it, players.begin()); it < players.end(); ++it) 129 { 130 usedIndexes[ (int)(*it)->getPlayerIndex() ] = true; 131 } 132 for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) 133 { 134 if(!usedIndexes[i]) 135 { 136 playerIndex = i; 137 break; 138 } 139 } 140 } 141 player->setPlayerIndex( playerIndex ); 142 player->setCustomSkin( packet->m_playerSkinId ); 143 player->setCustomCape( packet->m_playerCapeId ); 144 145 // 4J-JEV: Moved this here so we can send player-model texture and geometry data. 146 shared_ptr<PlayerConnection> playerConnection = shared_ptr<PlayerConnection>(new PlayerConnection(server, connection, player)); 147 //player->connection = playerConnection; // Used to be assigned in PlayerConnection ctor but moved out so we can use shared_ptr 148 149 if(newPlayer) 150 { 151 int mapScale = 3; 152#ifdef _LARGE_WORLDS 153 int scale = MapItemSavedData::MAP_SIZE * 2 * (1 << mapScale); 154 int centreXC = (int) (Math::round(player->x / scale) * scale); 155 int centreZC = (int) (Math::round(player->z / scale) * scale); 156#else 157 // 4J-PB - for Xbox maps, we'll centre them on the origin of the world, since we can fit the whole world in our map 158 int centreXC = 0; 159 int centreZC = 0; 160#endif 161 // 4J Added - Give every player a map the first time they join a server 162 player->inventory->setItem( 9, shared_ptr<ItemInstance>( new ItemInstance(Item::map_Id, 1, level->getAuxValueForMap(player->getXuid(),0,centreXC, centreZC, mapScale ) ) ) ); 163 if(app.getGameRuleDefinitions() != NULL) 164 { 165 app.getGameRuleDefinitions()->postProcessPlayer(player); 166 } 167 } 168 169 if(!player->customTextureUrl.empty() && player->customTextureUrl.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl)) 170 { 171 if( server->getConnection()->addPendingTextureRequest(player->customTextureUrl)) 172 { 173#ifndef _CONTENT_PACKAGE 174 wprintf(L"Sending texture packet to get custom skin %ls from player %ls\n",player->customTextureUrl.c_str(), player->name.c_str()); 175#endif 176 playerConnection->send(shared_ptr<TextureAndGeometryPacket>( new TextureAndGeometryPacket(player->customTextureUrl,NULL,0) ) ); 177 } 178 } 179 else if(!player->customTextureUrl.empty() && app.IsFileInMemoryTextures(player->customTextureUrl)) 180 { 181 // Update the ref count on the memory texture data 182 app.AddMemoryTextureFile(player->customTextureUrl,NULL,0); 183 } 184 185 if(!player->customTextureUrl2.empty() && player->customTextureUrl2.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl2)) 186 { 187 if( server->getConnection()->addPendingTextureRequest(player->customTextureUrl2)) 188 { 189#ifndef _CONTENT_PACKAGE 190 wprintf(L"Sending texture packet to get custom skin %ls from player %ls\n",player->customTextureUrl2.c_str(), player->name.c_str()); 191#endif 192 playerConnection->send(shared_ptr<TexturePacket>( new TexturePacket(player->customTextureUrl2,NULL,0) ) ); 193 } 194 } 195 else if(!player->customTextureUrl2.empty() && app.IsFileInMemoryTextures(player->customTextureUrl2)) 196 { 197 // Update the ref count on the memory texture data 198 app.AddMemoryTextureFile(player->customTextureUrl2,NULL,0); 199 } 200 201 player->setIsGuest( packet->m_isGuest ); 202 203 Pos *spawnPos = level->getSharedSpawnPos(); 204 205 updatePlayerGameMode(player, nullptr, level); 206 207 // Update the privileges with the correct game mode 208 GameType *gameType = Player::getPlayerGamePrivilege(player->getAllPlayerGamePrivileges(),Player::ePlayerGamePrivilege_CreativeMode) ? GameType::CREATIVE : GameType::SURVIVAL; 209 gameType = LevelSettings::validateGameType(gameType->getId()); 210 if (player->gameMode->getGameModeForPlayer() != gameType) 211 { 212 player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_CreativeMode,player->gameMode->getGameModeForPlayer()->getId() ); 213 } 214 215 //shared_ptr<PlayerConnection> playerConnection = shared_ptr<PlayerConnection>(new PlayerConnection(server, connection, player)); 216 player->connection = playerConnection; // Used to be assigned in PlayerConnection ctor but moved out so we can use shared_ptr 217 218 // 4J Added to store UGC settings 219 playerConnection->m_friendsOnlyUGC = packet->m_friendsOnlyUGC; 220 playerConnection->m_offlineXUID = packet->m_offlineXuid; 221 playerConnection->m_onlineXUID = packet->m_onlineXuid; 222 223 // This player is now added to the list, so incrementing this value invalidates all previous PreLogin packets 224 if(packet->m_friendsOnlyUGC) ++server->m_ugcPlayersVersion; 225 226 addPlayerToReceiving( player ); 227 228 playerConnection->send( shared_ptr<LoginPacket>( new LoginPacket(L"", player->entityId, level->getLevelData()->getGenerator(), level->getSeed(), player->gameMode->getGameModeForPlayer()->getId(), 229 (byte) level->dimension->id, (byte) level->getMaxBuildHeight(), (byte) getMaxPlayers(), 230 level->difficulty, TelemetryManager->GetMultiplayerInstanceID(), (BYTE)playerIndex, level->useNewSeaLevel(), player->getAllPlayerGamePrivileges(), 231 level->getLevelData()->getXZSize(), level->getLevelData()->getHellScale() ) ) ); 232 playerConnection->send( shared_ptr<SetSpawnPositionPacket>( new SetSpawnPositionPacket(spawnPos->x, spawnPos->y, spawnPos->z) ) ); 233 playerConnection->send( shared_ptr<PlayerAbilitiesPacket>( new PlayerAbilitiesPacket(&player->abilities)) ); 234 playerConnection->send( shared_ptr<SetCarriedItemPacket>( new SetCarriedItemPacket(player->inventory->selected))); 235 delete spawnPos; 236 237 updateEntireScoreboard((ServerScoreboard *) level->getScoreboard(), player); 238 239 sendLevelInfo(player, level); 240 241 // 4J-PB - removed, since it needs to be localised in the language the client is in 242 //server->players->broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(L"�e" + playerEntity->name + L" joined the game.") ) ); 243 broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(player->name, ChatPacket::e_ChatPlayerJoinedGame) ) ); 244 245 MemSect(14); 246 add(player); 247 MemSect(0); 248 249 player->doTick(true, true, false); // 4J - added - force sending of the nearest chunk before the player is teleported, so we have somewhere to arrive on... 250 playerConnection->teleport(player->x, player->y, player->z, player->yRot, player->xRot); 251 252 server->getConnection()->addPlayerConnection(playerConnection); 253 playerConnection->send( shared_ptr<SetTimePacket>( new SetTimePacket(level->getGameTime(), level->getDayTime(), level->getGameRules()->getBoolean(GameRules::RULE_DAYLIGHT)) ) ); 254 255 AUTO_VAR(activeEffects, player->getActiveEffects()); 256 for(AUTO_VAR(it, activeEffects->begin()); it != activeEffects->end(); ++it) 257 { 258 MobEffectInstance *effect = *it; 259 playerConnection->send(shared_ptr<UpdateMobEffectPacket>( new UpdateMobEffectPacket(player->entityId, effect) ) ); 260 } 261 262 player->initMenu(); 263 264 if (playerTag != NULL && playerTag->contains(Entity::RIDING_TAG)) 265 { 266 // this player has been saved with a mount tag 267 shared_ptr<Entity> mount = EntityIO::loadStatic(playerTag->getCompound(Entity::RIDING_TAG), level); 268 if (mount != NULL) 269 { 270 mount->forcedLoading = true; 271 level->addEntity(mount); 272 player->ride(mount); 273 mount->forcedLoading = false; 274 } 275 } 276 277 // If we are joining at the same time as someone in the end on this system is travelling through the win portal, 278 // then we should set our wonGame flag to true so that respawning works when the EndPoem is closed 279 INetworkPlayer *thisPlayer = player->connection->getNetworkPlayer(); 280 if( thisPlayer != NULL ) 281 { 282 for(AUTO_VAR(it, players.begin()); it != players.end(); ++it) 283 { 284 shared_ptr<ServerPlayer> servPlayer = *it; 285 INetworkPlayer *checkPlayer = servPlayer->connection->getNetworkPlayer(); 286 if(thisPlayer != checkPlayer && checkPlayer != NULL && thisPlayer->IsSameSystem( checkPlayer ) && servPlayer->wonGame ) 287 { 288 player->wonGame = true; 289 break; 290 } 291 } 292 } 293} 294 295void PlayerList::updateEntireScoreboard(ServerScoreboard *scoreboard, shared_ptr<ServerPlayer> player) 296{ 297 //unordered_set<Objective *> objectives; 298 299 //for (PlayerTeam team : scoreboard->getPlayerTeams()) 300 //{ 301 // player->connection->send( shared_ptr<SetPlayerTeamPacket>(new SetPlayerTeamPacket(team, SetPlayerTeamPacket::METHOD_ADD))); 302 //} 303 304 //for (int slot = 0; slot < Scoreboard::DISPLAY_SLOTS; slot++) 305 //{ 306 // Objective objective = scoreboard->getDisplayObjective(slot); 307 308 // if (objective != NULL && !objectives->contains(objective)) 309 // { 310 // vector<shared_ptr<Packet> > *packets = scoreboard->getStartTrackingPackets(objective); 311 312 // for (Packet packet : packets) 313 // { 314 // player->connection->send(packet); 315 // } 316 317 // objectives->add(objective); 318 // } 319 //} 320} 321 322void PlayerList::setLevel(ServerLevelArray levels) 323{ 324 playerIo = levels[0]->getLevelStorage()->getPlayerIO(); 325} 326 327void PlayerList::changeDimension(shared_ptr<ServerPlayer> player, ServerLevel *from) 328{ 329 ServerLevel *to = player->getLevel(); 330 331 if (from != NULL) from->getChunkMap()->remove(player); 332 to->getChunkMap()->add(player); 333 334 to->cache->create(((int) player->x) >> 4, ((int) player->z) >> 4); 335} 336 337int PlayerList::getMaxRange() 338{ 339 return PlayerChunkMap::convertChunkRangeToBlock(getViewDistance()); 340} 341 342CompoundTag *PlayerList::load(shared_ptr<ServerPlayer> player) 343{ 344 return playerIo->load(player); 345} 346 347void PlayerList::save(shared_ptr<ServerPlayer> player) 348{ 349 playerIo->save(player); 350} 351 352// 4J Stu - TU-1 hotifx 353// Add this function to take some of the code from the PlayerList::add function with the fixes 354// for checking spawn area, especially in the nether. These needed to be done in a different order from before 355// Fix for #13150 - When a player loads/joins a game after saving/leaving in the nether, sometimes they are spawned on top of the nether and cannot mine down 356void PlayerList::validatePlayerSpawnPosition(shared_ptr<ServerPlayer> player) 357{ 358 // 4J Stu - Some adjustments to make sure the current players position is correct 359 // Make sure that the player is on the ground, and in the centre x/z of the current column 360 app.DebugPrintf("Original pos is %f, %f, %f in dimension %d\n", player->x, player->y, player->z, player->dimension); 361 362 bool spawnForced = player->isRespawnForced(); 363 364 double targetX = 0; 365 if(player->x < 0) targetX = Mth::ceil(player->x) - 0.5; 366 else targetX = Mth::floor(player->x) + 0.5; 367 368 double targetY = floor(player->y); 369 370 double targetZ = 0; 371 if(player->z < 0) targetZ = Mth::ceil(player->z) - 0.5; 372 else targetZ = Mth::floor(player->z) + 0.5; 373 374 player->setPos(targetX, targetY, targetZ); 375 376 app.DebugPrintf("New pos is %f, %f, %f in dimension %d\n", player->x, player->y, player->z, player->dimension); 377 378 ServerLevel *level = server->getLevel(player->dimension); 379 while (level->getCubes(player, player->bb)->size() != 0) 380 { 381 player->setPos(player->x, player->y + 1, player->z); 382 } 383 app.DebugPrintf("Final pos is %f, %f, %f in dimension %d\n", player->x, player->y, player->z, player->dimension); 384 385 // 4J Stu - If we are in the nether and the above while loop has put us above the nether then we have a problem 386 // Finding a valid, safe spawn point is potentially computationally expensive (may have to hunt through a large part 387 // of the nether) so move the player to their spawn position in the overworld so that they do not lose their inventory 388 // 4J Stu - We also use this mechanism to force a spawn point in the overworld for players who were in the save when the reset nether option was applied 389 if(level->dimension->id == -1 && player->y > 125) 390 { 391 app.DebugPrintf("Player in the nether tried to spawn at y = %f, moving to overworld\n", player->y); 392 player->setLevel(server->getLevel(0)); 393 player->gameMode->setLevel(server->getLevel(0)); 394 player->dimension = 0; 395 396 level = server->getLevel(player->dimension); 397 398 Pos *levelSpawn = level->getSharedSpawnPos(); 399 player->setPos(levelSpawn->x, levelSpawn->y, levelSpawn->z); 400 delete levelSpawn; 401 402 Pos *bedPosition = player->getRespawnPosition(); 403 if (bedPosition != NULL) 404 { 405 Pos *respawnPosition = Player::checkBedValidRespawnPosition(server->getLevel(player->dimension), bedPosition, spawnForced); 406 if (respawnPosition != NULL) 407 { 408 player->moveTo(respawnPosition->x + 0.5f, respawnPosition->y + 0.1f, respawnPosition->z + 0.5f, 0, 0); 409 player->setRespawnPosition(bedPosition, spawnForced); 410 } 411 delete bedPosition; 412 } 413 while (level->getCubes(player, player->bb)->size() != 0) 414 { 415 player->setPos(player->x, player->y + 1, player->z); 416 } 417 418 app.DebugPrintf("Updated pos is %f, %f, %f in dimension %d\n", player->x, player->y, player->z, player->dimension); 419 } 420} 421 422void PlayerList::add(shared_ptr<ServerPlayer> player) 423{ 424 //broadcastAll(shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket(player->name, true, 1000) ) ); 425 if( player->connection->getNetworkPlayer() ) 426 { 427 broadcastAll(shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket( player ) ) ); 428 } 429 430 players.push_back(player); 431 432 // 4J Added 433 addPlayerToReceiving(player); 434 435 // Ensure the area the player is spawning in is loaded! 436 ServerLevel *level = server->getLevel(player->dimension); 437 438 // 4J Stu - TU-1 hotfix 439 // Fix for #13150 - When a player loads/joins a game after saving/leaving in the nether, sometimes they are spawned on top of the nether and cannot mine down 440 // Some code from here has been moved to the above validatePlayerSpawnPosition function 441 442 // 4J Stu - Swapped these lines about so that we get the chunk visiblity packet way ahead of all the add tracked entity packets 443 // Fix for #9169 - ART : Sign text is replaced with the words �Awaiting approval�. 444 changeDimension(player, NULL); 445 level->addEntity(player); 446 447 for (int i = 0; i < players.size(); i++) 448 { 449 shared_ptr<ServerPlayer> op = players.at(i); 450 //player->connection->send(shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket(op->name, true, op->latency) ) ); 451 if( op->connection->getNetworkPlayer() ) 452 { 453 player->connection->send(shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket( op ) ) ); 454 } 455 } 456 457 if(level->isAtLeastOnePlayerSleeping()) 458 { 459 shared_ptr<ServerPlayer> firstSleepingPlayer = nullptr; 460 for (unsigned int i = 0; i < players.size(); i++) 461 { 462 shared_ptr<ServerPlayer> thisPlayer = players[i]; 463 if(thisPlayer->isSleeping()) 464 { 465 if(firstSleepingPlayer == NULL) firstSleepingPlayer = thisPlayer; 466 thisPlayer->connection->send(shared_ptr<ChatPacket>( new ChatPacket(thisPlayer->name, ChatPacket::e_ChatBedMeSleep))); 467 } 468 } 469 player->connection->send(shared_ptr<ChatPacket>( new ChatPacket(firstSleepingPlayer->name, ChatPacket::e_ChatBedPlayerSleep))); 470 } 471} 472 473void PlayerList::move(shared_ptr<ServerPlayer> player) 474{ 475 player->getLevel()->getChunkMap()->move(player); 476} 477 478void PlayerList::remove(shared_ptr<ServerPlayer> player) 479{ 480 save(player); 481 //4J Stu - We don't want to save the map data for guests, so when we are sure that the player is gone delete the map 482 if(player->isGuest()) playerIo->deleteMapFilesForPlayer(player); 483 ServerLevel *level = player->getLevel(); 484if (player->riding != NULL) 485 { 486 level->removeEntityImmediately(player->riding); 487 app.DebugPrintf("removing player mount"); 488 } 489 level->getTracker()->removeEntity(player); 490 level->removeEntity(player); 491 level->getChunkMap()->remove(player); 492 AUTO_VAR(it, find(players.begin(),players.end(),player)); 493 if( it != players.end() ) 494 { 495 players.erase(it); 496 } 497 //broadcastAll(shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket(player->name, false, 9999) ) ); 498 499 removePlayerFromReceiving(player); 500 player->connection = nullptr; // Must remove reference to connection, or else there is a circular dependency 501 delete player->gameMode; // Gamemode also needs deleted as it references back to this player 502 player->gameMode = NULL; 503 504 // 4J Stu - Save all the players currently in the game, which will also free up unused map id slots if required, and remove old players 505 saveAll(NULL,false); 506} 507 508shared_ptr<ServerPlayer> PlayerList::getPlayerForLogin(PendingConnection *pendingConnection, const wstring& userName, PlayerUID xuid, PlayerUID onlineXuid) 509{ 510#ifdef _WINDOWS64 511 if (players.size() >= (unsigned int)MINECRAFT_NET_MAX_PLAYERS) 512#else 513 if (players.size() >= (unsigned int)maxPlayers) 514#endif 515 { 516 pendingConnection->disconnect(DisconnectPacket::eDisconnect_ServerFull); 517 return shared_ptr<ServerPlayer>(); 518 } 519 shared_ptr<ServerPlayer> player = shared_ptr<ServerPlayer>(new ServerPlayer(server, server->getLevel(0), userName, new ServerPlayerGameMode(server->getLevel(0)) )); 520 player->gameMode->player = player; // 4J added as had to remove this assignment from ServerPlayer ctor 521 player->setXuid( xuid ); // 4J Added 522 player->setOnlineXuid( onlineXuid ); // 4J Added 523#ifdef _WINDOWS64 524 { 525 INetworkPlayer* np = pendingConnection->connection->getSocket()->getPlayer(); 526 if (np != NULL) 527 { 528 PlayerUID realXuid = np->GetUID(); 529 player->setXuid(realXuid); 530 player->setOnlineXuid(realXuid); 531 } 532 } 533#endif 534 // Work out the base server player settings 535 INetworkPlayer *networkPlayer = pendingConnection->connection->getSocket()->getPlayer(); 536 if(networkPlayer != NULL && !networkPlayer->IsHost()) 537 { 538 player->enableAllPlayerPrivileges( app.GetGameHostOption(eGameHostOption_TrustPlayers)>0 ); 539 } 540 541 // 4J Added 542 LevelRuleset *serverRuleDefs = app.getGameRuleDefinitions(); 543 if(serverRuleDefs != NULL) 544 { 545 player->gameMode->setGameRules( GameRuleDefinition::generateNewGameRulesInstance(GameRulesInstance::eGameRulesInstanceType_ServerPlayer, serverRuleDefs, pendingConnection->connection) ); 546 } 547 548 return player; 549} 550 551shared_ptr<ServerPlayer> PlayerList::respawn(shared_ptr<ServerPlayer> serverPlayer, int targetDimension, bool keepAllPlayerData) 552{ 553 // How we handle the entity tracker depends on whether we are the primary player currently, and whether there will be any player in the same system in the same dimension once we finish respawning. 554 bool isPrimary = canReceiveAllPackets(serverPlayer); // Is this the primary player in its current dimension? 555 int oldDimension = serverPlayer->dimension; 556 bool isEmptying = ( targetDimension != oldDimension); // We're not emptying this dimension on this machine if this player is going back into the same dimension 557 558 // Also consider if there is another player on this machine which is in the same dimension and can take over as primary player 559 if( isEmptying ) 560 { 561 INetworkPlayer *thisPlayer = serverPlayer->connection->getNetworkPlayer(); 562 563 for( unsigned int i = 0; i < players.size(); i++ ) 564 { 565 shared_ptr<ServerPlayer> ep = players[i]; 566 if( ep == serverPlayer ) continue; 567 if( ep->dimension != oldDimension ) continue; 568 569 INetworkPlayer * otherPlayer = ep->connection->getNetworkPlayer(); 570 if( otherPlayer != NULL && thisPlayer->IsSameSystem(otherPlayer) ) 571 { 572 // There's another player here in the same dimension - we're not the last one out 573 isEmptying = false; 574 } 575 } 576 } 577 578 // Now we know where we stand, the actions to take are as follows: 579 // (1) if this isn't the primary player, then we just need to remove it from the entity tracker 580 // (2) if this Is the primary player then: 581 // (a) if isEmptying is true, then remove the player from the tracker, and send "remove entity" packets for anything seen (this is the original behaviour of the code) 582 // (b) if isEmptying is false, then we'll be transferring control of entity tracking to another player 583 584 if( isPrimary ) 585 { 586 if( isEmptying ) 587 { 588 app.DebugPrintf("Emptying this dimension\n"); 589 serverPlayer->getLevel()->getTracker()->clear(serverPlayer); 590 } 591 else 592 { 593 app.DebugPrintf("Transferring... storing flags\n"); 594 serverPlayer->getLevel()->getTracker()->removeEntity(serverPlayer); 595 } 596 } 597 else 598 { 599 app.DebugPrintf("Not primary player\n"); 600 serverPlayer->getLevel()->getTracker()->removeEntity(serverPlayer); 601 } 602 603 serverPlayer->getLevel()->getChunkMap()->remove(serverPlayer); 604 AUTO_VAR(it, find(players.begin(),players.end(),serverPlayer)); 605 if( it != players.end() ) 606 { 607 players.erase(it); 608 } 609 server->getLevel(serverPlayer->dimension)->removeEntityImmediately(serverPlayer); 610 611 Pos *bedPosition = serverPlayer->getRespawnPosition(); 612 bool spawnForced = serverPlayer->isRespawnForced(); 613 614 removePlayerFromReceiving(serverPlayer); 615 serverPlayer->dimension = targetDimension; 616 617 EDefaultSkins skin = serverPlayer->getPlayerDefaultSkin(); 618 DWORD playerIndex = serverPlayer->getPlayerIndex(); 619 620 PlayerUID playerXuid = serverPlayer->getXuid(); 621 PlayerUID playerOnlineXuid = serverPlayer->getOnlineXuid(); 622 623 shared_ptr<ServerPlayer> player = shared_ptr<ServerPlayer>(new ServerPlayer(server, server->getLevel(serverPlayer->dimension), serverPlayer->getName(), new ServerPlayerGameMode(server->getLevel(serverPlayer->dimension)))); 624 player->connection = serverPlayer->connection; 625 player->restoreFrom(serverPlayer, keepAllPlayerData); 626 if (keepAllPlayerData) 627 { 628 // Fix for #81759 - TU9: Content: Gameplay: Entering The End Exit Portal replaces the Player's currently held item with the first one from the Quickbar 629 player->inventory->selected = serverPlayer->inventory->selected; 630 } 631 player->gameMode->player = player; // 4J added as had to remove this assignment from ServerPlayer ctor 632 player->setXuid( playerXuid ); // 4J Added 633 player->setOnlineXuid( playerOnlineXuid ); // 4J Added 634 635 // 4J Stu - Don't reuse the id. If we do, then the player can be re-added after being removed, but the add packet gets sent before the remove packet 636 //player->entityId = serverPlayer->entityId; 637 638 player->setPlayerDefaultSkin( skin ); 639 player->setIsGuest( serverPlayer->isGuest() ); 640 player->setPlayerIndex( playerIndex ); 641 player->setCustomSkin( serverPlayer->getCustomSkin() ); 642 player->setCustomCape( serverPlayer->getCustomCape() ); 643 player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, serverPlayer->getAllPlayerGamePrivileges()); 644 player->gameMode->setGameRules( serverPlayer->gameMode->getGameRules() ); 645 player->dimension = targetDimension; 646 647 // 4J Stu - Added this as we need to know earlier if the player is the player for this connection so that 648 // we can work out if they are the primary for the system and can receive all packets 649 player->connection->setPlayer( player ); 650 651 addPlayerToReceiving(player); 652 653 ServerLevel *level = server->getLevel(serverPlayer->dimension); 654 655 // reset the player's game mode (first pick from old, then copy level if 656 // necessary) 657 updatePlayerGameMode(player, serverPlayer, level); 658 659 if(serverPlayer->wonGame && targetDimension == oldDimension && serverPlayer->getHealth() > 0) 660 { 661 // If the player is still alive and respawning to the same dimension, they are just being added back from someone else viewing the Win screen 662 player->moveTo(serverPlayer->x, serverPlayer->y, serverPlayer->z, serverPlayer->yRot, serverPlayer->xRot); 663 if(bedPosition != NULL) 664 { 665 player->setRespawnPosition(bedPosition, spawnForced); 666 delete bedPosition; 667 } 668 // Fix for #81759 - TU9: Content: Gameplay: Entering The End Exit Portal replaces the Player's currently held item with the first one from the Quickbar 669 player->inventory->selected = serverPlayer->inventory->selected; 670 } 671 else if (bedPosition != NULL) 672 { 673 Pos *respawnPosition = Player::checkBedValidRespawnPosition(server->getLevel(serverPlayer->dimension), bedPosition, spawnForced); 674 if (respawnPosition != NULL) 675 { 676 player->moveTo(respawnPosition->x + 0.5f, respawnPosition->y + 0.1f, respawnPosition->z + 0.5f, 0, 0); 677 player->setRespawnPosition(bedPosition, spawnForced); 678 } 679 else 680 { 681 player->connection->send( shared_ptr<GameEventPacket>( new GameEventPacket(GameEventPacket::NO_RESPAWN_BED_AVAILABLE, 0) ) ); 682 } 683 delete bedPosition; 684 } 685 686 // Ensure the area the player is spawning in is loaded! 687 level->cache->create(((int) player->x) >> 4, ((int) player->z) >> 4); 688 689 while (!level->getCubes(player, player->bb)->empty()) 690 { 691 player->setPos(player->x, player->y + 1, player->z); 692 } 693 694 player->connection->send( shared_ptr<RespawnPacket>( new RespawnPacket((char) player->dimension, player->level->getSeed(), player->level->getMaxBuildHeight(), 695 player->gameMode->getGameModeForPlayer(), level->difficulty, level->getLevelData()->getGenerator(), 696 player->level->useNewSeaLevel(), player->entityId, level->getLevelData()->getXZSize(), level->getLevelData()->getHellScale()) ) ); 697 player->connection->teleport(player->x, player->y, player->z, player->yRot, player->xRot); 698 player->connection->send( shared_ptr<SetExperiencePacket>( new SetExperiencePacket(player->experienceProgress, player->totalExperience, player->experienceLevel)) ); 699 700 if(keepAllPlayerData) 701 { 702 vector<MobEffectInstance *> *activeEffects = player->getActiveEffects(); 703 for(AUTO_VAR(it, activeEffects->begin()); it != activeEffects->end(); ++it) 704 { 705 MobEffectInstance *effect = *it; 706 707 player->connection->send(shared_ptr<UpdateMobEffectPacket>( new UpdateMobEffectPacket(player->entityId, effect) ) ); 708 } 709 delete activeEffects; 710 player->getEntityData()->markDirty(Mob::DATA_EFFECT_COLOR_ID); 711 } 712 713 sendLevelInfo(player, level); 714 715 level->getChunkMap()->add(player); 716 level->addEntity(player); 717 players.push_back(player); 718 719 player->initMenu(); 720 player->setHealth(player->getHealth()); 721 722 // 4J-JEV - Dying before this point in the tutorial is pretty annoying, 723 // making sure to remove health/hunger and give you back your meat. 724 if( Minecraft::GetInstance()->isTutorial() 725 && (!Minecraft::GetInstance()->gameMode->getTutorial()->isStateCompleted(e_Tutorial_State_Food_Bar)) ) 726 { 727 app.getGameRuleDefinitions()->postProcessPlayer(player); 728 } 729 730 if( oldDimension == 1 && player->dimension != 1 ) 731 { 732 player->displayClientMessage(IDS_PLAYER_LEFT_END); 733 } 734 735 return player; 736 737} 738 739void PlayerList::toggleDimension(shared_ptr<ServerPlayer> player, int targetDimension) 740{ 741 int lastDimension = player->dimension; 742 // How we handle the entity tracker depends on whether we are the primary player currently, and whether there will be any player in the same system in the same dimension once we finish respawning. 743 bool isPrimary = canReceiveAllPackets(player); // Is this the primary player in its current dimension? 744 bool isEmptying = true; 745 746 // Also consider if there is another player on this machine which is in the same dimension and can take over as primary player 747 INetworkPlayer *thisPlayer = player->connection->getNetworkPlayer(); 748 749 for( unsigned int i = 0; i < players.size(); i++ ) 750 { 751 shared_ptr<ServerPlayer> ep = players[i]; 752 if( ep == player ) continue; 753 if( ep->dimension != lastDimension ) continue; 754 755 INetworkPlayer * otherPlayer = ep->connection->getNetworkPlayer(); 756 if( otherPlayer != NULL && thisPlayer->IsSameSystem(otherPlayer) ) 757 { 758 // There's another player here in the same dimension - we're not the last one out 759 isEmptying = false; 760 } 761 } 762 763 764 // Now we know where we stand, the actions to take are as follows: 765 // (1) if this isn't the primary player, then we just need to remove it from the entity tracker 766 // (2) if this Is the primary player then: 767 // (a) if isEmptying is true, then remove the player from the tracker, and send "remove entity" packets for anything seen (this is the original behaviour of the code) 768 // (b) if isEmptying is false, then we'll be transferring control of entity tracking to another player 769 770 if( isPrimary ) 771 { 772 if( isEmptying ) 773 { 774 app.DebugPrintf("Toggle... Emptying this dimension\n"); 775 player->getLevel()->getTracker()->clear(player); 776 } 777 else 778 { 779 app.DebugPrintf("Toggle... transferring\n"); 780 player->getLevel()->getTracker()->removeEntity(player); 781 } 782 } 783 else 784 { 785 app.DebugPrintf("Toggle... Not primary player\n"); 786 player->getLevel()->getTracker()->removeEntity(player); 787 } 788 789 ServerLevel *oldLevel = server->getLevel(player->dimension); 790 791 // 4J Stu - Do this much earlier so we don't end up unloading chunks in the wrong dimension 792 player->getLevel()->getChunkMap()->remove(player); 793 794 if(player->dimension != 1 && targetDimension == 1) 795 { 796 player->displayClientMessage(IDS_PLAYER_ENTERED_END); 797 } 798 else if( player->dimension == 1 ) 799 { 800 player->displayClientMessage(IDS_PLAYER_LEFT_END); 801 } 802 803 player->dimension = targetDimension; 804 805 ServerLevel *newLevel = server->getLevel(player->dimension); 806 807 // 4J Stu - Fix for #46423 - TU5: Art: Code: No burning animation visible after entering The Nether while burning 808 player->clearFire(); // Stop burning if travelling through a portal 809 810 // 4J Stu Added so that we remove entities from the correct level, after the respawn packet we will be in the wrong level 811 player->flushEntitiesToRemove(); 812 813 player->connection->send( shared_ptr<RespawnPacket>( new RespawnPacket((char) player->dimension, newLevel->getSeed(), newLevel->getMaxBuildHeight(), 814 player->gameMode->getGameModeForPlayer(), newLevel->difficulty, newLevel->getLevelData()->getGenerator(), 815 newLevel->useNewSeaLevel(), player->entityId, newLevel->getLevelData()->getXZSize(), newLevel->getLevelData()->getHellScale()) ) ); 816 817 oldLevel->removeEntityImmediately(player); 818 player->removed = false; 819 820 repositionAcrossDimension(player, lastDimension, oldLevel, newLevel); 821 changeDimension(player, oldLevel); 822 823 player->gameMode->setLevel(newLevel); 824 825 // Resend the teleport if we haven't yet sent the chunk they will land on 826 if( !g_NetworkManager.SystemFlagGet(player->connection->getNetworkPlayer(),ServerPlayer::getFlagIndexForChunk( ChunkPos(player->xChunk,player->zChunk), player->level->dimension->id ) ) ) 827 { 828 player->connection->teleport(player->x, player->y, player->z, player->yRot, player->xRot, false); 829 // Force sending of the current chunk 830 player->doTick(true, true, true); 831 } 832 833 player->connection->teleport(player->x, player->y, player->z, player->yRot, player->xRot); 834 835 // 4J Stu - Fix for #64683 - Customer Encountered: TU7: Content: Gameplay: Potion effects are removed after using the Nether Portal 836 vector<MobEffectInstance *> *activeEffects = player->getActiveEffects(); 837 for(AUTO_VAR(it, activeEffects->begin()); it != activeEffects->end(); ++it) 838 { 839 MobEffectInstance *effect = *it; 840 841 player->connection->send(shared_ptr<UpdateMobEffectPacket>( new UpdateMobEffectPacket(player->entityId, effect) ) ); 842 } 843 delete activeEffects; 844 player->getEntityData()->markDirty(Mob::DATA_EFFECT_COLOR_ID); 845 846 sendLevelInfo(player, newLevel); 847 sendAllPlayerInfo(player); 848} 849 850void PlayerList::repositionAcrossDimension(shared_ptr<Entity> entity, int lastDimension, ServerLevel *oldLevel, ServerLevel *newLevel) 851{ 852 double xt = entity->x; 853 double zt = entity->z; 854 double xOriginal = entity->x; 855 double yOriginal = entity->y; 856 double zOriginal = entity->z; 857 float yRotOriginal = entity->yRot; 858 double scale = newLevel->getLevelData()->getHellScale(); // 4J Scale was 8 but this is all we can fit in 859 if (entity->dimension == -1) 860 { 861 xt /= scale; 862 zt /= scale; 863 entity->moveTo(xt, entity->y, zt, entity->yRot, entity->xRot); 864 if (entity->isAlive()) 865 { 866 oldLevel->tick(entity, false); 867 } 868 } 869 else if (entity->dimension == 0) 870 { 871 xt *= scale; 872 zt *= scale; 873 entity->moveTo(xt, entity->y, zt, entity->yRot, entity->xRot); 874 if (entity->isAlive()) 875 { 876 oldLevel->tick(entity, false); 877 } 878 } 879 else 880 { 881 Pos *p; 882 883 if (lastDimension == 1) 884 { 885 // Coming from the end 886 p = newLevel->getSharedSpawnPos(); 887 } 888 else 889 { 890 // Going to the end 891 p = newLevel->getDimensionSpecificSpawn(); 892 } 893 894 xt = p->x; 895 entity->y = p->y; 896 zt = p->z; 897 delete p; 898 entity->moveTo(xt, entity->y, zt, 90, 0); 899 if (entity->isAlive()) 900 { 901 oldLevel->tick(entity, false); 902 } 903 } 904 905 if(entity->GetType() == eTYPE_SERVERPLAYER) 906 { 907 shared_ptr<ServerPlayer> player = dynamic_pointer_cast<ServerPlayer>(entity); 908 removePlayerFromReceiving(player, false, lastDimension); 909 addPlayerToReceiving(player); 910 } 911 912 if (lastDimension != 1) 913 { 914 xt = (double) Mth::clamp((int) xt, -Level::MAX_LEVEL_SIZE + 128, Level::MAX_LEVEL_SIZE - 128); 915 zt = (double) Mth::clamp((int) zt, -Level::MAX_LEVEL_SIZE + 128, Level::MAX_LEVEL_SIZE - 128); 916 if (entity->isAlive()) 917 { 918 newLevel->addEntity(entity); 919 entity->moveTo(xt, entity->y, zt, entity->yRot, entity->xRot); 920 newLevel->tick(entity, false); 921 newLevel->cache->autoCreate = true; 922 newLevel->getPortalForcer()->force(entity, xOriginal, yOriginal, zOriginal, yRotOriginal); 923 newLevel->cache->autoCreate = false; 924 } 925 } 926 927 entity->setLevel(newLevel); 928} 929 930void PlayerList::tick() 931{ 932 // 4J - brought changes to how often this is sent forward from 1.2.3 933 if (++sendAllPlayerInfoIn > SEND_PLAYER_INFO_INTERVAL) 934 { 935 sendAllPlayerInfoIn = 0; 936 } 937 938 if (sendAllPlayerInfoIn < players.size()) 939 { 940 shared_ptr<ServerPlayer> op = players[sendAllPlayerInfoIn]; 941 //broadcastAll(shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket(op->name, true, op->latency) ) ); 942 if( op->connection->getNetworkPlayer() ) 943 { 944 broadcastAll(shared_ptr<PlayerInfoPacket>( new PlayerInfoPacket( op ) ) ); 945 } 946 } 947 948 EnterCriticalSection(&m_closePlayersCS); 949 while(!m_smallIdsToClose.empty()) 950 { 951 BYTE smallId = m_smallIdsToClose.front(); 952 m_smallIdsToClose.pop_front(); 953 954 shared_ptr<ServerPlayer> player = nullptr; 955 956 for(unsigned int i = 0; i < players.size(); i++) 957 { 958 shared_ptr<ServerPlayer> p = players.at(i); 959 // 4J Stu - May be being a bit overprotective with all the NULL checks, but adding late in TU7 so want to be safe 960 if (p != NULL && p->connection != NULL && p->connection->connection != NULL && p->connection->connection->getSocket() != NULL && p->connection->connection->getSocket()->getSmallId() == smallId ) 961 { 962 player = p; 963 break; 964 } 965 } 966 967 if (player != NULL) 968 { 969 player->connection->disconnect( DisconnectPacket::eDisconnect_Closed ); 970 } 971 } 972 LeaveCriticalSection(&m_closePlayersCS); 973 974 EnterCriticalSection(&m_kickPlayersCS); 975 while(!m_smallIdsToKick.empty()) 976 { 977 BYTE smallId = m_smallIdsToKick.front(); 978 m_smallIdsToKick.pop_front(); 979 INetworkPlayer *selectedPlayer = g_NetworkManager.GetPlayerBySmallId(smallId); 980 if( selectedPlayer != NULL ) 981 { 982 if( selectedPlayer->IsLocal() != TRUE ) 983 { 984 //#ifdef _XBOX 985 PlayerUID xuid = selectedPlayer->GetUID(); 986 // Kick this player from the game 987 shared_ptr<ServerPlayer> player = nullptr; 988 989 for(unsigned int i = 0; i < players.size(); i++) 990 { 991 shared_ptr<ServerPlayer> p = players.at(i); 992 PlayerUID playersXuid = p->getOnlineXuid(); 993 if (p != NULL && ProfileManager.AreXUIDSEqual(playersXuid, xuid ) ) 994 { 995 player = p; 996 break; 997 } 998 } 999 1000 if (player != NULL) 1001 { 1002 m_bannedXuids.push_back( player->getOnlineXuid() ); 1003 // 4J Stu - If we have kicked a player, make sure that they have no privileges if they later try to join the world when trust players is off 1004 player->enableAllPlayerPrivileges( false ); 1005 player->connection->setWasKicked(); 1006 player->connection->send( shared_ptr<DisconnectPacket>( new DisconnectPacket(DisconnectPacket::eDisconnect_Kicked) )); 1007 } 1008 //#endif 1009 } 1010 } 1011 } 1012 LeaveCriticalSection(&m_kickPlayersCS); 1013 1014 // Check our receiving players, and if they are dead see if we can replace them 1015 for(unsigned int dim = 0; dim < 2; ++dim) 1016 { 1017 for(unsigned int i = 0; i < receiveAllPlayers[dim].size(); ++i) 1018 { 1019 shared_ptr<ServerPlayer> currentPlayer = receiveAllPlayers[dim][i]; 1020 if(currentPlayer->removed) 1021 { 1022 shared_ptr<ServerPlayer> newPlayer = findAlivePlayerOnSystem(currentPlayer); 1023 if(newPlayer != NULL) 1024 { 1025 receiveAllPlayers[dim][i] = newPlayer; 1026 app.DebugPrintf("Replacing primary player %ls with %ls in dimension %d\n", currentPlayer->name.c_str(), newPlayer->name.c_str(), dim); 1027 } 1028 } 1029 } 1030 } 1031} 1032 1033bool PlayerList::isTrackingTile(int x, int y, int z, int dimension) 1034{ 1035 return server->getLevel(dimension)->getChunkMap()->isTrackingTile(x, y, z); 1036} 1037 1038// 4J added - make sure that any tile updates for the chunk at this location get prioritised for sending 1039void PlayerList::prioritiseTileChanges(int x, int y, int z, int dimension) 1040{ 1041 server->getLevel(dimension)->getChunkMap()->prioritiseTileChanges(x, y, z); 1042} 1043 1044void PlayerList::broadcastAll(shared_ptr<Packet> packet) 1045{ 1046 for (unsigned int i = 0; i < players.size(); i++) 1047 { 1048 shared_ptr<ServerPlayer> player = players[i]; 1049 player->connection->send(packet); 1050 } 1051} 1052 1053void PlayerList::broadcastAll(shared_ptr<Packet> packet, int dimension) 1054{ 1055 for (unsigned int i = 0; i < players.size(); i++) 1056 { 1057 shared_ptr<ServerPlayer> player = players[i]; 1058 if (player->dimension == dimension) player->connection->send(packet); 1059 } 1060} 1061 1062wstring PlayerList::getPlayerNames() 1063{ 1064 wstring msg; 1065 for (unsigned int i = 0; i < players.size(); i++) 1066 { 1067 if (i > 0) msg += L", "; 1068 msg += players[i]->name; 1069 } 1070 return msg; 1071} 1072 1073bool PlayerList::isWhiteListed(const wstring& name) 1074{ 1075 return true; 1076} 1077 1078bool PlayerList::isOp(const wstring& name) 1079{ 1080 return false; 1081} 1082 1083bool PlayerList::isOp(shared_ptr<ServerPlayer> player) 1084{ 1085 bool cheatsEnabled = app.GetGameHostOption(eGameHostOption_CheatsEnabled); 1086#ifdef _DEBUG_MENUS_ENABLED 1087 cheatsEnabled = cheatsEnabled || app.GetUseDPadForDebug(); 1088#endif 1089 INetworkPlayer *networkPlayer = player->connection->getNetworkPlayer(); 1090 bool isOp = cheatsEnabled && (player->isModerator() || (networkPlayer != NULL && networkPlayer->IsHost())); 1091 return isOp; 1092} 1093 1094shared_ptr<ServerPlayer> PlayerList::getPlayer(const wstring& name) 1095{ 1096 for (unsigned int i = 0; i < players.size(); i++) 1097 { 1098 shared_ptr<ServerPlayer> p = players[i]; 1099 if (p->name == name) // 4J - used to be case insensitive (using equalsIgnoreCase) - imagine we'll be shifting to XUIDs anyway 1100 { 1101 return p; 1102 } 1103 } 1104 return nullptr; 1105} 1106 1107// 4J Added 1108shared_ptr<ServerPlayer> PlayerList::getPlayer(PlayerUID uid) 1109{ 1110 for (unsigned int i = 0; i < players.size(); i++) 1111 { 1112 shared_ptr<ServerPlayer> p = players[i]; 1113 if (p->getXuid() == uid || p->getOnlineXuid() == uid) // 4J - used to be case insensitive (using equalsIgnoreCase) - imagine we'll be shifting to XUIDs anyway 1114 { 1115 return p; 1116 } 1117 } 1118 return nullptr; 1119} 1120 1121shared_ptr<ServerPlayer> PlayerList::getNearestPlayer(Pos *position, int range) 1122{ 1123 if (players.empty()) return nullptr; 1124 if (position == NULL) return players.at(0); 1125 shared_ptr<ServerPlayer> current = nullptr; 1126 double dist = -1; 1127 int rangeSqr = range * range; 1128 1129 for (int i = 0; i < players.size(); i++) 1130 { 1131 shared_ptr<ServerPlayer> next = players.at(i); 1132 double newDist = position->distSqr(next->getCommandSenderWorldPosition()); 1133 1134 if ((dist == -1 || newDist < dist) && (range <= 0 || newDist <= rangeSqr)) 1135 { 1136 dist = newDist; 1137 current = next; 1138 } 1139 } 1140 1141 return current; 1142} 1143 1144vector<ServerPlayer> *PlayerList::getPlayers(Pos *position, int rangeMin, int rangeMax, int count, int mode, int levelMin, int levelMax, unordered_map<wstring, int> *scoreRequirements, const wstring &playerName, const wstring &teamName, Level *level) 1145{ 1146 app.DebugPrintf("getPlayers NOT IMPLEMENTED!"); 1147 return NULL; 1148 1149 /*if (players.empty()) return NULL; 1150 vector<shared_ptr<ServerPlayer> > result = new vector<shared_ptr<ServerPlayer> >(); 1151 bool reverse = count < 0; 1152 bool playerNameNot = !playerName.empty() && playerName.startsWith("!"); 1153 bool teamNameNot = !teamName.empty() && teamName.startsWith("!"); 1154 int rangeMinSqr = rangeMin * rangeMin; 1155 int rangeMaxSqr = rangeMax * rangeMax; 1156 count = Mth.abs(count); 1157 1158 if (playerNameNot) playerName = playerName.substring(1); 1159 if (teamNameNot) teamName = teamName.substring(1); 1160 1161 for (int i = 0; i < players.size(); i++) { 1162 ServerPlayer player = players.get(i); 1163 1164 if (level != null && player.level != level) continue; 1165 if (playerName != null) { 1166 if (playerNameNot == playerName.equalsIgnoreCase(player.getAName())) continue; 1167 } 1168 if (teamName != null) { 1169 Team team = player.getTeam(); 1170 String actualName = team == null ? "" : team.getName(); 1171 if (teamNameNot == teamName.equalsIgnoreCase(actualName)) continue; 1172 } 1173 1174 if (position != null && (rangeMin > 0 || rangeMax > 0)) { 1175 float distance = position.distSqr(player.getCommandSenderWorldPosition()); 1176 if (rangeMin > 0 && distance < rangeMinSqr) continue; 1177 if (rangeMax > 0 && distance > rangeMaxSqr) continue; 1178 } 1179 1180 if (!meetsScoreRequirements(player, scoreRequirements)) continue; 1181 1182 if (mode != GameType.NOT_SET.getId() && mode != player.gameMode.getGameModeForPlayer().getId()) continue; 1183 if (levelMin > 0 && player.experienceLevel < levelMin) continue; 1184 if (player.experienceLevel > levelMax) continue; 1185 1186 result.add(player); 1187 } 1188 1189 if (position != null) Collections.sort(result, new PlayerDistanceComparator(position)); 1190 if (reverse) Collections.reverse(result); 1191 if (count > 0) result = result.subList(0, Math.min(count, result.size())); 1192 1193 return result;*/ 1194} 1195 1196bool PlayerList::meetsScoreRequirements(shared_ptr<Player> player, unordered_map<wstring, int> scoreRequirements) 1197{ 1198 app.DebugPrintf("meetsScoreRequirements NOT IMPLEMENTED!"); 1199 return false; 1200 1201 //if (scoreRequirements == null || scoreRequirements.size() == 0) return true; 1202 1203 //for (Map.Entry<String, Integer> requirement : scoreRequirements.entrySet()) { 1204 // String name = requirement.getKey(); 1205 // boolean min = false; 1206 1207 // if (name.endsWith("_min") && name.length() > 4) { 1208 // min = true; 1209 // name = name.substring(0, name.length() - 4); 1210 // } 1211 1212 // Scoreboard scoreboard = player.getScoreboard(); 1213 // Objective objective = scoreboard.getObjective(name); 1214 // if (objective == null) return false; 1215 // Score score = player.getScoreboard().getPlayerScore(player.getAName(), objective); 1216 // int value = score.getScore(); 1217 1218 // if (value < requirement.getValue() && min) { 1219 // return false; 1220 // } else if (value > requirement.getValue() && !min) { 1221 // return false; 1222 // } 1223 //} 1224 1225 //return true; 1226} 1227 1228void PlayerList::sendMessage(const wstring& name, const wstring& message) 1229{ 1230 shared_ptr<ServerPlayer> player = getPlayer(name); 1231 if (player != NULL) 1232 { 1233 player->connection->send( shared_ptr<ChatPacket>( new ChatPacket(message) ) ); 1234 } 1235} 1236 1237void PlayerList::broadcast(double x, double y, double z, double range, int dimension, shared_ptr<Packet> packet) 1238{ 1239 broadcast(nullptr, x, y, z, range, dimension, packet); 1240} 1241 1242void PlayerList::broadcast(shared_ptr<Player> except, double x, double y, double z, double range, int dimension, shared_ptr<Packet> packet) 1243{ 1244 // 4J - altered so that we don't send to the same machine more than once. Add the source player to the machines we have "sent" to as it doesn't need to go to that 1245 // machine either 1246 vector< shared_ptr<ServerPlayer> > sentTo; 1247 if( except != NULL ) 1248 { 1249 sentTo.push_back(dynamic_pointer_cast<ServerPlayer>(except)); 1250 } 1251 1252 for (unsigned int i = 0; i < players.size(); i++) 1253 { 1254 shared_ptr<ServerPlayer> p = players[i]; 1255 if (p == except) continue; 1256 if (p->dimension != dimension) continue; 1257 1258 // 4J - don't send to the same machine more than once 1259 bool dontSend = false; 1260 if( sentTo.size() ) 1261 { 1262 INetworkPlayer *thisPlayer = p->connection->getNetworkPlayer(); 1263 if( thisPlayer == NULL ) 1264 { 1265 dontSend = true; 1266 } 1267 else 1268 { 1269 for(unsigned int j = 0; j < sentTo.size(); j++ ) 1270 { 1271 shared_ptr<ServerPlayer> player2 = sentTo[j]; 1272 INetworkPlayer *otherPlayer = player2->connection->getNetworkPlayer(); 1273 if( otherPlayer != NULL && thisPlayer->IsSameSystem(otherPlayer) ) 1274 { 1275 dontSend = true; 1276 } 1277 } 1278 } 1279 } 1280 if( dontSend ) 1281 { 1282 continue; 1283 } 1284 1285 1286 double xd = x - p->x; 1287 double yd = y - p->y; 1288 double zd = z - p->z; 1289 if (xd * xd + yd * yd + zd * zd < range * range) 1290 { 1291#if 0 // _DEBUG 1292 shared_ptr<LevelSoundPacket> SoundPacket= dynamic_pointer_cast<LevelSoundPacket>(packet); 1293 1294 if(SoundPacket) 1295 { 1296 1297 app.DebugPrintf("---broadcast - eSoundType_[%d] ",SoundPacket->getSound()); 1298 OutputDebugStringW(ConsoleSoundEngine::wchSoundNames[SoundPacket->getSound()]); 1299 app.DebugPrintf("\n"); 1300 } 1301#endif 1302 p->connection->send(packet); 1303 sentTo.push_back( p ); 1304 } 1305 } 1306 1307} 1308 1309void PlayerList::saveAll(ProgressListener *progressListener, bool bDeleteGuestMaps /*= false*/) 1310{ 1311 if(progressListener != NULL) progressListener->progressStart(IDS_PROGRESS_SAVING_PLAYERS); 1312 // 4J - playerIo can be NULL if we have have to exit a game really early on due to network failure 1313 if(playerIo) 1314 { 1315 playerIo->saveAllCachedData(); 1316 for (unsigned int i = 0; i < players.size(); i++) 1317 { 1318 playerIo->save(players[i]); 1319 1320 //4J Stu - We don't want to save the map data for guests, so when we are sure that the player is gone delete the map 1321 if(bDeleteGuestMaps && players[i]->isGuest()) playerIo->deleteMapFilesForPlayer(players[i]); 1322 1323 if(progressListener != NULL) progressListener->progressStagePercentage((i * 100)/ ((int)players.size())); 1324 } 1325 playerIo->clearOldPlayerFiles(); 1326 playerIo->saveMapIdLookup(); 1327 } 1328} 1329 1330void PlayerList::whiteList(const wstring& playerName) 1331{ 1332} 1333 1334void PlayerList::blackList(const wstring& playerName) 1335{ 1336} 1337 1338void PlayerList::reloadWhitelist() 1339{ 1340} 1341 1342void PlayerList::sendLevelInfo(shared_ptr<ServerPlayer> player, ServerLevel *level) 1343{ 1344 player->connection->send( shared_ptr<SetTimePacket>( new SetTimePacket(level->getGameTime(), level->getDayTime(), level->getGameRules()->getBoolean(GameRules::RULE_DAYLIGHT)) ) ); 1345 if (level->isRaining()) 1346 { 1347 player->connection->send( shared_ptr<GameEventPacket>( new GameEventPacket(GameEventPacket::START_RAINING, 0) ) ); 1348 } 1349 else 1350 { 1351 // 4J Stu - Fix for #44836 - Customer Encountered: Out of Sync Weather [A-10] 1352 // If it was raining when the player left the level, and is now not raining we need to make sure that state is updated 1353 player->connection->send( shared_ptr<GameEventPacket>( new GameEventPacket(GameEventPacket::STOP_RAINING, 0) ) ); 1354 } 1355 1356 // send the stronghold position if there is one 1357 if((level->dimension->id==0) && level->getLevelData()->getHasStronghold()) 1358 { 1359 player->connection->send( shared_ptr<XZPacket>( new XZPacket(XZPacket::STRONGHOLD,level->getLevelData()->getXStronghold(),level->getLevelData()->getZStronghold()) ) ); 1360 } 1361} 1362 1363void PlayerList::sendAllPlayerInfo(shared_ptr<ServerPlayer> player) 1364{ 1365 player->refreshContainer(player->inventoryMenu); 1366 player->resetSentInfo(); 1367 player->connection->send( shared_ptr<SetCarriedItemPacket>( new SetCarriedItemPacket(player->inventory->selected)) ); 1368} 1369 1370int PlayerList::getPlayerCount() 1371{ 1372 return (int)players.size(); 1373} 1374 1375int PlayerList::getPlayerCount(ServerLevel *level) 1376{ 1377 int count = 0; 1378 1379 for(AUTO_VAR(it, players.begin()); it != players.end(); ++it) 1380 { 1381 if( (*it)->level == level ) ++count; 1382 } 1383 1384 return count; 1385} 1386 1387int PlayerList::getMaxPlayers() 1388{ 1389 return maxPlayers; 1390} 1391 1392MinecraftServer *PlayerList::getServer() 1393{ 1394 return server; 1395} 1396 1397int PlayerList::getViewDistance() 1398{ 1399 return viewDistance; 1400} 1401 1402void PlayerList::setOverrideGameMode(GameType *gameMode) 1403{ 1404 overrideGameMode = gameMode; 1405} 1406 1407void PlayerList::updatePlayerGameMode(shared_ptr<ServerPlayer> newPlayer, shared_ptr<ServerPlayer> oldPlayer, Level *level) 1408{ 1409 1410 // reset the player's game mode (first pick from old, then copy level if 1411 // necessary) 1412 if (oldPlayer != NULL) 1413 { 1414 newPlayer->gameMode->setGameModeForPlayer(oldPlayer->gameMode->getGameModeForPlayer()); 1415 } 1416 else if (overrideGameMode != NULL) 1417 { 1418 newPlayer->gameMode->setGameModeForPlayer(overrideGameMode); 1419 } 1420 newPlayer->gameMode->updateGameMode(level->getLevelData()->getGameType()); 1421} 1422 1423void PlayerList::setAllowCheatsForAllPlayers(bool allowCommands) 1424{ 1425 this->allowCheatsForAllPlayers = allowCommands; 1426} 1427 1428shared_ptr<ServerPlayer> PlayerList::findAlivePlayerOnSystem(shared_ptr<ServerPlayer> player) 1429{ 1430 int dimIndex, playerDim; 1431 dimIndex = playerDim = player->dimension; 1432 if( dimIndex == -1 ) dimIndex = 1; 1433 else if( dimIndex == 1) dimIndex = 2; 1434 1435 INetworkPlayer *thisPlayer = player->connection->getNetworkPlayer(); 1436 if( thisPlayer != NULL ) 1437 { 1438 for(AUTO_VAR(itP, players.begin()); itP != players.end(); ++itP) 1439 { 1440 shared_ptr<ServerPlayer> newPlayer = *itP; 1441 1442 INetworkPlayer *otherPlayer = newPlayer->connection->getNetworkPlayer(); 1443 1444 if( !newPlayer->removed && 1445 newPlayer != player && 1446 newPlayer->dimension == playerDim && 1447 otherPlayer != NULL && 1448 otherPlayer->IsSameSystem( thisPlayer ) 1449 ) 1450 { 1451 return newPlayer; 1452 } 1453 } 1454 } 1455 1456 return nullptr; 1457} 1458 1459void PlayerList::removePlayerFromReceiving(shared_ptr<ServerPlayer> player, bool usePlayerDimension /*= true*/, int dimension /*= 0*/) 1460{ 1461 int dimIndex, playerDim; 1462 dimIndex = playerDim = usePlayerDimension ? player->dimension : dimension; 1463 if( dimIndex == -1 ) dimIndex = 1; 1464 else if( dimIndex == 1) dimIndex = 2; 1465 1466#ifndef _CONTENT_PACKAGE 1467 app.DebugPrintf("Requesting remove player %ls as primary in dimension %d\n", player->name.c_str(), dimIndex); 1468#endif 1469 bool playerRemoved = false; 1470 1471 AUTO_VAR(it, find( receiveAllPlayers[dimIndex].begin(), receiveAllPlayers[dimIndex].end(), player)); 1472 if( it != receiveAllPlayers[dimIndex].end() ) 1473 { 1474#ifndef _CONTENT_PACKAGE 1475 app.DebugPrintf("Remove: Removing player %ls as primary in dimension %d\n", player->name.c_str(), dimIndex); 1476#endif 1477 receiveAllPlayers[dimIndex].erase(it); 1478 playerRemoved = true; 1479 } 1480 1481 INetworkPlayer *thisPlayer = player->connection->getNetworkPlayer(); 1482 if( thisPlayer != NULL && playerRemoved ) 1483 { 1484 for(AUTO_VAR(itP, players.begin()); itP != players.end(); ++itP) 1485 { 1486 shared_ptr<ServerPlayer> newPlayer = *itP; 1487 1488 INetworkPlayer *otherPlayer = newPlayer->connection->getNetworkPlayer(); 1489 1490 if( newPlayer != player && 1491 newPlayer->dimension == playerDim && 1492 otherPlayer != NULL && 1493 otherPlayer->IsSameSystem( thisPlayer ) 1494 ) 1495 { 1496#ifndef _CONTENT_PACKAGE 1497 app.DebugPrintf("Remove: Adding player %ls as primary in dimension %d\n", newPlayer->name.c_str(), dimIndex); 1498#endif 1499 receiveAllPlayers[dimIndex].push_back( newPlayer ); 1500 break; 1501 } 1502 } 1503 } 1504 else if( thisPlayer == NULL ) 1505 { 1506#ifndef _CONTENT_PACKAGE 1507 app.DebugPrintf("Remove: Qnet player for %ls was NULL so re-checking all players\n", player->name.c_str() ); 1508#endif 1509 // 4J Stu - Something went wrong, or possibly the QNet player left before we got here. 1510 // Re-check all active players and make sure they have someone on their system to receive all packets 1511 for(AUTO_VAR(itP, players.begin()); itP != players.end(); ++itP) 1512 { 1513 shared_ptr<ServerPlayer> newPlayer = *itP; 1514 INetworkPlayer *checkingPlayer = newPlayer->connection->getNetworkPlayer(); 1515 1516 if( checkingPlayer != NULL ) 1517 { 1518 int newPlayerDim = 0; 1519 if( newPlayer->dimension == -1 ) newPlayerDim = 1; 1520 else if( newPlayer->dimension == 1) newPlayerDim = 2; 1521 bool foundPrimary = false; 1522 for(AUTO_VAR(it, receiveAllPlayers[newPlayerDim].begin()); it != receiveAllPlayers[newPlayerDim].end(); ++it) 1523 { 1524 shared_ptr<ServerPlayer> primaryPlayer = *it; 1525 INetworkPlayer *primPlayer = primaryPlayer->connection->getNetworkPlayer(); 1526 if(primPlayer != NULL && checkingPlayer->IsSameSystem( primPlayer ) ) 1527 { 1528 foundPrimary = true; 1529 break; 1530 } 1531 } 1532 if(!foundPrimary) 1533 { 1534#ifndef _CONTENT_PACKAGE 1535 app.DebugPrintf("Remove: Adding player %ls as primary in dimension %d\n", newPlayer->name.c_str(), newPlayerDim); 1536#endif 1537 receiveAllPlayers[newPlayerDim].push_back( newPlayer ); 1538 } 1539 } 1540 } 1541 } 1542} 1543 1544void PlayerList::addPlayerToReceiving(shared_ptr<ServerPlayer> player) 1545{ 1546 int playerDim = 0; 1547 if( player->dimension == -1 ) playerDim = 1; 1548 else if( player->dimension == 1) playerDim = 2; 1549 1550#ifndef _CONTENT_PACKAGE 1551 app.DebugPrintf("Requesting add player %ls as primary in dimension %d\n", player->name.c_str(), playerDim); 1552#endif 1553 1554 bool shouldAddPlayer = true; 1555 1556 INetworkPlayer *thisPlayer = player->connection->getNetworkPlayer(); 1557 1558 if( thisPlayer == NULL ) 1559 { 1560#ifndef _CONTENT_PACKAGE 1561 app.DebugPrintf("Add: Qnet player for player %ls is NULL so not adding them\n", player->name.c_str() ); 1562#endif 1563 shouldAddPlayer = false; 1564 } 1565 else 1566 { 1567 for(AUTO_VAR(it, receiveAllPlayers[playerDim].begin()); it != receiveAllPlayers[playerDim].end(); ++it) 1568 { 1569 shared_ptr<ServerPlayer> oldPlayer = *it; 1570 INetworkPlayer *checkingPlayer = oldPlayer->connection->getNetworkPlayer(); 1571 if(checkingPlayer != NULL && checkingPlayer->IsSameSystem( thisPlayer ) ) 1572 { 1573 shouldAddPlayer = false; 1574 break; 1575 } 1576 } 1577 } 1578 1579 if( shouldAddPlayer ) 1580 { 1581#ifndef _CONTENT_PACKAGE 1582 app.DebugPrintf("Add: Adding player %ls as primary in dimension %d\n", player->name.c_str(), playerDim); 1583#endif 1584 receiveAllPlayers[playerDim].push_back( player ); 1585 } 1586} 1587 1588bool PlayerList::canReceiveAllPackets(shared_ptr<ServerPlayer> player) 1589{ 1590 int playerDim = 0; 1591 if( player->dimension == -1 ) playerDim = 1; 1592 else if( player->dimension == 1) playerDim = 2; 1593 for(AUTO_VAR(it, receiveAllPlayers[playerDim].begin()); it != receiveAllPlayers[playerDim].end(); ++it) 1594 { 1595 shared_ptr<ServerPlayer> newPlayer = *it; 1596 if(newPlayer == player) 1597 { 1598 return true; 1599 } 1600 } 1601 return false; 1602} 1603 1604void PlayerList::kickPlayerByShortId(BYTE networkSmallId) 1605{ 1606 EnterCriticalSection(&m_kickPlayersCS); 1607 m_smallIdsToKick.push_back(networkSmallId); 1608 LeaveCriticalSection(&m_kickPlayersCS); 1609} 1610 1611void PlayerList::closePlayerConnectionBySmallId(BYTE networkSmallId) 1612{ 1613 EnterCriticalSection(&m_closePlayersCS); 1614 m_smallIdsToClose.push_back(networkSmallId); 1615 LeaveCriticalSection(&m_closePlayersCS); 1616} 1617 1618bool PlayerList::isXuidBanned(PlayerUID xuid) 1619{ 1620 if( xuid == INVALID_XUID ) return false; 1621 1622 bool banned = false; 1623 1624 for( AUTO_VAR(it, m_bannedXuids.begin()); it != m_bannedXuids.end(); ++it ) 1625 { 1626 if( ProfileManager.AreXUIDSEqual( xuid, *it ) ) 1627 { 1628 banned = true; 1629 break; 1630 } 1631 } 1632 1633 return banned; 1634} 1635 1636// AP added for Vita so the range can be increased once the level starts 1637void PlayerList::setViewDistance(int newViewDistance) 1638{ 1639 viewDistance = newViewDistance; 1640}