How to allow others to set the timestamping method for a input signaling class?

Godot Version

v4.6

Question

I’m new to Godot, so I might miss things that might be common sense for this game engine.

For context, I wrote a input system because the input mapping system that comes with Godot doesn’t allow specific things I wanted. This is a “sensor” class that processes a input value if a appropriate input event can be found:

class_name InputSensor extends Node

# Note that timestamp uses Variant to address int and float types.
signal input_recognized(timestamp: Variant, value_name: String, value: Variant)

@export var values: Dictionary[String, InputValue]

func _ready():
	for value_name: String in values:
		values[value_name].reset(values[value_name].root_method)

func _input(event: InputEvent):
	var timestamp: int = Time.get_ticks_msec()
	for value_name: String in values:
		var value: Variant = values[value_name].evaluate_value(event, values[value_name].root_method)
		if value != null:
			input_recognized.emit(timestamp, value_name, value)
			break

I got to the point where I wanted the signal to record the time where the input was recognized, so a person that decides to program their own input buffer could listen to the signal on their class and record it into a array or dictionary for stuff like detecting 2 simultaneously pressed keys for a in-game action. As far as I know, I can’t find something that fits this description that is called like Time.get_ticks_msec() or Time.get_ticks_usec().

I thought that a person might want to have a in-game timestamp function that returns the elapsed time of a level which also reflects if the game is in a paused state or the timescale has been changed, so ideally they would be able to somehow tell my class to use a function’s output as a timestamp. However, I don’t know how to implement this.

There’s also a separate concern that if my class should have each instance act as a input map or be consolidated into a collection of input maps, because that has relevance to if the timestamp function that gets used should be applied to certain instances matching expected conditions or all existing instances in the scene tree. I can think of a person using 1 instance for gameplay, and another for pause menu navigation, however I think this concern is teetering out of relevancy to the main question.

Usually for timestamps you would use something like
Time.float get_unix_time_from_system() const
Time — Godot Engine (stable) documentation in English text`

There are other methods that give you date/time but this one can handle subsecond precision.

You could give a string export to find which callable to use, though selecting which object to reference may be hard

@export var time_function_name: String = "ticks"

var time_function: Callable

func _ready() -> void:
    time_function = Callable(self, time_function_name)
    # then use time_function.call()

func ticks() -> int:
    return Time.get_ticks_msec()

Not sure what your building on top of the input system though, what brought this on in the first place, what specific things couldn’t you do with the input mapping system? In case this really is a large XY problem

Accumulate time in _process() and use that as a stamp.

I think my initial post was more like a disorganized concern dump than a clear, direct question, sorry all.

The question I’m trying to find answers to is that I don’t know good practices on how to tell a instance to use a certain function from a script/class or some node with a script attached to it.

I didn’t know this was a legitimate method to get a timestamp for that situation. I appreciate it.

This seems to work. I’ll just write out what I did for the other folks passing by.
I wrote this simple accumulating timer just to test:

class_name Clock extends Node

var time: float = 0

func _process(delta: float):
	time += delta

func get_time() -> float:
	return time

I modified my class as well to have a reference to the node and function name:

@export var values: Dictionary[String, InputValue]
@export var clock: Node
@export var function_name: String = "get_time"
var timestamper: Callable

func _ready():
	if clock != null:
		timestamper = Callable(clock, function_name)
	for value_name: String in values:
		values[value_name].reset(values[value_name].root_method)

func _input(event: InputEvent):
	var timestamp: Variant = timestamper.call() if timestamper != null else Time.get_ticks_msec()
	for value_name: String in values:
		var value: Variant = values[value_name].evaluate_value(event, values[value_name].root_method)
		if value != null:
			input_recognized.emit(timestamp, value_name, value)
			break

I needed to assign the clock script to a node, and drag that node into the clock variable slot on my node using my InputSensor class for it to work.

I understand your concerns regarding the XY problem, it’s well warranted. I only mentioned the input system vaguely because I believe the only thing concerning it was how to tell the script to use a function that isn’t in itself. If I didn’t make the input system at all and was using the input map, I doubt that much would change as I would be eventually asking the same thing; how to point the script to use a function which produces a timestamp desired by the user, with the input map taking my input system’s place in the context.

1 Like

Why do you need the clock node/class when you can just incorporate that functionality into time stamper class.

That “time stamper class” is the class that recognizes input. Or senses, whatever way you want to put it.

If I wanted to consolidate timestamping functionality and didn’t care about leaving what timestamping method the user wants to use, I would’ve done so. The clock node in that post is serving as a class to hook up to, just as a example.

Personally, I think doing it that way isn’t appropriate because I don’t think systems that serve as modules (my input system in this case) should have its user go poke around in the code just to change what kind of timestamping method it’d use. Having it in that way also means you couldn’t apply separate timestamping methods on 2 InputSensor instances serving as a input action map because it’d be hardcoded to only use logic taken out of the clock class, which doesn’t allow the user to set it to whatever they want.

Look, I sense you’re suspicious of me, which I would bet it’s possibly due to some kind of discrepancy between that code block I provided in my OP and me not knowing how to access a function from another node via a string name. I’ve read exactly the part where you said from another post:

I understand the sentiment and I can agree with this conclusion. However, I can’t learn what I don’t know if you play coy as you stated; because I won’t know what you’re thinking until you elaborate:

We could probably move to direct messages, seeing as this topic is already solved.