Compare commits

...

37 commits

Author SHA1 Message Date
Fireblade c3e02fb2d6
Merge pull request #144 from DrPerkyLegit/fix/name-render
Some checks failed
Nightly Release / Build Client (push) Has been cancelled
Nightly Release / Build Server (push) Has been cancelled
Sync branches with main / sync (push) Has been cancelled
Nightly Release / Release Server (push) Has been cancelled
Nightly Release / Release Client (push) Has been cancelled
Nightly Release / cleanup (push) Has been cancelled
2026-06-01 17:43:59 -04:00
DrPerkyLegit 78a55e97ef make names render when forced 2026-06-01 17:40:47 -04:00
piebot 4b93dbeedd
chore: release v1.0.8b (#143)
Some checks failed
Nightly Release / Build Client (push) Waiting to run
Nightly Release / Build Server (push) Waiting to run
Nightly Release / Release Client (push) Blocked by required conditions
Nightly Release / Release Server (push) Blocked by required conditions
Nightly Release / cleanup (push) Blocked by required conditions
Sync branches with main / sync (push) Waiting to run
Stable Release / Build Client (push) Has been cancelled
Stable Release / Build Server (push) Has been cancelled
Stable Release / Release Server (push) Has been cancelled
Stable Release / Release Client (push) Has been cancelled
Stable Release / cleanup (push) Has been cancelled
2026-06-01 16:48:00 +03:00
piebot c268ef1cc3
add new acknowledgement for new logo (thanks rdust_dusted!) (#142) 2026-06-01 16:20:01 +03:00
piebot f3d4e20b7a
chore: update logo ingame (#141) 2026-06-01 16:18:05 +03:00
piebot c0196abe3b
chore: update logo in banner (#140) 2026-06-01 16:17:06 +03:00
Fireblade 7f967ed66f
Merge pull request #139 from DrPerkyLegit/fix/s2c-particles
Some checks are pending
Nightly Release / Build Client (push) Waiting to run
Nightly Release / Build Server (push) Waiting to run
Nightly Release / Release Client (push) Blocked by required conditions
Nightly Release / Release Server (push) Blocked by required conditions
Nightly Release / cleanup (push) Blocked by required conditions
Sync branches with main / sync (push) Waiting to run
2026-05-31 20:51:49 -04:00
DrPerkyLegit 61f363e803 fix particles being sent from the server 2026-05-31 20:50:30 -04:00
Fireblade baa6745f45
Merge pull request #138 from DrPerkyLegit/fix/armor-stands
Fix/armor stands
2026-05-31 19:32:27 -04:00
DrPerkyLegit 7d93753451
Merge branch 'neoStudiosLCE:main' into fix/armor-stands 2026-05-31 19:31:19 -04:00
DrPerkyLegit 76000424e1 fix armor stands no gravity field 2026-05-31 19:27:41 -04:00
DrPerkyLegit a465d22390 Reapply "noPhysics field now works"
This reverts commit 31abba9e04.
2026-05-31 17:23:50 -04:00
DrPerkyLegit 31abba9e04 Revert "noPhysics field now works"
This reverts commit e9b2f724c6.
2026-05-31 17:21:14 -04:00
DrPerkyLegit e9b2f724c6 noPhysics field now works 2026-05-31 16:46:48 -04:00
piebot 4a7d95d8e9
chore: update neoLegacy logo (#137)
Some checks are pending
Nightly Release / Build Client (push) Waiting to run
Nightly Release / Release Server (push) Blocked by required conditions
Nightly Release / Release Client (push) Blocked by required conditions
Nightly Release / cleanup (push) Blocked by required conditions
Sync branches with main / sync (push) Waiting to run
Nightly Release / Build Server (push) Waiting to run
2026-05-31 21:53:07 +03:00
Fireblade d421708b5f
Merge pull request #136 from DrPerkyLegit/fix/armor-stands
Fix/armor stands
2026-05-31 14:33:10 -04:00
DrPerkyLegit f8c9349510 items render correctly on the head 2026-05-31 13:57:04 -04:00
DrPerkyLegit 78759b9f15 render elytra on armor stands 2026-05-31 12:36:32 -04:00
Lord Cambion 2417eb4562
feat: better kill command, Host Privileges check (#135)
i changed a bit the kill command because it was not working properly,
then i added a check for HostPrivileges for each command
2026-05-31 18:48:53 +03:00
DrPerkyLegit 5857fab1f6 fix default arm rotations 2026-05-31 11:32:55 -04:00
DrPerkyLegit db4f09ffb8 items now render in the hand when they exist 2026-05-31 11:30:27 -04:00
Lord Cambion 128651de24
fix: Ocelot Can Be Tamed (#132)
Some checks failed
Nightly Release / Build Client (push) Has been cancelled
Nightly Release / Build Server (push) Has been cancelled
Nightly Release / Release Server (push) Has been cancelled
Nightly Release / Release Client (push) Has been cancelled
Sync branches with main / sync (push) Has been cancelled
Nightly Release / cleanup (push) Has been cancelled
* Revert "fix: ocelot couldnt be tamed"

This reverts commit 7701841381.

* fix: better implementd ocelots taming.
2026-05-30 16:59:03 +03:00
Lord Cambion 1cd3f977e4
fix(TU31): prismarine animation (#134)
tranq forgot to update the name of the files
2026-05-30 16:58:23 +03:00
Lord Cambion b7393ab153
feat: dye recipes using flowers (#131)
Some checks failed
Sync branches with main / sync (push) Has been cancelled
Nightly Release / cleanup (push) Has been cancelled
Nightly Release / Release Server (push) Has been cancelled
Nightly Release / Release Client (push) Has been cancelled
Nightly Release / Build Client (push) Has been cancelled
Nightly Release / Build Server (push) Has been cancelled
2026-05-28 22:31:49 +03:00
/home/neo edee888662
fix: ocelot couldnt be tamed (#130) 2026-05-28 21:23:00 +03:00
Lord_Cambion 7701841381 fix: ocelot couldnt be tamed 2026-05-28 20:09:18 +02:00
DrPerkyLegit 60aba187a7
fix custom recipe names not working (#129) 2026-05-28 17:20:24 +03:00
Lord Cambion 012ada2e88
Merge pull request #128 from neoStudiosLCE/bugfix/boat
Some checks are pending
Nightly Release / Build Client (push) Waiting to run
Nightly Release / Release Server (push) Blocked by required conditions
Nightly Release / cleanup (push) Blocked by required conditions
Nightly Release / Build Server (push) Waiting to run
Nightly Release / Release Client (push) Blocked by required conditions
Sync branches with main / sync (push) Waiting to run
Update: BlockPos.cpp comments
2026-05-27 19:58:57 +02:00
Lord_Cambion 6e29b9f778 Update: BlockPos.cpp comments
changed from italian to english
2026-05-27 19:58:09 +02:00
Lord Cambion c19d5bb58e
fix: boat not following correctly the player when speeding (#127) 2026-05-27 20:22:12 +03:00
Lord_Cambion 2d07c7abee fix: boat not following correctly the player when speeding 2026-05-27 19:20:09 +02:00
Lord_Cambion 311503ec46 fix: /kill now kills the player if in creative
Some checks failed
Nightly Release / Build Client (push) Has been cancelled
Nightly Release / Build Server (push) Has been cancelled
Sync branches with main / sync (push) Has been cancelled
Nightly Release / Release Server (push) Has been cancelled
Nightly Release / Release Client (push) Has been cancelled
Nightly Release / cleanup (push) Has been cancelled
2026-05-26 19:02:54 +02:00
Necmi bb37600c87
fix: game startup not checking fullscren values correct (#122)
* fix outdated fullscreenload & added a bool to check at startupfullscreen

* fix outdated methods & add back accidental deletes + debug things

* used old vars & added deleted showwindow & updatewindow

* added deleted few things
2026-05-26 19:00:08 +03:00
Zero 544befe162
Fix multiple memory leaks and stale pooled allocations (#123) 2026-05-26 15:47:43 +03:00
Fireblade 285fab70b2
chore: update revelations url
Some checks are pending
Nightly Release / Build Client (push) Waiting to run
Nightly Release / Release Client (push) Blocked by required conditions
Nightly Release / Build Server (push) Waiting to run
Nightly Release / Release Server (push) Blocked by required conditions
Nightly Release / cleanup (push) Blocked by required conditions
Sync branches with main / sync (push) Waiting to run
2026-05-25 15:30:55 -04:00
Necmi ac3ece01c7
fix: stop elytra sound when going to mainmenu (#118) 2026-05-25 22:17:36 +03:00
Joud Kandeel ef0dad4ffc
fix: memory leaks and heavily optimize the game (#117)
* fixed performance issue on getting texture height for rendering the player model as it loades the player texture on every frame

* updated the lifetime of the texture

* fixed 20 MB memory leak

* delay window display until engine init is done
2026-05-25 22:13:28 +03:00
48 changed files with 1195 additions and 292 deletions

View file

@ -62,7 +62,7 @@ body:
- type: input - type: input
id: itsrevela id: itsrevela
attributes: attributes:
label: Is this reproducable in itsRevela/LCE-Revelations? (https://github.com/itsRevela/LCE-Revelations) label: Is this reproducable in itsRevela/LCE-Revelations? (https://git.revela.dev/itsRevela/LCE-Revelations)
description: If this was a "no idea" or similar, it will be rejected. description: If this was a "no idea" or similar, it will be rejected.
validations: validations:
required: true required: true

BIN
.github/banner.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 KiB

After

Width:  |  Height:  |  Size: 673 KiB

2
BUMP
View file

@ -1 +1 @@
1.0.7b 1.0.8b

View file

@ -9,7 +9,6 @@ ArmorStandModel::ArmorStandModel(float scale) : HumanoidModel(scale)
texWidth = 64; texWidth = 64;
texHeight = 64; texHeight = 64;
head = new ModelPart(this, 0, 0); head = new ModelPart(this, 0, 0);
head->addBox(-1.0f, -7.0f, -1.0f, 2, 7, 2, scale); head->addBox(-1.0f, -7.0f, -1.0f, 2, 7, 2, scale);
head->setPos(0.0f, 0.0f, 0.0f); head->setPos(0.0f, 0.0f, 0.0f);

View file

@ -16,6 +16,7 @@
#include "PlayerRenderer.h" #include "PlayerRenderer.h"
#include "../Minecraft.World/SkullItem.h" #include "../Minecraft.World/SkullItem.h"
#include "../Minecraft.World/SkullTileEntity.h" #include "../Minecraft.World/SkullTileEntity.h"
#include "../Minecraft.World/ElytraItem.h"
static const float DEG_TO_RAD = 3.14159265f / 180.0f; static const float DEG_TO_RAD = 3.14159265f / 180.0f;
@ -84,9 +85,22 @@ void ArmorStandRenderer::render(shared_ptr<Entity> entity,
double x, double y, double z, double x, double y, double z,
float rot, float a) float rot, float a)
{ {
shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(entity);
float brightness = SharedConstants::TEXTURE_LIGHTING ? 1 : mob->getBrightness(a);
glColor3f(brightness, brightness, brightness);
shared_ptr<ItemInstance> item = mob->getCarriedItem();
prepareCarriedItem(mob, item);
LivingEntityRenderer::render(entity, x, y, z, rot, a); LivingEntityRenderer::render(entity, x, y, z, rot, a);
} }
void ArmorStandRenderer::prepareCarriedItem(shared_ptr<Entity> mob, shared_ptr<ItemInstance> item)
{
armorLayer->armorModel1->holdingRightHand = armorLayer->armorModel2->holdingRightHand = item != nullptr ? 1 : 0;
}
void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob, void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob, float wp, float ws, float bob,
float headRotMinusBodyRot, float headRotMinusBodyRot,
@ -166,6 +180,108 @@ void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
void ArmorStandRenderer::additionalRendering(shared_ptr<LivingEntity> mob, float a) void ArmorStandRenderer::additionalRendering(shared_ptr<LivingEntity> mob, float a)
{ {
{
shared_ptr<ItemInstance> chestItem = mob->getEquipmentSlots()[ArmorStand::SLOT_CHEST];
if (chestItem != nullptr && dynamic_cast<ElytraItem*>(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<ArmorStand*>(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<ItemInstance> 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();
}
} }

View file

@ -47,5 +47,7 @@ public:
float headRotMinusBodyRot, float headRotMinusBodyRot,
float headRotx, float scale) override; float headRotx, float scale) override;
virtual int prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a) override; virtual int prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a) override;
void prepareCarriedItem(shared_ptr<Entity> mob, shared_ptr<ItemInstance> item);
virtual void additionalRendering(shared_ptr<LivingEntity> mob, float a) override; virtual void additionalRendering(shared_ptr<LivingEntity> mob, float a) override;
}; };

View file

@ -4323,10 +4323,7 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket>
void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet) void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet)
{ {
const ParticleType* type = packet->getType(); ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)Integer::parseInt(packet->getName());
if (type == nullptr) return;
ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)type->getId();
for (int i = 0; i < packet->getCount(); i++) for (int i = 0; i < packet->getCount(); i++)
{ {

View file

@ -916,7 +916,7 @@ void IUIScene_CraftingMenu::UpdateHighlight()
// special case for the torch coal/charcoal // special case for the torch coal/charcoal
int id=pTempItemInstAdditional->getDescriptionId(); int id=pTempItemInstAdditional->getDescriptionId();
LPCWSTR itemstring; wstring itemstring;
switch(id) switch(id)
{ {
@ -945,11 +945,15 @@ void IUIScene_CraftingMenu::UpdateHighlight()
} }
break; break;
default: default:
if (pTempItemInstAdditional->hasCustomHoverName()) {
itemstring = pTempItemInstAdditional->getHoverName();
} else {
itemstring = app.GetString(id); itemstring = app.GetString(id);
}
break; break;
} }
setItemText(itemstring); setItemText(itemstring.c_str());
} }
else else
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -13,11 +13,19 @@
#include "../Minecraft.World/SkullTileEntity.h" #include "../Minecraft.World/SkullTileEntity.h"
#include "../Minecraft.World/LivingEntity.h" #include "../Minecraft.World/LivingEntity.h"
#include "../Minecraft.World/Facing.h" #include "../Minecraft.World/Facing.h"
#include "../Minecraft.Client/SimpleIcon.h"
#include "../Minecraft.World/AirTile.h"
CustomHeadLayer::CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer) CustomHeadLayer::CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer)
: headPart(headPart), parentRenderer(parentRenderer) : headPart(headPart), parentRenderer(parentRenderer)
{ {
tileRenderer = new TileRenderer();
}
CustomHeadLayer::~CustomHeadLayer() {
delete tileRenderer;
} }
int CustomHeadLayer::colorsOnDamage() int CustomHeadLayer::colorsOnDamage()
@ -90,12 +98,136 @@ void CustomHeadLayer::render(shared_ptr<LivingEntity> mob,
glRotatef(90.0f, 0.0f, 1.0f, 0.0f); glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
Minecraft* mc = Minecraft::GetInstance();
if (mc)
{ {
auto* iihr = mc->getItemInHandRenderer(); // 4J - code borrowed from render method below, although not factoring in brightness as that should already be being taken into account
if (iihr) // by texture lighting. This is for colourising things held in 3rd person view.
iihr->renderItem(mob, helmet, 0, true); 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<Entity> 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();
} }
} }

View file

@ -4,14 +4,17 @@
class ModelPart; class ModelPart;
class LivingEntity; class LivingEntity;
class LivingEntityRenderer; class LivingEntityRenderer;
class TileRenderer;
class CustomHeadLayer : public RenderLayer { class CustomHeadLayer : public RenderLayer {
public: public:
ModelPart* headPart; ModelPart* headPart;
LivingEntityRenderer* parentRenderer; LivingEntityRenderer* parentRenderer;
TileRenderer* tileRenderer;
CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer); CustomHeadLayer(ModelPart* headPart, LivingEntityRenderer* parentRenderer);
virtual ~CustomHeadLayer() {} virtual ~CustomHeadLayer();
virtual int colorsOnDamage() override; virtual int colorsOnDamage() override;
virtual void render(shared_ptr<LivingEntity> mob, virtual void render(shared_ptr<LivingEntity> mob,

View file

@ -8,6 +8,15 @@ GuiParticles::GuiParticles(Minecraft *mc)
this->mc = mc; this->mc = mc;
} }
GuiParticles::~GuiParticles()
{
for (GuiParticle *gp : particles)
{
delete gp;
}
particles.clear();
}
void GuiParticles::tick() void GuiParticles::tick()
{ {
for (unsigned int i = 0; i < particles.size(); i++) for (unsigned int i = 0; i < particles.size(); i++)
@ -19,6 +28,7 @@ void GuiParticles::tick()
if (gp->removed) if (gp->removed)
{ {
delete gp;
particles.erase(particles.begin()+i); particles.erase(particles.begin()+i);
i--; i--;
} }

View file

@ -13,6 +13,7 @@ private:
public: public:
GuiParticles(Minecraft *mc); GuiParticles(Minecraft *mc);
~GuiParticles();
void tick(); void tick();
void add(GuiParticle *guiParticle); void add(GuiParticle *guiParticle);
void render(float a); void render(float a);

View file

@ -555,7 +555,7 @@ void LivingEntityRenderer::renderName(shared_ptr<LivingEntity> mob, double x, do
bool LivingEntityRenderer::shouldShowName(shared_ptr<LivingEntity> mob) bool LivingEntityRenderer::shouldShowName(shared_ptr<LivingEntity> 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<LivingEntity> mob, double x, double y, double z, const wstring &msg, float scale, double dist) void LivingEntityRenderer::renderNameTags(shared_ptr<LivingEntity> mob, double x, double y, double z, const wstring &msg, float scale, double dist)

View file

@ -10,7 +10,14 @@ public:
int id; int id;
bool isLoaded; bool isLoaded;
int ticksSinceLastUse; int ticksSinceLastUse;
static const int UNUSED_TICKS_TO_FREE = 20; // @CDevJoud
// changing the lifetime of the texture from 20 ticks(1 sec) to 200 ticks (10 sec)
// as it helps the texture to have longer lifetime and reducing the usage of loadTexture for every second/frame
// note that we dont remove the code that removes the textures from `tick()` as it is required in memory limited environment such as older Consoles(PS3/XBOX360)
static const int UNUSED_TICKS_TO_FREE = 200;
//default ctor for int Texture::getHeight(const wstring& url, int backup)
MemTexture() = default;
MemTexture(const wstring& _name, PBYTE pbData, DWORD dwBytes, MemTextureProcessor *processor); MemTexture(const wstring& _name, PBYTE pbData, DWORD dwBytes, MemTextureProcessor *processor);
~MemTexture(); ~MemTexture();

View file

@ -526,9 +526,10 @@ LevelStorageSource *Minecraft::getLevelSource()
void Minecraft::setScreen(Screen *screen) void Minecraft::setScreen(Screen *screen)
{ {
if (this->screen != nullptr) Screen *oldScreen = this->screen;
if (oldScreen != nullptr)
{ {
this->screen->removed(); oldScreen->removed();
} }
#ifdef _WINDOWS64 #ifdef _WINDOWS64
@ -4438,6 +4439,8 @@ void Minecraft::setLevel(MultiPlayerLevel *level, int message /*=-1*/, shared_pt
// 4J If we are setting the level to nullptr then we are exiting, so delete the levels // 4J If we are setting the level to nullptr then we are exiting, so delete the levels
if( level == nullptr ) if( level == nullptr )
{ {
if (soundEngine) soundEngine->stopElytraSound();
if(levels[0]!=nullptr) if(levels[0]!=nullptr)
{ {
delete levels[0]; delete levels[0];

View file

@ -1046,6 +1046,13 @@ void PlayerConnection::handleCommand(const wstring& message)
ss >> cmd; ss >> cmd;
if (cmd == L"tp" || cmd == L"teleport") 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)) if (!player->hasPermission(eGameCommand_Teleport))
{ {
warn(L"You do not have permission to use this command."); 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") } 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)) if (!player->hasPermission(eGameCommand_Time))
{ {
warn(L"You do not have permission to use this command."); 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") 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)) if (!player->hasPermission(eGameCommand_Kill))
{ {
warn(L"You do not have permission to use this command."); warn(L"You do not have permission to use this command.");
return; return;
} }
wstring targetName;
ss >> targetName;
if (targetName.empty())
{
server->getCommandDispatcher()->performCommand(player, eGameCommand_Kill, byteArray()); 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") 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)) if (!player->hasPermission(eGameCommand_ToggleDownfall))
{ {
warn(L"You do not have permission to use this command."); warn(L"You do not have permission to use this command.");
@ -1285,6 +1328,14 @@ if (cmd == L"tp" || cmd == L"teleport")
shared_ptr<GameCommandPacket> packet = ToggleDownfallCommand::preparePacket(); shared_ptr<GameCommandPacket> packet = ToggleDownfallCommand::preparePacket();
server->getCommandDispatcher()->performCommand(player, eGameCommand_ToggleDownfall, packet->data); server->getCommandDispatcher()->performCommand(player, eGameCommand_ToggleDownfall, packet->data);
} else if (cmd == L"gamemode") { } 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)) if (!player->hasPermission(eGameCommand_GameMode))
{ {
warn(L"You do not have permission to use this command."); warn(L"You do not have permission to use this command.");
@ -1323,6 +1374,13 @@ if (cmd == L"tp" || cmd == L"teleport")
shared_ptr<GameCommandPacket> packet = GameModeCommand::preparePacket(target, mode); shared_ptr<GameCommandPacket> packet = GameModeCommand::preparePacket(target, mode);
server->getCommandDispatcher()->performCommand(player, eGameCommand_GameMode, packet->data); server->getCommandDispatcher()->performCommand(player, eGameCommand_GameMode, packet->data);
} else if (cmd == L"give") { } 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)) if (!player->hasPermission(eGameCommand_Give))
{ {
warn(L"You do not have permission to use this command."); warn(L"You do not have permission to use this command.");
@ -1868,6 +1926,8 @@ void PlayerConnection::handleGameCommand(shared_ptr<GameCommandPacket> packet)
player->getName().c_str(), player->isModerator() ? 1 : 0, isHost ? 1 : 0, player->getName().c_str(), player->isModerator() ? 1 : 0, isHost ? 1 : 0,
static_cast<int>(packet->command)); static_cast<int>(packet->command));
#endif #endif
MinecraftServer::getInstance()->getCommandDispatcher()->performCommand(player, packet->command, packet->data); MinecraftServer::getInstance()->getCommandDispatcher()->performCommand(player, packet->command, packet->data);
} }

View file

@ -23,6 +23,18 @@ Screen::Screen() // 4J added
clickedButton = nullptr; clickedButton = nullptr;
} }
Screen::~Screen()
{
delete particles;
particles = nullptr;
for (Button *button : buttons)
{
delete button;
}
buttons.clear();
}
void Screen::render(int xm, int ym, float a) void Screen::render(int xm, int ym, float a)
{ {
for (Button* button : buttons) for (Button* button : buttons)

View file

@ -22,6 +22,7 @@ public:
GuiParticles *particles; GuiParticles *particles;
Screen(); // 4J added Screen(); // 4J added
virtual ~Screen();
virtual void render(int xm, int ym, float a); virtual void render(int xm, int ym, float a);
protected: protected:
virtual void keyPressed(wchar_t eventCharacter, int eventKey); virtual void keyPressed(wchar_t eventCharacter, int eventKey);

View file

@ -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<int> data) 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<int> data)
{ {
wchar_t buf[32];
swprintf_s(buf, L"%d", type->getId());
auto packet = make_shared<LevelParticlesPacket>( auto packet = make_shared<LevelParticlesPacket>(
type, buf,
longDistance,
(float)x, (float)y, (float)z, (float)x, (float)y, (float)z,
(float)dx, (float)dy, (float)dz, (float)dx, (float)dy, (float)dz,
(float)speed, (float)speed,
count, count
data
); );
for (auto const& p : players) for (auto const& p : players)

View file

@ -850,8 +850,10 @@ void ServerPlayer::die(DamageSource *source)
bool ServerPlayer::hurt(DamageSource *dmgSource, float dmg) bool ServerPlayer::hurt(DamageSource *dmgSource, float dmg)
{ {
if (isInvulnerable()) return false; if (isInvulnerable() && dmgSource != DamageSource::outOfWorld) return false;
if (gameMode == nullptr||gameMode->isCreative()) return false; if (gameMode == nullptr || gameMode->isCreative()) {
if (dmgSource != DamageSource::outOfWorld) return false;
}
// 4J: Not relevant to console servers // 4J: Not relevant to console servers
// Allow falldamage on dedicated pvpservers -- so people cannot cheat their way out of 'fall traps' // Allow falldamage on dedicated pvpservers -- so people cannot cheat their way out of 'fall traps'

View file

@ -1256,8 +1256,14 @@ int Textures::getHeight(const wstring& url, int backup)
if (img) if (img)
{ {
MemTexture* _texture = new MemTexture();
_texture->loadedImage = img;
_texture->isLoaded = true;
_texture->id = getTexture(_texture->loadedImage, C4JRender::TEXTURE_FORMAT_RxGyBzAw, MIPMAP);
int h = img->getHeight(); int h = img->getHeight();
delete img; //delete img; // commenting this out and inserting the loaded texture to memTextures unordered_map
this->memTextures[url] = _texture;
return h; return h;
} }

View file

@ -291,21 +291,50 @@ void TrackedEntity::tick(EntityTracker *tracker, vector<shared_ptr<Player> > *pl
} }
else else
{ {
// the entity have a rider, the code didnt send position updates,
// causing desync between client and server when boat was spritning.
bool rot = abs(yRotn - yRotp) >= TOLERANCE_LEVEL || abs(xRotn - xRotp) >= TOLERANCE_LEVEL; bool rot = abs(yRotn - yRotp) >= TOLERANCE_LEVEL || abs(xRotn - xRotp) >= TOLERANCE_LEVEL;
if (rot) if (rot)
{ {
// 4J: Changed this to use deltas
broadcast(std::make_shared<MoveEntityPacket::Rot>(e->entityId, static_cast<byte>(yRota), static_cast<byte>(xRota))); broadcast(std::make_shared<MoveEntityPacket::Rot>(e->entityId, static_cast<byte>(yRota), static_cast<byte>(xRota)));
yRotp = yRotn; yRotp = yRotn;
xRotp = xRotn; xRotp = xRotn;
} }
xp = Mth::floor(e->x * 32.0); int xn = Mth::floor(e->x * 32.0);
yp = Mth::floor(e->y * 32.0); int yn = Mth::floor(e->y * 32.0);
zp = Mth::floor(e->z * 32.0); int zn = Mth::floor(e->z * 32.0);
int xa = xn - xp;
int ya = yn - yp;
int za = zn - zp;
// send only if the boat moved enough
// or 3 seconds periodically
bool pos = abs(xa) >= TOLERANCE_LEVEL || abs(ya) >= TOLERANCE_LEVEL || abs(za) >= TOLERANCE_LEVEL
|| (tickCount % (SharedConstants::TICKS_PER_SECOND * 3) == 0);
if (pos)
{
// if deltapos is too much big use teleport.
if (xa < -128 || xa >= 128 || ya < -128 || ya >= 128 || za < -128 || za >= 128)
{
broadcast(std::make_shared<TeleportEntityPacket>(e->entityId, xn, yn, zn,
static_cast<byte>(yRotn), static_cast<byte>(xRotn)));
}
else
{
// small movement, delta
broadcast(std::make_shared<MoveEntityPacket::Pos>(e->entityId,
static_cast<char>(xa), static_cast<char>(ya), static_cast<char>(za)));
}
xp = xn;
yp = yn;
zp = zn;
}
sendDirtyEntityData(); sendDirtyEntityData();
wasRiding = true; wasRiding = true;
} }

View file

@ -149,47 +149,57 @@ static void CopyWideArgToAnsi(LPCWSTR source, char* dest, size_t destSize)
dest[destSize - 1] = 0; dest[destSize - 1] = 0;
} }
// ---------- Persistent options (options.txt next to exe) ---------- // ---------- Persistent options (options.dat next to exe) ----------
static void GetOptionsFilePath(char *out, size_t outSize) static void GetOptionsFilePath(char *out, DWORD outSize)
{ {
GetModuleFileNameA(nullptr, out, static_cast<DWORD>(outSize)); GetModuleFileNameA(nullptr, out, outSize);
char *p = strrchr(out, '\\'); char *p = strrchr(out, '\\');
if (p) *(p + 1) = '\0'; if (p) *(p + 1) = '\0';
strncat_s(out, outSize, "options.txt", _TRUNCATE); strncat_s(out, outSize, "settings.dat", _TRUNCATE);
} }
static void SaveFullscreenOption(bool fullscreen) static void SaveFullscreenOption(bool fullscreen)
{ {
char path[MAX_PATH]; GAME_SETTINGS settings = {};
GetOptionsFilePath(path, sizeof(path));
char path[MAX_PATH] = {};
GetOptionsFilePath(path, MAX_PATH);
FILE *f = nullptr; FILE *f = nullptr;
if (fopen_s(&f, path, "w") == 0 && f) if (fopen_s(&f, path, "rb") == 0 && f)
{ {
fprintf(f, "fullscreen=%d\n", fullscreen ? 1 : 0); fread(&settings, sizeof(GAME_SETTINGS), 1, f);
fclose(f);
}
if (fullscreen)
settings.uiBitmaskValues |= (1UL << 25);
else
settings.uiBitmaskValues &= ~(1UL << 25);
if (fopen_s(&f, path, "wb") == 0 && f)
{
fwrite(&settings, sizeof(GAME_SETTINGS), 1, f);
fclose(f); fclose(f);
} }
} }
static bool LoadFullscreenOption() static bool LoadFullscreenOption()
{ {
char path[MAX_PATH]; char path[MAX_PATH] = {};
GetOptionsFilePath(path, sizeof(path)); GetOptionsFilePath(path, sizeof(path));
FILE *f = nullptr; FILE *f = nullptr;
if (fopen_s(&f, path, "r") == 0 && f) if (fopen_s(&f, path, "rb") != 0 || !f)
{
char line[256];
while (fgets(line, sizeof(line), f))
{
int val = 0;
if (sscanf_s(line, "fullscreen=%d", &val) == 1)
{
fclose(f);
return val != 0;
}
}
fclose(f);
}
return false; return false;
GAME_SETTINGS current = {};
bool ok = (fread(&current, sizeof(GAME_SETTINGS), 1, f) == 1);
fclose(f);
if (!ok)
return false;
return (current.uiBitmaskValues & (1UL << 25)) != 0;
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
@ -824,8 +834,7 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
return FALSE; return FALSE;
} }
ShowWindow(g_hWnd, (nCmdShow != SW_HIDE) ? SW_SHOWMAXIMIZED : nCmdShow);
UpdateWindow(g_hWnd);
return TRUE; return TRUE;
} }
@ -1456,8 +1465,9 @@ void CleanupDevice()
static Minecraft* InitialiseMinecraftRuntime() static Minecraft* InitialiseMinecraftRuntime()
{ {
app.loadMediaArchive(); app.loadMediaArchive();
// @CDevJoud: No need to call this method as it gets called once in `InitDevice()`
RenderManager.Initialise(g_pd3dDevice, g_pSwapChain); // Calling it again and it results of 20MB of memory leak!
//RenderManager.Initialise(g_pd3dDevice, g_pSwapChain);
app.loadStringTable(); app.loadStringTable();
ui.init(g_pd3dDevice, g_pImmediateContext, g_pRenderTargetView, g_pDepthStencilView, g_rScreenWidth, g_rScreenHeight); ui.init(g_pd3dDevice, g_pImmediateContext, g_pRenderTargetView, g_pDepthStencilView, g_rScreenWidth, g_rScreenHeight);
@ -1695,11 +1705,12 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
CleanupDevice(); CleanupDevice();
return 0; return 0;
} }
// Restore fullscreen state from previous session. Route through the // Restore fullscreen state from previous session. Route through the
// deferred exclusive fullscreen path so the main loop applies it on the // deferred exclusive fullscreen path so the main loop applies it on the
// first tick (safer than transitioning during init). // first tick (safer than transitioning during init).
if ((LoadFullscreenOption() && !g_isFullscreen) || launchOptions.fullscreen)
bool FullScreenEnabled = LoadFullscreenOption();
if (FullScreenEnabled && !g_isFullscreen)
{ {
g_bPendingExclusiveFullscreen = true; g_bPendingExclusiveFullscreen = true;
g_bPendingExclusiveFullscreenValue = true; g_bPendingExclusiveFullscreenValue = true;
@ -1790,6 +1801,20 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
hr = XuiTimersRun(); hr = XuiTimersRun();
} }
#endif #endif
// @CDevJoud The window should only be shown after the engine/game
// initialization has fully completed.
//
// Showing the window too early especially on low end devices,
// may cause windows to display a "Not Responding" state while
// initialization is still in progress.
//
// This creates an unprofessional first impression for the player.
// Instead, initialize all engine systems first, then display the
// window once everything is ready.
ShowWindow(g_hWnd, (nCmdShow != SW_HIDE) ? SW_SHOWMAXIMIZED : nCmdShow);
UpdateWindow(g_hWnd);
MSG msg = {0}; MSG msg = {0};
while( WM_QUIT != msg.message && !app.m_bShutdown) while( WM_QUIT != msg.message && !app.m_bShutdown)
{ {

View file

@ -1281,10 +1281,9 @@ void __cdecl NativeSpawnParticle(int entityId, int particleId, float x, float y,
{ {
auto player = FindPlayer(entityId); auto player = FindPlayer(entityId);
if (!player || !player->connection) return; if (!player || !player->connection) return;
const ParticleType* type = ParticleType::byId(particleId); wchar_t buf[32];
if (!type) type = ParticleType::getDefault(); swprintf_s(buf, L"%d", particleId);
arrayWithLength<int> noParams = { nullptr, 0 }; player->connection->send(std::make_shared<LevelParticlesPacket>(std::wstring(buf), x, y, z, offsetX, offsetY, offsetZ, speed, count));
player->connection->send(std::make_shared<LevelParticlesPacket>(type, false, x, y, z, offsetX, offsetY, offsetZ, speed, count, noParams));
} }
int __cdecl NativeSetPassenger(int entityId, int passengerEntityId) int __cdecl NativeSetPassenger(int entityId, int passengerEntityId)

View file

@ -54,10 +54,16 @@ AABB *AABB::newPermanent(double x0, double y0, double z0, double x1, double y1,
void AABB::clearPool() void AABB::clearPool()
{ {
ThreadStorage *tls = static_cast<ThreadStorage *>(TlsGetValue(tlsIdx));
if (tls != nullptr)
{
tls->poolPointer = 0;
}
} }
void AABB::resetPool() void AABB::resetPool()
{ {
clearPool();
} }
AABB *AABB::newTemp(double x0, double y0, double z0, double x1, double y1, double z1) AABB *AABB::newTemp(double x0, double y0, double z0, double x1, double y1, double z1)

View file

@ -16,11 +16,12 @@
#include "ParticleTypes.h" #include "ParticleTypes.h"
#include "Random.h" #include "Random.h"
#include "AABB.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_HEAD_POSE (0.0f, 0.0f, 0.0f);
const Rotations ArmorStand::DEFAULT_BODY_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_LEFT_ARM_POSE (-15.0f, 0.0f, 10.0f);
const Rotations ArmorStand::DEFAULT_RIGHT_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_LEFT_LEG_POSE (-1.0f, 0.0f, -1.0f);
const Rotations ArmorStand::DEFAULT_RIGHT_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++) for (int i = 0; i < equipmentCount; i++)
equipment[i] = nullptr; equipment[i] = nullptr;
rotateElytraX = 0.2617994f;
rotateElytraY = 0.0f;
rotateElytraZ = -0.2617994f;
headPose = DEFAULT_HEAD_POSE; headPose = DEFAULT_HEAD_POSE;
bodyPose = DEFAULT_BODY_POSE; bodyPose = DEFAULT_BODY_POSE;
leftArmPose = DEFAULT_LEFT_ARM_POSE; leftArmPose = DEFAULT_LEFT_ARM_POSE;
@ -83,7 +88,7 @@ void ArmorStand::defineSynchedData()
ArmorStand::~ArmorStand() {} 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::isBaby() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SMALL) != 0; }
bool ArmorStand::isSmall() const { return isBaby(); } bool ArmorStand::isSmall() const { return isBaby(); }
bool ArmorStand::isShowArms() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SHOW_ARMS) != 0; } bool ArmorStand::isShowArms() const { return (entityData->getByte(DATA_CLIENT_FLAGS) & FLAG_SHOW_ARMS) != 0; }
@ -188,6 +193,93 @@ void ArmorStand::updateInvisibilityStatus()
setInvisible(invisible); 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<int>(x), 0, static_cast<int>(z)) && level->getChunkAt(static_cast<int>(x), static_cast<int>(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() void ArmorStand::tick()
{ {

View file

@ -56,6 +56,10 @@ private:
bool isMarkerFlag; bool isMarkerFlag;
bool noPhysics; bool noPhysics;
float standDamage; float standDamage;
public:
float rotateElytraX;
float rotateElytraY;
float rotateElytraZ;
public: public:
long long lastHit; long long lastHit;
@ -64,6 +68,7 @@ public:
explicit ArmorStand(Level* level); explicit ArmorStand(Level* level);
virtual ~ArmorStand(); virtual ~ArmorStand();
bool hasPhysics() const;
bool isBaby() const; bool isBaby() const;
bool isSmall() const; bool isSmall() const;
bool isShowArms() const; bool isShowArms() const;
@ -142,6 +147,8 @@ public:
void updateBoundingBox(bool markerMode); void updateBoundingBox(bool markerMode);
void updateInvisibilityStatus(); void updateInvisibilityStatus();
virtual void travel(float xz, float ya);
virtual shared_ptr<ItemInstance> getCarriedItem() override; virtual shared_ptr<ItemInstance> getCarriedItem() override;
virtual shared_ptr<ItemInstance> getCarried(int slot) override; virtual shared_ptr<ItemInstance> getCarried(int slot) override;
virtual shared_ptr<ItemInstance> getArmor(int pos) override; virtual shared_ptr<ItemInstance> getArmor(int pos) override;

View file

@ -8,7 +8,7 @@
const BlockPos BlockPos::ZERO = BlockPos(0, 0, 0); const BlockPos BlockPos::ZERO = BlockPos(0, 0, 0);
// Costruttori
BlockPos::BlockPos() : Vec3i(0, 0, 0) {} BlockPos::BlockPos() : Vec3i(0, 0, 0) {}
BlockPos::BlockPos(int x, int y, int z) : Vec3i(x, y, z) {} BlockPos::BlockPos(int x, int y, int z) : Vec3i(x, y, z) {}
@ -49,7 +49,7 @@ BlockPos::BlockPos(int compressed) : Vec3i(0, 0, 0) {
BlockPos::BlockPos(BlockSource& source) BlockPos::BlockPos(BlockSource& source)
: Vec3i(source.getBlockX(), source.getBlockY(), source.getBlockZ()) {} : Vec3i(source.getBlockX(), source.getBlockY(), source.getBlockZ()) {}
// Metodi di confronto
bool BlockPos::equals(const BlockPos& other) const { bool BlockPos::equals(const BlockPos& other) const {
return x == other.x && y == other.y && z == other.z; return x == other.x && y == other.y && z == other.z;
} }
@ -88,7 +88,7 @@ BlockPos BlockPos::relative(int direction, int distance) const {
return BlockPos(x + dx, y, z + dz); return BlockPos(x + dx, y, z + dz);
} }
// Metodi direzionali // directional methods
BlockPos BlockPos::above(int distance) const { BlockPos BlockPos::above(int distance) const {
return BlockPos(x, y + distance, z); return BlockPos(x, y + distance, z);
} }
@ -119,7 +119,7 @@ BlockPos BlockPos::multiply(int factor) const {
return BlockPos(x * factor, y * factor, z * factor); return BlockPos(x * factor, y * factor, z * factor);
} }
// Compressione // compression
int BlockPos::compress() const { int BlockPos::compress() const {
static const int MASK_X = (1 << BITS_X) - 1; static const int MASK_X = (1 << BITS_X) - 1;
static const int MASK_Y = (1 << BITS_Y) - 1; static const int MASK_Y = (1 << BITS_Y) - 1;

View file

@ -188,6 +188,10 @@ void Boat::lerpMotion(double xd, double yd, double zd)
void Boat::tick() void Boat::tick()
{ {
Entity::tick(); Entity::tick();
if (getHurtTime() > 0) setHurtTime(getHurtTime() - 1); if (getHurtTime() > 0) setHurtTime(getHurtTime() - 1);
if (getDamage() > 0) setDamage(getDamage() - 1); if (getDamage() > 0) setDamage(getDamage() - 1);
xo = x; xo = x;
@ -199,8 +203,8 @@ void Boat::tick()
double waterPercentage = 0; double waterPercentage = 0;
for (int i = 0; i < steps; i++) for (int i = 0; i < steps; i++)
{ {
double y0 = bb->y0 + (bb->y1 - bb->y0) * (i + 0) / steps - 2 / 16.0f; double y0 = bb->y0 + (bb->y1 - bb->y0) * (i + 0) / steps + 1.5f / 16.0f;
double y1 = bb->y0 + (bb->y1 - bb->y0) * (i + 1) / steps - 2 / 16.0f; double y1 = bb->y0 + (bb->y1 - bb->y0) * (i + 1) / steps + 1.5f / 16.0f;
AABB *bb2 = AABB::newTemp(bb->x0, y0, bb->z0, bb->x1, y1, bb->z1); AABB *bb2 = AABB::newTemp(bb->x0, y0, bb->z0, bb->x1, y1, bb->z1);
if (level->containsLiquid(bb2, Material::water)) if (level->containsLiquid(bb2, Material::water))
{ {
@ -257,18 +261,19 @@ void Boat::tick()
return; return;
} }
// Bob in water // Bob in water & gravity
if (waterPercentage > 0) if (waterPercentage < 1.0)
{ {
double bob = waterPercentage * 2 - 1; double bob = waterPercentage * 2.0 - 1.0;
yd += 0.04f * bob; yd += 0.04f * bob;
} }
else
// Reimplement gravity again (??)
int tileUnder = level->getTile(Mth::floor(x), Mth::floor(y-0.15), Mth::floor(z));
if (tileUnder == 0 && !onGround)
{ {
yd -= 0.04f; if (yd < 0.0)
{
yd /= 2.0;
}
yd += 0.007f;
} }
// Rider controls // Rider controls
@ -281,24 +286,16 @@ void Boat::tick()
{ {
double riderXd = -sin(livingRider->yRot * PI / 180); double riderXd = -sin(livingRider->yRot * PI / 180);
double riderZd = cos(livingRider->yRot * PI / 180); double riderZd = cos(livingRider->yRot * PI / 180);
float mult = livingRider->isSprinting() ? 2.0f : 1.0f; double currentSpeed = sqrt(xd * xd + zd * zd);
float moveFactor = (float)forward; float moveFactor = (float)forward;
if (forward < 0) moveFactor *= 0.5f; // Move slower backwards if (forward < 0) moveFactor *= 0.5f; // Move slower backwards
xd += riderXd * acceleration * 0.05f * mult * moveFactor; xd += riderXd * acceleration * 0.05f * moveFactor;
zd += riderZd * acceleration * 0.05f * mult * moveFactor; zd += riderZd * acceleration * 0.05f * moveFactor;
} }
} }
double curSpeed = sqrt(xd * xd + zd * zd); double curSpeed = sqrt(xd * xd + zd * zd);
double maxSpeed = MAX_SPEED; double maxSpeed = MAX_SPEED;
if (rider.lock() != nullptr && rider.lock()->instanceof(eTYPE_LIVINGENTITY))
{
shared_ptr<LivingEntity> livingRider = dynamic_pointer_cast<LivingEntity>(rider.lock());
if (livingRider->isSprinting())
{
maxSpeed *= 1.5;
}
}
if (curSpeed > maxSpeed) if (curSpeed > maxSpeed)
{ {
@ -330,10 +327,12 @@ void Boat::tick()
move(xd, yd, zd); move(xd, yd, zd);
// Break boat on high speed collision // Break boat on high speed collision
float breakThreshold = (rider.lock() != nullptr) ? 0.35f : 0.20f;
if ((horizontalCollision && lastSpeed > 0.20)) if ((horizontalCollision && lastSpeed > 0.20))
{ {
if (!level->isClientSide && !removed) if (!level->isClientSide && !removed)
{ {
remove(); remove();
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
@ -343,6 +342,9 @@ void Boat::tick()
{ {
spawnAtLocation(Item::stick->id, 1, 0); spawnAtLocation(Item::stick->id, 1, 0);
} }
} }
} }
else else
@ -472,8 +474,17 @@ bool Boat::interact(shared_ptr<Player> player)
if ( (rider.lock() != nullptr) && rider.lock()->instanceof(eTYPE_PLAYER) && (rider.lock() != player) ) return true; if ( (rider.lock() != nullptr) && rider.lock()->instanceof(eTYPE_PLAYER) && (rider.lock() != player) ) return true;
if (!level->isClientSide) if (!level->isClientSide)
{ {
bool isRiding = (rider.lock() == player);
if (isRiding)
{
player->xd = 0;
player->yd = 0;
player->zd = 0;
}
// 4J HEG - Fixed issue with player not being able to dismount boat (issue #4446) // 4J HEG - Fixed issue with player not being able to dismount boat (issue #4446)
player->ride( rider.lock() == player ? nullptr : shared_from_this() ); player->ride(isRiding ? nullptr : shared_from_this());
} }
return true; return true;
} }

View file

@ -38,6 +38,8 @@ void ClothDyeRecipes::addRecipes(Recipes *r)
} }
// some dye recipes // some dye recipes
//flowers
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::YELLOW), r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::YELLOW),
L"tg", L"tg",
Tile::flower,L'D'); Tile::flower,L'D');
@ -46,6 +48,44 @@ void ClothDyeRecipes::addRecipes(Recipes *r)
L"tg", L"tg",
Tile::rose,L'D'); Tile::rose,L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::LIGHT_BLUE),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::BLUE_ORCHID), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::MAGENTA),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::ALLIUM), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::SILVER),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::AZURE_BLUET), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::RED_TULIP), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::PINK),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::PINK_TULIP), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::SILVER),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::WHITE_TULIP), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::ORANGE),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::ORANGE_TULIP), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 1, DyePowderItem::SILVER),
L"zg", new ItemInstance(Item::items[Tile::rose_Id], 1, Rose::OXEYE_DAISY), L'D');
// Tall flowers
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::YELLOW),
L"zg", new ItemInstance(Item::items[Tile::tallgrass2_Id], 1, TallGrass2::SUNFLOWER), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::MAGENTA),
L"zg", new ItemInstance(Item::items[Tile::tallgrass2_Id], 1, TallGrass2::LILAC), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::RED),
L"zg", new ItemInstance(Item::items[Tile::tallgrass2_Id], 1, TallGrass2::ROSE_BUSH), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::MAGENTA),
L"zg", new ItemInstance(Item::items[Tile::tallgrass2_Id], 1, TallGrass2::PEONY), L'D');
r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::WHITE), r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::WHITE),
L"ig", L"ig",
Item::bone,L'D'); Item::bone,L'D');
@ -114,6 +154,9 @@ void ClothDyeRecipes::addRecipes(Recipes *r)
new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED),
new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D');
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
r->addShapedRecipy(new ItemInstance(Tile::woolCarpet, 3, i), r->addShapedRecipy(new ItemInstance(Tile::woolCarpet, 3, i),

View file

@ -1170,6 +1170,12 @@ bool EnderDragon::hurt(shared_ptr<MultiEntityMobPart> MultiEntityMobPart, Damage
bool EnderDragon::hurt(DamageSource *source, float damage) bool EnderDragon::hurt(DamageSource *source, float damage)
{ {
if (source == DamageSource::outOfWorld)
{
setSynchedAction(e_EnderdragonAction_Sitting_Scanning, true);
reallyHurt(source, getMaxHealth() + 1);
return true;
}
return false; return false;
} }

View file

@ -0,0 +1,118 @@
#include "stdafx.h"
#include "EntityTypeMap.h"
static const unordered_map<wstring, eINSTANCEOF> 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<eINSTANCEOF, wstring> s_typeToName = []()
{
unordered_map<eINSTANCEOF, wstring> m;
for (auto& pair : s_nameToType)
{
if (m.find(pair.second) == m.end())
m[pair.second] = pair.first;
}
return m;
}();
const unordered_map<wstring, eINSTANCEOF>& EntityTypeMap::getNameToTypeMap()
{
return s_nameToType;
}
const unordered_map<eINSTANCEOF, wstring>& 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;
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "../Minecraft.World/Class.h"
#include <unordered_map>
#include <string>
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<wstring, eINSTANCEOF>& getNameToTypeMap();
static const unordered_map<eINSTANCEOF, wstring>& getTypeToNameMap();
};

View file

@ -1,9 +1,29 @@
#include "stdafx.h" #include "stdafx.h"
#include "net.minecraft.commands.h" #include "net.minecraft.commands.h"
#include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.entity.player.h"
#include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.damagesource.h"
#include "net.minecraft.world.level.h"
#include "BasicTypeContainers.h" #include "BasicTypeContainers.h"
#include "KillCommand.h" #include "KillCommand.h"
#include "EntityTypeMap.h"
static void killEntity(shared_ptr<Entity> entity)
{
if (entity->instanceof(eTYPE_LIVINGENTITY))
{
auto living = dynamic_pointer_cast<LivingEntity>(entity);
if (living != nullptr)
{
living->hurt(DamageSource::outOfWorld, Float::MAX_VALUE);
return;
}
entity->remove();
return;
}
entity->remove();
}
EGameCommand KillCommand::getId() EGameCommand KillCommand::getId()
{ {
@ -17,10 +37,161 @@ int KillCommand::getPermissionLevel()
void KillCommand::execute(shared_ptr<CommandSender> source, byteArray commandData) void KillCommand::execute(shared_ptr<CommandSender> source, byteArray commandData)
{ {
shared_ptr<Player> player = dynamic_pointer_cast<Player>(source); shared_ptr<Player> senderPlayer = dynamic_pointer_cast<Player>(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<shared_ptr<Player>> 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<Player> nearest = level->getNearestPlayer(
dynamic_pointer_cast<Entity>(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=<entity_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<shared_ptr<Entity>> 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<Player> 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.");
} }

View file

@ -1,34 +1,23 @@
 #include "stdafx.h"
#include "stdafx.h"
#include "PacketListener.h" #include "PacketListener.h"
#include "LevelParticlesPacket.h" #include "LevelParticlesPacket.h"
#include "../Minecraft.Client/ParticleType.h"
LevelParticlesPacket::LevelParticlesPacket() LevelParticlesPacket::LevelParticlesPacket()
{ {
this->name = L"";
this->overrideLimiter = false;
this->type = nullptr;
this->count = 0;
this->y = 0.0f;
this->paramCount = 0;
this->x = 0.0f; this->x = 0.0f;
this->y = 0.0f;
this->z = 0.0f;
this->xDist = 0.0f;
this->yDist = 0.0f; this->yDist = 0.0f;
this->zDist = 0.0f; this->zDist = 0.0f;
this->z = 0.0f;
this->maxSpeed = 0.0f; this->maxSpeed = 0.0f;
this->xDist = 0.0f; this->count = 0;
this->params = nullptr;
} }
LevelParticlesPacket::LevelParticlesPacket(const ParticleType* type, bool overrideLimiter, LevelParticlesPacket::LevelParticlesPacket(const wstring& name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count)
float x, float y, float z,
float xDist, float yDist, float zDist,
float maxSpeed, int count,
arrayWithLength<int> data)
{ {
this->type = type; this->name = name;
this->overrideLimiter = overrideLimiter;
this->x = x; this->x = x;
this->y = y; this->y = y;
this->z = z; this->z = z;
@ -37,83 +26,77 @@ LevelParticlesPacket::LevelParticlesPacket(const ParticleType* type, bool overri
this->zDist = zDist; this->zDist = zDist;
this->maxSpeed = maxSpeed; this->maxSpeed = maxSpeed;
this->count = count; 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;
}
} }
void LevelParticlesPacket::read(DataInputStream* dis) void LevelParticlesPacket::read(DataInputStream* dis)
{ {
int particleId = dis->readInt(); name = readUtf(dis, 64);
const ParticleType* resolved = ParticleType::byId(particleId); x = dis->readFloat();
if (!resolved) y = dis->readFloat();
resolved = ParticleType::getDefault(); z = dis->readFloat();
this->type = resolved; xDist = dis->readFloat();
yDist = dis->readFloat();
this->overrideLimiter = dis->readBoolean(); zDist = dis->readFloat();
maxSpeed = dis->readFloat();
this->x = dis->readFloat(); count = dis->readInt();
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;
}
} }
void LevelParticlesPacket::write(DataOutputStream* dos) void LevelParticlesPacket::write(DataOutputStream* dos)
{ {
dos->writeInt(this->type ? this->type->getId() : 0); writeUtf(name, dos);
dos->writeBoolean(this->overrideLimiter); dos->writeFloat(x);
dos->writeFloat(this->x); dos->writeFloat(y);
dos->writeFloat(this->y); dos->writeFloat(z);
dos->writeFloat(this->z); dos->writeFloat(xDist);
dos->writeFloat(this->xDist); dos->writeFloat(yDist);
dos->writeFloat(this->yDist); dos->writeFloat(zDist);
dos->writeFloat(this->zDist); dos->writeFloat(maxSpeed);
dos->writeFloat(this->maxSpeed); dos->writeInt(count);
dos->writeInt(this->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) void LevelParticlesPacket::handle(PacketListener* listener)
@ -123,5 +106,5 @@ void LevelParticlesPacket::handle(PacketListener* listener)
int LevelParticlesPacket::getEstimatedSize() int LevelParticlesPacket::getEstimatedSize()
{ {
return 0x40; return 4 * 2 + 7 * 8;
} }

View file

@ -1,13 +1,11 @@
#pragma once #pragma once
#include "Packet.h" #include "Packet.h"
#include "../Minecraft.Client/ParticleType.h"
class LevelParticlesPacket : public Packet, public enable_shared_from_this<LevelParticlesPacket> class LevelParticlesPacket : public Packet, public enable_shared_from_this<LevelParticlesPacket>
{ {
private: private:
wstring name;
const ParticleType* type;
float x; float x;
float y; float y;
float z; float z;
@ -16,38 +14,26 @@ private:
float zDist; float zDist;
float maxSpeed; float maxSpeed;
int count; int count;
bool overrideLimiter;
int* params;
int paramCount;
public: public:
LevelParticlesPacket(); LevelParticlesPacket();
LevelParticlesPacket(const ParticleType* type, bool overrideLimiter, LevelParticlesPacket(const wstring& name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count);
float x, float y, float z,
float xDist, float yDist, float zDist,
float maxSpeed, int count,
arrayWithLength<int> data);
~LevelParticlesPacket();
void read(DataInputStream* dis) override; void read(DataInputStream* dis);
void write(DataOutputStream* dos) override; void write(DataOutputStream* dos);
wstring getName();
const ParticleType* getType() { return type; } double getX();
double getX() { return x; } double getY();
double getY() { return y; } double getZ();
double getZ() { return z; } float getXDist();
double getXDist() { return xDist; } float getYDist();
double getYDist() { return yDist; } float getZDist();
double getZDist() { return zDist; } float getMaxSpeed();
double getMaxSpeed() { return maxSpeed; } int getCount();
int getCount() { return count; } void handle(PacketListener* listener);
bool isOverrideLimiter() { return overrideLimiter; } int getEstimatedSize();
int* getParams() { return params; }
int getParamCount() { return paramCount; }
void handle(PacketListener* listener) override;
int getEstimatedSize() override;
public:
static shared_ptr<Packet> create() { return std::make_shared<LevelParticlesPacket>(); } static shared_ptr<Packet> create() { return std::make_shared<LevelParticlesPacket>(); }
virtual int getId() override { return 63; } virtual int getId() { return 63; }
}; };

View file

@ -51,9 +51,10 @@ public:
static const int DATA_ARROW_COUNT_ID = 9; static const int DATA_ARROW_COUNT_ID = 9;
private: private:
BaseAttributeMap* attributes;
CombatTracker* combatTracker; CombatTracker* combatTracker;
unordered_map<int, MobEffectInstance*> activeEffects; unordered_map<int, MobEffectInstance*> activeEffects;
protected:
BaseAttributeMap* attributes;
ItemInstanceArray lastEquipment; ItemInstanceArray lastEquipment;
public: public:

View file

@ -35,13 +35,16 @@ Ocelot::Ocelot(Level *level) : TamableAnimal(level)
registerAttributes(); registerAttributes();
setHealth(getMaxHealth()); setHealth(getMaxHealth());
avoidPlayerGoal = nullptr;
reassessTameGoals();
setSize(0.6f, 0.8f); setSize(0.6f, 0.8f);
getNavigation()->setAvoidWater(true); getNavigation()->setAvoidWater(true);
goalSelector.addGoal(1, new FloatGoal(this)); goalSelector.addGoal(1, new FloatGoal(this));
goalSelector.addGoal(2, sitGoal, false); goalSelector.addGoal(2, sitGoal, false);
goalSelector.addGoal(3, temptGoal = new TemptGoal(this, SNEAK_SPEED_MOD, Item::fish_raw_Id, true), 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(5, new FollowOwnerGoal(this, FOLLOW_SPEED_MOD, 10, 5));
goalSelector.addGoal(6, new OcelotSitOnTileGoal(this, SPRINT_SPEED_MOD)); goalSelector.addGoal(6, new OcelotSitOnTileGoal(this, SPRINT_SPEED_MOD));
goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3f)); goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3f));
@ -60,6 +63,21 @@ void Ocelot::defineSynchedData()
entityData->define(DATA_TYPE_ID, static_cast<byte>(0)); entityData->define(DATA_TYPE_ID, static_cast<byte>(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() void Ocelot::serverAiMobStep()
{ {
if (getMoveControl()->hasWanted()) if (getMoveControl()->hasWanted())
@ -199,7 +217,10 @@ bool Ocelot::mobInteract(shared_ptr<Player> player)
} }
else 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 // 4J-PB - don't lose the fish in creative mode
if (!player->abilities.instabuild) item->count--; if (!player->abilities.instabuild) item->count--;
@ -284,6 +305,8 @@ void Ocelot::setCatType(int type)
bool Ocelot::canSpawn() bool Ocelot::canSpawn()
{ {
//return level->random->nextInt(3) != 0; when checkSpawnObstruction is implemented
// artificially make ozelots more rare // artificially make ozelots more rare
if (level->random->nextInt(3) == 0) if (level->random->nextInt(3) == 0)
{ {

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "TamableAnimal.h" #include "TamableAnimal.h"
#include "AvoidPlayerGoal.h"
class TemptGoal; class TemptGoal;
@ -32,6 +33,7 @@ public:
private: private:
TemptGoal *temptGoal; TemptGoal *temptGoal;
AvoidPlayerGoal *avoidPlayerGoal;
public: public:
Ocelot(Level *level); Ocelot(Level *level);
@ -41,6 +43,8 @@ protected:
public: public:
virtual void serverAiMobStep(); virtual void serverAiMobStep();
virtual void reassessTameGoals();
virtual void setTame(bool tame);
protected: protected:
virtual bool removeWhenFarAway(); virtual bool removeWhenFarAway();
@ -78,6 +82,7 @@ public:
virtual int getCatType(); virtual int getCatType();
virtual void setCatType(int type); virtual void setCatType(int type);
virtual bool canSpawn(); virtual bool canSpawn();
//virtual bool checkSpawnObstruction(); TODO when blockstates will be merged.
virtual wstring getAName(); virtual wstring getAName();
virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param

View file

@ -49,10 +49,16 @@ Vec3 *Vec3::newPermanent(double x, double y, double z)
void Vec3::clearPool() void Vec3::clearPool()
{ {
ThreadStorage *tls = static_cast<ThreadStorage *>(TlsGetValue(tlsIdx));
if (tls != nullptr)
{
tls->poolPointer = 0;
}
} }
void Vec3::resetPool() void Vec3::resetPool()
{ {
clearPool();
} }
Vec3 *Vec3::newTemp(double x, double y, double z) Vec3 *Vec3::newTemp(double x, double y, double z)

View file

@ -204,6 +204,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_COMMANDS_COMMON
"${CMAKE_CURRENT_SOURCE_DIR}/ToggleDownfallCommand.h" "${CMAKE_CURRENT_SOURCE_DIR}/ToggleDownfallCommand.h"
"${CMAKE_CURRENT_SOURCE_DIR}/WeatherCommand.h" "${CMAKE_CURRENT_SOURCE_DIR}/WeatherCommand.h"
"${CMAKE_CURRENT_SOURCE_DIR}/net.minecraft.commands.common.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}) source_group("net/minecraft/commands/common" FILES ${_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_COMMANDS_COMMON})

View file

@ -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.
<img width="784" height="410" alt="roadmap" src="https://github.com/user-attachments/assets/134856ae-b151-4003-aa97-7ecf19ccd278" /> <img width="784" height="410" alt="roadmap" src="https://github.com/user-attachments/assets/134856ae-b151-4003-aa97-7ecf19ccd278" />

View file

@ -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 - [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 - [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. - [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 # Build & Run