139 Commits

Author SHA1 Message Date
mschiller890
e0dac8a95c maybe manual caching will be better 2026-03-19 21:37:50 +02:00
mschiller890
1cd73cfc1e hmmmmmmmmmmmmmmmmmmmm... 2026-03-19 21:30:33 +02:00
mschiller890
c1fe428aa3 where are you hiding, r14b NDK 2026-03-19 21:25:44 +02:00
mschiller890
24d3b9488d improve Android build job with cached NDK script 2026-03-19 21:20:15 +02:00
mschiller890
f3f0918e77 SHITSHITSHIT 2026-03-19 20:39:30 +02:00
mschiller890
e190335abe Hopefully added Android building to the workflow
please work
2026-03-19 20:36:41 +02:00
InviseDivine
402b053432 wtf 2026-03-19 20:02:15 +02:00
Kolyah35
0964e3ea4b fix release att 1 2026-03-19 20:57:01 +03:00
Kolyah35
0dc8deac93 fuck i dumbass 2026-03-19 20:32:22 +03:00
Kolyah35
13280cb8a7 fix artifacts att 3 2026-03-19 20:16:04 +03:00
Kolyah35
11117cd4f6 fix artifacts att 2 2026-03-19 19:46:58 +03:00
Kolyah35
78d218ccb1 fix build att 6 2026-03-19 19:31:52 +03:00
Kolyah35
a72c2c4094 FIX: windows build ig 2026-03-19 19:12:00 +03:00
Kolyah35
193f63893d REMOVE: png server dependency 2026-03-19 19:09:40 +03:00
Kolyah35
bb181ca838 AAAAH 2026-03-19 18:59:05 +03:00
Kolyah35
eadbe78f6b -_- 2026-03-19 18:58:00 +03:00
Kolyah35
bfc796b59f oh fu 2026-03-19 18:55:17 +03:00
Kolyah35
04d892c926 ADD: github actions 2026-03-19 18:53:13 +03:00
Kolyah35
e469e03366 REMOVE: all build actions 2026-03-19 17:58:48 +03:00
Kolyah35
ca2af5edb4 ADD: fire (and reduce options writings) 2026-03-19 17:55:22 +03:00
Kolyah35
e49f58bc89 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-19 02:27:04 +03:00
Kolyah35
e9914e3fbd ADD: WebASM port (no sound/no network) 2026-03-19 02:26:34 +03:00
InviseDivine
157ef5ff05 FIX: Settings save when leave on escape 2026-03-18 22:50:35 +02:00
Kolyah35
4769d4ae72 minor changes 2026-03-17 23:08:56 +03:00
Kolyah35
d15051aab6 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-17 22:50:18 +03:00
Kolyah35
5ff8b54c4f REMOVE: User class 2026-03-17 22:49:59 +03:00
mschiller890
48e3b11c4e can i get a better error please??? 2026-03-17 21:44:23 +02:00
Kolyah35
2c132d5bc7 cache ndk to avoid downloading and extracting :v 2026-03-17 21:59:19 +03:00
Kolyah35
e0a39fb6c1 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-17 21:59:16 +03:00
Kolyah35
ccac464750 just a comment 2026-03-17 21:53:15 +03:00
mschiller890
11e986bcf2 FIXED: Android build issues, added building to Andr from Linux
I really hope this didnt break anything
Im proud of the bash script
2026-03-17 19:01:27 +01:00
Kolyah35
9d831bdb25 trying to up android build 2026-03-17 00:58:22 +03:00
Kolyah35
7e86e34189 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-17 00:40:49 +03:00
Kolyah35
1ca46fab32 some fixes 2026-03-17 00:40:32 +03:00
InviseDivine
7877301d7f Update .github/workflows/cmake-multiplatform.yml 2026-03-16 23:24:18 +02:00
Kolyah35
b8df42d9bd trying to up actions 2026-03-17 00:20:56 +03:00
InviseDivine
cdada510a0 readme upd 2026-03-16 23:18:44 +02:00
deepfriedwaffles
f3e94f697f Added *.xcuserstate wildcsrd to Xcode ignores 2026-03-16 17:02:34 -04:00
Kolyah35
aaad53761e Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-16 23:18:53 +03:00
Kolyah35
183487853c hopefully fixed blackscreen 🙏 2026-03-16 23:16:16 +03:00
mschiller890
2bc3be3153 FIXED: chat history clears on disconnect 2026-03-16 19:05:55 +01:00
Michal Schiller
997c3f2ebe Added a list of players when in multiplayer (tab list) 2026-03-16 13:34:42 +01:00
Michal Schiller
d3cf64cfdc FIXED: Skins work on Linux
There's still one more issue to this:
other peoples skins in multiplayer show corrupted.
2026-03-16 09:00:36 +01:00
Michal Schiller
babd7b4d96 i fucking FLIPPED the cape textures and fixed issues with options
were the options working for everyone else? am i stupid
2026-03-16 05:19:10 +01:00
InviseDivine
725353eb74 NO_SOUND Define 2026-03-15 22:59:43 +02:00
InviseDivine
c52f5a4393 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-15 22:01:17 +02:00
InviseDivine
df99a29258 FEAT: ifdef CHEATS (temp solution) 2026-03-15 22:01:15 +02:00
InviseDivine
76a5e19e9b Update build instruction 2026-03-15 21:47:57 +02:00
Kolyah35
c7d6289781 FIX: compilation on arm 2026-03-15 21:59:23 +03:00
Kolyah35
a50877af9e ADD: lastip 2026-03-15 20:54:28 +03:00
Kolyah35
fadcf3a7d0 FIX: i fucking wrote profiler just to find that sleep function takes SECONDS arg 😭😭😭😭😭😭😭😭😭😭 2026-03-15 20:35:02 +03:00
Kolyah35
b0fa2b820c REMOVE: debug feature 2026-03-15 18:32:41 +03:00
InviseDivine
c03f535c7e FIX: Nether reactor (by @bravelycowering) 2026-03-14 20:42:38 +02:00
InviseDivine
03ff7b118e settings names fixed 2026-03-14 20:24:28 +02:00
Kolyah35
1f5e1244f2 Merge pull request 'start menu screen overhaul' (#3) from freetolga/minecraft-pe-0.6.1:start-screen-overhaul into main
Reviewed-on: https://192.168.0.2:3000/Kolyah35/minecraft-pe-0.6.1/pulls/3
2026-03-14 17:21:58 +02:00
Kolyah35
0aa94bc56f REMOVE: AI useless code 2026-03-14 18:15:08 +03:00
freetolga
5f612652d9 start menu screen overhaul 2026-03-14 17:57:55 +03:00
Kolyah35
bf1a6d79b4 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-14 14:52:59 +03:00
Kolyah35
e49fe348e3 FIX: override warnings 2026-03-14 14:51:42 +03:00
Kolyah35
bb95e75c47 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-14 14:51:25 +03:00
mschiller890
4e179a47b6 Make chat show full history when opened 2026-03-14 12:22:14 +01:00
Kolyah35
badd59b644 FIX: Rewrite options 2026-03-14 14:13:49 +03:00
mschiller890
76839dfbaa Android build issues fixed
(except i fixed the wrong stuff first...)
2026-03-14 00:34:44 +01:00
mschiller890
9fd54afd61 Fixed creative mode instant mining 2026-03-14 00:08:58 +01:00
mschiller890
eb8caa887e Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 23:56:58 +01:00
mschiller890
97daa795fb Added capes (needs improvement) 2026-03-13 23:56:49 +01:00
InviseDivine
754329fc49 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 23:23:26 +02:00
InviseDivine
5385342272 sprint on ctrl 2026-03-13 23:23:25 +02:00
mschiller890
0db3a547c7 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 22:15:41 +01:00
mschiller890
94f4317b71 Restore cave generation + adjust ore spawn rates 2026-03-13 22:15:30 +01:00
InviseDivine
bf2248063d FEAT: F1 (but why jump doesnt work wtf) 2026-03-13 22:21:53 +02:00
InviseDivine
13dcf593d8 fck 2026-03-13 19:09:12 +02:00
InviseDivine
b547286e53 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 19:08:27 +02:00
InviseDivine
ce5307aa30 FEAT: Tweaks in options 2026-03-13 19:08:27 +02:00
mschiller890
85224c42b7 Skin layers added 2026-03-13 16:56:27 +01:00
mschiller890
450f0d9ec2 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 16:26:28 +01:00
mschiller890
12d5835711 Watch out! Skins! 2026-03-13 16:26:19 +01:00
InviseDivine
969d6b3ee7 Forgot about view bobick 2026-03-13 17:12:55 +02:00
InviseDivine
b0de432339 FIX: Settings save 2026-03-13 17:09:39 +02:00
InviseDivine
6f7812293e settings almost fixed 2026-03-13 15:57:16 +02:00
mschiller890
37e28d0fcc added a username label to the title screen 2026-03-13 13:22:47 +01:00
mschiller890
954ec6e505 Game now actually pauses when in a local world and when the server is set to be invisible. 2026-03-13 11:25:20 +01:00
mschiller890
b1cd6c6581 Added a dummy cheats toggle to the world creation screen. 2026-03-13 11:04:58 +01:00
mschiller890
248e9cb69a removed survival kit thing, go mining 2026-03-13 09:22:38 +01:00
mschiller890
caedc293eb Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 08:23:20 +01:00
mschiller890
2e9a9b810c Limit username to 12 chars and adjusted the Done button to go more with the rest of the games UI. 2026-03-13 08:22:54 +01:00
mschiller890
ce4c3e9d93 Update README.md 2026-03-13 09:05:59 +02:00
mschiller890
470509ee52 Add "Quit Game" button 2026-03-12 21:42:20 +01:00
mschiller890
0ea8b87970 Prevent duplicate world IDs by loading existing level list before generating a unique name 2026-03-12 21:31:01 +01:00
mschiller890
b4f54083dc Fixed door destroy logic 2026-03-12 19:17:32 +01:00
Michal Schiller
f17a11c670 Added mouse wheel support to the world selection screen. 2026-03-12 11:02:06 +01:00
mschiller890
adb23d18c6 Update README.md 2026-03-11 20:41:15 +02:00
mschiller890
4b6039d8a4 Added JoinByIPScreen.cpp to the source list 2026-03-11 20:16:35 +02:00
mschiller890
1e908423d5 Replaced std::stoi(port) with atoi(port.c_str()) call because of Android NDK 2026-03-11 20:15:15 +02:00
InviseDivine
4bd3821ff6 Update project/dedicated_server/CMakeLists.txt
change to yours
2026-03-11 19:55:38 +02:00
InviseDivine
28a49debcf Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-11 19:52:59 +02:00
InviseDivine
d2a5f4755c remove std stoi 2026-03-11 19:52:25 +02:00
mschiller890
7f3af5c98a Implemented openURL for android and updated init logic 2026-03-11 19:40:13 +02:00
mschiller890
d82d19be68 Updated the Discord link (and removed color tags cuz they were messing up the URL) 2026-03-11 19:38:53 +02:00
mschiller890
33590751c5 Added openURL(String) helper 2026-03-11 19:37:10 +02:00
mschiller890
a80d2ee847 Fix NPE in MainActivity.onDialogCompleted by guarding showSoftInput call with null focus check 2026-03-11 19:10:08 +02:00
InviseDivine
8875342557 Join by ip screen 2026-03-11 19:04:54 +02:00
InviseDivine
933ef9c988 Update README.md 2026-03-11 15:54:33 +02:00
mschiller890
09d28be195 Updated Android build version from 0.4.0 to 0.6.1-alpha-<build> 2026-03-11 12:49:04 +02:00
mschiller890
ffd9dda611 Upload files to "project/android" 2026-03-11 12:47:57 +02:00
mschiller890
6ed2d40edc Update build.ps1 2026-03-11 12:46:16 +02:00
mschiller890
ce6a987651 Game now asks for storage permission during runtime 2026-03-11 12:31:51 +02:00
mschiller890
23cdc15285 Bumped minSdk to 24 2026-03-11 12:27:36 +02:00
mschiller890
904bf68cd6 Bumped minSdk to 24 2026-03-11 12:27:11 +02:00
mschiller890
e529bd5d64 Fixed Done button not working and backspace on Android 2026-03-11 12:21:09 +02:00
mschiller890
099b560273 oopsie 2026-03-11 12:19:48 +02:00
mschiller890
2d70b68b73 Fixed Done button not working and backspace on Android 2026-03-11 11:03:06 +02:00
mschiller890
01f78eabc7 Upload files to "src" 2026-03-11 11:01:29 +02:00
Kolyah35
99164a781d whoops 2026-03-11 02:30:38 +03:00
Kolyah35
d25a04f154 REMOVE: license verification and BuyGame btns/screens 2026-03-11 00:39:27 +03:00
Kolyah35
3c71139a7c FIX: human readable world date 2026-03-10 23:58:20 +03:00
Kolyah35
9991ba312d FIX: improve textbox 2026-03-10 23:36:12 +03:00
Kolyah35
11d5551d02 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-10 23:27:15 +03:00
Kolyah35
d0939875fc FIX: improve create world screen 2026-03-10 23:26:02 +03:00
InviseDivine
da1906f94b Fix: linux open links 2026-03-10 22:14:39 +02:00
InviseDivine
04f13ab4a7 Fix: gui, block destroy
Feat: speed up on left mouse button in credits
2026-03-10 22:06:28 +02:00
InviseDivine
2d17f9d152 Ported to textfield 2026-03-10 21:37:12 +02:00
Kolyah35
ae84705332 Merge pull request 'A lot of stuff.' (#1) from mschiller890/minecraft-pe-0.6.1:alotofstuff into main
Reviewed-on: https://192.168.0.2:3000/Kolyah35/minecraft-pe-0.6.1/pulls/1
2026-03-10 21:07:27 +02:00
mschiller890
12b30c245a Update README.md 2026-03-10 21:00:09 +02:00
mschiller890
7345f68aee Update README.md 2026-03-10 20:59:27 +02:00
mschiller890
311e97bd77 Update README.md 2026-03-10 20:40:41 +02:00
mschiller890
6d43273b18 Update README.md 2026-03-10 20:36:33 +02:00
Michal Schiller
2fc323639a Fixes and enhancements from my MCPE repository. (https://github.com/mschiller890/mcpe64) 2026-03-10 19:31:40 +01:00
Kolyah35
0c97ceb340 TextBox / removed BuyButton / impoved CreateWorldScreen 2026-03-10 02:51:32 +03:00
InviseDivine
65d25748db no sound define 2026-03-09 21:15:55 +02:00
InviseDivine
8a53d3432d Fix: Creative mode flying and cheats enabled 2026-03-09 20:40:07 +02:00
InviseDivine
5311b134ac Fix: Block destroy 2026-03-09 19:14:38 +02:00
InviseDivine
310ff754ee Update README.md 2026-03-09 16:14:47 +02:00
InviseDivine
416253ebc7 Обновить README.md 2026-03-09 15:14:42 +02:00
InviseDivine
0370944cf6 Fix: block building 2026-03-09 15:05:44 +02:00
InviseDivine
6c22f3bc25 Fix: Sounds (now properly) 2026-03-09 14:11:28 +02:00
InviseDivine
d0f6a9b805 Fix: Sounds
Problem: its not working xD
2026-03-09 13:24:11 +02:00
InviseDivine
d0995643a5 Fix: line changing on signs, game launch on AMD gpus, mouse sensitivity
Feat: inv slots changing on keyboard
2026-03-06 22:48:59 +02:00
Kolyah35
f82021117c FIX: MSVC compile and item gui on desktop 2026-03-05 18:01:42 +03:00
186 changed files with 10861 additions and 3561 deletions

27
.github/actions/setup-cache/action.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Setup cache
description: Sets up sccache, CPM cache, etc.
inputs:
host:
description: 'Host platform: win or linux'
required: true
target:
description: 'Target platform: win, linux'
required: true
runs:
using: "composite"
steps:
- name: Setup sccache
uses: hendrikmuhs/ccache-action@v1.2.13
with:
variant: sccache
key: ${{ inputs.target }}-v1
- name: Setup CPM Cache
uses: actions/cache@v4
with:
path: cpm-cache
key: cpm-${{ inputs.target }}-v1-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }}
restore-keys: |
cpm-${{ inputs.target }}-v1-

239
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,239 @@
name: Build Game
on:
workflow_dispatch:
pull_request:
push:
branches:
- '**' # every branch
- '!no-build-**' # unless marked as no-build
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
permissions:
contents: write
jobs:
build-windows:
name: Windows Build
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup caches
uses: ./.github/actions/setup-cache
with:
host: win
target: win
- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: cmake -E make_directory ${{github.workspace}}/build
- name: Configure CMake
shell: powershell
working-directory: ${{github.workspace}}/build
run: cmake $env:GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$env:BUILD_TYPE
- name: Build
working-directory: ${{github.workspace}}/build
shell: powershell
run: cmake --build . --config $env:BUILD_TYPE --target MinecraftPE
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: mcpe-windows
path: |
${{github.workspace}}/build/${{ env.BUILD_TYPE }}/MinecraftPE.exe
${{github.workspace}}/build/${{ env.BUILD_TYPE }}/glfw3.dll
${{github.workspace}}/build/${{ env.BUILD_TYPE }}/libpng16.dll
${{github.workspace}}/build/${{ env.BUILD_TYPE }}/OpenAL32.dll
${{github.workspace}}/build/${{ env.BUILD_TYPE }}/z.dll
build-linux:
name: Linux Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup caches
uses: ./.github/actions/setup-cache
with:
host: linux
target: linux
- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory
# We'll use this as our working directory for all subsequent commands
run: cmake -E make_directory ${{github.workspace}}/build
- name: Setup Environment
run: |
sudo apt-get update -qq
sudo apt-get install gcc-multilib
sudo apt-get install -y --no-install-recommends build-essential libgl-dev libwayland-dev xorg-dev libxkbcommon-dev
- name: Configure CMake
# Use a bash shell so we can use the same syntax for environment variable
# access regardless of the host operating system
shell: bash
working-directory: ${{github.workspace}}/build
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- name: Build
working-directory: ${{github.workspace}}/build
shell: bash
run: cmake --build . --config $BUILD_TYPE
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: mcpe-linux
path: |
${{github.workspace}}/build/MinecraftPE
${{github.workspace}}/build/MinecraftPE-server
build-android: # pray to god
name: Build Android APK
runs-on: ubuntu-latest
env:
ANDROID_SDK_ROOT: ${{ github.workspace }}/android-sdk
# ANDROID_NDK_PATH: ${{ env.ANDROID_NDK_PATH }}
ANDROID_PLATFORM_API: 36
ANDROID_BUILD_TOOLS_VERSION: 36.0.0
ADB: /bin/true
# JAVA_HOME: ${{ env.JAVA_HOME }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Cache Android command-line tools
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/android-sdk/cmdline-tools
key: android-cmdline-tools-v36
- name: Setup Android command line tools
run: |
if [ ! -d "$ANDROID_SDK_ROOT/cmdline-tools/latest" ]; then
mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools"
curl -o cmdline-tools.zip -L "https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip"
unzip -q cmdline-tools.zip -d "$ANDROID_SDK_ROOT/cmdline-tools"
mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest"
fi
yes | "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" --sdk_root="$ANDROID_SDK_ROOT" "platform-tools" "platforms;android-${ANDROID_PLATFORM_API}" "build-tools;${ANDROID_BUILD_TOOLS_VERSION}"
- name: Cache Android NDK r14b
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/android-ndk-r14b
key: android-ndk-r14b
- name: Install Android NDK r14b
run: |
if [ ! -d "$GITHUB_WORKSPACE/android-ndk-r14b" ]; then
curl -L -o ndk.zip "https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip"
unzip -q ndk.zip -d "$GITHUB_WORKSPACE"
fi
echo "ANDROID_NDK_PATH=$GITHUB_WORKSPACE/android-ndk-r14b" >> $GITHUB_ENV
- name: Install system prerequisites
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends wget unzip curl git python3 libncurses6 libtinfo6
if ! ldconfig -p | grep -q "libncurses.so.5"; then
sudo ln -sf /lib/x86_64-linux-gnu/libncurses.so.6 /usr/lib/x86_64-linux-gnu/libncurses.so.5 || true
fi
if ! ldconfig -p | grep -q "libtinfo.so.5"; then
sudo ln -sf /lib/x86_64-linux-gnu/libtinfo.so.6 /usr/lib/x86_64-linux-gnu/libtinfo.so.5 || true
fi
- name: Setup Java 25
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 25
- name: Validate environment
run: |
echo "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT"
echo "ANDROID_NDK_PATH=$ANDROID_NDK_PATH"
echo "JAVA_HOME=$JAVA_HOME"
$ANDROID_SDK_ROOT/platform-tools/adb version || true
java -version
javac -version
- name: Run Android build script
run: |
chmod +x ./build.sh
./build.sh
- name: Upload APK
uses: actions/upload-artifact@v4
with:
name: minecraftpe-apk
path: ${{ github.workspace }}/build-apk/minecraftpe-debug.apk
publish:
name: Publish
runs-on: ubuntu-latest
needs: [ build-windows, build-linux, build-android ]
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Declare Version Variables
id: ref
run: |
echo "version=$(cat VERSION | xargs)" >> $GITHUB_OUTPUT
echo "hash=$(git rev-parse --short "$GITHUB_SHA")" >> $GITHUB_OUTPUT
- name: Download Artifacts
uses: actions/download-artifact@v4
- name: Zip Windows Artifacts
uses: vimtor/action-zip@v1.2
with:
files: ${{github.workspace}}/data/ mcpe-windows/MinecraftPE.exe mcpe-windows/glfw3.dll mcpe-windows/libpng16.dll mcpe-windows/OpenAL32.dll mcpe-windows/z.dll
dest: minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip
- name: Zip Linux Artifacts
uses: vimtor/action-zip@v1.2
with:
files: ${{github.workspace}}/data/ mcpe-linux/MinecraftPE # ye, you should install libraries by urself :trollface:
dest: minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip
- name: Zip Linux Server Artifacts
uses: vimtor/action-zip@v1.2
with:
files: mcpe-linux/MinecraftPE-server
dest: minecraftpe-server-${{ steps.ref.outputs.hash }}.zip
- name: Zip Android Artifact
uses: vimtor/action-zip@v1.2
with:
files: mcpe-apk/minecraftpe-debug.apk
dest: minecraftpe-${{ steps.ref.outputs.hash }}-android.zip
- name: Update Development Release
uses: andelf/nightly-release@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: dev
name: 'Development Release'
body: |
MinecraftPE development release for commit ${{ github.sha }}.
files: |
./minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip
./minecraftpe-server-${{ steps.ref.outputs.hash }}.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-android.zip

205
.gitignore vendored
View File

@@ -1,3 +1,204 @@
# Build output
build/ build/
linux-build/ out/
.cache/ bin/
lib/
build-apk/
cmake-build-*/
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
Makefile
*.cmake
!cmake/CPM.cmake
# Compiled object files
*.o
*.obj
*.a
*.lib
*.so
*.dylib
*.dll
*.exe
*.out
# CMake generated
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_CPack_Packages/
*.cbp
# Visual Studio
*.sdf
*.suo
*.user
*.userosscache
*.sln.docstates
*.VC.db
*.VC.opendb
.vs/
ipch/
x64/
x86/
Debug/
Release/
RelWithDebInfo/
MinSizeRel/
# Xcode
*.xcworkspace
xcuserdata/
*.xccheckout
*.xcuserstate
*.moved-aside
DerivedData/
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
# Android
*.apk
*.aab
*.ap_
local.properties
.gradle/
project/.gradle/
project/android/bin/
project/android/gen/
project/android/obj/
project/android_java/bin/
project/android_java/gen/
project/android_java/obj/
project/android/libs/*.so
# macOS
.DS_Store
.AppleDouble
.LSOverride
._*
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
# Linux
*~
.nfs*
# CLion / JetBrains
.idea/
*.iml
*.ipr
*.iws
# Eclipse CDT
.project
.cproject
.settings/
# Logs
*.log
# Ninja
.ninja_deps
.ninja_log
build.ninja
# VS Code
.vscode/
*.code-workspace
# Visual Studio additional
*.ncb
*.aps
*.pdb
*.ilk
*.exp
*.iobj
*.ipdb
*.tlog
*.lastbuildstate
*.pch
*.ipch
*.VC.db-shm
*.VC.db-wal
*.svclog
*.vcxproj.user
# CMake generated project files
ALL_BUILD.vcxproj
ALL_BUILD.vcxproj.filters
INSTALL.vcxproj
INSTALL.vcxproj.filters
PACKAGE.vcxproj
PACKAGE.vcxproj.filters
ZERO_CHECK.vcxproj
ZERO_CHECK.vcxproj.filters
MinecraftPE.vcxproj
MinecraftPE.vcxproj.filters
MinecraftPE.sln
CPackConfig.cmake
CPackSourceConfig.cmake
cpm-package-lock.cmake
MinecraftPE.dir/
_deps/
# Test / coverage
Testing/
CTestResults/
*.gcno
*.gcda
*.gcov
coverage/
lcov.info
# Precompiled headers
*.gch
# Compiler / linker intermediates
*.map
*.res
*.d
# Patch / diff leftovers
*.orig
*.rej
*.patch
# Backup / temp
*.bak
*.swp
*.swo
*.tmp
*~.nib
# Tags
tags
TAGS
.tags
ctags
# macOS extra
.Spotlight-V100
.Trashes
.fseventsd
Icon\r
# Windows extra
*.lnk
[Dd]esktop.ini
# User / local config
options.txt
local.cmake
games/
# Dependency cache
vcpkg_installed/
.cache/
conan/

View File

@@ -5,20 +5,69 @@ include(cmake/CPM.cmake)
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_FLAGS "-Wno-c++11-narrowing -Wno-invalid-source-encoding -Wno-reserved-user-defined-literal") set(CMAKE_POLICY_VERSION_MINIMUM 3.10)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "-Wno-c++11-narrowing -Wno-narrowing -Wno-invalid-source-encoding -Wno-reserved-user-defined-literal")
endif()
CPMAddPackage("gh:madler/zlib@1.3.2") find_package(Threads REQUIRED)
CPMAddPackage( find_package(OpenSSL)
NAME "libpng"
GIT_REPOSITORY "https://github.com/pnggroup/libpng.git" if(EMSCRIPTEN)
GIT_TAG "v1.6.55" set(AL_LIBTYPE "STATIC")
OPTIONS else()
"ZLIB_ROOT ${zlib_SOURCE_DIR}" set(AL_LIBTYPE "SHARED")
"ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}" endif()
"PNG_TOOLS OFF"
"PNG_TESTS OFF" # I totally shocked
"BUILD_SHARED_LIBS ON" if(EMSCRIPTEN)
) set(PNG_LIB png)
add_library(zlib INTERFACE IMPORTED)
set_target_properties(zlib PROPERTIES
INTERFACE_LINK_OPTIONS "-sUSE_ZLIB=1"
)
add_library(png INTERFACE IMPORTED)
set_target_properties(png PROPERTIES
INTERFACE_LINK_OPTIONS "-sUSE_LIBPNG=1"
)
add_library(glfw INTERFACE IMPORTED)
set_target_properties(glfw PROPERTIES
INTERFACE_LINK_OPTIONS "-sUSE_GLFW=3"
)
else()
set(PNG_LIB png_shared)
CPMAddPackage(
NAME "zlib"
GIT_REPOSITORY "https://github.com/madler/zlib"
GIT_TAG "v1.3.2"
)
CPMAddPackage(
NAME "libpng"
GIT_REPOSITORY "https://github.com/pnggroup/libpng.git"
GIT_TAG "v1.6.55"
OPTIONS
"ZLIB_ROOT ${zlib_SOURCE_DIR}"
"ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}"
"PNG_TOOLS OFF"
"PNG_TESTS OFF"
)
CPMAddPackage(
NAME "glfw"
GIT_REPOSITORY "https://github.com/glfw/glfw.git"
GIT_TAG "3.4"
EXCLUDE_FROM_ALL TRUE
OPTIONS
"GLFW_BUILD_EXAMPLES OFF"
"GLFW_BUILD_TESTS OFF"
"GLFW_BUILD_DOCS OFF"
)
endif()
CPMAddPackage( CPMAddPackage(
NAME "openal" NAME "openal"
@@ -28,21 +77,113 @@ CPMAddPackage(
"ALSOFT_EXAMPLES OFF" "ALSOFT_EXAMPLES OFF"
"ALSOFT_TESTS OFF" "ALSOFT_TESTS OFF"
"ALSOFT_UTILS OFF" "ALSOFT_UTILS OFF"
"BUILD_SHARED_LIBS ON" "LIBTYPE ${AL_LIBTYPE}"
) )
CPMAddPackage( # TODO: Clear this paths with *
NAME "glfw" file(GLOB SERVER_SOURCES
GIT_REPOSITORY "https://github.com/glfw/glfw.git" "project/lib_projects/raknet/jni/RaknetSources/*.cpp"
GIT_TAG "3.4" "src/NinecraftApp.cpp"
OPTIONS "src/Performance.cpp"
"GLFW_BUILD_EXAMPLES OFF" "src/SharedConstants.cpp"
"GLFW_BUILD_TESTS OFF"
"GLFW_BUILD_DOCS OFF"
"BUILD_SHARED_LIBS ON"
)
file(GLOB SOURCES "src/client/IConfigListener.cpp"
"src/client/Minecraft.cpp"
"src/client/OptionStrings.cpp"
"src/client/Option.cpp"
"src/client/Options.cpp"
"src/client/OptionsFile.cpp"
"src/client/ServerProfiler.cpp"
"src/client/gamemode/CreativeMode.cpp"
"src/client/gamemode/GameMode.cpp"
"src/client/gamemode/SurvivalMode.cpp"
"src/client/player/LocalPlayer.cpp"
"src/client/player/RemotePlayer.cpp"
"src/client/player/input/KeyboardInput.cpp"
"src/locale/I18n.cpp"
"src/main.cpp"
"src/main_dedicated.cpp"
"src/nbt/Tag.cpp"
"src/network/ClientSideNetworkHandler.cpp"
"src/network/NetEventCallback.cpp"
"src/network/Packet.cpp"
"src/network/RakNetInstance.cpp"
"src/network/ServerSideNetworkHandler.cpp"
"src/network/command/CommandServer.cpp"
"src/platform/CThread.cpp"
"src/platform/HttpClient.cpp"
"src/platform/PngLoader.cpp"
"src/platform/time.cpp"
"src/platform/input/Controller.cpp"
"src/platform/input/Keyboard.cpp"
"src/platform/input/Mouse.cpp"
"src/platform/input/Multitouch.cpp"
"src/server/ArgumentsSettings.cpp"
"src/server/ServerLevel.cpp"
"src/server/ServerPlayer.cpp"
"src/util/DataIO.cpp"
"src/util/Mth.cpp"
"src/util/PerfTimer.cpp"
"src/util/StringUtils.cpp"
"src/world/Direction.cpp"
"src/world/entity/*.cpp"
"src/world/entity/ai/control/MoveControl.cpp"
"src/world/entity/animal/*.cpp"
"src/world/entity/item/*.cpp"
"src/world/entity/monster/*.cpp"
"src/world/entity/player/Inventory.cpp"
"src/world/entity/player/Player.cpp"
"src/world/entity/projectile/Arrow.cpp"
"src/world/entity/projectile/Throwable.cpp"
"src/world/food/SimpleFoodData.cpp"
"src/world/inventory/*.cpp"
"src/world/item/*.cpp"
"src/world/item/crafting/*.cpp"
"src/world/level/*.cpp"
"src/world/level/biome/Biome.cpp"
"src/world/level/biome/BiomeSource.cpp"
"src/world/level/chunk/LevelChunk.cpp"
"src/world/level/dimension/Dimension.cpp"
"src/world/level/levelgen/*.cpp"
"src/world/level/levelgen/feature/Feature.cpp"
"src/world/level/levelgen/synth/*.cpp"
"src/world/level/material/Material.cpp"
"src/world/level/pathfinder/Path.cpp"
"src/world/level/storage/*.cpp"
"src/world/level/tile/*.cpp"
"src/world/level/tile/entity/*.cpp"
"src/world/phys/HitResult.cpp"
)
file(GLOB CLIENT_SOURCES
"src/client/*.cpp" "src/client/*.cpp"
"src/client/gamemode/*.cpp" "src/client/gamemode/*.cpp"
@@ -126,18 +267,33 @@ endif()
if(PLATFORM STREQUAL "PLATFORM_WIN32") if(PLATFORM STREQUAL "PLATFORM_WIN32")
list(APPEND SOURCES "src/AppPlatform_win32.cpp") list(APPEND CLIENT_SOURCES "src/AppPlatform_win32.cpp" "glad/src/glad.c")
endif() endif()
if(PLATFORM STREQUAL "PLATFORM_GLFW") if(PLATFORM STREQUAL "PLATFORM_GLFW")
list(APPEND SOURCES "src/AppPlatform_glfw.cpp") list(APPEND CLIENT_SOURCES "src/AppPlatform_glfw.cpp" "glad/src/glad.c")
endif() endif()
add_executable(${PROJECT_NAME} if(EMSCRIPTEN)
${SOURCES} list(APPEND CLIENT_SOURCES "glad/src/glad.c")
"glad/src/glad.c" endif()
# Server
if(UNIX)
add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES})
target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER")
target_include_directories("${PROJECT_NAME}-server" PUBLIC
"${CMAKE_SOURCE_DIR}/src/"
"project/lib_projects/raknet/jni/RaknetSources"
) )
target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT})
endif()
add_executable(${PROJECT_NAME} ${CLIENT_SOURCES})
if(WIN32) if(WIN32)
set(EXTRA_LIBS "ws2_32") set(EXTRA_LIBS "ws2_32")
target_compile_definitions(${PROJECT_NAME} PUBLIC "_CRT_SECURE_NO_WARNINGS") target_compile_definitions(${PROJECT_NAME} PUBLIC "_CRT_SECURE_NO_WARNINGS")
@@ -155,20 +311,78 @@ target_include_directories(${PROJECT_NAME} PUBLIC
"lib/include" "lib/include"
) )
target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM}) if(EMSCRIPTEN)
target_link_libraries(${PROJECT_NAME} zlib png_shared alsoft.common OpenAL::OpenAL glfw ${EXTRA_LIBS}) set(CMAKE_CXX_STANDARD 11)
# uuuh i hate it
set(EM_FLAGS "-pthread -sUSE_PTHREADS=1 -sSHARED_MEMORY=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EM_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EM_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EM_FLAGS} --preload-file ${CMAKE_SOURCE_DIR}/data@/data -sPROXY_TO_PTHREAD")
if (NOT UNIX) target_compile_options(${PROJECT_NAME} PUBLIC
add_custom_command( "-Os"
TARGET ${PROJECT_NAME} "-Wno-invalid-source-encoding"
POST_BUILD "-Wno-narrowing"
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${PROJECT_NAME}> $<TARGET_FILE_DIR:${PROJECT_NAME}> "-Wno-deprecated-register"
COMMAND_EXPAND_LISTS "-Wno-reserved-user-defined-literal"
) )
target_link_options(${PROJECT_NAME} PUBLIC
"-Os"
"-sALLOW_MEMORY_GROWTH=1"
"-sFORCE_FILESYSTEM=1"
"-sLEGACY_GL_EMULATION=1"
"-sGL_UNSAFE_OPTS=0"
"-sEMULATE_FUNCTION_POINTER_CASTS=1"
"-sALLOW_TABLE_GROWTH=1"
"-sEXPORTED_RUNTIME_METHODS=['FS','stringToUTF8','UTF8ToString','cwrap','ccall','HEAP8','HEAPU8','HEAP32','HEAPU32']"
"-sEXPORTED_FUNCTIONS=['_main']"
)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
message("DEBUG MODE")
target_link_options(${PROJECT_NAME} PUBLIC
"-sASSERTIONS=2"
"-sSTACK_OVERFLOW_CHECK=2"
"-sSTACK_SIZE=5242880"
"-sGL_DEBUG=1"
)
endif()
target_compile_definitions(${PROJECT_NAME} PUBLIC "__EMSCRIPTEN__" "NO_SOUND" "NO_NETWORK")
set(EXTRA_LIBS "idbfs.js")
endif() endif()
add_custom_command( # Client
TARGET ${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM})
POST_BUILD target_link_libraries(${PROJECT_NAME} zlib ${PNG_LIB} alsoft.common OpenAL::OpenAL glfw ${EXTRA_LIBS})
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $<TARGET_FILE_DIR:${PROJECT_NAME}>/data
) if (OpenSSL_FOUND)
target_link_libraries(${PROJECT_NAME} OpenSSL::SSL OpenSSL::Crypto)
target_compile_definitions(${PROJECT_NAME} PUBLIC HTTPCLIENT_USE_OPENSSL)
endif()
if (NOT UNIX)
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${PROJECT_NAME}> $<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMAND_EXPAND_LISTS
)
endif()
if(NOT EMSCRIPTEN)
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $<TARGET_FILE_DIR:${PROJECT_NAME}>/data
)
else()
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/misc/web/index.html" $<TARGET_FILE_DIR:${PROJECT_NAME}>
)
endif()

194
README.md
View File

@@ -1,18 +1,200 @@
# MinecraftPE # MinecraftPE
> [!Warning]
> Github repository **isnt main**. All issues and pull requests should be send in [Gitea Repository](https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1).
This is leaked source code of Minecraft PE 0.6.1 with my own impovements :sunglasses: > [!Important]
> We have a discord server, where you can report bugs or send feedback https://discord.gg/c58YesBxve
First of all I made it build with CMake (w/o VS2012). Also I fixed some compile errors. And finally I ported it to GLFW to make it run on several platforms and remove binary dependencies. Source code for **Minecraft Pocket Edition 0.6.1 alpha** with various fixes and improvements.
# TODO This project aims to preserve and improve this early version of Minecraft PE.
# TODO / Roadmap
- [x] Add platform GLFW - [x] Add platform GLFW
- [x] Compile for Linux - [x] Compile for Linux
- [ ] Compile for android aarch64 - [x] Compile for android aarch64
- [x] Touch control improvements
- [ ] Screen fixes
- [ ] Rewrite platform logic
- [x] Fix sound
- [x] Do a server connection GUI
- [ ] Controller support
- [x] Minecraft server hosting
- [x] Screen fixess
- [x] Fix fog
- [x] Add sprinting
- [x] Chat (semi working) and commands
- [x] Implementing options
- [x] Better F3
# Build # Build
## CMake ## CMake
### Linux
1. Install dependiences
(Debian-like)
``sudo apt install build-essential git cmake libgl-dev libwayland-dev xorg-dev libxkbcommon-dev``
(Arch-like)
``sudo pacman -S base-devel git cmake libglvnd wayland xorg-server-devel xorgproto libxkbcommon``
2. Create build folder
``mkdir build && cd build``
3. Generate CMake cache and build the project
``` ```
mkdir build && cd build
cmake .. -B . cmake .. -B .
make -j4 cmake --build .
``` ```
### Windows
1. Install [Visual studio Build Tools](https://aka.ms/vs/stable/vs_BuildTools.exe) and [CMake](https://github.com/Kitware/CMake/releases/download/v4.3.0-rc3/cmake-4.3.0-rc3-windows-x86_64.msi)
2. Create build folder
``mkdir build && cd build``
3. Generate CMake cache and build the project
```
cmake ..
cmake --build .
```
## Visual Studio
1. Open the repository folder in **Visual Studio**.
2. Visual Studio will automatically detect the `CMakeLists.txt` file and generate the project configuration.
3. Set **MinecraftPE.exe** as the **target**.
4. Press **Run** (or F5) to build and launch the game.
## Android
### Windows
1. Download **Android NDK r14b**:
http://dl.google.com/android/repository/android-ndk-r14b-windows-x86_64.zip
2. Extract it to the root of your `C:` drive so the path becomes:
```
C:\android-ndk-r14b
```
3. Run the build script:
```powershell
# Full build (NDK + Java + APK + install)
.\build.ps1
# Skip C++ compilation (Java/assets changed only)
.\build.ps1 -NoCpp
# Skip Java compilation (C++ changed only)
.\build.ps1 -NoJava
# Only repackage + install (no compilation)
.\build.ps1 -NoBuild
```
### Linux
1. Download **Command line tools**:
https://developer.android.com/studio#command-line-tools-only
2. Unzip it into a folder, e.g.:
```bash
mkdir -p "$HOME/Android/Sdk/"
unzip commandlinetools-linux-*.zip -d "$HOME/Android/Sdk/"
```
3. Your structure should look like
```bash
$HOME/Android/Sdk/cmdline-tools/bin/sdkmanager
```
> [!NOTE]
> `sdkmanager` expects the SDK to include a `cmdline-tools/latest/` folder.
> If you only have `cmdline-tools/bin`, create the required layout:
>
> ```bash
> mkdir -p "$HOME/Android/Sdk/cmdline-tools/latest"
> ln -snf ../bin "$HOME/Android/Sdk/cmdline-tools/latest/bin"
> ln -snf ../lib "$HOME/Android/Sdk/cmdline-tools/latest/lib"
> ln -snf ../source.properties "$HOME/Android/Sdk/cmdline-tools/latest/source.properties"
> ln -snf ../NOTICE.txt "$HOME/Android/Sdk/cmdline-tools/latest/NOTICE.txt"
> ```
4. Install the build tools (and platform) using `sdkmanager`
```bash
export ANDROID_SDK_ROOT="$HOME/Android/Sdk"
export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$PATH"
sdkmanager --install "platform-tools" "platforms;android-35" "build-tools;35.0.0"
```
> [!NOTE]
> if you want build.sh to always find the SDK,
> Set ANDROID_SDK_ROOT in your shell config (~/.bashrc / ~/.profile / ~/.config/fish/config.fish), for example:
>
> ```bash
> export ANDROID_SDK_ROOT="$HOME/Android/Sdk"
> ```
>
> Then restart your shell (or `source` the file)
5. Verify the install
```bash
ls "$ANDROID_SDK_ROOT/build-tools"
```
You should see a version folder like:
```bash
35.0.0
33.0.2
```
6. Download **Android NDK r14b**:
https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip
7. Extract the archive to `/home/username/`, so that the final directory path is `/home/username/android-ndk-r14b/`
> [!WARNING]
> Make sure you dont end up with a nested folder like `/home/username/android-ndk-r14b/android-ndk-r14b/`.
8. Re run `build.sh`
## Web
1. Download and install **emsdk**: https://emscripten.org/docs/getting_started/downloads.html
> [!NOTE]
> On arch linux you can use AUR:
> `yay -Sy emsdk`
2. Configure and build project:
```
mkdir build && cd build
cmake .. -B . -G Ninja "-DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
cmake --build . --target MinecraftPE
```
> [!NOTE]
> If you are using VSCode with CMake plugin, you can add Emscripten kit
> 1. Press Ctrl + Shift + P
> 2. Type `CMake: Edit User-Local CMake Kits` and hit Enter
> 3. Add this:
```json
{
"name": "Emscripten",
"compilers": {
"C": "/usr/lib/emsdk/upstream/bin/clang",
"CXX": "/usr/lib/emsdk/upstream/bin/clang++"
},
"toolchainFile": "/usr/lib/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
}
```
3. Run game:
```
emrun --port 8080 .
```

305
build.ps1 Normal file
View File

@@ -0,0 +1,305 @@
# ============================================================
# Usage:
# .\build.ps1 # full build (NDK + Java + APK + install)
# .\build.ps1 -NoCpp # skip NDK rebuild (Java/assets changed)
# .\build.ps1 -NoJava # skip Java recompile (C++ changed only)
# .\build.ps1 -NoBuild # repackage + install only (no recompile)
# .\build.ps1 -Clean # remove build output before building
# ============================================================
param(
[switch]$NoCpp,
[switch]$NoJava,
[switch]$NoBuild,
[switch]$Clean
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# ── Paths ────────────────────────────────────────────────────
$repo = $PSScriptRoot
$apkbuild = "C:\apkbuild"
$ndk = "C:\android-ndk-r14b"
$sdkTools = "$env:LOCALAPPDATA\Android\Sdk\build-tools\35.0.0"
$androidJar = "$env:LOCALAPPDATA\Android\Sdk\platforms\android-36\android.jar"
$adb = "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe"
$keystore = "$apkbuild\debug.keystore"
$pkg = "com.mojang.minecraftpe"
# Auto-detect keytool from JAVA_HOME, then from common install locations
$keytool = if ($env:JAVA_HOME) { "$env:JAVA_HOME\bin\keytool.exe" } else {
$found = Get-ChildItem "C:\Program Files\Java","C:\Program Files\Eclipse Adoptium" `
-Filter keytool.exe -Recurse -ErrorAction SilentlyContinue |
Sort-Object FullName -Descending | Select-Object -First 1 -ExpandProperty FullName
if (-not $found) { throw "keytool not found. Set JAVA_HOME or install a JDK." }
$found
}
$jniDir = "$repo\project\android\jni"
$libSrc = "$repo\project\android\libs\arm64-v8a\libminecraftpe.so"
$libDst = "$apkbuild\lib\arm64-v8a\libminecraftpe.so"
$manifest = "$repo\project\android_java\AndroidManifest.xml"
$res = "$repo\project\android_java\res"
$javaSrc = "$repo\project\android_java\src"
$stubsDir = "$apkbuild\stubs"
$rJava = "$apkbuild\gen\R.java"
$classesDir = "$apkbuild\classes"
$dexOut = "$apkbuild\classes.dex"
$dataDir = "$repo\data"
$unsigned = "$apkbuild\minecraftpe-unsigned.apk"
$aligned = "$apkbuild\minecraftpe-aligned.apk"
$signed = "$apkbuild\minecraftpe-debug.apk"
Add-Type -Assembly "System.IO.Compression.FileSystem"
function Write-Step([string]$msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
function Assert-ExitCode([string]$step) {
if ($LASTEXITCODE -ne 0) { Write-Host "FAILED: $step (exit $LASTEXITCODE)" -ForegroundColor Red; exit 1 }
}
function New-Dir([string]$path) { New-Item $path -ItemType Directory -Force | Out-Null }
function Write-Stub([string]$rel, [string]$content) {
$full = "$stubsDir\$rel"
New-Dir (Split-Path $full -Parent)
if (-not (Test-Path $full)) { [System.IO.File]::WriteAllText($full, $content); Write-Host " stub: $rel" }
}
# ── 0. Clean (optional) ───────────────────────────────────────
if ($Clean) {
Write-Step "Cleaning build output"
Remove-Item -Recurse -Force $apkbuild -ErrorAction SilentlyContinue
}
# ── 1. Bootstrap ─────────────────────────────────────────────
Write-Step "Bootstrap"
New-Dir $apkbuild
New-Dir "$apkbuild\lib\arm64-v8a"
New-Dir "$apkbuild\gen"
New-Dir $stubsDir
if (-not (Test-Path $keystore)) {
Write-Host " generating debug.keystore..."
$eap = $ErrorActionPreference; $ErrorActionPreference = "Continue"
& $keytool -genkeypair `
-keystore $keystore -storepass android -keypass android `
-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 `
-dname "CN=Android Debug,O=Android,C=US" 2>&1 | Out-Null
$ErrorActionPreference = $eap
Assert-ExitCode "keytool"
Write-Host " keystore created"
} else { Write-Host " keystore OK" }
Write-Stub "com\mojang\android\StringValue.java" "package com.mojang.android;`npublic interface StringValue { String getStringValue(); }`n"
Write-Stub "com\mojang\android\licensing\LicenseCodes.java" "package com.mojang.android.licensing;`npublic class LicenseCodes { public static final int LICENSE_OK = 0; }`n"
Write-Stub "com\mojang\android\EditTextAscii.java" @"
package com.mojang.android;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.widget.EditText;
public class EditTextAscii extends EditText implements TextWatcher {
public EditTextAscii(Context c) { super(c); addTextChangedListener(this); }
public EditTextAscii(Context c, AttributeSet a) { super(c,a); addTextChangedListener(this); }
public EditTextAscii(Context c, AttributeSet a, int d) { super(c,a,d); addTextChangedListener(this); }
@Override public void onTextChanged(CharSequence s,int st,int b,int co){}
public void beforeTextChanged(CharSequence s,int st,int co,int aft){}
public void afterTextChanged(Editable e){
String s=e.toString(),san=sanitize(s);
if(!s.equals(san))e.replace(0,e.length(),san);
}
static public String sanitize(String s){
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){char c=s.charAt(i);if(c<128)sb.append(c);}
return sb.toString();
}
}
"@
Write-Stub "com\mojang\android\preferences\SliderPreference.java" @"
package com.mojang.android.preferences;
import android.content.Context;
import android.content.res.Resources;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
public class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener {
private static final String NS="http://schemas.android.com/apk/res/android";
private Context _ctx; private TextView _tv; private SeekBar _sb;
private String _suf; private int _def,_max,_val,_min;
public SliderPreference(Context ctx,AttributeSet a){
super(ctx,a); _ctx=ctx;
_suf=gStr(a,NS,"text",""); _def=gInt(a,NS,"defaultValue",0);
_max=gInt(a,NS,"max",100); _min=gInt(a,null,"min",0);
setDefaultValue(_def);
}
@Override protected View onCreateDialogView(){
LinearLayout l=new LinearLayout(_ctx); l.setOrientation(LinearLayout.VERTICAL); l.setPadding(6,6,6,6);
_tv=new TextView(_ctx); _tv.setGravity(Gravity.CENTER_HORIZONTAL); _tv.setTextSize(32);
l.addView(_tv,new LinearLayout.LayoutParams(-1,-2));
_sb=new SeekBar(_ctx); _sb.setOnSeekBarChangeListener(this);
l.addView(_sb,new LinearLayout.LayoutParams(-1,-2));
if(shouldPersist())_val=getPersistedInt(_def);
_sb.setMax(_max); _sb.setProgress(_val); return l;
}
@Override protected void onSetInitialValue(boolean r,Object d){
super.onSetInitialValue(r,d);
_val=r?(shouldPersist()?getPersistedInt(_def):0):(Integer)d;
}
public void onProgressChanged(SeekBar s,int v,boolean f){
_val=v+_min; _tv.setText(_val+_suf);
if(shouldPersist())persistInt(_val); callChangeListener(Integer.valueOf(_val));
}
public void onStartTrackingTouch(SeekBar s){}
public void onStopTrackingTouch(SeekBar s){}
private int gInt(AttributeSet a,String ns,String n,int d){int id=a.getAttributeResourceValue(ns,n,0);return id!=0?getContext().getResources().getInteger(id):a.getAttributeIntValue(ns,n,d);}
private String gStr(AttributeSet a,String ns,String n,String d){int id=a.getAttributeResourceValue(ns,n,0);if(id!=0)return getContext().getResources().getString(id);String v=a.getAttributeValue(ns,n);return v!=null?v:d;}
}
"@
Write-Stub "com\mojang\minecraftpe\MainMenuOptionsActivity.java" @"
package com.mojang.minecraftpe;
import android.app.Activity;
public class MainMenuOptionsActivity extends Activity {
public static final String Internal_Game_DifficultyPeaceful="internal_game_difficulty_peaceful";
public static final String Game_DifficultyLevel="game_difficulty";
public static final String Controls_Sensitivity="controls_sensitivity";
}
"@
Write-Stub "com\mojang\minecraftpe\Minecraft_Market.java" @"
package com.mojang.minecraftpe;
import android.app.Activity; import android.content.Intent; import android.os.Bundle;
public class Minecraft_Market extends Activity {
@Override protected void onCreate(Bundle s){super.onCreate(s);startActivity(new Intent(this,MainActivity.class));finish();}
}
"@
Write-Stub "com\mojang\minecraftpe\Minecraft_Market_Demo.java" @"
package com.mojang.minecraftpe;
import android.content.Intent; import android.net.Uri;
public class Minecraft_Market_Demo extends MainActivity {
@Override public void buyGame(){startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("market://details?id=com.mojang.minecraftpe")));}
@Override protected boolean isDemo(){return true;}
}
"@
Write-Stub "com\mojang\minecraftpe\GameModeButton.java" @"
package com.mojang.minecraftpe;
import com.mojang.android.StringValue;
import android.content.Context; import android.util.AttributeSet;
import android.view.View; import android.view.View.OnClickListener;
import android.widget.TextView; import android.widget.ToggleButton;
public class GameModeButton extends ToggleButton implements OnClickListener,StringValue {
static final int Creative=0,Survival=1;
private int _type=0; private boolean _attached=false;
public GameModeButton(Context c,AttributeSet a){super(c,a);setOnClickListener(this);}
public void onClick(View v){_update();}
@Override protected void onFinishInflate(){super.onFinishInflate();_update();}
@Override protected void onAttachedToWindow(){if(!_attached){_update();_attached=true;}}
private void _update(){_set(isChecked()?Survival:Creative);}
private void _set(int i){
_type=i<Creative?Creative:(i>Survival?Survival:i);
int id=_type==Survival?R.string.gamemode_survival_summary:R.string.gamemode_creative_summary;
String desc=getContext().getString(id);
View v=getRootView().findViewById(R.id.labelGameModeDesc);
if(desc!=null&&v instanceof TextView)((TextView)v).setText(desc);
}
public String getStringValue(){return new String[]{"creative","survival"}[_type];}
static public String getStringForType(int i){int c=i<Creative?Creative:(i>Survival?Survival:i);return new String[]{"creative","survival"}[c];}
}
"@
Write-Host " stubs OK"
# ── 1. NDK build ─────────────────────────────────────────────
if (-not $NoCpp -and -not $NoBuild) {
Write-Step "NDK build (arm64-v8a)"
# NDK r14b on Windows hits the 32K CreateProcess limit with long paths.
# Work around it by building through a short junction C:\m -> repo root.
# Use forward slashes in the build paths to prevent the NDK toolchain from stripping backslashes.
$junctionBase = "C:/m"
if (-not (Test-Path "C:\m")) {
& cmd.exe /c "mklink /J `"C:\m`" `"$repo`"" | Out-Null
}
Push-Location "$junctionBase/project/android/jni"
$env:NDK_MODULE_PATH = "$junctionBase/project/lib_projects"
# run ndk-build and stream output directly to the console
$ndkCmd = Join-Path $ndk 'ndk-build.cmd'
$ndkArgs = "NDK_PROJECT_PATH=`"$junctionBase/project/android`" APP_BUILD_SCRIPT=`"$junctionBase/project/android/jni/Android.mk`""
$proc = Start-Process -FilePath $ndkCmd -ArgumentList $ndkArgs -NoNewWindow -Wait -PassThru
Pop-Location
if ($proc.ExitCode -ne 0) {
Write-Host "ndk-build failed (exit $($proc.ExitCode))" -ForegroundColor Red
exit 1
}
Copy-Item $libSrc $libDst -Force
Write-Host " .so -> $libDst"
}
# ── 2. Java compile ──────────────────────────────────────────
if (-not $NoJava -and -not $NoBuild) {
Write-Step "Java compile"
New-Dir (Split-Path $rJava -Parent)
& "$sdkTools\aapt.exe" package -f -M $manifest -S $res -I $androidJar -J "$apkbuild\gen" -F "$apkbuild\_rgen.apk"
Assert-ExitCode "aapt R.java"
Remove-Item "$apkbuild\_rgen.apk" -ea SilentlyContinue
$srcs = @(
Get-ChildItem $javaSrc -Recurse -Filter "*.java" | Select-Object -Exp FullName
Get-ChildItem $stubsDir -Recurse -Filter "*.java" | Select-Object -Exp FullName
$rJava
)
Remove-Item $classesDir -Recurse -Force -ea SilentlyContinue
New-Dir $classesDir
& javac --release 8 -cp $androidJar -d $classesDir @srcs
if ($LASTEXITCODE -ne 0) { Write-Host 'javac failed' -ForegroundColor Red; exit 1 }
Write-Host " javac OK"
$classFiles = Get-ChildItem $classesDir -Recurse -Filter "*.class" | Select-Object -Exp FullName
& "$sdkTools\d8.bat" --min-api 21 --output $apkbuild $classFiles
Assert-ExitCode "d8"
Write-Host " d8 -> $dexOut"
}
# ── 3. Package APK ───────────────────────────────────────────
Write-Step "Package APK"
Remove-Item $unsigned,$aligned,$signed -ea SilentlyContinue
& "$sdkTools\aapt.exe" package -f -M $manifest -S $res -I $androidJar -F $unsigned
Assert-ExitCode "aapt package"
$zip = [System.IO.Compression.ZipFile]::Open($unsigned, 'Update')
try {
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip,$dexOut,"classes.dex",[System.IO.Compression.CompressionLevel]::Fastest)|Out-Null
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip,$libDst,"lib/arm64-v8a/libminecraftpe.so",[System.IO.Compression.CompressionLevel]::NoCompression)|Out-Null
Get-ChildItem $dataDir -Recurse -File | ForEach-Object {
$rel=$_.FullName.Substring("$dataDir\".Length).Replace('\','/')
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip,$_.FullName,"assets/$rel",[System.IO.Compression.CompressionLevel]::NoCompression)|Out-Null
}
} finally { $zip.Dispose() }
Write-Host " APK assembled"
& "$sdkTools\zipalign.exe" -p 4 $unsigned $aligned; Assert-ExitCode "zipalign"
& "$sdkTools\apksigner.bat" sign --ks $keystore --ks-pass pass:android --key-pass pass:android --out $signed $aligned; Assert-ExitCode "apksigner"
Write-Host " signed -> $signed"
# ── 4. Install ───────────────────────────────────────────────
Write-Step "Install"
& $adb shell am force-stop $pkg
& $adb uninstall $pkg 2>$null
& $adb install --no-incremental $signed
Assert-ExitCode "adb install"
Write-Host "`nDone." -ForegroundColor Green

383
build.sh Executable file
View File

@@ -0,0 +1,383 @@
#!/usr/bin/env bash
# ============================================================
# Usage:
# ./build.sh # full build (NDK + Java + APK + install)
# ./build.sh --no-cpp # skip NDK rebuild (Java/assets changed)
# ./build.sh --no-java # skip Java recompile (C++ changed only)
# ./build.sh --no-build # repackage + install only (no recompile)
# ============================================================
# lets be strict cuz we are safe like that
# *thanos snap*
set -euo pipefail
IFS=$'\n\t'
########################################
# configuration
########################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$SCRIPT_DIR"
# build output directory (similar to apkbuild in the PS script)
# maybe doing this in build.ps1 would be cleaner, than putting the apkbuild in C:
BUILD_DIR="$REPO_ROOT/build-apk"
# default Android/NDK/SDK paths (can be overridden by env vars)
ANDROID_NDK_PATH="${ANDROID_NDK_PATH:-$HOME/android-ndk-r14b}"
ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-$HOME/Android/Sdk}}"
ANDROID_BUILD_TOOLS_VERSION="${ANDROID_BUILD_TOOLS_VERSION:-}"
ANDROID_PLATFORM_API="${ANDROID_PLATFORM_API:-}"
function fail() {
echo "ERROR: $1" >&2
exit 1
}
function find_build_tools_dir() {
if [[ -n "$ANDROID_BUILD_TOOLS_VERSION" ]]; then
local candidate="$ANDROID_SDK_ROOT/build-tools/$ANDROID_BUILD_TOOLS_VERSION"
[[ -d "$candidate" ]] && echo "$candidate" && return
fi
if [[ ! -d "$ANDROID_SDK_ROOT/build-tools" ]]; then
fail "Android build-tools not found under $ANDROID_SDK_ROOT/build-tools. Set ANDROID_SDK_ROOT or install Android SDK build-tools."
fi
# picking the highest build tools version because its the easiest way rn
# i guess if it breaks then fuck you
local best
best=$(ls -1 "$ANDROID_SDK_ROOT/build-tools" | sort -V | tail -n 1)
[[ -n "$best" && -d "$ANDROID_SDK_ROOT/build-tools/$best" ]] || \
fail "No Android build-tools versions found under $ANDROID_SDK_ROOT/build-tools."
echo "$ANDROID_SDK_ROOT/build-tools/$best"
}
function find_android_platform_dir() {
if [[ -n "$ANDROID_PLATFORM_API" ]]; then
local candidate="$ANDROID_SDK_ROOT/platforms/android-$ANDROID_PLATFORM_API"
[[ -d "$candidate" ]] && echo "$candidate" && return
fi
if [[ ! -d "$ANDROID_SDK_ROOT/platforms" ]]; then
fail "Android platforms not found under $ANDROID_SDK_ROOT/platforms. Install an Android platform."
fi
# pick the highest api level installed for now
# ideally we should be able to build to any api level, but lets keep it simple for now and
# just pick the highest one available
local best
best=$(ls -1 "$ANDROID_SDK_ROOT/platforms" | grep -E '^android-[0-9]+' | sed 's/android-//' | sort -n | tail -n 1)
[[ -n "$best" ]] || fail "No Android platforms found under $ANDROID_SDK_ROOT/platforms."
echo "$ANDROID_SDK_ROOT/platforms/android-$best"
}
ANDROID_BUILD_TOOLS_DIR="$(find_build_tools_dir)"
ANDROID_PLATFORM_DIR="$(find_android_platform_dir)"
KEYSTORE_FILE="$BUILD_DIR/debug.keystore"
PACKAGE_NAME="com.mojang.minecraftpe"
# android tool binaries
AAPT="$ANDROID_BUILD_TOOLS_DIR/aapt"
ZIPALIGN="$ANDROID_BUILD_TOOLS_DIR/zipalign"
APKSIGNER="$ANDROID_BUILD_TOOLS_DIR/apksigner"
DEX_TOOL="$ANDROID_BUILD_TOOLS_DIR/d8"
ADB="${ADB:-$ANDROID_SDK_ROOT/platform-tools/adb}"
# java tool binaries
JAVA_HOME_DEFAULT="${JAVA_HOME:-}" # may be empty
# prefer javac from the jdk;
# on some systems /usr/lib/jvm/default points to a JRE only.
# If javac is missing, try to locate a JDK installation.
JAVAC_CMD=""
if command -v javac >/dev/null 2>&1; then
JAVAC_CMD="$(command -v javac)"
elif [[ -n "$JAVA_HOME_DEFAULT" && -x "$JAVA_HOME_DEFAULT/bin/javac" ]]; then
JAVAC_CMD="$JAVA_HOME_DEFAULT/bin/javac"
elif [[ -x "/usr/lib/jvm/java-8-openjdk/bin/javac" ]]; then
JAVAC_CMD="/usr/lib/jvm/java-8-openjdk/bin/javac"
elif [[ -x "/usr/lib/jvm/default/bin/javac" ]]; then
JAVAC_CMD="/usr/lib/jvm/default/bin/javac"
fi
if [[ -z "$JAVAC_CMD" ]]; then
fail "javac not found; install a JDK and ensure javac is on PATH"
fi
KEYTOOL="" # will be detected later
# swource directories
JNI_DIR="$REPO_ROOT/project/android/jni"
JAVA_SRC_DIR="$REPO_ROOT/project/android_java/src"
ANDROID_MANIFEST="$REPO_ROOT/project/android_java/AndroidManifest.xml"
ANDROID_RES_DIR="$REPO_ROOT/project/android_java/res"
DATA_DIR="$REPO_ROOT/data"
# output files
APK_UNSIGNED="$BUILD_DIR/minecraftpe-unsigned.apk"
APK_ALIGNED="$BUILD_DIR/minecraftpe-aligned.apk"
APK_SIGNED="$BUILD_DIR/minecraftpe-debug.apk"
DEX_OUTPUT="$BUILD_DIR/classes.dex"
# flags parsed from CLI args
NO_CPP=false
NO_JAVA=false
NO_BUILD=false
########################################
# helpers
########################################
function usage() {
cat <<EOF
Usage: $0 [--no-cpp] [--no-java] [--no-build]
Options:
--no-cpp Skip the NDK (C++) build step
--no-java Skip the Java build step
--no-build Skip the compile steps; just package + install
EOF
exit 1
}
function log_step() {
echo -e "\n==> $1"
}
function fail() {
echo "ERROR: $1" >&2
exit 1
}
function require_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
fail "$1 not found; install it (e.g. 'sudo pacman -S $1')"
fi
}
# ensure required tools are available early
require_cmd zip
require_cmd unzip
function ensure_dir() {
mkdir -p "$1"
}
function find_keytool() {
# first try JAVA_HOME if set
if [[ -n "$JAVA_HOME_DEFAULT" && -x "$JAVA_HOME_DEFAULT/bin/keytool" ]]; then
echo "$JAVA_HOME_DEFAULT/bin/keytool"
return
fi
# try common install locations
if [[ -n "${JAVA_HOME:-}" && -x "${JAVA_HOME}/bin/keytool" ]]; then
echo "${JAVA_HOME}/bin/keytool"
return
fi
if command -v keytool >/dev/null 2>&1; then
command -v keytool
return
fi
fail "keytool not found. Set JAVA_HOME or install a JDK."
}
function write_stub_file() {
local rel_path="$1"
local content="$2"
local full_path="$BUILD_DIR/stubs/$rel_path"
ensure_dir "$(dirname "$full_path")"
if [[ ! -f "$full_path" ]]; then
echo -e "$content" > "$full_path"
echo " stub: $rel_path"
fi
}
########################################
# argument parsing
########################################
while [[ $# -gt 0 ]]; do
case "$1" in
--no-cpp) NO_CPP=true ;;
--no-java) NO_JAVA=true ;;
--no-build) NO_BUILD=true ;;
-h|--help) usage ;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
shift
done
########################################
# validate required tools
########################################
KEYTOOL="$(find_keytool)"
if [[ ! -x "$AAPT" ]]; then
fail "aapt not found at $AAPT"
fi
if [[ ! -x "$ZIPALIGN" ]]; then
fail "zipalign not found at $ZIPALIGN"
fi
if [[ ! -x "$APKSIGNER" ]]; then
fail "apksigner not found at $APKSIGNER"
fi
if [[ ! -x "$DEX_TOOL" ]]; then
fail "d8 not found at $DEX_TOOL"
fi
if [[ ! -x "$ADB" ]]; then
fail "adb not found at $ADB"
fi
########################################
# bootstrap
########################################
log_step "Bootstrap"
ensure_dir "$BUILD_DIR"
ensure_dir "$BUILD_DIR/lib/arm64-v8a"
ensure_dir "$BUILD_DIR/gen"
ensure_dir "$BUILD_DIR/stubs"
# create a debug keystore if it doesn't exist
if [[ ! -f "$KEYSTORE_FILE" ]]; then
echo " generating debug.keystore..."
"$KEYTOOL" -genkeypair \
-keystore "$KEYSTORE_FILE" -storepass android -keypass android \
-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 \
-dname "CN=Android Debug,O=Android,C=US" >/dev/null 2>&1
echo " keystore created"
else
echo " keystore OK"
fi
# why dont we just include the stubs lol
write_stub_file "com/mojang/android/StringValue.java" "package com.mojang.android;\npublic interface StringValue { String getStringValue(); }\n"
write_stub_file "com/mojang/android/licensing/LicenseCodes.java" "package com.mojang.android.licensing;\npublic class LicenseCodes { public static final int LICENSE_OK = 0; }\n"
write_stub_file "com/mojang/android/EditTextAscii.java" "package com.mojang.android;\nimport android.content.Context;\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.util.AttributeSet;\nimport android.widget.EditText;\npublic class EditTextAscii extends EditText implements TextWatcher {\n public EditTextAscii(Context c) { super(c); addTextChangedListener(this); }\n public EditTextAscii(Context c, AttributeSet a) { super(c,a); addTextChangedListener(this); }\n public EditTextAscii(Context c, AttributeSet a, int d) { super(c,a,d); addTextChangedListener(this); }\n @Override public void onTextChanged(CharSequence s,int st,int b,int co){}\n public void beforeTextChanged(CharSequence s,int st,int co,int aft){}\n public void afterTextChanged(Editable e){\n String s=e.toString(),san=sanitize(s);\n if(!s.equals(san))e.replace(0,e.length(),san);\n }\n static public String sanitize(String s){\n StringBuilder sb=new StringBuilder();\n for(int i=0;i<s.length();i++){char c=s.charAt(i);if(c<128)sb.append(c);}\n return sb.toString();\n }\n}\n"
write_stub_file "com/mojang/android/preferences/SliderPreference.java" "package com.mojang.android.preferences;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.preference.DialogPreference;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.widget.LinearLayout;\nimport android.widget.SeekBar;\nimport android.widget.TextView;\npublic class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener {\n private static final String NS=\"http://schemas.android.com/apk/res/android\";\n private Context _ctx; private TextView _tv; private SeekBar _sb;\n private String _suf; private int _def,_max,_val,_min;\n public SliderPreference(Context ctx,AttributeSet a){\n super(ctx,a); _ctx=ctx;\n _suf=gStr(a,NS,\"text\",\"\"); _def=gInt(a,NS,\"defaultValue\",0);\n _max=gInt(a,NS,\"max\",100); _min=gInt(a,null,\"min\",0);\n setDefaultValue(_def);\n }\n @Override protected View onCreateDialogView(){\n LinearLayout l=new LinearLayout(_ctx); l.setOrientation(LinearLayout.VERTICAL); l.setPadding(6,6,6,6);\n _tv=new TextView(_ctx); _tv.setGravity(Gravity.CENTER_HORIZONTAL); _tv.setTextSize(32);\n l.addView(_tv,new LinearLayout.LayoutParams(-1,-2));\n _sb=new SeekBar(_ctx); _sb.setOnSeekBarChangeListener(this);\n l.addView(_sb,new LinearLayout.LayoutParams(-1,-2));\n if(shouldPersist())_val=getPersistedInt(_def);\n _sb.setMax(_max); _sb.setProgress(_val); return l;\n }\n @Override protected void onSetInitialValue(boolean r,Object d){\n super.onSetInitialValue(r,d);\n _val=r?(shouldPersist()?getPersistedInt(_def):0):(Integer)d;\n }\n public void onProgressChanged(SeekBar s,int v,boolean f){\n _val=v+_min; _tv.setText(_val+_suf);\n if(shouldPersist())persistInt(_val); callChangeListener(Integer.valueOf(_val));\n }\n public void onStartTrackingTouch(SeekBar s){}\n public void onStopTrackingTouch(SeekBar s){}\n private int gInt(AttributeSet a,String ns,String n,int d){int id=a.getAttributeResourceValue(ns,n,0);return id!=0?getContext().getResources().getInteger(id):a.getAttributeIntValue(ns,n,d);}\n private String gStr(AttributeSet a,String ns,String n,String d){int id=a.getAttributeResourceValue(ns,n,0);if(id!=0)return getContext().getResources().getString(id);String v=a.getAttributeValue(ns,n);return v!=null?v:d;}\n}\n"
write_stub_file "com/mojang/minecraftpe/MainMenuOptionsActivity.java" "package com.mojang.minecraftpe;\nimport android.app.Activity;\npublic class MainMenuOptionsActivity extends Activity {\n public static final String Internal_Game_DifficultyPeaceful=\"internal_game_difficulty_peaceful\";\n public static final String Game_DifficultyLevel=\"game_difficulty\";\n public static final String Controls_Sensitivity=\"controls_sensitivity\";\n}\n"
write_stub_file "com/mojang/minecraftpe/Minecraft_Market.java" "package com.mojang.minecraftpe;\nimport android.app.Activity; import android.content.Intent; import android.os.Bundle;\npublic class Minecraft_Market extends Activity {\n @Override protected void onCreate(Bundle s){super.onCreate(s);startActivity(new Intent(this,MainActivity.class));finish();}\n}\n"
write_stub_file "com/mojang/minecraftpe/Minecraft_Market_Demo.java" "package com.mojang.minecraftpe;\nimport android.content.Intent; import android.net.Uri;\npublic class Minecraft_Market_Demo extends MainActivity {\n @Override public void buyGame(){startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse(\"market://details?id=com.mojang.minecraftpe\")));}\n @Override protected boolean isDemo(){return true;}\n}\n"
write_stub_file "com/mojang/minecraftpe/GameModeButton.java" "package com.mojang.minecraftpe;\nimport com.mojang.android.StringValue;\nimport android.content.Context; import android.util.AttributeSet;\nimport android.view.View; import android.view.View.OnClickListener;\nimport android.widget.TextView; import android.widget.ToggleButton;\npublic class GameModeButton extends ToggleButton implements OnClickListener,StringValue {\n static final int Creative=0,Survival=1;\n private int _type=0; private boolean _attached=false;\n public GameModeButton(Context c,AttributeSet a){super(c,a);setOnClickListener(this);}\n public void onClick(View v){_update();}\n @Override protected void onFinishInflate(){super.onFinishInflate();_update();}\n @Override protected void onAttachedToWindow(){if(!_attached){_update();_attached=true;}}\n private void _update(){_set(isChecked()?Survival:Creative);}\n private void _set(int i){\n _type=i<Creative?Creative:(i>Survival?Survival:i);\n int id=_type==Survival?R.string.gamemode_survival_summary:R.string.gamemode_creative_summary;\n String desc=getContext().getString(id);\n View v=getRootView().findViewById(R.id.labelGameModeDesc);\n if(desc!=null&&v instanceof TextView)((TextView)v).setText(desc);\n }\n public String getStringValue(){return new String[]{\"creative\",\"survival\"}[_type];}\n static public String getStringForType(int i){int c=i<Creative?Creative:(i>Survival?Survival:i);return new String[]{\"creative\",\"survival\"}[c];}\n}\n"
echo " stubs OK"
########################################
# ndk build
########################################
if [[ "$NO_CPP" == false && "$NO_BUILD" == false ]]; then
log_step "NDK build (arm64-v8a)"
# the original windows build script used a junction to avoid long paths here
# on linux, path lengths are *usually* fine, but we still keep things simple
pushd "$JNI_DIR" >/dev/null
export NDK_MODULE_PATH="$REPO_ROOT/project/lib_projects"
# run ndk-build and show output in case of failure
if ! "$ANDROID_NDK_PATH/ndk-build" NDK_PROJECT_PATH="$REPO_ROOT/project/android" APP_BUILD_SCRIPT="$JNI_DIR/Android.mk" 2>&1 | tee "$BUILD_DIR/ndk-build.log"; then
echo "NDK build failed. See $BUILD_DIR/ndk-build.log" >&2
exit 1
fi
popd >/dev/null
# copy the compiled library to the APK staging folder
cp -v "$REPO_ROOT/project/android/libs/arm64-v8a/libminecraftpe.so" "$BUILD_DIR/lib/arm64-v8a/"
echo " .so -> $BUILD_DIR/lib/arm64-v8a/libminecraftpe.so"
fi
########################################
# java compile
########################################
if [[ "$NO_JAVA" == false && "$NO_BUILD" == false ]]; then
log_step "Java compile"
ensure_dir "$(dirname "$BUILD_DIR/gen/R.java")"
# generate R.java
"$AAPT" package -f -M "$ANDROID_MANIFEST" -S "$ANDROID_RES_DIR" -I "$ANDROID_PLATFORM_DIR/android.jar" -J "$BUILD_DIR/gen" -F "$BUILD_DIR/_rgen.apk"
rm -f "$BUILD_DIR/_rgen.apk"
# collect all source files (project + stubs + generated R.java)
JAVA_SOURCES=(
$(find "$JAVA_SRC_DIR" -name "*.java" -print)
$(find "$BUILD_DIR/stubs" -name "*.java" -print)
"$BUILD_DIR/gen/R.java"
)
rm -rf "$BUILD_DIR/classes"
ensure_dir "$BUILD_DIR/classes"
# Some JDK versions (<=8) dont support --release.
JAVAC_ARGS=(--release 8)
if "$JAVAC_CMD" -version 2>&1 | grep -qE '^javac 1\.'; then
JAVAC_ARGS=(-source 1.8 -target 1.8)
fi
"$JAVAC_CMD" "${JAVAC_ARGS[@]}" -cp "$ANDROID_PLATFORM_DIR/android.jar" -d "$BUILD_DIR/classes" "${JAVA_SOURCES[@]}"
echo " javac OK"
# convert class files into dex
JAVA_CLASS_FILES=( $(find "$BUILD_DIR/classes" -name "*.class" -print) )
"$DEX_TOOL" --min-api 21 --output "$BUILD_DIR" "${JAVA_CLASS_FILES[@]}"
echo " d8 -> $DEX_OUTPUT"
fi
########################################
# package apk
########################################
log_step "Package APK"
rm -f "$APK_UNSIGNED" "$APK_ALIGNED" "$APK_SIGNED"
"$AAPT" package -f -M "$ANDROID_MANIFEST" -S "$ANDROID_RES_DIR" -I "$ANDROID_PLATFORM_DIR/android.jar" -F "$APK_UNSIGNED"
# add classes.dex and native library into apk
pushd "$BUILD_DIR" >/dev/null
zip -q "$APK_UNSIGNED" "classes.dex"
zip -q "$APK_UNSIGNED" "lib/arm64-v8a/libminecraftpe.so"
popd >/dev/null
# add assets from data/ directory into the apk under assets/
TMP_ASSETS_DIR="$(mktemp -d)"
mkdir -p "$TMP_ASSETS_DIR/assets"
cp -r "$DATA_DIR/." "$TMP_ASSETS_DIR/assets/"
pushd "$TMP_ASSETS_DIR" >/dev/null
zip -q -r "$APK_UNSIGNED" assets
popd >/dev/null
rm -rf "$TMP_ASSETS_DIR"
"$ZIPALIGN" -p 4 "$APK_UNSIGNED" "$APK_ALIGNED"
"$APKSIGNER" sign --ks "$KEYSTORE_FILE" --ks-pass pass:android --key-pass pass:android --out "$APK_SIGNED" "$APK_ALIGNED"
echo " signed -> $APK_SIGNED"
########################################
# install
########################################
log_step "Install"
"$ADB" shell am force-stop "$PACKAGE_NAME" || true
"$ADB" uninstall "$PACKAGE_NAME" || true
"$ADB" install --no-incremental "$APK_SIGNED"
echo -e "\nDone. Enjoy MCPE 0.6.1 on your device!"

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

@@ -144,6 +144,17 @@ options.fov.max=Quake Pro
options.gamma=Brightness options.gamma=Brightness
options.gamma.min=Moody options.gamma.min=Moody
options.gamma.max=Bright options.gamma.max=Bright
options.group.mojang=Login
options.group.general=General
options.group.game=Game
options.group.controls=Controls
options.group.graphics=Graphics
options.group.tweaks=Tweaks
options.allowSprint=Allow sprint
options.barOnTop=HUD above inventory
options.autojump=Auto Jump
options.thirdperson=Third Person
options.servervisible=Server Visible
options.sensitivity=Sensitivity options.sensitivity=Sensitivity
options.sensitivity.min=*yawn* options.sensitivity.min=*yawn*
options.sensitivity.max=HYPERSPEED!!! options.sensitivity.max=HYPERSPEED!!!
@@ -156,6 +167,8 @@ options.viewBobbing=View Bobbing
options.ao=Smooth Lighting options.ao=Smooth Lighting
options.anaglyph=3D Anaglyph options.anaglyph=3D Anaglyph
options.framerateLimit=Performance options.framerateLimit=Performance
options.limitFramerate=Limit Framerate
options.vsync=VSync
options.difficulty=Difficulty options.difficulty=Difficulty
options.difficulty.peaceful=Peaceful options.difficulty.peaceful=Peaceful
options.difficulty.easy=Easy options.difficulty.easy=Easy
@@ -170,6 +183,7 @@ options.guiScale.auto=Auto
options.guiScale.small=Small options.guiScale.small=Small
options.guiScale.normal=Normal options.guiScale.normal=Normal
options.guiScale.large=Large options.guiScale.large=Large
options.guiScale.larger=Larger
options.advancedOpengl=Advanced OpenGL options.advancedOpengl=Advanced OpenGL
options.renderClouds=Clouds options.renderClouds=Clouds
options.farWarning1=A 64 bit Java installation is recommended options.farWarning1=A 64 bit Java installation is recommended
@@ -178,6 +192,15 @@ options.particles=Particles
options.particles.all=All options.particles.all=All
options.particles.decreased=Decreased options.particles.decreased=Decreased
options.particles.minimal=Minimal options.particles.minimal=Minimal
options.username=Username
options.smoothCamera=Smooth camera
options.destroyVibration=Destroy vibration
options.isLeftHanded=Left handed
options.useTouchscreen=Use touchscreen
options.fancyGraphics=Fancy graphics
options.renderDebug=Debug render
options.anaglyph3d=3D anaglyph
performance.max=Max FPS performance.max=Max FPS
performance.balanced=Balanced performance.balanced=Balanced
@@ -185,21 +208,21 @@ performance.powersaver=Power saver
controls.title=Controls controls.title=Controls
key.forward=Forward options.key.forward=Forward
key.left=Left options.key.left=Left
key.back=Back options.key.back=Back
key.right=Right options.key.right=Right
key.jump=Jump options.key.jump=Jump
key.inventory=Inventory options.key.inventory=Inventory
key.drop=Drop options.key.drop=Drop
key.chat=Chat options.key.chat=Chat
key.fog=Toggle Fog options.key.fog=Toggle Fog
key.sneak=Sneak options.key.sneak=Sneak
key.playerlist=List Players options.key.playerlist=List Players
key.attack=Attack options.key.attack=Attack
key.use=Use Item options.key.use=Use Item
key.pickItem=Pick Block options.key.pickItem=Pick Block
key.mouseButton=Button %1$s options.key.mouseButton=Button %1$s
texturePack.openFolder=Open texture pack folder texturePack.openFolder=Open texture pack folder
texturePack.title=Select Texture Pack texturePack.title=Select Texture Pack

0
glad/include/KHR/khrplatform.h Executable file → Normal file
View File

2941
glad/include/glad/glad.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

1393
glad/src/glad.c Executable file → Normal file

File diff suppressed because it is too large Load Diff

143
misc/web/index.html Normal file
View File

@@ -0,0 +1,143 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Emscripten-Generated Code</title>
<style>
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
textarea.emscripten { font-family: monospace; width: 80%; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { border: 0px none; background-color: black; }
.spinner {
height: 50px;
width: 50px;
margin: 0px auto;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 10px solid rgb(0,150,240);
border-right: 10px solid rgb(0,150,240);
border-bottom: 10px solid rgb(0,150,240);
border-top: 10px solid rgb(100,0,200);
border-radius: 100%;
background-color: rgb(200,100,250);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
</style>
</head>
<body>
<hr/>
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>emscripten</strong></center></figure>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div>
<hr/>
<div class="emscripten">
<input type="checkbox" id="resize">Resize canvas
<input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
&nbsp;&nbsp;&nbsp;
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked,
document.getElementById('resize').checked)">
</div>
<hr/>
<textarea class="emscripten" id="output" rows="8"></textarea>
<hr>
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var spinnerElement = document.getElementById('spinner');
var canvasElement = document.getElementById('canvas');
var outputElement = document.getElementById('output');
if (outputElement) outputElement.value = ''; // clear browser cache
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvasElement.addEventListener("webglcontextlost", (e) => {
alert('WebGL context lost. You will need to reload the page.');
e.preventDefault();
}, false);
function setStatus(text) {
if (!setStatus.last) setStatus.last = { time: Date.now(), text: '' };
if (text === setStatus.last.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
setStatus.last.time = now;
setStatus.last.text = text;
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
spinnerElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
if (!text) spinnerElement.hidden = true;
}
statusElement.innerHTML = text;
}
var Module = {
print(...args) {
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(...args);
if (outputElement) {
var text = args.join(' ');
outputElement.value += text + "\n";
outputElement.scrollTop = outputElement.scrollHeight; // focus on bottom
}
},
canvas: canvasElement,
setStatus: setStatus,
totalDependencies: 0,
monitorRunDependencies(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
};
setStatus('Downloading...');
window.onerror = () => {
setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none';
setStatus = (text) => {
if (text) console.error('[post-exception status] ' + text);
};
};
</script>
<script src="MinecraftPE.js"></script>
</body>
</html>

View File

@@ -1,46 +1,46 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mojang.minecraftpe" package="com.mojang.minecraftpe"
android:versionCode="6006" android:versionCode="6010"
android:versionName="0.6.0" android:versionName="0.6.1-alpha-0.0.3"
android:installLocation="preferExternal"> android:installLocation="preferExternal">
<!-- This is the platform API where NativeActivity was introduced. --> <!-- This is the platform API where NativeActivity was introduced. -->
<uses-sdk android:minSdkVersion="9" <uses-sdk android:minSdkVersion="24"
android:targetSdkVersion="9" /> android:targetSdkVersion="24" />
<!-- uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="true"/ --> <!-- uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="true"/ -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<application android:icon="@drawable/icon" <application android:icon="@drawable/icon"
android:label="@string/app_name" android:label="@string/app_name"
> >
<activity android:name="com.mojang.minecraftpe.MainActivity" <activity android:name="com.mojang.minecraftpe.MainActivity"
android:label="@string/app_name_short" android:label="@string/app_name_short"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:screenOrientation="landscape" android:screenOrientation="landscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTop"> android:launchMode="singleTop">
<meta-data android:name="android.app.lib_name" <meta-data android:name="android.app.lib_name"
android:value="minecraftpe" /> android:value="minecraftpe" />
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.mojang.minecraftpe.MainMenuOptionsActivity"></activity> <activity android:name="com.mojang.minecraftpe.MainMenuOptionsActivity"></activity>
<meta-data android:name="xperiaplayoptimized_content" android:resource="@string/xperiaplayoptimized_content" /> <meta-data android:name="xperiaplayoptimized_content" android:resource="@string/xperiaplayoptimized_content" />
<meta-data android:name="game_display_name" android:resource="@string/app_name" /> <meta-data android:name="game_display_name" android:resource="@string/app_name" />
<meta-data android:name="game_icon" android:resource="@drawable/iconx" /> <meta-data android:name="game_icon" android:resource="@drawable/iconx" />
<uses-library android:name="xperiaplaycertified" android:required="false"/> <uses-library android:name="xperiaplaycertified" android:required="false"/>
</application> </application>
</manifest> </manifest>

View File

@@ -170,6 +170,7 @@ options.guiScale.auto=Auto
options.guiScale.small=Small options.guiScale.small=Small
options.guiScale.normal=Normal options.guiScale.normal=Normal
options.guiScale.large=Large options.guiScale.large=Large
options.guiScale.larger=Larger
options.advancedOpengl=Advanced OpenGL options.advancedOpengl=Advanced OpenGL
options.renderClouds=Clouds options.renderClouds=Clouds
options.farWarning1=A 64 bit Java installation is recommended options.farWarning1=A 64 bit Java installation is recommended

View File

@@ -1,10 +1,12 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
# Convert Windows backslashes to forward slashes so NDK toolchain doesnt treat them as escapes.
LOCAL_PATH := $(subst \,/,$(LOCAL_PATH))
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := minecraftpe LOCAL_MODULE := minecraftpe
LOCAL_SRC_FILES := ../../../src/main.cpp \ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/main_android.cpp \ ../../../src/main_android_java.cpp \
../../../src/platform/audio/SoundSystemSL.cpp \ ../../../src/platform/audio/SoundSystemSL.cpp \
../../../src/platform/input/Controller.cpp \ ../../../src/platform/input/Controller.cpp \
../../../src/platform/input/Keyboard.cpp \ ../../../src/platform/input/Keyboard.cpp \
@@ -12,6 +14,7 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/platform/input/Multitouch.cpp \ ../../../src/platform/input/Multitouch.cpp \
../../../src/platform/time.cpp \ ../../../src/platform/time.cpp \
../../../src/platform/CThread.cpp \ ../../../src/platform/CThread.cpp \
../../../src/platform/HttpClient.cpp \
../../../src/NinecraftApp.cpp \ ../../../src/NinecraftApp.cpp \
../../../src/Performance.cpp \ ../../../src/Performance.cpp \
../../../src/SharedConstants.cpp \ ../../../src/SharedConstants.cpp \
@@ -21,6 +24,7 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/client/Options.cpp \ ../../../src/client/Options.cpp \
../../../src/client/OptionsFile.cpp \ ../../../src/client/OptionsFile.cpp \
../../../src/client/OptionStrings.cpp \ ../../../src/client/OptionStrings.cpp \
../../../src/client/Option.cpp \
../../../src/client/gamemode/GameMode.cpp \ ../../../src/client/gamemode/GameMode.cpp \
../../../src/client/gamemode/CreativeMode.cpp \ ../../../src/client/gamemode/CreativeMode.cpp \
../../../src/client/gamemode/SurvivalMode.cpp \ ../../../src/client/gamemode/SurvivalMode.cpp \
@@ -34,13 +38,14 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/client/gui/components/NinePatch.cpp \ ../../../src/client/gui/components/NinePatch.cpp \
../../../src/client/gui/components/OptionsGroup.cpp \ ../../../src/client/gui/components/OptionsGroup.cpp \
../../../src/client/gui/components/OptionsItem.cpp \ ../../../src/client/gui/components/OptionsItem.cpp \
../../../src/client/gui/components/OptionsPane.cpp \ ../../../src/client/gui/components/KeyOption.cpp \
../../../src/client/gui/components/TextOption.cpp \
../../../src/client/gui/components/RolledSelectionListH.cpp \ ../../../src/client/gui/components/RolledSelectionListH.cpp \
../../../src/client/gui/components/RolledSelectionListV.cpp \ ../../../src/client/gui/components/RolledSelectionListV.cpp \
../../../src/client/gui/components/ScrolledSelectionList.cpp \ ../../../src/client/gui/components/ScrolledSelectionList.cpp \
../../../src/client/gui/components/ScrollingPane.cpp \ ../../../src/client/gui/components/ScrollingPane.cpp \
../../../src/client/gui/components/Slider.cpp \ ../../../src/client/gui/components/Slider.cpp \
../../../src/client/gui/components/SmallButton.cpp \ ../../../src/client/gui/components/TextBox.cpp \
../../../src/client/gui/Font.cpp \ ../../../src/client/gui/Font.cpp \
../../../src/client/gui/Gui.cpp \ ../../../src/client/gui/Gui.cpp \
../../../src/client/gui/GuiComponent.cpp \ ../../../src/client/gui/GuiComponent.cpp \
@@ -48,6 +53,10 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/client/gui/screens/ScreenChooser.cpp \ ../../../src/client/gui/screens/ScreenChooser.cpp \
../../../src/client/gui/screens/ArmorScreen.cpp \ ../../../src/client/gui/screens/ArmorScreen.cpp \
../../../src/client/gui/screens/ChatScreen.cpp \ ../../../src/client/gui/screens/ChatScreen.cpp \
../../../src/client/gui/screens/ChooseLevelScreen.cpp \
../../../src/client/gui/screens/SimpleChooseLevelScreen.cpp \
../../../src/client/gui/screens/ConsoleScreen.cpp \
../../../src/client/gui/screens/UsernameScreen.cpp \
../../../src/client/gui/screens/ConfirmScreen.cpp \ ../../../src/client/gui/screens/ConfirmScreen.cpp \
../../../src/client/gui/screens/ChestScreen.cpp \ ../../../src/client/gui/screens/ChestScreen.cpp \
../../../src/client/gui/screens/DeathScreen.cpp \ ../../../src/client/gui/screens/DeathScreen.cpp \
@@ -56,12 +65,14 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/client/gui/screens/IngameBlockSelectionScreen.cpp \ ../../../src/client/gui/screens/IngameBlockSelectionScreen.cpp \
../../../src/client/gui/screens/JoinGameScreen.cpp \ ../../../src/client/gui/screens/JoinGameScreen.cpp \
../../../src/client/gui/screens/OptionsScreen.cpp \ ../../../src/client/gui/screens/OptionsScreen.cpp \
../../../src/client/gui/screens/PauseScreen.cpp \ ../../../src/client/gui/screens/CreditsScreen.cpp \
../../../src/client/gui/screens/PauseScreen.cpp \
../../../src/client/gui/screens/ProgressScreen.cpp \ ../../../src/client/gui/screens/ProgressScreen.cpp \
../../../src/client/gui/screens/RenameMPLevelScreen.cpp \ ../../../src/client/gui/screens/RenameMPLevelScreen.cpp \
../../../src/client/gui/screens/SelectWorldScreen.cpp \ ../../../src/client/gui/screens/SelectWorldScreen.cpp \
../../../src/client/gui/screens/StartMenuScreen.cpp \ ../../../src/client/gui/screens/StartMenuScreen.cpp \
../../../src/client/gui/screens/TextEditScreen.cpp \ ../../../src/client/gui/screens/TextEditScreen.cpp \
../../../src/client/gui/screens/JoinByIPScreen.cpp \
../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \ ../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \
../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \ ../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \
../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \ ../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \
@@ -245,7 +256,10 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/world/level/tile/entity/FurnaceTileEntity.cpp \ ../../../src/world/level/tile/entity/FurnaceTileEntity.cpp \
../../../src/world/phys/HitResult.cpp ../../../src/world/phys/HitResult.cpp
LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS) LOCAL_CFLAGS := -DPLATFORM_ANDROID -DPRE_ANDROID23 -Wno-narrowing $(LOCAL_CFLAGS)
LOCAL_CPPFLAGS := -std=c++14 -frtti
LOCAL_CPPFLAGS += -frtti
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../src
#LOCAL_CFLAGS := -DANDROID_PUBLISH -DDEMO_MODE $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DANDROID_PUBLISH -DDEMO_MODE $(LOCAL_CFLAGS)
#LOCAL_CFLAGS := -DANDROID_PUBLISH $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DANDROID_PUBLISH $(LOCAL_CFLAGS)

View File

@@ -1,5 +1,7 @@
APP_PLATFORM := android-9 APP_PLATFORM := android-21
APP_STL := stlport_static APP_STL := gnustl_static
APP_OPTIM := release APP_OPTIM := release
APP_ABI := armeabi-v7a APP_ABI := arm64-v8a
APP_SHORT_COMMANDS := true
APP_CPPFLAGS += -frtti -fexceptions
#APP_ABI := armeabi-v7a x86 #APP_ABI := armeabi-v7a x86

View File

@@ -468,17 +468,16 @@ public class MainActivity extends NativeActivity {
_userInputStatus = 1; _userInputStatus = 1;
InputMethodManager inputManager = (InputMethodManager)getSystemService("input_method"); InputMethodManager inputManager = (InputMethodManager)getSystemService("input_method");
boolean result = inputManager.showSoftInput(this.getCurrentFocus(), InputMethodManager.SHOW_IMPLICIT); View focused = this.getCurrentFocus();
} if (focused != null) {
boolean result = inputManager.showSoftInput(focused, InputMethodManager.SHOW_IMPLICIT);
protected void onStart() { } else {
//System.out.println("onStart"); // fallback: try to show using decor view token
super.onStart(); View decor = getWindow().getDecorView();
} if (decor != null) {
inputManager.showSoftInput(decor, InputMethodManager.SHOW_IMPLICIT);
protected void onResume() { }
//System.out.println("onResume"); }
super.onResume();
} }
protected void onPause() { protected void onPause() {

View File

@@ -1,44 +1,74 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mojang.minecraftpe" package="com.mojang.minecraftpe"
android:versionCode="4000" android:versionCode="6010"
android:versionName="0.4.0" android:versionName="0.6.1-alpha-0.0.3">
>
<!-- android:installLocation="preferExternal" --> <uses-sdk
android:minSdkVersion="24"
<uses-sdk android:targetSdkVersion="8" android:minSdkVersion="7"/> android:targetSdkVersion="28"/>
<uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="true"/> <uses-feature
android:name="android.hardware.touchscreen.multitouch"
<uses-permission android:name="android.permission.INTERNET"/> android:required="true"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:icon="@drawable/icon" <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
android:label="@string/app_name" <uses-permission android:name="android.permission.VIBRATE"/>
>
<application
<activity android:name="com.mojang.minecraftpe.Minecraft_Market" android:icon="@drawable/icon"
android:label="@string/app_name_short" android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden" android:hardwareAccelerated="true"
android:screenOrientation="landscape" android:extractNativeLibs="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> android:requestLegacyExternalStorage="true">
<meta-data android:name="android.app.lib_name" <activity
android:value="minecraftpe" /> android:name="com.mojang.minecraftpe.Minecraft_Market"
android:label="@string/app_name_short"
<intent-filter> android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
<action android:name="android.intent.action.MAIN" /> android:screenOrientation="landscape"
<category android:name="android.intent.category.LAUNCHER" /> android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
</intent-filter> android:exported="true">
</activity>
<activity android:name="com.mojang.minecraftpe.MainMenuOptionsActivity"></activity> <meta-data
android:name="android.app.lib_name"
<meta-data android:name="xperiaplayoptimized_content" android:resource="@string/xperiaplayoptimized_content" /> android:value="minecraftpe"/>
<meta-data android:name="game_display_name" android:resource="@string/app_name" />
<meta-data android:name="game_icon" android:resource="@drawable/iconx" /> <intent-filter>
<action android:name="android.intent.action.MAIN"/>
<uses-library android:name="xperiaplaycertified" android:required="false"/> <category android:name="android.intent.category.LAUNCHER"/>
</application> </intent-filter>
</activity>
</manifest>
<activity
android:name="com.mojang.minecraftpe.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
android:screenOrientation="landscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:exported="false"/>
<activity
android:name="com.mojang.minecraftpe.MainMenuOptionsActivity"
android:exported="false"/>
<meta-data
android:name="xperiaplayoptimized_content"
android:resource="@string/xperiaplayoptimized_content"/>
<meta-data
android:name="game_display_name"
android:resource="@string/app_name"/>
<meta-data
android:name="game_icon"
android:resource="@drawable/iconx"/>
<uses-library
android:name="xperiaplaycertified"
android:required="false"/>
</application>
</manifest>

View File

@@ -31,6 +31,8 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.content.pm.PackageManager;
import android.os.Build;
import android.graphics.Bitmap.CompressFormat; import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.media.AudioManager; import android.media.AudioManager;
@@ -40,7 +42,6 @@ import android.os.Vibrator;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.Display;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -55,9 +56,12 @@ import com.mojang.minecraftpe.sound.SoundPlayer;
public class MainActivity extends Activity { public class MainActivity extends Activity {
/** Called when the activity is first created. */ /** Called when the activity is first created. */
private static final int PERMISSION_REQUEST_CODE = 123;
private GLView _glView; private GLView _glView;
public float invScale = 1.0f;// / 1.5f; public float invScale = 1.0f;// / 1.5f;
private int _screenWidth = 0;
private int _screenHeight = 0;
Vector<MotionEvent> _touchEvents = new Vector<MotionEvent>(); Vector<MotionEvent> _touchEvents = new Vector<MotionEvent>();
Vector<KeyEvent> _keyEvents = new Vector<KeyEvent>(); Vector<KeyEvent> _keyEvents = new Vector<KeyEvent>();
@@ -67,8 +71,13 @@ public class MainActivity extends Activity {
setVolumeControlStream(AudioManager.STREAM_MUSIC); setVolumeControlStream(AudioManager.STREAM_MUSIC);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
nativeRegisterThis(); nativeRegisterThis();
nativeOnCreate(); // Cache screen dimensions once to avoid re-entrant getDisplayMetrics() callbacks
android.util.DisplayMetrics _dm = getResources().getDisplayMetrics();
_screenWidth = Math.max(_dm.widthPixels, _dm.heightPixels);
_screenHeight = Math.min(_dm.widthPixels, _dm.heightPixels);
nativeOnCreate(_screenWidth, _screenHeight);
_glView = new GLView(getApplication(), this); _glView = new GLView(getApplication(), this);
//_glView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); //_glView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
@@ -102,18 +111,68 @@ public class MainActivity extends Activity {
setContentView(_glView); setContentView(_glView);
_soundPlayer = new SoundPlayer(this, AudioManager.STREAM_MUSIC); _soundPlayer = new SoundPlayer(this, AudioManager.STREAM_MUSIC);
// request dangerous permissions at runtime if necessary
checkAndRequestPermissions();
}
private void checkAndRequestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
boolean needRequest = false;
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
needRequest = true;
}
if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
needRequest = true;
}
if (needRequest) {
requestPermissions(new String[] {
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.READ_EXTERNAL_STORAGE
}, PERMISSION_REQUEST_CODE);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_CODE) {
boolean granted = true;
for (int r : grantResults) {
if (r != PackageManager.PERMISSION_GRANTED) {
granted = false;
break;
}
}
if (!granted) {
// user denied; you might want to warn or close the app
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
// method required by native code to detect touchscreen support
public boolean supportsTouchscreen() {
return true; // all devices using this build are touch-capable
} }
public boolean isTouchscreen() { return true; }
static public boolean isXperiaPlay() { return false; } static public boolean isXperiaPlay() { return false; }
static private boolean _isPowerVr = false; static private boolean _isPowerVr = false;
public void setIsPowerVR(boolean status) { MainActivity._isPowerVr = status; } public void setIsPowerVR(boolean status) { MainActivity._isPowerVr = status; }
static public boolean isPowerVR() { return _isPowerVr; } static public boolean isPowerVR() { return _isPowerVr; }
@SuppressWarnings("deprecation")
public void vibrate(int milliSeconds) { public void vibrate(int milliSeconds) {
Vibrator v = (Vibrator)this.getSystemService(VIBRATOR_SERVICE); Vibrator v = (Vibrator) getSystemService(VIBRATOR_SERVICE);
v.vibrate(milliSeconds); if (android.os.Build.VERSION.SDK_INT >= 26) {
v.vibrate(android.os.VibrationEffect.createOneShot(milliSeconds,
android.os.VibrationEffect.DEFAULT_AMPLITUDE));
} else {
v.vibrate(milliSeconds);
}
} }
private void createAlertDialog(boolean hasOkButton, boolean hasCancelButton, boolean preventBackKey) { private void createAlertDialog(boolean hasOkButton, boolean hasCancelButton, boolean preventBackKey) {
@@ -144,9 +203,16 @@ public class MainActivity extends Activity {
@Override @Override
public void onWindowFocusChanged(boolean hasFocus) { public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
//System.out.println("Focus has changed. Has Focus? " + hasFocus);
super.onWindowFocusChanged(hasFocus); super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}
} }
@Override @Override
@@ -184,9 +250,12 @@ public class MainActivity extends Activity {
return; return;
} }
if (event.getAction() == KeyEvent.ACTION_DOWN) if (event.getAction() == KeyEvent.ACTION_DOWN) {
nativeOnKeyDown(keyCode); nativeOnKeyDown(keyCode);
else if (event.getAction() == KeyEvent.ACTION_UP) int unicodeChar = event.getUnicodeChar(event.getMetaState());
if (unicodeChar > 0)
nativeTextChar(unicodeChar);
} else if (event.getAction() == KeyEvent.ACTION_UP)
nativeOnKeyUp(keyCode); nativeOnKeyUp(keyCode);
} }
@@ -347,22 +416,15 @@ public class MainActivity extends Activity {
} }
public int getScreenWidth() { public int getScreenWidth() {
Display display = ((WindowManager)this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); return _screenWidth;
int out = Math.max(display.getWidth(), display.getHeight());
//System.out.println("getwidth: " + out);
return out;
} }
public int getScreenHeight() { public int getScreenHeight() {
Display display = ((WindowManager)this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); return _screenHeight;
int out = Math.min(display.getWidth(), display.getHeight());
//System.out.println("getheight: " + out);
return out;
} }
public float getPixelsPerMillimeter() { public float getPixelsPerMillimeter() {
DisplayMetrics metrics = new DisplayMetrics(); android.util.DisplayMetrics metrics = getResources().getDisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
return (metrics.xdpi + metrics.ydpi) * 0.5f / 25.4f; return (metrics.xdpi + metrics.ydpi) * 0.5f / 25.4f;
} }
@@ -465,8 +527,8 @@ public class MainActivity extends Activity {
MainActivity.this.mDialog.show(); MainActivity.this.mDialog.show();
MainActivity.this.mDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); MainActivity.this.mDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
MainActivity.this.mDialog.getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); MainActivity.this.mDialog.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
//MainActivity.this.getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); //MainActivity.this.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
} }
}); });
} }
@@ -516,6 +578,20 @@ public class MainActivity extends Activity {
public void buyGame() {} public void buyGame() {}
public int getKeyFromKeyCode(int keyCode, int metaState, int deviceId) {
android.view.KeyCharacterMap kcm = android.view.KeyCharacterMap.load(deviceId);
return kcm.get(keyCode, metaState);
}
public void openURL(String url) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(url));
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getPlatformStringVar(int id) { public String getPlatformStringVar(int id) {
if (id == 0) return android.os.Build.MODEL; if (id == 0) return android.os.Build.MODEL;
return null; return null;
@@ -604,10 +680,11 @@ public class MainActivity extends Activity {
// //
native void nativeRegisterThis(); native void nativeRegisterThis();
native void nativeUnregisterThis(); native void nativeUnregisterThis();
native static void nativeOnCreate(); native static void nativeOnCreate(int screenWidth, int screenHeight);
native static void nativeOnDestroy(); native static void nativeOnDestroy();
native static void nativeOnKeyDown(int key); native static void nativeOnKeyDown(int key);
native static void nativeOnKeyUp(int key); native static void nativeOnKeyUp(int key);
native static void nativeTextChar(int unicodeChar);
native static boolean nativeHandleBack(boolean isDown); native static boolean nativeHandleBack(boolean isDown);
native static void nativeMouseDown(int pointerId, int buttonId, float x, float y); native static void nativeMouseDown(int pointerId, int buttonId, float x, float y);
native static void nativeMouseUp(int pointerId, int buttonId, float x, float y); native static void nativeMouseUp(int pointerId, int buttonId, float x, float y);

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.7) cmake_minimum_required(VERSION 3.5.0)
find_package (Threads) find_package (Threads)
include_directories("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni/RaknetSources") include_directories("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni/RaknetSources")
add_subdirectory("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni" "${CMAKE_CURRENT_BINARY_DIR}/raknet") add_subdirectory("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni" "${CMAKE_CURRENT_BINARY_DIR}/raknet")
@@ -19,6 +19,7 @@ set(CompileFiles ../../src/main.cpp
../../src/client/IConfigListener.cpp ../../src/client/IConfigListener.cpp
../../src/client/Minecraft.cpp ../../src/client/Minecraft.cpp
../../src/client/Options.cpp ../../src/client/Options.cpp
../../src/client/Option.cpp
../../src/client/OptionsFile.cpp ../../src/client/OptionsFile.cpp
../../src/client/OptionStrings.cpp ../../src/client/OptionStrings.cpp
../../src/client/gamemode/GameMode.cpp ../../src/client/gamemode/GameMode.cpp
@@ -151,6 +152,9 @@ set(CompileFiles ../../src/main.cpp
../../src/world/level/tile/entity/TileEntity.cpp ../../src/world/level/tile/entity/TileEntity.cpp
../../src/world/level/tile/entity/FurnaceTileEntity.cpp ../../src/world/level/tile/entity/FurnaceTileEntity.cpp
../../src/world/phys/HitResult.cpp) ../../src/world/phys/HitResult.cpp)
message(${CMAKE_LIBRARY_ARCHITECTURE})
add_executable(mcpe_server ${CompileFiles}) add_executable(mcpe_server ${CompileFiles})
target_link_libraries(mcpe_server raknet ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(mcpe_server raknet ${CMAKE_THREAD_LIBS_INIT})
target_include_directories(mcpe_server PUBLIC
"../../src/"
)

View File

@@ -4,10 +4,11 @@ include $(CLEAR_VARS)
LOCAL_MODULE := RakNet LOCAL_MODULE := RakNet
MY_PREFIX := $(LOCAL_PATH)/RakNetSources/ MY_PREFIX := $(LOCAL_PATH)/RaknetSources/
MY_SOURCES := $(wildcard $(MY_PREFIX)*.cpp) MY_SOURCES := $(wildcard $(MY_PREFIX)*.cpp)
LOCAL_SRC_FILES += $(MY_SOURCES:$(MY_PREFIX)%=RakNetSources/%) LOCAL_SRC_FILES += $(MY_SOURCES:$(MY_PREFIX)%=RaknetSources/%)
LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS) LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS)
LOCAL_CPPFLAGS += -frtti
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)

View File

@@ -5,13 +5,13 @@
#include <stdio.h> // RAKNET_DEBUG_PRINTF #include <stdio.h> // RAKNET_DEBUG_PRINTF
#include "RakAssert.h" #include "RakAssert.h"
#if defined(ANDROID) #if defined(ANDROID)
#include <asm/io.h> // <asm/io.h> not needed and unavailable on arm64
#elif defined(_WIN32) || defined(__CYGWIN__) #elif defined(_WIN32) || defined(__CYGWIN__)
#include <io.h> #include <io.h>
#elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __S3E__ ) // #elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __S3E__ )
#include <sys/io.h> // #include <sys/io.h>
#endif #endif

View File

@@ -124,7 +124,7 @@ static const unsigned int MAX_OFFLINE_DATA_LENGTH=400; // I set this because I l
#pragma warning(disable:4309) // 'initializing' : truncation of constant value #pragma warning(disable:4309) // 'initializing' : truncation of constant value
#endif #endif
// Make sure highest bit is 0, so isValid in DatagramHeaderFormat is false // Make sure highest bit is 0, so isValid in DatagramHeaderFormat is false
static const char OFFLINE_MESSAGE_DATA_ID[16]={0x00,0xFF,0xFF,0x00,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFD,0xFD,0x12,0x34,0x56,0x78}; static const unsigned char OFFLINE_MESSAGE_DATA_ID[16]={0x00,0xFF,0xFF,0x00,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFD,0xFD,0x12,0x34,0x56,0x78};
struct PacketFollowedByData struct PacketFollowedByData
{ {

View File

@@ -71,6 +71,7 @@ public:
virtual void saveScreenshot(const std::string& filename, int glWidth, int glHeight) {} virtual void saveScreenshot(const std::string& filename, int glWidth, int glHeight) {}
virtual TextureData loadTexture(const std::string& filename_, bool textureFolder) { return TextureData(); } virtual TextureData loadTexture(const std::string& filename_, bool textureFolder) { return TextureData(); }
virtual TextureData loadTextureFromMemory(const unsigned char* data, size_t size) { return TextureData(); }
virtual void playSound(const std::string& fn, float volume, float pitch) {} virtual void playSound(const std::string& fn, float volume, float pitch) {}
@@ -96,9 +97,6 @@ public:
virtual std::string getDateString(int s) { return ""; } virtual std::string getDateString(int s) { return ""; }
//virtual void createUserInputScreen(const char* types) {} //virtual void createUserInputScreen(const char* types) {}
virtual int checkLicense() { return 0; }
virtual bool hasBuyButtonWhenInvalidLicense() { return false; }
virtual void uploadPlatformDependentData(int id, void* data) {} virtual void uploadPlatformDependentData(int id, void* data) {}
virtual BinaryBlob readAssetFile(const std::string& filename) { return BinaryBlob(); } virtual BinaryBlob readAssetFile(const std::string& filename) { return BinaryBlob(); }
virtual void _tick() {} virtual void _tick() {}
@@ -117,7 +115,7 @@ public:
virtual bool isSuperFast() = 0; virtual bool isSuperFast() = 0;
#endif #endif
virtual void buyGame() {} virtual void openURL(const std::string& url) {}
virtual void finish() {} virtual void finish() {}

View File

@@ -68,9 +68,6 @@ public:
_methodGetDateString(0), _methodGetDateString(0),
_methodCheckLicense(0),
_methodHasBuyButton(0),
_methodBuyGame(0),
_methodVibrate(0), _methodVibrate(0),
_methodSupportsTouchscreen(0), _methodSupportsTouchscreen(0),
_methodSetIsPowerVR(0), _methodSetIsPowerVR(0),
@@ -104,6 +101,7 @@ public:
int getScreenWidth() { return _screenWidth; } int getScreenWidth() { return _screenWidth; }
int getScreenHeight() { return _screenHeight; } int getScreenHeight() { return _screenHeight; }
void setScreenDimensions(int w, int h) { _screenWidth = w; _screenHeight = h; }
// Note, this has to be called from the main thread (e.g. do it from JNI_onLoad) // Note, this has to be called from the main thread (e.g. do it from JNI_onLoad)
// Somewhere between calling this, and calling the AppPlatform methods, // Somewhere between calling this, and calling the AppPlatform methods,
@@ -146,10 +144,6 @@ public:
_methodGetDateString = env->GetMethodID( _activityClass, "getDateString", "(I)Ljava/lang/String;"); _methodGetDateString = env->GetMethodID( _activityClass, "getDateString", "(I)Ljava/lang/String;");
_methodCheckLicense = env->GetMethodID( _activityClass, "checkLicense", "()I");
_methodHasBuyButton = env->GetMethodID( _activityClass, "hasBuyButtonWhenInvalidLicense", "()Z");
_methodBuyGame = env->GetMethodID( _activityClass, "buyGame", "()V");
_methodVibrate = env->GetMethodID( _activityClass, "vibrate", "(I)V"); _methodVibrate = env->GetMethodID( _activityClass, "vibrate", "(I)V");
_methodSupportsTouchscreen = env->GetMethodID( _activityClass, "supportsTouchscreen", "()Z"); _methodSupportsTouchscreen = env->GetMethodID( _activityClass, "supportsTouchscreen", "()Z");
_methodSetIsPowerVR = env->GetMethodID( _activityClass, "setIsPowerVR", "(Z)V"); _methodSetIsPowerVR = env->GetMethodID( _activityClass, "setIsPowerVR", "(Z)V");
@@ -157,6 +151,8 @@ public:
_methodGetPixelsPerMillimeter = env->GetMethodID( _activityClass, "getPixelsPerMillimeter", "()F"); _methodGetPixelsPerMillimeter = env->GetMethodID( _activityClass, "getPixelsPerMillimeter", "()F");
_methodGetPlatformStringVar = env->GetMethodID( _activityClass, "getPlatformStringVar", "(I)Ljava/lang/String;"); _methodGetPlatformStringVar = env->GetMethodID( _activityClass, "getPlatformStringVar", "(I)Ljava/lang/String;");
// custom helper to launch external URLs
_methodOpenURL = env->GetMethodID(_activityClass, "openURL", "(Ljava/lang/String;)V");
_classWindow = (jclass)env->NewGlobalRef(env->FindClass("android/view/Window")); _classWindow = (jclass)env->NewGlobalRef(env->FindClass("android/view/Window"));
_classContext = (jclass)env->NewGlobalRef(env->FindClass("android/content/Context")); _classContext = (jclass)env->NewGlobalRef(env->FindClass("android/content/Context"));
@@ -192,14 +188,20 @@ public:
// be rewritten later on anyway // be rewritten later on anyway
int initConsts() { int initConsts() {
LOGI("initConsts: start\n");
JVMAttacher ta(_vm); JVMAttacher ta(_vm);
JNIEnv* env = ta.getEnv(); JNIEnv* env = ta.getEnv();
LOGI("initConsts: getting method IDs\n");
jmethodID fWidth = env->GetMethodID( _activityClass, "getScreenWidth", "()I"); jmethodID fWidth = env->GetMethodID( _activityClass, "getScreenWidth", "()I");
LOGI("initConsts: got fWidth=%p\n", fWidth);
jmethodID fHeight = env->GetMethodID( _activityClass, "getScreenHeight", "()I"); jmethodID fHeight = env->GetMethodID( _activityClass, "getScreenHeight", "()I");
LOGI("initConsts: got fHeight=%p, calling getScreenWidth\n", fHeight);
_screenWidth = env->CallIntMethod(instance, fWidth); _screenWidth = env->CallIntMethod(instance, fWidth);
LOGI("initConsts: screenWidth=%d, calling getScreenHeight\n", _screenWidth);
_screenHeight = env->CallIntMethod(instance, fHeight); _screenHeight = env->CallIntMethod(instance, fHeight);
LOGI("initConsts: screenHeight=%d, done\n", _screenHeight);
} }
void tick() { void tick() {
@@ -376,8 +378,9 @@ public:
JVMAttacher ta(_vm); JVMAttacher ta(_vm);
JNIEnv* env = ta.getEnv(); JNIEnv* env = ta.getEnv();
std::string path = textureFolder ? "images/" + filename : filename;
jintArray arr = (jintArray)env->CallObjectMethod( jintArray arr = (jintArray)env->CallObjectMethod(
instance, _getImageData, env->NewStringUTF(filename.c_str())); instance, _getImageData, env->NewStringUTF(path.c_str()));
if (!arr) if (!arr)
return TextureData(); return TextureData();
@@ -464,37 +467,15 @@ public:
env->ReleaseStringUTFChars(stringVar, str); env->ReleaseStringUTFChars(stringVar, str);
return out; return out;
} }
// Opens a webpage using an Android intent. Called from native code.
int checkLicense() { virtual void openURL(const std::string& url) {
if (!_isInited) return -2; if (!_isInited || !_methodOpenURL) return;
if (!_methodCheckLicense) return -2; JVMAttacher ta(_vm);
JNIEnv* env = ta.getEnv();
JVMAttacher ta(_vm); jstring jurl = env->NewStringUTF(url.c_str());
JNIEnv* env = ta.getEnv(); env->CallVoidMethod(instance, _methodOpenURL, jurl);
env->DeleteLocalRef(jurl);
return env->CallIntMethod(instance, _methodCheckLicense); }
}
bool hasBuyButtonWhenInvalidLicense() {
if (!_isInited) return false;
if (!_methodHasBuyButton) return false;
JVMAttacher ta(_vm);
JNIEnv* env = ta.getEnv();
return JNI_TRUE == env->CallBooleanMethod(instance, _methodHasBuyButton);
}
void buyGame() {
if (!_isInited) return;
if (!_methodBuyGame) return;
JVMAttacher ta(_vm);
JNIEnv* env = ta.getEnv();
env->CallVoidMethod(instance, _methodBuyGame);
}
virtual void finish() { virtual void finish() {
if (!_isInited) return; if (!_isInited) return;
if (!_methodFinish) return; if (!_methodFinish) return;
@@ -636,10 +617,6 @@ private:
jmethodID _methodGetDateString; jmethodID _methodGetDateString;
jmethodID _methodCheckLicense;
jmethodID _methodHasBuyButton;
jmethodID _methodBuyGame;
jmethodID _getScreenWidth; jmethodID _getScreenWidth;
jmethodID _getScreenHeight; jmethodID _getScreenHeight;
jmethodID _methodGetPixelsPerMillimeter; jmethodID _methodGetPixelsPerMillimeter;
@@ -649,6 +626,7 @@ private:
jmethodID _methodIsNetworkEnabled; jmethodID _methodIsNetworkEnabled;
jmethodID _methodGetPlatformStringVar; jmethodID _methodGetPlatformStringVar;
jmethodID _methodOpenURL; // new JNI method for launching browser
jclass _classWindow; jclass _classWindow;
jclass _classContext; jclass _classContext;

0
src/AppPlatform_glfw.cpp Executable file → Normal file
View File

View File

@@ -3,6 +3,8 @@
#include "AppPlatform.h" #include "AppPlatform.h"
#include "platform/log.h" #include "platform/log.h"
#include "platform/HttpClient.h"
#include "platform/PngLoader.h"
#include "client/renderer/gles.h" #include "client/renderer/gles.h"
#include "world/level/storage/FolderMethods.h" #include "world/level/storage/FolderMethods.h"
#include <png.h> #include <png.h>
@@ -10,6 +12,13 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <ctime>
#include "util/StringUtils.h"
#ifdef _WIN32
#include <windows.h>
#include <shellapi.h>
#endif
static void png_funcReadFile(png_structp pngPtr, png_bytep data, png_size_t length) { static void png_funcReadFile(png_structp pngPtr, png_bytep data, png_size_t length) {
((std::istream*)png_get_io_ptr(pngPtr))->read((char*)data, length); ((std::istream*)png_get_io_ptr(pngPtr))->read((char*)data, length);
@@ -22,7 +31,7 @@ public:
{ {
} }
BinaryBlob readAssetFile(const std::string& filename) { BinaryBlob readAssetFile(const std::string& filename) override {
FILE* fp = fopen(("data/" + filename).c_str(), "r"); FILE* fp = fopen(("data/" + filename).c_str(), "r");
if (!fp) if (!fp)
return BinaryBlob(); return BinaryBlob();
@@ -39,7 +48,7 @@ public:
return blob; return blob;
} }
void saveScreenshot(const std::string& filename, int glWidth, int glHeight) { void saveScreenshot(const std::string& filename, int glWidth, int glHeight) override {
//@todo //@todo
} }
@@ -47,12 +56,21 @@ public:
return (p & 0xff00ff00) | ((p >> 16) & 0xff) | ((p << 16) & 0xff0000); return (p & 0xff00ff00) | ((p >> 16) & 0xff) | ((p << 16) & 0xff0000);
} }
TextureData loadTexture(const std::string& filename_, bool textureFolder) TextureData loadTexture(const std::string& filename_, bool textureFolder) override
{ {
// Support fetching PNG textures via HTTP/HTTPS (for skins, etc)
if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) {
std::vector<unsigned char> body;
if (HttpClient::download(filename_, body) && !body.empty()) {
return loadTextureFromMemory(body.data(), body.size());
}
return TextureData();
}
TextureData out; TextureData out;
std::string filename = textureFolder? "data/images/" + filename_ std::string filename = textureFolder? "data/images/" + filename_
: filename_; : filename_;
std::ifstream source(filename.c_str(), std::ios::binary); std::ifstream source(filename.c_str(), std::ios::binary);
if (source) { if (source) {
@@ -101,29 +119,37 @@ public:
} }
} }
std::string getDateString(int s) { TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override {
std::stringstream ss; return loadPngFromMemory(data, size);
ss << s << " s (UTC)";
return ss.str();
} }
virtual int checkLicense() { virtual std::string getDateString(int s) override {
static int _z = 0;//20; time_t tm = s;
_z--;
if (_z < 0) return 0; char mbstr[100];
//if (_z < 0) return 107; std::strftime(mbstr, sizeof(mbstr), "%F %T", std::localtime(&tm));
return -2;
return std::string(mbstr);
} }
virtual int getScreenWidth() { return 854; }; virtual int getScreenWidth() override { return 854; };
virtual int getScreenHeight() { return 480; }; virtual int getScreenHeight() override { return 480; };
virtual float getPixelsPerMillimeter(); virtual float getPixelsPerMillimeter() override;
virtual bool supportsTouchscreen() { return true; } virtual bool supportsTouchscreen() override { return true; }
virtual bool hasBuyButtonWhenInvalidLicense() { return false; }
virtual void openURL(const std::string& url) override {
#ifdef _WIN32
ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
#elif __linux__
std::string command = "xdg-open " + url;
system(command.c_str());
#endif
}
GLFWwindow* window;
private: private:
}; };
#endif /*APPPLATFORM_GLFW_H__*/ #endif /*APPPLATFORM_GLFW_H__*/

View File

@@ -41,17 +41,6 @@ public:
std::string getDateString(int s); std::string getDateString(int s);
virtual int checkLicense() {
return 0;
static int _z = 20;
_z--;
if (_z < 0) return 0;
//if (_z < 0) return 107;
return -2;
}
virtual void buyGame();
virtual int getScreenWidth(); virtual int getScreenWidth();
virtual int getScreenHeight(); virtual int getScreenHeight();
virtual float getPixelsPerMillimeter(); virtual float getPixelsPerMillimeter();

View File

@@ -175,10 +175,6 @@ BinaryBlob AppPlatform_iOS::readAssetFile(const std::string& filename_) {
return BinaryBlob(bytes, numBytes); return BinaryBlob(bytes, numBytes);
} }
void AppPlatform_iOS::buyGame() {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=479516143&mt=8"]];
}
std::string AppPlatform_iOS::getDateString(int s) { std::string AppPlatform_iOS::getDateString(int s) {
NSDate* date = [NSDate dateWithTimeIntervalSince1970:s]; NSDate* date = [NSDate dateWithTimeIntervalSince1970:s];

View File

@@ -14,4 +14,3 @@ float AppPlatform_win32::getPixelsPerMillimeter() {
} }
bool AppPlatform_win32::supportsTouchscreen() { return true; } bool AppPlatform_win32::supportsTouchscreen() { return true; }
bool AppPlatform_win32::hasBuyButtonWhenInvalidLicense() { return true; }

View File

@@ -3,12 +3,17 @@
#include "AppPlatform.h" #include "AppPlatform.h"
#include "platform/log.h" #include "platform/log.h"
#include "platform/HttpClient.h"
#include "platform/PngLoader.h"
#include "client/renderer/gles.h" #include "client/renderer/gles.h"
#include "world/level/storage/FolderMethods.h" #include "world/level/storage/FolderMethods.h"
#include "util/StringUtils.h"
#include <png.h> #include <png.h>
#include <cmath> #include <cmath>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <windows.h>
#include <shellapi.h>
static void png_funcReadFile(png_structp pngPtr, png_bytep data, png_size_t length) { static void png_funcReadFile(png_structp pngPtr, png_bytep data, png_size_t length) {
((std::istream*)png_get_io_ptr(pngPtr))->read((char*)data, length); ((std::istream*)png_get_io_ptr(pngPtr))->read((char*)data, length);
@@ -48,10 +53,19 @@ public:
TextureData loadTexture(const std::string& filename_, bool textureFolder) TextureData loadTexture(const std::string& filename_, bool textureFolder)
{ {
// Support fetching PNG textures via HTTP/HTTPS (for skins, etc).
if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) {
std::vector<unsigned char> body;
if (HttpClient::download(filename_, body) && !body.empty()) {
return loadTextureFromMemory(body.data(), body.size());
}
return TextureData();
}
TextureData out; TextureData out;
std::string filename = textureFolder? "data/images/" + filename_ std::string filename = textureFolder? "data/images/" + filename_
: filename_; : filename_;
std::ifstream source(filename.c_str(), std::ios::binary); std::ifstream source(filename.c_str(), std::ios::binary);
if (source) { if (source) {
@@ -100,18 +114,15 @@ public:
} }
} }
std::string getDateString(int s) { TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override {
std::stringstream ss; return loadPngFromMemory(data, size);
ss << s << " s (UTC)";
return ss.str();
} }
time_t tm = s;
virtual int checkLicense() { char mbstr[100];
static int _z = 0;//20; std::strftime(mbstr, sizeof(mbstr), "%F %T", std::localtime(&tm));
_z--;
if (_z < 0) return 0; return std::string(mbstr);
//if (_z < 0) return 107;
return -2;
} }
virtual int getScreenWidth(); virtual int getScreenWidth();
@@ -120,7 +131,10 @@ public:
virtual float getPixelsPerMillimeter(); virtual float getPixelsPerMillimeter();
virtual bool supportsTouchscreen(); virtual bool supportsTouchscreen();
virtual bool hasBuyButtonWhenInvalidLicense();
virtual void openURL(const std::string& url) {
ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
}
private: private:
}; };

View File

@@ -18,6 +18,7 @@
//#include "world/level/storage/FolderMethods.h" //#include "world/level/storage/FolderMethods.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "client/gui/screens/StartMenuScreen.h" #include "client/gui/screens/StartMenuScreen.h"
#include "client/gui/screens/UsernameScreen.h"
#endif #endif
#include "client/player/LocalPlayer.h" #include "client/player/LocalPlayer.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
@@ -110,8 +111,12 @@ void NinecraftApp::init()
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
LOGI("This: %p\n", this); LOGI("This: %p\n", this);
screenChooser.setScreen(SCREEN_STARTMENU); screenChooser.setScreen(SCREEN_STARTMENU);
if (options.getBooleanValue(OPTIONS_FIRST_LAUNCH)) {
options.toggle(OPTIONS_FIRST_LAUNCH);
setScreen(new UsernameScreen());
}
#else #else
user->name = "Server";
hostMultiplayer(); hostMultiplayer();
#endif #endif
} }
@@ -240,8 +245,9 @@ void NinecraftApp::initGLStates()
glCullFace(GL_BACK); glCullFace(GL_BACK);
glEnable2(GL_TEXTURE_2D); glEnable2(GL_TEXTURE_2D);
#ifndef _EMSCRIPTEN_
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
#endif
// Both updates isPowerVR flag in java and returns if the graphics chip is PowerVR SGX or not // Both updates isPowerVR flag in java and returns if the graphics chip is PowerVR SGX or not
_powerVr = platform()->isPowerVR(); _powerVr = platform()->isPowerVR();
#ifdef __APPLE__ #ifdef __APPLE__

View File

@@ -4,7 +4,13 @@ namespace Common {
std::string getGameVersionString(const std::string& versionSuffix /* = "" */) std::string getGameVersionString(const std::string& versionSuffix /* = "" */)
{ {
return std::string("v0.6.1") + versionSuffix + " alpha"; std::string result = std::string("v0.6.1") + versionSuffix;
// append 64-bit port marker only on Android 64bit targets
#if defined(ANDROID) && (defined(__aarch64__) || defined(__x86_64__))
result += " (64-bit port)";
#endif
result += " alpha";
return result;
} }
}; };

View File

@@ -1,21 +0,0 @@
#ifndef NET_MINECRAFT_CLIENT__KeyMapping_H__
#define NET_MINECRAFT_CLIENT__KeyMapping_H__
//package net.minecraft.client;
#include <string>
class KeyMapping
{
public:
std::string name;
int key;
KeyMapping() {}
KeyMapping(const std::string& name_, int key_)
: name(name_),
key(key_)
{}
};
#endif /*NET_MINECRAFT_CLIENT__KeyMapping_H__*/

View File

@@ -1,5 +1,11 @@
#include "Minecraft.h" #include "Minecraft.h"
#include "client/Options.h"
#include "client/player/input/IBuildInput.h" #include "client/player/input/IBuildInput.h"
#include "platform/input/Keyboard.h"
#include "world/item/Item.h"
#include "world/item/ItemInstance.h"
#include <string>
#include <cstdlib>
#if defined(APPLE_DEMO_PROMOTION) #if defined(APPLE_DEMO_PROMOTION)
#define NO_NETWORK #define NO_NETWORK
@@ -8,88 +14,36 @@
#if defined(RPI) #if defined(RPI)
#define CREATORMODE #define CREATORMODE
#endif #endif
#include "../network/RakNetInstance.h" #include "../network/RakNetInstance.h"
#include "../network/ClientSideNetworkHandler.h" #include "../network/ClientSideNetworkHandler.h"
#include "../network/ServerSideNetworkHandler.h" #include "../network/ServerSideNetworkHandler.h"
//#include "../network/Packet.h" //#include "../network/Packet.h"
#include "../world/entity/player/Inventory.h" #include "../world/entity/player/Inventory.h"
#include "../world/level/chunk/ChunkCache.h"
#include "../world/level/tile/Tile.h" #include "../world/level/tile/Tile.h"
#include "../world/level/storage/LevelStorageSource.h" #include "../world/level/storage/LevelStorageSource.h"
#include "../world/level/storage/LevelStorage.h" #include "../world/level/storage/LevelStorage.h"
#include "player/input/KeyboardInput.h" #include "player/input/KeyboardInput.h"
#include "player/input/ControllerTurnInput.h"
#include "player/input/XperiaPlayInput.h"
#include "world/level/chunk/ChunkSource.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "player/input/touchscreen/TouchInputHolder.h" #include "player/input/touchscreen/TouchInputHolder.h"
#endif
#include "player/LocalPlayer.h"
#include "gamemode/CreativeMode.h"
#include "gamemode/SurvivalMode.h"
#include "player/LocalPlayer.h"
#ifndef STANDALONE_SERVER
#include "particle/ParticleEngine.h" #include "particle/ParticleEngine.h"
#include "gui/Screen.h" #include "gui/Screen.h"
#include "gui/Font.h" #include "gui/Font.h"
#include "gui/screens/RenameMPLevelScreen.h" #include "gui/screens/RenameMPLevelScreen.h"
#include "gui/screens/ConsoleScreen.h"
#include "gui/screens/ChatScreen.h"
#include "sound/SoundEngine.h" #include "sound/SoundEngine.h"
#endif
#include "../platform/CThread.h"
#include "../platform/input/Mouse.h"
#include "../AppPlatform.h"
#include "../Performance.h"
#include "../LicenseCodes.h"
#include "../util/PerfTimer.h"
#include "../util/PerfRenderer.h"
#include "player/input/MouseBuildInput.h"
#include "../world/Facing.h"
#include "../network/packet/PlaceBlockPacket.h"
#include "player/input/IInputHolder.h"
#ifndef STANDALONE_SERVER
#include "player/input/touchscreen/TouchscreenInput.h" #include "player/input/touchscreen/TouchscreenInput.h"
#include "renderer/Chunk.h"
#include "player/input/ControllerTurnInput.h"
#include "player/input/XperiaPlayInput.h"
#endif
#include "player/input/MouseTurnInput.h"
#include "../world/entity/MobFactory.h"
#include "../world/level/MobSpawner.h"
#include "../util/Mth.h"
#include "../network/packet/InteractPacket.h"
#ifndef STANDALONE_SERVER
#include "gui/screens/PrerenderTilesScreen.h" #include "gui/screens/PrerenderTilesScreen.h"
#include "renderer/Textures.h" #include "renderer/Textures.h"
#include "gui/screens/DeathScreen.h" #include "gui/screens/DeathScreen.h"
#endif
#include "../network/packet/RespawnPacket.h"
#include "IConfigListener.h"
#include "../world/entity/MobCategory.h"
#ifndef STANDALONE_SERVER
#include "gui/screens/FurnaceScreen.h" #include "gui/screens/FurnaceScreen.h"
#endif
#include "../world/Difficulty.h"
#include "../server/ServerLevel.h"
#ifdef CREATORMODE
#include "../server/CreatorLevel.h"
#endif
#include "../network/packet/AdventureSettingsPacket.h"
#include "../network/packet/SetSpawnPositionPacket.h"
#include "../network/command/CommandServer.h"
#include "gamemode/CreatorMode.h"
#ifndef STANDALONE_SERVER
#include "gui/screens/ArmorScreen.h" #include "gui/screens/ArmorScreen.h"
#endif
#include "../world/level/levelgen/synth/ImprovedNoise.h"
#ifndef STANDALONE_SERVER
#include "renderer/tileentity/TileEntityRenderDispatcher.h" #include "renderer/tileentity/TileEntityRenderDispatcher.h"
#endif
#ifndef STANDALONE_SERVER
#include "renderer/ptexture/DynamicTexture.h" #include "renderer/ptexture/DynamicTexture.h"
#include "renderer/GameRenderer.h" #include "renderer/GameRenderer.h"
#include "renderer/ItemInHandRenderer.h" #include "renderer/ItemInHandRenderer.h"
@@ -99,8 +53,42 @@
#include "gui/Font.h" #include "gui/Font.h"
#include "gui/screens/RenameMPLevelScreen.h" #include "gui/screens/RenameMPLevelScreen.h"
#include "sound/SoundEngine.h" #include "sound/SoundEngine.h"
#endif // STANDALONE_SERVER
#include "player/LocalPlayer.h"
#include "gamemode/CreativeMode.h"
#include "gamemode/SurvivalMode.h"
#include "player/LocalPlayer.h"
#include "../platform/CThread.h"
#include "../platform/input/Mouse.h"
#include "../AppPlatform.h"
#include "../LicenseCodes.h"
#include "../util/PerfTimer.h"
#include "../util/PerfRenderer.h"
#include "player/input/MouseBuildInput.h"
#include "player/input/IInputHolder.h"
#include "player/input/MouseTurnInput.h"
#include "../world/entity/MobFactory.h"
#include "../world/level/MobSpawner.h"
#include "../util/Mth.h"
#include "../network/packet/InteractPacket.h"
#include "../network/packet/RespawnPacket.h"
#include "../network/packet/AdventureSettingsPacket.h"
#include "../network/packet/SetSpawnPositionPacket.h"
#include "IConfigListener.h"
#include "../world/entity/MobCategory.h"
#include "../world/Difficulty.h"
#include "../server/ServerLevel.h"
#ifdef CREATORMODE
#include "../server/CreatorLevel.h"
#endif #endif
#include "../network/command/CommandServer.h"
#include "gamemode/CreatorMode.h"
static void checkGlError(const char* tag) { static void checkGlError(const char* tag) {
#ifdef GLDEBUG #ifdef GLDEBUG
while (1) { while (1) {
@@ -128,8 +116,7 @@ int Minecraft::customDebugId = Minecraft::CDI_NONE;
bool Minecraft::useAmbientOcclusion = false; bool Minecraft::useAmbientOcclusion = false;
Minecraft::Minecraft() Minecraft::Minecraft() :
: user(NULL),
level(NULL), level(NULL),
player(NULL), player(NULL),
cameraTargetPlayer(NULL), cameraTargetPlayer(NULL),
@@ -187,7 +174,7 @@ Minecraft::Minecraft()
_powerVr(false), _powerVr(false),
commandPort(4711), commandPort(4711),
reserved_d1(0),reserved_d2(0), reserved_d1(0),reserved_d2(0),
reserved_f1(0),reserved_f2(0) reserved_f1(0),reserved_f2(0), options(this)
{ {
//#ifdef ANDROID //#ifdef ANDROID
@@ -234,7 +221,6 @@ Minecraft::~Minecraft()
} }
//delete player; //delete player;
delete user;
delete inputHolder; delete inputHolder;
delete storageSource; delete storageSource;
@@ -349,6 +335,7 @@ void Minecraft::leaveGame(bool renameLevel /*=false*/)
_running = false; _running = false;
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
gui.clearMessages();
if (renameLevel) { if (renameLevel) {
setScreen(new RenameMPLevelScreen(LevelStorageSource::TempLevelId)); setScreen(new RenameMPLevelScreen(LevelStorageSource::TempLevelId));
} }
@@ -449,20 +436,21 @@ void Minecraft::update() {
// } // }
//} //}
if (pause && level != NULL) { // If we're paused (local world / invisible server), freeze gameplay and
float lastA = timer.a; // networking and only keep UI responsive.
timer.advanceTime(); bool freezeGame = pause;
timer.a = lastA;
} else { if (!freezeGame) {
timer.advanceTime(); timer.advanceTime();
} }
if (raknetInstance) { if (raknetInstance && !freezeGame) {
raknetInstance->runEvents(netCallback); raknetInstance->runEvents(netCallback);
} }
TIMER_PUSH("tick"); TIMER_PUSH("tick");
int toTick = timer.ticks; int toTick = freezeGame ? 1 : timer.ticks;
if (!freezeGame) timer.ticks = 0;
for (int i = 0; i < toTick; ++i, ++ticks) for (int i = 0; i < toTick; ++i, ++ticks)
tick(i, toTick-1); tick(i, toTick-1);
@@ -489,16 +477,15 @@ void Minecraft::update() {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
checkGlError("Update finished"); checkGlError("Update finished");
if (options.renderDebug) { if (options.getBooleanValue(OPTIONS_RENDER_DEBUG)) {
#ifndef PLATFORM_DESKTOP
if (!PerfTimer::enabled) { if (!PerfTimer::enabled) {
PerfTimer::reset(); PerfTimer::reset();
PerfTimer::enabled = true; PerfTimer::enabled = true;
} }
//TIMER_PUSH("debugfps");
_perfRenderer->renderFpsMeter(1); _perfRenderer->renderFpsMeter(1);
checkGlError("render debug"); checkGlError("render debug");
//TIMER_POP(); #endif
} else { } else {
PerfTimer::enabled = false; PerfTimer::enabled = false;
} }
@@ -558,7 +545,7 @@ void Minecraft::tick(int nTick, int maxTick) {
TIMER_POP_PUSH("levelRenderer"); TIMER_POP_PUSH("levelRenderer");
levelRenderer->tick(); levelRenderer->tick();
#endif #endif
level->difficulty = options.difficulty; level->difficulty = options.getIntValue(OPTIONS_DIFFICULTY);
if (level->isClientSide) level->difficulty = Difficulty::EASY; if (level->isClientSide) level->difficulty = Difficulty::EASY;
TIMER_POP_PUSH("level"); TIMER_POP_PUSH("level");
@@ -588,7 +575,9 @@ void Minecraft::tick(int nTick, int maxTick) {
#endif #endif
} }
TIMER_POP_PUSH("particles"); TIMER_POP_PUSH("particles");
particleEngine->tick(); if (!pause) {
particleEngine->tick();
}
if (screen) { if (screen) {
screenMutex = true; screenMutex = true;
screen->tick(); screen->tick();
@@ -664,10 +653,20 @@ void Minecraft::tickInput() {
} }
if (e.action == MouseAction::ACTION_WHEEL) { if (e.action == MouseAction::ACTION_WHEEL) {
Inventory* v = player->inventory; // If chat/console is open, use the wheel to scroll through chat history.
int numSlots = gui.getNumSlots() - 1; if (screen && (dynamic_cast<ChatScreen*>(screen) || dynamic_cast<ConsoleScreen*>(screen))) {
int slot = (v->selected - e.dy + numSlots) % numSlots; gui.scrollChat(e.dy);
v->selectSlot(slot); } else {
Inventory* v = player->inventory;
int numSlots = gui.getNumSlots();
#ifndef PLATFORM_DESKTOP
numSlots--;
#endif
int slot = (v->selected - e.dy + numSlots) % numSlots;
v->selectSlot(slot);
}
} }
/* /*
if (mouseDiggable && options.useMouseForDigging) { if (mouseDiggable && options.useMouseForDigging) {
@@ -692,12 +691,12 @@ void Minecraft::tickInput() {
if (isPressed) { if (isPressed) {
gui.handleKeyPressed(key); gui.handleKeyPressed(key);
#if defined(WIN32) || defined(RPI)//|| defined(_DEBUG) || defined(DEBUG) #if defined(WIN32) || defined(RPI) || defined (PLATFORM_DESKTOP)//|| defined(_DEBUG) || defined(DEBUG)
if (key >= '0' && key <= '9') { if (key >= '0' && key <= '9') {
int digit = key - '0'; int digit = key - '0';
int slot = digit - 1; int slot = digit - 1;
if (slot >= 0 && slot < gui.getNumSlots()-1) if (slot >= 0 && slot < gui.getNumSlots())
player->inventory->selectSlot(slot); player->inventory->selectSlot(slot);
#if defined(WIN32) #if defined(WIN32)
@@ -717,21 +716,24 @@ void Minecraft::tickInput() {
} }
#endif #endif
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
if (key == Keyboard::KEY_LEFT_CTRL) {
player->setSprinting(true);
}
if (key == Keyboard::KEY_E) { if (key == Keyboard::KEY_E) {
screenChooser.setScreen(SCREEN_BLOCKSELECTION); screenChooser.setScreen(SCREEN_BLOCKSELECTION);
} }
if (!screen && key == Keyboard::KEY_O || key == 250) {
releaseMouse(); if (!screen && key == Keyboard::KEY_T && level) {
} setScreen(new ConsoleScreen());
#endif
#if defined(WIN32)
if (key == Keyboard::KEY_F) {
options.isFlying = !options.isFlying;
player->noPhysics = options.isFlying;
} }
if (key == Keyboard::KEY_T) { if (key == Keyboard::KEY_F3) {
options.thirdPersonView = !options.thirdPersonView; options.toggle(OPTIONS_RENDER_DEBUG);
}
if (key == Keyboard::KEY_F5) {
options.toggle(OPTIONS_THIRD_PERSON_VIEW);
/* /*
ImprovedNoise noise; ImprovedNoise noise;
for (int i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
@@ -739,97 +741,96 @@ void Minecraft::tickInput() {
*/ */
} }
if (key == Keyboard::KEY_O) { if (!screen && key == Keyboard::KEY_O || key == 250) {
useAmbientOcclusion = !useAmbientOcclusion; releaseMouse();
options.ambientOcclusion = useAmbientOcclusion;
levelRenderer->allChanged();
} }
if (key == Keyboard::KEY_L) if (key == Keyboard::KEY_F) {
options.viewDistance = (options.viewDistance + 1) % 4; int dst = options.getIntValue(OPTIONS_VIEW_DISTANCE);
options.set(OPTIONS_VIEW_DISTANCE, (dst + 1) % 4);
if (key == Keyboard::KEY_U) {
onGraphicsReset();
player->heal(100);
} }
#ifdef CHEATS
if (key == Keyboard::KEY_B || key == 108) // Toggle the game mode if (key == Keyboard::KEY_U) {
setIsCreativeMode(!isCreativeMode()); onGraphicsReset();
player->heal(100);
if (key == Keyboard::KEY_P) // Step forward in time
level->setTime( level->getTime() + 1000);
if (key == Keyboard::KEY_G) {
setScreen(new ArmorScreen());
/*
std::vector<AABB>& boxs = level->getCubes(NULL, AABB(128.1f, 73, 128.1f, 128.9f, 74.9f, 128.9f));
LOGI("boxes: %d\n", (int)boxs.size());
*/
}
if (key == Keyboard::KEY_Y) {
textures->reloadAll();
player->hurtTo(2);
}
if (key == Keyboard::KEY_Z || key == 108) {
for (int i = 0; i < 1; ++i) {
Mob* mob = NULL;
int forceId = 0;//MobTypes::Sheep;
int types[] = {
MobTypes::Sheep,
MobTypes::Pig,
MobTypes::Chicken,
MobTypes::Cow,
};
int mobType = (forceId > 0)? forceId : types[Mth::random(sizeof(types) / sizeof(int))];
mob = MobFactory::CreateMob(mobType, level);
//((Animal*)mob)->setAge(-1000);
float dx = 4 - 8 * Mth::random() + 4 * Mth::sin(Mth::DEGRAD * player->yRot);
float dz = 4 - 8 * Mth::random() + 4 * Mth::cos(Mth::DEGRAD * player->yRot);
if (mob && !MobSpawner::addMob(level, mob, player->x + dx, player->y, player->z + dz, Mth::random()*360, 0, true))
delete mob;
} }
}
if (key == Keyboard::KEY_X) { if (key == Keyboard::KEY_B || key == 108) // Toggle the game mode
const EntityList& entities = level->getAllEntities(); setIsCreativeMode(!isCreativeMode());
for (int i = entities.size()-1; i >= 0; --i) {
Entity* e = entities[i]; if (key == Keyboard::KEY_P) // Step forward in time
if (!e->isPlayer()) level->setTime( level->getTime() + 1000);
level->removeEntity(e);
if (key == Keyboard::KEY_G) {
setScreen(new ArmorScreen());
/*
std::vector<AABB>& boxs = level->getCubes(NULL, AABB(128.1f, 73, 128.1f, 128.9f, 74.9f, 128.9f));
LOGI("boxes: %d\n", (int)boxs.size());
*/
} }
}
if (key == Keyboard::KEY_C /*|| key == 4*/) { if (key == Keyboard::KEY_Y) {
player->inventory->clearInventoryWithDefault(); textures->reloadAll();
// @todo: Add saving here for benchmarking player->hurtTo(2);
}
if (key == Keyboard::KEY_H) {
setScreen( new PrerenderTilesScreen() );
}
if (key == Keyboard::KEY_O) {
for (int i = Inventory::MAX_SELECTION_SIZE; i < player->inventory->getContainerSize(); ++i)
if (player->inventory->getItem(i))
player->inventory->dropSlot(i, false);
}
if (key == Keyboard::KEY_F3) {
options.renderDebug = !options.renderDebug;
}
if (key == Keyboard::KEY_M) {
options.difficulty = (options.difficulty == Difficulty::PEACEFUL)?
Difficulty::NORMAL : Difficulty::PEACEFUL;
//setIsCreativeMode( !isCreativeMode() );
}
if (options.renderDebug) {
if (key >= '0' && key <= '9') {
_perfRenderer->debugFpsMeterKeyPress(key - '0');
} }
} if (key == Keyboard::KEY_Z || key == 108) {
for (int i = 0; i < 1; ++i) {
Mob* mob = NULL;
int forceId = 0;//MobTypes::Sheep;
int types[] = {
MobTypes::Sheep,
MobTypes::Pig,
MobTypes::Chicken,
MobTypes::Cow,
};
int mobType = (forceId > 0)? forceId : types[Mth::random(sizeof(types) / sizeof(int))];
mob = MobFactory::CreateMob(mobType, level);
//((Animal*)mob)->setAge(-1000);
float dx = 4 - 8 * Mth::random() + 4 * Mth::sin(Mth::DEGRAD * player->yRot);
float dz = 4 - 8 * Mth::random() + 4 * Mth::cos(Mth::DEGRAD * player->yRot);
if (mob && !MobSpawner::addMob(level, mob, player->x + dx, player->y, player->z + dz, Mth::random()*360, 0, true))
delete mob;
}
}
if (key == Keyboard::KEY_X) {
const EntityList& entities = level->getAllEntities();
for (int i = entities.size()-1; i >= 0; --i) {
Entity* e = entities[i];
if (!e->isPlayer())
level->removeEntity(e);
}
}
if (key == Keyboard::KEY_C /*|| key == 4*/) {
player->inventory->clearInventoryWithDefault();
// @todo: Add saving here for benchmarking
}
if (key == Keyboard::KEY_H) {
setScreen( new PrerenderTilesScreen() );
}
if (key == Keyboard::KEY_O) {
for (int i = Inventory::MAX_SELECTION_SIZE; i < player->inventory->getContainerSize(); ++i)
if (player->inventory->getItem(i))
player->inventory->dropSlot(i, false);
}
if (key == Keyboard::KEY_M) {
Difficulty difficulty = (Difficulty)options.getIntValue(OPTIONS_DIFFICULTY);
options.set(OPTIONS_DIFFICULTY, (difficulty == Difficulty::PEACEFUL)?
Difficulty::NORMAL : Difficulty::PEACEFUL);
//setIsCreativeMode( !isCreativeMode() );
}
if (options.getBooleanValue(OPTIONS_RENDER_DEBUG)) {
if (key >= '0' && key <= '9') {
_perfRenderer->debugFpsMeterKeyPress(key - '0');
}
}
#endif
#endif #endif
#ifndef PLATFORM_DESKTOP #ifndef PLATFORM_DESKTOP
@@ -861,22 +862,43 @@ void Minecraft::tickInput() {
static bool prevMouseDownLeft = false; static bool prevMouseDownLeft = false;
// Destroy and attack is on same button if (Mouse::getButtonState(MouseAction::ACTION_LEFT) == 0) {
if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { gameMode->stopDestroyBlock();
auto baiFlags = BuildActionIntention::BAI_REMOVE | BuildActionIntention::BAI_ATTACK;
if (!prevMouseDownLeft) baiFlags |= BuildActionIntention::BAI_FIRSTREMOVE;
BuildActionIntention bai(baiFlags);
handleBuildAction(&bai);
} }
prevMouseDownLeft = Mouse::isButtonDown(MouseAction::ACTION_LEFT); if (useTouchscreen()) {
// Touch: gesture recognizer classifies the action type (turn/destroy/build)
BuildActionIntention bai;
if (inputHolder && inputHolder->getBuildInput()->tickBuild(player, &bai)) {
handleBuildAction(&bai);
}
} else {
// Desktop: left mouse = destroy/attack
if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) {
auto baiFlags = BuildActionIntention::BAI_REMOVE | BuildActionIntention::BAI_ATTACK;
// Build and use/interact is on same button if (!prevMouseDownLeft) baiFlags |= BuildActionIntention::BAI_FIRSTREMOVE;
if (Mouse::isButtonDown(MouseAction::ACTION_RIGHT)) {
BuildActionIntention bai(BuildActionIntention::BAI_BUILD | BuildActionIntention::BAI_INTERACT); BuildActionIntention bai(baiFlags);
handleBuildAction(&bai); handleBuildAction(&bai);
}
prevMouseDownLeft = Mouse::isButtonDown(MouseAction::ACTION_LEFT);
// Build and use/interact is on same button
// USPESHNO spizheno
static int buildHoldTicks = 0;
if (Mouse::isButtonDown(MouseAction::ACTION_RIGHT)) {
if (buildHoldTicks >= 5) buildHoldTicks = 0;
if (++buildHoldTicks == 1) {
BuildActionIntention bai(BuildActionIntention::BAI_BUILD | BuildActionIntention::BAI_INTERACT);
handleBuildAction(&bai);
}
} else {
buildHoldTicks = 0;
gameMode->releaseUsingItem(player);
}
} }
lastTickTime = getTimeMs(); lastTickTime = getTimeMs();
@@ -992,6 +1014,17 @@ bool Minecraft::isOnline()
} }
void Minecraft::pauseGame(bool isBackPaused) { void Minecraft::pauseGame(bool isBackPaused) {
// Only freeze gameplay when running a local server and it is not accepting
// incoming connections (invisible server), which includes typical single-
// player/lobby mode. If the server is visible, the game should keep ticking.
bool canFreeze = false;
if (raknetInstance && raknetInstance->isServer() && netCallback) {
ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback;
if (!ss->allowsIncomingConnections())
canFreeze = true;
}
pause = canFreeze;
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
if (screen != NULL) return; if (screen != NULL) return;
screenChooser.setScreen(isBackPaused? SCREEN_PAUSEPREV : SCREEN_PAUSE); screenChooser.setScreen(isBackPaused? SCREEN_PAUSEPREV : SCREEN_PAUSE);
@@ -1044,6 +1077,8 @@ void Minecraft::setScreen( Screen* screen )
//noRender = false; //noRender = false;
} else { } else {
// Closing a screen and returning to the game should unpause.
pause = false;
grabMouse(); grabMouse();
} }
#endif #endif
@@ -1077,21 +1112,19 @@ bool Minecraft::useTouchscreen() {
#ifdef RPI #ifdef RPI
return false; return false;
#endif #endif
return options.useTouchScreen || !_supportsNonTouchscreen; return options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN) || !_supportsNonTouchscreen;
} }
bool Minecraft::supportNonTouchScreen() { bool Minecraft::supportNonTouchScreen() {
return _supportsNonTouchscreen; return _supportsNonTouchscreen;
} }
void Minecraft::init() void Minecraft::init()
{ {
options.minecraft = this;
options.initDefaultValues();
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
checkGlError("Init enter"); checkGlError("Init enter");
_supportsNonTouchscreen = !platform()->supportsTouchscreen(); _supportsNonTouchscreen = !platform()->supportsTouchscreen();
LOGI("IS TOUCHSCREEN? %d\n", options.useTouchScreen); LOGI("IS TOUCHSCREEN? %d\n", options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN));
textures = new Textures(&options, platform()); textures = new Textures(&options, platform());
textures->addDynamicTexture(new WaterTexture()); textures->addDynamicTexture(new WaterTexture());
@@ -1110,10 +1143,8 @@ void Minecraft::init()
checkGlError("Init complete"); checkGlError("Init complete");
#endif #endif
user = new User("TestUser", "");
setIsCreativeMode(false); // false means it's Survival Mode setIsCreativeMode(false); // false means it's Survival Mode
reloadOptions(); reloadOptions();
} }
void Minecraft::setSize(int w, int h) { void Minecraft::setSize(int w, int h) {
@@ -1123,34 +1154,49 @@ void Minecraft::setSize(int w, int h) {
width = w; width = w;
height = h; height = h;
if (width >= 1000) { int guiScale = options.getIntValue(OPTIONS_GUI_SCALE);
// determine gui scale, optionally overriding auto
if (guiScale != 0) {
// manual selection: 1->small, 2->normal, 3->large, 4->larger
switch (guiScale) {
case 1: Gui::GuiScale = 2.0f; break;
case 2: Gui::GuiScale = 3.0f; break;
case 3: Gui::GuiScale = 4.0f; break;
case 4: Gui::GuiScale = 5.0f; break; // bigger than large
default: Gui::GuiScale = 1.0f; break; // auto
}
} else {
// auto compute from resolution
if (width >= 1000) {
#ifdef __APPLE__ #ifdef __APPLE__
Gui::GuiScale = (width > 2000)? 8.0f : 4.0f; Gui::GuiScale = (width > 2000)? 8.0f : 4.0f;
#else #else
Gui::GuiScale = 4.0f; Gui::GuiScale = 4.0f;
#endif #endif
} }
else if (width >= 800) { else if (width >= 800) {
#ifdef __APPLE__ #ifdef __APPLE__
Gui::GuiScale = 4.0f; Gui::GuiScale = 4.0f;
#else #else
Gui::GuiScale = 3.0f; Gui::GuiScale = 3.0f;
#endif #endif
} }
else if (width >= 400) else if (width >= 400)
Gui::GuiScale = 2.0f; Gui::GuiScale = 2.0f;
else else
Gui::GuiScale = 1.0f; Gui::GuiScale = 1.0f;
}
Gui::InvGuiScale = 1.0f / Gui::GuiScale; Gui::InvGuiScale = 1.0f / Gui::GuiScale;
int screenWidth = (int)(width * Gui::InvGuiScale); int screenWidth = (int)(width * Gui::InvGuiScale);
int screenHeight = (int)(height * Gui::InvGuiScale); int screenHeight = (int)(height * Gui::InvGuiScale);
if (platform()) { // if (platform()) {
float pixelsPerMillimeter = options.getProgressValue(&Options::Option::PIXELS_PER_MILLIMETER); // float pixelsPerMillimeter = options.getProgressValue(&Options::Option::PIXELS_PER_MILLIMETER);
pixelCalc.setPixelsPerMillimeter(pixelsPerMillimeter); // pixelCalc.setPixelsPerMillimeter(pixelsPerMillimeter);
pixelCalcUi.setPixelsPerMillimeter(pixelsPerMillimeter * Gui::InvGuiScale); // pixelCalcUi.setPixelsPerMillimeter(pixelsPerMillimeter * Gui::InvGuiScale);
} // }
Config config = createConfig(this); Config config = createConfig(this);
gui.onConfigChanged(config); gui.onConfigChanged(config);
@@ -1171,16 +1217,16 @@ void Minecraft::setSize(int w, int h) {
} }
void Minecraft::reloadOptions() { void Minecraft::reloadOptions() {
options.update();
options.save(); options.save();
bool wasTouchscreen = options.useTouchScreen; bool wasTouchscreen = options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN);
options.useTouchScreen = useTouchscreen(); options.set(OPTIONS_USE_TOUCHSCREEN, useTouchscreen());
options.save(); options.save();
if ((wasTouchscreen != options.useTouchScreen) || (inputHolder == 0)) if ((wasTouchscreen != useTouchscreen()) || (inputHolder == 0))
_reloadInput(); _reloadInput();
user->name = options.username; // TODO:
// user->name = options.username;
LOGI("Reloading-options\n"); LOGI("Reloading-options\n");
@@ -1193,7 +1239,12 @@ void Minecraft::_reloadInput() {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
delete inputHolder; delete inputHolder;
if (useTouchscreen() && !PLATFORM_DESKTOP) { #ifdef PLATFORM_DESKTOP
const bool useTouchHolder = false;
#else
const bool useTouchHolder = useTouchscreen();
#endif
if (useTouchHolder) {
inputHolder = new TouchInputHolder(this, &options); inputHolder = new TouchInputHolder(this, &options);
} else { } else {
#if defined(ANDROID) || defined(__APPLE__) #if defined(ANDROID) || defined(__APPLE__)
@@ -1245,6 +1296,31 @@ bool Minecraft::joinMultiplayer( const PingedCompatibleServer& server )
return false; return false;
} }
bool Minecraft::joinMultiplayerFromString( const std::string& server )
{
std::string ip = "";
std::string port = "19132";
size_t pos = server.find(":");
if (pos != std::string::npos) {
ip = server.substr(0, pos);
port = server.substr(pos + 1);
} else {
ip = server;
}
printf("%s \n", port.c_str());
if (isLookingForMultiplayer && netCallback) {
isLookingForMultiplayer = false;
printf("test");
int portNum = atoi(port.c_str());
return raknetInstance->connect(ip.c_str(), portNum);
}
return false;
}
void Minecraft::hostMultiplayer(int port) { void Minecraft::hostMultiplayer(int port) {
// Tear down last instance // Tear down last instance
raknetInstance->disconnect(); raknetInstance->disconnect();
@@ -1254,9 +1330,9 @@ void Minecraft::hostMultiplayer(int port) {
#if !defined(NO_NETWORK) #if !defined(NO_NETWORK)
netCallback = new ServerSideNetworkHandler(this, raknetInstance); netCallback = new ServerSideNetworkHandler(this, raknetInstance);
#ifdef STANDALONE_SERVER #ifdef STANDALONE_SERVER
raknetInstance->host(user->name, port, 16); raknetInstance->host("Server", port, 16);
#else #else
raknetInstance->host(user->name, port); raknetInstance->host(options.getStringValue(OPTIONS_USERNAME), port);
#endif #endif
#endif #endif
} }
@@ -1266,7 +1342,7 @@ void Minecraft::hostMultiplayer(int port) {
// //
/*static*/ /*static*/
void* Minecraft::prepareLevel_tspawn(void *p_param) void* Minecraft::prepareLevel_tspawn(void *p_param)
{ {
Minecraft* mc = (Minecraft*) p_param; Minecraft* mc = (Minecraft*) p_param;
mc->generateLevel("Currently not used", mc->level); mc->generateLevel("Currently not used", mc->level);
@@ -1313,8 +1389,10 @@ void Minecraft::_levelGenerated()
this->cameraTargetPlayer = player; this->cameraTargetPlayer = player;
std::string serverName = options.getStringValue(OPTIONS_USERNAME) + " - " + level->getLevelData()->levelName;
if (raknetInstance->isServer()) if (raknetInstance->isServer())
raknetInstance->announceServer(user->name); raknetInstance->announceServer(serverName);
if (netCallback) { if (netCallback) {
netCallback->levelGenerated(level); netCallback->levelGenerated(level);
@@ -1412,11 +1490,11 @@ LevelStorageSource* Minecraft::getLevelSource()
return storageSource; return storageSource;
} }
int Minecraft::getLicenseId() { // int Minecraft::getLicenseId() {
if (!LicenseCodes::isReady(_licenseId)) // if (!LicenseCodes::isReady(_licenseId))
_licenseId = platform()->checkLicense(); // _licenseId = platform()->checkLicense();
return _licenseId; // return _licenseId;
} // }
void Minecraft::audioEngineOn() { void Minecraft::audioEngineOn() {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
@@ -1486,22 +1564,25 @@ ICreator* Minecraft::getCreator()
#endif #endif
} }
void Minecraft::optionUpdated( const Options::Option* option, bool value ) { void Minecraft::optionUpdated(OptionId option, bool value ) {
if(netCallback != NULL && option == &Options::Option::SERVER_VISIBLE) { if(netCallback != NULL && option == OPTIONS_SERVER_VISIBLE) {
ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback; ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback;
ss->allowIncomingConnections(value); ss->allowIncomingConnections(value);
} }
} }
void Minecraft::optionUpdated( const Options::Option* option, float value ) { void Minecraft::optionUpdated(OptionId option, float value ) {
#ifndef STANDALONE_SERVER // #ifndef STANDALONE_SERVER
if(option == &Options::Option::PIXELS_PER_MILLIMETER) { // if(option == OPTIONS_PIXELS_PER_MILLIMETER) {
pixelCalcUi.setPixelsPerMillimeter(value * Gui::InvGuiScale); // pixelCalcUi.setPixelsPerMillimeter(value * Gui::InvGuiScale);
pixelCalc.setPixelsPerMillimeter(value); // pixelCalc.setPixelsPerMillimeter(value);
} // }
#endif // #endif
} }
void Minecraft::optionUpdated( const Options::Option* option, int value ) { void Minecraft::optionUpdated(OptionId option, int value ) {
if(option == OPTIONS_GUI_SCALE) {
// reapply screen scaling using current window size
setSize(width, height);
}
} }

View File

@@ -4,17 +4,15 @@
#include "Options.h" #include "Options.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "MouseHandler.h" #include "MouseHandler.h"
#endif
#include "Timer.h"
#include "player/input/ITurnInput.h"
#ifndef STANDALONE_SERVER
#include "gui/Gui.h" #include "gui/Gui.h"
#include "gui/screens/ScreenChooser.h" #include "gui/screens/ScreenChooser.h"
#endif #endif
#include "Timer.h"
//#include "../network/RakNetInstance.h" //#include "../network/RakNetInstance.h"
#include "../world/phys/HitResult.h" #include "../world/phys/HitResult.h"
class User;
class Level; class Level;
class LocalPlayer; class LocalPlayer;
class IInputHolder; class IInputHolder;
@@ -80,6 +78,7 @@ public:
void locateMultiplayer(); void locateMultiplayer();
void cancelLocateMultiplayer(); void cancelLocateMultiplayer();
bool joinMultiplayer(const PingedCompatibleServer& server); bool joinMultiplayer(const PingedCompatibleServer& server);
bool joinMultiplayerFromString(const std::string& server);
void hostMultiplayer(int port=19132); void hostMultiplayer(int port=19132);
Player* respawnPlayer(int playerId); Player* respawnPlayer(int playerId);
void respawnPlayer(); void respawnPlayer();
@@ -109,7 +108,6 @@ public:
void onGraphicsReset(); void onGraphicsReset();
bool isLevelGenerated(); bool isLevelGenerated();
int getLicenseId();
void audioEngineOn(); void audioEngineOn();
void audioEngineOff(); void audioEngineOff();
@@ -117,9 +115,9 @@ public:
bool isPowerVR() { return _powerVr; } bool isPowerVR() { return _powerVr; }
bool isKindleFire(int kindleVersion); bool isKindleFire(int kindleVersion);
bool transformResolution(int* w, int* h); bool transformResolution(int* w, int* h);
void optionUpdated(const Options::Option* option, bool value); void optionUpdated(OptionId option, bool value);
void optionUpdated(const Options::Option* option, float value); void optionUpdated(OptionId option, float value);
void optionUpdated(const Options::Option* option, int value); void optionUpdated(OptionId option, int value);
#ifdef __APPLE__ #ifdef __APPLE__
bool _isSuperFast; bool _isSuperFast;
bool isSuperFast() { return _isSuperFast; } bool isSuperFast() { return _isSuperFast; }
@@ -166,7 +164,6 @@ public:
int lastTickTime; int lastTickTime;
float ticksSinceLastUpdate; float ticksSinceLastUpdate;
User* user;
Level* level; Level* level;
LocalPlayer* player; LocalPlayer* player;

52
src/client/Option.cpp Normal file
View File

@@ -0,0 +1,52 @@
#include "Option.h"
#include <sstream>
#include <cstdio>
Option::~Option() {}
bool Option::parse_bool_like(const std::string& value, bool& out) {
if (value == "true" || value == "YES") {
out = true;
return true;
}
if (value == "false" || value == "NO") {
out = false;
return true;
}
return false;
}
bool OptionFloat::parse(const std::string& value) {
bool b;
if (parse_bool_like(value, b)) {
m_value = b ? 1.f : 0.f;
return true;
}
return sscanf(value.c_str(), "%f", &m_value) == 1;
}
bool OptionInt::parse(const std::string& value) {
bool b;
if (parse_bool_like(value, b)) {
m_value = b ? 1 : 0;
return true;
}
return sscanf(value.c_str(), "%d", &m_value) == 1;
}
bool OptionBool::parse(const std::string& value) {
if (value == "0") {
m_value = false;
return true;
}
if (value == "1") {
m_value = true;
return true;
}
return parse_bool_like(value, m_value);
}

107
src/client/Option.h Normal file
View File

@@ -0,0 +1,107 @@
#pragma once
#include <sstream>
#include <type_traits>
#include <util/Mth.h>
/*
template<typename T>
struct is_option_type : std::false_type {};
template<> struct is_option_type<bool> : std::true_type {};
template<> struct is_option_type<int> : std::true_type {};
template<> struct is_option_type<float> : std::true_type {};
template<> struct is_option_type<std::string> : std::true_type {};
template<typename T>
struct is_min_max_option : std::false_type {};
template<> struct is_min_max_option<int> : std::true_type {};
template<> struct is_min_max_option<float> : std::true_type {};
*/
class Option {
public:
Option(const std::string& key) : m_key("options." + key) {}
virtual ~Option();
const std::string& getStringId() { return m_key; }
virtual bool parse(const std::string& value) { return false; }
virtual std::string serialize() { return m_key + ":"; }
protected:
std::string m_key;
template<typename T>
std::string serialize_value(const T& value) const {
std::ostringstream ss;
ss << m_key << ":" << value;
return ss.str();
}
bool parse_bool_like(const std::string& value, bool& out);
};
class OptionFloat : public Option {
public:
OptionFloat(const std::string& key, float value = 0.f, float min = 0.f, float max = 1.f) :
Option(key), m_value(value), m_min(min), m_max(max) {}
float get() { return m_value; }
void set(float value) { m_value = Mth::clamp(value, m_min, m_max); }
float getMin() { return m_min; }
float getMax() { return m_max; }
virtual bool parse(const std::string& value);
virtual std::string serialize() { return serialize_value(m_value); }
private:
float m_value, m_min, m_max;
};
class OptionInt : public Option {
public:
OptionInt(const std::string& key, int value = 0, int min = -999999, int max = 999999) :
Option(key), m_value(value), m_min(min), m_max(max) {}
int get() { return m_value; }
void set(int value) { m_value = Mth::clamp(value, m_min, m_max); }
int getMin() { return m_min; }
int getMax() { return m_max; }
virtual bool parse(const std::string& value);
virtual std::string serialize() { return serialize_value(m_value); }
private:
int m_value, m_min, m_max;
};
class OptionBool : public Option {
public:
OptionBool(const std::string& key, bool value = false) : Option(key), m_value(value) {}
bool get() { return m_value; }
void set(int value) { m_value = value; }
void toggle() { m_value = !m_value; }
virtual bool parse(const std::string& value);
virtual std::string serialize() { return serialize_value(m_value); }
private:
bool m_value;
};
class OptionString : public Option {
public:
OptionString(const std::string& key, const std::string& str = "") : Option(key), m_value(str) {}
const std::string& get() { return m_value; }
void set(const std::string& value) { m_value = value; }
virtual bool parse(const std::string& value) { m_value = value; return true; }
virtual std::string serialize() { return m_key + ":" + m_value; }
private:
std::string m_value;
};

View File

@@ -5,12 +5,20 @@ const char* OptionStrings::Multiplayer_ServerVisible = "mp_server_visible_defa
const char* OptionStrings::Graphics_Fancy = "gfx_fancygraphics"; const char* OptionStrings::Graphics_Fancy = "gfx_fancygraphics";
const char* OptionStrings::Graphics_LowQuality = "gfx_lowquality"; const char* OptionStrings::Graphics_LowQuality = "gfx_lowquality";
const char* OptionStrings::Graphics_Vsync = "gfx_vsync";
const char* OptionStrings::Graphics_GUIScale = "gfx_guiscale";
const char* OptionStrings::Graphics_SmoothLightning = "gfx_smoothlightning";
const char* OptionStrings::Graphics_Anaglyph = "gfx_anaglyph";
const char* OptionStrings::Graphics_ViewBobbing = "gfx_viewbobbing";
const char* OptionStrings::Controls_Sensitivity = "ctrl_sensitivity"; const char* OptionStrings::Controls_Sensitivity = "ctrl_sensitivity";
const char* OptionStrings::Controls_InvertMouse = "ctrl_invertmouse"; const char* OptionStrings::Controls_InvertMouse = "ctrl_invertmouse";
const char* OptionStrings::Controls_UseTouchScreen = "ctrl_usetouchscreen"; const char* OptionStrings::Controls_UseTouchScreen = "ctrl_usetouchscreen";
const char* OptionStrings::Controls_UseTouchJoypad = "ctrl_usetouchjoypad"; const char* OptionStrings::Controls_UseTouchJoypad = "ctrl_usetouchjoypad";
const char* OptionStrings::Controls_IsLefthanded = "ctrl_islefthanded"; const char* OptionStrings::Controls_IsLefthanded = "ctrl_islefthanded";
// why it isnt ctrl_feedback_vibration? i dont want touch it because compatibility with older versions
const char* OptionStrings::Controls_FeedbackVibration = "feedback_vibration"; const char* OptionStrings::Controls_FeedbackVibration = "feedback_vibration";
const char* OptionStrings::Controls_AutoJump = "ctrl_autojump";
const char* OptionStrings::Game_DifficultyLevel = "game_difficulty"; const char* OptionStrings::Game_DifficultyLevel = "game_difficulty";

View File

@@ -8,15 +8,29 @@ public:
static const char* Graphics_Fancy; static const char* Graphics_Fancy;
static const char* Graphics_LowQuality; static const char* Graphics_LowQuality;
static const char* Graphics_GUIScale;
static const char* Graphics_Vsync;
static const char* Graphics_SmoothLightning;
static const char* Graphics_Anaglyph;
static const char* Graphics_ViewBobbing;
static const char* Controls_Sensitivity; static const char* Controls_Sensitivity;
static const char* Controls_InvertMouse; static const char* Controls_InvertMouse;
static const char* Controls_UseTouchScreen; static const char* Controls_UseTouchScreen;
static const char* Controls_UseTouchJoypad; static const char* Controls_UseTouchJoypad;
static const char* Controls_IsLefthanded; static const char* Controls_IsLefthanded;
static const char* Controls_FeedbackVibration; static const char* Controls_FeedbackVibration;
static const char* Controls_AutoJump;
static const char* Audio_Music;
static const char* Audio_Sound;
static const char* Game_DifficultyLevel; static const char* Game_DifficultyLevel;
static const char* Tweaks_Sprint;
static const char* Tweaks_BarOnTop;
}; };
#endif /*NET_MINECRAFT_CLIENT__OptionsStrings_H__*/ #endif /*NET_MINECRAFT_CLIENT__OptionsStrings_H__*/

View File

@@ -4,457 +4,293 @@
#include "../platform/log.h" #include "../platform/log.h"
#include "../world/Difficulty.h" #include "../world/Difficulty.h"
#include <cmath> #include <cmath>
#include <sstream>
/*static*/ #include <memory>
bool Options::debugGl = false; bool Options::debugGl = false;
void Options::initDefaultValues() { // OPTIONS TABLE
difficulty = Difficulty::NORMAL;
hideGui = false;
thirdPersonView = false;
renderDebug = false;
isFlying = false;
smoothCamera = true;
fixedCamera = false;
flySpeed = 1;
cameraSpeed = 1;
guiScale = 0;
useMouseForDigging = false; OptionInt difficulty("difficulty", Difficulty::NORMAL, 0, Difficulty::COUNT);
destroyVibration = true; OptionBool hidegui("hidegui", false);
isLeftHanded = false; OptionBool thirdPersonView("thirdperson", false);
OptionBool renderDebug("renderDebug", false);
OptionBool smoothCamera("smoothCamera", false);
OptionBool fixedCamera("fixedCamera", false);
OptionBool isFlying("isflying", false);
OptionBool barOnTop("barOnTop", false);
OptionBool allowSprint("allowSprint", true);
OptionBool autoJump("autoJump", true);
isJoyTouchArea = false;
music = 1; OptionFloat flySpeed("flySpeed", 1.f);
sound = 1; OptionFloat cameraSpeed("cameraSpeed", 1.f);
sensitivity = 0.5f;
invertYMouse = false;
viewDistance = 2;
bobView = true;
anaglyph3d = false;
limitFramerate = false;
fancyGraphics = true;//false;
ambientOcclusion = false;
if(minecraft->supportNonTouchScreen())
useTouchScreen = false;
else
useTouchScreen = true;
pixelsPerMillimeter = minecraft->platform()->getPixelsPerMillimeter();
//useMouseForDigging = true;
//skin = "Default"; OptionInt guiScale("guiScale", 0, 0, 5);
username = "Steve";
serverVisible = true;
keyUp = KeyMapping("key.forward", Keyboard::KEY_W); OptionString skin("skin", "Default");
keyLeft = KeyMapping("key.left", Keyboard::KEY_A);
keyDown = KeyMapping("key.back", Keyboard::KEY_S); #ifdef RPI
keyRight = KeyMapping("key.right", Keyboard::KEY_D); OptionString username("username", "StevePi");
keyJump = KeyMapping("key.jump", Keyboard::KEY_SPACE); #else
keyBuild = KeyMapping("key.inventory", Keyboard::KEY_E); OptionString username("username", "Steve");
keySneak = KeyMapping("key.sneak", Keyboard::KEY_LSHIFT);
#ifndef RPI
keyCraft = KeyMapping("key.crafting", Keyboard::KEY_Q);
keyDrop = KeyMapping("key.drop", Keyboard::KEY_Q);
keyChat = KeyMapping("key.chat", Keyboard::KEY_T);
keyFog = KeyMapping("key.fog", Keyboard::KEY_F);
keyDestroy=KeyMapping("key.destroy", 88); // @todo @fix
keyUse = KeyMapping("key.use", Keyboard::KEY_U);
#endif #endif
//const int Unused = 99999; OptionBool destroyVibration("destroyVibration", true);
keyMenuNext = KeyMapping("key.menu.next", 40); OptionBool isLeftHanded("isLeftHanded", false);
keyMenuPrevious = KeyMapping("key.menu.previous", 38); OptionBool isJoyTouchArea("isJoyTouchArea", false);
keyMenuOk = KeyMapping("key.menu.ok", 13);
keyMenuCancel = KeyMapping("key.menu.cancel", 8);
int k = 0; OptionFloat musicVolume("music", 1.f, MUSIC_MIN_VALUE, MUSIC_MAX_VALUE);
keyMappings[k++] = &keyUp; OptionFloat soundVolume("sound", 1.f, SOUND_MIN_VALUE, SOUND_MAX_VALUE);
keyMappings[k++] = &keyLeft;
keyMappings[k++] = &keyDown;
keyMappings[k++] = &keyRight;
keyMappings[k++] = &keyJump;
keyMappings[k++] = &keySneak;
keyMappings[k++] = &keyDrop;
keyMappings[k++] = &keyBuild;
keyMappings[k++] = &keyChat;
keyMappings[k++] = &keyFog;
keyMappings[k++] = &keyDestroy;
keyMappings[k++] = &keyUse;
keyMappings[k++] = &keyMenuNext; OptionFloat sensitivityOpt("sensitivity", 0.5f, SENSITIVITY_MIN_VALUE, SENSITIVITY_MAX_VALUE);
keyMappings[k++] = &keyMenuPrevious;
keyMappings[k++] = &keyMenuOk;
keyMappings[k++] = &keyMenuCancel;
// "Polymorphism" at it's worst. At least it's better to have it here OptionBool invertYMouse("invertMouse", false);
// for now, then to have it spread all around the game code (even if OptionInt viewDistance("renderDistance", 2, 0, 4);
// it would be slightly better performance with it inlined. Should
// probably create separate subclasses (or read from file). @fix @todo.
#if defined(ANDROID) || defined(__APPLE__) || defined(RPI)
viewDistance = 2;
thirdPersonView = false;
useMouseForDigging = false;
fancyGraphics = false;
//renderDebug = true; OptionBool anaglyph3d("anaglyph3d", false);
#if !defined(RPI) OptionBool limitFramerate("limitFramerate", false);
keyUp.key = 19; OptionBool vsync("vsync", true);
keyDown.key = 20; OptionBool fancyGraphics("fancyGraphics", true);
keyLeft.key = 21; OptionBool viewBobbing("viewBobbing", true);
keyRight.key = 22; OptionBool ambientOcclusion("ao", false);
keyJump.key = 23;
keyUse.key = 103;
keyDestroy.key = 102;
keyCraft.key = 109;
keyMenuNext.key = 20; OptionBool useTouchscreen("useTouchscreen", true);
keyMenuPrevious.key = 19;
keyMenuOk.key = 23; OptionBool serverVisible("servervisible", true);
keyMenuCancel.key = 4;
OptionInt keyForward("key.forward", Keyboard::KEY_W);
OptionInt keyLeft("key.left", Keyboard::KEY_A);
OptionInt keyBack("key.back", Keyboard::KEY_S);
OptionInt keyRight("key.right", Keyboard::KEY_D);
OptionInt keyJump("key.jump", Keyboard::KEY_SPACE);
OptionInt keyInventory("key.inventory", Keyboard::KEY_E);
OptionInt keySneak("key.sneak", Keyboard::KEY_LSHIFT);
OptionInt keyDrop("key.drop", Keyboard::KEY_Q);
OptionInt keyChat("key.chat", Keyboard::KEY_T);
OptionInt keyFog("key.fog", Keyboard::KEY_F);
OptionInt keyUse("key.use", Keyboard::KEY_U);
// TODO: make human readable keycodes here
OptionInt keyMenuNext("key.menu.next", 40);
OptionInt keyMenuPrev("key.menu.previous", 38);
OptionInt keyMenuOk("key.menu.ok", 13);
OptionInt keyMenuCancel("key.menu.cancel", 8);
OptionBool firstLaunch("firstLaunch", true);
OptionString lastIp("lastip");
void Options::initTable() {
m_options[OPTIONS_DIFFICULTY] = &difficulty;
m_options[OPTIONS_HIDEGUI] = &hidegui;
m_options[OPTIONS_THIRD_PERSON_VIEW] = &thirdPersonView;
m_options[OPTIONS_RENDER_DEBUG] = &renderDebug;
m_options[OPTIONS_SMOOTH_CAMERA] = &smoothCamera;
m_options[OPTIONS_FIXED_CAMERA] = &fixedCamera;
m_options[OPTIONS_IS_FLYING] = &isFlying;
m_options[OPTIONS_FLY_SPEED] = &flySpeed;
m_options[OPTIONS_CAMERA_SPEED] = &cameraSpeed;
m_options[OPTIONS_GUI_SCALE] = &guiScale;
m_options[OPTIONS_DESTROY_VIBRATION] = &destroyVibration;
m_options[OPTIONS_IS_LEFT_HANDED] = &isLeftHanded;
m_options[OPTIONS_IS_JOY_TOUCH_AREA] = &isJoyTouchArea;
m_options[OPTIONS_MUSIC_VOLUME] = &musicVolume;
m_options[OPTIONS_SOUND_VOLUME] = &soundVolume;
#if defined(PLATFORM_DESKTOP) || defined(RPI)
float sensitivity = sensitivityOpt.get();
sensitivity *= 0.4f;
sensitivityOpt.set(sensitivity);
#endif #endif
#endif
#if defined(RPI)
username = "StevePi"; m_options[OPTIONS_GUI_SCALE] = &guiScale;
sensitivity *= 0.4f;
useMouseForDigging = true; m_options[OPTIONS_SKIN] = &skin;
#endif m_options[OPTIONS_USERNAME] = &username;
m_options[OPTIONS_DESTROY_VIBRATION] = &destroyVibration;
m_options[OPTIONS_IS_LEFT_HANDED] = &isLeftHanded;
m_options[OPTIONS_MUSIC_VOLUME] = &musicVolume;
m_options[OPTIONS_SOUND_VOLUME] = &soundVolume;
m_options[OPTIONS_SENSITIVITY] = &sensitivityOpt;
m_options[OPTIONS_INVERT_Y_MOUSE] = &invertYMouse;
m_options[OPTIONS_VIEW_DISTANCE] = &viewDistance;
m_options[OPTIONS_ANAGLYPH_3D] = &anaglyph3d;
m_options[OPTIONS_LIMIT_FRAMERATE] = &limitFramerate;
m_options[OPTIONS_VSYNC] = &vsync;
m_options[OPTIONS_FANCY_GRAPHICS] = &fancyGraphics;
m_options[OPTIONS_VIEW_BOBBING] = &viewBobbing;
m_options[OPTIONS_AMBIENT_OCCLUSION] = &ambientOcclusion;
m_options[OPTIONS_USE_TOUCHSCREEN] = &useTouchscreen;
m_options[OPTIONS_SERVER_VISIBLE] = &serverVisible;
m_options[OPTIONS_KEY_FORWARD] = &keyForward;
m_options[OPTIONS_KEY_LEFT] = &keyLeft;
m_options[OPTIONS_KEY_BACK] = &keyBack;
m_options[OPTIONS_KEY_RIGHT] = &keyRight;
m_options[OPTIONS_KEY_JUMP] = &keyJump;
m_options[OPTIONS_KEY_INVENTORY] = &keyInventory;
m_options[OPTIONS_KEY_SNEAK] = &keySneak;
m_options[OPTIONS_KEY_DROP] = &keyDrop;
m_options[OPTIONS_KEY_CHAT] = &keyChat;
m_options[OPTIONS_KEY_FOG] = &keyFog;
m_options[OPTIONS_KEY_USE] = &keyUse;
m_options[OPTIONS_KEY_MENU_NEXT] = &keyMenuNext;
m_options[OPTIONS_KEY_MENU_PREV] = &keyMenuPrev;
m_options[OPTIONS_KEY_MENU_OK] = &keyMenuOk;
m_options[OPTIONS_KEY_MENU_CANCEL] = &keyMenuCancel;
m_options[OPTIONS_FIRST_LAUNCH] = &firstLaunch;
m_options[OPTIONS_BAR_ON_TOP] = &barOnTop;
m_options[OPTIONS_ALLOW_SPRINT] = &allowSprint;
m_options[OPTIONS_AUTOJUMP] = &autoJump;
m_options[OPTIONS_LAST_IP] = &lastIp;
} }
const Options::Option void Options::set(OptionId key, const std::string& value) {
Options::Option::MUSIC (0, "options.music", true, false), auto option = opt<OptionString>(key);
Options::Option::SOUND (1, "options.sound", true, false),
Options::Option::INVERT_MOUSE (2, "options.invertMouse", false, true),
Options::Option::SENSITIVITY (3, "options.sensitivity", true, false),
Options::Option::RENDER_DISTANCE (4, "options.renderDistance",false, false),
Options::Option::VIEW_BOBBING (5, "options.viewBobbing", false, true),
Options::Option::ANAGLYPH (6, "options.anaglyph", false, true),
Options::Option::LIMIT_FRAMERATE (7, "options.limitFramerate",false, true),
Options::Option::DIFFICULTY (8, "options.difficulty", false, false),
Options::Option::GRAPHICS (9, "options.graphics", false, false),
Options::Option::AMBIENT_OCCLUSION (10, "options.ao", false, true),
Options::Option::GUI_SCALE (11, "options.guiScale", false, false),
Options::Option::THIRD_PERSON (12, "options.thirdperson", false, true),
Options::Option::HIDE_GUI (13, "options.hidegui", false, true),
Options::Option::SERVER_VISIBLE (14, "options.servervisible", false, true),
Options::Option::LEFT_HANDED (15, "options.lefthanded", false, true),
Options::Option::USE_TOUCHSCREEN (16, "options.usetouchscreen", false, true),
Options::Option::USE_TOUCH_JOYPAD (17, "options.usetouchpad", false, true),
Options::Option::DESTROY_VIBRATION (18, "options.destroyvibration", false, true),
Options::Option::PIXELS_PER_MILLIMETER(19, "options.pixelspermilimeter", true, false);
/* private */ if (option) {
const float Options::SOUND_MIN_VALUE = 0.0f; option->set(value);
const float Options::SOUND_MAX_VALUE = 1.0f; notifyOptionUpdate(key, value);
const float Options::MUSIC_MIN_VALUE = 0.0f; }
const float Options::MUSIC_MAX_VALUE = 1.0f; }
const float Options::SENSITIVITY_MIN_VALUE = 0.0f;
const float Options::SENSITIVITY_MAX_VALUE = 1.0f;
const float Options::PIXELS_PER_MILLIMETER_MIN_VALUE = 3.0f;
const float Options::PIXELS_PER_MILLIMETER_MAX_VALUE = 4.0f;
const int DIFFICULY_LEVELS[] = {
Difficulty::PEACEFUL,
Difficulty::NORMAL
};
/*private*/ void Options::set(OptionId key, float value) {
const char* Options::RENDER_DISTANCE_NAMES[] = { auto option = opt<OptionFloat>(key);
"options.renderDistance.far",
"options.renderDistance.normal",
"options.renderDistance.short",
"options.renderDistance.tiny"
};
/*private*/ if (option) {
const char* Options::DIFFICULTY_NAMES[] = { option->set(value);
"options.difficulty.peaceful", notifyOptionUpdate(key, value);
"options.difficulty.easy", }
"options.difficulty.normal", }
"options.difficulty.hard"
};
/*private*/ void Options::set(OptionId key, int value) {
const char* Options::GUI_SCALE[] = { auto option = opt<OptionInt>(key);
"options.guiScale.auto",
"options.guiScale.small",
"options.guiScale.normal",
"options.guiScale.large"
};
void Options::update() if (option) {
{ option->set(value);
viewDistance = 2; notifyOptionUpdate(key, value);
}
}
void Options::toggle(OptionId key) {
auto option = opt<OptionBool>(key);
if (option) {
option->toggle();
notifyOptionUpdate(key, option->get());
}
}
void Options::load() {
StringVector optionStrings = optionsFile.getOptionStrings(); StringVector optionStrings = optionsFile.getOptionStrings();
for (unsigned int i = 0; i < optionStrings.size(); i += 2) {
for (auto i = 0; i < optionStrings.size(); i += 2) {
const std::string& key = optionStrings[i]; const std::string& key = optionStrings[i];
const std::string& value = optionStrings[i+1]; const std::string& value = optionStrings[i+1];
//LOGI("reading key: %s (%s)\n", key.c_str(), value.c_str()); // FIXME: woah this is so slow
auto opt = std::find_if(m_options.begin(), m_options.end(), [&](auto& it) {
return it != nullptr && it->getStringId() == key;
});
if (opt == m_options.end()) continue;
(*opt)->parse(value);
/*
// //LOGI("reading key: %s (%s)\n", key.c_str(), value.c_str());
// Multiplayer // // Multiplayer
if (key == OptionStrings::Multiplayer_Username) username = value; // // if (key == OptionStrings::Multiplayer_Username) username = value;
if (key == OptionStrings::Multiplayer_ServerVisible) readBool(value, serverVisible); // if (key == OptionStrings::Multiplayer_ServerVisible) {
// m_options[OPTIONS_SERVER_VISIBLE] = readBool(value);
// }
// Controls // // Controls
if (key == OptionStrings::Controls_Sensitivity) { // if (key == OptionStrings::Controls_Sensitivity) {
float sens; // float sens = readFloat(value);
if (readFloat(value, sens)) {
// sens is in range [0,1] with default/center at 0.5 (for aesthetics)
// We wanna map it to something like [0.3, 0.9] BUT keep 0.5 @ ~0.5...
sensitivity = 0.3f + std::pow(1.1f * sens, 1.3f) * 0.42f;
}
}
if (key == OptionStrings::Controls_InvertMouse) {
readBool(value, invertYMouse);
}
if (key == OptionStrings::Controls_IsLefthanded) {
readBool(value, isLeftHanded);
}
if (key == OptionStrings::Controls_UseTouchJoypad) {
readBool(value, isJoyTouchArea);
if (!minecraft->useTouchscreen())
isJoyTouchArea = false;
}
// Feedback // // sens is in range [0,1] with default/center at 0.5 (for aesthetics)
if (key == OptionStrings::Controls_FeedbackVibration) // // We wanna map it to something like [0.3, 0.9] BUT keep 0.5 @ ~0.5...
readBool(value, destroyVibration); // m_options[OPTIONS_SENSITIVITY] = 0.3f + std::pow(1.1f * sens, 1.3f) * 0.42f;
// }
// Graphics // if (key == OptionStrings::Controls_InvertMouse) {
if (key == OptionStrings::Graphics_Fancy) { // m_options[OPTIONS_INVERT_Y_MOUSE] = readBool(value);
readBool(value, fancyGraphics); // }
}
if (key == OptionStrings::Graphics_LowQuality) { // if (key == OptionStrings::Controls_IsLefthanded) {
bool isLow; // m_options[OPTIONS_IS_LEFT_HANDED] = readBool(value);
readBool(value, isLow); // }
if (isLow) {
viewDistance = 3; // if (key == OptionStrings::Controls_UseTouchJoypad) {
fancyGraphics = false; // m_options[OPTIONS_IS_JOY_TOUCH_AREA] = readBool(value) && minecraft->useTouchscreen();
} // }
}
// Game // // Feedback
if (key == OptionStrings::Game_DifficultyLevel) { // if (key == OptionStrings::Controls_FeedbackVibration) {
readInt(value, difficulty); // m_options[OPTIONS_DESTROY_VIBRATION] = readBool(value);
// Only support peaceful and normal right now // }
if (difficulty != Difficulty::PEACEFUL && difficulty != Difficulty::NORMAL)
difficulty = Difficulty::NORMAL; // // Graphics
} // if (key == OptionStrings::Graphics_Fancy) {
// m_options[OPTIONS_FANCY_GRAPHICS] = readBool(value);
// }
// // Graphics extras
// if (key == OptionStrings::Graphics_Vsync) {
// m_options[OPTIONS_VSYNC] = readBool(value);
// }
// if (key == OptionStrings::Graphics_GUIScale) {
// m_options[OPTIONS_GUI_SCALE] = readInt(value) % 5;
// }
// // Game
// if (key == OptionStrings::Game_DifficultyLevel) {
// readInt(value, difficulty);
// // Only support peaceful and normal right now
// if (difficulty != Difficulty::PEACEFUL && difficulty != Difficulty::NORMAL)
// difficulty = Difficulty::NORMAL;
// }*/
} }
#ifdef __APPLE__
// if (minecraft->isSuperFast()) {
// viewDistance = (viewDistance>0)? --viewDistance : 0;
// }
// LOGI("Is this card super fast?: %d\n", viewDistance);
#endif
//LOGI("Lefty is: %d\n", isLeftHanded);
} }
void Options::load() void Options::save() {
{
int a = 0;
//try {
// if (!optionsFile.exists()) return;
// BufferedReader br = /*new*/ BufferedReader(/*new*/ FileReader(optionsFile));
// std::string line = "";
// while ((line = br.readLine()) != NULL) {
// std::string[] cmds = line.split(":");
// if (cmds[0].equals("music")) music = readFloat(cmds[1]);
// if (cmds[0].equals("sound")) sound = readFloat(cmds[1]);
// if (cmds[0].equals("mouseSensitivity")) sensitivity = readFloat(cmds[1]);
// if (cmds[0].equals("invertYMouse")) invertYMouse = cmds[1].equals("true");
// if (cmds[0].equals("viewDistance")) viewDistance = Integer.parseInt(cmds[1]);
// if (cmds[0].equals("guiScale")) guiScale = Integer.parseInt(cmds[1]);
// if (cmds[0].equals("bobView")) bobView = cmds[1].equals("true");
// if (cmds[0].equals("anaglyph3d")) anaglyph3d = cmds[1].equals("true");
// if (cmds[0].equals("limitFramerate")) limitFramerate = cmds[1].equals("true");
// if (cmds[0].equals("difficulty")) difficulty = Integer.parseInt(cmds[1]);
// if (cmds[0].equals("fancyGraphics")) fancyGraphics = cmds[1].equals("true");
// if (cmds[0].equals("ao")) ambientOcclusion = cmds[1].equals("true");
// if (cmds[0].equals("skin")) skin = cmds[1];
// if (cmds[0].equals("lastServer") && cmds.length >= 2) lastMpIp = cmds[1];
// for (int i = 0; i < keyMappings.length; i++) {
// if (cmds[0].equals("key_" + keyMappings[i].name)) {
// keyMappings[i].key = Integer.parseInt(cmds[1]);
// }
// }
// }
// br.close();
//} catch (Exception e) {
// System.out.println("Failed to load options");
// e.printStackTrace();
//}
}
void Options::save()
{
StringVector stringVec; StringVector stringVec;
// Game
addOptionToSaveOutput(stringVec, OptionStrings::Multiplayer_ServerVisible, serverVisible); for (auto& it : m_options) {
addOptionToSaveOutput(stringVec, OptionStrings::Game_DifficultyLevel, difficulty); if (it) stringVec.push_back(it->serialize());
}
// Input optionsFile.save(stringVec);
addOptionToSaveOutput(stringVec, OptionStrings::Controls_InvertMouse, invertYMouse);
addOptionToSaveOutput(stringVec, OptionStrings::Controls_Sensitivity, sensitivity);
addOptionToSaveOutput(stringVec, OptionStrings::Controls_IsLefthanded, isLeftHanded);
addOptionToSaveOutput(stringVec, OptionStrings::Controls_UseTouchScreen, useTouchScreen);
addOptionToSaveOutput(stringVec, OptionStrings::Controls_UseTouchJoypad, isJoyTouchArea);
addOptionToSaveOutput(stringVec, OptionStrings::Controls_FeedbackVibration, destroyVibration);
//
// static const Option MUSIC;
// static const Option SOUND;
// static const Option INVERT_MOUSE;
// static const Option SENSITIVITY;
// static const Option RENDER_DISTANCE;
// static const Option VIEW_BOBBING;
// static const Option ANAGLYPH;
// static const Option LIMIT_FRAMERATE;
// static const Option DIFFICULTY;
// static const Option GRAPHICS;
// static const Option AMBIENT_OCCLUSION;
// static const Option GUI_SCALE;
//
// static const Option THIRD_PERSON;
// static const Option HIDE_GUI;
//try {
// PrintWriter pw = /*new*/ PrintWriter(/*new*/ FileWriter(optionsFile));
// pw.println("music:" + music);
// pw.println("sound:" + sound);
// pw.println("invertYMouse:" + invertYMouse);
// pw.println("mouseSensitivity:" + sensitivity);
// pw.println("viewDistance:" + viewDistance);
// pw.println("guiScale:" + guiScale);
// pw.println("bobView:" + bobView);
// pw.println("anaglyph3d:" + anaglyph3d);
// pw.println("limitFramerate:" + limitFramerate);
// pw.println("difficulty:" + difficulty);
// pw.println("fancyGraphics:" + fancyGraphics);
// pw.println("ao:" + ambientOcclusion);
// pw.println("skin:" + skin);
// pw.println("lastServer:" + lastMpIp);
// for (int i = 0; i < keyMappings.length; i++) {
// pw.println("key_" + keyMappings[i].name + ":" + keyMappings[i].key);
// }
// pw.close();
//} catch (Exception e) {
// System.out.println("Failed to save options");
// e.printStackTrace();
//}
}
void Options::addOptionToSaveOutput(StringVector& stringVector, std::string name, bool boolValue) {
std::stringstream ss;
ss << name << ":" << boolValue;
stringVector.push_back(ss.str());
}
void Options::addOptionToSaveOutput(StringVector& stringVector, std::string name, float floatValue) {
std::stringstream ss;
ss << name << ":" << floatValue;
stringVector.push_back(ss.str());
}
void Options::addOptionToSaveOutput(StringVector& stringVector, std::string name, int intValue) {
std::stringstream ss;
ss << name << ":" << intValue;
stringVector.push_back(ss.str());
} }
std::string Options::getMessage( const Option* item ) void Options::notifyOptionUpdate(OptionId key, bool value) {
{ minecraft->optionUpdated(key, value);
return "Options::getMessage - Not implemented";
//Language language = Language.getInstance();
//std::string caption = language.getElement(item.getCaptionId()) + ": ";
//if (item.isProgress()) {
// float progressValue = getProgressValue(item);
// if (item == Option.SENSITIVITY) {
// if (progressValue == 0) {
// return caption + language.getElement("options.sensitivity.min");
// }
// if (progressValue == 1) {
// return caption + language.getElement("options.sensitivity.max");
// }
// return caption + (int) (progressValue * 200) + "%";
// } else {
// if (progressValue == 0) {
// return caption + language.getElement("options.off");
// }
// return caption + (int) (progressValue * 100) + "%";
// }
//} else if (item.isBoolean()) {
// bool booleanValue = getBooleanValue(item);
// if (booleanValue) {
// return caption + language.getElement("options.on");
// }
// return caption + language.getElement("options.off");
//} else if (item == Option.RENDER_DISTANCE) {
// return caption + language.getElement(RENDER_DISTANCE_NAMES[viewDistance]);
//} else if (item == Option.DIFFICULTY) {
// return caption + language.getElement(DIFFICULTY_NAMES[difficulty]);
//} else if (item == Option.GUI_SCALE) {
// return caption + language.getElement(GUI_SCALE[guiScale]);
//} else if (item == Option.GRAPHICS) {
// if (fancyGraphics) {
// return caption + language.getElement("options.graphics.fancy");
// }
// return caption + language.getElement("options.graphics.fast");
//}
//return caption;
} }
/*static*/ void Options::notifyOptionUpdate(OptionId key, float value) {
bool Options::readFloat(const std::string& string, float& value) { minecraft->optionUpdated(key, value);
if (string == "true" || string == "YES") { value = 1; return true; }
if (string == "false" || string == "NO") { value = 0; return true; }
#ifdef _WIN32
if (sscanf_s(string.c_str(), "%f", &value))
return true;
#else
if (sscanf(string.c_str(), "%f", &value))
return true;
#endif
return false;
} }
/*static*/ void Options::notifyOptionUpdate(OptionId key, int value) {
bool Options::readInt(const std::string& string, int& value) { minecraft->optionUpdated(key, value);
if (string == "true" || string == "YES") { value = 1; return true; }
if (string == "false" || string == "NO") { value = 0; return true; }
#ifdef _WIN32
if (sscanf_s(string.c_str(), "%d", &value))
return true;
#else
if (sscanf(string.c_str(), "%d", &value))
return true;
#endif
return false;
}
/*static*/
bool Options::readBool(const std::string& string, bool& value) {
std::string s = Util::stringTrim(string);
if (string == "true" || string == "1" || string == "YES") { value = true; return true; }
if (string == "false" || string == "0" || string == "NO") { value = false; return true; }
return false;
}
void Options::notifyOptionUpdate( const Option* option, bool value ) {
minecraft->optionUpdated(option, value);
}
void Options::notifyOptionUpdate( const Option* option, float value ) {
minecraft->optionUpdated(option, value);
}
void Options::notifyOptionUpdate( const Option* option, int value ) {
minecraft->optionUpdated(option, value);
} }

View File

@@ -1,16 +1,91 @@
#ifndef NET_MINECRAFT_CLIENT__Options_H__ #ifndef NET_MINECRAFT_CLIENT__Options_H__
#define NET_MINECRAFT_CLIENT__Options_H__ #define NET_MINECRAFT_CLIENT__Options_H__
#define SOUND_MIN_VALUE 0.0f
#define SOUND_MAX_VALUE 1.0f
#define MUSIC_MIN_VALUE 0.0f
#define MUSIC_MAX_VALUE 1.0f
#define SENSITIVITY_MIN_VALUE 0.0f
#define SENSITIVITY_MAX_VALUE 1.0f
#define PIXELS_PER_MILLIMETER_MIN_VALUE 3.0f
#define PIXELS_PER_MILLIMETER_MAX_VALUE 4.0f
//package net.minecraft.client; //package net.minecraft.client;
//#include "locale/Language.h" //#include "locale/Language.h"
#include <string> #include <string>
#include <cstdio> #include <cstdio>
#include "KeyMapping.h"
#include "../platform/input/Keyboard.h" #include "../platform/input/Keyboard.h"
#include "../util/StringUtils.h" #include "../util/StringUtils.h"
#include "OptionsFile.h" #include "OptionsFile.h"
#include "Option.h"
#include <array>
enum OptionId {
// General
OPTIONS_DIFFICULTY,
OPTIONS_HIDEGUI,
OPTIONS_THIRD_PERSON_VIEW,
OPTIONS_GUI_SCALE,
OPTIONS_DESTROY_VIBRATION,
OPTIONS_MUSIC_VOLUME,
OPTIONS_SOUND_VOLUME,
OPTIONS_SKIN,
OPTIONS_USERNAME,
OPTIONS_SERVER_VISIBLE,
OPTIONS_BAR_ON_TOP,
OPTIONS_ALLOW_SPRINT,
OPTIONS_AUTOJUMP,
// Graphics
OPTIONS_RENDER_DEBUG,
OPTIONS_SMOOTH_CAMERA,
OPTIONS_FIXED_CAMERA,
OPTIONS_VIEW_DISTANCE,
OPTIONS_VIEW_BOBBING,
OPTIONS_AMBIENT_OCCLUSION,
OPTIONS_ANAGLYPH_3D,
OPTIONS_LIMIT_FRAMERATE,
OPTIONS_VSYNC,
OPTIONS_FANCY_GRAPHICS,
// Cheats / debug
OPTIONS_FLY_SPEED,
OPTIONS_CAMERA_SPEED,
OPTIONS_IS_FLYING,
// Control
OPTIONS_USE_MOUSE_FOR_DIGGING,
OPTIONS_IS_LEFT_HANDED,
OPTIONS_IS_JOY_TOUCH_AREA,
OPTIONS_SENSITIVITY,
OPTIONS_INVERT_Y_MOUSE,
OPTIONS_USE_TOUCHSCREEN,
OPTIONS_KEY_FORWARD,
OPTIONS_KEY_LEFT,
OPTIONS_KEY_BACK,
OPTIONS_KEY_RIGHT,
OPTIONS_KEY_JUMP,
OPTIONS_KEY_INVENTORY,
OPTIONS_KEY_SNEAK,
OPTIONS_KEY_DROP,
OPTIONS_KEY_CHAT,
OPTIONS_KEY_FOG,
OPTIONS_KEY_USE,
OPTIONS_KEY_MENU_NEXT,
OPTIONS_KEY_MENU_PREV,
OPTIONS_KEY_MENU_OK,
OPTIONS_KEY_MENU_CANCEL,
OPTIONS_FIRST_LAUNCH,
OPTIONS_LAST_IP,
// Should be last!
OPTIONS_COUNT
};
class Minecraft; class Minecraft;
typedef std::vector<std::string> StringVector; typedef std::vector<std::string> StringVector;
@@ -18,311 +93,74 @@ typedef std::vector<std::string> StringVector;
class Options class Options
{ {
public: public:
class Option static bool debugGl;
{
const bool _isProgress;
const bool _isBoolean;
const std::string _captionId;
const int _ordinal;
public:
static const Option MUSIC;
static const Option SOUND;
static const Option INVERT_MOUSE;
static const Option SENSITIVITY;
static const Option RENDER_DISTANCE;
static const Option VIEW_BOBBING;
static const Option ANAGLYPH;
static const Option LIMIT_FRAMERATE;
static const Option DIFFICULTY;
static const Option GRAPHICS;
static const Option AMBIENT_OCCLUSION;
static const Option GUI_SCALE;
static const Option THIRD_PERSON;
static const Option HIDE_GUI;
static const Option SERVER_VISIBLE;
static const Option LEFT_HANDED;
static const Option USE_TOUCHSCREEN;
static const Option USE_TOUCH_JOYPAD;
static const Option DESTROY_VIBRATION;
static const Option PIXELS_PER_MILLIMETER;
/*
static Option* getItem(int id) {
for (Option item : Option.values()) {
if (item.getId() == id) {
return item;
}
}
return NULL;
}
*/
Option(int ordinal, const std::string& captionId, bool hasProgress, bool isBoolean)
: _captionId(captionId),
_isProgress(hasProgress),
_isBoolean(isBoolean),
_ordinal(ordinal)
{}
bool isProgress() const {
return _isProgress;
}
bool isBoolean() const {
return _isBoolean;
}
bool isInt() const {
return (!_isBoolean && !_isProgress);
}
int getId() {
return _ordinal;
}
std::string getCaptionId() const {
return _captionId;
}
};
private:
static const float SOUND_MIN_VALUE;
static const float SOUND_MAX_VALUE;
static const float MUSIC_MIN_VALUE;
static const float MUSIC_MAX_VALUE;
static const float SENSITIVITY_MIN_VALUE;
static const float SENSITIVITY_MAX_VALUE;
static const float PIXELS_PER_MILLIMETER_MIN_VALUE;
static const float PIXELS_PER_MILLIMETER_MAX_VALUE;
static const char* RENDER_DISTANCE_NAMES[];
static const char* DIFFICULTY_NAMES[];
static const char* GUI_SCALE[];
static const int DIFFICULY_LEVELS[];
public:
static bool debugGl;
float music;
float sound;
//note: sensitivity is transformed in Options::update
float sensitivity;
bool invertYMouse;
int viewDistance;
bool bobView;
bool anaglyph3d;
bool limitFramerate;
bool fancyGraphics;
bool ambientOcclusion;
bool useMouseForDigging;
bool isLeftHanded;
bool destroyVibration;
//std::string skin;
KeyMapping keyUp;
KeyMapping keyLeft;
KeyMapping keyDown;
KeyMapping keyRight;
KeyMapping keyJump;
KeyMapping keyBuild;
KeyMapping keyDrop;
KeyMapping keyChat;
KeyMapping keyFog;
KeyMapping keySneak;
KeyMapping keyCraft;
KeyMapping keyDestroy;
KeyMapping keyUse;
KeyMapping keyMenuNext;
KeyMapping keyMenuPrevious;
KeyMapping keyMenuOk;
KeyMapping keyMenuCancel;
KeyMapping* keyMappings[16];
/*protected*/ Minecraft* minecraft;
///*private*/ File optionsFile;
int difficulty;
bool hideGui;
bool thirdPersonView;
bool renderDebug;
bool isFlying;
bool smoothCamera;
bool fixedCamera;
float flySpeed;
float cameraSpeed;
int guiScale;
std::string username;
bool serverVisible;
bool isJoyTouchArea;
bool useTouchScreen;
float pixelsPerMillimeter;
Options(Minecraft* minecraft, const std::string& workingDirectory)
: minecraft(minecraft)
{
//optionsFile = /*new*/ File(workingDirectory, "options.txt");
initDefaultValues();
Options(Minecraft* minecraft, const std::string& workingDirectory = "")
: minecraft(minecraft) {
// elements werent initialized so i was getting a garbage pointer and a crash
m_options.fill(nullptr);
initTable();
load(); load();
} }
Options() void initTable();
: minecraft(NULL)
{
}
void initDefaultValues(); void set(OptionId key, int value);
void set(OptionId key, float value);
void set(OptionId key, const std::string& value);
void toggle(OptionId key);
std::string getKeyDescription(int i) { int getIntValue(OptionId key) {
//Language language = Language.getInstance(); auto option = opt<OptionInt>(key);
//return language.getElement(keyMappings[i].name); return (option)? option->get() : 0;
return "Options::getKeyDescription not implemented";
} }
std::string getKeyMessage(int i) { std::string getStringValue(OptionId key) {
//return Keyboard.getKeyName(keyMappings[i].key); auto option = opt<OptionString>(key);
return "Options::getKeyMessage not implemented"; return (option)? option->get() : "";
} }
void setKey(int i, int key) { float getProgressValue(OptionId key) {
keyMappings[i]->key = key; auto option = opt<OptionFloat>(key);
save(); return (option)? option->get() : 0.f;
} }
void set(const Option* item, float value) { bool getBooleanValue(OptionId key) {
if (item == &Option::MUSIC) { auto option = opt<OptionBool>(key);
music = value; return (option)? option->get() : false;
//minecraft.soundEngine.updateOptions();
} else if (item == &Option::SOUND) {
sound = value;
//minecraft.soundEngine.updateOptions();
} else if (item == &Option::SENSITIVITY) {
sensitivity = value;
} else if (item == &Option::PIXELS_PER_MILLIMETER) {
pixelsPerMillimeter = value;
}
notifyOptionUpdate(item, value);
}
void set(const Option* item, int value) {
if(item == &Option::DIFFICULTY) {
difficulty = value;
}
notifyOptionUpdate(item, value);
}
void toggle(const Option* option, int dir) {
if (option == &Option::INVERT_MOUSE) invertYMouse = !invertYMouse;
if (option == &Option::RENDER_DISTANCE) viewDistance = (viewDistance + dir) & 3;
if (option == &Option::GUI_SCALE) guiScale = (guiScale + dir) & 3;
if (option == &Option::VIEW_BOBBING) bobView = !bobView;
if (option == &Option::THIRD_PERSON) thirdPersonView = !thirdPersonView;
if (option == &Option::HIDE_GUI) hideGui = !hideGui;
if (option == &Option::SERVER_VISIBLE) serverVisible = !serverVisible;
if (option == &Option::LEFT_HANDED) isLeftHanded = !isLeftHanded;
if (option == &Option::USE_TOUCHSCREEN) useTouchScreen = !useTouchScreen;
if (option == &Option::USE_TOUCH_JOYPAD) isJoyTouchArea = !isJoyTouchArea;
if (option == &Option::DESTROY_VIBRATION) destroyVibration = !destroyVibration;
if (option == &Option::ANAGLYPH) {
anaglyph3d = !anaglyph3d;
//minecraft->textures.reloadAll();
}
if (option == &Option::LIMIT_FRAMERATE) limitFramerate = !limitFramerate;
if (option == &Option::DIFFICULTY) difficulty = (difficulty + dir) & 3;
if (option == &Option::GRAPHICS) {
fancyGraphics = !fancyGraphics;
//minecraft->levelRenderer.allChanged();
}
if (option == &Option::AMBIENT_OCCLUSION) {
ambientOcclusion = !ambientOcclusion;
//minecraft->levelRenderer.allChanged();
}
notifyOptionUpdate(option, getBooleanValue(option));
save();
} }
int getIntValue(const Option* item) { float getProgrssMin(OptionId key) {
if(item == &Option::DIFFICULTY) return difficulty; auto option = opt<OptionFloat>(key);
return 0; return (option)? option->getMin() : 0.f;
}
float getProgressValue(const Option* item) {
if (item == &Option::MUSIC) return music;
if (item == &Option::SOUND) return sound;
if (item == &Option::SENSITIVITY) return sensitivity;
if (item == &Option::PIXELS_PER_MILLIMETER) return pixelsPerMillimeter;
return 0;
} }
bool getBooleanValue(const Option* item) { float getProgrssMax(OptionId key) {
if (item == &Option::INVERT_MOUSE) auto option = opt<OptionFloat>(key);
return invertYMouse; return (option)? option->getMax() : 0.f;
if (item == &Option::VIEW_BOBBING) }
return bobView;
if (item == &Option::ANAGLYPH)
return anaglyph3d;
if (item == &Option::LIMIT_FRAMERATE)
return limitFramerate;
if (item == &Option::AMBIENT_OCCLUSION)
return ambientOcclusion;
if (item == &Option::THIRD_PERSON)
return thirdPersonView;
if (item == &Option::HIDE_GUI)
return hideGui;
if (item == &Option::THIRD_PERSON)
return thirdPersonView;
if (item == &Option::SERVER_VISIBLE)
return serverVisible;
if (item == &Option::LEFT_HANDED)
return isLeftHanded;
if (item == &Option::USE_TOUCHSCREEN)
return useTouchScreen;
if (item == &Option::USE_TOUCH_JOYPAD)
return isJoyTouchArea;
if (item == &Option::DESTROY_VIBRATION)
return destroyVibration;
return false;
}
float getProgrssMin(const Option* item) { Option* getOpt(OptionId id) { return m_options[id]; }
if (item == &Option::MUSIC) return MUSIC_MIN_VALUE;
if (item == &Option::SOUND) return SOUND_MIN_VALUE;
if (item == &Option::SENSITIVITY) return SENSITIVITY_MIN_VALUE;
if (item == &Option::PIXELS_PER_MILLIMETER) return PIXELS_PER_MILLIMETER_MIN_VALUE;
return 0;
}
float getProgrssMax(const Option* item) {
if (item == &Option::MUSIC) return MUSIC_MAX_VALUE;
if (item == &Option::SOUND) return SOUND_MAX_VALUE;
if (item == &Option::SENSITIVITY) return SENSITIVITY_MAX_VALUE;
if (item == &Option::PIXELS_PER_MILLIMETER) return PIXELS_PER_MILLIMETER_MAX_VALUE;
return 1.0f;
}
std::string getMessage(const Option* item);
void update();
void load(); void load();
void save(); void save();
void addOptionToSaveOutput(StringVector& stringVector, std::string name, bool boolValue);
void addOptionToSaveOutput(StringVector& stringVector, std::string name, float floatValue); void notifyOptionUpdate(OptionId key, bool value);
void addOptionToSaveOutput(StringVector& stringVector, std::string name, int intValue); void notifyOptionUpdate(OptionId key, float value);
void notifyOptionUpdate(const Option* option, bool value); void notifyOptionUpdate(OptionId key, int value);
void notifyOptionUpdate(const Option* option, float value); void notifyOptionUpdate(OptionId key, const std::string& value) {}
void notifyOptionUpdate(const Option* option, int value);
private:
static bool readFloat(const std::string& string, float& value);
static bool readInt(const std::string& string, int& value);
static bool readBool(const std::string& string, bool& value);
private: private:
template<typename T>
T* opt(OptionId key) {
if (m_options[key] == nullptr) return nullptr;
return dynamic_cast<T*>(m_options[key]);
}
std::array<Option*, OPTIONS_COUNT> m_options;
OptionsFile optionsFile; OptionsFile optionsFile;
Minecraft* minecraft;
}; };
#endif /*NET_MINECRAFT_CLIENT__Options_H__*/ #endif /*NET_MINECRAFT_CLIENT__Options_H__*/

View File

@@ -1,6 +1,7 @@
#include "OptionsFile.h" #include "OptionsFile.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <platform/log.h>
OptionsFile::OptionsFile() { OptionsFile::OptionsFile() {
#ifdef __APPLE__ #ifdef __APPLE__
@@ -19,19 +20,32 @@ void OptionsFile::save(const StringVector& settings) {
fprintf(pFile, "%s\n", it->c_str()); fprintf(pFile, "%s\n", it->c_str());
} }
fclose(pFile); fclose(pFile);
} else {
LOGI("OptionsFile::save failed to open '%s' for writing: %s", settingsPath.c_str(), strerror(errno));
} }
} }
StringVector OptionsFile::getOptionStrings() { StringVector OptionsFile::getOptionStrings() {
StringVector returnVector; StringVector returnVector;
FILE* pFile = fopen(settingsPath.c_str(), "w"); FILE* pFile = fopen(settingsPath.c_str(), "r");
if(pFile != NULL) { if(pFile != NULL) {
char lineBuff[128]; char lineBuff[128];
while(fgets(lineBuff, sizeof lineBuff, pFile)) { while(fgets(lineBuff, sizeof lineBuff, pFile)) {
if(strlen(lineBuff) > 2) // Strip trailing newline
returnVector.push_back(std::string(lineBuff)); size_t len = strlen(lineBuff);
while(len > 0 && (lineBuff[len-1] == '\n' || lineBuff[len-1] == '\r'))
lineBuff[--len] = '\0';
if(len < 3) continue;
// Split "key:value" into two separate entries to match update() pairing
char* colon = strchr(lineBuff, ':');
if(colon) {
returnVector.push_back(std::string(lineBuff, colon - lineBuff));
returnVector.push_back(std::string(colon + 1));
}
} }
fclose(pFile); fclose(pFile);
} else {
LOGI("OptionsFile::getOptionStrings failed to open '%s' for reading: %s", settingsPath.c_str(), strerror(errno));
} }
return returnVector; return returnVector;
} }

View File

@@ -1,62 +0,0 @@
#ifndef NET_MINECRAFT_CLIENT__User_H__
#define NET_MINECRAFT_CLIENT__User_H__
//package net.minecraft.client;
#include "../world/level/tile/Tile.h"
class User
{
public:
//static List<Tile> allowedTiles = /*new*/ ArrayList<Tile>();
//static {
// allowedTiles.push_back(Tile::rock);
// allowedTiles.push_back(Tile::stoneBrick);
// allowedTiles.push_back(Tile::redBrick);
// allowedTiles.push_back(Tile::dirt);
// allowedTiles.push_back(Tile::wood);
// allowedTiles.push_back(Tile::treeTrunk);
// allowedTiles.push_back(Tile::leaves);
// allowedTiles.push_back(Tile::torch);
// allowedTiles.push_back(Tile::stoneSlabHalf);
// allowedTiles.push_back(Tile::glass);
// allowedTiles.push_back(Tile::mossStone);
// allowedTiles.push_back(Tile::sapling);
// allowedTiles.push_back(Tile::flower);
// allowedTiles.push_back(Tile::rose);
// allowedTiles.push_back(Tile::mushroom1);
// allowedTiles.push_back(Tile::mushroom2);
// allowedTiles.push_back(Tile::sand);
// allowedTiles.push_back(Tile::gravel);
// allowedTiles.push_back(Tile::sponge);
// allowedTiles.push_back(Tile::cloth);
// allowedTiles.push_back(Tile::coalOre);
// allowedTiles.push_back(Tile::ironOre);
// allowedTiles.push_back(Tile::goldOre);
// allowedTiles.push_back(Tile::ironBlock);
// allowedTiles.push_back(Tile::goldBlock);
// allowedTiles.push_back(Tile::bookshelf);
// allowedTiles.push_back(Tile::tnt);
// allowedTiles.push_back(Tile::obsidian);
// // System.out.println(allowedTiles.size());
//}
static bool isTileAllowed(const Tile& tile) {
return true;
}
std::string name;
std::string sessionId;
//std::string mpPassword;
User(const std::string& name, const std::string& sessionId) {
this->name = name;
this->sessionId = sessionId;
}
};
#endif /*NET_MINECRAFT_CLIENT__User_H__*/

View File

@@ -13,10 +13,10 @@
#include "../../network/packet/RemoveBlockPacket.h" #include "../../network/packet/RemoveBlockPacket.h"
#include "../../world/entity/player/Abilities.h" #include "../../world/entity/player/Abilities.h"
static const int DestructionTickDelay = 10; static const int DestructionTickDelay = 5;
CreativeMode::CreativeMode(Minecraft* minecraft) CreativeMode::CreativeMode(Minecraft* minecraft)
: super(minecraft) : super(minecraft)
{ {
} }
@@ -29,12 +29,8 @@ void CreativeMode::startDestroyBlock(int x, int y, int z, int face) {
} }
void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) { void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) {
//if (! minecraft->level->extinguishFire(x, y, z, face);
minecraft->level->extinguishFire(x, y, z, face) destroyBlock(x, y, z, face);
//{
;
destroyBlock(x, y, z, face);
//}
} }
void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) { void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
@@ -46,6 +42,7 @@ void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
} }
void CreativeMode::stopDestroyBlock() { void CreativeMode::stopDestroyBlock() {
destroyDelay = 0;
} }
void CreativeMode::initAbilities( Abilities& abilities ) { void CreativeMode::initAbilities( Abilities& abilities ) {

View File

@@ -9,7 +9,7 @@
#include "../../network/packet/RemoveBlockPacket.h" #include "../../network/packet/RemoveBlockPacket.h"
#include "../../world/entity/player/Abilities.h" #include "../../world/entity/player/Abilities.h"
static const int DestructionTickDelay = 10; static const int DestructionTickDelay = 5;
class Creator: public ICreator { class Creator: public ICreator {
//virtual void getEvents(); //virtual void getEvents();
@@ -60,12 +60,8 @@ void CreatorMode::startDestroyBlock(int x, int y, int z, int face) {
} }
void CreatorMode::CreatorDestroyBlock(int x, int y, int z, int face) { void CreatorMode::CreatorDestroyBlock(int x, int y, int z, int face) {
//if (! minecraft->level->extinguishFire(x, y, z, face);
minecraft->level->extinguishFire(x, y, z, face) destroyBlock(x, y, z, face);
//{
;
destroyBlock(x, y, z, face);
//}
} }
void CreatorMode::continueDestroyBlock(int x, int y, int z, int face) { void CreatorMode::continueDestroyBlock(int x, int y, int z, int face) {
@@ -83,6 +79,7 @@ bool CreatorMode::useItemOn( Player* player, Level* level, ItemInstance* item, i
} }
void CreatorMode::stopDestroyBlock() { void CreatorMode::stopDestroyBlock() {
destroyDelay = 0;
} }
void CreatorMode::initAbilities( Abilities& abilities ) { void CreatorMode::initAbilities( Abilities& abilities ) {

View File

@@ -5,6 +5,7 @@
#include "../../world/level/Level.h" #include "../../world/level/Level.h"
#include "../../world/item/ItemInstance.h" #include "../../world/item/ItemInstance.h"
#include "../player/LocalPlayer.h" #include "../player/LocalPlayer.h"
#include "client/Options.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "../sound/SoundEngine.h" #include "../sound/SoundEngine.h"
#include "../particle/ParticleEngine.h" #include "../particle/ParticleEngine.h"
@@ -27,7 +28,7 @@ GameMode::GameMode( Minecraft* minecraft)
/*virtual*/ /*virtual*/
Player* GameMode::createPlayer(Level* level) { Player* GameMode::createPlayer(Level* level) {
return new LocalPlayer(minecraft, level, minecraft->user, level->dimension->id, isCreativeType()); return new LocalPlayer(minecraft, level, minecraft->options.getStringValue(OPTIONS_USERNAME), level->dimension->id, isCreativeType());
} }
/*virtual*/ /*virtual*/
@@ -74,7 +75,7 @@ bool GameMode::destroyBlock(int x, int y, int z, int face) {
minecraft->soundEngine->play(oldTile->soundType->getBreakSound(), x + 0.5f, y + 0.5f, z + 0.5f, (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f); minecraft->soundEngine->play(oldTile->soundType->getBreakSound(), x + 0.5f, y + 0.5f, z + 0.5f, (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f);
#endif #endif
oldTile->destroy(level, x, y, z, data); oldTile->destroy(level, x, y, z, data);
if (minecraft->options.destroyVibration) minecraft->platform()->vibrate(24); if (minecraft->options.getBooleanValue(OPTIONS_DESTROY_VIBRATION)) minecraft->platform()->vibrate(24);
if (minecraft->isOnline()) { if (minecraft->isOnline()) {
RemoveBlockPacket packet(minecraft->player, x, y, z); RemoveBlockPacket packet(minecraft->player, x, y, z);

View File

@@ -1,6 +1,10 @@
#include "Gui.h" #include "Gui.h"
#include "Font.h" #include "Font.h"
#include "client/Options.h"
#include "platform/input/Keyboard.h"
#include "screens/IngameBlockSelectionScreen.h" #include "screens/IngameBlockSelectionScreen.h"
#include "screens/ChatScreen.h"
#include "screens/ConsoleScreen.h"
#include "../Minecraft.h" #include "../Minecraft.h"
#include "../player/LocalPlayer.h" #include "../player/LocalPlayer.h"
#include "../renderer/Tesselator.h" #include "../renderer/Tesselator.h"
@@ -20,6 +24,10 @@
#include "../../platform/input/Mouse.h" #include "../../platform/input/Mouse.h"
#include "../../world/level/Level.h" #include "../../world/level/Level.h"
#include "../../world/PosTranslator.h" #include "../../world/PosTranslator.h"
#include "../../platform/time.h"
#include <cmath>
#include <algorithm>
#include <sstream>
float Gui::InvGuiScale = 1.0f / 3.0f; float Gui::InvGuiScale = 1.0f / 3.0f;
float Gui::GuiScale = 1.0f / Gui::InvGuiScale; float Gui::GuiScale = 1.0f / Gui::InvGuiScale;
@@ -33,6 +41,7 @@ Gui::Gui(Minecraft* minecraft)
progress(0), progress(0),
overlayMessageTime(0), overlayMessageTime(0),
animateOverlayMessageColor(false), animateOverlayMessageColor(false),
chatScrollOffset(0),
tbr(1), tbr(1),
_inventoryNeedsUpdate(true), _inventoryNeedsUpdate(true),
_flashSlotId(-1), _flashSlotId(-1),
@@ -84,14 +93,16 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
// F: 3 // F: 3
int ySlot = screenHeight - 16 - 3; int ySlot = screenHeight - 16 - 3;
if (minecraft->gameMode->canHurtPlayer()) { if (!minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
minecraft->textures->loadAndBindTexture("gui/icons.png"); if (minecraft->gameMode->canHurtPlayer()) {
Tesselator& t = Tesselator::instance; minecraft->textures->loadAndBindTexture("gui/icons.png");
t.beginOverride(); Tesselator& t = Tesselator::instance;
t.colorABGR(0xffffffff); t.beginOverride();
renderHearts(); t.colorABGR(0xffffffff);
renderBubbles(); renderHearts();
t.endOverrideAndDraw(); renderBubbles();
t.endOverrideAndDraw();
}
} }
if(minecraft->player->getSleepTimer() > 0) { if(minecraft->player->getSleepTimer() > 0) {
@@ -103,18 +114,22 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
glEnable(GL_ALPHA_TEST); glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
} }
if (!minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
renderToolBar(a, ySlot, screenWidth); renderToolBar(a, ySlot, screenWidth);
//font->drawShadow(APP_NAME, 2, 2, 0xffffffff);
//font->drawShadow("This is a demo, not the finished product", 2, 10 + 2, 0xffffffff);
#ifdef APPLE_DEMO_PROMOTION
font->drawShadow("Demo version", 2, 0 + 2, 0xffffffff);
#endif /*APPLE_DEMO_PROMOTION*/
glEnable(GL_BLEND); glEnable(GL_BLEND);
bool isChatting = (minecraft->screen && (dynamic_cast<ChatScreen*>(minecraft->screen) || dynamic_cast<ConsoleScreen*>(minecraft->screen)));
unsigned int max = 10; unsigned int max = 10;
bool isChatting = false; if (isChatting) {
int lineHeight = 9;
max = (screenHeight - 48) / lineHeight;
if (max < 1) max = 1;
int maxScroll = (int)guiMessages.size() - (int)max;
if (maxScroll < 0) maxScroll = 0;
if (chatScrollOffset > maxScroll) chatScrollOffset = maxScroll;
} else {
chatScrollOffset = 0;
}
renderChatMessages(screenHeight, max, isChatting, font); renderChatMessages(screenHeight, max, isChatting, font);
#if !defined(RPI) #if !defined(RPI)
renderOnSelectItemNameText(screenWidth, font, ySlot); renderOnSelectItemNameText(screenWidth, font, ySlot);
@@ -123,9 +138,14 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
renderDebugInfo(); renderDebugInfo();
#endif #endif
// glPopMatrix2(); if (Keyboard::isKeyDown(Keyboard::KEY_TAB)) {
// renderPlayerList(font, screenWidth, screenHeight);
// glEnable(GL_ALPHA_TEST); }
if (minecraft->options.getBooleanValue(OPTIONS_RENDER_DEBUG))
renderDebugInfo();
}
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable2(GL_ALPHA_TEST); glEnable2(GL_ALPHA_TEST);
} }
@@ -188,11 +208,13 @@ void Gui::handleClick(int button, int x, int y) {
int slot = getSlotIdAt(x, y); int slot = getSlotIdAt(x, y);
if (slot != -1) if (slot != -1)
{ {
#ifndef PLATFORM_DESKTOP
if (slot == (getNumSlots()-1)) if (slot == (getNumSlots()-1))
{ {
minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION); minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION);
} }
else else
#endif
{ {
minecraft->player->inventory->selectSlot(slot); minecraft->player->inventory->selectSlot(slot);
itemNameOverlayTime = 0; itemNameOverlayTime = 0;
@@ -202,6 +224,33 @@ void Gui::handleClick(int button, int x, int y) {
void Gui::handleKeyPressed(int key) void Gui::handleKeyPressed(int key)
{ {
bool isChatting = (minecraft->screen && (dynamic_cast<ChatScreen*>(minecraft->screen) || dynamic_cast<ConsoleScreen*>(minecraft->screen)));
if (isChatting) {
// Allow scrolling the chat history with the mouse/keyboard when chat is open
if (key == 38) { // VK_UP
scrollChat(1);
return;
} else if (key == 40) { // VK_DOWN
scrollChat(-1);
return;
} else if (key == 33) { // VK_PRIOR (Page Up)
// Scroll by a page
int screenHeight = (int)(minecraft->height * InvGuiScale);
int maxVisible = (screenHeight - 48) / 9;
scrollChat(maxVisible);
return;
} else if (key == 34) { // VK_NEXT (Page Down)
int screenHeight = (int)(minecraft->height * InvGuiScale);
int maxVisible = (screenHeight - 48) / 9;
scrollChat(-maxVisible);
return;
}
}
if (key == Keyboard::KEY_F1) {
minecraft->options.toggle(OPTIONS_HIDEGUI);
}
if (key == 99) if (key == 99)
{ {
if (minecraft->player->inventory->selected > 0) if (minecraft->player->inventory->selected > 0)
@@ -220,6 +269,27 @@ void Gui::handleKeyPressed(int key)
{ {
minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION); minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION);
} }
else if (key == minecraft->options.getIntValue(OPTIONS_KEY_DROP))
{
minecraft->player->inventory->dropSlot(minecraft->player->inventory->selected, false);
}
}
void Gui::scrollChat(int delta) {
if (delta == 0)
return;
int screenHeight = (int)(minecraft->height * InvGuiScale);
int maxVisible = (screenHeight - 48) / 9;
if (maxVisible <= 0)
return;
int maxScroll = (int)guiMessages.size() - maxVisible;
if (maxScroll < 0) maxScroll = 0;
int desired = chatScrollOffset + delta;
if (desired < 0) desired = 0;
if (desired > maxScroll) desired = maxScroll;
chatScrollOffset = desired;
} }
void Gui::tick() { void Gui::tick() {
@@ -252,9 +322,22 @@ void Gui::addMessage(const std::string& _string) {
message.message = string; message.message = string;
message.ticks = 0; message.ticks = 0;
guiMessages.insert(guiMessages.begin(), message); guiMessages.insert(guiMessages.begin(), message);
while (guiMessages.size() > 30) {
// Keep a larger history so users can scroll through the full chat
const unsigned int MaxHistoryLines = 200;
while (guiMessages.size() > MaxHistoryLines) {
guiMessages.pop_back(); guiMessages.pop_back();
} }
// If the user has scrolled up, keep their window fixed (new messages shift older ones down)
if (chatScrollOffset > 0) {
chatScrollOffset++;
}
}
void Gui::clearMessages() {
guiMessages.clear();
chatScrollOffset = 0;
} }
void Gui::setNowPlaying(const std::string& string) { void Gui::setNowPlaying(const std::string& string) {
@@ -395,10 +478,11 @@ void Gui::onConfigChanged( const Config& c ) {
//LOGI("x,y: %f, %f\n", xx, yy); //LOGI("x,y: %f, %f\n", xx, yy);
} }
rcFeedbackInner = t.end(true, rcFeedbackInner.vboId); rcFeedbackInner = t.end(true, rcFeedbackInner.vboId);
if (c.minecraft->useTouchscreen()) { if (c.minecraft->useTouchscreen()) {
// I'll bump this up to 6. // I'll bump this up to 6.
int num = 6; // without "..." dots int num = 6; // without "..." dots
if (!c.minecraft->options.isJoyTouchArea && c.width > 480) { if (!c.minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA) && c.width > 480) {
while (num < Inventory::MAX_SELECTION_SIZE - 1) { while (num < Inventory::MAX_SELECTION_SIZE - 1) {
int x0, x1, y; int x0, x1, y;
getSlotPos(0, x0, y); getSlotPos(0, x0, y);
@@ -452,9 +536,16 @@ void Gui::tickItemDrop()
// Handle item drop // Handle item drop
static bool isCurrentlyActive = false; static bool isCurrentlyActive = false;
isCurrentlyActive = false; isCurrentlyActive = false;
int slots = getNumSlots();
#ifndef PLATFORM_DESKTOP
slots--;
#endif
if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) {
int slot = getSlotIdAt(Mouse::getX(), Mouse::getY()); int slot = getSlotIdAt(Mouse::getX(), Mouse::getY());
if (slot >= 0 && slot < getNumSlots()-1) { if (slot >= 0 && slot < slots) {
if (slot != _currentDropSlot) { if (slot != _currentDropSlot) {
_currentDropTicks = 0; _currentDropTicks = 0;
_currentDropSlot = slot; _currentDropSlot = slot;
@@ -505,7 +596,8 @@ void Gui::renderProgressIndicator( const bool isTouchInterface, const int screen
ItemInstance* currentItem = minecraft->player->inventory->getSelected(); ItemInstance* currentItem = minecraft->player->inventory->getSelected();
bool bowEquipped = currentItem != NULL ? currentItem->getItem() == Item::bow : false; bool bowEquipped = currentItem != NULL ? currentItem->getItem() == Item::bow : false;
bool itemInUse = currentItem != NULL ? currentItem->getItem() == minecraft->player->getUseItem()->getItem() : false; bool itemInUse = currentItem != NULL ? currentItem->getItem() == minecraft->player->getUseItem()->getItem() : false;
if (!isTouchInterface || minecraft->options.isJoyTouchArea || (bowEquipped && itemInUse)) { if ((!isTouchInterface || minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA)
|| (bowEquipped && itemInUse)) && !minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
minecraft->textures->loadAndBindTexture("gui/icons.png"); minecraft->textures->loadAndBindTexture("gui/icons.png");
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
@@ -574,11 +666,14 @@ void Gui::renderHearts() {
int oh = minecraft->player->lastHealth; int oh = minecraft->player->lastHealth;
random.setSeed(tickCount * 312871); random.setSeed(tickCount * 312871);
int xx = 2;//screenWidth / 2 - getNumSlots() * 10; int screenWidth = (int)(minecraft->width * InvGuiScale);
int screenHeight = (int)(minecraft->height * InvGuiScale);
int xx = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenWidth / 2 - getNumSlots() * 10 - 1 : 2;
int armor = minecraft->player->getArmorValue(); int armor = minecraft->player->getArmorValue();
for (int i = 0; i < Player::MAX_HEALTH / 2; i++) { for (int i = 0; i < Player::MAX_HEALTH / 2; i++) {
int yo = 2; int yo = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenHeight - 32 : 2;
int ip2 = i + i + 1; int ip2 = i + i + 1;
if (armor > 0) { if (armor > 0) {
@@ -606,11 +701,15 @@ void Gui::renderHearts() {
void Gui::renderBubbles() { void Gui::renderBubbles() {
if (minecraft->player->isUnderLiquid(Material::water)) { if (minecraft->player->isUnderLiquid(Material::water)) {
int yo = 12; int screenWidth = (int)(minecraft->width * InvGuiScale);
int screenHeight = (int)(minecraft->height * InvGuiScale);
int xx = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenWidth / 2 - getNumSlots() * 10 - 1 : 2;
int yo = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenHeight - 42 : 12;
int count = (int) std::ceil((minecraft->player->airSupply - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY); int count = (int) std::ceil((minecraft->player->airSupply - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY);
int extra = (int) std::ceil((minecraft->player->airSupply) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count; int extra = (int) std::ceil((minecraft->player->airSupply) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count;
for (int i = 0; i < count + extra; i++) { for (int i = 0; i < count + extra; i++) {
int xo = i * 8 + 2; int xo = i * 8 + xx;
if (i < count) blit(xo, yo, 16, 9 * 2, 9, 9); if (i < count) blit(xo, yo, 16, 9 * 2, 9, 9);
else blit(xo, yo, 16 + 9, 9 * 2, 9, 9); else blit(xo, yo, 16 + 9, 9 * 2, 9, 9);
} }
@@ -626,20 +725,169 @@ void Gui::onLevelGenerated() {
} }
void Gui::renderDebugInfo() { void Gui::renderDebugInfo() {
static char buf[256]; // FPS counter (updates once per second)
float xx = minecraft->player->x; static float fps = 0.0f;
float yy = minecraft->player->y - minecraft->player->heightOffset; static float fpsLastTime = 0.0f;
float zz = minecraft->player->z; static int fpsFrames = 0;
posTranslator.to(xx, yy, zz); float now = getTimeS();
sprintf(buf, "pos: %3.1f, %3.1f, %3.1f\n", xx, yy, zz); fpsFrames++;
if (now - fpsLastTime >= 1.0f) {
fps = fpsFrames / (now - fpsLastTime);
fpsFrames = 0;
fpsLastTime = now;
}
LocalPlayer* p = minecraft->player;
Level* lvl = minecraft->level;
// Position
float px = p->x, py = p->y - p->heightOffset, pz = p->z;
posTranslator.to(px, py, pz);
int bx = (int)floorf(px), by = (int)floorf(py), bz = (int)floorf(pz);
int cx = bx >> 4, cz = bz >> 4;
// Facing direction
float yMod = fmodf(p->yRot, 360.0f);
if (yMod < 0) yMod += 360.0f;
const char* facing;
const char* axis;
if (yMod < 45 || yMod >= 315) { facing = "South"; axis = "+Z"; }
else if (yMod < 135) { facing = "West"; axis = "-X"; }
else if (yMod < 225) { facing = "North"; axis = "-Z"; }
else { facing = "East"; axis = "+X"; }
// Biome
const char* biomeName = "unknown";
if (lvl) {
Biome* biome = lvl->getBiome(bx, bz);
if (biome) biomeName = biome->name.c_str();
}
// Time
long worldTime = lvl ? lvl->getTime() : 0;
long dayTime = worldTime % Level::TICKS_PER_DAY;
long day = worldTime / Level::TICKS_PER_DAY;
long seed = lvl ? lvl->getSeed() : 0;
// Build lines (NULL entry = blank gap)
static char ln[8][96];
sprintf(ln[0], "Minecraft PE 0.6.1 alpha (mcpe64)");
sprintf(ln[1], "%.1f fps", fps);
ln[2][0] = '\0'; // blank separator
sprintf(ln[3], "XYZ: %.3f / %.3f / %.3f", px, py, pz);
sprintf(ln[4], "Block: %d %d %d Chunk: %d %d", bx, by, bz, cx, cz);
sprintf(ln[5], "Facing: %s (%s) (%.1f / %.1f)", facing, axis, p->yRot, p->xRot);
sprintf(ln[6], "Biome: %s", biomeName);
sprintf(ln[7], "Day %ld Time: %ld Seed: %ld", day, dayTime, seed);
const int N = 8;
const float LH = (float)Font::DefaultLineHeight; // 10 font-pixels
const float MGN = 2.0f; // left/top margin in font-pixels
const float PAD = 2.0f; // horizontal padding for background
Font* font = minecraft->font;
// 1) Draw semi-transparent background boxes behind each line
for (int i = 0; i < N; i++) {
if (ln[i][0] == '\0') continue;
float w = (float)font->width(ln[i]);
float x0 = MGN - PAD;
float y0 = MGN + i * LH - 1.0f;
float x1 = MGN + w + PAD;
float y1 = MGN + (i + 1) * LH - 1.0f;
fill(x0, y0, x1, y1, 0x90000000);
}
// 2) Draw text (no extra scale — font coords are in GUI units, same as fill)
Tesselator& t = Tesselator::instance; Tesselator& t = Tesselator::instance;
t.beginOverride(); t.beginOverride();
t.scale2d(InvGuiScale, InvGuiScale); for (int i = 0; i < N; i++) {
minecraft->font->draw(buf, 2, 2, 0xffffff); if (ln[i][0] == '\0') continue;
t.resetScale(); float y = MGN + i * LH;
int col = (i == 0) ? 0xffFFFF55 : 0xffffffff; // title yellow, rest white
font->draw(ln[i], MGN, y, col);
}
t.endOverrideAndDraw(); t.endOverrideAndDraw();
} }
void Gui::renderPlayerList(Font* font, int screenWidth, int screenHeight) {
// only show when in game, no other screen
// if (!minecraft->level) return;
// only show the overlay while connected to a multiplayer server
Level* level = minecraft->level;
if (!level) return;
if (!level->isClientSide) return;
std::vector<std::string> playerNames;
playerNames.reserve(level->players.size());
for (Player* player : level->players) {
if (!player) continue;
playerNames.push_back(player->name);
}
// is this check needed? if there are no players, the box won't render at all since height will be 0,
// but maybe we want to skip rendering entirely in that case
// if (playerNames.empty())
// return;
std::sort(playerNames.begin(), playerNames.end());
float maxNameWidth = 0.0f;
// find the longest name so we can size the box accordingly
for (const std::string& name : playerNames) {
float nameWidth = font->width(name);
if (nameWidth > maxNameWidth)
maxNameWidth = nameWidth;
}
// player count title
std::ostringstream titleStream;
titleStream << "Players (" << playerNames.size() << ")";
std::string titleText = titleStream.str();
float titleWidth = font->width(titleText);
if (titleWidth > maxNameWidth)
maxNameWidth = titleWidth;
const float padding = 4.0f;
const float lineHeight = (float)Font::DefaultLineHeight;
const float boxWidth = maxNameWidth + padding * 2;
const float boxHeight = (playerNames.size() + 1) * lineHeight + padding * 2;
const float boxLeft = (screenWidth - boxWidth) / 2.0f;
const float boxTop = 10.0f;
const float boxRight = boxLeft + boxWidth;
const float boxBottom = boxTop + boxHeight;
fill(boxLeft, boxTop, boxRight, boxBottom, 0x90000000);
float titleX = (screenWidth - titleWidth) / 2.0f;
float titleY = boxTop + padding;
// scale the text down slightly
// i think the gl scaling is the best for this
// oh my god this looks really bad OH GOD
//const float textScale = 0.8f;
//const float invTextScale = 1.0f / textScale;
//glPushMatrix2();
//glScalef2(textScale, textScale, 1);
// draw title
//font->draw(titleText, titleX * invTextScale, titleY * invTextScale, 0xFFFFFFFF);
font->draw(titleText, titleX, titleY, 0xFFFFFFFF);
// draw player names
// we should add ping icons here eventually, but for now just show names
float currentY = boxTop + padding + lineHeight;
for (const std::string& name : playerNames) {
font->draw(name, (boxLeft + padding), currentY, 0xFFDDDDDD);
currentY += lineHeight;
}
//glPopMatrix2();
}
void Gui::renderSleepAnimation( const int screenWidth, const int screenHeight ) { void Gui::renderSleepAnimation( const int screenWidth, const int screenHeight ) {
int timer = minecraft->player->getSleepTimer(); int timer = minecraft->player->getSleepTimer();
float amount = (float) timer / (float) Player::SLEEP_DURATION; float amount = (float) timer / (float) Player::SLEEP_DURATION;
@@ -670,6 +918,70 @@ void Gui::renderOnSelectItemNameText( const int screenWidth, Font* font, int ySl
} }
} }
// helper structure used by drawColoredString
struct ColorSegment {
std::string text;
uint32_t color;
};
// parse [tag] and [/tag] markers; tags may contain a color name (gold, green, etc.)
static void parseColorTags(const std::string& in, std::vector<ColorSegment>& out) {
uint32_t curColor = 0xffffff;
size_t pos = 0;
while (pos < in.size()) {
size_t open = in.find('[', pos);
if (open == std::string::npos) {
out.push_back({in.substr(pos), curColor});
break;
}
if (open > pos) {
out.push_back({in.substr(pos, open - pos), curColor});
}
size_t close = in.find(']', open);
if (close == std::string::npos) {
out.push_back({in.substr(open), curColor});
break;
}
std::string tag = in.substr(open + 1, close - open - 1);
if (!tag.empty() && tag[0] == '/') {
curColor = 0xffffff;
} else {
std::string lower;
lower.resize(tag.size());
std::transform(tag.begin(), tag.end(), lower.begin(), ::tolower);
if (lower.find("gold") != std::string::npos) curColor = 0xffd700;
else if (lower.find("green") != std::string::npos) curColor = 0x00ff00;
else if (lower.find("yellow") != std::string::npos) curColor = 0xffff00;
else if (lower.find("red") != std::string::npos) curColor = 0xff0000;
else if (lower.find("blue") != std::string::npos) curColor = 0x0000ff;
}
pos = close + 1;
}
}
void Gui::drawColoredString(Font* font, const std::string& text, float x, float y, int alpha) {
std::vector<ColorSegment> segs;
parseColorTags(text, segs);
float cx = x;
for (auto &s : segs) {
int color = s.color + (alpha << 24);
font->drawShadow(s.text, cx, y, color);
cx += font->width(s.text);
}
}
float Gui::getColoredWidth(Font* font, const std::string& text) {
std::vector<ColorSegment> segs;
parseColorTags(text, segs);
float w = 0;
for (auto &s : segs) {
w += font->width(s.text);
}
return w;
}
void Gui::renderChatMessages( const int screenHeight, unsigned int max, bool isChatting, Font* font ) { void Gui::renderChatMessages( const int screenHeight, unsigned int max, bool isChatting, Font* font ) {
// if (minecraft.screen instanceof ChatScreen) { // if (minecraft.screen instanceof ChatScreen) {
// max = 20; // max = 20;
@@ -685,9 +997,16 @@ void Gui::renderChatMessages( const int screenHeight, unsigned int max, bool isC
// // glScalef2(1.0f / ssc.scale, 1.0f / ssc.scale, 1); // // glScalef2(1.0f / ssc.scale, 1.0f / ssc.scale, 1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int baseY = screenHeight - 48; int baseY = screenHeight - 48;
for (unsigned int i = 0; i < guiMessages.size() && i < max; i++) { int start = chatScrollOffset;
if (guiMessages.at(i).ticks < 20 * 10 || isChatting) { if (start < 0) start = 0;
float t = guiMessages.at(i).ticks / (20 * 10.0f); for (unsigned int i = 0; i < max; i++) {
unsigned int msgIdx = (unsigned int)start + i;
if (msgIdx >= guiMessages.size())
break;
GuiMessage& message = guiMessages.at(msgIdx);
if (message.ticks < 20 * 10 || isChatting) {
float t = message.ticks / (20 * 10.0f);
t = 1 - t; t = 1 - t;
t = t * 10; t = t * 10;
if (t < 0) t = 0; if (t < 0) t = 0;
@@ -699,11 +1018,18 @@ void Gui::renderChatMessages( const int screenHeight, unsigned int max, bool isC
if (alpha > 0) { if (alpha > 0) {
const float x = 2; const float x = 2;
const float y = (float)(baseY - i * 9); const float y = (float)(baseY - i * 9);
std::string msg = guiMessages.at(i).message; std::string msg = message.message;
this->fill(x, y - 1, x + MAX_MESSAGE_WIDTH, y + 8, (alpha / 2) << 24); this->fill(x, y - 1, x + MAX_MESSAGE_WIDTH, y + 8, (alpha / 2) << 24);
glEnable(GL_BLEND); glEnable(GL_BLEND);
font->drawShadow(msg, x, y, 0xffffff + (alpha << 24)); // special-case join/leave announcements
int baseColor = 0xffffff;
if (msg.find(" joined the game") != std::string::npos ||
msg.find(" left the game") != std::string::npos) {
baseColor = 0xffff00; // yellow
}
// replace previous logic; allow full colour tags now
Gui::drawColoredString(font, msg, x, y, alpha);
} }
} }
} }
@@ -756,20 +1082,24 @@ void Gui::renderToolBar( float a, int ySlot, const int screenWidth ) {
t.beginOverride(); t.beginOverride();
float x = baseItemX; float x = baseItemX;
for (int i = 0; i < getNumSlots()-1; i++) {
int slots = getNumSlots();
// TODO: if using touchscreen
#ifndef PLATFORM_DESKTOP
slots--;
#endif
for (int i = 0; i < slots; i++) {
renderSlot(i, (int)x, ySlot, a); renderSlot(i, (int)x, ySlot, a);
x += 20; x += 20;
} }
_inventoryNeedsUpdate = false; _inventoryNeedsUpdate = false;
//_inventoryRc = t.end(_inventoryRc.vboId);
//drawArrayVTC(_inventoryRc.vboId, _inventoryRc.vertexCount); #ifndef PLATFORM_DESKTOP
//renderSlotWatch.stop();
//renderSlotWatch.printEvery(100, "Render slots:");
//int x = screenWidth / 2 + getNumSlots() * 10 + (getNumSlots()-1) * 20 + 2;
blit(screenWidth / 2 + 10 * getNumSlots() - 20 + 4, ySlot + 6, 242, 252, 14, 4, 14, 4); blit(screenWidth / 2 + 10 * getNumSlots() - 20 + 4, ySlot + 6, 242, 252, 14, 4, 14, 4);
#endif
minecraft->textures->loadAndBindTexture("gui/gui_blocks.png"); minecraft->textures->loadAndBindTexture("gui/gui_blocks.png");
t.endOverrideAndDraw(); t.endOverrideAndDraw();
@@ -779,7 +1109,7 @@ void Gui::renderToolBar( float a, int ySlot, const int screenWidth ) {
glDisable2(GL_TEXTURE_2D); glDisable2(GL_TEXTURE_2D);
t.beginOverride(); t.beginOverride();
x = baseItemX; x = baseItemX;
for (int i = 0; i < getNumSlots()-1; i++) { for (int i = 0; i < slots; i++) {
ItemRenderer::renderGuiItemDecorations(minecraft->player->inventory->getItem(i), x, (float)ySlot); ItemRenderer::renderGuiItemDecorations(minecraft->player->inventory->getItem(i), x, (float)ySlot);
x += 20; x += 20;
} }
@@ -799,7 +1129,7 @@ void Gui::renderToolBar( float a, int ySlot, const int screenWidth ) {
t.beginOverride(); t.beginOverride();
if (minecraft->gameMode->isSurvivalType()) { if (minecraft->gameMode->isSurvivalType()) {
x = baseItemX; x = baseItemX;
for (int i = 0; i < getNumSlots()-1; i++) { for (int i = 0; i < slots; i++) {
ItemInstance* item = minecraft->player->inventory->getItem(i); ItemInstance* item = minecraft->player->inventory->getItem(i);
if (item && item->count >= 0) if (item && item->count >= 0)
renderSlotText(item, k*x, k*ySlot + 1, true, true); renderSlotText(item, k*x, k*ySlot + 1, true, true);

View File

@@ -39,6 +39,7 @@ public:
void handleClick(int button, int x, int y); void handleClick(int button, int x, int y);
void handleKeyPressed( int key ); void handleKeyPressed( int key );
void scrollChat(int delta);
void tick(); void tick();
void render(float a, bool mouseFree, int xMouse, int yMouse); void render(float a, bool mouseFree, int xMouse, int yMouse);
@@ -47,6 +48,12 @@ public:
void renderChatMessages( const int screenHeight, unsigned int max, bool isChatting, Font* font ); void renderChatMessages( const int screenHeight, unsigned int max, bool isChatting, Font* font );
// draw a string containing simple [color]...[/color] tags; color names are matched
// case-insensitively and default to white. alpha is applied to each segment.
// draw tagged string (ignores simple [color]…[/color] tags)
static void drawColoredString(Font* font, const std::string& text, float x, float y, int alpha);
static float getColoredWidth(Font* font, const std::string& text);
void renderOnSelectItemNameText( const int screenWidth, Font* font, int ySlot ); void renderOnSelectItemNameText( const int screenWidth, Font* font, int ySlot );
void renderSleepAnimation( const int screenWidth, const int screenHeight ); void renderSleepAnimation( const int screenWidth, const int screenHeight );
@@ -54,10 +61,12 @@ public:
void renderBubbles(); void renderBubbles();
void renderHearts(); void renderHearts();
void renderDebugInfo(); void renderDebugInfo();
void renderPlayerList(Font* font, int screenWidth, int screenHeight);
void renderProgressIndicator( const bool isTouchInterface, const int screenWidth, const int screenHeight, float a ); void renderProgressIndicator( const bool isTouchInterface, const int screenWidth, const int screenHeight, float a );
void addMessage(const std::string& string); void addMessage(const std::string& string);
void clearMessages();
void postError(int errCode); void postError(int errCode);
void onGraphicsReset(); void onGraphicsReset();
@@ -90,6 +99,7 @@ private:
int MAX_MESSAGE_WIDTH; int MAX_MESSAGE_WIDTH;
//ItemRenderer itemRenderer; //ItemRenderer itemRenderer;
GuiMessageList guiMessages; GuiMessageList guiMessages;
int chatScrollOffset;
Random random; Random random;
Minecraft* minecraft; Minecraft* minecraft;

View File

@@ -25,6 +25,12 @@ void Screen::render( int xm, int ym, float a )
Button* button = buttons[i]; Button* button = buttons[i];
button->render(minecraft, xm, ym); button->render(minecraft, xm, ym);
} }
// render any text boxes after buttons
for (unsigned int i = 0; i < textBoxes.size(); i++) {
TextBox* textbox = textBoxes[i];
textbox->render(minecraft, xm, ym);
}
} }
void Screen::init( Minecraft* minecraft, int width, int height ) void Screen::init( Minecraft* minecraft, int width, int height )
@@ -72,6 +78,14 @@ void Screen::updateEvents()
void Screen::mouseEvent() void Screen::mouseEvent()
{ {
const MouseAction& e = Mouse::getEvent(); const MouseAction& e = Mouse::getEvent();
// forward wheel events to subclasses
if (e.action == MouseAction::ACTION_WHEEL) {
int xm = e.x * width / minecraft->width;
int ym = e.y * height / minecraft->height - 1;
mouseWheel(e.dx, e.dy, xm, ym);
return;
}
if (!e.isButton()) if (!e.isButton())
return; return;
@@ -98,7 +112,7 @@ void Screen::keyboardEvent()
} }
void Screen::keyboardTextEvent() void Screen::keyboardTextEvent()
{ {
keyboardNewChar(Keyboard::getChar()); charPressed(Keyboard::getChar());
} }
void Screen::renderBackground() void Screen::renderBackground()
{ {
@@ -157,6 +171,12 @@ void Screen::keyPressed( int eventKey )
minecraft->setScreen(NULL); minecraft->setScreen(NULL);
//minecraft->grabMouse(); //minecraft->grabMouse();
} }
// pass key events to any text boxes first
for (auto& textbox : textBoxes) {
textbox->keyPressed(minecraft, eventKey);
}
if (minecraft->useTouchscreen()) if (minecraft->useTouchscreen())
return; return;
@@ -166,11 +186,11 @@ void Screen::keyPressed( int eventKey )
return; return;
Options& o = minecraft->options; Options& o = minecraft->options;
if (eventKey == o.keyMenuNext.key) if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_NEXT))
if (++tabButtonIndex == tabButtonCount) tabButtonIndex = 0; if (++tabButtonIndex == tabButtonCount) tabButtonIndex = 0;
if (eventKey == o.keyMenuPrevious.key) if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_PREV))
if (--tabButtonIndex == -1) tabButtonIndex = tabButtonCount-1; if (--tabButtonIndex == -1) tabButtonIndex = tabButtonCount-1;
if (eventKey == o.keyMenuOk.key) { if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_OK)) {
Button* button = tabButtons[tabButtonIndex]; Button* button = tabButtons[tabButtonIndex];
if (button->active) { if (button->active) {
minecraft->soundEngine->playUI("random.click", 1, 1); minecraft->soundEngine->playUI("random.click", 1, 1);
@@ -181,6 +201,12 @@ void Screen::keyPressed( int eventKey )
updateTabButtonSelection(); updateTabButtonSelection();
} }
void Screen::charPressed(char inputChar) {
for (auto& textbox : textBoxes) {
textbox->charPressed(minecraft, inputChar);
}
}
void Screen::updateTabButtonSelection() void Screen::updateTabButtonSelection()
{ {
if (minecraft->useTouchscreen()) if (minecraft->useTouchscreen())
@@ -210,6 +236,11 @@ void Screen::mouseClicked( int x, int y, int buttonNum )
} }
} }
} }
// let textboxes see the click regardless
for (auto& textbox : textBoxes) {
textbox->mouseClicked(minecraft, x, y, buttonNum);
}
} }
void Screen::mouseReleased( int x, int y, int buttonNum ) void Screen::mouseReleased( int x, int y, int buttonNum )

View File

@@ -57,8 +57,11 @@ protected:
virtual void mouseClicked(int x, int y, int buttonNum); virtual void mouseClicked(int x, int y, int buttonNum);
virtual void mouseReleased(int x, int y, int buttonNum); virtual void mouseReleased(int x, int y, int buttonNum);
// mouse wheel movement (dx/dy are wheel deltas, xm/ym are GUI coords)
virtual void mouseWheel(int dx, int dy, int xm, int ym) {}
virtual void keyPressed(int eventKey); virtual void keyPressed(int eventKey);
virtual void keyboardNewChar(char inputChar) {} virtual void charPressed(char inputChar);
public: public:
int width; int width;
int height; int height;

View File

@@ -9,13 +9,20 @@ class GuiElement : public GuiComponent {
public: public:
GuiElement(bool active=false, bool visible=true, int x = 0, int y = 0, int width=24, int height=24); GuiElement(bool active=false, bool visible=true, int x = 0, int y = 0, int width=24, int height=24);
virtual ~GuiElement() {} virtual ~GuiElement() {}
virtual void tick(Minecraft* minecraft) {}
virtual void tick(Minecraft* minecraft) {}
virtual void render(Minecraft* minecraft, int xm, int ym) { } virtual void render(Minecraft* minecraft, int xm, int ym) { }
virtual void setupPositions() {} virtual void setupPositions() {}
virtual void mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) {} virtual void mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) {}
virtual void mouseReleased(Minecraft* minecraft, int x, int y, int buttonNum) {} virtual void mouseReleased(Minecraft* minecraft, int x, int y, int buttonNum) {}
virtual void keyPressed(Minecraft* minecraft, int key) {}
virtual void charPressed(Minecraft* minecraft, char key) {}
virtual bool pointInside(int x, int y); virtual bool pointInside(int x, int y);
void setVisible(bool visible); void setVisible(bool visible);
bool active; bool active;
bool visible; bool visible;
int x; int x;

View File

@@ -52,3 +52,15 @@ void GuiElementContainer::mouseReleased( Minecraft* minecraft, int x, int y, int
(*it)->mouseReleased(minecraft, x, y, buttonNum); (*it)->mouseReleased(minecraft, x, y, buttonNum);
} }
} }
void GuiElementContainer::keyPressed(Minecraft* minecraft, int key) {
for(std::vector<GuiElement*>::iterator it = children.begin(); it != children.end(); ++it) {
(*it)->keyPressed(minecraft, key);
}
}
void GuiElementContainer::charPressed(Minecraft* minecraft, char key) {
for(std::vector<GuiElement*>::iterator it = children.begin(); it != children.end(); ++it) {
(*it)->charPressed(minecraft, key);
}
}

View File

@@ -17,8 +17,9 @@ public:
virtual void tick( Minecraft* minecraft ); virtual void tick( Minecraft* minecraft );
virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ); virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum );
virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ); virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum );
virtual void keyPressed(Minecraft* minecraft, int key);
virtual void charPressed(Minecraft* minecraft, char key);
protected: protected:
std::vector<GuiElement*> children; std::vector<GuiElement*> children;

View File

@@ -4,6 +4,7 @@
#include "../../../platform/log.h" #include "../../../platform/log.h"
#include "../../../util/Mth.h" #include "../../../util/Mth.h"
#include "../../renderer/Textures.h" #include "../../renderer/Textures.h"
#include <client/Option.h>
ImageButton::ImageButton(int id, const std::string& msg) ImageButton::ImageButton(int id, const std::string& msg)
@@ -112,43 +113,17 @@ void ImageButton::render(Minecraft* minecraft, int xm, int ym) {
// //
// A toggleable Button // A toggleable Button
// //
OptionButton::OptionButton(const Options::Option* option) OptionButton::OptionButton(OptionId option) : m_optId(option), super(ButtonId, "") {}
: _option(option),
_isFloat(false),
super(ButtonId, "")
{
}
OptionButton::OptionButton(const Options::Option* option, float onValue, float offValue)
: _option(option),
_isFloat(true),
_onValue(onValue),
_offValue(offValue),
super(ButtonId, "")
{
}
bool OptionButton::isSecondImage(bool hovered) {
return _secondImage;
}
void OptionButton::toggle(Options* options) { void OptionButton::toggle(Options* options) {
if (_isFloat) { options->toggle(m_optId);
options->set(_option, (Mth::abs(_current - _onValue) < 0.01f) ? _offValue : _onValue);
} else {
options->toggle(_option, 1);
}
// Update graphics here // Update graphics here
updateImage(options); updateImage(options);
} }
void OptionButton::updateImage(Options* options) { void OptionButton::updateImage(Options* options) {
if (_isFloat) { _secondImage = options->getBooleanValue(m_optId);
_current = options->getProgressValue(_option);
_secondImage = Mth::abs(_current - _onValue) < 0.01f;
} else {
_secondImage = options->getBooleanValue(_option);
}
} }
void OptionButton::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { void OptionButton::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) {

View File

@@ -77,28 +77,20 @@ class OptionButton: public ImageButton
{ {
typedef ImageButton super; typedef ImageButton super;
public: public:
OptionButton(const Options::Option* option); OptionButton(OptionId optId);
OptionButton(const Options::Option* option, float onValue, float offValue);
void toggle(Options* options); void toggle(Options* options);
void updateImage(Options* options); void updateImage(Options* options);
static const int ButtonId = 9999999; static const int ButtonId = 9999999;
protected: protected:
bool isSecondImage(bool hovered); bool isSecondImage(bool hovered) { return _secondImage; }
virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ); virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum );
private: private:
OptionId m_optId;
const Options::Option* _option;
bool _secondImage; bool _secondImage;
// If not float, it's considered to be a boolean value
bool _isFloat;
float _onValue;
float _offValue;
float _current;
}; };

View File

@@ -0,0 +1,22 @@
#include "KeyOption.h"
#include <client/Minecraft.h>
KeyOption::KeyOption(Minecraft* minecraft, OptionId optId)
: Touch::TButton((int)optId, Keyboard::getKeyName(minecraft->options.getIntValue(optId))) {}
void KeyOption::mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) {
selected = isInside(x, y);
msg = (selected)? "..." : Keyboard::getKeyName(minecraft->options.getIntValue((OptionId)id));
}
void KeyOption::keyPressed(Minecraft* minecraft, int key) {
if (!selected) return;
if (key != Keyboard::KEY_ESCAPE) {
minecraft->options.set((OptionId)id, key);
}
selected = false;
msg = Keyboard::getKeyName(minecraft->options.getIntValue((OptionId)id));
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "Button.h"
#include <client/Options.h>
class KeyOption : public Touch::TButton {
public:
KeyOption(Minecraft* minecraft, OptionId optId);
virtual void mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum);
virtual void released(int mx, int my) {}
virtual void keyPressed(Minecraft* minecraft, int key);
protected:
bool m_captureMode;
};

View File

@@ -4,13 +4,16 @@
#include "OptionsItem.h" #include "OptionsItem.h"
#include "Slider.h" #include "Slider.h"
#include "../../../locale/I18n.h" #include "../../../locale/I18n.h"
#include "TextOption.h"
#include "KeyOption.h"
OptionsGroup::OptionsGroup( std::string labelID ) { OptionsGroup::OptionsGroup( std::string labelID ) {
label = I18n::get(labelID); label = I18n::get(labelID);
} }
void OptionsGroup::setupPositions() { void OptionsGroup::setupPositions() {
// First we write the header and then we add the items // First we write the header and then we add the items
int curY = y + 10; int curY = y + 18;
for(std::vector<GuiElement*>::iterator it = children.begin(); it != children.end(); ++it) { for(std::vector<GuiElement*>::iterator it = children.begin(); it != children.end(); ++it) {
(*it)->width = width - 5; (*it)->width = width - 5;
@@ -23,46 +26,90 @@ void OptionsGroup::setupPositions() {
} }
void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) { void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) {
minecraft->font->draw(label, (float)x + 2, (float)y, 0xffffffff, false); float padX = 10.0f;
float padY = 5.0f;
minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false);
super::render(minecraft, xm, ym); super::render(minecraft, xm, ym);
} }
OptionsGroup& OptionsGroup::addOptionItem( const Options::Option* option, Minecraft* minecraft ) { OptionsGroup& OptionsGroup::addOptionItem(OptionId optId, Minecraft* minecraft ) {
if(option->isBoolean()) auto option = minecraft->options.getOpt(optId);
createToggle(option, minecraft);
else if(option->isProgress()) if (option == nullptr) return *this;
createProgressSlider(option, minecraft);
else if(option->isInt()) // TODO: do a options key class to check it faster via dynamic_cast
createStepSlider(option, minecraft); if (option->getStringId().find("options.key") != std::string::npos) createKey(optId, minecraft);
else if (dynamic_cast<OptionBool*>(option)) createToggle(optId, minecraft);
else if (dynamic_cast<OptionFloat*>(option)) createProgressSlider(optId, minecraft);
else if (dynamic_cast<OptionInt*>(option)) createStepSlider(optId, minecraft);
else if (dynamic_cast<OptionString*>(option)) createTextbox(optId, minecraft);
return *this; return *this;
} }
void OptionsGroup::createToggle( const Options::Option* option, Minecraft* minecraft ) { // TODO: wrap this copypaste shit into templates
void OptionsGroup::createToggle(OptionId optId, Minecraft* minecraft ) {
ImageDef def; ImageDef def;
def.setSrc(IntRectangle(160, 206, 39, 20)); def.setSrc(IntRectangle(160, 206, 39, 20));
def.name = "gui/touchgui.png"; def.name = "gui/touchgui.png";
def.width = 39 * 0.7f; def.width = 39 * 0.7f;
def.height = 20 * 0.7f; def.height = 20 * 0.7f;
OptionButton* element = new OptionButton(option);
OptionButton* element = new OptionButton(optId);
element->setImageDef(def, true); element->setImageDef(def, true);
std::string itemLabel = I18n::get(option->getCaptionId()); element->updateImage(&minecraft->options);
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item);
setupPositions();
}
void OptionsGroup::createProgressSlider(OptionId optId, Minecraft* minecraft ) {
Slider* element = new SliderFloat(minecraft, optId);
element->width = 100;
element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }
void OptionsGroup::createProgressSlider( const Options::Option* option, Minecraft* minecraft ) { void OptionsGroup::createStepSlider(OptionId optId, Minecraft* minecraft ) {
Slider* element = new Slider(minecraft, Slider* element = new SliderInt(minecraft, optId);
option,
minecraft->options.getProgrssMin(option),
minecraft->options.getProgrssMax(option));
element->width = 100; element->width = 100;
element->height = 20; element->height = 20;
OptionsItem* item = new OptionsItem(label, element); std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }
void OptionsGroup::createStepSlider( const Options::Option* option, Minecraft* minecraft ) { void OptionsGroup::createTextbox(OptionId optId, Minecraft* minecraft) {
TextBox* element = new TextOption(minecraft, optId);
element->width = 100;
element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item);
setupPositions();
} }
void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) {
KeyOption* element = new KeyOption(minecraft, optId);
element->width = 50;
element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item);
setupPositions();
}

View File

@@ -5,6 +5,7 @@
#include <string> #include <string>
#include "GuiElementContainer.h" #include "GuiElementContainer.h"
#include "ScrollingPane.h"
#include "../../Options.h" #include "../../Options.h"
class Font; class Font;
@@ -16,11 +17,15 @@ public:
OptionsGroup(std::string labelID); OptionsGroup(std::string labelID);
virtual void setupPositions(); virtual void setupPositions();
virtual void render(Minecraft* minecraft, int xm, int ym); virtual void render(Minecraft* minecraft, int xm, int ym);
virtual OptionsGroup& addOptionItem(const Options::Option* option, Minecraft* minecraft); OptionsGroup& addOptionItem(OptionId optId, Minecraft* minecraft);
protected: protected:
virtual void createToggle(const Options::Option* option, Minecraft* minecraft);
virtual void createProgressSlider(const Options::Option* option, Minecraft* minecraft); void createToggle(OptionId optId, Minecraft* minecraft);
virtual void createStepSlider(const Options::Option* option, Minecraft* minecraft); void createProgressSlider(OptionId optId, Minecraft* minecraft);
void createStepSlider(OptionId optId, Minecraft* minecraft);
void createTextbox(OptionId optId, Minecraft* minecraft);
void createKey(OptionId optId, Minecraft* minecraft);
std::string label; std::string label;
}; };

View File

@@ -1,64 +0,0 @@
#include "OptionsPane.h"
#include "OptionsGroup.h"
#include "OptionsItem.h"
#include "ImageButton.h"
#include "Slider.h"
#include "../../Minecraft.h"
OptionsPane::OptionsPane() {
}
void OptionsPane::setupPositions() {
int currentHeight = y + 1;
for(std::vector<GuiElement*>::iterator it = children.begin(); it != children.end(); ++it ) {
(*it)->width = width;
(*it)->y = currentHeight;
(*it)->x = x;
currentHeight += (*it)->height + 1;
}
height = currentHeight;
super::setupPositions();
}
OptionsGroup& OptionsPane::createOptionsGroup( std::string label ) {
OptionsGroup* newGroup = new OptionsGroup(label);
children.push_back(newGroup);
// create and return a new group index
return *newGroup;
}
void OptionsPane::createToggle( unsigned int group, std::string label, const Options::Option* option ) {
// if(group > children.size()) return;
// ImageDef def;
// def.setSrc(IntRectangle(160, 206, 39, 20));
// def.name = "gui/touchgui.png";
// def.width = 39 * 0.7f;
// def.height = 20 * 0.7f;
// OptionButton* element = new OptionButton(option);
// element->setImageDef(def, true);
// OptionsItem* item = new OptionsItem(label, element);
// ((OptionsGroup*)children[group])->addChild(item);
// setupPositions();
}
void OptionsPane::createProgressSlider( Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, float progressMin/*=1.0f*/, float progressMax/*=1.0f */ ) {
// if(group > children.size()) return;
// Slider* element = new Slider(minecraft, option, progressMin, progressMax);
// element->width = 100;
// element->height = 20;
// OptionsItem* item = new OptionsItem(label, element);
// ((OptionsGroup*)children[group])->addChild(item);
// setupPositions();
}
void OptionsPane::createStepSlider( Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, const std::vector<int>& stepVec ) {
// if(group > children.size()) return;
// Slider* element = new Slider(minecraft, option, stepVec);
// element->width = 100;
// element->height = 20;
// sliders.push_back(element);
// OptionsItem* item = new OptionsItem(label, element);
// ((OptionsGroup*)children[group])->addChild(item);
// setupPositions();
}

View File

@@ -1,30 +0,0 @@
#ifndef ITEMPANE_H__
#define ITEMPANE_H__
#include <string>
#include <vector>
#include "GuiElementContainer.h"
#include "../../../world/item/ItemInstance.h"
#include "../../../client/Options.h"
class Font;
class Textures;
class NinePatchLayer;
class ItemPane;
class OptionButton;
class Button;
class OptionsGroup;
class Slider;
class Minecraft;
class OptionsPane: public GuiElementContainer
{
typedef GuiElementContainer super;
public:
OptionsPane();
OptionsGroup& createOptionsGroup( std::string label );
void createToggle( unsigned int group, std::string label, const Options::Option* option );
void createProgressSlider(Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, float progressMin=1.0f, float progressMax=1.0f );
void createStepSlider(Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, const std::vector<int>& stepVec );
void setupPositions();
};
#endif /*ITEMPANE_H__*/

View File

@@ -548,6 +548,14 @@ void ScrollingPane::stepThroughDecelerationAnimation(bool noAnimation) {
} }
} }
void ScrollingPane::scrollBy(float dx, float dy) {
// adjust the translation offsets fpx/fpy by the requested amount
float nfpx = fpx + dx;
float nfpy = fpy + dy;
// convert back to content offset (fpx = -contentOffset.x)
setContentOffset(Vec3(-nfpx, -nfpy, 0));
}
void ScrollingPane::setContentOffset(float x, float y) { void ScrollingPane::setContentOffset(float x, float y) {
this->setContentOffsetWithAnimation(Vec3(x, y, 0), false); this->setContentOffsetWithAnimation(Vec3(x, y, 0), false);
} }

View File

@@ -51,6 +51,10 @@ public:
void tick(); void tick();
void render(int xm, int ym, float alpha); void render(int xm, int ym, float alpha);
// scroll the content by the given amount (dx horizontal, dy vertical)
// positive values move content downward/rightward
void scrollBy(float dx, float dy);
bool getGridItemFor_slow(int itemIndex, GridItem& out); bool getGridItemFor_slow(int itemIndex, GridItem& out);
void setSelected(int id, bool selected); void setSelected(int id, bool selected);

View File

@@ -5,35 +5,8 @@
#include "../../../util/Mth.h" #include "../../../util/Mth.h"
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
Slider::Slider(Minecraft* minecraft, const Options::Option* option, float progressMin, float progressMax)
: sliderType(SliderProgress), mouseDownOnElement(false), option(option), numSteps(0), progressMin(progressMin), progressMax(progressMax) {
if(option != NULL) {
percentage = (minecraft->options.getProgressValue(option) - progressMin) / (progressMax - progressMin);
}
}
Slider::Slider(Minecraft* minecraft, const Options::Option* option, const std::vector<int>& stepVec ) Slider::Slider(OptionId optId) : m_mouseDownOnElement(false), m_optId(optId), m_numSteps(0) {}
: sliderType(SliderStep),
curStepValue(0),
curStep(0),
sliderSteps(stepVec),
mouseDownOnElement(false),
option(option),
percentage(0),
progressMin(0.0f),
progressMax(1.0) {
assert(stepVec.size() > 1);
numSteps = sliderSteps.size();
if(option != NULL) {
curStepValue;
int curStep;
curStepValue = minecraft->options.getIntValue(option);
std::vector<int>::iterator currentItem = std::find(sliderSteps.begin(), sliderSteps.end(), curStepValue);
if(currentItem != sliderSteps.end()) {
curStep = currentItem - sliderSteps.begin();
}
}
}
void Slider::render( Minecraft* minecraft, int xm, int ym ) { void Slider::render( Minecraft* minecraft, int xm, int ym ) {
int xSliderStart = x + 5; int xSliderStart = x + 5;
@@ -45,56 +18,71 @@ void Slider::render( Minecraft* minecraft, int xm, int ym ) {
int barWidth = xSliderEnd - xSliderStart; int barWidth = xSliderEnd - xSliderStart;
//fill(x, y + 8, x + (int)(width * percentage), y + height, 0xffff00ff); //fill(x, y + 8, x + (int)(width * percentage), y + height, 0xffff00ff);
fill(xSliderStart, ySliderStart, xSliderEnd, ySliderEnd, 0xff606060); fill(xSliderStart, ySliderStart, xSliderEnd, ySliderEnd, 0xff606060);
if(sliderType == SliderStep) {
int stepDistance = barWidth / (numSteps -1); if (m_numSteps > 2) {
for(int a = 0; a <= numSteps - 1; ++a) { int stepDistance = barWidth / (m_numSteps-1);
for(int a = 0; a <= m_numSteps; ++a) {
int renderSliderStepPosX = xSliderStart + a * stepDistance + 1; int renderSliderStepPosX = xSliderStart + a * stepDistance + 1;
fill(renderSliderStepPosX - 1, ySliderStart - 2, renderSliderStepPosX + 1, ySliderEnd + 2, 0xff606060); fill(renderSliderStepPosX - 1, ySliderStart - 2, renderSliderStepPosX + 1, ySliderEnd + 2, 0xff606060);
} }
} }
minecraft->textures->loadAndBindTexture("gui/touchgui.png"); minecraft->textures->loadAndBindTexture("gui/touchgui.png");
blit(xSliderStart + (int)(percentage * barWidth) - handleSizeX / 2, y, 226, 126, handleSizeX, handleSizeY, handleSizeX, handleSizeY); blit(xSliderStart + (int)(m_percentage * barWidth) - handleSizeX / 2, y, 226, 126, handleSizeX, handleSizeY, handleSizeX, handleSizeY);
} }
void Slider::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { void Slider::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) {
if(pointInside(x, y)) { if(pointInside(x, y)) {
mouseDownOnElement = true; m_mouseDownOnElement = true;
} }
} }
void Slider::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { void Slider::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) {
mouseDownOnElement = false; m_mouseDownOnElement = false;
if(sliderType == SliderStep) { }
curStep = Mth::floor((percentage * (numSteps-1) + 0.5f));
curStepValue = sliderSteps[Mth::Min(curStep, numSteps-1)];
percentage = float(curStep) / (numSteps - 1);
setOption(minecraft);
}
}
void Slider::tick(Minecraft* minecraft) { void Slider::tick(Minecraft* minecraft) {
if(minecraft->screen != NULL) { if(minecraft->screen != NULL) {
int xm = Mouse::getX(); int xm = Mouse::getX();
int ym = Mouse::getY(); int ym = Mouse::getY();
minecraft->screen->toGUICoordinate(xm, ym); minecraft->screen->toGUICoordinate(xm, ym);
if(mouseDownOnElement) {
percentage = float(xm - x) / float(width); if(m_mouseDownOnElement) {
percentage = Mth::clamp(percentage, 0.0f, 1.0f); m_percentage = float(xm - x) / float(width);
setOption(minecraft); m_percentage = Mth::clamp(m_percentage, 0.0f, 1.0f);
} }
} }
} }
void Slider::setOption( Minecraft* minecraft ) { SliderFloat::SliderFloat(Minecraft* minecraft, OptionId option)
if(option != NULL) { : Slider(option), m_option(dynamic_cast<OptionFloat*>(minecraft->options.getOpt(option)))
if(sliderType == SliderStep) { {
if(minecraft->options.getIntValue(option) != curStepValue) { m_percentage = Mth::clamp((m_option->get() - m_option->getMin()) / (m_option->getMax() - m_option->getMin()), 0.f, 1.f);
minecraft->options.set(option, curStepValue); }
}
} else { SliderInt::SliderInt(Minecraft* minecraft, OptionId option)
if(minecraft->options.getProgressValue(option) != percentage * (progressMax - progressMin) + progressMin) { : Slider(option), m_option(dynamic_cast<OptionInt*>(minecraft->options.getOpt(option)))
minecraft->options.set(option, percentage * (progressMax - progressMin) + progressMin); {
} m_numSteps = m_option->getMax() - m_option->getMin();
} m_percentage = float(m_option->get() - m_option->getMin()) / (m_numSteps-1);
}
void SliderInt::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) {
Slider::mouseReleased(minecraft, x, y, buttonNum);
if (pointInside(x, y)) {
int curStep = Mth::floor(m_percentage * (m_numSteps-1));
m_percentage = float(curStep - m_option->getMin()) / (m_numSteps-1);
minecraft->options.set(m_optId, curStep);
} }
} }
void SliderFloat::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) {
Slider::mouseReleased(minecraft, x, y, buttonNum);
if (pointInside(x, y)) {
minecraft->options.set(m_optId, m_percentage * (m_option->getMax() - m_option->getMin()) + m_option->getMin());
}
}

View File

@@ -3,38 +3,45 @@
#include "GuiElement.h" #include "GuiElement.h"
#include "../../../client/Options.h" #include "../../../client/Options.h"
enum SliderType { #include <client/Option.h>
SliderProgress, // Sets slider between {0..1}
SliderStep // Uses the closest step
};
class Slider : public GuiElement { class Slider : public GuiElement {
typedef GuiElement super; typedef GuiElement super;
public: public:
// Creates a progress slider with no steps
Slider(Minecraft* minecraft, const Options::Option* option, float progressMin, float progressMax);
Slider(Minecraft* minecraft, const Options::Option* option, const std::vector<int>& stepVec);
virtual void render( Minecraft* minecraft, int xm, int ym ); virtual void render( Minecraft* minecraft, int xm, int ym );
virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ); virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum );
virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ); virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum );
virtual void tick(Minecraft* minecraft); virtual void tick(Minecraft* minecraft);
private:
virtual void setOption(Minecraft* minecraft);
private: protected:
SliderType sliderType; Slider(OptionId optId);
std::vector<int> sliderSteps;
bool mouseDownOnElement; OptionId m_optId;
float percentage;
int curStepValue; bool m_mouseDownOnElement;
int curStep; float m_percentage;
int numSteps; int m_numSteps;
float progressMin; };
float progressMax;
const Options::Option* option; class SliderFloat : public Slider {
public:
SliderFloat(Minecraft* minecraft, OptionId option);
virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) override;
protected:
OptionFloat* m_option;
};
class SliderInt : public Slider {
public:
SliderInt(Minecraft* minecraft, OptionId option);
virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) override;
protected:
OptionInt* m_option;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__Slider_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__Slider_H__*/

View File

@@ -1,24 +0,0 @@
#include "SmallButton.h"
SmallButton::SmallButton( int id, int x, int y, const std::string& msg )
: super(id, x, y, 150, 20, msg),
option(NULL)
{
}
SmallButton::SmallButton( int id, int x, int y, int width, int height, const std::string& msg )
: super(id, x, y, width, height, msg),
option(NULL)
{
}
SmallButton::SmallButton( int id, int x, int y, Options::Option* item, const std::string& msg )
: super(id, x, y, 150, 20, msg),
option(item)
{
}
Options::Option* SmallButton::getOption()
{
return option;
}

View File

@@ -1,23 +0,0 @@
#ifndef NET_MINECRAFT_CLIENT_GUI_COMPONENTS__SmallButton_H__
#define NET_MINECRAFT_CLIENT_GUI_COMPONENTS__SmallButton_H__
//package net.minecraft.client.gui;
#include <string>
#include "Button.h"
#include "../../Options.h"
class SmallButton: public Button
{
typedef Button super;
public:
SmallButton(int id, int x, int y, const std::string& msg);
SmallButton(int id, int x, int y, int width, int height, const std::string& msg);
SmallButton(int id, int x, int y, Options::Option* item, const std::string& msg);
Options::Option* getOption();
private:
Options::Option* option;
};
#endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__SmallButton_H__*/

View File

@@ -1,37 +1,102 @@
#include "TextBox.h" #include "TextBox.h"
#include "../Gui.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../../AppPlatform.h" #include "../../../AppPlatform.h"
TextBox::TextBox( int id, const std::string& msg ) #include "../../../platform/input/Mouse.h"
: id(0), w(0), h(0), x(0), y(0), text(msg), focused(false) {
// delegate constructors
TextBox::TextBox(int id, const std::string& msg)
: TextBox(id, 0, 0, msg)
{
} }
TextBox::TextBox( int id, int x, int y, const std::string& msg ) TextBox::TextBox(int id, int x, int y, const std::string& msg)
: id(id), w(0), h(0), x(x), y(y), text(msg), focused(false) { : TextBox(id, x, y, 24, Font::DefaultLineHeight + 4, msg)
{
} }
TextBox::TextBox( int id, int x, int y, int w, int h, const std::string& msg ) TextBox::TextBox(int id, int x, int y, int w, int h, const std::string& msg)
: id(id), w(w), h(h), x(x), y(y), text(msg) { : GuiElement(true, true, x, y, w, h),
id(id), hint(msg), focused(false), blink(false), blinkTicks(0)
{
} }
void TextBox::setFocus(Minecraft* minecraft) { void TextBox::setFocus(Minecraft* minecraft) {
if(!focused) { if (!focused) {
minecraft->platform()->showKeyboard(); minecraft->platform()->showKeyboard();
focused = true; focused = true;
} blinkTicks = 0;
blink = false;
}
} }
bool TextBox::loseFocus(Minecraft* minecraft) { bool TextBox::loseFocus(Minecraft* minecraft) {
if(focused) { if (focused) {
minecraft->platform()->showKeyboard(); minecraft->platform()->hideKeyboard();
focused = false; focused = false;
return true; return true;
} }
return false; return false;
} }
void TextBox::render( Minecraft* minecraft, int xm, int ym ) { void TextBox::mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) {
if (buttonNum == MouseAction::ACTION_LEFT) {
if (pointInside(x, y)) {
setFocus(minecraft);
} else {
loseFocus(minecraft);
}
}
}
void TextBox::charPressed(Minecraft* minecraft, char c) {
if (focused && c >= 32 && c < 127 && (int)text.size() < 256) {
text.push_back(c);
}
}
void TextBox::keyPressed(Minecraft* minecraft, int key) {
if (focused && key == Keyboard::KEY_BACKSPACE && !text.empty()) {
text.pop_back();
}
}
void TextBox::tick(Minecraft* minecraft) {
blinkTicks++;
if (blinkTicks >= 5) {
blink = !blink;
blinkTicks = 0;
}
}
void TextBox::render(Minecraft* minecraft, int xm, int ym) {
// textbox like in beta 1.7.3
// change appearance when focused so the user can tell it's active
// active background darker gray with a subtle border
uint32_t bgColor = focused ? 0xffa0a0a0 : 0xffa0a0a0;
uint32_t borderColor = focused ? 0xff000000 : 0xff000000;
fill(x, y, x + width, y + height, bgColor);
fill(x + 1, y + 1, x + width - 1, y + height - 1, borderColor);
glEnable2(GL_SCISSOR_TEST);
glScissor(
Gui::GuiScale * (x + 2),
minecraft->height - Gui::GuiScale * (y + height - 2),
Gui::GuiScale * (width - 2),
Gui::GuiScale * (height - 2)
);
int _y = y + (height - Font::DefaultLineHeight) / 2;
if (text.empty() && !focused) {
drawString(minecraft->font, hint, x + 2, _y, 0xff5e5e5e);
}
if (focused && blink) text.push_back('_');
drawString(minecraft->font, text, x + 2, _y, 0xffffffff);
if (focused && blink) text.pop_back();
glDisable2(GL_SCISSOR_TEST);
} }

View File

@@ -4,31 +4,41 @@
//package net.minecraft.client.gui; //package net.minecraft.client.gui;
#include <string> #include <string>
#include "../GuiComponent.h" #include "GuiElement.h"
#include "../../Options.h" #include "../../Options.h"
#include "../../../platform/input/Mouse.h"
#include "../../../platform/input/Keyboard.h"
class Font; class Font;
class Minecraft; class Minecraft;
class TextBox: public GuiComponent class TextBox: public GuiElement
{ {
public: public:
TextBox(int id, const std::string& msg); TextBox(int id, const std::string& msg);
TextBox(int id, int x, int y, const std::string& msg); TextBox(int id, int x, int y, const std::string& msg);
TextBox(int id, int x, int y, int w, int h, const std::string& msg); TextBox(int id, int x, int y, int w, int h, const std::string& msg);
virtual void mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum);
virtual void setFocus(Minecraft* minecraft); virtual void setFocus(Minecraft* minecraft);
virtual bool loseFocus(Minecraft* minecraft); virtual bool loseFocus(Minecraft* minecraft);
virtual void render(Minecraft* minecraft, int xm, int ym); virtual void render(Minecraft* minecraft, int xm, int ym);
virtual void keyPressed(Minecraft* minecraft, int key);
virtual void charPressed(Minecraft* minecraft, char c);
virtual void tick(Minecraft* minecraft);
public: public:
int w, h; std::string hint;
int x, y;
std::string text; std::string text;
int id; int id;
int blinkTicks;
bool focused; bool focused;
bool blink;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__TextBox_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__TextBox_H__*/

View File

@@ -0,0 +1,17 @@
#include "TextOption.h"
#include <client/Minecraft.h>
TextOption::TextOption(Minecraft* minecraft, OptionId optId)
: TextBox((int)optId, minecraft->options.getOpt(optId)->getStringId())
{
text = minecraft->options.getStringValue(optId);
}
bool TextOption::loseFocus(Minecraft* minecraft) {
if (TextBox::loseFocus(minecraft)) {
minecraft->options.set((OptionId)id, text);
return true;
}
return false;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "TextBox.h"
#include <client/Options.h>
class TextOption : public TextBox {
public:
TextOption(Minecraft* minecraft, OptionId optId);
virtual bool loseFocus(Minecraft* minecraft);
};

View File

@@ -1,26 +0,0 @@
#ifndef NET_MINECRAFT_CLIENT_GUI_SCREENS__BuyGameScreen_H__
#define NET_MINECRAFT_CLIENT_GUI_SCREENS__BuyGameScreen_H__
#include "../Screen.h"
#include "../components/Button.h"
class BuyGameScreen: public Screen
{
public:
BuyGameScreen() {}
virtual ~BuyGameScreen() {}
void init();
void render(int xm, int ym, float a);
void buttonClicked(Button* button) {
//if (button->id == bQuit.id)
}
private:
//Button bQuit;
//Button bBuyGame;
};
#endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__BuyGameScreen_H__*/

View File

@@ -4,7 +4,6 @@
//package net.minecraft.client.gui; //package net.minecraft.client.gui;
#include "../Screen.h" #include "../Screen.h"
#include "../components/SmallButton.h"
#include <string> #include <string>
class ConfirmScreen: public Screen class ConfirmScreen: public Screen

View File

@@ -0,0 +1,223 @@
#include "ConsoleScreen.h"
#include "../Gui.h"
#include "../../Minecraft.h"
#include "../../player/LocalPlayer.h"
#include "../../../platform/input/Keyboard.h"
#include "../../../world/level/Level.h"
#include "../../../network/RakNetInstance.h"
#include "../../../network/ServerSideNetworkHandler.h"
#include "../../../network/packet/ChatPacket.h"
#include "../../../platform/log.h"
#include <sstream>
#include <cstdlib>
#include <cctype>
ConsoleScreen::ConsoleScreen()
: _input(""),
_cursorBlink(0)
{
}
void ConsoleScreen::init()
{
}
void ConsoleScreen::tick()
{
_cursorBlink++;
}
bool ConsoleScreen::handleBackEvent(bool /*isDown*/)
{
minecraft->setScreen(NULL);
return true;
}
void ConsoleScreen::keyPressed(int eventKey)
{
if (eventKey == Keyboard::KEY_ESCAPE) {
minecraft->setScreen(NULL);
} else if (eventKey == Keyboard::KEY_RETURN) {
execute();
} else if (eventKey == Keyboard::KEY_BACKSPACE) {
if (!_input.empty())
_input.erase(_input.size() - 1, 1);
} else {
super::keyPressed(eventKey);
}
}
void ConsoleScreen::charPressed(char inputChar)
{
if (inputChar >= 32 && inputChar < 127)
_input += inputChar;
}
// ---------------------------------------------------------------------------
// execute: run _input as a command, print result, close screen
// ---------------------------------------------------------------------------
void ConsoleScreen::execute()
{
if (_input.empty()) {
minecraft->setScreen(NULL);
return;
}
if (_input[0] == '/') {
// Command
std::string result = processCommand(_input);
if (!result.empty())
minecraft->gui.addMessage(result);
} else {
// Chat message: <name> message
std::string msg = std::string("<") + minecraft->player->name + "> " + _input;
if (minecraft->netCallback && minecraft->raknetInstance->isServer()) {
// Hosting a LAN game: displayGameMessage shows locally + broadcasts MessagePacket to clients
static_cast<ServerSideNetworkHandler*>(minecraft->netCallback)->displayGameMessage(msg);
} else if (minecraft->netCallback) {
// Connected client: send ChatPacket to server; server echoes it back as MessagePacket
ChatPacket chatPkt(msg);
minecraft->raknetInstance->send(chatPkt);
} else {
// Singleplayer: show locally only
minecraft->gui.addMessage(msg);
}
}
minecraft->setScreen(NULL);
}
// ---------------------------------------------------------------------------
// processCommand
// ---------------------------------------------------------------------------
static std::string trim(const std::string& s) {
size_t a = s.find_first_not_of(" \t");
if (a == std::string::npos) return "";
size_t b = s.find_last_not_of(" \t");
return s.substr(a, b - a + 1);
}
std::string ConsoleScreen::processCommand(const std::string& raw)
{
// strip leading '/'
std::string line = raw;
if (!line.empty() && line[0] == '/') line = line.substr(1);
line = trim(line);
// tokenise
std::vector<std::string> args;
{
std::istringstream ss(line);
std::string tok;
while (ss >> tok) args.push_back(tok);
}
if (args.empty()) return "";
Level* level = minecraft->level;
if (!level) return "No level loaded.";
// -----------------------------------------------------------------------
// /time ...
// -----------------------------------------------------------------------
if (args[0] == "time") {
if (args.size() < 2)
return "Usage: /time <add|set|query> ...";
const std::string& sub = args[1];
// -- time add <value> -----------------------------------------------
if (sub == "add") {
if (args.size() < 3) return "Usage: /time add <value>";
long delta = std::atol(args[2].c_str());
long newTime = level->getTime() + delta;
level->setTime(newTime);
std::ostringstream out;
out << "Set the time to " << (newTime % Level::TICKS_PER_DAY);
return out.str();
}
// -- time set <value|day|night|noon|midnight> -----------------------
if (sub == "set") {
if (args.size() < 3) return "Usage: /time set <value|day|night|noon|midnight>";
const std::string& val = args[2];
long t = -1;
if (val == "day") t = 1000;
else if (val == "noon") t = 6000;
else if (val == "night") t = 13000;
else if (val == "midnight") t = 18000;
else {
// numeric — accept positive integers only
bool numeric = true;
for (char c : val)
if (!std::isdigit((unsigned char)c)) { numeric = false; break; }
if (!numeric) return std::string("Unknown value: ") + val;
t = std::atol(val.c_str());
}
// Preserve the total day count so only the time-of-day changes
long dayCount = level->getTime() / Level::TICKS_PER_DAY;
long newTime = dayCount * Level::TICKS_PER_DAY + (t % Level::TICKS_PER_DAY);
level->setTime(newTime);
std::ostringstream out;
out << "Set the time to " << t;
return out.str();
}
// -- time query <daytime|gametime|day> ------------------------------
if (sub == "query") {
if (args.size() < 3) return "Usage: /time query <daytime|gametime|day>";
const std::string& what = args[2];
long total = level->getTime();
long daytime = total % Level::TICKS_PER_DAY;
long day = total / Level::TICKS_PER_DAY;
std::ostringstream out;
if (what == "daytime") { out << "The time of day is " << daytime; }
else if (what == "gametime") { out << "The game time is " << total; }
else if (what == "day") { out << "The day is " << day; }
else return std::string("Unknown query: ") + what;
return out.str();
}
return "Unknown sub-command. Usage: /time <add|set|query> ...";
}
return std::string("Unknown command: /") + args[0];
}
// ---------------------------------------------------------------------------
// render
// ---------------------------------------------------------------------------
void ConsoleScreen::render(int /*xm*/, int /*ym*/, float /*a*/)
{
// Dim the game world slightly
fillGradient(0, 0, width, height, 0x00000000, 0x40000000);
const int boxH = 12;
const int boxY = height - boxH - 2;
const int boxX0 = 2;
const int boxX1 = width - 2;
// Input box background
fill(boxX0, boxY, boxX1, boxY + boxH, 0xc0000000);
// Border
fill(boxX0, boxY, boxX1, boxY + 1, 0xff808080);
fill(boxX0, boxY + boxH - 1, boxX1, boxY + boxH, 0xff808080);
fill(boxX0, boxY, boxX0 + 1, boxY + boxH, 0xff808080);
fill(boxX1 - 1, boxY, boxX1, boxY + boxH, 0xff808080);
// Input text + blinking cursor
std::string displayed = _input;
if ((_cursorBlink / 10) % 2 == 0)
displayed += '_';
// Placeholder hint when empty
if (_input.empty() && (_cursorBlink / 10) % 2 != 0)
font->drawShadow("Type a message or /command", (float)(boxX0 + 2), (float)(boxY + 2), 0xff606060);
else
font->drawShadow(displayed, (float)(boxX0 + 2), (float)(boxY + 2), 0xffffffff);
}

View File

@@ -0,0 +1,34 @@
#ifndef NET_MINECRAFT_CLIENT_GUI_SCREENS__ConsoleScreen_H__
#define NET_MINECRAFT_CLIENT_GUI_SCREENS__ConsoleScreen_H__
#include "../Screen.h"
#include <string>
class ConsoleScreen: public Screen
{
typedef Screen super;
public:
ConsoleScreen();
virtual ~ConsoleScreen() {}
void init();
void render(int xm, int ym, float a);
void tick();
virtual bool renderGameBehind() { return true; }
virtual bool isInGameScreen() { return true; }
virtual bool isPauseScreen() { return false; }
virtual void keyPressed(int eventKey);
virtual void charPressed(char inputChar);
virtual bool handleBackEvent(bool isDown);
private:
void execute();
std::string processCommand(const std::string& cmd);
std::string _input;
int _cursorBlink; // tick counter for cursor blink
};
#endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__ConsoleScreen_H__*/

View File

@@ -0,0 +1,129 @@
#include "CreditsScreen.h"
#include "StartMenuScreen.h"
#include "OptionsScreen.h"
#include "../../Minecraft.h"
#include "../components/Button.h"
#include "../components/ImageButton.h"
#include "platform/input/Mouse.h"
CreditsScreen::CreditsScreen()
: bHeader(NULL), btnBack(NULL)
{}
CreditsScreen::~CreditsScreen() {
if (bHeader) delete bHeader;
if (btnBack) delete btnBack;
}
void CreditsScreen::init() {
bHeader = new Touch::THeader(0, "Credits");
btnBack = new ImageButton(1, "");
{
ImageDef def;
def.name = "gui/touchgui.png";
def.width = 34;
def.height = 26;
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
btnBack->setImageDef(def, true);
}
buttons.push_back(bHeader);
buttons.push_back(btnBack);
// prepare text lines
_lines.clear();
_lines.push_back("Minecraft: Pocket Edition");
_lines.push_back("Original game by Mojang");
_lines.push_back("");
_lines.push_back("Programmers:");
_lines.push_back("mschiller890");
_lines.push_back("InviseDivine");
_lines.push_back("Kolyah35");
_lines.push_back("karson");
_lines.push_back("deepfriedwaffles");
_lines.push_back("");
// avoid color tags around the URL so it isn't mangled by the parser please
_lines.push_back("Join our Discord server: https://discord.gg/c58YesBxve");
_scrollSpeed = 0.5f;
_scrollY = height; // start below screen
}
void CreditsScreen::setupPositions() {
int buttonHeight = btnBack->height;
btnBack->x = width - btnBack->width;
btnBack->y = 0;
if (bHeader) {
bHeader->x = 0;
bHeader->y = 0;
bHeader->width = width - btnBack->width;
bHeader->height = btnBack->height;
}
// reset scroll starting position when screen size changes
_scrollY = height;
}
void CreditsScreen::tick() {
// move text upward
_scrollY -= _scrollSpeed;
// if text has scrolled off the top, restart
float totalHeight = _lines.size() * (minecraft->font->lineHeight + 8);
if (_scrollY + totalHeight < 0) {
_scrollY = height;
}
if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) {
_scrollSpeed = 1.5f;
} else {
_scrollSpeed = 0.5f;
}
}
void CreditsScreen::render(int xm, int ym, float a) {
renderBackground();
int w = width;
Font* font = minecraft->font;
float y = _scrollY;
const float lineHeight = font->lineHeight + 8;
for (size_t i = 0; i < _lines.size(); ++i) {
const std::string& line = _lines[i];
// use color-tag-aware drawing, centre by total width
float lineWidth = Gui::getColoredWidth(font, line);
Gui::drawColoredString(font, line, w/2 - lineWidth/2, (int)y, 255);
// underline hyperlink lines manually
if (line.find("http") != std::string::npos || line.find("discord.gg") != std::string::npos) {
float x0 = w/2 - lineWidth/2;
float y0 = y + font->lineHeight - 1;
this->fill(x0, y0, x0 + lineWidth, y0 + 1, 0xffffffff);
}
y += lineHeight;
}
super::render(xm, ym, a);
}
void CreditsScreen::buttonClicked(Button* button) {
if (button->id == 1) {
minecraft->setScreen(new OptionsScreen());
}
}
void CreditsScreen::mouseClicked(int x, int y, int buttonNum) {
// map click to a line in the scrolling text
const float lineHeight = minecraft->font->lineHeight + 8;
for (size_t i = 0; i < _lines.size(); ++i) {
float lineY = _scrollY + i * lineHeight;
if (y >= lineY && y < lineY + lineHeight) {
const std::string& line = _lines[i];
size_t start = line.find("http");
if (start == std::string::npos)
start = line.find("discord.gg");
if (start != std::string::npos) {
// extract until space
size_t end = line.find(' ', start);
std::string url = line.substr(start, (end == std::string::npos) ? std::string::npos : end - start);
minecraft->platform()->openURL(url);
return;
}
}
}
super::mouseClicked(x, y, buttonNum);
}

View File

@@ -0,0 +1,32 @@
#ifndef NET_MINECRAFT_CLIENT_GUI_SCREENS__CreditsScreen_H__
#define NET_MINECRAFT_CLIENT_GUI_SCREENS__CreditsScreen_H__
#include "../Screen.h"
#include "../components/Button.h"
class ImageButton;
#include <vector>
#include <string>
class CreditsScreen: public Screen {
public:
typedef Screen super;
CreditsScreen();
virtual ~CreditsScreen();
void init();
void setupPositions();
virtual void tick();
void render(int xm, int ym, float a);
void buttonClicked(Button* button);
virtual void mouseClicked(int x, int y, int buttonNum);
private:
Touch::THeader* bHeader;
ImageButton* btnBack;
std::vector<std::string> _lines;
float _scrollY;
float _scrollSpeed;
};
#endif /* NET_MINECRAFT_CLIENT_GUI_SCREENS__CreditsScreen_H__ */

View File

@@ -169,19 +169,19 @@ void IngameBlockSelectionScreen::keyPressed(int eventKey)
int tmpSelectedSlot = selectedItem; int tmpSelectedSlot = selectedItem;
Options& o = minecraft->options; Options& o = minecraft->options;
if (eventKey == o.keyLeft.key && selX > 0) if (eventKey == o.getIntValue(OPTIONS_KEY_LEFT) && selX > 0)
{ {
tmpSelectedSlot -= 1; tmpSelectedSlot -= 1;
} }
else if (eventKey == o.keyRight.key && selX < (InventoryCols - 1)) else if (eventKey == o.getIntValue(OPTIONS_KEY_RIGHT) && selX < (InventoryCols - 1))
{ {
tmpSelectedSlot += 1; tmpSelectedSlot += 1;
} }
else if (eventKey == o.keyDown.key && selY < (InventoryRows - 1)) else if (eventKey == o.getIntValue(OPTIONS_KEY_BACK) && selY < (InventoryRows - 1))
{ {
tmpSelectedSlot += InventoryCols; tmpSelectedSlot += InventoryCols;
} }
else if (eventKey == o.keyUp.key && selY > 0) else if (eventKey == o.getIntValue(OPTIONS_KEY_FORWARD) && selY > 0)
{ {
tmpSelectedSlot -= InventoryCols; tmpSelectedSlot -= InventoryCols;
} }
@@ -189,19 +189,38 @@ void IngameBlockSelectionScreen::keyPressed(int eventKey)
if (isAllowed(tmpSelectedSlot)) if (isAllowed(tmpSelectedSlot))
selectedItem = tmpSelectedSlot; selectedItem = tmpSelectedSlot;
if (eventKey == o.keyMenuOk.key) if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_OK))
selectSlotAndClose(); selectSlotAndClose();
#ifdef RPI #ifdef RPI
if (eventKey == o.keyMenuCancel.key if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_CANCEL)
|| eventKey == Keyboard::KEY_ESCAPE) || eventKey == Keyboard::KEY_ESCAPE)
minecraft->setScreen(NULL); minecraft->setScreen(NULL);
#else #else
if (eventKey == o.keyMenuCancel.key) if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_CANCEL))
minecraft->setScreen(NULL); minecraft->setScreen(NULL);
#endif #endif
} }
//------------------------------------------------------------------------------
// wheel support for creative inventory; scroll moves selection vertically
void IngameBlockSelectionScreen::mouseWheel(int dx, int dy, int xm, int ym)
{
if (dy == 0) return;
// just move selection up/down one row; desktop UI doesn't have a pane
int cols = InventoryCols;
int maxIndex = InventorySize - 1;
int idx = selectedItem;
if (dy > 0) {
// wheel up -> previous row
if (idx >= cols) idx -= cols;
} else {
// wheel down -> next row
if (idx + cols <= maxIndex) idx += cols;
}
selectedItem = idx;
}
int IngameBlockSelectionScreen::getSelectedSlot(int x, int y) int IngameBlockSelectionScreen::getSelectedSlot(int x, int y)
{ {
int left = width / 2 - InventoryCols * 10; int left = width / 2 - InventoryCols * 10;

View File

@@ -12,18 +12,21 @@ public:
IngameBlockSelectionScreen(); IngameBlockSelectionScreen();
virtual ~IngameBlockSelectionScreen() {} virtual ~IngameBlockSelectionScreen() {}
virtual void init(); virtual void init() override;
virtual void removed(); virtual void removed() override;
void render(int xm, int ym, float a); void render(int xm, int ym, float a) override;
protected: protected:
virtual void mouseClicked(int x, int y, int buttonNum); virtual void mouseClicked(int x, int y, int buttonNum) override;
virtual void mouseReleased(int x, int y, int buttonNum); virtual void mouseReleased(int x, int y, int buttonNum) override;
virtual void buttonClicked(Button* button); virtual void buttonClicked(Button* button) override;
virtual void keyPressed(int eventKey); // wheel input for creative inventory scrolling
virtual void mouseWheel(int dx, int dy, int xm, int ym) override;
virtual void keyPressed(int eventKey) override;
private: private:
void renderSlots(); void renderSlots();
void renderSlot(int slot, int x, int y, float a); void renderSlot(int slot, int x, int y, float a);

View File

@@ -1,107 +0,0 @@
#ifndef NET_MINECRAFT_CLIENT_GUI_SCREENS__InvalidLicenseScreen_H__
#define NET_MINECRAFT_CLIENT_GUI_SCREENS__InvalidLicenseScreen_H__
#include "../Screen.h"
#include "../components/Button.h"
#include "../../Minecraft.h"
#include "../../../LicenseCodes.h"
class InvalidLicenseScreen: public Screen
{
public:
InvalidLicenseScreen(int id, bool hasBuyButton)
: _id(id),
_hasBuyButton(hasBuyButton),
_baseY(0),
bOk(0),
bBuy(0)
{
}
virtual ~InvalidLicenseScreen() {
delete bOk;
delete bBuy;
}
void init() {
if (minecraft->useTouchscreen()) {
bOk = new Touch::TButton(1, "Ok");
bBuy = new Touch::TButton(2, "Buy");
} else {
bOk = new Button(1, "Ok");
bBuy = new Button(2, "Buy");
}
if (_hasBuyButton)
bOk->msg = "Quit";
if (!LicenseCodes::isOk(_id)) {
char buf[20] = {0};
sprintf(buf, "%d", _id);
desc1 = "License verification failed (error ";
desc1 += buf;
desc1 += ")";
desc2 = "Try again later.";
hint = "You need to be connected to the internet\n";
hint += "once while you start the game.";
}
buttons.push_back(bOk);
tabButtons.push_back(bOk);
if (_hasBuyButton) {
buttons.push_back(bBuy);
tabButtons.push_back(bBuy);
}
}
void setupPositions() {
_baseY = height/5 + 6;
//if (_hasBuyButton)
_baseY -= 24;
bOk->width = bBuy->width = 200;
bOk->x = bBuy->x = (width - bOk->width) / 2;
bBuy->y = _baseY + 84;
bOk->y = bBuy->y + bBuy->height + 4;
if (!_hasBuyButton)
bOk->y -= 24;
}
void tick() {}
//void keyPressed(int eventKey) {}
void render(int xm, int ym, float a) {
renderDirtBackground(0);
drawCenteredString(minecraft->font, desc1, width/2, _baseY, 0xffffff);
drawCenteredString(minecraft->font, desc2, width/2, _baseY + 24, 0xffffff);
drawCenteredString(minecraft->font, hint, width/2, _baseY + 60, 0xffffff);
Screen::render(xm, ym, a);
}
void buttonClicked(Button* button) {
if (button->id == bOk->id) {
minecraft->quit();
}
if (button->id == bBuy->id) {
minecraft->platform()->buyGame();
}
};
private:
int _id;
std::string desc1;
std::string desc2;
std::string hint;
Button* bOk;
Button* bBuy;
bool _hasBuyButton;
int _baseY;
};
#endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__InvalidLicenseScreen_H__*/

View File

@@ -0,0 +1,124 @@
#include "JoinByIPScreen.h"
#include "JoinGameScreen.h"
#include "StartMenuScreen.h"
#include "ProgressScreen.h"
#include "../Font.h"
#include "../../../network/RakNetInstance.h"
#include "client/Options.h"
#include "client/gui/Screen.h"
#include "client/gui/components/TextBox.h"
#include "network/ClientSideNetworkHandler.h"
JoinByIPScreen::JoinByIPScreen() :
tIP(0, "Server IP"),
bHeader(1, "Join on server"),
bJoin( 2, "Join Game"),
bBack( 3, "")
{
bJoin.active = false;
//gamesList->yInertia = 0.5f;
}
JoinByIPScreen::~JoinByIPScreen()
{
}
void JoinByIPScreen::buttonClicked(Button* button)
{
if (button->id == bJoin.id)
{
minecraft->isLookingForMultiplayer = true;
minecraft->netCallback = new ClientSideNetworkHandler(minecraft, minecraft->raknetInstance);
minecraft->joinMultiplayerFromString(tIP.text);
{
minecraft->options.set(OPTIONS_LAST_IP, tIP.text);
bJoin.active = false;
bBack.active = false;
minecraft->setScreen(new ProgressScreen());
}
}
if (button->id == bBack.id)
{
minecraft->cancelLocateMultiplayer();
minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
}
}
bool JoinByIPScreen::handleBackEvent(bool isDown)
{
if (!isDown)
{
minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
}
return true;
}
void JoinByIPScreen::tick()
{
Screen::tick();
bJoin.active = !tIP.text.empty();
}
void JoinByIPScreen::init()
{
ImageDef def;
def.name = "gui/touchgui.png";
def.width = 34;
def.height = 26;
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
bBack.setImageDef(def, true);
buttons.push_back(&bJoin);
buttons.push_back(&bBack);
buttons.push_back(&bHeader);
textBoxes.push_back(&tIP);
#ifdef ANDROID
tabButtons.push_back(&bJoin);
tabButtons.push_back(&bBack);
tabButtons.push_back(&bHeader);
#endif
tIP.text = minecraft->options.getStringValue(OPTIONS_LAST_IP);
}
void JoinByIPScreen::setupPositions() {
int tIpDiff = 40;
bJoin.y = height * 2 / 3;
bBack.y = 0;
bHeader.y = 0;
// Center buttons
//bJoin.x = width / 2 - 4 - bJoin.w;
bBack.x = width - bBack.width;//width / 2 + 4;
bJoin.x = (width - bJoin.width) / 2;
bHeader.x = 0;
bHeader.width = width - bBack.width;
tIP.width = bJoin.width + tIpDiff;
tIP.height = 16;
tIP.x = bJoin.x - tIpDiff / 2;
tIP.y = ((height - bJoin.height) / 2) - tIP.height - 4;
}
void JoinByIPScreen::render( int xm, int ym, float a )
{
renderBackground();
Screen::render(xm, ym, a);
}
void JoinByIPScreen::keyPressed(int eventKey)
{
if (eventKey == Keyboard::KEY_ESCAPE) {
minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
return;
}
// let base class handle navigation and text box keys
Screen::keyPressed(eventKey);
}

View File

@@ -0,0 +1,28 @@
#include "../Screen.h"
#include "../components/Button.h"
#include "../../Minecraft.h"
#include "client/gui/components/ImageButton.h"
#include "client/gui/components/TextBox.h"
class JoinByIPScreen: public Screen
{
public:
JoinByIPScreen();
virtual ~JoinByIPScreen();
void init();
void setupPositions();
virtual void tick();
void render(int xm, int ym, float a);
virtual void keyPressed(int eventKey);
void buttonClicked(Button* button);
virtual bool handleBackEvent(bool isDown);
private:
TextBox tIP;
Touch::THeader bHeader;
Touch::TButton bJoin;
ImageButton bBack;
};

View File

@@ -3,7 +3,6 @@
#include "../Screen.h" #include "../Screen.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/SmallButton.h"
#include "../components/ScrolledSelectionList.h" #include "../components/ScrolledSelectionList.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../../network/RakNetInstance.h" #include "../../../network/RakNetInstance.h"

View File

@@ -1,46 +1,63 @@
#include "OptionsScreen.h" #include "OptionsScreen.h"
#include "StartMenuScreen.h" #include "StartMenuScreen.h"
#include "UsernameScreen.h"
#include "DialogDefinitions.h" #include "DialogDefinitions.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../../AppPlatform.h" #include "../../../AppPlatform.h"
#include "CreditsScreen.h"
#include "../components/OptionsPane.h"
#include "../components/ImageButton.h" #include "../components/ImageButton.h"
#include "../components/OptionsGroup.h" #include "../components/OptionsGroup.h"
#include "platform/input/Keyboard.h"
OptionsScreen::OptionsScreen() OptionsScreen::OptionsScreen()
: btnClose(NULL), : btnClose(NULL),
bHeader(NULL), bHeader(NULL),
selectedCategory(0) { btnCredits(NULL),
selectedCategory(0) {
} }
OptionsScreen::~OptionsScreen() { OptionsScreen::~OptionsScreen() {
if(btnClose != NULL) {
if (btnClose != NULL) {
delete btnClose; delete btnClose;
btnClose = NULL; btnClose = NULL;
} }
if(bHeader != NULL) {
delete bHeader, if (bHeader != NULL) {
delete bHeader;
bHeader = NULL; bHeader = NULL;
} }
for(std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
if(*it != NULL) { if (btnCredits != NULL) {
delete *it; delete btnCredits;
btnCredits = NULL;
}
for (std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
if (*it != NULL) {
delete* it;
*it = NULL; *it = NULL;
} }
} }
for(std::vector<OptionsPane*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) {
if(*it != NULL) { for (std::vector<OptionsGroup*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) {
delete *it; if (*it != NULL) {
delete* it;
*it = NULL; *it = NULL;
} }
} }
categoryButtons.clear(); categoryButtons.clear();
} }
void OptionsScreen::init() { void OptionsScreen::init() {
bHeader = new Touch::THeader(0, "Options"); bHeader = new Touch::THeader(0, "Options");
btnClose = new ImageButton(1, ""); btnClose = new ImageButton(1, "");
ImageDef def; ImageDef def;
def.name = "gui/touchgui.png"; def.name = "gui/touchgui.png";
def.width = 34; def.width = 34;
@@ -49,133 +66,204 @@ void OptionsScreen::init() {
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
btnClose->setImageDef(def, true); btnClose->setImageDef(def, true);
categoryButtons.push_back(new Touch::TButton(2, "Login")); categoryButtons.push_back(new Touch::TButton(2, "General"));
categoryButtons.push_back(new Touch::TButton(3, "Game")); categoryButtons.push_back(new Touch::TButton(3, "Game"));
categoryButtons.push_back(new Touch::TButton(4, "Controls")); categoryButtons.push_back(new Touch::TButton(4, "Controls"));
categoryButtons.push_back(new Touch::TButton(5, "Graphics")); categoryButtons.push_back(new Touch::TButton(5, "Graphics"));
categoryButtons.push_back(new Touch::TButton(6, "Tweaks"));
btnCredits = new Touch::TButton(11, "Credits");
buttons.push_back(bHeader); buttons.push_back(bHeader);
buttons.push_back(btnClose); buttons.push_back(btnClose);
for(std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { buttons.push_back(btnCredits);
for (std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
buttons.push_back(*it); buttons.push_back(*it);
tabButtons.push_back(*it); tabButtons.push_back(*it);
} }
generateOptionScreens();
generateOptionScreens();
// start with first category selected
selectCategory(0);
} }
void OptionsScreen::setupPositions() { void OptionsScreen::setupPositions() {
int buttonHeight = btnClose->height; int buttonHeight = btnClose->height;
btnClose->x = width - btnClose->width; btnClose->x = width - btnClose->width;
btnClose->y = 0; btnClose->y = 0;
int offsetNum = 1; int offsetNum = 1;
for(std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
for (std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
(*it)->x = 0; (*it)->x = 0;
(*it)->y = offsetNum * buttonHeight; (*it)->y = offsetNum * buttonHeight;
(*it)->selected = false; (*it)->selected = false;
offsetNum++; offsetNum++;
} }
bHeader->x = 0; bHeader->x = 0;
bHeader->y = 0; bHeader->y = 0;
bHeader->width = width - btnClose->width; bHeader->width = width - btnClose->width;
bHeader->height = btnClose->height; bHeader->height = btnClose->height;
for(std::vector<OptionsPane*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) {
if(categoryButtons.size() > 0 && categoryButtons[0] != NULL) { // Credits button (bottom-right)
if (btnCredits != NULL) {
btnCredits->x = width - btnCredits->width;
btnCredits->y = height - btnCredits->height;
}
for (std::vector<OptionsGroup*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) {
if (categoryButtons.size() > 0 && categoryButtons[0] != NULL) {
(*it)->x = categoryButtons[0]->width; (*it)->x = categoryButtons[0]->width;
(*it)->y = bHeader->height; (*it)->y = bHeader->height;
(*it)->width = width - categoryButtons[0]->width; (*it)->width = width - categoryButtons[0]->width;
(*it)->setupPositions(); (*it)->setupPositions();
} }
} }
selectCategory(0);
// don't override user selection on resize
} }
void OptionsScreen::render( int xm, int ym, float a ) {
void OptionsScreen::render(int xm, int ym, float a) {
renderBackground(); renderBackground();
super::render(xm, ym, a);
int xmm = xm * width / minecraft->width; int xmm = xm * width / minecraft->width;
int ymm = ym * height / minecraft->height - 1; int ymm = ym * height / minecraft->height - 1;
if(currentOptionPane != NULL)
currentOptionPane->render(minecraft, xmm, ymm); if (currentOptionsGroup != NULL)
currentOptionsGroup->render(minecraft, xmm, ymm);
super::render(xm, ym, a);
} }
void OptionsScreen::removed() void OptionsScreen::removed() {
{
} }
void OptionsScreen::buttonClicked( Button* button ) {
if(button == btnClose) { void OptionsScreen::buttonClicked(Button* button) {
minecraft->reloadOptions();
if (button == btnClose) {
minecraft->options.save();
minecraft->screenChooser.setScreen(SCREEN_STARTMENU); minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
} else if(button->id > 1 && button->id < 7) { }
// This is a category button else if (button->id > 1 && button->id < 7) {
int categoryButton = button->id - categoryButtons[0]->id; int categoryButton = button->id - categoryButtons[0]->id;
selectCategory(categoryButton); selectCategory(categoryButton);
} }
else if (button == btnCredits) {
minecraft->setScreen(new CreditsScreen());
}
} }
void OptionsScreen::selectCategory( int index ) { void OptionsScreen::selectCategory(int index) {
int currentIndex = 0; int currentIndex = 0;
for(std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
if(index == currentIndex) { for (std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
if (index == currentIndex)
(*it)->selected = true; (*it)->selected = true;
} else { else
(*it)->selected = false; (*it)->selected = false;
}
currentIndex++; currentIndex++;
} }
if(index < (int)optionPanes.size())
currentOptionPane = optionPanes[index]; if (index < (int)optionPanes.size())
currentOptionsGroup = optionPanes[index];
} }
void OptionsScreen::generateOptionScreens() { void OptionsScreen::generateOptionScreens() {
optionPanes.push_back(new OptionsPane()); // how the fuck it works
optionPanes.push_back(new OptionsPane());
optionPanes.push_back(new OptionsPane()); optionPanes.push_back(new OptionsGroup("options.group.general"));
optionPanes.push_back(new OptionsPane()); optionPanes.push_back(new OptionsGroup("options.group.game"));
// Mojang Pane optionPanes.push_back(new OptionsGroup("options.group.controls"));
optionPanes[0]->createOptionsGroup("options.group.mojang") optionPanes.push_back(new OptionsGroup("options.group.graphics"));
//.addOptionItem(&Options::Option::THIRD_PERSON, minecraft); optionPanes.push_back(new OptionsGroup("options.group.tweaks"));
.addOptionItem(&Options::Option::SENSITIVITY, minecraft);
// int mojangGroup = optionPanes[0]->createOptionsGroup("Mojang"); // General Pane
// static const int arr[] = {5,4,3,15}; optionPanes[0]->addOptionItem(OPTIONS_USERNAME, minecraft)
// std::vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) ); .addOptionItem(OPTIONS_SENSITIVITY, minecraft);
// optionPanes[0]->createStepSlider(minecraft, mojangGroup, "This works?", &Options::Option::DIFFICULTY, vec);
// // Game Pane
// // Game Pane optionPanes[1]->addOptionItem(OPTIONS_DIFFICULTY, minecraft)
// int gameGroup = optionPanes[1]->createOptionsGroup("Game"); .addOptionItem(OPTIONS_SERVER_VISIBLE, minecraft)
// optionPanes[1]->createToggle(gameGroup, "Third person camera", &Options::Option::THIRD_PERSON); .addOptionItem(OPTIONS_THIRD_PERSON_VIEW, minecraft)
// optionPanes[1]->createToggle(gameGroup, "Server visible", &Options::Option::SERVER_VISIBLE); .addOptionItem(OPTIONS_GUI_SCALE, minecraft)
// .addOptionItem(OPTIONS_SENSITIVITY, minecraft)
// // Input Pane .addOptionItem(OPTIONS_MUSIC_VOLUME, minecraft)
// int controlsGroup = optionPanes[2]->createOptionsGroup("Controls"); .addOptionItem(OPTIONS_SOUND_VOLUME, minecraft)
// optionPanes[2]->createToggle(controlsGroup, "Invert X-axis", &Options::Option::INVERT_MOUSE); .addOptionItem(OPTIONS_SMOOTH_CAMERA, minecraft)
// optionPanes[2]->createToggle(controlsGroup, "Lefty", &Options::Option::LEFT_HANDED); .addOptionItem(OPTIONS_DESTROY_VIBRATION, minecraft)
// optionPanes[2]->createToggle(controlsGroup, "Use touch screen", &Options::Option::USE_TOUCHSCREEN); .addOptionItem(OPTIONS_IS_LEFT_HANDED, minecraft);
// optionPanes[2]->createToggle(controlsGroup, "Split touch controls", &Options::Option::USE_TOUCH_JOYPAD);
// int feedBackGroup = optionPanes[2]->createOptionsGroup("Feedback"); // // Controls Pane
// optionPanes[2]->createToggle(feedBackGroup, "Vibrate on destroy", &Options::Option::DESTROY_VIBRATION); optionPanes[2]->addOptionItem(OPTIONS_INVERT_Y_MOUSE, minecraft)
// .addOptionItem(OPTIONS_USE_TOUCHSCREEN, minecraft);
// int graphicsGroup = optionPanes[3]->createOptionsGroup("Graphics");
// optionPanes[3]->createProgressSlider(minecraft, graphicsGroup, "Gui Scale", &Options::Option::PIXELS_PER_MILLIMETER, 3, 4); for (int i = OPTIONS_KEY_FORWARD; i <= OPTIONS_KEY_USE; i++) {
// optionPanes[3]->createToggle(graphicsGroup, "Fancy Graphics", &Options::Option::INVERT_MOUSE); optionPanes[2]->addOptionItem((OptionId)i, minecraft);
// optionPanes[3]->createToggle(graphicsGroup, "Fancy Skies", &Options::Option::INVERT_MOUSE); }
// optionPanes[3]->createToggle(graphicsGroup, "Animated water", &Options::Option::INVERT_MOUSE);
// int experimentalGraphicsGroup = optionPanes[3]->createOptionsGroup("Experimental graphics"); // // Graphics Pane
// optionPanes[3]->createToggle(experimentalGraphicsGroup, "Soft shadows", &Options::Option::INVERT_MOUSE); optionPanes[3]->addOptionItem(OPTIONS_FANCY_GRAPHICS, minecraft)
.addOptionItem(OPTIONS_LIMIT_FRAMERATE, minecraft)
.addOptionItem(OPTIONS_VSYNC, minecraft)
.addOptionItem(OPTIONS_RENDER_DEBUG, minecraft)
.addOptionItem(OPTIONS_ANAGLYPH_3D, minecraft)
.addOptionItem(OPTIONS_VIEW_BOBBING, minecraft)
.addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft);
optionPanes[4]->addOptionItem(OPTIONS_ALLOW_SPRINT, minecraft)
.addOptionItem(OPTIONS_BAR_ON_TOP, minecraft);
} }
void OptionsScreen::mouseClicked( int x, int y, int buttonNum ) { void OptionsScreen::mouseClicked(int x, int y, int buttonNum) {
if(currentOptionPane != NULL)
currentOptionPane->mouseClicked(minecraft, x, y, buttonNum); if (currentOptionsGroup != NULL)
currentOptionsGroup->mouseClicked(minecraft, x, y, buttonNum);
super::mouseClicked(x, y, buttonNum); super::mouseClicked(x, y, buttonNum);
} }
void OptionsScreen::mouseReleased( int x, int y, int buttonNum ) { void OptionsScreen::mouseReleased(int x, int y, int buttonNum) {
if(currentOptionPane != NULL)
currentOptionPane->mouseReleased(minecraft, x, y, buttonNum); if (currentOptionsGroup != NULL)
currentOptionsGroup->mouseReleased(minecraft, x, y, buttonNum);
super::mouseReleased(x, y, buttonNum); super::mouseReleased(x, y, buttonNum);
} }
void OptionsScreen::tick() { void OptionsScreen::keyPressed(int eventKey) {
if(currentOptionPane != NULL) if (currentOptionsGroup != NULL)
currentOptionPane->tick(minecraft); currentOptionsGroup->keyPressed(minecraft, eventKey);
super::tick(); if (eventKey == Keyboard::KEY_ESCAPE)
minecraft->options.save();
super::keyPressed(eventKey);
} }
void OptionsScreen::charPressed(char inputChar) {
if (currentOptionsGroup != NULL)
currentOptionsGroup->charPressed(minecraft, inputChar);
super::keyPressed(inputChar);
}
void OptionsScreen::tick() {
if (currentOptionsGroup != NULL)
currentOptionsGroup->tick(minecraft);
super::tick();
}

View File

@@ -3,6 +3,7 @@
#include "../Screen.h" #include "../Screen.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/OptionsGroup.h"
class ImageButton; class ImageButton;
class OptionsPane; class OptionsPane;
@@ -10,29 +11,39 @@ class OptionsPane;
class OptionsScreen: public Screen class OptionsScreen: public Screen
{ {
typedef Screen super; typedef Screen super;
void init();
void init();
void generateOptionScreens(); void generateOptionScreens();
public: public:
OptionsScreen(); OptionsScreen();
~OptionsScreen(); ~OptionsScreen();
void setupPositions(); void setupPositions();
void buttonClicked( Button* button ); void buttonClicked(Button* button);
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
void removed(); void removed();
void selectCategory(int index); void selectCategory(int index);
virtual void mouseClicked( int x, int y, int buttonNum ); virtual void mouseClicked(int x, int y, int buttonNum);
virtual void mouseReleased( int x, int y, int buttonNum ); virtual void mouseReleased(int x, int y, int buttonNum);
virtual void keyPressed(int eventKey);
virtual void charPressed(char inputChar);
virtual void tick(); virtual void tick();
private: private:
Touch::THeader* bHeader; Touch::THeader* bHeader;
ImageButton* btnClose; ImageButton* btnClose;
Button* btnCredits; // <-- ADD THIS
std::vector<Touch::TButton*> categoryButtons; std::vector<Touch::TButton*> categoryButtons;
std::vector<OptionsPane*> optionPanes; std::vector<OptionsGroup*> optionPanes;
OptionsPane* currentOptionPane;
OptionsGroup* currentOptionsGroup;
int selectedCategory; int selectedCategory;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__OptionsScreen_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__OptionsScreen_H__*/

View File

@@ -15,9 +15,9 @@ PauseScreen::PauseScreen(bool wasBackPaused)
bServerVisibility(0), bServerVisibility(0),
// bThirdPerson(0), // bThirdPerson(0),
wasBackPaused(wasBackPaused), wasBackPaused(wasBackPaused),
bSound(&Options::Option::SOUND, 1, 0), // bSound(OPTIONS_SOUND_VOLUME, 1, 0),
bThirdPerson(&Options::Option::THIRD_PERSON), bThirdPerson(OPTIONS_THIRD_PERSON_VIEW),
bHideGui(&Options::Option::HIDE_GUI) bHideGui(OPTIONS_HIDEGUI)
{ {
ImageDef def; ImageDef def;
def.setSrc(IntRectangle(160, 144, 39, 31)); def.setSrc(IntRectangle(160, 144, 39, 31));
@@ -27,7 +27,7 @@ PauseScreen::PauseScreen(bool wasBackPaused)
def.width = defSrc.w * 0.666667f; def.width = defSrc.w * 0.666667f;
def.height = defSrc.h * 0.666667f; def.height = defSrc.h * 0.666667f;
bSound.setImageDef(def, true); // bSound.setImageDef(def, true);
defSrc.y += defSrc.h; defSrc.y += defSrc.h;
bThirdPerson.setImageDef(def, true); bThirdPerson.setImageDef(def, true);
bHideGui.setImageDef(def, true); bHideGui.setImageDef(def, true);
@@ -60,10 +60,10 @@ void PauseScreen::init() {
buttons.push_back(bContinue); buttons.push_back(bContinue);
buttons.push_back(bQuit); buttons.push_back(bQuit);
bSound.updateImage(&minecraft->options); // bSound.updateImage(&minecraft->options);
bThirdPerson.updateImage(&minecraft->options); bThirdPerson.updateImage(&minecraft->options);
bHideGui.updateImage(&minecraft->options); bHideGui.updateImage(&minecraft->options);
buttons.push_back(&bSound); // buttons.push_back(&bSound);
buttons.push_back(&bThirdPerson); buttons.push_back(&bThirdPerson);
//buttons.push_back(&bHideGui); //buttons.push_back(&bHideGui);
@@ -88,7 +88,7 @@ void PauseScreen::init() {
// buttons.push_back(bThirdPerson); // buttons.push_back(bThirdPerson);
for (unsigned int i = 0; i < buttons.size(); ++i) { for (unsigned int i = 0; i < buttons.size(); ++i) {
if (buttons[i] == &bSound) continue; // if (buttons[i] == &bSound) continue;
if (buttons[i] == &bThirdPerson) continue; if (buttons[i] == &bThirdPerson) continue;
if (buttons[i] == &bHideGui) continue; if (buttons[i] == &bHideGui) continue;
tabButtons.push_back(buttons[i]); tabButtons.push_back(buttons[i]);
@@ -115,10 +115,10 @@ void PauseScreen::setupPositions() {
bQuitAndSaveLocally->x = bServerVisibility->x = (width - bQuitAndSaveLocally->width) / 2; bQuitAndSaveLocally->x = bServerVisibility->x = (width - bQuitAndSaveLocally->width) / 2;
bQuitAndSaveLocally->y = bServerVisibility->y = yBase + 32 * 3; bQuitAndSaveLocally->y = bServerVisibility->y = yBase + 32 * 3;
bSound.y = bThirdPerson.y = 8; // bSound.y = bThirdPerson.y = 8;
bSound.x = 4; // bSound.x = 4;
bThirdPerson.x = bSound.x + 4 + bSound.width; // bThirdPerson.x = bSound.x + 4 + bSound.width;
bHideGui.x = bThirdPerson.x + 4 + bThirdPerson.width; // bHideGui.x = bThirdPerson.x + 4 + bThirdPerson.width;
//bThirdPerson->x = (width - bThirdPerson->w) / 2; //bThirdPerson->x = (width - bThirdPerson->w) / 2;
//bThirdPerson->y = yBase + 32 * 4; //bThirdPerson->y = yBase + 32 * 4;

View File

@@ -35,7 +35,7 @@ private:
Button* bServerVisibility; Button* bServerVisibility;
// Button* bThirdPerson; // Button* bThirdPerson;
OptionButton bSound; // OptionButton bSound;
OptionButton bThirdPerson; OptionButton bThirdPerson;
OptionButton bHideGui; OptionButton bHideGui;
}; };

View File

@@ -5,6 +5,7 @@
#include "PauseScreen.h" #include "PauseScreen.h"
#include "RenameMPLevelScreen.h" #include "RenameMPLevelScreen.h"
#include "IngameBlockSelectionScreen.h" #include "IngameBlockSelectionScreen.h"
#include "JoinByIPScreen.h"
#include "touch/TouchStartMenuScreen.h" #include "touch/TouchStartMenuScreen.h"
#include "touch/TouchSelectWorldScreen.h" #include "touch/TouchSelectWorldScreen.h"
#include "touch/TouchJoinGameScreen.h" #include "touch/TouchJoinGameScreen.h"
@@ -12,19 +13,21 @@
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include <client/gui/screens/UsernameScreen.h>
Screen* ScreenChooser::createScreen( ScreenId id ) Screen* ScreenChooser::createScreen( ScreenId id )
{ {
Screen* screen = NULL; Screen* screen = NULL;
if (_mc->useTouchscreen()) { if (_mc->useTouchscreen()) {
switch (id) { switch (id) {
case SCREEN_STARTMENU: screen = new Touch::StartMenuScreen(); break; case SCREEN_STARTMENU: screen = new Touch::StartMenuScreen(); break;
case SCREEN_SELECTWORLD:screen = new Touch::SelectWorldScreen();break; case SCREEN_SELECTWORLD: screen = new Touch::SelectWorldScreen();break;
case SCREEN_JOINGAME: screen = new Touch::JoinGameScreen(); break; case SCREEN_JOINGAME: screen = new Touch::JoinGameScreen(); break;
case SCREEN_PAUSE: screen = new PauseScreen(false); break; case SCREEN_PAUSE: screen = new PauseScreen(false); break;
case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break; case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break;
case SCREEN_BLOCKSELECTION: screen = new Touch::IngameBlockSelectionScreen(); break; case SCREEN_BLOCKSELECTION: screen = new Touch::IngameBlockSelectionScreen(); break;
case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break;
case SCREEN_NONE: case SCREEN_NONE:
default: default:
// Do nothing // Do nothing
@@ -32,12 +35,13 @@ Screen* ScreenChooser::createScreen( ScreenId id )
} }
} else { } else {
switch (id) { switch (id) {
case SCREEN_STARTMENU: screen = new StartMenuScreen(); break; case SCREEN_STARTMENU: screen = new StartMenuScreen(); break;
case SCREEN_SELECTWORLD:screen = new SelectWorldScreen();break; case SCREEN_SELECTWORLD: screen = new SelectWorldScreen();break;
case SCREEN_JOINGAME: screen = new JoinGameScreen(); break; case SCREEN_JOINGAME: screen = new JoinGameScreen(); break;
case SCREEN_PAUSE: screen = new PauseScreen(false); break; case SCREEN_PAUSE: screen = new PauseScreen(false); break;
case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break; case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break;
case SCREEN_BLOCKSELECTION: screen = new IngameBlockSelectionScreen(); break; case SCREEN_BLOCKSELECTION: screen = new IngameBlockSelectionScreen(); break;
case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break;
case SCREEN_NONE: case SCREEN_NONE:
default: default:

View File

@@ -8,7 +8,8 @@ enum ScreenId {
SCREEN_PAUSE, SCREEN_PAUSE,
SCREEN_PAUSEPREV, SCREEN_PAUSEPREV,
SCREEN_SELECTWORLD, SCREEN_SELECTWORLD,
SCREEN_BLOCKSELECTION SCREEN_BLOCKSELECTION,
SCREEN_JOINBYIP
}; };
class Screen; class Screen;

View File

@@ -230,7 +230,6 @@ SelectWorldScreen::SelectWorldScreen()
bBack (3, "Back"), bBack (3, "Back"),
bWorldView(4, ""), bWorldView(4, ""),
worldsList(NULL), worldsList(NULL),
_state(_STATE_DEFAULT),
_hasStartedLevel(false) _hasStartedLevel(false)
{ {
bDelete.active = false; bDelete.active = false;
@@ -244,17 +243,11 @@ SelectWorldScreen::~SelectWorldScreen()
void SelectWorldScreen::buttonClicked(Button* button) void SelectWorldScreen::buttonClicked(Button* button)
{ {
if (button->id == bCreate.id) { if (button->id == bCreate.id) {
//minecraft->setScreen( new CreateWorldScreen() ); // open in-game world-creation screen instead of using platform dialog
//minecraft->locateMultiplayer(); if (!_hasStartedLevel) {
//minecraft->setScreen(new JoinGameScreen()); std::string name = getUniqueLevelName("world");
minecraft->setScreen(new SimpleChooseLevelScreen(name));
//minecraft->hostMultiplayer(); }
//minecraft->setScreen(new ProgressScreen());
if (_state == _STATE_DEFAULT && !_hasStartedLevel) {
minecraft->platform()->createUserInput(DialogDefinitions::DIALOG_CREATE_NEW_WORLD);
_state = _STATE_CREATEWORLD;
}
} }
if (button->id == bDelete.id) { if (button->id == bDelete.id) {
if (isIndexValid(worldsList->selectedItem)) { if (isIndexValid(worldsList->selectedItem)) {
@@ -294,70 +287,6 @@ static char ILLEGAL_FILE_CHARACTERS[] = {
void SelectWorldScreen::tick() void SelectWorldScreen::tick()
{ {
if (_state == _STATE_CREATEWORLD) {
#if defined(RPI)
std::string levelId = getUniqueLevelName("world");
LevelSettings settings(getEpochTimeS(), GameType::Creative);
minecraft->selectLevel(levelId, levelId, settings);
minecraft->hostMultiplayer();
minecraft->setScreen(new ProgressScreen());
_hasStartedLevel = true;
#elif defined(WIN32)
std::string name = getUniqueLevelName("perf");
minecraft->setScreen(new SimpleChooseLevelScreen(name));
#else
int status = minecraft->platform()->getUserInputStatus();
if (status > -1) {
if (status == 1) {
StringVector sv = minecraft->platform()->getUserInput();
// Read the level name.
// 1) Trim name 2) Remove all bad chars 3) Append '-' chars 'til the name is unique
std::string levelName = Util::stringTrim(sv[0]);
std::string levelId = levelName;
for (int i = 0; i < sizeof(ILLEGAL_FILE_CHARACTERS) / sizeof(char); ++i)
levelId = Util::stringReplace(levelId, std::string(1, ILLEGAL_FILE_CHARACTERS[i]), "");
if ((int)levelId.length() == 0) {
levelId = "no_name";
}
levelId = getUniqueLevelName(levelId);
// Read the seed
int seed = getEpochTimeS();
if (sv.size() >= 2) {
std::string seedString = Util::stringTrim(sv[1]);
if (seedString.length() > 0) {
int tmpSeed;
// Try to read it as an integer
if (sscanf(seedString.c_str(), "%d", &tmpSeed) > 0) {
seed = tmpSeed;
} // Hash the "seed"
else {
seed = Util::hashCode(seedString);
}
}
}
// Read the game mode
bool isCreative = true;
if (sv.size() >= 3 && sv[2] == "survival")
isCreative = false;
// Start a new level with the given name and seed
LevelSettings settings(seed, isCreative? GameType::Creative : GameType::Survival);
LOGI("Creating a level with id '%s', name '%s' and seed '%d'\n", levelId.c_str(), levelName.c_str(), seed);
minecraft->selectLevel(levelId, levelName, settings);
minecraft->hostMultiplayer();
minecraft->setScreen(new ProgressScreen());
_hasStartedLevel = true;
}
_state = _STATE_DEFAULT;
}
#endif
return;
}
worldsList->tick(); worldsList->tick();
if (worldsList->hasPickedLevel) { if (worldsList->hasPickedLevel) {
@@ -425,13 +354,23 @@ void SelectWorldScreen::render( int xm, int ym, float a )
//Performance::watches.get("sws-worlds").start(); //Performance::watches.get("sws-worlds").start();
worldsList->setComponentSelected(bWorldView.selected); worldsList->setComponentSelected(bWorldView.selected);
// #ifdef PLATFORM_DESKTOP
// desktop: render the list normally (mouse wheel handled separately below)
if (_mouseHasBeenUp) if (_mouseHasBeenUp)
worldsList->render(xm, ym, a); worldsList->render(xm, ym, a);
else { else {
worldsList->render(0, 0, a); worldsList->render(0, 0, a);
_mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT);
} }
// #else
// if (_mouseHasBeenUp)
// worldsList->render(xm, ym, a);
// else {
// worldsList->render(0, 0, a);
// _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT);
// }
// #endif
//Performance::watches.get("sws-worlds").stop(); //Performance::watches.get("sws-worlds").stop();
//Performance::watches.get("sws-screen").start(); //Performance::watches.get("sws-screen").start();
@@ -473,12 +412,34 @@ std::string SelectWorldScreen::getUniqueLevelName( const std::string& level )
bool SelectWorldScreen::isInGameScreen() { return true; } bool SelectWorldScreen::isInGameScreen() { return true; }
void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym)
{
if (!worldsList)
return;
if (dy == 0)
return;
int num = worldsList->getNumberOfItems();
int idx = worldsList->selectedItem;
if (dy > 0) {
if (idx > 0) {
idx--;
worldsList->stepLeft();
}
} else {
if (idx < num - 1) {
idx++;
worldsList->stepRight();
}
}
worldsList->selectedItem = idx;
}
void SelectWorldScreen::keyPressed( int eventKey ) void SelectWorldScreen::keyPressed( int eventKey )
{ {
if (bWorldView.selected) { if (bWorldView.selected) {
if (eventKey == minecraft->options.keyLeft.key) if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_RIGHT))
worldsList->stepLeft(); worldsList->stepLeft();
if (eventKey == minecraft->options.keyRight.key) if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_LEFT))
worldsList->stepRight(); worldsList->stepRight();
} }

View File

@@ -4,7 +4,6 @@
#include "../Screen.h" #include "../Screen.h"
#include "../TweenData.h" #include "../TweenData.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/SmallButton.h"
#include "../components/RolledSelectionListH.h" #include "../components/RolledSelectionListH.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../../world/level/storage/LevelStorageSource.h" #include "../../../world/level/storage/LevelStorageSource.h"
@@ -90,6 +89,9 @@ public:
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
// mouse wheel scroll (new in desktop implementation)
virtual void mouseWheel(int dx, int dy, int xm, int ym);
bool isInGameScreen(); bool isInGameScreen();
private: private:
void loadLevelSource(); void loadLevelSource();
@@ -104,9 +106,6 @@ private:
bool _mouseHasBeenUp; bool _mouseHasBeenUp;
bool _hasStartedLevel; bool _hasStartedLevel;
int _state;
static const int _STATE_DEFAULT = 0;
static const int _STATE_CREATEWORLD = 1;
//LevelStorageSource* levels; //LevelStorageSource* levels;
}; };

View File

@@ -2,96 +2,259 @@
#include "ProgressScreen.h" #include "ProgressScreen.h"
#include "ScreenChooser.h" #include "ScreenChooser.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/ImageButton.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../../world/level/LevelSettings.h" #include "../../../world/level/LevelSettings.h"
#include "../../../platform/time.h" #include "../../../platform/time.h"
#include "../../../platform/input/Keyboard.h"
#include "../../../platform/log.h"
SimpleChooseLevelScreen::SimpleChooseLevelScreen(const std::string& levelName) SimpleChooseLevelScreen::SimpleChooseLevelScreen(const std::string& levelName)
: bCreative(0), : bHeader(0),
bSurvival(0), bGamemode(0),
bBack(0), bCheats(0),
levelName(levelName), bBack(0),
hasChosen(false) bCreate(0),
levelName(levelName),
hasChosen(false),
gamemode(GameType::Survival),
cheatsEnabled(false),
tLevelName(0, "World name"),
tSeed(1, "World seed")
{ {
} }
SimpleChooseLevelScreen::~SimpleChooseLevelScreen() SimpleChooseLevelScreen::~SimpleChooseLevelScreen()
{ {
delete bCreative; if (bHeader) delete bHeader;
delete bSurvival; delete bGamemode;
delete bBack; delete bCheats;
delete bBack;
delete bCreate;
} }
void SimpleChooseLevelScreen::init() void SimpleChooseLevelScreen::init()
{ {
if (minecraft->useTouchscreen()) { // make sure the base class loads the existing level list; the
bCreative = new Touch::TButton(1, "Creative mode"); // derived screen uses ChooseLevelScreen::getUniqueLevelName(), which
bSurvival = new Touch::TButton(2, "Survival mode"); // depends on `levels` being populated. omitting this used to result
bBack = new Touch::TButton(3, "Back"); // in duplicate IDs ("creating the second world would load the
} else { // first") when the name already existed.
bCreative = new Button(1, "Creative mode"); ChooseLevelScreen::init();
bSurvival = new Button(2, "Survival mode");
bBack = new Button(3, "Back");
}
buttons.push_back(bCreative);
buttons.push_back(bSurvival);
buttons.push_back(bBack);
tabButtons.push_back(bCreative); tLevelName.text = "New world";
tabButtons.push_back(bSurvival);
tabButtons.push_back(bBack); // header + close button
bHeader = new Touch::THeader(0, "Create World");
// create the back/X button as ImageButton like CreditsScreen
bBack = new ImageButton(2, "");
{
ImageDef def;
def.name = "gui/touchgui.png";
def.width = 34;
def.height = 26;
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
bBack->setImageDef(def, true);
}
if (minecraft->useTouchscreen()) {
bGamemode = new Touch::TButton(1, "Survival mode");
bCheats = new Touch::TButton(4, "Cheats: Off");
bCreate = new Touch::TButton(3, "Create");
} else {
bGamemode = new Button(1, "Survival mode");
bCheats = new Button(4, "Cheats: Off");
bCreate = new Button(3, "Create");
}
buttons.push_back(bHeader);
buttons.push_back(bBack);
buttons.push_back(bGamemode);
buttons.push_back(bCheats);
buttons.push_back(bCreate);
tabButtons.push_back(bGamemode);
tabButtons.push_back(bCheats);
tabButtons.push_back(bBack);
tabButtons.push_back(bCreate);
textBoxes.push_back(&tLevelName);
textBoxes.push_back(&tSeed);
} }
void SimpleChooseLevelScreen::setupPositions() void SimpleChooseLevelScreen::setupPositions()
{ {
bCreative->width = bSurvival->width = bBack->width = 120; int buttonHeight = bBack->height;
bCreative->x = (width - bCreative->width) / 2;
bCreative->y = height/3 - 40; // position back button in upper-right
bSurvival->x = (width - bSurvival->width) / 2; bBack->x = width - bBack->width;
bSurvival->y = 2*height/3 - 40; bBack->y = 0;
bBack->x = bSurvival->x + bSurvival->width - bBack->width;
bBack->y = height - 40; // header occupies remaining top bar
if (bHeader) {
bHeader->x = 0;
bHeader->y = 0;
bHeader->width = width - bBack->width;
bHeader->height = buttonHeight;
}
// layout the form elements below the header
int centerX = width / 2;
const int padding = 5;
tLevelName.width = tSeed.width = 200;
tLevelName.x = centerX - tLevelName.width / 2;
tLevelName.y = buttonHeight + 20;
tSeed.x = tLevelName.x;
tSeed.y = tLevelName.y + 30;
const int buttonWidth = 120;
const int buttonSpacing = 10;
const int totalButtonWidth = buttonWidth * 2 + buttonSpacing;
bGamemode->width = buttonWidth;
bCheats->width = buttonWidth;
bGamemode->x = centerX - totalButtonWidth / 2;
bCheats->x = bGamemode->x + buttonWidth + buttonSpacing;
// compute vertical centre for buttons in remaining space
{
int bottomPad = 20;
int availTop = buttonHeight + 20 + 30 + 10; // just below seed
int availBottom = height - bottomPad - bCreate->height - 10; // leave some gap before create
int availHeight = availBottom - availTop;
if (availHeight < 0) availHeight = 0;
int y = availTop + (availHeight - bGamemode->height) / 2;
bGamemode->y = y;
bCheats->y = y;
}
bCreate->width = 100;
bCreate->x = centerX - bCreate->width / 2;
int bottomPadding = 20;
bCreate->y = height - bottomPadding - bCreate->height;
}
void SimpleChooseLevelScreen::tick()
{
// let any textboxes handle their own blinking/input
for (auto* tb : textBoxes)
tb->tick(minecraft);
} }
void SimpleChooseLevelScreen::render( int xm, int ym, float a ) void SimpleChooseLevelScreen::render( int xm, int ym, float a )
{ {
renderDirtBackground(0); renderDirtBackground(0);
glEnable2(GL_BLEND); glEnable2(GL_BLEND);
drawCenteredString(minecraft->font, "Mobs, health and gather resources", width/2, bSurvival->y + bSurvival->height + 4, 0xffcccccc); const char* modeDesc = NULL;
drawCenteredString(minecraft->font, "Unlimited resources and flying", width/2, bCreative->y + bCreative->height + 4, 0xffcccccc); if (gamemode == GameType::Survival) {
modeDesc = "Mobs, health and gather resources";
} else if (gamemode == GameType::Creative) {
modeDesc = "Unlimited resources and flying";
}
if (modeDesc) {
drawCenteredString(minecraft->font, modeDesc, width / 2, bGamemode->y + bGamemode->height + 4, 0xffcccccc);
}
Screen::render(xm, ym, a); drawString(minecraft->font, "World name:", tLevelName.x, tLevelName.y - Font::DefaultLineHeight - 2, 0xffcccccc);
drawString(minecraft->font, "World seed:", tSeed.x, tSeed.y - Font::DefaultLineHeight - 2, 0xffcccccc);
Screen::render(xm, ym, a);
glDisable2(GL_BLEND); glDisable2(GL_BLEND);
} }
// mouse clicks should also manage textbox focus explicitly
void SimpleChooseLevelScreen::mouseClicked(int x, int y, int buttonNum)
{
if (buttonNum == MouseAction::ACTION_LEFT) {
// determine if the click landed on either textbox or its label above
int lvlTop = tLevelName.y - (Font::DefaultLineHeight + 4);
int lvlBottom = tLevelName.y + tLevelName.height;
int lvlLeft = tLevelName.x;
int lvlRight = tLevelName.x + tLevelName.width;
bool clickedLevel = x >= lvlLeft && x < lvlRight && y >= lvlTop && y < lvlBottom;
int seedTop = tSeed.y - (Font::DefaultLineHeight + 4);
int seedBottom = tSeed.y + tSeed.height;
int seedLeft = tSeed.x;
int seedRight = tSeed.x + tSeed.width;
bool clickedSeed = x >= seedLeft && x < seedRight && y >= seedTop && y < seedBottom;
if (clickedLevel) {
LOGI("SimpleChooseLevelScreen: level textbox clicked (%d,%d)\n", x, y);
tLevelName.setFocus(minecraft);
tSeed.loseFocus(minecraft);
} else if (clickedSeed) {
LOGI("SimpleChooseLevelScreen: seed textbox clicked (%d,%d)\n", x, y);
tSeed.setFocus(minecraft);
tLevelName.loseFocus(minecraft);
} else {
// click outside both fields -> blur both
tLevelName.loseFocus(minecraft);
tSeed.loseFocus(minecraft);
}
}
// allow normal button and textbox handling too
Screen::mouseClicked(x, y, buttonNum);
}
void SimpleChooseLevelScreen::buttonClicked( Button* button ) void SimpleChooseLevelScreen::buttonClicked( Button* button )
{ {
if (button == bBack) { if (hasChosen)
minecraft->screenChooser.setScreen(SCREEN_STARTMENU); return;
return;
}
if (hasChosen)
return;
int gameType; if (button == bGamemode) {
gamemode ^= 1;
bGamemode->msg = (gamemode == GameType::Survival) ? "Survival mode" : "Creative mode";
return;
}
if (button == bCreative) if (button == bCheats) {
gameType = GameType::Creative; cheatsEnabled = !cheatsEnabled;
bCheats->msg = cheatsEnabled ? "Cheats: On" : "Cheats: Off";
return;
}
if (button == bSurvival) if (button == bCreate && !tLevelName.text.empty()) {
gameType = GameType::Survival; int seed = getEpochTimeS();
if (!tSeed.text.empty()) {
std::string seedString = Util::stringTrim(tSeed.text);
int tmpSeed;
if (sscanf(seedString.c_str(), "%d", &tmpSeed) > 0) {
seed = tmpSeed;
} else {
seed = Util::hashCode(seedString);
}
}
std::string levelId = getUniqueLevelName(tLevelName.text);
LevelSettings settings(seed, gamemode, cheatsEnabled);
minecraft->selectLevel(levelId, levelId, settings);
minecraft->hostMultiplayer();
minecraft->setScreen(new ProgressScreen());
hasChosen = true;
return;
}
std::string levelId = getUniqueLevelName(levelName); if (button == bBack) {
LevelSettings settings(getEpochTimeS(), gameType); minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
minecraft->selectLevel(levelId, levelId, settings); }
minecraft->hostMultiplayer(); }
minecraft->setScreen(new ProgressScreen());
hasChosen = true; void SimpleChooseLevelScreen::keyPressed(int eventKey)
{
if (eventKey == Keyboard::KEY_ESCAPE) {
minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
return;
}
// let base class handle navigation and text box keys
Screen::keyPressed(eventKey);
} }
bool SimpleChooseLevelScreen::handleBackEvent(bool isDown) { bool SimpleChooseLevelScreen::handleBackEvent(bool isDown) {
if (!isDown) if (!isDown)
minecraft->screenChooser.setScreen(SCREEN_STARTMENU); minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
return true; return true;
} }

View File

@@ -2,7 +2,10 @@
#define NET_MINECRAFT_CLIENT_GUI_SCREENS__DemoChooseLevelScreen_H__ #define NET_MINECRAFT_CLIENT_GUI_SCREENS__DemoChooseLevelScreen_H__
#include "ChooseLevelScreen.h" #include "ChooseLevelScreen.h"
#include "../components/TextBox.h"
#include "../components/Button.h" // for Touch::THeader
class Button; class Button;
class ImageButton;
class SimpleChooseLevelScreen: public ChooseLevelScreen class SimpleChooseLevelScreen: public ChooseLevelScreen
{ {
@@ -12,21 +15,30 @@ public:
virtual ~SimpleChooseLevelScreen(); virtual ~SimpleChooseLevelScreen();
void init(); void init();
void setupPositions(); void setupPositions();
void tick();
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
void buttonClicked(Button* button); void buttonClicked(Button* button);
bool handleBackEvent(bool isDown); bool handleBackEvent(bool isDown);
virtual void keyPressed(int eventKey);
virtual void mouseClicked(int x, int y, int buttonNum);
private: private:
Button* bCreative; Touch::THeader* bHeader;
Button* bSurvival; Button* bGamemode;
Button* bBack; Button* bCheats;
ImageButton* bBack;
Button* bCreate;
bool hasChosen; bool hasChosen;
std::string levelName; std::string levelName;
int gamemode;
bool cheatsEnabled;
TextBox tLevelName;
TextBox tSeed;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__DemoChooseLevelScreen_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__DemoChooseLevelScreen_H__*/

View File

@@ -1,17 +1,16 @@
#include "StartMenuScreen.h" #include "StartMenuScreen.h"
#include "UsernameScreen.h"
#include "SelectWorldScreen.h" #include "SelectWorldScreen.h"
#include "ProgressScreen.h" #include "ProgressScreen.h"
#include "JoinGameScreen.h" #include "JoinGameScreen.h"
#include "OptionsScreen.h" #include "OptionsScreen.h"
#include "PauseScreen.h" #include "PauseScreen.h"
#include "InvalidLicenseScreen.h"
#include "PrerenderTilesScreen.h" // test button #include "PrerenderTilesScreen.h" // test button
//#include "BuyGameScreen.h" #include "../components/ImageButton.h"
#include "../../../util/Mth.h" #include "../../../util/Mth.h"
#include "../Font.h" #include "../Font.h"
#include "../components/SmallButton.h"
#include "../components/ScrolledSelectionList.h" #include "../components/ScrolledSelectionList.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
@@ -26,9 +25,8 @@
StartMenuScreen::StartMenuScreen() StartMenuScreen::StartMenuScreen()
: bHost( 2, 0, 0, 160, 24, "Start Game"), : bHost( 2, 0, 0, 160, 24, "Start Game"),
bJoin( 3, 0, 0, 160, 24, "Join Game"), bJoin( 3, 0, 0, 160, 24, "Join Game"),
bOptions( 4, 0, 0, 78, 22, "Options"), bOptions( 4, 0, 0, 160, 24, "Options"),
bBuy( 5, 0, 0, 78, 22, "Buy"), bQuit( 5, "")
bTest( 999, 0, 0, 78, 22, "Create")
{ {
} }
@@ -38,6 +36,12 @@ StartMenuScreen::~StartMenuScreen()
void StartMenuScreen::init() void StartMenuScreen::init()
{ {
bJoin.active = bHost.active = bOptions.active = true;
if (minecraft->options.getStringValue(OPTIONS_USERNAME).empty()) {
return; // tick() will redirect to UsernameScreen
}
buttons.push_back(&bHost); buttons.push_back(&bHost);
buttons.push_back(&bJoin); buttons.push_back(&bJoin);
//buttons.push_back(&bTest); //buttons.push_back(&bTest);
@@ -50,18 +54,28 @@ void StartMenuScreen::init()
tabButtons.push_back(&bOptions); tabButtons.push_back(&bOptions);
#endif #endif
#ifdef DEMO_MODE // add quit button (top right X icon) match OptionsScreen style
buttons.push_back(&bBuy); {
tabButtons.push_back(&bBuy); ImageDef def;
#endif def.name = "gui/touchgui.png";
def.width = 34;
def.height = 26;
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
bQuit.setImageDef(def, true);
bQuit.scaleWhenPressed = false;
buttons.push_back(&bQuit);
// don't include in tab navigation
}
copyright = "\xffMojang AB";//. Do not distribute!"; copyright = "\xffMojang AB";//. Do not distribute!";
#ifdef PRE_ANDROID23 // always show base version string, suffix was previously added for Android builds
std::string versionString = Common::getGameVersionString("j"); std::string versionString = Common::getGameVersionString();
#else
std::string versionString = Common::getGameVersionString(); std::string _username = minecraft->options.getStringValue(OPTIONS_USERNAME);
#endif if (_username.empty()) _username = "unknown";
username = "Username: " + _username;
#ifdef DEMO_MODE #ifdef DEMO_MODE
#ifdef __APPLE__ #ifdef __APPLE__
@@ -76,37 +90,26 @@ void StartMenuScreen::init()
version = versionString; version = versionString;
#endif #endif
#endif #endif
bJoin.active = bHost.active = bOptions.active = false;
} }
void StartMenuScreen::setupPositions() { void StartMenuScreen::setupPositions() {
int yBase = height / 2 + 25; int yBase = height / 2;
//#ifdef ANDROID bHost.y = yBase;
bHost.y = yBase - 28; bJoin.y = bHost.y + 24 + 4;
#ifdef RPI bOptions.y = bJoin.y + 24 + 4;
bJoin.y = yBase + 4;
#else
bJoin.y = yBase;
#endif
bOptions.y = yBase + 28 + 2;
bTest.y = bBuy.y = bOptions.y;
//#endif
// Center buttons // Center buttons
bHost.x = (width - bHost.width) / 2; bHost.x = (width - bHost.width) / 2;
bJoin.x = (width - bJoin.width) / 2; bJoin.x = (width - bJoin.width) / 2;
bOptions.x = (width - bJoin.width) / 2; bOptions.x = (width - bOptions.width) / 2;
bTest.x = bBuy.x = bOptions.x + bOptions.width + 4;
copyrightPosX = width - minecraft->font->width(copyright) - 1; // position quit icon at top-right (use image-defined size)
versionPosX = (width - minecraft->font->width(version)) / 2;// - minecraft->font->width(version) - 2; bQuit.x = width - bQuit.width;
bQuit.y = 0;
} }
void StartMenuScreen::tick() { void StartMenuScreen::tick() {
_updateLicense();
} }
void StartMenuScreen::buttonClicked(Button* button) { void StartMenuScreen::buttonClicked(Button* button) {
@@ -128,15 +131,9 @@ void StartMenuScreen::buttonClicked(Button* button) {
{ {
minecraft->setScreen(new OptionsScreen()); minecraft->setScreen(new OptionsScreen());
} }
if (button->id == bTest.id) if (button == &bQuit)
{ {
//minecraft->setScreen(new PauseScreen()); minecraft->quit();
//minecraft->setScreen(new PrerenderTilesScreen());
}
if (button->id == bBuy.id)
{
minecraft->platform()->buyGame();
//minecraft->setScreen(new BuyGameScreen());
} }
} }
@@ -146,6 +143,9 @@ void StartMenuScreen::render( int xm, int ym, float a )
{ {
renderBackground(); renderBackground();
// Show current username in the top-left corner
drawString(font, username, 2, 2, 0xffffffff);
#if defined(RPI) #if defined(RPI)
TextureId id = minecraft->textures->loadTexture("gui/pi_title.png"); TextureId id = minecraft->textures->loadTexture("gui/pi_title.png");
#else #else
@@ -157,7 +157,7 @@ void StartMenuScreen::render( int xm, int ym, float a )
minecraft->textures->bind(id); minecraft->textures->bind(id);
const float x = (float)width / 2; const float x = (float)width / 2;
const float y = 4; const float y = height/16;
//const float scale = Mth::Min( //const float scale = Mth::Min(
const float wh = Mth::Min((float)width/2.0f, (float)data->w / 2); const float wh = Mth::Min((float)width/2.0f, (float)data->w / 2);
const float scale = 2.0f * wh / (float)data->w; const float scale = 2.0f * wh / (float)data->w;
@@ -179,27 +179,35 @@ void StartMenuScreen::render( int xm, int ym, float a )
blit(0, height - 12, 0, 0, 43, 12, 256, 72+72); blit(0, height - 12, 0, 0, 43, 12, 256, 72+72);
#endif #endif
drawString(font, version, versionPosX, 62, /*50,*/ 0xffcccccc);//0x666666); drawString(font, version, width - font->width(version) - 2, height - 10, 0xffcccccc);//0x666666);
drawString(font, copyright, copyrightPosX, height - 10, 0xffffff); drawString(font, copyright, 2, height - 20, 0xffffff);
glEnable2(GL_BLEND);
glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f2(1, 1, 1, 1);
if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/github.png")))
blit(2, height - 10, 0, 0, 8, 8, 256, 256);
{
std::string txt = "Kolyah35/minecraft-pe-0.6.1";
float wtxt = font->width(txt);
Gui::drawColoredString(font, txt, 12, height - 10, 255);
// underline link
float y0 = height - 10 + font->lineHeight - 1;
this->fill(12, (int)y0, 12 + (int)wtxt, (int)(y0 + 1), 0xffffffff);
}
Screen::render(xm, ym, a); Screen::render(xm, ym, a);
} }
void StartMenuScreen::_updateLicense() void StartMenuScreen::mouseClicked(int x, int y, int buttonNum) {
{ const int logoX = 2;
int id = minecraft->getLicenseId(); const int logoW = 8 + 2 + font->width("Kolyah35/minecraft-pe-0.6.1");
if (LicenseCodes::isReady(id)) const int logoY = height - 10;
{ const int logoH = 10;
if (LicenseCodes::isOk(id)) if (x >= logoX && x <= logoX + logoW && y >= logoY && y <= logoY + logoH)
bJoin.active = bHost.active = bOptions.active = true; minecraft->platform()->openURL("https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1");
else else
{ Screen::mouseClicked(x, y, buttonNum);
bool hasBuyButton = minecraft->platform()->hasBuyButtonWhenInvalidLicense();
minecraft->setScreen(new InvalidLicenseScreen(id, hasBuyButton));
}
} else {
bJoin.active = bHost.active = bOptions.active = false;
}
} }
bool StartMenuScreen::handleBackEvent( bool isDown ) { bool StartMenuScreen::handleBackEvent( bool isDown ) {

View File

@@ -3,6 +3,7 @@
#include "../Screen.h" #include "../Screen.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/ImageButton.h"
class StartMenuScreen: public Screen class StartMenuScreen: public Screen
{ {
@@ -17,22 +18,23 @@ public:
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
void buttonClicked(Button* button); void buttonClicked(Button* button);
virtual void mouseClicked(int x, int y, int buttonNum);
bool handleBackEvent(bool isDown); bool handleBackEvent(bool isDown);
bool isInGameScreen(); bool isInGameScreen();
private: private:
void _updateLicense();
Button bHost; Button bHost;
Button bJoin; Button bJoin;
Button bOptions; Button bOptions;
Button bTest; ImageButton bQuit; // X button in top-right corner
Button bBuy;
std::string copyright; std::string copyright;
int copyrightPosX; int copyrightPosX;
std::string version; std::string version;
int versionPosX; int versionPosX;
std::string username;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__StartMenuScreen_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__StartMenuScreen_H__*/

View File

@@ -132,7 +132,7 @@ void TextEditScreen::keyPressed( int eventKey ) {
} }
} }
void TextEditScreen::keyboardNewChar( char inputChar ) { void TextEditScreen::charPressed( char inputChar ) {
std::string fullstring = sign->messages[line] + inputChar; std::string fullstring = sign->messages[line] + inputChar;
if(fullstring.length() < 16) { if(fullstring.length() < 16) {
sign->messages[line] = fullstring; sign->messages[line] = fullstring;

Some files were not shown because too many files have changed in this diff Show More