64 Commits

Author SHA1 Message Date
deepfriedwaffles
2d731bc3b6 fix missing file, commiting now because what im about to do might break Option class 2026-03-17 10:35:40 -04:00
deepfriedwaffles
0d1387ad8f added needed missing files 2026-03-17 02:31:41 -04:00
deepfriedwaffles
d103caddab Started to port to iOS; fixing compiler errors here and there 2026-03-17 02:22:17 -04:00
Kolyah35
9d831bdb25 trying to up android build 2026-03-17 00:58:22 +03:00
Kolyah35
7e86e34189 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-17 00:40:49 +03:00
Kolyah35
1ca46fab32 some fixes 2026-03-17 00:40:32 +03:00
InviseDivine
7877301d7f Update .github/workflows/cmake-multiplatform.yml 2026-03-16 23:24:18 +02:00
Kolyah35
b8df42d9bd trying to up actions 2026-03-17 00:20:56 +03:00
InviseDivine
cdada510a0 readme upd 2026-03-16 23:18:44 +02:00
deepfriedwaffles
f3e94f697f Added *.xcuserstate wildcsrd to Xcode ignores 2026-03-16 17:02:34 -04:00
Kolyah35
aaad53761e Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-16 23:18:53 +03:00
Kolyah35
183487853c hopefully fixed blackscreen 🙏 2026-03-16 23:16:16 +03:00
mschiller890
2bc3be3153 FIXED: chat history clears on disconnect 2026-03-16 19:05:55 +01:00
Michal Schiller
997c3f2ebe Added a list of players when in multiplayer (tab list) 2026-03-16 13:34:42 +01:00
Michal Schiller
d3cf64cfdc FIXED: Skins work on Linux
There's still one more issue to this:
other peoples skins in multiplayer show corrupted.
2026-03-16 09:00:36 +01:00
Michal Schiller
babd7b4d96 i fucking FLIPPED the cape textures and fixed issues with options
were the options working for everyone else? am i stupid
2026-03-16 05:19:10 +01:00
InviseDivine
725353eb74 NO_SOUND Define 2026-03-15 22:59:43 +02:00
InviseDivine
c52f5a4393 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-15 22:01:17 +02:00
InviseDivine
df99a29258 FEAT: ifdef CHEATS (temp solution) 2026-03-15 22:01:15 +02:00
InviseDivine
76a5e19e9b Update build instruction 2026-03-15 21:47:57 +02:00
Kolyah35
c7d6289781 FIX: compilation on arm 2026-03-15 21:59:23 +03:00
Kolyah35
a50877af9e ADD: lastip 2026-03-15 20:54:28 +03:00
Kolyah35
fadcf3a7d0 FIX: i fucking wrote profiler just to find that sleep function takes SECONDS arg 😭😭😭😭😭😭😭😭😭😭 2026-03-15 20:35:02 +03:00
Kolyah35
b0fa2b820c REMOVE: debug feature 2026-03-15 18:32:41 +03:00
InviseDivine
c03f535c7e FIX: Nether reactor (by @bravelycowering) 2026-03-14 20:42:38 +02:00
InviseDivine
03ff7b118e settings names fixed 2026-03-14 20:24:28 +02:00
Kolyah35
1f5e1244f2 Merge pull request 'start menu screen overhaul' (#3) from freetolga/minecraft-pe-0.6.1:start-screen-overhaul into main
Reviewed-on: https://192.168.0.2:3000/Kolyah35/minecraft-pe-0.6.1/pulls/3
2026-03-14 17:21:58 +02:00
Kolyah35
0aa94bc56f REMOVE: AI useless code 2026-03-14 18:15:08 +03:00
freetolga
5f612652d9 start menu screen overhaul 2026-03-14 17:57:55 +03:00
Kolyah35
bf1a6d79b4 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-14 14:52:59 +03:00
Kolyah35
e49fe348e3 FIX: override warnings 2026-03-14 14:51:42 +03:00
Kolyah35
bb95e75c47 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-03-14 14:51:25 +03:00
mschiller890
4e179a47b6 Make chat show full history when opened 2026-03-14 12:22:14 +01:00
Kolyah35
badd59b644 FIX: Rewrite options 2026-03-14 14:13:49 +03:00
mschiller890
76839dfbaa Android build issues fixed
(except i fixed the wrong stuff first...)
2026-03-14 00:34:44 +01:00
mschiller890
9fd54afd61 Fixed creative mode instant mining 2026-03-14 00:08:58 +01:00
mschiller890
eb8caa887e Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 23:56:58 +01:00
mschiller890
97daa795fb Added capes (needs improvement) 2026-03-13 23:56:49 +01:00
InviseDivine
754329fc49 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 23:23:26 +02:00
InviseDivine
5385342272 sprint on ctrl 2026-03-13 23:23:25 +02:00
mschiller890
0db3a547c7 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 22:15:41 +01:00
mschiller890
94f4317b71 Restore cave generation + adjust ore spawn rates 2026-03-13 22:15:30 +01:00
InviseDivine
bf2248063d FEAT: F1 (but why jump doesnt work wtf) 2026-03-13 22:21:53 +02:00
InviseDivine
13dcf593d8 fck 2026-03-13 19:09:12 +02:00
InviseDivine
b547286e53 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 19:08:27 +02:00
InviseDivine
ce5307aa30 FEAT: Tweaks in options 2026-03-13 19:08:27 +02:00
mschiller890
85224c42b7 Skin layers added 2026-03-13 16:56:27 +01:00
mschiller890
450f0d9ec2 Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 16:26:28 +01:00
mschiller890
12d5835711 Watch out! Skins! 2026-03-13 16:26:19 +01:00
InviseDivine
969d6b3ee7 Forgot about view bobick 2026-03-13 17:12:55 +02:00
InviseDivine
b0de432339 FIX: Settings save 2026-03-13 17:09:39 +02:00
InviseDivine
6f7812293e settings almost fixed 2026-03-13 15:57:16 +02:00
mschiller890
37e28d0fcc added a username label to the title screen 2026-03-13 13:22:47 +01:00
mschiller890
954ec6e505 Game now actually pauses when in a local world and when the server is set to be invisible. 2026-03-13 11:25:20 +01:00
mschiller890
b1cd6c6581 Added a dummy cheats toggle to the world creation screen. 2026-03-13 11:04:58 +01:00
mschiller890
248e9cb69a removed survival kit thing, go mining 2026-03-13 09:22:38 +01:00
mschiller890
caedc293eb Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1 2026-03-13 08:23:20 +01:00
mschiller890
2e9a9b810c Limit username to 12 chars and adjusted the Done button to go more with the rest of the games UI. 2026-03-13 08:22:54 +01:00
mschiller890
ce4c3e9d93 Update README.md 2026-03-13 09:05:59 +02:00
mschiller890
470509ee52 Add "Quit Game" button 2026-03-12 21:42:20 +01:00
mschiller890
0ea8b87970 Prevent duplicate world IDs by loading existing level list before generating a unique name 2026-03-12 21:31:01 +01:00
mschiller890
b4f54083dc Fixed door destroy logic 2026-03-12 19:17:32 +01:00
Michal Schiller
f17a11c670 Added mouse wheel support to the world selection screen. 2026-03-12 11:02:06 +01:00
mschiller890
adb23d18c6 Update README.md 2026-03-11 20:41:15 +02:00
143 changed files with 7407 additions and 2757 deletions

36
.github/workflows/android.yml vendored Normal file
View File

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

View File

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

1
.gitignore vendored
View File

@@ -50,6 +50,7 @@ MinSizeRel/
*.xcworkspace *.xcworkspace
xcuserdata/ xcuserdata/
*.xccheckout *.xccheckout
*.xcuserstate
*.moved-aside *.moved-aside
DerivedData/ DerivedData/
*.hmap *.hmap

View File

@@ -9,12 +9,20 @@ 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) find_package(Threads REQUIRED)
find_package(OpenSSL)
if (OpenSSL_FOUND)
message(STATUS "found openssl ${OPENSSL_VERSION}")
endif()
CPMAddPackage("gh:madler/zlib@1.3.2") CPMAddPackage("gh:madler/zlib@1.3.2")
CPMAddPackage( CPMAddPackage(
NAME "libpng" NAME "libpng"
GIT_REPOSITORY "https://github.com/pnggroup/libpng.git" GIT_REPOSITORY "https://github.com/pnggroup/libpng.git"
GIT_TAG "v1.6.55" GIT_TAG "v1.6.55"
EXCLUDE_FROM_ALL TRUE
OPTIONS OPTIONS
"ZLIB_ROOT ${zlib_SOURCE_DIR}" "ZLIB_ROOT ${zlib_SOURCE_DIR}"
"ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}" "ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}"
@@ -27,6 +35,7 @@ CPMAddPackage(
NAME "openal" NAME "openal"
GIT_REPOSITORY "https://github.com/kcat/openal-soft.git" GIT_REPOSITORY "https://github.com/kcat/openal-soft.git"
GIT_TAG "1.25.1" GIT_TAG "1.25.1"
EXCLUDE_FROM_ALL TRUE
OPTIONS OPTIONS
"ALSOFT_EXAMPLES OFF" "ALSOFT_EXAMPLES OFF"
"ALSOFT_TESTS OFF" "ALSOFT_TESTS OFF"
@@ -38,14 +47,17 @@ CPMAddPackage(
NAME "glfw" NAME "glfw"
GIT_REPOSITORY "https://github.com/glfw/glfw.git" GIT_REPOSITORY "https://github.com/glfw/glfw.git"
GIT_TAG "3.4" GIT_TAG "3.4"
EXCLUDE_FROM_ALL TRUE
OPTIONS OPTIONS
"GLFW_BUILD_EXAMPLES OFF" "GLFW_BUILD_EXAMPLES OFF"
"GLFW_BUILD_TESTS OFF" "GLFW_BUILD_TESTS OFF"
"GLFW_BUILD_DOCS OFF" "GLFW_BUILD_DOCS OFF"
"BUILD_SHARED_LIBS ON" "BUILD_SHARED_LIBS ON"
) )
# TODO: Clear this paths with * # TODO: Clear this paths with *
file(GLOB SERVER_SOURCES file(GLOB SERVER_SOURCES
"project/lib_projects/raknet/jni/RaknetSources/*.cpp"
"src/NinecraftApp.cpp" "src/NinecraftApp.cpp"
"src/Performance.cpp" "src/Performance.cpp"
"src/SharedConstants.cpp" "src/SharedConstants.cpp"
@@ -53,8 +65,10 @@ file(GLOB SERVER_SOURCES
"src/client/IConfigListener.cpp" "src/client/IConfigListener.cpp"
"src/client/Minecraft.cpp" "src/client/Minecraft.cpp"
"src/client/OptionStrings.cpp" "src/client/OptionStrings.cpp"
"src/client/Option.cpp"
"src/client/Options.cpp" "src/client/Options.cpp"
"src/client/OptionsFile.cpp" "src/client/OptionsFile.cpp"
"src/client/ServerProfiler.cpp"
"src/client/gamemode/CreativeMode.cpp" "src/client/gamemode/CreativeMode.cpp"
"src/client/gamemode/GameMode.cpp" "src/client/gamemode/GameMode.cpp"
@@ -79,6 +93,8 @@ file(GLOB SERVER_SOURCES
"src/network/command/CommandServer.cpp" "src/network/command/CommandServer.cpp"
"src/platform/CThread.cpp" "src/platform/CThread.cpp"
"src/platform/HttpClient.cpp"
"src/platform/PngLoader.cpp"
"src/platform/time.cpp" "src/platform/time.cpp"
"src/platform/input/Controller.cpp" "src/platform/input/Controller.cpp"
@@ -97,38 +113,15 @@ file(GLOB SERVER_SOURCES
"src/world/Direction.cpp" "src/world/Direction.cpp"
"src/world/entity/AgableMob.cpp" "src/world/entity/*.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/ai/control/MoveControl.cpp"
"src/world/entity/animal/Animal.cpp" "src/world/entity/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/*.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/*.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/Inventory.cpp"
"src/world/entity/player/Player.cpp" "src/world/entity/player/Player.cpp"
@@ -138,38 +131,10 @@ file(GLOB SERVER_SOURCES
"src/world/food/SimpleFoodData.cpp" "src/world/food/SimpleFoodData.cpp"
"src/world/inventory/BaseContainerMenu.cpp" "src/world/inventory/*.cpp"
"src/world/inventory/ContainerMenu.cpp" "src/world/item/*.cpp"
"src/world/inventory/FillingContainer.cpp" "src/world/item/crafting/*.cpp"
"src/world/inventory/FurnaceMenu.cpp" "src/world/level/*.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/Biome.cpp"
"src/world/level/biome/BiomeSource.cpp" "src/world/level/biome/BiomeSource.cpp"
@@ -178,54 +143,21 @@ file(GLOB SERVER_SOURCES
"src/world/level/dimension/Dimension.cpp" "src/world/level/dimension/Dimension.cpp"
"src/world/level/levelgen/CanyonFeature.cpp" "src/world/level/levelgen/*.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/feature/Feature.cpp"
"src/world/level/levelgen/synth/ImprovedNoise.cpp" "src/world/level/levelgen/synth/*.cpp"
"src/world/level/levelgen/synth/PerlinNoise.cpp"
"src/world/level/levelgen/synth/Synth.cpp"
"src/world/level/material/Material.cpp" "src/world/level/material/Material.cpp"
"src/world/level/pathfinder/Path.cpp" "src/world/level/pathfinder/Path.cpp"
"src/world/level/storage/ExternalFileLevelStorage.cpp" "src/world/level/storage/*.cpp"
"src/world/level/storage/ExternalFileLevelStorageSource.cpp" "src/world/level/tile/*.cpp"
"src/world/level/storage/FolderMethods.cpp" "src/world/level/tile/entity/*.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" "src/world/phys/HitResult.cpp"
) )
file(GLOB CLIENT_SOURCES file(GLOB CLIENT_SOURCES
"src/client/*.cpp" "src/client/*.cpp"
@@ -317,22 +249,25 @@ if(PLATFORM STREQUAL "PLATFORM_GLFW")
list(APPEND CLIENT_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 # Server
list(APPEND CLIENT_SOURCES if(UNIX)
"src/client/gui/screens/ConsoleScreen.cpp" add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES})
"src/client/gui/screens/UsernameScreen.cpp"
"src/client/gui/screens/CreditsScreen.cpp" target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER")
target_include_directories("${PROJECT_NAME}-server" PUBLIC
"${CMAKE_SOURCE_DIR}/src/"
"project/lib_projects/raknet/jni/RaknetSources"
) )
target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT} png_shared)
endif()
add_executable(${PROJECT_NAME} add_executable(${PROJECT_NAME}
${CLIENT_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")
@@ -343,6 +278,7 @@ if(PLATFORM STREQUAL "PLATFORM_WIN32" OR PLATFORM STREQUAL "PLATFORM_GLFW")
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"
@@ -351,19 +287,15 @@ 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 # 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})
if (OpenSSL_FOUND)
target_link_libraries(${PROJECT_NAME} OpenSSL::SSL OpenSSL::Crypto)
target_compile_definitions(${PROJECT_NAME} PUBLIC HTTPCLIENT_USE_OPENSSL)
endif()
if (NOT UNIX) if (NOT UNIX)
add_custom_command( add_custom_command(
TARGET ${PROJECT_NAME} TARGET ${PROJECT_NAME}
@@ -378,3 +310,59 @@ add_custom_command(
POST_BUILD POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $<TARGET_FILE_DIR:${PROJECT_NAME}>/data COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $<TARGET_FILE_DIR:${PROJECT_NAME}>/data
) )
# Installing and packing
find_package(Git REQUIRED)
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_SHORTSHA
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME)
set(CPACK_PACKAGE_NAME "MCPE-0.6.1-for-all")
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${SYSTEM_NAME})
set(CPACK_PACKAGE_VENDOR "MCPE-0.6.1-for-all")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/package")
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install")
set(CPACK_GENERATOR "ZIP")
set(GIT_REPO "https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1")
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION .)
if(NOT UNIX)
install(FILES
$<TARGET_RUNTIME_DLLS:${PROJECT_NAME}>
DESTINATION .
)
endif()
install(DIRECTORY "${CMAKE_SOURCE_DIR}/data" DESTINATION .)
string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
string(TIMESTAMP CURRENT_TIME "%H:%M:%S")
set(VERSION_STR "${PROJECT_VERSION}")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(VERSION_STR "${VERSION_STR} - Development Build")
endif()
file(WRITE "${CMAKE_BINARY_DIR}/version.txt"
"Minecraft PE 0.6.1
Autogenerated file by cmake-${CMAKE_VERSION}
Report issues ${GIT_REPO}/issues
Build date: ${CURRENT_DATE} ${CURRENT_TIME}
Build configuration: ${CMAKE_BUILD_TYPE}
Git commit: ${GIT_SHORTSHA}
Platform: ${CMAKE_SYSTEM_NAME}")
install(FILES "${CMAKE_BINARY_DIR}/version.txt" DESTINATION .)
include(CPack)

View File

@@ -1,4 +1,7 @@
# MinecraftPE # MinecraftPE
> [!Warning]
> Github repository **isnt main**. All issues and pull requests should be send in [Gitea Repository](https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1).
> [!Important] > [!Important]
> We have a discord server, where you can report bugs or send feedback https://discord.gg/c58YesBxve > We have a discord server, where you can report bugs or send feedback https://discord.gg/c58YesBxve
@@ -27,11 +30,38 @@ This project aims to preserve and improve this early version of Minecraft PE.
# Build # Build
## CMake ## CMake
### Linux
1. Install dependiences
(Debian-like)
``sudo apt install build-essential git cmake libgl-dev libwayland-dev xorg-dev libxkbcommon-dev``
(Arch-like)
``sudo pacman -S base-devel git cmake libglvnd wayland xorg-server-devel xorgproto libxkbcommon``
2. Create build folder
``mkdir build && cd build``
3. Generate CMake cache and build the project
``` ```
mkdir build && cd build
cmake .. -B . cmake .. -B .
make -j4 cmake --build .
``` ```
### Windows
1. Install [Visual studio Build Tools](https://aka.ms/vs/stable/vs_BuildTools.exe) and [CMake](https://github.com/Kitware/CMake/releases/download/v4.3.0-rc3/cmake-4.3.0-rc3-windows-x86_64.msi)
2. Create build folder
``mkdir build && cd build``
3. Generate CMake cache and build the project
```
cmake ..
cmake --build .
```
## Visual Studio ## Visual Studio
1. Open the repository folder in **Visual Studio**. 1. Open the repository folder in **Visual Studio**.
@@ -40,17 +70,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
``` ```

View File

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

View File

@@ -145,9 +145,14 @@ options.gamma=Brightness
options.gamma.min=Moody options.gamma.min=Moody
options.gamma.max=Bright options.gamma.max=Bright
options.group.mojang=Login options.group.mojang=Login
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.allowSprint=Allow 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
@@ -187,6 +192,15 @@ options.particles=Particles
options.particles.all=All options.particles.all=All
options.particles.decreased=Decreased options.particles.decreased=Decreased
options.particles.minimal=Minimal options.particles.minimal=Minimal
options.username=Username
options.smoothCamera=Smooth camera
options.destroyVibration=Destroy vibration
options.isLeftHanded=Left handed
options.useTouchscreen=Use touchscreen
options.fancyGraphics=Fancy graphics
options.renderDebug=Debug render
options.anaglyph3d=3D anaglyph
performance.max=Max FPS performance.max=Max FPS
performance.balanced=Balanced performance.balanced=Balanced
@@ -194,21 +208,21 @@ performance.powersaver=Power saver
controls.title=Controls controls.title=Controls
key.forward=Forward options.key.forward=Forward
key.left=Left options.key.left=Left
key.back=Back options.key.back=Back
key.right=Right options.key.right=Right
key.jump=Jump options.key.jump=Jump
key.inventory=Inventory options.key.inventory=Inventory
key.drop=Drop options.key.drop=Drop
key.chat=Chat options.key.chat=Chat
key.fog=Toggle Fog options.key.fog=Toggle Fog
key.sneak=Sneak options.key.sneak=Sneak
key.playerlist=List Players options.key.playerlist=List Players
key.attack=Attack options.key.attack=Attack
key.use=Use Item options.key.use=Use Item
key.pickItem=Pick Block options.key.pickItem=Pick Block
key.mouseButton=Button %1$s options.key.mouseButton=Button %1$s
texturePack.openFolder=Open texture pack folder texturePack.openFolder=Open texture pack folder
texturePack.title=Select Texture Pack texturePack.title=Select Texture Pack

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

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
# Convert Windows backslashes to forward slashes so NDK toolchain doesnt treat them as escapes.
LOCAL_PATH := $(subst \,/,$(LOCAL_PATH))
include $(CLEAR_VARS) include $(CLEAR_VARS)
@@ -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 \

View File

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

View File

@@ -19,6 +19,7 @@ set(CompileFiles ../../src/main.cpp
../../src/client/IConfigListener.cpp ../../src/client/IConfigListener.cpp
../../src/client/Minecraft.cpp ../../src/client/Minecraft.cpp
../../src/client/Options.cpp ../../src/client/Options.cpp
../../src/client/Option.cpp
../../src/client/OptionsFile.cpp ../../src/client/OptionsFile.cpp
../../src/client/OptionStrings.cpp ../../src/client/OptionStrings.cpp
../../src/client/gamemode/GameMode.cpp ../../src/client/gamemode/GameMode.cpp
@@ -155,5 +156,5 @@ set(CompileFiles ../../src/main.cpp
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 target_include_directories(mcpe_server PUBLIC
"minecraft-pe-0.6.1/src/" "../../src/"
) )

View File

@@ -1211,7 +1211,7 @@
042A91A916B17517007ABBC6 /* OptionsPane.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OptionsPane.cpp; sourceTree = "<group>"; }; 042A91A916B17517007ABBC6 /* OptionsPane.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OptionsPane.cpp; sourceTree = "<group>"; };
042A91AA16B17517007ABBC6 /* OptionsPane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionsPane.h; sourceTree = "<group>"; }; 042A91AA16B17517007ABBC6 /* OptionsPane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionsPane.h; sourceTree = "<group>"; };
042A91AB16B17517007ABBC6 /* TextBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextBox.cpp; sourceTree = "<group>"; }; 042A91AB16B17517007ABBC6 /* TextBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextBox.cpp; sourceTree = "<group>"; };
042A91AC16B17517007ABBC6 /* TextBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextBox.h; sourceTree = "<group>"; }; 042A91AC16B17517007ABBC6 /* TextBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextBox.h; path = ../../src/client/gui/components/TextBox.h; sourceTree = SOURCE_ROOT; };
044129061682FF9600B70EE6 /* MouseHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseHandler.cpp; sourceTree = "<group>"; }; 044129061682FF9600B70EE6 /* MouseHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseHandler.cpp; sourceTree = "<group>"; };
9D293CE616071C08000305C8 /* CreateNewWorld_iphone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CreateNewWorld_iphone.xib; path = minecraftpe/dialogs/CreateNewWorld_iphone.xib; sourceTree = "<group>"; }; 9D293CE616071C08000305C8 /* CreateNewWorld_iphone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CreateNewWorld_iphone.xib; path = minecraftpe/dialogs/CreateNewWorld_iphone.xib; sourceTree = "<group>"; };
9D293CEA160720D6000305C8 /* worldname_iphone5_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = worldname_iphone5_3.png; sourceTree = "<group>"; }; 9D293CEA160720D6000305C8 /* worldname_iphone5_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = worldname_iphone5_3.png; sourceTree = "<group>"; };
@@ -4527,10 +4527,16 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 0420; LastUpgradeCheck = 0420;
TargetAttributes = {
D5CF9C41144C225000E4244F = {
DevelopmentTeam = PZUVNW8F2U;
ProvisioningStyle = Automatic;
};
};
}; };
buildConfigurationList = D5CF9C3C144C225000E4244F /* Build configuration list for PBXProject "minecraftpe" */; buildConfigurationList = D5CF9C3C144C225000E4244F /* Build configuration list for PBXProject "minecraftpe" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
developmentRegion = English; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
en, en,
@@ -5736,24 +5742,27 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; ARCHS = "$(ARCHS_STANDARD)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Mojang AB"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Mojang AB";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PREPROCESSOR_DEFINITIONS = PUBLISH; GCC_PREPROCESSOR_DEFINITIONS = PUBLISH;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3; HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "C93D3524-5C6F-466E-B12B-833663B7EAE0"; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "C93D3524-5C6F-466E-B12B-833663B7EAE0";
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = "Ad-Hoc"; name = "Ad-Hoc";
@@ -5765,15 +5774,17 @@
GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch"; GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_PREPROCESSOR_DEFINITIONS = "";
"GCC_THUMB_SUPPORT[arch=armv7]" = NO; "GCC_THUMB_SUPPORT[arch=armv7]" = NO;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
HEADER_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist"; INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 4.3; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.mojang.mcpe-arm64";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
VALID_ARCHS = "i386 armv6 armv7";
WRAPPER_EXTENSION = app; WRAPPER_EXTENSION = app;
}; };
name = "Ad-Hoc"; name = "Ad-Hoc";
@@ -5847,23 +5858,26 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; ARCHS = "$(ARCHS_STANDARD)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Mojang AB"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Mojang AB";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3; HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "64BA8967-1A9A-4980-972C-42E75AD5E023"; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "64BA8967-1A9A-4980-972C-42E75AD5E023";
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = AppStore; name = AppStore;
@@ -5876,11 +5890,13 @@
GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch"; GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = PUBLISH; GCC_PREPROCESSOR_DEFINITIONS = PUBLISH;
"GCC_THUMB_SUPPORT[arch=armv7]" = NO; "GCC_THUMB_SUPPORT[arch=armv7]" = NO;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
HEADER_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist"; INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 4.3; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-DNS_BLOCK_ASSERTIONS=1", "-DNS_BLOCK_ASSERTIONS=1",
"-DANDROID_PUBLISH", "-DANDROID_PUBLISH",
@@ -5888,8 +5904,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "1B194957-98CF-49B7-A0E7-76692B4B722D"; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "1B194957-98CF-49B7-A0E7-76692B4B722D";
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
VALID_ARCHS = "i386 armv6 armv7";
WRAPPER_EXTENSION = app; WRAPPER_EXTENSION = app;
}; };
name = AppStore; name = AppStore;
@@ -5923,7 +5938,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; ARCHS = "$(ARCHS_STANDARD)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -5935,17 +5950,21 @@
"$(inherited)", "$(inherited)",
); );
GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3; HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
VALIDATE_PRODUCT = YES;
}; };
name = Debug; name = Debug;
}; };
@@ -5953,23 +5972,26 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; ARCHS = "$(ARCHS_STANDARD)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_PREPROCESSOR_DEFINITIONS = PUBLISH; GCC_PREPROCESSOR_DEFINITIONS = PUBLISH;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = NO;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3; HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)\\src/**";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
@@ -5977,19 +5999,25 @@
D5CF9C6F144C225000E4244F /* Debug */ = { D5CF9C6F144C225000E4244F /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = PZUVNW8F2U;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch"; GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
"GCC_THUMB_SUPPORT[arch=armv7]" = NO; "GCC_THUMB_SUPPORT[arch=armv7]" = NO;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
HEADER_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist"; INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 4.3; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.mojang.mcpe-arm64";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
VALID_ARCHS = "i386 armv6 armv7";
WRAPPER_EXTENSION = app; WRAPPER_EXTENSION = app;
}; };
name = Debug; name = Debug;
@@ -5997,19 +6025,25 @@
D5CF9C70144C225000E4244F /* Release */ = { D5CF9C70144C225000E4244F /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = PZUVNW8F2U;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch"; GCC_PREFIX_HEADER = "minecraftpe/minecraftpe-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_PREPROCESSOR_DEFINITIONS = "";
"GCC_THUMB_SUPPORT[arch=armv7]" = NO; "GCC_THUMB_SUPPORT[arch=armv7]" = NO;
GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_VERSION = "";
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
HEADER_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist"; INFOPLIST_FILE = "minecraftpe/minecraftpe-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 4.3; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games";
IPHONEOS_DEPLOYMENT_TARGET = 14;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.mojang.mcpe-arm64";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
RUN_CLANG_STATIC_ANALYZER = NO; RUN_CLANG_STATIC_ANALYZER = NO;
SDKROOT = iphoneos6.0; SDKROOT = iphoneos;
VALID_ARCHS = "i386 armv6 armv7";
WRAPPER_EXTENSION = app; WRAPPER_EXTENSION = app;
}; };
name = Release; name = Release;

View File

@@ -37,7 +37,7 @@
</dict> </dict>
</dict> </dict>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.mojang.${PRODUCT_NAME:rfc1034identifier}</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>

View File

@@ -10,8 +10,8 @@
#include <io.h> #include <io.h>
#elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __S3E__ ) // #elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __S3E__ )
#include <sys/io.h> // #include <sys/io.h>
#endif #endif

View File

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

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

@@ -1,74 +1,5 @@
#include "AppPlatform_glfw.h" #include "AppPlatform_glfw.h"
#ifdef WIN32
#include <Windows.h>
#endif
// Loader that tries GLFW first, then falls back to opengl32.dll for any
// function that glfwGetProcAddress can't resolve.
void* winGLLoader(const char* name) {
void* p = (void*)glfwGetProcAddress(name);
#ifdef WIN32
if (!p) {
static HMODULE opengl32 = LoadLibraryA("opengl32.dll");
if (opengl32) p = (void*)GetProcAddress(opengl32, name);
}
#endif
return p;
}
// -----------------------------------------------------------------------
// Compatibility wrappers for OpenGL ES functions absent from desktop GL.
// The desktop equivalents use double parameters and are not declared in
// the GLES1 GLAD header, so look them up at runtime via winGLLoader.
// -----------------------------------------------------------------------
static void APIENTRY compat_glDepthRangef(GLfloat n, GLfloat f) {
typedef void(APIENTRY *fn_t)(double, double);
static fn_t fn = (fn_t)winGLLoader("glDepthRange");
if (fn) fn((double)n, (double)f);
}
static void APIENTRY compat_glClearDepthf(GLfloat d) {
typedef void(APIENTRY *fn_t)(double);
static fn_t fn = (fn_t)winGLLoader("glClearDepth");
if (fn) fn((double)d);
}
static void APIENTRY compat_glOrthof(GLfloat l, GLfloat r, GLfloat b,
GLfloat t, GLfloat n, GLfloat f) {
typedef void(APIENTRY *fn_t)(double,double,double,double,double,double);
static fn_t fn = (fn_t)winGLLoader("glOrtho");
if (fn) fn(l, r, b, t, n, f);
}
static void APIENTRY compat_glFrustumf(GLfloat l, GLfloat r, GLfloat b,
GLfloat t, GLfloat n, GLfloat f) {
typedef void(APIENTRY *fn_t)(double,double,double,double,double,double);
static fn_t fn = (fn_t)winGLLoader("glFrustum");
if (fn) fn(l, r, b, t, n, f);
}
// glFogx / glFogxv are OpenGL ES fixed-point variants that don't exist in
// desktop opengl32.dll. Wrap them via the float equivalents. For fog-mode
// enum params the GLfixed value IS the enum integer, so the cast is exact.
static void APIENTRY compat_glFogx(GLenum pname, GLfixed param) {
glFogf(pname, (GLfloat)param);
}
static void APIENTRY compat_glFogxv(GLenum pname, const GLfixed* params) {
// Only GL_FOG_COLOR uses an array; convert each element.
GLfloat fp[4] = {
(GLfloat)params[0], (GLfloat)params[1],
(GLfloat)params[2], (GLfloat)params[3]
};
glFogfv(pname, fp);
}
void glPatchDesktopCompat() {
if (!glad_glDepthRangef) glad_glDepthRangef = compat_glDepthRangef;
if (!glad_glClearDepthf) glad_glClearDepthf = compat_glClearDepthf;
if (!glad_glOrthof) glad_glOrthof = compat_glOrthof;
if (!glad_glFrustumf) glad_glFrustumf = compat_glFrustumf;
if (!glad_glFogx) glad_glFogx = compat_glFogx;
if (!glad_glFogxv) glad_glFogxv = compat_glFogxv;
}
float AppPlatform_glfw::getPixelsPerMillimeter() { float AppPlatform_glfw::getPixelsPerMillimeter() {
GLFWmonitor* monitor = glfwGetPrimaryMonitor(); GLFWmonitor* monitor = glfwGetPrimaryMonitor();

View File

@@ -3,6 +3,8 @@
#include "AppPlatform.h" #include "AppPlatform.h"
#include "platform/log.h" #include "platform/log.h"
#include "platform/HttpClient.h"
#include "platform/PngLoader.h"
#include "client/renderer/gles.h" #include "client/renderer/gles.h"
#include "world/level/storage/FolderMethods.h" #include "world/level/storage/FolderMethods.h"
#include <png.h> #include <png.h>
@@ -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,6 +58,15 @@ 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_
@@ -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];
@@ -121,9 +137,9 @@ public:
virtual float getPixelsPerMillimeter(); virtual float getPixelsPerMillimeter();
virtual bool supportsTouchscreen() { return true; } virtual bool supportsTouchscreen() override { return true; }
virtual void openURL(const std::string& url) { virtual void openURL(const std::string& url) override {
#ifdef _WIN32 #ifdef _WIN32
ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL); ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
#elif __linux__ #elif __linux__
@@ -134,8 +150,4 @@ public:
private: private:
}; };
void* winGLLoader(const char* name);
void glPatchDesktopCompat();
#endif /*APPPLATFORM_GLFW_H__*/ #endif /*APPPLATFORM_GLFW_H__*/

View File

@@ -52,11 +52,10 @@ public:
virtual StringVector getOptionStrings(); virtual StringVector getOptionStrings();
virtual bool isPowerVR() { return false; } virtual bool isPowerVR();
virtual bool isSuperFast(); virtual bool isSuperFast();
virtual void showKeyboard(); virtual void showKeyboard();
virtual void hideKeyboard(); virtual void hideKeyboard();
virtual void isPowerVR();
private: private:
std::string _basePath; std::string _basePath;

View File

@@ -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,6 +53,15 @@ 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_
@@ -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];

View File

@@ -111,7 +111,9 @@ void NinecraftApp::init()
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
LOGI("This: %p\n", this); LOGI("This: %p\n", this);
screenChooser.setScreen(SCREEN_STARTMENU); screenChooser.setScreen(SCREEN_STARTMENU);
if (options.username.empty()) {
if (options.getBooleanValue(OPTIONS_FIRST_LAUNCH)) {
options.toggle(OPTIONS_FIRST_LAUNCH);
setScreen(new UsernameScreen()); setScreen(new UsernameScreen());
} }
#else #else

0
src/client/KeyMapping.h Executable file → Normal file
View File

View File

@@ -1,5 +1,9 @@
#include "Minecraft.h" #include "Minecraft.h"
#include "client/Options.h"
#include "client/player/input/IBuildInput.h" #include "client/player/input/IBuildInput.h"
#include "platform/input/Keyboard.h"
#include "world/item/Item.h"
#include "world/item/ItemInstance.h"
#include <string> #include <string>
#include <cstdlib> #include <cstdlib>
@@ -10,88 +14,34 @@
#if defined(RPI) #if defined(RPI)
#define CREATORMODE #define CREATORMODE
#endif #endif
#include "../network/RakNetInstance.h" #include "../network/RakNetInstance.h"
#include "../network/ClientSideNetworkHandler.h" #include "../network/ClientSideNetworkHandler.h"
#include "../network/ServerSideNetworkHandler.h" #include "../network/ServerSideNetworkHandler.h"
//#include "../network/Packet.h" //#include "../network/Packet.h"
#include "../world/entity/player/Inventory.h" #include "../world/entity/player/Inventory.h"
#include "../world/level/chunk/ChunkCache.h"
#include "../world/level/tile/Tile.h" #include "../world/level/tile/Tile.h"
#include "../world/level/storage/LevelStorageSource.h" #include "../world/level/storage/LevelStorageSource.h"
#include "../world/level/storage/LevelStorage.h" #include "../world/level/storage/LevelStorage.h"
#include "player/input/KeyboardInput.h" #include "player/input/KeyboardInput.h"
#include "world/level/chunk/ChunkSource.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "player/input/touchscreen/TouchInputHolder.h" #include "player/input/touchscreen/TouchInputHolder.h"
#endif
#include "player/LocalPlayer.h"
#include "gamemode/CreativeMode.h"
#include "gamemode/SurvivalMode.h"
#include "player/LocalPlayer.h"
#ifndef STANDALONE_SERVER
#include "particle/ParticleEngine.h" #include "particle/ParticleEngine.h"
#include "gui/Screen.h" #include "gui/Screen.h"
#include "gui/Font.h" #include "gui/Font.h"
#include "gui/screens/RenameMPLevelScreen.h" #include "gui/screens/RenameMPLevelScreen.h"
#include "gui/screens/ConsoleScreen.h" #include "gui/screens/ConsoleScreen.h"
#include "gui/screens/ChatScreen.h"
#include "sound/SoundEngine.h" #include "sound/SoundEngine.h"
#endif
#include "../platform/CThread.h"
#include "../platform/input/Mouse.h"
#include "../AppPlatform.h"
#include "../Performance.h"
#include "../LicenseCodes.h"
#include "../util/PerfTimer.h"
#include "../util/PerfRenderer.h"
#include "player/input/MouseBuildInput.h"
#include "../world/Facing.h"
#include "../network/packet/PlaceBlockPacket.h"
#include "player/input/IInputHolder.h"
#ifndef STANDALONE_SERVER
#include "player/input/touchscreen/TouchscreenInput.h" #include "player/input/touchscreen/TouchscreenInput.h"
#include "renderer/Chunk.h"
#include "player/input/ControllerTurnInput.h"
#include "player/input/XperiaPlayInput.h"
#endif
#include "player/input/MouseTurnInput.h"
#include "../world/entity/MobFactory.h"
#include "../world/level/MobSpawner.h"
#include "../util/Mth.h"
#include "../network/packet/InteractPacket.h"
#ifndef STANDALONE_SERVER
#include "gui/screens/PrerenderTilesScreen.h" #include "gui/screens/PrerenderTilesScreen.h"
#include "renderer/Textures.h" #include "renderer/Textures.h"
#include "gui/screens/DeathScreen.h" #include "gui/screens/DeathScreen.h"
#endif
#include "../network/packet/RespawnPacket.h"
#include "IConfigListener.h"
#include "../world/entity/MobCategory.h"
#ifndef STANDALONE_SERVER
#include "gui/screens/FurnaceScreen.h" #include "gui/screens/FurnaceScreen.h"
#endif
#include "../world/Difficulty.h"
#include "../server/ServerLevel.h"
#ifdef CREATORMODE
#include "../server/CreatorLevel.h"
#endif
#include "../network/packet/AdventureSettingsPacket.h"
#include "../network/packet/SetSpawnPositionPacket.h"
#include "../network/command/CommandServer.h"
#include "gamemode/CreatorMode.h"
#ifndef STANDALONE_SERVER
#include "gui/screens/ArmorScreen.h" #include "gui/screens/ArmorScreen.h"
#endif
#include "../world/level/levelgen/synth/ImprovedNoise.h"
#ifndef STANDALONE_SERVER
#include "renderer/tileentity/TileEntityRenderDispatcher.h" #include "renderer/tileentity/TileEntityRenderDispatcher.h"
#endif
#ifndef STANDALONE_SERVER
#include "renderer/ptexture/DynamicTexture.h" #include "renderer/ptexture/DynamicTexture.h"
#include "renderer/GameRenderer.h" #include "renderer/GameRenderer.h"
#include "renderer/ItemInHandRenderer.h" #include "renderer/ItemInHandRenderer.h"
@@ -101,8 +51,42 @@
#include "gui/Font.h" #include "gui/Font.h"
#include "gui/screens/RenameMPLevelScreen.h" #include "gui/screens/RenameMPLevelScreen.h"
#include "sound/SoundEngine.h" #include "sound/SoundEngine.h"
#endif // STANDALONE_SERVER
#include "player/LocalPlayer.h"
#include "gamemode/CreativeMode.h"
#include "gamemode/SurvivalMode.h"
#include "player/LocalPlayer.h"
#include "../platform/CThread.h"
#include "../platform/input/Mouse.h"
#include "../AppPlatform.h"
#include "../LicenseCodes.h"
#include "../util/PerfTimer.h"
#include "../util/PerfRenderer.h"
#include "player/input/MouseBuildInput.h"
#include "player/input/IInputHolder.h"
#include "player/input/MouseTurnInput.h"
#include "../world/entity/MobFactory.h"
#include "../world/level/MobSpawner.h"
#include "../util/Mth.h"
#include "../network/packet/InteractPacket.h"
#include "../network/packet/RespawnPacket.h"
#include "../network/packet/AdventureSettingsPacket.h"
#include "../network/packet/SetSpawnPositionPacket.h"
#include "IConfigListener.h"
#include "../world/entity/MobCategory.h"
#include "../world/Difficulty.h"
#include "../server/ServerLevel.h"
#ifdef CREATORMODE
#include "../server/CreatorLevel.h"
#endif #endif
#include "../network/command/CommandServer.h"
#include "gamemode/CreatorMode.h"
static void checkGlError(const char* tag) { static void checkGlError(const char* tag) {
#ifdef GLDEBUG #ifdef GLDEBUG
while (1) { while (1) {
@@ -189,7 +173,7 @@ Minecraft::Minecraft()
_powerVr(false), _powerVr(false),
commandPort(4711), commandPort(4711),
reserved_d1(0),reserved_d2(0), reserved_d1(0),reserved_d2(0),
reserved_f1(0),reserved_f2(0) reserved_f1(0),reserved_f2(0), options(this)
{ {
//#ifdef ANDROID //#ifdef ANDROID
@@ -351,6 +335,7 @@ void Minecraft::leaveGame(bool renameLevel /*=false*/)
_running = false; _running = false;
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
gui.clearMessages();
if (renameLevel) { if (renameLevel) {
setScreen(new RenameMPLevelScreen(LevelStorageSource::TempLevelId)); setScreen(new RenameMPLevelScreen(LevelStorageSource::TempLevelId));
} }
@@ -451,20 +436,21 @@ void Minecraft::update() {
// } // }
//} //}
if (pause && level != NULL) { // If we're paused (local world / invisible server), freeze gameplay and
float lastA = timer.a; // networking and only keep UI responsive.
timer.advanceTime(); bool freezeGame = pause;
timer.a = lastA;
} else { if (!freezeGame) {
timer.advanceTime(); timer.advanceTime();
} }
if (raknetInstance) { if (raknetInstance && !freezeGame) {
raknetInstance->runEvents(netCallback); raknetInstance->runEvents(netCallback);
} }
TIMER_PUSH("tick"); TIMER_PUSH("tick");
int toTick = timer.ticks; int toTick = freezeGame ? 1 : timer.ticks;
if (!freezeGame) timer.ticks = 0;
for (int i = 0; i < toTick; ++i, ++ticks) for (int i = 0; i < toTick; ++i, ++ticks)
tick(i, toTick-1); tick(i, toTick-1);
@@ -491,7 +477,7 @@ void Minecraft::update() {
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
checkGlError("Update finished"); checkGlError("Update finished");
if (options.renderDebug) { if (options.getBooleanValue(OPTIONS_RENDER_DEBUG)) {
#ifndef PLATFORM_DESKTOP #ifndef PLATFORM_DESKTOP
if (!PerfTimer::enabled) { if (!PerfTimer::enabled) {
PerfTimer::reset(); PerfTimer::reset();
@@ -559,7 +545,7 @@ void Minecraft::tick(int nTick, int maxTick) {
TIMER_POP_PUSH("levelRenderer"); TIMER_POP_PUSH("levelRenderer");
levelRenderer->tick(); levelRenderer->tick();
#endif #endif
level->difficulty = options.difficulty; level->difficulty = options.getIntValue(OPTIONS_DIFFICULTY);
if (level->isClientSide) level->difficulty = Difficulty::EASY; if (level->isClientSide) level->difficulty = Difficulty::EASY;
TIMER_POP_PUSH("level"); TIMER_POP_PUSH("level");
@@ -589,7 +575,9 @@ void Minecraft::tick(int nTick, int maxTick) {
#endif #endif
} }
TIMER_POP_PUSH("particles"); TIMER_POP_PUSH("particles");
if (!pause) {
particleEngine->tick(); particleEngine->tick();
}
if (screen) { if (screen) {
screenMutex = true; screenMutex = true;
screen->tick(); screen->tick();
@@ -665,6 +653,10 @@ void Minecraft::tickInput() {
} }
if (e.action == MouseAction::ACTION_WHEEL) { if (e.action == MouseAction::ACTION_WHEEL) {
// If chat/console is open, use the wheel to scroll through chat history.
if (screen && (dynamic_cast<ChatScreen*>(screen) || dynamic_cast<ConsoleScreen*>(screen))) {
gui.scrollChat(e.dy);
} else {
Inventory* v = player->inventory; Inventory* v = player->inventory;
int numSlots = gui.getNumSlots(); int numSlots = gui.getNumSlots();
@@ -675,6 +667,7 @@ void Minecraft::tickInput() {
int slot = (v->selected - e.dy + numSlots) % numSlots; int slot = (v->selected - e.dy + numSlots) % numSlots;
v->selectSlot(slot); v->selectSlot(slot);
} }
}
/* /*
if (mouseDiggable && options.useMouseForDigging) { if (mouseDiggable && options.useMouseForDigging) {
if (Mouse::getEventButton() == MouseAction::ACTION_LEFT && Mouse::getEventButtonState()) { if (Mouse::getEventButton() == MouseAction::ACTION_LEFT && Mouse::getEventButtonState()) {
@@ -723,35 +716,40 @@ 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) {
releaseMouse(); if (key == Keyboard::KEY_F3) {
options.toggle(OPTIONS_RENDER_DEBUG);
} }
if (key == Keyboard::KEY_F5) { if (key == Keyboard::KEY_F5) {
options.thirdPersonView = !options.thirdPersonView; options.toggle(OPTIONS_THIRD_PERSON_VIEW);
/* /*
ImprovedNoise noise; ImprovedNoise noise;
for (int i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
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 (!screen && key == Keyboard::KEY_O || key == 250) {
if (key == Keyboard::KEY_F) { releaseMouse();
options.isFlying = !options.isFlying;
player->noPhysics = options.isFlying;
} }
if (key == Keyboard::KEY_F) {
if (key == Keyboard::KEY_L) int dst = options.getIntValue(OPTIONS_VIEW_DISTANCE);
options.viewDistance = (options.viewDistance + 1) % 4; options.set(OPTIONS_VIEW_DISTANCE, (dst + 1) % 4);
}
#ifdef CHEATS
if (key == Keyboard::KEY_U) { if (key == Keyboard::KEY_U) {
onGraphicsReset(); onGraphicsReset();
player->heal(100); player->heal(100);
@@ -820,21 +818,20 @@ 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)? Difficulty difficulty = (Difficulty)options.getIntValue(OPTIONS_DIFFICULTY);
Difficulty::NORMAL : Difficulty::PEACEFUL; options.set(OPTIONS_DIFFICULTY, (difficulty == Difficulty::PEACEFUL)?
Difficulty::NORMAL : Difficulty::PEACEFUL);
//setIsCreativeMode( !isCreativeMode() ); //setIsCreativeMode( !isCreativeMode() );
} }
if (options.renderDebug) { if (options.getBooleanValue(OPTIONS_RENDER_DEBUG)) {
if (key >= '0' && key <= '9') { if (key >= '0' && key <= '9') {
_perfRenderer->debugFpsMeterKeyPress(key - '0'); _perfRenderer->debugFpsMeterKeyPress(key - '0');
} }
} }
#endif #endif
#endif
#ifndef PLATFORM_DESKTOP #ifndef PLATFORM_DESKTOP
if (key == 82) if (key == 82)
@@ -892,8 +889,6 @@ void Minecraft::tickInput() {
// USPESHNO spizheno // USPESHNO spizheno
static int buildHoldTicks = 0; static int buildHoldTicks = 0;
if (Mouse::isButtonDown(MouseAction::ACTION_RIGHT)) { if (Mouse::isButtonDown(MouseAction::ACTION_RIGHT)) {
BuildActionIntention bai(BuildActionIntention::BAI_BUILD | BuildActionIntention::BAI_INTERACT);
handleBuildAction(&bai);
if (buildHoldTicks >= 5) buildHoldTicks = 0; if (buildHoldTicks >= 5) buildHoldTicks = 0;
if (++buildHoldTicks == 1) { if (++buildHoldTicks == 1) {
@@ -902,6 +897,7 @@ void Minecraft::tickInput() {
} }
} else { } else {
buildHoldTicks = 0; buildHoldTicks = 0;
gameMode->releaseUsingItem(player);
} }
} }
@@ -1018,6 +1014,17 @@ bool Minecraft::isOnline()
} }
void Minecraft::pauseGame(bool isBackPaused) { void Minecraft::pauseGame(bool isBackPaused) {
// Only freeze gameplay when running a local server and it is not accepting
// incoming connections (invisible server), which includes typical single-
// player/lobby mode. If the server is visible, the game should keep ticking.
bool canFreeze = false;
if (raknetInstance && raknetInstance->isServer() && netCallback) {
ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback;
if (!ss->allowsIncomingConnections())
canFreeze = true;
}
pause = canFreeze;
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
if (screen != NULL) return; if (screen != NULL) return;
screenChooser.setScreen(isBackPaused? SCREEN_PAUSEPREV : SCREEN_PAUSE); screenChooser.setScreen(isBackPaused? SCREEN_PAUSEPREV : SCREEN_PAUSE);
@@ -1070,6 +1077,8 @@ void Minecraft::setScreen( Screen* screen )
//noRender = false; //noRender = false;
} else { } else {
// Closing a screen and returning to the game should unpause.
pause = false;
grabMouse(); grabMouse();
} }
#endif #endif
@@ -1103,21 +1112,19 @@ bool Minecraft::useTouchscreen() {
#ifdef RPI #ifdef RPI
return false; return false;
#endif #endif
return options.useTouchScreen || !_supportsNonTouchscreen; return options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN) || !_supportsNonTouchscreen;
} }
bool Minecraft::supportNonTouchScreen() { bool Minecraft::supportNonTouchScreen() {
return _supportsNonTouchscreen; return _supportsNonTouchscreen;
} }
void Minecraft::init() void Minecraft::init()
{ {
options.minecraft = this;
options.initDefaultValues();
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
checkGlError("Init enter"); checkGlError("Init enter");
_supportsNonTouchscreen = !platform()->supportsTouchscreen(); _supportsNonTouchscreen = !platform()->supportsTouchscreen();
LOGI("IS TOUCHSCREEN? %d\n", options.useTouchScreen); LOGI("IS TOUCHSCREEN? %d\n", options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN));
textures = new Textures(&options, platform()); textures = new Textures(&options, platform());
textures->addDynamicTexture(new WaterTexture()); textures->addDynamicTexture(new WaterTexture());
@@ -1136,7 +1143,7 @@ void Minecraft::init()
checkGlError("Init complete"); checkGlError("Init complete");
#endif #endif
user = new User("TestUser", ""); user = new User(options.getStringValue(OPTIONS_USERNAME), "");
setIsCreativeMode(false); // false means it's Survival Mode setIsCreativeMode(false); // false means it's Survival Mode
reloadOptions(); reloadOptions();
@@ -1149,10 +1156,12 @@ void Minecraft::setSize(int w, int h) {
width = w; width = w;
height = h; height = h;
int guiScale = options.getIntValue(OPTIONS_GUI_SCALE);
// determine gui scale, optionally overriding auto // determine gui scale, optionally overriding auto
if (options.guiScale != 0) { if (guiScale != 0) {
// manual selection: 1->small, 2->normal, 3->large, 4->larger // manual selection: 1->small, 2->normal, 3->large, 4->larger
switch (options.guiScale) { switch (guiScale) {
case 1: Gui::GuiScale = 2.0f; break; case 1: Gui::GuiScale = 2.0f; break;
case 2: Gui::GuiScale = 3.0f; break; case 2: Gui::GuiScale = 3.0f; break;
case 3: Gui::GuiScale = 4.0f; break; case 3: Gui::GuiScale = 4.0f; break;
@@ -1185,11 +1194,11 @@ void Minecraft::setSize(int w, int h) {
int screenWidth = (int)(width * Gui::InvGuiScale); int screenWidth = (int)(width * Gui::InvGuiScale);
int screenHeight = (int)(height * Gui::InvGuiScale); int screenHeight = (int)(height * Gui::InvGuiScale);
if (platform()) { // if (platform()) {
float pixelsPerMillimeter = options.getProgressValue(&Options::Option::PIXELS_PER_MILLIMETER); // float pixelsPerMillimeter = options.getProgressValue(&Options::Option::PIXELS_PER_MILLIMETER);
pixelCalc.setPixelsPerMillimeter(pixelsPerMillimeter); // pixelCalc.setPixelsPerMillimeter(pixelsPerMillimeter);
pixelCalcUi.setPixelsPerMillimeter(pixelsPerMillimeter * Gui::InvGuiScale); // pixelCalcUi.setPixelsPerMillimeter(pixelsPerMillimeter * Gui::InvGuiScale);
} // }
Config config = createConfig(this); Config config = createConfig(this);
gui.onConfigChanged(config); gui.onConfigChanged(config);
@@ -1210,16 +1219,16 @@ void Minecraft::setSize(int w, int h) {
} }
void Minecraft::reloadOptions() { void Minecraft::reloadOptions() {
options.update();
options.save(); options.save();
bool wasTouchscreen = options.useTouchScreen; bool wasTouchscreen = options.getBooleanValue(OPTIONS_USE_TOUCHSCREEN);
options.useTouchScreen = useTouchscreen(); options.set(OPTIONS_USE_TOUCHSCREEN, useTouchscreen());
options.save(); options.save();
if ((wasTouchscreen != options.useTouchScreen) || (inputHolder == 0)) if ((wasTouchscreen != useTouchscreen()) || (inputHolder == 0))
_reloadInput(); _reloadInput();
user->name = options.username; // TODO:
// user->name = options.username;
LOGI("Reloading-options\n"); LOGI("Reloading-options\n");
@@ -1555,24 +1564,24 @@ ICreator* Minecraft::getCreator()
#endif #endif
} }
void Minecraft::optionUpdated( const Options::Option* option, bool value ) { void Minecraft::optionUpdated(OptionId option, bool value ) {
if(netCallback != NULL && option == &Options::Option::SERVER_VISIBLE) { if(netCallback != NULL && option == OPTIONS_SERVER_VISIBLE) {
ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback; ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback;
ss->allowIncomingConnections(value); ss->allowIncomingConnections(value);
} }
} }
void Minecraft::optionUpdated( const Options::Option* option, float value ) { void Minecraft::optionUpdated(OptionId option, float value ) {
#ifndef STANDALONE_SERVER // #ifndef STANDALONE_SERVER
if(option == &Options::Option::PIXELS_PER_MILLIMETER) { // if(option == OPTIONS_PIXELS_PER_MILLIMETER) {
pixelCalcUi.setPixelsPerMillimeter(value * Gui::InvGuiScale); // pixelCalcUi.setPixelsPerMillimeter(value * Gui::InvGuiScale);
pixelCalc.setPixelsPerMillimeter(value); // pixelCalc.setPixelsPerMillimeter(value);
} // }
#endif // #endif
} }
void Minecraft::optionUpdated( const Options::Option* option, int value ) { void Minecraft::optionUpdated(OptionId option, int value ) {
if(option == &Options::Option::GUI_SCALE) { if(option == OPTIONS_GUI_SCALE) {
// reapply screen scaling using current window size // reapply screen scaling using current window size
setSize(width, height); setSize(width, height);
} }

View File

@@ -4,13 +4,12 @@
#include "Options.h" #include "Options.h"
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
#include "MouseHandler.h" #include "MouseHandler.h"
#endif
#include "Timer.h"
#include "player/input/ITurnInput.h"
#ifndef STANDALONE_SERVER
#include "gui/Gui.h" #include "gui/Gui.h"
#include "gui/screens/ScreenChooser.h" #include "gui/screens/ScreenChooser.h"
#endif #endif
#include "Timer.h"
//#include "../network/RakNetInstance.h" //#include "../network/RakNetInstance.h"
#include "../world/phys/HitResult.h" #include "../world/phys/HitResult.h"
@@ -117,9 +116,9 @@ public:
bool isPowerVR() { return _powerVr; } bool isPowerVR() { return _powerVr; }
bool isKindleFire(int kindleVersion); bool isKindleFire(int kindleVersion);
bool transformResolution(int* w, int* h); bool transformResolution(int* w, int* h);
void optionUpdated(const Options::Option* option, bool value); void optionUpdated(OptionId option, bool value);
void optionUpdated(const Options::Option* option, float value); void optionUpdated(OptionId option, float value);
void optionUpdated(const Options::Option* option, int value); void optionUpdated(OptionId option, int value);
#ifdef __APPLE__ #ifdef __APPLE__
bool _isSuperFast; bool _isSuperFast;
bool isSuperFast() { return _isSuperFast; } bool isSuperFast() { return _isSuperFast; }

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

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

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

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

View File

@@ -7,12 +7,18 @@ 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";

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,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;
CreativeMode::CreativeMode(Minecraft* minecraft) CreativeMode::CreativeMode(Minecraft* minecraft)
: super(minecraft) : super(minecraft)
@@ -29,12 +29,8 @@ void CreativeMode::startDestroyBlock(int x, int y, int z, int face) {
} }
void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) { void CreativeMode::creativeDestroyBlock(int x, int y, int z, int face) {
//if (! minecraft->level->extinguishFire(x, y, z, face);
minecraft->level->extinguishFire(x, y, z, face)
//{
;
destroyBlock(x, y, z, face); destroyBlock(x, y, z, face);
//}
} }
void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) { void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
@@ -46,6 +42,7 @@ void CreativeMode::continueDestroyBlock(int x, int y, int z, int face) {
} }
void CreativeMode::stopDestroyBlock() { void CreativeMode::stopDestroyBlock() {
destroyDelay = 0;
} }
void CreativeMode::initAbilities( Abilities& abilities ) { void CreativeMode::initAbilities( Abilities& abilities ) {

View File

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

View File

@@ -74,7 +74,7 @@ bool GameMode::destroyBlock(int x, int y, int z, int face) {
minecraft->soundEngine->play(oldTile->soundType->getBreakSound(), x + 0.5f, y + 0.5f, z + 0.5f, (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f); minecraft->soundEngine->play(oldTile->soundType->getBreakSound(), x + 0.5f, y + 0.5f, z + 0.5f, (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f);
#endif #endif
oldTile->destroy(level, x, y, z, data); oldTile->destroy(level, x, y, z, data);
if (minecraft->options.destroyVibration) minecraft->platform()->vibrate(24); if (minecraft->options.getBooleanValue(OPTIONS_DESTROY_VIBRATION)) minecraft->platform()->vibrate(24);
if (minecraft->isOnline()) { if (minecraft->isOnline()) {
RemoveBlockPacket packet(minecraft->player, x, y, z); RemoveBlockPacket packet(minecraft->player, x, y, z);

View File

@@ -1,7 +1,10 @@
#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 "screens/ChatScreen.h"
#include "screens/ConsoleScreen.h"
#include "../Minecraft.h" #include "../Minecraft.h"
#include "../player/LocalPlayer.h" #include "../player/LocalPlayer.h"
#include "../renderer/Tesselator.h" #include "../renderer/Tesselator.h"
@@ -23,6 +26,7 @@
#include "../../world/PosTranslator.h" #include "../../world/PosTranslator.h"
#include "../../platform/time.h" #include "../../platform/time.h"
#include <cmath> #include <cmath>
#include <algorithm>
float Gui::InvGuiScale = 1.0f / 3.0f; float Gui::InvGuiScale = 1.0f / 3.0f;
float Gui::GuiScale = 1.0f / Gui::InvGuiScale; float Gui::GuiScale = 1.0f / Gui::InvGuiScale;
@@ -36,6 +40,7 @@ Gui::Gui(Minecraft* minecraft)
progress(0), progress(0),
overlayMessageTime(0), overlayMessageTime(0),
animateOverlayMessageColor(false), animateOverlayMessageColor(false),
chatScrollOffset(0),
tbr(1), tbr(1),
_inventoryNeedsUpdate(true), _inventoryNeedsUpdate(true),
_flashSlotId(-1), _flashSlotId(-1),
@@ -87,6 +92,7 @@ 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->options.getBooleanValue(OPTIONS_HIDEGUI)) {
if (minecraft->gameMode->canHurtPlayer()) { if (minecraft->gameMode->canHurtPlayer()) {
minecraft->textures->loadAndBindTexture("gui/icons.png"); minecraft->textures->loadAndBindTexture("gui/icons.png");
Tesselator& t = Tesselator::instance; Tesselator& t = Tesselator::instance;
@@ -96,6 +102,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) {
renderBubbles(); renderBubbles();
t.endOverrideAndDraw(); t.endOverrideAndDraw();
} }
}
if(minecraft->player->getSleepTimer() > 0) { if(minecraft->player->getSleepTimer() > 0) {
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@@ -106,23 +113,38 @@ 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);
bool isChatting = (minecraft->screen && (dynamic_cast<ChatScreen*>(minecraft->screen) || dynamic_cast<ConsoleScreen*>(minecraft->screen)));
unsigned int max = 10; unsigned int max = 10;
bool isChatting = false; if (isChatting) {
int lineHeight = 9;
max = (screenHeight - 48) / lineHeight;
if (max < 1) max = 1;
int maxScroll = (int)guiMessages.size() - (int)max;
if (maxScroll < 0) maxScroll = 0;
if (chatScrollOffset > maxScroll) chatScrollOffset = maxScroll;
} else {
chatScrollOffset = 0;
}
renderChatMessages(screenHeight, max, isChatting, font); renderChatMessages(screenHeight, max, isChatting, font);
#if !defined(RPI) #if !defined(RPI)
renderOnSelectItemNameText(screenWidth, font, ySlot); renderOnSelectItemNameText(screenWidth, font, ySlot);
#endif #endif
#if defined(RPI) #if defined(RPI)
renderDebugInfo(); renderDebugInfo();
#elif defined(PLATFORM_DESKTOP)
if (minecraft->options.renderDebug)
renderDebugInfo();
#endif #endif
if (Keyboard::isKeyDown(Keyboard::KEY_TAB)) {
renderPlayerList(font, screenWidth, screenHeight);
}
if (minecraft->options.getBooleanValue(OPTIONS_RENDER_DEBUG))
renderDebugInfo();
}
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable2(GL_ALPHA_TEST); glEnable2(GL_ALPHA_TEST);
} }
@@ -201,6 +223,33 @@ void Gui::handleClick(int button, int x, int y) {
void Gui::handleKeyPressed(int key) void Gui::handleKeyPressed(int key)
{ {
bool isChatting = (minecraft->screen && (dynamic_cast<ChatScreen*>(minecraft->screen) || dynamic_cast<ConsoleScreen*>(minecraft->screen)));
if (isChatting) {
// Allow scrolling the chat history with the mouse/keyboard when chat is open
if (key == 38) { // VK_UP
scrollChat(1);
return;
} else if (key == 40) { // VK_DOWN
scrollChat(-1);
return;
} else if (key == 33) { // VK_PRIOR (Page Up)
// Scroll by a page
int screenHeight = (int)(minecraft->height * InvGuiScale);
int maxVisible = (screenHeight - 48) / 9;
scrollChat(maxVisible);
return;
} else if (key == 34) { // VK_NEXT (Page Down)
int screenHeight = (int)(minecraft->height * InvGuiScale);
int maxVisible = (screenHeight - 48) / 9;
scrollChat(-maxVisible);
return;
}
}
if (key == Keyboard::KEY_F1) {
minecraft->options.toggle(OPTIONS_HIDEGUI);
}
if (key == 99) if (key == 99)
{ {
if (minecraft->player->inventory->selected > 0) if (minecraft->player->inventory->selected > 0)
@@ -219,12 +268,29 @@ void Gui::handleKeyPressed(int key)
{ {
minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION); minecraft->screenChooser.setScreen(SCREEN_BLOCKSELECTION);
} }
else if (key == minecraft->options.keyDrop.key) else if (key == minecraft->options.getIntValue(OPTIONS_KEY_DROP))
{ {
minecraft->player->inventory->dropSlot(minecraft->player->inventory->selected, false); minecraft->player->inventory->dropSlot(minecraft->player->inventory->selected, false);
} }
} }
void Gui::scrollChat(int delta) {
if (delta == 0)
return;
int screenHeight = (int)(minecraft->height * InvGuiScale);
int maxVisible = (screenHeight - 48) / 9;
if (maxVisible <= 0)
return;
int maxScroll = (int)guiMessages.size() - maxVisible;
if (maxScroll < 0) maxScroll = 0;
int desired = chatScrollOffset + delta;
if (desired < 0) desired = 0;
if (desired > maxScroll) desired = maxScroll;
chatScrollOffset = desired;
}
void Gui::tick() { void Gui::tick() {
if (overlayMessageTime > 0) overlayMessageTime--; if (overlayMessageTime > 0) overlayMessageTime--;
tickCount++; tickCount++;
@@ -255,9 +321,22 @@ void Gui::addMessage(const std::string& _string) {
message.message = string; message.message = string;
message.ticks = 0; message.ticks = 0;
guiMessages.insert(guiMessages.begin(), message); guiMessages.insert(guiMessages.begin(), message);
while (guiMessages.size() > 30) {
// Keep a larger history so users can scroll through the full chat
const unsigned int MaxHistoryLines = 200;
while (guiMessages.size() > MaxHistoryLines) {
guiMessages.pop_back(); guiMessages.pop_back();
} }
// If the user has scrolled up, keep their window fixed (new messages shift older ones down)
if (chatScrollOffset > 0) {
chatScrollOffset++;
}
}
void Gui::clearMessages() {
guiMessages.clear();
chatScrollOffset = 0;
} }
void Gui::setNowPlaying(const std::string& string) { void Gui::setNowPlaying(const std::string& string) {
@@ -402,7 +481,7 @@ void Gui::onConfigChanged( const Config& c ) {
if (c.minecraft->useTouchscreen()) { if (c.minecraft->useTouchscreen()) {
// I'll bump this up to 6. // I'll bump this up to 6.
int num = 6; // without "..." dots int num = 6; // without "..." dots
if (!c.minecraft->options.isJoyTouchArea && c.width > 480) { if (!c.minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA) && c.width > 480) {
while (num < Inventory::MAX_SELECTION_SIZE - 1) { while (num < Inventory::MAX_SELECTION_SIZE - 1) {
int x0, x1, y; int x0, x1, y;
getSlotPos(0, x0, y); getSlotPos(0, x0, y);
@@ -516,7 +595,8 @@ void Gui::renderProgressIndicator( const bool isTouchInterface, const int screen
ItemInstance* currentItem = minecraft->player->inventory->getSelected(); ItemInstance* currentItem = minecraft->player->inventory->getSelected();
bool bowEquipped = currentItem != NULL ? currentItem->getItem() == Item::bow : false; bool bowEquipped = currentItem != NULL ? currentItem->getItem() == Item::bow : false;
bool itemInUse = currentItem != NULL ? currentItem->getItem() == minecraft->player->getUseItem()->getItem() : false; bool itemInUse = currentItem != NULL ? currentItem->getItem() == minecraft->player->getUseItem()->getItem() : false;
if (!isTouchInterface || minecraft->options.isJoyTouchArea || (bowEquipped && itemInUse)) { if ((!isTouchInterface || minecraft->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA)
|| (bowEquipped && itemInUse)) && !minecraft->options.getBooleanValue(OPTIONS_HIDEGUI)) {
minecraft->textures->loadAndBindTexture("gui/icons.png"); minecraft->textures->loadAndBindTexture("gui/icons.png");
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); glBlendFunc2(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
@@ -585,11 +665,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 +700,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);
} }
@@ -721,6 +808,83 @@ void Gui::renderDebugInfo() {
t.endOverrideAndDraw(); t.endOverrideAndDraw();
} }
void Gui::renderPlayerList(Font* font, int screenWidth, int screenHeight) {
// only show when in game, no other screen
// if (!minecraft->level) return;
// only show the overlay while connected to a multiplayer server
Level* level = minecraft->level;
if (!level) return;
if (!level->isClientSide) return;
std::vector<std::string> playerNames;
playerNames.reserve(level->players.size());
for (Player* player : level->players) {
if (!player) continue;
playerNames.push_back(player->name);
}
// is this check needed? if there are no players, the box won't render at all since height will be 0,
// but maybe we want to skip rendering entirely in that case
// if (playerNames.empty())
// return;
std::sort(playerNames.begin(), playerNames.end());
float maxNameWidth = 0.0f;
// find the longest name so we can size the box accordingly
for (const std::string& name : playerNames) {
float nameWidth = font->width(name);
if (nameWidth > maxNameWidth)
maxNameWidth = nameWidth;
}
// player count title
std::string titleText = "Players (" + std::to_string(playerNames.size()) + ")";
float titleWidth = font->width(titleText);
if (titleWidth > maxNameWidth)
maxNameWidth = titleWidth;
const float padding = 4.0f;
const float lineHeight = (float)Font::DefaultLineHeight;
const float boxWidth = maxNameWidth + padding * 2;
const float boxHeight = (playerNames.size() + 1) * lineHeight + padding * 2;
const float boxLeft = (screenWidth - boxWidth) / 2.0f;
const float boxTop = 10.0f;
const float boxRight = boxLeft + boxWidth;
const float boxBottom = boxTop + boxHeight;
fill(boxLeft, boxTop, boxRight, boxBottom, 0x90000000);
float titleX = (screenWidth - titleWidth) / 2.0f;
float titleY = boxTop + padding;
// scale the text down slightly
// i think the gl scaling is the best for this
// oh my god this looks really bad OH GOD
//const float textScale = 0.8f;
//const float invTextScale = 1.0f / textScale;
//glPushMatrix2();
//glScalef2(textScale, textScale, 1);
// draw title
//font->draw(titleText, titleX * invTextScale, titleY * invTextScale, 0xFFFFFFFF);
font->draw(titleText, titleX, titleY, 0xFFFFFFFF);
// draw player names
// we should add ping icons here eventually, but for now just show names
float currentY = boxTop + padding + lineHeight;
for (const std::string& name : playerNames) {
font->draw(name, (boxLeft + padding), currentY, 0xFFDDDDDD);
currentY += lineHeight;
}
//glPopMatrix2();
}
void Gui::renderSleepAnimation( const int screenWidth, const int screenHeight ) { void Gui::renderSleepAnimation( const int screenWidth, const int screenHeight ) {
int timer = minecraft->player->getSleepTimer(); int timer = minecraft->player->getSleepTimer();
float amount = (float) timer / (float) Player::SLEEP_DURATION; float amount = (float) timer / (float) Player::SLEEP_DURATION;
@@ -830,9 +994,16 @@ void Gui::renderChatMessages( const int screenHeight, unsigned int max, bool isC
// // glScalef2(1.0f / ssc.scale, 1.0f / ssc.scale, 1); // // glScalef2(1.0f / ssc.scale, 1.0f / ssc.scale, 1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int baseY = screenHeight - 48; int baseY = screenHeight - 48;
for (unsigned int i = 0; i < guiMessages.size() && i < max; i++) { int start = chatScrollOffset;
if (guiMessages.at(i).ticks < 20 * 10 || isChatting) { if (start < 0) start = 0;
float t = guiMessages.at(i).ticks / (20 * 10.0f); for (unsigned int i = 0; i < max; i++) {
unsigned int msgIdx = (unsigned int)start + i;
if (msgIdx >= guiMessages.size())
break;
GuiMessage& message = guiMessages.at(msgIdx);
if (message.ticks < 20 * 10 || isChatting) {
float t = message.ticks / (20 * 10.0f);
t = 1 - t; t = 1 - t;
t = t * 10; t = t * 10;
if (t < 0) t = 0; if (t < 0) t = 0;
@@ -844,7 +1015,7 @@ void Gui::renderChatMessages( const int screenHeight, unsigned int max, bool isC
if (alpha > 0) { if (alpha > 0) {
const float x = 2; const float x = 2;
const float y = (float)(baseY - i * 9); const float y = (float)(baseY - i * 9);
std::string msg = guiMessages.at(i).message; std::string msg = message.message;
this->fill(x, y - 1, x + MAX_MESSAGE_WIDTH, y + 8, (alpha / 2) << 24); this->fill(x, y - 1, x + MAX_MESSAGE_WIDTH, y + 8, (alpha / 2) << 24);
glEnable(GL_BLEND); glEnable(GL_BLEND);

View File

@@ -39,6 +39,7 @@ public:
void handleClick(int button, int x, int y); void handleClick(int button, int x, int y);
void handleKeyPressed( int key ); void handleKeyPressed( int key );
void scrollChat(int delta);
void tick(); void tick();
void render(float a, bool mouseFree, int xMouse, int yMouse); void render(float a, bool mouseFree, int xMouse, int yMouse);
@@ -60,10 +61,12 @@ public:
void renderBubbles(); void renderBubbles();
void renderHearts(); void renderHearts();
void renderDebugInfo(); void renderDebugInfo();
void renderPlayerList(Font* font, int screenWidth, int screenHeight);
void renderProgressIndicator( const bool isTouchInterface, const int screenWidth, const int screenHeight, float a ); void renderProgressIndicator( const bool isTouchInterface, const int screenWidth, const int screenHeight, float a );
void addMessage(const std::string& string); void addMessage(const std::string& string);
void clearMessages();
void postError(int errCode); void postError(int errCode);
void onGraphicsReset(); void onGraphicsReset();
@@ -96,6 +99,7 @@ private:
int MAX_MESSAGE_WIDTH; int MAX_MESSAGE_WIDTH;
//ItemRenderer itemRenderer; //ItemRenderer itemRenderer;
GuiMessageList guiMessages; GuiMessageList guiMessages;
int chatScrollOffset;
Random random; Random random;
Minecraft* minecraft; Minecraft* minecraft;

View File

@@ -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;
@@ -104,7 +112,7 @@ void Screen::keyboardEvent()
} }
void Screen::keyboardTextEvent() void Screen::keyboardTextEvent()
{ {
keyboardNewChar(Keyboard::getChar()); charPressed(Keyboard::getChar());
} }
void Screen::renderBackground() void Screen::renderBackground()
{ {
@@ -166,7 +174,7 @@ void Screen::keyPressed( int eventKey )
// pass key events to any text boxes first // pass key events to any text boxes first
for (auto& textbox : textBoxes) { for (auto& textbox : textBoxes) {
textbox->handleKey(eventKey); textbox->keyPressed(minecraft, eventKey);
} }
if (minecraft->useTouchscreen()) if (minecraft->useTouchscreen())
@@ -178,11 +186,11 @@ void Screen::keyPressed( int eventKey )
return; return;
Options& o = minecraft->options; Options& o = minecraft->options;
if (eventKey == o.keyMenuNext.key) if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_NEXT))
if (++tabButtonIndex == tabButtonCount) tabButtonIndex = 0; if (++tabButtonIndex == tabButtonCount) tabButtonIndex = 0;
if (eventKey == o.keyMenuPrevious.key) if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_PREV))
if (--tabButtonIndex == -1) tabButtonIndex = tabButtonCount-1; if (--tabButtonIndex == -1) tabButtonIndex = tabButtonCount-1;
if (eventKey == o.keyMenuOk.key) { if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_OK)) {
Button* button = tabButtons[tabButtonIndex]; Button* button = tabButtons[tabButtonIndex];
if (button->active) { if (button->active) {
minecraft->soundEngine->playUI("random.click", 1, 1); minecraft->soundEngine->playUI("random.click", 1, 1);
@@ -193,6 +201,12 @@ void Screen::keyPressed( int eventKey )
updateTabButtonSelection(); updateTabButtonSelection();
} }
void Screen::charPressed(char inputChar) {
for (auto& textbox : textBoxes) {
textbox->charPressed(minecraft, inputChar);
}
}
void Screen::updateTabButtonSelection() void Screen::updateTabButtonSelection()
{ {
if (minecraft->useTouchscreen()) if (minecraft->useTouchscreen())

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,9 @@
#include "OptionsItem.h" #include "OptionsItem.h"
#include "Slider.h" #include "Slider.h"
#include "../../../locale/I18n.h" #include "../../../locale/I18n.h"
#include "TextOption.h"
#include "KeyOption.h"
OptionsGroup::OptionsGroup( std::string labelID ) { OptionsGroup::OptionsGroup( std::string labelID ) {
label = I18n::get(labelID); label = I18n::get(labelID);
} }
@@ -25,73 +28,87 @@ void OptionsGroup::setupPositions() {
void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) { void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) {
float padX = 10.0f; float padX = 10.0f;
float padY = 5.0f; float padY = 5.0f;
minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false); minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false);
super::render(minecraft, xm, ym); super::render(minecraft, xm, ym);
} }
OptionsGroup& OptionsGroup::addOptionItem( const Options::Option* option, Minecraft* minecraft ) { OptionsGroup& OptionsGroup::addOptionItem(OptionId optId, Minecraft* minecraft ) {
if(option->isBoolean()) auto option = minecraft->options.getOpt(optId);
createToggle(option, minecraft);
else if(option->isProgress()) if (option == nullptr) return *this;
createProgressSlider(option, minecraft);
else if(option->isInt()) // TODO: do a options key class to check it faster via dynamic_cast
createStepSlider(option, minecraft); if (option->getStringId().find("options.key") != std::string::npos) createKey(optId, minecraft);
else if (dynamic_cast<OptionBool*>(option)) createToggle(optId, minecraft);
else if (dynamic_cast<OptionFloat*>(option)) createProgressSlider(optId, minecraft);
else if (dynamic_cast<OptionInt*>(option)) createStepSlider(optId, minecraft);
else if (dynamic_cast<OptionString*>(option)) createTextbox(optId, minecraft);
return *this; return *this;
} }
void OptionsGroup::createToggle( const Options::Option* option, Minecraft* minecraft ) { // TODO: wrap this copypaste shit into templates
void OptionsGroup::createToggle(OptionId optId, Minecraft* minecraft ) {
ImageDef def; ImageDef def;
def.setSrc(IntRectangle(160, 206, 39, 20)); def.setSrc(IntRectangle(160, 206, 39, 20));
def.name = "gui/touchgui.png"; def.name = "gui/touchgui.png";
def.width = 39 * 0.7f; def.width = 39 * 0.7f;
def.height = 20 * 0.7f; def.height = 20 * 0.7f;
OptionButton* element = new OptionButton(option);
OptionButton* element = new OptionButton(optId);
element->setImageDef(def, true); element->setImageDef(def, true);
element->updateImage(&minecraft->options); element->updateImage(&minecraft->options);
std::string itemLabel = I18n::get(option->getCaptionId());
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item);
setupPositions();
}
void OptionsGroup::createProgressSlider(OptionId optId, Minecraft* minecraft ) {
Slider* element = new SliderFloat(minecraft, optId);
element->width = 100;
element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }
void OptionsGroup::createProgressSlider( const Options::Option* option, Minecraft* minecraft ) { void OptionsGroup::createStepSlider(OptionId optId, Minecraft* minecraft ) {
Slider* element = new Slider(minecraft, Slider* element = new SliderInt(minecraft, optId);
option,
minecraft->options.getProgrssMin(option),
minecraft->options.getProgrssMax(option));
element->width = 100; element->width = 100;
element->height = 20; element->height = 20;
std::string itemLabel = I18n::get(option->getCaptionId()); std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();
} }
void OptionsGroup::createStepSlider( const Options::Option* option, Minecraft* minecraft ) { void OptionsGroup::createTextbox(OptionId optId, Minecraft* minecraft) {
// integer-valued option; use step slider TextBox* element = new TextOption(minecraft, optId);
std::vector<int> steps;
// render distance was removed; fall through to other cases
if(option == &Options::Option::DIFFICULTY) {
steps.push_back(0);
steps.push_back(1);
steps.push_back(2);
steps.push_back(3);
} else if(option == &Options::Option::GUI_SCALE) {
// slider order: small,normal,large,larger,auto
steps.push_back(1);
steps.push_back(2);
steps.push_back(3);
steps.push_back(4);
steps.push_back(0);
} else {
// fallback: use single value; duplicate so numSteps>1 and avoid divide-by-zero
steps.push_back(0);
steps.push_back(0);
}
Slider* element = new Slider(minecraft, option, steps);
element->width = 100; element->width = 100;
element->height = 20; element->height = 20;
std::string itemLabel = I18n::get(option->getCaptionId());
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item);
setupPositions();
}
void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) {
KeyOption* element = new KeyOption(minecraft, optId);
element->width = 50;
element->height = 20;
std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId());
OptionsItem* item = new OptionsItem(itemLabel, element); OptionsItem* item = new OptionsItem(itemLabel, element);
addChild(item); addChild(item);
setupPositions(); setupPositions();

View File

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

51
src/client/gui/components/OptionsPane.cpp Executable file → Normal file
View File

@@ -29,36 +29,35 @@ OptionsGroup& OptionsPane::createOptionsGroup( std::string label ) {
} }
void OptionsPane::createToggle( unsigned int group, std::string label, const Options::Option* option ) { void OptionsPane::createToggle( unsigned int group, std::string label, const Options::Option* option ) {
// if(group > children.size()) return; if(group > children.size()) return;
// ImageDef def; ImageDef def;
// def.setSrc(IntRectangle(160, 206, 39, 20)); def.setSrc(IntRectangle(160, 206, 39, 20));
// def.name = "gui/touchgui.png"; def.name = "gui/touchgui.png";
// def.width = 39 * 0.7f; def.width = 39 * 0.7f;
// def.height = 20 * 0.7f; def.height = 20 * 0.7f;
// OptionButton* element = new OptionButton(option); OptionButton* element = new OptionButton(option);
// element->setImageDef(def, true); element->setImageDef(def, true);
// OptionsItem* item = new OptionsItem(label, element); OptionsItem* item = new OptionsItem(label, element);
// ((OptionsGroup*)children[group])->addChild(item); ((OptionsGroup*)children[group])->addChild(item);
// setupPositions(); setupPositions();
} }
void OptionsPane::createProgressSlider( Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, float progressMin/*=1.0f*/, float progressMax/*=1.0f */ ) { void OptionsPane::createProgressSlider( Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, float progressMin/*=1.0f*/, float progressMax/*=1.0f */ ) {
// if(group > children.size()) return; if(group > children.size()) return;
// Slider* element = new Slider(minecraft, option, progressMin, progressMax); Slider* element = new Slider(minecraft, option, progressMin, progressMax);
// element->width = 100; element->width = 100;
// element->height = 20; element->height = 20;
// OptionsItem* item = new OptionsItem(label, element); OptionsItem* item = new OptionsItem(label, element);
// ((OptionsGroup*)children[group])->addChild(item); ((OptionsGroup*)children[group])->addChild(item);
// setupPositions(); setupPositions();
} }
void OptionsPane::createStepSlider( Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, const std::vector<int>& stepVec ) { void OptionsPane::createStepSlider( Minecraft* minecraft, unsigned int group, std::string label, const Options::Option* option, const std::vector<int>& stepVec ) {
// if(group > children.size()) return; if(group > children.size()) return;
// Slider* element = new Slider(minecraft, option, stepVec); Slider* element = new Slider(minecraft, option, stepVec);
// element->width = 100; element->width = 100;
// element->height = 20; element->height = 20;
// sliders.push_back(element); OptionsItem* item = new OptionsItem(label, element);
// OptionsItem* item = new OptionsItem(label, element); ((OptionsGroup*)children[group])->addChild(item);
// ((OptionsGroup*)children[group])->addChild(item); setupPositions();
// setupPositions();
} }

0
src/client/gui/components/OptionsPane.h Executable file → Normal file
View File

View File

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

View File

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

View File

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

View File

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

0
src/client/gui/components/SmallButton.cpp Executable file → Normal file
View File

0
src/client/gui/components/SmallButton.h Executable file → Normal file
View File

View File

@@ -49,13 +49,13 @@ void TextBox::mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) {
} }
} }
void TextBox::handleChar(char c) { void TextBox::charPressed(Minecraft* minecraft, char c) {
if (focused && c >= 32 && c < 127 && (int)text.size() < 256) { if (focused && c >= 32 && c < 127 && (int)text.size() < 256) {
text.push_back(c); text.push_back(c);
} }
} }
void TextBox::handleKey(int key) { void TextBox::keyPressed(Minecraft* minecraft, int key) {
if (focused && key == Keyboard::KEY_BACKSPACE && !text.empty()) { if (focused && key == Keyboard::KEY_BACKSPACE && !text.empty()) {
text.pop_back(); text.pop_back();
} }

View File

@@ -26,8 +26,8 @@ public:
virtual void render(Minecraft* minecraft, int xm, int ym); virtual void render(Minecraft* minecraft, int xm, int ym);
virtual void handleKey(int key); virtual void keyPressed(Minecraft* minecraft, int key);
virtual void handleChar(char c); virtual void charPressed(Minecraft* minecraft, char c);
virtual void tick(Minecraft* minecraft); virtual void tick(Minecraft* minecraft);
public: public:

View File

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

View File

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

View File

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

View File

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

View File

@@ -48,7 +48,7 @@ void ConsoleScreen::keyPressed(int eventKey)
} }
} }
void ConsoleScreen::keyboardNewChar(char inputChar) void ConsoleScreen::charPressed(char inputChar)
{ {
if (inputChar >= 32 && inputChar < 127) if (inputChar >= 32 && inputChar < 127)
_input += inputChar; _input += inputChar;

View File

@@ -20,7 +20,7 @@ public:
virtual bool isPauseScreen() { return false; } virtual bool isPauseScreen() { return false; }
virtual void keyPressed(int eventKey); virtual void keyPressed(int eventKey);
virtual void keyboardNewChar(char inputChar); virtual void charPressed(char inputChar);
virtual bool handleBackEvent(bool isDown); virtual bool handleBackEvent(bool isDown);
private: private:

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,8 @@
#include "ProgressScreen.h" #include "ProgressScreen.h"
#include "../Font.h" #include "../Font.h"
#include "../../../network/RakNetInstance.h" #include "../../../network/RakNetInstance.h"
#include "client/Options.h"
#include "client/gui/Screen.h"
#include "client/gui/components/TextBox.h" #include "client/gui/components/TextBox.h"
#include "network/ClientSideNetworkHandler.h" #include "network/ClientSideNetworkHandler.h"
@@ -31,7 +33,7 @@ void JoinByIPScreen::buttonClicked(Button* button)
minecraft->joinMultiplayerFromString(tIP.text); minecraft->joinMultiplayerFromString(tIP.text);
{ {
minecraft->options.set(OPTIONS_LAST_IP, tIP.text);
bJoin.active = false; bJoin.active = false;
bBack.active = false; bBack.active = false;
minecraft->setScreen(new ProgressScreen()); minecraft->setScreen(new ProgressScreen());
@@ -55,6 +57,7 @@ bool JoinByIPScreen::handleBackEvent(bool isDown)
void JoinByIPScreen::tick() void JoinByIPScreen::tick()
{ {
Screen::tick();
bJoin.active = !tIP.text.empty(); bJoin.active = !tIP.text.empty();
} }
@@ -78,6 +81,8 @@ void JoinByIPScreen::init()
tabButtons.push_back(&bBack); tabButtons.push_back(&bBack);
tabButtons.push_back(&bHeader); tabButtons.push_back(&bHeader);
#endif #endif
tIP.text = minecraft->options.getStringValue(OPTIONS_LAST_IP);
} }
void JoinByIPScreen::setupPositions() { void JoinByIPScreen::setupPositions() {
@@ -102,21 +107,6 @@ void JoinByIPScreen::setupPositions() {
tIP.y = ((height - bJoin.height) / 2) - tIP.height - 4; 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 ) void JoinByIPScreen::render( int xm, int ym, float a )
{ {
renderBackground(); renderBackground();
@@ -132,9 +122,3 @@ void JoinByIPScreen::keyPressed(int eventKey)
// let base class handle navigation and text box keys // let base class handle navigation and text box keys
Screen::keyPressed(eventKey); Screen::keyPressed(eventKey);
} }
void JoinByIPScreen::keyboardNewChar(char inputChar)
{
// forward character input to focused textbox(s)
for (auto* tb : textBoxes) tb->handleChar(inputChar);
}

View File

@@ -18,9 +18,7 @@ public:
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
virtual void keyPressed(int eventKey); virtual void keyPressed(int eventKey);
virtual void keyboardNewChar(char inputChar);
void buttonClicked(Button* button); void buttonClicked(Button* button);
virtual void mouseClicked(int x, int y, int buttonNum);
virtual bool handleBackEvent(bool isDown); virtual bool handleBackEvent(bool isDown);
private: private:
TextBox tIP; TextBox tIP;

View File

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

View File

@@ -7,14 +7,12 @@
#include "../../../AppPlatform.h" #include "../../../AppPlatform.h"
#include "CreditsScreen.h" #include "CreditsScreen.h"
#include "../components/OptionsPane.h"
#include "../components/ImageButton.h" #include "../components/ImageButton.h"
#include "../components/OptionsGroup.h" #include "../components/OptionsGroup.h"
OptionsScreen::OptionsScreen() OptionsScreen::OptionsScreen()
: btnClose(NULL), : btnClose(NULL),
bHeader(NULL), bHeader(NULL),
btnChangeUsername(NULL),
btnCredits(NULL), btnCredits(NULL),
selectedCategory(0) { selectedCategory(0) {
} }
@@ -31,11 +29,6 @@ OptionsScreen::~OptionsScreen() {
bHeader = NULL; bHeader = NULL;
} }
if (btnChangeUsername != NULL) {
delete btnChangeUsername;
btnChangeUsername = NULL;
}
if (btnCredits != NULL) { if (btnCredits != NULL) {
delete btnCredits; delete btnCredits;
btnCredits = NULL; btnCredits = NULL;
@@ -48,7 +41,7 @@ OptionsScreen::~OptionsScreen() {
} }
} }
for (std::vector<OptionsPane*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) { for (std::vector<OptionsGroup*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) {
if (*it != NULL) { if (*it != NULL) {
delete* it; delete* it;
*it = NULL; *it = NULL;
@@ -72,17 +65,16 @@ void OptionsScreen::init() {
def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height));
btnClose->setImageDef(def, true); btnClose->setImageDef(def, true);
categoryButtons.push_back(new Touch::TButton(2, "Login")); categoryButtons.push_back(new Touch::TButton(2, "General"));
categoryButtons.push_back(new Touch::TButton(3, "Game")); categoryButtons.push_back(new Touch::TButton(3, "Game"));
categoryButtons.push_back(new Touch::TButton(4, "Controls")); categoryButtons.push_back(new Touch::TButton(4, "Controls"));
categoryButtons.push_back(new Touch::TButton(5, "Graphics")); categoryButtons.push_back(new Touch::TButton(5, "Graphics"));
categoryButtons.push_back(new Touch::TButton(6, "Tweaks"));
btnChangeUsername = new Touch::TButton(10, "Username");
btnCredits = new Touch::TButton(11, "Credits"); btnCredits = new Touch::TButton(11, "Credits");
buttons.push_back(bHeader); buttons.push_back(bHeader);
buttons.push_back(btnClose); buttons.push_back(btnClose);
buttons.push_back(btnChangeUsername);
buttons.push_back(btnCredits); buttons.push_back(btnCredits);
for (std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { for (std::vector<Touch::TButton*>::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) {
@@ -118,27 +110,13 @@ void OptionsScreen::setupPositions() {
bHeader->width = width - btnClose->width; bHeader->width = width - btnClose->width;
bHeader->height = btnClose->height; bHeader->height = btnClose->height;
// Username button (bottom-left)
if (btnChangeUsername != NULL) {
btnChangeUsername->width = categoryButtons.empty() ? 80 : categoryButtons[0]->width;
btnChangeUsername->height = btnClose->height;
btnChangeUsername->x = 0;
btnChangeUsername->y = height - btnChangeUsername->height;
}
// Credits button (bottom-right) // Credits button (bottom-right)
if (btnCredits != NULL) { if (btnCredits != NULL) {
btnCredits->width = btnChangeUsername->width;
btnCredits->height = btnChangeUsername->height;
btnCredits->x = width - btnCredits->width; btnCredits->x = width - btnCredits->width;
btnCredits->y = height - btnCredits->height; btnCredits->y = height - btnCredits->height;
} }
for (std::vector<OptionsPane*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) { for (std::vector<OptionsGroup*>::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) {
if (categoryButtons.size() > 0 && categoryButtons[0] != NULL) { if (categoryButtons.size() > 0 && categoryButtons[0] != NULL) {
@@ -158,13 +136,13 @@ void OptionsScreen::render(int xm, int ym, float a) {
renderBackground(); renderBackground();
super::render(xm, ym, a);
int xmm = xm * width / minecraft->width; int xmm = xm * width / minecraft->width;
int ymm = ym * height / minecraft->height - 1; int ymm = ym * height / minecraft->height - 1;
if (currentOptionPane != NULL) if (currentOptionsGroup != NULL)
currentOptionPane->render(minecraft, xmm, ymm); currentOptionsGroup->render(minecraft, xmm, ymm);
super::render(xm, ym, a);
} }
void OptionsScreen::removed() { void OptionsScreen::removed() {
@@ -173,16 +151,9 @@ void OptionsScreen::removed() {
void OptionsScreen::buttonClicked(Button* button) { void OptionsScreen::buttonClicked(Button* button) {
if (button == btnClose) { if (button == btnClose) {
minecraft->options.save(); minecraft->options.save();
minecraft->screenChooser.setScreen(SCREEN_STARTMENU); minecraft->screenChooser.setScreen(SCREEN_STARTMENU);
}
else if (button == btnChangeUsername) {
minecraft->options.save();
minecraft->setScreen(new UsernameScreen());
} }
else if (button->id > 1 && button->id < 7) { else if (button->id > 1 && button->id < 7) {
@@ -212,63 +183,92 @@ void OptionsScreen::selectCategory(int index) {
} }
if (index < (int)optionPanes.size()) if (index < (int)optionPanes.size())
currentOptionPane = optionPanes[index]; currentOptionsGroup = optionPanes[index];
} }
void OptionsScreen::generateOptionScreens() { void OptionsScreen::generateOptionScreens() {
// how the fuck it works
optionPanes.push_back(new OptionsPane()); optionPanes.push_back(new OptionsGroup("options.group.general"));
optionPanes.push_back(new OptionsPane()); optionPanes.push_back(new OptionsGroup("options.group.game"));
optionPanes.push_back(new OptionsPane()); optionPanes.push_back(new OptionsGroup("options.group.controls"));
optionPanes.push_back(new OptionsPane()); optionPanes.push_back(new OptionsGroup("options.group.graphics"));
optionPanes.push_back(new OptionsGroup("options.group.tweaks"));
// Login Pane // General Pane
optionPanes[0]->createOptionsGroup("options.group.mojang") optionPanes[0]->addOptionItem(OPTIONS_USERNAME, minecraft)
.addOptionItem(&Options::Option::SENSITIVITY, minecraft); .addOptionItem(OPTIONS_SENSITIVITY, minecraft);
// Game Pane // Game Pane
optionPanes[1]->createOptionsGroup("options.group.game") optionPanes[1]->addOptionItem(OPTIONS_DIFFICULTY, minecraft)
.addOptionItem(&Options::Option::DIFFICULTY, minecraft) .addOptionItem(OPTIONS_SERVER_VISIBLE, minecraft)
.addOptionItem(&Options::Option::SERVER_VISIBLE, minecraft) .addOptionItem(OPTIONS_THIRD_PERSON_VIEW, minecraft)
.addOptionItem(&Options::Option::THIRD_PERSON, minecraft) .addOptionItem(OPTIONS_GUI_SCALE, minecraft)
.addOptionItem(&Options::Option::GUI_SCALE, minecraft); .addOptionItem(OPTIONS_SENSITIVITY, minecraft)
.addOptionItem(OPTIONS_MUSIC_VOLUME, minecraft)
.addOptionItem(OPTIONS_SOUND_VOLUME, minecraft)
.addOptionItem(OPTIONS_SMOOTH_CAMERA, minecraft)
.addOptionItem(OPTIONS_DESTROY_VIBRATION, minecraft)
.addOptionItem(OPTIONS_IS_LEFT_HANDED, minecraft);
// Controls Pane // // Controls Pane
optionPanes[2]->createOptionsGroup("options.group.controls") optionPanes[2]->addOptionItem(OPTIONS_INVERT_Y_MOUSE, minecraft)
.addOptionItem(&Options::Option::INVERT_MOUSE, minecraft); .addOptionItem(OPTIONS_USE_TOUCHSCREEN, minecraft);
// Graphics Pane for (int i = OPTIONS_KEY_FORWARD; i <= OPTIONS_KEY_USE; i++) {
optionPanes[3]->createOptionsGroup("options.group.graphics") optionPanes[2]->addOptionItem((OptionId)i, minecraft);
.addOptionItem(&Options::Option::GRAPHICS, minecraft) }
.addOptionItem(&Options::Option::VIEW_BOBBING, minecraft)
.addOptionItem(&Options::Option::AMBIENT_OCCLUSION, minecraft) // // Graphics Pane
.addOptionItem(&Options::Option::ANAGLYPH, minecraft) optionPanes[3]->addOptionItem(OPTIONS_FANCY_GRAPHICS, minecraft)
.addOptionItem(&Options::Option::LIMIT_FRAMERATE, minecraft) // .addOptionItem(&Options::Option::VIEW_BOBBING, minecraft)
.addOptionItem(&Options::Option::VSYNC, minecraft) // .addOptionItem(&Options::Option::AMBIENT_OCCLUSION, minecraft)
.addOptionItem(&Options::Option::MUSIC, minecraft) // .addOptionItem(&Options::Option::ANAGLYPH, minecraft)
.addOptionItem(&Options::Option::SOUND, minecraft); .addOptionItem(OPTIONS_LIMIT_FRAMERATE, minecraft)
.addOptionItem(OPTIONS_VSYNC, minecraft)
.addOptionItem(OPTIONS_RENDER_DEBUG, minecraft)
.addOptionItem(OPTIONS_ANAGLYPH_3D, minecraft)
.addOptionItem(OPTIONS_VIEW_BOBBING, minecraft)
.addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft);
optionPanes[4]->addOptionItem(OPTIONS_ALLOW_SPRINT, minecraft)
.addOptionItem(OPTIONS_BAR_ON_TOP, minecraft);
} }
void OptionsScreen::mouseClicked(int x, int y, int buttonNum) { void OptionsScreen::mouseClicked(int x, int y, int buttonNum) {
if (currentOptionPane != NULL) if (currentOptionsGroup != NULL)
currentOptionPane->mouseClicked(minecraft, x, y, buttonNum); currentOptionsGroup->mouseClicked(minecraft, x, y, buttonNum);
super::mouseClicked(x, y, buttonNum); super::mouseClicked(x, y, buttonNum);
} }
void OptionsScreen::mouseReleased(int x, int y, int buttonNum) { void OptionsScreen::mouseReleased(int x, int y, int buttonNum) {
if (currentOptionPane != NULL) if (currentOptionsGroup != NULL)
currentOptionPane->mouseReleased(minecraft, x, y, buttonNum); currentOptionsGroup->mouseReleased(minecraft, x, y, buttonNum);
super::mouseReleased(x, y, buttonNum); super::mouseReleased(x, y, buttonNum);
} }
void OptionsScreen::keyPressed(int eventKey) {
if (currentOptionsGroup != NULL)
currentOptionsGroup->keyPressed(minecraft, eventKey);
super::keyPressed(eventKey);
}
void OptionsScreen::charPressed(char inputChar) {
if (currentOptionsGroup != NULL)
currentOptionsGroup->charPressed(minecraft, inputChar);
super::keyPressed(inputChar);
}
void OptionsScreen::tick() { void OptionsScreen::tick() {
if (currentOptionPane != NULL) if (currentOptionsGroup != NULL)
currentOptionPane->tick(minecraft); currentOptionsGroup->tick(minecraft);
super::tick(); super::tick();
} }

View File

@@ -3,6 +3,7 @@
#include "../Screen.h" #include "../Screen.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/OptionsGroup.h"
class ImageButton; class ImageButton;
class OptionsPane; class OptionsPane;
@@ -26,19 +27,21 @@ public:
virtual void mouseClicked(int x, int y, int buttonNum); virtual void mouseClicked(int x, int y, int buttonNum);
virtual void mouseReleased(int x, int y, int buttonNum); virtual void mouseReleased(int x, int y, int buttonNum);
virtual void keyPressed(int eventKey);
virtual void charPressed(char inputChar);
virtual void tick(); virtual void tick();
private: private:
Touch::THeader* bHeader; Touch::THeader* bHeader;
ImageButton* btnClose; ImageButton* btnClose;
Button* btnChangeUsername;
Button* btnCredits; // <-- ADD THIS Button* btnCredits; // <-- ADD THIS
std::vector<Touch::TButton*> categoryButtons; std::vector<Touch::TButton*> categoryButtons;
std::vector<OptionsPane*> optionPanes; std::vector<OptionsGroup*> optionPanes;
OptionsPane* currentOptionPane; OptionsGroup* currentOptionsGroup;
int selectedCategory; int selectedCategory;
}; };

View File

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

View File

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

View File

@@ -13,6 +13,8 @@
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include <client/gui/screens/UsernameScreen.h>
Screen* ScreenChooser::createScreen( ScreenId id ) Screen* ScreenChooser::createScreen( ScreenId id )
{ {
Screen* screen = NULL; Screen* screen = NULL;

View File

@@ -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,12 +412,34 @@ std::string SelectWorldScreen::getUniqueLevelName( const std::string& level )
bool SelectWorldScreen::isInGameScreen() { return true; } bool SelectWorldScreen::isInGameScreen() { return true; }
void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym)
{
if (!worldsList)
return;
if (dy == 0)
return;
int num = worldsList->getNumberOfItems();
int idx = worldsList->selectedItem;
if (dy > 0) {
if (idx > 0) {
idx--;
worldsList->stepLeft();
}
} else {
if (idx < num - 1) {
idx++;
worldsList->stepRight();
}
}
worldsList->selectedItem = idx;
}
void SelectWorldScreen::keyPressed( int eventKey ) void SelectWorldScreen::keyPressed( int eventKey )
{ {
if (bWorldView.selected) { if (bWorldView.selected) {
if (eventKey == minecraft->options.keyLeft.key) if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_RIGHT))
worldsList->stepLeft(); worldsList->stepLeft();
if (eventKey == minecraft->options.keyRight.key) if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_LEFT))
worldsList->stepRight(); worldsList->stepRight();
} }

View File

@@ -4,7 +4,6 @@
#include "../Screen.h" #include "../Screen.h"
#include "../TweenData.h" #include "../TweenData.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/SmallButton.h"
#include "../components/RolledSelectionListH.h" #include "../components/RolledSelectionListH.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
#include "../../../world/level/storage/LevelStorageSource.h" #include "../../../world/level/storage/LevelStorageSource.h"
@@ -90,6 +89,9 @@ public:
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
// mouse wheel scroll (new in desktop implementation)
virtual void mouseWheel(int dx, int dy, int xm, int ym);
bool isInGameScreen(); bool isInGameScreen();
private: private:
void loadLevelSource(); void loadLevelSource();

View File

@@ -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());
@@ -223,12 +253,6 @@ void SimpleChooseLevelScreen::keyPressed(int eventKey)
Screen::keyPressed(eventKey); Screen::keyPressed(eventKey);
} }
void SimpleChooseLevelScreen::keyboardNewChar(char inputChar)
{
// forward character input to focused textbox(s)
for (auto* tb : textBoxes) tb->handleChar(inputChar);
}
bool SimpleChooseLevelScreen::handleBackEvent(bool isDown) { bool SimpleChooseLevelScreen::handleBackEvent(bool isDown) {
if (!isDown) if (!isDown)
minecraft->screenChooser.setScreen(SCREEN_STARTMENU); minecraft->screenChooser.setScreen(SCREEN_STARTMENU);

View File

@@ -23,18 +23,19 @@ public:
void buttonClicked(Button* button); void buttonClicked(Button* button);
bool handleBackEvent(bool isDown); bool handleBackEvent(bool isDown);
virtual void keyPressed(int eventKey); virtual void keyPressed(int eventKey);
virtual void keyboardNewChar(char inputChar);
virtual void mouseClicked(int x, int y, int buttonNum); virtual void mouseClicked(int x, int y, int buttonNum);
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;

View File

@@ -6,11 +6,11 @@
#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"
#include "../Font.h" #include "../Font.h"
#include "../components/SmallButton.h"
#include "../components/ScrolledSelectionList.h" #include "../components/ScrolledSelectionList.h"
#include "../../Minecraft.h" #include "../../Minecraft.h"
@@ -25,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, 160, 24, "Options"),
bQuit( 5, "")
{ {
} }
@@ -35,10 +36,9 @@ StartMenuScreen::~StartMenuScreen()
void StartMenuScreen::init() void StartMenuScreen::init()
{ {
bJoin.active = bHost.active = bOptions.active = true; bJoin.active = bHost.active = bOptions.active = true;
if (minecraft->options.username.empty()) { if (minecraft->options.getStringValue(OPTIONS_USERNAME).empty()) {
return; // tick() will redirect to UsernameScreen return; // tick() will redirect to UsernameScreen
} }
@@ -54,16 +54,29 @@ 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!";
// always show base version string, suffix was previously added for Android builds // always show base version string, suffix was previously added for Android builds
std::string versionString = Common::getGameVersionString(); std::string versionString = Common::getGameVersionString();
std::string _username = minecraft->options.getStringValue(OPTIONS_USERNAME);
if (_username.empty()) _username = "unknown";
username = "Username: " + _username;
#ifdef DEMO_MODE #ifdef DEMO_MODE
#ifdef __APPLE__ #ifdef __APPLE__
version = versionString + " (Lite)"; version = versionString + " (Lite)";
@@ -77,38 +90,26 @@ void StartMenuScreen::init()
version = versionString; version = versionString;
#endif #endif
#endif #endif
bJoin.active = bHost.active = bOptions.active = false;
} }
void StartMenuScreen::setupPositions() { void StartMenuScreen::setupPositions() {
int yBase = height / 2 + 25; int yBase = height / 2;
//#ifdef ANDROID bHost.y = yBase;
bHost.y = yBase - 28; bJoin.y = bHost.y + 24 + 4;
#ifdef RPI bOptions.y = bJoin.y + 24 + 4;
bJoin.y = yBase + 4;
#else
bJoin.y = yBase;
#endif
bOptions.y = yBase + 28 + 2;
//#endif
// Center buttons // Center buttons
bHost.x = (width - bHost.width) / 2; bHost.x = (width - bHost.width) / 2;
bJoin.x = (width - bJoin.width) / 2; bJoin.x = (width - bJoin.width) / 2;
bOptions.x = (width - bJoin.width) / 2; bOptions.x = (width - bOptions.width) / 2;
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() {
if (minecraft->options.username.empty()) {
minecraft->setScreen(new UsernameScreen());
return;
}
} }
void StartMenuScreen::buttonClicked(Button* button) { void StartMenuScreen::buttonClicked(Button* button) {
@@ -130,6 +131,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; }
@@ -138,6 +143,9 @@ void StartMenuScreen::render( int xm, int ym, float a )
{ {
renderBackground(); renderBackground();
// Show current username in the top-left corner
drawString(font, username, 2, 2, 0xffffffff);
#if defined(RPI) #if defined(RPI)
TextureId id = minecraft->textures->loadTexture("gui/pi_title.png"); TextureId id = minecraft->textures->loadTexture("gui/pi_title.png");
#else #else
@@ -149,7 +157,7 @@ void StartMenuScreen::render( int xm, int ym, float a )
minecraft->textures->bind(id); minecraft->textures->bind(id);
const float x = (float)width / 2; const float x = (float)width / 2;
const float y = 4; const float y = height/16;
//const float scale = Mth::Min( //const float scale = Mth::Min(
const float wh = Mth::Min((float)width/2.0f, (float)data->w / 2); const float wh = Mth::Min((float)width/2.0f, (float)data->w / 2);
const float scale = 2.0f * wh / (float)data->w; const float scale = 2.0f * wh / (float)data->w;
@@ -171,14 +179,14 @@ void StartMenuScreen::render( int xm, int ym, float a )
blit(0, height - 12, 0, 0, 43, 12, 256, 72+72); blit(0, height - 12, 0, 0, 43, 12, 256, 72+72);
#endif #endif
drawString(font, version, versionPosX, 62, /*50,*/ 0xffcccccc);//0x666666); drawString(font, version, width - font->width(version) - 2, height - 10, 0xffcccccc);//0x666666);
drawString(font, copyright, copyrightPosX, height - 10, 0xffffff); drawString(font, copyright, 2, height - 20, 0xffffff);
glEnable2(GL_BLEND); glEnable2(GL_BLEND);
glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f2(1, 1, 1, 1); glColor4f2(1, 1, 1, 1);
if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/github.png"))) if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/github.png")))
blit(2, height - 10, 0, 0, 8, 8, 256, 256); blit(2, height - 10, 0, 0, 8, 8, 256, 256);
{ {
std::string txt = "Kolyah35/minecraft-pe-0.6.1"; std::string txt = "Kolyah35/minecraft-pe-0.6.1";
float wtxt = font->width(txt); float wtxt = font->width(txt);
Gui::drawColoredString(font, txt, 12, height - 10, 255); Gui::drawColoredString(font, txt, 12, height - 10, 255);
@@ -186,6 +194,9 @@ void StartMenuScreen::render( int xm, int ym, float a )
float y0 = height - 10 + font->lineHeight - 1; float y0 = height - 10 + font->lineHeight - 1;
this->fill(12, (int)y0, 12 + (int)wtxt, (int)(y0 + 1), 0xffffffff); this->fill(12, (int)y0, 12 + (int)wtxt, (int)(y0 + 1), 0xffffffff);
} }
Screen::render(xm, ym, a);
} }
void StartMenuScreen::mouseClicked(int x, int y, int buttonNum) { void StartMenuScreen::mouseClicked(int x, int y, int buttonNum) {

View File

@@ -3,6 +3,7 @@
#include "../Screen.h" #include "../Screen.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "../components/ImageButton.h"
class StartMenuScreen: public Screen class StartMenuScreen: public Screen
{ {
@@ -25,12 +26,15 @@ 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;
std::string version; std::string version;
int versionPosX; int versionPosX;
std::string username;
}; };
#endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__StartMenuScreen_H__*/ #endif /*NET_MINECRAFT_CLIENT_GUI_SCREENS__StartMenuScreen_H__*/

View File

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

View File

@@ -20,7 +20,7 @@ public:
void render(int xm, int ym, float a); void render(int xm, int ym, float a);
virtual void lostFocus(); virtual void lostFocus();
virtual void keyPressed(int eventKey); virtual void keyPressed(int eventKey);
virtual void keyboardNewChar(char inputChar); virtual void charPressed(char inputChar);
void setupPositions(); void setupPositions();
void buttonClicked(Button* button); void buttonClicked(Button* button);
protected: protected:

View File

@@ -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,33 +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);
}
void UsernameScreen::keyboardNewChar(char inputChar) // enable the Done button only when there is some text (and ensure it updates after backspace)
{ _btnDone.active = !tUsername.text.empty();
for (auto* tb : textBoxes) tb->handleChar(inputChar);
}
void UsernameScreen::mouseClicked(int x, int y, int button)
{
int lvlTop = tUsername.y - (Font::DefaultLineHeight + 4);
int lvlBottom = tUsername.y + tUsername.height;
int lvlLeft = tUsername.x;
int lvlRight = tUsername.x + tUsername.width;
bool clickedLevel = x >= lvlLeft && x < lvlRight && y >= lvlTop && y < lvlBottom;
if (clickedLevel) {
tUsername.setFocus(minecraft);
} else {
// click outside both fields -> blur both
tUsername.loseFocus(minecraft);
}
// also let the parent class handle button presses/etc.
Screen::mouseClicked(x, y, button);
} }
void UsernameScreen::removed() void UsernameScreen::removed()
@@ -95,7 +73,7 @@ void UsernameScreen::removed()
void UsernameScreen::buttonClicked(Button* button) void UsernameScreen::buttonClicked(Button* button)
{ {
if (button == &_btnDone && !tUsername.text.empty()) { if (button == &_btnDone && !tUsername.text.empty()) {
minecraft->options.username = tUsername.text; minecraft->options.set(OPTIONS_USERNAME, tUsername.text);
minecraft->options.save(); minecraft->options.save();
minecraft->user->name = tUsername.text; minecraft->user->name = tUsername.text;
minecraft->setScreen(NULL); // goes to StartMenuScreen minecraft->setScreen(NULL); // goes to StartMenuScreen

View File

@@ -3,7 +3,7 @@
#include "../Screen.h" #include "../Screen.h"
#include "../components/Button.h" #include "../components/Button.h"
#include "client/gui/components/TextBox.h" #include "/client/gui/components/TextBox.h"
#include <string> #include <string>
class UsernameScreen : public Screen class UsernameScreen : public Screen
@@ -13,24 +13,22 @@ public:
UsernameScreen(); UsernameScreen();
virtual ~UsernameScreen(); virtual ~UsernameScreen();
void init(); void init() override;
virtual void setupPositions() override; virtual void setupPositions() override;
void render(int xm, int ym, float a); void render(int xm, int ym, float a) override;
void tick(); void tick() override;
virtual bool isPauseScreen() { return false; } virtual bool isPauseScreen() override { return false; }
virtual void keyPressed(int eventKey); virtual void keyPressed(int eventKey) override;
virtual void keyboardNewChar(char inputChar); virtual bool handleBackEvent(bool isDown) override { return true; } // block back/escape
virtual bool handleBackEvent(bool isDown) { return true; } // block back/escape virtual void removed() override;
virtual void removed();
virtual void mouseClicked(int x, int y, int button);
protected: protected:
virtual void buttonClicked(Button* button); virtual void buttonClicked(Button* button) override;
private: private:
Button _btnDone; Touch::TButton _btnDone;
TextBox tUsername; TextBox tUsername;
std::string _input; std::string _input;
int _cursorBlink; int _cursorBlink;

View File

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

View File

@@ -21,30 +21,34 @@ public:
IngameBlockSelectionScreen(); IngameBlockSelectionScreen();
virtual ~IngameBlockSelectionScreen(); virtual ~IngameBlockSelectionScreen();
virtual void init(); virtual void init() override;
virtual void setupPositions(); virtual void setupPositions() override;
virtual void removed(); virtual void removed() override;
void tick(); void tick() override;
void render(int xm, int ym, float a); void render(int xm, int ym, float a) override;
bool hasClippingArea(IntRectangle& out); bool hasClippingArea(IntRectangle& out) override;
// IInventoryPaneCallback // IInventoryPaneCallback
bool addItem(const InventoryPane* pane, int itemId); bool addItem(const InventoryPane* pane, int itemId) override;
bool isAllowed(int slot); bool isAllowed(int slot) override;
std::vector<const ItemInstance*> getItems(const InventoryPane* forPane); std::vector<const ItemInstance*> getItems(const InventoryPane* forPane) override;
void buttonClicked(Button* button); void buttonClicked(Button* button) override;
protected: protected:
virtual void mouseClicked(int x, int y, int buttonNum); virtual void mouseClicked(int x, int y, int buttonNum) override;
virtual void mouseReleased(int x, int y, int buttonNum); virtual void mouseReleased(int x, int y, int buttonNum) override;
// 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;

View File

@@ -3,7 +3,6 @@
#include "../../Screen.h" #include "../../Screen.h"
#include "../../components/Button.h" #include "../../components/Button.h"
#include "../../components/SmallButton.h"
#include "../../components/RolledSelectionListV.h" #include "../../components/RolledSelectionListV.h"
#include "../../../Minecraft.h" #include "../../../Minecraft.h"
#include "../../../../platform/input/Multitouch.h" #include "../../../../platform/input/Multitouch.h"

View File

@@ -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
@@ -552,9 +572,9 @@ bool SelectWorldScreen::isInGameScreen() { return true; }
void SelectWorldScreen::keyPressed( int eventKey ) void SelectWorldScreen::keyPressed( int eventKey )
{ {
if (bWorldView.selected) { if (bWorldView.selected) {
if (eventKey == minecraft->options.keyLeft.key) if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_LEFT))
worldsList->stepLeft(); worldsList->stepLeft();
if (eventKey == minecraft->options.keyRight.key) if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_RIGHT))
worldsList->stepRight(); worldsList->stepRight();
} }

View File

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

View File

@@ -4,7 +4,6 @@
#include "../PauseScreen.h" #include "../PauseScreen.h"
#include "../../Font.h" #include "../../Font.h"
#include "../../components/SmallButton.h"
#include "../../components/ScrolledSelectionList.h" #include "../../components/ScrolledSelectionList.h"
#include "../../components/GuiElement.h" #include "../../components/GuiElement.h"
@@ -30,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;
@@ -59,7 +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);
@@ -75,6 +85,11 @@ void StartMenuScreen::init()
// always show base version string // always show base version string
std::string versionString = Common::getGameVersionString(); std::string versionString = Common::getGameVersionString();
std::string _username = minecraft->options.getStringValue(OPTIONS_USERNAME);
if (_username.empty()) _username = "unknown";
username = "Username: " + _username;
#ifdef DEMO_MODE #ifdef DEMO_MODE
#ifdef __APPLE__ #ifdef __APPLE__
version = versionString + " (Lite)"; version = versionString + " (Lite)";
@@ -108,6 +123,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;
} }
@@ -135,6 +154,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; }
@@ -143,6 +166,9 @@ void StartMenuScreen::render( int xm, int ym, float a )
{ {
renderBackground(); renderBackground();
// Show current username in the top-left corner
drawString(font, username, 2, 2, 0xffffffff);
glEnable2(GL_BLEND); glEnable2(GL_BLEND);
#if defined(RPI) #if defined(RPI)

View File

@@ -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,12 +28,15 @@ 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;
std::string version; std::string version;
int versionPosX; int versionPosX;
std::string username;
}; };
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,257 @@
#include "../../world/item/ArmorItem.h" #include "../../world/item/ArmorItem.h"
#include "../../network/packet/PlayerArmorEquipmentPacket.h" #include "../../network/packet/PlayerArmorEquipmentPacket.h"
namespace {
#ifndef STANDALONE_SERVER
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");
}
#endif
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
}
#ifndef STANDALONE_SERVER
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;
}
#endif
//@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 +308,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,11 +325,14 @@ LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, int dim
this->dimension = dimension; this->dimension = dimension;
_init(); _init();
if (user != NULL) { #ifndef STANDALONE_SERVER
if (user->name.length() > 0) if (user != NULL && !user->name.empty()) {
//customTextureUrl = "http://s3.amazonaws.com/MinecraftSkins/" + user.name + ".png";
this->name = user->name; this->name = user->name;
// Fetch user skin and cape from Mojang servers in the background (avoids blocking the main thread)
new CThread(fetchSkinForPlayer, this);
new CThread(fetchCapeForPlayer, this);
} }
#endif
} }
LocalPlayer::~LocalPlayer() { LocalPlayer::~LocalPlayer() {
@@ -72,22 +342,24 @@ LocalPlayer::~LocalPlayer() {
/*private*/ /*private*/
void LocalPlayer::calculateFlight(float xa, float ya, float za) { void LocalPlayer::calculateFlight(float xa, float ya, float za) {
float flySpeed = minecraft->options.getProgressValue(OPTIONS_FLY_SPEED);
float sensivity = minecraft->options.getProgressValue(OPTIONS_SENSITIVITY);
xa = xa * minecraft->options.flySpeed; xa = xa * flySpeed;
ya = 0; ya = 0;
za = za * minecraft->options.flySpeed; za = za * flySpeed;
#ifdef ANDROID #ifdef ANDROID
if (Keyboard::isKeyDown(103)) ya = .2f * minecraft->options.flySpeed; if (Keyboard::isKeyDown(103)) ya = .2f * minecraft->options.flySpeed;
if (Keyboard::isKeyDown(102)) ya = -.2f * minecraft->options.flySpeed; if (Keyboard::isKeyDown(102)) ya = -.2f * minecraft->options.flySpeed;
#else #else
if (Keyboard::isKeyDown(Keyboard::KEY_E)) ya = .2f * minecraft->options.flySpeed; if (Keyboard::isKeyDown(Keyboard::KEY_E)) ya = .2f * flySpeed;
if (Keyboard::isKeyDown(Keyboard::KEY_Q)) ya = -.2f * minecraft->options.flySpeed; if (Keyboard::isKeyDown(Keyboard::KEY_Q)) ya = -.2f * flySpeed;
#endif #endif
flyX = 10 * smoothFlyX.getNewDeltaValue(xa, .35f * minecraft->options.sensitivity); flyX = 10 * smoothFlyX.getNewDeltaValue(xa, .35f * sensivity);
flyY = 10 * smoothFlyY.getNewDeltaValue(ya, .35f * minecraft->options.sensitivity); flyY = 10 * smoothFlyY.getNewDeltaValue(ya, .35f * sensivity);
flyZ = 10 * smoothFlyZ.getNewDeltaValue(za, .35f * minecraft->options.sensitivity); flyZ = 10 * smoothFlyZ.getNewDeltaValue(za, .35f * sensivity);
} }
bool LocalPlayer::isSolidTile(int x, int y, int z) { bool LocalPlayer::isSolidTile(int x, int y, int z) {
@@ -152,7 +424,7 @@ void LocalPlayer::tick() {
printf("armor %d: %d\n", i, a->getAuxValue()); printf("armor %d: %d\n", i, a->getAuxValue());
} }
/**/ */
updateArmorTypeHash(); updateArmorTypeHash();
#ifndef STANDALONE_SERVER #ifndef STANDALONE_SERVER
@@ -182,7 +454,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.getBooleanValue(OPTIONS_ALLOW_SPRINT)) {
// leading edge of W press // leading edge of W press
if (sprintDoubleTapTimer > 0) if (sprintDoubleTapTimer > 0)
sprinting = true; sprinting = true;
@@ -251,7 +523,7 @@ void LocalPlayer::closeContainer() {
//@Override //@Override
void LocalPlayer::move(float xa, float ya, float za) { void LocalPlayer::move(float xa, float ya, float za) {
//@note: why is this == minecraft->player needed? //@note: why is this == minecraft->player needed?
if (this == minecraft->player && minecraft->options.isFlying) { if (this == minecraft->player && minecraft->options.getBooleanValue(OPTIONS_IS_FLYING)) {
noPhysics = true; noPhysics = true;
float tmp = walkDist; // update float tmp = walkDist; // update
calculateFlight((float) xa, (float) ya, (float) za); calculateFlight((float) xa, (float) ya, (float) za);
@@ -271,7 +543,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.getBooleanValue(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;

View File

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

View File

@@ -12,14 +12,12 @@ KeyboardInput::KeyboardInput( Options* options )
void KeyboardInput::setKey( int key, bool state ) void KeyboardInput::setKey( int key, bool state )
{ {
int id = -1; int id = -1;
if (key == options->keyUp.key) id = KEY_UP; if (key == options->getIntValue(OPTIONS_KEY_FORWARD)) id = KEY_UP;
if (key == options->keyDown.key) id = KEY_DOWN; if (key == options->getIntValue(OPTIONS_KEY_BACK)) id = KEY_DOWN;
if (key == options->keyLeft.key) id = KEY_LEFT; if (key == options->getIntValue(OPTIONS_KEY_LEFT)) id = KEY_LEFT;
if (key == options->keyRight.key) id = KEY_RIGHT; if (key == options->getIntValue(OPTIONS_KEY_RIGHT)) id = KEY_RIGHT;
if (key == options->keyJump.key) id = KEY_JUMP; if (key == options->getIntValue(OPTIONS_KEY_JUMP)) id = KEY_JUMP;
if (key == options->keySneak.key) id = KEY_SNEAK; if (key == options->getIntValue(OPTIONS_KEY_SNEAK)) id = KEY_SNEAK;
if (key == options->keyCraft.key) id = KEY_CRAFT;
//printf("key: %d\n", id);
if (id >= 0) { if (id >= 0) {
keys[id] = state; keys[id] = state;
} }

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