45 #include <rapidjson/rapidjson.h> 
   48 #define SAVEGAME_FILE_FORMAT 3 
   56 std::string GameContext::GetQuicksaveFilename()
 
   61     return "quicksave_" + StringUtil::replaceAll(terrain_name, 
".terrn2", 
"") + mp + 
".sav";
 
   64 void GameContext::LoadScene(std::string 
const& filename)
 
   67     m_actor_manager.LoadScene(filename);
 
   70 void GameContext::SaveScene(std::string 
const& filename)
 
   72     m_actor_manager.SaveScene(filename);
 
   75 std::string GameContext::ExtractSceneName(std::string 
const& filename)
 
   78     rapidjson::Document j_doc;
 
   80         !j_doc.IsObject() || !j_doc.HasMember(
"format_version") || !j_doc[
"format_version"].IsNumber() ||
 
   81         !j_doc.HasMember(
"scene_name") || !j_doc[
"scene_name"].IsString())
 
   84     return j_doc[
"scene_name"].GetString();
 
   87 std::string GameContext::ExtractSceneTerrain(std::string 
const& filename)
 
   90     rapidjson::Document j_doc;
 
   92         !j_doc.IsObject() || !j_doc.HasMember(
"format_version") || !j_doc[
"format_version"].IsNumber() ||
 
   93         !j_doc.HasMember(
"terrain_name") || !j_doc[
"terrain_name"].IsString())
 
   96     return j_doc[
"terrain_name"].GetString();
 
   99 void GameContext::HandleSavegameHotkeys()
 
  206             dialog->
mbc_title = 
_LC(
"QuickloadDialog", 
"Load game?");
 
  207             dialog->
mbc_text = 
_LC(
"QuickloadDialog", 
"You will lose all unsaved progress!");
 
  240 bool ActorManager::LoadScene(Ogre::String save_filename)
 
  243     rapidjson::Document j_doc;
 
  245         !j_doc.IsObject() || !j_doc.HasMember(
"format_version") || !j_doc[
"format_version"].IsNumber())
 
  248             Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR, 
_L(
"Error while loading scene: File invalid or missing"));
 
  254             Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR, 
_L(
"Error while loading scene: File format mismatch"));
 
  259     String terrain_name = j_doc[
"terrain_name"].GetString();
 
  263         if (save_filename == 
"autosave.sav")
 
  268                 Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR, 
_L(
"Error while loading scene: Terrain mismatch"));
 
  271         if (j_doc[
"actors"].GetArray().Size() > 3)
 
  274                 Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR, 
_L(
"Error while loading scene: Too many vehicles"));
 
  279     m_forced_awake = j_doc[
"forced_awake"].GetBool();
 
  286         if (j_doc.HasMember(
"daytime"))
 
  294     auto data = j_doc[
"player_position"].GetArray();
 
  295     Vector3 position = Vector3(data[0].GetFloat(), data[1].GetFloat(), data[2].GetFloat());
 
  300     auto actors_changed = 
false;
 
  303     std::vector<ActorPtr> actors;
 
  304     std::vector<ActorPtr> x_actors = GetLocalActors();
 
  305     for (rapidjson::Value& j_entry: j_doc[
"actors"].GetArray())
 
  308         String rigdef_filename_maybe_bundle_qualified = j_entry[
"filename"].GetString();
 
  309         std::string filename;
 
  310         std::string bundlename;
 
  315         if (j_entry.HasMember(
"skin"))
 
  321         if (j_entry.HasMember(
"tuneup_document"))
 
  323             const char* tuneup_str = j_entry[
"tuneup_document"].GetString();
 
  324             size_t tuneup_len = j_entry[
"tuneup_document"].GetStringLength();
 
  325             Ogre::DataStreamPtr datastream(
new Ogre::MemoryDataStream((
void*)tuneup_str, tuneup_len));
 
  326             std::vector<TuneupDefPtr> tuneups = TuneupUtil::ParseTuneups(datastream);
 
  328             working_tuneup = tuneups[0];
 
  331         String section_config = j_entry[
"section_config"].GetString();
 
  334         int index = 
static_cast<int>(actors.size());
 
  335         if (index < x_actors.size())
 
  337             if (filename != x_actors[index]->ar_filename ||
 
  338                 (skin != 
nullptr && skin->
dname != x_actors[index]->m_used_skin_entry->dname) ||
 
  339                 section_config != x_actors[index]->getSectionConfig())
 
  341                 if (x_actors[index] == player_actor)
 
  345                 else if (x_actors[index] == prev_player_actor)
 
  350                 actors_changed = 
