2 Commits

7 changed files with 212 additions and 132 deletions

View File

@@ -1,6 +1,7 @@
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <SDL3_mixer/SDL_mixer.h>
#include <SDL3/SDL_stdinc.h>
#include <aklabs/exclib.h>
#include "game.h"
@@ -12,10 +13,13 @@ void load_frame_from_image(char *fname, GAME_frame *frame)
THROW_ZERO(frame, EXC_NULLPOINTER, "load_frame_from_image received NULL frame");
THROW_ZERO(fname, EXC_NULLPOINTER, "load_frame_from_image received NULL filename");
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
tex = IMG_LoadTexture(renderer, asset_path);
THROW_ZERO(tex, EXC_NULLPOINTER, "Failed loading asset");
TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
tex = IMG_LoadTexture(renderer, asset_path);
THROW_ZERO(tex, EXC_NULLPOINTER, "Failed loading asset");
} FINALLY {
SDL_free(asset_path);
} ETRY;
frame->texture = tex;
SDL_GetTextureSize(tex, &frame->w, &frame->h);
@@ -27,12 +31,15 @@ void load_start_bgm(char *fname)
THROW_ZERO(fname, EXC_NULLPOINTER, "load_start_bgm received NULL filename");
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
SDL_Log("Loading music asset from %s", asset_path);
bgm = Mix_LoadMUS(asset_path);
THROW_ZERO(bgm, EXC_NULLPOINTER, "Failed to load music asset");
if (!Mix_PlayMusic(bgm, 0)) {
THROW(EXC_SDL_MUSICMIXER, "Failed to play music asset");
}
TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
SDL_Log("Loading music asset from %s", asset_path);
bgm = Mix_LoadMUS(asset_path);
THROW_ZERO(bgm, EXC_NULLPOINTER, "Failed to load music asset");
if (!Mix_PlayMusic(bgm, 0)) {
THROW(EXC_SDL_MUSICMIXER, "Failed to play music asset");
}
} FINALLY {
SDL_free(asset_path);
} ETRY;
}

View File

@@ -1,6 +1,8 @@
#include <jansson.h>
#include "json_helpers.h"
#include "game.h"
#include "string.h"
#include "heap.h"
json_t *get_json_object_value(json_t *obj, char *key)
{
@@ -10,12 +12,14 @@ json_t *get_json_object_value(json_t *obj, char *key)
return value;
}
int get_json_boolean_value(json_t *obj, char *key)
bool get_json_boolean_value(json_t *obj, char *key)
{
json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_boolean(value), EXC_ATTRIBUTEERROR, "");
return json_boolean_value(value);
bool i = json_boolean_value(value);
json_decref(value);
return i;
}
int get_json_integer_value(json_t *obj, char *key)
@@ -23,30 +27,38 @@ int get_json_integer_value(json_t *obj, char *key)
json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, "");
return json_integer_value(value);
int i = json_integer_value(value);
json_decref(value);
return i;
}
float get_json_number_value(json_t *obj, char *key)
{
json_t *value = json_object_get(obj, key);
float f;
THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_number(value), EXC_ATTRIBUTEERROR, "");
return json_number_value(value);
f = json_number_value(value);
json_decref(value);
return f;
}
const char *get_json_string_value(json_t *obj, char *key)
string *get_json_string_value(json_t *obj, char *key)
{
string *s = heap_next_string();
json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_string(value), EXC_ATTRIBUTEERROR, "");
return json_string_value(value);
THROW_ZERO(value, EXC_KEYERROR, key);
THROW_ZERO(json_is_string(value), EXC_ATTRIBUTEERROR, key);
strncpy(s->data, (char *)json_string_value(value), MAX_STRING_LENGTH);
json_decref(value);
return s;
}
json_t *get_json_array_value(json_t *obj, char *key)
{
json_t *value = json_object_get(obj, key);
THROW_ZERO(value, EXC_KEYERROR, "");
THROW_ZERO(json_is_array(value), EXC_ATTRIBUTEERROR, "");
THROW_ZERO(value, EXC_KEYERROR, key);
THROW_ZERO(json_is_array(value), EXC_ATTRIBUTEERROR, key);
return value;
}
@@ -60,8 +72,11 @@ json_t *get_json_array_index_object(json_t *array, int index)
int get_json_array_index_integer(json_t *array, int index)
{
int i;
json_t *value = json_array_get(array, index);
THROW_ZERO(value, EXC_INDEXERROR, "");
THROW_ZERO(json_is_integer(value), EXC_ATTRIBUTEERROR, "");
return json_integer_value(value);
i = json_integer_value(value);
json_decref(value);
return i;
}

