Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing and improving the Tuning menu. #3151

Merged
merged 19 commits into from
May 28, 2024

Conversation

ohlidalp
Copy link
Member

@ohlidalp ohlidalp commented Apr 13, 2024

Highlights:

  • Addonpart file format: added directive addonpart_filename <foo.truck> to whitelist only some vehicles if GUID is too broad.
  • Tuneup file format: added directive filename <foo.truck> to filter the "Saved tuneups" list by vehicle filename, since GUID is too broad and some vehicles don't even have one.
  • Tuning UI: Added sections Exhausts, Flares and Managed Materials
  • Tuning UI: Added anti-conflict system: if 2 addonparts tweak the same element, they cannot be installed together.
    • Gray X marker = conflict with installed addonpart.
    • Red [ ] marker = conflict with mouse-hovered addonpart (regardless of being installed or not)

obrazek

Changes made so far:

  • Fixed crash when multiple addonparts try to tweak the same node. previously, whenever 2 addonparts conflicted, I actually by mistake inserted a zeroed-out tweak to the schedule. That happened in the logging code.
  • INFO log about adding tweak from addonpart to tuneup was changed from "tweaking *** with params" to "Scheduling tweak for *** with params" to clarify it's not applied yet.
  • INFO log about withdrawing tweak from tuneup due to another addonpart trying to tweak the same element was changed from "conflict of tweaks at ***" to WARNING "Resetting tweaks for *** due to conflict"
  • Fixed FlexbodyDebug UI 'hide other' not working for flexbodies. Broken in 9551d05 - since this commit flexbodies got a dynamic visibility control, exactly the same as props. From user (truck fileformat) perspective, it was the same already but the update pattern was different, and this commit unified it. The FlexbodyDebug UI didn't reflect this however.
  • Fixed addonpart conflict handling. The tuning menu now evaluates conflicts between addonparts (each element like wheel or node can be tweaked only by 1 addonpart) and shows markers on conflict:
    • Gray X = conflict with installed addonpart.
    • Red [ ] = conflict with mouse-hovered addonpart (regardless of being installed or not)
  • Modcache query system: fixed the GUID filtering being case-sensitive in all cases (trucks, skins, addonparts), even though the search string is always case-insensitive.
  • Added flares to tuning system: flare/flare2/addonpart_unwanted_flare in .addonpart, protected/forceremoved states in .tuneup, including UI. Tweaks were omitted.
  • Added exhausts to tuning system: addonpart_unwanted_exhausts in .addonpart, protectd/forceremoved states in .tuneup, including UI. Tweaks and defining new exhausts in .addonpart were omitted.
  • Fixed a bug in GenericDocument tokenizer - If OPTION_ALLOW_NAKED_STRINGS was used, strings starting like true/false, for example f or t alone, would get discarded.
  • UI touch: right-aligned addonpart [Reload] buttons.
  • Tuneup format + UI: Added managed materials tweaks.

Additional discovered issues:

  • [Fixed] The idea was that 2 or more addonparts cannot tweak the same element. There is a flaw in this logic though: if there are 3 conflicting addonparts, the second one will reset the first one, but the third one will pass. And so on.

@ohlidalp
Copy link
Member Author

I'm fixing the addonpart conflicts - I figured I need to block the user from selecting conflicting addonparts at all, preferably with some visual markers. This is what I have right now - the graphics are not final and there's a huge lag when opening the menu. To be improved.
obrazek

@ohlidalp
Copy link
Member Author

Markers are finished:

  • Gray X = conflict with installed addonpart.
  • Red [ ] = conflict with mouse-hovered addonpart (regardless of being installed or not)

obrazek

ohlidalp added a commit to ohlidalp/rigs-of-rods that referenced this pull request Apr 24, 2024
The modder can add any number of `addonpart_filename <foo.truck>` directives (case-insensitive). If none are specified, any filename goes. Matching by GUID is still the primary method, this only helps in cases where the GUID is shared by too many trucks (not uncommon).

This commit also fixes the GUID filtering being case-sensitive in all cases (trucks, skins, addonparts), even though the search string is always case-insensitive.

