the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 396 lines 12 kB view raw
1#include "stdafx.h" 2#include "ServerPlayerGameMode.h" 3#include "ServerLevel.h" 4#include "ServerPlayer.h" 5#include "PlayerConnection.h" 6#include "..\Minecraft.World\net.minecraft.world.level.tile.h" 7#include "..\Minecraft.World\net.minecraft.world.entity.player.h" 8#include "..\Minecraft.World\net.minecraft.world.item.h" 9#include "..\Minecraft.World\net.minecraft.network.packet.h" 10#include "..\Minecraft.World\net.minecraft.world.level.h" 11#include "..\Minecraft.World\net.minecraft.world.level.chunk.h" 12#include "..\Minecraft.World\net.minecraft.world.level.dimension.h" 13#include "MultiPlayerLevel.h" 14#include "LevelRenderer.h" 15 16ServerPlayerGameMode::ServerPlayerGameMode(Level *level) 17{ 18 // 4J - added initialisers 19 isDestroyingBlock = false; 20 destroyProgressStart = 0; 21 xDestroyBlock = yDestroyBlock = zDestroyBlock = 0; 22 gameTicks = 0; 23 hasDelayedDestroy = false; 24 delayedDestroyX = delayedDestroyY = delayedDestroyZ = 0; 25 delayedTickStart = 0; 26 lastSentState = -1; 27 gameModeForPlayer = GameType::NOT_SET; 28 29 this->level = level; 30 31 // 4J Added 32 m_gameRules = NULL; 33} 34 35ServerPlayerGameMode::~ServerPlayerGameMode() 36{ 37 if(m_gameRules!=NULL) delete m_gameRules; 38} 39 40void ServerPlayerGameMode::setGameModeForPlayer(GameType *gameModeForPlayer) 41{ 42 this->gameModeForPlayer = gameModeForPlayer; 43 44 gameModeForPlayer->updatePlayerAbilities(&(player->abilities)); 45 player->onUpdateAbilities(); 46 47} 48 49GameType *ServerPlayerGameMode::getGameModeForPlayer() 50{ 51 return gameModeForPlayer; 52} 53 54bool ServerPlayerGameMode::isSurvival() 55{ 56 return gameModeForPlayer->isSurvival(); 57} 58 59bool ServerPlayerGameMode::isCreative() 60{ 61 return gameModeForPlayer->isCreative(); 62} 63 64void ServerPlayerGameMode::updateGameMode(GameType *gameType) 65{ 66 if (gameModeForPlayer == GameType::NOT_SET) 67 { 68 gameModeForPlayer = gameType; 69 } 70 setGameModeForPlayer(gameModeForPlayer); 71} 72 73void ServerPlayerGameMode::tick() 74{ 75 gameTicks++; 76 77 if (hasDelayedDestroy) 78 { 79 int ticksSpentDestroying = gameTicks - delayedTickStart; 80 int t = level->getTile(delayedDestroyX, delayedDestroyY, delayedDestroyZ); 81 if (t == 0) 82 { 83 hasDelayedDestroy = false; 84 } 85 else 86 { 87 Tile *tile = Tile::tiles[t]; 88 float destroyProgress = tile->getDestroyProgress(player, player->level, delayedDestroyX, delayedDestroyY, delayedDestroyZ) * (ticksSpentDestroying + 1); 89 int state = (int) (destroyProgress * 10); 90 91 if (state != lastSentState) 92 { 93 level->destroyTileProgress(player->entityId, delayedDestroyX, delayedDestroyY, delayedDestroyZ, state); 94 lastSentState = state; 95 } 96 if (destroyProgress >= 1) 97 { 98 hasDelayedDestroy = false; 99 destroyBlock(delayedDestroyX, delayedDestroyY, delayedDestroyZ); 100 } 101 } 102 } 103 else if (isDestroyingBlock) 104 { 105 int t = level->getTile(xDestroyBlock, yDestroyBlock, zDestroyBlock); 106 Tile *tile = Tile::tiles[t]; 107 108 if (tile == NULL) 109 { 110 level->destroyTileProgress(player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, -1); 111 lastSentState = -1; 112 isDestroyingBlock = false; 113 } 114 else 115 { 116 int ticksSpentDestroying = gameTicks - destroyProgressStart; 117 float destroyProgress = tile->getDestroyProgress(player, player->level, xDestroyBlock, yDestroyBlock, zDestroyBlock) * (ticksSpentDestroying + 1); 118 int state = (int) (destroyProgress * 10); 119 120 if (state != lastSentState) 121 { 122 level->destroyTileProgress(player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, state); 123 lastSentState = state; 124 } 125 } 126 } 127} 128 129void ServerPlayerGameMode::startDestroyBlock(int x, int y, int z, int face) 130{ 131 if(!player->isAllowedToMine()) return; 132 133 if (gameModeForPlayer->isAdventureRestricted()) 134 { 135 if (!player->mayDestroyBlockAt(x, y, z)) 136 { 137 return; 138 } 139 } 140 141 if (isCreative()) 142 { 143 if(!level->extinguishFire(nullptr, x, y, z, face)) 144 { 145 destroyBlock(x, y, z); 146 } 147 return; 148 } 149 level->extinguishFire(player, x, y, z, face); 150 destroyProgressStart = gameTicks; 151 float progress = 1.0f; 152 int t = level->getTile(x, y, z); 153 if (t > 0) 154 { 155 Tile::tiles[t]->attack(level, x, y, z, player); 156 progress = Tile::tiles[t]->getDestroyProgress(player, player->level, x, y, z); 157 } 158 159 if (t > 0 && (progress >= 1 ) ) //|| (app.DebugSettingsOn() && (player->GetDebugOptions()&(1L<<eDebugSetting_InstantDestroy) ) ))) 160 { 161 destroyBlock(x, y, z); 162 } 163 else 164 { 165 isDestroyingBlock = true; 166 xDestroyBlock = x; 167 yDestroyBlock = y; 168 zDestroyBlock = z; 169 int state = (int) (progress * 10); 170 level->destroyTileProgress(player->entityId, x, y, z, state); 171 lastSentState = state; 172 } 173} 174 175void ServerPlayerGameMode::stopDestroyBlock(int x, int y, int z) 176{ 177 if (x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock) 178 { 179 // int ticksSpentDestroying = gameTicks - destroyProgressStart; 180 181 int t = level->getTile(x, y, z); 182 if (t != 0) 183 { 184 Tile *tile = Tile::tiles[t]; 185 186 // MGH - removed checking for the destroy progress here, it has already been checked on the client before it sent the packet. 187 // fixes issues with this failing to destroy because of packets bunching up 188 // float destroyProgress = tile->getDestroyProgress(player, player->level, x, y, z) * (ticksSpentDestroying + 1); 189 // if (destroyProgress >= .7f || bIgnoreDestroyProgress) 190 { 191 isDestroyingBlock = false; 192 level->destroyTileProgress(player->entityId, x, y, z, -1); 193 destroyBlock(x, y, z); 194 } 195 // else if (!hasDelayedDestroy) 196 // { 197 // isDestroyingBlock = false; 198 // hasDelayedDestroy = true; 199 // delayedDestroyX = x; 200 // delayedDestroyY = y; 201 // delayedDestroyZ = z; 202 // delayedTickStart = destroyProgressStart; 203 // } 204 } 205 } 206} 207 208void ServerPlayerGameMode::abortDestroyBlock(int x, int y, int z) 209{ 210 isDestroyingBlock = false; 211 level->destroyTileProgress(player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, -1); 212} 213 214bool ServerPlayerGameMode::superDestroyBlock(int x, int y, int z) 215{ 216 Tile *oldTile = Tile::tiles[level->getTile(x, y, z)]; 217 int data = level->getData(x, y, z); 218 219 if (oldTile != NULL) 220 { 221 oldTile->playerWillDestroy(level, x, y, z, data, player); 222 } 223 224 bool changed = level->removeTile(x, y, z); 225 if (oldTile != NULL && changed) 226 { 227 oldTile->destroy(level, x, y, z, data); 228 } 229 return changed; 230} 231 232bool ServerPlayerGameMode::destroyBlock(int x, int y, int z) 233{ 234 if (gameModeForPlayer->isAdventureRestricted()) 235 { 236 if (!player->mayDestroyBlockAt(x, y, z)) 237 { 238 return false; 239 } 240 } 241 242 if (gameModeForPlayer->isCreative()) 243 { 244 if (player->getCarriedItem() != NULL && dynamic_cast<WeaponItem *>(player->getCarriedItem()->getItem()) != NULL) 245 { 246 return false; 247 } 248 } 249 250 int t = level->getTile(x, y, z); 251 int data = level->getData(x, y, z); 252 253 level->levelEvent(player, LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, t + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT)); 254 255 // 4J - In creative mode, the point where we need to tell the renderer that we are about to destroy a tile via destroyingTileAt is quite complicated. 256 // If the player being told is remote, then we always want the client to do it as it does the final update. If the player being told is local, 257 // then we need to update the renderer Here if we are sharing data between host & client as this is the final point where the original data is still intact. 258 // If the player being told is local, and we aren't sharing data between host & client, then we can just treat it as if it is a remote player and 259 // it can update the renderer. 260 bool clientToUpdateRenderer = false; 261 if( isCreative() ) 262 { 263 clientToUpdateRenderer = true; 264 if( dynamic_pointer_cast<ServerPlayer>(player)->connection->isLocal() ) 265 { 266 // Establish whether we are sharing this chunk between client & server 267 MultiPlayerLevel *clientLevel = Minecraft::GetInstance()->getLevel(level->dimension->id); 268 if( clientLevel ) 269 { 270 LevelChunk *lc = clientLevel->getChunkAt( x, z ); 271#ifdef SHARING_ENABLED 272 if( lc->sharingTilesAndData ) 273 { 274 // We are sharing - this is the last point we can tell the renderer 275 Minecraft::GetInstance()->levelRenderer->destroyedTileManager->destroyingTileAt( clientLevel, x, y, z ); 276 277 // Don't need to ask the client to do this too 278 clientToUpdateRenderer = false; 279 } 280#endif 281 } 282 } 283 } 284 285 bool changed = superDestroyBlock(x, y, z); 286 287 if (isCreative()) 288 { 289 shared_ptr<TileUpdatePacket> tup = shared_ptr<TileUpdatePacket>( new TileUpdatePacket(x, y, z, level) ); 290 // 4J - a bit of a hack here, but if we want to tell the client that it needs to inform the renderer of a block being destroyed, then send a block 255 instead of a 0. This is handled in ClientConnection::handleTileUpdate 291 if( tup->block == 0 ) 292 { 293 if( clientToUpdateRenderer ) tup->block = 255; 294 } 295 player->connection->send( tup ); 296 } 297 else 298 { 299 shared_ptr<ItemInstance> item = player->getSelectedItem(); 300 bool canDestroy = player->canDestroy(Tile::tiles[t]); 301 if (item != NULL) 302 { 303 item->mineBlock(level, t, x, y, z, player); 304 if (item->count == 0) 305 { 306 player->removeSelectedItem(); 307 } 308 } 309 if (changed && canDestroy) 310 { 311 Tile::tiles[t]->playerDestroy(level, player, x, y, z, data); 312 } 313 } 314 return changed; 315 316} 317 318bool ServerPlayerGameMode::useItem(shared_ptr<Player> player, Level *level, shared_ptr<ItemInstance> item, bool bTestUseOnly) 319{ 320 if(!player->isAllowedToUse(item)) return false; 321 322 int oldCount = item->count; 323 int oldAux = item->getAuxValue(); 324 shared_ptr<ItemInstance> itemInstance = item->use(level, player); 325 if (itemInstance != item || (itemInstance != NULL && (itemInstance->count != oldCount || itemInstance->getUseDuration() > 0 || itemInstance->getAuxValue() != oldAux))) 326 { 327 player->inventory->items[player->inventory->selected] = itemInstance; 328 if (isCreative()) 329 { 330 itemInstance->count = oldCount; 331 if (itemInstance->isDamageableItem()) itemInstance->setAuxValue(oldAux); 332 } 333 if (itemInstance->count == 0) 334 { 335 player->inventory->items[player->inventory->selected] = nullptr; 336 } 337 if (!player->isUsingItem()) 338 { 339 dynamic_pointer_cast<ServerPlayer>(player)->refreshContainer(player->inventoryMenu); 340 } 341 return true; 342 } 343 return false; 344 345} 346 347bool ServerPlayerGameMode::useItemOn(shared_ptr<Player> player, Level *level, shared_ptr<ItemInstance> item, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly, bool *pbUsedItem) 348{ 349 // 4J-PB - Adding a test only version to allow tooltips to be displayed 350 int t = level->getTile(x, y, z); 351 if (!player->isSneaking() || player->getCarriedItem() == NULL) 352 { 353 if (t > 0 && player->isAllowedToUse(Tile::tiles[t])) 354 { 355 if(bTestUseOnOnly) 356 { 357 if (Tile::tiles[t]->TestUse()) return true; 358 } 359 else 360 { 361 if (Tile::tiles[t]->use(level, x, y, z, player, face, clickX, clickY, clickZ)) 362 { 363 if(m_gameRules != NULL) m_gameRules->onUseTile(t,x,y,z); 364 return true; 365 } 366 } 367 } 368 } 369 370 if (item == NULL || !player->isAllowedToUse(item)) return false; 371 if (isCreative()) 372 { 373 int aux = item->getAuxValue(); 374 int count = item->count; 375 bool success = item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ); 376 item->setAuxValue(aux); 377 item->count = count; 378 return success; 379 } 380 else 381 { 382 return item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ, bTestUseOnOnly); 383 } 384} 385 386void ServerPlayerGameMode::setLevel(ServerLevel *newLevel) 387{ 388 level = newLevel; 389} 390 391// 4J Added 392void ServerPlayerGameMode::setGameRules(GameRulesInstance *rules) 393{ 394 if(m_gameRules != NULL) delete m_gameRules; 395 m_gameRules = rules; 396}