diff --git a/.github/banner.png b/.github/banner.png index 88b2e310..e65ff3db 100644 Binary files a/.github/banner.png and b/.github/banner.png differ diff --git a/BUMP b/BUMP index ce96854b..8b7b705c 100644 --- a/BUMP +++ b/BUMP @@ -1 +1 @@ -1.0.7b +1.0.8b diff --git a/Minecraft.Client/ArmorStandModel.cpp b/Minecraft.Client/ArmorStandModel.cpp index c6349eb9..5232eb5c 100644 --- a/Minecraft.Client/ArmorStandModel.cpp +++ b/Minecraft.Client/ArmorStandModel.cpp @@ -8,7 +8,6 @@ ArmorStandModel::ArmorStandModel(float scale) : HumanoidModel(scale) { texWidth = 64; texHeight = 64; - head = new ModelPart(this, 0, 0); head->addBox(-1.0f, -7.0f, -1.0f, 2, 7, 2, scale); diff --git a/Minecraft.Client/ArmorStandRenderer.cpp b/Minecraft.Client/ArmorStandRenderer.cpp index 96337d92..15654c65 100644 --- a/Minecraft.Client/ArmorStandRenderer.cpp +++ b/Minecraft.Client/ArmorStandRenderer.cpp @@ -16,6 +16,7 @@ #include "PlayerRenderer.h" #include "../Minecraft.World/SkullItem.h" #include "../Minecraft.World/SkullTileEntity.h" +#include "../Minecraft.World/ElytraItem.h" static const float DEG_TO_RAD = 3.14159265f / 180.0f; @@ -84,9 +85,22 @@ void ArmorStandRenderer::render(shared_ptr entity, double x, double y, double z, float rot, float a) { + shared_ptr mob = dynamic_pointer_cast(entity); + + float brightness = SharedConstants::TEXTURE_LIGHTING ? 1 : mob->getBrightness(a); + glColor3f(brightness, brightness, brightness); + shared_ptr item = mob->getCarriedItem(); + + prepareCarriedItem(mob, item); + LivingEntityRenderer::render(entity, x, y, z, rot, a); } +void ArmorStandRenderer::prepareCarriedItem(shared_ptr mob, shared_ptr item) +{ + armorLayer->armorModel1->holdingRightHand = armorLayer->armorModel2->holdingRightHand = item != nullptr ? 1 : 0; +} + void ArmorStandRenderer::renderModel(shared_ptr mob, float wp, float ws, float bob, float headRotMinusBodyRot, @@ -165,7 +179,109 @@ void ArmorStandRenderer::renderModel(shared_ptr mob, void ArmorStandRenderer::additionalRendering(shared_ptr mob, float a) { - + + { + shared_ptr chestItem = mob->getEquipmentSlots()[ArmorStand::SLOT_CHEST]; + if (chestItem != nullptr && dynamic_cast(chestItem->getItem()) != nullptr) + { + static ResourceLocation elytraTexture(L"item/elytra.png"); + bindTexture(&elytraTexture); + + float brightness2 = SharedConstants::TEXTURE_LIGHTING ? 1 : mob->getBrightness(a); + glColor3f(brightness2, brightness2, brightness2); + + ArmorStandModel* standModel = ((ArmorStandModel*)this->model); + ArmorStand* stand = dynamic_cast(mob.get()); + + float wf = 0.2617994f; + float wf1 = -0.2617994f; + float wf2 = standModel->body->y; + float wf3 = 0.0f; + + stand->rotateElytraX += (wf - stand->rotateElytraX) * 0.3f; + stand->rotateElytraY += (wf3 - stand->rotateElytraY) * 0.3f; + stand->rotateElytraZ += (wf1 - stand->rotateElytraZ) * 0.3f; + + + standModel->elytraRight->y = wf2; + standModel->elytraRight->xRot = stand->rotateElytraX; + standModel->elytraRight->yRot = stand->rotateElytraY; + standModel->elytraRight->zRot = stand->rotateElytraZ; + + standModel->elytraLeft->y = wf2; + standModel->elytraLeft->xRot = stand->rotateElytraX; + standModel->elytraLeft->yRot = -stand->rotateElytraY; + standModel->elytraLeft->zRot = -stand->rotateElytraZ; + + glPushMatrix(); + glTranslatef(0, 0.0f, (2.0f + 0.125f) / 16.0f); + standModel->renderElytra(1 / 16.0f, true); + glPopMatrix(); + } + } + + std::shared_ptr item = mob->getCarriedItem(); + if (item != nullptr) + { + glPushMatrix(); + + ArmorStandModel* standModel = ((ArmorStandModel*)model); + + if (standModel->young) { + float s = 0.5f; + glTranslatef(0 / 16.0f, 10 / 16.0f, 0 / 16.0f); + glRotatef(-20, -1, 0, 0); + glScalef(s, s, s); + } + + + standModel->arm1->translateTo(1 / 16.0f); + glTranslatef(-1 / 16.0f, 7 / 16.0f, 1 / 16.0f); + + if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape()) && item->id != Tile::barrier_Id) + { + float s = 8 / 16.0f; + glTranslatef(-0 / 16.0f, 3 / 16.0f, -5 / 16.0f); + s *= 0.75f; + glRotatef(20, 1, 0, 0); + glRotatef(45, 0, 1, 0); + glScalef(-s, -s, s); + } + else if (item->id == Item::bow_Id) + { + float s = 10 / 16.0f; + glTranslatef(0 / 16.0f, 2 / 16.0f, 5 / 16.0f); + glRotatef(-20, 0, 1, 0); + glScalef(s, -s, s); + glRotatef(-100, 1, 0, 0); + glRotatef(45, 0, 1, 0); + } + else if (Item::items[item->id]->isHandEquipped()) + { + float s = 10 / 16.0f; + glTranslatef(0, 3 / 16.0f, 0); + glScalef(s, -s, s); + glRotatef(-100, 1, 0, 0); + glRotatef(45, 0, 1, 0); + } + else + { + float s = 6 / 16.0f; + glTranslatef(+4 / 16.0f, +3 / 16.0f, -3 / 16.0f); + glScalef(s, s, s); + glRotatef(60, 0, 0, 1); + glRotatef(-90, 1, 0, 0); + glRotatef(20, 0, 0, 1); + } + + this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, 0); + if (item->getItem()->hasMultipleSpriteLayers()) + { + this->entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item, 1); + } + + glPopMatrix(); + } } diff --git a/Minecraft.Client/ArmorStandRenderer.h b/Minecraft.Client/ArmorStandRenderer.h index 9742f31e..9eda1077 100644 --- a/Minecraft.Client/ArmorStandRenderer.h +++ b/Minecraft.Client/ArmorStandRenderer.h @@ -47,5 +47,7 @@ public: float headRotMinusBodyRot, float headRotx, float scale) override; virtual int prepareArmor(shared_ptr mob, int layer, float a) override; + void prepareCarriedItem(shared_ptr mob, shared_ptr item); + virtual void additionalRendering(shared_ptr mob, float a) override; }; \ No newline at end of file diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index 2965a182..e6c8b891 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -4328,22 +4328,19 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr void ClientConnection::handleParticleEvent(shared_ptr packet) { - const ParticleType* type = packet->getType(); - if (type == nullptr) return; + ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)Integer::parseInt(packet->getName()); - ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)type->getId(); + for (int i = 0; i < packet->getCount(); i++) + { + double xVarience = random->nextGaussian() * packet->getXDist(); + double yVarience = random->nextGaussian() * packet->getYDist(); + double zVarience = random->nextGaussian() * packet->getZDist(); + double xa = random->nextGaussian() * packet->getMaxSpeed(); + double ya = random->nextGaussian() * packet->getMaxSpeed(); + double za = random->nextGaussian() * packet->getMaxSpeed(); - for (int i = 0; i < packet->getCount(); i++) - { - double xVarience = random->nextGaussian() * packet->getXDist(); - double yVarience = random->nextGaussian() * packet->getYDist(); - double zVarience = random->nextGaussian() * packet->getZDist(); - double xa = random->nextGaussian() * packet->getMaxSpeed(); - double ya = random->nextGaussian() * packet->getMaxSpeed(); - double za = random->nextGaussian() * packet->getMaxSpeed(); - - level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za); - } + level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za); + } } void ClientConnection::handleUpdateAttributes(shared_ptr packet) diff --git a/Minecraft.Client/Common/Media/MediaWindows64/skinHDWin.swf b/Minecraft.Client/Common/Media/MediaWindows64/skinHDWin.swf index cd0618b3..cd426fa6 100644 Binary files a/Minecraft.Client/Common/Media/MediaWindows64/skinHDWin.swf and b/Minecraft.Client/Common/Media/MediaWindows64/skinHDWin.swf differ diff --git a/Minecraft.Client/Common/Media/MediaWindows64/skinWin.swf b/Minecraft.Client/Common/Media/MediaWindows64/skinWin.swf index 4a788aa8..ed8fe774 100644 Binary files a/Minecraft.Client/Common/Media/MediaWindows64/skinWin.swf and b/Minecraft.Client/Common/Media/MediaWindows64/skinWin.swf differ diff --git a/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine_rough.png b/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine.png similarity index 100% rename from Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine_rough.png rename to Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine.png diff --git a/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine_rough.txt b/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine.txt similarity index 100% rename from Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine_rough.txt rename to Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/prismarine.txt diff --git a/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/sea_lantern.png b/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/sea_lantern.png index 4f08fd2d..1ac866da 100644 Binary files a/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/sea_lantern.png and b/Minecraft.Client/Common/res/TitleUpdate/res/textures/blocks/sea_lantern.png differ diff --git a/Minecraft.Client/CustomHeadLayer.cpp b/Minecraft.Client/CustomHeadLayer.cpp index 72f9955a..44c062c2 100644 --- a/Minecraft.Client/CustomHeadLayer.cpp +++ b/Minecraft.Client/CustomHeadLayer.cpp @@ -13,11 +13,19 @@ #include "../Minecraft.World/SkullTileEntity.h" #include "../Minecraft.World/LivingEntity.h" #include "../Minecraft.World/Facing.h" +#include "../Minecraft.Client/SimpleIcon.h" +#include "../Minecraft.World/AirTile.h" CustomHeadLayer::CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer) : headPart(headPart), parentRenderer(parentRenderer) { + tileRenderer = new TileRenderer(); + +} + +CustomHeadLayer::~CustomHeadLayer() { + delete tileRenderer; } int CustomHeadLayer::colorsOnDamage() @@ -90,12 +98,136 @@ void CustomHeadLayer::render(shared_ptr mob, glRotatef(90.0f, 0.0f, 1.0f, 0.0f); - Minecraft* mc = Minecraft::GetInstance(); - if (mc) { - auto* iihr = mc->getItemInHandRenderer(); - if (iihr) - iihr->renderItem(mob, helmet, 0, true); + // 4J - code borrowed from render method below, although not factoring in brightness as that should already be being taken into account + // by texture lighting. This is for colourising things held in 3rd person view. + if ((item != nullptr)) { + int col = Item::items[item->id]->getColor(helmet, 0); + float red = ((col >> 16) & 0xff) / 255.0f; + float g = ((col >> 8) & 0xff) / 255.0f; + float b = ((col) & 0xff) / 255.0f; + + glColor4f(red, g, b, 1); + } + + Minecraft* minecraft = Minecraft::GetInstance(); + + glPushMatrix(); + + Tile* tile = Tile::tiles[item->id]; + if ((item->getIconType() == Icon::TYPE_TERRAIN && tile != nullptr && TileRenderer::canRender(tile->getRenderShape())) && item->id != AirTile::barrier_Id) + { + MemSect(31); + minecraft->textures->bindTexture(minecraft->textures->getTextureLocation(Icon::TYPE_TERRAIN)); + MemSect(0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + tileRenderer->renderTile(Tile::tiles[item->id], helmet->getAuxValue(), SharedConstants::TEXTURE_LIGHTING ? 1.0f : mob->getBrightness(1)); // 4J - change brought forward from 1.8.2 + glDisable(GL_BLEND); + } + else + { + MemSect(31); + Icon* icon = mob->getItemInHandIcon(helmet, 0); + if (icon == nullptr) + { + glPopMatrix(); + MemSect(0); + return; + } + + bool bIsTerrain = item->getIconType() == Icon::TYPE_TERRAIN; + minecraft->textures->bindTexture(minecraft->textures->getTextureLocation(item->getIconType())); + + MemSect(0); + Tesselator* t = Tesselator::getInstance(); + + // Consider forcing the mipmap LOD level to use, if this is to be rendered from a larger than standard source texture. + int iconWidth = icon->getWidth(); + int LOD = -1; // Default to not doing anything special with LOD forcing + if (iconWidth == 32) + { + LOD = 1; // Force LOD level 1 to achieve texture reads from 256x256 map + } + else if (iconWidth == 64) + { + LOD = 2; // Force LOD level 2 to achieve texture reads from 256x256 map + } + RenderManager.StateSetForceLOD(LOD); + + // 4J Original comment + // Yes, these are backwards. + // No, I don't know why. + // 4J Stu - Make them the right way round...u coords were swapped + float u0 = icon->getU0(); + float u1 = icon->getU1(); + float v0 = icon->getV0(); + float v1 = icon->getV1(); + + float xo = 0.0f; + float yo = 0.3f; + + // Re position height of held item if skin is small + if (mob->getAnimOverrideBitmask() & (1 << HumanoidModel::eAnim_SmallModel)) + { + if (mob->isRiding()) + { + std::shared_ptr ridingEntity = mob->riding; + if (ridingEntity != nullptr) // Safety check; + { + yo += 0.3f; // reverts the change in Boat.cpp for smaller models. + } + } + } + + glEnable(GL_RESCALE_NORMAL); + glTranslatef(-xo, -yo, 0); + glScalef(1, 1, 1); + + glRotatef(90, 0, 1, 0); + glTranslatef(-7.5f / 16.0f, 9 / 16.0f, 0); + glTranslatef(0, 0.03f, 0); + float dd = 1 / 16.0f; + + ItemInHandRenderer::renderItem3D(t, u0, v0, u1, v1, icon->getSourceWidth(), icon->getSourceHeight(), 1 / 16.0f, false, bIsTerrain); + + if (item != nullptr && helmet->isFoil()) + { + glDepthFunc(GL_EQUAL); + glDisable(GL_LIGHTING); + minecraft->textures->bindTexture(&ItemInHandRenderer::ENCHANT_GLINT_LOCATION); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_COLOR, GL_ONE); + float br = 0.76f; + glColor4f(0.5f * br, 0.25f * br, 0.8f * br, 1); // MGH - for some reason this colour isn't making it through to the render, so I've added to the tesselator for the glint geom above + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + float ss = 1 / 8.0f; + glScalef(ss, ss, ss); + float sx = Minecraft::currentTimeMillis() % (3000) / (3000.0f) * 8; + glTranslatef(sx, 0, 0); + glRotatef(-50, 0, 0, 1); + + ItemInHandRenderer::renderItem3D(t, 0, 0, 1, 1, 256, 256, 1 / 16.0f, true, bIsTerrain); + glPopMatrix(); + glPushMatrix(); + glScalef(ss, ss, ss); + sx = System::currentTimeMillis() % (3000 + 1873) / (3000 + 1873.0f) * 8; + glTranslatef(-sx, 0, 0); + glRotatef(10, 0, 0, 1); + ItemInHandRenderer::renderItem3D(t, 0, 0, 1, 1, 256, 256, 1 / 16.0f, true, bIsTerrain); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glDisable(GL_BLEND); + glEnable(GL_LIGHTING); + glDepthFunc(GL_LEQUAL); + } + + RenderManager.StateSetForceLOD(-1); + + glDisable(GL_RESCALE_NORMAL); + } + glPopMatrix(); } } diff --git a/Minecraft.Client/CustomHeadLayer.h b/Minecraft.Client/CustomHeadLayer.h index da6814c6..1d09cc0e 100644 --- a/Minecraft.Client/CustomHeadLayer.h +++ b/Minecraft.Client/CustomHeadLayer.h @@ -4,14 +4,17 @@ class ModelPart; class LivingEntity; class LivingEntityRenderer; +class TileRenderer; class CustomHeadLayer : public RenderLayer { public: ModelPart* headPart; LivingEntityRenderer* parentRenderer; + TileRenderer* tileRenderer; + CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer); - virtual ~CustomHeadLayer() {} + virtual ~CustomHeadLayer(); virtual int colorsOnDamage() override; virtual void render(shared_ptr mob, diff --git a/Minecraft.Client/LivingEntityRenderer.cpp b/Minecraft.Client/LivingEntityRenderer.cpp index bc5deb77..67e78c7e 100644 --- a/Minecraft.Client/LivingEntityRenderer.cpp +++ b/Minecraft.Client/LivingEntityRenderer.cpp @@ -474,7 +474,7 @@ void LivingEntityRenderer::renderName(shared_ptr mob, double x, do bool LivingEntityRenderer::shouldShowName(shared_ptr mob) { - return Minecraft::renderNames() && mob != entityRenderDispatcher->cameraEntity && !mob->isInvisibleTo(Minecraft::GetInstance()->player) && mob->rider.lock() == nullptr; + return Minecraft::renderNames() && mob != entityRenderDispatcher->cameraEntity && (!mob->isInvisibleTo(Minecraft::GetInstance()->player) || mob->isCustomNameVisible()) && mob->rider.lock() == nullptr; } void LivingEntityRenderer::renderNameTags(shared_ptr mob, double x, double y, double z, const wstring &msg, float scale, double dist) diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp index d3ccb1e4..87fb2fcb 100644 --- a/Minecraft.Client/PlayerConnection.cpp +++ b/Minecraft.Client/PlayerConnection.cpp @@ -1046,6 +1046,13 @@ void PlayerConnection::handleCommand(const wstring& message) ss >> cmd; if (cmd == L"tp" || cmd == L"teleport") { + + if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled)) + { + warn(L"Cheats are not enabled on this server."); + return; + } + if (!player->hasPermission(eGameCommand_Teleport)) { warn(L"You do not have permission to use this command."); @@ -1138,6 +1145,13 @@ if (cmd == L"tp" || cmd == L"teleport") } } else if (cmd == L"time") { + + if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled)) + { + warn(L"Cheats are not enabled on this server."); + return; + } + if (!player->hasPermission(eGameCommand_Time)) { warn(L"You do not have permission to use this command."); @@ -1268,15 +1282,44 @@ if (cmd == L"tp" || cmd == L"teleport") } else if (cmd == L"kill") { + if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled)) + { + warn(L"Cheats are not enabled on this server."); + return; + } + if (!player->hasPermission(eGameCommand_Kill)) { warn(L"You do not have permission to use this command."); return; } - server->getCommandDispatcher()->performCommand(player, eGameCommand_Kill, byteArray()); + + wstring targetName; + ss >> targetName; + + if (targetName.empty()) + { + + server->getCommandDispatcher()->performCommand(player, eGameCommand_Kill, byteArray()); + } + else + { + + ByteArrayOutputStream baos; + DataOutputStream dos(&baos); + dos.writeUTF(targetName); + byteArray data = baos.toByteArray(); + server->getCommandDispatcher()->performCommand(player, eGameCommand_Kill, data); + } } else if (cmd == L"toggledownfall") { + if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled)) + { + warn(L"Cheats are not enabled on this server."); + return; + } + if (!player->hasPermission(eGameCommand_ToggleDownfall)) { warn(L"You do not have permission to use this command."); @@ -1285,6 +1328,14 @@ if (cmd == L"tp" || cmd == L"teleport") shared_ptr packet = ToggleDownfallCommand::preparePacket(); server->getCommandDispatcher()->performCommand(player, eGameCommand_ToggleDownfall, packet->data); } else if (cmd == L"gamemode") { + + + if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled)) + { + warn(L"Cheats are not enabled on this server."); + return; + } + if (!player->hasPermission(eGameCommand_GameMode)) { warn(L"You do not have permission to use this command."); @@ -1323,6 +1374,13 @@ if (cmd == L"tp" || cmd == L"teleport") shared_ptr packet = GameModeCommand::preparePacket(target, mode); server->getCommandDispatcher()->performCommand(player, eGameCommand_GameMode, packet->data); } else if (cmd == L"give") { + + if (!app.GetGameHostOption(eGameHostOption_CheatsEnabled)) + { + warn(L"Cheats are not enabled on this server."); + return; + } + if (!player->hasPermission(eGameCommand_Give)) { warn(L"You do not have permission to use this command."); @@ -1877,6 +1935,8 @@ void PlayerConnection::handleGameCommand(shared_ptr packet) player->getName().c_str(), player->isModerator() ? 1 : 0, isHost ? 1 : 0, static_cast(packet->command)); #endif + + MinecraftServer::getInstance()->getCommandDispatcher()->performCommand(player, packet->command, packet->data); } diff --git a/Minecraft.Client/ServerLevel.cpp b/Minecraft.Client/ServerLevel.cpp index 507bfbc7..a15e1af5 100644 --- a/Minecraft.Client/ServerLevel.cpp +++ b/Minecraft.Client/ServerLevel.cpp @@ -1683,14 +1683,15 @@ 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()); + auto packet = make_shared( - type, - longDistance, + buf, (float)x, (float)y, (float)z, (float)dx, (float)dy, (float)dz, (float)speed, - count, - data + count ); for (auto const& p : players) diff --git a/Minecraft.Server/FourKitNatives.cpp b/Minecraft.Server/FourKitNatives.cpp index e19a1423..57993fec 100644 --- a/Minecraft.Server/FourKitNatives.cpp +++ b/Minecraft.Server/FourKitNatives.cpp @@ -1281,10 +1281,9 @@ void __cdecl NativeSpawnParticle(int entityId, int particleId, float x, float y, { auto player = FindPlayer(entityId); if (!player || !player->connection) return; - const ParticleType* type = ParticleType::byId(particleId); - if (!type) type = ParticleType::getDefault(); - arrayWithLength noParams = { nullptr, 0 }; - player->connection->send(std::make_shared(type, false, x, y, z, offsetX, offsetY, offsetZ, speed, count, noParams)); + wchar_t buf[32]; + swprintf_s(buf, L"%d", particleId); + player->connection->send(std::make_shared(std::wstring(buf), x, y, z, offsetX, offsetY, offsetZ, speed, count)); } int __cdecl NativeSetPassenger(int entityId, int passengerEntityId) diff --git a/Minecraft.World/ArmorStand.cpp b/Minecraft.World/ArmorStand.cpp index 6fcde73a..81f6beca 100644 --- a/Minecraft.World/ArmorStand.cpp +++ b/Minecraft.World/ArmorStand.cpp @@ -16,11 +16,12 @@ #include "ParticleTypes.h" #include "Random.h" #include "AABB.h" +#include "../Minecraft.World/LevelChunk.h" const Rotations ArmorStand::DEFAULT_HEAD_POSE (0.0f, 0.0f, 0.0f); const Rotations ArmorStand::DEFAULT_BODY_POSE (0.0f, 0.0f, 0.0f); -const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-10.0f, 0.0f, -10.0f); -const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-15.0f, 0.0f, 10.0f); +const Rotations ArmorStand::DEFAULT_LEFT_ARM_POSE (-15.0f, 0.0f, 10.0f); +const Rotations ArmorStand::DEFAULT_RIGHT_ARM_POSE (-10.0f, 0.0f, -10.0f); const Rotations ArmorStand::DEFAULT_LEFT_LEG_POSE (-1.0f, 0.0f, -1.0f); const Rotations ArmorStand::DEFAULT_RIGHT_LEG_POSE (1.0f, 0.0f, 1.0f); @@ -45,6 +46,10 @@ void ArmorStand::init() for (int i = 0; i < equipmentCount; i++) equipment[i] = nullptr; + rotateElytraX = 0.2617994f; + rotateElytraY = 0.0f; + rotateElytraZ = -0.2617994f; + headPose = DEFAULT_HEAD_POSE; bodyPose = DEFAULT_BODY_POSE; leftArmPose = DEFAULT_LEFT_ARM_POSE; @@ -83,7 +88,7 @@ void ArmorStand::defineSynchedData() ArmorStand::~ArmorStand() {} - +bool ArmorStand::hasPhysics() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_NO_GRAVITY) == 0; } bool ArmorStand::isBaby() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SMALL) != 0; } bool ArmorStand::isSmall() const { return isBaby(); } bool ArmorStand::isShowArms() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SHOW_ARMS) != 0; } @@ -188,6 +193,93 @@ void ArmorStand::updateInvisibilityStatus() setInvisible(invisible); } +void ArmorStand::travel(float xa, float ya) +{ + if (hasPhysics()) { + float friction = 0.91f; + int frictionTile = 0; + if (onGround) + { + frictionTile = level->getTile(Mth::floor(x), Mth::floor(bb->y0) - 1, Mth::floor(z)); + friction = 0.6f * 0.91f; + if (frictionTile > 0) + { + friction = Tile::tiles[frictionTile]->friction * 0.91f; + } + } + + float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction); + + float speed; + if (onGround) + { + speed = getSpeed() * friction2; + } + else + { + speed = flyingSpeed; + } + + moveRelative(xa, ya, speed); + + friction = 0.91f; + if (onGround) + { + friction = 0.6f * 0.91f; + if (frictionTile > 0) + { + friction = Tile::tiles[frictionTile]->friction * 0.91f; + } + } + if (onLadder()) + { + float max = 0.15f; + if (xd < -max) xd = -max; + if (xd > max) xd = max; + if (zd < -max) zd = -max; + if (zd > max) zd = max; + fallDistance = 0; + if (yd < -0.15) yd = -0.15; + bool playerSneaking = isSneaking() && this->instanceof(eTYPE_PLAYER); + if (playerSneaking && yd < 0) yd = 0; + } + + move(xd, yd, zd); + + if (horizontalCollision && onLadder()) + { + yd = 0.2; + } + + if (!level->isClientSide || (level->hasChunkAt(static_cast(x), 0, static_cast(z)) && level->getChunkAt(static_cast(x), static_cast(z))->loaded)) + { + yd -= 0.08; + } + else if (y > 0) + { + yd = -0.1; + } + else + { + yd = 0; + } + + yd *= 0.98f; + xd *= friction; + zd *= friction; + + walkAnimSpeedO = walkAnimSpeed; + double xxd = x - xo; + double zzd = z - zo; + float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4; + if (wst > 1) wst = 1; + walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; + walkAnimPos += walkAnimSpeed; + } else { + move(xd, yd, zd); + } +} + void ArmorStand::tick() { @@ -195,14 +287,14 @@ void ArmorStand::tick() LivingEntity::tick(); if (onGround) { - BlockPos pos((int)floorf(x), (int)floorf(y) - 1, (int)floorf(z)); - int blockId = level->getTile(pos.getX(), pos.getY(), pos.getZ()); - if (blockId == Tile::topSnow->id) - { - int meta = level->getData(pos.getX(), pos.getY(), pos.getZ()); - float snowHeight = ((meta & 0x7) + 1) * 0.125f; - moveTo(x, floorf(y) + snowHeight, z, yRot, xRot); - } + BlockPos pos((int)floorf(x), (int)floorf(y) - 1, (int)floorf(z)); + int blockId = level->getTile(pos.getX(), pos.getY(), pos.getZ()); + if (blockId == Tile::topSnow->id) + { + int meta = level->getData(pos.getX(), pos.getY(), pos.getZ()); + float snowHeight = ((meta & 0x7) + 1) * 0.125f; + moveTo(x, floorf(y) + snowHeight, z, yRot, xRot); + } } this->yRot = lockedRot; this->yRotO = lockedRot; diff --git a/Minecraft.World/ArmorStand.h b/Minecraft.World/ArmorStand.h index 629d08aa..eb2df737 100644 --- a/Minecraft.World/ArmorStand.h +++ b/Minecraft.World/ArmorStand.h @@ -56,6 +56,10 @@ private: bool isMarkerFlag; bool noPhysics; float standDamage; +public: + float rotateElytraX; + float rotateElytraY; + float rotateElytraZ; public: long long lastHit; @@ -64,6 +68,7 @@ public: explicit ArmorStand(Level* level); virtual ~ArmorStand(); + bool hasPhysics() const; bool isBaby() const; bool isSmall() const; bool isShowArms() const; @@ -142,6 +147,8 @@ public: void updateBoundingBox(bool markerMode); void updateInvisibilityStatus(); + virtual void travel(float xz, float ya); + virtual shared_ptr getCarriedItem() override; virtual shared_ptr getCarried(int slot) override; virtual shared_ptr getArmor(int pos) override; diff --git a/Minecraft.World/EnderDragon.cpp b/Minecraft.World/EnderDragon.cpp index e9cc670f..43f198be 100644 --- a/Minecraft.World/EnderDragon.cpp +++ b/Minecraft.World/EnderDragon.cpp @@ -1170,7 +1170,13 @@ bool EnderDragon::hurt(shared_ptr MultiEntityMobPart, Damage bool EnderDragon::hurt(DamageSource *source, float damage) { - return false; + if (source == DamageSource::outOfWorld) + { + setSynchedAction(e_EnderdragonAction_Sitting_Scanning, true); + reallyHurt(source, getMaxHealth() + 1); + return true; + } + return false; } bool EnderDragon::reallyHurt(DamageSource *source, float damage) diff --git a/Minecraft.World/EntityTypeMap.cpp b/Minecraft.World/EntityTypeMap.cpp new file mode 100644 index 00000000..450d2f75 --- /dev/null +++ b/Minecraft.World/EntityTypeMap.cpp @@ -0,0 +1,118 @@ +#include "stdafx.h" +#include "EntityTypeMap.h" + +static const unordered_map s_nameToType = { + // animals + { L"pig", eTYPE_PIG }, + { L"cow", eTYPE_COW }, + { L"sheep", eTYPE_SHEEP }, + { L"chicken", eTYPE_CHICKEN }, + { L"horse", eTYPE_HORSE }, + { L"wolf", eTYPE_WOLF }, + { L"ocelot", eTYPE_OCELOT }, + { L"rabbit", eTYPE_RABBIT }, + { L"mooshroom", eTYPE_MUSHROOMCOW }, + { L"squid", eTYPE_SQUID }, + { L"bat", eTYPE_BAT }, + // neutral/passive + { L"villager", eTYPE_VILLAGER }, + { L"snowgolem", eTYPE_SNOWMAN }, + { L"irongolem", eTYPE_VILLAGERGOLEM }, + // monsters + { L"zombie", eTYPE_ZOMBIE }, + { L"skeleton", eTYPE_SKELETON }, + { L"creeper", eTYPE_CREEPER }, + { L"spider", eTYPE_SPIDER }, + { L"cavespider", eTYPE_CAVESPIDER }, + { L"enderman", eTYPE_ENDERMAN }, + { L"silverfish", eTYPE_SILVERFISH }, + { L"blaze", eTYPE_BLAZE }, + { L"witch", eTYPE_WITCH }, + { L"ghast", eTYPE_GHAST }, + { L"slime", eTYPE_SLIME }, + { L"magmacube", eTYPE_LAVASLIME }, + { L"zombie_pigman", eTYPE_PIGZOMBIE }, + { L"witherboss", eTYPE_WITHERBOSS }, + { L"enderdragon", eTYPE_ENDERDRAGON }, + { L"giant", eTYPE_GIANT }, + { L"endermite", eTYPE_ENDERMITE }, + { L"guardian", eTYPE_GUARDIAN }, + { L"elder_guardian", eTYPE_ELDER_GUARDIAN }, + // minecart + { L"minecart", eTYPE_MINECART }, + { L"minecart_chest", eTYPE_MINECART_CHEST }, + { L"minecart_hopper", eTYPE_MINECART_HOPPER }, + { L"minecart_tnt", eTYPE_MINECART_TNT }, + { L"minecart_furnace", eTYPE_MINECART_FURNACE }, + { L"minecart_spawner", eTYPE_MINECART_SPAWNER }, + // projectiles + { L"arrow", eTYPE_ARROW }, + { L"snowball", eTYPE_SNOWBALL }, + { L"egg", eTYPE_THROWNEGG }, + { L"enderpearl", eTYPE_THROWNENDERPEARL }, + { L"potion", eTYPE_THROWNPOTION }, + { L"expbottle", eTYPE_THROWNEXPBOTTLE }, + { L"large_fireball", eTYPE_LARGE_FIREBALL }, + { L"small_fireball", eTYPE_SMALL_FIREBALL }, + { L"wither_skull", eTYPE_WITHER_SKULL }, + { L"dragon_fireball", eTYPE_DRAGON_FIREBALL }, + { L"fireworks_rocket", eTYPE_FIREWORKS_ROCKET }, + { L"eyeofender", eTYPE_EYEOFENDERSIGNAL }, + // hanging + { L"painting", eTYPE_PAINTING }, + { L"item_frame", eTYPE_ITEM_FRAME }, + { L"leash_knot", eTYPE_LEASHFENCEKNOT }, + // others + { L"item", eTYPE_ITEMENTITY }, + { L"xp_orb", eTYPE_EXPERIENCEORB }, + { L"boat", eTYPE_BOAT }, + { L"tnt", eTYPE_PRIMEDTNT }, + { L"falling_block", eTYPE_FALLINGTILE }, + { L"armor_stand", eTYPE_ARMORSTAND }, + { L"ender_crystal", eTYPE_ENDER_CRYSTAL }, + { L"lightning_bolt", eTYPE_LIGHTNINGBOLT }, +}; + +static const unordered_map s_typeToName = []() +{ + unordered_map m; + for (auto& pair : s_nameToType) + { + if (m.find(pair.second) == m.end()) + m[pair.second] = pair.first; + } + return m; +}(); + +const unordered_map& EntityTypeMap::getNameToTypeMap() +{ + return s_nameToType; +} + +const unordered_map& EntityTypeMap::getTypeToNameMap() +{ + return s_typeToName; +} + +eINSTANCEOF EntityTypeMap::getTypeFromName(const wstring& name) +{ + wstring lower = name; + transform(lower.begin(), lower.end(), lower.begin(), towlower); + auto it = s_nameToType.find(lower); + if (it != s_nameToType.end()) + return it->second; + return eTYPE_NOTSET; +} + +wstring EntityTypeMap::getNameFromType(eINSTANCEOF type) +{ + auto it = s_typeToName.find(type); + if (it != s_typeToName.end()) + return it->second; + return L""; +} + +bool EntityTypeMap::isValidType(const wstring& name) +{ + return getTypeFromName(name) != eTYPE_NOTSET; +} \ No newline at end of file diff --git a/Minecraft.World/EntityTypeMap.h b/Minecraft.World/EntityTypeMap.h new file mode 100644 index 00000000..e3235bec --- /dev/null +++ b/Minecraft.World/EntityTypeMap.h @@ -0,0 +1,21 @@ +#pragma once +#include "../Minecraft.World/Class.h" +#include +#include +using namespace std; + +class EntityTypeMap +{ +public: + + static eINSTANCEOF getTypeFromName(const wstring& name); + + static wstring getNameFromType(eINSTANCEOF type); + + + static bool isValidType(const wstring& name); + +private: + static const unordered_map& getNameToTypeMap(); + static const unordered_map& getTypeToNameMap(); +}; \ No newline at end of file diff --git a/Minecraft.World/KillCommand.cpp b/Minecraft.World/KillCommand.cpp index c726b21f..d48fd70b 100644 --- a/Minecraft.World/KillCommand.cpp +++ b/Minecraft.World/KillCommand.cpp @@ -1,26 +1,197 @@ -#include "stdafx.h" +#include "stdafx.h" #include "net.minecraft.commands.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.level.h" #include "BasicTypeContainers.h" #include "KillCommand.h" +#include "EntityTypeMap.h" + + +static void killEntity(shared_ptr entity) +{ + if (entity->instanceof(eTYPE_LIVINGENTITY)) + { + auto living = dynamic_pointer_cast(entity); + if (living != nullptr) + { + living->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + return; + } + + entity->remove(); + return; + } + entity->remove(); +} EGameCommand KillCommand::getId() { - return eGameCommand_Kill; + return eGameCommand_Kill; } int KillCommand::getPermissionLevel() { - return LEVEL_ALL; + return LEVEL_ALL; } void KillCommand::execute(shared_ptr source, byteArray commandData) { - shared_ptr player = dynamic_pointer_cast(source); + shared_ptr senderPlayer = dynamic_pointer_cast(source); + if (senderPlayer == nullptr) + return; - player->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + Level *level = senderPlayer->level; + if (level == nullptr) + return; - source->sendMessage(L"Ouch. That look like it hurt."); -//source.sendMessage(ChatMessageComponent.forTranslation("commands.kill.success")); + + //nothing is the same of @s + if (commandData.length == 0 || commandData.data == nullptr) + { + senderPlayer->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + return; + } + + ByteArrayInputStream bais(commandData); + DataInputStream dis(&bais); + wstring targetName = dis.readUTF(); + + wstring targetLower = targetName; + transform(targetLower.begin(), targetLower.end(), targetLower.begin(), towlower); + + //@s + if (targetLower == L"@s") + { + senderPlayer->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + return; + } + + //@a + if (targetLower == L"@a") + { + vector> toKill; + for (auto& p : level->players) + if (p != nullptr && !p->removed) + toKill.push_back(p); + for (auto& p : toKill) + p->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + return; + } + + //@p + if (targetLower == L"@p") + { + shared_ptr nearest = level->getNearestPlayer( + dynamic_pointer_cast(senderPlayer), 9999.0); + if (nearest != nullptr) + { + nearest->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + source->sendMessage(L"Killed " + nearest->getName() + L"."); + } + else + { + source->sendMessage(L"No player found."); + } + return; + } + + //@r + if (targetLower == L"@r") + { + if (level->players.empty()) + { + source->sendMessage(L"No player found."); + return; + } + int idx = rand() % (int)level->players.size(); + auto& p = level->players[idx]; + if (p != nullptr && !p->removed) + { + p->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + source->sendMessage(L"Killed " + p->getName() + L"."); + } + return; + } + + // @e + if (targetLower.size() >= 2 && targetLower.substr(0, 2) == L"@e") + { + eINSTANCEOF filterType = eTYPE_NOTSET; + bool invertFilter = false; + bool filterIsPlayer = false; + + if (targetLower.size() > 3 && targetLower[2] == L'[') + { + wstring inner = targetLower.substr(3, targetLower.size() - 4); + wstring key = L"type="; + size_t pos = inner.find(key); + if (pos == wstring::npos) + { + source->sendMessage(L"Invalid selector syntax. Usage: @e[type=]"); + return; + } + + wstring typeStr = inner.substr(pos + key.size()); + if (!typeStr.empty() && typeStr[0] == L'!') + { + invertFilter = true; + typeStr = typeStr.substr(1); + } + + if (typeStr == L"player") + { + filterIsPlayer = true; + } + else + { + filterType = EntityTypeMap::getTypeFromName(typeStr); + if (filterType == eTYPE_NOTSET) + { + source->sendMessage(L"Unknown entity type: " + typeStr); + return; + } + } + } + + vector> toKill; + for (auto& entity : level->entities) + { + if (entity == nullptr || entity->removed) continue; + + bool isPlayer = entity->instanceof(eTYPE_PLAYER); + + + bool matchesFilter; + if (filterType == eTYPE_NOTSET && !filterIsPlayer) + matchesFilter = true; + else if (filterIsPlayer) + matchesFilter = isPlayer; + else + matchesFilter = entity->instanceof(filterType); + + if (invertFilter) matchesFilter = !matchesFilter; + + if (matchesFilter) + toKill.push_back(entity); + } + + for (auto& entity : toKill) + if (!entity->removed) + killEntity(entity); + + source->sendMessage(L"Killed " + to_wstring(toKill.size()) + L" entities."); + return; + } + + // by player name + shared_ptr targetPlayer = level->getPlayerByName(targetName); + if (targetPlayer != nullptr) + { + targetPlayer->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); + source->sendMessage(L"Killed " + targetName + L"."); + return; + } + + source->sendMessage(L"No entity was found."); } \ No newline at end of file diff --git a/Minecraft.World/LevelParticlesPacket.cpp b/Minecraft.World/LevelParticlesPacket.cpp index b9d5a840..834bcf44 100644 --- a/Minecraft.World/LevelParticlesPacket.cpp +++ b/Minecraft.World/LevelParticlesPacket.cpp @@ -1,127 +1,110 @@ - -#include "stdafx.h" +#include "stdafx.h" #include "PacketListener.h" #include "LevelParticlesPacket.h" -#include "../Minecraft.Client/ParticleType.h" LevelParticlesPacket::LevelParticlesPacket() { - - this->overrideLimiter = false; - this->type = nullptr; - this->count = 0; - this->y = 0.0f; - this->paramCount = 0; - this->x = 0.0f; - this->yDist = 0.0f; - this->zDist = 0.0f; - this->z = 0.0f; - this->maxSpeed = 0.0f; - this->xDist = 0.0f; - this->params = nullptr; + this->name = L""; + this->x = 0.0f; + this->y = 0.0f; + this->z = 0.0f; + this->xDist = 0.0f; + this->yDist = 0.0f; + this->zDist = 0.0f; + this->maxSpeed = 0.0f; + this->count = 0; } -LevelParticlesPacket::LevelParticlesPacket(const ParticleType* type, bool overrideLimiter, - float x, float y, float z, - float xDist, float yDist, float zDist, - float maxSpeed, int count, - arrayWithLength data) +LevelParticlesPacket::LevelParticlesPacket(const wstring& name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count) { - this->type = type; - this->overrideLimiter = overrideLimiter; - this->x = x; - this->y = y; - this->z = z; - this->xDist = xDist; - this->yDist = yDist; - this->zDist = zDist; - this->maxSpeed = maxSpeed; - this->count = count; - this->paramCount = data.length; - - if (data.data && data.length > 0) - { - this->params = new int[data.length]; - memcpy(this->params, data.data, data.length * sizeof(int)); - } - else - { - this->params = nullptr; - } -} - -LevelParticlesPacket::~LevelParticlesPacket() -{ - - if (params) - { - delete[] params; - params = nullptr; - } + this->name = name; + this->x = x; + this->y = y; + this->z = z; + this->xDist = xDist; + this->yDist = yDist; + this->zDist = zDist; + this->maxSpeed = maxSpeed; + this->count = count; } void LevelParticlesPacket::read(DataInputStream* dis) { - int particleId = dis->readInt(); - const ParticleType* resolved = ParticleType::byId(particleId); - if (!resolved) - resolved = ParticleType::getDefault(); - this->type = resolved; - - this->overrideLimiter = dis->readBoolean(); - - this->x = dis->readFloat(); - this->y = dis->readFloat(); - this->z = dis->readFloat(); - this->xDist = dis->readFloat(); - this->yDist = dis->readFloat(); - this->zDist = dis->readFloat(); - this->maxSpeed = dis->readFloat(); - this->count = dis->readInt(); - - int paramCount = this->type ? this->type->getParamCount() : 0; - this->paramCount = paramCount; - - if (paramCount > 0) - { - this->params = new int[paramCount](); - for (int i = 0; i < paramCount; i++) - { - this->params[i] = dis->readInt(); - } - } - else - { - this->params = nullptr; - } + name = readUtf(dis, 64); + x = dis->readFloat(); + y = dis->readFloat(); + z = dis->readFloat(); + xDist = dis->readFloat(); + yDist = dis->readFloat(); + zDist = dis->readFloat(); + maxSpeed = dis->readFloat(); + count = dis->readInt(); } void LevelParticlesPacket::write(DataOutputStream* dos) { - dos->writeInt(this->type ? this->type->getId() : 0); - dos->writeBoolean(this->overrideLimiter); - dos->writeFloat(this->x); - dos->writeFloat(this->y); - dos->writeFloat(this->z); - dos->writeFloat(this->xDist); - dos->writeFloat(this->yDist); - dos->writeFloat(this->zDist); - dos->writeFloat(this->maxSpeed); - dos->writeInt(this->count); + writeUtf(name, dos); + dos->writeFloat(x); + dos->writeFloat(y); + dos->writeFloat(z); + dos->writeFloat(xDist); + dos->writeFloat(yDist); + dos->writeFloat(zDist); + dos->writeFloat(maxSpeed); + dos->writeInt(count); +} - int toWrite = this->type ? this->type->getParamCount() : 0; - for (int i = 0; i < toWrite; i++) - { - dos->writeInt(this->params[i]); - } +wstring LevelParticlesPacket::getName() +{ + return name; +} + +double LevelParticlesPacket::getX() +{ + return x; +} + +double LevelParticlesPacket::getY() +{ + return y; +} + +double LevelParticlesPacket::getZ() +{ + return z; +} + +float LevelParticlesPacket::getXDist() +{ + return xDist; +} + +float LevelParticlesPacket::getYDist() +{ + return yDist; +} + +float LevelParticlesPacket::getZDist() +{ + return zDist; +} + +float LevelParticlesPacket::getMaxSpeed() +{ + return maxSpeed; +} + +int LevelParticlesPacket::getCount() +{ + return count; } void LevelParticlesPacket::handle(PacketListener* listener) { - listener->handleParticleEvent(shared_from_this()); + listener->handleParticleEvent(shared_from_this()); } int LevelParticlesPacket::getEstimatedSize() { - return 0x40; + return 4 * 2 + 7 * 8; } \ No newline at end of file diff --git a/Minecraft.World/LevelParticlesPacket.h b/Minecraft.World/LevelParticlesPacket.h index bd156ec5..076df914 100644 --- a/Minecraft.World/LevelParticlesPacket.h +++ b/Minecraft.World/LevelParticlesPacket.h @@ -1,53 +1,39 @@ - #pragma once + #include "Packet.h" -#include "../Minecraft.Client/ParticleType.h" class LevelParticlesPacket : public Packet, public enable_shared_from_this { private: - - const ParticleType* type; - float x; - float y; - float z; - float xDist; - float yDist; - float zDist; - float maxSpeed; - int count; - bool overrideLimiter; - int* params; - int paramCount; + wstring name; + float x; + float y; + float z; + float xDist; + float yDist; + float zDist; + float maxSpeed; + int count; public: - LevelParticlesPacket(); - LevelParticlesPacket(const ParticleType* type, bool overrideLimiter, - float x, float y, float z, - float xDist, float yDist, float zDist, - float maxSpeed, int count, - arrayWithLength data); - ~LevelParticlesPacket(); + LevelParticlesPacket(); + LevelParticlesPacket(const wstring& name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count); - void read(DataInputStream* dis) override; - void write(DataOutputStream* dos) override; + void read(DataInputStream* dis); + void write(DataOutputStream* dos); + wstring getName(); + double getX(); + double getY(); + double getZ(); + float getXDist(); + float getYDist(); + float getZDist(); + float getMaxSpeed(); + int getCount(); + void handle(PacketListener* listener); + int getEstimatedSize(); - const ParticleType* getType() { return type; } - double getX() { return x; } - double getY() { return y; } - double getZ() { return z; } - double getXDist() { return xDist; } - double getYDist() { return yDist; } - double getZDist() { return zDist; } - double getMaxSpeed() { return maxSpeed; } - int getCount() { return count; } - bool isOverrideLimiter() { return overrideLimiter; } - int* getParams() { return params; } - int getParamCount() { return paramCount; } - - void handle(PacketListener* listener) override; - int getEstimatedSize() override; - - static shared_ptr create() { return std::make_shared(); } - virtual int getId() override { return 63; } +public: + static shared_ptr create() { return std::make_shared(); } + virtual int getId() { return 63; } }; \ No newline at end of file diff --git a/Minecraft.World/LivingEntity.h b/Minecraft.World/LivingEntity.h index cdce6701..6a3d6a50 100644 --- a/Minecraft.World/LivingEntity.h +++ b/Minecraft.World/LivingEntity.h @@ -51,9 +51,10 @@ public: static const int DATA_ARROW_COUNT_ID = 9; private: - BaseAttributeMap* attributes; CombatTracker* combatTracker; unordered_map activeEffects; +protected: + BaseAttributeMap* attributes; ItemInstanceArray lastEquipment; public: diff --git a/Minecraft.World/Ocelot.cpp b/Minecraft.World/Ocelot.cpp index 02ef07c1..6816cabc 100644 --- a/Minecraft.World/Ocelot.cpp +++ b/Minecraft.World/Ocelot.cpp @@ -35,13 +35,16 @@ Ocelot::Ocelot(Level *level) : TamableAnimal(level) registerAttributes(); setHealth(getMaxHealth()); + avoidPlayerGoal = nullptr; + + reassessTameGoals(); + setSize(0.6f, 0.8f); getNavigation()->setAvoidWater(true); goalSelector.addGoal(1, new FloatGoal(this)); goalSelector.addGoal(2, sitGoal, false); goalSelector.addGoal(3, temptGoal = new TemptGoal(this, SNEAK_SPEED_MOD, Item::fish_raw_Id, true), false); - goalSelector.addGoal(4, new AvoidPlayerGoal(this, typeid(Player), 16, WALK_SPEED_MOD, SPRINT_SPEED_MOD)); goalSelector.addGoal(5, new FollowOwnerGoal(this, FOLLOW_SPEED_MOD, 10, 5)); goalSelector.addGoal(6, new OcelotSitOnTileGoal(this, SPRINT_SPEED_MOD)); goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3f)); @@ -60,6 +63,21 @@ void Ocelot::defineSynchedData() entityData->define(DATA_TYPE_ID, static_cast(0)); } +void Ocelot::reassessTameGoals() +{ + if (!avoidPlayerGoal) + avoidPlayerGoal = new AvoidPlayerGoal(this, typeid(Player), 16, WALK_SPEED_MOD, SPRINT_SPEED_MOD); + + goalSelector.removeGoal(avoidPlayerGoal); + if (!isTame()) + goalSelector.addGoal(4, avoidPlayerGoal, false); +} + +void Ocelot::setTame(bool tame) +{ + TamableAnimal::setTame(tame); +} + void Ocelot::serverAiMobStep() { if (getMoveControl()->hasWanted()) @@ -199,7 +217,10 @@ bool Ocelot::mobInteract(shared_ptr player) } else { - if (/*temptGoal->isRunning() &&*/ item != nullptr && item->id == Item::fish_raw_Id && player->distanceToSqr(shared_from_this()) < 3 * 3) + //player must be close holding raw fish + // temptGoal->isRunning() check removed + // when the player enters interaction range, which would block taming entirely + if (item != nullptr && item->id == Item::fish_raw_Id && player->distanceToSqr(shared_from_this()) < 3 * 3) { // 4J-PB - don't lose the fish in creative mode if (!player->abilities.instabuild) item->count--; @@ -284,6 +305,8 @@ void Ocelot::setCatType(int type) bool Ocelot::canSpawn() { + + //return level->random->nextInt(3) != 0; when checkSpawnObstruction is implemented // artificially make ozelots more rare if (level->random->nextInt(3) == 0) { diff --git a/Minecraft.World/Ocelot.h b/Minecraft.World/Ocelot.h index 7f02bf02..8336f856 100644 --- a/Minecraft.World/Ocelot.h +++ b/Minecraft.World/Ocelot.h @@ -1,6 +1,7 @@ #pragma once #include "TamableAnimal.h" +#include "AvoidPlayerGoal.h" class TemptGoal; @@ -32,6 +33,7 @@ public: private: TemptGoal *temptGoal; + AvoidPlayerGoal *avoidPlayerGoal; public: Ocelot(Level *level); @@ -41,6 +43,8 @@ protected: public: virtual void serverAiMobStep(); + virtual void reassessTameGoals(); + virtual void setTame(bool tame); protected: virtual bool removeWhenFarAway(); @@ -78,6 +82,7 @@ public: virtual int getCatType(); virtual void setCatType(int type); virtual bool canSpawn(); + //virtual bool checkSpawnObstruction(); TODO when blockstates will be merged. virtual wstring getAName(); virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param diff --git a/Minecraft.World/cmake/sources/Common.cmake b/Minecraft.World/cmake/sources/Common.cmake index 8c201c0b..6b45f3b6 100644 --- a/Minecraft.World/cmake/sources/Common.cmake +++ b/Minecraft.World/cmake/sources/Common.cmake @@ -204,6 +204,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_COMMANDS_COMMON "${CMAKE_CURRENT_SOURCE_DIR}/ToggleDownfallCommand.h" "${CMAKE_CURRENT_SOURCE_DIR}/WeatherCommand.h" "${CMAKE_CURRENT_SOURCE_DIR}/net.minecraft.commands.common.h" + "${CMAKE_CURRENT_SOURCE_DIR}/EntityTypeMap.h" + "${CMAKE_CURRENT_SOURCE_DIR}/EntityTypeMap.cpp" ) source_group("net/minecraft/commands/common" FILES ${_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_COMMANDS_COMMON}) diff --git a/NOTES.md b/NOTES.md index 5a3445e9..2c34a056 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,6 +1,18 @@ -# neoLegacy v1.0.7b +# neoLegacy v1.0.8b -- Reverted "Expanded" world size due to it causing crashing and lighting issues. +### Bug Fixes +- Game has been heavily optimized; expect more FPS. +- Fullscreen option is now correctly applied on startup. +- `/kill` now kills the player in creative. +- Boat now follows the player correctly when speeding. +- Ocelots can now be tamed. +- Elytras and items are now rendered correctly when on an armor stand. + +### Changes +- Added new logo (made by rdust). +- Added TU31 parity changes which include: + - Dye recipes using flowers. + - Prismarine block animation. roadmap diff --git a/README.md b/README.md index 008a0bee..a46c04d1 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Huge thanks to the following projects: - [Patoke/LCERenewed](https://github.com/Patoke/LCERenewed) - for some of the patches that required deep decompilation - [itsRevela/LCE-Revelations](https://git.revela.dev/itsRevela/LCE-Revelations) - for providing a stable project for neoLegacy to continue with - [GabsPuNs/Project-Zenith](https://github.com/GabsPuNs/Project-Zenith-Main) - for providing us with their implemention of the Classic Crafting Feature. +- rdust_dusted (Discord) - for providing us with a redesigned logo that we currently use. # Build & Run