Skip to content

Instantly share code, notes, and snippets.

@tehsausage
Created May 18, 2022 16:15
Show Gist options
  • Save tehsausage/73ad61f9cdd418bc0c81698ff88dcc02 to your computer and use it in GitHub Desktop.
Save tehsausage/73ad61f9cdd418bc0c81698ff88dcc02 to your computer and use it in GitHub Desktop.
diff --git a/config/files.ini b/config/files.ini
index 5ab9b96..e98e9d8 100644
--- a/config/files.ini
+++ b/config/files.ini
@@ -6,6 +6,7 @@
## EIF, ENF, ESF, ECF (string)
# pub file locations
+# "001" will be replaced with the appropriate file number automatically
EIF = ./data/pub/dat001.eif
ENF = ./data/pub/dtn001.enf
ESF = ./data/pub/dsl001.esf
@@ -13,7 +14,7 @@ ECF = ./data/pub/dat001.ecf
## AutoSplitPubFiles (bool)
# Automatically split large pub files in to multiple smaller files
-# This is required for more than 900 items to work
+# This is required to have more than 900 items when using older editors
AutoSplitPubFiles = yes
## NewsFile (string)
diff --git a/src/eoclient.cpp b/src/eoclient.cpp
index 8e12933..1e185c4 100644
--- a/src/eoclient.cpp
+++ b/src/eoclient.cpp
@@ -293,11 +293,6 @@ void EOClient::Execute(const std::string &data)
bool EOClient::Upload(FileType type, int id, InitReply init_reply)
{
- bool auto_split = server()->world->config["AutoSplitPubFiles"];
-
- if (type != FILE_MAP && id != 1 && !auto_split)
- return false;
-
this->upload_file_id = id;
std::string filename;
@@ -306,6 +301,29 @@ bool EOClient::Upload(FileType type, int id, InitReply init_reply)
std::vector<std::size_t>* file_splits = nullptr;
+ auto load_file_splits = [&](auto pub)
+ {
+ if (pub.files.empty())
+ return false;
+
+ Pub_File& first_file = pub.files[0];
+
+ if (pub.files.size() == 1 && first_file.splits.size() > 2)
+ {
+ filename = first_file.filename;
+ file_splits = &first_file.splits;
+ }
+ else
+ {
+ if (id - 1 < 0 || id - 1 > pub.files.size())
+ return false;
+
+ filename = pub.files[id - 1].filename;
+ }
+
+ return true;
+ };
+
if (type == FILE_MAP)
{
char mapbuf[7];
@@ -314,26 +332,26 @@ bool EOClient::Upload(FileType type, int id, InitReply init_reply)
}
else if (type == FILE_ITEM)
{
- file_splits = &this->server()->world->eif->file_splits;
- filename = this->server()->world->config["EIF"].GetString();
+ if (!load_file_splits(*this->server()->world->eif))
+ return false;
}
else if (type == FILE_NPC)
{
- file_splits = &this->server()->world->enf->file_splits;
- filename = this->server()->world->config["ENF"].GetString();
+ if (!load_file_splits(*this->server()->world->enf))
+ return false;
}
else if (type == FILE_SPELL)
{
- file_splits = &this->server()->world->esf->file_splits;
- filename = this->server()->world->config["ESF"].GetString();
+ if (!load_file_splits(*this->server()->world->esf))
+ return false;
}
else if (type == FILE_CLASS)
{
- file_splits = &this->server()->world->ecf->file_splits;
- filename = this->server()->world->config["ECF"].GetString();
+ if (!load_file_splits(*this->server()->world->ecf))
+ return false;
}
- if (auto_split && file_splits)
+ if (file_splits)
{
if (id < 1 || id >= file_splits->size())
return false;
@@ -349,9 +367,14 @@ bool EOClient::Upload(FileType type, const std::string &filename, std::size_t fi
{
using std::swap;
+ printf("Sending file %s (start=%d, length=%d)\n", filename.c_str(), (int)file_start, (int)file_length);
+
if (this->upload_fh)
throw std::runtime_error("Already uploading file");
+ if (file_length > 63992)
+ throw std::runtime_error("File is too large to send");
+
this->upload_fh = std::fopen(filename.c_str(), "rb");
if (!this->upload_fh)
diff --git a/src/eodata.cpp b/src/eodata.cpp
index cc4642c..84f90e1 100644
--- a/src/eodata.cpp
+++ b/src/eodata.cpp
@@ -8,12 +8,35 @@
#include "console.hpp"
#include "packet.hpp"
-#include <cstdio>
#include <cstdlib>
+#include <cstring>
#include <string>
+#include <type_traits>
static const char *eodata_safe_fail_filename;
+std::string convert_pub_filename(const std::string& s)
+{
+ std::string result;
+
+ for (const char* p = &s[0]; *p != '\0'; ++p)
+ {
+ if ((p - &s[0]) < s.size() - 3 && p[0] == '0' && p[1] == '0' && p[2] == '1')
+ {
+ result += "%03d";
+ p += 2;
+ continue;
+ }
+
+ if (*p == '%')
+ result += '%';
+
+ result += *p;
+ }
+
+ return result;
+}
+
static void eodata_safe_fail(int line)
{
Console::Err("Invalid file / failed read/seek: %s -- %i", eodata_safe_fail_filename, line);
@@ -23,243 +46,243 @@ static void eodata_safe_fail(int line)
#define SAFE_SEEK(fh, offset, from) if (std::fseek(fh, offset, from) != 0) { std::fclose(fh); eodata_safe_fail(__LINE__); }
#define SAFE_READ(buf, size, count, fh) if (std::fread(buf, size, count, fh) != static_cast<std::size_t>(count)) { std::fclose(fh); eodata_safe_fail(__LINE__); }
-void EIF::Read(const std::string& filename)
+void pub_read_record(EIF_Data& newdata, char* buf)
{
- this->data.clear();
-
- std::FILE *fh = std::fopen(filename.c_str(), "rb");
- eodata_safe_fail_filename = filename.c_str();
-
- if (!fh)
+ newdata.graphic = PacketProcessor::Number(buf[0], buf[1]);
+ newdata.type = static_cast<EIF::Type>(PacketProcessor::Number(buf[2]));
+ newdata.subtype = static_cast<EIF::SubType>(PacketProcessor::Number(buf[3]));
+ // Ranged gun hack
+ if (newdata.id == 365 && newdata.name == "Gun")
{
- Console::Err("Could not load file: %s", filename.c_str());
- std::exit(1);
+ newdata.subtype = EIF::Ranged;
}
+ // / Ranged gun hack
+ newdata.special = static_cast<EIF::Special>(PacketProcessor::Number(buf[4]));
+ newdata.hp = PacketProcessor::Number(buf[5], buf[6]);
+ newdata.tp = PacketProcessor::Number(buf[7], buf[8]);
+ newdata.mindam = PacketProcessor::Number(buf[9], buf[10]);
+ newdata.maxdam = PacketProcessor::Number(buf[11], buf[12]);
+ newdata.accuracy = PacketProcessor::Number(buf[13], buf[14]);
+ newdata.evade = PacketProcessor::Number(buf[15], buf[16]);
+ newdata.armor = PacketProcessor::Number(buf[17], buf[18]);
+
+ newdata.str = PacketProcessor::Number(buf[20]);
+ newdata.intl = PacketProcessor::Number(buf[21]);
+ newdata.wis = PacketProcessor::Number(buf[22]);
+ newdata.agi = PacketProcessor::Number(buf[23]);
+ newdata.con = PacketProcessor::Number(buf[24]);
+ newdata.cha = PacketProcessor::Number(buf[25]);
+
+ newdata.light = PacketProcessor::Number(buf[26]);
+ newdata.dark = PacketProcessor::Number(buf[27]);
+ newdata.earth = PacketProcessor::Number(buf[28]);
+ newdata.air = PacketProcessor::Number(buf[29]);
+ newdata.water = PacketProcessor::Number(buf[30]);
+ newdata.fire = PacketProcessor::Number(buf[31]);
+
+ newdata.scrollmap = PacketProcessor::Number(buf[32], buf[33], buf[34]);
+ newdata.scrollx = PacketProcessor::Number(buf[35]);
+ newdata.scrolly = PacketProcessor::Number(buf[36]);
+
+ newdata.levelreq = PacketProcessor::Number(buf[37], buf[38]);
+ newdata.classreq = PacketProcessor::Number(buf[39], buf[40]);
+
+ newdata.strreq = PacketProcessor::Number(buf[41], buf[42]);
+ newdata.intreq = PacketProcessor::Number(buf[43], buf[44]);
+ newdata.wisreq = PacketProcessor::Number(buf[45], buf[46]);
+ newdata.agireq = PacketProcessor::Number(buf[47], buf[48]);
+ newdata.conreq = PacketProcessor::Number(buf[49], buf[50]);
+ newdata.chareq = PacketProcessor::Number(buf[51], buf[52]);
+
+ newdata.weight = PacketProcessor::Number(buf[55]);
+
+ newdata.size = static_cast<EIF::Size>(PacketProcessor::Number(buf[57]));
+}
- SAFE_SEEK(fh, 3, SEEK_SET);
- SAFE_READ(this->rid.data(), sizeof(char), 4, fh);
- SAFE_READ(this->len.data(), sizeof(char), 2, fh);
- int numobj = PacketProcessor::Number(this->len[0], this->len[1]);
- SAFE_SEEK(fh, 1, SEEK_CUR);
-
- this->file_splits.reserve(1 + (numobj / EIF::FILE_MAX_ENTRIES));
-
- unsigned char namesize;
- std::string name;
- char buf[EIF::DATA_SIZE] = {0};
-
- this->data.resize(numobj+1);
-
- SAFE_READ(static_cast<void *>(&namesize), sizeof(char), 1, fh);
- for (int i = 1; i <= numobj; ++i)
- {
- EIF_Data& newdata = this->data[i];
-
- if ((i - 1) % EIF::FILE_MAX_ENTRIES == 0)
- this->file_splits.push_back(std::size_t(std::ftell(fh)) - 1);
-
- namesize = PacketProcessor::Number(namesize);
- name.resize(namesize);
- SAFE_READ(&name[0], sizeof(char), namesize, fh);
- SAFE_READ(buf, sizeof(char), EIF::DATA_SIZE, fh);
-
- newdata.id = i;
- newdata.name = name;
- newdata.graphic = PacketProcessor::Number(buf[0], buf[1]);
- newdata.type = static_cast<EIF::Type>(PacketProcessor::Number(buf[2]));
- newdata.subtype = static_cast<EIF::SubType>(PacketProcessor::Number(buf[3]));
- // Ranged gun hack
- if (newdata.id == 365 && newdata.name == "Gun")
- {
- newdata.subtype = EIF::Ranged;
- }
- // / Ranged gun hack
- newdata.special = static_cast<EIF::Special>(PacketProcessor::Number(buf[4]));
- newdata.hp = PacketProcessor::Number(buf[5], buf[6]);
- newdata.tp = PacketProcessor::Number(buf[7], buf[8]);
- newdata.mindam = PacketProcessor::Number(buf[9], buf[10]);
- newdata.maxdam = PacketProcessor::Number(buf[11], buf[12]);
- newdata.accuracy = PacketProcessor::Number(buf[13], buf[14]);
- newdata.evade = PacketProcessor::Number(buf[15], buf[16]);
- newdata.armor = PacketProcessor::Number(buf[17], buf[18]);
-
- newdata.str = PacketProcessor::Number(buf[20]);
- newdata.intl = PacketProcessor::Number(buf[21]);
- newdata.wis = PacketProcessor::Number(buf[22]);
- newdata.agi = PacketProcessor::Number(buf[23]);
- newdata.con = PacketProcessor::Number(buf[24]);
- newdata.cha = PacketProcessor::Number(buf[25]);
-
- newdata.light = PacketProcessor::Number(buf[26]);
- newdata.dark = PacketProcessor::Number(buf[27]);
- newdata.earth = PacketProcessor::Number(buf[28]);
- newdata.air = PacketProcessor::Number(buf[29]);
- newdata.water = PacketProcessor::Number(buf[30]);
- newdata.fire = PacketProcessor::Number(buf[31]);
-
- newdata.scrollmap = PacketProcessor::Number(buf[32], buf[33], buf[34]);
- newdata.scrollx = PacketProcessor::Number(buf[35]);
- newdata.scrolly = PacketProcessor::Number(buf[36]);
-
- newdata.levelreq = PacketProcessor::Number(buf[37], buf[38]);
- newdata.classreq = PacketProcessor::Number(buf[39], buf[40]);
-
- newdata.strreq = PacketProcessor::Number(buf[41], buf[42]);
- newdata.intreq = PacketProcessor::Number(buf[43], buf[44]);
- newdata.wisreq = PacketProcessor::Number(buf[45], buf[46]);
- newdata.agireq = PacketProcessor::Number(buf[47], buf[48]);
- newdata.conreq = PacketProcessor::Number(buf[49], buf[50]);
- newdata.chareq = PacketProcessor::Number(buf[51], buf[52]);
-
- newdata.weight = PacketProcessor::Number(buf[55]);
-
- newdata.size = static_cast<EIF::Size>(PacketProcessor::Number(buf[57]));
-
- if (i < numobj && std::fread(static_cast<void *>(&namesize), sizeof(char), 1, fh) != 1)
- {
- break;
- }
- }
+void pub_read_record(ENF_Data& newdata, char* buf)
+{
+ newdata.graphic = PacketProcessor::Number(buf[0], buf[1]);
- if (this->data.back().name.compare("eof") == 0)
- {
- this->data.pop_back();
- }
+ newdata.boss = PacketProcessor::Number(buf[3], buf[4]);
+ newdata.child = PacketProcessor::Number(buf[5], buf[6]);
+ newdata.type = static_cast<ENF::Type>(PacketProcessor::Number(buf[7], buf[8]));
+ newdata.vendor_id = PacketProcessor::Number(buf[9], buf[10]);
+ newdata.hp = PacketProcessor::Number(buf[11], buf[12], buf[13]);
- this->file_splits.push_back(std::size_t(std::ftell(fh)));
+ newdata.mindam = PacketProcessor::Number(buf[16], buf[17]);
+ newdata.maxdam = PacketProcessor::Number(buf[18], buf[19]);
- Console::Out("%i items loaded.", this->data.size()-1);
+ newdata.accuracy = PacketProcessor::Number(buf[20], buf[21]);
+ newdata.evade = PacketProcessor::Number(buf[22], buf[23]);
+ newdata.armor = PacketProcessor::Number(buf[24], buf[25]);
- std::fclose(fh);
+ newdata.exp = PacketProcessor::Number(buf[36], buf[37]);
}
-EIF_Data& EIF::Get(unsigned int id)
+void pub_read_record(ESF_Data& newdata, char* buf)
{
- if (id < this->data.size())
- return this->data[id];
- else
- return this->data[0];
+ newdata.icon = PacketProcessor::Number(buf[0], buf[1]);
+ newdata.graphic = PacketProcessor::Number(buf[2], buf[3]);
+ newdata.tp = PacketProcessor::Number(buf[4], buf[5]);
+ newdata.sp = PacketProcessor::Number(buf[6], buf[7]);
+ newdata.cast_time = PacketProcessor::Number(buf[8]);
+
+ newdata.type = static_cast<ESF::Type>(PacketProcessor::Number(buf[11]));
+ newdata.target_restrict = static_cast<ESF::TargetRestrict>(PacketProcessor::Number(buf[17]));
+ newdata.target = static_cast<ESF::Target>(PacketProcessor::Number(buf[18]));
+
+ newdata.mindam = PacketProcessor::Number(buf[23], buf[24]);
+ newdata.maxdam = PacketProcessor::Number(buf[25], buf[26]);
+ newdata.accuracy = PacketProcessor::Number(buf[27], buf[28]);
+ newdata.hp = PacketProcessor::Number(buf[34], buf[35]);
}
-const EIF_Data& EIF::Get(unsigned int id) const
+void pub_read_record(ECF_Data& newdata, char* buf)
{
- if (id < this->data.size())
- return this->data[id];
- else
- return this->data[0];
+ newdata.base = PacketProcessor::Number(buf[0]);
+ newdata.type = PacketProcessor::Number(buf[1]);
+
+ newdata.str = PacketProcessor::Number(buf[2], buf[3]);
+ newdata.intl = PacketProcessor::Number(buf[4], buf[5]);
+ newdata.wis = PacketProcessor::Number(buf[6], buf[7]);
+ newdata.agi = PacketProcessor::Number(buf[8], buf[9]);
+ newdata.con = PacketProcessor::Number(buf[10], buf[11]);
+ newdata.cha = PacketProcessor::Number(buf[12], buf[13]);
}
-unsigned int EIF::GetKey(int keynum) const
+template <class T>
+int read_single_file(T& pub, Pub_File& file, bool auto_split, int version, int first_id)
{
- for (std::size_t i = 0; i < this->data.size(); ++i)
+ std::FILE *fh = std::fopen(file.filename.c_str(), "rb");
+ eodata_safe_fail_filename = file.filename.c_str();
+
+ if (!fh)
{
- if (this->Get(i).type == EIF::Key && this->Get(i).key == keynum)
- return i;
+ Console::Err("Could not load file: %s", file.filename.c_str());
+ std::exit(1);
}
- return 0;
-}
+ // Only attempt to auto-split the first file
+ if (first_id != 1)
+ auto_split = false;
-void ENF::Read(const std::string& filename)
-{
- this->data.clear();
+ unsigned char namesize, shoutsize;
+ std::string name, shout;
+ char buf[T::DATA_SIZE] = {0};
- std::FILE *fh = std::fopen(filename.c_str(), "rb");
- eodata_safe_fail_filename = filename.c_str();
+ int readobj = 0;
+ int max_entries = T::FILE_MAX_ENTRIES;
- if (!fh)
+ if constexpr (std::is_same_v<T, ECF>)
{
- Console::Err("Could not load file: %s", filename.c_str());
- std::exit(1);
+ if (version >= 1)
+ max_entries = T::FILE_MAX_ENTRIES_V2;
}
- SAFE_SEEK(fh, 3, SEEK_SET);
- SAFE_READ(this->rid.data(), sizeof(char), 4, fh);
- SAFE_READ(this->len.data(), sizeof(char), 2, fh);
- int numobj = PacketProcessor::Number(this->len[0], this->len[1]);
- SAFE_SEEK(fh, 1, SEEK_CUR);
+ if (version < 1 && auto_split == true)
+ max_entries = 64000;
- this->file_splits.reserve(1 + (numobj / ENF::FILE_MAX_ENTRIES));
+ SAFE_SEEK(fh, 10, SEEK_SET);
+ SAFE_READ(static_cast<void *>(&namesize), sizeof(char), 1, fh);
- unsigned char namesize;
- std::string name;
- char buf[ENF::DATA_SIZE] = {0};
+ if constexpr (std::is_same_v<T, ESF>)
+ {
+ SAFE_READ(static_cast<void *>(&shoutsize), sizeof(char), 1, fh);
+ }
- this->data.resize(numobj+1);
+ file.splits.reserve(4);
- SAFE_READ(static_cast<void *>(&namesize), sizeof(char), 1, fh);
- for (int i = 1; i <= numobj; ++i)
+ for (int i = 0; i < max_entries; ++i)
{
- ENF_Data& newdata = this->data[i];
+ if (auto_split && (i % T::FILE_MAX_ENTRIES == 0))
+ {
+ std::size_t split = std::size_t(std::ftell(fh)) - 1;
+ int size = (int)split - (file.splits.empty() ? 0 : (int)file.splits.back());
+
+ if (size > 63992)
+ Console::Err("Auto-split file is too large (%d bytes too long): %s", size - 63992, file.filename.c_str());
- if ((i - 1) % ENF::FILE_MAX_ENTRIES == 0)
- this->file_splits.push_back(std::size_t(std::ftell(fh)) - 1);
+ file.splits.push_back(std::size_t(std::ftell(fh)) - 1);
+ }
namesize = PacketProcessor::Number(namesize);
name.resize(namesize);
- SAFE_READ(&name[0], sizeof(char), namesize, fh);
- SAFE_READ(buf, sizeof(char), ENF::DATA_SIZE, fh);
- newdata.id = i;
- newdata.name = name;
+ if (namesize > 0)
+ SAFE_READ(&name[0], sizeof(char), namesize, fh);
- newdata.graphic = PacketProcessor::Number(buf[0], buf[1]);
+ if constexpr (std::is_same_v<T, ESF>)
+ {
+ shoutsize = PacketProcessor::Number(shoutsize);
+ shout.resize(shoutsize);
- newdata.boss = PacketProcessor::Number(buf[3], buf[4]);
- newdata.child = PacketProcessor::Number(buf[5], buf[6]);
- newdata.type = static_cast<ENF::Type>(PacketProcessor::Number(buf[7], buf[8]));
- newdata.vendor_id = PacketProcessor::Number(buf[9], buf[10]);
- newdata.hp = PacketProcessor::Number(buf[11], buf[12], buf[13]);
+ if (shoutsize > 0)
+ SAFE_READ(&shout[0], sizeof(char), shoutsize, fh);
+ }
- newdata.mindam = PacketProcessor::Number(buf[16], buf[17]);
- newdata.maxdam = PacketProcessor::Number(buf[18], buf[19]);
+ SAFE_READ(buf, sizeof(char), T::DATA_SIZE, fh);
- newdata.accuracy = PacketProcessor::Number(buf[20], buf[21]);
- newdata.evade = PacketProcessor::Number(buf[22], buf[23]);
- newdata.armor = PacketProcessor::Number(buf[24], buf[25]);
+ typename T::data_t& newdata = pub.data[first_id + i];
- newdata.exp = PacketProcessor::Number(buf[36], buf[37]);
+ ++readobj;
- if (i < numobj && std::fread(static_cast<void *>(&namesize), sizeof(char), 1, fh) != 1)
+ newdata.id = first_id + i;
+ newdata.name = name;
+
+ if constexpr (std::is_same_v<T, ESF>)
+ {
+ newdata.shout = shout;
+ }
+
+ pub_read_record(newdata, buf);
+
+ if (first_id + i >= pub.data.size()
+ || std::fread(static_cast<void *>(&namesize), sizeof(char), 1, fh) != 1)
{
break;
}
+
+ if constexpr (std::is_same_v<T, ESF>)
+ {
+ if (std::fread(static_cast<void *>(&shoutsize), sizeof(char), 1, fh) != 1)
+ {
+ break;
+ }
+ }
}
- if (this->data.back().name.compare("eof") == 0)
+ std::size_t last_split = std::size_t(std::ftell(fh));
+ int size = (int)last_split - (int)file.splits.back();
+
+ if (size > 63992)
{
- this->data.pop_back();
+ if (auto_split && file.splits.size() > 1)
+ Console::Err("Auto-split file is too large (%d bytes too long): %s", size - 63992, file.filename.c_str());
+ else
+ Console::Err("File is too large (%d bytes too long): %s", size - 63992, file.filename.c_str());
}
- this->file_splits.push_back(std::size_t(std::ftell(fh)));
-
- Console::Out("%i npc types loaded.", this->data.size()-1);
+ file.splits.push_back(last_split);
std::fclose(fh);
-}
-ENF_Data& ENF::Get(unsigned int id)
-{
- if (id < this->data.size())
- return this->data[id];
- else
- return this->data[0];
+ return readobj;
}
-const ENF_Data& ENF::Get(unsigned int id) const
+template <class T>
+void read_pub_files(T& pub, const std::string& filename, bool auto_split)
{
- if (id < this->data.size())
- return this->data[id];
- else
- return this->data[0];
-}
+ pub.files.clear();
+ pub.data.clear();
-void ESF::Read(const std::string& filename)
-{
- this->data.clear();
+ std::string filename_template = convert_pub_filename(filename);
+ char fn_buf[256];
+ int file_number = 1;
+
+ std::snprintf(fn_buf, sizeof fn_buf, filename_template.c_str(), file_number);
- std::FILE *fh = std::fopen(filename.c_str(), "rb");
+ std::FILE *fh = std::fopen(fn_buf, "rb");
eodata_safe_fail_filename = filename.c_str();
if (!fh)
@@ -268,88 +291,41 @@ void ESF::Read(const std::string& filename)
std::exit(1);
}
- SAFE_SEEK(fh, 3, SEEK_SET);
- SAFE_READ(this->rid.data(), sizeof(char), 4, fh);
- SAFE_READ(this->len.data(), sizeof(char), 2, fh);
- int numobj = PacketProcessor::Number(this->len[0], this->len[1]);
- SAFE_SEEK(fh, 1, SEEK_CUR);
+ char header_buf[10];
+ SAFE_READ(header_buf, sizeof(char), 10, fh);
- this->file_splits.reserve(1 + (numobj / ESF::FILE_MAX_ENTRIES));
+ std::memcpy(pub.rid.data(), header_buf + 3, 4);
+ std::memcpy(pub.len.data(), header_buf + 7, 2);
- unsigned char namesize, shoutsize;
- std::string name, shout;
- char buf[ESF::DATA_SIZE] = {0};
+ int readobj = 0;
+ int numobj = PacketProcessor::Number(pub.len[0], pub.len[1]);
+ int version = PacketProcessor::Number(header_buf[9]);
- this->data.resize(numobj+1);
+ pub.data.resize(numobj + 1);
- SAFE_READ(static_cast<void *>(&namesize), sizeof(char), 1, fh);
- SAFE_READ(static_cast<void *>(&shoutsize), sizeof(char), 1, fh);
- for (int i = 1; i <= numobj; ++i)
+ while (readobj < numobj && file_number < 1000)
{
- ESF_Data& newdata = this->data[i];
-
- if ((i - 1) % ESF::FILE_MAX_ENTRIES == 0)
- this->file_splits.push_back(std::size_t(std::ftell(fh)) - 2);
-
- namesize = PacketProcessor::Number(namesize);
- name.resize(namesize);
- if (namesize > 0)
- {
- SAFE_READ(&name[0], sizeof(char), namesize, fh);
- }
-
- shoutsize = PacketProcessor::Number(shoutsize);
- shout.resize(shoutsize);
- if (shoutsize > 0)
- {
- SAFE_READ(&shout[0], sizeof(char), shoutsize, fh);
- }
+ std::snprintf(fn_buf, sizeof fn_buf, filename_template.c_str(), file_number++);
+ pub.files.push_back(Pub_File{fn_buf, {}});
+ Pub_File& pub_file = pub.files.back();
+ readobj += read_single_file(pub, pub_file, auto_split, version, readobj + 1);
- SAFE_READ(buf, sizeof(char), ESF::DATA_SIZE, fh);
-
- newdata.id = i;
- newdata.name = name;
- newdata.shout = shout;
-
- newdata.icon = PacketProcessor::Number(buf[0], buf[1]);
- newdata.graphic = PacketProcessor::Number(buf[2], buf[3]);
- newdata.tp = PacketProcessor::Number(buf[4], buf[5]);
- newdata.sp = PacketProcessor::Number(buf[6], buf[7]);
- newdata.cast_time = PacketProcessor::Number(buf[8]);
-
- newdata.type = static_cast<ESF::Type>(PacketProcessor::Number(buf[11]));
- newdata.target_restrict = static_cast<ESF::TargetRestrict>(PacketProcessor::Number(buf[17]));
- newdata.target = static_cast<ESF::Target>(PacketProcessor::Number(buf[18]));
-
- newdata.mindam = PacketProcessor::Number(buf[23], buf[24]);
- newdata.maxdam = PacketProcessor::Number(buf[25], buf[26]);
- newdata.accuracy = PacketProcessor::Number(buf[27], buf[28]);
- newdata.hp = PacketProcessor::Number(buf[34], buf[35]);
-
- if (i < numobj && std::fread(static_cast<void *>(&namesize), sizeof(char), 1, fh) != 1)
- {
+ // Only a single file is loaded if auto-splitting occurs
+ if (pub_file.splits.size() > 2)
break;
- }
-
- if (i < numobj && std::fread(static_cast<void *>(&shoutsize), sizeof(char), 1, fh) != 1)
- {
- break;
- }
}
- if (this->data.back().name.compare("eof") == 0)
- {
- this->data.pop_back();
- }
-
- this->file_splits.push_back(std::size_t(std::ftell(fh)));
-
- Console::Out("%i spells loaded.", this->data.size()-1);
+ if (version < 1 && pub.data.back().name == "eof")
+ pub.data.pop_back();
+}
- std::fclose(fh);
+void EIF::Read(const std::string& filename, bool auto_split)
+{
+ read_pub_files(*this, filename, auto_split);
+ Console::Out("%i items loaded.", this->data.size()-1);
}
-ESF_Data& ESF::Get(unsigned int id)
+EIF_Data& EIF::Get(unsigned int id)
{
if (id < this->data.size())
return this->data[id];
@@ -357,7 +333,7 @@ ESF_Data& ESF::Get(unsigned int id)
return this->data[0];
}
-const ESF_Data& ESF::Get(unsigned int id) const
+const EIF_Data& EIF::Get(unsigned int id) const
{
if (id < this->data.size())
return this->data[id];
@@ -365,76 +341,65 @@ const ESF_Data& ESF::Get(unsigned int id) const
return this->data[0];
}
-void ECF::Read(const std::string& filename)
+unsigned int EIF::GetKey(int keynum) const
{
- this->data.clear();
-
- std::FILE *fh = std::fopen(filename.c_str(), "rb");
- eodata_safe_fail_filename = filename.c_str();
-
- if (!fh)
+ for (std::size_t i = 0; i < this->data.size(); ++i)
{
- Console::Err("Could not load file: %s", filename.c_str());
- std::exit(1);
+ if (this->Get(i).type == EIF::Key && this->Get(i).key == keynum)
+ return i;
}
- SAFE_SEEK(fh, 3, SEEK_SET);
- SAFE_READ(this->rid.data(), sizeof(char), 4, fh);
- SAFE_READ(this->len.data(), sizeof(char), 2, fh);
- int numobj = PacketProcessor::Number(this->len[0], this->len[1]);
- SAFE_SEEK(fh, 1, SEEK_CUR);
-
- this->file_splits.reserve(1 + (numobj / ECF::FILE_MAX_ENTRIES));
-
- unsigned char namesize;
- std::string name;
- char buf[ECF::DATA_SIZE] = {0};
-
- this->data.resize(numobj+1);
-
- SAFE_READ(static_cast<void *>(&namesize), sizeof(char), 1, fh);
- for (int i = 1; i <= numobj; ++i)
- {
- ECF_Data& newdata = this->data[i];
-
- if ((i - 1) % ECF::FILE_MAX_ENTRIES == 0)
- this->file_splits.push_back(std::size_t(std::ftell(fh)) - 1);
-
- namesize = PacketProcessor::Number(namesize);
- name.resize(namesize);
- SAFE_READ(&name[0], sizeof(char), namesize, fh);
-
- SAFE_READ(buf, sizeof(char), ECF::DATA_SIZE, fh);
+ return 0;
+}
- newdata.id = i;
- newdata.name = name;
+void ENF::Read(const std::string& filename, bool auto_split)
+{
+ read_pub_files(*this, filename, auto_split);
+ Console::Out("%i npc types loaded.", this->data.size()-1);
+}
- newdata.base = PacketProcessor::Number(buf[0]);
- newdata.type = PacketProcessor::Number(buf[1]);
+ENF_Data& ENF::Get(unsigned int id)
+{
+ if (id < this->data.size())
+ return this->data[id];
+ else
+ return this->data[0];
+}
- newdata.str = PacketProcessor::Number(buf[2], buf[3]);
- newdata.intl = PacketProcessor::Number(buf[4], buf[5]);
- newdata.wis = PacketProcessor::Number(buf[6], buf[7]);
- newdata.agi = PacketProcessor::Number(buf[8], buf[9]);
- newdata.con = PacketProcessor::Number(buf[10], buf[11]);
- newdata.cha = PacketProcessor::Number(buf[12], buf[13]);
+const ENF_Data& ENF::Get(unsigned int id) const
+{
+ if (id < this->data.size())
+ return this->data[id];
+ else
+ return this->data[0];
+}
- if (i < numobj && std::fread(static_cast<void *>(&namesize), sizeof(char), 1, fh) != 1)
- {
- break;
- }
- }
+void ESF::Read(const std::string& filename, bool auto_split)
+{
+ read_pub_files(*this, filename, auto_split);
+ Console::Out("%i spells loaded.", this->data.size()-1);
+}
- if (this->data.back().name.compare("eof") == 0)
- {
- this->data.pop_back();
- }
+ESF_Data& ESF::Get(unsigned int id)
+{
+ if (id < this->data.size())
+ return this->data[id];
+ else
+ return this->data[0];
+}
- this->file_splits.push_back(std::size_t(std::ftell(fh)));
+const ESF_Data& ESF::Get(unsigned int id) const
+{
+ if (id < this->data.size())
+ return this->data[id];
+ else
+ return this->data[0];
+}
+void ECF::Read(const std::string& filename, bool auto_split)
+{
+ read_pub_files(*this, filename, auto_split);
Console::Out("%i classes loaded.", this->data.size()-1);
-
- std::fclose(fh);
}
ECF_Data& ECF::Get(unsigned int id)
diff --git a/src/eodata.hpp b/src/eodata.hpp
index 10be5f0..59555d7 100644
--- a/src/eodata.hpp
+++ b/src/eodata.hpp
@@ -12,6 +12,12 @@
#include <string>
#include <vector>
+struct Pub_File
+{
+ std::string filename;
+ std::vector<std::size_t> splits;
+};
+
/**
* One item record in an EIF object
*/
@@ -177,16 +183,17 @@ class EIF
}
}
+ using data_t = EIF_Data;
static const int DATA_SIZE = 58;
static const int FILE_MAX_ENTRIES = 900;
std::array<unsigned char, 4> rid;
std::array<unsigned char, 2> len;
std::vector<EIF_Data> data;
- std::vector<std::size_t> file_splits;
+ std::vector<Pub_File> files;
- EIF(const std::string& filename) { Read(filename.c_str()); }
+ EIF(const std::string& filename, bool auto_split) { Read(filename.c_str(), auto_split); }
- void Read(const std::string& filename);
+ void Read(const std::string& filename, bool auto_split);
EIF_Data& Get(unsigned int id);
const EIF_Data& Get(unsigned int id) const;
@@ -253,16 +260,17 @@ class ENF
Quest
};
+ using data_t = ENF_Data;
static const int DATA_SIZE = 39;
static const int FILE_MAX_ENTRIES = 900;
std::array<unsigned char, 4> rid;
std::array<unsigned char, 2> len;
std::vector<ENF_Data> data;
- std::vector<std::size_t> file_splits;
+ std::vector<Pub_File> files;
- ENF(const std::string& filename) { Read(filename.c_str()); }
+ ENF(const std::string& filename, bool auto_split) { Read(filename.c_str(), auto_split); }
- void Read(const std::string& filename);
+ void Read(const std::string& filename, bool auto_split);
ENF_Data& Get(unsigned int id);
const ENF_Data& Get(unsigned int id) const;
@@ -331,16 +339,17 @@ class ESF
Group
};
+ using data_t = ESF_Data;
static const int DATA_SIZE = 51;
static const int FILE_MAX_ENTRIES = 900;
std::array<unsigned char, 4> rid;
std::array<unsigned char, 2> len;
std::vector<ESF_Data> data;
- std::vector<std::size_t> file_splits;
+ std::vector<Pub_File> files;
- ESF(const std::string& filename) { Read(filename.c_str()); }
+ ESF(const std::string& filename, bool auto_split) { Read(filename.c_str(), auto_split); }
- void Read(const std::string& filename);
+ void Read(const std::string& filename, bool auto_split);
ESF_Data& Get(unsigned int id);
const ESF_Data& Get(unsigned int id) const;
@@ -378,16 +387,18 @@ template <class ECF> struct ECF_Data_Base
class ECF
{
public:
+ using data_t = ECF_Data;
static const int DATA_SIZE = 14;
static const int FILE_MAX_ENTRIES = 250;
+ static const int FILE_MAX_ENTRIES_V2 = 900;
std::array<unsigned char, 4> rid;
std::array<unsigned char, 2> len;
std::vector<ECF_Data> data;
- std::vector<std::size_t> file_splits;
+ std::vector<Pub_File> files;
- ECF(const std::string& filename) { Read(filename.c_str()); }
+ ECF(const std::string& filename, bool auto_split) { Read(filename.c_str(), auto_split); }
- void Read(const std::string& filename);
+ void Read(const std::string& filename, bool auto_split);
ECF_Data& Get(unsigned int id);
const ECF_Data& Get(unsigned int id) const;
diff --git a/src/world.cpp b/src/world.cpp
index 20efe7b..49fd96a 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -403,10 +403,12 @@ World::World(std::array<std::string, 6> dbinfo, const Config &eoserv_config, con
this->UpdateConfig();
this->LoadHome();
- this->eif = new EIF(this->config["EIF"]);
- this->enf = new ENF(this->config["ENF"]);
- this->esf = new ESF(this->config["ESF"]);
- this->ecf = new ECF(this->config["ECF"]);
+ bool auto_split = this->config["AutoSplitPubFiles"];
+
+ this->eif = new EIF(this->config["EIF"], auto_split);
+ this->enf = new ENF(this->config["ENF"], auto_split);
+ this->esf = new ESF(this->config["ESF"], auto_split);
+ this->ecf = new ECF(this->config["ECF"], auto_split);
std::size_t num_npcs = this->enf->data.size();
this->npc_data.resize(num_npcs);
@@ -915,10 +917,12 @@ void World::ReloadPub(bool quiet)
auto esf_id = this->esf->rid;
auto ecf_id = this->ecf->rid;
- this->eif->Read(this->config["EIF"]);
- this->enf->Read(this->config["ENF"]);
- this->esf->Read(this->config["ESF"]);
- this->ecf->Read(this->config["ECF"]);
+ bool auto_split = this->config["AutoSplitPubFiles"];
+
+ this->eif->Read(this->config["EIF"], auto_split);
+ this->enf->Read(this->config["ENF"], auto_split);
+ this->esf->Read(this->config["ESF"], auto_split);
+ this->ecf->Read(this->config["ECF"], auto_split);
if (eif_id != this->eif->rid || enf_id != this->enf->rid
|| esf_id != this->esf->rid || ecf_id != this->ecf->rid)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment