7#define JSMN_PARENT_LINKS
12 memset(building, 0,
sizeof(
Building));
28static bool json_token_streq(
const char *json,
const jsmntok_t *token,
const char *s)
35static int jsonint(
const char *json,
const jsmntok_t *token)
41 strncpy(temp, json + token->
start, len);
47static bool jsonbool(
const char *json,
const jsmntok_t *token)
49 if (json_token_streq(json, token,
"true"))
57static int skip_token_tree(
const jsmntok_t *tokens,
int token_count,
int index)
59 if (index >= token_count)
70 int children_count = tokens[index].
size;
71 int next_index = index + 1;
72 for (
int i = 0; i < children_count; i++)
74 if (next_index >= token_count)
81 next_index = skip_token_tree(tokens, token_count, next_index);
82 next_index = skip_token_tree(tokens, token_count, next_index);
87 next_index = skip_token_tree(tokens, token_count, next_index);
102 if (json_token_streq(json, token,
"id"))
104 if (json_token_streq(json, token,
"building_required"))
106 if (json_token_streq(json, token,
"can_enter"))
108 if (json_token_streq(json, token,
"center_x"))
110 if (json_token_streq(json, token,
"center_y"))
112 if (json_token_streq(json, token,
"collision_count"))
114 if (json_token_streq(json, token,
"collisions"))
116 if (json_token_streq(json, token,
"description_id"))
118 if (json_token_streq(json, token,
"flags"))
120 if (json_token_streq(json, token,
"health"))
122 if (json_token_streq(json, token,
"name_id"))
124 if (json_token_streq(json, token,
"race"))
126 if (json_token_streq(json, token,
"resources"))
128 if (json_token_streq(json, token,
"slot_count"))
130 if (json_token_streq(json, token,
"shadow"))
132 if (json_token_streq(json, token,
"points"))
134 if (json_token_streq(json, token,
"amount"))
136 if (json_token_streq(json, token,
"type"))
138 if (json_token_streq(json, token,
"list"))
140 if (json_token_streq(json, token,
"number"))
142 if (json_token_streq(json, token,
"x"))
144 if (json_token_streq(json, token,
"y"))
158 if (start_index >= token_count || tokens[start_index].type !=
JSMN_OBJECT)
162 int pair_count = tokens[start_index].
size;
163 int current_index = start_index + 1;
164 for (
int i = 0; i < pair_count; i++)
166 if (current_index >= token_count)
168 FieldKey key = parse_field_key(json, &tokens[current_index]);
171 current_index = skip_token_tree(tokens, token_count, current_index);
172 current_index = skip_token_tree(tokens, token_count, current_index);
176 const jsmntok_t *value_token = &tokens[current_index + 1];
179 current_index = skip_token_tree(tokens, token_count, current_index);
180 current_index = skip_token_tree(tokens, token_count, current_index);
187 coord->
X = jsonint(json, value_token);
190 coord->
Y = jsonint(json, value_token);
195 current_index = skip_token_tree(tokens, token_count, current_index);
196 current_index = skip_token_tree(tokens, token_count, current_index);
204 if (start_index >= token_count || tokens[start_index].type !=
JSMN_OBJECT)
209 int pair_count = tokens[start_index].
size;
210 int current_index = start_index + 1;
211 for (
int i = 0; i < pair_count; i++)
213 if (current_index >= token_count)
215 FieldKey key = parse_field_key(json, &tokens[current_index]);
220 collision->
shadow = jsonbool(json, &tokens[current_index + 1]);
224 int points_array_index = current_index + 1;
225 if (points_array_index >= token_count || tokens[points_array_index].type !=
JSMN_ARRAY)
229 int point_count = tokens[points_array_index].
size;
233 int point_index = points_array_index + 1;
234 for (
int j = 0; j < point_count; j++)
236 if (point_index >= token_count)
242 point_index = skip_token_tree(tokens, token_count, point_index);
249 current_index = skip_token_tree(tokens, token_count, current_index);
250 current_index = skip_token_tree(tokens, token_count, current_index);
258 if (start_index >= token_count || tokens[start_index].type !=
JSMN_OBJECT)
262 int pair_count = tokens[start_index].
size;
263 int current_index = start_index + 1;
264 for (
int i = 0; i < pair_count; i++)
266 if (current_index >= token_count)
268 FieldKey key = parse_field_key(json, &tokens[current_index]);
273 resource->
amount = jsonint(json, &tokens[current_index + 1]);
277 const jsmntok_t *type_token = &tokens[current_index + 1];
278 int len = type_token->
end - type_token->
start;
281 strncpy(resource->
type, json + type_token->
start, len);
282 resource->
type[len] =
'\0';
288 current_index = skip_token_tree(tokens, token_count, current_index);
289 current_index = skip_token_tree(tokens, token_count, current_index);
297 if (start_index >= token_count || tokens[start_index].type !=
JSMN_OBJECT)
302 int pair_count = tokens[start_index].
size;
303 int current_index = start_index + 1;
304 for (
int i = 0; i < pair_count; i++)
306 if (current_index >= token_count)
308 FieldKey key = parse_field_key(json, &tokens[current_index]);
317 int list_array_index = current_index + 1;
318 if (list_array_index >= token_count || tokens[list_array_index].type !=
JSMN_ARRAY)
322 int list_count = tokens[list_array_index].
size;
326 int list_item_index = list_array_index + 1;
327 for (
int j = 0; j < list_count; j++)
329 if (list_item_index >= token_count)
335 list_item_index = skip_token_tree(tokens, token_count, list_item_index);
342 current_index = skip_token_tree(tokens, token_count, current_index);
343 current_index = skip_token_tree(tokens, token_count, current_index);
356 int token_count =
jsmn_parse(&parser, json_string, strlen(json_string), NULL, 0);
359 token_count =
jsmn_parse(&parser, json_string, strlen(json_string), tokens, token_count);
364 log_info(
"Failed to parse due to Negative token count (Enable DEBUG HIGH to view raw JSON string.)");
372 log_info(
"No object found in JSON file. (Enable DEBUG HIGH to view raw JSON string.)");
391 int pairs_to_process = tokens[0].
size;
393 int current_token_index = 1;
395 for (
int i = 0; i < pairs_to_process; i++)
398 if (current_token_index >= token_count)
401 FieldKey key = parse_field_key(json, &tokens[current_token_index]);
402 int value_index = current_token_index + 1;
405 if (value_index >= token_count)
411 building->
id = jsonint(json, &tokens[value_index]);
419 building->
can_enter = jsonbool(json, &tokens[value_index]);
423 building->
center_x = jsonint(json, &tokens[value_index]);
427 building->
center_y = jsonint(json, &tokens[value_index]);
439 building->
flags = jsonint(json, &tokens[value_index]);
443 building->
health = jsonint(json, &tokens[value_index]);
447 building->
name_id = jsonint(json, &tokens[value_index]);
451 building->
race = jsonint(json, &tokens[value_index]);
455 building->
slot_count = jsonint(json, &tokens[value_index]);
461 int collisions_array_index = value_index;
462 if (tokens[collisions_array_index].type ==
JSMN_ARRAY)
464 int collisions_to_parse = tokens[collisions_array_index].
size;
468 int collision_token_index = collisions_array_index + 1;
469 for (
int j = 0; j < collisions_to_parse; j++)
475 collision_token_index = skip_token_tree(tokens, token_count, collision_token_index);
489 current_token_index = skip_token_tree(tokens, token_count, current_token_index);
490 current_token_index = skip_token_tree(tokens, token_count, current_token_index);
498 FILE *file = fopen(path,
"rb");
501 log_error(
"Expected file \"%s\" not found\n", path);
505 fseek(file,0,SEEK_END);
506 long len = ftell(file);
507 fseek(file,0,SEEK_SET);
511 log_error(
"Empty or unreadable file: \"%s\"\n",path);
517 char *buffer = (
char *) malloc(len+1);
520 log_error(
"Unable to allocate memory for file: \"%s\"\n",path);
525 size_t read_len = fread(buffer, 1, len, file);
528 if(read_len != (
size_t)len)
530 log_error(
"File Read Incomplete: \"%s\" (Expected %ld bytes, got %ld bytes)\n", path, len, (
long) read_len);
535 buffer[read_len] =
'\0';
537 char *last_brace = strrchr(buffer,
'}');
538 if(last_brace != NULL)
540 last_brace[1] =
'\0';
544 log_error(
"Invalid JSON: No closing brace found in \"%s\"\n", path);
554 char currentDir[MAX_PATH];
555 GetCurrentDirectory(MAX_PATH, currentDir);
557 snprintf(path,
sizeof(path),
"%s\\sfsf\\%s\\buildings\\%s.json", currentDir, mod_id, building_json_name);
566 memset(out_building, 0,
sizeof(
Building));
570 log_error(
"Building JSON structure invalid: %s", building_json_name);
void log_error(const char *format,...)
void log_debug(DebugLevel level, const char *format,...)
void log_info(const char *format,...)
void jsmn_init(jsmn_parser *parser)
int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, jsmntok_t *tokens, const unsigned int num_tokens)
bool parse_collision(const char *json, const jsmntok_t *tokens, int token_count, int start_index, Collision *collision)
bool parse_resources(const char *json, const jsmntok_t *tokens, int token_count, int start_index, Building *building)
char * readfile(const char *path)
void print_building(const Building *building)
bool parse_building_from_tokens(const char *json, jsmntok_t *tokens, int token_count, Building *building)
bool parse_building_json(const char *json_string, Building *building)
bool parse_building_json_entrypoint(const char *building_json_name, const char *mod_id, Building *out_building)
void init_building(Building *building)
bool parse_resource(const char *json, const jsmntok_t *tokens, int token_count, int start_index, Resource *resource)
bool parse_world_coord(const char *json, const jsmntok_t *tokens, int token_count, int start_index, WorldCoord *coord)
@ FIELD_BUILDING_REQUIRED
bool found_collision_count
bool found_description_id
bool found_building_required