Merge branch 'dev' into feat/restore-java-gui

This commit is contained in:
Tropical 2026-03-10 21:02:58 -05:00
commit cf3defee35
76 changed files with 813 additions and 1051 deletions

View file

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

View file

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

View file

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

2
.gitignore vendored
View file

@ -29,7 +29,7 @@ meson-logs/
*.out
*.d
compile_commands.json
.clangd
# ----- Scratch / legacy -----

View file

@ -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 <GLFW/glfw3.h>
#include "../4J.Render/4J_Render.h"
#include <SDL2/SDL.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
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;
}
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(){}

View file

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

View file

@ -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('.'),
)

View file

@ -1,14 +1,11 @@
// TODO: ADD BETTER COMMENTS.
#include "4J_Render.h"
#include <cstring>
#include <cstdlib> // getenv
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
#include <GLFW/glfw3.h>
#include <SDL2/SDL.h>
#include <cstdio>
#include <cmath>
#include <pthread.h>
@ -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<float>(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;

View file

@ -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',
],

View file

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

View file

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

View file

@ -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<<MINECRAFT_ACTION_ACTION)))
@ -3422,7 +3420,8 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
}
if ( (player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_PAUSEMENU))
#ifdef _DURANGO
#ifdef _DURANGO
|| (player->ullButtonsPressed&(1LL<<ACTION_MENU_GTC_PAUSE))
#endif
)
@ -3442,6 +3441,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
__uint64 ullButtonsPressed=player->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<<MINECRAFT_ACTION_DROP)) )
{
std::wstring itemName = L"";
@ -3512,7 +3520,14 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
int wheel = Mouse.getEventDWheel();
if (wheel != 0) {
player->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;

View file

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

View file

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

View file

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

View file

@ -27,6 +27,7 @@ protected:
public:
GameRuleDefinition();
virtual ~GameRuleDefinition(){}
virtual ConsoleGameRules::EGameRuleType getActionType() = 0;

View file

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

View file

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

View file

@ -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);
};
};

View file

@ -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<m_iTilesCount;i++)
{
@ -65,4 +66,4 @@ bool LookAtTileHint::onLookAt(int id,int iData)
}
}
return false;
}
}

View file

@ -16,7 +16,8 @@ private:
public:
LookAtTileHint(eTutorial_Hint id, Tutorial *tutorial, int tiles[], unsigned int tilesLength, int iconOverride = -1, int iData=-1, int iDataOverride = -1);
~LookAtTileHint();
//TODO: 4jcraft, added, destructor was never implemented
~LookAtTileHint(){};
virtual bool onLookAt(int id, int iData=0);
};
};

View file

@ -13,7 +13,8 @@ private:
public:
TakeItemHint(eTutorial_Hint id, Tutorial *tutorial, int items[], unsigned int itemsLength);
~TakeItemHint();
//TODO: 4jcraft, added, it was never implemented
virtual ~TakeItemHint(){};
virtual bool onTake( std::shared_ptr<ItemInstance> item );
};
};

View file

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

View file

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

View file

@ -10,7 +10,7 @@
#include <GL/gl.h>
#include <GL/glext.h>
#include <GLFW/glfw3.h>
#include <SDL2/SDL.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
@ -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) \
/* <end> */
/* 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) \
/* <end> */
#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);
}

View file

@ -32,6 +32,8 @@ void CConsoleMinecraftApp::ExitGame()
}
void CConsoleMinecraftApp::FatalLoadError()
{
app.DebugPrintf("CConsoleMinecraftApp::FatalLoadError - asserting 0 and dying...\n");
assert(0);
}
void CConsoleMinecraftApp::CaptureSaveThumbnail()

View file

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

View file

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

View file

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

View file

@ -19,6 +19,7 @@ public:
int texHeight;
Model(); // 4J added
virtual ~Model(){}
virtual void render(std::shared_ptr<Entity> 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> mob, float time, float r, float a) {}

View file

@ -4,5 +4,6 @@ class BufferedImage;
class MemTextureProcessor
{
public:
virtual ~MemTextureProcessor(){}
virtual BufferedImage *process(BufferedImage *read) = 0;
};
};

View file

@ -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();

View file

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

View file

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

View file

@ -86,4 +86,4 @@ public:
void setFlags(int flags); // 4J added
virtual void freeFrameTextures(); // 4J added
virtual bool hasOwnData(); // 4J Added
};
};

View file

@ -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);
}
}

View file

@ -1,5 +1,4 @@
#pragma once
#include "MemoryTracker.h"
class ByteBuffer;
class IntBuffer;
class FloatBuffer;

View file

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

View file

@ -12,7 +12,9 @@ private:
public:
JumpControl(Mob *mob);
virtual ~JumpControl(){}
void jump();
//genuinly, why tf is this VIRTUAL
virtual void tick();
};
};

View file

