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

AngelScript: FreeForces (with a PartyBaloon demo mod) #3159

Merged
merged 2 commits into from
Aug 4, 2024

Conversation

ohlidalp
Copy link
Member

@ohlidalp ohlidalp commented Jun 17, 2024

FreeForces are global, persistent forces which act upon one node of one actor each. They exist separately from actors and their existing hook/tie/rope interactions. This means they do not interfere with actor N/B or any of the existing linking logic. They're intended for creating special physics effects which aren't supported otherwise, like making party baloons fly. They're intentionally only accessible from scripts to maximize their flexibility and limit maintenance of the codebase.

desperadoBaloonsV2

To manage FreeForces, you use game.pushMessage() with MSG_SIM_ADD_FREEFORCE_REQUESTED, MSG_SIM_MODIFY_FREEFORCE_REQUESTED or MSG_SIM_REMOVE_FREEFORCE_REQUESTED.

Parameters common to ADD/MODIFY requests:

  • 'id' (int) - unique ID of this freeforce, use game.getFreeForceNextId() to obtain an unique sequential ID.
  • 'type' (FreeForceType) - One of FREEFORCETYPE_DUMMY, FREEFORCETYPE_CONSTANT, FREEFORCETYPE_TOWARDS_COORDS, FREEFORCETYPE_TOWARDS_NODE
  • 'base_actor' (int) - Unique actor instance ID, obtain it by game.getCurrentTruck().getInstanceId(), or if you're in an actor-script, then you can do thisActor.getInstanceId() // BeamClass@ thisActoris automatic global variable for scripts bound to actors.
  • 'base_node' (int) - Node number (0 - 65535)
  • 'force_magnitude' (float) - the amount of force to apply, in Newton/meters Parameters for FREEFORCETYPE_CONSTANT:
  • 'force_const_direction' (vector3) - constant force direction. Note that Y=up, so to make things float, use vector3(0, 1, 0).

Additional parameters for FREEFORCETYPE_TOWARDS_COORDS:

  • 'target_coords' (vector3) - world position to target. For example game.getPersonPosition() will target it at position where character is standing AT THE MOMENT.

Additional parameters for FREEFORCETYPE_TOWARDS_NODE:

  • 'target_actor' (int) - Unique actor instance ID.
  • 'target_node' (int) - Node number (0 - 65535).

Note when any of the actors involved in a FreeForce (be it the base one or target one), the freeforce is deleted.

Example from the PartyBaloon demo mod:

    // Create the up-force
    upforce_assigned_id = game.getFreeForceNextId();
    game.pushMessage(MSG_SIM_ADD_FREEFORCE_REQUESTED, {
        {'id', upforce_assigned_id },
        {'type', FREEFORCETYPE_CONSTANT },
        {'base_actor', thisActor.getInstanceId() },  // `BeamClass@ thisActor`is automatic global variable for scripts bound to actors.
        {'base_node', UPFORCE_NODE },
        {'force_const_direction', vector3(0, 1, 0) }, // Y=up
        {'force_magnitude', 0.4f } // Newton/meters
    });

Keep in mind that the physics simulation runs at 2khz (2000 steps per second), while scripts run in sync with FPS. That's why there's no option to add temporary/one-off force impulses from scripts - you are responsible for adding the persistent force, monitoring and adjusting it as needed, and then removing it when no longer necessary. You can create the forces as dummy and then change their type later as needed.

Below is the demo PartyBaloon mod. It weights only 12 grams (0.012 Kg) and under our simulation it moves very slowly, not bypasing a certain threshold, regardless of pull force applied to it. By default, it will just fly off (you can grab it with mouse) but you can use console variables to bind it somewhere:
obrazek
The script bundled with the baloon will read these variables and create an additional FreeForce towards either the spawn position or given node on given actor.
Download PartyBaloon-12grams.zip

Have fun!

@Miner34dev
Copy link

Not sure why, but game.getCurrentTruck().getInstanceId() doesn't work (trows an error) and i don't know what actor is the car to attach the baloon to. I don't think it was broken by this PR, it's months the entire angelscript panel (together with any getCurrentTruck() related command) don't work in dev builds.

@ohlidalp
Copy link
Member Author

@Miner34dev That's a quirk of our present reference-counting mechanism, sorry about that, I haven't yet found a way to fix it. You must do either game.getCurrentTruck().getHandle().getInstanceId() or BeamClass@ b = game.getCurrentTruck(); b.getInstanceId() because the return type isn't BeamClass@ but rather BeamClassPtr@ More info is at https://github.com/ohlidalp/RefCountingObject-AngelScript

@Miner34dev
Copy link

How does this affect performance? I have to apply a force to over 500 nodes, is it going to make me lag/crash?

@Miner34dev
Copy link

How does this affect performance? I have to apply a force to over 500 nodes, is it going to make me lag/crash?

