From 3f69fdbfbebba74e3dcabcfa61f506a7929b072f Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:26:15 +0100 Subject: [PATCH 01/21] Fix documentation: JSON classes throw JsonError. --- src/item_factory.h | 6 +++--- src/item_group.h | 2 +- src/mod_manager.h | 3 +-- src/mutation.h | 4 ++-- src/trait_group.h | 2 +- src/trap.h | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/item_factory.h b/src/item_factory.h index 947bdbff6f182..45ec7ddbe022c 100644 --- a/src/item_factory.h +++ b/src/item_factory.h @@ -86,7 +86,7 @@ class Item_factory /** * Callback for the init system (@ref DynamicDataLoader), loads an item group definitions. * @param jsobj The json object to load from. - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ void load_item_group( const JsonObject &jsobj ); /** @@ -99,7 +99,7 @@ class Item_factory * @param group_id The ident of the item that is to be loaded. * @param subtype The type of the item group, either "collection", "distribution" or "old" * ("old" is a distribution, too). - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ void load_item_group( const JsonObject &jsobj, const Group_tag &group_id, const std::string &subtype ); @@ -148,7 +148,7 @@ class Item_factory * These function load different instances of itype objects from json. * The loaded item types are stored and can be accessed through @ref find_template. * @param jo The json object to load data from. - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ /*@{*/ void load_ammo( const JsonObject &jo, const std::string &src ); diff --git a/src/item_group.h b/src/item_group.h index f38f38cdf7cba..81b050ac6803e 100644 --- a/src/item_group.h +++ b/src/item_group.h @@ -93,7 +93,7 @@ void load_item_group( const JsonObject &jsobj, const Group_tag &group_id, * @param stream Stream to load from * @param default_subtype If an inlined item group is loaded this is used as the default * subtype. It must be either "distribution" or "collection". See @ref Item_group. - * @throw std::string as usual for JSON errors, including invalid input values. + * @throw JsonError as usual for JSON errors, including invalid input values. */ Group_tag load_item_group( JsonIn &stream, const std::string &default_subtype ); } // namespace item_group diff --git a/src/mod_manager.h b/src/mod_manager.h index 5722324fa76ad..d83ce12f037ff 100644 --- a/src/mod_manager.h +++ b/src/mod_manager.h @@ -141,8 +141,7 @@ class mod_manager /** * Load mod info from a json object. Put the loaded modinfo * directly into @ref mod_map. - * @throws std::string on all kind of errors. The string - * contains the error message. + * @throws JsonError on all kind of errors. */ void load_modfile( const JsonObject &jo, const std::string &path ); diff --git a/src/mutation.h b/src/mutation.h index 40d27df15ab01..e2a06a1295e50 100644 --- a/src/mutation.h +++ b/src/mutation.h @@ -316,7 +316,7 @@ struct mutation_branch { * Callback for the init system (@ref DynamicDataLoader), loads a trait * group definitions. * @param jsobj The json object to load from. - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ static void load_trait_group( const JsonObject &jsobj ); @@ -332,7 +332,7 @@ struct mutation_branch { * @param gid The ID of the group that is to be loaded. * @param subtype The type of the trait group, either "collection", "distribution" or "old" * (i.e. the old list-based format, `[ ["TRAIT", 100] ]`). - * @throw std::string if the json object contains invalid data. + * @throw JsonError if the json object contains invalid data. */ static void load_trait_group( const JsonObject &jsobj, const trait_group::Trait_group_tag &gid, const std::string &subtype ); diff --git a/src/trait_group.h b/src/trait_group.h index 4744814629e54..7cc93a437ca3a 100644 --- a/src/trait_group.h +++ b/src/trait_group.h @@ -52,7 +52,7 @@ void load_trait_group( const JsonObject &jsobj, const Trait_group_tag &gid, * @param stream Stream to load from * @param default_subtype If an inlined trait group is loaded this is used as the default * subtype. It must be either "distribution" or "collection". See @ref Trait_group. - * @throw std::string as usual for JSON errors, including invalid input values. + * @throw JsonError as usual for JSON errors, including invalid input values. */ Trait_group_tag load_trait_group( JsonIn &stream, const std::string &default_subtype ); diff --git a/src/trap.h b/src/trap.h index c5b075f7cc398..c8e61e96bf25e 100644 --- a/src/trap.h +++ b/src/trap.h @@ -229,7 +229,7 @@ struct trap { */ /** * Loads the trap and adds it to the trapmap, and the traplist. - * @throw std::string if the json is invalid as usual. + * @throw JsonError if the json is invalid as usual. */ static void load_trap( const JsonObject &jo, const std::string &src ); /** From 884fa50a4b19464ec4fa90f500230b88e54ff58a Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:10:34 +0100 Subject: [PATCH 02/21] Don't skip JSON data in unexpected form, trigger an error instead. The current code would just skip the array entry if it was neither a string nor an object. There is no indication to the modder that their data has been ignored. The new code will trigger an error instead. The modder will know about the invalid format. --- src/condition.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/condition.cpp b/src/condition.cpp index 9925b46a53426..bdbb425f986da 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -899,12 +899,10 @@ conditional_t::conditional_t( const JsonObject &jo ) if( ja.test_string() ) { conditional_t type_condition( ja.next_string() ); conditionals.emplace_back( type_condition ); - } else if( ja.test_object() ) { + } else { JsonObject cond = ja.next_object(); conditional_t type_condition( cond ); conditionals.emplace_back( type_condition ); - } else { - ja.skip_value(); } } return conditionals; From d7334f6d16cb389fee71527d0039b9f252487676 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:10:10 +0100 Subject: [PATCH 03/21] Avoid UB: actually set the JsonObject to something before using it. --- src/magic_enchantment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index e654109134787..c2a8c1044a4c9 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -202,7 +202,7 @@ void enchantment::load( const JsonObject &jo, const std::string & ) JsonObject jobj = jo.get_object( "intermittent_activation" ); JsonArray jarray = jo.get_array( "effects" ); while( jarray.has_more() ) { - JsonObject effect_obj; + JsonObject effect_obj = jarray.next_object(); time_duration dur = read_from_json_string( *effect_obj.get_raw( "frequency" ), time_duration::units ); if( effect_obj.has_array( "spell_effects" ) ) { From 31a61ecff5c171c3861bc40e1f32b0e44ca11fe4 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:12:11 +0100 Subject: [PATCH 04/21] Call dedicated clear method instead of clearing by assigning an empty value. --- src/crafting_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index c68a233dd21bd..870ed894f370e 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -82,7 +82,7 @@ void load_recipe_category( const JsonObject &jsobj ) const std::string cat_name = get_cat_unprefixed( category ); - craft_subcat_list[category] = std::vector(); + craft_subcat_list[category].clear(); JsonArray subcats = jsobj.get_array( "recipe_subcategories" ); while( subcats.has_more() ) { const std::string subcat_id = subcats.next_string(); From b396d120d6ef2a9d909102fcd834f367e39b1406 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:14:41 +0100 Subject: [PATCH 05/21] Fix accessing an unrelated JSON entry: The code would always use the first entry of the parent array (`trait`) instead of the that of the subarray. It would however use the *second* value of the subarray and skip the first one. Makes no sense. --- src/mutation_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index 9adbc6a75eaac..d7ae65077c568 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -704,7 +704,7 @@ void mutation_branch::load_trait_group( const JsonObject &jsobj, tg.add_group_entry( trait_group::Trait_group_tag( traits.next_string() ), 100 ); } else if( traits.test_array() ) { JsonArray subtrait = traits.next_array(); - tg.add_group_entry( trait_group::Trait_group_tag( traits.get_string( 0 ) ), subtrait.get_int( 1 ) ); + tg.add_group_entry( trait_group::Trait_group_tag( subtrait.get_string( 0 ) ), subtrait.get_int( 1 ) ); } else { JsonObject subobj = traits.next_object(); add_entry( tg, subobj ); From d09813419a02f0b07bad5629c593af881ed1461c Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:37:05 +0100 Subject: [PATCH 06/21] Remove unnecessary emptiness check. There is a check for whether the array has more entries. That one will catch empty array. --- src/savegame_json.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 4629e0ea02a3f..8504c1b88d732 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -1826,20 +1826,18 @@ void monster::load( const JsonObject &data ) // sp_timeout indicates an old save, prior to the special_attacks refactor if( data.has_array( "sp_timeout" ) ) { JsonArray parray = data.get_array( "sp_timeout" ); - if( !parray.empty() ) { - int index = 0; - int ptimeout = 0; - while( parray.has_more() && index < static_cast( type->special_attacks_names.size() ) ) { - if( parray.read_next( ptimeout ) ) { - // assume timeouts saved in same order as current monsters.json listing - const std::string &aname = type->special_attacks_names[index++]; - auto &entry = special_attacks[aname]; - if( ptimeout >= 0 ) { - entry.cooldown = ptimeout; - } else { // -1 means disabled, unclear what <-1 values mean in old saves - entry.cooldown = type->special_attacks.at( aname )->cooldown; - entry.enabled = false; - } + int index = 0; + int ptimeout = 0; + while( parray.has_more() && index < static_cast( type->special_attacks_names.size() ) ) { + if( parray.read_next( ptimeout ) ) { + // assume timeouts saved in same order as current monsters.json listing + const std::string &aname = type->special_attacks_names[index++]; + auto &entry = special_attacks[aname]; + if( ptimeout >= 0 ) { + entry.cooldown = ptimeout; + } else { // -1 means disabled, unclear what <-1 values mean in old saves + entry.cooldown = type->special_attacks.at( aname )->cooldown; + entry.enabled = false; } } } From 4fddade98b08a2123ccda5e00bb5b2aa071e7586 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 19:02:06 +0100 Subject: [PATCH 07/21] Remove redundant check for existence of array *after* getting it. --- src/field_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field_type.cpp b/src/field_type.cpp index 3de5c96d72a39..d2a246f1150f4 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -122,7 +122,7 @@ void field_type::load( const JsonObject &jo, const std::string & ) { optional( jo, was_loaded, "legacy_enum_id", legacy_enum_id, -1 ); JsonArray ja = jo.get_array( "intensity_levels" ); - if( !jo.has_array( "intensity_levels" ) || ja.empty() ) { + if( ja.empty() ) { jo.throw_error( "No intensity levels defined for field type", "id" ); } for( size_t i = 0; i < ja.size(); ++i ) { From 7355bedf9a5880f310351148805e770203ccfb5d Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 19:03:20 +0100 Subject: [PATCH 08/21] Move field type consistency check to after the loop. It checks the same thing essentially: that there is at least one intensity level defined. --- src/field_type.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/field_type.cpp b/src/field_type.cpp index d2a246f1150f4..3ba0b00087483 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -122,9 +122,6 @@ void field_type::load( const JsonObject &jo, const std::string & ) { optional( jo, was_loaded, "legacy_enum_id", legacy_enum_id, -1 ); JsonArray ja = jo.get_array( "intensity_levels" ); - if( ja.empty() ) { - jo.throw_error( "No intensity levels defined for field type", "id" ); - } for( size_t i = 0; i < ja.size(); ++i ) { field_intensity_level intensity_level; field_intensity_level fallback_intensity_level = i > 0 ? intensity_levels[i - 1] : intensity_level; @@ -199,6 +196,9 @@ void field_type::load( const JsonObject &jo, const std::string & ) fallback_intensity_level.scent_neutralization ); intensity_levels.emplace_back( intensity_level ); } + if( intensity_levels.empty() ) { + jo.throw_error( "No intensity levels defined for field type", "id" ); + } if( jo.has_object( "npc_complain" ) ) { JsonObject joc = jo.get_object( "npc_complain" ); From 924cbc54fe76678aea74560c70c467a9373125af Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:37:58 +0100 Subject: [PATCH 09/21] Use proper type so we don't have to cast it. --- src/savegame_json.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 8504c1b88d732..47dbe2971818f 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -1826,9 +1826,9 @@ void monster::load( const JsonObject &data ) // sp_timeout indicates an old save, prior to the special_attacks refactor if( data.has_array( "sp_timeout" ) ) { JsonArray parray = data.get_array( "sp_timeout" ); - int index = 0; + size_t index = 0; int ptimeout = 0; - while( parray.has_more() && index < static_cast( type->special_attacks_names.size() ) ) { + while( parray.has_more() && index < type->special_attacks_names.size() ) { if( parray.read_next( ptimeout ) ) { // assume timeouts saved in same order as current monsters.json listing const std::string &aname = type->special_attacks_names[index++]; From 1d2b89c13dad17f02c1c286da7a09bcfbce6f184 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:19:37 +0100 Subject: [PATCH 10/21] Replace usage of JsonArray::has_more with range-based loops. --- src/artifact.cpp | 30 +++---- src/bionics.cpp | 21 ++--- src/cata_tiles.cpp | 37 +++------ src/clothing_mod.cpp | 11 +-- src/condition.cpp | 9 +-- src/construction.cpp | 9 +-- src/crafting_gui.cpp | 4 +- src/damage.cpp | 4 +- src/effect.cpp | 25 +++--- src/fault.cpp | 8 +- src/field_type.cpp | 9 +-- src/harvest.cpp | 4 +- src/input.cpp | 12 +-- src/item_factory.cpp | 137 ++++++++++++-------------------- src/iuse_actor.cpp | 41 ++++------ src/json.cpp | 15 ++-- src/json.h | 19 +++++ src/magic_enchantment.cpp | 12 +-- src/magic_ter_fur_transform.cpp | 9 +-- src/mapgen.cpp | 46 +++++------ src/monstergenerator.cpp | 13 ++- src/mutation_data.cpp | 29 +++---- src/npctalk.cpp | 44 +++++----- src/trap.cpp | 18 ++--- src/uistate.h | 5 +- src/veh_type.cpp | 19 ++--- 26 files changed, 236 insertions(+), 354 deletions(-) diff --git a/src/artifact.cpp b/src/artifact.cpp index 45d88b054a101..84c85c0606646 100644 --- a/src/artifact.cpp +++ b/src/artifact.cpp @@ -1209,36 +1209,31 @@ void it_artifact_tool::deserialize( const JsonObject &jo ) artifact->charge_req = ACR_NULL; } - JsonArray ja = jo.get_array( "effects_wielded" ); - while( ja.has_more() ) { - artifact->effects_wielded.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_wielded" ) ) { + artifact->effects_wielded.push_back( static_cast( entry ) ); } - ja = jo.get_array( "effects_activated" ); - while( ja.has_more() ) { - artifact->effects_activated.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_activated" ) ) { + artifact->effects_activated.push_back( static_cast( entry ) ); } - ja = jo.get_array( "effects_carried" ); - while( ja.has_more() ) { - artifact->effects_carried.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_carried" ) ) { + artifact->effects_carried.push_back( static_cast( entry ) ); } //Generate any missing dream data (due to e.g. old save) if( !jo.has_array( "dream_unmet" ) ) { artifact->dream_msg_unmet = artifact_dream_data[static_cast( artifact->charge_req )].msg_unmet; } else { - ja = jo.get_array( "dream_unmet" ); - while( ja.has_more() ) { - artifact->dream_msg_unmet.push_back( ja.next_string() ); + for( const std::string &line : jo.get_array( "dream_unmet" ) ) { + artifact->dream_msg_unmet.push_back( line ); } } if( !jo.has_array( "dream_met" ) ) { artifact->dream_msg_met = artifact_dream_data[static_cast( artifact->charge_req )].msg_met; } else { - ja = jo.get_array( "dream_met" ); - while( ja.has_more() ) { - artifact->dream_msg_met.push_back( ja.next_string() ); + for( const std::string &line : jo.get_array( "dream_met" ) ) { + artifact->dream_msg_met.push_back( line ); } } if( jo.has_int( "dream_freq_unmet" ) ) { @@ -1303,9 +1298,8 @@ void it_artifact_armor::deserialize( const JsonObject &jo ) armor->storage = jo.get_int( "storage" ) * units::legacy_volume_factor; armor->power_armor = jo.get_bool( "power_armor" ); - JsonArray ja = jo.get_array( "effects_worn" ); - while( ja.has_more() ) { - artifact->effects_worn.push_back( static_cast( ja.next_int() ) ); + for( const int entry : jo.get_array( "effects_worn" ) ) { + artifact->effects_worn.push_back( static_cast( entry ) ); } } diff --git a/src/bionics.cpp b/src/bionics.cpp index 8f583517fd7a5..2940a53f9d2c6 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -2308,30 +2308,22 @@ void load_bionic( const JsonObject &jsobj ) jsobj.read( "fuel_options", new_bionic.fuel_opts ); jsobj.read( "fuel_capacity", new_bionic.fuel_capacity ); - JsonArray jsr = jsobj.get_array( "stat_bonus" ); - while( jsr.has_more() ) { - JsonArray ja = jsr.next_array(); + for( JsonArray ja : jsobj.get_array( "stat_bonus" ) ) { new_bionic.stat_bonus.emplace( io::string_to_enum( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } - JsonArray jsar = jsobj.get_array( "encumbrance" ); - while( jsar.has_more() ) { - JsonArray ja = jsar.next_array(); + for( JsonArray ja : jsobj.get_array( "encumbrance" ) ) { new_bionic.encumbrance.emplace( get_body_part_token( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } - JsonArray jsarr = jsobj.get_array( "occupied_bodyparts" ); - while( jsarr.has_more() ) { - JsonArray ja = jsarr.next_array(); + for( JsonArray ja : jsobj.get_array( "occupied_bodyparts" ) ) { new_bionic.occupied_bodyparts.emplace( get_body_part_token( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } - JsonArray json_arr = jsobj.get_array( "env_protec" ); - while( json_arr.has_more() ) { - JsonArray ja = json_arr.next_array(); + for( JsonArray ja : jsobj.get_array( "env_protec" ) ) { new_bionic.env_protec.emplace( get_body_part_token( ja.get_string( 0 ) ), ja.get_int( 1 ) ); } @@ -2529,9 +2521,8 @@ void bionic::deserialize( JsonIn &jsin ) auto_start_threshold = jo.get_float( "auto_start_threshold" ); } if( jo.has_array( "bionic_tags" ) ) { - JsonArray jsar = jo.get_array( "bionic_tags" ); - while( jsar.has_more() ) { - bionic_tags.insert( jsar.next_string() ); + for( const std::string &line : jo.get_array( "bionic_tags" ) ) { + bionic_tags.insert( line ); } } diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index c748b590ef9b4..1d47d43202dcb 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -542,9 +542,7 @@ void tileset_loader::load( const std::string &tileset_id, const bool precheck ) config.throw_error( "\"tile_info\" missing" ); } - JsonArray info = config.get_array( "tile_info" ); - while( info.has_more() ) { - JsonObject curr_info = info.next_object(); + for( const JsonObject &curr_info : config.get_array( "tile_info" ) ) { ts.tile_height = curr_info.get_int( "height" ); ts.tile_width = curr_info.get_int( "width" ); tile_iso = curr_info.get_bool( "iso", false ); @@ -581,9 +579,7 @@ void tileset_loader::load( const std::string &tileset_id, const bool precheck ) int num_in_file = 1; if( mod_config_json.test_array() ) { - JsonArray mod_config_array = mod_config_json.get_array(); - while( mod_config_array.has_more() ) { - JsonObject mod_config = mod_config_array.next_object(); + for( const JsonObject &mod_config : mod_config_json.get_array() ) { if( mod_config.get_string( "type" ) == "mod_tileset" ) { if( num_in_file == mts.num_in_file() ) { load_internal( mod_config, tileset_root, img_path ); @@ -628,9 +624,7 @@ void tileset_loader::load_internal( const JsonObject &config, const std::string // new system, several entries // When loading multiple tileset images this defines where // the tiles from the most recently loaded image start from. - JsonArray tiles_new = config.get_array( "tiles-new" ); - while( tiles_new.has_more() ) { - JsonObject tile_part_def = tiles_new.next_object(); + for( const JsonObject &tile_part_def : config.get_array( "tiles-new" ) ) { const std::string tileset_image_path = tileset_root + '/' + tile_part_def.get_string( "file" ); R = -1; G = -1; @@ -728,9 +722,7 @@ void tileset_loader::load_ascii( const JsonObject &config ) if( !config.has_member( "ascii" ) ) { config.throw_error( "\"ascii\" section missing" ); } - JsonArray ascii = config.get_array( "ascii" ); - while( ascii.has_more() ) { - JsonObject entry = ascii.next_object(); + for( const JsonObject &entry : config.get_array( "ascii" ) ) { load_ascii_set( entry ); } } @@ -850,10 +842,7 @@ void tileset_loader::load_tilejson_from_file( const JsonObject &config ) config.throw_error( "\"tiles\" section missing" ); } - JsonArray tiles = config.get_array( "tiles" ); - while( tiles.has_more() ) { - JsonObject entry = tiles.next_object(); - + for( const JsonObject &entry : config.get_array( "tiles" ) ) { std::vector ids; if( entry.has_string( "id" ) ) { ids.push_back( entry.get_string( "id" ) ); @@ -868,9 +857,7 @@ void tileset_loader::load_tilejson_from_file( const JsonObject &config ) int t_h3d = entry.get_int( "height_3d", 0 ); if( t_multi ) { // fetch additional tiles - JsonArray subentries = entry.get_array( "additional_tiles" ); - while( subentries.has_more() ) { - JsonObject subentry = subentries.next_object(); + for( const JsonObject &subentry : entry.get_array( "additional_tiles" ) ) { const std::string s_id = subentry.get_string( "id" ); const std::string m_id = t_id + "_" + s_id; tile_type &curr_subtile = load_tile( subentry, m_id ); @@ -921,8 +908,8 @@ void tileset_loader::load_tile_spritelists( const JsonObject &entry, // create one variation, populate sprite_ids with list of ints if( g_array.test_int() ) { std::vector v; - while( g_array.has_more() ) { - const int sprite_id = g_array.next_int() + sprite_id_offset; + for( const int entry : g_array ) { + const int sprite_id = entry + sprite_id_offset; if( sprite_id >= 0 ) { v.push_back( sprite_id ); } @@ -932,9 +919,8 @@ void tileset_loader::load_tile_spritelists( const JsonObject &entry, // object elements of array indicates variations // create one variation per object else if( g_array.test_object() ) { - while( g_array.has_more() ) { + for( const JsonObject &vo : g_array ) { std::vector v; - JsonObject vo = g_array.next_object(); int weight = vo.get_int( "weight" ); // negative weight is invalid if( weight < 0 ) { @@ -949,9 +935,8 @@ void tileset_loader::load_tile_spritelists( const JsonObject &entry, } // array sprite means rotations else if( vo.has_array( "sprite" ) ) { - JsonArray sprites = vo.get_array( "sprite" ); - while( sprites.has_more() ) { - const int sprite_id = sprites.next_int() + sprite_id_offset; + for( const int entry : vo.get_array( "sprite" ) ) { + const int sprite_id = entry + sprite_id_offset; if( sprite_id >= 0 && sprite_id < size ) { v.push_back( sprite_id ); } else { diff --git a/src/clothing_mod.cpp b/src/clothing_mod.cpp index 51cf5eeea1264..e28f7ad4be378 100644 --- a/src/clothing_mod.cpp +++ b/src/clothing_mod.cpp @@ -64,24 +64,21 @@ void clothing_mod::load( const JsonObject &jo, const std::string & ) mandatory( jo, was_loaded, "destroy_prompt", destroy_prompt ); optional( jo, was_loaded, "restricted", restricted, false ); - JsonArray jarr = jo.get_array( "mod_value" ); - while( jarr.has_more() ) { - JsonObject mv_jo = jarr.next_object(); + for( const JsonObject &mv_jo : jo.get_array( "mod_value" ) ) { mod_value mv; std::string temp_str; mandatory( mv_jo, was_loaded, "type", temp_str ); mv.type = io::string_to_enum( temp_str ); mandatory( mv_jo, was_loaded, "value", mv.value ); optional( mv_jo, was_loaded, "round_up", mv.round_up ); - JsonArray jarr_prop = mv_jo.get_array( "proportion" ); - while( jarr_prop.has_more() ) { - std::string str = jarr_prop.next_string(); + for( const JsonValue &entry : mv_jo.get_array( "proportion" ) ) { + const std::string &str = entry.get_string(); if( str == "thickness" ) { mv.thickness_propotion = true; } else if( str == "coverage" ) { mv.coverage_propotion = true; } else { - jarr_prop.throw_error( R"(Invalid value, valid are: "coverage" and "thickness")" ); + entry.throw_error( R"(Invalid value, valid are: "coverage" and "thickness")" ); } } mod_values.push_back( mv ); diff --git a/src/condition.cpp b/src/condition.cpp index bdbb425f986da..8a196f95fb223 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -894,13 +894,12 @@ conditional_t::conditional_t( const JsonObject &jo ) bool found_sub_member = false; const auto parse_array = []( const JsonObject & jo, const std::string & type ) { std::vector conditionals; - JsonArray ja = jo.get_array( type ); - while( ja.has_more() ) { - if( ja.test_string() ) { - conditional_t type_condition( ja.next_string() ); + for( const JsonValue &entry : jo.get_array( type ) ) { + if( entry.test_string() ) { + conditional_t type_condition( entry.get_string() ); conditionals.emplace_back( type_condition ); } else { - JsonObject cond = ja.next_object(); + JsonObject cond = entry.get_object(); conditional_t type_condition( cond ); conditionals.emplace_back( type_condition ); } diff --git a/src/construction.cpp b/src/construction.cpp index 32e20794772ec..55974e535c850 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -1344,9 +1344,7 @@ void load_construction( const JsonObject &jo ) con.description = jo.get_string( "description" ); if( jo.has_member( "required_skills" ) ) { - auto sk = jo.get_array( "required_skills" ); - while( sk.has_more() ) { - auto arr = sk.next_array(); + for( JsonArray arr : jo.get_array( "required_skills" ) ) { con.required_skills[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } else { @@ -1371,10 +1369,7 @@ void load_construction( const JsonObject &jo ) if( jo.has_string( "using" ) ) { con.reqs_using = { { requirement_id( jo.get_string( "using" ) ), 1} }; } else if( jo.has_array( "using" ) ) { - auto arr = jo.get_array( "using" ); - - while( arr.has_more() ) { - auto cur = arr.next_array(); + for( JsonArray cur : jo.get_array( "using" ) ) { con.reqs_using.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) ); } } diff --git a/src/crafting_gui.cpp b/src/crafting_gui.cpp index 870ed894f370e..cbf0aae4a8681 100644 --- a/src/crafting_gui.cpp +++ b/src/crafting_gui.cpp @@ -83,9 +83,7 @@ void load_recipe_category( const JsonObject &jsobj ) const std::string cat_name = get_cat_unprefixed( category ); craft_subcat_list[category].clear(); - JsonArray subcats = jsobj.get_array( "recipe_subcategories" ); - while( subcats.has_more() ) { - const std::string subcat_id = subcats.next_string(); + for( const std::string &subcat_id : jsobj.get_array( "recipe_subcategories" ) ) { if( subcat_id.find( "CSC_" + cat_name + "_" ) != 0 && subcat_id != "CSC_ALL" ) { jsobj.throw_error( "Crafting sub-category id has to be prefixed with CSC__" ); } diff --git a/src/damage.cpp b/src/damage.cpp index d871128c9a897..1442a61872bf6 100644 --- a/src/damage.cpp +++ b/src/damage.cpp @@ -304,9 +304,7 @@ damage_instance load_damage_instance( const JsonObject &jo ) { damage_instance di; if( jo.has_array( "values" ) ) { - JsonArray jarr = jo.get_array( "values" ); - while( jarr.has_more() ) { - JsonObject curr = jarr.next_object(); + for( const JsonObject &curr : jo.get_array( "values" ) ) { di.damage_units.push_back( load_damage_unit( curr ) ); } } else if( jo.has_string( "damage_type" ) ) { diff --git a/src/effect.cpp b/src/effect.cpp index f07f10c47b290..49fd3aa1ad9e3 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -452,9 +452,7 @@ bool effect_type::is_show_in_info() const bool effect_type::load_miss_msgs( const JsonObject &jo, const std::string &member ) { if( jo.has_array( member ) ) { - JsonArray outer = jo.get_array( member ); - while( outer.has_more() ) { - JsonArray inner = outer.next_array(); + for( JsonArray inner : jo.get_array( member ) ) { miss_msgs.push_back( std::make_pair( inner.get_string( 0 ), inner.get_int( 1 ) ) ); } return true; @@ -464,9 +462,7 @@ bool effect_type::load_miss_msgs( const JsonObject &jo, const std::string &membe bool effect_type::load_decay_msgs( const JsonObject &jo, const std::string &member ) { if( jo.has_array( member ) ) { - JsonArray outer = jo.get_array( member ); - while( outer.has_more() ) { - JsonArray inner = outer.next_array(); + for( JsonArray inner : jo.get_array( member ) ) { std::string msg = inner.get_string( 0 ); std::string r = inner.get_string( 1 ); game_message_type rate = m_neutral; @@ -1213,11 +1209,10 @@ void load_effect_type( const JsonObject &jo ) new_etype.id = efftype_id( jo.get_string( "id" ) ); if( jo.has_member( "name" ) ) { - JsonArray jsarr = jo.get_array( "name" ); - while( jsarr.has_more() ) { + for( const JsonValue &entry : jo.get_array( "name" ) ) { translation name; - if( !jsarr.read_next( name ) ) { - jsarr.throw_error( "Error reading effect names" ); + if( !entry.read( name ) ) { + entry.throw_error( "Error reading effect names" ); } new_etype.name.emplace_back( name ); } @@ -1227,17 +1222,15 @@ void load_effect_type( const JsonObject &jo ) new_etype.speed_mod_name = jo.get_string( "speed_name", "" ); if( jo.has_member( "desc" ) ) { - JsonArray jsarr = jo.get_array( "desc" ); - while( jsarr.has_more() ) { - new_etype.desc.push_back( jsarr.next_string() ); + for( const std::string &line : jo.get_array( "desc" ) ) { + new_etype.desc.push_back( line ); } } else { new_etype.desc.push_back( "" ); } if( jo.has_member( "reduced_desc" ) ) { - JsonArray jsarr = jo.get_array( "reduced_desc" ); - while( jsarr.has_more() ) { - new_etype.reduced_desc.push_back( jsarr.next_string() ); + for( const std::string &line : jo.get_array( "reduced_desc" ) ) { + new_etype.reduced_desc.push_back( line ); } } else { new_etype.reduced_desc = new_etype.desc; diff --git a/src/fault.cpp b/src/fault.cpp index 0991520cab024..5ee6719394b79 100644 --- a/src/fault.cpp +++ b/src/fault.cpp @@ -39,9 +39,7 @@ void fault::load_fault( const JsonObject &jo ) mandatory( jo, false, "name", f.name_ ); mandatory( jo, false, "description", f.description_ ); - JsonArray ja_methods = jo.get_array( "mending_methods" ); - while( ja_methods.has_more() ) { - JsonObject jo_method = ja_methods.next_object(); + for( const JsonObject &jo_method : jo.get_array( "mending_methods" ) ) { mending_method m; mandatory( jo_method, false, "id", m.id ); @@ -50,9 +48,7 @@ void fault::load_fault( const JsonObject &jo ) mandatory( jo_method, false, "success_msg", m.success_msg ); mandatory( jo_method, false, "time", m.time ); - JsonArray jo_skills = jo_method.get_array( "skills" ); - while( jo_skills.has_more() ) { - JsonObject jo_skill = jo_skills.next_object(); + for( const JsonObject &jo_skill : jo_method.get_array( "skills" ) ) { skill_id sk_id; mandatory( jo_skill, false, "id", sk_id ); m.skills.emplace( sk_id, jo_skill.get_int( "level" ) ); diff --git a/src/field_type.cpp b/src/field_type.cpp index 3ba0b00087483..7e7833143e5ff 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -214,13 +214,10 @@ void field_type::load( const JsonObject &jo, const std::string & ) } JsonObject jid = jo.get_object( "immunity_data" ); - JsonArray jidt = jid.get_array( "traits" ); - while( jidt.has_more() ) { - immunity_data_traits.emplace_back( trait_id( jidt.next_string() ) ); + for( const std::string &id : jid.get_array( "traits" ) ) { + immunity_data_traits.emplace_back( id ); } - JsonArray jidr = jid.get_array( "body_part_env_resistance" ); - while( jidr.has_more() ) { - JsonArray jao = jidr.next_array(); + for( JsonArray jao : jid.get_array( "body_part_env_resistance" ) ) { immunity_data_body_part_env_resistance.emplace_back( std::make_pair( get_body_part_token( jao.get_string( 0 ) ), jao.get_int( 1 ) ) ); } diff --git a/src/harvest.cpp b/src/harvest.cpp index 4d1db71646bb7..cc29a1e18029f 100644 --- a/src/harvest.cpp +++ b/src/harvest.cpp @@ -85,9 +85,7 @@ const harvest_id &harvest_list::load( const JsonObject &jo, const std::string &s ret.message_ = jo.get_string( "message" ); } - JsonArray jo_entries = jo.get_array( "entries" ); - while( jo_entries.has_more() ) { - JsonObject current_entry = jo_entries.next_object(); + for( const JsonObject ¤t_entry : jo.get_array( "entries" ) ) { ret.entries_.push_back( harvest_entry::load( current_entry, src ) ); } diff --git a/src/input.cpp b/src/input.cpp index 597c1ee9d6819..488752476348a 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -217,11 +217,8 @@ void input_manager::load( const std::string &file_name, bool is_user_preferences actions[action_id].name = action.get_string( "name" ); } - // Iterate over the bindings JSON array - JsonArray bindings = action.get_array( "bindings" ); t_input_event_list events; - while( bindings.has_more() ) { - JsonObject keybinding = bindings.next_object(); + for( const JsonObject &keybinding : action.get_array( "bindings" ) ) { std::string input_method = keybinding.get_string( "input_method" ); input_event new_event; if( input_method == "keyboard" ) { @@ -233,11 +230,8 @@ void input_manager::load( const std::string &file_name, bool is_user_preferences } if( keybinding.has_array( "key" ) ) { - JsonArray keys = keybinding.get_array( "key" ); - while( keys.has_more() ) { - new_event.sequence.push_back( - get_keycode( keys.next_string() ) - ); + for( const std::string &line : keybinding.get_array( "key" ) ) { + new_event.sequence.push_back( get_keycode( line ) ); } } else { // assume string if not array, and throw if not string new_event.sequence.push_back( diff --git a/src/item_factory.cpp b/src/item_factory.cpp index a2562458d6417..de48ba670bcad 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -77,9 +77,7 @@ static void assign( const JsonObject &jo, const std::string &name, return; } mods.clear(); - JsonArray jarr = jo.get_array( name ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( name ) ) { mods.emplace( gun_mode_id( curr.get_string( 0 ) ), gun_modifier_data( curr.get_string( 1 ), curr.get_int( 2 ), curr.size() >= 4 ? curr.get_tags( 3 ) : std::set() ) ); } @@ -109,9 +107,8 @@ static bool assign_coverage_from_json( const JsonObject &jo, const std::string & }; if( jo.has_array( key ) ) { - JsonArray arr = jo.get_array( key ); - while( arr.has_more() ) { - parse( arr.next_string() ); + for( const std::string &line : jo.get_array( key ) ) { + parse( line ); } return true; @@ -1446,9 +1443,7 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin if( jo.has_array( "valid_mod_locations" ) ) { slot.valid_mod_locations.clear(); - JsonArray jarr = jo.get_array( "valid_mod_locations" ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( "valid_mod_locations" ) ) { slot.valid_mod_locations.emplace( curr.get_string( 0 ), curr.get_int( 1 ) ); } } @@ -1540,16 +1535,15 @@ void Item_factory::load( islot_tool &slot, const JsonObject &jo, const std::stri assign( jo, "sub", slot.subtype, strict ); if( jo.has_array( "rand_charges" ) ) { - JsonArray jarr = jo.get_array( "rand_charges" ); if( jo.has_member( "initial_charges" ) ) { - jarr.throw_error( "You can have a fixed initial amount of charges, or randomized. Not both." ); + jo.throw_error( "You can have a fixed initial amount of charges, or randomized. Not both.", "rand_charges" ); } - while( jarr.has_more() ) { - slot.rand_charges.push_back( jarr.next_int() ); + for( const int charge : jo.get_array( "rand_charges" ) ) { + slot.rand_charges.push_back( charge ); } if( slot.rand_charges.size() == 1 ) { // see item::item(...) for the use of this array - jarr.throw_error( "a rand_charges array with only one entry will be ignored, it needs at least 2 entries!" ); + jo.throw_error( "a rand_charges array with only one entry will be ignored, it needs at least 2 entries!", "rand_charges" ); } } } @@ -1593,14 +1587,11 @@ void Item_factory::load( islot_mod &slot, const JsonObject &jo, const std::strin if( !mags.empty() ) { slot.magazine_adaptor.clear(); } - while( mags.has_more() ) { - JsonArray arr = mags.next_array(); - + for( JsonArray arr : mags ) { ammotype ammo( arr.get_string( 0 ) ); // an ammo type (e.g. 9mm) - JsonArray compat = arr.get_array( 1 ); // compatible magazines for this ammo type - - while( compat.has_more() ) { - slot.magazine_adaptor[ ammo ].insert( compat.next_string() ); + // compatible magazines for this ammo type + for( const std::string &line : arr.get_array( 1 ) ) { + slot.magazine_adaptor[ ammo ].insert( line ); } } } @@ -1734,9 +1725,7 @@ void Item_factory::load( islot_comestible &slot, const JsonObject &jo, const std // any specification of vitamins suppresses use of material defaults @see Item_factory::finalize if( jo.has_array( "vitamins" ) ) { - auto vits = jo.get_array( "vitamins" ); - while( vits.has_more() ) { - auto pair = vits.next_array(); + for( JsonArray pair : jo.get_array( "vitamins" ) ) { vitamin_id vit( pair.get_string( 0 ) ); slot.default_nutrition.vitamins[ vit ] = pair.get_int( 1 ); } @@ -1748,9 +1737,7 @@ void Item_factory::load( islot_comestible &slot, const JsonObject &jo, const std slot.default_nutrition.vitamins[ v.first ] += relative.get_int( "vitamins" ); } } else if( relative.has_array( "vitamins" ) ) { - auto vits = relative.get_array( "vitamins" ); - while( vits.has_more() ) { - auto pair = vits.next_array(); + for( JsonArray pair : relative.get_array( "vitamins" ) ) { vitamin_id vit( pair.get_string( 0 ) ); slot.default_nutrition.vitamins[ vit ] += pair.get_int( 1 ); } @@ -1847,9 +1834,7 @@ void Item_factory::load( islot_gunmod &slot, const JsonObject &jo, const std::st assign( jo, "min_str_required_mod", slot.min_str_required_mod ); if( jo.has_array( "add_mod" ) ) { slot.add_mod.clear(); - JsonArray jarr = jo.get_array( "add_mod" ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( "add_mod" ) ) { slot.add_mod.emplace( curr.get_string( 0 ), curr.get_int( 1 ) ); } } @@ -2106,10 +2091,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: def.magazine_default.clear(); def.magazines.clear(); - JsonArray mags = jo.get_array( "magazines" ); - while( mags.has_more() ) { - JsonArray arr = mags.next_array(); - + for( JsonArray arr : jo.get_array( "magazines" ) ) { ammotype ammo( arr.get_string( 0 ) ); // an ammo type (e.g. 9mm) JsonArray compat = arr.get_array( 1 ); // compatible magazines for this ammo type @@ -2126,8 +2108,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: if( !jarr.empty() ) { def.min_skills.clear(); } - while( jarr.has_more() ) { - JsonArray cur = jarr.next_array(); + for( JsonArray cur : jarr ) { const auto sk = skill_id( cur.get_string( 0 ) ); if( !sk.is_valid() ) { jo.throw_error( string_format( "invalid skill: %s", sk.c_str() ), "min_skills" ); @@ -2182,9 +2163,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: if( jo.has_member( "conditional_names" ) ) { def.conditional_names.clear(); - JsonArray jarr = jo.get_array( "conditional_names" ); - while( jarr.has_more() ) { - JsonObject curr = jarr.next_object(); + for( const JsonObject &curr : jo.get_array( "conditional_names" ) ) { conditional_name cname; cname.type = curr.get_enum_value( "type" ); cname.condition = curr.get_string( "condition" ); @@ -2254,9 +2233,8 @@ void Item_factory::load_migration( const JsonObject &jo ) m.id = jo.get_string( "id" ); migrations[ m.id ] = m; } else if( jo.has_array( "id" ) ) { - JsonArray ja = jo.get_array( "id" ); - while( ja.has_more() ) { - m.id = ja.next_string(); + for( const std::string &line : jo.get_array( "id" ) ) { + m.id = line; migrations[ m.id ] = m; } } else { @@ -2301,9 +2279,7 @@ void Item_factory::set_qualities_from_json( const JsonObject &jo, const std::str itype &def ) { if( jo.has_array( member ) ) { - JsonArray jarr = jo.get_array( member ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( member ) ) { const auto quali = std::pair( quality_id( curr.get_string( 0 ) ), curr.get_int( 1 ) ); if( def.qualities.count( quali.first ) > 0 ) { @@ -2320,9 +2296,7 @@ void Item_factory::set_properties_from_json( const JsonObject &jo, const std::st itype &def ) { if( jo.has_array( member ) ) { - JsonArray jarr = jo.get_array( member ); - while( jarr.has_more() ) { - JsonArray curr = jarr.next_array(); + for( JsonArray curr : jo.get_array( member ) ) { const auto prop = std::pair( curr.get_string( 0 ), curr.get_string( 1 ) ); if( def.properties.count( prop.first ) > 0 ) { curr.throw_error( "Duplicated property", 0 ); @@ -2420,9 +2394,8 @@ bool Item_factory::load_sub_ref( std::unique_ptr &ptr, const Js } else if( name != "contents" ) { obj.throw_error( string_format( "You can't use an array for '%s'", arr_name ) ); } - JsonArray arr = obj.get_array( arr_name ); - while( arr.has_more() ) { - entries.push_back( std::make_pair( arr.next_string(), isgroup ) ); + for( const std::string &line : obj.get_array( arr_name ) ) { + entries.emplace_back( line, isgroup ); } }; get_array( iname, false ); @@ -2474,10 +2447,9 @@ bool Item_factory::load_string( std::vector &vec, const JsonObject std::string temp; if( obj.has_array( name ) ) { - JsonArray arr = obj.get_array( name ); - while( arr.has_more() ) { - result |= arr.read_next( temp ); - vec.push_back( temp ); + for( const std::string &line : obj.get_array( name ) ) { + result |= true; + vec.push_back( line ); } } else if( obj.has_member( name ) ) { result |= obj.read( name, temp ); @@ -2502,8 +2474,7 @@ void Item_factory::add_entry( Item_group &ig, const JsonObject &obj ) jarr = obj.get_array( "distribution" ); } if( gptr ) { - while( jarr.has_more() ) { - JsonObject job2 = jarr.next_object(); + for( const JsonObject &job2 : jarr ) { add_entry( *gptr, job2 ); } ig.add_entry( std::move( gptr ) ); @@ -2577,13 +2548,12 @@ void Item_factory::load_item_group( const JsonObject &jsobj, const Group_tag &gr jsobj.get_int( "magazine", 0 ) ); if( subtype == "old" ) { - JsonArray items = jsobj.get_array( "items" ); - while( items.has_more() ) { - if( items.test_object() ) { - JsonObject subobj = items.next_object(); + for( const JsonValue &entry : jsobj.get_array( "items" ) ) { + if( entry.test_object() ) { + JsonObject subobj = entry.get_object(); add_entry( *ig, subobj ); } else { - JsonArray pair = items.next_array(); + JsonArray pair = entry.get_array(); ig->add_item_entry( pair.get_string( 0 ), pair.get_int( 1 ) ); } } @@ -2591,36 +2561,32 @@ void Item_factory::load_item_group( const JsonObject &jsobj, const Group_tag &gr } if( jsobj.has_member( "entries" ) ) { - JsonArray items = jsobj.get_array( "entries" ); - while( items.has_more() ) { - JsonObject subobj = items.next_object(); + for( const JsonObject &subobj : jsobj.get_array( "entries" ) ) { add_entry( *ig, subobj ); } } if( jsobj.has_member( "items" ) ) { - JsonArray items = jsobj.get_array( "items" ); - while( items.has_more() ) { - if( items.test_string() ) { - ig->add_item_entry( items.next_string(), 100 ); - } else if( items.test_array() ) { - JsonArray subitem = items.next_array(); + for( const JsonValue &entry : jsobj.get_array( "items" ) ) { + if( entry.test_string() ) { + ig->add_item_entry( entry.get_string(), 100 ); + } else if( entry.test_array() ) { + JsonArray subitem = entry.get_array(); ig->add_item_entry( subitem.get_string( 0 ), subitem.get_int( 1 ) ); } else { - JsonObject subobj = items.next_object(); + JsonObject subobj = entry.get_object(); add_entry( *ig, subobj ); } } } if( jsobj.has_member( "groups" ) ) { - JsonArray items = jsobj.get_array( "groups" ); - while( items.has_more() ) { - if( items.test_string() ) { - ig->add_group_entry( items.next_string(), 100 ); - } else if( items.test_array() ) { - JsonArray subitem = items.next_array(); + for( const JsonValue &entry : jsobj.get_array( "groups" ) ) { + if( entry.test_string() ) { + ig->add_group_entry( entry.get_string(), 100 ); + } else if( entry.test_array() ) { + JsonArray subitem = entry.get_array(); ig->add_group_entry( subitem.get_string( 0 ), subitem.get_int( 1 ) ); } else { - JsonObject subobj = items.next_object(); + JsonObject subobj = entry.get_object(); add_entry( *ig, subobj ); } } @@ -2636,16 +2602,15 @@ void Item_factory::set_use_methods_from_json( const JsonObject &jo, const std::s use_methods.clear(); if( jo.has_array( member ) ) { - JsonArray jarr = jo.get_array( member ); - while( jarr.has_more() ) { - if( jarr.test_string() ) { - std::string type = jarr.next_string(); + for( const JsonValue &entry : jo.get_array( member ) ) { + if( entry.test_string() ) { + std::string type = entry.get_string(); use_methods.emplace( type, usage_from_string( type ) ); - } else if( jarr.test_object() ) { - auto obj = jarr.next_object(); + } else if( entry.test_object() ) { + auto obj = entry.get_object(); use_methods.insert( usage_from_object( obj ) ); } else { - jarr.throw_error( "array element is neither string nor object." ); + entry.throw_error( "array element is neither string nor object." ); } } diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 2961ca35ef39f..7bc6b7605700a 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -137,9 +137,8 @@ void iuse_transform::load( const JsonObject &obj ) } obj.read( "target_charges", ammo_qty ); if( obj.has_array( "rand_target_charges" ) ) { - JsonArray jarr = obj.get_array( "rand_target_charges" ); - while( jarr.has_more() ) { - random_ammo_qty.push_back( jarr.next_int() ); + for( const int charge : obj.get_array( "rand_target_charges" ) ) { + random_ammo_qty.push_back( charge ); } if( random_ammo_qty.size() < 2 ) { obj.throw_error( "You must specify two or more values to choose between", "rand_target_charges" ); @@ -616,9 +615,7 @@ void consume_drug_iuse::load( const JsonObject &obj ) obj.read( "tools_needed", tools_needed ); if( obj.has_array( "effects" ) ) { - JsonArray jsarr = obj.get_array( "effects" ); - while( jsarr.has_more() ) { - JsonObject e = jsarr.next_object(); + for( const JsonObject &e : obj.get_array( "effects" ) ) { effects.push_back( load_effect_data( e ) ); } } @@ -626,9 +623,7 @@ void consume_drug_iuse::load( const JsonObject &obj ) obj.read( "fields_produced", fields_produced ); obj.read( "moves", moves ); - auto arr = obj.get_array( "vitamins" ); - while( arr.has_more() ) { - auto vit = arr.next_array(); + for( JsonArray vit : obj.get_array( "vitamins" ) ) { auto lo = vit.get_int( 1 ); auto hi = vit.size() >= 3 ? vit.get_int( 2 ) : lo; vitamins.emplace( vitamin_id( vit.get_string( 0 ) ), std::make_pair( lo, hi ) ); @@ -1152,15 +1147,14 @@ void reveal_map_actor::load( const JsonObject &obj ) { radius = obj.get_int( "radius" ); message = obj.get_string( "message" ); - JsonArray jarr = obj.get_array( "terrain" ); std::string ter; ot_match_type ter_match_type; - while( jarr.has_more() ) { - if( jarr.test_string() ) { - ter = jarr.next_string(); + for( const JsonValue &entry : obj.get_array( "terrain" ) ) { + if( entry.test_string() ) { + ter = entry.get_string(); ter_match_type = ot_match_type::contains; } else { - JsonObject jo = jarr.next_object(); + JsonObject jo = entry.get_object(); ter = jo.get_string( "om_terrain" ); ter_match_type = jo.get_enum_value( jo.get_string( "om_terrain_match_type", "CONTAINS" ), ot_match_type::contains ); @@ -2835,9 +2829,8 @@ int ammobelt_actor::use( player &p, item &, bool, const tripoint & ) const void repair_item_actor::load( const JsonObject &obj ) { // Mandatory: - JsonArray jarr = obj.get_array( "materials" ); - while( jarr.has_more() ) { - materials.emplace( jarr.next_string() ); + for( const std::string &line : obj.get_array( "materials" ) ) { + materials.emplace( line ); } // TODO: Make skill non-mandatory while still erroring on invalid skill @@ -3419,9 +3412,7 @@ void heal_actor::load( const JsonObject &obj ) long_action = obj.get_bool( "long_action", false ); if( obj.has_array( "effects" ) ) { - JsonArray jsarr = obj.get_array( "effects" ); - while( jsarr.has_more() ) { - JsonObject e = jsarr.next_object(); + for( const JsonObject &e : obj.get_array( "effects" ) ) { effects.push_back( load_effect_data( e ) ); } } @@ -4475,13 +4466,11 @@ std::unique_ptr weigh_self_actor::clone() const void sew_advanced_actor::load( const JsonObject &obj ) { // Mandatory: - JsonArray jarr = obj.get_array( "materials" ); - while( jarr.has_more() ) { - materials.emplace( jarr.next_string() ); + for( const std::string &line : obj.get_array( "materials" ) ) { + materials.emplace( line ); } - jarr = obj.get_array( "clothing_mods" ); - while( jarr.has_more() ) { - clothing_mods.push_back( clothing_mod_id( jarr.next_string() ) ); + for( const std::string &line : obj.get_array( "clothing_mods" ) ) { + clothing_mods.push_back( clothing_mod_id( line ) ); } // TODO: Make skill non-mandatory while still erroring on invalid skill diff --git a/src/json.cpp b/src/json.cpp index c53fc7276fc5b..cd60cbd7c9af4 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -321,20 +321,18 @@ JsonArray JsonObject::get_array( const std::string &name ) const std::vector JsonObject::get_int_array( const std::string &name ) const { - JsonArray ja = get_array( name ); std::vector ret; - while( ja.has_more() ) { - ret.push_back( ja.next_int() ); + for( const int entry : get_array( name ) ) { + ret.push_back( entry ); } return ret; } std::vector JsonObject::get_string_array( const std::string &name ) const { - JsonArray ja = get_array( name ); std::vector ret; - while( ja.has_more() ) { - ret.push_back( ja.next_string() ); + for( const std::string &entry : get_array( name ) ) { + ret.push_back( entry ); } return ret; } @@ -699,9 +697,8 @@ bool JsonArray::has_object( const size_t i ) const void add_array_to_set( std::set &s, const JsonObject &json, const std::string &name ) { - JsonArray jarr = json.get_array( name ); - while( jarr.has_more() ) { - s.insert( jarr.next_string() ); + for( const std::string &line : json.get_array( name ) ) { + s.insert( line ); } } diff --git a/src/json.h b/src/json.h index 43b3170287768..8a5d7c43982cd 100644 --- a/src/json.h +++ b/src/json.h @@ -1114,6 +1114,25 @@ class JsonValue return seek().read( t ); } + bool test_string() const { + return seek().test_string(); + } + bool test_int() const { + return seek().test_int(); + } + bool test_bool() const { + return seek().test_bool(); + } + bool test_float() const { + return seek().test_float(); + } + bool test_object() const { + return seek().test_object(); + } + bool test_array() const { + return seek().test_array(); + } + void throw_error( const std::string &err ) const { seek().error( err ); } diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index c2a8c1044a4c9..efd7c246167ce 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -200,16 +200,12 @@ void enchantment::load( const JsonObject &jo, const std::string & ) if( jo.has_object( "intermittent_activation" ) ) { JsonObject jobj = jo.get_object( "intermittent_activation" ); - JsonArray jarray = jo.get_array( "effects" ); - while( jarray.has_more() ) { - JsonObject effect_obj = jarray.next_object(); + for( const JsonObject &effect_obj : jo.get_array( "effects" ) ) { time_duration dur = read_from_json_string( *effect_obj.get_raw( "frequency" ), time_duration::units ); if( effect_obj.has_array( "spell_effects" ) ) { - JsonArray jarray = effect_obj.get_array( "spell_effects" ); - while( jarray.has_more() ) { + for( const JsonObject &fake_spell_obj : effect_obj.get_array( "spell_effects" ) ) { fake_spell fake; - JsonObject fake_spell_obj = jarray.next_object(); fake.load( fake_spell_obj ); add_activation( dur, fake ); } @@ -227,9 +223,7 @@ void enchantment::load( const JsonObject &jo, const std::string & ) "ALWAYS" ) ); if( jo.has_array( "values" ) ) { - JsonArray jarray = jo.get_array( "values" ); - while( jarray.has_more() ) { - JsonObject value_obj = jarray.next_object(); + for( const JsonObject &value_obj : jo.get_array( "values" ) ) { const enchantment::mod value = io::string_to_enum( value_obj.get_string( "value" ) ); const int add = value_obj.get_int( "add", 0 ); const double mult = value_obj.get_float( "multiply", 0.0 ); diff --git a/src/magic_ter_fur_transform.cpp b/src/magic_ter_fur_transform.cpp index 0dc1adc256b8d..5099e95bdddae 100644 --- a/src/magic_ter_fur_transform.cpp +++ b/src/magic_ter_fur_transform.cpp @@ -55,13 +55,12 @@ static void load_transform_results( const JsonObject &jsi, const std::string &js list.add( T( jsi.get_string( json_key ) ), 1 ); return; } - JsonArray jarr = jsi.get_array( json_key ); - while( jarr.has_more() ) { - if( jarr.test_array() ) { - JsonArray inner = jarr.next_array(); + for( const JsonValue &entry : jsi.get_array( json_key ) ) { + if( entry.test_array() ) { + JsonArray inner = entry.get_array(); list.add( T( inner.get_string( 0 ) ), inner.get_int( 1 ) ); } else { - list.add( T( jarr.next_string() ), 1 ); + list.add( T( entry.get_string() ), 1 ); } } } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 936b58b8d34fe..019c3f4cd10e2 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1165,16 +1165,15 @@ class jmapgen_monster : public jmapgen_piece return; } } else if( jsi.has_array( "monster" ) ) { - JsonArray jarr = jsi.get_array( "monster" ); - while( jarr.has_more() ) { + for( const JsonValue &entry : jsi.get_array( "monster" ) ) { mtype_id id; int weight = 100; - if( jarr.test_array() ) { - JsonArray inner = jarr.next_array(); + if( entry.test_array() ) { + JsonArray inner = entry.get_array(); id = mtype_id( inner.get_string( 0 ) ); weight = inner.get_int( 1 ); } else { - id = mtype_id( jarr.next_string() ); + id = mtype_id( entry.get_string() ); } if( !id.is_valid() ) { set_mapgen_defer( jsi, "monster", "no such monster" ); @@ -1641,13 +1640,12 @@ class jmapgen_zone : public jmapgen_piece static void load_weighted_entries( const JsonObject &jsi, const std::string &json_key, weighted_int_list &list ) { - JsonArray jarr = jsi.get_array( json_key ); - while( jarr.has_more() ) { - if( jarr.test_array() ) { - JsonArray inner = jarr.next_array(); + for( const JsonValue &entry : jsi.get_array( json_key ) ) { + if( entry.test_array() ) { + JsonArray inner = entry.get_array(); list.add( inner.get_string( 0 ), inner.get_int( 1 ) ); } else { - list.add( jarr.next_string(), 100 ); + list.add( entry.get_string(), 100 ); } } } @@ -1883,17 +1881,16 @@ void load_place_mapings_string( const JsonObject &pjo, const std::string &key, } else if( pjo.has_object( key ) ) { load_place_mapings( pjo.get_object( key ), vect ); } else { - JsonArray jarr = pjo.get_array( key ); - while( jarr.has_more() ) { - if( jarr.test_string() ) { + for( const JsonValue &entry : pjo.get_array( key ) ) { + if( entry.test_string() ) { try { - vect.push_back( make_shared_fast( jarr.next_string() ) ); + vect.push_back( make_shared_fast( entry.get_string() ) ); } catch( const std::runtime_error &err ) { // Using the json object here adds nice formatting and context information - jarr.throw_error( err.what() ); + entry.throw_error( err.what() ); } } else { - load_place_mapings( jarr.next_object(), vect ); + load_place_mapings( entry.get_object(), vect ); } } } @@ -1911,21 +1908,20 @@ void load_place_mapings_alternatively( const JsonObject &pjo, const std::string load_place_mapings_string( pjo, key, vect ); } else { auto alter = make_shared_fast< jmapgen_alternativly >(); - JsonArray jarr = pjo.get_array( key ); - while( jarr.has_more() ) { - if( jarr.test_string() ) { + for( const JsonValue &entry : pjo.get_array( key ) ) { + if( entry.test_string() ) { try { - alter->alternatives.emplace_back( jarr.next_string() ); + alter->alternatives.emplace_back( entry.get_string() ); } catch( const std::runtime_error &err ) { // Using the json object here adds nice formatting and context information - jarr.throw_error( err.what() ); + entry.throw_error( err.what() ); } - } else if( jarr.test_object() ) { - JsonObject jsi = jarr.next_object(); + } else if( entry.test_object() ) { + JsonObject jsi = entry.get_object(); alter->alternatives.emplace_back( jsi ); - } else if( jarr.test_array() ) { + } else if( entry.test_array() ) { // If this is an array, it means it is an entry followed by a desired total count of instances. - JsonArray piece_and_count_jarr = jarr.next_array(); + JsonArray piece_and_count_jarr = entry.get_array(); if( piece_and_count_jarr.size() != 2 ) { piece_and_count_jarr.throw_error( "Array must have exactly two entries: the object, then the count." ); } diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 6aebf2d8783ed..b0efdfd8fca4a 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -1024,14 +1024,13 @@ void mtype::add_special_attacks( const JsonObject &jo, const std::string &member return; } - JsonArray outer = jo.get_array( member ); - while( outer.has_more() ) { - if( outer.test_array() ) { - add_special_attack( outer.next_array(), src ); - } else if( outer.test_object() ) { - add_special_attack( outer.next_object(), src ); + for( const JsonValue &entry : jo.get_array( member ) ) { + if( entry.test_array() ) { + add_special_attack( entry.get_array(), src ); + } else if( entry.test_object() ) { + add_special_attack( entry.get_object(), src ); } else { - outer.throw_error( "array element is neither array nor object." ); + entry.throw_error( "array element is neither array nor object." ); } } } diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index d7ae65077c568..c6c1c34e893bb 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -684,29 +684,27 @@ void mutation_branch::load_trait_group( const JsonObject &jsobj, } } if( jsobj.has_member( "traits" ) ) { - JsonArray traits = jsobj.get_array( "traits" ); - while( traits.has_more() ) { - if( traits.test_string() ) { - tg.add_trait_entry( trait_id( traits.next_string() ), 100 ); - } else if( traits.test_array() ) { - JsonArray subtrait = traits.next_array(); + for( const JsonValue &entry : jsobj.get_array( "traits" ) ) { + if( entry.test_string() ) { + tg.add_trait_entry( trait_id( entry.get_string() ), 100 ); + } else if( entry.test_array() ) { + JsonArray subtrait = entry.get_array(); tg.add_trait_entry( trait_id( subtrait.get_string( 0 ) ), subtrait.get_int( 1 ) ); } else { - JsonObject subobj = traits.next_object(); + JsonObject subobj = entry.get_object(); add_entry( tg, subobj ); } } } if( jsobj.has_member( "groups" ) ) { - JsonArray traits = jsobj.get_array( "groups" ); - while( traits.has_more() ) { - if( traits.test_string() ) { - tg.add_group_entry( trait_group::Trait_group_tag( traits.next_string() ), 100 ); - } else if( traits.test_array() ) { - JsonArray subtrait = traits.next_array(); + for( const JsonValue &entry : jsobj.get_array( "groups" ) ) { + if( entry.test_string() ) { + tg.add_group_entry( trait_group::Trait_group_tag( entry.get_string() ), 100 ); + } else if( entry.test_array() ) { + JsonArray subtrait = entry.get_array(); tg.add_group_entry( trait_group::Trait_group_tag( subtrait.get_string( 0 ) ), subtrait.get_int( 1 ) ); } else { - JsonObject subobj = traits.next_object(); + JsonObject subobj = entry.get_object(); add_entry( tg, subobj ); } } @@ -729,8 +727,7 @@ void mutation_branch::add_entry( Trait_group &tg, const JsonObject &obj ) if( ptr ) { Trait_group &tg2 = dynamic_cast( *ptr ); - while( jarr.has_more() ) { - JsonObject job2 = jarr.next_object(); + for( const JsonObject &job2 : jarr ) { add_entry( tg2, job2 ); } tg.add_entry( std::move( ptr ) ); diff --git a/src/npctalk.cpp b/src/npctalk.cpp index e3c3deb9a7b68..454c47dd500a3 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2676,13 +2676,12 @@ void talk_effect_t::load_effect( const JsonObject &jo ) JsonObject sub_effect = jo.get_object( member_name ); parse_sub_effect( sub_effect ); } else if( jo.has_array( member_name ) ) { - JsonArray ja = jo.get_array( member_name ); - while( ja.has_more() ) { - if( ja.test_string() ) { - const std::string type = ja.next_string(); + for( const JsonValue &entry : jo.get_array( member_name ) ) { + if( entry.test_string() ) { + const std::string type = entry.get_string(); parse_string_effect( type, jo ); - } else if( ja.test_object() ) { - JsonObject sub_effect = ja.next_object(); + } else if( entry.test_object() ) { + JsonObject sub_effect = entry.get_object(); parse_sub_effect( sub_effect ); } else { jo.throw_error( "invalid effect array syntax", member_name ); @@ -2869,16 +2868,15 @@ dynamic_line_t::dynamic_line_t( const JsonObject &jo ) { if( jo.has_member( "and" ) ) { std::vector lines; - JsonArray ja = jo.get_array( "and" ); - while( ja.has_more() ) { - if( ja.test_string() ) { - lines.emplace_back( ja.next_string() ); - } else if( ja.test_array() ) { - lines.emplace_back( ja.next_array() ); - } else if( ja.test_object() ) { - lines.emplace_back( ja.next_object() ); + for( const JsonValue &entry : jo.get_array( "and" ) ) { + if( entry.test_string() ) { + lines.emplace_back( entry.get_string() ); + } else if( entry.test_array() ) { + lines.emplace_back( entry.get_array() ); + } else if( entry.test_object() ) { + lines.emplace_back( entry.get_object() ); } else { - ja.throw_error( "invalid format: must be string, array or object" ); + entry.throw_error( "invalid format: must be string, array or object" ); } } function = [lines]( const dialogue & d ) { @@ -2950,15 +2948,15 @@ dynamic_line_t::dynamic_line_t( const JsonObject &jo ) dynamic_line_t::dynamic_line_t( JsonArray ja ) { std::vector lines; - while( ja.has_more() ) { - if( ja.test_string() ) { - lines.emplace_back( ja.next_string() ); - } else if( ja.test_array() ) { - lines.emplace_back( ja.next_array() ); - } else if( ja.test_object() ) { - lines.emplace_back( ja.next_object() ); + for( const JsonValue &entry : ja ) { + if( entry.test_string() ) { + lines.emplace_back( entry.get_string() ); + } else if( entry.test_array() ) { + lines.emplace_back( entry.get_array() ); + } else if( entry.test_object() ) { + lines.emplace_back( entry.get_object() ); } else { - ja.throw_error( "invalid format: must be string, array or object" ); + entry.throw_error( "invalid format: must be string, array or object" ); } } function = [lines]( const dialogue & d ) { diff --git a/src/trap.cpp b/src/trap.cpp index ead593c7ec56c..651619e1c69cb 100644 --- a/src/trap.cpp +++ b/src/trap.cpp @@ -120,18 +120,17 @@ void trap::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "comfort", comfort, 0 ); optional( jo, was_loaded, "floor_bedding_warmth", floor_bedding_warmth, 0 ); assign( jo, "trigger_weight", trigger_weight ); - JsonArray ja = jo.get_array( "drops" ); - while( ja.has_more() ) { + for( const JsonValue &entry : jo.get_array( "drops" ) ) { std::string item_type; int quantity = 0; int charges = 0; - if( ja.test_object() ) { - JsonObject jc = ja.next_object(); + if( entry.test_object() ) { + JsonObject jc = entry.get_object(); item_type = jc.get_string( "item" ); quantity = jc.get_int( "quantity", 1 ); charges = jc.get_int( "charges", 1 ); } else { - item_type = ja.next_string(); + item_type = entry.get_string(); quantity = 1; charges = 1; } @@ -153,13 +152,12 @@ void trap::load( const JsonObject &jo, const std::string & ) vehicle_data.sound_variant = jv.get_string( "sound_variant", "" ); vehicle_data.spawn_items.clear(); if( jv.has_array( "spawn_items" ) ) { - JsonArray ja = jv.get_array( "spawn_items" ); - while( ja.has_more() ) { - if( ja.test_object() ) { - JsonObject joitm = ja.next_object(); + for( const JsonValue &entry : jv.get_array( "spawn_items" ) ) { + if( entry.test_object() ) { + JsonObject joitm = entry.get_object(); vehicle_data.spawn_items.emplace_back( joitm.get_string( "id" ), joitm.get_float( "chance" ) ); } else { - vehicle_data.spawn_items.emplace_back( ja.next_string(), 1.0 ); + vehicle_data.spawn_items.emplace_back( entry.get_string(), 1.0 ); } } } diff --git a/src/uistate.h b/src/uistate.h index 293101cd36624..c2ff1478bb67c 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -256,11 +256,10 @@ class uistatedata jo.read( "list_item_priority_active", list_item_priority_active ); for( const JsonMember &member : jo.get_object( "input_history" ) ) { - JsonArray ja = member.get_array(); std::vector &v = gethistory( member.name() ); v.clear(); - while( ja.has_more() ) { - v.push_back( ja.next_string() ); + for( const std::string &line : member.get_array() ) { + v.push_back( line ); } } // fetch list_item settings from input_history diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 8151b2c5de948..17a99e4d5a1e1 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -946,13 +946,12 @@ void vehicle_prototype::load( const JsonObject &jo ) if( part.has_string( "part" ) ) { add_part_obj( part, pos ); } else if( part.has_array( "parts" ) ) { - JsonArray subparts = part.get_array( "parts" ); - while( subparts.has_more() ) { - if( subparts.test_string() ) { - std::string part_name = subparts.next_string(); + for( const JsonValue &entry : part.get_array( "parts" ) ) { + if( entry.test_string() ) { + std::string part_name = entry.get_string(); add_part_string( part_name, pos ); } else { - JsonObject subpart = subparts.next_object(); + JsonObject subpart = entry.get_object(); add_part_obj( subpart, pos ); } } @@ -978,9 +977,8 @@ void vehicle_prototype::load( const JsonObject &jo ) if( spawn_info.has_array( "items" ) ) { //Array of items that all spawn together (i.e. jack+tire) - JsonArray item_group = spawn_info.get_array( "items" ); - while( item_group.has_more() ) { - next_spawn.item_ids.push_back( item_group.next_string() ); + for( const std::string &line : spawn_info.get_array( "items" ) ) { + next_spawn.item_ids.push_back( line ); } } else if( spawn_info.has_string( "items" ) ) { //Treat single item as array @@ -988,9 +986,8 @@ void vehicle_prototype::load( const JsonObject &jo ) } if( spawn_info.has_array( "item_groups" ) ) { //Pick from a group of items, just like map::place_items - JsonArray item_group_names = spawn_info.get_array( "item_groups" ); - while( item_group_names.has_more() ) { - next_spawn.item_groups.push_back( item_group_names.next_string() ); + for( const std::string &line : spawn_info.get_array( "item_groups" ) ) { + next_spawn.item_groups.push_back( line ); } } else if( spawn_info.has_string( "item_groups" ) ) { next_spawn.item_groups.push_back( spawn_info.get_string( "item_groups" ) ); From 2b488f5f528e99b6867c8a4a58a5f0a0a207f7e3 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:59:27 +0100 Subject: [PATCH 11/21] Replace index based loops over JsonArray with range-based loops. --- src/artifact.cpp | 15 ++++++--------- src/field_type.cpp | 10 +++------- src/item_factory.cpp | 20 ++++++++------------ 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/artifact.cpp b/src/artifact.cpp index 84c85c0606646..9833c6caccda0 100644 --- a/src/artifact.cpp +++ b/src/artifact.cpp @@ -1165,9 +1165,8 @@ void it_artifact_tool::deserialize( const JsonObject &jo ) // Assumption, perhaps dangerous, that we won't wind up with m1 and m2 and // a materials array in our serialized objects at the same time. if( jo.has_array( "materials" ) ) { - JsonArray jarr = jo.get_array( "materials" ); - for( size_t i = 0; i < jarr.size(); ++i ) { - materials.push_back( material_id( jarr.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "materials" ) ) { + materials.push_back( material_id( id ) ); } } volume = jo.get_int( "volume" ) * units::legacy_volume_factor; @@ -1185,9 +1184,8 @@ void it_artifact_tool::deserialize( const JsonObject &jo ) // Artifacts in older saves store ammo as string. if( jo.has_array( "ammo" ) ) { - JsonArray atypes = jo.get_array( "ammo" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - tool->ammo_id.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo" ) ) { + tool->ammo_id.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo" ) ) { tool->ammo_id.insert( ammotype( jo.get_string( "ammo" ) ) ); @@ -1275,9 +1273,8 @@ void it_artifact_armor::deserialize( const JsonObject &jo ) // Assumption, perhaps dangerous, that we won't wind up with m1 and m2 and // a materials array in our serialized objects at the same time. if( jo.has_array( "materials" ) ) { - JsonArray jarr = jo.get_array( "materials" ); - for( size_t i = 0; i < jarr.size(); ++i ) { - materials.push_back( material_id( jarr.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "materials" ) ) { + materials.push_back( material_id( id ) ); } } volume = jo.get_int( "volume" ) * units::legacy_volume_factor; diff --git a/src/field_type.cpp b/src/field_type.cpp index 7e7833143e5ff..3a14d92a7b955 100644 --- a/src/field_type.cpp +++ b/src/field_type.cpp @@ -121,11 +121,9 @@ const field_intensity_level &field_type::get_intensity_level( int level ) const void field_type::load( const JsonObject &jo, const std::string & ) { optional( jo, was_loaded, "legacy_enum_id", legacy_enum_id, -1 ); - JsonArray ja = jo.get_array( "intensity_levels" ); - for( size_t i = 0; i < ja.size(); ++i ) { + for( const JsonObject &jao : jo.get_array( "intensity_levels" ) ) { field_intensity_level intensity_level; - field_intensity_level fallback_intensity_level = i > 0 ? intensity_levels[i - 1] : intensity_level; - JsonObject jao = ja.get_object( i ); + field_intensity_level fallback_intensity_level = !intensity_levels.empty() ? intensity_levels.back() : intensity_level; optional( jao, was_loaded, "name", intensity_level.name, fallback_intensity_level.name ); optional( jao, was_loaded, "sym", intensity_level.symbol, unicode_codepoint_from_symbol_reader, fallback_intensity_level.symbol ); @@ -166,9 +164,7 @@ void field_type::load( const JsonObject &jo, const std::string & ) optional( jao, was_loaded, "convection_temperature_mod", intensity_level.convection_temperature_mod, fallback_intensity_level.convection_temperature_mod ); if( jao.has_array( "effects" ) ) { - JsonArray jae = jao.get_array( "effects" ); - for( size_t j = 0; j < jae.size(); ++j ) { - JsonObject joe = jae.next_object(); + for( const JsonObject &joe : jao.get_array( "effects" ) ) { field_effect fe; mandatory( joe, was_loaded, "effect_id", fe.id ); optional( joe, was_loaded, "min_duration", fe.min_duration ); diff --git a/src/item_factory.cpp b/src/item_factory.cpp index de48ba670bcad..a3a3f557e654d 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -1406,9 +1406,8 @@ void Item_factory::load( islot_gun &slot, const JsonObject &jo, const std::strin assign( jo, "skill", slot.skill_used, strict ); if( jo.has_array( "ammo" ) ) { slot.ammo.clear(); - JsonArray atypes = jo.get_array( "ammo" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.ammo.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo" ) ) { + slot.ammo.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo" ) ) { slot.ammo.clear(); @@ -1517,9 +1516,8 @@ void Item_factory::load( islot_tool &slot, const JsonObject &jo, const std::stri bool strict = src == "dda"; if( jo.has_array( "ammo" ) ) { - JsonArray atypes = jo.get_array( "ammo" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.ammo_id.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo" ) ) { + slot.ammo_id.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo" ) ) { slot.ammo_id.insert( ammotype( jo.get_string( "ammo" ) ) ); @@ -1567,9 +1565,8 @@ void Item_factory::load( islot_mod &slot, const JsonObject &jo, const std::strin bool strict = src == "dda"; if( jo.has_array( "ammo_modifier" ) ) { - JsonArray atypes = jo.get_array( "ammo_modifier" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.ammo_modifier.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo_modifier" ) ) { + slot.ammo_modifier.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo_modifier" ) ) { slot.ammo_modifier.insert( ammotype( jo.get_string( "ammo_modifier" ) ) ); @@ -1855,9 +1852,8 @@ void Item_factory::load( islot_magazine &slot, const JsonObject &jo, const std:: { bool strict = src == "dda"; if( jo.has_array( "ammo_type" ) ) { - JsonArray atypes = jo.get_array( "ammo_type" ); - for( size_t i = 0; i < atypes.size(); ++i ) { - slot.type.insert( ammotype( atypes.get_string( i ) ) ); + for( const std::string &id : jo.get_array( "ammo_type" ) ) { + slot.type.insert( ammotype( id ) ); } } else if( jo.has_string( "ammo_type" ) ) { slot.type.insert( ammotype( jo.get_string( "ammo_type" ) ) ); From 7dfc1c84fdd98f0f06d06dd2612658c09da62f28 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:33:42 +0100 Subject: [PATCH 12/21] Change loading elements of requirements: Change `requirement_data::load_obj_list` to take a reference to const JsonArray. This allows to inline the code in the caller (the JsonArray instance does not need to be stored in a variable). Inside the function, change the loops to range-based loops over the array / the subarray. In turn, change the various `load` functions to accept `const JsonValue &` (entries of the array). The functions used to get the full array as reference and would extract the next element from it. --- src/requirements.cpp | 42 +++++++++++++++++++----------------------- src/requirements.h | 13 +++++++------ 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/requirements.cpp b/src/requirements.cpp index 27e0060b921c4..d1500ee9fd6b9 100644 --- a/src/requirements.cpp +++ b/src/requirements.cpp @@ -156,9 +156,9 @@ std::string item_comp::to_string( const int batch, const int avail ) const } } -void quality_requirement::load( JsonArray &jsarr ) +void quality_requirement::load( const JsonValue &value ) { - JsonObject quality_data = jsarr.next_object(); + const JsonObject quality_data = value.get_object(); type = quality_id( quality_data.get_string( "id" ) ); level = quality_data.get_int( "level", 1 ); count = quality_data.get_int( "amount", 1 ); @@ -168,27 +168,27 @@ void quality_requirement::load( JsonArray &jsarr ) // Note: level is not checked, negative values and 0 are allow, see butchering quality. } -void tool_comp::load( JsonArray &ja ) +void tool_comp::load( const JsonValue &value ) { - if( ja.test_string() ) { + if( value.test_string() ) { // constructions uses this format: [ "tool", ... ] - type = ja.next_string(); + type = value.get_string(); count = -1; } else { - JsonArray comp = ja.next_array(); + JsonArray comp = value.get_array(); type = comp.get_string( 0 ); count = comp.get_int( 1 ); requirement = comp.size() > 2 && comp.get_string( 2 ) == "LIST"; } if( count == 0 ) { - ja.throw_error( "tool count must not be 0" ); + value.throw_error( "tool count must not be 0" ); } // Note: negative count means charges (of the tool) should be consumed } -void item_comp::load( JsonArray &ja ) +void item_comp::load( const JsonValue &value ) { - JsonArray comp = ja.next_array(); + JsonArray comp = value.get_array(); type = comp.get_string( 0 ); count = comp.get_int( 1 ); size_t handled = 2; @@ -201,20 +201,19 @@ void item_comp::load( JsonArray &ja ) } } if( count <= 0 ) { - ja.throw_error( "item count must be a positive number" ); + value.throw_error( "item count must be a positive number" ); } } template -void requirement_data::load_obj_list( JsonArray &jsarr, std::vector< std::vector > &objs ) +void requirement_data::load_obj_list( const JsonArray &jsarr, std::vector< std::vector > &objs ) { - while( jsarr.has_more() ) { - if( jsarr.test_array() ) { + for( const JsonValue &entry : jsarr ) { + if( entry.test_array() ) { std::vector choices; - JsonArray ja = jsarr.next_array(); - while( ja.has_more() ) { + for( const JsonValue &subentry : entry.get_array() ) { choices.push_back( T() ); - choices.back().load( ja ); + choices.back().load( subentry ); } if( !choices.empty() ) { objs.push_back( choices ); @@ -223,7 +222,7 @@ void requirement_data::load_obj_list( JsonArray &jsarr, std::vector< std::vector // tool qualities don't normally use a list of alternatives // each quality is mandatory. objs.push_back( std::vector( 1 ) ); - objs.back().back().load( jsarr ); + objs.back().back().load( entry ); } } } @@ -268,12 +267,9 @@ void requirement_data::load_requirement( const JsonObject &jsobj, const requirem { requirement_data req; - JsonArray jsarr = jsobj.get_array( "components" ); - requirement_data::load_obj_list( jsarr, req.components ); - jsarr = jsobj.get_array( "qualities" ); - requirement_data::load_obj_list( jsarr, req.qualities ); - jsarr = jsobj.get_array( "tools" ); - requirement_data::load_obj_list( jsarr, req.tools ); + load_obj_list( jsobj.get_array( "components" ), req.components ); + load_obj_list( jsobj.get_array( "qualities" ), req.qualities ); + load_obj_list( jsobj.get_array( "tools" ), req.tools ); if( !id.is_null() ) { req.id_ = id; diff --git a/src/requirements.h b/src/requirements.h index 452558e2273e0..7fbf2a84c84ac 100644 --- a/src/requirements.h +++ b/src/requirements.h @@ -14,6 +14,7 @@ #include "type_id.h" class nc_color; +class JsonValue; class JsonObject; class JsonArray; class JsonIn; @@ -76,7 +77,7 @@ struct tool_comp : public component { tool_comp() = default; tool_comp( const itype_id &TYPE, int COUNT ) : component( TYPE, COUNT ) { } - void load( JsonArray &ja ); + void load( const JsonValue &value ); bool has( const inventory &crafting_inv, const std::function &filter, int batch = 1, std::function visitor = std::function() ) const; std::string to_string( int batch = 1, int avail = 0 ) const; @@ -92,7 +93,7 @@ struct item_comp : public component { item_comp() = default; item_comp( const itype_id &TYPE, int COUNT ) : component( TYPE, COUNT ) { } - void load( JsonArray &ja ); + void load( const JsonValue &value ); bool has( const inventory &crafting_inv, const std::function &filter, int batch = 1, std::function visitor = std::function() ) const; std::string to_string( int batch = 1, int avail = 0 ) const; @@ -114,7 +115,7 @@ struct quality_requirement { quality_requirement( const quality_id &TYPE, int COUNT, int LEVEL ) : type( TYPE ), count( COUNT ), level( LEVEL ) { } - void load( JsonArray &jsarr ); + void load( const JsonValue &value ); bool has( const inventory &crafting_inv, const std::function &filter, int = 0, std::function visitor = std::function() ) const; std::string to_string( int batch = 1, int avail = 0 ) const; @@ -142,8 +143,8 @@ struct quality_requirement { * * Requirements (item_comp, tool_comp, quality_requirement) must have those * functions: - * Load from the next entry of the json array: - * void load(JsonArray &jarr); + * Load from an entry of a json array: + * void load(const JsonValue &value); * Check whether the player has fulfills the requirement with this crafting * inventory (or by mutation): * bool has(const inventory &crafting_inv) const; @@ -326,7 +327,7 @@ struct requirement_data { template static bool any_marked_available( const std::vector &comps ); template - static void load_obj_list( JsonArray &jsarr, std::vector< std::vector > &objs ); + static void load_obj_list( const JsonArray &jsarr, std::vector< std::vector > &objs ); template static const T *find_by_type( const std::vector< std::vector > &vec, const ID &type ); }; From 5e2088fd4bb86877b689e830562dd1f935c08201 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:37:44 +0100 Subject: [PATCH 13/21] Change mutation_branch::load_trait_group to accept a const reference This allows to iterate over the array using a range-based lood. --- src/mutation_data.cpp | 11 +++++------ src/trait_group.cpp | 5 ++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index c6c1c34e893bb..acc31eb20dd7b 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -639,21 +639,20 @@ static Trait_group &make_group_or_throw( const trait_group::Trait_group_tag &gid return *found->second; } -void mutation_branch::load_trait_group( JsonArray &entries, const trait_group::Trait_group_tag &gid, - const bool is_collection ) +void mutation_branch::load_trait_group( const JsonArray &entries, const trait_group::Trait_group_tag &gid, const bool is_collection ) { Trait_group &tg = make_group_or_throw( gid, is_collection ); - while( entries.has_more() ) { + for( const JsonValue &entry : entries ) { // Backwards-compatibility with old format ["TRAIT", 100] - if( entries.test_array() ) { - JsonArray subarr = entries.next_array(); + if( entry.test_array() ) { + JsonArray subarr = entry.get_array(); trait_id id( subarr.get_string( 0 ) ); tg.add_entry( std::make_unique( id, subarr.get_int( 1 ) ) ); // Otherwise load new format {"trait": ... } or {"group": ...} } else { - JsonObject subobj = entries.next_object(); + JsonObject subobj = entry.get_object(); add_entry( tg, subobj ); } } diff --git a/src/trait_group.cpp b/src/trait_group.cpp index da028ca39a8b1..5f176822e919c 100644 --- a/src/trait_group.cpp +++ b/src/trait_group.cpp @@ -66,12 +66,11 @@ Trait_group_tag trait_group::load_trait_group( JsonIn &stream, const std::string } else if( stream.test_array() ) { const Trait_group_tag group = get_unique_trait_group_id(); - JsonArray jarr = stream.get_array(); if( default_subtype != "collection" && default_subtype != "distribution" ) { - jarr.throw_error( "invalid subtype for trait group" ); + stream.throw_error( "invalid subtype for trait group" ); } - mutation_branch::load_trait_group( jarr, group, default_subtype == "collection" ); + mutation_branch::load_trait_group( stream.get_array(), group, default_subtype == "collection" ); return group; } else { stream.error( "invalid trait group, must be string (group id) or object/array (the group data)" ); From d088831964073b28a0054b35ea62cc23074a1da5 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:40:00 +0100 Subject: [PATCH 14/21] Change trait_group::load_trait_group to accept a JsonValue Which can be used just like the stream. Also added a `JsonObject::get_member` function to get a specific member as `JsonValue`. --- src/json.cpp | 9 +++++++++ src/json.h | 4 ++-- src/mutation.h | 3 +-- src/npc_class.cpp | 4 ++-- src/trait_group.cpp | 18 +++++++++--------- src/trait_group.h | 10 +++++----- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/json.cpp b/src/json.cpp index cd60cbd7c9af4..38d3dce723c82 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -1885,3 +1885,12 @@ JsonIn &JsonValue::seek() const jsin_.seek( pos_ ); return jsin_; } + +JsonValue JsonObject::get_member( const std::string &name ) const { + const auto iter = positions.find(name); + if(!jsin || iter == positions.end()) { + throw_error("requested non-existing member \"" + name + "\""); + } + visited_members.insert( name ); + return JsonValue( *jsin, iter->second ); +} diff --git a/src/json.h b/src/json.h index 8a5d7c43982cd..259077859d27c 100644 --- a/src/json.h +++ b/src/json.h @@ -35,6 +35,7 @@ class JsonObject; class JsonArray; class JsonSerializer; class JsonDeserializer; +class JsonValue; template class string_id; @@ -836,6 +837,7 @@ class JsonObject [[noreturn]] void throw_error( std::string err, const std::string &name ) const; // seek to a value and return a pointer to the JsonIn (member must exist) JsonIn *get_raw( const std::string &name ) const; + JsonValue get_member( const std::string &name ) const; // values by name // variants with no fallback throw an error if the name is not found. @@ -910,8 +912,6 @@ class JsonObject std::string line_number() const; // for occasional use only }; -class JsonValue; - /* JsonArray * ========= * diff --git a/src/mutation.h b/src/mutation.h index e2a06a1295e50..d03cb1c16f013 100644 --- a/src/mutation.h +++ b/src/mutation.h @@ -355,8 +355,7 @@ struct mutation_branch { * Note that each entry in the array has to be a JSON object. The other function above * can also load data from arrays of strings, where the strings are item or group ids. */ - static void load_trait_group( JsonArray &entries, const trait_group::Trait_group_tag &gid, - bool is_collection ); + static void load_trait_group( const JsonArray &entries, const trait_group::Trait_group_tag &gid, bool is_collection ); /** * Create a new trait group as specified by the given JSON object and register diff --git a/src/npc_class.cpp b/src/npc_class.cpp index 7ad7c54a0bb30..949ca3871001a 100644 --- a/src/npc_class.cpp +++ b/src/npc_class.cpp @@ -247,8 +247,8 @@ void npc_class::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "carry_override", carry_override ); optional( jo, was_loaded, "weapon_override", weapon_override ); - if( jo.has_array( "traits" ) ) { - traits = trait_group::load_trait_group( *jo.get_raw( "traits" ), "collection" ); + if( jo.has_member( "traits" ) ) { + traits = trait_group::load_trait_group( jo.get_member( "traits" ), "collection" ); } if( jo.has_array( "spells" ) ) { diff --git a/src/trait_group.cpp b/src/trait_group.cpp index 5f176822e919c..2037c4759ba53 100644 --- a/src/trait_group.cpp +++ b/src/trait_group.cpp @@ -50,30 +50,30 @@ static Trait_group_tag get_unique_trait_group_id() } } -Trait_group_tag trait_group::load_trait_group( JsonIn &stream, const std::string &default_subtype ) +Trait_group_tag trait_group::load_trait_group( const JsonValue &value, const std::string &default_subtype ) { - if( stream.test_string() ) { - return Trait_group_tag( stream.get_string() ); - } else if( stream.test_object() ) { + if( value.test_string() ) { + return Trait_group_tag( value.get_string() ); + } else if( value.test_object() ) { const Trait_group_tag group = get_unique_trait_group_id(); - JsonObject jo = stream.get_object(); + JsonObject jo = value.get_object(); const std::string subtype = jo.get_string( "subtype", default_subtype ); mutation_branch::load_trait_group( jo, group, subtype ); return group; - } else if( stream.test_array() ) { + } else if( value.test_array() ) { const Trait_group_tag group = get_unique_trait_group_id(); if( default_subtype != "collection" && default_subtype != "distribution" ) { - stream.throw_error( "invalid subtype for trait group" ); + value.throw_error( "invalid subtype for trait group" ); } - mutation_branch::load_trait_group( stream.get_array(), group, default_subtype == "collection" ); + mutation_branch::load_trait_group( value.get_array(), group, default_subtype == "collection" ); return group; } else { - stream.error( "invalid trait group, must be string (group id) or object/array (the group data)" ); + value.throw_error( "invalid trait group, must be string (group id) or object/array (the group data)" ); return Trait_group_tag{}; } } diff --git a/src/trait_group.h b/src/trait_group.h index 7cc93a437ca3a..cb2dd1bd4c24c 100644 --- a/src/trait_group.h +++ b/src/trait_group.h @@ -12,6 +12,7 @@ class JsonObject; class JsonIn; class Trait_group; +class JsonValue; namespace trait_group { @@ -38,23 +39,22 @@ void load_trait_group( const JsonObject &jsobj, const Trait_group_tag &gid, /** * Get a trait group ID and optionally load an inlined trait group. * - * If the next value in the JSON stream is string, it's assumed to be a trait group id and it's + * If the value is string, it's assumed to be a trait group id and it's * returned directly. * - * If the next value is a JSON object, it is loaded as a trait group. The group will be given a + * If the value is a JSON object, it is loaded as a trait group. The group will be given a * unique id (if the JSON object contains an id, it is ignored) and that id will be returned. * If the JSON object does not contain a subtype, the given default is used. * - * If the next value is a JSON array, it is loaded as a trait group: the default_subtype will be + * If the value is a JSON array, it is loaded as a trait group: the default_subtype will be * used as subtype of the new trait group and the array is loaded like the "entries" array of * a trait group definition (see format of trait groups). * - * @param stream Stream to load from * @param default_subtype If an inlined trait group is loaded this is used as the default * subtype. It must be either "distribution" or "collection". See @ref Trait_group. * @throw JsonError as usual for JSON errors, including invalid input values. */ -Trait_group_tag load_trait_group( JsonIn &stream, const std::string &default_subtype ); +Trait_group_tag load_trait_group( const JsonValue &value, const std::string &default_subtype ); /** * Show a debug menu for testing trait groups. From 59f8ce1dff14d48e6ee03cfc78f7ef4bb70b634f Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 17:59:18 +0100 Subject: [PATCH 15/21] Change snippet_library::add_snippets_from_json to take a const reference. Which allows to iterate over the array using a range-based loop. --- src/item_factory.cpp | 3 +-- src/text_snippets.cpp | 15 +++++++-------- src/text_snippets.h | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/item_factory.cpp b/src/item_factory.cpp index a3a3f557e654d..9ba667b588603 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2204,8 +2204,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: // auto-create a category that is unlikely to already be used and put the // snippets in it. def.snippet_category = std::string( "auto:" ) + def.id; - JsonArray jarr = jo.get_array( "snippet_category" ); - SNIPPET.add_snippets_from_json( def.snippet_category, jarr ); + SNIPPET.add_snippets_from_json( def.snippet_category, jo.get_array( "snippet_category" ) ); } else { def.snippet_category = jo.get_string( "snippet_category", "" ); } diff --git a/src/text_snippets.cpp b/src/text_snippets.cpp index 77702961c2293..86cfb0bee09dc 100644 --- a/src/text_snippets.cpp +++ b/src/text_snippets.cpp @@ -18,28 +18,27 @@ void snippet_library::load_snippet( const JsonObject &jsobj ) hash_to_id_migration = cata::nullopt; const std::string category = jsobj.get_string( "category" ); if( jsobj.has_array( "text" ) ) { - JsonArray jarr = jsobj.get_array( "text" ); - add_snippets_from_json( category, jarr ); + add_snippets_from_json( category, jsobj.get_array( "text" ) ); } else { add_snippet_from_json( category, jsobj ); } } -void snippet_library::add_snippets_from_json( const std::string &category, JsonArray &jarr ) +void snippet_library::add_snippets_from_json( const std::string &category, const JsonArray &jarr ) { if( hash_to_id_migration.has_value() ) { debugmsg( "snippet_library::add_snippets_from_json called after snippet_library::migrate_hash_to_id." ); } hash_to_id_migration = cata::nullopt; - while( jarr.has_more() ) { - if( jarr.test_string() ) { + for( const JsonValue &entry : jarr ) { + if( entry.test_string() ) { translation text; - if( !jarr.read_next( text ) ) { - jarr.throw_error( "Error reading snippet from JSON array" ); + if( !entry.read( text ) ) { + entry.throw_error( "Error reading snippet from JSON array" ); } snippets_by_category[category].no_id.emplace_back( text ); } else { - JsonObject jo = jarr.next_object(); + JsonObject jo = entry.get_object(); add_snippet_from_json( category, jo ); } } diff --git a/src/text_snippets.h b/src/text_snippets.h index f20dd03b6c380..91d062efd4946 100644 --- a/src/text_snippets.h +++ b/src/text_snippets.h @@ -24,7 +24,7 @@ class snippet_library * Entries in the array can be simple strings, or json objects (for the * later see add_snippet_from_json). */ - void add_snippets_from_json( const std::string &category, JsonArray &jarr ); + void add_snippets_from_json( const std::string &category, const JsonArray &jarr ); /** * Load a single snippet text from the json object. The object should have * a "text" member with the text of the snippet. From 10d7ac2bf5b7267cff27f31a529b52409105713e Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:00:41 +0100 Subject: [PATCH 16/21] Change mission_util::set_reveal_any to take a const reference --- src/mission.h | 2 +- src/mission_util.cpp | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/mission.h b/src/mission.h index 15595e6decf56..11c76a7e4a505 100644 --- a/src/mission.h +++ b/src/mission.h @@ -172,7 +172,7 @@ tripoint target_om_ter_random( const std::string &omter, int reveal_rad, mission bool must_see, int range, tripoint loc = overmap::invalid_tripoint ); void set_reveal( const std::string &terrain, std::vector> &funcs ); -void set_reveal_any( JsonArray &ja, std::vector> &funcs ); +void set_reveal_any( const JsonArray &ja, std::vector> &funcs ); mission_target_params parse_mission_om_target( const JsonObject &jo ); cata::optional assign_mission_target( const mission_target_params ¶ms ); tripoint get_om_terrain_pos( const mission_target_params ¶ms ); diff --git a/src/mission_util.cpp b/src/mission_util.cpp index 19c9308d661bd..b120861872d1c 100644 --- a/src/mission_util.cpp +++ b/src/mission_util.cpp @@ -423,12 +423,10 @@ void mission_util::set_reveal( const std::string &terrain, funcs.emplace_back( mission_func ); } -void mission_util::set_reveal_any( JsonArray &ja, - std::vector> &funcs ) +void mission_util::set_reveal_any( const JsonArray &ja, std::vector> &funcs ) { std::vector terrains; - while( ja.has_more() ) { - std::string terrain = ja.next_string(); + for( const std::string &terrain : ja ) { terrains.push_back( terrain ); } const auto mission_func = [ terrains ]( mission * miss ) { @@ -486,8 +484,7 @@ bool mission_util::load_funcs( const JsonObject &jo, const std::string target_terrain = jo.get_string( "reveal_om_ter" ); set_reveal( target_terrain, funcs ); } else if( jo.has_array( "reveal_om_ter" ) ) { - JsonArray target_terrain = jo.get_array( "reveal_om_ter" ); - set_reveal_any( target_terrain, funcs ); + set_reveal_any( jo.get_array( "reveal_om_ter" ), funcs ); } else if( jo.has_object( "assign_mission_target" ) ) { JsonObject mission_target = jo.get_object( "assign_mission_target" ); set_assign_om_target( mission_target, funcs ); From 84a53d7bb4023efb243aa3e31b52ebd0029800a2 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:04:43 +0100 Subject: [PATCH 17/21] Change load_damage_instance to take a const reference And use a range-based loop. --- src/damage.cpp | 8 +++----- src/damage.h | 2 +- src/item_factory.cpp | 3 +-- src/mattack_actors.cpp | 3 +-- src/monstergenerator.cpp | 3 +-- src/mutation_data.cpp | 6 ++---- 6 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/damage.cpp b/src/damage.cpp index 1442a61872bf6..1e3dd442ef0a0 100644 --- a/src/damage.cpp +++ b/src/damage.cpp @@ -146,8 +146,7 @@ void damage_instance::deserialize( JsonIn &jsin ) JsonObject jo = jsin.get_object(); damage_units = load_damage_instance( jo ).damage_units; } else if( jsin.test_array() ) { - JsonArray ja = jsin.get_array(); - damage_units = load_damage_instance( ja ).damage_units; + damage_units = load_damage_instance( jsin.get_array() ).damage_units; } else { jsin.error( "Expected object or array for damage_instance" ); } @@ -314,11 +313,10 @@ damage_instance load_damage_instance( const JsonObject &jo ) return di; } -damage_instance load_damage_instance( JsonArray &jarr ) +damage_instance load_damage_instance( const JsonArray &jarr ) { damage_instance di; - while( jarr.has_more() ) { - JsonObject curr = jarr.next_object(); + for( const JsonObject &curr : jarr ) { di.damage_units.push_back( load_damage_unit( curr ) ); } diff --git a/src/damage.h b/src/damage.h index e4ebf3f94bde4..2c63574bb02fa 100644 --- a/src/damage.h +++ b/src/damage.h @@ -111,7 +111,7 @@ std::string name_by_dt( const damage_type &dt ); const skill_id &skill_by_dt( damage_type dt ); damage_instance load_damage_instance( const JsonObject &jo ); -damage_instance load_damage_instance( JsonArray &jarr ); +damage_instance load_damage_instance( const JsonArray &jarr ); resistances load_resistances_instance( const JsonObject &jo ); diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 9ba667b588603..1f3f7c95c943b 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2035,8 +2035,7 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: assign( jo, "insulation", def.insulation_factor ); if( jo.has_member( "thrown_damage" ) ) { - JsonArray jarr = jo.get_array( "thrown_damage" ); - def.thrown_damage = load_damage_instance( jarr ); + def.thrown_damage = load_damage_instance( jo.get_array( "thrown_damage" ) ); } else { // TODO: Move to finalization def.thrown_damage.clear(); diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index 7114931720c2e..ab1f8bb3704ea 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -214,8 +214,7 @@ void melee_actor::load_internal( const JsonObject &obj, const std::string & ) { // Optional: if( obj.has_array( "damage_max_instance" ) ) { - JsonArray arr = obj.get_array( "damage_max_instance" ); - damage_max_instance = load_damage_instance( arr ); + damage_max_instance = load_damage_instance( obj.get_array( "damage_max_instance" ) ); } else if( obj.has_object( "damage_max_instance" ) ) { damage_max_instance = load_damage_instance( obj ); } diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index b0efdfd8fca4a..50f91ee2004ac 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -679,8 +679,7 @@ void mtype::load( const JsonObject &jo, const std::string &src ) // TODO: make this work with `was_loaded` if( jo.has_array( "melee_damage" ) ) { - JsonArray arr = jo.get_array( "melee_damage" ); - melee_damage = load_damage_instance( arr ); + melee_damage = load_damage_instance( jo.get_array( "melee_damage" ) ); } else if( jo.has_object( "melee_damage" ) ) { melee_damage = load_damage_instance( jo ); } diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index acc31eb20dd7b..09e280bf33816 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -215,16 +215,14 @@ static mut_attack load_mutation_attack( const JsonObject &jo ) jo.read( "chance", ret.chance ); if( jo.has_array( "base_damage" ) ) { - JsonArray jo_dam = jo.get_array( "base_damage" ); - ret.base_damage = load_damage_instance( jo_dam ); + ret.base_damage = load_damage_instance( jo.get_array( "base_damage" ) ); } else if( jo.has_object( "base_damage" ) ) { JsonObject jo_dam = jo.get_object( "base_damage" ); ret.base_damage = load_damage_instance( jo_dam ); } if( jo.has_array( "strength_damage" ) ) { - JsonArray jo_dam = jo.get_array( "strength_damage" ); - ret.strength_damage = load_damage_instance( jo_dam ); + ret.strength_damage = load_damage_instance( jo.get_array( "strength_damage" ) ); } else if( jo.has_object( "strength_damage" ) ) { JsonObject jo_dam = jo.get_object( "strength_damage" ); ret.strength_damage = load_damage_instance( jo_dam ); From f4fa18c4dbc36d3ef573e81b5b8cf63a6435d4b6 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:13:59 +0100 Subject: [PATCH 18/21] Change mapgen_function_json_base::setup_setmap to take a const reference And iterate over it via a range-based loop. --- src/mapgen.cpp | 8 +++----- src/mapgen.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 019c3f4cd10e2..01d2b47de9e5d 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -577,7 +577,7 @@ int jmapgen_int::get() const * Turn json gobbldigook into machine friendly gobbldigook, for applying * basic map 'set' functions, optionally based on one_in(chance) or repeat value */ -void mapgen_function_json_base::setup_setmap( JsonArray &parray ) +void mapgen_function_json_base::setup_setmap( const JsonArray &parray ) { std::string tmpval; std::map setmap_opmap; @@ -590,8 +590,7 @@ void mapgen_function_json_base::setup_setmap( JsonArray &parray ) jmapgen_setmap_op tmpop; int setmap_optype = 0; - while( parray.has_more() ) { - JsonObject pjo = parray.next_object(); + for( const JsonObject &pjo : parray ) { if( pjo.read( "point", tmpval ) ) { setmap_optype = JMAPGEN_SETMAP_OPTYPE_POINT; } else if( pjo.read( "set", tmpval ) ) { @@ -2304,8 +2303,7 @@ bool mapgen_function_json_base::setup_common( const JsonObject &jo ) } if( jo.has_array( "set" ) ) { - parray = jo.get_array( "set" ); - setup_setmap( parray ); + setup_setmap( jo.get_array( "set" ) ); } // "add" is deprecated in favor of "place_item", but kept to support mods diff --git a/src/mapgen.h b/src/mapgen.h index e21be63201c30..d76980a3cef42 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -290,7 +290,7 @@ class mapgen_function_json_base void setup_common(); bool setup_common( const JsonObject &jo ); - void setup_setmap( JsonArray &parray ); + void setup_setmap( const JsonArray &parray ); // Returns true if the mapgen qualifies at this point already virtual bool setup_internal( const JsonObject &jo ) = 0; virtual void setup_setmap_internal() { } From 30d957835266ad57b45556bbdb4c992567752556 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:16:35 +0100 Subject: [PATCH 19/21] Change loop to respect size of both arrays: The loop would previously read more data than there was storage reserved for (it could read more than `adv_inv_in_vehicle.size()` elements). --- src/uistate.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uistate.h b/src/uistate.h index c2ff1478bb67c..16e823f3d2120 100644 --- a/src/uistate.h +++ b/src/uistate.h @@ -206,9 +206,9 @@ class uistatedata } // viewing vehicle cargo if( jo.has_array( "adv_inv_in_vehicle" ) ) { - auto ja = jo.get_array( "adv_inv_in_vehicle" ); - for( size_t i = 0; ja.has_more(); ++i ) { - adv_inv_in_vehicle[i] = ja.next_bool(); + const JsonArray ja = jo.get_array( "adv_inv_in_vehicle" ); + for( size_t i = 0; i < adv_inv_in_vehicle.size() && i < ja.size(); ++i ) { + adv_inv_in_vehicle[i] = ja.get_bool( i ); } } // filter strings From a7bb9a75d6bf4dfedc032babcf4919c4743dc7e7 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:25:37 +0100 Subject: [PATCH 20/21] Change Item_factory::load_item_group to take a const reference --- src/item_factory.cpp | 7 ++----- src/item_factory.h | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 1f3f7c95c943b..c61fa6e6f9fee 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2513,16 +2513,13 @@ void Item_factory::load_item_group( const JsonObject &jsobj ) load_item_group( jsobj, group_id, subtype ); } -void Item_factory::load_item_group( JsonArray &entries, const Group_tag &group_id, - const bool is_collection, int ammo_chance, - int magazine_chance ) +void Item_factory::load_item_group( const JsonArray &entries, const Group_tag &group_id, const bool is_collection, const int ammo_chance, const int magazine_chance ) { const auto type = is_collection ? Item_group::G_COLLECTION : Item_group::G_DISTRIBUTION; std::unique_ptr &isd = m_template_groups[group_id]; Item_group *const ig = make_group_or_throw( group_id, isd, type, ammo_chance, magazine_chance ); - while( entries.has_more() ) { - JsonObject subobj = entries.next_object(); + for( const JsonObject &subobj : entries ) { add_entry( *ig, subobj ); } } diff --git a/src/item_factory.h b/src/item_factory.h index 45ec7ddbe022c..6570965930581 100644 --- a/src/item_factory.h +++ b/src/item_factory.h @@ -121,8 +121,7 @@ class Item_factory * Note that each entry in the array has to be a JSON object. The other function above * can also load data from arrays of strings, where the strings are item or group ids. */ - void load_item_group( JsonArray &entries, const Group_tag &group_id, bool is_collection, - int ammo_chance, int magazine_chance ); + void load_item_group( const JsonArray &entries, const Group_tag &group_id, bool is_collection, int ammo_chance, int magazine_chance ); /** * Get the item group object. Returns null if the item group does not exists. */ From f5efe43c37778a56275591421cf4107f6127b7d0 Mon Sep 17 00:00:00 2001 From: BevapDin Date: Thu, 12 Dec 2019 18:30:07 +0100 Subject: [PATCH 21/21] Change item_group::load_item_group to take a JsonValue instead of a stream. --- src/construction.cpp | 3 +-- src/item_group.cpp | 16 ++++++++-------- src/item_group.h | 10 +++++----- src/mapdata.cpp | 6 ++---- src/monstergenerator.cpp | 3 +-- src/profession.cpp | 6 +++--- src/veh_type.cpp | 3 +-- 7 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/construction.cpp b/src/construction.cpp index 55974e535c850..c984694bfbcd7 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -1398,8 +1398,7 @@ void load_construction( const JsonObject &jo ) con.post_flags = jo.get_tags( "post_flags" ); if( jo.has_member( "byproducts" ) ) { - JsonIn &stream = *jo.get_raw( "byproducts" ); - con.byproduct_item_group = item_group::load_item_group( stream, "collection" ); + con.byproduct_item_group = item_group::load_item_group( jo.get_member( "byproducts" ), "collection" ); } static const std::map> pre_special_map = {{ diff --git a/src/item_group.cpp b/src/item_group.cpp index 9dbb4421086f5..086ac150471e6 100644 --- a/src/item_group.cpp +++ b/src/item_group.cpp @@ -588,22 +588,22 @@ static Group_tag get_unique_group_id() } } -Group_tag item_group::load_item_group( JsonIn &stream, const std::string &default_subtype ) +Group_tag item_group::load_item_group( const JsonValue &value, const std::string &default_subtype ) { - if( stream.test_string() ) { - return stream.get_string(); - } else if( stream.test_object() ) { + if( value.test_string() ) { + return value.get_string(); + } else if( value.test_object() ) { const Group_tag group = get_unique_group_id(); - JsonObject jo = stream.get_object(); + JsonObject jo = value.get_object(); const std::string subtype = jo.get_string( "subtype", default_subtype ); item_controller->load_item_group( jo, group, subtype ); return group; - } else if( stream.test_array() ) { + } else if( value.test_array() ) { const Group_tag group = get_unique_group_id(); - JsonArray jarr = stream.get_array(); + JsonArray jarr = value.get_array(); // load_item_group needs a bool, invalid subtypes are unexpected and most likely errors // from the caller of this function. if( default_subtype != "collection" && default_subtype != "distribution" ) { @@ -613,7 +613,7 @@ Group_tag item_group::load_item_group( JsonIn &stream, const std::string &defaul return group; } else { - stream.error( "invalid item group, must be string (group id) or object/array (the group data)" ); + value.throw_error( "invalid item group, must be string (group id) or object/array (the group data)" ); // stream.error always throws, this is here to prevent a warning return Group_tag{}; } diff --git a/src/item_group.h b/src/item_group.h index 81b050ac6803e..7e1c72f74f94e 100644 --- a/src/item_group.h +++ b/src/item_group.h @@ -16,7 +16,7 @@ struct itype; using Item_tag = std::string; using Group_tag = std::string; class JsonObject; -class JsonIn; +class JsonValue; class time_point; namespace item_group @@ -79,14 +79,14 @@ void load_item_group( const JsonObject &jsobj, const Group_tag &group_id, /** * Get an item group id and (optionally) load an inlined item group. * - * If the next value in the JSON stream is string, it's assumed to be an item group id and it's + * If the value is string, it's assumed to be an item group id and it's * returned directly. * - * If the next value is a JSON object, it is loaded as item group. The group will be given a + * If the value is a JSON object, it is loaded as item group. The group will be given a * unique id (if the JSON object contains an id, it is ignored) and that id will be returned. * If the JSON object does not contain a subtype, the given default is used. * - * If the next value is a JSON array, it is loaded as item group: the default_subtype will be + * If the value is a JSON array, it is loaded as item group: the default_subtype will be * used as subtype of the new item group and the array is loaded like the "entries" array of * a item group definition (see format of item groups). * @@ -95,7 +95,7 @@ void load_item_group( const JsonObject &jsobj, const Group_tag &group_id, * subtype. It must be either "distribution" or "collection". See @ref Item_group. * @throw JsonError as usual for JSON errors, including invalid input values. */ -Group_tag load_item_group( JsonIn &stream, const std::string &default_subtype ); +Group_tag load_item_group( const JsonValue &value, const std::string &default_subtype ); } // namespace item_group /** diff --git a/src/mapdata.cpp b/src/mapdata.cpp index 616a16da7ea7e..7cf26bedd0215 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -239,8 +239,7 @@ bool map_bash_info::load( const JsonObject &jsobj, const std::string &member, bo } if( j.has_member( "items" ) ) { - JsonIn &stream = *j.get_raw( "items" ); - drop_group = item_group::load_item_group( stream, "collection" ); + drop_group = item_group::load_item_group( j.get_member( "items" ), "collection" ); } else { drop_group = "EMPTY_GROUP"; } @@ -270,8 +269,7 @@ bool map_deconstruct_info::load( const JsonObject &jsobj, const std::string &mem can_do = true; deconstruct_above = j.get_bool( "deconstruct_above", false ); - JsonIn &stream = *j.get_raw( "items" ); - drop_group = item_group::load_item_group( stream, "collection" ); + drop_group = item_group::load_item_group( j.get_member( "items" ), "collection" ); return true; } diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 50f91ee2004ac..a03e930232131 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -697,8 +697,7 @@ void mtype::load( const JsonObject &jo, const std::string &src ) } if( jo.has_member( "death_drops" ) ) { - JsonIn &stream = *jo.get_raw( "death_drops" ); - death_drops = item_group::load_item_group( stream, "distribution" ); + death_drops = item_group::load_item_group( jo.get_member( "death_drops" ), "distribution" ); } assign( jo, "harvest", harvest ); diff --git a/src/profession.cpp b/src/profession.cpp index ef58e88775e93..2ec55f98be56a 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -196,19 +196,19 @@ void profession::load( const JsonObject &jo, const std::string & ) optional( items_obj, was_loaded, "both", legacy_starting_items, item_reader {} ); } if( items_obj.has_object( "both" ) ) { - _starting_items = item_group::load_item_group( *items_obj.get_raw( "both" ), "collection" ); + _starting_items = item_group::load_item_group( items_obj.get_member( "both" ), "collection" ); } if( items_obj.has_array( "male" ) ) { optional( items_obj, was_loaded, "male", legacy_starting_items_male, item_reader {} ); } if( items_obj.has_object( "male" ) ) { - _starting_items_male = item_group::load_item_group( *items_obj.get_raw( "male" ), "collection" ); + _starting_items_male = item_group::load_item_group( items_obj.get_member( "male" ), "collection" ); } if( items_obj.has_array( "female" ) ) { optional( items_obj, was_loaded, "female", legacy_starting_items_female, item_reader {} ); } if( items_obj.has_object( "female" ) ) { - _starting_items_female = item_group::load_item_group( *items_obj.get_raw( "female" ), + _starting_items_female = item_group::load_item_group( items_obj.get_member( "female" ), "collection" ); } } diff --git a/src/veh_type.cpp b/src/veh_type.cpp index 17a99e4d5a1e1..6d62cfdcb1be9 100644 --- a/src/veh_type.cpp +++ b/src/veh_type.cpp @@ -388,8 +388,7 @@ void vpart_info::load( const JsonObject &jo, const std::string &src ) } if( jo.has_member( "breaks_into" ) ) { - JsonIn &stream = *jo.get_raw( "breaks_into" ); - def.breaks_into_group = item_group::load_item_group( stream, "collection" ); + def.breaks_into_group = item_group::load_item_group( jo.get_member( "breaks_into" ), "collection" ); } auto qual = jo.get_array( "qualities" );