3 Commits

Author SHA1 Message Date
Revela a00b9962bb Prevent exit-without-saving loophole for hardcore players
Switch player to Adventure mode on death in hardcore mode, ban their XUID, and trigger a save action to prevent quitting without saving.
2026-03-15 04:11:03 -05:00
Revela 00fef6e9d2 smartcmd/MinecraftConsoles and itsRevela/MinecraftConsoles network packet compatibility fix:
LoginPacket.cpp:
  - read(): Extracts hardcore from bit 3 of gameType (gameType & 0x8), then masks it off (gameType &
  ~0x8)
  - write(): Encodes hardcore into gameType via gameType | (m_isHardcore ? 0x8 : 0)
  - Removed the separate readBoolean()/writeBoolean() for m_isHardcore
  - Removed trailing + sizeof(bool) from getEstimatedSize()

  RespawnPacket.cpp:
  - read(): Extracts hardcore from bit 3 of the playerGameType byte, then masks it off before passing
  to GameType::byId()
  - write(): Encodes hardcore into the playerGameType byte via getId() | (m_isHardcore ? 0x8 : 0)
  - Removed the separate readBoolean()/writeBoolean() for m_isHardcore
  - Reverted getEstimatedSize() from 14+length to 13+length
2026-03-15 04:11:03 -05:00
Revela a82e0ccf82 detailed summary of every changed file:
---
  Minecraft.Client/ClientConnection.cpp

  Purpose: Propagate hardcore flag through network level creation

  - handleLogin() (2 sites): Changed MultiPlayerLevel constructor calls from hardcoded false for the
  hardcore parameter to packet->m_isHardcore, so the client-side level correctly knows it's hardcore
  when joining a server.
  - handleRespawn(): Same change - when creating a new dimension level on respawn, uses
  packet->m_isHardcore instead of querying minecraft->level->getLevelData()->isHardcore() (which could
   be stale/wrong).

  ---
  Minecraft.Client/Common/App_Defines.h

  Purpose: Define bitmask for hardcore host option

  - Added GAME_HOST_OPTION_BITMASK_HARDCORE (0x40000000) - a new bit in the host options bitfield to
  store whether the game is hardcore.

  ---
  Minecraft.Client/Common/App_enums.h

  Purpose: Add hardcore enum value

  - Added eGameHostOption_Hardcore to the eGameHostOption enum so code can get/set the hardcore flag
  via SetGameHostOption/GetGameHostOption.

  ---
  Minecraft.Client/Common/Consoles_App.cpp

  Purpose: Implement hardcore get/set in host options bitfield

  - SetGameHostOption(): Added case eGameHostOption_Hardcore - sets or clears the
  GAME_HOST_OPTION_BITMASK_HARDCORE bit.
  - GetGameHostOption(): Added case eGameHostOption_Hardcore - returns 1 if the hardcore bit is set, 0
   otherwise.

  ---
  Minecraft.Client/Common/Consoles_App.h

  Purpose: Store save folder name for hardcore world deletion

  - Added SetCurrentSaveFolderName() and GetCurrentSaveFolderName() public methods.
  - Added wstring m_currentSaveFolderName private member - stores the save folder name so the hardcore
   death handler can find and delete the world.

  ---
  Minecraft.Client/Common/UI/IUIScene_PauseMenu.cpp

  Purpose: Delete hardcore world's save data on exit

  - Added Win64_DeleteSaveDirectory() - a recursive directory deletion helper (Windows64 only).
  - In _ExitWorld(): Before the server is torn down, captures whether this is a hardcore death exit
  (getDeleteWorldOnExit()). Tries 3 sources for the save folder name: app storage, StorageManager, and
   MinecraftServer.
  - After the server fully stops, if shouldDeleteHardcoreWorld is true, deletes the entire
  Windows64\GameHDD\<savefolder> directory.

  ---
  Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp

  Purpose: Hardcore difficulty slider in Create World menu

  - Added file-scope s_bHardcore flag to track when the slider is at position 4 (Hardcore).
  - Constructor: Extended difficulty slider range from 0-3 to 0-4, resets s_bHardcore to false.
  - handleSliderMove(): When slider value >= 4, sets s_bHardcore = true, stores actual difficulty as 3
   (Hard), and displays "Hardcore" label. Otherwise behaves normally.
  - CreateGame(): Clears the save folder name (new world), and sets eGameHostOption_Hardcore based on
  s_bHardcore.
  - Minor: Changed RequestErrorMessage to RequestAlertMessage for a content restriction dialog.

  ---
  Minecraft.Client/Common/UI/UIScene_DeathMenu.cpp

  Purpose: Hardcore death screen behavior (Iggy UI)

  - Constructor: Checks if current level is hardcore. If so, shows IDS_HARDCORE_DEATH_MESSAGE on the
  respawn button and hides it. Otherwise shows normal "Respawn" button.
  - handlePress() - Respawn: Added safeguard - if hardcore, blocks respawn entirely.
  - handlePress() - Exit Game: If hardcore and host, skips save dialog, disables save-on-exit, enables
   delete-world-on-exit, and triggers immediate world exit.

  ---
  Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp

  Purpose: Show "Difficulty: Hardcore" in Load World menu + persist hardcore through game launch

  - Static array: Expanded m_iDifficultyTitleSettingA from 4 to 5 entries, added IDS_GAMEMODE_HARDCORE
   at index 4.
  - Constructor: Initializes m_bHardcore = false. In Windows64 block: sets up thumbnail name from save
   details, and reads isHardcore from params->saveDetails. If hardcore, immediately initializes the
  difficulty slider to show "Hardcore" locked at position 4.
  - tick(): When host options are read (bHostOptionsRead block), also reads the hardcore flag and
  re-initializes the slider if needed (for console path).
  - handleSliderMove(): If m_bHardcore, locks the slider at position 4 (prevents changing difficulty).
  - StartGameFromSave(): Stores the save folder name in app for later hardcore deletion. Sets
  eGameHostOption_Hardcore from m_bHardcore.

  ---
  Minecraft.Client/Common/UI/UIScene_LoadMenu.h

  Purpose: Declare hardcore member

  - Expanded m_iDifficultyTitleSettingA from [4] to [5].
  - Added bool m_bHardcore private member.

  ---
  Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp

  Purpose: Read hardcore flag from level.dat when building the save list

  - ReadLevelNameFromSaveFile(): Added optional bool *outHardcore parameter. Inside the NBT Data
  compound tag parsing, if outHardcore is non-null, reads dataTag->getBoolean(L"hardcore").
  - Save enumeration block (Windows64): Passes &saveHardcore to ReadLevelNameFromSaveFile and stores
  the result in m_saveDetails[i].isHardcore.

  ---
  Minecraft.Client/Common/UI/UIStructs.h

  Purpose: Add isHardcore to save list details struct

  - Added bool isHardcore field to _SaveListDetails struct.
  - Initialized to false in the constructor.

  ---
  Minecraft.Client/Common/XUI/XUI_Death.cpp

  Purpose: Hardcore death screen behavior (XUI/Xbox UI)

  - Mirror of the Iggy UIScene_DeathMenu.cpp changes but for the XUI rendering path.
  - OnInit(): Checks isHardcore(), hides respawn button and shows death message if true.
  - OnNotifyPressEx() - Exit Game: If hardcore and host, skips save, flags world for deletion, exits
  immediately.
  - OnNotifyPressEx() - Respawn: Safeguard to block respawn in hardcore.

  ---
  Minecraft.Client/Gui.cpp

  Purpose: Syntax fix

  - Fixed lines.push_back(L"" → lines.push_back(L"") - missing closing quote/paren in debug terrain
  feature display.

  ---
  Minecraft.Client/MinecraftServer.cpp

  Purpose: Server-side hardcore support

  - Constructor: Initializes m_deleteWorldOnExit = false.
  - loadLevel(): Captures the save folder name from StorageManager into m_saveFolderName for later use
   in hardcore world deletion.
  - isHardcore(): Changed from always returning false to returning
  app.GetGameHostOption(eGameHostOption_Hardcore) > 0 - this is the key change that makes the server
  actually report hardcore mode.

  ---
  Minecraft.Client/MinecraftServer.h

  Purpose: Declare hardcore-related members

  - Added bool m_deleteWorldOnExit and wstring m_saveFolderName private members.
  - Added setDeleteWorldOnExit(), getDeleteWorldOnExit(), and getSaveFolderName() public methods.

  ---
  Minecraft.Client/PlayerConnection.h

  Purpose: Thread-safety fix for kicked flag

  - Changed m_bWasKicked from bool to std::atomic<bool> (initialized with {false}).
  - Changed setWasKicked()/getWasKicked() to use .store()/.load() - fixes a race condition where the
  kicked flag is set on one thread and read on another.

  ---
  Minecraft.Client/PlayerList.cpp

  Purpose: Hardcore multiplayer - ban, respawn as Adventure, thread-safe bans

  - Constructor/Destructor: Added InitializeCriticalSection/DeleteCriticalSection for m_banCS.
  - placeNewPlayer(): Passes isHardcore() flag to the LoginPacket constructor so clients joining know
  it's hardcore.
  - respawn(): After respawn in hardcore, forces the player into Adventure mode (spectate-like: can
  look around but not interact). Sends GameEventPacket to sync client.
  - respawn() and toggleDimension() (2 sites): Pass isHardcore() to RespawnPacket constructor.
  - isXuidBanned(): Wrapped m_bannedXuids iteration with EnterCriticalSection/LeaveCriticalSection for
   thread safety.
  - banXuid() (new): Thread-safe method to add a player's XUID to the ban list - used when a player
  dies in hardcore multiplayer.

  ---
  Minecraft.Client/PlayerList.h

  Purpose: Declare ban-related additions

  - Added CRITICAL_SECTION m_banCS to protect m_bannedXuids.
  - Added void banXuid(PlayerUID xuid) public method.

  ---
  Minecraft.Client/SelectWorldScreen.cpp

  Purpose: Show [Hardcore] badge in Java-style world list

  - In renderItem(): If levelSummary->isHardcore(), appends  [Hardcore] to the world name display.

  ---
  Minecraft.Client/ServerPlayer.cpp

  Purpose: Hardcore death behavior on server

  - die(): If the level is hardcore, switches the dead player to Adventure mode (so they can't
  interact if somehow respawned).
  - Minor: Two comment lines changed // → /// (no functional change).

  ---
  Minecraft.Client/Windows64Media/strings.h

  Purpose: String IDs for hardcore UI text

  - Added 8 new string IDs (2286-2293): IDS_GAMEMODE_HARDCORE, IDS_HARDCORE, IDS_HARDCORE_TOOLTIP,
  IDS_HARDCORE_WARNING_TITLE, IDS_HARDCORE_WARNING_TEXT, IDS_HARDCORE_DEATH_MESSAGE,
  IDS_LABEL_HARDCORE, IDS_GAMEOPTION_HARDCORE.

  ---
  Minecraft.World/ConsoleSaveFileOriginal.cpp

  Purpose: Capture save folder name after first save (for new worlds)

  - SaveSaveDataCallback() (Windows64 only): After a successful save, if the app doesn't yet know the
  save folder name, attempts to capture it via StorageManager or by scanning Windows64\GameHDD\ for
  the newest folder. This handles the case where a newly-created hardcore world hasn't been saved yet
  when the folder name is needed.

  ---
  Minecraft.World/DisconnectPacket.h

  Purpose: Hardcore disconnect reason

  - Added eDisconnect_HardcoreDeath to the disconnect reason enum - used when kicking a player who
  died in hardcore multiplayer.

  ---
  Minecraft.World/LoginPacket.cpp & LoginPacket.h

  Purpose: Serialize hardcore flag in login packet

  - Added bool m_isHardcore member, initialized to false in both constructors.
  - Server→Client constructor now accepts bool isHardcore = false parameter.
  - read(): Reads m_isHardcore from the stream.
  - write(): Writes m_isHardcore to the stream.
  - getEstimatedSize(): Added sizeof(bool) for the new field.

  ---
  Minecraft.World/RespawnPacket.cpp & RespawnPacket.h

  Purpose: Serialize hardcore flag in respawn packet

  - Added bool m_isHardcore member, initialized to false.
  - Constructor now accepts bool isHardcore = false parameter.
  - read()/write(): Serialize m_isHardcore via readBoolean()/writeBoolean().
  - getEstimatedSize(): Changed from 13 to 14 bytes to account for the new boolean.
2026-03-15 04:10:57 -05:00
175 changed files with 3162 additions and 12375 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: 778 KiB

+31
View File
@@ -0,0 +1,31 @@
name: Build Minecraft Legacy Console Edition
on:
workflow_dispatch:
jobs:
build:
runs-on: windows-2022
strategy:
matrix:
configuration: [Release, Debug]
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
- name: Build Minecraft Legacy Console Edition
run: |
msbuild MinecraftConsoles.sln `
/p:Configuration=${{ matrix.configuration }} `
/p:Platform=Windows64 `
/m
- name: Upload Release + Debug Artifacts
uses: actions/upload-artifact@v4
with:
name: MinecraftClient-${{ matrix.configuration }}
path: x64/${{ matrix.configuration }}
+32
View File
@@ -0,0 +1,32 @@
name: MSBuild Debug Test
on:
workflow_dispatch:
pull_request:
types: [opened, reopened, synchronize]
paths-ignore:
- '.gitignore'
- '*.md'
- '.github/*.md'
push:
branches:
- 'main'
paths-ignore:
- '.gitignore'
- '*.md'
- '.github/*.md'
jobs:
build:
name: Build Windows64 (DEBUG)
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup msbuild
uses: microsoft/setup-msbuild@v2
- name: Build
run: MSBuild.exe MinecraftConsoles.sln /p:Configuration=Debug /p:Platform="Windows64"
+160
View File
@@ -0,0 +1,160 @@
name: Docker Nightly Dedicated Server
on:
workflow_dispatch:
push:
branches:
- "main"
- 'feature/dedicated-server'
paths-ignore:
- ".gitignore"
- "*.md"
- ".github/*.md"
permissions:
contents: read
packages: write
concurrency:
group: docker-nightly-dedicated-server
cancel-in-progress: true
jobs:
build-runtime:
name: Build Dedicated Server Runtime
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup msbuild
uses: microsoft/setup-msbuild@v2
- name: Build Dedicated Server Runtime Only
shell: pwsh
run: |
MSBuild.exe Minecraft.World\Minecraft.World.vcxproj /p:Configuration=Release /p:Platform=x64 /m
MSBuild.exe Minecraft.Server\Minecraft.Server.vcxproj /p:Configuration=Release /p:Platform=x64 /m
- name: Stage dedicated server runtime
shell: pwsh
run: |
$serverOut = "Minecraft.Server/x64/Minecraft.Server/Release"
$stage = ".artifacts/dedicated-server-runtime"
if (Test-Path $stage) {
Remove-Item -Path $stage -Recurse -Force
}
New-Item -ItemType Directory -Path (Join-Path $stage "Windows64") -Force | Out-Null
# Minimum required runtime files
$required = @(
"Minecraft.Server.exe",
"iggy_w64.dll",
"Common"
)
foreach ($entry in $required) {
$src = Join-Path $serverOut $entry
if (-not (Test-Path $src)) {
throw "Missing required runtime path: $src"
}
}
# Copy required files
Copy-Item -Path (Join-Path $serverOut "Minecraft.Server.exe") -Destination (Join-Path $stage "Minecraft.Server.exe") -Force
Copy-Item -Path (Join-Path $serverOut "iggy_w64.dll") -Destination (Join-Path $stage "iggy_w64.dll") -Force
Copy-Item -Path (Join-Path $serverOut "Common") -Destination (Join-Path $stage "Common") -Recurse -Force
if (Test-Path (Join-Path $serverOut "Windows64")) {
Copy-Item -Path (Join-Path $serverOut "Windows64/*") -Destination (Join-Path $stage "Windows64") -Recurse -Force
} else {
Write-Host "Windows64 directory is not present in build output; staging without it."
}
Get-ChildItem -Path $stage -Recurse -File | Select-Object -First 20 | ForEach-Object {
Write-Host "Staged: $($_.FullName)"
}
- name: Upload dedicated server runtime to artifacts
uses: actions/upload-artifact@v4
with:
name: dedicated-server-runtime
if-no-files-found: error
path: |
.artifacts/dedicated-server-runtime/**
docker-publish:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: build-runtime
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download dedicated server runtime from artifacts
uses: actions/download-artifact@v4
with:
name: dedicated-server-runtime
path: .artifacts/runtime
- name: Prepare Docker runtime directory
shell: bash
run: |
set -euo pipefail
rm -rf runtime
mkdir -p runtime
cp .artifacts/runtime/Minecraft.Server.exe runtime/Minecraft.Server.exe
cp .artifacts/runtime/iggy_w64.dll runtime/iggy_w64.dll
cp -R .artifacts/runtime/Common runtime/Common
mkdir -p runtime/Windows64
if [[ -d ".artifacts/runtime/Windows64" ]]; then
cp -R .artifacts/runtime/Windows64/. runtime/Windows64/
fi
test -f runtime/Minecraft.Server.exe
test -f runtime/iggy_w64.dll
test -d runtime/Common
test -d runtime/Windows64
- name: Compute image name
id: image
shell: bash
run: |
owner="$(echo "${{ vars.CONTAINER_REGISTRY_OWNER || github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
image_tag="nightly"
# if [[ "${{ github.ref }}" != "refs/heads/main" ]]; then
# image_tag="nightly-test"
# fi
echo "owner=$owner" >> "$GITHUB_OUTPUT"
echo "image=ghcr.io/$owner/minecraft-lce-dedicated-server" >> "$GITHUB_OUTPUT"
echo "image_tag=$image_tag" >> "$GITHUB_OUTPUT"
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.image.outputs.image }}
tags: |
type=raw,value=${{ steps.image.outputs.image_tag }}
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME || github.actor }}
password: ${{ secrets.GHCR_TOKEN || secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
file: docker/dedicated-server/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
MC_RUNTIME_DIR=runtime
-167
View File
@@ -1,167 +0,0 @@
name: Nightly Server Release
on:
workflow_dispatch:
push:
branches:
- 'main'
paths-ignore:
- '.gitignore'
- '*.md'
- '.github/**'
- '!.github/workflows/nightly-server.yml'
permissions:
contents: write
packages: write
concurrency:
group: nightly-server
cancel-in-progress: true
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
platform: [Windows64]
steps:
- name: Checkout
uses: actions/checkout@v6
- 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.Server']"
- name: Zip Build
run: 7z a -r LCEServer${{ matrix.platform }}.zip ./build/${{ env.MATRIX_PLATFORM }}/Minecraft.Server/Release/* -x!*.ipdb -x!*.iobj
- name: Stage artifacts
run: |
New-Item -ItemType Directory -Force -Path staging
Copy-Item LCEServer${{ matrix.platform }}.zip staging/
- name: Stage exe and pdb
if: matrix.platform == 'Windows64'
run: |
Copy-Item ./build/${{ env.MATRIX_PLATFORM }}/Minecraft.Server/Release/Minecraft.Server.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: nightly-dedicated-server
name: Nightly Dedicated Server Release
body: |
Dedicated Server runtime for Windows64.
Download `LCEServerWindows64.zip` and extract it to a folder where you'd like to keep the server runtime.
files: |
artifacts/*
docker-publish:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download dedicated server runtime from artifacts
uses: actions/download-artifact@v4
with:
name: build-Windows64
path: .artifacts/
- name: Prepare Docker runtime directory
shell: bash
run: |
set -euo pipefail
rm -rf runtime
mkdir -p runtime
unzip .artifacts/LCEServerWindows64.zip -d runtime
- name: Compute image name
id: image
shell: bash
run: |
owner="$(echo "${{ vars.CONTAINER_REGISTRY_OWNER || github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
image_tag="nightly"
# if [[ "${{ github.ref }}" != "refs/heads/main" ]]; then
# image_tag="nightly-test"
# fi
echo "owner=$owner" >> "$GITHUB_OUTPUT"
echo "image=ghcr.io/$owner/minecraft-lce-dedicated-server" >> "$GITHUB_OUTPUT"
echo "image_tag=$image_tag" >> "$GITHUB_OUTPUT"
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.image.outputs.image }}
tags: |
type=raw,value=${{ steps.image.outputs.image_tag }}
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME || github.actor }}
password: ${{ secrets.GHCR_TOKEN || secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
file: docker/dedicated-server/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
MC_RUNTIME_DIR=runtime
cleanup:
needs: [build, release]
if: always()
runs-on: ubuntu-latest
steps:
- name: Cleanup artifacts
uses: geekyeggo/delete-artifact@v5
with:
name: build-*
+9 -1
View File
@@ -1,7 +1,15 @@
name: Nightly Releases
on:
workflow_dispatch:
workflow_dispatch:
push:
branches:
- 'main'
- 'feature/dedicated-server'
paths-ignore:
- '.gitignore'
- '*.md'
- '.github/*.md'
permissions:
contents: write
-32
View File
@@ -1,32 +0,0 @@
name: Pull Request Build
on:
workflow_dispatch:
pull_request:
types: [opened, reopened, synchronize]
paths-ignore:
- '.gitignore'
- '*.md'
- '.github/*.md'
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- 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: windows64
buildPreset: windows64-debug
+32 -4
View File
@@ -26,7 +26,6 @@ mono_crash.*
[Rr]elease/
[Rr]eleases/
x64/
x64_*/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
@@ -408,10 +407,39 @@ enc_temp_folder/
Minecraft.Client/Schematics/
Minecraft.Client/Windows64/GameHDD/
# CMake build output
build/
# Intermediate build files (per-project)
Minecraft.Client/x64/
Minecraft.Client/Debug/
Minecraft.Client/x64_Debug/
Minecraft.Client/Release/
Minecraft.Client/x64_Release/
Minecraft.World/x64/
Minecraft.World/Debug/
Minecraft.World/x64_Debug/
Minecraft.World/Release/
Minecraft.World/x64_Release/
Minecraft.Server/x64/
Minecraft.Server/Debug/
Minecraft.Server/x64_Debug/
Minecraft.Server/Release/
Minecraft.Server/x64_Release/
build/*
# Existing build output files
!x64/**/Effects.msscmp
!x64/**/iggy_w64.dll
!x64/**/mss64.dll
!x64/**/redist64/
# Local saves
Minecraft.Client/Saves/
# Server data
tmp*/
_server_asset_probe/
server-data/
# Visual Studio Per-User Config
*.user
/out
+216 -85
View File
@@ -13,101 +13,232 @@ if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
message(FATAL_ERROR "Use a 64-bit generator/toolchain (x64).")
endif()
set(CMAKE_CONFIGURATION_TYPES
"Debug"
"Release"
CACHE STRING "" FORCE
)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
function(configure_compiler_target target)
# MSVC and compatible compilers (like Clang-cl)
if (MSVC)
target_compile_options(${target} PRIVATE
$<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:C,CXX>>:/W3>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/W0>
$<$<COMPILE_LANGUAGE:C,CXX>:/MP>
$<$<COMPILE_LANGUAGE:C,CXX>:/FS>
$<$<COMPILE_LANGUAGE:C,CXX>:/GS>
$<$<COMPILE_LANGUAGE:CXX>:/EHsc>
$<$<COMPILE_LANGUAGE:CXX>:/GR>
$<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:C,CXX>>:/Od>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/O2 /Oi /GT /GF>
)
endif()
# MSVC
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${target} PRIVATE
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/GL>
)
target_link_options(${target} PRIVATE
$<$<CONFIG:Release>:/LTCG:incremental>
)
endif()
# Clang
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(${target} PRIVATE
$<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:C,CXX>>:-O0 -Wall>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:-O2 -w -flto>
)
target_link_options(${target} PRIVATE
$<$<CONFIG:Release>:-flto>
)
endif()
function(configure_msvc_target target)
target_compile_options(${target} PRIVATE
$<$<AND:$<NOT:$<CONFIG:Release>>,$<COMPILE_LANGUAGE:C,CXX>>:/W3>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/W0>
$<$<COMPILE_LANGUAGE:C,CXX>:/MP>
$<$<COMPILE_LANGUAGE:C,CXX>:/FS>
$<$<COMPILE_LANGUAGE:CXX>:/EHsc>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/GL /O2 /Oi /GT /GF>
)
endfunction()
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/WorldSources.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/ClientSources.cmake")
# ---
# Configuration
# ---
set(MINECRAFT_SHARED_DEFINES
_LARGE_WORLDS
_DEBUG_MENUS_ENABLED
$<$<CONFIG:Debug>:_DEBUG>
_CRT_NON_CONFORMING_SWPRINTFS
_CRT_SECURE_NO_WARNINGS
list(TRANSFORM MINECRAFT_WORLD_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/")
list(TRANSFORM MINECRAFT_CLIENT_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/")
list(APPEND MINECRAFT_CLIENT_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Xbox/MinecraftWindows.rc"
)
# Add platform-specific defines
list(APPEND MINECRAFT_SHARED_DEFINES ${PLATFORM_DEFINES})
# ---
# Sources
# ---
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)
add_library(MinecraftWorld STATIC ${MINECRAFT_WORLD_SOURCES})
target_include_directories(MinecraftWorld PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/x64headers"
)
target_compile_definitions(MinecraftWorld PRIVATE
$<$<CONFIG:Debug>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64>
$<$<NOT:$<CONFIG:Debug>>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64>
)
if(MSVC)
configure_msvc_target(MinecraftWorld)
endif()
# ---
# Build versioning
# ---
set(BUILDVER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateBuildVer.cmake")
set(BUILDVER_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/Common/BuildVer.h")
add_executable(MinecraftClient WIN32 ${MINECRAFT_CLIENT_SOURCES})
target_include_directories(MinecraftClient PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/include"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Xbox/Sentient/Include"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/x64headers"
"${CMAKE_CURRENT_SOURCE_DIR}/include/"
)
target_compile_definitions(MinecraftClient PRIVATE
$<$<CONFIG:Debug>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64>
$<$<NOT:$<CONFIG:Debug>>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64>
)
if(MSVC)
configure_msvc_target(MinecraftClient)
target_link_options(MinecraftClient PRIVATE
$<$<CONFIG:Release>:/LTCG /INCREMENTAL:NO>
)
endif()
add_custom_target(GenerateBuildVer
COMMAND ${CMAKE_COMMAND}
"-DOUTPUT_FILE=${BUILDVER_OUTPUT}"
-P "${BUILDVER_SCRIPT}"
COMMENT "Generating BuildVer.h..."
set_target_properties(MinecraftClient PROPERTIES
VS_DEBUGGER_WORKING_DIRECTORY "$<TARGET_FILE_DIR:MinecraftClient>"
)
target_link_libraries(MinecraftClient PRIVATE
MinecraftWorld
d3d11
XInput9_1_0
wsock32
legacy_stdio_definitions
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/lib/iggy_w64.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/lib/iggyperfmon_w64.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/lib/iggyexpruntime_w64.lib"
$<$<CONFIG:Debug>:
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Input_d.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Storage_d.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC_d.lib"
>
$<$<NOT:$<CONFIG:Debug>>:
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Input.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Storage.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC.lib"
>
)
set(MINECRAFT_SERVER_SOURCES ${MINECRAFT_CLIENT_SOURCES})
list(APPEND MINECRAFT_SERVER_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Windows64/ServerMain.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Access/Access.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Access/BanManager.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Access/WhitelistManager.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCli.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCliInput.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCliParser.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCliEngine.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/ServerCliRegistry.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/ban/CliCommandBan.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/ban-ip/CliCommandBanIp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/ban-list/CliCommandBanList.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/help/CliCommandHelp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/pardon/CliCommandPardon.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/pardon-ip/CliCommandPardonIp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/stop/CliCommandStop.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/list/CliCommandList.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/tp/CliCommandTp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/whitelist/CliCommandWhitelist.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/gamemode/CliCommandGamemode.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/time/CliCommandTime.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/weather/CliCommandWeather.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/give/CliCommandGive.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/enchant/CliCommandEnchant.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/kill/CliCommandKill.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/defaultgamemode/CliCommandDefaultGamemode.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/experience/CliCommandExperience.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Common/FileUtils.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Common/StringUtils.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/ServerLogger.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/ServerLogManager.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/ServerProperties.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/vendor/linenoise/linenoise.c"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/WorldManager.cpp"
)
add_executable(MinecraftServer ${MINECRAFT_SERVER_SOURCES})
target_include_directories(MinecraftServer PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/include"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Xbox/Sentient/Include"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/x64headers"
"${CMAKE_CURRENT_SOURCE_DIR}/include/"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Windows64"
)
target_compile_definitions(MinecraftServer PRIVATE
$<$<CONFIG:Debug>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;MINECRAFT_SERVER_BUILD>
$<$<NOT:$<CONFIG:Debug>>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;MINECRAFT_SERVER_BUILD>
)
if(MSVC)
configure_msvc_target(MinecraftServer)
target_link_options(MinecraftServer PRIVATE
$<$<CONFIG:Release>:/LTCG /INCREMENTAL:NO>
)
endif()
set_target_properties(MinecraftServer PROPERTIES
OUTPUT_NAME "Minecraft.Server"
VS_DEBUGGER_WORKING_DIRECTORY "$<TARGET_FILE_DIR:MinecraftServer>"
VS_DEBUGGER_COMMAND_ARGUMENTS "-port 25565 -bind 0.0.0.0 -name DedicatedServer"
)
target_link_libraries(MinecraftServer PRIVATE
MinecraftWorld
d3d11
XInput9_1_0
wsock32
legacy_stdio_definitions
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/lib/iggy_w64.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/lib/iggyperfmon_w64.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/Iggy/lib/iggyexpruntime_w64.lib"
$<$<CONFIG:Debug>:
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Input_d.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Storage_d.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC_d.lib"
>
$<$<NOT:$<CONFIG:Debug>>:
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Input.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Storage.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Windows64/4JLibs/libs/4J_Render_PC.lib"
>
)
if(CMAKE_HOST_WIN32)
message(STATUS "Starting redist copy...")
execute_process(
COMMAND robocopy.exe
"${CMAKE_CURRENT_SOURCE_DIR}/x64/Release"
"${CMAKE_CURRENT_BINARY_DIR}"
/S /MT /R:0 /W:0 /NP
)
message(STATUS "Starting asset copy...")
execute_process(
COMMAND robocopy.exe
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client"
"${CMAKE_CURRENT_BINARY_DIR}"
/S /MT /R:0 /W:0 /NP
/XF "*.cpp" "*.c" "*.h" "*.hpp" "*.asm"
"*.xml" "*.lang" "*.vcxproj" "*.vcxproj.*" "*.sln"
"*.docx" "*.xls"
"*.bat" "*.cmd" "*.ps1" "*.py"
"*Test*"
/XD "Durango*" "Orbis*" "PS*" "Xbox"
)
message(STATUS "Patching Windows64Media...")
execute_process(
COMMAND robocopy.exe
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/DurangoMedia"
"${CMAKE_CURRENT_BINARY_DIR}/Windows64Media"
/S /MT /R:0 /W:0 /NP
/XF "*.h" "*.xml" "*.lang" "*.bat"
)
elseif(CMAKE_HOST_UNIX)
message(STATUS "Starting redist copy...")
execute_process(
COMMAND rsync -av "${CMAKE_CURRENT_SOURCE_DIR}/x64/Release/" "${CMAKE_CURRENT_BINARY_DIR}/"
)
message(STATUS "Starting asset copy...")
execute_process(
COMMAND rsync -av
"--exclude=*.cpp" "--exclude=*.c" "--exclude=*.h" "--exclude=*.hpp" "--exclude=*.asm"
"--exclude=*.xml" "--exclude=*.lang" "--exclude=*.vcxproj" "--exclude=*.vcxproj.*" "--exclude=*.sln"
"--exclude=*.docx" "--exclude=*.xls"
"--exclude=*.bat" "--exclude=*.cmd" "--exclude=*.ps1" "--exclude=*.py"
"--exclude=*Test*"
"--exclude=Durango*" "--exclude=Orbis*" "--exclude=PS*" "--exclude=Xbox"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/" "${CMAKE_CURRENT_BINARY_DIR}/"
)
message(STATUS "Patching Windows64Media...")
execute_process(
COMMAND rsync -av
"--exclude=*.h" "--exclude=*.xml" "--exclude=*.lang" "--exclude=*.bat"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/DurangoMedia/" "${CMAKE_CURRENT_BINARY_DIR}/Windows64Media/"
)
else()
message(FATAL_ERROR "Redist and asset copying is only supported on Windows (Robocopy) and Unix systems (rsync).")
endif()
add_custom_command(TARGET MinecraftServer POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-DPROJECT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
-DOUTPUT_DIR="$<TARGET_FILE_DIR:MinecraftServer>"
-DCONFIGURATION=$<CONFIG>
-P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CopyServerAssets.cmake"
VERBATIM
)
add_dependencies(Minecraft.World GenerateBuildVer)
add_dependencies(Minecraft.Client GenerateBuildVer)
if(PLATFORM_NAME STREQUAL "Windows64")
add_dependencies(Minecraft.Server GenerateBuildVer)
endif()
# ---
# 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(DIRECTORY PROPERTY VS_STARTUP_PROJECT MinecraftServer)
-94
View File
@@ -1,94 +0,0 @@
{
"version": 5,
"configurePresets": [
{
"name": "base",
"generator": "Ninja Multi-Config",
"binaryDir": "${sourceDir}/build/${presetName}",
"hidden": true
},
{
"name": "windows64",
"displayName": "Windows64",
"inherits": "base",
"cacheVariables": {
"PLATFORM_DEFINES": "_WINDOWS64",
"PLATFORM_NAME": "Windows64",
"IGGY_LIBS": "iggy_w64.lib;iggyperfmon_w64.lib;iggyexpruntime_w64.lib"
}
},
{
"name": "durango",
"displayName": "Durango",
"inherits": "base",
"toolchainFile": "${sourceDir}/cmake/toolchains/durango.cmake",
"cacheVariables": {
"PLATFORM_DEFINES": "_DURANGO;_XBOX_ONE",
"PLATFORM_NAME": "Durango",
"IGGY_LIBS": "iggy_durango.lib;iggyperfmon_durango.lib"
}
},
{
"name": "orbis",
"displayName": "ORBIS",
"inherits": "base",
"toolchainFile": "${sourceDir}/cmake/toolchains/orbis.cmake",
"cacheVariables": {
"PLATFORM_DEFINES": "__ORBIS__",
"PLATFORM_NAME": "Orbis",
"IGGY_LIBS": "libiggy_orbis.a;libiggyperfmon_orbis.a"
}
},
{
"name": "ps3",
"displayName": "PS3",
"inherits": "base",
"toolchainFile": "${sourceDir}/cmake/toolchains/ps3.cmake",
"cacheVariables": {
"PLATFORM_DEFINES": "__PS3__",
"PLATFORM_NAME": "PS3",
"IGGY_LIBS": "libiggy_ps3.a;libiggyperfmon_ps3.a;libiggyexpruntime_ps3.a"
}
},
{
"name": "psvita",
"displayName": "PSVita",
"inherits": "base",
"toolchainFile": "${sourceDir}/cmake/toolchains/psvita.cmake",
"cacheVariables": {
"PLATFORM_DEFINES": "__PSVITA__",
"PLATFORM_NAME": "PSVita",
"IGGY_LIBS": "libiggy_psp2.a;libiggyperfmon_psp2.a"
}
},
{
"name": "xbox360",
"displayName": "Xbox 360",
"inherits": "base",
"toolchainFile": "${sourceDir}/cmake/toolchains/xbox360.cmake",
"cacheVariables": {
"PLATFORM_DEFINES": "_XBOX",
"PLATFORM_NAME": "Xbox"
}
}
],
"buildPresets": [
{ "name": "windows64-debug", "displayName": "Windows64 - Debug", "configurePreset": "windows64", "configuration": "Debug" },
{ "name": "windows64-release", "displayName": "Windows64 - Release", "configurePreset": "windows64", "configuration": "Release" },
{ "name": "durango-debug", "displayName": "Durango - Debug", "configurePreset": "durango", "configuration": "Debug" },
{ "name": "durango-release", "displayName": "Durango - Release", "configurePreset": "durango", "configuration": "Release" },
{ "name": "orbis-debug", "displayName": "ORBIS - Debug", "configurePreset": "orbis", "configuration": "Debug" },
{ "name": "orbis-release", "displayName": "ORBIS - Release", "configurePreset": "orbis", "configuration": "Release" },
{ "name": "ps3-debug", "displayName": "PS3 - Debug", "configurePreset": "ps3", "configuration": "Debug" },
{ "name": "ps3-release", "displayName": "PS3 - Release", "configurePreset": "ps3", "configuration": "Release" },
{ "name": "psvita-debug", "displayName": "PSVita - Debug", "configurePreset": "psvita", "configuration": "Debug" },
{ "name": "psvita-release", "displayName": "PSVita - Release", "configurePreset": "psvita", "configuration": "Release" },
{ "name": "xbox360-debug", "displayName": "Xbox 360 - Debug", "configurePreset": "xbox360", "configuration": "Debug" },
{ "name": "xbox360-release", "displayName": "Xbox 360 - Release", "configurePreset": "xbox360", "configuration": "Release" }
]
}
+19 -19
View File
@@ -1,14 +1,16 @@
# Compile Instructions
## Visual Studio
## Visual Studio (`.sln`)
1. Clone or download the repository
1. Open the repo folder in Visual Studio 2022+.
2. Wait for cmake to configure the project and load all assets (this may take a few minutes on the first run).
3. Right click a folder in the solution explorer and switch to the 'CMake Targets View'
4. Select platform and configuration from the dropdown. EG: `Windows64 - Debug` or `Windows64 - Release`
5. Pick the startup project `Minecraft.Client.exe` or `Minecraft.Server.exe` using the debug targets dropdown
6. Build and run the project:
1. Open `MinecraftConsoles.sln` in Visual Studio 2022.
2. Set Startup Project:
- Client: `Minecraft.Client`
- Dedicated server: `Minecraft.Server`
3. Select configuration:
- `Debug` (recommended), or
- `Release`
4. Select platform: `Windows64`.
5. Build and run:
- `Build > Build Solution` (or `Ctrl+Shift+B`)
- Start debugging with `F5`.
@@ -27,52 +29,50 @@
Configure (use your VS Community instance explicitly):
Open `Developer PowerShell for VS` and run:
```powershell
cmake --preset windows64
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_GENERATOR_INSTANCE="C:/Program Files/Microsoft Visual Studio/2022/Community"
```
Build Debug:
```powershell
cmake --build --preset windows64-debug --target Minecraft.Client
cmake --build build --config Debug --target MinecraftClient
```
Build Release:
```powershell
cmake --build --preset windows64-release --target Minecraft.Client
cmake --build build --config Release --target MinecraftClient
```
Build Dedicated Server (Debug):
```powershell
cmake --build --preset windows64-debug --target Minecraft.Server
cmake --build build --config Debug --target MinecraftServer
```
Build Dedicated Server (Release):
```powershell
cmake --build --preset windows64-release --target Minecraft.Server
cmake --build build --config Release --target MinecraftServer
```
Run executable:
```powershell
cd .\build\windows64\Minecraft.Client\Debug
.\Minecraft.Client.exe
cd .\build\Debug
.\MinecraftClient.exe
```
Run dedicated server:
```powershell
cd .\build\windows64\Minecraft.Server\Debug
cd .\build\Debug
.\Minecraft.Server.exe -port 25565 -bind 0.0.0.0 -name DedicatedServer
```
Notes:
- The CMake build is Windows-only and x64-only.
- Contributors on macOS or Linux need a Windows machine or VM to build the project. Running the game via Wine is separate from having a supported build environment.
- Post-build asset copy is automatic for `Minecraft.Client` in CMake (Debug and Release variants).
- Post-build asset copy is automatic for `MinecraftClient` in CMake (Debug and Release variants).
- The game relies on relative paths (for example `Common\Media\...`), so launching from the output directory is required.
-96
View File
@@ -1,96 +0,0 @@
include("${CMAKE_CURRENT_LIST_DIR}/cmake/sources/Common.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cmake/sources/Durango.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cmake/sources/ORBIS.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cmake/sources/PS3.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cmake/sources/PSVita.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cmake/sources/Windows.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cmake/sources/Xbox360.cmake")
include("${CMAKE_SOURCE_DIR}/cmake/CommonSources.cmake")
include("${CMAKE_SOURCE_DIR}/cmake/Utils.cmake")
# Combine all source files into a single variable for the target
# We cant use CMAKE_CONFIGURE_PRESET here as VS doesn't set it, so just rely on the folder
set(MINECRAFT_CLIENT_SOURCES
${MINECRAFT_CLIENT_COMMON}
$<$<STREQUAL:${PLATFORM_NAME},Durango>:${MINECRAFT_CLIENT_DURANGO}>
$<$<STREQUAL:${PLATFORM_NAME},Orbis>:${MINECRAFT_CLIENT_ORBIS}>
$<$<STREQUAL:${PLATFORM_NAME},PS3>:${MINECRAFT_CLIENT_PS3}>
$<$<STREQUAL:${PLATFORM_NAME},PSVita>:${MINECRAFT_CLIENT_PSVITA}>
$<$<STREQUAL:${PLATFORM_NAME},Windows64>:${MINECRAFT_CLIENT_WINDOWS}>
$<$<STREQUAL:${PLATFORM_NAME},Xbox>:${MINECRAFT_CLIENT_XBOX360}>
${SOURCES_COMMON}
)
add_executable(Minecraft.Client ${MINECRAFT_CLIENT_SOURCES})
# Only define executable on windows
if(PLATFORM_NAME STREQUAL "Windows64")
set_target_properties(Minecraft.Client PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
target_include_directories(Minecraft.Client PRIVATE
"${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/"
)
target_compile_definitions(Minecraft.Client PRIVATE
${MINECRAFT_SHARED_DEFINES}
)
target_precompile_headers(Minecraft.Client PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:stdafx.h>")
set_source_files_properties(compat_shims.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON) # This redefines internal MSVC CRT symbols which will cause an issue with PCH
configure_compiler_target(Minecraft.Client)
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
d3dcompiler
XInput9_1_0
wsock32
legacy_stdio_definitions
$<$<CONFIG:Debug>: # Debug 4J libraries
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/4JLibs/libs/4J_Input_d.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/4JLibs/libs/4J_Storage_d.lib"
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/4JLibs/libs/4J_Render_PC_d.lib"
>
$<$<NOT:$<CONFIG:Debug>>: # Release 4J libraries
"${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"
>
)
# Iggy libs
foreach(lib IN LISTS IGGY_LIBS)
target_link_libraries(Minecraft.Client PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}/Iggy/lib/${lib}")
endforeach()
# ---
# Asset / redist copy
# ---
include("${CMAKE_SOURCE_DIR}/cmake/CopyAssets.cmake")
set(ASSET_FOLDER_PAIRS
"${CMAKE_CURRENT_SOURCE_DIR}/music" "music"
"${CMAKE_CURRENT_SOURCE_DIR}/Common/Media" "Common/Media"
"${CMAKE_CURRENT_SOURCE_DIR}/Common/res" "Common/res"
"${CMAKE_CURRENT_SOURCE_DIR}/Common/Trial" "Common/Trial"
"${CMAKE_CURRENT_SOURCE_DIR}/Common/Tutorial" "Common/Tutorial"
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}Media" "${PLATFORM_NAME}Media"
)
setup_asset_folder_copy(Minecraft.Client "${ASSET_FOLDER_PAIRS}")
# Copy redist files
add_copyredist_target(Minecraft.Client)
# Make sure GameHDD exists on Windows
if(PLATFORM_NAME STREQUAL "Windows64")
add_gamehdd_target(Minecraft.Client)
endif()
+8 -25
View File
@@ -6,7 +6,6 @@
#include "..\Minecraft.World\SharedConstants.h"
#include "..\Minecraft.World\StringHelpers.h"
#include "..\Minecraft.World\ChatPacket.h"
#include "..\Minecraft.World\ArabicShaping.h"
const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters;
vector<wstring> ChatScreen::s_chatHistory;
@@ -15,12 +14,7 @@ wstring ChatScreen::s_historyDraft;
bool ChatScreen::isAllowedChatChar(wchar_t c)
{
if (c < 0x20) return false;
// Block Unicode bidirectional override characters that can be used to
// spoof chat messages or impersonate players.
if (c >= 0x202A && c <= 0x202E) return false; // LRE, RLE, PDF, LRO, RLO
if (c >= 0x2066 && c <= 0x2069) return false; // LRI, RLI, FSI, PDI
return true;
return c >= 0x20 && (c == L'\u00A7' || allowedChars.empty() || allowedChars.find(c) != wstring::npos);
}
ChatScreen::ChatScreen()
@@ -99,9 +93,6 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
if (eventKey == Keyboard::KEY_RETURN)
{
wstring trim = trimString(message);
{ char buf[64]; sprintf_s(buf, "[CHAT] Sending (%d chars): ", (int)trim.length()); OutputDebugStringA(buf); }
OutputDebugStringW(trim.c_str());
OutputDebugStringA("\n");
if (trim.length() > 0)
{
if (!minecraft->handleClientSideCommand(trim))
@@ -144,7 +135,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); }
}
}
@@ -155,21 +145,14 @@ void ChatScreen::render(int xm, int ym, float a)
int x = 4;
drawString(font, prefix, x, height - 12, 0xe0e0e0);
x += font->width(prefix);
// Shape the full message as one unit so letter connections and word order
// are correct. Track where the logical cursor maps in the visual string.
int visualCursorPos = 0;
wstring shaped = shapeArabicText(message, cursorIndex, &visualCursorPos);
// Render the full shaped message without re-shaping it
drawStringPreshaped(font, shaped, x, height - 12, 0xe0e0e0);
// Place the cursor at the correct visual position
wstring beforeCursorVisual = shaped.substr(0, visualCursorPos);
int cursorX = x + font->widthPreshaped(beforeCursorVisual);
wstring beforeCursor = message.substr(0, cursorIndex);
wstring afterCursor = message.substr(cursorIndex);
drawStringLiteral(font, beforeCursor, x, height - 12, 0xe0e0e0);
x += font->widthLiteral(beforeCursor);
if (frame / 6 % 2 == 0)
drawString(font, L"_", cursorX, height - 12, 0xe0e0e0);
drawString(font, L"_", x, height - 12, 0xe0e0e0);
x += font->width(L"_");
drawStringLiteral(font, afterCursor, x, height - 12, 0xe0e0e0);
Screen::render(xm, ym, a);
}
+4 -6
View File
@@ -3315,9 +3315,7 @@ void ClientConnection::handleTileEditorOpen(shared_ptr<TileEditorOpenPacket> pac
void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
{
app.DebugPrintf("[SIGN] handleSignUpdate at (%d, %d, %d):\n", packet->x, packet->y, packet->z);
for (int i = 0; i < MAX_SIGN_LINES; i++)
app.DebugPrintf("[SIGN] Line%d: \"%ls\"\n", i+1, packet->lines[i].c_str());
app.DebugPrintf("ClientConnection::handleSignUpdate - ");
if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z))
{
shared_ptr<TileEntity> te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z);
@@ -3331,7 +3329,7 @@ void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
ste->SetMessage(i,packet->lines[i]);
}
app.DebugPrintf("[SIGN] verified=%d censored=%d\n", packet->m_bVerified, packet->m_bCensored);
app.DebugPrintf("verified = %d\tCensored = %d\n",packet->m_bVerified,packet->m_bCensored);
ste->SetVerified(packet->m_bVerified);
ste->SetCensored(packet->m_bCensored);
@@ -3339,12 +3337,12 @@ void ClientConnection::handleSignUpdate(shared_ptr<SignUpdatePacket> packet)
}
else
{
app.DebugPrintf("[SIGN] ERROR: tile entity is not a SignTileEntity\n");
app.DebugPrintf("dynamic_pointer_cast<SignTileEntity>(te) == nullptr\n");
}
}
else
{
app.DebugPrintf("[SIGN] ERROR: chunk not loaded at position\n");
app.DebugPrintf("hasChunkAt failed\n");
}
}
-8
View File
@@ -1,13 +1,5 @@
#include "stdafx.h"
#include "ClientConstants.h"
#include "Common/BuildVer.h"
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;
// 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
-3
View File
@@ -15,8 +15,5 @@ public:
static const wstring VERSION_STRING;
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;
};
+1 -2
View File
@@ -879,8 +879,7 @@ enum EControllerActions
MINECRAFT_ACTION_SPAWN_CREEPER,
MINECRAFT_ACTION_CHANGE_SKIN,
MINECRAFT_ACTION_FLY_TOGGLE,
MINECRAFT_ACTION_RENDER_DEBUG,
MINECRAFT_ACTION_SCREENSHOT
MINECRAFT_ACTION_RENDER_DEBUG
};
enum eMCLang
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#define VER_PRODUCTBUILD 560
#define VER_PRODUCTVERSION_STR_W L"DEV (unknown version)"
#define VER_FILEVERSION_STR_W VER_PRODUCTVERSION_STR_W
#define VER_BRANCHVERSION_STR_W L"UNKNOWN BRANCH"
#define VER_NETWORK VER_PRODUCTBUILD
Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -38220,56 +38220,6 @@
<Time>19</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>NormalHardcore</Name>
<Time>20</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>HalfHardcore</Name>
<Time>21</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>FullHardcore</Name>
<Time>22</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>HalfPoisonHardcore</Name>
<Time>23</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>FullPoisonHardcore</Name>
<Time>24</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>NormalFlashHardcore</Name>
<Time>25</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>HalfFlashHardcore</Name>
<Time>26</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>FullFlashHardcore</Name>
<Time>27</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>HalfPoisonFlashHardcore</Name>
<Time>28</Time>
<Command>stop</Command>
</NamedFrame>
<NamedFrame>
<Name>FullPoisonFlashHardcore</Name>
<Time>29</Time>
<Command>stop</Command>
</NamedFrame>
</NamedFrames>
<Timeline>
<Id>Border</Id>
@@ -38324,16 +38274,6 @@
<Interpolation>0</Interpolation>
<Prop>Graphics\HUD\Health_Background_Flash.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>20</Time>
<Interpolation>0</Interpolation>
<Prop>Graphics\HUD\Health_Background_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>25</Time>
<Interpolation>0</Interpolation>
<Prop>Graphics\HUD\Health_Background_Hardcore_Flash.png</Prop>
</KeyFrame>
</Timeline>
<Timeline>
<Id>Heart</Id>
@@ -38459,66 +38399,6 @@
<Prop>true</Prop>
<Prop>Graphics\HUD\HorseHealth_Half_Flash.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>20</Time>
<Interpolation>0</Interpolation>
<Prop>false</Prop>
<Prop></Prop>
</KeyFrame>
<KeyFrame>
<Time>21</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Half_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>22</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Full_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>23</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Half_Poison_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>24</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Full_Poison_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>25</Time>
<Interpolation>0</Interpolation>
<Prop>false</Prop>
<Prop></Prop>
</KeyFrame>
<KeyFrame>
<Time>26</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Half_Flash_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>27</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Full_Flash_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>28</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Half_Poison_Flash_Hardcore.png</Prop>
</KeyFrame>
<KeyFrame>
<Time>29</Time>
<Interpolation>0</Interpolation>
<Prop>true</Prop>
<Prop>Graphics\HUD\Health_Full_Poison_Flash_Hardcore.png</Prop>
</KeyFrame>
</Timeline>
</Timelines>
</XuiVisual>
+13 -3
View File
@@ -141,9 +141,6 @@ S32 UIBitmapFont::GetCodepointGlyph(U32 codepoint)
// 4J-JEV: Change "right single quotation marks" to apostrophies.
if (codepoint == 0x2019) codepoint = 0x27;
if (!m_cFontData->hasGlyph(codepoint))
return IGGY_GLYPH_INVALID;
return m_cFontData->getGlyphId(codepoint);
}
@@ -256,6 +253,19 @@ rrbool UIBitmapFont::GetGlyphBitmap(S32 glyph,F32 pixel_scale,IggyBitmapCharacte
while ( (0.5f + glyphScale) * truePixelScale < pixel_scale)
glyphScale++;
// Debug: log each unique (font, pixel_scale) pair
{
static std::unordered_set<int> s_loggedScaleKeys;
// Encode font pointer + quantized scale into a key to log each combo once
int scaleKey = (int)(pixel_scale * 100.0f) ^ (int)(uintptr_t)m_cFontData;
if (s_loggedScaleKeys.find(scaleKey) == s_loggedScaleKeys.end() && s_loggedScaleKeys.size() < 50) {
s_loggedScaleKeys.insert(scaleKey);
float tps = truePixelScale;
app.DebugPrintf("[FONT-DBG] GetGlyphBitmap: font=%s glyph=%d pixel_scale=%.3f truePixelScale=%.1f glyphScale=%.0f\n",
m_cFontData->getFontName().c_str(), glyph, pixel_scale, tps, glyphScale);
}
}
// 4J-JEV: Debug code to check which font sizes are being used.
#if (!defined _CONTENT_PACKAGE) && (VERBOSE_FONT_OUTPUT > 0)
+4 -11
View File
@@ -3,7 +3,6 @@
#include "UIControl.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\..\Minecraft.World\JavaMath.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
UIControl_Base::UIControl_Base()
{
@@ -33,16 +32,13 @@ void UIControl_Base::tick()
//app.DebugPrintf("Calling SetLabel - '%ls'\n", m_label.c_str());
m_bLabelChanged = false;
// Shape the text before sending to Iggy; m_label stays unshaped for future updates
wstring shaped = shapeArabicText(m_label.getString());
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_string_UTF16;
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*) shaped.c_str();
stringVal.length = (int)shaped.length();
stringVal.string = (IggyUTF16*) m_label.c_str();
stringVal.length = m_label.length();
value[0].string16 = stringVal;
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_setLabelFunc , 1 , value );
@@ -60,16 +56,13 @@ void UIControl_Base::setLabel(UIString label, bool instant, bool force)
{
m_bLabelChanged = false;
// Shape the text before sending to Iggy; m_label stays unshaped for future updates
wstring shaped = shapeArabicText(m_label.getString());
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_string_UTF16;
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*) shaped.c_str();
stringVal.length = (int)shaped.length();
stringVal.string = (IggyUTF16*)m_label.c_str();
stringVal.length = m_label.length();
value[0].string16 = stringVal;
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_setLabelFunc , 1 , value );
@@ -2,7 +2,6 @@
#include "UI.h"
#include "UIControl_Label.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
UIControl_Label::UIControl_Label()
{
@@ -23,15 +22,13 @@ void UIControl_Label::init(UIString label)
{
m_label = label;
wstring shaped = shapeArabicText(m_label.getString());
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_string_UTF16;
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*)shaped.c_str();
stringVal.length = (int)shaped.length();
stringVal.string = (IggyUTF16*)label.c_str();
stringVal.length = label.length();
value[0].string16 = stringVal;
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_initFunc , 1 , value );
}
@@ -1,7 +1,6 @@
#include "stdafx.h"
#include "UI.h"
#include "UIControl_SaveList.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
bool UIControl_SaveList::setupControl(UIScene *scene, IggyValuePath *parent, const string &controlName)
{
@@ -70,14 +69,12 @@ void UIControl_SaveList::addItem(const string &label, const wstring &iconName, i
void UIControl_SaveList::addItem(const wstring &label, const wstring &iconName, int data)
{
wstring shaped = shapeArabicText(label);
IggyDataValue result;
IggyDataValue value[3];
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*)shaped.c_str();
stringVal.length = static_cast<S32>(shaped.length());
stringVal.string = (IggyUTF16*)label.c_str();
stringVal.length = static_cast<S32>(label.length());
value[0].type = IGGY_DATATYPE_string_UTF16;
value[0].string16 = stringVal;
@@ -1,7 +1,6 @@
#include "stdafx.h"
#include "UI.h"
#include "UIControl_TextInput.h"
#include "..\..\Screen.h"
UIControl_TextInput::UIControl_TextInput()
{
@@ -212,21 +211,6 @@ UIControl_TextInput::EDirectEditResult UIControl_TextInput::tickDirectEdit()
}
}
// Paste from clipboard
if (g_KBMInput.IsKeyPressed('V') && g_KBMInput.IsKeyDown(VK_CONTROL))
{
wstring pasted = Screen::getClipboard();
for (size_t i = 0; i < pasted.length(); i++)
{
wchar_t pc = pasted[i];
if (pc < 0x20) continue; // skip control characters
if (m_iCharLimit > 0 && (int)m_editBuffer.length() >= m_iCharLimit) break;
m_editBuffer.insert(m_iCursorPos, 1, pc);
m_iCursorPos++;
changed = true;
}
}
// Arrow keys, Home, End, Delete for cursor movement
if (g_KBMInput.IsKeyPressed(VK_LEFT) && m_iCursorPos > 0)
{
@@ -13,7 +13,6 @@
#include "..\..\EnderDragonRenderer.h"
#include "..\..\MultiPlayerLocalPlayer.h"
#include "UIFontData.h"
#include "UIUnicodeBitmapFont.h"
#include "UISplitScreenHelpers.h"
#ifdef _WINDOWS64
#include "..\..\Windows64\KeyboardMouseInput.h"
@@ -194,7 +193,6 @@ UIController::UIController()
m_mcTTFFont = nullptr;
m_moj7 = nullptr;
m_moj11 = nullptr;
m_unicodeBitmapFont = nullptr;
// 4J-JEV: It's important that these remain the same, unless updateCurrentLanguage is going to be called.
m_eCurrentFont = m_eTargetFont = eFont_NotLoaded;
@@ -309,14 +307,6 @@ void UIController::postInit()
IggySetAS3ExternalFunctionCallbackUTF16 ( &UIController::ExternalFunctionCallback, this );
IggySetTextureSubstitutionCallbacks ( &UIController::TextureSubstitutionCreateCallback , &UIController::TextureSubstitutionDestroyCallback, this );
// Load a unicode bitmap font as Iggy's global fallback for characters not
// covered by the Mojangles bitmap font (CJK, Thai, Arabic, Korean, etc.).
// Uses the same glyph page PNGs as the legacy Font class, with matching
// Mojangles metrics for correct vertical alignment.
m_unicodeBitmapFont = new UIUnicodeBitmapFont("Mojangles_Unicode_Bitmap", SFontData::Mojangles_7);
m_unicodeBitmapFont->registerFont();
IggyFontSetFallbackFontUTF8("Mojangles_Unicode_Bitmap", -1, IGGY_FONTFLAG_none);
SetupFont();
//
loadSkins();
@@ -7,7 +7,6 @@ using namespace std;
class UIAbstractBitmapFont;
class UIBitmapFont;
class UIUnicodeBitmapFont;
class UITTFFont;
class UIComponent_DebugUIConsole;
class UIComponent_DebugUIMarketingGuide;
@@ -64,7 +63,6 @@ private:
UIAbstractBitmapFont *m_mcBitmapFont;
UITTFFont *m_mcTTFFont;
UIBitmapFont *m_moj7, *m_moj11;
UIUnicodeBitmapFont *m_unicodeBitmapFont;
std::mt19937 m_randomGenerator;
std::uniform_real_distribution<float> m_randomDistribution;
@@ -335,11 +335,6 @@ bool CFontData::unicodeIsWhitespace(unsigned int unicode)
return false;
}
bool CFontData::hasGlyph(unsigned int unicodepoint)
{
return m_unicodeMap.find(unicodepoint) != m_unicodeMap.end();
}
void CFontData::moveCursor(unsigned char *&cursor, unsigned int dx, unsigned int dy)
{
cursor += (dy * m_sFontData->m_uiGlyphMapX) + dx;
-3
View File
@@ -125,9 +125,6 @@ public:
// Returns true if this unicodepoint is whitespace
bool unicodeIsWhitespace(unsigned int unicodepoint);
// Returns true if this unicodepoint exists in the font's glyph map.
bool hasGlyph(unsigned int unicodepoint);
private:
// Move a pointer in an image dx pixels right and dy pixels down, wrap around in either dimension leads to unknown behaviour.
+8 -18
View File
@@ -480,6 +480,14 @@ SCreditTextItemDef UIScene_Credits::gs_aCreditDefs[MAX_CREDIT_STRINGS] =
{ L"Copyright (C) 2009-2013 by RAD Game Tools, Inc.", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
#else
{ L"Copyright (C) 2009-2014 by RAD Game Tools, Inc.", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
#endif
{ L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
{ L"", CREDIT_ICON, eCreditIcon_Miles,eSmallText }, // extra blank line
{ L"Uses Miles Sound System.", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
#ifdef __PS3__
{ L"Copyright (C) 1991-2013 by RAD Game Tools, Inc.", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
#else
{ L"Copyright (C) 1991-2014 by RAD Game Tools, Inc.", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
#endif
#ifdef __PS3__
{ L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
@@ -488,24 +496,6 @@ SCreditTextItemDef UIScene_Credits::gs_aCreditDefs[MAX_CREDIT_STRINGS] =
{ L"are trademarks of Dolby Laboratories.", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING,eSmallText }, // extra blank line
#endif
#endif
{L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"MinecraftConsoles", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eExtraLargeText},
{L"Project Maintainers", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText},
{L"smartcmd", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"codeHusky", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"Patoke", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"rtm516", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"mattsumi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"dxf", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"la", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"Thank you to our 100+ contributors on GitHub!", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText},
{L"github.com/smartcmd/MinecraftConsoles", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
{L"Additional Thanks", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText},
{L"notpies - Security Fixes", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}
};
UIScene_Credits::UIScene_Credits(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
@@ -1,7 +1,6 @@
#include "stdafx.h"
#include "UI.h"
#include "UIScene_Keyboard.h"
#include "..\..\Screen.h"
#ifdef _WINDOWS64
// Global buffer that stores the text entered in the native keyboard scene.
@@ -225,28 +224,6 @@ void UIScene_Keyboard::tick()
}
}
// Paste from clipboard
if (g_KBMInput.IsKeyPressed('V') && g_KBMInput.IsKeyDown(VK_CONTROL))
{
wstring pasted = Screen::getClipboard();
for (size_t i = 0; i < pasted.length(); i++)
{
wchar_t pc = pasted[i];
if (pc < 0x20) continue; // skip control characters
if (static_cast<int>(m_win64TextBuffer.length()) >= m_win64MaxChars) break;
if (m_bPCMode)
{
m_win64TextBuffer.insert(m_iCursorPos, 1, pc);
m_iCursorPos++;
}
else
{
m_win64TextBuffer += pc;
}
changed = true;
}
}
if (m_bPCMode)
{
// Arrow keys, Home, End, Delete for cursor movement
@@ -255,7 +255,7 @@ UIScene_LoadMenu::UIScene_LoadMenu(int iPad, void *initData, UILayer *parentLaye
{
wchar_t wSaveName[128];
ZeroMemory(wSaveName, sizeof(wSaveName));
MultiByteToWideChar(CP_UTF8, 0, params->saveDetails->UTF8SaveName, -1, wSaveName, 127);
mbstowcs(wSaveName, params->saveDetails->UTF8SaveName, 127);
m_levelName = wstring(wSaveName);
m_labelGameName.init(m_levelName);
}
@@ -49,7 +49,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
if (len > 0)
{
wchar_t wbuf[128] = {};
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, 127);
mbstowcs(wbuf, buf, 127);
return wstring(wbuf);
}
}
@@ -210,8 +210,6 @@ int UIScene_LoadOrJoinMenu::LoadSaveCallback(LPVOID lpParam,bool bRes)
UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
{
constexpr uint64_t MAXIMUM_SAVE_STORAGE = 4LL * 1024LL * 1024LL * 1024LL;
// Setup all the Iggy references we need for this scene
initialiseMovie();
app.SetLiveLinkRequired( true );
@@ -236,8 +234,8 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
m_controlJoinTimer.setVisible( true );
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(_WINDOWS64)
m_spaceIndicatorSaves.init(L"",eControl_SpaceIndicator,0, MAXIMUM_SAVE_STORAGE);
#if defined(_XBOX_ONE) || defined(__ORBIS__)
m_spaceIndicatorSaves.init(L"",eControl_SpaceIndicator,0, (4LL *1024LL * 1024LL * 1024LL) );
#endif
m_bUpdateSaveSize = false;
@@ -701,7 +699,7 @@ void UIScene_LoadOrJoinMenu::tick()
if(m_eSaveTransferState == eSaveTransfer_Idle)
m_bSaveTransferRunning = false;
#endif
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(_WINDOWS64)
#if defined(_XBOX_ONE) || defined(__ORBIS__)
if(m_bUpdateSaveSize)
{
if((m_iDefaultButtonsC > 0) && (m_iSaveListIndex >= m_iDefaultButtonsC))
@@ -722,7 +720,7 @@ void UIScene_LoadOrJoinMenu::tick()
if(m_pSaveDetails!=nullptr)
{
//CD - Fix - Adding define for ORBIS/XBOXONE
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(_WINDOWS64)
#if defined(_XBOX_ONE) || defined(__ORBIS__)
m_spaceIndicatorSaves.reset();
#endif
@@ -764,22 +762,6 @@ void UIScene_LoadOrJoinMenu::tick()
{
#if defined(_XBOX_ONE)
m_spaceIndicatorSaves.addSave(m_pSaveDetails->SaveInfoA[i].totalSize);
#elif defined(_WINDOWS64)
int origIdx = sortedIdx[i];
wchar_t wFilename[MAX_SAVEFILENAME_LENGTH];
ZeroMemory(wFilename, sizeof(wFilename));
mbstowcs(wFilename, m_pSaveDetails->SaveInfoA[origIdx].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
wstring filePath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\saveData.ms");
HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
DWORD fileSize = 0;
if (hFile != INVALID_HANDLE_VALUE) {
fileSize = GetFileSize(hFile, nullptr);
if (fileSize < 12 || fileSize == INVALID_FILE_SIZE) fileSize = 0;
CloseHandle(hFile);
}
m_spaceIndicatorSaves.addSave(fileSize);
#elif defined(__ORBIS__)
m_spaceIndicatorSaves.addSave(m_pSaveDetails->SaveInfoA[i].blocksUsed * (32 * 1024) );
#endif
@@ -792,17 +774,19 @@ void UIScene_LoadOrJoinMenu::tick()
#else
#ifdef _WINDOWS64
{
int origIdx = sortedIdx[i];
wchar_t wFilename[MAX_SAVEFILENAME_LENGTH];
ZeroMemory(wFilename, sizeof(wFilename));
mbstowcs(wFilename, m_pSaveDetails->SaveInfoA[origIdx].UTF8SaveFilename, MAX_SAVEFILENAME_LENGTH - 1);
wstring filePath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\saveData.ms");
bool saveHardcore = false;
wstring levelName = ReadLevelNameFromSaveFile(filePath, &saveHardcore);
m_saveDetails[i].isHardcore = saveHardcore;
if (!levelName.empty())
{
m_buttonListSaves.addItem(levelName, wstring(L""));
{
int n = WideCharToMultiByte(CP_UTF8, 0, levelName.c_str(), -1, m_saveDetails[i].UTF8SaveName, 127, nullptr, nullptr);
if (n <= 0) m_saveDetails[i].UTF8SaveName[0] = '\0';
m_saveDetails[i].UTF8SaveName[127] = '\0';
}
wcstombs(m_saveDetails[i].UTF8SaveName, levelName.c_str(), 127);
m_saveDetails[i].UTF8SaveName[127] = '\0';
}
else
{
@@ -1447,9 +1431,9 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
for (int k = 0; k < 127 && ui16Text[k]; k++)
wNewName[k] = static_cast<wchar_t>(ui16Text[k]);
// Convert to narrow for storage and in-memory update (UTF-8 to preserve Unicode)
char narrowName[256] = {};
WideCharToMultiByte(CP_UTF8, 0, wNewName, -1, narrowName, 255, nullptr, nullptr);
// Convert to narrow for storage and in-memory update
char narrowName[128] = {};
wcstombs(narrowName, wNewName, 127);
// Build the sidecar path: Windows64\GameHDD\{folder}\worldname.txt
wchar_t wFilename[MAX_SAVEFILENAME_LENGTH] = {};
@@ -1465,7 +1449,7 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
// Update the in-memory display name so the list reflects it immediately
strncpy_s(pClass->m_saveDetails[listPos].UTF8SaveName, narrowName, 127);
pClass->m_saveDetails[listPos].UTF8SaveName[127] = '\0'; // UTF8SaveName is still 128 bytes; narrowName fits as Arabic is <=2 bytes/char in UTF-8
pClass->m_saveDetails[listPos].UTF8SaveName[127] = '\0';
// Reuse the existing callback to trigger the list repopulate
UIScene_LoadOrJoinMenu::RenameSaveDataReturned(pClass, true);
@@ -2533,7 +2517,7 @@ int UIScene_LoadOrJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,C4JS
{
wchar_t wSaveName[128];
ZeroMemory(wSaveName, 128 * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, -1, wSaveName, 127);
mbstowcs_s(nullptr, wSaveName, 128, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, _TRUNCATE);
UIKeyboardInitData kbData;
kbData.title = app.GetString(IDS_RENAME_WORLD_TITLE);
kbData.defaultText = wSaveName;
@@ -20,7 +20,7 @@ private:
{
eControl_SavesList,
eControl_GamesList,
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(_WINDOWS64)
#if defined(_XBOX_ONE) || defined(__ORBIS__)
eControl_SpaceIndicator,
#endif
};
@@ -52,7 +52,7 @@ protected:
UIControl_SaveList m_buttonListGames;
UIControl_Label m_labelSavesListTitle, m_labelJoinListTitle, m_labelNoGames;
UIControl m_controlSavesTimer, m_controlJoinTimer;
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(_WINDOWS64)
#if defined(_XBOX_ONE) || defined(__ORBIS__)
UIControl_SpaceIndicatorBar m_spaceIndicatorSaves;
#endif
@@ -68,7 +68,7 @@ private:
UI_MAP_ELEMENT( m_controlSavesTimer, "SavesTimer")
UI_MAP_ELEMENT( m_controlJoinTimer, "JoinTimer")
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(_WINDOWS64)
#if defined(_XBOX_ONE) || defined(__ORBIS__)
UI_MAP_ELEMENT( m_spaceIndicatorSaves, "SaveSizeBar")
#endif
UI_END_MAP_ELEMENTS_AND_NAMES()
@@ -368,7 +368,7 @@ void UIScene_MainMenu::handlePress(F64 controlId, F64 childId)
UINT uiIDA[2];
uiIDA[0]=IDS_CANCEL;
uiIDA[1]=IDS_OK;
ui.RequestErrorMessage(IDS_WINDOWS_EXIT, IDS_WARNING_ARCADE_TEXT, uiIDA, 2, XUSER_INDEX_ANY,&UIScene_MainMenu::ExitGameReturned,this);
ui.RequestErrorMessage(IDS_WARNING_ARCADE_TITLE, IDS_WARNING_ARCADE_TEXT, uiIDA, 2, XUSER_INDEX_ANY,&UIScene_MainMenu::ExitGameReturned,this);
}
else
{
+4 -7
View File
@@ -4,7 +4,7 @@
#include "..\..\..\Minecraft.World\File.h"
#include "UITTFFont.h"
UITTFFont::UITTFFont(const string &name, const string &path, S32 fallbackCharacter, bool registerAsDefaultFonts)
UITTFFont::UITTFFont(const string &name, const string &path, S32 fallbackCharacter)
: m_strFontName(name)
{
app.DebugPrintf("UITTFFont opening %s\n",path.c_str());
@@ -41,12 +41,9 @@ UITTFFont::UITTFFont(const string &name, const string &path, S32 fallbackCharact
IggyFontInstallTruetypeFallbackCodepointUTF8( m_strFontName.c_str(), -1, IGGY_FONTFLAG_none, fallbackCharacter );
if (registerAsDefaultFonts)
{
// 4J Stu - These are so we can use the default flash controls
IggyFontInstallTruetypeUTF8 ( (void *)pbData, IGGY_TTC_INDEX_none, "Times New Roman", -1, IGGY_FONTFLAG_none );
IggyFontInstallTruetypeUTF8 ( (void *)pbData, IGGY_TTC_INDEX_none, "Arial", -1, IGGY_FONTFLAG_none );
}
// 4J Stu - These are so we can use the default flash controls
IggyFontInstallTruetypeUTF8 ( (void *)pbData, IGGY_TTC_INDEX_none, "Times New Roman", -1, IGGY_FONTFLAG_none );
IggyFontInstallTruetypeUTF8 ( (void *)pbData, IGGY_TTC_INDEX_none, "Arial", -1, IGGY_FONTFLAG_none );
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ private:
//DWORD dwDataSize;
public:
UITTFFont(const string &name, const string &path, S32 fallbackCharacter, bool registerAsDefaultFonts = true);
UITTFFont(const string &name, const string &path, S32 fallbackCharacter);
~UITTFFont();
string getFontName();
@@ -1,164 +0,0 @@
#include "stdafx.h"
#include "BufferedImage.h"
#include "UIFontData.h"
#include "UIUnicodeBitmapFont.h"
UIUnicodeBitmapFont::UIUnicodeBitmapFont(const string &fontname, SFontData &referenceFontData)
: UIAbstractBitmapFont(fontname)
{
m_numGlyphs = 65536;
m_referenceFontData = &referenceFontData;
memset(m_glyphPages, 0, sizeof(m_glyphPages));
memset(m_unicodeWidth, 0, sizeof(m_unicodeWidth));
FILE *f = nullptr;
fopen_s(&f, "Common/res/1_2_2/font/glyph_sizes.bin", "rb");
if (f)
{
fread(m_unicodeWidth, 1, 65536, f);
fclose(f);
}
}
UIUnicodeBitmapFont::~UIUnicodeBitmapFont()
{
for (int i = 0; i < 256; i++)
delete[] m_glyphPages[i];
}
void UIUnicodeBitmapFont::loadGlyphPage(int page)
{
wchar_t fileName[64];
swprintf(fileName, 64, L"/1_2_2/font/glyph_%02X.png", page);
BufferedImage bimg(fileName);
int *rawData = bimg.getData();
if (!rawData) return;
int size = 256 * 256;
m_glyphPages[page] = new unsigned char[size];
for (int i = 0; i < size; i++)
m_glyphPages[page][i] = (rawData[i] & 0xFF000000) >> 24;
}
IggyFontMetrics *UIUnicodeBitmapFont::GetFontMetrics(IggyFontMetrics *metrics)
{
metrics->ascent = m_referenceFontData->m_fAscent;
metrics->descent = m_referenceFontData->m_fDescent;
metrics->average_glyph_width_for_tab_stops = 8.0f;
metrics->largest_glyph_bbox_y1 = metrics->descent;
return metrics;
}
S32 UIUnicodeBitmapFont::GetCodepointGlyph(U32 codepoint)
{
if (codepoint < 65536 && m_unicodeWidth[codepoint] != 0)
return (S32)codepoint;
return IGGY_GLYPH_INVALID;
}
IggyGlyphMetrics *UIUnicodeBitmapFont::GetGlyphMetrics(S32 glyph, IggyGlyphMetrics *metrics)
{
if (glyph < 0 || glyph >= 65536) { metrics->x0 = metrics->x1 = metrics->advance = metrics->y0 = metrics->y1 = 0; return metrics; }
int left = m_unicodeWidth[glyph] >> 4;
int right = (m_unicodeWidth[glyph] & 0xF) + 1;
float pixelWidth = (right - left) / 2.0f + 1.0f;
float advance = pixelWidth * m_referenceFontData->m_fAdvPerPixel;
metrics->x0 = 0.0f;
metrics->x1 = advance;
metrics->advance = advance;
metrics->y0 = 0.0f;
metrics->y1 = 1.0f;
return metrics;
}
rrbool UIUnicodeBitmapFont::IsGlyphEmpty(S32 glyph)
{
if (glyph < 0 || glyph >= 65536) return true;
return m_unicodeWidth[glyph] == 0;
}
F32 UIUnicodeBitmapFont::GetKerningForGlyphPair(S32 first_glyph, S32 second_glyph)
{
return 0.0f;
}
rrbool UIUnicodeBitmapFont::CanProvideBitmap(S32 glyph, F32 pixel_scale)
{
return glyph >= 0 && glyph < 65536;
}
rrbool UIUnicodeBitmapFont::GetGlyphBitmap(S32 glyph, F32 pixel_scale, IggyBitmapCharacter *bitmap)
{
if (glyph < 0 || glyph >= 65536) return false;
int page = glyph / 256;
if (!m_glyphPages[page])
{
loadGlyphPage(page);
if (!m_glyphPages[page]) return false;
}
int cx = (glyph % 16) * 16;
int cy = ((glyph & 0xFF) / 16) * 16;
bitmap->pixels_one_per_byte = m_glyphPages[page] + (cy * 256) + cx;
bitmap->width_in_pixels = 16;
bitmap->height_in_pixels = 16;
bitmap->stride_in_bytes = 256;
bitmap->top_left_x = 0;
bitmap->top_left_y = -static_cast<S32>(16) * m_referenceFontData->m_fAscent;
bitmap->oversample = 0;
// Scale parameters: match UIBitmapFont's approach.
// truePixelScale = the pixel_scale at which 1 glyph pixel = 1 screen pixel.
// For 16px glyphs displayed at the same visual size as Mojangles_7 (8px glyphs with advPerPixel 1/10):
// The reference truePixelScale for Mojangles_7 is 1.0f/m_fAdvPerPixel = 10.0f
// Since our glyphs are 16px (2x the Mojangles 8px), our truePixelScale is 20.0f
float truePixelScale = 2.0f / m_referenceFontData->m_fAdvPerPixel;
#ifdef _WINDOWS64
bitmap->pixel_scale_correct = truePixelScale;
if (pixel_scale < truePixelScale)
{
bitmap->pixel_scale_min = 0.0f;
bitmap->pixel_scale_max = truePixelScale;
bitmap->point_sample = false;
}
else
{
bitmap->pixel_scale_min = truePixelScale;
bitmap->pixel_scale_max = 99.0f;
bitmap->point_sample = true;
}
#else
float glyphScale = 1.0f;
while ((0.5f + glyphScale) * truePixelScale < pixel_scale)
glyphScale++;
if (glyphScale <= 1 && pixel_scale < truePixelScale)
{
bitmap->pixel_scale_correct = truePixelScale;
bitmap->pixel_scale_min = 0.0f;
bitmap->pixel_scale_max = truePixelScale * 1.001f;
bitmap->point_sample = false;
}
else
{
float actualScale = pixel_scale / glyphScale;
bitmap->pixel_scale_correct = actualScale;
bitmap->pixel_scale_min = truePixelScale;
bitmap->pixel_scale_max = 99.0f;
bitmap->point_sample = true;
}
#endif
bitmap->user_context_for_free = nullptr;
return true;
}
void UIUnicodeBitmapFont::FreeGlyphBitmap(S32 glyph, F32 pixel_scale, IggyBitmapCharacter *bitmap)
{
// Pixel data lives in m_glyphPages -- nothing to free.
}
@@ -1,27 +0,0 @@
#pragma once
#include "UIBitmapFont.h"
struct SFontData;
class UIUnicodeBitmapFont : public UIAbstractBitmapFont
{
private:
unsigned char m_unicodeWidth[65536];
unsigned char* m_glyphPages[256];
SFontData* m_referenceFontData;
void loadGlyphPage(int page);
public:
UIUnicodeBitmapFont(const string &fontname, SFontData &referenceFontData);
~UIUnicodeBitmapFont();
virtual IggyFontMetrics *GetFontMetrics(IggyFontMetrics *metrics);
virtual S32 GetCodepointGlyph(U32 codepoint);
virtual IggyGlyphMetrics *GetGlyphMetrics(S32 glyph, IggyGlyphMetrics *metrics);
virtual rrbool IsGlyphEmpty(S32 glyph);
virtual F32 GetKerningForGlyphPair(S32 first_glyph, S32 second_glyph);
virtual rrbool CanProvideBitmap(S32 glyph, F32 pixel_scale);
virtual rrbool GetGlyphBitmap(S32 glyph, F32 pixel_scale, IggyBitmapCharacter *bitmap);
virtual void FreeGlyphBitmap(S32 glyph, F32 pixel_scale, IggyBitmapCharacter *bitmap);
};
+1 -3
View File
@@ -2,7 +2,6 @@
#include "XUI_Chat.h"
#include "..\..\Minecraft.h"
#include "..\..\Gui.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
HRESULT CScene_Chat::OnInit( XUIMessageInit* pInitData, BOOL& bHandled )
{
@@ -30,8 +29,7 @@ HRESULT CScene_Chat::OnTimer( XUIMessageTimer *pXUIMessageTimer, BOOL &bHandled)
{
m_Backgrounds[i].SetOpacity(opacity);
m_Labels[i].SetOpacity(opacity);
wstring shaped = shapeArabicText(pGui->getMessage(m_iPad, i));
m_Labels[i].SetText( shaped.c_str() );
m_Labels[i].SetText( pGui->getMessage(m_iPad,i).c_str() );
}
else
{
@@ -1,6 +1,5 @@
#include "stdafx.h"
#include "XUI_Ctrl_4JList.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
static bool TimeSortFn(const void *a, const void *b);
@@ -295,16 +294,8 @@ HRESULT CXuiCtrl4JList::OnGetSourceDataText(XUIMessageGetSourceText *pGetSourceT
if( ( 0 == pGetSourceTextData->iData ) && ( ( pGetSourceTextData->bItemData ) ) )
{
EnterCriticalSection(&m_AccessListData);
LPCWSTR rawText = GetData(pGetSourceTextData->iItem).pwszText;
if (rawText)
{
m_shapedTextCache = shapeArabicText(rawText);
pGetSourceTextData->szText = m_shapedTextCache.c_str();
}
else
{
pGetSourceTextData->szText = rawText;
}
pGetSourceTextData->szText =
GetData(pGetSourceTextData->iItem).pwszText;
LeaveCriticalSection(&m_AccessListData);
bHandled = TRUE;
}
@@ -75,5 +75,4 @@ private:
static bool IndexSortFn(const void *a, const void *b);
HXUIOBJ m_hSelectionChangedHandlerObj;
std::wstring m_shapedTextCache; // temp buffer for Arabic-shaped text in OnGetSourceDataText
};
+11 -32
View File
@@ -186,8 +186,7 @@ HRESULT CXuiSceneHud::OnCustomMessage_TickScene()
if (pMinecraft->localplayers[m_iPad]->invulnerableTime < 10) blink = false;
int iHealth = pMinecraft->localplayers[m_iPad]->getHealth();
int iLastHealth = pMinecraft->localplayers[m_iPad]->lastHealth;
bool bHasPoison = pMinecraft->localplayers[m_iPad]->hasEffect(MobEffect::poison);
bool isHardcore = pMinecraft->level != nullptr && pMinecraft->level->getLevelData()->isHardcore();
bool bHasPoison = pMinecraft->localplayers[m_iPad]->hasEffect(MobEffect::poison);
for (int icon = 0; icon < Player::MAX_HEALTH / 2; icon++)
{
if(blink)
@@ -197,15 +196,11 @@ HRESULT CXuiSceneHud::OnCustomMessage_TickScene()
// Full
if(bHasPoison)
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"FullPoisonFlashHardcore" : L"FullPoisonFlash", nullptr,
isHardcore ? L"FullPoisonFlashHardcore" : L"FullPoisonFlash");
m_healthIcon[icon].PlayVisualRange(L"FullPoisonFlash",nullptr,L"FullPoisonFlash");
}
else
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"FullFlashHardcore" : L"FullFlash", nullptr,
isHardcore ? L"FullFlashHardcore" : L"FullFlash");
m_healthIcon[icon].PlayVisualRange(L"FullFlash",nullptr,L"FullFlash");
}
}
else if (icon * 2 + 1 == iLastHealth || icon * 2 + 1 == iHealth)
@@ -213,23 +208,17 @@ HRESULT CXuiSceneHud::OnCustomMessage_TickScene()
// Half
if(bHasPoison)
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"HalfPoisonFlashHardcore" : L"HalfPoisonFlash", nullptr,
isHardcore ? L"HalfPoisonFlashHardcore" : L"HalfPoisonFlash");
m_healthIcon[icon].PlayVisualRange(L"HalfPoisonFlash",nullptr,L"HalfPoisonFlash");
}
else
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"HalfFlashHardcore" : L"HalfFlash", nullptr,
isHardcore ? L"HalfFlashHardcore" : L"HalfFlash");
m_healthIcon[icon].PlayVisualRange(L"HalfFlash",nullptr,L"HalfFlash");
}
}
else
{
// Empty
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"NormalFlashHardcore" : L"NormalFlash", nullptr,
isHardcore ? L"NormalFlashHardcore" : L"NormalFlash");
m_healthIcon[icon].PlayVisualRange(L"NormalFlash",nullptr,L"NormalFlash");
}
}
else
@@ -239,15 +228,11 @@ HRESULT CXuiSceneHud::OnCustomMessage_TickScene()
// Full
if(bHasPoison)
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"FullPoisonHardcore" : L"FullPoison", nullptr,
isHardcore ? L"FullPoisonHardcore" : L"FullPoison");
m_healthIcon[icon].PlayVisualRange(L"FullPoison",nullptr,L"FullPoison");
}
else
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"FullHardcore" : L"Full", nullptr,
isHardcore ? L"FullHardcore" : L"Full");
m_healthIcon[icon].PlayVisualRange(L"Full",nullptr,L"Full");
}
}
else if (icon * 2 + 1 == iHealth)
@@ -255,23 +240,17 @@ HRESULT CXuiSceneHud::OnCustomMessage_TickScene()
// Half
if(bHasPoison)
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"HalfPoisonHardcore" : L"HalfPoison", nullptr,
isHardcore ? L"HalfPoisonHardcore" : L"HalfPoison");
m_healthIcon[icon].PlayVisualRange(L"HalfPoison",nullptr,L"HalfPoison");
}
else
{
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"HalfHardcore" : L"Half", nullptr,
isHardcore ? L"HalfHardcore" : L"Half");
m_healthIcon[icon].PlayVisualRange(L"Half",nullptr,L"Half");
}
}
else
{
// Empty
m_healthIcon[icon].PlayVisualRange(
isHardcore ? L"NormalHardcore" : L"Normal", nullptr,
isHardcore ? L"NormalHardcore" : L"Normal");
m_healthIcon[icon].PlayVisualRange(L"Normal",nullptr,L"Normal");
}
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
+31 -156
View File
@@ -8,7 +8,6 @@
#include "..\Minecraft.World\net.minecraft.h"
#include "..\Minecraft.World\StringHelpers.h"
#include "..\Minecraft.World\Random.h"
#include "..\Minecraft.World\ArabicShaping.h"
Font::Font(Options *options, const wstring& name, Textures* textures, bool enforceUnicode, ResourceLocation *textureLocation, int cols, int rows, int charWidth, int charHeight, unsigned short charMap[]/* = nullptr */) : textures(textures)
{
@@ -17,7 +16,7 @@ Font::Font(Options *options, const wstring& name, Textures* textures, bool enfor
charWidths = new int[charC];
// 4J - added initialisers
memset(charWidths, 0, charC * sizeof(int));
memset(charWidths, 0, charC);
enforceUnicodeSheet = false;
bidirectional = false;
@@ -27,19 +26,6 @@ Font::Font(Options *options, const wstring& name, Textures* textures, bool enfor
m_underline = false;
m_strikethrough = false;
memset(unicodeTexID, 0, sizeof(unicodeTexID));
memset(unicodeWidth, 0, sizeof(unicodeWidth));
lastBoundTexture = 0;
// Load unicode glyph sizes
FILE *glyphFile = nullptr;
fopen_s(&glyphFile, "Common/res/1_2_2/font/glyph_sizes.bin", "rb");
if (glyphFile)
{
fread(unicodeWidth, 1, 65536, glyphFile);
fclose(glyphFile);
}
// Set up member variables
m_cols = cols;
m_rows = rows;
@@ -275,87 +261,7 @@ void Font::drawLiteral(const wstring& str, int x, int y, int color)
yPos = static_cast<float>(y);
wstring cleanStr = sanitize(str);
for (size_t i = 0; i < cleanStr.length(); ++i)
{
wchar_t c = cleanStr.at(i);
if (isUnicodeGlyphChar(c))
{
renderUnicodeCharacter(c);
textures->bindTexture(m_textureLocation);
lastBoundTexture = fontTexture;
}
else
{
renderCharacter(c);
}
}
}
// Like sanitize() but skips the shapeArabicText() call - for pre-shaped strings.
wstring Font::sanitizePreshaped(const wstring& str)
{
wstring sb = str;
for (unsigned int i = 0; i < sb.length(); i++)
{
if (CharacterExists(sb[i]))
sb[i] = MapCharacter(sb[i]);
else if (unicodeWidth[sb[i]] != 0)
{
// Leave as-is: raw codepoint for glyph page rendering
}
else
{
sb[i] = 0;
}
}
return sb;
}
void Font::drawLiteralPreshaped(const wstring& str, int x, int y, int color)
{
if (str.empty()) return;
if ((color & 0xFC000000) == 0) color |= 0xFF000000;
textures->bindTexture(m_textureLocation);
glColor4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (color >> 24 & 255) / 255.0F);
xPos = static_cast<float>(x);
yPos = static_cast<float>(y);
wstring cleanStr = sanitizePreshaped(str);
for (size_t i = 0; i < cleanStr.length(); ++i)
{
wchar_t c = cleanStr.at(i);
if (isUnicodeGlyphChar(c))
{
renderUnicodeCharacter(c);
textures->bindTexture(m_textureLocation);
lastBoundTexture = fontTexture;
}
else
{
renderCharacter(c);
}
}
}
void Font::drawShadowLiteralPreshaped(const wstring& str, int x, int y, int color)
{
int shadowColor = (color & 0xFCFCFC) >> 2 | (color & 0xFF000000);
drawLiteralPreshaped(str, x + 1, y + 1, shadowColor);
drawLiteralPreshaped(str, x, y, color);
}
int Font::widthPreshaped(const wstring& str)
{
wstring cleanStr = sanitizePreshaped(str);
if (cleanStr.empty()) return 0;
int len = 0;
for (size_t i = 0; i < cleanStr.length(); ++i)
{
wchar_t wc = cleanStr.at(i);
if (isUnicodeGlyphChar(wc))
len += (int)unicodeCharWidth(wc);
else
len += charWidths[static_cast<unsigned>(wc)];
}
return len;
renderCharacter(cleanStr.at(i));
}
void Font::drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h)
@@ -439,7 +345,7 @@ void Font::draw(const wstring &str, bool dropShadow)
}
// "noise" for crazy splash screen message
if (noise && !isUnicodeGlyphChar(c))
if (noise)
{
int newc;
do
@@ -449,18 +355,7 @@ void Font::draw(const wstring &str, bool dropShadow)
c = newc;
}
if (isUnicodeGlyphChar(c))
{
t->end();
renderUnicodeCharacter(c);
textures->bindTexture(m_textureLocation);
lastBoundTexture = fontTexture;
t->begin();
}
else
{
addCharacterQuad(c);
}
addCharacterQuad(c);
}
t->end();
@@ -501,22 +396,11 @@ int Font::width(const wstring& str)
++i;
else
{
if (isUnicodeGlyphChar(167))
len += (int)unicodeCharWidth(167);
else
len += charWidths[167];
len += charWidths[167];
if (i + 1 < cleanStr.length())
{
wchar_t nextC = cleanStr[++i];
if (isUnicodeGlyphChar(nextC))
len += (int)unicodeCharWidth(nextC);
else if (static_cast<unsigned>(nextC) < static_cast<unsigned>(m_cols * m_rows))
len += charWidths[static_cast<unsigned>(nextC)];
}
len += charWidths[static_cast<unsigned>(cleanStr[++i])];
}
}
else if (isUnicodeGlyphChar(c))
len += (int)unicodeCharWidth(c);
else
len += charWidths[c];
}
@@ -530,19 +414,13 @@ int Font::widthLiteral(const wstring& str)
if (cleanStr == L"") return 0;
int len = 0;
for (size_t i = 0; i < cleanStr.length(); ++i)
{
wchar_t wc = cleanStr.at(i);
if (isUnicodeGlyphChar(wc))
len += (int)unicodeCharWidth(wc);
else
len += charWidths[static_cast<unsigned>(wc)];
}
len += charWidths[static_cast<unsigned>(cleanStr.at(i))];
return len;
}
wstring Font::sanitize(const wstring& str)
{
wstring sb = shapeArabicText(str);
wstring sb = str;
for (unsigned int i = 0; i < sb.length(); i++)
{
@@ -550,10 +428,6 @@ wstring Font::sanitize(const wstring& str)
{
sb[i] = MapCharacter(sb[i]);
}
else if (unicodeWidth[sb[i]] != 0)
{
// Leave as-is: raw codepoint for glyph page rendering
}
else
{
// If this character isn't supported, just show the first character (empty square box character)
@@ -797,22 +671,33 @@ void Font::renderFakeCB(IntBuffer *ib)
}
}
}
*/
void Font::loadUnicodePage(int page)
{
wchar_t fileName[40];
swprintf(fileName, 40, L"/1_2_2/font/glyph_%02X.png", page);
wchar_t fileName[25];
//String fileName = String.format("/1_2_2/font/glyph_%02X.png", page);
swprintf(fileName,25,L"/1_2_2/font/glyph_%02X.png",page);
BufferedImage *image = new BufferedImage(fileName);
//try
//{
// image = ImageIO.read(Textures.class.getResourceAsStream(fileName.toString()));
//}
//catch (IOException e)
//{
// throw new RuntimeException(e);
//}
unicodeTexID[page] = textures->getTexture(image);
lastBoundTexture = unicodeTexID[page];
delete image;
}
void Font::renderUnicodeCharacter(wchar_t c)
{
if (unicodeWidth[c] == 0)
{
// System.out.println("no-width char " + c);
return;
}
int page = c / 256;
@@ -824,17 +709,19 @@ void Font::renderUnicodeCharacter(wchar_t c)
lastBoundTexture = unicodeTexID[page];
}
// first column with non-trans pixels
int firstLeft = unicodeWidth[c] >> 4;
// last column with non-trans pixels
int firstRight = unicodeWidth[c] & 0xF;
float left = (float)firstLeft;
float right = (float)(firstRight + 1);
float left = firstLeft;
float right = firstRight + 1;
float xOff = (c % 16) * 16 + left;
float yOff = ((c & 0xFF) / 16) * 16;
float xOff = c % 16 * 16 + left;
float yOff = (c & 0xFF) / 16 * 16;
float width = right - left - .02f;
Tesselator *t = Tesselator::getInstance();
Tesselator *t = Tesselator::getInstance();
t->begin(GL_TRIANGLE_STRIP);
t->tex(xOff / 256.0F, yOff / 256.0F);
t->vertex(xPos, yPos, 0.0f);
@@ -848,17 +735,5 @@ void Font::renderUnicodeCharacter(wchar_t c)
xPos += (right - left) / 2 + 1;
}
float Font::unicodeCharWidth(wchar_t c)
{
if (unicodeWidth[c] == 0) return 0;
int firstLeft = unicodeWidth[c] >> 4;
int firstRight = unicodeWidth[c] & 0xF;
return (firstRight + 1 - firstLeft) / 2.0f + 1;
}
bool Font::isUnicodeGlyphChar(wchar_t c)
{
return c >= m_cols * m_rows && unicodeWidth[c] != 0;
}
*/
-12
View File
@@ -18,10 +18,6 @@ private:
Textures *textures;
int unicodeTexID[256];
unsigned char unicodeWidth[65536];
int lastBoundTexture;
float xPos;
float yPos;
@@ -74,18 +70,10 @@ private:
void drawLiteral(const wstring& str, int x, int y, int color); // no § parsing
int MapCharacter(wchar_t c); // 4J added
bool CharacterExists(wchar_t c); // 4J added
void loadUnicodePage(int page);
void renderUnicodeCharacter(wchar_t c);
float unicodeCharWidth(wchar_t c);
bool isUnicodeGlyphChar(wchar_t c);
wstring sanitizePreshaped(const wstring& str); // sanitize without re-shaping Arabic
void drawLiteralPreshaped(const wstring& str, int x, int y, int color);
public:
int width(const wstring& str);
int widthLiteral(const wstring& str); // width without skipping § codes (for chat input)
int widthPreshaped(const wstring& str); // width of already-shaped text, no re-shaping
void drawShadowLiteralPreshaped(const wstring& str, int x, int y, int color);
wstring sanitize(const wstring& str);
void drawWordWrap(const wstring &string, int x, int y, int w, int col, int h); // 4J Added h param
+2 -7
View File
@@ -359,17 +359,14 @@ void GameRenderer::pick(float a)
}
}
// Toru - wrapping these methods for backwards compatibility,
// no longer setting m_fov as its use doesn't respect applyEffects param in GameRenderer::getFov
void GameRenderer::SetFovVal(float fov)
{
//m_fov=fov;
mc->options->set(Options::Option::FOV, (fov - 70) / 40);
m_fov=fov;
}
float GameRenderer::GetFovVal()
{
return 70 + mc->options->fov * 40;//m_fov;
return m_fov;
}
void GameRenderer::tickFov()
@@ -393,8 +390,6 @@ float GameRenderer::getFov(float a, bool applyEffects)
shared_ptr<LocalPlayer> player = dynamic_pointer_cast<LocalPlayer>(mc->cameraTargetPlayer);
int playerIdx = player ? player->GetXboxPad() : 0;
float fov = m_fov;//70;
if (fov < 1) fov = 1; // Crash fix
if (applyEffects)
{
fov += mc->options->fov * 40;
+211 -10
View File
@@ -499,10 +499,11 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
int y0 = 0;
//if (minecraft->level->getLevelData()->isHardcore())
//{
// y0 = 5;
//}
// No hardcore on console
/*if (minecraft->level.getLevelData().isHardcore())
{
y0 = 5;
}*/
blit(xo, yo, 16 + bg * 9, 9 * y0, 9, 9);
if (blink)
@@ -853,11 +854,214 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
// font.draw(str, x + 1, y, 0xffffff);
// }
#ifndef _FINAL_BUILD
MemSect(31);
// temporarily render overlay at all times so version is more obvious in bug reports
// we can turn this off once things stabilize
if (true)// minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
{
const int debugLeft = 1;
const int debugTop = 1;
const float maxContentWidth = 1200.f;
const float maxContentHeight = 420.f;
float scale = static_cast<float>(screenWidth - debugLeft - 8) / maxContentWidth;
float scaleV = static_cast<float>(screenHeight - debugTop - 80) / maxContentHeight;
if (scaleV < scale) scale = scaleV;
if (scale > 1.f) scale = 1.f;
if (scale < 0.5f) scale = 0.5f;
glPushMatrix();
glTranslatef(static_cast<float>(debugLeft), static_cast<float>(debugTop), 0.f);
glScalef(scale, scale, 1.f);
glTranslatef(static_cast<float>(-debugLeft), static_cast<float>(-debugTop), 0.f);
vector<wstring> lines;
// Only add version/branch lines if the watermark toggle is enabled
if (ClientConstants::SHOW_VERSION_WATERMARK) {
lines.push_back(ClientConstants::VERSION_STRING);
lines.push_back(ClientConstants::BRANCH_STRING);
}
if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
{
lines.push_back(minecraft->fpsString);
lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size())); // Could maybe use entity::shouldRender to work out how many are rendered but thats like expensive
// TODO Add server information with packet counts - once multiplayer is more stable
int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance);
// Calculate the chunk sections using 16 * (2n + 1)^2
lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance));
lines.push_back(minecraft->gatherStats4()); // Chunk Cache
// Dimension
wstring dimension = L"unknown";
switch (minecraft->player->dimension)
{
case -1:
dimension = L"minecraft:the_nether";
break;
case 0:
dimension = L"minecraft:overworld";
break;
case 1:
dimension = L"minecraft:the_end";
break;
}
lines.push_back(dimension);
lines.push_back(L""); // Spacer
// Players block pos
int xBlockPos = Mth::floor(minecraft->player->x);
int yBlockPos = Mth::floor(minecraft->player->y);
int zBlockPos = Mth::floor(minecraft->player->z);
// Chunk player is in
int xChunkPos = xBlockPos >> 4;
int yChunkPos = yBlockPos >> 4;
int zChunkPos = zBlockPos >> 4;
// Players offset within the chunk
int xChunkOffset = xBlockPos & 15;
int yChunkOffset = yBlockPos & 15;
int zChunkOffset = zBlockPos & 15;
// Format the position like java with limited decumal places
WCHAR posString[44]; // Allows upto 7 digit positions (+-9_999_999)
swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z);
lines.push_back(L"XYZ: " + std::wstring(posString));
lines.push_back(L"Block: " + std::to_wstring(static_cast<int>(xBlockPos)) + L" " + std::to_wstring(static_cast<int>(yBlockPos)) + L" " + std::to_wstring(static_cast<int>(zBlockPos)));
lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos));
// Wrap the yRot to 360 then adjust to (-180 to 180) range to match java
float yRotDisplay = fmod(minecraft->player->yRot, 360.0f);
if (yRotDisplay > 180.0f)
{
yRotDisplay -= 360.0f;
}
if (yRotDisplay < -180.0f)
{
yRotDisplay += 360.0f;
}
// Generate the angle string in the format "yRot / xRot" with one decimal place, similar to java edition
WCHAR angleString[16];
swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot);
// Work out the named direction
int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3;
wstring cardinalDirection;
switch (direction)
{
case 0:
cardinalDirection = L"south";
break;
case 1:
cardinalDirection = L"west";
break;
case 2:
cardinalDirection = L"north";
break;
case 3:
cardinalDirection = L"east";
break;
}
lines.push_back(L"Facing: " + cardinalDirection + L" (" + angleString + L")");
// We have to limit y to 256 as we don't get any information past that
if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos))
{
LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos);
if (chunkAt != NULL)
{
int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset);
int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset);
int maxLight = fmax(skyLight, blockLight);
lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)");
lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset)));
Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource());
lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")");
lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")");
}
}
// This is all LCE only stuff, it was never on java
lines.push_back(L""); // Spacer
lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed()));
lines.push_back(minecraft->gatherStats1()); // Time to autosave
lines.push_back(minecraft->gatherStats2()); // Empty currently - CPlatformNetworkManagerStub::GatherStats()
lines.push_back(minecraft->gatherStats3()); // RTT
}
#ifdef _DEBUG // Only show terrain features in debug builds not release
// TERRAIN FEATURES
if (minecraft->level->dimension->id == 0)
{
wstring wfeature[eTerrainFeature_Count];
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: ";
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: ";
wfeature[eTerrainFeature_Village] = L"Village: ";
wfeature[eTerrainFeature_Ravine] = L"Ravine: ";
float maxW = static_cast<float>(screenWidth - debugLeft - 8) / scale;
float maxWForContent = maxW - static_cast<float>(font->width(L"..."));
bool truncated[eTerrainFeature_Count] = {};
for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++)
{
FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i];
int type = pFeatureData->eTerrainFeature;
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine)
{
continue;
}
if (truncated[type])
{
continue;
}
wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] ";
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
{
wfeature[type] += itemInfo;
}
else
{
wfeature[type] += L"...";
truncated[type] = true;
}
}
lines.push_back(L""); // Add a spacer line
for (int i = eTerrainFeature_Stronghold; i <= static_cast<int>(eTerrainFeature_Ravine); i++)
{
lines.push_back(wfeature[i]);
}
lines.push_back(L"");
}
#endif
// Loop through the lines and draw them all on screen
int yPos = debugTop;
for (const auto &line : lines)
{
drawString(font, line, debugLeft, yPos, 0xffffff);
yPos += 10;
}
glPopMatrix();
}
MemSect(0);
#endif
lastTickA = a;
// 4J Stu - This is now displayed in a xui scene
#if 0
// Jukebox CD message
// Jukebox CD message
if (overlayMessageTime > 0)
{
float t = overlayMessageTime - a;
@@ -1065,7 +1269,7 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
vector<wstring> lines;
// Only show version/branch for player 0 to avoid cluttering each splitscreen viewport
if (iPad == 0 && ClientConstants::SHOW_VERSION_WATERMARK)
if (iPad == 0)
{
lines.push_back(ClientConstants::VERSION_STRING);
lines.push_back(ClientConstants::BRANCH_STRING);
@@ -1386,9 +1590,6 @@ void Gui::clearMessages(int iPad)
void Gui::addMessage(const wstring& _string,int iPad,bool bIsDeathMessage)
{
{ char buf[32]; sprintf_s(buf, "[CHAT] Display (pad=%d): ", iPad); OutputDebugStringA(buf); }
OutputDebugStringW(_string.c_str());
OutputDebugStringA("\n");
wstring string = _string; // 4J - Take copy of input as it is const
//int iScale=1;
@@ -1610,7 +1811,7 @@ void Gui::renderGraph(int dataLength, int dataPos, int64_t *dataA, float dataASc
t->vertex((float)(xScale*i + 0.5f), (float)( height - aVal + 0.5f), static_cast<float>(0));
t->vertex((float)(xScale*i + 0.5f), (float)( height + 0.5f), static_cast<float>(0));
}
}
if( dataB != NULL )
{
-5
View File
@@ -110,11 +110,6 @@ void GuiComponent::drawStringLiteral(Font *font, const wstring& str, int x, int
font->drawShadowLiteral(str, x, y, color);
}
void GuiComponent::drawStringPreshaped(Font *font, const wstring& str, int x, int y, int color)
{
font->drawShadowLiteralPreshaped(str, x, y, color);
}
void GuiComponent::blit(int x, int y, int sx, int sy, int w, int h)
{
float us = 1 / 256.0f;
-1
View File
@@ -16,6 +16,5 @@ public:
void drawCenteredString(Font *font, const wstring& str, int x, int y, int color);
void drawString(Font *font, const wstring& str, int x, int y, int color);
void drawStringLiteral(Font* font, const wstring& str, int x, int y, int color);
void drawStringPreshaped(Font* font, const wstring& str, int x, int y, int color);
void blit(int x, int y, int sx, int sy, int w, int h);
};
-32
View File
@@ -6894,22 +6894,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PSVita'">false</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="Common\UI\UIUnicodeBitmapFont.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PSVita'">false</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="Common\UI\UIComponent_Chat.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Xbox 360'">true</ExcludedFromBuild>
@@ -29639,22 +29623,6 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PSVita'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Common\UI\UIUnicodeBitmapFont.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PSVita'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Common\UI\UIComponent_Chat.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Xbox 360'">true</ExcludedFromBuild>
@@ -2953,9 +2953,6 @@
<ClInclude Include="Common\UI\UIBitmapFont.h">
<Filter>Common\Source Files\UI</Filter>
</ClInclude>
<ClInclude Include="Common\UI\UIUnicodeBitmapFont.h">
<Filter>Common\Source Files\UI</Filter>
</ClInclude>
<ClInclude Include="Common\UI\UITTFFont.h">
<Filter>Common\Source Files\UI</Filter>
</ClInclude>
@@ -5202,9 +5199,6 @@
<ClCompile Include="Common\UI\UIBitmapFont.cpp">
<Filter>Common\Source Files\UI</Filter>
</ClCompile>
<ClCompile Include="Common\UI\UIUnicodeBitmapFont.cpp">
<Filter>Common\Source Files\UI</Filter>
</ClCompile>
<ClCompile Include="Common\UI\UITTFFont.cpp">
<Filter>Common\Source Files\UI</Filter>
</ClCompile>
@@ -0,0 +1,11 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "1"
"EXCLUDED_FILE0" = "Durango\\Autogenerated.appxmanifest"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
-82
View File
@@ -73,11 +73,6 @@
#include "Common\UI\UIFontData.h"
#include "DLCTexturePack.h"
#ifdef _WINDOWS64
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "Windows64/stb_image_write.h"
#endif
#ifdef __ORBIS__
#include "Orbis\Network\PsPlusUpsellWrapper_Orbis.h"
#endif
@@ -1554,9 +1549,6 @@ void Minecraft::run_middle()
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_DEBUG;
}
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_SCREENSHOT))
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_SCREENSHOT;
// In flying mode, Shift held = sneak/descend
if(g_KBMInput.IsKBMActive() && g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SNEAK))
{
@@ -3745,80 +3737,6 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
//options->thirdPersonView = !options->thirdPersonView;
}
#ifdef _WINDOWS64
if(player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_SCREENSHOT))
{
extern ID3D11Device* g_pd3dDevice;
extern ID3D11DeviceContext* g_pImmediateContext;
extern IDXGISwapChain* g_pSwapChain;
ID3D11Texture2D* pBackBuffer = nullptr;
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
if (SUCCEEDED(hr))
{
D3D11_TEXTURE2D_DESC desc;
pBackBuffer->GetDesc(&desc);
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
ID3D11Texture2D* pStaging = nullptr;
hr = g_pd3dDevice->CreateTexture2D(&desc, nullptr, &pStaging);
if (SUCCEEDED(hr))
{
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
// Build path next to the executable
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wchar_t* lastSlash = wcsrchr(exePath, L'\\');
if (lastSlash) *(lastSlash + 1) = L'\0';
wstring screenshotDirPath = wstring(exePath) + L"screenshots";
CreateDirectoryW(screenshotDirPath.c_str(), NULL);
SYSTEMTIME st;
GetLocalTime(&st);
wchar_t filename[128];
swprintf_s(filename, L"%04d-%02d-%02d_%02d.%02d.%02d.png",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
wstring screenshotPath = screenshotDirPath + L"\\" + filename;
D3D11_MAPPED_SUBRESOURCE mapped;
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
if (SUCCEEDED(hr))
{
// Copy rows and force alpha to fully opaque
unsigned char* rgba = new unsigned char[desc.Width * desc.Height * 4];
for (UINT row = 0; row < desc.Height; row++)
{
unsigned char* src = (unsigned char*)mapped.pData + row * mapped.RowPitch;
unsigned char* dst = rgba + row * desc.Width * 4;
memcpy(dst, src, desc.Width * 4);
for (UINT x = 0; x < desc.Width; x++)
dst[x * 4 + 3] = 0xFF;
}
g_pImmediateContext->Unmap(pStaging, 0);
// Save PNG via stb_image_write
string narrowPath(screenshotPath.begin(), screenshotPath.end());
int writeResult = stbi_write_png(narrowPath.c_str(), desc.Width, desc.Height, 4, rgba, desc.Width * 4);
delete[] rgba;
// Send local-only chat message on success
if (writeResult)
{
wstring msg = L"Saved screenshot to " + wstring(filename);
gui->addMessage(msg, iPad);
}
}
pStaging->Release();
}
pBackBuffer->Release();
}
}
#endif
if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_GAME_INFO)) && gameMode->isInputAllowed(MINECRAFT_ACTION_GAME_INFO))
{
ui.NavigateToScene(iPad,eUIScene_InGameInfoMenu);
+245 -267
View File
@@ -658,7 +658,7 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW
setFlightAllowed(GetDedicatedServerBool(settings, L"allow-flight", true));
// 4J Stu - Enabling flight to stop it kicking us when we use it
#if (defined _DEBUG_MENUS_ENABLED && defined _DEBUG)
#ifdef _DEBUG_MENUS_ENABLED
setFlightAllowed(true);
#endif
@@ -1007,9 +1007,6 @@ bool MinecraftServer::loadLevel(LevelStorageSource *storageSource, const wstring
#endif
levels[i]->getLevelData()->setGameType(gameType);
// Apply hardcore flag from host option to level data so loaded worlds respect server.properties
levels[i]->getLevelData()->setHardcore(isHardcore());
if(app.getLevelGenerationOptions() != nullptr)
{
LevelGenerationOptions *mapOptions = app.getLevelGenerationOptions();
@@ -1728,345 +1725,330 @@ void MinecraftServer::setPlayerIdleTimeout(int playerIdleTimeout)
extern int c0a, c0b, c1a, c1b, c1c, c2a, c2b;
void MinecraftServer::run(int64_t seed, void *lpParameter)
{
NetworkGameInitData *initData = nullptr;
DWORD initSettings = 0;
bool findSeed = false;
NetworkGameInitData *initData = nullptr;
DWORD initSettings = 0;
bool findSeed = false;
if(lpParameter != nullptr)
{
initData = static_cast<NetworkGameInitData *>(lpParameter);
initSettings = app.GetGameHostOption(eGameHostOption_All);
findSeed = initData->findSeed;
m_texturePackId = initData->texturePackId;
}
// try { // 4J - removed try/catch/finally
bool didInit = false;
{
initData = static_cast<NetworkGameInitData *>(lpParameter);
initSettings = app.GetGameHostOption(eGameHostOption_All);
findSeed = initData->findSeed;
m_texturePackId = initData->texturePackId;
}
// try { // 4J - removed try/catch/finally
bool didInit = false;
if (initServer(seed, initData, initSettings,findSeed))
{
didInit = true;
ServerLevel *levelNormalDimension = levels[0];
// 4J-PB - Set the Stronghold position in the leveldata if there isn't one in there
Minecraft *pMinecraft = Minecraft::GetInstance();
{
didInit = true;
ServerLevel *levelNormalDimension = levels[0];
// 4J-PB - Set the Stronghold position in the leveldata if there isn't one in there
Minecraft *pMinecraft = Minecraft::GetInstance();
LevelData *pLevelData=levelNormalDimension->getLevelData();
if(pLevelData && pLevelData->getHasStronghold()==false)
{
{
int x,z;
if(app.GetTerrainFeaturePosition(eTerrainFeature_Stronghold,&x,&z))
{
pLevelData->setXStronghold(x);
pLevelData->setZStronghold(z);
pLevelData->setHasStronghold();
}
}
{
pLevelData->setXStronghold(x);
pLevelData->setZStronghold(z);
pLevelData->setHasStronghold();
}
}
int64_t lastTime = getCurrentTimeMillis();
int64_t unprocessedTime = 0;
while (running && !s_bServerHalted)
{
int64_t now = getCurrentTimeMillis();
int64_t lastTime = getCurrentTimeMillis();
int64_t unprocessedTime = 0;
while (running && !s_bServerHalted)
{
int64_t now = getCurrentTimeMillis();
// 4J Stu - When we pause the server, we don't want to count that as time passed
// 4J Stu - TU-1 hotifx - Remove this line. We want to make sure that we tick connections at the proper rate when paused
// 4J Stu - When we pause the server, we don't want to count that as time passed
// 4J Stu - TU-1 hotifx - Remove this line. We want to make sure that we tick connections at the proper rate when paused
//Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost
//if(m_isServerPaused) lastTime = now;
int64_t passedTime = now - lastTime;
if (passedTime > MS_PER_TICK * 40)
{
// logger.warning("Can't keep up! Did the system time change, or is the server overloaded?");
passedTime = MS_PER_TICK * 40;
}
if (passedTime < 0)
{
// logger.warning("Time ran backwards! Did the system time change?");
passedTime = 0;
}
unprocessedTime += passedTime;
lastTime = now;
int64_t passedTime = now - lastTime;
if (passedTime > MS_PER_TICK * 40)
{
// logger.warning("Can't keep up! Did the system time change, or is the server overloaded?");
passedTime = MS_PER_TICK * 40;
}
if (passedTime < 0)
{
// logger.warning("Time ran backwards! Did the system time change?");
passedTime = 0;
}
unprocessedTime += passedTime;
lastTime = now;
// 4J Added ability to pause the server
// 4J Added ability to pause the server
if( !m_isServerPaused )
{
bool didTick = false;
if (levels[0]->allPlayersAreSleeping())
{
tick();
unprocessedTime = 0;
}
else
{
// int tickcount = 0;
// int64_t beforeall = System::currentTimeMillis();
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
chunkPacketManagement_PreTick();
// int64_t before = System::currentTimeMillis();
tick();
// int64_t after = System::currentTimeMillis();
// PIXReportCounter(L"Server time",(float)(after-before));
{
bool didTick = false;
if (levels[0]->allPlayersAreSleeping())
{
tick();
unprocessedTime = 0;
}
else
{
// int tickcount = 0;
// int64_t beforeall = System::currentTimeMillis();
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
chunkPacketManagement_PreTick();
// int64_t before = System::currentTimeMillis();
tick();
// int64_t after = System::currentTimeMillis();
// PIXReportCounter(L"Server time",(float)(after-before));
chunkPacketManagement_PostTick();
}
// int64_t afterall = System::currentTimeMillis();
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
// PIXReportCounter(L"Server ticks",(float)tickcount);
}
}
else
{
// 4J Stu - TU1-hotfix
chunkPacketManagement_PostTick();
}
// int64_t afterall = System::currentTimeMillis();
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
// PIXReportCounter(L"Server ticks",(float)tickcount);
}
}
else
{
// 4J Stu - TU1-hotfix
//Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost
// The connections should tick at the same frequency even when paused
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
// Keep ticking the connections to stop them timing out
connection->tick();
}
}
// The connections should tick at the same frequency even when paused
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
// Keep ticking the connections to stop them timing out
connection->tick();
}
}
if(MinecraftServer::setTimeAtEndOfTick)
{
MinecraftServer::setTimeAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
// if (i == 0 || settings->getBoolean(L"allow-nether", true)) // 4J removed - we always have nether
{
ServerLevel *level = levels[i];
{
MinecraftServer::setTimeAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
// if (i == 0 || settings->getBoolean(L"allow-nether", true)) // 4J removed - we always have nether
{
ServerLevel *level = levels[i];
level->setGameTime( MinecraftServer::setTime );
}
}
}
}
}
}
if(MinecraftServer::setTimeOfDayAtEndOfTick)
{
MinecraftServer::setTimeOfDayAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
if (i == 0 || GetDedicatedServerBool(settings, L"allow-nether", true))
{
ServerLevel *level = levels[i];
{
MinecraftServer::setTimeOfDayAtEndOfTick = false;
for (unsigned int i = 0; i < levels.length; i++)
{
if (i == 0 || GetDedicatedServerBool(settings, L"allow-nether", true))
{
ServerLevel *level = levels[i];
level->setDayTime( MinecraftServer::setTimeOfDay );
}
}
}
}
}
}
// Process delayed actions
eXuiServerAction eAction;
LPVOID param;
// Process delayed actions
eXuiServerAction eAction;
LPVOID param;
for(int i=0;i<XUSER_MAX_COUNT;i++)
{
eAction = app.GetXuiServerAction(i);
param = app.GetXuiServerActionParam(i);
{
eAction = app.GetXuiServerAction(i);
param = app.GetXuiServerActionParam(i);
switch(eAction)
{
case eXuiServerAction_AutoSaveGame:
#if defined(_XBOX_ONE) || defined(__ORBIS__) || defined(MINECRAFT_SERVER_BUILD)
{
{
case eXuiServerAction_AutoSaveGame:
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXBeginNamedEvent(0, "Autosave");
{
PIXBeginNamedEvent(0,"Autosave");
// Get the frequency of the timer
LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime;
float fElapsedTime = 0.0f;
QueryPerformanceFrequency(&qwTicksPerSec);
float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;
// Get the frequency of the timer
LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime;
float fElapsedTime = 0.0f;
QueryPerformanceFrequency( &qwTicksPerSec );
float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart;
// Save the start time
QueryPerformanceCounter(&qwTime);
#endif
// Save the start time
QueryPerformanceCounter( &qwTime );
if (players != nullptr)
{
players->saveAll(nullptr);
}
if (players != nullptr)
{
players->saveAll(nullptr);
}
for (unsigned int j = 0; j < levels.length; j++)
{
for (unsigned int j = 0; j < levels.length; j++)
{
if( s_bServerHalted ) break;
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXBeginNamedEvent(0, "Saving level %d", levels.length - 1 - j);
#endif
level->save(false, nullptr, true);
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
#endif
}
if (!s_bServerHalted)
{
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXBeginNamedEvent(0, "Saving game rules");
#endif
saveGameRules();
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
PIXBeginNamedEvent(0, "Saving level %d",levels.length - 1 - j);
level->save(false, nullptr, true);
PIXEndNamedEvent();
}
if( !s_bServerHalted )
{
PIXBeginNamedEvent(0,"Saving game rules");
saveGameRules();
PIXEndNamedEvent();
PIXBeginNamedEvent(0, "Save to disc");
#endif
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, true);
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
#endif
}
PIXBeginNamedEvent(0,"Save to disc");
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, true);
PIXEndNamedEvent();
}
PIXEndNamedEvent();
#if defined(_XBOX_ONE) || defined(__ORBIS__)
PIXEndNamedEvent();
QueryPerformanceCounter(&qwNewTime);
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart;
fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
app.DebugPrintf("Autosave: Elapsed time %f\n", fElapsedTime);
QueryPerformanceCounter( &qwNewTime );
qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart;
fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart));
app.DebugPrintf("Autosave: Elapsed time %f\n", fElapsedTime);
}
break;
#endif
}
break;
#endif
case eXuiServerAction_SaveGame:
app.EnterSaveNotificationSection();
if (players != nullptr)
{
players->saveAll(Minecraft::GetInstance()->progressRenderer);
}
case eXuiServerAction_SaveGame:
app.EnterSaveNotificationSection();
if (players != nullptr)
{
players->saveAll(Minecraft::GetInstance()->progressRenderer);
}
players->broadcastAll(std::make_shared<UpdateProgressPacket>(20));
players->broadcastAll(std::make_shared<UpdateProgressPacket>(20));
for (unsigned int j = 0; j < levels.length; j++)
{
for (unsigned int j = 0; j < levels.length; j++)
{
if( s_bServerHalted ) break;
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
// 4J Stu - Save the levels in reverse order so we don't overwrite the level.dat
// with the data from the nethers leveldata.
// Fix for #7418 - Functional: Gameplay: Saving after sleeping in a bed will place player at nighttime when restarting.
ServerLevel *level = levels[levels.length - 1 - j];
level->save(true, Minecraft::GetInstance()->progressRenderer, (eAction==eXuiServerAction_AutoSaveGame));
players->broadcastAll(std::make_shared<UpdateProgressPacket>(33 + (j * 33)));
}
players->broadcastAll(std::make_shared<UpdateProgressPacket>(33 + (j * 33)));
}
if( !s_bServerHalted )
{
saveGameRules();
{
saveGameRules();
levels[0]->saveToDisc(Minecraft::GetInstance()->progressRenderer, (eAction==eXuiServerAction_AutoSaveGame));
}
app.LeaveSaveNotificationSection();
break;
case eXuiServerAction_DropItem:
// Find the player, and drop the id at their feet
{
shared_ptr<ServerPlayer> player = players->players.at(0);
}
app.LeaveSaveNotificationSection();
break;
case eXuiServerAction_DropItem:
// Find the player, and drop the id at their feet
{
shared_ptr<ServerPlayer> player = players->players.at(0);
size_t id = (size_t) param;
player->drop(std::make_shared<ItemInstance>(id, 1, 0));
}
break;
case eXuiServerAction_SpawnMob:
{
shared_ptr<ServerPlayer> player = players->players.at(0);
eINSTANCEOF factory = static_cast<eINSTANCEOF>((size_t)param);
player->drop(std::make_shared<ItemInstance>(id, 1, 0));
}
break;
case eXuiServerAction_SpawnMob:
{
shared_ptr<ServerPlayer> player = players->players.at(0);
eINSTANCEOF factory = static_cast<eINSTANCEOF>((size_t)param);
shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(EntityIO::newByEnumType(factory,player->level ));
mob->moveTo(player->x+1, player->y, player->z+1, player->level->random->nextFloat() * 360, 0);
mob->setDespawnProtected(); // 4J added, default to being protected against despawning (has to be done after initial position is set)
player->level->addEntity(mob);
}
break;
case eXuiServerAction_PauseServer:
player->level->addEntity(mob);
}
break;
case eXuiServerAction_PauseServer:
m_isServerPaused = ( (size_t) param == TRUE );
if( m_isServerPaused )
{
m_serverPausedEvent->Set();
}
break;
case eXuiServerAction_ToggleRain:
{
bool isRaining = levels[0]->getLevelData()->isRaining();
levels[0]->getLevelData()->setRaining(!isRaining);
levels[0]->getLevelData()->setRainTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ToggleThunder:
{
bool isThundering = levels[0]->getLevelData()->isThundering();
levels[0]->getLevelData()->setThundering(!isThundering);
levels[0]->getLevelData()->setThunderTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ServerSettingChanged_Gamertags:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_OPTIONS, app.GetGameHostOption(eGameHostOption_Gamertags)));
break;
case eXuiServerAction_ServerSettingChanged_BedrockFog:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS, app.GetGameHostOption(eGameHostOption_All)));
break;
{
m_serverPausedEvent->Set();
}
break;
case eXuiServerAction_ToggleRain:
{
bool isRaining = levels[0]->getLevelData()->isRaining();
levels[0]->getLevelData()->setRaining(!isRaining);
levels[0]->getLevelData()->setRainTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ToggleThunder:
{
bool isThundering = levels[0]->getLevelData()->isThundering();
levels[0]->getLevelData()->setThundering(!isThundering);
levels[0]->getLevelData()->setThunderTime(levels[0]->random->nextInt(Level::TICKS_PER_DAY * 7) + Level::TICKS_PER_DAY / 2);
}
break;
case eXuiServerAction_ServerSettingChanged_Gamertags:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_OPTIONS, app.GetGameHostOption(eGameHostOption_Gamertags)));
break;
case eXuiServerAction_ServerSettingChanged_BedrockFog:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS, app.GetGameHostOption(eGameHostOption_All)));
break;
case eXuiServerAction_ServerSettingChanged_Difficulty:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_DIFFICULTY, Minecraft::GetInstance()->options->difficulty));
break;
case eXuiServerAction_ExportSchematic:
case eXuiServerAction_ServerSettingChanged_Difficulty:
players->broadcastAll(std::make_shared<ServerSettingsChangedPacket>(ServerSettingsChangedPacket::HOST_DIFFICULTY, Minecraft::GetInstance()->options->difficulty));
break;
case eXuiServerAction_ExportSchematic:
#ifndef _CONTENT_PACKAGE
app.EnterSaveNotificationSection();
app.EnterSaveNotificationSection();
//players->broadcastAll( shared_ptr<UpdateProgressPacket>( new UpdateProgressPacket(20) ) );
if( !s_bServerHalted )
{
ConsoleSchematicFile::XboxSchematicInitParam *initData = static_cast<ConsoleSchematicFile::XboxSchematicInitParam *>(param);
{
ConsoleSchematicFile::XboxSchematicInitParam *initData = static_cast<ConsoleSchematicFile::XboxSchematicInitParam *>(param);
#ifdef _XBOX
File targetFileDir(File::pathRoot + File::pathSeparator + L"Schematics");
File targetFileDir(File::pathRoot + File::pathSeparator + L"Schematics");
#else
File targetFileDir(L"Schematics");
File targetFileDir(L"Schematics");
#endif
if(!targetFileDir.exists()) targetFileDir.mkdir();
wchar_t filename[128];
wchar_t filename[128];
swprintf(filename,128,L"%ls%dx%dx%d.sch",initData->name,(initData->endX - initData->startX + 1), (initData->endY - initData->startY + 1), (initData->endZ - initData->startZ + 1));
File dataFile = File( targetFileDir, wstring(filename) );
if(dataFile.exists()) dataFile._delete();
FileOutputStream fos = FileOutputStream(dataFile);
DataOutputStream dos = DataOutputStream(&fos);
ConsoleSchematicFile::generateSchematicFile(&dos, levels[0], initData->startX, initData->startY, initData->startZ, initData->endX, initData->endY, initData->endZ, initData->bSaveMobs, initData->compressionType);
dos.close();
FileOutputStream fos = FileOutputStream(dataFile);
DataOutputStream dos = DataOutputStream(&fos);
ConsoleSchematicFile::generateSchematicFile(&dos, levels[0], initData->startX, initData->startY, initData->startZ, initData->endX, initData->endY, initData->endZ, initData->bSaveMobs, initData->compressionType);
dos.close();
delete initData;
}
app.LeaveSaveNotificationSection();
delete initData;
}
app.LeaveSaveNotificationSection();
#endif
break;
case eXuiServerAction_SetCameraLocation:
break;
case eXuiServerAction_SetCameraLocation:
#ifndef _CONTENT_PACKAGE
{
DebugSetCameraPosition *pos = static_cast<DebugSetCameraPosition *>(param);
{
DebugSetCameraPosition *pos = static_cast<DebugSetCameraPosition *>(param);
app.DebugPrintf( "DEBUG: Player=%i\n", pos->player );
app.DebugPrintf( "DEBUG: Teleporting to pos=(%f.2, %f.2, %f.2), looking at=(%f.2,%f.2)\n",
pos->m_camX, pos->m_camY, pos->m_camZ,
pos->m_camX, pos->m_camY, pos->m_camZ,
pos->m_yRot, pos->m_elev
);
shared_ptr<ServerPlayer> player = players->players.at(pos->player);
shared_ptr<ServerPlayer> player = players->players.at(pos->player);
player->debug_setPosition( pos->m_camX, pos->m_camY, pos->m_camZ,
pos->m_yRot, pos->m_elev );
// Doesn't work
// Doesn't work
//player->setYHeadRot(pos->m_yRot);
//player->absMoveTo(pos->m_camX, pos->m_camY, pos->m_camZ, pos->m_yRot, pos->m_elev);
}
}
#endif
break;
}
break;
}
app.SetXuiServerAction(i,eXuiServerAction_Idle);
}
}
Sleep(1);
}
}
Sleep(1);
}
}
//else
//{
//{
// while (running)
// {
// {
// handleConsoleInputs();
// Sleep(10);
// Sleep(10);
// }
//}
#if 0
@@ -2093,9 +2075,9 @@ void MinecraftServer::run(int64_t seed, void *lpParameter)
}
#endif
// 4J Stu - Stop the server when the loops complete, as the finally would do
stopServer(didInit);
stopped = true;
// 4J Stu - Stop the server when the loops complete, as the finally would do
stopServer(didInit);
stopped = true;
}
void MinecraftServer::broadcastStartSavingPacket()
@@ -2403,9 +2385,6 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
{
if( player == nullptr ) return false;
#ifdef MINECRAFT_SERVER_BUILD
return true;
#else
int time = GetTickCount();
DWORD currentPlayerCount = g_NetworkManager.GetPlayerCount();
if( currentPlayerCount == 0 ) return false;
@@ -2417,7 +2396,6 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
}
return false;
#endif
}
void MinecraftServer::chunkPacketManagement_DidSendTo(INetworkPlayer *player)
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
+16 -15
View File
@@ -25,7 +25,6 @@
#include "..\Minecraft.World\StringHelpers.h"
#include "..\Minecraft.World\Socket.h"
#include "..\Minecraft.World\Achievements.h"
#include "..\Minecraft.World\LevelData.h"
#include "..\Minecraft.World\net.minecraft.h"
#include "EntityTracker.h"
#include "ServerConnection.h"
@@ -143,14 +142,6 @@ void PlayerConnection::tick()
{
dropSpamTickCount--;
}
// Ensure server-side player tick runs even when no move packet was received this tick.
// Without this, environmental damage (drowning, fire, lava) is never applied to clients
// that don't send frequent move packets.
if (!didTick && player != nullptr)
{
player->doTick(false);
}
}
void PlayerConnection::disconnect(DisconnectPacket::eDisconnectReason reason)
@@ -1118,12 +1109,22 @@ void PlayerConnection::handleClientCommand(shared_ptr<ClientCommandPacket> packe
{
player = server->getPlayers()->respawn(player, player->m_enteredEndExitPortal?0:player->dimension, true);
}
else if (player->level->getLevelData()->isHardcore())
{
// Hardcore mode — server rejects respawn. Ban and disconnect are already
// handled in ServerPlayer::die() via banPlayerForHardcoreDeath().
return;
}
//else if (player.getLevel().getLevelData().isHardcore())
//{
// if (server.isSingleplayer() && player.name.equals(server.getSingleplayerName()))
// {
// player.connection.disconnect("You have died. Game over, man, it's game over!");
// server.selfDestruct();
// }
// else
// {
// BanEntry ban = new BanEntry(player.name);
// ban.setReason("Death in Hardcore");
// server.getPlayers().getBans().add(ban);
// player.connection.disconnect("You have died. Game over, man, it's game over!");
// }
//}
else
{
if (player->getHealth() > 0) return;
-77
View File
@@ -39,10 +39,6 @@
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
#include "..\Minecraft.Server\Access\Access.h"
#include "..\Minecraft.Server\Common\StringUtils.h"
#include "..\Minecraft.Server\ServerLogger.h"
#include "..\Minecraft.Server\ServerLogManager.h"
#include "..\Minecraft.Server\ServerProperties.h"
extern bool g_Win64DedicatedServer;
#endif
@@ -1733,79 +1729,6 @@ void PlayerList::banXuid(PlayerUID xuid)
LeaveCriticalSection(&m_banCS);
}
void PlayerList::banPlayerForHardcoreDeath(ServerPlayer *player)
{
if (player == nullptr) return;
// Always apply the in-memory XUID ban (works for both client-hosted and dedicated)
banXuid(player->getOnlineXuid());
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
if (g_Win64DedicatedServer)
{
const std::string playerName = ServerRuntime::StringUtils::WideToUtf8(player->getName());
ServerRuntime::Access::BanMetadata metadata = ServerRuntime::Access::BanManager::BuildDefaultMetadata("Hardcore Death");
metadata.reason = "Died in hardcore mode";
// Ban online XUID
ServerRuntime::Access::AddPlayerBan(player->getOnlineXuid(), playerName, metadata);
// Also ban offline XUID if it differs (follows CliCommandBan pattern)
PlayerUID offlineXuid = player->getXuid();
if (offlineXuid != INVALID_XUID && offlineXuid != player->getOnlineXuid())
{
ServerRuntime::Access::AddPlayerBan(offlineXuid, playerName, metadata);
}
// Ban the player's IP address (uses same access path as CliCommandBanIp)
auto serverConfig = ServerRuntime::LoadServerPropertiesConfig();
if (serverConfig.hardcoreBanIp)
{
if (player->connection != nullptr && player->connection->connection != nullptr && player->connection->connection->getSocket() != nullptr)
{
const unsigned char smallId = player->connection->connection->getSocket()->getSmallId();
std::string ip;
if (smallId != 0 && ServerRuntime::ServerLogManager::TryGetConnectionRemoteIp(smallId, &ip))
{
ServerRuntime::Access::AddIpBan(ip, metadata);
ServerRuntime::LogInfof("Hardcore", "Player %s banned (XUID + IP %s) for dying in hardcore mode.", playerName.c_str(), ip.c_str());
}
else
{
ServerRuntime::LogInfof("Hardcore", "Player %s banned (XUID only, IP not available) for dying in hardcore mode.", playerName.c_str());
}
}
else
{
ServerRuntime::LogInfof("Hardcore", "Player %s banned (XUID only, no connection) for dying in hardcore mode.", playerName.c_str());
}
}
else
{
ServerRuntime::LogInfof("Hardcore", "Player %s banned (XUID only, IP ban disabled) for dying in hardcore mode.", playerName.c_str());
}
// Send ban reason then defer the actual close to the next tick, because this
// method runs mid-tick inside ServerPlayer::die(). A synchronous disconnect
// can invalidate the player/connection while the tick is still executing.
if (player->connection != nullptr)
{
player->connection->send(std::make_shared<DisconnectPacket>(DisconnectPacket::eDisconnect_Banned));
player->connection->closeOnTick();
}
}
else
#endif
{
// Client-hosted: force-save so the host cannot circumvent death by quitting without saving.
// On dedicated server the autosave handles persistence, so skip the forced save to avoid
// the client getting stuck on a "host is saving" screen during disconnect.
app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_SaveGame);
}
}
// AP added for Vita so the range can be increased once the level starts
void PlayerList::setViewDistance(int newViewDistance)
{
-1
View File
@@ -137,7 +137,6 @@ public:
void queueSmallIdForRecycle(BYTE smallId);
bool isXuidBanned(PlayerUID xuid);
void banXuid(PlayerUID xuid); // 4J Added - for hardcore mode ban-on-death
void banPlayerForHardcoreDeath(ServerPlayer *player); // Persistent XUID + IP ban on hardcore death
// AP added for Vita so the range can be increased once the level starts
void setViewDistance(int newViewDistance);
};
+1 -1
View File
@@ -204,7 +204,7 @@ void Screen::updateEvents()
// Map to Screen::keyPressed
int mappedKey = -1;
wchar_t ch = 0;
if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
else if (vk == VK_RETURN) mappedKey = Keyboard::KEY_RETURN;
else if (vk == VK_BACK) mappedKey = Keyboard::KEY_BACK;
else if (vk == VK_UP) mappedKey = Keyboard::KEY_UP;
+19 -24
View File
@@ -146,8 +146,7 @@ void ServerPlayer::flagEntitiesToBeRemoved(unsigned int *flags, bool *removedFou
if( ( *removedFound ) == false )
{
*removedFound = true;
// before this left 192 bytes uninitialized!!!!!
memset(flags, 0, (2048 / 32) * sizeof(unsigned int));
memset(flags, 0, 2048/32);
}
for(int index : entitiesToRemove)
@@ -377,9 +376,6 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
// connection->done);
// }
#ifdef MINECRAFT_SERVER_BUILD
if (dontDelayChunks || (canSendToPlayer && !connection->done))
#else
if( dontDelayChunks ||
(canSendToPlayer &&
#ifdef _XBOX_ONE
@@ -394,22 +390,21 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
#endif
//(tickCount - lastBrupSendTickCount) > (connection->getNetworkPlayer()->GetCurrentRtt()>>4) &&
!connection->done) )
#endif
{
lastBrupSendTickCount = tickCount;
okToSend = true;
MinecraftServer::chunkPacketManagement_DidSendTo(connection->getNetworkPlayer());
{
lastBrupSendTickCount = tickCount;
okToSend = true;
MinecraftServer::chunkPacketManagement_DidSendTo(connection->getNetworkPlayer());
// static unordered_map<wstring,int64_t> mapLastTime;
// int64_t thisTime = System::currentTimeMillis();
// int64_t lastTime = mapLastTime[connection->getNetworkPlayer()->GetUID().toString()];
// app.DebugPrintf(" - OK to send (%d ms since last)\n", thisTime - lastTime);
// mapLastTime[connection->getNetworkPlayer()->GetUID().toString()] = thisTime;
}
else
{
// app.DebugPrintf(" - <NOT OK>\n");
}
// static unordered_map<wstring,int64_t> mapLastTime;
// int64_t thisTime = System::currentTimeMillis();
// int64_t lastTime = mapLastTime[connection->getNetworkPlayer()->GetUID().toString()];
// app.DebugPrintf(" - OK to send (%d ms since last)\n", thisTime - lastTime);
// mapLastTime[connection->getNetworkPlayer()->GetUID().toString()] = thisTime;
}
else
{
// app.DebugPrintf(" - <NOT OK>\n");
}
}
if (okToSend)
@@ -574,10 +569,10 @@ void ServerPlayer::die(DamageSource *source)
{
setGameMode(GameType::ADVENTURE);
// Ban this player's XUID and queue disconnect.
// The force-save is triggered inside banPlayerForHardcoreDeath after the
// disconnect is queued, so the client doesn't get stuck on a save screen.
server->getPlayers()->banPlayerForHardcoreDeath(this);
// Ban this player's XUID and force-save so the host
// cannot circumvent the death by quitting without saving.
server->getPlayers()->banXuid(getOnlineXuid());
app.SetXuiServerAction(ProfileManager.GetPrimaryPad(), eXuiServerAction_SaveGame);
}
if (!level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY))
@@ -25,18 +25,12 @@ public:
static const int KEY_DROP = 'Q';
static const int KEY_CRAFTING = 'C';
static const int KEY_CRAFTING_ALT = 'R';
static const int KEY_CHAT = 'T';
static const int KEY_CONFIRM = VK_RETURN;
static const int KEY_CANCEL = VK_ESCAPE;
static const int KEY_PAUSE = VK_ESCAPE;
static const int KEY_TOGGLE_HUD = VK_F1;
static const int KEY_THIRD_PERSON = VK_F5;
static const int KEY_DEBUG_INFO = VK_F3;
static const int KEY_DEBUG_MENU = VK_F4;
static const int KEY_THIRD_PERSON = VK_F5;
static const int KEY_DEBUG_CONSOLE = VK_F6;
static const int KEY_HOST_SETTINGS = VK_TAB;
static const int KEY_FULLSCREEN = VK_F11;
static const int KEY_SCREENSHOT = VK_F2;
void Init();
void Tick();
@@ -121,6 +121,7 @@ static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };
struct Win64LaunchOptions
{
int screenMode;
bool serverMode;
bool fullscreen;
};
@@ -206,9 +207,13 @@ static Win64LaunchOptions ParseLaunchOptions()
{
Win64LaunchOptions options = {};
options.screenMode = 0;
options.serverMode = false;
g_Win64MultiplayerJoin = false;
g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT;
g_Win64DedicatedServer = false;
g_Win64DedicatedServerPort = WIN64_NET_DEFAULT_PORT;
g_Win64DedicatedServerBindIP[0] = 0;
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
@@ -221,6 +226,17 @@ static Win64LaunchOptions ParseLaunchOptions()
options.screenMode = argv[1][0] - L'0';
}
for (int i = 1; i < argc; ++i)
{
if (_wcsicmp(argv[i], L"-server") == 0)
{
options.serverMode = true;
break;
}
}
g_Win64DedicatedServer = options.serverMode;
for (int i = 1; i < argc; ++i)
{
if (_wcsicmp(argv[i], L"-name") == 0 && (i + 1) < argc)
@@ -231,8 +247,15 @@ static Win64LaunchOptions ParseLaunchOptions()
{
char ipBuf[256];
CopyWideArgToAnsi(argv[++i], ipBuf, sizeof(ipBuf));
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), ipBuf, _TRUNCATE);
g_Win64MultiplayerJoin = true;
if (options.serverMode)
{
strncpy_s(g_Win64DedicatedServerBindIP, sizeof(g_Win64DedicatedServerBindIP), ipBuf, _TRUNCATE);
}
else
{
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), ipBuf, _TRUNCATE);
g_Win64MultiplayerJoin = true;
}
}
else if (_wcsicmp(argv[i], L"-port") == 0 && (i + 1) < argc)
{
@@ -240,7 +263,10 @@ static Win64LaunchOptions ParseLaunchOptions()
const long port = wcstol(argv[++i], &endPtr, 10);
if (endPtr != argv[i] && *endPtr == 0 && port > 0 && port <= 65535)
{
g_Win64MultiplayerPort = static_cast<int>(port);
if (options.serverMode)
g_Win64DedicatedServerPort = static_cast<int>(port);
else
g_Win64MultiplayerPort = static_cast<int>(port);
}
}
else if (_wcsicmp(argv[i], L"-fullscreen") == 0)
@@ -251,6 +277,36 @@ static Win64LaunchOptions ParseLaunchOptions()
return options;
}
static BOOL WINAPI HeadlessServerCtrlHandler(DWORD ctrlType)
{
switch (ctrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_SHUTDOWN_EVENT:
app.m_bShutdown = true;
MinecraftServer::HaltServer();
return TRUE;
default:
return FALSE;
}
}
static void SetupHeadlessServerConsole()
{
if (AllocConsole())
{
FILE* stream = nullptr;
freopen_s(&stream, "CONIN$", "r", stdin);
freopen_s(&stream, "CONOUT$", "w", stdout);
freopen_s(&stream, "CONOUT$", "w", stderr);
SetConsoleTitleA("Minecraft Server");
}
SetConsoleCtrlHandler(HeadlessServerCtrlHandler, TRUE);
}
void DefineActions(void)
{
// The app needs to define the actions required, and the possible mappings for these
@@ -506,7 +562,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break;
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
@@ -563,7 +619,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
else if (vk == VK_MENU)
vk = (lParam & (1 << 24)) ? VK_RMENU : VK_LMENU;
g_KBMInput.OnKeyDown(vk);
return DefWindowProcW(hWnd, message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
}
case WM_KEYUP:
case WM_SYSKEYUP:
@@ -661,7 +717,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
}
break;
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
@@ -673,23 +729,23 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"Minecraft");
wcex.hIcon = LoadIcon(hInstance, "Minecraft");
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = L"Minecraft";
wcex.lpszClassName = L"MinecraftClass";
wcex.lpszMenuName = "Minecraft";
wcex.lpszClassName = "MinecraftClass";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MINECRAFTWINDOWS));
return RegisterClassExW(&wcex);
return RegisterClassEx(&wcex);
}
//
@@ -709,8 +765,8 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
RECT wr = {0, 0, g_rScreenWidth, g_rScreenHeight}; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
g_hWnd = CreateWindowW( L"MinecraftClass",
L"Minecraft",
g_hWnd = CreateWindow( "MinecraftClass",
"Minecraft",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
@@ -1294,6 +1350,161 @@ static Minecraft* InitialiseMinecraftRuntime()
return pMinecraft;
}
static int HeadlessServerConsoleThreadProc(void* lpParameter)
{
UNREFERENCED_PARAMETER(lpParameter);
std::string line;
while (!app.m_bShutdown)
{
if (!std::getline(std::cin, line))
{
if (std::cin.eof())
{
break;
}
std::cin.clear();
Sleep(50);
continue;
}
wstring command = trimString(convStringToWstring(line));
if (command.empty())
continue;
MinecraftServer* server = MinecraftServer::getInstance();
if (server != nullptr)
{
server->handleConsoleInput(command, server);
}
}
return 0;
}
static int RunHeadlessServer()
{
SetupHeadlessServerConsole();
Settings serverSettings(new File(L"server.properties"));
const wstring configuredBindIp = serverSettings.getString(L"server-ip", L"");
const char* bindIp = "*";
if (g_Win64DedicatedServerBindIP[0] != 0)
{
bindIp = g_Win64DedicatedServerBindIP;
}
else if (!configuredBindIp.empty())
{
bindIp = wstringtochararray(configuredBindIp);
}
const int port = g_Win64DedicatedServerPort > 0 ? g_Win64DedicatedServerPort : serverSettings.getInt(L"server-port", WIN64_NET_DEFAULT_PORT);
printf("Starting headless server on %s:%d\n", bindIp, port);
fflush(stdout);
const Minecraft* pMinecraft = InitialiseMinecraftRuntime();
if (pMinecraft == nullptr)
{
fprintf(stderr, "Failed to initialise the Minecraft runtime.\n");
return 1;
}
app.SetGameHostOption(eGameHostOption_Difficulty, serverSettings.getInt(L"difficulty", 1));
app.SetGameHostOption(eGameHostOption_Gamertags, 1);
app.SetGameHostOption(eGameHostOption_GameType, serverSettings.getInt(L"gamemode", 0));
app.SetGameHostOption(eGameHostOption_LevelType, 0);
app.SetGameHostOption(eGameHostOption_Structures, serverSettings.getBoolean(L"generate-structures", true) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_BonusChest, serverSettings.getBoolean(L"bonus-chest", false) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_PvP, serverSettings.getBoolean(L"pvp", true) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_TrustPlayers, serverSettings.getBoolean(L"trust-players", true) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_FireSpreads, serverSettings.getBoolean(L"fire-spreads", true) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_TNT, serverSettings.getBoolean(L"tnt", true) ? 1 : 0);
app.SetGameHostOption(eGameHostOption_HostCanFly, 1);
app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, 1);
app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, 1);
app.SetGameHostOption(eGameHostOption_MobGriefing, 1);
app.SetGameHostOption(eGameHostOption_KeepInventory, 0);
app.SetGameHostOption(eGameHostOption_DoMobSpawning, 1);
app.SetGameHostOption(eGameHostOption_DoMobLoot, 1);
app.SetGameHostOption(eGameHostOption_DoTileDrops, 1);
app.SetGameHostOption(eGameHostOption_NaturalRegeneration, 1);
app.SetGameHostOption(eGameHostOption_DoDaylightCycle, 1);
MinecraftServer::resetFlags();
g_NetworkManager.HostGame(0, false, true, MINECRAFT_NET_MAX_PLAYERS, 0);
if (!WinsockNetLayer::IsActive())
{
fprintf(stderr, "Failed to bind the server socket on %s:%d.\n", bindIp, port);
return 1;
}
g_NetworkManager.FakeLocalPlayerJoined();
NetworkGameInitData* param = new NetworkGameInitData();
param->seed = 0;
param->settings = app.GetGameHostOption(eGameHostOption_All);
g_NetworkManager.ServerStoppedCreate(true);
g_NetworkManager.ServerReadyCreate(true);
C4JThread* thread = new C4JThread(&CGameNetworkManager::ServerThreadProc, param, "Server", 256 * 1024);
thread->SetProcessor(CPU_CORE_SERVER);
thread->Run();
g_NetworkManager.ServerReadyWait();
g_NetworkManager.ServerReadyDestroy();
if (MinecraftServer::serverHalted())
{
fprintf(stderr, "The server halted during startup.\n");
g_NetworkManager.LeaveGame(false);
return 1;
}
app.SetGameStarted(true);
g_NetworkManager.DoWork();
printf("Server ready on %s:%d\n", bindIp, port);
printf("Type 'help' for server commands.\n");
fflush(stdout);
C4JThread* consoleThread = new C4JThread(&HeadlessServerConsoleThreadProc, nullptr, "Server console", 128 * 1024);
consoleThread->Run();
MSG msg = { 0 };
while (WM_QUIT != msg.message && !app.m_bShutdown && !MinecraftServer::serverHalted())
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
app.UpdateTime();
ProfileManager.Tick();
StorageManager.Tick();
RenderManager.Tick();
ui.tick();
g_NetworkManager.DoWork();
app.HandleXuiActions();
Sleep(10);
}
printf("Stopping server...\n");
fflush(stdout);
app.m_bShutdown = true;
MinecraftServer::HaltServer();
g_NetworkManager.LeaveGame(false);
return 0;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
@@ -1355,8 +1566,11 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
const Win64LaunchOptions launchOptions = ParseLaunchOptions();
ApplyScreenMode(launchOptions.screenMode);
// Ensure uid.dat exists from startup (before any multiplayer/login path).
Win64Xuid::ResolvePersistentXuid();
// Ensure uid.dat exists from startup in client mode (before any multiplayer/login path).
if (!launchOptions.serverMode)
{
Win64Xuid::ResolvePersistentXuid();
}
// If no username, let's fall back
if (g_Win64Username[0] == 0)
@@ -1437,7 +1651,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
if (!InitInstance (hInstance, launchOptions.serverMode ? SW_HIDE : nCmdShow))
{
return FALSE;
}
@@ -1456,6 +1670,13 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
ToggleFullscreen();
}
if (launchOptions.serverMode)
{
const int serverResult = RunHeadlessServer();
CleanupDevice();
return serverResult;
}
#if 0
// Main message loop
MSG msg = {0};
@@ -1765,7 +1986,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
// F1 toggles the HUD
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_TOGGLE_HUD))
if (g_KBMInput.IsKeyPressed(VK_F1))
{
const int primaryPad = ProfileManager.GetPrimaryPad();
const unsigned char displayHud = app.GetGameSettings(primaryPad, eGameSetting_DisplayHUD);
@@ -1774,7 +1995,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
// F3 toggles onscreen debug info
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO))
if (g_KBMInput.IsKeyPressed(VK_F3))
{
if (const Minecraft* pMinecraft = Minecraft::GetInstance())
{
@@ -1787,7 +2008,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
#ifdef _DEBUG_MENUS_ENABLED
// F6 Open debug console
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_CONSOLE))
if (g_KBMInput.IsKeyPressed(VK_F6))
{
static bool s_debugConsole = false;
s_debugConsole = !s_debugConsole;
@@ -1795,14 +2016,14 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
#endif
// toggle fullscreen
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_FULLSCREEN))
// F11 Toggle fullscreen
if (g_KBMInput.IsKeyPressed(VK_F11))
{
ToggleFullscreen();
}
// TAB opens game info menu. - Vvis :3 - Updated by detectiveren
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_HOST_SETTINGS) && !ui.GetMenuDisplayed(0))
if (g_KBMInput.IsKeyPressed(VK_TAB) && !ui.GetMenuDisplayed(0))
{
if (Minecraft* pMinecraft = Minecraft::GetInstance())
{
@@ -1814,7 +2035,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
// Open chat
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CHAT) && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
if (g_KBMInput.IsKeyPressed('T') && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
{
g_KBMInput.ClearCharBuffer();
pMinecraft->setScreen(new ChatScreen());
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

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