Tested it out, it's completely fine (at least if i add the force at the start and then leave it untouched.)

@Miner34dev
Copy link

Miner34dev commented Jul 1, 2024

I'm having a problem with FREEFORCETYPE_TOWARDS_COORDS (i haven't tested with the other ones though), i can't change anything withMSG_SIM_MODIFY_FREEFORCE_REQUESTED, it has no effect. The modification is called from frameStep(). Am i doing something wrong, or is this a bug?

@ohlidalp
Copy link
Member Author

ohlidalp commented Jul 3, 2024

@Miner34dev I tested your scenario and sure enough, the force isn't getting updated. UPDATE: fixed.

My test script is below, I used it with 'Slalom Cone' load from Auriga map. To use the script, put it to directory 'Documents/My Games\Rigs of Rods\scripts'.
example_freeforce_movingPoint.zip

FreeForces are global, persistent forces which act upon one node of one actor each. They exist separately from actors and their existing hook/tie/rope interactions. This means they do not interfere with actor N/B or any of the existing linking logic. They're intended for creating special physics effects which aren't supported otherwise, like making party baloons float. They're intentionally only accessible from scripts to maximize their flexibility and limit maintenance of the codebase.

Keep in mind that the physics simulation runs at 2khz (2000 steps per second), while scripts run in sync with FPS. That's why there's no option to add temporary/one-off force impulses from scripts - you are responsible for adding the persistent force, monitoring and adjusting it as needed, and then removing it when no longer necessary. You can create the forces as dummy and then change their type later as needed.

To manage FreeForces, you use `game.pushMessage()` with `MSG_SIM_ADD_FREEFORCE_REQUESTED`, `MSG_SIM_MODIFY_FREEFORCE_REQUESTED` or `MSG_SIM_REMOVE_FREEFORCE_REQUESTED`.
Parameters common to ADD/MODIFY requests:
* 'id' (int) - unique ID of this freeforce, use `game.getFreeForceNextId()` to obtain an unique sequential ID.
* 'type' (FreeForceType) - One of `FREEFORCETYPE_DUMMY`, `FREEFORCETYPE_CONSTANT`, `FREEFORCETYPE_TOWARDS_COORDS`, `FREEFORCETYPE_TOWARDS_NODE`
* 'base_actor' (int) - Unique actor instance ID, obtain it by `game.getCurrentTruck().getInstanceId()`, or if you're in an actor-script, then you can do `thisActor.getInstanceId()` // `BeamClass@ thisActor`is automatic global variable for scripts bound to actors.
* 'base_node' (int) - Node number (0 - 65535)
* 'force_magnitude' (float) - the amount of force to apply, in Newton/meters
Parameters for `FREEFORCETYPE_CONSTANT`:
* 'force_const_direction' (vector3) - constant force direction. Note that  Y=up, so to make things float, use vector3(0, 1, 0).
Parameters for `FREEFORCETYPE_TOWARDS_COORDS`:
* 'target_coords' (vector3) - world position to target. For example `game.getPersonPosition()` will target it at position where character is standing AT THE MOMENT.
Parameters for `FREEFORCETYPE_TOWARDS_NODE`:
* 'target_actor' (int) - Unique actor instance ID.
* 'target_node' (int) - Node number (0 - 65535).

Note when any of the actors involved in a FreeForce (be it the base one or target one), the freeforce is deleted.

Example from the PartyBaloon demo mod:
```
    // Create the up-force
    upforce_assigned_id = game.getFreeForceNextId();
    game.pushMessage(MSG_SIM_ADD_FREEFORCE_REQUESTED, {
        {'id', upforce_assigned_id },
        {'type', FREEFORCETYPE_CONSTANT },
        {'base_actor', thisActor.getInstanceId() },  // `BeamClass@ thisActor`is automatic global variable for scripts bound to actors.
        {'base_node', UPFORCE_NODE },
        {'force_const_direction', vector3(0, 1, 0) }, // Y=up
        {'force_magnitude', 0.4f } // Newton/meters
    });
```
@CuriousMike56
Copy link
Collaborator

Forces work OK, not entirely sure how to attach the balloon to a vehicle though. The above script only works once, trying to remove gives "ID not found":
image

@ohlidalp
Copy link
Member Author

ohlidalp commented Jul 8, 2024

@CuriousMike56

The above script only works once, trying to remove gives "ID not found":

Script is broken, I'll fix it and add it to 'examples'.

not entirely sure how to attach the balloon to a vehicle though

You need to type out the console variables which the baloon script reads on spawn. In this case, I typed

setint partybaloon_bind_actor 1
setint partybaloon_bind_node 159

obrazek

@ohlidalp ohlidalp merged commit edb9484 into RigsOfRods:master Aug 4, 2024
2 checks passed
@ohlidalp ohlidalp deleted the freeforces branch August 4, 2024 12:31
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.

3 participants