diff options
author | Florian Diebold <flodiebold@gmail.com> | 2012-11-14 19:59:46 +0100 |
---|---|---|
committer | Florian Diebold <flodiebold@gmail.com> | 2012-11-14 20:02:44 +0100 |
commit | b0df2b25b2c3b0232a0ace8dcd06b1bb15e69d7a (patch) | |
tree | 08bbae956110f6d962ab52041ba7e3070641f084 | |
parent | 68bdec137909c3b2cdb8f57b60552cc0b8fd0ff0 (diff) | |
download | crawl-ref-b0df2b25b2c3b0232a0ace8dcd06b1bb15e69d7a.tar.gz crawl-ref-b0df2b25b2c3b0232a0ace8dcd06b1bb15e69d7a.zip |
Webtiles: Improve JSON generation functions; always send proper JSON.
-rw-r--r-- | crawl-ref/source/menu.cc | 8 | ||||
-rw-r--r-- | crawl-ref/source/tileweb-text.cc | 14 | ||||
-rw-r--r-- | crawl-ref/source/tileweb.cc | 375 | ||||
-rw-r--r-- | crawl-ref/source/tileweb.h | 38 | ||||
-rw-r--r-- | crawl-ref/source/webserver/game_data/static/cell_renderer.js | 18 |
5 files changed, 260 insertions, 193 deletions
diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc index 7901fb1749..a55c4490df 100644 --- a/crawl-ref/source/menu.cc +++ b/crawl-ref/source/menu.cc @@ -1486,7 +1486,7 @@ void Menu::webtiles_handle_item_request(int start, int end) tiles.json_close_array(); tiles.json_close_object(); - tiles.send_message(); + tiles.finish_message(); } void Menu::webtiles_update_item(int index) const @@ -1511,7 +1511,7 @@ void Menu::webtiles_update_item(int index) const tiles.json_close_array(); tiles.json_close_object(); - tiles.send_message(); + tiles.finish_message(); } void Menu::webtiles_update_title() const @@ -1520,7 +1520,7 @@ void Menu::webtiles_update_title() const tiles.json_write_string("msg", "update_menu"); webtiles_write_title(); tiles.json_close_object(); - tiles.send_message(); + tiles.finish_message(); } void Menu::webtiles_update_scroll_pos() const @@ -1529,7 +1529,7 @@ void Menu::webtiles_update_scroll_pos() const tiles.json_write_string("msg", "menu_scroll"); tiles.json_write_int("first", first_entry); tiles.json_close_object(); - tiles.send_message(); + tiles.finish_message(); } void Menu::webtiles_write_title() const diff --git a/crawl-ref/source/tileweb-text.cc b/crawl-ref/source/tileweb-text.cc index 84faad14f5..3dcd349184 100644 --- a/crawl-ref/source/tileweb-text.cc +++ b/crawl-ref/source/tileweb-text.cc @@ -172,19 +172,23 @@ void WebTextArea::send(bool force) { if (!sending) { - tiles.write_message("{msg:'txt',id:'%s'", + tiles.write_message("{\"msg\":\"txt\",\"id\":\"%s\"", m_client_side_name.c_str()); if (force) - tiles.write_message(",clear:1"); - tiles.write_message(",lines:{"); + tiles.write_message(",\"clear\":true"); + tiles.write_message(",\"lines\":{"); sending = true; } - tiles.write_message("%u:\"%s\",", y, html.c_str()); + tiles.json_write_comma(); + tiles.write_message("\"%u\":\"%s\"", y, html.c_str()); } } if (sending) - tiles.send_message("}}"); + { + tiles.write_message("}}"); + tiles.finish_message(); + } } void WebTextArea::on_resize() diff --git a/crawl-ref/source/tileweb.cc b/crawl-ref/source/tileweb.cc index b56ae285f0..c2032b1525 100644 --- a/crawl-ref/source/tileweb.cc +++ b/crawl-ref/source/tileweb.cc @@ -149,17 +149,8 @@ bool TilesFramework::initialise() return true; } -void TilesFramework::write_message() -{ - for (unsigned int i = 0; i < m_prefixes.size(); ++i) - m_msg_buf.append(m_prefixes[i].data()); - m_prefixes.clear(); -} - void TilesFramework::write_message(const char *format, ...) { - write_message(); // prefixes - char buf[2048]; int len; @@ -179,7 +170,6 @@ void TilesFramework::write_message(const char *format, ...) void TilesFramework::finish_message() { - m_prefixes.clear(); if (m_msg_buf.size() == 0) return; @@ -223,16 +213,8 @@ void TilesFramework::finish_message() m_msg_buf.clear(); } -void TilesFramework::send_message() -{ - write_message(); - finish_message(); -} - void TilesFramework::send_message(const char *format, ...) { - write_message(); - char buf[2048]; int len; @@ -404,28 +386,16 @@ bool TilesFramework::await_input(wint_t& c, bool block) } } -void TilesFramework::push_prefix(const string& prefix) -{ - m_prefixes.push_back(prefix); -} - -void TilesFramework::pop_prefix(const string& suffix) -{ - if (!m_prefixes.empty()) - m_prefixes.pop_back(); - else - write_message("%s", suffix.c_str()); -} - -bool TilesFramework::prefix_popped() -{ - return m_prefixes.empty(); -} - void TilesFramework::dump() { fprintf(stderr, "Webtiles message buffer: %s\n", m_msg_buf.c_str()); - fprintf(stderr, "Webtiles prefix count: %d\n", (int) m_prefixes.size()); + fprintf(stderr, "Webtiles JSON stack:\n"); + for (unsigned int i = 0; i < m_json_stack.size(); ++i) + { + fprintf(stderr, "start: %d end: %d type: %c\n", + m_json_stack[i].start, m_json_stack[i].prefix_end, + m_json_stack[i].type); + } } void TilesFramework::_send_version() @@ -436,7 +406,7 @@ void TilesFramework::_send_version() #endif string title = CRAWL " " + Version::Long(); - send_message("{msg:\"version\",text:\"%s\"}", title.c_str()); + send_message("{\"msg\":\"version\",\"text\":\"%s\"}", title.c_str()); } void TilesFramework::push_menu(Menu* m) @@ -445,7 +415,7 @@ void TilesFramework::push_menu(Menu* m) mi.menu = m; m_menu_stack.push_back(mi); m->webtiles_write_menu(); - tiles.send_message(); + tiles.finish_message(); } void TilesFramework::push_crt_menu(string tag) @@ -460,7 +430,7 @@ void TilesFramework::push_crt_menu(string tag) json_write_string("type", "crt"); json_write_string("tag", tag); json_close_object(); - send_message(); + finish_message(); } void TilesFramework::pop_menu() @@ -468,7 +438,7 @@ void TilesFramework::pop_menu() if (m_menu_stack.empty()) return; MenuInfo mi = m_menu_stack.back(); m_menu_stack.pop_back(); - send_message("{msg:'close_menu'}"); + send_message("{\"msg\":\"close_menu\"}"); } void TilesFramework::close_all_menus() @@ -483,7 +453,7 @@ static void _send_ui_state(WebtilesUIState state) tiles.json_write_string("msg", "ui_state"); tiles.json_write_int("state", state); tiles.json_close_object(); - tiles.send_message(); + tiles.finish_message(); } void TilesFramework::set_ui_state(WebtilesUIState state) @@ -549,7 +519,7 @@ static void _send_doll(const dolls_data &doll, bool submerged, bool ghost) flags[TILEP_PART_BOOTS] = is_cent ? TILEP_FLAG_NORMAL : TILEP_FLAG_HIDE; } - tiles.write_message("doll:["); + tiles.json_open_array("doll"); for (int i = 0; i < TILEP_PART_MAX; ++i) { @@ -569,35 +539,40 @@ static void _send_doll(const dolls_data &doll, bool submerged, bool ghost) ymax = 18; } - tiles.write_message("[%u,%d],", (unsigned int) doll.parts[p], ymax); + tiles.json_write_comma(); + tiles.write_message("[%u,%d]", (unsigned int) doll.parts[p], ymax); } - tiles.write_message("],"); + tiles.json_close_array(); } static void _send_mcache(mcache_entry *entry, bool submerged) { bool trans = entry->transparent(); if (trans) - tiles.write_message("trans:true,"); + tiles.json_write_int("trans", 1); const dolls_data *doll = entry->doll(); if (doll) _send_doll(*doll, submerged, trans); else - tiles.write_message("doll:[],"); + { + tiles.json_write_comma(); + tiles.write_message("\"doll\":[]"); + } - tiles.write_message("mcache:["); + tiles.json_open_array("mcache"); tile_draw_info dinfo[mcache_entry::MAX_INFO_COUNT]; int draw_info_count = entry->info(&dinfo[0]); for (int i = 0; i < draw_info_count; i++) { - tiles.write_message("[%u,%d,%d],", (unsigned int) dinfo[i].idx, + tiles.json_write_comma(); + tiles.write_message("[%u,%d,%d]", (unsigned int) dinfo[i].idx, dinfo[i].ofs_x, dinfo[i].ofs_y); } - tiles.write_message("],"); + tiles.json_close_array(); } static bool _in_water(const packed_cell &cell) @@ -649,30 +624,33 @@ void TilesFramework::_send_cell(const coord_def &gc, bool force_full) { if (current_mc.feat() != next_mc.feat()) - write_message("f:%d,", next_mc.feat()); + json_write_int("f", next_mc.feat()); if (next_mc.monsterinfo()) _send_monster(gc, next_mc.monsterinfo(), new_monster_locs, force_full); else if (current_mc.monsterinfo()) - write_message("mon:null,"); + { + json_write_null("mon"); + } map_feature mf = get_cell_map_feature(next_mc); if (get_cell_map_feature(current_mc) != mf) - write_message("mf:%u,", mf); + json_write_int("mf", mf); // Glyph and colour ucs_t glyph = next_sc.glyph; if (current_sc.glyph != glyph) { + json_write_comma(); if (glyph == '\\') - write_message("g:'\\\\',"); - else if (glyph == '\'') - write_message("g:'\\'',"); + write_message("\"g\":\"\\\\\""); + else if (glyph == '"') + write_message("\"g\":\"\\\"\""); else { char buf[5]; buf[wctoutf8(buf, glyph)] = 0; - write_message("g:'%s',", buf); + write_message("\"g\":\"%s\"", buf); } } if ((current_sc.colour != next_sc.colour @@ -680,10 +658,10 @@ void TilesFramework::_send_cell(const coord_def &gc, { int col = next_sc.colour; col = (_get_brand(col) << 4) | (col & 0xF); - write_message("col:%d,", col); + json_write_int("col", col); } - push_prefix("t:{"); + json_open_object("t"); { // Tile data const packed_cell &next_pc = next_sc.tile; @@ -698,61 +676,59 @@ void TilesFramework::_send_cell(const coord_def &gc, { fg_changed = true; - write_message("fg:"); + json_write_name("fg"); _write_tileidx(next_pc.fg); - write_message(","); if (fg_idx && fg_idx <= TILE_MAIN_MAX) - write_message("base:%u,", (unsigned int) tileidx_known_base_item(fg_idx)); + json_write_int("base", (int) tileidx_known_base_item(fg_idx)); } if (next_pc.bg != current_pc.bg) { - write_message("bg:"); + json_write_name("bg"); _write_tileidx(next_pc.bg); - write_message(","); } if (next_pc.is_bloody != current_pc.is_bloody) - write_message("bloody:%u,", next_pc.is_bloody); + json_write_bool("bloody", next_pc.is_bloody); if (next_pc.old_blood != current_pc.old_blood) - write_message("old_blood:%u,", next_pc.old_blood); + json_write_bool("old_blood", next_pc.old_blood); if (next_pc.is_silenced != current_pc.is_silenced) - write_message("silenced:%u,", next_pc.is_silenced); + json_write_bool("silenced", next_pc.is_silenced); if (next_pc.is_suppressed != current_pc.is_suppressed) - write_message("suppressed:%u,", next_pc.is_suppressed); + json_write_bool("suppressed", next_pc.is_suppressed); if (next_pc.halo != current_pc.halo) - write_message("halo:%u,", next_pc.halo); + json_write_int("halo", next_pc.halo); if (next_pc.is_moldy != current_pc.is_moldy) - write_message("moldy:%u,", next_pc.is_moldy); + json_write_bool("moldy", next_pc.is_moldy); if (next_pc.glowing_mold != current_pc.glowing_mold) - write_message("glowing_mold:%u,", next_pc.glowing_mold); + json_write_bool("glowing_mold", next_pc.glowing_mold); if (next_pc.is_sanctuary != current_pc.is_sanctuary) - write_message("sanctuary:%u,", next_pc.is_sanctuary); + json_write_bool("sanctuary", next_pc.is_sanctuary); if (next_pc.is_liquefied != current_pc.is_liquefied) - write_message("liquefied:%u,", next_pc.is_liquefied); + json_write_bool("liquefied", next_pc.is_liquefied); if (next_pc.orb_glow != current_pc.orb_glow) - write_message("orb_glow:%u,", next_pc.orb_glow); + json_write_int("orb_glow", next_pc.orb_glow); if (next_pc.quad_glow != current_pc.quad_glow) - write_message("quad_glow:%u,", next_pc.quad_glow); + json_write_bool("quad_glow", next_pc.quad_glow); if (next_pc.mangrove_water != current_pc.mangrove_water) - write_message("swtree:%u,", next_pc.mangrove_water); + json_write_bool("mangrove_water", next_pc.mangrove_water); if (next_pc.blood_rotation != current_pc.blood_rotation) - write_message("bloodrot:%d,", next_pc.blood_rotation); + json_write_int("blood_rotation", next_pc.blood_rotation); if (next_pc.travel_trail != current_pc.travel_trail) - write_message("tt:%d,", next_pc.travel_trail); + json_write_int("travel_trail", next_pc.travel_trail); if (_needs_flavour(next_pc) && (next_pc.flv.floor != current_pc.flv.floor @@ -760,10 +736,11 @@ void TilesFramework::_send_cell(const coord_def &gc, || !_needs_flavour(current_pc) || force_full)) { - write_message("flv:{f:%d,", next_pc.flv.floor); + json_open_object("flv"); + json_write_int("f", next_pc.flv.floor); if (next_pc.flv.special) - write_message("s:%d,", next_pc.flv.special); - write_message("},"); + json_write_int("s", next_pc.flv.special); + json_close_object(); } if (fg_idx >= TILEP_MCACHE_START) @@ -774,7 +751,10 @@ void TilesFramework::_send_cell(const coord_def &gc, if (entry) _send_mcache(entry, in_water); else - write_message("doll:[[%d,%d]],", TILEP_MONS_UNKNOWN, TILE_Y); + { + json_write_comma(); + write_message("\"doll\":[[%d,%d]]", TILEP_MONS_UNKNOWN, TILE_Y); + } } } else if (fg_idx == TILEP_PLAYER) @@ -794,7 +774,8 @@ void TilesFramework::_send_cell(const coord_def &gc, { if (fg_changed) { - write_message("doll:[[%u,%d]],", (unsigned int) fg_idx, TILE_Y); + json_write_comma(); + write_message("\"doll\":[[%u,%d]]", (unsigned int) fg_idx, TILE_Y); // TODO: _transform_add_weapon } } @@ -817,13 +798,13 @@ void TilesFramework::_send_cell(const coord_def &gc, if (overlays_changed) { - write_message("ov:["); + json_open_array("ov"); for (int i = 0; i < next_pc.num_dngn_overlay; ++i) - write_message("%d,", next_pc.dngn_overlay[i]); - write_message("],"); + json_write_int(next_pc.dngn_overlay[i]); + json_close_array(); } } - pop_prefix("},"); + json_close_object(true); } void TilesFramework::_send_map(bool force_full) @@ -833,10 +814,12 @@ void TilesFramework::_send_map(bool force_full) force_full = force_full || m_need_full_map; m_need_full_map = false; - push_prefix("{msg:\"map\","); + json_open_object(); + json_write_string("msg", "map"); + json_treat_as_empty(); if (force_full) - write_message("clear:1,"); + json_write_bool("clear", true); screen_cell_t default_cell; default_cell.tile.bg = TILE_FLAG_UNSEEN; @@ -847,7 +830,7 @@ void TilesFramework::_send_map(bool force_full) coord_def last_gc(0, 0); bool send_gc = true; - push_prefix("cells:["); + json_open_array("cells"); for (int y = 0; y < GYM; y++) for (int x = 0; x < GXM; x++) { @@ -870,14 +853,15 @@ void TilesFramework::_send_map(bool force_full) if (m_origin.equals(-1, -1)) m_origin = gc; + json_open_object(); if (send_gc || last_gc.x + 1 != gc.x || last_gc.y != gc.y) { - push_prefix(make_stringf("{x:%d,y:%d,", (x - m_origin.x), (y - m_origin.y))); + json_write_int("x", x - m_origin.x); + json_write_int("y", y - m_origin.y); + json_treat_as_empty(); } - else - push_prefix("{"); const screen_cell_t& sc = force_full ? default_cell : m_current_view(gc); @@ -889,15 +873,16 @@ void TilesFramework::_send_map(bool force_full) mc, env.map_knowledge(gc), new_monster_locs, force_full); - if (prefix_popped()) + if (!json_is_empty()) { send_gc = false; last_gc = gc; } - pop_prefix("},"); + json_close_object(true); } - pop_prefix("]"); - pop_prefix("}"); + json_close_array(true); + + json_close_object(true); m_current_map_knowledge = env.map_knowledge; m_current_view = m_next_view; @@ -909,13 +894,13 @@ void TilesFramework::_send_monster(const coord_def &gc, const monster_info* m, map<uint32_t, coord_def>& new_monster_locs, bool force_full) { + json_open_object("mon"); if (m->client_id) { - push_prefix(make_stringf("mon:{id:%d,", m->client_id)); + json_write_int("id", m->client_id); + json_treat_as_empty(); new_monster_locs[m->client_id] = gc; } - else - push_prefix("mon:{"); const monster_info* last = NULL; map<uint32_t, coord_def>::const_iterator it = @@ -925,14 +910,14 @@ void TilesFramework::_send_monster(const coord_def &gc, const monster_info* m, last = m_current_map_knowledge(gc).monsterinfo(); if (last && (last->client_id != m->client_id)) - write_message(); // Force sending at least the id + json_treat_as_nonempty(); // Force sending at least the id } else { last = m_current_map_knowledge(it->second).monsterinfo(); if (it->second != gc) - write_message(); // As above + json_treat_as_nonempty(); // As above } if (last == NULL) @@ -940,37 +925,36 @@ void TilesFramework::_send_monster(const coord_def &gc, const monster_info* m, if (force_full || (last->full_name() != m->full_name())) { - write_message("name:'%s',", - replace_all_of(m->full_name(), "'", "\\'").c_str()); + json_write_string("name", m->full_name()); } if (force_full || (last->pluralised_name() != m->pluralised_name())) { - write_message("plural:'%s',", - replace_all_of(m->pluralised_name(), "'", "\\'").c_str()); + json_write_string("plural", m->pluralised_name()); } if (force_full || (last->type != m->type)) { - write_message("type:%d,", m->type); + json_write_int("type", m->type); // TODO: get this information to the client in another way - write_message("typedata:{avghp:%d,", mons_avg_hp(m->type)); + json_open_object("typedata"); + json_write_int("avghp", mons_avg_hp(m->type)); if (mons_class_flag(m->type, M_NO_EXP_GAIN)) - write_message("no_exp:1,"); - write_message("},"); + json_write_bool("no_exp", true); + json_close_object(); } if (force_full || (last->attitude != m->attitude)) - write_message("att:%d,", m->attitude); + json_write_int("att", m->attitude); if (force_full || (last->base_type != m->base_type)) - write_message("btype:%d,", m->base_type); + json_write_int("btype", m->base_type); if (force_full || (last->threat != m->threat)) - write_message("threat:%d,", m->threat); + json_write_int("threat", m->threat); - pop_prefix("},"); + json_close_object(true); } void TilesFramework::load_dungeon(const crawl_view_buffer &vbuf, @@ -1055,7 +1039,7 @@ static void _send_layout_data() tiles.json_close_object(); - tiles.send_message(); + tiles.finish_message(); } void TilesFramework::resize() @@ -1077,14 +1061,14 @@ void TilesFramework::_send_everything() _send_version(); _send_layout_data(); - send_message("{msg:\"vgrdc\",x:%d,y:%d}", + send_message("{\"msg\":\"vgrdc\",\"x\":%d,\"y\":%d}", m_current_gc.x - m_origin.x, m_current_gc.y - m_origin.y); - send_message("{msg:\"flash\",col:%d}", m_current_flash_colour); + send_message("{\"msg\":\"flash\",\"col\":%d}", m_current_flash_colour); _send_map(true); finish_message(); - send_message("{msg:'redraw'}"); + send_message("{\"msg\":\"redraw\"}"); // UI State _send_ui_state(m_ui_state); @@ -1108,7 +1092,7 @@ void TilesFramework::_send_everything() } json_close_array(); json_close_object(); - send_message(); + finish_message(); m_text_crt.send(true); m_text_stat.send(true); @@ -1173,12 +1157,15 @@ void TilesFramework::redraw() if (m_need_redraw) { - push_prefix("{msg:'multi',msgs:["); + json_open_object(); + json_write_string("msg", "multi"); + json_treat_as_empty(); + json_open_array("msgs"); if (m_current_gc != m_next_gc) { if (m_origin.equals(-1, -1)) m_origin = m_next_gc; - write_message("{msg:'vgrdc',x:%d,y:%d},", + write_message("{\"msg\":\"vgrdc\",\"x\":%d,\"y\":%d}", m_next_gc.x - m_origin.x, m_next_gc.y - m_origin.y); m_current_gc = m_next_gc; @@ -1186,18 +1173,24 @@ void TilesFramework::redraw() if (m_current_flash_colour != m_next_flash_colour) { - write_message("{msg:'flash',col:%d},", + json_write_comma(); + write_message("{\"msg\":\"flash\",\"col\":%d}", m_next_flash_colour); m_current_flash_colour = m_next_flash_colour; } if (m_view_loaded) { - push_prefix(""); _send_map(false); - pop_prefix(","); } - pop_prefix("{msg:'redraw'}]}"); + + if (!json_is_empty()) + { + json_write_comma(); + write_message("{\"msg\":\"redraw\"}"); + } + json_close_array(true); + json_close_object(true); finish_message(); } @@ -1264,13 +1257,13 @@ void TilesFramework::place_cursor(cursor_type type, const coord_def &gc) if (result == NO_CURSOR) { - send_message("{msg:\"cursor\",id:%d}", type); + send_message("{\"msg\":\"cursor\",\"id\":%d}", type); return; } else { - send_message("{msg:\"cursor\",id:%d,loc:{x:%d,y:%d}}", type, - result.x - m_origin.x, result.y - m_origin.y); + send_message("{\"msg\":\"cursor\",\"id\":%d,\"loc\":{\"x\":%d,\"y\":%d}}", + type, result.x - m_origin.x, result.y - m_origin.y); } } } @@ -1300,14 +1293,14 @@ void TilesFramework::add_overlay(const coord_def &gc, tileidx_t idx) m_has_overlays = true; - send_message("{msg:'overlay',idx:%u,x:%d,y:%d}", (unsigned int) idx, - gc.x - m_origin.x, gc.y - m_origin.y); + send_message("{\"msg\":\"overlay\",\"idx\":%u,\"x\":%d,\"y\":%d}", + (unsigned int) idx, gc.x - m_origin.x, gc.y - m_origin.y); } void TilesFramework::clear_overlays() { if (m_has_overlays) - send_message("{msg:'clear_overlays'}"); + send_message("{\"msg\":\"clear_overlays\"}"); m_has_overlays = false; } @@ -1430,49 +1423,84 @@ void TilesFramework::write_message_escaped(const string& s) } } -void TilesFramework::json_open_object(const string& name) +void TilesFramework::json_open(const string& name, char opener, char type) { + m_json_stack.resize(m_json_stack.size() + 1); + JsonFrame& fr = m_json_stack.back(); + fr.start = m_msg_buf.size(); + json_write_comma(); if (!name.empty()) json_write_name(name); - write_message("{"); - json_object_level++; - need_comma = false; + m_msg_buf.append(1, opener); + + fr.prefix_end = m_msg_buf.size(); + fr.type = type; } -void TilesFramework::json_close_object() +void TilesFramework::json_treat_as_empty() { - write_message("}"); - json_object_level--; - need_comma = true; + if (m_json_stack.empty()) + die("json error: empty stack"); + m_json_stack.back().prefix_end = m_msg_buf.size(); } -void TilesFramework::json_open_array(const string& name) +void TilesFramework::json_treat_as_nonempty() { - json_write_comma(); - if (!name.empty()) - json_write_name(name); + if (m_json_stack.empty()) + die("json error: empty stack"); + m_json_stack.back().prefix_end = -1; +} - write_message("["); - json_object_level++; - need_comma = false; +bool TilesFramework::json_is_empty() +{ + if (m_json_stack.empty()) + die("json error: empty stack"); + return m_json_stack.back().prefix_end == (int) m_msg_buf.size(); +} + +void TilesFramework::json_close(bool erase_if_empty, char type) +{ + if (m_json_stack.empty()) + die("json error: attempting to close object/array on empty stack"); + if (m_json_stack.back().type != type) + die("json error: attempting to close wrong type"); + + if (erase_if_empty && json_is_empty()) + m_msg_buf.resize(m_json_stack.back().start); + else + m_msg_buf.append(1, type); + + m_json_stack.pop_back(); +} + +void TilesFramework::json_open_object(const string& name) +{ + json_open(name, '{', '}'); } -void TilesFramework::json_close_array() +void TilesFramework::json_close_object(bool erase_if_empty) { - write_message("]"); - json_object_level--; - need_comma = true; + json_close(erase_if_empty, '}'); +} + +void TilesFramework::json_open_array(const string& name) +{ + json_open(name, '[', ']'); +} + +void TilesFramework::json_close_array(bool erase_if_empty) +{ + json_close(erase_if_empty, ']'); } void TilesFramework::json_write_comma() { - if (json_object_level > 0 && need_comma) - { - write_message(","); - need_comma = false; - } + if (m_msg_buf.empty()) return; + char last = m_msg_buf[m_msg_buf.size() - 1]; + if (last == '{' || last == '[' || last == ',' || last == ':') return; + write_message(","); } void TilesFramework::json_write_name(const string& name) @@ -1489,8 +1517,6 @@ void TilesFramework::json_write_int(int value) json_write_comma(); write_message("%d", value); - - need_comma = true; } void TilesFramework::json_write_int(const string& name, int value) @@ -1501,6 +1527,39 @@ void TilesFramework::json_write_int(const string& name, int value) json_write_int(value); } +void TilesFramework::json_write_bool(bool value) +{ + json_write_comma(); + + if (value) + write_message("true"); + else + write_message("false"); +} + +void TilesFramework::json_write_bool(const string& name, bool value) +{ + if (!name.empty()) + json_write_name(name); + + json_write_bool(value); +} + +void TilesFramework::json_write_null() +{ + json_write_comma(); + + write_message("null"); +} + +void TilesFramework::json_write_null(const string& name) +{ + if (!name.empty()) + json_write_name(name); + + json_write_null(); +} + void TilesFramework::json_write_string(const string& value) { json_write_comma(); @@ -1508,8 +1567,6 @@ void TilesFramework::json_write_string(const string& value) write_message("\""); write_message_escaped(value); write_message("\""); - - need_comma = true; } void TilesFramework::json_write_string(const string& name, const string& value) diff --git a/crawl-ref/source/tileweb.h b/crawl-ref/source/tileweb.h index 77d0ded425..00969068a3 100644 --- a/crawl-ref/source/tileweb.h +++ b/crawl-ref/source/tileweb.h @@ -81,10 +81,8 @@ public: void pop_menu(); void close_all_menus(); - void write_message(); void write_message(PRINTF(1, )); void finish_message(); - void send_message(); void send_message(PRINTF(1, )); bool has_receivers() { return !m_dest_addrs.empty(); } @@ -109,27 +107,28 @@ public: void check_for_control_messages(); - /* Adds a prefix that will be written before any other - data that is sent after this call, unless no other - data is sent until pop_prefix is called. The suffix - passed to pop_prefix will only be sent if the prefix - was sent. */ - void push_prefix(const string& prefix); - void pop_prefix(const string& suffix); - bool prefix_popped(); - // Helper functions for writing JSON void write_message_escaped(const string& s); void json_open_object(const string& name = ""); - void json_close_object(); + void json_close_object(bool erase_if_empty = false); void json_open_array(const string& name = ""); - void json_close_array(); + void json_close_array(bool erase_if_empty = false); void json_write_comma(); void json_write_name(const string& name); void json_write_int(int value); void json_write_int(const string& name, int value); + void json_write_bool(bool value); + void json_write_bool(const string& name, bool value); + void json_write_null(); + void json_write_null(const string& name); void json_write_string(const string& value); void json_write_string(const string& name, const string& value); + /* Causes the current object/array to be erased if it is closed + with erase_if_empty without writing any other content after + this call */ + void json_treat_as_empty(); + void json_treat_as_nonempty(); + bool json_is_empty(); string m_sock_name; bool m_await_connection; @@ -155,9 +154,16 @@ protected: wint_t _handle_control_message(sockaddr_un addr, string data); wint_t _receive_control_message(); - vector<string> m_prefixes; - int json_object_level; - bool need_comma; + struct JsonFrame + { + int start; + int prefix_end; + char type; // '}' or ']' + }; + vector<JsonFrame> m_json_stack; + + void json_open(const string& name, char opener, char type); + void json_close(bool erase_if_empty, char type); struct MenuInfo { diff --git a/crawl-ref/source/webserver/game_data/static/cell_renderer.js b/crawl-ref/source/webserver/game_data/static/cell_renderer.js index 8a674b4e62..1b64704974 100644 --- a/crawl-ref/source/webserver/game_data/static/cell_renderer.js +++ b/crawl-ref/source/webserver/game_data/static/cell_renderer.js @@ -389,14 +389,14 @@ function ($, view_data, main, player, icons, dngn, enums, map_knowledge, tileinf } else if (cell.bloody) { - cell.bloodrot = cell.bloodrot || 0; + cell.blood_rotation = cell.blood_rotation || 0; var basetile; if (is_wall) { basetile = cell.old_blood ? dngn.WALL_OLD_BLOOD : dngn.WALL_BLOOD_S; - basetile += dngn.tile_count(basetile) * cell.bloodrot; + basetile += dngn.tile_count(basetile) * cell.blood_rotation; basetile = dngn.WALL_BLOOD_S + dngn.tile_count(dngn.WALL_BLOOD_S) - * cell.bloodrot; + * cell.blood_rotation; } else basetile = dngn.BLOOD; @@ -420,7 +420,7 @@ function ($, view_data, main, player, icons, dngn, enums, map_knowledge, tileinf var bg = cell.bg; var bg_idx = cell.bg.value; - if (cell.swtree && bg_idx > dngn.DNGN_UNSEEN) + if (cell.mangrove_water && bg_idx > dngn.DNGN_UNSEEN) this.draw_dngn(dngn.DNGN_SHALLOW_WATER, x, y); else if (bg_idx >= dngn.DNGN_FIRST_TRANSPARENT) this.draw_dngn(cell.flv.f, x, y); // f = floor @@ -429,7 +429,7 @@ function ($, view_data, main, player, icons, dngn, enums, map_knowledge, tileinf if (bg_idx > dngn.WALL_MAX) this.draw_blood_overlay(x, y, cell); - if (cell.swtree) // Draw the tree submerged + if (cell.mangrove_water) // Draw the tree submerged { this.ctx.save(); try @@ -721,15 +721,15 @@ function ($, view_data, main, player, icons, dngn, enums, map_knowledge, tileinf this.draw_icon(icons.CURSOR3, x, y); } - if (cell.tt & 0xF) + if (cell.travel_trail & 0xF) { this.draw_icon(icons.TRAVEL_PATH_FROM + - (cell.tt & 0xF) - 1, x, y); + (cell.travel_trail & 0xF) - 1, x, y); } - if (cell.tt & 0xF0) + if (cell.travel_trail & 0xF0) { this.draw_icon(icons.TRAVEL_PATH_TO + - ((cell.tt & 0xF0) >> 4) - 1, x, y); + ((cell.travel_trail & 0xF0) >> 4) - 1, x, y); } if (fg.MDAM_LIGHT) |