80 Commits

Author SHA1 Message Date
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
108 changed files with 2950 additions and 1613 deletions

View File

@@ -18,7 +18,7 @@ permissions:
jobs: jobs:
build-windows: build-windows:
name: Windows Build name: Build Windows
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
@@ -68,13 +68,12 @@ jobs:
name: mcpe-windows name: mcpe-windows
path: | path: |
${{github.workspace}}/build/MinecraftPE.exe ${{github.workspace}}/build/MinecraftPE.exe
${{github.workspace}}/build/glfw3.dll
${{github.workspace}}/build/libpng16.dll ${{github.workspace}}/build/libpng16.dll
${{github.workspace}}/build/OpenAL32.dll ${{github.workspace}}/build/OpenAL32.dll
${{github.workspace}}/build/z.dll ${{github.workspace}}/build/libz.dll
build-linux: build-linux:
name: Linux Build name: Build Linux
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -120,7 +119,7 @@ jobs:
${{github.workspace}}/build/MinecraftPE-server ${{github.workspace}}/build/MinecraftPE-server
build-android: # pray to god build-android: # pray to god
name: Build Android APK (${{ matrix.abi }}) name: Build Android (${{ matrix.abi }})
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@@ -215,10 +214,59 @@ jobs:
name: minecraftpe-apk-${{ matrix.abi }} name: minecraftpe-apk-${{ matrix.abi }}
path: ${{ github.workspace }}/build-apk/minecraftpe-*-debug.apk 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: publish:
name: Publish name: Publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [ build-windows, build-linux, build-android ] needs: [ build-windows, build-linux, build-android, build-web ]
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
steps: steps:
- name: Checkout - name: Checkout
@@ -236,13 +284,13 @@ jobs:
- name: Zip Windows Artifacts - name: Zip Windows Artifacts
uses: vimtor/action-zip@v1.2 uses: vimtor/action-zip@v1.2
with: with:
files: data mcpe-windows/MinecraftPE.exe mcpe-windows/glfw3.dll mcpe-windows/libpng16.dll mcpe-windows/OpenAL32.dll mcpe-windows/z.dll 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 dest: minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip
- name: Zip Linux Artifacts - name: Zip Linux Artifacts
uses: vimtor/action-zip@v1.2 uses: vimtor/action-zip@v1.2
with: with:
files: data mcpe-linux/MinecraftPE files: mcpe-linux/MinecraftPE
dest: minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip dest: minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip
- name: Zip Linux Server Artifacts - name: Zip Linux Server Artifacts
@@ -263,6 +311,19 @@ jobs:
files: minecraftpe-apk-armeabi-v7a/minecraftpe-v7a-debug.apk files: minecraftpe-apk-armeabi-v7a/minecraftpe-v7a-debug.apk
dest: minecraftpe-${{ steps.ref.outputs.hash }}-android-armeabi-v7a.zip 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 - name: Update Development Release
uses: andelf/nightly-release@main uses: andelf/nightly-release@main
env: env:
@@ -273,8 +334,10 @@ jobs:
body: | body: |
MinecraftPE development release for commit ${{ github.sha }}. MinecraftPE development release for commit ${{ github.sha }}.
files: | files: |
./data.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip
./minecraftpe-server-${{ steps.ref.outputs.hash }}.zip ./minecraftpe-server-${{ steps.ref.outputs.hash }}.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-android-arm64-v8a.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-android-arm64-v8a.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-android-armeabi-v7a.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-android-armeabi-v7a.zip
./minecraftpe-${{ steps.ref.outputs.hash }}-web.zip

View File

@@ -7,10 +7,6 @@ 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")
endif()
include(cmake/EnumOption.cmake) include(cmake/EnumOption.cmake)
if(EMSCRIPTEN) if(EMSCRIPTEN)
@@ -26,6 +22,14 @@ find_package(OpenSSL)
if (${PLATFORM} STREQUAL "Desktop") if (${PLATFORM} STREQUAL "Desktop")
set(PLATFORM_CPP "PLATFORM_DESKTOP") set(PLATFORM_CPP "PLATFORM_DESKTOP")
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) if (WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_WARNINGS)
include_directories(misc/windows) include_directories(misc/windows)
@@ -52,6 +56,7 @@ if(${PLATFORM} MATCHES "Web")
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"
) )
@@ -102,9 +107,10 @@ CPMAddPackage(
"ALSOFT_UTILS OFF" "ALSOFT_UTILS OFF"
"LIBTYPE ${AL_LIBTYPE}" "LIBTYPE ${AL_LIBTYPE}"
"ALSOFT_ENABLE_MODULES OFF" "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"
@@ -205,6 +211,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
@@ -286,6 +293,8 @@ file(GLOB CLIENT_SOURCES
"src/AppPlatform_glfw.cpp" "src/AppPlatform_glfw.cpp"
"src/main.cpp" "src/main.cpp"
"src/commands/*.cpp"
) )
if (${PLATFORM} STREQUAL "Desktop") if (${PLATFORM} STREQUAL "Desktop")
@@ -321,11 +330,11 @@ target_include_directories(${PROJECT_NAME} PUBLIC
if(${PLATFORM} MATCHES "Web") 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"

View File

@@ -153,7 +153,7 @@ options.group.tweaks=Tweaks
options.allowSprint=Allow sprint options.allowSprint=Allow sprint
options.barOnTop=HUD above inventory options.barOnTop=HUD above inventory
options.rpiCursor=Show Raspberry PI cursor options.rpiCursor=Show Raspberry PI cursor
options.autojump=Auto Jump 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

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

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

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

@@ -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);
} }
@@ -102,12 +106,31 @@ 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 { virtual void hideCursor(bool hide) override {
int isHide = hide ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN; int isHide = hide ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN;
@@ -120,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

@@ -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
@@ -274,6 +277,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 +365,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 +385,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)
@@ -552,7 +560,7 @@ void Minecraft::tick(int nTick, int maxTick) {
level->tickEntities(); level->tickEntities();
level->tick(); level->tick();
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
TIMER_POP_PUSH("animateTick"); TIMER_POP_PUSH("animateTick");
if (player) { if (player) {
level->animateTick(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); level->animateTick(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z));
} }
@@ -640,13 +648,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 +666,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,155 +695,162 @@ 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;
if (slot >= 0 && slot < gui.getNumSlots()) if (slot >= 0 && slot < gui.getNumSlots())
player->inventory->selectSlot(slot); player->inventory->selectSlot(slot);
#if defined(WIN32) #if defined(WIN32)
if (digit >= 1 && GetAsyncKeyState(VK_CONTROL) < 0) { if (digit >= 1 && GetAsyncKeyState(VK_CONTROL) < 0) {
// Set adventure settings here! // Set adventure settings here!
AdventureSettingsPacket p(level->adventureSettings); AdventureSettingsPacket p(level->adventureSettings);
p.toggle((AdventureSettingsPacket::Flags)(1 << slot)); p.toggle((AdventureSettingsPacket::Flags)(1 << slot));
p.fillIn(level->adventureSettings); p.fillIn(level->adventureSettings);
raknetInstance->send(p); raknetInstance->send(p);
} }
if (digit == 0) { if (digit == 0) {
Pos pos((int)player->x, (int)player->y-1, (int)player->z); Pos pos((int)player->x, (int)player->y-1, (int)player->z);
SetSpawnPositionPacket p(pos); SetSpawnPositionPacket p(pos);
raknetInstance->send(p); raknetInstance->send(p);
} }
#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); }
if (key == Keyboard::KEY_E) {
screenChooser.setScreen(SCREEN_BLOCKSELECTION);
}
if (!screen && key == Keyboard::KEY_T && level) {
setScreen(new ConsoleScreen());
}
if (key == Keyboard::KEY_F3) {
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) {
options.toggle(OPTIONS_THIRD_PERSON_VIEW);
/*
ImprovedNoise noise;
for (int i = 0; i < 16; ++i)
printf("%d\t%f\n", i, noise.grad2(i, 3, 8));
*/
}
if (!screen && key == Keyboard::KEY_O || key == 250) {
releaseMouse();
}
if (key == Keyboard::KEY_F) {
int dst = options.getIntValue(OPTIONS_VIEW_DISTANCE);
options.set(OPTIONS_VIEW_DISTANCE, (dst + 1) % 4);
}
#ifdef CHEATS
if (key == Keyboard::KEY_U) {
onGraphicsReset();
player->heal(100);
} }
if (key == Keyboard::KEY_E) { if (key == Keyboard::KEY_B || key == 108) // Toggle the game mode
screenChooser.setScreen(SCREEN_BLOCKSELECTION); setIsCreativeMode(!isCreativeMode());
}
if (!screen && key == Keyboard::KEY_T && level) { if (key == Keyboard::KEY_P) // Step forward in time
setScreen(new ConsoleScreen()); level->setTime( level->getTime() + 1000);
}
if (key == Keyboard::KEY_F3) { if (key == Keyboard::KEY_G) {
options.toggle(OPTIONS_RENDER_DEBUG); setScreen(new ArmorScreen());
}
if (key == Keyboard::KEY_F5) {
options.toggle(OPTIONS_THIRD_PERSON_VIEW);
/* /*
ImprovedNoise noise; std::vector<AABB>& boxs = level->getCubes(NULL, AABB(128.1f, 73, 128.1f, 128.9f, 74.9f, 128.9f));
for (int i = 0; i < 16; ++i) LOGI("boxes: %d\n", (int)boxs.size());
printf("%d\t%f\n", i, noise.grad2(i, 3, 8));
*/ */
} }
if (!screen && key == Keyboard::KEY_O || key == 250) { if (key == Keyboard::KEY_Y) {
releaseMouse(); textures->reloadAll();
player->hurtTo(2);
}
if (key == Keyboard::KEY_Z || key == 108) {
for (int i = 0; i < 1; ++i) {
Mob* mob = NULL;
int forceId = 0;//MobTypes::Sheep;
int types[] = {
MobTypes::Sheep,
MobTypes::Pig,
MobTypes::Chicken,
MobTypes::Cow,
};
int mobType = (forceId > 0)? forceId : types[Mth::random(sizeof(types) / sizeof(int))];
mob = MobFactory::CreateMob(mobType, level);
//((Animal*)mob)->setAge(-1000);
float dx = 4 - 8 * Mth::random() + 4 * Mth::sin(Mth::DEGRAD * player->yRot);
float dz = 4 - 8 * Mth::random() + 4 * Mth::cos(Mth::DEGRAD * player->yRot);
if (mob && !MobSpawner::addMob(level, mob, player->x + dx, player->y, player->z + dz, Mth::random()*360, 0, true))
delete mob;
}
} }
if (key == Keyboard::KEY_F) { if (key == Keyboard::KEY_X) {
int dst = options.getIntValue(OPTIONS_VIEW_DISTANCE); const EntityList& entities = level->getAllEntities();
options.set(OPTIONS_VIEW_DISTANCE, (dst + 1) % 4); for (int i = entities.size()-1; i >= 0; --i) {
Entity* e = entities[i];
if (!e->isPlayer())
level->removeEntity(e);
}
} }
#ifdef CHEATS
if (key == Keyboard::KEY_U) { if (key == Keyboard::KEY_C /*|| key == 4*/) {
onGraphicsReset(); player->inventory->clearInventoryWithDefault();
player->heal(100); // @todo: Add saving here for benchmarking
}
if (key == Keyboard::KEY_H) {
setScreen( new PrerenderTilesScreen() );
}
if (key == Keyboard::KEY_O) {
for (int i = Inventory::MAX_SELECTION_SIZE; i < player->inventory->getContainerSize(); ++i)
if (player->inventory->getItem(i))
player->inventory->dropSlot(i, false);
}
if (key == Keyboard::KEY_M) {
Difficulty difficulty = (Difficulty)options.getIntValue(OPTIONS_DIFFICULTY);
options.set(OPTIONS_DIFFICULTY, (difficulty == Difficulty::PEACEFUL)?
Difficulty::NORMAL : Difficulty::PEACEFUL);
//setIsCreativeMode( !isCreativeMode() );
}
if (options.getBooleanValue(OPTIONS_RENDER_DEBUG)) {
if (key >= '0' && key <= '9') {
_perfRenderer->debugFpsMeterKeyPress(key - '0');
} }
}
if (key == Keyboard::KEY_B || key == 108) // Toggle the game mode
setIsCreativeMode(!isCreativeMode());
if (key == Keyboard::KEY_P) // Step forward in time
level->setTime( level->getTime() + 1000);
if (key == Keyboard::KEY_G) {
setScreen(new ArmorScreen());
/*
std::vector<AABB>& boxs = level->getCubes(NULL, AABB(128.1f, 73, 128.1f, 128.9f, 74.9f, 128.9f));
LOGI("boxes: %d\n", (int)boxs.size());
*/
}
if (key == Keyboard::KEY_Y) {
textures->reloadAll();
player->hurtTo(2);
}
if (key == Keyboard::KEY_Z || key == 108) {
for (int i = 0; i < 1; ++i) {
Mob* mob = NULL;
int forceId = 0;//MobTypes::Sheep;
int types[] = {
MobTypes::Sheep,
MobTypes::Pig,
MobTypes::Chicken,
MobTypes::Cow,
};
int mobType = (forceId > 0)? forceId : types[Mth::random(sizeof(types) / sizeof(int))];
mob = MobFactory::CreateMob(mobType, level);
//((Animal*)mob)->setAge(-1000);
float dx = 4 - 8 * Mth::random() + 4 * Mth::sin(Mth::DEGRAD * player->yRot);
float dz = 4 - 8 * Mth::random() + 4 * Mth::cos(Mth::DEGRAD * player->yRot);
if (mob && !MobSpawner::addMob(level, mob, player->x + dx, player->y, player->z + dz, Mth::random()*360, 0, true))
delete mob;
}
}
if (key == Keyboard::KEY_X) {
const EntityList& entities = level->getAllEntities();
for (int i = entities.size()-1; i >= 0; --i) {
Entity* e = entities[i];
if (!e->isPlayer())
level->removeEntity(e);
}
}
if (key == Keyboard::KEY_C /*|| key == 4*/) {
player->inventory->clearInventoryWithDefault();
// @todo: Add saving here for benchmarking
}
if (key == Keyboard::KEY_H) {
setScreen( new PrerenderTilesScreen() );
}
if (key == Keyboard::KEY_O) {
for (int i = Inventory::MAX_SELECTION_SIZE; i < player->inventory->getContainerSize(); ++i)
if (player->inventory->getItem(i))
player->inventory->dropSlot(i, false);
}
if (key == Keyboard::KEY_M) {
Difficulty difficulty = (Difficulty)options.getIntValue(OPTIONS_DIFFICULTY);
options.set(OPTIONS_DIFFICULTY, (difficulty == Difficulty::PEACEFUL)?
Difficulty::NORMAL : Difficulty::PEACEFUL);
//setIsCreativeMode( !isCreativeMode() );
}
if (options.getBooleanValue(OPTIONS_RENDER_DEBUG)) {
if (key >= '0' && key <= '9') {
_perfRenderer->debugFpsMeterKeyPress(key - '0');
}
}
#endif
#endif #endif
#ifndef PLATFORM_DESKTOP if (key == Keyboard::KEY_ESCAPE)
if (key == 82) pauseGame(false);
pauseGame(false);
#else
if (key == Keyboard::KEY_ESCAPE)
pauseGame(false);
#endif
#ifndef OPENGL_ES #ifndef OPENGL_ES
if (key == Keyboard::KEY_P) { if (key == Keyboard::KEY_P) {
@@ -866,11 +877,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,7 +1130,7 @@ 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;
@@ -1228,7 +1246,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");
@@ -1242,11 +1259,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 {
@@ -1312,12 +1325,9 @@ bool Minecraft::joinMultiplayerFromString( const std::string& server )
} else { } else {
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);
} }
@@ -1571,6 +1581,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();
} }
} }
@@ -1589,3 +1601,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,7 +204,8 @@ 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_DESKTOP #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_DESKTOP #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_DESKTOP #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

@@ -16,6 +16,8 @@ OptionsFile::OptionsFile() {
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

View File

@@ -1,69 +1,56 @@
#include "CreativeMode.h" #include "CreativeMode.h"
#include "../Minecraft.h" #include "../Minecraft.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "../particle/ParticleEngine.h" #include "../particle/ParticleEngine.h"
#endif #endif
#include "../player/LocalPlayer.h" #include "../player/LocalPlayer.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "../renderer/LevelRenderer.h" #include "../renderer/LevelRenderer.h"
#include "../sound/SoundEngine.h" #include "../sound/SoundEngine.h"
#endif #endif
#include "../../world/level/Level.h" #include "../../world/level/Level.h"
//#include "../../network/Packet.h" //#include "../../network/Packet.h"
#include "../../network/packet/RemoveBlockPacket.h" #include "../../network/packet/RemoveBlockPacket.h"
#include "../../world/entity/player/Abilities.h" #include "../../world/entity/player/Abilities.h"
static const int DestructionTickDelay = 5; static const int DestructionTickDelay = 5;
CreativeMode::CreativeMode(Minecraft* minecraft) CreativeMode::CreativeMode(Minecraft* minecraft)
: super(minecraft) : super(minecraft)
{ {
} }
void CreativeMode::startDestroyBlock(int x, int y, int z, int face) { void CreativeMode::startDestroyBlock(int x, int y, int z, int face) {
if(minecraft->player->getCarriedItem() != NULL && minecraft->player->getCarriedItem()->id == Item::bow->id) if(minecraft->player->getCarriedItem() != NULL && minecraft->player->getCarriedItem()->id == Item::bow->id)
return; return;
creativeDestroyBlock(x, y, z, face); creativeDestroyBlock(x, y, z, face);
destroyDelay = DestructionTickDelay; destroyDelay = DestructionTickDelay;
} }
void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) { void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) {
minecraft->level->extinguishFire(x, y, z, face); minecraft->level->extinguishFire(x, y, z, face);
destroyBlock(x, y, z, face); destroyBlock(x, y, z, face);
} }
void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) { void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
destroyDelay--; destroyDelay--;
if (destroyDelay <= 0) { if (destroyDelay <= 0) {
destroyDelay = DestructionTickDelay; destroyDelay = DestructionTickDelay;
creativeDestroyBlock(x, y, z, face); creativeDestroyBlock(x, y, z, face);
} }
} }
void CreativeMode::stopDestroyBlock() { void CreativeMode::stopDestroyBlock() {
destroyDelay = 0; destroyDelay = 0;
} }
void CreativeMode::initAbilities( Abilities& abilities ) { void CreativeMode::initAbilities( Abilities& abilities ) {
abilities.mayfly = true; abilities.mayfly = true;
abilities.instabuild = true; abilities.instabuild = true;
abilities.invulnerable = true; abilities.invulnerable = true;
} }
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

@@ -1,27 +1,26 @@
#ifndef NET_MINECRAFT_CLIENT_GAMEMODE__CreativeMode_H__ #ifndef NET_MINECRAFT_CLIENT_GAMEMODE__CreativeMode_H__
#define NET_MINECRAFT_CLIENT_GAMEMODE__CreativeMode_H__ #define NET_MINECRAFT_CLIENT_GAMEMODE__CreativeMode_H__
//package net.minecraft.client.gamemode; //package net.minecraft.client.gamemode;
#include "GameMode.h" #include "GameMode.h"
class CreativeMode: public GameMode class CreativeMode: public GameMode
{ {
typedef GameMode super; typedef GameMode super;
public: public:
CreativeMode(Minecraft* minecraft); CreativeMode(Minecraft* minecraft);
void startDestroyBlock(int x, int y, int z, int face); void startDestroyBlock(int x, int y, int z, int face);
void continueDestroyBlock(int x, int y, int z, int face); void continueDestroyBlock(int x, int y, int z, int face);
void stopDestroyBlock(); void stopDestroyBlock();
bool isCreativeType(); bool isCreativeType();
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); };
};
#endif /*NET_MINECRAFT_CLIENT_GAMEMODE__CreativeMode_H__*/
#endif /*NET_MINECRAFT_CLIENT_GAMEMODE__CreativeMode_H__*/

View File

