diff --git a/Minecraft.Client/Player/EntityTracker.cpp b/Minecraft.Client/Player/EntityTracker.cpp index 802f7480d..81e6b020d 100644 --- a/Minecraft.Client/Player/EntityTracker.cpp +++ b/Minecraft.Client/Player/EntityTracker.cpp @@ -18,6 +18,7 @@ #include "../../Minecraft.World/Headers/net.minecraft.network.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.dimension.h" #include "../../Minecraft.World/Util/BasicTypeContainers.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.level.chunk.h" #include "../Network/PlayerConnection.h" EntityTracker::EntityTracker(ServerLevel* level) { @@ -26,7 +27,7 @@ EntityTracker::EntityTracker(ServerLevel* level) { } void EntityTracker::addEntity(std::shared_ptr e) { - if (e->GetType() == eTYPE_SERVERPLAYER) { + if (e->instanceof(eTYPE_SERVERPLAYER)) { addEntity(e, 32 * 16, 2); std::shared_ptr player = std::dynamic_pointer_cast(e); @@ -35,51 +36,57 @@ void EntityTracker::addEntity(std::shared_ptr e) { (*it)->updatePlayer(this, player); } } - } else if (e->GetType() == eTYPE_FISHINGHOOK) + } else if (e->instanceof(eTYPE_FISHINGHOOK)) addEntity(e, 16 * 4, 5, true); - else if (e->GetType() == eTYPE_SMALL_FIREBALL) + else if (e->instanceof(eTYPE_SMALL_FIREBALL)) addEntity(e, 16 * 4, 10, false); - else if (e->GetType() == eTYPE_DRAGON_FIREBALL) + else if (e->instanceof(eTYPE_DRAGON_FIREBALL)) addEntity(e, 16 * 4, 10, false); // 4J Added TU9 - else if (e->GetType() == eTYPE_ARROW) + else if (e->instanceof(eTYPE_ARROW)) addEntity(e, 16 * 4, 20, false); - else if (e->GetType() == eTYPE_FIREBALL) + else if (e->instanceof(eTYPE_FIREBALL)) addEntity(e, 16 * 4, 10, false); - else if (e->GetType() == eTYPE_SNOWBALL) + else if (e->instanceof(eTYPE_SNOWBALL)) addEntity(e, 16 * 4, 10, true); - else if (e->GetType() == eTYPE_THROWNENDERPEARL) + else if (e->instanceof(eTYPE_THROWNENDERPEARL)) addEntity(e, 16 * 4, 10, true); - else if (e->GetType() == eTYPE_EYEOFENDERSIGNAL) + else if (e->instanceof(eTYPE_EYEOFENDERSIGNAL)) addEntity(e, 16 * 4, 4, true); - else if (e->GetType() == eTYPE_THROWNEGG) + else if (e->instanceof(eTYPE_THROWNEGG)) addEntity(e, 16 * 4, 10, true); - else if (e->GetType() == eTYPE_THROWNPOTION) + else if (e->instanceof(eTYPE_THROWNPOTION)) addEntity(e, 16 * 4, 10, true); - else if (e->GetType() == eTYPE_THROWNEXPBOTTLE) + else if (e->instanceof(eTYPE_THROWNEXPBOTTLE)) addEntity(e, 16 * 4, 10, true); - else if (e->GetType() == eTYPE_ITEMENTITY) + else if (e->instanceof(eTYPE_FIREWORKS_ROCKET)) + addEntity(e, 16 * 4, 10, true); + else if (e->instanceof(eTYPE_ITEMENTITY)) addEntity(e, 16 * 4, 20, true); - else if (e->GetType() == eTYPE_MINECART) + else if (e->instanceof(eTYPE_MINECART)) addEntity(e, 16 * 5, 3, true); - else if (e->GetType() == eTYPE_BOAT) + else if (e->instanceof(eTYPE_BOAT)) addEntity(e, 16 * 5, 3, true); - else if (e->GetType() == eTYPE_SQUID) + else if (e->instanceof(eTYPE_SQUID)) addEntity(e, 16 * 4, 3, true); + else if (e->instanceof(eTYPE_WITHERBOSS)) + addEntity(e, 16 * 5, 3, false); + else if (e->instanceof(eTYPE_BAT)) + addEntity(e, 16 * 5, 3, false); else if (std::dynamic_pointer_cast(e) != NULL) addEntity(e, 16 * 5, 3, true); - else if (e->GetType() == eTYPE_ENDERDRAGON) + else if (e->instanceof(eTYPE_ENDERDRAGON)) addEntity(e, 16 * 10, 3, true); - else if (e->GetType() == eTYPE_PRIMEDTNT) + else if (e->instanceof(eTYPE_PRIMEDTNT)) addEntity(e, 16 * 10, 10, true); - else if (e->GetType() == eTYPE_FALLINGTILE) + else if (e->instanceof(eTYPE_FALLINGTILE)) addEntity(e, 16 * 10, 20, true); - else if (e->GetType() == eTYPE_PAINTING) + else if (e->instanceof(eTYPE_HANGING_ENTITY)) addEntity(e, 16 * 10, INT_MAX, false); - else if (e->GetType() == eTYPE_EXPERIENCEORB) + else if (e->instanceof(eTYPE_EXPERIENCEORB)) addEntity(e, 16 * 10, 20, true); - else if (e->GetType() == eTYPE_ENDER_CRYSTAL) + else if (e->instanceof(eTYPE_ENDER_CRYSTAL)) addEntity(e, 16 * 16, INT_MAX, false); - else if (e->GetType() == eTYPE_ITEM_FRAME) + else if (e->instanceof(eTYPE_ITEM_FRAME)) addEntity(e, 16 * 10, INT_MAX, false); } @@ -125,6 +132,10 @@ void EntityTracker::removePlayer(std::shared_ptr e) { for (AUTO_VAR(it, entities.begin()); it != entities.end(); it++) { (*it)->removePlayer(player); } + + // 4J: Flush now to ensure remove packets are sent before player + // respawns and add entity packets are sent + player->flushEntitiesToRemove(); } } @@ -216,6 +227,17 @@ void EntityTracker::clear(std::shared_ptr serverPlayer) { } } +void EntityTracker::playerLoadedChunk(std::shared_ptr player, + LevelChunk* chunk) { + for (AUTO_VAR(it, entities.begin()); it != entities.end(); ++it) { + std::shared_ptr te = *it; + if (te->e != player && te->e->xChunk == chunk->x && + te->e->zChunk == chunk->z) { + te->updatePlayer(this, player); + } + } +} + // AP added for Vita so the range can be increased once the level starts void EntityTracker::updateMaxRange() { maxRange = level->getServer()->getPlayers()->getMaxRange(); diff --git a/Minecraft.Client/Player/EntityTracker.h b/Minecraft.Client/Player/EntityTracker.h index 3a0fb8471..55c657f12 100644 --- a/Minecraft.Client/Player/EntityTracker.h +++ b/Minecraft.Client/Player/EntityTracker.h @@ -29,6 +29,8 @@ public: void broadcastAndSend(std::shared_ptr e, std::shared_ptr packet); void clear(std::shared_ptr serverPlayer); + void playerLoadedChunk(std::shared_ptr player, + LevelChunk* chunk); void updateMaxRange(); // AP added for Vita // 4J-JEV: Added, needed access to tracked entity of a riders mount. diff --git a/Minecraft.Client/Player/LocalPlayer.cpp b/Minecraft.Client/Player/LocalPlayer.cpp index 4689b25f7..efad25d6e 100644 --- a/Minecraft.Client/Player/LocalPlayer.cpp +++ b/Minecraft.Client/Player/LocalPlayer.cpp @@ -16,18 +16,22 @@ #include "../GameState/CreativeMode.h" #include "../Rendering/GameRenderer.h" #include "../Rendering/EntityRenderers/ItemInHandRenderer.h" +#include "../../Minecraft.World/AI/Attributes/AttributeInstance.h" #include "../../Minecraft.World/Level/LevelData.h" #include "../../Minecraft.World/Headers/net.minecraft.world.damagesource.h" #include "../../Minecraft.World/Headers/net.minecraft.world.item.h" #include "../../Minecraft.World/Headers/net.minecraft.world.food.h" #include "../../Minecraft.World/Headers/net.minecraft.world.effect.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.player.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.entity.monster.h" #include "../../Minecraft.World/Entities/ItemEntity.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.level.tile.entity.h" #include "../../Minecraft.World/Headers/net.minecraft.world.phys.h" #include "../../Minecraft.World/Headers/net.minecraft.stats.h" #include "../../Minecraft.World/Headers/com.mojang.nbt.h" #include "../../Minecraft.World/Util/Random.h" +#include "../../Minecraft.World/Blocks/TileEntities/TileEntity.h" #include "../../Minecraft.World/Util/Mth.h" #include "../UI/Screens/AchievementPopup.h" #include "../Rendering/Particles/CritParticle.h" @@ -55,7 +59,7 @@ LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, int dimension) - : Player(level) { + : Player(level, user->name) { flyX = flyY = flyZ = 0.0f; // 4J added m_awardedThisSession = 0; @@ -64,6 +68,10 @@ LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, twoJumpsRegistered = false; sprintTime = 0; m_uiInactiveTicks = 0; + portalTime = 0.0f; + oPortalTime = 0.0f; + jumpRidingTicks = 0; + jumpRidingScale = 0.0f; yBob = xBob = yBobO = xBobO = 0.0f; @@ -76,7 +84,6 @@ LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, } if (user != NULL) { this->name = user->name; - m_UUID = name; // wprintf(L"Created LocalPlayer with name %ls\n", name.c_str() ); // check to see if this player's xuid is in the list of special players MOJANG_DATA* pMojangData = app.GetMojangDataForXuid(getOnlineXuid()); @@ -116,28 +123,6 @@ LocalPlayer::~LocalPlayer() { if (this->input != NULL) delete input; } -// 4J - added noEntityCubes parameter -void LocalPlayer::move(double xa, double ya, double za, bool noEntityCubes) { - if (ClientConstants::DEADMAU5_CAMERA_CHEATS) { - if (shared_from_this() == minecraft->player && - minecraft->options->isFlying) { - noPhysics = true; - float tmp = walkDist; // update - calculateFlight((float)xa, (float)ya, (float)za); - fallDistance = 0.0f; - yd = 0.0f; - Player::move(flyX, flyY, flyZ, noEntityCubes); - onGround = true; - walkDist = tmp; - } else { - noPhysics = false; - Player::move(xa, ya, za, noEntityCubes); - } - } else { - Player::move(xa, ya, za, noEntityCubes); - } -} - void LocalPlayer::calculateFlight(float xa, float ya, float za) { xa = xa * minecraft->options->flySpeed; ya = 0; @@ -193,7 +178,7 @@ void LocalPlayer::serverAiStep() { // mapPlayerChunk(8); } -bool LocalPlayer::isEffectiveAI() { return true; } +bool LocalPlayer::isEffectiveAi() { return true; } void LocalPlayer::aiStep() { if (sprintTime > 0) { @@ -248,7 +233,7 @@ void LocalPlayer::aiStep() { // input->tick( std::dynamic_pointer_cast( shared_from_this() ) ); // 4J-PB - make it a localplayer input->tick(this); - if (isUsingItem()) { + if (isUsingItem() && !isRiding()) { input->xa *= 0.2f; input->ya *= 0.2f; sprintTriggerTime = 0; @@ -373,6 +358,36 @@ void LocalPlayer::aiStep() { } } + if (isRidingJumpable()) { + if (jumpRidingTicks < 0) { + jumpRidingTicks++; + if (jumpRidingTicks == 0) { + // reset scale (for gui) + jumpRidingScale = 0; + } + } + if (wasJumping && !input->jumping) { + // jump release + jumpRidingTicks = -10; + sendRidingJump(); + } else if (!wasJumping && input->jumping) { + // jump press + jumpRidingTicks = 0; + jumpRidingScale = 0; + } else if (wasJumping) { + // calc jump scale + jumpRidingTicks++; + if (jumpRidingTicks < 10) { + jumpRidingScale = (float)jumpRidingTicks * .1f; + } else { + jumpRidingScale = + .8f + (2.f / ((float)(jumpRidingTicks - 9))) * .1f; + } + } + } else { + jumpRidingScale = 0; + } + Player::aiStep(); // 4J-PB - If we're in Creative Mode, allow flying on ground @@ -491,8 +506,10 @@ float LocalPlayer::getFieldOfViewModifier() { // modify for movement if (abilities.flying) targetFov *= 1.1f; - targetFov *= - ((walkingSpeed * getWalkingSpeedModifier()) / defaultWalkSpeed + 1) / 2; + + AttributeInstance* speed = + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + targetFov *= (speed->getValue() / abilities.getWalkingSpeed() + 1) / 2; // modify for bow =) if (isUsingItem() && getUseItem()->id == Item::bow->id) { @@ -511,12 +528,12 @@ float LocalPlayer::getFieldOfViewModifier() { void LocalPlayer::addAdditonalSaveData(CompoundTag* entityTag) { Player::addAdditonalSaveData(entityTag); - entityTag->putInt(L"Score", score); + // entityTag->putInt(L"Score", score); } void LocalPlayer::readAdditionalSaveData(CompoundTag* entityTag) { Player::readAdditionalSaveData(entityTag); - score = entityTag->getInt(L"Score"); + // score = entityTag->getInt(L"Score"); } void LocalPlayer::closeContainer() { @@ -530,12 +547,23 @@ void LocalPlayer::closeContainer() { ui.CloseUIScenes(m_iPad); } -void LocalPlayer::openTextEdit(std::shared_ptr sign) { +void LocalPlayer::openTextEdit(std::shared_ptr tileEntity) { #ifdef ENABLE_JAVA_GUIS minecraft->setScreen(new TextEditScreen(sign)); bool success = true; #else - bool success = app.LoadSignEntryMenu(GetXboxPad(), sign); + bool success; + + if (tileEntity->GetType() == eTYPE_SIGNTILEENTITY) { + success = app.LoadSignEntryMenu( + GetXboxPad(), + std::dynamic_pointer_cast(tileEntity)); + } else if (tileEntity->GetType() == eTYPE_COMMANDBLOCKTILEENTITY) { + success = app.LoadCommandBlockMenu( + GetXboxPad(), + std::dynamic_pointer_cast(tileEntity)); + } + if (success) ui.PlayUISFX(eSFX_Press); #endif } @@ -548,6 +576,30 @@ bool LocalPlayer::openContainer(std::shared_ptr container) { bool success = app.LoadContainerMenu(GetXboxPad(), inventory, container); if (success) ui.PlayUISFX(eSFX_Press); #endif + // minecraft->setScreen(new ContainerScreen(inventory, container)); + return success; +} + +bool LocalPlayer::openHopper(std::shared_ptr container) { + // minecraft->setScreen(new HopperScreen(inventory, container)); + bool success = app.LoadHopperMenu(GetXboxPad(), inventory, container); + if (success) ui.PlayUISFX(eSFX_Press); + return success; +} + +bool LocalPlayer::openHopper(std::shared_ptr container) { + // minecraft->setScreen(new HopperScreen(inventory, container)); + bool success = app.LoadHopperMenu(GetXboxPad(), inventory, container); + if (success) ui.PlayUISFX(eSFX_Press); + return success; +} + +bool LocalPlayer::openHorseInventory(std::shared_ptr horse, + std::shared_ptr container) { + // minecraft->setScreen(new HorseInventoryScreen(inventory, container, + // horse)); + bool success = app.LoadHorseMenu(GetXboxPad(), inventory, container, horse); + if (success) ui.PlayUISFX(eSFX_Press); return success; } @@ -562,12 +614,22 @@ bool LocalPlayer::startCrafting(int x, int y, int z) { if (success) ui.PlayUISFX(eSFX_Press); #endif // app.LoadXuiCraftMenu(0,inventory, level, x, y, z); + // minecraft->setScreen(new CraftingScreen(inventory, level, x, y, z)); return success; } -bool LocalPlayer::startEnchanting(int x, int y, int z) { +bool LocalPlayer::openFireworks(int x, int y, int z) { + bool success = app.LoadFireworksMenu( + GetXboxPad(), + std::dynamic_pointer_cast(shared_from_this()), x, y, z); + if (success) ui.PlayUISFX(eSFX_Press); + return success; +} + +bool LocalPlayer::startEnchanting(int x, int y, int z, + const std::wstring& name) { bool success = - app.LoadEnchantingMenu(GetXboxPad(), inventory, x, y, z, level); + app.LoadEnchantingMenu(GetXboxPad(), inventory, x, y, z, level, name); if (success) ui.PlayUISFX(eSFX_Press); // minecraft.setScreen(new EnchantmentScreen(inventory, level, x, y, z)); return success; @@ -606,6 +668,13 @@ bool LocalPlayer::openBrewingStand( return success; } +bool LocalPlayer::openBeacon(std::shared_ptr beacon) { + // minecraft->setScreen(new BeaconScreen(inventory, beacon)); + bool success = app.LoadBeaconMenu(GetXboxPad(), inventory, beacon); + if (success) ui.PlayUISFX(eSFX_Press); + return success; +} + bool LocalPlayer::openTrap(std::shared_ptr trap) { bool success = app.LoadTrapMenu(GetXboxPad(), inventory, trap); if (success) ui.PlayUISFX(eSFX_Press); @@ -613,9 +682,10 @@ bool LocalPlayer::openTrap(std::shared_ptr trap) { return success; } -bool LocalPlayer::openTrading(std::shared_ptr traderTarget) { +bool LocalPlayer::openTrading(std::shared_ptr traderTarget, + const std::wstring& name) { bool success = - app.LoadTradingMenu(GetXboxPad(), inventory, traderTarget, level); + app.LoadTradingMenu(GetXboxPad(), inventory, traderTarget, level, name); if (success) ui.PlayUISFX(eSFX_Press); // minecraft.setScreen(new MerchantScreen(inventory, traderTarget, level)); return success; @@ -645,8 +715,8 @@ void LocalPlayer::chat(const std::wstring& message) {} bool LocalPlayer::isSneaking() { return input->sneaking && !m_isSleeping; } -void LocalPlayer::hurtTo(int newHealth, ETelemetryChallenges damageSource) { - int dmg = getHealth() - newHealth; +void LocalPlayer::hurtTo(float newHealth, ETelemetryChallenges damageSource) { + float dmg = getHealth() - newHealth; if (dmg <= 0) { setHealth(newHealth); if (dmg < 0) { @@ -660,8 +730,9 @@ void LocalPlayer::hurtTo(int newHealth, ETelemetryChallenges damageSource) { hurtTime = hurtDuration = 10; } - if (this->health <= 0) { - int deathTime = (int)(level->getTime() % Level::TICKS_PER_DAY) / 1000; + if (this->getHealth() <= 0) { + int deathTime = + (int)(level->getGameTime() % Level::TICKS_PER_DAY) / 1000; int carriedId = inventory->getSelected() == NULL ? 0 : inventory->getSelected()->id; TelemetryManager->RecordPlayerDiedOrFailed(GetXboxPad(), 0, y, 0, 0, @@ -972,15 +1043,15 @@ void LocalPlayer::awardStat(Stat* stat, byteArray param) { bool justPickedupWool = false; for (int i = 0; i < 16; i++) - if (stat == GenericStats::itemsCollected(Tile::cloth_Id, i)) + if (stat == GenericStats::itemsCollected(Tile::wool_Id, i)) justPickedupWool = true; if (justPickedupWool) { unsigned int woolCount = 0; for (unsigned int i = 0; i < 16; i++) { - if (pStats->getTotalValue(GenericStats::itemsCollected( - Tile::cloth_Id, i)) > 0) + if (pStats->getTotalValue( + GenericStats::itemsCollected(Tile::wool_Id, i)) > 0) woolCount++; } @@ -1084,6 +1155,33 @@ void LocalPlayer::setExperienceValues(float experienceProgress, int totalExp, this->experienceLevel = experienceLevel; } +// 4J: removed +// void LocalPlayer::sendMessage(ChatMessageComponent *message) +//{ +// minecraft->gui->getChat()->addMessage(message.toString(true)); +//} + +Pos LocalPlayer::getCommandSenderWorldPosition() { + return new Pos(floor(x + .5), floor(y + .5), floor(z + .5)); +} + +std::shared_ptr LocalPlayer::getCarriedItem() { + return inventory->getSelected(); +} + +void LocalPlayer::playSound(int soundId, float volume, float pitch) { + level->playLocalSound(x, y - heightOffset, z, soundId, volume, pitch, + false); +} + +bool LocalPlayer::isRidingJumpable() { + return riding != NULL && riding->GetType() == eTYPE_HORSE; +} + +float LocalPlayer::getJumpRidingScale() { return jumpRidingScale; } + +void LocalPlayer::sendRidingJump() {} + bool LocalPlayer::hasPermission(EGameCommand command) { return level->getLevelData()->getAllowCommands(); } @@ -1168,7 +1266,7 @@ void LocalPlayer::handleMouseDown(int button, bool down) { minecraft->gameMode->continueDestroyBlock(x, y, z, minecraft->hitResult->f); - if (mayBuild(x, y, z)) { + if (mayDestroyBlockAt(x, y, z)) { minecraft->particleEngine->crack(x, y, z, minecraft->hitResult->f); swing(); } @@ -1449,15 +1547,12 @@ void LocalPlayer::updateRichPresence() { app.SetRichPresenceContext(m_iPad, CONTEXT_GAME_STATE_FISHING); } else if (selectedItem != NULL && selectedItem->id == Item::map_Id) { app.SetRichPresenceContext(m_iPad, CONTEXT_GAME_STATE_MAP); - } else if (riding != NULL && - std::dynamic_pointer_cast(riding) != NULL) { + } else if ((riding != NULL) && riding->instanceof(eTYPE_MINECART)) { app.SetRichPresenceContext(m_iPad, CONTEXT_GAME_STATE_RIDING_MINECART); - } else if (riding != NULL && - std::dynamic_pointer_cast(riding) != NULL) { + } else if ((riding != NULL) && riding->instanceof(eTYPE_BOAT)) { app.SetRichPresenceContext(m_iPad, CONTEXT_GAME_STATE_BOATING); - } else if (riding != NULL && - std::dynamic_pointer_cast(riding) != NULL) { + } else if ((riding != NULL) && riding->instanceof(eTYPE_PIG)) { app.SetRichPresenceContext(m_iPad, CONTEXT_GAME_STATE_RIDING_PIG); } else if (this->dimension == -1) { app.SetRichPresenceContext(m_iPad, CONTEXT_GAME_STATE_NETHER); diff --git a/Minecraft.Client/Player/LocalPlayer.h b/Minecraft.Client/Player/LocalPlayer.h index 28edd6270..9b7ed26b7 100644 --- a/Minecraft.Client/Player/LocalPlayer.h +++ b/Minecraft.Client/Player/LocalPlayer.h @@ -21,6 +21,8 @@ class LocalPlayer : public Player { public: static const int SPRINT_DURATION = 20 * 30; + eINSTANCEOF GetType() { return eTYPE_LOCALPLAYER; } + Input* input; protected: @@ -42,24 +44,23 @@ public: float yBob, xBob; float yBobO, xBobO; + float portalTime; + float oPortalTime; + LocalPlayer(Minecraft* minecraft, Level* level, User* user, int dimension); virtual ~LocalPlayer(); - void move( - double xa, double ya, double za, - bool noEntityCubes = false); // 4J - added noEntityCubes parameter - int m_iScreenSection; // assuming 4player splitscreen for now, or -1 for // single player - __uint64 + uint64_t ullButtonsPressed; // Stores the button presses, since the inputmanager - // can be ticked faster than the minecraft player - // tick, and a button press and release combo can be - // missed in the minecraft::tick + // can be ticked faster than the minecraft + // player tick, and a button press and release combo can be missed in the + // minecraft::tick - __uint64 ullDpad_last; - __uint64 ullDpad_this; - __uint64 ullDpad_filtered; + uint64_t ullDpad_last; + uint64_t ullDpad_this; + uint64_t ullDpad_filtered; // 4J-PB - moved these in from the minecraft structure, since they are per // player things for splitscreen @@ -74,6 +75,9 @@ public: private: float flyX, flyY, flyZ; + int jumpRidingTicks; + float jumpRidingScale; + protected: // 4J-PB - player's xbox pad int m_iPad; @@ -95,7 +99,7 @@ public: virtual void serverAiStep(); protected: - bool isEffectiveAI(); + bool isEffectiveAi(); public: virtual void aiStep(); @@ -104,26 +108,38 @@ public: virtual void addAdditonalSaveData(CompoundTag* entityTag); virtual void readAdditionalSaveData(CompoundTag* entityTag); virtual void closeContainer(); - virtual void openTextEdit(std::shared_ptr sign); + virtual void openTextEdit(std::shared_ptr sign); virtual bool openContainer( - std::shared_ptr container); // 4J added bool return - virtual bool startCrafting(int x, int y, int z); // 4J added bool return - virtual bool startEnchanting(int x, int y, int z); // 4J added bool return + std::shared_ptr container); // 4J added bool return + virtual bool openHopper( + std::shared_ptr container); // 4J added bool return + virtual bool openHopper( + std::shared_ptr container); // 4J added bool return + virtual bool openHorseInventory( + std::shared_ptr horse, + std::shared_ptr container); // 4J added bool return + virtual bool startCrafting(int x, int y, int z); // 4J added bool return + virtual bool openFireworks(int x, int y, int z); // 4J added + virtual bool startEnchanting( + int x, int y, int z, const std::wstring& name); // 4J added bool return virtual bool startRepairing(int x, int y, int z); virtual bool openFurnace( std::shared_ptr furnace); // 4J added bool return virtual bool openBrewingStand(std::shared_ptr brewingStand); // 4J added bool return + virtual bool openBeacon( + std::shared_ptr beacon); // 4J added bool return virtual bool openTrap( std::shared_ptr trap); // 4J added bool return - virtual bool openTrading(std::shared_ptr traderTarget); + virtual bool openTrading(std::shared_ptr traderTarget, + const std::wstring& name); virtual void crit(std::shared_ptr e); virtual void magicCrit(std::shared_ptr e); virtual void take(std::shared_ptr e, int orgCount); virtual void chat(const std::wstring& message); virtual bool isSneaking(); // virtual bool isIdle(); - virtual void hurtTo(int newHealth, ETelemetryChallenges damageSource); + virtual void hurtTo(float newHealth, ETelemetryChallenges damageSource); virtual void respawn(); virtual void animateRespawn(); virtual void displayClientMessage(int messageId); @@ -174,8 +190,8 @@ public: // Minecraft.Client virtual void onCrafted(std::shared_ptr item); - virtual void setAndBroadcastCustomSkin(std::uint32_t skinId); - virtual void setAndBroadcastCustomCape(std::uint32_t capeId); + virtual void setAndBroadcastCustomSkin(DWORD skinId); + virtual void setAndBroadcastCustomCape(DWORD capeId); private: bool isSolidBlock(int x, int y, int z); @@ -189,6 +205,17 @@ public: void setExperienceValues(float experienceProgress, int totalExp, int experienceLevel); + // virtual void sendMessage(ChatMessageComponent *message); // 4J: removed + virtual Pos getCommandSenderWorldPosition(); + virtual std::shared_ptr getCarriedItem(); + virtual void playSound(int soundId, float volume, float pitch); + bool isRidingJumpable(); + float getJumpRidingScale(); + +protected: + virtual void sendRidingJump(); + +public: bool hasPermission(EGameCommand command); void updateRichPresence(); @@ -197,7 +224,6 @@ public: float m_sessionTimeStart; float m_dimensionTimeStart; -public: void SetSessionTimerStart(void); float getSessionTimer(void); diff --git a/Minecraft.Client/Player/MultiPlayerGameMode.cpp b/Minecraft.Client/Player/MultiPlayerGameMode.cpp index 8d9957c3e..bbd7e2a91 100644 --- a/Minecraft.Client/Player/MultiPlayerGameMode.cpp +++ b/Minecraft.Client/Player/MultiPlayerGameMode.cpp @@ -19,8 +19,8 @@ MultiPlayerGameMode::MultiPlayerGameMode(Minecraft* minecraft, xDestroyBlock = -1; yDestroyBlock = -1; zDestroyBlock = -1; + destroyingItem = nullptr; destroyProgress = 0; - oDestroyProgress = 0; destroyTicks = 0; destroyDelay = 0; isDestroying = false; @@ -58,8 +58,18 @@ bool MultiPlayerGameMode::canHurtPlayer() { } bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face) { - if (localPlayerMode->isReadOnly()) { - return false; + if (localPlayerMode->isAdventureRestricted()) { + if (!minecraft->player->mayDestroyBlockAt(x, y, z)) { + return false; + } + } + + if (localPlayerMode->isCreative()) { + if (minecraft->player->getCarriedItem() != NULL && + dynamic_cast( + minecraft->player->getCarriedItem()->getItem()) != NULL) { + return false; + } } Level* level = minecraft->level; @@ -72,10 +82,11 @@ bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face) { oldTile->id + (level->getData(x, y, z) << Tile::TILE_NUM_SHIFT)); int data = level->getData(x, y, z); - bool changed = level->setTile(x, y, z, 0); + bool changed = level->removeTile(x, y, z); if (changed) { oldTile->destroy(level, x, y, z, data); } + yDestroyBlock = -1; if (!localPlayerMode->isCreative()) { std::shared_ptr item = @@ -93,8 +104,11 @@ bool MultiPlayerGameMode::destroyBlock(int x, int y, int z, int face) { void MultiPlayerGameMode::startDestroyBlock(int x, int y, int z, int face) { if (!minecraft->player->isAllowedToMine()) return; - if (localPlayerMode->isReadOnly()) { - return; + + if (localPlayerMode->isAdventureRestricted()) { + if (!minecraft->player->mayDestroyBlockAt(x, y, z)) { + return; + } } if (localPlayerMode->isCreative()) { @@ -103,8 +117,13 @@ void MultiPlayerGameMode::startDestroyBlock(int x, int y, int z, int face) { PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face))); creativeDestroyBlock(minecraft, this, x, y, z, face); destroyDelay = 5; - } else if (!isDestroying || x != xDestroyBlock || y != yDestroyBlock || - z != zDestroyBlock) { + } else if (!isDestroying || !sameDestroyTarget(x, y, z)) { + if (isDestroying) { + connection->send( + std::shared_ptr(new PlayerActionPacket( + PlayerActionPacket::ABORT_DESTROY_BLOCK, xDestroyBlock, + yDestroyBlock, zDestroyBlock, face))); + } connection->send( std::shared_ptr(new PlayerActionPacket( PlayerActionPacket::START_DESTROY_BLOCK, x, y, z, face))); @@ -114,18 +133,18 @@ void MultiPlayerGameMode::startDestroyBlock(int x, int y, int z, int face) { minecraft->player); if (t > 0 && (Tile::tiles[t]->getDestroyProgress( - minecraft->player, minecraft->player->level, x, y, z) >= 1 || - (app.DebugSettingsOn() && - app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & - (1L << eDebugSetting_InstantDestroy)))) { + minecraft->player, minecraft->player->level, x, y, z) >= 1 + // ||(app.DebugSettingsOn() && + // app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<player->getCarriedItem(); destroyProgress = 0; - oDestroyProgress = 0; destroyTicks = 0; minecraft->level->destroyTileProgress( minecraft->player->entityId, xDestroyBlock, yDestroyBlock, @@ -170,7 +189,7 @@ void MultiPlayerGameMode::continueDestroyBlock(int x, int y, int z, int face) { return; } - if (x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock) { + if (sameDestroyTarget(x, y, z)) { int t = minecraft->level->getTile(x, y, z); if (t == 0) { isDestroying = false; @@ -201,7 +220,6 @@ void MultiPlayerGameMode::continueDestroyBlock(int x, int y, int z, int face) { PlayerActionPacket::STOP_DESTROY_BLOCK, x, y, z, face))); destroyBlock(x, y, z, face); destroyProgress = 0; - oDestroyProgress = 0; destroyTicks = 0; destroyDelay = 5; } @@ -223,10 +241,23 @@ float MultiPlayerGameMode::getPickRange() { void MultiPlayerGameMode::tick() { ensureHasSentCarriedItem(); - oDestroyProgress = destroyProgress; // minecraft->soundEngine->playMusicTick(); } +bool MultiPlayerGameMode::sameDestroyTarget(int x, int y, int z) { + std::shared_ptr selected = + minecraft->player->getCarriedItem(); + bool sameItems = destroyingItem == NULL && selected == NULL; + if (destroyingItem != NULL && selected != NULL) { + sameItems = selected->id == destroyingItem->id && + ItemInstance::tagMatches(selected, destroyingItem) && + (selected->isDamageableItem() || + selected->getAuxValue() == destroyingItem->getAuxValue()); + } + return x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock && + sameItems; +} + void MultiPlayerGameMode::ensureHasSentCarriedItem() { int newItem = minecraft->player->inventory->selected; if (newItem != carriedItem) { @@ -251,31 +282,34 @@ bool MultiPlayerGameMode::useItemOn(std::shared_ptr player, float clickY = (float)hit->y - y; float clickZ = (float)hit->z - z; bool didSomething = false; - int t = level->getTile(x, y, z); - if (t > 0 && player->isAllowedToUse(Tile::tiles[t])) { - if (bTestUseOnly) { - switch (t) { - case Tile::recordPlayer_Id: - case Tile::bed_Id: // special case for a bed - if (Tile::tiles[t]->TestUse(level, x, y, z, player)) { - return true; - } else if (t == Tile::bed_Id) // 4J-JEV: You can still use - // items on record players - // (ie. set fire to them). - { - // bed is too far away, or something - return false; - } - break; - default: - if (Tile::tiles[t]->TestUse()) return true; - break; + if (!player->isSneaking() || player->getCarriedItem() == NULL) { + int t = level->getTile(x, y, z); + if (t > 0 && player->isAllowedToUse(Tile::tiles[t])) { + if (bTestUseOnly) { + switch (t) { + case Tile::jukebox_Id: + case Tile::bed_Id: // special case for a bed + if (Tile::tiles[t]->TestUse(level, x, y, z, player)) { + return true; + } else if (t == + Tile::bed_Id) // 4J-JEV: You can still use + // items on record players + // (ie. set fire to them). + { + // bed is too far away, or something + return false; + } + break; + default: + if (Tile::tiles[t]->TestUse()) return true; + break; + } + } else { + if (Tile::tiles[t]->use(level, x, y, z, player, face, clickX, + clickY, clickZ)) + didSomething = true; } - } else { - if (Tile::tiles[t]->use(level, x, y, z, player, face, clickX, - clickY, clickZ)) - didSomething = true; } } @@ -306,6 +340,7 @@ bool MultiPlayerGameMode::useItemOn(std::shared_ptr player, } } } else { + int t = level->getTile(x, y, z); // 4J - Bit of a hack, however seems preferable to any larger changes // which would have more chance of causing unwanted side effects. If we // aren't going to be actually performing the use method locally, then @@ -355,7 +390,7 @@ bool MultiPlayerGameMode::useItem(std::shared_ptr player, Level* level, // 4J-PB added for tooltips to test use only if (bTestUseOnly) { - result = item->TestUse(level, player); + result = item->TestUse(item, level, player); } else { int oldCount = item->count; std::shared_ptr itemInstance = item->use(level, player); @@ -445,7 +480,9 @@ void MultiPlayerGameMode::releaseUsingItem(std::shared_ptr player) { player->releaseUsingItem(); } -bool MultiPlayerGameMode::hasExperience() { return true; } +bool MultiPlayerGameMode::hasExperience() { + return localPlayerMode->isSurvival(); +} bool MultiPlayerGameMode::hasMissTime() { return !localPlayerMode->isCreative(); @@ -459,6 +496,13 @@ bool MultiPlayerGameMode::hasFarPickRange() { 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() { + return minecraft->player->isRiding() && + minecraft->player->riding->instanceof(eTYPE_HORSE); +} + bool MultiPlayerGameMode::handleCraftItem(int recipe, std::shared_ptr player) { short changeUid = player->containerMenu->backup(player->inventory); diff --git a/Minecraft.Client/Player/MultiPlayerGameMode.h b/Minecraft.Client/Player/MultiPlayerGameMode.h index d136461c6..becc93ce5 100644 --- a/Minecraft.Client/Player/MultiPlayerGameMode.h +++ b/Minecraft.Client/Player/MultiPlayerGameMode.h @@ -9,8 +9,8 @@ private: int xDestroyBlock; int yDestroyBlock; int zDestroyBlock; + std::shared_ptr destroyingItem; float destroyProgress; - float oDestroyProgress; int destroyTicks; // 4J was float but doesn't seem to need to be int destroyDelay; bool isDestroying; @@ -22,7 +22,6 @@ protected: public: MultiPlayerGameMode(Minecraft* minecraft, ClientConnection* connection); - virtual ~MultiPlayerGameMode() {} static void creativeDestroyBlock(Minecraft* minecraft, MultiPlayerGameMode* gameMode, int x, int y, int z, int face); @@ -42,6 +41,7 @@ private: int carriedItem; private: + bool sameDestroyTarget(int x, int y, int z); void ensureHasSentCarriedItem(); public: @@ -70,6 +70,7 @@ public: virtual bool hasMissTime(); virtual bool hasInfiniteItems(); virtual bool hasFarPickRange(); + virtual bool isServerControlledInventory(); // 4J Stu - Added so we can send packets for this in the network game virtual bool handleCraftItem(int recipe, std::shared_ptr player); @@ -80,4 +81,4 @@ public: virtual bool isInputAllowed(int mapping) { return true; } virtual bool isTutorial() { return false; } virtual Tutorial* getTutorial() { return NULL; } -}; +}; \ No newline at end of file diff --git a/Minecraft.Client/Player/MultiPlayerLocalPlayer.cpp b/Minecraft.Client/Player/MultiPlayerLocalPlayer.cpp index 8b79bcadc..9e1c5babd 100644 --- a/Minecraft.Client/Player/MultiPlayerLocalPlayer.cpp +++ b/Minecraft.Client/Player/MultiPlayerLocalPlayer.cpp @@ -12,6 +12,13 @@ #include "../../Minecraft.World/Headers/net.minecraft.world.effect.h" #include "../../Minecraft.World/Level/LevelData.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.item.h" +#include "../Input/Input.h" +#include "../Rendering/LevelRenderer.h" + +// 4J added for testing +#ifdef STRESS_TEST_MOVE +volatile bool stressTestEnabled = true; +#endif MultiplayerLocalPlayer::MultiplayerLocalPlayer(Minecraft* minecraft, Level* level, User* user, @@ -30,11 +37,11 @@ MultiplayerLocalPlayer::MultiplayerLocalPlayer(Minecraft* minecraft, this->connection = connection; } -bool MultiplayerLocalPlayer::hurt(DamageSource* source, int dmg) { +bool MultiplayerLocalPlayer::hurt(DamageSource* source, float dmg) { return false; } -void MultiplayerLocalPlayer::heal(int heal) {} +void MultiplayerLocalPlayer::heal(float heal) {} void MultiplayerLocalPlayer::tick() { // 4J Added @@ -57,14 +64,31 @@ void MultiplayerLocalPlayer::tick() { if (!level->hasChunkAt(Mth::floor(x), 0, Mth::floor(z))) return; double tempX = x, tempY = y, tempZ = z; + LocalPlayer::tick(); + // 4J added for testing +#ifdef STRESS_TEST_MOVE + if (stressTestEnabled) { + StressTestMove(&tempX, &tempY, &tempZ); + } +#endif + // if( !minecraft->localgameModes[m_iPad]->isTutorial() || // minecraft->localgameModes[m_iPad]->getTutorial()->canMoveToPosition(tempX, // tempY, tempZ, x, y, z) ) if (minecraft->localgameModes[m_iPad]->getTutorial()->canMoveToPosition( tempX, tempY, tempZ, x, y, z)) { - sendPosition(); + if (isRiding()) { + connection->send( + std::shared_ptr(new MovePlayerPacket::Rot( + yRot, xRot, onGround, abilities.flying))); + connection->send( + std::shared_ptr(new PlayerInputPacket( + xxa, yya, input->jumping, input->sneaking))); + } else { + sendPosition(); + } } else { // app.Debugprintf("Cannot move to position (%f, %f, %f), falling back // to (%f, %f, %f)\n", x, y, z, tempX, y, tempZ); @@ -189,7 +213,8 @@ void MultiplayerLocalPlayer::respawn() { new ClientCommandPacket(ClientCommandPacket::PERFORM_RESPAWN))); } -void MultiplayerLocalPlayer::actuallyHurt(DamageSource* source, int dmg) { +void MultiplayerLocalPlayer::actuallyHurt(DamageSource* source, float dmg) { + if (isInvulnerable()) return; setHealth(getHealth() - dmg); } @@ -216,7 +241,8 @@ void MultiplayerLocalPlayer::onEffectAdded(MobEffectInstance* effect) { Player::onEffectAdded(effect); } -void MultiplayerLocalPlayer::onEffectUpdated(MobEffectInstance* effect) { +void MultiplayerLocalPlayer::onEffectUpdated(MobEffectInstance* effect, + bool doRefreshAttributes) { Minecraft* pMinecraft = Minecraft::GetInstance(); if (pMinecraft->localgameModes[m_iPad] != NULL) { TutorialMode* gameMode = @@ -224,7 +250,7 @@ void MultiplayerLocalPlayer::onEffectUpdated(MobEffectInstance* effect) { Tutorial* tutorial = gameMode->getTutorial(); tutorial->onEffectChanged(MobEffect::effects[effect->getId()]); } - Player::onEffectUpdated(effect); + Player::onEffectUpdated(effect, doRefreshAttributes); } void MultiplayerLocalPlayer::onEffectRemoved(MobEffectInstance* effect) { @@ -241,11 +267,16 @@ void MultiplayerLocalPlayer::onEffectRemoved(MobEffectInstance* effect) { void MultiplayerLocalPlayer::closeContainer() { connection->send(std::shared_ptr( new ContainerClosePacket(containerMenu->containerId))); + clientSideCloseContainer(); +} + +// close the container without sending a packet to the server +void MultiplayerLocalPlayer::clientSideCloseContainer() { inventory->setCarried(nullptr); LocalPlayer::closeContainer(); } -void MultiplayerLocalPlayer::hurtTo(int newHealth, +void MultiplayerLocalPlayer::hurtTo(float newHealth, ETelemetryChallenges damageSource) { if (flashOnSetHealth) { LocalPlayer::hurtTo(newHealth, damageSource); @@ -283,11 +314,30 @@ void MultiplayerLocalPlayer::onUpdateAbilities() { bool MultiplayerLocalPlayer::isLocalPlayer() { return true; } +void MultiplayerLocalPlayer::sendRidingJump() { + connection->send( + std::shared_ptr(new PlayerCommandPacket( + shared_from_this(), PlayerCommandPacket::RIDING_JUMP, + (int)(getJumpRidingScale() * 100.0f)))); +} + +void MultiplayerLocalPlayer::sendOpenInventory() { + connection->send( + std::shared_ptr(new PlayerCommandPacket( + shared_from_this(), PlayerCommandPacket::OPEN_INVENTORY))); +} + void MultiplayerLocalPlayer::ride(std::shared_ptr e) { bool wasRiding = riding != NULL; LocalPlayer::ride(e); bool isRiding = riding != NULL; + // 4J Added + if (wasRiding && !isRiding) { + setSneaking(false); + input->sneaking = false; + } + if (isRiding) { ETelemetryChallenges eventType = eTelemetryChallenges_Unknown; if (this->riding != NULL) { @@ -301,8 +351,6 @@ void MultiplayerLocalPlayer::ride(std::shared_ptr e) { case eTYPE_PIG: eventType = eTelemetryInGame_Ride_Pig; break; - default: - break; }; } TelemetryManager->RecordEnemyKilledOrOvercome(GetXboxPad(), 0, y, 0, 0, @@ -320,12 +368,7 @@ void MultiplayerLocalPlayer::ride(std::shared_ptr e) { gameMode->getTutorial()->changeTutorialState( e_Tutorial_State_Gameplay); } else if (!wasRiding && isRiding) { - if (std::dynamic_pointer_cast(e) != NULL) - gameMode->getTutorial()->changeTutorialState( - e_Tutorial_State_Riding_Minecart); - else if (std::dynamic_pointer_cast(e) != NULL) - gameMode->getTutorial()->changeTutorialState( - e_Tutorial_State_Riding_Boat); + gameMode->getTutorial()->onRideEntity(e); } } } @@ -363,3 +406,78 @@ void MultiplayerLocalPlayer::setAndBroadcastCustomCape(std::uint32_t capeId) { shared_from_this(), TextureChangePacket::e_TextureChange_Cape, app.GetPlayerCapeName(GetXboxPad())))); } + +// 4J added for testing. This moves the player in a repeated sequence of 2 +// modes: Mode 0 - teleports to random location in the world, and waits for the +// number of chunks that are fully loaded/created to have setting for 2 seconds +// before changing to mode 1 Mode 1 - picks a random direction to move in for +// 200 ticks (~10 seconds), repeating for a total of 2000 ticks, before cycling +// back to mode 0 Whilst carrying out this movement pattern, this calls +// checkAllPresentChunks which checks the integrity of all currently +// loaded/created chunks round the player. +#ifdef STRESS_TEST_MOVE +void MultiplayerLocalPlayer::StressTestMove(double* tempX, double* tempY, + double* tempZ) { + static volatile int64_t lastChangeTime = 0; + static volatile int64_t lastTeleportTime = 0; + static int lastCount = 0; + static int stressTestCount = 0; + const int dirChangeTickCount = 200; + + int64_t currentTime = System::currentTimeMillis(); + + bool faultFound = false; + int count = Minecraft::GetInstance()->levelRenderer->checkAllPresentChunks( + &faultFound); + + /* + if( faultFound ) + { + app.DebugPrintf("Fault found\n"); + stressTestEnabled = false; + } + */ + if (count != lastCount) { + lastChangeTime = currentTime; + lastCount = count; + } + + static float angle = 30.0; + static float dx = cos(30.0); + static float dz = sin(30.0); + +#if 0 + if( ( stressTestCount % dirChangeTickCount) == 0 ) + { + int angledeg = rand() % 360; + angle = (((double)angledeg) / 360.0 ) * ( 2.0 * 3.141592654 ); + dx = cos(angle); + dz = sin(angle); + } +#endif + + float nx = x + (dx * 1.2); + float nz = z + (dz * 1.2); + float ny = y; + if (ny < 140.0f) ny += 0.5f; + if (nx > 2539.0) { + nx = 2539.0; + dx = -dx; + } + if (nz > 2539.0) { + nz = 2539.0; + dz = -dz; + } + if (nx < -2550.0) { + nx = -2550.0; + dx = -dx; + } + + if (nz < -2550.0) { + nz = -2550.0; + dz = -dz; + } + absMoveTo(nx, ny, nz, yRot, xRot); + stressTestCount++; +} +#endif \ No newline at end of file diff --git a/Minecraft.Client/Player/MultiPlayerLocalPlayer.h b/Minecraft.Client/Player/MultiPlayerLocalPlayer.h index b865dd566..b40e28752 100644 --- a/Minecraft.Client/Player/MultiPlayerLocalPlayer.h +++ b/Minecraft.Client/Player/MultiPlayerLocalPlayer.h @@ -7,6 +7,8 @@ class ClientConnection; class Minecraft; class Level; +// #define STRESS_TEST_MOVE + class MultiplayerLocalPlayer : public LocalPlayer { private: static const int POSITION_REMINDER_INTERVAL = @@ -27,8 +29,8 @@ private: float yRotLast, xRotLast; public: - virtual bool hurt(DamageSource* source, int dmg); - virtual void heal(int heal); + virtual bool hurt(DamageSource* source, float dmg); + virtual void heal(float heal); virtual void tick(); private: @@ -53,24 +55,32 @@ public: virtual void respawn(); protected: - virtual void actuallyHurt(DamageSource* source, int dmg); + virtual void actuallyHurt(DamageSource* source, float dmg); // 4J Added override to capture event for tutorial messages virtual void completeUsingItem(); // 4J Added overrides to capture events for tutorial virtual void onEffectAdded(MobEffectInstance* effect); - virtual void onEffectUpdated(MobEffectInstance* effect); + virtual void onEffectUpdated(MobEffectInstance* effect, + bool doRefreshAttributes); virtual void onEffectRemoved(MobEffectInstance* effect); public: virtual void closeContainer(); - virtual void hurtTo(int newHealth, ETelemetryChallenges damageSource); + void clientSideCloseContainer(); + virtual void hurtTo(float newHealth, ETelemetryChallenges damageSource); virtual void awardStat(Stat* stat, byteArray param); void awardStatFromServer(Stat* stat, byteArray param); void onUpdateAbilities(); bool isLocalPlayer(); +protected: + virtual void sendRidingJump(); + +public: + virtual void sendOpenInventory(); + // 4J - send the custom skin texture data if there is one // void CustomSkin(PBYTE pbData, DWORD dwBytes); @@ -81,6 +91,11 @@ public: virtual void StopSleeping(); // 4J Added - virtual void setAndBroadcastCustomSkin(std::uint32_t skinId); - virtual void setAndBroadcastCustomCape(std::uint32_t capeId); + virtual void setAndBroadcastCustomSkin(DWORD skinId); + virtual void setAndBroadcastCustomCape(DWORD capeId); + + // 4J added for testing +#ifdef STRESS_TEST_MOVE + void StressTestMove(double* tempX, double* tempY, double* tempZ); +#endif }; diff --git a/Minecraft.Client/Player/RemotePlayer.cpp b/Minecraft.Client/Player/RemotePlayer.cpp index cd81b5743..86f3e993d 100644 --- a/Minecraft.Client/Player/RemotePlayer.cpp +++ b/Minecraft.Client/Player/RemotePlayer.cpp @@ -4,34 +4,28 @@ #include "../../Minecraft.World/Util/Mth.h" RemotePlayer::RemotePlayer(Level* level, const std::wstring& name) - : Player(level) { + : Player(level, name) { // 4J - added initialisers hasStartedUsingItem = false; lSteps = 0; lx = ly = lz = lyr = lxr = 0.0; fallTime = 0.0f; - this->name = name; - m_UUID = name; app.DebugPrintf("Created RemotePlayer with name %ls\n", name.c_str()); heightOffset = 0; - this->footSize = 0; - if (name.length() > 0) { - customTextureUrl = L""; // L"http://s3.amazonaws.com/MinecraftSkins/" + - // name + L".png"; - } + footSize = 0; - this->noPhysics = true; + noPhysics = true; bedOffsetY = 4 / 16.0f; - this->viewScale = 10; + viewScale = 10; } void RemotePlayer::setDefaultHeadHeight() { heightOffset = 0; } -bool RemotePlayer::hurt(DamageSource* source, int dmg) { return true; } +bool RemotePlayer::hurt(DamageSource* source, float dmg) { return true; } void RemotePlayer::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) { @@ -99,8 +93,8 @@ void RemotePlayer::aiStep() { xRot += (float)((lxr - xRot) / lSteps); lSteps--; - this->setPos(xt, yt, zt); - this->setRot(yRot, xRot); + setPos(xt, yt, zt); + setRot(yRot, xRot); } oBob = bob; @@ -129,4 +123,8 @@ void RemotePlayer::animateRespawn() { // Player.animateRespawn(this, level); } -float RemotePlayer::getHeadHeight() { return 1.82f; } \ No newline at end of file +float RemotePlayer::getHeadHeight() { return 1.82f; } + +Pos RemotePlayer::getCommandSenderWorldPosition() { + return new Pos(floor(x + .5), floor(y + .5), floor(z + .5)); +} \ No newline at end of file diff --git a/Minecraft.Client/Player/RemotePlayer.h b/Minecraft.Client/Player/RemotePlayer.h index 47ac32c21..938543917 100644 --- a/Minecraft.Client/Player/RemotePlayer.h +++ b/Minecraft.Client/Player/RemotePlayer.h @@ -5,6 +5,9 @@ class Input; class RemotePlayer : public Player { +public: + eINSTANCEOF GetType() { return eTYPE_REMOTEPLAYER; } + private: bool hasStartedUsingItem; @@ -16,7 +19,7 @@ protected: virtual void setDefaultHeadHeight(); public: - virtual bool hurt(DamageSource* source, int dmg); + virtual bool hurt(DamageSource* source, float dmg); private: int lSteps; @@ -39,4 +42,5 @@ public: virtual void animateRespawn(); virtual float getHeadHeight(); bool hasPermission(EGameCommand command) { return false; } + virtual Pos getCommandSenderWorldPosition(); }; \ No newline at end of file diff --git a/Minecraft.Client/Player/ServerPlayer.cpp b/Minecraft.Client/Player/ServerPlayer.cpp index b3ea69cac..108b1697d 100644 --- a/Minecraft.Client/Player/ServerPlayer.cpp +++ b/Minecraft.Client/Player/ServerPlayer.cpp @@ -8,33 +8,40 @@ #include "../GameState/Settings.h" #include "../Network/PlayerList.h" #include "../Level/MultiPlayerLevel.h" -#include "../../Minecraft.World/Util/Pos.h" + +#include "../../Minecraft.World/Headers/net.minecraft.network.packet.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.damagesource.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.inventory.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.storage.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.dimension.h" -#include "../../Minecraft.World/Util/Random.h" -#include "../../Minecraft.World/Headers/net.minecraft.world.inventory.h" -#include "../../Minecraft.World/Headers/net.minecraft.network.packet.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.projectile.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.entity.animal.h" #include "../../Minecraft.World/Headers/net.minecraft.world.item.h" #include "../../Minecraft.World/Headers/net.minecraft.world.item.trading.h" #include "../../Minecraft.World/Headers/net.minecraft.world.entity.item.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.tile.entity.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.scores.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.scores.criteria.h" #include "../../Minecraft.World/Headers/net.minecraft.stats.h" #include "../../Minecraft.World/Headers/net.minecraft.locale.h" -#include "../../Minecraft.World/Headers/net.minecraft.world.damagesource.h" + +#include "../../Minecraft.World/Util/Pos.h" +#include "../../Minecraft.World/Util/Random.h" + #include "../../Minecraft.World/Level/LevelChunk.h" #include "../Rendering/LevelRenderer.h" ServerPlayer::ServerPlayer(MinecraftServer* server, Level* level, const std::wstring& name, ServerPlayerGameMode* gameMode) - : Player(level) { + : Player(level, name) { // 4J - added initialisers connection = nullptr; lastMoveX = lastMoveZ = 0; spewTimer = 0; + lastRecordedHealthAndAbsorption = FLT_MIN; lastSentHealth = -99999999; lastSentFood = -99999999; lastFoodSaturationZero = true; @@ -45,11 +52,10 @@ ServerPlayer::ServerPlayer(MinecraftServer* server, Level* level, latency = 0; wonGame = false; m_enteredEndExitPortal = false; - lastCarried = ItemInstanceArray(5); - viewDistance = 10; + // lastCarried = ItemInstanceArray(5); + lastActionTime = 0; - // 4jcraft added (0 initialized) - m_lastDamageSource = eTelemetryChallenges_Unknown; + viewDistance = server->getPlayers()->getViewDistance(); // gameMode->player = this; // 4J - removed to avoid use of // shared_from_this in ctor, now set up externally @@ -65,6 +71,8 @@ ServerPlayer::ServerPlayer(MinecraftServer* server, Level* level, level->getLevelData()->getGameType() != GameType::ADVENTURE) { level->isFindingSpawn = true; + int radius = std::max(5, server->getSpawnProtectionRadius() - 6); + // 4J added - do additional checking that we aren't putting the player // in deep water. Give up after 20 or goes just in case the spawnPos is // somehow in a really bad spot and we would just lock here. @@ -79,8 +87,8 @@ ServerPlayer::ServerPlayer(MinecraftServer* server, Level* level, do { // Also check that we aren't straying outside of the map do { - xx2 = xx + random->nextInt(20) - 10; - zz2 = zz + random->nextInt(20) - 10; + xx2 = xx + random->nextInt(radius * 2) - radius; + zz2 = zz + random->nextInt(radius * 2) - radius; } while ((xx2 > maxXZ) || (xx2 < minXZ) || (zz2 > maxXZ) || (zz2 < minXZ)); yy2 = level->getTopSolidBlock(xx2, zz2); @@ -104,22 +112,29 @@ ServerPlayer::ServerPlayer(MinecraftServer* server, Level* level, level->isFindingSpawn = false; } + this->server = server; + footSize = 0; + heightOffset = 0; // 4J - this height used to be set up after moveTo, but that ends up // with the y value being incorrect as it depends on this offset this->moveTo(xx + 0.5, yy, zz + 0.5, 0, 0); - this->server = server; - footSize = 0; + // 4J Handled later + // while (!level->getCubes(this, bb).empty()) + //{ + // setPos(x, y + 1, z); + //} - this->name = name; - m_UUID = name; + // m_UUID = name; // 4J Added lastBrupSendTickCount = 0; } -ServerPlayer::~ServerPlayer() { delete[] lastCarried.data; } +ServerPlayer::~ServerPlayer() { + // delete [] lastCarried.data; +} // 4J added - add bits to a flag array that is passed in, to represent those // entities which have small Ids, and are in our vector of entitiesToRemove. If @@ -158,7 +173,14 @@ void ServerPlayer::readAdditionalSaveData(CompoundTag* entityTag) { if (entityTag->contains(L"playerGameType")) { // 4J Stu - We do not want to change the game mode for the player, // instead we let the server override it globally - // gameMode->setGameModeForPlayer(GameType::byId(entityTag->getInt(L"playerGameType"))); + // if (MinecraftServer::getInstance()->getForceGameType()) + //{ + // gameMode->setGameModeForPlayer(MinecraftServer::getInstance()->getDefaultGameType()); + //} + // else + //{ + // gameMode->setGameModeForPlayer(GameType::byId(entityTag->getInt(L"playerGameType"))); + //} } GameRulesInstance* grs = gameMode->getGameRules(); @@ -193,15 +215,13 @@ void ServerPlayer::addAdditonalSaveData(CompoundTag* entityTag) { // gameMode->getGameModeForPlayer()->getId()); } -void ServerPlayer::withdrawExperienceLevels(int amount) { - Player::withdrawExperienceLevels(amount); +void ServerPlayer::giveExperienceLevels(int amount) { + Player::giveExperienceLevels(amount); lastSentExp = -1; } void ServerPlayer::initMenu() { containerMenu->addSlotListener(this); } -ItemInstanceArray ServerPlayer::getEquipmentSlots() { return lastCarried; } - void ServerPlayer::setDefaultHeadHeight() { heightOffset = 0; } float ServerPlayer::getHeadHeight() { return 1.62f; } @@ -220,15 +240,11 @@ void ServerPlayer::tick() { currentBiome = newBiome; } - for (int i = 0; i < 5; i++) { - std::shared_ptr currentCarried = getCarried(i); - if (currentCarried != lastCarried[i]) { - getLevel()->getTracker()->broadcast( - shared_from_this(), - std::shared_ptr( - new SetEquippedItemPacket(this->entityId, i, - currentCarried))); - lastCarried[i] = currentCarried; + if (!level->isClientSide) { + if (!containerMenu->stillValid( + std::dynamic_pointer_cast(shared_from_this()))) { + closeContainer(); + containerMenu = inventoryMenu; } } @@ -237,7 +253,7 @@ void ServerPlayer::tick() { // 4J Stu - Split out here so that we can call this from other places void ServerPlayer::flushEntitiesToRemove() { - if (!entitiesToRemove.empty()) { + while (!entitiesToRemove.empty()) { int sz = entitiesToRemove.size(); int amount = std::min(sz, RemoveEntitiesPacket::MAX_PER_PACKET); intArray ids(amount); @@ -259,11 +275,16 @@ void ServerPlayer::flushEntitiesToRemove() { // full doTick used to do, by calling this method void ServerPlayer::doTick(bool sendChunks, bool dontDelayChunks /*=false*/, bool ignorePortal /*=false*/) { + m_ignorePortal = ignorePortal; + if (sendChunks) { + updateFrameTick(); + } doTickA(); if (sendChunks) { doChunkSendingTick(dontDelayChunks); } - doTickB(ignorePortal); + doTickB(); + m_ignorePortal = false; } void ServerPlayer::doTickA() { @@ -298,7 +319,7 @@ void ServerPlayer::doTickA() { // do this exactly once per player per server tick void ServerPlayer::doChunkSendingTick(bool dontDelayChunks) { // printf("[%d] %s: sendChunks: %d, empty: %d\n",tickCount, - //connection->getNetworkPlayer()->GetUID().getOnlineID(),sendChunks,chunksToSend.empty()); + // connection->getNetworkPlayer()->GetUID().getOnlineID(),sendChunks,chunksToSend.empty()); if (!chunksToSend.empty()) { ChunkPos nearest = chunksToSend.front(); bool nearestValid = false; @@ -332,21 +353,27 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks) { if (connection->isLocal()) { if (!connection->done) okToSend = true; } else { - bool canSendOnSlowQueue = MinecraftServer::canSendOnSlowQueue( - connection->getNetworkPlayer()); + bool canSendToPlayer = + MinecraftServer::chunkPacketManagement_CanSendTo( + connection->getNetworkPlayer()); - // app.DebugPrintf("%ls: - //canSendOnSlowQueue %d, countDelayedPackets %d - //GetSendQueueSizeBytes %d done: %d", - // connection->getNetworkPlayer()->GetUID().toString().c_str(), - // canSendOnSlowQueue, - //connection->countDelayedPackets(), - // g_NetworkManager.GetHostPlayer()->GetSendQueueSizeBytes( - //NULL, true ), connection->done); + // app.DebugPrintf(">>> %d\n", + // canSendToPlayer); if( + // connection->getNetworkPlayer() ) + // { + // app.DebugPrintf("%d: + // canSendToPlayer %d, countDelayedPackets %d + // GetSendQueueSizeBytes %d done: %d\n", + // connection->getNetworkPlayer()->GetSmallId(), + // canSendToPlayer, + // connection->countDelayedPackets(), + // g_NetworkManager.GetHostPlayer()->GetSendQueueSizeMessages( + // NULL, true ), + // connection->done); + // } if (dontDelayChunks || - (canSendOnSlowQueue && - (connection->countDelayedPackets() < 4) && + (canSendToPlayer && #ifdef _XBOX_ONE // The network manager on xbox one doesn't currently split // data into slow & fast queues - since we can only measure @@ -355,7 +382,11 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks) { // queueing too much up (g_NetworkManager.GetHostPlayer()->GetSendQueueSizeBytes( NULL, true) < 8192) && +#elif defined _XBOX + (g_NetworkManager.GetHostPlayer() + ->GetSendQueueSizeMessages(NULL, true) < 4) && #else + (connection->countDelayedPackets() < 4) && (g_NetworkManager.GetHostPlayer() ->GetSendQueueSizeMessages(NULL, true) < 4) && #endif @@ -364,21 +395,22 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks) { !connection->done)) { lastBrupSendTickCount = tickCount; okToSend = true; - MinecraftServer::s_slowQueuePacketSent = true; + MinecraftServer::chunkPacketManagement_DidSendTo( + connection->getNetworkPlayer()); // static - //std::unordered_map mapLastTime; - // __int64 thisTime = - //System::currentTimeMillis(); - // __int64 lastTime = - //mapLastTime[connection->getNetworkPlayer()->GetUID().toString()]; + // unordered_map mapLastTime; + // int64_t thisTime = + // System::currentTimeMillis(); + // int64_t lastTime = + // mapLastTime[connection->getNetworkPlayer()->GetUID().toString()]; // app.DebugPrintf(" - OK - //to send (%d ms since last)\n", thisTime - lastTime); + // to send (%d ms since last)\n", thisTime - lastTime); // mapLastTime[connection->getNetworkPlayer()->GetUID().toString()] //= thisTime; } else { // app.DebugPrintf(" - \n"); + // OK>\n"); } } @@ -413,13 +445,17 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks) { if (!g_NetworkManager.SystemFlagGet( connection->getNetworkPlayer(), flagIndex)) { // app.DebugPrintf("Creating - //BRUP for %d %d\n",nearest.x, nearest.z); + // BRUP for %d %d\n",nearest.x, nearest.z); PIXBeginNamedEvent(0, "Creation BRUP for sending\n"); + int64_t before = System::currentTimeMillis(); std::shared_ptr packet = std::shared_ptr( new BlockRegionUpdatePacket( nearest.x * 16, 0, nearest.z * 16, 16, Level::maxBuildHeight, 16, level)); + int64_t after = System::currentTimeMillis(); + // app.DebugPrintf(">>><<< + //%d ms\n",after-before); PIXEndNamedEvent(); if (dontDelayChunks) packet->shouldDelay = false; @@ -484,21 +520,20 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks) { } } -void ServerPlayer::doTickB(bool ignorePortal) { +void ServerPlayer::doTickB() { #ifndef _CONTENT_PACKAGE // check if there's a debug dimension change requested - if (app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()) & - (1L << eDebugSetting_GoToNether)) { - if (level->dimension->id == 0) { - ignorePortal = false; - isInsidePortal = true; - portalTime = 1; - } - unsigned int uiVal = - app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()); - app.SetGameSettingsDebugMask(ProfileManager.GetPrimaryPad(), - uiVal & ~(1L << eDebugSetting_GoToNether)); - } + // if(app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<dimension->id == 0 ) + // { + // isInsidePortal=true; + // portalTime=1; + // } + // unsigned int + // uiVal=app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad()); + // app.SetGameSettingsDebugMask(ProfileManager.GetPrimaryPad(),uiVal&~(1L<dimension->id != 0) { - ignorePortal = false; isInsidePortal = true; portalTime = 1; } @@ -526,51 +561,10 @@ void ServerPlayer::doTickB(bool ignorePortal) { } #endif - if (!ignorePortal) { - if (isInsidePortal) { - if (server->isNetherEnabled()) { - if (containerMenu != inventoryMenu) { - closeContainer(); - } - if (riding != NULL) { - this->ride(riding); - } else { - portalTime += 1 / 80.0f; - if (portalTime >= 1) { - portalTime = 1; - changingDimensionDelay = 10; - - int targetDimension = 0; - if (dimension == -1) - targetDimension = 0; - else - targetDimension = -1; - - server->getPlayers()->toggleDimension( - std::dynamic_pointer_cast( - shared_from_this()), - targetDimension); - lastSentExp = -1; - lastSentHealth = -1; - lastSentFood = -1; - - // awardStat(Achievements::portal); - } - } - isInsidePortal = false; - } - } else { - if (portalTime > 0) portalTime -= 1 / 20.0f; - if (portalTime < 0) portalTime = 0; - } - if (changingDimensionDelay > 0) changingDimensionDelay--; - } - if (getHealth() != lastSentHealth || lastSentFood != foodData.getFoodLevel() || ((foodData.getSaturationLevel() == 0) != lastFoodSaturationZero)) { - // 4J Stu - Added m_lastDamageSource for telemetry //4jcraft, nice but - // you never initialized it + // 4J Stu - Added m_lastDamageSource for telemetry connection->send(std::shared_ptr(new SetHealthPacket( getHealth(), foodData.getFoodLevel(), foodData.getSaturationLevel(), m_lastDamageSource))); @@ -579,12 +573,36 @@ void ServerPlayer::doTickB(bool ignorePortal) { lastFoodSaturationZero = foodData.getSaturationLevel() == 0; } + if (getHealth() + getAbsorptionAmount() != + lastRecordedHealthAndAbsorption) { + lastRecordedHealthAndAbsorption = getHealth() + getAbsorptionAmount(); + + std::vector* objectives = + getScoreboard()->findObjectiveFor(ObjectiveCriteria::HEALTH); + if (objectives) { + std::vector > players = + std::vector >(); + players.push_back( + std::dynamic_pointer_cast(shared_from_this())); + + for (AUTO_VAR(it, objectives->begin()); it != objectives->end(); + ++it) { + Objective* objective = *it; + getScoreboard() + ->getPlayerScore(getAName(), objective) + ->updateFor(&players); + } + delete objectives; + } + } + if (totalExperience != lastSentExp) { lastSentExp = totalExperience; connection->send( std::shared_ptr(new SetExperiencePacket( experienceProgress, totalExperience, experienceLevel))); } + std:: } std::shared_ptr ServerPlayer::getCarried(int slot) { @@ -593,13 +611,44 @@ std::shared_ptr ServerPlayer::getCarried(int slot) { } void ServerPlayer::die(DamageSource* source) { - server->getPlayers()->broadcastAll(source->getDeathMessagePacket( - std::dynamic_pointer_cast(shared_from_this()))); - inventory->dropAll(); + server->getPlayers()->broadcastAll( + getCombatTracker()->getDeathMessagePacket()); + + if (!level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) { + inventory->dropAll(); + } + + std::vector* objectives = + level->getScoreboard()->findObjectiveFor( + ObjectiveCriteria::DEATH_COUNT); + if (objectives) { + for (int i = 0; i < objectives->size(); i++) { + Objective* objective = objectives->at(i); + + Score* score = + getScoreboard()->getPlayerScore(getAName(), objective); + score->increment(); + } + delete objectives; + } + + std::shared_ptr killer = getKillCredit(); + if (killer != NULL) killer->awardKillScore(shared_from_this(), deathScore); + // awardStat(Stats::deaths, 1); } -bool ServerPlayer::hurt(DamageSource* dmgSource, int dmg) { - if (invulnerableTime > 0) return false; +bool ServerPlayer::hurt(DamageSource* dmgSource, float dmg) { + if (isInvulnerable()) return false; + + // 4J: Not relevant to console servers + // Allow falldamage on dedicated pvpservers -- so people cannot cheat their + // way out of 'fall traps' + // bool allowFallDamage = server->isPvpAllowed() && + // server->isDedicatedServer() && server->isPvpAllowed() && + // (dmgSource->msgId.compare(L"fall") == 0); + if (!server->isPvpAllowed() && invulnerableTime > 0 && + dmgSource != DamageSource::outOfWorld) + return false; if (dynamic_cast(dmgSource) != NULL) { // 4J Stu - Fix for #46422 - TU5: Crash: Gameplay: Crash when being hit @@ -608,19 +657,19 @@ bool ServerPlayer::hurt(DamageSource* dmgSource, int dmg) { // sometimes NULL. std::shared_ptr source = dmgSource->getDirectEntity(); - if (std::dynamic_pointer_cast(source) != NULL && - (!server->pvp || !std::dynamic_pointer_cast(source) - ->isAllowedToAttackPlayers())) { + if (source->instanceof(eTYPE_PLAYER) && + !std::dynamic_pointer_cast(source)->canHarmPlayer( + std::dynamic_pointer_cast(shared_from_this()))) { return false; } - if (source != NULL && source->GetType() == eTYPE_ARROW) { + if ((source != NULL) && source->instanceof(eTYPE_ARROW)) { std::shared_ptr arrow = std::dynamic_pointer_cast(source); - if (std::dynamic_pointer_cast(arrow->owner) != NULL && - (!server->pvp || - !std::dynamic_pointer_cast(arrow->owner) - ->isAllowedToAttackPlayers())) { + if ((arrow->owner != NULL) && + arrow->owner->instanceof(eTYPE_PLAYER) && + !canHarmPlayer( + std::dynamic_pointer_cast(arrow->owner))) { return false; } } @@ -722,7 +771,30 @@ bool ServerPlayer::hurt(DamageSource* dmgSource, int dmg) { return returnVal; } -bool ServerPlayer::isPlayerVersusPlayer() { return server->pvp; } +bool ServerPlayer::canHarmPlayer(std::shared_ptr target) { + if (!server->isPvpAllowed()) return false; + if (!isAllowedToAttackPlayers()) return false; + return Player::canHarmPlayer(target); +} + +// 4J: Added for checking when only player name is provided (possible player +// isn't on server), e.g. can harm owned animals +bool ServerPlayer::canHarmPlayer(std::wstring targetName) { + bool canHarm = true; + + std::shared_ptr owner = + server->getPlayers()->getPlayer(targetName); + if (owner != NULL) { + if ((shared_from_this() != owner) && canHarmPlayer(owner)) + canHarm = false; + } else { + if (this->name != targetName && + (!isAllowedToAttackPlayers() || !server->isPvpAllowed())) + canHarm = false; + } + + return canHarm; +} void ServerPlayer::changeDimension(int i) { if (!connection->hasClientTickedOnce()) return; @@ -771,15 +843,22 @@ void ServerPlayer::changeDimension(int i) { } app.DebugPrintf("End win game\n"); } else { - awardStat(GenericStats::theEnd(), GenericStats::param_theEnd()); + if (dimension == 0 && i == 1) { + awardStat(GenericStats::theEnd(), GenericStats::param_theEnd()); - Pos* pos = server->getLevel(i)->getDimensionSpecificSpawn(); - if (pos != NULL) { - connection->teleport(pos->x, pos->y, pos->z, 0, 0); - delete pos; + Pos* pos = server->getLevel(i)->getDimensionSpecificSpawn(); + if (pos != NULL) { + connection->teleport(pos->x, pos->y, pos->z, 0, 0); + delete pos; + } + + i = 1; + } else { + // 4J: Removed on the advice of the mighty King of Achievments (JV) + // awardStat(GenericStats::portal(), GenericStats::param_portal()); } server->getPlayers()->toggleDimension( - std::dynamic_pointer_cast(shared_from_this()), 1); + std::dynamic_pointer_cast(shared_from_this()), i); lastSentExp = -1; lastSentHealth = -1; lastSentFood = -1; @@ -788,7 +867,7 @@ void ServerPlayer::changeDimension(int i) { // 4J Added delay param void ServerPlayer::broadcast(std::shared_ptr te, - bool delay /*= false*/) { + bool delay /*= false*/) { if (te != NULL) { std::shared_ptr p = te->getUpdatePacket(); if (p != NULL) { @@ -802,39 +881,10 @@ void ServerPlayer::broadcast(std::shared_ptr te, } void ServerPlayer::take(std::shared_ptr e, int orgCount) { - if (!e->removed) { - EntityTracker* entityTracker = getLevel()->getTracker(); - if (e->GetType() == eTYPE_ITEMENTITY) { - entityTracker->broadcast( - e, std::shared_ptr( - new TakeItemEntityPacket(e->entityId, entityId))); - } - if (e->GetType() == eTYPE_ARROW) { - entityTracker->broadcast( - e, std::shared_ptr( - new TakeItemEntityPacket(e->entityId, entityId))); - } - if (e->GetType() == eTYPE_EXPERIENCEORB) { - entityTracker->broadcast( - e, std::shared_ptr( - new TakeItemEntityPacket(e->entityId, entityId))); - } - } Player::take(e, orgCount); containerMenu->broadcastChanges(); } -void ServerPlayer::swing() { - if (!swinging) { - swingTime = -1; - swinging = true; - getLevel()->getTracker()->broadcast( - shared_from_this(), - std::shared_ptr( - new AnimatePacket(shared_from_this(), AnimatePacket::SWING))); - } -} - Player::BedSleepingResult ServerPlayer::startSleepInBed(int x, int y, int z, bool bTestUse) { BedSleepingResult result = Player::startSleepInBed(x, y, z, bTestUse); @@ -865,8 +915,9 @@ void ServerPlayer::stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, void ServerPlayer::ride(std::shared_ptr e) { Player::ride(e); - connection->send(std::shared_ptr( - new SetRidingPacket(shared_from_this(), riding))); + connection->send( + std::shared_ptr(new SetEntityLinkPacket( + SetEntityLinkPacket::RIDING, shared_from_this(), riding))); // 4J Removed this - The act of riding will be handled on the client and // will change the position of the player. If we also teleport it then we @@ -882,6 +933,18 @@ void ServerPlayer::doCheckFallDamage(double ya, bool onGround) { Player::checkFallDamage(ya, onGround); } +void ServerPlayer::openTextEdit(std::shared_ptr sign) { + std::shared_ptr signTE = + std::dynamic_pointer_cast(sign); + if (signTE != NULL) { + signTE->setAllowedPlayerEditor( + std::dynamic_pointer_cast(shared_from_this())); + connection->send( + std::shared_ptr(new TileEditorOpenPacket( + TileEditorOpenPacket::SIGN, sign->x, sign->y, sign->z))); + } +} + void ServerPlayer::nextContainerCounter() { containerCounter = (containerCounter % 100) + 1; } @@ -891,7 +954,8 @@ bool ServerPlayer::startCrafting(int x, int y, int z) { nextContainerCounter(); connection->send( std::shared_ptr(new ContainerOpenPacket( - containerCounter, ContainerOpenPacket::WORKBENCH, 0, 9))); + containerCounter, ContainerOpenPacket::WORKBENCH, L"", 9, + false))); containerMenu = new CraftingMenu(inventory, level, x, y, z); containerMenu->containerId = containerCounter; containerMenu->addSlotListener(this); @@ -904,12 +968,44 @@ bool ServerPlayer::startCrafting(int x, int y, int z) { return true; } -bool ServerPlayer::startEnchanting(int x, int y, int z) { +bool ServerPlayer::openFireworks(int x, int y, int z) { if (containerMenu == inventoryMenu) { nextContainerCounter(); connection->send( std::shared_ptr(new ContainerOpenPacket( - containerCounter, ContainerOpenPacket::ENCHANTMENT, 0, 9))); + containerCounter, ContainerOpenPacket::FIREWORKS, L"", 9, + false))); + containerMenu = new FireworksMenu(inventory, level, x, y, z); + containerMenu->containerId = containerCounter; + containerMenu->addSlotListener(this); + } else if (dynamic_cast(containerMenu) != NULL) { + closeContainer(); + + nextContainerCounter(); + connection->send( + std::shared_ptr(new ContainerOpenPacket( + containerCounter, ContainerOpenPacket::FIREWORKS, L"", 9, + false))); + containerMenu = new FireworksMenu(inventory, level, x, y, z); + containerMenu->containerId = containerCounter; + containerMenu->addSlotListener(this); + } else { + app.DebugPrintf( + "ServerPlayer tried to open crafting container when one was " + "already open\n"); + } + + return true; +} + +bool ServerPlayer::startEnchanting(int x, int y, int z, + const std::wstring& name) { + if (containerMenu == inventoryMenu) { + nextContainerCounter(); + connection->send( + std::shared_ptr(new ContainerOpenPacket( + containerCounter, ContainerOpenPacket::ENCHANTMENT, + name.empty() ? L"" : name, 9, !name.empty()))); containerMenu = new EnchantmentMenu(inventory, level, x, y, z); containerMenu->containerId = containerCounter; containerMenu->addSlotListener(this); @@ -927,8 +1023,9 @@ bool ServerPlayer::startRepairing(int x, int y, int z) { nextContainerCounter(); connection->send( std::shared_ptr(new ContainerOpenPacket( - containerCounter, ContainerOpenPacket::REPAIR_TABLE, 0, 9))); - containerMenu = new RepairMenu( + containerCounter, ContainerOpenPacket::REPAIR_TABLE, L"", 9, + false))); + containerMenu = new AnvilMenu( inventory, level, x, y, z, std::dynamic_pointer_cast(shared_from_this())); containerMenu->containerId = containerCounter; @@ -945,10 +1042,16 @@ bool ServerPlayer::startRepairing(int x, int y, int z) { bool ServerPlayer::openContainer(std::shared_ptr container) { if (containerMenu == inventoryMenu) { nextContainerCounter(); + + // 4J-JEV: Added to distinguish between ender, bonus, large and small + // chests (for displaying the name of the chest). + int containerType = container->getContainerType(); + assert(containerType >= 0); + connection->send( std::shared_ptr(new ContainerOpenPacket( - containerCounter, ContainerOpenPacket::CONTAINER, - container->getName(), container->getContainerSize()))); + containerCounter, containerType, container->getCustomName(), + container->getContainerSize(), container->hasCustomName()))); containerMenu = new ContainerMenu(inventory, container); containerMenu->containerId = containerCounter; @@ -961,13 +1064,55 @@ bool ServerPlayer::openContainer(std::shared_ptr container) { return true; } +bool ServerPlayer::openHopper( + std::shared_ptr container) { + if (containerMenu == inventoryMenu) { + nextContainerCounter(); + connection->send( + std::shared_ptr(new ContainerOpenPacket( + containerCounter, ContainerOpenPacket::HOPPER, + container->getCustomName(), container->getContainerSize(), + container->hasCustomName()))); + containerMenu = new HopperMenu(inventory, container); + containerMenu->containerId = containerCounter; + containerMenu->addSlotListener(this); + } else { + app.DebugPrintf( + "ServerPlayer tried to open hopper container when one was already " + "open\n"); + } + + return true; +} + +bool ServerPlayer::openHopper(std::shared_ptr container) { + if (containerMenu == inventoryMenu) { + nextContainerCounter(); + connection->send( + std::shared_ptr(new ContainerOpenPacket( + containerCounter, ContainerOpenPacket::HOPPER, + container->getCustomName(), container->getContainerSize(), + container->hasCustomName()))); + containerMenu = new HopperMenu(inventory, container); + containerMenu->containerId = containerCounter; + containerMenu->addSlotListener(this); + } else { + app.DebugPrintf( + "ServerPlayer tried to open minecart hopper container when one was " + "already open\n"); + } + + return true; +} + bool ServerPlayer::openFurnace(std::shared_ptr furnace) { if (containerMenu == inventoryMenu) { nextContainerCounter(); connection->send( std::shared_ptr(new ContainerOpenPacket( - containerCounter, ContainerOpenPacket::FURNACE, 0, - furnace->getContainerSize()))); + containerCounter, ContainerOpenPacket::FURNACE, + furnace->getCustomName(), furnace->getContainerSize(), + furnace->hasCustomName()))); containerMenu = new FurnaceMenu(inventory, furnace); containerMenu->containerId = containerCounter; containerMenu->addSlotListener(this); @@ -982,9 +1127,14 @@ bool ServerPlayer::openFurnace(std::shared_ptr furnace) { bool ServerPlayer::openTrap(std::shared_ptr trap) { if (containerMenu == inventoryMenu) { nextContainerCounter(); - connection->send(std::shared_ptr( - new ContainerOpenPacket(containerCounter, ContainerOpenPacket::TRAP, - 0, trap->getContainerSize()))); + connection->send( + std::shared_ptr(new ContainerOpenPacket( + containerCounter, + trap->GetType() == eTYPE_DROPPERTILEENTITY + ? ContainerOpenPacket::DROPPER + : ContainerOpenPacket::TRAP, + trap->getCustomName(), trap->getContainerSize(), + trap->hasCustomName()))); containerMenu = new TrapMenu(inventory, trap); containerMenu->containerId = containerCounter; containerMenu->addSlotListener(this); @@ -1002,8 +1152,9 @@ bool ServerPlayer::openBrewingStand( nextContainerCounter(); connection->send( std::shared_ptr(new ContainerOpenPacket( - containerCounter, ContainerOpenPacket::BREWING_STAND, 0, - brewingStand->getContainerSize()))); + containerCounter, ContainerOpenPacket::BREWING_STAND, + brewingStand->getCustomName(), brewingStand->getContainerSize(), + brewingStand->hasCustomName()))); containerMenu = new BrewingStandMenu(inventory, brewingStand); containerMenu->containerId = containerCounter; containerMenu->addSlotListener(this); @@ -1016,7 +1167,27 @@ bool ServerPlayer::openBrewingStand( return true; } -bool ServerPlayer::openTrading(std::shared_ptr traderTarget) { +bool ServerPlayer::openBeacon(std::shared_ptr beacon) { + if (containerMenu == inventoryMenu) { + nextContainerCounter(); + connection->send( + std::shared_ptr(new ContainerOpenPacket( + containerCounter, ContainerOpenPacket::BEACON, + beacon->getCustomName(), beacon->getContainerSize(), + beacon->hasCustomName()))); + containerMenu = new BeaconMenu(inventory, beacon); + containerMenu->containerId = containerCounter; + containerMenu->addSlotListener(this); + } else { + app.DebugPrintf( + "ServerPlayer tried to open beacon when one was already open\n"); + } + + return true; +} + +bool ServerPlayer::openTrading(std::shared_ptr traderTarget, + const std::wstring& name) { if (containerMenu == inventoryMenu) { nextContainerCounter(); containerMenu = new MerchantMenu(inventory, traderTarget, level); @@ -1028,7 +1199,8 @@ bool ServerPlayer::openTrading(std::shared_ptr traderTarget) { connection->send( std::shared_ptr(new ContainerOpenPacket( containerCounter, ContainerOpenPacket::TRADER_NPC, - container->getName(), container->getContainerSize()))); + name.empty() ? L"" : name, container->getContainerSize(), + !name.empty()))); MerchantRecipeList* offers = traderTarget->getOffers( std::dynamic_pointer_cast(shared_from_this())); @@ -1053,7 +1225,26 @@ bool ServerPlayer::openTrading(std::shared_ptr traderTarget) { return true; } -void ServerPlayer::slotChanged(AbstractContainerMenu* container, int slotIndex, +bool ServerPlayer::openHorseInventory( + std::shared_ptr horse, std::shared_ptr container) { + if (containerMenu != inventoryMenu) { + closeContainer(); + } + nextContainerCounter(); + connection->send( + std::shared_ptr(new ContainerOpenPacket( + containerCounter, ContainerOpenPacket::HORSE, + horse->getCustomName(), container->getContainerSize(), + container->hasCustomName(), horse->entityId))); + containerMenu = new HorseInventoryMenu(inventory, container, horse); + containerMenu->containerId = containerCounter; + containerMenu->addSlotListener(this); + + return true; +} + +void ServerPlayer::slotChanged(AbstractContainerMenu* container, + int slotIndstd::ex, std::shared_ptr item) { if (dynamic_cast(container->getSlot(slotIndex))) { return; @@ -1126,14 +1317,14 @@ void ServerPlayer::doCloseContainer() { containerMenu = inventoryMenu; } -void ServerPlayer::setPlayerInput(float xa, float ya, bool jumping, - bool sneaking, float xRot, float yRot) { - xxa = xa; - yya = ya; - this->jumping = jumping; - this->setSneaking(sneaking); - this->xRot = xRot; - this->yRot = yRot; +void ServerPlayer::setPlayerInput(float xxa, float yya, bool jumping, + bool sneaking) { + if (riding != NULL) { + if (xxa >= -1 && xxa <= 1) this->xxa = xxa; + if (yya >= -1 && yya <= 1) this->yya = yya; + this->jumping = jumping; + this->setSneaking(sneaking); + } } void ServerPlayer::awardStat(Stat* stat, byteArray param) { @@ -1147,11 +1338,6 @@ void ServerPlayer::awardStat(Stat* stat, byteArray param) { int count = *((int*)param.data); delete[] param.data; - while (count > 100) { - connection->send(std::shared_ptr( - new AwardStatPacket(stat->id, 100))); - count -= 100; - } connection->send(std::shared_ptr( new AwardStatPacket(stat->id, count))); #else @@ -1164,9 +1350,8 @@ void ServerPlayer::awardStat(Stat* stat, byteArray param) { } void ServerPlayer::disconnect() { - if (riding != NULL) ride(riding); if (rider.lock() != NULL) rider.lock()->ride(shared_from_this()); - if (this->m_isSleeping) { + if (m_isSleeping) { stopSleepInBed(true, false, false); } } @@ -1281,6 +1466,17 @@ void ServerPlayer::displayClientMessage(int messageId) { } } break; + case IDS_MAX_BATS_SPAWNED: + for (unsigned int i = 0; i < server->getPlayers()->players.size(); + i++) { + std::shared_ptr player = + server->getPlayers()->players[i]; + if (shared_from_this() == player) { + player->connection->send(std::shared_ptr( + new ChatPacket(name, ChatPacket::e_ChatPlayerMaxBats))); + } + } + break; case IDS_MAX_WOLVES_SPAWNED: for (unsigned int i = 0; i < server->getPlayers()->players.size(); i++) { @@ -1442,9 +1638,9 @@ void ServerPlayer::displayClientMessage(int messageId) { } // Language *language = Language::getInstance(); - // std::wstring languageString = + // wstring languageString = // app.GetString(messageId);//language->getElement(messageId); - // connection->send( std::shared_ptr( new ChatPacket(L"", + // connection->send( shared_ptr( new ChatPacket(L"", // messageType) ) ); } @@ -1455,7 +1651,7 @@ void ServerPlayer::completeUsingItem() { } void ServerPlayer::startUsingItem(std::shared_ptr instance, - int duration) { + int duration) { Player::startUsingItem(instance, duration); if (instance != NULL && instance->getItem() != NULL && @@ -1468,7 +1664,7 @@ void ServerPlayer::startUsingItem(std::shared_ptr instance, } void ServerPlayer::restoreFrom(std::shared_ptr oldPlayer, - bool restoreAll) { + bool restoreAll) { Player::restoreFrom(oldPlayer, restoreAll); lastSentExp = -1; lastSentHealth = -1; @@ -1483,8 +1679,9 @@ void ServerPlayer::onEffectAdded(MobEffectInstance* effect) { new UpdateMobEffectPacket(entityId, effect))); } -void ServerPlayer::onEffectUpdated(MobEffectInstance* effect) { - Player::onEffectUpdated(effect); +void ServerPlayer::onEffectUpdated(MobEffectInstance* effect, + bool doRefreshAttributes) { + Player::onEffectUpdated(effect, doRefreshAttributes); connection->send(std::shared_ptr( new UpdateMobEffectPacket(entityId, effect))); } @@ -1528,7 +1725,8 @@ void ServerPlayer::setGameMode(GameType* mode) { void ServerPlayer::sendMessage( const std::wstring& message, ChatPacket::EChatPacketMessage type /*= e_ChatCustom*/, - int customData /*= -1*/, const std::wstring& additionalMessage /*= L""*/) { + int customData /*= -1*/, + const std::wstring& additionalMessage /*= L""*/) { connection->send(std::shared_ptr( new ChatPacket(message, type, customData, additionalMessage))); } @@ -1536,11 +1734,19 @@ void ServerPlayer::sendMessage( bool ServerPlayer::hasPermission(EGameCommand command) { return server->getPlayers()->isOp( std::dynamic_pointer_cast(shared_from_this())); + + // 4J: Removed permission level + /*if( + server->getPlayers()->isOp(std::dynamic_pointer_cast(shared_from_this())) + ) + { + return server->getOperatorUserPermissionLevel() >= permissionLevel; + } + return false;*/ } // 4J - Don't use -// void ServerPlayer::updateOptions(std::shared_ptr -// packet) +// void ServerPlayer::updateOptions(shared_ptr packet) //{ // // 4J - Don't need // //if (language.getLanguageList().containsKey(packet.getLanguage())) @@ -1550,7 +1756,7 @@ bool ServerPlayer::hasPermission(EGameCommand command) { // // int dist = 16 * 16 >> packet->getViewDistance(); // if (dist > PlayerChunkMap::MIN_VIEW_DISTANCE && dist < -//PlayerChunkMap::MAX_VIEW_DISTANCE) +// PlayerChunkMap::MAX_VIEW_DISTANCE) // { // this->viewDistance = dist; // } @@ -1560,7 +1766,7 @@ bool ServerPlayer::hasPermission(EGameCommand command) { // // // 4J - Don't need // //if (server.isSingleplayer() && -//server.getSingleplayerName().equals(name)) +// server.getSingleplayerName().equals(name)) // //{ // // server.setDifficulty(packet.getDifficulty()); // //} @@ -1578,6 +1784,14 @@ int ServerPlayer::getViewDistance() { return viewDistance; } // return chatVisibility; // } +Pos* ServerPlayer::getCommandSenderWorldPosition() { + return new Pos(Mth::floor(x), Mth::floor(y + .5), Mth::floor(z)); +} + +void ServerPlayer::resetLastActionTime() { + this->lastActionTime = MinecraftServer::getCurrentTimeMillis(); +} + // Get an index that can be used to uniquely reference this chunk from either // dimension int ServerPlayer::getFlagIndexForChunk(const ChunkPos& pos, int dimension) { diff --git a/Minecraft.Client/Player/ServerPlayer.h b/Minecraft.Client/Player/ServerPlayer.h index f3f4c5c45..30160d730 100644 --- a/Minecraft.Client/Player/ServerPlayer.h +++ b/Minecraft.Client/Player/ServerPlayer.h @@ -10,6 +10,10 @@ class Stat; class TileEntity; class Entity; class BrewingStandTileEntity; +class HopperTileEntity; +class MinecartHopper; +class BeaconTileEntity; +class EntityHorse; class Merchant; class ServerPlayer : public Player, @@ -29,12 +33,14 @@ public: Biome* currentBiome; private: - int lastSentHealth; + float lastRecordedHealthAndAbsorption; + float lastSentHealth; int lastSentFood; bool lastFoodSaturationZero; int lastSentExp; int invulnerableTime; int viewDistance; + int64_t lastActionTime; int lastBrupSendTickCount; // 4J Added public: @@ -46,15 +52,9 @@ public: virtual void readAdditionalSaveData(CompoundTag* entityTag); virtual void addAdditonalSaveData(CompoundTag* entityTag); - virtual void withdrawExperienceLevels(int amount); + virtual void giveExperienceLevels(int amount); void initMenu(); -private: - ItemInstanceArray lastCarried; - -public: - virtual ItemInstanceArray getEquipmentSlots(); - protected: virtual void setDefaultHeadHeight(); @@ -64,13 +64,14 @@ public: void flushEntitiesToRemove(); virtual std::shared_ptr getCarried(int slot); virtual void die(DamageSource* source); - virtual bool hurt(DamageSource* dmgSource, int dmg); - virtual bool isPlayerVersusPlayer(); + virtual bool hurt(DamageSource* dmgSource, float dmg); + virtual bool canHarmPlayer(std::shared_ptr target); + bool canHarmPlayer(std::wstring targetName); // 4J: Added void doTick(bool sendChunks, bool dontDelayChunks = false, bool ignorePortal = false); void doTickA(); void doChunkSendingTick(bool dontDelayChunks); - void doTickB(bool ignorePortal); + void doTickB(); virtual void changeDimension(int i); private: @@ -78,7 +79,6 @@ private: public: virtual void take(std::shared_ptr e, int orgCount); - virtual void swing(); virtual BedSleepingResult startSleepInBed(int x, int y, int z, bool bTestUse = false); @@ -106,19 +106,27 @@ private: void nextContainerCounter(); public: - virtual bool startCrafting(int x, int y, int z); // 4J added bool return - virtual bool startEnchanting(int x, int y, int z); // 4J added bool return - virtual bool startRepairing(int x, int y, int z); // 4J added bool return + virtual void openTextEdit(std::shared_ptr sign); + virtual bool startCrafting(int x, int y, int z); // 4J added bool return + virtual bool openFireworks(int x, int y, int z); // 4J added + virtual bool startEnchanting( + int x, int y, int z, const std::wstring& name); // 4J added bool return + virtual bool startRepairing(int x, int y, int z); // 4J added bool return virtual bool openContainer( std::shared_ptr container); // 4J added bool return + virtual bool openHopper(std::shared_ptr container); + virtual bool openHopper(std::shared_ptr container); virtual bool openFurnace( std::shared_ptr furnace); // 4J added bool return virtual bool openTrap( std::shared_ptr trap); // 4J added bool return virtual bool openBrewingStand(std::shared_ptr brewingStand); // 4J added bool return - virtual bool openTrading( - std::shared_ptr traderTarget); // 4J added bool return + virtual bool openBeacon(std::shared_ptr beacon); + virtual bool openTrading(std::shared_ptr traderTarget, + const std::wstring& name); // 4J added bool return + virtual bool openHorseInventory(std::shared_ptr horse, + std::shared_ptr container); virtual void slotChanged(AbstractContainerMenu* container, int slotIndex, std::shared_ptr item); void refreshContainer(AbstractContainerMenu* menu); @@ -130,8 +138,7 @@ public: virtual void closeContainer(); void broadcastCarriedItem(); void doCloseContainer(); - void setPlayerInput(float xa, float ya, bool jumping, bool sneaking, - float xRot, float yRot); + void setPlayerInput(float xa, float ya, bool jumping, bool sneaking); virtual void awardStat(Stat* stat, byteArray param); @@ -150,7 +157,8 @@ public: protected: virtual void onEffectAdded(MobEffectInstance* effect); - virtual void onEffectUpdated(MobEffectInstance* effect); + virtual void onEffectUpdated(MobEffectInstance* effect, + bool doRefreshAttributes); virtual void onEffectRemoved(MobEffectInstance* effect); public: @@ -166,11 +174,14 @@ public: ChatPacket::EChatPacketMessage type = ChatPacket::e_ChatCustom, int customData = -1, const std::wstring& additionalMessage = L""); bool hasPermission(EGameCommand command); - // 4J - Don't use - // void updateOptions(std::shared_ptr packet); + // bool hasPermission(int permissionLevel, EGameCommand command); + // void updateOptions(std::shared_ptr packet); // + // 4J: Don't use int getViewDistance(); // bool canChatInColor(); // int getChatVisibility(); + Pos* getCommandSenderWorldPosition(); + void resetLastActionTime(); public: static int getFlagIndexForChunk(const ChunkPos& pos, diff --git a/Minecraft.Client/Player/ServerPlayerGameMode.cpp b/Minecraft.Client/Player/ServerPlayerGameMode.cpp index cabbf4189..9da479e6f 100644 --- a/Minecraft.Client/Player/ServerPlayerGameMode.cpp +++ b/Minecraft.Client/Player/ServerPlayerGameMode.cpp @@ -118,8 +118,10 @@ void ServerPlayerGameMode::tick() { void ServerPlayerGameMode::startDestroyBlock(int x, int y, int z, int face) { if (!player->isAllowedToMine()) return; - if (gameModeForPlayer->isReadOnly()) { - return; + if (gameModeForPlayer->isAdventureRestricted()) { + if (!player->mayDestroyBlockAt(x, y, z)) { + return; + } } if (isCreative()) { @@ -138,9 +140,12 @@ void ServerPlayerGameMode::startDestroyBlock(int x, int y, int z, int face) { Tile::tiles[t]->getDestroyProgress(player, player->level, x, y, z); } - if (t > 0 && (progress >= 1 || (app.DebugSettingsOn() && - (player->GetDebugOptions() & - (1L << eDebugSetting_InstantDestroy))))) { + if (t > 0 && + (progress >= + 1)) //|| (app.DebugSettingsOn() && + //(player->GetDebugOptions()&(1L<getDestroyProgress(player, player->level, x, y, // z) * (ticksSpentDestroying + 1); if (destroyProgress @@ -201,7 +206,7 @@ bool ServerPlayerGameMode::superDestroyBlock(int x, int y, int z) { oldTile->playerWillDestroy(level, x, y, z, data, player); } - bool changed = level->setTile(x, y, z, 0); + bool changed = level->removeTile(x, y, z); if (oldTile != NULL && changed) { oldTile->destroy(level, x, y, z, data); } @@ -209,8 +214,18 @@ bool ServerPlayerGameMode::superDestroyBlock(int x, int y, int z) { } bool ServerPlayerGameMode::destroyBlock(int x, int y, int z) { - if (gameModeForPlayer->isReadOnly()) { - return false; + if (gameModeForPlayer->isAdventureRestricted()) { + if (!player->mayDestroyBlockAt(x, y, z)) { + return false; + } + } + + if (gameModeForPlayer->isCreative()) { + if (player->getCarriedItem() != NULL && + dynamic_cast(player->getCarriedItem()->getItem()) != + NULL) { + return false; + } } int t = level->getTile(x, y, z); @@ -293,17 +308,23 @@ bool ServerPlayerGameMode::useItem(std::shared_ptr player, Level* level, int oldCount = item->count; int oldAux = item->getAuxValue(); std::shared_ptr itemInstance = item->use(level, player); - if ((itemInstance != NULL && itemInstance != item) || - (itemInstance != NULL && itemInstance->count != oldCount) || - (itemInstance != NULL && itemInstance->getUseDuration() > 0)) { + if (itemInstance != item || + (itemInstance != NULL && (itemInstance->count != oldCount || + itemInstance->getUseDuration() > 0 || + itemInstance->getAuxValue() != oldAux))) { player->inventory->items[player->inventory->selected] = itemInstance; if (isCreative()) { itemInstance->count = oldCount; - itemInstance->setAuxValue(oldAux); + if (itemInstance->isDamageableItem()) + itemInstance->setAuxValue(oldAux); } if (itemInstance->count == 0) { player->inventory->items[player->inventory->selected] = nullptr; } + if (!player->isUsingItem()) { + std::dynamic_pointer_cast(player)->refreshContainer( + player->inventoryMenu); + } return true; } return false; @@ -317,14 +338,16 @@ bool ServerPlayerGameMode::useItemOn(std::shared_ptr player, bool bTestUseOnOnly, bool* pbUsedItem) { // 4J-PB - Adding a test only version to allow tooltips to be displayed int t = level->getTile(x, y, z); - if (t > 0 && player->isAllowedToUse(Tile::tiles[t])) { - if (bTestUseOnOnly) { - if (Tile::tiles[t]->TestUse()) return true; - } else { - if (Tile::tiles[t]->use(level, x, y, z, player, face, clickX, - clickY, clickZ)) { - if (m_gameRules != NULL) m_gameRules->onUseTile(t, x, y, z); - return true; + if (!player->isSneaking() || player->getCarriedItem() == NULL) { + if (t > 0 && player->isAllowedToUse(Tile::tiles[t])) { + if (bTestUseOnOnly) { + if (Tile::tiles[t]->TestUse()) return true; + } else { + if (Tile::tiles[t]->use(level, x, y, z, player, face, clickX, + clickY, clickZ)) { + if (m_gameRules != NULL) m_gameRules->onUseTile(t, x, y, z); + return true; + } } } } diff --git a/Minecraft.Client/Player/TrackedEntity.cpp b/Minecraft.Client/Player/TrackedEntity.cpp index c6f58808b..b7d96a3e1 100644 --- a/Minecraft.Client/Player/TrackedEntity.cpp +++ b/Minecraft.Client/Player/TrackedEntity.cpp @@ -13,6 +13,7 @@ #include "../../Minecraft.World/Headers/net.minecraft.network.packet.h" #include "../../Minecraft.World/Headers/net.minecraft.world.item.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.saveddata.h" +#include "../../Minecraft.World/Headers/net.minecraft.world.entity.ai.attributes.h" #include "../MinecraftServer.h" #include "../Level/ServerLevel.h" #include "../Network/PlayerList.h" @@ -31,6 +32,7 @@ TrackedEntity::TrackedEntity(std::shared_ptr e, int range, updatedPlayerVisibility = false; teleportDelay = 0; moved = false; + wasRiding = false; this->e = e; this->range = range; @@ -60,10 +62,12 @@ void TrackedEntity::tick(EntityTracker* tracker, updatePlayers(tracker, players); } - if (wasRiding != e->riding) { - wasRiding = e->riding; - broadcast(std::shared_ptr( - new SetRidingPacket(e, e->riding))); + if (lastRidingEntity != e->riding || + (e->riding != NULL && + tickCount % (SharedConstants::TICKS_PER_SECOND * 3) == 0)) { + lastRidingEntity = e->riding; + broadcast(std::shared_ptr(new SetEntityLinkPacket( + SetEntityLinkPacket::RIDING, e, e->riding))); } // Moving forward special case for item frames @@ -95,43 +99,64 @@ void TrackedEntity::tick(EntityTracker* tracker, broadcastAndSend(std::shared_ptr( new SetEntityDataPacket(e->entityId, entityData, false))); } - } else { + } else if (tickCount % updateInterval == 0 || e->hasImpulse || + e->getEntityData()->isDirty()) { + // 4J: Moved this as it's shared + int yRotn = Mth::floor(e->yRot * 256 / 360); + int xRotn = Mth::floor(e->xRot * 256 / 360); + + // 4J: Changed rotation to be generally sent as a delta as well as + // position + int yRota = yRotn - yRotp; + int xRota = xRotn - xRotp; + if (e->riding == NULL) { teleportDelay++; - if (tickCount++ % updateInterval == 0 || e->hasImpulse) { - int xn = Mth::floor(this->e->x * 32.0); - int yn = Mth::floor(this->e->y * 32.0); - int zn = Mth::floor(this->e->z * 32.0); - int yRotn = Mth::floor(e->yRot * 256 / 360); - int xRotn = Mth::floor(e->xRot * 256 / 360); - int xa = xn - xp; - int ya = yn - yp; - int za = zn - zp; + int xn = Mth::floor(e->x * 32.0); + int yn = Mth::floor(e->y * 32.0); + int zn = Mth::floor(e->z * 32.0); - std::shared_ptr packet = nullptr; + int xa = xn - xp; + int ya = yn - yp; + int za = zn - zp; - // 4J - this pos flag used to be set based on abs(xn) etc. but - // that just seems wrong - bool pos = abs(xa) >= TOLERANCE_LEVEL || - abs(ya) >= TOLERANCE_LEVEL || - abs(za) >= TOLERANCE_LEVEL; - // 4J - changed rotation to be generally sent as a delta as well - // as position - int yRota = yRotn - yRotp; - int xRota = xRotn - xRotp; - // Keep rotation deltas in +/- 180 degree range - while (yRota > 127) yRota -= 256; - while (yRota < -128) yRota += 256; - while (xRota > 127) xRota -= 256; - while (xRota < -128) xRota += 256; + std::shared_ptr packet = nullptr; - bool rot = abs(yRota) >= TOLERANCE_LEVEL || - abs(xRota) >= TOLERANCE_LEVEL; + // 4J - this pos flag used to be set based on abs(xn) etc. but that + // just seems wrong + bool pos = + abs(xa) >= TOLERANCE_LEVEL || abs(ya) >= TOLERANCE_LEVEL || + abs(za) >= TOLERANCE_LEVEL || + (tickCount % (SharedConstants::TICKS_PER_SECOND * 3) == 0); + // Keep rotation deltas in +/- 180 degree range + while (yRota > 127) yRota -= 256; + while (yRota < -128) yRota += 256; + while (xRota > 127) xRota -= 256; + while (xRota < -128) xRota += 256; + + bool rot = + abs(yRota) >= TOLERANCE_LEVEL || abs(xRota) >= TOLERANCE_LEVEL; + + // 4J: Modified the following check. It was originally added by + // Mojang to address certain unspecified issues with entity + // position. Turns out the issue effects a variety of different + // entities so we've left it in and just added the new exceptions + // (so far just players) + + // 4J: Original comment follows + // TODO: Figure out how to fix this properly + // skip first tick since position is sent in addEntity packet + // FallingTile depends on this because it removes its source block + // in the first tick() + + if (tickCount > 0 || e->instanceof(eTYPE_ARROW) || + e->instanceof(eTYPE_PLAYER)) // 4J: Modifed, see above + { if (xa < -128 || xa >= 128 || ya < -128 || ya >= 128 || - za < -128 || - za >= 128 + za < -128 || za >= 128 || + wasRiding // 4J Stu - I fixed the initialisation of teleportDelay in // the ctor, but we managed this far without out and would // prefer not to have all the extra traffix so ignore it 4J @@ -176,7 +201,7 @@ void TrackedEntity::tick(EntityTracker* tracker, e->entityId, (char)xa, (char)ya, (char)za, (char)yRota, (char)xRota)); // printf("%d: New - //posrot %d + %d = + // posrot %d + %d = //%d\n",e->entityId,yRotp,yRota,yRotn); c0b++; } @@ -226,7 +251,7 @@ void TrackedEntity::tick(EntityTracker* tracker, c2a++; } else { // printf("%d: New - //rot %d + %d = + // rot %d + %d = //%d\n",e->entityId,yRotp,yRota,yRotn); packet = std::shared_ptr( new MoveEntityPacket::Rot( @@ -235,76 +260,77 @@ void TrackedEntity::tick(EntityTracker* tracker, } } } - - if (trackDelta) { - double xad = e->xd - xap; - double yad = e->yd - yap; - double zad = e->zd - zap; - - double max = 0.02; - - double diff = xad * xad + yad * yad + zad * zad; - - if (diff > max * max || - (diff > 0 && e->xd == 0 && e->yd == 0 && e->zd == 0)) { - xap = e->xd; - yap = e->yd; - zap = e->zd; - broadcast(std::shared_ptr( - new SetEntityMotionPacket(e->entityId, xap, yap, - zap))); - } - } - - if (packet != NULL) { - broadcast(packet); - } - - std::shared_ptr entityData = - e->getEntityData(); - - if (entityData->isDirty()) { - broadcastAndSend(std::shared_ptr( - new SetEntityDataPacket(e->entityId, entityData, - false))); - } - - int yHeadRot = Mth::floor(e->getYHeadRot() * 256 / 360); - if (abs(yHeadRot - yHeadRotp) >= TOLERANCE_LEVEL) { - broadcast(std::shared_ptr( - new RotateHeadPacket(e->entityId, (uint8_t)yHeadRot))); - yHeadRotp = yHeadRot; - } - - if (pos) { - xp = xn; - yp = yn; - zp = zn; - } - if (rot) { - yRotp = yRotn; - xRotp = xRotn; - } - - // if( std::dynamic_pointer_cast(e) - //!= NULL ) - // { - // printf("%d: %d + %d = %d - //(%f)\n",e->entityId,xRotp,xRota,xRotn,e->xRot); - // } } - } else // 4J-JEV: Added: Mobs in minecarts weren't synching their - // invisibility. - { - std::shared_ptr entityData = e->getEntityData(); - if (entityData->isDirty()) - broadcastAndSend(std::shared_ptr( - new SetEntityDataPacket(e->entityId, entityData, false))); + if (trackDelta) { + double xad = e->xd - xap; + double yad = e->yd - yap; + double zad = e->zd - zap; + + double max = 0.02; + + double diff = xad * xad + yad * yad + zad * zad; + + if (diff > max * max || + (diff > 0 && e->xd == 0 && e->yd == 0 && e->zd == 0)) { + xap = e->xd; + yap = e->yd; + zap = e->zd; + broadcast(std::shared_ptr( + new SetEntityMotionPacket(e->entityId, xap, yap, zap))); + } + } + + if (packet != NULL) { + broadcast(packet); + } + + sendDirtyEntityData(); + + if (pos) { + xp = xn; + yp = yn; + zp = zn; + } + if (rot) { + yRotp = yRotn; + xRotp = xRotn; + } + + wasRiding = false; + } else { + bool rot = abs(yRotn - yRotp) >= TOLERANCE_LEVEL || + abs(xRotn - xRotp) >= TOLERANCE_LEVEL; + if (rot) { + // 4J: Changed this to use deltas + broadcast( + std::shared_ptr(new MoveEntityPacket::Rot( + e->entityId, (uint8_t)yRota, (uint8_t)xRota))); + yRotp = yRotn; + xRotp = xRotn; + } + + xp = Mth::floor(e->x * 32.0); + yp = Mth::floor(e->y * 32.0); + zp = Mth::floor(e->z * 32.0); + + sendDirtyEntityData(); + + wasRiding = true; } + + int yHeadRot = Mth::floor(e->getYHeadRot() * 256 / 360); + if (abs(yHeadRot - yHeadRotp) >= TOLERANCE_LEVEL) { + broadcast(std::shared_ptr( + new RotateHeadPacket(e->entityId, (uint8_t)yHeadRot))); + yHeadRotp = yHeadRot; + } + e->hasImpulse = false; } + tickCount++; + if (e->hurtMarked) { // broadcast(new AnimatePacket(e, AnimatePacket.HURT)); broadcastAndSend(std::shared_ptr( @@ -313,6 +339,30 @@ void TrackedEntity::tick(EntityTracker* tracker, } } +void TrackedEntity::sendDirtyEntityData() { + std::shared_ptr entityData = e->getEntityData(); + if (entityData->isDirty()) { + broadcastAndSend(std::shared_ptr( + new SetEntityDataPacket(e->entityId, entityData, false))); + } + + if (e->instanceof(eTYPE_LIVINGENTITY)) { + std::shared_ptr living = + std::dynamic_pointer_cast(e); + ServersideAttributeMap* attributeMap = + (ServersideAttributeMap*)living->getAttributes(); + std::unordered_set* attributes = + attributeMap->getDirtyAttributes(); + + if (!attributes->empty()) { + broadcastAndSend(std::shared_ptr( + new UpdateAttributesPacket(e->entityId, attributes))); + } + + attributes->clear(); + } +} + void TrackedEntity::broadcast(std::shared_ptr packet) { if (Packet::canSendToAnyClient(packet)) { // 4J-PB - due to the knockback on a player being hit, we need to send @@ -345,10 +395,11 @@ void TrackedEntity::broadcast(std::shared_ptr packet) { thisPlayer->IsSameSystem(otherPlayer)) { dontSend = true; // #ifdef _DEBUG - // std::shared_ptr + // shared_ptr // emp= // std::dynamic_pointer_cast - // (packet); if(emp!=NULL) + // (packet); + // if(emp!=NULL) // { // app.DebugPrintf("Not // sending this SetEntityMotionPacket to player - @@ -381,7 +432,9 @@ void TrackedEntity::broadcastAndSend(std::shared_ptr packet) { std::vector > sentTo; broadcast(packet); std::shared_ptr sp = - std::dynamic_pointer_cast(e); + e->instanceof(eTYPE_SERVERPLAYER) + ? std::dynamic_pointer_cast(e) + : nullptr; if (sp != NULL && sp->connection) { sp->connection->send(packet); } @@ -396,6 +449,7 @@ void TrackedEntity::broadcastRemoved() { void TrackedEntity::removePlayer(std::shared_ptr sp) { AUTO_VAR(it, seenBy.find(sp)); if (it != seenBy.end()) { + sp->entitiesToRemove.push_back(e->entityId); seenBy.erase(it); } } @@ -411,6 +465,13 @@ TrackedEntity::eVisibility TrackedEntity::isVisible( double xd = sp->x - xpu; // xp / 32; double zd = sp->z - zpu; // zp / 32; + // 4J Stu - Fix for loading a player who is currently riding something (e.g. + // a horse) + if (e->forcedLoading) { + xd = sp->x - xp / 32; + zd = sp->z - zp / 32; + } + int playersRange = range; if (playersRange > TRACKED_ENTITY_MINIMUM_VIEW_DISTANCE) { playersRange -= sp->getPlayerViewDistanceModifier(); @@ -486,7 +547,7 @@ void TrackedEntity::updatePlayer(EntityTracker* tracker, eVisibility visibility = this->isVisible(tracker, sp); if (visibility == eVisibility_SeenAndVisible && - seenBy.find(sp) == seenBy.end()) { + (seenBy.find(sp) == seenBy.end() || e->forcedLoading)) { seenBy.insert(sp); std::shared_ptr packet = getAddEntityPacket(); sp->connection->send(packet); @@ -495,8 +556,8 @@ void TrackedEntity::updatePlayer(EntityTracker* tracker, yap = e->yd; zap = e->zd; - std::shared_ptr plr = std::dynamic_pointer_cast(e); - if (plr != NULL) { + if (e->instanceof(eTYPE_PLAYER)) { + std::shared_ptr plr = std::dynamic_pointer_cast(e); app.DebugPrintf( "TrackedEntity:: Player '%ls' is now visible to player '%ls', " "%s.\n", @@ -504,33 +565,60 @@ void TrackedEntity::updatePlayer(EntityTracker* tracker, (e->riding == NULL ? "not riding minecart" : "in minecart")); } + bool isAddMobPacket = + std::dynamic_pointer_cast(packet) != NULL; + // 4J Stu brought forward to fix when Item Frames - if (!e->getEntityData()->isEmpty() && - !(std::dynamic_pointer_cast(packet))) { + if (!e->getEntityData()->isEmpty() && !isAddMobPacket) { sp->connection->send( std::shared_ptr(new SetEntityDataPacket( e->entityId, e->getEntityData(), true))); } - if (this->trackDelta) { + if (e->instanceof(eTYPE_LIVINGENTITY)) { + std::shared_ptr living = + std::dynamic_pointer_cast(e); + ServersideAttributeMap* attributeMap = + (ServersideAttributeMap*)living->getAttributes(); + std::unordered_set* attributes = + attributeMap->getSyncableAttributes(); + + if (!attributes->empty()) { + sp->connection->send(std::shared_ptr( + new UpdateAttributesPacket(e->entityId, attributes))); + } + delete attributes; + } + + if (trackDelta && !isAddMobPacket) { sp->connection->send(std::shared_ptr( new SetEntityMotionPacket(e->entityId, e->xd, e->yd, e->zd))); } if (e->riding != NULL) { - sp->connection->send(std::shared_ptr( - new SetRidingPacket(e, e->riding))); + sp->connection->send( + std::shared_ptr(new SetEntityLinkPacket( + SetEntityLinkPacket::RIDING, e, e->riding))); + } + if (e->instanceof(eTYPE_MOB) && + std::dynamic_pointer_cast(e)->getLeashHolder() != NULL) { + sp->connection->send( + std::shared_ptr(new SetEntityLinkPacket( + SetEntityLinkPacket::LEASH, e, + std::dynamic_pointer_cast(e)->getLeashHolder()))); } - ItemInstanceArray equipped = e->getEquipmentSlots(); - if (equipped.data != NULL) { - for (unsigned int i = 0; i < equipped.length; i++) { - sp->connection->send(std::shared_ptr( - new SetEquippedItemPacket(e->entityId, i, equipped[i]))); + if (e->instanceof(eTYPE_LIVINGENTITY)) { + for (int i = 0; i < 5; i++) { + std::shared_ptr item = + std::dynamic_pointer_cast(e)->getCarried(i); + if (item != NULL) + sp->connection->send(std::shared_ptr( + new SetEquippedItemPacket(e->entityId, i, item))); } } - if (std::dynamic_pointer_cast(e) != NULL) { + if (e->instanceof(eTYPE_PLAYER)) { std::shared_ptr spe = std::dynamic_pointer_cast(e); if (spe->isSleeping()) { sp->connection->send( @@ -542,8 +630,9 @@ void TrackedEntity::updatePlayer(EntityTracker* tracker, } } - if (std::dynamic_pointer_cast(e) != NULL) { - std::shared_ptr mob = std::dynamic_pointer_cast(e); + if (e->instanceof(eTYPE_LIVINGENTITY)) { + std::shared_ptr mob = + std::dynamic_pointer_cast(e); std::vector* activeEffects = mob->getActiveEffects(); for (AUTO_VAR(it, activeEffects->begin()); @@ -573,7 +662,7 @@ bool TrackedEntity::canBySeenBy(std::shared_ptr player) { return true; // return player->getLevel()->getChunkMap()->isPlayerIn(player, e->xChunk, - //e->zChunk); + // e->zChunk); } void TrackedEntity::updatePlayers( @@ -598,405 +687,153 @@ std::shared_ptr TrackedEntity::getAddEntityPacket() { xp, yp, zp, yHeadRotp)); } - switch (e->GetType()) { - case eTYPE_ITEMENTITY: { - std::shared_ptr packet = - std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::ITEM, 1, yRotp, xRotp, xp, yp, zp)); - return packet; - } break; - case eTYPE_SERVERPLAYER: { - std::shared_ptr player = - std::dynamic_pointer_cast(e); - PlayerUID xuid = INVALID_XUID; - PlayerUID OnlineXuid = INVALID_XUID; - if (player != NULL) { - xuid = player->getXuid(); - OnlineXuid = player->getOnlineXuid(); - } - // 4J Added yHeadRotp param to fix #102563 - TU12: Content: - // Gameplay: When one of the Players is idle for a few minutes his - // head turns 180 degrees. - return std::shared_ptr(new AddPlayerPacket( - std::dynamic_pointer_cast(e), xuid, OnlineXuid, xp, yp, - zp, yRotp, xRotp, yHeadRotp)); - } break; - case eTYPE_MINECART: { - std::shared_ptr minecart = - std::dynamic_pointer_cast(e); - if (minecart->type == Minecart::RIDEABLE) - return std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::MINECART_RIDEABLE, - yRotp, xRotp, xp, yp, zp)); - if (minecart->type == Minecart::CHEST) - return std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::MINECART_CHEST, - yRotp, xRotp, xp, yp, zp)); - if (minecart->type == Minecart::FURNACE) - return std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::MINECART_FURNACE, - yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_BOAT: { - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::BOAT, yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_ENDERDRAGON: { - yHeadRotp = Mth::floor(e->getYHeadRot() * 256 / 360); - return std::shared_ptr( - new AddMobPacket(std::dynamic_pointer_cast(e), yRotp, - xRotp, xp, yp, zp, yHeadRotp)); - } break; - case eTYPE_FISHINGHOOK: { - std::shared_ptr owner = - std::dynamic_pointer_cast(e)->owner; - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::FISH_HOOK, - owner != NULL ? owner->entityId : e->entityId, yRotp, xRotp, xp, - yp, zp)); - } break; - case eTYPE_ARROW: { - std::shared_ptr owner = - (std::dynamic_pointer_cast(e))->owner; - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::ARROW, - owner != NULL ? owner->entityId : e->entityId, yRotp, xRotp, xp, - yp, zp)); - } break; - case eTYPE_SNOWBALL: { - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::SNOWBALL, yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_THROWNPOTION: { - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::THROWN_POTION, - ((std::dynamic_pointer_cast(e)) - ->getPotionValue()), - yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_THROWNEXPBOTTLE: { - return std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::THROWN_EXPBOTTLE, yRotp, - xRotp, xp, yp, zp)); - } break; - case eTYPE_THROWNENDERPEARL: { - return std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::THROWN_ENDERPEARL, + if (e->instanceof(eTYPE_ITEMENTITY)) { + std::shared_ptr packet = + std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::ITEM, 1, yRotp, xRotp, xp, yp, zp)); + return packet; + } else if (e->instanceof(eTYPE_SERVERPLAYER)) { + std::shared_ptr player = + std::dynamic_pointer_cast(e); + + PlayerUID xuid = INVALID_XUID; + PlayerUID OnlineXuid = INVALID_XUID; + if (player != NULL) { + xuid = player->getXuid(); + OnlineXuid = player->getOnlineXuid(); + } + // 4J Added yHeadRotp param to fix #102563 - TU12: Content: Gameplay: + // When one of the Players is idle for a few minutes his head turns 180 + // degrees. + return std::shared_ptr(new AddPlayerPacket( + player, xuid, OnlineXuid, xp, yp, zp, yRotp, xRotp, yHeadRotp)); + } else if (e->instanceof(eTYPE_MINECART)) { + std::shared_ptr minecart = + std::dynamic_pointer_cast(e); + return std::shared_ptr( + new AddEntityPacket(e, AddEntityPacket::MINECART, + minecart->getType(), yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_BOAT)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::BOAT, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_ENDERDRAGON)) { + yHeadRotp = Mth::floor(e->getYHeadRot() * 256 / 360); + return std::shared_ptr( + new AddMobPacket(std::dynamic_pointer_cast(e), yRotp, + xRotp, xp, yp, zp, yHeadRotp)); + } else if (e->instanceof(eTYPE_FISHINGHOOK)) { + std::shared_ptr owner = + std::dynamic_pointer_cast(e)->owner; + return std::shared_ptr( + new AddEntityPacket(e, AddEntityPacket::FISH_HOOK, + owner != NULL ? owner->entityId : e->entityId, + yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_ARROW)) { + std::shared_ptr owner = + (std::dynamic_pointer_cast(e))->owner; + return std::shared_ptr( + new AddEntityPacket(e, AddEntityPacket::ARROW, + owner != NULL ? owner->entityId : e->entityId, + yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_SNOWBALL)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::SNOWBALL, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_THROWNPOTION)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::THROWN_POTION, + ((std::dynamic_pointer_cast(e))->getPotionValue()), + yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_THROWNEXPBOTTLE)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::THROWN_EXPBOTTLE, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_THROWNENDERPEARL)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::THROWN_ENDERPEARL, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_EYEOFENDERSIGNAL)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::EYEOFENDERSIGNAL, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_FIREWORKS_ROCKET)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::FIREWORKS, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_FIREBALL)) { + eINSTANCEOF classType = e->GetType(); + int type = AddEntityPacket::FIREBALL; + if (classType == eTYPE_SMALL_FIREBALL) { + type = AddEntityPacket::SMALL_FIREBALL; + } else if (classType == eTYPE_DRAGON_FIREBALL) { + type = AddEntityPacket::DRAGON_FIRE_BALL; + } else if (classType == eTYPE_WITHER_SKULL) { + type = AddEntityPacket::WITHER_SKULL; + } + + std::shared_ptr fb = std::dynamic_pointer_cast(e); + std::shared_ptr aep = nullptr; + if (fb->owner != NULL) { + aep = std::shared_ptr(new AddEntityPacket( + e, type, fb->owner->entityId, yRotp, xRotp, xp, yp, zp)); + } else { + aep = std::shared_ptr( + new AddEntityPacket(e, type, 0, yRotp, xRotp, xp, yp, zp)); + } + aep->xa = (int)(fb->xPower * 8000); + aep->ya = (int)(fb->yPower * 8000); + aep->za = (int)(fb->zPower * 8000); + return aep; + } else if (e->instanceof(eTYPE_THROWNEGG)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::EGG, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_PRIMEDTNT)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::PRIMED_TNT, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_ENDER_CRYSTAL)) { + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::ENDER_CRYSTAL, yRotp, xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_FALLINGTILE)) { + std::shared_ptr ft = + std::dynamic_pointer_cast(e); + return std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::FALLING, ft->tile | (ft->data << 16), yRotp, + xRotp, xp, yp, zp)); + } else if (e->instanceof(eTYPE_PAINTING)) { + return std::shared_ptr( + new AddPaintingPacket(std::dynamic_pointer_cast(e))); + } else if (e->instanceof(eTYPE_ITEM_FRAME)) { + std::shared_ptr frame = + std::dynamic_pointer_cast(e); + + { + int ix = (int)frame->xTile; + int iy = (int)frame->yTile; + int iz = (int)frame->zTile; + app.DebugPrintf("eTYPE_ITEM_FRAME xyz %d,%d,%d\n", ix, iy, iz); + } + + std::shared_ptr packet = + std::shared_ptr( + new AddEntityPacket(e, AddEntityPacket::ITEM_FRAME, frame->dir, yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_EYEOFENDERSIGNAL: { - return std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::EYEOFENDERSIGNAL, yRotp, - xRotp, xp, yp, zp)); - } break; - case eTYPE_SMALL_FIREBALL: { - std::shared_ptr fb = - std::dynamic_pointer_cast(e); - std::shared_ptr aep = nullptr; - if (fb->owner != NULL) { - aep = std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::SMALL_FIREBALL, fb->owner->entityId, - yRotp, xRotp, xp, yp, zp)); - } else { - aep = std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::SMALL_FIREBALL, 0, - yRotp, xRotp, xp, yp, zp)); - } - aep->xa = (int)(fb->xPower * 8000); - aep->ya = (int)(fb->yPower * 8000); - aep->za = (int)(fb->zPower * 8000); - return aep; - } break; - case eTYPE_DRAGON_FIREBALL: { - std::shared_ptr fb = - std::dynamic_pointer_cast(e); - std::shared_ptr aep = nullptr; - if (fb->owner != NULL) { - aep = std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::DRAGON_FIRE_BALL, fb->owner->entityId, - yRotp, xRotp, xp, yp, zp)); - } else { - aep = std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::DRAGON_FIRE_BALL, 0, - yRotp, xRotp, xp, yp, zp)); - } - aep->xa = (int)(fb->xPower * 8000); - aep->ya = (int)(fb->yPower * 8000); - aep->za = (int)(fb->zPower * 8000); - return aep; - } break; - case eTYPE_FIREBALL: { - std::shared_ptr fb = - std::dynamic_pointer_cast(e); - std::shared_ptr aep = nullptr; - if (fb->owner != NULL) { - aep = std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::FIREBALL, fb->owner->entityId, yRotp, - xRotp, xp, yp, zp)); - } else { - aep = std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::FIREBALL, 0, yRotp, xRotp, xp, yp, zp)); - } - aep->xa = (int)(fb->xPower * 8000); - aep->ya = (int)(fb->yPower * 8000); - aep->za = (int)(fb->zPower * 8000); - return aep; - } break; - case eTYPE_THROWNEGG: { - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::EGG, yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_PRIMEDTNT: { - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::PRIMED_TNT, yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_ENDER_CRYSTAL: { - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::ENDER_CRYSTAL, yRotp, xRotp, xp, yp, zp)); - } break; - case eTYPE_FALLINGTILE: { - std::shared_ptr ft = - std::dynamic_pointer_cast(e); - return std::shared_ptr(new AddEntityPacket( - e, AddEntityPacket::FALLING, ft->tile | (ft->data << 16), yRotp, - xRotp, xp, yp, zp)); - } break; - case eTYPE_PAINTING: { - return std::shared_ptr( - new AddPaintingPacket(std::dynamic_pointer_cast(e))); - } break; - case eTYPE_ITEM_FRAME: { - std::shared_ptr frame = - std::dynamic_pointer_cast(e); - { - int ix = (int)frame->xTile; - int iy = (int)frame->yTile; - int iz = (int)frame->zTile; - app.DebugPrintf("eTYPE_ITEM_FRAME xyz %d,%d,%d\n", ix, iy, iz); - } - - std::shared_ptr packet = - std::shared_ptr( - new AddEntityPacket(e, AddEntityPacket::ITEM_FRAME, - frame->dir, yRotp, xRotp, xp, yp, zp)); - packet->x = Mth::floor(frame->xTile * 32.0f); - packet->y = Mth::floor(frame->yTile * 32.0f); - packet->z = Mth::floor(frame->zTile * 32.0f); - return packet; - } break; - case eTYPE_EXPERIENCEORB: { - return std::shared_ptr( - new AddExperienceOrbPacket( - std::dynamic_pointer_cast(e))); - } break; - default: - assert(false); - break; + packet->x = Mth::floor(frame->xTile * 32.0f); + packet->y = Mth::floor(frame->yTile * 32.0f); + packet->z = Mth::floor(frame->zTile * 32.0f); + return packet; + } else if (e->instanceof(eTYPE_LEASHFENCEKNOT)) { + std::shared_ptr knot = + std::dynamic_pointer_cast(e); + std::shared_ptr packet = + std::shared_ptr(new AddEntityPacket( + e, AddEntityPacket::LEASH_KNOT, yRotp, xRotp, xp, yp, zp)); + packet->x = Mth::floor((float)knot->xTile * 32); + packet->y = Mth::floor((float)knot->yTile * 32); + packet->z = Mth::floor((float)knot->zTile * 32); + return packet; + } else if (e->instanceof(eTYPE_EXPERIENCEORB)) { + return std::shared_ptr( + new AddExperienceOrbPacket( + std::dynamic_pointer_cast(e))); + } else { + assert(false); } - /* - if (e->GetType() == eTYPE_ITEMENTITY) - { - std::shared_ptr itemEntity = - std::dynamic_pointer_cast(e); - std::shared_ptr packet = - std::shared_ptr( new AddItemEntityPacket(itemEntity, - xp, yp, zp) ); itemEntity->x = packet->x / 32.0; itemEntity->y = - packet->y / 32.0; itemEntity->z = packet->z / 32.0; return packet; - } - if (e->GetType() == eTYPE_SERVERPLAYER ) - { - std::shared_ptr player = - std::dynamic_pointer_cast(e); XUID xuid = INVALID_XUID; - XUID OnlineXuid = INVALID_XUID; - if( player != NULL ) - { - xuid = player->getXuid(); - OnlineXuid = player->getOnlineXuid(); - } - return std::shared_ptr( new - AddPlayerPacket(std::dynamic_pointer_cast(e), xuid, OnlineXuid, - xp, yp, zp, yRotp, xRotp ) ); - } - if (e->GetType() == eTYPE_MINECART) - { - std::shared_ptr minecart = - std::dynamic_pointer_cast(e); if (minecart->type == - Minecart::RIDEABLE) return std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::MINECART_RIDEABLE, yRotp, xRotp, xp, - yp, zp) ); if (minecart->type == Minecart::CHEST) return - std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::MINECART_CHEST, yRotp, xRotp, xp, yp, zp) ); if - (minecart->type == Minecart::FURNACE) return - std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::MINECART_FURNACE, yRotp, xRotp, xp, yp, zp) ); - } - if (e->GetType() == eTYPE_BOAT) - { - return std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::BOAT, yRotp, xRotp, xp, yp, zp) ); - } - if (std::dynamic_pointer_cast(e) != NULL) - { - return std::shared_ptr( new - AddMobPacket(std::dynamic_pointer_cast(e), yRotp, xRotp, xp, yp, zp) - ); - } - if (e->GetType() == eTYPE_ENDERDRAGON) - { - return std::shared_ptr( new - AddMobPacket(std::dynamic_pointer_cast(e), yRotp, xRotp, xp, yp, zp - ) ); - } - if (e->GetType() == eTYPE_FISHINGHOOK) - { - std::shared_ptr owner = - std::dynamic_pointer_cast(e)->owner; return - std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::FISH_HOOK, owner != NULL ? owner->entityId : - e->entityId, yRotp, xRotp, xp, yp, zp) ); - } - if (e->GetType() == eTYPE_ARROW) - { - std::shared_ptr owner = - (std::dynamic_pointer_cast(e))->owner; return - std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::ARROW, owner != NULL ? owner->entityId : e->entityId, - yRotp, xRotp, xp, yp, zp) ); - } - if (e->GetType() == eTYPE_SNOWBALL) - { - return std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::SNOWBALL, yRotp, xRotp, xp, yp, zp) ); - } - if (e->GetType() == eTYPE_THROWNPOTION) - { - return std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::THROWN_POTION, - ((std::dynamic_pointer_cast(e))->getPotionValue()), yRotp, - xRotp, xp, yp, zp)); - } - if (e->GetType() == eTYPE_THROWNEXPBOTTLE) - { - return std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::THROWN_EXPBOTTLE, yRotp, xRotp, xp, - yp, zp) ); - } - if (e->GetType() == eTYPE_THROWNENDERPEARL) - { - return std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::THROWN_ENDERPEARL, yRotp, xRotp, xp, - yp, zp) ); - } - if (e->GetType() == eTYPE_EYEOFENDERSIGNAL) - { - return std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::EYEOFENDERSIGNAL, yRotp, xRotp, xp, - yp, zp) ); - } - if (e->GetType() == eTYPE_SMALL_FIREBALL) - { - std::shared_ptr fb = - std::dynamic_pointer_cast(e); - std::shared_ptr aep = NULL; - if (fb->owner != NULL) - { - aep = std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::SMALL_FIREBALL, fb->owner->entityId, - yRotp, xRotp, xp, yp, zp) ); - } - else - { - aep = std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::SMALL_FIREBALL, 0, yRotp, xRotp, xp, - yp, zp) ); - } - aep->xa = (int) (fb->xPower * 8000); - aep->ya = (int) (fb->yPower * 8000); - aep->za = (int) (fb->zPower * 8000); - return aep; - } - if (e->GetType() == eTYPE_FIREBALL) - { - std::shared_ptr fb = - std::dynamic_pointer_cast(e); std::shared_ptr - aep = NULL; if (fb->owner != NULL) - { - aep = std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::FIREBALL, fb->owner->entityId, yRotp, - xRotp, xp, yp, zp) ); - } - else - { - aep = std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::FIREBALL, 0, yRotp, xRotp, xp, yp, - zp) ); - } - aep->xa = (int) (fb->xPower * 8000); - aep->ya = (int) (fb->yPower * 8000); - aep->za = (int) (fb->zPower * 8000); - return aep; - } - if (e->GetType() == eTYPE_THROWNEGG) - { - return std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::EGG, yRotp, xRotp, xp, yp, zp) ); - } - if (e->GetType() == eTYPE_PRIMEDTNT) - { - return std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::PRIMED_TNT, yRotp, xRotp, xp, yp, zp) ); - } - if (e->GetType() == eTYPE_ENDER_CRYSTAL) - { - return std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::ENDER_CRYSTAL, yRotp, xRotp, xp, yp, - zp) ); - } - if (e->GetType() == eTYPE_FALLINGTILE) - { - std::shared_ptr ft = - std::dynamic_pointer_cast(e); if (ft->tile == Tile::sand_Id) - return std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::FALLING_SAND, yRotp, xRotp, xp, yp, zp) ); if (ft->tile - == Tile::gravel_Id) return std::shared_ptr( new - AddEntityPacket(e, AddEntityPacket::FALLING_GRAVEL, yRotp, xRotp, xp, yp, - zp) ); if (ft->tile == Tile::dragonEgg_Id) return - std::shared_ptr( new AddEntityPacket(e, - AddEntityPacket::FALLING_EGG, yRotp, xRotp, xp, yp, zp) ); - } - if (e->GetType() == eTYPE_PAINTING) - { - return std::shared_ptr( new - AddPaintingPacket(std::dynamic_pointer_cast(e)) ); - } - if (e->GetType() == eTYPE_ITEM_FRAME) - { - std::shared_ptr frame = - std::dynamic_pointer_cast(e); - { - - int ix= (int)frame->xTile; - int iy= (int)frame->yTile; - int iz= (int)frame->zTile; - app.DebugPrintf("eTYPE_ITEM_FRAME xyz %d,%d,%d\n",ix,iy,iz); - } - - std::shared_ptr packet = - std::shared_ptr(new AddEntityPacket(e, - AddEntityPacket::ITEM_FRAME, frame->dir, yRotp, xRotp, xp, yp, zp)); - packet->x = Mth::floor(frame->xTile * 32.0f); - packet->y = Mth::floor(frame->yTile * 32.0f); - packet->z = Mth::floor(frame->zTile * 32.0f); - return packet; - } - if (e->GetType() == eTYPE_EXPERIENCEORB) - { - return std::shared_ptr( new - AddExperienceOrbPacket(std::dynamic_pointer_cast(e)) ); - } - assert(false); - */ return nullptr; } diff --git a/Minecraft.Client/Player/TrackedEntity.h b/Minecraft.Client/Player/TrackedEntity.h index 4a879eb03..02db083b7 100644 --- a/Minecraft.Client/Player/TrackedEntity.h +++ b/Minecraft.Client/Player/TrackedEntity.h @@ -25,7 +25,8 @@ private: bool updatedPlayerVisibility; bool trackDelta; int teleportDelay; - std::shared_ptr wasRiding; + std::shared_ptr lastRidingEntity; + bool wasRiding; public: bool moved; @@ -39,6 +40,11 @@ public: void tick(EntityTracker* tracker, std::vector >* players); + +private: + void sendDirtyEntityData(); + +public: void broadcast(std::shared_ptr packet); void broadcastAndSend(std::shared_ptr packet); void broadcastRemoved(); diff --git a/Minecraft.Client/Player/User.cpp b/Minecraft.Client/Player/User.cpp index 3c5ac9fe0..6d0c21bfd 100644 --- a/Minecraft.Client/Player/User.cpp +++ b/Minecraft.Client/Player/User.cpp @@ -5,8 +5,8 @@ std::vector User::allowedTiles; void User::staticCtor() { - allowedTiles.push_back(Tile::rock); - allowedTiles.push_back(Tile::stoneBrick); + allowedTiles.push_back(Tile::stone); + allowedTiles.push_back(Tile::cobblestone); allowedTiles.push_back(Tile::redBrick); allowedTiles.push_back(Tile::dirt); allowedTiles.push_back(Tile::wood); @@ -16,17 +16,17 @@ void User::staticCtor() { allowedTiles.push_back(Tile::stoneSlabHalf); allowedTiles.push_back(Tile::glass); - allowedTiles.push_back(Tile::mossStone); + allowedTiles.push_back(Tile::mossyCobblestone); allowedTiles.push_back(Tile::sapling); allowedTiles.push_back(Tile::flower); allowedTiles.push_back(Tile::rose); - allowedTiles.push_back(Tile::mushroom1); - allowedTiles.push_back(Tile::mushroom2); + allowedTiles.push_back(Tile::mushroom_brown); + allowedTiles.push_back(Tile::mushroom_red); allowedTiles.push_back(Tile::sand); allowedTiles.push_back(Tile::gravel); allowedTiles.push_back(Tile::sponge); - allowedTiles.push_back(Tile::cloth); + allowedTiles.push_back(Tile::wool); allowedTiles.push_back(Tile::coalOre); allowedTiles.push_back(Tile::ironOre); allowedTiles.push_back(Tile::goldOre);