mirror of
https://github.com/neoStudiosLCE/neoLegacy.git
synced 2026-07-17 23:27:01 +00:00
Compare commits
43 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3e02fb2d6 | ||
|
|
78a55e97ef | ||
|
|
4b93dbeedd | ||
|
|
c268ef1cc3 | ||
|
|
f3d4e20b7a | ||
|
|
c0196abe3b | ||
|
|
7f967ed66f | ||
|
|
61f363e803 | ||
|
|
baa6745f45 | ||
|
|
7d93753451 | ||
|
|
76000424e1 | ||
|
|
a465d22390 | ||
|
|
31abba9e04 | ||
|
|
e9b2f724c6 | ||
|
|
4a7d95d8e9 | ||
|
|
d421708b5f | ||
|
|
f8c9349510 | ||
|
|
78759b9f15 | ||
|
|
2417eb4562 | ||
|
|
5857fab1f6 | ||
|
|
db4f09ffb8 | ||
|
|
128651de24 | ||
|
|
1cd3f977e4 | ||
|
|
b7393ab153 | ||
|
|
edee888662 | ||
|
|
7701841381 | ||
|
|
60aba187a7 | ||
|
|
012ada2e88 | ||
|
|
6e29b9f778 | ||
|
|
c19d5bb58e | ||
|
|
2d07c7abee | ||
|
|
311503ec46 | ||
|
|
bb37600c87 | ||
|
|
544befe162 | ||
|
|
285fab70b2 | ||
|
|
ac3ece01c7 | ||
|
|
ef0dad4ffc | ||
|
|
6ed34078fd | ||
|
|
cd50236b8a | ||
|
|
4d745ab65c | ||
|
|
f904fb1972 | ||
|
|
4003a8e548 | ||
|
|
0bd0cd2452 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -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
BIN
.github/banner.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 656 KiB After Width: | Height: | Size: 673 KiB |
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,7 @@ enum EGameHostOptionWorldSize
|
||||||
e_worldSize_Classic,
|
e_worldSize_Classic,
|
||||||
e_worldSize_Small,
|
e_worldSize_Small,
|
||||||
e_worldSize_Medium,
|
e_worldSize_Medium,
|
||||||
e_worldSize_Large,
|
e_worldSize_Large
|
||||||
e_worldSize_Expanded
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -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:
|
||||||
itemstring=app.GetString(id );
|
if (pTempItemInstAdditional->hasCustomHoverName()) {
|
||||||
|
itemstring = pTempItemInstAdditional->getHoverName();
|
||||||
|
} else {
|
||||||
|
itemstring = app.GetString(id);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setItemText(itemstring);
|
setItemText(itemstring.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 2.5 KiB |
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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--;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ MultiPlayerChunkCache::MultiPlayerChunkCache(Level *level)
|
||||||
this->level = level;
|
this->level = level;
|
||||||
|
|
||||||
this->cache = new LevelChunk *[XZSIZE * XZSIZE];
|
this->cache = new LevelChunk *[XZSIZE * XZSIZE];
|
||||||
memset(this->cache, 0, sizeof(LevelChunk*) * XZSIZE * XZSIZE);
|
memset(this->cache, 0, XZSIZE * XZSIZE * sizeof(LevelChunk *));
|
||||||
InitializeCriticalSectionAndSpinCount(&m_csLoadCreate,4000);
|
InitializeCriticalSectionAndSpinCount(&m_csLoadCreate,4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,7 +132,7 @@ bool MultiPlayerChunkCache::reallyHasChunk(int x, int z)
|
||||||
int idx = ix * XZSIZE + iz;
|
int idx = ix * XZSIZE + iz;
|
||||||
|
|
||||||
LevelChunk *chunk = cache[idx];
|
LevelChunk *chunk = cache[idx];
|
||||||
if (chunk == nullptr)
|
if( chunk == nullptr )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -145,8 +145,7 @@ void MultiPlayerChunkCache::drop(const int x, const int z)
|
||||||
const int iz = z + XZOFFSET;
|
const int iz = z + XZOFFSET;
|
||||||
if ((ix < 0) || (ix >= XZSIZE)) return;
|
if ((ix < 0) || (ix >= XZSIZE)) return;
|
||||||
if ((iz < 0) || (iz >= XZSIZE)) return;
|
if ((iz < 0) || (iz >= XZSIZE)) return;
|
||||||
|
const int idx = ix * XZSIZE + iz;
|
||||||
int idx = ix * XZSIZE + iz;
|
|
||||||
LevelChunk* chunk = cache[idx];
|
LevelChunk* chunk = cache[idx];
|
||||||
|
|
||||||
if (chunk != nullptr && !chunk->isEmpty())
|
if (chunk != nullptr && !chunk->isEmpty())
|
||||||
|
|
@ -170,7 +169,6 @@ LevelChunk *MultiPlayerChunkCache::create(int x, int z)
|
||||||
if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk );
|
if( ( ix < 0 ) || ( ix >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk );
|
||||||
if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk );
|
if( ( iz < 0 ) || ( iz >= XZSIZE ) ) return ( waterChunk ? waterChunk : emptyChunk );
|
||||||
int idx = ix * XZSIZE + iz;
|
int idx = ix * XZSIZE + iz;
|
||||||
|
|
||||||
LevelChunk *chunk = cache[idx];
|
LevelChunk *chunk = cache[idx];
|
||||||
LevelChunk *lastChunk = chunk;
|
LevelChunk *lastChunk = chunk;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -138,12 +138,21 @@ private:
|
||||||
// 4J - added for implementation of finite limit to number of item entities, tnt and falling block entities
|
// 4J - added for implementation of finite limit to number of item entities, tnt and falling block entities
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static const int MAX_HANGING_ENTITIES = 400;
|
static const int MAX_HANGING_ENTITIES = 800;
|
||||||
static const int MAX_ITEM_ENTITIES = 200;
|
static const int MAX_ITEM_ENTITIES = 400;
|
||||||
static const int MAX_ARROW_ENTITIES = 200;
|
static const int MAX_ARROW_ENTITIES = 400;
|
||||||
static const int MAX_EXPERIENCEORB_ENTITIES = 50;
|
static const int MAX_EXPERIENCEORB_ENTITIES = 100;
|
||||||
static const int MAX_PRIMED_TNT = 20;
|
static const int MAX_PRIMED_TNT = 40;
|
||||||
static const int MAX_FALLING_TILE = 20;
|
static const int MAX_FALLING_TILE = 40;
|
||||||
|
|
||||||
|
//static const int MAX_HANGING_ENTITIES = 400;
|
||||||
|
//static const int MAX_ITEM_ENTITIES = 200;
|
||||||
|
//static const int MAX_ARROW_ENTITIES = 200;
|
||||||
|
//static const int MAX_EXPERIENCEORB_ENTITIES = 50;
|
||||||
|
//static const int MAX_PRIMED_TNT = 20;
|
||||||
|
//static const int MAX_FALLING_TILE = 20;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int m_primedTntCount;
|
int m_primedTntCount;
|
||||||
int m_fallingTileCount;
|
int m_fallingTileCount;
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -290,24 +290,53 @@ void TrackedEntity::tick(EntityTracker *tracker, vector<shared_ptr<Player> > *pl
|
||||||
wasRiding = false;
|
wasRiding = false;
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
int yHeadRot = Mth::floor(e->getYHeadRot() * 256 / 360);
|
int yHeadRot = Mth::floor(e->getYHeadRot() * 256 / 360);
|
||||||
if (abs(yHeadRot - yHeadRotp) >= TOLERANCE_LEVEL)
|
if (abs(yHeadRot - yHeadRotp) >= TOLERANCE_LEVEL)
|
||||||
|
|
|
||||||
|
|
@ -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(¤t, 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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -628,8 +628,6 @@ static std::string WorldSizeToPropertyValue(int worldSize)
|
||||||
return "medium";
|
return "medium";
|
||||||
case e_worldSize_Large:
|
case e_worldSize_Large:
|
||||||
return "large";
|
return "large";
|
||||||
case e_worldSize_Expanded:
|
|
||||||
return "expanded";
|
|
||||||
case e_worldSize_Classic:
|
case e_worldSize_Classic:
|
||||||
default:
|
default:
|
||||||
return "classic";
|
return "classic";
|
||||||
|
|
@ -646,8 +644,6 @@ static int WorldSizeToXzChunks(int worldSize)
|
||||||
return LEVEL_WIDTH_MEDIUM;
|
return LEVEL_WIDTH_MEDIUM;
|
||||||
case e_worldSize_Large:
|
case e_worldSize_Large:
|
||||||
return LEVEL_WIDTH_LARGE;
|
return LEVEL_WIDTH_LARGE;
|
||||||
case e_worldSize_Expanded:
|
|
||||||
return LEVEL_WIDTH_EXPANDED;
|
|
||||||
case e_worldSize_Classic:
|
case e_worldSize_Classic:
|
||||||
default:
|
default:
|
||||||
return LEVEL_WIDTH_CLASSIC;
|
return LEVEL_WIDTH_CLASSIC;
|
||||||
|
|
@ -663,7 +659,6 @@ static int WorldSizeToHellScale(int worldSize)
|
||||||
case e_worldSize_Medium:
|
case e_worldSize_Medium:
|
||||||
return HELL_LEVEL_SCALE_MEDIUM;
|
return HELL_LEVEL_SCALE_MEDIUM;
|
||||||
case e_worldSize_Large:
|
case e_worldSize_Large:
|
||||||
case e_worldSize_Expanded:
|
|
||||||
return HELL_LEVEL_SCALE_LARGE;
|
return HELL_LEVEL_SCALE_LARGE;
|
||||||
case e_worldSize_Classic:
|
case e_worldSize_Classic:
|
||||||
default:
|
default:
|
||||||
|
|
@ -699,12 +694,6 @@ static bool TryParseWorldSize(const std::string &lowered, int *outWorldSize)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lowered == "expanded" || lowered == "344" || lowered == "8")
|
|
||||||
{
|
|
||||||
*outWorldSize = e_worldSize_Expanded;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ void Boat::lerpTo(double x, double y, double z, float yRot, float xRot, int step
|
||||||
{
|
{
|
||||||
if (doLerp)
|
if (doLerp)
|
||||||
{
|
{
|
||||||
lSteps = steps + 5;
|
lSteps = steps +5;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,12 @@ class TilePos;
|
||||||
// The maximum number of chunks that we can store
|
// The maximum number of chunks that we can store
|
||||||
#ifdef _LARGE_WORLDS
|
#ifdef _LARGE_WORLDS
|
||||||
// 4J Stu - Our default map (at zoom level 3) is 1024x1024 blocks (or 64 chunks)
|
// 4J Stu - Our default map (at zoom level 3) is 1024x1024 blocks (or 64 chunks)
|
||||||
|
#define LEVEL_MAX_WIDTH (5*64) //(6*54)
|
||||||
|
|
||||||
#define LEVEL_WIDTH_CLASSIC 54
|
#define LEVEL_WIDTH_CLASSIC 54
|
||||||
#define LEVEL_WIDTH_SMALL 64
|
#define LEVEL_WIDTH_SMALL 64
|
||||||
#define LEVEL_WIDTH_MEDIUM (3*64)
|
#define LEVEL_WIDTH_MEDIUM (3*64)
|
||||||
#define LEVEL_WIDTH_LARGE (5*64)
|
#define LEVEL_WIDTH_LARGE (5*64)
|
||||||
#define LEVEL_WIDTH_EXPANDED (5*64) + 24
|
|
||||||
|
|
||||||
|
|
||||||
#define LEVEL_MAX_WIDTH LEVEL_WIDTH_EXPANDED
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define LEVEL_MAX_WIDTH 54
|
#define LEVEL_MAX_WIDTH 54
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
118
Minecraft.World/EntityTypeMap.cpp
Normal file
118
Minecraft.World/EntityTypeMap.cpp
Normal 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;
|
||||||
|
}
|
||||||
21
Minecraft.World/EntityTypeMap.h
Normal file
21
Minecraft.World/EntityTypeMap.h
Normal 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();
|
||||||
|
};
|
||||||
|
|
@ -121,8 +121,14 @@ void GrassTile::tick(Level *level, int x, int y, int z, Random *random)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// using isSolid() here is wrong because non full blocks like iron bars,
|
||||||
|
// fences, walls are also flagged as solid by their material
|
||||||
|
int aboveTileId = level->getTile(x, y + 1, z);
|
||||||
Material* above = level->getMaterial(x, y + 1, z);
|
Material* above = level->getMaterial(x, y + 1, z);
|
||||||
if (above->isSolid() || above->isLiquid()) level->setTileAndUpdate(x, y, z, Tile::dirt_Id);
|
if (above->isLiquid() || Tile::lightBlock[aboveTileId] > 2)
|
||||||
|
{
|
||||||
|
level->setTileAndUpdate(x, y, z, Tile::dirt_Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GrassTile::getResource(int data, Random *random, int playerBonusLevel)
|
int GrassTile::getResource(int data, Random *random, int playerBonusLevel)
|
||||||
|
|
|
||||||
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +46,6 @@ DWORD Level::tlsIdxLightCache = TlsAlloc();
|
||||||
|
|
||||||
// 4J : WESTY : Added for time played stats.
|
// 4J : WESTY : Added for time played stats.
|
||||||
#include "net.minecraft.stats.h"
|
#include "net.minecraft.stats.h"
|
||||||
#include "../Minecraft.Client/MultiPlayerChunkCache.h"
|
|
||||||
|
|
||||||
// 4J - Caching of lighting data added. This is implemented as a 16x16x16 cache of ints (ie 16K storage in total). The index of the element to be used in the array is determined by the lower
|
// 4J - Caching of lighting data added. This is implemented as a 16x16x16 cache of ints (ie 16K storage in total). The index of the element to be used in the array is determined by the lower
|
||||||
// four bits of each x/y/z position, and the upper 7/4/7 bits of the x/y/z positions are stored within the element itself along with the cached values etc. The cache can be enabled per thread by
|
// four bits of each x/y/z position, and the upper 7/4/7 bits of the x/y/z positions are stored within the element itself along with the cached values etc. The cache can be enabled per thread by
|
||||||
|
|
@ -1336,7 +1335,7 @@ int Level::getBrightness(LightLayer::variety layer, int x, int y, int z)
|
||||||
int idx = ix * chunkSourceXZSize + iz;
|
int idx = ix * chunkSourceXZSize + iz;
|
||||||
LevelChunk *c = chunkSourceCache[idx];
|
LevelChunk *c = chunkSourceCache[idx];
|
||||||
|
|
||||||
if( c == nullptr) return (int)layer;
|
if( c == nullptr ) return (int)layer;
|
||||||
|
|
||||||
if (y < 0) y = 0;
|
if (y < 0) y = 0;
|
||||||
if (y >= maxBuildHeight) y = maxBuildHeight - 1;
|
if (y >= maxBuildHeight) y = maxBuildHeight - 1;
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,6 @@ LevelData::LevelData(CompoundTag *tag)
|
||||||
case LEVEL_WIDTH_SMALL: hostOptionworldSize = e_worldSize_Small; break;
|
case LEVEL_WIDTH_SMALL: hostOptionworldSize = e_worldSize_Small; break;
|
||||||
case LEVEL_WIDTH_MEDIUM: hostOptionworldSize = e_worldSize_Medium; break;
|
case LEVEL_WIDTH_MEDIUM: hostOptionworldSize = e_worldSize_Medium; break;
|
||||||
case LEVEL_WIDTH_LARGE: hostOptionworldSize = e_worldSize_Large; break;
|
case LEVEL_WIDTH_LARGE: hostOptionworldSize = e_worldSize_Large; break;
|
||||||
case LEVEL_WIDTH_EXPANDED: hostOptionworldSize = e_worldSize_Expanded; break;
|
|
||||||
default: assert(0); break;
|
default: assert(0); break;
|
||||||
}
|
}
|
||||||
app.SetGameHostOption(eGameHostOption_WorldSize, hostOptionworldSize );
|
app.SetGameHostOption(eGameHostOption_WorldSize, hostOptionworldSize );
|
||||||
|
|
|
||||||
|
|
@ -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;
|
wstring LevelParticlesPacket::getName()
|
||||||
for (int i = 0; i < toWrite; i++)
|
{
|
||||||
{
|
return name;
|
||||||
dos->writeInt(this->params[i]);
|
}
|
||||||
}
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -63,18 +63,18 @@ void MobCategory::setMaxInstancesPerLevel(int max)
|
||||||
m_maxPerLevel = max;
|
m_maxPerLevel = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MobCategory::maxAnimalsWithBreeding() { return creature->getMaxInstancesPerLevel() + 20; }
|
int MobCategory::maxAnimalsWithBreeding() { return (creature->getMaxInstancesPerLevel() + 20)*2; }
|
||||||
int MobCategory::maxChickensWithBreeding() { return creature_chicken->getMaxInstancesPerLevel() + 8; }
|
int MobCategory::maxChickensWithBreeding() { return (creature_chicken->getMaxInstancesPerLevel() + 8)*2; }
|
||||||
int MobCategory::maxMushroomCowsWithBreeding() { return creature_mushroomcow->getMaxInstancesPerLevel() + 20; }
|
int MobCategory::maxMushroomCowsWithBreeding() { return (creature_mushroomcow->getMaxInstancesPerLevel() + 20)*2; }
|
||||||
int MobCategory::maxWolvesWithBreeding() { return creature_wolf->getMaxInstancesPerLevel() + 8; }
|
int MobCategory::maxWolvesWithBreeding() { return (creature_wolf->getMaxInstancesPerLevel() + 8)*2; }
|
||||||
|
|
||||||
int MobCategory::maxAnimalsWithSpawnEgg() { return maxAnimalsWithBreeding() + 20; }
|
int MobCategory::maxAnimalsWithSpawnEgg() { return (maxAnimalsWithBreeding() + 20)*2; }
|
||||||
int MobCategory::maxChickensWithSpawnEgg() { return maxChickensWithBreeding() + 10; }
|
int MobCategory::maxChickensWithSpawnEgg() { return (maxChickensWithBreeding() + 10)*2; }
|
||||||
int MobCategory::maxWolvesWithSpawnEgg() { return maxWolvesWithBreeding() + 10; }
|
int MobCategory::maxWolvesWithSpawnEgg() { return (maxWolvesWithBreeding() + 10)*2; }
|
||||||
int MobCategory::maxMonstersWithSpawnEgg() { return monster->getMaxInstancesPerLevel() + 20; }
|
int MobCategory::maxMonstersWithSpawnEgg() { return (monster->getMaxInstancesPerLevel() + 20)*2; }
|
||||||
int MobCategory::maxMushroomCowsWithSpawnEgg() { return maxMushroomCowsWithBreeding() + 8; }
|
int MobCategory::maxMushroomCowsWithSpawnEgg() { return (maxMushroomCowsWithBreeding() + 8)*2; }
|
||||||
int MobCategory::maxSquidsWithSpawnEgg() { return waterCreature->getMaxInstancesPerLevel() + 8; }
|
int MobCategory::maxSquidsWithSpawnEgg() { return (waterCreature->getMaxInstancesPerLevel() + 8)*2; }
|
||||||
int MobCategory::maxAmbientWithSpawnEgg() { return ambient->getMaxInstancesPerLevel() + 8; }
|
int MobCategory::maxAmbientWithSpawnEgg() { return (ambient->getMaxInstancesPerLevel() + 8)*2; }
|
||||||
|
|
||||||
Material *MobCategory::getSpawnPositionMaterial()
|
Material *MobCategory::getSpawnPositionMaterial()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ class MobCategory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// 4J - putting constants for xbox spawning in one place to tidy things up a bit - all numbers are per level
|
// 4J - putting constants for xbox spawning in one place to tidy things up a bit - all numbers are per level
|
||||||
static const int CONSOLE_MONSTERS_HARD_LIMIT = 50; // Max number of enemies (skeleton, zombie, creeper etc) that the mob spawner will produce
|
static const int CONSOLE_MONSTERS_HARD_LIMIT = 100; // Max number of enemies (skeleton, zombie, creeper etc) that the mob spawner will produce
|
||||||
static const int CONSOLE_ANIMALS_HARD_LIMIT = 50; // Max number of animals (cows, sheep, pigs) that the mob spawner will produce
|
static const int CONSOLE_ANIMALS_HARD_LIMIT = 100; // Max number of animals (cows, sheep, pigs) that the mob spawner will produce
|
||||||
static const int CONSOLE_AMBIENT_HARD_LIMIT = 20; // Ambient mobs
|
static const int CONSOLE_AMBIENT_HARD_LIMIT = 40; // Ambient mobs
|
||||||
|
|
||||||
static const int MAX_XBOX_CHICKENS = 8; // Max number of chickens that the mob spawner will produce
|
static const int MAX_XBOX_CHICKENS = 8; // Max number of chickens that the mob spawner will produce
|
||||||
static const int MAX_XBOX_WOLVES = 8; // Max number of wolves that the mob spawner will produce
|
static const int MAX_XBOX_WOLVES = 8; // Max number of wolves that the mob spawner will produce
|
||||||
|
|
@ -20,7 +20,7 @@ public:
|
||||||
static const int MAX_CONSOLE_BOSS = 1; // Max number of bosses (enderdragon/wither)
|
static const int MAX_CONSOLE_BOSS = 1; // Max number of bosses (enderdragon/wither)
|
||||||
|
|
||||||
// 4J Villager breeding/egg limits - villagers are not a MobCategory so these stay hardcoded
|
// 4J Villager breeding/egg limits - villagers are not a MobCategory so these stay hardcoded
|
||||||
static const int MAX_VILLAGERS_WITH_BREEDING = 35;
|
static const int MAX_VILLAGERS_WITH_BREEDING = 70;
|
||||||
static const int MAX_XBOX_VILLAGERS_WITH_SPAWN_EGG = MAX_VILLAGERS_WITH_BREEDING + 15;
|
static const int MAX_XBOX_VILLAGERS_WITH_SPAWN_EGG = MAX_VILLAGERS_WITH_BREEDING + 15;
|
||||||
|
|
||||||
// Breeding headroom above the natural spawn cap. Read at call time so these
|
// Breeding headroom above the natural spawn cap. Read at call time so these
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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})
|
||||||
|
|
||||||
|
|
|
||||||
15
NOTES.md
15
NOTES.md
|
|
@ -1,7 +1,18 @@
|
||||||
# neoLegacy v1.0.5b
|
# neoLegacy v1.0.8b
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
- Fixed crashing, lagging, and lighting issues caused by expanded world generation.
|
- 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" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue