-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathdecorators.ts
More file actions
172 lines (161 loc) · 6.4 KB
/
decorators.ts
File metadata and controls
172 lines (161 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/**
* Expose as a godot class.
* An class object is created and attached automatically when construct an instance from this class
*/
export function gdclass<T extends godot.Object>(target: new() => T) {
const id = gdclass['internal_class_id'] = gdclass['internal_class_id'] ? gdclass['internal_class_id'] + 1 : 1;
const class_name = `AnonymousJSClass${id}`;
godot.register_class(target, class_name);
}
/** Set the script is runable in editor */
export function tool<T extends godot.Object>(target: new() => T) {
godot.set_script_tooled(target, true);
}
/** Set the script icon */
export function icon<T extends godot.Object>(icon) {
return function (target: new() => T) {
godot.set_script_icon(target, icon);
}
}
/** Register signal to godot script */
export function signal(target: godot.Object | (new() => godot.Object), property: string, descriptor?: any) {
var constructor: Function = typeof(target) === 'function' ? target : target.constructor;
var prototype: object = constructor.prototype;
godot.register_signal(target, property);
descriptor = descriptor || {};
(descriptor as PropertyDescriptor).value = property;
(descriptor as PropertyDescriptor).writable = false;
Object.defineProperty(constructor, property, descriptor);
Object.defineProperty(prototype, property, descriptor);
}
/**
* Register property to godot class
* @param value The default value of the property
*/
export function property<T extends godot.Object>(info: godot.PropertyInfo) {
return function (target: T, property: string, descriptor?: any) {
info = info || {};
godot.register_property(target, property, info);
return descriptor;
}
}
/**
* Return the node with `path` if the `_onready` is called
* @param path The path or the type to get the node
*/
export function onready<T extends godot.Node>(path: string | (new()=>godot.Node)) {
return function (target: T, property: string, descriptor?: any) {
const key = `$onready:${property}`;
descriptor = descriptor || {};
descriptor.set = function(v) { this[key] = v; };
descriptor.get = function() {
let v = this[key];
if (!v) {
v = (this as godot.Node).get_node(path as (new()=>godot.Node));
this[key] = v;
}
return v;
};
return descriptor;
}
}
/**
* Register the member as a node property
* **Note: The value is null before current node is ready**
* @param path The default path name of the node
*/
export function node<T extends godot.Node>(target: T, property: string, descriptor?: any) {
const key = `$onready:${property}`;
const path_key = `${property} `; // <-- a space at the end
descriptor = descriptor || {};
descriptor.set = function(v) { this[key] = v; };
descriptor.get = function() {
let v = this[key];
if (!v) {
v = (this as godot.Node).get_node(this[path_key]);
this[key] = v;
}
return v;
};
godot.register_property(target, path_key, { type: godot.TYPE_NODE_PATH });
return descriptor;
}
/**
* Register an enumeration property
* @param enumeration Enumeration name list
* @param default_value The default value of the property
*/
export function enumeration<T extends godot.Object>(enumeration: string[], default_value?: string|number) {
return function (target: T, property: string, descriptor?: any) {
const pi: godot.PropertyInfo = {
hint: godot.PropertyHint.PROPERTY_HINT_ENUM,
type: typeof(default_value) === 'string' ? godot.TYPE_STRING : godot.TYPE_INT,
hint_string: '',
default: typeof(default_value) === 'string' ? default_value : 0
};
for (let i = 0; i < enumeration.length; i++) {
pi.hint_string += enumeration[i];
if (i < enumeration.length - 1) {
pi.hint_string += ',';
}
}
godot.register_property(target, property, pi);
return descriptor;
}
}
function make_rpc_mode_config_decorator(mode: godot.MultiplayerAPI.RPCMode) {
return function <T extends godot.Node>(target: T, property: string, descriptor?: any) {
const is_method = typeof target[property] === 'function';
const original_ready = target._ready;
target._ready = function (this: godot.Node) {
if (is_method) this.rpc_config(property, mode);
else this.rset_config(property, mode);
if (original_ready) return original_ready.call(this);
};
return descriptor;
}
}
/**
* Used with `Node.rpc_config` or `Node.rset_config` to set a method to be called or
* a property to be changed only on the remote end, not locally.
* Analogous to the `remote` keyword. Calls and property changes are accepted from all
* remote peers, no matter if they are node's master or puppets.
*/
export const remote = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_REMOTE)
/**
* Used with `Node.rpc_config` or `Node.rset_config` to set a method to be called or
* a property to be changed only on the network master for this node.
* Analogous to the `master` keyword. Only accepts calls or property changes from the
* node's network puppets, see `Node.set_network_master`.
*/
export const master = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_MASTER)
/**
* Used with `Node.rpc_config` or `Node.rset_config` to set a method to be called or
* a property to be changed only on puppets for this node.
* Analogous to the `puppet` keyword. Only accepts calls or property changes from the
* node's network master, see `Node.set_network_master`.
*/
export const puppet = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_PUPPET)
/**
* @deprecated Use `RPC_MODE_PUPPET` (@puppet) instead. Analogous to the `slave` keyword.
*/
export const slave = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_SLAVE)
/**
* Behave like `RPC_MODE_REMOTE` (@remote) but also make the call or property change locally.
* Analogous to the `remotesync` keyword.
*/
export const remote_sync = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_REMOTESYNC)
/**
* @deprecated Use `RPC_MODE_REMOTESYNC` (@remote_sync) instead. Analogous to the `sync` keyword
*/
export const sync = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_REMOTESYNC)
/**
* Behave like `RPC_MODE_MASTER` (@master) but also make the call or property change locally.
* Analogous to the `mastersync` keyword.
*/
export const master_sync = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_MASTERSYNC)
/**
* Behave like `RPC_MODE_PUPPET` (@puppet) but also make the call or property change locally.
* Analogous to the `puppetsync` keyword.
*/
export const puppet_sync = make_rpc_mode_config_decorator(godot.MultiplayerAPI.RPC_MODE_PUPPETSYNC)