13 Commits
3124 changed files with 199201 additions and 666568 deletions
-3
View File
@@ -1,3 +0,0 @@
.github/workflows/docker-nightly.yml merge=ours
.github/workflows/nightly.yml merge=ours
docker-compose.dedicated-server.ghcr.yml merge=ours
Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 778 KiB

+107
View File
@@ -0,0 +1,107 @@
name: TU31 Release
on:
workflow_dispatch:
push:
branches:
- 'TU31'
paths:
- '**'
- '!.gitignore'
- '!*.md'
- '!.github/**'
- '.github/workflows/nightly.yml'
permissions:
contents: write
concurrency:
group: TU31
cancel-in-progress: true
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
platform: [Windows64]
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: recursive
- name: Set platform lowercase
run: echo "MATRIX_PLATFORM=$('${{ matrix.platform }}'.ToLower())" >> $env:GITHUB_ENV
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
- name: Setup CMake
uses: lukka/get-cmake@latest
- name: Run CMake
uses: lukka/run-cmake@v10
env:
VCPKG_ROOT: "" # Disable vcpkg for CI builds
with:
configurePreset: ${{ env.MATRIX_PLATFORM }}
buildPreset: ${{ env.MATRIX_PLATFORM }}-release
buildPresetAdditionalArgs: "['--target', 'Minecraft.Client']"
- name: Zip Build
run: 7z a -r LCE${{ matrix.platform }}.zip ./build/${{ env.MATRIX_PLATFORM }}/Minecraft.Client/Release/* "-x!*.ipdb" "-x!*.iobj"
- name: Stage artifacts
run: |
New-Item -ItemType Directory -Force -Path staging
Copy-Item LCE${{ matrix.platform }}.zip staging/
- name: Stage exe and pdb
if: matrix.platform == 'Windows64'
run: |
Copy-Item ./build/${{ env.MATRIX_PLATFORM }}/Minecraft.Client/Release/Minecraft.Client.exe staging/
- name: Upload artifacts
uses: actions/upload-artifact@v6
with:
name: build-${{ matrix.platform }}
path: staging/*
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v7
with:
path: artifacts
merge-multiple: true
- name: Update release
uses: andelf/nightly-release@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: TU31-Nightly
name: TU31 Nightly Client Release
body: |
Requires at least Windows 7 and DirectX 11 compatible GPU to run.
# 🚨 First time here? 🚨
If you've never downloaded the game before, you need to download `LCEWindows64.zip` and extract it to the folder where you'd like to keep the game. The other files are included in this `.zip` file!
files: |
artifacts/*
cleanup:
needs: [build, release]
if: always()
runs-on: ubuntu-latest
steps:
- name: Cleanup artifacts
uses: geekyeggo/delete-artifact@v5
with:
name: build-*
-213
View File
@@ -1,213 +0,0 @@
name: Nightly Release
on:
workflow_dispatch:
permissions:
contents: write
id-token: write
attestations: write
packages: write
concurrency:
group: nightly
cancel-in-progress: true
jobs:
build-client:
name: Build Client
runs-on: [self-hosted, windows]
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
with:
submodules: recursive
- name: Setup MSVC
uses: https://github.com/ilammy/msvc-dev-cmd@v1
- name: Setup CMake
uses: https://github.com/lukka/get-cmake@latest
- name: Run CMake
uses: https://github.com/lukka/run-cmake@v10
env:
VCPKG_ROOT: ""
with:
configurePreset: windows64
buildPreset: windows64-release
buildPresetAdditionalArgs: "['--target', 'Minecraft.Client']"
- name: Zip Build
shell: pwsh
run: |
$source = "./build/windows64/Minecraft.Client/Release"
$zip = "LCE-Online-Client-Win64.zip"
$topLevel = "LCE-Online-Client-Win64"
$files = Get-ChildItem -Path $source -Recurse -File |
Where-Object { $_.Extension -notin '.pch', '.pdb', '.zip', '.ipdb', '.iobj', '.exp', '.lib' }
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
$basePath = (Resolve-Path $source).Path
$fs = [System.IO.File]::Open($zip, [System.IO.FileMode]::Create)
try {
$archive = New-Object System.IO.Compression.ZipArchive($fs, [System.IO.Compression.ZipArchiveMode]::Create)
try {
Get-ChildItem -Path $basePath -Recurse -Directory | ForEach-Object {
$rel = $_.FullName.Substring($basePath.Length).TrimStart('\', '/')
$archive.CreateEntry("$topLevel/$($rel -replace '\\','/')/") | Out-Null
}
foreach ($file in $files) {
$rel = $file.FullName.Substring($basePath.Length).TrimStart('\', '/')
$entryName = "$topLevel/$($rel -replace '\\','/')"
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile(
$archive, $file.FullName, $entryName,
[System.IO.Compression.CompressionLevel]::Optimal
) | Out-Null
}
} finally { $archive.Dispose() }
} finally { $fs.Dispose() }
Write-Host "Created $zip"
- name: Stage artifacts
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path staging
Copy-Item LCE-Online-Client-Win64.zip staging/
Copy-Item ./build/windows64/Minecraft.Client/Release/Minecraft.Client.exe staging/
Copy-Item ./build/windows64/Minecraft.Client/Release/Minecraft.Client.pdb staging/
- name: Upload artifacts
uses: https://github.com/actions/upload-artifact@v3
with:
name: client-build
path: staging/*
release-client:
name: Release Client
needs: build-client
runs-on: [self-hosted, linux]
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Download client artifacts
uses: https://github.com/actions/download-artifact@v3
with:
name: client-build
path: artifacts
- name: Install jq
run: apt-get update && apt-get install -y --no-install-recommends jq
- name: Get short SHA
id: sha
run: echo "short=$(echo '${{ github.sha }}' | cut -c1-7)" >> "$GITHUB_OUTPUT"
- name: Delete old release and tag
env:
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="Nightly"
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
AUTH="Authorization: token $FORGEJO_TOKEN"
EXISTING_ID=$(curl -sf -H "$AUTH" "$API/releases/tags/$TAG" 2>/dev/null | jq -r '.id // empty' || true)
if [ -n "$EXISTING_ID" ]; then
curl -sf -X DELETE -H "$AUTH" "$API/releases/$EXISTING_ID"
fi
curl -s -X DELETE -H "$AUTH" "$API/tags/$TAG" > /dev/null || true
- name: Import GPG key
uses: https://github.com/crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
git_user_signingkey: true
git_tag_gpgsign: true
- name: Create signed tag
run: |
git tag -s -f Nightly -m "Nightly release ${{ steps.sha.outputs.short }}"
git push origin Nightly --force
- name: Write release notes
run: |
cat > notes.md <<'NOTES'
# Instructions:
**Newcomers:**
- If this is your first time, download `LCE-Online-Client-Win64.zip` and extract it wherever you would like to keep it.
- I would recommend to set your username prior to launch (create a file called `username.txt`, put your desired username into the file, and save).
- To play, simply run `Minecraft.Client.exe`.
**For those that wish to update their existing installation with the latest build:**
- Download `Minecraft.Client.exe` and copy it over to your existing LCE-Online-Client-Win64 build (overwrite your old version of Minecraft.Client.exe).
**For developers:**
- `Minecraft.Client.pdb` contains debug symbols for crash analysis and development. Place it next to `Minecraft.Client.exe` for stack traces to show function names and line numbers.
**Steam Deck & Linux:**
- Y'all know the drill. Download the `LCE-Online-Client-Win64.zip`, extract it, add the `Minecraft.Client.exe` as a "Non-Steam Game" within the Steam library, turn on compatibility mode with Proton Experimental, and then run it!
# Multiplayer instructions:
LAN games are natively supported, and any LAN games will appear automatically on the right. However, if you'd like to play with your friends online (and if you don't want to require them to setup a vpn, and/or if you don't want to port forward), I would recommend the following setup. Please keep in mind, you do NOT need to do this to enjoy the game. This is just how I have it setup for me so my friends can join without any hassle:
Prerequisites:
- Premium playit.gg account, costs about $3 USD per month. This is for setting up the tunnel.
- playit.gg agent installed on host PC.
How-to:
- Ensure your playit.gg agent is connected to your playit.gg account
- On the playit.gg website, setup a new tunnel (choose TCP). Ensure the configurable settings are set to the below values, assuming your agent is installed on the same computer as your LCE Online game is hosted from.
- Configurable settings:
- Local IP: `127.0.0.1`
- Local Port: `25565`
- Proxy Protocol: `None`
- After creating your tunnel, navigate to the "Tunnels" main page. You'll see the IP address and port for your tunnel. This is what your friends will input when adding your server in order to join your online game!
NOTES
- name: Create release on Forgejo
env:
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="Nightly"
TITLE="Client: ${{ steps.sha.outputs.short }}"
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
AUTH="Authorization: token $FORGEJO_TOKEN"
BODY=$(cat notes.md)
PAYLOAD=$(jq -nc --arg tag "$TAG" --arg name "$TITLE" --arg body "$BODY" \
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:false}')
RID=$(curl -sf -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d "$PAYLOAD" "$API/releases" | jq -r '.id')
if [ -z "$RID" ] || [ "$RID" = "null" ]; then
echo "Failed to create release" >&2
exit 1
fi
echo "Created release id=$RID"
for asset in artifacts/*; do
name=$(basename "$asset")
size=$(stat -c%s "$asset")
echo "Uploading $name ($size bytes)"
HTTP=$(curl -sS -w '%{http_code}' -o /tmp/upload-resp -X POST -H "$AUTH" \
-F "attachment=@$asset" \
"$API/releases/$RID/assets?name=$name")
if [ "$HTTP" -lt 200 ] || [ "$HTTP" -ge 300 ]; then
echo "Upload failed: HTTP $HTTP" >&2
echo "--- response body ---" >&2
cat /tmp/upload-resp >&2 || true
echo "" >&2
exit 1
fi
echo "Uploaded $name OK (HTTP $HTTP)"
done
+12 -15
View File
@@ -4,34 +4,31 @@ on:
workflow_dispatch:
pull_request:
types: [opened, reopened, synchronize]
paths-ignore:
- '.gitignore'
- '*.md'
- '.github/*.md'
paths:
- '**'
- '!.gitignore'
- '!*.md'
- '!.github/**'
- '.github/workflows/pull-request.yml'
jobs:
build:
runs-on: [self-hosted, windows]
runs-on: windows-latest
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
uses: actions/checkout@v6
with:
submodules: recursive
- name: Setup MSVC
uses: https://github.com/ilammy/msvc-dev-cmd@v1
uses: ilammy/msvc-dev-cmd@v1
- name: Setup CMake
uses: https://github.com/lukka/get-cmake@latest
- name: Setup .NET
uses: https://github.com/actions/setup-dotnet@v4
with:
global-json-file: global.json
uses: lukka/get-cmake@latest
- name: Run CMake
uses: https://github.com/lukka/run-cmake@v10
uses: lukka/run-cmake@v10
env:
VCPKG_ROOT: "" # Disable vcpkg for CI builds
with:
+2 -9
View File
@@ -26,7 +26,6 @@ mono_crash.*
[Rr]elease/
[Rr]eleases/
x64/
x64_*/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
@@ -416,19 +415,13 @@ tmp*/
_server_asset_probe/
server-data/
# Tools build artifacts and intermediates
tools/*.class
tools/*.swf
tools/staging/
tools/server-monitor/
# Nix
result
result-*
.direnv/
.xwin-cache/
.xwin/
# macOS
.DS_Store
.idea/
+1 -1
View File
@@ -1,3 +1,3 @@
[submodule "Minecraft.Client/Windows64/4JLibs"]
path = Minecraft.Client/Windows64/4JLibs
url = https://github.com/itsRevela/4JLibs.git
url = https://gitea.str1k3r.xyz/str1k3r/4JLibs.git
-116
View File
@@ -1,116 +0,0 @@
{
"search.exclude": {
"**/Minecraft.Client/Common/DummyTexturePack/res": true,
"**/Minecraft.Client/Common/Media": true,
"**/Minecraft.Client/Common/res": true,
"**/Minecraft.Client/Common/Trial": true,
"**/Minecraft.Client/Durango/4JLibs/libs": true,
"**/Minecraft.Client/Durango/CU": true,
"**/Minecraft.Client/Durango/DLCImages": true,
"**/Minecraft.Client/Durango/DurangoExtras/xcompress.dll": true,
"**/Minecraft.Client/Durango/DurangoExtras/xcompress.lib": true,
"**/Minecraft.Client/Durango/Iggy/lib": true,
"**/Minecraft.Client/Durango/Layout": true,
"**/Minecraft.Client/Durango/Miles/lib": true,
"**/Minecraft.Client/Durango/Network/Windows.Xbox.Networking.RealtimeSession.dll": true,
"**/Minecraft.Client/Durango/Network/windows.xbox.networking.realtimesession.pdb": true,
"**/Minecraft.Client/Durango/Network/windows.xbox.networking.realtimesession.winmd": true,
"**/Minecraft.Client/Durango/ServiceConfig": true,
"**/Minecraft.Client/Durango/Sound": true,
"**/Minecraft.Client/Durango/DLCXbox1.cmp": true,
"**/Minecraft.Client/Durango/*.png": true,
"**/Minecraft.Client/DurangoMedia/DLC": true,
"**/Minecraft.Client/DurangoMedia/Layout": true,
"**/Minecraft.Client/DurangoMedia/loc": true,
"**/Minecraft.Client/DurangoMedia/loc/strings.h": false,
"**/Minecraft.Client/DurangoMedia/Media": true,
"**/Minecraft.Client/DurangoMedia/Sound": true,
"**/Minecraft.Client/music": true,
"**/Minecraft.Client/Orbis/4JLibs/Libs": true,
"**/Minecraft.Client/Orbis/DLCImages": true,
"**/Minecraft.Client/Orbis/GameConfig": true,
"**/Minecraft.Client/Orbis/GameConfig/Minecraft.spa.h": false,
"**/Minecraft.Client/Orbis/Iggy/lib": true,
"**/Minecraft.Client/Orbis/Miles/lib": true,
"**/Minecraft.Client/Orbis/min/min.sig": true,
"**/Minecraft.Client/Orbis/min/pronunciation.sig": true,
"**/Minecraft.Client/Orbis/MinecraftPronunciation/MinecraftPronunciation.sig": true,
"**/Minecraft.Client/Orbis/MinecraftPronunciation/pronunciation.sig": true,
"**/Minecraft.Client/Orbis/PS4ProductCodes.bin": true,
"**/Minecraft.Client/Orbis/session_image.jpg": true,
"**/Minecraft.Client/Orbis/session_image.png": true,
"**/Minecraft.Client/OrbisMedia/DLC": true,
"**/Minecraft.Client/OrbisMedia/loc": true,
"**/Minecraft.Client/OrbisMedia/loc/strings.h": false,
"**/Minecraft.Client/OrbisMedia/Media": true,
"**/Minecraft.Client/PS3/4JLibs/libs": true,
"**/Minecraft.Client/PS3/DATA": true,
"**/Minecraft.Client/PS3/Edge": true,
"**/Minecraft.Client/PS3/GameConfig/MinecraftIcon.png": true,
"**/Minecraft.Client/PS3/GameConfig/set.png": true,
"**/Minecraft.Client/PS3/Iggy/lib": true,
"**/Minecraft.Client/PS3/Media": true,
"**/Minecraft.Client/PS3/Media/*.h": true,
"**/Minecraft.Client/PS3/Miles/lib": true,
"**/Minecraft.Client/PS3/Sound": true,
"**/Minecraft.Client/PS3/SPU_Tasks/*.o": true,
"**/Minecraft.Client/PS3/SPU_Tasks/mssspurs.elf": true,
"**/Minecraft.Client/PS3/PS3ProductCodes.bin": true,
"**/Minecraft.Client/PS3_GAME": true,
"**/Minecraft.Client/PS3Media/DLC": true,
"**/Minecraft.Client/PS3Media/loc": true,
"**/Minecraft.Client/PS3Media/Media": true,
"**/Minecraft.Client/PS4_GAME": true,
"**/Minecraft.Client/PSVita/4JLibs/libs": true,
"**/Minecraft.Client/PSVita/app": true,
"**/Minecraft.Client/PSVita/Builds": true,
"**/Minecraft.Client/PSVita/GameConfig": true,
"**/Minecraft.Client/PSVita/GameConfig/Minecraft.spa.h": false,
"**/Minecraft.Client/PSVita/Iggy/lib": true,
"**/Minecraft.Client/PSVita/Miles/lib": true,
"**/Minecraft.Client/PSVita/Sound": true,
"**/Minecraft.Client/PSVita/Tutorial": true,
"**/Minecraft.Client/PSVita/configuration.psp2path": true,
"**/Minecraft.Client/PSVita/PSVitaProductCodes.bin": true,
"**/Minecraft.Client/PSVita/session_image.png": true,
"**/Minecraft.Client/PSVitaMedia/DLC": true,
"**/Minecraft.Client/PSVitaMedia/loc": true,
"**/Minecraft.Client/PSVitaMedia/Media": true,
"**/Minecraft.Client/PSVitaMedia/Tutorial": true,
"**/Minecraft.Client/PSVitaMedia/Minecraft.Client.self": true,
"**/Minecraft.Client/redist64": true
"**/Minecraft.Client/sce_sys": true
"**/Minecraft.Client/TROPDIR": true
"**/Minecraft.Client/Windows64/4JLibs/libs": true,
"**/Minecraft.Client/Windows64/GameConfig/Minecraft.spa": true,
"**/Minecraft.Client/Windows64/GameHDD": true,
"**/Minecraft.Client/Windows64/Iggy/lib": true,
"**/Minecraft.Client/Windows64Media": true,
"**/Minecraft.Client/Windows64Media/4J_strings.h": false,
"**/Minecraft.Client/Windows64Media/strings.h": false,
"**/Minecraft.Client/x64": true,
"**/Minecraft.Client/Xbox/4JLibs/libs": true,
"**/Minecraft.Client/Xbox/4JLibs/Media": true,
"**/Minecraft.Client/Xbox/Cheats": true,
"**/Minecraft.Client/Xbox/ContentPackageBuild": true,
"**/Minecraft.Client/Xbox/Docs": true,
"**/Minecraft.Client/Xbox/GameConfig": true,
"**/Minecraft.Client/Xbox/GameConfig/Minecraft.spa.h": false,
"**/Minecraft.Client/Xbox/kinect": true,
"**/Minecraft.Client/Xbox/loc": true,
"**/Minecraft.Client/Xbox/ReleaseBuild": true,
"**/Minecraft.Client/Xbox/SubmissionBuild": true,
"**/Minecraft.Client/Xbox/Title Update": true,
"**/Minecraft.Client/Xbox/TMSFiles": true,
"**/Minecraft.Client/Xbox/MinecraftWindows.ico": true,
"**/Minecraft.Client/Xbox/small.ico": true,
"**/Minecraft.Client/alphaTest.png": true,
"**/Minecraft.Client/thumbnailTest64.png": true,
"**/Minecraft.Client/thumbnailTest128.png": true,
"**/Minecraft.Client/thumbnailTest256.png": true,
"**/Minecraft.Client/thumbnailTest1028.png": true,
"**/Minecraft.World/x64_Debug": true,
"**/Minecraft.World/x64_Release": true
"**/x64": true
}
}
+154 -10
View File
@@ -12,15 +12,28 @@ endif()
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
message(FATAL_ERROR "Use a 64-bit generator/toolchain (x64).")
endif()
set(LCE_XWIN_CROSS_DEBUG_COMPAT OFF)
if(CMAKE_CROSSCOMPILING AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(LCE_XWIN_CROSS_DEBUG_COMPAT ON)
endif()
set(CMAKE_CONFIGURATION_TYPES
"Debug"
"Release"
CACHE STRING "" FORCE
)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
if(CMAKE_CROSSCOMPILING AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")
else()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
endif()
function(configure_compiler_target target)
# MSVC and compatible compilers (like Clang-cl) !
# MSVC and compatible compilers (like Clang-cl)
if (MSVC)
target_compile_options(${target} PRIVATE
$<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:C,CXX>>:/W3>
@@ -30,9 +43,13 @@ function(configure_compiler_target target)
$<$<COMPILE_LANGUAGE:C,CXX>:/GS>
$<$<COMPILE_LANGUAGE:CXX>:/EHsc>
$<$<COMPILE_LANGUAGE:CXX>:/GR>
$<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:C,CXX>>:/Z7>
$<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:C,CXX>>:/Od>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/O2 /Oi /GT /GF>
)
target_link_options(${target} PRIVATE
$<$<CONFIG:Debug>:/DEBUG:FULL /INCREMENTAL:NO>
)
endif()
# MSVC
@@ -64,7 +81,9 @@ endfunction()
set(MINECRAFT_SHARED_DEFINES
_LARGE_WORLDS
_DEBUG_MENUS_ENABLED
$<$<CONFIG:Debug>:_DEBUG>
$<$<AND:$<CONFIG:Debug>,$<NOT:$<BOOL:${LCE_XWIN_CROSS_DEBUG_COMPAT}>>>:_DEBUG>
$<$<AND:$<CONFIG:Debug>,$<BOOL:${LCE_XWIN_CROSS_DEBUG_COMPAT}>>:_ITERATOR_DEBUG_LEVEL=0>
$<$<AND:$<CONFIG:Debug>,$<BOOL:${LCE_XWIN_CROSS_DEBUG_COMPAT}>>:_HAS_ITERATOR_DEBUGGING=0>
_CRT_NON_CONFORMING_SWPRINTFS
_CRT_SECURE_NO_WARNINGS
_HAS_STD_BYTE=0
@@ -77,21 +96,117 @@ if(PLATFORM_NAME STREQUAL "Windows64")
endif()
list(APPEND MINECRAFT_SHARED_DEFINES ${PLATFORM_DEFINES})
# handle fxc shader compilation on non-windows platforms
if(CMAKE_HOST_UNIX AND CMAKE_CROSSCOMPILING AND PLATFORM_NAME STREQUAL "Windows64")
set(_LCE_FXC_CANDIDATES
"${CMAKE_SOURCE_DIR}/Minecraft.Client/Windows64/Shaders/fxc.exe"
"${CMAKE_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/impls/Windows_Libs/Render/shaders/fxc.exe"
)
unset(LCE_FXC_EXE)
foreach(_LCE_FXC_CANDIDATE IN LISTS _LCE_FXC_CANDIDATES)
if(EXISTS "${_LCE_FXC_CANDIDATE}")
set(LCE_FXC_EXE "${_LCE_FXC_CANDIDATE}")
break()
endif()
endforeach()
if(LCE_FXC_EXE)
find_program(LCE_WINE_PROGRAM NAMES wine)
if(NOT LCE_WINE_PROGRAM)
message(FATAL_ERROR "Found fxc.exe at '${LCE_FXC_EXE}', but could not find wine in the system PATH.")
endif()
set(_LCE_FXC_WRAPPER_DIR "${CMAKE_BINARY_DIR}/tools")
set(_LCE_FXC_WRAPPER "${_LCE_FXC_WRAPPER_DIR}/fxc")
file(MAKE_DIRECTORY "${_LCE_FXC_WRAPPER_DIR}")
configure_file(
"${CMAKE_SOURCE_DIR}/cmake/FxcWineWrapper.sh.in"
"${_LCE_FXC_WRAPPER}"
@ONLY
)
file(CHMOD "${_LCE_FXC_WRAPPER}"
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
set(FXC_COMPILER "${_LCE_FXC_WRAPPER}" CACHE FILEPATH "Path to FXC compiler" FORCE)
message(STATUS "Translating FXC through Wine: ${LCE_WINE_PROGRAM} ${LCE_FXC_EXE}")
endif()
endif()
# ---
# Sources
# ---
add_subdirectory("Minecraft.Client/${PLATFORM_NAME}/4JLibs")
if(CMAKE_CROSSCOMPILING AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# clang apparently doesnt like whatever __m128 is so we gotta define it manually
if(TARGET 4JLibs.${PLATFORM_NAME}.Render)
target_compile_definitions(4JLibs.${PLATFORM_NAME}.Render PRIVATE
_XM_NO_INTRINSICS_
m128_f32=vector4_f32
)
endif()
endif()
add_subdirectory(Minecraft.World)
add_subdirectory(Minecraft.Client)
if(PLATFORM_NAME STREQUAL "Windows64") # Server is only supported on Windows for now
add_subdirectory(Minecraft.Server.FourKit)
add_subdirectory(Minecraft.Server)
if(TARGET GenerateStringsHeader_Minecraft.Client)
add_dependencies(Minecraft.World GenerateStringsHeader_Minecraft.Client)
endif()
# ---
# String ID lookup generation
# ---
set(STRING_ID_LOOKUP_OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/generated/StringIdLookup.generated.inc"
)
set(STRING_ID_XML_ROOT
"${CMAKE_SOURCE_DIR}/Minecraft.Client/Windows64Media/loc"
)
file(GLOB_RECURSE STRING_ID_XML_FILES CONFIGURE_DEPENDS
"${STRING_ID_XML_ROOT}/*.xml"
)
set(GENERATED_STRINGS_HEADER
"${CMAKE_BINARY_DIR}/generated/Windows64Media/strings.h"
)
add_custom_command(
OUTPUT "${STRING_ID_LOOKUP_OUTPUT}"
COMMAND ${CMAKE_COMMAND}
"-DHEADER_LIST=${GENERATED_STRINGS_HEADER}"
"-DOUTPUT_FILE=${STRING_ID_LOOKUP_OUTPUT}"
-P "${CMAKE_SOURCE_DIR}/cmake/GenerateStringIdLookup.cmake"
DEPENDS
${STRING_ID_XML_FILES}
"${GENERATED_STRINGS_HEADER}"
"${CMAKE_SOURCE_DIR}/cmake/GenerateStringIdLookup.cmake"
COMMENT "Generating StringIdLookup.generated.inc"
VERBATIM
)
add_custom_target(GenerateStringIdLookup ALL
DEPENDS "${STRING_ID_LOOKUP_OUTPUT}"
)
if(TARGET GenerateStringsHeader_Minecraft.Client)
add_dependencies(GenerateStringIdLookup GenerateStringsHeader_Minecraft.Client)
endif()
set_property(TARGET GenerateStringIdLookup PROPERTY FOLDER "Build")
# ---
# Build versioning
# ---
set(BUILDVER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateBuildVer.cmake")
set(BUILDVER_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/Common/BuildVer.h")
@@ -105,16 +220,45 @@ add_custom_target(GenerateBuildVer
add_dependencies(Minecraft.World GenerateBuildVer)
add_dependencies(Minecraft.Client GenerateBuildVer)
if(PLATFORM_NAME STREQUAL "Windows64")
add_dependencies(Minecraft.Server GenerateBuildVer)
endif()
add_dependencies(Minecraft.Client GenerateStringIdLookup)
set(_item_map_inputs
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/Tile.h"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/Item.h"
)
#neo: added ItemNameMap generation
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/generated/ItemNameMap.h"
COMMAND ${CMAKE_COMMAND}
"-DINPUT_FILES=${_item_map_inputs}"
"-DOUTPUT_FILE=${CMAKE_BINARY_DIR}/generated/ItemNameMap.h"
-P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateItemNameMap.cmake"
DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/Tile.h"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/Item.h"
COMMENT "Generating ItemNameMap.h"
)
add_custom_target(GenerateItemNameMap ALL
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/generated/ItemNameMap.h"
)
add_dependencies(Minecraft.Client GenerateItemNameMap)
add_dependencies(Minecraft.World GenerateItemNameMap)
target_include_directories(Minecraft.Client PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/generated"
)
# ---
# Project organisation
# ---
# Set the startup project for Visual Studio
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT Minecraft.Client)
# Setup folders for Visual Studio, just hides the build targets under a sub folder
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set_property(TARGET GenerateBuildVer PROPERTY FOLDER "Build")
set_property(TARGET GenerateBuildVer PROPERTY FOLDER "Build")
+85 -83
View File
@@ -1,56 +1,25 @@
# Compile Instructions
## Prerequisites
## Visual Studio
- **Visual Studio 2022** with the **Desktop development with C++** workload (this includes the CMake tools, MSVC toolchain, and Windows 10 SDK).
- **.NET 10 SDK**, required to build the FourKit plugin host (`Minecraft.Server.FourKit`).
- Download: https://dotnet.microsoft.com/download/dotnet/10.0 (pick the **x64 SDK** installer)
- The exact SDK version is pinned in `global.json` at the repo root.
- CMake will fail configure with a clear error message if .NET 10 is not installed, so you find out immediately rather than partway through a build.
- The build invokes `dotnet publish ... --runtime win-x64 --self-contained true`, so the published output bundles a complete .NET 10 runtime alongside the FourKit assembly. End users running the produced server do **not** need to install .NET themselves.
- All FourKit runtime files (DLL + .NET runtime + `hostfxr.dll`) land in a `runtime/` subfolder next to `Minecraft.Server.exe`. An empty `plugins/` folder is also created. Both are produced automatically by the build.
## Visual Studio 2022 quick start (recommended)
VS 2022 has built-in CMake support, so there is no need to generate a `.sln` file by hand.
1. Install the prerequisites above.
2. Clone the repo with submodules. If you don't, you will get a build error!
- `git clone --recurse-submodules https://github.com/itsRevela/LCE-Revelations.git`
3. In Visual Studio: `File > Open > Folder...` and select the **repo root** (the folder that contains `CMakeLists.txt`).
4. Wait for CMake to configure (~5 seconds on a warm cache, a few minutes on the first run while assets copy).
5. Pick a build configuration in the dropdown, for example `windows64-release`.
6. `Build > Build All` (or `F7`). Targets of interest:
- `Minecraft.Client`: the game client.
- `Minecraft.Server`: the **vanilla** dedicated server. Standalone C++ binary, no plugin host, no .NET dependency at runtime, smallest distribution.
- `Minecraft.Server.FourKit`: the **FourKit-enabled** dedicated server. Bundles the .NET 10 plugin host alongside the exe (in `runtime/`) and creates an empty `plugins/` folder for end users to drop plugin DLLs into. Building this target also triggers the `Minecraft.Server.FourKit.Managed` target which publishes the C# project.
7. Use the debug target dropdown to pick `Minecraft.Client.exe` or whichever server flavour you want, then `F5` to launch.
### Server flavours
Both server targets compile from the same source tree and produce a binary literally named `Minecraft.Server.exe`. The variant identity lives in the build directory:
```
build/<preset>/Minecraft.Server/Release/
Minecraft.Server.exe (vanilla, no plugin support)
Common/, Windows64/, ...
build/<preset>/Minecraft.Server.FourKit/Release/
Minecraft.Server.exe (FourKit-enabled, same exe name on purpose)
runtime/ (self-contained .NET 10 + Minecraft.Server.FourKit.dll)
plugins/ (empty drop point)
Common/, Windows64/, ...
```
The FourKit target gets the `MINECRAFT_SERVER_FOURKIT_BUILD` preprocessor define. Inside `FourKitBridge.h`, the real plugin entry points are conditional on that define; the vanilla target sees inline no-op stubs instead, so gameplay code can call `FourKitBridge::Fire*` unconditionally and produce the right behaviour for each flavour without per-call-site `#ifdef`s.
1. Clone the repo, including submodules.
- If you don't, the build will fail. `git clone --recurse-submodules https://github.com/MCLCE/MinecraftConsoles.git`
2. Open the repo folder in Visual Studio 2022+.
3. Wait for cmake to configure the project and load all assets (this may take a few minutes on the first run).
4. Right click a folder in the solution explorer and switch to the 'CMake Targets View'
5. Select platform and configuration from the dropdown. EG: `Windows64 - Debug` or `Windows64 - Release`
6. Pick the startup project `Minecraft.Client.exe` or `Minecraft.Server.exe` using the debug targets dropdown
7. Build and run the project:
- `Build > Build Solution` (or `Ctrl+Shift+B`)
- Start debugging with `F5`.
### Dedicated server debug arguments
- Default debugger arguments for both `Minecraft.Server` and `Minecraft.Server.FourKit`:
- Default debugger arguments for `Minecraft.Server`:
- `-port 25565 -bind 0.0.0.0 -name DedicatedServer`
- You can override arguments in:
- `Project Properties > Debugging > Command Arguments`
- Both server targets post-build copy the dedicated-server asset set:
- `Minecraft.Server` post-build copies only the dedicated-server asset set:
- `Common/Media/MediaWindows64.arc`
- `Common/res`
- `Windows64/GameHDD`
@@ -77,36 +46,18 @@ Build Release:
cmake --build --preset windows64-release --target Minecraft.Client
```
Build vanilla Dedicated Server (Debug):
Build Dedicated Server (Debug):
```powershell
cmake --build --preset windows64-debug --target Minecraft.Server
```
Build vanilla Dedicated Server (Release):
Build Dedicated Server (Release):
```powershell
cmake --build --preset windows64-release --target Minecraft.Server
```
Build FourKit Dedicated Server (Debug):
```powershell
cmake --build --preset windows64-debug --target Minecraft.Server.FourKit
```
Build FourKit Dedicated Server (Release):
```powershell
cmake --build --preset windows64-release --target Minecraft.Server.FourKit
```
Build everything (client + both server flavours):
```powershell
cmake --build --preset windows64-release
```
Run executable:
```powershell
@@ -114,20 +65,13 @@ cd .\build\windows64\Minecraft.Client\Debug
.\Minecraft.Client.exe
```
Run vanilla dedicated server:
Run dedicated server:
```powershell
cd .\build\windows64\Minecraft.Server\Debug
.\Minecraft.Server.exe -port 25565 -bind 0.0.0.0 -name DedicatedServer
```
Run FourKit dedicated server:
```powershell
cd .\build\windows64\Minecraft.Server.FourKit\Debug
.\Minecraft.Server.exe -port 25565 -bind 0.0.0.0 -name DedicatedServer
```
Notes:
- Post-build asset copy is automatic for `Minecraft.Client` in CMake (Debug and Release variants).
- The game relies on relative paths (for example `Common\Media\...`), so launching from the output directory is required.
@@ -150,18 +94,81 @@ Install xwin for downloading the Windows SDK:
cargo install xwin
```
### Compile
### Download Windows SDK
Download and extract the Windows SDK and CRT:
Run this (Release):
```bash
./build-linux.sh
xwin --accept-license splat --output ~/.cache/xwin/splat
```
Or, for debug:
Create symlinks to account for Linux filesystems being case sensitive:
```bash
./build-linux.sh . Debug
WINSDK=~/.cache/xwin/splat
ln -sf $WINSDK/sdk/include/shared/sdkddkver.h $WINSDK/sdk/include/shared/SDKDDKVer.h
ln -sf $WINSDK/sdk/lib/um/x86_64/xinput9_1_0.lib $WINSDK/sdk/lib/um/x86_64/XInput9_1_0.lib
ln -sf $WINSDK/sdk/lib/um/x86_64/ws2_32.lib $WINSDK/sdk/lib/um/x86_64/Ws2_32.lib
```
### Configure
Set environment variables and configure CMake:
```bash
export WINSDK=~/.cache/xwin/splat
export INCLUDE="$WINSDK/crt/include;$WINSDK/sdk/include/um;$WINSDK/sdk/include/ucrt;$WINSDK/sdk/include/shared"
export LIB="$WINSDK/crt/lib/x86_64;$WINSDK/sdk/lib/um/x86_64;$WINSDK/sdk/lib/ucrt/x86_64"
cmake -S . -B build/windows64-clang \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang-cl \
-DCMAKE_CXX_COMPILER=clang-cl \
-DCMAKE_LINKER=lld-link \
-DCMAKE_RC_COMPILER=llvm-rc \
-DCMAKE_MT=llvm-mt \
-DPLATFORM_DEFINES="_WINDOWS64" \
-DPLATFORM_NAME="Windows64" \
-DIGGY_LIBS="iggy_w64.lib;iggyperfmon_w64.lib;iggyexpruntime_w64.lib" \
-DCMAKE_SYSTEM_NAME=Windows \
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded \
-DCMAKE_C_FLAGS="/MT -fms-compatibility -fms-extensions --target=x86_64-pc-windows-msvc -imsvc $WINSDK/crt/include -imsvc $WINSDK/sdk/include/ucrt -imsvc $WINSDK/sdk/include/um -imsvc $WINSDK/sdk/include/shared" \
-DCMAKE_CXX_FLAGS="/MT -fms-compatibility -fms-extensions --target=x86_64-pc-windows-msvc -imsvc $WINSDK/crt/include -imsvc $WINSDK/sdk/include/ucrt -imsvc $WINSDK/sdk/include/um -imsvc $WINSDK/sdk/include/shared" \
-DCMAKE_ASM_MASM_FLAGS="-m64" \
-DCMAKE_EXE_LINKER_FLAGS="-libpath:$WINSDK/crt/lib/x86_64 -libpath:$WINSDK/sdk/lib/um/x86_64 -libpath:$WINSDK/sdk/lib/ucrt/x86_64"
```
### Build
Build Release:
```bash
cmake --build build/windows64-clang --config Release
```
Build specific target:
```bash
cmake --build build/windows64-clang --config Release --target Minecraft.Client
cmake --build build/windows64-clang --config Release --target Minecraft.Server
```
### Run with Wine
Run executable:
```bash
cd build/windows64-clang/Minecraft.Client
wine ./Minecraft.Client.exe
```
Run dedicated server:
```bash
cd build/windows64-clang/Minecraft.Server
wine ./Minecraft.Server.exe -port 25565 -bind 0.0.0.0 -name DedicatedServer
```
### NixOS / Nix
@@ -180,10 +187,5 @@ nix develop
Notes:
- Requires LLVM 15+ with clang-cl, lld-link, llvm-rc, and llvm-mt.
- The xwin tool downloads ~1GB of SDK files on first run.
- Wine is required to run the compiled Windows executables on Linux.
### Troubleshooting
- **`'vswhere.exe' is not recognized`**: harmless warning. This appears if you ran `vcvars64.bat` from a plain command prompt instead of `Developer PowerShell for VS`. The Visual Studio Installer's `vswhere.exe` lives at `C:\Program Files (x86)\Microsoft Visual Studio\Installer\` and is not on the default `PATH`. Use the Developer PowerShell shortcut, or open the repo folder directly in VS (which handles the dev env for you).
- **`.NET 10 SDK not found` at configure time**: install the x64 SDK from https://dotnet.microsoft.com/download/dotnet/10.0 and re-run CMake configure (`Project > Configure Cache` in VS, or `cmake --preset windows64` from a shell).
- **Server starts but logs `hostfxr_initialize_for_dotnet_command_line failed`**: the `runtime/` folder next to `Minecraft.Server.exe` is missing or stale. Rebuild the `Minecraft.Server.FourKit` target (which re-stages `runtime/`), or do a clean rebuild of `Minecraft.Server`.
-60
View File
@@ -1,60 +0,0 @@
# Scope of Project
At the moment, this project's scope is generally limited outside of adding new content to the game (blocks, mobs, items). We are currently prioritizing stability, quality of life, and platform support over these things.
## Parity
We are attempting to keep our version of LCE as close to visual and experience parity with the original console experience of LCE as possible. This means that we will not be accepting changes that...
- Backport things from Java Edition that did not ever exist in LCE
- Swap out LCE visuals for Java Edition or Bedrock Edition style visuals
- Change LCE defaults in favor of different defaults if it changes the experience
- For example, increasing mob spawn limits without increasing the area mobs can spawn within, aka increasing mob density past what was the original console experience
- Redesign UI components different than LCE
- Break controller support, or otherwise do not support play with a controller
- Add custom texture packs or DLC that never existed in LCE
- Add any gameplay content (block, item, mob) that has no existing point of reference in any official LCE build
However, we would accept changes that...
- Fix legitimately buggy or inconsistent behavior in LCE that causes unexpected outcomes
- For example, mobs clipping outside of walls, clipping through the world, broken mechanics
- Add features to better support multi-platform use of LCE, such as video and control settings
- These menus need to respect the visual style of LCE, though.
- Replace existing UI systems with SWF-free rendering techniques that are as visually and functionally identical as possible
- Improve the quality of assets (such as sounds) while preserving their contents
- For example, upgrading the quality of all music in-game while preserving any unique cuts / versions, or faithfully remaking those unique cuts / versions with higher quality assets
- Backport things like modern skin rendering
- Change the code from using non-stitched textures to individually named texture PNGs and stitching at runtime
- Adding menus to better support custom dedicated servers with their own fixed IPs
- Add support for things like Steamworks Networking and other P2P networking and auth strategies
- Improve Keyboard and Mouse control support
- Add minimal, non-invasive Quality of Life features that don't otherwise compromise the LCE experience
- For example, adjusting certain crafting recipes or change item behaviors like non-stackable doors
## Current Goals
- Being a robust Desktop version of LCE
- Having proper controller support across all types, brands on Desktop or Desktop-like platforms (Steam Deck)
- Improving stability as much as possible
- Fixing as many bugs as possible
- Enabling Desktop multiplayer options
- LAN P2P Multiplayer
- Splitscreen Multiplayer
- WAN Servers (IP:Port connectivity)
- Platform-based P2P Connectivity
- Steam Networking
- GameDate?
- Maybe more?
- Refining rendering settings, renderer options, as well as reaching rendering parity with true LCE
- Having workable multi-platform compilation for ARM, Consoles, Linux
- Being a good base for further expansion and modding of LCE, such as backports and "modpacks".
# Scope of PRs
All Pull Requests should fully document the changes they include in their file changes. They should also be limited to one general topic and not touch all over the codebase unless its justifiable.
For example, we would not accept a PR that reworks UI, multiplayer code, and furnace ticking even if its a "fixup" PR as its too difficult to review a ton of code changes that are all irrelevant from each other. However, a PR focused on adding a bunch of commands or fixes several crashes that are otherwise irrelevant to each other would be accepted.
If your PR includes any undocumented changes it will be closed.
# Use of AI and LLMs
We currently do not accept any new code into the project that was written largely, entirely, or even noticably by an LLM. All contributions should be made by humans that understand the codebase.
# Pull Request Template
We request that all PRs made for this repo use our PR template to the fullest extent possible. Completely wiping it out to write minimal information will likely get your PR closed.
+36
View File
@@ -0,0 +1,36 @@
#include "stdafx.h"
#include "AbstractArmorLayer.h"
#include "LivingEntityRenderer.h"
#include "HumanoidModel.h"
AbstractArmorLayer::AbstractArmorLayer(LivingEntityRenderer* renderer)
: armorModel1(nullptr),
armorModel2(nullptr),
renderer(renderer),
colorR(1.0f),
colorG(1.0f),
colorB(1.0f),
colorA(1.0f),
hasColor(false)
{
}
HumanoidModel* AbstractArmorLayer::getArmorModel(int slot) {
if (slot == 2)
return armorModel1;
return armorModel2;
}
int AbstractArmorLayer::colorsOnDamage() {
return 0;
}
void AbstractArmorLayer::resetColor() {
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
hasColor = false;
}
void AbstractArmorLayer::createArmorModels() {
// default: no-op
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <memory>
using namespace std;
class LivingEntityRenderer;
class HumanoidModel;
class LivingEntity;
class AbstractArmorLayer {
public:
HumanoidModel* armorModel1;
HumanoidModel* armorModel2;
LivingEntityRenderer* renderer;
float colorR;
float colorG;
float colorB;
float colorA;
bool hasColor;
explicit AbstractArmorLayer(LivingEntityRenderer* renderer);
virtual ~AbstractArmorLayer() {}
virtual HumanoidModel* getArmorModel(int slot);
virtual void createArmorModels();
virtual int colorsOnDamage();
virtual void resetColor();
};
+70
View File
@@ -0,0 +1,70 @@
#include "stdafx.h"
#include "ArmorStandArmorModel.h"
#include "ModelPart.h"
#include "../Minecraft.World/ArmorStand.h"
static const float DEG_TO_RAD = 0.017453292f;
ArmorStandArmorModel::ArmorStandArmorModel(float scale, int texWidth, int texHeight)
: HumanoidModel(scale, 0.0f, texWidth, texHeight)
{
}
ArmorStandArmorModel::~ArmorStandArmorModel() {}
void ArmorStandArmorModel::setupAnim(float time, float r, float bob,
float yRot, float xRot, float scale,
shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim)
{
if (!entity) return;
if (!entity->instanceof(eTYPE_ARMORSTAND)) return;
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(entity);
if (!stand) return;
Rotations h = stand->getHeadPose();
Rotations b = stand->getBodyPose();
Rotations la = stand->getLeftArmPose();
Rotations ra = stand->getRightArmPose();
Rotations ll = stand->getLeftLegPose();
Rotations rl = stand->getRightLegPose();
head->xRot = DEG_TO_RAD * h.getX();
head->yRot = DEG_TO_RAD * h.getY();
head->zRot = DEG_TO_RAD * h.getZ();
head->setPos(0.0f, 1.0f, 0.0f);
body->xRot = DEG_TO_RAD * b.getX();
body->yRot = DEG_TO_RAD * b.getY();
body->zRot = DEG_TO_RAD * b.getZ();
arm0->xRot = DEG_TO_RAD * la.getX();
arm0->yRot = DEG_TO_RAD * la.getY();
arm0->zRot = DEG_TO_RAD * la.getZ();
arm1->xRot = DEG_TO_RAD * ra.getX();
arm1->yRot = DEG_TO_RAD * ra.getY();
arm1->zRot = DEG_TO_RAD * ra.getZ();
leg1->xRot = DEG_TO_RAD * ll.getX();
leg1->yRot = DEG_TO_RAD * ll.getY();
leg1->zRot = DEG_TO_RAD * ll.getZ();
leg1->setPos(1.9f, 11.0f, 0.0f);
leg0->xRot = DEG_TO_RAD * rl.getX();
leg0->yRot = DEG_TO_RAD * rl.getY();
leg0->zRot = DEG_TO_RAD * rl.getZ();
leg0->setPos(-1.9f, 11.0f, 0.0f);
ModelPart::copyModelPart(head, hair);
}
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include "HumanoidModel.h"
class Entity;
class ArmorStandArmorModel : public HumanoidModel {
public:
ArmorStandArmorModel(float scale,
int texWidth = 64,
int texHeight = 32);
virtual ~ArmorStandArmorModel();
virtual void setupAnim(float time, float r, float bob,
float yRot, float xRot, float scale,
shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim = 0) override;
};
+138
View File
@@ -0,0 +1,138 @@
#include "stdafx.h"
#include "ModelPart.h"
#include "ArmorStandModel.h"
#include "../Minecraft.World/ArmorStand.h"
ArmorStandModel::ArmorStandModel(float scale) : HumanoidModel(scale)
{
texWidth = 64;
texHeight = 64;
head = new ModelPart(this, 0, 0);
head->addBox(-1.0f, -7.0f, -1.0f, 2, 7, 2, scale);
head->setPos(0.0f, 0.0f, 0.0f);
head->compile(1.0f / 16.0f);
hair = new ModelPart(this, 0, 0);
body = new ModelPart(this, 0, 26);
body->addBox(-6.0f, 0.0f, -1.5f, 12, 3, 3, scale);
body->setPos(0.0f, 0.0f, 0.0f);
body->compile(1.0f / 16.0f);
arm1 = new ModelPart(this, 24, 0);
arm1->addBox(-2.0f, -2.0f, -1.0f, 2, 12, 2, scale);
arm1->setPos(-5.0f, 2.0f, 0.0f);
arm1->compile(1.0f / 16.0f);
arm0 = new ModelPart(this, 32, 16);
arm0->mirror();
arm0->addBox(0.0f, -2.0f, -1.0f, 2, 12, 2, scale);
arm0->setPos(5.0f, 2.0f, 0.0f);
arm0->compile(1.0f / 16.0f);
leg0 = new ModelPart(this, 8, 0);
leg0->addBox(-1.0f, 0.0f, -1.0f, 2, 11, 2, scale);
leg0->setPos(-1.9f, 12.0f, 0.0f);
leg0->compile(1.0f / 16.0f);
leg1 = new ModelPart(this, 40, 16);
leg1->mirror();
leg1->addBox(-1.0f, 0.0f, -1.0f, 2, 11, 2, scale);
leg1->setPos(1.9f, 12.0f, 0.0f);
leg1->compile(1.0f / 16.0f);
rightBodyStick = new ModelPart(this, 16, 0);
rightBodyStick->addBox(-3.0f, 3.0f, -1.0f, 2, 7, 2, scale);
rightBodyStick->setPos(0.0f, 0.0f, 0.0f);
rightBodyStick->visible = false;
rightBodyStick->compile(1.0f / 16.0f);
leftBodyStick = new ModelPart(this, 48, 16);
leftBodyStick->addBox(1.0f, 3.0f, -1.0f, 2, 7, 2, scale);
leftBodyStick->setPos(0.0f, 0.0f, 0.0f);
leftBodyStick->visible = false;
leftBodyStick->compile(1.0f / 16.0f);
shoulderStick = new ModelPart(this, 0, 48);
shoulderStick->addBox(-4.0f, 10.0f, -1.0f, 8, 2, 2, scale);
shoulderStick->setPos(0.0f, 0.0f, 0.0f);
shoulderStick->compile(1.0f / 16.0f);
basePlate = new ModelPart(this, 0, 32);
basePlate->mirror();
basePlate->addBox(-6.0f, 11.0f, -6.0f, 12, 1, 12, scale);
basePlate->setPos(0.0f, 12.0f, 0.0f);
basePlate->compile(1.0f / 16.0f);
}
void ArmorStandModel::setupPose(
float hX, float hY, float hZ,
float bX, float bY, float bZ,
float lAX, float lAY, float lAZ,
float rAX, float rAY, float rAZ,
float lLX, float lLY, float lLZ,
float rLX, float rLY, float rLZ)
{
head->xRot = hX; head->yRot = hY; head->zRot = hZ;
if (hair) { hair->xRot = hX; hair->yRot = hY; hair->zRot = hZ; }
body->xRot = bX; body->yRot = bY; body->zRot = bZ;
rightBodyStick->xRot = bX; rightBodyStick->yRot = bY; rightBodyStick->zRot = bZ;
leftBodyStick->xRot = bX; leftBodyStick->yRot = bY; leftBodyStick->zRot = bZ;
shoulderStick->xRot = bX; shoulderStick->yRot = bY; shoulderStick->zRot = bZ;
arm1->xRot = lAX; arm1->yRot = lAY; arm1->zRot = lAZ;
arm0->xRot = rAX; arm0->yRot = rAY; arm0->zRot = rAZ;
leg1->xRot = lLX; leg1->yRot = lLY; leg1->zRot = lLZ;
leg0->xRot = rLX; leg0->yRot = rLY; leg0->zRot = rLZ;
}
void ArmorStandModel::setupAnim(float time, float r, float bob, float yRot, float xRot,
float scale, shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim)
{
}
void ArmorStandModel::render(shared_ptr<Entity> entity,
float time, float r, float bob,
float yRot, float xRot,
float scale, bool usecompiled)
{
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(entity);
if (stand)
{
bool armsVis = stand->isShowArms();
bool baseVis = stand->showBasePlate();
bool isSmallSt = stand->isSmall();
arm0->visible = armsVis;
arm1->visible = armsVis;
rightBodyStick->visible = !isSmallSt;
leftBodyStick->visible = !isSmallSt;
shoulderStick->visible = !isSmallSt;
basePlate->visible = baseVis;
}
HumanoidModel::render(entity, time, r, bob, yRot, xRot, scale, usecompiled);
rightBodyStick->render(scale, usecompiled);
leftBodyStick->render(scale, usecompiled);
shoulderStick->render(scale, usecompiled);
basePlate->render(scale, usecompiled);
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include "HumanoidModel.h"
#include "ModelPart.h"
class ArmorStandModel : public HumanoidModel
{
public:
ModelPart* rightBodyStick;
ModelPart* leftBodyStick;
ModelPart* shoulderStick;
ModelPart* basePlate;
ArmorStandModel(float scale = 0.0f);
virtual ~ArmorStandModel() {}
virtual void setupAnim(float time, float r, float bob, float yRot, float xRot,
float scale, shared_ptr<Entity> entity,
unsigned int uiBitmaskOverrideAnim = 0) override;
void setupPose(float hX, float hY, float hZ,
float bX, float bY, float bZ,
float lAX, float lAY, float lAZ,
float rAX, float rAY, float rAZ,
float lLX, float lLY, float lLZ,
float rLX, float rLY, float rLZ);
virtual void render(shared_ptr<Entity> entity,
float time, float r, float bob,
float yRot, float xRot,
float scale, bool usecompiled) override;
};
+215
View File
@@ -0,0 +1,215 @@
#include "stdafx.h"
#include "HumanoidMobRenderer.h"
#include "ArmorStandRenderer.h"
#include "ArmorStandArmorModel.h"
#include "HumanoidModel.h"
#include "ArmorStandModel.h"
#include "CustomHeadLayer.h"
#include "Textures.h"
#include "../Minecraft.World/ArmorStand.h"
#include "../Minecraft.World/ArmorItem.h"
#include "../Minecraft.World/Tile.h"
#include "../Minecraft.World/Facing.h"
#include <cmath>
#include "EntityRenderDispatcher.h"
#include "SkullTileRenderer.h"
#include "PlayerRenderer.h"
#include "../Minecraft.World/SkullItem.h"
#include "../Minecraft.World/SkullTileEntity.h"
static const float DEG_TO_RAD = 3.14159265f / 180.0f;
ResourceLocation ArmorStandRenderer::LOC_ARMOR_STAND = ResourceLocation(TN_MOB_ARMORSTAND);
ArmorStandRenderer::ArmorStandArmorLayer::ArmorStandArmorLayer(LivingEntityRenderer* renderer)
: HumanoidArmorLayer(renderer)
{
delete armorModel1;
delete armorModel2;
armorModel1 = new ArmorStandArmorModel(0.5f);
armorModel2 = new ArmorStandArmorModel(1.0f);
}
void ArmorStandRenderer::ArmorStandArmorLayer::createArmorModels()
{
delete armorModel1;
delete armorModel2;
armorModel1 = new ArmorStandArmorModel(0.5f);
armorModel2 = new ArmorStandArmorModel(1.0f);
}
ArmorStandRenderer::ArmorStandRenderer()
: LivingEntityRenderer(new ArmorStandModel(0.0f), 0.0f)
{
armorLayer = new ArmorStandArmorLayer(this);
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
headLayer = m ? new CustomHeadLayer(m->head, this) : nullptr;
}
ArmorStandRenderer::~ArmorStandRenderer() {}
ResourceLocation* ArmorStandRenderer::getTextureLocation(shared_ptr<Entity> entity)
{
return &LOC_ARMOR_STAND;
}
bool ArmorStandRenderer::shouldShowName(shared_ptr<LivingEntity> entity)
{
if (!entity) return false;
return entity->isCustomNameVisible();
}
void ArmorStandRenderer::setupRotations(shared_ptr<LivingEntity> mob,
float bob, float bodyRot, float a)
{
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(mob);
glRotatef(180.0f - bodyRot, 0.0f, 1.0f, 0.0f);
if (stand)
{
long long ticksSinceHit = (long long)stand->tickCount - stand->lastHit;
if (ticksSinceHit >= 0 && ticksSinceHit < 5)
{
float wobble = (float)(ticksSinceHit + a) / 5.0f;
float angle = (float)stand->hurtDir * sinf(wobble * 3.14159265f) * 3.0f;
glRotatef(angle, 0.0f, 0.0f, 1.0f);
}
}
}
void ArmorStandRenderer::render(shared_ptr<Entity> entity,
double x, double y, double z,
float rot, float a)
{
LivingEntityRenderer::render(entity, x, y, z, rot, a);
}
void ArmorStandRenderer::renderModel(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRotMinusBodyRot,
float headRotx, float scale)
{
shared_ptr<ArmorStand> stand = dynamic_pointer_cast<ArmorStand>(mob);
if (!stand) return;
ArmorStandModel* m = static_cast<ArmorStandModel*>(getModel());
if (!m) return;
Rotations h = stand->getHeadPose();
Rotations b = stand->getBodyPose();
Rotations la = stand->getLeftArmPose();
Rotations ra = stand->getRightArmPose();
Rotations ll = stand->getLeftLegPose();
Rotations rl = stand->getRightLegPose();
m->setupPose(
h.x * DEG_TO_RAD, h.y * DEG_TO_RAD, h.z * DEG_TO_RAD,
b.x * DEG_TO_RAD, b.y * DEG_TO_RAD, b.z * DEG_TO_RAD,
la.x * DEG_TO_RAD, la.y * DEG_TO_RAD, la.z * DEG_TO_RAD,
ra.x * DEG_TO_RAD, ra.y * DEG_TO_RAD, ra.z * DEG_TO_RAD,
ll.x * DEG_TO_RAD, ll.y * DEG_TO_RAD, ll.z * DEG_TO_RAD,
rl.x * DEG_TO_RAD, rl.y * DEG_TO_RAD, rl.z * DEG_TO_RAD
);
if (armorLayer)
{
auto applyPose = [&](HumanoidModel* am)
{
if (!am) return;
am->head->xRot = h.x * DEG_TO_RAD;
am->head->yRot = h.y * DEG_TO_RAD;
am->head->zRot = h.z * DEG_TO_RAD;
if (am->hair)
{
am->hair->xRot = h.x * DEG_TO_RAD;
am->hair->yRot = h.y * DEG_TO_RAD;
am->hair->zRot = h.z * DEG_TO_RAD;
}
am->body->xRot = b.x * DEG_TO_RAD;
am->body->yRot = b.y * DEG_TO_RAD;
am->body->zRot = b.z * DEG_TO_RAD;
am->arm1->xRot = la.x * DEG_TO_RAD;
am->arm1->yRot = la.y * DEG_TO_RAD;
am->arm1->zRot = la.z * DEG_TO_RAD;
am->arm0->xRot = ra.x * DEG_TO_RAD;
am->arm0->yRot = ra.y * DEG_TO_RAD;
am->arm0->zRot = ra.z * DEG_TO_RAD;
am->leg0->xRot = rl.x * DEG_TO_RAD;
am->leg0->yRot = rl.y * DEG_TO_RAD;
am->leg0->zRot = rl.z * DEG_TO_RAD;
am->leg1->xRot = ll.x * DEG_TO_RAD;
am->leg1->yRot = ll.y * DEG_TO_RAD;
am->leg1->zRot = ll.z * DEG_TO_RAD;
};
applyPose(static_cast<HumanoidModel*>(armorLayer->armorModel1));
applyPose(static_cast<HumanoidModel*>(armorLayer->armorModel2));
}
LivingEntityRenderer::renderModel(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale);
if (headLayer)
{
float fScale = 1.0f / 16.0f;
float bodyRot = mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * 0.0f;
float headRot = mob->yHeadRotO + (mob->yHeadRot - mob->yHeadRotO) * 0.0f;
float headRotX = mob->xRotO + (mob->xRot - mob->xRotO) * 0.0f;
headLayer->render(mob, wp, ws, bob, headRot - bodyRot, headRotX, fScale, true);
}
}
void ArmorStandRenderer::additionalRendering(shared_ptr<LivingEntity> mob, float a)
{
}
int ArmorStandRenderer::prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a)
{
if (!armorLayer) return -1;
shared_ptr<ItemInstance> itemInstance = mob->getArmor(3 - layer);
if (!itemInstance) return -1;
Item* item = itemInstance->getItem();
if (!item) return -1;
ArmorItem* armorItem = dynamic_cast<ArmorItem*>(item);
if (!armorItem) return -1;
bindTexture(HumanoidMobRenderer::getArmorLocation(armorItem, layer));
HumanoidModel* am = armorLayer->getArmorModel(layer);
if (!am) return -1;
am->head->visible = (layer == 0);
if (am->hair) am->hair->visible = (layer == 0);
am->body->visible = (layer == 1 || layer == 2);
am->arm0->visible = (layer == 1);
am->arm1->visible = (layer == 1);
am->leg0->visible = (layer == 2 || layer == 3);
am->leg1->visible = (layer == 2 || layer == 3);
setArmor(am);
am->attackTime = model->attackTime;
am->riding = model->riding;
am->young = mob->isBaby();
if (armorItem->getMaterial() == ArmorItem::ArmorMaterial::CLOTH)
{
int color = armorItem->getColor(itemInstance);
float red = static_cast<float>((color >> 16) & 0xFF) / 255.0f;
float green = static_cast<float>((color >> 8) & 0xFF) / 255.0f;
float blue = static_cast<float>( color & 0xFF) / 255.0f;
glColor3f(red, green, blue);
return itemInstance->isEnchanted() ? 0x1f : 0x10;
}
glColor3f(1.0f, 1.0f, 1.0f);
return itemInstance->isEnchanted() ? 15 : 1;
}
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#include "LivingEntityRenderer.h"
#include "HumanoidArmorLayer.h"
#include "ResourceLocation.h"
#include <vector>
class ArmorStandModel;
class LivingEntity;
class Entity;
class RenderLayer;
class CustomHeadLayer;
class ArmorStandRenderer : public LivingEntityRenderer {
public:
class ArmorStandArmorLayer : public HumanoidArmorLayer {
public:
explicit ArmorStandArmorLayer(LivingEntityRenderer* renderer);
virtual ~ArmorStandArmorLayer() {}
virtual void createArmorModels() override;
};
protected:
std::vector<RenderLayer*> renderLayers;
ArmorStandArmorLayer* armorLayer;
CustomHeadLayer* headLayer;
public:
void addLayer(RenderLayer* layer) { renderLayers.push_back(layer); }
void addLayer(ArmorStandArmorLayer* layer) { armorLayer = layer; }
ArmorStandArmorLayer* getArmorLayer() { return armorLayer; }
static ResourceLocation LOC_ARMOR_STAND;
ArmorStandRenderer();
virtual ~ArmorStandRenderer();
virtual ResourceLocation* getTextureLocation(shared_ptr<Entity> entity) override;
virtual bool shouldShowName(shared_ptr<LivingEntity> mob) override;
virtual void setupRotations(shared_ptr<LivingEntity> mob,
float bob, float bodyRot, float a) override;
virtual void render(shared_ptr<Entity> entity,
double x, double y, double z,
float rot, float a) override;
virtual void renderModel(shared_ptr<LivingEntity> mob,
float wp, float ws, float bob,
float headRotMinusBodyRot,
float headRotx, float scale) override;
virtual int prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a) override;
virtual void additionalRendering(shared_ptr<LivingEntity> mob, float a) override;
};
+80
View File
@@ -0,0 +1,80 @@
#include "stdafx.h"
#include "BarrierParticle.h"
#include "Minecraft.h"
#include "Tesselator.h"
#include "../Minecraft.World/Item.h"
#include "../Minecraft.World/Icon.h"
#include "../Minecraft.World/net.minecraft.world.level.tile.h"
#include "../Minecraft.World/Facing.h"
#include "../Minecraft.World/Level.h"
#include "../Minecraft.World/JavaMath.h"
void BarrierParticle::init(Level* level, double x, double y, double z, float scale)
{
xd = yd = zd = 0;
rCol = gCol = bCol = 1.0f;
alpha = 1.0f;
// fixed size
size = 0.5f * scale;
oSize = size;
lifetime = 80;
gravity = 0.0f;
}
BarrierParticle::BarrierParticle(Level* level,
double x, double y, double z,
double xa, double ya, double za)
: Particle(level, x, y, z, xa, ya, za)
{
init(level, x, y, z, 1.0f);
// set particle texture to barrier texture
this->setTex(Minecraft::GetInstance()->textures, Tile::barrier->getTexture(Facing::UP));
}
int BarrierParticle::getParticleTexture()
{
return ParticleEngine::TERRAIN_TEXTURE;
}
void BarrierParticle::render(Tesselator* t, float a, float xa, float ya, float za, float xa2, float za2)
{
rCol = gCol = bCol = 1.0f;
alpha = 1.0f;
float u0 = tex->getU0();
float u1 = tex->getU1();
float v0 = tex->getV0();
float v1 = tex->getV1();
float half = size;
float px = static_cast<float>(xo + (this->x - xo) * a - xOff);
float py = static_cast<float>(yo + (this->y - yo) * a - yOff);
float pz = static_cast<float>(zo + (this->z - zo) * a - zOff);
float br = SharedConstants::TEXTURE_LIGHTING ? 1.0f : getBrightness(a);
t->color(br * rCol, br * gCol, br * bCol, alpha);
t->tex2(getLightColor(a));
t->vertexUV((double)(px - xa * half - xa2 * half), (double)(py - ya * half), (double)(pz - za * half - za2 * half), (double)u1, (double)v1);
t->vertexUV((double)(px - xa * half + xa2 * half), (double)(py + ya * half), (double)(pz - za * half + za2 * half), (double)u1, (double)v0);
t->vertexUV((double)(px + xa * half + xa2 * half), (double)(py + ya * half), (double)(pz + za * half + za2 * half), (double)u0, (double)v0);
t->vertexUV((double)(px + xa * half - xa2 * half), (double)(py - ya * half), (double)(pz + za * half - za2 * half), (double)u0, (double)v1);
}
void BarrierParticle::tick()
{
xo = x;
yo = y;
zo = z;
if (++age >= lifetime)
remove();
xd = yd = zd = 0;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "Particle.h"
class BarrierParticle : public Particle
{
public:
virtual eINSTANCEOF GetType() { return eType_BARRIERPARTICLE; }
private:
void init(Level* level, double x, double y, double z, float scale);
public:
float oSize;
BarrierParticle(Level* level,
double x, double y, double z,
double xa, double ya, double za);
virtual int getParticleTexture();
virtual void render(Tesselator* t, float a, float xa, float ya, float za, float xa2, float za2);
virtual void tick();
};
+168 -102
View File
@@ -3,135 +3,201 @@
#include "../Minecraft.World/net.minecraft.world.level.h"
#include "BeaconRenderer.h"
#include "Tesselator.h"
#include <cmath>
#include"..\StainedGlassBlock.h"
#include"..\StainedGlassPaneBlock.h"
ResourceLocation BeaconRenderer::BEAM_LOCATION = ResourceLocation(TN_MISC_BEACON_BEAM);
bool BeaconRenderer::s_renderOuterHalo = false;
static float BEACON_COLORS[16][3] = {
{0.074f, 0.074f, 0.074f}, // 0: Black
{0.600f, 0.164f, 0.164f}, // 1: Red
{0.337f, 0.423f, 0.184f}, // 2: Green
{0.411f, 0.270f, 0.156f}, // 3: Brown
{0.203f, 0.286f, 0.611f}, // 4: Blue
{0.478f, 0.203f, 0.658f}, // 5: Purple
{0.298f, 0.501f, 0.600f}, // 6: Cyan
{0.623f, 0.623f, 0.623f}, // 7: Silver (Light Gray)
{0.298f, 0.298f, 0.298f}, // 8: Gray
{0.941f, 0.482f, 0.639f}, // 9: Pink
{0.501f, 0.752f, 0.125f}, // 10: Lime
{0.870f, 0.870f, 0.164f}, // 11: Yellow
{0.400f, 0.623f, 0.811f}, // 12: Light Blue
{0.701f, 0.325f, 0.823f}, // 13: Magenta
{0.850f, 0.478f, 0.235f}, // 14: Orange
{1.000f, 1.000f, 1.000f} // 15: White
};
void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y, double z, float a, bool setColor, float alpha, bool useCompiled)
{
shared_ptr<BeaconTileEntity> beacon = dynamic_pointer_cast<BeaconTileEntity>(_beacon);
shared_ptr<BeaconTileEntity> beacon = dynamic_pointer_cast<BeaconTileEntity>(_beacon);
if (!beacon) return;
float scale = beacon->getAndUpdateClientSideScale();
float scale = beacon->getAndUpdateClientSideScale();
if (scale <= 0) return;
if (scale > 0)
{
Tesselator *t = Tesselator::getInstance();
Tesselator *t = Tesselator::getInstance();
Level* level = beacon->getLevel();
bindTexture(&BEAM_LOCATION);
bindTexture(&BEAM_LOCATION);
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
float tt = (float)level->getGameTime() + a;
float texVOff = -tt * .20f - floor(-tt * .10f);
float tt = beacon->getLevel()->getGameTime() + a;
float texVOff = -tt * .20f - floor(-tt * .10f);
struct BeamSegment {
float r, g, b;
int height;
};
std::vector<BeamSegment> segments;
if (!s_renderOuterHalo)
{
glDisable(GL_BLEND);
glDepthMask(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
float curR = 1.0f, curG = 1.0f, curB = 1.0f;
int bx = beacon->x;
int by = beacon->y;
int bz = beacon->z;
bool firstGlass = true;
int r = 1;
for (int i = by + 1; i < 256; i++) {
int tileID = level->getTile(bx, i, bz);
if (tileID == Tile::stained_glass_Id || tileID == Tile::stained_glass_pane_Id) {
int meta = level->getData(bx, i, bz);
int colorIdx = StainedGlassBlock::getItemAuxValueForBlockData(meta);
if (firstGlass) {
curR = BEACON_COLORS[colorIdx][0];
curG = BEACON_COLORS[colorIdx][1];
curB = BEACON_COLORS[colorIdx][2];
firstGlass = false;
} else {
curR = (curR + BEACON_COLORS[colorIdx][0]) * 0.5f;
curG = (curG + BEACON_COLORS[colorIdx][1]) * 0.5f;
curB = (curB + BEACON_COLORS[colorIdx][2]) * 0.5f;
}
segments.push_back({curR, curG, curB, 1});
}
else if (tileID == 0 || tileID == Tile::glass_Id || tileID == Tile::thinGlass_Id) {
if (segments.empty()) {
segments.push_back({1.0f, 1.0f, 1.0f, 1});
} else {
segments.back().height++;
}
}
else {
if (Tile::tiles[tileID] && Tile::tiles[tileID]->blocksLight()) {
break;
}
else if (!segments.empty()) {
segments.back().height++;
}
}
}
double rot = tt * .025 * (1 - (r & 1) * 2.5);
if (segments.empty()) return;
t->begin();
t->color(255, 255, 255, 32);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(true);
double rr1 = r * 0.2;
double currentYBase = 0;
for (const auto& seg : segments) {
int r = (int)(seg.r * 255);
int g = (int)(seg.g * 255);
int b = (int)(seg.b * 255);
double wnx = .5 + cos(rot + PI * .75) * rr1;
double wnz = .5 + sin(rot + PI * .75) * rr1;
double enx = .5 + cos(rot + PI * .25) * rr1;
double enz = .5 + sin(rot + PI * .25) * rr1;
double rot = tt * .025 * (1 - (1 & 1) * 2.5);
double rr1 = 0.2;
double wsx = .5 + cos(rot + PI * 1.25) * rr1;
double wsz = .5 + sin(rot + PI * 1.25) * rr1;
double esx = .5 + cos(rot + PI * 1.75) * rr1;
double esz = .5 + sin(rot + PI * 1.75) * rr1;
double wnx = .5 + cos(rot + PI * .75) * rr1;
double wnz = .5 + sin(rot + PI * .75) * rr1;
double enx = .5 + cos(rot + PI * .25) * rr1;
double enz = .5 + sin(rot + PI * .25) * rr1;
double wsx = .5 + cos(rot + PI * 1.25) * rr1;
double wsz = .5 + sin(rot + PI * 1.25) * rr1;
double esx = .5 + cos(rot + PI * 1.75) * rr1;
double esz = .5 + sin(rot + PI * 1.75) * rr1;
double top = 256 * scale;
double yMin = currentYBase * scale;
double yMax = (currentYBase + seg.height) * scale;
double vv2 = currentYBase * scale * (0.5 / rr1) + texVOff;
double vv1 = (currentYBase + seg.height) * scale * (0.5 / rr1) + texVOff;
double uu1 = 0;
double uu2 = 1;
double vv2 = -1 + texVOff;
double vv1 = 256 * scale * (.5 / rr1) + vv2;
t->begin();
t->color(r, g, b, 255);
t->vertexUV(x + wnx, y + top, z + wnz, uu2, vv1);
t->vertexUV(x + wnx, y, z + wnz, uu2, vv2);
t->vertexUV(x + enx, y, z + enz, uu1, vv2);
t->vertexUV(x + enx, y + top, z + enz, uu1, vv1);
t->vertexUV(x + wnx, y + yMax, z + wnz, 1.0, vv1);
t->vertexUV(x + wnx, y + yMin, z + wnz, 1.0, vv2);
t->vertexUV(x + enx, y + yMin, z + enz, 0.0, vv2);
t->vertexUV(x + enx, y + yMax, z + enz, 0.0, vv1);
t->vertexUV(x + esx, y + yMax, z + esz, 1.0, vv1);
t->vertexUV(x + esx, y + yMin, z + esz, 1.0, vv2);
t->vertexUV(x + wsx, y + yMin, z + wsz, 0.0, vv2);
t->vertexUV(x + wsx, y + yMax, z + wsz, 0.0, vv1);
t->vertexUV(x + enx, y + yMax, z + enz, 1.0, vv1);
t->vertexUV(x + enx, y + yMin, z + enz, 1.0, vv2);
t->vertexUV(x + esx, y + yMin, z + esz, 0.0, vv2);
t->vertexUV(x + esx, y + yMax, z + esz, 0.0, vv1);
t->vertexUV(x + wsx, y + yMax, z + wsz, 1.0, vv1);
t->vertexUV(x + wsx, y + yMin, z + wsz, 1.0, vv2);
t->vertexUV(x + wnx, y + yMin, z + wnz, 0.0, vv2);
t->vertexUV(x + wnx, y + yMax, z + wnz, 0.0, vv1);
t->end();
t->vertexUV(x + esx, y + top, z + esz, uu2, vv1);
t->vertexUV(x + esx, y, z + esz, uu2, vv2);
t->vertexUV(x + wsx, y, z + wsz, uu1, vv2);
t->vertexUV(x + wsx, y + top, z + wsz, uu1, vv1);
currentYBase += seg.height;
}
t->vertexUV(x + enx, y + top, z + enz, uu2, vv1);
t->vertexUV(x + enx, y, z + enz, uu2, vv2);
t->vertexUV(x + esx, y, z + esz, uu1, vv2);
t->vertexUV(x + esx, y + top, z + esz, uu1, vv1);
glDepthMask(false);
t->vertexUV(x + wsx, y + top, z + wsz, uu2, vv1);
t->vertexUV(x + wsx, y, z + wsz, uu2, vv2);
t->vertexUV(x + wnx, y, z + wnz, uu1, vv2);
t->vertexUV(x + wnx, y + top, z + wnz, uu1, vv1);
currentYBase = 0;
for (const auto& seg : segments) {
int r = (int)(seg.r * 255);
int g = (int)(seg.g * 255);
int b = (int)(seg.b * 255);
t->end();
}
else
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(false);
double yMin = currentYBase * scale;
double yMax = (currentYBase + seg.height) * scale;
double vv2 = currentYBase * scale + texVOff;
double vv1 = (currentYBase + seg.height) * scale + texVOff;
t->begin();
t->color(255, 255, 255, 32);
t->begin();
t->color(r, g, b, 32);
double wnx = .2;
double wnz = .2;
double enx = .8;
double enz = .2;
t->vertexUV(x + 0.2, y + yMax, z + 0.2, 1.0, vv1);
t->vertexUV(x + 0.2, y + yMin, z + 0.2, 1.0, vv2);
t->vertexUV(x + 0.8, y + yMin, z + 0.2, 0.0, vv2);
t->vertexUV(x + 0.8, y + yMax, z + 0.2, 0.0, vv1);
t->vertexUV(x + 0.8, y + yMax, z + 0.8, 1.0, vv1);
t->vertexUV(x + 0.8, y + yMin, z + 0.8, 1.0, vv2);
t->vertexUV(x + 0.2, y + yMin, z + 0.8, 0.0, vv2);
t->vertexUV(x + 0.2, y + yMax, z + 0.8, 0.0, vv1);
t->vertexUV(x + 0.8, y + yMax, z + 0.2, 1.0, vv1);
t->vertexUV(x + 0.8, y + yMin, z + 0.2, 1.0, vv2);
t->vertexUV(x + 0.8, y + yMin, z + 0.8, 0.0, vv2);
t->vertexUV(x + 0.8, y + yMax, z + 0.8, 0.0, vv1);
t->vertexUV(x + 0.2, y + yMax, z + 0.8, 1.0, vv1);
t->vertexUV(x + 0.2, y + yMin, z + 0.8, 1.0, vv2);
t->vertexUV(x + 0.2, y + yMin, z + 0.2, 0.0, vv2);
t->vertexUV(x + 0.2, y + yMax, z + 0.2, 0.0, vv1);
t->end();
double wsx = .2;
double wsz = .8;
double esx = .8;
double esz = .8;
currentYBase += seg.height;
}
double top = 256 * scale;
double uu1 = 0;
double uu2 = 1;
double vv2 = -1 + texVOff;
double vv1 = 256 * scale + vv2;
t->vertexUV(x + wnx, y + top, z + wnz, uu2, vv1);
t->vertexUV(x + wnx, y, z + wnz, uu2, vv2);
t->vertexUV(x + enx, y, z + enz, uu1, vv2);
t->vertexUV(x + enx, y + top, z + enz, uu1, vv1);
t->vertexUV(x + esx, y + top, z + esz, uu2, vv1);
t->vertexUV(x + esx, y, z + esz, uu2, vv2);
t->vertexUV(x + wsx, y, z + wsz, uu1, vv2);
t->vertexUV(x + wsx, y + top, z + wsz, uu1, vv1);
t->vertexUV(x + enx, y + top, z + enz, uu2, vv1);
t->vertexUV(x + enx, y, z + enz, uu2, vv2);
t->vertexUV(x + esx, y, z + esz, uu1, vv2);
t->vertexUV(x + esx, y + top, z + esz, uu1, vv1);
t->vertexUV(x + wsx, y + top, z + wsz, uu2, vv1);
t->vertexUV(x + wsx, y, z + wsz, uu2, vv2);
t->vertexUV(x + wnx, y, z + wnz, uu1, vv2);
t->vertexUV(x + wnx, y + top, z + wnz, uu1, vv1);
t->end();
}
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glDepthMask(true);
}
glDepthMask(true);
glDisable(GL_BLEND);
}
-2
View File
@@ -9,7 +9,5 @@ private:
static ResourceLocation BEAM_LOCATION;
public:
static bool s_renderOuterHalo;
virtual void render(shared_ptr<TileEntity> _beacon, double x, double y, double z, float a, bool setColor, float alpha, bool useCompiled);
};
+17 -8
View File
@@ -1,16 +1,25 @@
#include "stdafx.h"
#include "BossMobGuiInfo.h"
#include "../Minecraft.World/BossMob.h"
#include "../Minecraft.World/LevelData.h"
float BossMobGuiInfo::healthProgress = 0.0f;
int BossMobGuiInfo::displayTicks = 0;
wstring BossMobGuiInfo::name = L"";
bool BossMobGuiInfo::darkenWorld = false;
float BossMobGuiInfo::healthProgress[3] = { 0.0f, 0.0f, 0.0f };
int BossMobGuiInfo::displayTicks[3] = { 0, 0, 0 };
wstring BossMobGuiInfo::name[3];
bool BossMobGuiInfo::darkenWorld[3] = { false, false, false };
void BossMobGuiInfo::setBossHealth(shared_ptr<BossMob> boss, bool darkenWorld)
{
healthProgress = (float) boss->getHealth() / (float) boss->getMaxHealth();
displayTicks = SharedConstants::TICKS_PER_SECOND * 5;
name = boss->getAName();
BossMobGuiInfo::darkenWorld = darkenWorld;
int idx = getIndexFromDimension(boss->getDimension());
healthProgress[idx] = (float) boss->getHealth() / (float) boss->getMaxHealth();
displayTicks[idx] = SharedConstants::TICKS_PER_SECOND * 5;
name[idx] = boss->getAName();
BossMobGuiInfo::darkenWorld[idx] = darkenWorld;
}
int BossMobGuiInfo::getIndexFromDimension(int dimension)
{
if (dimension == LevelData::DIMENSION_NETHER) return 1;
if (dimension == LevelData::DIMENSION_END) return 2;
return 0;
}
+6 -4
View File
@@ -5,10 +5,12 @@ class BossMob;
class BossMobGuiInfo
{
public:
static float healthProgress;
static int displayTicks;
static wstring name;
static bool darkenWorld;
static float healthProgress[3];
static int displayTicks[3];
static wstring name[3];
static bool darkenWorld[3];
static void setBossHealth(shared_ptr<BossMob> boss, bool darkenWorld);
static int getIndexFromDimension(int dimension);
};
+82 -24
View File
@@ -21,13 +21,34 @@ set(MINECRAFT_CLIENT_SOURCES
$<$<STREQUAL:${PLATFORM_NAME},Windows64>:${MINECRAFT_CLIENT_WINDOWS}>
$<$<STREQUAL:${PLATFORM_NAME},Xbox>:${MINECRAFT_CLIENT_XBOX360}>
${SOURCES_COMMON}
"${CMAKE_SOURCE_DIR}/Minecraft.Client/Common/StringUtils.cpp"
)
add_executable(Minecraft.Client ${MINECRAFT_CLIENT_SOURCES})
set(MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}Media/strings.h")
if(PLATFORM_NAME STREQUAL "Windows64")
set(MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER "${CMAKE_BINARY_DIR}/generated/Windows64Media/strings.h")
file(GLOB_RECURSE MINECRAFT_CLIENT_WINDOWS_LOCALIZATION_XML CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/Windows64Media/loc/*.xml"
)
add_executable(Minecraft.Client ${MINECRAFT_CLIENT_SOURCES} "Common/UI/UIScene_AchievementsMenu.cpp" "Common/UI/UIScene_AchievementsMenu.h" "Common/UI/UIControl_AchievementsList.cpp" "Common/UI/UIControl_AchievementsList.h" "Windows64/NetworkHelpers.h" "Windows64/NetworkHelpers.cpp" "Windows64/Windows64_Launcher.cpp" "Windows64/Windows64_Launcher.h"
)
add_custom_command(
OUTPUT "${MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER}"
COMMAND ${CMAKE_COMMAND}
"-DXML_ROOT=${CMAKE_CURRENT_SOURCE_DIR}/Windows64Media/loc"
"-DOUTPUT_FILE=${MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER}"
-P "${CMAKE_SOURCE_DIR}/cmake/GenerateStringsHeaderFromXml.cmake"
DEPENDS
${MINECRAFT_CLIENT_WINDOWS_LOCALIZATION_XML}
"${CMAKE_SOURCE_DIR}/cmake/GenerateStringsHeaderFromXml.cmake"
COMMENT "Generating compile-time string IDs from XML"
VERBATIM
)
add_custom_target(GenerateStringsHeader_Minecraft.Client DEPENDS "${MINECRAFT_CLIENT_COMPILETIME_STRINGS_HEADER}")
set_property(TARGET GenerateStringsHeader_Minecraft.Client PROPERTY FOLDER "Build")
add_dependencies(Minecraft.Client GenerateStringsHeader_Minecraft.Client)
add_dependencies(Minecraft.Client GenerateStringIdLookup)
endif()
# Only define executable on windows
if(PLATFORM_NAME STREQUAL "Windows64")
@@ -35,12 +56,12 @@ if(PLATFORM_NAME STREQUAL "Windows64")
endif()
target_include_directories(Minecraft.Client PRIVATE
"${CMAKE_BINARY_DIR}/generated/" # This is for the generated BuildVer.h
"${CMAKE_BINARY_DIR}/generated" # This is for the generated BuildVer.h
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/Iggy/include"
"${CMAKE_SOURCE_DIR}/include/"
"${CMAKE_CURRENT_SOURCE_DIR}/Windows64/ExtraLibs/webview2/build/native/include"
"${CMAKE_SOURCE_DIR}/include"
)
target_compile_definitions(Minecraft.Client PRIVATE
${MINECRAFT_SHARED_DEFINES}
)
@@ -49,28 +70,45 @@ set_source_files_properties(compat_shims.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS
configure_compiler_target(Minecraft.Client)
set(MINECRAFT_CLIENT_USE_4J_DEBUG_LIBS TRUE)
if(CMAKE_CROSSCOMPILING AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(MINECRAFT_CLIENT_USE_4J_DEBUG_LIBS FALSE)
endif()
set_target_properties(Minecraft.Client PROPERTIES
OUTPUT_NAME "Minecraft.Client"
VS_DEBUGGER_WORKING_DIRECTORY "$<TARGET_FILE_DIR:Minecraft.Client>"
)
target_link_libraries(Minecraft.Client PRIVATE
Minecraft.World
d3d11
dxgi
d3dcompiler
XInput9_1_0
wsock32
legacy_stdio_definitions
4JLibs.${PLATFORM_NAME}.Input
4JLibs.${PLATFORM_NAME}.Profile
4JLibs.${PLATFORM_NAME}.Storage
4JLibs.${PLATFORM_NAME}.Render
$<$<STREQUAL:${PLATFORM_NAME},Windows64>:${CMAKE_CURRENT_SOURCE_DIR}/Windows64/ExtraLibs/discordsdk/discord_game_sdk.dll.lib>
$<$<STREQUAL:${PLATFORM_NAME},Windows64>:${CMAKE_CURRENT_SOURCE_DIR}/Windows64/ExtraLibs/webview2/build/native/x64/WebView2LoaderStatic.lib>
$<$<STREQUAL:${PLATFORM_NAME},Windows64>:shlwapi>
$<$<STREQUAL:${PLATFORM_NAME},Windows64>:ole32>
)
if(MINECRAFT_CLIENT_USE_4J_DEBUG_LIBS)
target_link_libraries(Minecraft.Client PRIVATE
Minecraft.World
d3d11
dxgi
d3dcompiler
XInput9_1_0
wsock32
legacy_stdio_definitions
4JLibs.${PLATFORM_NAME}.Input
4JLibs.${PLATFORM_NAME}.Profile
4JLibs.${PLATFORM_NAME}.Storage
4JLibs.${PLATFORM_NAME}.Render
$<$<STREQUAL:${PLATFORM_NAME},Windows64>:${CMAKE_CURRENT_SOURCE_DIR}/Windows64/ExtraLibs/discordsdk/discord_game_sdk.dll.lib>
)
else()
target_link_libraries(Minecraft.Client PRIVATE
Minecraft.World
d3d11
dxgi
d3dcompiler
XInput9_1_0
wsock32
legacy_stdio_definitions
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/4JLibs/libs/4J_Input.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/4JLibs/libs/4J_Storage.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/4JLibs/libs/4J_Render_PC.lib"
)
endif()
# Iggy libs
foreach(lib IN LISTS IGGY_LIBS)
@@ -89,6 +127,25 @@ set(ASSET_FOLDER_PAIRS
)
setup_asset_folder_copy(Minecraft.Client "${ASSET_FOLDER_PAIRS}")
# copy prebuilt loc folder and use it lmao
if(PLATFORM_NAME STREQUAL "Windows64")
add_custom_target(AssetLocalizationCopy_Minecraft.Client ALL
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Common/Localization/strings.h"
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Common/Localization/4J_strings.h"
COMMAND ${CMAKE_COMMAND}
"-DCOPY_SOURCE=${CMAKE_CURRENT_SOURCE_DIR}/Windows64Media/loc"
"-DCOPY_DEST=$<TARGET_FILE_DIR:Minecraft.Client>/Common/Localization"
-P "${CMAKE_SOURCE_DIR}/cmake/CopyFolderScript.cmake"
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Windows64Media/strings.h"
COMMAND ${CMAKE_COMMAND} -E rm -f "$<TARGET_FILE_DIR:Minecraft.Client>/Windows64Media/4J_strings.h"
COMMENT "Copying language files into build folder..."
VERBATIM
)
add_dependencies(Minecraft.Client AssetLocalizationCopy_Minecraft.Client)
set_property(TARGET AssetLocalizationCopy_Minecraft.Client PROPERTY FOLDER "Build")
endif()
# Copy redist files
add_copyredist_target(Minecraft.Client)
@@ -96,3 +153,4 @@ add_copyredist_target(Minecraft.Client)
if(PLATFORM_NAME STREQUAL "Windows64")
add_gamehdd_target(Minecraft.Client)
endif()
-1
View File
@@ -161,7 +161,6 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
{
message.insert(cursorIndex, 1, ch);
cursorIndex++;
{ char buf[64]; sprintf_s(buf, "[CHAT] Char U+%04X accepted (%d chars)\n", (unsigned)ch, (int)message.length()); OutputDebugStringA(buf); }
}
}
+34 -14
View File
@@ -214,7 +214,7 @@ void Chunk::rebuild()
int r = 1;
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2;
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * LevelRenderer::CHUNK_RENDER_LAYERS;
lists += levelRenderer->chunkLists;
PIXEndNamedEvent();
@@ -329,6 +329,7 @@ void Chunk::rebuild()
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
RenderManager.CBuffClear(lists + currentLayer);
}
RenderManager.CBuffClear(lists + 2);
delete region;
delete tileRenderer;
@@ -349,7 +350,7 @@ void Chunk::rebuild()
bounds.boundingBox[4] = SIZE+g;
bounds.boundingBox[5] = XZSIZE+g;
}
for (int currentLayer = 0; currentLayer < 2; currentLayer++)
for (int currentLayer = 0; currentLayer < LevelRenderer::CHUNK_RENDER_LAYERS; currentLayer++)
{
bool renderNextLayer = false;
bool rendered = false;
@@ -413,7 +414,7 @@ void Chunk::rebuild()
}
int renderLayer = tile->getRenderLayer();
if (renderLayer != currentLayer)
if (renderLayer > currentLayer)
{
renderNextLayer = true;
}
@@ -456,18 +457,30 @@ void Chunk::rebuild()
if (rendered)
{
levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
if (currentLayer < 2)
{
levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
}
}
else
{
// 4J - added - clear any renderer data associated with this unused list
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
if (currentLayer < 2)
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
}
RenderManager.CBuffClear(lists + currentLayer);
}
if((currentLayer==0)&&(!renderNextLayer))
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY1);
RenderManager.CBuffClear(lists + 1);
RenderManager.CBuffClear(lists + 2);
break;
}
if((currentLayer==1)&&(!renderNextLayer))
{
RenderManager.CBuffClear(lists + 2);
break;
}
}
@@ -670,7 +683,7 @@ void Chunk::rebuild_SPU()
Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r, r);
TileRenderer tileRenderer(&region);
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2;
int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * LevelRenderer::CHUNK_RENDER_LAYERS;
lists += levelRenderer->chunkLists;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -695,7 +708,7 @@ void Chunk::rebuild_SPU()
bounds.boundingBox[5] = SIZE+g;
}
for (int currentLayer = 0; currentLayer < 2; currentLayer++)
for (int currentLayer = 0; currentLayer < LevelRenderer::CHUNK_RENDER_LAYERS; currentLayer++)
{
bool rendered = false;
@@ -757,7 +770,7 @@ void Chunk::rebuild_SPU()
if (!tile) continue;
int renderLayer = tile->getRenderLayer();
if (renderLayer != currentLayer)
if (renderLayer > currentLayer)
{
// renderNextLayer = true;
}
@@ -784,12 +797,18 @@ void Chunk::rebuild_SPU()
}
if (rendered)
{
levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
if (currentLayer < 2)
{
levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
}
}
else
{
// 4J - added - clear any renderer data associated with this unused list
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
if (currentLayer < 2)
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
}
RenderManager.CBuffClear(lists + currentLayer);
}
@@ -961,11 +980,11 @@ void Chunk::reset()
// printf("\t\t [dec] refcount %d at %d, %d, %d\n",refCount,x,y,z);
if( refCount == 0 )
{
int lists = levelRenderer->getGlobalIndexForChunk(x, y, z, level) * 2;
int lists = levelRenderer->getGlobalIndexForChunk(x, y, z, level) * LevelRenderer::CHUNK_RENDER_LAYERS;
if(lists >= 0)
{
lists += levelRenderer->chunkLists;
for (int i = 0; i < 2; i++)
for (int i = 0; i < LevelRenderer::CHUNK_RENDER_LAYERS; i++)
{
// 4J - added - clear any renderer data associated with this unused list
RenderManager.CBuffClear(lists + i);
@@ -987,12 +1006,13 @@ void Chunk::_delete()
int Chunk::getList(int layer)
{
if (layer < 0 || layer >= LevelRenderer::CHUNK_RENDER_LAYERS) return -1;
if (!clipChunk->visible) return -1;
int lists = levelRenderer->getGlobalIndexForChunk(x, y, z,level) * 2;
int lists = levelRenderer->getGlobalIndexForChunk(x, y, z,level) * LevelRenderer::CHUNK_RENDER_LAYERS;
lists += levelRenderer->chunkLists;
bool empty = levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer);
bool empty = (layer < 2) && levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer);
if (!empty) return lists + layer;
return -1;
}
+73 -33
View File
@@ -61,6 +61,8 @@
#include "Windows64/Network/WinsockNetLayer.h"
#endif
#include "../Minecraft.World/Recipes.h"
#ifdef _DURANGO
#include "../Minecraft.World/DurangoStats.h"
@@ -137,6 +139,9 @@ ClientConnection::ClientConnection(Minecraft *minecraft, Socket *socket, int iUs
maxPlayers = 20;
m_isForkServer = false;
m_recivedRecipeRegistyUpdate = false;
m_recivedCreativeRegistyUpdate = false;
this->minecraft = minecraft;
if( iUserIndex < 0 )
@@ -246,6 +251,14 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
{
if (done) return;
if (!m_recivedRecipeRegistyUpdate) {
Recipes::getInstance()->loadFromLocal();
}
if (!m_recivedCreativeRegistyUpdate) {
IUIScene_CreativeMenu::loadFromLocal();
}
PlayerUID OnlineXuid;
ProfileManager.GetXUID(m_userIndex,&OnlineXuid,true); // online xuid
MOJANG_DATA *pMojangData = nullptr;
@@ -3897,27 +3910,6 @@ void ClientConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> custo
return;
}
// Stream cipher handshake: server sent us a key
if (CustomPayloadPacket::CIPHER_KEY_CHANNEL.compare(customPayloadPacket->identifier) == 0)
{
if (customPayloadPacket->length == ServerRuntime::Security::StreamCipher::KEY_SIZE &&
customPayloadPacket->data.data != nullptr)
{
app.DebugPrintf("Client: Received MC|CKey from server (%d bytes)\n", customPayloadPacket->length);
// Store key and send ack+activate atomically to prevent ResetClientCipher race
WinsockNetLayer::StoreClientCipherKey(customPayloadPacket->data.data);
if (!WinsockNetLayer::SendAckAndActivateClientSendCipher())
{
app.DebugPrintf("Client: Failed to send cipher ack, connection will be closed\n");
}
}
else
{
app.DebugPrintf("Client: Received malformed MC|CKey (length=%d)\n", customPayloadPacket->length);
}
return;
}
// Fork server identification: enables render-distance-independent player list
if (CustomPayloadPacket::FORK_HELLO_CHANNEL.compare(customPayloadPacket->identifier) == 0)
{
@@ -3989,6 +3981,52 @@ void ClientConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> custo
trader->overrideOffers(recipeList);
}
}
else if (CustomPayloadPacket::ENCHANTMENT_LIST_PACKET.compare(customPayloadPacket->identifier) == 0) {
ByteArrayInputStream bais(customPayloadPacket->data);
DataInputStream input(&bais);
bool done = false;
int l = 0;
bool firstInGroup = true;
EnchantmentEntry temp;
//int firstAmount = input.readInt();
while (!done) {
int a = input.readInt();
if (a == -1) {
minecraft->localplayers[m_userIndex]->enchantmentEntries[l] = temp;
l++;
firstInGroup = true;
}
else if (a == -2) {
done = true;
}
else if (a == -4) {
for (int i = 0; i < 3; i++) {
minecraft->localplayers[m_userIndex]->enchantmentEntries[i].id = -3;
}
done = true;
}
else {
if (firstInGroup) {
temp.id = a;
temp.level = input.readInt();
firstInGroup = false;
}
else {
input.readInt();
}
}
}
}
else if (CustomPayloadPacket::UPDATE_RECIPE_REGISTRY.compare(customPayloadPacket->identifier) == 0) {
this->m_recivedRecipeRegistyUpdate = true;
Recipes::getInstance()->loadFromPacket(customPayloadPacket->data);
}
else if (CustomPayloadPacket::UPDATE_CREATIVE_REGISTRY.compare(customPayloadPacket->identifier) == 0) {
this->m_recivedCreativeRegistyUpdate = true;
IUIScene_CreativeMenu::loadFromPacket(customPayloadPacket->data);
}
}
Connection *ClientConnection::getConnection()
@@ -4264,20 +4302,22 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket>
void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet)
{
wstring particleName = packet->getName();
ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)Integer::parseInt(particleName);
const ParticleType* type = packet->getType();
if (type == nullptr) return;
for (int i = 0; i < packet->getCount(); i++)
{
double xVarience = random->nextGaussian() * packet->getXDist();
double yVarience = random->nextGaussian() * packet->getYDist();
double zVarience = random->nextGaussian() * packet->getZDist();
double xa = random->nextGaussian() * packet->getMaxSpeed();
double ya = random->nextGaussian() * packet->getMaxSpeed();
double za = random->nextGaussian() * packet->getMaxSpeed();
ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)type->getId();
level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za);
}
for (int i = 0; i < packet->getCount(); i++)
{
double xVarience = random->nextGaussian() * packet->getXDist();
double yVarience = random->nextGaussian() * packet->getYDist();
double zVarience = random->nextGaussian() * packet->getZDist();
double xa = random->nextGaussian() * packet->getMaxSpeed();
double ya = random->nextGaussian() * packet->getMaxSpeed();
double za = random->nextGaussian() * packet->getMaxSpeed();
level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za);
}
}
void ClientConnection::handleUpdateAttributes(shared_ptr<UpdateAttributesPacket> packet)
+2
View File
@@ -49,6 +49,8 @@ private:
std::unordered_set<int> m_trackedEntityIds;
std::unordered_set<int64_t> m_visibleChunks;
bool m_isForkServer; // true when connected to a fork server (received MC|ForkHello)
bool m_recivedRecipeRegistyUpdate;
bool m_recivedCreativeRegistyUpdate;
static int64_t chunkKey(int x, int z) { return ((int64_t)x << 32) | ((int64_t)z & 0xFFFFFFFF); }
+9 -9
View File
@@ -1,13 +1,13 @@
#include "stdafx.h"
#include "ClientConstants.h"
#include <string>
#include "Common/BuildVer.h"
const wchar_t* ClientConstants::LCEN_HOST = L"";
const wstring ClientConstants::VERSION_STRING = wstring(L"Minecraft LCE ") + VER_FILEVERSION_STR_W;//+ SharedConstants::VERSION_STRING;
const wstring ClientConstants::BRANCH_STRING = VER_BRANCHVERSION_STR_W;
const std::wstring ClientConstants::VERSION_STRING =
L"Minecraft: Legacy Network Beta Build 2026.06.14-128 [DO NOT DISTRIBUTE]";
std::wstring ClientConstants::GetLCENString()
{
return L"";
}
// Default value for the toggle. If BuildVer defines VER_SHOW_VERSION_WATERMARK, use that.
#ifdef VER_SHOW_VERSION_WATERMARK
const bool ClientConstants::SHOW_VERSION_WATERMARK = (VER_SHOW_VERSION_WATERMARK != 0);
#else
const bool ClientConstants::SHOW_VERSION_WATERMARK = false;
#endif
+4 -3
View File
@@ -13,9 +13,10 @@ class ClientConstants
// INTERNAL DEVELOPMENT SETTINGS
public:
static const wstring VERSION_STRING;
static const wstring LCEN_STRING;
static const wchar_t* LCEN_HOST;
static std::wstring GetLCENString();
static const wstring BRANCH_STRING;
// Toggle to show/hide the version/branch watermark in the debug overlay
static const bool SHOW_VERSION_WATERMARK;
static const bool DEADMAU5_CAMERA_CHEATS = false;
};
+2
View File
@@ -107,6 +107,8 @@ enum EGameHostOptionWorldSize
#define GAMESETTING_PSVITANETWORKMODEADHOC 0x00020000
#define GAMESETTING_VSYNC 0x01000000
#define GAMESETTING_EXCLUSIVEFULLSCREEN 0x02000000
#define GAMESETTING_CLASSICCRAFTING 0x04000000
#define GAMESETTING_HIDESAVESIZEBAR 0x08000000
// defines for languages
+21 -1
View File
@@ -182,6 +182,10 @@ enum eGameSetting
eGameSetting_VSync,
eGameSetting_ExclusiveFullscreen,
//TU25
eGameSetting_ClassicCrafting,
// if enabled hides the save size bar in loadcreatejoinmenu (load tab)
eGameSetting_HideSaveSizeBar,
};
@@ -224,6 +228,9 @@ enum eMinecraftColour
eMinecraftColour_Foliage_ExtremeHillsEdge,
eMinecraftColour_Foliage_Jungle,
eMinecraftColour_Foliage_JungleHills,
eMinecraftColour_Foliage_Savanna,
eMinecraftColour_Foliage_RoofedForest,
eMinecraftColour_Foliage_Mesa,
eMinecraftColour_Grass_Common,
eMinecraftColour_Grass_Ocean,
@@ -249,6 +256,9 @@ enum eMinecraftColour
eMinecraftColour_Grass_ExtremeHillsEdge,
eMinecraftColour_Grass_Jungle,
eMinecraftColour_Grass_JungleHills,
eMinecraftColour_Grass_Savanna,
eMinecraftColour_Grass_RoofedForest,
eMinecraftColour_Grass_Mesa,
eMinecraftColour_Water_Ocean,
eMinecraftColour_Water_Plains,
@@ -273,6 +283,7 @@ enum eMinecraftColour
eMinecraftColour_Water_ExtremeHillsEdge,
eMinecraftColour_Water_Jungle,
eMinecraftColour_Water_JungleHills,
eMinecraftColour_Water_Mesa,
eMinecraftColour_Sky_Ocean,
eMinecraftColour_Sky_Plains,
@@ -441,6 +452,14 @@ enum eMinecraftColour
eMinecraftColour_Mob_Witch_Colour2,
eMinecraftColour_Mob_Horse_Colour1,
eMinecraftColour_Mob_Horse_Colour2,
eMinecraftColour_Mob_Rabbit_Colour1,
eMinecraftColour_Mob_Rabbit_Colour2,
eMinecraftColour_Mob_Endermite_Colour1,
eMinecraftColour_Mob_Endermite_Colour2,
eMinecraftColour_Mob_Guardian_Colour1,
eMinecraftColour_Mob_Guardian_Colour2,
eMinecraftColour_Mob_ElderGuardian_Colour1,
eMinecraftColour_Mob_ElderGuardian_Colour2,
eMinecraftColour_Armour_Default_Leather_Colour,
@@ -610,6 +629,7 @@ enum _eTerrainFeatureType
eTerrainFeature_Ravine,
eTerrainFeature_NetherFortress,
eTerrainFeature_StrongholdEndPortal,
eTerrainFeature_OceanMonument,
eTerrainFeature_Count
};
@@ -953,4 +973,4 @@ enum eMCLang
eMCLang_hans,
eMCLang_hant,
};
};
+280 -251
View File
@@ -1,6 +1,8 @@
#include "stdafx.h"
#include "stdafx.h"
#include "SoundEngine.h"
#include "BossMobGuiInfo.h"
#include "../Consoles_App.h"
#include "../../MultiPlayerLocalPlayer.h"
#include "../../../Minecraft.World/net.minecraft.world.level.h"
@@ -8,8 +10,6 @@
#include "../../Minecraft.World/Mth.h"
#include "../../TexturePackRepository.h"
#include "../../DLCTexturePack.h"
#include "../../MultiPlayerGameMode.h"
#include "../../Minecraft.World/LevelSettings.h"
#include "Common/DLC/DLCAudioFile.h"
#ifdef __PSVITA__
@@ -116,11 +116,7 @@ const char *SoundEngine::m_szStreamFileA[eStream_Max]=
"hal4",
"nuance1",
"nuance2",
"piano1",
"piano2",
"piano3",
#ifndef _XBOX
"creative1",
"creative2",
"creative3",
@@ -131,7 +127,10 @@ const char *SoundEngine::m_szStreamFileA[eStream_Max]=
"menu2",
"menu3",
"menu4",
#endif
"piano1",
"piano2",
"piano3",
// Nether
"nether1",
@@ -142,6 +141,12 @@ const char *SoundEngine::m_szStreamFileA[eStream_Max]=
// The End
"the_end_dragon_alive",
"the_end_end",
// Battle
"BattleMode1",
"BattleMode2",
"BattleMode3",
"BattleMode4",
// CDs
"11",
@@ -192,7 +197,7 @@ void SoundEngine::init(Options* pOptions)
return;
}
void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1)
void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCreativeMin, int iCreativeMax, int iMenuMin, int iMenuMax, int iBattleMin, int iBattleMax, int iCD1)
{
m_iStream_Overworld_Min=iOverworldMin;
m_iStream_Overworld_Max=iOverWorldMax;
@@ -200,6 +205,12 @@ void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int i
m_iStream_Nether_Max=iNetherMax;
m_iStream_End_Min=iEndMin;
m_iStream_End_Max=iEndMax;
m_iStream_Creative_Min = iCreativeMin;
m_iStream_Creative_Max = iCreativeMax;
m_iStream_Menu_Min = iMenuMin;
m_iStream_Menu_Max = iMenuMax;
m_iStream_Battle_Min = iBattleMin;
m_iStream_Battle_Max = iBattleMax;
m_iStream_CD_1=iCD1;
// array to monitor recently played tracks
@@ -314,6 +325,22 @@ void SoundEngine::updateMiniAudio()
}
}
/////////////////////////////////////////////
//
// getGameModeMusicID
//
/////////////////////////////////////////////
inline void SoundEngine::getGameModeMusicID(Minecraft* pMinecraft, unsigned int i)
{
if (pMinecraft->localplayers[i] != nullptr && pMinecraft->localplayers[i]->abilities.instabuild && pMinecraft->localplayers[i]->abilities.mayfly)
m_musicID = getMusicID(eMusicType_Creative);
// TODO(3UR): this is a part of minigames also in the future other minigame ids will need to be handled for now TU30 only checks for BATTLE
//else if (pMinecraft->GetCustomGameMode() && CustomGameModeInst::GetId() == EMiniGameId::BATTLE) // @3UR: thanks https://github.com/GRAnimated/MinecraftLCE/blob/6947670d152582457bfe02bd909ee30a7ab7eb55/src/Minecraft.World/net/minecraft/world/level/gamemode/minigames/EMiniGameId.h#L3
// m_musicID = getMusicID(eMusicType_Battle);
else
m_musicID = getMusicID(eMusicType_Overworld);
}
/////////////////////////////////////////////
//
// tick
@@ -405,19 +432,15 @@ SoundEngine::SoundEngine()
m_bHeardTrackA=nullptr;
// Start the streaming music playing some music from the overworld
SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3,
eStream_Nether1,eStream_Nether4,
eStream_end_dragon,eStream_end_end,
eStream_CD_1);
SetStreamingSounds(eStream_Overworld_Calm1, eStream_Overworld_piano3,
eStream_Nether1, eStream_Nether4,
eStream_end_dragon, eStream_end_end,
eStream_Overworld_Creative1, eStream_Overworld_Creative6,
eStream_Overworld_Menu1, eStream_Overworld_Menu4,
eStream_BattleMode1, eStream_BattleMode4,
eStream_CD_1);
#ifndef _XBOX
m_iStream_Creative_Min = eStream_Overworld_Creative1;
m_iStream_Creative_Max = eStream_Overworld_Creative6;
m_iStream_Menu_Min = eStream_Overworld_Menu1;
m_iStream_Menu_Max = eStream_Overworld_Menu4;
#endif
m_musicID=getMusicID(LevelData::DIMENSION_OVERWORLD);
m_musicID = getMusicID(eMusicType_Menu);
m_StreamingAudioInfo.bIs3D=false;
m_StreamingAudioInfo.x=0;
@@ -476,69 +499,65 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume, floa
sprintf_s(basePath, "Windows64Media/Sound/%s", (char*)szSoundName);
char finalPath[256];
sprintf_s(finalPath, "%s.wav", basePath);
// Check path cache first to avoid expensive filesystem probing
auto cacheIt = m_soundPathCache.find(iSound);
if (cacheIt != m_soundPathCache.end())
const char* extensions[] = { ".ogg", ".wav", ".mp3" };
size_t extCount = sizeof(extensions) / sizeof(extensions[0]);
bool found = false;
for (size_t extIdx = 0; extIdx < extCount; extIdx++)
{
const auto& paths = cacheIt->second;
if (paths.empty())
return; // previously probed, no files found
const std::string& chosen = paths[rand() % paths.size()];
sprintf_s(finalPath, "%s", chosen.c_str());
char basePlusExt[256];
sprintf_s(basePlusExt, "%s%s", basePath, extensions[extIdx]);
DWORD attr = GetFileAttributesA(basePlusExt);
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
{
sprintf_s(finalPath, "%s", basePlusExt);
found = true;
break;
}
}
else
{
// Cache miss — probe filesystem and store results
std::vector<std::string> validPaths;
const char* extensions[] = { ".ogg", ".wav", ".mp3" };
size_t extCount = sizeof(extensions) / sizeof(extensions[0]);
bool found = false;
// Check base name with each extension (non-numbered)
if (!found)
{
int count = 0;
for (size_t extIdx = 0; extIdx < extCount; extIdx++)
{
char basePlusExt[256];
sprintf_s(basePlusExt, "%s%s", basePath, extensions[extIdx]);
DWORD attr = GetFileAttributesA(basePlusExt);
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
for (size_t i = 1; i < 32; i++)
{
validPaths.push_back(basePlusExt);
found = true;
break; // non-numbered: only one base file needed
}
}
if (!found)
{
// Check numbered variants (e.g. sound1.ogg, sound2.ogg, ...)
for (size_t extIdx = 0; extIdx < extCount; extIdx++)
{
for (int i = 1; i < 32; i++)
char numberedPath[256];
sprintf_s(numberedPath, "%s%d%s", basePath, i, extensions[extIdx]);
DWORD attr = GetFileAttributesA(numberedPath);
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
{
char numberedPath[256];
sprintf_s(numberedPath, "%s%d%s", basePath, i, extensions[extIdx]);
DWORD attr = GetFileAttributesA(numberedPath);
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
{
validPaths.push_back(numberedPath);
}
count = i;
}
}
}
m_soundPathCache[iSound] = validPaths;
if (validPaths.empty())
if (count > 0)
{
sprintf_s(finalPath, "%s.wav", basePath); // fallback for debug print
}
else
{
const std::string& chosen = validPaths[rand() % validPaths.size()];
sprintf_s(finalPath, "%s", chosen.c_str());
int chosen = (rand() % count) + 1;
for (size_t extIdx = 0; extIdx < extCount; extIdx++)
{
char numberedPath[256];
sprintf_s(numberedPath, "%s%d%s", basePath, chosen, extensions[extIdx]);
DWORD attr = GetFileAttributesA(numberedPath);
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
{
sprintf_s(finalPath, "%s", numberedPath);
found = true;
break;
}
}
if (!found)
{
sprintf_s(finalPath, "%s%d.wav", basePath, chosen);
}
}
}
@@ -558,7 +577,7 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume, floa
if (ma_sound_init_from_file(
&m_engine,
finalPath,
MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC,
MA_SOUND_FLAG_ASYNC,
nullptr,
nullptr,
&s->sound) != MA_SUCCESS)
@@ -588,7 +607,91 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume, floa
/////////////////////////////////////////////
//
// playUI
//
// startElytraSound / stopElytraSound
// Manages a single persistent looping sound for elytra gliding.
// Call startElytraSound every tick while gliding (it no-ops if already running,
// just updates volume). Call stopElytraSound when gliding ends.
//
// IMPORTANT: m_elytraLoopingSound is NOT added to m_activeSounds.
// The tick() cleanup loop deletes sounds where is_playing()==false.
// A looping sound briefly reports is_playing()==false at the loop point,
// which would cause tick() to free it and leave m_elytraLoopingSound dangling.
//
/////////////////////////////////////////////
void SoundEngine::startElytraSound(float x, float y, float z, float volume, float pitch)
{
// If already initialized just update volume and pitch - never reinitialize mid-flight.
if (m_elytraLoopingSound != nullptr)
{
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN) finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&m_elytraLoopingSound->sound, finalVolume);
ma_sound_set_pitch(&m_elytraLoopingSound->sound, pitch);
return;
}
// Resolve file path using the same logic as play().
wstring name = wchSoundNames[eSoundType_ITEM_ELYTRA_FLYING];
char* soundName = ConvertSoundPathToName(name);
char basePath[256];
sprintf_s(basePath, "Windows64Media/Sound/Minecraft/%s", soundName);
const char* extensions[] = { ".ogg", ".wav", ".mp3" };
char finalPath[256] = {};
bool found = false;
for (auto& ext : extensions)
{
char candidate[256];
sprintf_s(candidate, "%s%s", basePath, ext);
DWORD attr = GetFileAttributesA(candidate);
if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY))
{
sprintf_s(finalPath, "%s", candidate);
found = true;
break;
}
}
if (!found) return;
MiniAudioSound* s = new MiniAudioSound();
memset(&s->info, 0, sizeof(AUDIO_INFO));
s->info.volume = volume; s->info.pitch = pitch;
s->info.bIs3D = false;
s->info.iSound = eSoundType_ITEM_ELYTRA_FLYING + eSFX_MAX;
// Synchronous load so the sound is immediately ready - no ASYNC gap.
if (ma_sound_init_from_file(&m_engine, finalPath, 0,
nullptr, nullptr, &s->sound) != MA_SUCCESS)
{
delete s;
return;
}
ma_sound_set_spatialization_enabled(&s->sound, MA_FALSE);
ma_sound_set_looping(&s->sound, MA_TRUE);
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN) finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&s->sound, finalVolume);
ma_sound_set_pitch(&s->sound, pitch);
ma_sound_start(&s->sound);
// NOT added to m_activeSounds - tick() cleanup would delete it at loop boundaries.
m_elytraLoopingSound = s;
}
void SoundEngine::stopElytraSound()
{
if (m_elytraLoopingSound == nullptr) return;
ma_sound_stop(&m_elytraLoopingSound->sound);
ma_sound_uninit(&m_elytraLoopingSound->sound);
delete m_elytraLoopingSound;
m_elytraLoopingSound = nullptr;
}
/////////////////////////////////////////////
// playUI
//
/////////////////////////////////////////////
void SoundEngine::playUI(int iSound, float volume, float pitch)
@@ -617,40 +720,24 @@ void SoundEngine::playUI(int iSound, float volume, float pitch)
sprintf_s(basePath, "Windows64Media/Sound/%s/%s", soundDir, ConvertSoundPathToName(name));
char finalPath[256];
sprintf_s(finalPath, "%s.wav", basePath);
// Check UI sound path cache first
auto cacheIt = m_uiSoundPathCache.find(iSound);
if (cacheIt != m_uiSoundPathCache.end())
const char* extensions[] = { ".ogg", ".wav", ".mp3" };
size_t count = sizeof(extensions) / sizeof(extensions[0]);
bool found = false;
for (size_t i = 0; i < count; i++)
{
if (cacheIt->second.empty())
sprintf_s(finalPath, "%s%s", basePath, extensions[i]);
if (FileExists(finalPath))
{
app.DebugPrintf("No sound file found for UI sound (cached): %s\n", basePath);
return;
found = true;
break;
}
sprintf_s(finalPath, "%s", cacheIt->second.c_str());
}
else
if (!found)
{
// Cache miss — probe filesystem and store result
const char* extensions[] = { ".ogg", ".wav", ".mp3" };
size_t count = sizeof(extensions) / sizeof(extensions[0]);
bool found = false;
for (size_t i = 0; i < count; i++)
{
sprintf_s(finalPath, "%s%s", basePath, extensions[i]);
if (FileExists(finalPath))
{
found = true;
break;
}
}
if (!found)
{
m_uiSoundPathCache[iSound] = ""; // cache negative result
app.DebugPrintf("No sound file found for UI sound: %s\n", basePath);
return;
}
m_uiSoundPathCache[iSound] = finalPath;
app.DebugPrintf("No sound file found for UI sound: %s\n", basePath);
return;
}
MiniAudioSound* s = new MiniAudioSound();
@@ -664,7 +751,7 @@ void SoundEngine::playUI(int iSound, float volume, float pitch)
if (ma_sound_init_from_file(
&m_engine,
finalPath,
MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC,
MA_SOUND_FLAG_ASYNC,
nullptr,
nullptr,
&s->sound) != MA_SUCCESS)
@@ -694,81 +781,70 @@ void SoundEngine::playUI(int iSound, float volume, float pitch)
// playStreaming
//
/////////////////////////////////////////////
void SoundEngine::playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay)
void SoundEngine::playStreaming(const wstring& name, float x, float y, float z, float volume, float pitch, bool bMusicDelay)
{
// This function doesn't actually play a streaming sound, just sets states and an id for the music tick to play it
// Level audio will be played when a play with an empty name comes in
// CD audio will be played when a named stream comes in
m_StreamingAudioInfo.x=x;
m_StreamingAudioInfo.y=y;
m_StreamingAudioInfo.z=z;
m_StreamingAudioInfo.volume=volume;
m_StreamingAudioInfo.pitch=pitch;
m_StreamingAudioInfo.x = x;
m_StreamingAudioInfo.y = y;
m_StreamingAudioInfo.z = z;
m_StreamingAudioInfo.volume = volume;
m_StreamingAudioInfo.pitch = pitch;
if(m_StreamState==eMusicStreamState_Playing)
{
m_StreamState=eMusicStreamState_Stop;
}
else if(m_StreamState==eMusicStreamState_Opening)
{
m_StreamState=eMusicStreamState_OpeningCancel;
}
if(m_StreamState == eMusicStreamState_Playing)
m_StreamState = eMusicStreamState_Stop;
else if(m_StreamState == eMusicStreamState_Opening)
m_StreamState = eMusicStreamState_OpeningCancel;
if(name.empty())
{
// music, or stop CD
m_StreamingAudioInfo.bIs3D=false;
m_StreamingAudioInfo.bIs3D = false;
// we need a music id
// random delay of up to 3 minutes for music
m_iMusicDelay = random->nextInt(20 * 60 * 3);//random->nextInt(20 * 60 * 10) + 20 * 60 * 10;
m_iMusicDelay = random->nextInt(20 * 60 * 3);
#ifdef _DEBUG
m_iMusicDelay=0;
m_iMusicDelay = 0;
#endif
Minecraft *pMinecraft=Minecraft::GetInstance();
bool playerInEnd=false;
bool playerInNether=false;
Minecraft *pMinecraft = Minecraft::GetInstance();
for(unsigned int i=0;i<MAX_LOCAL_PLAYERS;i++)
bool playerInEnd = false;
bool playerInNether = false;
unsigned int i = 0;
for(i = 0; i < MAX_LOCAL_PLAYERS; i++)
{
if(pMinecraft->localplayers[i]!=nullptr)
if(pMinecraft->localplayers[i] != nullptr)
{
if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END)
{
playerInEnd=true;
}
else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER)
{
playerInNether=true;
}
if(pMinecraft->localplayers[i]->dimension == LevelData::DIMENSION_END)
playerInEnd = true;
else if(pMinecraft->localplayers[i]->dimension == LevelData::DIMENSION_NETHER)
playerInNether = true;
}
}
if(playerInEnd)
{
m_musicID = getMusicID(LevelData::DIMENSION_END);
}
m_musicID = getMusicID(eMusicType_End);
else if(playerInNether)
{
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
}
m_musicID = getMusicID(eMusicType_Nether);
else
{
m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD);
}
getGameModeMusicID(pMinecraft, i);
}
else
{
// jukebox
m_StreamingAudioInfo.bIs3D=true;
m_musicID=getMusicID(name);
m_iMusicDelay=0;
m_StreamingAudioInfo.bIs3D=true;
m_musicID=getMusicID(name);
m_iMusicDelay=0;
}
}
int SoundEngine::GetRandomishTrack(int iStart,int iEnd)
{
// 4J-PB - make it more likely that we'll get a track we've not heard for a while, although repeating tracks sometimes is fine
@@ -781,14 +857,14 @@ int SoundEngine::GetRandomishTrack(int iStart,int iEnd)
if(m_bHeardTrackA[i]==false)
{
bAllTracksHeard=false;
app.DebugPrintf("Not heard all tracks yet\n");
//app.DebugPrintf("Not heard all tracks yet\n");
break;
}
}
if(bAllTracksHeard)
{
app.DebugPrintf("Heard all tracks - resetting the tracking array\n");
//app.DebugPrintf("Heard all tracks - resetting the tracking array\n");
for(size_t i=iStart;i<=iEnd;i++)
{
@@ -804,117 +880,73 @@ int SoundEngine::GetRandomishTrack(int iStart,int iEnd)
if(m_bHeardTrackA[iVal]==false)
{
// not heard this
app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal);
//app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal);
m_bHeardTrackA[iVal]=true;
break;
}
else
{
app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal);
//app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal);
}
}
app.DebugPrintf("Select track %d\n",iVal);
//app.DebugPrintf("Select track %d\n",iVal);
return iVal;
}
/////////////////////////////////////////////
//
// getOverworldMusicID - selects overworld music based on game mode
//
/////////////////////////////////////////////
int SoundEngine::getOverworldMusicID(Minecraft *pMinecraft)
{
#ifndef _XBOX
// Check if any local player is in creative mode
bool isCreative = false;
for(unsigned int i = 0; i < MAX_LOCAL_PLAYERS; i++)
{
if(pMinecraft->localplayers[i] != nullptr && pMinecraft->localgameModes[i] != nullptr)
{
GameType *mode = pMinecraft->localgameModes[i]->getLocalPlayerMode();
if(mode != nullptr && mode->isCreative())
{
isCreative = true;
break;
}
}
}
if(isCreative)
{
// Creative: survival tracks + creative tracks
int survivalCount = m_iStream_Overworld_Max - m_iStream_Overworld_Min + 1;
int creativeCount = m_iStream_Creative_Max - m_iStream_Creative_Min + 1;
int pick = random->nextInt(survivalCount + creativeCount);
if(pick < survivalCount)
return GetRandomishTrack(m_iStream_Overworld_Min, m_iStream_Overworld_Max);
else
return GetRandomishTrack(m_iStream_Creative_Min, m_iStream_Creative_Max);
}
#endif
// Survival/Adventure: survival tracks only
return GetRandomishTrack(m_iStream_Overworld_Min, m_iStream_Overworld_Max);
}
/////////////////////////////////////////////
//
// getMusicID
//
/////////////////////////////////////////////
int SoundEngine::getMusicID(int iDomain)
int SoundEngine::getMusicID(eMusicType iDomain)
{
int result=-1;
Minecraft *pMinecraft=Minecraft::GetInstance();
// Before the game has started?
if(pMinecraft==nullptr)
{
#ifndef _XBOX
// Title screen: play menu music
result = GetRandomishTrack(m_iStream_Menu_Min,m_iStream_Menu_Max);
#else
result = GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max);
#endif
}
else if(pMinecraft->skins->isUsingDefaultSkin())
if(pMinecraft && !pMinecraft->skins->isUsingDefaultSkin())
{
// using a texture pack - may have multiple End music tracks
switch(iDomain)
{
case LevelData::DIMENSION_END:
// the end isn't random - it has different music depending on whether the dragon is alive or not, but we've not added the dead dragon music yet
result = m_iStream_End_Min;
break;
case LevelData::DIMENSION_NETHER:
result = GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max);
break;
case eMusicType_Nether:
return GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max);
//return m_iStream_Nether_Min + random->nextInt(m_iStream_Nether_Max-m_iStream_Nether_Min);
case eMusicType_Menu:
return GetRandomishTrack(m_iStream_Menu_Min, m_iStream_Menu_Max);
case eMusicType_End:
return GetRandomishTrack(m_iStream_End_Min, m_iStream_End_Max);
case eMusicType_Creative:
return GetRandomishTrack(m_iStream_Creative_Min, m_iStream_Creative_Max);
case eMusicType_Battle:
return GetRandomishTrack(m_iStream_Battle_Min, m_iStream_Battle_Max);
default: //overworld
result = getOverworldMusicID(pMinecraft);
break;
}
}
else
{
// using a texture pack - may have multiple End music tracks
switch(iDomain)
{
case LevelData::DIMENSION_END:
result = GetRandomishTrack(m_iStream_End_Min,m_iStream_End_Max);
break;
case LevelData::DIMENSION_NETHER:
result = GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max);
break;
default: //overworld
result = getOverworldMusicID(pMinecraft);
break;
//return m_iStream_Overworld_Min + random->nextInt(m_iStream_Overworld_Max-m_iStream_Overworld_Min);
return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max);
}
}
switch(iDomain)
{
case eMusicType_Nether:
return GetRandomishTrack(m_iStream_Nether_Min, m_iStream_Nether_Max);
case eMusicType_Menu:
return GetRandomishTrack(m_iStream_Menu_Min, m_iStream_Menu_Max);
case eMusicType_End:
// the end isn't random - it has different music depending on whether the dragon is alive or not, but we've not added the dead dragon music yet
{
int idx = BossMobGuiInfo::getIndexFromDimension(LevelData::DIMENSION_END);
if (!BossMobGuiInfo::name[idx].empty() && BossMobGuiInfo::displayTicks[idx] > 0)
return m_iStream_End_Min;
else
return m_iStream_End_Max;
#ifdef _DEBUG
if(result >= 0 && result < eStream_Max)
app.DebugPrintf("getMusicID: selected track '%s' (id=%d, domain=%d)\n", m_szStreamFileA[result], result, iDomain);
#endif
return result;
}
case eMusicType_Creative:
return GetRandomishTrack(m_iStream_Creative_Min, m_iStream_Creative_Max);
case eMusicType_Battle:
return GetRandomishTrack(m_iStream_Battle_Min, m_iStream_Battle_Max);
default:
return GetRandomishTrack(m_iStream_Overworld_Min, m_iStream_Overworld_Max);
}
}
/////////////////////////////////////////////
@@ -1111,7 +1143,6 @@ void SoundEngine::playMusicUpdate()
{
SetIsPlayingStreamingGameMusic(true);
SetIsPlayingStreamingCDMusic(false);
m_MusicType=eMusicType_Game;
m_StreamingAudioInfo.bIs3D=false;
#ifdef _XBOX_ONE
@@ -1137,7 +1168,6 @@ void SoundEngine::playMusicUpdate()
{
SetIsPlayingStreamingGameMusic(false);
SetIsPlayingStreamingCDMusic(true);
m_MusicType=eMusicType_CD;
m_StreamingAudioInfo.bIs3D=true;
// Need to adjust to index into the cds in the game's m_szStreamFileA
@@ -1166,14 +1196,12 @@ void SoundEngine::playMusicUpdate()
SetIsPlayingStreamingGameMusic(true);
SetIsPlayingStreamingCDMusic(false);
m_MusicType=eMusicType_Game;
m_StreamingAudioInfo.bIs3D=false;
}
else if(m_musicID<m_iStream_CD_1)
{
SetIsPlayingStreamingGameMusic(true);
SetIsPlayingStreamingCDMusic(false);
m_MusicType=eMusicType_Game;
m_StreamingAudioInfo.bIs3D=false;
// build the name
strcat((char *)m_szStreamName,"music/");
@@ -1185,7 +1213,6 @@ void SoundEngine::playMusicUpdate()
{
SetIsPlayingStreamingGameMusic(false);
SetIsPlayingStreamingCDMusic(true);
m_MusicType=eMusicType_CD;
m_StreamingAudioInfo.bIs3D=true;
// build the name
strcat((char *)m_szStreamName,"cds/");
@@ -1197,7 +1224,6 @@ void SoundEngine::playMusicUpdate()
{
SetIsPlayingStreamingGameMusic(true);
SetIsPlayingStreamingCDMusic(false);
m_MusicType=eMusicType_Game;
m_StreamingAudioInfo.bIs3D=false;
// build the name
strcat((char *)m_szStreamName,"music/");
@@ -1206,7 +1232,6 @@ void SoundEngine::playMusicUpdate()
{
SetIsPlayingStreamingGameMusic(false);
SetIsPlayingStreamingCDMusic(true);
m_MusicType=eMusicType_CD;
m_StreamingAudioInfo.bIs3D=true;
// build the name
strcat((char *)m_szStreamName,"cds/");
@@ -1369,7 +1394,8 @@ void SoundEngine::playMusicUpdate()
bool playerInEnd = false;
bool playerInNether=false;
Minecraft *pMinecraft = Minecraft::GetInstance();
for(unsigned int i = 0; i < MAX_LOCAL_PLAYERS; ++i)
unsigned int i = 0;
for(i = 0; i < MAX_LOCAL_PLAYERS; ++i)
{
if(pMinecraft->localplayers[i]!=nullptr)
{
@@ -1389,7 +1415,7 @@ void SoundEngine::playMusicUpdate()
m_StreamState=eMusicStreamState_Stop;
// Set the end track
m_musicID = getMusicID(LevelData::DIMENSION_END);
m_musicID = getMusicID(eMusicType_End);
SetIsPlayingEndMusic(true);
SetIsPlayingNetherMusic(false);
}
@@ -1400,7 +1426,7 @@ void SoundEngine::playMusicUpdate()
m_StreamState=eMusicStreamState_Stop;
// Set the end track
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
m_musicID = getMusicID(eMusicType_Nether);
SetIsPlayingEndMusic(false);
SetIsPlayingNetherMusic(true);
}
@@ -1409,7 +1435,7 @@ void SoundEngine::playMusicUpdate()
m_StreamState=eMusicStreamState_Stop;
// Set the end track
m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD);
m_musicID = getMusicID(eMusicType_Overworld);
SetIsPlayingEndMusic(false);
SetIsPlayingNetherMusic(false);
}
@@ -1418,7 +1444,7 @@ void SoundEngine::playMusicUpdate()
{
m_StreamState=eMusicStreamState_Stop;
// set the Nether track
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
m_musicID = getMusicID(eMusicType_Nether);
SetIsPlayingNetherMusic(true);
SetIsPlayingEndMusic(false);
}
@@ -1428,7 +1454,7 @@ void SoundEngine::playMusicUpdate()
{
m_StreamState=eMusicStreamState_Stop;
// set the Nether track
m_musicID = getMusicID(LevelData::DIMENSION_END);
m_musicID = getMusicID(eMusicType_End);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(true);
}
@@ -1436,11 +1462,13 @@ void SoundEngine::playMusicUpdate()
{
m_StreamState=eMusicStreamState_Stop;
// set the Nether track
m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD);
m_musicID = getMusicID(eMusicType_Overworld);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(false);
}
}
else if(!playerInEnd && !playerInNether)
getGameModeMusicID(pMinecraft, i);
// volume change required?
if (m_musicStreamActive)
@@ -1500,7 +1528,8 @@ void SoundEngine::playMusicUpdate()
bool playerInEnd=false;
bool playerInNether=false;
for(unsigned int i=0;i<MAX_LOCAL_PLAYERS;i++)
unsigned int i=0;
for(i=0;i<MAX_LOCAL_PLAYERS;i++)
{
if(pMinecraft->localplayers[i]!=nullptr)
{
@@ -1516,19 +1545,19 @@ void SoundEngine::playMusicUpdate()
}
if(playerInEnd)
{
m_musicID = getMusicID(LevelData::DIMENSION_END);
m_musicID = getMusicID(eMusicType_End);
SetIsPlayingEndMusic(true);
SetIsPlayingNetherMusic(false);
}
else if(playerInNether)
{
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
m_musicID = getMusicID(eMusicType_Nether);
SetIsPlayingNetherMusic(true);
SetIsPlayingEndMusic(false);
}
else
{
m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD);
m_musicID = getMusicID(eMusicType_Overworld);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(false);
}
+33 -27
View File
@@ -1,13 +1,10 @@
#pragma once
class Minecraft;
class Mob;
class Options;
using namespace std;
#include "..\..\Minecraft.World\SoundTypes.h"
#include "../../Minecraft.World/SoundTypes.h"
#include "miniaudio.h"
#include <unordered_map>
#include <string>
constexpr float SFX_3D_MIN_DISTANCE = 1.0f;
constexpr float SFX_3D_MAX_DISTANCE = 16.0f;
@@ -15,7 +12,7 @@ constexpr float SFX_3D_ROLLOFF = 0.5f;
constexpr float SFX_VOLUME_MULTIPLIER = 1.5f;
constexpr float SFX_MAX_GAIN = 1.5f;
enum eMUSICFILES
enum eMusicFiles
{
eStream_Overworld_Calm1 = 0,
eStream_Overworld_Calm2,
@@ -26,10 +23,7 @@ enum eMUSICFILES
eStream_Overworld_hal4,
eStream_Overworld_nuance1,
eStream_Overworld_nuance2,
eStream_Overworld_piano1,
eStream_Overworld_piano2,
eStream_Overworld_piano3, // <-- make piano3 the last survival overworld one
#ifndef _XBOX
// Add the new music tracks
eStream_Overworld_Creative1,
eStream_Overworld_Creative2,
eStream_Overworld_Creative3,
@@ -40,7 +34,9 @@ enum eMUSICFILES
eStream_Overworld_Menu2,
eStream_Overworld_Menu3,
eStream_Overworld_Menu4,
#endif
eStream_Overworld_piano1,
eStream_Overworld_piano2,
eStream_Overworld_piano3, // <-- make piano3 the last overworld one
// Nether
eStream_Nether1,
eStream_Nether2,
@@ -49,6 +45,11 @@ enum eMUSICFILES
// The End
eStream_end_dragon,
eStream_end_end,
// Battle
eStream_BattleMode1,
eStream_BattleMode2,
eStream_BattleMode3,
eStream_BattleMode4,
eStream_CD_1,
eStream_CD_2,
eStream_CD_3,
@@ -64,15 +65,20 @@ enum eMUSICFILES
eStream_Max,
};
enum eMUSICTYPE
enum eMusicType
{
eMusicType_None,
eMusicType_Game,
eMusicType_CD,
eMusicType_Nether = 0,
// ???
eMusicType_Menu = 2,
// ???
eMusicType_End = 4,
eMusicType_Creative = 5,
eMusicType_Battle = 6,
eMusicType_Overworld = 7,
};
enum MUSIC_STREAMSTATE
enum eMusicStreamState
{
eMusicStreamState_Idle=0,
eMusicStreamState_Stop,
@@ -121,6 +127,8 @@ public:
void GetSoundName(char *szSoundName,int iSound);
#endif
void play(int iSound, float x, float y, float z, float volume, float pitch) override;
void startElytraSound(float x, float y, float z, float volume, float pitch);
void stopElytraSound();
void playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay=true) override;
void playUI(int iSound, float volume, float pitch) override;
void playMusicTick() override;
@@ -134,11 +142,11 @@ public:
void addStreaming(const wstring& name, File *file) override;
char *ConvertSoundPathToName(const wstring& name, bool bConvertSpaces=false) override;
bool isStreamingWavebankReady(); // 4J Added
int getMusicID(int iDomain);
int getMusicID(eMusicType iDomain);
int getMusicID(const wstring& name);
int getOverworldMusicID(Minecraft *pMinecraft);
void SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1);
void SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCreativeMin, int iCreativeMax, int iMenuMin, int iMenuMax, int iBattleMin, int iBattleMax, int iCD1);
void updateMiniAudio();
inline void getGameModeMusicID(Minecraft* pMinecraft, unsigned int i);
void playMusicUpdate();
private:
@@ -153,6 +161,9 @@ private:
int GetRandomishTrack(int iStart,int iEnd);
MiniAudioSound* m_elytraLoopingSound = nullptr;
ma_engine m_engine;
ma_engine_config m_engineConfig;
ma_sound m_musicStream;
@@ -171,7 +182,6 @@ private:
int m_musicID;
int m_iMusicDelay;
int m_StreamState;
int m_MusicType;
AUDIO_INFO m_StreamingAudioInfo;
wstring m_CDMusic;
BOOL m_bSystemMusicPlaying;
@@ -187,17 +197,13 @@ private:
int m_iStream_Overworld_Min,m_iStream_Overworld_Max;
int m_iStream_Nether_Min,m_iStream_Nether_Max;
int m_iStream_End_Min,m_iStream_End_Max;
int m_iStream_Creative_Min,m_iStream_Creative_Max;
int m_iStream_Menu_Min,m_iStream_Menu_Max;
int m_iStream_Battle_Min,m_iStream_Battle_Max;
int m_iStream_CD_1;
#ifndef _XBOX
int m_iStream_Creative_Min, m_iStream_Creative_Max;
int m_iStream_Menu_Min, m_iStream_Menu_Max;
#endif
bool *m_bHeardTrackA;
std::unordered_map<int, std::vector<std::string>> m_soundPathCache; // play(): sound ID → all valid variant paths
std::unordered_map<int, std::string> m_uiSoundPathCache; // playUI(): sound ID → resolved path
#ifdef __ORBIS__
int32_t m_hBGMAudio;
#endif
};
};
@@ -224,7 +224,72 @@ const WCHAR *ConsoleSoundEngine::wchSoundNames[eSoundType_MAX]=
// instead, we'll add the sounds as new ones and change the code to reference them
L"fire.new_ignite",
L"mob.rabbit.idle",
L"mob.rabbit.hurt",
L"mob.rabbit.bunnymurder",
L"mob.rabbit.hop",
L"item.armor.equip_leather1",
L"item.armor.equip_leather2",
L"item.armor.equip_leather3",
L"item.armor.equip_leather4",
L"item.armor.equip_leather5",
L"item.armor.equip_leather6",
L"item.armor.equip_chain1",
L"item.armor.equip_chain2",
L"item.armor.equip_chain3",
L"item.armor.equip_chain4",
L"item.armor.equip_chain5",
L"item.armor.equip_chain6",
L"item.armor.equip_iron1",
L"item.armor.equip_iron2",
L"item.armor.equip_iron3",
L"item.armor.equip_iron4",
L"item.armor.equip_iron5",
L"item.armor.equip_iron6",
L"item.armor.equip_gold1",
L"item.armor.equip_gold2",
L"item.armor.equip_gold3",
L"item.armor.equip_gold4",
L"item.armor.equip_gold5",
L"item.armor.equip_gold6",
L"item.armor.equip_diamond1",
L"item.armor.equip_diamond2",
L"item.armor.equip_diamond3",
L"item.armor.equip_diamond4",
L"item.armor.equip_diamond5",
L"item.armor.equip_diamond6",
L"item.armor.equip_generic1",
L"item.armor.equip_generic2",
L"item.armor.equip_generic3",
L"item.armor.equip_generic4",
L"item.armor.equip_generic5",
L"item.armor.equip_generic6",
L"damage.critical", //eSoundType_DAMAGE_CRITICAL,
L"item.elytra.flying", // eSoundType_ITEM_ELYTRA_FLYING
L"mob.guardian.attack_loop",
L"mob.guardian.guardian_death",
L"mob.guardian.guardian_hit",
L"mob.guardian.flop",
L"mob.guardian.land_death",
L"mob.guardian.land_hit",
L"mob.guardian.land_idle",
L"mob.guardian.curse",
L"mob.guardian.elder_death",
L"mob.guardian.elder_hit",
L"mob.guardian.elder_idle"
};
@@ -236,4 +301,7 @@ const WCHAR *ConsoleSoundEngine::wchUISoundNames[eSFX_MAX]=
L"focus",
L"press",
L"scroll",
L"open_flip1",
L"open_flip2",
L"open_flip3"
};
@@ -35,6 +35,9 @@ const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
L"Foliage_ExtremeHillsEdge",
L"Foliage_Jungle",
L"Foliage_JungleHills",
L"Foliage_Savanna",
L"Foliage_RoofedForest",
L"Foliage_Mesa",
L"Grass_Common",
L"Grass_Ocean",
@@ -60,6 +63,9 @@ const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
L"Grass_ExtremeHillsEdge",
L"Grass_Jungle",
L"Grass_JungleHills",
L"Grass_Savanna",
L"Grass_RoofedForest",
L"Grass_Mesa",
L"Water_Ocean",
L"Water_Plains",
@@ -84,6 +90,7 @@ const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
L"Water_ExtremeHillsEdge",
L"Water_Jungle",
L"Water_JungleHills",
L"Water_Mesa",
L"Sky_Ocean",
L"Sky_Plains",
@@ -256,16 +263,32 @@ const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
L"Mob_Witch_Colour2",
L"Mob_Horse_Colour1",
L"Mob_Horse_Colour2",
L"Mob_Rabbit_Colour1",
L"Mob_Rabbit_Colour2",
L"Mob_Endermite_Colour1",
L"Mob_Endermite_Colour2",
L"Mob_Guardian_Colour1",
L"Mob_Guardian_Colour2",
L"Mob_ElderGuardian_Colour1",
L"Mob_ElderGuardian_Colour2",
L"Armour_Default_Leather_Colour",
L"Under_Water_Clear_Colour",
L"Under_Lava_Clear_Colour",
L"In_Cloud_Base_Colour",
L"Under_Water_Fog_Colour",
L"Under_Lava_Fog_Colour",
L"In_Cloud_Fog_Colour",
L"Default_Fog_Colour",
L"Nether_Fog_Colour",
L"End_Fog_Colour",
@@ -323,14 +346,19 @@ const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
void ColourTable::staticCtor()
{
for(unsigned int i = eMinecraftColour_NOT_SET; i < eMinecraftColour_COUNT; ++i)
for(unsigned int i = 0; i < eMinecraftColour_COUNT; ++i)
{
// Critical check: Stop if we hit a NULL pointer or reach the end of the defined array
if (i >= _countof(ColourTableElements) || ColourTableElements[i] == nullptr)
break;
s_colourNamesMap.insert( unordered_map<wstring,eMinecraftColour>::value_type( ColourTableElements[i], static_cast<eMinecraftColour>(i)) );
}
}
ColourTable::ColourTable(PBYTE pbData, DWORD dwLength)
{
XMemSet(m_colourValues, 0, sizeof(m_colourValues));
loadColoursFromData(pbData, dwLength);
}
@@ -366,7 +394,11 @@ void ColourTable::setColour(const wstring &colourName, int value)
auto it = s_colourNamesMap.find(colourName);
if(it != s_colourNamesMap.end())
{
m_colourValues[static_cast<int>(it->second)] = value;
int id = static_cast<int>(it->second);
if (id >= 0 && id < eMinecraftColour_COUNT)
{
m_colourValues[id] = value;
}
}
}
@@ -377,5 +409,10 @@ void ColourTable::setColour(const wstring &colourName, const wstring &value)
unsigned int ColourTable::getColour(eMinecraftColour id)
{
return m_colourValues[static_cast<int>(id)];
int idx = static_cast<int>(id);
if (idx >= 0 && idx < eMinecraftColour_COUNT)
{
return m_colourValues[idx];
}
return 0; // Return black for invalid IDs
}
+248 -74
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "../../Minecraft.World/net.minecraft.world.entity.item.h"
#include "../../Minecraft.World/net.minecraft.world.entity.player.h"
#include "../../Minecraft.World/net.minecraft.world.level.tile.entity.h"
@@ -27,6 +27,9 @@
#include "../GameMode.h"
#include "../Xbox/Social/SocialManager.h"
#include "Tutorial/TutorialMode.h"
#ifdef _WINDOWS64
#include "../Windows64/Network/WinsockNetLayer.h" // HUCKLE - added for quit on disconnect
#endif
#if defined _XBOX || defined _WINDOWS64
#include "../Xbox/XML/ATGXmlParser.h"
#include "../Xbox/XML/xmlFilesCallback.h"
@@ -242,6 +245,34 @@ CMinecraftApp::CMinecraftApp()
}
void CMinecraftApp::GetSkinAdjustments(_SkinAdjustments* out,
unsigned int skinId)
{
_SkinAdjustments adj;
EnterCriticalSection(&csAdditionalSkinBoxes);
if (!m_SkinAdjustmentsMap.empty())
{
auto it = m_SkinAdjustmentsMap.find(skinId);
if (it != m_SkinAdjustmentsMap.end())
adj = it->second;
}
LeaveCriticalSection(&csAdditionalSkinBoxes);
*out = adj;
}
void CMinecraftApp::SetSkinAdjustments(unsigned int skinId,
const _SkinAdjustments& adj)
{
EnterCriticalSection(&csAdditionalSkinBoxes);
m_SkinAdjustmentsMap[skinId] = adj;
LeaveCriticalSection(&csAdditionalSkinBoxes);
}
void CMinecraftApp::DebugPrintf(const char *szFormat, ...)
{
@@ -329,11 +360,73 @@ void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...)
#endif
}
namespace
{
const wchar_t *ResolveStringKeyFromId(int iID)
{
#ifdef _WINDOWS64
switch(iID)
{
#include "StringIdLookup.generated.inc"
default:
return nullptr;
}
#else
(void)iID;
return nullptr;
#endif
}
}
LPCWSTR CMinecraftApp::GetString(int iID)
{
//return L"Değişiklikler ve Yenilikler";
//return L"ÕÕÕÕÖÖÖÖ";
return app.m_stringTable->getString(iID);
if(app.m_stringTable == nullptr)
{
const wchar_t *key = ResolveStringKeyFromId(iID);
return key != nullptr ? key : L"";
}
LPCWSTR byIndex = app.m_stringTable->getString(iID);
if(byIndex != nullptr && byIndex[0] != L'\0')
{
return byIndex;
}
const wchar_t *key = ResolveStringKeyFromId(iID);
if(key != nullptr)
{
LPCWSTR byKey = app.m_stringTable->getString(key);
if(byKey != nullptr && byKey[0] != L'\0')
{
return byKey;
}
// Prefer visible fallback text instead of returning an empty string.
return key;
}
return L"";
}
LPCWSTR CMinecraftApp::GetString(const wchar_t *id)
{
if(id == nullptr)
{
return L"";
}
if(app.m_stringTable == nullptr)
{
return id;
}
LPCWSTR byKey = app.m_stringTable->getString(id);
if(byKey != nullptr && byKey[0] != L'\0')
{
return byKey;
}
return id;
}
void CMinecraftApp::SetAction(int iPad, eXuiAction action, LPVOID param)
@@ -360,7 +453,7 @@ void CMinecraftApp::SetAction(int iPad, eXuiAction action, LPVOID param)
bool CMinecraftApp::IsAppPaused()
{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(_WINDOWS64)
bool paused = m_bIsAppPaused;
EnterCriticalSection(&m_saveNotificationCriticalSection);
if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 )
@@ -487,16 +580,15 @@ bool CMinecraftApp::LoadCrafting3x3Menu(int iPad,shared_ptr<LocalPlayer> player,
initData->y = y;
initData->z = z;
if(app.GetLocalPlayerCount()>1)
{
initData->bSplitscreen=true;
success = ui.NavigateToScene(iPad,eUIScene_Crafting3x3Menu, initData);
}
if (app.GetLocalPlayerCount() > 1)
initData->bSplitscreen = true;
else
{
initData->bSplitscreen=false;
success = ui.NavigateToScene(iPad,eUIScene_Crafting3x3Menu, initData);
}
initData->bSplitscreen = false;
if (app.GetGameSettings(iPad, eGameSetting_ClassicCrafting))
success = ui.NavigateToScene(iPad, eUIScene_ClassicCraftingMenu, initData);
else
success = ui.NavigateToScene(iPad, eUIScene_Crafting3x3Menu, initData);
return success;
}
@@ -781,6 +873,21 @@ bool CMinecraftApp::LoadBeaconMenu(int iPad ,shared_ptr<Inventory> inventory, sh
return success;
}
bool CMinecraftApp::LoadWritingBookMenu(int iPad, shared_ptr<ItemInstance> instance, shared_ptr<Player> player, bool editable)
{
bool success = true;
WritingBookMenuParams* initData = new WritingBookMenuParams();
initData->itemInstance = instance;
initData->player = player;
initData->iPad = iPad;
initData->isEditable = editable;
success = ui.NavigateToScene(iPad, eUIScene_BookMenu, initData);
return success;
}
//////////////////////////////////////////////
// GAME SETTINGS
//////////////////////////////////////////////
@@ -842,15 +949,16 @@ void CMinecraftApp::InitGameSettings()
memset(pProfileSettings,0,sizeof(C_4JProfile::PROFILESETTINGS));
SetDefaultOptions(pProfileSettings,i);
Win64_LoadSettings(GameSettingsA[i]);
app.SetMinecraftLocale(i, GameSettingsA[i]->ucLocale);
app.loadStringTable();
#ifndef MINECRAFT_SERVER_BUILD
ApplyGameSettingsChanged(i);
#endif
#elif defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__
C4JStorage::PROFILESETTINGS *pProfileSettings=StorageManager.GetDashboardProfileSettings(i);
// 4J-PB - don't cause an options write to happen here
SetDefaultOptions(pProfileSettings,i,false);
#endif
Minecraft* minecraft = Minecraft::GetInstance();
if (minecraft != nullptr && minecraft->stats[i] != nullptr)
{
@@ -937,6 +1045,9 @@ int CMinecraftApp::SetDefaultOptions(C_4JProfile::PROFILESETTINGS *pSettings,con
app.SetGameHostOption(eGameHostOption_NaturalRegeneration, 1 );
app.SetGameHostOption(eGameHostOption_DoDaylightCycle, 1 );
//TU25
SetGameSettings(iPad, eGameSetting_ClassicCrafting, 0);
// 4J-PB - leave these in, or remove from everywhere they are referenced!
// Although probably best to leave in unless we split the profile settings into platform specific classes - having different meaning per platform for the same bitmask could get confusing
//#ifdef __PS3__
@@ -1334,6 +1445,7 @@ int CMinecraftApp::OldProfileVersionCallback(LPVOID pParam,unsigned char *pucDat
pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE&0x00000800); // uisize 2
pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE_SPLITSCREEN&0x00004000); // splitscreen ui size 3
pGameSettings->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; //eGameSetting_AnimatedCharacter - on
pGameSettings->uiBitmaskValues |= GAMESETTING_CLASSICCRAFTING; //eGameSetting_ClassicCrafting - off
// TU12
// favorite skins added, but only set in TU12 - set to FFs
for(int i=0;i<MAX_FAVORITE_SKINS;i++)
@@ -1393,6 +1505,9 @@ void CMinecraftApp::ApplyGameSettingsChanged(int iPad)
ActionGameSettings(iPad,eGameSetting_PS3_EULA_Read);
ActionGameSettings(iPad,eGameSetting_VSync);
//TU25
ActionGameSettings(iPad, eGameSetting_ClassicCrafting);
ActionGameSettings(iPad, eGameSetting_HideSaveSizeBar);
}
void CMinecraftApp::ActionGameSettings(int iPad,eGameSetting eVal)
@@ -1643,6 +1758,12 @@ void CMinecraftApp::ActionGameSettings(int iPad,eGameSetting eVal)
}
#endif
break;
case eGameSetting_ClassicCrafting:
//nothing to do here
break;
case eGameSetting_HideSaveSizeBar:
//nothing to do here
break;
}
}
@@ -2385,7 +2506,36 @@ void CMinecraftApp::SetGameSettings(int iPad,eGameSetting eVal,unsigned char ucV
GameSettingsA[iPad]->bSettingsChanged=true;
}
break;
case eGameSetting_ClassicCrafting:
if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_CLASSICCRAFTING) != (ucVal & 0x01) << 19)
{
if (ucVal == 1)
{
GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_CLASSICCRAFTING;
}
else
{
GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_CLASSICCRAFTING;
}
ActionGameSettings(iPad, eVal);
GameSettingsA[iPad]->bSettingsChanged = true;
}
break;
case eGameSetting_HideSaveSizeBar:
if ((GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_HIDESAVESIZEBAR) != (ucVal & 0x01) << 27)
{
if (ucVal == 1)
{
GameSettingsA[iPad]->uiBitmaskValues |= GAMESETTING_HIDESAVESIZEBAR;
}
else
{
GameSettingsA[iPad]->uiBitmaskValues &= ~GAMESETTING_HIDESAVESIZEBAR;
}
ActionGameSettings(iPad, eVal);
GameSettingsA[iPad]->bSettingsChanged = true;
}
break;
}
}
@@ -2521,6 +2671,12 @@ unsigned char CMinecraftApp::GetGameSettings(int iPad,eGameSetting eVal)
case eGameSetting_PSVita_NetworkModeAdhoc:
return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_PSVITANETWORKMODEADHOC)>>17;
case eGameSetting_ClassicCrafting:
return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_CLASSICCRAFTING) >> 26;
case eGameSetting_HideSaveSizeBar:
return (GameSettingsA[iPad]->uiBitmaskValues & GAMESETTING_HIDESAVESIZEBAR) >> 27;
case eGameSetting_VSync:
return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_VSYNC)>>24;
@@ -3839,10 +3995,13 @@ void CMinecraftApp::HandleXuiActions(void)
// need to stop the streaming audio - by playing streaming audio from the default texture pack now
// reset the streaming sounds back to the normal ones
#ifndef _XBOX
pMinecraft->soundEngine->SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3,
eStream_Nether1,eStream_Nether4,
eStream_end_dragon,eStream_end_end,
eStream_CD_1);
pMinecraft->soundEngine->SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3,
eStream_Nether1,eStream_Nether4,
eStream_end_dragon,eStream_end_end,
eStream_Overworld_Creative1,eStream_Overworld_Creative6,
eStream_Overworld_Menu1,eStream_Overworld_Menu4,
eStream_BattleMode1,eStream_BattleMode4,
eStream_CD_1);
#endif
pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 1, 1);
@@ -4486,20 +4645,20 @@ void CMinecraftApp::loadMediaArchive()
wstring mediapath = L"";
#ifdef __PS3__
mediapath = L"Common\\Media\\MediaPS3.arc";
mediapath = L"Common\\Media\\MediaPS3";
#elif _WINDOWS64
mediapath = L"Common\\Media\\MediaWindows64.arc";
mediapath = L"Common\\Media\\MediaWindows64";
#elif __ORBIS__
mediapath = L"Common\\Media\\MediaOrbis.arc";
mediapath = L"Common\\Media\\MediaOrbis";
#elif _DURANGO
mediapath = L"Common\\Media\\MediaDurango.arc";
mediapath = L"Common\\Media\\MediaDurango";
#elif __PSVITA__
mediapath = L"Common\\Media\\MediaPSVita.arc";
mediapath = L"Common\\Media\\MediaPSVita";
#endif
if (!mediapath.empty())
{
m_mediaArchive = new ArchiveFile( File(mediapath) );
m_mediaArchive = new FolderFile(mediapath);
}
#if 0
string path = "Common\\media.arc";
@@ -4551,6 +4710,58 @@ void CMinecraftApp::loadStringTable()
// we need to unload the current string table, this is a reload
delete m_stringTable;
}
#ifdef _WINDOWS64
m_stringTable = nullptr;
const wstring localisationCandidates[] =
{
L"Common\\Localization", // Fireblade - check multiple directories before resulting to .loc usage
L"Windows64Media\\loc",
L"..\\Minecraft.Client\\Windows64Media\\loc"
};
for (const auto &localisationFolder : localisationCandidates)
{
File localisationDirectory(localisationFolder);
if (localisationDirectory.exists() && localisationDirectory.isDirectory())
{
StringTable *candidateTable = new StringTable(localisationFolder); // Fireblade - xml before loc
const bool hasKeyString = candidateTable->hasStringKey(L"IDS_OK");
bool hasIndexString = false;
#ifdef IDS_OK
LPCWSTR indexedString = candidateTable->getString(IDS_OK);
hasIndexString = (indexedString != nullptr && indexedString[0] != L'\0');
#endif
if (hasKeyString || hasIndexString)
{
m_stringTable = candidateTable;
app.DebugPrintf("Loaded language data from '%ls'\n", localisationFolder.c_str());
break;
}
app.DebugPrintf("Ignoring localisation path '%ls' (missing expected IDs)\n", localisationFolder.c_str());
delete candidateTable;
}
}
if (m_stringTable == nullptr && m_mediaArchive != nullptr) // Fireblade - fallback to previous behavior
{
const wstring localisationFile = L"languages.loc";
if (m_mediaArchive->hasFile(localisationFile))
{
byteArray locFile = m_mediaArchive->getFile(localisationFile);
m_stringTable = new StringTable(locFile.data, locFile.length);
delete locFile.data;
}
}
if (m_stringTable == nullptr)
{
app.DebugPrintf("Failed to initialize language data\n");
assert(false);
}
#else // Fireblade - other platforms keep same logic
wstring localisationFile = L"languages.loc";
if (m_mediaArchive->hasFile(localisationFile))
{
@@ -4565,6 +4776,7 @@ void CMinecraftApp::loadStringTable()
// AHHHHHHHHH.
}
#endif
#endif
}
int CMinecraftApp::PrimaryPlayerSignedOutReturned(void *pParam,int iPad,const C4JStorage::EMessageResult)
@@ -4713,7 +4925,6 @@ int CMinecraftApp::SignoutExitWorldThreadProc( void* lpParameter )
break;
case DisconnectPacket::eDisconnect_OutdatedClient:
exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD;
break;
default:
exitReasonStringId = IDS_DISCONNECTED;
}
@@ -8725,6 +8936,9 @@ wstring CMinecraftApp::getEntityName(eINSTANCEOF type)
return app.GetString(IDS_WITHER);
case eTYPE_BAT:
return app.GetString(IDS_BAT);
case eTYPE_RABBIT:
return app.GetString(IDS_RABBIT);
};
return L"";
@@ -9402,8 +9616,9 @@ bool CMinecraftApp::DLCContentRetrieved(eDLCMarketplaceType eType)
void CMinecraftApp::SetAdditionalSkinBoxes(DWORD dwSkinID, SKIN_BOX *SkinBoxA, DWORD dwSkinBoxC)
{
EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER);
Model *pModel = renderer->getModel();
EntityRenderDispatcher *dispatcher = EntityRenderDispatcher::instance;
EntityRenderer *renderer = dispatcher ? dispatcher->getRenderer(eTYPE_PLAYER) : nullptr;
Model *pModel = renderer ? renderer->getModel() : nullptr;
vector<ModelPart *> *pvModelPart = new vector<ModelPart *>;
vector<SKIN_BOX *> *pvSkinBoxes = new vector<SKIN_BOX *>;
@@ -9434,8 +9649,9 @@ void CMinecraftApp::SetAdditionalSkinBoxes(DWORD dwSkinID, SKIN_BOX *SkinBoxA, D
vector<ModelPart *> * CMinecraftApp::SetAdditionalSkinBoxes(DWORD dwSkinID, vector<SKIN_BOX *> *pvSkinBoxA)
{
EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER);
Model *pModel = renderer->getModel();
EntityRenderDispatcher *dispatcher = EntityRenderDispatcher::instance;
EntityRenderer *renderer = dispatcher ? dispatcher->getRenderer(eTYPE_PLAYER) : nullptr;
Model *pModel = renderer ? renderer->getModel() : nullptr;
vector<ModelPart *> *pvModelPart = new vector<ModelPart *>;
EnterCriticalSection( &csAdditionalModelParts );
@@ -9809,48 +10025,6 @@ bool CMinecraftApp::IsLocalMultiplayerAvailable()
void CMinecraftApp::getLocale(vector<wstring> &vecWstrLocales)
{
#ifdef _WINDOWS64
{
int iPad = ProfileManager.GetPrimaryPad();
if (iPad >= 0 && GameSettingsA[iPad] != nullptr &&
GameSettingsA[iPad]->ucLanguage != MINECRAFT_LANGUAGE_DEFAULT)
{
DWORD lang = GameSettingsA[iPad]->ucLanguage;
DWORD locale = GameSettingsA[iPad]->ucLocale;
vector<eMCLang> locales;
switch(lang)
{
case XC_LANGUAGE_GERMAN: locales.push_back(eMCLang_deDE); break;
case XC_LANGUAGE_FRENCH: locales.push_back(eMCLang_frFR); break;
case XC_LANGUAGE_ITALIAN: locales.push_back(eMCLang_itIT); break;
case XC_LANGUAGE_JAPANESE: locales.push_back(eMCLang_jaJP); break;
case XC_LANGUAGE_KOREAN: locales.push_back(eMCLang_koKR); break;
case XC_LANGUAGE_POLISH: locales.push_back(eMCLang_plPL); break;
case XC_LANGUAGE_RUSSIAN: locales.push_back(eMCLang_ruRU); break;
case XC_LANGUAGE_DUTCH: locales.push_back(eMCLang_nlNL); break;
case XC_LANGUAGE_DANISH: locales.push_back(eMCLang_daDA); break;
case XC_LANGUAGE_FINISH: locales.push_back(eMCLang_fiFI); break;
case XC_LANGUAGE_SWEDISH: locales.push_back(eMCLang_svSV); break;
case XC_LANGUAGE_BNORWEGIAN: locales.push_back(eMCLang_nbNO); break;
case XC_LANGUAGE_GREEK: locales.push_back(eMCLang_elGR); break;
case XC_LANGUAGE_TCHINESE: locales.push_back(eMCLang_zhCHT); break;
case XC_LANGUAGE_PORTUGUESE:
if(locale == XC_LOCALE_BRAZIL) locales.push_back(eMCLang_ptBR);
locales.push_back(eMCLang_ptPT);
break;
case XC_LANGUAGE_SPANISH:
if(locale == XC_LOCALE_LATIN_AMERICA) locales.push_back(eMCLang_esMX);
locales.push_back(eMCLang_esES);
break;
}
locales.push_back(eMCLang_enUS);
locales.push_back(eMCLang_null);
for (auto &l : locales)
vecWstrLocales.push_back(m_localeA[l]);
return;
}
}
#endif
vector<eMCLang> locales;
DWORD dwSystemLanguage = XGetLanguage( );
+11 -3
View File
@@ -22,6 +22,9 @@ using namespace std;
#include "./GameRules/GameRuleManager.h"
#include "../SkinBox.h"
#include "../ArchiveFile.h"
#include "lce_filesystem/FolderFile.h"
typedef struct _JoinFromInviteData
{
@@ -52,6 +55,7 @@ class Model;
class ModelPart;
class StringTable;
class Merchant;
struct _SkinAdjustments;
class CMinecraftAudio;
@@ -63,7 +67,7 @@ class CMinecraftApp
{
private:
static int s_iHTMLFontSizesA[eHTMLSize_COUNT];
unordered_map<unsigned int, _SkinAdjustments> m_SkinAdjustmentsMap;
public:
CMinecraftApp();
@@ -81,6 +85,8 @@ public:
// storing credits text from the DLC
std::vector <wstring > m_vCreditText; // hold the credit text lines so we can avoid duplicating them
void GetSkinAdjustments(_SkinAdjustments* out,unsigned int skinId);
void SetSkinAdjustments(unsigned int skinId, const _SkinAdjustments& adj);
// In builds prior to TU5, the size of the GAME_SETTINGS struct was 204 bytes. We added a few new values to the internal struct in TU5, and even though we
// changed the size of the ucUnused array to be decreased by the size of the values we added, the packing of the struct has introduced some extra
@@ -97,7 +103,7 @@ public:
*/
static const int GAME_DEFINED_PROFILE_DATA_BYTES = 2*972; // per user
#else
static const int GAME_DEFINED_PROFILE_DATA_BYTES = 2*972; // per user
static const int GAME_DEFINED_PROFILE_DATA_BYTES = 3*972; // per user
#endif
unsigned int uiGameDefinedDataChangedBitmask;
@@ -149,6 +155,7 @@ public:
bool LoadHopperMenu(int iPad ,shared_ptr<Inventory> inventory, shared_ptr<MinecartHopper> hopper);
bool LoadHorseMenu(int iPad ,shared_ptr<Inventory> inventory, shared_ptr<Container> container, shared_ptr<EntityHorse> horse);
bool LoadBeaconMenu(int iPad ,shared_ptr<Inventory> inventory, shared_ptr<BeaconTileEntity> beacon);
bool LoadWritingBookMenu(int iPad, shared_ptr<ItemInstance> instance, shared_ptr<Player> player, bool editable);
bool GetTutorialMode() { return m_bTutorialMode;}
void SetTutorialMode(bool bSet) {m_bTutorialMode=bSet;}
@@ -156,6 +163,7 @@ public:
void SetSpecialTutorialCompletionFlag(int iPad, int index);
static LPCWSTR GetString(int iID);
static LPCWSTR GetString(const wchar_t *id);
eGameMode GetGameMode() { return m_eGameMode;}
void SetGameMode(eGameMode eMode) { m_eGameMode=eMode;}
@@ -431,7 +439,7 @@ public:
void loadStringTable();
protected:
ArchiveFile *m_mediaArchive;
FolderFile *m_mediaArchive;
StringTable *m_stringTable;
public:
+18 -21
View File
@@ -26,10 +26,12 @@ PBYTE DLCAudioFile::getData(DWORD &dwBytes)
return m_pbData;
}
// @3UR: thanks https://github.com/LCERD/PCK-Studio/blob/500fc74395ce99fe20cbd7598999bfab3b606745/PckStudio.Core/IO/PckAudio/PckAudioFileWriter.cs#L15
const WCHAR *DLCAudioFile::wchTypeNamesA[]=
{
L"CUENAME",
L"CREDIT",
L"CUENAME",
L"CREDIT",
L"CREDITID",
};
DLCAudioFile::EAudioParameterType DLCAudioFile::getParameterType(const wstring &paramName)
@@ -76,7 +78,7 @@ void DLCAudioFile::addParameter(EAudioType type, EAudioParameterType ptype, cons
case XC_LANGUAGE_JAPANESE:
case XC_LANGUAGE_TCHINESE:
case XC_LANGUAGE_KOREAN:
maximumChars = 35;
maximumChars = 55; // @3UR: this is 55 in TU30
break;
}
wstring creditValue = value;
@@ -88,23 +90,6 @@ void DLCAudioFile::addParameter(EAudioType type, EAudioParameterType ptype, cons
i++;
}
size_t iLast=creditValue.find_last_of(L" ", i);
switch(XGetLanguage())
{
case XC_LANGUAGE_JAPANESE:
case XC_LANGUAGE_TCHINESE:
case XC_LANGUAGE_KOREAN:
iLast = maximumChars;
break;
default:
iLast=creditValue.find_last_of(L" ", i);
break;
}
// if a space was found, include the space on this line
if(iLast!=i)
{
iLast++;
}
app.AddCreditText((creditValue.substr(0, iLast)).c_str());
creditValue = creditValue.substr(iLast);
@@ -117,6 +102,9 @@ void DLCAudioFile::addParameter(EAudioType type, EAudioParameterType ptype, cons
m_parameters[type].push_back(value);
//m_parameters[(int)type] = value;
break;
// @3UR: in IDA for TU30 this is literally just empty...
case e_AudioParamType_CreditId:
break;
}
}
@@ -170,6 +158,14 @@ bool DLCAudioFile::processDLCDataFile(PBYTE pbData, DWORD dwLength)
for(unsigned int i=0;i<uiFileCount;i++)
{
EAudioType type = static_cast<EAudioType>(pFile->dwType);
//Bounds Checking
if (type < 0 || type >= e_AudioType_Max)
{
app.DebugPrintf("Error parser: EAudioType (%d) out of bounds!\n", type);
continue;
}
// Params
unsigned int uiParameterCount=*(unsigned int *)pbTemp;
pbTemp+=sizeof(int);
@@ -182,7 +178,8 @@ bool DLCAudioFile::processDLCDataFile(PBYTE pbData, DWORD dwLength)
if(it != parameterMapping.end() )
{
addParameter(type,static_cast<EAudioParameterType>(pParams->dwType),(WCHAR *)pParams->wchData);
//addParameter(type,static_cast<EAudioParameterType>(pParams->dwType),(WCHAR *)pParams->wchData);
addParameter(type, it->second, (WCHAR *)pParams->wchData);
}
pbTemp+=sizeof(C4JStorage::DLC_FILE_PARAM)+(sizeof(WCHAR)*pParams->dwWchCount);
pParams = (C4JStorage::DLC_FILE_PARAM *)pbTemp;
+10 -1
View File
@@ -14,7 +14,15 @@ public:
e_AudioType_Overworld = 0,
e_AudioType_Nether,
e_AudioType_End,
e_AudioType_End,
// @3UR: thanks https://github.com/LCERD/PCK-Studio/blob/500fc74395ce99fe20cbd7598999bfab3b606745/PckStudio.Core/FileFormats/PckAudioFile.cs#L25
e_AudioType_Creative,
e_AudioType_Menu,
e_AudioType_Battle,
e_AudioType_Tumble,
e_AudioType_Glide,
e_AudioType_BuildOff,
e_AudioType_Max,
};
@@ -24,6 +32,7 @@ public:
e_AudioParamType_Cuename = 0,
e_AudioParamType_Credit,
e_AudioParamType_CreditId,
e_AudioParamType_Max,
+5 -1
View File
@@ -15,7 +15,11 @@ DLCSkinFile::DLCSkinFile(const wstring &path) : DLCFile(DLCManager::e_DLCType_Sk
m_bIsFree = false;
m_uiAnimOverrideBitmask=0L;
}
void DLCSkinFile::getSkinAdjustments(_SkinAdjustments* adj)
{
memcpy(adj, &m_skinAdjustments, sizeof(_SkinAdjustments));
}
void DLCSkinFile::addData(PBYTE pbData, DWORD dwBytes)
{
app.AddMemoryTextureFile(m_path,pbData,dwBytes);
+3 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "DLCFile.h"
#include "../../../Minecraft.Client/HumanoidModel.h"
#include "../../../Minecraft.World/Entity.h"
class DLCSkinFile : public DLCFile
{
@@ -12,11 +13,12 @@ private:
unsigned int m_uiAnimOverrideBitmask;
bool m_bIsFree;
vector<SKIN_BOX *> m_AdditionalBoxes;
_SkinAdjustments m_skinAdjustments;
public:
DLCSkinFile(const wstring &path);
void getSkinAdjustments(_SkinAdjustments* adj);
void addData(PBYTE pbData, DWORD dwBytes) override;
void addParameter(DLCManager::EDLCParameterType type, const wstring &value) override;
@@ -1,171 +0,0 @@
<root>
<data name="IDS_NULL">
<value>Not Used</value>
</data>
<data name="IDS_OK">
<value>OK</value>
</data>
<data name="IDS_BACK">
<value>Back</value>
</data>
<data name="IDS_CANCEL">
<value>Cancel</value>
</data>
<data name="IDS_YES">
<value>Yes</value>
</data>
<data name="IDS_NO">
<value>No</value>
</data>
<data name="IDS_CORRUPTSAVE_TITLE">
<value>Corrupt Save</value>
</data>
<data name="IDS_CORRUPTSAVE_TEXT">
<value>Your save data appears to be corrupt. Create a new save and overwrite the corrupt one?</value>
</data>
<data name="IDS_NOFREESPACE_TITLE">
<value>No Free Space</value>
</data>
<data name="IDS_NOFREESPACE_TEXT">
<value>Your selected storage device doesn't have enough free space to create a game save.</value>
</data>
<data name="IDS_SELECTAGAIN">
<value>Select again</value>
</data>
<data name="IDS_PLAYWITHOUTSAVING">
<value>Play without saving</value>
</data>
<data name="IDS_CREATEANEWSAVE">
<value>Create a new save</value>
</data>
<data name="IDS_OVERWRITESAVE_TITLE">
<value>Overwrite save?</value>
</data>
<data name="IDS_OVERWRITESAVE_TEXT">
<value>Your selected storage device already contains this save. Is it OK to overwrite it?</value>
</data>
<data name="IDS_OVERWRITESAVE_NO">
<value>No - don't overwrite</value>
</data>
<data name="IDS_OVERWRITESAVE_YES">
<value>Overwrite and save</value>
</data>
<data name="IDS_FAILED_TO_SAVE_TITLE">
<value>Save failed</value>
</data>
<data name="IDS_STORAGEDEVICEPROBLEM_TITLE">
<value>Storage Device Problem</value>
</data>
<data name="IDS_FAILED_TO_SAVE_TEXT">
<value>Your storage device is unavailable or has an error</value>
</data>
<data name="IDS_FAILED_TO_LOADSAVE_TEXT">
<value>Your storage device is unavailable or has an error. Please select a new storage device.</value>
</data>
<data name="IDS_SELECTANEWDEVICE">
<value>Select a new storage device</value>
</data>
<data name="IDS_NODEVICE_TITLE">
<value>No storage device selected</value>
</data>
<data name="IDS_NODEVICE_TEXT">
<value>If you do not select a storage device, game saves will be disabled</value>
</data>
<data name="IDS_NODEVICE_ACCEPT">
<value>Select a storage device</value>
</data>
<data name="IDS_NODEVICE_DECLINE">
<value>Continue without saving</value>
</data>
<data name="IDS_DEVICEGONE_TEXT">
<value>Your storage device has been removed. Please select a new one.</value>
</data>
<data name="IDS_DEVICEGONE_TITLE">
<value>Loading failed</value>
</data>
<data name="IDS_KEYBOARDUI_SAVEGAME_TITLE">
<value>Name the save</value>
</data>
<data name="IDS_KEYBOARDUI_SAVEGAME_TEXT">
<value>Enter a name for your savegame</value>
</data>
<data name="IDS_WARNING_ARCADE_TITLE">
<value>Return to Xbox Dashboard</value>
</data>
<data name="IDS_WARNING_ARCADE_TEXT">
<value>Are you sure you want to exit the game?</value>
</data>
<data name="IDS_PRO_RETURNEDTOMENU_TITLE">
<value>Signed out</value>
</data>
<data name="IDS_PRO_RETURNEDTOTITLESCREEN_TEXT">
<value>You have been returned to the title screen because your gamer profile was signed out</value>
</data>
<data name="IDS_PRO_RETURNEDTOMENU_TEXT">
<value>The match has ended because a gamer profile was signed out</value>
</data>
<data name="IDS_PRO_RETURNEDTOMENU_ACCEPT">
<value>Continue playing</value>
</data>
<data name="IDS_PRO_NOTONLINE_TITLE">
<value>Gamer profile not online</value>
</data>
<data name="IDS_PRO_NOTONLINE_TEXT">
<value>This game has some features which require an Xbox Live enabled gamer profile, but you are currently offline.</value>
</data>
<data name="IDS_PRO_XBOXLIVE_NOTIFICATION">
<value>This feature requires a gamer profile which is signed into Xbox Live.</value>
</data>
<data name="IDS_PRO_NOTONLINE_ACCEPT">
<value>Connect to Xbox Live</value>
</data>
<data name="IDS_PRO_NOTONLINE_DECLINE">
<value>Continue playing offline</value>
</data>
<data name="IDS_PRO_ACHIEVEMENTPROBLEM_TITLE">
<value>Achievement Award Problem</value>
</data>
<data name="IDS_PRO_ACHIEVEMENTPROBLEM_TEXT">
<value> There was a problem accessing your gamer profile. Your achievement could not be awarded at this time.</value>
</data>
<data name="IDS_PRO_NOPROFILE_TITLE">
<value>Gamer profile problem</value>
</data>
<data name="IDS_PRO_NOPROFILEOPTIONS_TEXT">
<value>Saving of settings to gamer profile has failed.</value>
</data>
<data name="IDS_PRO_GUESTPROFILE_TITLE">
<value>Guest Gamer Profile</value>
</data>
<data name="IDS_PRO_GUESTPROFILE_TEXT">
<value>Guest gamer profile cannot access this feature. Please use a different gamer profile.</value>
</data>
<data name="IDS_STO_SAVING_SHORT">
<value>Saving…</value>
</data>
<data name="IDS_STO_SAVING_LONG">
<value>Saving content. Please don't turn off your console.</value>
</data>
<data name="IDS_PRO_UNLOCKGAME_TITLE">
<value>Unlock Full Game</value>
</data>
<data name="IDS_PRO_UNLOCKGAME_TEXT">
<value>This is the Minecraft trial game. If you had the full game, you would just have earned an achievement!
Unlock the full game to experience the joy of Minecraft and to play with your friends across the globe through Xbox Live.
Would you like to unlock the full game?</value>
</data>
<data name="IDS_PRO_PROFILEPROBLEM_TEXT">
<value>You are being returned to the main menu because of a problem reading your profile.</value>
</data>
</root>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

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