@@ -1,115 +1,102 @@
#include "CreatorMode.h" #include "CreatorMode.h"
#include "../Minecraft.h" #include "../Minecraft.h"
#include "../particle/ParticleEngine.h" #include "../particle/ParticleEngine.h"
#include "../player/LocalPlayer.h" #include "../player/LocalPlayer.h"
#include "../renderer/LevelRenderer.h" #include "../renderer/LevelRenderer.h"
#include "../sound/SoundEngine.h" #include "../sound/SoundEngine.h"
#include "../../world/level/Level.h" #include "../../world/level/Level.h"
//#include "../../network/Packet.h" //#include "../../network/Packet.h"
#include "../../network/packet/RemoveBlockPacket.h" #include "../../network/packet/RemoveBlockPacket.h"
#include "../../world/entity/player/Abilities.h" #include "../../world/entity/player/Abilities.h"
static const int DestructionTickDelay = 5; static const int DestructionTickDelay = 5;
class Creator: public ICreator { class Creator: public ICreator {
//virtual void getEvents(); //virtual void getEvents();
public: public:
Creator(/*int eventLifeTime*/) Creator(/*int eventLifeTime*/)
: _tileEvents(32), : _tileEvents(32),
_tickId(0) _tickId(0)
{ {
} }
void setTick(int tick) { void setTick(int tick) {
_tickId = tick; _tickId = tick;
} }
EventList<TileEvent>& getTileEvents() { return _tileEvents; } EventList<TileEvent>& getTileEvents() { return _tileEvents; }
void addevent_blockUse(int entityId, int x, int y, int z, int face) { void addevent_blockUse(int entityId, int x, int y, int z, int face) {
TileEvent t = { TileEvent t = {
entityId, entityId,
x,y,z, x,y,z,
face face
}; };
_tileEvents.add(t, _tickId); _tileEvents.add(t, _tickId);
} }
private: private:
EventList<TileEvent> _tileEvents; EventList<TileEvent> _tileEvents;
int _tickId; int _tickId;
}; };
CreatorMode::CreatorMode(Minecraft* minecraft) CreatorMode::CreatorMode(Minecraft* minecraft)
: super(minecraft) : super(minecraft)
{ {
_creator = new Creator(); _creator = new Creator();
} }
CreatorMode::~CreatorMode() { CreatorMode::~CreatorMode() {
delete _creator; delete _creator;
} }
void CreatorMode::startDestroyBlock(int x, int y, int z, int face) { void CreatorMode::startDestroyBlock(int x, int y, int z, int face) {
if(minecraft->player->getCarriedItem() != NULL && minecraft->player->getCarriedItem()->id == Item::bow->id) if(minecraft->player->getCarriedItem() != NULL && minecraft->player->getCarriedItem()->id == Item::bow->id)
return; return;
CreatorDestroyBlock(x, y, z, face); CreatorDestroyBlock(x, y, z, face);
destroyDelay = DestructionTickDelay; destroyDelay = DestructionTickDelay;
} }
void CreatorMode::CreatorDestroyBlock(int x, int y, int z, int face) { void CreatorMode::CreatorDestroyBlock(int x, int y, int z, int face) {
minecraft->level->extinguishFire(x, y, z, face); minecraft->level->extinguishFire(x, y, z, face);
destroyBlock(x, y, z, face); destroyBlock(x, y, z, face);
} }
void CreatorMode::continueDestroyBlock(int x, int y, int z, int face) { void CreatorMode::continueDestroyBlock(int x, int y, int z, int face) {
destroyDelay--; destroyDelay--;
if (destroyDelay <= 0) { if (destroyDelay <= 0) {
destroyDelay = DestructionTickDelay; destroyDelay = DestructionTickDelay;
CreatorDestroyBlock(x, y, z, face); CreatorDestroyBlock(x, y, z, face);
} }
} }
bool CreatorMode::useItemOn( Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit ) { bool CreatorMode::useItemOn( Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit ) {
if (item && item->id == ((Item*)Item::sword_iron)->id) if (item && item->id == ((Item*)Item::sword_iron)->id)
_creator->addevent_blockUse(player->entityId, x, y, z, face); _creator->addevent_blockUse(player->entityId, x, y, z, face);
return super::useItemOn(player, level, item, x, y, z, face, hit); return super::useItemOn(player, level, item, x, y, z, face, hit);
} }
void CreatorMode::stopDestroyBlock() { void CreatorMode::stopDestroyBlock() {
destroyDelay = 0; destroyDelay = 0;
} }
void CreatorMode::initAbilities( Abilities& abilities ) { void CreatorMode::initAbilities( Abilities& abilities ) {
abilities.mayfly = true; abilities.mayfly = true;
abilities.instabuild = true; abilities.instabuild = true;
abilities.invulnerable = true; abilities.invulnerable = true;
} }
bool CreatorMode::isCreativeType() { bool CreatorMode::isCreativeType() {
return true; return true;
} }
void CreatorMode::releaseUsingItem( Player* player ) { ICreator* CreatorMode::getCreator() {
if(player->getCarriedItem() != NULL) { return _creator;
int oldItemId = player->getCarriedItem()->id; }
int oldAux = player->getAuxData();
super::releaseUsingItem(player); void CreatorMode::tick() {
if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == oldItemId) { _creator->setTick(minecraft->level->getTime());
player->getCarriedItem()->setAuxValue(oldAux); super::tick();
} }
} else {
super::releaseUsingItem(player);
}
}
ICreator* CreatorMode::getCreator() {
return _creator;
}
void CreatorMode::tick() {
_creator->setTick(minecraft->level->getTime());
super::tick();
}

View File

@@ -1,61 +1,61 @@
#ifndef NET_MINECRAFT_CLIENT_GAMEMODE__CreatorMode_H__ #ifndef NET_MINECRAFT_CLIENT_GAMEMODE__CreatorMode_H__
#define NET_MINECRAFT_CLIENT_GAMEMODE__CreatorMode_H__ #define NET_MINECRAFT_CLIENT_GAMEMODE__CreatorMode_H__
//package net.minecraft.client.gamemode; //package net.minecraft.client.gamemode;
#include "GameMode.h" #include "GameMode.h"
#include "../../world/PosTranslator.h" #include "../../world/PosTranslator.h"
class ICreator { class ICreator {
public: public:
virtual ~ICreator() {} virtual ~ICreator() {}
struct TileEvent { struct TileEvent {
int entityId; int entityId;
int x, y, z; int x, y, z;
int face; int face;
void write(std::stringstream& ss, IPosTranslator& t) const { void write(std::stringstream& ss, IPosTranslator& t) const {
int xx = x, yy = y, zz = z; int xx = x, yy = y, zz = z;
t.to(xx, yy, zz); t.to(xx, yy, zz);
ss << xx << "," << yy << "," << zz << "," << face << "," << entityId; ss << xx << "," << yy << "," << zz << "," << face << "," << entityId;
} }
}; };
template <class T> template <class T>
class EventList { class EventList {
public: public:
EventList(int size) { EventList(int size) {
_events.reserve(size); _events.reserve(size);
_maxSize = (int)size; _maxSize = (int)size;
clear(); clear();
} }
void clear() { void clear() {
_index = -1; _index = -1;
_size = 0; _size = 0;
} }
void add(const T& item, int tick) { void add(const T& item, int tick) {
if (_size < _maxSize) { if (_size < _maxSize) {
_events.push_back(Item()); _events.push_back(Item());
++_size; ++_size;
} }
Item& e = _events[_nextIndex()]; Item& e = _events[_nextIndex()];
e.item = item; e.item = item;
e.timestamp = tick; e.timestamp = tick;
} }
int size() const { int size() const {
return _size; return _size;
} }
const T& operator[](int i) const { const T& operator[](int i) const {
return _events[_getIndex(i)].item; return _events[_getIndex(i)].item;
} }
T& operator[](int i) { T& operator[](int i) {
return _events[_getIndex(i)].item; return _events[_getIndex(i)].item;
} }
void write(std::stringstream& ss, IPosTranslator& t, int minTimetamp) const { void write(std::stringstream& ss, IPosTranslator& t, int minTimetamp) const {
int i = _getFirstNewerIndex(minTimetamp); int i = _getFirstNewerIndex(minTimetamp);
if (i < 0) if (i < 0)
return; return;
@@ -66,63 +66,62 @@ public:
ss << "|"; ss << "|";
if (++i == _size) i = 0; if (++i == _size) i = 0;
} }
} }
private: private:
int _getIndex(int i) const { return (1 + _index + i) % _size; } int _getIndex(int i) const { return (1 + _index + i) % _size; }
int _nextIndex() { int _nextIndex() {
if (++_index == _size) _index = 0; if (++_index == _size) _index = 0;
return _index; return _index;
} }
int _getFirstNewerIndex(int timestamp) const { int _getFirstNewerIndex(int timestamp) const {
for (int i = _index + 1, j = 0; j < _size; ++i, ++j) { for (int i = _index + 1, j = 0; j < _size; ++i, ++j) {
if (i == _size) i = 0; if (i == _size) i = 0;
if (_events[i].timestamp >= timestamp) return i; if (_events[i].timestamp >= timestamp) return i;
} }
return -1; return -1;
} }
struct Item { struct Item {
int timestamp; int timestamp;
T item; T item;
}; };
int _index; int _index;
int _size; int _size;
int _maxSize; int _maxSize;
std::vector<Item> _events; std::vector<Item> _events;
}; };
virtual EventList<TileEvent>& getTileEvents() = 0; virtual EventList<TileEvent>& getTileEvents() = 0;
}; };
class Creator; class Creator;
class CreatorMode: public GameMode class CreatorMode: public GameMode
{ {
typedef GameMode super; typedef GameMode super;
public: public:
CreatorMode(Minecraft* minecraft); CreatorMode(Minecraft* minecraft);
~CreatorMode(); ~CreatorMode();
void startDestroyBlock(int x, int y, int z, int face); void startDestroyBlock(int x, int y, int z, int face);
void continueDestroyBlock(int x, int y, int z, int face); void continueDestroyBlock(int x, int y, int z, int face);
void stopDestroyBlock(); void stopDestroyBlock();
bool useItemOn(Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit); bool useItemOn(Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit);
void tick(); void tick();
ICreator* getCreator(); ICreator* getCreator();
bool isCreativeType(); bool isCreativeType();
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);
Creator* _creator;
Creator* _creator; };
};
#endif /*NET_MINECRAFT_CLIENT_GAMEMODE__CreatorMode_H__*/
#endif /*NET_MINECRAFT_CLIENT_GAMEMODE__CreatorMode_H__*/

View File

@@ -1,174 +1,174 @@
#include "GameMode.h" #include "GameMode.h"
#include "../Minecraft.h" #include "../Minecraft.h"
#include "../../network/packet/UseItemPacket.h" #include "../../network/packet/UseItemPacket.h"
#include "../../network/packet/PlayerActionPacket.h" #include "../../network/packet/PlayerActionPacket.h"
#include "../../world/level/Level.h" #include "../../world/level/Level.h"
#include "../../world/item/ItemInstance.h" #include "../../world/item/ItemInstance.h"
#include "../player/LocalPlayer.h" #include "../player/LocalPlayer.h"
#include "client/Options.h" #include "client/Options.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "../sound/SoundEngine.h" #include "../sound/SoundEngine.h"
#include "../particle/ParticleEngine.h" #include "../particle/ParticleEngine.h"
#endif #endif
#include "../../network/RakNetInstance.h" #include "../../network/RakNetInstance.h"
#include "../../network/packet/RemoveBlockPacket.h" #include "../../network/packet/RemoveBlockPacket.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "../renderer/LevelRenderer.h" #include "../renderer/LevelRenderer.h"
#endif #endif
#include "../../world/level/material/Material.h" #include "../../world/level/material/Material.h"
GameMode::GameMode( Minecraft* minecraft) GameMode::GameMode( Minecraft* minecraft)
: minecraft(minecraft), : minecraft(minecraft),
destroyProgress(0), destroyProgress(0),
oDestroyProgress(0), oDestroyProgress(0),
destroyTicks(0), destroyTicks(0),
destroyDelay(0) destroyDelay(0)
{ {
} }
/*virtual*/ /*virtual*/
Player* GameMode::createPlayer(Level* level) { Player* GameMode::createPlayer(Level* level) {
return new LocalPlayer(minecraft, level, minecraft->options.getStringValue(OPTIONS_USERNAME), level->dimension->id, isCreativeType()); return new LocalPlayer(minecraft, level, minecraft->options.getStringValue(OPTIONS_USERNAME), level->dimension->id, isCreativeType());
} }
/*virtual*/ /*virtual*/
void GameMode::interact(Player* player, Entity* entity) { void GameMode::interact(Player* player, Entity* entity) {
player->interact(entity); player->interact(entity);
} }
/*virtual*/ /*virtual*/
void GameMode::attack(Player* player, Entity* entity) { void GameMode::attack(Player* player, Entity* entity) {
if (minecraft->level->adventureSettings.noPvP && entity->isPlayer()) if (minecraft->level->adventureSettings.noPvP && entity->isPlayer())
return; return;
if (minecraft->level->adventureSettings.noPvM && entity->isMob()) if (minecraft->level->adventureSettings.noPvM && entity->isMob())
return; return;
player->attack(entity); player->attack(entity);
} }
/* virtual */ /* virtual */
void GameMode::startDestroyBlock( int x, int y, int z, int face ) { void GameMode::startDestroyBlock( int x, int y, int z, int face ) {
if(minecraft->player->getCarriedItem() != NULL && minecraft->player->getCarriedItem()->id == Item::bow->id) if(minecraft->player->getCarriedItem() != NULL && minecraft->player->getCarriedItem()->id == Item::bow->id)
return; return;
destroyBlock(x, y, z, face); destroyBlock(x, y, z, face);
} }
/*virtual*/ /*virtual*/
bool GameMode::destroyBlock(int x, int y, int z, int face) { bool GameMode::destroyBlock(int x, int y, int z, int face) {
Level* level = minecraft->level; Level* level = minecraft->level;
Tile* oldTile = Tile::tiles[level->getTile(x, y, z)]; Tile* oldTile = Tile::tiles[level->getTile(x, y, z)];
if (!oldTile) if (!oldTile)
return false; return false;
if (level->adventureSettings.immutableWorld) { if (level->adventureSettings.immutableWorld) {
if (oldTile != (Tile*)Tile::leaves if (oldTile != (Tile*)Tile::leaves
&& oldTile->material != Material::plant) { && oldTile->material != Material::plant) {
return false; return false;
} }
} }
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
minecraft->particleEngine->destroy(x, y, z); minecraft->particleEngine->destroy(x, y, z);
#endif #endif
int data = level->getData(x, y, z); int data = level->getData(x, y, z);
bool changed = level->setTile(x, y, z, 0); bool changed = level->setTile(x, y, z, 0);
if (changed) { if (changed) {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
minecraft->soundEngine->play(oldTile->soundType->getBreakSound(), x + 0.5f, y + 0.5f, z + 0.5f, (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f); minecraft->soundEngine->play(oldTile->soundType->getBreakSound(), x + 0.5f, y + 0.5f, z + 0.5f, (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f);
#endif #endif
oldTile->destroy(level, x, y, z, data); oldTile->destroy(level, x, y, z, data);
if (minecraft->options.getBooleanValue(OPTIONS_DESTROY_VIBRATION)) minecraft->platform()->vibrate(24); if (minecraft->options.getBooleanValue(OPTIONS_DESTROY_VIBRATION)) minecraft->platform()->vibrate(24);
if (minecraft->isOnline()) { if (minecraft->isOnline()) {
RemoveBlockPacket packet(minecraft->player, x, y, z); RemoveBlockPacket packet(minecraft->player, x, y, z);
minecraft->raknetInstance->send(packet); minecraft->raknetInstance->send(packet);
} }
} }
return changed; return changed;
} }
/*virtual*/ /*virtual*/
bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit) { bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit) {
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;
item = player->inventory->getSelected(); if (level->isClientSide) {
if(level->isClientSide) { item = player->inventory->getSelected();
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);
} }
int t = level->getTile(x, y, z); int t = level->getTile(x, y, z);
if (t == Tile::invisible_bedrock->id) return false; if (t == Tile::invisible_bedrock->id) return false;
if (t > 0 && Tile::tiles[t]->use(level, x, y, z, player)) if (t > 0 && Tile::tiles[t]->use(level, x, y, z, player))
return true; return true;
if (item == NULL) return false; if (item == NULL) return false;
if(isCreativeType()) { if(isCreativeType()) {
int aux = item->getAuxValue(); int aux = item->getAuxValue();
int count = item->count; int count = item->count;
bool success = item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ); bool success = item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ);
item->setAuxValue(aux); item->setAuxValue(aux);
item->count = count; item->count = count;
return success; return success;
} else { } else {
return item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ); return item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ);
} }
} }
bool GameMode::useItem( Player* player, Level* level, ItemInstance* item ) { bool GameMode::useItem( Player* player, Level* level, ItemInstance* item ) {
int oldCount = item->count; int oldCount = item->count;
ItemInstance* itemInstance = item->use(level, player); ItemInstance* itemInstance = item->use(level, player);
if(level->isClientSide) { if(level->isClientSide) {
UseItemPacket packet(item, player->entityId, player->aimDirection); UseItemPacket packet(item, player->entityId, player->aimDirection);
minecraft->raknetInstance->send(packet); minecraft->raknetInstance->send(packet);
} }
if (itemInstance != item || (itemInstance != NULL && itemInstance->count != oldCount)) { if (itemInstance != item || (itemInstance != NULL && itemInstance->count != oldCount)) {
//player.inventory.items[player.inventory.selected] = itemInstance; //player.inventory.items[player.inventory.selected] = itemInstance;
//if (itemInstance.count == 0) { //if (itemInstance.count == 0) {
// player.inventory.items[player.inventory.selected] = NULL; // player.inventory.items[player.inventory.selected] = NULL;
//} //}
return true; return true;
} }
return false; return false;
} }
ItemInstance* GameMode::handleInventoryMouseClick( int containerId, int slotNum, int buttonNum, Player* player ) { ItemInstance* GameMode::handleInventoryMouseClick( int containerId, int slotNum, int buttonNum, Player* player ) {
//return player.containerMenu.clicked(slotNum, buttonNum, player); //return player.containerMenu.clicked(slotNum, buttonNum, player);
return NULL; return NULL;
} }
void GameMode::handleCloseInventory( int containerId, Player* player ) { void GameMode::handleCloseInventory( int containerId, Player* player ) {
//player.containerMenu.removed(player); //player.containerMenu.removed(player);
//player.containerMenu = player.inventoryMenu; //player.containerMenu = player.inventoryMenu;
} }
float GameMode::getPickRange() { float GameMode::getPickRange() {
return 5.0f; return 5.0f;
} }
void GameMode::initPlayer( Player* player ) { void GameMode::initPlayer( Player* player ) {
initAbilities(player->abilities); initAbilities(player->abilities);
} }
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);
} }
player->releaseUsingItem(); player->releaseUsingItem();
} }
void GameMode::tick() { void GameMode::tick() {
oDestroyProgress = destroyProgress; oDestroyProgress = destroyProgress;
} }
void GameMode::render( float a ) { void GameMode::render( float a ) {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
if (destroyProgress <= 0) { if (destroyProgress <= 0) {
minecraft->gui.progress = 0; minecraft->gui.progress = 0;
minecraft->levelRenderer->destroyProgress = 0; minecraft->levelRenderer->destroyProgress = 0;
} else { } else {
float dp = oDestroyProgress + (destroyProgress - oDestroyProgress) * a; float dp = oDestroyProgress + (destroyProgress - oDestroyProgress) * a;
minecraft->gui.progress = dp; minecraft->gui.progress = dp;
minecraft->levelRenderer->destroyProgress = dp; minecraft->levelRenderer->destroyProgress = dp;
} }
#endif #endif
} }

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

@@ -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) {
@@ -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
blit(screenWidth / 2 + 10 * getNumSlots() - 20 + 4, ySlot + 6, 242, 252, 14, 4, 14, 4); if (_openInventorySlot) {
#endif blit(screenWidth / 2 + 10 * getNumSlots() - 20 + 4, ySlot + 6, 242, 252, 14, 4, 14, 4);
}
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

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

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

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,10 +146,13 @@ 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();
minecraft->screenChooser.setScreen(SCREEN_STARTMENU); if (minecraft->screen != NULL) {
minecraft->setScreen(NULL);
} else {
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;
@@ -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);
@@ -230,7 +229,6 @@ void OptionsScreen::generateOptionScreens() {
} }
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);
@@ -238,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

