the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 528 lines 17 kB view raw
1#include "stdafx.h" 2#include "MultiPlayerGameMode.h" 3#include "CreativeMode.h" 4#include "MultiPlayerLocalPlayer.h" 5#include "MultiPlayerLevel.h" 6#include "Minecraft.h" 7#include "ClientConnection.h" 8#include "LevelRenderer.h" 9#include "Common\Network\GameNetworkManager.h" 10#include "..\Minecraft.World\net.minecraft.world.level.h" 11#include "..\Minecraft.World\net.minecraft.world.item.h" 12#include "..\Minecraft.World\net.minecraft.world.entity.player.h" 13#include "..\Minecraft.World\net.minecraft.world.level.tile.h" 14#include "..\Minecraft.World\net.minecraft.world.inventory.h" 15#include "..\Minecraft.World\net.minecraft.h" 16 17MultiPlayerGameMode::MultiPlayerGameMode(Minecraft *minecraft, ClientConnection *connection) 18{ 19 // 4J - added initialisers 20 xDestroyBlock = -1; 21 yDestroyBlock = -1; 22 zDestroyBlock = -1; 23 destroyingItem = nullptr; 24 destroyProgress = 0; 25 destroyTicks = 0; 26 destroyDelay = 0; 27 isDestroying = false; 28 carriedItem = 0; 29 localPlayerMode = GameType::SURVIVAL; 30 this->minecraft = minecraft; 31 this->connection = connection; 32} 33 34void MultiPlayerGameMode::creativeDestroyBlock(Minecraft *minecraft, MultiPlayerGameMode *gameMode, int x, int y, int z, int face) 35{ 36 if (!minecraft->level->extinguishFire(minecraft->player, x, y, z, face)) 37 { 38 gameMode->destroyBlock(x, y, z, face); 39 } 40} 41 42void MultiPlayerGameMode::adjustPlayer(shared_ptr<Player> player) 43{ 44 localPlayerMode->updatePlayerAbilities(&player->abilities); 45} 46 47bool MultiPlayerGameMode::isCutScene() 48{ 49 return false; 50} 51 52void MultiPlayerGameMode::setLocalMode(GameType *mode) 53{ 54 localPlayerMode = mode; 55 localPlayerMode->updatePlayerAbilities(&minecraft->player->abilities); 56} 57 58void MultiPlayerGameMode::initPlayer(shared_ptr<Player> player) 59{ 60 player->yRot = -180; 61} 62 63bool MultiPlayerGameMode::canHurtPlayer() 64{ 65 return localPlayerMode->isSurvival(); 66} 67 68bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face) 69{ 70 if (localPlayerMode->isAdventureRestricted()) { 71 if (!minecraft->player->mayDestroyBlockAt(x, y, z)) { 72 return false; 73 } 74 } 75 76 if (localPlayerMode->isCreative()) 77 { 78 if (minecraft->player->getCarriedItem() != NULL && dynamic_cast<WeaponItem *>(minecraft->player->getCarriedItem()->getItem()) != NULL) 79 { 80 return false; 81 } 82 } 83 84 Level *level = minecraft->level; 85 Tile *oldTile = Tile::tiles[level->getTile(x, y, z)]; 86 87 if (oldTile == NULL) return false; 88 89#ifdef _WINDOWS64 90 if (g_NetworkManager.IsHost()) 91 { 92 level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, oldTile->id + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT)); 93 return true; 94 } 95#endif 96 97 level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, oldTile->id + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT)); 98 99 int data = level->getData(x, y, z); 100 bool changed = level->removeTile(x, y, z); 101 if (changed) 102 { 103 oldTile->destroy(level, x, y, z, data); 104 } 105 yDestroyBlock = -1; 106 107 if (!localPlayerMode->isCreative()) 108 { 109 shared_ptr<ItemInstance> item = minecraft->player->getSelectedItem(); 110 if (item != NULL) 111 { 112 item->mineBlock(level, oldTile->id, x, y, z, minecraft->player); 113 if (item->count == 0) 114 { 115 minecraft->player->removeSelectedItem(); 116 } 117 } 118 } 119 120 return changed; 121} 122 123void MultiPlayerGameMode::startDestroyBlock(int x, int y, int z, int face) 124{ 125 if(!minecraft->player->isAllowedToMine()) return; 126 127 if (localPlayerMode->isAdventureRestricted()) 128 { 129 if (!minecraft->player->mayDestroyBlockAt(x, y, z)) 130 { 131 return; 132 } 133 } 134 135 if (localPlayerMode->isCreative()) 136 { 137 connection->send(shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face) )); 138 creativeDestroyBlock(minecraft, this, x, y, z, face); 139 destroyDelay = 5; 140 } 141 else if (!isDestroying || !sameDestroyTarget(x, y, z)) 142 { 143 if (isDestroying) 144 { 145 connection->send(shared_ptr<PlayerActionPacket>(new PlayerActionPacket(PlayerActionPacket::ABORT_DESTROY_BLOCK, xDestroyBlock, yDestroyBlock, zDestroyBlock, face))); 146 } 147 connection->send( shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face) ) ); 148 int t = minecraft->level->getTile(x, y, z); 149 if (t > 0 && destroyProgress == 0) Tile::tiles[t]->attack(minecraft->level, x, y, z, minecraft->player); 150 if (t > 0 && 151 (Tile::tiles[t]->getDestroyProgress(minecraft->player, minecraft->player->level, x, y, z) >= 1 152 // ||(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_InstantDestroy)) 153 ) 154 ) 155 { 156 destroyBlock(x, y, z, face); 157 } 158 else 159 { 160 isDestroying = true; 161 xDestroyBlock = x; 162 yDestroyBlock = y; 163 zDestroyBlock = z; 164 destroyingItem = minecraft->player->getCarriedItem(); 165 destroyProgress = 0; 166 destroyTicks = 0; 167 minecraft->level->destroyTileProgress(minecraft->player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, (int)(destroyProgress * 10) - 1); 168 } 169 } 170 171} 172 173void MultiPlayerGameMode::stopDestroyBlock() 174{ 175 if (isDestroying) 176 { 177 connection->send(shared_ptr<PlayerActionPacket>(new PlayerActionPacket(PlayerActionPacket::ABORT_DESTROY_BLOCK, xDestroyBlock, yDestroyBlock, zDestroyBlock, -1))); 178 } 179 180 isDestroying = false; 181 destroyProgress = 0; 182 minecraft->level->destroyTileProgress(minecraft->player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, -1); 183} 184 185void MultiPlayerGameMode::continueDestroyBlock(int x, int y, int z, int face) 186{ 187 if(!minecraft->player->isAllowedToMine()) return; 188 ensureHasSentCarriedItem(); 189// connection.send(new PlayerActionPacket(PlayerActionPacket.CONTINUE_DESTROY_BLOCK, x, y, z, face)); 190 191 if (destroyDelay > 0) 192 { 193 destroyDelay--; 194 return; 195 } 196 197 if (localPlayerMode->isCreative()) 198 { 199 destroyDelay = 5; 200 connection->send(shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face) ) ); 201 creativeDestroyBlock(minecraft, this, x, y, z, face); 202 return; 203 } 204 205 if (sameDestroyTarget(x, y, z)) 206 { 207 int t = minecraft->level->getTile(x, y, z); 208 if (t == 0) 209 { 210 isDestroying = false; 211 return; 212 } 213 Tile *tile = Tile::tiles[t]; 214 215 destroyProgress += tile->getDestroyProgress(minecraft->player, minecraft->player->level, x, y, z); 216 217 if (destroyTicks % 4 == 0) 218 { 219 if (tile != NULL) 220 { 221 int iStepSound=tile->soundType->getStepSound(); 222 223 minecraft->soundEngine->play(iStepSound, x + 0.5f, y + 0.5f, z + 0.5f, (tile->soundType->getVolume() + 1) / 8, tile->soundType->getPitch() * 0.5f); 224 } 225 } 226 227 destroyTicks++; 228 229 if (destroyProgress >= 1) 230 { 231 isDestroying = false; 232 connection->send( shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::STOP_DESTROY_BLOCK, x, y, z, face) ) ); 233 destroyBlock(x, y, z, face); 234 destroyProgress = 0; 235 destroyTicks = 0; 236 destroyDelay = 5; 237 } 238 239 minecraft->level->destroyTileProgress(minecraft->player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, (int)(destroyProgress * 10) - 1); 240 } 241 else 242 { 243 startDestroyBlock(x, y, z, face); 244 } 245 246} 247 248float MultiPlayerGameMode::getPickRange() 249{ 250 if (localPlayerMode->isCreative()) 251 { 252 return 5.0f; 253 } 254 return 4.5f; 255} 256 257void MultiPlayerGameMode::tick() 258{ 259 ensureHasSentCarriedItem(); 260 //minecraft->soundEngine->playMusicTick(); 261} 262 263bool MultiPlayerGameMode::sameDestroyTarget(int x, int y, int z) 264{ 265 shared_ptr<ItemInstance> selected = minecraft->player->getCarriedItem(); 266 bool sameItems = destroyingItem == NULL && selected == NULL; 267 if (destroyingItem != NULL && selected != NULL) 268 { 269 sameItems = 270 selected->id == destroyingItem->id && 271 ItemInstance::tagMatches(selected, destroyingItem) && 272 (selected->isDamageableItem() || selected->getAuxValue() == destroyingItem->getAuxValue()); 273 } 274 return x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock && sameItems; 275} 276 277void MultiPlayerGameMode::ensureHasSentCarriedItem() 278{ 279 int newItem = minecraft->player->inventory->selected; 280 if (newItem != carriedItem) 281 { 282 carriedItem = newItem; 283 connection->send( shared_ptr<SetCarriedItemPacket>( new SetCarriedItemPacket(carriedItem) ) ); 284 } 285} 286 287bool MultiPlayerGameMode::useItemOn(shared_ptr<Player> player, Level *level, shared_ptr<ItemInstance> item, int x, int y, int z, int face, Vec3 *hit, bool bTestUseOnly, bool *pbUsedItem) 288{ 289 if( pbUsedItem ) *pbUsedItem = false; // Did we actually use the held item? 290 291 // 4J-PB - Adding a test only version to allow tooltips to be displayed 292 if(!bTestUseOnly) 293 { 294 ensureHasSentCarriedItem(); 295 } 296 float clickX = (float) hit->x - x; 297 float clickY = (float) hit->y - y; 298 float clickZ = (float) hit->z - z; 299 bool didSomething = false; 300 301 if (!player->isSneaking() || player->getCarriedItem() == NULL) 302 { 303 int t = level->getTile(x, y, z); 304 if (t > 0 && player->isAllowedToUse(Tile::tiles[t])) 305 { 306 if(bTestUseOnly) 307 { 308 switch(t) 309 { 310 case Tile::jukebox_Id: 311 case Tile::bed_Id: // special case for a bed 312 if (Tile::tiles[t]->TestUse(level, x, y, z, player )) 313 { 314 return true; 315 } 316 else if (t==Tile::bed_Id) // 4J-JEV: You can still use items on record players (ie. set fire to them). 317 { 318 // bed is too far away, or something 319 return false; 320 } 321 break; 322 default: 323 if (Tile::tiles[t]->TestUse()) return true; 324 break; 325 } 326 } 327 else 328 { 329 if (Tile::tiles[t]->use(level, x, y, z, player, face, clickX, clickY, clickZ)) didSomething = true; 330 } 331 } 332 } 333 334 if (!didSomething && item != NULL && dynamic_cast<TileItem *>(item->getItem())) 335 { 336 TileItem *tile = dynamic_cast<TileItem *>(item->getItem()); 337 if (!tile->mayPlace(level, x, y, z, face, player, item)) return false; 338 } 339 340 // 4J Stu - In Java we send the use packet before the above check for item being NULL 341 // so the following never gets executed but the packet still gets sent (for opening chests etc) 342 if(item != NULL) 343 { 344 if(!didSomething && player->isAllowedToUse(item)) 345 { 346 if (localPlayerMode->isCreative()) 347 { 348 int aux = item->getAuxValue(); 349 int count = item->count; 350 didSomething = item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ, bTestUseOnly); 351 item->setAuxValue(aux); 352 item->count = count; 353 } 354 else 355 { 356 didSomething = item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ, bTestUseOnly); 357 } 358 if( didSomething ) 359 { 360 if( pbUsedItem ) *pbUsedItem = true; 361 } 362 } 363 } 364 else 365 { 366 int t = level->getTile(x, y, z); 367 // 4J - Bit of a hack, however seems preferable to any larger changes which would have more chance of causing unwanted side effects. 368 // If we aren't going to be actually performing the use method locally, then call this method with its "soundOnly" parameter set to true. 369 // This is an addition from the java version, and as its name suggests, doesn't actually perform the use locally but just makes any sounds that 370 // are meant to be directly caused by this. If we don't do this, then the sounds never happen as the tile's use method is only called on the 371 // server, and that won't allow any sounds that are directly made, or broadcast back level events to us that would make the sound, since we are 372 // the source of the event. 373 if( ( t > 0 ) && ( !bTestUseOnly ) && player->isAllowedToUse(Tile::tiles[t]) ) 374 { 375 Tile::tiles[t]->use(level, x, y, z, player, face, clickX, clickY, clickZ, true); 376 } 377 } 378 379 // 4J Stu - Do the action before we send the packet, so that our predicted count is sent in the packet and the server 380 // doesn't think it has to update us 381 // Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water. 382 if(!bTestUseOnly) 383 { 384 connection->send( shared_ptr<UseItemPacket>( new UseItemPacket(x, y, z, face, player->inventory->getSelected(), clickX, clickY, clickZ) ) ); 385 } 386 return didSomething; 387} 388 389bool MultiPlayerGameMode::useItem(shared_ptr<Player> player, Level *level, shared_ptr<ItemInstance> item, bool bTestUseOnly) 390{ 391 if(!player->isAllowedToUse(item)) return false; 392 393 // 4J-PB - Adding a test only version to allow tooltips to be displayed 394 if(!bTestUseOnly) 395 { 396 ensureHasSentCarriedItem(); 397 } 398 399 // 4J Stu - Do the action before we send the packet, so that our predicted count is sent in the packet and the server 400 // doesn't think it has to update us, or can update us if we are wrong 401 // Fix for #13120 - Using a bucket of water or lava in the spawn area (centre of the map) causes the inventory to get out of sync 402 bool result = false; 403 404 // 4J-PB added for tooltips to test use only 405 if(bTestUseOnly) 406 { 407 result = item->TestUse(item, level, player); 408 } 409 else 410 { 411 int oldCount = item->count; 412 shared_ptr<ItemInstance> itemInstance = item->use(level, player); 413 if ((itemInstance != NULL && itemInstance != item) || (itemInstance != NULL && itemInstance->count != oldCount)) 414 { 415 player->inventory->items[player->inventory->selected] = itemInstance; 416 if (itemInstance->count == 0) 417 { 418 player->inventory->items[player->inventory->selected] = nullptr; 419 } 420 result = true; 421 } 422 } 423 424 if(!bTestUseOnly) 425 { 426 connection->send( shared_ptr<UseItemPacket>( new UseItemPacket(-1, -1, -1, 255, player->inventory->getSelected(), 0, 0, 0) ) ); 427 } 428 return result; 429} 430 431shared_ptr<MultiplayerLocalPlayer> MultiPlayerGameMode::createPlayer(Level *level) 432{ 433 return shared_ptr<MultiplayerLocalPlayer>( new MultiplayerLocalPlayer(minecraft, level, minecraft->user, connection) ); 434} 435 436void MultiPlayerGameMode::attack(shared_ptr<Player> player, shared_ptr<Entity> entity) 437{ 438 ensureHasSentCarriedItem(); 439 connection->send( shared_ptr<InteractPacket>( new InteractPacket(player->entityId, entity->entityId, InteractPacket::ATTACK) ) ); 440 player->attack(entity); 441} 442 443bool MultiPlayerGameMode::interact(shared_ptr<Player> player, shared_ptr<Entity> entity) 444{ 445 ensureHasSentCarriedItem(); 446 connection->send(shared_ptr<InteractPacket>( new InteractPacket(player->entityId, entity->entityId, InteractPacket::INTERACT) ) ); 447 return player->interact(entity); 448} 449 450shared_ptr<ItemInstance> MultiPlayerGameMode::handleInventoryMouseClick(int containerId, int slotNum, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player) 451{ 452 short changeUid = player->containerMenu->backup(player->inventory); 453 454 shared_ptr<ItemInstance> clicked = player->containerMenu->clicked(slotNum, buttonNum, quickKeyHeld?AbstractContainerMenu::CLICK_QUICK_MOVE:AbstractContainerMenu::CLICK_PICKUP, player); 455 connection->send( shared_ptr<ContainerClickPacket>( new ContainerClickPacket(containerId, slotNum, buttonNum, quickKeyHeld, clicked, changeUid) ) ); 456 457 return clicked; 458} 459 460void MultiPlayerGameMode::handleInventoryButtonClick(int containerId, int buttonId) 461{ 462 connection->send(shared_ptr<ContainerButtonClickPacket>( new ContainerButtonClickPacket(containerId, buttonId) )); 463} 464 465void MultiPlayerGameMode::handleCreativeModeItemAdd(shared_ptr<ItemInstance> clicked, int slot) 466{ 467 if (localPlayerMode->isCreative()) 468 { 469 connection->send(shared_ptr<SetCreativeModeSlotPacket>( new SetCreativeModeSlotPacket(slot, clicked) ) ); 470 } 471} 472 473void MultiPlayerGameMode::handleCreativeModeItemDrop(shared_ptr<ItemInstance> clicked) 474{ 475 if (localPlayerMode->isCreative() && clicked != NULL) 476 { 477 connection->send(shared_ptr<SetCreativeModeSlotPacket>( new SetCreativeModeSlotPacket(-1, clicked) ) ); 478 } 479} 480 481void MultiPlayerGameMode::releaseUsingItem(shared_ptr<Player> player) 482{ 483 ensureHasSentCarriedItem(); 484 connection->send(shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::RELEASE_USE_ITEM, 0, 0, 0, 255) ) ); 485 player->releaseUsingItem(); 486} 487 488bool MultiPlayerGameMode::hasExperience() 489{ 490 return localPlayerMode->isSurvival(); 491} 492 493bool MultiPlayerGameMode::hasMissTime() 494{ 495 return !localPlayerMode->isCreative(); 496} 497 498bool MultiPlayerGameMode::hasInfiniteItems() 499{ 500 return localPlayerMode->isCreative(); 501} 502 503bool MultiPlayerGameMode::hasFarPickRange() 504{ 505 return localPlayerMode->isCreative(); 506} 507 508// Returns true when the inventory is opened from the server-side. Currently 509// only happens when the player is riding a horse. 510bool MultiPlayerGameMode::isServerControlledInventory() 511{ 512 return minecraft->player->isRiding() && minecraft->player->riding->instanceof(eTYPE_HORSE); 513} 514 515bool MultiPlayerGameMode::handleCraftItem(int recipe, shared_ptr<Player> player) 516{ 517 short changeUid = player->containerMenu->backup(player->inventory); 518 519 connection->send( shared_ptr<CraftItemPacket>( new CraftItemPacket(recipe, changeUid) ) ); 520 521 return true; 522} 523 524void MultiPlayerGameMode::handleDebugOptions(unsigned int uiVal, shared_ptr<Player> player) 525{ 526 player->SetDebugOptions(uiVal); 527 connection->send( shared_ptr<DebugOptionsPacket>( new DebugOptionsPacket(uiVal) ) ); 528}