10 Commits

Author SHA1 Message Date
la
d7596aa28c Fix issue where visually the HUD shows you have 0 hearts when you dont (#1089)
* Fix for issue where player is able to stay alive with zero hearts in their healthbar.

* use static cast over c style cast
2026-03-09 22:30:01 -05:00
eh-K
c998346312 FIX: Bonus Chests spawn again when loading back in. #982 (#992)
* Fixed bug where Bonus Chests would spawn again when loading back into it.

Fixes #982

Added a check for if the world is new.

Meaning no more additional chests if the world is loaded up again.

* Replace NULL with nullptr for chest check
2026-03-09 22:07:38 -05:00
Marlian
91ae76f132 Fix tamed horses despawning when player moves away (#1057)
Co-authored-by: MCbabel <MCbabel@users.noreply.github.com>
2026-03-09 22:06:38 -05:00
Us3ful"-Dev
c90a6bf5ab Fixed Enderman, monster aggro in creative (#1051)
Fixed endermans by making a invulnerable check
2026-03-09 22:05:56 -05:00
Alezito2008
5f777a7f45 Fix: Prevent clicking disabled checkboxes (#1075) 2026-03-09 22:03:39 -05:00
Marlian
3bcf588fbe Fix crash when loading saved tutorial worlds (#1001)
writeRuleFile() was missing the schematic file count integer before the schematic entries. The reader in readRuleFile() expected this count, causing a stream misalignment that led to an assertion failure (Unrecognised schematic version) when reloading a saved tutorial world.

The fix writes the count on save and adds backward-compatible reading that detects old saves (without count) via a peek heuristic and falls back to count-less parsing.

Co-authored-by: MCbabel <MCbabel@users.noreply.github.com>
2026-03-09 22:02:39 -05:00
Loki Rautio
58c236ead5 Disable git LFS
It was never even enabled properly to begin with
2026-03-09 20:49:50 -05:00
Loki
e6eafda90e Remove another servers.txt reference 2026-03-09 18:27:02 -05:00
Loki
0fbc8903f3 Update README, remove servers.txt references 2026-03-09 18:26:00 -05:00
la
e9dba1fa56 Prevent TNT Minecart exploding with TNT disabled (#1067)
This set of changes was made to make the code better mimic TU20 based on its disassembly
2026-03-09 16:01:17 -05:00
11 changed files with 100 additions and 68 deletions

8
.gitattributes vendored
View File

@@ -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

View File

@@ -344,6 +344,7 @@ void GameRuleManager::writeRuleFile(DataOutputStream *dos)
// Write schematic files.
unordered_map<wstring, ConsoleSchematicFile *> *files;
files = getLevelGenerationOptions()->getUnfinishedSchematicFiles();
dos->writeInt((int)files->size());
for ( auto& it : *files )
{
const wstring& filename = it.first;
@@ -497,17 +498,36 @@ bool GameRuleManager::readRuleFile(LevelGenerationOptions *lgo, byte *dIn, UINT
}*/
// subfile
// Old saves didn't write a numFiles count before the schematic entries.
// Detect this: a real count is small, but a UTF filename prefix reads as a large int.
UINT numFiles = contentDis->readInt();
for (UINT i = 0; i < numFiles; i++)
if (lgo->isFromSave() && numFiles > 100)
{
wstring sFilename = contentDis->readUTF();
int length = contentDis->readInt();
byteArray ba( length );
contentDis->read(ba);
levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length);
contentDis->skip(-4);
while (true)
{
int peek = contentDis->readInt();
if (peek <= 100) { contentDis->skip(-4); break; }
contentDis->skip(-4);
wstring sFilename = contentDis->readUTF();
int length = contentDis->readInt();
byteArray ba( length );
contentDis->read(ba);
levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length);
}
}
else
{
for (UINT i = 0; i < numFiles; i++)
{
wstring sFilename = contentDis->readUTF();
int length = contentDis->readInt();
byteArray ba( length );
contentDis->read(ba);
levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length);
}
}
LEVEL_GEN_ID lgoID = LEVEL_GEN_ID_NULL;

View File

@@ -195,8 +195,8 @@ void IUIScene_HUD::renderPlayerHealth()
// Update health
bool blink = pMinecraft->localplayers[iPad]->invulnerableTime / 3 % 2 == 1;
if (pMinecraft->localplayers[iPad]->invulnerableTime < 10) blink = false;
int currentHealth = pMinecraft->localplayers[iPad]->getHealth();
int oldHealth = pMinecraft->localplayers[iPad]->lastHealth;
int currentHealth = static_cast<int>(ceil(pMinecraft->localplayers[iPad]->getHealth()));
int oldHealth = static_cast<int>(ceil(pMinecraft->localplayers[iPad]->lastHealth));
bool bHasPoison = pMinecraft->localplayers[iPad]->hasEffect(MobEffect::poison);
bool bHasWither = pMinecraft->localplayers[iPad]->hasEffect(MobEffect::wither);
AttributeInstance *maxHealthAttribute = pMinecraft->localplayers[iPad]->getAttribute(SharedMonsterAttributes::MAX_HEALTH);

View File

@@ -578,9 +578,12 @@ bool UIScene::handleMouseClick(F32 x, F32 y)
if (bestCtrl->getControlType() == UIControl::eCheckBox)
{
UIControl_CheckBox *cb = static_cast<UIControl_CheckBox*>(bestCtrl);
bool newState = !cb->IsChecked();
cb->setChecked(newState);
handleCheckboxToggled((F64)bestId, newState);
if (cb->IsEnabled())
{
bool newState = !cb->IsChecked();
cb->setChecked(newState);
handleCheckboxToggled((F64)bestId, newState);
}
}
else
{

View File

@@ -24,18 +24,21 @@ bool BonusChestFeature::place(Level *level, Random *random, int x, int y, int z)
bool BonusChestFeature::place(Level *level, Random *random, int x, int y, int z, bool force)
{
if( !force )
//Will only spawn a bonus chest if the world is new and has never been saved.
if (level->isNew)
{
int t = 0;
while (((t = level->getTile(x, y, z)) == 0 || t == Tile::leaves_Id) && y > 1)
if( !force )
{
int t = 0;
while (((t = level->getTile(x, y, z)) == 0 || t == Tile::leaves_Id) && y > 1)
y--;
if (y < 1)
{
return false;
if (y < 1)
{
return false;
}
y++;
}
y++;
}
for (int i = 0; i < 4; i++)
{
@@ -85,4 +88,6 @@ bool BonusChestFeature::place(Level *level, Random *random, int x, int y, int z,
}
return false;
}
}

View File

@@ -410,9 +410,14 @@ bool EnderMan::hurt(DamageSource *source, float damage)
if ( dynamic_cast<EntityDamageSource *>(source) != nullptr && source->getEntity()->instanceof(eTYPE_PLAYER))
{
aggroedByPlayer = true;
if (!dynamic_pointer_cast<Player>(source->getEntity())->abilities.invulnerable)
{
aggroedByPlayer = true;
}
else setCreepy(false);
}
if (dynamic_cast<IndirectEntityDamageSource *>(source) != nullptr)
{
aggroedByPlayer = false;

View File

@@ -515,6 +515,15 @@ bool EntityHorse::canSpawn()
return Animal::canSpawn();
}
bool EntityHorse::removeWhenFarAway()
{
if (isTamed()) return false;
if (isSaddled()) return false;
if (isLeashed()) return false;
if (getArmorType() > 0) return false;
return Animal::removeWhenFarAway();
}
shared_ptr<EntityHorse> EntityHorse::getClosestMommy(shared_ptr<Entity> baby, double searchRadius)
{

View File

@@ -192,6 +192,7 @@ private:
public:
virtual void containerChanged();
virtual bool canSpawn();
virtual bool removeWhenFarAway() override;
protected:
virtual shared_ptr<EntityHorse> getClosestMommy(shared_ptr<Entity> baby, double searchRadius);

View File

@@ -64,28 +64,34 @@ void MinecartTNT::destroy(DamageSource *source)
double speedSqr = xd * xd + zd * zd;
if (!source->isExplosion())
if (!app.GetGameHostOption(eGameHostOption_TNT) || !source->isExplosion())
{
spawnAtLocation(std::make_shared<ItemInstance>(Tile::tnt, 1), 0);
spawnAtLocation( shared_ptr<ItemInstance>( new ItemInstance(Tile::tnt, 1) ), 0);
}
if (source->isFire() || source->isExplosion() || speedSqr >= 0.01f)
if (app.GetGameHostOption(eGameHostOption_TNT))
{
explode(speedSqr);
if (source->isFire() || source->isExplosion() || speedSqr >= 0.01f)
{
explode(speedSqr);
}
}
}
void MinecartTNT::explode(double speedSqr)
{
if (!app.GetGameHostOption(eGameHostOption_TNT))
{
remove();
return;
}
if (!level->isClientSide)
{
double speed = sqrt(speedSqr);
if (speed > 5.0) speed = 5.0;
if (app.GetGameHostOption(eGameHostOption_TNT))
{
level->explode(shared_from_this(), x, y, z, static_cast<float>(4 + random->nextDouble() * 1.5f * speed), true);
remove();
}
if (speed > 5) speed = 5;
level->explode(shared_from_this(), x, y, z, (float) (4 + random->nextDouble() * 1.5f * speed), true);
remove();
}
}
@@ -122,12 +128,15 @@ void MinecartTNT::handleEntityEvent(byte eventId)
void MinecartTNT::primeFuse()
{
fuse = 80;
if (!level->isClientSide)
if (app.GetGameHostOption(eGameHostOption_TNT))
{
level->broadcastEntityEvent(shared_from_this(), EVENT_PRIME);
level->playEntitySound(shared_from_this(), eSoundType_RANDOM_FUSE, 1, 1.0f);
fuse = 80;
if (!level->isClientSide)
{
level->broadcastEntityEvent(shared_from_this(), EVENT_PRIME);
level->playEntitySound(shared_from_this(), eSoundType_RANDOM_FUSE, 1, 1.0f);
}
}
}

View File

@@ -60,7 +60,14 @@ bool Monster::hurt(DamageSource *source, float dmg)
if (sourceEntity != shared_from_this())
{
attackTarget = sourceEntity;
if (sourceEntity->instanceof(eTYPE_PLAYER))
{
if (!dynamic_pointer_cast<Player>(sourceEntity)->abilities.invulnerable)
{
attackTarget = sourceEntity;
}
}
else attackTarget = sourceEntity;
}
return true;
}

View File

@@ -9,7 +9,7 @@
This project contains the source code of Minecraft Legacy Console Edition v1.6.0560.0 (TU19) with some fixes and improvements applied.
## Download
Windows users can download our [Nightly Build](https://github.com/smartcmd/MinecraftConsoles/releases/tag/nightly)! Simply download the `.zip` file and extract it to a folder where you'd like to keep the game. You can set your username in `username.txt` (you'll have to make this file) and add servers to connect to in `servers.txt`
Windows users can download our [Nightly Build](https://github.com/smartcmd/MinecraftConsoles/releases/tag/nightly)! Simply download the `.zip` file and extract it to a folder where you'd like to keep the game. You can set your username in `username.txt` (you'll have to make this file)
## Platform Support
@@ -35,30 +35,11 @@ Basic LAN multiplayer is available on the Windows build
- Other players on the same LAN can discover the session from the in-game Join Game menu
- Game connections use TCP port `25565` by default
- LAN discovery uses UDP port `25566`
- Add servers to your server list with `servers.txt` (temp solution)
- Add servers to your server list with the in-game Add Server button (temp)
- Rename yourself without losing data by keeping your `uid.dat`
Parts of this feature are based on code from [LCEMP](https://github.com/LCEMP/LCEMP) (thanks!)
### servers.txt
To add a server to your game, create the `servers.txt` file in the same directory as you have `Minecraft.Client.exe`. Inside, follow this format:
```
serverip.example.com
25565
The name of your server in UI!
```
For example, here's a valid servers.txt
```
1.1.1.1
25565
Cloudflare's Very Own LCE Server
127.0.0.1
25565
Localhost Test Crap
```
### Launch Arguments
| Argument | Description |
@@ -100,7 +81,7 @@ Minecraft.Client.exe -name Steve -fullscreen
2. Clone the repository.
3. Open the project by double-clicking `MinecraftConsoles.sln`.
4. Make sure `Minecraft.Client` is set as the Startup Project.
5. Set the build configuration to **Debug** (Release is also OK but has some bugs) and the target platform to **Windows64**, then build and run.
5. Set the build configuration to **Debug** (Release is also ok but missing some debug features) and the target platform to **Windows64**, then build and run.
### CMake (Windows x64)