-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
jatum.dm
221 lines (192 loc) · 5.88 KB
/
jatum.dm
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
// JATUM. System for making the serializing and deserializing of PoD types easier
/**
* Gets the flat list that can be passed in a `new /type(argslist(retval))` expression to recreate the datum. Must only return a list containing values that can be JATUM serialized
*/
/datum/proc/jatum_new_arglist()
return null
/// The JATUM version used for serializing and deserializing
#define JATUM_VERSION 1
/**
* Attempt to serialize a given value to the JATUM format.
*
* * value - The var to serialize.
*/
/world/proc/jatum_serialize(value)
var/list/json_structure
try
json_structure = _jatum_serialize_value(value, list())
catch(var/exception/e)
CRASH(e)
return json_encode(list(
"jatum\\version" = JATUM_VERSION,
"content" = json_structure
))
/world/proc/_jatum_serialize_value(value, list/seen_references)
if(isnull(value))
return null
if(isnum(value) || istext(value))
return list(
"type" = "jatum\\raw",
"value" = value
)
if(ispath(value))
return list(
"type" = "jatum\\path",
"path" = value
)
var/ref = "\ref[value]"
var/existing_ref = seen_references[ref]
if(existing_ref)
return list(
"type" = "jatum\\ref",
"jatum\\id" = existing_ref)
// Simple incrementing ID system
var/ref_id = seen_references.len + 1
seen_references[ref] = ref_id
if(istype(value, /matrix)) // matricies work with json_encode so use a custom arglist
return list(
"jatum\\id" = ref_id,
"type" = "/matrix",
"jatum\\new_arglist" = _jatum_serialize_value(json_decode(json_encode(value))), seen_references)
if(istype(value, /savefile)) // Just store the path, rely on BYOND for the rest
var/savefile/save = value
return list(
"jatum\\id" = ref_id,
"type" = "/savefile",
"jatum\\new_arglist" = _jatum_serialize_value(list(save.name), seen_references)
)
if(istype(value, /regex)) // store construct params
var/regex/rx = value
return list(
"jatum\\id" = ref_id,
"type" = "/regex",
"name" = rx.name,
"flags" = rx.flags
)
if(islist(value))
// Serialize all lists as dicts, list("a") and list("a" = null) can't be differentiated in DM
var/list_contents = list()
for(var/key in value)
var/got_l_value
var/l_value
try
l_value = value[key]
got_l_value = TRUE
catch
// Expected, indicates a flat list
if(got_l_value)
list_contents += list(list(
"key" = _jatum_serialize_value(key, seen_references),
"value" = _jatum_serialize_value(l_value, seen_references)
))
else
list_contents += list(list(
"value" = _jatum_serialize_value(key, seen_references)
))
return list(
"jatum\\id" = ref_id,
"type" = "/list",
"contents" = list_contents)
// JATUM is really only meant for PoD types
if(!istype(value, /datum)\
|| istype(value, /image)\
|| istype(value, /icon)\
|| istype(value, /sound)\
|| istype(value, /atom)\
|| istype(value, /mutable_appearance)\
|| istype(value, /client)\
|| istype(value, /database))
CRASH("Incompatible type for JATUM: [value]([ref])")
// Confirmed /datum type
var/datum/D = value
var/json_structure = list(
"jatum\\id" = ref_id,
"type" = "[D.type]"
)
var/new_arglist = D.jatum_new_arglist()
if(new_arglist)
if(!islist(new_arglist))
CRASH("Non-list return from jatum_new_arglist from [D.type]!")
json_structure["jatum\\new_arglist"] = _jatum_serialize_value(new_arglist, seen_references)
for(var/var_name in D.vars)
if(var_name == "vars" || var_name == "parent_type" || var_name == "type")
continue
var/d_value = D.vars[var_name]
json_structure[var_name] = _jatum_serialize_value(d_value, seen_references)
return json_structure
/**
* Attempt to create a value from a JATUN JSON.
*
* * json - The JSON to deserialize.
*/
/world/proc/jatum_deserialize(json)
if(!istext(json))
CRASH("Non-text passed!")
var/list/structure = json_decode(json)
if(!structure)
CRASH("Invalid JSON!")
var/jatum_version = structure["jatum\\version"]
if(isnull(jatum_version))
CRASH("Not JATUM JSON!")
if(jatum_version != JATUM_VERSION)
CRASH("Incompatible JATUM_VERSION")
try
return _jatum_deserialize_value(structure["content"], list())
catch(var/exception/e)
CRASH(e)
/world/proc/_jatum_deserialize_value(list/structure, list/active_references)
if(!structure)
return null
var/ref_id = structure["jatum\\id"]
var/entry_type = structure["type"]
switch(entry_type)
if("jatum\\raw")
return structure["value"]
if("jatum\\path")
var/string_path = structure["path"]
var/path = text2path(string_path)
if(!path)
CRASH("Invalid path: [string_path]")
return path
if("jatum\\ref")
var/result = active_references[ref_id]
if(!result)
CRASH("Missing reference ID [ref_id]!")
return result
if("/regex")
var/name = structure["name"]
var/flags = structure["flags"]
if(flags)
. = new /regex(name, flags)
else
. = new /regex(name)
if("/list")
var/list_contents = structure["contents"]
. = list()
for(var/entry in list_contents)
var/key = entry["key"]
var/l_value = entry["value"]
if(key)
.[_jatum_deserialize_value(key, active_references)] = _jatum_deserialize_value(l_value, active_references)
else
. += _jatum_deserialize_value(l_value, active_references)
else
// everything else is a /datum and instantiates via reflection
var/list/jatum_arglist = structure["jatum\\new_arglist"]
var/full_type = text2path(entry_type)
if(!full_type)
CRASH("Invalid type: [entry_type]")
if(jatum_arglist)
var/list/new_arglist = _jatum_deserialize_value(jatum_arglist, active_references)
. = new full_type(arglist(new_arglist))
else
. = new full_type
var/datum/D = .
for(var/var_name in structure)
if(var_name == "type"\
|| var_name == "jatum\\id"\
|| var_name == "jatum\\new_arglist")
continue
var/value = structure[var_name]
D.vars[var_name] = _jatum_deserialize_value(value, active_references)
active_references["[ref_id]"] = .