true;
 
  354                 actor = x_actors[index];
 
  360         if (actor == 
nullptr && !j_entry[
"preloaded_with_terrain"].GetBool())
 
  363             rq->
asr_filename      = rigdef_filename_maybe_bundle_qualified;
 
  367             rq->
asr_rotation      = Quaternion(Degree(270) - Radian(j_entry[
"rotation"].GetFloat()), Vector3::UNIT_Y);
 
  371             rq->
asr_origin        = ActorSpawnRequest::Origin::SAVEGAME;
 
  373             rq->
asr_saved_state = std::shared_ptr<rapidjson::Document>(
new rapidjson::Document());
 
  377             actors_changed = 
true;
 
  381         actors.push_back(actor);
 
  383     for (
size_t index = actors.size(); index < x_actors.size(); index++)
 
  385         if (x_actors[index] == player_actor)
 
  389         else if (x_actors[index] == prev_player_actor)
 
  394         actors_changed = 
true;
 
  397     const int num_actors = 
static_cast<int>(j_doc[
"actors"].Size());
 
  398     for (
int index = 0; index < num_actors; index++)
 
  400         if (actors[index] == 
nullptr)
 
  404         rapidjson::Value& j_entry = j_doc[
"actors"][index];
 
  406         this->RestoreSavedState(actor, j_entry);
 
  409     if (save_filename != 
"autosave.sav")
 
  412             Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, 
_L(
"Scene loaded"));
 
  418 bool ActorManager::SaveScene(Ogre::String filename)
 
  420     std::vector<ActorPtr> x_actors = GetLocalActors();
 
  424         if (filename == 
"autosave.sav")
 
  426         if (x_actors.size() > 3)
 
  429                 Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR, 
_L(
"Error while saving scene: Too many vehicles"));
 
  434     rapidjson::Document j_doc;
 
  440     String scene_name = 
StringUtil::format(
"%s [%d]", pretty_name.c_str(), x_actors.size());
 
  441     j_doc.AddMember(
"scene_name", rapidjson::StringRef(scene_name.c_str()), j_doc.GetAllocator());
 
  444     j_doc.AddMember(
"terrain_name", rapidjson::StringRef(
App::sim_terrain_name->getStr().c_str()), j_doc.GetAllocator());
 
  453     j_doc.AddMember(
"forced_awake", m_forced_awake, j_doc.GetAllocator());
 
  455     j_doc.AddMember(
"physics_paused", 
App::GetGameContext()->GetActorManager()->IsSimulationPaused(), j_doc.GetAllocator());
 
  458     rapidjson::Value j_player_position(rapidjson::kArrayType);
 
  459     j_player_position.PushBack(
App::GetGameContext()->GetPlayerCharacter()->getPosition().
x, j_doc.GetAllocator());
 
  460     j_player_position.PushBack(
App::GetGameContext()->GetPlayerCharacter()->getPosition().
y, j_doc.GetAllocator());
 
  461     j_player_position.PushBack(
App::GetGameContext()->GetPlayerCharacter()->getPosition().
z, j_doc.GetAllocator());
 
  462     j_doc.AddMember(
"player_position", j_player_position, j_doc.GetAllocator());
 
  463     j_doc.AddMember(
"player_rotation", 
App::GetGameContext()->GetPlayerCharacter()->getRotation().valueRadians(), j_doc.GetAllocator());
 
  465     std::map<int, int> vector_index_lookup;
 
  468         vector_index_lookup[actor->ar_vector_index] = -1;
 
  469         auto search = std::find_if(x_actors.begin(), x_actors.end(), [actor](
ActorPtr b)
 
  470                 { return actor->ar_instance_id == b->ar_instance_id; });
 
  471         if (search != x_actors.end())
 
  473             vector_index_lookup[actor->ar_vector_index] = std::distance(x_actors.begin(), search);
 
  478     rapidjson::Value j_actors(rapidjson::kArrayType);
 
  481         rapidjson::Value j_entry(rapidjson::kObjectType);
 
  486         Ogre::StringUtil::splitFilename(actor->getUsedActorEntry()->resource_bundle_path, bname, bpath);
 
  487         std::string bq_filename = 
