RigsOfRods / rigs-of-rods

Main development repository for Rigs of Rods soft-body physics simulator
https://www.rigsofrods.org
GNU General Public License v3.0
991 stars 175 forks source link

Created vehicle tuning GUI using new .addonpart mod type #3096

Closed ohlidalp closed 5 months ago

ohlidalp commented 8 months ago

UPDATE 01/2024: For most up-to-date info, please see the Wrapping Up post below.

The master branch has almost everything you need to create a truck editor script. Almost. This PR will fill the blanks. EDIT: After Discord debate, I steered this PR towards a vehicle configuration/tuning system.

So far I've done the most important bit: I've made GenericDocument editable, as originally promised. The GenericDocReaderClass was renamed to GenericDocContextClass and there are new functions:

    bool insertToken(int offset = 0); //!< Inserts `TokenType::NONE`; @return false if offset is beyond EOF
    bool eraseToken(int offset = 0); //!< @return false if offset is beyond EOF

    bool setTokString(int offset, const string&in str);
    bool setTokFloat(int offset, float val);
    bool setTokBool(int offset, bool val);
    bool setTokKeyword(int offset, const string&in str);
    bool setTokComment(int offset, const string&in str);
    bool setTokLineBreak(int offset);

To showcase it, I created an example script - you can run it by opening ingame console and typing loadscript example_GenericDoc_editor.as. It doesn't edit yet, just lets you select tokens with mouse and prints details. Green text is hovered, red text has focus. obrazek

CuriousMike56 commented 8 months ago

Nice! Hopefully we'll be able to make temporary edits and apply them to the vehicle. Would be fun to mess with, say, engine tunes in real time.

ohlidalp commented 8 months ago

@CuriousMike56 💌 I'd like that too, here's facts:

ohlidalp commented 8 months ago

You can now do this in AngelScript:

       // Fetch the current actor cache entry
         CacheEntryClass@ src_entry = cache.findEntryByFilename(LOADER_TYPE_ALLBEAM, /*partial:*/false, actor.getTruckFileName());

       // request project to be created from that cache entry
       string proj_name = "project1";
       game.pushMessage(MSG_EDI_CREATE_PROJECT_REQUESTED, {
           {'name', proj_name},
           {'source_entry', src_entry}
       });

The game will create a subdirectory in 'My Games\Rigs of Rods\project' and copy all files from the existing mod ZIP. It will also rename the truck file for you and publish it in modcache. You can look it up under new category "Projects" (catetgory ID 8990). As you can see on the screenshot, the material is glitched but otherwise the project spawns as fully functional actor. obrazek

The example script does all this. I guess I'm done with this branch for now, if anybody is interested in expanding this, everything can be deduced from docs, demo_script.as or builtin examples.

What doesn't work yet: the cachefile is not updated and modcache regen doesn't yet pick up the new projects directory. Also the new MSG_ and the new modcache objects weren't added to docs yet. Contributions are most welcome.

ohlidalp commented 8 months ago

