Fix delayed block breaking sync with renderer/server #442

This commit is contained in:
Chase Cooper 2026-03-04 16:58:41 -05:00
parent 391dd3caae
commit 138d92359c
2 changed files with 287 additions and 261 deletions

View file

@ -16,7 +16,6 @@
MultiPlayerGameMode::MultiPlayerGameMode(Minecraft *minecraft, ClientConnection *connection) MultiPlayerGameMode::MultiPlayerGameMode(Minecraft *minecraft, ClientConnection *connection)
{ {
// 4J - added initialisers
xDestroyBlock = -1; xDestroyBlock = -1;
yDestroyBlock = -1; yDestroyBlock = -1;
zDestroyBlock = -1; zDestroyBlock = -1;
@ -29,12 +28,18 @@ MultiPlayerGameMode::MultiPlayerGameMode(Minecraft *minecraft, ClientConnection
localPlayerMode = GameType::SURVIVAL; localPlayerMode = GameType::SURVIVAL;
this->minecraft = minecraft; this->minecraft = minecraft;
this->connection = connection; this->connection = connection;
lastSentDestroyState = -2;
} }
void MultiPlayerGameMode::creativeDestroyBlock(Minecraft *minecraft, MultiPlayerGameMode *gameMode, int x, int y, int z, int face) void MultiPlayerGameMode::creativeDestroyBlock(Minecraft *minecraft, MultiPlayerGameMode *gameMode, int x, int y, int z, int face)
{ {
if (!minecraft->level->extinguishFire(minecraft->player, x, y, z, face)) if (!minecraft->level->extinguishFire(minecraft->player, x, y, z, face))
{ {
// Tell renderer we're about to destroy this tile so collision/sound sync better while render updates
if (minecraft->levelRenderer && minecraft->levelRenderer->destroyedTileManager)
{
minecraft->levelRenderer->destroyedTileManager->destroyingTileAt(minecraft->level, x, y, z);
}
gameMode->destroyBlock(x, y, z, face); gameMode->destroyBlock(x, y, z, face);
} }
} }
@ -75,7 +80,7 @@ bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face)
if (localPlayerMode->isCreative()) if (localPlayerMode->isCreative())
{ {
if (minecraft->player->getCarriedItem() != NULL && dynamic_cast<WeaponItem *>(minecraft->player->getCarriedItem()->getItem()) != NULL) if (minecraft->player->getCarriedItem() != nullptr && dynamic_cast<WeaponItem *>(minecraft->player->getCarriedItem()->getItem()) != nullptr)
{ {
return false; return false;
} }
@ -84,7 +89,7 @@ bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face)
Level *level = minecraft->level; Level *level = minecraft->level;
Tile *oldTile = Tile::tiles[level->getTile(x, y, z)]; Tile *oldTile = Tile::tiles[level->getTile(x, y, z)];
if (oldTile == NULL) return false; if (oldTile == nullptr) return false;
#ifdef _WINDOWS64 #ifdef _WINDOWS64
if (g_NetworkManager.IsHost()) if (g_NetworkManager.IsHost())
@ -94,10 +99,15 @@ bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face)
} }
#endif #endif
if (minecraft->levelRenderer && minecraft->levelRenderer->destroyedTileManager)
{
minecraft->levelRenderer->destroyedTileManager->destroyingTileAt(level, x, y, z);
}
level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, oldTile->id + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT)); level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, oldTile->id + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT));
int data = level->getData(x, y, z); const int data = level->getData(x, y, z);
bool changed = level->removeTile(x, y, z); const bool changed = level->setTileAndData(x, y, z, 0, 0, Tile::UPDATE_CLIENTS);
if (changed) if (changed)
{ {
oldTile->destroy(level, x, y, z, data); oldTile->destroy(level, x, y, z, data);
@ -106,8 +116,8 @@ bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face)
if (!localPlayerMode->isCreative()) if (!localPlayerMode->isCreative())
{ {
shared_ptr<ItemInstance> item = minecraft->player->getSelectedItem(); const shared_ptr<ItemInstance> item = minecraft->player->getSelectedItem();
if (item != NULL) if (item != nullptr)
{ {
item->mineBlock(level, oldTile->id, x, y, z, minecraft->player); item->mineBlock(level, oldTile->id, x, y, z, minecraft->player);
if (item->count == 0) if (item->count == 0)
@ -134,7 +144,7 @@ void MultiPlayerGameMode::startDestroyBlock(int x, int y, int z, int face)
if (localPlayerMode->isCreative()) if (localPlayerMode->isCreative())
{ {
connection->send(shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face) )); connection->send(std::make_shared<PlayerActionPacket>(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face));
creativeDestroyBlock(minecraft, this, x, y, z, face); creativeDestroyBlock(minecraft, this, x, y, z, face);
destroyDelay = 5; destroyDelay = 5;
} }
@ -142,16 +152,12 @@ void MultiPlayerGameMode::startDestroyBlock(int x, int y, int z, int face)
{ {
if (isDestroying) if (isDestroying)
{ {
connection->send(shared_ptr<PlayerActionPacket>(new PlayerActionPacket(PlayerActionPacket::ABORT_DESTROY_BLOCK, xDestroyBlock, yDestroyBlock, zDestroyBlock, face))); connection->send(std::make_shared<PlayerActionPacket>(PlayerActionPacket::ABORT_DESTROY_BLOCK, xDestroyBlock, yDestroyBlock, zDestroyBlock, face));
} }
connection->send( shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face) ) ); connection->send(std::make_shared<PlayerActionPacket>(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face));
int t = minecraft->level->getTile(x, y, z); int t = minecraft->level->getTile(x, y, z);
if (t > 0 && destroyProgress == 0) Tile::tiles[t]->attack(minecraft->level, x, y, z, minecraft->player); if (t > 0 && destroyProgress == 0) Tile::tiles[t]->attack(minecraft->level, x, y, z, minecraft->player);
if (t > 0 && if (t > 0 && (Tile::tiles[t]->getDestroyProgress(minecraft->player, minecraft->player->level, x, y, z) >= 1))
(Tile::tiles[t]->getDestroyProgress(minecraft->player, minecraft->player->level, x, y, z) >= 1
// ||(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_InstantDestroy))
)
)
{ {
destroyBlock(x, y, z, face); destroyBlock(x, y, z, face);
} }
@ -164,7 +170,15 @@ void MultiPlayerGameMode::startDestroyBlock(int x, int y, int z, int face)
destroyingItem = minecraft->player->getCarriedItem(); destroyingItem = minecraft->player->getCarriedItem();
destroyProgress = 0; destroyProgress = 0;
destroyTicks = 0; destroyTicks = 0;
minecraft->level->destroyTileProgress(minecraft->player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, (int)(destroyProgress * 10) - 1);
// Inform renderer immediately that this tile is about to be destroyed to avoid lingering visuals/collision
if (minecraft->levelRenderer && minecraft->levelRenderer->destroyedTileManager)
{
minecraft->levelRenderer->destroyedTileManager->destroyingTileAt(minecraft->level, xDestroyBlock, yDestroyBlock, zDestroyBlock);
}
lastSentDestroyState = -2;
minecraft->level->destroyTileProgress(minecraft->player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, static_cast<int>(destroyProgress * 10) - 1);
} }
} }
@ -174,7 +188,7 @@ void MultiPlayerGameMode::stopDestroyBlock()
{ {
if (isDestroying) if (isDestroying)
{ {
connection->send(shared_ptr<PlayerActionPacket>(new PlayerActionPacket(PlayerActionPacket::ABORT_DESTROY_BLOCK, xDestroyBlock, yDestroyBlock, zDestroyBlock, -1))); connection->send(std::make_shared<PlayerActionPacket>(PlayerActionPacket::ABORT_DESTROY_BLOCK, xDestroyBlock, yDestroyBlock, zDestroyBlock, -1));
} }
isDestroying = false; isDestroying = false;
@ -186,7 +200,6 @@ void MultiPlayerGameMode::continueDestroyBlock(int x, int y, int z, int face)
{ {
if(!minecraft->player->isAllowedToMine()) return; if(!minecraft->player->isAllowedToMine()) return;
ensureHasSentCarriedItem(); ensureHasSentCarriedItem();
// connection.send(new PlayerActionPacket(PlayerActionPacket.CONTINUE_DESTROY_BLOCK, x, y, z, face));
if (destroyDelay > 0) if (destroyDelay > 0)
{ {
@ -197,7 +210,7 @@ void MultiPlayerGameMode::continueDestroyBlock(int x, int y, int z, int face)
if (localPlayerMode->isCreative()) if (localPlayerMode->isCreative())
{ {
destroyDelay = 5; destroyDelay = 5;
connection->send(shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face) ) ); connection->send(std::make_shared<PlayerActionPacket>(PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face));
creativeDestroyBlock(minecraft, this, x, y, z, face); creativeDestroyBlock(minecraft, this, x, y, z, face);
return; return;
} }
@ -216,11 +229,16 @@ void MultiPlayerGameMode::continueDestroyBlock(int x, int y, int z, int face)
if (destroyTicks % 4 == 0) if (destroyTicks % 4 == 0)
{ {
if (tile != NULL) if (tile != nullptr)
{ {
int iStepSound=tile->soundType->getStepSound(); const int iStepSound=tile->soundType->getStepSound();
minecraft->soundEngine->play(iStepSound, x + 0.5f, y + 0.5f, z + 0.5f, (tile->soundType->getVolume() + 1) / 8, tile->soundType->getPitch() * 0.5f); minecraft->soundEngine->play(iStepSound,
static_cast<float>(x) + 0.5f,
static_cast<float>(y) + 0.5f,
static_cast<float>(z) + 0.5f,
(tile->soundType->getVolume() + 1) / 8,
tile->soundType->getPitch() * 0.5f);
} }
} }
@ -229,14 +247,21 @@ void MultiPlayerGameMode::continueDestroyBlock(int x, int y, int z, int face)
if (destroyProgress >= 1) if (destroyProgress >= 1)
{ {
isDestroying = false; isDestroying = false;
connection->send( shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::STOP_DESTROY_BLOCK, x, y, z, face) ) ); connection->send(std::make_shared<PlayerActionPacket>(PlayerActionPacket::STOP_DESTROY_BLOCK, x, y, z, face));
destroyBlock(x, y, z, face); destroyBlock(x, y, z, face);
destroyProgress = 0; destroyProgress = 0;
destroyTicks = 0; destroyTicks = 0;
destroyDelay = 5; destroyDelay = 5;
} }
minecraft->level->destroyTileProgress(minecraft->player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, (int)(destroyProgress * 10) - 1); int state = static_cast<int>(destroyProgress * 10);
state = min(state, 10);
state = max(state, -1);
if (state != lastSentDestroyState)
{
minecraft->level->destroyTileProgress(minecraft->player->entityId, xDestroyBlock, yDestroyBlock, zDestroyBlock, state);
lastSentDestroyState = state;
}
} }
else else
{ {
@ -263,8 +288,8 @@ void MultiPlayerGameMode::tick()
bool MultiPlayerGameMode::sameDestroyTarget(int x, int y, int z) bool MultiPlayerGameMode::sameDestroyTarget(int x, int y, int z)
{ {
shared_ptr<ItemInstance> selected = minecraft->player->getCarriedItem(); shared_ptr<ItemInstance> selected = minecraft->player->getCarriedItem();
bool sameItems = destroyingItem == NULL && selected == NULL; bool sameItems = destroyingItem == nullptr && selected == nullptr;
if (destroyingItem != NULL && selected != NULL) if (destroyingItem != nullptr && selected != nullptr)
{ {
sameItems = sameItems =
selected->id == destroyingItem->id && selected->id == destroyingItem->id &&
@ -280,25 +305,25 @@ void MultiPlayerGameMode::ensureHasSentCarriedItem()
if (newItem != carriedItem) if (newItem != carriedItem)
{ {
carriedItem = newItem; carriedItem = newItem;
connection->send( shared_ptr<SetCarriedItemPacket>( new SetCarriedItemPacket(carriedItem) ) ); connection->send(std::make_shared<SetCarriedItemPacket>(carriedItem));
} }
} }
bool 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) bool 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)
{ {
if( pbUsedItem ) *pbUsedItem = false; // Did we actually use the held item? if( pbUsedItem ) *pbUsedItem = false;
// 4J-PB - Adding a test only version to allow tooltips to be displayed // 4J-PB - Adding a test only version to allow tooltips to be displayed
if(!bTestUseOnly) if(!bTestUseOnly)
{ {
ensureHasSentCarriedItem(); ensureHasSentCarriedItem();
} }
float clickX = (float) hit->x - x; float clickX = static_cast<float>(hit->x) - x;
float clickY = (float) hit->y - y; float clickY = static_cast<float>(hit->y) - y;
float clickZ = (float) hit->z - z; float clickZ = static_cast<float>(hit->z) - z;
bool didSomething = false; bool didSomething = false;
if (!player->isSneaking() || player->getCarriedItem() == NULL) if (!player->isSneaking() || player->getCarriedItem() == nullptr)
{ {
int t = level->getTile(x, y, z); int t = level->getTile(x, y, z);
if (t > 0 && player->isAllowedToUse(Tile::tiles[t])) if (t > 0 && player->isAllowedToUse(Tile::tiles[t]))
@ -331,7 +356,7 @@ bool MultiPlayerGameMode::useItemOn(shared_ptr<Player> player, Level *level, sha
} }
} }
if (!didSomething && item != NULL && dynamic_cast<TileItem *>(item->getItem())) if (!didSomething && item != nullptr && dynamic_cast<TileItem *>(item->getItem()))
{ {
TileItem *tile = dynamic_cast<TileItem *>(item->getItem()); TileItem *tile = dynamic_cast<TileItem *>(item->getItem());
if (!tile->mayPlace(level, x, y, z, face, player, item)) return false; if (!tile->mayPlace(level, x, y, z, face, player, item)) return false;
@ -339,7 +364,7 @@ bool MultiPlayerGameMode::useItemOn(shared_ptr<Player> player, Level *level, sha
// 4J Stu - In Java we send the use packet before the above check for item being NULL // 4J Stu - In Java we send the use packet before the above check for item being NULL
// so the following never gets executed but the packet still gets sent (for opening chests etc) // so the following never gets executed but the packet still gets sent (for opening chests etc)
if(item != NULL) if(item != nullptr)
{ {
if(!didSomething && player->isAllowedToUse(item)) if(!didSomething && player->isAllowedToUse(item))
{ {
@ -383,7 +408,7 @@ bool MultiPlayerGameMode::useItemOn(shared_ptr<Player> player, Level *level, sha
// Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water. // Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water.
if(!bTestUseOnly) if(!bTestUseOnly)
{ {
connection->send( shared_ptr<UseItemPacket>( new UseItemPacket(x, y, z, face, player->inventory->getSelected(), clickX, clickY, clickZ) ) ); connection->send(std::make_shared<UseItemPacket>(x, y, z, face, player->inventory->getSelected(), clickX, clickY, clickZ));
} }
return didSomething; return didSomething;
} }
@ -412,7 +437,7 @@ bool MultiPlayerGameMode::useItem(shared_ptr<Player> player, Level *level, share
{ {
int oldCount = item->count; int oldCount = item->count;
shared_ptr<ItemInstance> itemInstance = item->use(level, player); shared_ptr<ItemInstance> itemInstance = item->use(level, player);
if ((itemInstance != NULL && itemInstance != item) || (itemInstance != NULL && itemInstance->count != oldCount)) if ((itemInstance != nullptr && itemInstance != item) || (itemInstance != nullptr && itemInstance->count != oldCount))
{ {
player->inventory->items[player->inventory->selected] = itemInstance; player->inventory->items[player->inventory->selected] = itemInstance;
if (itemInstance->count == 0) if (itemInstance->count == 0)
@ -425,27 +450,27 @@ bool MultiPlayerGameMode::useItem(shared_ptr<Player> player, Level *level, share
if(!bTestUseOnly) if(!bTestUseOnly)
{ {
connection->send( shared_ptr<UseItemPacket>( new UseItemPacket(-1, -1, -1, 255, player->inventory->getSelected(), 0, 0, 0) ) ); connection->send(std::make_shared<UseItemPacket>(-1, -1, -1, 255, player->inventory->getSelected(), 0, 0, 0));
} }
return result; return result;
} }
shared_ptr<MultiplayerLocalPlayer> MultiPlayerGameMode::createPlayer(Level *level) shared_ptr<MultiplayerLocalPlayer> MultiPlayerGameMode::createPlayer(Level *level)
{ {
return shared_ptr<MultiplayerLocalPlayer>( new MultiplayerLocalPlayer(minecraft, level, minecraft->user, connection) ); return std::make_shared<MultiplayerLocalPlayer>(minecraft, level, minecraft->user, connection);
} }
void MultiPlayerGameMode::attack(shared_ptr<Player> player, shared_ptr<Entity> entity) void MultiPlayerGameMode::attack(shared_ptr<Player> player, shared_ptr<Entity> entity)
{ {
ensureHasSentCarriedItem(); ensureHasSentCarriedItem();
connection->send( shared_ptr<InteractPacket>( new InteractPacket(player->entityId, entity->entityId, InteractPacket::ATTACK) ) ); connection->send(std::make_shared<InteractPacket>(player->entityId, entity->entityId, InteractPacket::ATTACK));
player->attack(entity); player->attack(entity);
} }
bool MultiPlayerGameMode::interact(shared_ptr<Player> player, shared_ptr<Entity> entity) bool MultiPlayerGameMode::interact(shared_ptr<Player> player, shared_ptr<Entity> entity)
{ {
ensureHasSentCarriedItem(); ensureHasSentCarriedItem();
connection->send(shared_ptr<InteractPacket>( new InteractPacket(player->entityId, entity->entityId, InteractPacket::INTERACT) ) ); connection->send(std::make_shared<InteractPacket>(player->entityId, entity->entityId, InteractPacket::INTERACT));
return player->interact(entity); return player->interact(entity);
} }
@ -454,36 +479,36 @@ shared_ptr<ItemInstance> MultiPlayerGameMode::handleInventoryMouseClick(int cont
short changeUid = player->containerMenu->backup(player->inventory); short changeUid = player->containerMenu->backup(player->inventory);
shared_ptr<ItemInstance> clicked = player->containerMenu->clicked(slotNum, buttonNum, quickKeyHeld?AbstractContainerMenu::CLICK_QUICK_MOVE:AbstractContainerMenu::CLICK_PICKUP, player); shared_ptr<ItemInstance> clicked = player->containerMenu->clicked(slotNum, buttonNum, quickKeyHeld?AbstractContainerMenu::CLICK_QUICK_MOVE:AbstractContainerMenu::CLICK_PICKUP, player);
connection->send( shared_ptr<ContainerClickPacket>( new ContainerClickPacket(containerId, slotNum, buttonNum, quickKeyHeld, clicked, changeUid) ) ); connection->send(std::make_shared<ContainerClickPacket>(containerId, slotNum, buttonNum, quickKeyHeld, clicked, changeUid));
return clicked; return clicked;
} }
void MultiPlayerGameMode::handleInventoryButtonClick(int containerId, int buttonId) void MultiPlayerGameMode::handleInventoryButtonClick(int containerId, int buttonId)
{ {
connection->send(shared_ptr<ContainerButtonClickPacket>( new ContainerButtonClickPacket(containerId, buttonId) )); connection->send(std::make_shared<ContainerButtonClickPacket>(containerId, buttonId));
} }
void MultiPlayerGameMode::handleCreativeModeItemAdd(shared_ptr<ItemInstance> clicked, int slot) void MultiPlayerGameMode::handleCreativeModeItemAdd(shared_ptr<ItemInstance> clicked, int slot)
{ {
if (localPlayerMode->isCreative()) if (localPlayerMode->isCreative())
{ {
connection->send(shared_ptr<SetCreativeModeSlotPacket>( new SetCreativeModeSlotPacket(slot, clicked) ) ); connection->send(std::make_shared<SetCreativeModeSlotPacket>(slot, clicked));
} }
} }
void MultiPlayerGameMode::handleCreativeModeItemDrop(shared_ptr<ItemInstance> clicked) void MultiPlayerGameMode::handleCreativeModeItemDrop(shared_ptr<ItemInstance> clicked)
{ {
if (localPlayerMode->isCreative() && clicked != NULL) if (localPlayerMode->isCreative() && clicked != nullptr)
{ {
connection->send(shared_ptr<SetCreativeModeSlotPacket>( new SetCreativeModeSlotPacket(-1, clicked) ) ); connection->send(std::make_shared<SetCreativeModeSlotPacket>(-1, clicked));
} }
} }
void MultiPlayerGameMode::releaseUsingItem(shared_ptr<Player> player) void MultiPlayerGameMode::releaseUsingItem(shared_ptr<Player> player)
{ {
ensureHasSentCarriedItem(); ensureHasSentCarriedItem();
connection->send(shared_ptr<PlayerActionPacket>( new PlayerActionPacket(PlayerActionPacket::RELEASE_USE_ITEM, 0, 0, 0, 255) ) ); connection->send(std::make_shared<PlayerActionPacket>(PlayerActionPacket::RELEASE_USE_ITEM, 0, 0, 0, 255));
player->releaseUsingItem(); player->releaseUsingItem();
} }
@ -507,8 +532,6 @@ bool MultiPlayerGameMode::hasFarPickRange()
return localPlayerMode->isCreative(); return localPlayerMode->isCreative();
} }
// Returns true when the inventory is opened from the server-side. Currently
// only happens when the player is riding a horse.
bool MultiPlayerGameMode::isServerControlledInventory() bool MultiPlayerGameMode::isServerControlledInventory()
{ {
return minecraft->player->isRiding() && minecraft->player->riding->instanceof(eTYPE_HORSE); return minecraft->player->isRiding() && minecraft->player->riding->instanceof(eTYPE_HORSE);
@ -518,7 +541,7 @@ bool MultiPlayerGameMode::handleCraftItem(int recipe, shared_ptr<Player> player)
{ {
short changeUid = player->containerMenu->backup(player->inventory); short changeUid = player->containerMenu->backup(player->inventory);
connection->send( shared_ptr<CraftItemPacket>( new CraftItemPacket(recipe, changeUid) ) ); connection->send(std::make_shared<CraftItemPacket>(recipe, changeUid));
return true; return true;
} }
@ -526,5 +549,5 @@ bool MultiPlayerGameMode::handleCraftItem(int recipe, shared_ptr<Player> player)
void MultiPlayerGameMode::handleDebugOptions(unsigned int uiVal, shared_ptr<Player> player) void MultiPlayerGameMode::handleDebugOptions(unsigned int uiVal, shared_ptr<Player> player)
{ {
player->SetDebugOptions(uiVal); player->SetDebugOptions(uiVal);
connection->send( shared_ptr<DebugOptionsPacket>( new DebugOptionsPacket(uiVal) ) ); connection->send(std::make_shared<DebugOptionsPacket>(uiVal));
} }

View file

@ -65,5 +65,8 @@ public:
// 4J Stu - Added for tutorial checks // 4J Stu - Added for tutorial checks
virtual bool isInputAllowed(int mapping) { return true; } virtual bool isInputAllowed(int mapping) { return true; }
virtual bool isTutorial() { return false; } virtual bool isTutorial() { return false; }
virtual Tutorial *getTutorial() { return NULL; } virtual Tutorial *getTutorial() { return nullptr; }
// Cache of last destroy progress state sent to avoid redundant calls
int lastSentDestroyState;
}; };