summaryrefslogtreecommitdiff
path: root/src/map/script-startup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/script-startup.cpp')
-rw-r--r--src/map/script-startup.cpp265
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