Cache file format was set to dummy value; will be properly bumped when RigsOfRods#3151 is merged.
@ohlidalp
Copy link
Member Author

Added addonpart_filename directive (optional whitelist)

The modder can add any number of addonpart_filename <foo.truck> directives (case-insensitive). If none are specified, any filename goes.

Matching by GUID is still the primary method, this only helps in cases where the GUID is shared by too many trucks (not uncommon).

@CuriousMike56
Copy link
Collaborator

Unfortunately adding flares doesn't seem to work for me:
MV4_PolicePackage.zip
image
RoR_2024-04-26_01-05-48
Adding the flares after flexbodies introduces the flexbody errors.

Expected result:

RoR_2024-04-26_01-15-41.mp4

CTRL+2 activates the lightbar and CTRL+3 for the front/rear flashers.

@ohlidalp
Copy link
Member Author

ohlidalp commented Apr 27, 2024

I fixed the discarding incomplete boolean token 'f' warnings - it was a tokenizer bug.

EDIT: Another fix - I forgot to update the condition around block = keyword;, causing the parser to interpret all flare lines as whatever was before (flexbodies in this case).

Finally I fixed the case where the flare used material from the addonpart ZIP - same story as with props and flexbodies, I just forgot to handle it the first time.

@ohlidalp
Copy link
Member Author

ohlidalp commented May 9, 2024

Added managed materials tweaks:
obrazek

INFO log about adding tweak from addonpart to tuneup was changed from "tweaking *** with params" to "Scheduling tweak for *** with params" to clarify it's not applied yet.

INFO log about withdrawing tweak from tuneup due to another addonpart trying to tweak the same element was changed from "conflict of tweaks at ***" to WARNING "Resetting tweaks for *** due to conflict"

The idea was that 2 or more addonparts cannot tweak the same element. There is a flaw in this logic though: if there are 3 conflicting addonparts, the second one will reset the first one, but the third one will pass. And so on.

Additionally this commit fixes terminology in the logs: addonpart keywords are now called 'directives', not 'elements' ... because elements mean the things actors consist of (wheels/props/flexbodies/nodes etc...).
Broken in 9551d05 - since this commit flexbodies got a dynamic visibility control, exactly the same as props. From user (truck fileformat) perspective, it was the same already but the update pattern was different, and this commit unified it. The FlexbodyDebug UI didn't reflect this however.

In addition to fixing the glitch, this commit also unifies code for the visibility handling - same variables, same constants, just different prefixes.

Codechanges:
* GfxData: cosmetic changes to CAMERA_MODE constants - added typedef
* FlexBody: replaced single visibility mode field with _active+_orig fields, same as props have. Also using the same coding style as props do.
* GfxActor: cosmetic change - use the new variables in flexbody.
* ActorSpawner: set flexbody visibility via the new vars.
This implements proactive scanning for addonpart conflicts when the menu is refreshed. This incurs a big lag when opening the menu and likely a lot of spam in RoR.log, but it works. Currently it only displays red squares as conflict markers when one addonpart is hovered.

The original conflict resolution logic is still present in `ResolveUnwantedAndTweakedElements()` - when a conflict is found, tweeaks for that elements are reset. But this is flawed, if there's an odd number of conflicting tweaks, the last one will pass. I'll remove it in next commits.
This removes the huge UI lag on first open of the tuning menu, which was caused by loading all addonparts to evaluate conflicts. But the lag isnt gone - it now happens upon spawning the actor. It could only be fully eliminated by caching the tweaked element IDs directly in `CacheEntry`, something I'll eventually do but not now.

Codechanges:
* CacheSystem: added dummy TuneupDef with addonpart data to CacheEntry.
* AddonPartFileFormat: added silent mode, using the new CacheEntry field.
* GameContext: also push MSG_SIM_REFRESH_TUNING_MENU_REQUESTED after spawning new actor and seating player there. Deleted duplicate code in SpawnActor()
Gray X = conflict with installed addonpart.
Red [] = conflict with mouse-hovered addonpart (regardless of being installed or not)
The modder can add any number of `addonpart_filename <foo.truck>` directives (case-insensitive). If none are specified, any filename goes. Matching by GUID is still the primary method, this only helps in cases where the GUID is shared by too many trucks (not uncommon).

This commit also fixes the GUID filtering being case-sensitive in all cases (trucks, skins, addonparts), even though the search string is always case-insensitive.

Cache file format was set to dummy value; will be properly bumped when RigsOfRods#3151 is merged.
This was an exercise in extending the Tuning system. Took 2 hours, 35 minutes (including writing the long HOWTO below).
* An `addonpart_unwanted_flare` directive was added.
* Addonparts now support 'flares' and 'flares2' (flares3 aren't supported).
* Note that tweaks for flares were not added, as adding/removing seems to be enough.

Codechanges (HOWTO add a new feature to the Tuning system [if you're a daring programmer] - changes are ordered to intuitively form the picture):
* ForwardDeclarations.h: added typedef FlareID_t ~ this isn't technically necessary but makes the code more pleasant to read.
* TuneupFileFormat.h: added unwanted/forece_remove/protected flare lists to the TuneupDef document, and helper functions to TuneupUtil. See //comments to understand their meaning. ~ I just duplicated the same code as props already use, just changed the ID type to flares.
* AddonPartFileFormat: added support for defining 'flares' and 'flares2' in the .addonpart file. ~ Since the syntax is the same as in 'truck' fileformat and the output object is also the same, this basically means copypasting `RigDef::Parser::ParseFlaresUnified()` (see file RigDef_Parser.cpp) and modifying it to fit. A slight twist is that I didn't use an unified function but created separate 'flares' and 'flares2' functions. This is because 'flares3' is separate either way.
    FIXUP: I forgot to update the condition around `block = keyword;`, causing the parser to interpret all flare lines as whatever was before (flexbodies in my case).
* CacheSystem: added PROTECTED + FORCEREMOVE SET/RESET ModifyProjectRequest types. ~ in RoR, everything important is done via message queue. Tuning changes are done by MSG_EDI_MODIFY_PROJECT_REQUESTED.
* GUI_TopMenubar.cpp: added "Flares" section ~ pretty much a copypaste of existing Flexbodies section code above, just modified to fit: changed the loop to read flares instead of flexbodies, added code to compose name of the flare, and change the ModifyProjectRequestType constants.
* ActorSpawner: if the flare is removed by Tuning system, just create a placeholder. ~ This is the moment of truth. When spawning, the tuning changes must be evaluated, but to maintain consistent lists of elements in the Tuning menu (and other tools), the unwanted/forceRemoved elements are left around as inactive 'placeholders'. In this case, it's a complete flare object, just without the visual flare billboard and light.
* SimData.h: just // comments about tuning
* GfxActor: skip placeholder flares when updating visuals.
* DashBoardManager: added helper function to convert linkID back to the name - needed for the Tuning UI menu to display link name for 'd' (dashboard) flares.
To understand code changes, find previous commit which adds flares to the tuning system - it provides detailed checklist for making such change.
If OPTION_ALLOW_NAKED_STRINGS was used, strings starting like true/false, for example f or t alone, would get discarded.
Of course I could't get it right the first time.

The mechanism I added is the same thing that props and flexbodies already use. Search fulltext for `*_rg_override`.
Null pointer access :/
I removed the confusing variable `current_actor` altogether - now there's only `tuning_actor`.
This fixes 55e98ca which introduced `_somemedia_override_rg` fields to props and flexbodies (later followed by flares), alghough there was already a more elegant solution - the `RigDef::Module::origin_addonpart` field used by managedmaterials (created along with the very inception of the AddonPart system in b1f4d23).
I couldn't determine why I created this redundant logic in the first place.
Either way, This commit unifies the logic around the `origin_addonpart` mechanic.
Another exercise in extending the Tuning system. Took ~5 hours (2 hours just Spawner - resolving texture tweaks was tricky)
* An `addonpart_unwanted_managedmaterial` directive was added.
* An `addonpart_tweak_managedmaterial <name> <type> <media1> <media2> [<media3>]` directive was added.
Unlike all other elements which are referenced by ID, managedmaterials are referenced by name because it must be unique anyway.

Codechanges ~HOWTO add a new feature to the Tuning system [if you're a daring programmer]
  changes are ordered to intuitively form the picture
  (this is an updated version of the 'flares' guide)
  ==================================================

* TuneupFileFormat.h:
    - added struct TuneupManagedMatTweak ~ same pattern as other tweaks.
    - added unwanted/forece_remove/protected flare lists to the TuneupDef document, and helper functions to TuneupUtil. See //comments to understand their meaning.
     ~ I followed the same pattern as other elements use, except I used plain `std::string` for an ID.
* TuneupFileFormat.cpp:
    - implemented all new functions, in same manner as nodes/flexbodies/props already do. No special features.
* AddonPartFileFormat:
    - Added ProcessTweaked***() and ProcessUnwanted***() helper functions for managedmats.
    - Extended `ResolveUnwantedAndTweakedElements()` to use them.
* CacheSystem:
    - added PROTECTED + FORCEREMOVE SET/RESET ModifyProjectRequest types. ~ in RoR, everything important is done via message queue. Tuning changes are done by MSG_EDI_MODIFY_PROJECT_REQUESTED.
        ~ Unlike other elements which use `subject_id` field (integer), these use `subject` (string) field, see //!< comments.
*  GUI_TopMenubar.cpp:
      - Added magic constant TUNING_SUBJECTID_USE_NAME to be able to use the helper funcs `DrawTuning{ForceRemove/Protected}Controls` with name (subject) instead of ID (subject_id)
      - added "Managed Materials" section ~ pretty much a copypaste of the Exhausts section code above, just modified to fit: changed the loop to read managedmats instead of exhausts, added code to compose name of the flare, and use the new SUBJECTID_USE_NAME constant.
* ActorSpawner:
      - created `AssignManagedMaterialTexture()` to resolve Tweaks and check if texture exists - Helper for `ProcessManagedMaterial()`.
      - if the managed material  is removed by Tuning system, just create a placeholder. ~ This is the moment of truth. When spawning, the tuning changes must be evaluated, but to maintain consistent lists of elements in the Tuning menu (and other tools), the unwanted/forceRemoved elements are left around as inactive 'placeholders'. In this case, it's a clone of "tracks/transred" material from builtin resources.
@ohlidalp
Copy link
Member Author

I fixed the remaining 2 glitches:

  • Cannot load flat files from '/projects' dir - turned out to be an exception due to 'readOnly' flag in OGRE archives.
  • When actor has no guid, the 'saved tuneups' list show tuneups for all actors - fixed by adding 'filename' directive to .tuneup file, allowing to filter by filename.

@ohlidalp ohlidalp marked this pull request as ready for review May 27, 2024 05:24
There is a new field in the .tuneup format, 'filename'. It should really be 'associated_filename', but this would be confusing with 'guid' (which should really be 'associated_guid') and changing that would be confusing with .skin format which also uses 'guid' and cannot be changed because #compatibility. C'est la vie.
Cause: bad loop code in AddonPartFileFormat.cpp, function `RecordAddonpartConflicts()`, which inserted garbage into `_tweaks` arrays. For example if the addonpart only tweaked prop 6, there should be just the item 6 in the set, but it ended up being garbage items 0-5 and valid 6. Why? This is a backwards compatibility quirk of C++: when you ask a `std::set<>` for non-existent element via `[]` brackets, it inserts a dummy element and gives it to you. And because these loops went "from 0 to number of elements", gradually, as repeated conflict resolutions happened, garbage built up.

Fixed by looping using iterators which only retrieve actually existing elements.
@ohlidalp ohlidalp merged commit 47f022e into RigsOfRods:master May 28, 2024
2 checks passed
ohlidalp added a commit that referenced this pull request May 28, 2024
The modder can add any number of `addonpart_filename <foo.truck>` directives (case-insensitive). If none are specified, any filename goes. Matching by GUID is still the primary method, this only helps in cases where the GUID is shared by too many trucks (not uncommon).

This commit also fixes the GUID filtering being case-sensitive in all cases (trucks, skins, addonparts), even though the search string is always case-insensitive.

Cache file format was set to dummy value; will be properly bumped when #3151 is merged.
@ohlidalp ohlidalp deleted the 3122_Tuning_glitches branch May 28, 2024 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants