154 Commits

Author SHA1 Message Date
26e5376030 FIX: Crash when server is disaibling 2026-07-10 21:45:52 +02:00
d3d9b1a238 anticheat sucks xdxd 2026-07-10 00:59:26 +02:00
f0df3fe257 Server for windows wow 2026-07-10 00:46:36 +02:00
3ebed84cdb FIX: crash while joining to large world server 2026-07-02 16:32:17 +03:00
b73f7f121d ee 2026-05-12 21:29:17 +02:00
Kolyah35
5e19ef778e FIX: memset ._. 2026-05-12 22:12:52 +03:00
5bc19c4ab2 FEAT: Ban command, save ops and banned ppl in files
TODO: fix many crashes...
2026-05-09 16:37:11 +02:00
dfb3bf1da7 FIX: render
ty shredder
2026-05-09 14:41:31 +02:00
263118f2e0 Fix 2026-05-09 13:09:45 +02:00
1d0264a9c5 FEAT: World size 2026-05-09 01:45:19 +02:00
43f0d1f75f server config 2026-05-08 23:42:41 +02:00
70308d4151 qqqqqq 2026-05-05 21:55:03 +02:00
830549791a 121 2026-05-05 21:51:35 +02:00
27b22d8108 vegetables 2026-05-05 21:41:26 +02:00
4047fd71e1 oi 2026-05-05 21:36:35 +02:00
30dd344208 123 2026-05-05 21:33:28 +02:00
7e9de7a461 fck android build!!! 2026-05-05 21:19:08 +02:00
2465292473 jopa 2026-05-05 21:14:17 +02:00
26b2c196fa :\ 2026-05-05 21:09:42 +02:00
18793a6e05 idk? 2026-05-05 20:40:41 +02:00
Kolyah35
3e48c7fabd FIX: compilation 2026-05-02 21:31:48 +03:00
de72a9a3b7 all was broken :\ 2026-04-27 23:43:36 +02:00
0645905fc6 eeee it doesnt work 😭 2026-04-27 22:18:18 +02:00
Kolyah35
4023d70687 FEAT: server-side commands 2026-04-04 01:13:56 +03:00
Kolyah35
4dc7055d9d FIX: make antispeedhack working 2026-03-31 23:34:41 +03:00
Kolyah35
1ec347d5d5 FEAT: Server operators 2026-03-31 00:40:10 +03:00
Kolyah35
5194575092 FEAT: Meet the commands 2026-03-30 14:04:16 +03:00
3cfa2d9ee7 FIX IT AHTUNG AHTUNG ALL DOESNT WORK FIX IT FIX IT FIX IT FIX IT BIG WARNING BIG WARNING 2026-03-29 16:53:46 +02:00
f016f00eab idk?? 2026-03-29 00:16:19 +02:00
Kolyah35
470c28d83a I dont know what im doin please help 2026-03-29 00:36:36 +03:00
4363157cd9 Delete useless class 2026-03-28 21:08:52 +02:00
ba3ed3b4dd i dont see reason of this error 2026-03-28 18:37:02 +02:00
5783fb93f3 forgot to comment 2026-03-28 17:39:37 +02:00
73fb2a2b3d wtf 2026-03-28 17:18:38 +02:00
bcf48eb5e3 FEAT: Damage on server 2026-03-28 16:41:00 +02:00
Kolyah35
f5fecbc928 Merge remote-tracking branch 'refs/remotes/origin/dedicated-rewrite' into dedicated-rewrite 2026-03-27 22:15:26 +03:00
Kolyah35
77d02fcca2 FIX: workbench compatibility 2026-03-27 22:15:03 +03:00
6d696af235 FEAT: taken nickname 2026-03-27 21:08:17 +02:00
Kolyah35
370363f792 Merge remote-tracking branch 'refs/remotes/origin/dedicated-rewrite' into dedicated-rewrite 2026-03-27 21:26:48 +03:00
Kolyah35
61a2349b8b FEAT: Player data saving/loading 2026-03-27 21:26:25 +03:00
eed3a6df61 FEAT: Message for outdated clients 2026-03-27 20:22:05 +02:00
97b0fb4d46 FEAT: New proto check 2026-03-27 20:16:59 +02:00
8be842a8ac FEAT: player anticheat speed 2026-03-27 19:41:54 +02:00
6957f144e1 FIX: Inventory change when cheating items (TODO: Linked slots) 2026-03-27 17:05:50 +02:00
f9d9a0f0f9 FIX: Recheck recipes in MP 2026-03-27 13:47:33 +02:00
Kolyah35
28febb4e63 FIX: tool durablity mismatch 2026-03-27 14:01:49 +03:00
Kolyah35
aeef442f76 FIX: Server-side item remove when crafting 2026-03-27 04:02:27 +03:00
8098ab8906 easy 2026-03-27 02:48:56 +02:00
f0cb6d0b7c Fix compile errors 2026-03-27 02:42:34 +02:00
d1672c0ee2 Merge branch 'dedicated-rewrite' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 into dedicated-rewrite 2026-03-27 02:40:55 +02:00
c234abe3aa FIX: Item crafting 2026-03-27 02:40:52 +02:00
Kolyah35
e4ff7728af Merge remote-tracking branch 'refs/remotes/origin/dedicated-rewrite' into dedicated-rewrite 2026-03-27 03:34:29 +03:00
Kolyah35
41c5bdf243 FIX: The end of item cheating 2026-03-27 03:33:21 +03:00
96e8826f01 FEAT: Crafting on server 2026-03-27 02:14:28 +02:00
db8993683f Merge branch 'dedicated-rewrite' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 into dedicated-rewrite 2026-03-26 22:48:52 +02:00
2c1b5e256e change proto ver 2026-03-26 22:48:50 +02:00
Kolyah35
4beb5cb0f9 i think i fixed player equip 2026-03-26 23:32:09 +03:00
Kolyah35
cbd81b47ce ADD: EpikIzCool to credits 2026-03-24 17:32:52 +03:00
c146791845 Merge pull request 'Fix Whool and block variations n slabs n stuff' (#13) from EpikIzCool/minecraft-pe-0.6.1:main into main
Reviewed-on: https://192.168.0.2:3000/Kolyah35/minecraft-pe-0.6.1/pulls/13
2026-03-24 16:31:46 +02:00
a7c75d2ad2 Touch thingie 2026-03-24 00:29:52 +02:00
468ae4a211 Whool Fix part 1 2026-03-24 00:24:16 +02:00
9405e8daad FIXED: Scrolling with mouse wheel improved 2026-03-22 18:38:14 +01:00
bef09a3305 FIXED: sprinting now works when flying 2026-03-22 14:51:22 +01:00
Kolyah35
82f827af29 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-22 02:12:46 +03:00
Kolyah35
4f8b18b735 FIX: Now we're using useTouchsceen() right way!!!! 2026-03-22 02:12:04 +03:00
2acb57d051 revert all sht 2026-03-21 19:19:07 +02:00
5251085752 i broke all 2026-03-21 19:09:11 +02:00
a16f76f2b6 idk??? 2026-03-21 19:05:00 +02:00
b088f39e52 emm 2026-03-21 18:54:51 +02:00
13c624e07e hmmmmmmmmmm 2026-03-21 18:54:04 +02:00
2bfa8f11f1 hmm 2026-03-21 18:39:08 +02:00
98a05e5aa3 FIX: Keyboard on android 2026-03-21 18:25:42 +02:00
3f6d9cdcb8 FIX: Armor display 2026-03-21 18:10:46 +02:00
39186069cf Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-21 16:22:50 +02:00
b94c16b22a FIX: Bow release 2026-03-21 16:22:50 +02:00
Kolyah35
91ce365a26 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-21 17:20:18 +03:00
Kolyah35
f114536463 FIX: improve web port 2026-03-21 17:19:46 +03:00
6e0615c0bc FEAT: Auto jump in settings (again) 2026-03-21 16:03:51 +02:00
fd3ee23e4e Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-21 15:44:06 +02:00
e9766ed2a1 FEAT: Option button in PauseScreen 2026-03-21 15:44:05 +02:00
Kolyah35
298451c290 USE_LIBPNG when compile web 2026-03-21 15:28:50 +03:00
Kolyah35
668fc9d16f oh i forgot data 2026-03-21 15:25:18 +03:00
Kolyah35
5717aeab24 ADD: Web action 2026-03-21 15:23:37 +03:00
Kolyah35
9af1496b9d FIX: windows CI build 2026-03-21 15:04:50 +03:00
6bfae5a14e Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-21 13:43:29 +02:00
4034cf243d FIX: glfw crash when closing the game 2026-03-21 13:43:28 +02:00
b6e7414f04 Merge pull request 'fix msvc build & mingw build' (#10) from evildebugger/minecraft-pe-0.6.1:main into main
Reviewed-on: https://192.168.0.2:3000/Kolyah35/minecraft-pe-0.6.1/pulls/10
2026-03-21 12:48:51 +02:00
66hh
83f3284827 fix msvc build & mingw build
1. Include unified header files using lowercase filenames
2. Change special characters to escape sequences to solve encoding issues
2026-03-21 18:32:09 +08:00
Kolyah35
3dab395af3 fix workflow and im done 2026-03-21 02:45:06 +03:00
Kolyah35
011c8f7123 fix mingw build 2026-03-21 02:35:04 +03:00
Kolyah35
f69c009da9 replace pwd with workspace 2026-03-21 01:38:17 +03:00
Kolyah35
b66b4a2dc2 wtf im dumb 2026-03-21 01:35:40 +03:00
Kolyah35
7037b2b5f2 create build dir 2026-03-21 01:33:57 +03:00
Kolyah35
d54e39b332 -_- 2026-03-21 01:32:47 +03:00
Kolyah35
f96ba8bb33 ubuntu 22.04 2026-03-21 01:31:42 +03:00
Kolyah35
f0e1980f59 i dont like xwin anymore 2026-03-21 01:31:35 +03:00
52f607b126 Made some changes to the GUI scale slider.
Should be waaaaaaay better now
2026-03-20 23:20:37 +01:00
Kolyah35
84a956531c and here 2026-03-21 00:56:21 +03:00
Kolyah35
c4f5f22f24 disable module scan 2026-03-21 00:51:35 +03:00
Kolyah35
7867aea042 bruh 2026-03-21 00:43:57 +03:00
Kolyah35
a90e1463ee maybe try geode msvc sdk 2026-03-21 00:41:19 +03:00
Kolyah35
59e820e27f setup ninja 2026-03-21 00:33:59 +03:00
Kolyah35
1199f53632 -_- 2026-03-21 00:28:07 +03:00
Kolyah35
dc0e2c192b oh i forgot headers 2026-03-21 00:23:56 +03:00
Kolyah35
6ef9efa434 maybe ninja? 2026-03-21 00:17:53 +03:00
Kolyah35
72e6537dc5 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-21 00:15:24 +03:00
Kolyah35
0e2e7694d3 oops 2026-03-21 00:12:51 +03:00
45f04ca07b readme fix 2026-03-20 23:08:24 +02:00
42e7a3da90 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-20 23:00:36 +02:00
0edee15930 FEAT:Raspberry PI cursor in tweaks 2026-03-20 22:59:52 +02:00
753fdbe701 FIXED: support 64x32 + 64x64 skins with fallback for failed skin URL 2026-03-20 21:47:53 +01:00
ac60559a22 FIXED: Saving works on Android now!
I honestly changed too much stuff trying to pinpoint a fix. I might be stupid.
I have no idea what I did that fixed this.
2026-03-20 21:11:17 +01:00
Kolyah35
be6fa57a10 trying to speed up windows build 2026-03-20 23:07:27 +03:00
Kolyah35
68f5bc3a0a why zip only files inside data??? 2026-03-20 22:56:00 +03:00
Kolyah35
0a24a51663 uuuh 2026-03-20 22:43:49 +03:00
Kolyah35
96b17e9c8a tring to pack data with desktop releases 2026-03-20 22:26:26 +03:00
Kolyah35
c08c4d270d specify targets for linux 2026-03-20 22:17:20 +03:00
Kolyah35
8cd74922bf maybe remove that subdir from path? 2026-03-20 22:10:50 +03:00
Kolyah35
b2707cc35d yeah fix shit 2026-03-20 22:03:41 +03:00
Kolyah35
1ff91505d8 FIX: ndk and tools caching 2026-03-20 21:57:57 +03:00
Kolyah35
b909f3c576 EnumOption 2026-03-20 21:53:10 +03:00
Kolyah35
8d1c4f1c4e aaah who did revert my cmake changes 2026-03-20 21:50:45 +03:00
Kolyah35
bc5cbe6b73 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-20 21:47:46 +03:00
Kolyah35
cda2534c1e ADD: pause and chat btn 2026-03-20 21:46:43 +03:00
c54bdfdcff Target SDK lowered for compatibility
Setting it to 36 broke some permission things
Still seems like the game can't write anywhere even with r/w permissions...
2026-03-20 19:07:25 +01:00
d5b2c59ebf FIX: Cmake 2026-03-20 19:14:18 +02:00
Kolyah35
5d415dcca1 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-20 19:57:24 +03:00
Kolyah35
a317bf66af FIX: Increased save time 2026-03-20 19:57:00 +03:00
cb28b78776 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-20 18:43:33 +02:00
6a77ae3c64 FIX: Skins loading 2026-03-20 18:41:28 +02:00
c5fb648df7 FIXED: Android controls no longer tiny 2026-03-20 13:19:57 +01:00
a51f47a108 FIXED: Android 32bit build issues, expanded supported SDKs 2026-03-20 12:57:55 +01:00
017d908c54 armeabi-v7a building should work now.
./build.sh --abi arm64-v8a
./build.sh --abi armeabi-v7a

arm64-v8a is default.
2026-03-20 09:31:34 +01:00
70a45fb446 fixed apk not getting packaged 2026-03-20 09:35:47 +02:00
e0dac8a95c maybe manual caching will be better 2026-03-19 21:37:50 +02:00
1cd73cfc1e hmmmmmmmmmmmmmmmmmmmm... 2026-03-19 21:30:33 +02:00
c1fe428aa3 where are you hiding, r14b NDK 2026-03-19 21:25:44 +02:00
24d3b9488d improve Android build job with cached NDK script 2026-03-19 21:20:15 +02:00
f3f0918e77 SHITSHITSHIT 2026-03-19 20:39:30 +02:00
e190335abe Hopefully added Android building to the workflow
please work
2026-03-19 20:36:41 +02:00
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
155 changed files with 3868 additions and 2105 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-

17
.github/actions/setup-ninja/action.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Setup Ninja
description: Sets up Ninja
inputs:
host:
description: 'Host platform: win, mac or linux'
required: true
runs:
using: "composite"
steps:
- name: Setup
shell: bash
run: |
curl -L https://github.com/ninja-build/ninja/releases/latest/download/ninja-${{ inputs.host }}.zip -o ninja.zip
7z x ninja.zip -o"$GITHUB_WORKSPACE/ninja"
echo "$GITHUB_WORKSPACE/ninja" >> $GITHUB_PATH

View File

@@ -1,45 +0,0 @@
name: Android Build
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Android NDK r14b
id: ndk-cache
uses: actions/cache@v4
with:
path: C:\android-ndk-r14b
key: android-ndk-r14b
- name: Download Android NDK r14b
if: steps.ndk-cache.outputs.cache-hit != 'true'
shell: powershell
run: |
Invoke-WebRequest `
-Uri "http://dl.google.com/android/repository/android-ndk-r14b-windows-x86_64.zip" `
-OutFile "ndk.zip"
- name: Extract Android NDK
if: steps.ndk-cache.outputs.cache-hit != 'true'
shell: powershell
run: |
Expand-Archive ndk.zip C:\
- name: Verify NDK path
shell: powershell
run: |
Test-Path "C:\android-ndk-r14b"
- name: Run build script
shell: powershell
run: |
./build.ps1

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

@@ -0,0 +1,343 @@
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: Build Windows
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup caches
uses: ./.github/actions/setup-cache
with:
host: linux
target: win
- name: Setup Ninja
uses: ./.github/actions/setup-ninja
with:
host: linux
- name: Download llvm-mingw
run: |
curl -L https://github.com/mstorsjo/llvm-mingw/releases/download/20260311/llvm-mingw-20260311-msvcrt-ubuntu-22.04-x86_64.tar.xz -o llvm-mingw.tar.xz
tar -xf llvm-mingw.tar.xz
mv llvm-mingw-* llvm-mingw
- 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
working-directory: ${{github.workspace}}/build
run: |
cmake $GITHUB_WORKSPACE \
-G Ninja \
-DCMAKE_SYSTEM_NAME=Windows \
-DCMAKE_C_COMPILER=$GITHUB_WORKSPACE/llvm-mingw/bin/x86_64-w64-mingw32-clang \
-DCMAKE_CXX_COMPILER=$GITHUB_WORKSPACE/llvm-mingw/bin/x86_64-w64-mingw32-clang++ \
-DCMAKE_RC_COMPILER=$GITHUB_WORKSPACE/llvm-mingw/bin/x86_64-w64-mingw32-windres \
-DALSOFT_BACKEND_PIPEWIRE=OFF \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE
- name: Build
working-directory: ${{github.workspace}}/build
run: cmake --build . --config $BUILD_TYPE --target MinecraftPE --parallel
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: mcpe-windows
path: |
${{github.workspace}}/build/MinecraftPE.exe
${{github.workspace}}/build/libpng16.dll
${{github.workspace}}/build/OpenAL32.dll
${{github.workspace}}/build/libz.dll
build-linux:
name: Build Linux
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 --target MinecraftPE --parallel
cmake --build . --config $BUILD_TYPE --target MinecraftPE-server --parallel
- 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 (${{ matrix.abi }})
runs-on: ubuntu-latest
strategy:
# keep going with the other ABI if one fails so you at least get something useful
fail-fast: false
matrix:
abi: [ arm64-v8a, armeabi-v7a ]
env:
ANDROID_SDK_ROOT: ${{ github.workspace }}/android-sdk
ANDROID_NDK_PATH: ${{ github.workspace }}/android-ndk-r14b
ANDROID_PLATFORM_API: 36
ANDROID_BUILD_TOOLS_VERSION: 36.0.0
ADB: /bin/true
# build.sh reads MATRIX_ABI to decide which ABI to build when no --abi flag is passed
MATRIX_ABI: ${{ matrix.abi }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Cache Android command-line tools
id: cache-android-tools
uses: actions/cache@v3
with:
path: ${{ env.ANDROID_SDK_ROOT }}
key: android-cmdline-tools-v36
- name: Setup Android command line tools
if: steps.cache-android-tools.outputs.cache-hit != 'true'
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
id: cache-android-ndk
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/android-ndk-r14b
key: android-ndk-r14b
- name: Install Android NDK r14b
if: steps.cache-android-ndk.outputs.cache-hit != 'true'
run: |
if [ ! -d "$ANDROID_NDK_PATH" ]; 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
- 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"
echo "MATRIX_ABI=$MATRIX_ABI"
$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:
# artifact name is ABI-specific so both matrix legs can upload without clobbering each other
name: minecraftpe-apk-${{ matrix.abi }}
path: ${{ github.workspace }}/build-apk/minecraftpe-*-debug.apk
build-web:
name: Build Web
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup caches
uses: ./.github/actions/setup-cache
with:
host: linux
target: linux
- name: Setup Ninja
uses: ./.github/actions/setup-ninja
with:
host: linux
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v14
with:
version: 5.0.3
actions-cache-folder: 'emsdk-cache'
- 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
# 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 -G Ninja -DCMAKE_TOOLCHAIN_FILE="$GITHUB_WORKSPACE/emsdk-cache/emsdk-main/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
- name: Build
working-directory: ${{github.workspace}}/build
run: cmake --build . --config $BUILD_TYPE --target MinecraftPE --parallel
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: mcpe-web
path: |
${{github.workspace}}/build/MinecraftPE.js
${{github.workspace}}/build/MinecraftPE.wasm
${{github.workspace}}/build/MinecraftPE.data
publish:
name: Publish
runs-on: ubuntu-latest
needs: [ build-windows, build-linux, build-android, build-web ]
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: mcpe-windows/MinecraftPE.exe mcpe-windows/libpng16.dll mcpe-windows/OpenAL32.dll mcpe-windows/libz.dll
dest: minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip
- name: Zip Linux Artifacts
uses: vimtor/action-zip@v1.2
with:
files: mcpe-linux/MinecraftPE
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 arm64-v8a Artifact
uses: vimtor/action-zip@v1.2
with:
files: minecraftpe-apk-arm64-v8a/minecraftpe-v8a-debug.apk
dest: minecraftpe-${{ steps.ref.outputs.hash }}-android-arm64-v8a.zip
- name: Zip Android armeabi-v7a Artifact
uses: vimtor/action-zip@v1.2
with:
files: minecraftpe-apk-armeabi-v7a/minecraftpe-v7a-debug.apk
dest: minecraftpe-${{ steps.ref.outputs.hash }}-android-armeabi-v7a.zip
- name: Zip Web Artifact
uses: vimtor/action-zip@v1.2
with:
files: mcpe-web/MinecraftPE.js mcpe-web/MinecraftPE.wasm mcpe-web/MinecraftPE.data misc/web/index.html
dest: minecraftpe-${{ steps.ref.outputs.hash }}-web.zip
- name: Zip Data
uses: vimtor/action-zip@v1.2
with:
files: data
recursive: false
dest: data.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: |
./data.zip
./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-arm64-v8a.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-android-armeabi-v7a.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-web.zip

View File

@@ -1,75 +0,0 @@
name: CMake multiplatform
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: write
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
build_type: [Release]
include:
- os: windows-latest
c_compiler: clang
cpp_compiler: clang++
- os: ubuntu-latest
c_compiler: clang
cpp_compiler: clang++
steps:
- uses: actions/checkout@v4
- name: Set reusable strings
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Setup Environment
if: ${{ matrix.os == 'ubuntu-latest' }}
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
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-S ${{ github.workspace }}
- name: Build
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
- name: Install
run: cmake --install ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
- name: Pack
run: |
cd ${{ steps.strings.outputs.build-output-dir }}
cpack -C ${{ matrix.build_type }}
- name: Create or Update Development Release
uses: softprops/action-gh-release@v1
with:
name: Development Build
tag_name: dev
body: |
${{ github.event.head_commit.timestamp }}
draft: false
prerelease: true
generate_release_notes: false
files: 'build/package/*.zip'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View File

@@ -9,8 +9,6 @@ CMakeFiles/
CMakeCache.txt CMakeCache.txt
cmake_install.cmake cmake_install.cmake
Makefile Makefile
*.cmake
!cmake/CPM.cmake
# Compiled object files # Compiled object files
*.o *.o

View File

@@ -6,21 +6,49 @@ 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_POLICY_VERSION_MINIMUM 3.10) 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") include(cmake/EnumOption.cmake)
if(EMSCRIPTEN)
# When configuring web builds with "emcmake cmake -B build -S .", set PLATFORM to Web by default
set(PLATFORM Web CACHE STRING "Platform to build for.")
endif() endif()
enum_option(PLATFORM "Desktop;Web" "Platform to build for.")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(OpenSSL) find_package(OpenSSL)
if(EMSCRIPTEN) if (${PLATFORM} STREQUAL "Desktop")
set(AL_LIBTYPE "STATIC") set(PLATFORM_CPP "PLATFORM_DESKTOP")
else()
set(AL_LIBTYPE "SHARED") if (MINGW)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-narrowing -Wno-narrowing -Wno-invalid-source-encoding -Wno-reserved-user-defined-literal")
endif()
if (WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
include_directories(misc/windows)
set(EXTRA_LIBS ws2_32 winhttp)
elseif(UNIX)
find_library(pthread NAMES pthread)
set(EXTRA_LIBS pthread m)
endif()
elseif (${PLATFORM} STREQUAL "Web")
set(PLATFORM_CPP "PLATFORM_WEB")
set(EXTRA_LIBS "idbfs.js")
endif() endif()
# I totally shocked # I totally shocked
if(EMSCRIPTEN) if(${PLATFORM} MATCHES "Web")
set(PNG_LIB png)
set(AL_LIBTYPE "STATIC")
add_library(zlib INTERFACE IMPORTED) add_library(zlib INTERFACE IMPORTED)
set_target_properties(zlib PROPERTIES set_target_properties(zlib PROPERTIES
INTERFACE_LINK_OPTIONS "-sUSE_ZLIB=1" INTERFACE_LINK_OPTIONS "-sUSE_ZLIB=1"
@@ -28,6 +56,7 @@ if(EMSCRIPTEN)
add_library(png INTERFACE IMPORTED) add_library(png INTERFACE IMPORTED)
set_target_properties(png PROPERTIES set_target_properties(png PROPERTIES
INTERFACE_COMPILE_OPTIONS "-sUSE_LIBPNG=1"
INTERFACE_LINK_OPTIONS "-sUSE_LIBPNG=1" INTERFACE_LINK_OPTIONS "-sUSE_LIBPNG=1"
) )
@@ -36,6 +65,9 @@ if(EMSCRIPTEN)
INTERFACE_LINK_OPTIONS "-sUSE_GLFW=3" INTERFACE_LINK_OPTIONS "-sUSE_GLFW=3"
) )
else() else()
set(PNG_LIB png_shared)
set(AL_LIBTYPE "SHARED")
CPMAddPackage( CPMAddPackage(
NAME "zlib" NAME "zlib"
GIT_REPOSITORY "https://github.com/madler/zlib" GIT_REPOSITORY "https://github.com/madler/zlib"
@@ -74,9 +106,11 @@ CPMAddPackage(
"ALSOFT_TESTS OFF" "ALSOFT_TESTS OFF"
"ALSOFT_UTILS OFF" "ALSOFT_UTILS OFF"
"LIBTYPE ${AL_LIBTYPE}" "LIBTYPE ${AL_LIBTYPE}"
"ALSOFT_ENABLE_MODULES OFF"
"ALSOFT_STATIC_STDCXX ON"
"ALSOFT_STATIC_LIBGCC ON"
) )
# TODO: Clear this paths with *
file(GLOB SERVER_SOURCES file(GLOB SERVER_SOURCES
"project/lib_projects/raknet/jni/RaknetSources/*.cpp" "project/lib_projects/raknet/jni/RaknetSources/*.cpp"
"src/NinecraftApp.cpp" "src/NinecraftApp.cpp"
@@ -115,7 +149,6 @@ file(GLOB SERVER_SOURCES
"src/platform/CThread.cpp" "src/platform/CThread.cpp"
"src/platform/HttpClient.cpp" "src/platform/HttpClient.cpp"
"src/platform/PngLoader.cpp"
"src/platform/time.cpp" "src/platform/time.cpp"
"src/platform/input/Controller.cpp" "src/platform/input/Controller.cpp"
@@ -177,6 +210,7 @@ file(GLOB SERVER_SOURCES
"src/world/level/tile/entity/*.cpp" "src/world/level/tile/entity/*.cpp"
"src/world/phys/HitResult.cpp" "src/world/phys/HitResult.cpp"
"src/commands/*.cpp"
) )
file(GLOB CLIENT_SOURCES file(GLOB CLIENT_SOURCES
@@ -255,27 +289,18 @@ file(GLOB CLIENT_SOURCES
"src/SharedConstants.cpp" "src/SharedConstants.cpp"
"src/main.cpp" "src/main.cpp"
"src/NinecraftApp.cpp" "src/NinecraftApp.cpp"
"src/AppPlatform_glfw.cpp"
"src/main.cpp"
"src/commands/*.cpp"
) )
if(NOT DEFINED PLATFORM) if (${PLATFORM} STREQUAL "Desktop")
set(PLATFORM "PLATFORM_GLFW") list(APPEND CLIENT_SOURCES glad/src/glad.c)
endif()
if(PLATFORM STREQUAL "PLATFORM_WIN32")
list(APPEND CLIENT_SOURCES "src/AppPlatform_win32.cpp" "glad/src/glad.c")
endif()
if(PLATFORM STREQUAL "PLATFORM_GLFW")
list(APPEND CLIENT_SOURCES "src/AppPlatform_glfw.cpp" "glad/src/glad.c")
endif()
if(EMSCRIPTEN)
list(APPEND CLIENT_SOURCES "glad/src/glad.c")
endif() endif()
# Server # Server
if(UNIX)
add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES}) add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES})
target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER") target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER")
@@ -286,18 +311,10 @@ target_include_directories("${PROJECT_NAME}-server" PUBLIC
) )
target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT})
endif()
add_executable(${PROJECT_NAME} ${CLIENT_SOURCES}) add_executable(${PROJECT_NAME} ${CLIENT_SOURCES})
if(WIN32) target_compile_definitions(${PROJECT_NAME} PUBLIC ${PLATFORM_CPP})
set(EXTRA_LIBS "ws2_32")
target_compile_definitions(${PROJECT_NAME} PUBLIC "_CRT_SECURE_NO_WARNINGS")
endif()
if(PLATFORM STREQUAL "PLATFORM_WIN32" OR PLATFORM STREQUAL "PLATFORM_GLFW")
target_compile_definitions(${PROJECT_NAME} PUBLIC "PLATFORM_DESKTOP")
endif()
target_include_directories(${PROJECT_NAME} PUBLIC target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_SOURCE_DIR}/glad/include/" "${CMAKE_SOURCE_DIR}/glad/include/"
@@ -307,14 +324,14 @@ target_include_directories(${PROJECT_NAME} PUBLIC
"lib/include" "lib/include"
) )
if(EMSCRIPTEN) if(${PLATFORM} MATCHES "Web")
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
# uuuh i hate it # uuuh i hate it
set(EM_FLAGS "-pthread -sUSE_PTHREADS=1 -sSHARED_MEMORY=1") set(EM_FLAGS "-pthread -sUSE_PTHREADS=1 -sUSE_LIBPNG=1 -sSHARED_MEMORY=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EM_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EM_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_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") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EM_FLAGS} --preload-file ${CMAKE_SOURCE_DIR}/data@/data")
target_compile_options(${PROJECT_NAME} PUBLIC target_compile_options(${PROJECT_NAME} PUBLIC
"-Os" "-Os"
@@ -348,12 +365,11 @@ if(EMSCRIPTEN)
endif() endif()
target_compile_definitions(${PROJECT_NAME} PUBLIC "__EMSCRIPTEN__" "NO_SOUND" "NO_NETWORK") target_compile_definitions(${PROJECT_NAME} PUBLIC "__EMSCRIPTEN__" "NO_SOUND" "NO_NETWORK")
set(EXTRA_LIBS "idbfs.js")
endif() endif()
# Client # Client
target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM}) target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM})
target_link_libraries(${PROJECT_NAME} zlib png alsoft.common OpenAL::OpenAL glfw ${EXTRA_LIBS}) target_link_libraries(${PROJECT_NAME} zlib ${PNG_LIB} OpenAL::OpenAL glfw ${EXTRA_LIBS})
if (OpenSSL_FOUND) if (OpenSSL_FOUND)
target_link_libraries(${PROJECT_NAME} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(${PROJECT_NAME} OpenSSL::SSL OpenSSL::Crypto)
@@ -369,7 +385,7 @@ if (NOT UNIX)
) )
endif() endif()
if(NOT EMSCRIPTEN) if(NOT ${PLATFORM} MATCHES "Web")
add_custom_command( add_custom_command(
TARGET ${PROJECT_NAME} TARGET ${PROJECT_NAME}
POST_BUILD POST_BUILD
@@ -383,58 +399,5 @@ else()
) )
endif() endif()
# Installing and packing message(STATUS "Compiling with the flags:")
message(STATUS " PLATFORM=" ${PLATFORM_CPP})
find_package(Git REQUIRED)
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_SHORTSHA
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME)
set(CPACK_PACKAGE_NAME "MCPE-0.6.1-for-all")
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${SYSTEM_NAME})
set(CPACK_PACKAGE_VENDOR "MCPE-0.6.1-for-all")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/package")
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install")
set(CPACK_GENERATOR "ZIP")
set(GIT_REPO "https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1")
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION .)
if(NOT UNIX)
install(FILES
$<TARGET_RUNTIME_DLLS:${PROJECT_NAME}>
DESTINATION .
)
endif()
install(DIRECTORY "${CMAKE_SOURCE_DIR}/data" DESTINATION .)
string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
string(TIMESTAMP CURRENT_TIME "%H:%M:%S")
set(VERSION_STR "${PROJECT_VERSION}")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(VERSION_STR "${VERSION_STR} - Development Build")
endif()
file(WRITE "${CMAKE_BINARY_DIR}/version.txt"
"Minecraft PE 0.6.1
Autogenerated file by cmake-${CMAKE_VERSION}
Report issues ${GIT_REPO}/issues
Build date: ${CURRENT_DATE} ${CURRENT_TIME}
Build configuration: ${CMAKE_BUILD_TYPE}
Git commit: ${GIT_SHORTSHA}
Platform: ${CMAKE_SYSTEM_NAME}")
install(FILES "${CMAKE_BINARY_DIR}/version.txt" DESTINATION .)
include(CPack)

View File

@@ -113,7 +113,7 @@ cmake --build .
$HOME/Android/Sdk/cmdline-tools/bin/sdkmanager $HOME/Android/Sdk/cmdline-tools/bin/sdkmanager
``` ```
> [!NOTE] > [!Note]
> `sdkmanager` expects the SDK to include a `cmdline-tools/latest/` folder. > `sdkmanager` expects the SDK to include a `cmdline-tools/latest/` folder.
> If you only have `cmdline-tools/bin`, create the required layout: > If you only have `cmdline-tools/bin`, create the required layout:
> >
@@ -134,7 +134,7 @@ cmake --build .
sdkmanager --install "platform-tools" "platforms;android-35" "build-tools;35.0.0" sdkmanager --install "platform-tools" "platforms;android-35" "build-tools;35.0.0"
``` ```
> [!NOTE] > [!Note]
> if you want build.sh to always find the SDK, > 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: > Set ANDROID_SDK_ROOT in your shell config (~/.bashrc / ~/.profile / ~/.config/fish/config.fish), for example:
> >
@@ -162,14 +162,14 @@ cmake --build .
7. Extract the archive to `/home/username/`, so that the final directory path is `/home/username/android-ndk-r14b/` 7. Extract the archive to `/home/username/`, so that the final directory path is `/home/username/android-ndk-r14b/`
> [!WARNING] > [!Warning]
> Make sure you dont end up with a nested folder like `/home/username/android-ndk-r14b/android-ndk-r14b/`. > Make sure you dont end up with a nested folder like `/home/username/android-ndk-r14b/android-ndk-r14b/`.
8. Re run `build.sh` 8. Re run `build.sh`
## Web ## Web
1. Download and install **emsdk**: https://emscripten.org/docs/getting_started/downloads.html 1. Download and install **emsdk**: https://emscripten.org/docs/getting_started/downloads.html
> [!NOTE] > [!Note]
> On arch linux you can use AUR: > On arch linux you can use AUR:
> `yay -Sy emsdk` > `yay -Sy emsdk`
@@ -179,7 +179,7 @@ cmake --build .
cmake .. -B . -G Ninja "-DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" cmake .. -B . -G Ninja "-DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
cmake --build . --target MinecraftPE cmake --build . --target MinecraftPE
``` ```
> [!NOTE] > [!Note]
> If you are using VSCode with CMake plugin, you can add Emscripten kit > If you are using VSCode with CMake plugin, you can add Emscripten kit
> 1. Press Ctrl + Shift + P > 1. Press Ctrl + Shift + P
> 2. Type `CMake: Edit User-Local CMake Kits` and hit Enter > 2. Type `CMake: Edit User-Local CMake Kits` and hit Enter

108
build.sh
View File

@@ -5,6 +5,11 @@
# ./build.sh --no-cpp # skip NDK rebuild (Java/assets changed) # ./build.sh --no-cpp # skip NDK rebuild (Java/assets changed)
# ./build.sh --no-java # skip Java recompile (C++ changed only) # ./build.sh --no-java # skip Java recompile (C++ changed only)
# ./build.sh --no-build # repackage + install only (no recompile) # ./build.sh --no-build # repackage + install only (no recompile)
#
# ABI targeting:
# ./build.sh --abi arm64-v8a # build for arm64 only (default)
# ./build.sh --abi armeabi-v7a # build for ARMv7 only
# ./build.sh --abi all # build for both ABIs (fat APK)
# ============================================================ # ============================================================
# lets be strict cuz we are safe like that # lets be strict cuz we are safe like that
@@ -28,6 +33,11 @@ ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-$HOME/Android/Sdk}}"
ANDROID_BUILD_TOOLS_VERSION="${ANDROID_BUILD_TOOLS_VERSION:-}" ANDROID_BUILD_TOOLS_VERSION="${ANDROID_BUILD_TOOLS_VERSION:-}"
ANDROID_PLATFORM_API="${ANDROID_PLATFORM_API:-}" ANDROID_PLATFORM_API="${ANDROID_PLATFORM_API:-}"
# ABI selection: can be set via --abi flag or MATRIX_ABI env var.
# Supported values: arm64-v8a, armeabi-v7a, all
# MATRIX_ABI takes precedence over the default but is overridden by --abi on the CLI.
TARGET_ABI="${MATRIX_ABI:-arm64-v8a}"
function fail() { function fail() {
echo "ERROR: $1" >&2 echo "ERROR: $1" >&2
exit 1 exit 1
@@ -114,10 +124,11 @@ ANDROID_MANIFEST="$REPO_ROOT/project/android_java/AndroidManifest.xml"
ANDROID_RES_DIR="$REPO_ROOT/project/android_java/res" ANDROID_RES_DIR="$REPO_ROOT/project/android_java/res"
DATA_DIR="$REPO_ROOT/data" DATA_DIR="$REPO_ROOT/data"
# output files # output files: APK names are derived after argument parsing once TARGET_ABI is final.
APK_UNSIGNED="$BUILD_DIR/minecraftpe-unsigned.apk" # see the "resolve APK output filenames" block below.
APK_ALIGNED="$BUILD_DIR/minecraftpe-aligned.apk" APK_UNSIGNED=""
APK_SIGNED="$BUILD_DIR/minecraftpe-debug.apk" APK_ALIGNED=""
APK_SIGNED=""
DEX_OUTPUT="$BUILD_DIR/classes.dex" DEX_OUTPUT="$BUILD_DIR/classes.dex"
# flags parsed from CLI args # flags parsed from CLI args
@@ -130,12 +141,14 @@ NO_BUILD=false
######################################## ########################################
function usage() { function usage() {
cat <<EOF cat <<EOF
Usage: $0 [--no-cpp] [--no-java] [--no-build] Usage: $0 [--no-cpp] [--no-java] [--no-build] [--abi <abi>]
Options: Options:
--no-cpp Skip the NDK (C++) build step --no-cpp Skip the NDK (C++) build step
--no-java Skip the Java build step --no-java Skip the Java build step
--no-build Skip the compile steps; just package + install --no-build Skip the compile steps; just package + install
--abi <abi> Target ABI: arm64-v8a (default), armeabi-v7a, or all
Can also be set via MATRIX_ABI env var for CI matrix builds.
EOF EOF
exit 1 exit 1
} }
@@ -196,6 +209,33 @@ function write_stub_file() {
fi fi
} }
function build_ndk_abi() {
local abi="$1"
# armeabi-v7a needs a few extra NDK flags to get hardware FPU support
# without APP_ABI the default would be whatever Android.mk says, so we
# always pass it explicitly so the same Android.mk works for both targets
local -a extra_flags=( "APP_ABI=$abi" )
if [[ "$abi" == "armeabi-v7a" ]]; then
# enable hardware FPU + NEON like the old Minecraft ARMv7 builds used to
extra_flags+=( "APP_ARM_MODE=arm" "APP_ARM_NEON=true" )
fi
echo " ndk-build for $abi..."
if ! "$ANDROID_NDK_PATH/ndk-build" \
NDK_PROJECT_PATH="$REPO_ROOT/project/android" \
APP_BUILD_SCRIPT="$JNI_DIR/Android.mk" \
"${extra_flags[@]}" \
2>&1 | tee "$BUILD_DIR/ndk-build-${abi}.log"; then
echo "NDK build failed for $abi. See $BUILD_DIR/ndk-build-${abi}.log" >&2
exit 1
fi
ensure_dir "$BUILD_DIR/lib/$abi"
cp -v "$REPO_ROOT/project/android/libs/$abi/libminecraftpe.so" "$BUILD_DIR/lib/$abi/"
echo " .so -> $BUILD_DIR/lib/$abi/libminecraftpe.so"
}
######################################## ########################################
# argument parsing # argument parsing
######################################## ########################################
@@ -204,6 +244,11 @@ while [[ $# -gt 0 ]]; do
--no-cpp) NO_CPP=true ;; --no-cpp) NO_CPP=true ;;
--no-java) NO_JAVA=true ;; --no-java) NO_JAVA=true ;;
--no-build) NO_BUILD=true ;; --no-build) NO_BUILD=true ;;
--abi)
shift
[[ $# -gt 0 ]] || fail "--abi requires a value (arm64-v8a, armeabi-v7a, all)"
TARGET_ABI="$1"
;;
-h|--help) usage ;; -h|--help) usage ;;
*) *)
echo "Unknown option: $1" >&2 echo "Unknown option: $1" >&2
@@ -213,6 +258,27 @@ while [[ $# -gt 0 ]]; do
shift shift
done done
# validate the ABI value now that all args are parsed
case "$TARGET_ABI" in
arm64-v8a|armeabi-v7a|all) ;;
*) fail "Unknown ABI '$TARGET_ABI'. Supported values: arm64-v8a, armeabi-v7a, all" ;;
esac
echo " TARGET_ABI=$TARGET_ABI"
# resolve APK output filenames now that TARGET_ABI is final.
# arm64-v8a -> minecraftpe-v8a-debug.apk
# armeabi-v7a -> minecraftpe-v7a-debug.apk
# all -> minecraftpe-all-debug.apk (fat APK containing both ABIs)
case "$TARGET_ABI" in
arm64-v8a) APK_SUFFIX="v8a" ;;
armeabi-v7a) APK_SUFFIX="v7a" ;;
*) APK_SUFFIX="$TARGET_ABI" ;;
esac
APK_UNSIGNED="$BUILD_DIR/minecraftpe-${APK_SUFFIX}-unsigned.apk"
APK_ALIGNED="$BUILD_DIR/minecraftpe-${APK_SUFFIX}-aligned.apk"
APK_SIGNED="$BUILD_DIR/minecraftpe-${APK_SUFFIX}-debug.apk"
######################################## ########################################
# validate required tools # validate required tools
######################################## ########################################
@@ -245,6 +311,7 @@ log_step "Bootstrap"
ensure_dir "$BUILD_DIR" ensure_dir "$BUILD_DIR"
ensure_dir "$BUILD_DIR/lib/arm64-v8a" ensure_dir "$BUILD_DIR/lib/arm64-v8a"
ensure_dir "$BUILD_DIR/lib/armeabi-v7a"
ensure_dir "$BUILD_DIR/gen" ensure_dir "$BUILD_DIR/gen"
ensure_dir "$BUILD_DIR/stubs" ensure_dir "$BUILD_DIR/stubs"
@@ -283,7 +350,7 @@ echo " stubs OK"
# ndk build # ndk build
######################################## ########################################
if [[ "$NO_CPP" == false && "$NO_BUILD" == false ]]; then if [[ "$NO_CPP" == false && "$NO_BUILD" == false ]]; then
log_step "NDK build (arm64-v8a)" log_step "NDK build ($TARGET_ABI)"
# the original windows build script used a junction to avoid long paths here # 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 # on linux, path lengths are *usually* fine, but we still keep things simple
@@ -291,18 +358,15 @@ if [[ "$NO_CPP" == false && "$NO_BUILD" == false ]]; then
export NDK_MODULE_PATH="$REPO_ROOT/project/lib_projects" export NDK_MODULE_PATH="$REPO_ROOT/project/lib_projects"
# run ndk-build and show output in case of failure # build each requested ABI by delegating to build_ndk_abi()
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 if [[ "$TARGET_ABI" == "all" ]]; then
echo "NDK build failed. See $BUILD_DIR/ndk-build.log" >&2 build_ndk_abi "arm64-v8a"
exit 1 build_ndk_abi "armeabi-v7a"
else
build_ndk_abi "$TARGET_ABI"
fi fi
popd >/dev/null 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 fi
######################################## ########################################
@@ -327,7 +391,7 @@ if [[ "$NO_JAVA" == false && "$NO_BUILD" == false ]]; then
rm -rf "$BUILD_DIR/classes" rm -rf "$BUILD_DIR/classes"
ensure_dir "$BUILD_DIR/classes" ensure_dir "$BUILD_DIR/classes"
# Some JDK versions (<=8) dont support --release. # Some JDK versions (<=8) don't support --release.
JAVAC_ARGS=(--release 8) JAVAC_ARGS=(--release 8)
if "$JAVAC_CMD" -version 2>&1 | grep -qE '^javac 1\.'; then if "$JAVAC_CMD" -version 2>&1 | grep -qE '^javac 1\.'; then
JAVAC_ARGS=(-source 1.8 -target 1.8) JAVAC_ARGS=(-source 1.8 -target 1.8)
@@ -351,10 +415,18 @@ 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" "$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 # add classes.dex and native library/libraries into apk.
# when building for "all" we pack both ABIs into the same APK so Android can
# pick the right one at install time (fat APK). for a single-ABI build we
# only include the one .so that was actually compiled.
pushd "$BUILD_DIR" >/dev/null pushd "$BUILD_DIR" >/dev/null
zip -q "$APK_UNSIGNED" "classes.dex" zip -q "$APK_UNSIGNED" "classes.dex"
zip -q "$APK_UNSIGNED" "lib/arm64-v8a/libminecraftpe.so" if [[ "$TARGET_ABI" == "all" ]]; then
zip -q "$APK_UNSIGNED" "lib/arm64-v8a/libminecraftpe.so"
zip -q "$APK_UNSIGNED" "lib/armeabi-v7a/libminecraftpe.so"
else
zip -q "$APK_UNSIGNED" "lib/$TARGET_ABI/libminecraftpe.so"
fi
popd >/dev/null popd >/dev/null
# add assets from data/ directory into the apk under assets/ # add assets from data/ directory into the apk under assets/

9
cmake/EnumOption.cmake Normal file
View File

@@ -0,0 +1,9 @@
macro(enum_option var values description)
set(${var}_VALUES ${values})
list(GET ${var}_VALUES 0 default)
set(${var} "${default}" CACHE STRING "${description}")
set_property(CACHE ${var} PROPERTY STRINGS ${${var}_VALUES})
if (NOT ";${${var}_VALUES};" MATCHES ";${${var}};")
message(FATAL_ERROR "Unknown value ${${var}}. Only -D${var}=${${var}_VALUES} allowed.")
endif()
endmacro()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

@@ -152,7 +152,8 @@ options.group.graphics=Graphics
options.group.tweaks=Tweaks options.group.tweaks=Tweaks
options.allowSprint=Allow sprint options.allowSprint=Allow sprint
options.barOnTop=HUD above inventory options.barOnTop=HUD above inventory
options.autojump=Auto Jump options.rpiCursor=Show Raspberry PI cursor
options.autoJump=Auto Jump
options.thirdperson=Third Person options.thirdperson=Third Person
options.servervisible=Server Visible options.servervisible=Server Visible
options.sensitivity=Sensitivity options.sensitivity=Sensitivity
@@ -181,9 +182,10 @@ options.graphics.fast=Fast
options.guiScale=GUI Scale options.guiScale=GUI Scale
options.guiScale.auto=Auto options.guiScale.auto=Auto
options.guiScale.small=Small options.guiScale.small=Small
options.guiScale.normal=Normal options.guiScale.medium=Medium
options.guiScale.large=Large options.guiScale.large=Large
options.guiScale.larger=Larger options.guiScale.larger=Larger
options.guiScale.largest=Largest
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,143 +1,46 @@
<!doctype html> <!DOCTYPE html>
<html lang="en-us"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>MCPE 0.6.1</title>
<title>Emscripten-Generated Code</title>
<style> <style>
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } html, body {
textarea.emscripten { font-family: monospace; width: 80%; } margin: 0;
div.emscripten { text-align: center; } padding: 0;
div.emscripten_border { border: 1px solid black; } height: 100%;
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */ background: black;
canvas.emscripten { border: 0px none; background-color: black; } overflow: hidden;
.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);}
} }
#canvas {
width: 100vw;
height: 100vh;
display: block;
}
</style> </style>
</head> </head>
<body> <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/> <canvas id="canvas"></canvas>
<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;
}
<script>
var Module = { var Module = {
print(...args) { canvas: document.getElementById('canvas'),
// These replacements are necessary if you render to raw HTML onRuntimeInitialized: function () { resizeCanvas() }
//text = text.replace(/&/g, "&amp;"); };
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;"); function resizeCanvas() {
//text = text.replace('\n', '<br>', 'g'); const canvas = Module.canvas;
console.log(...args); canvas.width = window.innerWidth;
if (outputElement) { canvas.height = window.innerHeight;
var text = args.join(' ');
outputElement.value += text + "\n";
outputElement.scrollTop = outputElement.scrollHeight; // focus on bottom
} }
},
canvas: canvasElement, window.addEventListener('resize', resizeCanvas);
setStatus: setStatus, window.addEventListener('onunload', () => {
totalDependencies: 0, FS.syncfs(true, function (err) { console.log('Sync FS failed: ' + err) });
monitorRunDependencies(left) { })
this.totalDependencies = Math.max(this.totalDependencies, left); </script>
setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
} <script src="MinecraftPE.js"></script>
}; </body>
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> </html>