@@ -21,7 +21,7 @@ Screen* ScreenChooser::createScreen( ScreenId id )
Screen* screen = NULL; Screen* screen = NULL;
// :sob: // :sob:
if (_mc->useTouchscreen()) { 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;

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,25 +464,29 @@ 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];
// If the recipe allows any aux-value as ingredients, first deplete // If the recipe allows any aux-value as ingredients, first deplete
// aux == 0 from inventory. Since I'm not sure if this always is // aux == 0 from inventory. Since I'm not sure if this always is
// correct, let's only do it for ingredient sandstone for now. // correct, let's only do it for ingredient sandstone for now.
ItemInstance toRemove = req.item; ItemInstance toRemove = req.item;
if (Tile::sandStone->id == req.item.id if (Tile::sandStone->id == req.item.id
&& Recipe::ANY_AUX_VALUE == req.item.getAuxValue()) { && Recipe::ANY_AUX_VALUE == req.item.getAuxValue()) {
toRemove.setAuxValue(0); toRemove.setAuxValue(0);
toRemove.count = minecraft->player->inventory->removeResource(toRemove, true); toRemove.count = minecraft->player->inventory->removeResource(toRemove, true);
toRemove.setAuxValue(Recipe::ANY_AUX_VALUE); toRemove.setAuxValue(Recipe::ANY_AUX_VALUE);
} }
if (toRemove.count > 0) { if (toRemove.count > 0) {
minecraft->player->inventory->removeResource(toRemove); minecraft->player->inventory->removeResource(toRemove);
} }
} }
// ... add the new one! (in this order, to fill empty slots better) // ... add the new one! (in this order, to fill empty slots better)
// if it doesn't fit, throw it on the ground! // if it doesn't fit, throw it on the ground!
@@ -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

@@ -1,291 +1,293 @@
#include "TouchIngameBlockSelectionScreen.h" #include "TouchIngameBlockSelectionScreen.h"
#include "../crafting/WorkbenchScreen.h" #include "../crafting/WorkbenchScreen.h"
#include "../../Screen.h" #include "../../Screen.h"
#include "../../components/ImageButton.h" #include "../../components/ImageButton.h"
#include "../../components/InventoryPane.h" #include "../../components/InventoryPane.h"
#include "../../../gamemode/GameMode.h" #include "../../../gamemode/GameMode.h"
#include "../../../renderer/TileRenderer.h" #include "../../../renderer/TileRenderer.h"
#include "../../../player/LocalPlayer.h" #include "../../../player/LocalPlayer.h"
#include "../../../renderer/gles.h" #include "../../../renderer/gles.h"
#include "../../../renderer/entity/ItemRenderer.h" #include "../../../renderer/entity/ItemRenderer.h"
#include "../../../renderer/Tesselator.h" #include "../../../renderer/Tesselator.h"
#include "../../../renderer/Textures.h" #include "../../../renderer/Textures.h"
#include "../../../Minecraft.h" #include "../../../Minecraft.h"
#include "../../../sound/SoundEngine.h" #include "../../../sound/SoundEngine.h"
#include "../../../../world/entity/player/Inventory.h" #include "../../../../world/entity/player/Inventory.h"
#include "../../../../platform/input/Mouse.h" #include "../../../../platform/input/Mouse.h"
#include "../../../../util/Mth.h" #include "../../../../util/Mth.h"
#include "../../../../world/item/ItemInstance.h" #include "../../../../world/item/ItemInstance.h"
#include "../../../../world/entity/player/Player.h" #include "../../../../world/entity/player/Player.h"
#include "../../../../world/item/crafting/Recipe.h" #include "../../../../world/item/crafting/Recipe.h"
#include "../../../player/input/touchscreen/TouchAreaModel.h" #include "../../../player/input/touchscreen/TouchAreaModel.h"
#include "../ArmorScreen.h" #include "../ArmorScreen.h"
namespace Touch { namespace Touch {
#if defined(__APPLE__) #if defined(__APPLE__)
static const std::string demoVersionString("Not available in the Lite version"); static const std::string demoVersionString("Not available in the Lite version");
#else #else
static const std::string demoVersionString("Not available in the demo version"); static const std::string demoVersionString("Not available in the demo version");
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
static const float BorderPixels = 4; static const float BorderPixels = 4;
#ifdef DEMO_MODE #ifdef DEMO_MODE
static const float BlockPixels = 22; static const float BlockPixels = 22;
#else #else
static const float BlockPixels = 22; static const float BlockPixels = 22;
#endif #endif
#else #else
static const float BorderPixels = 4; static const float BorderPixels = 4;
static const float BlockPixels = 24; static const float BlockPixels = 24;
#endif #endif
static const int ItemSize = (int)(BlockPixels + 2*BorderPixels); static const int ItemSize = (int)(BlockPixels + 2*BorderPixels);
static const int Bx = 10; // Border Frame width static const int Bx = 10; // Border Frame width
static const int By = 6; // Border Frame height static const int By = 6; // Border Frame height
// //
// Block selection screen // Block selection screen
// //
IngameBlockSelectionScreen::IngameBlockSelectionScreen() IngameBlockSelectionScreen::IngameBlockSelectionScreen()
: selectedItem(0), : selectedItem(0),
_blockList(NULL), _blockList(NULL),
_pendingClose(false), _pendingClose(false),
bArmor (4, "Armor"), bArmor (4, "Armor"),
bDone (3, ""), bDone (3, ""),
//bDone (3, "Done"), //bDone (3, "Done"),
bMenu (2, "Menu"), bMenu (2, "Menu"),
bCraft (1, "Craft"), bCraft (1, "Craft"),
bHeader (0, "Select blocks") bHeader (0, "Select blocks")
{ {
} }
IngameBlockSelectionScreen::~IngameBlockSelectionScreen() IngameBlockSelectionScreen::~IngameBlockSelectionScreen()
{ {
delete _blockList; delete _blockList;
} }
void IngameBlockSelectionScreen::init() void IngameBlockSelectionScreen::init()
{ {
Inventory* inventory = minecraft->player->inventory; Inventory* inventory = minecraft->player->inventory;
//const int itemWidth = 2 * BorderPixels + //const int itemWidth = 2 * BorderPixels +
int maxWidth = width - Bx - Bx; int maxWidth = width - Bx - Bx;
InventoryColumns = maxWidth / ItemSize; InventoryColumns = maxWidth / ItemSize;
const int realWidth = InventoryColumns * ItemSize; const int realWidth = InventoryColumns * ItemSize;
const int realBx = (width - realWidth) / 2; const int realBx = (width - realWidth) / 2;
IntRectangle rect(realBx, IntRectangle rect(realBx,
#ifdef __APPLE__ #ifdef __APPLE__
24 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-20-24); 24 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-20-24);
#else #else
24 + By, realWidth, height-By-By-20-24); 24 + By, realWidth, height-By-By-20-24);
#endif #endif
_blockList = new InventoryPane(this, minecraft, rect, width, BorderPixels, inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE, ItemSize, (int)BorderPixels); _blockList = new InventoryPane(this, minecraft, rect, width, BorderPixels, inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE, ItemSize, (int)BorderPixels);
_blockList->fillMarginX = realBx; _blockList->fillMarginX = realBx;
//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.
InventoryRows = 1 + (InventorySize-1) / InventoryColumns; InventorySize = inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE;
InventoryRows = 1 + (InventorySize-1) / InventoryColumns;
//
// Buttons //
// // Buttons
ImageDef def; //
def.name = "gui/spritesheet.png"; ImageDef def;
def.x = 0; def.name = "gui/spritesheet.png";
def.y = 1; def.x = 0;
def.width = def.height = 18; def.y = 1;
def.setSrc(IntRectangle(60, 0, 18, 18)); def.width = def.height = 18;
bDone.setImageDef(def, true); def.setSrc(IntRectangle(60, 0, 18, 18));
bDone.width = bDone.height = 19; bDone.setImageDef(def, true);
bDone.width = bDone.height = 19;
bDone.scaleWhenPressed = false;
bDone.scaleWhenPressed = false;
buttons.push_back(&bHeader);
buttons.push_back(&bDone); buttons.push_back(&bHeader);
if (!minecraft->isCreativeMode()) { buttons.push_back(&bDone);
buttons.push_back(&bCraft); if (!minecraft->isCreativeMode()) {
buttons.push_back(&bArmor); buttons.push_back(&bCraft);
} buttons.push_back(&bArmor);
} }
}
void IngameBlockSelectionScreen::setupPositions() {
bHeader.y = bDone.y = bCraft.y = 0; void IngameBlockSelectionScreen::setupPositions() {
bDone.x = width - bDone.width; bHeader.y = bDone.y = bCraft.y = 0;
bCraft.x = 0;//width - bDone.w - bCraft.w; bDone.x = width - bDone.width;
bCraft.width = bArmor.width = 48; bCraft.x = 0;//width - bDone.w - bCraft.w;
bArmor.x = bCraft.width; bCraft.width = bArmor.width = 48;
bArmor.x = bCraft.width;
if (minecraft->isCreativeMode()) {
bHeader.x = 0; if (minecraft->isCreativeMode()) {
bHeader.width = width;// - bDone.w; bHeader.x = 0;
bHeader.xText = width/2; // Center of the screen bHeader.width = width;// - bDone.w;
} else { bHeader.xText = width/2; // Center of the screen
bHeader.x = bCraft.width + bArmor.width; } else {
bHeader.width = width - bCraft.width - bArmor.width;// - bDone.w; bHeader.x = bCraft.width + bArmor.width;
bHeader.xText = bHeader.x + (bHeader.width - bDone.width) /2; bHeader.width = width - bCraft.width - bArmor.width;// - bDone.w;
} bHeader.xText = bHeader.x + (bHeader.width - bDone.width) /2;
}
clippingArea.x = 0;
clippingArea.w = minecraft->width; clippingArea.x = 0;
clippingArea.y = 0; clippingArea.w = minecraft->width;
clippingArea.h = (int)(Gui::GuiScale * 24); clippingArea.y = 0;
} clippingArea.h = (int)(Gui::GuiScale * 24);
}
void IngameBlockSelectionScreen::removed()
{ void IngameBlockSelectionScreen::removed()
minecraft->gui.inventoryUpdated(); {
} minecraft->gui.inventoryUpdated();
}
int IngameBlockSelectionScreen::getSlotPosX(int slotX) {
// @todo: Number of columns int IngameBlockSelectionScreen::getSlotPosX(int slotX) {
return width / 2 - InventoryColumns * 10 + slotX * 20 + 2; // @todo: Number of columns
} return width / 2 - InventoryColumns * 10 + slotX * 20 + 2;
}
int IngameBlockSelectionScreen::getSlotPosY(int slotY) {
return height - 16 - 3 - 22 * 2 - 22 * slotY; int IngameBlockSelectionScreen::getSlotPosY(int slotY) {
} return height - 16 - 3 - 22 * 2 - 22 * slotY;
}
int IngameBlockSelectionScreen::getSlotHeight() {
// same as non-touch implementation int IngameBlockSelectionScreen::getSlotHeight() {
return 22; // same as non-touch implementation
} return 22;
}
void IngameBlockSelectionScreen::mouseClicked(int x, int y, int buttonNum) {
_pendingClose = _blockList->_clickArea->isInside((float)x, (float)y); void IngameBlockSelectionScreen::mouseClicked(int x, int y, int buttonNum) {
if (!_pendingClose) _pendingClose = _blockList->_clickArea->isInside((float)x, (float)y);
super::mouseClicked(x, y, buttonNum); if (!_pendingClose)
} super::mouseClicked(x, y, buttonNum);
}
void IngameBlockSelectionScreen::mouseReleased(int x, int y, int buttonNum) {
if (_pendingClose && _blockList->_clickArea->isInside((float)x, (float)y)) void IngameBlockSelectionScreen::mouseReleased(int x, int y, int buttonNum) {
minecraft->setScreen(NULL); if (_pendingClose && _blockList->_clickArea->isInside((float)x, (float)y))
else minecraft->setScreen(NULL);
super::mouseReleased(x, y, buttonNum); else
} super::mouseReleased(x, y, buttonNum);
}
void IngameBlockSelectionScreen::mouseWheel(int dx, int dy, int xm, int ym)
{ void IngameBlockSelectionScreen::mouseWheel(int dx, int dy, int xm, int ym)
if (dy == 0) return; {
if (_blockList) { if (dy == 0) return;
float amount = -dy * getSlotHeight(); if (_blockList) {
_blockList->scrollBy(0, amount); float amount = -dy * getSlotHeight();
} _blockList->scrollBy(0, amount);
int cols = InventoryColumns; }
int maxIndex = InventorySize - 1; int cols = InventoryColumns;
int idx = selectedItem; int maxIndex = InventorySize - 1;
if (dy > 0) { int idx = selectedItem;
if (idx >= cols) idx -= cols; if (dy > 0) {
} else { if (idx >= cols) idx -= cols;
if (idx + cols <= maxIndex) idx += cols; } else {
} if (idx + cols <= maxIndex) idx += cols;
selectedItem = idx; }
} selectedItem = idx;
}
bool IngameBlockSelectionScreen::addItem(const InventoryPane* pane, int itemId)
{ bool IngameBlockSelectionScreen::addItem(const InventoryPane* pane, int itemId)
Inventory* inventory = minecraft->player->inventory; {
itemId += Inventory::MAX_SELECTION_SIZE; Inventory* inventory = minecraft->player->inventory;
itemId += Inventory::MAX_SELECTION_SIZE;
if (!inventory->getItem(itemId))
return false; if (!inventory->getItem(itemId))
return false;
inventory->moveToSelectionSlot(0, itemId, true);
inventory->moveToSelectionSlot(0, itemId, true);
inventory->selectSlot(0);
#ifdef __APPLE__ inventory->selectSlot(0);
minecraft->soundEngine->playUI("random.pop", 0.3f, 0.3f);//1.0f + 0.2f*(Mth::random()-Mth::random())); #ifdef __APPLE__
#else minecraft->soundEngine->playUI("random.pop", 0.3f, 0.3f);//1.0f + 0.2f*(Mth::random()-Mth::random()));
minecraft->soundEngine->playUI("random.pop2", 1.0f, 0.3f);//1.0f + 0.2f*(Mth::random()-Mth::random())); #else
#endif minecraft->soundEngine->playUI("random.pop2", 1.0f, 0.3f);//1.0f + 0.2f*(Mth::random()-Mth::random()));
#endif
// Flash the selected gui item
minecraft->gui.flashSlot(inventory->selected); // Flash the selected gui item
return true; minecraft->gui.flashSlot(inventory->selected);
} return true;
}
void IngameBlockSelectionScreen::tick()
{ void IngameBlockSelectionScreen::tick()
_blockList->tick(); {
super::tick(); _blockList->tick();
} super::tick();
}
void IngameBlockSelectionScreen::render( int xm, int ym, float a )
{ void IngameBlockSelectionScreen::render( int xm, int ym, float a )
glDisable2(GL_DEPTH_TEST); {
glEnable2(GL_BLEND); glDisable2(GL_DEPTH_TEST);
glEnable2(GL_BLEND);
Screen::render(xm, ym, a);
_blockList->render(xm, ym, a); Screen::render(xm, ym, a);
_blockList->render(xm, ym, a);
// render frame
IntRectangle& bbox = _blockList->rect; // render frame
Tesselator::instance.colorABGR(0xffffffff); IntRectangle& bbox = _blockList->rect;
minecraft->textures->loadAndBindTexture("gui/itemframe.png"); Tesselator::instance.colorABGR(0xffffffff);
glEnable2(GL_BLEND); minecraft->textures->loadAndBindTexture("gui/itemframe.png");
glColor4f2(1, 1, 1, 1); glEnable2(GL_BLEND);
glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f2(1, 1, 1, 1);
blit(0, bbox.y-By, 0, 0, width, bbox.h+By+By, 215, 256); // why bbox.h + 1*B? glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable2(GL_BLEND); blit(0, bbox.y-By, 0, 0, width, bbox.h+By+By, 215, 256); // why bbox.h + 1*B?
glDisable2(GL_BLEND);
glEnable2(GL_DEPTH_TEST);
} glEnable2(GL_DEPTH_TEST);
}
void IngameBlockSelectionScreen::renderDemoOverlay() {
#ifdef DEMO_MODE void IngameBlockSelectionScreen::renderDemoOverlay() {
fill( getSlotPosX(0) - 3, getSlotPosY(1) - 3, #ifdef DEMO_MODE
getSlotPosX(9) - 3, getSlotPosY(-1) - 3, 0xa0 << 24); fill( getSlotPosX(0) - 3, getSlotPosY(1) - 3,
getSlotPosX(9) - 3, getSlotPosY(-1) - 3, 0xa0 << 24);
const int centerX = (getSlotPosX(4) + getSlotPosX(5)) / 2;
const int centerY = (getSlotPosY(0) + getSlotPosY(1)) / 2 + 5; const int centerX = (getSlotPosX(4) + getSlotPosX(5)) / 2;
drawCenteredString(minecraft->font, demoVersionString, centerX, centerY, 0xffffffff); const int centerY = (getSlotPosY(0) + getSlotPosY(1)) / 2 + 5;
#endif /*DEMO_MODE*/ drawCenteredString(minecraft->font, demoVersionString, centerX, centerY, 0xffffffff);
} #endif /*DEMO_MODE*/
}
void IngameBlockSelectionScreen::buttonClicked(Button* button) {
if (button->id == bDone.id) void IngameBlockSelectionScreen::buttonClicked(Button* button) {
minecraft->setScreen(NULL); if (button->id == bDone.id)
minecraft->setScreen(NULL);
if (button->id == bMenu.id)
minecraft->screenChooser.setScreen(SCREEN_PAUSE); if (button->id == bMenu.id)
minecraft->screenChooser.setScreen(SCREEN_PAUSE);
if (button->id == bCraft.id)
minecraft->setScreen(new WorkbenchScreen(Recipe::SIZE_2X2)); if (button->id == bCraft.id)
minecraft->setScreen(new WorkbenchScreen(Recipe::SIZE_2X2));
if (button == &bArmor)
minecraft->setScreen(new ArmorScreen()); if (button == &bArmor)
} minecraft->setScreen(new ArmorScreen());
}
bool IngameBlockSelectionScreen::isAllowed( int slot )
{ bool IngameBlockSelectionScreen::isAllowed( int slot )
if (slot < 0 || slot >= minecraft->player->inventory->getContainerSize()) {
return false; const int gridCount = minecraft->player->inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE;
if (slot < 0 || slot >= gridCount)
#ifdef DEMO_MODE return false;
if (slot >= (minecraft->isCreativeMode()? 28 : 27)) return false;
#endif #ifdef DEMO_MODE
return true; if (slot >= (minecraft->isCreativeMode()? 28 : 27)) return false;
} #endif
return true;
bool IngameBlockSelectionScreen::hasClippingArea( IntRectangle& out ) }
{
out = clippingArea; bool IngameBlockSelectionScreen::hasClippingArea( IntRectangle& out )
return true; {
} out = clippingArea;
return true;
std::vector<const ItemInstance*> IngameBlockSelectionScreen::getItems( const InventoryPane* forPane ) }
{
std::vector<const ItemInstance*> out; std::vector<const ItemInstance*> IngameBlockSelectionScreen::getItems( const InventoryPane* forPane )
for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) {
out.push_back(minecraft->player->inventory->getItem(i)); std::vector<const ItemInstance*> out;
return out; for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i)
} out.push_back(minecraft->player->inventory->getItem(i));
return out;
} }
}

View File

@@ -388,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;
@@ -450,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);
} }
} }
@@ -506,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

@@ -164,7 +164,7 @@ void TouchscreenInput_TestFps::onConfigChanged(const Config& c) {
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);
float btnSize = pc.millimetersToPixels(50); float btnSize = pc.millimetersToPixels(18 * Gui::GuiScale);
_model.addArea(AREA_PAUSE, aPause = new RectangleArea(w - 4 - btnSize, 4, w - 4, 4 + btnSize)); _model.addArea(AREA_PAUSE, aPause = new RectangleArea(w - 4 - btnSize, 4, w - 4, 4 + btnSize));
_model.addArea(AREA_CHAT, aChat = new RectangleArea(w - 8 - btnSize * 2, 4, w - 8 - btnSize, 4 + btnSize)); _model.addArea(AREA_CHAT, aChat = new RectangleArea(w - 8 - btnSize * 2, 4, w - 8 - btnSize, 4 + btnSize));
@@ -320,6 +320,7 @@ void TouchscreenInput_TestFps::tick( Player* player )
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_CONSOLE); _minecraft->screenChooser.setScreen(SCREEN_CONSOLE);
_minecraft->platform()->showKeyboard();
} }
} }

View File

