MorriCraft v2.2.21: Player position save fix and improved updater feedback

This commit is contained in:
Michael Howard 2026-04-25 11:19:30 -05:00
parent d96c97df26
commit cbe650009c
6 changed files with 44 additions and 33 deletions

View File

@ -106,12 +106,13 @@ A pre-built `MorriCraft-Windows.zip` is available in the repository root.
## 📜 Version History
### v2.2.20 - UI Polish & Spawn Fixes (Current)
- **Ignore Update**: Added an "Ignore" button to the update prompt to skip updates for the current session.
- **Chat Fix**: Resolved an issue where the chat box would remain stuck open after sending a message.
- **Universal Tooltips**: Item names now appear when hovering over items in ALL screens (Chest, Crafting Table, and Cheat Menu).
- **Morning Spawn Fix**: Adjusted the initial spawn time to ensure new worlds start in bright daylight.
- **Version UI**: Moved the version number to the bottom-left to avoid cutting it off on different screen sizes.
### v2.2.21 - Save Fix & Updater Polish (Current)
- **Player Position Fix**: Resolved a critical bug where players would reset to spawn when reloading a world. Player coordinates are now correctly preserved.
- **Improved Updater**: Added "Downloading" and "Installing" status messages.
- **Dynamic Progress**: The progress bar now pulses during the download to show active background work.
- **Extraction Fix**: Resolved an issue where the updater failed to find the downloaded ZIP due to an incorrect filename extension.
### v2.2.20 - UI Polish & Spawn Fixes
### v2.2.19 - Torch & persistence Overhaul

Binary file not shown.

Binary file not shown.

View File

@ -1 +1 @@
v2.2.20
v2.2.21

View File