fmt::format(
"{}:{}", bname, actor->ar_filename);
 
  488         rapidjson::Value j_bq_filename(bq_filename.c_str(), j_doc.GetAllocator());
 
  489         j_entry.AddMember(
"filename", j_bq_filename, j_doc.GetAllocator());
 
  491         rapidjson::Value j_actor_position(rapidjson::kArrayType);
 
  492         j_actor_position.PushBack(actor->ar_nodes[0].AbsPosition.x, j_doc.GetAllocator());
 
  493         j_actor_position.PushBack(actor->ar_nodes[0].AbsPosition.y, j_doc.GetAllocator());
 
  494         j_actor_position.PushBack(actor->ar_nodes[0].AbsPosition.z, j_doc.GetAllocator());
 
  495         j_entry.AddMember(
"position", j_actor_position, j_doc.GetAllocator());
 
  496         j_entry.AddMember(
"rotation", actor->getRotation(), j_doc.GetAllocator());
 
  497         j_entry.AddMember(
"min_height", actor->getMinHeight(), j_doc.GetAllocator());
 
  498         j_entry.AddMember(
"spawn_rotation", actor->m_spawn_rotation, j_doc.GetAllocator());
 
  499         j_entry.AddMember(
"preloaded_with_terrain", actor->isPreloadedWithTerrain(), j_doc.GetAllocator());
 
  500         j_entry.AddMember(
"sim_state", 
static_cast<int>(actor->ar_state), j_doc.GetAllocator());
 
  501         j_entry.AddMember(
"physics_paused", actor->ar_physics_paused, j_doc.GetAllocator());
 
  502         j_entry.AddMember(
"player_actor", actor==
App::GetGameContext()->GetPlayerActor(), j_doc.GetAllocator());
 
  503         j_entry.AddMember(
"prev_player_actor", actor==
App::GetGameContext()->GetPrevPlayerActor(), j_doc.GetAllocator());
 
  505         if (actor->m_used_skin_entry)
 
  507             j_entry.AddMember(
"skin", rapidjson::StringRef(actor->m_used_skin_entry->dname.c_str()), j_doc.GetAllocator());
 
  510         if (actor->getWorkingTuneupDef())
 
  513             rapidjson::Value j_tuneup_document(rapidjson::kStringType);
 
  515             Ogre::DataStreamPtr datastream(
new Ogre::MemoryDataStream(tuneup_buf.
GetBuffer(), tuneup_buf.
GetCapacity()));
 
  516             TuneupUtil::ExportTuneup(datastream, actor->getWorkingTuneupDef());
 
  517             j_tuneup_document.SetString(datastream->getAsString().c_str(), j_doc.GetAllocator());
 
  518             j_entry.AddMember(
"tuneup_document", j_tuneup_document, j_doc.GetAllocator());
 
  521         j_entry.AddMember(
"section_config", rapidjson::StringRef(actor->m_section_config.c_str()), j_doc.GetAllocator());
 
  524         if (actor->ar_engine)
 
  526             j_entry.AddMember(
"engine_gear", actor->ar_engine->getGear(), j_doc.GetAllocator());
 
  527             j_entry.AddMember(
"engine_rpm", actor->ar_engine->getRPM(), j_doc.GetAllocator());
 
  528             j_entry.AddMember(
"engine_auto_mode", 
static_cast<int>(actor->ar_engine->getAutoMode()), j_doc.GetAllocator());
 
  529             j_entry.AddMember(
"engine_auto_select", actor->ar_engine->getAutoShift(), j_doc.GetAllocator());
 
  530             j_entry.AddMember(
"engine_is_running", actor->ar_engine->isRunning(), j_doc.GetAllocator());
 
  531             j_entry.AddMember(
"engine_has_contact", actor->ar_engine->hasContact(), j_doc.GetAllocator());
 
  532             j_entry.AddMember(
"engine_wheel_spin", actor->ar_wheel_spin, j_doc.GetAllocator());
 
  533             j_entry.AddMember(
"alb_mode", actor->alb_mode, j_doc.GetAllocator());
 
  534             j_entry.AddMember(
"tc_mode", actor->tc_mode, j_doc.GetAllocator());
 
  535             j_entry.AddMember(
"cc_mode", actor->cc_mode, j_doc.GetAllocator());
 
  536             j_entry.AddMember(
"cc_target_rpm", actor->cc_target_rpm, j_doc.GetAllocator());
 
  537             j_entry.AddMember(
"cc_target_speed", actor->cc_target_speed, j_doc.GetAllocator());
 
  540         j_entry.AddMember(
"hydro_dir_state", actor->ar_hydro_dir_state, j_doc.GetAllocator());
 
  541         j_entry.AddMember(
"hydro_aileron_state", actor->ar_hydro_aileron_state, j_doc.GetAllocator());
 
  542         j_entry.AddMember(
"hydro_rudder_state", actor->ar_hydro_rudder_state, j_doc.GetAllocator());
 
  543         j_entry.AddMember(
"hydro_elevator_state", actor->ar_hydro_elevator_state, j_doc.GetAllocator());
 
  544         j_entry.AddMember(
"parking_brake", actor->ar_parking_brake, j_doc.GetAllocator());
 
  545         j_entry.AddMember(
"trailer_parking_brake", actor->ar_trailer_parking_brake, j_doc.GetAllocator());
 
  546         j_entry.AddMember(
"avg_wheel_speed", actor->ar_avg_wheel_speed, j_doc.GetAllocator());
 
  547         j_entry.AddMember(
"wheel_speed", actor->ar_wheel_speed, j_doc.GetAllocator());
 
  548         j_entry.AddMember(
"wheel_spin", actor->ar_wheel_spin, j_doc.GetAllocator());
 
  550         j_entry.AddMember(
"custom_particles", actor->ar_cparticles_active, j_doc.GetAllocator());
 
  553         j_entry.AddMember(
"lights", (
int)actor->getHeadlightsVisible(), j_doc.GetAllocator());
 
  554         j_entry.AddMember(
"blink_type", (
int)actor->getBlinkType(), j_doc.GetAllocator());
 
  557         j_entry.AddMember(
"beacon_light", actor->getBeaconMode(), j_doc.GetAllocator());
 
  558         j_entry.AddMember(
"high_beams_on", actor->getHighBeamsVisible(), j_doc.GetAllocator());
 
  559         j_entry.AddMember(
"fog_lights_on", actor->getFogLightsVisible(), j_doc.GetAllocator());
 
  562         rapidjson::Value j_custom_lights(rapidjson::kArrayType);
 
  565             j_custom_lights.PushBack(actor->getCustomLightVisible(i), j_doc.GetAllocator());
 
  567         j_entry.AddMember(
"custom_lights", j_custom_lights, j_doc.GetAllocator());
 
  570         if (actor->m_buoyance)
 
  572             j_entry.AddMember(
"buoyance_sink", actor->m_buoyance->sink, j_doc.GetAllocator());
 
  576         rapidjson::Value j_aeroengines(rapidjson::kArrayType);
 
  577         for (
int i = 0; i < actor->ar_num_aeroengines; i++)
 
  579             rapidjson::Value j_aeroengine(rapidjson::kObjectType);
 
  580             j_aeroengine.AddMember(
"rpm", actor->ar_aeroengines[i]->getRPM(), j_doc.GetAllocator());
 
  581             j_aeroengine.AddMember(
"reverse", actor->ar_aeroengines[i]->getReverse(), j_doc.GetAllocator());
 
  582             j_aeroengine.AddMember(
"ignition", actor->ar_aeroengines[i]->getIgnition(), j_doc.GetAllocator());
 
  583             j_aeroengine.AddMember(
"throttle", actor->ar_aeroengines[i]->getThrottle(), j_doc.GetAllocator());
 
  584             j_aeroengines.PushBack(j_aeroengine, j_doc.GetAllocator());
 
  586         j_entry.AddMember(
"aeroengines", j_aeroengines, j_doc.GetAllocator());
 
  589         rapidjson::Value j_screwprops(rapidjson::kArrayType);
 
  590         for (
int i = 0; i < actor->ar_num_screwprops; i++)
 
  592             rapidjson::Value j_screwprop(rapidjson::kObjectType);
 
  593             j_screwprop.AddMember(
"rudder", actor->ar_screwprops[i]->getRudder(), j_doc.GetAllocator());
 
  594             j_screwprop.AddMember(
"throttle", actor->ar_screwprops[i]->getThrottle(), j_doc.GetAllocator());
 
  595             j_screwprops.PushBack(j_screwprop, j_doc.GetAllocator());
 
  597         j_entry.AddMember(
"screwprops", j_screwprops, j_doc.GetAllocator());
 
  600         rapidjson::Value j_rotators(rapidjson::kArrayType);
 
  601         for (
int i = 0; i < actor->ar_num_rotators; i++)
 
  603             j_rotators.PushBack(actor->ar_rotators[i].angle, j_doc.GetAllocator());
 
  605         j_entry.AddMember(
"rotators", j_rotators, j_doc.GetAllocator());
 
  608         rapidjson::Value j_wheels(rapidjson::kArrayType);
 
  609         for (
int i = 0; i < actor->ar_num_wheels; i++)
 
  611             j_wheels.PushBack(actor->ar_wheels[i].wh_is_detached, j_doc.GetAllocator());
 
  613         j_entry.AddMember(
"wheels", j_wheels, j_doc.GetAllocator());
 
  616         rapidjson::Value j_wheel_diffs(rapidjson::kArrayType);
 
  617         for (
int i = 0; i < actor->m_num_wheel_diffs; i++)
 
  619             j_wheel_diffs.PushBack(actor->m_wheel_diffs[i]->GetActiveDiffType(), j_doc.GetAllocator());
 
  621         j_entry.AddMember(
"wheel_diffs", j_wheel_diffs, j_doc.GetAllocator());
 
  624         rapidjson::Value j_axle_diffs(rapidjson::kArrayType);
 
  625         for (
int i = 0; i < actor->m_num_axle_diffs; i++)
 
  627             j_axle_diffs.PushBack(actor->m_axle_diffs[i]->GetActiveDiffType(), j_doc.GetAllocator());
 
  629         j_entry.AddMember(
"axle_diffs", j_axle_diffs, j_doc.GetAllocator());
 
  632         if (actor->m_transfer_case)
 
  634             rapidjson::Value j_transfer_case(rapidjson::kObjectType);
 
  635             j_transfer_case.AddMember(
"4WD", actor->m_transfer_case->tr_4wd_mode, j_doc.GetAllocator());
 
  636             j_transfer_case.AddMember(
"GearRatio", actor->m_transfer_case->tr_gear_ratios[0], j_doc.GetAllocator());
 
  637             j_entry.AddMember(
"transfercase", j_transfer_case, j_doc.GetAllocator());
 
  641         rapidjson::Value j_commands(rapidjson::kArrayType);
 
  644             rapidjson::Value j_command(rapidjson::kArrayType);
 
  645             j_command.PushBack(actor->ar_command_key[i].commandValue, j_doc.GetAllocator());
 
  646             j_command.PushBack(actor->ar_command_key[i].triggerInputValue, j_doc.GetAllocator());
 
  648             rapidjson::Value j_command_beams(rapidjson::kArrayType);
 
  649             for (
int j = 0; j < (int)actor->ar_command_key[i].beams.size(); j++)
 
  651                 rapidjson::Value j_cmb(rapidjson::kArrayType);
 
  652                 auto& beam = actor->ar_command_key[i].beams[j];
 
  653                 j_cmb.PushBack(beam.cmb_state->auto_moving_mode, j_doc.GetAllocator());
 
  654                 j_cmb.PushBack(beam.cmb_state->pressed_center_mode, j_doc.GetAllocator());
 
  655                 j_command_beams.PushBack(j_cmb, j_doc.GetAllocator());
 
  657             j_command.PushBack(j_command_beams, j_doc.GetAllocator());
 
  659             j_commands.PushBack(j_command, j_doc.GetAllocator());
 
  661         j_entry.AddMember(
"commands", j_commands, j_doc.GetAllocator());
 
  664         rapidjson::Value j_hooks(rapidjson::kArrayType);
 
  665         for (
const auto& h : actor->ar_hooks)
 
  667             rapidjson::Value j_hook(rapidjson::kObjectType);
 
  668             int lock_node = h.hk_lock_node ? h.hk_lock_node->pos : -1;
 
  669             int locked_actor = h.hk_locked_actor ? vector_index_lookup[h.hk_locked_actor->ar_vector_index] : -1;
 
  670             j_hook.AddMember(
"locked", h.hk_locked, j_doc.GetAllocator());
 
  671             j_hook.AddMember(
"lock_node", lock_node, j_doc.GetAllocator());
 
  672             j_hook.AddMember(
"locked_actor", locked_actor, j_doc.GetAllocator());
 
  673             j_hooks.PushBack(j_hook, j_doc.GetAllocator());
 
  675         j_entry.AddMember(
"hooks", j_hooks, j_doc.GetAllocator());
 
  678         rapidjson::Value j_ropes(rapidjson::kArrayType);
 
  679         for (
const auto& r : actor->ar_ropes)
 
  681             rapidjson::Value j_rope(rapidjson::kObjectType);
 
  682             int locked_ropable = r.rp_locked_ropable ? r.rp_locked_ropable->pos : -1;
 
  683             int locked_actor = r.rp_locked_actor ? vector_index_lookup[r.rp_locked_actor->ar_vector_index] : -1;
 
  684             j_rope.AddMember(
"locked", r.rp_locked, j_doc.GetAllocator());
 
  685             j_rope.AddMember(
"locked_ropable", locked_ropable, j_doc.GetAllocator());
 
  686             j_rope.AddMember(
"locked_actor", locked_actor, j_doc.GetAllocator());
 
  687             j_ropes.PushBack(j_rope, j_doc.GetAllocator());
 
  689         j_entry.AddMember(
"ropes", j_ropes, j_doc.GetAllocator());
 
  692         rapidjson::Value j_ties(rapidjson::kArrayType);
 
  693         for (
const auto& t : actor->ar_ties)
 
  695             rapidjson::Value j_tie(rapidjson::kObjectType);
 
  696             int locked_ropable = t.ti_locked_ropable ? t.ti_locked_ropable->pos : -1;
 
  697             int locked_actor = t.ti_locked_actor ? vector_index_lookup[t.ti_locked_actor->ar_vector_index] : -1;
 
  698             j_tie.AddMember(
"tied", t.ti_tied, j_doc.GetAllocator());
 
  699             j_tie.AddMember(
"tying", t.ti_tying, j_doc.GetAllocator());
 
  700             j_tie.AddMember(
"locked_ropable", locked_ropable, j_doc.GetAllocator());
 
  701             j_tie.AddMember(
"locked_actor", locked_actor, j_doc.GetAllocator());
 
  702             j_ties.PushBack(j_tie, j_doc.GetAllocator());
 
  704         j_entry.AddMember(
"ties", j_ties, j_doc.GetAllocator());
 
  707         rapidjson::Value j_ropables(rapidjson::kArrayType);
 
  708         for (
const auto& r : actor->ar_ropables)
 
  710             rapidjson::Value j_ropable(rapidjson::kObjectType);
 
  711             j_ropable.AddMember(
"attached_ties", r.attached_ties, j_doc.GetAllocator());
 
  712             j_ropable.AddMember(
"attached_ropes", r.attached_ropes, j_doc.GetAllocator());
 
  713             j_ropables.PushBack(j_ropable, j_doc.GetAllocator());
 
  715         j_entry.AddMember(
"ropables", j_ropables, j_doc.GetAllocator());
 
  717         j_entry.AddMember(
"slidenodes_locked", actor->m_slidenodes_locked, j_doc.GetAllocator());
 
  720         rapidjson::Value j_nodes(rapidjson::kArrayType);
 
  721         for (
int i = 0; i < actor->ar_num_nodes; i++)
 
  723             rapidjson::Value j_node(rapidjson::kArrayType);
 
  726             j_node.PushBack(actor->ar_nodes[i].AbsPosition.x, j_doc.GetAllocator());
 
  727             j_node.PushBack(actor->ar_nodes[i].AbsPosition.y, j_doc.GetAllocator());
 
  728             j_node.PushBack(actor->ar_nodes[i].AbsPosition.z, j_doc.GetAllocator());
 
  731             j_node.PushBack(actor->ar_nodes[i].Velocity.x, j_doc.GetAllocator());
 
  732             j_node.PushBack(actor->ar_nodes[i].Velocity.y, j_doc.GetAllocator());
 
  733             j_node.PushBack(actor->ar_nodes[i].Velocity.z, j_doc.GetAllocator());
 
  736             j_node.PushBack(actor->ar_initial_node_positions[i].x, j_doc.GetAllocator());
 
  737             j_node.PushBack(actor->ar_initial_node_positions[i].y, j_doc.GetAllocator());
 
  738             j_node.PushBack(actor->ar_initial_node_positions[i].z, j_doc.GetAllocator());
 
  740             j_nodes.PushBack(j_node, j_doc.GetAllocator());
 
  742         j_entry.AddMember(
"nodes", j_nodes, j_doc.GetAllocator());
 
  745         rapidjson::Value j_beams(rapidjson::kArrayType);
 
  746         for (
int i = 0; i < actor->ar_num_beams; i++)
 
  748             rapidjson::Value j_beam(rapidjson::kArrayType);
 
  750             j_beam.PushBack(actor->ar_beams[i].maxposstress, j_doc.GetAllocator());
 
  751             j_beam.PushBack(actor->ar_beams[i].maxnegstress, j_doc.GetAllocator());
 
  752             j_beam.PushBack(actor->ar_beams[i].minmaxposnegstress, j_doc.GetAllocator());
 
  753             j_beam.PushBack(actor->ar_beams[i].strength, j_doc.GetAllocator());
 
  754             j_beam.PushBack(actor->ar_beams[i].L, j_doc.GetAllocator());
 
  755             j_beam.PushBack(actor->ar_beams[i].bm_broken, j_doc.GetAllocator());
 
  756             j_beam.PushBack(actor->ar_beams[i].bm_disabled, j_doc.GetAllocator());
 
  757             j_beam.PushBack(actor->ar_beams[i].bm_inter_actor, j_doc.GetAllocator());
 
  759             j_beam.PushBack(locked_actor ? vector_index_lookup[locked_actor->
ar_vector_index] : -1, j_doc.GetAllocator());
 
  761             j_beams.PushBack(j_beam, j_doc.GetAllocator());
 
  763         j_entry.AddMember(
"beams", j_beams, j_doc.GetAllocator());
 
  765         j_actors.PushBack(j_entry, j_doc.GetAllocator());
 
  767     j_doc.AddMember(
"actors", j_actors, j_doc.GetAllocator());
 
  774             Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR, 
