-/*!
+/*!
* @file save.c
* @brief セーブファイル書き込み処理 / Purpose: interact with savefiles
* @date 2014/07/12
#include "view/display-messages.h"
#include "world/world.h"
#include <algorithm>
+#include <sstream>
+#include <string>
/*!
* @brief セーブデータの書き込み /
wr_u32b(tmp32u);
for (int i = tmp32u - 1; i >= 0; i--) {
- wr_string(message_str(i));
+ wr_string(*message_str(i));
}
uint16_t tmp16u = static_cast<uint16_t>(monraces_info.size());
tmp8u = MAX_RANDOM_QUEST - MIN_RANDOM_QUEST;
wr_byte(tmp8u);
- for (const auto &[q_idx, q_ref] : quest_list) {
+ for (const auto &[q_idx, quest] : quest_list) {
wr_s16b(enum2i(q_idx));
- wr_s16b(enum2i(q_ref.status));
- wr_s16b((int16_t)q_ref.level);
- wr_byte((byte)q_ref.complev);
- wr_u32b(q_ref.comptime);
-
- auto is_quest_running = q_ref.status == QuestStatusType::TAKEN;
- is_quest_running |= q_ref.status == QuestStatusType::COMPLETED;
- is_quest_running |= !quest_type::is_fixed(q_idx);
+ wr_s16b(enum2i(quest.status));
+ wr_s16b((int16_t)quest.level);
+ wr_byte((byte)quest.complev);
+ wr_u32b(quest.comptime);
+
+ auto is_quest_running = quest.status == QuestStatusType::TAKEN;
+ is_quest_running |= quest.status == QuestStatusType::COMPLETED;
+ is_quest_running |= !QuestType::is_fixed(q_idx);
if (!is_quest_running) {
continue;
}
- wr_s16b((int16_t)q_ref.cur_num);
- wr_s16b((int16_t)q_ref.max_num);
- wr_s16b(enum2i(q_ref.type));
- wr_s16b(enum2i(q_ref.r_idx));
- wr_s16b(enum2i(q_ref.reward_artifact_idx));
- wr_byte((byte)q_ref.flags);
- wr_byte((byte)q_ref.dungeon);
+ wr_s16b((int16_t)quest.cur_num);
+ wr_s16b((int16_t)quest.max_num);
+ wr_s16b(enum2i(quest.type));
+ wr_s16b(enum2i(quest.r_idx));
+ wr_s16b(enum2i(quest.reward_artifact_idx));
+ wr_byte((byte)quest.flags);
+ wr_byte((byte)quest.dungeon);
}
wr_s32b(player_ptr->wilderness_x);
auto max_a_num = enum2i(artifacts_info.rbegin()->first);
tmp16u = max_a_num + 1;
wr_u16b(tmp16u);
- ArtifactType dummy;
for (auto i = 0U; i < tmp16u; i++) {
const auto a_idx = i2enum<FixedArtifactId>(i);
- const auto &artifact = (i > 0) ? artifacts_info.at(a_idx) : dummy;
+ const auto &artifact = ArtifactsInfo::get_instance().get_artifact(a_idx);
wr_bool(artifact.is_generated);
wr_s16b(artifact.floor_id);
}
for (int i = 0; i < INVEN_TOTAL; i++) {
auto *o_ptr = &player_ptr->inventory_list[i];
- if (!o_ptr->bi_id) {
+ if (!o_ptr->is_valid()) {
continue;
}
tmp16u = MAX_STORES;
wr_u16b(tmp16u);
for (size_t i = 1; i < towns_info.size(); i++) {
- for (auto j = 0; j < MAX_STORES; j++) {
- wr_store(&towns_info[i].store[j]);
+ for (auto sst : STORE_SALE_TYPE_LIST) {
+ wr_store(&towns_info[i].stores[sst]);
}
}
}
/*!
- * @brief セーブデータ書き込みのサブルーチン /
- * Medium level player saver
+ * @brief セーブデータ書き込みのサブルーチン
* @param player_ptr プレイヤーへの参照ポインタ
- * @return 成功すればtrue
- * @details
- * Angband 2.8.0 will use "fd" instead of "fff" if possible
+ * @param path セーブデータのフルパス
+ * @param type セーブ後の処理種別
+ * @return セーブの成功可否
*/
-static bool save_player_aux(PlayerType *player_ptr, char *name, SaveType type)
+static bool save_player_aux(PlayerType *player_ptr, const std::filesystem::path &path, SaveType type)
{
- safe_setuid_grab(player_ptr);
- int file_permission = 0644;
- int fd = fd_make(name, file_permission);
+ safe_setuid_grab();
+ auto fd = fd_make(path);
safe_setuid_drop();
bool is_save_successful = false;
saving_savefile = nullptr;
if (fd >= 0) {
(void)fd_close(fd);
- safe_setuid_grab(player_ptr);
- saving_savefile = angband_fopen(name, FileOpenMode::WRITE, true);
+ safe_setuid_grab();
+ saving_savefile = angband_fopen(path, FileOpenMode::WRITE, true,
+ FileOpenType::SAVE);
safe_setuid_drop();
if (saving_savefile) {
if (wr_savefile_new(player_ptr, type)) {
}
}
- safe_setuid_grab(player_ptr);
+ safe_setuid_grab();
if (!is_save_successful) {
- (void)fd_kill(name);
+ (void)fd_kill(path);
}
safe_setuid_drop();
}
/*!
- * @brief セーブデータ書き込みのメインルーチン /
- * Attempt to save the player in a savefile
+ * @brief セーブデータ書き込みのメインルーチン
* @param player_ptr プレイヤーへの参照ポインタ
* @return 成功すればtrue
+ * @details 以下の順番で書き込みを実行する.
+ * 1. hoge.new にセーブデータを書き込む
+ * 2. hoge をhoge.old にリネームする
+ * 3. hoge.new をhoge にリネームする
+ * 4. hoge.old を削除する
*/
bool save_player(PlayerType *player_ptr, SaveType type)
{
- char safe[1024];
- strcpy(safe, savefile);
- strcat(safe, ".new");
- safe_setuid_grab(player_ptr);
- fd_kill(safe);
+ std::stringstream ss_new;
+ ss_new << savefile.string() << ".new";
+ auto savefile_new = ss_new.str();
+ safe_setuid_grab();
+ fd_kill(savefile_new);
+ if (type == SaveType::DEBUG) {
+ const auto debug_save_dir = std::filesystem::path(debug_savefile).remove_filename();
+ std::error_code ec;
+ std::filesystem::create_directory(debug_save_dir, ec);
+ }
safe_setuid_drop();
update_playtime();
bool result = false;
- if (save_player_aux(player_ptr, safe, type)) {
- char temp[1024];
- char filename[1024];
- strcpy(temp, savefile);
- strcat(temp, ".old");
- safe_setuid_grab(player_ptr);
- fd_kill(temp);
-
- if (type == SaveType::DEBUG) {
- strcpy(filename, debug_savefile);
- }
- if (type != SaveType::DEBUG) {
- strcpy(filename, savefile);
- }
-
- fd_move(filename, temp);
- fd_move(safe, filename);
- fd_kill(temp);
+ if (save_player_aux(player_ptr, savefile_new.data(), type)) {
+ std::stringstream ss_old;
+ ss_old << savefile.string() << ".old";
+ auto savefile_old = ss_old.str();
+ safe_setuid_grab();
+ fd_kill(savefile_old);
+ const auto &path = type == SaveType::DEBUG ? debug_savefile : savefile;
+ fd_move(path, savefile_old);
+ fd_move(savefile_new, path);
+ fd_kill(savefile_old);
safe_setuid_drop();
w_ptr->character_loaded = true;
result = true;