@ -380,7 +380,7 @@ void RebuildChunkRenderList(Chunk* chunk, int cx, int cz) {
unsigned char faces = GetExposedFaces(lx, ly, lz, chunk, nxM, nxP, nzM, nzP);
if (faces != 0) {
// Simple Torch Lighting (v2.2.20)
// Simple Torch Lighting (v2.2.21)
float blockLight = 0.0f;
Vector3 bPos = {(float)(worldX+lx), (float)ly, (float)(worldZ+lz)};
for (const auto& tp : torchPositions) {
@ -965,7 +965,7 @@ int main(void)
// By default, windows have minimize, maximize, and close buttons on the top bar.
SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_VSYNC_HINT);
InitWindow(screenWidth, screenHeight, "MorriCraft v2.2.20");
InitWindow(screenWidth, screenHeight, "MorriCraft v2.2.21");
LoadConfig();
SetExitKey(KEY_NULL); // Prevent ESC from closing the window
@ -1029,7 +1029,7 @@ int main(void)
float updateTimer = 0.0f;
float downloadProgress = 0.0f;
std::string latestVersion = "";
std::string localVersion = "v2.2.20"; // Default fallback
std::string localVersion = "v2.2.21"; // Default fallback
// Read local version
std::ifstream vfile("assets/version.txt");
@ -1636,7 +1636,7 @@ int main(void)
// --- GLOBAL TIME & AUDIO MANAGEMENT ---
float cycleLength = 600.0f; // Slower day cycle (v2.2.20: cut speed in half)
float cycleLength = 600.0f; // Slower day cycle (v2.2.21: cut speed in half)
if (currentState == GAMEPLAY) gameTime += GetFrameTime();
float timeOfDay = fmodf(gameTime, cycleLength) / cycleLength;
float sunAngle = timeOfDay * 2.0f * 3.14159f - 3.14159f/2.0f;
@ -1990,7 +1990,7 @@ int main(void)
AddToInventory(targetBlock);
NetSetBlock(hitX, hitY, hitZ, AIR);
// Tool Durability Logic (v2.2.20)
// Tool Durability Logic (v2.2.21)
InventorySlot* slot = &hotbar[activeHotbarSlot];
if (slot->maxDurability > 0) {
slot->durability--;
@ -2146,6 +2146,7 @@ int main(void)
} else if (currentState == DOWNLOADING_UPDATE) {
static bool startedDownload = false;
static bool downloadFailed = false;
static bool isInstalling = false;
static bool downloadFinished = false;
static float currentProgress = 0.0f;
@ -2164,29 +2165,31 @@ int main(void)
std::string versionUrl = "https://git.linology.tech/michael/MorriCraft/raw/branch/master/release/version.txt";
// Download binary
int r1 = system(("curl -L -s -o " + binaryName + ".new \"" + binaryUrl + "\"").c_str());
currentProgress = 0.6f;
// v2.2.21: Download directly to the expected zip name
int r1 = system(("curl -L -s -o " + binaryName + " \"" + binaryUrl + "\"").c_str());
currentProgress = 0.7f;
// Download version
int r2 = system(("curl -L -s -o version.txt.new \"" + versionUrl + "\"").c_str());
currentProgress = 0.8f;
currentProgress = 0.9f;
if (r1 == 0 && r2 == 0) {
isInstalling = true;
#ifdef _WIN32
// Windows Update: Move exe, unzip assets
system("move MorriCraft.exe MorriCraft.old >nul 2>&1");
system("powershell -Command \"Expand-Archive -Path MorriCraft-Windows.zip -DestinationPath . -Force\"");
system(("powershell -Command \"Expand-Archive -Path " + binaryName + " -DestinationPath . -Force\"").c_str());
system("move version.txt.new version.txt >nul 2>&1");
system("copy version.txt assets\\version.txt >nul 2>&1");
system("del MorriCraft-Windows.zip");
system(("del " + binaryName).c_str());
#else
// Linux Update: Move binary, unzip assets
system("mv MorriCraft MorriCraft.old 2>/dev/null");
system("unzip -o MorriCraft-Linux.zip");
system(("unzip -o " + binaryName).c_str());
system("chmod +x MorriCraft");
system("mv version.txt.new version.txt 2>/dev/null");
system("cp version.txt assets/version.txt 2>/dev/null");
system("rm MorriCraft-Linux.zip");
system(("rm " + binaryName).c_str());
#endif
currentProgress = 1.0f;
downloadFinished = true;
@ -2206,7 +2209,13 @@ int main(void)
DrawRectangleRec(backBtn, DARKGRAY);
DrawTextEx(customFont, "BACK", (Vector2){ backBtn.x + 70, backBtn.y + 10 }, 20, 1.0f, WHITE);
} else {
DrawTextEx(customFont, "Updating...", (Vector2){ (float)currentWidth/2 - 50, (float)currentHeight/2 - 60 }, 24, 1.0f, YELLOW);
if (isInstalling) {
DrawTextEx(customFont, "Installing update...", (Vector2){ (float)currentWidth/2 - 80, (float)currentHeight/2 - 60 }, 24, 1.0f, GREEN);
} else {
DrawTextEx(customFont, "Downloading update...", (Vector2){ (float)currentWidth/2 - 90, (float)currentHeight/2 - 60 }, 24, 1.0f, YELLOW);
// Dynamic progress pulse (v2.2.21)
if (currentProgress < 0.7f) currentProgress += 0.001f;
}
int bw = 500, bh = 35;
Rectangle barBg = { (float)currentWidth/2 - bw/2, (float)currentHeight/2 - bh/2, (float)bw, (float)bh };
DrawRectangleRec(barBg, BLACK);
@ -2478,8 +2487,8 @@ int main(void)
DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE);
EndMode2D();
// Show Version Number (v2.2.20) in Red
DrawTextEx(customFont, "v2.2.20", (Vector2){ 20, (float)currentHeight - 30 }, 22, 1.0f, RED);
// Show Version Number (v2.2.21) in Red
DrawTextEx(customFont, "v2.2.21", (Vector2){ 20, (float)currentHeight - 30 }, 22, 1.0f, RED);
// --- PLAYER NAME POPUP (IF MISSING) ---
if (playerName == "") {
@ -2652,11 +2661,12 @@ int main(void)
if (worldFile.is_open()) {
worldFile >> globalSeedHash >> spawnSavedX >> spawnSavedY >> spawnSavedZ;
worldFile.close();
} else {
globalSeedHash = 12345;
spawnSavedX = 0; spawnSavedY = -1; spawnSavedZ = 0;
}
// Load Chests (v2.2.20)
// Load Chests (v2.2.21)
chestInventories.clear();
std::ifstream cf("saves/" + currentWorldName + "/chests.dat", std::ios::binary);
if (cf.is_open()) {
@ -2674,7 +2684,7 @@ int main(void)
cf.close();
}
// Load Torches (v2.2.20)
// Load Torches (v2.2.21)
torchPositions.clear();
std::ifstream tf("saves/" + currentWorldName + "/torches.dat", std::ios::binary);
if (tf.is_open()) {
@ -2958,7 +2968,7 @@ int main(void)
snprintf(worldName, sizeof(worldName), "%s", currentWorldName.c_str());
worldNameLen = strlen(worldName);
gameTime = 150.0f; // Start new world at 7:00 AM (v2.2.20 adjusted for slower cycle)
gameTime = 150.0f; // Start new world at 7:00 AM (v2.2.21 adjusted for slower cycle)
if (serverMode) {
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
@ -3105,7 +3115,7 @@ int main(void)
} else if (renderType == TORCH) {
for (Chunk* chunk : visibleChunks) {
for (auto& data : chunk->renderLists[TORCH]) {
// 3D Flickering Torch (v2.2.20)
// 3D Flickering Torch (v2.2.21)
float flicker = sinf(GetTime() * 12.0f) * 0.03f;
float h = 0.6f + flicker;
float w = 0.12f;
@ -3349,7 +3359,7 @@ int main(void)
(Vector2){ (float)(sx + (slotSize/2) - (countSize.x/2)), (float)(hotbarY + slotSize - 14) },
12, 1.0f, WHITE);
// Draw Hotbar Durability Bar (v2.2.20)
// Draw Hotbar Durability Bar (v2.2.21)
if (hotbar[s].maxDurability > 0 && hotbar[s].durability < hotbar[s].maxDurability) {
float durP = (float)hotbar[s].durability / hotbar[s].maxDurability;
int barW = slotSize - 10;
@ -3380,7 +3390,7 @@ int main(void)
DrawRectangleRec(slotRect, hov ? (Color){90,90,90,255} : (Color){60,60,60,255});
DrawRectangleLinesEx(slotRect, 2.0f, hov ? WHITE : (Color){100,100,100,200});
// Draw Durability Bar (v2.2.20)
// Draw Durability Bar (v2.2.21)
if (slot.maxDurability > 0 && slot.durability < slot.maxDurability) {
float durPercent = (float)slot.durability / slot.maxDurability;
int barW = slotRect.width - 10;
@ -3656,7 +3666,7 @@ int main(void)
}
}
if (hov && IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
// Right click: pick up/place one (v2.2.20)
// Right click: pick up/place one (v2.2.21)
if (mouseHeldItem.blockType == AIR) {
if (chestInv[i].blockType != AIR && chestInv[i].count > 0) {
mouseHeldItem = InventorySlot(chestInv[i].blockType, 1);
@ -3703,7 +3713,7 @@ int main(void)
}
}
if (hov && IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
// Right click logic for player inv in chest GUI (v2.2.20)
// Right click logic for player inv in chest GUI (v2.2.21)
if (mouseHeldItem.blockType == AIR) {
if (inventory[i].blockType != AIR && inventory[i].count > 0) {
mouseHeldItem = InventorySlot(inventory[i].blockType, 1);
@ -3880,7 +3890,7 @@ int main(void)
invf.close();
}
// Save Chests (v2.2.20)
// Save Chests (v2.2.21)
std::ofstream cf("saves/" + currentWorldName + "/chests.dat", std::ios::binary);
if (cf.is_open()) {
uint32_t count = (uint32_t)chestInventories.size();
@ -3896,7 +3906,7 @@ int main(void)
cf.close();
}
// Save Torches (v2.2.20)
// Save Torches (v2.2.21)
std::ofstream tf("saves/" + currentWorldName + "/torches.dat", std::ios::binary);
if (tf.is_open()) {
uint32_t count = (uint32_t)torchPositions.size();

View File

@ -1 +1 @@
v2.2.20
v2.2.21