diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ad9186a4..1b65eb467 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,16 +18,19 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true - name: Install Dependencies run: | sudo apt-get update - sudo apt-get install --no-install-recommends -y build-essential cmake ninja-build libopenal-dev libsdl2-dev zlib1g-dev + sudo apt-get install --no-install-recommends -y \ + build-essential \ + cmake ninja-build \ + libopenal-dev \ + libsdl2-dev zlib1g-dev - name: Build run: | - cd platforms/sdl mkdir build cd build cmake -GNinja ${{ matrix.flags }} .. @@ -37,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true - name: Install Dependencies @@ -51,7 +54,7 @@ jobs: runs-on: macos-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true - name: Install MacPorts @@ -62,6 +65,7 @@ jobs: sudo port install libpng +universal - name: Build macOS Archive run: | + ln -s sound/openal platforms/openal # Please someone fix this properly later. cd platforms/macos/projects/Minecraft xcodebuild -scheme "MinecraftClient.SDL2" \ -archivePath $RUNNER_TEMP/GitHubActions_MacOS_SDL2.xcarchive \ @@ -103,11 +107,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true - name: Setup JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' @@ -116,3 +120,32 @@ jobs: run: | cd ${{ matrix.directory }} ./gradlew build + mingw: + strategy: + fail-fast: false + matrix: + include: + - name: Win32 + flags: "-DREMCPE_PLATFORM=windows" + - name: SDL + flags: "-DREMCPE_PLATFORM=sdl" + name: MinGW-w64 (${{ matrix.name }}) + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + submodules: true + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y \ + build-essential \ + cmake ninja-build \ + mingw-w64 + - name: Build + run: | + mkdir build + cd build + cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=../cmake/mingw-w64-toolchain.cmake ${{ matrix.flags }} .. + cmake --build . \ No newline at end of file diff --git a/.gitignore b/.gitignore index 22c107a57..c3708db6d 100644 --- a/.gitignore +++ b/.gitignore @@ -123,7 +123,7 @@ xcuserdata/ /sound_data # Ignore linux/mingw build artifacts. -/build +/build* /minecraftcpp /minecraftcpp.exe @@ -187,9 +187,7 @@ xcuserdata/ /game/assets/gui/startmenu/sm_play.png /game/assets/gui/startmenu/sm_multi.png /game/assets/gui/startmenu/sm_options.png -/game/assets/gui/touchgui.png -/game/assets/gui/feedback_fill.png -/game/assets/gui/feedback_outer.png + /game/assets/snow.png # Ignore all native iOS UI assets. /game/assets/app/ios/ @@ -242,3 +240,12 @@ xcuserdata/ # Ignore options.txt - where your configuration will be saved /game/options.txt /game/assetsO + +# CLion +/.idea +/cmake-build-* + +# Sound +/tools/__pycache__ +/tools/venv +/game/assets/sound diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..63d18d425 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,61 @@ +cmake_minimum_required(VERSION 3.16.0) +project(reminecraftpe) + +# Store Output In Top-Level Build Directory +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") + +# WASM +if(EMSCRIPTEN) + function(add_compile_and_link_options) + add_compile_options(${ARGV}) + add_link_options(${ARGV}) + endfunction() + set(CMAKE_EXECUTABLE_SUFFIX ".js") + add_link_options("$<$:-gsource-map>") + add_link_options(-Wno-pthreads-mem-growth -sALLOW_MEMORY_GROWTH=1) +endif() + +# Clang +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_compile_options(-Wno-inconsistent-missing-override -Wno-enum-compare-switch -Wno-register) +endif() + +# Windows Linking +if(WIN32) + add_link_options( + -static-libgcc + -static-libstdc++ + ) +endif() + +# HaikuOS Network Library +if(HAIKU) + link_libraries(network) +endif() + +# Threading +if(EMSCRIPTEN) + add_compile_and_link_options(-pthread) +else() + find_package(Threads) + link_libraries(Threads::Threads) +endif() + +# Android Logging +if(ANDROID) + link_libraries(log) +endif() + +# Load Common Code +add_subdirectory(source) + +# Load Platform-Specific Code +add_subdirectory(platforms) + +# Assets +if(EMSCRIPTEN) + target_link_options(reminecraftpe PRIVATE --use-preload-plugins --preload-file "${CMAKE_CURRENT_SOURCE_DIR}/game@/") +else() + file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/game/assets" "${CMAKE_CURRENT_BINARY_DIR}/assets" SYMBOLIC) +endif() \ No newline at end of file diff --git a/README.md b/README.md index ebb4e7b9e..d72711ee5 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ based on Minecraft PE v0.1.3. * To keep the source code layout similar to the original Minecraft PE (reconstructed from clues hidden within certain versions of the game, such as the 0.1.0 touch prototype/debug build) * To port the game to more platforms, such as Windows (including older versions), Xbox 360, Wii, and more. - Currently there are ports for: + Currently, there are ports for: * Windows XP-11 * Android (thanks to [Stom](https://github.com/Stommm) for the help) * Linux * WebGL - * Mac OS (port by [BrentDaMage](https://github.com/BrentDaMage)) + * macOS (port by [BrentDaMage](https://github.com/BrentDaMage)) * iOS (3.0 and above; port by [BrentDaMage](https://github.com/BrentDaMage)) * HaikuOS (thanks to [SanyaSho](https://github.com/SanyaSho)) * Xbox 360 (work in progress; port by [BrentDaMage](https://github.com/BrentDaMage)) @@ -36,7 +36,7 @@ Note: While the original Minecraft PE v0.1.3 may not work on newer devices, ReMi ## License information -This project is licensed under the [BSD 1 clause license](LICENSE.md). However, it contains third party +This project is licensed under the [BSD 1 clause license](LICENSE.txt). However, it contains third party software with different but compatible licenses: - [RakNet](https://github.com/facebookarchive/RakNet): [Licensed under the BSD 2 clause license](thirdparty/raknet/LICENSE) @@ -142,7 +142,6 @@ This project uses CMake on Linux. Just like WebAssembly, the game assets must be #### How To Build ```sh -cd platforms/sdl mkdir build && cd build cmake -GNinja .. cmake --build . diff --git a/build-wasm.sh b/build-wasm.sh index bc1265706..033140ec2 100755 --- a/build-wasm.sh +++ b/build-wasm.sh @@ -31,7 +31,7 @@ mkdir -p build cd build # Configure Build -emcmake cmake -GNinja "$@" ../../platforms/sdl +emcmake cmake -GNinja "$@" ../../ # Build cmake --build . diff --git a/cmake/mingw-w64-toolchain.cmake b/cmake/mingw-w64-toolchain.cmake new file mode 100644 index 000000000..9610577a5 --- /dev/null +++ b/cmake/mingw-w64-toolchain.cmake @@ -0,0 +1,11 @@ +# https://gist.github.com/peterspackman/8cf73f7f12ba270aa8192d6911972fe8 +set(CMAKE_SYSTEM_NAME Windows) +set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) +set(CMAKE_C_COMPILER "${TOOLCHAIN_PREFIX}-gcc") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PREFIX}-g++") +set(CMAKE_Fortran_COMPILER "${TOOLCHAIN_PREFIX}-gfortran") +set(CMAKE_RC_COMPILER "${TOOLCHAIN_PREFIX}-windres") +set(CMAKE_FIND_ROOT_PATH "/usr/${TOOLCHAIN_PREFIX}") +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) \ No newline at end of file diff --git a/compat/KeyCodes.hpp b/compat/KeyCodes.hpp index 783a04595..f2316c5f1 100644 --- a/compat/KeyCodes.hpp +++ b/compat/KeyCodes.hpp @@ -23,7 +23,7 @@ enum eSDLVirtualKeys #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN - #include + #include #elif __APPLE__ // https://i.stack.imgur.com/LD8pT.png #define AKEYCODE_FORWARD_DEL 0x75 diff --git a/platforms/CMakeLists.txt b/platforms/CMakeLists.txt new file mode 100644 index 000000000..daf641034 --- /dev/null +++ b/platforms/CMakeLists.txt @@ -0,0 +1,12 @@ +project(reminecraftpe-platforms) + +# Select & Build +set(DEFAULT_PLATFORM "sdl") +if(WIN32) + set(DEFAULT_PLATFORM "windows") +endif() +set(REMCPE_PLATFORM "${DEFAULT_PLATFORM}" CACHE STRING "ReMCPE Platform (Check /platforms)") +add_subdirectory("${REMCPE_PLATFORM}") + +# Load Sound +add_subdirectory(sound) \ No newline at end of file diff --git a/platforms/android/AppPlatform_android.cpp b/platforms/android/AppPlatform_android.cpp index 117f68b13..1f9493cec 100644 --- a/platforms/android/AppPlatform_android.cpp +++ b/platforms/android/AppPlatform_android.cpp @@ -9,7 +9,7 @@ #include #include "AppPlatform_android.hpp" -#include "SoundSystemSL.hpp" +#include "CustomSoundSystem.hpp" #include "client/player/input/Mouse.hpp" #include "stb_image.h" @@ -174,7 +174,7 @@ SoundSystem* const AppPlatform_android::getSoundSystem() const void AppPlatform_android::initSoundSystem() { if (!m_pSoundSystem) - m_pSoundSystem = new SoundSystemSL(); + m_pSoundSystem = new SOUND_SYSTEM(); else LOG_E("Trying to initialize SoundSystem more than once!"); } @@ -357,3 +357,22 @@ int AppPlatform_android::getKeyboardUpOffset() // For now we'll just return 1/2 of the screen height. That ought to cover most cases. return m_ScreenHeight / 2; } + +AssetFile AppPlatform_android::readAssetFile(const std::string& str) const +{ + std::string realPath = str; + if (realPath.size() && realPath[0] == '/') + // trim it off + realPath = realPath.substr(1); + + AAsset* asset = AAssetManager_open(m_app->activity->assetManager, str.c_str(), AASSET_MODE_BUFFER); + if (!asset) { + LOG_E("File %s couldn't be opened", realPath.c_str()); + return AssetFile(); + } + size_t cnt = AAsset_getLength(asset); + unsigned char* buffer = new unsigned char[cnt]; + AAsset_read(asset, (void*)buffer, cnt); + AAsset_close(asset); + return AssetFile(ssize_t(cnt), buffer); +} \ No newline at end of file diff --git a/platforms/android/AppPlatform_android.hpp b/platforms/android/AppPlatform_android.hpp index 3e6de84f6..e67f85ec3 100644 --- a/platforms/android/AppPlatform_android.hpp +++ b/platforms/android/AppPlatform_android.hpp @@ -62,6 +62,8 @@ class AppPlatform_android : public AppPlatform void initAndroidApp(android_app* ptr); void setExternalStoragePath(const std::string& path); + AssetFile readAssetFile(const std::string&) const override; + private: void changeKeyboardVisibility(bool bShown); diff --git a/platforms/android/project/app/src/main/cpp/CMakeLists.txt b/platforms/android/CMakeLists.txt similarity index 63% rename from platforms/android/project/app/src/main/cpp/CMakeLists.txt rename to platforms/android/CMakeLists.txt index 6a03a611f..634657cae 100644 --- a/platforms/android/project/app/src/main/cpp/CMakeLists.txt +++ b/platforms/android/CMakeLists.txt @@ -1,31 +1,28 @@ cmake_minimum_required(VERSION 3.16.0) project(reminecraftpe-android) -# Project Root -set(MC_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../..") - # Native Android Build -add_compile_definitions(USE_NATIVE_ANDROID) -set(USE_NATIVE_ANDROID TRUE) +target_compile_definitions(reminecraftpe-core PUBLIC USE_NATIVE_ANDROID) # Build add_library(reminecraftpe SHARED - "${MC_ROOT}/platforms/android/android_native_app_glue.c" - "${MC_ROOT}/platforms/android/AppPlatform_android.cpp" - "${MC_ROOT}/platforms/android/SoundSystemSL.cpp" - "${MC_ROOT}/platforms/android/main.cpp" + android_native_app_glue.c + AppPlatform_android.cpp + main.cpp ) # Core -add_subdirectory("${MC_ROOT}/source" source) target_link_libraries(reminecraftpe reminecraftpe-core) +# OpenGL +target_link_libraries(reminecraftpe-core PUBLIC EGL GLESv1_CM) + # stb_image -add_subdirectory("${MC_ROOT}/thirdparty/stb_image" stb_image) +add_subdirectory(../../thirdparty/stb_image stb_image) target_link_libraries(reminecraftpe stb_image) # Extra Dependencies -target_link_libraries(reminecraftpe android OpenSLES) +target_link_libraries(reminecraftpe android) # Check for the presence of some optional asset based features. if(EXISTS "${MC_ROOT}/game/assets/gui/background/panorama_0.png") diff --git a/platforms/android/project/app/build.gradle b/platforms/android/project/app/build.gradle index 84b308c56..7743e2ab1 100644 --- a/platforms/android/project/app/build.gradle +++ b/platforms/android/project/app/build.gradle @@ -29,7 +29,7 @@ android { // testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { - arguments '-DANDROID_PLATFORM=android-21', '-DANDROID_STL=c++_static' + arguments '-DANDROID_PLATFORM=android-21', '-DANDROID_STL=c++_static', '-DREMCPE_PLATFORM=android', '-DREMCPE_SOUND_PLATFORM=opensl' abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } @@ -47,7 +47,7 @@ android { } externalNativeBuild { cmake { - path file('src/main/cpp/CMakeLists.txt') + path '../../../../CMakeLists.txt' version '3.22.1' } } diff --git a/platforms/macos/projects/Minecraft/Minecraft.xcodeproj/project.pbxproj b/platforms/macos/projects/Minecraft/Minecraft.xcodeproj/project.pbxproj index fd769b36a..d5e38b874 100644 --- a/platforms/macos/projects/Minecraft/Minecraft.xcodeproj/project.pbxproj +++ b/platforms/macos/projects/Minecraft/Minecraft.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 8400E0532DB53AE100FFB167 /* sound_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 8400E0522DB53AE100FFB167 /* sound_list.h */; }; + 8400E0552DB5549900FFB167 /* stb_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 84AA8CD02B32FB32003F5B82 /* stb_vorbis.c */; }; + 8400E0562DB5549900FFB167 /* stb_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 84AA8CD02B32FB32003F5B82 /* stb_vorbis.c */; }; 8406FD2A2AF181B800B09C1D /* GL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD6542AC810620006A435 /* GL.cpp */; }; 8406FD2C2AF1820700B09C1D /* MinecraftPackets.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 840DD63B2AC810620006A435 /* MinecraftPackets.hpp */; }; 8406FD2D2AF1820700B09C1D /* NetEventCallback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 840DD63D2AC810620006A435 /* NetEventCallback.hpp */; }; @@ -200,6 +203,8 @@ 8426107E2AE989730065905F /* RakNetInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD64E2AC810620006A435 /* RakNetInstance.cpp */; }; 8426107F2AE989730065905F /* ServerSideNetworkHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD6502AC810620006A435 /* ServerSideNetworkHandler.cpp */; }; 842610882AE98A4C0065905F /* libRakNet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84FFBD7E2ACA2876005A8CCF /* libRakNet.a */; }; + 843C50C12DB40E73006680A3 /* SoundSystemAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 843C50B82DB40E73006680A3 /* SoundSystemAL.cpp */; }; + 843C50C82DB40E73006680A3 /* SoundSystemAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 843C50B82DB40E73006680A3 /* SoundSystemAL.cpp */; }; 8443B6EA2A98675F0086730C /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8443B6E92A98675F0086730C /* libSDL2.a */; }; 8445E7A02D769329008DC834 /* EntityCategories.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8445E7952D769329008DC834 /* EntityCategories.cpp */; }; 8445E7A12D769329008DC834 /* EntityCategories.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8445E7962D769329008DC834 /* EntityCategories.hpp */; }; @@ -245,7 +250,6 @@ 84619B212AF1EDA300B0DE81 /* libWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84BF630B2AF1859D008A9995 /* libWorld.a */; }; 84619B222AF1EDA300B0DE81 /* libZLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84498A832AF18C7A005EF5A5 /* libZLib.a */; }; 84619B392AF1F73900B0DE81 /* GL.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 840DD6552AC810620006A435 /* GL.hpp */; }; - 84619B3A2AF1FE1500B0DE81 /* SoundSystemAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84EAE8E62AF1EAFA000894E8 /* SoundSystemAL.cpp */; }; 84619B3C2AF1FE4C00B0DE81 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84619B3B2AF1FE4C00B0DE81 /* OpenAL.framework */; }; 84619B3E2AF1FEB700B0DE81 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84619B3D2AF1FEB700B0DE81 /* QuartzCore.framework */; }; 8470AF2B2BE9B60A00BCA54E /* EntityType.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 8470AF282BE9B60900BCA54E /* EntityType.hpp */; }; @@ -520,7 +524,6 @@ 84AA8C762B32F536003F5B82 /* ZombieModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84AA8C582B32F535003F5B82 /* ZombieModel.cpp */; }; 84AA8C772B32F536003F5B82 /* ZombieModel.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84AA8C592B32F535003F5B82 /* ZombieModel.hpp */; }; 84AA8C792B32F578003F5B82 /* gui_custom.png in Resources */ = {isa = PBXBuildFile; fileRef = 84AA8C782B32F578003F5B82 /* gui_custom.png */; }; - 84AA8E4D2B32FB33003F5B82 /* stb_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 84AA8CD02B32FB32003F5B82 /* stb_vorbis.c */; }; 84AA8E802B32FB33003F5B82 /* stb_image_impl.c in Sources */ = {isa = PBXBuildFile; fileRef = 84AA8E462B32FB33003F5B82 /* stb_image_impl.c */; }; 84AAF6432AF18BD000BD67F4 /* GLExt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD7332AC810620006A435 /* GLExt.cpp */; }; 84AAF6442AF18BE700BD67F4 /* GL.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 840DD7322AC810620006A435 /* GL.hpp */; }; @@ -895,7 +898,6 @@ 84EAE8DE2AF1EAA1000894E8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EAE8DD2AF1EAA1000894E8 /* UIKit.framework */; }; 84EAE8E02AF1EAA9000894E8 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EAE8DF2AF1EAA9000894E8 /* CoreGraphics.framework */; }; 84EAE8E42AF1EABE000894E8 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84EAE8E32AF1EABE000894E8 /* OpenGLES.framework */; }; - 84EAE8F32AF1EAFA000894E8 /* SoundSystemAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84EAE8E62AF1EAFA000894E8 /* SoundSystemAL.cpp */; }; 84EAE8F72AF1EAFA000894E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84EAE8F12AF1EAFA000894E8 /* main.cpp */; }; 84ED99D52AFF12D1003B6AF0 /* minecraftpe.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = 84ED99D42AFF12D1003B6AF0 /* minecraftpe.entitlements */; }; 84FFBE952ACA3415005A8CCF /* _FindFirst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD73A2AC810620006A435 /* _FindFirst.cpp */; }; @@ -1124,6 +1126,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 8400E0522DB53AE100FFB167 /* sound_list.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sound_list.h; sourceTree = ""; }; 8406FD292AF1814500B09C1D /* libRenderer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRenderer.a; sourceTree = BUILT_PRODUCTS_DIR; }; 840DD5792AC810620006A435 /* KeyCodes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = KeyCodes.hpp; sourceTree = ""; }; 840DD57A2AC810620006A435 /* SDLKeyCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLKeyCodes.h; sourceTree = ""; }; @@ -1776,6 +1779,8 @@ 84336BA52B1EB57E00097DB0 /* Settings_iOS_Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Settings_iOS_Debug.xcconfig; path = ../Configuration/Settings_iOS_Debug.xcconfig; sourceTree = ""; }; 84336BA82B1EB88500097DB0 /* Settings_macOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Settings_macOS.xcconfig; path = ../Configuration/Settings_macOS.xcconfig; sourceTree = ""; }; 84336BA92B1EB9C200097DB0 /* Settings_macOS_Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Settings_macOS_Debug.xcconfig; path = ../Configuration/Settings_macOS_Debug.xcconfig; sourceTree = ""; }; + 843C50B72DB40E73006680A3 /* CustomSoundSystem.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CustomSoundSystem.hpp; sourceTree = ""; }; + 843C50B82DB40E73006680A3 /* SoundSystemAL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SoundSystemAL.cpp; sourceTree = ""; }; 8443B6E92A98675F0086730C /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = /opt/local/lib/libSDL2.a; sourceTree = ""; }; 8445E7952D769329008DC834 /* EntityCategories.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EntityCategories.cpp; sourceTree = ""; }; 8445E7962D769329008DC834 /* EntityCategories.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = EntityCategories.hpp; sourceTree = ""; }; @@ -2164,9 +2169,6 @@ 84EAE8DF2AF1EAA9000894E8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 84EAE8E12AF1EAB5000894E8 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; 84EAE8E32AF1EABE000894E8 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; - 84EAE8E62AF1EAFA000894E8 /* SoundSystemAL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SoundSystemAL.cpp; sourceTree = ""; }; - 84EAE8E72AF1EAFA000894E8 /* SoundSystemAL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SoundSystemAL.hpp; sourceTree = ""; }; - 84EAE8F02AF1EAFA000894E8 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 84EAE8F12AF1EAFA000894E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; 84ED99D42AFF12D1003B6AF0 /* minecraftpe.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = minecraftpe.entitlements; sourceTree = ""; }; 84FFBD7E2ACA2876005A8CCF /* libRakNet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRakNet.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2536,15 +2538,16 @@ 840DD61A2AC810620006A435 /* sound */ = { isa = PBXGroup; children = ( - 840DD61B2AC810620006A435 /* SoundData.cpp */, + 8400E0522DB53AE100FFB167 /* sound_list.h */, 840DD61C2AC810620006A435 /* SoundData.hpp */, + 840DD61B2AC810620006A435 /* SoundData.cpp */, 840DD61D2AC810620006A435 /* SoundDefs.hpp */, - 840DD61E2AC810620006A435 /* SoundEngine.cpp */, 840DD61F2AC810620006A435 /* SoundEngine.hpp */, - 840DD6202AC810620006A435 /* SoundRepository.cpp */, + 840DD61E2AC810620006A435 /* SoundEngine.cpp */, 840DD6212AC810620006A435 /* SoundRepository.hpp */, - 840DD6222AC810620006A435 /* SoundSystem.cpp */, + 840DD6202AC810620006A435 /* SoundRepository.cpp */, 840DD6232AC810620006A435 /* SoundSystem.hpp */, + 840DD6222AC810620006A435 /* SoundSystem.cpp */, ); path = sound; sourceTree = ""; @@ -3342,8 +3345,8 @@ isa = PBXGroup; children = ( 84790AEC2AD7DA410076F2A1 /* ios */, - 84EAE8E52AF1EAFA000894E8 /* openal */, 84EAE8E82AF1EAFA000894E8 /* sdl */, + 843C50BF2DB40E73006680A3 /* sound */, ); name = platforms; path = ../../..; @@ -3385,6 +3388,23 @@ name = macOS; sourceTree = ""; }; + 843C50B92DB40E73006680A3 /* openal */ = { + isa = PBXGroup; + children = ( + 843C50B72DB40E73006680A3 /* CustomSoundSystem.hpp */, + 843C50B82DB40E73006680A3 /* SoundSystemAL.cpp */, + ); + path = openal; + sourceTree = ""; + }; + 843C50BF2DB40E73006680A3 /* sound */ = { + isa = PBXGroup; + children = ( + 843C50B92DB40E73006680A3 /* openal */, + ); + path = sound; + sourceTree = ""; + }; 8470AF422BE9B8B600BCA54E /* environment */ = { isa = PBXGroup; children = ( @@ -3903,20 +3923,10 @@ path = mob; sourceTree = ""; }; - 84EAE8E52AF1EAFA000894E8 /* openal */ = { - isa = PBXGroup; - children = ( - 84EAE8E62AF1EAFA000894E8 /* SoundSystemAL.cpp */, - 84EAE8E72AF1EAFA000894E8 /* SoundSystemAL.hpp */, - ); - path = openal; - sourceTree = ""; - }; 84EAE8E82AF1EAFA000894E8 /* sdl */ = { isa = PBXGroup; children = ( 841DD8712AF8AA7A00AA3B66 /* base */, - 84EAE8F02AF1EAFA000894E8 /* CMakeLists.txt */, 841DD8742AF8AA7A00AA3B66 /* desktop */, 84EAE8F12AF1EAFA000894E8 /* main.cpp */, ); @@ -4037,6 +4047,7 @@ 84E001222AF39E84009B9555 /* IInputHolder.hpp in Headers */, 84E001242AF39E84009B9555 /* IMoveInput.hpp in Headers */, 84E001262AF39E84009B9555 /* IncludeExcludeArea.hpp in Headers */, + 8400E0532DB53AE100FFB167 /* sound_list.h in Headers */, 84E001282AF39E84009B9555 /* ITouchScreenModel.hpp in Headers */, 84E0012A2AF39E84009B9555 /* MouseDevice.hpp in Headers */, 84E0012C2AF39E84009B9555 /* MouseHandler.hpp in Headers */, @@ -4854,12 +4865,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 84EAE8F32AF1EAFA000894E8 /* SoundSystemAL.cpp in Sources */, + 8400E0552DB5549900FFB167 /* stb_vorbis.c in Sources */, 84EAE8F72AF1EAFA000894E8 /* main.cpp in Sources */, 841DD8772AF8AA7A00AA3B66 /* AppPlatform_sdl_base.cpp in Sources */, 841DD8782AF8AA7A00AA3B66 /* AppPlatform_sdl.cpp in Sources */, - 84AA8E4D2B32FB33003F5B82 /* stb_vorbis.c in Sources */, 84AA8E802B32FB33003F5B82 /* stb_image_impl.c in Sources */, + 843C50C82DB40E73006680A3 /* SoundSystemAL.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4867,12 +4878,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 84619B3A2AF1FE1500B0DE81 /* SoundSystemAL.cpp in Sources */, + 8400E0562DB5549900FFB167 /* stb_vorbis.c in Sources */, 849259592AD8FD4F0081F5B9 /* minecraftpeAppDelegate.mm in Sources */, 8492595A2AD8FD4F0081F5B9 /* minecraftpeViewController.mm in Sources */, 8492595B2AD8FD4F0081F5B9 /* Shader.fsh in Sources */, 8492595C2AD8FD4F0081F5B9 /* Shader.vsh in Sources */, 849259622AD8FDD10081F5B9 /* main.m in Sources */, + 843C50C12DB40E73006680A3 /* SoundSystemAL.cpp in Sources */, 84CEF0032AE3C97D006C5829 /* EAGLView.m in Sources */, 8495E4892AF0905B00A06901 /* AppPlatform_iOS.mm in Sources */, 8488C08A2B1EDD4F001AEC4F /* ShowKeyboardView.mm in Sources */, diff --git a/platforms/openal/CMakeLists.txt b/platforms/openal/CMakeLists.txt deleted file mode 100644 index 36450e0fe..000000000 --- a/platforms/openal/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -cmake_minimum_required(VERSION 3.16.0) -project(reminecraftpe-openal) - -# Build -add_library(reminecraftpe-openal STATIC - SoundSystemAL.cpp -) - -# Core -target_link_libraries(reminecraftpe-openal PUBLIC reminecraftpe-core) - -# OpenAL -if(ANDROID) - # Use Vendored OpenAL - set(ALSOFT_UTILS FALSE CACHE BOOL "" FORCE) - set(ALSOFT_EXAMPLES FALSE CACHE BOOL "" FORCE) - set(ALSOFT_TESTS FALSE CACHE BOOL "" FORCE) - set(ALSOFT_REQUIRE_OPENSL TRUE CACHE BOOL "" FORCE) - add_subdirectory(../../thirdparty/OpenAL openal EXCLUDE_FROM_ALL) - target_link_libraries(reminecraftpe-openal PUBLIC OpenAL::OpenAL) -elseif(EMSCRIPTEN) - # Use Emscripten's OpenAL - target_link_libraries(reminecraftpe-openal PUBLIC openal) -else() - # Use System ZLib - find_library(OPENAL_LIBRARY NAMES openal REQUIRED) - target_link_libraries(reminecraftpe-openal PUBLIC "${OPENAL_LIBRARY}") -endif() - -# Headers -target_include_directories(reminecraftpe-openal PUBLIC .) diff --git a/platforms/sdl/CMakeLists.txt b/platforms/sdl/CMakeLists.txt index b5cff20c9..ddfe18b54 100644 --- a/platforms/sdl/CMakeLists.txt +++ b/platforms/sdl/CMakeLists.txt @@ -2,36 +2,10 @@ cmake_minimum_required(VERSION 3.16.0) project(reminecraftpe-sdl) # SDL Build -add_compile_definitions(USE_SDL USE_OPENAL HANDLE_CHARS_SEPARATELY) -set(USE_SDL TRUE) - -# WASM -if(EMSCRIPTEN) - function(add_compile_and_link_options) - add_compile_options(${ARGV}) - add_link_options(${ARGV}) - endfunction() - set(CMAKE_EXECUTABLE_SUFFIX ".js") - add_link_options("$<$:-gsource-map>") -endif() - -# Clang -if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - add_compile_options(-Wno-inconsistent-missing-override -Wno-enum-compare-switch -Wno-register) -endif() - -# Network library -if(HAIKU) - link_libraries(network) -endif() - -# Threads -if(EMSCRIPTEN) - add_compile_and_link_options(-pthread) -else() - find_package(Threads) - link_libraries(Threads::Threads) -endif() +target_compile_definitions(reminecraftpe-core + PUBLIC USE_SDL + PUBLIC HANDLE_CHARS_SEPARATELY +) # Build set(SOURCES @@ -51,13 +25,8 @@ else() endif() # Core -add_subdirectory(../../source source) target_link_libraries(reminecraftpe reminecraftpe-core) -# OpenAL -add_subdirectory(../openal openal) -target_link_libraries(reminecraftpe reminecraftpe-openal) - # stb_image (If Needed) if(NOT EMSCRIPTEN) add_subdirectory(../../thirdparty/stb_image stb_image) @@ -65,21 +34,47 @@ if(NOT EMSCRIPTEN) endif() # SDL +add_library(SDL INTERFACE) +if(ANDROID OR WIN32) + # Use Vendored SDL2 (Only For Android) + add_subdirectory(../../thirdparty/SDL2/src SDL EXCLUDE_FROM_ALL) + target_link_libraries(SDL INTERFACE SDL2::SDL2) +elseif(EMSCRIPTEN) + # Use Emscripten's SDL2 + set(SDL_FLAG -sUSE_SDL=2) + target_compile_options(SDL INTERFACE "${SDL_FLAG}") + target_link_options(SDL INTERFACE "${SDL_FLAG}") +else() + # Use System SDL2 + find_package(SDL2 REQUIRED) + target_link_libraries(SDL INTERFACE SDL2::SDL2) +endif() +target_link_libraries(reminecraftpe-core PUBLIC SDL) if(TARGET SDL2::SDL2main) target_link_libraries(reminecraftpe SDL2::SDL2main) endif() +# OpenGL +if(NOT EMSCRIPTEN AND NOT ANDROID AND NOT WIN32) + option(USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" TRUE) +else() + set(USE_GLES1_COMPATIBILITY_LAYER TRUE CACHE BOOL "" FORCE) +endif() +if(USE_GLES1_COMPATIBILITY_LAYER) + add_subdirectory(../../thirdparty/gles-compatibility-layer gles-compatibility-layer) + target_link_libraries(reminecraftpe-core PUBLIC gles-compatibility-layer) + target_compile_definitions(reminecraftpe-core PUBLIC USE_GLES1_COMPATIBILITY_LAYER) + if(EMSCRIPTEN) + # Use WebGL 2 + target_link_options(reminecraftpe-core PUBLIC -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2) + endif() +else() + find_package(OpenGL REQUIRED) + target_link_libraries(reminecraftpe-core PUBLIC OpenGL::GL) +endif() + # WASM if(EMSCRIPTEN) - target_link_options(reminecraftpe PRIVATE -Wno-pthreads-mem-growth) - target_link_options(reminecraftpe PRIVATE -sALLOW_MEMORY_GROWTH=1) # Export Resize Function target_link_options(reminecraftpe PRIVATE -sEXPORTED_FUNCTIONS=_main,_resize_from_js -sEXPORTED_RUNTIME_METHODS=ccall) endif() - -# Assets -if(EMSCRIPTEN) - target_link_options(reminecraftpe PRIVATE --use-preload-plugins --preload-file "${CMAKE_CURRENT_SOURCE_DIR}/../../game@/") -elseif(NOT ANDROID) - file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/../../game/assets" "${CMAKE_CURRENT_BINARY_DIR}/assets" SYMBOLIC) -endif() diff --git a/platforms/sdl/android/app/build.gradle b/platforms/sdl/android/app/build.gradle index dddb581b7..f08bc84ae 100644 --- a/platforms/sdl/android/app/build.gradle +++ b/platforms/sdl/android/app/build.gradle @@ -33,7 +33,7 @@ android { } externalNativeBuild { cmake { - path '../../CMakeLists.txt' + path '../../../../CMakeLists.txt' version '3.22.1' } } diff --git a/platforms/sdl/android/app/src/main/AndroidManifest.xml b/platforms/sdl/android/app/src/main/AndroidManifest.xml index 99abe3faf..db14630f1 100644 --- a/platforms/sdl/android/app/src/main/AndroidManifest.xml +++ b/platforms/sdl/android/app/src/main/AndroidManifest.xml @@ -5,8 +5,8 @@ android:versionName="1.0" android:installLocation="auto"> - - + + size(io); - if (size == -1) - { - LOG_E("Error determining the size of the patch data file!"); - } - - char *buf = new char[size]; - SDL_RWread(io, buf, size, 1); - - SDL_RWclose(io); - - return std::string(buf); -} diff --git a/platforms/sdl/desktop/AppPlatform_sdl.hpp b/platforms/sdl/desktop/AppPlatform_sdl.hpp index cf7f761b6..e139b57f0 100644 --- a/platforms/sdl/desktop/AppPlatform_sdl.hpp +++ b/platforms/sdl/desktop/AppPlatform_sdl.hpp @@ -18,7 +18,6 @@ class AppPlatform_sdl : public AppPlatform_sdl_base bool doesTextureExist(const std::string& path) const override; bool hasFileSystemAccess() override; - std::string getPatchData() override; protected: void ensureDirectoryExists(const char* path) override; diff --git a/platforms/sdl/main.cpp b/platforms/sdl/main.cpp index c9f49d55b..86e5ea7d4 100644 --- a/platforms/sdl/main.cpp +++ b/platforms/sdl/main.cpp @@ -111,6 +111,17 @@ extern "C" void resize_from_js(int new_width, int new_height) } #endif +// DirectSound Support +#ifdef _WIN32 +HWND GetHWND() +{ + SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + SDL_GetWindowWMInfo(window, &wmInfo); + return wmInfo.info.win.window; +} +#endif + // Handle Events static bool window_resized = false; static void handle_events() @@ -298,6 +309,10 @@ static EM_BOOL main_loop(double time, void *user_data) // Main int main(int argc, char *argv[]) { + // Setup Logging + Logger::setSingleton(new Logger); + + // Setup SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) { //LOG_E("Unable To Initialize SDL: %s", SDL_GetError()); @@ -331,7 +346,7 @@ int main(int argc, char *argv[]) window = SDL_CreateWindow("ReMinecraftPE", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, Minecraft::width, Minecraft::height, flags); if (!window) { - //LOG_E("Unable to create SDL window"); + LOG_E("Unable to create SDL window: %s", SDL_GetError()); exit(EXIT_FAILURE); } @@ -357,7 +372,7 @@ int main(int argc, char *argv[]) } } -#ifdef _WIN32 +#if defined(_WIN32) && !defined(USE_GLES1_COMPATIBILITY_LAYER) xglInit(); if (!xglInitted()) @@ -371,7 +386,7 @@ int main(int argc, char *argv[]) // Setup Compatibility Layer If Needed #ifdef USE_GLES1_COMPATIBILITY_LAYER - init_gles_compatibility_layer(); + init_gles_compatibility_layer(SDL_GL_GetProcAddress); #endif // Setup Teardown diff --git a/platforms/sound/CMakeLists.txt b/platforms/sound/CMakeLists.txt new file mode 100644 index 000000000..886b3f6b4 --- /dev/null +++ b/platforms/sound/CMakeLists.txt @@ -0,0 +1,10 @@ +project(reminecraftpe-sound) + +# Select & Build +set(DEFAULT_SOUND_PLATFORM "openal") +if(WIN32) + set(DEFAULT_SOUND_PLATFORM "directsound") +endif() +set(REMCPE_SOUND_PLATFORM "${DEFAULT_SOUND_PLATFORM}" CACHE STRING "ReMCPE Sound Platform (Check /platforms/sound)") +add_subdirectory("${REMCPE_SOUND_PLATFORM}") +target_link_libraries(reminecraftpe reminecraftpe-sound) \ No newline at end of file diff --git a/platforms/sound/directsound/CMakeLists.txt b/platforms/sound/directsound/CMakeLists.txt new file mode 100644 index 000000000..24daf6bbf --- /dev/null +++ b/platforms/sound/directsound/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.16.0) +project(reminecraftpe-directsound) + +# Build +add_library(reminecraftpe-sound STATIC + SoundSystemDS.cpp +) + +# Libraries +target_link_libraries(reminecraftpe-sound + reminecraftpe-core + dsound + dxguid +) + +# Headers +target_include_directories(reminecraftpe-sound PUBLIC .) diff --git a/platforms/windows/SoundSystemDS.hpp b/platforms/sound/directsound/CustomSoundSystem.hpp similarity index 91% rename from platforms/windows/SoundSystemDS.hpp rename to platforms/sound/directsound/CustomSoundSystem.hpp index 7543c4a55..254e41ea3 100644 --- a/platforms/windows/SoundSystemDS.hpp +++ b/platforms/sound/directsound/CustomSoundSystem.hpp @@ -8,7 +8,7 @@ #pragma once #include -#include +#include #include #include #include @@ -37,7 +37,10 @@ class SoundSystemDS : public SoundSystem virtual void pause(const std::string& sound); virtual void stop(const std::string& sound); virtual void playAt(const SoundDesc& sound, float x, float y, float z, float a, float b); + private: + // Release sounds that finished playing + void clearBuffers(); struct BufferInfo { @@ -49,4 +52,6 @@ class SoundSystemDS : public SoundSystem IDirectSound* m_directsound; LPDIRECTSOUND3DLISTENER m_listener; std::vector m_buffers; -}; \ No newline at end of file +}; + +#define SOUND_SYSTEM SoundSystemDS diff --git a/platforms/windows/SoundSystemDS.cpp b/platforms/sound/directsound/SoundSystemDS.cpp similarity index 94% rename from platforms/windows/SoundSystemDS.cpp rename to platforms/sound/directsound/SoundSystemDS.cpp index 34ca8efd3..6d95d15c5 100644 --- a/platforms/windows/SoundSystemDS.cpp +++ b/platforms/sound/directsound/SoundSystemDS.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #define WIN32_LEAN_AND_MEAN -#include "SoundSystemDS.hpp" +#include "CustomSoundSystem.hpp" #include "common/Utils.hpp" // @TODO: fix crash in playAt when Asan is active @@ -138,44 +138,30 @@ void SoundSystemDS::playAt(const SoundDesc& sound, float x, float y, float z, fl { return; } - - //Release sounds that finished playing - for (size_t i = 0; i < m_buffers.size(); i++) - { - DWORD status; - m_buffers[i].buffer->GetStatus(&status); - if (status != DSBSTATUS_PLAYING) { - m_buffers[i].buffer->Release(); - if (m_buffers[i].object3d != NULL) - { - m_buffers[i].object3d->Release(); - } - m_buffers.erase(m_buffers.begin() + i); - i--; - } - } + + clearBuffers(); HRESULT result; IDirectSoundBuffer* tempBuffer; unsigned char* bufferPtr; unsigned long bufferSize; - int length = sound.m_pHeader->m_length * sound.m_pHeader->m_bytes_per_sample; + int length = sound.m_header.m_length * sound.m_header.m_bytes_per_sample; bool is2D = sqrtf(x * x + y * y + z * z) == 0.f; //For some reason mojang made 3D sounds are REALLY quiet, with some of their volumes literally going below 0.1 - if (!is2D) + /*if (!is2D) { volume *= 5.f; - } + }*/ LPDIRECTSOUNDBUFFER soundbuffer; //= (LPDIRECTSOUNDBUFFER*)calloc(1, sizeof(LPDIRECTSOUNDBUFFER)); WAVEFORMATEX waveFormat; waveFormat.wFormatTag = WAVE_FORMAT_PCM; - waveFormat.nSamplesPerSec = DWORD(float(sound.m_pHeader->m_sample_rate) * pitch); - waveFormat.wBitsPerSample = 8 * sound.m_pHeader->m_bytes_per_sample; - waveFormat.nChannels = sound.m_pHeader->m_channels; + waveFormat.nSamplesPerSec = DWORD(float(sound.m_header.m_sample_rate) * pitch); + waveFormat.wBitsPerSample = 8 * sound.m_header.m_bytes_per_sample; + waveFormat.nChannels = sound.m_header.m_channels; waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; waveFormat.cbSize = 0; @@ -268,7 +254,7 @@ void SoundSystemDS::playAt(const SoundDesc& sound, float x, float y, float z, fl info.object3d = NULL; //Check if position is not 0,0,0 and for mono to play 3D sound - if (!is2D && sound.m_pHeader->m_channels == 1) + if (!is2D && sound.m_header.m_channels == 1) { LPDIRECTSOUND3DBUFFER object3d; @@ -295,4 +281,22 @@ void SoundSystemDS::playAt(const SoundDesc& sound, float x, float y, float z, fl soundbuffer->Play(0, 0, 0); m_buffers.push_back(info); +} + +void SoundSystemDS::clearBuffers() +{ + for (size_t i = 0; i < m_buffers.size(); i++) + { + DWORD status; + m_buffers[i].buffer->GetStatus(&status); + if (status != DSBSTATUS_PLAYING) { + m_buffers[i].buffer->Release(); + if (m_buffers[i].object3d != NULL) + { + m_buffers[i].object3d->Release(); + } + m_buffers.erase(m_buffers.begin() + i); + i--; + } + } } \ No newline at end of file diff --git a/platforms/sound/openal/CMakeLists.txt b/platforms/sound/openal/CMakeLists.txt new file mode 100644 index 000000000..101c05f28 --- /dev/null +++ b/platforms/sound/openal/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.16.0) +project(reminecraftpe-openal) + +# Build +add_library(reminecraftpe-sound STATIC + SoundSystemAL.cpp +) + +# Core +target_link_libraries(reminecraftpe-sound PUBLIC reminecraftpe-core) + +# OpenAL +if(ANDROID) + # Use Vendored OpenAL + set(ALSOFT_UTILS FALSE CACHE BOOL "" FORCE) + set(ALSOFT_EXAMPLES FALSE CACHE BOOL "" FORCE) + set(ALSOFT_TESTS FALSE CACHE BOOL "" FORCE) + set(ALSOFT_REQUIRE_OPENSL TRUE CACHE BOOL "" FORCE) + add_subdirectory(../../../thirdparty/OpenAL openal EXCLUDE_FROM_ALL) + target_link_libraries(reminecraftpe-sound PUBLIC OpenAL::OpenAL) +elseif(EMSCRIPTEN) + # Use Emscripten's OpenAL + target_link_libraries(reminecraftpe-sound PUBLIC openal) +else() + # Use System OpenAL + find_package(OpenAL REQUIRED) + target_link_libraries(reminecraftpe-sound PUBLIC "${OPENAL_LIBRARY}") + target_include_directories(reminecraftpe-sound PUBLIC "${OPENAL_INCLUDE_DIR}") +endif() + +# Headers +target_include_directories(reminecraftpe-sound PUBLIC .) diff --git a/platforms/openal/SoundSystemAL.hpp b/platforms/sound/openal/CustomSoundSystem.hpp similarity index 87% rename from platforms/openal/SoundSystemAL.hpp rename to platforms/sound/openal/CustomSoundSystem.hpp index bc04737bf..7cf74eb32 100644 --- a/platforms/openal/SoundSystemAL.hpp +++ b/platforms/sound/openal/CustomSoundSystem.hpp @@ -1,17 +1,18 @@ #pragma once -#ifdef USE_OPENAL -#ifdef _WIN32 -#include -#include -#pragma comment( lib, "OpenAl32.lib" ) -#elif defined(__APPLE__) +#ifdef __APPLE__ #include #include -#else +#elif defined(__EMSCRIPTEN__) #include #include +#else +#include "al.h" +#include "alc.h" +#ifdef _WIN32 +#pragma comment( lib, "OpenAL32.lib" ) +#endif #endif #include @@ -24,6 +25,8 @@ #define MAX_IDLE_SOURCES 50 #define MAX_DISTANCE 16.0f +#define SOUND_SYSTEM SoundSystemAL + class SoundSystemAL : public SoundSystem { public: @@ -54,5 +57,3 @@ class SoundSystemAL : public SoundSystem Vec3 _lastListenerPos; float _listenerVolume; }; - -#endif diff --git a/platforms/openal/SoundSystemAL.cpp b/platforms/sound/openal/SoundSystemAL.cpp similarity index 97% rename from platforms/openal/SoundSystemAL.cpp rename to platforms/sound/openal/SoundSystemAL.cpp index 2130532c6..c9d1c5190 100644 --- a/platforms/openal/SoundSystemAL.cpp +++ b/platforms/sound/openal/SoundSystemAL.cpp @@ -1,5 +1,4 @@ -#ifdef USE_OPENAL -#include "SoundSystemAL.hpp" +#include "CustomSoundSystem.hpp" #include "common/Utils.hpp" @@ -87,7 +86,7 @@ ALuint SoundSystemAL::get_buffer(const SoundDesc& sound) } // Sound Data Size - int size = sound.m_header.m_channels * sound.m_header.m_length * sound.m_header.m_bytes_per_sample; + int size = sound.m_dataSize; // Create Buffer ALuint buffer; @@ -343,6 +342,4 @@ void SoundSystemAL::stopEngine() // Mark as unloaded _initialized = false; -} - -#endif +} \ No newline at end of file diff --git a/platforms/sound/opensl/CMakeLists.txt b/platforms/sound/opensl/CMakeLists.txt new file mode 100644 index 000000000..89eeabc98 --- /dev/null +++ b/platforms/sound/opensl/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.0) +project(reminecraftpe-opensl) + +# Build +add_library(reminecraftpe-sound STATIC + SoundSystemSL.cpp +) + +# Core +target_link_libraries(reminecraftpe-sound PUBLIC reminecraftpe-core) + +# OpenSL +target_link_libraries(reminecraftpe-sound PUBLIC OpenSLES) + +# Headers +target_include_directories(reminecraftpe-sound PUBLIC .) diff --git a/platforms/android/SoundSystemSL.hpp b/platforms/sound/opensl/CustomSoundSystem.hpp similarity index 97% rename from platforms/android/SoundSystemSL.hpp rename to platforms/sound/opensl/CustomSoundSystem.hpp index 121625bc1..f9e37e3da 100644 --- a/platforms/android/SoundSystemSL.hpp +++ b/platforms/sound/opensl/CustomSoundSystem.hpp @@ -30,6 +30,8 @@ typedef std::list SLSoundList; +#define SOUND_SYSTEM SoundSystemSL + class SoundSystemSL : public SoundSystem { public: @@ -62,4 +64,4 @@ class SoundSystemSL : public SoundSystem static std::vector toRemove; static SLObjectItf objEngine; static pthread_mutex_t toRemoveMutex; -}; \ No newline at end of file +}; diff --git a/platforms/android/SoundSystemSL.cpp b/platforms/sound/opensl/SoundSystemSL.cpp similarity index 99% rename from platforms/android/SoundSystemSL.cpp rename to platforms/sound/opensl/SoundSystemSL.cpp index 65649cd94..fcfca14da 100644 --- a/platforms/android/SoundSystemSL.cpp +++ b/platforms/sound/opensl/SoundSystemSL.cpp @@ -5,7 +5,7 @@ The following code is licensed under the BSD 1 clause license. SPDX-License-Identifier: BSD-1-Clause ********************************************************************/ -#include "SoundSystemSL.hpp" +#include "CustomSoundSystem.hpp" #include "common/Utils.hpp" #define C_MAX_SOUNDS 4 diff --git a/platforms/windows/AppPlatform_win32.cpp b/platforms/windows/AppPlatform_win32.cpp index e5daf9d67..467ae3f71 100644 --- a/platforms/windows/AppPlatform_win32.cpp +++ b/platforms/windows/AppPlatform_win32.cpp @@ -14,7 +14,6 @@ #include "GameMods.hpp" #include "AppPlatform_win32.hpp" -#include "LoggerWin32.hpp" #include "thirdparty/GL/GL.hpp" @@ -37,24 +36,18 @@ AppPlatform_win32::AppPlatform_win32() m_MouseDiffX = 0, m_MouseDiffY = 0; - // This initializes the Logger singleton to use the Windows-specific variant - // If we didn't initialize it here, the Minecraft class would have our back - m_pLogger = new LoggerWin32(); m_pSoundSystem = nullptr; } AppPlatform_win32::~AppPlatform_win32() { SAFE_DELETE(m_pSoundSystem); - - // DELETE THIS LAST - SAFE_DELETE(m_pLogger); } void AppPlatform_win32::initSoundSystem() { if (!m_pSoundSystem) - m_pSoundSystem = new SoundSystemDS(); + m_pSoundSystem = new SOUND_SYSTEM(); else LOG_E("Trying to initialize SoundSystem more than once!"); } @@ -214,16 +207,20 @@ bool AppPlatform_win32::hasFileSystemAccess() return true; } -std::string AppPlatform_win32::getPatchData() +AssetFile AppPlatform_win32::readAssetFile(const std::string& str) const { - std::ifstream ifs("assets/patches/patch_data.txt"); + std::string path = getAssetPath(str); + std::ifstream ifs(path, std::ios::binary | std::ios::ate); if (!ifs.is_open()) - return ""; + return AssetFile(); + + std::streamsize size = ifs.tellg(); + ifs.seekg(0, std::ios::beg); - std::stringstream ss; - ss << ifs.rdbuf(); + unsigned char* buffer = new unsigned char[size]; + ifs.read((char*) buffer, size); - return ss.str(); + return AssetFile(size, buffer); } void AppPlatform_win32::setScreenSize(int width, int height) diff --git a/platforms/windows/AppPlatform_win32.hpp b/platforms/windows/AppPlatform_win32.hpp index 772e4cfc2..caba74644 100644 --- a/platforms/windows/AppPlatform_win32.hpp +++ b/platforms/windows/AppPlatform_win32.hpp @@ -15,7 +15,7 @@ #include "client/player/input/Keyboard.hpp" #include "common/Utils.hpp" #include "LoggerWin32.hpp" -#include "SoundSystemDS.hpp" +#include "CustomSoundSystem.hpp" class AppPlatform_win32 : public AppPlatform { @@ -55,7 +55,7 @@ class AppPlatform_win32 : public AppPlatform bool hasFileSystemAccess() override; // Also add this to allow dynamic texture patching. - std::string getPatchData() override; + AssetFile readAssetFile(const std::string&) const override; void setScreenSize(int width, int height); const char* const getWindowTitle() const { return m_WindowTitle; } @@ -83,7 +83,6 @@ class AppPlatform_win32 : public AppPlatform int m_MouseDiffX, m_MouseDiffY; - LoggerWin32 *m_pLogger; - SoundSystemDS* m_pSoundSystem; + SOUND_SYSTEM* m_pSoundSystem; }; diff --git a/platforms/windows/CMakeLists.txt b/platforms/windows/CMakeLists.txt new file mode 100644 index 000000000..ff391c178 --- /dev/null +++ b/platforms/windows/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.16.0) +project(reminecraftpe-windows) + +# Win32 Build +target_compile_definitions(reminecraftpe-core + PUBLIC HANDLE_CHARS_SEPARATELY +) + +# Libraries +target_link_libraries(reminecraftpe-core + PUBLIC opengl32 + PUBLIC glu32 + PUBLIC gdi32 + PUBLIC uuid +) + +# Build +add_executable(reminecraftpe WIN32 + LoggerWin32.cpp + AppPlatform_win32.cpp + main.cpp + ../../thirdparty/GL/GLExt.cpp +) + +# Core +target_link_libraries(reminecraftpe reminecraftpe-core) + +# stb_image (If Needed) +add_subdirectory(../../thirdparty/stb_image stb_image) +target_link_libraries(reminecraftpe stb_image) \ No newline at end of file diff --git a/platforms/windows/LoggerWin32.hpp b/platforms/windows/LoggerWin32.hpp index 22bd0da1d..ac7f4a55b 100644 --- a/platforms/windows/LoggerWin32.hpp +++ b/platforms/windows/LoggerWin32.hpp @@ -3,7 +3,7 @@ #include #include "common/Logger.hpp" -class LoggerWin32 : Logger +class LoggerWin32 : public Logger { void print(eLogLevel, const char* const str) override; void print(eLogLevel, std::string str) override; diff --git a/platforms/windows/main.cpp b/platforms/windows/main.cpp index 2279f7954..ffc66ad8a 100644 --- a/platforms/windows/main.cpp +++ b/platforms/windows/main.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include -#include +#include #include "thirdparty/GL/GL.hpp" #include "compat/KeyCodes.hpp" @@ -18,6 +18,7 @@ #include "client/player/input/Multitouch.hpp" #include "AppPlatform_win32.hpp" +#include "LoggerWin32.hpp" #include "resource.h" LPCTSTR g_WindowClassName = TEXT("MCPEClass"); @@ -128,6 +129,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine SetInstance(hInstance); + // This initializes the Logger singleton to use the Windows-specific variant + // If we didn't initialize it here, the Minecraft class would have our back + Logger::setSingleton(new LoggerWin32); + // register the window class: WNDCLASS wc; wc.style = CS_OWNDC; diff --git a/platforms/windows/projects/Client/Client.vcxproj b/platforms/windows/projects/Client/Client.vcxproj index cdfbbd235..148326044 100644 --- a/platforms/windows/projects/Client/Client.vcxproj +++ b/platforms/windows/projects/Client/Client.vcxproj @@ -176,6 +176,7 @@ + diff --git a/platforms/windows/projects/Client/Client.vcxproj.filters b/platforms/windows/projects/Client/Client.vcxproj.filters index e234a075c..37cf018ef 100644 --- a/platforms/windows/projects/Client/Client.vcxproj.filters +++ b/platforms/windows/projects/Client/Client.vcxproj.filters @@ -455,6 +455,9 @@ Header Files\Player\Input + + Header Files\Sound + diff --git a/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj b/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj index 46f98edb0..2763b5aeb 100644 --- a/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj +++ b/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj @@ -37,7 +37,7 @@ - $(MC_ROOT)\platforms\openal;$(MC_ROOT)\thirdparty\stb_image\include;$(SDL2_PATH)\include;$(LIBPNG_PATH);$(OPENAL_PATH)\include;%(AdditionalIncludeDirectories) + $(MC_ROOT)\platforms\sound\openal;$(MC_ROOT)\thirdparty\stb_image\include;$(SDL2_PATH)\include;$(LIBPNG_PATH);$(OPENAL_PATH)\include;%(AdditionalIncludeDirectories) Console @@ -61,7 +61,7 @@ - + @@ -70,7 +70,7 @@ - + diff --git a/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj.filters b/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj.filters index 0c2cb9f2a..c0512ae8f 100644 --- a/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj.filters +++ b/platforms/windows/projects/MinecraftClient.SDL2/MinecraftClient.SDL2.vcxproj.filters @@ -24,15 +24,15 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + @@ -41,14 +41,14 @@ Header Files\Compatibility - - Header Files - Header Files\Compatibility Header Files + + Header Files + \ No newline at end of file diff --git a/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj b/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj index 3e71dab03..f502d9abd 100644 --- a/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj +++ b/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj @@ -37,7 +37,7 @@ - $(DXSDK_DIR)\Include;$(MC_ROOT)\thirdparty\stb_image\include;%(AdditionalIncludeDirectories) + $(DXSDK_DIR)\Include;$(MC_ROOT)\platforms\sound\directsound;$(MC_ROOT)\thirdparty\stb_image\include;%(AdditionalIncludeDirectories) Windows @@ -56,7 +56,7 @@ - + @@ -64,7 +64,7 @@ - + diff --git a/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj.filters b/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj.filters index c76c4fdab..5991da251 100644 --- a/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj.filters +++ b/platforms/windows/projects/MinecraftClient.Win32/MinecraftClient.Win32.vcxproj.filters @@ -24,7 +24,7 @@ Header Files - + Header Files @@ -44,7 +44,7 @@ Source Files - + Source Files diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index acf65732e..d9f947e7a 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -306,74 +306,19 @@ add_subdirectory(../thirdparty/raknet raknet) target_link_libraries(reminecraftpe-core PUBLIC raknet) # zlib -add_library(zlib INTERFACE) -if(EMSCRIPTEN) +add_library(zlib-interface INTERFACE) +if(WIN32) + # Compile Vendored ZLib + add_subdirectory(../thirdparty/zlib zlib) + target_link_libraries(zlib-interface INTERFACE zlib) +elseif(EMSCRIPTEN) # Use Emscripten's ZLib set(ZLIB_FLAG -sUSE_ZLIB=1) - target_compile_options(zlib INTERFACE "${ZLIB_FLAG}") - target_link_options(zlib INTERFACE "${ZLIB_FLAG}") + target_compile_options(zlib-interface INTERFACE "${ZLIB_FLAG}") + target_link_options(zlib-interface INTERFACE "${ZLIB_FLAG}") else() # Use System ZLib find_package(ZLIB REQUIRED) - target_link_libraries(zlib INTERFACE ZLIB::ZLIB) -endif() -target_link_libraries(reminecraftpe-core PUBLIC zlib) - -# Platform Dependencies -if(USE_SDL) - # SDL - add_library(SDL INTERFACE) - if(ANDROID) - # Use Vendored SDL2 (Only For Android) - add_subdirectory(../thirdparty/SDL2/src SDL EXCLUDE_FROM_ALL) - target_link_libraries(SDL INTERFACE SDL2::SDL2) - elseif(EMSCRIPTEN) - # Use Emscripten's SDL2 - set(SDL_FLAG -sUSE_SDL=2) - target_compile_options(SDL INTERFACE "${SDL_FLAG}") - target_link_options(SDL INTERFACE "${SDL_FLAG}") - else() - # Use System SDL2 - find_package(SDL2 REQUIRED) - target_link_libraries(SDL INTERFACE SDL2::SDL2) - endif() - target_link_libraries(reminecraftpe-core PUBLIC SDL) - - # OpenGL - if(NOT EMSCRIPTEN AND NOT ANDROID) - option(USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" TRUE) - else() - set(USE_GLES1_COMPATIBILITY_LAYER TRUE CACHE BOOL "" FORCE) - endif() - if(USE_GLES1_COMPATIBILITY_LAYER) - set(GLES_COMPATIBILITY_LAYER_USE_SDL TRUE CACHE BOOL "" FORCE) - set(GLES_COMPATIBILITY_LAYER_DEPENDENCY SDL CACHE STRING "" FORCE) - set(GLES_COMPATIBILITY_LAYER_USE_ES3 FALSE CACHE BOOL "" FORCE) - add_subdirectory(../thirdparty/gles-compatibility-layer gles-compatibility-layer) - target_link_libraries(reminecraftpe-core PUBLIC gles-compatibility-layer) - target_compile_definitions(reminecraftpe-core PUBLIC USE_GLES1_COMPATIBILITY_LAYER) - if(EMSCRIPTEN) - # Use WebGL 2 - target_link_options(reminecraftpe-core PUBLIC -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2) - endif() - else() - find_package(OpenGL REQUIRED) - target_link_libraries(reminecraftpe-core PUBLIC OpenGL::GL) - endif() -elseif(USE_NATIVE_ANDROID) - # OpenGL - target_link_libraries(reminecraftpe-core PUBLIC EGL GLESv1_CM) -endif() - -# Android Logging -if(ANDROID) - target_link_libraries(reminecraftpe-core PUBLIC log) -endif() - -# Sound Data -if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../sound_data/sounds.h") - if(NOT DEFINED ENV{CI}) - message(WARNING "Missing sound data! Did you run tools/grabsounds.py?") - endif() - target_compile_definitions(reminecraftpe-core PRIVATE MISSING_SOUND_DATA) + target_link_libraries(zlib-interface INTERFACE ZLIB::ZLIB) endif() +target_link_libraries(reminecraftpe-core PUBLIC zlib-interface) \ No newline at end of file diff --git a/source/client/app/AppPlatform.cpp b/source/client/app/AppPlatform.cpp index b90592c86..52515af85 100644 --- a/source/client/app/AppPlatform.cpp +++ b/source/client/app/AppPlatform.cpp @@ -226,7 +226,15 @@ bool AppPlatform::hasFileSystemAccess() std::string AppPlatform::getPatchData() { - return ""; + const AssetFile file = readAssetFile("patches/patch_data.txt"); + std::string out = std::string(file.data, file.data + file.size); + delete file.data; + return out; +} + +AssetFile AppPlatform::readAssetFile(const std::string& path) const +{ + return AssetFile(); } void AppPlatform::initSoundSystem() diff --git a/source/client/app/AppPlatform.hpp b/source/client/app/AppPlatform.hpp index 082552140..581c0f306 100644 --- a/source/client/app/AppPlatform.hpp +++ b/source/client/app/AppPlatform.hpp @@ -13,6 +13,7 @@ #include "client/renderer/Texture.hpp" #include "client/sound/SoundSystem.hpp" +#include "AssetFile.hpp" class AppPlatform { @@ -85,6 +86,8 @@ class AppPlatform virtual std::string getPatchData(); virtual void initSoundSystem(); virtual SoundSystem* const getSoundSystem() const; + // Used For Sounds + virtual AssetFile readAssetFile(const std::string&) const; #endif public: diff --git a/source/client/app/AssetFile.hpp b/source/client/app/AssetFile.hpp new file mode 100644 index 000000000..81a26900f --- /dev/null +++ b/source/client/app/AssetFile.hpp @@ -0,0 +1,20 @@ +/******************************************************************** +Minecraft: Pocket Edition - Decompilation Project + Copyright (C) 2023 iProgramInCpp + + The following code is licensed under the BSD 1 clause license. + SPDX-License-Identifier: BSD-1-Clause + ********************************************************************/ + +#pragma once + +#include + +struct AssetFile +{ + ptrdiff_t size; + unsigned char *data; + + AssetFile(): size(-1), data(nullptr) {} + AssetFile(ptrdiff_t size, unsigned char *data): size(size), data(data) {} +}; \ No newline at end of file diff --git a/source/client/app/Minecraft.cpp b/source/client/app/Minecraft.cpp index 1d38364d9..976d95c84 100644 --- a/source/client/app/Minecraft.cpp +++ b/source/client/app/Minecraft.cpp @@ -98,8 +98,6 @@ Minecraft::Minecraft() : m_fLastUpdated = 0; m_fDeltaTime = 0; m_lastInteractTime = 0; - - m_Logger = new Logger(); } int Minecraft::getLicenseId() @@ -840,7 +838,7 @@ void Minecraft::init() GetPatchManager()->PatchTiles(); m_pSoundEngine = new SoundEngine(platform()->getSoundSystem()); - m_pSoundEngine->init(m_options); + m_pSoundEngine->init(m_options, platform()); m_pLevelRenderer = new LevelRenderer(this, m_pTextures); m_pGameRenderer = new GameRenderer(this); @@ -868,6 +866,7 @@ Minecraft::~Minecraft() SAFE_DELETE(m_pLevelRenderer); SAFE_DELETE(m_pGameRenderer); SAFE_DELETE(m_pParticleEngine); + m_pSoundEngine->destroy(); SAFE_DELETE(m_pSoundEngine); SAFE_DELETE(m_pGameMode); SAFE_DELETE(m_pFont); @@ -885,7 +884,6 @@ Minecraft::~Minecraft() SAFE_DELETE(m_pUser); SAFE_DELETE(m_pLevelStorageSource); SAFE_DELETE(m_pInputHolder); - SAFE_DELETE(m_Logger); //@BUG: potentially leaking a CThread instance if this is destroyed early? } diff --git a/source/client/app/Minecraft.hpp b/source/client/app/Minecraft.hpp index f69d9284c..28e8fc252 100644 --- a/source/client/app/Minecraft.hpp +++ b/source/client/app/Minecraft.hpp @@ -107,7 +107,6 @@ class Minecraft : public App static int customDebugId; private: - Logger *m_Logger; Options *m_options; public: diff --git a/source/client/app/NinecraftApp.cpp b/source/client/app/NinecraftApp.cpp index 70b72fa31..91d6f963d 100644 --- a/source/client/app/NinecraftApp.cpp +++ b/source/client/app/NinecraftApp.cpp @@ -62,6 +62,7 @@ void NinecraftApp::initGLStates() glDepthFunc(GL_LEQUAL); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.1f); + //glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glEnable(GL_TEXTURE_2D); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); diff --git a/source/client/gui/Gui.cpp b/source/client/gui/Gui.cpp index 148a270fa..8f9a7a9fb 100644 --- a/source/client/gui/Gui.cpp +++ b/source/client/gui/Gui.cpp @@ -288,9 +288,9 @@ void Gui::render(float f, bool bHaveScreen, int mouseX, int mouseY) int emptyHeartX = 16; bool b1 = false; - if (player->field_B8 < 10) + if (player->m_invulnerableTime < 10) { - b1 = player->field_B8 / 3 % 2; + b1 = player->m_invulnerableTime / 3 % 2; emptyHeartX += 9 * b1; } @@ -318,9 +318,9 @@ void Gui::render(float f, bool bHaveScreen, int mouseX, int mouseY) if (b1) { - if (healthNo < player->field_100) + if (healthNo < player->m_lastHealth) blit(heartX, heartY, 70, 0, 9, 9, 0, 0); - else if (healthNo == player->field_100) + else if (healthNo == player->m_lastHealth) blit(heartX, heartY, 79, 0, 9, 9, 0, 0); } diff --git a/source/client/gui/Screen.cpp b/source/client/gui/Screen.cpp index 99e7cb4b0..aeb233a2e 100644 --- a/source/client/gui/Screen.cpp +++ b/source/client/gui/Screen.cpp @@ -63,7 +63,7 @@ void Screen::keyPressed(int key) { if (m_buttonTabList[m_tabButtonIndex]->m_bEnabled) { - m_pMinecraft->m_pSoundEngine->play("random.click"); + m_pMinecraft->m_pSoundEngine->playUI("random.click"); buttonClicked(m_buttonTabList[m_tabButtonIndex]); } } @@ -210,7 +210,7 @@ void Screen::mouseClicked(int xPos, int yPos, int d) // d = clicked? if (!m_pMinecraft->isTouchscreen()) { - m_pMinecraft->m_pSoundEngine->play("random.click"); + m_pMinecraft->m_pSoundEngine->playUI("random.click"); buttonClicked(button); } } @@ -264,7 +264,7 @@ void Screen::mouseReleased(int xPos, int yPos, int d) { if (m_pMinecraft->isTouchscreen() && m_pClickedButton->clicked(m_pMinecraft, xPos, yPos)) { - m_pMinecraft->m_pSoundEngine->play("random.click"); + m_pMinecraft->m_pSoundEngine->playUI("random.click"); buttonClicked(m_pClickedButton); } m_pClickedButton->released(xPos, yPos); diff --git a/source/client/gui/screens/StartMenuScreen.cpp b/source/client/gui/screens/StartMenuScreen.cpp index 18c196e4f..5156523d0 100644 --- a/source/client/gui/screens/StartMenuScreen.cpp +++ b/source/client/gui/screens/StartMenuScreen.cpp @@ -13,7 +13,7 @@ #include "SelectWorldScreen.hpp" #include "JoinGameScreen.hpp" -#if defined(_WIN32) || (defined(TARGET_OS_MAC) && TARGET_OS_IPHONE == 0) +#if (defined(USE_SDL) || defined(_WIN32) || (defined(TARGET_OS_MAC) && TARGET_OS_IPHONE == 0)) && !defined(ANDROID) #define CAN_QUIT #endif diff --git a/source/client/renderer/LevelRenderer.cpp b/source/client/renderer/LevelRenderer.cpp index 36e103f75..a12704673 100644 --- a/source/client/renderer/LevelRenderer.cpp +++ b/source/client/renderer/LevelRenderer.cpp @@ -903,17 +903,26 @@ void LevelRenderer::renderHitOutline(Player* pPlayer, const HitResult& hr, int i glDisable(GL_TEXTURE_2D); glDepthMask(false); - // Maximize Line Width - glEnable(GL_LINE_SMOOTH); - + // Determine Line Width + float line_width = 1.5f / Minecraft::getRenderScaleMultiplier(); + // Clamp Line Width float range[2]; +#ifdef GL_ALIASED_LINE_WIDTH_RANGE + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range); +#else + glEnable(GL_LINE_SMOOTH); glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, range); - - float lineWidth = 2.0f * Minecraft::getRenderScaleMultiplier(); - if (lineWidth > range[1]) - lineWidth = range[1]; - - glLineWidth(lineWidth); +#endif + if (range[1] < line_width) + { + line_width = range[1]; + } + else if (range[0] > line_width) + { + line_width = range[0]; + } + // Set Line Width + glLineWidth(line_width); TileID tile = m_pLevel->getTile(hr.m_tilePos); if (tile > 0) @@ -934,6 +943,9 @@ void LevelRenderer::renderHitOutline(Player* pPlayer, const HitResult& hr, int i render(aabb); } +#ifndef GL_ALIASED_LINE_WIDTH_RANGE + glDisable(GL_LINE_SMOOTH); +#endif glDepthMask(true); glEnable(GL_TEXTURE_2D); glDisable(GL_BLEND); diff --git a/source/client/renderer/entity/EntityRenderer.cpp b/source/client/renderer/entity/EntityRenderer.cpp index 8a3e96047..db1a3709d 100644 --- a/source/client/renderer/entity/EntityRenderer.cpp +++ b/source/client/renderer/entity/EntityRenderer.cpp @@ -138,7 +138,7 @@ Level* EntityRenderer::getLevel() const return m_pDispatcher->m_pLevel; } -void EntityRenderer::renderTileShadow(Tile* tt, const Vec3& pos, TilePos& tilePos, float pow, float r, const Vec3& oPos) +void EntityRenderer::renderTileShadow(Tile* tt, const Vec3& pos, const TilePos& tilePos, float pow, float r, const Vec3& oPos) { Tesselator& t = Tesselator::instance; if (!tt->isCubeShaped()) return; diff --git a/source/client/renderer/entity/EntityRenderer.hpp b/source/client/renderer/entity/EntityRenderer.hpp index 65bb9141e..b06206832 100644 --- a/source/client/renderer/entity/EntityRenderer.hpp +++ b/source/client/renderer/entity/EntityRenderer.hpp @@ -29,7 +29,7 @@ class EntityRenderer Level* getLevel() const; void renderFlame(Entity* e, const Vec3& pos, float a); void renderShadow(Entity* e, const Vec3& pos, float pow, float a); - void renderTileShadow(Tile* tt, const Vec3& pos, TilePos& tilePos, float pow, float r, const Vec3& oPos); + void renderTileShadow(Tile* tt, const Vec3& pos, const TilePos& tilePos, float pow, float r, const Vec3& oPos); public: EntityRenderer(); diff --git a/source/client/renderer/entity/FallingTileRenderer.cpp b/source/client/renderer/entity/FallingTileRenderer.cpp index a72e9c3d9..3286447fa 100644 --- a/source/client/renderer/entity/FallingTileRenderer.cpp +++ b/source/client/renderer/entity/FallingTileRenderer.cpp @@ -35,7 +35,7 @@ void FallingTileRenderer::render(Entity* entity, float x, float y, float z, floa #define ARGPATCH #endif - m_tileRenderer.renderTile(Tile::tiles[fallingTile->m_id], 0 ARGPATCH); + m_tileRenderer.renderTile(Tile::tiles[fallingTile->m_tileId], 0 ARGPATCH); glPopMatrix(); diff --git a/source/client/renderer/entity/MobRenderer.cpp b/source/client/renderer/entity/MobRenderer.cpp index 1fbeead8c..43a664ec7 100644 --- a/source/client/renderer/entity/MobRenderer.cpp +++ b/source/client/renderer/entity/MobRenderer.cpp @@ -109,10 +109,10 @@ void MobRenderer::render(Entity* entity, float x, float y, float z, float unused //glTranslatef(0.0f, -1.5078f, 0.0f); glTranslatef(0.0f, -24.0f * fScale - (1.0f / 128.0f), 0.0f); - float x1 = pMob->field_128 + (pMob->field_12C - pMob->field_128) * f; + float x1 = pMob->field_128 + (pMob->m_walkAnimSpeed - pMob->field_128) * f; if (x1 > 1.0f) x1 = 1.0f; - float x2 = pMob->field_130 - pMob->field_12C * (1.0f - f); + float x2 = pMob->field_130 - pMob->m_walkAnimSpeed * (1.0f - f); bindTexture(pMob->getTexture()); glEnable(GL_ALPHA_TEST); diff --git a/source/client/sound/SoundData.cpp b/source/client/sound/SoundData.cpp index c1cabd486..534074fb9 100644 --- a/source/client/sound/SoundData.cpp +++ b/source/client/sound/SoundData.cpp @@ -8,13 +8,115 @@ #include "SoundData.hpp" -// -------------------------------------------------------------------- -// WARNING! If you have an error here it is most likely because you did -// not grab the sound data from a working Minecraft PE 0.1.3 .apk. -// -// Check the readme for a guide on how to extract game sounds from the -// Minecraft PE 0.1.3 .apk file. -// -------------------------------------------------------------------- -#ifndef MISSING_SOUND_DATA -#include "../../sound_data/sounds.h" -#endif +#define STB_VORBIS_HEADER_ONLY +#include "thirdparty/stb_image/include/stb_vorbis.c" + +#include "client/app/AppPlatform.hpp" + +bool SoundDesc::_load(const AppPlatform* platform, const char* category, const char *name) +{ + if (m_isLoaded) + { + LOG_W("Sound \"%s\" is already loaded!", name); + return true; + } + + if (_loadOgg(platform, category, name) || _loadPcm(platform, category, name)) + { + // Success! + return true; + } + else + { + m_codecType = AudioCodec::NONE; + } + + LOG_W("Failed to load sound \"%s\"!", name); + return false; +} + +bool SoundDesc::_loadPcm(const AppPlatform* platform, const char* category, const char *name) +{ + m_file = platform->readAssetFile(std::string("sound/") + name + ".pcm"); + m_isLoaded = m_file.size > 0; + if (m_isLoaded) + { + m_codecType = AudioCodec::PCM; + m_fileData = m_file.data; + m_header = *(PCMSoundHeader *) m_fileData; + m_pData = (uint16_t *) (m_fileData + sizeof(PCMSoundHeader)); + m_dataSize = m_header.m_channels * m_header.m_length * m_header.m_bytes_per_sample; + + // Success! + return true; + } + + return false; +} + +bool SoundDesc::_loadOgg(const AppPlatform* platform, const char* category, const char *name) +{ + m_file = platform->readAssetFile(std::string("sound/") + category + '/' + name + ".ogg"); + m_isLoaded = m_file.size > 0; + if (m_isLoaded) + { + m_codecType = AudioCodec::OGG; + m_fileData = m_file.data; + m_header.m_bytes_per_sample = 2; // Always 2 (16-bit) + // Casting to a short** here might cause problems. Let's find out... + // Seems like it doesn't. Cool. + m_header.m_length = stb_vorbis_decode_memory(m_file.data, (int)m_file.size, &m_header.m_channels, &m_header.m_sample_rate, (short**)&m_pData); + if (m_header.m_length == -1) + { + LOG_E("An error occurred while trying to decode a sound!"); + return false; + } + m_dataSize = m_header.m_channels * m_header.m_length * m_header.m_bytes_per_sample; + + // Success! + return true; + } + + return false; +} + +void SoundDesc::_unload() +{ + if (!m_isLoaded) + { + // Sound is already unloaded + return; + } + + switch (m_codecType) + { + case AudioCodec::OGG: + free(m_pData); + break; + default: + // Do nothing + break; + } + + m_isLoaded = false; +} + +// Load All Sounds +void SoundDesc::_loadAll(const AppPlatform* platform) +{ +#define SOUND(category, name, number) SA_##name##number._load(platform, #category, #name#number); +#include "sound_list.h" +#undef SOUND +} + +// Un-load All Sounds +void SoundDesc::_unloadAll() +{ +#define SOUND(category, name, number) SA_##name##number._unload(); +#include "sound_list.h" +#undef SOUND +} + +#define SOUND(category, name, number) SoundDesc SA_##name##number; +#include "sound_list.h" +#undef SOUND diff --git a/source/client/sound/SoundData.hpp b/source/client/sound/SoundData.hpp index 6769bc73b..3a96ea7c0 100644 --- a/source/client/sound/SoundData.hpp +++ b/source/client/sound/SoundData.hpp @@ -10,6 +10,20 @@ #include #include "common/Utils.hpp" +#include "client/app/AssetFile.hpp" + +class AppPlatform; + +class AudioCodec +{ +public: + enum Type + { + NONE, + PCM, + OGG + }; +}; struct PCMSoundHeader { @@ -21,22 +35,23 @@ struct PCMSoundHeader struct SoundDesc { + bool m_isLoaded; + AudioCodec::Type m_codecType; + + AssetFile m_file; uint16_t* m_pData; - int field_4; + int m_dataSize; PCMSoundHeader m_header; - PCMSoundHeader* m_pHeader; - - SoundDesc() - { - m_pData = nullptr; - field_4 = 0; - m_pHeader = nullptr; - } - SoundDesc(PCMSoundHeader& header, uint16_t* data) - { - m_pHeader = &header; - m_header = header; - m_pData = data; - field_4 = header.m_channels * header.m_length * header.m_bytes_per_sample; - } + unsigned char* m_fileData; + + bool _load(const AppPlatform* platform, const char* category, const char *name); + bool _loadPcm(const AppPlatform* platform, const char* category, const char *name); + bool _loadOgg(const AppPlatform* platform, const char* category, const char *name); + void _unload(); + static void _loadAll(const AppPlatform*); + static void _unloadAll(); }; + +#define SOUND(category, name, number) extern SoundDesc SA_##name##number; +#include "sound_list.h" +#undef SOUND diff --git a/source/client/sound/SoundEngine.cpp b/source/client/sound/SoundEngine.cpp index d67a9ec32..5934f7c76 100644 --- a/source/client/sound/SoundEngine.cpp +++ b/source/client/sound/SoundEngine.cpp @@ -15,56 +15,27 @@ SoundEngine::SoundEngine(SoundSystem* soundSystem) m_pSoundSystem = soundSystem; m_pOptions = nullptr; field_40 = 0; - field_A1C = 0; + m_noMusicDelay = m_random.nextInt(12000); field_A20 = 0; m_muted = false; } float SoundEngine::_getVolumeMult(const Vec3& pos) { + // @TODO: this is not supposed to be a constant return 1.0f; } -void SoundEngine::init(Options* options) +void SoundEngine::init(Options* options, AppPlatform* platform) { // TODO: Who's the genius who decided it'd be better to check a name string rather than an enum? m_pOptions = options; + // Load Sounds + SoundDesc::_loadAll(platform); -#ifndef MISSING_SOUND_DATA - m_repository.add("step.cloth", SA_cloth1); - m_repository.add("step.cloth", SA_cloth2); - m_repository.add("step.cloth", SA_cloth3); - m_repository.add("step.cloth", SA_cloth4); - - m_repository.add("step.grass", SA_grass1); - m_repository.add("step.grass", SA_grass2); - m_repository.add("step.grass", SA_grass3); - m_repository.add("step.grass", SA_grass4); - - m_repository.add("step.gravel", SA_gravel1); - m_repository.add("step.gravel", SA_gravel2); - m_repository.add("step.gravel", SA_gravel3); - m_repository.add("step.gravel", SA_gravel4); - - m_repository.add("step.sand", SA_sand1); - m_repository.add("step.sand", SA_sand2); - m_repository.add("step.sand", SA_sand3); - m_repository.add("step.sand", SA_sand4); - - m_repository.add("step.stone", SA_stone1); - m_repository.add("step.stone", SA_stone2); - m_repository.add("step.stone", SA_stone3); - m_repository.add("step.stone", SA_stone4); - - m_repository.add("step.wood", SA_wood1); - m_repository.add("step.wood", SA_wood2); - m_repository.add("step.wood", SA_wood3); - m_repository.add("step.wood", SA_wood4); - - m_repository.add("random.splash", SA_splash); - m_repository.add("random.explode", SA_explode); - m_repository.add("random.click", SA_click); -#endif +#define SOUND(category, name, number) m_sounds.add(#category "." #name, SA_##name##number); +#include "sound_list.h" +#undef SOUND } void SoundEngine::enable(bool b) @@ -87,6 +58,8 @@ void SoundEngine::unMute() void SoundEngine::destroy() { + // Un-load Sounds + SoundDesc::_unloadAll(); } void SoundEngine::play(const std::string& name, const Vec3& pos, float volume, float pitch) @@ -99,7 +72,25 @@ void SoundEngine::play(const std::string& name, const Vec3& pos, float volume, f float cPitch = Mth::clamp(pitch, -1.0f, 1.0f); SoundDesc sd; - if (m_repository.get(name, sd)) { - m_pSoundSystem->playAt(sd, pos.x, pos.y, pos.z, cVolume, pitch); + if (m_sounds.get(name, sd)) + { + m_pSoundSystem->playAt(sd, pos.x, pos.y, pos.z, cVolume, cPitch); + } +} + +void SoundEngine::playUI(const std::string& name, float volume, float pitch) +{ + volume *= 0.25F; // present on Java b1.2_02, but not Pocket for some reason + float vol = m_pOptions->m_fMasterVolume * volume; + if (vol <= 0.0f) + return; + + float cVolume = Mth::clamp(vol, 0.0f, 1.0f); + float cPitch = Mth::clamp(pitch, -1.0f, 1.0f); + SoundDesc sd; + + if (m_sounds.get(name, sd)) + { + m_pSoundSystem->playAt(sd, 0.0f, 0.0f, 0.0f, cVolume, cPitch); } } diff --git a/source/client/sound/SoundEngine.hpp b/source/client/sound/SoundEngine.hpp index 40012fc56..84dc1fb19 100644 --- a/source/client/sound/SoundEngine.hpp +++ b/source/client/sound/SoundEngine.hpp @@ -20,21 +20,25 @@ class SoundEngine float _getVolumeMult(const Vec3& pos); public: SoundEngine(SoundSystem* soundSystem); - void init(Options*); + void init(Options*, AppPlatform*); void enable(bool b); void updateOptions(); void mute(); void unMute(); void destroy(); void play(const std::string& name, const Vec3& pos = Vec3::ZERO, float volume = 1.0f, float pitch = 1.0f); + void playUI(const std::string& name, float volume = 1.0f, float pitch = 1.0f); public: SoundSystem* m_pSoundSystem; +private: + SoundRepository m_sounds; + SoundRepository m_streamingSounds; + SoundRepository m_songs; Options* m_pOptions; int field_40; - //Random m_random; - SoundRepository m_repository; - int field_A1C; + Random m_random; + int m_noMusicDelay; int field_A20; bool m_muted; }; diff --git a/source/client/sound/SoundRepository.cpp b/source/client/sound/SoundRepository.cpp index b2e54c9e7..1b7d3e32a 100644 --- a/source/client/sound/SoundRepository.cpp +++ b/source/client/sound/SoundRepository.cpp @@ -12,12 +12,14 @@ void SoundRepository::add(const std::string& name, SoundDesc& sd) { + if (!sd.m_isLoaded) + return; std::map >::iterator iter = m_repo.find(name); if (iter == m_repo.end()) { std::vector sdv; sdv.push_back(sd); - m_repo.insert(std::pair >(name, sdv)); + m_repo.insert(std::make_pair(name, sdv)); } else { diff --git a/source/client/sound/SoundSystem.cpp b/source/client/sound/SoundSystem.cpp index 9fb023458..5fe66e1c0 100644 --- a/source/client/sound/SoundSystem.cpp +++ b/source/client/sound/SoundSystem.cpp @@ -41,7 +41,7 @@ void SoundSystem::stop(const std::string& sound) { } -void SoundSystem::playAt(const SoundDesc& sound, float x, float y, float z, float a, float b) +void SoundSystem::playAt(const SoundDesc& sound, float x, float y, float z, float volume, float pitch) { } diff --git a/source/client/sound/SoundSystem.hpp b/source/client/sound/SoundSystem.hpp index 3192fa58d..e7a2e823a 100644 --- a/source/client/sound/SoundSystem.hpp +++ b/source/client/sound/SoundSystem.hpp @@ -23,7 +23,7 @@ class SoundSystem virtual void play(const std::string& sound); virtual void pause(const std::string& sound); virtual void stop(const std::string& sound); - virtual void playAt(const SoundDesc& sound, float x, float y, float z, float a, float b); + virtual void playAt(const SoundDesc& sound, float x, float y, float z, float volume, float pitch); // Be prepared for these to be called regardless of engine state virtual void startEngine(); diff --git a/source/client/sound/sound_list.h b/source/client/sound/sound_list.h new file mode 100644 index 000000000..78f69a433 --- /dev/null +++ b/source/client/sound/sound_list.h @@ -0,0 +1,69 @@ +SOUND(step, cloth, 1) +SOUND(step, cloth, 2) +SOUND(step, cloth, 3) +SOUND(step, cloth, 4) + +SOUND(step, grass, 1) +SOUND(step, grass, 2) +SOUND(step, grass, 3) +SOUND(step, grass, 4) + +SOUND(step, gravel, 1) +SOUND(step, gravel, 2) +SOUND(step, gravel, 3) +SOUND(step, gravel, 4) + +SOUND(step, sand, 1) +SOUND(step, sand, 2) +SOUND(step, sand, 3) +SOUND(step, sand, 4) + +SOUND(step, stone, 1) +SOUND(step, stone, 2) +SOUND(step, stone, 3) +SOUND(step, stone, 4) + +SOUND(step, wood, 1) +SOUND(step, wood, 2) +SOUND(step, wood, 3) +SOUND(step, wood, 4) + +SOUND(random, splash, ) +SOUND(random, explode, 1) +SOUND(random, explode, 2) +SOUND(random, explode, 3) +SOUND(random, explode, 4) +SOUND(random, click, ) +SOUND(random, door_close, ) +SOUND(random, door_open, ) +SOUND(random, pop, ) +SOUND(random, fizz, ) + +SOUND(fire, fire, ) + +SOUND(damage, fallbig, 1) +SOUND(damage, fallbig, 2) + +SOUND(damage, fallsmall, ) + +SOUND(mob, pig, 1) +SOUND(mob, pig, 2) +SOUND(mob, pig, 3) +SOUND(mob, pigdeath, ) + +SOUND(mob, sheep, 1) +SOUND(mob, sheep, 2) +SOUND(mob, sheep, 3) + +SOUND(mob, cow, 1) +SOUND(mob, cow, 2) +SOUND(mob, cow, 3) +SOUND(mob, cow, 4) +SOUND(mob, cowhurt, 1) +SOUND(mob, cowhurt, 2) +SOUND(mob, cowhurt, 3) + +SOUND(mob, chicken, 2) +SOUND(mob, chicken, 3) +SOUND(mob, chickenhurt, 1) +SOUND(mob, chickenhurt, 2) diff --git a/source/common/CThread.cpp b/source/common/CThread.cpp index f2857c8d9..530a40fbc 100644 --- a/source/common/CThread.cpp +++ b/source/common/CThread.cpp @@ -12,7 +12,7 @@ #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN -#include // for Sleep() +#include // for Sleep() #else #include #endif diff --git a/source/common/CThread.hpp b/source/common/CThread.hpp index b2b02b04a..ecc7cd955 100644 --- a/source/common/CThread.hpp +++ b/source/common/CThread.hpp @@ -13,7 +13,7 @@ #if defined(_WIN32) #ifndef USE_WIN32_THREADS -#if defined(_XBOX) || defined(USE_OLD_CPP) +#if defined(_XBOX) || defined(USE_OLD_CPP) || defined(__MINGW32__) // USE_WIN32_THREADS - Use a Win32 implementation of threads instead of using pthread #define USE_WIN32_THREADS #else @@ -41,7 +41,7 @@ #include #else #define WIN32_LEAN_AND_MEAN -#include +#include #endif #else diff --git a/source/common/Logger.cpp b/source/common/Logger.cpp index f629ac4f2..0b75ba832 100644 --- a/source/common/Logger.cpp +++ b/source/common/Logger.cpp @@ -12,11 +12,14 @@ Logger* const Logger::singleton() return m_singleton; } -Logger::Logger() +void Logger::setSingleton(Logger* logger) { // Stick with the first output handle we get - if (!m_singleton) - m_singleton = this; + if (!m_singleton) { + m_singleton = logger; + } else { + m_singleton->print(LOG_ERR, "Logging already setup!"); + } } Logger::~Logger() diff --git a/source/common/Logger.hpp b/source/common/Logger.hpp index 3d1f4a597..7ab2e5863 100644 --- a/source/common/Logger.hpp +++ b/source/common/Logger.hpp @@ -26,8 +26,8 @@ class Logger static Logger* m_singleton; public: static Logger* const singleton(); + static void setSingleton(Logger*); - Logger(); virtual ~Logger(); const char* GetTag(eLogLevel ll); diff --git a/source/common/Utils.cpp b/source/common/Utils.cpp index e187e142a..beb8f1785 100644 --- a/source/common/Utils.cpp +++ b/source/common/Utils.cpp @@ -14,7 +14,7 @@ #if defined(_WIN32) && !defined(_XBOX) #define WIN32_LEAN_AND_MEAN -#include +#include #include #include @@ -276,7 +276,7 @@ time_t getEpochTimeS() return time(0); } -#ifdef _WIN32 +#if defined(_WIN32) && !defined(USE_SDL) HINSTANCE g_hInstance = NULL; HWND g_hWnd = NULL; diff --git a/source/common/Utils.hpp b/source/common/Utils.hpp index 8098fc8f3..f0ae463d1 100644 --- a/source/common/Utils.hpp +++ b/source/common/Utils.hpp @@ -37,9 +37,9 @@ // Do we even need all this WinSock stuff anymore? #ifndef _XBOX // assume we're on a normal Windows device #define WIN32_LEAN_AND_MEAN -#include -#include -#include +#include +#include +#include #include #include diff --git a/source/network/ServerSideNetworkHandler.cpp b/source/network/ServerSideNetworkHandler.cpp index 6a5ea9303..3c6fdf700 100644 --- a/source/network/ServerSideNetworkHandler.cpp +++ b/source/network/ServerSideNetworkHandler.cpp @@ -614,7 +614,7 @@ void ServerSideNetworkHandler::commandSummon(OnlinePlayer* player, const std::ve for (int i = 0; i++ < amount;) { - Mob* mob = MobFactory::CreateMob(descriptor->getEntityType().getId(), m_pLevel); + Entity* mob = MobFactory::CreateMob(descriptor->getEntityType().getId(), m_pLevel); if (mob == nullptr) { ss << "Unable to summon object"; diff --git a/source/world/entity/Entity.cpp b/source/world/entity/Entity.cpp index 4d08af3e8..8b63c4d36 100644 --- a/source/world/entity/Entity.cpp +++ b/source/world/entity/Entity.cpp @@ -23,7 +23,7 @@ void Entity::_init() field_24 = 0; field_28 = 0; field_30 = 1.0f; - m_bBlocksBuilding = false; + m_bBlocksBuilding = false; m_pLevel = nullptr; m_rot = Vec2::ZERO; m_rotPrev = Vec2::ZERO; @@ -44,8 +44,8 @@ void Entity::_init() field_A8 = 0.0f; m_bNoPhysics = false; field_B0 = 0.0f; - m_tickCount = 0; - field_B8 = 0; + m_tickCount = 0; + m_invulnerableTime = 0; m_airCapacity = TOTAL_AIR_SUPPLY; m_fireTicks = 0; m_flameTime = 1; diff --git a/source/world/entity/Entity.hpp b/source/world/entity/Entity.hpp index 520eae1af..5d0478f7b 100644 --- a/source/world/entity/Entity.hpp +++ b/source/world/entity/Entity.hpp @@ -183,8 +183,8 @@ class Entity float field_30; bool m_bBlocksBuilding; Level* m_pLevel; - Vec3 m_oPos; // "o" in Java or "xo" ""yo" "zo" - Vec3 m_vel; + Vec3 m_oPos; // "o" in Java or "xo" "yo" "zo" + Vec3 m_vel; // "d" in Java or "xd" "yd" "zd" Vec2 m_rot; //maybe these are the actual m_yaw and m_pitch, and //the one I annotated are the destination yaw and pitch. @@ -210,7 +210,7 @@ class Entity bool m_bNoPhysics; float field_B0; int m_tickCount; - int field_B8; + int m_invulnerableTime; int m_airCapacity; int m_fireTicks; int m_flameTime; diff --git a/source/world/entity/FallingTile.cpp b/source/world/entity/FallingTile.cpp index 3718c5e91..4bd814a34 100644 --- a/source/world/entity/FallingTile.cpp +++ b/source/world/entity/FallingTile.cpp @@ -9,20 +9,16 @@ #include "FallingTile.hpp" #include "world/level/Level.hpp" -FallingTile::FallingTile(Level* level) : Entity(level), - field_E0(0) +void FallingTile::_init(TileID tileId, int tileData) { -} + m_pDescriptor = &EntityTypeDescriptor::fallingTile; -FallingTile::FallingTile(Level* level, const Vec3& pos, int id) : Entity(level), - field_E0(0) -{ - m_id = id; - m_bBlocksBuilding = false; + m_tileId = tileId; + m_tileData = tileData; + m_time = 0; + m_bBlocksBuilding = true; setSize(0.98f, 0.98f); m_heightOffset = m_bbHeight * 0.5f; - setPos(pos); - m_oPos = pos; m_bMakeStepSound = false; m_vel = Vec3::ZERO; @@ -31,6 +27,14 @@ FallingTile::FallingTile(Level* level, const Vec3& pos, int id) : Entity(level), #endif } +void FallingTile::_init(const Vec3& pos, TileID tileId, int tileData) +{ + _init(tileId, tileData); + + setPos(pos); + m_oPos = pos; +} + float FallingTile::getShadowHeightOffs() const { return 0.0f; @@ -43,11 +47,14 @@ bool FallingTile::isPickable() const void FallingTile::tick() { - if (!m_id) + if (m_tileId == TILE_AIR) + { remove(); + return; + } m_oPos = m_pos; - field_E0++; + m_time++; m_vel.y -= 0.04f; move(m_vel); @@ -58,28 +65,29 @@ void FallingTile::tick() // if we're inside one of our own tiles, clear it. // Assumes we started there - if (m_pLevel->getTile(tilePos) == m_id) - m_pLevel->setTile(tilePos, TILE_AIR); - - if (!m_onGround) + if (m_pLevel->getTile(tilePos) == m_tileId) { - if (field_E0 > 100 && !m_pLevel->m_bIsMultiplayer) - remove(); - - return; + m_pLevel->removeTile(tilePos); + LOG_I("%d: Removed fell tile", m_pLevel->getTime()); } - m_vel.x *= 0.7f; - m_vel.z *= 0.7f; - m_vel.y *= -0.5f; - remove(); - if (m_pLevel->mayPlace(m_id, tilePos, true)) + if (m_onGround) { - m_pLevel->setTile(tilePos, m_id); + m_vel.x *= 0.7f; + m_vel.z *= 0.7f; + m_vel.y *= -0.5f; + remove(); + if ((!m_pLevel->mayPlace(m_tileId, tilePos, true) || !m_pLevel->setTileAndData(tilePos, m_tileId, m_tileData)) && !m_pLevel->m_bIsMultiplayer) + { + // Spawn resources + spawnAtLocation(m_tileId, 1); + } } - else + else if (m_time > 100 && !m_pLevel->m_bIsMultiplayer) { - // @TODO: spawn resources? + // Spawn resources + spawnAtLocation(m_tileId, 1); + remove(); } } diff --git a/source/world/entity/FallingTile.hpp b/source/world/entity/FallingTile.hpp index 5ba75e41a..f601a5077 100644 --- a/source/world/entity/FallingTile.hpp +++ b/source/world/entity/FallingTile.hpp @@ -12,9 +12,12 @@ class FallingTile : public Entity { +private: + void _init(TileID tileId = TILE_AIR, int tileData = 0); + void _init(const Vec3& pos, TileID tileId, int tileData); public: - FallingTile(Level*); - FallingTile(Level*, const Vec3& pos, int id); + FallingTile(Level* level) : Entity(level) { _init(); } + FallingTile(Level* level, const Vec3& pos, TileID tileId, int tileData = 0) : Entity(level) { _init(pos, tileId, tileData); }; float getShadowHeightOffs() const override; bool isPickable() const override; @@ -23,7 +26,8 @@ class FallingTile : public Entity Level* getLevel(); public: - int m_id; - int field_E0; + TileID m_tileId; + int m_tileData; + int m_time; }; diff --git a/source/world/entity/ItemEntity.cpp b/source/world/entity/ItemEntity.cpp index 9dfa8b7cd..2eabccd4b 100644 --- a/source/world/entity/ItemEntity.cpp +++ b/source/world/entity/ItemEntity.cpp @@ -12,7 +12,7 @@ void ItemEntity::_init(const ItemInstance* itemInstance) { field_E0 = 0; - field_E4 = 0; + m_throwTime = 0; field_EC = 0; m_health = 5; m_bMakeStepSound = false; @@ -65,15 +65,17 @@ bool ItemEntity::isInWater() void ItemEntity::playerTouch(Player* player) { // Here, this would give the item to the player, and remove the item entity. - if (field_E4 != 0) + if (m_throwTime != 0) return; Inventory* pInventory = player->m_pInventory; pInventory->addItem(&m_itemInstance); - m_pLevel->playSound(this, "random.pop", 0.3f, - (((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f) + 1.0f) + (((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f) + 1.0f)); + m_pLevel->playSound(this, "random.pop", 0.2f, + (((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f) + 1.0f) * 2.0f); + + player->take(this, m_itemInstance.m_count); if (m_itemInstance.m_count <= 0) remove(); @@ -83,8 +85,8 @@ void ItemEntity::tick() { Entity::tick(); - if (field_E4 > 0) - field_E4--; + if (m_throwTime > 0) + m_throwTime--; m_oPos = m_pos; m_vel.y -= 0.04f; diff --git a/source/world/entity/ItemEntity.hpp b/source/world/entity/ItemEntity.hpp index e05d91fb2..3ccfbf621 100644 --- a/source/world/entity/ItemEntity.hpp +++ b/source/world/entity/ItemEntity.hpp @@ -37,7 +37,7 @@ class ItemEntity : public Entity #endif int field_E0; - int field_E4; + int m_throwTime; float field_E8; int field_EC; int m_health; diff --git a/source/world/entity/LocalPlayer.cpp b/source/world/entity/LocalPlayer.cpp index 434adff13..cf57de039 100644 --- a/source/world/entity/LocalPlayer.cpp +++ b/source/world/entity/LocalPlayer.cpp @@ -87,6 +87,11 @@ bool LocalPlayer::isImmobile() const return Player::isImmobile() || (m_pMinecraft->useController() && m_pMinecraft->m_pScreen); //!m_pMinecraft->m_bGrabbedMouse; // this works if we still set this when not using a mouse } +void LocalPlayer::take(Entity* pEnt, int orgCount) +{ + //m_pMinecraft->m_pParticleEngine->add(new TakeAnimationParticle(m_pLevel, pEnt, this, -0.5f)); +} + void LocalPlayer::animateRespawn() { diff --git a/source/world/entity/LocalPlayer.hpp b/source/world/entity/LocalPlayer.hpp index e2a59af71..15781a75c 100644 --- a/source/world/entity/LocalPlayer.hpp +++ b/source/world/entity/LocalPlayer.hpp @@ -30,6 +30,7 @@ class LocalPlayer : public Player virtual bool isLocalPlayer() const override { return true; } virtual void drop(const ItemInstance* pItemInstance, bool b = false) override; virtual bool isImmobile() const override; + virtual void take(Entity* pEnt, int orgCount); void calculateFlight(const Vec3& pos); void closeContainer(); //@HUH: oddly enough not a virtual/override diff --git a/source/world/entity/Mob.cpp b/source/world/entity/Mob.cpp index 55d791fc2..7f8f1d3f0 100644 --- a/source/world/entity/Mob.cpp +++ b/source/world/entity/Mob.cpp @@ -12,14 +12,14 @@ Mob::Mob(Level* pLevel) : Entity(pLevel) { - field_DC = 10; + m_invulnerableDuration = 10; field_E8 = 0.0f; field_EC = 0.0f; field_F0 = 0; m_oAttackAnim = 0.0f; m_attackAnim = 0.0f; m_health = 10; - field_100 = 20; + m_lastHealth = 20; m_hurtTime = 0; m_hurtDuration = 0; m_hurtDir = 0.0f; @@ -30,7 +30,7 @@ Mob::Mob(Level* pLevel) : Entity(pLevel) field_120 = 0; field_124 = 0; field_128 = 0.0f; - field_12C = 0.0f; + m_walkAnimSpeed = 0.0f; field_130 = 0.0f; m_noActionTime = 0; field_B00 = Vec2::ZERO; @@ -51,16 +51,17 @@ Mob::Mob(Level* pLevel) : Entity(pLevel) m_lSteps = 0; m_lPos = Vec3::ZERO; m_lRot = Vec2::ZERO; - field_B84 = 0; + m_lastHurt = 0; m_pEntLookedAt = nullptr; m_bSwinging = false; m_swingTime = 0; + m_ambientSoundTime = 0; m_texture = "/mob/pig.png"; m_class = ""; - m_bBlocksBuilding = true; - + m_bBlocksBuilding = true; + field_E4 = (Mth::random() + 1.0f) * 0.01f; setPos(m_pos); field_E0 = Mth::random() * 12398.0f; @@ -227,9 +228,21 @@ void Mob::baseTick() m_oAttackAnim = m_attackAnim; Entity::baseTick(); + if (m_random.nextInt(1000) < m_ambientSoundTime++) + { + playAmbientSound(); + } + if (isAlive() && isInWall()) hurt(nullptr, 1); + // Java + /*if (m_bFireImmune || m_pLevel->m_bIsMultiplayer) + { + m_fireTicks = 0; + }*/ + + if (isAlive() && isUnderLiquid(Material::water) && !isWaterMob()) { m_airCapacity--; @@ -261,7 +274,7 @@ void Mob::baseTick() if (field_114 > 0) field_114--; if (m_hurtTime > 0) m_hurtTime--; - if (field_B8 > 0) field_B8--; + if (m_invulnerableTime > 0) m_invulnerableTime--; if (m_health <= 0) { @@ -311,17 +324,31 @@ bool Mob::hurt(Entity *pAttacker, int damage) if (m_health <= 0) return false; - field_12C = 1.5f; - if (float(field_B8) <= float(field_DC) * 0.5f) + m_walkAnimSpeed = 1.5f; + bool var3 = true; + if (float(m_invulnerableTime) > float(m_invulnerableDuration) / 2.0f) { - field_100 = m_health; - field_B8 = field_DC; - field_B84 = damage; + if (damage <= m_lastHurt) + return false; + + actuallyHurt(damage - m_lastHurt); + m_lastHurt = damage; + var3 = false; + } + else + { + m_lastHurt = damage; + m_lastHealth = m_health; + m_invulnerableTime = m_invulnerableDuration; actuallyHurt(damage); - m_hurtDuration = 10; - m_hurtTime = 10; + m_hurtTime = m_hurtDuration = 10; + } - // not in 0.1 + m_hurtDir = 0.0f; + // not in 0.1 + if (var3) + { + //m_pLevel->broadcastEntityEvent(this, 2); // Java markHurt(); if (pAttacker) @@ -341,18 +368,21 @@ bool Mob::hurt(Entity *pAttacker, int damage) knockback(pAttacker, damage, xd, zd); } } - else + + if (m_health <= 0) { - if (field_B84 >= damage) - return 0; + if (var3) + { + m_pLevel->playSound(this, getDeathSound(), getSoundVolume(), (m_random.nextFloat() - m_random.nextFloat()) * 0.2f + 1.0f); + } - actuallyHurt(damage - field_B84); - field_B84 = damage; + die(pAttacker); + } + else if (var3) + { + m_pLevel->playSound(this, getHurtSound(), getSoundVolume(), (m_random.nextFloat() - m_random.nextFloat()) * 0.2f + 1.0f); } - m_hurtDir = 0; - if (m_health <= 0) - die(pAttacker); return true; } @@ -432,7 +462,12 @@ std::string Mob::getTexture() const void Mob::playAmbientSound() { - + m_ambientSoundTime = -getAmbientSoundInterval(); + std::string sound = getAmbientSound(); + if (sound != "") + { + m_pLevel->playSound(this, sound, getSoundVolume(), (m_random.nextFloat() - m_random.nextFloat()) * 0.2f + 1.0f); + } } int Mob::getAmbientSoundInterval() const @@ -449,7 +484,7 @@ void Mob::heal(int health) if (m_health > C_MAX_MOB_HEALTH) m_health = C_MAX_MOB_HEALTH; - field_B8 = field_DC / 2; + m_invulnerableTime = m_invulnerableDuration / 2; } HitResult Mob::pick(float f1, float f2) @@ -575,7 +610,7 @@ bool Mob::canSee(Entity* pEnt) const void Mob::updateWalkAnim() { - field_128 = field_12C; + field_128 = m_walkAnimSpeed; float diffX = m_pos.x - m_oPos.x; float diffZ = m_pos.z - m_oPos.z; @@ -584,8 +619,8 @@ void Mob::updateWalkAnim() if (spd > 1.0f) spd = 1.0f; - field_12C += (spd - field_12C) * 0.4f; - field_130 += field_12C; + m_walkAnimSpeed += (spd - m_walkAnimSpeed) * 0.4f; + field_130 += m_walkAnimSpeed; } void Mob::aiStep() diff --git a/source/world/entity/Mob.hpp b/source/world/entity/Mob.hpp index 63568fc1d..600294363 100644 --- a/source/world/entity/Mob.hpp +++ b/source/world/entity/Mob.hpp @@ -84,8 +84,11 @@ class Mob : public Entity float rotlerp(float, float, float); void updateAttackAnim(); +private: + int m_ambientSoundTime; + public: - int field_DC; + int m_invulnerableDuration; float field_E0; float field_E4; float field_E8; @@ -94,7 +97,7 @@ class Mob : public Entity float m_oAttackAnim; float m_attackAnim; int m_health; - int field_100; + int m_lastHealth; int m_hurtTime; int m_hurtDuration; float m_hurtDir; @@ -105,7 +108,7 @@ class Mob : public Entity int field_120; int field_124; float field_128; - float field_12C; + float m_walkAnimSpeed; float field_130; Random m_random; int m_noActionTime; @@ -129,7 +132,7 @@ class Mob : public Entity int m_lSteps; Vec3 m_lPos; Vec2 m_lRot; - int field_B84; + int m_lastHurt; Entity* m_pEntLookedAt; float v020_field_104; diff --git a/source/world/entity/MobFactory.cpp b/source/world/entity/MobFactory.cpp index 01b232ddf..3c034e73b 100644 --- a/source/world/entity/MobFactory.cpp +++ b/source/world/entity/MobFactory.cpp @@ -3,6 +3,7 @@ #include "Cow.hpp" #include "Pig.hpp" #include "Sheep.hpp" +#include "PrimedTnt.hpp" //#include "Zombie.hpp" #include "Creeper.hpp" //#include "Skeleton.hpp" @@ -13,6 +14,7 @@ ENT(COW, Cow) \ ENT(PIG, Pig) \ ENT(SHEEP, Sheep) \ + ENT(PRIMED_TNT, PrimedTnt) \ //ENT(ZOMBIE, Zombie) \ //ENT(CREEPER, Creeper) \ //ENT(SKELETON, Skeleton) \ @@ -21,7 +23,7 @@ #define ENT(enumType, classType) case EntityType::enumType: return new classType(level); -Mob* MobFactory::CreateMob(EntityType::ID entityType, Level *level) +Entity* MobFactory::CreateMob(EntityType::ID entityType, Level *level) { switch (entityType) { diff --git a/source/world/entity/MobFactory.hpp b/source/world/entity/MobFactory.hpp index 0a9a078aa..a1cbd6195 100644 --- a/source/world/entity/MobFactory.hpp +++ b/source/world/entity/MobFactory.hpp @@ -6,5 +6,5 @@ class MobFactory { public: - static Mob* CreateMob(EntityType::ID entityType, Level *level); + static Entity* CreateMob(EntityType::ID entityType, Level *level); }; \ No newline at end of file diff --git a/source/world/entity/Player.cpp b/source/world/entity/Player.cpp index 937b83b53..7b272fa96 100644 --- a/source/world/entity/Player.cpp +++ b/source/world/entity/Player.cpp @@ -251,7 +251,7 @@ void Player::drop(const ItemInstance* pItemInstance, bool b) return; ItemEntity* pItemEntity = new ItemEntity(m_pLevel, Vec3(m_pos.x, m_pos.y - 0.3f + getHeadHeight(), m_pos.z), pItemInstance); - pItemEntity->field_E4 = 40; + pItemEntity->m_throwTime = 40; if (b) { @@ -346,7 +346,7 @@ void Player::stopDestroying() m_destroyingBlock = false; } -void Player::take(Entity* pEnt, int x) +void Player::take(Entity* pEnt, int orgCount) { } diff --git a/source/world/entity/Player.hpp b/source/world/entity/Player.hpp index eea58dbcc..f0d145f64 100644 --- a/source/world/entity/Player.hpp +++ b/source/world/entity/Player.hpp @@ -46,6 +46,7 @@ class Player : public Mob virtual void startDestroying(); virtual void stopDestroying(); virtual bool isLocalPlayer() const { return false; } + virtual void take(Entity* pEnt, int orgCount); int addResource(int); void animateRespawn(Player*, Level*); @@ -65,7 +66,6 @@ class Player : public Mob void setDefaultHeadHeight(); void setRespawnPos(const TilePos& pos); - void take(Entity* pEnt, int x); void touch(Entity* pEnt); GameType getPlayerGameType() const { return _playerGameType; } void setPlayerGameType(GameType playerGameType) { _playerGameType = playerGameType; } diff --git a/source/world/entity/PrimedTnt.cpp b/source/world/entity/PrimedTnt.cpp index fc2321cab..cd58ec74b 100644 --- a/source/world/entity/PrimedTnt.cpp +++ b/source/world/entity/PrimedTnt.cpp @@ -11,9 +11,11 @@ void PrimedTnt::_init() { - m_fuseTimer = 0; + m_pDescriptor = &EntityTypeDescriptor::primedTnt; + + m_fuseTimer = 80; // 4 secs field_C8 = RENDER_TNT; - m_bBlocksBuilding = true; + m_bBlocksBuilding = true; setSize(0.98f, 0.98f); m_heightOffset = m_bbHeight * 0.5f; m_bMakeStepSound = false; @@ -31,8 +33,6 @@ PrimedTnt::PrimedTnt(Level* level, const Vec3& pos) : Entity(level) m_vel.y = 0.2f; m_oPos = m_pos; - - m_fuseTimer = 80; // 4 secs } void PrimedTnt::explode() diff --git a/source/world/entity/Rocket.cpp b/source/world/entity/Rocket.cpp index b5b8ccad0..c5f2761c8 100644 --- a/source/world/entity/Rocket.cpp +++ b/source/world/entity/Rocket.cpp @@ -16,7 +16,7 @@ Rocket::Rocket(Level* level, const Vec3& pos) : Entity(level) field_B90 = 80; field_C8 = RENDER_ROCKET; - m_bBlocksBuilding = true; + m_bBlocksBuilding = true; setSize(0.1f, 1.0f); m_heightOffset = m_bbHeight * 0.5f - 0.25f; diff --git a/source/world/entity/TripodCamera.cpp b/source/world/entity/TripodCamera.cpp index df00627d9..f00cc310f 100644 --- a/source/world/entity/TripodCamera.cpp +++ b/source/world/entity/TripodCamera.cpp @@ -21,7 +21,7 @@ TripodCamera::TripodCamera(Level* level, Player* player, const Vec3& pos) : Mob( m_rotPrev = m_rot = player->m_rot; - m_bBlocksBuilding = true; + m_bBlocksBuilding = true; setSize(1.0f, 1.5f); m_heightOffset = m_bbHeight * 0.5f - 0.25f; diff --git a/source/world/level/Level.cpp b/source/world/level/Level.cpp index 2e21dc644..12fe84f16 100644 --- a/source/world/level/Level.cpp +++ b/source/world/level/Level.cpp @@ -1267,7 +1267,7 @@ bool Level::isUnobstructed(AABB* aabb) const { Entity* pEnt = *it; if (!pEnt->m_bRemoved && pEnt->m_bBlocksBuilding) - return false; + return false; } return true; @@ -1520,7 +1520,7 @@ HitResult Level::clip(Vec3 v1, Vec3 v2, bool flag) const if (xd != 999.0f) xe = (float)(xd - v1.x) / xl; if (yd != 999.0f) ye = (float)(yd - v1.y) / yl; if (zd != 999.0f) ze = (float)(zd - v1.z) / zl; - int hitSide = 0; + Facing::Name hitSide = Facing::DOWN; if (xe >= ye || xe >= ze) { if (ye >= ze) @@ -1647,12 +1647,12 @@ void Level::playSound(Entity* entity, const std::string& name, float volume, flo } } -void Level::playSound(const Vec3& pos, const std::string& name, float a, float b) +void Level::playSound(const Vec3& pos, const std::string& name, float volume, float pitch) { for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) { LevelListener* pListener = *it; - pListener->playSound(name, pos, a, b); + pListener->playSound(name, pos, volume, pitch); } } @@ -1750,7 +1750,10 @@ bool Level::extinguishFire(Player* player, const TilePos& pos, Facing::Name face TilePos p(pos.relative(face)); if (getTile(p) == Tile::fire->m_ID) + { + playSound(pos + 0.5f, "random.fizz", 0.5f, 2.6f + (m_random.nextFloat() - m_random.nextFloat()) * 0.8f); return setTile(p, TILE_AIR); + } return false; } diff --git a/source/world/level/Level.hpp b/source/world/level/Level.hpp index 53c0babb1..b87d3d9b8 100644 --- a/source/world/level/Level.hpp +++ b/source/world/level/Level.hpp @@ -84,14 +84,15 @@ class Level : public LevelSource void updateLight(const LightLayer&, const TilePos& tilePos1, const TilePos& tilePos2); void updateLight(const LightLayer&, const TilePos& tilePos1, const TilePos& tilePos2, bool); void updateLightIfOtherThan(const LightLayer&, const TilePos& pos, int); - bool setTileAndDataNoUpdate(const TilePos& pos, TileID tile, int data); + bool setTile(const TilePos& pos, TileID tile); bool setTileNoUpdate(const TilePos& pos, TileID tile); - bool setDataNoUpdate(const TilePos& pos, int data); bool setTileAndData(const TilePos& pos, TileID tile, int data); - bool setTile(const TilePos& pos, TileID tile); + bool setTileAndDataNoUpdate(const TilePos& pos, TileID tile, int data); bool setData(const TilePos& pos, int data); + bool setDataNoUpdate(const TilePos& pos, int data); void sendTileUpdated(const TilePos& pos); void tileUpdated(const TilePos& pos, TileID tile); + bool removeTile(const TilePos& pos) { return setTileAndData(pos, TILE_AIR, 0); } void updateNeighborsAt(const TilePos& pos, TileID tile); void neighborChanged(const TilePos& pos, TileID tile); void setTilesDirty(const TilePos& min, const TilePos& max); diff --git a/source/world/level/TilePos.hpp b/source/world/level/TilePos.hpp index fc39776cf..4ebc4dfa7 100644 --- a/source/world/level/TilePos.hpp +++ b/source/world/level/TilePos.hpp @@ -15,7 +15,7 @@ struct ChunkPos; struct TilePos { int x; - uint8_t y; // 255 height limit + int y; // adding 1 to 255 (height limit) means we underflow back to 0 if this is a uint8_t int z; private: diff --git a/source/world/tile/FireTile.cpp b/source/world/tile/FireTile.cpp index e94f5b8a4..7e35ff6ec 100644 --- a/source/world/tile/FireTile.cpp +++ b/source/world/tile/FireTile.cpp @@ -68,6 +68,11 @@ int FireTile::getTickDelay() const void FireTile::animateTick(Level* level, const TilePos& pos, Random* random) { + if (random->nextInt(24) == 0) + { + level->playSound(pos + 0.5f, "fire.fire", 1.0f + random->nextFloat(), (random->nextFloat() * 0.7f) + 0.3f); + } + // @TODO: Mark Tile::fire as FireTile* instead of Tile* FireTile* pFireTile = (FireTile*)Tile::fire; if (level->isSolidTile(pos.below()) || pFireTile->canBurn(level, pos.below())) diff --git a/source/world/tile/SandTile.cpp b/source/world/tile/SandTile.cpp index ad43e4f74..2d8b38115 100644 --- a/source/world/tile/SandTile.cpp +++ b/source/world/tile/SandTile.cpp @@ -23,7 +23,7 @@ SandTile::SandTile(int ID, int texture, Material* pMtl) : Tile(ID, texture, pMtl int SandTile::getTickDelay() const { - return 3; + return 3; // 3 on Java, 2 on PE, no idea why } void SandTile::checkSlide(Level* level, const TilePos& pos) @@ -34,10 +34,10 @@ void SandTile::checkSlide(Level* level, const TilePos& pos) // standing on something, don't fall return; - if (pos.y <= 0) + if (pos.y < 0) return; - if (SandTile::instaFall || !level->hasChunksAt(TilePos(pos.x - 32, pos.y - 32, pos.z - 32), TilePos(pos.x + 32, pos.y + 32, pos.z + 32))) + if (SandTile::instaFall || !level->hasChunksAt(pos, 32)) { level->setTile(pos, 0); @@ -56,7 +56,11 @@ void SandTile::checkSlide(Level* level, const TilePos& pos) // The original code attempts to spawn a falling tile entity, but it fails since it's not a player. // The falling sand tile #if defined(ORIGINAL_CODE) || defined(ENH_ALLOW_SAND_GRAVITY) - level->addEntity(new FallingTile(level, Vec3(float(pos.x) + 0.5f, float(pos.y) + 0.5f, float(pos.z) + 0.5f), m_ID)); + bool isEmpty = level->isEmptyTile(pos); // from 0.7.0 in HeavyTile + Entity* fallingTile = new FallingTile(level, Vec3(pos) + 0.5f, m_ID, isEmpty); + //setTicking(true); // from 0.7.0, for HeavyTile + level->addEntity(fallingTile); + LOG_I("%d: Added FallingTile entity", level->getTime()); #endif } } @@ -81,6 +85,7 @@ bool SandTile::isFree(Level* level, const TilePos& pos) void SandTile::tick(Level* level, const TilePos& pos, Random* random) { + // Specific to PE if (level->m_bIsMultiplayer) return; diff --git a/source/world/tile/SandTile.hpp b/source/world/tile/SandTile.hpp index 5cd77f508..00dce7313 100644 --- a/source/world/tile/SandTile.hpp +++ b/source/world/tile/SandTile.hpp @@ -10,6 +10,7 @@ #include "Tile.hpp" +// @TODO: Abstract out into HeavyTile, then have GravelTile inherit class SandTile : public Tile { public: diff --git a/source/world/tile/Tile.cpp b/source/world/tile/Tile.cpp index ba590e2fd..233420d81 100644 --- a/source/world/tile/Tile.cpp +++ b/source/world/tile/Tile.cpp @@ -1059,7 +1059,7 @@ void Tile::spawnResources(Level* pLevel, const TilePos& pos, int data, float fCh ItemInstance inst(id, 1, getSpawnResourcesAuxValue(data)); ItemEntity* pEntity = new ItemEntity(pLevel, Vec3(pos) + o, &inst); - pEntity->field_E4 = 10; + pEntity->m_throwTime = 10; pLevel->addEntity(pEntity); } diff --git a/source/world/tile/TntTile.cpp b/source/world/tile/TntTile.cpp index 48016e5c0..16389d989 100644 --- a/source/world/tile/TntTile.cpp +++ b/source/world/tile/TntTile.cpp @@ -44,7 +44,12 @@ void TntTile::destroy(Level* level, const TilePos& pos, int data) void TntTile::wasExploded(Level* level, const TilePos& pos) { PrimedTnt* tnt = new PrimedTnt(level, Vec3(pos) + 0.5f); - tnt->m_fuseTimer = level->m_random.nextInt(tnt->m_fuseTimer / 4) + tnt->m_fuseTimer / 8; + + unsigned int timer = tnt->m_fuseTimer; + if (timer < 4) + timer = 4; + + tnt->m_fuseTimer = level->m_random.nextInt(timer / 4) + timer / 8; level->addEntity(tnt); } diff --git a/thirdparty/GL/GL.hpp b/thirdparty/GL/GL.hpp index bfe1cf645..46fe44b6f 100644 --- a/thirdparty/GL/GL.hpp +++ b/thirdparty/GL/GL.hpp @@ -137,7 +137,7 @@ void xglDrawArrays(GLenum mode, GLint first, GLsizei count); #endif -#if defined(_WIN32) && !defined(USE_SDL) +#if defined(_WIN32) && !defined(USE_GLES1_COMPATIBILITY_LAYER) // Win32 defines xglOrthof as a regular function #elif defined USE_GL_ORTHO_F #define xglOrthof glOrthof diff --git a/thirdparty/SDL2/SDL2.h b/thirdparty/SDL2/SDL2.h index 04de4d961..3d2518b96 100644 --- a/thirdparty/SDL2/SDL2.h +++ b/thirdparty/SDL2/SDL2.h @@ -3,6 +3,7 @@ #ifdef _WIN32 #pragma comment(lib, "SDL2.lib") #include +#include #else #include #endif \ No newline at end of file diff --git a/thirdparty/raknet/CMakeLists.txt b/thirdparty/raknet/CMakeLists.txt index 99465983b..3fac7eb43 100644 --- a/thirdparty/raknet/CMakeLists.txt +++ b/thirdparty/raknet/CMakeLists.txt @@ -115,3 +115,12 @@ add_library(raknet STATIC RakSleep.cpp ) target_include_directories(raknet PUBLIC .) + +# Windows Support +if(WIN32) + target_compile_definitions(raknet + PUBLIC SHA1_HAS_TCHAR + PUBLIC LOCKLESS_TYPES_USE_MUTEX + ) + target_link_libraries(raknet ws2_32) +endif() \ No newline at end of file diff --git a/thirdparty/raknet/WindowsIncludes.h b/thirdparty/raknet/WindowsIncludes.h index 9ec686837..969d9aeb5 100644 --- a/thirdparty/raknet/WindowsIncludes.h +++ b/thirdparty/raknet/WindowsIncludes.h @@ -16,9 +16,9 @@ #include #elif defined (_WIN32) && !defined(WINDOWS_PHONE_8) && !defined(WINDOWS_STORE_RT) #define _WINPC -#include +#include #include -#include +#include // Must always include Winsock2.h before windows.h // or else: diff --git a/thirdparty/stb_image/CMakeLists.txt b/thirdparty/stb_image/CMakeLists.txt index 0e11124b8..4efda7ab7 100644 --- a/thirdparty/stb_image/CMakeLists.txt +++ b/thirdparty/stb_image/CMakeLists.txt @@ -2,5 +2,5 @@ cmake_minimum_required(VERSION 3.16.0) project(stb_image) # Build -add_library(stb_image STATIC src/stb_image_impl.c) +add_library(stb_image STATIC src/stb_image_impl.c include/stb_vorbis.c) target_include_directories(stb_image PUBLIC include) diff --git a/tools/extract_apk.py b/tools/extract_apk.py new file mode 100755 index 000000000..21f8c8764 --- /dev/null +++ b/tools/extract_apk.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +import setup_venv + +import grabsounds +import sys +import zipfile +import os + +# Constants +TITLE = 'APK Extractor' +ASSETS_DIR = 'assets/' +SOUND_DATA_FILE = 'libminecraftpe.so' + +# Determine Mode +use_gui = len(sys.argv) < 2 +if use_gui: + # Setup GUI + import tkinter as tk + from tkinter import filedialog, messagebox + root = tk.Tk() + root.withdraw() + +# Show Information +def info(msg): + print(msg) + if use_gui: + messagebox.showinfo(title=TITLE, message=msg) + +# Extract Sounds +def extract_sounds(apk_zip): + # Search For File + for name in apk_zip.namelist(): + if os.path.basename(name) == SOUND_DATA_FILE: + with apk_zip.open(name) as sound_data: + grabsounds.main(sound_data) + return + raise Exception('Unable to find sound data!') + +# Extract Assets +def extract_assets(apk_zip): + assets = os.path.dirname(os.path.abspath(__file__)) + assets = os.path.join(assets, '..', 'game', 'assets') + # Search For Assets + for name in apk_zip.namelist(): + if name.startswith(ASSETS_DIR): + # Found Asset + short_name = name[len(ASSETS_DIR):] + print(f'Extracting Asset {short_name}...') + out = os.path.join(assets, short_name) + os.makedirs(os.path.dirname(out), exist_ok=True) + # Extract + with open(out, 'wb') as file: + file.write(apk_zip.read(name)) + +# Open APK +def open_apk(): + if use_gui: + out = filedialog.askopenfile('rb', title=TITLE, filetypes=[('APK', '*.apk')]) + if out is None: + sys.exit() + return out + else: + return open(sys.argv[1], 'rb') + +# Main +def main(): + with open_apk() as apk: + # Extract + with zipfile.ZipFile(apk) as apk_zip: + extract_sounds(apk_zip) + extract_assets(apk_zip) + # Done + info('Done!') + +# Handle Errors +try: + main() +except Exception as e: + if use_gui: + info('An error has occurred!') + raise diff --git a/tools/grabsounds.py b/tools/grabsounds.py index 42bacb235..9040bc8fc 100755 --- a/tools/grabsounds.py +++ b/tools/grabsounds.py @@ -1,155 +1,36 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 +import setup_venv -# Minecraft PE Reverse Engineering Project -# Copyright (C) 2023 iProgramInCpp -# ----------------------------------------------- -# This tool grabs the sound data from the .so file from the source Minecraft PE -# Android *.so file. Offsets are hardcoded to that version, nothing else will work. -# -# TODO: Lookup ELF symbols to un-hardcode the offsets? +import lief import sys import os -import hashlib -# use memory efficient range always -merange = range -try: - merange = xrange # python 2 -except NameError: - pass - -# defines -pcm_addresses = [ - ('PCM_cloth1', 0x00112B08), - ('PCM_cloth2', 0x00117134), - ('PCM_cloth3', 0x0011B760), - ('PCM_cloth4', 0x0011FD8C), - ('PCM_grass1', 0x001243B8), - ('PCM_grass2', 0x0012F00C), - ('PCM_grass3', 0x00139C60), - ('PCM_grass4', 0x001448B4), - ('PCM_gravel1', 0x0014F508), - ('PCM_gravel2', 0x0015A15C), - ('PCM_gravel3', 0x00164DB0), - ('PCM_gravel4', 0x0016FA04), - ('PCM_sand1', 0x0017A658), - ('PCM_sand2', 0x00181214), - ('PCM_sand3', 0x00187DD0), - ('PCM_sand4', 0x0018E98C), - ('PCM_stone1', 0x00195548), - ('PCM_stone2', 0x001A019C), - ('PCM_stone3', 0x001AADF0), - ('PCM_stone4', 0x001B5A44), - ('PCM_wood1', 0x001C0698), - ('PCM_wood2', 0x001CB2EC), - ('PCM_wood3', 0x001D5F40), - ('PCM_wood4', 0x001E0B94), - ('PCM_click', 0x001EB7E8), - ('PCM_explode', 0x001F78A8), - ('PCM_splash', 0x00209A38) -] - -so_file_sha256 = '157af341d13a54cc935bbe24c5e1cf3d02d7e40ec20f9859b9853c2e996ebd81' - -header_1 = '// Minecraft Pocket Edition Reverse Engineering Project\n// Copyright (C) 2011 Mojang Specifications.\n' -header_2 = '// Data extracted from libminecraftpe.so (Minecraft PE v0.1.3.apk).\n\n' - -def read_int_from_bytes(arr_bytes, offset): - return arr_bytes[offset] | arr_bytes[offset + 1] << 8 | arr_bytes[offset + 2] << 16 | arr_bytes[offset + 3] << 24 - -def read_short_from_bytes(arr_bytes, offset): - return arr_bytes[offset] | arr_bytes[offset + 1] << 8 - -def format_hex_short(short): - return "{:04x}".format(short) - -def main(): - if len(sys.argv) < 2: - print('Usage:', sys.argv[0], '[libminecraftpe.so] (output dir)') - return - - output_dir = '' - - if len(sys.argv) > 2: - output_dir = sys.argv[2] - - if len(output_dir) == 0: - output_dir = './sound_data/' - - # append a slash to the file name, if it doesn't have one already - if output_dir[len(output_dir) - 1] != '/': - output_dir += '/' - - if not os.path.exists(output_dir): - os.makedirs(output_dir) - - bytes = [] - - # open the file - try: - with open(sys.argv[1],mode='rb') as sofile: - # read all bytes - bytes = sofile.read() - - except FileNotFoundError: - print('ERROR: The file', sys.argv[1], 'was not found.') - return - - # first off, hash the file to ensure it matches - src_sha256 = hashlib.sha256(bytes).hexdigest() - - print('* Source file hash: ', src_sha256) - - if src_sha256 != so_file_sha256: - print('ERROR: Source file does not match the Source APK\'s SO file. Please extract one from the aforementioned APK. See the readme for more details.') - return - - print('* Extracting PCM data...') - - include_all_str = '#pragma once\n\n' + header_1 - include_all_str+= '\n// @NOTE: This is meant to be included in exactly 1 compile object/source file.\n\n' + header_2 - - for item in pcm_addresses: - include_all_str += '#include "' + item[0] + '.h"\n' - ostr = header_1 + header_2 - - channels = read_int_from_bytes(bytes, item[1] + 0) - data_length = read_int_from_bytes(bytes, item[1] + 12) - - # @NOTE: All the PCM sound data is in `.data`. So there's no consts to be found. - - ostr += 'PCMSoundHeader '+item[0]+' =\n{\n' - ostr += '\t' + str(channels) + ',\n' - ostr += '\t' + str(read_int_from_bytes(bytes, item[1] + 4)) + ',\n' - ostr += '\t' + str(read_int_from_bytes(bytes, item[1] + 8)) + ',\n' - ostr += '\t' + str(data_length) - ostr += '\n};\n\n' - - data_length *= channels - - ostr += 'uint16_t '+item[0]+'_data['+str(data_length)+'] =\n{' - - for i in merange(data_length): - if i % 16 == 0: - ostr += '\n\t' - ostr += '0x'+format_hex_short(read_short_from_bytes(bytes, item[1] + 16 + i * 2)) + ',' - - ostr += '\n};\n' - - filename = output_dir + item[0] + '.h' - with open(filename, 'w') as of: - of.write(ostr) - - include_all_str += '\n\n' - - for item in pcm_addresses: - include_all_str += 'SoundDesc SA_' + item[0][4:] + '(' + item[0] + ', ' + item[0] + '_data);\n' - - with open(output_dir + 'sounds.h', 'w') as of: - of.write(include_all_str) - - pass - - +# Main Function +def main(file): + # Output Directory + out = os.path.dirname(os.path.abspath(__file__)) + out = os.path.join(out, '..', 'game', 'assets', 'sound') + os.makedirs(out, exist_ok=True) + # Extract Sound Data + elf = lief.parse(file) + prefix = 'PCM_' + for sym in elf.dynamic_symbols: + if sym.name.startswith('PCM_'): + # Found Sound Symbol, Extract It + name = sym.name[len(prefix):] + print(f'Extracting Sound {name}...') + path = os.path.join(out, name + '.pcm') + data = bytes(elf.get_content_from_virtual_address(sym.value, sym.size)) + with open(path, 'wb') as file: + file.write(data) + +# Entrypoint if __name__ == '__main__': - main() + # Check Arguments + if len(sys.argv) < 2: + print(f'USAGE: {__file__} libminecraftpe.so') + sys.exit() + # Run + main(sys.argv[1]) + # Done + print('Done!') diff --git a/tools/setup_venv.py b/tools/setup_venv.py new file mode 100644 index 000000000..ae6010bfc --- /dev/null +++ b/tools/setup_venv.py @@ -0,0 +1,44 @@ +import os +import venv +import sys +import subprocess +import platform + +# Find Binary Directory +bin_dir = 'bin' +if platform.system() == 'Windows': + bin_dir = 'Scripts' + +# Paths +path = os.path.dirname(os.path.abspath(__file__)) +path = os.path.join(path, 'venv') +valid_file = os.path.join(path, '.valid') + +# Open In Virtualenv +def restart_in_venv(path): + print('Activating Virtualenv...') + py = os.path.basename(sys.executable) + py = os.path.join(path, bin_dir, py) + os.execv(py, [py] + sys.argv) + +# Create Virtualenv +def create_venv(path): + # Check If It Already Exists + if os.path.exists(valid_file): + return + # Build Environment + print('Creating Virtualenv...') + builder = venv.EnvBuilder(clear=True, symlinks=False, with_pip=True) + builder.create(path) + # Install LIEF + pip = 'pip' + if platform.system() == 'Windows': + pip += '.exe' + subprocess.run([os.path.join(path, bin_dir, pip), 'install', 'lief']) + # Mark As Created + open(valid_file, 'wb').close() + +# Run +if not sys.executable.startswith(path): + create_venv(path) + restart_in_venv(path)