@@ -153,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) {
@@ -164,7 +164,6 @@ void GameRenderer::render(float a) {
yMouse = -9999; yMouse = -9999;
} }
} }
#endif
TIMER_POP(); TIMER_POP();
bool hasClearedColorBuffer = false; bool hasClearedColorBuffer = false;
@@ -361,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);
} }
} }
@@ -657,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);

View File

@@ -17,8 +17,8 @@ PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow )
: super(humanoidModel, shadow), : super(humanoidModel, shadow),
playerModel64(humanoidModel), playerModel64(humanoidModel),
playerModel32(new HumanoidModel(0, 0, 64, 32)), playerModel32(new HumanoidModel(0, 0, 64, 32)),
armorParts1(new HumanoidModel(1.0f, 0, 64, 64)), armorParts1(new HumanoidModel(1.0f, 0, 64, 32)),
armorParts2(new HumanoidModel(0.5f, 0, 64, 64)) armorParts2(new HumanoidModel(0.5f, 0, 64, 32))
{ {
// default to legacy skin path until we know the exact texture size // default to legacy skin path until we know the exact texture size
model = playerModel32; model = playerModel32;
@@ -77,10 +77,10 @@ void PlayerRenderer::render(Entity* mob_, float x, float y, float z, float rot,
model = desired; model = desired;
humanoidModel = desired; humanoidModel = desired;
} }
// LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n", /* LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n",
// ((Player*)mob)->name.c_str(), mob->getTexture().c_str(), ((Player*)mob)->name.c_str(), mob->getTexture().c_str(),
// humanoidModel->texWidth, humanoidModel->texHeight, humanoidModel->texWidth, humanoidModel->texHeight,
// (desired == playerModel64 ? "64" : "32")); (desired == playerModel64 ? "64" : "32")); */
HumanoidMobRenderer::render(mob_, x, y, z, rot, a); HumanoidMobRenderer::render(mob_, x, y, z, rot, a);
} }

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

@@ -1,3 +1,4 @@
#include <fstream>
#include <iostream> #include <iostream>
#include "NinecraftApp.h" #include "NinecraftApp.h"
#include "AppPlatform.h" #include "AppPlatform.h"
@@ -11,6 +12,7 @@
#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 +29,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()); if (valuePos == std::string::npos) {
printf("--levelname - The name of the server [default: \"%s\"]\n", defaultSettings.getLevelName().c_str()); throw std::runtime_error("Cannot find value");
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()); std::string valueStr = "";
printf("--serverkey - The key that the server should use for API calls. [default: \"%s\"]\n", defaultSettings.getServerKey().c_str());
printf("-------------------------------------------------------\n"); valuePos += 1 + line.size();
return 0;
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", aSettings.getLevelName().c_str());
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 +208,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);

View File

@@ -1,6 +1,7 @@
#include "ClientSideNetworkHandler.h" #include "ClientSideNetworkHandler.h"
#include "client/Options.h" #include "client/Options.h"
#include "network/packet/LoginStatusPacket.h"
#include "packet/PacketInclude.h" #include "packet/PacketInclude.h"
#include "RakNetInstance.h" #include "RakNetInstance.h"
#include "../world/level/chunk/ChunkSource.h" #include "../world/level/chunk/ChunkSource.h"
@@ -10,6 +11,9 @@
#include "../world/entity/player/Inventory.h" #include "../world/entity/player/Inventory.h"
#include "../client/Minecraft.h" #include "../client/Minecraft.h"
#include "../client/gamemode/GameMode.h" #include "../client/gamemode/GameMode.h"
#include "world/item/ItemInstance.h"
#include "world/level/LevelConstants.h"
#include <cstddef>
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "../client/gui/screens/DisconnectionScreen.h" #include "../client/gui/screens/DisconnectionScreen.h"
#endif #endif
@@ -42,6 +46,9 @@ ClientSideNetworkHandler::ClientSideNetworkHandler(Minecraft* minecraft, IRakNet
requestNextChunkPosition(0), requestNextChunkPosition(0),
requestNextChunkIndex(0) requestNextChunkIndex(0)
{ {
NumRequestChunks = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH;
requestNextChunkIndexList.resize(NumRequestChunks);
chunksLoaded.resize(NumRequestChunks);
rakPeer = raknetInstance->getPeer(); rakPeer = raknetInstance->getPeer();
} }
@@ -59,7 +66,7 @@ void ClientSideNetworkHandler::requestNextChunk()
//LOGI("requesting chunks @ (%d, %d)\n", chunk.x, chunk.y); //LOGI("requesting chunks @ (%d, %d)\n", chunk.x, chunk.y);
//raknetInstance->send(new RequestChunkPacket(requestNextChunkPosition % CHUNK_CACHE_WIDTH, requestNextChunkPosition / CHUNK_CACHE_WIDTH)); //raknetInstance->send(new RequestChunkPacket(requestNextChunkPosition % LevelConstants::CHUNK_CACHE_WIDTH, requestNextChunkPosition / LevelConstants::CHUNK_CACHE_WIDTH));
requestNextChunkIndex++; requestNextChunkIndex++;
requestNextChunkPosition++; requestNextChunkPosition++;
} }
@@ -67,16 +74,16 @@ void ClientSideNetworkHandler::requestNextChunk()
bool ClientSideNetworkHandler::areAllChunksLoaded() bool ClientSideNetworkHandler::areAllChunksLoaded()
{ {
return (requestNextChunkPosition >= (CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH)); return (requestNextChunkPosition >= (LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH));
} }
bool ClientSideNetworkHandler::isChunkLoaded(int x, int z) bool ClientSideNetworkHandler::isChunkLoaded(int x, int z)
{ {
if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH) { if (x < 0 || x >= LevelConstants::CHUNK_CACHE_WIDTH || z < 0 || z >= LevelConstants::CHUNK_CACHE_WIDTH) {
LOGE("Error: Tried to request chunk (%d, %d)\n", x, z); LOGE("Error: Tried to request chunk (%d, %d)\n", x, z);
return true; return true;
} }
return chunksLoaded[x * CHUNK_CACHE_WIDTH + z]; return chunksLoaded[x * LevelConstants::CHUNK_CACHE_WIDTH + z];
//return areAllChunksLoaded(); //return areAllChunksLoaded();
} }
@@ -86,7 +93,7 @@ void ClientSideNetworkHandler::onConnect(const RakNet::RakNetGUID& hostGuid)
serverGuid = hostGuid; serverGuid = hostGuid;
clearChunksLoaded(); clearChunksLoaded();
LoginPacket packet(minecraft->options.getStringValue(OPTIONS_USERNAME).c_str(), SharedConstants::NetworkProtocolVersion); LoginPacket packet(minecraft->options.getStringValue(OPTIONS_USERNAME).c_str(), SharedConstants::NetworkProtocolVersion, true);
raknetInstance->send(packet); raknetInstance->send(packet);
} }
@@ -97,6 +104,11 @@ void ClientSideNetworkHandler::onUnableToConnect()
void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid)
{ {
LevelConstants::CHUNK_CACHE_WIDTH = 16;
LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH;
LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH;
// TODO: Good disconnecting
LOGI("onDisconnect\n"); LOGI("onDisconnect\n");
if (level) if (level)
{ {
@@ -109,6 +121,7 @@ void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid)
} }
} }
} }
minecraft->setLevel(NULL);
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
minecraft->gui.addMessage("Disconnected from server"); minecraft->gui.addMessage("Disconnected from server");
#endif #endif
@@ -130,6 +143,18 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginSta
LOGI("Disconnect! Server is outdated!\n"); LOGI("Disconnect! Server is outdated!\n");
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
minecraft->setScreen(new DisconnectionScreen("Could not connect: Outdated server!")); minecraft->setScreen(new DisconnectionScreen("Could not connect: Outdated server!"));
#endif
}
if (packet->status == LoginStatus::Failed_TakenNickname) {
LOGI("Disconnect! Nickname is taken!\n");
#ifndef STANDALONE_SERVER
minecraft->setScreen(new DisconnectionScreen("Could not connect: Nickname is taken!"));
#endif
}
if (packet->status == LoginStatus::Failed_Banned) {
LOGI("Disconnect! You're banned from this server!\n");
#ifndef STANDALONE_SERVER
minecraft->setScreen(new DisconnectionScreen("Could not connect: You're banned from this server!"));
#endif #endif
} }
} }
@@ -146,6 +171,19 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, StartGam
} }
#endif #endif
// @todo @note i think its trash
// we can put it directly to selectLevel?
if (packet->chunkCacheWidth != 0) {
printf("lol \n");
LevelConstants::CHUNK_CACHE_WIDTH = packet->chunkCacheWidth;
LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH;
LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH;
}
NumRequestChunks = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH;
requestNextChunkIndexList.resize(NumRequestChunks);
chunksLoaded.resize(NumRequestChunks);
const std::string& levelId = LevelStorageSource::TempLevelId; const std::string& levelId = LevelStorageSource::TempLevelId;
LevelStorageSource* storageSource = minecraft->getLevelSource(); LevelStorageSource* storageSource = minecraft->getLevelSource();
storageSource->deleteLevel(levelId); storageSource->deleteLevel(levelId);
@@ -324,7 +362,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveEn
if (!level) return; if (!level) return;
Entity* entity = level->getEntity(packet->entityId); Entity* entity = level->getEntity(packet->entityId);
LOGI("RemoveEntityPacket %p %p, %d\n", entity, minecraft->player, entity?(int)(entity->isPlayer()): -1); // LOGI("RemoveEntityPacket %p %p, %d\n", entity, minecraft->player, entity?(int)(entity->isPlayer()): -1);
if (!entity) return; if (!entity) return;
level->removeEntity(entity); level->removeEntity(entity);
@@ -344,6 +382,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddItemE
} }
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TakeItemEntityPacket* packet) { void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TakeItemEntityPacket* packet) {
printf("TakeItemEntityPacket \n");
if (!level) return; if (!level) return;
Entity* e = level->getEntity(packet->itemId); Entity* e = level->getEntity(packet->itemId);
@@ -386,6 +425,54 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlay
} }
} }
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SendInventoryPacket* packet) {
if (!level) return;
if (packet->entityId == minecraft->player->entityId) {
auto items = packet->items;
minecraft->player->inventory->replace(items);
for (int i = 0; i < packet->linkedSlot.size(); i++) {
minecraft->player->inventory->linkSlot(i, packet->linkedSlot[i].inventorySlot, true);
LOGI("%i -> %i\n", packet->linkedSlot[i].inventorySlot, i);
}
}
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TakeItemPacket* packet) {
if (!level) return;
LOGI("TakeItemPacket\n");
ItemInstance* item;
item->count = packet->count;
item->id = packet->itemId;
item->setAuxValue(packet->auxValue);
// if (minecraft->player->entityId == packet->playerId) {
if (!minecraft->player->inventory->add(item)) {
minecraft->player->drop(new ItemInstance(*item), false);
}
// }
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveItemPacket* packet) {
// Idk how it works...
if (!level) return;
ItemInstance item;
item.count = packet->count;
item.id = packet->itemId;
item.setAuxValue(packet->auxValue);
// if (minecraft->player->entityId == packet->playerId) {
minecraft->player->inventory->removeResource(item);
// }
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MoveEntityPacket* packet) void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MoveEntityPacket* packet)
{ {
if (!level) if (!level)
@@ -475,19 +562,19 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat
//unsigned char* blockIds = chunk->getBlockData(); //unsigned char* blockIds = chunk->getBlockData();
DataLayer& blockData = chunk->data; DataLayer& blockData = chunk->data;
const int setSize = LEVEL_HEIGHT / 8; const int setSize = LevelConstants::LEVEL_HEIGHT / 8;
const int setShift = 4; // power of LEVEL_HEIGHT / 8 const int setShift = 4; // power of LevelConstants::LEVEL_HEIGHT / 8
bool recalcHeight = false; bool recalcHeight = false;
int x0 = 16, x1 = 0, z0 = 16, z1 = 0, y0 = LEVEL_HEIGHT, y1 = 0; int x0 = 16, x1 = 0, z0 = 16, z1 = 0, y0 = LevelConstants::LEVEL_HEIGHT, y1 = 0;
int rx = packet->x << 4; int rx = packet->x << 4;
int rz = packet->z << 4; int rz = packet->z << 4;
unsigned char readBlockBuffer[setSize]; unsigned char* readBlockBuffer = new unsigned char[setSize];
unsigned char readDataBuffer[setSize / 2]; unsigned char* readDataBuffer = new unsigned char[setSize / 2];
for (int i = 0; i < CHUNK_COLUMNS; i++) for (int i = 0; i < LevelConstants::CHUNK_COLUMNS; i++)
{ {
unsigned char updateBits = 0; unsigned char updateBits = 0;
packet->chunkData.Read(updateBits); packet->chunkData.Read(updateBits);
@@ -496,8 +583,8 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat
{ {
recalcHeight = true; recalcHeight = true;
int colX = (i % CHUNK_WIDTH); int colX = (i % LevelConstants::CHUNK_WIDTH);
int colZ = (i / CHUNK_WIDTH); int colZ = (i / LevelConstants::CHUNK_WIDTH);
int colDataPosition = colX << 11 | colZ << 7; int colDataPosition = colX << 11 | colZ << 7;
for (int set = 0; set < 8; set++) for (int set = 0; set < 8; set++)
@@ -531,30 +618,33 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat
{ {
y0 = ((1 << set) << setShift); y0 = ((1 << set) << setShift);
} }
if (((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1 > y1) if (((1 << set) << setShift) + (LevelConstants::LEVEL_HEIGHT / 8) - 1 > y1)
{ {
y1 = ((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1; y1 = ((1 << set) << setShift) + (LevelConstants::LEVEL_HEIGHT / 8) - 1;
} }
} }
if ((i % CHUNK_WIDTH) < x0) if ((i % LevelConstants::CHUNK_WIDTH) < x0)
{ {
x0 = (i % CHUNK_WIDTH); x0 = (i % LevelConstants::CHUNK_WIDTH);
} }
if ((i % CHUNK_WIDTH) > x1) if ((i % LevelConstants::CHUNK_WIDTH) > x1)
{ {
x1 = (i % CHUNK_WIDTH); x1 = (i % LevelConstants::CHUNK_WIDTH);
} }
if ((i / CHUNK_WIDTH) < z0) if ((i / LevelConstants::CHUNK_WIDTH) < z0)
{ {
z0 = (i / CHUNK_WIDTH); z0 = (i / LevelConstants::CHUNK_WIDTH);
} }
if ((i / CHUNK_WIDTH) > z1) if ((i / LevelConstants::CHUNK_WIDTH) > z1)
{ {
z1 = (i / CHUNK_WIDTH); z1 = (i / LevelConstants::CHUNK_WIDTH);
} }
} }
} }
delete[] readBlockBuffer;
delete[] readDataBuffer;
if (recalcHeight) if (recalcHeight)
{ {
// chunk->recalcHeightmap(); // chunk->recalcHeightmap();
@@ -579,7 +669,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat
//chunk->terrainPopulated = true; //chunk->terrainPopulated = true;
chunk->unsaved = false; chunk->unsaved = false;
chunksLoaded[packet->x * CHUNK_CACHE_WIDTH + packet->z] = true; chunksLoaded[packet->x * LevelConstants::CHUNK_CACHE_WIDTH + packet->z] = true;
if (areAllChunksLoaded()) if (areAllChunksLoaded())
{ {
@@ -627,18 +717,18 @@ void ClientSideNetworkHandler::arrangeRequestChunkOrder() {
clearChunksLoaded(); clearChunksLoaded();
// Default sort is around center of the world // Default sort is around center of the world
int cx = CHUNK_CACHE_WIDTH / 2; int cx = LevelConstants::CHUNK_CACHE_WIDTH / 2;
int cz = CHUNK_CACHE_WIDTH / 2; int cz = LevelConstants::CHUNK_CACHE_WIDTH / 2;
// If player exists, let's sort around him // If player exists, let's sort around him
Player* p = minecraft? minecraft->player : NULL; Player* p = minecraft? minecraft->player : NULL;
if (p) { if (p) {
cx = Mth::floor(p->x / (float)CHUNK_WIDTH); cx = Mth::floor(p->x / (float)LevelConstants::CHUNK_WIDTH);
cz = Mth::floor(p->z / (float)CHUNK_DEPTH); cz = Mth::floor(p->z / (float)LevelConstants::CHUNK_DEPTH);
} }
_ChunkSorter sorter(cx, cz); _ChunkSorter sorter(cx, cz);
std::sort(requestNextChunkIndexList, requestNextChunkIndexList + NumRequestChunks, sorter); std::sort(requestNextChunkIndexList.begin(), requestNextChunkIndexList.end(), sorter);
} }
void ClientSideNetworkHandler::levelGenerated(Level* level) void ClientSideNetworkHandler::levelGenerated(Level* level)
@@ -782,6 +872,10 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimateP
} }
} }
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet)
{
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet)
{ {
} }
@@ -791,6 +885,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetHealt
if (!level || !minecraft->player) if (!level || !minecraft->player)
return; return;
printf("SetHealthPacket \n");
minecraft->player->hurtTo(packet->health); minecraft->player->hurtTo(packet->health);
} }
@@ -886,7 +981,11 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe
void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, ChatPacket* packet ) void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, ChatPacket* packet )
{ {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
minecraft->gui.displayClientMessage(packet->message); // minecraft->gui.displayClientMessage(packet->message);
std::istringstream iss(packet->message);
for (std::string line; std::getline(iss, line); ) {
minecraft->gui.addMessage(line);
}
#endif #endif
} }
@@ -919,8 +1018,8 @@ void ClientSideNetworkHandler::clearChunksLoaded()
{ {
// Init the chunk positions // Init the chunk positions
for (int i = 0; i < NumRequestChunks; ++i) { for (int i = 0; i < NumRequestChunks; ++i) {
requestNextChunkIndexList[i].x = i/CHUNK_WIDTH; requestNextChunkIndexList[i].x = i / LevelConstants::CHUNK_WIDTH;
requestNextChunkIndexList[i].y = i%CHUNK_WIDTH; requestNextChunkIndexList[i].y = i % LevelConstants::CHUNK_WIDTH;
chunksLoaded[i] = false; chunksLoaded[i] = false;
} }
} }

View File

@@ -77,6 +77,11 @@ public:
virtual void handle(const RakNet::RakNetGUID& source, ChatPacket* packet); virtual void handle(const RakNet::RakNetGUID& source, ChatPacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet); virtual void handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet); virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, RemoveItemPacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, TakeItemPacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, SendInventoryPacket* packet);
private: private:
void requestNextChunk(); void requestNextChunk();
@@ -97,11 +102,11 @@ private:
BlockUpdateList bufferedBlockUpdates; BlockUpdateList bufferedBlockUpdates;
int requestNextChunkPosition; int requestNextChunkPosition;
static const int NumRequestChunks = CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; int NumRequestChunks;
int requestNextChunkIndex; int requestNextChunkIndex;
IntPair requestNextChunkIndexList[NumRequestChunks]; std::vector<IntPair> requestNextChunkIndexList;
bool chunksLoaded[NumRequestChunks]; std::vector<bool> chunksLoaded;
}; };
#endif #endif

View File

@@ -1,33 +0,0 @@
#include "NATPunchHandler.h"
#include "../raknet/TCPInterface.h"
#include "../raknet/HTTPConnection.h"
#include "PHPDirectoryServer2.h"
using namespace RakNet;
NATPuchHandler::NATPuchHandler() {
tcpInterface = new TCPInterface;
}
NATPuchHandler::~NATPuchHandler() {
delete tcpInterface;
}
void NATPuchHandler::initialize() {
tcpInterface->Start(0, 64);
}
void NATPuchHandler::registerToGameList(const RakNet::RakString& serverName, int port) {
HTTPConnection httpConnection;
httpConnection.Init(tcpInterface, "johanbernhardsson.se");
PHPDirectoryServer2 directoryServer;
directoryServer.Init(&httpConnection, "/DirectoryServer.php");
directoryServer.UploadTable("", serverName, port, true);
}
void NATPuchHandler::removeFromGameList() {
}
void NATPuchHandler::close() {
}

View File

