PlayerConnection::handleChat called FormatChatMessage with
applyStyling=false before broadcasting, which stripped all color codes
from the message. The client then had nothing left to format. Send the
raw message and let the client handle formatting on receive.
Three issues fixed:
- Save file path used hardcoded saveData.ms but new 4JLibs names files
as <title>.ms. ReadLevelNameFromSaveFile now constructs the correct
path with fallback to saveData.ms for old saves.
- The level.dat code path for reading the hardcore flag (sidecar rename)
returned early without ever parsing level.dat. Now stores the sidecar
name and continues to read the hardcore flag from NBT.
- The thumbnail host options path could overwrite m_bHardcore to false.
Now only upgrades to true, never downgrades.
- Load menu constructor and tick handler both lock difficulty slider to
Hardcore and gamemode to Survival when hardcore is detected.
- Hide title logo on load menu to match create world menu.
The new 4JLibs CaptureThumbnail produces all-black 64x64 PNGs because
its internal m_backBufferTexture copy fails silently. Bypass it entirely
and capture from the swap chain backbuffer using the same proven approach
as our F2 screenshot, with center-crop and downsample to 64x64 PNG.
- Remove shadowcolor from font tags (Iggy doesn't support multiple)
- Enforce HTML text mode on chat labels and jukebox
- Move IDS translatable pattern matching into FormatChatMessage
- Add §r (reset) color code support
- Fix message truncation to count visible characters, skipping HTML tags
- Fix CJK truncation using raw index instead of visible char count
Includes fixes and some modernizations compared to the original 4J
library binaries. Also introduces functionality to support stuff like
F2 screenshots, etc. This is basically the beginning of modernizing the
codebase.
Notably also adds some metadata files for NixOS
* add support for linux clang cross compiles
* add linux clang instructions
* un-capitalize Mob.horse.*
* update the description in flake.nix
---------
Co-authored-by: Loki <lokirautio@gmail.com>
* f3 menu text scaling
* Reduce overscaling above 1080p
Restores original scaling for 1440p to try and keep the text size more
sane on high DPI monitors
---------
Co-authored-by: Loki Rautio <lokirautio@gmail.com>
* add chat support for html formatting
* html character serialization, normal color format support
* change for chat input handling on color
has a bug where the text after the cursor gets stripped of its color, need to make a function to backstep on a string and find the last used color codes, or get all color codes used before the string is split, and apply them to the start of the next string
* expose jukebox label as action bar like java
* prevent players from sending chat color
* restore non styled chat size check
* f3 menu text scaling
* Reduce overscaling above 1080p
Restores original scaling for 1440p to try and keep the text size more
sane on high DPI monitors
---------
Co-authored-by: Loki Rautio <lokirautio@gmail.com>
When a new player was whitelisted while they were sitting on the join screen, their next attempt would insta-kick before the world ever loaded, and the retry after that would let them in for roughly 20 seconds before booting them with "connection closed". Two separate bugs were colliding.
The first kick was a stale cancel flag on the client. When the server rejects a join, the "Connecting to host..." screen tears down, and its teardown path fires the cancel callback defensively. That flag would latch on without ever being consumed, so the very first tick of the next join attempt saw it and immediately closed the fresh connection. Clearing the flag when a new join starts prevents this.
The second kick was an orphan on the server. When the first failed join's TCP dropped, its slot got recycled for the next successful join, but the half-built login object from the broken attempt was still in the pending queue. 30 seconds later its "login took too long" timer fired, and the disconnect packet it tried to send was routed to whoever currently held that slot, which was now the new in-world player. It landed on their live socket and kicked them. Telling the game's Socket layer about the TCP drop lets the orphan clean itself up, and refusing to write on an already-closing socket stops any late packet from leaking into the recycled slot.
Before this change, turning VSync off did not actually uncap your frame rate. The game ran in borderless fullscreen, where Windows' desktop compositor owns the display pipeline and applies its own VSync regardless of what the game asks for. So on a 240Hz monitor with a GPU that could draw 800fps, you still only saw 240 frames per second and the other 560 were thrown away. Worse, the frames you did see were up to a refresh cycle stale by the time they hit your eyes, which is input latency you can feel when moving the camera or aiming.
Fullscreen now uses true DXGI exclusive mode, where the compositor is out of the way and the swap chain writes directly to the display. Every frame the GPU produces lands on screen as soon as it is ready, so "VSync off" actually does something. Expect FPS to climb well past your monitor's refresh rate and the mouse to feel noticeably more responsive.
Exclusive fullscreen also displays at your monitor's native resolution with no driver-side scaling or filtering. The backbuffer is grown to match the monitor exactly before the transition, and the display mode is pinned to the backbuffer size so nothing in the output pipeline resamples your pixels on the way to the screen. The result is a crisp 1:1 image with none of the softening or greyish filter that stretched output can introduce.
Yes, this is the mode where screen tearing can happen. Tearing gets a bad reputation but it is a visual tradeoff, not a bug, and many players prefer it over the latency VSync causes. If you want to avoid tearing, just turn VSync on in the settings and the game will cap cleanly to your refresh rate. You now have a real choice between the two instead of "off" quietly being broken.
Under the hood, F11 and the saved fullscreen preference both route through a new ApplyExclusiveFullscreen path that does Microsoft's recommended transition: grow the window to cover the monitor, ResizeTarget with no scaling so the display mode is pinned to the backbuffer size, SetFullscreenState(TRUE), SetColorSpace1(sRGB), then a second ResizeTarget so picky drivers actually apply the mode. Exit forces a real decorated windowed state so F11 cycles cleanly between windowed and exclusive fullscreen. ResizeD3D skips its swap-chain-recreate path while in exclusive mode so it does not fight DXGI for ownership.
The swap chain's RefreshRate changes from a hardcoded 60Hz to 0/0 so DXGI matches the current display mode. Fixes an "input signal out of range" error that could happen on high-refresh monitors after entering fullscreen, where the monitor was being asked to renegotiate timing off of 240Hz down to 60Hz on every launch.
The previous FLIP_DISCARD swap chain configuration was producing broken rendering and a stretched aspect ratio on startup and after window resize, because the closed-source 4J Renderer library holds hidden backbuffer references that prevent ResizeBuffers from succeeding in flip mode. Switches the swap chain to the legacy bitblt DISCARD model with BufferCount=1, which lets the "destroy old, create new" resize path in ResizeD3D work cleanly. In-world rendering and aspect ratio are now correct at launch and across window resizes.
Known regression from this change: screen tearing no longer works when VSync is off. On Windows 10 and 11, bitblt swap chains always go through the DWM compositor, which locks presentation to the monitor refresh rate regardless of the SyncInterval parameter we pass to Present. Every frame the renderer produces above the refresh rate is silently dropped by DWM, which hurts input latency compared to a true uncapped-fps presentation path. The next iteration will reverse-engineer the 4J Renderer struct layout to find where those hidden backbuffer references are stored, release them before ResizeBuffers, and switch back to FLIP_DISCARD with ALLOW_TEARING so real tearing is possible again.
Also removes the dead SwapChainVSyncProxy COM wrapper. The proxy was originally intended to intercept Present calls from the Renderer library for VSync control, but the library hardcodes SyncInterval=1 and does not dispatch Present through the proxy vtable, so it was never actually doing anything useful.
The upstream project (formerly smartcmd/MinecraftConsoles, now MCLCE/MinecraftConsoles) reorganized their in-game credits screen. This pulls in that restructure so our credits accurately reflect who the current and former upstream maintainers are, and points the attribution URL at the right place. codeHusky and mattsumi stay as Project Maintainers, and itsRevela is added alongside them. smartcmd, Patoke, and rtm516 move to a new Former Maintainers section. The contributor count ticks up from 100+ to 120+, and the credit URL at the bottom now reads github.com/MCLCE/MinecraftConsoles with a "(formerly smartcmd/MinecraftConsoles)" line underneath it.
On the README side, only the Star History chart URL was updated from smartcmd to MCLCE. The Nightly client and dedicated server download links stay pointed at itsRevela/LCE-Revelations since our fork has its own release pipeline.
Upstream attribution: d0786f95 by Loki Rautio. Applied as a partial cherry-pick with the two Nightly download URL hunks dropped and itsRevela added to the maintainer list.
The personal repo was renamed from itsRevela/MinecraftConsoles to itsRevela/LCE-Revelations, so this sweeps the rest of the codebase to match. In-game, the credits screen now shows "LCE-Revelations" instead of "MinecraftConsoles" as the project heading. In the README, the Nightly client and dedicated server download links point at the new repo URL, and the Docker image reference is now ghcr.io/itsrevela/lce-revelations-dedicated-server. The dedicated server's generated server.properties file also picks up a new header comment reflecting the rename.
For folks building from source: the CMake project name was renamed, so when you configure the build the generated solution file is now LCE-Revelations.sln instead of MinecraftConsoles.sln. The Nix flake description and the Nightly release uploader script were updated to match, and a historical FourKit port reconnaissance document was removed since that port is already complete.
Also restored the Fluxer server link at the top of the README, which was lost when the repo was fast-forwarded from the upstream that got griefed.
When framerate was uncapped (vsync off, high-end hardware), the controller cursor in the inventory and creative menus moved way too fast. Basically unusable unless you switched to the dpad. The cursor update was tied to how often the screen redraws, so the faster the game ran, the faster the cursor flew.
Now the cursor moves a smaller distance per frame at higher framerates, so the actual on-screen speed stays the same whether you're at 60 FPS or 600 FPS.
While fixing this I also found an old workaround that was rounding the cursor position to whole pixels every frame and nudging it by 1 pixel to keep it from getting stuck. That nudge was pointing the wrong way on the vertical axis, which made up/down movement feel broken once the per-frame distance got small. Removed the rounding and the nudge. The cursor can now hold a fractional position between frames, and the part of the code that actually draws the cursor still snaps it to whole pixels on screen.
Fixes#3
- Protect PlayerList and ServerConnection players vectors with critical
sections; all iterations use copy-on-read snapshots to prevent iterator
invalidation during concurrent join/leave
- Add null check on player bounding box in movement validation to prevent
crash when player is removed mid-tick
- Re-validate socket player pointer immediately before SendData to narrow
the TOCTOU race window on disconnect
- Replace inline disconnect cleanup with a queued system drained on the
main tick thread, eliminating the done_cs -> m_playersCS lock inversion
that caused deadlocks under load
- Disable Windows QuickEdit mode at server startup to prevent console
input selection from freezing the process
- Move chunk priority sort behind ServerConnection::sortPlayersByChunkPriority()
to keep the players vector lock-protected
- Prevent payment item from being consumed when submitting unchanged powers
- Reorder ServerPlayer::openBeacon to send ContainerOpenPacket before
addSlotListener so beacon data packets arrive after the client menu is ready
- Add BeaconMenu::broadcastChanges() to continuously sync levels and powers
to clients, matching the pattern FurnaceMenu already uses
- Initialize UIControl_BeaconEffectButton::m_lastState to prevent stale
heap memory from suppressing Iggy ChangeState calls on menu re-entry
Adds the FourKit .NET 10 plugin host as a second dedicated server
build flavour alongside the existing vanilla server. Both flavours
build from the same source tree, with FourKit gated by the
MINECRAFT_SERVER_FOURKIT_BUILD preprocessor define.
Build layout:
Minecraft.Server vanilla, no plugin support, no .NET dep
Minecraft.Server.FourKit FourKit-enabled, ships with bundled
.NET 10 self-contained runtime in runtime/
and an empty plugins/ folder
Both produce a Minecraft.Server.exe in their own per-target output
dir. The variant identity lives in the directory name, not the
binary name, so either flavour can be shipped as a drop-in.
Native bridge (Minecraft.Server/FourKit*.{cpp,h}):
* FourKitRuntime: hosts CoreCLR via hostfxr's command-line init API
(the runtime-config API does not support self-contained components)
* FourKitBridge: ~50 Fire* event entry points, with inline no-op
stubs for the standalone build so gameplay code can call them
unconditionally
* FourKitNatives: ~80 native callbacks the managed side invokes
for player/world/inventory mutations
* FourKitMappers: type and enum mapping helpers
Managed plugin host (Minecraft.Server.FourKit/):
* Bukkit-style API: Player, World, Block, Inventory, Command,
Listener, EventHandler attribute, ~54 event classes
* PluginLoader with per-plugin AssemblyLoadContext
* FourKitHost as the [UnmanagedCallersOnly] entry point table
* Runtime resolves plugins relative to the host process so they
always live next to Minecraft.Server.exe regardless of where the
managed assembly itself is loaded from
Engine hooks (Minecraft.Client/, Minecraft.World/):
* Player lifecycle (PreLogin, Login, Join, Quit, Kick, Move,
Teleport, Portal, Death) wired into PendingConnection and
PlayerConnection without disturbing the cipher handshake or
identity-token security flow
* Inventory open/click/drop hooks across every container menu type
* Block place/break/grow/burn/spread/from-to hooks across the
full tile family
* Bed enter/leave, sign change, entity damage/death, ender pearl
teleport hooks
Regression fixes preserved while applying donor diffs:
* ServerPlayer::die() retains the LCE-Revelations hardcore branch
(setGameMode(ADVENTURE) + banPlayerForHardcoreDeath) in both the
FourKit and non-FourKit code paths
* ServerLevel::entityAdded() retains the sub-entity ID reassignment
loop required by the client's handleAddMob offset, fixing Ender
Dragon and Wither boss multi-part hit detection
* LivingEntity::travel() retains the raw Player* cast and the
cached frictionTile, both Revelations perf wins that the donor
silently reverted
* ServerLogger.cpp keeps the file-logging code donor stripped
* PlayerList.cpp end portal transition fix and UIScene_EndPoem
bounds-check are intact
Build system:
* Top-level CMakeLists.txt adds the Minecraft.Server.FourKit
subdirectory and pulls in the new shared cmake/ServerTarget.cmake
helper
* Minecraft.Server/cmake/sources/Common.cmake is now location
independent (uses CMAKE_CURRENT_LIST_DIR) so the source list
can be consumed from either server target's CMakeLists.txt
* The seven FourKit*.cpp/h files live in their own
_MINECRAFT_SERVER_COMMON_SERVER_FOURKIT variable so the
standalone target omits them
* configure-time .NET 10 SDK check fails fast with a clear
download link if the SDK is missing
* global.json pins the SDK to 10.0.100 with latestFeature
rollforward
Sample plugin (samples/HelloPlugin/) demonstrates the loader and
the PlayerJoinEvent listener pattern.
CI:
* nightly.yml builds both server flavours, ships
LCE-Revelations-Server-Win64.zip and
LCE-Revelations-Server-Win64-FourKit.zip, attests both, and
updates release notes for the dual-flavour layout
* pull-request.yml pulls in actions/setup-dotnet so the FourKit
publish step works in PR validation
* All zip artifacts and the client zip are renamed from
LCREWindows64 to LCE-Revelations-{Client,Server}-Win64
Documentation:
* COMPILE.md gets a VS 2022 quick start, .NET 10 prereq section,
server flavours explanation, and a troubleshooting section
* docs/FOURKIT_PORT_RECON.md captures the file-by-file recon that
drove the port
* docs/FOURKIT_PARITY.md is the canonical reference for which
events FourKit fires
Docker:
* docker-compose.dedicated-server.yml MC_RUNTIME_DIR default points
at the vanilla CMake output. The FourKit Docker image is
intentionally NOT shipped yet because hosting .NET 10 self
contained inside Wine has not been smoke-tested