diff --git a/Minecraft.Client/LevelRenderer.cpp b/Minecraft.Client/LevelRenderer.cpp index 645b740d..a7578092 100644 --- a/Minecraft.Client/LevelRenderer.cpp +++ b/Minecraft.Client/LevelRenderer.cpp @@ -3185,6 +3185,11 @@ shared_ptr LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticle int id = PARTICLE_CRACK_ID(eParticleType), data = PARTICLE_CRACK_DATA(eParticleType); particle = std::make_shared(lev, x, y, z, xa, ya, za, Item::items[id], textures, data); } + else if( ( eParticleType >= eParticleType_blockdust_base ) && ( eParticleType <= eParticleType_blockdust_last ) ) + { + int id = PARTICLE_CRACK_ID(eParticleType), data = PARTICLE_CRACK_DATA(eParticleType); + particle = dynamic_pointer_cast(std::make_shared(lev, x, y, z, xa, ya, za, Tile::tiles[id], 0, data, textures, false)->init(data) ); + } else if( ( eParticleType >= eParticleType_tilecrack_base ) && ( eParticleType <= eParticleType_tilecrack_last ) ) { int id = PARTICLE_CRACK_ID(eParticleType), data = PARTICLE_CRACK_DATA(eParticleType); diff --git a/Minecraft.Client/Particle.cpp b/Minecraft.Client/Particle.cpp index 4d4b4654..23d44f90 100644 --- a/Minecraft.Client/Particle.cpp +++ b/Minecraft.Client/Particle.cpp @@ -98,7 +98,7 @@ Particle::Particle(Level *level, double x, double y, double z) : Entity(nullptr, } } -Particle::Particle(Level *level, double x, double y, double z, double xa, double ya, double za) : Entity(nullptr, false) +Particle::Particle(Level *level, double x, double y, double z, double xa, double ya, double za, bool useRandomizedLogic) : Entity(nullptr, false) { _init(level,x,y,z); @@ -113,15 +113,28 @@ Particle::Particle(Level *level, double x, double y, double z, double xa, double this->level = nullptr; } - xd = xa + static_cast(Math::random() * 2 - 1) * 0.4f; - yd = ya + static_cast(Math::random() * 2 - 1) * 0.4f; - zd = za + static_cast(Math::random() * 2 - 1) * 0.4f; - float speed = static_cast(Math::random() + Math::random() + 1) * 0.15f; + if (useRandomizedLogic) { + xd = xa + static_cast(Math::random() * 2 - 1) * 0.4f; + yd = ya + static_cast(Math::random() * 2 - 1) * 0.4f; + zd = za + static_cast(Math::random() * 2 - 1) * 0.4f; + float speed = static_cast(Math::random() + Math::random() + 1) * 0.15f; - float dd = (float) (Mth::sqrt(xd * xd + yd * yd + zd * zd)); - xd = xd / dd * speed * 0.4f; - yd = yd / dd * speed * 0.4f + 0.1f; - zd = zd / dd * speed * 0.4f;} + float dd = (float) (Mth::sqrt(xd * xd + yd * yd + zd * zd)); + xd = xd / dd * speed * 0.4f; + yd = yd / dd * speed * 0.4f + 0.1f; + zd = zd / dd * speed * 0.4f; + } + else { + xd = xa; + yd = ya; + zd = za; + } +} + + +Particle::Particle(Level *level, double x, double y, double z, double xa, double ya, double za) : Particle(level, x, y, z, xa, ya, za, true) +{ +} shared_ptr Particle::setPower(float power) { diff --git a/Minecraft.Client/Particle.h b/Minecraft.Client/Particle.h index 2bfcf2a4..2c6260dc 100644 --- a/Minecraft.Client/Particle.h +++ b/Minecraft.Client/Particle.h @@ -28,6 +28,7 @@ protected: Particle(Level *level, double x, double y, double z); public: Particle(Level *level, double x, double y, double z, double xa, double ya, double za); + Particle(Level *level, double x, double y, double z, double xa, double ya, double za, bool useRandomizedLogic); virtual shared_ptr setPower(float power); virtual shared_ptr scale(float scale); void setColor(float r, float g, float b); diff --git a/Minecraft.Client/ParticleType.cpp b/Minecraft.Client/ParticleType.cpp index 30dc0721..8c03d672 100644 --- a/Minecraft.Client/ParticleType.cpp +++ b/Minecraft.Client/ParticleType.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" +#include #include "ParticleType.h" ParticleType::ParticleType(const std::string& name, int id, bool overrideLimiter, int paramCount) @@ -10,6 +11,19 @@ ParticleType::ParticleType(const std::string& name, int id, bool overrideLimiter this->paramCount = paramCount; } +const ParticleType* ParticleType::blockdust = new ParticleType("blockdust_", 0x29, false, 1); +const ParticleType* ParticleType::blockcrack = new ParticleType("blockcrack_", 0x28, false, 2); + +static std::unordered_map& particleRegistry() +{ + static std::unordered_map registry = { + { ParticleType::blockdust->getId(), ParticleType::blockdust }, + { ParticleType::blockcrack->getId(), ParticleType::blockcrack }, + }; + return registry; +} + + int ParticleType::getId() const { return id; @@ -34,6 +48,7 @@ const ParticleType* ParticleType::getDefault() const ParticleType* ParticleType::byId(int searchId) { - - return nullptr; + auto& reg = particleRegistry(); + auto it = reg.find(searchId); + return (it != reg.end()) ? it->second : nullptr; } \ No newline at end of file diff --git a/Minecraft.Client/ParticleType.h b/Minecraft.Client/ParticleType.h index 7b3459f9..735a9930 100644 --- a/Minecraft.Client/ParticleType.h +++ b/Minecraft.Client/ParticleType.h @@ -20,4 +20,7 @@ public: static const ParticleType* byId(int id); static const ParticleType* getDefault(); + + static const ParticleType* blockdust; + static const ParticleType* blockcrack; }; \ No newline at end of file diff --git a/Minecraft.Client/ServerLevel.cpp b/Minecraft.Client/ServerLevel.cpp index 5aab82f6..6fda30b8 100644 --- a/Minecraft.Client/ServerLevel.cpp +++ b/Minecraft.Client/ServerLevel.cpp @@ -1683,11 +1683,22 @@ void ServerLevel::flagEntitiesToBeRemoved(unsigned int *flags, bool *removedFoun } void ServerLevel::sendParticles(const ParticleType* type, bool longDistance, double x, double y, double z, int count, double dx, double dy, double dz, double speed, arrayWithLength data) { - wchar_t buf[32]; - swprintf_s(buf, L"%d", type->getId()); + wstring particleName; + if (type != nullptr && type->getId() == ParticleType::blockdust->getId() && data.length > 0) + { + int tileId = data[0] & Tile::TILE_NUM_MASK; + int tileData = (data[0] >> Tile::TILE_NUM_SHIFT) & 0xFF; + particleName = std::to_wstring(PARTICLE_BLOCKDUST(tileId, tileData)); + } + else + { + wchar_t buf[32]; + swprintf_s(buf, L"%d", type != nullptr ? type->getId() : 0); + particleName = buf; + } auto packet = make_shared( - buf, + particleName, (float)x, (float)y, (float)z, (float)dx, (float)dy, (float)dz, (float)speed, diff --git a/Minecraft.Client/TerrainParticle.cpp b/Minecraft.Client/TerrainParticle.cpp index ef10f8f9..c1fc7973 100644 --- a/Minecraft.Client/TerrainParticle.cpp +++ b/Minecraft.Client/TerrainParticle.cpp @@ -5,7 +5,11 @@ #include "../Minecraft.World/net.minecraft.world.level.h" #include "../Minecraft.World/net.minecraft.world.h" -TerrainParticle::TerrainParticle(Level *level, double x, double y, double z, double xa, double ya, double za, Tile *tile, int face, int data, Textures *textures) : Particle(level, x, y, z, xa, ya, za) +TerrainParticle::TerrainParticle(Level *level, double x, double y, double z, double xa, double ya, double za, Tile *tile, int face, int data, Textures *textures) : TerrainParticle(level, x, y, z, xa, ya, za, tile, face, data, textures, true) +{ +} + +TerrainParticle::TerrainParticle(Level *level, double x, double y, double z, double xa, double ya, double za, Tile *tile, int face, int data, Textures *textures, bool useRandomizedLogic) : Particle(level, x, y, z, xa, ya, za, useRandomizedLogic) { this->tile = tile; if (tile == nullptr) return; // tu31 tutorial world fix diff --git a/Minecraft.Client/TerrainParticle.h b/Minecraft.Client/TerrainParticle.h index 5d4a743f..aa79fac8 100644 --- a/Minecraft.Client/TerrainParticle.h +++ b/Minecraft.Client/TerrainParticle.h @@ -11,6 +11,7 @@ private: public: TerrainParticle(Level *level, double x, double y, double z, double xa, double ya, double za, Tile *tile, int face, int data, Textures *textures); + TerrainParticle(Level *level, double x, double y, double z, double xa, double ya, double za, Tile *tile, int face, int data, Textures *textures, bool useRandomizedLogic); shared_ptr init(int x, int y, int z, int data); // 4J - added data parameter shared_ptr init(int data); virtual int getParticleTexture(); diff --git a/Minecraft.World/LivingEntity.cpp b/Minecraft.World/LivingEntity.cpp index d5f2dda9..2d6f1210 100644 --- a/Minecraft.World/LivingEntity.cpp +++ b/Minecraft.World/LivingEntity.cpp @@ -160,44 +160,77 @@ void LivingEntity::registerAttributes() void LivingEntity::checkFallDamage(double ya, bool onGround) { - if (!isInWater()) - { - // double-check if we've reached water in this move tick - updateInWaterState(); - } + if (!isInWater()) + { + // double-check if we've reached water in this move tick + updateInWaterState(); + } - if (onGround) - { - // TODO: LANDING PARTICLES HERE - int xt = Mth::floor(x); - int yt = Mth::floor(y - 0.2f - heightOffset); - int zt = Mth::floor(z); - int t = level->getTile(xt, yt, zt); - if (t == 0) - { - int renderShape = level->getTileRenderShape(xt, yt - 1, zt); - if (renderShape == Tile::SHAPE_FENCE || renderShape == Tile::SHAPE_WALL || renderShape == Tile::SHAPE_FENCE_GATE) - { - t = level->getTile(xt, yt - 1, zt); - } - } + if (onGround) + { + int xt = Mth::floor(x); + int yt = Mth::floor(y - 0.2f - heightOffset); + int zt = Mth::floor(z); + int t = level->getTile(xt, yt, zt); + if (t == 0) + { + int renderShape = level->getTileRenderShape(xt, yt - 1, zt); + if (renderShape == Tile::SHAPE_FENCE || renderShape == Tile::SHAPE_WALL || renderShape == Tile::SHAPE_FENCE_GATE) + { + t = level->getTile(xt, yt - 1, zt); + } + } - Tile *tile = Tile::tiles[t]; - if (t > 0 && tile != nullptr) // tu31 tutorial world fix - { - if (fallDistance > 0 || t == Tile::slimeBlock->id) - { - auto ent = shared_from_this(); - Tile::tiles[t]->fallOn(level, xt, yt, zt, ent, fallDistance); - if (t == Tile::slimeBlock->id && !isSneaking()) - { - m_clearFallDamageThisTick = true; - } - } - } - } + Tile *tile = Tile::tiles[t]; + if (t > 0 && tile != nullptr) // tu31 tutorial world fix + { + if (fallDistance > 0 || t == Tile::slimeBlock->id) + { + auto ent = shared_from_this(); + Tile::tiles[t]->fallOn(level, xt, yt, zt, ent, fallDistance); + if (t == Tile::slimeBlock->id && !isSneaking()) + { + m_clearFallDamageThisTick = true; + } + } + } - Entity::checkFallDamage(ya, onGround); + // landing particles + if (!level->isClientSide && fallDistance > 3.0f) + { + Material* material = level->getMaterial(xt, yt, zt); + if (material != Material::air) + { + float adjusted = ceilf(fallDistance - 3.0f); + float scaled = (adjusted / 15.0f) + 0.2f; + + float speed = 10.0f; + if (scaled < 10.0f) speed = scaled; + if (speed > 2.5f) speed = 2.5f; + + int particleCount = (int)(speed * 150.0f); + int blockIdWithData = t | (level->getData(xt, yt, zt) << Tile::TILE_NUM_SHIFT); + arrayWithLength extraData(1, false); + extraData[0] = blockIdWithData; + ServerLevel *serverLevel = dynamic_cast(level); + + if (serverLevel != nullptr) + { + serverLevel->sendParticles( + ParticleType::blockdust, + false, + x, y, z, + particleCount, + 0, 0, 0, + 0.15, + extraData + ); + } + } + } + } + + Entity::checkFallDamage(ya, onGround); } bool LivingEntity::isWaterMob() diff --git a/Minecraft.World/LootTableManager.cpp b/Minecraft.World/LootTableManager.cpp index c9d008f6..2554cc03 100644 --- a/Minecraft.World/LootTableManager.cpp +++ b/Minecraft.World/LootTableManager.cpp @@ -1086,7 +1086,8 @@ std::vector LootTableManager::ResolveDrops( } else if (functionIt->functionName == "enchant_randomly") { - LootLog("[LootDbg] enchant_randomly -> deferred to enchantment system\n"); + result.enchantLevels = 1 + randomInt(30); + LootLog("[LootDbg] enchant_randomly -> levels=%d\n", result.enchantLevels); } } diff --git a/Minecraft.World/ParticleTypes.h b/Minecraft.World/ParticleTypes.h index 130d5cdb..4d3e939f 100644 --- a/Minecraft.World/ParticleTypes.h +++ b/Minecraft.World/ParticleTypes.h @@ -49,13 +49,16 @@ enum ePARTICLE_TYPE eParticleType_iconcrack_last = 0x1FFFFF, eParticleType_tilecrack_base = 0x200000, // There's a range of tilecrack particle types based on tile id and data. eParticleType_tilecrack_last = 0x2FFFFF, - // 0x0000FF, <- these bits are for storing the data value. - // 0x0FFF00, <- these bits are for encoding tile/item id. - // 0x300000, <- these bits show if its an icon/tile or not. + eParticleType_blockdust_base = 0x300000, + eParticleType_blockdust_last = 0x3FFFFF, + // 0x0000FF, <- these bits are for storing the data value. + // 0x0FFF00, <- these bits are for encoding tile/item id. + // 0x300000, <- these bits show if its an icon/tile or not. }; #define PARTICLE_TILECRACK(id,data) ( (ePARTICLE_TYPE) ( ((int) eParticleType_tilecrack_base) | ((0x0FFF & id) << 8) | (0x0FF & data)) ) +#define PARTICLE_BLOCKDUST(id,data) ( (ePARTICLE_TYPE) ( ((int) eParticleType_blockdust_base) | ((0x0FFF & id) << 8) | (0x0FF & data)) ) #define PARTICLE_ICONCRACK(id,data) ( (ePARTICLE_TYPE) ( ((int) eParticleType_iconcrack_base) | ((0x0FFF & id) << 8) | (0x0FF & data)) ) #define PARTICLE_CRACK_ID(ePType) ((0x0FFF00 & (int)ePType) >> 8)