130 Commits

Author SHA1 Message Date
itsRevela 5079622a6f ci: revert chunked-upload and full-history workarounds 2026-05-17 06:39:57 -05:00
itsRevela 6e31a8c0b8 ci: point workflow at git.revela.dev 2026-05-17 06:36:52 -05:00
itsRevela 61a8a13245 ci: enable buildx docker-container driver for OCI export 2026-05-17 02:01:49 -05:00
itsRevela c0cb7b7809 ci: push docker images via crane with chunked uploads 2026-05-17 01:30:12 -05:00
itsRevela 289225e07d ci: use REGISTRY_TOKEN for Forgejo container registry push 2026-05-15 03:04:29 -05:00
itsRevela ea02b5ee36 ci: full-history checkout for release tag push 2026-05-15 01:09:30 -05:00
itsRevela 59c39428fa ci: log file sizes and HTTP status on release asset upload 2026-05-14 16:44:10 -05:00
itsRevela 8ad207368b ci: pin artifact actions to v3 for Forgejo compatibility 2026-05-14 15:37:04 -05:00
itsRevela 07f0eb95dd ci: port nightly release pipeline to Forgejo 2026-05-14 15:24:32 -05:00
itsRevela 9c9238c6c4 ci: pin action uses to full GitHub URLs 2026-05-14 14:28:27 -05:00
itsRevela cf22f5f5f4 ci: switch workflows to self-hosted runner labels 2026-05-14 14:22:28 -05:00
itsRevela 386b9c430b Revert "chore(server): re-enable console QuickEdit mode"
This reverts commit 99120e5323.
2026-05-02 14:47:46 -05:00
itsRevela 68c2994523 chore: sync upstream MinecraftConsoles through d3df5350 2026-04-30 15:49:27 -05:00
itsRevela 1d9e79b9b3 docs: add submodule clone hint to compile instructions 2026-04-30 15:49:12 -05:00
itsRevela 50746cd3de revert(server): empty-dim entity tick gate 2026-04-30 15:46:26 -05:00
Loki d3df53503a Update COMPILE.md 2026-04-30 13:21:31 -05:00
Loki 5bccf89fe2 Update COMPILE.md 2026-04-30 13:21:25 -05:00
itsRevela 99120e5323 chore(server): re-enable console QuickEdit mode 2026-04-30 11:19:58 -05:00
itsRevela ca0619939c chore: sync upstream MinecraftConsoles through 5f931d74 2026-04-30 10:51:06 -05:00
itsRevela e4005d6b76 docs: add submodule clone hint to build instructions 2026-04-30 10:50:45 -05:00
itsRevela bddcc13bff chore(server): raise perf log thresholds to reduce noise 2026-04-30 10:47:08 -05:00
Loki Rautio 5f931d74fc Update 4JLibs, adjust README 2026-04-29 17:02:40 -05:00
itsRevela 5c90744677 docs: document fourkit docker image alongside vanilla in readme 2026-04-29 13:35:30 -05:00
itsRevela 750c4696ae chore: rewrite code comments 2026-04-29 13:33:19 -05:00
itsRevela ff3241cfee fix: server save-on-exit reliability and logging 2026-04-29 13:28:20 -05:00
itsRevela 17fdc78567 chore: bump 4JLibs to include PNG text section fix 2026-04-29 12:06:26 -05:00
itsRevela 3064afc9b2 chore: point 4JLibs submodule to itsRevela fork 2026-04-29 11:47:18 -05:00
itsRevela 3c1a7c174a feat: wire docker job into nightly workflow and update Dockerfile for both flavours 2026-04-28 17:31:58 -05:00
itsRevela 54b60867d4 feat: build vanilla and fourkit dedicated server docker images in nightly 2026-04-28 17:31:34 -05:00
itsRevela 8495baf83e fix: remove 30-second sprint auto-stop 2026-04-28 17:12:50 -05:00
itsRevela cc68899cec fix: iron door no longer blocks held-item use on right-click 2026-04-28 15:33:14 -05:00
itsRevela 89ed116fe0 fix: beacon outer halo washed out behind water 2026-04-28 14:19:22 -05:00
itsRevela 0df5cd865b chore: sync upstream MinecraftConsoles through 585455ce 2026-04-26 15:40:23 -05:00
ModMaker101 cbdb92d045 Replace MSVC __debugbreak with cross-compiler DEBUG_BREAK macro. (#1540) 2026-04-26 15:38:13 -05:00
ModMaker101 0625db38f5 Fix autosave thread compression TLS crash. (#1544) 2026-04-26 15:38:13 -05:00
Loki Rautio fc0e32f346 Fix PR workflow
Per patoke
2026-04-26 15:38:13 -05:00
Loki Rautio 3cef7f17dc fix: Control mappings wrong (update 4JLibs)
fixes #1531 and #1528
2026-04-26 15:38:13 -05:00
Loki Rautio d467b10e39 Remove redundant gitignore line 2026-04-26 15:38:13 -05:00
gsds 54ecbed263 Include 4JLibs as a submodule (#1535)
* feat: 4JLibs as a submodule

* fix: forgot submodule

* fix: actions didn't recurse submodules on checkout

* fix: oops, using old commit
2026-04-26 15:38:13 -05:00
dtentiion 7f18fe1236 fix: Nether portal trigger and travel sounds not playing (#1523) 2026-04-26 15:38:13 -05:00
Revela f583495958 Merge pull request #2 from Firebladedoge229/main
fix: paper doll transformations on non-16:9 aspect ratios
2026-04-26 15:10:39 -05:00
itsRevela 6b7d81a92b revert: /ping command and kernel TCP RTT plumbing 2026-04-26 14:52:46 -05:00
ModMaker101 585455cef0 Replace MSVC __debugbreak with cross-compiler DEBUG_BREAK macro. (#1540) 2026-04-26 12:23:52 -05:00
ModMaker101 3ab29ec26e Remove HTML escape for apostrophe in chat (#1541)
Fixes #1537
2026-04-26 12:22:51 -05:00
ModMaker101 e5351b51c0 Fix autosave thread compression TLS crash. (#1544) 2026-04-26 12:21:33 -05:00
itsRevela 44283e5971 fix(server): empty-dim tick gate broke block updates 2026-04-26 00:00:24 -05:00
itsRevela 70a610fd2c feat(server): kernel TCP RTT for Player.getPing() 2026-04-25 23:26:13 -05:00
itsRevela 0708120ae8 feat: add TpsPlugin sample with /tps and /ping 2026-04-25 22:45:35 -05:00
itsRevela f105952140 docs: README entry for TPS recovery at scale 2026-04-25 13:46:01 -05:00
itsRevela ce9ffefba6 perf(server): hold 20 TPS at 50-player scale 2026-04-25 13:42:29 -05:00
Fireblade da91372804 chore: clean up paper doll code for redundancy 2026-04-25 12:09:30 -04:00
Fireblade 1672dbab05 fix: paper doll viewmodel on non-16:9 window aspect ratios 2026-04-24 22:54:06 -04:00
itsRevela 18a08ec693 docs: README entry for FourKit dispatch performance fix 2026-04-24 21:35:34 -05:00
itsRevela b64b1f17db perf(fourkit): server gc, fast-path event dispatch, tps probe 2026-04-24 21:31:06 -05:00
Loki Rautio 42e75876f2 Fix PR workflow
Per patoke
2026-04-24 07:11:34 -05:00
Loki Rautio 5e5b685c72 fix: Control mappings wrong (update 4JLibs)
fixes #1531 and #1528
2026-04-21 19:55:46 -05:00
Loki Rautio d4ac3cd645 Remove redundant gitignore line 2026-04-21 18:57:30 -05:00
gsds 1b8a14357c Include 4JLibs as a submodule (#1535)
* feat: 4JLibs as a submodule

* fix: forgot submodule

* fix: actions didn't recurse submodules on checkout

* fix: oops, using old commit
2026-04-21 18:32:02 -05:00
itsRevela 6db68bda06 test(fourkit): add setblock and chatcolor subcommands to test plugin 2026-04-18 20:22:26 -05:00
sylvessa cb941db3ad i forgot to add chunk events to the docs 2026-04-18 19:57:20 -05:00
sylvessa b441998732 new funcs in Block, chatcolor enum 2026-04-18 19:57:14 -05:00
itsRevela 8dd9d92ad6 feat: add FourKit test plugin for chunk/inventory/disenchant verification 2026-04-18 19:15:56 -05:00
Sylvessa 7c1606837f fix: worlds without worlds won't open (#1529) 2026-04-18 19:14:42 -05:00
sylvessa 2e0f4f91d6 fix disenchant bugs from setdurability etc 2026-04-18 18:16:29 -05:00
sylvessa f9cac6395b fill in old stubs regaridng chunk stuff & another inv fix 2026-04-18 18:16:24 -05:00
sylvessa a9c735e7aa fix bugs found regarding inventories 2026-04-18 18:15:03 -05:00
sylvessa a3221c9e14 chunk additions 2026-04-18 18:14:58 -05:00
dtentiion 4a7b34f4c2 fix: Display save thumbnail in world detail view on Windows64 (#1519) 2026-04-18 17:49:43 -05:00
dtentiion 9167454767 fix: Nether portal trigger and travel sounds not playing (#1523) 2026-04-18 17:47:18 -05:00
itsRevela 84e4a77409 fix: exit save sometimes dropped during shutdown race 2026-04-18 10:56:54 -05:00
itsRevela 68c3440394 docs: note breeding/spawn-egg scaling with mob cap config 2026-04-18 10:19:27 -05:00
itsRevela 7e586e0d49 fix: scale breeding and spawn-egg caps with configured mob caps 2026-04-18 10:15:33 -05:00
itsRevela defd9ebd00 docs: update readme with recent fixes and mob cap config 2026-04-18 09:39:09 -05:00
itsRevela ffdad03aca feat: configurable mob spawn caps via server.properties 2026-04-18 09:31:45 -05:00
itsRevela c297b26f36 fix: duplicate join message on FourKit servers 2026-04-18 09:10:47 -05:00
itsRevela b4a34df1a9 fix: apostrophes rendering as ' in Iggy HTML chat labels 2026-04-17 16:55:56 -05:00
itsRevela ee3cf5117b chore: exclude .exp and .lib build artifacts from release zips 2026-04-17 15:31:53 -05:00
itsRevela afa3e22715 fix: force backbuffer clear alpha to 1.0 to prevent DWM window transparency 2026-04-17 12:43:46 -05:00
itsRevela cf81dd9d13 fix: apostrophes and quotes displaying as HTML entities in chat 2026-04-17 12:20:58 -05:00
itsRevela fde5fbe6f4 fix: force VSync on main menu to prevent GPU coil whine 2026-04-17 11:55:04 -05:00
itsRevela af39797303 chore: add PDB to nightly release, update readme
- Enable /Zi and /DEBUG for Release builds to generate PDB files
- Stage Minecraft.Client.pdb as standalone release asset
- Exclude .pdb from the zip release (dev-only artifact)
- Update release notes to separate player and developer instructions
- Update readme Latest section with recent bug fixes
2026-04-17 07:21:29 -05:00
itsRevela ce2efc1a4d fix: crash when opening UI scenes at sub-720p window size
SWF movie loading crashed with __debugbreak when the window height was
below 720px (e.g. after leaving exclusive fullscreen). The fallback
chain only tried 720.swf which doesn't exist. Now falls back through
720 -> 1080 so scenes always find a valid SWF.
2026-04-17 07:07:02 -05:00
itsRevela eb5aa9fa8f fix: chat color codes not rendering in singleplayer
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.
2026-04-17 07:06:39 -05:00
itsRevela 59f9dbc8c6 fix: hardcore mode UI not locking difficulty/gamemode on world load
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.
2026-04-17 07:06:26 -05:00
itsRevela bc6e445f0c fix: capture save thumbnails directly from D3D11 backbuffer
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.
2026-04-17 07:06:02 -05:00
itsRevela ec5ec84407 feat: add 4JLibs comparison tooling
Tools for comparing 4JLibs binary changes between git refs:
- compare-4jlibs.py: Extracts libs, parses symbol tables via dumpbin,
  demangles with undname, generates structured diff reports
- extract_lib.py: Extracts .obj members from COFF .lib archives
- ExportLibInfo.java: Ghidra headless script for non-LTCG object files
- list-lib-symbols.sh / compare-4jlibs.sh: Shell wrappers
2026-04-17 05:55:25 -05:00
itsRevela 019b790fb3 chore: sync upstream MinecraftConsoles through 1a552fbd 2026-04-17 05:53:46 -05:00
DrPerkyLegit 9ddb95e7ad Fix broken Chat Formatting behavior (#1520)
- 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
2026-04-17 05:52:26 -05:00
dtentiion 8464bfd448 fix: Skin pack names showing only first letter after 4JLibs update (#1518) 2026-04-17 05:49:22 -05:00
Loki Rautio 0e0f8f696d feat: Upgrade to 4JLibs libraries
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.
2026-04-17 05:40:38 -05:00
Loki 6ef535d53e Add new Discord invite to issue config 2026-04-17 05:39:51 -05:00
Alisa Vulpes 004cd72ba5 Add .DS_Store to .gitignore (#1509) 2026-04-17 05:38:39 -05:00
DrPerkyLegit 1a552fbd0c Fix broken Chat Formatting behavior (#1520)
* fix formatting in chat

iggy doesnt like multiple shadow colors

* enforce html labels

* dont format before sending packet, client formats anyway

* move translateables to chat format, restore original empty message results

* fix crappy string cutoff

* forgot a line on last commit, reset color support

* restore function to strip styling from player messages
2026-04-16 22:41:50 -05:00
dtentiion cccfd860b9 fix: Skin pack names showing only first letter after 4JLibs update (#1518) 2026-04-16 22:35:14 -05:00
Revela d0094a6409 Add F2 screenshot functionality (#1262)
- Updated `EControllerActions` to include `MINECRAFT_ACTION_SCREENSHOT`.
- Added conditional compilation for `stb_image_write.h` in `Minecraft.cpp`.
- Modified `run_middle()` to handle screenshot key press.
- Updated `tick()` to capture and save screenshots as PNG files.
- Introduced `KEY_SCREENSHOT` in `KeyboardMouseInput.h` mapped to F2.
- Added `stb_image_write.h` for image writing capabilities.
2026-04-16 22:33:30 -05:00
Loki Rautio 78d4bc80cf feat: Upgrade to 4JLibs libraries
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.
2026-04-15 19:07:15 -05:00
Loki 6595b3820d Add new Discord invite to issue config 2026-04-15 18:22:01 -05:00
Alisa Vulpes 7f0237a286 Add .DS_Store to .gitignore (#1509)
macOS automatically creates a .DS_Store file if any custom macOS attributes are set to files (like visual position in Finder). It's redundant for this repo and to avoid that to be accidentally committed/pushed, I added it to .gitignore.
2026-04-15 17:26:27 -05:00
itsRevela d694cd1c9d chore: sync upstream MinecraftConsoles through 2fba264c 2026-04-15 05:25:33 -05:00
Loki Rautio 9d92d5eb9b Swap critical.mp3 for critical.ogg (#1503) 2026-04-15 05:22:37 -05:00
Loki 2fba264c08 Revert "Prevent contextually wrong music from playing (#1138)"
This reverts commit 2d41711055.
2026-04-14 17:00:35 -05:00
Loki Rautio 1533b2138f Swap critical.mp3 for critical.ogg (#1503) 2026-04-14 16:59:58 -05:00
Riley M. c0da06e4ee major: Switch to forward slashes(+more) to fix compilation on Linux (#1403)
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>
2026-04-14 16:47:37 -05:00
itsRevela 5133925be0 chore: sync upstream MinecraftConsoles through f78dec6e 2026-04-13 03:16:34 -05:00
itsRevela 0544add4e2 chore: remove redundant/unused 4JLibs files 2026-04-13 03:15:58 -05:00
Loki Rautio f78dec6e00 Remove redundant/unused 4JLibs files
also adds some countermeasures against, yknow.
2026-04-13 01:26:36 -05:00
itsRevela 0d102b167f docs: add Latest entries for upstream sync through 78afb091 2026-04-13 01:00:03 -05:00
itsRevela 8c34855343 chore: sync upstream MinecraftConsoles through 78afb091 2026-04-13 00:54:24 -05:00
Tyler Reese 6913ce5323 fix: Implement missing critical hit sound (#1141) 2026-04-13 00:51:16 -05:00
DrPerkyLegit 71707fbb8c Add Chat Formatting Support For Servers (#1483) 2026-04-13 00:49:49 -05:00
GabsPuNs ae9dbd837d Exclude more files, reduce build .zip size (#1374) 2026-04-13 00:48:43 -05:00
Toru the Red Fox 825e96da54 Request dedicated GPU (#850) 2026-04-13 00:47:00 -05:00
Botch dea2bad0c4 fix: Disable font mipmapping (#1410) 2026-04-13 00:46:32 -05:00
DrPerkyLegit ae3c843ee5 fix: Increase entity network limit to 16k entities (#1492) 2026-04-13 00:43:18 -05:00
DrPerkyLegit 6c572d4940 feat: Scrollable chat (#1493) 2026-04-13 00:42:04 -05:00
DrPerkyLegit 5e7ad7333e Better Text Scaling (#1494)
* 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>
2026-04-13 00:37:54 -05:00
Tyler Reese 78afb091a4 fix: Implement missing critical hit sound (#1141)
* Fix

* Crit Sound Now Plays On Death

* Revert BuildVer.h

---------

Co-authored-by: Loki <lokio.casebstv@gmail.com>
2026-04-12 23:24:29 -05:00
Tyler Reese 2d41711055 fix: Prevent contextually wrong music from playing (#1138) 2026-04-12 23:22:14 -05:00
DrPerkyLegit 14f8d793dd Add Chat Formatting Support For Servers (#1483)
* 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
2026-04-12 23:17:45 -05:00
GabsPuNs bfcb621808 Exclude more files, reduce build .zip size (#1374)
* Fix Sign

* Exclude more files from the compilation.

* Remove Trial and Tutorial folder in Common, Tutorial world is in windows64media
2026-04-12 23:17:21 -05:00
Toru the Red Fox 050c501786 Request dedicated GPU (#850) 2026-04-12 22:56:24 -05:00
Botch e5ce9a06cd fix: Disable font mipmapping (#1410)
Fixes visual artifacts with signs, improving legibility at distances
2026-04-12 22:55:07 -05:00
Us3ful"-Dev e730033bcc fix: Prevent end poem crash (#1489)
Removed player name check that always fails to work on non host instances
2026-04-12 22:53:39 -05:00
rtm516 9e6e3de338 Improve actions file ignore rules (#1491)
* Add clang-format workflow for pull request checks

* Modify push paths in nightly workflow

Updated paths for push event to include all files except specified ones.

* Update paths for nightly-server workflow triggers

* Modify paths for pull request triggers

Update pull request workflow to include specific paths.

* Remove formatting check workflow
2026-04-12 22:52:34 -05:00
DrPerkyLegit 82c1ae1968 fix: Increase entity network limit to 16k entities (#1492) 2026-04-12 22:50:46 -05:00
DrPerkyLegit c7014f6b18 feat: Scrollable chat (#1493)
* chat scrolling

* allow escape to close chat instead of opening pause
2026-04-12 22:50:16 -05:00
DrPerkyLegit 744048f455 Better Text Scaling (#1494)
* 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>
2026-04-12 22:48:08 -05:00
itsRevela 33bec8a93c docs: add Latest entries for recent client fixes
Covers the join-flow kick bug, the fullscreen and frame rate work, and the controller cursor speed fix.
2026-04-11 08:13:58 -05:00
itsRevela abb18e3e12 fix: new players kicked when joining right after being whitelisted
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.
2026-04-11 08:13:46 -05:00
itsRevela f189234614 feat: uncap fps in fullscreen for lower input latency
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.
2026-04-11 06:19:22 -05:00
211 changed files with 6691 additions and 1570 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: MinecraftConsoles Community Discord
url: https://discord.gg/jrum7HhegA
- name: ❗NEW❗ MinecraftConsoles Community Discord
url: https://discord.gg/dH8AZWGcau
about: If you need help, please ask for it in our Discord! You will get assistance much faster there, including help getting the project to compile.
+214 -80
View File
@@ -7,6 +7,7 @@ permissions:
contents: write
id-token: write
attestations: write
packages: write
concurrency:
group: nightly
@@ -15,20 +16,22 @@ concurrency:
jobs:
build-client:
name: Build Client
runs-on: windows-latest
runs-on: [self-hosted, windows]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: https://github.com/actions/checkout@v6
with:
submodules: recursive
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
uses: https://github.com/ilammy/msvc-dev-cmd@v1
- name: Setup CMake
uses: lukka/get-cmake@latest
uses: https://github.com/lukka/get-cmake@latest
- name: Run CMake
uses: lukka/run-cmake@v10
uses: https://github.com/lukka/run-cmake@v10
env:
VCPKG_ROOT: ""
with:
@@ -45,7 +48,7 @@ jobs:
# Collect files, excluding unwanted extensions
$files = Get-ChildItem -Path $source -Recurse -File |
Where-Object { $_.Extension -notin '.pch', '.zip', '.ipdb', '.iobj' }
Where-Object { $_.Extension -notin '.pch', '.pdb', '.zip', '.ipdb', '.iobj', '.exp', '.lib' }
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
@@ -80,34 +83,37 @@ jobs:
New-Item -ItemType Directory -Force -Path staging
Copy-Item LCE-Revelations-Client-Win64.zip staging/
Copy-Item ./build/windows64/Minecraft.Client/Release/Minecraft.Client.exe staging/
Copy-Item ./build/windows64/Minecraft.Client/Release/Minecraft.Client.pdb staging/
- name: Upload artifacts
uses: actions/upload-artifact@v6
uses: https://github.com/actions/upload-artifact@v3
with:
name: client-build
path: staging/*
build-server:
name: Build Server
runs-on: windows-latest
runs-on: [self-hosted, windows]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: https://github.com/actions/checkout@v6
with:
submodules: recursive
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
uses: https://github.com/ilammy/msvc-dev-cmd@v1
- name: Setup CMake
uses: lukka/get-cmake@latest
uses: https://github.com/lukka/get-cmake@latest
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: https://github.com/actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Run CMake
uses: lukka/run-cmake@v10
uses: https://github.com/lukka/run-cmake@v10
env:
VCPKG_ROOT: ""
with:
@@ -123,7 +129,7 @@ jobs:
$topLevel = "LCE-Revelations-Server-Win64"
$files = Get-ChildItem -Path $source -Recurse -File |
Where-Object { $_.Extension -notin '.pch', '.zip', '.ipdb', '.iobj' }
Where-Object { $_.Extension -notin '.pch', '.zip', '.ipdb', '.iobj', '.exp', '.lib' }
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
@@ -158,7 +164,7 @@ jobs:
$topLevel = "LCE-Revelations-Server-Win64-FourKit"
$files = Get-ChildItem -Path $source -Recurse -File |
Where-Object { $_.Extension -notin '.pch', '.zip', '.ipdb', '.iobj' }
Where-Object { $_.Extension -notin '.pch', '.zip', '.ipdb', '.iobj', '.exp', '.lib' }
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
@@ -193,49 +199,119 @@ jobs:
Copy-Item LCE-Revelations-Server-Win64-FourKit.zip staging/
- name: Upload artifacts
uses: actions/upload-artifact@v6
uses: https://github.com/actions/upload-artifact@v3
with:
name: server-build
path: staging/*
release-server:
name: Release Server
docker:
name: Build Docker (${{ matrix.variant }})
needs: build-server
runs-on: ubuntu-latest
runs-on: [self-hosted, linux]
strategy:
fail-fast: false
matrix:
include:
- variant: vanilla
zip: LCE-Revelations-Server-Win64.zip
subdir: LCE-Revelations-Server-Win64
image: lce-revelations-dedicated-server
- variant: fourkit
zip: LCE-Revelations-Server-Win64-FourKit.zip
subdir: LCE-Revelations-Server-Win64-FourKit
image: lce-revelations-dedicated-server-fourkit
steps:
- name: Checkout
uses: actions/checkout@v6
uses: https://github.com/actions/checkout@v6
- name: Download server artifacts
uses: actions/download-artifact@v7
uses: https://github.com/actions/download-artifact@v3
with:
name: server-build
path: .artifacts/
- name: Prepare runtime directory
shell: bash
run: |
set -euo pipefail
rm -rf runtime .extracted
unzip -q ".artifacts/${{ matrix.zip }}" -d .extracted
mv ".extracted/${{ matrix.subdir }}" runtime
# Strip debug symbols to keep image small (zip includes .pdb).
find runtime -name '*.pdb' -delete
- name: Compute image name
id: image
shell: bash
run: |
owner="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')"
echo "image=git.revela.dev/$owner/${{ matrix.image }}" >> "$GITHUB_OUTPUT"
- name: Extract Docker metadata
id: meta
uses: https://github.com/docker/metadata-action@v5
with:
images: ${{ steps.image.outputs.image }}
tags: |
type=raw,value=nightly
- name: Login to Forgejo registry
uses: https://github.com/docker/login-action@v3
with:
registry: git.revela.dev
username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push image
uses: https://github.com/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
release-server:
name: Release Server
needs: build-server
runs-on: [self-hosted, linux]
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Download server artifacts
uses: https://github.com/actions/download-artifact@v3
with:
name: server-build
path: artifacts
- name: Attest artifacts
uses: actions/attest-build-provenance@v2
with:
subject-path: |
artifacts/LCE-Revelations-Server-Win64.zip
artifacts/LCE-Revelations-Server-Win64-FourKit.zip
- name: Install jq
run: apt-get update && apt-get install -y --no-install-recommends jq
- name: Get short SHA
id: sha
run: echo "short=$(echo '${{ github.sha }}' | cut -c1-7)" >> "$GITHUB_OUTPUT"
- name: Delete old release
- name: Delete old release and tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release delete Nightly-Dedicated-Server --yes || true
- name: Delete old tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh api repos/${{ github.repository }}/git/refs/tags/Nightly-Dedicated-Server --method DELETE || true
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="Nightly-Dedicated-Server"
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
AUTH="Authorization: token $FORGEJO_TOKEN"
EXISTING_ID=$(curl -sf -H "$AUTH" "$API/releases/tags/$TAG" 2>/dev/null | jq -r '.id // empty' || true)
if [ -n "$EXISTING_ID" ]; then
curl -sf -X DELETE -H "$AUTH" "$API/releases/$EXISTING_ID"
fi
curl -s -X DELETE -H "$AUTH" "$API/tags/$TAG" > /dev/null || true
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
uses: https://github.com/crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
@@ -247,59 +323,94 @@ jobs:
git tag -s -f Nightly-Dedicated-Server -m "Nightly server release ${{ steps.sha.outputs.short }}"
git push origin Nightly-Dedicated-Server --force
- name: Create release
- name: Create release on Forgejo
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create Nightly-Dedicated-Server artifacts/* \
--title "Server: ${{ steps.sha.outputs.short }}" \
--notes "Dedicated Server runtime for Windows64.
set -euo pipefail
TAG="Nightly-Dedicated-Server"
TITLE="Server: ${{ steps.sha.outputs.short }}"
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
AUTH="Authorization: token $FORGEJO_TOKEN"
NOTES=$(cat <<'EOF'
Dedicated Server runtime for Windows64.
Two flavours are attached:
- \`LCE-Revelations-Server-Win64.zip\`: vanilla server, no plugin support, smallest download.
- \`LCE-Revelations-Server-Win64-FourKit.zip\`: server with the FourKit plugin host, bundled .NET 10 runtime, and an empty \`plugins/\` folder ready for plugin authors to drop DLLs into.
- `LCE-Revelations-Server-Win64.zip`: vanilla server, no plugin support, smallest download.
- `LCE-Revelations-Server-Win64-FourKit.zip`: server with the FourKit plugin host, bundled .NET 10 runtime, and an empty `plugins/` folder ready for plugin authors to drop DLLs into.
Pick the flavour you want and extract it to a folder where you'd like to keep the server runtime." \
--latest=false
Pick the flavour you want and extract it to a folder where you'd like to keep the server runtime.
EOF
)
PAYLOAD=$(jq -nc --arg tag "$TAG" --arg name "$TITLE" --arg body "$NOTES" \
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:false}')
RID=$(curl -sf -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d "$PAYLOAD" "$API/releases" | jq -r '.id')
if [ -z "$RID" ] || [ "$RID" = "null" ]; then
echo "Failed to create release" >&2
exit 1
fi
echo "Created release id=$RID"
for asset in artifacts/*; do
name=$(basename "$asset")
size=$(stat -c%s "$asset")
echo "Uploading $name ($size bytes)"
HTTP=$(curl -sS -w '%{http_code}' -o /tmp/upload-resp -X POST -H "$AUTH" \
-F "attachment=@$asset" \
"$API/releases/$RID/assets?name=$name")
if [ "$HTTP" -lt 200 ] || [ "$HTTP" -ge 300 ]; then
echo "Upload failed: HTTP $HTTP" >&2
echo "--- response body ---" >&2
cat /tmp/upload-resp >&2 || true
echo "" >&2
exit 1
fi
echo "Uploaded $name OK (HTTP $HTTP)"
done
release-client:
name: Release Client
needs: [build-client, release-server]
runs-on: ubuntu-latest
runs-on: [self-hosted, linux]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: https://github.com/actions/checkout@v6
- name: Download client artifacts
uses: actions/download-artifact@v7
uses: https://github.com/actions/download-artifact@v3
with:
name: client-build
path: artifacts
- name: Attest artifacts
uses: actions/attest-build-provenance@v2
with:
subject-path: |
artifacts/LCE-Revelations-Client-Win64.zip
artifacts/Minecraft.Client.exe
- name: Install jq
run: apt-get update && apt-get install -y --no-install-recommends jq
- name: Get short SHA
id: sha
run: echo "short=$(echo '${{ github.sha }}' | cut -c1-7)" >> "$GITHUB_OUTPUT"
- name: Delete old release
- name: Delete old release and tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release delete Nightly --yes || true
- name: Delete old tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh api repos/${{ github.repository }}/git/refs/tags/Nightly --method DELETE || true
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="Nightly"
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
AUTH="Authorization: token $FORGEJO_TOKEN"
EXISTING_ID=$(curl -sf -H "$AUTH" "$API/releases/tags/$TAG" 2>/dev/null | jq -r '.id // empty' || true)
if [ -n "$EXISTING_ID" ]; then
curl -sf -X DELETE -H "$AUTH" "$API/releases/$EXISTING_ID"
fi
curl -s -X DELETE -H "$AUTH" "$API/tags/$TAG" > /dev/null || true
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
uses: https://github.com/crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
@@ -321,7 +432,10 @@ jobs:
- To play, simply run `Minecraft.Client.exe`.
**For those that wish to update their existing installation with the latest build:**
- Download `Minecraft.Client.exe` and `Minecraft.Client.pdb` and copy them over to your existing LCE-Revelations-Client-Win64 build (overwrite your old version of Minecraft.Client.exe and Minecraft.Client.pdb).
- Download `Minecraft.Client.exe` and copy it over to your existing LCE-Revelations-Client-Win64 build (overwrite your old version of Minecraft.Client.exe).
**For developers:**
- `Minecraft.Client.pdb` contains debug symbols for crash analysis and development. Place it next to `Minecraft.Client.exe` for stack traces to show function names and line numbers.
**Steam Deck & Linux:**
- Y'all know the drill. Download the `LCE-Revelations-Client-Win64.zip`, extract it, add the `Minecraft.Client.exe` as a "Non-Steam Game" within the Steam library, turn on compatibility mode with Proton Experimental, and then run it!
@@ -343,22 +457,42 @@ jobs:
- After creating your tunnel, navigate to the "Tunnels" main page. You'll see the IP address and port for your tunnel. This is what your friends will input when adding your server in order to join your online game!
NOTES
- name: Create release
- name: Create release on Forgejo
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create Nightly artifacts/* \
--title "Client: ${{ steps.sha.outputs.short }}" \
--notes-file notes.md
set -euo pipefail
TAG="Nightly"
TITLE="Client: ${{ steps.sha.outputs.short }}"
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
AUTH="Authorization: token $FORGEJO_TOKEN"
cleanup:
needs: [release-client, release-server]
if: always()
runs-on: ubuntu-latest
steps:
- name: Cleanup artifacts
uses: geekyeggo/delete-artifact@v5
with:
name: |
client-build
server-build
BODY=$(cat notes.md)
PAYLOAD=$(jq -nc --arg tag "$TAG" --arg name "$TITLE" --arg body "$BODY" \
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:false}')
RID=$(curl -sf -X POST -H "$AUTH" -H "Content-Type: application/json" \
-d "$PAYLOAD" "$API/releases" | jq -r '.id')
if [ -z "$RID" ] || [ "$RID" = "null" ]; then
echo "Failed to create release" >&2
exit 1
fi
echo "Created release id=$RID"
for asset in artifacts/*; do
name=$(basename "$asset")
size=$(stat -c%s "$asset")
echo "Uploading $name ($size bytes)"
HTTP=$(curl -sS -w '%{http_code}' -o /tmp/upload-resp -X POST -H "$AUTH" \
-F "attachment=@$asset" \
"$API/releases/$RID/assets?name=$name")
if [ "$HTTP" -lt 200 ] || [ "$HTTP" -ge 300 ]; then
echo "Upload failed: HTTP $HTTP" >&2
echo "--- response body ---" >&2
cat /tmp/upload-resp >&2 || true
echo "" >&2
exit 1
fi
echo "Uploaded $name OK (HTTP $HTTP)"
done
+8 -6
View File
@@ -11,25 +11,27 @@ on:
jobs:
build:
runs-on: windows-latest
runs-on: [self-hosted, windows]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: https://github.com/actions/checkout@v6
with:
submodules: recursive
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
uses: https://github.com/ilammy/msvc-dev-cmd@v1
- name: Setup CMake
uses: lukka/get-cmake@latest
uses: https://github.com/lukka/get-cmake@latest
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: https://github.com/actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Run CMake
uses: lukka/run-cmake@v10
uses: https://github.com/lukka/run-cmake@v10
env:
VCPKG_ROOT: "" # Disable vcpkg for CI builds
with:
+3
View File
@@ -429,3 +429,6 @@ result-*
.direnv/
.xwin-cache/
.xwin/
# macOS
.DS_Store
+3
View File
@@ -0,0 +1,3 @@
[submodule "Minecraft.Client/Windows64/4JLibs"]
path = Minecraft.Client/Windows64/4JLibs
url = https://github.com/itsRevela/4JLibs.git
+4 -2
View File
@@ -39,10 +39,10 @@ function(configure_compiler_target target)
# MSVC
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(${target} PRIVATE
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/GL>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/GL /Zi>
)
target_link_options(${target} PRIVATE
$<$<CONFIG:Release>:/LTCG:incremental>
$<$<CONFIG:Release>:/LTCG:incremental /DEBUG /OPT:REF /OPT:ICF>
)
endif()
@@ -81,6 +81,8 @@ list(APPEND MINECRAFT_SHARED_DEFINES ${PLATFORM_DEFINES})
# ---
# Sources
# ---
add_subdirectory("Minecraft.Client/${PLATFORM_NAME}/4JLibs")
add_subdirectory(Minecraft.World)
add_subdirectory(Minecraft.Client)
if(PLATFORM_NAME STREQUAL "Windows64") # Server is only supported on Windows for now
+2 -1
View File
@@ -15,7 +15,8 @@
VS 2022 has built-in CMake support, so there is no need to generate a `.sln` file by hand.
1. Install the prerequisites above.
2. Clone the repo.
2. Clone the repo with submodules. If you don't, you will get a build error!
- `git clone --recurse-submodules https://github.com/itsRevela/LCE-Revelations.git`
3. In Visual Studio: `File > Open > Folder...` and select the **repo root** (the folder that contains `CMakeLists.txt`).
4. Wait for CMake to configure (~5 seconds on a warm cache, a few minutes on the first run while assets copy).
5. Pick a build configuration in the dropdown, for example `windows64-release`.
+1 -1
View File
@@ -104,7 +104,7 @@ byteArray ArchiveFile::getFile(const wstring &filename)
app.DebugPrintf("Couldn't find file in archive\n");
app.DebugPrintf("Failed to find file '%ls' in archive\n", filename.c_str());
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
app.FatalLoadError();
}
+18 -19
View File
@@ -6,6 +6,8 @@
ResourceLocation BeaconRenderer::BEAM_LOCATION = ResourceLocation(TN_MISC_BEACON_BEAM);
bool BeaconRenderer::s_renderOuterHalo = false;
void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y, double z, float a, bool setColor, float alpha, bool useCompiled)
{
shared_ptr<BeaconTileEntity> beacon = dynamic_pointer_cast<BeaconTileEntity>(_beacon);
@@ -18,21 +20,18 @@ void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y,
bindTexture(&BEAM_LOCATION);
// TODO: 4J: Put this back in
//assert(0);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthMask(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
float tt = beacon->getLevel()->getGameTime() + a;
float texVOff = -tt * .20f - floor(-tt * .10f);
if (!s_renderOuterHalo)
{
glDisable(GL_BLEND);
glDepthMask(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
int r = 1;
double rot = tt * .025 * (1 - (r & 1) * 2.5);
@@ -73,20 +72,20 @@ void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y,
t->vertexUV(x + enx, y, z + enz, uu2, vv2);
t->vertexUV(x + esx, y, z + esz, uu1, vv2);
t->vertexUV(x + esx, y + top, z + esz, uu1, vv1);
t->vertexUV(x + wsx, y + top, z + wsz, uu2, vv1);
t->vertexUV(x + wsx, y, z + wsz, uu2, vv2);
t->vertexUV(x + wnx, y, z + wnz, uu1, vv2);
t->vertexUV(x + wnx, y + top, z + wnz, uu1, vv1);
t->end();
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(false);
else
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(false);
t->begin();
t->color(255, 255, 255, 32);
@@ -111,22 +110,22 @@ void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y,
t->vertexUV(x + wnx, y, z + wnz, uu2, vv2);
t->vertexUV(x + enx, y, z + enz, uu1, vv2);
t->vertexUV(x + enx, y + top, z + enz, uu1, vv1);
t->vertexUV(x + esx, y + top, z + esz, uu2, vv1);
t->vertexUV(x + esx, y, z + esz, uu2, vv2);
t->vertexUV(x + wsx, y, z + wsz, uu1, vv2);
t->vertexUV(x + wsx, y + top, z + wsz, uu1, vv1);
t->vertexUV(x + enx, y + top, z + enz, uu2, vv1);
t->vertexUV(x + enx, y, z + enz, uu2, vv2);
t->vertexUV(x + esx, y, z + esz, uu1, vv2);
t->vertexUV(x + esx, y + top, z + esz, uu1, vv1);
t->vertexUV(x + wsx, y + top, z + wsz, uu2, vv1);
t->vertexUV(x + wsx, y, z + wsz, uu2, vv2);
t->vertexUV(x + wnx, y, z + wnz, uu1, vv2);
t->vertexUV(x + wnx, y + top, z + wnz, uu1, vv1);
t->end();
}
+2
View File
@@ -9,5 +9,7 @@ private:
static ResourceLocation BEAM_LOCATION;
public:
static bool s_renderOuterHalo;
virtual void render(shared_ptr<TileEntity> _beacon, double x, double y, double z, float a, bool setColor, float alpha, bool useCompiled);
};
+4 -12
View File
@@ -57,16 +57,10 @@ target_link_libraries(Minecraft.Client PRIVATE
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"
>
4JLibs.${PLATFORM_NAME}.Input
4JLibs.${PLATFORM_NAME}.Profile
4JLibs.${PLATFORM_NAME}.Storage
4JLibs.${PLATFORM_NAME}.Render
)
# Iggy libs
@@ -82,8 +76,6 @@ 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}")
+18 -1
View File
@@ -12,6 +12,7 @@ const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters;
vector<wstring> ChatScreen::s_chatHistory;
int ChatScreen::s_historyIndex = -1;
wstring ChatScreen::s_historyDraft;
int ChatScreen::s_chatIndex = 0;
bool ChatScreen::isAllowedChatChar(wchar_t c)
{
@@ -28,6 +29,8 @@ ChatScreen::ChatScreen()
frame = 0;
cursorIndex = 0;
s_historyIndex = -1;
ChatScreen::s_chatIndex = 0;
}
void ChatScreen::init()
@@ -89,6 +92,20 @@ void ChatScreen::handleHistoryDown()
applyHistoryMessage();
}
int ChatScreen::getChatIndex()
{
return ChatScreen::s_chatIndex;
}
void ChatScreen::correctChatIndex(int newChatIndex) {
ChatScreen::s_chatIndex = newChatIndex;
}
void ChatScreen::setWheelValue(int wheel) {
ChatScreen::s_chatIndex += wheel;
if (ChatScreen::s_chatIndex < 0) ChatScreen::s_chatIndex = 0;
}
void ChatScreen::keyPressed(wchar_t ch, int eventKey)
{
if (eventKey == Keyboard::KEY_ESCAPE)
@@ -140,7 +157,7 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
cursorIndex--;
return;
}
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxChatLength)
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxVisibleLength)
{
message.insert(cursorIndex, 1, ch);
cursorIndex++;
+4
View File
@@ -16,6 +16,7 @@ private:
static std::vector<wstring> s_chatHistory;
static int s_historyIndex;
static wstring s_historyDraft;
static int s_chatIndex;
static const wstring allowedChars;
static bool isAllowedChatChar(wchar_t c);
@@ -28,6 +29,9 @@ public:
virtual void handleHistoryUp();
virtual void handleHistoryDown();
static int getChatIndex();
static void correctChatIndex(int newChatIndex);
static void setWheelValue(int wheel);
protected:
void keyPressed(wchar_t ch, int eventKey);
public:
+1 -1
View File
@@ -1016,7 +1016,7 @@ bool Chunk::isEmpty()
void Chunk::setDirty()
{
// 4J - not used, but if this starts being used again then we'll need to investigate how best to handle it.
__debugbreak();
DEBUG_BREAK();
levelRenderer->setGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_DIRTY);
}
+18 -5
View File
@@ -1607,17 +1607,28 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
bool replaceEntitySource = false;
bool replaceItem = false;
int stringArgsSize = packet->m_stringArgs.size();
wstring playerDisplayName = L"";
wstring sourceDisplayName = L"";
// On platforms other than Xbox One this just sets display name to gamertag
if (packet->m_stringArgs.size() >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]);
if (packet->m_stringArgs.size() >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]);
if (stringArgsSize >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]);
if (stringArgsSize >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]);
switch(packet->m_messageType)
{
case ChatPacket::e_ChatCustom:
message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L"";
case ChatPacket::e_ChatActionBar:
if (stringArgsSize >= 1) {
message = packet->m_stringArgs[0];
message = app.EscapeHTMLString(message); //do this to enforce escaped string
message = app.FormatChatMessage(message); //this needs to be last cause it converts colors to html colors that would have been escaped
} else {
message = L"";
}
displayOnGui = (packet->m_messageType == ChatPacket::e_ChatCustom);
break;
case ChatPacket::e_ChatBedOccupied:
message = app.GetString(IDS_TILE_BED_OCCUPIED);
@@ -1967,7 +1978,7 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
if(replacePlayer)
{
message = replaceAll(message,L"{*PLAYER*}",playerDisplayName);
message = replaceAll(message,L"{*PLAYER*}", playerDisplayName);
}
if(replaceEntitySource)
@@ -2002,7 +2013,9 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
// flag that a message is a death message
bool bIsDeathMessage = (packet->m_messageType>=ChatPacket::e_ChatDeathInFire) && (packet->m_messageType<=ChatPacket::e_ChatDeathIndirectMagicItem);
if( displayOnGui ) minecraft->gui->addMessage(message,m_userIndex, bIsDeathMessage);
if( displayOnGui ) minecraft->gui->addMessage(message, m_userIndex, bIsDeathMessage);
if (!displayOnGui && !message.empty()) minecraft->gui->setActionBarMessage(message);
}
void ClientConnection::handleAnimate(shared_ptr<AnimatePacket> packet)
@@ -595,23 +595,26 @@ void SoundEngine::playUI(int iSound, float volume, float pitch)
{
U8 szSoundName[256];
wstring name;
const char* soundDir;
if (iSound >= eSFX_MAX)
{
strcpy((char*)szSoundName, "Minecraft/");
name = wchSoundNames[iSound];
soundDir = "Minecraft";
}
else
{
strcpy((char*)szSoundName, "Minecraft/UI/");
name = wchUISoundNames[iSound];
soundDir = "Minecraft/UI";
}
char* SoundName = (char*)ConvertSoundPathToName(name);
strcat((char*)szSoundName, SoundName);
char basePath[256];
sprintf_s(basePath, "Windows64Media/Sound/Minecraft/UI/%s", ConvertSoundPathToName(name));
sprintf_s(basePath, "Windows64Media/Sound/%s/%s", soundDir, ConvertSoundPathToName(name));
char finalPath[256];
@@ -223,6 +223,8 @@ const WCHAR *ConsoleSoundEngine::wchSoundNames[eSoundType_MAX]=
// 4J-PB - Some sounds were updated, but we can't do that for the 360 or we have to do a new sound bank
// instead, we'll add the sounds as new ones and change the code to reference them
L"fire.new_ignite",
L"damage.critical", //eSoundType_DAMAGE_CRITICAL,
};
+94 -5
View File
@@ -70,6 +70,7 @@
#endif
#include "../Common/Leaderboards/LeaderboardManager.h"
#include <regex>
//CMinecraftApp app;
unsigned int CMinecraftApp::m_uiLastSignInData = 0;
@@ -95,7 +96,7 @@ CMinecraftApp::CMinecraftApp()
// 4J Stu - See comment for GAME_SETTINGS_PROFILE_DATA_BYTES in Xbox_App.h
DebugPrintf("WARNING: The size of the profile GAME_SETTINGS struct has changed, so all stat data is likely incorrect. Is: %d, Should be: %d\n",sizeof(GAME_SETTINGS),GAME_SETTINGS_PROFILE_DATA_BYTES);
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
}
@@ -1302,9 +1303,6 @@ int CMinecraftApp::OldProfileVersionCallback(LPVOID pParam,unsigned char *pucDat
{
// This might be from a version during testing of new profile updates
app.DebugPrintf("Don't know what to do with this profile version!\n");
#ifndef _CONTENT_PACKAGE
// __debugbreak();
#endif
GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData;
pGameSettings->ucMenuSensitivity=100; //eGameSetting_Sensitivity_InMenu
@@ -6478,7 +6476,7 @@ void CMinecraftApp::InitialiseTips()
{
// the m_TriviaTipA or the m_GameTipA are out of sync
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
}
}
@@ -6653,6 +6651,97 @@ wstring CMinecraftApp::FormatHTMLString(int iPad, const wstring &desc, int shado
return text;
}
//found list of html escapes at https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-in-html
wstring CMinecraftApp::EscapeHTMLString(const wstring& desc)
{
static std::unordered_map<wchar_t, wchar_t*> replacementMap = {
{L'&', L"&amp;"},
{L'<', L"&lt;"},
{L'>', L"&gt;"},
};
wstring finalString = L"";
for (int i = 0; i < desc.size(); i++) {
wchar_t _char = desc[i];
auto it = replacementMap.find(_char);
if (it != replacementMap.end()) finalString += it->second;
else finalString += _char;
}
return finalString;
}
wstring CMinecraftApp::FormatChatMessage(const wstring& desc, bool applyStyling)
{
static std::wregex IDS_Pattern(LR"(\{\*IDS_(\d+)\*\})"); //maybe theres a better way to do translateable IDS
static std::wstring_view colorFormatString = L"<font color=\"#%08x\">";
wstring results = desc;
wchar_t replacements[64];
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF);
results = replaceAll(results, L"§0", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF);
results = replaceAll(results, L"§1", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF);
results = replaceAll(results, L"§2", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF);
results = replaceAll(results, L"§3", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF);
results = replaceAll(results, L"§4", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF);
results = replaceAll(results, L"§5", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF);
results = replaceAll(results, L"§6", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF);
results = replaceAll(results, L"§7", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF);
results = replaceAll(results, L"§8", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF);
results = replaceAll(results, L"§9", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF);
results = replaceAll(results, L"§a", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF);
results = replaceAll(results, L"§b", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF);
results = replaceAll(results, L"§c", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF);
results = replaceAll(results, L"§d", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF);
results = replaceAll(results, L"§e", replacements);
swprintf(replacements, 64, (applyStyling ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_f), 0xFFFFFFFF);
results = replaceAll(results, L"§f", replacements);
results = replaceAll(results, L"§r", replacements); //we only support color so reset is the same as white color
results = replaceAll(results, L"'", L"\u2019");
if (applyStyling) {
std::wsmatch match;
while (std::regex_search(results, match, IDS_Pattern)) {
results = replaceAll(results, match[0], app.GetString(std::stoi(match[1].str())));
}
}
return results;
}
wstring CMinecraftApp::GetActionReplacement(int iPad, unsigned char ucAction)
{
unsigned int input = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad) ,ucAction);
+3 -1
View File
@@ -564,7 +564,9 @@ public:
int GetHTMLColour(eMinecraftColour colour);
int GetHTMLColor(eMinecraftColour colour) { return GetHTMLColour(colour); }
int GetHTMLFontSize(EHTMLFontSize size);
wstring FormatHTMLString(int iPad, const wstring &desc, int shadowColour = 0xFFFFFFFF);
wstring FormatHTMLString(int iPad, const wstring& desc, int shadowColour = 0xFFFFFFFF);
wstring EscapeHTMLString(const wstring &desc);
wstring FormatChatMessage(const wstring& desc, bool applyStyling = true);
wstring GetActionReplacement(int iPad, unsigned char ucAction);
wstring GetVKReplacement(unsigned int uiVKey);
wstring GetIconReplacement(unsigned int uiIcon);
+1 -2
View File
@@ -171,7 +171,7 @@ DLCPack *DLCManager::getPack(DWORD index, EDLCType type /*= e_DLCType_All*/)
if(index >= m_packs.size())
{
app.DebugPrintf("DLCManager: Trying to access a DLC pack beyond the range of valid packs\n");
__debugbreak();
DEBUG_BREAK();
}
pack = m_packs[index];
}
@@ -186,7 +186,6 @@ DWORD DLCManager::getPackIndex(DLCPack *pack, bool &found, EDLCType type /*= e_D
if(pack == nullptr)
{
app.DebugPrintf("DLCManager: Attempting to find the index for a nullptr pack\n");
//__debugbreak();
return foundIndex;
}
if( type != e_DLCType_All )
+2 -5
View File
@@ -107,7 +107,7 @@ void DLCPack::addChildPack(DLCPack *childPack)
#ifndef _CONTENT_PACKAGE
if(packId < 0 || packId > 15)
{
__debugbreak();
DEBUG_BREAK();
}
#endif
childPack->SetPackId( (packId<<24) | m_packId );
@@ -362,7 +362,7 @@ DWORD DLCPack::getFileIndexAt(DLCManager::EDLCType type, const wstring &path, bo
{
app.DebugPrintf("Unimplemented\n");
#ifndef __CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return 0;
}
@@ -392,9 +392,6 @@ bool DLCPack::hasPurchasedFile(DLCManager::EDLCType type, const wstring &path)
/*if(type == DLCManager::e_DLCType_All)
{
app.DebugPrintf("Unimplemented\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
#endif
return false;
}
#ifndef _CONTENT_PACKAGE
@@ -122,7 +122,7 @@ void ConsoleSchematicFile::load(DataInputStream *dis)
{
#ifndef _CONTENT_PACKAGE
app.DebugPrintf("ConsoleSchematicFile has read a nullptr tile entity\n");
__debugbreak();
DEBUG_BREAK();
#endif
}
else
@@ -635,7 +635,7 @@ void ConsoleSchematicFile::generateSchematicFile(DataOutputStream *dos, Level *l
}
#ifndef _CONTENT_PACKAGE
if(p!=blockCount) __debugbreak();
if(p!=blockCount) DEBUG_BREAK();
#endif
// We don't know how this will compress - just make a fixed length buffer to initially decompress into
@@ -24,7 +24,7 @@ GameRule::ValueType GameRule::getParameter(const wstring &parameterName)
{
#ifndef _CONTENT_PACKAGE
wprintf(L"WARNING: Parameter %ls was not set before being fetched\n", parameterName.c_str());
__debugbreak();
DEBUG_BREAK();
#endif
}
return m_parameters[parameterName];
@@ -238,7 +238,7 @@ HRESULT SonyLeaderboardManager::fillByIdsQuery(const SceNpId &myNpId, SceNpId* &
{
// 4J-JEV: Something terrible must have happend,
// 'getFriendslist' was supposed to be a synchronous operation.
__debugbreak();
DEBUG_BREAK();
// 4J-JEV: We can at least fall-back to just the players score.
len = 1;
@@ -204,6 +204,12 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
ProfileManager.SetDeferredSignoutEnabled(true);
#endif
// Clear any stale cancel flag latched by the previous join's progress
// UI teardown, otherwise the next join's first tick insta-closes.
EnterCriticalSection(&bCancelRequestedCS);
g_NetworkManager.m_bCancelRequested = false;
LeaveCriticalSection(&bCancelRequestedCS);
int64_t seed = 0;
bool dedicatedNoLocalHostPlayer = false;
if (lpParameter != nullptr)
@@ -134,7 +134,14 @@ void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer* pQNetPlayer)
if (socket != nullptr)
{
if (m_pIQNet->IsHost())
{
g_NetworkManager.CloseConnection(networkPlayer);
// Propagate the TCP drop to the game Socket so any orphaned
// PendingConnection at this smallId cleans up before its login
// timer fires and leaks a DisconnectPacket to the reused slot.
socket->close(true);
}
}
if (m_pIQNet->IsHost())
@@ -247,8 +247,6 @@ void CPlatformNetworkManagerSony::HandlePlayerJoined(SQRNetworkPlayer *
void CPlatformNetworkManagerSony::HandlePlayerLeaving(SQRNetworkPlayer *pSQRPlayer)
{
//__debugbreak();
app.DebugPrintf( "Player 0x%p leaving.\n",
pSQRPlayer );
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "UIController.h"
#include <ChatScreen.h>
#include "UI.h"
#include "UIScene.h"
#include "UIControl_Slider.h"
@@ -1438,6 +1439,9 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
}
#endif
if (key == 4) ChatScreen::setWheelValue(1);
if (key == 5) ChatScreen::setWheelValue(-1);
if(pressed) app.DebugPrintf("Pressed %d\n",key);
if(released) app.DebugPrintf("Released %d\n",key);
// Repeat handling
+28 -27
View File
@@ -310,19 +310,27 @@ void UIScene::loadMovie()
if(!app.hasArchiveFile(moviePath))
{
app.DebugPrintf("WARNING: Could not find iggy movie %ls, falling back on 720\n", moviePath.c_str());
app.DebugPrintf("WARNING: Could not find iggy movie %ls, trying other resolutions\n", moviePath.c_str());
// Try 720 first, then 1080 as final fallback
moviePath = getMoviePath();
moviePath.append(L"720.swf");
m_loadedResolution = eSceneResolution_720;
if(!app.hasArchiveFile(moviePath))
{
app.DebugPrintf("ERROR: Could not find any iggy movie for %ls!\n", moviePath.c_str());
moviePath = getMoviePath();
moviePath.append(L"1080.swf");
m_loadedResolution = eSceneResolution_1080;
if(!app.hasArchiveFile(moviePath))
{
app.DebugPrintf("ERROR: Could not find any iggy movie for %ls!\n", moviePath.c_str());
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
app.FatalLoadError();
app.FatalLoadError();
}
}
}
@@ -335,7 +343,7 @@ void UIScene::loadMovie()
{
app.DebugPrintf("ERROR: Failed to load iggy scene!\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
app.FatalLoadError();
}
@@ -941,9 +949,6 @@ void UIScene::_customDrawSlotControl(CustomDrawData *region, int iPad, shared_pt
// if(m_parentLayer == nullptr)
// {
// app.DebugPrintf("A scene is trying to navigate forwards, but it's parent layer is nullptr!\n");
//#ifndef _CONTENT_PACKAGE
// __debugbreak();
//#endif
// }
// else
// {
@@ -960,10 +965,6 @@ void UIScene::navigateBack()
if(m_parentLayer == nullptr)
{
// app.DebugPrintf("A scene is trying to navigate back, but it's parent layer is nullptr!\n");
#ifndef _CONTENT_PACKAGE
// __debugbreak();
#endif
}
else
{
@@ -1194,7 +1195,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handlePress did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1202,7 +1203,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Arguments for handlePress were not of the correct type\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1214,7 +1215,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handleFocusChange did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1222,7 +1223,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Arguments for handleFocusChange were not of the correct type\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1234,7 +1235,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handleInitFocus did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1242,7 +1243,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Arguments for handleInitFocus were not of the correct type\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1254,7 +1255,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handleCheckboxToggled did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1262,7 +1263,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Arguments for handleCheckboxToggled were not of the correct type\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1274,7 +1275,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handleSliderMove did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1282,7 +1283,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Arguments for handleSliderMove were not of the correct type\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1294,7 +1295,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handleAnimationEnd did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1306,7 +1307,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handleSelectionChanged did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1314,7 +1315,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Arguments for handleSelectionChanged were not of the correct type\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1332,7 +1333,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Callback for handleRequestMoreData did not have the correct number of arguments\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
@@ -1340,7 +1341,7 @@ void UIScene::externalCallback(IggyExternalFunctionCallUTF16 * call)
{
app.DebugPrintf("Arguments for handleRequestMoreData were not of the correct type\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return;
}
+28 -7
View File
@@ -9,6 +9,7 @@
#include "../../EnderDragonRenderer.h"
#include "../../../Minecraft.World/net.minecraft.world.inventory.h"
#include "../../../Minecraft.World/StringHelpers.h"
#include <ChatScreen.h>
UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
{
@@ -23,8 +24,10 @@ UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UISce
for(unsigned int i = 0; i < CHAT_LINES_COUNT; ++i)
{
m_labelChatText[i].init(L"");
IggyValueSetBooleanRS(m_labelChatText[i].getIggyValuePath(), 0, "m_bUseHtmlText", true);
}
m_labelJukebox.init(L"");
IggyValueSetBooleanRS(m_labelJukebox.getIggyValuePath(), 0, "m_bUseHtmlText", true);
addTimer(0, 100);
}
@@ -254,8 +257,10 @@ void UIScene_HUD::handleReload()
for(unsigned int i = 0; i < CHAT_LINES_COUNT; ++i)
{
m_labelChatText[i].init(L"");
IggyValueSetBooleanRS(m_labelChatText[i].getIggyValuePath(), 0, "m_bUseHtmlText", true);
}
m_labelJukebox.init(L"");
IggyValueSetBooleanRS(m_labelJukebox.getIggyValuePath(), 0, "m_bUseHtmlText", true);
int iGuiScale;
Minecraft *pMinecraft = Minecraft::GetInstance();
@@ -778,16 +783,31 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor
void UIScene_HUD::handleTimerComplete(int id)
{
Minecraft *pMinecraft = Minecraft::GetInstance();
bool isChatOpen = (dynamic_cast<ChatScreen*>(pMinecraft->getScreen()) != nullptr);
bool anyVisible = false;
if(pMinecraft->localplayers[m_iPad]!= nullptr)
{
Gui *pGui = pMinecraft->gui;
//DWORD messagesToDisplay = min( CHAT_LINES_COUNT, pGui->getMessagesCount(m_iPad) );
for( unsigned int i = 0; i < CHAT_LINES_COUNT; ++i )
DWORD totalMessages = pGui->getMessagesCount(m_iPad);
DWORD messagesToDisplay = min( CHAT_LINES_COUNT, totalMessages);
DWORD maxScroll = max(0, totalMessages - messagesToDisplay);
bool canScroll = messagesToDisplay < totalMessages;
int startIndex = (canScroll && isChatOpen ? ChatScreen::getChatIndex() : 0);
if (startIndex > maxScroll) {
ChatScreen::correctChatIndex(maxScroll);
startIndex = maxScroll;
}
app.DebugPrintf("handleTimerComplete: %d | %d | %d\n", maxScroll, startIndex, totalMessages);
for( unsigned int i = 0; i < messagesToDisplay; ++i )
{
float opacity = pGui->getOpacity(m_iPad, i);
if( opacity > 0 )
unsigned int msgIndex = startIndex + i;
float opacity = pGui->getOpacity(m_iPad, msgIndex);
if( opacity > 0 || isChatOpen)
{
#if 0 // def _WINDOWS64 // Use Iggy chat until Gui::render has visual parity
// Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats.
@@ -795,9 +815,10 @@ void UIScene_HUD::handleTimerComplete(int id)
m_labelChatText[i].setOpacity(0);
m_labelChatText[i].setLabel(L"");
#else
m_controlLabelBackground[i].setOpacity(opacity);
m_labelChatText[i].setOpacity(opacity);
m_labelChatText[i].setLabel( pGui->getMessagesCount(m_iPad) ? pGui->getMessage(m_iPad,i) : L"" );
m_controlLabelBackground[i].setOpacity((isChatOpen ? 1 : opacity));
m_labelChatText[i].setOpacity((isChatOpen ? 1 : opacity));
m_labelChatText[i].setLabel(pGui->getMessage(m_iPad, msgIndex));
#endif
anyVisible = true;
}
+1 -1
View File
@@ -11,7 +11,7 @@ private:
bool m_bSplitscreen;
protected:
UIControl_Label m_labelChatText[CHAT_LINES_COUNT];
UIControl_HTMLLabel m_labelChatText[CHAT_LINES_COUNT];
UIControl_Label m_labelJukebox;
UIControl m_controlLabelBackground[CHAT_LINES_COUNT];
UIControl_Label m_labelDisplayName;
@@ -281,6 +281,11 @@ UIScene_LoadMenu::UIScene_LoadMenu(int iPad, void *initData, UILayer *parentLaye
WCHAR TempString[256];
swprintf((WCHAR *)TempString, 256, L"%ls: %ls", app.GetString(IDS_SLIDER_DIFFICULTY), L"Hardcore");
m_sliderDifficulty.init(TempString, eControl_Difficulty, 0, 4, 4);
// Hardcore locks game mode to Survival
m_iGameModeId = GameType::SURVIVAL->getId();
m_bGameModeCreative = false;
m_buttonGamemode.setLabel(app.GetString(IDS_GAMEMODE_SURVIVAL));
}
}
#endif
@@ -421,15 +426,7 @@ void UIScene_LoadMenu::updateTooltips()
void UIScene_LoadMenu::updateComponents()
{
m_parentLayer->showComponent(m_iPad,eUIComponent_Panorama,true);
if(RenderManager.IsWidescreen())
{
m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,true);
}
else
{
m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,false);
}
m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,false);
}
wstring UIScene_LoadMenu::getMoviePath()
@@ -573,7 +570,9 @@ void UIScene_LoadMenu::tick()
m_MoreOptionsParams.bAllowFriendsOfFriends = TRUE;
}
m_bHardcore = app.GetGameHostOption(uiHostOptions, eGameHostOption_Hardcore) > 0;
// Use thumbnail host options if available, otherwise preserve the level.dat value
if (app.GetGameHostOption(uiHostOptions, eGameHostOption_Hardcore) > 0)
m_bHardcore = true;
if (m_bHardcore)
{
WCHAR TempString[256];
@@ -32,6 +32,7 @@
static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardcore = nullptr)
{
// Check for a worldname.txt sidecar written by the rename feature first
wstring sidecarName = L"";
size_t slashPos = filePath.rfind(L'\\');
if (slashPos != wstring::npos)
{
@@ -50,7 +51,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
{
wchar_t wbuf[128] = {};
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, 127);
return wstring(wbuf);
sidecarName = wbuf;
}
}
else fclose(fr);
@@ -58,10 +59,10 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
}
HANDLE hFile = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
if (hFile == INVALID_HANDLE_VALUE) return L"";
if (hFile == INVALID_HANDLE_VALUE) return sidecarName;
DWORD fileSize = GetFileSize(hFile, nullptr);
if (fileSize < 12 || fileSize == INVALID_FILE_SIZE) { CloseHandle(hFile); return L""; }
if (fileSize < 12 || fileSize == INVALID_FILE_SIZE) { CloseHandle(hFile); return sidecarName; }
unsigned char *rawData = new unsigned char[fileSize];
DWORD bytesRead = 0;
@@ -69,7 +70,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
{
CloseHandle(hFile);
delete[] rawData;
return L"";
return sidecarName;
}
CloseHandle(hFile);
@@ -84,7 +85,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
if (decompSize == 0 || decompSize > 128 * 1024 * 1024)
{
delete[] rawData;
return L"";
return sidecarName;
}
saveData = new unsigned char[decompSize];
Compression::getCompression()->Decompress(saveData, &decompSize, rawData + 8, fileSize - 8);
@@ -140,6 +141,10 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
if (freeSaveData) delete[] saveData;
delete[] rawData;
// Prefer the sidecar name (user-renamed) over the level.dat name
if (!sidecarName.empty()) return sidecarName;
// "world" is the engine default - it means no real name was ever set,
// so return empty to let the caller fall back to the save filename (timestamp).
if (result == L"world") result = L"";
@@ -774,7 +779,16 @@ void UIScene_LoadOrJoinMenu::tick()
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");
wchar_t wTitle[MAX_DISPLAYNAME_LENGTH];
ZeroMemory(wTitle, sizeof(wTitle));
mbstowcs(wTitle, m_pSaveDetails->SaveInfoA[origIdx].UTF8SaveTitle, MAX_DISPLAYNAME_LENGTH - 1);
wstring filePath = wstring(L"Windows64\\GameHDD\\") + wstring(wFilename) + wstring(L"\\") + wstring(wTitle) + wstring(L".ms");
// Fallback to legacy saveData.ms if new-style filename doesn't exist
{
DWORD attrs = GetFileAttributesW(filePath.c_str());
if (attrs == INVALID_FILE_ATTRIBUTES)
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;
@@ -390,7 +390,7 @@ void UIScene_MainMenu::handlePress(F64 controlId, F64 childId)
break;
#endif
default: __debugbreak();
default: DEBUG_BREAK();
}
bool confirmUser = false;
@@ -1127,15 +1127,6 @@ void UIScene_SkinSelectMenu::handlePackIndexChanged()
updatePackDisplay();
}
std::wstring fakeWideToRealWide(const wchar_t* original)
{
const char* name = reinterpret_cast<const char*>(original);
int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
std::wstring wName(len, 0);
MultiByteToWideChar(CP_UTF8, 0, name, -1, &wName[0], len);
return wName.c_str();
}
void UIScene_SkinSelectMenu::updatePackDisplay()
{
m_currentPackCount = app.m_dlcManager.getPackCount(DLCManager::e_DLCType_Skin) + SKIN_SELECT_MAX_DEFAULTS;
@@ -1143,18 +1134,16 @@ void UIScene_SkinSelectMenu::updatePackDisplay()
if(m_packIndex >= SKIN_SELECT_MAX_DEFAULTS)
{
DLCPack *thisPack = app.m_dlcManager.getPack(m_packIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin);
// Fix the incorrect string type on title to display correctly
setCentreLabel(fakeWideToRealWide(thisPack->getName().c_str()));
//setCentreLabel(thisPack->getName().c_str());
setCentreLabel(thisPack->getName().c_str());
}
else
{
switch(m_packIndex)
{
case SKIN_SELECT_PACK_DEFAULT:
case SKIN_SELECT_PACK_DEFAULT:
setCentreLabel(app.GetString(IDS_NO_SKIN_PACK));
break;
case SKIN_SELECT_PACK_FAVORITES:
case SKIN_SELECT_PACK_FAVORITES:
setCentreLabel(app.GetString(IDS_FAVORITES_SKIN_PACK));
break;
}
@@ -1164,18 +1153,16 @@ void UIScene_SkinSelectMenu::updatePackDisplay()
if(nextPackIndex >= SKIN_SELECT_MAX_DEFAULTS)
{
DLCPack *thisPack = app.m_dlcManager.getPack(nextPackIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin);
// Fix the incorrect string type on title to display correctly
setRightLabel(fakeWideToRealWide(thisPack->getName().c_str()));
//setRightLabel(thisPack->getName().c_str());
setRightLabel(thisPack->getName().c_str());
}
else
{
switch(nextPackIndex)
{
case SKIN_SELECT_PACK_DEFAULT:
case SKIN_SELECT_PACK_DEFAULT:
setRightLabel(app.GetString(IDS_NO_SKIN_PACK));
break;
case SKIN_SELECT_PACK_FAVORITES:
case SKIN_SELECT_PACK_FAVORITES:
setRightLabel(app.GetString(IDS_FAVORITES_SKIN_PACK));
break;
}
@@ -1185,18 +1172,16 @@ void UIScene_SkinSelectMenu::updatePackDisplay()
if(previousPackIndex >= SKIN_SELECT_MAX_DEFAULTS)
{
DLCPack *thisPack = app.m_dlcManager.getPack(previousPackIndex - SKIN_SELECT_MAX_DEFAULTS, DLCManager::e_DLCType_Skin);
// Fix the incorrect string type on title to display correctly
setLeftLabel(fakeWideToRealWide(thisPack->getName().c_str()));
//setLeftLabel(thisPack->getName().c_str());
setLeftLabel(thisPack->getName().c_str());
}
else
{
switch(previousPackIndex)
{
case SKIN_SELECT_PACK_DEFAULT:
case SKIN_SELECT_PACK_DEFAULT:
setLeftLabel(app.GetString(IDS_NO_SKIN_PACK));
break;
case SKIN_SELECT_PACK_FAVORITES:
case SKIN_SELECT_PACK_FAVORITES:
setLeftLabel(app.GetString(IDS_FAVORITES_SKIN_PACK));
break;
}
+2 -2
View File
@@ -106,7 +106,7 @@ wstring DLCTexturePack::getResource(const wstring& name)
{
// 4J Stu - We should never call this function
#ifndef __CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
return L"";
}
@@ -115,7 +115,7 @@ InputStream *DLCTexturePack::getResourceImplementation(const wstring &name) //th
{
// 4J Stu - We should never call this function
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
if(hasFile(name)) return nullptr;
#endif
return nullptr; //resource;
+1 -1
View File
@@ -641,7 +641,7 @@ int CConsoleMinecraftApp::Callback_TMSPPReadDLCFile(void *pParam,int iPad, int i
{
DWORD error = GetLastError();
app.DebugPrintf("Failed to open DLCXbox1.cmp with error code %d (%x)\n", error, error);
__debugbreak();
DEBUG_BREAK();
return 0;
}
@@ -20,7 +20,7 @@ void ConsoleUIController::init(Microsoft::WRL::ComPtr<ID3D11Device> dev, Microso
{
app.DebugPrintf("Failed to initialise GDraw!\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
app.FatalLoadError();
}
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
@@ -187,8 +187,6 @@ void CPlatformNetworkManagerDurango::HandlePlayerJoined(DQRNetworkPlayer *pDQRPl
void CPlatformNetworkManagerDurango::HandlePlayerLeaving(DQRNetworkPlayer *pDQRPlayer)
{
//__debugbreak();
app.DebugPrintf( "Player 0x%p leaving.\n",
pDQRPlayer );
+1 -1
View File
@@ -187,7 +187,7 @@ EntityRenderer *EntityRenderDispatcher::getRenderer(eINSTANCEOF e)
{
app.DebugPrintf("Couldn't find renderer for entity of type %d\n", e);
// New renderer mapping required in above table
__debugbreak();
DEBUG_BREAK();
}
/* 4J - not doing this hierarchical search anymore. We need to explicitly add renderers for any eINSTANCEOF type that we want to be able to render
if (it == renderers.end() && e != Entity::_class)
+2 -2
View File
@@ -85,9 +85,9 @@ void EntityTracker::addEntity(shared_ptr<Entity> e, int range, int updateInterva
{
assert(false); // Entity already tracked
}
if( e->entityId >= 2048 )
if( e->entityId >= 16384 )
{
__debugbreak();
DEBUG_BREAK();
}
shared_ptr<TrackedEntity> te = std::make_shared<TrackedEntity>(e, range, updateInterval, trackDeltas);
entities.insert(te);
+4
View File
@@ -404,6 +404,8 @@ void Font::draw(const wstring &str, bool dropShadow, int initialColor)
t->begin();
t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255);
bool prev = t->setMipmapEnable(false); // Disable mipmapping for fonts, and save previous enabled value to be restored later - Botch
for (int i = 0; i < static_cast<int>(cleanStr.length()); ++i)
{
// Map character
@@ -481,6 +483,8 @@ void Font::draw(const wstring &str, bool dropShadow, int initialColor)
}
}
t->setMipmapEnable(prev); //Reinstates previously used enabled value - Botch
t->end();
}
+5 -1
View File
@@ -1558,6 +1558,10 @@ void GameRenderer::renderLevel(float a, int64_t until)
PIXEndNamedEvent();
}
PIXBeginNamedEvent(0,"Beacon beam halo (after water)");
levelRenderer->renderBeaconBeams(a);
PIXEndNamedEvent();
// 4J - added - have split out translucent particle rendering so that it happens after the water is rendered, primarily for fireworks
PIXBeginNamedEvent(0,"Particle render (translucent)");
Lighting::turnOn();
@@ -2112,7 +2116,7 @@ void GameRenderer::setupFog(int i, float alpha)
if (i == 999)
{
__debugbreak();
DEBUG_BREAK();
// 4J TODO
/*
glFog(GL_FOG_COLOR, getBuffer(0, 0, 0, 1));
+87 -16
View File
@@ -697,8 +697,8 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
glEnable(GL_COLOR_MATERIAL);
// 4J - TomK now using safe zone values directly instead of the magic number calculation that lived here before (which only worked for medium scale, the other two were off!)
int xo = iSafezoneXHalf + 10;
int yo = iSafezoneTopYHalf + 10;
int xo = iSafezoneXHalf + 10; // TODO: fix relative scaling for atrocious aspect ratios
int yo = iSafezoneTopYHalf + 10; // TODO: fix relative scaling for atrocious aspect ratios
#ifdef __PSVITA__
// align directly with corners, there are no safe zones on vita
@@ -708,8 +708,29 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
glPushMatrix();
glTranslatef(static_cast<float>(xo), static_cast<float>(yo), 50);
float ss = 12;
glScalef(-ss, ss, ss);
// correct paper doll aspect ratio
float ss = 12.0f;
float aspectScaleX = 1.0f;
float aspectScaleY = 1.0f;
extern int g_rScreenWidth;
extern int g_rScreenHeight;
if (g_rScreenWidth > 0 && g_rScreenHeight > 0) {
float screenAspect = (float)g_rScreenWidth / (float)g_rScreenHeight;
const float targetAspect = 16.0f / 9.0f;
// apply correction if window is not already at a 16:9 aspect ratio
if (fabs(screenAspect - targetAspect) > 0.01f) {
if (screenAspect > targetAspect)
aspectScaleX = targetAspect / screenAspect;
else
aspectScaleY = screenAspect / targetAspect;
}
}
glScalef(-ss * aspectScaleX, ss * aspectScaleY, ss);
glRotatef(180, 0, 0, 1);
float oyr = minecraft->player->yRot;
@@ -1208,7 +1229,20 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
// Disable the depth test so the text shows on top of the paperdoll
glDisable(GL_DEPTH_TEST);
#ifdef _WINDOWS64
float scaleWidth = (g_rScreenWidth / 1920.0f);
float scaleHeight = (g_rScreenHeight / 1080.0f);
float scale = min(scaleWidth, scaleHeight); //stop stretching
if (scale < 0.5f) scale = 0.5f; // force minimum scale
if (scale > 1.2f) // resolutions over 1296 pixels tall
{
scale = scale - 0.33f; // tame overscaling on 1440p
}
glScalef(scale, scale, 1);
#endif
// Loop through the lines and draw them all on screen
int yPos = debugTop;
for (const auto &line : lines)
@@ -1217,6 +1251,9 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
yPos += 10;
}
#ifdef _WINDOWS64
glScalef(1, 1, 1);
#endif
// Restore the depth test
glEnable(GL_DEPTH_TEST);
@@ -1421,6 +1458,37 @@ void Gui::clearMessages(int iPad)
}
}
int getVisibleMessageLength(const wstring& _string) {
int visibleMessageLength = 0;
bool inHtmlTag = false;
for (wchar_t _char : _string) {
if (_char == L'<') inHtmlTag = true;
if (_char == L'>') inHtmlTag = false;
if (!inHtmlTag) visibleMessageLength++;
}
return visibleMessageLength;
}
int getVisibleIndexToRaw(const wstring& _string, size_t target) {
int visibleMessageLength = 0;
bool inHtmlTag = false;
for (size_t i = 0; i < _string.size(); i++) {
if (_string[i] == L'<') inHtmlTag = true;
if (_string[i] == L'>') inHtmlTag = false;
if (!inHtmlTag) {
if (visibleMessageLength == target) return i;
visibleMessageLength++;
}
}
return _string.size();
}
void Gui::addMessage(const wstring& _string,int iPad,bool bIsDeathMessage)
{
@@ -1504,29 +1572,25 @@ void Gui::addMessage(const wstring& _string,int iPad,bool bIsDeathMessage)
break;
}
while (string.length() > maximumChars)
while (getVisibleMessageLength(string) > maximumChars)
{
unsigned int i = 1;
while (i < string.length() && (i + 1) <= maximumChars)
{
i++;
}
size_t iLast=string.find_last_of(L" ",i);
size_t cutOffset = getVisibleIndexToRaw(string, maximumChars);
size_t iLast=string.find_last_of(L" ", cutOffset);
switch(XGetLanguage())
{
case XC_LANGUAGE_JAPANESE:
case XC_LANGUAGE_TCHINESE:
case XC_LANGUAGE_KOREAN:
iLast = maximumChars;
iLast = cutOffset;
break;
default:
iLast=string.find_last_of(L" ",i);
iLast=string.find_last_of(L" ", cutOffset);
break;
}
// if a space was found, include the space on this line
if(iLast!=i)
if(iLast!=cutOffset)
{
iLast++;
}
@@ -1578,6 +1642,13 @@ float Gui::getOpacity(int iPad, DWORD index)
return opacityPercentage;
}
//just like java functionality it overwrites the jukebox label
void Gui::setActionBarMessage(wstring message)
{
overlayMessageString = message;
overlayMessageTime = 20 * 4; //idk how long it should last, need to check java usage
}
float Gui::getJukeboxOpacity(int iPad)
{
float t = overlayMessageTime - lastTickA;
@@ -1593,7 +1664,7 @@ void Gui::setNowPlaying(const wstring& string)
// overlayMessageString = L"Now playing: " + string;
overlayMessageString = app.GetString(IDS_NOWPLAYING) + string;
overlayMessageTime = 20 * 3;
animateOverlayMessageColor = true;
animateOverlayMessageColor = true; //appears to be unused, @DrPerkyLegit plans to add in later pr
}
void Gui::displayClientMessage(int messageId, int iPad)
+3
View File
@@ -17,6 +17,7 @@ private:
static const int m_iMaxMessageWidth = 280;
static ItemRenderer *itemRenderer;
vector<GuiMessage> guiMessages[XUSER_MAX_COUNT];
int chatIndex = 0;
Random *random;
Minecraft *minecraft;
@@ -63,6 +64,8 @@ public:
wstring getMessage(int iPad, DWORD index) { return guiMessages[iPad].at(index).string; }
float getOpacity(int iPad, DWORD index);
void setActionBarMessage(wstring message); //uses jukebox label
wstring getJukeboxMessage(int iPad) { return overlayMessageString; }
float getJukeboxOpacity(int iPad);
+25
View File
@@ -6,6 +6,7 @@
#include "Chunk.h"
#include "EntityRenderDispatcher.h"
#include "TileEntityRenderDispatcher.h"
#include "BeaconRenderer.h"
#include "DistanceChunkSorter.h"
#include "DirtyChunkSorter.h"
#include "MobSkinTextureProcessor.h"
@@ -653,6 +654,30 @@ void LevelRenderer::renderEntities(Vec3 *cam, Culler *culler, float a)
mc->gameRenderer->turnOffLightLayer(a); // 4J - brought forward from 1.8.2
}
void LevelRenderer::renderBeaconBeams(float a)
{
if (mc == nullptr || mc->player == nullptr) return;
int playerIndex = mc->player->GetXboxPad();
if (level[playerIndex] == nullptr) return;
BeaconRenderer::s_renderOuterHalo = true;
EnterCriticalSection(&m_csRenderableTileEntities);
for (auto & it : renderableTileEntities)
{
if (!isGlobalIndexInSameDimension(it.first, level[playerIndex])) continue;
for (auto& te : it.second)
{
if (te->GetType() != eTYPE_BEACONTILEENTITY) continue;
TileEntityRenderDispatcher::instance->render(te, a);
}
}
LeaveCriticalSection(&m_csRenderableTileEntities);
BeaconRenderer::s_renderOuterHalo = false;
}
wstring LevelRenderer::gatherStats1()
{
return L"C: " + std::to_wstring(renderedChunks) + L"/" + std::to_wstring(totalChunks) + L". F: " + std::to_wstring(offscreenChunks) + L", O: " + std::to_wstring(occludedChunks) + L", E: " + std::to_wstring(emptyChunks);
+1
View File
@@ -77,6 +77,7 @@ public:
void AddDLCSkinsToMemTextures();
public:
void renderEntities(Vec3 *cam, Culler *culler, float a);
void renderBeaconBeams(float a);
wstring gatherStats1();
wstring gatherStats2();
private:
+2 -9
View File
@@ -164,14 +164,7 @@ bool LocalPlayer::isEffectiveAi()
void LocalPlayer::aiStep()
{
if (sprintTime > 0)
{
sprintTime--;
if (sprintTime == 0)
{
setSprinting(false);
}
}
if (sprintTime > 0) sprintTime--;
if (sprintTriggerTime > 0) sprintTriggerTime--;
if (minecraft->gameMode->isCutScene())
{
@@ -518,7 +511,7 @@ void LocalPlayer::changeDimension(int i)
//minecraft.setScreen(new WinScreen());
#ifndef _CONTENT_PACKAGE
app.DebugPrintf("LocalPlayer::changeDimension from 1 to 1 but WinScreen has not been implemented.\n");
__debugbreak();
DEBUG_BREAK();
#endif
}
else
+7 -3
View File
@@ -1542,8 +1542,12 @@ void Minecraft::run_middle()
// Utility keys always work regardless of KBM active state
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.GetMenuDisplayed(i))
{
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
if (dynamic_cast<ChatScreen*>(getScreen()) != nullptr) {
setScreen(nullptr);
} else {
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
}
}
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_THIRD_PERSON))
@@ -4808,7 +4812,7 @@ void Minecraft::main()
app.DebugPrintf("<xs:enumeration value=\"%d\"><xs:annotation><xs:documentation>%ls</xs:documentation></xs:annotation></xs:enumeration>\n", i, app.GetString( Tile::tiles[i]->getDescriptionId() ));
}
}
__debugbreak();
DEBUG_BREAK();
#endif
// 4J-PB - Can't call this for the first 5 seconds of a game - MS rule
+180 -13
View File
@@ -85,6 +85,9 @@ vector<INetworkPlayer *> MinecraftServer::s_sentTo;
int MinecraftServer::s_slowQueuePlayerIndex = 0;
int MinecraftServer::s_slowQueueLastTime = 0;
bool MinecraftServer::s_slowQueuePacketSent = false;
#ifdef MINECRAFT_SERVER_BUILD
int MinecraftServer::s_dedicatedChunkSendsThisTick = 0;
#endif
#endif
unordered_map<wstring, int> MinecraftServer::ironTimers;
@@ -1541,6 +1544,12 @@ void MinecraftServer::stopServer(bool didInit)
}
}
}
// connection->stop() enqueued disconnects; the run loop is gone, so
// drain now or DisconnectPacket + sendAndQuit() never fire.
if (players != nullptr)
{
players->drainPendingDisconnects();
}
// reset the primary player signout flag
m_bPrimaryPlayerSignedOut=false;
s_bServerHalted = false;
@@ -1770,6 +1779,12 @@ void MinecraftServer::run(int64_t seed, void *lpParameter)
int64_t unprocessedTime = 0;
while (running && !s_bServerHalted)
{
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
// Full wall-clock cost of one run loop iteration (catch-up ticks
// + setTime handlers + XUI delayed actions + Sleep).
int64_t outerIterStart = getCurrentTimeMillis();
int64_t outerIterTickWork = 0;
#endif
int64_t now = getCurrentTimeMillis();
// 4J Stu - When we pause the server, we don't want to count that as time passed
@@ -1807,14 +1822,39 @@ void MinecraftServer::run(int64_t seed, void *lpParameter)
while (unprocessedTime > MS_PER_TICK)
{
unprocessedTime -= MS_PER_TICK;
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
// Per-iteration pre/tick/post timing.
int64_t iter_t0 = System::currentTimeMillis();
#endif
chunkPacketManagement_PreTick();
// int64_t before = System::currentTimeMillis();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t iter_t1 = System::currentTimeMillis();
#endif
tick();
// int64_t after = System::currentTimeMillis();
// PIXReportCounter(L"Server time",(float)(after-before));
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t iter_t2 = System::currentTimeMillis();
#endif
chunkPacketManagement_PostTick();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t iter_t3 = System::currentTimeMillis();
int64_t iter_total = iter_t3 - iter_t0;
outerIterTickWork += iter_total;
if (iter_total > 200)
{
ServerRuntime::LogInfof("perf",
"iter total=%lldms pre=%lld tick=%lld post=%lld",
(long long)iter_total,
(long long)(iter_t1 - iter_t0),
(long long)(iter_t2 - iter_t1),
(long long)(iter_t3 - iter_t2));
}
#endif
}
// Do NOT reset lastTime here. Resetting discards the wall
// time spent in the catch-up so passedTime restarts from
// post-tick, capping effective TPS at 1000 / (MS_PER_TICK
// + avgTickBody). Runaway after a real freeze is bounded
// by the passedTime > MS_PER_TICK * 40 cap above.
// int64_t afterall = System::currentTimeMillis();
// PIXReportCounter(L"Server time all",(float)(afterall-beforeall));
// PIXReportCounter(L"Server ticks",(float)tickcount);
@@ -2100,6 +2140,73 @@ void MinecraftServer::run(int64_t seed, void *lpParameter)
}
Sleep(1);
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t outerIterTotal = getCurrentTimeMillis() - outerIterStart;
// Distribution histogram (gated). Buckets every outer iter, dumps
// the bucket counts + a self-computed TPS every ~10 seconds.
if (ServerRuntime::g_serverPerfTrace)
{
static const int kBucketCount = 14;
static int64_t s_bucketEdges[kBucketCount] = {
2, 5, 10, 20, 30, 40, 50, 60, 80, 100, 200, 500, 1000, INT64_MAX
};
static unsigned int s_buckets[kBucketCount] = {0};
static int64_t s_histWindowStartMs = 0;
static int s_histWindowStartTick = 0;
static int64_t s_histTotalIterMs = 0;
static unsigned int s_histTotalIters = 0;
static unsigned int s_histTickIters = 0;
int64_t nowMsForHist = getCurrentTimeMillis();
if (s_histWindowStartMs == 0)
{
s_histWindowStartMs = nowMsForHist;
s_histWindowStartTick = (int)tickCount;
}
for (int b = 0; b < kBucketCount; b++)
{
if (outerIterTotal <= s_bucketEdges[b])
{
s_buckets[b]++;
break;
}
}
s_histTotalIterMs += outerIterTotal;
s_histTotalIters++;
if (outerIterTickWork > 0) s_histTickIters++;
int ticksThisWindow = (int)tickCount - s_histWindowStartTick;
if (ticksThisWindow >= 200)
{
int64_t windowMs = nowMsForHist - s_histWindowStartMs;
double calcTps = windowMs > 0 ? (ticksThisWindow * 1000.0) / windowMs : 0.0;
double avgIterMs = s_histTotalIters > 0 ? (double)s_histTotalIterMs / s_histTotalIters : 0.0;
ServerRuntime::LogInfof("perf",
"histogram window: %d ticks in %lldms calcTps=%.2f iters=%u tickIters=%u avgIter=%.2fms | "
"<=2:%u <=5:%u <=10:%u <=20:%u <=30:%u <=40:%u <=50:%u <=60:%u <=80:%u <=100:%u <=200:%u <=500:%u <=1000:%u >1000:%u",
ticksThisWindow, (long long)windowMs, calcTps,
s_histTotalIters, s_histTickIters, avgIterMs,
s_buckets[0], s_buckets[1], s_buckets[2], s_buckets[3],
s_buckets[4], s_buckets[5], s_buckets[6], s_buckets[7],
s_buckets[8], s_buckets[9], s_buckets[10], s_buckets[11],
s_buckets[12], s_buckets[13]);
for (int b = 0; b < kBucketCount; b++) s_buckets[b] = 0;
s_histWindowStartMs = nowMsForHist;
s_histWindowStartTick = (int)tickCount;
s_histTotalIterMs = 0;
s_histTotalIters = 0;
s_histTickIters = 0;
}
}
if (outerIterTotal > 200)
{
ServerRuntime::LogInfof("perf",
"outerIter total=%lldms tickWork=%lld postTickOverhead=%lld",
(long long)outerIterTotal,
(long long)outerIterTickWork,
(long long)(outerIterTotal - outerIterTickWork));
}
#endif
}
}
//else
@@ -2154,6 +2261,17 @@ void MinecraftServer::broadcastStopSavingPacket()
void MinecraftServer::tick()
{
// Per-substep wall-clock timing. Logs one summary line when total tick
// exceeds TICK_SLOW_THRESHOLD_MS.
const int64_t TICK_SLOW_THRESHOLD_MS = 200;
const int kMaxLevelsRecorded = 8;
int64_t tickStart = System::currentTimeMillis();
int64_t lvlTickMs[kMaxLevelsRecorded] = {0};
int64_t lvlEntMs[kMaxLevelsRecorded] = {0};
int64_t lvlTrkMs[kMaxLevelsRecorded] = {0};
int lvlDimId[kMaxLevelsRecorded] = {0};
unsigned int recordedLevels = 0;
vector<wstring> toRemove;
for ( auto& it : ironTimers )
{
@@ -2217,13 +2335,9 @@ void MinecraftServer::tick()
int64_t st2 = System::currentTimeMillis();
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Entity tick %d",i);
// 4J added to stop ticking entities in levels when players are not in those levels.
// Note: now changed so that we also tick if there are entities to be removed, as this also happens as a result of calling tickEntities. If we don't do this, then the
// entities get removed at the first point that there is a player count in the level - this has been causing a problem when going from normal dimension -> nether -> normal,
// as the player is getting flagged as to be removed (from the normal dimension) when going to the nether, but Actually gets removed only when it returns
if( ( players->getPlayerCount(level) > 0) || ( level->hasEntitiesToRemove() ) )
{
#ifdef __PSVITA__
if ((players->getPlayerCount(level) > 0) || level->hasEntitiesToRemove())
{
// AP - the PlayerList->viewDistance initially starts out at 3 to make starting a level speedy
// the problem with this is that spawned monsters are always generated on the edge of the known map
// which means they wont process (unless they are surrounded by 2 visible chunks). This means
@@ -2233,11 +2347,13 @@ void MinecraftServer::tick()
level->getServer()->getPlayers()->setViewDistance(newViewDistance);
level->getTracker()->updateMaxRange();
level->getChunkMap()->setRadius(level->getServer()->getPlayers()->getViewDistance());
#endif
level->tickEntities();
}
#endif
level->tickEntities();
PIXEndNamedEvent();
int64_t stEntDone = System::currentTimeMillis();
PIXBeginNamedEvent(0,"Entity tracker tick");
level->getTracker()->tick();
PIXEndNamedEvent();
@@ -2246,9 +2362,21 @@ void MinecraftServer::tick()
// printf(">>>>>>>>>>>>>>>>>>>>>> Tick %d %d %d : %d\n", st1 - st0, st2 - st1, st3 - st2, st0 - stc );
stc = st0;
// #endif// __PS3__
// Record per-level breakdown for the slow-tick summary.
if (i < kMaxLevelsRecorded)
{
lvlTickMs[i] = st1 - st0; // Level::tick (mob spawner, chunk source, tile ticks, etc.)
lvlEntMs[i] = stEntDone - st2; // tickEntities (per-entity AI/physics)
lvlTrkMs[i] = st3 - stEntDone; // EntityTracker::tick (visibility & broadcasts)
lvlDimId[i] = level->dimension->id;
recordedLevels = i + 1;
}
}
}
int64_t afterLevels = System::currentTimeMillis();
Entity::tickExtraWandering(); // 4J added
int64_t afterExtraW = System::currentTimeMillis();
// Process player disconnect/kick queue BEFORE ticking connections.
// PendingConnection::handleLogin rejects duplicate XUIDs, so the old
@@ -2257,9 +2385,11 @@ void MinecraftServer::tick()
PIXBeginNamedEvent(0,"Players tick");
players->tick();
PIXEndNamedEvent();
int64_t afterPlayers = System::currentTimeMillis();
PIXBeginNamedEvent(0,"Connection tick");
connection->tick();
PIXEndNamedEvent();
int64_t afterConn = System::currentTimeMillis();
// 4J - removed
#if 0
@@ -2273,6 +2403,35 @@ void MinecraftServer::tick()
// } catch (Exception e) {
// logger.log(Level.WARNING, "Unexpected exception while parsing console command", e);
// }
int64_t totalMs = System::currentTimeMillis() - tickStart;
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
if (totalMs > TICK_SLOW_THRESHOLD_MS)
{
// Build a single one-line breakdown so it greps cleanly. Per-level:
// Level::tick / tickEntities / tracker tick. Then global subsystems.
char buf[512];
int n = 0;
for (unsigned int i = 0; i < recordedLevels && n >= 0 && n < (int)sizeof(buf); i++)
{
n += snprintf(buf + n, sizeof(buf) - n,
" L%d:tick=%lld ent=%lld trk=%lld",
lvlDimId[i],
(long long)lvlTickMs[i],
(long long)lvlEntMs[i],
(long long)lvlTrkMs[i]);
}
ServerRuntime::LogInfof("perf",
"slow tick total=%lldms%s | extraW=%lld players=%lld conn=%lld",
(long long)totalMs,
buf,
(long long)(afterExtraW - afterLevels),
(long long)(afterPlayers - afterExtraW),
(long long)(afterConn - afterPlayers));
}
#else
(void)totalMs;
#endif
}
void MinecraftServer::handleConsoleInput(const wstring& msg, ConsoleInputSource *source)
@@ -2416,7 +2575,9 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
if( player == nullptr ) return false;
#ifdef MINECRAFT_SERVER_BUILD
return true;
// Cap chunk-data sends per tick. Other players are served on later ticks
// via the per-tick rotation in ServerConnection::tick.
return s_dedicatedChunkSendsThisTick < DEDICATED_MAX_CHUNK_SENDS_PER_TICK;
#else
int time = GetTickCount();
DWORD currentPlayerCount = g_NetworkManager.GetPlayerCount();
@@ -2435,10 +2596,16 @@ bool MinecraftServer::chunkPacketManagement_CanSendTo(INetworkPlayer *player)
void MinecraftServer::chunkPacketManagement_DidSendTo(INetworkPlayer *player)
{
s_slowQueuePacketSent = true;
#ifdef MINECRAFT_SERVER_BUILD
s_dedicatedChunkSendsThisTick++;
#endif
}
void MinecraftServer::chunkPacketManagement_PreTick()
{
#ifdef MINECRAFT_SERVER_BUILD
s_dedicatedChunkSendsThisTick = 0;
#endif
}
void MinecraftServer::chunkPacketManagement_PostTick()
+6
View File
@@ -258,6 +258,12 @@ private:
static int s_slowQueuePlayerIndex;
static int s_slowQueueLastTime;
static bool s_slowQueuePacketSent;
#ifdef MINECRAFT_SERVER_BUILD
// Cap on chunk-data packet sends per tick. Paired with per-tick rotation
// in ServerConnection::tick so every player gets a turn even when bound.
static int s_dedicatedChunkSendsThisTick;
static const int DEDICATED_MAX_CHUNK_SENDS_PER_TICK = 10;
#endif
#endif
bool IsServerPaused() { return m_isServerPaused; }
+1 -1
View File
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
@@ -245,7 +245,7 @@ bool OrbisLeaderboardManager::getScoreByIds()
{
// 4J-JEV: Something terrible must have happend,
// 'getFriendslist' was supposed to be a synchronous operation.
__debugbreak();
DEBUG_BREAK();
// 4J-JEV: We can at least fall-back to just the players score.
num = 1;
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
+1 -1
View File
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
+1 -1
View File
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
+2 -2
View File
@@ -218,7 +218,7 @@ void Particle::setTex(Textures *textures, Icon *icon)
{
#ifndef _CONTENT_PACKAGE
printf("Invalid call to Particle.setTex, use coordinate methods\n");
__debugbreak();
DEBUG_BREAK();
#endif
//throw new RuntimeException("Invalid call to Particle.setTex, use coordinate methods");
}
@@ -230,7 +230,7 @@ void Particle::setMiscTex(int slotIndex)
{
#ifndef _CONTENT_PACKAGE
printf("Invalid call to Particle.setMixTex\n");
__debugbreak();
DEBUG_BREAK();
//throw new RuntimeException("Invalid call to Particle.setMiscTex");
#endif
}
+66 -4
View File
@@ -13,6 +13,14 @@
#include "../Minecraft.World/System.h"
#include "PlayerList.h"
#include <unordered_set>
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
#include "../Minecraft.Server/ServerLogger.h"
// Per-tick accumulators for tickAddRequests timing.
static int64_t g_findUsAccum = 0;
static int64_t g_addUsAccum = 0;
static int g_addCount = 0;
#endif
PlayerChunkMap::PlayerChunk::PlayerChunk(int x, int z, PlayerChunkMap *pcm) : pos(x,z)
{
@@ -74,7 +82,7 @@ void PlayerChunkMap::PlayerChunk::add(shared_ptr<ServerPlayer> player, bool send
players.push_back(player);
player->chunksToSend.push_back(pos);
player->chunksToSend.insert(pos);
#ifdef _LARGE_WORLDS
parent->getLevel()->cache->dontDrop(pos.x, pos.z); // 4J Added;
@@ -118,7 +126,7 @@ void PlayerChunkMap::PlayerChunk::remove(shared_ptr<ServerPlayer> player)
parent->getLevel()->cache->drop(pos.x, pos.z);
}
player->chunksToSend.remove(pos);
player->chunksToSend.erase(pos);
// 4J - I don't think there's any point sending these anymore, as we don't need to unload chunks with fixed sized maps
// 4J - We do need to send these to unload entities in chunks when players are dead. If we do not and the entity is removed
// while they are dead, that entity will remain in the clients world
@@ -369,6 +377,15 @@ ServerLevel *PlayerChunkMap::getLevel()
void PlayerChunkMap::tick()
{
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
// Substep timing for slow chunkMap diagnostics.
const int64_t CHUNKMAP_SLOW_THRESHOLD_MS = 150;
int64_t cm_t0 = System::currentTimeMillis();
int cm_addReqStart = (int)addRequests.size();
g_findUsAccum = 0;
g_addUsAccum = 0;
g_addCount = 0;
#endif
int64_t time = level->getGameTime();
if (time - lastInhabitedUpdate > Level::TICKS_PER_DAY / 3)
@@ -385,6 +402,9 @@ void PlayerChunkMap::tick()
chunk->updateInhabitedTime();
}
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t cm_t1 = System::currentTimeMillis();
#endif
// 4J - some changes here so that we only send one region update per tick. The chunks themselves also
// limit their resend rate to once every MIN_TICKS_BETWEEN_REGION_UPDATE ticks
@@ -404,11 +424,35 @@ void PlayerChunkMap::tick()
i++;
}
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t cm_t2 = System::currentTimeMillis();
#endif
for( unsigned int i = 0; i < players.size(); i++ )
{
tickAddRequests(players[i]);
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t cm_t3 = System::currentTimeMillis();
int64_t cm_total = cm_t3 - cm_t0;
if (cm_total > CHUNKMAP_SLOW_THRESHOLD_MS)
{
ServerRuntime::LogInfof("perf",
"L%d chunkMap total=%lldms inhabited=%lld changed=%lld addReq=%lld | players=%d addReqQueue=%d->%d | adds=%d findUs=%lld addUs=%lld avgAddUs=%lld",
this->dimension,
(long long)cm_total,
(long long)(cm_t1 - cm_t0),
(long long)(cm_t2 - cm_t1),
(long long)(cm_t3 - cm_t2),
(int)players.size(),
cm_addReqStart,
(int)addRequests.size(),
g_addCount,
(long long)g_findUsAccum,
(long long)g_addUsAccum,
g_addCount > 0 ? (long long)(g_addUsAccum / g_addCount) : 0LL);
}
#endif
// 4J Stu - Added 1.1 but not relevant to us as we never no 0 players anyway, and don't think we should be dropping stuff
//if (players.isEmpty()) {
@@ -490,7 +534,11 @@ void PlayerChunkMap::getChunkAndRemovePlayer(int x, int z, shared_ptr<ServerPlay
// Processes up to CHUNKS_PER_PLAYER_PER_TICK requests per call to speed up initial chunk loading.
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
static const int CHUNKS_PER_PLAYER_PER_TICK = 16;
// Per-player drain rate for the addRequest queue. Each PlayerChunk::add
// issues a synchronous ChunkVisibilityPacket, so per-tick send volume
// scales as players * this. Pair with DEDICATED_MAX_CHUNK_SENDS_PER_TICK
// on the chunk-data side.
static const int CHUNKS_PER_PLAYER_PER_TICK = 4;
#else
static const int CHUNKS_PER_PLAYER_PER_TICK = 1;
#endif
@@ -504,6 +552,11 @@ void PlayerChunkMap::tickAddRequests(shared_ptr<ServerPlayer> player)
for (int processed = 0; processed < CHUNKS_PER_PLAYER_PER_TICK; processed++)
{
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
LARGE_INTEGER qpcFreq, qpcA, qpcB, qpcC;
QueryPerformanceFrequency(&qpcFreq);
QueryPerformanceCounter(&qpcA);
#endif
// Find the nearest chunk request to the player
int minDistSq = -1;
auto itNearest = addRequests.end();
@@ -522,12 +575,21 @@ void PlayerChunkMap::tickAddRequests(shared_ptr<ServerPlayer> player)
}
}
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
QueryPerformanceCounter(&qpcB);
g_findUsAccum += (qpcB.QuadPart - qpcA.QuadPart) * 1000000 / qpcFreq.QuadPart;
#endif
// If we found one, process it and continue; otherwise done
if( itNearest != addRequests.end() )
{
getChunk(itNearest->x, itNearest->z, true)->add(itNearest->player);
addRequests.erase(itNearest);
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
QueryPerformanceCounter(&qpcC);
g_addUsAccum += (qpcC.QuadPart - qpcB.QuadPart) * 1000000 / qpcFreq.QuadPart;
g_addCount++;
#endif
}
else
{
@@ -781,7 +843,7 @@ bool PlayerChunkMap::isPlayerIn(shared_ptr<ServerPlayer> player, int xChunk, int
else
{
auto it1 = find(chunk->players.begin(), chunk->players.end(), player);
auto it2 = find(player->chunksToSend.begin(), player->chunksToSend.end(), chunk->pos);
auto it2 = player->chunksToSend.find(chunk->pos);
return it1 != chunk->players.end() && it2 == player->chunksToSend.end();
}
+44 -39
View File
@@ -121,6 +121,45 @@ void PlayerList::queueDisconnect(shared_ptr<ServerPlayer> player, int reason, co
LeaveCriticalSection(&m_disconnectCS);
}
void PlayerList::drainPendingDisconnects()
{
std::deque<PendingDisconnect> dcCopy;
EnterCriticalSection(&m_disconnectCS);
dcCopy.swap(m_pendingDisconnects);
LeaveCriticalSection(&m_disconnectCS);
while (!dcCopy.empty())
{
PendingDisconnect pd = dcCopy.front();
dcCopy.pop_front();
server->getPlayers()->removePlayerFromReceiving(pd.player);
if (pd.player->connection != nullptr)
{
pd.player->connection->send(std::make_shared<DisconnectPacket>(static_cast<DisconnectPacket::eDisconnectReason>(pd.reason)));
pd.player->connection->connection->sendAndQuit();
}
if (!pd.kickMessage.empty())
{
broadcastAll(std::make_shared<ChatPacket>(pd.kickMessage));
}
else if (!pd.fourKitHandledQuit)
{
if (pd.wasKicked)
{
broadcastAll(std::make_shared<ChatPacket>(pd.player->name, ChatPacket::e_ChatPlayerKickedFromGame));
}
else
{
broadcastAll(std::make_shared<ChatPacket>(pd.player->name, ChatPacket::e_ChatPlayerLeftGame));
}
}
remove(pd.player);
}
}
bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer> player, shared_ptr<LoginPacket> packet)
{
CompoundTag *playerTag = load(player);
@@ -327,7 +366,9 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
// 4J-PB - removed, since it needs to be localised in the language the client is in
//server->players->broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(L"e" + playerEntity->name + L" joined the game.") ) );
#if !(defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD))
broadcastAll(std::make_shared<ChatPacket>(player->name, ChatPacket::e_ChatPlayerJoinedGame));
#endif
MemSect(14);
add(player);
@@ -872,7 +913,7 @@ shared_ptr<ServerPlayer> PlayerList::respawn(shared_ptr<ServerPlayer> serverPlay
// necessary)
updatePlayerGameMode(player, serverPlayer, level);
// 4J Added: Hardcore mode force Adventure mode on respawn
// 4J Added: Hardcore mode forces Adventure mode on respawn
if (server->getLevel(0)->getLevelData()->isHardcore())
{
player->gameMode->setGameModeForPlayer(GameType::ADVENTURE);
@@ -1298,43 +1339,7 @@ void PlayerList::tick()
// Drain the pending disconnect queue. disconnect() enqueues here so it
// can release done_cs before the heavy cleanup runs on the tick thread.
{
std::deque<PendingDisconnect> dcCopy;
EnterCriticalSection(&m_disconnectCS);
dcCopy.swap(m_pendingDisconnects);
LeaveCriticalSection(&m_disconnectCS);
while (!dcCopy.empty())
{
PendingDisconnect pd = dcCopy.front();
dcCopy.pop_front();
server->getPlayers()->removePlayerFromReceiving(pd.player);
if (pd.player->connection != nullptr)
{
pd.player->connection->send(std::make_shared<DisconnectPacket>(static_cast<DisconnectPacket::eDisconnectReason>(pd.reason)));
pd.player->connection->connection->sendAndQuit();
}
if (!pd.kickMessage.empty())
{
broadcastAll(std::make_shared<ChatPacket>(pd.kickMessage));
}
else if (!pd.fourKitHandledQuit)
{
if (pd.wasKicked)
{
broadcastAll(std::make_shared<ChatPacket>(pd.player->name, ChatPacket::e_ChatPlayerKickedFromGame));
}
else
{
broadcastAll(std::make_shared<ChatPacket>(pd.player->name, ChatPacket::e_ChatPlayerLeftGame));
}
}
remove(pd.player);
}
}
drainPendingDisconnects();
// Drain the close queue: snapshot the deque, then release the CS before
// calling disconnect() which may itself try to acquire other locks.
@@ -1370,7 +1375,7 @@ void PlayerList::tick()
#ifdef _WINDOWS64
// The old Connection's read/write threads are now dead (disconnect waits
// for them). Safe to recycle the smallId no stale write thread can
// for them). Safe to recycle the smallId: no stale write thread can
// resolve getPlayer() to a new connection that reuses this slot.
WinsockNetLayer::PushFreeSmallId(smallId);
WinsockNetLayer::ClearSocketForSmallId(smallId);
+1
View File
@@ -98,6 +98,7 @@ public:
void move(shared_ptr<ServerPlayer> player);
void remove(shared_ptr<ServerPlayer> player);
void queueDisconnect(shared_ptr<ServerPlayer> player, int reason, const wstring& kickMessage, bool wasKicked, bool fourKitHandledQuit);
void drainPendingDisconnects();
shared_ptr<ServerPlayer> getPlayerForLogin(PendingConnection *pendingConnection, const wstring& userName, PlayerUID xuid, PlayerUID OnlineXuid);
shared_ptr<ServerPlayer> respawn(shared_ptr<ServerPlayer> serverPlayer, int targetDimension, bool keepAllPlayerData);
void toggleDimension(shared_ptr<ServerPlayer> player, int targetDimension);
+1 -1
View File
@@ -618,4 +618,4 @@ ResourceLocation *PlayerRenderer::getTextureLocation(shared_ptr<Entity> entity)
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(entity);
return new ResourceLocation(static_cast<_TEXTURE_NAME>(player->getTexture()));
}
}
+3 -4
View File
@@ -227,7 +227,6 @@ void PreStitchedTextureMap::makeTextureAnimated(TexturePack *texturePack, Stitch
if(first->getWidth() != tex->getWidth() || first->getHeight() != tex->getHeight())
{
app.DebugPrintf("%ls - first w - %d, h - %d, tex w - %d, h - %d\n",textureFileName.c_str(),first->getWidth(),tex->getWidth(),first->getHeight(),tex->getHeight());
//__debugbreak();
}
#endif
@@ -246,7 +245,7 @@ StitchedTexture *PreStitchedTextureMap::getTexture(const wstring &name)
{
#ifndef _CONTENT_PACKAGE
app.DebugPrintf("Not implemented!\n");
__debugbreak();
DEBUG_BREAK();
#endif
return nullptr;
#if 0
@@ -277,7 +276,7 @@ Icon *PreStitchedTextureMap::registerIcon(const wstring &name)
{
app.DebugPrintf("Don't register nullptr\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
result = missingPosition;
//new RuntimeException("Don't register null!").printStackTrace();
@@ -290,7 +289,7 @@ Icon *PreStitchedTextureMap::registerIcon(const wstring &name)
{
#ifndef _CONTENT_PACKAGE
app.DebugPrintf("Could not find uv data for icon %ls\n", name.c_str() );
__debugbreak();
DEBUG_BREAK();
#endif
result = missingPosition;
}
+1 -1
View File
@@ -161,7 +161,7 @@ void Screen::updateEvents()
static bool s_arrowFirstRepeat[2] = { false, false };
const DWORD ARROW_REPEAT_DELAY_MS = 250;
const DWORD ARROW_REPEAT_INTERVAL_MS = 50;
DWORD now = GetTickCount();
DWORD now = GetTickCount64();
// Poll keyboard events (special keys that may not come through WM_CHAR, e.g. Escape, arrows)
for (int vk = 0; vk < 256; vk++)
+53 -4
View File
@@ -12,6 +12,9 @@
#include "../Minecraft.World/compression.h"
#include "../Minecraft.World/OldChunkStorage.h"
#include "../Minecraft.World/Tile.h"
#ifdef MINECRAFT_SERVER_BUILD
#include "../Minecraft.Server/FourKitBridge.h"
#endif
ServerChunkCache::ServerChunkCache(ServerLevel *level, ChunkStorage *storage, ChunkSource *source)
{
@@ -125,7 +128,10 @@ LevelChunk *ServerChunkCache::create(int x, int z, bool asyncPostProcess) // 4J
{
EnterCriticalSection(&m_csLoadCreate);
chunk = load(x, z);
if (chunk == nullptr)
#ifdef MINECRAFT_SERVER_BUILD
bool isNewChunk = (chunk == nullptr);
#endif
if (chunk == nullptr)
{
if (source == nullptr)
{
@@ -204,6 +210,10 @@ LevelChunk *ServerChunkCache::create(int x, int z, bool asyncPostProcess) // 4J
if( hasChunk( x - 1, z ) && hasChunk( x + 1, z ) && hasChunk ( x, z - 1 ) && hasChunk( x, z + 1 ) ) chunk->checkChests( this, x, z );
LeaveCriticalSection(&m_csLoadCreate);
#ifdef MINECRAFT_SERVER_BUILD
FourKitBridge::FireChunkLoad(level->dimension->id, x, z, isNewChunk);
#endif
}
else
{
@@ -351,6 +361,38 @@ void ServerChunkCache::overwriteHellLevelChunkFromSource(int x, int z, int minVa
#endif
#ifdef MINECRAFT_SERVER_BUILD
void ServerChunkCache::regenerateChunk(int x, int z)
{
if (!source)
return;
LevelChunk *freshChunk = source->getChunk(x, z);
if (!freshChunk)
return;
LevelChunk *cachedChunk = nullptr;
if (hasChunk(x, z))
cachedChunk = getChunk(x, z);
if (cachedChunk && cachedChunk != emptyChunk)
{
for (int lx = 0; lx < 16; lx++)
for (int ly = 0; ly < 128; ly++)
for (int lz = 0; lz < 16; lz++)
cachedChunk->setTileAndData(lx, ly, lz, freshChunk->getTile(lx, ly, lz), freshChunk->getData(lx, ly, lz));
save(cachedChunk);
}
else
{
save(freshChunk);
}
freshChunk->unload(false);
delete freshChunk;
}
#endif
// 4J Added //
#ifdef _LARGE_WORLDS
void ServerChunkCache::dontDrop(int x, int z)
@@ -914,15 +956,19 @@ bool ServerChunkCache::tick()
// player's tick is called to remove them from the chunk they used to be in, and add them to their current chunk. This will only be a temporary state and
// we should be able to unload the chunk on the next call to this tick.
if( !chunk->containsPlayer() )
{
{
#ifdef MINECRAFT_SERVER_BUILD
if (!FourKitBridge::FireChunkUnload(level->dimension->id, chunk->x, chunk->z))
{
#endif
save(chunk);
saveEntities(chunk);
chunk->unload(true);
//loadedChunks.remove(cp);
//loadedChunkList.remove(chunk);
auto it = std::find(m_loadedChunkList.begin(), m_loadedChunkList.end(), chunk);
if(it != m_loadedChunkList.end()) m_loadedChunkList.erase(it);
auto it = std::find(m_loadedChunkList.begin(), m_loadedChunkList.end(), chunk);
if(it != m_loadedChunkList.end()) m_loadedChunkList.erase(it);
int ix = chunk->x + XZOFFSET;
int iz = chunk->z + XZOFFSET;
@@ -930,6 +976,9 @@ bool ServerChunkCache::tick()
delete m_unloadedCache[idx];
m_unloadedCache[idx] = chunk;
cache[idx] = nullptr;
#ifdef MINECRAFT_SERVER_BUILD
}
#endif
}
else
{
+3
View File
@@ -53,6 +53,9 @@ public:
#endif
virtual LevelChunk **getCache() { return cache; } // 4J added
#ifdef MINECRAFT_SERVER_BUILD
void regenerateChunk(int x, int z);
#endif
// 4J-JEV Added; Remove chunk from the toDrop queue.
#ifdef _LARGE_WORLDS
+53 -1
View File
@@ -13,6 +13,8 @@
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
#include "../Minecraft.Server/Security/SecurityConfig.h"
#include "../Minecraft.Server/ServerLogManager.h"
#include "../Minecraft.Server/ServerLogger.h"
#include "../Minecraft.World/System.h"
#endif
ServerConnection::ServerConnection(MinecraftServer *server)
@@ -129,16 +131,45 @@ void ServerConnection::tick()
vector< shared_ptr<PlayerConnection> > tempPlayers = players;
LeaveCriticalSection(&players_cs);
for (unsigned int i = 0; i < tempPlayers.size(); i++)
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
// Substep timing for chunk / tick / flush across all players.
LARGE_INTEGER scFreq, scA, scB, scC, scD;
QueryPerformanceFrequency(&scFreq);
int64_t sc_chunkUs = 0;
int64_t sc_tickUs = 0;
int64_t sc_flushUs = 0;
int64_t sc_loopT0 = System::currentTimeMillis();
#endif
// Rotate the per-tick start offset so the chunk-send cap doesn't
// starve players at the back of the vector.
static unsigned int s_chunkRotationOffset = 0;
s_chunkRotationOffset++;
size_t playerCount = tempPlayers.size();
size_t startIdx = playerCount > 0 ? (s_chunkRotationOffset % playerCount) : 0;
for (unsigned int k = 0; k < tempPlayers.size(); k++)
{
unsigned int i = (unsigned int)((startIdx + k) % playerCount);
shared_ptr<PlayerConnection> player = tempPlayers[i];
shared_ptr<ServerPlayer> serverPlayer = player->getPlayer();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
QueryPerformanceCounter(&scA);
#endif
if( serverPlayer )
{
serverPlayer->updateFrameTick();
serverPlayer->doChunkSendingTick(false);
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
QueryPerformanceCounter(&scB);
sc_chunkUs += (scB.QuadPart - scA.QuadPart) * 1000000 / scFreq.QuadPart;
#endif
player->tick();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
QueryPerformanceCounter(&scC);
sc_tickUs += (scC.QuadPart - scB.QuadPart) * 1000000 / scFreq.QuadPart;
#endif
if (player->done)
{
EnterCriticalSection(&players_cs);
@@ -150,7 +181,28 @@ void ServerConnection::tick()
{
player->connection->flush();
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
QueryPerformanceCounter(&scD);
sc_flushUs += (scD.QuadPart - scC.QuadPart) * 1000000 / scFreq.QuadPart;
#endif
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
int64_t sc_loopTotal = System::currentTimeMillis() - sc_loopT0;
if (sc_loopTotal > 150)
{
ServerRuntime::LogInfof("perf",
"conn playerLoop total=%lldms players=%d chunkUs=%lld tickUs=%lld flushUs=%lld | avg chunk=%lld tick=%lld flush=%lld",
(long long)sc_loopTotal,
(int)tempPlayers.size(),
(long long)sc_chunkUs,
(long long)sc_tickUs,
(long long)sc_flushUs,
tempPlayers.size() > 0 ? (long long)(sc_chunkUs / tempPlayers.size()) : 0LL,
tempPlayers.size() > 0 ? (long long)(sc_tickUs / tempPlayers.size()) : 0LL,
tempPlayers.size() > 0 ? (long long)(sc_flushUs / tempPlayers.size()) : 0LL);
}
#endif
}
}
+65
View File
@@ -41,6 +41,7 @@
#include "PlayerChunkMap.h"
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
#include "../Minecraft.Server/FourKitBridge.h"
#include "../Minecraft.Server/ServerLogger.h"
#endif
WeighedTreasureArray ServerLevel::RANDOM_BONUS_ITEMS;
@@ -197,6 +198,14 @@ ServerLevel::~ServerLevel()
void ServerLevel::tick()
{
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
// ts[N] = wall-clock at substep N. Logged when level total exceeds
// LEVEL_SLOW_THRESHOLD_MS to pinpoint the dominant substep.
const int64_t LEVEL_SLOW_THRESHOLD_MS = 150;
int64_t ts[13];
ts[0] = System::currentTimeMillis();
#endif
Level::tick();
if (getLevelData()->isHardcore() && difficulty < 3)
{
@@ -218,6 +227,9 @@ void ServerLevel::tick()
}
awakenAllPlayers();
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[1] = System::currentTimeMillis();
#endif
PIXBeginNamedEvent(0,"Mob spawner tick");
// for Minecraft 1.8, spawn friendlies really rarely - 4J - altered from once every 400 ticks to 40 ticks as we depend on this a more than the original since we don't have chunk post-process spawning
@@ -233,6 +245,9 @@ void ServerLevel::tick()
mobSpawner->tick(this, finalSpawnEnemies, finalSpawnFriendlies, finalSpawnPersistent);
}
PIXEndNamedEvent();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[2] = System::currentTimeMillis();
#endif
PIXBeginNamedEvent(0,"Chunk source tick");
chunkSource->tick();
PIXEndNamedEvent();
@@ -248,6 +263,9 @@ void ServerLevel::tick()
}
}
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[3] = System::currentTimeMillis();
#endif
//4J - temporarily disabling saves as they are causing gameplay to generally stutter quite a lot
@@ -263,6 +281,9 @@ void ServerLevel::tick()
save(false, nullptr);
PIXEndNamedEvent();
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[4] = System::currentTimeMillis();
#endif
// 4J : WESTY : Changed so that time update goes through stats tracking update code.
//levelData->setTime(time);
@@ -278,19 +299,31 @@ void ServerLevel::tick()
setDayTime(levelData->getDayTime() + 1);
}
}
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[5] = System::currentTimeMillis();
#endif
PIXBeginNamedEvent(0,"Tick pending ticks");
// if (tickCount % 5 == 0) {
tickPendingTicks(false);
PIXEndNamedEvent();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[6] = System::currentTimeMillis();
#endif
PIXBeginNamedEvent(0,"Tick tiles");
MemSect(18);
tickTiles();
MemSect(0);
PIXEndNamedEvent();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[7] = System::currentTimeMillis();
#endif
chunkMap->tick();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[8] = System::currentTimeMillis();
#endif
PIXBeginNamedEvent(0,"Tick villages");
//MemSect(18);
@@ -298,18 +331,50 @@ void ServerLevel::tick()
villageSiege->tick();
//MemSect(0);
PIXEndNamedEvent();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[9] = System::currentTimeMillis();
#endif
PIXBeginNamedEvent(0,"Tick portal forcer");
portalForcer->tick(getGameTime());
PIXEndNamedEvent();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[10] = System::currentTimeMillis();
#endif
// repeat after tile ticks
PIXBeginNamedEvent(0,"runTileEvents");
runTileEvents();
PIXEndNamedEvent();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[11] = System::currentTimeMillis();
#endif
// 4J Added
runQueuedSendTileUpdates();
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
ts[12] = System::currentTimeMillis();
int64_t levelTotal = ts[12] - ts[0];
if (levelTotal > LEVEL_SLOW_THRESHOLD_MS)
{
ServerRuntime::LogInfof("perf",
"L%d substep total=%lldms base=%lld spawn=%lld chunkSrc=%lld save=%lld time=%lld pending=%lld tiles=%lld chunkMap=%lld villages=%lld portal=%lld evt=%lld sendTU=%lld",
dimension->id,
(long long)levelTotal,
(long long)(ts[1] - ts[0]),
(long long)(ts[2] - ts[1]),
(long long)(ts[3] - ts[2]),
(long long)(ts[4] - ts[3]),
(long long)(ts[5] - ts[4]),
(long long)(ts[6] - ts[5]),
(long long)(ts[7] - ts[6]),
(long long)(ts[8] - ts[7]),
(long long)(ts[9] - ts[8]),
(long long)(ts[10] - ts[9]),
(long long)(ts[11] - ts[10]),
(long long)(ts[12] - ts[11]));
}
#endif
}
Biome::MobSpawnerData *ServerLevel::getRandomMobSpawnAt(MobCategory *mobCategory, int x, int y, int z)
+79 -15
View File
@@ -8,6 +8,9 @@
#include "Settings.h"
#include "PlayerList.h"
#include "MultiPlayerLevel.h"
#include "Minecraft.h"
#include "Common/Audio/SoundEngine.h"
#include "../Minecraft.World/SoundTypes.h"
#include "../Minecraft.World/net.minecraft.network.packet.h"
#include "../Minecraft.World/net.minecraft.world.damagesource.h"
@@ -295,12 +298,12 @@ void ServerPlayer::flagEntitiesToBeRemoved(unsigned int *flags, bool *removedFou
{
*removedFound = true;
// before this left 192 bytes uninitialized!!!!!
memset(flags, 0, (2048 / 32) * sizeof(unsigned int));
memset(flags, 0, (16384 / 32) * sizeof(unsigned int));
}
for(int index : entitiesToRemove)
{
if( index < 2048 )
if( index < 16384 )
{
unsigned int i = index / 32;
unsigned int j = index % 32;
@@ -474,28 +477,82 @@ void ServerPlayer::doTickA()
}
// 4J - split off the chunk sending bit of the tick here from ::doTick so we can do this exactly once per player per server tick
//
// Find-nearest uses spiral iteration from the player's chunk position with
// O(1) hash lookups against chunksToSend. A bounded fallback walk covers
// the rare case of a stale entry outside the spiral radius.
void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
{
// printf("[%d] %s: sendChunks: %d, empty: %d\n",tickCount, connection->getNetworkPlayer()->GetUID().getOnlineID(),sendChunks,chunksToSend.empty());
if (!chunksToSend.empty())
{
ChunkPos nearest = chunksToSend.front();
ChunkPos nearest(0, 0);
bool nearestValid = false;
// 4J - reinstated and optimised some code that was commented out in the original, to make sure that we always
// send the nearest chunk to the player. The original uses the bukkit sorting thing to try and avoid doing this, but
// the player can quickly wander away from the centre of the spiral of chunks that that method creates, long before transmission
// of them is complete.
double dist = DBL_MAX;
for(ChunkPos chunk : chunksToSend)
const int px = (int)floor(x) >> 4;
const int pz = (int)floor(z) >> 4;
// Bound on spiral radius. Configured view distance is much smaller.
const int kMaxSpiralRadius = 32;
// Inline distance: ChunkPos::distanceToSqr is non-const so it can't
// be called on the const refs we get when iterating an unordered_set.
auto chunkDistSq = [&](int cx, int cz) -> double {
double xPos = cx * 16.0 + 8.0;
double zPos = cz * 16.0 + 8.0;
double xd = xPos - this->x;
double zd = zPos - this->z;
return xd * xd + zd * zd;
};
// Ring r=0: the player's own chunk.
{
if( level->isChunkFinalised(chunk.x, chunk.z) )
ChunkPos cp(px, pz);
auto it = chunksToSend.find(cp);
if (it != chunksToSend.end() && level->isChunkFinalised(cp.x, cp.z))
{
double newDist = chunk.distanceToSqr(x, z);
if ( (!nearestValid) || (newDist < dist) )
nearest = cp;
dist = chunkDistSq(cp.x, cp.z);
nearestValid = true;
}
}
// Rings r>=1: Chebyshev perimeter. First ring with a match wins;
// within it pick the closest by true Euclidean distance.
for (int r = 1; r <= kMaxSpiralRadius && !nearestValid; r++)
{
for (int dx = -r; dx <= r; dx++)
{
for (int dz = -r; dz <= r; dz++)
{
nearest = chunk;
dist = chunk.distanceToSqr(x, z);
int adx = dx < 0 ? -dx : dx;
int adz = dz < 0 ? -dz : dz;
if ((adx > adz ? adx : adz) != r) continue; // perimeter only
ChunkPos cp(px + dx, pz + dz);
if (chunksToSend.find(cp) == chunksToSend.end()) continue;
if (!level->isChunkFinalised(cp.x, cp.z)) continue;
double d = chunkDistSq(cp.x, cp.z);
if (!nearestValid || d < dist)
{
nearest = cp;
dist = d;
nearestValid = true;
}
}
}
}
// Fallback for chunks outside the spiral radius (rare).
if (!nearestValid)
{
for (const ChunkPos& cp : chunksToSend)
{
if (!level->isChunkFinalised(cp.x, cp.z)) continue;
double d = chunkDistSq(cp.x, cp.z);
if (!nearestValid || d < dist)
{
nearest = cp;
dist = d;
nearestValid = true;
}
}
@@ -564,7 +621,7 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
{
ServerLevel *level = server->getLevel(dimension);
int flagIndex = getFlagIndexForChunk(nearest,this->level->dimension->id);
chunksToSend.remove(nearest);
chunksToSend.erase(nearest);
bool chunkDataSent = false;
@@ -1035,6 +1092,13 @@ void ServerPlayer::changeDimension(int i)
// 4J: Removed on the advice of the mighty King of Achievments (JV)
// awardStat(GenericStats::portal(), GenericStats::param_portal());
}
// play the travel whoosh right before the actual dimension swap
Minecraft *mc = Minecraft::GetInstance();
if (mc != nullptr && mc->soundEngine != nullptr)
{
mc->soundEngine->playUI(eSoundType_PORTAL_TRAVEL, 1, 1.0f);
}
server->getPlayers()->toggleDimension( dynamic_pointer_cast<ServerPlayer>(shared_from_this()), i);
#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD)
if (portalDestModified)
+3 -1
View File
@@ -25,7 +25,9 @@ public:
MinecraftServer *server;
ServerPlayerGameMode *gameMode;
double lastMoveX, lastMoveZ;
list<ChunkPos> chunksToSend;
// Hash set for O(1) membership/erase. Find-nearest is done via
// spiral iteration in ServerPlayer::doChunkSendingTick, not a sweep.
unordered_set<ChunkPos, ChunkPosKeyHash, ChunkPosKeyEq> chunksToSend;
vector<int> entitiesToRemove;
unordered_set<ChunkPos, ChunkPosKeyHash, ChunkPosKeyEq> seenChunks;
int spewTimer;
+1 -1
View File
@@ -87,7 +87,7 @@ void Stitcher::stitch()
{
app.DebugPrintf("Stitcher exception!\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
//throw new StitcherException(textureHolder);
}
+2 -2
View File
@@ -144,7 +144,7 @@ LPCWSTR StringTable::getString(const wstring &id)
#ifndef _CONTENT_PACKAGE
if (isStatic)
{
__debugbreak();
DEBUG_BREAK();
return L"";
}
#endif
@@ -166,7 +166,7 @@ LPCWSTR StringTable::getString(int id)
#ifndef _CONTENT_PACKAGE
if (!isStatic)
{
__debugbreak();
DEBUG_BREAK();
return L"";
}
#endif
+1 -1
View File
@@ -214,7 +214,7 @@ Icon *TextureMap::registerIcon(const wstring &name)
{
app.DebugPrintf("Don't register nullptr\n");
#ifndef _CONTENT_PACKAGE
__debugbreak();
DEBUG_BREAK();
#endif
//new RuntimeException("Don't register null!").printStackTrace();
}
@@ -339,7 +339,6 @@ bool TexturePackRepository::selectTexturePackById(DWORD id)
app.DebugPrintf("Failed to select texture pack %d as it is not in the list\n", id);
#ifndef _CONTENT_PACKAGE
// TODO - 4J Stu: We should report this to the player in some way
//__debugbreak();
#endif
// Fail safely
if( selectSkin( DEFAULT_TEXTURE_PACK ) )
@@ -1,137 +0,0 @@
#pragma once
#define MAP_STYLE_0 0
#define MAP_STYLE_1 1
#define MAP_STYLE_2 2
#define _360_JOY_BUTTON_A 0x00000001
#define _360_JOY_BUTTON_B 0x00000002
#define _360_JOY_BUTTON_X 0x00000004
#define _360_JOY_BUTTON_Y 0x00000008
#define _360_JOY_BUTTON_START 0x00000010
#define _360_JOY_BUTTON_BACK 0x00000020
#define _360_JOY_BUTTON_RB 0x00000040
#define _360_JOY_BUTTON_LB 0x00000080
#define _360_JOY_BUTTON_RTHUMB 0x00000100
#define _360_JOY_BUTTON_LTHUMB 0x00000200
#define _360_JOY_BUTTON_DPAD_UP 0x00000400
#define _360_JOY_BUTTON_DPAD_DOWN 0x00000800
#define _360_JOY_BUTTON_DPAD_LEFT 0x00001000
#define _360_JOY_BUTTON_DPAD_RIGHT 0x00002000
// fake digital versions of analog values
#define _360_JOY_BUTTON_LSTICK_RIGHT 0x00004000
#define _360_JOY_BUTTON_LSTICK_LEFT 0x00008000
#define _360_JOY_BUTTON_RSTICK_DOWN 0x00010000
#define _360_JOY_BUTTON_RSTICK_UP 0x00020000
#define _360_JOY_BUTTON_RSTICK_RIGHT 0x00040000
#define _360_JOY_BUTTON_RSTICK_LEFT 0x00080000
#define _360_JOY_BUTTON_LSTICK_DOWN 0x00100000
#define _360_JOY_BUTTON_LSTICK_UP 0x00200000
#define _360_JOY_BUTTON_RT 0x00400000
#define _360_JOY_BUTTON_LT 0x00800000
// Stick axis maps - to allow changes for SouthPaw in-game axis mapping
#define AXIS_MAP_LX 0
#define AXIS_MAP_LY 1
#define AXIS_MAP_RX 2
#define AXIS_MAP_RY 3
// Trigger map - to allow for swap triggers in-game
#define TRIGGER_MAP_0 0
#define TRIGGER_MAP_1 1
enum EKeyboardResult
{
EKeyboard_Pending,
EKeyboard_Cancelled,
EKeyboard_ResultAccept,
EKeyboard_ResultDecline,
};
typedef struct _STRING_VERIFY_RESPONSE
{
WORD wNumStrings;
HRESULT *pStringResult;
}
STRING_VERIFY_RESPONSE;
class C_4JInput
{
public:
enum EKeyboardMode
{
EKeyboardMode_Default,
EKeyboardMode_Numeric,
EKeyboardMode_Password,
EKeyboardMode_Alphabet,
EKeyboardMode_Full,
EKeyboardMode_Alphabet_Extended,
EKeyboardMode_IP_Address,
EKeyboardMode_Phone
};
void Initialise( int iInputStateC, unsigned char ucMapC,unsigned char ucActionC, unsigned char ucMenuActionC );
void Tick(void);
void SetDeadzoneAndMovementRange(unsigned int uiDeadzone, unsigned int uiMovementRangeMax );
void SetGameJoypadMaps(unsigned char ucMap,unsigned char ucAction,unsigned int uiActionVal);
unsigned int GetGameJoypadMaps(unsigned char ucMap,unsigned char ucAction);
void SetJoypadMapVal(int iPad,unsigned char ucMap);
unsigned char GetJoypadMapVal(int iPad);
void SetJoypadSensitivity(int iPad, float fSensitivity);
unsigned int GetValue(int iPad,unsigned char ucAction, bool bRepeat=false);
bool ButtonPressed(int iPad,unsigned char ucAction=255); // toggled
bool ButtonReleased(int iPad,unsigned char ucAction); //toggled
bool ButtonDown(int iPad,unsigned char ucAction=255); // button held down
// Functions to remap the axis and triggers for in-game (not menus) - SouthPaw, etc
void SetJoypadStickAxisMap(int iPad,unsigned int uiFrom, unsigned int uiTo);
void SetJoypadStickTriggerMap(int iPad,unsigned int uiFrom, unsigned int uiTo);
void SetKeyRepeatRate(float fRepeatDelaySecs,float fRepeatRateSecs);
void SetDebugSequence( const char *chSequenceA,int( *Func)(LPVOID),LPVOID lpParam );
FLOAT GetIdleSeconds(int iPad);
bool IsPadConnected(int iPad);
// In-Game values which may have been remapped due to Southpaw, swap triggers, etc
float GetJoypadStick_LX(int iPad, bool bCheckMenuDisplay=true);
float GetJoypadStick_LY(int iPad, bool bCheckMenuDisplay=true);
float GetJoypadStick_RX(int iPad, bool bCheckMenuDisplay=true);
float GetJoypadStick_RY(int iPad, bool bCheckMenuDisplay=true);
unsigned char GetJoypadLTrigger(int iPad, bool bCheckMenuDisplay=true);
unsigned char GetJoypadRTrigger(int iPad, bool bCheckMenuDisplay=true);
void SetMenuDisplayed(int iPad, bool bVal);
// EKeyboardResult RequestKeyboard(UINT uiTitle, UINT uiText, UINT uiDesc, DWORD dwPad, WCHAR *pwchResult, UINT uiResultSize,int( *Func)(LPVOID,const bool),LPVOID lpParam,EKeyboardMode eMode,C4JStringTable *pStringTable=nullptr);
// EKeyboardResult RequestKeyboard(UINT uiTitle, LPCWSTR pwchDefault, UINT uiDesc, DWORD dwPad, WCHAR *pwchResult, UINT uiResultSize,int( *Func)(LPVOID,const bool),LPVOID lpParam, EKeyboardMode eMode,C4JStringTable *pStringTable=nullptr);
EKeyboardResult RequestKeyboard(LPCWSTR Title, LPCWSTR Text, DWORD dwPad, UINT uiMaxChars, int( *Func)(LPVOID,const bool),LPVOID lpParam,C_4JInput::EKeyboardMode eMode);
void GetText(uint16_t *UTF16String);
// Online check strings against offensive list - TCR 92
// TCR # 092 CMTV Player Text String Verification
// Requirement Any player-entered text visible to another player on Xbox LIVE must be verified using the Xbox LIVE service before being transmitted. Text that is rejected by the Xbox LIVE service must not be displayed.
//
// Remarks
// This requirement applies to any player-entered string that can be exposed to other players on Xbox LIVE. It includes session names, content descriptions, text messages, tags, team names, mottos, comments, and so on.
//
// Games may decide to not send the text, blank it out, or use generic text if the text was rejected by the Xbox LIVE service.
//
// Games verify the text by calling the XStringVerify function.
//
// Exemption It is not required to use the Xbox LIVE service to verify real-time text communication. An example of real-time text communication is in-game text chat.
//
// Intent Protect players from inappropriate language.
bool VerifyStrings(WCHAR **pwStringA,int iStringC,int( *Func)(LPVOID,STRING_VERIFY_RESPONSE *),LPVOID lpParam);
void CancelQueuedVerifyStrings(int( *Func)(LPVOID,STRING_VERIFY_RESPONSE *),LPVOID lpParam);
void CancelAllVerifyInProgress(void);
//bool InputDetected(DWORD dwUserIndex,WCHAR *pwchInput);
};
// Singleton
extern C_4JInput InputManager;
@@ -1,128 +0,0 @@
#pragma once
enum eAwardType
{
eAwardType_Achievement = 0,
eAwardType_GamerPic,
eAwardType_Theme,
eAwardType_AvatarItem,
};
enum eUpsellType
{
eUpsellType_Custom = 0, // This is the default, and means that the upsell dialog was initiated in the app code
eUpsellType_Achievement,
eUpsellType_GamerPic,
eUpsellType_Theme,
eUpsellType_AvatarItem,
};
enum eUpsellResponse
{
eUpsellResponse_Declined,
eUpsellResponse_Accepted_NoPurchase,
eUpsellResponse_Accepted_Purchase,
};
class C_4JProfile
{
public:
struct PROFILESETTINGS
{
int iYAxisInversion;
int iControllerSensitivity;
int iVibration;
bool bSwapSticks;
};
// 4 players have game defined data, puiGameDefinedDataChangedBitmask needs to be checked by the game side to see if there's an update needed - it'll have the bits set for players to be updated
void Initialise( DWORD dwTitleID,
DWORD dwOfferID,
unsigned short usProfileVersion,
UINT uiProfileValuesC,
UINT uiProfileSettingsC,
DWORD *pdwProfileSettingsA,
int iGameDefinedDataSizeX4,
unsigned int *puiGameDefinedDataChangedBitmask);
void SetTrialTextStringTable(CXuiStringTable *pStringTable,int iAccept,int iReject);
void SetTrialAwardText(eAwardType AwardType,int iTitle,int iText); // achievement popup in the trial game
int GetLockedProfile();
void SetLockedProfile(int iProf);
bool IsSignedIn(int iQuadrant);
bool IsSignedInLive(int iProf);
bool IsGuest(int iQuadrant);
UINT RequestSignInUI(bool bFromInvite,bool bLocalGame,bool bNoGuestsAllowed,bool bMultiplayerSignIn,bool bAddUser, int( *Func)(LPVOID,const bool, const int iPad),LPVOID lpParam,int iQuadrant=XUSER_INDEX_ANY);
UINT DisplayOfflineProfile(int( *Func)(LPVOID,const bool, const int iPad),LPVOID lpParam,int iQuadrant=XUSER_INDEX_ANY);
UINT RequestConvertOfflineToGuestUI(int( *Func)(LPVOID,const bool, const int iPad),LPVOID lpParam,int iQuadrant=XUSER_INDEX_ANY);
void SetPrimaryPlayerChanged(bool bVal);
bool QuerySigninStatus(void);
void GetXUID(int iPad, PlayerUID *pXuid,bool bOnlineXuid);
BOOL AreXUIDSEqual(PlayerUID xuid1,PlayerUID xuid2);
BOOL XUIDIsGuest(PlayerUID xuid);
bool AllowedToPlayMultiplayer(int iProf);
bool GetChatAndContentRestrictions(int iPad,bool *pbChatRestricted,bool *pbContentRestricted,int *piAge);
void StartTrialGame(); // disables saves and leaderboard, and change state to readyforgame from pregame
void AllowedPlayerCreatedContent(int iPad, bool thisQuadrantOnly, BOOL *allAllowed, BOOL *friendsAllowed);
BOOL CanViewPlayerCreatedContent(int iPad, bool thisQuadrantOnly, PPlayerUID pXuids, DWORD dwXuidCount );
void ShowProfileCard(int iPad, PlayerUID targetUid);
bool GetProfileAvatar(int iPad,int( *Func)(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes), LPVOID lpParam);
void CancelProfileAvatarRequest();
// SYS
int GetPrimaryPad();
void SetPrimaryPad(int iPad);
char* GetGamertag(int iPad);
wstring GetDisplayName(int iPad);
bool IsFullVersion();
void SetSignInChangeCallback(void ( *Func)(LPVOID, bool, unsigned int),LPVOID lpParam);
void SetNotificationsCallback(void ( *Func)(LPVOID, DWORD, unsigned int),LPVOID lpParam);
bool RegionIsNorthAmerica(void);
bool LocaleIsUSorCanada(void);
HRESULT GetLiveConnectionStatus();
bool IsSystemUIDisplayed();
void SetProfileReadErrorCallback(void ( *Func)(LPVOID), LPVOID lpParam);
// PROFILE DATA
int SetDefaultOptionsCallback(int( *Func)(LPVOID,PROFILESETTINGS *, const int iPad),LPVOID lpParam);
int SetOldProfileVersionCallback(int( *Func)(LPVOID,unsigned char *, const unsigned short,const int),LPVOID lpParam);
PROFILESETTINGS * GetDashboardProfileSettings(int iPad);
void WriteToProfile(int iQuadrant, bool bGameDefinedDataChanged=false, bool bOverride5MinuteLimitOnProfileWrites=false);
void ForceQueuedProfileWrites(int iPad=XUSER_INDEX_ANY);
void *GetGameDefinedProfileData(int iQuadrant);
void ResetProfileProcessState(); // after a sign out from the primary player, call this
void Tick( void );
// ACHIEVEMENTS & AWARDS
void RegisterAward(int iAwardNumber,int iGamerconfigID, eAwardType eType, bool bLeaderboardAffected=false,
CXuiStringTable*pStringTable=nullptr, int iTitleStr=-1, int iTextStr=-1, int iAcceptStr=-1, char *pszThemeName=nullptr, unsigned int uiThemeSize=0L);
int GetAwardId(int iAwardNumber);
eAwardType GetAwardType(int iAwardNumber);
bool CanBeAwarded(int iQuadrant, int iAwardNumber);
void Award(int iQuadrant, int iAwardNumber, bool bForce=false);
bool IsAwardsFlagSet(int iQuadrant, int iAward);
// RICH PRESENCE
void RichPresenceInit(int iPresenceCount, int iContextCount);
void RegisterRichPresenceContext(int iGameConfigContextID);
void SetRichPresenceContextValue(int iPad,int iContextID, int iVal);
void SetCurrentGameActivity(int iPad,int iNewPresence, bool bSetOthersToIdle=false);
// PURCHASE
void DisplayFullVersionPurchase(bool bRequired, int iQuadrant, int iUpsellParam = -1);
void SetUpsellCallback(void ( *Func)(LPVOID lpParam, eUpsellType type, eUpsellResponse response, int iUserData),LPVOID lpParam);
// Debug
void SetDebugFullOverride(bool bVal); // To override the license version (trail/full). Only in debug/release, not ContentPackage
};
// Singleton
extern C_4JProfile ProfileManager;
@@ -1,302 +0,0 @@
#pragma once
class ImageFileBuffer
{
public:
enum EImageType
{
e_typePNG,
e_typeJPG
};
EImageType m_type;
void* m_pBuffer;
int m_bufferSize;
int GetType() { return m_type; }
void *GetBufferPointer() { return m_pBuffer; }
int GetBufferSize() { return m_bufferSize; }
void Release() { free(m_pBuffer); m_pBuffer = nullptr; }
bool Allocated() { return m_pBuffer != nullptr; }
};
typedef struct
{
int Width;
int Height;
}D3DXIMAGE_INFO;
typedef struct _XSOCIAL_PREVIEWIMAGE {
BYTE *pBytes;
DWORD Pitch;
DWORD Width;
DWORD Height;
// D3DFORMAT Format;
} XSOCIAL_PREVIEWIMAGE, *PXSOCIAL_PREVIEWIMAGE;
class C4JRender
{
public:
void Tick();
void UpdateGamma(unsigned short usGamma);
// Matrix stack
void MatrixMode(int type);
void MatrixSetIdentity();
void MatrixTranslate(float x,float y,float z);
void MatrixRotate(float angle, float x, float y, float z);
void MatrixScale(float x, float y, float z);
void MatrixPerspective(float fovy, float aspect, float zNear, float zFar);
void MatrixOrthogonal(float left,float right,float bottom,float top,float zNear,float zFar);
void MatrixPop();
void MatrixPush();
void MatrixMult(float *mat);
const float *MatrixGet(int type);
void Set_matrixDirty();
// Core
void Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain);
void InitialiseContext();
void StartFrame();
void DoScreenGrabOnNextPresent();
void Present();
void Clear(int flags, D3D11_RECT *pRect = nullptr);
void SetClearColour(const float colourRGBA[4]);
bool IsWidescreen();
bool IsHiDef();
void CaptureThumbnail(ImageFileBuffer *pngOut);
void CaptureScreen(ImageFileBuffer *jpgOut, XSOCIAL_PREVIEWIMAGE *previewOut);
void BeginConditionalSurvey(int identifier);
void EndConditionalSurvey();
void BeginConditionalRendering(int identifier);
void EndConditionalRendering();
// Vertex data handling
typedef enum
{
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1, // Position 3 x float, texture 2 x float, colour 4 x byte, normal 4 x byte, padding 1 DWORD
VERTEX_TYPE_COMPRESSED, // Compressed format - see comment at top of VS_PS3_TS2_CS1.hlsl for description of layout
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT, // as VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1 with lighting applied,
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN, // as VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1 with tex gen
VERTEX_TYPE_COUNT
} eVertexType;
// Pixel shader
typedef enum
{
PIXEL_SHADER_TYPE_STANDARD,
PIXEL_SHADER_TYPE_PROJECTION,
PIXEL_SHADER_TYPE_FORCELOD,
PIXEL_SHADER_COUNT
} ePixelShaderType;
typedef enum
{
VIEWPORT_TYPE_FULLSCREEN,
VIEWPORT_TYPE_SPLIT_TOP,
VIEWPORT_TYPE_SPLIT_BOTTOM,
VIEWPORT_TYPE_SPLIT_LEFT,
VIEWPORT_TYPE_SPLIT_RIGHT,
VIEWPORT_TYPE_QUADRANT_TOP_LEFT,
VIEWPORT_TYPE_QUADRANT_TOP_RIGHT,
VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT,
VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT,
} eViewportType;
typedef enum
{
PRIMITIVE_TYPE_TRIANGLE_LIST,
PRIMITIVE_TYPE_TRIANGLE_STRIP,
PRIMITIVE_TYPE_TRIANGLE_FAN,
PRIMITIVE_TYPE_QUAD_LIST,
PRIMITIVE_TYPE_LINE_LIST,
PRIMITIVE_TYPE_LINE_STRIP,
PRIMITIVE_TYPE_COUNT
} ePrimitiveType;
void DrawVertices(ePrimitiveType PrimitiveType, int count, void *dataIn, eVertexType vType, C4JRender::ePixelShaderType psType);
void DrawVertexBuffer(ePrimitiveType PrimitiveType, int count, ID3D11Buffer *buffer, C4JRender::eVertexType vType, C4JRender::ePixelShaderType psType);
// Command buffers
void CBuffLockStaticCreations();
int CBuffCreate(int count);
void CBuffDelete(int first, int count);
void CBuffStart(int index, bool full = false);
void CBuffClear(int index);
int CBuffSize(int index);
void CBuffEnd();
bool CBuffCall(int index, bool full = true);
void CBuffTick();
void CBuffDeferredModeStart();
void CBuffDeferredModeEnd();
typedef enum
{
TEXTURE_FORMAT_RxGyBzAw, // Normal 32-bit RGBA texture, 8 bits per component
/* Don't think these are all directly available on D3D 11 - leaving for now
TEXTURE_FORMAT_R0G0B0Ax, // One 8-bit component mapped to alpha channel, R=G=B=0
TEXTURE_FORMAT_R1G1B1Ax, // One 8-bit component mapped to alpha channel, R=G=B=1
TEXTURE_FORMAT_RxGxBxAx, // One 8-bit component mapped to all channels
*/
MAX_TEXTURE_FORMATS
} eTextureFormat;
// Textures
int TextureCreate();
void TextureFree(int idx);
void TextureBind(int idx);
void TextureBindVertex(int idx);
void TextureSetTextureLevels(int levels);
int TextureGetTextureLevels();
void TextureData(int width, int height, void *data, int level, eTextureFormat format = TEXTURE_FORMAT_RxGyBzAw);
void TextureDataUpdate(int xoffset, int yoffset, int width, int height, void *data, int level);
void TextureSetParam(int param, int value);
void TextureDynamicUpdateStart();
void TextureDynamicUpdateEnd();
HRESULT LoadTextureData(const char *szFilename,D3DXIMAGE_INFO *pSrcInfo, int **ppDataOut);
HRESULT LoadTextureData(BYTE *pbData, DWORD dwBytes,D3DXIMAGE_INFO *pSrcInfo, int **ppDataOut);
HRESULT SaveTextureData(const char *szFilename, D3DXIMAGE_INFO *pSrcInfo, int *ppDataOut);
HRESULT SaveTextureDataToMemory(void *pOutput, int outputCapacity, int *outputLength, int width, int height, int *ppDataIn);
void TextureGetStats();
ID3D11ShaderResourceView *TextureGetTexture(int idx);
// State control
void StateSetColour(float r, float g, float b, float a);
void StateSetDepthMask(bool enable);
void StateSetBlendEnable(bool enable);
void StateSetBlendFunc(int src, int dst);
void StateSetBlendFactor(unsigned int colour);
void StateSetAlphaFunc(int func, float param);
void StateSetDepthFunc(int func);
void StateSetFaceCull(bool enable);
void StateSetFaceCullCW(bool enable);
void StateSetLineWidth(float width);
void StateSetWriteEnable(bool red, bool green, bool blue, bool alpha);
void StateSetDepthTestEnable(bool enable);
void StateSetAlphaTestEnable(bool enable);
void StateSetDepthSlopeAndBias(float slope, float bias);
void StateSetFogEnable(bool enable);
void StateSetFogMode(int mode);
void StateSetFogNearDistance(float dist);
void StateSetFogFarDistance(float dist);
void StateSetFogDensity(float density);
void StateSetFogColour(float red, float green, float blue);
void StateSetLightingEnable(bool enable);
void StateSetVertexTextureUV( float u, float v);
void StateSetLightColour(int light, float red, float green, float blue);
void StateSetLightAmbientColour(float red, float green, float blue);
void StateSetLightDirection(int light, float x, float y, float z);
void StateSetLightEnable(int light, bool enable);
void StateSetViewport(eViewportType viewportType);
void StateSetEnableViewportClipPlanes(bool enable);
void StateSetTexGenCol(int col, float x, float y, float z, float w, bool eyeSpace);
void StateSetStencil(int Function, uint8_t stencil_ref, uint8_t stencil_func_mask, uint8_t stencil_write_mask);
void StateSetForceLOD(int LOD);
// Event tracking
void BeginEvent(LPCWSTR eventName);
void EndEvent();
// PLM event handling
void Suspend();
bool Suspended();
void Resume();
};
const int GL_MODELVIEW_MATRIX = 0;
const int GL_PROJECTION_MATRIX = 1;
const int GL_MODELVIEW = 0;
const int GL_PROJECTION = 1;
const int GL_TEXTURE = 2;
// These things required for tex gen
const int GL_S = 0;
const int GL_T = 1;
const int GL_R = 2;
const int GL_Q = 3;
const int GL_TEXTURE_GEN_S = 0;
const int GL_TEXTURE_GEN_T = 1;
const int GL_TEXTURE_GEN_Q = 2;
const int GL_TEXTURE_GEN_R = 3;
const int GL_TEXTURE_GEN_MODE = 0;
const int GL_OBJECT_LINEAR = 0;
const int GL_EYE_LINEAR = 1;
const int GL_OBJECT_PLANE = 0;
const int GL_EYE_PLANE = 1;
// These things are used by glEnable/glDisable so must be different and non-zero (zero is used by things we haven't assigned yet)
const int GL_TEXTURE_2D = 1;
const int GL_BLEND = 2;
const int GL_CULL_FACE = 3;
const int GL_ALPHA_TEST = 4;
const int GL_DEPTH_TEST = 5;
const int GL_FOG = 6;
const int GL_LIGHTING = 7;
const int GL_LIGHT0 = 8;
const int GL_LIGHT1 = 9;
const int CLEAR_DEPTH_FLAG = 1;
const int CLEAR_COLOUR_FLAG = 2;
const int GL_DEPTH_BUFFER_BIT = CLEAR_DEPTH_FLAG;
const int GL_COLOR_BUFFER_BIT = CLEAR_COLOUR_FLAG;
const int GL_SRC_ALPHA = D3D11_BLEND_SRC_ALPHA;
const int GL_ONE_MINUS_SRC_ALPHA = D3D11_BLEND_INV_SRC_ALPHA;
const int GL_ONE = D3D11_BLEND_ONE;
const int GL_ZERO = D3D11_BLEND_ZERO;
const int GL_DST_ALPHA = D3D11_BLEND_DEST_ALPHA;
const int GL_SRC_COLOR = D3D11_BLEND_SRC_COLOR;
const int GL_DST_COLOR = D3D11_BLEND_DEST_COLOR;
const int GL_ONE_MINUS_DST_COLOR = D3D11_BLEND_INV_DEST_COLOR;
const int GL_ONE_MINUS_SRC_COLOR = D3D11_BLEND_INV_SRC_COLOR;
const int GL_CONSTANT_ALPHA = D3D11_BLEND_BLEND_FACTOR;
const int GL_ONE_MINUS_CONSTANT_ALPHA = D3D11_BLEND_INV_BLEND_FACTOR;
const int GL_GREATER = D3D11_COMPARISON_GREATER;
const int GL_EQUAL = D3D11_COMPARISON_EQUAL;
const int GL_LEQUAL = D3D11_COMPARISON_LESS_EQUAL;
const int GL_GEQUAL = D3D11_COMPARISON_GREATER_EQUAL;
const int GL_ALWAYS = D3D11_COMPARISON_ALWAYS;
const int GL_TEXTURE_MIN_FILTER = 1;
const int GL_TEXTURE_MAG_FILTER = 2;
const int GL_TEXTURE_WRAP_S = 3;
const int GL_TEXTURE_WRAP_T = 4;
const int GL_NEAREST = 0;
const int GL_LINEAR = 1;
const int GL_EXP = 2;
const int GL_NEAREST_MIPMAP_LINEAR = 0; // TODO - mipmapping bit of this
const int GL_CLAMP = 0;
const int GL_REPEAT = 1;
const int GL_FOG_START = 1;
const int GL_FOG_END = 2;
const int GL_FOG_MODE = 3;
const int GL_FOG_DENSITY = 4;
const int GL_FOG_COLOR = 5;
const int GL_POSITION = 1;
const int GL_AMBIENT = 2;
const int GL_DIFFUSE = 3;
const int GL_SPECULAR = 4;
const int GL_LIGHT_MODEL_AMBIENT = 1;
const int GL_LINES = C4JRender::PRIMITIVE_TYPE_LINE_LIST;
const int GL_LINE_STRIP = C4JRender::PRIMITIVE_TYPE_LINE_STRIP;
const int GL_QUADS = C4JRender::PRIMITIVE_TYPE_QUAD_LIST;
const int GL_TRIANGLE_FAN = C4JRender::PRIMITIVE_TYPE_TRIANGLE_FAN;
const int GL_TRIANGLE_STRIP = C4JRender::PRIMITIVE_TYPE_TRIANGLE_STRIP;
// Singleton
extern C4JRender RenderManager;
@@ -1,344 +0,0 @@
#pragma once
#include <vector>
//#include <xtms.h>
class C4JStringTable;
#define MAX_DISPLAYNAME_LENGTH 128 // CELL_SAVEDATA_SYSP_SUBTITLE_SIZE on PS3
#define MAX_DETAILS_LENGTH 128 // CELL_SAVEDATA_SYSP_SUBTITLE_SIZE on PS3
#define MAX_SAVEFILENAME_LENGTH 32 // CELL_SAVEDATA_DIRNAME_SIZE
typedef struct
{
time_t modifiedTime;
unsigned int dataSize;
unsigned int thumbnailSize;
}
CONTAINER_METADATA;
typedef struct
{
char UTF8SaveFilename[MAX_SAVEFILENAME_LENGTH];
char UTF8SaveTitle[MAX_DISPLAYNAME_LENGTH];
CONTAINER_METADATA metaData;
PBYTE thumbnailData;
}
SAVE_INFO,*PSAVE_INFO;
typedef struct
{
int iSaveC;
PSAVE_INFO SaveInfoA;
}
SAVE_DETAILS,*PSAVE_DETAILS;
typedef std::vector <PXMARKETPLACE_CONTENTOFFER_INFO> OfferDataArray;
typedef std::vector <PXCONTENT_DATA> XContentDataArray;
//typedef std::vector <PSAVE_DETAILS> SaveDetailsArray;
// Current version of the dlc data creator
#define CURRENT_DLC_VERSION_NUM 3
class C4JStorage
{
public:
// Structs defined in the DLC_Creator, but added here to be used in the app
typedef struct
{
unsigned int uiFileSize;
DWORD dwType;
DWORD dwWchCount; // count of WCHAR in next array
WCHAR wchFile[1];
}
DLC_FILE_DETAILS, *PDLC_FILE_DETAILS;
typedef struct
{
DWORD dwType;
DWORD dwWchCount; // count of WCHAR in next array;
WCHAR wchData[1]; // will be an array of size dwBytes
}
DLC_FILE_PARAM, *PDLC_FILE_PARAM;
// End of DLC_Creator structs
typedef struct
{
WCHAR wchDisplayName[XCONTENT_MAX_DISPLAYNAME_LENGTH];
CHAR szFileName[XCONTENT_MAX_FILENAME_LENGTH];
DWORD dwImageOffset;
DWORD dwImageBytes;
}
CACHEINFOSTRUCT;
// structure to hold DLC info in TMS
typedef struct
{
DWORD dwVersion;
DWORD dwNewOffers;
DWORD dwTotalOffers;
DWORD dwInstalledTotalOffers;
BYTE bPadding[1024-sizeof(DWORD)*4]; // future expansion
}
DLC_TMS_DETAILS;
enum eGTS_FileTypes
{
eGTS_Type_Skin=0,
eGTS_Type_Cape,
eGTS_Type_MAX
};
enum eGlobalStorage
{
//eGlobalStorage_GameClip=0,
eGlobalStorage_Title=0,
eGlobalStorage_TitleUser,
eGlobalStorage_Max
};
enum EMessageResult
{
EMessage_Undefined=0,
EMessage_Busy,
EMessage_Pending,
EMessage_Cancelled,
EMessage_ResultAccept,
EMessage_ResultDecline,
EMessage_ResultThirdOption,
EMessage_ResultFourthOption
};
enum ESaveGameControlState
{
ESaveGameControl_Idle=0,
ESaveGameControl_Save,
ESaveGameControl_InternalRequestingDevice,
ESaveGameControl_InternalGetSaveName,
ESaveGameControl_InternalSaving,
ESaveGameControl_CopySave,
ESaveGameControl_CopyingSave,
};
enum ESaveGameState
{
ESaveGame_Idle=0,
ESaveGame_Save,
ESaveGame_InternalRequestingDevice,
ESaveGame_InternalGetSaveName,
ESaveGame_InternalSaving,
ESaveGame_CopySave,
ESaveGame_CopyingSave,
ESaveGame_Load,
ESaveGame_GetSavesInfo,
ESaveGame_Rename,
ESaveGame_Delete,
ESaveGame_GetSaveThumbnail // Not used as an actual state in the PS4, but the game expects this to be returned to indicate success when getting a thumbnail
};
enum ELoadGameStatus
{
ELoadGame_Idle=0,
ELoadGame_InProgress,
ELoadGame_NoSaves,
ELoadGame_ChangedDevice,
ELoadGame_DeviceRemoved
};
enum EDeleteGameStatus
{
EDeleteGame_Idle=0,
EDeleteGame_InProgress,
};
enum ESGIStatus
{
ESGIStatus_Error=0,
ESGIStatus_Idle,
ESGIStatus_ReadInProgress,
ESGIStatus_NoSaves,
};
enum EDLCStatus
{
EDLC_Error=0,
EDLC_Idle,
EDLC_NoOffers,
EDLC_AlreadyEnumeratedAllOffers,
EDLC_NoInstalledDLC,
EDLC_Pending,
EDLC_LoadInProgress,
EDLC_Loaded,
EDLC_ChangedDevice
};
enum ESavingMessage
{
ESavingMessage_None=0,
ESavingMessage_Short,
ESavingMessage_Long
};
enum ETMSStatus
{
ETMSStatus_Idle=0,
ETMSStatus_Fail,
ETMSStatus_Fail_ReadInProgress,
ETMSStatus_Fail_WriteInProgress,
ETMSStatus_Pending,
};
enum eTMS_FileType
{
eTMS_FileType_Normal=0,
eTMS_FileType_Graphic,
};
enum eTMS_FILETYPEVAL
{
TMS_FILETYPE_BINARY,
TMS_FILETYPE_CONFIG,
TMS_FILETYPE_JSON,
TMS_FILETYPE_MAX
};
enum eTMS_UGCTYPE
{
TMS_UGCTYPE_NONE,
TMS_UGCTYPE_IMAGE,
TMS_UGCTYPE_MAX
};
typedef struct
{
CHAR szFilename[256];
int iFileSize;
eTMS_FILETYPEVAL eFileTypeVal;
}
TMSPP_FILE_DETAILS, *PTMSPP_FILE_DETAILS;
typedef struct
{
int iCount;
PTMSPP_FILE_DETAILS FileDetailsA;
}
TMSPP_FILE_LIST, *PTMSPP_FILE_LIST;
typedef struct
{
DWORD dwSize;
PBYTE pbData;
}
TMSPP_FILEDATA, *PTMSPP_FILEDATA;
C4JStorage();
void Tick(void);
// Messages
C4JStorage::EMessageResult RequestMessageBox(UINT uiTitle, UINT uiText, UINT *uiOptionA,UINT uiOptionC, DWORD dwPad=XUSER_INDEX_ANY,
int( *Func)(LPVOID,int,const C4JStorage::EMessageResult)=nullptr,LPVOID lpParam=nullptr, C4JStringTable *pStringTable=nullptr, WCHAR *pwchFormatString=nullptr,DWORD dwFocusButton=0);
C4JStorage::EMessageResult GetMessageBoxResult();
// save device
bool SetSaveDevice(int( *Func)(LPVOID,const bool),LPVOID lpParam, bool bForceResetOfSaveDevice=false);
// savegame
void Init(unsigned int uiSaveVersion,LPCWSTR pwchDefaultSaveName,char *pszSavePackName,int iMinimumSaveSize,int( *Func)(LPVOID, const ESavingMessage, int),LPVOID lpParam,LPCSTR szGroupID);
void ResetSaveData(); // Call before a new save to clear out stored save file name
void SetDefaultSaveNameForKeyboardDisplay(LPCWSTR pwchDefaultSaveName);
void SetSaveTitle(LPCWSTR pwchDefaultSaveName);
bool GetSaveUniqueNumber(INT *piVal);
bool GetSaveUniqueFilename(char *pszName);
void SetSaveUniqueFilename(char *szFilename);
void SetState(ESaveGameControlState eControlState,int( *Func)(LPVOID,const bool),LPVOID lpParam);
void SetSaveDisabled(bool bDisable);
bool GetSaveDisabled(void);
unsigned int GetSaveSize();
void GetSaveData(void *pvData,unsigned int *puiBytes);
PVOID AllocateSaveData(unsigned int uiBytes);
void SetSaveImages( PBYTE pbThumbnail,DWORD dwThumbnailBytes,PBYTE pbImage,DWORD dwImageBytes, PBYTE pbTextData ,DWORD dwTextDataBytes); // Sets the thumbnail & image for the save, optionally setting the metadata in the png
C4JStorage::ESaveGameState SaveSaveData(int( *Func)(LPVOID ,const bool),LPVOID lpParam);
void CopySaveDataToNewSave(PBYTE pbThumbnail,DWORD cbThumbnail,WCHAR *wchNewName,int ( *Func)(LPVOID lpParam, bool), LPVOID lpParam);
void SetSaveDeviceSelected(unsigned int uiPad,bool bSelected);
bool GetSaveDeviceSelected(unsigned int iPad);
C4JStorage::ESaveGameState DoesSaveExist(bool *pbExists);
bool EnoughSpaceForAMinSaveGame();
void SetSaveMessageVPosition(float fY); // The 'Saving' message will display at a default position unless changed
// Get the info for the saves
C4JStorage::ESaveGameState GetSavesInfo(int iPad,int ( *Func)(LPVOID lpParam,SAVE_DETAILS *pSaveDetails,const bool),LPVOID lpParam,char *pszSavePackName);
PSAVE_DETAILS ReturnSavesInfo();
void ClearSavesInfo(); // Clears results
C4JStorage::ESaveGameState LoadSaveDataThumbnail(PSAVE_INFO pSaveInfo,int( *Func)(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes), LPVOID lpParam); // Get the thumbnail for an individual save referenced by pSaveInfo
void GetSaveCacheFileInfo(DWORD dwFile,XCONTENT_DATA &xContentData);
void GetSaveCacheFileInfo(DWORD dwFile, PBYTE *ppbImageData, DWORD *pdwImageBytes);
// Load the save. Need to call GetSaveData once the callback is called
C4JStorage::ESaveGameState LoadSaveData(PSAVE_INFO pSaveInfo,int( *Func)(LPVOID lpParam,const bool, const bool), LPVOID lpParam);
C4JStorage::ESaveGameState DeleteSaveData(PSAVE_INFO pSaveInfo,int( *Func)(LPVOID lpParam,const bool), LPVOID lpParam);
// DLC
void RegisterMarketplaceCountsCallback(int ( *Func)(LPVOID lpParam, C4JStorage::DLC_TMS_DETAILS *, int), LPVOID lpParam );
void SetDLCPackageRoot(char *pszDLCRoot);
C4JStorage::EDLCStatus GetDLCOffers(int iPad,int( *Func)(LPVOID, int, DWORD, int),LPVOID lpParam, DWORD dwOfferTypesBitmask=XMARKETPLACE_OFFERING_TYPE_CONTENT);
DWORD CancelGetDLCOffers();
void ClearDLCOffers();
XMARKETPLACE_CONTENTOFFER_INFO& GetOffer(DWORD dw);
int GetOfferCount();
DWORD InstallOffer(int iOfferIDC, uint64_t *ullOfferIDA,int( *Func)(LPVOID, int, int),LPVOID lpParam, bool bTrial=false);
DWORD GetAvailableDLCCount( int iPad);
C4JStorage::EDLCStatus GetInstalledDLC(int iPad,int( *Func)(LPVOID, int, int),LPVOID lpParam);
XCONTENT_DATA& GetDLC(DWORD dw);
DWORD MountInstalledDLC(int iPad,DWORD dwDLC,int( *Func)(LPVOID, int, DWORD,DWORD),LPVOID lpParam,LPCSTR szMountDrive=nullptr);
DWORD UnmountInstalledDLC(LPCSTR szMountDrive = nullptr);
void GetMountedDLCFileList(const char* szMountDrive, std::vector<std::string>& fileList);
std::string GetMountedPath(std::string szMount);
// Global title storage
C4JStorage::ETMSStatus ReadTMSFile(int iQuadrant,eGlobalStorage eStorageFacility,C4JStorage::eTMS_FileType eFileType,
WCHAR *pwchFilename,BYTE **ppBuffer,DWORD *pdwBufferSize,int( *Func)(LPVOID, WCHAR *,int, bool, int)=nullptr,LPVOID lpParam=nullptr, int iAction=0);
bool WriteTMSFile(int iQuadrant,eGlobalStorage eStorageFacility,WCHAR *pwchFilename,BYTE *pBuffer,DWORD dwBufferSize);
bool DeleteTMSFile(int iQuadrant,eGlobalStorage eStorageFacility,WCHAR *pwchFilename);
void StoreTMSPathName(WCHAR *pwchName=nullptr);
// TMS++
#ifdef _XBOX
C4JStorage::ETMSStatus WriteTMSFile(int iPad,C4JStorage::eGlobalStorage eStorageFacility,C4JStorage::eTMS_FileType eFileType,CHAR *pchFilePath,CHAR *pchBuffer,DWORD dwBufferSize,TMSCLIENT_CALLBACK Func,LPVOID lpParam);
HRESULT GetUserQuotaInfo(int iPad,TMSCLIENT_CALLBACK Func,LPVOID lpParam);
#endif
// C4JStorage::ETMSStatus TMSPP_WriteFile(int iPad,C4JStorage::eGlobalStorage eStorageFacility,C4JStorage::eTMS_FILETYPEVAL eFileTypeVal,C4JStorage::eTMS_UGCTYPE eUGCType,CHAR *pchFilePath,CHAR *pchBuffer,DWORD dwBufferSize,int( *Func)(LPVOID,int,int)=nullptr,LPVOID lpParam=nullptr, int iUserData=0);
// C4JStorage::ETMSStatus TMSPP_GetUserQuotaInfo(int iPad,TMSCLIENT_CALLBACK Func,LPVOID lpParam, int iUserData=0);
C4JStorage::ETMSStatus TMSPP_ReadFile(int iPad,C4JStorage::eGlobalStorage eStorageFacility,C4JStorage::eTMS_FILETYPEVAL eFileTypeVal,LPCSTR szFilename,int( *Func)(LPVOID,int,int,PTMSPP_FILEDATA, LPCSTR)=nullptr,LPVOID lpParam=nullptr, int iUserData=0);
// C4JStorage::ETMSStatus TMSPP_ReadFileList(int iPad,C4JStorage::eGlobalStorage eStorageFacility,CHAR *pchFilePath,int( *Func)(LPVOID,int,int,PTMSPP_FILE_LIST)=nullptr,LPVOID lpParam=nullptr, int iUserData=0);
// C4JStorage::ETMSStatus TMSPP_DeleteFile(int iPad,LPCSTR szFilePath,C4JStorage::eTMS_FILETYPEVAL eFileTypeVal,int( *Func)(LPVOID,int,int),LPVOID lpParam=nullptr, int iUserData=0);
// bool TMSPP_InFileList(eGlobalStorage eStorageFacility, int iPad,const wstring &Filename);
// unsigned int CRC(unsigned char *buf, int len);
// enum eXBLWS
// {
// eXBLWS_GET,
// eXBLWS_POST,
// eXBLWS_PUT,
// eXBLWS_DELETE,
// };
//bool XBLWS_Command(eXBLWS eCommand);
unsigned int CRC(unsigned char *buf, int len);
// #ifdef _DEBUG
// void SetSaveName(int i);
// #endif
// string table for all the Storage problems. Loaded by the application
C4JStringTable *m_pStringTable;
};
extern C4JStorage StorageManager;
Binary file not shown.
Binary file not shown.
@@ -1619,7 +1619,7 @@ RADDEFSTART
#define RR_BREAK() __builtin_trap()
#define RR_CACHE_LINE_SIZE 32
#elif defined(__RADXENON__)
#define RR_BREAK() __debugbreak()
#define RR_BREAK() DEBUG_BREAK()
#define RR_CACHE_LINE_SIZE 128
#elif defined(__RADANDROID__)
#define RR_BREAK() __builtin_trap()
+117 -1
View File
@@ -9,6 +9,11 @@
#include "../../Minecraft.World/LevelSettings.h"
#include "../../Minecraft.World/BiomeSource.h"
#include "../../Minecraft.World/LevelType.h"
#include "stb_image_write.h"
extern ID3D11Device* g_pd3dDevice;
extern ID3D11DeviceContext* g_pImmediateContext;
extern IDXGISwapChain* g_pSwapChain;
CConsoleMinecraftApp app;
@@ -33,9 +38,120 @@ void CConsoleMinecraftApp::FatalLoadError()
{
}
static const int THUMBNAIL_SIZE = 64;
void CConsoleMinecraftApp::CaptureSaveThumbnail()
{
RenderManager.CaptureThumbnail(&m_ThumbnailBuffer);
if (!g_pSwapChain || !g_pd3dDevice || !g_pImmediateContext)
return;
// Release any previous capture
if (m_ThumbnailBuffer.Allocated())
m_ThumbnailBuffer.Release();
// Get the backbuffer
ID3D11Texture2D* pBackBuffer = nullptr;
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
if (FAILED(hr))
return;
D3D11_TEXTURE2D_DESC backDesc = {};
pBackBuffer->GetDesc(&backDesc);
// Create a staging texture at backbuffer size to read pixels
D3D11_TEXTURE2D_DESC stagingDesc = backDesc;
stagingDesc.Usage = D3D11_USAGE_STAGING;
stagingDesc.BindFlags = 0;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.MiscFlags = 0;
ID3D11Texture2D* pStaging = nullptr;
hr = g_pd3dDevice->CreateTexture2D(&stagingDesc, nullptr, &pStaging);
if (FAILED(hr))
{
pBackBuffer->Release();
return;
}
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
pBackBuffer->Release();
D3D11_MAPPED_SUBRESOURCE mapped = {};
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
if (FAILED(hr))
{
pStaging->Release();
return;
}
// Downsample to THUMBNAIL_SIZE x THUMBNAIL_SIZE with simple box filter
unsigned char* thumb = new unsigned char[THUMBNAIL_SIZE * THUMBNAIL_SIZE * 4];
// Crop to square (center crop), then scale down
UINT srcSize = (backDesc.Width < backDesc.Height) ? backDesc.Width : backDesc.Height;
UINT offsetX = (backDesc.Width - srcSize) / 2;
UINT offsetY = (backDesc.Height - srcSize) / 2;
for (int ty = 0; ty < THUMBNAIL_SIZE; ty++)
{
for (int tx = 0; tx < THUMBNAIL_SIZE; tx++)
{
// Map thumbnail pixel to source region
UINT sx = offsetX + (tx * srcSize) / THUMBNAIL_SIZE;
UINT sy = offsetY + (ty * srcSize) / THUMBNAIL_SIZE;
const unsigned char* src = (const unsigned char*)mapped.pData + sy * mapped.RowPitch + sx * 4;
unsigned char* dst = thumb + (ty * THUMBNAIL_SIZE + tx) * 4;
dst[0] = src[0]; // R (or B depending on format, but BGRA->RGBA swap below)
dst[1] = src[1]; // G
dst[2] = src[2]; // B
dst[3] = 0xFF; // A
}
}
g_pImmediateContext->Unmap(pStaging, 0);
pStaging->Release();
// If backbuffer is BGRA, swap to RGBA for PNG
if (backDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || backDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)
{
for (int i = 0; i < THUMBNAIL_SIZE * THUMBNAIL_SIZE; i++)
{
unsigned char tmp = thumb[i * 4];
thumb[i * 4] = thumb[i * 4 + 2];
thumb[i * 4 + 2] = tmp;
}
}
// Encode to PNG in memory using stbi_write_png_to_func
struct PngBuffer { unsigned char* data; int size; int capacity; } pngBuf = {};
pngBuf.capacity = THUMBNAIL_SIZE * THUMBNAIL_SIZE * 4 + 256;
pngBuf.data = (unsigned char*)malloc(pngBuf.capacity);
pngBuf.size = 0;
stbi_write_png_to_func([](void* ctx, void* data, int size) {
PngBuffer* buf = (PngBuffer*)ctx;
if (buf->size + size > buf->capacity)
{
buf->capacity = (buf->size + size) * 2;
buf->data = (unsigned char*)realloc(buf->data, buf->capacity);
}
memcpy(buf->data + buf->size, data, size);
buf->size += size;
}, &pngBuf, THUMBNAIL_SIZE, THUMBNAIL_SIZE, 4, thumb, THUMBNAIL_SIZE * 4);
delete[] thumb;
if (pngBuf.size > 0)
{
m_ThumbnailBuffer.m_type = ImageFileBuffer::e_typePNG;
m_ThumbnailBuffer.m_pBuffer = pngBuf.data;
m_ThumbnailBuffer.m_bufferSize = pngBuf.size;
}
else
{
free(pngBuf.data);
}
}
void CConsoleMinecraftApp::GetSaveThumbnail(PBYTE *pbData,DWORD *pdwSize)
{

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