mirror of
https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1.git
synced 2026-03-19 22:43:32 +00:00
Merge remote-tracking branch 'refs/remotes/origin/main'
This commit is contained in:
212
CMakeLists.txt
212
CMakeLists.txt
@@ -5,11 +5,11 @@ include(cmake/CPM.cmake)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||||
|
set(CMAKE_POLICY_VERSION_MINIMUM 3.10)
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
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")
|
set(CMAKE_CXX_FLAGS "-Wno-c++11-narrowing -Wno-narrowing -Wno-invalid-source-encoding -Wno-reserved-user-defined-literal")
|
||||||
endif()
|
endif()
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
CPMAddPackage("gh:madler/zlib@1.3.2")
|
CPMAddPackage("gh:madler/zlib@1.3.2")
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME "libpng"
|
NAME "libpng"
|
||||||
@@ -44,8 +44,191 @@ CPMAddPackage(
|
|||||||
"GLFW_BUILD_DOCS OFF"
|
"GLFW_BUILD_DOCS OFF"
|
||||||
"BUILD_SHARED_LIBS ON"
|
"BUILD_SHARED_LIBS ON"
|
||||||
)
|
)
|
||||||
|
# TODO: Clear this paths with *
|
||||||
|
file(GLOB SERVER_SOURCES
|
||||||
|
"src/NinecraftApp.cpp"
|
||||||
|
"src/Performance.cpp"
|
||||||
|
"src/SharedConstants.cpp"
|
||||||
|
|
||||||
file(GLOB SOURCES
|
"src/client/IConfigListener.cpp"
|
||||||
|
"src/client/Minecraft.cpp"
|
||||||
|
"src/client/OptionStrings.cpp"
|
||||||
|
"src/client/Options.cpp"
|
||||||
|
"src/client/OptionsFile.cpp"
|
||||||
|
|
||||||
|
"src/client/gamemode/CreativeMode.cpp"
|
||||||
|
"src/client/gamemode/GameMode.cpp"
|
||||||
|
"src/client/gamemode/SurvivalMode.cpp"
|
||||||
|
|
||||||
|
"src/client/player/LocalPlayer.cpp"
|
||||||
|
"src/client/player/RemotePlayer.cpp"
|
||||||
|
"src/client/player/input/KeyboardInput.cpp"
|
||||||
|
|
||||||
|
"src/locale/I18n.cpp"
|
||||||
|
|
||||||
|
"src/main.cpp"
|
||||||
|
"src/main_dedicated.cpp"
|
||||||
|
|
||||||
|
"src/nbt/Tag.cpp"
|
||||||
|
|
||||||
|
"src/network/ClientSideNetworkHandler.cpp"
|
||||||
|
"src/network/NetEventCallback.cpp"
|
||||||
|
"src/network/Packet.cpp"
|
||||||
|
"src/network/RakNetInstance.cpp"
|
||||||
|
"src/network/ServerSideNetworkHandler.cpp"
|
||||||
|
"src/network/command/CommandServer.cpp"
|
||||||
|
|
||||||
|
"src/platform/CThread.cpp"
|
||||||
|
"src/platform/HttpClient.cpp"
|
||||||
|
"src/platform/PngLoader.cpp"
|
||||||
|
"src/platform/time.cpp"
|
||||||
|
|
||||||
|
"src/platform/input/Controller.cpp"
|
||||||
|
"src/platform/input/Keyboard.cpp"
|
||||||
|
"src/platform/input/Mouse.cpp"
|
||||||
|
"src/platform/input/Multitouch.cpp"
|
||||||
|
|
||||||
|
"src/server/ArgumentsSettings.cpp"
|
||||||
|
"src/server/ServerLevel.cpp"
|
||||||
|
"src/server/ServerPlayer.cpp"
|
||||||
|
|
||||||
|
"src/util/DataIO.cpp"
|
||||||
|
"src/util/Mth.cpp"
|
||||||
|
"src/util/PerfTimer.cpp"
|
||||||
|
"src/util/StringUtils.cpp"
|
||||||
|
|
||||||
|
"src/world/Direction.cpp"
|
||||||
|
|
||||||
|
"src/world/entity/AgableMob.cpp"
|
||||||
|
"src/world/entity/Entity.cpp"
|
||||||
|
"src/world/entity/EntityFactory.cpp"
|
||||||
|
"src/world/entity/FlyingMob.cpp"
|
||||||
|
"src/world/entity/HangingEntity.cpp"
|
||||||
|
"src/world/entity/Mob.cpp"
|
||||||
|
"src/world/entity/MobCategory.cpp"
|
||||||
|
"src/world/entity/Motive.cpp"
|
||||||
|
"src/world/entity/Painting.cpp"
|
||||||
|
"src/world/entity/PathfinderMob.cpp"
|
||||||
|
"src/world/entity/SynchedEntityData.cpp"
|
||||||
|
|
||||||
|
"src/world/entity/ai/control/MoveControl.cpp"
|
||||||
|
|
||||||
|
"src/world/entity/animal/Animal.cpp"
|
||||||
|
"src/world/entity/animal/Chicken.cpp"
|
||||||
|
"src/world/entity/animal/Cow.cpp"
|
||||||
|
"src/world/entity/animal/Pig.cpp"
|
||||||
|
"src/world/entity/animal/Sheep.cpp"
|
||||||
|
"src/world/entity/animal/WaterAnimal.cpp"
|
||||||
|
|
||||||
|
"src/world/entity/item/FallingTile.cpp"
|
||||||
|
"src/world/entity/item/ItemEntity.cpp"
|
||||||
|
"src/world/entity/item/PrimedTnt.cpp"
|
||||||
|
"src/world/entity/item/TripodCamera.cpp"
|
||||||
|
|
||||||
|
"src/world/entity/monster/Creeper.cpp"
|
||||||
|
"src/world/entity/monster/Monster.cpp"
|
||||||
|
"src/world/entity/monster/PigZombie.cpp"
|
||||||
|
"src/world/entity/monster/Skeleton.cpp"
|
||||||
|
"src/world/entity/monster/Spider.cpp"
|
||||||
|
"src/world/entity/monster/Zombie.cpp"
|
||||||
|
|
||||||
|
"src/world/entity/player/Inventory.cpp"
|
||||||
|
"src/world/entity/player/Player.cpp"
|
||||||
|
|
||||||
|
"src/world/entity/projectile/Arrow.cpp"
|
||||||
|
"src/world/entity/projectile/Throwable.cpp"
|
||||||
|
|
||||||
|
"src/world/food/SimpleFoodData.cpp"
|
||||||
|
|
||||||
|
"src/world/inventory/BaseContainerMenu.cpp"
|
||||||
|
"src/world/inventory/ContainerMenu.cpp"
|
||||||
|
"src/world/inventory/FillingContainer.cpp"
|
||||||
|
"src/world/inventory/FurnaceMenu.cpp"
|
||||||
|
|
||||||
|
"src/world/item/ArmorItem.cpp"
|
||||||
|
"src/world/item/BedItem.cpp"
|
||||||
|
"src/world/item/DyePowderItem.cpp"
|
||||||
|
"src/world/item/HangingEntityItem.cpp"
|
||||||
|
"src/world/item/HatchetItem.cpp"
|
||||||
|
"src/world/item/HoeItem.cpp"
|
||||||
|
"src/world/item/Item.cpp"
|
||||||
|
"src/world/item/ItemInstance.cpp"
|
||||||
|
"src/world/item/PickaxeItem.cpp"
|
||||||
|
"src/world/item/ShovelItem.cpp"
|
||||||
|
|
||||||
|
"src/world/item/crafting/ArmorRecipes.cpp"
|
||||||
|
"src/world/item/crafting/FurnaceRecipes.cpp"
|
||||||
|
"src/world/item/crafting/OreRecipes.cpp"
|
||||||
|
"src/world/item/crafting/Recipe.cpp"
|
||||||
|
"src/world/item/crafting/Recipes.cpp"
|
||||||
|
"src/world/item/crafting/StructureRecipes.cpp"
|
||||||
|
"src/world/item/crafting/ToolRecipes.cpp"
|
||||||
|
"src/world/item/crafting/WeaponRecipes.cpp"
|
||||||
|
|
||||||
|
"src/world/level/Explosion.cpp"
|
||||||
|
"src/world/level/Level.cpp"
|
||||||
|
"src/world/level/LightLayer.cpp"
|
||||||
|
"src/world/level/LightUpdate.cpp"
|
||||||
|
"src/world/level/MobSpawner.cpp"
|
||||||
|
"src/world/level/Region.cpp"
|
||||||
|
"src/world/level/TickNextTickData.cpp"
|
||||||
|
|
||||||
|
"src/world/level/biome/Biome.cpp"
|
||||||
|
"src/world/level/biome/BiomeSource.cpp"
|
||||||
|
|
||||||
|
"src/world/level/chunk/LevelChunk.cpp"
|
||||||
|
|
||||||
|
"src/world/level/dimension/Dimension.cpp"
|
||||||
|
|
||||||
|
"src/world/level/levelgen/CanyonFeature.cpp"
|
||||||
|
"src/world/level/levelgen/DungeonFeature.cpp"
|
||||||
|
"src/world/level/levelgen/LargeCaveFeature.cpp"
|
||||||
|
"src/world/level/levelgen/LargeFeature.cpp"
|
||||||
|
"src/world/level/levelgen/RandomLevelSource.cpp"
|
||||||
|
"src/world/level/levelgen/feature/Feature.cpp"
|
||||||
|
"src/world/level/levelgen/synth/ImprovedNoise.cpp"
|
||||||
|
"src/world/level/levelgen/synth/PerlinNoise.cpp"
|
||||||
|
"src/world/level/levelgen/synth/Synth.cpp"
|
||||||
|
|
||||||
|
"src/world/level/material/Material.cpp"
|
||||||
|
|
||||||
|
"src/world/level/pathfinder/Path.cpp"
|
||||||
|
|
||||||
|
"src/world/level/storage/ExternalFileLevelStorage.cpp"
|
||||||
|
"src/world/level/storage/ExternalFileLevelStorageSource.cpp"
|
||||||
|
"src/world/level/storage/FolderMethods.cpp"
|
||||||
|
"src/world/level/storage/LevelData.cpp"
|
||||||
|
"src/world/level/storage/LevelStorageSource.cpp"
|
||||||
|
"src/world/level/storage/RegionFile.cpp"
|
||||||
|
|
||||||
|
"src/world/level/tile/BedTile.cpp"
|
||||||
|
"src/world/level/tile/ChestTile.cpp"
|
||||||
|
"src/world/level/tile/CropTile.cpp"
|
||||||
|
"src/world/level/tile/DoorTile.cpp"
|
||||||
|
"src/world/level/tile/EntityTile.cpp"
|
||||||
|
"src/world/level/tile/FurnaceTile.cpp"
|
||||||
|
"src/world/level/tile/GrassTile.cpp"
|
||||||
|
"src/world/level/tile/HeavyTile.cpp"
|
||||||
|
"src/world/level/tile/LightGemTile.cpp"
|
||||||
|
"src/world/level/tile/MelonTile.cpp"
|
||||||
|
"src/world/level/tile/Mushroom.cpp"
|
||||||
|
"src/world/level/tile/NetherReactor.cpp"
|
||||||
|
"src/world/level/tile/NetherReactorPattern.cpp"
|
||||||
|
"src/world/level/tile/StairTile.cpp"
|
||||||
|
"src/world/level/tile/StemTile.cpp"
|
||||||
|
"src/world/level/tile/StoneSlabTile.cpp"
|
||||||
|
"src/world/level/tile/TallGrass.cpp"
|
||||||
|
"src/world/level/tile/Tile.cpp"
|
||||||
|
"src/world/level/tile/TrapDoorTile.cpp"
|
||||||
|
"src/world/level/tile/entity/ChestTileEntity.cpp"
|
||||||
|
"src/world/level/tile/entity/FurnaceTileEntity.cpp"
|
||||||
|
"src/world/level/tile/entity/NetherReactorTileEntity.cpp"
|
||||||
|
"src/world/level/tile/entity/SignTileEntity.cpp"
|
||||||
|
"src/world/level/tile/entity/TileEntity.cpp"
|
||||||
|
|
||||||
|
"src/world/phys/HitResult.cpp"
|
||||||
|
)
|
||||||
|
file(GLOB CLIENT_SOURCES
|
||||||
"src/client/*.cpp"
|
"src/client/*.cpp"
|
||||||
|
|
||||||
"src/client/gamemode/*.cpp"
|
"src/client/gamemode/*.cpp"
|
||||||
@@ -129,25 +312,29 @@ endif()
|
|||||||
|
|
||||||
|
|
||||||
if(PLATFORM STREQUAL "PLATFORM_WIN32")
|
if(PLATFORM STREQUAL "PLATFORM_WIN32")
|
||||||
list(APPEND SOURCES "src/AppPlatform_win32.cpp")
|
list(APPEND CLIENT_SOURCES "src/AppPlatform_win32.cpp")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(PLATFORM STREQUAL "PLATFORM_GLFW")
|
if(PLATFORM STREQUAL "PLATFORM_GLFW")
|
||||||
list(APPEND SOURCES "src/AppPlatform_glfw.cpp")
|
list(APPEND CLIENT_SOURCES "src/AppPlatform_glfw.cpp")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Explicitly list files added after the initial glob so they are always included
|
# Explicitly list files added after the initial glob so they are always included
|
||||||
list(APPEND SOURCES
|
list(APPEND CLIENT_SOURCES
|
||||||
"src/client/gui/screens/ConsoleScreen.cpp"
|
"src/client/gui/screens/ConsoleScreen.cpp"
|
||||||
"src/client/gui/screens/UsernameScreen.cpp"
|
"src/client/gui/screens/UsernameScreen.cpp"
|
||||||
"src/client/gui/screens/CreditsScreen.cpp"
|
"src/client/gui/screens/CreditsScreen.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
${SOURCES}
|
${CLIENT_SOURCES}
|
||||||
"glad/src/glad.c"
|
"glad/src/glad.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#add_executable("${PROJECT_NAME}-server"
|
||||||
|
# ${SERVER_SOURCES}
|
||||||
|
#)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(EXTRA_LIBS "ws2_32")
|
set(EXTRA_LIBS "ws2_32")
|
||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC "_CRT_SECURE_NO_WARNINGS")
|
target_compile_definitions(${PROJECT_NAME} PUBLIC "_CRT_SECURE_NO_WARNINGS")
|
||||||
@@ -157,6 +344,7 @@ if(PLATFORM STREQUAL "PLATFORM_WIN32" OR PLATFORM STREQUAL "PLATFORM_GLFW")
|
|||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC "PLATFORM_DESKTOP")
|
target_compile_definitions(${PROJECT_NAME} PUBLIC "PLATFORM_DESKTOP")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
"${CMAKE_SOURCE_DIR}/glad/include/"
|
"${CMAKE_SOURCE_DIR}/glad/include/"
|
||||||
"${CMAKE_SOURCE_DIR}/src"
|
"${CMAKE_SOURCE_DIR}/src"
|
||||||
@@ -165,6 +353,16 @@ target_include_directories(${PROJECT_NAME} PUBLIC
|
|||||||
"lib/include"
|
"lib/include"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Server
|
||||||
|
#target_link_libraries("${PROJECT_NAME}-server" PRIVATE
|
||||||
|
# raknet ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
#target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER")
|
||||||
|
|
||||||
|
#target_include_directories("${PROJECT_NAME}-server" PUBLIC
|
||||||
|
# "${CMAKE_SOURCE_DIR}/src/"
|
||||||
|
#)
|
||||||
|
|
||||||
|
# Client
|
||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM})
|
target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM})
|
||||||
target_link_libraries(${PROJECT_NAME} zlib png_shared alsoft.common OpenAL::OpenAL glfw ${EXTRA_LIBS})
|
target_link_libraries(${PROJECT_NAME} zlib png_shared alsoft.common OpenAL::OpenAL glfw ${EXTRA_LIBS})
|
||||||
|
|
||||||
|
|||||||
33
README.md
33
README.md
@@ -1,6 +1,6 @@
|
|||||||
# MinecraftPE
|
# MinecraftPE
|
||||||
> [!Important]
|
> [!Important]
|
||||||
> We have a discord server, where you can report bugs or send feedback https://discord.gg/ryZ884DWJf
|
> We have a discord server, where you can report bugs or send feedback https://discord.gg/c58YesBxve
|
||||||
|
|
||||||
Source code for **Minecraft Pocket Edition 0.6.1 alpha** with various fixes and improvements.
|
Source code for **Minecraft Pocket Edition 0.6.1 alpha** with various fixes and improvements.
|
||||||
|
|
||||||
@@ -32,6 +32,12 @@ mkdir build && cd build
|
|||||||
cmake .. -B .
|
cmake .. -B .
|
||||||
make -j4
|
make -j4
|
||||||
```
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake --build . --config Release -j 10
|
||||||
|
```
|
||||||
|
|
||||||
## Visual Studio
|
## Visual Studio
|
||||||
|
|
||||||
1. Open the repository folder in **Visual Studio**.
|
1. Open the repository folder in **Visual Studio**.
|
||||||
@@ -40,17 +46,28 @@ make -j4
|
|||||||
4. Press **Run** (or F5) to build and launch the game.
|
4. Press **Run** (or F5) to build and launch the game.
|
||||||
|
|
||||||
## Android
|
## Android
|
||||||
Download [r14b Android NDK](http://dl.google.com/android/repository/android-ndk-r14b-windows-x86_64.zip) and run `build.ps1`:
|
|
||||||
```
|
1. Download **Android NDK r14b**:
|
||||||
|
http://dl.google.com/android/repository/android-ndk-r14b-windows-x86_64.zip
|
||||||
|
|
||||||
|
2. Extract it to the root of your `C:` drive so the path becomes:
|
||||||
|
|
||||||
|
```
|
||||||
|
C:\android-ndk-r14b
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the build script:
|
||||||
|
|
||||||
|
```powershell
|
||||||
# Full build (NDK + Java + APK + install)
|
# Full build (NDK + Java + APK + install)
|
||||||
.\build.ps1
|
.\build.ps1
|
||||||
|
|
||||||
# Skip NDK recompile (Java/assets changed only)
|
# Skip C++ compilation (Java/assets changed only)
|
||||||
.\build.ps1 -NoJava
|
|
||||||
|
|
||||||
# Skip Java recompile (C++ changed only)
|
|
||||||
.\build.ps1 -NoCpp
|
.\build.ps1 -NoCpp
|
||||||
|
|
||||||
# Only repackage + install (no recompile at all)
|
# Skip Java compilation (C++ changed only)
|
||||||
|
.\build.ps1 -NoJava
|
||||||
|
|
||||||
|
# Only repackage + install (no compilation)
|
||||||
.\build.ps1 -NoBuild
|
.\build.ps1 -NoBuild
|
||||||
```
|
```
|
||||||
13
build.ps1
13
build.ps1
@@ -220,14 +220,15 @@ if (-not $NoCpp -and -not $NoBuild) {
|
|||||||
Write-Step "NDK build (arm64-v8a)"
|
Write-Step "NDK build (arm64-v8a)"
|
||||||
# NDK r14b on Windows hits the 32K CreateProcess limit with long paths.
|
# NDK r14b on Windows hits the 32K CreateProcess limit with long paths.
|
||||||
# Work around it by building through a short junction C:\m -> repo root.
|
# Work around it by building through a short junction C:\m -> repo root.
|
||||||
$junctionBase = "C:\m"
|
# Use forward slashes in the build paths to prevent the NDK toolchain from stripping backslashes.
|
||||||
if (-not (Test-Path $junctionBase)) {
|
$junctionBase = "C:/m"
|
||||||
& cmd.exe /c "mklink /J `"$junctionBase`" `"$repo`"" | Out-Null
|
if (-not (Test-Path "C:\m")) {
|
||||||
|
& cmd.exe /c "mklink /J `"C:\m`" `"$repo`"" | Out-Null
|
||||||
}
|
}
|
||||||
Push-Location "$junctionBase\project\android\jni"
|
Push-Location "$junctionBase/project/android/jni"
|
||||||
$env:NDK_MODULE_PATH = "$junctionBase\project\lib_projects"
|
$env:NDK_MODULE_PATH = "$junctionBase/project/lib_projects"
|
||||||
# run ndk-build and capture everything; let user see full output for debugging
|
# run ndk-build and capture everything; let user see full output for debugging
|
||||||
$ndkOutput = & "$ndk\ndk-build.cmd" NDK_PROJECT_PATH="$junctionBase\project\android" APP_BUILD_SCRIPT="$junctionBase\project\android\jni\Android.mk" 2>&1 | Tee-Object -Variable ndkOutput
|
$ndkOutput = & "$ndk\ndk-build.cmd" NDK_PROJECT_PATH="$junctionBase/project/android" APP_BUILD_SCRIPT="$junctionBase/project/android/jni/Android.mk" 2>&1 | Tee-Object -Variable ndkOutput
|
||||||
# dump entire output for diagnosis
|
# dump entire output for diagnosis
|
||||||
Write-Host "---- NDK BUILD OUTPUT BEGIN ----"
|
Write-Host "---- NDK BUILD OUTPUT BEGIN ----"
|
||||||
$ndkOutput | ForEach-Object { Write-Host $_ }
|
$ndkOutput | ForEach-Object { Write-Host $_ }
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -149,6 +149,10 @@ options.group.general=General
|
|||||||
options.group.game=Game
|
options.group.game=Game
|
||||||
options.group.controls=Controls
|
options.group.controls=Controls
|
||||||
options.group.graphics=Graphics
|
options.group.graphics=Graphics
|
||||||
|
options.group.tweaks=Tweaks
|
||||||
|
options.sprint=Sprint
|
||||||
|
options.barontop=HUD above inventory
|
||||||
|
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
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
# Convert Windows backslashes to forward slashes so NDK toolchain doesn’t treat them as escapes.
|
||||||
|
LOCAL_PATH := $(subst \,/,$(LOCAL_PATH))
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
@@ -12,6 +14,7 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
|
|||||||
../../../src/platform/input/Multitouch.cpp \
|
../../../src/platform/input/Multitouch.cpp \
|
||||||
../../../src/platform/time.cpp \
|
../../../src/platform/time.cpp \
|
||||||
../../../src/platform/CThread.cpp \
|
../../../src/platform/CThread.cpp \
|
||||||
|
../../../src/platform/HttpClient.cpp \
|
||||||
../../../src/NinecraftApp.cpp \
|
../../../src/NinecraftApp.cpp \
|
||||||
../../../src/Performance.cpp \
|
../../../src/Performance.cpp \
|
||||||
../../../src/SharedConstants.cpp \
|
../../../src/SharedConstants.cpp \
|
||||||
@@ -68,6 +71,7 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \
|
|||||||
../../../src/client/gui/screens/SelectWorldScreen.cpp \
|
../../../src/client/gui/screens/SelectWorldScreen.cpp \
|
||||||
../../../src/client/gui/screens/StartMenuScreen.cpp \
|
../../../src/client/gui/screens/StartMenuScreen.cpp \
|
||||||
../../../src/client/gui/screens/TextEditScreen.cpp \
|
../../../src/client/gui/screens/TextEditScreen.cpp \
|
||||||
|
../../../src/client/gui/screens/JoinByIPScreen.cpp \
|
||||||
../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \
|
../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \
|
||||||
../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \
|
../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \
|
||||||
../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \
|
../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ APP_PLATFORM := android-21
|
|||||||
APP_STL := gnustl_static
|
APP_STL := gnustl_static
|
||||||
APP_OPTIM := release
|
APP_OPTIM := release
|
||||||
APP_ABI := arm64-v8a
|
APP_ABI := arm64-v8a
|
||||||
|
APP_SHORT_COMMANDS := true
|
||||||
#APP_ABI := armeabi-v7a x86
|
#APP_ABI := armeabi-v7a x86
|
||||||
|
|||||||
@@ -468,17 +468,16 @@ public class MainActivity extends NativeActivity {
|
|||||||
|
|
||||||
_userInputStatus = 1;
|
_userInputStatus = 1;
|
||||||
InputMethodManager inputManager = (InputMethodManager)getSystemService("input_method");
|
InputMethodManager inputManager = (InputMethodManager)getSystemService("input_method");
|
||||||
boolean result = inputManager.showSoftInput(this.getCurrentFocus(), InputMethodManager.SHOW_IMPLICIT);
|
View focused = this.getCurrentFocus();
|
||||||
}
|
if (focused != null) {
|
||||||
|
boolean result = inputManager.showSoftInput(focused, InputMethodManager.SHOW_IMPLICIT);
|
||||||
protected void onStart() {
|
} else {
|
||||||
//System.out.println("onStart");
|
// fallback: try to show using decor view token
|
||||||
super.onStart();
|
View decor = getWindow().getDecorView();
|
||||||
}
|
if (decor != null) {
|
||||||
|
inputManager.showSoftInput(decor, InputMethodManager.SHOW_IMPLICIT);
|
||||||
protected void onResume() {
|
}
|
||||||
//System.out.println("onResume");
|
}
|
||||||
super.onResume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
|
|||||||
@@ -583,6 +583,15 @@ public class MainActivity extends Activity {
|
|||||||
return kcm.get(keyCode, metaState);
|
return kcm.get(keyCode, metaState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void openURL(String url) {
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(url));
|
||||||
|
startActivity(intent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getPlatformStringVar(int id) {
|
public String getPlatformStringVar(int id) {
|
||||||
if (id == 0) return android.os.Build.MODEL;
|
if (id == 0) return android.os.Build.MODEL;
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.7)
|
cmake_minimum_required(VERSION 3.5.0)
|
||||||
find_package (Threads)
|
find_package (Threads)
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni/RaknetSources")
|
include_directories("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni/RaknetSources")
|
||||||
add_subdirectory("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni" "${CMAKE_CURRENT_BINARY_DIR}/raknet")
|
add_subdirectory("${PROJECT_SOURCE_DIR}/../lib_projects/raknet/jni" "${CMAKE_CURRENT_BINARY_DIR}/raknet")
|
||||||
@@ -151,6 +151,9 @@ set(CompileFiles ../../src/main.cpp
|
|||||||
../../src/world/level/tile/entity/TileEntity.cpp
|
../../src/world/level/tile/entity/TileEntity.cpp
|
||||||
../../src/world/level/tile/entity/FurnaceTileEntity.cpp
|
../../src/world/level/tile/entity/FurnaceTileEntity.cpp
|
||||||
../../src/world/phys/HitResult.cpp)
|
../../src/world/phys/HitResult.cpp)
|
||||||
message(${CMAKE_LIBRARY_ARCHITECTURE})
|
|
||||||
add_executable(mcpe_server ${CompileFiles})
|
add_executable(mcpe_server ${CompileFiles})
|
||||||
target_link_libraries(mcpe_server raknet ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(mcpe_server raknet ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
target_include_directories(mcpe_server PUBLIC
|
||||||
|
"../../src/"
|
||||||
|
)
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ static const unsigned int MAX_OFFLINE_DATA_LENGTH=400; // I set this because I l
|
|||||||
#pragma warning(disable:4309) // 'initializing' : truncation of constant value
|
#pragma warning(disable:4309) // 'initializing' : truncation of constant value
|
||||||
#endif
|
#endif
|
||||||
// Make sure highest bit is 0, so isValid in DatagramHeaderFormat is false
|
// Make sure highest bit is 0, so isValid in DatagramHeaderFormat is false
|
||||||
static const char OFFLINE_MESSAGE_DATA_ID[16]={0x00,0xFF,0xFF,0x00,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFD,0xFD,0x12,0x34,0x56,0x78};
|
static const unsigned char OFFLINE_MESSAGE_DATA_ID[16]={0x00,0xFF,0xFF,0x00,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFD,0xFD,0x12,0x34,0x56,0x78};
|
||||||
|
|
||||||
struct PacketFollowedByData
|
struct PacketFollowedByData
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ public:
|
|||||||
|
|
||||||
virtual void saveScreenshot(const std::string& filename, int glWidth, int glHeight) {}
|
virtual void saveScreenshot(const std::string& filename, int glWidth, int glHeight) {}
|
||||||
virtual TextureData loadTexture(const std::string& filename_, bool textureFolder) { return TextureData(); }
|
virtual TextureData loadTexture(const std::string& filename_, bool textureFolder) { return TextureData(); }
|
||||||
|
virtual TextureData loadTextureFromMemory(const unsigned char* data, size_t size) { return TextureData(); }
|
||||||
|
|
||||||
virtual void playSound(const std::string& fn, float volume, float pitch) {}
|
virtual void playSound(const std::string& fn, float volume, float pitch) {}
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,8 @@ public:
|
|||||||
|
|
||||||
_methodGetPixelsPerMillimeter = env->GetMethodID( _activityClass, "getPixelsPerMillimeter", "()F");
|
_methodGetPixelsPerMillimeter = env->GetMethodID( _activityClass, "getPixelsPerMillimeter", "()F");
|
||||||
_methodGetPlatformStringVar = env->GetMethodID( _activityClass, "getPlatformStringVar", "(I)Ljava/lang/String;");
|
_methodGetPlatformStringVar = env->GetMethodID( _activityClass, "getPlatformStringVar", "(I)Ljava/lang/String;");
|
||||||
|
// custom helper to launch external URLs
|
||||||
|
_methodOpenURL = env->GetMethodID(_activityClass, "openURL", "(Ljava/lang/String;)V");
|
||||||
|
|
||||||
_classWindow = (jclass)env->NewGlobalRef(env->FindClass("android/view/Window"));
|
_classWindow = (jclass)env->NewGlobalRef(env->FindClass("android/view/Window"));
|
||||||
_classContext = (jclass)env->NewGlobalRef(env->FindClass("android/content/Context"));
|
_classContext = (jclass)env->NewGlobalRef(env->FindClass("android/content/Context"));
|
||||||
@@ -465,7 +467,15 @@ public:
|
|||||||
env->ReleaseStringUTFChars(stringVar, str);
|
env->ReleaseStringUTFChars(stringVar, str);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
// Opens a webpage using an Android intent. Called from native code.
|
||||||
|
virtual void openURL(const std::string& url) {
|
||||||
|
if (!_isInited || !_methodOpenURL) return;
|
||||||
|
JVMAttacher ta(_vm);
|
||||||
|
JNIEnv* env = ta.getEnv();
|
||||||
|
jstring jurl = env->NewStringUTF(url.c_str());
|
||||||
|
env->CallVoidMethod(instance, _methodOpenURL, jurl);
|
||||||
|
env->DeleteLocalRef(jurl);
|
||||||
|
}
|
||||||
virtual void finish() {
|
virtual void finish() {
|
||||||
if (!_isInited) return;
|
if (!_isInited) return;
|
||||||
if (!_methodFinish) return;
|
if (!_methodFinish) return;
|
||||||
@@ -616,6 +626,7 @@ private:
|
|||||||
jmethodID _methodIsNetworkEnabled;
|
jmethodID _methodIsNetworkEnabled;
|
||||||
|
|
||||||
jmethodID _methodGetPlatformStringVar;
|
jmethodID _methodGetPlatformStringVar;
|
||||||
|
jmethodID _methodOpenURL; // new JNI method for launching browser
|
||||||
|
|
||||||
jclass _classWindow;
|
jclass _classWindow;
|
||||||
jclass _classContext;
|
jclass _classContext;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "AppPlatform.h"
|
#include "AppPlatform.h"
|
||||||
#include "platform/log.h"
|
#include "platform/log.h"
|
||||||
|
#include "platform/HttpClient.h"
|
||||||
|
#include "platform/PngLoader.h"
|
||||||
#include "client/renderer/gles.h"
|
#include "client/renderer/gles.h"
|
||||||
#include "world/level/storage/FolderMethods.h"
|
#include "world/level/storage/FolderMethods.h"
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
@@ -11,6 +13,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include "util/StringUtils.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -55,10 +58,19 @@ public:
|
|||||||
|
|
||||||
TextureData loadTexture(const std::string& filename_, bool textureFolder)
|
TextureData loadTexture(const std::string& filename_, bool textureFolder)
|
||||||
{
|
{
|
||||||
|
// Support fetching PNG textures via HTTP/HTTPS (for skins, etc)
|
||||||
|
if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) {
|
||||||
|
std::vector<unsigned char> body;
|
||||||
|
if (HttpClient::download(filename_, body) && !body.empty()) {
|
||||||
|
return loadTextureFromMemory(body.data(), body.size());
|
||||||
|
}
|
||||||
|
return TextureData();
|
||||||
|
}
|
||||||
|
|
||||||
TextureData out;
|
TextureData out;
|
||||||
|
|
||||||
std::string filename = textureFolder? "data/images/" + filename_
|
std::string filename = textureFolder? "data/images/" + filename_
|
||||||
: filename_;
|
: filename_;
|
||||||
std::ifstream source(filename.c_str(), std::ios::binary);
|
std::ifstream source(filename.c_str(), std::ios::binary);
|
||||||
|
|
||||||
if (source) {
|
if (source) {
|
||||||
@@ -107,7 +119,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getDateString(int s) {
|
TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override {
|
||||||
|
return loadPngFromMemory(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string getDateString(int s) override {
|
||||||
time_t tm = s;
|
time_t tm = s;
|
||||||
|
|
||||||
char mbstr[100];
|
char mbstr[100];
|
||||||
|
|||||||
@@ -3,8 +3,11 @@
|
|||||||
|
|
||||||
#include "AppPlatform.h"
|
#include "AppPlatform.h"
|
||||||
#include "platform/log.h"
|
#include "platform/log.h"
|
||||||
|
#include "platform/HttpClient.h"
|
||||||
|
#include "platform/PngLoader.h"
|
||||||
#include "client/renderer/gles.h"
|
#include "client/renderer/gles.h"
|
||||||
#include "world/level/storage/FolderMethods.h"
|
#include "world/level/storage/FolderMethods.h"
|
||||||
|
#include "util/StringUtils.h"
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -50,10 +53,19 @@ public:
|
|||||||
|
|
||||||
TextureData loadTexture(const std::string& filename_, bool textureFolder)
|
TextureData loadTexture(const std::string& filename_, bool textureFolder)
|
||||||
{
|
{
|
||||||
|
// Support fetching PNG textures via HTTP/HTTPS (for skins, etc).
|
||||||
|
if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) {
|
||||||
|
std::vector<unsigned char> body;
|
||||||
|
if (HttpClient::download(filename_, body) && !body.empty()) {
|
||||||
|
return loadTextureFromMemory(body.data(), body.size());
|
||||||
|
}
|
||||||
|
return TextureData();
|
||||||
|
}
|
||||||
|
|
||||||
TextureData out;
|
TextureData out;
|
||||||
|
|
||||||
std::string filename = textureFolder? "data/images/" + filename_
|
std::string filename = textureFolder? "data/images/" + filename_
|
||||||
: filename_;
|
: filename_;
|
||||||
std::ifstream source(filename.c_str(), std::ios::binary);
|
std::ifstream source(filename.c_str(), std::ios::binary);
|
||||||
|
|
||||||
if (source) {
|
if (source) {
|
||||||
@@ -102,7 +114,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getDateString(int s) {
|
TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override {
|
||||||
|
return loadPngFromMemory(data, size);
|
||||||
|
}
|
||||||
time_t tm = s;
|
time_t tm = s;
|
||||||
|
|
||||||
char mbstr[100];
|
char mbstr[100];
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
#include "Minecraft.h"
|
#include "Minecraft.h"
|
||||||
#include "client/player/input/IBuildInput.h"
|
#include "client/player/input/IBuildInput.h"
|
||||||
|
#include "platform/input/Keyboard.h"
|
||||||
|
#include "world/item/Item.h"
|
||||||
|
#include "world/item/ItemInstance.h"
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#if defined(APPLE_DEMO_PROMOTION)
|
#if defined(APPLE_DEMO_PROMOTION)
|
||||||
#define NO_NETWORK
|
#define NO_NETWORK
|
||||||
@@ -8,7 +13,6 @@
|
|||||||
#if defined(RPI)
|
#if defined(RPI)
|
||||||
#define CREATORMODE
|
#define CREATORMODE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../network/RakNetInstance.h"
|
#include "../network/RakNetInstance.h"
|
||||||
#include "../network/ClientSideNetworkHandler.h"
|
#include "../network/ClientSideNetworkHandler.h"
|
||||||
#include "../network/ServerSideNetworkHandler.h"
|
#include "../network/ServerSideNetworkHandler.h"
|
||||||
@@ -56,6 +60,7 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "renderer/Chunk.h"
|
||||||
#include "player/input/MouseTurnInput.h"
|
#include "player/input/MouseTurnInput.h"
|
||||||
#include "../world/entity/MobFactory.h"
|
#include "../world/entity/MobFactory.h"
|
||||||
#include "../world/level/MobSpawner.h"
|
#include "../world/level/MobSpawner.h"
|
||||||
@@ -112,7 +117,7 @@ static void checkGlError(const char* tag) {
|
|||||||
}
|
}
|
||||||
#endif /*GLDEBUG*/
|
#endif /*GLDEBUG*/
|
||||||
}
|
}
|
||||||
|
#include <fstream>
|
||||||
/*static*/
|
/*static*/
|
||||||
const char* Minecraft::progressMessages[] = {
|
const char* Minecraft::progressMessages[] = {
|
||||||
"Locating server",
|
"Locating server",
|
||||||
@@ -450,20 +455,21 @@ void Minecraft::update() {
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (pause && level != NULL) {
|
// If we're paused (local world / invisible server), freeze gameplay and
|
||||||
float lastA = timer.a;
|
// networking and only keep UI responsive.
|
||||||
timer.advanceTime();
|
bool freezeGame = pause;
|
||||||
timer.a = lastA;
|
|
||||||
} else {
|
if (!freezeGame) {
|
||||||
timer.advanceTime();
|
timer.advanceTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raknetInstance) {
|
if (raknetInstance && !freezeGame) {
|
||||||
raknetInstance->runEvents(netCallback);
|
raknetInstance->runEvents(netCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
TIMER_PUSH("tick");
|
TIMER_PUSH("tick");
|
||||||
int toTick = timer.ticks;
|
int toTick = freezeGame ? 1 : timer.ticks;
|
||||||
|
if (!freezeGame) timer.ticks = 0;
|
||||||
for (int i = 0; i < toTick; ++i, ++ticks)
|
for (int i = 0; i < toTick; ++i, ++ticks)
|
||||||
tick(i, toTick-1);
|
tick(i, toTick-1);
|
||||||
|
|
||||||
@@ -588,7 +594,9 @@ void Minecraft::tick(int nTick, int maxTick) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
TIMER_POP_PUSH("particles");
|
TIMER_POP_PUSH("particles");
|
||||||
particleEngine->tick();
|
if (!pause) {
|
||||||
|
particleEngine->tick();
|
||||||
|
}
|
||||||
if (screen) {
|
if (screen) {
|
||||||
screenMutex = true;
|
screenMutex = true;
|
||||||
screen->tick();
|
screen->tick();
|
||||||
@@ -722,16 +730,29 @@ void Minecraft::tickInput() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(PLATFORM_DESKTOP)
|
#if defined(PLATFORM_DESKTOP)
|
||||||
|
if (key == Keyboard::KEY_LEFT_CTRL) {
|
||||||
|
player->setSprinting(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (key == Keyboard::KEY_E) {
|
if (key == Keyboard::KEY_E) {
|
||||||
screenChooser.setScreen(SCREEN_BLOCKSELECTION);
|
screenChooser.setScreen(SCREEN_BLOCKSELECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!screen && key == Keyboard::KEY_T && level) {
|
if (!screen && key == Keyboard::KEY_T && level) {
|
||||||
setScreen(new ConsoleScreen());
|
setScreen(new ConsoleScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!screen && key == Keyboard::KEY_O || key == 250) {
|
if (!screen && key == Keyboard::KEY_O || key == 250) {
|
||||||
releaseMouse();
|
releaseMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key == Keyboard::KEY_F)
|
||||||
|
options.viewDistance = (options.viewDistance + 1) % 4;
|
||||||
|
|
||||||
|
if (key == Keyboard::KEY_F3) {
|
||||||
|
options.renderDebug = !options.renderDebug;
|
||||||
|
}
|
||||||
|
|
||||||
if (key == Keyboard::KEY_F5) {
|
if (key == Keyboard::KEY_F5) {
|
||||||
options.toggle(OPTIONS_THIRD_PERSON_VIEW);
|
options.toggle(OPTIONS_THIRD_PERSON_VIEW);
|
||||||
/*
|
/*
|
||||||
@@ -740,12 +761,6 @@ void Minecraft::tickInput() {
|
|||||||
printf("%d\t%f\n", i, noise.grad2(i, 3, 8));
|
printf("%d\t%f\n", i, noise.grad2(i, 3, 8));
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if defined(WIN32)
|
|
||||||
if (key == Keyboard::KEY_F) {
|
|
||||||
options.isFlying = !options.isFlying;
|
|
||||||
player->noPhysics = options.isFlying;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (key == Keyboard::KEY_L)
|
if (key == Keyboard::KEY_L)
|
||||||
@@ -819,9 +834,6 @@ void Minecraft::tickInput() {
|
|||||||
if (player->inventory->getItem(i))
|
if (player->inventory->getItem(i))
|
||||||
player->inventory->dropSlot(i, false);
|
player->inventory->dropSlot(i, false);
|
||||||
}
|
}
|
||||||
if (key == Keyboard::KEY_F3) {
|
|
||||||
options.renderDebug = !options.renderDebug;
|
|
||||||
}
|
|
||||||
if (key == Keyboard::KEY_M) {
|
if (key == Keyboard::KEY_M) {
|
||||||
options.difficulty = (options.difficulty == Difficulty::PEACEFUL)?
|
options.difficulty = (options.difficulty == Difficulty::PEACEFUL)?
|
||||||
Difficulty::NORMAL : Difficulty::PEACEFUL;
|
Difficulty::NORMAL : Difficulty::PEACEFUL;
|
||||||
@@ -1017,6 +1029,17 @@ bool Minecraft::isOnline()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Minecraft::pauseGame(bool isBackPaused) {
|
void Minecraft::pauseGame(bool isBackPaused) {
|
||||||
|
// Only freeze gameplay when running a local server and it is not accepting
|
||||||
|
// incoming connections (invisible server), which includes typical single-
|
||||||
|
// player/lobby mode. If the server is visible, the game should keep ticking.
|
||||||
|
bool canFreeze = false;
|
||||||
|
if (raknetInstance && raknetInstance->isServer() && netCallback) {
|
||||||
|
ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback;
|
||||||
|
if (!ss->allowsIncomingConnections())
|
||||||
|
canFreeze = true;
|
||||||
|
}
|
||||||
|
pause = canFreeze;
|
||||||
|
|
||||||
#ifndef STANDALONE_SERVER
|
#ifndef STANDALONE_SERVER
|
||||||
if (screen != NULL) return;
|
if (screen != NULL) return;
|
||||||
screenChooser.setScreen(isBackPaused? SCREEN_PAUSEPREV : SCREEN_PAUSE);
|
screenChooser.setScreen(isBackPaused? SCREEN_PAUSEPREV : SCREEN_PAUSE);
|
||||||
@@ -1069,6 +1092,8 @@ void Minecraft::setScreen( Screen* screen )
|
|||||||
|
|
||||||
//noRender = false;
|
//noRender = false;
|
||||||
} else {
|
} else {
|
||||||
|
// Closing a screen and returning to the game should unpause.
|
||||||
|
pause = false;
|
||||||
grabMouse();
|
grabMouse();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1288,6 +1313,31 @@ bool Minecraft::joinMultiplayer( const PingedCompatibleServer& server )
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Minecraft::joinMultiplayerFromString( const std::string& server )
|
||||||
|
{
|
||||||
|
std::string ip = "";
|
||||||
|
std::string port = "19132";
|
||||||
|
|
||||||
|
size_t pos = server.find(":");
|
||||||
|
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
ip = server.substr(0, pos);
|
||||||
|
port = server.substr(pos + 1);
|
||||||
|
} else {
|
||||||
|
ip = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s \n", port.c_str());
|
||||||
|
|
||||||
|
if (isLookingForMultiplayer && netCallback) {
|
||||||
|
isLookingForMultiplayer = false;
|
||||||
|
printf("test");
|
||||||
|
int portNum = atoi(port.c_str());
|
||||||
|
return raknetInstance->connect(ip.c_str(), portNum);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Minecraft::hostMultiplayer(int port) {
|
void Minecraft::hostMultiplayer(int port) {
|
||||||
// Tear down last instance
|
// Tear down last instance
|
||||||
raknetInstance->disconnect();
|
raknetInstance->disconnect();
|
||||||
@@ -1455,6 +1505,12 @@ LevelStorageSource* Minecraft::getLevelSource()
|
|||||||
return storageSource;
|
return storageSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int Minecraft::getLicenseId() {
|
||||||
|
// if (!LicenseCodes::isReady(_licenseId))
|
||||||
|
// _licenseId = platform()->checkLicense();
|
||||||
|
// return _licenseId;
|
||||||
|
// }
|
||||||
|
|
||||||
void Minecraft::audioEngineOn() {
|
void Minecraft::audioEngineOn() {
|
||||||
#ifndef STANDALONE_SERVER
|
#ifndef STANDALONE_SERVER
|
||||||
soundEngine->enable(true);
|
soundEngine->enable(true);
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public:
|
|||||||
void locateMultiplayer();
|
void locateMultiplayer();
|
||||||
void cancelLocateMultiplayer();
|
void cancelLocateMultiplayer();
|
||||||
bool joinMultiplayer(const PingedCompatibleServer& server);
|
bool joinMultiplayer(const PingedCompatibleServer& server);
|
||||||
|
bool joinMultiplayerFromString(const std::string& server);
|
||||||
void hostMultiplayer(int port=19132);
|
void hostMultiplayer(int port=19132);
|
||||||
Player* respawnPlayer(int playerId);
|
Player* respawnPlayer(int playerId);
|
||||||
void respawnPlayer();
|
void respawnPlayer();
|
||||||
|
|||||||
@@ -6,14 +6,19 @@ const char* OptionStrings::Multiplayer_ServerVisible = "mp_server_visible_defa
|
|||||||
const char* OptionStrings::Graphics_Fancy = "gfx_fancygraphics";
|
const char* OptionStrings::Graphics_Fancy = "gfx_fancygraphics";
|
||||||
const char* OptionStrings::Graphics_LowQuality = "gfx_lowquality";
|
const char* OptionStrings::Graphics_LowQuality = "gfx_lowquality";
|
||||||
const char* OptionStrings::Graphics_Vsync = "gfx_vsync";
|
const char* OptionStrings::Graphics_Vsync = "gfx_vsync";
|
||||||
const char* OptionStrings::Graphics_GUIScale = "gfx_guiscale";
|
const char* OptionStrings::Graphics_GUIScale = "gfx_guiscale";
|
||||||
|
const char* OptionStrings::Graphics_SmoothLightning = "gfx_smoothlightning";
|
||||||
|
const char* OptionStrings::Graphics_Anaglyph = "gfx_anaglyph";
|
||||||
|
const char* OptionStrings::Graphics_ViewBobbing = "gfx_viewbobbing";
|
||||||
|
|
||||||
const char* OptionStrings::Controls_Sensitivity = "ctrl_sensitivity";
|
const char* OptionStrings::Controls_Sensitivity = "ctrl_sensitivity";
|
||||||
const char* OptionStrings::Controls_InvertMouse = "ctrl_invertmouse";
|
const char* OptionStrings::Controls_InvertMouse = "ctrl_invertmouse";
|
||||||
const char* OptionStrings::Controls_UseTouchScreen = "ctrl_usetouchscreen";
|
const char* OptionStrings::Controls_UseTouchScreen = "ctrl_usetouchscreen";
|
||||||
const char* OptionStrings::Controls_UseTouchJoypad = "ctrl_usetouchjoypad";
|
const char* OptionStrings::Controls_UseTouchJoypad = "ctrl_usetouchjoypad";
|
||||||
const char* OptionStrings::Controls_IsLefthanded = "ctrl_islefthanded";
|
const char* OptionStrings::Controls_IsLefthanded = "ctrl_islefthanded";
|
||||||
|
// why it isnt ctrl_feedback_vibration? i dont want touch it because compatibility with older versions
|
||||||
const char* OptionStrings::Controls_FeedbackVibration = "feedback_vibration";
|
const char* OptionStrings::Controls_FeedbackVibration = "feedback_vibration";
|
||||||
|
const char* OptionStrings::Controls_AutoJump = "ctrl_autojump";
|
||||||
|
|
||||||
const char* OptionStrings::Game_DifficultyLevel = "game_difficulty";
|
const char* OptionStrings::Game_DifficultyLevel = "game_difficulty";
|
||||||
|
|
||||||
|
|||||||
@@ -10,14 +10,27 @@ public:
|
|||||||
static const char* Graphics_LowQuality;
|
static const char* Graphics_LowQuality;
|
||||||
static const char* Graphics_GUIScale;
|
static const char* Graphics_GUIScale;
|
||||||
static const char* Graphics_Vsync;
|
static const char* Graphics_Vsync;
|
||||||
|
static const char* Graphics_SmoothLightning;
|
||||||
|
static const char* Graphics_Anaglyph;
|
||||||
|
static const char* Graphics_ViewBobbing;
|
||||||
|
|
||||||
static const char* Controls_Sensitivity;
|
static const char* Controls_Sensitivity;
|
||||||
static const char* Controls_InvertMouse;
|
static const char* Controls_InvertMouse;
|
||||||
static const char* Controls_UseTouchScreen;
|
static const char* Controls_UseTouchScreen;
|
||||||
static const char* Controls_UseTouchJoypad;
|
static const char* Controls_UseTouchJoypad;
|
||||||
static const char* Controls_IsLefthanded;
|
static const char* Controls_IsLefthanded;
|
||||||
static const char* Controls_FeedbackVibration;
|
static const char* Controls_FeedbackVibration;
|
||||||
|
static const char* Controls_AutoJump;
|
||||||
|
|
||||||
|
static const char* Audio_Music;
|
||||||
|
static const char* Audio_Sound;
|
||||||
|
|
||||||
|
|
||||||
static const char* Game_DifficultyLevel;
|
static const char* Game_DifficultyLevel;
|
||||||
|
|
||||||
|
static const char* Tweaks_Sprint;
|
||||||
|
static const char* Tweaks_BarOnTop;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*NET_MINECRAFT_CLIENT__OptionsStrings_H__*/
|
#endif /*NET_MINECRAFT_CLIENT__OptionsStrings_H__*/
|
||||||
|
|||||||
@@ -13,10 +13,10 @@
|
|||||||
#include "../../network/packet/RemoveBlockPacket.h"
|
#include "../../network/packet/RemoveBlockPacket.h"
|
||||||
#include "../../world/entity/player/Abilities.h"
|
#include "../../world/entity/player/Abilities.h"
|
||||||
|
|
||||||
static const int DestructionTickDelay = 10;
|
static const int DestructionTickDelay = 5;
|
||||||
|
|
||||||
CreativeMode::CreativeMode(Minecraft* minecraft)
|
CreativeMode::CreativeMode(Minecraft* minecraft)
|
||||||
: super(minecraft)
|
: super(minecraft)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,12 +29,8 @@ void CreativeMode::startDestroyBlock(int x, int y, int z, int face) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) {
|
void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) {
|
||||||
//if (!
|
minecraft->level->extinguishFire(x, y, z, face);
|
||||||
minecraft->level->extinguishFire(x, y, z, face)
|
destroyBlock(x, y, z, face);
|
||||||
//{
|
|
||||||
;
|
|
||||||
destroyBlock(x, y, z, face);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
|
void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
|
||||||
@@ -46,6 +42,7 @@ void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CreativeMode::stopDestroyBlock() {
|
void CreativeMode::stopDestroyBlock() {
|
||||||
|
destroyDelay = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreativeMode::initAbilities( Abilities& abilities ) {
|
void CreativeMode::initAbilities( Abilities& abilities ) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "../../network/packet/RemoveBlockPacket.h"
|
#include "../../network/packet/RemoveBlockPacket.h"
|
||||||
#include "../../world/entity/player/Abilities.h"
|
#include "../../world/entity/player/Abilities.h"
|
||||||
|
|
||||||
static const int DestructionTickDelay = 10;
|
static const int DestructionTickDelay = 5;
|
||||||
|
|
||||||
class Creator: public ICreator {
|
class Creator: public ICreator {
|
||||||
//virtual void getEvents();
|
//virtual void getEvents();
|
||||||
@@ -60,12 +60,8 @@ void CreatorMode::startDestroyBlock(int x, int y, int z, int face) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CreatorMode::CreatorDestroyBlock(int x, int y, int z, int face) {
|
void CreatorMode::CreatorDestroyBlock(int x, int y, int z, int face) {
|
||||||
//if (!
|
minecraft->level->extinguishFire(x, y, z, face);
|
||||||
minecraft->level->extinguishFire(x, y, z, face)
|
destroyBlock(x, y, z, face);
|
||||||
//{
|
|
||||||
;
|
|
||||||
destroyBlock(x, y, z, face);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatorMode::continueDestroyBlock(int x, int y, int z, int face) {
|
void CreatorMode::continueDestroyBlock(int x, int y, int z, int face) {
|
||||||
@@ -83,6 +79,7 @@ bool CreatorMode::useItemOn( Player* player, Level* level, ItemInstance* item, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CreatorMode::stopDestroyBlock() {
|
void CreatorMode::stopDestroyBlock() {
|
||||||
|
destroyDelay = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatorMode::initAbilities( Abilities& abilities ) {
|
void CreatorMode::initAbilities( Abilities& abilities ) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "Gui.h"
|
#include "Gui.h"
|
||||||
#include "Font.h"
|
#include "Font.h"
|
||||||
#include "client/Options.h"
|
#include "client/Options.h"
|
||||||
|
#include "platform/input/Keyboard.h"
|
||||||
#include "screens/IngameBlockSelectionScreen.h"
|
#include "screens/IngameBlockSelectionScreen.h"
|
||||||
#include "../Minecraft.h"
|
#include "../Minecraft.h"
|
||||||
#include "../player/LocalPlayer.h"
|
#include "../player/LocalPlayer.h"
|
||||||
@@ -87,14 +88,16 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
|
|||||||
// F: 3
|
// F: 3
|
||||||
int ySlot = screenHeight - 16 - 3;
|
int ySlot = screenHeight - 16 - 3;
|
||||||
|
|
||||||
if (minecraft->gameMode->canHurtPlayer()) {
|
if (!minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
|
||||||
minecraft->textures->loadAndBindTexture("gui/icons.png");
|
if (minecraft->gameMode->canHurtPlayer()) {
|
||||||
Tesselator& t = Tesselator::instance;
|
minecraft->textures->loadAndBindTexture("gui/icons.png");
|
||||||
t.beginOverride();
|
Tesselator& t = Tesselator::instance;
|
||||||
t.colorABGR(0xffffffff);
|
t.beginOverride();
|
||||||
renderHearts();
|
t.colorABGR(0xffffffff);
|
||||||
renderBubbles();
|
renderHearts();
|
||||||
t.endOverrideAndDraw();
|
renderBubbles();
|
||||||
|
t.endOverrideAndDraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(minecraft->player->getSleepTimer() > 0) {
|
if(minecraft->player->getSleepTimer() > 0) {
|
||||||
@@ -106,7 +109,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
|
|||||||
glEnable(GL_ALPHA_TEST);
|
glEnable(GL_ALPHA_TEST);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
if (!minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
|
||||||
renderToolBar(a, ySlot, screenWidth);
|
renderToolBar(a, ySlot, screenWidth);
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
@@ -122,6 +125,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
|
|||||||
if (minecraft->options.getBooleanValue(OPTIONS_RENDER_DEBUG))
|
if (minecraft->options.getBooleanValue(OPTIONS_RENDER_DEBUG))
|
||||||
renderDebugInfo();
|
renderDebugInfo();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glEnable2(GL_ALPHA_TEST);
|
glEnable2(GL_ALPHA_TEST);
|
||||||
@@ -201,6 +205,10 @@ void Gui::handleClick(int button, int x, int y) {
|
|||||||
|
|
||||||
void Gui::handleKeyPressed(int key)
|
void Gui::handleKeyPressed(int key)
|
||||||
{
|
{
|
||||||
|
if (key == Keyboard::KEY_F1) {
|
||||||
|
minecraft->options.toggle(OPTIONS_HIDEGUI);
|
||||||
|
}
|
||||||
|
|
||||||
if (key == 99)
|
if (key == 99)
|
||||||
{
|
{
|
||||||
if (minecraft->player->inventory->selected > 0)
|
if (minecraft->player->inventory->selected > 0)
|
||||||
@@ -516,7 +524,8 @@ void Gui::renderProgressIndicator( const bool isTouchInterface, const int screen
|
|||||||
ItemInstance* currentItem = minecraft->player->inventory->getSelected();
|
ItemInstance* currentItem = minecraft->player->inventory->getSelected();
|
||||||
bool bowEquipped = currentItem != NULL ? currentItem->getItem() == Item::bow : false;
|
bool bowEquipped = currentItem != NULL ? currentItem->getItem() == Item::bow : false;
|
||||||
bool itemInUse = currentItem != NULL ? currentItem->getItem() == minecraft->player->getUseItem()->getItem() : false;
|
bool itemInUse = currentItem != NULL ? currentItem->getItem() == minecraft->player->getUseItem()->getItem() : false;
|
||||||
if (!isTouchInterface || minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA) || (bowEquipped && itemInUse)) {
|
if ((!isTouchInterface || minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA)
|
||||||
|
|| (bowEquipped && itemInUse)) && !minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
|
||||||
minecraft->textures->loadAndBindTexture("gui/icons.png");
|
minecraft->textures->loadAndBindTexture("gui/icons.png");
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
||||||
@@ -585,11 +594,14 @@ void Gui::renderHearts() {
|
|||||||
int oh = minecraft->player->lastHealth;
|
int oh = minecraft->player->lastHealth;
|
||||||
random.setSeed(tickCount * 312871);
|
random.setSeed(tickCount * 312871);
|
||||||
|
|
||||||
int xx = 2;//screenWidth / 2 - getNumSlots() * 10;
|
int screenWidth = (int)(minecraft->width * InvGuiScale);
|
||||||
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
||||||
|
|
||||||
|
int xx = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenWidth / 2 - getNumSlots() * 10 - 1 : 2;
|
||||||
|
|
||||||
int armor = minecraft->player->getArmorValue();
|
int armor = minecraft->player->getArmorValue();
|
||||||
for (int i = 0; i < Player::MAX_HEALTH / 2; i++) {
|
for (int i = 0; i < Player::MAX_HEALTH / 2; i++) {
|
||||||
int yo = 2;
|
int yo = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenHeight - 32 : 2;
|
||||||
int ip2 = i + i + 1;
|
int ip2 = i + i + 1;
|
||||||
|
|
||||||
if (armor > 0) {
|
if (armor > 0) {
|
||||||
@@ -617,11 +629,15 @@ void Gui::renderHearts() {
|
|||||||
|
|
||||||
void Gui::renderBubbles() {
|
void Gui::renderBubbles() {
|
||||||
if (minecraft->player->isUnderLiquid(Material::water)) {
|
if (minecraft->player->isUnderLiquid(Material::water)) {
|
||||||
int yo = 12;
|
int screenWidth = (int)(minecraft->width * InvGuiScale);
|
||||||
|
int screenHeight = (int)(minecraft->height * InvGuiScale);
|
||||||
|
|
||||||
|
int xx = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenWidth / 2 - getNumSlots() * 10 - 1 : 2;
|
||||||
|
int yo = (minecraft->options.getBooleanValue(OPTIONS_BAR_ON_TOP)) ? screenHeight - 42 : 12;
|
||||||
int count = (int) std::ceil((minecraft->player->airSupply - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY);
|
int count = (int) std::ceil((minecraft->player->airSupply - 2) * 10.0f / Player::TOTAL_AIR_SUPPLY);
|
||||||
int extra = (int) std::ceil((minecraft->player->airSupply) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count;
|
int extra = (int) std::ceil((minecraft->player->airSupply) * 10.0f / Player::TOTAL_AIR_SUPPLY) - count;
|
||||||
for (int i = 0; i < count + extra; i++) {
|
for (int i = 0; i < count + extra; i++) {
|
||||||
int xo = i * 8 + 2;
|
int xo = i * 8 + xx;
|
||||||
if (i < count) blit(xo, yo, 16, 9 * 2, 9, 9);
|
if (i < count) blit(xo, yo, 16, 9 * 2, 9, 9);
|
||||||
else blit(xo, yo, 16 + 9, 9 * 2, 9, 9);
|
else blit(xo, yo, 16 + 9, 9 * 2, 9, 9);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,14 @@ void Screen::updateEvents()
|
|||||||
void Screen::mouseEvent()
|
void Screen::mouseEvent()
|
||||||
{
|
{
|
||||||
const MouseAction& e = Mouse::getEvent();
|
const MouseAction& e = Mouse::getEvent();
|
||||||
|
// forward wheel events to subclasses
|
||||||
|
if (e.action == MouseAction::ACTION_WHEEL) {
|
||||||
|
int xm = e.x * width / minecraft->width;
|
||||||
|
int ym = e.y * height / minecraft->height - 1;
|
||||||
|
mouseWheel(e.dx, e.dy, xm, ym);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!e.isButton())
|
if (!e.isButton())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ protected:
|
|||||||
virtual void mouseClicked(int x, int y, int buttonNum);
|
virtual void mouseClicked(int x, int y, int buttonNum);
|
||||||
virtual void mouseReleased(int x, int y, int buttonNum);
|
virtual void mouseReleased(int x, int y, int buttonNum);
|
||||||
|
|
||||||
|
// mouse wheel movement (dx/dy are wheel deltas, xm/ym are GUI coords)
|
||||||
|
virtual void mouseWheel(int dx, int dy, int xm, int ym) {}
|
||||||
|
|
||||||
virtual void keyPressed(int eventKey);
|
virtual void keyPressed(int eventKey);
|
||||||
virtual void charPressed(char inputChar);
|
virtual void charPressed(char inputChar);
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -548,6 +548,14 @@ void ScrollingPane::stepThroughDecelerationAnimation(bool noAnimation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScrollingPane::scrollBy(float dx, float dy) {
|
||||||
|
// adjust the translation offsets fpx/fpy by the requested amount
|
||||||
|
float nfpx = fpx + dx;
|
||||||
|
float nfpy = fpy + dy;
|
||||||
|
// convert back to content offset (fpx = -contentOffset.x)
|
||||||
|
setContentOffset(Vec3(-nfpx, -nfpy, 0));
|
||||||
|
}
|
||||||
|
|
||||||
void ScrollingPane::setContentOffset(float x, float y) {
|
void ScrollingPane::setContentOffset(float x, float y) {
|
||||||
this->setContentOffsetWithAnimation(Vec3(x, y, 0), false);
|
this->setContentOffsetWithAnimation(Vec3(x, y, 0), false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ public:
|
|||||||
void tick();
|
void tick();
|
||||||
void render(int xm, int ym, float alpha);
|
void render(int xm, int ym, float alpha);
|
||||||
|
|
||||||
|
// scroll the content by the given amount (dx horizontal, dy vertical)
|
||||||
|
// positive values move content downward/rightward
|
||||||
|
void scrollBy(float dx, float dy);
|
||||||
|
|
||||||
bool getGridItemFor_slow(int itemIndex, GridItem& out);
|
bool getGridItemFor_slow(int itemIndex, GridItem& out);
|
||||||
|
|
||||||
void setSelected(int id, bool selected);
|
void setSelected(int id, bool selected);
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ void CreditsScreen::init() {
|
|||||||
_lines.push_back("InviseDivine");
|
_lines.push_back("InviseDivine");
|
||||||
_lines.push_back("Kolyah35");
|
_lines.push_back("Kolyah35");
|
||||||
_lines.push_back("");
|
_lines.push_back("");
|
||||||
_lines.push_back("[Gold]Join our Discord server:[/Gold] [Green]url.....[/Green]");
|
// avoid color tags around the URL so it isn't mangled by the parser please
|
||||||
|
_lines.push_back("Join our Discord server: https://discord.gg/c58YesBxve");
|
||||||
_scrollSpeed = 0.5f;
|
_scrollSpeed = 0.5f;
|
||||||
_scrollY = height; // start below screen
|
_scrollY = height; // start below screen
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,25 @@ void IngameBlockSelectionScreen::keyPressed(int eventKey)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// wheel support for creative inventory; scroll moves selection vertically
|
||||||
|
void IngameBlockSelectionScreen::mouseWheel(int dx, int dy, int xm, int ym)
|
||||||
|
{
|
||||||
|
if (dy == 0) return;
|
||||||
|
// just move selection up/down one row; desktop UI doesn't have a pane
|
||||||
|
int cols = InventoryCols;
|
||||||
|
int maxIndex = InventorySize - 1;
|
||||||
|
int idx = selectedItem;
|
||||||
|
if (dy > 0) {
|
||||||
|
// wheel up -> previous row
|
||||||
|
if (idx >= cols) idx -= cols;
|
||||||
|
} else {
|
||||||
|
// wheel down -> next row
|
||||||
|
if (idx + cols <= maxIndex) idx += cols;
|
||||||
|
}
|
||||||
|
selectedItem = idx;
|
||||||
|
}
|
||||||
|
|
||||||
int IngameBlockSelectionScreen::getSelectedSlot(int x, int y)
|
int IngameBlockSelectionScreen::getSelectedSlot(int x, int y)
|
||||||
{
|
{
|
||||||
int left = width / 2 - InventoryCols * 10;
|
int left = width / 2 - InventoryCols * 10;
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ protected:
|
|||||||
|
|
||||||
virtual void buttonClicked(Button* button);
|
virtual void buttonClicked(Button* button);
|
||||||
|
|
||||||
|
// wheel input for creative inventory scrolling
|
||||||
|
virtual void mouseWheel(int dx, int dy, int xm, int ym) override;
|
||||||
|
|
||||||
virtual void keyPressed(int eventKey);
|
virtual void keyPressed(int eventKey);
|
||||||
private:
|
private:
|
||||||
void renderSlots();
|
void renderSlots();
|
||||||
|
|||||||
140
src/client/gui/screens/JoinByIPScreen.cpp
Normal file
140
src/client/gui/screens/JoinByIPScreen.cpp
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include "JoinByIPScreen.h"
|
||||||
|
|
||||||
|
#include "JoinGameScreen.h"
|
||||||
|
#include "StartMenuScreen.h"
|
||||||
|
#include "ProgressScreen.h"
|
||||||
|
#include "../Font.h"
|
||||||
|
#include "../../../network/RakNetInstance.h"
|
||||||
|
#include "client/gui/components/TextBox.h"
|
||||||
|
#include "network/ClientSideNetworkHandler.h"
|
||||||
|
|
||||||
|
JoinByIPScreen::JoinByIPScreen() :
|
||||||
|
tIP(0, "Server IP"),
|
||||||
|
bHeader(1, "Join on server"),
|
||||||
|
bJoin( 2, "Join Game"),
|
||||||
|
bBack( 3, "")
|
||||||
|
{
|
||||||
|
bJoin.active = false;
|
||||||
|
//gamesList->yInertia = 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
JoinByIPScreen::~JoinByIPScreen()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinByIPScreen::buttonClicked(Button* button)
|
||||||
|
{
|
||||||
|
if (button->id == bJoin.id)
|
||||||
|
{
|
||||||
|
minecraft->isLookingForMultiplayer = true;
|
||||||
|
minecraft->netCallback = new ClientSideNetworkHandler(minecraft, minecraft->raknetInstance);
|
||||||
|
|
||||||
|
minecraft->joinMultiplayerFromString(tIP.text);
|
||||||
|
{
|
||||||
|
|
||||||
|
bJoin.active = false;
|
||||||
|
bBack.active = false;
|
||||||
|
minecraft->setScreen(new ProgressScreen());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (button->id == bBack.id)
|
||||||
|
{
|
||||||
|
minecraft->cancelLocateMultiplayer();
|
||||||
|
minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JoinByIPScreen::handleBackEvent(bool isDown)
|
||||||
|
{
|
||||||
|
if (!isDown)
|
||||||
|
{
|
||||||
|
minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinByIPScreen::tick()
|
||||||
|
{
|
||||||
|
bJoin.active = !tIP.text.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinByIPScreen::init()
|
||||||
|
{
|
||||||
|
ImageDef def;
|
||||||
|
def.name = "gui/touchgui.png";
|
||||||
|
def.width = 34;
|
||||||
|
def.height = 26;
|
||||||
|
|
||||||
|
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
|
||||||
|
bBack.setImageDef(def, true);
|
||||||
|
|
||||||
|
buttons.push_back(&bJoin);
|
||||||
|
buttons.push_back(&bBack);
|
||||||
|
buttons.push_back(&bHeader);
|
||||||
|
|
||||||
|
textBoxes.push_back(&tIP);
|
||||||
|
#ifdef ANDROID
|
||||||
|
tabButtons.push_back(&bJoin);
|
||||||
|
tabButtons.push_back(&bBack);
|
||||||
|
tabButtons.push_back(&bHeader);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinByIPScreen::setupPositions() {
|
||||||
|
int tIpDiff = 40;
|
||||||
|
|
||||||
|
bJoin.y = height * 2 / 3;
|
||||||
|
bBack.y = 0;
|
||||||
|
bHeader.y = 0;
|
||||||
|
|
||||||
|
// Center buttons
|
||||||
|
//bJoin.x = width / 2 - 4 - bJoin.w;
|
||||||
|
bBack.x = width - bBack.width;//width / 2 + 4;
|
||||||
|
|
||||||
|
bJoin.x = (width - bJoin.width) / 2;
|
||||||
|
|
||||||
|
bHeader.x = 0;
|
||||||
|
bHeader.width = width - bBack.width;
|
||||||
|
|
||||||
|
tIP.width = bJoin.width + tIpDiff;
|
||||||
|
tIP.height = 16;
|
||||||
|
tIP.x = bJoin.x - tIpDiff / 2;
|
||||||
|
tIP.y = ((height - bJoin.height) / 2) - tIP.height - 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinByIPScreen::mouseClicked(int x, int y, int buttonNum) {
|
||||||
|
int lvlTop = tIP.y - (Font::DefaultLineHeight + 4);
|
||||||
|
int lvlBottom = tIP.y + tIP.height;
|
||||||
|
int lvlLeft = tIP.x;
|
||||||
|
int lvlRight = tIP.x + tIP.width;
|
||||||
|
bool clickedIP = x >= lvlLeft && x < lvlRight && y >= lvlTop && y < lvlBottom;
|
||||||
|
|
||||||
|
if (clickedIP) {
|
||||||
|
tIP.setFocus(minecraft);
|
||||||
|
} else {
|
||||||
|
tIP.loseFocus(minecraft);
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::mouseClicked(x, y, buttonNum);
|
||||||
|
}
|
||||||
|
void JoinByIPScreen::render( int xm, int ym, float a )
|
||||||
|
{
|
||||||
|
renderBackground();
|
||||||
|
Screen::render(xm, ym, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinByIPScreen::keyPressed(int eventKey)
|
||||||
|
{
|
||||||
|
if (eventKey == Keyboard::KEY_ESCAPE) {
|
||||||
|
minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// let base class handle navigation and text box keys
|
||||||
|
Screen::keyPressed(eventKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoinByIPScreen::keyboardNewChar(char inputChar)
|
||||||
|
{
|
||||||
|
// forward character input to focused textbox(s)
|
||||||
|
for (auto* tb : textBoxes) tb->handleChar(inputChar);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
#include "../Screen.h"
|
||||||
|
#include "../components/Button.h"
|
||||||
|
#include "../../Minecraft.h"
|
||||||
|
#include "client/gui/components/ImageButton.h"
|
||||||
|
#include "client/gui/components/TextBox.h"
|
||||||
|
|
||||||
|
class JoinByIPScreen: public Screen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JoinByIPScreen();
|
||||||
|
virtual ~JoinByIPScreen();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void setupPositions();
|
||||||
|
|
||||||
|
virtual void tick();
|
||||||
|
void render(int xm, int ym, float a);
|
||||||
|
|
||||||
|
virtual void keyPressed(int eventKey);
|
||||||
|
virtual void keyboardNewChar(char inputChar);
|
||||||
|
void buttonClicked(Button* button);
|
||||||
|
virtual void mouseClicked(int x, int y, int buttonNum);
|
||||||
|
virtual bool handleBackEvent(bool isDown);
|
||||||
|
private:
|
||||||
|
TextBox tIP;
|
||||||
|
Touch::THeader bHeader;
|
||||||
|
Touch::TButton bJoin;
|
||||||
|
ImageButton bBack;
|
||||||
|
};
|
||||||
@@ -69,6 +69,7 @@ void OptionsScreen::init() {
|
|||||||
categoryButtons.push_back(new Touch::TButton(3, "Game"));
|
categoryButtons.push_back(new Touch::TButton(3, "Game"));
|
||||||
categoryButtons.push_back(new Touch::TButton(4, "Controls"));
|
categoryButtons.push_back(new Touch::TButton(4, "Controls"));
|
||||||
categoryButtons.push_back(new Touch::TButton(5, "Graphics"));
|
categoryButtons.push_back(new Touch::TButton(5, "Graphics"));
|
||||||
|
categoryButtons.push_back(new Touch::TButton(6, "Tweaks"));
|
||||||
|
|
||||||
btnCredits = new Touch::TButton(11, "Credits");
|
btnCredits = new Touch::TButton(11, "Credits");
|
||||||
|
|
||||||
@@ -192,6 +193,7 @@ void OptionsScreen::generateOptionScreens() {
|
|||||||
optionPanes.push_back(new OptionsGroup("options.group.game"));
|
optionPanes.push_back(new OptionsGroup("options.group.game"));
|
||||||
optionPanes.push_back(new OptionsGroup("options.group.control"));
|
optionPanes.push_back(new OptionsGroup("options.group.control"));
|
||||||
optionPanes.push_back(new OptionsGroup("options.group.graphics"));
|
optionPanes.push_back(new OptionsGroup("options.group.graphics"));
|
||||||
|
optionPanes.push_back(new OptionsGroup("options.group.tweaks"));
|
||||||
|
|
||||||
// General Pane
|
// General Pane
|
||||||
optionPanes[0]->addOptionItem(OPTIONS_USERNAME, minecraft)
|
optionPanes[0]->addOptionItem(OPTIONS_USERNAME, minecraft)
|
||||||
@@ -228,6 +230,9 @@ void OptionsScreen::generateOptionScreens() {
|
|||||||
.addOptionItem(OPTIONS_ANAGLYPH_3D, minecraft)
|
.addOptionItem(OPTIONS_ANAGLYPH_3D, minecraft)
|
||||||
.addOptionItem(OPTIONS_VIEW_BOBBING, minecraft)
|
.addOptionItem(OPTIONS_VIEW_BOBBING, minecraft)
|
||||||
.addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft);
|
.addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft);
|
||||||
|
|
||||||
|
optionPanes[4]->addOptionItem(OPTIONS_ALLOW_SPRINT, minecraft)
|
||||||
|
.addOptionItem(OPTIONS_BAR_ON_TOP, minecraft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsScreen::mouseClicked(int x, int y, int buttonNum) {
|
void OptionsScreen::mouseClicked(int x, int y, int buttonNum) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "PauseScreen.h"
|
#include "PauseScreen.h"
|
||||||
#include "RenameMPLevelScreen.h"
|
#include "RenameMPLevelScreen.h"
|
||||||
#include "IngameBlockSelectionScreen.h"
|
#include "IngameBlockSelectionScreen.h"
|
||||||
|
#include "JoinByIPScreen.h"
|
||||||
#include "touch/TouchStartMenuScreen.h"
|
#include "touch/TouchStartMenuScreen.h"
|
||||||
#include "touch/TouchSelectWorldScreen.h"
|
#include "touch/TouchSelectWorldScreen.h"
|
||||||
#include "touch/TouchJoinGameScreen.h"
|
#include "touch/TouchJoinGameScreen.h"
|
||||||
@@ -20,13 +21,13 @@ Screen* ScreenChooser::createScreen( ScreenId id )
|
|||||||
|
|
||||||
if (_mc->useTouchscreen()) {
|
if (_mc->useTouchscreen()) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case SCREEN_STARTMENU: screen = new Touch::StartMenuScreen(); break;
|
case SCREEN_STARTMENU: screen = new Touch::StartMenuScreen(); break;
|
||||||
case SCREEN_SELECTWORLD:screen = new Touch::SelectWorldScreen();break;
|
case SCREEN_SELECTWORLD: screen = new Touch::SelectWorldScreen();break;
|
||||||
case SCREEN_JOINGAME: screen = new Touch::JoinGameScreen(); break;
|
case SCREEN_JOINGAME: screen = new Touch::JoinGameScreen(); break;
|
||||||
case SCREEN_PAUSE: screen = new PauseScreen(false); break;
|
case SCREEN_PAUSE: screen = new PauseScreen(false); break;
|
||||||
case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break;
|
case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break;
|
||||||
case SCREEN_BLOCKSELECTION: screen = new Touch::IngameBlockSelectionScreen(); break;
|
case SCREEN_BLOCKSELECTION: screen = new Touch::IngameBlockSelectionScreen(); break;
|
||||||
|
case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break;
|
||||||
case SCREEN_NONE:
|
case SCREEN_NONE:
|
||||||
default:
|
default:
|
||||||
// Do nothing
|
// Do nothing
|
||||||
@@ -34,12 +35,13 @@ Screen* ScreenChooser::createScreen( ScreenId id )
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case SCREEN_STARTMENU: screen = new StartMenuScreen(); break;
|
case SCREEN_STARTMENU: screen = new StartMenuScreen(); break;
|
||||||
case SCREEN_SELECTWORLD:screen = new SelectWorldScreen();break;
|
case SCREEN_SELECTWORLD: screen = new SelectWorldScreen();break;
|
||||||
case SCREEN_JOINGAME: screen = new JoinGameScreen(); break;
|
case SCREEN_JOINGAME: screen = new JoinGameScreen(); break;
|
||||||
case SCREEN_PAUSE: screen = new PauseScreen(false); break;
|
case SCREEN_PAUSE: screen = new PauseScreen(false); break;
|
||||||
case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break;
|
case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break;
|
||||||
case SCREEN_BLOCKSELECTION: screen = new IngameBlockSelectionScreen(); break;
|
case SCREEN_BLOCKSELECTION: screen = new IngameBlockSelectionScreen(); break;
|
||||||
|
case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break;
|
||||||
|
|
||||||
case SCREEN_NONE:
|
case SCREEN_NONE:
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ enum ScreenId {
|
|||||||
SCREEN_PAUSE,
|
SCREEN_PAUSE,
|
||||||
SCREEN_PAUSEPREV,
|
SCREEN_PAUSEPREV,
|
||||||
SCREEN_SELECTWORLD,
|
SCREEN_SELECTWORLD,
|
||||||
SCREEN_BLOCKSELECTION
|
SCREEN_BLOCKSELECTION,
|
||||||
|
SCREEN_JOINBYIP
|
||||||
};
|
};
|
||||||
|
|
||||||
class Screen;
|
class Screen;
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ void SelectWorldScreen::render( int xm, int ym, float a )
|
|||||||
worldsList->setComponentSelected(bWorldView.selected);
|
worldsList->setComponentSelected(bWorldView.selected);
|
||||||
// #ifdef PLATFORM_DESKTOP
|
// #ifdef PLATFORM_DESKTOP
|
||||||
|
|
||||||
// We should add scrolling with mouse wheel but currently i dont know how to implement it
|
// desktop: render the list normally (mouse wheel handled separately below)
|
||||||
if (_mouseHasBeenUp)
|
if (_mouseHasBeenUp)
|
||||||
worldsList->render(xm, ym, a);
|
worldsList->render(xm, ym, a);
|
||||||
else {
|
else {
|
||||||
@@ -412,6 +412,28 @@ std::string SelectWorldScreen::getUniqueLevelName( const std::string& level )
|
|||||||
|
|
||||||
bool SelectWorldScreen::isInGameScreen() { return true; }
|
bool SelectWorldScreen::isInGameScreen() { return true; }
|
||||||
|
|
||||||
|
void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym)
|
||||||
|
{
|
||||||
|
if (!worldsList)
|
||||||
|
return;
|
||||||
|
if (dy == 0)
|
||||||
|
return;
|
||||||
|
int num = worldsList->getNumberOfItems();
|
||||||
|
int idx = worldsList->selectedItem;
|
||||||
|
if (dy > 0) {
|
||||||
|
if (idx > 0) {
|
||||||
|
idx--;
|
||||||
|
worldsList->stepLeft();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (idx < num - 1) {
|
||||||
|
idx++;
|
||||||
|
worldsList->stepRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worldsList->selectedItem = idx;
|
||||||
|
}
|
||||||
|
|
||||||
void SelectWorldScreen::keyPressed( int eventKey )
|
void SelectWorldScreen::keyPressed( int eventKey )
|
||||||
{
|
{
|
||||||
if (bWorldView.selected) {
|
if (bWorldView.selected) {
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ public:
|
|||||||
|
|
||||||
void render(int xm, int ym, float a);
|
void render(int xm, int ym, float a);
|
||||||
|
|
||||||
|
// mouse wheel scroll (new in desktop implementation)
|
||||||
|
virtual void mouseWheel(int dx, int dy, int xm, int ym);
|
||||||
|
|
||||||
bool isInGameScreen();
|
bool isInGameScreen();
|
||||||
private:
|
private:
|
||||||
void loadLevelSource();
|
void loadLevelSource();
|
||||||
|
|||||||
@@ -12,11 +12,13 @@
|
|||||||
SimpleChooseLevelScreen::SimpleChooseLevelScreen(const std::string& levelName)
|
SimpleChooseLevelScreen::SimpleChooseLevelScreen(const std::string& levelName)
|
||||||
: bHeader(0),
|
: bHeader(0),
|
||||||
bGamemode(0),
|
bGamemode(0),
|
||||||
|
bCheats(0),
|
||||||
bBack(0),
|
bBack(0),
|
||||||
bCreate(0),
|
bCreate(0),
|
||||||
levelName(levelName),
|
levelName(levelName),
|
||||||
hasChosen(false),
|
hasChosen(false),
|
||||||
gamemode(GameType::Survival),
|
gamemode(GameType::Survival),
|
||||||
|
cheatsEnabled(false),
|
||||||
tLevelName(0, "World name"),
|
tLevelName(0, "World name"),
|
||||||
tSeed(1, "World seed")
|
tSeed(1, "World seed")
|
||||||
{
|
{
|
||||||
@@ -26,12 +28,20 @@ SimpleChooseLevelScreen::~SimpleChooseLevelScreen()
|
|||||||
{
|
{
|
||||||
if (bHeader) delete bHeader;
|
if (bHeader) delete bHeader;
|
||||||
delete bGamemode;
|
delete bGamemode;
|
||||||
|
delete bCheats;
|
||||||
delete bBack;
|
delete bBack;
|
||||||
delete bCreate;
|
delete bCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleChooseLevelScreen::init()
|
void SimpleChooseLevelScreen::init()
|
||||||
{
|
{
|
||||||
|
// make sure the base class loads the existing level list; the
|
||||||
|
// derived screen uses ChooseLevelScreen::getUniqueLevelName(), which
|
||||||
|
// depends on `levels` being populated. omitting this used to result
|
||||||
|
// in duplicate IDs ("creating the second world would load the
|
||||||
|
// first") when the name already existed.
|
||||||
|
ChooseLevelScreen::init();
|
||||||
|
|
||||||
tLevelName.text = "New world";
|
tLevelName.text = "New world";
|
||||||
|
|
||||||
// header + close button
|
// header + close button
|
||||||
@@ -48,18 +58,22 @@ void SimpleChooseLevelScreen::init()
|
|||||||
}
|
}
|
||||||
if (minecraft->useTouchscreen()) {
|
if (minecraft->useTouchscreen()) {
|
||||||
bGamemode = new Touch::TButton(1, "Survival mode");
|
bGamemode = new Touch::TButton(1, "Survival mode");
|
||||||
|
bCheats = new Touch::TButton(4, "Cheats: Off");
|
||||||
bCreate = new Touch::TButton(3, "Create");
|
bCreate = new Touch::TButton(3, "Create");
|
||||||
} else {
|
} else {
|
||||||
bGamemode = new Button(1, "Survival mode");
|
bGamemode = new Button(1, "Survival mode");
|
||||||
|
bCheats = new Button(4, "Cheats: Off");
|
||||||
bCreate = new Button(3, "Create");
|
bCreate = new Button(3, "Create");
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons.push_back(bHeader);
|
buttons.push_back(bHeader);
|
||||||
buttons.push_back(bBack);
|
buttons.push_back(bBack);
|
||||||
buttons.push_back(bGamemode);
|
buttons.push_back(bGamemode);
|
||||||
|
buttons.push_back(bCheats);
|
||||||
buttons.push_back(bCreate);
|
buttons.push_back(bCreate);
|
||||||
|
|
||||||
tabButtons.push_back(bGamemode);
|
tabButtons.push_back(bGamemode);
|
||||||
|
tabButtons.push_back(bCheats);
|
||||||
tabButtons.push_back(bBack);
|
tabButtons.push_back(bBack);
|
||||||
tabButtons.push_back(bCreate);
|
tabButtons.push_back(bCreate);
|
||||||
|
|
||||||
@@ -94,16 +108,26 @@ void SimpleChooseLevelScreen::setupPositions()
|
|||||||
tSeed.x = tLevelName.x;
|
tSeed.x = tLevelName.x;
|
||||||
tSeed.y = tLevelName.y + 30;
|
tSeed.y = tLevelName.y + 30;
|
||||||
|
|
||||||
bGamemode->width = 140;
|
const int buttonWidth = 120;
|
||||||
bGamemode->x = centerX - bGamemode->width / 2;
|
const int buttonSpacing = 10;
|
||||||
// compute vertical centre for gamemode in remaining space
|
const int totalButtonWidth = buttonWidth * 2 + buttonSpacing;
|
||||||
|
|
||||||
|
bGamemode->width = buttonWidth;
|
||||||
|
bCheats->width = buttonWidth;
|
||||||
|
|
||||||
|
bGamemode->x = centerX - totalButtonWidth / 2;
|
||||||
|
bCheats->x = bGamemode->x + buttonWidth + buttonSpacing;
|
||||||
|
|
||||||
|
// compute vertical centre for buttons in remaining space
|
||||||
{
|
{
|
||||||
int bottomPad = 20;
|
int bottomPad = 20;
|
||||||
int availTop = buttonHeight + 20 + 30 + 10; // just below seed
|
int availTop = buttonHeight + 20 + 30 + 10; // just below seed
|
||||||
int availBottom = height - bottomPad - bCreate->height - 10; // leave some gap before create
|
int availBottom = height - bottomPad - bCreate->height - 10; // leave some gap before create
|
||||||
int availHeight = availBottom - availTop;
|
int availHeight = availBottom - availTop;
|
||||||
if (availHeight < 0) availHeight = 0;
|
if (availHeight < 0) availHeight = 0;
|
||||||
bGamemode->y = availTop + (availHeight - bGamemode->height) / 2;
|
int y = availTop + (availHeight - bGamemode->height) / 2;
|
||||||
|
bGamemode->y = y;
|
||||||
|
bCheats->y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
bCreate->width = 100;
|
bCreate->width = 100;
|
||||||
@@ -124,14 +148,14 @@ void SimpleChooseLevelScreen::render( int xm, int ym, float a )
|
|||||||
renderDirtBackground(0);
|
renderDirtBackground(0);
|
||||||
glEnable2(GL_BLEND);
|
glEnable2(GL_BLEND);
|
||||||
|
|
||||||
const char* str = NULL;
|
const char* modeDesc = NULL;
|
||||||
if (gamemode == GameType::Survival) {
|
if (gamemode == GameType::Survival) {
|
||||||
str = "Mobs, health and gather resources";
|
modeDesc = "Mobs, health and gather resources";
|
||||||
} else if (gamemode == GameType::Creative) {
|
} else if (gamemode == GameType::Creative) {
|
||||||
str = "Unlimited resources and flying";
|
modeDesc = "Unlimited resources and flying";
|
||||||
}
|
}
|
||||||
if (str) {
|
if (modeDesc) {
|
||||||
drawCenteredString(minecraft->font, str, width/2, bGamemode->y + bGamemode->height + 4, 0xffcccccc);
|
drawCenteredString(minecraft->font, modeDesc, width / 2, bGamemode->y + bGamemode->height + 4, 0xffcccccc);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawString(minecraft->font, "World name:", tLevelName.x, tLevelName.y - Font::DefaultLineHeight - 2, 0xffcccccc);
|
drawString(minecraft->font, "World name:", tLevelName.x, tLevelName.y - Font::DefaultLineHeight - 2, 0xffcccccc);
|
||||||
@@ -188,6 +212,12 @@ void SimpleChooseLevelScreen::buttonClicked( Button* button )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (button == bCheats) {
|
||||||
|
cheatsEnabled = !cheatsEnabled;
|
||||||
|
bCheats->msg = cheatsEnabled ? "Cheats: On" : "Cheats: Off";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (button == bCreate && !tLevelName.text.empty()) {
|
if (button == bCreate && !tLevelName.text.empty()) {
|
||||||
int seed = getEpochTimeS();
|
int seed = getEpochTimeS();
|
||||||
if (!tSeed.text.empty()) {
|
if (!tSeed.text.empty()) {
|
||||||
@@ -200,7 +230,7 @@ void SimpleChooseLevelScreen::buttonClicked( Button* button )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string levelId = getUniqueLevelName(tLevelName.text);
|
std::string levelId = getUniqueLevelName(tLevelName.text);
|
||||||
LevelSettings settings(seed, gamemode);
|
LevelSettings settings(seed, gamemode, cheatsEnabled);
|
||||||
minecraft->selectLevel(levelId, levelId, settings);
|
minecraft->selectLevel(levelId, levelId, settings);
|
||||||
minecraft->hostMultiplayer();
|
minecraft->hostMultiplayer();
|
||||||
minecraft->setScreen(new ProgressScreen());
|
minecraft->setScreen(new ProgressScreen());
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ public:
|
|||||||
private:
|
private:
|
||||||
Touch::THeader* bHeader;
|
Touch::THeader* bHeader;
|
||||||
Button* bGamemode;
|
Button* bGamemode;
|
||||||
|
Button* bCheats;
|
||||||
ImageButton* bBack;
|
ImageButton* bBack;
|
||||||
Button* bCreate;
|
Button* bCreate;
|
||||||
bool hasChosen;
|
bool hasChosen;
|
||||||
|
|
||||||
std::string levelName;
|
std::string levelName;
|
||||||
int gamemode;
|
int gamemode;
|
||||||
|
bool cheatsEnabled;
|
||||||
|
|
||||||
TextBox tLevelName;
|
TextBox tLevelName;
|
||||||
TextBox tSeed;
|
TextBox tSeed;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "OptionsScreen.h"
|
#include "OptionsScreen.h"
|
||||||
#include "PauseScreen.h"
|
#include "PauseScreen.h"
|
||||||
#include "PrerenderTilesScreen.h" // test button
|
#include "PrerenderTilesScreen.h" // test button
|
||||||
|
#include "../components/ImageButton.h"
|
||||||
|
|
||||||
#include "../../../util/Mth.h"
|
#include "../../../util/Mth.h"
|
||||||
|
|
||||||
@@ -24,7 +25,8 @@
|
|||||||
StartMenuScreen::StartMenuScreen()
|
StartMenuScreen::StartMenuScreen()
|
||||||
: bHost( 2, 0, 0, 160, 24, "Start Game"),
|
: bHost( 2, 0, 0, 160, 24, "Start Game"),
|
||||||
bJoin( 3, 0, 0, 160, 24, "Join Game"),
|
bJoin( 3, 0, 0, 160, 24, "Join Game"),
|
||||||
bOptions( 4, 0, 0, 78, 22, "Options")
|
bOptions( 4, 0, 0, 78, 22, "Options"),
|
||||||
|
bQuit( 5, "")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,10 +55,18 @@ void StartMenuScreen::init()
|
|||||||
tabButtons.push_back(&bOptions);
|
tabButtons.push_back(&bOptions);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEMO_MODE
|
// add quit button (top right X icon) – match OptionsScreen style
|
||||||
buttons.push_back(&bBuy);
|
{
|
||||||
tabButtons.push_back(&bBuy);
|
ImageDef def;
|
||||||
#endif
|
def.name = "gui/touchgui.png";
|
||||||
|
def.width = 34;
|
||||||
|
def.height = 26;
|
||||||
|
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
|
||||||
|
bQuit.setImageDef(def, true);
|
||||||
|
bQuit.scaleWhenPressed = false;
|
||||||
|
buttons.push_back(&bQuit);
|
||||||
|
// don't include in tab navigation
|
||||||
|
}
|
||||||
|
|
||||||
copyright = "\xffMojang AB";//. Do not distribute!";
|
copyright = "\xffMojang AB";//. Do not distribute!";
|
||||||
|
|
||||||
@@ -99,8 +109,9 @@ void StartMenuScreen::setupPositions() {
|
|||||||
bJoin.x = (width - bJoin.width) / 2;
|
bJoin.x = (width - bJoin.width) / 2;
|
||||||
bOptions.x = (width - bJoin.width) / 2;
|
bOptions.x = (width - bJoin.width) / 2;
|
||||||
|
|
||||||
copyrightPosX = width - minecraft->font->width(copyright) - 1;
|
// position quit icon at top-right (use image-defined size)
|
||||||
versionPosX = (width - minecraft->font->width(version)) / 2;// - minecraft->font->width(version) - 2;
|
bQuit.x = width - bQuit.width;
|
||||||
|
bQuit.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartMenuScreen::tick() {
|
void StartMenuScreen::tick() {
|
||||||
@@ -129,6 +140,10 @@ void StartMenuScreen::buttonClicked(Button* button) {
|
|||||||
{
|
{
|
||||||
minecraft->setScreen(new OptionsScreen());
|
minecraft->setScreen(new OptionsScreen());
|
||||||
}
|
}
|
||||||
|
if (button == &bQuit)
|
||||||
|
{
|
||||||
|
minecraft->quit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StartMenuScreen::isInGameScreen() { return false; }
|
bool StartMenuScreen::isInGameScreen() { return false; }
|
||||||
@@ -137,6 +152,10 @@ void StartMenuScreen::render( int xm, int ym, float a )
|
|||||||
{
|
{
|
||||||
renderBackground();
|
renderBackground();
|
||||||
|
|
||||||
|
// Show current username in the top-left corner
|
||||||
|
std::string username = minecraft->options.username.empty() ? "unknown" : minecraft->options.username;
|
||||||
|
drawString(font, std::string("Username: ") + username, 2, 2, 0xffffffff);
|
||||||
|
|
||||||
#if defined(RPI)
|
#if defined(RPI)
|
||||||
TextureId id = minecraft->textures->loadTexture("gui/pi_title.png");
|
TextureId id = minecraft->textures->loadTexture("gui/pi_title.png");
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "../Screen.h"
|
#include "../Screen.h"
|
||||||
#include "../components/Button.h"
|
#include "../components/Button.h"
|
||||||
|
#include "../components/ImageButton.h"
|
||||||
|
|
||||||
class StartMenuScreen: public Screen
|
class StartMenuScreen: public Screen
|
||||||
{
|
{
|
||||||
@@ -25,6 +26,7 @@ private:
|
|||||||
Button bHost;
|
Button bHost;
|
||||||
Button bJoin;
|
Button bJoin;
|
||||||
Button bOptions;
|
Button bOptions;
|
||||||
|
ImageButton bQuit; // X button in top-right corner
|
||||||
|
|
||||||
std::string copyright;
|
std::string copyright;
|
||||||
int copyrightPosX;
|
int copyrightPosX;
|
||||||
|
|||||||
@@ -33,15 +33,16 @@ void UsernameScreen::setupPositions()
|
|||||||
int cx = width / 2;
|
int cx = width / 2;
|
||||||
int cy = height / 2;
|
int cy = height / 2;
|
||||||
|
|
||||||
_btnDone.width = 120;
|
// Make the done button match the touch-style option tabs
|
||||||
_btnDone.height = 20;
|
_btnDone.width = 66;
|
||||||
|
_btnDone.height = 26;
|
||||||
_btnDone.x = (width - _btnDone.width) / 2;
|
_btnDone.x = (width - _btnDone.width) / 2;
|
||||||
_btnDone.y = height / 2 + 52;
|
_btnDone.y = height / 2 + 52;
|
||||||
|
|
||||||
tUsername.x = _btnDone.x;
|
|
||||||
tUsername.y = _btnDone.y - 60;
|
|
||||||
tUsername.width = 120;
|
tUsername.width = 120;
|
||||||
tUsername.height = 20;
|
tUsername.height = 20;
|
||||||
|
tUsername.x = (width - tUsername.width) / 2;
|
||||||
|
tUsername.y = _btnDone.y - 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsernameScreen::tick()
|
void UsernameScreen::tick()
|
||||||
@@ -58,9 +59,10 @@ void UsernameScreen::keyPressed(int eventKey)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deliberately do NOT call super::keyPressed — that would close the screen on Escape
|
// deliberately do NOT call super::keyPressed — that would close the screen on Escape
|
||||||
_btnDone.active = !tUsername.text.empty();
|
|
||||||
|
|
||||||
Screen::keyPressed(eventKey);
|
Screen::keyPressed(eventKey);
|
||||||
|
|
||||||
|
// enable the Done button only when there is some text (and ensure it updates after backspace)
|
||||||
|
_btnDone.active = !tUsername.text.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsernameScreen::removed()
|
void UsernameScreen::removed()
|
||||||
|
|||||||
@@ -153,6 +153,11 @@ int IngameBlockSelectionScreen::getSlotPosY(int slotY) {
|
|||||||
return height - 16 - 3 - 22 * 2 - 22 * slotY;
|
return height - 16 - 3 - 22 * 2 - 22 * slotY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int IngameBlockSelectionScreen::getSlotHeight() {
|
||||||
|
// same as non-touch implementation
|
||||||
|
return 22;
|
||||||
|
}
|
||||||
|
|
||||||
void IngameBlockSelectionScreen::mouseClicked(int x, int y, int buttonNum) {
|
void IngameBlockSelectionScreen::mouseClicked(int x, int y, int buttonNum) {
|
||||||
_pendingClose = _blockList->_clickArea->isInside((float)x, (float)y);
|
_pendingClose = _blockList->_clickArea->isInside((float)x, (float)y);
|
||||||
if (!_pendingClose)
|
if (!_pendingClose)
|
||||||
@@ -166,6 +171,24 @@ void IngameBlockSelectionScreen::mouseReleased(int x, int y, int buttonNum) {
|
|||||||
super::mouseReleased(x, y, buttonNum);
|
super::mouseReleased(x, y, buttonNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IngameBlockSelectionScreen::mouseWheel(int dx, int dy, int xm, int ym)
|
||||||
|
{
|
||||||
|
if (dy == 0) return;
|
||||||
|
if (_blockList) {
|
||||||
|
float amount = -dy * getSlotHeight();
|
||||||
|
_blockList->scrollBy(0, amount);
|
||||||
|
}
|
||||||
|
int cols = InventoryColumns;
|
||||||
|
int maxIndex = InventorySize - 1;
|
||||||
|
int idx = selectedItem;
|
||||||
|
if (dy > 0) {
|
||||||
|
if (idx >= cols) idx -= cols;
|
||||||
|
} else {
|
||||||
|
if (idx + cols <= maxIndex) idx += cols;
|
||||||
|
}
|
||||||
|
selectedItem = idx;
|
||||||
|
}
|
||||||
|
|
||||||
bool IngameBlockSelectionScreen::addItem(const InventoryPane* pane, int itemId)
|
bool IngameBlockSelectionScreen::addItem(const InventoryPane* pane, int itemId)
|
||||||
{
|
{
|
||||||
Inventory* inventory = minecraft->player->inventory;
|
Inventory* inventory = minecraft->player->inventory;
|
||||||
|
|||||||
@@ -39,12 +39,16 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual void mouseClicked(int x, int y, int buttonNum);
|
virtual void mouseClicked(int x, int y, int buttonNum);
|
||||||
virtual void mouseReleased(int x, int y, int buttonNum);
|
virtual void mouseReleased(int x, int y, int buttonNum);
|
||||||
|
|
||||||
|
// also support wheel scrolling
|
||||||
|
virtual void mouseWheel(int dx, int dy, int xm, int ym) override;
|
||||||
private:
|
private:
|
||||||
void renderDemoOverlay();
|
void renderDemoOverlay();
|
||||||
|
|
||||||
//int getLinearSlotId(int x, int y);
|
//int getLinearSlotId(int x, int y);
|
||||||
int getSlotPosX(int slotX);
|
int getSlotPosX(int slotX);
|
||||||
int getSlotPosY(int slotY);
|
int getSlotPosY(int slotY);
|
||||||
|
int getSlotHeight();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int selectedItem;
|
int selectedItem;
|
||||||
|
|||||||
@@ -129,6 +129,11 @@ void JoinGameScreen::buttonClicked(Button* button)
|
|||||||
//minecraft->locateMultiplayer();
|
//minecraft->locateMultiplayer();
|
||||||
//minecraft->setScreen(new JoinGameScreen());
|
//minecraft->setScreen(new JoinGameScreen());
|
||||||
}
|
}
|
||||||
|
if(button->id == bJoinByIp.id) {
|
||||||
|
minecraft->cancelLocateMultiplayer();
|
||||||
|
minecraft->screenChooser.setScreen(SCREEN_JOINBYIP);
|
||||||
|
}
|
||||||
|
|
||||||
if (button->id == bBack.id)
|
if (button->id == bBack.id)
|
||||||
{
|
{
|
||||||
minecraft->cancelLocateMultiplayer();
|
minecraft->cancelLocateMultiplayer();
|
||||||
|
|||||||
@@ -389,6 +389,26 @@ static char ILLEGAL_FILE_CHARACTERS[] = {
|
|||||||
'/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':'
|
'/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym)
|
||||||
|
{
|
||||||
|
if (!worldsList) return;
|
||||||
|
if (dy == 0) return;
|
||||||
|
int num = worldsList->getNumberOfItems();
|
||||||
|
int idx = worldsList->selectedItem;
|
||||||
|
if (dy > 0) {
|
||||||
|
if (idx > 0) {
|
||||||
|
idx--;
|
||||||
|
worldsList->stepLeft();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (idx < num - 1) {
|
||||||
|
idx++;
|
||||||
|
worldsList->stepRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worldsList->selectedItem = idx;
|
||||||
|
}
|
||||||
|
|
||||||
void SelectWorldScreen::tick()
|
void SelectWorldScreen::tick()
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
|
|||||||
@@ -97,6 +97,9 @@ public:
|
|||||||
virtual void buttonClicked(Button* button);
|
virtual void buttonClicked(Button* button);
|
||||||
virtual void keyPressed(int eventKey);
|
virtual void keyPressed(int eventKey);
|
||||||
|
|
||||||
|
// support for mouse wheel when desktop code uses touch variant
|
||||||
|
virtual void mouseWheel(int dx, int dy, int xm, int ym) override;
|
||||||
|
|
||||||
bool isInGameScreen();
|
bool isInGameScreen();
|
||||||
private:
|
private:
|
||||||
void loadLevelSource();
|
void loadLevelSource();
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ namespace Touch {
|
|||||||
StartMenuScreen::StartMenuScreen()
|
StartMenuScreen::StartMenuScreen()
|
||||||
: bHost( 2, "Start Game"),
|
: bHost( 2, "Start Game"),
|
||||||
bJoin( 3, "Join Game"),
|
bJoin( 3, "Join Game"),
|
||||||
bOptions( 4, "Options")
|
bOptions( 4, "Options"),
|
||||||
|
bQuit( 5, "")
|
||||||
{
|
{
|
||||||
ImageDef def;
|
ImageDef def;
|
||||||
bJoin.width = 75;
|
bJoin.width = 75;
|
||||||
@@ -58,6 +59,17 @@ void StartMenuScreen::init()
|
|||||||
buttons.push_back(&bJoin);
|
buttons.push_back(&bJoin);
|
||||||
buttons.push_back(&bOptions);
|
buttons.push_back(&bOptions);
|
||||||
|
|
||||||
|
// add quit icon (same look as options header)
|
||||||
|
{
|
||||||
|
ImageDef def;
|
||||||
|
def.name = "gui/touchgui.png";
|
||||||
|
def.width = 34;
|
||||||
|
def.height = 26;
|
||||||
|
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
|
||||||
|
bQuit.setImageDef(def, true);
|
||||||
|
bQuit.scaleWhenPressed = false;
|
||||||
|
buttons.push_back(&bQuit);
|
||||||
|
}
|
||||||
|
|
||||||
tabButtons.push_back(&bHost);
|
tabButtons.push_back(&bHost);
|
||||||
tabButtons.push_back(&bJoin);
|
tabButtons.push_back(&bJoin);
|
||||||
@@ -106,6 +118,10 @@ void StartMenuScreen::setupPositions() {
|
|||||||
bHost.x = 1*buttonWidth + (int)(2*spacing);
|
bHost.x = 1*buttonWidth + (int)(2*spacing);
|
||||||
bOptions.x = 2*buttonWidth + (int)(3*spacing);
|
bOptions.x = 2*buttonWidth + (int)(3*spacing);
|
||||||
|
|
||||||
|
// quit icon top-right (use size assigned in init)
|
||||||
|
bQuit.x = width - bQuit.width;
|
||||||
|
bQuit.y = 0;
|
||||||
|
|
||||||
copyrightPosX = width - minecraft->font->width(copyright) - 1;
|
copyrightPosX = width - minecraft->font->width(copyright) - 1;
|
||||||
versionPosX = (width - minecraft->font->width(version)) / 2;// - minecraft->font->width(version) - 2;
|
versionPosX = (width - minecraft->font->width(version)) / 2;// - minecraft->font->width(version) - 2;
|
||||||
}
|
}
|
||||||
@@ -133,6 +149,10 @@ void StartMenuScreen::buttonClicked(::Button* button) {
|
|||||||
{
|
{
|
||||||
minecraft->setScreen(new OptionsScreen());
|
minecraft->setScreen(new OptionsScreen());
|
||||||
}
|
}
|
||||||
|
if (button == &bQuit)
|
||||||
|
{
|
||||||
|
minecraft->quit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StartMenuScreen::isInGameScreen() { return false; }
|
bool StartMenuScreen::isInGameScreen() { return false; }
|
||||||
@@ -140,6 +160,10 @@ bool StartMenuScreen::isInGameScreen() { return false; }
|
|||||||
void StartMenuScreen::render( int xm, int ym, float a )
|
void StartMenuScreen::render( int xm, int ym, float a )
|
||||||
{
|
{
|
||||||
renderBackground();
|
renderBackground();
|
||||||
|
|
||||||
|
// Show current username in the top-left corner
|
||||||
|
std::string username = minecraft->options.username.empty() ? "unknown" : minecraft->options.username;
|
||||||
|
drawString(font, std::string("Username: ") + username, 2, 2, 0xffffffff);
|
||||||
|
|
||||||
glEnable2(GL_BLEND);
|
glEnable2(GL_BLEND);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "../../Screen.h"
|
#include "../../Screen.h"
|
||||||
#include "../../components/LargeImageButton.h"
|
#include "../../components/LargeImageButton.h"
|
||||||
|
#include "../../components/ImageButton.h"
|
||||||
#include "../../components/TextBox.h"
|
#include "../../components/TextBox.h"
|
||||||
|
|
||||||
namespace Touch {
|
namespace Touch {
|
||||||
@@ -27,6 +28,7 @@ private:
|
|||||||
LargeImageButton bHost;
|
LargeImageButton bHost;
|
||||||
LargeImageButton bJoin;
|
LargeImageButton bJoin;
|
||||||
LargeImageButton bOptions;
|
LargeImageButton bOptions;
|
||||||
|
ImageButton bQuit; // X close icon
|
||||||
|
|
||||||
std::string copyright;
|
std::string copyright;
|
||||||
int copyrightPosX;
|
int copyrightPosX;
|
||||||
|
|||||||
@@ -4,34 +4,46 @@
|
|||||||
#include "../../world/entity/player/Player.h"
|
#include "../../world/entity/player/Player.h"
|
||||||
#include "../../world/entity/player/Inventory.h"
|
#include "../../world/entity/player/Inventory.h"
|
||||||
|
|
||||||
HumanoidModel::HumanoidModel( float g /*= 0*/, float yOffset /*= 0*/ )
|
HumanoidModel::HumanoidModel( float g /*= 0*/, float yOffset /*= 0*/, int texW /*= 64*/, int texH /*= 32*/ )
|
||||||
: holdingLeftHand(false),
|
: holdingLeftHand(false),
|
||||||
holdingRightHand(false),
|
holdingRightHand(false),
|
||||||
sneaking(false),
|
sneaking(false),
|
||||||
bowAndArrow(false),
|
bowAndArrow(false),
|
||||||
head(0, 0),
|
head(0, 0),
|
||||||
|
hair(32, 0),
|
||||||
//ear (24, 0),
|
//ear (24, 0),
|
||||||
//hair(32, 0),
|
|
||||||
body(16, 16),
|
body(16, 16),
|
||||||
arm0(24 + 16, 16),
|
arm0(24 + 16, 16),
|
||||||
arm1(24 + 16, 16),
|
arm1(24 + 16, 16),
|
||||||
leg0(0, 16),
|
leg0(0, 16),
|
||||||
leg1(0, 16)
|
leg1(0, 16)
|
||||||
{
|
{
|
||||||
|
texWidth = texW;
|
||||||
|
texHeight = texH;
|
||||||
|
|
||||||
head.setModel(this);
|
head.setModel(this);
|
||||||
|
hair.setModel(this);
|
||||||
body.setModel(this);
|
body.setModel(this);
|
||||||
arm0.setModel(this);
|
arm0.setModel(this);
|
||||||
arm1.setModel(this);
|
arm1.setModel(this);
|
||||||
leg0.setModel(this);
|
leg0.setModel(this);
|
||||||
leg1.setModel(this);
|
leg1.setModel(this);
|
||||||
|
|
||||||
|
// If the texture is 64x64, use the modern skin layout for arms/legs and add overlay layers.
|
||||||
|
bool modernSkin = (texWidth == 64 && texHeight == 64);
|
||||||
|
if (modernSkin) {
|
||||||
|
// Left arm and left leg are located in the bottom half of a 64x64 skin.
|
||||||
|
arm1.texOffs(32, 48);
|
||||||
|
leg1.texOffs(16, 48);
|
||||||
|
}
|
||||||
|
|
||||||
head.addBox(-4, -8, -4, 8, 8, 8, g); // Head
|
head.addBox(-4, -8, -4, 8, 8, 8, g); // Head
|
||||||
head.setPos(0, 0 + yOffset, 0);
|
head.setPos(0, 0 + yOffset, 0);
|
||||||
|
|
||||||
//ear.addBox(-3, -6, -1, 6, 6, 1, g); // Ear
|
if (modernSkin) {
|
||||||
|
hair.addBox(-4, -8, -4, 8, 8, 8, g + 0.5f); // Outer head layer (hat)
|
||||||
//hair.addBox(-4, -8, -4, 8, 8, 8, g + 0.5f); // Head
|
hair.setPos(0, 0 + yOffset, 0);
|
||||||
// hair.setPos(0, 0 + yOffset, 0);
|
}
|
||||||
|
|
||||||
body.addBox(-4, 0, -2, 8, 12, 4, g); // Body
|
body.addBox(-4, 0, -2, 8, 12, 4, g); // Body
|
||||||
body.setPos(0, 0 + yOffset, 0);
|
body.setPos(0, 0 + yOffset, 0);
|
||||||
@@ -49,6 +61,24 @@ HumanoidModel::HumanoidModel( float g /*= 0*/, float yOffset /*= 0*/ )
|
|||||||
leg1.mirror = true;
|
leg1.mirror = true;
|
||||||
leg1.addBox(-2, 0, -2, 4, 12, 4, g); // Leg1
|
leg1.addBox(-2, 0, -2, 4, 12, 4, g); // Leg1
|
||||||
leg1.setPos(2, 12 + yOffset, 0);
|
leg1.setPos(2, 12 + yOffset, 0);
|
||||||
|
|
||||||
|
if (modernSkin) {
|
||||||
|
// Overlay layers for 64x64 skins (same geometry, different texture regions)
|
||||||
|
body.texOffs(16, 32);
|
||||||
|
body.addBox(-4, 0, -2, 8, 12, 4, g + 0.5f);
|
||||||
|
|
||||||
|
arm0.texOffs(40, 32);
|
||||||
|
arm0.addBox(-3, -2, -2, 4, 12, 4, g + 0.5f);
|
||||||
|
|
||||||
|
arm1.texOffs(48, 48);
|
||||||
|
arm1.addBox(-1, -2, -2, 4, 12, 4, g + 0.5f);
|
||||||
|
|
||||||
|
leg0.texOffs(0, 32);
|
||||||
|
leg0.addBox(-2, 0, -2, 4, 12, 4, g + 0.5f);
|
||||||
|
|
||||||
|
leg1.texOffs(0, 48);
|
||||||
|
leg1.addBox(-2, 0, -2, 4, 12, 4, g + 0.5f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HumanoidModel::render(Entity* e, float time, float r, float bob, float yRot, float xRot, float scale )
|
void HumanoidModel::render(Entity* e, float time, float r, float bob, float yRot, float xRot, float scale )
|
||||||
@@ -68,14 +98,24 @@ void HumanoidModel::render(Entity* e, float time, float r, float bob, float yRot
|
|||||||
|
|
||||||
setupAnim(time, r, bob, yRot, xRot, scale);
|
setupAnim(time, r, bob, yRot, xRot, scale);
|
||||||
|
|
||||||
|
// Sync overlay with head rotation/position
|
||||||
|
if (texWidth == 64 && texHeight == 64) {
|
||||||
|
hair.xRot = head.xRot;
|
||||||
|
hair.yRot = head.yRot;
|
||||||
|
hair.zRot = head.zRot;
|
||||||
|
hair.y = head.y;
|
||||||
|
}
|
||||||
|
|
||||||
head.render(scale);
|
head.render(scale);
|
||||||
|
if (texWidth == 64 && texHeight == 64) {
|
||||||
|
hair.render(scale);
|
||||||
|
}
|
||||||
body.render(scale);
|
body.render(scale);
|
||||||
arm0.render(scale);
|
arm0.render(scale);
|
||||||
arm1.render(scale);
|
arm1.render(scale);
|
||||||
leg0.render(scale);
|
leg0.render(scale);
|
||||||
leg1.render(scale);
|
leg1.render(scale);
|
||||||
bowAndArrow = false;
|
bowAndArrow = false;
|
||||||
//hair.render(scale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HumanoidModel::render( HumanoidModel* model, float scale )
|
void HumanoidModel::render( HumanoidModel* model, float scale )
|
||||||
@@ -83,8 +123,12 @@ void HumanoidModel::render( HumanoidModel* model, float scale )
|
|||||||
head.yRot = model->head.yRot;
|
head.yRot = model->head.yRot;
|
||||||
head.y = model->head.y;
|
head.y = model->head.y;
|
||||||
head.xRot = model->head.xRot;
|
head.xRot = model->head.xRot;
|
||||||
//hair.yRot = head.yRot;
|
if (texWidth == 64 && texHeight == 64) {
|
||||||
//hair.xRot = head.xRot;
|
hair.yRot = head.yRot;
|
||||||
|
hair.xRot = head.xRot;
|
||||||
|
hair.zRot = head.zRot;
|
||||||
|
hair.y = head.y;
|
||||||
|
}
|
||||||
|
|
||||||
arm0.xRot = model->arm0.xRot;
|
arm0.xRot = model->arm0.xRot;
|
||||||
arm0.zRot = model->arm0.zRot;
|
arm0.zRot = model->arm0.zRot;
|
||||||
@@ -96,12 +140,14 @@ void HumanoidModel::render( HumanoidModel* model, float scale )
|
|||||||
leg1.xRot = model->leg1.xRot;
|
leg1.xRot = model->leg1.xRot;
|
||||||
|
|
||||||
head.render(scale);
|
head.render(scale);
|
||||||
|
if (texWidth == 64 && texHeight == 64) {
|
||||||
|
hair.render(scale);
|
||||||
|
}
|
||||||
body.render(scale);
|
body.render(scale);
|
||||||
arm0.render(scale);
|
arm0.render(scale);
|
||||||
arm1.render(scale);
|
arm1.render(scale);
|
||||||
leg0.render(scale);
|
leg0.render(scale);
|
||||||
leg1.render(scale);
|
leg1.render(scale);
|
||||||
//hair.render(scale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HumanoidModel::renderHorrible( float time, float r, float bob, float yRot, float xRot, float scale )
|
void HumanoidModel::renderHorrible( float time, float r, float bob, float yRot, float xRot, float scale )
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class ItemInstance;
|
|||||||
class HumanoidModel: public Model
|
class HumanoidModel: public Model
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HumanoidModel(float g = 0, float yOffset = 0);
|
HumanoidModel(float g = 0, float yOffset = 0, int texW = 64, int texH = 32);
|
||||||
|
|
||||||
void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale);
|
void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale);
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ public:
|
|||||||
void renderHorrible(float time, float r, float bob, float yRot, float xRot, float scale);
|
void renderHorrible(float time, float r, float bob, float yRot, float xRot, float scale);
|
||||||
void onGraphicsReset();
|
void onGraphicsReset();
|
||||||
|
|
||||||
ModelPart head, /*hair,*/ body, arm0, arm1, leg0, leg1;//, ear;
|
ModelPart head, hair, body, arm0, arm1, leg0, leg1;//, ear;
|
||||||
bool holdingLeftHand;
|
bool holdingLeftHand;
|
||||||
bool holdingRightHand;
|
bool holdingRightHand;
|
||||||
bool sneaking;
|
bool sneaking;
|
||||||
|
|||||||
@@ -50,12 +50,12 @@ Cube::Cube(ModelPart* modelPart, int xTexOffs, int yTexOffs, float x0, float y0,
|
|||||||
VertexPT* l2 = ++ptr;
|
VertexPT* l2 = ++ptr;
|
||||||
VertexPT* l3 = ++ptr;
|
VertexPT* l3 = ++ptr;
|
||||||
|
|
||||||
polygons[0] = PolygonQuad(l1, u1, u2, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + d, yTexOffs + d + h); // Right
|
polygons[0] = PolygonQuad(l1, u1, u2, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + d, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Right
|
||||||
polygons[1] = PolygonQuad(u0, l0, l3, u3, xTexOffs + 0, yTexOffs + d, xTexOffs + d, yTexOffs + d + h); // Left
|
polygons[1] = PolygonQuad(u0, l0, l3, u3, xTexOffs + 0, yTexOffs + d, xTexOffs + d, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Left
|
||||||
polygons[2] = PolygonQuad(l1, l0, u0, u1, xTexOffs + d, yTexOffs + 0, xTexOffs + d + w, yTexOffs + d); // Up
|
polygons[2] = PolygonQuad(l1, l0, u0, u1, xTexOffs + d, yTexOffs + 0, xTexOffs + d + w, yTexOffs + d, modelPart->xTexSize, modelPart->yTexSize); // Up
|
||||||
polygons[3] = PolygonQuad(u2, u3, l3, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + w, yTexOffs); // Down
|
polygons[3] = PolygonQuad(u2, u3, l3, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + w, yTexOffs, modelPart->xTexSize, modelPart->yTexSize); // Down
|
||||||
polygons[4] = PolygonQuad(u1, u0, u3, u2, xTexOffs + d, yTexOffs + d, xTexOffs + d + w, yTexOffs + d + h); // Front
|
polygons[4] = PolygonQuad(u1, u0, u3, u2, xTexOffs + d, yTexOffs + d, xTexOffs + d + w, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Front
|
||||||
polygons[5] = PolygonQuad(l0, l1, l2, l3, xTexOffs + d + w + d, yTexOffs + d, xTexOffs + d + w + d + w, yTexOffs + d + h); // Back
|
polygons[5] = PolygonQuad(l0, l1, l2, l3, xTexOffs + d + w + d, yTexOffs + d, xTexOffs + d + w + d + w, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Back
|
||||||
|
|
||||||
if (modelPart->mirror) {
|
if (modelPart->mirror) {
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ PolygonQuad::PolygonQuad(VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3)
|
|||||||
}
|
}
|
||||||
|
|
||||||
PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3,
|
PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3,
|
||||||
int uu0, int vv0, int uu1, int vv1)
|
int uu0, int vv0, int uu1, int vv1, float texW, float texH)
|
||||||
: _flipNormal(false)
|
: _flipNormal(false)
|
||||||
{
|
{
|
||||||
const float us = -0.002f / 64.0f;//0.1f / 64.0f;
|
const float us = -0.002f / texW;
|
||||||
const float vs = -0.002f / 32.0f;//0.1f / 32.0f;
|
const float vs = -0.002f / texH;
|
||||||
vertices[0] = v0->remap(uu1 / 64.0f - us, vv0 / 32.0f + vs);
|
vertices[0] = v0->remap(uu1 / texW - us, vv0 / texH + vs);
|
||||||
vertices[1] = v1->remap(uu0 / 64.0f + us, vv0 / 32.0f + vs);
|
vertices[1] = v1->remap(uu0 / texW + us, vv0 / texH + vs);
|
||||||
vertices[2] = v2->remap(uu0 / 64.0f + us, vv1 / 32.0f - vs);
|
vertices[2] = v2->remap(uu0 / texW + us, vv1 / texH - vs);
|
||||||
vertices[3] = v3->remap(uu1 / 64.0f - us, vv1 / 32.0f - vs);
|
vertices[3] = v3->remap(uu1 / texW - us, vv1 / texH - vs);
|
||||||
}
|
}
|
||||||
|
|
||||||
PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3,
|
PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class PolygonQuad
|
|||||||
public:
|
public:
|
||||||
PolygonQuad() {}
|
PolygonQuad() {}
|
||||||
PolygonQuad(VertexPT*,VertexPT*,VertexPT*,VertexPT*);
|
PolygonQuad(VertexPT*,VertexPT*,VertexPT*,VertexPT*);
|
||||||
PolygonQuad(VertexPT*,VertexPT*,VertexPT*,VertexPT*, int u0, int v0, int u1, int v1);
|
PolygonQuad(VertexPT*,VertexPT*,VertexPT*,VertexPT*, int u0, int v0, int u1, int v1, float texW = 64.0f, float texH = 32.0f);
|
||||||
PolygonQuad(VertexPT*,VertexPT*,VertexPT*,VertexPT*, float u0, float v0, float u1, float v1);
|
PolygonQuad(VertexPT*,VertexPT*,VertexPT*,VertexPT*, float u0, float v0, float u1, float v1);
|
||||||
|
|
||||||
void mirror();
|
void mirror();
|
||||||
|
|||||||
@@ -18,6 +18,20 @@
|
|||||||
#include "../../network/packet/SendInventoryPacket.h"
|
#include "../../network/packet/SendInventoryPacket.h"
|
||||||
#include "../../network/packet/EntityEventPacket.h"
|
#include "../../network/packet/EntityEventPacket.h"
|
||||||
#include "../../network/packet/PlayerActionPacket.h"
|
#include "../../network/packet/PlayerActionPacket.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <cctype>
|
||||||
|
#include "../../platform/log.h"
|
||||||
|
#include "../../platform/HttpClient.h"
|
||||||
|
#include "../../platform/CThread.h"
|
||||||
|
#include "../../util/StringUtils.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef STANDALONE_SERVER
|
#ifndef STANDALONE_SERVER
|
||||||
#include "../gui/Screen.h"
|
#include "../gui/Screen.h"
|
||||||
#include "../gui/screens/FurnaceScreen.h"
|
#include "../gui/screens/FurnaceScreen.h"
|
||||||
@@ -32,6 +46,250 @@
|
|||||||
#include "../../world/item/ArmorItem.h"
|
#include "../../world/item/ArmorItem.h"
|
||||||
#include "../../network/packet/PlayerArmorEquipmentPacket.h"
|
#include "../../network/packet/PlayerArmorEquipmentPacket.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static bool isBase64(unsigned char c) {
|
||||||
|
return (std::isalnum(c) || (c == '+') || (c == '/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string base64Decode(const std::string& encoded) {
|
||||||
|
static const std::string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
std::string out;
|
||||||
|
int in_len = (int)encoded.size();
|
||||||
|
int i = 0;
|
||||||
|
int in_ = 0;
|
||||||
|
unsigned char char_array_4[4], char_array_3[3];
|
||||||
|
|
||||||
|
while (in_len-- && (encoded[in_] != '=') && isBase64(encoded[in_])) {
|
||||||
|
char_array_4[i++] = encoded[in_]; in_++;
|
||||||
|
if (i == 4) {
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
char_array_4[i] = (unsigned char)base64Chars.find(char_array_4[i]);
|
||||||
|
|
||||||
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||||
|
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
out += char_array_3[i];
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
for (int j = i; j < 4; j++)
|
||||||
|
char_array_4[j] = 0;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
char_array_4[j] = (unsigned char)base64Chars.find(char_array_4[j]);
|
||||||
|
|
||||||
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||||
|
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||||
|
|
||||||
|
for (int j = 0; (j < i - 1); j++)
|
||||||
|
out += char_array_3[j];
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string extractJsonString(const std::string& json, const std::string& key) {
|
||||||
|
std::string search = "\"" + key + "\"";
|
||||||
|
size_t pos = json.find(search);
|
||||||
|
if (pos == std::string::npos) return "";
|
||||||
|
pos = json.find(':', pos + search.size());
|
||||||
|
if (pos == std::string::npos) return "";
|
||||||
|
pos++;
|
||||||
|
while (pos < json.size() && std::isspace((unsigned char)json[pos])) pos++;
|
||||||
|
if (pos >= json.size() || json[pos] != '"') return "";
|
||||||
|
pos++;
|
||||||
|
size_t end = json.find('"', pos);
|
||||||
|
if (end == std::string::npos) return "";
|
||||||
|
return json.substr(pos, end - pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getTextureUrlForUsername(const std::string& username, const std::string& textureKey) {
|
||||||
|
if (username.empty()) {
|
||||||
|
LOGI("[%s] username empty\n", textureKey.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("[%s] resolving UUID for user '%s'...\n", textureKey.c_str(), username.c_str());
|
||||||
|
std::vector<unsigned char> body;
|
||||||
|
std::string apiUrl = "http://api.mojang.com/users/profiles/minecraft/" + username;
|
||||||
|
if (!HttpClient::download(apiUrl, body)) {
|
||||||
|
LOGW("[%s] failed to download UUID for %s\n", textureKey.c_str(), username.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string response(body.begin(), body.end());
|
||||||
|
std::string uuid = extractJsonString(response, "id");
|
||||||
|
if (uuid.empty()) {
|
||||||
|
LOGW("[%s] no UUID found in Mojang response for %s\n", textureKey.c_str(), username.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("[%s] UUID=%s for user %s\n", textureKey.c_str(), uuid.c_str(), username.c_str());
|
||||||
|
|
||||||
|
std::string profileUrl = "http://sessionserver.mojang.com/session/minecraft/profile/" + uuid;
|
||||||
|
if (!HttpClient::download(profileUrl, body)) {
|
||||||
|
LOGW("[%s] failed to download profile for UUID %s\n", textureKey.c_str(), uuid.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
response.assign(body.begin(), body.end());
|
||||||
|
std::string encoded = extractJsonString(response, "value");
|
||||||
|
if (encoded.empty()) {
|
||||||
|
LOGW("[%s] no value field in profile response for UUID %s\n", textureKey.c_str(), uuid.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string decoded = base64Decode(encoded);
|
||||||
|
|
||||||
|
std::string searchKey = "\"" + textureKey + "\"";
|
||||||
|
size_t texturePos = decoded.find(searchKey);
|
||||||
|
if (texturePos == std::string::npos) {
|
||||||
|
LOGW("[%s] no %s entry in decoded profile for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
size_t urlPos = decoded.find("\"url\"", texturePos);
|
||||||
|
if (urlPos == std::string::npos) {
|
||||||
|
LOGW("[%s] no url field under %s for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the URL value from the substring starting at urlPos
|
||||||
|
std::string urlFragment = decoded.substr(urlPos);
|
||||||
|
std::string textureUrl = extractJsonString(urlFragment, "url");
|
||||||
|
if (textureUrl.empty()) {
|
||||||
|
LOGW("[%s] failed to parse %s URL for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("[%s] %s URL for %s: %s\n", textureKey.c_str(), textureKey.c_str(), username.c_str(), textureUrl.c_str());
|
||||||
|
return textureUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getSkinUrlForUsername(const std::string& username) {
|
||||||
|
return getTextureUrlForUsername(username, "SKIN");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getCapeUrlForUsername(const std::string& username) {
|
||||||
|
return getTextureUrlForUsername(username, "CAPE");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ensureDirectoryExists(const std::string& path) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _mkdir(path.c_str()) == 0 || errno == EEXIST;
|
||||||
|
#else
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode))
|
||||||
|
return true;
|
||||||
|
return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fileExists(const std::string& path) {
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path.c_str(), &st) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return (st.st_mode & _S_IFREG) != 0;
|
||||||
|
#else
|
||||||
|
return S_ISREG(st.st_mode);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* fetchSkinForPlayer(void* param) {
|
||||||
|
LocalPlayer* player = (LocalPlayer*)param;
|
||||||
|
if (!player) return NULL;
|
||||||
|
|
||||||
|
LOGI("[Skin] starting skin download for %s\n", player->name.c_str());
|
||||||
|
|
||||||
|
const std::string cacheDir = "data/images/skins";
|
||||||
|
if (!ensureDirectoryExists(cacheDir)) {
|
||||||
|
LOGW("[Skin] failed to create cache directory %s\n", cacheDir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cacheFile = cacheDir + "/" + player->name + ".png";
|
||||||
|
if (fileExists(cacheFile)) {
|
||||||
|
LOGI("[Skin] using cached skin for %s\n", player->name.c_str());
|
||||||
|
player->setTextureName("skins/" + player->name + ".png");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string skinUrl = getSkinUrlForUsername(player->name);
|
||||||
|
if (skinUrl.empty()) {
|
||||||
|
LOGW("[Skin] skin URL lookup failed for %s\n", player->name.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("[Skin] downloading skin from %s\n", skinUrl.c_str());
|
||||||
|
std::vector<unsigned char> skinData;
|
||||||
|
if (!HttpClient::download(skinUrl, skinData) || skinData.empty()) {
|
||||||
|
LOGW("[Skin] download failed for %s\n", skinUrl.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save to cache
|
||||||
|
FILE* fp = fopen(cacheFile.c_str(), "wb");
|
||||||
|
if (fp) {
|
||||||
|
fwrite(skinData.data(), 1, skinData.size(), fp);
|
||||||
|
fclose(fp);
|
||||||
|
LOGI("[Skin] cached skin to %s\n", cacheFile.c_str());
|
||||||
|
} else {
|
||||||
|
LOGW("[Skin] failed to write skin cache %s\n", cacheFile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
player->setTextureName("skins/" + player->name + ".png");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* fetchCapeForPlayer(void* param) {
|
||||||
|
LocalPlayer* player = (LocalPlayer*)param;
|
||||||
|
if (!player) return NULL;
|
||||||
|
|
||||||
|
LOGI("[Cape] starting cape download for %s\n", player->name.c_str());
|
||||||
|
|
||||||
|
const std::string cacheDir = "data/images/capes";
|
||||||
|
if (!ensureDirectoryExists(cacheDir)) {
|
||||||
|
LOGW("[Cape] failed to create cache directory %s\n", cacheDir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cacheFile = cacheDir + "/" + player->name + ".png";
|
||||||
|
if (fileExists(cacheFile)) {
|
||||||
|
LOGI("[Cape] using cached cape for %s\n", player->name.c_str());
|
||||||
|
player->setCapeTextureName("capes/" + player->name + ".png");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string capeUrl = getCapeUrlForUsername(player->name);
|
||||||
|
if (capeUrl.empty()) {
|
||||||
|
LOGW("[Cape] cape URL lookup failed for %s\n", player->name.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("[Cape] downloading cape from %s\n", capeUrl.c_str());
|
||||||
|
std::vector<unsigned char> capeData;
|
||||||
|
if (!HttpClient::download(capeUrl, capeData) || capeData.empty()) {
|
||||||
|
LOGW("[Cape] download failed for %s\n", capeUrl.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save to cache
|
||||||
|
FILE* fp = fopen(cacheFile.c_str(), "wb");
|
||||||
|
if (fp) {
|
||||||
|
fwrite(capeData.data(), 1, capeData.size(), fp);
|
||||||
|
fclose(fp);
|
||||||
|
LOGI("[Cape] cached cape to %s\n", cacheFile.c_str());
|
||||||
|
} else {
|
||||||
|
LOGW("[Cape] failed to write cape cache %s\n", cacheFile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
player->setCapeTextureName("capes/" + player->name + ".png");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//@note: doesn't work completely, since it doesn't care about stairs rotation
|
//@note: doesn't work completely, since it doesn't care about stairs rotation
|
||||||
static bool isJumpable(int tileId) {
|
static bool isJumpable(int tileId) {
|
||||||
return tileId != Tile::fence->id
|
return tileId != Tile::fence->id
|
||||||
@@ -43,6 +301,8 @@ static bool isJumpable(int tileId) {
|
|||||||
&& (Tile::tiles[tileId] != NULL && Tile::tiles[tileId]->getRenderShape() != Tile::SHAPE_STAIRS);
|
&& (Tile::tiles[tileId] != NULL && Tile::tiles[tileId]->getRenderShape() != Tile::SHAPE_STAIRS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, int dimension, bool isCreative)
|
LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, int dimension, bool isCreative)
|
||||||
: Player(level, isCreative),
|
: Player(level, isCreative),
|
||||||
minecraft(minecraft),
|
minecraft(minecraft),
|
||||||
@@ -58,10 +318,11 @@ LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, int dim
|
|||||||
this->dimension = dimension;
|
this->dimension = dimension;
|
||||||
_init();
|
_init();
|
||||||
|
|
||||||
if (user != NULL) {
|
if (user != NULL && !user->name.empty()) {
|
||||||
if (user->name.length() > 0)
|
this->name = user->name;
|
||||||
//customTextureUrl = "http://s3.amazonaws.com/MinecraftSkins/" + user.name + ".png";
|
// Fetch user skin and cape from Mojang servers in the background (avoids blocking the main thread)
|
||||||
this->name = user->name;
|
new CThread(fetchSkinForPlayer, this);
|
||||||
|
new CThread(fetchCapeForPlayer, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +445,7 @@ void LocalPlayer::aiStep() {
|
|||||||
// Sprint: detect W double-tap
|
// Sprint: detect W double-tap
|
||||||
{
|
{
|
||||||
bool forwardHeld = (input->ya > 0);
|
bool forwardHeld = (input->ya > 0);
|
||||||
if (forwardHeld && !prevForwardHeld) {
|
if (forwardHeld && !prevForwardHeld && minecraft->options.useSprinting) {
|
||||||
// leading edge of W press
|
// leading edge of W press
|
||||||
if (sprintDoubleTapTimer > 0)
|
if (sprintDoubleTapTimer > 0)
|
||||||
sprinting = true;
|
sprinting = true;
|
||||||
@@ -273,7 +534,7 @@ void LocalPlayer::move(float xa, float ya, float za) {
|
|||||||
|
|
||||||
float newX = x, newZ = z;
|
float newX = x, newZ = z;
|
||||||
|
|
||||||
if (autoJumpTime <= 0 && autoJumpEnabled)
|
if (autoJumpTime <= 0 && minecraft->options.autoJump)
|
||||||
{
|
{
|
||||||
// auto-jump when crossing the middle of a tile, and the tile in the front is blocked
|
// auto-jump when crossing the middle of a tile, and the tile in the front is blocked
|
||||||
bool jump = false;
|
bool jump = false;
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ private:
|
|||||||
bool sprinting;
|
bool sprinting;
|
||||||
int sprintDoubleTapTimer;
|
int sprintDoubleTapTimer;
|
||||||
bool prevForwardHeld;
|
bool prevForwardHeld;
|
||||||
|
public:
|
||||||
|
void setSprinting(bool sprint) { sprinting = sprint; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*NET_MINECRAFT_CLIENT_PLAYER__LocalPlayer_H__*/
|
#endif /*NET_MINECRAFT_CLIENT_PLAYER__LocalPlayer_H__*/
|
||||||
|
|||||||
@@ -137,12 +137,6 @@ void Chunk::rebuild()
|
|||||||
Tile* tile = Tile::tiles[tileId];
|
Tile* tile = Tile::tiles[tileId];
|
||||||
int renderLayer = tile->getRenderLayer();
|
int renderLayer = tile->getRenderLayer();
|
||||||
|
|
||||||
// if (renderLayer == l)
|
|
||||||
// rendered |= tileRenderer.tesselateInWorld(tile, x, y, z);
|
|
||||||
// else {
|
|
||||||
// _layerChunks[_layerChunkCount[renderLayer]++] = cindex;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (renderLayer > l) {
|
if (renderLayer > l) {
|
||||||
renderNextLayer = true;
|
renderNextLayer = true;
|
||||||
doRenderLayer[renderLayer] = true;
|
doRenderLayer[renderLayer] = true;
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ void GameRenderer::renderLevel(float a) {
|
|||||||
// glDisable2(GL_FOG);
|
// glDisable2(GL_FOG);
|
||||||
setupFog(1);
|
setupFog(1);
|
||||||
|
|
||||||
if (zoom == 1) {
|
if (zoom == 1 && !mc->options.F1) {
|
||||||
TIMER_POP_PUSH("hand");
|
TIMER_POP_PUSH("hand");
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
renderItemInHand(a, i);
|
renderItemInHand(a, i);
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ void ItemInHandRenderer::render( float a )
|
|||||||
glRotatef2(-swing3 * 20, 0, 0, 1);
|
glRotatef2(-swing3 * 20, 0, 0, 1);
|
||||||
// glRotatef2(-swing2 * 80, 1, 0, 0);
|
// glRotatef2(-swing2 * 80, 1, 0, 0);
|
||||||
|
|
||||||
mc->textures->loadAndBindTexture("mob/char.png");
|
mc->textures->loadAndBindTexture(player->getTexture());
|
||||||
glTranslatef2(-1.0f, +3.6f, +3.5f);
|
glTranslatef2(-1.0f, +3.6f, +3.5f);
|
||||||
glRotatef2(120, 0, 0, 1);
|
glRotatef2(120, 0, 0, 1);
|
||||||
glRotatef2(180 + 20, 1, 0, 0);
|
glRotatef2(180 + 20, 1, 0, 0);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ typedef struct TextureData {
|
|||||||
TextureData()
|
TextureData()
|
||||||
: w(0),
|
: w(0),
|
||||||
h(0),
|
h(0),
|
||||||
data(NULL),
|
data(nullptr),
|
||||||
numBytes(0),
|
numBytes(0),
|
||||||
transparent(true),
|
transparent(true),
|
||||||
memoryHandledExternally(false),
|
memoryHandledExternally(false),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "../Options.h"
|
#include "../Options.h"
|
||||||
#include "../../platform/time.h"
|
#include "../../platform/time.h"
|
||||||
#include "../../AppPlatform.h"
|
#include "../../AppPlatform.h"
|
||||||
|
#include "../../util/StringUtils.h"
|
||||||
|
|
||||||
/*static*/ int Textures::textureChanges = 0;
|
/*static*/ int Textures::textureChanges = 0;
|
||||||
/*static*/ bool Textures::MIPMAP = false;
|
/*static*/ bool Textures::MIPMAP = false;
|
||||||
@@ -64,7 +65,8 @@ TextureId Textures::loadTexture( const std::string& resourceName, bool inTexture
|
|||||||
if (it != idMap.end())
|
if (it != idMap.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
TextureData texdata = platform->loadTexture(resourceName, inTextureFolder);
|
bool isUrl = Util::startsWith(resourceName, "http://") || Util::startsWith(resourceName, "https://");
|
||||||
|
TextureData texdata = platform->loadTexture(resourceName, isUrl ? false : inTextureFolder);
|
||||||
if (texdata.data)
|
if (texdata.data)
|
||||||
return assignTexture(resourceName, texdata);
|
return assignTexture(resourceName, texdata);
|
||||||
else if (texdata.identifier != InvalidId) {
|
else if (texdata.identifier != InvalidId) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "TileRenderer.h"
|
#include "TileRenderer.h"
|
||||||
|
#include "Chunk.h"
|
||||||
#include "../Minecraft.h"
|
#include "../Minecraft.h"
|
||||||
#include "Tesselator.h"
|
#include "Tesselator.h"
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ bool TileRenderer::tesselateBlockInWorld( Tile* tt, int x, int y, int z, float r
|
|||||||
float c2 = 0.8f;
|
float c2 = 0.8f;
|
||||||
float c3 = 0.6f;
|
float c3 = 0.6f;
|
||||||
|
|
||||||
|
|
||||||
float r11 = c11 * r;
|
float r11 = c11 * r;
|
||||||
float g11 = c11 * g;
|
float g11 = c11 * g;
|
||||||
float b11 = c11 * b;
|
float b11 = c11 * b;
|
||||||
@@ -128,6 +130,7 @@ bool TileRenderer::tesselateBlockInWorld( Tile* tt, int x, int y, int z, float r
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TileRenderer::tesselateInWorld( Tile* tile, int x, int y, int z, int fixedTexture )
|
void TileRenderer::tesselateInWorld( Tile* tile, int x, int y, int z, int fixedTexture )
|
||||||
{
|
{
|
||||||
this->fixedTexture = fixedTexture;
|
this->fixedTexture = fixedTexture;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ EntityRenderDispatcher::EntityRenderDispatcher()
|
|||||||
assign( ER_SPIDER_RENDERER, new SpiderRenderer());
|
assign( ER_SPIDER_RENDERER, new SpiderRenderer());
|
||||||
assign( ER_TNT_RENDERER, new TntRenderer());
|
assign( ER_TNT_RENDERER, new TntRenderer());
|
||||||
assign( ER_ARROW_RENDERER, new ArrowRenderer());
|
assign( ER_ARROW_RENDERER, new ArrowRenderer());
|
||||||
assign( ER_PLAYER_RENDERER, new PlayerRenderer(new HumanoidModel(), 0));
|
assign( ER_PLAYER_RENDERER, new PlayerRenderer(new HumanoidModel(0, 0, 64, 64), 0));
|
||||||
assign( ER_THROWNEGG_RENDERER, new ItemSpriteRenderer(Item::egg->getIcon(0)));
|
assign( ER_THROWNEGG_RENDERER, new ItemSpriteRenderer(Item::egg->getIcon(0)));
|
||||||
assign( ER_SNOWBALL_RENDERER, new ItemSpriteRenderer(Item::snowBall->getIcon(0)));
|
assign( ER_SNOWBALL_RENDERER, new ItemSpriteRenderer(Item::snowBall->getIcon(0)));
|
||||||
assign( ER_PAINTING_RENDERER, new PaintingRenderer());
|
assign( ER_PAINTING_RENDERER, new PaintingRenderer());
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "EntityRenderDispatcher.h"
|
#include "EntityRenderDispatcher.h"
|
||||||
#include "../ItemInHandRenderer.h"
|
#include "../ItemInHandRenderer.h"
|
||||||
#include "../TileRenderer.h"
|
#include "../TileRenderer.h"
|
||||||
|
#include "../Tesselator.h"
|
||||||
#include "../../model/HumanoidModel.h"
|
#include "../../model/HumanoidModel.h"
|
||||||
#include "../../../world/level/tile/Tile.h"
|
#include "../../../world/level/tile/Tile.h"
|
||||||
#include "../../../world/entity/player/Player.h"
|
#include "../../../world/entity/player/Player.h"
|
||||||
@@ -12,7 +13,9 @@
|
|||||||
|
|
||||||
HumanoidMobRenderer::HumanoidMobRenderer(HumanoidModel* humanoidModel, float shadow)
|
HumanoidMobRenderer::HumanoidMobRenderer(HumanoidModel* humanoidModel, float shadow)
|
||||||
: super(humanoidModel, shadow),
|
: super(humanoidModel, shadow),
|
||||||
humanoidModel(humanoidModel)
|
humanoidModel(humanoidModel),
|
||||||
|
lastCapeXRot(0),
|
||||||
|
lastCapeZRot(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +71,143 @@ void HumanoidMobRenderer::additionalRendering(Mob* mob, float a) {
|
|||||||
entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item);
|
entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item);
|
||||||
glPopMatrix2();
|
glPopMatrix2();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render player cape if available
|
||||||
|
{
|
||||||
|
Player* player = Player::asPlayer(mob);
|
||||||
|
if (player) {
|
||||||
|
const std::string capeTex = player->getCapeTexture();
|
||||||
|
if (!capeTex.empty()) {
|
||||||
|
|
||||||
|
bindTexture(capeTex);
|
||||||
|
|
||||||
|
glPushMatrix2();
|
||||||
|
|
||||||
|
// Attach to player body
|
||||||
|
humanoidModel->body.translateTo(1 / 16.0f);
|
||||||
|
|
||||||
|
// Convert model units (pixels) to world units
|
||||||
|
glScalef2(1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f);
|
||||||
|
|
||||||
|
// Position cape slightly down and behind the shoulders
|
||||||
|
glTranslatef2(0.0f, 1.0f, 2.0f);
|
||||||
|
|
||||||
|
// Java-like cape physics (interpolated inertia + body motion)
|
||||||
|
float pt = a;
|
||||||
|
|
||||||
|
double capeX = player->getCapePrevX() + (player->getCapeX() - player->getCapePrevX()) * pt;
|
||||||
|
double capeY = player->getCapePrevY() + (player->getCapeY() - player->getCapePrevY()) * pt;
|
||||||
|
double capeZ = player->getCapePrevZ() + (player->getCapeZ() - player->getCapePrevZ()) * pt;
|
||||||
|
|
||||||
|
double px = player->xo + (player->x - player->xo) * pt;
|
||||||
|
double py = player->yo + (player->y - player->yo) * pt;
|
||||||
|
double pz = player->zo + (player->z - player->zo) * pt;
|
||||||
|
|
||||||
|
double dx = capeX - px;
|
||||||
|
double dy = capeY - py;
|
||||||
|
double dz = capeZ - pz;
|
||||||
|
|
||||||
|
float bodyYaw = player->yBodyRotO + (player->yBodyRot - player->yBodyRotO) * pt;
|
||||||
|
|
||||||
|
float rad = bodyYaw * Mth::PI / 180.0f;
|
||||||
|
double sinYaw = Mth::sin(rad);
|
||||||
|
double cosYaw = -Mth::cos(rad);
|
||||||
|
|
||||||
|
float forward = (float)(dx * sinYaw + dz * cosYaw) * 100.0f;
|
||||||
|
float sideways = (float)(dx * cosYaw - dz * sinYaw) * 100.0f;
|
||||||
|
if (forward < 0.0f) forward = 0.0f;
|
||||||
|
|
||||||
|
float lift = (float)dy * 10.0f;
|
||||||
|
if (lift < -6.0f) lift = -6.0f;
|
||||||
|
if (lift > 32.0f) lift = 32.0f;
|
||||||
|
|
||||||
|
float walk =
|
||||||
|
Mth::sin((player->walkAnimPos + player->walkAnimSpeed) * 6.0f) *
|
||||||
|
32.0f *
|
||||||
|
player->walkAnimSpeed;
|
||||||
|
|
||||||
|
float capeXRot = 6.0f + forward / 2.0f + lift + walk;
|
||||||
|
float capeZRot = sideways / 2.0f;
|
||||||
|
|
||||||
|
// Smooth out jitter by lerping from the previous frame
|
||||||
|
const float smooth = 0.3f;
|
||||||
|
capeXRot = lastCapeXRot + (capeXRot - lastCapeXRot) * smooth;
|
||||||
|
capeZRot = lastCapeZRot + (capeZRot - lastCapeZRot) * smooth;
|
||||||
|
|
||||||
|
lastCapeXRot = capeXRot;
|
||||||
|
lastCapeZRot = capeZRot;
|
||||||
|
|
||||||
|
glRotatef2(capeXRot, 1.0f, 0.0f, 0.0f);
|
||||||
|
glRotatef2(capeZRot, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
|
||||||
|
// UV coordinates (64x32 skin layout)
|
||||||
|
const float u0 = 1.0f / 64.0f;
|
||||||
|
const float u1 = 11.0f / 64.0f;
|
||||||
|
const float u2 = 12.0f / 64.0f;
|
||||||
|
const float u3 = 22.0f / 64.0f;
|
||||||
|
|
||||||
|
const float uL0 = 0.0f / 64.0f;
|
||||||
|
const float uL1 = 1.0f / 64.0f;
|
||||||
|
|
||||||
|
const float uR0 = 11.0f / 64.0f;
|
||||||
|
const float uR1 = 12.0f / 64.0f;
|
||||||
|
|
||||||
|
const float v0 = 0.0f / 32.0f;
|
||||||
|
const float v1 = 1.0f / 32.0f;
|
||||||
|
|
||||||
|
const float vTop = 1.0f / 32.0f;
|
||||||
|
const float vBottom = 17.0f / 32.0f;
|
||||||
|
|
||||||
|
// Cape size (10x16x1 pixels)
|
||||||
|
const float halfW = 5.0f;
|
||||||
|
const float height = 16.0f;
|
||||||
|
const float depth = 1.0f;
|
||||||
|
|
||||||
|
// Front
|
||||||
|
t.tex(u0, vTop); t.vertex(-halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(u1, vTop); t.vertex(halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(u1, vBottom); t.vertex(halfW, height, 0.0f);
|
||||||
|
t.tex(u0, vBottom); t.vertex(-halfW, height, 0.0f);
|
||||||
|
|
||||||
|
// Back
|
||||||
|
t.tex(u2, vTop); t.vertex(halfW, 0.0f, depth);
|
||||||
|
t.tex(u3, vTop); t.vertex(-halfW, 0.0f, depth);
|
||||||
|
t.tex(u3, vBottom); t.vertex(-halfW, height, depth);
|
||||||
|
t.tex(u2, vBottom); t.vertex(halfW, height, depth);
|
||||||
|
|
||||||
|
// Left
|
||||||
|
t.tex(uL0, vTop); t.vertex(-halfW, 0.0f, depth);
|
||||||
|
t.tex(uL1, vTop); t.vertex(-halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(uL1, vBottom); t.vertex(-halfW, height, 0.0f);
|
||||||
|
t.tex(uL0, vBottom); t.vertex(-halfW, height, depth);
|
||||||
|
|
||||||
|
// Right
|
||||||
|
t.tex(uR0, vTop); t.vertex(halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(uR1, vTop); t.vertex(halfW, 0.0f, depth);
|
||||||
|
t.tex(uR1, vBottom); t.vertex(halfW, height, depth);
|
||||||
|
t.tex(uR0, vBottom); t.vertex(halfW, height, 0.0f);
|
||||||
|
|
||||||
|
// Top
|
||||||
|
t.tex(u0, v0); t.vertex(-halfW, 0.0f, depth);
|
||||||
|
t.tex(u1, v0); t.vertex(halfW, 0.0f, depth);
|
||||||
|
t.tex(u1, v1); t.vertex(halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(u0, v1); t.vertex(-halfW, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
// Bottom
|
||||||
|
t.tex(u2, v0); t.vertex(halfW, height, 0.0f);
|
||||||
|
t.tex(u3, v0); t.vertex(-halfW, height, 0.0f);
|
||||||
|
t.tex(u3, v1); t.vertex(-halfW, height, depth);
|
||||||
|
t.tex(u2, v1); t.vertex(halfW, height, depth);
|
||||||
|
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
glPopMatrix2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HumanoidMobRenderer::render( Entity* mob_, float x, float y, float z, float rot, float a ) {
|
void HumanoidMobRenderer::render( Entity* mob_, float x, float y, float z, float rot, float a ) {
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
HumanoidModel* humanoidModel;
|
HumanoidModel* humanoidModel;
|
||||||
|
|
||||||
|
// Last rotation values for cape smoothing (reduces jitter)
|
||||||
|
float lastCapeXRot;
|
||||||
|
float lastCapeZRot;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/
|
#endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ static const std::string armorFilenames[10] = {
|
|||||||
|
|
||||||
PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow )
|
PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow )
|
||||||
: super(humanoidModel, shadow),
|
: super(humanoidModel, shadow),
|
||||||
armorParts1(new HumanoidModel(1.0f)),
|
armorParts1(new HumanoidModel(1.0f, 0, 64, 64)),
|
||||||
armorParts2(new HumanoidModel(0.5f))
|
armorParts2(new HumanoidModel(0.5f, 0, 64, 64))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ int transformKey(int glfwkey) {
|
|||||||
case GLFW_KEY_BACKSPACE: return Keyboard::KEY_BACKSPACE;
|
case GLFW_KEY_BACKSPACE: return Keyboard::KEY_BACKSPACE;
|
||||||
case GLFW_KEY_LEFT_SHIFT: return Keyboard::KEY_LSHIFT;
|
case GLFW_KEY_LEFT_SHIFT: return Keyboard::KEY_LSHIFT;
|
||||||
case GLFW_KEY_ENTER: return Keyboard::KEY_RETURN;
|
case GLFW_KEY_ENTER: return Keyboard::KEY_RETURN;
|
||||||
|
case GLFW_KEY_LEFT_CONTROL: return Keyboard::KEY_LEFT_CTRL;
|
||||||
default: return glfwkey;
|
default: return glfwkey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,14 @@ LRESULT WINAPI windowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|||||||
Multitouch::feed(0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0);
|
Multitouch::feed(0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case WM_MOUSEWHEEL: {
|
||||||
|
// wheel delta is multiples of WHEEL_DELTA (120); convert to +/-1
|
||||||
|
int delta = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
|
||||||
|
short x = GET_X_LPARAM(lParam);
|
||||||
|
short y = GET_Y_LPARAM(lParam);
|
||||||
|
Mouse::feed(MouseAction::ACTION_WHEEL, 0, x, y, 0, delta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (uMsg == WM_NCDESTROY) g_running = false;
|
if (uMsg == WM_NCDESTROY) g_running = false;
|
||||||
else {
|
else {
|
||||||
|
|||||||
338
src/platform/HttpClient.cpp
Normal file
338
src/platform/HttpClient.cpp
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
#include "HttpClient.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <winhttp.h>
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
#pragma comment(lib, "winhttp.lib")
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool startsWith(const std::string& s, const std::string& prefix) {
|
||||||
|
return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseUrl(const std::string& url, std::string& scheme, std::string& host, int& port, std::string& path);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
bool downloadHttpsWinHttp(const std::string& url, std::vector<unsigned char>& outBody) {
|
||||||
|
outBody.clear();
|
||||||
|
|
||||||
|
std::string scheme, host, path;
|
||||||
|
int port = 0;
|
||||||
|
if (!parseUrl(url, scheme, host, port, path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// WinHTTP expects the path to include the leading '/'.
|
||||||
|
HINTERNET hSession = WinHttpOpen(L"MinecraftPE/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
|
||||||
|
if (!hSession)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HINTERNET hConnect = WinHttpConnect(hSession, std::wstring(host.begin(), host.end()).c_str(), port, 0);
|
||||||
|
if (!hConnect) {
|
||||||
|
WinHttpCloseHandle(hSession);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HINTERNET hRequest = WinHttpOpenRequest(
|
||||||
|
hConnect,
|
||||||
|
L"GET",
|
||||||
|
std::wstring(path.begin(), path.end()).c_str(),
|
||||||
|
NULL,
|
||||||
|
WINHTTP_NO_REFERER,
|
||||||
|
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||||
|
WINHTTP_FLAG_SECURE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hRequest) {
|
||||||
|
WinHttpCloseHandle(hConnect);
|
||||||
|
WinHttpCloseHandle(hSession);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD redirectPolicy = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
|
||||||
|
WinHttpSetOption(hRequest, WINHTTP_OPTION_REDIRECT_POLICY, &redirectPolicy, sizeof(redirectPolicy));
|
||||||
|
|
||||||
|
BOOL result = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
|
||||||
|
if (!result) {
|
||||||
|
WinHttpCloseHandle(hRequest);
|
||||||
|
WinHttpCloseHandle(hConnect);
|
||||||
|
WinHttpCloseHandle(hSession);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = WinHttpReceiveResponse(hRequest, NULL);
|
||||||
|
if (!result) {
|
||||||
|
WinHttpCloseHandle(hRequest);
|
||||||
|
WinHttpCloseHandle(hConnect);
|
||||||
|
WinHttpCloseHandle(hSession);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD bytesAvailable = 0;
|
||||||
|
while (WinHttpQueryDataAvailable(hRequest, &bytesAvailable) && bytesAvailable > 0) {
|
||||||
|
std::vector<unsigned char> buffer(bytesAvailable);
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
if (!WinHttpReadData(hRequest, buffer.data(), bytesAvailable, &bytesRead) || bytesRead == 0)
|
||||||
|
break;
|
||||||
|
outBody.insert(outBody.end(), buffer.begin(), buffer.begin() + bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
WinHttpCloseHandle(hRequest);
|
||||||
|
WinHttpCloseHandle(hConnect);
|
||||||
|
WinHttpCloseHandle(hSession);
|
||||||
|
|
||||||
|
return !outBody.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string toLower(const std::string& s) {
|
||||||
|
std::string out = s;
|
||||||
|
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseUrl(const std::string& url, std::string& scheme, std::string& host, int& port, std::string& path) {
|
||||||
|
scheme.clear();
|
||||||
|
host.clear();
|
||||||
|
path.clear();
|
||||||
|
port = 0;
|
||||||
|
|
||||||
|
// Very simple URL parser.
|
||||||
|
// url format: scheme://host[:port]/path
|
||||||
|
auto pos = url.find("://");
|
||||||
|
if (pos == std::string::npos) return false;
|
||||||
|
scheme = toLower(url.substr(0, pos));
|
||||||
|
size_t start = pos + 3;
|
||||||
|
|
||||||
|
size_t slash = url.find('/', start);
|
||||||
|
std::string hostPort = (slash == std::string::npos) ? url.substr(start) : url.substr(start, slash - start);
|
||||||
|
path = (slash == std::string::npos) ? "/" : url.substr(slash);
|
||||||
|
|
||||||
|
size_t colon = hostPort.find(':');
|
||||||
|
if (colon != std::string::npos) {
|
||||||
|
host = hostPort.substr(0, colon);
|
||||||
|
port = atoi(hostPort.c_str() + colon + 1);
|
||||||
|
} else {
|
||||||
|
host = hostPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scheme == "http") {
|
||||||
|
if (port == 0) port = 80;
|
||||||
|
} else if (scheme == "https") {
|
||||||
|
if (port == 0) port = 443;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !host.empty() && !scheme.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readAll(int sockfd, std::vector<unsigned char>& out) {
|
||||||
|
const int BUF_SIZE = 4096;
|
||||||
|
unsigned char buffer[BUF_SIZE];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int received = recv(sockfd, (char*)buffer, BUF_SIZE, 0);
|
||||||
|
if (received <= 0)
|
||||||
|
break;
|
||||||
|
out.insert(out.end(), buffer, buffer + received);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resolveAndConnect(const std::string& host, int port, int& outSock) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
static bool initialized = false;
|
||||||
|
if (!initialized) {
|
||||||
|
WSADATA wsaData;
|
||||||
|
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo* result = NULL;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
|
std::ostringstream portStream;
|
||||||
|
portStream << port;
|
||||||
|
const std::string portStr = portStream.str();
|
||||||
|
if (getaddrinfo(host.c_str(), portStr.c_str(), &hints, &result) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int sock = -1;
|
||||||
|
for (struct addrinfo* rp = result; rp != NULL; rp = rp->ai_next) {
|
||||||
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
|
if (sock < 0) continue;
|
||||||
|
if (connect(sock, rp->ai_addr, (int)rp->ai_addrlen) == 0)
|
||||||
|
break; // success
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
closesocket(sock);
|
||||||
|
#else
|
||||||
|
close(sock);
|
||||||
|
#endif
|
||||||
|
sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
|
if (sock < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
outSock = sock;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getHeaderValue(const std::string& headers, const std::string& key) {
|
||||||
|
std::string lower = toLower(headers);
|
||||||
|
std::string lowerKey = toLower(key);
|
||||||
|
size_t pos = lower.find(lowerKey);
|
||||||
|
if (pos == std::string::npos) return "";
|
||||||
|
size_t colon = lower.find(':', pos + lowerKey.size());
|
||||||
|
if (colon == std::string::npos) return "";
|
||||||
|
size_t start = colon + 1;
|
||||||
|
while (start < lower.size() && (lower[start] == ' ' || lower[start] == '\t')) start++;
|
||||||
|
size_t end = lower.find('\r', start);
|
||||||
|
if (end == std::string::npos) end = lower.find('\n', start);
|
||||||
|
if (end == std::string::npos) end = lower.size();
|
||||||
|
return headers.substr(start, end - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool extractStatusCode(const std::string& headers, int& outStatus) {
|
||||||
|
size_t pos = headers.find(" ");
|
||||||
|
if (pos == std::string::npos) return false;
|
||||||
|
size_t pos2 = headers.find(" ", pos + 1);
|
||||||
|
if (pos2 == std::string::npos) return false;
|
||||||
|
std::string code = headers.substr(pos + 1, pos2 - pos - 1);
|
||||||
|
outStatus = atoi(code.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
namespace HttpClient {
|
||||||
|
|
||||||
|
bool download(const std::string& url, std::vector<unsigned char>& outBody) {
|
||||||
|
outBody.clear();
|
||||||
|
|
||||||
|
std::string currentUrl = url;
|
||||||
|
for (int redirect = 0; redirect < 3; ++redirect) {
|
||||||
|
std::string scheme, host, path;
|
||||||
|
int port = 0;
|
||||||
|
if (!parseUrl(currentUrl, scheme, host, port, path)) {
|
||||||
|
LOGW("[HttpClient] parseUrl failed for '%s'\n", currentUrl.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scheme == "https") {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
LOGI("[HttpClient] using WinHTTP for HTTPS URL %s\n", currentUrl.c_str());
|
||||||
|
return downloadHttpsWinHttp(currentUrl, outBody);
|
||||||
|
#else
|
||||||
|
LOGW("[HttpClient] HTTPS not supported on this platform: %s\n", currentUrl.c_str());
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scheme != "http") {
|
||||||
|
LOGW("[HttpClient] unsupported scheme '%s' for URL '%s'\n", scheme.c_str(), currentUrl.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock = -1;
|
||||||
|
if (!resolveAndConnect(host, port, sock)) {
|
||||||
|
LOGW("[HttpClient] resolve/connect failed for %s:%d\n", host.c_str(), port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string request = "GET " + path + " HTTP/1.1\r\n";
|
||||||
|
request += "Host: " + host + "\r\n";
|
||||||
|
request += "User-Agent: MinecraftPE\r\n";
|
||||||
|
request += "Connection: close\r\n";
|
||||||
|
request += "\r\n";
|
||||||
|
|
||||||
|
send(sock, request.c_str(), (int)request.size(), 0);
|
||||||
|
|
||||||
|
std::vector<unsigned char> raw;
|
||||||
|
readAll(sock, raw);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
closesocket(sock);
|
||||||
|
#else
|
||||||
|
close(sock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (raw.empty()) {
|
||||||
|
LOGW("[HttpClient] no response data from %s\n", currentUrl.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split headers and body
|
||||||
|
const std::string delim = "\r\n\r\n";
|
||||||
|
auto it = std::search(raw.begin(), raw.end(), delim.begin(), delim.end());
|
||||||
|
if (it == raw.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t headerLen = it - raw.begin();
|
||||||
|
std::string headers(reinterpret_cast<const char*>(raw.data()), headerLen);
|
||||||
|
size_t bodyStart = headerLen + delim.size();
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
if (!extractStatusCode(headers, status))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (status == 301 || status == 302 || status == 307 || status == 308) {
|
||||||
|
std::string location = getHeaderValue(headers, "Location");
|
||||||
|
if (location.empty()) {
|
||||||
|
LOGW("[HttpClient] redirect without Location header for %s\n", currentUrl.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOGI("[HttpClient] redirect %s -> %s\n", currentUrl.c_str(), location.c_str());
|
||||||
|
currentUrl = location;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != 200) {
|
||||||
|
std::string bodySnippet;
|
||||||
|
if (!outBody.empty()) {
|
||||||
|
size_t len = std::min(outBody.size(), (size_t)1024);
|
||||||
|
bodySnippet.assign(outBody.begin(), outBody.begin() + len);
|
||||||
|
}
|
||||||
|
LOGW("[HttpClient] HTTP status %d for %s\n", status, currentUrl.c_str());
|
||||||
|
LOGW("[HttpClient] Headers:\n%s\n", headers.c_str());
|
||||||
|
LOGW("[HttpClient] Body (up to 1024 bytes):\n%s\n", bodySnippet.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBody.assign(raw.begin() + bodyStart, raw.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace HttpClient
|
||||||
16
src/platform/HttpClient.h
Normal file
16
src/platform/HttpClient.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef HTTPCLIENT_H__
|
||||||
|
#define HTTPCLIENT_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace HttpClient {
|
||||||
|
|
||||||
|
/// Download the given URL into "outBody".
|
||||||
|
/// Returns true if the download completed successfully (HTTP 200) and the body is in outBody.
|
||||||
|
/// This function supports plain HTTP only (no TLS). It will follow up to 3 redirects.
|
||||||
|
bool download(const std::string& url, std::vector<unsigned char>& outBody);
|
||||||
|
|
||||||
|
} // namespace HttpClient
|
||||||
|
|
||||||
|
#endif /* HTTPCLIENT_H__ */
|
||||||
94
src/platform/PngLoader.cpp
Normal file
94
src/platform/PngLoader.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include "PngLoader.h"
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
struct MemoryReader {
|
||||||
|
const unsigned char* data;
|
||||||
|
size_t size;
|
||||||
|
size_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pngMemoryRead(png_structp pngPtr, png_bytep outBytes, png_size_t byteCountToRead) {
|
||||||
|
MemoryReader* reader = (MemoryReader*)png_get_io_ptr(pngPtr);
|
||||||
|
if (!reader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (reader->pos + byteCountToRead > reader->size) {
|
||||||
|
png_error(pngPtr, "Read past end of buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(outBytes, reader->data + reader->pos, byteCountToRead);
|
||||||
|
reader->pos += byteCountToRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureData loadPngFromMemory(const unsigned char* data, size_t size) {
|
||||||
|
TextureData out;
|
||||||
|
if (!data || size == 0) return out;
|
||||||
|
|
||||||
|
png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (!pngPtr) return out;
|
||||||
|
|
||||||
|
png_infop infoPtr = png_create_info_struct(pngPtr);
|
||||||
|
if (!infoPtr) {
|
||||||
|
png_destroy_read_struct(&pngPtr, NULL, NULL);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(pngPtr))) {
|
||||||
|
png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryReader reader;
|
||||||
|
reader.data = data;
|
||||||
|
reader.size = size;
|
||||||
|
reader.pos = 0;
|
||||||
|
|
||||||
|
png_set_read_fn(pngPtr, &reader, pngMemoryRead);
|
||||||
|
png_read_info(pngPtr, infoPtr);
|
||||||
|
|
||||||
|
// Convert any color type to 8-bit RGBA
|
||||||
|
if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_palette_to_rgb(pngPtr);
|
||||||
|
if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(pngPtr, infoPtr) < 8)
|
||||||
|
png_set_expand_gray_1_2_4_to_8(pngPtr);
|
||||||
|
if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS))
|
||||||
|
png_set_tRNS_to_alpha(pngPtr);
|
||||||
|
if (png_get_bit_depth(pngPtr, infoPtr) == 16)
|
||||||
|
png_set_strip_16(pngPtr);
|
||||||
|
|
||||||
|
// Ensure we always have RGBA (4 bytes per pixel)
|
||||||
|
// Only add alpha if the image lacks it (e.g., RGB skin files).
|
||||||
|
png_set_gray_to_rgb(pngPtr);
|
||||||
|
|
||||||
|
// Handle interlaced PNGs properly
|
||||||
|
int number_passes = png_set_interlace_handling(pngPtr);
|
||||||
|
|
||||||
|
png_read_update_info(pngPtr, infoPtr);
|
||||||
|
|
||||||
|
int colorType = png_get_color_type(pngPtr, infoPtr);
|
||||||
|
if (colorType == PNG_COLOR_TYPE_RGB) {
|
||||||
|
png_set_filler(pngPtr, 0xFF, PNG_FILLER_AFTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.w = png_get_image_width(pngPtr, infoPtr);
|
||||||
|
out.h = png_get_image_height(pngPtr, infoPtr);
|
||||||
|
|
||||||
|
png_bytep* rowPtrs = new png_bytep[out.h];
|
||||||
|
out.data = new unsigned char[4 * out.w * out.h];
|
||||||
|
out.memoryHandledExternally = false;
|
||||||
|
|
||||||
|
int rowStrideBytes = 4 * out.w;
|
||||||
|
for (int i = 0; i < out.h; i++) {
|
||||||
|
rowPtrs[i] = (png_bytep)&out.data[i*rowStrideBytes];
|
||||||
|
}
|
||||||
|
|
||||||
|
png_read_image(pngPtr, rowPtrs);
|
||||||
|
|
||||||
|
png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
|
||||||
|
delete[] rowPtrs;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
12
src/platform/PngLoader.h
Normal file
12
src/platform/PngLoader.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef PNGLOADER_H__
|
||||||
|
#define PNGLOADER_H__
|
||||||
|
|
||||||
|
#include "../client/renderer/TextureData.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
/// Decode a PNG (from memory) into a TextureData.
|
||||||
|
/// Returns an empty TextureData on failure.
|
||||||
|
TextureData loadPngFromMemory(const unsigned char* data, size_t size);
|
||||||
|
|
||||||
|
#endif // PNGLOADER_H__
|
||||||
@@ -71,9 +71,11 @@ public:
|
|||||||
static const int KEY_F11 = 122;
|
static const int KEY_F11 = 122;
|
||||||
static const int KEY_F12 = 123;
|
static const int KEY_F12 = 123;
|
||||||
|
|
||||||
|
|
||||||
static const int KEY_ESCAPE = 27;
|
static const int KEY_ESCAPE = 27;
|
||||||
static const int KEY_SPACE = 32;
|
static const int KEY_SPACE = 32;
|
||||||
static const int KEY_LSHIFT = 10;
|
static const int KEY_LSHIFT = 10;
|
||||||
|
static const int KEY_LEFT_CTRL = 232;
|
||||||
|
|
||||||
static bool isKeyDown(int keyCode) {
|
static bool isKeyDown(int keyCode) {
|
||||||
return _states[keyCode] == KeyboardAction::KEYDOWN;
|
return _states[keyCode] == KeyboardAction::KEYDOWN;
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ static const unsigned int MAX_OFFLINE_DATA_LENGTH=400; // I set this because I l
|
|||||||
#pragma warning(disable:4309) // 'initializing' : truncation of constant value
|
#pragma warning(disable:4309) // 'initializing' : truncation of constant value
|
||||||
#endif
|
#endif
|
||||||
// Make sure highest bit is 0, so isValid in DatagramHeaderFormat is false
|
// Make sure highest bit is 0, so isValid in DatagramHeaderFormat is false
|
||||||
static const char OFFLINE_MESSAGE_DATA_ID[16]={0x00,0xFF,0xFF,0x00,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFD,0xFD,0x12,0x34,0x56,0x78};
|
static const unsigned char OFFLINE_MESSAGE_DATA_ID[16]={0x00,0xFF,0xFF,0x00,0xFE,0xFE,0xFE,0xFE,0xFD,0xFD,0xFD,0xFD,0x12,0x34,0x56,0x78};
|
||||||
|
|
||||||
struct PacketFollowedByData
|
struct PacketFollowedByData
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ Mob::Mob(Level* level)
|
|||||||
invulnerableDuration(20),
|
invulnerableDuration(20),
|
||||||
//hasHair(false),
|
//hasHair(false),
|
||||||
textureName("mob/char.png"),
|
textureName("mob/char.png"),
|
||||||
|
capeTextureName(""),
|
||||||
allowAlpha(true),
|
allowAlpha(true),
|
||||||
modelName(""),
|
modelName(""),
|
||||||
bobStrength(1),
|
bobStrength(1),
|
||||||
@@ -82,6 +83,15 @@ Mob::Mob(Level* level)
|
|||||||
yRot = (float) (Mth::random() * Mth::PI * 2);
|
yRot = (float) (Mth::random() * Mth::PI * 2);
|
||||||
|
|
||||||
this->footSize = 0.5f;
|
this->footSize = 0.5f;
|
||||||
|
|
||||||
|
// Initialize cape inertia positions
|
||||||
|
xCape = x;
|
||||||
|
yCape = y;
|
||||||
|
zCape = z;
|
||||||
|
|
||||||
|
xc = xCape;
|
||||||
|
yc = yCape;
|
||||||
|
zc = zCape;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mob::~Mob() {
|
Mob::~Mob() {
|
||||||
@@ -110,6 +120,21 @@ std::string Mob::getTexture()
|
|||||||
return textureName;
|
return textureName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mob::setTextureName(const std::string& name)
|
||||||
|
{
|
||||||
|
textureName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Mob::getCapeTexture()
|
||||||
|
{
|
||||||
|
return capeTextureName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::setCapeTextureName(const std::string& name)
|
||||||
|
{
|
||||||
|
capeTextureName = name;
|
||||||
|
}
|
||||||
|
|
||||||
bool Mob::isPickable()
|
bool Mob::isPickable()
|
||||||
{
|
{
|
||||||
return !removed;
|
return !removed;
|
||||||
@@ -269,6 +294,10 @@ void Mob::superTick()
|
|||||||
|
|
||||||
void Mob::tick()
|
void Mob::tick()
|
||||||
{
|
{
|
||||||
|
xc = xCape;
|
||||||
|
yc = yCape;
|
||||||
|
zc = zCape;
|
||||||
|
|
||||||
super::tick();
|
super::tick();
|
||||||
|
|
||||||
if (arrowCount > 0) {
|
if (arrowCount > 0) {
|
||||||
@@ -373,6 +402,18 @@ void Mob::tick()
|
|||||||
while (xRot - xRotO >= 180)
|
while (xRot - xRotO >= 180)
|
||||||
xRotO += 360;
|
xRotO += 360;
|
||||||
animStep += walkSpeed;
|
animStep += walkSpeed;
|
||||||
|
|
||||||
|
// Reduce jitter by using a smaller interpolation factor (more lag, smoother motion)
|
||||||
|
double dxCape = x - xCape;
|
||||||
|
double dyCape = y - yCape;
|
||||||
|
double dzCape = z - zCape;
|
||||||
|
|
||||||
|
const double interp = 0.15; // small value for smoother cape motion
|
||||||
|
const double interpY = 0.12; // extra smoothing on vertical movement
|
||||||
|
|
||||||
|
xCape += dxCape * interp;
|
||||||
|
yCape += dyCape * interpY;
|
||||||
|
zCape += dzCape * interp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::setSize( float w, float h )
|
void Mob::setSize( float w, float h )
|
||||||
|
|||||||
@@ -42,10 +42,16 @@ public:
|
|||||||
|
|
||||||
virtual void spawnAnim();
|
virtual void spawnAnim();
|
||||||
virtual std::string getTexture();
|
virtual std::string getTexture();
|
||||||
|
virtual void setTextureName(const std::string& name);
|
||||||
|
|
||||||
virtual bool isAlive();
|
// Optional player cape texture (non-null on clients when available)
|
||||||
|
virtual std::string getCapeTexture();
|
||||||
|
virtual void setCapeTextureName(const std::string& name);
|
||||||
|
|
||||||
|
virtual bool isAlive();
|
||||||
virtual bool isPickable();
|
virtual bool isPickable();
|
||||||
virtual bool isPushable();
|
virtual bool isPushable();
|
||||||
|
|
||||||
virtual bool isShootable();
|
virtual bool isShootable();
|
||||||
|
|
||||||
MoveControl* getMoveControl();
|
MoveControl* getMoveControl();
|
||||||
@@ -212,7 +218,22 @@ protected:
|
|||||||
float walkingSpeed;
|
float walkingSpeed;
|
||||||
float flyingSpeed;
|
float flyingSpeed;
|
||||||
|
|
||||||
|
// Cape inertia positions
|
||||||
|
double xCape, yCape, zCape;
|
||||||
|
double xc, yc, zc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Cape position accessors (for renderers)
|
||||||
|
double getCapeX() const { return xCape; }
|
||||||
|
double getCapeY() const { return yCape; }
|
||||||
|
double getCapeZ() const { return zCape; }
|
||||||
|
|
||||||
|
double getCapePrevX() const { return xc; }
|
||||||
|
double getCapePrevY() const { return yc; }
|
||||||
|
double getCapePrevZ() const { return zc; }
|
||||||
|
|
||||||
std::string textureName;
|
std::string textureName;
|
||||||
|
std::string capeTextureName;
|
||||||
std::string modelName;
|
std::string modelName;
|
||||||
int deathScore;
|
int deathScore;
|
||||||
float oRun, run;
|
float oRun, run;
|
||||||
|
|||||||
@@ -255,16 +255,16 @@ void Inventory::setupDefault() {
|
|||||||
} else {
|
} else {
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
// Survival
|
// Survival
|
||||||
addItem(new ItemInstance(Item::ironIngot, 64));
|
// addItem(new ItemInstance(Item::ironIngot, 64));
|
||||||
addItem(new ItemInstance(Item::ironIngot, 34));
|
// addItem(new ItemInstance(Item::ironIngot, 34));
|
||||||
addItem(new ItemInstance(Tile::stonecutterBench));
|
// addItem(new ItemInstance(Tile::stonecutterBench));
|
||||||
addItem(new ItemInstance(Tile::workBench));
|
// addItem(new ItemInstance(Tile::workBench));
|
||||||
addItem(new ItemInstance(Tile::furnace));
|
// addItem(new ItemInstance(Tile::furnace));
|
||||||
addItem(new ItemInstance(Tile::wood, 54));
|
// addItem(new ItemInstance(Tile::wood, 54));
|
||||||
addItem(new ItemInstance(Item::stick, 14));
|
// addItem(new ItemInstance(Item::stick, 14));
|
||||||
addItem(new ItemInstance(Item::coal, 31));
|
// addItem(new ItemInstance(Item::coal, 31));
|
||||||
addItem(new ItemInstance(Tile::sand, 6));
|
// addItem(new ItemInstance(Tile::sand, 6));
|
||||||
addItem(new ItemInstance(Item::dye_powder, 23, DyePowderItem::PURPLE));
|
// addItem(new ItemInstance(Item::dye_powder, 23, DyePowderItem::PURPLE));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,13 +14,14 @@ namespace GameType {
|
|||||||
class LevelSettings
|
class LevelSettings
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LevelSettings(long seed, int gameType)
|
LevelSettings(long seed, int gameType, bool allowCheats = false)
|
||||||
: seed(seed),
|
: seed(seed),
|
||||||
gameType(gameType)
|
gameType(gameType),
|
||||||
|
allowCheats(allowCheats)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
static LevelSettings None() {
|
static LevelSettings None() {
|
||||||
return LevelSettings(-1,-1);
|
return LevelSettings(-1,-1,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
long getSeed() const {
|
long getSeed() const {
|
||||||
@@ -31,6 +32,10 @@ public:
|
|||||||
return gameType;
|
return gameType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getAllowCheats() const {
|
||||||
|
return allowCheats;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Those two should actually not be here
|
// Those two should actually not be here
|
||||||
// @todo: Move out when we add LevelSettings.cpp :p
|
// @todo: Move out when we add LevelSettings.cpp :p
|
||||||
@@ -53,6 +58,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
const long seed;
|
const long seed;
|
||||||
const int gameType;
|
const int gameType;
|
||||||
|
const bool allowCheats;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*NET_MINECRAFT_WORLD_LEVEL__LevelSettings_H__*/
|
#endif /*NET_MINECRAFT_WORLD_LEVEL__LevelSettings_H__*/
|
||||||
|
|||||||
@@ -287,53 +287,58 @@ void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) {
|
|||||||
feature.place(level, &random, x, y, z);
|
feature.place(level, &random, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++) {
|
// Coal: common, wide Y range, moderate vein size
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
int x = xo + random.nextInt(16);
|
int x = xo + random.nextInt(16);
|
||||||
int y = random.nextInt(128);
|
int y = random.nextInt(128);
|
||||||
int z = zo + random.nextInt(16);
|
int z = zo + random.nextInt(16);
|
||||||
OreFeature feature(Tile::coalOre->id, 16);
|
OreFeature feature(Tile::coalOre->id, 14);
|
||||||
feature.place(level, &random, x, y, z);
|
feature.place(level, &random, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++) {
|
// Iron: common, limited to upper underground
|
||||||
|
for (int i = 0; i < 14; i++) {
|
||||||
int x = xo + random.nextInt(16);
|
int x = xo + random.nextInt(16);
|
||||||
int y = random.nextInt(64);
|
int y = random.nextInt(64);
|
||||||
int z = zo + random.nextInt(16);
|
int z = zo + random.nextInt(16);
|
||||||
OreFeature feature(Tile::ironOre->id, 8);
|
OreFeature feature(Tile::ironOre->id, 10);
|
||||||
feature.place(level, &random, x, y, z);
|
feature.place(level, &random, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gold: rarer and deeper
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
int x = xo + random.nextInt(16);
|
int x = xo + random.nextInt(16);
|
||||||
int y = random.nextInt(32);
|
int y = random.nextInt(32);
|
||||||
int z = zo + random.nextInt(16);
|
int z = zo + random.nextInt(16);
|
||||||
OreFeature feature(Tile::goldOre->id, 8);
|
OreFeature feature(Tile::goldOre->id, 9);
|
||||||
feature.place(level, &random, x, y, z);
|
feature.place(level, &random, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
// Redstone: somewhat common at low depths
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
int x = xo + random.nextInt(16);
|
int x = xo + random.nextInt(16);
|
||||||
int y = random.nextInt(16);
|
int y = random.nextInt(16);
|
||||||
int z = zo + random.nextInt(16);
|
int z = zo + random.nextInt(16);
|
||||||
OreFeature feature(Tile::redStoneOre->id, 7);
|
OreFeature feature(Tile::redStoneOre->id, 8);
|
||||||
feature.place(level, &random, x, y, z);
|
feature.place(level, &random, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 1; i++) {
|
// Emerald (diamond-equivalent): still rare but slightly more than vanilla
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
int x = xo + random.nextInt(16);
|
int x = xo + random.nextInt(16);
|
||||||
int y = random.nextInt(16);
|
int y = random.nextInt(16);
|
||||||
int z = zo + random.nextInt(16);
|
int z = zo + random.nextInt(16);
|
||||||
OreFeature feature(Tile::emeraldOre->id, 7);
|
OreFeature feature(Tile::emeraldOre->id, 6);
|
||||||
feature.place(level, &random, x, y, z);
|
feature.place(level, &random, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// lapis ore
|
// Lapis: rare and not in very high Y
|
||||||
for (int i = 0; i < 1; i++) {
|
for (int i = 0; i < 1; i++) {
|
||||||
int x = xo + random.nextInt(16);
|
int x = xo + random.nextInt(16);
|
||||||
int y = random.nextInt(16) + random.nextInt(16);
|
int y = random.nextInt(16) + random.nextInt(16);
|
||||||
int z = zo + random.nextInt(16);
|
int z = zo + random.nextInt(16);
|
||||||
OreFeature feature(Tile::lapisOre->id, 6);
|
OreFeature feature(Tile::lapisOre->id, 6);
|
||||||
feature.place(level, &random, x, y, z);
|
feature.place(level, &random, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float ss = 0.5f;
|
const float ss = 0.5f;
|
||||||
@@ -504,7 +509,8 @@ LevelChunk* RandomLevelSource::getChunk(int xOffs, int zOffs) {
|
|||||||
prepareHeights(xOffs, zOffs, blocks, 0, temperatures);//biomes, temperatures);
|
prepareHeights(xOffs, zOffs, blocks, 0, temperatures);//biomes, temperatures);
|
||||||
buildSurfaces(xOffs, zOffs, blocks, biomes);
|
buildSurfaces(xOffs, zOffs, blocks, biomes);
|
||||||
|
|
||||||
//caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount);
|
// Carve caves into the chunk
|
||||||
|
caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount);
|
||||||
levelChunk->recalcHeightmap();
|
levelChunk->recalcHeightmap();
|
||||||
|
|
||||||
return levelChunk;
|
return levelChunk;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ LevelData::LevelData()
|
|||||||
dimension(Dimension::NORMAL),
|
dimension(Dimension::NORMAL),
|
||||||
playerDataVersion(-1),
|
playerDataVersion(-1),
|
||||||
storageVersion(0),
|
storageVersion(0),
|
||||||
gameType(GameType::Default),
|
gameType(GameType::Default), spawnMobs(false),
|
||||||
loadedPlayerTag(NULL)
|
allowCheats(false), loadedPlayerTag(NULL)
|
||||||
{
|
{
|
||||||
//LOGI("ctor 1: %p\n", this);
|
//LOGI("ctor 1: %p\n", this);
|
||||||
spawnMobs = (gameType == GameType::Survival);
|
spawnMobs = (gameType == GameType::Survival);
|
||||||
@@ -21,8 +21,7 @@ LevelData::LevelData()
|
|||||||
|
|
||||||
LevelData::LevelData( const LevelSettings& settings, const std::string& levelName, int generatorVersion /*= -1*/ )
|
LevelData::LevelData( const LevelSettings& settings, const std::string& levelName, int generatorVersion /*= -1*/ )
|
||||||
: seed(settings.getSeed()),
|
: seed(settings.getSeed()),
|
||||||
gameType(settings.getGameType()),
|
gameType(settings.getGameType()), allowCheats(settings.getAllowCheats()), levelName(levelName),
|
||||||
levelName(levelName),
|
|
||||||
xSpawn(128),
|
xSpawn(128),
|
||||||
ySpawn(64),
|
ySpawn(64),
|
||||||
zSpawn(128),
|
zSpawn(128),
|
||||||
@@ -62,6 +61,7 @@ LevelData::LevelData( const LevelData& rhs )
|
|||||||
playerDataVersion(rhs.playerDataVersion),
|
playerDataVersion(rhs.playerDataVersion),
|
||||||
generatorVersion(rhs.generatorVersion),
|
generatorVersion(rhs.generatorVersion),
|
||||||
spawnMobs(rhs.spawnMobs),
|
spawnMobs(rhs.spawnMobs),
|
||||||
|
allowCheats(rhs.allowCheats),
|
||||||
loadedPlayerTag(NULL),
|
loadedPlayerTag(NULL),
|
||||||
playerData(rhs.playerData)
|
playerData(rhs.playerData)
|
||||||
{
|
{
|
||||||
@@ -84,6 +84,7 @@ LevelData& LevelData::operator=( const LevelData& rhs )
|
|||||||
time = rhs.time;
|
time = rhs.time;
|
||||||
dimension = rhs.dimension;
|
dimension = rhs.dimension;
|
||||||
spawnMobs = rhs.spawnMobs;
|
spawnMobs = rhs.spawnMobs;
|
||||||
|
allowCheats = rhs.allowCheats;
|
||||||
playerData = rhs.playerData;
|
playerData = rhs.playerData;
|
||||||
playerDataVersion = rhs.playerDataVersion;
|
playerDataVersion = rhs.playerDataVersion;
|
||||||
generatorVersion = rhs.generatorVersion;
|
generatorVersion = rhs.generatorVersion;
|
||||||
@@ -161,6 +162,7 @@ void LevelData::setTagData( CompoundTag* tag, CompoundTag* playerTag )
|
|||||||
if (!tag) return;
|
if (!tag) return;
|
||||||
tag->putLong("RandomSeed", seed);
|
tag->putLong("RandomSeed", seed);
|
||||||
tag->putInt("GameType", gameType);
|
tag->putInt("GameType", gameType);
|
||||||
|
tag->putBoolean("AllowCommands", allowCheats);
|
||||||
tag->putInt("SpawnX", xSpawn);
|
tag->putInt("SpawnX", xSpawn);
|
||||||
tag->putInt("SpawnY", ySpawn);
|
tag->putInt("SpawnY", ySpawn);
|
||||||
tag->putInt("SpawnZ", zSpawn);
|
tag->putInt("SpawnZ", zSpawn);
|
||||||
@@ -181,6 +183,7 @@ void LevelData::getTagData( const CompoundTag* tag )
|
|||||||
if (!tag) return;
|
if (!tag) return;
|
||||||
seed = (long)tag->getLong("RandomSeed");
|
seed = (long)tag->getLong("RandomSeed");
|
||||||
gameType = tag->getInt("GameType");
|
gameType = tag->getInt("GameType");
|
||||||
|
allowCheats = tag->getBoolean("AllowCommands");
|
||||||
xSpawn = tag->getInt("SpawnX");
|
xSpawn = tag->getInt("SpawnX");
|
||||||
ySpawn = tag->getInt("SpawnY");
|
ySpawn = tag->getInt("SpawnY");
|
||||||
zSpawn = tag->getInt("SpawnZ");
|
zSpawn = tag->getInt("SpawnZ");
|
||||||
@@ -362,3 +365,13 @@ void LevelData::setSpawnMobs( bool doSpawn )
|
|||||||
{
|
{
|
||||||
spawnMobs = doSpawn;
|
spawnMobs = doSpawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LevelData::getAllowCheats() const
|
||||||
|
{
|
||||||
|
return allowCheats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelData::setAllowCheats( bool allow )
|
||||||
|
{
|
||||||
|
allowCheats = allow;
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ public:
|
|||||||
bool getSpawnMobs() const;
|
bool getSpawnMobs() const;
|
||||||
void setSpawnMobs(bool doSpawn);
|
void setSpawnMobs(bool doSpawn);
|
||||||
|
|
||||||
|
bool getAllowCheats() const;
|
||||||
|
void setAllowCheats(bool allow);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlayerData playerData;
|
PlayerData playerData;
|
||||||
int playerDataVersion;
|
int playerDataVersion;
|
||||||
@@ -89,6 +92,7 @@ private:
|
|||||||
int gameType;
|
int gameType;
|
||||||
int storageVersion;
|
int storageVersion;
|
||||||
bool spawnMobs;
|
bool spawnMobs;
|
||||||
|
bool allowCheats;
|
||||||
//@note: This version is never written or loaded to disk. The only purpose
|
//@note: This version is never written or loaded to disk. The only purpose
|
||||||
// is to use it in the level generator on server and clients.
|
// is to use it in the level generator on server and clients.
|
||||||
int generatorVersion;
|
int generatorVersion;
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ void DoorTile::neighborChanged(Level* level, int x, int y, int z, int type) {
|
|||||||
}
|
}
|
||||||
if (spawn) {
|
if (spawn) {
|
||||||
if (!level->isClientSide) {
|
if (!level->isClientSide) {
|
||||||
spawnResources(level, x, y, z, data, 0);
|
// use default chance (1.0) so the drop always occurs
|
||||||
|
spawnResources(level, x, y, z, data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z);
|
bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z);
|
||||||
@@ -174,13 +175,12 @@ void DoorTile::neighborChanged(Level* level, int x, int y, int z, int type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// upper half: removal should not drop a second door. the
|
||||||
|
// lower half neighbour handler takes care of spawning the item
|
||||||
|
// whenever the door is broken from either end.
|
||||||
if (level->getTile(x, y - 1, z) != id) {
|
if (level->getTile(x, y - 1, z) != id) {
|
||||||
level->setTile(x, y, z, 0);
|
level->setTile(x, y, z, 0);
|
||||||
if(material == Material::metal) {
|
// no resource spawn here
|
||||||
popResource(level, x, y, z, ItemInstance(Item::door_iron));
|
|
||||||
} else {
|
|
||||||
popResource(level, x, y, z, ItemInstance(Item::door_wood));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (type > 0 && type != id) {
|
if (type > 0 && type != id) {
|
||||||
neighborChanged(level, x, y - 1, z, type);
|
neighborChanged(level, x, y - 1, z, type);
|
||||||
@@ -189,7 +189,11 @@ void DoorTile::neighborChanged(Level* level, int x, int y, int z, int type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int DoorTile::getResource(int data, Random* random) {
|
int DoorTile::getResource(int data, Random* random) {
|
||||||
if ((data & 8) != 0) return 0;
|
// only the lower half should return a resource ID; the upper half
|
||||||
|
// itself never drops anything and playerDestroy suppresses spawning
|
||||||
|
// from the top. This prevents duplicate drops if the bottom half is
|
||||||
|
// mined.
|
||||||
|
if ((data & UPPER_BIT) != 0) return 0;
|
||||||
if (material == Material::metal) return Item::door_iron->id;
|
if (material == Material::metal) return Item::door_iron->id;
|
||||||
return Item::door_wood->id;
|
return Item::door_wood->id;
|
||||||
}
|
}
|
||||||
@@ -199,6 +203,14 @@ HitResult DoorTile::clip(Level* level, int xt, int yt, int zt, const Vec3& a, co
|
|||||||
return super::clip(level, xt, yt, zt, a, b);
|
return super::clip(level, xt, yt, zt, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// override to prevent double-dropping when top half is directly mined
|
||||||
|
void DoorTile::playerDestroy(Level* level, Player* player, int x, int y, int z, int data) {
|
||||||
|
if ((data & UPPER_BIT) == 0) {
|
||||||
|
// only let the lower half handle the actual spawning
|
||||||
|
super::playerDestroy(level, player, x, y, z, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DoorTile::getDir(LevelSource* level, int x, int y, int z) {
|
int DoorTile::getDir(LevelSource* level, int x, int y, int z) {
|
||||||
return getCompositeData(level, x, y, z) & C_DIR_MASK;
|
return getCompositeData(level, x, y, z) & C_DIR_MASK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ public:
|
|||||||
|
|
||||||
int getResource(int data, Random* random);
|
int getResource(int data, Random* random);
|
||||||
|
|
||||||
|
// override to avoid duplicate drops when upper half is mined directly
|
||||||
|
void playerDestroy(Level* level, Player* player, int x, int y, int z, int data) override;
|
||||||
|
|
||||||
HitResult clip(Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b);
|
HitResult clip(Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b);
|
||||||
|
|
||||||
int getDir(LevelSource* level, int x, int y, int z);
|
int getDir(LevelSource* level, int x, int y, int z);
|
||||||
|
|||||||
Reference in New Issue
Block a user