_L(
"Error while saving scene"));
 
  778     if (filename != 
"autosave.sav")
 
  781             Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, 
_L(
"Scene saved"));
 
  787 void ActorManager::RestoreSavedState(
ActorPtr actor, rapidjson::Value 
const& j_entry)
 
  793     if (j_entry[
"player_actor"].GetBool())
 
  797     else if (j_entry[
"prev_player_actor"].GetBool())
 
  804         int gear = j_entry[
"engine_gear"].GetInt();
 
  805         float rpm = j_entry[
"engine_rpm"].GetFloat();
 
  806         int automode = j_entry[
"engine_auto_mode"].GetInt();
 
  807         int autoselect = j_entry[
"engine_auto_select"].GetInt();
 
  808         bool running = j_entry[
"engine_is_running"].GetBool();
 
  809         bool contact = j_entry[
"engine_has_contact"].GetBool();
 
  819         actor->
alb_mode = j_entry[
"alb_mode"].GetBool();
 
  820         actor->
tc_mode = j_entry[
"tc_mode"].GetBool();
 
  821         actor->
cc_mode = j_entry[
"cc_mode"].GetBool();
 
  846     actor->
setBeaconMode(j_entry.HasMember(
"beacon_light") ? j_entry[
"beacon_light"].GetBool() : j_entry[
"pp_beacon_light"].GetBool());
 
  847     actor->
