diff options
Diffstat (limited to 'src/map/script-startup.cpp')
-rw-r--r-- | src/map/script-startup.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/src/map/script-startup.cpp b/src/map/script-startup.cpp new file mode 100644 index 0000000..1aa63aa --- /dev/null +++ b/src/map/script-startup.cpp @@ -0,0 +1,265 @@ +#include "script-startup-internal.hpp" +// script-startup.cpp - EAthena script frontend, engine, and library. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011 Chuck Miller +// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> +// Copyright © 2013 wushin +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include "../strings/zstring.hpp" + +#include "../generic/db.hpp" +#include "../generic/intern-pool.hpp" + +#include "../io/cxxstdio.hpp" +#include "../io/read.hpp" +#include "../io/lock.hpp" + +#include "../net/timer.hpp" + +#include "../mmo/extract.hpp" + +#include "map.hpp" +#include "script-parse-internal.hpp" +#include "script-persist.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +DMap<SIR, int> mapreg_db; +Map<SIR, RString> mapregstr_db; +int mapreg_dirty = -1; +AString mapreg_txt = "save/mapreg.txt"_s; +constexpr std::chrono::milliseconds MAPREG_AUTOSAVE_INTERVAL = 10_s; + +bool read_constdb(ZString filename) +{ + io::ReadFile in(filename); + if (!in.is_open()) + { + PRINTF("can't read %s\n"_fmt, filename); + return false; + } + + bool rv = true; + AString line_; + while (in.getline(line_)) + { + // is_comment only works for whole-line comments + // that could change once the Z dependency is dropped ... + LString comment = "//"_s; + XString line = line_.xislice_h(std::search(line_.begin(), line_.end(), comment.begin(), comment.end())).rstrip(); + if (!line) + continue; + // "%m[A-Za-z0-9_] %i %i" + + // TODO promote either qsplit() or asplit() + auto _it = std::find(line.begin(), line.end(), ' '); + auto name = line.xislice_h(_it); + auto _rest = line.xislice_t(_it); + while (_rest.startswith(' ')) + _rest = _rest.xslice_t(1); + auto _it2 = std::find(_rest.begin(), _rest.end(), ' '); + auto val_ = _rest.xislice_h(_it2); + auto type_ = _rest.xislice_t(_it2); + while (type_.startswith(' ')) + type_ = type_.xslice_t(1); + // yes, the above actually DTRT even for underlength input + + int val; + int type = 0; + // Note for future archeaologists: this code is indented correctly + if (std::find_if_not(name.begin(), name.end(), + [](char c) + { + return ('0' <= c && c <= '9') + || ('A' <= c && c <= 'Z') + || ('a' <= c && c <= 'z') + || (c == '_'); + }) != name.end() + || !extract(val_, &val) + || (!extract(type_, &type) && type_)) + { + PRINTF("Bad const line: %s\n"_fmt, line_); + rv = false; + continue; + } + str_data_t *n = add_strp(name); + n->type = type ? StringCode::PARAM : StringCode::INT; + n->val = val; + } + return rv; +} + +/*========================================== + * マップ変数の変更 + *------------------------------------------ + */ +void mapreg_setreg(SIR reg, int val) +{ + mapreg_db.put(reg, val); + + mapreg_dirty = 1; +} + +/*========================================== + * 文字列型マップ変数の変更 + *------------------------------------------ + */ +void mapreg_setregstr(SIR reg, XString str) +{ + if (!str) + mapregstr_db.erase(reg); + else + mapregstr_db.insert(reg, str); + + mapreg_dirty = 1; +} + +/*========================================== + * 永続的マップ変数の読み込み + *------------------------------------------ + */ +static +void script_load_mapreg(void) +{ + io::ReadFile in(mapreg_txt); + + if (!in.is_open()) + return; + + AString line; + while (in.getline(line)) + { + XString buf1, buf2; + int index = 0; + if (extract(line, + record<'\t'>( + record<','>(&buf1, &index), + &buf2)) + || extract(line, + record<'\t'>( + record<','>(&buf1), + &buf2))) + { + int s = variable_names.intern(buf1); + SIR key = SIR::from(s, index); + if (buf1.back() == '$') + { + mapregstr_db.insert(key, buf2); + } + else + { + int v; + if (!extract(buf2, &v)) + goto borken; + mapreg_db.put(key, v); + } + } + else + { + borken: + PRINTF("%s: %s broken data !\n"_fmt, mapreg_txt, AString(buf1)); + continue; + } + } + mapreg_dirty = 0; +} + +/*========================================== + * 永続的マップ変数の書き込み + *------------------------------------------ + */ +static +void script_save_mapreg_intsub(SIR key, int data, io::WriteFile& fp) +{ + int num = key.base(), i = key.index(); + ZString name = variable_names.outtern(num); + if (name[1] != '@') + { + if (i == 0) + FPRINTF(fp, "%s\t%d\n"_fmt, name, data); + else + FPRINTF(fp, "%s,%d\t%d\n"_fmt, name, i, data); + } +} + +static +void script_save_mapreg_strsub(SIR key, ZString data, io::WriteFile& fp) +{ + int num = key.base(), i = key.index(); + ZString name = variable_names.outtern(num); + if (name[1] != '@') + { + if (i == 0) + FPRINTF(fp, "%s\t%s\n"_fmt, name, data); + else + FPRINTF(fp, "%s,%d\t%s\n"_fmt, name, i, data); + } +} + +static +void script_save_mapreg(void) +{ + io::WriteLock fp(mapreg_txt); + if (!fp.is_open()) + return; + for (auto& pair : mapreg_db) + script_save_mapreg_intsub(pair.first, pair.second, fp); + for (auto& pair : mapregstr_db) + script_save_mapreg_strsub(pair.first, pair.second, fp); + mapreg_dirty = 0; +} + +static +void script_autosave_mapreg(TimerData *, tick_t) +{ + if (mapreg_dirty) + script_save_mapreg(); +} + +void do_final_script(void) +{ + if (mapreg_dirty >= 0) + script_save_mapreg(); + + mapreg_db.clear(); + mapregstr_db.clear(); + scriptlabel_db.clear(); + userfunc_db.clear(); + + str_datam.clear(); +} + +/*========================================== + * 初期化 + *------------------------------------------ + */ +void do_init_script(void) +{ + script_load_mapreg(); + + Timer(gettick() + MAPREG_AUTOSAVE_INTERVAL, + script_autosave_mapreg, + MAPREG_AUTOSAVE_INTERVAL + ).detach(); +} +} // namespace tmwa |