This guide will show you how you can declare a generic callback thanks to Codeware's reflection.
Requirements
You need Codeware (Nexus | Wiki) to use the following classes. It provides a Reflection module which is exactly what we need to make our callback in a generic way.
How to
We will declare two classes: Callback to use with methods of a class, and StaticCallback to use with static methods of a class.
Callback
Declaration
import Codeware.*
public class Callback extends DelayCallback {
private let m_target: wref<IScriptable>;
private let m_fn: CName;
private let m_data: array<Variant>;
public static func Create(target: wref<IScriptable>, fn: CName, opt data: array<Variant>) -> ref<Callback> {
let self = new Callback();
self.m_target = target;
self.m_fn = fn;
self.m_data = data;
return self;
}
public func Call() {
if !IsDefined(this.m_target) {
return;
}
Reflection.GetClassOf(this.m_target)
.GetFunction(this.m_fn)
.Call(this.m_target, this.m_data);
}
}
We declare Callback which inherits DelayCallback. This way we can use Callback if we need it as-is, and we can also use it with DelaySystem.
We implement the method Call() which is expected by DelaySystem / DelayCallback. If we want to use it without DelaySystem, we simply need to call Call() when we want to execute a callback by ourself.
Example
public class MyService extends ScriptableService {
// ...
public cb func OnSessionReady(event: ref<GameSessionEvent>) {
if event.IsPreGame() {
return;
}
let delaySystem = GameInstance.GetDelaySystem(GetGameInstance());
let callback = Callback.Create(this, n"OnPlay", [42]);
let delay: Float = 1.0; // seconds
delaySystem.DelayCallback(callback, delay, false);
// callback.Call();
}
// [cb] is required to make function a callback.
// [arg] is an optional argument which can be passed when calling [Callback.Create].
private cb func OnPlay(arg: Int32) {
FTLog(s"arg: \(arg)");
// do stuff after [delay] s.
}
}
StaticCallback
Declaration
public class StaticCallback extends DelayCallback {
private let m_fn: CName;
private let m_data: array<Variant>;
public static func Create(fn: CName, opt data: array<Variant>) -> ref<StaticCallback> {
let self = new StaticCallback();
self.m_fn = fn;
self.m_data = data;
return self;
}
public func Call() {
Reflection.GetGlobalFunction(this.m_fn)
.Call(this.m_data);
}
}
This looks like Callback, we still inherits DelayCallback to be compatible with DelaySystem. But this time we only need a function's name.
Static methods of a class are registered as global functions. You'll need to use this syntax: n"ModuleName.ClassName::MethodName". Method must be declared with keyword cb. ModuleName is optional.
Example
This shows how it looks like when declaring in a custom module MyModule. It is not mandatory and you can declare it in the global scope.
module MyModule
public class MyService extends ScriptableService {
// ...
public cb func OnSessionReady(event: ref<GameSessionEvent>) {
if event.IsPreGame() {
return;
}
let delaySystem = GameInstance.GetDelaySystem(GetGameInstance());
let callback = StaticCallback.Create(n"MyModule.MyService::OnPlay", [n"Choom"]);
let delay: Float = 1.0; // seconds
delaySystem.DelayCallback(callback, delay, false);
// callback.Call();
}
// [cb] is required to make function a callback.
// [name] is an optional argument which can be passed when calling [StaticCallback.Create].
private static cb func OnPlay(name: CName) {
FTLog(s"name: \(name)");
// do stuff after [delay] s.
}
}