diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 7ae419ffc..ed043dc98 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -9,29 +9,16 @@ RUN apt-get update \ && apt-get update \ && apt-get install -y \ build-essential \ - cmake \ - libglfw3-dev \ + python3 \ + ninja-build \ + meson \ + libsdl2-dev \ libgl-dev \ libglu1-mesa-dev \ - libopenal-dev \ - libvorbis-dev \ - libpng-dev \ - libpthread-stubs0-dev \ - clang \ - lld \ - meson \ - ninja-build \ - gcc-15 \ - g++-15 \ + libpthread-stubs0-dev # Clean up lol && apt-get autoremove -y \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* -# Set GCC 15 as default -RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 100 \ - && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 100 \ - && update-alternatives --install /usr/bin/cc cc /usr/bin/gcc 100 \ - && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 100 - ENV DEBIAN_FRONTEND=dialog \ No newline at end of file diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 42cb25d20..fceea68b3 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -1,4 +1,4 @@ -name: Build Linux Release +name: Build (Linux, x86_64) on: push: @@ -25,9 +25,6 @@ on: jobs: build-linux: runs-on: ubuntu-latest - concurrency: - group: build-linux-${{ github.ref }} - cancel-in-progress: true steps: - name: Checkout repository uses: actions/checkout@v4 @@ -35,26 +32,10 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y build-essential python3 python3-pip python3-setuptools libgl1-mesa-dev libglu1-mesa-dev libglfw3-dev libpng-dev pkg-config clang lld ccache libssl-dev + sudo apt-get install -y build-essential python3 ninja-build meson libsdl2-dev libgl-dev libglu1-mesa-dev libpthread-stubs0-dev # Set a reasonable ccache size ccache -M 5G || true - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - - name: Cache pip packages - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('.github/workflows/build-linux.yml') }} - - - name: Install Meson and Ninja (pip) - run: | - python -m pip install --upgrade pip - pip install meson ninja - - name: Restore ccache uses: actions/cache@v4 with: @@ -75,7 +56,51 @@ jobs: run: | mkdir -p "$CCACHE_DIR" export CCACHE_DIR="$CCACHE_DIR" - meson setup build_meson --wipe --buildtype=release + meson setup build_release --wipe --buildtype=release --native-file=./scripts/llvm_native.txt + + - name: Build with Meson + env: + CC: "ccache clang" + CXX: "ccache clang++" + CCACHE_DIR: ${{ runner.temp }}/ccache + run: | + export CCACHE_DIR="${{ runner.temp }}/ccache" + # Use all available cores for faster parallel builds + meson compile -C build_release -j $(nproc) -v Minecraft.Client + + - name: Install patchelf + run: sudo apt-get install -y patchelf + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: minecraft-client-linux-release_exe-${{ github.sha }} + path: build_release/Minecraft.Client/Minecraft.Client + retention-days: 7 + build-linux-debug: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential python3 ninja-build meson libsdl2-dev libgl-dev libglu1-mesa-dev libpthread-stubs0-dev + # Set a reasonable ccache size + ccache -M 5G || true + + - name: Restore ccache + uses: actions/cache@v4 + with: + path: ~/.ccache + key: ${{ runner.os }}-ccache-debug-${{ hashFiles('**/meson.build') }} + + - name: Restore meson cache + uses: actions/cache@v4 + with: + path: ~/.cache/meson + key: ${{ runner.os }}-meson-debug-${{ hashFiles('**/meson.build') }} - name: Configure Meson (debug) env: @@ -85,9 +110,9 @@ jobs: run: | mkdir -p "$CCACHE_DIR" export CCACHE_DIR="$CCACHE_DIR" - meson setup build_debug --wipe --buildtype=debug + meson setup build_debug --wipe --buildtype=debug --native-file=./scripts/llvm_native.txt - - name: Build with Ninja + - name: Build Debug with Meson env: CC: "ccache clang" CXX: "ccache clang++" @@ -95,137 +120,11 @@ jobs: run: | export CCACHE_DIR="${{ runner.temp }}/ccache" # Use all available cores for faster parallel builds - ninja -C build_meson -j$(nproc) -v + meson compile -C build_debug -j $(nproc) -v Minecraft.Client - - name: Build Debug with Ninja - env: - CC: "ccache clang" - CXX: "ccache clang++" - CCACHE_DIR: ${{ runner.temp }}/ccache - run: | - export CCACHE_DIR="${{ runner.temp }}/ccache" - ninja -C build_debug -j$(nproc) -v - - - name: Install patchelf - run: sudo apt-get install -y patchelf - - - name: Bundle executable + libraries - env: - GITHUB_SHA: ${{ github.sha }} - run: | - set -euo pipefail - EXE_PATH=build_meson/Minecraft.Client/Minecraft.Client - if [ ! -f "$EXE_PATH" ]; then - echo "ERROR: expected executable at $EXE_PATH" >&2 - ls -la build_meson || true - exit 1 - fi - - SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-8) - BUNDLE=out/minecraft-client-linux-${SHORT_SHA} - mkdir -p "$BUNDLE/lib" - - # Copy the binary - cp "$EXE_PATH" "$BUNDLE/Minecraft.Client" - - # Collect non-system shared library dependencies and copy them in. - # Exclude glibc/libstdc++/libgcc — these are ABI-specific and must - # come from the user's system, not from the build runner. - ldd "$EXE_PATH" \ - | awk '/=>/ { print $3 }' \ - | grep -v '^(' \ - | grep -Ev '/(libc|libm|libdl|libpthread|librt|libgcc_s|libstdc\+\+|ld-linux)[^/]*\.so' \ - | sort -u \ - | while read -r lib; do - [ -f "$lib" ] && cp "$lib" "$BUNDLE/lib/" || true - done - - # Patch the binary RPATH so it finds libs in ./lib at runtime - patchelf --set-rpath '$ORIGIN/lib' "$BUNDLE/Minecraft.Client" - - # Write a launcher script - cat > "$BUNDLE/run.sh" << 'RUNEOF' - #!/usr/bin/env bash - # 4JCraft Linux launcher - # ------------------------------------------------------------------- - # IMPORTANT: Before running, copy the "Common" assets folder from - # https://github.com/smartcmd/MinecraftConsoles/releases/tag/nightly - # (LCEWindows64.zip → extract → copy "Common" next to this script) - # ------------------------------------------------------------------- - DIR="$(cd "$(dirname "$0")" && pwd)" - if [ ! -d "$DIR/Common" ]; then - echo "ERROR: Missing 'Common' assets folder." - echo "Download LCEWindows64.zip from:" - echo " https://github.com/smartcmd/MinecraftConsoles/releases/tag/nightly" - echo "Extract it and copy the 'Common' folder next to this run.sh file." - exit 1 - fi - cd "$DIR" - exec ./Minecraft.Client "$@" - RUNEOF - chmod +x "$BUNDLE/run.sh" - - # Write a README - cat > "$BUNDLE/README.txt" << 'EOF' - 4JCraft Linux Build - =================== - This bundle contains: - Minecraft.Client - compiled Linux binary - lib/ - all required shared libraries (GL, GLFW, png, zlib, X11 etc.) - run.sh - launcher script - - To run: - 1. Download LCEWindows64.zip from the MinecraftConsoles nightly release: - https://github.com/smartcmd/MinecraftConsoles/releases/tag/nightly - 2. Extract it and copy the "Common" folder into this directory - (so you have Common/ sitting next to run.sh) - 3. Run: ./run.sh [--width W] [--height H] [--fullscreen] - EOF - - echo "Bundle ready: $BUNDLE" - ls -lh "$BUNDLE" "$BUNDLE/lib" - - - name: Bundle debug executable + libraries - env: - GITHUB_SHA: ${{ github.sha }} - run: | - set -euo pipefail - EXE_PATH=build_debug/Minecraft.Client/Minecraft.Client - if [ ! -f "$EXE_PATH" ]; then - echo "ERROR: expected debug executable at $EXE_PATH" >&2 - ls -la build_debug || true - exit 1 - fi - - SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-8) - BUNDLE=out/minecraft-client-linux-${SHORT_SHA}-debug - mkdir -p "$BUNDLE/lib" - - # Copy the binary - cp "$EXE_PATH" "$BUNDLE/Minecraft.Client.debug" - - # Collect non-system shared library dependencies and copy them in. - ldd "$EXE_PATH" \ - | awk '/=>/ { print $3 }' \ - | grep -v '^(' \ - | grep -Ev '/(libc|libm|libdl|libpthread|librt|libgcc_s|libstdc\+\+|ld-linux)[^/]*\.so' \ - | sort -u \ - | while read -r lib; do - [ -f "$lib" ] && cp "$lib" "$BUNDLE/lib/" || true - done - - # Patch the binary RPATH so it finds libs in ./lib at runtime - patchelf --set-rpath '$ORIGIN/lib' "$BUNDLE/Minecraft.Client.debug" - - # Keep a copy of the unstripped debug binary (symbols are already present in debug build) - echo "Debug bundle ready: $BUNDLE" - ls -lh "$BUNDLE" "$BUNDLE/lib" - - - name: Upload artifact + - name: Upload debug executable uses: actions/upload-artifact@v4 with: - name: minecraft-client-linux-${{ github.sha }} - path: | - out/minecraft-client-linux-*/ - out/minecraft-client-linux-*-debug/ + name: minecraft-client-linux-debug_exe-${{ github.sha }} + path: build_debug/Minecraft.Client/Minecraft.Client retention-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index bcfa32d7d..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: CI Build - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y build-essential pkg-config ca-certificates curl git \ - libgl1-mesa-dev libglu1-mesa-dev libglfw3-dev libpng-dev libx11-dev \ - libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libudev-dev - - - name: Install Meson and Ninja (pip) - run: | - python -m pip install --upgrade pip - pip install meson ninja - - - name: Configure Meson - run: | - meson setup build_meson --wipe --buildtype=release - - - name: Build with Ninja - run: | - ninja -C build_meson -v - - - name: Package build output - run: | - tar -czf minecraft-binaries.tar.gz -C build_meson . - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: minecraft-binaries - path: minecraft-binaries.tar.gz diff --git a/.gitignore b/.gitignore index ffdd21a84..0c9c8e1f4 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,7 @@ meson-logs/ *.out *.d compile_commands.json - +.clangd # ----- Scratch / legacy ----- diff --git a/4J.Input/4J_Input.cpp b/4J.Input/4J_Input.cpp index 99ed54adb..2ed4de5e4 100644 --- a/4J.Input/4J_Input.cpp +++ b/4J.Input/4J_Input.cpp @@ -1,536 +1,338 @@ -// 4J_Input.cpp - GLFW keyboard + mouse input for the Linux port -// Replaces the SDL2 oldimpl with GLFW equivalents. -// Uses glfwGetCurrentContext() to get the window the render manager created, -// avoiding a coupling dependency on 4J_Render.h. - #include "4J_Input.h" #include "../Minecraft.Client/Platform/Common/App_enums.h" -#include +#include "../4J.Render/4J_Render.h" +#include #include #include #include C_4JInput InputManager; -// --------------------------------------------------------------------------- -// State - all static to avoid adding new fields to C_4JInput -// --------------------------------------------------------------------------- - -static const int KEY_COUNT = GLFW_KEY_LAST + 1; // 349 on GLFW 3 - +static const int KEY_COUNT = SDL_NUM_SCANCODES; +static const float MOUSE_SCALE = 0.015f; +// Vars +static bool s_sdlInitialized = false; static bool s_keysCurrent[KEY_COUNT] = {}; -static bool s_keysPrev[KEY_COUNT] = {}; - +static bool s_keysPrev [KEY_COUNT] = {}; static bool s_mouseLeftCurrent = false, s_mouseLeftPrev = false; static bool s_mouseRightCurrent = false, s_mouseRightPrev = false; +static bool s_menuDisplayed[4] = {}; +static bool s_prevMenuDisplayed = false; +static bool s_snapTaken = false; +static float s_accumRelX = 0, s_accumRelY = 0; +static float s_snapRelX = 0, s_snapRelY = 0; -// Accumulated cursor delta from the GLFW cursor-pos callback. -// Snapshotted into s_frameRelX/Y at Tick() start, then reset to 0. -static double s_lastCursorX = 0.0, s_lastCursorY = 0.0; -static bool s_cursorInitialized = false; -static float s_mouseAccumX = 0.0f, s_mouseAccumY = 0.0f; // callback accumulator -static float s_frameRelX = 0.0f, s_frameRelY = 0.0f; // per-frame snapshot +static int s_scrollTicksForButtonPressed = 0; +static int s_scrollTicksForGetValue = 0; +static int s_scrollTicksSnap = 0; +static bool s_scrollSnapTaken = false; -// Scroll wheel -static float s_scrollAccum = 0.0f; // callback accumulator -static float s_scrollFrame = 0.0f; // current frame snapshot -static float s_scrollPrevFrame = 0.0f; - -// Mouse lock / menu state -static bool s_mouseLocked = false; -static bool s_menuDisplayed[4] = {}; -static bool s_prevMenuDisplayed = true; // start as "in menu" so auto-lock triggers after first frame - -// Sensitivity: scales raw pixel delta before sqrt-compression -// Smaller value = less mouse movement per pixel -static const float MOUSE_SCALE = 0.012f; - -// --------------------------------------------------------------------------- -// GLFW window (obtained lazily via glfwGetCurrentContext on the render thread) -// --------------------------------------------------------------------------- -static GLFWwindow *s_inputWindow = nullptr; - -static GLFWwindow *getWindow() { - if (!s_inputWindow) { - s_inputWindow = glfwGetCurrentContext(); - } - return s_inputWindow; -} - -// --------------------------------------------------------------------------- -// GLFW callbacks -// --------------------------------------------------------------------------- - -static void onCursorPos(GLFWwindow* w, double x, double y) { - float scaleX = 1; - float scaleY = 1; - glfwGetWindowContentScale(w, &scaleX, &scaleY); - - x *= scaleX; - y *= scaleX; - - if (s_cursorInitialized) { - s_mouseAccumX += (float)(x - s_lastCursorX); - s_mouseAccumY += (float)(y - s_lastCursorY); - } else { - s_cursorInitialized = true; - } - - s_lastCursorX = x; - s_lastCursorY = y; -} - -static void onScroll(GLFWwindow * /*w*/, double /*xoffset*/, double yoffset) { - s_scrollAccum += (float)yoffset; -} - -// --------------------------------------------------------------------------- -// Helpers -// --------------------------------------------------------------------------- - -static inline bool KDown(int key) { - return (key >= 0 && key < KEY_COUNT) ? s_keysCurrent[key] : false; -} -static inline bool KPressed(int key) { - return (key >= 0 && key < KEY_COUNT) ? (s_keysCurrent[key] && !s_keysPrev[key]) : false; -} -static inline bool KReleased(int key) { - return (key >= 0 && key < KEY_COUNT) ? (!s_keysCurrent[key] && s_keysPrev[key]) : false; -} - -static inline bool MouseLDown() { return s_mouseLeftCurrent; } -static inline bool MouseLPressed() { return s_mouseLeftCurrent && !s_mouseLeftPrev; } -static inline bool MouseLReleased() { return !s_mouseLeftCurrent && s_mouseLeftPrev; } -static inline bool MouseRDown() { return s_mouseRightCurrent; } -static inline bool MouseRPressed() { return s_mouseRightCurrent && !s_mouseRightPrev; } -static inline bool MouseRReleased() { return !s_mouseRightCurrent && s_mouseRightPrev; } - -static inline bool WheelUp() { return s_scrollFrame > 0.1f; } -static inline bool WheelDown() { return s_scrollFrame < -0.1f; } -static inline bool WheelUpEdge() { return s_scrollFrame > 0.1f && s_scrollPrevFrame <= 0.1f; } -static inline bool WheelDownEdge() { return s_scrollFrame < -0.1f && s_scrollPrevFrame >= -0.1f; } - -// Keys to snapshot each Tick (avoid iterating all 349 entries) +// We set all the watched keys +// I don't know if I'll need to change this if we add chat support soon. static const int s_watchedKeys[] = { - GLFW_KEY_W, GLFW_KEY_A, GLFW_KEY_S, GLFW_KEY_D, - GLFW_KEY_SPACE, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, - GLFW_KEY_E, GLFW_KEY_Q, GLFW_KEY_F, - GLFW_KEY_ESCAPE, GLFW_KEY_ENTER, - GLFW_KEY_F3, GLFW_KEY_F5, - GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT, - GLFW_KEY_PAGE_UP, GLFW_KEY_PAGE_DOWN, - GLFW_KEY_TAB, - GLFW_KEY_LEFT_CONTROL, GLFW_KEY_RIGHT_CONTROL, - GLFW_KEY_1, GLFW_KEY_2, GLFW_KEY_3, GLFW_KEY_4, GLFW_KEY_5, - GLFW_KEY_6, GLFW_KEY_7, GLFW_KEY_8, GLFW_KEY_9, + SDL_SCANCODE_W, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D, + SDL_SCANCODE_SPACE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_RSHIFT, + SDL_SCANCODE_E, SDL_SCANCODE_Q, SDL_SCANCODE_F, + SDL_SCANCODE_C, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_RETURN, + SDL_SCANCODE_F3, SDL_SCANCODE_F5, + SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, + SDL_SCANCODE_PAGEUP, SDL_SCANCODE_PAGEDOWN, + SDL_SCANCODE_TAB, SDL_SCANCODE_LCTRL, SDL_SCANCODE_RCTRL, + SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, + SDL_SCANCODE_5, SDL_SCANCODE_6, SDL_SCANCODE_7, SDL_SCANCODE_8, + SDL_SCANCODE_9, }; static const int s_watchedKeyCount = (int)(sizeof(s_watchedKeys) / sizeof(s_watchedKeys[0])); -// --------------------------------------------------------------------------- -// C_4JInput::Initialise -// --------------------------------------------------------------------------- -void C_4JInput::Initialise(int /*iInputStateC*/, unsigned char /*ucMapC*/, - unsigned char /*ucActionC*/, unsigned char /*ucMenuActionC*/) { - memset(s_keysCurrent, 0, sizeof(s_keysCurrent)); - memset(s_keysPrev, 0, sizeof(s_keysPrev)); - memset(s_menuDisplayed, 0, sizeof(s_menuDisplayed)); +static inline bool KDown (int sc) { return (sc > 0 && sc < KEY_COUNT) ? s_keysCurrent[sc] : false; } +static inline bool KPressed (int sc) { return (sc > 0 && sc < KEY_COUNT) ? !s_keysPrev[sc] && s_keysCurrent[sc] : false; } +static inline bool KReleased(int sc) { return (sc > 0 && sc < KEY_COUNT) ? s_keysPrev[sc] && !s_keysCurrent[sc] : false; } - s_mouseLeftCurrent = s_mouseLeftPrev = false; - s_mouseRightCurrent = s_mouseRightPrev = false; - s_mouseAccumX = s_mouseAccumY = 0.0f; - s_frameRelX = s_frameRelY = 0.0f; - s_scrollAccum = s_scrollFrame = s_scrollPrevFrame = 0.0f; - s_mouseLocked = false; - s_prevMenuDisplayed = true; // triggers auto-lock once game leaves first menu - s_cursorInitialized = false; +static inline bool MouseLDown () { return s_mouseLeftCurrent; } +static inline bool MouseLPressed () { return s_mouseLeftCurrent && !s_mouseLeftPrev; } +static inline bool MouseLReleased() { return !s_mouseLeftCurrent && s_mouseLeftPrev; } +static inline bool MouseRDown () { return s_mouseRightCurrent; } +static inline bool MouseRPressed () { return s_mouseRightCurrent && !s_mouseRightPrev; } +static inline bool MouseRReleased() { return !s_mouseRightCurrent && s_mouseRightPrev; } - GLFWwindow *w = getWindow(); - if (w) { - glfwSetCursorPosCallback(w, onCursorPos); - glfwSetScrollCallback(w, onScroll); - // NOTE: GLFW_RAW_MOUSE_MOTION must only be set when cursor mode is - // GLFW_CURSOR_DISABLED (Wayland zwp_relative_pointer_v1 requirement). - // It is activated at the cursor-lock call sites below in Tick(). +// get directly into SDL events before the game queue can steal them. +// this took me a while. +static int SDLCALL EventWatcher(void*, SDL_Event* e) { + if (e->type == SDL_MOUSEWHEEL) { + int y = e->wheel.y; + if (e->wheel.direction == SDL_MOUSEWHEEL_FLIPPED) { + y = -y; + } + s_scrollTicksForGetValue += y; + s_scrollTicksForButtonPressed += y; + } else if (e->type == SDL_MOUSEBUTTONDOWN) { + if (e->button.button == 4) { + s_scrollTicksForGetValue++; + s_scrollTicksForButtonPressed++; + } else if (e->button.button == 5) { + s_scrollTicksForGetValue--; + s_scrollTicksForButtonPressed--; + } + } else if (e->type == SDL_MOUSEMOTION) { + s_accumRelX += (float)e->motion.xrel; + s_accumRelY += (float)e->motion.yrel; } - - printf("[4J_Input] GLFW input initialised\n"); - printf(" WASD=move Mouse=look LMB=attack RMB=use\n"); - printf(" Space=jump LShift=sneak E=inventory Q=drop Esc=pause\n"); - printf(" F5=3rd-person F3=debug Scroll=hotbar\n"); - fflush(stdout); + return 1; } -// --------------------------------------------------------------------------- -// C_4JInput::Tick (called once per frame, BEFORE Present / glfwPollEvents) -// --------------------------------------------------------------------------- -void C_4JInput::Tick(void) { - GLFWwindow *w = getWindow(); - if (!w) return; +static int ScrollSnap() { + if (!s_scrollSnapTaken) { + s_scrollTicksSnap = s_scrollTicksForButtonPressed; + s_scrollTicksForButtonPressed = 0; + s_scrollSnapTaken = true; + } + return s_scrollTicksSnap; +} + +static void TakeSnapIfNeeded() { + if (!s_snapTaken) { + s_snapRelX = s_accumRelX; s_accumRelX = 0; + s_snapRelY = s_accumRelY; s_accumRelY = 0; + s_snapTaken = true; + } +} +// We initialize the SDL input +void C_4JInput::Initialise(int, unsigned char, unsigned char, unsigned char) { + if (!s_sdlInitialized) { + if (SDL_WasInit(SDL_INIT_VIDEO) == 0) { + SDL_Init(SDL_INIT_VIDEO); + } + SDL_AddEventWatch(EventWatcher, NULL); + s_sdlInitialized = true; + } + + memset(s_keysCurrent, 0, sizeof(s_keysCurrent)); + memset(s_keysPrev, 0, sizeof(s_keysPrev)); + memset(s_menuDisplayed, 0, sizeof(s_menuDisplayed)); + + s_mouseLeftCurrent = s_mouseLeftPrev = s_mouseRightCurrent = s_mouseRightPrev = false; + s_accumRelX = s_accumRelY = s_snapRelX = s_snapRelY = 0; + // i really gotta name these vars better.. + s_scrollTicksForButtonPressed = s_scrollTicksForGetValue = s_scrollTicksSnap = 0; + s_snapTaken = s_scrollSnapTaken = s_prevMenuDisplayed = false; + + if (s_sdlInitialized) + SDL_SetRelativeMouseMode(SDL_TRUE); +} +// Each tick we update the input state by polling SDL, this is where we get the kbd and mouse state. +void C_4JInput::Tick() { + if (!s_sdlInitialized) return; - // 1. Save previous frame memcpy(s_keysPrev, s_keysCurrent, sizeof(s_keysCurrent)); s_mouseLeftPrev = s_mouseLeftCurrent; s_mouseRightPrev = s_mouseRightCurrent; - s_scrollPrevFrame = s_scrollFrame; + s_snapTaken = false; + s_scrollSnapTaken = false; + s_snapRelX = s_snapRelY = 0; + s_scrollTicksSnap = 0; - // 2. Snapshot current keyboard state for watched keys - for (int i = 0; i < s_watchedKeyCount; i++) { - int k = s_watchedKeys[i]; - s_keysCurrent[k] = (glfwGetKey(w, k) == GLFW_PRESS); + SDL_PumpEvents(); + + if (s_menuDisplayed[0]) { + s_scrollTicksForGetValue = 0; } - // 3. Snapshot and reset scroll accumulator - s_scrollFrame = s_scrollAccum; - s_scrollAccum = 0.0f; - - // 4. Mouse-lock management based on menu display state - bool menuNow = s_menuDisplayed[0]; - - if (menuNow && s_mouseLocked) { - // Re-entered a menu → release mouse cursor - s_mouseLocked = false; - if (glfwRawMouseMotionSupported()) - glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE); - glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - // Discard stale delta so the view doesn't jerk on re-lock - s_mouseAccumX = s_mouseAccumY = 0.0f; - s_cursorInitialized = false; + const Uint8 *state = SDL_GetKeyboardState(NULL); + for (int i = 0; i < s_watchedKeyCount; ++i) { + int sc = s_watchedKeys[i]; + if (sc > 0 && sc < KEY_COUNT) s_keysCurrent[sc] = state[sc] != 0; } - if (!menuNow && s_prevMenuDisplayed && !s_mouseLocked) { - // Left the menu → lock mouse for look control - s_mouseLocked = true; - glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - // Enable raw (un-accelerated) relative motion now that cursor is disabled. - // On Wayland this activates zwp_relative_pointer_v1 for sub-pixel precise - // mouse deltas; on X11 it bypasses the compositor acceleration curve. - if (glfwRawMouseMotionSupported()) - glfwSetInputMode(w, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); - s_mouseAccumX = s_mouseAccumY = 0.0f; - s_cursorInitialized = false; + + Uint32 btns = SDL_GetMouseState(NULL, NULL); + s_mouseLeftCurrent = (btns & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; + s_mouseRightCurrent = (btns & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; + + if (!SDL_GetRelativeMouseMode()) { + s_accumRelX = 0; + s_accumRelY = 0; } - s_prevMenuDisplayed = menuNow; - // 5. Snapshot and reset mouse delta from callback - s_frameRelX = s_mouseAccumX; - s_frameRelY = s_mouseAccumY; - s_mouseAccumX = s_mouseAccumY = 0.0f; - - // 6. Mouse buttons (only meaningful when locked in-game) - s_mouseLeftCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); - s_mouseRightCurrent = (glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); + if (!SDL_GetKeyboardFocus()) { + SDL_Window *mf = SDL_GetMouseFocus(); + if (mf) { SDL_RaiseWindow(mf); SDL_SetWindowGrab(mf, SDL_TRUE); } + } } -// --------------------------------------------------------------------------- -// ButtonDown – is action held this frame? -// --------------------------------------------------------------------------- -bool C_4JInput::ButtonDown(int /*iPad*/, unsigned char ucAction) { +int C_4JInput::GetHotbarSlotPressed(int iPad) { + if (iPad != 0) return -1; + + constexpr size_t NUM_HOTBAR_SLOTS = 9; + + static const int sc[NUM_HOTBAR_SLOTS] = { + SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, + SDL_SCANCODE_5, SDL_SCANCODE_6, SDL_SCANCODE_7, SDL_SCANCODE_8, + SDL_SCANCODE_9, + }; + static bool s_wasDown[NUM_HOTBAR_SLOTS] = {}; + + for (int i = 0; i < NUM_HOTBAR_SLOTS; ++i) { + bool down = KDown(sc[i]); + bool pressed = down && !s_wasDown[i]; + s_wasDown[i] = down; + if (pressed) return i; + } + return -1; +} + +#define ACTION_CASES(FN) \ +case ACTION_MENU_UP: return FN(SDL_SCANCODE_UP); \ +case ACTION_MENU_DOWN: return FN(SDL_SCANCODE_DOWN); \ +case ACTION_MENU_LEFT: return FN(SDL_SCANCODE_LEFT); \ +case ACTION_MENU_RIGHT: return FN(SDL_SCANCODE_RIGHT); \ +case ACTION_MENU_PAGEUP: return FN(SDL_SCANCODE_PAGEUP); \ +case ACTION_MENU_PAGEDOWN: return FN(SDL_SCANCODE_PAGEDOWN); \ +case ACTION_MENU_OK: return FN(SDL_SCANCODE_RETURN); \ +case ACTION_MENU_CANCEL: return FN(SDL_SCANCODE_ESCAPE); \ +case MINECRAFT_ACTION_JUMP: return FN(SDL_SCANCODE_SPACE); \ +case MINECRAFT_ACTION_FORWARD: return FN(SDL_SCANCODE_W); \ +case MINECRAFT_ACTION_BACKWARD: return FN(SDL_SCANCODE_S); \ +case MINECRAFT_ACTION_LEFT: return FN(SDL_SCANCODE_A); \ +case MINECRAFT_ACTION_RIGHT: return FN(SDL_SCANCODE_D); \ +case MINECRAFT_ACTION_INVENTORY: return FN(SDL_SCANCODE_E); \ +case MINECRAFT_ACTION_PAUSEMENU: return FN(SDL_SCANCODE_ESCAPE); \ +case MINECRAFT_ACTION_DROP: return FN(SDL_SCANCODE_Q); \ +case MINECRAFT_ACTION_CRAFTING: return FN(SDL_SCANCODE_C); \ +case MINECRAFT_ACTION_RENDER_THIRD_PERSON:return FN(SDL_SCANCODE_F5); \ +case MINECRAFT_ACTION_GAME_INFO: return FN(SDL_SCANCODE_F3); \ +case MINECRAFT_ACTION_DPAD_LEFT: return FN(SDL_SCANCODE_LEFT); \ +case MINECRAFT_ACTION_DPAD_RIGHT: return FN(SDL_SCANCODE_RIGHT); \ +case MINECRAFT_ACTION_DPAD_UP: return FN(SDL_SCANCODE_UP); \ +case MINECRAFT_ACTION_DPAD_DOWN: return FN(SDL_SCANCODE_DOWN); \ +default: return false; + +bool C_4JInput::ButtonDown(int iPad, unsigned char ucAction) { + if (iPad != 0) return false; + if (ucAction == 255) { + for (int i = 0; i < s_watchedKeyCount; ++i) + if (s_keysCurrent[s_watchedKeys[i]]) return true; + return s_mouseLeftCurrent || s_mouseRightCurrent; + } switch (ucAction) { - // ---- Menu navigation ---- - case ACTION_MENU_UP: return KDown(GLFW_KEY_UP) || KDown(GLFW_KEY_W); - case ACTION_MENU_DOWN: return KDown(GLFW_KEY_DOWN) || KDown(GLFW_KEY_S); - case ACTION_MENU_LEFT: return KDown(GLFW_KEY_LEFT) || KDown(GLFW_KEY_A); - case ACTION_MENU_RIGHT: return KDown(GLFW_KEY_RIGHT) || KDown(GLFW_KEY_D); - - case ACTION_MENU_A: - case ACTION_MENU_OK: - return KDown(GLFW_KEY_ENTER) || KDown(GLFW_KEY_SPACE); - - case ACTION_MENU_B: - case ACTION_MENU_CANCEL: - return KDown(GLFW_KEY_ESCAPE); - - case ACTION_MENU_X: return KDown(GLFW_KEY_F); - case ACTION_MENU_Y: return KDown(GLFW_KEY_E); - - case ACTION_MENU_PAGEUP: return KDown(GLFW_KEY_PAGE_UP) || KDown(GLFW_KEY_LEFT_SHIFT); - case ACTION_MENU_PAGEDOWN: return KDown(GLFW_KEY_PAGE_DOWN) || KDown(GLFW_KEY_RIGHT_SHIFT); - case ACTION_MENU_RIGHT_SCROLL: return KDown(GLFW_KEY_RIGHT_SHIFT) || WheelUp(); - case ACTION_MENU_LEFT_SCROLL: return KDown(GLFW_KEY_LEFT_SHIFT) || WheelDown(); - - case ACTION_MENU_STICK_PRESS: return false; - case ACTION_MENU_OTHER_STICK_PRESS: return false; - case ACTION_MENU_OTHER_STICK_UP: return KDown(GLFW_KEY_UP); - case ACTION_MENU_OTHER_STICK_DOWN: return KDown(GLFW_KEY_DOWN); - case ACTION_MENU_OTHER_STICK_LEFT: return KDown(GLFW_KEY_LEFT); - case ACTION_MENU_OTHER_STICK_RIGHT: return KDown(GLFW_KEY_RIGHT); - - case ACTION_MENU_PAUSEMENU: return KDown(GLFW_KEY_ESCAPE); - - // ---- Minecraft in-game ---- - case MINECRAFT_ACTION_JUMP: return KDown(GLFW_KEY_SPACE); - case MINECRAFT_ACTION_FORWARD: return KDown(GLFW_KEY_W); - case MINECRAFT_ACTION_BACKWARD: return KDown(GLFW_KEY_S); - case MINECRAFT_ACTION_LEFT: return KDown(GLFW_KEY_A); - case MINECRAFT_ACTION_RIGHT: return KDown(GLFW_KEY_D); - - // Look axes are handled by analog stick RX/RY (mouse) - case MINECRAFT_ACTION_LOOK_LEFT: return false; - case MINECRAFT_ACTION_LOOK_RIGHT: return false; - case MINECRAFT_ACTION_LOOK_UP: return false; - case MINECRAFT_ACTION_LOOK_DOWN: return false; - - case MINECRAFT_ACTION_USE: return MouseRDown(); - case MINECRAFT_ACTION_ACTION: return MouseLDown(); - case MINECRAFT_ACTION_LEFT_SCROLL: return WheelDown(); - case MINECRAFT_ACTION_RIGHT_SCROLL: return WheelUp(); - - case MINECRAFT_ACTION_INVENTORY: return KDown(GLFW_KEY_E); - case MINECRAFT_ACTION_PAUSEMENU: return KDown(GLFW_KEY_ESCAPE); - case MINECRAFT_ACTION_DROP: return KDown(GLFW_KEY_Q); - case MINECRAFT_ACTION_SNEAK_TOGGLE: return KDown(GLFW_KEY_LEFT_SHIFT); - case MINECRAFT_ACTION_CRAFTING: return KDown(GLFW_KEY_F); - case MINECRAFT_ACTION_RENDER_THIRD_PERSON: return KDown(GLFW_KEY_F5); - case MINECRAFT_ACTION_GAME_INFO: return KDown(GLFW_KEY_F3); - - case MINECRAFT_ACTION_DPAD_LEFT: return KDown(GLFW_KEY_LEFT); - case MINECRAFT_ACTION_DPAD_RIGHT: return KDown(GLFW_KEY_RIGHT); - case MINECRAFT_ACTION_DPAD_UP: return KDown(GLFW_KEY_UP); - case MINECRAFT_ACTION_DPAD_DOWN: return KDown(GLFW_KEY_DOWN); - - default: return false; + case MINECRAFT_ACTION_ACTION: return MouseLDown() || KDown(SDL_SCANCODE_RETURN); + case MINECRAFT_ACTION_USE: return MouseRDown() || KDown(SDL_SCANCODE_F); + case MINECRAFT_ACTION_SNEAK_TOGGLE: return KDown(SDL_SCANCODE_LSHIFT) || KDown(SDL_SCANCODE_RSHIFT) || KDown(SDL_SCANCODE_LCTRL) || KDown(SDL_SCANCODE_RCTRL); + case MINECRAFT_ACTION_LEFT_SCROLL: + case ACTION_MENU_LEFT_SCROLL: return ScrollSnap() > 0; + case MINECRAFT_ACTION_RIGHT_SCROLL: + case ACTION_MENU_RIGHT_SCROLL: return ScrollSnap() < 0; + ACTION_CASES(KDown) } } - -// --------------------------------------------------------------------------- -// ButtonPressed – rising edge (press event this frame) -// --------------------------------------------------------------------------- -bool C_4JInput::ButtonPressed(int /*iPad*/, unsigned char ucAction) { +// The part that handles completing the action of pressing a button. +bool C_4JInput::ButtonPressed(int iPad, unsigned char ucAction) { + if (iPad != 0 || ucAction == 255) return false; switch (ucAction) { - case ACTION_MENU_UP: return KPressed(GLFW_KEY_UP) || KPressed(GLFW_KEY_W); - case ACTION_MENU_DOWN: return KPressed(GLFW_KEY_DOWN) || KPressed(GLFW_KEY_S); - case ACTION_MENU_LEFT: return KPressed(GLFW_KEY_LEFT) || KPressed(GLFW_KEY_A); - case ACTION_MENU_RIGHT: return KPressed(GLFW_KEY_RIGHT) || KPressed(GLFW_KEY_D); - - case ACTION_MENU_A: - case ACTION_MENU_OK: - return KPressed(GLFW_KEY_ENTER) || KPressed(GLFW_KEY_SPACE); - - case ACTION_MENU_B: - case ACTION_MENU_CANCEL: - return KPressed(GLFW_KEY_ESCAPE); - - case ACTION_MENU_X: return KPressed(GLFW_KEY_F); - case ACTION_MENU_Y: return KPressed(GLFW_KEY_E); - - case ACTION_MENU_PAGEUP: return KPressed(GLFW_KEY_PAGE_UP) || KPressed(GLFW_KEY_LEFT_SHIFT); - case ACTION_MENU_PAGEDOWN: return KPressed(GLFW_KEY_PAGE_DOWN) || KPressed(GLFW_KEY_RIGHT_SHIFT); - case ACTION_MENU_RIGHT_SCROLL: return KPressed(GLFW_KEY_RIGHT_SHIFT) || WheelUpEdge(); - case ACTION_MENU_LEFT_SCROLL: return KPressed(GLFW_KEY_LEFT_SHIFT) || WheelDownEdge(); - - case ACTION_MENU_STICK_PRESS: return false; - case ACTION_MENU_OTHER_STICK_PRESS: return false; - case ACTION_MENU_OTHER_STICK_UP: return KPressed(GLFW_KEY_UP); - case ACTION_MENU_OTHER_STICK_DOWN: return KPressed(GLFW_KEY_DOWN); - case ACTION_MENU_OTHER_STICK_LEFT: return KPressed(GLFW_KEY_LEFT); - case ACTION_MENU_OTHER_STICK_RIGHT: return KPressed(GLFW_KEY_RIGHT); - case ACTION_MENU_PAUSEMENU: return KPressed(GLFW_KEY_ESCAPE); - - case MINECRAFT_ACTION_JUMP: return KPressed(GLFW_KEY_SPACE); - case MINECRAFT_ACTION_FORWARD: return KPressed(GLFW_KEY_W); - case MINECRAFT_ACTION_BACKWARD: return KPressed(GLFW_KEY_S); - case MINECRAFT_ACTION_LEFT: return KPressed(GLFW_KEY_A); - case MINECRAFT_ACTION_RIGHT: return KPressed(GLFW_KEY_D); - - case MINECRAFT_ACTION_LOOK_LEFT: - case MINECRAFT_ACTION_LOOK_RIGHT: - case MINECRAFT_ACTION_LOOK_UP: - case MINECRAFT_ACTION_LOOK_DOWN: - return false; - - case MINECRAFT_ACTION_USE: return MouseRPressed(); - case MINECRAFT_ACTION_ACTION: return MouseLPressed(); - case MINECRAFT_ACTION_LEFT_SCROLL: return WheelDownEdge(); - case MINECRAFT_ACTION_RIGHT_SCROLL: return WheelUpEdge(); - - case MINECRAFT_ACTION_INVENTORY: return KPressed(GLFW_KEY_E); - case MINECRAFT_ACTION_PAUSEMENU: return KPressed(GLFW_KEY_ESCAPE); - case MINECRAFT_ACTION_DROP: return KPressed(GLFW_KEY_Q); - case MINECRAFT_ACTION_SNEAK_TOGGLE: return KPressed(GLFW_KEY_LEFT_SHIFT); - case MINECRAFT_ACTION_CRAFTING: return KPressed(GLFW_KEY_F); - case MINECRAFT_ACTION_RENDER_THIRD_PERSON: return KPressed(GLFW_KEY_F5); - case MINECRAFT_ACTION_GAME_INFO: return KPressed(GLFW_KEY_F3); - - case MINECRAFT_ACTION_DPAD_LEFT: return KPressed(GLFW_KEY_LEFT); - case MINECRAFT_ACTION_DPAD_RIGHT: return KPressed(GLFW_KEY_RIGHT); - case MINECRAFT_ACTION_DPAD_UP: return KPressed(GLFW_KEY_UP); - case MINECRAFT_ACTION_DPAD_DOWN: return KPressed(GLFW_KEY_DOWN); - - default: return false; + case MINECRAFT_ACTION_ACTION: return MouseLPressed() || KPressed(SDL_SCANCODE_RETURN); + case MINECRAFT_ACTION_USE: return MouseRPressed() || KPressed(SDL_SCANCODE_F); + case MINECRAFT_ACTION_SNEAK_TOGGLE: return KPressed(SDL_SCANCODE_LSHIFT) || KPressed(SDL_SCANCODE_RSHIFT) || KPressed(SDL_SCANCODE_LCTRL) || KPressed(SDL_SCANCODE_RCTRL); + case MINECRAFT_ACTION_LEFT_SCROLL: + case ACTION_MENU_LEFT_SCROLL: return ScrollSnap() > 0; + case MINECRAFT_ACTION_RIGHT_SCROLL: + case ACTION_MENU_RIGHT_SCROLL: return ScrollSnap() < 0; + ACTION_CASES(KPressed) } } - -// --------------------------------------------------------------------------- -// ButtonReleased – falling edge (released this frame) -// --------------------------------------------------------------------------- -bool C_4JInput::ButtonReleased(int /*iPad*/, unsigned char ucAction) { +// The part that handles Releasing a button. +bool C_4JInput::ButtonReleased(int iPad, unsigned char ucAction) { + if (iPad != 0 || ucAction == 255) return false; switch (ucAction) { - case ACTION_MENU_UP: return KReleased(GLFW_KEY_UP) || KReleased(GLFW_KEY_W); - case ACTION_MENU_DOWN: return KReleased(GLFW_KEY_DOWN) || KReleased(GLFW_KEY_S); - case ACTION_MENU_LEFT: return KReleased(GLFW_KEY_LEFT) || KReleased(GLFW_KEY_A); - case ACTION_MENU_RIGHT: return KReleased(GLFW_KEY_RIGHT) || KReleased(GLFW_KEY_D); - - case ACTION_MENU_A: - case ACTION_MENU_OK: - return KReleased(GLFW_KEY_ENTER) || KReleased(GLFW_KEY_SPACE); - - case ACTION_MENU_B: - case ACTION_MENU_CANCEL: - return KReleased(GLFW_KEY_ESCAPE); - - case ACTION_MENU_X: return KReleased(GLFW_KEY_F); - case ACTION_MENU_Y: return KReleased(GLFW_KEY_E); - - case ACTION_MENU_PAGEUP: return KReleased(GLFW_KEY_PAGE_UP) || KReleased(GLFW_KEY_LEFT_SHIFT); - case ACTION_MENU_PAGEDOWN: return KReleased(GLFW_KEY_PAGE_DOWN) || KReleased(GLFW_KEY_RIGHT_SHIFT); - case ACTION_MENU_RIGHT_SCROLL: return KReleased(GLFW_KEY_RIGHT_SHIFT); - case ACTION_MENU_LEFT_SCROLL: return KReleased(GLFW_KEY_LEFT_SHIFT); - - case ACTION_MENU_STICK_PRESS: return false; - case ACTION_MENU_OTHER_STICK_PRESS: return false; - case ACTION_MENU_OTHER_STICK_UP: return KReleased(GLFW_KEY_UP); - case ACTION_MENU_OTHER_STICK_DOWN: return KReleased(GLFW_KEY_DOWN); - case ACTION_MENU_OTHER_STICK_LEFT: return KReleased(GLFW_KEY_LEFT); - case ACTION_MENU_OTHER_STICK_RIGHT: return KReleased(GLFW_KEY_RIGHT); - case ACTION_MENU_PAUSEMENU: return KReleased(GLFW_KEY_ESCAPE); - - case MINECRAFT_ACTION_JUMP: return KReleased(GLFW_KEY_SPACE); - case MINECRAFT_ACTION_FORWARD: return KReleased(GLFW_KEY_W); - case MINECRAFT_ACTION_BACKWARD: return KReleased(GLFW_KEY_S); - case MINECRAFT_ACTION_LEFT: return KReleased(GLFW_KEY_A); - case MINECRAFT_ACTION_RIGHT: return KReleased(GLFW_KEY_D); - - case MINECRAFT_ACTION_LOOK_LEFT: - case MINECRAFT_ACTION_LOOK_RIGHT: - case MINECRAFT_ACTION_LOOK_UP: - case MINECRAFT_ACTION_LOOK_DOWN: - return false; - - case MINECRAFT_ACTION_USE: return MouseRReleased(); - case MINECRAFT_ACTION_ACTION: return MouseLReleased(); - case MINECRAFT_ACTION_LEFT_SCROLL: return false; // scroll wheel has no "release" - case MINECRAFT_ACTION_RIGHT_SCROLL: return false; - - case MINECRAFT_ACTION_INVENTORY: return KReleased(GLFW_KEY_E); - case MINECRAFT_ACTION_PAUSEMENU: return KReleased(GLFW_KEY_ESCAPE); - case MINECRAFT_ACTION_DROP: return KReleased(GLFW_KEY_Q); - case MINECRAFT_ACTION_SNEAK_TOGGLE: return KReleased(GLFW_KEY_LEFT_SHIFT); - case MINECRAFT_ACTION_CRAFTING: return KReleased(GLFW_KEY_F); - case MINECRAFT_ACTION_RENDER_THIRD_PERSON: return KReleased(GLFW_KEY_F5); - case MINECRAFT_ACTION_GAME_INFO: return KReleased(GLFW_KEY_F3); - - case MINECRAFT_ACTION_DPAD_LEFT: return KReleased(GLFW_KEY_LEFT); - case MINECRAFT_ACTION_DPAD_RIGHT: return KReleased(GLFW_KEY_RIGHT); - case MINECRAFT_ACTION_DPAD_UP: return KReleased(GLFW_KEY_UP); - case MINECRAFT_ACTION_DPAD_DOWN: return KReleased(GLFW_KEY_DOWN); - - default: return false; + case MINECRAFT_ACTION_ACTION: return MouseLReleased() || KReleased(SDL_SCANCODE_RETURN); + case MINECRAFT_ACTION_USE: return MouseRReleased() || KReleased(SDL_SCANCODE_F); + case MINECRAFT_ACTION_SNEAK_TOGGLE: return KReleased(SDL_SCANCODE_LSHIFT) || KReleased(SDL_SCANCODE_RSHIFT) || KReleased(SDL_SCANCODE_LCTRL) || KReleased(SDL_SCANCODE_RCTRL); + case MINECRAFT_ACTION_LEFT_SCROLL: + case ACTION_MENU_LEFT_SCROLL: + case MINECRAFT_ACTION_RIGHT_SCROLL: + case ACTION_MENU_RIGHT_SCROLL: return false; + ACTION_CASES(KReleased) } } -// --------------------------------------------------------------------------- -// GetValue – returns 1 if action held, 0 otherwise -// --------------------------------------------------------------------------- -unsigned int C_4JInput::GetValue(int iPad, unsigned char ucAction, bool /*bRepeat*/) { +unsigned int C_4JInput::GetValue(int iPad, unsigned char ucAction, bool) { + if (iPad != 0) return 0; + if (ucAction == MINECRAFT_ACTION_LEFT_SCROLL) { + if (s_scrollTicksForGetValue > 0) { + unsigned int v = (unsigned int)s_scrollTicksForGetValue; + s_scrollTicksForGetValue = 0; + return v; + } + return 0u; + } + if (ucAction == MINECRAFT_ACTION_RIGHT_SCROLL) { + if (s_scrollTicksForGetValue < 0) { + unsigned int v = (unsigned int)(-s_scrollTicksForGetValue); + s_scrollTicksForGetValue = 0; + return v; + } + return 0u; + } return ButtonDown(iPad, ucAction) ? 1u : 0u; } - -// --------------------------------------------------------------------------- -// Analog sticks -// -// Left stick = WASD keyboard (±1.0) -// Right stick = mouse delta with sqrt-compression to linearise the quadratic -// look-speed formula used by the console game code: -// turnSpeed = rx * |rx| * 50 * sensitivity -// Passing sqrt(|raw|)*sign(raw) makes turn speed proportional -// to raw pixel delta, giving a natural mouse feel. -// --------------------------------------------------------------------------- - -float C_4JInput::GetJoypadStick_LX(int /*iPad*/, bool /*bCheckMenuDisplay*/) { - // Return 0 while cursor is still in menu mode so Input::tick()'s - // lReset guard sees a zero-stick frame during the menu->game transition. - // Once s_mouseLocked becomes true (cursor captured for gameplay), return - // the real WASD values. - if (!s_mouseLocked) return 0.0f; - float v = 0.0f; - if (KDown(GLFW_KEY_A)) v -= 1.0f; - if (KDown(GLFW_KEY_D)) v += 1.0f; - return v; +// Left stick movement, the one that moves the player around or selects menu options. (Soon be tested.) +float C_4JInput::GetJoypadStick_LX(int, bool) { + return (KDown(SDL_SCANCODE_D) ? 1.f : 0.f) - (KDown(SDL_SCANCODE_A) ? 1.f : 0.f); +} +float C_4JInput::GetJoypadStick_LY(int, bool) { + return (KDown(SDL_SCANCODE_W) ? 1.f : 0.f) - (KDown(SDL_SCANCODE_S) ? 1.f : 0.f); +} +// We use mouse movement and convert it into a Right Stick output using logarithmic scaling +// This is the most important mouse part. Yet it's so small. +static float MouseAxis(float raw) { + if (fabsf(raw) < 0.0001f) return 0.f; // from 4j previous code + return (raw >= 0.f ? 1.f : -1.f) * sqrtf(fabsf(raw)); +} +// We apply the Stick movement on the R(Right) X(2D Position) +float C_4JInput::GetJoypadStick_RX(int, bool) { + if (!SDL_GetRelativeMouseMode()) return 0.f; + TakeSnapIfNeeded(); + return MouseAxis(s_snapRelX * MOUSE_SCALE); +} +// Bis. but with Y(2D Position) +float C_4JInput::GetJoypadStick_RY(int, bool) { + if (!SDL_GetRelativeMouseMode()) return 0.f; + TakeSnapIfNeeded(); + return MouseAxis(-s_snapRelY * MOUSE_SCALE); } -float C_4JInput::GetJoypadStick_LY(int /*iPad*/, bool /*bCheckMenuDisplay*/) { - if (!s_mouseLocked) return 0.0f; - float v = 0.0f; - if (KDown(GLFW_KEY_W)) v += 1.0f; // W = forward = negative Y on consoles - if (KDown(GLFW_KEY_S)) v -= 1.0f; - return v; -} - -float C_4JInput::GetJoypadStick_RX(int /*iPad*/, bool /*bCheckMenuDisplay*/) { - if (!s_mouseLocked) return 0.0f; - float raw = s_frameRelX * MOUSE_SCALE; - float absRaw = fabsf(raw); - if (absRaw > 1.0f) absRaw = 1.0f; - if (absRaw < 0.0001f) return 0.0f; - return (raw >= 0.0f ? 1.0f : -1.0f) * sqrtf(absRaw); -} - -float C_4JInput::GetJoypadStick_RY(int /*iPad*/, bool /*bCheckMenuDisplay*/) { - if (!s_mouseLocked) return 0.0f; - float raw = -s_frameRelY * MOUSE_SCALE; - float absRaw = fabsf(raw); - if (absRaw > 1.0f) absRaw = 1.0f; - if (absRaw < 0.0001f) return 0.0f; - return (raw >= 0.0f ? 1.0f : -1.0f) * sqrtf(absRaw); -} - -// Left trigger = right mouse button (use/place) -// Right trigger = left mouse button (attack/destroy) -unsigned char C_4JInput::GetJoypadLTrigger(int /*iPad*/, bool /*bCheckMenuDisplay*/) { - return s_mouseRightCurrent ? 255 : 0; -} -unsigned char C_4JInput::GetJoypadRTrigger(int /*iPad*/, bool /*bCheckMenuDisplay*/) { - return s_mouseLeftCurrent ? 255 : 0; -} - -// --------------------------------------------------------------------------- -// Joypad map / sensitivity stubs (not meaningful for keyboard+mouse) -// --------------------------------------------------------------------------- -void C_4JInput::SetDeadzoneAndMovementRange(unsigned int /*uiDeadzone*/, unsigned int /*uiMovementRangeMax*/) {} -void C_4JInput::SetGameJoypadMaps(unsigned char /*ucMap*/, unsigned char /*ucAction*/, unsigned int /*uiActionVal*/) {} -unsigned int C_4JInput::GetGameJoypadMaps(unsigned char /*ucMap*/, unsigned char /*ucAction*/) { return 0; } -void C_4JInput::SetJoypadMapVal(int /*iPad*/, unsigned char /*ucMap*/) {} -unsigned char C_4JInput::GetJoypadMapVal(int /*iPad*/) { return 0; } -void C_4JInput::SetJoypadSensitivity(int /*iPad*/, float /*fSensitivity*/) {} -void C_4JInput::SetJoypadStickAxisMap(int /*iPad*/, unsigned int /*uiFrom*/, unsigned int /*uiTo*/) {} -void C_4JInput::SetJoypadStickTriggerMap(int /*iPad*/, unsigned int /*uiFrom*/, unsigned int /*uiTo*/) {} -void C_4JInput::SetKeyRepeatRate(float /*fRepeatDelaySecs*/, float /*fRepeatRateSecs*/) {} -void C_4JInput::SetDebugSequence(const char * /*chSequenceA*/, int(*/*Func*/)(LPVOID), LPVOID /*lpParam*/) {} -FLOAT C_4JInput::GetIdleSeconds(int /*iPad*/) { return 0.0f; } -bool C_4JInput::IsPadConnected(int iPad) { return iPad == 0; } // slot 0 = keyboard+mouse - +unsigned char C_4JInput::GetJoypadLTrigger(int, bool) { return s_mouseRightCurrent ? 255 : 0; } +unsigned char C_4JInput::GetJoypadRTrigger(int, bool) { return s_mouseLeftCurrent ? 255 : 0; } +// We detect if a Menu is visible on the player's screen to the mouse being stuck. void C_4JInput::SetMenuDisplayed(int iPad, bool bVal) { if (iPad >= 0 && iPad < 4) s_menuDisplayed[iPad] = bVal; + if (!s_sdlInitialized || bVal == s_prevMenuDisplayed) return; + SDL_SetRelativeMouseMode(bVal ? SDL_FALSE : SDL_TRUE); + s_prevMenuDisplayed = bVal; } -// --------------------------------------------------------------------------- -// Keyboard (text entry) / string verification stubs -// --------------------------------------------------------------------------- -EKeyboardResult C_4JInput::RequestKeyboard(LPCWSTR /*Title*/, LPCWSTR /*Text*/, DWORD /*dwPad*/, - UINT /*uiMaxChars*/, - int(*/*Func*/)(LPVOID, const bool), LPVOID /*lpParam*/, - C_4JInput::EKeyboardMode /*eMode*/) { - return EKeyboard_Cancelled; -} -void C_4JInput::GetText(uint16_t *UTF16String) { if (UTF16String) UTF16String[0] = 0; } -bool C_4JInput::VerifyStrings(WCHAR ** /*pwStringA*/, int /*iStringC*/, - int(*/*Func*/)(LPVOID, STRING_VERIFY_RESPONSE *), LPVOID /*lpParam*/) { return true; } -void C_4JInput::CancelQueuedVerifyStrings(int(*/*Func*/)(LPVOID, STRING_VERIFY_RESPONSE *), LPVOID /*lpParam*/) {} -void C_4JInput::CancelAllVerifyInProgress(void) {} - -float C_4JInput::GetMouseX() { - return (float)s_lastCursorX; +int C_4JInput::GetScrollDelta() { + int v = s_scrollTicksForButtonPressed; + s_scrollTicksForButtonPressed = 0; + return v; } -float C_4JInput::GetMouseY() { - return (float)s_lastCursorY; -} \ No newline at end of file +void C_4JInput::SetDeadzoneAndMovementRange(unsigned int, unsigned int){} +void C_4JInput::SetGameJoypadMaps(unsigned char, unsigned char, unsigned int){} +unsigned int C_4JInput::GetGameJoypadMaps(unsigned char, unsigned char){ return 0; } +void C_4JInput::SetJoypadMapVal(int, unsigned char){} +unsigned char C_4JInput::GetJoypadMapVal(int){ return 0; } +void C_4JInput::SetJoypadSensitivity(int, float){} +void C_4JInput::SetJoypadStickAxisMap(int, unsigned int, unsigned int){} +void C_4JInput::SetJoypadStickTriggerMap(int, unsigned int, unsigned int){} +void C_4JInput::SetKeyRepeatRate(float, float){} +void C_4JInput::SetDebugSequence(const char*, int(*)(LPVOID), LPVOID){} +FLOAT C_4JInput::GetIdleSeconds(int){ return 0.f; } +bool C_4JInput::IsPadConnected(int iPad){ return iPad == 0; } + +// Silly check, we check if we have a keyboard. +EKeyboardResult C_4JInput::RequestKeyboard(LPCWSTR, LPCWSTR, DWORD, UINT, + int(*)(LPVOID, const bool), LPVOID, C_4JInput::EKeyboardMode) +{ return EKeyboard_Cancelled; } + +void C_4JInput::GetText(uint16_t *s){ if (s) s[0] = 0; } +bool C_4JInput::VerifyStrings(WCHAR**, int, int(*)(LPVOID, STRING_VERIFY_RESPONSE*), LPVOID){ return true; } +void C_4JInput::CancelQueuedVerifyStrings(int(*)(LPVOID, STRING_VERIFY_RESPONSE*), LPVOID){} +void C_4JInput::CancelAllVerifyInProgress(){} \ No newline at end of file diff --git a/4J.Input/4J_Input.h b/4J.Input/4J_Input.h index b0120927b..6fbe0006c 100644 --- a/4J.Input/4J_Input.h +++ b/4J.Input/4J_Input.h @@ -106,6 +106,8 @@ public: unsigned char GetJoypadRTrigger(int iPad, bool bCheckMenuDisplay=true); void SetMenuDisplayed(int iPad, bool bVal); + int GetHotbarSlotPressed(int iPad); + int GetScrollDelta(); // EKeyboardResult RequestKeyboard(UINT uiTitle, UINT uiText, UINT uiDesc, DWORD dwPad, WCHAR *pwchResult, UINT uiResultSize,int( *Func)(LPVOID,const bool),LPVOID lpParam,EKeyboardMode eMode,C4JStringTable *pStringTable=NULL); // EKeyboardResult RequestKeyboard(UINT uiTitle, LPCWSTR pwchDefault, UINT uiDesc, DWORD dwPad, WCHAR *pwchResult, UINT uiResultSize,int( *Func)(LPVOID,const bool),LPVOID lpParam, EKeyboardMode eMode,C4JStringTable *pStringTable=NULL); diff --git a/4J.Input/meson.build b/4J.Input/meson.build index abad05d4e..3a2cb9ffa 100644 --- a/4J.Input/meson.build +++ b/4J.Input/meson.build @@ -15,7 +15,11 @@ lib_input = static_library('4J_Input', ], ) +# We import SDL2 but not SDL3.. which is a bit sad, +sdl_dep = dependency('sdl2', required : false) + input_dep = declare_dependency( link_with : lib_input, + dependencies : [sdl_dep], include_directories : include_directories('.'), ) diff --git a/4J.Render/4J_Render.cpp b/4J.Render/4J_Render.cpp index 351532d4f..c16920e82 100644 --- a/4J.Render/4J_Render.cpp +++ b/4J.Render/4J_Render.cpp @@ -1,14 +1,11 @@ - -// TODO: ADD BETTER COMMENTS. #include "4J_Render.h" #include #include // getenv -#define GL_GLEXT_PROTOTYPES #include #include #include -#include +#include #include #include #include @@ -18,38 +15,53 @@ C4JRender RenderManager; -static GLFWwindow *s_window = nullptr; +// Hello SDL! +static SDL_Window *s_window = nullptr; +static SDL_GLContext s_glContext = nullptr; +static bool s_shouldClose = false; static int s_textureLevels = 1; -static int s_windowWidth = 1280; // updated to actual framebuffer size each frame -static int s_windowHeight = 720; -static int s_reqWidth = 0; // 0 = auto-detect from primary monitor +static int s_windowWidth = 0; +static int s_windowHeight = 0; + +// We set Window size with the monitor's res, so that I can get rid of ugly values. +static void SetInitialWindowSize() +{ + int w = 0, h = 0; + if (SDL_Init(SDL_INIT_VIDEO) == 0) { + SDL_DisplayMode mode; + if (SDL_GetCurrentDisplayMode(0, &mode) == 0) { + w = (int)(mode.w * 0.4f); + h = (int)(mode.h * 0.4f); + } + } + if (w > 0 && h > 0) { s_windowWidth = w; s_windowHeight = h; } + else { s_windowWidth = 1280; s_windowHeight = 720; } +} +// (can't believe i had to rewrite this, i literally did it TODAY.) +static int s_reqWidth = 0; static int s_reqHeight = 0; +// When we'll have a settings system in order, we'll set bool to that value, right now it's hardcoded. static bool s_fullscreen = false; -// Thread-local storage for per-thread shared GL contexts. -// The main thread uses s_window directly; worker threads get invisible -// windows that share objects (textures, display lists) with s_window. static pthread_key_t s_glCtxKey; static pthread_once_t s_glCtxKeyOnce = PTHREAD_ONCE_INIT; static void makeGLCtxKey() { pthread_key_create(&s_glCtxKey, nullptr); } - -// Pre-created pool of shared contexts for worker threads - -// AMD drivers (especially on Linux/Mesa) can be very sensitive to the number of shared contexts -// and concurrent display list compilation. 8 was original, 4 was an attempt to fix it. -// 6 covers the 5 concurrent worker threads (update + 3x rebuild + main thread). -static const int MAX_SHARED_CONTEXTS = 6; -static GLFWwindow *s_sharedContexts[MAX_SHARED_CONTEXTS] = {}; +// Do not touch exactly this number | +static const int MAX_SHARED_CONTEXTS = 6; // <- this one, do not touch +static SDL_Window *s_sharedContextWindows[MAX_SHARED_CONTEXTS] = {}; +static SDL_GLContext s_sharedContexts[MAX_SHARED_CONTEXTS] = {}; static int s_sharedContextCount = 0; static int s_nextSharedContext = 0; static pthread_mutex_t s_sharedCtxMutex = PTHREAD_MUTEX_INITIALIZER; +// Tells thread to do Direct GL calls, just don't touch. +static pthread_mutex_t s_glCallMutex = PTHREAD_MUTEX_INITIALIZER; // Track which thread is the main (rendering) thread static pthread_t s_mainThread; static bool s_mainThreadSet = false; // viewport go brr -static void onFramebufferResize(GLFWwindow * /*win*/, int w, int h) +static void onFramebufferResize(int w, int h) { if (w < 1) w = 1; if (h < 1) h = 1; @@ -58,48 +70,62 @@ static void onFramebufferResize(GLFWwindow * /*win*/, int w, int h) ::glViewport(0, 0, w, h); } +// Initialize OpenGL & The SDL window. void C4JRender::Initialise() { - if (!glfwInit()) { - fprintf(stderr, "[4J_Render] Failed to initialise GLFW\n"); + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "[4J_Render] Failed to initialise SDL: %s\n", SDL_GetError()); return; } - GLFWmonitor *primaryMonitor = glfwGetPrimaryMonitor(); - const GLFWvidmode *mode = primaryMonitor ? glfwGetVideoMode(primaryMonitor) : nullptr; + SDL_DisplayMode mode; + int haveMode = (SDL_GetCurrentDisplayMode(0, &mode) == 0); if (s_reqWidth > 0 && s_reqHeight > 0) { s_windowWidth = s_reqWidth; s_windowHeight = s_reqHeight; - } else if (mode) { - s_windowWidth = mode->width; - s_windowHeight = mode->height; + } else if (haveMode) { + s_windowWidth = mode.w; + s_windowHeight = mode.h; } fprintf(stderr, "[4J_Render] Window %dx%d fullscreen=%s\n", s_windowWidth, s_windowHeight, s_fullscreen ? "yes" : "no"); fflush(stderr); - // opengl 2.1!!! - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); - glfwWindowHint(GLFW_DEPTH_BITS, 24); - glfwWindowHint(GLFW_STENCIL_BITS, 8); + // Setting the sdl_gl ver. Change in future incase we want to use shaders + // Yes i'm still using fixed functions, get mad at me + // I don't care. + // Im not gonna be rewriting the whole renderer.. AGAIN. ;w; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - GLFWmonitor *fsMonitor = s_fullscreen ? primaryMonitor : nullptr; - s_window = glfwCreateWindow(s_windowWidth, s_windowHeight, - "Minecraft Console Edition", fsMonitor, nullptr); + Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + if (s_fullscreen) winFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + s_window = SDL_CreateWindow("Minecraft Console Edition", + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + s_windowWidth, s_windowHeight, + winFlags); if (!s_window) { - fprintf(stderr, "[4J_Render] Failed to create GLFW window\n"); - glfwTerminate(); + fprintf(stderr, "[4J_Render] Failed to create SDL window: %s\n", SDL_GetError()); + SDL_Quit(); return; } - glfwMakeContextCurrent(s_window); - glfwSwapInterval(1); // vsync - - // Keep viewport in sync with OS-driven window resizes. - glfwSetFramebufferSizeCallback(s_window, onFramebufferResize); + s_glContext = SDL_GL_CreateContext(s_window); + if (!s_glContext) { + fprintf(stderr, "[4J_Render] Failed to create GL context: %s\n", SDL_GetError()); + SDL_DestroyWindow(s_window); + s_window = nullptr; + SDL_Quit(); + return; + } + SDL_GL_SetSwapInterval(0); // V-Sync Off Please. - // init opengl + int fw, fh; SDL_GetWindowSize(s_window, &fw, &fh); onFramebufferResize(fw, fh); + + // We initialize the OpenGL states. Touching those values makes some funny artifacts appear. ::glEnable(GL_TEXTURE_2D); ::glEnable(GL_DEPTH_TEST); ::glDepthFunc(GL_LEQUAL); @@ -116,7 +142,7 @@ void C4JRender::Initialise() ::glViewport(0, 0, s_windowWidth, s_windowHeight); ::glEnable(GL_COLOR_MATERIAL); ::glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - + // Print the renderer's version incase we change it in the future. printf("[4J_Render] OpenGL %s | %s\n", (const char*)::glGetString(GL_VERSION), (const char*)::glGetString(GL_RENDERER)); @@ -126,25 +152,34 @@ void C4JRender::Initialise() pthread_once(&s_glCtxKeyOnce, makeGLCtxKey); s_mainThread = pthread_self(); s_mainThreadSet = true; - pthread_setspecific(s_glCtxKey, s_window); + pthread_setspecific(s_glCtxKey, (void*)s_window); // Pre-create shared GL contexts for worker threads (chunk builders etc.) - // Must be done on the main thread because GLFW requires it. // Ensure they are invisible so they don't interfere with the window manager. - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + + // Pre-create shared GL contexts for worker threads (chunk builders & other shit etc.) + // SDL_GL_SHARE_WITH_CURRENT_CONTEXT my saviour. for (int i = 0; i < MAX_SHARED_CONTEXTS; i++) { - s_sharedContexts[i] = glfwCreateWindow(1, 1, "", nullptr, s_window); - if (s_sharedContexts[i]) { - s_sharedContextCount++; - } else { - fprintf(stderr, "[4J_Render] WARN: only created %d/%d shared contexts\n", i, MAX_SHARED_CONTEXTS); + SDL_Window *w = SDL_CreateWindow("", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + 1, 1, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + if (!w) break; + // Ensure sharing + // I've been stuck on this for a while. Im stupid.. + SDL_GL_MakeCurrent(s_window, s_glContext); + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); + SDL_GLContext ctx = SDL_GL_CreateContext(w); + if (!ctx) { + SDL_DestroyWindow(w); break; } + s_sharedContextWindows[s_sharedContextCount] = w; + s_sharedContexts[s_sharedContextCount] = ctx; + s_sharedContextCount++; } - glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Ensure main thread still has the context - glfwMakeContextCurrent(s_window); + SDL_GL_MakeCurrent(s_window, s_glContext); fprintf(stderr, "[4J_Render] Created %d shared GL contexts for worker threads\n", s_sharedContextCount); fflush(stderr); } @@ -156,21 +191,25 @@ void C4JRender::InitialiseContext() // Main thread reclaiming context (e.g. after startup thread finishes) if (s_mainThreadSet && pthread_equal(pthread_self(), s_mainThread)) { - glfwMakeContextCurrent(s_window); - pthread_setspecific(s_glCtxKey, s_window); + SDL_GL_MakeCurrent(s_window, s_glContext); + pthread_setspecific(s_glCtxKey, (void*)s_window); return; } - // Worker thread: check if it already has a shared context - GLFWwindow *ctx = (GLFWwindow*)pthread_getspecific(s_glCtxKey); - if (ctx) { - glfwMakeContextCurrent(ctx); + // Worker thread checks if there's a context, we don't want to have multiple contexts. + void *ctxPtr = pthread_getspecific(s_glCtxKey); + if (ctxPtr) { + // ctxPtr -> SDL_GLContext pointer + SDL_GLContext ctx = (SDL_GLContext)ctxPtr; + int idx = -1; + for (int i = 0; i < s_sharedContextCount; ++i) if (s_sharedContexts[i] == ctx) { idx = i; break; } + if (idx >= 0 && s_sharedContextWindows[idx]) SDL_GL_MakeCurrent(s_sharedContextWindows[idx], ctx); return; } // Grab a pre-created shared context from the pool pthread_mutex_lock(&s_sharedCtxMutex); - GLFWwindow *shared = nullptr; + SDL_GLContext shared = nullptr; if (s_nextSharedContext < s_sharedContextCount) { shared = s_sharedContexts[s_nextSharedContext++]; } @@ -181,7 +220,10 @@ void C4JRender::InitialiseContext() fflush(stderr); return; } - glfwMakeContextCurrent(shared); + // ewww..... look at line 201-203, we gotta make a function for that.... + int idx = -1; + for (int i = 0; i < s_sharedContextCount; ++i) if (s_sharedContexts[i] == shared) { idx = i; break; } + if (idx >= 0 && s_sharedContextWindows[idx]) SDL_GL_MakeCurrent(s_sharedContextWindows[idx], shared); // Initialize some basic state for this context to ensure consistent display list recording ::glEnable(GL_TEXTURE_2D); @@ -194,7 +236,7 @@ void C4JRender::InitialiseContext() ::glEnable(GL_COLOR_MATERIAL); ::glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - pthread_setspecific(s_glCtxKey, shared); + pthread_setspecific(s_glCtxKey, (void*)shared); fprintf(stderr, "[4J_Render] Assigned shared GL context %p to worker thread %lu\n", (void*)shared, (unsigned long)pthread_self()); fflush(stderr); } @@ -202,18 +244,28 @@ void C4JRender::InitialiseContext() void C4JRender::StartFrame() { if (!s_window) return; - glfwGetFramebufferSize(s_window, &s_windowWidth, &s_windowHeight); - if (s_windowWidth < 1) s_windowWidth = 1; - if (s_windowHeight < 1) s_windowHeight = 1; + int w,h; SDL_GetWindowSize(s_window, &w, &h); + s_windowWidth = w > 0 ? w : 1; + s_windowHeight = h > 0 ? h : 1; ::glViewport(0, 0, s_windowWidth, s_windowHeight); } void C4JRender::Present() { if (!s_window) return; + SDL_Event ev; + while (SDL_PollEvent(&ev)) { + if (ev.type == SDL_QUIT) s_shouldClose = true; + else if (ev.type == SDL_WINDOWEVENT) { + if (ev.window.event == SDL_WINDOWEVENT_CLOSE) s_shouldClose = true; + else if (ev.window.event == SDL_WINDOWEVENT_RESIZED) onFramebufferResize(ev.window.data1, ev.window.data2); + } + } + // Present the rendered frame after processing input/events to avoid input timing issues ::glFlush(); - glfwSwapBuffers(s_window); - glfwPollEvents(); + // debug log to help diagnose mouse issues + // printf("[4J_Render] Presenting frame (mouse lock=%d)\n", s_mouseLocked); fflush(stdout); + SDL_GL_SwapWindow(s_window); } void C4JRender::SetWindowSize(int w, int h) @@ -229,21 +281,38 @@ void C4JRender::SetFullscreen(bool fs) bool C4JRender::ShouldClose() { - return !s_window || glfwWindowShouldClose(s_window); + return !s_window || s_shouldClose; } void C4JRender::Shutdown() { - // Destroy the main window and terminate GLFW cleanly so that + // Destroy the main window and clean up SDL resources so that // destructors running after the game loop don't touch a dead context. if (s_window) { - glfwDestroyWindow(s_window); + if (s_glContext) { + SDL_GL_DeleteContext(s_glContext); + s_glContext = nullptr; + } + SDL_DestroyWindow(s_window); s_window = nullptr; } - glfwTerminate(); + + for (int i = 0; i < s_sharedContextCount; ++i) { + if (s_sharedContexts[i]) { + SDL_GL_DeleteContext(s_sharedContexts[i]); + s_sharedContexts[i] = 0; + } + if (s_sharedContextWindows[i]) { + SDL_DestroyWindow(s_sharedContextWindows[i]); + s_sharedContextWindows[i] = nullptr; + } + } + s_sharedContextCount = 0; + SDL_Quit(); } +// rip glfw. you won't be missed. (i hope) void C4JRender::DoScreenGrabOnNextPresent() {} void C4JRender::Clear(int flags) @@ -272,8 +341,8 @@ void C4JRender::MatrixTranslate(float x, float y, float z) { ::glTranslatef(x, y void C4JRender::MatrixRotate(float angle, float x, float y, float z) { - // can't fucking afford pi - ::glRotatef(angle * (180.0f / 3.14159265358979f), x, y, z); + // We use math from the math lib instead of hardcoding it. How Ugly. + ::glRotatef(angle * (180.0f / static_cast(M_PI)), x, y, z); } void C4JRender::MatrixScale(float x, float y, float z) { ::glScalef(x, y, z); } @@ -284,7 +353,7 @@ void C4JRender::MatrixPerspective(float fovy, float aspect, float zNear, float z } void C4JRender::MatrixOrthogonal(float left, float right, float bottom, float top, - float zNear, float zFar) + float zNear, float zFar) { ::glOrtho(left, right, bottom, top, zNear, zFar); } @@ -314,27 +383,29 @@ static GLenum mapPrimType(int pt) // Map from ePrimitiveType enum switch (pt) { - case C4JRender::PRIMITIVE_TYPE_TRIANGLE_LIST: return GL_TRIANGLES; - case C4JRender::PRIMITIVE_TYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP; - case C4JRender::PRIMITIVE_TYPE_TRIANGLE_FAN: return GL_TRIANGLE_FAN; - case C4JRender::PRIMITIVE_TYPE_QUAD_LIST: return GL_QUADS; - case C4JRender::PRIMITIVE_TYPE_LINE_LIST: return GL_LINES; - case C4JRender::PRIMITIVE_TYPE_LINE_STRIP: return GL_LINE_STRIP; - default: return GL_TRIANGLES; + case C4JRender::PRIMITIVE_TYPE_TRIANGLE_LIST: return GL_TRIANGLES; + case C4JRender::PRIMITIVE_TYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP; + case C4JRender::PRIMITIVE_TYPE_TRIANGLE_FAN: return GL_TRIANGLE_FAN; + case C4JRender::PRIMITIVE_TYPE_QUAD_LIST: return GL_QUADS; + case C4JRender::PRIMITIVE_TYPE_LINE_LIST: return GL_LINES; + case C4JRender::PRIMITIVE_TYPE_LINE_STRIP: return GL_LINE_STRIP; + default: return GL_TRIANGLES; } } -// clientside awawawa +// This is the clientside vertex processing. void C4JRender::DrawVertices(ePrimitiveType PrimitiveType, int count, void *dataIn, eVertexType vType, C4JRender::ePixelShaderType psType) { if (count <= 0 || !dataIn) return; + // trash trash trash trash + pthread_mutex_lock(&s_glCallMutex); + GLenum mode = mapPrimType((int)PrimitiveType); if (vType == VERTEX_TYPE_COMPRESSED) { - // NO NEED TO REWRITE IT ALL YAY int16_t *sdata = (int16_t *)dataIn; ::glBegin(mode); for (int i = 0; i < count; i++) { @@ -352,7 +423,7 @@ void C4JRender::DrawVertices(ePrimitiveType PrimitiveType, int count, float fu = vert[4] / 8192.0f; float fv = vert[5] / 8192.0f; - // Strip mipmap-disable flag: Tesselator adds +1.0 (= +8192) to u when mipmaps off + // Tesselator does that. Thanks 4J. if (fu >= 1.0f) fu -= 1.0f; // Unit 1 (lightmap) UVs @@ -388,8 +459,7 @@ void C4JRender::DrawVertices(ePrimitiveType PrimitiveType, int count, ::glNormal3f(nx / 127.0f, ny / 127.0f, nz / 127.0f); } - // Only override current GL color when the vertex actually carries one. - // colorInt == 0 is the Tesselator sentinel for "no colour set" + // This breaks particle colors.. i think. fixme! if (colorInt != 0) { ::glColor4ub(cr, cg, cb, ca); } @@ -397,6 +467,7 @@ void C4JRender::DrawVertices(ePrimitiveType PrimitiveType, int count, ::glTexCoord2f(fdata[3], fdata[4]); // Unit 1 (lightmap) UVs - 0xfe00fe00 is sentinel for "no Unit 1 UVs" + // Ugly hack, replace soon. if (tex2Int != 0xfe00fe00) { float u2 = (float)(short)(tex2Int & 0xFFFF) / 256.0f; float v2 = (float)(short)((tex2Int >> 16) & 0xFFFF) / 256.0f; @@ -408,6 +479,8 @@ void C4JRender::DrawVertices(ePrimitiveType PrimitiveType, int count, ::glEnd(); } ::glFlush(); + + pthread_mutex_unlock(&s_glCallMutex); } @@ -438,9 +511,9 @@ void C4JRender::CBuffStart(int index, bool /*full*/) void C4JRender::CBuffClear(int index) { - if (index > 0) { - ::glNewList(index, GL_COMPILE); - ::glEndList(); + if (index > 0) { + ::glNewList(index, GL_COMPILE); + ::glEndList(); ::glFlush(); } } @@ -508,9 +581,7 @@ void C4JRender::TextureBindVertex(int idx) void C4JRender::TextureSetTextureLevels(int levels) { - // Set GL_TEXTURE_MAX_LEVEL so OpenGL knows how many mip levels this texture has. - // Without this, the default is 1000, and any texture that doesn't upload all 1000 - // levels is considered "incomplete" and renders as white. + // base level is always 0, no mipmaps sadly. I'll add them later. ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels > 0 ? levels - 1 : 0); s_textureLevels = levels; } @@ -519,8 +590,7 @@ int C4JRender::TextureGetTextureLevels() { return s_textureLevels; } void C4JRender::TextureData(int width, int height, void *data, int level, eTextureFormat /*format*/) { - // Game produces [r,g,b,a] bytes via the non-Xbox transferFromImage/loadTexture paths. - // Use GL_RGBA so OpenGL interprets them correctly. GL_BGRA would swap R and B channels. + // TODO: Check if correct format. ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); @@ -554,7 +624,7 @@ void C4JRender::TextureDynamicUpdateEnd() {} void C4JRender::Tick() {} void C4JRender::UpdateGamma(unsigned short) {} -// This sucks, but at least better than libpng +// Converts RGBA data to the format expected by the texture loader. static HRESULT LoadFromSTB(unsigned char* data, int width, int height, D3DXIMAGE_INFO* pSrcInfo, int** ppDataOut) { int pixelCount = width * height; @@ -614,7 +684,6 @@ HRESULT C4JRender::SaveTextureDataToMemory(void *pOutput, int outputCapacity, in void C4JRender::TextureGetStats() {} void* C4JRender::TextureGetTexture(int idx) { return nullptr; } -// we handle opengl calls cuz multiplatform is painful!! void C4JRender::StateSetColour(float r, float g, float b, float a) { ::glColor4f(r, g, b, a); @@ -755,13 +824,12 @@ void C4JRender::StateSetLightAmbientColour(float red, float green, float blue) float ambient[4] = {red, green, blue, 1.0f}; float model[4] = {red, green, blue, 1.0f}; ::glLightModelfv(GL_LIGHT_MODEL_AMBIENT, model); - // Also set on light 0 as a fallback incase ::glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); } void C4JRender::StateSetLightDirection(int light, float x, float y, float z) { - float dir[4] = {x, y, z, 0.0f}; // w=0 → directional light + float dir[4] = {x, y, z, 0.0f}; // TODO: Java seems to do the reverse, gotta check. ::glLightfv(GL_LIGHT0 + light, GL_POSITION, dir); } @@ -787,11 +855,11 @@ void C4JRender::StateSetTexGenCol(int col, float x, float y, float z, float w, b { GLenum coord; switch (col) { - case 0: coord = GL_S; break; - case 1: coord = GL_T; break; - case 2: coord = GL_R; break; - case 3: coord = GL_Q; break; - default: coord = GL_S; break; + case 0: coord = GL_S; break; + case 1: coord = GL_T; break; + case 2: coord = GL_R; break; + case 3: coord = GL_Q; break; + default: coord = GL_S; break; } float plane[4] = {x, y, z, w}; GLenum planeMode = eyeSpace ? GL_EYE_PLANE : GL_OBJECT_PLANE; diff --git a/4J.Render/meson.build b/4J.Render/meson.build index 3dee4717c..21043a5e3 100644 --- a/4J.Render/meson.build +++ b/4J.Render/meson.build @@ -6,7 +6,7 @@ render_sources = files( lib_render = static_library('4J_Render', render_sources, include_directories : include_directories('.'), - dependencies : [png_dep, glfw_dep, gl_dep, thread_dep], + dependencies : [sdl2_dep, gl_dep, thread_dep], cpp_args : global_cpp_args + global_cpp_defs + [ '-include', meson.current_source_dir() / 'stdafx.h', ], diff --git a/Minecraft.Client/Input/ConsoleInputSource.h b/Minecraft.Client/Input/ConsoleInputSource.h index 7d79c0941..391d12916 100644 --- a/Minecraft.Client/Input/ConsoleInputSource.h +++ b/Minecraft.Client/Input/ConsoleInputSource.h @@ -3,6 +3,7 @@ class ConsoleInputSource { public: + virtual ~ConsoleInputSource(){} virtual void info(const std::wstring& string) = 0; virtual void warn(const std::wstring& string) = 0; virtual std::wstring getConsoleName() = 0; diff --git a/Minecraft.Client/Input/Input.h b/Minecraft.Client/Input/Input.h index 0a44d7656..daac8bf6d 100644 --- a/Minecraft.Client/Input/Input.h +++ b/Minecraft.Client/Input/Input.h @@ -12,6 +12,7 @@ public: bool sneaking; Input(); // 4J - added + virtual ~Input(){} virtual void tick(LocalPlayer *player); @@ -19,4 +20,4 @@ private: bool lReset; bool rReset; -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 0f74ad0db..531168cc0 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -3194,13 +3194,12 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) ui.SetTooltips( iPad, iA,iB,iX,iY,iLT,iRT,iLB,iRB); int wheel = 0; - if (InputManager.GetValue(iPad, MINECRAFT_ACTION_LEFT_SCROLL, true) > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL) ) - { - wheel = 1; - } - else if (InputManager.GetValue(iPad, MINECRAFT_ACTION_RIGHT_SCROLL,true) > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_RIGHT_SCROLL) ) - { - wheel = -1; + unsigned int leftTicks = InputManager.GetValue(iPad, MINECRAFT_ACTION_LEFT_SCROLL, true); + unsigned int rightTicks = InputManager.GetValue(iPad, MINECRAFT_ACTION_RIGHT_SCROLL, true); + if (leftTicks > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL)) { + wheel = (int)leftTicks; // positive = left + } else if (rightTicks > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_RIGHT_SCROLL)) { + wheel = -(int)rightTicks; // negative = right } if (wheel != 0) { @@ -3223,7 +3222,6 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) options->flySpeed += wheel * .25f; } } - if( gameMode->isInputAllowed(MINECRAFT_ACTION_ACTION) ) { if((player->ullButtonsPressed&(1LL<ullButtonsPressed&(1LL<ullButtonsPressed&(1LL<ullButtonsPressed; bool selected = false; + #ifdef __PSVITA__ // 4J-PB - use the touchscreen for quickselect SceTouchData* pTouchData = InputManager.GetTouchPadData(iPad,false); @@ -3458,6 +3458,14 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) } } #endif + { + int hotbarSlot = InputManager.GetHotbarSlotPressed(iPad); + if (hotbarSlot >= 0 && hotbarSlot <= 9) + { + player->inventory->selected = hotbarSlot; + selected = true; + } + } if( selected || wheel != 0 || (player->ullButtonsPressed&(1LL<inventory.swapPaint(wheel); - + { + int hotbarSlot = InputManager.GetHotbarSlotPressed(iPad); + if (hotbarSlot >= 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL)) + { + player->inventory->selected = hotbarSlot; + selected = true; + } + } if (options.isFlying) { if (wheel > 0) wheel = 1; if (wheel < 0) wheel = -1; diff --git a/Minecraft.Client/Network/PlayerChunkMap.cpp b/Minecraft.Client/Network/PlayerChunkMap.cpp index 8bedd4d6e..0f86fc0bf 100644 --- a/Minecraft.Client/Network/PlayerChunkMap.cpp +++ b/Minecraft.Client/Network/PlayerChunkMap.cpp @@ -33,7 +33,7 @@ PlayerChunkMap::PlayerChunk::PlayerChunk(int x, int z, PlayerChunkMap *pcm) : po PlayerChunkMap::PlayerChunk::~PlayerChunk() { - delete changedTiles.data; + delete[] changedTiles.data; //4jcraft, changed to [] } // 4J added - construct an an array of flags that indicate which entities are still waiting to have network packets sent out to say that they have been removed @@ -797,4 +797,4 @@ void PlayerChunkMap::setRadius(int newRadius) assert(radius >= MIN_VIEW_DISTANCE); this->radius = newRadius; } -} \ No newline at end of file +} diff --git a/Minecraft.Client/Platform/Common/Consoles_App.cpp b/Minecraft.Client/Platform/Common/Consoles_App.cpp index 9c4974493..c226ca016 100644 --- a/Minecraft.Client/Platform/Common/Consoles_App.cpp +++ b/Minecraft.Client/Platform/Common/Consoles_App.cpp @@ -4111,7 +4111,7 @@ void CMinecraftApp::loadStringTable() { byteArray locFile = m_mediaArchive->getFile(localisationFile); m_stringTable = new StringTable(locFile.data, locFile.length); - delete locFile.data; + delete[] locFile.data; } else { diff --git a/Minecraft.Client/Platform/Common/GameRules/ConsoleSchematicFile.cpp b/Minecraft.Client/Platform/Common/GameRules/ConsoleSchematicFile.cpp index 586e29997..f8af5039a 100644 --- a/Minecraft.Client/Platform/Common/GameRules/ConsoleSchematicFile.cpp +++ b/Minecraft.Client/Platform/Common/GameRules/ConsoleSchematicFile.cpp @@ -285,12 +285,12 @@ __int64 ConsoleSchematicFile::applyBlocksAndData(LevelChunk *chunk, AABB *chunkB PIXBeginNamedEvent(0,"Setting Block data"); chunk->setBlockData(blockData); PIXEndNamedEvent(); - delete blockData.data; + delete[] blockData.data; //4jcraft changed to array delete chunk->recalcHeightmapOnly(); PIXBeginNamedEvent(0,"Setting Data data"); chunk->setDataData(dataData); PIXEndNamedEvent(); - delete dataData.data; + delete[] dataData.data; //4jcraft, same here // A basic pass through to roughly do the lighting. At this point of post-processing, we don't have all the neighbouring chunks loaded in, // so any lighting here should be things that won't propagate out of this chunk. diff --git a/Minecraft.Client/Platform/Common/GameRules/GameRuleDefinition.h b/Minecraft.Client/Platform/Common/GameRules/GameRuleDefinition.h index d41e1aea7..289734428 100644 --- a/Minecraft.Client/Platform/Common/GameRules/GameRuleDefinition.h +++ b/Minecraft.Client/Platform/Common/GameRules/GameRuleDefinition.h @@ -27,6 +27,7 @@ protected: public: GameRuleDefinition(); + virtual ~GameRuleDefinition(){} virtual ConsoleGameRules::EGameRuleType getActionType() = 0; diff --git a/Minecraft.Client/Platform/Common/GameRules/LevelGenerationOptions.h b/Minecraft.Client/Platform/Common/GameRules/LevelGenerationOptions.h index d81436bee..11970a555 100644 --- a/Minecraft.Client/Platform/Common/GameRules/LevelGenerationOptions.h +++ b/Minecraft.Client/Platform/Common/GameRules/LevelGenerationOptions.h @@ -22,6 +22,7 @@ public: // was being mixed in with all the game information as they have // completely different lifespans. + virtual ~GrSource(){} virtual bool requiresTexturePack()=0; virtual UINT getRequiredTexturePackId()=0; virtual std::wstring getDefaultSaveName()=0; diff --git a/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp index 5fa598f74..a62be6143 100644 --- a/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp +++ b/Minecraft.Client/Platform/Common/Network/GameNetworkManager.cpp @@ -1108,7 +1108,7 @@ int CGameNetworkManager::ChangeSessionTypeThreadProc( void* lpParam ) app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)TRUE); // wait for the server to be in a non-ticking state - pServer->m_serverPausedEvent->WaitForSignal(INFINITY); + pServer->m_serverPausedEvent->WaitForSignal(INFINITE); #if defined(__PS3__) || defined(__ORBIS__) || defined __PSVITA__ // Swap these two messages around as one is too long to display at 480 @@ -1926,7 +1926,7 @@ void CGameNetworkManager::ServerReadyWait() { if (m_hServerReadyEvent != NULL) { - m_hServerReadyEvent->WaitForSignal(INFINITY); + m_hServerReadyEvent->WaitForSignal(INFINITE); } else { @@ -1990,7 +1990,7 @@ void CGameNetworkManager::ServerStoppedWait() { if (m_hServerStoppedEvent != NULL) { - m_hServerStoppedEvent->WaitForSignal(INFINITY); + m_hServerStoppedEvent->WaitForSignal(INFINITE); } else { diff --git a/Minecraft.Client/Platform/Common/Tutorial/LookAtEntityHint.h b/Minecraft.Client/Platform/Common/Tutorial/LookAtEntityHint.h index a30701a37..035a88e68 100644 --- a/Minecraft.Client/Platform/Common/Tutorial/LookAtEntityHint.h +++ b/Minecraft.Client/Platform/Common/Tutorial/LookAtEntityHint.h @@ -14,7 +14,8 @@ private: public: LookAtEntityHint(eTutorial_Hint id, Tutorial *tutorial, int descriptionId, int titleId, eINSTANCEOF type); - ~LookAtEntityHint(); + //TODO: 4jcraft added, this was not implemented + ~LookAtEntityHint(){}; virtual bool onLookAtEntity(eINSTANCEOF type); -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/Platform/Common/Tutorial/LookAtTileHint.cpp b/Minecraft.Client/Platform/Common/Tutorial/LookAtTileHint.cpp index 5d03960c9..760d5b54f 100644 --- a/Minecraft.Client/Platform/Common/Tutorial/LookAtTileHint.cpp +++ b/Minecraft.Client/Platform/Common/Tutorial/LookAtTileHint.cpp @@ -10,6 +10,7 @@ LookAtTileHint::LookAtTileHint(eTutorial_Hint id, Tutorial *tutorial, int tiles[ { m_iTilesCount = tilesLength; + //TODO: 4jcraft: allocating but never freeing mem, leak m_iTiles= new int [m_iTilesCount]; for(unsigned int i=0;i item ); -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/Platform/Common/Tutorial/Tutorial.h b/Minecraft.Client/Platform/Common/Tutorial/Tutorial.h index 3f06df12f..5e9aaaad1 100644 --- a/Minecraft.Client/Platform/Common/Tutorial/Tutorial.h +++ b/Minecraft.Client/Platform/Common/Tutorial/Tutorial.h @@ -123,7 +123,7 @@ public: bool m_isFullTutorial; public: Tutorial(int iPad, bool isFullTutorial = false); - ~Tutorial(); + virtual ~Tutorial(); void tick(); int getPad() { return m_iPad; } diff --git a/Minecraft.Client/Platform/Common/Tutorial/TutorialHint.h b/Minecraft.Client/Platform/Common/Tutorial/TutorialHint.h index 191b021f3..e40759841 100644 --- a/Minecraft.Client/Platform/Common/Tutorial/TutorialHint.h +++ b/Minecraft.Client/Platform/Common/Tutorial/TutorialHint.h @@ -37,6 +37,7 @@ protected: public: TutorialHint(eTutorial_Hint id, Tutorial *tutorial, int descriptionId, eHintType type, bool allowFade = true); + virtual ~TutorialHint(){} eTutorial_Hint getId() { return m_id; } @@ -50,4 +51,4 @@ public: virtual bool onLookAtEntity(eINSTANCEOF type); virtual int tick(); virtual bool allowFade() { return m_allowFade; } -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/Platform/Linux/Iggy/gdraw/gdraw_glfw.c b/Minecraft.Client/Platform/Linux/Iggy/gdraw/gdraw_glfw.c index 7962ef494..96fe64b4e 100644 --- a/Minecraft.Client/Platform/Linux/Iggy/gdraw/gdraw_glfw.c +++ b/Minecraft.Client/Platform/Linux/Iggy/gdraw/gdraw_glfw.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -23,26 +23,26 @@ // Iggy GDraw support functions - normally in the Iggy library, stubbed here void * IggyGDrawMallocAnnotated(SINTa size, const char *file, int line) { - (void)file; (void)line; - return malloc((size_t)size); + (void)file; (void)line; + return malloc((size_t)size); } void IggyGDrawFree(void *ptr) { - free(ptr); + free(ptr); } void IggyGDrawSendWarning(Iggy *f, char const *message, ...) { - (void)f; - va_list args; - va_start(args, message); - fprintf(stderr, "[Iggy GDraw Warning] "); - vfprintf(stderr, message, args); - fprintf(stderr, "\n"); - va_end(args); + (void)f; + va_list args; + va_start(args, message); + fprintf(stderr, "[Iggy GDraw Warning] "); + vfprintf(stderr, message, args); + fprintf(stderr, "\n"); + va_end(args); } void IggyDiscardVertexBufferCallback(void *owner, void *buf) { - (void)owner; (void)buf; + (void)owner; (void)buf; } /////////////////////////////////////////////////////////////////////////////// @@ -56,56 +56,56 @@ void IggyDiscardVertexBufferCallback(void *owner, void *buf) { // #define GDRAW_GL_EXTENSION_LIST \ - /* identifier import procname */ \ - /* GL_ARB_vertex_buffer_object */ \ - GLE(GenBuffers, "GenBuffersARB", GENBUFFERSARB) \ - GLE(DeleteBuffers, "DeleteBuffersARB", DELETEBUFFERSARB) \ - GLE(BindBuffer, "BindBufferARB", BINDBUFFERARB) \ - GLE(BufferData, "BufferDataARB", BUFFERDATAARB) \ - GLE(MapBuffer, "MapBufferARB", MAPBUFFERARB) \ - GLE(UnmapBuffer, "UnmapBufferARB", UNMAPBUFFERARB) \ - GLE(VertexAttribPointer, "VertexAttribPointerARB", VERTEXATTRIBPOINTERARB) \ - GLE(EnableVertexAttribArray, "EnableVertexAttribArrayARB", ENABLEVERTEXATTRIBARRAYARB) \ - GLE(DisableVertexAttribArray, "DisableVertexAttribArrayARB", DISABLEVERTEXATTRIBARRAYARB) \ - /* GL_ARB_shader_objects */ \ - GLE(CreateShader, "CreateShaderObjectARB", CREATESHADEROBJECTARB) \ - GLE(DeleteShader, "DeleteObjectARB", DELETEOBJECTARB) \ - GLE(ShaderSource, "ShaderSourceARB", SHADERSOURCEARB) \ - GLE(CompileShader, "CompileShaderARB", COMPILESHADERARB) \ - GLE(GetShaderiv, "GetObjectParameterivARB", GETOBJECTPARAMETERIVARB) \ - GLE(GetShaderInfoLog, "GetInfoLogARB", GETINFOLOGARB) \ - GLE(CreateProgram, "CreateProgramObjectARB", CREATEPROGRAMOBJECTARB) \ - GLE(DeleteProgram, "DeleteObjectARB", DELETEOBJECTARB) \ - GLE(AttachShader, "AttachObjectARB", ATTACHOBJECTARB) \ - GLE(LinkProgram, "LinkProgramARB", LINKPROGRAMARB) \ - GLE(GetUniformLocation, "GetUniformLocationARB", GETUNIFORMLOCATIONARB) \ - GLE(UseProgram, "UseProgramObjectARB", USEPROGRAMOBJECTARB) \ - GLE(GetProgramiv, "GetObjectParameterivARB", GETOBJECTPARAMETERIVARB) \ - GLE(GetProgramInfoLog, "GetInfoLogARB", GETINFOLOGARB) \ - GLE(Uniform1i, "Uniform1iARB", UNIFORM1IARB) \ - GLE(Uniform4f, "Uniform4fARB", UNIFORM4FARB) \ - GLE(Uniform4fv, "Uniform4fvARB", UNIFORM4FVARB) \ - /* GL_ARB_vertex_shader */ \ - GLE(BindAttribLocation, "BindAttribLocationARB", BINDATTRIBLOCATIONARB) \ - /* Missing from WGL but needed by shared code */ \ - GLE(Uniform1f, "Uniform1fARB", UNIFORM1FARB) \ - /* GL_EXT_framebuffer_object */ \ - GLE(GenRenderbuffers, "GenRenderbuffersEXT", GENRENDERBUFFERSEXT) \ - GLE(DeleteRenderbuffers, "DeleteRenderbuffersEXT", DELETERENDERBUFFERSEXT) \ - GLE(BindRenderbuffer, "BindRenderbufferEXT", BINDRENDERBUFFEREXT) \ - GLE(RenderbufferStorage, "RenderbufferStorageEXT", RENDERBUFFERSTORAGEEXT) \ - GLE(GenFramebuffers, "GenFramebuffersEXT", GENFRAMEBUFFERSEXT) \ - GLE(DeleteFramebuffers, "DeleteFramebuffersEXT", DELETEFRAMEBUFFERSEXT) \ - GLE(BindFramebuffer, "BindFramebufferEXT", BINDFRAMEBUFFEREXT) \ - GLE(CheckFramebufferStatus, "CheckFramebufferStatusEXT", CHECKFRAMEBUFFERSTATUSEXT) \ - GLE(FramebufferRenderbuffer, "FramebufferRenderbufferEXT", FRAMEBUFFERRENDERBUFFEREXT) \ - GLE(FramebufferTexture2D, "FramebufferTexture2DEXT", FRAMEBUFFERTEXTURE2DEXT) \ - GLE(GenerateMipmap, "GenerateMipmapEXT", GENERATEMIPMAPEXT) \ - /* GL_EXT_framebuffer_blit */ \ - GLE(BlitFramebuffer, "BlitFramebufferEXT", BLITFRAMEBUFFEREXT) \ - /* GL_EXT_framebuffer_multisample */ \ - GLE(RenderbufferStorageMultisample, "RenderbufferStorageMultisampleEXT",RENDERBUFFERSTORAGEMULTISAMPLEEXT) \ - /* */ +/* identifier import procname */ \ +/* GL_ARB_vertex_buffer_object */ \ +GLE(GenBuffers, "GenBuffersARB", GENBUFFERSARB) \ +GLE(DeleteBuffers, "DeleteBuffersARB", DELETEBUFFERSARB) \ +GLE(BindBuffer, "BindBufferARB", BINDBUFFERARB) \ +GLE(BufferData, "BufferDataARB", BUFFERDATAARB) \ +GLE(MapBuffer, "MapBufferARB", MAPBUFFERARB) \ +GLE(UnmapBuffer, "UnmapBufferARB", UNMAPBUFFERARB) \ +GLE(VertexAttribPointer, "VertexAttribPointerARB", VERTEXATTRIBPOINTERARB) \ +GLE(EnableVertexAttribArray, "EnableVertexAttribArrayARB", ENABLEVERTEXATTRIBARRAYARB) \ +GLE(DisableVertexAttribArray, "DisableVertexAttribArrayARB", DISABLEVERTEXATTRIBARRAYARB) \ +/* GL_ARB_shader_objects */ \ +GLE(CreateShader, "CreateShaderObjectARB", CREATESHADEROBJECTARB) \ +GLE(DeleteShader, "DeleteObjectARB", DELETEOBJECTARB) \ +GLE(ShaderSource, "ShaderSourceARB", SHADERSOURCEARB) \ +GLE(CompileShader, "CompileShaderARB", COMPILESHADERARB) \ +GLE(GetShaderiv, "GetObjectParameterivARB", GETOBJECTPARAMETERIVARB) \ +GLE(GetShaderInfoLog, "GetInfoLogARB", GETINFOLOGARB) \ +GLE(CreateProgram, "CreateProgramObjectARB", CREATEPROGRAMOBJECTARB) \ +GLE(DeleteProgram, "DeleteObjectARB", DELETEOBJECTARB) \ +GLE(AttachShader, "AttachObjectARB", ATTACHOBJECTARB) \ +GLE(LinkProgram, "LinkProgramARB", LINKPROGRAMARB) \ +GLE(GetUniformLocation, "GetUniformLocationARB", GETUNIFORMLOCATIONARB) \ +GLE(UseProgram, "UseProgramObjectARB", USEPROGRAMOBJECTARB) \ +GLE(GetProgramiv, "GetObjectParameterivARB", GETOBJECTPARAMETERIVARB) \ +GLE(GetProgramInfoLog, "GetInfoLogARB", GETINFOLOGARB) \ +GLE(Uniform1i, "Uniform1iARB", UNIFORM1IARB) \ +GLE(Uniform4f, "Uniform4fARB", UNIFORM4FARB) \ +GLE(Uniform4fv, "Uniform4fvARB", UNIFORM4FVARB) \ +/* GL_ARB_vertex_shader */ \ +GLE(BindAttribLocation, "BindAttribLocationARB", BINDATTRIBLOCATIONARB) \ +/* Missing from WGL but needed by shared code */ \ +GLE(Uniform1f, "Uniform1fARB", UNIFORM1FARB) \ +/* GL_EXT_framebuffer_object */ \ +GLE(GenRenderbuffers, "GenRenderbuffersEXT", GENRENDERBUFFERSEXT) \ +GLE(DeleteRenderbuffers, "DeleteRenderbuffersEXT", DELETERENDERBUFFERSEXT) \ +GLE(BindRenderbuffer, "BindRenderbufferEXT", BINDRENDERBUFFEREXT) \ +GLE(RenderbufferStorage, "RenderbufferStorageEXT", RENDERBUFFERSTORAGEEXT) \ +GLE(GenFramebuffers, "GenFramebuffersEXT", GENFRAMEBUFFERSEXT) \ +GLE(DeleteFramebuffers, "DeleteFramebuffersEXT", DELETEFRAMEBUFFERSEXT) \ +GLE(BindFramebuffer, "BindFramebufferEXT", BINDFRAMEBUFFEREXT) \ +GLE(CheckFramebufferStatus, "CheckFramebufferStatusEXT", CHECKFRAMEBUFFERSTATUSEXT) \ +GLE(FramebufferRenderbuffer, "FramebufferRenderbufferEXT", FRAMEBUFFERRENDERBUFFEREXT) \ +GLE(FramebufferTexture2D, "FramebufferTexture2DEXT", FRAMEBUFFERTEXTURE2DEXT) \ +GLE(GenerateMipmap, "GenerateMipmapEXT", GENERATEMIPMAPEXT) \ +/* GL_EXT_framebuffer_blit */ \ +GLE(BlitFramebuffer, "BlitFramebufferEXT", BLITFRAMEBUFFEREXT) \ +/* GL_EXT_framebuffer_multisample */ \ +GLE(RenderbufferStorageMultisample, "RenderbufferStorageMultisampleEXT",RENDERBUFFERSTORAGEMULTISAMPLEEXT) \ +/* */ #define gdraw_GLx_(id) gdraw_GL_##id #define GDRAW_GLx_(id) GDRAW_GL_##id @@ -125,19 +125,19 @@ GDRAW_GL_EXTENSION_LIST static void load_extensions(void) { -#define GLE(id, import, procname) gl##id = (PFNGL##procname##PROC) glfwGetProcAddress("gl" import); - GDRAW_GL_EXTENSION_LIST -#undef GLE + #define GLE(id, import, procname) gl##id = (PFNGL##procname##PROC) SDL_GL_GetProcAddress("gl" import); + GDRAW_GL_EXTENSION_LIST + #undef GLE } static void clear_renderstate_platform_specific(void) { - glDisable(GL_ALPHA_TEST); + glDisable(GL_ALPHA_TEST); } static void error_msg_platform_specific(const char *msg) { - fprintf(stderr, "[GDraw GL] %s\n", msg); + fprintf(stderr, "[GDraw GL] %s\n", msg); } /////////////////////////////////////////////////////////////////////////////// @@ -162,80 +162,80 @@ static void error_msg_platform_specific(const char *msg) GDrawFunctions *gdraw_GL_CreateContext(S32 w, S32 h, S32 msaa_samples) { - static const TextureFormatDesc tex_formats[] = { - { IFT_FORMAT_rgba_8888, 1, 1, 4, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_rgba_4444_LE, 1, 1, 2, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }, - { IFT_FORMAT_rgba_5551_LE, 1, 1, 2, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, - { IFT_FORMAT_la_88, 1, 1, 2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_la_44, 1, 1, 1, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_i_8, 1, 1, 1, GL_INTENSITY8, GL_ALPHA, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_i_4, 1, 1, 1, GL_INTENSITY4, GL_ALPHA, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_l_8, 1, 1, 1, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_l_4, 1, 1, 1, GL_LUMINANCE4, GL_LUMINANCE, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_DXT1, 4, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_DXT3, 4, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0, GL_UNSIGNED_BYTE }, - { IFT_FORMAT_DXT5, 4, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0, GL_UNSIGNED_BYTE }, - { 0, 0, 0, 0, 0, 0, 0 }, - }; + static const TextureFormatDesc tex_formats[] = { + { IFT_FORMAT_rgba_8888, 1, 1, 4, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_rgba_4444_LE, 1, 1, 2, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }, + { IFT_FORMAT_rgba_5551_LE, 1, 1, 2, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, + { IFT_FORMAT_la_88, 1, 1, 2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_la_44, 1, 1, 1, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_i_8, 1, 1, 1, GL_INTENSITY8, GL_ALPHA, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_i_4, 1, 1, 1, GL_INTENSITY4, GL_ALPHA, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_l_8, 1, 1, 1, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_l_4, 1, 1, 1, GL_LUMINANCE4, GL_LUMINANCE, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_DXT1, 4, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_DXT3, 4, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0, GL_UNSIGNED_BYTE }, + { IFT_FORMAT_DXT5, 4, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0, GL_UNSIGNED_BYTE }, + { 0, 0, 0, 0, 0, 0, 0 }, + }; - GDrawFunctions *funcs; - const char *s; - GLint n; + GDrawFunctions *funcs; + const char *s; + GLint n; - // check for the extensions we need - s = (const char *) glGetString(GL_EXTENSIONS); - if (s == NULL) { - fprintf(stderr, "[GDraw GL] glGetString(GL_EXTENSIONS) returned NULL - GL context not current?\n"); - assert(s != NULL); - return NULL; - } + // check for the extensions we need + s = (const char *) glGetString(GL_EXTENSIONS); + if (s == NULL) { + fprintf(stderr, "[GDraw GL] glGetString(GL_EXTENSIONS) returned NULL - GL context not current?\n"); + assert(s != NULL); + return NULL; + } - // check for the extensions we won't work without - if (!hasext(s, "GL_ARB_multitexture") || - !hasext(s, "GL_ARB_texture_compression") || - !hasext(s, "GL_ARB_texture_mirrored_repeat") || - !hasext(s, "GL_ARB_texture_non_power_of_two") || - !hasext(s, "GL_ARB_vertex_buffer_object") || - !hasext(s, "GL_EXT_framebuffer_object") || - !hasext(s, "GL_ARB_shader_objects") || - !hasext(s, "GL_ARB_vertex_shader") || - !hasext(s, "GL_ARB_fragment_shader")) - { - fprintf(stderr, "[GDraw GL] Required GL extensions not available\n"); - return NULL; - } + // check for the extensions we won't work without + if (!hasext(s, "GL_ARB_multitexture") || + !hasext(s, "GL_ARB_texture_compression") || + !hasext(s, "GL_ARB_texture_mirrored_repeat") || + !hasext(s, "GL_ARB_texture_non_power_of_two") || + !hasext(s, "GL_ARB_vertex_buffer_object") || + !hasext(s, "GL_EXT_framebuffer_object") || + !hasext(s, "GL_ARB_shader_objects") || + !hasext(s, "GL_ARB_vertex_shader") || + !hasext(s, "GL_ARB_fragment_shader")) + { + fprintf(stderr, "[GDraw GL] Required GL extensions not available\n"); + return NULL; + } - // if user requests multisampling and HW doesn't support it, bail - if (!hasext(s, "GL_EXT_framebuffer_multisample") && msaa_samples > 1) - return NULL; + // if user requests multisampling and HW doesn't support it, bail + if (!hasext(s, "GL_EXT_framebuffer_multisample") && msaa_samples > 1) + return NULL; - load_extensions(); - funcs = create_context(w, h); - if (!funcs) - return NULL; + load_extensions(); + funcs = create_context(w, h); + if (!funcs) + return NULL; - gdraw->tex_formats = tex_formats; + gdraw->tex_formats = tex_formats; - // check for optional extensions - gdraw->has_mapbuffer = true; // part of core VBO extension on regular GL - gdraw->has_depth24 = true; // we just assume. - gdraw->has_texture_max_level = true; // core on regular GL + // check for optional extensions + gdraw->has_mapbuffer = true; // part of core VBO extension on regular GL + gdraw->has_depth24 = true; // we just assume. + gdraw->has_texture_max_level = true; // core on regular GL - if (hasext(s, "GL_EXT_packed_depth_stencil")) gdraw->has_packed_depth_stencil = true; + if (hasext(s, "GL_EXT_packed_depth_stencil")) gdraw->has_packed_depth_stencil = true; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &n); - gdraw->has_conditional_non_power_of_two = n < 8192; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &n); + gdraw->has_conditional_non_power_of_two = n < 8192; - // clamp number of multisampling levels to max supported - if (msaa_samples > 1) { - glGetIntegerv(GL_MAX_SAMPLES, &n); - gdraw->multisampling = RR_MIN(msaa_samples, n); - } + // clamp number of multisampling levels to max supported + if (msaa_samples > 1) { + glGetIntegerv(GL_MAX_SAMPLES, &n); + gdraw->multisampling = RR_MIN(msaa_samples, n); + } - opengl_check(); + opengl_check(); - fprintf(stderr, "[GDraw GL] Context created successfully (%dx%d, msaa=%d)\n", w, h, msaa_samples); - return funcs; + fprintf(stderr, "[GDraw GL] Context created successfully (%dx%d, msaa=%d)\n", w, h, msaa_samples); + return funcs; } /////////////////////////////////////////////////////////////////////////////// @@ -245,12 +245,12 @@ GDrawFunctions *gdraw_GL_CreateContext(S32 w, S32 h, S32 msaa_samples) void gdraw_GL_BeginCustomDraw_4J(IggyCustomDrawCallbackRegion *region, F32 *matrix) { - // Same as BeginCustomDraw but uses different depth param - clear_renderstate(); - gdraw_GetObjectSpaceMatrix(matrix, region->o2w, gdraw->projection, depth_from_id(0), 1); + // Same as BeginCustomDraw but uses different depth param + clear_renderstate(); + gdraw_GetObjectSpaceMatrix(matrix, region->o2w, gdraw->projection, depth_from_id(0), 1); } void gdraw_GL_CalculateCustomDraw_4J(IggyCustomDrawCallbackRegion *region, F32 *matrix) { - gdraw_GetObjectSpaceMatrix(matrix, region->o2w, gdraw->projection, 0.0f, 0); + gdraw_GetObjectSpaceMatrix(matrix, region->o2w, gdraw->projection, 0.0f, 0); } diff --git a/Minecraft.Client/Platform/Linux/Linux_App.cpp b/Minecraft.Client/Platform/Linux/Linux_App.cpp index 5fcd8017e..a9520f211 100644 --- a/Minecraft.Client/Platform/Linux/Linux_App.cpp +++ b/Minecraft.Client/Platform/Linux/Linux_App.cpp @@ -32,6 +32,8 @@ void CConsoleMinecraftApp::ExitGame() } void CConsoleMinecraftApp::FatalLoadError() { + app.DebugPrintf("CConsoleMinecraftApp::FatalLoadError - asserting 0 and dying...\n"); + assert(0); } void CConsoleMinecraftApp::CaptureSaveThumbnail() diff --git a/Minecraft.Client/Platform/Linux/Linux_Minecraft.cpp b/Minecraft.Client/Platform/Linux/Linux_Minecraft.cpp index 4ab22f581..38717792f 100644 --- a/Minecraft.Client/Platform/Linux/Linux_Minecraft.cpp +++ b/Minecraft.Client/Platform/Linux/Linux_Minecraft.cpp @@ -699,10 +699,6 @@ ProfileManager.Initialise(TITLEID_MINECRAFT, &app.uiGameDefinedDataChangedBitmask ); -byteArray baOptionsIcon = app.getArchiveFile(L"DefaultOptionsImage228x128.png"); -byteArray baSaveThumbnail = app.getArchiveFile(L"DefaultSaveThumbnail64x64.png"); -byteArray baSaveImage = app.getArchiveFile(L"DefaultSaveImage228x128.png"); - // set a function to be called when there's a sign in change, so we can exit a level if the primary player signs out ProfileManager.SetSignInChangeCallback(&CConsoleMinecraftApp::SignInChangeCallback,(LPVOID)&app); diff --git a/Minecraft.Client/Player/MultiPlayerGameMode.h b/Minecraft.Client/Player/MultiPlayerGameMode.h index 19ef46af6..34396aebd 100644 --- a/Minecraft.Client/Player/MultiPlayerGameMode.h +++ b/Minecraft.Client/Player/MultiPlayerGameMode.h @@ -23,6 +23,7 @@ protected: public: MultiPlayerGameMode(Minecraft *minecraft, ClientConnection *connection); + virtual ~MultiPlayerGameMode(){} static void creativeDestroyBlock(Minecraft *minecraft, MultiPlayerGameMode *gameMode, int x, int y, int z, int face); void adjustPlayer(std::shared_ptr player); bool isCutScene(); @@ -64,4 +65,4 @@ public: virtual bool isInputAllowed(int mapping) { return true; } virtual bool isTutorial() { return false; } virtual Tutorial *getTutorial() { return NULL; } -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/Rendering/EntityRenderers/TileRenderer.cpp b/Minecraft.Client/Rendering/EntityRenderers/TileRenderer.cpp index a84a13eeb..30d05c2b3 100644 --- a/Minecraft.Client/Rendering/EntityRenderers/TileRenderer.cpp +++ b/Minecraft.Client/Rendering/EntityRenderers/TileRenderer.cpp @@ -160,7 +160,7 @@ TileRenderer::TileRenderer( LevelSource* level, int xMin, int yMin, int zMin, un TileRenderer::~TileRenderer() { - delete cache; + delete[] cache; //4jcraft, changed to [] } TileRenderer::TileRenderer( LevelSource* level ) diff --git a/Minecraft.Client/Rendering/Models/Model.h b/Minecraft.Client/Rendering/Models/Model.h index 104e6ce27..c80f9e8f6 100644 --- a/Minecraft.Client/Rendering/Models/Model.h +++ b/Minecraft.Client/Rendering/Models/Model.h @@ -19,6 +19,7 @@ public: int texHeight; Model(); // 4J added + virtual ~Model(){} virtual void render(std::shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled) {} virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, unsigned int uiBitmaskOverrideAnim=0) {} virtual void prepareMobModel(std::shared_ptr mob, float time, float r, float a) {} diff --git a/Minecraft.Client/Textures/MemTextureProcessor.h b/Minecraft.Client/Textures/MemTextureProcessor.h index 8e945e1d5..56590d428 100644 --- a/Minecraft.Client/Textures/MemTextureProcessor.h +++ b/Minecraft.Client/Textures/MemTextureProcessor.h @@ -4,5 +4,6 @@ class BufferedImage; class MemTextureProcessor { public: + virtual ~MemTextureProcessor(){} virtual BufferedImage *process(BufferedImage *read) = 0; -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/Textures/Packs/DLCTexturePack.h b/Minecraft.Client/Textures/Packs/DLCTexturePack.h index 375c8cafe..f69eb0258 100644 --- a/Minecraft.Client/Textures/Packs/DLCTexturePack.h +++ b/Minecraft.Client/Textures/Packs/DLCTexturePack.h @@ -23,7 +23,7 @@ public: using AbstractTexturePack::getResource; DLCTexturePack(DWORD id, DLCPack *pack, TexturePack *fallback); - ~DLCTexturePack(); + ~DLCTexturePack(){}; virtual std::wstring getResource(const std::wstring& name); virtual DLCPack * getDLCPack(); diff --git a/Minecraft.Client/Textures/Packs/TexturePack.h b/Minecraft.Client/Textures/Packs/TexturePack.h index edbabc796..781fbe474 100644 --- a/Minecraft.Client/Textures/Packs/TexturePack.h +++ b/Minecraft.Client/Textures/Packs/TexturePack.h @@ -12,6 +12,7 @@ class TexturePack public: TexturePack() { m_bHasAudio=false;} + virtual ~TexturePack(){} virtual bool hasData() = 0; virtual bool hasAudio() { return m_bHasAudio;} virtual void setHasAudio(bool bVal) {m_bHasAudio=bVal;} diff --git a/Minecraft.Client/Textures/Stitching/StitchedTexture.cpp b/Minecraft.Client/Textures/Stitching/StitchedTexture.cpp index 86eb37577..124c7207f 100644 --- a/Minecraft.Client/Textures/Stitching/StitchedTexture.cpp +++ b/Minecraft.Client/Textures/Stitching/StitchedTexture.cpp @@ -60,11 +60,17 @@ void StitchedTexture::freeFrameTextures() StitchedTexture::~StitchedTexture() { - for(AUTO_VAR(it, frames->begin()); it != frames->end(); ++it) - { - delete *it; + // 4jcraft, added null check + // the constructor does not allocate the frames vector. + // in some scenarios the destructor/delete is called + // without ever calling ::init() + if(frames) { + for(AUTO_VAR(it, frames->begin()); it != frames->end(); ++it) + { + delete *it; + } + delete frames; } - delete frames; } void StitchedTexture::initUVs(float U0, float V0, float U1, float V1) @@ -351,4 +357,4 @@ int StitchedTexture::getFlags() const bool StitchedTexture::hasOwnData() { return true; -} \ No newline at end of file +} diff --git a/Minecraft.Client/Textures/Stitching/StitchedTexture.h b/Minecraft.Client/Textures/Stitching/StitchedTexture.h index edb3c3c05..306ffd1b7 100644 --- a/Minecraft.Client/Textures/Stitching/StitchedTexture.h +++ b/Minecraft.Client/Textures/Stitching/StitchedTexture.h @@ -86,4 +86,4 @@ public: void setFlags(int flags); // 4J added virtual void freeFrameTextures(); // 4J added virtual bool hasOwnData(); // 4J Added -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/Textures/TextureManager.cpp b/Minecraft.Client/Textures/TextureManager.cpp index 6fd3813fa..546bdc17f 100644 --- a/Minecraft.Client/Textures/TextureManager.cpp +++ b/Minecraft.Client/Textures/TextureManager.cpp @@ -193,4 +193,4 @@ Texture *TextureManager::createTexture(const std::wstring &name, int mode, int w // 4J Stu - Don't clamp as it causes issues with how we signal non-mipmmapped textures to the pixel shader //return createTexture(name, mode, width, height, Texture::WM_CLAMP, format, Texture::TFLT_NEAREST, Texture::TFLT_NEAREST, mipmap, NULL); return createTexture(name, mode, width, height, Texture::WM_WRAP, format, Texture::TFLT_NEAREST, Texture::TFLT_NEAREST, mipmap, NULL); -} \ No newline at end of file +} diff --git a/Minecraft.Client/Utils/MemoryTracker.h b/Minecraft.Client/Utils/MemoryTracker.h index 8bf103be5..8492aae28 100644 --- a/Minecraft.Client/Utils/MemoryTracker.h +++ b/Minecraft.Client/Utils/MemoryTracker.h @@ -1,5 +1,4 @@ #pragma once -#include "MemoryTracker.h" class ByteBuffer; class IntBuffer; class FloatBuffer; diff --git a/Minecraft.Client/meson.build b/Minecraft.Client/meson.build index b362462c8..94a7e4933 100644 --- a/Minecraft.Client/meson.build +++ b/Minecraft.Client/meson.build @@ -57,9 +57,8 @@ client = executable('Minecraft.Client', world_dep, gl_dep, glu_dep, - glfw_dep, thread_dep, - dl_dep, + thread_dep, dependency('zlib'), ], cpp_args : global_cpp_args + global_cpp_defs + [ @@ -86,4 +85,4 @@ custom_target('copy_assets_to_client', '@OUTPUT@', ], build_by_default: true, -) \ No newline at end of file +) diff --git a/Minecraft.World/AI/Control/JumpControl.h b/Minecraft.World/AI/Control/JumpControl.h index b33648c7e..4ff9cfce7 100644 --- a/Minecraft.World/AI/Control/JumpControl.h +++ b/Minecraft.World/AI/Control/JumpControl.h @@ -12,7 +12,9 @@ private: public: JumpControl(Mob *mob); + virtual ~JumpControl(){} void jump(); + //genuinly, why tf is this VIRTUAL virtual void tick(); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/AI/Control/LookControl.h b/Minecraft.World/AI/Control/LookControl.h index fe182e7c7..3f9dabb2e 100644 --- a/Minecraft.World/AI/Control/LookControl.h +++ b/Minecraft.World/AI/Control/LookControl.h @@ -15,6 +15,7 @@ private: public: LookControl(Mob *mob); + virtual ~LookControl(){} void setLookAt(std::shared_ptr target, float yMax, float xMax); void setLookAt(double x, double y, double z, float yMax, float xMax); @@ -30,4 +31,4 @@ public: double getWantedX(); double getWantedY(); double getWantedZ(); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/AI/Control/MoveControl.h b/Minecraft.World/AI/Control/MoveControl.h index 4138280e0..89ac8162b 100644 --- a/Minecraft.World/AI/Control/MoveControl.h +++ b/Minecraft.World/AI/Control/MoveControl.h @@ -22,6 +22,7 @@ private: public: MoveControl(Mob *mob); + virtual ~MoveControl(){} bool hasWanted(); float getSpeed(); @@ -31,4 +32,4 @@ public: private: float rotlerp(float a, float b, float max); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Containers/Container.h b/Minecraft.World/Containers/Container.h index 46444696f..06ee42a28 100644 --- a/Minecraft.World/Containers/Container.h +++ b/Minecraft.World/Containers/Container.h @@ -7,6 +7,7 @@ class Player; class Container { public: + virtual ~Container(){} static const int LARGE_MAX_STACK_SIZE = 64; virtual unsigned int getContainerSize() = 0; @@ -20,4 +21,4 @@ public: virtual bool stillValid(std::shared_ptr player) = 0; virtual void startOpen() = 0; virtual void stopOpen() = 0; -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Containers/CraftingContainer.h b/Minecraft.World/Containers/CraftingContainer.h index 5ef82ea20..e912c0957 100644 --- a/Minecraft.World/Containers/CraftingContainer.h +++ b/Minecraft.World/Containers/CraftingContainer.h @@ -13,7 +13,7 @@ private: public: CraftingContainer(AbstractContainerMenu *menu, unsigned int w, unsigned int h); - ~CraftingContainer(); + virtual ~CraftingContainer(); virtual unsigned int getContainerSize(); virtual std::shared_ptr getItem(unsigned int slot); @@ -29,4 +29,4 @@ public: void startOpen() { } // TODO Auto-generated method stub void stopOpen() { } // TODO Auto-generated method stub -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Containers/Merchant.h b/Minecraft.World/Containers/Merchant.h index ad7ab1fcb..6c700c7ff 100644 --- a/Minecraft.World/Containers/Merchant.h +++ b/Minecraft.World/Containers/Merchant.h @@ -7,6 +7,7 @@ class Player; class Merchant { public: + virtual ~Merchant(){} virtual void setTradingPlayer(std::shared_ptr player) = 0; virtual std::shared_ptr getTradingPlayer() = 0; virtual MerchantRecipeList *getOffers(std::shared_ptr forPlayer) = 0; @@ -14,4 +15,4 @@ public: virtual void notifyTrade(MerchantRecipe *activeRecipe) = 0; virtual void notifyTradeUpdated(std::shared_ptr item) = 0; virtual int getDisplayName() = 0; -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Containers/ResultContainer.h b/Minecraft.World/Containers/ResultContainer.h index 1b030d810..8f83543d6 100644 --- a/Minecraft.World/Containers/ResultContainer.h +++ b/Minecraft.World/Containers/ResultContainer.h @@ -10,6 +10,7 @@ private: public: // 4J Stu Added a ctor to init items ResultContainer(); + virtual ~ResultContainer(){} virtual unsigned int getContainerSize(); virtual std::shared_ptr getItem(unsigned int slot); @@ -23,4 +24,4 @@ public: void startOpen() { } // TODO Auto-generated method stub void stopOpen() { } // TODO Auto-generated method stub -}; \ No newline at end of file +}; diff --git a/Minecraft.World/IO/Streams/BufferedOutputStream.cpp b/Minecraft.World/IO/Streams/BufferedOutputStream.cpp index 4e1051a7c..379686138 100644 --- a/Minecraft.World/IO/Streams/BufferedOutputStream.cpp +++ b/Minecraft.World/IO/Streams/BufferedOutputStream.cpp @@ -15,7 +15,11 @@ BufferedOutputStream::BufferedOutputStream(OutputStream *out, int size) BufferedOutputStream::~BufferedOutputStream() { - delete buf.data; + //4jcraft, changed to [], deallocates internal buffer + //TODO: ArrayWithLength.h doesnt have a destructor. + //this wouldnt need to be done manually. + //but for some reason the destructor is commented out in the source code? + delete[] buf.data; } //Flushes this buffered output stream. This forces any buffered output bytes to be written out to the underlying output stream. diff --git a/Minecraft.World/Items/ItemInstance.h b/Minecraft.World/Items/ItemInstance.h index 465ee1ec0..6a706d0ad 100644 --- a/Minecraft.World/Items/ItemInstance.h +++ b/Minecraft.World/Items/ItemInstance.h @@ -63,7 +63,7 @@ private: ItemInstance() { _init(-1,0,0); } public: - ~ItemInstance(); + virtual ~ItemInstance(); std::shared_ptr remove(int count); Item *getItem() const; @@ -151,4 +151,4 @@ public: int getBaseRepairCost(); void setRepairCost(int cost); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Items/MapItem.cpp b/Minecraft.World/Items/MapItem.cpp index 292320b27..908d0f776 100644 --- a/Minecraft.World/Items/MapItem.cpp +++ b/Minecraft.World/Items/MapItem.cpp @@ -342,6 +342,6 @@ std::shared_ptr MapItem::getUpdatePacket(std::shared_ptr i if (data.data == NULL || data.length == 0) return nullptr; std::shared_ptr retval = std::shared_ptr(new ComplexItemDataPacket((short) Item::map->id, (short) itemInstance->getAuxValue(), data)); - delete data.data; + delete[] data.data; //4jcraft, changed to [] return retval; } diff --git a/Minecraft.World/Level/Dimensions/Dimension.h b/Minecraft.World/Level/Dimensions/Dimension.h index 752ed0df4..9d79c990f 100644 --- a/Minecraft.World/Level/Dimensions/Dimension.h +++ b/Minecraft.World/Level/Dimensions/Dimension.h @@ -28,7 +28,7 @@ protected: public: Dimension(); - ~Dimension(); + virtual ~Dimension(); virtual ChunkSource *createRandomLevelSource() const; virtual ChunkSource *createFlatLevelSource() const; virtual ChunkStorage *createStorage(File dir); diff --git a/Minecraft.World/Level/LevelChunk.h b/Minecraft.World/Level/LevelChunk.h index f7d208273..72aeb04f2 100644 --- a/Minecraft.World/Level/LevelChunk.h +++ b/Minecraft.World/Level/LevelChunk.h @@ -152,7 +152,7 @@ public: LevelChunk(Level *level, int x, int z); LevelChunk(Level *level, byteArray blocks, int x, int z); LevelChunk(Level *level, int x, int z, LevelChunk *lc); - ~LevelChunk(); + virtual ~LevelChunk(); virtual bool isAt(int x, int z); diff --git a/Minecraft.World/Level/LevelData.h b/Minecraft.World/Level/LevelData.h index ac5148164..8e8cb77a8 100644 --- a/Minecraft.World/Level/LevelData.h +++ b/Minecraft.World/Level/LevelData.h @@ -71,6 +71,7 @@ protected: virtual void setTagData(CompoundTag *tag); // 4J - removed CompoundTag *playerTag public: + virtual ~LevelData(){} virtual __int64 getSeed(); virtual int getXSpawn(); virtual int getYSpawn(); diff --git a/Minecraft.World/Level/Storage/LevelStorage.h b/Minecraft.World/Level/Storage/LevelStorage.h index 4212eaf32..1ed3f5b34 100644 --- a/Minecraft.World/Level/Storage/LevelStorage.h +++ b/Minecraft.World/Level/Storage/LevelStorage.h @@ -18,6 +18,7 @@ public: static const std::wstring NETHER_FOLDER; static const std::wstring ENDER_FOLDER; + virtual ~LevelStorage(){} virtual LevelData *prepareLevel() = 0; virtual void checkSession() = 0; virtual ChunkStorage *createChunkStorage(Dimension *dimension) = 0; diff --git a/Minecraft.World/Level/Storage/MapItemSavedData.cpp b/Minecraft.World/Level/Storage/MapItemSavedData.cpp index c0ee9b024..ae98d8698 100644 --- a/Minecraft.World/Level/Storage/MapItemSavedData.cpp +++ b/Minecraft.World/Level/Storage/MapItemSavedData.cpp @@ -123,7 +123,7 @@ charArray MapItemSavedData::HoldingPlayer::nextUpdatePacket(std::shared_ptr servPlayer = std::dynamic_pointer_cast(player); for (int d = 0; d < 10; d++) diff --git a/Minecraft.World/Level/Storage/PlayerIO.h b/Minecraft.World/Level/Storage/PlayerIO.h index 2de00aeeb..141fb6b0a 100644 --- a/Minecraft.World/Level/Storage/PlayerIO.h +++ b/Minecraft.World/Level/Storage/PlayerIO.h @@ -19,4 +19,4 @@ public: virtual void saveMapIdLookup() = 0; virtual void deleteMapFilesForPlayer(std::shared_ptr player) = 0; virtual void saveAllCachedData() = 0; -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Level/Storage/SavedData.h b/Minecraft.World/Level/Storage/SavedData.h index b81956cd4..37e9f2579 100644 --- a/Minecraft.World/Level/Storage/SavedData.h +++ b/Minecraft.World/Level/Storage/SavedData.h @@ -15,6 +15,7 @@ private: public: SavedData(const std::wstring& id); + virtual ~SavedData(){} virtual void load(CompoundTag *tag) = 0; virtual void save(CompoundTag *tag) = 0; @@ -22,4 +23,4 @@ public: void setDirty(); void setDirty(bool dirty); bool isDirty(); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Network/Packets/AwardStatPacket.cpp b/Minecraft.World/Network/Packets/AwardStatPacket.cpp index efa503b9b..3ec3113a0 100644 --- a/Minecraft.World/Network/Packets/AwardStatPacket.cpp +++ b/Minecraft.World/Network/Packets/AwardStatPacket.cpp @@ -16,7 +16,13 @@ AwardStatPacket::AwardStatPacket(int statId, int count) { this->statId = statId; - this->m_paramData.data = (uint8_t *) new int(count); + // 4jcraft, changed from (uint8_t*) new int(count); to: + // new uint8_t[sizeof(int)]; + // and memcpy of the integer into the array + // reason: operator missmatch, array is deleted with delete[] + // and typesafety + this->m_paramData.data = new uint8_t[sizeof(int)]; + memcpy(this->m_paramData.data, &count, sizeof(int)); this->m_paramData.length = sizeof(int); } @@ -30,7 +36,7 @@ AwardStatPacket::~AwardStatPacket() { if (m_paramData.data != NULL) { - delete [] m_paramData.data; + delete[] m_paramData.data; m_paramData.data = NULL; } } diff --git a/Minecraft.World/Network/Packets/Packet.h b/Minecraft.World/Network/Packets/Packet.h index 57e420d3d..20a3bfb04 100644 --- a/Minecraft.World/Network/Packets/Packet.h +++ b/Minecraft.World/Network/Packets/Packet.h @@ -32,7 +32,7 @@ public: const int id; public: - PacketStatistics(int id) : id( id ), count( 0 ), totalSize( 0 ), samplesPos( 0 ), firstSampleTime( 0 ) { countSamples[0] = 0; sizeSamples[0] = 0; } + PacketStatistics(int id) : count( 0 ), totalSize( 0 ), samplesPos( 0 ), firstSampleTime( 0 ), id( id ) { countSamples[0] = 0; sizeSamples[0] = 0; } void addPacket(int bytes); int getCount(); double getAverageSize(); @@ -61,6 +61,7 @@ public: const __int64 createTime; Packet(); + virtual ~Packet(){} static std::shared_ptr getPacket(int id); @@ -110,4 +111,4 @@ public: protected: static void writeNbt(CompoundTag *tag, DataOutputStream *dos); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/Network/Packets/PacketListener.h b/Minecraft.World/Network/Packets/PacketListener.h index 1fb81e19d..766e96f58 100644 --- a/Minecraft.World/Network/Packets/PacketListener.h +++ b/Minecraft.World/Network/Packets/PacketListener.h @@ -106,6 +106,7 @@ class GameCommandPacket; class PacketListener { public: + virtual ~PacketListener(){} virtual bool isServerPacketListener() = 0; virtual void handleBlockRegionUpdate(std::shared_ptr packet); virtual void onUnhandledPacket(std::shared_ptr packet); diff --git a/Minecraft.World/Network/Packets/RemoveEntitiesPacket.cpp b/Minecraft.World/Network/Packets/RemoveEntitiesPacket.cpp index a007849a2..9207ca8bf 100644 --- a/Minecraft.World/Network/Packets/RemoveEntitiesPacket.cpp +++ b/Minecraft.World/Network/Packets/RemoveEntitiesPacket.cpp @@ -16,7 +16,7 @@ RemoveEntitiesPacket::RemoveEntitiesPacket(intArray ids) RemoveEntitiesPacket::~RemoveEntitiesPacket() { - delete ids.data; + delete[] ids.data; //4jcraft, changed to [] } void RemoveEntitiesPacket::read(DataInputStream *dis) //throws IOException diff --git a/Minecraft.World/Util/AABB.cpp b/Minecraft.World/Util/AABB.cpp index b768f76f6..3dc459497 100644 --- a/Minecraft.World/Util/AABB.cpp +++ b/Minecraft.World/Util/AABB.cpp @@ -12,14 +12,14 @@ AABB::ThreadStorage *AABB::tlsDefault = NULL; AABB::ThreadStorage::ThreadStorage() { - pool = new AABB[POOL_SIZE]; + pool = new AABB[POOL_SIZE]; //4jcraft, needs to be deleted with delete[] poolPointer = 0; } AABB::ThreadStorage::~ThreadStorage() { - delete pool; + delete[] pool; //4jcraft, changed to [] } void AABB::CreateNewThreadStorage() diff --git a/Minecraft.World/Util/Icon.h b/Minecraft.World/Util/Icon.h index fa606ff48..c77fba2c9 100644 --- a/Minecraft.World/Util/Icon.h +++ b/Minecraft.World/Util/Icon.h @@ -16,6 +16,8 @@ public: static const int IS_ALPHA_CUT_OUT = 4; #endif + virtual ~Icon() {} // added by 4jcraft, needed for abstract class + virtual int getX() const = 0; virtual int getY() const = 0; virtual int getWidth() const = 0; diff --git a/Minecraft.World/WorldGen/Biomes/BiomeDecorator.h b/Minecraft.World/WorldGen/Biomes/BiomeDecorator.h index 01560045a..480def9dd 100644 --- a/Minecraft.World/WorldGen/Biomes/BiomeDecorator.h +++ b/Minecraft.World/WorldGen/Biomes/BiomeDecorator.h @@ -24,6 +24,8 @@ protected: public: BiomeDecorator(Biome *biome); + virtual ~BiomeDecorator(){} + void decorate(Level *level, Random *random, int xo, int zo); @@ -72,4 +74,4 @@ protected: void decorateDepthSpan(int count, Feature *feature, int y0, int y1); void decorateDepthAverage(int count, Feature *feature, int yMid, int ySpan); void decorateOres(); -}; \ No newline at end of file +}; diff --git a/Minecraft.World/WorldGen/Biomes/BiomeSource.cpp b/Minecraft.World/WorldGen/Biomes/BiomeSource.cpp index f5c142e12..3a77b436d 100644 --- a/Minecraft.World/WorldGen/Biomes/BiomeSource.cpp +++ b/Minecraft.World/WorldGen/Biomes/BiomeSource.cpp @@ -218,7 +218,7 @@ void BiomeSource::getBiomeBlock(BiomeArray& biomes, int x, int z, int w, int h, { BiomeArray tmp = cache->getBiomeBlockAt(x, z); System::arraycopy(tmp, 0, &biomes, 0, w * h); - delete tmp.data; // MGH - added, the caching creates this array from the indices now. + delete[] tmp.data; // MGH - added, the caching creates this array from the indices now. //4jcraft made it array delete //return biomes; } @@ -635,4 +635,4 @@ bool BiomeSource::getIsMatch(float *frac) // Consider as suitable if we've got all the critical ones, and in total 9 or more - currently there's 8 critical so this just forces at least 1 more others return ( typeCount >= 9 ); -} \ No newline at end of file +} diff --git a/Minecraft.World/WorldGen/Biomes/BiomeSource.h b/Minecraft.World/WorldGen/Biomes/BiomeSource.h index 550531fa9..a85908934 100644 --- a/Minecraft.World/WorldGen/Biomes/BiomeSource.h +++ b/Minecraft.World/WorldGen/Biomes/BiomeSource.h @@ -40,7 +40,7 @@ public: #else static __int64 findSeed(LevelType *generator); // 4J added #endif - ~BiomeSource(); + virtual ~BiomeSource(); public: std::vector getPlayerSpawnBiomes() { return playerSpawnBiomes; } diff --git a/Minecraft.World/WorldGen/Features/HouseFeature.cpp b/Minecraft.World/WorldGen/Features/HouseFeature.cpp index 8fb59910a..dc72d33d8 100644 --- a/Minecraft.World/WorldGen/Features/HouseFeature.cpp +++ b/Minecraft.World/WorldGen/Features/HouseFeature.cpp @@ -7,9 +7,9 @@ bool HouseFeature::place(Level *level, Random *random, int x, int y, int z) { - while (y > 0 && !level->getMaterial(x, y - 1, z)->blocksMotion()) + while (y > 0 && !level->getMaterial(x, y - 1, z)->blocksMotion()) { y--; - + } int w = random->nextInt(7) + 7; int h = 4 + random->nextInt(3) / 2; int d = random->nextInt(7) + 7; @@ -190,4 +190,4 @@ bool HouseFeature::place(Level *level, Random *random, int x, int y, int z) return true; -} \ No newline at end of file +} diff --git a/Minecraft.World/WorldGen/Features/LakeFeature.cpp b/Minecraft.World/WorldGen/Features/LakeFeature.cpp index c70939596..ad07da9d4 100644 --- a/Minecraft.World/WorldGen/Features/LakeFeature.cpp +++ b/Minecraft.World/WorldGen/Features/LakeFeature.cpp @@ -13,8 +13,9 @@ bool LakeFeature::place(Level *level, Random *random, int x, int y, int z) { x -= 8; z -= 8; - while (y > 5 && level->isEmptyTile(x, y, z)) + while (y > 5 && level->isEmptyTile(x, y, z)) { y--; + } if (y <= 4) { return false; @@ -172,4 +173,4 @@ bool LakeFeature::place(Level *level, Random *random, int x, int y, int z) } return true; -} \ No newline at end of file +} diff --git a/Minecraft.World/WorldGen/Features/LargeFeature.h b/Minecraft.World/WorldGen/Features/LargeFeature.h index 0bbce2c92..b35fc566b 100644 --- a/Minecraft.World/WorldGen/Features/LargeFeature.h +++ b/Minecraft.World/WorldGen/Features/LargeFeature.h @@ -14,10 +14,10 @@ protected: public: LargeFeature(); - ~LargeFeature(); + virtual ~LargeFeature(); virtual void apply(ChunkSource *ChunkSource, Level *level, int xOffs, int zOffs, byteArray blocks); protected: virtual void addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) {} -}; \ No newline at end of file +}; diff --git a/Minecraft.World/WorldGen/Features/TreeFeature.h b/Minecraft.World/WorldGen/Features/TreeFeature.h index e29c0b0c3..c58f72d9e 100644 --- a/Minecraft.World/WorldGen/Features/TreeFeature.h +++ b/Minecraft.World/WorldGen/Features/TreeFeature.h @@ -5,9 +5,9 @@ class TreeFeature : public Feature { private: const int baseHeight; - const bool addJungleFeatures; const int trunkType; const int leafType; + const bool addJungleFeatures; public: TreeFeature(bool doUpdate); diff --git a/Minecraft.World/WorldGen/Layers/BiomeOverrideLayer.cpp b/Minecraft.World/WorldGen/Layers/BiomeOverrideLayer.cpp index 436cdc5ae..eefe26b4d 100644 --- a/Minecraft.World/WorldGen/Layers/BiomeOverrideLayer.cpp +++ b/Minecraft.World/WorldGen/Layers/BiomeOverrideLayer.cpp @@ -22,7 +22,7 @@ BiomeOverrideLayer::BiomeOverrideLayer(int seedMixup) : Layer(seedMixup) #endif if( file == INVALID_HANDLE_VALUE ) { - DWORD error = GetLastError(); + // DWORD error = GetLastError(); //assert(false); app.DebugPrintf("Biome override not found, using plains as default\n"); @@ -78,4 +78,4 @@ intArray BiomeOverrideLayer::getArea(int xo, int yo, int w, int h) } } return result; -} \ No newline at end of file +} diff --git a/Minecraft.World/WorldGen/Layers/Layer.h b/Minecraft.World/WorldGen/Layers/Layer.h index 3afe13acc..2104d219d 100644 --- a/Minecraft.World/WorldGen/Layers/Layer.h +++ b/Minecraft.World/WorldGen/Layers/Layer.h @@ -24,6 +24,7 @@ public: static LayerArray getDefaultLayers(__int64 seed, LevelType *levelType); Layer(__int64 seedMixup); + virtual ~Layer(){} virtual void init(__int64 seed); virtual void initRandom(__int64 x, __int64 y); @@ -33,4 +34,4 @@ protected: public: virtual intArray getArea(int xo, int yo, int w, int h) = 0; -}; \ No newline at end of file +}; diff --git a/Minecraft.World/WorldGen/Noise/Synth.h b/Minecraft.World/WorldGen/Noise/Synth.h index 74e686342..033632cf4 100644 --- a/Minecraft.World/WorldGen/Noise/Synth.h +++ b/Minecraft.World/WorldGen/Noise/Synth.h @@ -3,6 +3,7 @@ class Synth { public: virtual double getValue(double x, double y) = 0; + virtual ~Synth(){} doubleArray create(int width, int height); }; diff --git a/Minecraft.World/WorldGen/Sources/TheEndLevelRandomLevelSource.cpp b/Minecraft.World/WorldGen/Sources/TheEndLevelRandomLevelSource.cpp index 63bfa9837..7280ea617 100644 --- a/Minecraft.World/WorldGen/Sources/TheEndLevelRandomLevelSource.cpp +++ b/Minecraft.World/WorldGen/Sources/TheEndLevelRandomLevelSource.cpp @@ -188,7 +188,8 @@ LevelChunk *TheEndLevelRandomLevelSource::getChunk(int xOffs, int zOffs) levelChunk->recalcHeightmap(); //delete blocks.data; // Don't delete the blocks as the array data is actually owned by the chunk now - delete biomes.data; + //4jcraft changed to [] + delete[] biomes.data; return levelChunk; } diff --git a/Minecraft.World/WorldGen/Structures/StrongholdPieces.h b/Minecraft.World/WorldGen/Structures/StrongholdPieces.h index b73a89e12..d9779d6a8 100644 --- a/Minecraft.World/WorldGen/Structures/StrongholdPieces.h +++ b/Minecraft.World/WorldGen/Structures/StrongholdPieces.h @@ -39,6 +39,7 @@ private: int maxPlaceCount; PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount); + virtual ~PieceWeight(){} virtual bool doPlace(int depth); bool isValid(); }; diff --git a/README.md b/README.md index d77b02b2c..f09aa64e7 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ At the moment, we're aiming to support the following platforms: - Android (not started) > [!WARNING] -> There NO Windows support, for that, go to [smartcmd/MinecraftConsoles](https://github.com/smartcmd/MinecraftConsoles/). +> There is NO Windows support, for that, go to [smartcmd/MinecraftConsoles](https://github.com/smartcmd/MinecraftConsoles/). > All efforts are focused towards a native Linux port, OpenGL rendering pipeline, and modernizing the existing LCE codebase/tooling to make future platform ports easier. > @@ -38,26 +38,19 @@ At the moment, we're aiming to support the following platforms: Install the following packages before building (Debian/Ubuntu names shown): ```bash -sudo apt install \ - build-essential cmake \ - libglfw3-dev libgl-dev libglu1-mesa-dev \ - libopenal-dev libvorbis-dev \ - libpng-dev libpthread-stubs0-dev +sudo apt-get install -y build-essential libsdl2-dev libgl-dev libglu1-mesa-dev libpthread-stubs0-dev ``` #### Arch/Manjaro ```bash -sudo pacman -S base-devel gcc pkgconf cmake glfw-x11 mesa openal libvorbis glu +sudo pacman -S base-devel gcc pkgconf cmake sdl2-compat mesa glu ``` -> [!TIP] -> If you are on wayland, you may swap `glfw-x11` to `glfw-wayland` for native wayland windowing instead of xwayland. - #### Fedora/Red Hat/Nobara ```bash -sudo dnf in gcc gcc-c++ make cmake glfw-devel mesa-libGL-devel mesa-libGLU-devel openal-soft-devel libvorbis-devel libpng-devel openssl-devel +sudo dnf in gcc gcc-c++ make cmake SDL2-devel mesa-libGL-devel mesa-libGLU-devel openssl-devel ``` #### Docker diff --git a/flake.nix b/flake.nix index 9897d7fc6..dc9acfbb7 100644 --- a/flake.nix +++ b/flake.nix @@ -21,19 +21,15 @@ { devShells = forAllSystems ({ pkgs }: let - libs = with pkgs; [ + libs = with pkgs; [ openssl.dev libGL libGLU - glfw - libpng + sdl2 zlib - openal - libvorbis ]; packages = with pkgs; [ - python3 - gcc15 + clang lld cmake gnumake diff --git a/meson.build b/meson.build index fbec8dca4..90f4e8988 100644 --- a/meson.build +++ b/meson.build @@ -16,10 +16,9 @@ cc = meson.get_compiler('cpp') # system deps gl_dep = dependency('gl') glu_dep = dependency('glu') -glfw_dep = dependency('glfw3') -png_dep = dependency('libpng') +sdl2_dep = dependency('sdl2') # Yes.. i know sdl3 is out, but there's not point upgrading right now except when + # someone is gonna ask me "Hey juicey can you make it SDL3?" and i'd be like fuck you and still do it. thread_dep = dependency('threads') -dl_dep = cc.find_library('dl') # compile flags (chagne ts juicey) global_cpp_args = [ @@ -56,4 +55,4 @@ subdir('4J.Profile') subdir('4J.Storage') subdir('Minecraft.Assets') subdir('Minecraft.World') -subdir('Minecraft.Client') \ No newline at end of file +subdir('Minecraft.Client')