setHighBeamsVisible(j_entry.HasMember(
"high_beams_on") ? j_entry[
"high_beams_on"].GetBool() : 
false); 
 
  848     actor->
setFogLightsVisible(j_entry.HasMember(
"fog_lights_on") ? j_entry[
"fog_lights_on"].GetBool() : 
false); 
 
  851     if (j_entry.HasMember(
"custom_lights"))
 
  853         auto flares = j_entry[
"custom_lights"].GetArray();
 
  862         actor->
m_buoyance->sink = j_entry[
"buoyance_sink"].GetBool();
 
  865     auto aeroengines = j_entry[
"aeroengines"].GetArray();
 
  874     auto screwprops = j_entry[
"screwprops"].GetArray();
 
  923     auto commands = j_entry[
"commands"].GetArray();
 
  927         command_key.commandValue = commands[i][0].GetFloat();
 
  928         command_key.triggerInputValue = commands[i][1].GetFloat();
 
  929         auto command_beams = commands[i][2].GetArray();
 
  930         for (
int j = 0; j < (int)command_key.beams.size(); j++)
 
  932             command_key.beams[j].cmb_state->auto_moving_mode = command_beams[j][0].GetInt();
 
  933             command_key.beams[j].cmb_state->pressed_center_mode = command_beams[j][1].GetBool();
 
  937     auto nodes = j_entry[
"nodes"].GetArray();
 
  938     for (rapidjson::SizeType i = 0; i < 
nodes.Size(); i++)
 
  940         auto data = 