View File

@@ -6,8 +6,8 @@
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="24" <uses-sdk android:minSdkVersion="19"
android:targetSdkVersion="24" /> android:targetSdkVersion="30" />
<!-- uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="true"/ --> <!-- uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="true"/ -->

View File

@@ -168,9 +168,10 @@ options.graphics.fast=Fast
options.guiScale=GUI Scale options.guiScale=GUI Scale
options.guiScale.auto=Auto options.guiScale.auto=Auto
options.guiScale.small=Small options.guiScale.small=Small
options.guiScale.normal=Normal options.guiScale.medium=Medium
options.guiScale.large=Large options.guiScale.large=Large
options.guiScale.larger=Larger options.guiScale.larger=Larger
options.guiScale.largest=Largest
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

@@ -109,6 +109,7 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/client/renderer/Textures.cpp \ ../../../src/client/renderer/Textures.cpp \
../../../src/client/renderer/TileRenderer.cpp \ ../../../src/client/renderer/TileRenderer.cpp \
../../../src/client/renderer/gles.cpp \ ../../../src/client/renderer/gles.cpp \
../../../src/world/level/LevelConstants.cpp \
../../../src/client/renderer/culling/Frustum.cpp \ ../../../src/client/renderer/culling/Frustum.cpp \
../../../src/client/renderer/entity/ArrowRenderer.cpp \ ../../../src/client/renderer/entity/ArrowRenderer.cpp \
../../../src/client/renderer/entity/ChickenRenderer.cpp \ ../../../src/client/renderer/entity/ChickenRenderer.cpp \
@@ -139,6 +140,12 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/network/Packet.cpp \ ../../../src/network/Packet.cpp \
../../../src/network/RakNetInstance.cpp \ ../../../src/network/RakNetInstance.cpp \
../../../src/network/ServerSideNetworkHandler.cpp \ ../../../src/network/ServerSideNetworkHandler.cpp \
../../../src/commands/Command.cpp \
../../../src/commands/CommandHelp.cpp \
../../../src/commands/CommandKick.cpp \
../../../src/commands/CommandBan.cpp \
../../../src/commands/CommandManager.cpp \
../../../src/commands/CommandOp.cpp \
../../../src/server/ServerLevel.cpp \ ../../../src/server/ServerLevel.cpp \
../../../src/server/ServerPlayer.cpp \ ../../../src/server/ServerPlayer.cpp \
../../../src/util/DataIO.cpp \ ../../../src/util/DataIO.cpp \

View File

@@ -1,4 +1,4 @@
APP_PLATFORM := android-21 APP_PLATFORM := android-19
APP_STL := gnustl_static APP_STL := gnustl_static
APP_OPTIM := release APP_OPTIM := release
APP_ABI := arm64-v8a APP_ABI := arm64-v8a

View File

@@ -5,8 +5,8 @@
android:versionName="0.6.1-alpha-0.0.3"> android:versionName="0.6.1-alpha-0.0.3">
<uses-sdk <uses-sdk
android:minSdkVersion="24" android:minSdkVersion="19"
android:targetSdkVersion="28"/> android:targetSdkVersion="30"/>
<uses-feature <uses-feature
android:name="android.hardware.touchscreen.multitouch" android:name="android.hardware.touchscreen.multitouch"

View File

@@ -168,8 +168,10 @@ options.graphics.fast=Fast
options.guiScale=GUI Scale options.guiScale=GUI Scale
options.guiScale.auto=Auto options.guiScale.auto=Auto
options.guiScale.small=Small options.guiScale.small=Small
options.guiScale.normal=Normal options.guiScale.medium=Medium
options.guiScale.large=Large options.guiScale.large=Large
options.guiScale.larger=Larger
options.guiScale.largest=Largest
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

@@ -228,6 +228,7 @@ LOCAL_SRC_FILES := ../../../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
../../../src/world/level/LevelConstants.cpp
LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS) LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS)

View File

@@ -1,4 +1,4 @@
APP_PLATFORM := android-9 APP_PLATFORM := android-19
APP_STL := gnustl_static APP_STL := gnustl_static
APP_OPTIM := release APP_OPTIM := release
APP_ABI := armeabi-v7a APP_ABI := armeabi-v7a

View File

@@ -59,6 +59,7 @@ public class MainActivity extends Activity {
private static final int PERMISSION_REQUEST_CODE = 123; private static final int PERMISSION_REQUEST_CODE = 123;
private GLView _glView; private GLView _glView;
private boolean _nativeInitialized = false;
public float invScale = 1.0f;// / 1.5f; public float invScale = 1.0f;// / 1.5f;
private int _screenWidth = 0; private int _screenWidth = 0;
private int _screenHeight = 0; private int _screenHeight = 0;
@@ -77,63 +78,48 @@ public class MainActivity extends Activity {
_screenWidth = Math.max(_dm.widthPixels, _dm.heightPixels); _screenWidth = Math.max(_dm.widthPixels, _dm.heightPixels);
_screenHeight = Math.min(_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);
_glView.setEGLConfigChooser(true); _glView.setEGLConfigChooser(true);
//_glView //_glView
// _glView.setEGLConfigChooser(
// new GLSurfaceView.EGLConfigChooser() {
//
// @Override
// public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
// // TODO Auto-generated method stub
//
// // Specify a configuration for our opengl session
// // and grab the first configuration that matches is
// int[] configSpec = {
// EGL10.EGL_DEPTH_SIZE, 24,
// EGL10.EGL_NONE
// };
// EGLConfig[] configs = new EGLConfig[1];
// int[] num_config = new int[1];
// egl.eglChooseConfig(display, configSpec, configs, 1, num_config);
// EGLConfig config = configs[0];
// return config;
//
// //return null;
// }
// } );
_glView.commit(); _glView.commit();
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(); checkAndRequestPermissions();
initNative();
} }
private void checkAndRequestPermissions() { private void initNative() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (_nativeInitialized) {
boolean needRequest = false; return;
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
needRequest = true;
} }
if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) _nativeInitialized = true;
!= PackageManager.PERMISSION_GRANTED) { nativeOnCreate(_screenWidth, _screenHeight);
needRequest = true;
} }
if (needRequest) {
// request dangerous permissions at runtime if necessary
private boolean checkAndRequestPermissions() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
boolean writeGranted = checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
boolean readGranted = checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
if (writeGranted && readGranted) {
return true;
}
requestPermissions(new String[] { requestPermissions(new String[] {
android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.READ_EXTERNAL_STORAGE android.Manifest.permission.READ_EXTERNAL_STORAGE
}, PERMISSION_REQUEST_CODE); }, PERMISSION_REQUEST_CODE);
}
} return false;
} }
@Override @Override
@@ -146,8 +132,18 @@ public class MainActivity extends Activity {
break; break;
} }
} }
if (!granted) { if (granted) {
// user denied; you might want to warn or close the app initNative();
} else {
// We can still run using app-specific external files in scoped-storage,
// so allow startup while warning the user.
initNative();
new AlertDialog.Builder(this)
.setTitle("Storage permission recommended")
.setMessage("MinecraftPE can still run with app-private storage, but public external save/load may require permission.")
.setPositiveButton("OK", null)
.setCancelable(true)
.show();
} }
} }
super.onRequestPermissionsResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults);

View File

@@ -1,8 +1,8 @@
#if defined(X360__) #if defined(X360__)
#elif defined (_WIN32) #elif defined (_WIN32)
#include <WinSock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#include <Ws2tcpip.h> #include <ws2tcpip.h>
// Must always include Winsock2.h before windows.h // Must always include Winsock2.h before windows.h
// or else: // or else:

View File

@@ -75,6 +75,8 @@ public:
virtual void playSound(const std::string& fn, float volume, float pitch) {} virtual void playSound(const std::string& fn, float volume, float pitch) {}
virtual void hideCursor(bool hide) {}
virtual void showDialog(int dialogId) {} virtual void showDialog(int dialogId) {}
virtual void createUserInput() {} virtual void createUserInput() {}

View File

@@ -202,6 +202,8 @@ public:
LOGI("initConsts: screenWidth=%d, calling getScreenHeight\n", _screenWidth); 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); LOGI("initConsts: screenHeight=%d, done\n", _screenHeight);
return 1;
} }
void tick() { void tick() {
@@ -536,7 +538,7 @@ public:
static __inline bool isSquare(int n) { static __inline bool isSquare(int n) {
int L = n & 0xf; int L = n & 0xf;
if ((1 << L) & 0x213 == 0) return false; if (((1 << L) & 0x213) == 0) return false;
int t = (int) sqrt((double) n) + 0.5; int t = (int) sqrt((double) n) + 0.5;
return t*t == n; return t*t == n;

View File

@@ -20,6 +20,10 @@
#include <shellapi.h> #include <shellapi.h>
#endif #endif
#ifdef __EMSCRIPTEN__
#include <emscripten/html5.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);
} }
@@ -73,50 +77,20 @@ public:
: filename_; : filename_;
std::ifstream source(filename.c_str(), std::ios::binary); std::ifstream source(filename.c_str(), std::ios::binary);
if (source) { if (!source) {
png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!pngPtr)
return out;
png_infop infoPtr = png_create_info_struct(pngPtr);
if (!infoPtr) {
png_destroy_read_struct(&pngPtr, NULL, NULL);
return out;
}
// Hack to get around the broken libpng for windows
png_set_read_fn(pngPtr,(void*)&source, png_funcReadFile);
png_read_info(pngPtr, infoPtr);
// Set up the texdata properties
out.w = png_get_image_width(pngPtr, infoPtr);
out.h = png_get_image_height(pngPtr, infoPtr);
png_bytep* rowPtrs = new png_bytep[out.h];
out.data = new unsigned char[4 * out.w * out.h];
out.memoryHandledExternally = false;
int rowStrideBytes = 4 * out.w;
for (int i = 0; i < out.h; i++) {
rowPtrs[i] = (png_bytep)&out.data[i*rowStrideBytes];
}
png_read_image(pngPtr, rowPtrs);
// Teardown and return
png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);
delete[] (png_bytep)rowPtrs;
source.close();
return out;
}
else
{
LOGI("Couldn't find file: %s\n", filename.c_str()); LOGI("Couldn't find file: %s\n", filename.c_str());
return out; return out;
} }
std::vector<unsigned char> fileData((std::istreambuf_iterator<char>(source)), std::istreambuf_iterator<char>());
source.close();
if (fileData.empty()) {
LOGI("Couldn't read file: %s\n", filename.c_str());
return out;
}
return loadTextureFromMemory(fileData.data(), fileData.size());
} }
TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override { TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override {
@@ -132,12 +106,36 @@ public:
return std::string(mbstr); return std::string(mbstr);
} }
virtual int getScreenWidth() override { return 854; }; virtual int getScreenWidth() override {
virtual int getScreenHeight() override { return 480; }; #ifdef __EMSCRIPTEN__
int w, h;
emscripten_get_canvas_element_size("canvas", &w, &h);
return w;
#endif
return 854;
};
virtual int getScreenHeight() override {
#ifdef __EMSCRIPTEN__
int w, h;
emscripten_get_canvas_element_size("canvas", &w, &h);
return h;
#endif
return 480;
};
virtual float getPixelsPerMillimeter() override; virtual float getPixelsPerMillimeter() override;
virtual bool supportsTouchscreen() override { return true; } virtual bool supportsTouchscreen() override { return false; /* glfw supports only mouse and keyboard */ }
virtual void hideCursor(bool hide) override {
int isHide = hide ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN;
glfwSetInputMode(window, GLFW_CURSOR, isHide);
}
virtual void openURL(const std::string& url) override { virtual void openURL(const std::string& url) override {
#ifdef _WIN32 #ifdef _WIN32
@@ -145,6 +143,8 @@ public:
#elif __linux__ #elif __linux__
std::string command = "xdg-open " + url; std::string command = "xdg-open " + url;
system(command.c_str()); system(command.c_str());
#elif __EMSCRIPTEN__
emscripten_run_script(std::string("window.open('" + url + "', '_blank')").c_str());
#endif #endif
} }

View File

