Repository navigation
Add a FUComplete build of the MHFU profile (PokeeFUC) - #4
Draft
Oddity-git wants to merge 96 commits into
Draft
Oddity-git wants to merge 96 commits into
Oddity-git wants to merge 96 commits into
Conversation
FUComplete patches Monster Hunter Portable 2nd G (ULJM-05500), not Freedom Unite, so it needs its own executable, corpus and data folder. Configuring with -DMHFU_TITLE=FUC selects it: - the installer accepts a FUComplete image: disc id ULJM05500, the FUC folder, and an EBOOT.BIN that is already a plain ELF; an unpatched Portable 2nd G is refused with a pointer to FUCTool - data in Pokee/FUC; corpus, overlays, game and analysis in *_fuc - overlay slots from the executable's *.ovl sections - the Freedom Unite extras (camera, HUD, layered armor, damage numbers, gather icon, sharpness gauge, item box, lock-on) and DATA.BIN mods off - sceIoMkdir, which FUComplete's loader imports - databin.py reads a plain DATA.BIN; the scripts read the title from the build directory The default build is unchanged apart from sceIoMkdir. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The automatic codegen jumped to a local label when a J or JAL target was decoded in the same unit, before checking whether the target is a PSP import stub. FUComplete's plain executable keeps its stubs as `jr ra; nop` right after .text, so module_start's calls ran the stub's return instead of the HLE import and the game never started its main thread. Import stubs are now checked first, and a regression test covers a call into a stub that sits in the caller's unit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
FUComplete's Portable 2nd G has the same camera, aim, gather, carve, fishing-spot and farm code as Freedom Unite at other addresses. Each address the two features use now has its FUComplete value beside the Freedom Unite one, selected at compile time by the build's title, with the same instruction checks before anything is hooked or read: - the camera update at 0x08886B54 (0x2FC lower), its 38 checked words, the aim pitch clamp (0x2948 higher), the hunter list at 0x089C6CB4; - game_task's aim function, weapon table and bow case; - the gather search, area lookup, stage-id table, carve table, spot search, lobby_task's farm handler and game_sub's farm counts; - the overlay slots and the GameSys pointer in guest_layout.hpp. Every hunter field offset matched: only global addresses and calls differ. title.hpp gets a flag per extra; analog camera and hold to gather are on for both titles, lock-on stays Freedom Unite's and is kept out of the camera driver on FUComplete. The camera-unit scan in CMake looks for the title's update address, and main.cpp prepares the camera for a FUComplete corpus that matches its executable. Tests use the title's addresses and skip the extras that are still Freedom Unite's only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The FUComplete build installs beside the standard one, so everything the player reads says which is which: the window title, the menu's header and About row, the setup screens, the installer's dialogs and messages, and the data folder and log messages. MHFU_APP_NAME in title.hpp is "Pokee" for Freedom Unite and "PokeeFUC" for FUComplete. It is a macro so it joins the string literals it appears in. The executable, its data folder (Pokee/FUC) and code identifiers keep their names, and the Freedom Unite build's text is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
A semicolon ended the dialog text after "passed its checks", so the question whether to copy the image, its size and both paths were a discarded expression (GCC warns: ignoring the result of operator+). The dialog showed the check result with Copy / Use it where it is buttons and no question. The two parts are one string again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Extras that are still Freedom Unite's only did nothing in the FUComplete build, while the menu still offered them: UI Scaling and Hide HUD among others. Each such row is now drawn only where its feature runs, by the title's flag for it in title.hpp: Aspect ratio, UI Scaling, Hide HUD, Empty item slot, the Lock-on section, Damage numbers, Modern sharpness gauge, Gather icon, Layered armor and Give Any Rarity Item. A feature ported later brings its row back with its flag. Freedom Unite's menu is unchanged. The renderer UI test exercises those rows only where they are shown. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
packaging/linux/install_user.sh copies a build's executable, bundled libraries and overlay libraries into ~/.local/share/pokee or ~/.local/share/pokee-fuc with a launcher that raises the stack limit, and installs a .desktop entry and the emblem as its icon under ~/.local/share, so the game is in the application menu without root, Flatpak tooling or a container SDK. The build's title picks the name, app id, directory and entry, so the FUComplete build installs as PokeeFUC (io.github.teamgdb.PokeeFUC) next to Pokee and never replaces it. Running it again updates the copy; --uninstall removes it. The window now tells the desktop its app id (SDL_SetAppMetadata, before video starts in the game and in the setup dialogs), so the window is matched to its own entry, icon and taskbar group. Verified on Linux: the entry validates with desktop-file-validate, and the installed launcher starts the FUComplete build with the per-user data folder and loads its save (headless). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
FUComplete's loader rewrites words of the executable's code when the game starts: jumps from the file I/O into its own code at 0x08A35910 (its file replacer), and the immediates of the save keys for its Save Region option. A generated unit runs the words it was translated from, and falls through its own instructions without asking the dispatcher, so none of those changes ran: the hooks never reached FUComplete's code. The FUComplete build now watches the executable's code sections during the first minute. Once the loader's changes have held for a second, it writes the executable with them as EBOOT.FUC.ELF beside EBOOT.ELF and says how to generate the corpus from it. main.cpp starts from EBOOT.FUC.ELF when the linked corpus was generated from it, so the hooks are compiled code that jumps into FUComplete's (interpreted) loader. A configuration that patches other words writes the file again; MHFU_FUC_CODE_PATCHES=0 turns the watch off. Freedom Unite's build is unchanged. Verified on Linux with FUComplete's default configuration: the loader changed 48 words; a corpus generated from EBOOT.FUC.ELF rebuilt 4 of 67 units; the game starts from that file, finds nothing left to change, and FUComplete's hook ran (its buffer at 0x08A35890 holds the index and digits of the file being read, which nothing else writes). Speed stayed at 100%. fuc_code_patches_tests covers finding the code sections, counting changed words, writing the patched executable and the watch. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
With a game option on (the byte GameSys copies to +0x6ADE0, 0x088496F4 in FUComplete), the follow update picks again, every update, the vertical preset whose height is nearest its view and points camera +0x70 at it (0x088876A8 in Freedom Unite, 0x088873AC in FUComplete). That dropped the preset the driver had bent for the tilt, so the tilt eased back to the game's level as soon as it was made, even with the stick held. Seen in FUComplete, whose new character had the option on; the code is the same in Freedom Unite. While the driver has bent the preset for an update, the option reads as off for that update and is put back afterwards. Both of the update's reads of it join the camera's code signature for each title. A test checks that the update sees it off only while the driver owns the pitch, and that the player's setting is restored each time. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
FUComplete's Save Region option changes, in the game's code, the key the game passes to the savedata utility. With that change compiled in, a save written before it (with the executable's own key) failed its PARAM.SFO hash and the game called it broken. The savedata HLE now keeps every key a game passes in savedata_keys.txt in the data folder. When a save does not match the hash the current key gives, it loads with an earlier key of the same game, and says so; the game's next save writes the folder with the current key, so the save moves to it in the normal course of play. A damaged save matches no key and stays broken. Freedom Unite passes one key, so nothing changes there. Verified on Linux with a save made while FUComplete's patches did not run: with them compiled in, it failed with the current key, loaded with the earlier one, and the game reached Pokke Village with the hunter. Tests cover keeping the keys, the fallback, a save written again, and damaged data. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
FUComplete's loader patches overlays as they load: lobby_task gets 9 words changed, jumps into its own code, and game_task is changed too. Such an overlay matches no library built from DATA.BIN, so it ran in the interpreter: slower, and the wrappers on its functions could not be installed. Without the aim wrapper a drawn sword and shield (action 1001) counted as aiming and the analog camera stopped turning. The FUComplete build now dumps every overlay it has no library for into overlay_dumps in its data folder (MHFU_DUMP_OVERLAYS still names another directory; 0 now turns dumping off). A dump is named after its slot and its image, overlay_09A5A580_lobby_task.bin, since the slot is shared, and is written once a run. scripts/build_overlay_dumps.sh builds a library from every dump with add_overlay.py; libraries are named by the image's hash, so a patched overlay gets its own beside the unpatched one. Verified on Linux: FUComplete's lobby_task was dumped and built, the village installed it instead of interpreting it, and the interpreter ran 17 thousand instructions on the way to the village instead of 7.3 million. game_task needs a quest to be dumped. Tests cover the dump names and directory for both titles. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Each line of the follow camera's trace now ends with the followed hunter's bytes +0x298, +0x299 and +0x29C, which choose among the update's fixed heights and the preset, and the vertical snap option, or -1 where they cannot be read. These told the drifting tilt in FUComplete apart from the snap option: the option was off and the preset was used. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Fill widens the game's view to the window's shape by writing the aspect ratio into the camera object the projection is built from. FUComplete's executable has the same set-up, reset, projection and culling code 0xDC0 higher; only the store of the camera object differs (0x089C6CB4). The signature has its FUComplete table beside Freedom Unite's, picked by the title, main.cpp prepares it for a FUComplete corpus that matches its executable, and present_frame runs it under the title's kGameAspect, so the Aspect ratio row is back in the FUComplete menu. Verified: the FUComplete executable passes the signature at start (no mismatch logged); the aspect tests pass for both titles. Not yet looked at on a wide window. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The test cleared MHFU_GIVE_ANY_RARITY by setting it to an empty string. On Windows, _putenv_s removes a variable given an empty value; on Linux and macOS setenv keeps it, and an empty value of a switch reads as on, so "giving at any rarity is off by default" failed there. The helper now unsets the variable for an empty value. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
FUComplete's executable has the item menu's give check at 0x08829FC4, the item id lookup at 0x08826F8C, the pouch slot at 0x088567AC and the item table at 0x0899A238, with the same instructions as Freedom Unite's apart from the calls and the table's address. The check's address, the item table, GameSys and the signature each have their FUComplete value beside Freedom Unite's, picked by the title, and the wrapper is installed under the title's kGiveRarity, so the row is back on the FUComplete Mods page. Verified: every FUComplete word of the signature against the executable; the give-rarity tests pass for both titles. Not verified in play: giving needs another hunter in the Guild Hall. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The item bar's step (0x088DAB44), the pouch's packing, the HUD strip's calls, the name check and print, and game_task's first selection (from 0x09A63328 in FUComplete's game_task) have the same instructions in FUComplete as in Freedom Unite at their own addresses. Every address, return address and call word of the feature has its FUComplete value beside Freedom Unite's in empty_item_slot.hpp, the signatures have their FUComplete tables, and the wrappers go in under the title's kEmptyItemSlot, so the row is back in the FUComplete menu. Verified: all 34 FUComplete words of the two signatures against the executable and FUComplete's patched game_task; the tests pass for both titles. Not yet looked at in a quest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Hiding the HUD wraps the display list's packet insert, the text queue appends and the character draw in the executable, and recognises the HUD's functions in game_task and lobby_task by their prologues. FUComplete has all of them at its own addresses (the insert at 0x088595E8, the quest HUD at 0x09A5B508 in its game_task, the lobby callback at 0x09A673D0 in its lobby_task) with the same instructions; only the calls and the text context's address (0x08A5E278) differ. game_hud.cpp picks each address with at(Freedom Unite, FUComplete) by the title, the signature has its FUComplete table, CMake scans the corpus for the title's HUD functions, and the HUD is watched under the title's kHideHud, so the row and the F7 key work in the FUComplete build. Verified on Linux: every FUComplete word of the signature and of the overlay prologues (against FUComplete's patched game_task and lobby_task); in the village, F7 hid the name over the hunter and brought it back. The HUD tests pass for both titles. The quest HUD not yet looked at. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Both read the quest's entity list and the camera object, and damage numbers watch game_task's hit and status-tick functions. In FUComplete: - the entity manager is at 0x09D146E0 (game_sub's 456 loads of it read lui 0x09D1, +0x46E0 where Freedom Unite's read lui 0x09D2, -0x67A0); - the hunter vtable is at 0x089B6378, found by its entries; - lock-on's camera-object check reads the same code 0xDC0 higher; - the hit adjustment is at 0x09AC2BD8 in its game_task (an 80-word match) and the status tick at 0x09ACD860. The world extras in present_frame are split by feature (damage numbers, lock-on and its hunt portraits, the gather icon) under their own title flags, as is the renderer's note of the world camera; kLockOn and kDamageNumbers are now on for both titles, and a carve's monster icon needs lock-on's list. The hunt portraits' sheet is a runtime texture address not yet traced in FUComplete, so they may not show there. Verified: the lock-on, damage-number and analog camera tests pass for both titles (lock-on's tests now use the title's addresses). Not yet looked at in a quest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
These extras read the game's HUD textures. Traced with MHFU_TRACE_CAPTURE in a FUComplete quest: the HUD's sheets sit 0x4400 below Freedom Unite's. The item atlas is at 0x091830A0 (the item bar's icon and the map's marks are drawn from it), the HUD sheet at 0x091527A0, and the five window-frame textures UI Scaling recognises at 0x0915F820, 0x09160020, 0x09160820, 0x0915FFA0 and 0x091600A0; the area map stays at 0x0419C200. The hunt icon's sheet and palette take the same shift (0x09197900, 0x091AA110); no monster icon was in the capture to confirm them. The gather icon's pictures read the item records, icon sprites, sprite rectangles and tints, which FUComplete's executable finds at 0x0899A23C, 0x08938014, 0x089366F0 and 0x08937FA4 (gather_art.cpp has their code's FUComplete table). UI Scaling runs on Hide HUD's tracking of the 2D draws, now on for FUComplete; the sharpness gauge and the gather icon get their own title flags. Layered armor stays off: FUComplete's equipment code and records differ. Tests use the title's texture and table addresses; the HUD replay fixtures are Freedom Unite captures and run for that title only. All tests pass for both titles. Not yet looked at in a FUComplete quest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
UI Scaling sizes the hunter's name plate under the clock as Status. It told the plate's 8 by 16 end apart by its place, x 96, where Freedom Unite's plate (8, 56)-(104, 72) ends. FUComplete's plate is 8 shorter, (8, 56)-(96, 72), so its end at x 88 was no piece: it kept the game's place while the rest of the plate shrank toward the clock, and floated beside it. The end's place now follows the title. Found by replaying a FUComplete quest's MHFU_TRACE_CAPTURE log with the player's sizes (map 65, status 70, items 50, names 70): the end was the plate's only piece left out, and is now sized with it; every other quest HUD quad of that capture is a piece. The replay tool now also replays a capture in a FUComplete build; only its Freedom Unite fixtures are skipped there. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The settings tests drew the plate's end at x 96, Freedom Unite's place, and failed in the FUComplete build since its end moved to x 88. They now draw it at hud_scale::kPlateEndLeft. Both titles' suites pass again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The profile README's FUComplete table lists every extra as on at FUComplete's addresses, except the fast item box, which FUComplete has already, and layered armor, which stays off. It names the data that moved (GameSys, the camera object, the entity manager, the HUD's textures) and the shorter name plate. COMPATIBILITY.md gets a section for the FUComplete build with what a player and scripted runs checked on Linux, and what is still unchecked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The modern sharpness gauge finds the colour ends of the hunter's weapon from the weapon records, the model classes and the class tables, and the knife's sprites and colours, all data in the executable. Those were still Freedom Unite's addresses, so in FUComplete the gauge found no ends and the colour stayed whole instead of emptying as it is used. FUComplete keeps them lower, read from its own code: the weapon records at 0x089574C8 and the class tables at 0x08976738 (0x088DD4DC, the colour lookup), the model classes at 0x08975984 (0x0885CCE0), the knife's sprites and colours at 0x08935DA0 and 0x08935DA8 (0x0884111C). The hunter's sharpness fields are the same. Reported by the player; the tests pass for both titles. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
The Mods page said "Mods need the game's disc image, which is not open" in the FUComplete build, where the disc is open: the list of Freedom Unite mods is off there on purpose, because FUComplete replaces files with its own loader. The page now says so, and where FUComplete's own replacements go (its NATIVEPSP folder in ms0/PSP/SAVEDATA/FUCDAT) and that FUCTool sets them up. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Layered armor stands in for the armor model lookup, the hunter's load step and task, and the lobby's equipment calls, and reads the armor tables, the equipment box and the hunter records. FUComplete has all of it with the same instructions and record layout at its own addresses: - the lookup at 0x088517A8, the sex lookup at 0x088515D0, the part check at 0x08851B68, the resolve at 0x088D8CD0, the file load at 0x088DE504, the part model at 0x08851994 and the resident load at 0x08866E08; - the load step at 0x088C37AC, and the hunter task at 0x088BF3F8: the same dispatch on the task word, compiled with a 32-byte frame where Freedom Unite's has 4576, and the hunter in s2; - lobby_task's 13 calls, each matched with a 48-word window and checked by the call before it (its two copies of one block included); - the armor tables 0x2C24 lower, the text block at 0x089C7510, GameSys, and the hunter, file and model objects at 0x09A4099C, 0x09A4AE04 and 0x09A4AE1C, each read from FUComplete's own instructions and checked by the number of its uses (14, 122 and 62 in the executable, 20, 161 and 23 in lobby_task, as in Freedom Unite). Each has its FUComplete value beside Freedom Unite's, picked by the title, with FUComplete signature tables, and CMake scans the corpus for the title's functions. kLayeredArmor is now on for both titles, so the Layered armor page is back in the FUComplete menu. Verified on Linux: every FUComplete word of the nine signatures against the executable; in the village, with every part set to nothing, the hunter was drawn bare instead of in the worn armor. The tests pass for both titles. Not yet checked: chosen pieces, the equipment change, a quest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
FUComplete's packs live in textures/ULJM05500, but the Video page and the import row still pointed at textures/ULUS10391. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
A textures.ini saved by a Windows editor starts with a UTF-8 byte order mark. The line was "\xEF\xBB\xBF[options]", which is no section header, so the pack's hash setting was never read and the import refused it: "[options] does not say which hash the pack uses". PPSSPP reads such files. trim() now drops a leading byte order mark, in each of the texture pack's ini readers. A test checks a pack whose ini starts with one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
libc++ (macOS, Android) does not pull in <sstream> through the other headers, and Ruff flags base_text in add_overlay.py as unused (F841). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
Packs made for PPSSPP increasingly ship their images as KTX2 files holding Basis Universal UASTC or ETC1S data, often zstd-supercompressed, which stb_image cannot read. TexturePack::decode now recognises the KTX2 identifier and transcodes the first level to RGBA with the unmodified Basis Universal 2.1.0 transcoder and the zstd 1.5.7 decompressor it ships, both vendored under third_party/basis_universal and recorded in SOURCE_PROVENANCE.md and THIRD_PARTY_NOTICES.md. Hash-named images in a pack's top folder may be .ktx2 too. HDR data is refused. Tested with synthetic UASTC+zstd, ETC1S and HDR images in the texture pack suite, and with a community Portable 2nd G pack of 6101 KTX2 images in the FUComplete build: title, loading screen, HUD and village drawn from it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
…FU-to-FUComplete-port
The game writes the camera's field of view every frame, then its projection update builds the view only when that value differs from the one it last built with. Wrapping that update lets a new Video setting scale the value after the game sets it and before the projection is built, so the change shows at once, in the village and in quests, without a restart. Scaling after the update instead would grow every frame, because the value is not written again before the next wrap. Video > Field of view offers 50% to 150% of the game's own field of view (video.fov_scale, MHFU_FOV_SCALE). The target is checked to be a plausible field of view before it is written. MHFU_TRACE_FOV prints the projection camera's value and when the update is wrapped. The wrapper is installed only while the setting is not 100%, and it passes through when it is. Tests cover the scaling and its refusal of values outside memory or outside a field of view's range, and the wrapper being installed; both suites pass. A scripted run to the village with the setting at 140% drew the view wider and the camera's field of view read 1.41565 instead of 1.01118.
…tion The player confirmed the Video field of view scale changes the view while the game runs. FUComplete's own option is the player's field of view in a quest and is read by its loader at boot, so the live control is Pokee's, not that one.
The projection update's wrapper is now called: it scales the field of view the game wrote (0.8 at 125% builds from 1.0) before the update runs. MHFU_TRACE_FOV prints the camera's field of view once, and again only when it changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QmTUbk7nDg9Ffkqb3wtMax
…it/PokeeFUC into MHFU-to-FUComplete-port
release_linux.sh takes --title (or MHFU_TITLE) and, for FUC, uses game_fuc/EBOOT.ELF (the loader-patched EBOOT.FUC.ELF) and the FUC ISO, builds the FUC corpus and overlays, stages the .code files the patched overlays need, and names the tarball pokee-fuc. The Flatpak gets its own app id, desktop file, metainfo and launcher, so PokeeFUC and Pokee install side by side. The FU path is unchanged: same app id, names, game directory and executable hash check.
The landing page now says what PokeeFUC is, how to make the patched image with FUComplete and FUCTool, and how to install the Linux release or build from source. The base Pokee/Freedom Unite project and its credits stay, under their own section. The profile README's first build block now generates from EBOOT.FUC.ELF after the first start, not from the disc's executable: FUComplete's loader rewrites the code at start-up, and the corpus has to come from the loader's result.
It separates the two kinds of mod that matter here: game-content mods, which go through FUComplete's File Replacer and NATIVEPSP, and features built into PokeeFUC itself in C++. The first half covers the data folder, FUCTool's nativePSP generation, enabling the replacer, testing with a copied data folder, and what is still unknown (file names, the whitelist, quest packs, size changes). The second half covers title flags, signature checks, hooks, tests, traces and the rules. Linked from AGENTS.md and the root README.
…FU-to-FUComplete-port
A release already contains the corpus from EBOOT.FUC.ELF. Its first start writes that file and runs the unpatched executable once, then the next start uses the compiled code. The README and the open work now say so; the first-run message itself is left for the next build.
The arm64 APK installs beside Pokee, keeps its data across updates signed with the same key, and asks for the patched image on first start. It is a test build, checked on the emulator only so far. Uninstalling an earlier APK deletes its saves, so install over it.
The arm64 build boots from the patched image on a phone, the touch controls work, and 60/90/120 fps interpolation no longer bursts models after the vertex flush. Fill with Interface at the edges keeps menus and loot notices whole. The README, COMPATIBILITY and the open work now say so; versionCode 714 is the build tested.
The offline Gathering Hall offers the Guild's four-hunter quests to a hunter alone. With game.hub_scaling on, a large monster in a quest started from the hall keeps 65% of its health: its current and most health are cut when it appears, and put back when the switch goes off. MHFU_HUB_SCALING_HEALTH sets another percentage (1 to 100). The gate is the stage loaded just before the quest started, traced in FUComplete: the offline hall is stage 85, Pokke Village 139. The accepted quest's id is not kept in guest memory during the hunt, so the place it came from is what tells the two apart. An active ad hoc session turns the scaling off, so online play is untouched, and village quests never change. The trace prints the stage and each cut. The unit test covers the hall, the village, an online session, the flat cut and the restore. Seen in game: a 1-star Guild Bulldrome quest felt like its village counterpart, and a village quest printed last stage 139 with scaling off.
Scale Guild Hall quests for one hunter, offline
Take Pokee's True Attack Value element and status display, the bowgun reticle and stamina fill with the interface sizes, and the v0.4.4 formatting. The new true_element extra starts as kTrueElement = kTrueAttack (Freedom Unite only, where FUComplete has its own True Raw), gated in the frame call and described by the same menu row. true_element_tests set MHFU_TRUE_ATTACK to empty on Linux, which the switch reads as on; unset it instead, as true_attack_tests already does.
System > Saves gets a guided Sync saves screen: choose a folder (a path on a computer, a document tree on Android), upload this device's save, then Sync now on the other device. The folder holds only this game's save files, so Google Drive, Syncthing, Nextcloud or a shared folder all work. The two copies are compared by a SHA-256 of PARAM.SFO and the data files it lists: upload when only this device changed, download when only the folder changed, ask when both did, and keep the copy being replaced as a backup. Upload/Use-the-folder buttons force one direction. The README has the setup steps for Android (Drive app and the folder picker) and Linux (rclone, Insync, Syncthing). Android keeps the picked folder permission across restarts and reads/writes the save through its documents bridge. Tests cover the hash, the copy, the decision and finding the game's save folder.
On a 60 Hz panel 45 fps is 1.5 refreshes a present: the cadence alternates one and two refreshes and reads as judder. The governor's ladder now keeps a rate only when the display's refresh divides by it, so 60 Hz offers 60 and 30, 90 Hz offers 90, 45 and 30, and 120 Hz offers 120, 60 and 30. An unusual refresh with none of the known rates on its grid keeps the old ladder so there is still a way down. A display change rebuilds it. Android has no environment to set MHFU_TRACE_RENDER in, so Performance: Log now also prints the render split, showing where the renderer's CPU time goes as well as where it waited.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
Before: Pokee accepts only USA Freedom Unite (
ULUS-10391). A FUComplete image is refused at the installer.After: a build configured with
-DMHFU_TITLE=FUC, named PokeeFUC, installs and runs a FUComplete image (Monster Hunter Portable 2nd G,ULJM-05500, patched by FUCTool) with Pokee's extras. The defaultFUbuild behaves as before.This replaces #1, which GitHub closed when its branch was renamed to
MHFU-to-FUComplete-port. The code and commits are the same.How:
host/title.hpp,MHFU_TITLE): separate corpus, overlays, game and player data (Pokee/FUC), and a per-feature flag for each extra.ULJM05500only withFUC/PRELOAD.BINand a plain ELFEBOOT.BIN; an unpatched image is sent to FUCTool; each build points a disc of the other title to the right build.textures.iniwith a byte order mark.sceIoMkdir, which FUComplete uses to create its save folder.Related issues
Replaces #1.
Validation
FU, 64 inFUC) on the current head, including new installer disc-check tests on synthetic ISO images.Not verified
main: the C++ formatting check and three cppcheck findings in Pokee's own code.Checklist
Generated by Claude Code