diff --git a/MorriCraft-Windows.zip b/MorriCraft-Windows.zip index 1805398..4bbd49b 100644 Binary files a/MorriCraft-Windows.zip and b/MorriCraft-Windows.zip differ diff --git a/build-linux/MorriCraft b/build-linux/MorriCraft index e0a3edc..370c946 100755 Binary files a/build-linux/MorriCraft and b/build-linux/MorriCraft differ diff --git a/build-linux/assets/version.txt b/build-linux/assets/version.txt index 8cbbde4..4fd2b78 100644 --- a/build-linux/assets/version.txt +++ b/build-linux/assets/version.txt @@ -1 +1 @@ -v2.2.23 +v2.2.24 diff --git a/build-windows/MorriCraft.exe b/build-windows/MorriCraft.exe index 608a230..5a9a82d 100755 Binary files a/build-windows/MorriCraft.exe and b/build-windows/MorriCraft.exe differ diff --git a/build-windows/assets/version.txt b/build-windows/assets/version.txt index 8cbbde4..4fd2b78 100644 --- a/build-windows/assets/version.txt +++ b/build-windows/assets/version.txt @@ -1 +1 @@ -v2.2.23 +v2.2.24 diff --git a/release/MorriCraft-Linux.zip b/release/MorriCraft-Linux.zip index 271d36d..d9066d9 100644 Binary files a/release/MorriCraft-Linux.zip and b/release/MorriCraft-Linux.zip differ diff --git a/release/MorriCraft-Windows.zip b/release/MorriCraft-Windows.zip index a95755d..768b680 100644 Binary files a/release/MorriCraft-Windows.zip and b/release/MorriCraft-Windows.zip differ diff --git a/src/main.cpp b/src/main.cpp index d462f75..107ae46 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -173,7 +173,7 @@ static float playerHealth = 16.0f; static uint32_t localPlayerID = 0; static Sound hitSound; -enum MenuState { MAIN_MENU, OPTIONS_MENU, CREATE_WORLD_MENU, LOAD_WORLD_MENU, GAMEPLAY, PAUSE_MENU, CRAFTING_GUI, CHECKING_UPDATES, UPDATE_NOTES, UPDATE_FOUND, DOWNLOADING_UPDATE, CONNECT_MENU, SKIN_EDITOR, WORLD_CREATION_PROGRESS, CHEST_GUI, CHEAT_GUI }; +enum MenuState { MAIN_MENU, OPTIONS_MENU, CREATE_WORLD_MENU, LOAD_WORLD_MENU, GAMEPLAY, PAUSE_MENU, CRAFTING_GUI, CHECKING_UPDATES, UPDATE_NOTES, UPDATE_FOUND, DOWNLOADING_UPDATE, EXTRACTING_UPDATE, CONNECT_MENU, SKIN_EDITOR, WORLD_CREATION_PROGRESS, CHEST_GUI, CHEAT_GUI }; // Forward Declarations unsigned char GetExposedFaces(int lx, int ly, int lz, Chunk* chunk, Chunk* nxM, Chunk* nxP, Chunk* nzM, Chunk* nzP); @@ -627,6 +627,35 @@ float fbm(float x, float y, unsigned int seed) { // Forward-declare so FindSpawnY can call GenerateChunk void GenerateChunk(int cx, int cz); +// Find a spawn point near (0,0) that is far from biome edges +Vector2 FindIdealSpawn() { + float bestScore = -1.0f; + Vector2 bestPos = { 0, 0 }; + // Scan a spiral to find the most "stable" biome point + for (int r = 0; r < 500; r += 16) { + for (float a = 0; a < 2.0f * PI; a += 0.4f) { + float x = cosf(a) * r; + float z = sinf(a) * r; + float bn = fbm(x * 0.002f, z * 0.002f, globalSeedHash + 77777); + + // Score based on distance from the transition thresholds (-0.3, 0.3) + // We want points that are deeply in a biome (e.g. bn = 0.0, 0.7, or -0.7) + float distToEdge = fminf(fabsf(bn - 0.3f), fabsf(bn + 0.3f)); + + // Also prioritize points closer to origin if scores are similar + float finalScore = distToEdge - (r * 0.0001f); + + if (finalScore > bestScore) { + bestScore = finalScore; + bestPos = { x, z }; + } + } + // If we found a very stable point (dist > 0.2 from edge), stop early + if (bestScore > 0.2f) break; + } + return bestPos; +} + // Generate the spawn chunk and scan downward to find the first solid surface. // Returns the player eye-level Y (surface block top + 1.6 camera height). float FindSpawnY(int spawnX, int spawnZ) { @@ -1036,6 +1065,12 @@ int main(void) MenuState currentState = CHECKING_UPDATES; MenuState optionsReturnState = MAIN_MENU; + bool startedDownload = false; + bool downloadFailed = false; + bool isInstalling = false; + bool downloadFinished = false; + float currentProgress = 0.0f; + bool updateReady = false; float updateTimer = 0.0f; float downloadProgress = 0.0f; @@ -2157,16 +2192,10 @@ int main(void) currentState = MAIN_MENU; } } 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; - if (!startedDownload) { startedDownload = true; currentProgress = 0.1f; - std::thread([]() { + std::thread([&]() { std::string binaryUrl, binaryName; #ifdef _WIN32 binaryUrl = "https://git.linology.tech/michael/MorriCraft/raw/branch/master/release/MorriCraft-Windows.zip"; @@ -2178,27 +2207,34 @@ int main(void) std::string versionUrl = "https://git.linology.tech/michael/MorriCraft/raw/branch/master/release/version.txt"; // Download binary - // v2.2.23: Download directly to the expected zip name int r1 = system(("curl -L -s -o " + binaryName + " \"" + binaryUrl + "\"").c_str()); - currentProgress = 0.7f; + currentProgress = 0.85f; // Most of the way done after binary // Download version int r2 = system(("curl -L -s -o version.txt.new \"" + versionUrl + "\"").c_str()); - currentProgress = 0.9f; + currentProgress = 1.0f; if (r1 == 0 && r2 == 0) { + // Switch to extraction phase + currentState = EXTRACTING_UPDATE; isInstalling = true; + currentProgress = 0.0f; // Reset for extraction phase + #ifdef _WIN32 // Windows Update: Move exe, unzip assets system("move MorriCraft.exe MorriCraft.old >nul 2>&1"); + currentProgress = 0.3f; system(("powershell -Command \"Expand-Archive -Path " + binaryName + " -DestinationPath . -Force\"").c_str()); + currentProgress = 0.8f; system("move version.txt.new version.txt >nul 2>&1"); system("copy version.txt assets\\version.txt >nul 2>&1"); system(("del " + binaryName).c_str()); #else // Linux Update: Move binary, unzip assets system("mv MorriCraft MorriCraft.old 2>/dev/null"); + currentProgress = 0.3f; system(("unzip -o " + binaryName).c_str()); + currentProgress = 0.8f; system("chmod +x MorriCraft"); system("mv version.txt.new version.txt 2>/dev/null"); system("cp version.txt assets/version.txt 2>/dev/null"); @@ -2222,33 +2258,52 @@ int main(void) DrawRectangleRec(backBtn, DARKGRAY); DrawTextEx(customFont, "BACK", (Vector2){ backBtn.x + 70, backBtn.y + 10 }, 20, 1.0f, WHITE); } else { - 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.23) - if (currentProgress < 0.7f) currentProgress += 0.001f; - } + DrawTextEx(customFont, "Downloading update...", (Vector2){ (float)currentWidth/2 - 90, (float)currentHeight/2 - 60 }, 24, 1.0f, YELLOW); + // Dynamic progress pulse (v2.2.23) + 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); DrawRectangle(barBg.x, barBg.y, (int)(bw * currentProgress), bh, GREEN); DrawRectangleLinesEx(barBg, 2.0f, GRAY); DrawTextEx(customFont, TextFormat("%i%%", (int)(currentProgress * 100)), (Vector2){ barBg.x + bw + 15, barBg.y + 5 }, 20, 1.0f, WHITE); + } + } else if (currentState == EXTRACTING_UPDATE) { + DrawRectangle(0, 0, currentWidth, currentHeight, (Color){ 20, 20, 20, 255 }); + DrawTextEx(customFont, "Extracting and Installing Update...", (Vector2){ (float)currentWidth/2 - 150, (float)currentHeight/2 - 60 }, 24, 1.0f, GREEN); + + int bw = 500, bh = 35; + Rectangle barBg = { (float)currentWidth/2 - bw/2, (float)currentHeight/2 - bh/2, (float)bw, (float)bh }; + DrawRectangleRec(barBg, BLACK); + // We use the thread's progress for the extraction bar too + DrawRectangle(barBg.x, barBg.y, (int)(bw * 1.0f), bh, (Color){0, 228, 48, 150}); // Faded green background + DrawRectangle(barBg.x, barBg.y, (int)(bw * 1.0f), bh, GREEN); + DrawRectangleLinesEx(barBg, 2.0f, GRAY); + DrawTextEx(customFont, "Applying files...", (Vector2){ barBg.x, barBg.y + bh + 10 }, 18, 1.0f, GRAY); + + if (downloadFinished) { + DrawRectangle(0, 0, currentWidth, currentHeight, (Color){ 0, 0, 0, 230 }); + int pw = 500, ph = 220; + Rectangle pBox = { (float)currentWidth/2 - pw/2, (float)currentHeight/2 - ph/2, (float)pw, (float)ph }; + DrawRectangleRec(pBox, (Color){ 30, 30, 30, 255 }); + DrawRectangleLinesEx(pBox, 4.0f, GREEN); - if (downloadFinished) { - DrawRectangle(0, 0, currentWidth, currentHeight, (Color){ 0, 0, 0, 230 }); - int pw = 500, ph = 220; - Rectangle pBox = { (float)currentWidth/2 - pw/2, (float)currentHeight/2 - ph/2, (float)pw, (float)ph }; - DrawRectangleRec(pBox, (Color){ 30, 30, 30, 255 }); - - DrawTextEx(customFont, "UPDATE SUCCESSFUL!", (Vector2){ pBox.x + 80, pBox.y + 40 }, 28, 1.0f, GREEN); - DrawTextEx(customFont, "PLEASE RESTART THE CLIENT TO APPLY.", (Vector2){ pBox.x + 60, pBox.y + 90 }, 20, 1.0f, WHITE); - - Rectangle exitBtn = { pBox.x + pw/2 - 90, pBox.y + 145, 180, 45 }; - if (CheckCollisionPointRec(mousePos, exitBtn) && IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) exit(0); - DrawRectangleRec(exitBtn, MAROON); - DrawTextEx(customFont, "EXIT GAME", (Vector2){ exitBtn.x + 40, exitBtn.y + 12 }, 20, 1.0f, WHITE); + DrawTextEx(customFont, "UPDATE SUCCESSFUL!", (Vector2){ pBox.x + 80, pBox.y + 40 }, 28, 1.0f, GREEN); + DrawTextEx(customFont, "THE GAME NEEDS TO RESTART TO APPLY.", (Vector2){ pBox.x + 60, pBox.y + 90 }, 20, 1.0f, WHITE); + + Rectangle restartBtn = { pBox.x + pw/2 - 90, pBox.y + 145, 180, 45 }; + bool hRestart = CheckCollisionPointRec(mousePos, restartBtn); + DrawRectangleRec(restartBtn, hRestart ? GREEN : DARKGREEN); + DrawTextEx(customFont, "RESTART", (Vector2){ restartBtn.x + 45, restartBtn.y + 12 }, 20, 1.0f, WHITE); + + if (hRestart && IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) { + #ifdef _WIN32 + system("start MorriCraft.exe"); + #else + system("./MorriCraft &"); + #endif + exit(0); } } } else if (currentState == CHEAT_GUI) { @@ -2438,9 +2493,10 @@ int main(void) if (chunksGeneratedCount >= totalChunksToPreGen) { // FINALIZE: Place player and save world data if (isNewWorldGeneration) { - float spawnY = FindSpawnY(0, 0); - camera3D.position = (Vector3){ 0.0f, spawnY, 0.0f }; - camera3D.target = (Vector3){ 0.0f, spawnY, 1.0f }; + Vector2 idealSpawn = FindIdealSpawn(); + float spawnY = FindSpawnY((int)idealSpawn.x, (int)idealSpawn.y); + camera3D.position = (Vector3){ idealSpawn.x, spawnY, idealSpawn.y }; + camera3D.target = (Vector3){ idealSpawn.x, spawnY, idealSpawn.y + 1.0f }; std::ofstream worldFile2("saves/" + currentWorldName + "/world.dat"); if (worldFile2.is_open()) { @@ -3246,27 +3302,36 @@ int main(void) itemPos = Vector3Add(itemPos, Vector3Scale(upVM, 0.05f)); itemPos = Vector3Add(itemPos, Vector3Scale(rightVM, -0.05f)); - Texture2D itemTex = (heldBT == GRASS) ? grassTopTexture : (heldBT == CRAFTING_TABLE ? craftingSideTexture : blockTextures[heldBT]); - if (itemTex.id > 0) { - if (heldBT < STICK) { - // 3D Block in hand - rlSetTexture(itemTex.id); - rlPushMatrix(); - rlTranslatef(itemPos.x, itemPos.y, itemPos.z); - rlRotatef(camYaw * 180.0f/PI + 45.0f, 0, 1, 0); - rlRotatef(20.0f, 1, 0, 1); + if (heldBT < STICK) { + // 3D Block in hand + rlPushMatrix(); + rlTranslatef(itemPos.x, itemPos.y, itemPos.z); + rlRotatef(camYaw * 180.0f/PI + 45.0f, 0, 1, 0); + rlRotatef(20.0f, 1, 0, 1); + rlScalef(0.15f, 0.15f, 0.15f); + + if (heldBT == GRASS) { + DrawGrassBlock((Vector3){0,0,0}, blockTextures[GRASS].id, grassTopTexture.id, blockTextures[DIRT].id, WHITE, 63); + } else if (heldBT == LOG) { + DrawLog((Vector3){0,0,0}, logSideTexture.id, logTopTexture.id, WHITE, 63); + } else if (heldBT == CRAFTING_TABLE) { + DrawCraftingTable((Vector3){0,0,0}, craftingSideTexture.id, craftingTopTexture.id, blockTextures[DIRT].id, WHITE, 63); + } else { + rlSetTexture(blockTextures[heldBT].id); rlBegin(RL_QUADS); rlColor4ub(255, 255, 255, 255); - DrawCubeVertices(0,0,0, 0.15f, 0.15f, 0.15f, 63); + DrawCubeVertices(0,0,0, 1.0f, 1.0f, 1.0f, 63); rlEnd(); - rlPopMatrix(); - rlSetTexture(0); - } else { - // Item (Stick/Axe) as Billboard + } + rlPopMatrix(); + rlSetTexture(0); + } else { + // Item (Stick/Axe) as Billboard + Texture2D itemTex = blockTextures[heldBT]; + if (itemTex.id > 0) { Rectangle src = { 0, 0, (float)itemTex.width, (float)itemTex.height }; Vector2 itemSize = { 0.35f, 0.35f }; Vector2 pivot = { -itemSize.x/2.0f, -itemSize.y/2.0f }; - // v2.2.23: Rotated by 90 degrees (135 -> 45) DrawBillboardPro(camera3D, itemTex, src, itemPos, camera3D.up, itemSize, pivot, 45.0f + swingVal * 40.0f, WHITE); } }