View File

@@ -1,11 +1,14 @@
#ifndef _JSON_HELPERS_H_
#define _JSON_HELPERS_H_
#include <stdbool.h>
#include "string.h"
json_t *get_json_object_value(json_t *obj, char *key);
int get_json_boolean_value(json_t *obj, char *key);
bool get_json_boolean_value(json_t *obj, char *key);
int get_json_integer_value(json_t *obj, char *key);
float get_json_number_value(json_t *obj, char *key);
const char *get_json_string_value(json_t *obj, char *key);
string *get_json_string_value(json_t *obj, char *key);
json_t *get_json_array_value(json_t *obj, char *key);
json_t *get_json_array_index_object(json_t *array, int index);
int get_json_array_index_integer(json_t *array, int index);

View File

@@ -83,18 +83,6 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
return SDL_APP_FAILURE;
} ETRY;
/*TRY {
actorptr = heap_next_actor();
actor_initialize(actorptr, "npc");
actorptr->basechar = characterptr;
actorptr->x = 0;
actorptr->y = 0;
actorptr->state = (ACTOR_STATE_ALIVE | ACTOR_STATE_FACE_LEFT | ACTOR_STATE_MOVING_LEFT);
} CATCH(EXC_NULLPOINTER) {
SDL_Log("Attempting to setup npc: %s (%s)", EXCLIB_EXCEPTION->description, SDL_GetError());
return SDL_APP_FAILURE;
} ETRY;*/
/*
TRY {
//load_start_bgm("../assets/nutcracker.mid");

View File

@@ -1,10 +1,11 @@
#include <SDL3/SDL.h>
#include <SDL3/SDL_stdinc.h>
#include <SDL3_image/SDL_image.h>
#include <box2d/box2d.h>
#include <aklabs/exclib.h>
#include <string.h>
#include <jansson.h>
#include "string.h"
#include "game.h"
#include "sprite.h"
#include "json_helpers.h"
@@ -142,6 +143,7 @@ void character_load_json(char *filename)
json_t *mappings;
json_t *curmapping;
json_error_t error;
string *s;
sprite *spriteptr = NULL;
char *asset_path = NULL;
character *obj = NULL;
@@ -149,29 +151,32 @@ void character_load_json(char *filename)
THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename");
obj = heap_next_character();
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading character from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed");
}
character_initialize(obj, (char *)get_json_string_value(json, "name"));
TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading character from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed");
}
} FINALLY {
SDL_free(asset_path);
} ETRY;
TRY {
s = get_json_string_value(json, "name");
character_initialize(obj, s->data);
heap_release_string(s);
mappings = get_json_array_value(json, "sprite_mappings");
TRY {
for ( i = 0; i < json_array_size(mappings) ; i++ ) {
curmapping = get_json_array_index_object(mappings, i);
s = get_json_string_value(curmapping, "sprite");
spriteptr = SDL_GetPointerProperty(
REGISTRY_SPRITE,
get_json_string_value(curmapping, "sprite"),
s->data,
NULL
);
SDL_Log("Character %s for state %d references sprite %s",
(char *)get_json_string_value(json, "name"),
get_json_integer_value(curmapping, "state"),
(char *)get_json_string_value(curmapping, "sprite")
);
heap_release_string(s);
THROW_ZERO(spriteptr, EXC_NULLPOINTER, "Character references sprite that does not exist");
character_sprite_add(
obj,
@@ -181,9 +186,9 @@ void character_load_json(char *filename)
}
} FINALLY {
json_decref(curmapping);
json_decref(mappings);
} ETRY;
} FINALLY {
json_decref(mappings);
json_decref(json);
} ETRY;
}
@@ -194,6 +199,7 @@ void sprite_load_json(char *filename)
json_t *spritesheet_json;
json_t *frames;
json_error_t error;
string *s;
spritesheet *sheet = NULL;
char *asset_path = NULL;
sprite *obj = NULL;
@@ -201,34 +207,43 @@ void sprite_load_json(char *filename)
THROW_ZERO(filename, EXC_NULLPOINTER, "Received null filename");
obj = heap_next_sprite();
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading sprite from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed");
}
TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading sprite from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON sprite failed");
}
} FINALLY {
SDL_free(asset_path);
} ETRY;
TRY {
spritesheet_json = get_json_object_value(json, "spritesheet");
s = get_json_string_value(spritesheet_json, "filename");
sheet = SDL_GetPointerProperty(
REGISTRY_SPRITESHEET,
get_json_string_value(spritesheet_json, "filename"),
s->data,
NULL
);
if ( sheet == NULL ) {
sheet = heap_next_spritesheet();
spritesheet_initialize(
sheet,
get_json_integer_value(spritesheet_json, "frame_width"),
get_json_integer_value(spritesheet_json, "frame_height"),
(char *)get_json_string_value(spritesheet_json, "filename")
);
}
TRY {
if ( sheet == NULL ) {
sheet = heap_next_spritesheet();
spritesheet_initialize(
sheet,
get_json_integer_value(spritesheet_json, "frame_width"),
get_json_integer_value(spritesheet_json, "frame_height"),
s->data
);
}
heap_release_string(s);
s = get_json_string_value(json, "name");
sprite_initialize(
obj,
(char *)get_json_string_value(json, "name"),
s->data,
sheet);
heap_release_string(s);
} FINALLY {
json_decref(spritesheet_json);
} ETRY;
@@ -274,8 +289,13 @@ void spritesheet_initialize(spritesheet *sheet, short sprite_w, short sprite_h,
THROW_ZERO(sheet, EXC_NULLPOINTER, "Null spritesheet pointer");
THROW_ZERO(filename, EXC_NULLPOINTER, "Null filename pointer");
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
sheet->texture = IMG_LoadTexture(renderer, asset_path);
TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), filename);
sheet->texture = IMG_LoadTexture(renderer, asset_path);
} FINALLY {
SDL_free(asset_path);
} ETRY;
strncpy(sheet->name, filename, SPRITE_SHEET_MAX_FILENAME_LENGTH);
THROW_ZERO(sheet->texture, EXC_NULLPOINTER, "Failed loading asset");
@@ -351,3 +371,4 @@ void character_state_sprites_iterate(void *userdata, SDL_PropertiesID registry,
}
}

View File

@@ -7,6 +7,6 @@ void string_initialize(string *obj, char *init)
if ( init != NULL ) {
strncpy(obj->data, init, MAX_STRING_LENGTH);
} else {
memset(&obj->data, 0x00, sizeof(MAX_STRING_LENGTH));
memset(obj->data, 0x00, sizeof(string));
}
}

View File

@@ -2,51 +2,67 @@
#include <SDL3_image/SDL_image.h>
#include <SDL3_mixer/SDL_mixer.h>
#include <aklabs/exclib.h>
#include <string.h>
#include <jansson.h>
#include "tilemap.h"
#include "game.h"
#include "sprite.h"
#include "json_helpers.h"
#include "heap.h"
#include "string.h"
#include "registry.h"
#include "string.h"
#include <string.h>
#include <jansson.h>
#include "json_helpers.h"
static json_t *get_json_tilemap_property(json_t *obj, char *key, char *type)
{
json_t *properties;
json_t *property;
string *s;
int i = 0;
// This is not a generic JSON helper. It assumes we are receiving an object with a 'properties' key
// inside of it. That key is an array of objects, and each object has a name, type, and value.
THROW_ZERO(obj, EXC_NULLPOINTER, "NULL json obj reference");
THROW_ZERO(key, EXC_NULLPOINTER, "NULL key string");
properties = get_json_array_value(obj, "properties");
for (i = 0; i < json_array_size(properties); i++) {
property = get_json_array_index_object(properties, i);
if ( strcmp(get_json_string_value(property, "name"), key) != 0 ) {
continue;
TRY {
for (i = 0; i < json_array_size(properties); i++) {
property = get_json_array_index_object(properties, i);
s = get_json_string_value(property, "name");
if ( strcmp(s->data, key) != 0 ) {
heap_release_string(s);
continue;
}
heap_release_string(s);
s = get_json_string_value(property, "type");
if ( strcmp(s->data, type) != 0 ) {
THROW(EXC_ATTRIBUTEERROR, "Character property is present but is incorrect type");
}
heap_release_string(s);
json_decref(properties);
return property;
}
if ( strcmp(get_json_string_value(property, "type"), type) != 0 ) {
THROW(EXC_ATTRIBUTEERROR, "Character property is present but is incorrect type");
}
return property;
}
} FINALLY {
heap_release_string(s);
json_decref(properties);
} ETRY;
THROW(EXC_KEYERROR, "Property not found in properties map");
}
static const char *get_json_properties_string(json_t *obj, char *key)
static string *get_json_properties_string(json_t *obj, char *key)
{
json_t *property = get_json_tilemap_property(obj, key, "string");
return get_json_string_value(property, "value");
string *s = get_json_string_value(property, "value");;
json_decref(property);
return s;
}
static int get_json_properties_integer(json_t *obj, char *key)
{
json_t *property = get_json_tilemap_property(obj, key, "int");
return get_json_integer_value(property, "value");
int i = get_json_integer_value(property, "value");
json_decref(property);
return i;
}
static void tilemap_load_tilesets(tilemap *dest, json_t *root)
@@ -54,6 +70,7 @@ static void tilemap_load_tilesets(tilemap *dest, json_t *root)
THROW_ZERO(dest, EXC_NULLPOINTER, "Received NULL tilemap pointer");
THROW_ZERO(root, EXC_NULLPOINTER, "Received NULL json object pointer");
char *asset_path;
string *s;
json_t *tilesets = get_json_array_value(root, "tilesets");
json_t *tileset;
int i;
@@ -76,17 +93,21 @@ static void tilemap_load_tilesets(tilemap *dest, json_t *root)
dest->tilesets[i].tileheight = get_json_integer_value(tileset, "tileheight");
dest->tilesets[i].tilewidth = get_json_integer_value(tileset, "tilewidth");
s = get_json_string_value(tileset, "name");
strncpy((char *)&dest->tilesets[i].name,
get_json_string_value(tileset, "name"),
s->data,
TILEMAP_MAX_TILESET_NAME_SIZE
);
heap_release_string(s);
s = get_json_string_value(tileset, "image");
snprintf((char *)&dest->tilesets[i].imagefilename,
TILEMAP_MAX_TILESET_FILENAME_SIZE,
"%s%s",
SDL_GetBasePath(),
get_json_string_value(tileset, "image")
s->data
);
heap_release_string(s);
dest->tilesets[i].texture = IMG_LoadTexture(renderer, (char *)&dest->tilesets[i].imagefilename);
THROW_ZERO(dest->tilesets[i].texture, EXC_NULLPOINTER, "Failed loading tileset image");
@@ -134,8 +155,10 @@ static void tilemap_load_tilesets(tilemap *dest, json_t *root)
y_offset);*/
}
// SDL_Log("Processed %d total tiles for tileset", j);
json_decref(tileset);
dest->numtilesets += 1;
}
json_decref(tilesets);
}
static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
@@ -145,6 +168,8 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
int j;
int len;
actor *actorobj;
string *s;
string *sc;
tilemap_layer *curlayer;
tilemap_object *curobj;
const char *charptr;
@@ -159,11 +184,14 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
for ( j = 0; j < len; j++ ) {
layerdatavalue = get_json_array_index_object(layerdata, j);
curobj = &curlayer->objects[j];
strncpy(curobj->name, get_json_string_value(layerdatavalue, "name"), SPRITE_MAX_ACTOR_NAME_LENGTH);
s = get_json_string_value(layerdatavalue, "name");
strncpy(curobj->name, s->data, SPRITE_MAX_ACTOR_NAME_LENGTH);
heap_release_string(s);
curobj->x = (int) get_json_number_value(layerdatavalue, "x");
curobj->y = (int) get_json_number_value(layerdatavalue, "y");
curobj->visible = get_json_boolean_value(layerdatavalue, "visible");
if ( strcmp((char *)get_json_string_value(layerdatavalue, "type"), "actor") == 0 ) {
s = get_json_string_value(layerdatavalue, "type");
if ( strcmp(s->data, "actor") == 0 ) {
curobj->type = TILEMAP_OBJECT_TYPE_ACTOR;
if ( strlen((char *)&curobj->name) == 0 ) {
THROW(EXC_KEYERROR, "Actor in tile object layer cannot have empty name");
@@ -171,8 +199,10 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
actorobj = SDL_GetPointerProperty(REGISTRY_ACTOR, (char *)&curobj->name, NULL);
if ( actorobj == NULL ) {
actorobj = heap_next_actor();
sc = get_json_properties_string(layerdatavalue, "character");
actor_initialize(actorobj, (char *)&curobj->name);
actor_set_character(actorobj, (char *)get_json_properties_string(layerdatavalue, "character"));
actor_set_character(actorobj, sc->data);
heap_release_string(sc);
} else {
actorobj->refcount += 1;
}
@@ -186,6 +216,7 @@ static void tilemap_load_layer_objects(tilemap *dest, json_t *root, int layerid)
json_decref(layerdatavalue);
}
} FINALLY {
heap_release_string(s);
if ( layerdatavalue != NULL ) {
json_decref(layerdatavalue);
}
@@ -212,6 +243,7 @@ static void tilemap_load_layer_tile(tilemap *dest, json_t *root, int layerid)
json_decref(layerdata);
THROW(EXC_OUTOFBOUNDS, "Map layer exceeds the maximum size");
}
TRY {
for ( j = 0; j < layerdatalen; j++ ) {
layerdatavalue = json_array_get(layerdata, j);
if (!json_is_integer(layerdatavalue)) {
@@ -222,7 +254,12 @@ static void tilemap_load_layer_tile(tilemap *dest, json_t *root, int layerid)
dest->layers[layerid].data[j] = json_integer_value(layerdatavalue);
json_decref(layerdatavalue);
}
json_decref(layerdata);
} FINALLY {
if ( layerdatavalue != NULL ) {
json_decref(layerdatavalue);
json_decref(layerdata);
}
} ETRY;
}
static void tilemap_load_layers(tilemap *dest, json_t *root)
@@ -231,42 +268,47 @@ static void tilemap_load_layers(tilemap *dest, json_t *root)
THROW_ZERO(root, EXC_NULLPOINTER, "tilemap_load_layers received NULL json object pointer");
json_t *layers = get_json_array_value(root, "layers");
json_t *layer;
string *s;
const char *layertype = NULL;
int i;
dest->numlayers = json_array_size(layers);
for ( i = 0; i < dest->numlayers; i++) {
if ( i >= TILEMAP_MAX_LAYERS ) {
json_decref(layers);
THROW(EXC_OUTOFBOUNDS, "Map exceeds the maximum number of layers");
}
layer = get_json_array_index_object(layers, i);
if ( (get_json_integer_value(layer, "id") - 1) != i ) {
// TileD's map layer IDs start at 1, not 0, and are sequential but not necessarily contiguous. We may have a gap in IDs.
json_decref(layer);
continue;
}
TRY {
for ( i = 0; i < dest->numlayers; i++) {
if ( i >= TILEMAP_MAX_LAYERS ) {
THROW(EXC_OUTOFBOUNDS, "Map exceeds the maximum number of layers");
}
layer = get_json_array_index_object(layers, i);
if ( (get_json_integer_value(layer, "id") - 1) != i ) {
// TileD's map layer IDs start at 1, not 0, and are sequential but not necessarily contiguous. We may have a gap in IDs.
json_decref(layer);
continue;
}
dest->layers[i].opacity = get_json_number_value(layer, "opacity");
dest->layers[i].visible = get_json_boolean_value(layer, "visible");
dest->layers[i].id = get_json_integer_value(layer, "id");
dest->layers[i].x = get_json_integer_value(layer, "x");
dest->layers[i].y = get_json_integer_value(layer, "y");
dest->layers[i].opacity = get_json_number_value(layer, "opacity");
dest->layers[i].visible = get_json_boolean_value(layer, "visible");
dest->layers[i].id = get_json_integer_value(layer, "id");
dest->layers[i].x = get_json_integer_value(layer, "x");
dest->layers[i].y = get_json_integer_value(layer, "y");
TRY {
layertype = get_json_string_value(layer, "type");
if ( strncmp(layertype, "objectgroup", strlen(layertype)) == 0 ) {
TRY {
s = get_json_string_value(layer, "type");
if ( strncmp(s->data, "objectgroup", strlen(s->data)) == 0 ) {
dest->layers[i].type = TILEMAP_LAYER_TYPE_OBJECTS;
tilemap_load_layer_objects(dest, layer, i);
} else if ( strncmp(layertype, "tilelayer", strlen(layertype)) == 0 ) {
} else if ( strncmp(s->data, "tilelayer", strlen(s->data)) == 0 ) {
dest->layers[i].type = TILEMAP_LAYER_TYPE_TILES;
tilemap_load_layer_tile(dest, layer, i);
}
} FINALLY {
} FINALLY {
heap_release_string(s);
json_decref(layer);
} ETRY;
}
json_decref(layers);
} ETRY;
}
} FINALLY {
json_decref(layers);
} ETRY;
}
void tilemap_load(char *fname, tilemap *dest)
@@ -280,12 +322,16 @@ void tilemap_load(char *fname, tilemap *dest)
memset(dest, 0x00, sizeof(tilemap));
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading tilemap from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON tilemap failed");
}
TRY {
SDL_asprintf(&asset_path, "%s%s", SDL_GetBasePath(), fname);
json = json_load_file(asset_path, 0, &error);
if (!json) {
SDL_Log("Error while loading tilemap from %s on line %d: %s", asset_path, error.line, error.text);
THROW(EXC_NULLPOINTER, "Loading JSON tilemap failed");
}
} FINALLY {
SDL_free(asset_path);
} ETRY;
TRY {
dest->tileheight = get_json_integer_value(json, "tileheight");