@@ -99,6 +99,9 @@ void NinecraftApp::init()
I18n::loadLanguage(platform(), "en_US"); I18n::loadLanguage(platform(), "en_US");
#endif #endif
if (!externalStoragePath.empty()) {
options.setOptionsFilePath(externalStoragePath);
}
Minecraft::init(); Minecraft::init();
#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) && !defined(NO_STORAGE) #if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) && !defined(NO_STORAGE)
@@ -133,7 +136,7 @@ void NinecraftApp::teardown()
Recipes ::teardownRecipes(); Recipes ::teardownRecipes();
TileEntity::teardownTileEntities(); TileEntity::teardownTileEntities();
#endif #endif
#ifdef WIN32 #if defined(WIN32) && !defined(STANDALONE_SERVER)
ItemRenderer::teardown_static(); ItemRenderer::teardown_static();
if (EntityTileRenderer::instance != NULL) { if (EntityTileRenderer::instance != NULL) {
delete EntityTileRenderer::instance; delete EntityTileRenderer::instance;

View File

@@ -1,6 +1,8 @@
#include "Minecraft.h" #include "Minecraft.h"
#include "Options.h"
#include "client/Options.h" #include "client/Options.h"
#include "client/player/input/IBuildInput.h" #include "client/player/input/IBuildInput.h"
#include "commands/CommandManager.hpp"
#include "platform/input/Keyboard.h" #include "platform/input/Keyboard.h"
#include "world/item/Item.h" #include "world/item/Item.h"
#include "world/item/ItemInstance.h" #include "world/item/ItemInstance.h"
@@ -174,7 +176,8 @@ 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), options(this) reserved_f1(0),reserved_f2(0), options(this),
m_commandManager()
{ {
//#ifdef ANDROID //#ifdef ANDROID
@@ -255,9 +258,10 @@ void Minecraft::selectLevel( const std::string& levelId, const std::string& leve
void Minecraft::setLevel(Level* level, const std::string& message /* ="" */, LocalPlayer* forceInsertPlayer /* = NULL */) { void Minecraft::setLevel(Level* level, const std::string& message /* ="" */, LocalPlayer* forceInsertPlayer /* = NULL */) {
cameraTargetPlayer = NULL; cameraTargetPlayer = NULL;
LOGI("Seed is %ld\n", level->getSeed());
if (level != NULL) { if (level != NULL) {
LOGI("Seed is %ld\n", level->getSeed());
level->raknetInstance = raknetInstance; level->raknetInstance = raknetInstance;
gameMode->initLevel(level); gameMode->initLevel(level);
@@ -274,6 +278,11 @@ void Minecraft::setLevel(Level* level, const std::string& message /* ="" */, Loc
} }
} }
this->level = level; this->level = level;
// So uhhh
std::string op = options.getStringValue(OPTIONS_USERNAME);
std::transform(op.begin(), op.end(), op.begin(), ::tolower);
level->ops.emplace(op);
_hasSignaledGeneratingLevelFinished = false; _hasSignaledGeneratingLevelFinished = false;
#ifdef STANDALONE_SERVER #ifdef STANDALONE_SERVER
const bool threadedLevelCreation = false; const bool threadedLevelCreation = false;
@@ -357,10 +366,10 @@ void Minecraft::prepareLevel(const std::string& title) {
if (!level->isNew()) if (!level->isNew())
level->setUpdateLights(false); level->setUpdateLights(false);
int Max = CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; int Max = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH;
int pp = 0; int pp = 0;
for (int x = 8; x < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); x += CHUNK_WIDTH) { for (int x = 8; x < (LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH); x += LevelConstants::CHUNK_WIDTH) {
for (int z = 8; z < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); z += CHUNK_WIDTH) { for (int z = 8; z < (LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH); z += LevelConstants::CHUNK_WIDTH) {
progressStagePercentage = 100 * pp++ / Max; progressStagePercentage = 100 * pp++ / Max;
//printf("level generation progress %d\n", progressStagePercentage); //printf("level generation progress %d\n", progressStagePercentage);
B.start(); B.start();
@@ -377,9 +386,9 @@ void Minecraft::prepareLevel(const std::string& title) {
level->setUpdateLights(true); level->setUpdateLights(true);
C.start(); C.start();
for (int x = 0; x < CHUNK_CACHE_WIDTH; x++) for (int x = 0; x < LevelConstants::CHUNK_CACHE_WIDTH; x++)
{ {
for (int z = 0; z < CHUNK_CACHE_WIDTH; z++) for (int z = 0; z < LevelConstants::CHUNK_CACHE_WIDTH; z++)
{ {
LevelChunk* chunk = level->getChunk(x, z); LevelChunk* chunk = level->getChunk(x, z);
if (chunk && !chunk->createdFromSave) if (chunk && !chunk->createdFromSave)
@@ -640,13 +649,11 @@ void Minecraft::tickInput() {
const MouseAction& e = Mouse::getEvent(); const MouseAction& e = Mouse::getEvent();
#ifdef RPI // If clicked when not having focus, get focus @keyboard if (!useTouchscreen() && !mouseGrabbed) {
if (!mouseGrabbed) {
if (!screen && e.data == MouseAction::DATA_DOWN) { if (!screen && e.data == MouseAction::DATA_DOWN) {
grabMouse(); grabMouse();
} }
} }
#endif
if (allowGuiClicks && e.action == MouseAction::ACTION_LEFT && e.data == MouseAction::DATA_DOWN) { if (allowGuiClicks && e.action == MouseAction::ACTION_LEFT && e.data == MouseAction::DATA_DOWN) {
gui.handleClick(MouseAction::ACTION_LEFT, Mouse::getX(), Mouse::getY()); gui.handleClick(MouseAction::ACTION_LEFT, Mouse::getX(), Mouse::getY());
@@ -660,9 +667,7 @@ void Minecraft::tickInput() {
Inventory* v = player->inventory; Inventory* v = player->inventory;
int numSlots = gui.getNumSlots(); int numSlots = gui.getNumSlots();
#ifndef PLATFORM_DESKTOP if (!useTouchscreen()) numSlots--;
numSlots--;
#endif
int slot = (v->selected - e.dy + numSlots) % numSlots; int slot = (v->selected - e.dy + numSlots) % numSlots;
v->selectSlot(slot); v->selectSlot(slot);
@@ -691,7 +696,6 @@ void Minecraft::tickInput() {
if (isPressed) { if (isPressed) {
gui.handleKeyPressed(key); gui.handleKeyPressed(key);
#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;
@@ -714,8 +718,7 @@ void Minecraft::tickInput() {
} }
#endif #endif
} }
#endif
#if defined(PLATFORM_DESKTOP)
if (key == Keyboard::KEY_LEFT_CTRL) { if (key == Keyboard::KEY_LEFT_CTRL) {
player->setSprinting(true); player->setSprinting(true);
} }
@@ -732,6 +735,21 @@ void Minecraft::tickInput() {
options.toggle(OPTIONS_RENDER_DEBUG); options.toggle(OPTIONS_RENDER_DEBUG);
} }
// TODO: replace it with client /give command :face_vomiting:
// if (key == Keyboard::KEY_F4) {
// player->inventory->add(new ItemInstance(Tile::redBrick));
// player->inventory->add(new ItemInstance(Item::ironIngot, 64));
// player->inventory->add(new ItemInstance(Item::ironIngot, 34));
// player->inventory->add(new ItemInstance(Tile::stonecutterBench));
// player->inventory->add(new ItemInstance(Tile::workBench));
// player->inventory->add(new ItemInstance(Tile::furnace));
// player->inventory->add(new ItemInstance(Tile::wood, 54));
// player->inventory->add(new ItemInstance(Item::stick, 14));
// player->inventory->add(new ItemInstance(Item::coal, 31));
// player->inventory->add(new ItemInstance(Tile::sand, 6));
// }
if (key == Keyboard::KEY_F5) { if (key == Keyboard::KEY_F5) {
options.toggle(OPTIONS_THIRD_PERSON_VIEW); options.toggle(OPTIONS_THIRD_PERSON_VIEW);
/* /*
@@ -831,15 +849,9 @@ void Minecraft::tickInput() {
} }
} }
#endif #endif
#endif
#ifndef PLATFORM_DESKTOP
if (key == 82)
pauseGame(false);
#else
if (key == Keyboard::KEY_ESCAPE) if (key == Keyboard::KEY_ESCAPE)
pauseGame(false); pauseGame(false);
#endif
#ifndef OPENGL_ES #ifndef OPENGL_ES
if (key == Keyboard::KEY_P) { if (key == Keyboard::KEY_P) {
@@ -866,11 +878,18 @@ void Minecraft::tickInput() {
gameMode->stopDestroyBlock(); gameMode->stopDestroyBlock();
} }
if (!Mouse::isButtonDown(MouseAction::ACTION_RIGHT)) {
gameMode->releaseUsingItem(player);
}
if (useTouchscreen()) { if (useTouchscreen()) {
// Touch: gesture recognizer classifies the action type (turn/destroy/build) // Touch: gesture recognizer classifies the action type (turn/destroy/build)
BuildActionIntention bai; BuildActionIntention bai;
if (inputHolder && inputHolder->getBuildInput()->tickBuild(player, &bai)) { if (inputHolder && inputHolder->getBuildInput()->tickBuild(player, &bai)) {
handleBuildAction(&bai); handleBuildAction(&bai);
} else {
gameMode->stopDestroyBlock();
} }
} else { } else {
// Desktop: left mouse = destroy/attack // Desktop: left mouse = destroy/attack
@@ -1112,13 +1131,14 @@ bool Minecraft::useTouchscreen() {
#ifdef RPI #ifdef RPI
return false; return false;
#endif #endif
return options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN) || !_supportsNonTouchscreen; return options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN) && !_supportsNonTouchscreen;
} }
bool Minecraft::supportNonTouchScreen() { bool Minecraft::supportNonTouchScreen() {
return _supportsNonTouchscreen; return _supportsNonTouchscreen;
} }
void Minecraft::init() void Minecraft::init()
{ {
LevelChunk::ChunkBlockCount = LevelConstants::CHUNK_BLOCK_COUNT;
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
checkGlError("Init enter"); checkGlError("Init enter");
@@ -1143,6 +1163,8 @@ void Minecraft::init()
checkGlError("Init complete"); checkGlError("Init complete");
#endif #endif
options.load();
setIsCreativeMode(false); // false means it's Survival Mode setIsCreativeMode(false); // false means it's Survival Mode
reloadOptions(); reloadOptions();
} }
@@ -1158,12 +1180,13 @@ void Minecraft::setSize(int w, int h) {
// determine gui scale, optionally overriding auto // determine gui scale, optionally overriding auto
if (guiScale != 0) { if (guiScale != 0) {
// manual selection: 1->small, 2->normal, 3->large, 4->larger // manual selection: 1->small, 2->medium, 3->large, 4->larger, 5->largest
switch (guiScale) { switch (guiScale) {
case 1: Gui::GuiScale = 2.0f; break; case 1: Gui::GuiScale = 2.0f; break;
case 2: Gui::GuiScale = 3.0f; break; case 2: Gui::GuiScale = 3.0f; break;
case 3: Gui::GuiScale = 4.0f; break; case 3: Gui::GuiScale = 4.0f; break;
case 4: Gui::GuiScale = 5.0f; break; // bigger than large case 4: Gui::GuiScale = 5.0f; break;
case 5: Gui::GuiScale = 6.0f; break;
default: Gui::GuiScale = 1.0f; break; // auto default: Gui::GuiScale = 1.0f; break; // auto
} }
} else { } else {
@@ -1225,7 +1248,6 @@ void Minecraft::reloadOptions() {
if ((wasTouchscreen != useTouchscreen()) || (inputHolder == 0)) if ((wasTouchscreen != useTouchscreen()) || (inputHolder == 0))
_reloadInput(); _reloadInput();
// TODO:
// user->name = options.username; // user->name = options.username;
LOGI("Reloading-options\n"); LOGI("Reloading-options\n");
@@ -1239,11 +1261,7 @@ void Minecraft::_reloadInput() {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
delete inputHolder; delete inputHolder;
#ifdef PLATFORM_DESKTOP
const bool useTouchHolder = false;
#else
const bool useTouchHolder = useTouchscreen(); const bool useTouchHolder = useTouchscreen();
#endif
if (useTouchHolder) { if (useTouchHolder) {
inputHolder = new TouchInputHolder(this, &options); inputHolder = new TouchInputHolder(this, &options);
} else { } else {
@@ -1310,11 +1328,8 @@ bool Minecraft::joinMultiplayerFromString( const std::string& server )
ip = server; ip = server;
} }
printf("%s \n", port.c_str());
if (isLookingForMultiplayer && netCallback) { if (isLookingForMultiplayer && netCallback) {
isLookingForMultiplayer = false; isLookingForMultiplayer = false;
printf("test");
int portNum = atoi(port.c_str()); int portNum = atoi(port.c_str());
return raknetInstance->connect(ip.c_str(), portNum); return raknetInstance->connect(ip.c_str(), portNum);
} }
@@ -1568,6 +1583,8 @@ void Minecraft::optionUpdated(OptionId option, bool value ) {
if(netCallback != NULL && option == OPTIONS_SERVER_VISIBLE) { if(netCallback != NULL && option == OPTIONS_SERVER_VISIBLE) {
ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback; ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback;
ss->allowIncomingConnections(value); ss->allowIncomingConnections(value);
} else if (option == OPTIONS_USE_TOUCHSCREEN) {
_reloadInput();
} }
} }
@@ -1586,3 +1603,11 @@ void Minecraft::optionUpdated(OptionId option, int value ) {
setSize(width, height); setSize(width, height);
} }
} }
void Minecraft::addMessage(const std::string& msg) {
#ifndef STANDALONE_SERVER
gui.addMessage(msg);
#else
LOGI("%s \n", msg.c_str());
#endif
}

View File

@@ -2,6 +2,7 @@
#define NET_MINECRAFT_CLIENT__Minecraft_H__ #define NET_MINECRAFT_CLIENT__Minecraft_H__
#include "Options.h" #include "Options.h"
#include "commands/CommandManager.hpp"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "MouseHandler.h" #include "MouseHandler.h"
#include "gui/Gui.h" #include "gui/Gui.h"
@@ -109,6 +110,8 @@ public:
bool isLevelGenerated(); bool isLevelGenerated();
void handleMouseDown(int button, bool down);
void audioEngineOn(); void audioEngineOn();
void audioEngineOff(); void audioEngineOff();
@@ -118,11 +121,17 @@ public:
void optionUpdated(OptionId option, bool value); void optionUpdated(OptionId option, bool value);
void optionUpdated(OptionId option, float value); void optionUpdated(OptionId option, float value);
void optionUpdated(OptionId option, int value); void optionUpdated(OptionId option, int value);
int getTicks() { return ticks; }
void addMessage(const std::string& msg);
#ifdef __APPLE__ #ifdef __APPLE__
bool _isSuperFast; bool _isSuperFast;
bool isSuperFast() { return _isSuperFast; } bool isSuperFast() { return _isSuperFast; }
#endif #endif
CommandManager& commandManager() { return m_commandManager; }
protected: protected:
void _levelGenerated(); void _levelGenerated();
@@ -195,6 +204,7 @@ public:
std::string externalCacheStoragePath; std::string externalCacheStoragePath;
protected: protected:
Timer timer; Timer timer;
// @note @attn @warn: this is dangerous as fuck! // @note @attn @warn: this is dangerous as fuck!
volatile bool isGeneratingLevel; volatile bool isGeneratingLevel;
bool _hasSignaledGeneratingLevelFinished; bool _hasSignaledGeneratingLevelFinished;
@@ -222,6 +232,8 @@ private:
PerfRenderer* _perfRenderer; PerfRenderer* _perfRenderer;
CommandServer* _commandServer; CommandServer* _commandServer;
CommandManager m_commandManager;
}; };
#endif /*NET_MINECRAFT_CLIENT__Minecraft_H__*/ #endif /*NET_MINECRAFT_CLIENT__Minecraft_H__*/

View File

@@ -5,7 +5,7 @@
#include <SDL/SDL.h> #include <SDL/SDL.h>
#endif #endif
#ifdef PLATFORM_GLFW #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#endif #endif
@@ -34,7 +34,7 @@ void MouseHandler::grab() {
SDL_ShowCursor(0); SDL_ShowCursor(0);
#endif #endif
#ifdef PLATFORM_GLFW #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_DISABLED);
#endif #endif
} }
@@ -46,7 +46,7 @@ void MouseHandler::release() {
SDL_ShowCursor(1); SDL_ShowCursor(1);
#endif #endif
#ifdef PLATFORM_GLFW #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_NORMAL);
#endif #endif
} }

View File

@@ -20,6 +20,7 @@ OptionBool fixedCamera("fixedCamera", false);
OptionBool isFlying("isflying", false); OptionBool isFlying("isflying", false);
OptionBool barOnTop("barOnTop", false); OptionBool barOnTop("barOnTop", false);
OptionBool allowSprint("allowSprint", true); OptionBool allowSprint("allowSprint", true);
OptionBool rpiCursor("rpiCursor", false);
OptionBool autoJump("autoJump", true); OptionBool autoJump("autoJump", true);
@@ -158,6 +159,7 @@ void Options::initTable() {
m_options[OPTIONS_BAR_ON_TOP] = &barOnTop; m_options[OPTIONS_BAR_ON_TOP] = &barOnTop;
m_options[OPTIONS_ALLOW_SPRINT] = &allowSprint; m_options[OPTIONS_ALLOW_SPRINT] = &allowSprint;
m_options[OPTIONS_RPI_CURSOR] = &rpiCursor;
m_options[OPTIONS_AUTOJUMP] = &autoJump; m_options[OPTIONS_AUTOJUMP] = &autoJump;
m_options[OPTIONS_LAST_IP] = &lastIp; m_options[OPTIONS_LAST_IP] = &lastIp;
@@ -168,9 +170,7 @@ void Options::set(OptionId key, const std::string& value) {
if (option) { if (option) {
option->set(value); option->set(value);
notifyOptionUpdate(key, value); notifyOptionUpdate(key, value);
save();
} }
} }
@@ -179,9 +179,7 @@ void Options::set(OptionId key, float value) {
if (option) { if (option) {
option->set(value); option->set(value);
notifyOptionUpdate(key, value); notifyOptionUpdate(key, value);
save();
} }
} }
@@ -190,9 +188,7 @@ void Options::set(OptionId key, int value) {
if (option) { if (option) {
option->set(value); option->set(value);
notifyOptionUpdate(key, value); notifyOptionUpdate(key, value);
save();
} }
} }
@@ -201,9 +197,7 @@ void Options::toggle(OptionId key) {
if (option) { if (option) {
option->toggle(); option->toggle();
notifyOptionUpdate(key, option->get()); notifyOptionUpdate(key, option->get());
save();
} }
} }
@@ -291,6 +285,10 @@ void Options::save() {
optionsFile.save(stringVec); optionsFile.save(stringVec);
} }
void Options::setOptionsFilePath(const std::string& path) {
optionsFile.setOptionsPath(path + "/options.txt");
}
void Options::notifyOptionUpdate(OptionId key, bool value) { void Options::notifyOptionUpdate(OptionId key, bool value) {
minecraft->optionUpdated(key, value); minecraft->optionUpdated(key, value);
} }

View File

@@ -83,6 +83,7 @@ enum OptionId {
OPTIONS_FIRST_LAUNCH, OPTIONS_FIRST_LAUNCH,
OPTIONS_LAST_IP, OPTIONS_LAST_IP,
OPTIONS_RPI_CURSOR,
// Should be last! // Should be last!
OPTIONS_COUNT OPTIONS_COUNT
}; };
@@ -100,16 +101,11 @@ public:
// elements werent initialized so i was getting a garbage pointer and a crash // elements werent initialized so i was getting a garbage pointer and a crash
m_options.fill(nullptr); m_options.fill(nullptr);
initTable(); initTable();
load(); // load() is deferred to init() where path is configured correctly
} }
void initTable(); void initTable();
void set(OptionId key, int value);
void set(OptionId key, float value);
void set(OptionId key, const std::string& value);
void toggle(OptionId key);
int getIntValue(OptionId key) { int getIntValue(OptionId key) {
auto option = opt<OptionInt>(key); auto option = opt<OptionInt>(key);
return (option)? option->get() : 0; return (option)? option->get() : 0;
@@ -144,6 +140,11 @@ public:
void load(); void load();
void save(); void save();
void set(OptionId key, int value);
void set(OptionId key, float value);
void set(OptionId key, const std::string& value);
void setOptionsFilePath(const std::string& path);
void toggle(OptionId key);
void notifyOptionUpdate(OptionId key, bool value); void notifyOptionUpdate(OptionId key, bool value);
void notifyOptionUpdate(OptionId key, float value); void notifyOptionUpdate(OptionId key, float value);

View File

@@ -1,30 +1,76 @@
#include "OptionsFile.h" #include "OptionsFile.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <platform/log.h> #include <platform/log.h>
#if defined(_WIN32)
#include <direct.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#endif
OptionsFile::OptionsFile() { OptionsFile::OptionsFile() {
#ifdef __APPLE__ #ifdef __APPLE__
settingsPath = "./Documents/options.txt"; settingsPath = "./Documents/options.txt";
#elif defined(ANDROID) #elif defined(ANDROID)
settingsPath = "options.txt"; settingsPath = "options.txt";
#elif defined(__EMSCRIPTEN__)
settingsPath = "/games/com.mojang/options.txt";
#else #else
settingsPath = "options.txt"; settingsPath = "options.txt";
#endif #endif
} }
void OptionsFile::setOptionsPath(const std::string& path) {
settingsPath = path;
}
std::string OptionsFile::getOptionsPath() const {
return settingsPath;
}
void OptionsFile::save(const StringVector& settings) { void OptionsFile::save(const StringVector& settings) {
FILE* pFile = fopen(settingsPath.c_str(), "w"); FILE* pFile = fopen(settingsPath.c_str(), "w");
if(pFile != NULL) {
for(StringVector::const_iterator it = settings.begin(); it != settings.end(); ++it) { if (!pFile && errno == ENOENT) {
fprintf(pFile, "%s\n", it->c_str()); std::string dir = settingsPath;
size_t fpos = dir.find_last_of("/\\");
if (fpos != std::string::npos) {
dir.resize(fpos);
std::string toCreate;
for (size_t i = 0; i <= dir.size(); ++i) {
if (i == dir.size() || dir[i] == '/' || dir[i] == '\\') {
if (!toCreate.empty()) {
#if defined(_WIN32)
_mkdir(toCreate.c_str());
#else
mkdir(toCreate.c_str(), 0755);
#endif
} }
}
if (i < dir.size())
toCreate.push_back(dir[i]);
}
}
pFile = fopen(settingsPath.c_str(), "w");
}
if (!pFile) {
LOGI("OptionsFile::save failed: %s", strerror(errno));
return;
}
for (const auto& s : settings) {
fprintf(pFile, "%s\n", s.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(), "r"); FILE* pFile = fopen(settingsPath.c_str(), "r");
@@ -45,6 +91,7 @@ StringVector OptionsFile::getOptionStrings() {
} }
fclose(pFile); fclose(pFile);
} else { } else {
if (errno != ENOENT)
LOGI("OptionsFile::getOptionStrings failed to open '%s' for reading: %s", settingsPath.c_str(), strerror(errno)); LOGI("OptionsFile::getOptionStrings failed to open '%s' for reading: %s", settingsPath.c_str(), strerror(errno));
} }
return returnVector; return returnVector;

View File

@@ -11,6 +11,8 @@ public:
OptionsFile(); OptionsFile();
void save(const StringVector& settings); void save(const StringVector& settings);
StringVector getOptionStrings(); StringVector getOptionStrings();
void setOptionsPath(const std::string& path);
std::string getOptionsPath() const;
private: private:
std::string settingsPath; std::string settingsPath;

View File

@@ -54,16 +54,3 @@ void CreativeMode::initAbilities( Abilities& abilities ) {
bool CreativeMode::isCreativeType() { bool CreativeMode::isCreativeType() {
return true; return true;
} }
void CreativeMode::releaseUsingItem( Player* player ) {
if(player->getCarriedItem() != NULL) {
int oldItemId = player->getCarriedItem()->id;
int oldAux = player->getAuxData();
super::releaseUsingItem(player);
if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == oldItemId) {
player->getCarriedItem()->setAuxValue(oldAux);
}
} else {
super::releaseUsingItem(player);
}
}

View File

@@ -19,7 +19,6 @@ public:
void initAbilities(Abilities& abilities); void initAbilities(Abilities& abilities);
void releaseUsingItem(Player* player);
private: private:
void creativeDestroyBlock(int x, int y, int z, int face); void creativeDestroyBlock(int x, int y, int z, int face);
}; };

View File

@@ -92,19 +92,6 @@ bool CreatorMode::isCreativeType() {
return true; return true;
} }
void CreatorMode::releaseUsingItem( Player* player ) {
if(player->getCarriedItem() != NULL) {
int oldItemId = player->getCarriedItem()->id;
int oldAux = player->getAuxData();
super::releaseUsingItem(player);
if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == oldItemId) {
player->getCarriedItem()->setAuxValue(oldAux);
}
} else {
super::releaseUsingItem(player);
}
}
ICreator* CreatorMode::getCreator() { ICreator* CreatorMode::getCreator() {
return _creator; return _creator;
} }

View File

@@ -118,7 +118,6 @@ public:
void initAbilities(Abilities& abilities); void initAbilities(Abilities& abilities);
void releaseUsingItem(Player* player);
private: private:
void CreatorDestroyBlock(int x, int y, int z, int face); void CreatorDestroyBlock(int x, int y, int z, int face);

View File

@@ -89,8 +89,8 @@ bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x
float clickX = hit.x - x; float clickX = hit.x - x;
float clickY = hit.y - y; float clickY = hit.y - y;
float clickZ = hit.z - z; float clickZ = hit.z - z;
if (level->isClientSide) {
item = player->inventory->getSelected(); item = player->inventory->getSelected();
if(level->isClientSide) {
UseItemPacket packet(x, y, z, face, item, player->entityId, clickX, clickY, clickZ); UseItemPacket packet(x, y, z, face, item, player->entityId, clickX, clickY, clickZ);
minecraft->raknetInstance->send(packet); minecraft->raknetInstance->send(packet);
} }
@@ -149,7 +149,7 @@ void GameMode::initPlayer( Player* player ) {
} }
void GameMode::releaseUsingItem(Player* player){ void GameMode::releaseUsingItem(Player* player){
if(minecraft->level->isClientSide) { if (minecraft->level->isClientSide && player->isUsingItem()) {
PlayerActionPacket packet(PlayerActionPacket::RELEASE_USE_ITEM, 0, 0, 0, 0, player->entityId); PlayerActionPacket packet(PlayerActionPacket::RELEASE_USE_ITEM, 0, 0, 0, 0, player->entityId);
minecraft->raknetInstance->send(packet); minecraft->raknetInstance->send(packet);
} }

View File

@@ -68,6 +68,7 @@ bool SurvivalMode::destroyBlock( int x, int y, int z, int face ) {
minecraft->player->inventory->clearSlot(minecraft->player->inventory->selected); minecraft->player->inventory->clearSlot(minecraft->player->inventory->selected);
} }
} }
if (changed && couldDestroy) { if (changed && couldDestroy) {
ItemInstance instance(t, 1, data); ItemInstance instance(t, 1, data);
Tile::tiles[t]->playerDestroy(minecraft->level, minecraft->player, x, y, z, data); Tile::tiles[t]->playerDestroy(minecraft->level, minecraft->player, x, y, z, data);

View File

@@ -186,7 +186,7 @@ void Font::draw( const std::string& str, float x, float y, int color, bool darke
glPushMatrix2(); glPushMatrix2();
glTranslatef2((GLfloat)x, (GLfloat)y, 0.0f); glTranslatef2((GLfloat)x, (GLfloat)y, 0.0f);
for (unsigned int i = 0; i < str.length(); i++) { for (unsigned int i = 0; i < str.length(); i++) {
while (str.length() > i + 1 && str[i] == '§') { while (str.length() > i + 1 && str[i] == '\xa7') {
int cc = hex.find((char)tolower(str[i + 1])); int cc = hex.find((char)tolower(str[i + 1]));
if (cc < 0 || cc > 15) cc = 15; if (cc < 0 || cc > 15) cc = 15;
lists[index++] = listPos + 256 + cc + (darken ? 16 : 0); lists[index++] = listPos + 256 + cc + (darken ? 16 : 0);
@@ -235,7 +235,7 @@ int Font::width( const std::string& str )
int len = 0; int len = 0;
for (unsigned int i = 0; i < str.length(); i++) { for (unsigned int i = 0; i < str.length(); i++) {
if (str[i] == '§') { if (str[i] == '\xa7') {
i++; i++;
} else { } else {
//int ch = SharedConstants.acceptableLetters.indexOf(str.charAt(i)); //int ch = SharedConstants.acceptableLetters.indexOf(str.charAt(i));
@@ -274,7 +274,7 @@ std::string Font::sanitize( const std::string& str )
int j = 0; int j = 0;
for (unsigned int i = 0; i < str.length(); i++) { for (unsigned int i = 0; i < str.length(); i++) {
if (str[i] == '§') { if (str[i] == '\xa7') {
i++; i++;
//} else if (SharedConstants.acceptableLetters.indexOf(str.charAt(i)) >= 0) { //} else if (SharedConstants.acceptableLetters.indexOf(str.charAt(i)) >= 0) {
} else { } else {

View File

@@ -51,7 +51,8 @@ Gui::Gui(Minecraft* minecraft)
_currentDropTicks(-1), _currentDropTicks(-1),
_currentDropSlot(-1), _currentDropSlot(-1),
MAX_MESSAGE_WIDTH(240), MAX_MESSAGE_WIDTH(240),
itemNameOverlayTime(2) itemNameOverlayTime(2),
_openInventorySlot(minecraft->useTouchscreen())
{ {
glGenBuffers2(1, &_inventoryRc.vboId); glGenBuffers2(1, &_inventoryRc.vboId);
glGenBuffers2(1, &rcFeedbackInner.vboId); glGenBuffers2(1, &rcFeedbackInner.vboId);
@@ -75,11 +76,8 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
//minecraft->gameRenderer->setupGuiScreen(); //minecraft->gameRenderer->setupGuiScreen();
Font* font = minecraft->font; Font* font = minecraft->font;
#ifdef PLATFORM_DESKTOP
const bool isTouchInterface = false;
#else
const bool isTouchInterface = minecraft->useTouchscreen(); const bool isTouchInterface = minecraft->useTouchscreen();
#endif
const int screenWidth = (int)(minecraft->width * InvGuiScale); const int screenWidth = (int)(minecraft->width * InvGuiScale);
const int screenHeight = (int)(minecraft->height * InvGuiScale); const int screenHeight = (int)(minecraft->height * InvGuiScale);
blitOffset = -90; blitOffset = -90;
@@ -206,16 +204,10 @@ void Gui::handleClick(int button, int x, int y) {
if (button != MouseAction::ACTION_LEFT) return; if (button != MouseAction::ACTION_LEFT) return;
int slot = getSlotIdAt(x, y); int slot = getSlotIdAt(x, y);
if (slot != -1) if (slot != -1) {
{ if (_openInventorySlot && slot == (getNumSlots()-1)) {
#ifndef PLATFORM_DESKTOP
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;
} }
@@ -349,7 +341,7 @@ void Gui::setNowPlaying(const std::string& string) {
void Gui::displayClientMessage(const std::string& messageId) { void Gui::displayClientMessage(const std::string& messageId) {
//Language language = Language.getInstance(); //Language language = Language.getInstance();
//std::string languageString = language.getElement(messageId); //std::string languageString = language.getElement(messageId);
addMessage(std::string("Client message: ") + messageId); addMessage(messageId);
} }
void Gui::renderVignette(float br, int w, int h) { void Gui::renderVignette(float br, int w, int h) {
@@ -430,9 +422,9 @@ void Gui::onConfigChanged( const Config& c ) {
// Create outer feedback circle // Create outer feedback circle
// //
#ifdef ANDROID #ifdef ANDROID
const float mm = 12; const float mm = 50; //20
#else #else
const float mm = 12; const float mm = 50; //20
#endif #endif
const float maxRadius = minecraft->pixelCalcUi.millimetersToPixels(mm); const float maxRadius = minecraft->pixelCalcUi.millimetersToPixels(mm);
const float radius = Mth::Min(80.0f/2, maxRadius); const float radius = Mth::Min(80.0f/2, maxRadius);
@@ -537,11 +529,7 @@ void Gui::tickItemDrop()
static bool isCurrentlyActive = false; static bool isCurrentlyActive = false;
isCurrentlyActive = false; isCurrentlyActive = false;
int slots = getNumSlots(); int slots = getNumSlots() - _openInventorySlot;
#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());
@@ -742,7 +730,6 @@ void Gui::renderDebugInfo() {
// Position // Position
float px = p->x, py = p->y - p->heightOffset, pz = p->z; 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 bx = (int)floorf(px), by = (int)floorf(py), bz = (int)floorf(pz);
int cx = bx >> 4, cz = bz >> 4; int cx = bx >> 4, cz = bz >> 4;
@@ -1083,13 +1070,7 @@ void Gui::renderToolBar( float a, int ySlot, const int screenWidth ) {
float x = baseItemX; float x = baseItemX;
int slots = getNumSlots(); int slots = getNumSlots() - _openInventorySlot;
// TODO: if using touchscreen
#ifndef PLATFORM_DESKTOP
slots--;
#endif
for (int i = 0; i < slots; i++) { for (int i = 0; i < slots; i++) {
renderSlot(i, (int)x, ySlot, a); renderSlot(i, (int)x, ySlot, a);
@@ -1097,9 +1078,10 @@ void Gui::renderToolBar( float a, int ySlot, const int screenWidth ) {
} }
_inventoryNeedsUpdate = false; _inventoryNeedsUpdate = false;
#ifndef PLATFORM_DESKTOP
if (_openInventorySlot) {
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();

View File

@@ -127,6 +127,8 @@ private:
static const float DropTicks; static const float DropTicks;
float _currentDropTicks; float _currentDropTicks;
int _currentDropSlot; int _currentDropSlot;
bool _openInventorySlot;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI__Gui_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI__Gui_H__*/

View File

@@ -177,9 +177,11 @@ void Screen::keyPressed( int eventKey )
textbox->keyPressed(minecraft, eventKey); textbox->keyPressed(minecraft, eventKey);
} }
#ifdef TABBING
if (minecraft->useTouchscreen()) if (minecraft->useTouchscreen())
return; return;
// "Tabbing" the buttons (walking with keys) // "Tabbing" the buttons (walking with keys)
const int tabButtonCount = tabButtons.size(); const int tabButtonCount = tabButtons.size();
if (!tabButtonCount) if (!tabButtonCount)
@@ -199,6 +201,7 @@ void Screen::keyPressed( int eventKey )
} }
updateTabButtonSelection(); updateTabButtonSelection();
#endif
} }
void Screen::charPressed(char inputChar) { void Screen::charPressed(char inputChar) {
@@ -209,11 +212,13 @@ void Screen::charPressed(char inputChar) {
void Screen::updateTabButtonSelection() void Screen::updateTabButtonSelection()
{ {
#ifdef TABBING
if (minecraft->useTouchscreen()) if (minecraft->useTouchscreen())
return; return;
for (unsigned int i = 0; i < tabButtons.size(); ++i) for (unsigned int i = 0; i < tabButtons.size(); ++i)
tabButtons[i]->selected = (i == tabButtonIndex); tabButtons[i]->selected = (i == tabButtonIndex);
#endif
} }
void Screen::mouseClicked( int x, int y, int buttonNum ) void Screen::mouseClicked( int x, int y, int buttonNum )

View File

@@ -95,7 +95,7 @@ void Button::renderBg( Minecraft* minecraft, int xm, int ym )
} }
bool Button::hovered(Minecraft* minecraft, int xm , int ym) { bool Button::hovered(Minecraft* minecraft, int xm , int ym) {
return minecraft->useTouchscreen()? (_currentlyDown && isInside(xm, ym)) : false; return minecraft->useTouchscreen()? (_currentlyDown && isInside(xm, ym)) : isInside(xm, ym);
} }
bool Button::isInside( int xm, int ym ) { bool Button::isInside( int xm, int ym ) {
@@ -143,7 +143,8 @@ TButton::TButton( int id, int x, int y, int w, int h, const std::string& msg )
void TButton::renderBg( Minecraft* minecraft, int xm, int ym ) void TButton::renderBg( Minecraft* minecraft, int xm, int ym )
{ {
bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : false); bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym));
// bool hovered = active && (_currentlyDown && isInside(xm, ym));
minecraft->textures->loadAndBindTexture("gui/touchgui.png"); minecraft->textures->loadAndBindTexture("gui/touchgui.png");

View File

@@ -42,7 +42,7 @@ void ImageButton::render(Minecraft* minecraft, int xm, int ym) {
//minecraft->textures->loadAndBindTexture("gui/gui.png"); //minecraft->textures->loadAndBindTexture("gui/gui.png");
glColor4f2(1, 1, 1, 1); glColor4f2(1, 1, 1, 1);
bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : false); bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym));
bool IsSecondImage = isSecondImage(hovered); bool IsSecondImage = isSecondImage(hovered);
//printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym);

View File

@@ -33,7 +33,7 @@ void LargeImageButton::render(Minecraft* minecraft, int xm, int ym) {
//minecraft->textures->loadAndBindTexture("gui/gui.png"); //minecraft->textures->loadAndBindTexture("gui/gui.png");
glColor4f2(1, 1, 1, 1); glColor4f2(1, 1, 1, 1);
bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : false); bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym));
//printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym);
//int yImage = getYImage(hovered || selected); //int yImage = getYImage(hovered || selected);

View File

@@ -65,7 +65,7 @@ void OptionsGroup::createToggle(OptionId optId, Minecraft* minecraft ) {
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(optId, itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
@@ -77,7 +77,7 @@ void OptionsGroup::createProgressSlider(OptionId optId, Minecraft* minecraft ) {
element->height = 20; element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(optId, itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }
@@ -87,7 +87,7 @@ void OptionsGroup::createStepSlider(OptionId optId, Minecraft* minecraft ) {
element->width = 100; element->width = 100;
element->height = 20; element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(optId, itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }
@@ -98,7 +98,7 @@ void OptionsGroup::createTextbox(OptionId optId, Minecraft* minecraft) {
element->height = 20; element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(optId, itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }
@@ -109,7 +109,7 @@ void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) {
element->height = 20; element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(optId, itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }

View File

@@ -1,9 +1,11 @@
#include "OptionsItem.h" #include "OptionsItem.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../../locale/I18n.h"
#include "../../../util/Mth.h" #include "../../../util/Mth.h"
OptionsItem::OptionsItem( std::string label, GuiElement* element ) OptionsItem::OptionsItem( OptionId optionId, std::string label, GuiElement* element )
: GuiElementContainer(false, true, 0, 0, 24, 12), : GuiElementContainer(false, true, 0, 0, 24, 12),
label(label) { m_optionId(optionId),
m_label(label) {
addChild(element); addChild(element);
} }
@@ -19,6 +21,22 @@ void OptionsItem::setupPositions() {
void OptionsItem::render( Minecraft* minecraft, int xm, int ym ) { void OptionsItem::render( Minecraft* minecraft, int xm, int ym ) {
int yOffset = (height - 8) / 2; int yOffset = (height - 8) / 2;
minecraft->font->draw(label, (float)x, (float)y + yOffset, 0x909090, false); std::string text = m_label;
if (m_optionId == OPTIONS_GUI_SCALE) {
int value = minecraft->options.getIntValue(OPTIONS_GUI_SCALE);
std::string scaleText;
switch (value) {
case 0: scaleText = I18n::get("options.guiScale.auto"); break;
case 1: scaleText = I18n::get("options.guiScale.small"); break;
case 2: scaleText = I18n::get("options.guiScale.medium"); break;
case 3: scaleText = I18n::get("options.guiScale.large"); break;
case 4: scaleText = I18n::get("options.guiScale.larger"); break;
case 5: scaleText = I18n::get("options.guiScale.largest"); break;
default: scaleText = I18n::get("options.guiScale.auto"); break;
}
text += ": " + scaleText;
}
minecraft->font->draw(text, (float)x, (float)y + yOffset, 0x909090, false);
super::render(minecraft, xm, ym); super::render(minecraft, xm, ym);
} }

View File

@@ -15,12 +15,13 @@ class OptionsItem: public GuiElementContainer
{ {
typedef GuiElementContainer super; typedef GuiElementContainer super;
public: public:
OptionsItem(std::string label, GuiElement* element); OptionsItem(OptionId optionId, std::string label, GuiElement* element);
virtual void render(Minecraft* minecraft, int xm, int ym); virtual void render(Minecraft* minecraft, int xm, int ym);
void setupPositions(); void setupPositions();
private: private:
std::string label; OptionId m_optionId;
std::string m_label;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__OptionsItem_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__OptionsItem_H__*/

View File

@@ -20,6 +20,9 @@ static const float kMinimumTrackingForDrag = 5;
static const float kMinIndicatorLength = 34.0f / 3; static const float kMinIndicatorLength = 34.0f / 3;
static const float PKScrollIndicatorEndSize = 3; static const float PKScrollIndicatorEndSize = 3;
static const float PKScrollIndicatorThickness = 7.0f /3; static const float PKScrollIndicatorThickness = 7.0f /3;
static const float kWheelOverscrollMax = 80.0f;
static const float kWheelOverscrollDamping = 0.6f;
static const float kWheelOverscrollRestoreAlpha = 0.18f;
ScrollingPane::ScrollingPane( ScrollingPane::ScrollingPane(
int optionFlags, int optionFlags,
@@ -70,13 +73,19 @@ ScrollingPane::ScrollingPane(
} }
//LOGI("%d, %d :: %d\n", bbox.w, itemBbox.w, this->columns); //LOGI("%d, %d :: %d\n", bbox.w, itemBbox.w, this->columns);
rows = 1 + (numItems-1) / this->columns, rows = 1 + (numItems-1) / this->columns;
/* /*
if (columns * itemBbox.w <= bbox.w) flags |= SF_LockX; if (columns * itemBbox.w <= bbox.w) flags |= SF_LockX;
if (rows * itemBbox.h <= bbox.h) flags |= SF_LockY; if (rows * itemBbox.h <= bbox.h) flags |= SF_LockY;
*/ */
// initialize content bounds immediately
adjustContentSize();
minPoint.set((float)(this->size.w - this->adjustedContentSize.w), (float)(this->size.h - this->adjustedContentSize.h), 0);
this->snapContentOffsetToBounds(false);
dragDeltas.reserve(128); dragDeltas.reserve(128);
te_moved = 0; te_moved = 0;
@@ -114,6 +123,34 @@ void ScrollingPane::tick() {
updateScrollFade(vScroll); updateScrollFade(vScroll);
updateScrollFade(hScroll); updateScrollFade(hScroll);
} }
if (isNotSet(SF_HardLimits) && !Mouse::isButtonDown(MouseAction::ACTION_LEFT) && !dragging && !tracking && !decelerating) {
float targetX = _contentOffset.x;
float targetY = _contentOffset.y;
bool corrected = false;
if (targetX > 0.0f) {
targetX = Mth::lerp(targetX, 0.0f, kWheelOverscrollRestoreAlpha);
corrected = true;
} else if (targetX < minPoint.x) {
targetX = Mth::lerp(targetX, minPoint.x, kWheelOverscrollRestoreAlpha);
corrected = true;
}
if (targetY > 0.0f) {
targetY = Mth::lerp(targetY, 0.0f, kWheelOverscrollRestoreAlpha);
corrected = true;
} else if (targetY < minPoint.y) {
targetY = Mth::lerp(targetY, minPoint.y, kWheelOverscrollRestoreAlpha);
corrected = true;
}
if (corrected) {
if (Mth::abs(targetX - _contentOffset.x) < 0.25f) targetX = (targetX > 0.0f ? 0.0f : (targetX < minPoint.x ? minPoint.x : targetX));
if (Mth::abs(targetY - _contentOffset.y) < 0.25f) targetY = (targetY > 0.0f ? 0.0f : (targetY < minPoint.y ? minPoint.y : targetY));
setContentOffset(Vec3(targetX, targetY, 0));
}
}
} }
bool ScrollingPane::getGridItemFor_slow(int itemIndex, GridItem& out) { bool ScrollingPane::getGridItemFor_slow(int itemIndex, GridItem& out) {
@@ -549,11 +586,39 @@ void ScrollingPane::stepThroughDecelerationAnimation(bool noAnimation) {
} }
void ScrollingPane::scrollBy(float dx, float dy) { void ScrollingPane::scrollBy(float dx, float dy) {
// adjust the translation offsets fpx/fpy by the requested amount // compute target content offset from wheel delta (in screen-space w/ opposite sign)
float nfpx = fpx + dx; float targetX = _contentOffset.x - dx;
float nfpy = fpy + dy; float targetY = _contentOffset.y - dy;
// convert back to content offset (fpx = -contentOffset.x)
setContentOffset(Vec3(-nfpx, -nfpy, 0)); if (isSet(SF_LockX)) targetX = _contentOffset.x;
if (isSet(SF_LockY)) targetY = _contentOffset.y;
if (isSet(SF_HardLimits)) {
targetX = Mth::clamp(targetX, minPoint.x, 0.0f);
targetY = Mth::clamp(targetY, minPoint.y, 0.0f);
} else {
if (targetX > 0.0f) {
float overshoot = targetX;
overshoot = Mth::Min(overshoot, kWheelOverscrollMax);
targetX = overshoot * kWheelOverscrollDamping;
} else if (targetX < minPoint.x) {
float overshoot = targetX - minPoint.x;
overshoot = Mth::Max(overshoot, -kWheelOverscrollMax);
targetX = minPoint.x + overshoot * kWheelOverscrollDamping;
}
if (targetY > 0.0f) {
float overshoot = targetY;
overshoot = Mth::Min(overshoot, kWheelOverscrollMax);
targetY = overshoot * kWheelOverscrollDamping;
} else if (targetY < minPoint.y) {
float overshoot = targetY - minPoint.y;
overshoot = Mth::Max(overshoot, -kWheelOverscrollMax);
targetY = minPoint.y + overshoot * kWheelOverscrollDamping;
}
}
setContentOffset(Vec3(targetX, targetY, 0));
} }
void ScrollingPane::setContentOffset(float x, float y) { void ScrollingPane::setContentOffset(float x, float y) {

View File

@@ -2,6 +2,7 @@
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../renderer/Textures.h" #include "../../renderer/Textures.h"
#include "../Screen.h" #include "../Screen.h"
#include "../../../locale/I18n.h"
#include "../../../util/Mth.h" #include "../../../util/Mth.h"
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
@@ -21,7 +22,7 @@ void Slider::render( Minecraft* minecraft, int xm, int ym ) {
if (m_numSteps > 2) { if (m_numSteps > 2) {
int stepDistance = barWidth / (m_numSteps-1); int stepDistance = barWidth / (m_numSteps-1);
for(int a = 0; a <= m_numSteps; ++a) { 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);
} }
@@ -64,15 +65,20 @@ SliderFloat::SliderFloat(Minecraft* minecraft, OptionId option)
SliderInt::SliderInt(Minecraft* minecraft, OptionId option) SliderInt::SliderInt(Minecraft* minecraft, OptionId option)
: Slider(option), m_option(dynamic_cast<OptionInt*>(minecraft->options.getOpt(option))) : Slider(option), m_option(dynamic_cast<OptionInt*>(minecraft->options.getOpt(option)))
{ {
m_numSteps = m_option->getMax() - m_option->getMin(); m_numSteps = m_option->getMax() - m_option->getMin() + 1;
m_percentage = float(m_option->get() - m_option->getMin()) / (m_numSteps-1); m_percentage = float(m_option->get() - m_option->getMin()) / (m_numSteps-1);
} }
void SliderInt::render( Minecraft* minecraft, int xm, int ym ) {
Slider::render(minecraft, xm, ym);
}
void SliderInt::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { void SliderInt::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) {
Slider::mouseReleased(minecraft, x, y, buttonNum); Slider::mouseReleased(minecraft, x, y, buttonNum);
if (pointInside(x, y)) { if (pointInside(x, y)) {
int curStep = Mth::floor(m_percentage * (m_numSteps-1)); int curStep = int(m_percentage * (m_numSteps-1) + 0.5f);
curStep = Mth::clamp(curStep + m_option->getMin(), m_option->getMin(), m_option->getMax());
m_percentage = float(curStep - m_option->getMin()) / (m_numSteps-1); m_percentage = float(curStep - m_option->getMin()) / (m_numSteps-1);
minecraft->options.set(m_optId, curStep); minecraft->options.set(m_optId, curStep);

View File

@@ -38,6 +38,7 @@ class SliderInt : public Slider {
public: public:
SliderInt(Minecraft* minecraft, OptionId option); SliderInt(Minecraft* minecraft, OptionId option);
virtual void render( Minecraft* minecraft, int xm, int ym ) override;
virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) override; virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) override;
protected: protected:

View File

@@ -31,7 +31,7 @@ ConfirmScreen::~ConfirmScreen() {
void ConfirmScreen::init() void ConfirmScreen::init()
{ {
if (minecraft->useTouchscreen()) { if (/* minecraft->useTouchscreen() */ true) {
yesButton = new Touch::TButton(0, 0, 0, yesButtonText), yesButton = new Touch::TButton(0, 0, 0, yesButtonText),
noButton = new Touch::TButton(1, 0, 0, noButtonText); noButton = new Touch::TButton(1, 0, 0, noButtonText);
} else { } else {

View File

@@ -8,6 +8,7 @@
#include "../../../network/ServerSideNetworkHandler.h" #include "../../../network/ServerSideNetworkHandler.h"
#include "../../../network/packet/ChatPacket.h" #include "../../../network/packet/ChatPacket.h"
#include "../../../platform/log.h" #include "../../../platform/log.h"
#include "util/StringUtils.h"
#include <sstream> #include <sstream>
#include <cstdlib> #include <cstdlib>
@@ -54,141 +55,37 @@ void ConsoleScreen::charPressed(char inputChar)
_input += inputChar; _input += inputChar;
} }
// ---------------------------------------------------------------------------
// execute: run _input as a command, print result, close screen
// ---------------------------------------------------------------------------
void ConsoleScreen::execute() void ConsoleScreen::execute()
{ {
if (!minecraft->level) return;
if (_input.empty()) { if (_input.empty()) {
minecraft->setScreen(NULL); return minecraft->setScreen(NULL);
return;
} }
if (_input[0] == '/') { if (_input[0] == '/') {
// Command // Command
std::string result = processCommand(_input); _input = Util::stringTrim(_input.substr(1));
if (!result.empty())
minecraft->gui.addMessage(result); std::istringstream iss(minecraft->commandManager().execute(*minecraft, *minecraft->player, _input));
for (std::string line; std::getline(iss, line); ) {
minecraft->gui.addMessage(line);
}
} else { } else {
// Chat message: <name> message // @ai @rewrite
std::string msg = std::string("<") + minecraft->player->name + "> " + _input;
if (minecraft->netCallback && minecraft->raknetInstance->isServer()) { if (minecraft->netCallback && minecraft->raknetInstance->isServer()) {
// Hosting a LAN game: displayGameMessage shows locally + broadcasts MessagePacket to clients static_cast<ServerSideNetworkHandler*>(minecraft->netCallback)->displayGameMessage(_input);
static_cast<ServerSideNetworkHandler*>(minecraft->netCallback)->displayGameMessage(msg);
} else if (minecraft->netCallback) { } else if (minecraft->netCallback) {
// Connected client: send ChatPacket to server; server echoes it back as MessagePacket ChatPacket chatPkt(_input);
ChatPacket chatPkt(msg);
minecraft->raknetInstance->send(chatPkt); minecraft->raknetInstance->send(chatPkt);
} else { } else {
// Singleplayer: show locally only minecraft->gui.addMessage("<" + minecraft->player->name + "> " + _input);
minecraft->gui.addMessage(msg);
} }
} }
minecraft->setScreen(NULL); 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 // render
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -216,8 +113,5 @@ void ConsoleScreen::render(int /*xm*/, int /*ym*/, float /*a*/)
displayed += '_'; displayed += '_';
// Placeholder hint when empty // 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); font->drawShadow(displayed, (float)(boxX0 + 2), (float)(boxY + 2), 0xffffffff);
} }

View File

@@ -25,7 +25,6 @@ public:
private: private:
void execute(); void execute();
std::string processCommand(const std::string& cmd);
std::string _input; std::string _input;
int _cursorBlink; // tick counter for cursor blink int _cursorBlink; // tick counter for cursor blink

View File

@@ -28,6 +28,7 @@ void CreditsScreen::init() {
buttons.push_back(bHeader); buttons.push_back(bHeader);
buttons.push_back(btnBack); buttons.push_back(btnBack);
// TODO: rewrite it
// prepare text lines // prepare text lines
_lines.clear(); _lines.clear();
_lines.push_back("Minecraft: Pocket Edition"); _lines.push_back("Minecraft: Pocket Edition");
@@ -39,6 +40,7 @@ void CreditsScreen::init() {
_lines.push_back("Kolyah35"); _lines.push_back("Kolyah35");
_lines.push_back("karson"); _lines.push_back("karson");
_lines.push_back("deepfriedwaffles"); _lines.push_back("deepfriedwaffles");
_lines.push_back("EpikIzCool");
_lines.push_back(""); _lines.push_back("");
// avoid color tags around the URL so it isn't mangled by the parser please // 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"); _lines.push_back("Join our Discord server: https://discord.gg/c58YesBxve");

View File

@@ -23,7 +23,7 @@ DeathScreen::~DeathScreen()
void DeathScreen::init() void DeathScreen::init()
{ {
if (minecraft->useTouchscreen()) { if (/* minecraft->useTouchscreen() */ true) {
bRespawn = new Touch::TButton(1, "Respawn!"); bRespawn = new Touch::TButton(1, "Respawn!");
bTitle = new Touch::TButton(2, "Main menu"); bTitle = new Touch::TButton(2, "Main menu");
} else { } else {

View File

@@ -21,7 +21,7 @@ public:
} }
void init() { void init() {
if (minecraft->useTouchscreen()) if (/* minecraft->useTouchscreen() */ true)
_back = new Touch::TButton(1, "Ok"); _back = new Touch::TButton(1, "Ok");
else else
_back = new Button(1, "Ok"); _back = new Button(1, "Ok");

View File

@@ -17,7 +17,7 @@ InBedScreen::~InBedScreen() {
} }
void InBedScreen::init() { void InBedScreen::init() {
if (minecraft->useTouchscreen()) { if (/* minecraft->useTouchscreen() */ true) {
bWakeUp = new Touch::TButton(1, "Leave Bed"); bWakeUp = new Touch::TButton(1, "Leave Bed");
} else { } else {
bWakeUp = new Button(1, "Leave Bed"); bWakeUp = new Button(1, "Leave Bed");

View File

@@ -19,7 +19,6 @@ OptionsScreen::OptionsScreen()
} }
OptionsScreen::~OptionsScreen() { OptionsScreen::~OptionsScreen() {
if (btnClose != NULL) { if (btnClose != NULL) {
delete btnClose; delete btnClose;
btnClose = NULL; btnClose = NULL;
@@ -53,7 +52,6 @@ OptionsScreen::~OptionsScreen() {
} }
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, "");
@@ -89,7 +87,6 @@ void OptionsScreen::init() {
} }
void OptionsScreen::setupPositions() { void OptionsScreen::setupPositions() {
int buttonHeight = btnClose->height; int buttonHeight = btnClose->height;
btnClose->x = width - btnClose->width; btnClose->x = width - btnClose->width;
@@ -134,7 +131,6 @@ void OptionsScreen::setupPositions() {
void OptionsScreen::render(int xm, int ym, float a) { void OptionsScreen::render(int xm, int ym, float a) {
renderBackground(); renderBackground();
int xmm = xm * width / minecraft->width; int xmm = xm * width / minecraft->width;
@@ -150,11 +146,14 @@ void OptionsScreen::removed() {
} }
void OptionsScreen::buttonClicked(Button* button) { void OptionsScreen::buttonClicked(Button* button) {
if (button == btnClose) { if (button == btnClose) {
minecraft->options.save(); minecraft->options.save();
if (minecraft->screen != NULL) {
minecraft->setScreen(NULL);
} else {
minecraft->screenChooser.setScreen(SCREEN_STARTMENU); minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
} }
}
else if (button->id > 1 && button->id < 7) { 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);
@@ -165,7 +164,6 @@ void OptionsScreen::buttonClicked(Button* button) {
} }
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) { for (std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
@@ -209,7 +207,8 @@ void OptionsScreen::generateOptionScreens() {
// // Controls Pane // // Controls Pane
optionPanes[2]->addOptionItem(OPTIONS_INVERT_Y_MOUSE, minecraft) optionPanes[2]->addOptionItem(OPTIONS_INVERT_Y_MOUSE, minecraft)
.addOptionItem(OPTIONS_USE_TOUCHSCREEN, minecraft); .addOptionItem(OPTIONS_USE_TOUCHSCREEN, minecraft)
.addOptionItem(OPTIONS_AUTOJUMP, minecraft);
for (int i = OPTIONS_KEY_FORWARD; i <= OPTIONS_KEY_USE; i++) { for (int i = OPTIONS_KEY_FORWARD; i <= OPTIONS_KEY_USE; i++) {
optionPanes[2]->addOptionItem((OptionId)i, minecraft); optionPanes[2]->addOptionItem((OptionId)i, minecraft);
@@ -217,9 +216,6 @@ void OptionsScreen::generateOptionScreens() {
// // Graphics Pane // // Graphics Pane
optionPanes[3]->addOptionItem(OPTIONS_FANCY_GRAPHICS, minecraft) optionPanes[3]->addOptionItem(OPTIONS_FANCY_GRAPHICS, minecraft)
// .addOptionItem(&Options::Option::VIEW_BOBBING, minecraft)
// .addOptionItem(&Options::Option::AMBIENT_OCCLUSION, minecraft)
// .addOptionItem(&Options::Option::ANAGLYPH, minecraft)
.addOptionItem(OPTIONS_LIMIT_FRAMERATE, minecraft) .addOptionItem(OPTIONS_LIMIT_FRAMERATE, minecraft)
.addOptionItem(OPTIONS_VSYNC, minecraft) .addOptionItem(OPTIONS_VSYNC, minecraft)
.addOptionItem(OPTIONS_RENDER_DEBUG, minecraft) .addOptionItem(OPTIONS_RENDER_DEBUG, minecraft)
@@ -228,11 +224,11 @@ void OptionsScreen::generateOptionScreens() {
.addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft); .addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft);
optionPanes[4]->addOptionItem(OPTIONS_ALLOW_SPRINT, minecraft) optionPanes[4]->addOptionItem(OPTIONS_ALLOW_SPRINT, minecraft)
.addOptionItem(OPTIONS_BAR_ON_TOP, minecraft); .addOptionItem(OPTIONS_BAR_ON_TOP, minecraft)
.addOptionItem(OPTIONS_RPI_CURSOR, minecraft);
} }
void OptionsScreen::mouseClicked(int x, int y, int buttonNum) { void OptionsScreen::mouseClicked(int x, int y, int buttonNum) {
if (currentOptionsGroup != NULL) if (currentOptionsGroup != NULL)
currentOptionsGroup->mouseClicked(minecraft, x, y, buttonNum); currentOptionsGroup->mouseClicked(minecraft, x, y, buttonNum);
@@ -240,7 +236,6 @@ void OptionsScreen::mouseClicked(int x, int y, int buttonNum) {
} }
void OptionsScreen::mouseReleased(int x, int y, int buttonNum) { void OptionsScreen::mouseReleased(int x, int y, int buttonNum) {
if (currentOptionsGroup != NULL) if (currentOptionsGroup != NULL)
currentOptionsGroup->mouseReleased(minecraft, x, y, buttonNum); currentOptionsGroup->mouseReleased(minecraft, x, y, buttonNum);

View File

@@ -5,12 +5,16 @@
#include "../../../util/Mth.h" #include "../../../util/Mth.h"
#include "../../../network/RakNetInstance.h" #include "../../../network/RakNetInstance.h"
#include "../../../network/ServerSideNetworkHandler.h" #include "../../../network/ServerSideNetworkHandler.h"
#include "client/Options.h"
#include "client/gui/components/Button.h"
#include "client/gui/screens/OptionsScreen.h"
PauseScreen::PauseScreen(bool wasBackPaused) PauseScreen::PauseScreen(bool wasBackPaused)
: saveStep(0), : saveStep(0),
visibleTime(0), visibleTime(0),
bContinue(0), bContinue(0),
bQuit(0), bQuit(0),
bOptions(0),
bQuitAndSaveLocally(0), bQuitAndSaveLocally(0),
bServerVisibility(0), bServerVisibility(0),
// bThirdPerson(0), // bThirdPerson(0),
@@ -39,18 +43,21 @@ PauseScreen::~PauseScreen() {
delete bQuit; delete bQuit;
delete bQuitAndSaveLocally; delete bQuitAndSaveLocally;
delete bServerVisibility; delete bServerVisibility;
delete bOptions;
// delete bThirdPerson; // delete bThirdPerson;
} }
void PauseScreen::init() { void PauseScreen::init() {
if (minecraft->useTouchscreen()) { if (/* minecraft->useTouchscreen() */ true) {
bContinue = new Touch::TButton(1, "Back to game"); bContinue = new Touch::TButton(1, "Back to game");
bOptions = new Touch::TButton(5, "Options");
bQuit = new Touch::TButton(2, "Quit to title"); bQuit = new Touch::TButton(2, "Quit to title");
bQuitAndSaveLocally = new Touch::TButton(3, "Quit and copy map"); bQuitAndSaveLocally = new Touch::TButton(3, "Quit and copy map");
bServerVisibility = new Touch::TButton(4, ""); bServerVisibility = new Touch::TButton(4, "");
// bThirdPerson = new Touch::TButton(5, "Toggle 3:rd person view"); // bThirdPerson = new Touch::TButton(5, "Toggle 3:rd person view");
} else { } else {
bContinue = new Button(1, "Back to game"); bContinue = new Button(1, "Back to game");
bOptions = new Button(5, "Options");
bQuit = new Button(2, "Quit to title"); bQuit = new Button(2, "Quit to title");
bQuitAndSaveLocally = new Button(3, "Quit and copy map"); bQuitAndSaveLocally = new Button(3, "Quit and copy map");
bServerVisibility = new Button(4, ""); bServerVisibility = new Button(4, "");
@@ -59,7 +66,7 @@ void PauseScreen::init() {
buttons.push_back(bContinue); buttons.push_back(bContinue);
buttons.push_back(bQuit); buttons.push_back(bQuit);
buttons.push_back(bOptions);
// bSound.updateImage(&minecraft->options); // bSound.updateImage(&minecraft->options);
bThirdPerson.updateImage(&minecraft->options); bThirdPerson.updateImage(&minecraft->options);
bHideGui.updateImage(&minecraft->options); bHideGui.updateImage(&minecraft->options);
@@ -99,21 +106,24 @@ void PauseScreen::setupPositions() {
saveStep = 0; saveStep = 0;
int yBase = 16; int yBase = 16;
bContinue->width = bQuit->width = /*bThirdPerson->w =*/ 160; bContinue->width = bOptions->width = bQuit->width = /*bThirdPerson->w =*/ 160;
bQuitAndSaveLocally->width = bServerVisibility->width = 160; bQuitAndSaveLocally->width = bServerVisibility->width = 160;
bContinue->x = (width - bContinue->width) / 2; bContinue->x = (width - bContinue->width) / 2;
bContinue->y = yBase + 32 * 1; bContinue->y = yBase + 32 * 1;
bOptions->x = (width - bOptions->width) / 2;
bOptions->y = yBase + 32 * 2;
bQuit->x = (width - bQuit->width) / 2; bQuit->x = (width - bQuit->width) / 2;
bQuit->y = yBase + 32 * 2; bQuit->y = yBase + 32 * 3;
#if APPLE_DEMO_PROMOTION #if APPLE_DEMO_PROMOTION
bQuit->y += 16; bQuit->y += 16;
#endif #endif
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 * 4;
// bSound.y = bThirdPerson.y = 8; // bSound.y = bThirdPerson.y = 8;
// bSound.x = 4; // bSound.x = 4;
@@ -157,7 +167,9 @@ void PauseScreen::buttonClicked(Button* button) {
if (button->id == bQuitAndSaveLocally->id) { if (button->id == bQuitAndSaveLocally->id) {
minecraft->leaveGame(true); minecraft->leaveGame(true);
} }
if (button->id == bOptions->id) {
minecraft->setScreen(new OptionsScreen());
}
if (button->id == bServerVisibility->id) { if (button->id == bServerVisibility->id) {
if (minecraft->raknetInstance && minecraft->netCallback && minecraft->raknetInstance->isServer()) { if (minecraft->raknetInstance && minecraft->netCallback && minecraft->raknetInstance->isServer()) {
ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) minecraft->netCallback; ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) minecraft->netCallback;

View File

@@ -33,7 +33,9 @@ private:
Button* bQuit; Button* bQuit;
Button* bQuitAndSaveLocally; Button* bQuitAndSaveLocally;
Button* bServerVisibility; Button* bServerVisibility;
// Button* bThirdPerson; Button* bOptions;
// Button* bThirdPerson;
// OptionButton bSound; // OptionButton bSound;
OptionButton bThirdPerson; OptionButton bThirdPerson;

View File

@@ -11,6 +11,8 @@ public:
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
bool isInGameScreen(); bool isInGameScreen();
virtual void keyPressed(int eventKey) {}
void tick(); void tick();
private: private:
int ticks; int ticks;

View File

@@ -4,6 +4,7 @@
#include "JoinGameScreen.h" #include "JoinGameScreen.h"
#include "PauseScreen.h" #include "PauseScreen.h"
#include "RenameMPLevelScreen.h" #include "RenameMPLevelScreen.h"
#include "ConsoleScreen.h"
#include "IngameBlockSelectionScreen.h" #include "IngameBlockSelectionScreen.h"
#include "JoinByIPScreen.h" #include "JoinByIPScreen.h"
#include "touch/TouchStartMenuScreen.h" #include "touch/TouchStartMenuScreen.h"
@@ -19,7 +20,8 @@ Screen* ScreenChooser::createScreen( ScreenId id )
{ {
Screen* screen = NULL; Screen* screen = NULL;
if (_mc->useTouchscreen()) { // :sob:
if (/* _mc->useTouchscreen() */ true) {
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;
@@ -28,6 +30,7 @@ Screen* ScreenChooser::createScreen( ScreenId id )
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_JOINBYIP: screen = new JoinByIPScreen(); break;
case SCREEN_CONSOLE: screen = new ConsoleScreen(); break;
case SCREEN_NONE: case SCREEN_NONE:
default: default:
// Do nothing // Do nothing
@@ -42,7 +45,7 @@ Screen* ScreenChooser::createScreen( ScreenId id )
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_JOINBYIP: screen = new JoinByIPScreen(); break;
case SCREEN_CONSOLE: screen = new ConsoleScreen(); break;
case SCREEN_NONE: case SCREEN_NONE:
default: default:
// Do nothing // Do nothing

View File

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

View File

@@ -56,7 +56,7 @@ void SimpleChooseLevelScreen::init()
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
bBack->setImageDef(def, true); bBack->setImageDef(def, true);
} }
if (minecraft->useTouchscreen()) { if (/* minecraft->useTouchscreen() */ true) {
bGamemode = new Touch::TButton(1, "Survival mode"); bGamemode = new Touch::TButton(1, "Survival mode");
bCheats = new Touch::TButton(4, "Cheats: Off"); bCheats = new Touch::TButton(4, "Cheats: Off");
bCreate = new Touch::TButton(3, "Create"); bCreate = new Touch::TButton(3, "Create");

View File

@@ -16,7 +16,12 @@
#include "../../../../world/level/Level.h" #include "../../../../world/level/Level.h"
#include "../../../../world/item/DyePowderItem.h" #include "../../../../world/item/DyePowderItem.h"
#include "../../../../world/item/crafting/Recipe.h" #include "../../../../world/item/crafting/Recipe.h"
#include "network/RakNetInstance.h"
#include "network/packet/WantCreatePacket.h"
#include "platform/input/Keyboard.h" #include "platform/input/Keyboard.h"
#include <cstdint>
#include <iostream>
#include <string>
static NinePatchLayer* guiPaneFrame = NULL; static NinePatchLayer* guiPaneFrame = NULL;
@@ -41,7 +46,7 @@ public:
//fill(x+1, y+1, x+w-1, y+h-1, 0xff999999); //fill(x+1, y+1, x+w-1, y+h-1, 0xff999999);
bool hovered = active && (minecraft->useTouchscreen()? bool hovered = active && (minecraft->useTouchscreen()?
(_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : false); (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym));
if (hovered || *selectedPtr == this) if (hovered || *selectedPtr == this)
statePressed->draw(Tesselator::instance, (float)x, (float)y); statePressed->draw(Tesselator::instance, (float)x, (float)y);
@@ -193,6 +198,26 @@ void PaneCraftingScreen::setupPositions() {
} }
void PaneCraftingScreen::tick() { void PaneCraftingScreen::tick() {
if (minecraft->isOnline()) {
// TODO: Make better algorithm
static std::map<uint8_t, uint16_t> oldMap = {};
std::map<uint8_t, uint16_t> newMap = {};
for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) {
auto itm = minecraft->player->inventory->getItem(i);
if (itm != NULL) {
newMap[itm->id] += itm->count;
}
}
if (oldMap != newMap) {
oldMap = newMap;
newMap = {};
recheckRecipes();
}
}
if (pane) pane->tick(); if (pane) pane->tick();
} }
@@ -439,6 +464,10 @@ void PaneCraftingScreen::craftSelectedItem()
ItemInstance resultItem = currentItem->item; ItemInstance resultItem = currentItem->item;
if (minecraft->player) { if (minecraft->player) {
if (minecraft->isOnline()) {
WantCreatePacket packet(minecraft->player->entityId, resultItem.count, resultItem.getAuxValue(), resultItem.id);
minecraft->raknetInstance->send(packet);
}
// Remove all items required for the recipe and ... // Remove all items required for the recipe and ...
for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) {
CItem::ReqItem& req = currentItem->neededItems[i]; CItem::ReqItem& req = currentItem->neededItems[i];
@@ -547,7 +576,7 @@ void CraftButton::renderBg(Minecraft* minecraft, int xm, int ym) {
//fill(x+1, y+1, x+w-1, y+h-1, 0xff999999); //fill(x+1, y+1, x+w-1, y+h-1, 0xff999999);
bool hovered = active && (minecraft->useTouchscreen()? bool hovered = active && (minecraft->useTouchscreen()?
(_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : false); (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym));
if (hovered || selected) if (hovered || selected)
bgSelected->draw(Tesselator::instance, (float)x, (float)y); bgSelected->draw(Tesselator::instance, (float)x, (float)y);

View File

@@ -91,7 +91,8 @@ void IngameBlockSelectionScreen::init()
//for (int i = 0; i < inventory->getContainerSize(); ++i) //for (int i = 0; i < inventory->getContainerSize(); ++i)
//LOGI("> %d - %s\n", i, inventory->getItem(i)? inventory->getItem(i)->getDescriptionId().c_str() : "<-->\n"); //LOGI("> %d - %s\n", i, inventory->getItem(i)? inventory->getItem(i)->getDescriptionId().c_str() : "<-->\n");
InventorySize = inventory->getContainerSize(); // Grid indices are 0..N-1 for main inventory only; slots 0..MAX_SELECTION_SIZE-1 are hotbar links.
InventorySize = inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE;
InventoryRows = 1 + (InventorySize-1) / InventoryColumns; InventoryRows = 1 + (InventorySize-1) / InventoryColumns;
// //
@@ -265,7 +266,8 @@ void IngameBlockSelectionScreen::buttonClicked(Button* button) {
bool IngameBlockSelectionScreen::isAllowed( int slot ) bool IngameBlockSelectionScreen::isAllowed( int slot )
{ {
if (slot < 0 || slot >= minecraft->player->inventory->getContainerSize()) const int gridCount = minecraft->player->inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE;
if (slot < 0 || slot >= gridCount)
return false; return false;
#ifdef DEMO_MODE #ifdef DEMO_MODE

View File

@@ -24,12 +24,15 @@
#include "../../platform/HttpClient.h" #include "../../platform/HttpClient.h"
#include "../../platform/CThread.h" #include "../../platform/CThread.h"
#include "../../util/StringUtils.h" #include "../../util/StringUtils.h"
#include "client/Options.h"
#if defined(_WIN32) #if defined(_WIN32)
#include <direct.h> #include <direct.h>
#include <sys/stat.h>
#else #else
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <errno.h>
#endif #endif
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
@@ -185,6 +188,33 @@ static bool ensureDirectoryExists(const std::string& path) {
return _mkdir(path.c_str()) == 0 || errno == EEXIST; return _mkdir(path.c_str()) == 0 || errno == EEXIST;
#else #else
struct stat st; struct stat st;
if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode))
return true;
std::string subPath;
size_t i = 0;
while (i < path.length()) {
i = path.find_first_of("/\\", i);
if (i == std::string::npos) {
subPath = path;
} else {
subPath = path.substr(0, i);
}
if (!subPath.empty()) {
if (stat(subPath.c_str(), &st) != 0) {
if (mkdir(subPath.c_str(), 0755) != 0 && errno != EEXIST)
return false;
} else if (!S_ISDIR(st.st_mode)) {
return false;
}
}
if (i == std::string::npos)
break;
i += 1;
}
if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode))
return true; return true;
return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST; return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST;
@@ -226,6 +256,7 @@ static void* fetchSkinForPlayer(void* param) {
std::string skinUrl = getSkinUrlForUsername(player->name); std::string skinUrl = getSkinUrlForUsername(player->name);
if (skinUrl.empty()) { if (skinUrl.empty()) {
LOGW("[Skin] skin URL lookup failed for %s\n", player->name.c_str()); LOGW("[Skin] skin URL lookup failed for %s\n", player->name.c_str());
player->setTextureName("mob/char.png");
return NULL; return NULL;
} }
@@ -233,6 +264,7 @@ static void* fetchSkinForPlayer(void* param) {
std::vector<unsigned char> skinData; std::vector<unsigned char> skinData;
if (!HttpClient::download(skinUrl, skinData) || skinData.empty()) { if (!HttpClient::download(skinUrl, skinData) || skinData.empty()) {
LOGW("[Skin] download failed for %s\n", skinUrl.c_str()); LOGW("[Skin] download failed for %s\n", skinUrl.c_str());
player->setTextureName("mob/char.png");
return NULL; return NULL;
} }
@@ -246,6 +278,7 @@ static void* fetchSkinForPlayer(void* param) {
player->setTextureName("skins/" + player->name + ".png"); player->setTextureName("skins/" + player->name + ".png");
} else { } else {
LOGW("[Skin] failed to write skin cache %s\n", cacheFile.c_str()); LOGW("[Skin] failed to write skin cache %s\n", cacheFile.c_str());
player->setTextureName("mob/char.png");
} }
return NULL; return NULL;
@@ -326,10 +359,13 @@ LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, const std::string&
{ {
this->dimension = dimension; this->dimension = dimension;
_init(); _init();
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
if (!name.empty()) {
this->name = name; if (minecraft->options.getStringValue(OPTIONS_USERNAME).size() != 0) {
textureName = "mob/char.png";
this->name = minecraft->options.getStringValue(OPTIONS_USERNAME);
printf("test \n");
// Fetch user skin and cape from Mojang servers in the background (avoids blocking the main thread) // Fetch user skin and cape from Mojang servers in the background (avoids blocking the main thread)
// TODO: Fix this memory leak // TODO: Fix this memory leak
new CThread(fetchSkinForPlayer, this); new CThread(fetchSkinForPlayer, this);
@@ -352,6 +388,12 @@ void LocalPlayer::calculateFlight(float xa, float ya, float za) {
ya = 0; ya = 0;
za = za * flySpeed; za = za * flySpeed;
if (sprinting) {
float sprintBoost = getWalkingSpeedModifier(); // 1.3x
xa *= sprintBoost;
za *= sprintBoost;
}
#ifdef ANDROID #ifdef ANDROID
if (Keyboard::isKeyDown(103)) ya = .2f * flySpeed; if (Keyboard::isKeyDown(103)) ya = .2f * flySpeed;
if (Keyboard::isKeyDown(102)) ya = -.2f * flySpeed; if (Keyboard::isKeyDown(102)) ya = -.2f * flySpeed;
@@ -414,7 +456,7 @@ void LocalPlayer::tick() {
{ {
sentInventoryItemId = newItemId; sentInventoryItemId = newItemId;
sentInventoryItemData = newItemData; sentInventoryItemData = newItemData;
PlayerEquipmentPacket packet(entityId, newItemId, newItemData); PlayerEquipmentPacket packet(entityId, newItemId, newItemData, inventory->selected, inventory->getSlot(newItemId, newItemData));
minecraft->raknetInstance->send(packet); minecraft->raknetInstance->send(packet);
} }
} }
@@ -470,7 +512,7 @@ void LocalPlayer::aiStep() {
if (sprintDoubleTapTimer > 0) sprintDoubleTapTimer--; if (sprintDoubleTapTimer > 0) sprintDoubleTapTimer--;
prevForwardHeld = forwardHeld; prevForwardHeld = forwardHeld;
} }
if (input->sneaking || abilities.flying) if (input->sneaking)
sprinting = false; sprinting = false;
if (input->sneaking) { if (input->sneaking) {

View File

@@ -50,10 +50,8 @@ void KeyboardInput::tick( Player* player )
ya *= 0.3f; ya *= 0.3f;
} }
#if defined(RPI) || defined(PLATFORM_DESKTOP)
wantUp = jumping; wantUp = jumping;
wantDown = sneaking; wantDown = sneaking;
#endif
if (keys[KEY_CRAFT]) if (keys[KEY_CRAFT])
player->startCrafting((int)player->x, (int)player->y, (int)player->z, Recipe::SIZE_2X2); player->startCrafting((int)player->x, (int)player->y, (int)player->z, Recipe::SIZE_2X2);

View File

@@ -426,9 +426,7 @@ public:
virtual void onConfigChanged(const Config& c) { virtual void onConfigChanged(const Config& c) {
_move.onConfigChanged(c); _move.onConfigChanged(c);
_turnBuild.moveArea = _move.getRectangleArea(); _turnBuild.moveArea = _move.getRectangleArea();
#ifdef __APPLE__
_turnBuild.pauseArea = _move.getPauseRectangleArea(); _turnBuild.pauseArea = _move.getPauseRectangleArea();
#endif
_turnBuild.inventoryArea = _mc->gui.getRectangleArea( _mc->options.getBooleanValue(OPTIONS_IS_LEFT_HANDED)? 1 : -1 ); _turnBuild.inventoryArea = _mc->gui.getRectangleArea( _mc->options.getBooleanValue(OPTIONS_IS_LEFT_HANDED)? 1 : -1 );
_turnBuild.setSensitivity(c.options->getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA)? 1.8f : 1.0f); _turnBuild.setSensitivity(c.options->getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA)? 1.8f : 1.0f);
((ITurnInput*)&_turnBuild)->onConfigChanged(c); ((ITurnInput*)&_turnBuild)->onConfigChanged(c);

View File

@@ -9,7 +9,10 @@
#include "../../../../platform/log.h" #include "../../../../platform/log.h"
#include "../../../renderer/Textures.h" #include "../../../renderer/Textures.h"
#include "../../../sound/SoundEngine.h" #include "../../../sound/SoundEngine.h"
#include "client/gui/screens/ScreenChooser.h"
// ARGHHHHHH WHY NOT FUCKING ENUM
static const int AREA_DPAD_FIRST = 100; static const int AREA_DPAD_FIRST = 100;
static const int AREA_DPAD_N = 100; static const int AREA_DPAD_N = 100;
static const int AREA_DPAD_S = 101; static const int AREA_DPAD_S = 101;
@@ -17,6 +20,7 @@ static const int AREA_DPAD_W = 102;
static const int AREA_DPAD_E = 103; static const int AREA_DPAD_E = 103;
static const int AREA_DPAD_C = 104; static const int AREA_DPAD_C = 104;
static const int AREA_PAUSE = 105; static const int AREA_PAUSE = 105;
static const int AREA_CHAT = 106;
static int cPressed = 0; static int cPressed = 0;
static int cReleased = 0; static int cReleased = 0;
@@ -126,8 +130,8 @@ void TouchscreenInput_TestFps::onConfigChanged(const Config& c) {
// If too large (like playing on Tablet) // If too large (like playing on Tablet)
PixelCalc& pc = _minecraft->pixelCalc; PixelCalc& pc = _minecraft->pixelCalc;
if (pc.pixelsToMillimeters(Bw) > 14) { if (pc.pixelsToMillimeters(Bw) > 200) { //14
Bw = Bh = pc.millimetersToPixels(14); Bw = Bh = pc.millimetersToPixels(200); //14
} }
// temp data // temp data
float xx; float xx;
@@ -158,14 +162,11 @@ void TouchscreenInput_TestFps::onConfigChanged(const Config& c) {
xx = BaseX + 2 * Bw; yy = BaseY + Bh; xx = BaseX + 2 * Bw; yy = BaseY + Bh;
_model.addArea(AREA_DPAD_E, aRight = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); _model.addArea(AREA_DPAD_E, aRight = new RectangleArea(xx, yy, xx+Bw, yy+Bh));
#ifdef __APPLE__
float maxPixels = _minecraft->pixelCalc.millimetersToPixels(10); float maxPixels = _minecraft->pixelCalc.millimetersToPixels(10);
float btnSize = Mth::Min(18 * Gui::GuiScale, maxPixels); // float btnSize = Mth::Min(18 * Gui::GuiScale, maxPixels);
_model.addArea(AREA_PAUSE, aPause = new RectangleArea(w - 4 - btnSize, float btnSize = pc.millimetersToPixels(18 * Gui::GuiScale);
4, _model.addArea(AREA_PAUSE, aPause = new RectangleArea(w - 4 - btnSize, 4, w - 4, 4 + btnSize));
w - 4, _model.addArea(AREA_CHAT, aChat = new RectangleArea(w - 8 - btnSize * 2, 4, w - 8 - btnSize, 4 + btnSize));
4 + btnSize));
#endif /* __APPLE__ */
//rebuild(); //rebuild();
} }
@@ -309,14 +310,20 @@ void TouchscreenInput_TestFps::tick( Player* player )
setButton = true; setButton = true;
xa -= 1; xa -= 1;
} }
#ifdef __APPLE__
else if (areaId == AREA_PAUSE) { else if (areaId == AREA_PAUSE) {
if (Multitouch::isReleased(p)) { if (Multitouch::isReleased(p)) {
_minecraft->soundEngine->playUI("random.click", 1, 1); _minecraft->soundEngine->playUI("random.click", 1, 1);
_minecraft->screenChooser.setScreen(SCREEN_PAUSE); _minecraft->screenChooser.setScreen(SCREEN_PAUSE);
} }
} }
#endif /*__APPLE__*/ else if (areaId == AREA_CHAT) {
if (Multitouch::isReleased(p)) {
_minecraft->soundEngine->playUI("random.click", 1, 1);
_minecraft->screenChooser.setScreen(SCREEN_CONSOLE);
_minecraft->platform()->showKeyboard();
}
}
_buttons[areaId - AREA_DPAD_FIRST] = setButton; _buttons[areaId - AREA_DPAD_FIRST] = setButton;
} }
@@ -499,15 +506,14 @@ void TouchscreenInput_TestFps::rebuild() {
drawRectangleArea(t, aJump, imageU + imageSize * 4, imageV, (float)imageSize); drawRectangleArea(t, aJump, imageU + imageSize * 4, imageV, (float)imageSize);
} }
#ifdef __APPLE__
if (!_minecraft->screen) { if (!_minecraft->screen) {
if (isButtonDown(AREA_PAUSE)) t.colorABGR(cPressedPause); t.colorABGR(0xFFFFFFFF);
else t.colorABGR(cReleasedPause); // if (isButtonDown(AREA_PAUSE)) t.colorABGR(cPressedPause);
// else t.colorABGR(cReleasedPause);
drawRectangleArea(t, aPause, 200, 64, 18.0f); drawRectangleArea(t, aPause, 200, 64, 18.0f);
drawRectangleArea(t, aChat, 200, 82, 18.0f);
} }
#endif /*__APPLE__*/
//t.end(true, _bufferId); //t.end(true, _bufferId);
//return; //return;

View File

@@ -61,6 +61,7 @@ private:
RectangleArea* aUp; RectangleArea* aUp;
RectangleArea* aDown; RectangleArea* aDown;
RectangleArea* aPause; RectangleArea* aPause;
RectangleArea* aChat;
//RectangleArea* aUpJump; //RectangleArea* aUpJump;
RectangleArea* aJump; RectangleArea* aJump;
RectangleArea* aUpLeft; RectangleArea* aUpLeft;

View File

@@ -1,4 +1,5 @@
#include "GameRenderer.h" #include "GameRenderer.h"
#include "client/Options.h"
#include "gles.h" #include "gles.h"
#include "../../util/PerfTimer.h" #include "../../util/PerfTimer.h"
@@ -152,7 +153,7 @@ void GameRenderer::render(float a) {
int xMouse = (int)(Mouse::getX() * Gui::InvGuiScale); int xMouse = (int)(Mouse::getX() * Gui::InvGuiScale);
int yMouse = (int)(Mouse::getY() * Gui::InvGuiScale); int yMouse = (int)(Mouse::getY() * Gui::InvGuiScale);
#ifndef PLATFORM_DESKTOP
if (mc->useTouchscreen()) { if (mc->useTouchscreen()) {
const int pid = Multitouch::getFirstActivePointerIdExThisUpdate(); const int pid = Multitouch::getFirstActivePointerIdExThisUpdate();
if (pid >= 0) { if (pid >= 0) {
@@ -163,7 +164,6 @@ void GameRenderer::render(float a) {
yMouse = -9999; yMouse = -9999;
} }
} }
#endif
TIMER_POP(); TIMER_POP();
bool hasClearedColorBuffer = false; bool hasClearedColorBuffer = false;
@@ -214,9 +214,11 @@ void GameRenderer::render(float a) {
glDisable2(GL_SCISSOR_TEST); glDisable2(GL_SCISSOR_TEST);
mc->screen->render(xMouse, yMouse, a); mc->screen->render(xMouse, yMouse, a);
#ifdef RPI
mc->platform()->hideCursor(!mc->options.getBooleanValue(OPTIONS_RPI_CURSOR));
if (mc->options.getBooleanValue(OPTIONS_RPI_CURSOR))
renderCursor(xMouse, yMouse, mc); renderCursor(xMouse, yMouse, mc);
#endif
// Screen might have been removed, so check it again // Screen might have been removed, so check it again
if (mc->screen && !mc->screen->isInGameScreen()) if (mc->screen && !mc->screen->isInGameScreen())
sleepMs(15); sleepMs(15);
@@ -358,9 +360,9 @@ void GameRenderer::renderLevel(float a) {
if (mc->hitResult.isHit() && !cameraEntity->isUnderLiquid(Material::water)) { if (mc->hitResult.isHit() && !cameraEntity->isUnderLiquid(Material::water)) {
TIMER_POP_PUSH("select"); TIMER_POP_PUSH("select");
Player* player = (Player*) cameraEntity; Player* player = (Player*) cameraEntity;
if (mc->useTouchscreen()) { // if (mc->useTouchscreen()) {
levelRenderer->renderHitSelect(player, mc->hitResult, 0, NULL, a); //player.inventory->getSelected(), a); levelRenderer->renderHitSelect(player, mc->hitResult, 0, NULL, a); //player.inventory->getSelected(), a);
} // }
levelRenderer->renderHit(player, mc->hitResult, 0, NULL, a);//player->inventory.getSelected(), a); levelRenderer->renderHit(player, mc->hitResult, 0, NULL, a);//player->inventory.getSelected(), a);
} }
} }
@@ -654,11 +656,9 @@ void GameRenderer::pick(float a) {
float range = mc->gameMode->getPickRange(); float range = mc->gameMode->getPickRange();
bool isPicking = true; bool isPicking = true;
#ifndef PLATFORM_DESKTOP
bool freeform = mc->useTouchscreen() && !mc->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA); bool freeform = mc->useTouchscreen(); //&& !mc->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA);
#else
bool freeform = false;
#endif
if (freeform) { if (freeform) {
isPicking = updateFreeformPickDirection(a, pickDirection); isPicking = updateFreeformPickDirection(a, pickDirection);
} else { } else {

View File

@@ -65,7 +65,7 @@ LevelRenderer::LevelRenderer( Minecraft* mc)
destroyProgress(0) destroyProgress(0)
{ {
#ifdef OPENGL_ES #ifdef OPENGL_ES
int maxChunksWidth = 2 * LEVEL_WIDTH / CHUNK_SIZE + 1; int maxChunksWidth = 2 * LevelConstants::LEVEL_WIDTH / CHUNK_SIZE + 1;
numListsOrBuffers = maxChunksWidth * maxChunksWidth * (128/CHUNK_SIZE) * 3; numListsOrBuffers = maxChunksWidth * maxChunksWidth * (128/CHUNK_SIZE) * 3;
chunkBuffers = new GLuint[numListsOrBuffers]; chunkBuffers = new GLuint[numListsOrBuffers];
glGenBuffers2(numListsOrBuffers, chunkBuffers); glGenBuffers2(numListsOrBuffers, chunkBuffers);
@@ -1077,13 +1077,13 @@ void LevelRenderer::playSound(const std::string& name, float x, float y, float z
float dd = 16; float dd = 16;
if (volume > 1) dd *= volume; if (volume > 1) dd *= volume;
if (mc->cameraTargetPlayer->distanceToSqr(x, y, z) < dd * dd) { if (mc->cameraTargetPlayer != NULL && mc->cameraTargetPlayer->distanceToSqr(x, y, z) < dd * dd) {
mc->soundEngine->play(name, x, y, z, volume, pitch); mc->soundEngine->play(name, x, y, z, volume, pitch);
} }
} }
void LevelRenderer::addParticle(const std::string& name, float x, float y, float z, float xa, float ya, float za, int data) { void LevelRenderer::addParticle(const std::string& name, float x, float y, float z, float xa, float ya, float za, int data) {
if (mc->cameraTargetPlayer != NULL) {
float xd = mc->cameraTargetPlayer->x - x; float xd = mc->cameraTargetPlayer->x - x;
float yd = mc->cameraTargetPlayer->y - y; float yd = mc->cameraTargetPlayer->y - y;
float zd = mc->cameraTargetPlayer->z - z; float zd = mc->cameraTargetPlayer->z - z;
@@ -1124,6 +1124,7 @@ void LevelRenderer::addParticle(const std::string& name, float x, float y, float
//sw.stop(); //sw.stop();
//sw.printEvery(50, "add-particle-string"); //sw.printEvery(50, "add-particle-string");
}
} }
/* /*

View File

@@ -19,12 +19,13 @@ public:
protected: protected:
void additionalRendering(Mob* mob, float a); void additionalRendering(Mob* mob, float a);
private:
HumanoidModel* humanoidModel; HumanoidModel* humanoidModel;
// Last rotation values for cape smoothing (reduces jitter) // Last rotation values for cape smoothing (reduces jitter)
float lastCapeXRot; float lastCapeXRot;
float lastCapeZRot; float lastCapeZRot;
private:
// i guess ill keep this just in case seomthing breaks
}; };
#endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/ #endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/

View File

@@ -43,8 +43,8 @@ public:
protected: protected:
void setArmor(Model* armor); void setArmor(Model* armor);
Model* getArmor(); Model* getArmor();
Model* model; // allows derived renderers to swap models dynamically for skin formats
private: private:
Model* model;
Model* armor; Model* armor;
}; };

View File

@@ -1,5 +1,6 @@
#include "PlayerRenderer.h" #include "PlayerRenderer.h"
#include "EntityRenderDispatcher.h" #include "EntityRenderDispatcher.h"
#include "../Textures.h"
#include "../../../world/entity/player/Player.h" #include "../../../world/entity/player/Player.h"
#include "../../../world/level/Level.h" #include "../../../world/level/Level.h"
#include "../../../world/item/ArmorItem.h" #include "../../../world/item/ArmorItem.h"
@@ -14,12 +15,22 @@ static const std::string armorFilenames[10] = {
PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow ) PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow )
: super(humanoidModel, shadow), : super(humanoidModel, shadow),
armorParts1(new HumanoidModel(1.0f, 0, 64, 64)), playerModel64(humanoidModel),
armorParts2(new HumanoidModel(0.5f, 0, 64, 64)) playerModel32(new HumanoidModel(0, 0, 64, 32)),
armorParts1(new HumanoidModel(1.0f, 0, 64, 32)),
armorParts2(new HumanoidModel(0.5f, 0, 64, 32))
{ {
// default to legacy skin path until we know the exact texture size
model = playerModel32;
humanoidModel = playerModel32;
} }
PlayerRenderer::~PlayerRenderer() { PlayerRenderer::~PlayerRenderer() {
// prevent MobRenderer destructor from deleting model pointers we manage manually
model = nullptr;
delete playerModel32;
delete playerModel64;
delete armorParts1; delete armorParts1;
delete armorParts2; delete armorParts2;
} }
@@ -43,6 +54,15 @@ void PlayerRenderer::setupRotations( Entity* mob, float bob, float bodyRot, floa
super::setupRotations(mob, bob, bodyRot, a); super::setupRotations(mob, bob, bodyRot, a);
} }
bool PlayerRenderer::isModernPlayerSkin(Mob* mob) {
const std::string texName = mob->getTexture();
TextureId texId = entityRenderDispatcher->textures->loadTexture(texName);
if (!Textures::isTextureIdValid(texId))
return false;
const TextureData* texData = entityRenderDispatcher->textures->getTemporaryTextureData(texId);
return texData && texData->w == 64 && texData->h == 64;
}
void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){ void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){
//@todo: figure out how to handle HideGUI //@todo: figure out how to handle HideGUI
if (mob != entityRenderDispatcher->cameraEntity && mob->level->adventureSettings.showNameTags) { if (mob != entityRenderDispatcher->cameraEntity && mob->level->adventureSettings.showNameTags) {
@@ -50,6 +70,20 @@ void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){
} }
} }
void PlayerRenderer::render(Entity* mob_, float x, float y, float z, float rot, float a) {
Mob* mob = (Mob*) mob_;
HumanoidModel* desired = isModernPlayerSkin(mob) ? playerModel64 : playerModel32;
if (model != desired || humanoidModel != desired) {
model = desired;
humanoidModel = desired;
}
/* LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n",
((Player*)mob)->name.c_str(), mob->getTexture().c_str(),
humanoidModel->texWidth, humanoidModel->texHeight,
(desired == playerModel64 ? "64" : "32")); */
HumanoidMobRenderer::render(mob_, x, y, z, rot, a);
}
int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) { int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) {
Player* player = (Player*) mob; Player* player = (Player*) mob;
@@ -80,8 +114,11 @@ int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) {
} }
void PlayerRenderer::onGraphicsReset() { void PlayerRenderer::onGraphicsReset() {
super::onGraphicsReset(); if (playerModel32) playerModel32->onGraphicsReset();
if (playerModel64) playerModel64->onGraphicsReset();
if (armorParts1) armorParts1->onGraphicsReset(); if (armorParts1) armorParts1->onGraphicsReset();
if (armorParts2) armorParts2->onGraphicsReset(); if (armorParts2) armorParts2->onGraphicsReset();
super::onGraphicsReset();
} }

View File

@@ -11,6 +11,8 @@ public:
~PlayerRenderer(); ~PlayerRenderer();
virtual int prepareArmor(Mob* mob, int layer, float a); virtual int prepareArmor(Mob* mob, int layer, float a);
bool isModernPlayerSkin(Mob* mob);
virtual void render(Entity* mob, float x, float y, float z, float rot, float a);
virtual void setupPosition(Entity* mob, float x, float y, float z); virtual void setupPosition(Entity* mob, float x, float y, float z);
virtual void setupRotations(Entity* mob, float bob, float bodyRot, float a); virtual void setupRotations(Entity* mob, float bob, float bodyRot, float a);
@@ -18,6 +20,8 @@ public:
virtual void renderName(Mob* mob, float x, float y, float z); virtual void renderName(Mob* mob, float x, float y, float z);
virtual void onGraphicsReset(); virtual void onGraphicsReset();
private: private:
HumanoidModel* playerModel32;
HumanoidModel* playerModel64;
HumanoidModel* armorParts1; HumanoidModel* armorParts1;
HumanoidModel* armorParts2; HumanoidModel* armorParts2;
}; };

View File

@@ -31,7 +31,7 @@
// #else // #else
// // Uglyness to fix redeclaration issues // // Uglyness to fix redeclaration issues
// #ifdef WIN32 // #ifdef WIN32
// #include <WinSock2.h> // #include <winsock2.h>
// #include <Windows.h> // #include <Windows.h>
// #endif // #endif
// #include <gl/glew.h> // #include <gl/glew.h>

10
src/commands/Command.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include "Command.hpp"
#include "world/level/Level.h"
#include <client/Minecraft.h>
bool Command::isPlayerOp(Minecraft& mc, Player& player) {
std::string nicknameLower = player.name;
std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower);
return mc.level->ops.find(nicknameLower) != mc.level->ops.end();
}

28
src/commands/Command.hpp Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <vector>
enum CommandFlags {
COMMAND_FLAG_SINGLEPLAYER_ONLY = (1 << 1),
COMMAND_FLAG_NO_ARGS = (1 << 2),
};
class Minecraft;
class Player;
class Command {
public:
const std::string& getName() { return m_name; }
const CommandFlags getFlags() { return m_flags; }
bool isPlayerOp(Minecraft& mc, Player& player);
virtual std::string execute(Minecraft& mc, Player& player, const std::vector<std::string>& args) = 0;
virtual std::string help(Minecraft& mc) = 0;
protected:
Command(const std::string& name, CommandFlags flags = (CommandFlags)0) : m_name(name), m_flags(flags) {}
const std::string m_name;
const CommandFlags m_flags;
};

View File

@@ -0,0 +1,52 @@
#include "CommandBan.hpp"
#include "commands/Command.hpp"
#include "network/RakNetInstance.h"
#include "raknet/RakPeerInterface.h"
#include "world/level/Level.h"
#include <algorithm>
#include <client/Minecraft.h>
CommandBan::CommandBan() : Command("ban") {}
std::string CommandBan::execute(Minecraft& mc, Player& player, const std::vector<std::string>& args) {
if (!isPlayerOp(mc, player)) {
return "You aren't enough priveleged to run this command";
}
if (args.empty()) {
return help(mc);
}
std::string nicknameLower = args[0];
std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower);
auto it = std::find_if(mc.level->players.begin(), mc.level->players.end(), [args, nicknameLower] (auto& it) -> bool {
std::string lower = it->name;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
return lower == nicknameLower;
});
if (*it == (Player*)mc.player) {
return "ban: you can't ban urself lol";
}
if (it != mc.level->players.end()) {
mc.level->removePlayer(*it);
(*it)->remove();
mc.raknetInstance->getPeer()->CloseConnection((*it)->owner, true);
} else {
for (auto& banned : mc.level->bannedPpl) {
if (nicknameLower == banned) {
return args[0] + "already banned!";
}
}
}
mc.level->bannedPpl.insert(nicknameLower);
return "ban: successfully banned player " + args[0];
}
std::string CommandBan::help(Minecraft& mc) {
return "Usage: /ban <player>";
}

View File

@@ -0,0 +1,9 @@
#include "Command.hpp"
class CommandBan : public Command {
public:
CommandBan();
std::string execute(Minecraft& mc, Player& player, const std::vector<std::string>& args);
std::string help(Minecraft& mc);
};

View File

@@ -0,0 +1,35 @@
#include "CommandHelp.hpp"
#include "commands/Command.hpp"
#include "CommandManager.hpp"
#include <client/Minecraft.h>
#include <sstream>
CommandHelp::CommandHelp() : Command("help") {}
std::string CommandHelp::execute(Minecraft& mc, Player& player, const std::vector<std::string>& args) {
if (args.empty()) {
auto cmds = mc.commandManager().getListAllCommands();
std::ostringstream output;
output << "List of all commands:" << std::endl;
for (auto& cmd : cmds) {
output << " - " + cmd << std::endl;;
}
return output.str();
}
Command* cmd = mc.commandManager().getCommand(args[0]);
if (cmd != nullptr) {
return cmd->help(mc);
}
return "help: command " + args[0] + " not found";
}
std::string CommandHelp::help(Minecraft& mc) {
return "Usage: /help <command>";
}

View File

@@ -0,0 +1,9 @@
#include "Command.hpp"
class CommandHelp : public Command {
public:
CommandHelp();
std::string execute(Minecraft& mc, Player& player, const std::vector<std::string>& args);
std::string help(Minecraft& mc);
};

View File

@@ -0,0 +1,46 @@
#include "CommandKick.hpp"
#include "commands/Command.hpp"
#include "network/RakNetInstance.h"
#include "raknet/RakPeerInterface.h"
#include "world/level/Level.h"
#include <algorithm>
#include <client/Minecraft.h>
CommandKick::CommandKick() : Command("kick") {}
std::string CommandKick::execute(Minecraft& mc, Player& player, const std::vector<std::string>& args) {
if (!isPlayerOp(mc, player)) {
return "You aren't enough priveleged to run this command";
}
if (args.empty()) {
return help(mc);
}
std::string nicknameLower = args[0];
std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower);
auto it = std::find_if(mc.level->players.begin(), mc.level->players.end(), [args, nicknameLower] (auto& it) -> bool {
std::string lower = it->name;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
return lower == nicknameLower;
});
if (it == mc.level->players.end()) {
return "kick: can't find player with name " + args[0];
}
if (*it == (Player*)mc.player) {
return "kick: you can't kick urself lol";
}
mc.level->removePlayer(*it);
(*it)->remove();
mc.raknetInstance->getPeer()->CloseConnection((*it)->owner, true);
return "kick: successfully kicked player " + args[0];
}
std::string CommandKick::help(Minecraft& mc) {
return "Usage: /kick <player>";
}

View File

@@ -0,0 +1,9 @@
#include "Command.hpp"
class CommandKick : public Command {
public:
CommandKick();
std::string execute(Minecraft& mc, Player& player, const std::vector<std::string>& args);
std::string help(Minecraft& mc);
};

View File

@@ -0,0 +1,75 @@
#include "CommandManager.hpp"
#include <algorithm>
#include <string>
#include <vector>
#include "client/Minecraft.h"
#include "commands/Command.hpp"
#include "commands/CommandHelp.hpp"
#include "commands/CommandKick.hpp"
#include "commands/CommandOp.hpp"
#include "commands/CommandBan.hpp"
#include "network/packet/ChatPacket.h"
#include "network/RakNetInstance.h"
#include "world/level/Level.h"
CommandManager::CommandManager() {
registerAllCommands();
}
void CommandManager::registerAllCommands() {
m_commands.push_back(new CommandHelp());
m_commands.push_back(new CommandKick());
m_commands.push_back(new CommandOp());
m_commands.push_back(new CommandBan());
}
std::vector<std::string> CommandManager::getListAllCommands() {
std::vector<std::string> ret;
for (auto& cmd : m_commands) {
ret.push_back(cmd->getName());
}
return ret;
}
std::string CommandManager::execute(Minecraft& mc, Player& player, const std::string& input) {
std::istringstream ss(input);
std::string cmd;
ss >> cmd;
auto it = std::find_if(m_commands.begin(), m_commands.end(), [cmd](auto& it) -> bool {
return it->getName() == cmd;
});
if (it == m_commands.end()) {
return "Command /" + cmd + " not found";
}
std::vector<std::string> args;
std::string tok;
while (ss >> tok) args.push_back(tok);
if (!mc.level->isClientSide || (*it)->getFlags() & CommandFlags::COMMAND_FLAG_SINGLEPLAYER_ONLY) {
return (*it)->execute(mc, player, args);
} else {
ChatPacket packet("/" + input);
mc.raknetInstance->send(packet);
}
return "";
}
Command* CommandManager::getCommand(const std::string& name) {
auto it = std::find_if(m_commands.begin(), m_commands.end(), [name](auto& it) -> bool {
return it->getName() == name;
});
if (it == m_commands.end()) {
return *it;
}
return nullptr;
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <string>
#include <vector>
#include "Command.hpp"
class CommandManager {
public:
CommandManager();
std::vector<std::string> getListAllCommands();
std::string execute(Minecraft& mc, Player& player, const std::string& input);
Command* getCommand(const std::string& name);
private:
void registerAllCommands();
std::vector<Command*> m_commands;
};

View File

@@ -0,0 +1,31 @@
#include "CommandOp.hpp"
#include "commands/Command.hpp"
#include "world/level/Level.h"
#include <algorithm>
#include <client/Minecraft.h>
CommandOp::CommandOp() : Command("op") {}
std::string CommandOp::execute(Minecraft& mc, Player& player, const std::vector<std::string>& args) {
if (!isPlayerOp(mc, player)) {
return "You aren't enough priveleged to run this command";
}
if (args.empty()) {
return help(mc);
}
std::string nicknameLower = args[0];
std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower);
if (mc.level->ops.find(nicknameLower) != mc.level->ops.end()) {
return "op: player " + args[0] + " already opped";
}
mc.level->ops.emplace(nicknameLower);
return "op: successfully opped player " + args[0];
}
std::string CommandOp::help(Minecraft& mc) {
return "Usage: /op <player>";
}

View File

@@ -0,0 +1,9 @@
#include "Command.hpp"
class CommandOp : public Command {
public:
CommandOp();
std::string execute(Minecraft& mc, Player& player, const std::vector<std::string>& args);
std::string help(Minecraft& mc);
};

View File

@@ -22,12 +22,12 @@
#include "NinecraftApp.h" #include "NinecraftApp.h"
#define MAIN_CLASS NinecraftApp #define MAIN_CLASS NinecraftApp
#ifdef PLATFORM_WINDOWS // #ifdef PLATFORM_WINDOWS
#include "main_win32.h" // #include "main_win32.h"
#endif // #endif
#ifdef PLATFORM_GLFW #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
#include "main_glfw.h" #include "main_glfw.h"
#endif #endif

View File

@@ -25,12 +25,33 @@ static void setupExternalPath(struct android_app* state, MAIN_CLASS* app)
{ {
LOGI("Environment exists"); LOGI("Environment exists");
} }
// try appspecific external directory first
jobject activity = state->activity->clazz;
jclass activityClass = env->GetObjectClass(activity);
jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
jobject file = NULL;
if (getExternalFilesDir != NULL) {
file = env->CallObjectMethod(activity, getExternalFilesDir, NULL);
}
if (file == NULL) {
// Fallback to the legacy shared storage directory
jclass clazz = env->FindClass("android/os/Environment"); jclass clazz = env->FindClass("android/os/Environment");
jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;"); jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;");
if (env->ExceptionOccurred()) { if (env->ExceptionOccurred()) {
env->ExceptionDescribe(); env->ExceptionDescribe();
env->ExceptionClear();
}
file = env->CallStaticObjectMethod(clazz, method);
}
if (!file) {
LOGI("Failed to get external storage file object, using current working dir");
app->externalStoragePath = ".";
app->externalCacheStoragePath = ".";
return;
} }
jobject file = env->CallStaticObjectMethod(clazz, method);
jclass fileClass = env->GetObjectClass(file); jclass fileClass = env->GetObjectClass(file);
jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;"); jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");

View File

@@ -7,8 +7,7 @@
//#include "main_android_java.h" //#include "main_android_java.h"
#include "platform/input/Multitouch.h" #include "platform/input/Multitouch.h"
#include <unistd.h> #include <unistd.h>
#include <sys/syscall.h> #include <pthread.h>
#define gettid() ((int)syscall(SYS_gettid))
// Horrible, I know. / A // Horrible, I know. / A
#ifndef MAIN_CLASS #ifndef MAIN_CLASS
@@ -31,12 +30,33 @@ static void setupExternalPath(JNIEnv* env, MAIN_CLASS* app)
{ {
LOGI("Environment exists"); LOGI("Environment exists");
} }
// try appspecific external directory first
jobject activity = g_pActivity;
jclass activityClass = env->GetObjectClass(activity);
jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
jobject file = NULL;
if (getExternalFilesDir != NULL) {
file = env->CallObjectMethod(activity, getExternalFilesDir, NULL);
}
if (file == NULL) {
// Fallback to the legacy shared storage directory
jclass clazz = env->FindClass("android/os/Environment"); jclass clazz = env->FindClass("android/os/Environment");
jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;"); jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;");
if (env->ExceptionOccurred()) { if (env->ExceptionOccurred()) {
env->ExceptionDescribe(); env->ExceptionDescribe();
env->ExceptionClear();
}
file = env->CallStaticObjectMethod(clazz, method);
}
if (!file) {
LOGI("Failed to get external storage file object, using current working dir");
app->externalStoragePath = ".";
app->externalCacheStoragePath = ".";
return;
} }
jobject file = env->CallStaticObjectMethod(clazz, method);
jclass fileClass = env->GetObjectClass(file); jclass fileClass = env->GetObjectClass(file);
jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;"); jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
@@ -145,7 +165,7 @@ Java_com_mojang_minecraftpe_GLRenderer_nativeOnSurfaceCreated(JNIEnv* env) {
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_com_mojang_minecraftpe_GLRenderer_nativeOnSurfaceChanged(JNIEnv* env, jclass cls, jint w, jint h) { Java_com_mojang_minecraftpe_GLRenderer_nativeOnSurfaceChanged(JNIEnv* env, jclass cls, jint w, jint h) {
LOGI("@nativeOnSurfaceChanged: %p\n", pthread_self()); LOGI("@nativeOnSurfaceChanged: %lu\n", (unsigned long)pthread_self());
if (gApp) { if (gApp) {
gApp->setSize(w, h); gApp->setSize(w, h);

View File

@@ -1,16 +1,20 @@
#include <fstream>
#include <iostream> #include <iostream>
#include "NinecraftApp.h" #include "NinecraftApp.h"
#include "AppPlatform.h" #include "AppPlatform.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#ifdef __linux__
#include <unistd.h> #include <unistd.h>
#endif
#include "world/level/LevelSettings.h" #include "world/level/LevelSettings.h"
#include "world/level/Level.h" #include "world/level/Level.h"
#include "server/ArgumentsSettings.h" #include "server/ArgumentsSettings.h"
#include "platform/time.h" #include "platform/time.h"
#include "SharedConstants.h" #include "SharedConstants.h"
#include "world/level/LevelConstants.h"
#define MAIN_CLASS NinecraftApp #define MAIN_CLASS NinecraftApp
static App* g_app = 0; static App* g_app = 0;
@@ -27,36 +31,175 @@ void signal_callback_handler(int signum) {
} }
} }
int main(int numArguments, char* pszArgs[]) { std::string findStringInConfig(std::string line, std::string config) {
ArgumentsSettings aSettings(numArguments, pszArgs); auto valuePos = config.find(line);
if(aSettings.getShowHelp()) {
ArgumentsSettings defaultSettings(0, NULL); if (line.empty()) {
printf("Minecraft Pockect Edition Server %s\n", Common::getGameVersionString("").c_str()); throw std::runtime_error("Key cannot be empty");
printf("-------------------------------------------------------\n");
printf("--cachepath - Path to where the server can store temp stuff (not sure if this is used) [default: \"%s\"]\n", defaultSettings.getCachePath().c_str());
printf("--externalpath - The path to the place where the server should store the levels. [default: \"%s\"]\n", defaultSettings.getExternalPath().c_str());
printf("--levelname - The name of the server [default: \"%s\"]\n", defaultSettings.getLevelName().c_str());
printf("--leveldir - The name of the server [default: \"%s\"]\n", defaultSettings.getLevelDir().c_str());
printf("--help - Shows this message.\n");
printf("--port - The port to run the server on. [default: %d]\n", defaultSettings.getPort());
printf("--serverkey - The key that the server should use for API calls. [default: \"%s\"]\n", defaultSettings.getServerKey().c_str());
printf("-------------------------------------------------------\n");
return 0;
} }
printf("Level Name: %s\n", aSettings.getLevelName().c_str());
if (valuePos == std::string::npos) {
throw std::runtime_error("Cannot find value");
}
std::string valueStr = "";
valuePos += 1 + line.size();
while (true) {
auto sym = config.at(valuePos);
if (sym == '\n') {
break;
}
if (valuePos == config.size()) {
throw std::runtime_error("Cannot find end of the line");
}
valueStr += sym;
valuePos++;
}
return valueStr;
}
int main(int numArguments, char* pszArgs[]) {
std::ifstream serverProperties("server.properties");
int port = 0;
int gamemode = 0;
int worldSize = 0;
std::string levelDir = "";
std::string cachePath = "";
std::string externalPath = "";
std::string levelName = "";
if (serverProperties.is_open()) {
std::string propString;
std::string line;
while (std::getline(serverProperties, line)) {
propString += line;
propString += "\n";
}
if (propString.empty()) {
throw std::runtime_error("Config cannot be empty");
}
port = std::stoi(findStringInConfig("port", propString));
worldSize = std::stoi(findStringInConfig("world-size", propString));
if (worldSize < 16 || worldSize > 32) {
throw std::runtime_error("Incorrect world size.");
}
LevelConstants::CHUNK_CACHE_WIDTH = worldSize;
LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH;
LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH;
cachePath = findStringInConfig("level-cachepath", propString);
externalPath = findStringInConfig("level-externalpath", propString);
levelName = findStringInConfig("level-name", propString);
levelDir = findStringInConfig("level-dir", propString);
std::string gamemodeStr = findStringInConfig("gamemode", propString);
if (gamemodeStr == "survival") {
gamemode = GameType::Survival;
} else if (gamemodeStr == "creative") {
gamemode = GameType::Creative;
} else {
gamemode = GameType::Survival;
}
printf("%d %s %s %d %d\n", port, cachePath.c_str(), externalPath.c_str(), gamemode, LevelConstants::CHUNK_CACHE_WIDTH);
} else {
std::ofstream defaultProperties("server.properties");
if (defaultProperties.is_open()) {
ArgumentsSettings defaultSettings(0, NULL);
std::stringstream buffer;
buffer << "// MCPE Server properties" << std::endl;
buffer << "port=" << defaultSettings.getPort() << std::endl;
buffer << "level-dir=" << defaultSettings.getLevelDir() << std::endl;
buffer << "level-cachepath=" << defaultSettings.getCachePath() << std::endl;
buffer << "level-externalpath=" << defaultSettings.getExternalPath() << std::endl;
buffer << "gamemode=survival" << std::endl;
buffer << "level-name=" << defaultSettings.getLevelName() << std::endl;
buffer << "world-size=16" << std::endl;
defaultProperties << buffer.str();
printf("%s \n", buffer.str().c_str());
printf("Edit a config file first!\n");
defaultProperties.close();
exit(0);
} else {
throw std::runtime_error("Cannot create default config.");
}
}
printf("Level Name: %s\n", levelName.c_str());
AppContext appContext; AppContext appContext;
appContext.platform = new AppPlatform(); appContext.platform = new AppPlatform();
App* app = new MAIN_CLASS(); App* app = new MAIN_CLASS();
signal(SIGINT, signal_callback_handler); signal(SIGINT, signal_callback_handler);
g_app = app; g_app = app;
((MAIN_CLASS*)g_app)->externalStoragePath = aSettings.getExternalPath(); ((MAIN_CLASS*)g_app)->externalStoragePath = externalPath;
((MAIN_CLASS*)g_app)->externalCacheStoragePath = aSettings.getCachePath(); ((MAIN_CLASS*)g_app)->externalCacheStoragePath = cachePath;
g_app->init(appContext); g_app->init(appContext);
LevelSettings settings(getEpochTimeS(), GameType::Creative); LevelSettings settings(getEpochTimeS(), gamemode);
float startTime = getTimeS(); float startTime = getTimeS();
((MAIN_CLASS*)g_app)->selectLevel(aSettings.getLevelDir(), aSettings.getLevelName(), settings); ((MAIN_CLASS*)g_app)->selectLevel(levelDir, levelName, settings);
((MAIN_CLASS*)g_app)->hostMultiplayer(aSettings.getPort()); ((MAIN_CLASS*)g_app)->hostMultiplayer(port);
// Reading ops
std::ifstream ops("ops.txt");
if (ops.is_open()) {
std::string line;
while (std::getline(ops, line)) {
if (!line.empty()) {
((MAIN_CLASS*)g_app)->level->ops.insert(line);
}
}
} else {
std::ofstream opsDefault("ops.txt");
if (!opsDefault.is_open()) {
throw std::runtime_error("Cannot create ops list.");
}
}
// Reading banned ppl
std::ifstream banned("banned-players.txt");
if (banned.is_open()) {
std::string line;
while (std::getline(banned, line)) {
if (!line.empty()) {
((MAIN_CLASS*)g_app)->level->bannedPpl.insert(line);
}
}
} else {
std::ofstream bannedPpl("banned-players.txt");
if (!bannedPpl.is_open()) {
throw std::runtime_error("Cannot create banned players list.");
}
}
std::cout << "Level has been generated in " << getTimeS() - startTime << std::endl; std::cout << "Level has been generated in " << getTimeS() - startTime << std::endl;
((MAIN_CLASS*)g_app)->level->saveLevelData(); ((MAIN_CLASS*)g_app)->level->saveLevelData();
@@ -67,7 +210,31 @@ int main(int numArguments, char* pszArgs[]) {
//pthread_yield(); //pthread_yield();
sleepMs(20); sleepMs(20);
} }
std::ofstream opsWrite("ops.txt");
if (opsWrite.is_open()) {
for (auto& op : ((MAIN_CLASS*)g_app)->level->ops) {
opsWrite << op << std::endl;
}
opsWrite.close();
} else {
throw std::runtime_error("Cannot open ops list.");
}
std::ofstream bannedWrite("banned-players.txt");
if (bannedWrite.is_open()) {
for (auto& banned : ((MAIN_CLASS*)g_app)->level->bannedPpl) {
bannedWrite << banned << std::endl;
}
bannedWrite.close();
} else {
throw std::runtime_error("Cannot open banned players list.");
}
((MAIN_CLASS*)g_app)->level->saveLevelData(); ((MAIN_CLASS*)g_app)->level->saveLevelData();
delete app; delete app;
appContext.platform->finish(); appContext.platform->finish();
delete appContext.platform; delete appContext.platform;

View File

@@ -139,12 +139,14 @@ int main(void) {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
// Platform init. // Platform init.
appContext.platform = new AppPlatform_glfw(); appContext.platform = new AppPlatform_glfw();
#if defined(DEBUG) && defined(__EMSCRIPTEN__) #if defined(__EMSCRIPTEN__)
EM_ASM({ EM_ASM(
console.log(FS.readdir("/")); FS.mkdir('/games');
console.log(FS.readdir("/data")); FS.mkdir('/games/com.mojang');
console.log(FS.readdir("/data/images")); FS.mkdir('/games/com.mojang/minecraftWorlds');
}); FS.mount(IDBFS, {}, '/games');
FS.syncfs(true, function (err) {});
);
#endif #endif
glfwSetErrorCallback(error_callback); glfwSetErrorCallback(error_callback);
@@ -166,7 +168,7 @@ int main(void) {
AppPlatform_glfw* platform = (AppPlatform_glfw*)appContext.platform; AppPlatform_glfw* platform = (AppPlatform_glfw*)appContext.platform;
platform->window = glfwCreateWindow(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight(), "main", NULL, NULL); platform->window = glfwCreateWindow(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight(), "Minecraft PE 0.6.1", NULL, NULL);
if (platform->window == NULL) { if (platform->window == NULL) {
return 1; return 1;
@@ -205,16 +207,16 @@ int main(void) {
delete app; delete app;
appContext.platform->finish();
delete appContext.platform;
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
// Exit. // Exit.
glfwDestroyWindow(platform->window); glfwDestroyWindow(platform->window);
glfwTerminate(); glfwTerminate();
#endif #endif
appContext.platform->finish();
delete appContext.platform;
return 0; return 0;
} }

View File

@@ -14,7 +14,7 @@
#include <windows.h> #include <windows.h>
#include <windowsx.h> #include <windowsx.h>
#include <WinSock2.h> #include <winsock2.h>
#include <process.h> #include <process.h>
#include "SharedConstants.h" #include "SharedConstants.h"

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