nodes[i].GetArray();
 
  941         actor->
ar_nodes[i].
AbsPosition      = Vector3(data[0].GetFloat(), data[1].GetFloat(), data[2].GetFloat());
 
  943         actor->
ar_nodes[i].
Velocity         = Vector3(data[3].GetFloat(), data[4].GetFloat(), data[5].GetFloat());
 
  947     std::vector<ActorPtr> actors = this->GetLocalActors();
 
  949     auto beams = j_entry[
"beams"].GetArray();
 
  950     for (rapidjson::SizeType i = 0; i < beams.Size(); i++)
 
  952         auto data = beams[i].GetArray();
 
  957         actor->
ar_beams[i].
L                  = data[4].GetFloat();
 
  961         int locked_actor                      = data[8].GetInt();
 
  962         if (locked_actor != -1 &&
 
  963             locked_actor < (
int)actors.size() &&
 
  964             actors[locked_actor] != 
nullptr)
 
  970     auto hooks = j_entry[
"hooks"].GetArray();
 
  971     for (
int i = 0; i < actor->
ar_hooks.size(); i++)
 
  973         int lock_node = hooks[i][
"lock_node"].GetInt();
 
  974         int locked_actor = hooks[i][
"locked_actor"].GetInt();
 
  975         if (lock_node != -1 &&
 
  976             locked_actor != -1 &&
 
  977             locked_actor < (
int)actors.size() &&
 
  978             actors[locked_actor] != 
nullptr)
 
  981             actor->