This is why I started this branch in the first place... While working on the script editor, I prototyped a GridViewer component (#include gridviewer_utils.as) which draws a scrolling/zooming window and lets you draw stuff to it, automatically calculating the zoomed/scrolled positions. It was just collecting dust on my harddisk, and now it's finally at work, with 3 instances and a tokenized document view on the left. Inspired by good ol' Editorizer.. As you can see, axes are off and views are rotated/upside down, but with a hint it's recognizable as DAF semitruck.

obrazek

ohlidalp commented 8 months ago

Some interesting thoughts from Discord (UPDATE: added "-->" closures):

ohlidalp commented 8 months ago

After Discord debate, I steered this PR towards a vehicle configuration/tuning system.

STATUS: ALPHA! Glitchy, only adding a part works, the remove-button is dummy. addonpartsPrototype

This adds a new mod type "addonpart" (file pattern *.addonpart) which works as a partial truck file - when selected, it adds additional elements to it. Currently supported features are: managedmaterials, props, flexbodies. The point is to automate what users had to do manually before: https://docs.rigsofrods.org/tools-tutorials/addons/

The addon parts receive all usual treatment from modcache: they can have preview images, name + description are always displayed, they can be searched for, the MainSelectorUI can be opened in mode 'LT_AddonPart' to show only addon parts. In addition, the search can be filtered by a vehicle GUID, much like with SkinZips. This is an example addonpart (port of https://forum.rigsofrods.org/resources/heavy-bumper-for-the-chevy-k3500.461/):

addonpart_name "Heavy Bumper for the Chevy K3500 (Prop, Black)"
addonpart_description "For use with GMT400 88-98 Chevy Truck Pack"

;addonpart_guid <guid>  ~ multiple GUIDs can be specified
addonpart_guid 057b21c8-cb54-496d-88ce-4855a8d6d43d
; * 1990 Chevy 454ss,  * 1990 Chevy k3500    * 1990 Chevy K3500HD
addonpart_guid 6a53ad83-255d-4d5e-bf14-ca0714e5228d
; * 1990 Chevy k2500 Blazer, -SAS, -Suburban

managedmaterials
    CHeavyBumper        mesh_standard       HeavyBumper.dds     HeavyBumper_s.dds

props
    39, 62, 34,    0.50,    0.32,     -0.5,   0,    180,    180, CHeavyBumper.mesh

There's a new menu in TopMenubarUI: "Tuning". It lists already installed addonparts and contains [add parts] button which opens MainSelectorUI in 'LT_AddonPart' mode, with GUID filtering for the current vehicle.

To remember what addonparts user selected, an additional mod type was added: "tuneup" (file pattern *.tuneup) - this works like ".skin for addonparts" and has intentionally similar syntax. There are 2 power tools:

Note: An option to replace prop was intentionally not implemented because that would be a duplicate feature with addonparts. It's up to user to remove props if and only if they don't want them together with new parts.

When user uses addonpart with a vehicle for the first time, the game creates a .tuneup file for it in {Documents\My Games\Rigs of Rods\projects}. When spawning the vehicle next time, the .tuneup is loaded automatically. In the future the menu will be able to save custom tuneups. Here's an example:

Tuned 1990 Chevy 454ss
{
      use_addonpart = CHeavyBumperBlackProp.addonpart
    preview =
    description =
    author_name = ohlidalp
    author_id = -1
    category_id = 8100
    guid = 057b21c8-cb54-496d-88ce-4855a8d6d43d
}

Under the hood, applying the addonparts to the vehicle works entirely in system memory, no truck files are modified or written.

ohlidalp commented 8 months ago

I added GUI for 'remove_prop' directives in .tuneup: obrazek

The '.tuneup' on display:

// This is a '.tuneup' mod - it's similar to '.skin' mod but deals with '.addonpart' mods.
// See https://github.com/RigsOfRods/rigs-of-rods/pull/3096#issuecomment-1783976601

Tuned 1990 Chevy 454ss
{
    preview = ABCD
    description = EFGT
    author_name = 
    author_id = -1
    category_id = 8100
    guid = 057b21c8-cb54-496d-88ce-4855a8d6d43d

    remove_prop = 454ss_Mirrors.mesh
    remove_prop = Kodiak_Windows.mesh
}
ohlidalp commented 8 months ago

I made the rusted bumper work, which means texture lookup works for .addonpart mods.

Prop-addons are now fully functional; Flexbody addons report "node not found" for all nodes at the moment.

See bottom posts for updated downloads.

obrazek

ohlidalp commented 8 months ago

Saving '.tuneup' presets now works. And I think the UI is not an embarrasement. I figured a nice confirmation mechanic - just hold the button for 1.5 sec and watch the countdown progressbar.

obrazek

ohlidalp commented 8 months ago

I added the concept of 'unwanted props/flexbodies' to addons and 'protected props/flexbodies' to tuneups.

The .addonpart file can now specify "unwanted" props or flexbodies, to simulate swapping of parts. Under the hood, this works by adding the mesh names to "remove" lists, same as if user disabled them from top menu. Example addonpart:

  ; Add the stock bumpers to 'tuneup.removed_flexbodies' unless user added it to 'tuneup.protected_flexbodies' first.
  addonpart_unwanted_flexbody "K3500_FBump.mesh"
  addonpart_unwanted_flexbody "454ss_FBump.mesh"

The .tuneup file now contains lists of "protected" props and flexbodies which cannot be removed by the addonpart and remain "removed" or not as the user wishes. This lets user force default meshes to be kept or addonpart meshes to not be added (may be useful if the addonpart specifies multiple meshes). Example of protected entry in .tuneup file:

    protected_flexbody = 454ss_FBump.mesh
    protected_flexbody = K3500_FBump.mesh

See bottom posts for updated downloads.

Meshes can be marked 'protected' via new widget in top menubar: obrazek

ohlidalp commented 8 months ago

By popular demand, I added 'tweaks' in the addonpart system. These directives let you modify existing elements.

There are 2 new directives in the addonpart format:

See bottom posts for updated downloads.

image

ohlidalp commented 7 months ago

I fixed the last big glitch and renamed the PR to advertise the new main feature. Originally the goal was an example truck editing script, which is present, but the main focus became an addon part system with UI, which doesn't use scripting.

new features so far

scripting extensions so far:

CuriousMike56 commented 7 months ago

In addition to the above, I've realized it is technically possible to create wheel addons that can be applied to almost any vehicle. Only real problem is the wheel side flag, as the direction the wheel mesh faces depends on the vehicle. Would be awesome if the wheel direction could be changed on-the-fly through the tuning menu.

ohlidalp commented 7 months ago

The design agreed on Discord https://discord.com/channels/136544456244461568/189904947649708032/1174499523901534218

  1. player spawns a clean car. UI shows each wheel with small "L/R" radio button and an "protected" checkbox on the right, like other things. The radiobutton is set to whatever's in the truckfile.
  2. player installs an addonpart with the generic wheels. tweak_wheel records are inserted to the .tuneup file. Radiobutton updates to whatever the addonpart did.
  3. player sees the rims are wrong and adjusts the radiobuttons. Internally this means updating the tweak_wheel entries that came from addonpart, which is possible as long as the "protected" flag is set for the wheels. This however also means that when user uninstalls the addonpart, the wheels will stay on. Alternatively I can add ui_fixups_* concept to the .tuneup format and scrap the whole "protected" flag system... I'll give it some more thought.

Ditto: https://discord.com/channels/136544456244461568/189904947649708032/1174464748461506634

addonpart_tweak_prop <prop ID> <offsetX> <offsetY> <offsetZ> <rotX> <rotY> <rotZ> <meshName>

ohlidalp commented 7 months ago

Tuneup format + UI change

All vehicle elements in the Tuning menu now show with numbers. They represent the order of definition in the truckfile, starting with 0. The removed/protected arrays in the .tuneup file now use these numbers (instead of mesh names), to cover cases where the same mesh is used multiple times.

New .addonpart features:

; PROP TWEAKS
; Media1 = prop mesh; Media2: Steering wheel mesh or beacon flare material.
addonpart_tweak_prop <prop ID> <offsetX> <offsetY> <offsetZ> <rotX> <rotY> <rotZ> <media1> <media2>

; FLEXBODY TWEAKS
addonpart_tweak_flexbody <flexbody ID> <offsetX> <offsetY> <offsetZ> <rotX> <rotY> <rotZ> <meshName>

This is an example flexbody tweak. Note that presently you must fill in all the parameters. In the future I'll add a null token to the GenericDocument so the params can be left undefined.

; 'addonpart_tweak_flexbody <flexbody ID> <offsetX> <offsetY> <offsetZ> <rotX> <rotY> <rotZ> <media1> <media2(optional)>'
addonpart_tweak_flexbody    0,             39, 62, 34,                  0.50,    0.32,  -0.5,          CHeavyBumper.mesh

For updated downloads, see bottom posts.

obrazek

ohlidalp commented 7 months ago

Added ability to flip rim meshes via UI

This overrides whatever is in 'addonpart_tweak_wheel'.

obrazek

ohlidalp commented 7 months ago

Things to fix in this PR:

Things for next time (UPDATE: see #3151):

ohlidalp commented 6 months ago

Reworked part removal via .tuneup + updated UI

All the UI overrides (removed flexbodies/flipped wheel rims) are now separate from any addonpart changes (tweaks or 'unwanted_*'). The 'protected' checkbox on the right just blocks addonpart changes, but isn't necessary for the UI overrides anymore. When you make an UI override, the respective widget will be outlined orange and a 'reset' button will be drawn.

In the .tuneup file, the UI overrides are called "forcesomething", while parts removed via addonparts are called 'unwantedsomething'.

KNOWN BUGS: Fixed in following commit. * Top menubar Tuning menu is only corrected for flexbodies, not props yet! * The forced flexbody removals are broken, they don't apply to the vehicle (wheel rim flips work OK, though).

obrazek

ohlidalp commented 5 months ago

Wrapping up

Almost all bugs are fixed, only minor glitches may be left. Technical overview with AngelScript docs: https://github.com/RigsOfRods/rigs-of-rods/pull/3096#issuecomment-1809055287. List of bugs to fix / features to leave for later: https://github.com/RigsOfRods/rigs-of-rods/pull/3096#issuecomment-1839678550

Below is a draft documentation.

The .addonpart mod type

There's a new mod type "Addon part" (file extension .addonpart) which automates the process of customizing a vehicle, previously requiring to manually edit files as you can read in https://docs.rigsofrods.org/tools-tutorials/addons/. The addonpart file format is similar to truck file format with added addonpart_* directives. In game, player can install addonparts using new menu "Tuning" in top menu bar.

Organizational info

Note: Preview images for selector UI (aka mini-images) are also supported.

Tweaking existing elements

'Tweaking' is the process of modifying existing elements. You use a directive addonpart_tweak_ABC followed by the target element's position in the truck file, numbered from 0. This is akin to how materialflarebindings work.

Parameters in [ ] are optional, leaving them out results in keeping original values. To omit an argument in between, use "" for string args or -1 for numeric args. This doesn't apply to positions and offsets, those are always required.

The 'media' can be meshes/materials (more types may come) depending on what the targeted element accepts.

Internally, the edits are applied in memory at last moment during spawn, files in mod cache are not affected.

Adding new elements

Just use the same syntax as in truck file, anywhere in the .addonpart file. Currently supported elements are props, flexbodies, managedmaterials.

Note that forset line MUST be in quotes, otherwise the parser will not read it whole. For example:

flexbodies
10,11,26,0.5,-1.17,-0.27,-90,180,0,Roll-Cage_MV4.mesh
"forset 0-110,141-177,238-239"

Supressing existing elements

These accept a single parameter - the target element's position in the truck file, numbered from 0.

The .tuneup mod type

This one is intentionally similar to .skin; it has the same structure and serves very similar purpose - applying addonparts and other user changes to a vehicle on spawn. The internal processing is also very similar. The game creates and edits these files automatically as the player uses the Tuning menu. Files are saved to Documents\My Games\Rigs of Rods\projects directory which is a newly introduced directory monitored by modcache (like 'mods') but intended for modding and tuning.

UPDATE: Only the user-saved tuneups are now stored to modcache (category ID 8001), the working tuneup instances are just in memory and individual to every spawned actor.

The tuning menu

obrazek

There's a new menu "Tuning" in the top menubar UI, which allows user to pick addonparts. Following paragraphs are a description of the UI, in top down order:

"Enable tuning" checkbox

Toggles cvar sim_tuning_enabled (persisted in RoR.cfg)

List of saved tuneups

Saved tuneups for current vehicle. Only created or modified on user request. When saving, the 'auto' (working) tuneup gets copied to the save; when loading, the 'auto' (working) tuneup gets overwritten by the save. Each line has [Delete] button in purplish color, indicating it's a "hold to confirm" type button.

The Save/Reset buttons

[Save] button shows a save box with text field to enter name.

[Delete] button has purplish color, indicating it's a "hold to confirm" type button.

List of installed addonparts

Each comes with a [Reload] button to reload the file from disk if you're modding it.

User overrides: props/flexbodies/wheels

Number: All vehicle elements in the Tuning menu now show with numbers. They represent the order of definition in the truckfile, starting with 0. The removed/protected arrays in the .tuneup file use these numbers (instead of mesh names), to cover cases where the same mesh is used multiple times.

Override checkbox: All the UI overrides (removed flexbodies/flipped wheel rims) are separate from any addonpart changes (tweaks or unwanted_*). When you make an UI override, the respective widget will be outlined orange and a 'reset' button will be drawn.

The 'protected' checkbox: (on the right) - Just blocks addonpart changes, doesn't affect the UI overrides in any way. Translates to protected_* directives in the .tuneup file.

In the .tuneup file, the UI overrides are called "force_something", while parts removed via addonparts are called 'unwanted_something'.

Updated addonparts to test

Mostly by @CuriousMike56

CuriousMike56 commented 5 months ago

✅ ✅