@@ -1,24 +0,0 @@
#ifndef _MINECRAFT_NETWORK_NATPUNCHHANDLER_H_
#define _MINECRAFT_NETWORK_NATPUNCHHANDLER_H_
#include "../raknet/TCPInterface.h"
#include "../raknet/RakString.h"
class NATPuchHandler {
public:
enum NATPuchHandlerStatus {
NATPuchInitilized = 0,
NATPuchFetchingServerList = 1,
NATPuchConnecting = 2,
NATPuchConnected = 3,
NATPuchDissconnected = 4
};
NATPuchHandler();
~NATPuchHandler();
void initialize();
void registerToGameList(const RakNet::RakString& serverName, int port);
void removeFromGameList();
void close();
private:
RakNet::TCPInterface *tcpInterface;
};
#endif /* _MINECRAFT_NETWORK_NATPUNCHHANDLER_H_ */

View File

@@ -18,6 +18,8 @@ class RemovePlayerPacket;
class RemoveEntityPacket; class RemoveEntityPacket;
class MoveEntityPacket; class MoveEntityPacket;
//class TeleportEntityPacket; //class TeleportEntityPacket;
class RemoveItemPacket;
class TakeItemPacket;
class MovePlayerPacket; class MovePlayerPacket;
class PlaceBlockPacket; class PlaceBlockPacket;
class RemoveBlockPacket; class RemoveBlockPacket;
@@ -48,6 +50,7 @@ class ContainerClosePacket;
class ContainerSetSlotPacket; class ContainerSetSlotPacket;
class ContainerSetDataPacket; class ContainerSetDataPacket;
class ContainerSetContentPacket; class ContainerSetContentPacket;
class WantCreatePacket;
class ChatPacket; class ChatPacket;
class SignUpdatePacket; class SignUpdatePacket;
class Minecraft; class Minecraft;
@@ -119,6 +122,9 @@ public:
virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet) {} virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet) {}
virtual void handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet) {} virtual void handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet) {}
virtual void handle(const RakNet::RakNetGUID& source, AnimatePacket* packet) {} virtual void handle(const RakNet::RakNetGUID& source, AnimatePacket* packet) {}
virtual void handle(const RakNet::RakNetGUID& source, RemoveItemPacket* packet) {}
virtual void handle(const RakNet::RakNetGUID& source, TakeItemPacket* packet) {}
virtual void handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet) {}
// //
// Common implementation for Client and Server // Common implementation for Client and Server

View File

@@ -2,6 +2,7 @@
#include "Packet.h" #include "Packet.h"
#include "../world/level/chunk/LevelChunk.h" #include "../world/level/chunk/LevelChunk.h"
#include "network/packet/TakeItemPacket.h"
#include "packet/PacketInclude.h" #include "packet/PacketInclude.h"
Packet::Packet() Packet::Packet()
@@ -41,10 +42,16 @@ Packet* MinecraftPackets::createPacket(int id)
case PACKET_ADDITEMENTITY: case PACKET_ADDITEMENTITY:
packet = new AddItemEntityPacket(); packet = new AddItemEntityPacket();
break; break;
case PACKET_REMOVEITEM:
packet = new RemoveItemPacket();
break;
case PACKET_TAKEITEM:
packet = new TakeItemPacket();
break;
case PACKET_TAKEITEMENTITY: case PACKET_TAKEITEMENTITY:
packet = new TakeItemEntityPacket(); packet = new TakeItemEntityPacket();
break; break;
case PACKET_ADDMOB: case PACKET_ADDMOB:
packet = new AddMobPacket(); packet = new AddMobPacket();
break; break;
case PACKET_ADDPLAYER: case PACKET_ADDPLAYER:
@@ -68,6 +75,9 @@ Packet* MinecraftPackets::createPacket(int id)
case PACKET_RESPAWN: case PACKET_RESPAWN:
packet = new RespawnPacket(); packet = new RespawnPacket();
break; break;
case PACKET_WANTCREATEITEM:
packet = new WantCreatePacket();
break;
case PACKET_REMOVEENTITY: case PACKET_REMOVEENTITY:
packet = new RemoveEntityPacket(); packet = new RemoveEntityPacket();
break; break;

View File

@@ -33,7 +33,10 @@ enum MinecraftPacketIds
PACKET_REMOVEENTITY, PACKET_REMOVEENTITY,
PACKET_ADDITEMENTITY, PACKET_ADDITEMENTITY,
PACKET_TAKEITEMENTITY, PACKET_TAKEITEMENTITY,
PACKET_TAKEITEM,
PACKET_REMOVEITEM,
PACKET_WANTCREATEITEM,
PACKET_MOVEENTITY, PACKET_MOVEENTITY,
PACKET_MOVEENTITY_POS, PACKET_MOVEENTITY_POS,
PACKET_MOVEENTITY_ROT, PACKET_MOVEENTITY_ROT,

View File

@@ -5,6 +5,16 @@
#include "../world/entity/player/Inventory.h" #include "../world/entity/player/Inventory.h"
#include "../world/Container.h" #include "../world/Container.h"
#include "../world/inventory/BaseContainerMenu.h" #include "../world/inventory/BaseContainerMenu.h"
#include "network/packet/ChatPacket.h"
#include "network/packet/ContainerSetSlotPacket.h"
#include "network/packet/LoginStatusPacket.h"
#include "network/packet/MovePlayerPacket.h"
#include "network/packet/RemoveBlockPacket.h"
#include "network/packet/SendInventoryPacket.h"
#include "network/packet/UpdateBlockPacket.h"
#include "network/packet/RemoveItemPacket.h"
#include "network/packet/TakeItemPacket.h"
#include "network/packet/WantCreatePacket.h"
#include "packet/PacketInclude.h" #include "packet/PacketInclude.h"
#include "RakNetInstance.h" #include "RakNetInstance.h"
@@ -13,6 +23,17 @@
#include "../client/gamemode/GameMode.h" #include "../client/gamemode/GameMode.h"
#include "../raknet/RakPeerInterface.h" #include "../raknet/RakPeerInterface.h"
#include "../raknet/PacketPriority.h" #include "../raknet/PacketPriority.h"
#include "platform/log.h"
#include "util/Mth.h"
#include "util/StringUtils.h"
#include "world/item/ItemInstance.h"
#include "world/level/LevelConstants.h"
#include "world/level/storage/LevelStorage.h"
#include "world/phys/Vec3.h"
#include "world/item/crafting/Recipe.h"
#include "world/item/crafting/Recipes.h"
#include <cstddef>
#include <cstdio>
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "../client/sound/SoundEngine.h" #include "../client/sound/SoundEngine.h"
#endif #endif
@@ -53,11 +74,11 @@ void ServerSideNetworkHandler::tileChanged(int x, int y, int z)
Packet* ServerSideNetworkHandler::getAddPacketFromEntity( Entity* entity ) { Packet* ServerSideNetworkHandler::getAddPacketFromEntity( Entity* entity ) {
if (entity->isMob() && !entity->isPlayer()) { //@fix: This code is duplicated. See if it can be unified. if (entity->isMob() && !entity->isPlayer()) { //@fix: This code is duplicated. See if it can be unified.
if (minecraft->player) { // if (minecraft->player) {
// I guess this should always be true, but it crashed somewhere in this // I guess this should always be true, but it crashed somewhere in this
// function once and I only see this one as a potential problem // function once and I only see this one as a potential problem
return new AddMobPacket((Mob*)entity); return new AddMobPacket((Mob*)entity);
} // }
} }
else if (entity->isPlayer()) { else if (entity->isPlayer()) {
@@ -136,7 +157,18 @@ void ServerSideNetworkHandler::displayGameMessage(const std::string& message)
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChatPacket* packet) void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChatPacket* packet)
{ {
displayGameMessage(packet->message); auto player = getPlayer(source);
if (player == nullptr) return; // @todo maybe kick?
if (packet->message[0] == '/') {
// This is a command
ChatPacket resp(minecraft->commandManager().execute(*minecraft, *player, Util::stringTrim(packet->message.substr(1))));
return sendPrivate(resp, source);
}
displayGameMessage("<" + player->name + "> " + packet->message);
} }
void ServerSideNetworkHandler::onNewClient(const RakNet::RakNetGUID& clientGuid) void ServerSideNetworkHandler::onNewClient(const RakNet::RakNetGUID& clientGuid)
@@ -156,6 +188,8 @@ void ServerSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid)
if (player->owner == guid) if (player->owner == guid)
{ {
minecraft->level->getLevelStorage()->savePlayer(*player);
std::string message = player->name; std::string message = player->name;
message += " disconnected from the game"; message += " disconnected from the game";
displayGameMessage(message); displayGameMessage(message);
@@ -179,15 +213,39 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPac
if (!_allowIncoming) return; if (!_allowIncoming) return;
LOGI("LoginPacket\n"); LOGI("LoginPacket\n");
int loginStatus = LoginStatus::Success; int loginStatus = LoginStatus::Success;
// //
// Bad/incompatible client version // Bad/incompatible client version
// //
bool oldClient = packet->clientNetworkVersion < SharedConstants::NetworkProtocolLowestSupportedVersion; bool oldClient = packet->clientNetworkVersion < SharedConstants::NetworkProtocolLowestSupportedVersion;
bool oldServer = packet->clientNetworkLowestSupportedVersion > SharedConstants::NetworkProtocolVersion; bool oldServer = packet->clientNetworkLowestSupportedVersion > SharedConstants::NetworkProtocolVersion;
if (oldClient || oldServer) if (oldClient || oldServer || !packet->newProto)
loginStatus = oldClient? LoginStatus::Failed_ClientOld : LoginStatus::Failed_ServerOld; loginStatus = oldClient || !packet->newProto? LoginStatus::Failed_ClientOld : LoginStatus::Failed_ServerOld;
std::string nicknameLower = packet->clientName.C_String();
std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower);
printf("%s lower \n", nicknameLower.c_str());
for (int i = 0; i < level->players.size(); i++) {
ServerPlayer* player = (ServerPlayer*) level->players.at(i);
std::string clientLower = player->name;
std::transform(clientLower.begin(), clientLower.end(), clientLower.begin(), ::tolower);
// @todo to lower case
if (nicknameLower == clientLower) {
loginStatus = packet->newProto ? LoginStatus::Failed_TakenNickname : LoginStatus::Failed_ClientOld;
break;
}
}
for (auto& banned : level->bannedPpl) {
if (nicknameLower == banned) {
loginStatus = packet->newProto ? LoginStatus::Failed_Banned : LoginStatus::Failed_ClientOld;
break;
}
}
RakNet::BitStream bitStream; RakNet::BitStream bitStream;
LoginStatusPacket(loginStatus).write(&bitStream); LoginStatusPacket(loginStatus).write(&bitStream);
@@ -199,13 +257,16 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPac
// //
// Valid client version // Valid client version
// //
Player* newPlayer = new ServerPlayer(minecraft, level);
Player* newPlayer = new ServerPlayer(minecraft, level, packet->newProto);
minecraft->gameMode->initAbilities(newPlayer->abilities); minecraft->gameMode->initAbilities(newPlayer->abilities);
newPlayer->owner = source; newPlayer->owner = source;
newPlayer->name = packet->clientName.C_String(); newPlayer->name = packet->clientName.C_String();
_pendingPlayers.push_back(newPlayer); _pendingPlayers.push_back(newPlayer);
LOGI("Adding new player... isCreative: %i\n", minecraft->isCreativeMode());
// Reset the player so he doesn't spawn inside blocks // Reset the player so he doesn't spawn inside blocks
while (newPlayer->y > 0) { while (newPlayer->y > 0) {
newPlayer->setPos(newPlayer->x, newPlayer->y, newPlayer->z); newPlayer->setPos(newPlayer->x, newPlayer->y, newPlayer->z);
@@ -228,7 +289,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPac
level->getLevelData()->getGeneratorVersion(), level->getLevelData()->getGeneratorVersion(),
gameType, gameType,
newPlayer->entityId, newPlayer->entityId,
newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z,
LevelConstants::CHUNK_CACHE_WIDTH
).write(&bitStream); ).write(&bitStream);
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false);
@@ -244,6 +306,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ReadyPac
if (packet->type == ReadyPacket::READY_REQUESTEDCHUNKS) if (packet->type == ReadyPacket::READY_REQUESTEDCHUNKS)
onReady_RequestedChunks(source); onReady_RequestedChunks(source);
LOGI("Ready player two ready ready player two!!\n ");
} }
void ServerSideNetworkHandler::onReady_ClientGeneration(const RakNet::RakNetGUID& source) void ServerSideNetworkHandler::onReady_ClientGeneration(const RakNet::RakNetGUID& source)
@@ -301,6 +365,36 @@ void ServerSideNetworkHandler::onReady_ClientGeneration(const RakNet::RakNetGUID
} }
} }
if (!minecraft->level->getLevelStorage()->loadPlayer(*newPlayer)) {
LOGW("Failed to load %s data\n", newPlayer->name.c_str());
}
// Credits to EpikIzCool
bitStream.Reset();
MovePlayerPacket mv(newPlayer->entityId, newPlayer->x, newPlayer->y - newPlayer->heightOffset,
newPlayer->z, newPlayer->xRot, newPlayer->yRot);
mv.write(&bitStream);
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false);
bitStream.Reset();
SetHealthPacket hp(newPlayer->health);
hp.write(&bitStream);
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false);
if (newPlayer->hasRespawnPosition()) {
bitStream.Reset();
SetSpawnPositionPacket sp(newPlayer->getRespawnPosition());
sp.write(&bitStream);
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false);
}
bitStream.Reset();
SendInventoryPacket(newPlayer, false).write(&bitStream);
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false);
// Additional packets // Additional packets
// * set spawn // * set spawn
/* /*
@@ -338,15 +432,32 @@ void ServerSideNetworkHandler::onReady_RequestedChunks(const RakNet::RakNetGUID&
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlayerPacket* packet) void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlayerPacket* packet)
{ {
if (!level) return; if (!level) return;
//LOGI("MovePlayerPacket\n"); //LOGI("MovePlayerPacket\n");
if (Entity* entity = level->getEntity(packet->entityId)) if (Entity* entity = level->getEntity(packet->entityId)) {
{ ServerPlayer* player = (ServerPlayer*) getPlayer(source);
entity->xd = entity->yd = entity->zd = 0;
entity->lerpTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot, 3);
int timeElapsed = minecraft->getTicks() - player->getLastMoveTicks();
if (timeElapsed > 0) {
float dist = player->distanceTo(packet->x, player->y, packet->z);
float speed = dist / (minecraft->getTicks() - player->getLastMoveTicks());
player->setLastMoveTicks(minecraft->getTicks());
float maxSpeed = (minecraft->isCreativeMode()) ? 1.65f : 1.f;
if (speed > maxSpeed) {
MovePlayerPacket refuse(player->entityId, player->x, player->y, player->z, player->xRot, player->yRot);
return raknetInstance->send(refuse);
}
}
entity->xd = entity->yd = entity->zd = 0;
entity->lerpTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot, 3);
// broadcast this packet to other clients // broadcast this packet to other clients
redistributePacket(packet, source); redistributePacket(packet, source);
} }
} }
@@ -368,12 +479,29 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveBl
if (oldTile != NULL && changed) { if (oldTile != NULL && changed) {
level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, oldTile->soundType->getBreakSound(), (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f); level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, oldTile->soundType->getBreakSound(), (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f);
if (minecraft->gameMode->isSurvivalType() && player->canDestroy(oldTile)) if (minecraft->gameMode->isSurvivalType() && player->canDestroy(oldTile)) {
//oldTile->spawnResources(level, x, y, z, data, 1); //@todo // From SurvivalMode.cpp
// Why tf i have to copy this shit from SurvivalMode class
// Why SurvivalMode class locked to LOCAL MINECRAFT PLAYER :sob: :sob: :sob: :sob: :sob: :sob: :sob: :sob:
// @fix @warn @ahtung @alert
ItemInstance* item = player->inventory->getSelected();
if (item != NULL) {
item->mineBlock(oldTile->id, x, y, z);
if (item->count == 0) {
//item->snap(minecraft->player);
player->inventory->clearSlot(player->inventory->selected);
}
}
// oldTile->spawnResources(level, x, y, z, data, 1); //@todo
oldTile->playerDestroy(level, player, x, y, z, data); oldTile->playerDestroy(level, player, x, y, z, data);
}
oldTile->destroy(level, x, y, z, data); oldTile->destroy(level, x, y, z, data);
} }
LOGI("Remove block [%i, %i, %i]\n", packet->x, packet->y, packet->z);
} }
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RequestChunkPacket* packet) void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RequestChunkPacket* packet)
@@ -403,6 +531,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RequestC
raknetInstance->send(source, p); raknetInstance->send(source, p);
} }
} }
// LOGI("Requested chunk [%i, %i]\n", packet->x, packet->z);
} }
void ServerSideNetworkHandler::levelGenerated( Level* level ) void ServerSideNetworkHandler::levelGenerated( Level* level )
@@ -429,23 +559,31 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerEq
if (!player) return; if (!player) return;
if (rakPeer->GetMyGUID() == player->owner) return; if (rakPeer->GetMyGUID() == player->owner) return;
LOGI("Equip item: id %i aux %i\n", packet->itemId, packet->itemAuxValue);
// override the player's inventory // override the player's inventory
//int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue); int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue);
int slot = Inventory::MAX_SELECTION_SIZE;
if (slot >= 0) { if (slot >= 0 && slot != packet->inventorySlot && packet->itemId != 0) {
if (packet->itemId == 0) { LOGW("PlayerEquipmentPacket: Item in player inventory but slots doesn't match!");
player->inventory->clearSlot(slot); packet->inventorySlot = slot;
} else {
// @note: 128 is an ugly hack for depletable items.
// @todo: fix
ItemInstance newItem(packet->itemId, 128, packet->itemAuxValue);
player->inventory->replaceSlot(slot, &newItem);
}
player->inventory->moveToSelectedSlot(slot, true);
redistributePacket(packet, source);
} else {
LOGW("Warning: Remote player doesn't have his thing, Odd!\n");
} }
if (slot < 0 && packet->itemId != 0) {
LOGW("PlayerEquipmentPacket: Remote player doesn't have his thing (or crafted it)!\n");
SendInventoryPacket newInventory (player, false);
raknetInstance->send(newInventory);
return;
}
player->inventory->selectSlot(packet->selectedSlot);
player->inventory->linkSlot(packet->selectedSlot, packet->inventorySlot, true);
player->inventory->print();
redistributePacket(packet, source);
} }
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerArmorEquipmentPacket* packet) { void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerArmorEquipmentPacket* packet) {
@@ -455,6 +593,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerAr
if (!player) return; if (!player) return;
if (rakPeer->GetMyGUID() == player->owner) return; if (rakPeer->GetMyGUID() == player->owner) return;
// LOGI("Equip armor: %i %i %i %i\n", packet->head, packet->torso, packet->legs, packet->feet);
packet->fillIn(player); packet->fillIn(player);
redistributePacket(packet, source); redistributePacket(packet, source);
} }
@@ -466,6 +606,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Interact
Entity* entity = level->getEntity(packet->targetId); Entity* entity = level->getEntity(packet->targetId);
if (src && entity && src->isPlayer()) if (src && entity && src->isPlayer())
{ {
LOGI("Interact: source %i target %i\n", packet->sourceId, packet->targetId);
Player* player = (Player*) src; Player* player = (Player*) src;
if (InteractPacket::Attack == packet->action) { if (InteractPacket::Attack == packet->action) {
player->swing(); player->swing();
@@ -506,12 +648,73 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimateP
} }
redistributePacket(packet, source); redistributePacket(packet, source);
} }
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet) {
LOGI("WantCreatePacket\n");
Entity* entity = level->getEntity(packet->playerId);
if (entity && entity->isPlayer()) {
Player* p = (Player*)entity;
auto playerInv = p->inventory;
ItemInstance wantCreate;
wantCreate.id = packet->itemId;
wantCreate.count = packet->count;
wantCreate.setAuxValue(packet->auxValue);
Recipe* recipe = Recipes::getInstance()->getRecipeFor(wantCreate);
std::vector<ItemInstance> items = recipe->getItemPack().getItemInstances();
std::vector<int> checkForExists = {};
for (int i = Inventory::MAX_SELECTION_SIZE; i < p->inventory->getContainerSize(); ++i) {
auto itm = p->inventory->getItem(i);
if (itm != NULL) {
for (int y = 0; y < items.size(); y++) {
auto itmRecipe = items.at(y);
if (itmRecipe.id == itm->id && itm->count >= itmRecipe.count) {
checkForExists.push_back(itm->id);
}
}
}
}
if (checkForExists.empty()) {
return;
}
for (int i = 0; i < items.size(); i++) {
auto item = items.at(i);
auto it = std::find(checkForExists.begin(), checkForExists.end(), item.id);
if (it == checkForExists.end() && checkForExists.size() > 1) {
return;
}
}
// for (int i = 0; i < items.size(); i++) {
// RemoveItemPacket removePacket(packet->playerId, items.at(i).count, items.at(i).getAuxValue(), items.at(i).id);
// raknetInstance->send(source, removePacket);
// p->inventory->removeResource(ItemInstance(items.at(i).id, items.at(i).count, items.at(i).getAuxValue()));
// }
// TakeItemPacket itemAdd(p->entityId, wantCreate.count, wantCreate.getAuxValue(), wantCreate.id);
// raknetInstance->send(source, itemAdd);
p->inventory->add(new ItemInstance(wantCreate.id, wantCreate.count, wantCreate.getAuxValue()));
}
}
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet)
{ {
if (!level) return; if (!level) return;
LOGI("UseItemPacket\n"); LOGI("UseItemPacket: id %i data %i\n", packet->itemId, packet->itemData);
Entity* entity = level->getEntity(packet->entityId); Entity* entity = level->getEntity(packet->entityId);
if (entity && entity->isPlayer()) { if (entity && entity->isPlayer()) {
Player* player = (Player*) entity; Player* player = (Player*) entity;
@@ -522,7 +725,30 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemP
if (t && t->use(level, x, y, z, player)) return; if (t && t->use(level, x, y, z, player)) return;
if (packet->item.isNull()) return; if (packet->item.isNull()) return;
ItemInstance* item = &packet->item; ItemInstance* packetItem = &packet->item;
int slot = player->inventory->getSlot(packet->itemId, packet->itemData);
if (slot < 0) {
LOGW("UseItemPacket: Player doesn't have this item!\n");
auto pos = Vec3(packet->x, packet->y, packet->z);
if (ItemInstance::isBlock(packetItem)) {
LOGI("UseItemPacket: This is even block!!!\n");
pos.x += packet->clickX;
pos.y += packet->clickY;
pos.z += packet->clickZ;
}
UpdateBlockPacket refuse(pos.x, pos.y, pos.z, level->getTile(pos.x, pos.y, pos.z), level->getData(pos.x, pos.y, pos.z));
raknetInstance->send(refuse);
return;
}
ItemInstance* item = player->inventory->getItem(slot);
if(packet->face == 255) { if(packet->face == 255) {
// Special case: x,y,z means direction-of-action // Special case: x,y,z means direction-of-action
@@ -533,6 +759,10 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemP
minecraft->gameMode->useItemOn(player, level, item, packet->x, packet->y, packet->z, packet->face, minecraft->gameMode->useItemOn(player, level, item, packet->x, packet->y, packet->z, packet->face,
Vec3(packet->clickX + packet->x, packet->clickY + packet->y, packet->clickZ + packet->z)); Vec3(packet->clickX + packet->x, packet->clickY + packet->y, packet->clickZ + packet->z));
} }
if (item && item->count <= 0) {
player->inventory->clearSlot(slot);
}
//LOGW("Use Item not working! Out of synch?\n"); //LOGW("Use Item not working! Out of synch?\n");
@@ -544,6 +774,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemP
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, EntityEventPacket* packet) { void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, EntityEventPacket* packet) {
if (!level) return; if (!level) return;
LOGI("EntityEventPacket: id %i\n", packet->eventId);
if (Entity* e = level->getEntity(packet->entityId)) if (Entity* e = level->getEntity(packet->entityId))
e->handleEntityEvent(packet->eventId); e->handleEntityEvent(packet->eventId);
} }
@@ -577,6 +809,11 @@ void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SendInv
{ {
if (!level) return; if (!level) return;
LOGI("SendInventoryPacket:\n");
for (int i = 0; i < packet->numItems; i++) {
LOGI("\t %i: %s (%i)\n", i, packet->items.at(i).getName().c_str(), packet->items.at(i).count);
}
Entity* entity = level->getEntity(packet->entityId); Entity* entity = level->getEntity(packet->entityId);
if (entity && entity->isPlayer()) { if (entity && entity->isPlayer()) {
Player* p = (Player*)entity; Player* p = (Player*)entity;
@@ -592,15 +829,27 @@ void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, DropIte
{ {
if (!level) return; if (!level) return;
LOGI("DropItemPacket\n");
Entity* entity = level->getEntity(packet->entityId); Entity* entity = level->getEntity(packet->entityId);
if (entity && entity->isPlayer()) { if (entity && entity->isPlayer()) {
Player* p = (Player*)entity; Player* p = (Player*)entity;
p->drop(new ItemInstance(packet->item), packet->dropType != 0); // p->drop(new ItemInstance(packet->item), packet->dropType != 0);
int slot = p->inventory->getSlot(packet->item.id, packet->item.getAuxValue());
if (slot < 0) {
LOGW("DropItemPacket: player doesn't have these items!\n");
return;
}
p->inventory->dropSlot(slot, false, packet->dropType != 0);
} }
} }
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet) { void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet) {
if (!level) return; if (!level) return;
LOGI("ContainerClosePacket\n");
Player* p = findPlayer(level, &source); Player* p = findPlayer(level, &source);
if (!p) return; if (!p) return;
@@ -612,6 +861,16 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetSlotPacket* packet) { void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetSlotPacket* packet) {
if (!level) return; if (!level) return;
const char* type = "unknown";
switch (packet->setType) {
case ContainerSetSlotPacket::SETTYPE_ADD: type = "add"; break;
case ContainerSetSlotPacket::SETTYPE_SET: type = "set"; break;
case ContainerSetSlotPacket::SETTYPE_TAKE: type = "take"; break;
};
LOGI("ContainerSetSlot: slot %i item %s type %s\n", packet->slot, packet->item.getName().c_str(), type);
Player* p = findPlayer(level, &source); Player* p = findPlayer(level, &source);
if (!p) return; if (!p) return;
@@ -619,11 +878,79 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe
LOGW("User has no container!\n"); LOGW("User has no container!\n");
return; return;
} }
if (p->containerMenu->containerId != packet->containerId)
{ if (p->containerMenu->containerId != packet->containerId) {
LOGW("Wrong container id: %d vs %d\n", p->containerMenu->containerId, packet->containerId); LOGW("Wrong container id: %d vs %d\n", p->containerMenu->containerId, packet->containerId);
return; return;
} }
if (packet->item.count > 64) {
LOGW("ContainerSetSlotPacket: player tried to put more than 64");
return;
}
auto contItems = p->containerMenu->getItems();
// find same item in player inventory (used not in all cases)
int invSlot = p->inventory->getSlot(packet->item.id, packet->item.getAuxValue());
auto invItem = p->inventory->getItem(invSlot);
if (contItems.at(packet->slot).id == 0 && packet->item.id != 0) {
LOGI("ContainerSetSlotPacket: player tried to put items to slot %i\n", packet->slot);
if (invSlot < 0) {
LOGW("ContainerSetSlotPacket: player doesn't have this item\n");
return;
}
if (invItem->count < packet->item.count) {
LOGW("ContainerSetSlotPacket: player tried to put more than he have\n");
packet->item.count = invItem->count;
}
invItem->count -= packet->item.count;
if (invItem->count <= 0) {
p->inventory->removeItem(invItem);
}
} else if(contItems.at(packet->slot).id == packet->item.id) {
int deltaItem = packet->item.count - contItems.at(packet->slot).count;
if (deltaItem > 0) {
LOGI("ContainerSetSlotPacket: player tried to add %i items to slot %i\n", deltaItem, packet->slot);
auto invItem = p->inventory->getItem(invSlot);
if (invSlot < 0) {
LOGW("ContainerSetSlotPacket: player doesn't have this item\n");
return;
}
if (invItem->count < deltaItem) {
LOGW("ContainerSetSlotPacket: player tried to put more than he have");
packet->item.count -= (deltaItem - invItem->count);
deltaItem = invItem->count;
}
invItem->count -= deltaItem;
if (invItem->count <= 0) {
p->inventory->removeItem(invItem);
}
} else if (deltaItem < 0) {
LOGW("ContainerSetSlotPacket: player tried to take %i items from slot %i\n", -deltaItem, packet->slot);
p->inventory->add(new ItemInstance(packet->item.getItem(), -deltaItem, contItems.at(packet->slot).getAuxValue()));
}
} else if(contItems.at(packet->slot).id && !packet->item.id) {
LOGI("ContainerSetSlotPacket: player tried to take all items from slot %i\n", packet->slot);
packet->item.count = 0;
packet->item.setAuxValue(0);
p->inventory->add(new ItemInstance(contItems.at(packet->slot).getItem(), contItems.at(packet->slot).count, contItems.at(packet->slot).getAuxValue()));
} else {
LOGW("ContainerSetSlotPacket: illegal container operation in slot %i\n", packet->slot);
return;
}
if (ContainerType::FURNACE == p->containerMenu->containerType) { if (ContainerType::FURNACE == p->containerMenu->containerType) {
//LOGI("Server:Setting slot %d: %s\n", packet->slot, packet->item.toString().c_str()); //LOGI("Server:Setting slot %d: %s\n", packet->slot, packet->item.toString().c_str());
@@ -635,6 +962,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe
p->containerMenu->setSlot(packet->slot, &packet->item); p->containerMenu->setSlot(packet->slot, &packet->item);
//p->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); //p->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item);
} }
p->inventory->print();
} }
void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SetHealthPacket* packet ) void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SetHealthPacket* packet )
@@ -657,6 +986,8 @@ void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SignUpd
if (!level) if (!level)
return; return;
LOGI("SignUpdate: [%i, %i, %i]\n", packet->x, packet->y, packet->z);
TileEntity* te = level->getTileEntity(packet->x, packet->y, packet->z); TileEntity* te = level->getTileEntity(packet->x, packet->y, packet->z);
if (TileEntity::isType(te, TileEntityType::Sign)) { if (TileEntity::isType(te, TileEntityType::Sign)) {
SignTileEntity* ste = (SignTileEntity*) te; SignTileEntity* ste = (SignTileEntity*) te;
@@ -713,3 +1044,9 @@ Player* ServerSideNetworkHandler::getPlayer( const RakNet::RakNetGUID& source )
if (source == level->players[i]->owner) return level->players[i]; if (source == level->players[i]->owner) return level->players[i];
return NULL; return NULL;
} }
void ServerSideNetworkHandler::sendPrivate(Packet& packet, const RakNet::RakNetGUID& source) {
RakNet::BitStream bitStream;
packet.write(&bitStream);
rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false);
}

View File

@@ -58,7 +58,8 @@ public:
virtual void handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet); virtual void handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet); virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, ChatPacket* packet); virtual void handle(const RakNet::RakNetGUID& source, ChatPacket* packet);
virtual void handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet);
bool allowsIncomingConnections() { return _allowIncoming; } bool allowsIncomingConnections() { return _allowIncoming; }
void allowIncomingConnections(bool doAllow); void allowIncomingConnections(bool doAllow);
@@ -70,6 +71,12 @@ private:
* @brief Send packet to all players * @brief Send packet to all players
*/ */
void redistributePacket(Packet* packet, const RakNet::RakNetGUID& fromPlayer); void redistributePacket(Packet* packet, const RakNet::RakNetGUID& fromPlayer);
/**
* @brief Send packer private with GUID
*/
void sendPrivate(Packet& packet, const RakNet::RakNetGUID& source);
Player* getPlayer(const RakNet::RakNetGUID& source); Player* getPlayer(const RakNet::RakNetGUID& source);
Minecraft* minecraft; Minecraft* minecraft;

View File

@@ -236,9 +236,9 @@ std::string CommandServer::parse(ConnectedClient& client, const std::string& s)
if (x0 < 0) x0 = 0; if (x0 < 0) x0 = 0;
if (y0 < 0) y0 = 0; if (y0 < 0) y0 = 0;
if (z0 < 0) z0 = 0; if (z0 < 0) z0 = 0;
if (x1 >= LEVEL_WIDTH ) x1 = LEVEL_WIDTH - 1; if (x1 >= LevelConstants::LEVEL_WIDTH ) x1 = LevelConstants::LEVEL_WIDTH - 1;
if (y1 >= LEVEL_HEIGHT) y1 = LEVEL_HEIGHT - 1; if (y1 >= LevelConstants::LEVEL_HEIGHT) y1 = LevelConstants::LEVEL_HEIGHT - 1;
if (z1 >= LEVEL_DEPTH ) z1 = LEVEL_DEPTH - 1; if (z1 >= LevelConstants::LEVEL_DEPTH ) z1 = LevelConstants::LEVEL_DEPTH - 1;
for (int y = y0; y <= y1; ++y) for (int y = y0; y <= y1; ++y)
for (int z = z0; z <= z1; ++z) for (int z = z0; z <= z1; ++z)
@@ -456,7 +456,7 @@ std::string CommandServer::parse(ConnectedClient& client, const std::string& s)
sw.start(); sw.start();
// Save a cuboid around the player // Save a cuboid around the player
const int CSize = CHUNK_CACHE_WIDTH; const int CSize = LevelConstants::CHUNK_CACHE_WIDTH;
int cx = (int)e->x / CSize; int cx = (int)e->x / CSize;
int cz = (int)e->z / CSize; int cz = (int)e->z / CSize;
@@ -504,7 +504,7 @@ bool CommandServer::handleCheckpoint(bool doRestore ) {
const int cz = restorePos.z; const int cz = restorePos.z;
const int y0 = restorePos.y; const int y0 = restorePos.y;
const int y1 = y0 + RestoreHeight; const int y1 = y0 + RestoreHeight;
const int CSize = CHUNK_CACHE_WIDTH; const int CSize = LevelConstants::CHUNK_CACHE_WIDTH;
const int numChunkBytes = RestoreHeight * CSize * CSize * 20 / 8; const int numChunkBytes = RestoreHeight * CSize * CSize * 20 / 8;
if (!restoreBuffer) { if (!restoreBuffer) {

View File

@@ -33,18 +33,18 @@ public:
unsigned char* blockIds = chunk->getBlockData(); unsigned char* blockIds = chunk->getBlockData();
DataLayer& blockData = chunk->data; DataLayer& blockData = chunk->data;
const int setSize = LEVEL_HEIGHT / 8; const int setSize = LevelConstants::LEVEL_HEIGHT / 8;
const int setShift = 4; // power of LEVEL_HEIGHT / 8 const int setShift = 4; // power of LevelConstants::LEVEL_HEIGHT / 8
chunkData.Reset(); chunkData.Reset();
for (int i = 0; i < CHUNK_COLUMNS; i++) for (int i = 0; i < LevelConstants::CHUNK_COLUMNS; i++)
{ {
unsigned char updateBits = chunk->updateMap[i]; unsigned char updateBits = chunk->updateMap[i];
chunkData.Write(updateBits); chunkData.Write(updateBits);
if (updateBits > 0) if (updateBits > 0)
{ {
int colDataPosition = (i % CHUNK_WIDTH) << 11 | (i / CHUNK_WIDTH) << 7; int colDataPosition = (i % LevelConstants::CHUNK_WIDTH) << 11 | (i / LevelConstants::CHUNK_WIDTH) << 7;
for (int set = 0; set < 8; set++) for (int set = 0; set < 8; set++)
{ {

View File

@@ -9,17 +9,20 @@ public:
RakNet::RakString clientName; RakNet::RakString clientName;
int clientNetworkVersion; int clientNetworkVersion;
int clientNetworkLowestSupportedVersion; int clientNetworkLowestSupportedVersion;
bool newProto;
LoginPacket() LoginPacket()
: clientNetworkVersion(-1), : clientNetworkVersion(-1),
clientNetworkLowestSupportedVersion(-1) clientNetworkLowestSupportedVersion(-1),
newProto(false)
{ {
} }
LoginPacket(const RakNet::RakString& clientName, int clientVersion) LoginPacket(const RakNet::RakString& clientName, int clientVersion, bool newProto)
: clientName(clientName), : clientName(clientName),
clientNetworkVersion(clientVersion), clientNetworkVersion(clientVersion),
clientNetworkLowestSupportedVersion(clientVersion) clientNetworkLowestSupportedVersion(clientVersion),
newProto(newProto)
{ {
} }
@@ -29,6 +32,7 @@ public:
bitStream->Write(clientName); bitStream->Write(clientName);
bitStream->Write(clientNetworkVersion); bitStream->Write(clientNetworkVersion);
bitStream->Write(clientNetworkLowestSupportedVersion); bitStream->Write(clientNetworkLowestSupportedVersion);
bitStream->Write(newProto);
} }
void read(RakNet::BitStream* bitStream) void read(RakNet::BitStream* bitStream)
@@ -39,6 +43,11 @@ public:
if (bitStream->GetNumberOfUnreadBits() > 0) { if (bitStream->GetNumberOfUnreadBits() > 0) {
bitStream->Read(clientNetworkVersion); bitStream->Read(clientNetworkVersion);
bitStream->Read(clientNetworkLowestSupportedVersion); bitStream->Read(clientNetworkLowestSupportedVersion);
// Checking for new proto
if (bitStream->GetNumberOfUnreadBits() > 0) {
bitStream->Read(newProto);
}
} }
} }

View File

@@ -3,10 +3,13 @@
#include "../Packet.h" #include "../Packet.h"
// wtf why not enum
namespace LoginStatus { namespace LoginStatus {
const int Success = 0; const int Success = 0;
const int Failed_ClientOld = 1; const int Failed_ClientOld = 1;
const int Failed_ServerOld = 2; const int Failed_ServerOld = 2;
const int Failed_TakenNickname = 3;
const int Failed_Banned = 4;
} }
class LoginStatusPacket : public Packet { class LoginStatusPacket : public Packet {

View File

@@ -50,5 +50,7 @@
#include "TileEventPacket.h" #include "TileEventPacket.h"
#include "UpdateBlockPacket.h" #include "UpdateBlockPacket.h"
#include "UseItemPacket.h" #include "UseItemPacket.h"
#include "RemoveItemPacket.h"
#include "WantCreatePacket.h"
#include "TakeItemPacket.h"
#endif /*NET_MINECRAFT_NETWORK_PACKET__PacketInclude_H__*/ #endif /*NET_MINECRAFT_NETWORK_PACKET__PacketInclude_H__*/

View File

@@ -9,15 +9,19 @@ public:
int entityId; int entityId;
unsigned short itemId; unsigned short itemId;
unsigned short itemAuxValue; unsigned short itemAuxValue;
unsigned char selectedSlot;
unsigned char inventorySlot;
PlayerEquipmentPacket() PlayerEquipmentPacket()
{ {
} }
PlayerEquipmentPacket(int entityId, int itemId, int data) PlayerEquipmentPacket(int entityId, int itemId, int data, int selSlot, int invSlot)
: entityId(entityId), : entityId(entityId),
itemId(itemId), itemId(itemId),
itemAuxValue(data) itemAuxValue(data),
selectedSlot(selSlot),
inventorySlot(invSlot)
{ {
} }
@@ -28,6 +32,8 @@ public:
bitStream->Write(entityId); bitStream->Write(entityId);
bitStream->Write(itemId); bitStream->Write(itemId);
bitStream->Write(itemAuxValue); bitStream->Write(itemAuxValue);
bitStream->Write(selectedSlot);
bitStream->Write(inventorySlot);
} }
void read(RakNet::BitStream* bitStream) void read(RakNet::BitStream* bitStream)
@@ -35,6 +41,8 @@ public:
bitStream->Read(entityId); bitStream->Read(entityId);
bitStream->Read(itemId); bitStream->Read(itemId);
bitStream->Read(itemAuxValue); bitStream->Read(itemAuxValue);
bitStream->Read(selectedSlot);
bitStream->Read(inventorySlot);
} }
void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback)

View File

@@ -0,0 +1,54 @@
#ifndef NET_MINECRAFT_NETWORK_PACKET__RemoveItemPacket_H__
#define NET_MINECRAFT_NETWORK_PACKET__RemoveItemPacket_H__
//package net.minecraft.network.packet;
#include "../Packet.h"
class RemoveItemPacket: public Packet
{
public:
RemoveItemPacket() {
}
RemoveItemPacket(int playerId, int count, int auxValue, int itemId)
:
playerId(playerId),
count(count),
auxValue(auxValue),
itemId(itemId)
{
}
void write(RakNet::BitStream* bitStream)
{
bitStream->Write((RakNet::MessageID)(ID_USER_PACKET_ENUM + PACKET_REMOVEITEM));
bitStream->Write(itemId);
bitStream->Write(count);
bitStream->Write(auxValue);
bitStream->Write(playerId);
}
void read(RakNet::BitStream* bitStream)
{
bitStream->Read(itemId);
bitStream->Read(count);
bitStream->Read(auxValue);
bitStream->Read(playerId);
}
void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback)
{
callback->handle(source, (RemoveItemPacket*)this);
}
int playerId;
int itemId;
int count;
int auxValue;
};
#endif /*NET_MINECRAFT_NETWORK_PACKET__RemoveItemPacket_H__*/

View File

@@ -2,13 +2,14 @@
#define NET_MINECRAFT_NETWORK_PACKET__SendInventoryPacket_H__ #define NET_MINECRAFT_NETWORK_PACKET__SendInventoryPacket_H__
#include "../Packet.h" #include "../Packet.h"
#include "world/entity/player/Inventory.h"
#include "world/inventory/FillingContainer.h"
#include <array>
class SendInventoryPacket: public Packet class SendInventoryPacket: public Packet
{ {
public: public:
SendInventoryPacket() SendInventoryPacket() {}
{
}
SendInventoryPacket(Player* player, bool dropItems) SendInventoryPacket(Player* player, bool dropItems)
: entityId(player->entityId), : entityId(player->entityId),
@@ -21,10 +22,15 @@ public:
ItemInstance* item = inv->getItem(i); ItemInstance* item = inv->getItem(i);
items.push_back(item? *item : ItemInstance()); items.push_back(item? *item : ItemInstance());
} }
for (int i = 0; i < NumArmorItems; ++i) { for (int i = 0; i < NumArmorItems; ++i) {
ItemInstance* item = player->getArmor(i); ItemInstance* item = player->getArmor(i);
items.push_back(item? *item : ItemInstance()); items.push_back(item? *item : ItemInstance());
} }
for (int i = 0; i < inv->numLinkedSlots; ++i) {
linkedSlot[i] = inv->linkedSlots[i];
}
} }
void write(RakNet::BitStream* bitStream) void write(RakNet::BitStream* bitStream)
@@ -39,6 +45,13 @@ public:
// Armor // Armor
for (int i = 0; i < NumArmorItems; ++i) for (int i = 0; i < NumArmorItems; ++i)
PacketUtil::writeItemInstance(items[i + numItems], bitStream); PacketUtil::writeItemInstance(items[i + numItems], bitStream);
int lSlots = Inventory::MAX_SELECTION_SIZE;
// Linked slots
bitStream->Write(lSlots);
for (int i = 0; i < lSlots; ++i)
bitStream->Write(linkedSlot[i]);
} }
void read(RakNet::BitStream* bitStream) void read(RakNet::BitStream* bitStream)
@@ -50,6 +63,12 @@ public:
// Inventory, Armor // Inventory, Armor
for (int i = 0; i < numItems + NumArmorItems; ++i) for (int i = 0; i < numItems + NumArmorItems; ++i)
items.push_back(PacketUtil::readItemInstance(bitStream)); items.push_back(PacketUtil::readItemInstance(bitStream));
// Linked slots
int lSlots = 0;
bitStream->Read(lSlots);
for (int i = 0; i < lSlots; ++i)
bitStream->Read(linkedSlot[i]);
} }
void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback)
@@ -62,6 +81,8 @@ public:
short numItems; short numItems;
unsigned char extra; unsigned char extra;
std::array<FillingContainer::LinkedSlot, Inventory::MAX_SELECTION_SIZE> linkedSlot;
static const int ExtraDrop = 1; static const int ExtraDrop = 1;
static const int NumArmorItems = 4; static const int NumArmorItems = 4;
}; };

View File

@@ -2,6 +2,7 @@
#define NET_MINECRAFT_NETWORK_PACKET__StartGamePacket_H__ #define NET_MINECRAFT_NETWORK_PACKET__StartGamePacket_H__
#include "../Packet.h" #include "../Packet.h"
#include "world/level/LevelConstants.h"
#include <cstdint> #include <cstdint>
class StartGamePacket : public Packet class StartGamePacket : public Packet
@@ -14,18 +15,20 @@ public:
int entityId; int entityId;
float x, y, z; float x, y, z;
int chunkCacheWidth = 0;
StartGamePacket() StartGamePacket()
{ {
} }
StartGamePacket(long seed, int levelGeneratorVersion, int gameType, int entityId, float x, float y, float z) StartGamePacket(long seed, int levelGeneratorVersion, int gameType, int entityId, float x, float y, float z, int chunkCacheWidth)
: levelSeed((int32_t)seed), : levelSeed((int32_t)seed),
levelGeneratorVersion(levelGeneratorVersion), levelGeneratorVersion(levelGeneratorVersion),
gameType(gameType), gameType(gameType),
entityId(entityId), entityId(entityId),
x(x), x(x),
y(y), y(y),
z(z) z(z),
chunkCacheWidth(chunkCacheWidth)
{ {
} }
@@ -40,6 +43,7 @@ public:
bitStream->Write(x); bitStream->Write(x);
bitStream->Write(y); bitStream->Write(y);
bitStream->Write(z); bitStream->Write(z);
bitStream->Write(LevelConstants::CHUNK_CACHE_WIDTH);
} }
void read(RakNet::BitStream* bitStream) void read(RakNet::BitStream* bitStream)
@@ -51,6 +55,10 @@ public:
bitStream->Read(x); bitStream->Read(x);
bitStream->Read(y); bitStream->Read(y);
bitStream->Read(z); bitStream->Read(z);
if (bitStream->GetNumberOfUnreadBits() > 0) {
bitStream->Read(chunkCacheWidth);
}
} }
void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback)

View File

@@ -0,0 +1,54 @@
#ifndef NET_MINECRAFT_NETWORK_PACKET__TakeItemPacket_H__
#define NET_MINECRAFT_NETWORK_PACKET__TakeItemPacket_H__
//package net.minecraft.network.packet;
#include "../Packet.h"
class TakeItemPacket: public Packet
{
public:
TakeItemPacket() {
}
TakeItemPacket(int playerId, int count, int auxValue, int itemId)
:
playerId(playerId),
count(count),
auxValue(auxValue),
itemId(itemId)
{
}
void write(RakNet::BitStream* bitStream)
{
bitStream->Write((RakNet::MessageID)(ID_USER_PACKET_ENUM + PACKET_TAKEITEM));
bitStream->Write(itemId);
bitStream->Write(count);
bitStream->Write(auxValue);
bitStream->Write(playerId);
}
void read(RakNet::BitStream* bitStream)
{
bitStream->Read(itemId);
bitStream->Read(count);
bitStream->Read(auxValue);
bitStream->Read(playerId);
}
void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback)
{
callback->handle(source, (TakeItemPacket*)this);
}
int playerId;
int itemId;
int count;
int auxValue;
};
#endif /*NET_MINECRAFT_NETWORK_PACKET__TakeItemPacket_H__*/

View File

@@ -0,0 +1,54 @@
#ifndef NET_MINECRAFT_NETWORK_PACKET__WantCreatePacket_H__
#define NET_MINECRAFT_NETWORK_PACKET__WantCreatePacket_H__
//package net.minecraft.network.packet;
#include "../Packet.h"
class WantCreatePacket: public Packet
{
public:
WantCreatePacket() {
}
WantCreatePacket(int playerId, int count, int auxValue, int itemId)
:
playerId(playerId),
count(count),
auxValue(auxValue),
itemId(itemId)
{
}
void write(RakNet::BitStream* bitStream)
{
bitStream->Write((RakNet::MessageID)(ID_USER_PACKET_ENUM + PACKET_WANTCREATEITEM));
bitStream->Write(itemId);
bitStream->Write(count);
bitStream->Write(auxValue);
bitStream->Write(playerId);
}
void read(RakNet::BitStream* bitStream)
{
bitStream->Read(itemId);
bitStream->Read(count);
bitStream->Read(auxValue);
bitStream->Read(playerId);
}
void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback)
{
callback->handle(source, (WantCreatePacket*)this);
}
int playerId;
int itemId;
int count;
int auxValue;
};
#endif /*NET_MINECRAFT_NETWORK_PACKET__WantCreatePacket_H__*/

View File

@@ -17,6 +17,11 @@ ArgumentsSettings::ArgumentsSettings(int numArguments, char** arguments)
levelName = std::string(arguments[a+1]); levelName = std::string(arguments[a+1]);
a++; // Skip the next argument since it's part of this one. a++; // Skip the next argument since it's part of this one.
} }
} else if(strcmp(arguments[a], "--gamemode") == 0) {
if(a + 1 < numArguments) {
gamemode = std::string(arguments[a+1]);
a++; // Skip the next argument since it's part of this one.
}
} else if(strcmp(arguments[a], "--leveldir") == 0) { } else if(strcmp(arguments[a], "--leveldir") == 0) {
if(a + 1 < numArguments) { if(a + 1 < numArguments) {
levelDir = std::string(arguments[a+1]); levelDir = std::string(arguments[a+1]);
@@ -51,6 +56,9 @@ std::string ArgumentsSettings::getServerKey() {
std::string ArgumentsSettings::getCachePath() { std::string ArgumentsSettings::getCachePath() {
return cachePath; return cachePath;
} }
std::string ArgumentsSettings::getGamemode() {
return gamemode;
}
std::string ArgumentsSettings::getLevelDir() { std::string ArgumentsSettings::getLevelDir() {
return levelDir; return levelDir;
} }

View File

@@ -4,20 +4,27 @@
class ArgumentsSettings { class ArgumentsSettings {
public: public:
ArgumentsSettings(int numArguments, char** arguments); ArgumentsSettings(int numArguments, char** arguments);
std::string getExternalPath(); std::string getExternalPath();
std::string getLevelName(); std::string getLevelName();
std::string getServerKey(); std::string getServerKey();
std::string getCachePath(); std::string getCachePath();
std::string getLevelDir(); std::string getLevelDir();
std::string getGamemode();
bool getShowHelp(); bool getShowHelp();
int getPort(); int getPort();
private: private:
std::string cachePath; std::string cachePath;
std::string externalPath; std::string externalPath;
std::string levelName; std::string levelName;
std::string gamemode;
std::string levelDir; std::string levelDir;
std::string serverKey; std::string serverKey;
bool showHelp; bool showHelp;
int port; int port;
}; };

View File

@@ -12,16 +12,19 @@ ServerLevel::ServerLevel(LevelStorage* levelStorage, const std::string& levelNam
void ServerLevel::updateSleepingPlayerList() { void ServerLevel::updateSleepingPlayerList() {
bool allPlayersWasSleeping = allPlayersAreSleeping; bool allPlayersWasSleeping = allPlayersAreSleeping;
allPlayersAreSleeping = !players.empty(); allPlayersAreSleeping = !players.empty();
for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) {
for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) {
Player* player = *it; Player* player = *it;
if(!player->isSleeping()) {
if (!player->isSleeping()) {
allPlayersAreSleeping = false; allPlayersAreSleeping = false;
break; break;
} }
} }
if(!allPlayersWasSleeping && allPlayersAreSleeping) { if (!allPlayersWasSleeping && allPlayersAreSleeping) {
levelEvent(NULL, LevelEvent::ALL_PLAYERS_SLEEPING, 0, 0, 0, 0); levelEvent(NULL, LevelEvent::ALL_PLAYERS_SLEEPING, 0, 0, 0, 0);
for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) {
for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) {
(*it)->setAllPlayersSleeping(); (*it)->setAllPlayersSleeping();
} }
} }
@@ -29,23 +32,26 @@ void ServerLevel::updateSleepingPlayerList() {
void ServerLevel::awakenAllPlayers() { void ServerLevel::awakenAllPlayers() {
allPlayersAreSleeping = false; allPlayersAreSleeping = false;
for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) {
for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) {
Player* player = *it; Player* player = *it;
if(player->isSleeping()) {
if (player->isSleeping()) {
player->stopSleepInBed(false, false, true); player->stopSleepInBed(false, false, true);
player->health = Player::MAX_HEALTH; player->health = Player::MAX_HEALTH;
player->lastHealth = Player::MAX_HEALTH; player->lastHealth = Player::MAX_HEALTH;
} }
} }
SetHealthPacket packet(Player::MAX_HEALTH); SetHealthPacket packet(Player::MAX_HEALTH);
raknetInstance->send(packet); raknetInstance->send(packet);
} }
bool ServerLevel::allPlayersSleeping() { bool ServerLevel::allPlayersSleeping() {
if(allPlayersAreSleeping && !isClientSide) { if (allPlayersAreSleeping && !isClientSide) {
// all players are sleeping, but have they slept long enough? // all players are sleeping, but have they slept long enough?
for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) {
if(!(*it)->isSleepingLongEnough()) { if (!(*it)->isSleepingLongEnough()) {
return false; return false;
} }
} }
@@ -55,13 +61,17 @@ bool ServerLevel::allPlayersSleeping() {
return false; return false;
} }
void ServerLevel::tick(){ void ServerLevel::tick() {
super::tick(); super::tick();
if(allPlayersSleeping()) {
if (allPlayersSleeping()) {
long newTime = levelData.getTime() + TICKS_PER_DAY; long newTime = levelData.getTime() + TICKS_PER_DAY;
levelData.setTime(newTime - (newTime % TICKS_PER_DAY)); levelData.setTime(newTime - (newTime % TICKS_PER_DAY));
SetTimePacket packet(levelData.getTime()); SetTimePacket packet(levelData.getTime());
raknetInstance->send(packet); raknetInstance->send(packet);
awakenAllPlayers(); awakenAllPlayers();
} }
} }

View File

@@ -19,14 +19,17 @@
#include "../network/packet/AnimatePacket.h" #include "../network/packet/AnimatePacket.h"
#include "../world/level/tile/entity/ChestTileEntity.h" #include "../world/level/tile/entity/ChestTileEntity.h"
#include "../network/packet/HurtArmorPacket.h" #include "../network/packet/HurtArmorPacket.h"
#include "network/packet/SendInventoryPacket.h"
#include "world/entity/player/Inventory.h"
ServerPlayer::ServerPlayer( Minecraft* minecraft, Level* level ) ServerPlayer::ServerPlayer( Minecraft* minecraft, Level* level, bool proto)
: super(level, minecraft->isCreativeMode()), : super(level, minecraft->isCreativeMode()),
_mc(minecraft), _mc(minecraft),
_prevHealth(-999), _prevHealth(-999),
_containerCounter(0) _containerCounter(0),
isNewProto(proto)
{ {
hasFakeInventory = true; // hasFakeInventory = true;
footSize = 0; footSize = 0;
} }
@@ -67,7 +70,16 @@ void ServerPlayer::tick() {
void ServerPlayer::take( Entity* e, int orgCount ) { void ServerPlayer::take( Entity* e, int orgCount ) {
TakeItemEntityPacket packet(e->entityId, entityId); TakeItemEntityPacket packet(e->entityId, entityId);
// SendInventoryPacket packet(this, false);
_mc->raknetInstance->send(packet); _mc->raknetInstance->send(packet);
printf("TakeItemEntityPacket \n");
LOGI("Inventory:\n");
for (int i = 0; i < inventory->numLinkedSlots; i++) {
auto item = inventory->getItem(i);
if (item)
LOGI("\t %i: %s (%i)\n", i, item->getName().c_str(), item->count);
}
super::take(e, orgCount); super::take(e, orgCount);
} }
@@ -118,20 +130,20 @@ bool ServerPlayer::hasResource( int id ) {
void ServerPlayer::setContainerData( BaseContainerMenu* menu, int id, int value ) { void ServerPlayer::setContainerData( BaseContainerMenu* menu, int id, int value ) {
ContainerSetDataPacket p(menu->containerId, id, value); ContainerSetDataPacket p(menu->containerId, id, value);
_mc->raknetInstance->send(owner, p); _mc->raknetInstance->send(owner, p);
//LOGI("Setting container data for id %d: %d\n", id, value); LOGI("Setting container data for id %d: %d\n", id, value);
} }
void ServerPlayer::slotChanged( BaseContainerMenu* menu, int slot, const ItemInstance& item, bool isResultSlot ) { void ServerPlayer::slotChanged( BaseContainerMenu* menu, int slot, const ItemInstance& item, bool isResultSlot ) {
if (isResultSlot) return; if (isResultSlot) return;
ContainerSetSlotPacket p(menu->containerId, slot, item); ContainerSetSlotPacket p(menu->containerId, slot, item);
_mc->raknetInstance->send(owner, p); _mc->raknetInstance->send(owner, p);
//LOGI("Slot %d changed\n", slot); LOGI("Slot %d changed\n", slot);
} }
void ServerPlayer::refreshContainer( BaseContainerMenu* menu, const std::vector<ItemInstance>& items ) { void ServerPlayer::refreshContainer( BaseContainerMenu* menu, const std::vector<ItemInstance>& items ) {
ContainerSetContentPacket p(menu->containerId, menu->getItems()); ContainerSetContentPacket p(menu->containerId, menu->getItems());
_mc->raknetInstance->send(owner, p); _mc->raknetInstance->send(owner, p);
//LOGI("Refreshing container with %d items\n", items.size()); LOGI("Refreshing container with %zu items\n", items.size());
} }
void ServerPlayer::nextContainerCounter() { void ServerPlayer::nextContainerCounter() {
@@ -163,3 +175,12 @@ void ServerPlayer::displayClientMessage( const std::string& messageId ) {
ChatPacket package(messageId); ChatPacket package(messageId);
_mc->raknetInstance->send(owner, package); _mc->raknetInstance->send(owner, package);
} }
void ServerPlayer::causeFallDamage(float distance) {
int dmg = (int) ceil((distance - 3));
if (dmg > 0) {
SetHealthPacket packet(SetHealthPacket::HEALTH_MODIFY_OFFSET + dmg);
_mc->raknetInstance->send(owner, packet);
}
super::causeFallDamage(distance);
}

View File

@@ -15,7 +15,7 @@ class ServerPlayer: public Player,
{ {
typedef Player super; typedef Player super;
public: public:
ServerPlayer(Minecraft* minecraft, Level* level); ServerPlayer(Minecraft* minecraft, Level* level, bool proto);
~ServerPlayer(); ~ServerPlayer();
@@ -43,6 +43,17 @@ public:
virtual void stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint); virtual void stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint);
void completeUsingItem(); void completeUsingItem();
void setLastMoveTicks(int lastMoveTicks) { this->lastMoveTicks = lastMoveTicks; }
int getLastMoveTicks() { return lastMoveTicks; }
void setTicksInAir(int ticksInAir) { this->ticksInAir = ticksInAir; }
int getTicksInAir() { return ticksInAir; }
void setNewProto(bool proto) { isNewProto = proto; }
bool getProto() { return isNewProto; }
virtual void causeFallDamage(float distance);
private: private:
void nextContainerCounter(); void nextContainerCounter();
void setContainerMenu( BaseContainerMenu* menu ); void setContainerMenu( BaseContainerMenu* menu );
@@ -50,6 +61,11 @@ private:
Minecraft* _mc; Minecraft* _mc;
int _prevHealth; int _prevHealth;
int _containerCounter; int _containerCounter;
int lastMoveTicks = 0;
int ticksInAir = 0;
bool isNewProto = false;
}; };
#endif /*ServerPlayer_H__*/ #endif /*ServerPlayer_H__*/

View File

@@ -871,8 +871,8 @@ bool Entity::load( CompoundTag* tag )
// Add a small padding if standing next to the world edges // Add a small padding if standing next to the world edges
const float padding = bbWidth * 0.5f + 0.001f; const float padding = bbWidth * 0.5f + 0.001f;
xx = Mth::clamp(xx, padding, (float)LEVEL_WIDTH - padding); xx = Mth::clamp(xx, padding, (float)LevelConstants::LEVEL_WIDTH - padding);
zz = Mth::clamp(zz, padding, (float)LEVEL_DEPTH - padding); zz = Mth::clamp(zz, padding, (float)LevelConstants::LEVEL_DEPTH - padding);
xo = xOld = x = xx; xo = xOld = x = xx;
yo = yOld = y = yy; yo = yOld = y = yy;

View File

@@ -129,6 +129,7 @@ public:
virtual bool isHangingEntity(); virtual bool isHangingEntity();
virtual int getAuxData(); virtual int getAuxData();
virtual void checkFallDamage(float ya, bool onGround);
protected: protected:
virtual void setRot(float yRot, float xRot); virtual void setRot(float yRot, float xRot);
@@ -137,7 +138,6 @@ protected:
virtual void resetPos(bool clearMore); virtual void resetPos(bool clearMore);
virtual void outOfWorld(); virtual void outOfWorld();
virtual void checkFallDamage(float ya, bool onGround);
virtual void causeFallDamage(float fallDamage2); virtual void causeFallDamage(float fallDamage2);
virtual void markHurt(); virtual void markHurt();

View File

@@ -729,7 +729,6 @@ bool Mob::isWaterMob()
void Mob::aiStep() void Mob::aiStep()
{ {
//@todo? 30 lines of code here in java version //@todo? 30 lines of code here in java version
TIMER_PUSH("ai"); TIMER_PUSH("ai");
if (isImmobile()) { if (isImmobile()) {
jumping = false; jumping = false;

View File

@@ -223,6 +223,9 @@ protected:
double xc, yc, zc; double xc, yc, zc;
public: public:
void setxxa(float xxa) { this->xxa = xxa; }
void setyya(float yya) { this->yya = yya; }
// Cape position accessors (for renderers) // Cape position accessors (for renderers)
double getCapeX() const { return xCape; } double getCapeX() const { return xCape; }
double getCapeY() const { return yCape; } double getCapeY() const { return yCape; }

View File

@@ -357,3 +357,12 @@ bool Inventory::removeItem( const ItemInstance* samePtr ) {
} }
return false; return false;
} }
void Inventory::print() {
LOGI("%s's Inventory:\n", player->name.c_str());
for (int i = 0; i < numTotalSlots; i++) {
auto item = getItem(i);
if (item) LOGI("\t %i: %s (%i) %s\n", i, item->getName().c_str(), item->count, (player->inventory->getLinked(i))? "(Linked)" : "");
}
}

View File

@@ -45,6 +45,8 @@ public:
int getAttackDamage(Entity* entity); int getAttackDamage(Entity* entity);
float getDestroySpeed(Tile* tile); float getDestroySpeed(Tile* tile);
bool canDestroy(Tile* tile); bool canDestroy(Tile* tile);
void print();
private: private:
void setupDefault(); void setupDefault();
public: public:

View File

@@ -141,6 +141,11 @@ bool FillingContainer::add( ItemInstance* item )
// // silently destroy the item when having a full inventory // // silently destroy the item when having a full inventory
// item->count = 0; // item->count = 0;
// return true; // return true;
LOGI("Inventory:\n");
for (int i = 0; i < numTotalSlots; i++) {
LOGI("\t %i: %s (%i)\n", i, items.at(i)->getName().c_str(), items.at(i)->count);
}
} }
return false; return false;

View File

@@ -290,3 +290,7 @@ bool ItemInstance::isArmorItem( const ItemInstance* instance ) {
return item->isArmor(); return item->isArmor();
} }
bool ItemInstance::isBlock(const ItemInstance* instance) {
return instance->id < 256;
}

View File

@@ -81,6 +81,8 @@ public:
static bool isArmorItem(const ItemInstance* instance); static bool isArmorItem(const ItemInstance* instance);
static bool isBlock(const ItemInstance* instance);
/** /**
* Checks if this item is the same item as the other one, disregarding the * Checks if this item is the same item as the other one, disregarding the
* 'count' value. * 'count' value.

View File

@@ -29,6 +29,9 @@
#include "../Difficulty.h" #include "../Difficulty.h"
#include "../../network/packet/ExplodePacket.h" #include "../../network/packet/ExplodePacket.h"
const int Level::DEPTH = LevelConstants::LEVEL_HEIGHT;
const int Level::SEA_LEVEL = Level::DEPTH / 2 - 1;
Level::Level(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */) Level::Level(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */)
: levelStorage(levelStorage), : levelStorage(levelStorage),
isClientSide(false), isClientSide(false),
@@ -278,8 +281,8 @@ void Level::tickTiles() {
for (int i = 0; i < pollChunkOffsetsSize; i += 2) { for (int i = 0; i < pollChunkOffsetsSize; i += 2) {
const int xp = xx + pollChunkOffsets[i]; const int xp = xx + pollChunkOffsets[i];
const int zp = zz + pollChunkOffsets[i+1]; const int zp = zz + pollChunkOffsets[i+1];
if (xp >= 0 && xp < CHUNK_CACHE_WIDTH && if (xp >= 0 && xp < LevelConstants::CHUNK_CACHE_WIDTH &&
zp >= 0 && zp < CHUNK_CACHE_WIDTH) zp >= 0 && zp < LevelConstants::CHUNK_CACHE_WIDTH)
_chunksToPoll.insert(ChunkPos(xp, zp)); _chunksToPoll.insert(ChunkPos(xp, zp));
} }
} }
@@ -428,17 +431,17 @@ bool Level::findPath(Path* path, Entity* from, int xBest, int yBest, int zBest,
/*protected*/ /*protected*/
void Level::setInitialSpawn() { void Level::setInitialSpawn() {
isFindingSpawn = true; isFindingSpawn = true;
int xSpawn = CHUNK_CACHE_WIDTH * CHUNK_WIDTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; int xSpawn = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0;
int ySpawn = 64; int ySpawn = 64;
int zSpawn = CHUNK_CACHE_WIDTH * CHUNK_DEPTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; int zSpawn = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0;
while (!dimension->isValidSpawn(xSpawn, zSpawn)) { while (!dimension->isValidSpawn(xSpawn, zSpawn)) {
xSpawn += random.nextInt(32) - random.nextInt(32); xSpawn += random.nextInt(32) - random.nextInt(32);
zSpawn += random.nextInt(32) - random.nextInt(32); zSpawn += random.nextInt(32) - random.nextInt(32);
if (xSpawn < 4) xSpawn += 32; if (xSpawn < 4) xSpawn += 32;
if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 32; if (xSpawn >= LevelConstants::LEVEL_WIDTH-4) xSpawn -= 32;
if (zSpawn < 4) zSpawn += 32; if (zSpawn < 4) zSpawn += 32;
if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 32; if (zSpawn >= LevelConstants::LEVEL_DEPTH-4) zSpawn -= 32;
} }
levelData.setSpawn(xSpawn, ySpawn, zSpawn); levelData.setSpawn(xSpawn, ySpawn, zSpawn);
isFindingSpawn = false; isFindingSpawn = false;
@@ -456,9 +459,9 @@ void Level::validateSpawn() {
zSpawn += random.nextInt(8) - random.nextInt(8); zSpawn += random.nextInt(8) - random.nextInt(8);
if (xSpawn < 4) xSpawn += 8; if (xSpawn < 4) xSpawn += 8;
if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 8; if (xSpawn >= LevelConstants::LEVEL_WIDTH-4) xSpawn -= 8;
if (zSpawn < 4) zSpawn += 8; if (zSpawn < 4) zSpawn += 8;
if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 8; if (zSpawn >= LevelConstants::LEVEL_DEPTH-4) zSpawn -= 8;
} }
levelData.setXSpawn(xSpawn); levelData.setXSpawn(xSpawn);
levelData.setZSpawn(zSpawn); levelData.setZSpawn(zSpawn);
@@ -944,7 +947,7 @@ HitResult Level::clip(const Vec3& A, const Vec3& b, bool liquid /*= false*/, boo
if (solidOnly && tile != NULL && tile->getAABB(this, xTile0, yTile0, zTile0) == NULL) { if (solidOnly && tile != NULL && tile->getAABB(this, xTile0, yTile0, zTile0) == NULL) {
// No collision // No collision
} else if (t > 0 && tile->mayPick(data, liquid)) { } else if (t > 0 && tile->mayPick(data, liquid)) {
if(xTile0 >= 0 && zTile0 >= 0 && xTile0 < LEVEL_WIDTH && zTile0 < LEVEL_WIDTH) { if(xTile0 >= 0 && zTile0 >= 0 && xTile0 < LevelConstants::LEVEL_WIDTH && zTile0 < LevelConstants::LEVEL_WIDTH) {
HitResult r = tile->clip(this, xTile0, yTile0, zTile0, a, b); HitResult r = tile->clip(this, xTile0, yTile0, zTile0, a, b);
if (r.isHit()) return r; if (r.isHit()) return r;
} }
@@ -2222,9 +2225,9 @@ void Level::setNightMode( bool isNightMode ) {
} }
bool Level::inRange( int x, int y, int z ) { bool Level::inRange( int x, int y, int z ) {
return x >= 0 && x < LEVEL_WIDTH return x >= 0 && x < LevelConstants::LEVEL_WIDTH
&& y >= 0 && y < LEVEL_HEIGHT && y >= 0 && y < LevelConstants::LEVEL_HEIGHT
&& z >= 0 && z < LEVEL_DEPTH; && z >= 0 && z < LevelConstants::LEVEL_DEPTH;
} }
// //

View File

@@ -67,8 +67,8 @@ class Level: public LevelSource
public: public:
static const int MAX_LEVEL_SIZE = 32000000; static const int MAX_LEVEL_SIZE = 32000000;
static const short DEPTH = LEVEL_HEIGHT; static const int DEPTH;
static const short SEA_LEVEL = DEPTH / 2 - 1; static const int SEA_LEVEL;
static const int MAX_BRIGHTNESS = 15; static const int MAX_BRIGHTNESS = 15;
static const int TICKS_PER_DAY = SharedConstants::TicksPerSecond * 60 * 16;// SharedConstants::TicksPerSecond * 60 * 12; // ORG:20*60*20 static const int TICKS_PER_DAY = SharedConstants::TicksPerSecond * 60 * 16;// SharedConstants::TicksPerSecond * 60 * 12; // ORG:20*60*20
@@ -307,6 +307,9 @@ public:
Dimension* dimension; Dimension* dimension;
IRakNetInstance* raknetInstance; IRakNetInstance* raknetInstance;
Random random; Random random;
std::set<std::string> ops;
std::set<std::string> bannedPpl;
protected: protected:
bool isFindingSpawn; bool isFindingSpawn;

View File

@@ -0,0 +1,10 @@
#include "LevelConstants.h"
int LevelConstants::LEVEL_HEIGHT = 128;
int LevelConstants::CHUNK_CACHE_WIDTH = 16; // in chunks
int LevelConstants::CHUNK_WIDTH = 16; // in blocks
int LevelConstants::CHUNK_DEPTH = 16;
int LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * CHUNK_WIDTH;
int LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * CHUNK_DEPTH;
int LevelConstants::CHUNK_COLUMNS = LevelConstants::CHUNK_WIDTH * LevelConstants::CHUNK_DEPTH;
int LevelConstants::CHUNK_BLOCK_COUNT = LevelConstants::CHUNK_COLUMNS * LevelConstants::LEVEL_HEIGHT;

View File

@@ -1,14 +1,14 @@
#ifndef _MINECRAFT_WORLD_LEVELCONSTANTS_H_ #pragma once
#define _MINECRAFT_WORLD_LEVELCONSTANTS_H_
class LevelConstants {
const int LEVEL_HEIGHT = 128; public:
const int CHUNK_CACHE_WIDTH = 16; // in chunks static int CHUNK_CACHE_WIDTH; // in chunks
const int CHUNK_WIDTH = 16; // in blocks static int LEVEL_WIDTH;
const int CHUNK_DEPTH = 16; static int LEVEL_DEPTH;
const int LEVEL_WIDTH = CHUNK_CACHE_WIDTH * CHUNK_WIDTH; static int LEVEL_HEIGHT;
const int LEVEL_DEPTH = CHUNK_CACHE_WIDTH * CHUNK_DEPTH;
const int CHUNK_COLUMNS = CHUNK_WIDTH * CHUNK_DEPTH; static int CHUNK_WIDTH; // in blocks
const int CHUNK_BLOCK_COUNT = CHUNK_COLUMNS * LEVEL_HEIGHT; static int CHUNK_DEPTH;
static int CHUNK_COLUMNS;
#endif static int CHUNK_BLOCK_COUNT;
};

View File

@@ -10,7 +10,7 @@
#include "../LevelConstants.h" #include "../LevelConstants.h"
class ChunkCache: public ChunkSource { class ChunkCache: public ChunkSource {
//static const int CHUNK_CACHE_WIDTH = CHUNK_CACHE_WIDTH; // WAS 32; //static const int LevelConstants::CHUNK_CACHE_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH; // WAS 32;
static const int MAX_SAVES = 2; static const int MAX_SAVES = 2;
public: public:
ChunkCache(Level* level_, ChunkStorage* storage_, ChunkSource* source_) ChunkCache(Level* level_, ChunkStorage* storage_, ChunkSource* source_)
@@ -24,14 +24,17 @@ public:
isChunkCache = true; isChunkCache = true;
//emptyChunk = new EmptyLevelChunk(level_, emptyChunkBlocks, 0, 0); //emptyChunk = new EmptyLevelChunk(level_, emptyChunkBlocks, 0, 0);
emptyChunk = new EmptyLevelChunk(level_, NULL, 0, 0); emptyChunk = new EmptyLevelChunk(level_, NULL, 0, 0);
memset(chunks, 0, sizeof(LevelChunk*) * CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH);
chunks = new LevelChunk *[LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH];
memset(chunks, 0, sizeof(LevelChunk*) * LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH);
LOGI("Chunks allocated.");
} }
~ChunkCache() { ~ChunkCache() {
delete source; delete source;
delete emptyChunk; delete emptyChunk;
for (int i = 0; i < CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; i++) for (int i = 0; i < LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH; i++)
{ {
if (chunks[i]) if (chunks[i])
{ {
@@ -42,7 +45,7 @@ public:
} }
bool fits(int x, int z) { bool fits(int x, int z) {
return (x >= 0 && z >= 0 && x < CHUNK_CACHE_WIDTH && z < CHUNK_CACHE_WIDTH); return (x >= 0 && z >= 0 && x < LevelConstants::CHUNK_CACHE_WIDTH && z < LevelConstants::CHUNK_CACHE_WIDTH);
} }
bool hasChunk(int x, int z) { bool hasChunk(int x, int z) {
@@ -52,9 +55,9 @@ public:
if (x == xLast && z == zLast && last != NULL) { if (x == xLast && z == zLast && last != NULL) {
return true; return true;
} }
int xs = x & (CHUNK_CACHE_WIDTH - 1); int xs = x & (LevelConstants::CHUNK_CACHE_WIDTH - 1);
int zs = z & (CHUNK_CACHE_WIDTH - 1); int zs = z & (LevelConstants::CHUNK_CACHE_WIDTH - 1);
int slot = xs + zs * CHUNK_CACHE_WIDTH; int slot = xs + zs * LevelConstants::CHUNK_CACHE_WIDTH;
return chunks[slot] != NULL && (chunks[slot] == emptyChunk || chunks[slot]->isAt(x, z)); return chunks[slot] != NULL && (chunks[slot] == emptyChunk || chunks[slot]->isAt(x, z));
} }
@@ -71,9 +74,9 @@ public:
} }
if (!fits(x, z)) return emptyChunk; if (!fits(x, z)) return emptyChunk;
//if (!level->isFindingSpawn && !fits(x, z)) return emptyChunk; //if (!level->isFindingSpawn && !fits(x, z)) return emptyChunk;
int xs = x & (CHUNK_CACHE_WIDTH - 1); int xs = x & (LevelConstants::CHUNK_CACHE_WIDTH - 1);
int zs = z & (CHUNK_CACHE_WIDTH - 1); int zs = z & (LevelConstants::CHUNK_CACHE_WIDTH - 1);
int slot = xs + zs * CHUNK_CACHE_WIDTH; int slot = xs + zs * LevelConstants::CHUNK_CACHE_WIDTH;
if (!hasChunk(x, z)) { if (!hasChunk(x, z)) {
if (chunks[slot] != NULL) { if (chunks[slot] != NULL) {
chunks[slot]->unload(); chunks[slot]->unload();
@@ -199,8 +202,8 @@ public:
void saveAll(bool onlyUnsaved) { void saveAll(bool onlyUnsaved) {
if (storage != NULL) { if (storage != NULL) {
std::vector<LevelChunk*> chunks; std::vector<LevelChunk*> chunks;
for (int z = 0; z < CHUNK_CACHE_WIDTH; ++z) for (int z = 0; z < LevelConstants::CHUNK_CACHE_WIDTH; ++z)
for (int x = 0; x < CHUNK_CACHE_WIDTH; ++x) { for (int x = 0; x < LevelConstants::CHUNK_CACHE_WIDTH; ++x) {
LevelChunk* chunk = level->getChunk(x, z); LevelChunk* chunk = level->getChunk(x, z);
if (!onlyUnsaved || chunk->shouldSave(false)) if (!onlyUnsaved || chunk->shouldSave(false))
chunks.push_back( chunk ); chunks.push_back( chunk );
@@ -211,7 +214,7 @@ public:
private: private:
LevelChunk* load(int x, int z) { LevelChunk* load(int x, int z) {
if (storage == NULL) return emptyChunk; if (storage == NULL) return emptyChunk;
if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH) if (x < 0 || x >= LevelConstants::CHUNK_CACHE_WIDTH || z < 0 || z >= LevelConstants::CHUNK_CACHE_WIDTH)
{ {
return emptyChunk; return emptyChunk;
} }
@@ -254,7 +257,7 @@ private:
LevelChunk* emptyChunk; LevelChunk* emptyChunk;
ChunkSource* source; ChunkSource* source;
ChunkStorage* storage; ChunkStorage* storage;
LevelChunk* chunks[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH]; LevelChunk** chunks;
Level* level; Level* level;
LevelChunk* last; LevelChunk* last;

View File

@@ -12,13 +12,14 @@
/*static*/ /*static*/
bool LevelChunk::touchedSky = false; bool LevelChunk::touchedSky = false;
const int LevelChunk::ChunkBlockCount = LevelConstants::CHUNK_BLOCK_COUNT;
LevelChunk::LevelChunk( Level* level, int x, int z ) LevelChunk::LevelChunk( Level* level, int x, int z )
: level(level), : level(level),
x(x), x(x),
z(z), z(z),
xt(x * CHUNK_WIDTH), xt(x * LevelConstants::CHUNK_WIDTH),
zt(z * CHUNK_DEPTH) zt(z * LevelConstants::CHUNK_DEPTH)
{ {
init(); init();
} }
@@ -27,8 +28,8 @@ LevelChunk::LevelChunk( Level* level, unsigned char* blocks, int x, int z )
: level(level), : level(level),
x(x), x(x),
z(z), z(z),
xt(x * CHUNK_WIDTH), xt(x * LevelConstants::CHUNK_WIDTH),
zt(z * CHUNK_DEPTH), zt(z * LevelConstants::CHUNK_DEPTH),
blocks(blocks), blocks(blocks),
data(ChunkBlockCount), data(ChunkBlockCount),
skyLight(ChunkBlockCount), skyLight(ChunkBlockCount),
@@ -45,6 +46,9 @@ LevelChunk::~LevelChunk()
void LevelChunk::init() void LevelChunk::init()
{ {
heightmap = new char[LevelConstants::CHUNK_COLUMNS];
updateMap = new unsigned char[LevelConstants::CHUNK_COLUMNS];
terrainPopulated = false; terrainPopulated = false;
dontSave = false; dontSave = false;
unsaved = false; unsaved = false;

View File

@@ -106,9 +106,9 @@ private:
void recalcHeight(int x, int yStart, int z); void recalcHeight(int x, int yStart, int z);
public: public:
static bool touchedSky; static bool touchedSky;
static const int ChunkBlockCount = CHUNK_BLOCK_COUNT; static const int ChunkBlockCount;
static const int ChunkSize = ChunkBlockCount; const int ChunkSize = ChunkBlockCount;
static const int UpdateMapBitShift = 4; // power of (LEVEL_HEIGHT / 8) == 16 static const int UpdateMapBitShift = 4; // power of (LevelConstants::LEVEL_HEIGHT / 8) == 16
int blocksLength; // ? needed or not? (i.e. are all chunks the same size?) int blocksLength; // ? needed or not? (i.e. are all chunks the same size?)
@@ -118,12 +118,12 @@ public:
DataLayer skyLight; DataLayer skyLight;
DataLayer blockLight; DataLayer blockLight;
char heightmap[CHUNK_COLUMNS]; char* heightmap; // [LevelConstants::CHUNK_COLUMNS]
unsigned char updateMap[CHUNK_COLUMNS]; // marks regions within block columns that have been modified unsigned char* updateMap; // marks regions within block columns that have been modified [LevelConstants::CHUNK_COLUMNS]
int minHeight; int minHeight;
const int x, z; int x, z;
const int xt, zt; int xt, zt;
bool terrainPopulated; bool terrainPopulated;
bool unsaved; bool unsaved;

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