-
Notifications
You must be signed in to change notification settings - Fork 6
/
client_api.txt
258 lines (191 loc) · 8.03 KB
/
client_api.txt
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
Buildat Client API
==================
Lua code is run in two subtly different environments.
Interface common to both environments
=====================================
buildat.bytes(data) -> table<int>
buildat.dump(value) -> string
buildat.Logger(module_name) -> object
:error(message)
:warning(message)
:info(message)
:verbose(message)
:debug(message)
buildat.send_packet(name, data)
buildat.sub_packet(name, function)
buildat.unsub_packet(function)
buildat.run_script_file(name)
- Run script file gotten from server in sandbox environment
The extension environment
=========================
Extensions and the client boot-up code is run in the extension environment. It
is a raw Lua environment with no sandboxing or other rules.
Some of the sandbox-specific functions are not available or do not work normally
in the extension environment.
Extensions use the new Lua 5.1/5.2 module interface.
If an extension wish to provide an interface to sandboxed code, it should
implement table "safe", which contains the safe interface. When sandboxed code
requires the module, it only gets the plain safe interface.
Extensions and modules use require("buildat/extension/<name>") to get access to the interface of an extension.
If an extension wants to purely use the safe interface of an extension, it is
recommended to do this:
<name> = require("buildat/extension/<name>").safe
API specific to the extension environment:
buildat.connect_server(address)
- Address may include port in format "host:port" or "[host]:port"
buildat.extension_path(name)
The sandbox environment
=======================
All code sent by the server to the client is run in the sandbox environment.
Extensions are accessed by using require("buildat/extension/<name>"); this is
the equivalent of using require("buildat/extension/<name>").safe in the
extension environment.
API specific to the sandbox environment:
sandbox.make_global(table)
- Copies contents table into the current global sandbox environemnt. It will
still not leak into the scope of other files running in the sandbox. Useful if
you want to remove the "namespace table" of an extension.
buildat.disconnect()
- If connected from menu, quit to menu (client state is reset by restarting it)
- If connected from command line, close the client
Safe interfaces of built-in extensions
======================================
Use extensions in this way:
cereal = require("buildat/extension/cereal")
cereal.binary_output(...)
You can use sandbox.make_global like this:
sandbox.make_global(require("buildat/extension/urho3d"))
local scene = Scene()
cereal
------
cereal.binary_input(data: string, type: object) -> value: <ny>
cereal.binary_output(value: <any>, type: object) -> data: string
Example usage (by using an object as the base structure for value):
type = {"object",
{"a", "byte"},
{"b", "int32_t"},
{"c", "double"},
{"d", "string"},
{"e", {"array", "string"}},
{"f", {"object", {"x", "int32_t"}, {"y", "int32_t"}}}
}
input_value = {
a = 128,
b = 1000,
c = 3.14,
d = "Foo",
e = {"Bar1", "Bar2"},
f = {x=1, y=2},
}
data = cereal.binary_output(input_value, type)
-- Data can be now sent over network or be saved on disk
output_values = cereal.binary_input(data, type)
urho3d
------
Whitelist-based wrapper for the Urho3D Lua API.
NOTE: The whitelist is grossly incomplete. Please extend it and submit a pull
request. It is found in these files:
* extensions/urho3d/safe_globals.lua
* extensions/urho3d/safe_classes.lua
* extensions/urho3d/safe_events.lua
File paths and other things are converted automatically.
Additions to regular Urho3D:
SubscribeToEvent(event_name, callback)
- callback: function(event_type: string, event_data: VariantMap)
SubscribeToEvent(object, event_name, callback)
- callback: function(object, event_type: string, event_data: VariantMap)
- Callback can be a function, unlike in plain Urho3D where it must be a global
function name.
- Return value: Name of the generated global callback which can be unusbscbribed
from Urho3D via UnsubscribeFromEvent(event_name, callback_name).
replicate
---------
Interface to server->client synchronized (replicated) scenes.
Note:
There is a gotcha in scene replication: Resources are replicated by resource
name, meaning that resources like Materials and Models created or edited on
the server will not be replicated on the client.
If you wish to create or edit resources used by the replicated scene, you
can use urho3d.sub_sync_node_added() to listen to node additions and name or
otherwise augment your nodes in such a way that you can generate or set
resources to each node that requires it.
The sandbox wrapper adds the client-side components to the node using
urho3d.LOCAL by default, avoiding the problems of accidentally using
urho3d.REPLICATED on the client.
Make sure to not set anything to that resource of the node on the server
side, because then you will get unpredictable fighting between the one set
on server-side and client-side.
Example: games/entitytest/main/client_lua/init.lua
replicate.main_scene
- Main replicated scene instance. To show it on screen, add a camera and a
viewport. Add your local stuff to this as needed.
- You don't have to use this if you wish to synchronize your scene in a custom
way.
- CreateNode and CreateComponent uses urho3d.LOCAL by default unlike native
Urho3D. With urho3d.REPLICATED (native default) they will end up in the
synchronized ID space and will be overridden by data coming from the server.
ui_utils
--------
UI utiltiies.
show_message_dialog(message)
Unsafe interfaces of built-in extensions
========================================
urho3d
------
The unsafe interface consists of the namespace tables "safe" and "unsafe". Use
the safe interface unless the unsafe one is specifically needed:
require("buildat/extension/urho3d").safe
This enforces interoperability between modules and extensions.
If you get an error like this:
'Disallowed type: "userdata"; Allowed types: ...'
You probably are giving a non-sandboxed object to an interface that requires
sandboxed ones.
An actual unsafe Urho3D interface is available in:
require("buildat/extension/urho3d").unsafe
DO NOT USE the unsafe version of urho3d unless specifically needed. All
interfacing with other extensions and module code has to be done using the
sandboxed version in order to make interfacing possible between all of them.
The unsafe version of the urho3d extension actually just wraps to the global
environment, except for the additions to the API documented here.
Note that due to technical reasons Urho3D's non-sandboxed API is currently
always globally defined in the extension environment, but this will not be
supported in the future.
Additions to regular Urho3D:
SubscribeToEvent(event_name, callback)
- callback: function(event_type: string, event_data: VariantMap)
SubscribeToEvent(object, event_name, callback)
- callback: function(object, event_type: string, event_data: VariantMap)
- Callback can be a function, unlike in plain Urho3D where it must be a global
function name.
- Return value: Name of the generated global callback which can be unusbscbribed
from Urho3D via UnsubscribeFromEvent(event_name, callback_name).
Miscellaneous
=============
You can create a client-side voxel registry like this:
local voxel_reg = buildat.createVoxelRegistry()
local atlas_reg = buildat.createAtlasRegistry()
do
local vdef = buildat.VoxelDefinition()
vdef.name.block_name = "rock"
vdef.name.segment_x = 0
vdef.name.segment_y = 0
vdef.name.segment_z = 0
vdef.name.rotation_primary = 0
vdef.name.rotation_secondary = 0
vdef.handler_module = ""
local textures = {}
for i = 1, 6 do
local seg = buildat.AtlasSegmentDefinition()
seg.resource_name = "main/rock.png"
seg.total_segments = magic.IntVector2(1, 1)
seg.select_segment = magic.IntVector2(0, 0)
table.insert(textures, seg)
end
vdef.textures = textures
vdef.edge_material_id = buildat.VoxelDefinition.EDGEMATERIALID_GROUND
vdef.physically_solid = true
voxel_reg:add_voxel(vdef)
voxel_reg:add_voxel(vdef)
voxel_reg:add_voxel(vdef)
voxel_reg:add_voxel(vdef)
end