ar_hooks[i].hk_locked_actor = actors[locked_actor];
 
  982             actor->
ar_hooks[i].hk_lock_node = &actors[locked_actor]->ar_nodes[lock_node];
 
  983             if (actor->
ar_hooks[i].hk_beam->bm_inter_actor)
 
  990     auto ropes = j_entry[
"ropes"].GetArray();
 
  991     for (
int i = 0; i < actor->
ar_ropes.size(); i++)
 
  993         int ropable = ropes[i][
"locked_ropable"].GetInt();
 
  994         int locked_actor = ropes[i][
"locked_actor"].GetInt();
 
  996             locked_actor != -1 &&
 
  997             locked_actor < (
int)actors.size() &&
 
  998             actors[locked_actor] != 
nullptr)
 
 1000             actor->
ar_ropes[i].rp_locked = ropes[i][
"locked"].GetInt();
 
 1001             actor->
ar_ropes[i].rp_locked_actor = actors[locked_actor];
 
 1002             actor->
ar_ropes[i].rp_locked_ropable = &actors[locked_actor]->ar_ropables[ropable];
 
 1006     auto ties = j_entry[
"ties"].GetArray();
 
 1007     for (
int i = 0; i < actor->
ar_ties.size(); i++)
 
 1009         int ropable = ties[i][
"locked_ropable"].GetInt();
 
 1010         int locked_actor = ties[i][
"locked_actor"].GetInt();
 
 1011         if (ropable != -1 &&
 
 1012             locked_actor != -1 &&
 
 1013             locked_actor < (
int)actors.size() &&
 
 1014             actors[locked_actor] != 
nullptr)
 
 1016             actor->
ar_ties[i].ti_tied  = ties[i][
"tied"].GetBool();
 
 1017             actor->
ar_ties[i].ti_tying = ties[i][
"tying"].GetBool();
 
 1018             actor->
ar_ties[i].ti_locked_actor = actors[locked_actor];
 
 1019             actor->
ar_ties[i].ti_locked_ropable = &actors[locked_actor]->ar_ropables[ropable];
 
 1020             if (actor->
ar_ties[i].ti_beam->bm_inter_actor)
 
 1022                 actor->
ar_ties[i].ti_beam->p2 = actor->
ar_ties[i].ti_locked_ropable->node;
 
 1027     auto ropables = j_entry[
"ropables"].GetArray();
 
 1028     for (
int i = 0; i < actor->
ar_ropables.size(); i++)
 
 1030         actor->
ar_ropables[i].attached_ties  = ropables[i][
"attached_ties"].GetInt();
 
 1031         actor->
ar_ropables[i].attached_ropes = ropables[i][
"attached_ropes"].GetInt();