@ -15,6 +15,7 @@ private:
public:
LookControl(Mob *mob);
virtual ~LookControl(){}
void setLookAt(std::shared_ptr<Entity> 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();
};
};

View file

@ -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);
};
};

View file

@ -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> player) = 0;
virtual void startOpen() = 0;
virtual void stopOpen() = 0;
};
};

View file

@ -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<ItemInstance> getItem(unsigned int slot);
@ -29,4 +29,4 @@ public:
void startOpen() { } // TODO Auto-generated method stub
void stopOpen() { } // TODO Auto-generated method stub
};
};

View file

@ -7,6 +7,7 @@ class Player;
class Merchant
{
public:
virtual ~Merchant(){}
virtual void setTradingPlayer(std::shared_ptr<Player> player) = 0;
virtual std::shared_ptr<Player> getTradingPlayer() = 0;
virtual MerchantRecipeList *getOffers(std::shared_ptr<Player> forPlayer) = 0;
@ -14,4 +15,4 @@ public:
virtual void notifyTrade(MerchantRecipe *activeRecipe) = 0;
virtual void notifyTradeUpdated(std::shared_ptr<ItemInstance> item) = 0;
virtual int getDisplayName() = 0;
};
};

View file

@ -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<ItemInstance> getItem(unsigned int slot);
@ -23,4 +24,4 @@ public:
void startOpen() { } // TODO Auto-generated method stub
void stopOpen() { } // TODO Auto-generated method stub
};
};

View file

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

View file

@ -63,7 +63,7 @@ private:
ItemInstance() { _init(-1,0,0); }
public:
~ItemInstance();
virtual ~ItemInstance();
std::shared_ptr<ItemInstance> remove(int count);
Item *getItem() const;
@ -151,4 +151,4 @@ public:
int getBaseRepairCost();
void setRepairCost(int cost);
};
};

View file

@ -342,6 +342,6 @@ std::shared_ptr<Packet> MapItem::getUpdatePacket(std::shared_ptr<ItemInstance> i
if (data.data == NULL || data.length == 0) return nullptr;
std::shared_ptr<Packet> retval = std::shared_ptr<Packet>(new ComplexItemDataPacket((short) Item::map->id, (short) itemInstance->getAuxValue(), data));
delete data.data;
delete[] data.data; //4jcraft, changed to []
return retval;
}

View file

@ -28,7 +28,7 @@ protected:
public:
Dimension();
~Dimension();
virtual ~Dimension();
virtual ChunkSource *createRandomLevelSource() const;
virtual ChunkSource *createFlatLevelSource() const;
virtual ChunkStorage *createStorage(File dir);

View file

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

View file

@ -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();

View file

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

View file

@ -123,7 +123,7 @@ charArray MapItemSavedData::HoldingPlayer::nextUpdatePacket(std::shared_ptr<Item
memcpy(lastSentDecorations.data, data.data, data.length);
return data;
}
delete data.data;
delete[] data.data; //4jcraft, changed to []
}
std::shared_ptr<ServerPlayer> servPlayer = std::dynamic_pointer_cast<ServerPlayer>(player);
for (int d = 0; d < 10; d++)

View file

@ -19,4 +19,4 @@ public:
virtual void saveMapIdLookup() = 0;
virtual void deleteMapFilesForPlayer(std::shared_ptr<Player> player) = 0;
virtual void saveAllCachedData() = 0;
};
};

View file

@ -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();
};
};

View file

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

View file

@ -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<Packet> getPacket(int id);
@ -110,4 +111,4 @@ public:
protected:
static void writeNbt(CompoundTag *tag, DataOutputStream *dos);
};
};

View file

@ -106,6 +106,7 @@ class GameCommandPacket;
class PacketListener
{
public:
virtual ~PacketListener(){}
virtual bool isServerPacketListener() = 0;
virtual void handleBlockRegionUpdate(std::shared_ptr<BlockRegionUpdatePacket> packet);
virtual void onUnhandledPacket(std::shared_ptr<Packet> packet);

View file

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

View file

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

View file

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

View file

@ -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();
};
};

View file

@ -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 );
}
}

View file

@ -40,7 +40,7 @@ public:
#else
static __int64 findSeed(LevelType *generator); // 4J added
#endif
~BiomeSource();
virtual ~BiomeSource();
public:
std::vector<Biome *> getPlayerSpawnBiomes() { return playerSpawnBiomes; }

View file

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

View file

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

View file

@ -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) {}
};
};

View file

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

View file

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

View file

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

View file

@ -3,6 +3,7 @@ class Synth
{
public:
virtual double getValue(double x, double y) = 0;
virtual ~Synth(){}
doubleArray create(int width, int height);
};

View file

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

View file

@ -39,6 +39,7 @@ private:
int maxPlaceCount;
PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount);
virtual ~PieceWeight(){}
virtual bool doPlace(int depth);
bool isValid();
};

View file

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

View file

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

View file

@ -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')
subdir('Minecraft.Client')