Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
41b734e
CPU Overhead Optimization,Pathfinding and Entity Optimizations
starseed12345 Mar 9, 2026
fe65ec2
Remove dead link from README (#1064)
Tuff-CWC Mar 9, 2026
e9dba1f
Prevent TNT Minecart exploding with TNT disabled (#1067)
3UR Mar 9, 2026
0fbc890
Update README, remove servers.txt references
codeHusky Mar 9, 2026
e6eafda
Remove another servers.txt reference
codeHusky Mar 9, 2026
58c236e
Disable git LFS
codeHusky Mar 10, 2026
3bcf588
Fix crash when loading saved tutorial worlds (#1001)
MCbabel Mar 10, 2026
5f777a7
Fix: Prevent clicking disabled checkboxes (#1075)
Alezito2008 Mar 10, 2026
c90a6bf
Fixed Enderman, monster aggro in creative (#1051)
Us3ful-dev Mar 10, 2026
91ae76f
Fix tamed horses despawning when player moves away (#1057)
MCbabel Mar 10, 2026
c998346
FIX: Bonus Chests spawn again when loading back in. #982 (#992)
eh-K Mar 10, 2026
d7596aa
Fix issue where visually the HUD shows you have 0 hearts when you don…
3UR Mar 10, 2026
a18f7b3
Button placement backport Ceiling/Floor
starseed12345 Mar 10, 2026
a195ac7
Only single topic PRs, please - CONTRIBUTING.md
codeHusky Mar 10, 2026
1036b73
Fixed DLC map loading / saving, missing chunks (#1114)
MarvelcoCode Mar 11, 2026
44fc8a4
Fix quiet in-game audio after engine update #897 (#1171)
ModMaker101 Mar 12, 2026
bb8ffee
Fix mouse being pulled to the bottom right (#1156)
ayushthoren Mar 12, 2026
e689562
Fix SubEntity hitbox hit detection (#1175)
Matt-T-123 Mar 12, 2026
1c32d7b
Remove some leftover files (#881)
Twig6943 Mar 12, 2026
e140978
fix: logo rendering order after closing host options (#907)
Alezito2008 Mar 12, 2026
1cee213
Added LittleBigPlanet Skin Pack (#793)
RatCatcherVr Mar 12, 2026
714462b
Fix background stretching in settings>graphics menu (#1092)
jvnpr Mar 12, 2026
ad74d44
Fix joining servers in split screen, splitscreen fixes (#1031)
MrTheShy Mar 13, 2026
d131a55
Fix mounted minecarts not persisting across world reloads (#979)
ayushthoren Mar 13, 2026
3794340
Fix witches' bottle color (#1205)
Prakhar1808 Mar 13, 2026
4e4e4df
Remove all old binka redist files (#1116)
rtm516 Mar 13, 2026
4d200a5
Fixed dangling pointer issue (#1209)
troglodyte9 Mar 13, 2026
b119bb5
Infinite World Gen /WIP
starseed12345 Mar 13, 2026
7afd983
Merge branch 'main' of https://github.com/starseed12345/MinecraftCons…
starseed12345 Mar 13, 2026
fb37ced
Update languages.loc
starseed12345 Mar 13, 2026
b608eaf
futureproof stronghold (untested)
starseed12345 Mar 14, 2026
3276393
Revert to original Stronghold
starseed12345 Mar 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,8 +0,0 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.binka filter=lfs diff=lfs merge=lfs -text
*.arc filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.ico filter=lfs diff=lfs merge=lfs -text
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ However, we would accept changes that...
- Having workable multi-platform compilation for ARM, Consoles, Linux
- Being a good base for further expansion and modding of LCE, such as backports and "modpacks".

# Scope of PRs
All Pull Requests should fully document the changes they include in their file changes. They should also be limited to one general topic and not touch all over the codebase unless its justifiable.

For example, we would not accept a PR that reworks UI, multiplayer code, and furnace ticking even if its a "fixup" PR as its too difficult to review a ton of code changes that are all irrelevant from each other. However, a PR focused on adding a bunch of commands or fixes several crashes that are otherwise irrelevant to each other would be accepted.

If your PR includes any undocumented changes it will be closed.

# Use of AI and LLMs
We currently do not accept any new code into the project that was written largely, entirely, or even noticably by an LLM. All contributions should be made by humans that understand the codebase.

Expand Down
2 changes: 1 addition & 1 deletion Minecraft.Client/ArrowRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ class ArrowRenderer : public EntityRenderer
static ResourceLocation ARROW_LOCATION;

public:
virtual void render(shared_ptr<Entity> _arrow, double x, double y, double z, float rot, float a);
virtual void render(const shared_ptr<Entity> _arrow, double x, double y, double z, float rot, float a);
virtual ResourceLocation *getTextureLocation(shared_ptr<Entity> mob);
};
2 changes: 1 addition & 1 deletion Minecraft.Client/BatRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class BatRenderer : public MobRenderer

public:
BatRenderer();
virtual void render(shared_ptr<Entity> _mob, double x, double y, double z, float rot, float a);
virtual void render(const shared_ptr<Entity> _mob, double x, double y, double z, float rot, float a);

protected:
virtual ResourceLocation *getTextureLocation(shared_ptr<Entity> mob);
Expand Down
2 changes: 1 addition & 1 deletion Minecraft.Client/BlazeRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ class BlazeRenderer : public MobRenderer
public:
BlazeRenderer();

virtual void render(shared_ptr<Entity> mob, double x, double y, double z, float rot, float a);
virtual void render(const shared_ptr<Entity> mob, double x, double y, double z, float rot, float a);
virtual ResourceLocation *getTextureLocation(shared_ptr<Entity> mob);
};
2 changes: 1 addition & 1 deletion Minecraft.Client/BoatRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ class BoatRenderer : public EntityRenderer
public:
BoatRenderer();

virtual void render(shared_ptr<Entity> boat, double x, double y, double z, float rot, float a);
virtual void render(const shared_ptr<Entity> boat, double x, double y, double z, float rot, float a);
virtual ResourceLocation *getTextureLocation(shared_ptr<Entity> mob);
};
2 changes: 1 addition & 1 deletion Minecraft.Client/ChickenRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ChickenRenderer : public MobRenderer

public:
ChickenRenderer(Model *model, float shadow);
virtual void render(shared_ptr<Entity> _mob, double x, double y, double z, float rot, float a);
virtual void render(const shared_ptr<Entity> _mob, double x, double y, double z, float rot, float a);
virtual ResourceLocation *getTextureLocation(shared_ptr<Entity> mob);

protected:
Expand Down
104 changes: 83 additions & 21 deletions Minecraft.Client/ClientConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,56 @@ bool ClientConnection::isPrimaryConnection() const
return g_NetworkManager.IsHost() || m_userIndex == ProfileManager.GetPrimaryPad();
}

ClientConnection* ClientConnection::findPrimaryConnection() const
{
if (level == nullptr) return nullptr;
int primaryPad = ProfileManager.GetPrimaryPad();
MultiPlayerLevel* mpLevel = (MultiPlayerLevel*)level;
for (ClientConnection* conn : mpLevel->connections)
{
if (conn != this && conn->m_userIndex == primaryPad)
return conn;
}
return nullptr;
}

bool ClientConnection::shouldProcessForEntity(int entityId) const
{
if (g_NetworkManager.IsHost()) return true;
if (m_userIndex == ProfileManager.GetPrimaryPad()) return true;

ClientConnection* primary = findPrimaryConnection();
if (primary == nullptr) return true;
return !primary->isTrackingEntity(entityId);
}

bool ClientConnection::shouldProcessForPosition(int blockX, int blockZ) const
{
if (g_NetworkManager.IsHost()) return true;
if (m_userIndex == ProfileManager.GetPrimaryPad()) return true;

ClientConnection* primary = findPrimaryConnection();
if (primary == nullptr) return true;
return !primary->m_visibleChunks.count(chunkKey(blockX >> 4, blockZ >> 4));
}

bool ClientConnection::anyOtherConnectionHasChunk(int x, int z) const
{
if (level == nullptr) return false;
MultiPlayerLevel* mpLevel = (MultiPlayerLevel*)level;
int64_t key = chunkKey(x, z);
for (ClientConnection* conn : mpLevel->connections)
{
if (conn != this && conn->m_visibleChunks.count(key))
return true;
}
return false;
}

ClientConnection::~ClientConnection()
{
m_trackedEntityIds.clear();
m_visibleChunks.clear();
delete connection;
delete random;
delete savedDataStorage;
Expand Down Expand Up @@ -664,6 +712,7 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
}
e->entityId = packet->id;
level->putEntity(packet->id, e);
m_trackedEntityIds.insert(packet->id);

if (packet->data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0
{
Expand Down Expand Up @@ -712,6 +761,7 @@ void ClientConnection::handleAddExperienceOrb(shared_ptr<AddExperienceOrbPacket>
e->xRot = 0;
e->entityId = packet->id;
level->putEntity(packet->id, e);
m_trackedEntityIds.insert(packet->id);
}

void ClientConnection::handleAddGlobalEntity(shared_ptr<AddGlobalEntityPacket> packet)
Expand All @@ -738,13 +788,13 @@ void ClientConnection::handleAddPainting(shared_ptr<AddPaintingPacket> packet)
{
shared_ptr<Painting> painting = std::make_shared<Painting>(level, packet->x, packet->y, packet->z, packet->dir, packet->motive);
level->putEntity(packet->id, painting);
m_trackedEntityIds.insert(packet->id);
}

void ClientConnection::handleSetEntityMotion(shared_ptr<SetEntityMotionPacket> packet)
{
if (!isPrimaryConnection())
if (!shouldProcessForEntity(packet->id))
{
// Secondary connection: only accept motion for our own local player (knockback)
if (minecraft->localplayers[m_userIndex] == NULL ||
packet->id != minecraft->localplayers[m_userIndex]->entityId)
return;
Expand Down Expand Up @@ -939,6 +989,7 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
app.DebugPrintf("Custom cape for player %ls is %ls\n",player->name.c_str(),player->customTextureUrl2.c_str());

level->putEntity(packet->id, player);
m_trackedEntityIds.insert(packet->id);

vector<shared_ptr<SynchedEntityData::DataItem> > *unpackedData = packet->getUnpackedData();
if (unpackedData != nullptr)
Expand Down Expand Up @@ -979,7 +1030,7 @@ void ClientConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> pac

void ClientConnection::handleMoveEntity(shared_ptr<MoveEntityPacket> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForEntity(packet->id)) return;
shared_ptr<Entity> e = getEntity(packet->id);
if (e == nullptr) return;
e->xp += packet->xa;
Expand Down Expand Up @@ -1009,7 +1060,7 @@ void ClientConnection::handleRotateMob(shared_ptr<RotateHeadPacket> packet)

void ClientConnection::handleMoveEntitySmall(shared_ptr<MoveEntityPacketSmall> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForEntity(packet->id)) return;
shared_ptr<Entity> e = getEntity(packet->id);
if (e == nullptr) return;
e->xp += packet->xa;
Expand Down Expand Up @@ -1068,6 +1119,7 @@ void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packe
#endif
for (int i = 0; i < packet->ids.length; i++)
{
m_trackedEntityIds.erase(packet->ids[i]);
level->removeEntity(packet->ids[i]);
}
}
Expand Down Expand Up @@ -1136,19 +1188,35 @@ void ClientConnection::handleChunkVisibilityArea(shared_ptr<ChunkVisibilityAreaP
{
if (level == NULL) return;
for(int z = packet->m_minZ; z <= packet->m_maxZ; ++z)
{
for(int x = packet->m_minX; x <= packet->m_maxX; ++x)
{
m_visibleChunks.insert(chunkKey(x, z));
level->setChunkVisible(x, z, true);
}
}
}

void ClientConnection::handleChunkVisibility(shared_ptr<ChunkVisibilityPacket> packet)
{
if (level == NULL) return;
level->setChunkVisible(packet->x, packet->z, packet->visible);
if (packet->visible)
{
m_visibleChunks.insert(chunkKey(packet->x, packet->z));
level->setChunkVisible(packet->x, packet->z, true);
}
else
{
m_visibleChunks.erase(chunkKey(packet->x, packet->z));
if (!anyOtherConnectionHasChunk(packet->x, packet->z))
{
level->setChunkVisible(packet->x, packet->z, false);
}
}
}

void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
// 4J - changed to encode level in packet
MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx];
if( dimensionLevel )
Expand Down Expand Up @@ -1218,7 +1286,6 @@ void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket>

void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
// 4J - changed to encode level in packet
MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx];
if( dimensionLevel )
Expand Down Expand Up @@ -1279,7 +1346,6 @@ void ClientConnection::handleBlockRegionUpdate(shared_ptr<BlockRegionUpdatePacke

void ClientConnection::handleTileUpdate(shared_ptr<TileUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
// 4J added - using a block of 255 to signify that this is a packet for destroying a tile, where we need to inform the level renderer that we are about to do so.
// This is used in creative mode as the point where a tile is first destroyed at the client end of things. Packets formed like this are potentially sent from
// ServerPlayerGameMode::destroyBlock
Expand Down Expand Up @@ -1394,7 +1460,7 @@ void ClientConnection::send(shared_ptr<Packet> packet)

void ClientConnection::handleTakeItemEntity(shared_ptr<TakeItemEntityPacket> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForEntity(packet->itemId)) return;
shared_ptr<Entity> from = getEntity(packet->itemId);
shared_ptr<LivingEntity> to = dynamic_pointer_cast<LivingEntity>(getEntity(packet->playerId));

Expand Down Expand Up @@ -2414,6 +2480,8 @@ void ClientConnection::close()
// If it's already done, then we don't need to do anything here. And in fact trying to do something could cause a crash
if(done) return;
done = true;
m_trackedEntityIds.clear();
m_visibleChunks.clear();
connection->flush();
connection->close(DisconnectPacket::eDisconnect_Closed);
}
Expand Down Expand Up @@ -2453,6 +2521,7 @@ void ClientConnection::handleAddMob(shared_ptr<AddMobPacket> packet)
mob->yd = packet->yd / 8000.0f;
mob->zd = packet->zd / 8000.0f;
level->putEntity(packet->id, mob);
m_trackedEntityIds.insert(packet->id);

vector<shared_ptr<SynchedEntityData::DataItem> > *unpackedData = packet->getUnpackedData();
if (unpackedData != nullptr)
Expand Down Expand Up @@ -2792,6 +2861,9 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
// so it doesn't leak into the new dimension
level->playStreamingMusic(L"", 0, 0, 0);

m_trackedEntityIds.clear();
m_visibleChunks.clear();

// Remove client connection from this level
level->removeClientConnection(this, false);

Expand Down Expand Up @@ -2899,8 +2971,7 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)

void ClientConnection::handleExplosion(shared_ptr<ExplodePacket> packet)
{
// World modification (block destruction) must only happen once
if (isPrimaryConnection())
if (shouldProcessForPosition((int)packet->x, (int)packet->z))
{
if(!packet->m_bKnockbackOnly)
{
Expand Down Expand Up @@ -3244,7 +3315,6 @@ void ClientConnection::handleTileEditorOpen(shared_ptr<TileEditorOpenPacket> pac

void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
{
if (!isPrimaryConnection()) return;
app.DebugPrintf("ClientConnection::handleSignUpdate - ");
if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z))
{
Expand Down Expand Up @@ -3278,7 +3348,6 @@ void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)

void ClientConnection::handleTileEntityData(shared_ptr<TileEntityDataPacket> packet)
{
if (!isPrimaryConnection()) return;
if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z))
{
shared_ptr<TileEntity> te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z);
Expand Down Expand Up @@ -3331,15 +3400,13 @@ void ClientConnection::handleContainerClose(shared_ptr<ContainerClosePacket> pac

void ClientConnection::handleTileEvent(shared_ptr<TileEventPacket> packet)
{
if (!isPrimaryConnection()) return;
PIXBeginNamedEvent(0,"Handle tile event\n");
minecraft->level->tileEvent(packet->x, packet->y, packet->z, packet->tile, packet->b0, packet->b1);
PIXEndNamedEvent();
}

void ClientConnection::handleTileDestruction(shared_ptr<TileDestructionPacket> packet)
{
if (!isPrimaryConnection()) return;
minecraft->level->destroyTileProgress(packet->getEntityId(), packet->getX(), packet->getY(), packet->getZ(), packet->getState());
}

Expand Down Expand Up @@ -3421,7 +3488,6 @@ void ClientConnection::handleGameEvent(shared_ptr<GameEventPacket> gameEventPack

void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> packet)
{
if (!isPrimaryConnection()) return;
if (packet->itemType == Item::map->id)
{
MapItem::getSavedData(packet->itemId, minecraft->level)->handleComplexItemData(packet->data);
Expand All @@ -3436,7 +3502,7 @@ void ClientConnection::handleComplexItemData(shared_ptr<ComplexItemDataPacket> p

void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet)
{
if (!isPrimaryConnection()) return;
if (!shouldProcessForPosition(packet->x, packet->z)) return;
if (packet->type == LevelEvent::SOUND_DRAGON_DEATH)
{
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
Expand All @@ -3456,8 +3522,6 @@ void ClientConnection::handleLevelEvent(shared_ptr<LevelEventPacket> packet)
{
minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data);
}

minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data);
}

void ClientConnection::handleAwardStat(shared_ptr<AwardStatPacket> packet)
Expand Down Expand Up @@ -3660,7 +3724,6 @@ void ClientConnection::handlePlayerAbilities(shared_ptr<PlayerAbilitiesPacket> p

void ClientConnection::handleSoundEvent(shared_ptr<LevelSoundPacket> packet)
{
if (!isPrimaryConnection()) return;
minecraft->level->playLocalSound(packet->getX(), packet->getY(), packet->getZ(), packet->getSound(), packet->getVolume(), packet->getPitch(), false);
}

Expand Down Expand Up @@ -3973,7 +4036,6 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket>

void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet)
{
if (!isPrimaryConnection()) return;
for (int i = 0; i < packet->getCount(); i++)
{
double xVarience = random->nextGaussian() * packet->getXDist();
Expand Down
15 changes: 15 additions & 0 deletions Minecraft.Client/ClientConnection.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <unordered_set>
#include "..\Minecraft.World\net.minecraft.network.h"
class Minecraft;
class MultiPlayerLevel;
Expand Down Expand Up @@ -44,6 +45,20 @@ class ClientConnection : public PacketListener
private:
DWORD m_userIndex; // 4J Added
bool isPrimaryConnection() const;

std::unordered_set<int> m_trackedEntityIds;
std::unordered_set<int64_t> m_visibleChunks;

static int64_t chunkKey(int x, int z) { return ((int64_t)x << 32) | ((int64_t)z & 0xFFFFFFFF); }

ClientConnection* findPrimaryConnection() const;
bool shouldProcessForEntity(int entityId) const;
bool shouldProcessForPosition(int blockX, int blockZ) const;
bool anyOtherConnectionHasChunk(int x, int z) const;

public:
bool isTrackingEntity(int entityId) const { return m_trackedEntityIds.count(entityId) > 0; }

public:
SavedDataStorage *savedDataStorage;
ClientConnection(Minecraft *minecraft, const wstring& ip, int port);
Expand Down
Loading