diff --git a/Minecraft.Client/LocalPlayer.cpp b/Minecraft.Client/LocalPlayer.cpp index 799103a3..7bef68cf 100644 --- a/Minecraft.Client/LocalPlayer.cpp +++ b/Minecraft.Client/LocalPlayer.cpp @@ -532,6 +532,8 @@ void LocalPlayer::aiStep() onGround = true; } + /* + if (isAlive()) { int frostWalkerLevel = EnchantmentHelper::getFrostWalker(dynamic_pointer_cast(shared_from_this())); @@ -542,6 +544,8 @@ void LocalPlayer::aiStep() } } + */ + // Check if the player is idle and the rich presence needs updated if( !m_bIsIdle && InputManager.GetIdleSeconds( m_iPad ) > PLAYER_IDLE_TIME ) { diff --git a/Minecraft.Client/ServerPlayer.cpp b/Minecraft.Client/ServerPlayer.cpp index f8c7ac9c..1da68599 100644 --- a/Minecraft.Client/ServerPlayer.cpp +++ b/Minecraft.Client/ServerPlayer.cpp @@ -390,6 +390,14 @@ float ServerPlayer::getHeadHeight() return 1.62f; } +void ServerPlayer::onChangedBlock(BlockPos pos) +{ + if (true /*!isSpectator()*/) // we dont have true spectator mode yet + { + LivingEntity::onChangedBlock(pos); + } +} + void ServerPlayer::tick() { gameMode->tick(); diff --git a/Minecraft.Client/ServerPlayer.h b/Minecraft.Client/ServerPlayer.h index b759cd52..92dbd8f9 100644 --- a/Minecraft.Client/ServerPlayer.h +++ b/Minecraft.Client/ServerPlayer.h @@ -9,6 +9,7 @@ class Level; class Stat; class TileEntity; class Entity; +class BlockPos; class BrewingStandTileEntity; class HopperTileEntity; class MinecartHopper; @@ -63,6 +64,7 @@ public: virtual float getHeadHeight(); virtual void tick(); void flushEntitiesToRemove(); + void onChangedBlock(BlockPos pos); virtual shared_ptr getCarried(int slot); virtual void die(DamageSource *source); virtual bool hurt(DamageSource *dmgSource, float dmg); diff --git a/Minecraft.World/Enchantment.cpp b/Minecraft.World/Enchantment.cpp index 3d3a94e1..9713f955 100644 --- a/Minecraft.World/Enchantment.cpp +++ b/Minecraft.World/Enchantment.cpp @@ -94,7 +94,7 @@ void Enchantment::staticCtor() for(unsigned int i = 0; i < 256; ++i) { Enchantment *enchantment = enchantments[i]; - if (enchantment != nullptr && !enchantment->isTreasureEnchantment()) + if (enchantment != nullptr && !enchantment->isTreasureOnly()) { validEnchantments.push_back(enchantment); } diff --git a/Minecraft.World/Enchantment.h b/Minecraft.World/Enchantment.h index e7d4f658..fa3ad5a9 100644 --- a/Minecraft.World/Enchantment.h +++ b/Minecraft.World/Enchantment.h @@ -85,9 +85,9 @@ public: virtual int getDamageProtection(int level, DamageSource *source); virtual float getDamageBonus(int level, shared_ptr target); virtual bool isCompatibleWith(Enchantment *other) const; - virtual bool isTreasureEnchantment() const { return false; } virtual Enchantment *setDescriptionId(int id); virtual int getDescriptionId(); + virtual bool isTreasureOnly() { return false; } virtual HtmlString getFullname(int level); virtual bool canEnchant(shared_ptr item); // 4J Added diff --git a/Minecraft.World/EnchantmentHelper.cpp b/Minecraft.World/EnchantmentHelper.cpp index 0be92cbc..377ba592 100644 --- a/Minecraft.World/EnchantmentHelper.cpp +++ b/Minecraft.World/EnchantmentHelper.cpp @@ -481,6 +481,11 @@ unordered_map *EnchantmentHelper::getAvailableEnchan continue; } + if (e->isTreasureOnly()) + { + continue; + } + // Only picks "normal" enchantments, no specialcases if (!e->category->canEnchant(item) && !isBook) { diff --git a/Minecraft.World/EnchantmentHelper.h b/Minecraft.World/EnchantmentHelper.h index 57761d21..9891ca44 100644 --- a/Minecraft.World/EnchantmentHelper.h +++ b/Minecraft.World/EnchantmentHelper.h @@ -5,6 +5,7 @@ class Inventory; class DamageSource; class Enchantment; class EnchantmentInstance; +class LivingEntity; class EnchantmentHelper { @@ -50,6 +51,7 @@ private: */ public: static int getDamageProtection(ItemInstanceArray armor, DamageSource *source); + static bool hasFrostWalker(shared_ptr living); private: class GetDamageBonusIteration : public EnchantmentIterationMethod diff --git a/Minecraft.World/EnchantmentMenu.cpp b/Minecraft.World/EnchantmentMenu.cpp index 56505c00..0e23b458 100644 --- a/Minecraft.World/EnchantmentMenu.cpp +++ b/Minecraft.World/EnchantmentMenu.cpp @@ -98,9 +98,36 @@ vector EnchantmentMenu::getEnchantment() { void EnchantmentMenu::slotsChanged(int a) // 4J used to take a shared_ptr container but wasn't using it, so removed to simplify things { shared_ptr item = enchantSlots->getItem(0); - shared_ptr lapis = lapisSlot->getItem(1); + bool itemChanged = false; + if (item == nullptr || lastEnchantmentItem == nullptr) + { + itemChanged = (item == nullptr) != (lastEnchantmentItem == nullptr); + } + else if (item->id != lastEnchantmentItem->id || item->getDamageValue() != lastEnchantmentItem->getDamageValue()) + { + itemChanged = true; + } + + if (itemChanged) + { + alreadyRan = false; + for (int i = 0; i < 3; ++i) + { + if (cachedEnchantments[i] != nullptr) + { + for (EnchantmentInstance *cached : *cachedEnchantments[i]) + { + delete cached; + } + cachedEnchantments[i]->clear(); + delete cachedEnchantments[i]; + cachedEnchantments[i] = nullptr; + } + } + } + if (item == nullptr || !item->isEnchantable()) { if (!level->isClientSide) @@ -220,6 +247,7 @@ void EnchantmentMenu::slotsChanged(int a) // 4J used to take a shared_ptr player, int i) @@ -257,6 +285,7 @@ bool EnchantmentMenu::clickMenuButton(shared_ptr player, int i) delete e; } delete newEnchantment; + cachedEnchantments[i] = nullptr; slotsChanged(1);// Removed enchantSlots parameter as the function can reference it directly } } diff --git a/Minecraft.World/EnchantmentMenu.h b/Minecraft.World/EnchantmentMenu.h index 6b568b28..be57db5b 100644 --- a/Minecraft.World/EnchantmentMenu.h +++ b/Minecraft.World/EnchantmentMenu.h @@ -17,6 +17,7 @@ public: public: shared_ptr enchantSlots; shared_ptr lapisSlot; + shared_ptr lastEnchantmentItem; bool alreadyRan = false; bool en = false; // Header diff --git a/Minecraft.World/FrostWalkerEnchantment.cpp b/Minecraft.World/FrostWalkerEnchantment.cpp index f25b8363..9275db21 100644 --- a/Minecraft.World/FrostWalkerEnchantment.cpp +++ b/Minecraft.World/FrostWalkerEnchantment.cpp @@ -2,9 +2,12 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.player.h" #include "Material.h" #include "Mth.h" +#include "BlockPos.h" #include "FrostWalkerEnchantment.h" +#include "EnchantmentHelper.h" FrostWalkerEnchantment::FrostWalkerEnchantment(int id, int frequency) : Enchantment(id, frequency, EnchantmentCategory::armor_feet) { @@ -26,38 +29,56 @@ int FrostWalkerEnchantment::getMaxLevel() return 2; } -void FrostWalkerEnchantment::freezeNearby(shared_ptr living, Level *level, int px, int py, int pz, int enchLevel) +bool FrostWalkerEnchantment::isCompatibleWith(Enchantment *other) const +{ + if (!Enchantment::isCompatibleWith(other)) return false; + return other != Enchantment::waterWalker; +} + +bool EnchantmentHelper::hasFrostWalker(shared_ptr living) +{ + return getFrostWalker(living) != 0; +} + +void FrostWalkerEnchantment::onEntityMoved(shared_ptr living, Level *level, BlockPos pos, int enchLevel) { if (!living->onGround) return; - int radius = 2 + enchLevel; + Player *player = dynamic_cast(living.get()); + if (player != nullptr && player->abilities.flying) return; + + int radius = enchLevel + 2; if (radius > 16) radius = 16; - float f = (float)radius; - int r = radius; + float f = static_cast(radius); - for (int dx = -r; dx <= r; dx++) + BlockPos minPos = pos.offset(-radius, -1, -radius); + BlockPos maxPos = pos.offset(radius, -1, radius); + + for (int x = minPos.getX(); x <= maxPos.getX(); ++x) { - for (int dz = -r; dz <= r; dz++) + for (int y = minPos.getY(); y <= maxPos.getY(); ++y) { - int bx = px + dx; - int by = py - 1; - int bz = pz + dz; - - double ddx = (bx + 0.5) - living->x; - double ddy = (by + 0.5) - living->y; - double ddz = (bz + 0.5) - living->z; - if (ddx * ddx + ddy * ddy + ddz * ddz > (double)(f * f)) continue; - - if (level->getTile(bx, by + 1, bz) != 0) continue; - - Material *ground = level->getMaterial(bx, by, bz); - if (ground != Material::water) continue; - if (level->getData(bx, by, bz) != 0) continue; - - if (Tile::frosted_ice->mayPlace(level, bx, by, bz)) + for (int z = minPos.getZ(); z <= maxPos.getZ(); ++z) { - level->setTileAndData(bx, by, bz, Tile::frosted_ice_Id, 0, Tile::UPDATE_ALL); + double dx = (x + 0.5) - living->x; + double dy = (y + 0.5) - living->y; + double dz = (z + 0.5) - living->z; + if (dx * dx + dy * dy + dz * dz > static_cast(f * f)) continue; + + if (level->getTile(x, y + 1, z) != 0) continue; + + Material *ground = level->getMaterial(x, y, z); + if (ground != Material::water) continue; + if (level->getData(x, y, z) != 0) continue; + + bool canPlace = level->mayPlace(Tile::frosted_ice_Id, x, y, z, false, 0, nullptr, nullptr); + if (!canPlace) continue; + + level->setTileAndData(x, y, z, Tile::frosted_ice_Id, 0, Tile::UPDATE_ALL); + + int ticks = Mth::nextInt(living->getRandom(), 60, 120); + level->addToTickNextTick(x, y, z, Tile::frosted_ice_Id, ticks); } } } -} +} \ No newline at end of file diff --git a/Minecraft.World/FrostWalkerEnchantment.h b/Minecraft.World/FrostWalkerEnchantment.h index b8e5c0aa..b1c5386e 100644 --- a/Minecraft.World/FrostWalkerEnchantment.h +++ b/Minecraft.World/FrostWalkerEnchantment.h @@ -4,6 +4,7 @@ class Level; class LivingEntity; +class BlockPos; class FrostWalkerEnchantment : public Enchantment { @@ -13,7 +14,9 @@ public: virtual int getMinCost(int level) override; virtual int getMaxCost(int level) override; virtual int getMaxLevel() override; - virtual bool isTreasureEnchantment() const override { return true; } + virtual bool isCompatibleWith(Enchantment *other) const override; + virtual bool isTreasureOnly() override { return true; } - static void freezeNearby(shared_ptr living, Level *level, int px, int py, int pz, int enchLevel); + static void freezeNearby(shared_ptr living, Level *level, int x, int y, int z, int enchLevel); + static void onEntityMoved(shared_ptr living, Level *level, BlockPos pos, int enchLevel); }; diff --git a/Minecraft.World/LivingEntity.cpp b/Minecraft.World/LivingEntity.cpp index 0f20231f..798a45f7 100644 --- a/Minecraft.World/LivingEntity.cpp +++ b/Minecraft.World/LivingEntity.cpp @@ -33,6 +33,8 @@ #include "Dimension.h" #include "GenericStats.h" #include "ItemEntity.h" +#include "TilePos.h" + #if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) #include "../Minecraft.Server/FourKitBridge.h" #endif @@ -296,17 +298,7 @@ void LivingEntity::baseTick() tickEffects(); animStepO = animStep; - - if (!level->isClientSide && isAlive()) - { - int frostWalkerLevel = EnchantmentHelper::getFrostWalker(dynamic_pointer_cast(shared_from_this())); - if (frostWalkerLevel > 0) - { - FrostWalkerEnchantment::freezeNearby(dynamic_pointer_cast(shared_from_this()), level, - Mth::floor(x), Mth::floor(y), Mth::floor(z), frostWalkerLevel); - } - } - + yBodyRotO = yBodyRot; yHeadRotO = yHeadRot; yRotO = yRot; @@ -1075,6 +1067,21 @@ int LivingEntity::getDeathSound() return eSoundType_DAMAGE_HURT; } +// frost walker-specific + +void LivingEntity::onChangedBlock(BlockPos pos) +{ + shared_ptr self = dynamic_pointer_cast(shared_from_this()); + + int frostWalkerLevel = EnchantmentHelper::getEnchantmentLevel(Enchantment::frostWalker->id, getEquipmentSlots()); + if (frostWalkerLevel < 1) + { + return; + } + + FrostWalkerEnchantment::onEntityMoved(self, level, pos, frostWalkerLevel); +} + /** * Drop extra rare loot. Only occurs roughly 5% of the time, rareRootLevel * is set to 1 (otherwise 0) 1% of the time. diff --git a/Minecraft.World/LivingEntity.h b/Minecraft.World/LivingEntity.h index 6a3d6a50..f06329da 100644 --- a/Minecraft.World/LivingEntity.h +++ b/Minecraft.World/LivingEntity.h @@ -203,6 +203,7 @@ public: virtual bool onLadder(); virtual bool isShootable(); virtual bool isAlive(); + virtual void onChangedBlock(BlockPos pos); virtual void causeFallDamage(float distance); virtual void animateHurt(); virtual int getArmorValue(); diff --git a/Minecraft.World/MendingEnchantment.cpp b/Minecraft.World/MendingEnchantment.cpp index 856ee9a5..8ade6110 100644 --- a/Minecraft.World/MendingEnchantment.cpp +++ b/Minecraft.World/MendingEnchantment.cpp @@ -26,4 +26,4 @@ int MendingEnchantment::getMaxLevel() bool MendingEnchantment::canEnchant(shared_ptr item) { return item->isDamageableItem(); -} +} \ No newline at end of file diff --git a/Minecraft.World/MendingEnchantment.h b/Minecraft.World/MendingEnchantment.h index 3892bb40..d3dca04a 100644 --- a/Minecraft.World/MendingEnchantment.h +++ b/Minecraft.World/MendingEnchantment.h @@ -10,6 +10,6 @@ public: virtual int getMinCost(int level) override; virtual int getMaxCost(int level) override; virtual int getMaxLevel() override; - virtual bool isTreasureEnchantment() const override { return true; } + virtual bool isTreasureOnly() override { return true; }; virtual bool canEnchant(shared_ptr item) override; }; diff --git a/Minecraft.World/Player.cpp b/Minecraft.World/Player.cpp index b517ce8c..8644baa7 100644 --- a/Minecraft.World/Player.cpp +++ b/Minecraft.World/Player.cpp @@ -145,6 +145,7 @@ Player::Player(Level *level, const wstring &name) : LivingEntity( level ) Pos *spawnPos = level->getSharedSpawnPos(); moveTo(spawnPos->x + 0.5, spawnPos->y + 1, spawnPos->z + 0.5, 0, 0); delete spawnPos; + lastChangedBlockPos = BlockPos(x, y, z); rotOffs = 180; flameTime = 20; @@ -330,6 +331,13 @@ void Player::tick() LivingEntity::tick(); + BlockPos currentBlockPos(Mth::floor(x), Mth::floor(y), Mth::floor(z)); + if (currentBlockPos != lastChangedBlockPos) + { + lastChangedBlockPos = currentBlockPos; + onChangedBlock(currentBlockPos); + } + if (!level->isClientSide) { if (containerMenu != nullptr && !containerMenu->stillValid( dynamic_pointer_cast( shared_from_this() ) )) @@ -624,6 +632,14 @@ bool Player::isImmobile() return getHealth() <= 0 || isSleeping(); } +void Player::onChangedBlock(BlockPos pos) +{ + if (true /*!isSpectator()*/) // spectator is not a thing yet + { + LivingEntity::onChangedBlock(pos); + } +} + void Player::closeContainer() { containerMenu = inventoryMenu; diff --git a/Minecraft.World/Player.h b/Minecraft.World/Player.h index 482d2a1e..19bef7bd 100644 --- a/Minecraft.World/Player.h +++ b/Minecraft.World/Player.h @@ -8,6 +8,7 @@ using namespace std; #include "PlayerEnderChestContainer.h" #include "CommandSender.h" #include "ScoreHolder.h" +#include "BlockPos.h" class AbstractContainerMenu; class Stats; @@ -133,6 +134,7 @@ public: private: int sleepCounter; // animation timer int deathFadeCounter; // animation timer + BlockPos lastChangedBlockPos; public: float bedOffsetX, bedOffsetY, bedOffsetZ; @@ -207,6 +209,7 @@ protected: public: virtual void handleEntityEvent(byte id); + void onChangedBlock(BlockPos pos); protected: bool isImmobile();