godot-rust / godot-rust/gdext

Virtual `#[func]` in `#[godot_dyn]` traits

Open
#1,231 9 comments 0 reactions 0 assignees View on GitHub
c: register quality-of-life
Dominant language
Rust
Stars
5.2k
Forks
312
Avg merge
11h 10m
Merged PRs (30d)
10

Description

Context:
im doing multiplayer game networking (and taking a lot of inspiration from how [netfox](github.com/foxssake/netfox) is doing things)
However, netfox abuses gdscript's dynamic typing to handle rollback like this

```GDScript
## Checks if a given object is rollback-aware, i.e. has the
## [code]_rollback_tick[/code] method implemented.
##
## This is used by [RollbackSynchronizer] to see if it should simulate the
## given object during rollback.
func is_rollback_aware(what: Object) -> bool:
return what.has_method(&"_rollback_tick")

## Calls the [code]_rollback_tick[/code] method on the target, running its
## simulation for the given rollback tick.
## [br][br]
## This is used by [RollbackSynchronizer] to resimulate ticks during rollback.
## While the [code]_rollback_tick[/code] method could be called directly as
## well, this method exists to future-proof the code a bit, so the method name
## is not repeated all over the place.
## [br][br]
## [i]Note:[/i] Make sure to check if the target is rollback-aware, because if
## it's not, this method will run into an error.
func process_rollback(target: Object, delta: float, p_tick: int, is_fresh: bool) -> void:
target._rollback_tick(delta, p_tick, is_fresh)
```

I feel like it would nice if I could implement this in Rust instead

I should also mention what I’d like to do is have an array of all rollbackable objects and call “rollback_tick” on them
So something like
```rust
#[derive(GodotClass)]
#[class(init, base=Node)]
struct Container {
list: Array>,
base: Base,
}

#[godot_api]
impl INode for Container{
fn process(&mut self, delta: f64) {
for node in self.list {
node.rollback_tick(delta);
}
}
}
```

The api should look something like this (as provided by @Yarwin on discord)

```rust
#[godot_dyn]
impl Rollbackable for MyNode {
#[func]
fn rollback_tick(&self, delta: f32, p_tick: i64, is_fresh: bool){
godot_print!("hello from macro impl!");
}
}
```

This should result in something like

![image](https://github.com/user-attachments/assets/02e126ca-4b29-47e3-b1b5-7171b22d2636)

Contributor guide

Open the contributing guide

Research direction

Start with the existing #[godot_dyn] and #[func] macro entry points, then inspect how DynGd is intended to dispatch trait methods. Use the proposed Rollbackable and Container example as the acceptance case; done means the virtual method can be stored and called through the collection from Rust.

Written by the indexing model from the issue text.

Assessment

Tech stack
godot, rust
Domain
devtools, game-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.