use phosg namespace

This commit is contained in:
Martin Michelsen
2024-07-28 11:54:41 -07:00
parent 5523388ad4
commit 1bfbf09891
116 changed files with 2969 additions and 3088 deletions
+8 -10
View File
@@ -23,7 +23,7 @@ AFSArchive::AFSArchive(shared_ptr<const string> data)
le_uint32_t size; le_uint32_t size;
} __packed_ws__(FileEntry, 8); } __packed_ws__(FileEntry, 8);
StringReader r(*this->data); phosg::StringReader r(*this->data);
const auto& header = r.get<FileHeader>(); const auto& header = r.get<FileHeader>();
if (header.magic != 0x41465300) { // 'AFS\0' if (header.magic != 0x41465300) { // 'AFS\0'
throw runtime_error("file is not an AFS archive"); throw runtime_error("file is not an AFS archive");
@@ -52,29 +52,27 @@ string AFSArchive::get_copy(size_t index) const {
return string(reinterpret_cast<const char*>(ret.first), ret.second); return string(reinterpret_cast<const char*>(ret.first), ret.second);
} }
StringReader AFSArchive::get_reader(size_t index) const { phosg::StringReader AFSArchive::get_reader(size_t index) const {
auto ret = this->get(index); auto ret = this->get(index);
return StringReader(ret.first, ret.second); return phosg::StringReader(ret.first, ret.second);
} }
string AFSArchive::generate(const vector<string>& files, bool big_endian) { string AFSArchive::generate(const vector<string>& files, bool big_endian) {
return big_endian ? AFSArchive::generate_t<true>(files) : AFSArchive::generate_t<false>(files); return big_endian ? AFSArchive::generate_t<true>(files) : AFSArchive::generate_t<false>(files);
} }
template <bool IsBigEndian> template <bool BE>
string AFSArchive::generate_t(const vector<string>& files) { string AFSArchive::generate_t(const vector<string>& files) {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; phosg::StringWriter w;
StringWriter w;
w.put_u32b(0x41465300); // 'AFS\0' w.put_u32b(0x41465300); // 'AFS\0'
w.put<U32T>(files.size()); w.put<U32T<BE>>(files.size());
// It seems entries are aligned to 0x800-byte boundaries, and the file's // It seems entries are aligned to 0x800-byte boundaries, and the file's
// header is always 0x80000 (!) bytes, most of which is unused // header is always 0x80000 (!) bytes, most of which is unused
uint32_t data_offset = 0x80000; uint32_t data_offset = 0x80000;
for (const auto& file : files) { for (const auto& file : files) {
w.put<U32T>(data_offset); w.put<U32T<BE>>(data_offset);
w.put<U32T>(file.size()); w.put<U32T<BE>>(file.size());
data_offset = (data_offset + file.size() + 0x7FF) & (~0x7FF); data_offset = (data_offset + file.size() + 0x7FF) & (~0x7FF);
} }
+4 -2
View File
@@ -8,6 +8,8 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "Types.hh"
class AFSArchive { class AFSArchive {
public: public:
AFSArchive(std::shared_ptr<const std::string> data); AFSArchive(std::shared_ptr<const std::string> data);
@@ -23,12 +25,12 @@ public:
std::pair<const void*, size_t> get(size_t index) const; std::pair<const void*, size_t> get(size_t index) const;
std::string get_copy(size_t index) const; std::string get_copy(size_t index) const;
StringReader get_reader(size_t index) const; phosg::StringReader get_reader(size_t index) const;
static std::string generate(const std::vector<std::string>& files, bool big_endian); static std::string generate(const std::vector<std::string>& files, bool big_endian);
private: private:
template <bool IsBigEndian> template <bool BE>
static std::string generate_t(const std::vector<std::string>& files); static std::string generate_t(const std::vector<std::string>& files);
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
+48 -48
View File
@@ -11,7 +11,7 @@
using namespace std; using namespace std;
shared_ptr<DCNTELicense> DCNTELicense::from_json(const JSON& json) { shared_ptr<DCNTELicense> DCNTELicense::from_json(const phosg::JSON& json) {
auto ret = make_shared<DCNTELicense>(); auto ret = make_shared<DCNTELicense>();
ret->serial_number = json.get_string("SerialNumber"); ret->serial_number = json.get_string("SerialNumber");
ret->access_key = json.get_string("AccessKey"); ret->access_key = json.get_string("AccessKey");
@@ -30,14 +30,14 @@ shared_ptr<DCNTELicense> DCNTELicense::from_json(const JSON& json) {
return ret; return ret;
} }
JSON DCNTELicense::json() const { phosg::JSON DCNTELicense::json() const {
return JSON::dict({ return phosg::JSON::dict({
{"SerialNumber", this->serial_number}, {"SerialNumber", this->serial_number},
{"AccessKey", this->access_key}, {"AccessKey", this->access_key},
}); });
} }
shared_ptr<V1V2License> V1V2License::from_json(const JSON& json) { shared_ptr<V1V2License> V1V2License::from_json(const phosg::JSON& json) {
auto ret = make_shared<V1V2License>(); auto ret = make_shared<V1V2License>();
ret->serial_number = json.get_int("SerialNumber"); ret->serial_number = json.get_int("SerialNumber");
ret->access_key = json.get_string("AccessKey"); ret->access_key = json.get_string("AccessKey");
@@ -50,14 +50,14 @@ shared_ptr<V1V2License> V1V2License::from_json(const JSON& json) {
return ret; return ret;
} }
JSON V1V2License::json() const { phosg::JSON V1V2License::json() const {
return JSON::dict({ return phosg::JSON::dict({
{"SerialNumber", this->serial_number}, {"SerialNumber", this->serial_number},
{"AccessKey", this->access_key}, {"AccessKey", this->access_key},
}); });
} }
shared_ptr<GCLicense> GCLicense::from_json(const JSON& json) { shared_ptr<GCLicense> GCLicense::from_json(const phosg::JSON& json) {
auto ret = make_shared<GCLicense>(); auto ret = make_shared<GCLicense>();
ret->serial_number = json.get_int("SerialNumber"); ret->serial_number = json.get_int("SerialNumber");
ret->access_key = json.get_string("AccessKey"); ret->access_key = json.get_string("AccessKey");
@@ -74,15 +74,15 @@ shared_ptr<GCLicense> GCLicense::from_json(const JSON& json) {
return ret; return ret;
} }
JSON GCLicense::json() const { phosg::JSON GCLicense::json() const {
return JSON::dict({ return phosg::JSON::dict({
{"SerialNumber", this->serial_number}, {"SerialNumber", this->serial_number},
{"AccessKey", this->access_key}, {"AccessKey", this->access_key},
{"Password", this->password}, {"Password", this->password},
}); });
} }
shared_ptr<XBLicense> XBLicense::from_json(const JSON& json) { shared_ptr<XBLicense> XBLicense::from_json(const phosg::JSON& json) {
auto ret = make_shared<XBLicense>(); auto ret = make_shared<XBLicense>();
ret->gamertag = json.get_string("GamerTag"); ret->gamertag = json.get_string("GamerTag");
ret->user_id = json.get_int("UserID"); ret->user_id = json.get_int("UserID");
@@ -99,15 +99,15 @@ shared_ptr<XBLicense> XBLicense::from_json(const JSON& json) {
return ret; return ret;
} }
JSON XBLicense::json() const { phosg::JSON XBLicense::json() const {
return JSON::dict({ return phosg::JSON::dict({
{"GamerTag", this->gamertag}, {"GamerTag", this->gamertag},
{"UserID", this->user_id}, {"UserID", this->user_id},
{"AccountID", this->account_id}, {"AccountID", this->account_id},
}); });
} }
shared_ptr<BBLicense> BBLicense::from_json(const JSON& json) { shared_ptr<BBLicense> BBLicense::from_json(const phosg::JSON& json) {
auto ret = make_shared<BBLicense>(); auto ret = make_shared<BBLicense>();
ret->username = json.get_string("UserName"); ret->username = json.get_string("UserName");
ret->password = json.get_string("Password"); ret->password = json.get_string("Password");
@@ -126,14 +126,14 @@ shared_ptr<BBLicense> BBLicense::from_json(const JSON& json) {
return ret; return ret;
} }
JSON BBLicense::json() const { phosg::JSON BBLicense::json() const {
return JSON::dict({ return phosg::JSON::dict({
{"UserName", this->username}, {"UserName", this->username},
{"Password", this->password}, {"Password", this->password},
}); });
} }
Account::Account(const JSON& json) Account::Account(const phosg::JSON& json)
: account_id(0), : account_id(0),
flags(0), flags(0),
ban_end_time(0), ban_end_time(0),
@@ -237,38 +237,38 @@ Account::Account(const JSON& json)
} }
} }
JSON Account::json() const { phosg::JSON Account::json() const {
JSON dc_nte_json = JSON::list(); phosg::JSON dc_nte_json = phosg::JSON::list();
for (const auto& it : this->dc_nte_licenses) { for (const auto& it : this->dc_nte_licenses) {
dc_nte_json.emplace_back(it.second->json()); dc_nte_json.emplace_back(it.second->json());
} }
JSON dc_json = JSON::list(); phosg::JSON dc_json = phosg::JSON::list();
for (const auto& it : this->dc_licenses) { for (const auto& it : this->dc_licenses) {
dc_json.emplace_back(it.second->json()); dc_json.emplace_back(it.second->json());
} }
JSON pc_json = JSON::list(); phosg::JSON pc_json = phosg::JSON::list();
for (const auto& it : this->pc_licenses) { for (const auto& it : this->pc_licenses) {
pc_json.emplace_back(it.second->json()); pc_json.emplace_back(it.second->json());
} }
JSON gc_json = JSON::list(); phosg::JSON gc_json = phosg::JSON::list();
for (const auto& it : this->gc_licenses) { for (const auto& it : this->gc_licenses) {
gc_json.emplace_back(it.second->json()); gc_json.emplace_back(it.second->json());
} }
JSON xb_json = JSON::list(); phosg::JSON xb_json = phosg::JSON::list();
for (const auto& it : this->xb_licenses) { for (const auto& it : this->xb_licenses) {
xb_json.emplace_back(it.second->json()); xb_json.emplace_back(it.second->json());
} }
JSON bb_json = JSON::list(); phosg::JSON bb_json = phosg::JSON::list();
for (const auto& it : this->bb_licenses) { for (const auto& it : this->bb_licenses) {
bb_json.emplace_back(it.second->json()); bb_json.emplace_back(it.second->json());
} }
JSON auto_patches_json = JSON::list(); phosg::JSON auto_patches_json = phosg::JSON::list();
for (const auto& it : this->auto_patches_enabled) { for (const auto& it : this->auto_patches_enabled) {
auto_patches_json.emplace_back(it); auto_patches_json.emplace_back(it);
} }
return JSON::dict({ return phosg::JSON::dict({
{"FormatVersion", 1}, {"FormatVersion", 1},
{"AccountID", this->account_id}, {"AccountID", this->account_id},
{"DCNTELicenses", std::move(dc_nte_json)}, {"DCNTELicenses", std::move(dc_nte_json)},
@@ -333,14 +333,14 @@ void Account::print(FILE* stream) const {
} }
if (flags_str.empty()) { if (flags_str.empty()) {
flags_str = "none"; flags_str = "none";
} else if (ends_with(flags_str, ",")) { } else if (phosg::ends_with(flags_str, ",")) {
flags_str.pop_back(); flags_str.pop_back();
} }
fprintf(stream, " Flags: %08" PRIX32 " (%s)\n", this->flags, flags_str.c_str()); fprintf(stream, " Flags: %08" PRIX32 " (%s)\n", this->flags, flags_str.c_str());
} }
if (this->ban_end_time) { if (this->ban_end_time) {
string time_str = format_time(this->ban_end_time); string time_str = phosg::format_time(this->ban_end_time);
fprintf(stream, " Banned until: %" PRIu64 " (%s)\n", this->ban_end_time, time_str.c_str()); fprintf(stream, " Banned until: %" PRIu64 " (%s)\n", this->ban_end_time, time_str.c_str());
} }
if (this->ep3_current_meseta || this->ep3_total_meseta_earned) { if (this->ep3_current_meseta || this->ep3_total_meseta_earned) {
@@ -388,14 +388,14 @@ void Account::print(FILE* stream) const {
void Account::save() const { void Account::save() const {
if (!this->is_temporary) { if (!this->is_temporary) {
auto json = this->json(); auto json = this->json();
string json_data = json.serialize(JSON::SerializeOption::FORMAT | JSON::SerializeOption::HEX_INTEGERS); string json_data = json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::HEX_INTEGERS);
string filename = string_printf("system/licenses/%010" PRIu32 ".json", this->account_id); string filename = phosg::string_printf("system/licenses/%010" PRIu32 ".json", this->account_id);
save_file(filename, json_data); phosg::save_file(filename, json_data);
} }
} }
void Account::delete_file() const { void Account::delete_file() const {
string filename = string_printf("system/licenses/%010" PRIu32 ".json", this->account_id); string filename = phosg::string_printf("system/licenses/%010" PRIu32 ".json", this->account_id);
remove(filename.c_str()); remove(filename.c_str());
} }
@@ -420,7 +420,7 @@ shared_ptr<Login> AccountIndex::from_dc_nte_credentials_locked(const string& ser
if (login->dc_nte_license->access_key != access_key) { if (login->dc_nte_license->access_key != access_key) {
throw incorrect_access_key(); throw incorrect_access_key();
} }
if (login->account->ban_end_time && (login->account->ban_end_time >= now())) { if (login->account->ban_end_time && (login->account->ban_end_time >= phosg::now())) {
throw invalid_argument("user is banned"); throw invalid_argument("user is banned");
} }
return login; return login;
@@ -448,7 +448,7 @@ shared_ptr<Login> AccountIndex::from_dc_nte_credentials(
auto login = make_shared<Login>(); auto login = make_shared<Login>();
login->account_was_created = true; login->account_was_created = true;
login->account = make_shared<Account>(); login->account = make_shared<Account>();
login->account->account_id = fnv1a32(serial_number) & 0x7FFFFFFF; login->account->account_id = phosg::fnv1a32(serial_number) & 0x7FFFFFFF;
auto lic = make_shared<DCNTELicense>(); auto lic = make_shared<DCNTELicense>();
lic->serial_number = serial_number; lic->serial_number = serial_number;
lic->access_key = access_key; lic->access_key = access_key;
@@ -470,7 +470,7 @@ shared_ptr<Login> AccountIndex::from_dc_credentials_locked(
if (!is_shared && (login->dc_license->access_key != access_key)) { if (!is_shared && (login->dc_license->access_key != access_key)) {
throw incorrect_access_key(); throw incorrect_access_key();
} }
if (login->account->ban_end_time && (login->account->ban_end_time >= now())) { if (login->account->ban_end_time && (login->account->ban_end_time >= phosg::now())) {
throw invalid_argument("user is banned"); throw invalid_argument("user is banned");
} }
if (is_shared) { if (is_shared) {
@@ -519,7 +519,7 @@ shared_ptr<Login> AccountIndex::from_pc_nte_credentials(uint32_t guild_card_numb
throw missing_account(); throw missing_account();
} }
if (guild_card_number == 0xFFFFFFFF) { if (guild_card_number == 0xFFFFFFFF) {
guild_card_number = random_object<uint32_t>() & 0x7FFFFFFF; guild_card_number = phosg::random_object<uint32_t>() & 0x7FFFFFFF;
} }
auto login = make_shared<Login>(); auto login = make_shared<Login>();
login->account_was_created = true; login->account_was_created = true;
@@ -543,7 +543,7 @@ shared_ptr<Login> AccountIndex::from_pc_credentials_locked(
if (!is_shared && (login->pc_license->access_key != access_key)) { if (!is_shared && (login->pc_license->access_key != access_key)) {
throw incorrect_access_key(); throw incorrect_access_key();
} }
if (login->account->ban_end_time && (login->account->ban_end_time >= now())) { if (login->account->ban_end_time && (login->account->ban_end_time >= phosg::now())) {
throw invalid_argument("user is banned"); throw invalid_argument("user is banned");
} }
if (is_shared) { if (is_shared) {
@@ -599,7 +599,7 @@ shared_ptr<Login> AccountIndex::from_gc_credentials_locked(
if (password && (login->gc_license->password != *password)) { if (password && (login->gc_license->password != *password)) {
throw incorrect_password(); throw incorrect_password();
} }
if (login->account->ban_end_time && (login->account->ban_end_time >= now())) { if (login->account->ban_end_time && (login->account->ban_end_time >= phosg::now())) {
throw invalid_argument("user is banned"); throw invalid_argument("user is banned");
} }
if (is_shared) { if (is_shared) {
@@ -652,7 +652,7 @@ shared_ptr<Login> AccountIndex::from_xb_credentials_locked(const string& gamerta
(login->xb_license->account_id && (login->xb_license->account_id != account_id))) { (login->xb_license->account_id && (login->xb_license->account_id != account_id))) {
throw incorrect_access_key(); throw incorrect_access_key();
} }
if (login->account->ban_end_time && (login->account->ban_end_time >= now())) { if (login->account->ban_end_time && (login->account->ban_end_time >= phosg::now())) {
throw invalid_argument("user is banned"); throw invalid_argument("user is banned");
} }
return login; return login;
@@ -680,7 +680,7 @@ shared_ptr<Login> AccountIndex::from_xb_credentials(
auto login = make_shared<Login>(); auto login = make_shared<Login>();
login->account_was_created = true; login->account_was_created = true;
login->account = make_shared<Account>(); login->account = make_shared<Account>();
login->account->account_id = fnv1a32(gamertag) & 0x7FFFFFFF; login->account->account_id = phosg::fnv1a32(gamertag) & 0x7FFFFFFF;
auto lic = make_shared<XBLicense>(); auto lic = make_shared<XBLicense>();
lic->gamertag = gamertag; lic->gamertag = gamertag;
lic->user_id = user_id; lic->user_id = user_id;
@@ -701,7 +701,7 @@ shared_ptr<Login> AccountIndex::from_bb_credentials_locked(const string& usernam
if (password && (login->bb_license->password != *password)) { if (password && (login->bb_license->password != *password)) {
throw incorrect_password(); throw incorrect_password();
} }
if (login->account->ban_end_time && (login->account->ban_end_time >= now())) { if (login->account->ban_end_time && (login->account->ban_end_time >= phosg::now())) {
throw invalid_argument("user is banned"); throw invalid_argument("user is banned");
} }
return login; return login;
@@ -728,7 +728,7 @@ shared_ptr<Login> AccountIndex::from_bb_credentials(const string& username, cons
auto login = make_shared<Login>(); auto login = make_shared<Login>();
login->account_was_created = true; login->account_was_created = true;
login->account = make_shared<Account>(); login->account = make_shared<Account>();
login->account->account_id = fnv1a32(username) & 0x7FFFFFFF; login->account->account_id = phosg::fnv1a32(username) & 0x7FFFFFFF;
auto lic = make_shared<BBLicense>(); auto lic = make_shared<BBLicense>();
lic->username = username; lic->username = username;
lic->password = *password; lic->password = *password;
@@ -976,24 +976,24 @@ shared_ptr<Account> AccountIndex::create_temporary_account_for_shared_account(
shared_ptr<const Account> src_a, const string& variation_data) const { shared_ptr<const Account> src_a, const string& variation_data) const {
auto ret = make_shared<Account>(*src_a); auto ret = make_shared<Account>(*src_a);
ret->is_temporary = true; ret->is_temporary = true;
ret->account_id = fnv1a32(&src_a->account_id, sizeof(src_a->account_id)); ret->account_id = phosg::fnv1a32(&src_a->account_id, sizeof(src_a->account_id));
ret->account_id = fnv1a32(variation_data, ret->account_id); ret->account_id = phosg::fnv1a32(variation_data, ret->account_id);
return ret; return ret;
} }
AccountIndex::AccountIndex(bool force_all_temporary) AccountIndex::AccountIndex(bool force_all_temporary)
: force_all_temporary(force_all_temporary) { : force_all_temporary(force_all_temporary) {
if (!this->force_all_temporary) { if (!this->force_all_temporary) {
if (!isdir("system/licenses")) { if (!phosg::isdir("system/licenses")) {
mkdir("system/licenses", 0755); mkdir("system/licenses", 0755);
} else { } else {
for (const auto& item : list_directory("system/licenses")) { for (const auto& item : phosg::list_directory("system/licenses")) {
if (ends_with(item, ".json")) { if (phosg::ends_with(item, ".json")) {
try { try {
JSON json = JSON::parse(load_file("system/licenses/" + item)); phosg::JSON json = phosg::JSON::parse(phosg::load_file("system/licenses/" + item));
this->add(make_shared<Account>(json)); this->add(make_shared<Account>(json));
} catch (const exception& e) { } catch (const exception& e) {
log_error("Failed to index account %s", item.c_str()); phosg::log_error("Failed to index account %s", item.c_str());
throw; throw;
} }
} }
+12 -12
View File
@@ -16,16 +16,16 @@ struct DCNTELicense {
std::string serial_number; std::string serial_number;
std::string access_key; std::string access_key;
static std::shared_ptr<DCNTELicense> from_json(const JSON& json); static std::shared_ptr<DCNTELicense> from_json(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
}; };
struct V1V2License { struct V1V2License {
uint32_t serial_number = 0; uint32_t serial_number = 0;
std::string access_key; std::string access_key;
static std::shared_ptr<V1V2License> from_json(const JSON& json); static std::shared_ptr<V1V2License> from_json(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
}; };
struct GCLicense { struct GCLicense {
@@ -33,8 +33,8 @@ struct GCLicense {
std::string access_key; std::string access_key;
std::string password; std::string password;
static std::shared_ptr<GCLicense> from_json(const JSON& json); static std::shared_ptr<GCLicense> from_json(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
}; };
struct XBLicense { struct XBLicense {
@@ -42,16 +42,16 @@ struct XBLicense {
uint64_t user_id = 0; uint64_t user_id = 0;
uint64_t account_id = 0; uint64_t account_id = 0;
static std::shared_ptr<XBLicense> from_json(const JSON& json); static std::shared_ptr<XBLicense> from_json(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
}; };
struct BBLicense { struct BBLicense {
std::string username; std::string username;
std::string password; std::string password;
static std::shared_ptr<BBLicense> from_json(const JSON& json); static std::shared_ptr<BBLicense> from_json(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
}; };
struct Account { struct Account {
@@ -101,10 +101,10 @@ struct Account {
std::unordered_map<std::string, std::shared_ptr<BBLicense>> bb_licenses; std::unordered_map<std::string, std::shared_ptr<BBLicense>> bb_licenses;
Account() = default; Account() = default;
explicit Account(const JSON& json); explicit Account(const phosg::JSON& json);
virtual ~Account() = default; virtual ~Account() = default;
JSON json() const; phosg::JSON json() const;
virtual void save() const; virtual void save() const;
virtual void delete_file() const; virtual void delete_file() const;
+13 -13
View File
@@ -108,11 +108,11 @@ public:
: log("[addr-trans] "), : log("[addr-trans] "),
directory(directory), directory(directory),
enable_ppc(false) { enable_ppc(false) {
while (ends_with(this->directory, "/")) { while (phosg::ends_with(this->directory, "/")) {
this->directory.pop_back(); this->directory.pop_back();
} }
for (const auto& filename : list_directory(this->directory)) { for (const auto& filename : phosg::list_directory(this->directory)) {
if (ends_with(filename, ".dol")) { if (phosg::ends_with(filename, ".dol")) {
string name = filename.substr(0, filename.size() - 4); string name = filename.substr(0, filename.size() - 4);
string path = directory + "/" + filename; string path = directory + "/" + filename;
ResourceDASM::DOLFile dol(path.c_str()); ResourceDASM::DOLFile dol(path.c_str());
@@ -121,7 +121,7 @@ public:
this->mems.emplace(name, mem); this->mems.emplace(name, mem);
this->enable_ppc = true; this->enable_ppc = true;
this->log.info("Loaded %s", name.c_str()); this->log.info("Loaded %s", name.c_str());
} else if (ends_with(filename, ".xbe")) { } else if (phosg::ends_with(filename, ".xbe")) {
string name = filename.substr(0, filename.size() - 4); string name = filename.substr(0, filename.size() - 4);
string path = directory + "/" + filename; string path = directory + "/" + filename;
ResourceDASM::XBEFile xbe(path.c_str()); ResourceDASM::XBEFile xbe(path.c_str());
@@ -129,10 +129,10 @@ public:
xbe.load_into(mem); xbe.load_into(mem);
this->mems.emplace(name, mem); this->mems.emplace(name, mem);
this->log.info("Loaded %s", name.c_str()); this->log.info("Loaded %s", name.c_str());
} else if (ends_with(filename, ".bin")) { } else if (phosg::ends_with(filename, ".bin")) {
string name = filename.substr(0, filename.size() - 4); string name = filename.substr(0, filename.size() - 4);
string path = directory + "/" + filename; string path = directory + "/" + filename;
string data = load_file(path); string data = phosg::load_file(path);
auto mem = make_shared<ResourceDASM::MemoryContext>(); auto mem = make_shared<ResourceDASM::MemoryContext>();
mem->allocate_at(0x8C010000, data.size()); mem->allocate_at(0x8C010000, data.size());
mem->memcpy(0x8C010000, data.data(), data.size()); mem->memcpy(0x8C010000, data.data(), data.size());
@@ -160,7 +160,7 @@ public:
uint32_t r2 = 0; uint32_t r2 = 0;
uint32_t r13 = 0; uint32_t r13 = 0;
for (const auto& block : it.second->allocated_blocks()) { for (const auto& block : it.second->allocated_blocks()) {
StringReader r = it.second->reader(block.first, block.second); phosg::StringReader r = it.second->reader(block.first, block.second);
while (!r.eof() && r.where()) { while (!r.eof() && r.where()) {
uint32_t opcode = r.get_u32b(); uint32_t opcode = r.get_u32b();
if ((opcode & 0xFFFF0000) == 0x3DA00000) { if ((opcode & 0xFFFF0000) == 0x3DA00000) {
@@ -243,13 +243,13 @@ public:
size_t num_matches = 0; size_t num_matches = 0;
size_t last_match_address = 0; size_t last_match_address = 0;
size_t match_length = match_bytes_before + match_bytes_after + 4; size_t match_length = match_bytes_before + match_bytes_after + 4;
StringReader src_r = this->src_mem->reader(src_section.first + src_offset - match_bytes_before, match_length); phosg::StringReader src_r = this->src_mem->reader(src_section.first + src_offset - match_bytes_before, match_length);
for (const auto& dest_section : dest_mem->allocated_blocks()) { for (const auto& dest_section : dest_mem->allocated_blocks()) {
for (size_t dest_match_offset = 0; for (size_t dest_match_offset = 0;
dest_match_offset + match_length < dest_section.second; dest_match_offset + match_length < dest_section.second;
dest_match_offset += (is_ppc ? 4 : 1)) { dest_match_offset += (is_ppc ? 4 : 1)) {
src_r.go(0); src_r.go(0);
StringReader dest_r = dest_mem->reader(dest_section.first + dest_match_offset, match_length); phosg::StringReader dest_r = dest_mem->reader(dest_section.first + dest_match_offset, match_length);
size_t z; size_t z;
if (is_ppc) { if (is_ppc) {
for (z = 0; z < match_length; z += 4) { for (z = 0; z < match_length; z += 4) {
@@ -429,11 +429,11 @@ public:
} }
void handle_command(const string& command) { void handle_command(const string& command) {
auto tokens = split(command, ' '); auto tokens = phosg::split(command, ' ');
if (tokens.empty()) { if (tokens.empty()) {
throw runtime_error("no command given"); throw runtime_error("no command given");
} }
strip_trailing_whitespace(tokens[tokens.size() - 1]); phosg::strip_trailing_whitespace(tokens[tokens.size() - 1]);
if (tokens[0] == "use") { if (tokens[0] == "use") {
this->set_source_file(tokens.at(1)); this->set_source_file(tokens.at(1));
@@ -457,7 +457,7 @@ public:
} }
fflush(stdout); fflush(stdout);
string command = fgets(stdin); string command = phosg::fgets(stdin);
try { try {
this->handle_command(command); this->handle_command(command);
} catch (const exception& e) { } catch (const exception& e) {
@@ -468,7 +468,7 @@ public:
} }
private: private:
PrefixedLogger log; phosg::PrefixedLogger log;
string directory; string directory;
unordered_map<string, shared_ptr<const ResourceDASM::MemoryContext>> mems; unordered_map<string, shared_ptr<const ResourceDASM::MemoryContext>> mems;
string src_filename; string src_filename;
+14 -17
View File
@@ -5,15 +5,14 @@
#include <stdexcept> #include <stdexcept>
#include "Text.hh" #include "Text.hh"
#include "Types.hh"
using namespace std; using namespace std;
template <bool IsBigEndian> template <bool BE>
struct BMLHeaderT { struct BMLHeaderT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
parray<uint8_t, 0x04> unknown_a1; parray<uint8_t, 0x04> unknown_a1;
U32T num_entries; U32T<BE> num_entries;
parray<uint8_t, 0x38> unknown_a2; parray<uint8_t, 0x38> unknown_a2;
} __packed__; } __packed__;
@@ -22,16 +21,14 @@ using BMLHeaderBE = BMLHeaderT<true>;
check_struct_size(BMLHeader, 0x40); check_struct_size(BMLHeader, 0x40);
check_struct_size(BMLHeaderBE, 0x40); check_struct_size(BMLHeaderBE, 0x40);
template <bool IsBigEndian> template <bool BE>
struct BMLHeaderEntryT { struct BMLHeaderEntryT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
pstring<TextEncoding::ASCII, 0x20> filename; pstring<TextEncoding::ASCII, 0x20> filename;
U32T compressed_size; U32T<BE> compressed_size;
parray<uint8_t, 0x04> unknown_a1; parray<uint8_t, 0x04> unknown_a1;
U32T decompressed_size; U32T<BE> decompressed_size;
U32T compressed_gvm_size; U32T<BE> compressed_gvm_size;
U32T decompressed_gvm_size; U32T<BE> decompressed_gvm_size;
parray<uint8_t, 0x0C> unknown_a2; parray<uint8_t, 0x0C> unknown_a2;
} __packed__; } __packed__;
@@ -40,15 +37,15 @@ using BMLHeaderEntryBE = BMLHeaderEntryT<true>;
check_struct_size(BMLHeaderEntry, 0x40); check_struct_size(BMLHeaderEntry, 0x40);
check_struct_size(BMLHeaderEntryBE, 0x40); check_struct_size(BMLHeaderEntryBE, 0x40);
template <bool IsBigEndian> template <bool BE>
void BMLArchive::load_t() { void BMLArchive::load_t() {
StringReader r(*this->data); phosg::StringReader r(*this->data);
const auto& header = r.get<BMLHeaderT<IsBigEndian>>(); const auto& header = r.get<BMLHeaderT<BE>>();
size_t offset = 0x800; size_t offset = 0x800;
while (this->entries.size() < header.num_entries) { while (this->entries.size() < header.num_entries) {
const auto& entry = r.get<BMLHeaderEntryT<IsBigEndian>>(); const auto& entry = r.get<BMLHeaderEntryT<BE>>();
if (offset + entry.compressed_size > this->data->size()) { if (offset + entry.compressed_size > this->data->size()) {
throw runtime_error("BML data entry extends beyond end of data"); throw runtime_error("BML data entry extends beyond end of data");
@@ -106,10 +103,10 @@ string BMLArchive::get_copy(const string& name) const {
} }
} }
StringReader BMLArchive::get_reader(const string& name) const { phosg::StringReader BMLArchive::get_reader(const string& name) const {
try { try {
const auto& entry = this->entries.at(name); const auto& entry = this->entries.at(name);
return StringReader(this->data->data() + entry.offset, entry.size); return phosg::StringReader(this->data->data() + entry.offset, entry.size);
} catch (const out_of_range&) { } catch (const out_of_range&) {
throw out_of_range("BML does not contain file: " + name); throw out_of_range("BML does not contain file: " + name);
} }
+2 -2
View File
@@ -24,10 +24,10 @@ public:
std::pair<const void*, size_t> get(const std::string& name) const; std::pair<const void*, size_t> get(const std::string& name) const;
std::pair<const void*, size_t> get_gvm(const std::string& name) const; std::pair<const void*, size_t> get_gvm(const std::string& name) const;
std::string get_copy(const std::string& name) const; std::string get_copy(const std::string& name) const;
StringReader get_reader(const std::string& name) const; phosg::StringReader get_reader(const std::string& name) const;
private: private:
template <bool IsBigEndian> template <bool BE>
void load_t(); void load_t();
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
+1 -1
View File
@@ -54,7 +54,7 @@ BattleParamsIndex::BattleParamsIndex(
for (uint8_t episode = 0; episode < 3; episode++) { for (uint8_t episode = 0; episode < 3; episode++) {
auto& file = this->files[is_solo][episode]; auto& file = this->files[is_solo][episode];
if (file.data->size() < sizeof(Table)) { if (file.data->size() < sizeof(Table)) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"battle params table size is incorrect (expected %zX bytes, have %zX bytes; is_solo=%hhu, episode=%hhu)", "battle params table size is incorrect (expected %zX bytes, have %zX bytes; is_solo=%hhu, episode=%hhu)",
sizeof(Table), file.data->size(), is_solo, episode)); sizeof(Table), file.data->size(), is_solo, episode));
} }
+7 -8
View File
@@ -38,7 +38,7 @@ CatSession::CatSession(
const struct sockaddr_storage& remote, const struct sockaddr_storage& remote,
Version version, Version version,
shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file) shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file)
: log(string_printf("[CatSession:%s] ", name_for_enum(version)), proxy_server_log.min_level), : log(phosg::string_printf("[CatSession:%s] ", phosg::name_for_enum(version)), proxy_server_log.min_level),
base(base), base(base),
read_event(event_new(this->base.get(), 0, EV_READ | EV_PERSIST, CatSession::dispatch_read_stdin, this), event_free), read_event(event_new(this->base.get(), 0, EV_READ | EV_PERSIST, CatSession::dispatch_read_stdin, this), event_free),
channel(version, 1, CatSession::dispatch_on_channel_input, CatSession::dispatch_on_channel_error, this, "CatSession"), channel(version, 1, CatSession::dispatch_on_channel_input, CatSession::dispatch_on_channel_error, this, "CatSession"),
@@ -48,19 +48,19 @@ CatSession::CatSession(
throw runtime_error("remote is not AF_INET"); throw runtime_error("remote is not AF_INET");
} }
string netloc_str = render_sockaddr_storage(remote); string netloc_str = phosg::render_sockaddr_storage(remote);
this->log.info("Connecting to %s", netloc_str.c_str()); this->log.info("Connecting to %s", netloc_str.c_str());
struct bufferevent* bev = bufferevent_socket_new( struct bufferevent* bev = bufferevent_socket_new(
this->base.get(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); this->base.get(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
if (!bev) { if (!bev) {
throw runtime_error(string_printf("failed to open socket (%d)", EVUTIL_SOCKET_ERROR())); throw runtime_error(phosg::string_printf("failed to open socket (%d)", EVUTIL_SOCKET_ERROR()));
} }
this->channel.set_bufferevent(bev, 0); this->channel.set_bufferevent(bev, 0);
if (bufferevent_socket_connect(this->channel.bev.get(), if (bufferevent_socket_connect(this->channel.bev.get(),
reinterpret_cast<const sockaddr*>(&remote), sizeof(struct sockaddr_in)) != 0) { reinterpret_cast<const sockaddr*>(&remote), sizeof(struct sockaddr_in)) != 0) {
throw runtime_error(string_printf("failed to connect (%d)", EVUTIL_SOCKET_ERROR())); throw runtime_error(phosg::string_printf("failed to connect (%d)", EVUTIL_SOCKET_ERROR()));
} }
event_add(this->read_event.get(), nullptr); event_add(this->read_event.get(), nullptr);
@@ -68,7 +68,7 @@ CatSession::CatSession(
} }
void CatSession::execute_command(const std::string& command) { void CatSession::execute_command(const std::string& command) {
string full_cmd = parse_data_string(command, nullptr, ParseDataFlags::ALLOW_FILES); string full_cmd = phosg::parse_data_string(command, nullptr, phosg::ParseDataFlags::ALLOW_FILES);
send_command_with_header(this->channel, full_cmd.data(), full_cmd.size()); send_command_with_header(this->channel, full_cmd.data(), full_cmd.size());
} }
@@ -109,9 +109,8 @@ void CatSession::on_channel_input(
// TODO: Use the iovec form of print_data here instead of // TODO: Use the iovec form of print_data here instead of
// prepend_command_header (which copies the string) // prepend_command_header (which copies the string)
string full_cmd = prepend_command_header( string full_cmd = prepend_command_header(this->channel.version, this->channel.crypt_in.get(), command, flag, data);
this->channel.version, this->channel.crypt_in.get(), command, flag, data); phosg::print_data(stdout, full_cmd, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
print_data(stdout, full_cmd, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS);
} }
void CatSession::dispatch_on_channel_error(Channel& ch, short events) { void CatSession::dispatch_on_channel_error(Channel& ch, short events) {
+2 -2
View File
@@ -29,10 +29,10 @@ public:
virtual ~CatSession() = default; virtual ~CatSession() = default;
protected: protected:
PrefixedLogger log; phosg::PrefixedLogger log;
std::shared_ptr<struct event_base> base; std::shared_ptr<struct event_base> base;
std::unique_ptr<struct event, void (*)(struct event*)> read_event; std::unique_ptr<struct event, void (*)(struct event*)> read_event;
Poll poll; phosg::Poll poll;
Channel channel; Channel channel;
std::shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file; std::shared_ptr<const PSOBBEncryption::KeyFile> bb_key_file;
+19 -19
View File
@@ -29,8 +29,8 @@ Channel::Channel(
on_error_t on_error, on_error_t on_error,
void* context_obj, void* context_obj,
const string& name, const string& name,
TerminalFormat terminal_send_color, phosg::TerminalFormat terminal_send_color,
TerminalFormat terminal_recv_color) phosg::TerminalFormat terminal_recv_color)
: bev(nullptr, flush_and_free_bufferevent), : bev(nullptr, flush_and_free_bufferevent),
virtual_network_id(0), virtual_network_id(0),
version(version), version(version),
@@ -52,8 +52,8 @@ Channel::Channel(
on_error_t on_error, on_error_t on_error,
void* context_obj, void* context_obj,
const string& name, const string& name,
TerminalFormat terminal_send_color, phosg::TerminalFormat terminal_send_color,
TerminalFormat terminal_recv_color) phosg::TerminalFormat terminal_recv_color)
: bev(nullptr, flush_and_free_bufferevent), : bev(nullptr, flush_and_free_bufferevent),
version(version), version(version),
language(language), language(language),
@@ -98,7 +98,7 @@ void Channel::set_bufferevent(struct bufferevent* bev, uint64_t virtual_network_
memset(&this->local_addr, 0, sizeof(this->local_addr)); memset(&this->local_addr, 0, sizeof(this->local_addr));
memset(&this->remote_addr, 0, sizeof(this->remote_addr)); memset(&this->remote_addr, 0, sizeof(this->remote_addr));
} else { } else {
get_socket_addresses(fd, &this->local_addr, &this->remote_addr); phosg::get_socket_addresses(fd, &this->local_addr, &this->remote_addr);
} }
bufferevent_setcb(this->bev.get(), &Channel::dispatch_on_input, nullptr, &Channel::dispatch_on_error, this); bufferevent_setcb(this->bev.get(), &Channel::dispatch_on_input, nullptr, &Channel::dispatch_on_error, this);
@@ -206,9 +206,9 @@ Channel::Message Channel::recv() {
} }
command_data.resize(command_logical_size - header_size); command_data.resize(command_logical_size - header_size);
if (command_data_log.should_log(LogLevel::INFO) && (this->terminal_recv_color != TerminalFormat::END)) { if (command_data_log.should_log(phosg::LogLevel::INFO) && (this->terminal_recv_color != phosg::TerminalFormat::END)) {
if (use_terminal_colors && this->terminal_recv_color != TerminalFormat::NORMAL) { if (use_terminal_colors && this->terminal_recv_color != phosg::TerminalFormat::NORMAL) {
print_color_escape(stderr, this->terminal_recv_color, TerminalFormat::BOLD, TerminalFormat::END); print_color_escape(stderr, this->terminal_recv_color, phosg::TerminalFormat::BOLD, phosg::TerminalFormat::END);
} }
if (version == Version::BB_V4) { if (version == Version::BB_V4) {
@@ -221,7 +221,7 @@ Channel::Message Channel::recv() {
command_data_log.info( command_data_log.info(
"Received from %s (version=%s command=%02hX flag=%02" PRIX32 ")", "Received from %s (version=%s command=%02hX flag=%02" PRIX32 ")",
this->name.c_str(), this->name.c_str(),
name_for_enum(this->version), phosg::name_for_enum(this->version),
header.command(this->version), header.command(this->version),
header.flag(this->version)); header.flag(this->version));
} }
@@ -229,10 +229,10 @@ Channel::Message Channel::recv() {
vector<struct iovec> iovs; vector<struct iovec> iovs;
iovs.emplace_back(iovec{.iov_base = header_data.data(), .iov_len = header_data.size()}); iovs.emplace_back(iovec{.iov_base = header_data.data(), .iov_len = header_data.size()});
iovs.emplace_back(iovec{.iov_base = command_data.data(), .iov_len = command_data.size()}); iovs.emplace_back(iovec{.iov_base = command_data.data(), .iov_len = command_data.size()});
print_data(stderr, iovs, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, iovs, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
if (use_terminal_colors && this->terminal_recv_color != TerminalFormat::NORMAL) { if (use_terminal_colors && this->terminal_recv_color != phosg::TerminalFormat::NORMAL) {
print_color_escape(stderr, TerminalFormat::NORMAL, TerminalFormat::END); phosg::print_color_escape(stderr, phosg::TerminalFormat::NORMAL, phosg::TerminalFormat::END);
} }
} }
@@ -342,20 +342,20 @@ void Channel::send(uint16_t cmd, uint32_t flag, const std::vector<std::pair<cons
} }
send_data.resize(send_data_size, '\0'); send_data.resize(send_data_size, '\0');
if (!silent && (command_data_log.should_log(LogLevel::INFO)) && (this->terminal_send_color != TerminalFormat::END)) { if (!silent && (command_data_log.should_log(phosg::LogLevel::INFO)) && (this->terminal_send_color != phosg::TerminalFormat::END)) {
if (use_terminal_colors && this->terminal_send_color != TerminalFormat::NORMAL) { if (use_terminal_colors && this->terminal_send_color != phosg::TerminalFormat::NORMAL) {
print_color_escape(stderr, TerminalFormat::FG_YELLOW, TerminalFormat::BOLD, TerminalFormat::END); print_color_escape(stderr, phosg::TerminalFormat::FG_YELLOW, phosg::TerminalFormat::BOLD, phosg::TerminalFormat::END);
} }
if (version == Version::BB_V4) { if (version == Version::BB_V4) {
command_data_log.info("Sending to %s (version=BB command=%04hX flag=%08" PRIX32 ")", command_data_log.info("Sending to %s (version=BB command=%04hX flag=%08" PRIX32 ")",
this->name.c_str(), cmd, flag); this->name.c_str(), cmd, flag);
} else { } else {
command_data_log.info("Sending to %s (version=%s command=%02hX flag=%02" PRIX32 ")", command_data_log.info("Sending to %s (version=%s command=%02hX flag=%02" PRIX32 ")",
this->name.c_str(), name_for_enum(version), cmd, flag); this->name.c_str(), phosg::name_for_enum(version), cmd, flag);
} }
print_data(stderr, send_data.data(), logical_size, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, send_data.data(), logical_size, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
if (use_terminal_colors && this->terminal_send_color != TerminalFormat::NORMAL) { if (use_terminal_colors && this->terminal_send_color != phosg::TerminalFormat::NORMAL) {
print_color_escape(stderr, TerminalFormat::NORMAL, TerminalFormat::END); print_color_escape(stderr, phosg::TerminalFormat::NORMAL, phosg::TerminalFormat::END);
} }
} }
+6 -6
View File
@@ -21,8 +21,8 @@ struct Channel {
std::shared_ptr<PSOEncryption> crypt_out; std::shared_ptr<PSOEncryption> crypt_out;
std::string name; std::string name;
TerminalFormat terminal_send_color; phosg::TerminalFormat terminal_send_color;
TerminalFormat terminal_recv_color; phosg::TerminalFormat terminal_recv_color;
struct Message { struct Message {
uint16_t command; uint16_t command;
@@ -45,8 +45,8 @@ struct Channel {
on_error_t on_error, on_error_t on_error,
void* context_obj, void* context_obj,
const std::string& name, const std::string& name,
TerminalFormat terminal_send_color = TerminalFormat::END, phosg::TerminalFormat terminal_send_color = phosg::TerminalFormat::END,
TerminalFormat terminal_recv_color = TerminalFormat::END); phosg::TerminalFormat terminal_recv_color = phosg::TerminalFormat::END);
// Creates a connected channel // Creates a connected channel
Channel( Channel(
struct bufferevent* bev, struct bufferevent* bev,
@@ -57,8 +57,8 @@ struct Channel {
on_error_t on_error, on_error_t on_error,
void* context_obj, void* context_obj,
const std::string& name = "", const std::string& name = "",
TerminalFormat terminal_send_color = TerminalFormat::END, phosg::TerminalFormat terminal_send_color = phosg::TerminalFormat::END,
TerminalFormat terminal_recv_color = TerminalFormat::END); phosg::TerminalFormat terminal_recv_color = phosg::TerminalFormat::END);
Channel(const Channel& other) = delete; Channel(const Channel& other) = delete;
Channel(Channel&& other) = delete; Channel(Channel&& other) = delete;
Channel& operator=(const Channel& other) = delete; Channel& operator=(const Channel& other) = delete;
+48 -48
View File
@@ -103,7 +103,7 @@ static void check_is_leader(shared_ptr<Lobby> l, shared_ptr<Client> c) {
static void server_command_server_info(shared_ptr<Client> c, const std::string&) { static void server_command_server_info(shared_ptr<Client> c, const std::string&) {
auto s = c->require_server_state(); auto s = c->require_server_state();
string uptime_str = format_duration(now() - s->creation_time); string uptime_str = phosg::format_duration(phosg::now() - s->creation_time);
send_text_message_printf(c, send_text_message_printf(c,
"Uptime: $C6%s$C7\nLobbies: $C6%zu$C7\nClients: $C6%zu$C7(g) $C6%zu$C7(p)", "Uptime: $C6%s$C7\nLobbies: $C6%zu$C7\nClients: $C6%zu$C7(g) $C6%zu$C7(p)",
uptime_str.c_str(), uptime_str.c_str(),
@@ -123,11 +123,11 @@ static void server_command_lobby_info(shared_ptr<Client> c, const std::string&)
if (l->is_game()) { if (l->is_game()) {
if (!l->is_ep3()) { if (!l->is_ep3()) {
if (l->max_level == 0xFFFFFFFF) { if (l->max_level == 0xFFFFFFFF) {
lines.emplace_back(string_printf("$C6%08X$C7 L$C6%d+$C7", l->lobby_id, l->min_level + 1)); lines.emplace_back(phosg::string_printf("$C6%08X$C7 L$C6%d+$C7", l->lobby_id, l->min_level + 1));
} else { } else {
lines.emplace_back(string_printf("$C6%08X$C7 L$C6%d-%d$C7", l->lobby_id, l->min_level + 1, l->max_level + 1)); lines.emplace_back(phosg::string_printf("$C6%08X$C7 L$C6%d-%d$C7", l->lobby_id, l->min_level + 1, l->max_level + 1));
} }
lines.emplace_back(string_printf("$C7Section ID: $C6%s$C7", name_for_section_id(l->effective_section_id()))); lines.emplace_back(phosg::string_printf("$C7Section ID: $C6%s$C7", name_for_section_id(l->effective_section_id())));
switch (l->drop_mode) { switch (l->drop_mode) {
case Lobby::DropMode::DISABLED: case Lobby::DropMode::DISABLED:
@@ -153,45 +153,45 @@ static void server_command_lobby_info(shared_ptr<Client> c, const std::string&)
} }
} else { } else {
lines.emplace_back(string_printf("$C7State seed: $C6%08X$C7", l->random_seed)); lines.emplace_back(phosg::string_printf("$C7State seed: $C6%08X$C7", l->random_seed));
} }
} else { } else {
lines.emplace_back(string_printf("$C7Lobby ID: $C6%08X$C7", l->lobby_id)); lines.emplace_back(phosg::string_printf("$C7Lobby ID: $C6%08X$C7", l->lobby_id));
} }
string slots_str = "Slots: "; string slots_str = "Slots: ";
for (size_t z = 0; z < l->clients.size(); z++) { for (size_t z = 0; z < l->clients.size(); z++) {
if (!l->clients[z]) { if (!l->clients[z]) {
slots_str += string_printf("$C0%zX$C7", z); slots_str += phosg::string_printf("$C0%zX$C7", z);
} else { } else {
bool is_self = l->clients[z] == c; bool is_self = l->clients[z] == c;
bool is_leader = z == l->leader_id; bool is_leader = z == l->leader_id;
if (is_self && is_leader) { if (is_self && is_leader) {
slots_str += string_printf("$C6%zX$C7", z); slots_str += phosg::string_printf("$C6%zX$C7", z);
} else if (is_self) { } else if (is_self) {
slots_str += string_printf("$C2%zX$C7", z); slots_str += phosg::string_printf("$C2%zX$C7", z);
} else if (is_leader) { } else if (is_leader) {
slots_str += string_printf("$C4%zX$C7", z); slots_str += phosg::string_printf("$C4%zX$C7", z);
} else { } else {
slots_str += string_printf("%zX", z); slots_str += phosg::string_printf("%zX", z);
} }
} }
} }
lines.emplace_back(std::move(slots_str)); lines.emplace_back(std::move(slots_str));
} }
send_text_message(c, join(lines, "\n")); send_text_message(c, phosg::join(lines, "\n"));
} }
static void server_command_ping(shared_ptr<Client> c, const std::string&) { static void server_command_ping(shared_ptr<Client> c, const std::string&) {
c->ping_start_time = now(); c->ping_start_time = phosg::now();
send_command(c, 0x1D, 0x00); send_command(c, 0x1D, 0x00);
} }
static void proxy_command_ping(shared_ptr<ProxyServer::LinkedSession> ses, const std::string&) { static void proxy_command_ping(shared_ptr<ProxyServer::LinkedSession> ses, const std::string&) {
ses->client_ping_start_time = now(); ses->client_ping_start_time = phosg::now();
ses->server_ping_start_time = now(); ses->server_ping_start_time = ses->client_ping_start_time;
C_GuildCardSearch_40 cmd = {0x00010000, ses->remote_guild_card_number, ses->remote_guild_card_number}; C_GuildCardSearch_40 cmd = {0x00010000, ses->remote_guild_card_number, ses->remote_guild_card_number};
ses->client_channel.send(0x1D, 0x00); ses->client_channel.send(0x1D, 0x00);
@@ -204,7 +204,7 @@ static void proxy_command_lobby_info(shared_ptr<ProxyServer::LinkedSession> ses,
// don't show it. (The user can see it in the pause menu, unlike in masked-GC // don't show it. (The user can see it in the pause menu, unlike in masked-GC
// sessions like GC.) // sessions like GC.)
if (ses->remote_guild_card_number >= 0) { if (ses->remote_guild_card_number >= 0) {
msg = string_printf("$C7GC: $C6%" PRId64 "$C7\n", ses->remote_guild_card_number); msg = phosg::string_printf("$C7GC: $C6%" PRId64 "$C7\n", ses->remote_guild_card_number);
} }
msg += "Slots: "; msg += "Slots: ";
@@ -212,15 +212,15 @@ static void proxy_command_lobby_info(shared_ptr<ProxyServer::LinkedSession> ses,
bool is_self = z == ses->lobby_client_id; bool is_self = z == ses->lobby_client_id;
bool is_leader = z == ses->leader_client_id; bool is_leader = z == ses->leader_client_id;
if (ses->lobby_players[z].guild_card_number == 0) { if (ses->lobby_players[z].guild_card_number == 0) {
msg += string_printf("$C0%zX$C7", z); msg += phosg::string_printf("$C0%zX$C7", z);
} else if (is_self && is_leader) { } else if (is_self && is_leader) {
msg += string_printf("$C6%zX$C7", z); msg += phosg::string_printf("$C6%zX$C7", z);
} else if (is_self) { } else if (is_self) {
msg += string_printf("$C2%zX$C7", z); msg += phosg::string_printf("$C2%zX$C7", z);
} else if (is_leader) { } else if (is_leader) {
msg += string_printf("$C4%zX$C7", z); msg += phosg::string_printf("$C4%zX$C7", z);
} else { } else {
msg += string_printf("%zX", z); msg += phosg::string_printf("%zX", z);
} }
} }
@@ -233,7 +233,7 @@ static void proxy_command_lobby_info(shared_ptr<ProxyServer::LinkedSession> ses,
} }
if (!cheats_tokens.empty()) { if (!cheats_tokens.empty()) {
msg += "\n$C7Cheats: $C6"; msg += "\n$C7Cheats: $C6";
msg += join(cheats_tokens, ","); msg += phosg::join(cheats_tokens, ",");
} }
vector<const char*> behaviors_tokens; vector<const char*> behaviors_tokens;
@@ -251,7 +251,7 @@ static void proxy_command_lobby_info(shared_ptr<ProxyServer::LinkedSession> ses,
} }
if (!behaviors_tokens.empty()) { if (!behaviors_tokens.empty()) {
msg += "\n$C7Flags: $C6"; msg += "\n$C7Flags: $C6";
msg += join(behaviors_tokens, ","); msg += phosg::join(behaviors_tokens, ",");
} }
if (ses->config.override_section_id != 0xFF) { if (ses->config.override_section_id != 0xFF) {
@@ -353,7 +353,7 @@ static void server_command_swset_swclear(shared_ptr<Client> c, const std::string
return; return;
} }
auto tokens = split(args, ' '); auto tokens = phosg::split(args, ' ');
uint8_t floor, flag_num; uint8_t floor, flag_num;
if (tokens.size() == 1) { if (tokens.size() == 1) {
floor = c->floor; floor = c->floor;
@@ -391,7 +391,7 @@ static void proxy_command_swset_swclear(shared_ptr<ProxyServer::LinkedSession> s
return; return;
} }
auto tokens = split(args, ' '); auto tokens = phosg::split(args, ' ');
uint8_t floor, flag_num; uint8_t floor, flag_num;
if (tokens.size() == 1) { if (tokens.size() == 1) {
floor = ses->floor; floor = ses->floor;
@@ -589,7 +589,7 @@ static void server_command_qgwrite(shared_ptr<Client> c, const std::string& args
return; return;
} }
auto tokens = split(args, ' '); auto tokens = phosg::split(args, ' ');
if (tokens.size() != 2) { if (tokens.size() != 2) {
send_text_message(c, "$C6Incorrect number\nof arguments"); send_text_message(c, "$C6Incorrect number\nof arguments");
return; return;
@@ -616,7 +616,7 @@ static void server_command_qsync_qsyncall(shared_ptr<Client> c, const std::strin
return; return;
} }
auto tokens = split(args, ' '); auto tokens = phosg::split(args, ' ');
if (tokens.size() != 2) { if (tokens.size() != 2) {
send_text_message(c, "$C6Incorrect number of\narguments"); send_text_message(c, "$C6Incorrect number of\narguments");
return; return;
@@ -655,7 +655,7 @@ static void proxy_command_qsync_qsyncall(shared_ptr<ProxyServer::LinkedSession>
return; return;
} }
auto tokens = split(args, ' '); auto tokens = phosg::split(args, ' ');
if (tokens.size() != 2) { if (tokens.size() != 2) {
send_text_message(ses->client_channel, "$C6Incorrect number of\narguments"); send_text_message(ses->client_channel, "$C6Incorrect number of\narguments");
return; return;
@@ -896,26 +896,26 @@ static void proxy_command_get_player_card(shared_ptr<ProxyServer::LinkedSession>
static void server_command_send_client(shared_ptr<Client> c, const std::string& args) { static void server_command_send_client(shared_ptr<Client> c, const std::string& args) {
check_debug_enabled(c); check_debug_enabled(c);
string data = parse_data_string(args); string data = phosg::parse_data_string(args);
data.resize((data.size() + 3) & (~3)); data.resize((data.size() + 3) & (~3));
c->channel.send(data); c->channel.send(data);
} }
static void server_command_send_server(shared_ptr<Client> c, const std::string& args) { static void server_command_send_server(shared_ptr<Client> c, const std::string& args) {
check_debug_enabled(c); check_debug_enabled(c);
string data = parse_data_string(args); string data = phosg::parse_data_string(args);
data.resize((data.size() + 3) & (~3)); data.resize((data.size() + 3) & (~3));
on_command_with_header(c, data); on_command_with_header(c, data);
} }
static void proxy_command_send_client(shared_ptr<ProxyServer::LinkedSession> ses, const std::string& args) { static void proxy_command_send_client(shared_ptr<ProxyServer::LinkedSession> ses, const std::string& args) {
string data = parse_data_string(args); string data = phosg::parse_data_string(args);
data.resize((data.size() + 3) & (~3)); data.resize((data.size() + 3) & (~3));
ses->client_channel.send(data); ses->client_channel.send(data);
} }
static void proxy_command_send_server(shared_ptr<ProxyServer::LinkedSession> ses, const std::string& args) { static void proxy_command_send_server(shared_ptr<ProxyServer::LinkedSession> ses, const std::string& args) {
string data = parse_data_string(args); string data = phosg::parse_data_string(args);
data.resize((data.size() + 3) & (~3)); data.resize((data.size() + 3) & (~3));
ses->server_channel.send(data); ses->server_channel.send(data);
} }
@@ -1044,7 +1044,7 @@ static string file_path_for_recording(const std::string& args, uint32_t account_
throw runtime_error("invalid recording name"); throw runtime_error("invalid recording name");
} }
} }
return string_printf("system/ep3/battle-records/%010" PRIu32 "_%s.mzrd", account_id, args.c_str()); return phosg::string_printf("system/ep3/battle-records/%010" PRIu32 "_%s.mzrd", account_id, args.c_str());
} }
static void server_command_saverec(shared_ptr<Client> c, const std::string& args) { static void server_command_saverec(shared_ptr<Client> c, const std::string& args) {
@@ -1054,7 +1054,7 @@ static void server_command_saverec(shared_ptr<Client> c, const std::string& args
} }
string file_path = file_path_for_recording(args, c->login->account->account_id); string file_path = file_path_for_recording(args, c->login->account->account_id);
string data = c->ep3_prev_battle_record->serialize(); string data = c->ep3_prev_battle_record->serialize();
save_file(file_path, data); phosg::save_file(file_path, data);
send_text_message(c, "$C7Recording saved"); send_text_message(c, "$C7Recording saved");
c->ep3_prev_battle_record.reset(); c->ep3_prev_battle_record.reset();
} }
@@ -1080,8 +1080,8 @@ static void server_command_playrec(shared_ptr<Client> c, const std::string& args
string data; string data;
try { try {
data = load_file(file_path); data = phosg::load_file(file_path);
} catch (const cannot_open_file&) { } catch (const phosg::cannot_open_file&) {
send_text_message(c, "$C4The recording does\nnot exist"); send_text_message(c, "$C4The recording does\nnot exist");
return; return;
} }
@@ -1307,8 +1307,8 @@ static void server_command_edit(shared_ptr<Client> c, const std::string& args) {
bool cheats_allowed = ((s->cheat_mode_behavior != ServerState::BehaviorSwitch::OFF) || bool cheats_allowed = ((s->cheat_mode_behavior != ServerState::BehaviorSwitch::OFF) ||
c->login->account->check_flag(Account::Flag::CHEAT_ANYWHERE)); c->login->account->check_flag(Account::Flag::CHEAT_ANYWHERE));
string encoded_args = tolower(args); string encoded_args = phosg::tolower(args);
vector<string> tokens = split(encoded_args, ' '); vector<string> tokens = phosg::split(encoded_args, ' ');
try { try {
auto p = c->character(); auto p = c->character();
@@ -1360,7 +1360,7 @@ static void server_command_edit(shared_ptr<Client> c, const std::string& args) {
p->disp.visual.section_id = secid; p->disp.visual.section_id = secid;
} }
} else if (tokens.at(0) == "name") { } else if (tokens.at(0) == "name") {
vector<string> orig_tokens = split(args, ' '); vector<string> orig_tokens = phosg::split(args, ' ');
p->disp.name.encode(orig_tokens.at(1), p->inventory.language); p->disp.name.encode(orig_tokens.at(1), p->inventory.language);
} else if (tokens.at(0) == "npc") { } else if (tokens.at(0) == "npc") {
if (tokens.at(1) == "none") { if (tokens.at(1) == "none") {
@@ -1457,7 +1457,7 @@ static void server_command_bbchar_savechar(shared_ptr<Client> c, const std::stri
auto pending_export = make_unique<Client::PendingCharacterExport>(); auto pending_export = make_unique<Client::PendingCharacterExport>();
if (is_bb_conversion) { if (is_bb_conversion) {
vector<string> tokens = split(args, ' '); vector<string> tokens = phosg::split(args, ' ');
if (tokens.size() != 3) { if (tokens.size() != 3) {
send_text_message(c, "$C6Incorrect argument count"); send_text_message(c, "$C6Incorrect argument count");
return; return;
@@ -1632,7 +1632,7 @@ static string name_for_client(shared_ptr<Client> c) {
} }
if (c->login) { if (c->login) {
return string_printf("SN:%" PRIu32, c->login->account->account_id); return phosg::string_printf("SN:%" PRIu32, c->login->account->account_id);
} }
return "Player"; return "Player";
@@ -1727,7 +1727,7 @@ static void server_command_ban(shared_ptr<Client> c, const std::string& args) {
usecs *= 60 * 60 * 24 * 365; usecs *= 60 * 60 * 24 * 365;
} }
target->login->account->ban_end_time = now() + usecs; target->login->account->ban_end_time = phosg::now() + usecs;
target->login->account->save(); target->login->account->save();
send_message_box(target, "$C6You have been banned."); send_message_box(target, "$C6You have been banned.");
target->should_disconnect = true; target->should_disconnect = true;
@@ -2135,7 +2135,7 @@ static void proxy_command_item(shared_ptr<ProxyServer::LinkedSession> ses, const
bool set_drop = (!args.empty() && (args[0] == '!')); bool set_drop = (!args.empty() && (args[0] == '!'));
ItemData item = s->parse_item_description(ses->version(), (set_drop ? args.substr(1) : args)); ItemData item = s->parse_item_description(ses->version(), (set_drop ? args.substr(1) : args));
item.id = random_object<uint32_t>() | 0x80000000; item.id = phosg::random_object<uint32_t>() | 0x80000000;
if (set_drop) { if (set_drop) {
ses->next_drop_item = item; ses->next_drop_item = item;
@@ -2224,7 +2224,7 @@ static void server_command_ep3_set_dice_range(shared_ptr<Client> c, const std::s
} }
auto parse_dice_range = +[](const string& spec) -> uint8_t { auto parse_dice_range = +[](const string& spec) -> uint8_t {
auto tokens = split(spec, '-'); auto tokens = phosg::split(spec, '-');
if (tokens.size() == 1) { if (tokens.size() == 1) {
uint8_t v = stoull(spec); uint8_t v = stoull(spec);
return (v << 4) | (v & 0x0F); return (v << 4) | (v & 0x0F);
@@ -2238,8 +2238,8 @@ static void server_command_ep3_set_dice_range(shared_ptr<Client> c, const std::s
uint8_t def_dice_range = 0; uint8_t def_dice_range = 0;
uint8_t atk_dice_range_2v1 = 0; uint8_t atk_dice_range_2v1 = 0;
uint8_t def_dice_range_2v1 = 0; uint8_t def_dice_range_2v1 = 0;
for (const auto& spec : split(args, ' ')) { for (const auto& spec : phosg::split(args, ' ')) {
auto tokens = split(spec, ':'); auto tokens = phosg::split(spec, ':');
if (tokens.size() != 2) { if (tokens.size() != 2) {
send_text_message(c, "$C6Invalid dice spec\nformat"); send_text_message(c, "$C6Invalid dice spec\nformat");
return; return;
@@ -2305,7 +2305,7 @@ static void server_command_ep3_replace_assist_card(shared_ptr<Client> c, const s
size_t client_id; size_t client_id;
string card_name; string card_name;
if (isdigit(args[0])) { if (isdigit(args[0])) {
auto tokens = split(args, ' ', 1); auto tokens = phosg::split(args, ' ', 1);
client_id = stoul(tokens.at(0), nullptr, 0) - 1; client_id = stoul(tokens.at(0), nullptr, 0) - 1;
card_name = tokens.at(1); card_name = tokens.at(1);
} else { } else {
@@ -2408,7 +2408,7 @@ static void server_command_get_ep3_battle_stat(shared_ptr<Client> c, const std::
const char* rank_name = ps->stats.name_for_rank(rank); const char* rank_name = ps->stats.name_for_rank(rank);
send_text_message_printf(c, "$C7Score: %g\nRank: %hhu (%s)", score, rank, rank_name); send_text_message_printf(c, "$C7Score: %g\nRank: %hhu (%s)", score, rank, rank_name);
} else if (args == "duration") { } else if (args == "duration") {
string s = format_duration(now() - l->ep3_server->battle_start_usecs); string s = phosg::format_duration(phosg::now() - l->ep3_server->battle_start_usecs);
send_text_message_printf(c, "$C7Duration: %s", s.c_str()); send_text_message_printf(c, "$C7Duration: %s", s.c_str());
} else if (args == "fcs-destroyed") { } else if (args == "fcs-destroyed") {
send_text_message_printf(c, "$C7Team FCs destroyed:\n%" PRIu32, l->ep3_server->team_num_ally_fcs_destroyed[team_id]); send_text_message_printf(c, "$C7Team FCs destroyed:\n%" PRIu32, l->ep3_server->team_num_ally_fcs_destroyed[team_id]);
+7 -9
View File
@@ -7,18 +7,16 @@
#include <vector> #include <vector>
#include "Text.hh" #include "Text.hh"
#include "Types.hh"
class Client; class Client;
template <bool IsBigEndian> template <bool BE>
struct ChoiceSearchConfigT { struct ChoiceSearchConfigT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; U32T<BE> disabled = 1; // 0 = enabled, 1 = disabled. Unused in command C3
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
U32T disabled = 1; // 0 = enabled, 1 = disabled. Unused in command C3
struct Entry { struct Entry {
U16T parent_choice_id = 0; U16T<BE> parent_choice_id = 0;
U16T choice_id = 0; U16T<BE> choice_id = 0;
} __packed_ws__(Entry, 4); } __packed_ws__(Entry, 4);
parray<Entry, 5> entries; parray<Entry, 5> entries;
@@ -31,8 +29,8 @@ struct ChoiceSearchConfigT {
return -1; return -1;
} }
operator ChoiceSearchConfigT<!IsBigEndian>() const { operator ChoiceSearchConfigT<!BE>() const {
ChoiceSearchConfigT<!IsBigEndian> ret; ChoiceSearchConfigT<!BE> ret;
ret.disabled = this->disabled.load(); ret.disabled = this->disabled.load();
for (size_t z = 0; z < this->entries.size(); z++) { for (size_t z = 0; z < this->entries.size(); z++) {
auto& ret_e = ret.entries[z]; auto& ret_e = ret.entries[z];
+53 -53
View File
@@ -144,7 +144,7 @@ void Client::Config::set_flags_for_version(Version version, int64_t sub_version)
this->set_flag(Flag::CAN_RECEIVE_ENABLE_B2_QUEST); this->set_flag(Flag::CAN_RECEIVE_ENABLE_B2_QUEST);
break; break;
default: default:
throw runtime_error(string_printf("unknown sub_version %" PRIX64, sub_version)); throw runtime_error(phosg::string_printf("unknown sub_version %" PRIX64, sub_version));
} }
} }
@@ -188,8 +188,8 @@ Client::Client(
ServerBehavior server_behavior) ServerBehavior server_behavior)
: server(server), : server(server),
id(next_id++), id(next_id++),
log(string_printf("[C-%" PRIX64 "] ", this->id), client_log.min_level), log(phosg::string_printf("[C-%" PRIX64 "] ", this->id), client_log.min_level),
channel(bev, virtual_network_id, version, 1, nullptr, nullptr, this, "", TerminalFormat::FG_YELLOW, TerminalFormat::FG_GREEN), channel(bev, virtual_network_id, version, 1, nullptr, nullptr, this, "", phosg::TerminalFormat::FG_YELLOW, phosg::TerminalFormat::FG_GREEN),
server_behavior(server_behavior), server_behavior(server_behavior),
should_disconnect(false), should_disconnect(false),
should_send_to_lobby_server(false), should_send_to_lobby_server(false),
@@ -248,8 +248,8 @@ Client::Client(
// more annoying than helpful at this point. // more annoying than helpful at this point.
if ((s->hide_download_commands) && if ((s->hide_download_commands) &&
((this->channel.version == Version::PC_PATCH) || (this->channel.version == Version::BB_PATCH))) { ((this->channel.version == Version::PC_PATCH) || (this->channel.version == Version::BB_PATCH))) {
this->channel.terminal_recv_color = TerminalFormat::END; this->channel.terminal_recv_color = phosg::TerminalFormat::END;
this->channel.terminal_send_color = TerminalFormat::END; this->channel.terminal_send_color = phosg::TerminalFormat::END;
} }
this->log.info("Created"); this->log.info("Created");
@@ -276,24 +276,24 @@ void Client::update_channel_name() {
auto player = this->character(false, false); auto player = this->character(false, false);
if (player) { if (player) {
string name_str = player->disp.name.decode(this->language()); string name_str = player->disp.name.decode(this->language());
this->channel.name = string_printf("C-%" PRIX64 " (%s) @ %s", this->id, name_str.c_str(), ip_str.c_str()); this->channel.name = phosg::string_printf("C-%" PRIX64 " (%s) @ %s", this->id, name_str.c_str(), ip_str.c_str());
} else { } else {
this->channel.name = string_printf("C-%" PRIX64 " @ %s", this->id, ip_str.c_str()); this->channel.name = phosg::string_printf("C-%" PRIX64 " @ %s", this->id, ip_str.c_str());
} }
} }
void Client::reschedule_save_game_data_event() { void Client::reschedule_save_game_data_event() {
if (this->version() == Version::BB_V4) { if (this->version() == Version::BB_V4) {
struct timeval tv = usecs_to_timeval(60000000); // 1 minute struct timeval tv = phosg::usecs_to_timeval(60000000); // 1 minute
event_add(this->save_game_data_event.get(), &tv); event_add(this->save_game_data_event.get(), &tv);
} }
} }
void Client::reschedule_ping_and_timeout_events() { void Client::reschedule_ping_and_timeout_events() {
auto s = this->require_server_state(); auto s = this->require_server_state();
struct timeval ping_tv = usecs_to_timeval(s->client_ping_interval_usecs); struct timeval ping_tv = phosg::usecs_to_timeval(s->client_ping_interval_usecs);
event_add(this->send_ping_event.get(), &ping_tv); event_add(this->send_ping_event.get(), &ping_tv);
struct timeval idle_tv = usecs_to_timeval(s->client_idle_timeout_usecs); struct timeval idle_tv = phosg::usecs_to_timeval(s->client_idle_timeout_usecs);
event_add(this->idle_timeout_event.get(), &idle_tv); event_add(this->idle_timeout_event.get(), &idle_tv);
} }
@@ -393,7 +393,7 @@ bool Client::evaluate_quest_availability_expression(
.v1_present = v1_present, .v1_present = v1_present,
}; };
int64_t ret = expr->evaluate(env); int64_t ret = expr->evaluate(env);
if (this->log.should_log(LogLevel::INFO)) { if (this->log.should_log(phosg::LogLevel::INFO)) {
string expr_str = expr->str(); string expr_str = expr->str();
this->log.info("Evaluated integral expression %s => %s", expr_str.c_str(), ret ? "TRUE" : "FALSE"); this->log.info("Evaluated integral expression %s => %s", expr_str.c_str(), ret ? "TRUE" : "FALSE");
} }
@@ -451,7 +451,7 @@ void Client::send_ping() {
if (!is_patch(this->version())) { if (!is_patch(this->version())) {
this->log.info("Sending ping command"); this->log.info("Sending ping command");
// The game doesn't use this timestamp; we only use it for debugging purposes // The game doesn't use this timestamp; we only use it for debugging purposes
be_uint64_t timestamp = now(); be_uint64_t timestamp = phosg::now();
try { try {
this->channel.send(0x1D, 0x00, &timestamp, sizeof(be_uint64_t)); this->channel.send(0x1D, 0x00, &timestamp, sizeof(be_uint64_t));
} catch (const exception& e) { } catch (const exception& e) {
@@ -643,7 +643,7 @@ string Client::system_filename() const {
if (!this->login || !this->login->bb_license) { if (!this->login || !this->login->bb_license) {
throw logic_error("client is not logged in"); throw logic_error("client is not logged in");
} }
return string_printf("system/players/system_%s.psosys", this->login->bb_license->username.c_str()); return phosg::string_printf("system/players/system_%s.psosys", this->login->bb_license->username.c_str());
} }
string Client::character_filename(const std::string& bb_username, int8_t index) { string Client::character_filename(const std::string& bb_username, int8_t index) {
@@ -653,11 +653,11 @@ string Client::character_filename(const std::string& bb_username, int8_t index)
if (index < 0) { if (index < 0) {
throw logic_error("character index is not set"); throw logic_error("character index is not set");
} }
return string_printf("system/players/player_%s_%hhd.psochar", bb_username.c_str(), index); return phosg::string_printf("system/players/player_%s_%hhd.psochar", bb_username.c_str(), index);
} }
string Client::backup_character_filename(uint32_t account_id, size_t index, bool is_ep3) { string Client::backup_character_filename(uint32_t account_id, size_t index, bool is_ep3) {
return string_printf("system/players/backup_player_%" PRIu32 "_%zu.%s", return phosg::string_printf("system/players/backup_player_%" PRIu32 "_%zu.%s",
account_id, index, is_ep3 ? "pso3char" : "psochar"); account_id, index, is_ep3 ? "pso3char" : "psochar");
} }
@@ -678,7 +678,7 @@ string Client::guild_card_filename() const {
if (!this->login || !this->login->bb_license) { if (!this->login || !this->login->bb_license) {
throw logic_error("client is not logged in"); throw logic_error("client is not logged in");
} }
return string_printf("system/players/guild_cards_%s.psocard", this->login->bb_license->username.c_str()); return phosg::string_printf("system/players/guild_cards_%s.psocard", this->login->bb_license->username.c_str());
} }
string Client::shared_bank_filename() const { string Client::shared_bank_filename() const {
@@ -688,7 +688,7 @@ string Client::shared_bank_filename() const {
if (!this->login || !this->login->bb_license) { if (!this->login || !this->login->bb_license) {
throw logic_error("client is not logged in"); throw logic_error("client is not logged in");
} }
return string_printf("system/players/shared_bank_%s.psobank", this->login->bb_license->username.c_str()); return phosg::string_printf("system/players/shared_bank_%s.psobank", this->login->bb_license->username.c_str());
} }
string Client::legacy_account_filename() const { string Client::legacy_account_filename() const {
@@ -698,7 +698,7 @@ string Client::legacy_account_filename() const {
if (!this->login || !this->login->bb_license) { if (!this->login || !this->login->bb_license) {
throw logic_error("client is not logged in"); throw logic_error("client is not logged in");
} }
return string_printf("system/players/account_%s.nsa", this->login->bb_license->username.c_str()); return phosg::string_printf("system/players/account_%s.nsa", this->login->bb_license->username.c_str());
} }
string Client::legacy_player_filename() const { string Client::legacy_player_filename() const {
@@ -711,7 +711,7 @@ string Client::legacy_player_filename() const {
if (this->bb_character_index < 0) { if (this->bb_character_index < 0) {
throw logic_error("character index is not set"); throw logic_error("character index is not set");
} }
return string_printf( return phosg::string_printf(
"system/players/player_%s_%hhd.nsc", "system/players/player_%s_%hhd.nsc",
this->login->bb_license->username.c_str(), this->login->bb_license->username.c_str(),
static_cast<int8_t>(this->bb_character_index + 1)); static_cast<int8_t>(this->bb_character_index + 1));
@@ -747,8 +747,8 @@ void Client::load_all_files() {
this->system_data = files_manager->get_system(sys_filename); this->system_data = files_manager->get_system(sys_filename);
if (this->system_data) { if (this->system_data) {
player_data_log.info("Using loaded system file %s", sys_filename.c_str()); player_data_log.info("Using loaded system file %s", sys_filename.c_str());
} else if (isfile(sys_filename)) { } else if (phosg::isfile(sys_filename)) {
this->system_data = make_shared<PSOBBBaseSystemFile>(load_object_file<PSOBBBaseSystemFile>(sys_filename, true)); this->system_data = make_shared<PSOBBBaseSystemFile>(phosg::load_object_file<PSOBBBaseSystemFile>(sys_filename, true));
files_manager->set_system(sys_filename, this->system_data); files_manager->set_system(sys_filename, this->system_data);
player_data_log.info("Loaded system data from %s", sys_filename.c_str()); player_data_log.info("Loaded system data from %s", sys_filename.c_str());
} else { } else {
@@ -760,9 +760,9 @@ void Client::load_all_files() {
this->character_data = files_manager->get_character(char_filename); this->character_data = files_manager->get_character(char_filename);
if (this->character_data) { if (this->character_data) {
player_data_log.info("Using loaded character file %s", char_filename.c_str()); player_data_log.info("Using loaded character file %s", char_filename.c_str());
} else if (isfile(char_filename)) { } else if (phosg::isfile(char_filename)) {
auto f = fopen_unique(char_filename, "rb"); auto f = phosg::fopen_unique(char_filename, "rb");
auto header = freadx<PSOCommandHeaderBB>(f.get()); auto header = phosg::freadx<PSOCommandHeaderBB>(f.get());
if (header.size != 0x399C) { if (header.size != 0x399C) {
throw runtime_error("incorrect size in character file header"); throw runtime_error("incorrect size in character file header");
} }
@@ -773,14 +773,14 @@ void Client::load_all_files() {
throw runtime_error("incorrect flag in character file header"); throw runtime_error("incorrect flag in character file header");
} }
static_assert(sizeof(PSOBBCharacterFile) + sizeof(PSOBBFullSystemFile) == 0x3994, ".psochar size is incorrect"); static_assert(sizeof(PSOBBCharacterFile) + sizeof(PSOBBFullSystemFile) == 0x3994, ".psochar size is incorrect");
this->character_data = make_shared<PSOBBCharacterFile>(freadx<PSOBBCharacterFile>(f.get())); this->character_data = make_shared<PSOBBCharacterFile>(phosg::freadx<PSOBBCharacterFile>(f.get()));
files_manager->set_character(char_filename, this->character_data); files_manager->set_character(char_filename, this->character_data);
player_data_log.info("Loaded character data from %s", char_filename.c_str()); player_data_log.info("Loaded character data from %s", char_filename.c_str());
// If there was no .psosys file, load the system file from the .psochar // If there was no .psosys file, load the system file from the .psochar
// file instead // file instead
if (!this->system_data) { if (!this->system_data) {
this->system_data = make_shared<PSOBBBaseSystemFile>(freadx<PSOBBBaseSystemFile>(f.get())); this->system_data = make_shared<PSOBBBaseSystemFile>(phosg::freadx<PSOBBBaseSystemFile>(f.get()));
files_manager->set_system(sys_filename, this->system_data); files_manager->set_system(sys_filename, this->system_data);
player_data_log.info("Loaded system data from %s", char_filename.c_str()); player_data_log.info("Loaded system data from %s", char_filename.c_str());
} }
@@ -797,8 +797,8 @@ void Client::load_all_files() {
this->guild_card_data = files_manager->get_guild_card(card_filename); this->guild_card_data = files_manager->get_guild_card(card_filename);
if (this->guild_card_data) { if (this->guild_card_data) {
player_data_log.info("Using loaded Guild Card file %s", card_filename.c_str()); player_data_log.info("Using loaded Guild Card file %s", card_filename.c_str());
} else if (isfile(card_filename)) { } else if (phosg::isfile(card_filename)) {
this->guild_card_data = make_shared<PSOBBGuildCardFile>(load_object_file<PSOBBGuildCardFile>(card_filename)); this->guild_card_data = make_shared<PSOBBGuildCardFile>(phosg::load_object_file<PSOBBGuildCardFile>(card_filename));
files_manager->set_guild_card(card_filename, this->guild_card_data); files_manager->set_guild_card(card_filename, this->guild_card_data);
player_data_log.info("Loaded Guild Card data from %s", card_filename.c_str()); player_data_log.info("Loaded Guild Card data from %s", card_filename.c_str());
} else { } else {
@@ -809,8 +809,8 @@ void Client::load_all_files() {
if (!this->system_data || (!this->character_data && (this->bb_character_index >= 0)) || !this->guild_card_data) { if (!this->system_data || (!this->character_data && (this->bb_character_index >= 0)) || !this->guild_card_data) {
string nsa_filename = this->legacy_account_filename(); string nsa_filename = this->legacy_account_filename();
shared_ptr<LegacySavedAccountDataBB> nsa_data; shared_ptr<LegacySavedAccountDataBB> nsa_data;
if (isfile(nsa_filename)) { if (phosg::isfile(nsa_filename)) {
nsa_data = make_shared<LegacySavedAccountDataBB>(load_object_file<LegacySavedAccountDataBB>(nsa_filename)); nsa_data = make_shared<LegacySavedAccountDataBB>(phosg::load_object_file<LegacySavedAccountDataBB>(nsa_filename));
if (!nsa_data->signature.eq(LegacySavedAccountDataBB::SIGNATURE)) { if (!nsa_data->signature.eq(LegacySavedAccountDataBB::SIGNATURE)) {
throw runtime_error("account data header is incorrect"); throw runtime_error("account data header is incorrect");
} }
@@ -839,7 +839,7 @@ void Client::load_all_files() {
if (!this->character_data && (this->bb_character_index >= 0)) { if (!this->character_data && (this->bb_character_index >= 0)) {
string nsc_filename = this->legacy_player_filename(); string nsc_filename = this->legacy_player_filename();
auto nsc_data = load_object_file<LegacySavedPlayerDataBB>(nsc_filename); auto nsc_data = phosg::load_object_file<LegacySavedPlayerDataBB>(nsc_filename);
if (nsc_data.signature == LegacySavedPlayerDataBB::SIGNATURE_V0) { if (nsc_data.signature == LegacySavedPlayerDataBB::SIGNATURE_V0) {
nsc_data.signature = LegacySavedPlayerDataBB::SIGNATURE_V0; nsc_data.signature = LegacySavedPlayerDataBB::SIGNATURE_V0;
nsc_data.unused.clear(); nsc_data.unused.clear();
@@ -895,7 +895,7 @@ void Client::load_all_files() {
this->character_data->disp.name.clear_after_bytes(0x18); this->character_data->disp.name.clear_after_bytes(0x18);
this->login->account->auto_reply_message = this->character_data->auto_reply.decode(); this->login->account->auto_reply_message = this->character_data->auto_reply.decode();
this->login->account->save(); this->login->account->save();
this->last_play_time_update = now(); this->last_play_time_update = phosg::now();
} }
} }
@@ -920,7 +920,7 @@ void Client::save_all() {
} }
if (this->external_bank) { if (this->external_bank) {
string filename = this->shared_bank_filename(); string filename = this->shared_bank_filename();
save_object_file<PlayerBank200>(filename, *this->external_bank); phosg::save_object_file<PlayerBank200>(filename, *this->external_bank);
player_data_log.info("Saved shared bank file %s", filename.c_str()); player_data_log.info("Saved shared bank file %s", filename.c_str());
} }
if (this->external_bank_character) { if (this->external_bank_character) {
@@ -936,7 +936,7 @@ void Client::save_system_file() const {
throw logic_error("no system file loaded"); throw logic_error("no system file loaded");
} }
string filename = this->system_filename(); string filename = this->system_filename();
save_object_file(filename, *this->system_data); phosg::save_object_file(filename, *this->system_data);
player_data_log.info("Saved system file %s", filename.c_str()); player_data_log.info("Saved system file %s", filename.c_str());
} }
@@ -944,11 +944,11 @@ void Client::save_character_file(
const string& filename, const string& filename,
shared_ptr<const PSOBBBaseSystemFile> system, shared_ptr<const PSOBBBaseSystemFile> system,
shared_ptr<const PSOBBCharacterFile> character) { shared_ptr<const PSOBBCharacterFile> character) {
auto f = fopen_unique(filename, "wb"); auto f = phosg::fopen_unique(filename, "wb");
PSOCommandHeaderBB header = {sizeof(PSOCommandHeaderBB) + sizeof(PSOBBCharacterFile) + sizeof(PSOBBBaseSystemFile) + sizeof(PSOBBTeamMembership), 0x00E7, 0x00000000}; PSOCommandHeaderBB header = {sizeof(PSOCommandHeaderBB) + sizeof(PSOBBCharacterFile) + sizeof(PSOBBBaseSystemFile) + sizeof(PSOBBTeamMembership), 0x00E7, 0x00000000};
fwritex(f.get(), header); phosg::fwritex(f.get(), header);
fwritex(f.get(), *character); phosg::fwritex(f.get(), *character);
fwritex(f.get(), *system); phosg::fwritex(f.get(), *system);
// TODO: Technically, we should write the actual team membership struct to the // TODO: Technically, we should write the actual team membership struct to the
// file here, but that would cause Client to depend on Account, which // file here, but that would cause Client to depend on Account, which
// it currently does not. This data doesn't matter at all for correctness // it currently does not. This data doesn't matter at all for correctness
@@ -960,14 +960,14 @@ void Client::save_character_file(
// of teams with a different set of team IDs anyway, so the membership struct // of teams with a different set of team IDs anyway, so the membership struct
// here would be useless either way. // here would be useless either way.
static const PSOBBTeamMembership empty_membership; static const PSOBBTeamMembership empty_membership;
fwritex(f.get(), empty_membership); phosg::fwritex(f.get(), empty_membership);
player_data_log.info("Saved character file %s", filename.c_str()); player_data_log.info("Saved character file %s", filename.c_str());
} }
void Client::save_ep3_character_file( void Client::save_ep3_character_file(
const string& filename, const string& filename,
const PSOGCEp3CharacterFile::Character& character) { const PSOGCEp3CharacterFile::Character& character) {
save_file(filename, &character, sizeof(character)); phosg::save_file(filename, &character, sizeof(character));
player_data_log.info("Saved Episode 3 character file %s", filename.c_str()); player_data_log.info("Saved Episode 3 character file %s", filename.c_str());
} }
@@ -981,7 +981,7 @@ void Client::save_character_file() {
if (this->should_update_play_time) { if (this->should_update_play_time) {
// This is slightly inaccurate, since fractions of a second are truncated // This is slightly inaccurate, since fractions of a second are truncated
// off each time we save. I'm lazy, so insert shrug emoji here. // off each time we save. I'm lazy, so insert shrug emoji here.
uint64_t t = now(); uint64_t t = phosg::now();
uint64_t seconds = (t - this->last_play_time_update) / 1000000; uint64_t seconds = (t - this->last_play_time_update) / 1000000;
this->character_data->play_time_seconds += seconds; this->character_data->play_time_seconds += seconds;
player_data_log.info("Added %" PRIu64 " seconds to play time", seconds); player_data_log.info("Added %" PRIu64 " seconds to play time", seconds);
@@ -996,14 +996,14 @@ void Client::save_guild_card_file() const {
throw logic_error("no Guild Card file loaded"); throw logic_error("no Guild Card file loaded");
} }
string filename = this->guild_card_filename(); string filename = this->guild_card_filename();
save_object_file(filename, *this->guild_card_data); phosg::save_object_file(filename, *this->guild_card_data);
player_data_log.info("Saved Guild Card file %s", filename.c_str()); player_data_log.info("Saved Guild Card file %s", filename.c_str());
} }
void Client::load_backup_character(uint32_t account_id, size_t index) { void Client::load_backup_character(uint32_t account_id, size_t index) {
string filename = this->backup_character_filename(account_id, index, false); string filename = this->backup_character_filename(account_id, index, false);
auto f = fopen_unique(filename, "rb"); auto f = phosg::fopen_unique(filename, "rb");
auto header = freadx<PSOCommandHeaderBB>(f.get()); auto header = phosg::freadx<PSOCommandHeaderBB>(f.get());
if (header.size != 0x399C) { if (header.size != 0x399C) {
throw runtime_error("incorrect size in character file header"); throw runtime_error("incorrect size in character file header");
} }
@@ -1013,14 +1013,14 @@ void Client::load_backup_character(uint32_t account_id, size_t index) {
if (header.flag != 0x00000000) { if (header.flag != 0x00000000) {
throw runtime_error("incorrect flag in character file header"); throw runtime_error("incorrect flag in character file header");
} }
this->character_data = make_shared<PSOBBCharacterFile>(freadx<PSOBBCharacterFile>(f.get())); this->character_data = make_shared<PSOBBCharacterFile>(phosg::freadx<PSOBBCharacterFile>(f.get()));
this->update_character_data_after_load(this->character_data); this->update_character_data_after_load(this->character_data);
this->v1_v2_last_reported_disp.reset(); this->v1_v2_last_reported_disp.reset();
} }
shared_ptr<PSOGCEp3CharacterFile::Character> Client::load_ep3_backup_character(uint32_t account_id, size_t index) { shared_ptr<PSOGCEp3CharacterFile::Character> Client::load_ep3_backup_character(uint32_t account_id, size_t index) {
string filename = this->backup_character_filename(account_id, index, true); string filename = this->backup_character_filename(account_id, index, true);
auto ch = make_shared<PSOGCEp3CharacterFile::Character>(load_object_file<PSOGCEp3CharacterFile::Character>(filename)); auto ch = make_shared<PSOGCEp3CharacterFile::Character>(phosg::load_object_file<PSOGCEp3CharacterFile::Character>(filename));
this->character_data = PSOBBCharacterFile::create_from_ep3(*ch); this->character_data = PSOBBCharacterFile::create_from_ep3(*ch);
this->ep3_config = make_shared<Episode3::PlayerConfig>(ch->ep3_config); this->ep3_config = make_shared<Episode3::PlayerConfig>(ch->ep3_config);
this->update_character_data_after_load(this->character_data); this->update_character_data_after_load(this->character_data);
@@ -1052,7 +1052,7 @@ std::shared_ptr<PSOBBCharacterFile> Client::current_bank_character() {
void Client::use_default_bank() { void Client::use_default_bank() {
if (this->external_bank) { if (this->external_bank) {
string filename = this->shared_bank_filename(); string filename = this->shared_bank_filename();
save_object_file<PlayerBank200>(filename, *this->external_bank); phosg::save_object_file<PlayerBank200>(filename, *this->external_bank);
this->external_bank.reset(); this->external_bank.reset();
player_data_log.info("Detached shared bank %s", filename.c_str()); player_data_log.info("Detached shared bank %s", filename.c_str());
} }
@@ -1073,8 +1073,8 @@ bool Client::use_shared_bank() {
if (this->external_bank) { if (this->external_bank) {
player_data_log.info("Using loaded shared bank %s", filename.c_str()); player_data_log.info("Using loaded shared bank %s", filename.c_str());
return true; return true;
} else if (isfile(filename)) { } else if (phosg::isfile(filename)) {
this->external_bank = make_shared<PlayerBank200>(load_object_file<PlayerBank200>(filename)); this->external_bank = make_shared<PlayerBank200>(phosg::load_object_file<PlayerBank200>(filename));
files_manager->set_bank(filename, this->external_bank); files_manager->set_bank(filename, this->external_bank);
player_data_log.info("Loaded shared bank %s", filename.c_str()); player_data_log.info("Loaded shared bank %s", filename.c_str());
return true; return true;
@@ -1096,9 +1096,9 @@ void Client::use_character_bank(int8_t index) {
if (this->external_bank_character) { if (this->external_bank_character) {
this->external_bank_character_index = index; this->external_bank_character_index = index;
player_data_log.info("Using loaded character file %s for external bank", filename.c_str()); player_data_log.info("Using loaded character file %s for external bank", filename.c_str());
} else if (isfile(filename)) { } else if (phosg::isfile(filename)) {
auto f = fopen_unique(filename, "rb"); auto f = phosg::fopen_unique(filename, "rb");
auto header = freadx<PSOCommandHeaderBB>(f.get()); auto header = phosg::freadx<PSOCommandHeaderBB>(f.get());
if (header.size != 0x399C) { if (header.size != 0x399C) {
throw runtime_error("incorrect size in character file header"); throw runtime_error("incorrect size in character file header");
} }
@@ -1108,7 +1108,7 @@ void Client::use_character_bank(int8_t index) {
if (header.flag != 0x00000000) { if (header.flag != 0x00000000) {
throw runtime_error("incorrect flag in character file header"); throw runtime_error("incorrect flag in character file header");
} }
this->external_bank_character = make_shared<PSOBBCharacterFile>(freadx<PSOBBCharacterFile>(f.get())); this->external_bank_character = make_shared<PSOBBCharacterFile>(phosg::freadx<PSOBBCharacterFile>(f.get()));
this->update_character_data_after_load(this->external_bank_character); this->update_character_data_after_load(this->external_bank_character);
this->external_bank_character_index = index; this->external_bank_character_index = index;
files_manager->set_character(filename, this->external_bank_character); files_manager->set_character(filename, this->external_bank_character);
+3 -3
View File
@@ -147,7 +147,7 @@ public:
template <size_t Bytes> template <size_t Bytes>
void parse_from(const parray<uint8_t, Bytes>& data) { void parse_from(const parray<uint8_t, Bytes>& data) {
StringReader r(data.data(), data.size()); phosg::StringReader r(data.data(), data.size());
if (r.get_u32l() != CLIENT_CONFIG_MAGIC) { if (r.get_u32l() != CLIENT_CONFIG_MAGIC) {
throw std::invalid_argument("config signature is incorrect"); throw std::invalid_argument("config signature is incorrect");
} }
@@ -163,7 +163,7 @@ public:
template <size_t Bytes> template <size_t Bytes>
void serialize_into(parray<uint8_t, Bytes>& data) const { void serialize_into(parray<uint8_t, Bytes>& data) const {
StringWriter w; phosg::StringWriter w;
w.put_u32l(CLIENT_CONFIG_MAGIC); w.put_u32l(CLIENT_CONFIG_MAGIC);
w.put_u32l(this->specific_version); w.put_u32l(this->specific_version);
w.put_u64l(this->enabled_flags & static_cast<uint64_t>(Flag::CLIENT_SIDE_MASK)); w.put_u64l(this->enabled_flags & static_cast<uint64_t>(Flag::CLIENT_SIDE_MASK));
@@ -184,7 +184,7 @@ public:
std::weak_ptr<Server> server; std::weak_ptr<Server> server;
uint64_t id; uint64_t id;
PrefixedLogger log; phosg::PrefixedLogger log;
std::shared_ptr<Login> login; std::shared_ptr<Login> login;
+21 -27
View File
@@ -2228,10 +2228,9 @@ struct S_ExecuteCode_B2 {
// The code immediately follows, ending with an S_ExecuteCode_Footer_B2 // The code immediately follows, ending with an S_ExecuteCode_Footer_B2
} __packed_ws__(S_ExecuteCode_B2, 0x0C); } __packed_ws__(S_ExecuteCode_B2, 0x0C);
template <bool IsBigEndian> template <bool BE>
struct S_ExecuteCode_FooterT_B2 { struct S_ExecuteCode_FooterT_B2 {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; static constexpr bool IsBE = BE; // Needed by generate_client_command_t
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
// Relocations is a list of words (le_uint16_t on DC/PC/XB/BB, be_uint16_t on // Relocations is a list of words (le_uint16_t on DC/PC/XB/BB, be_uint16_t on
// GC) containing the number of doublewords (uint32_t) to skip for each // GC) containing the number of doublewords (uint32_t) to skip for each
@@ -2251,14 +2250,14 @@ struct S_ExecuteCode_FooterT_B2 {
// relocations_offset points there, so those 12 bytes may also be omitted from // relocations_offset points there, so those 12 bytes may also be omitted from
// the command entirely (without changing code_size - so code_size would // the command entirely (without changing code_size - so code_size would
// technically extend beyond the end of the B2 command). // technically extend beyond the end of the B2 command).
U32T relocations_offset = 0; // Relative to code base (after checksum_size) U32T<BE> relocations_offset = 0; // Relative to code base (after checksum_size)
U32T num_relocations = 0; U32T<BE> num_relocations = 0;
parray<U32T, 2> unused1; parray<U32T<BE>, 2> unused1;
// entrypoint_offset is doubly indirect - it points to a pointer to a 32-bit // entrypoint_offset is doubly indirect - it points to a pointer to a 32-bit
// value that itself is the actual entrypoint. This is presumably done so the // value that itself is the actual entrypoint. This is presumably done so the
// entrypoint can be optionally relocated. // entrypoint can be optionally relocated.
U32T entrypoint_addr_offset = 0; // Relative to code base (after checksum_size). U32T<BE> entrypoint_addr_offset = 0; // Relative to code base (after checksum_size).
parray<U32T, 3> unused2; parray<U32T<BE>, 3> unused2;
} __packed__; } __packed__;
using S_ExecuteCode_Footer_GC_B2 = S_ExecuteCode_FooterT_B2<true>; using S_ExecuteCode_Footer_GC_B2 = S_ExecuteCode_FooterT_B2<true>;
using S_ExecuteCode_Footer_DC_PC_XB_BB_B2 = S_ExecuteCode_FooterT_B2<false>; using S_ExecuteCode_Footer_DC_PC_XB_BB_B2 = S_ExecuteCode_FooterT_B2<false>;
@@ -3951,7 +3950,7 @@ struct G_Unknown_6x09 {
// 6x0A: Update enemy state // 6x0A: Update enemy state
template <bool IsBigEndian> template <bool BE>
struct G_UpdateEnemyStateT_6x0A { struct G_UpdateEnemyStateT_6x0A {
G_EnemyIDHeader header; G_EnemyIDHeader header;
le_uint16_t enemy_index = 0; // [0, 0xB50) le_uint16_t enemy_index = 0; // [0, 0xB50)
@@ -3959,7 +3958,7 @@ struct G_UpdateEnemyStateT_6x0A {
// Flags: // Flags:
// 00000400 - should play hit animation // 00000400 - should play hit animation
// 00000800 - is dead // 00000800 - is dead
typename std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t> flags = 0; typename std::conditional_t<BE, be_uint32_t, le_uint32_t> flags = 0;
} __packed__; } __packed__;
using G_UpdateEnemyState_GC_6x0A = G_UpdateEnemyStateT_6x0A<true>; using G_UpdateEnemyState_GC_6x0A = G_UpdateEnemyStateT_6x0A<true>;
using G_UpdateEnemyState_DC_PC_XB_BB_6x0A = G_UpdateEnemyStateT_6x0A<false>; using G_UpdateEnemyState_DC_PC_XB_BB_6x0A = G_UpdateEnemyStateT_6x0A<false>;
@@ -4005,15 +4004,14 @@ struct G_Unknown_6x10_6x11_6x12_6x14 {
// 6x12: Dragon boss actions (not valid on Episode 3) // 6x12: Dragon boss actions (not valid on Episode 3)
template <bool IsBigEndian> template <bool BE>
struct G_DragonBossActionsT_6x12 { struct G_DragonBossActionsT_6x12 {
using F32T = typename std::conditional<IsBigEndian, be_float, le_float>::type;
G_EnemyIDHeader header; G_EnemyIDHeader header;
le_uint16_t unknown_a2 = 0; le_uint16_t unknown_a2 = 0;
le_uint16_t unknown_a3 = 0; le_uint16_t unknown_a3 = 0;
le_uint32_t unknown_a4 = 0; le_uint32_t unknown_a4 = 0;
F32T x = 0.0f; F32T<BE> x = 0.0f;
F32T z = 0.0f; F32T<BE> z = 0.0f;
} __packed__; } __packed__;
using G_DragonBossActions_DC_PC_XB_BB_6x12 = G_DragonBossActionsT_6x12<false>; using G_DragonBossActions_DC_PC_XB_BB_6x12 = G_DragonBossActionsT_6x12<false>;
using G_DragonBossActions_GC_6x12 = G_DragonBossActionsT_6x12<true>; using G_DragonBossActions_GC_6x12 = G_DragonBossActionsT_6x12<true>;
@@ -5043,12 +5041,11 @@ struct G_ExitQuest_6x73 {
// There is a bug in PSO GC with regard to this command: the client does not // There is a bug in PSO GC with regard to this command: the client does not
// byteswap the header, which means the client_id field is big-endian. // byteswap the header, which means the client_id field is big-endian.
template <bool IsBigEndian> template <bool BE>
struct G_WordSelectT_6x74 { struct G_WordSelectT_6x74 {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
uint8_t subcommand = 0; uint8_t subcommand = 0;
uint8_t size = 0; uint8_t size = 0;
U16T client_id = 0; U16T<BE> client_id = 0;
WordSelectMessage message; WordSelectMessage message;
} __packed__; } __packed__;
using G_WordSelect_6x74 = G_WordSelectT_6x74<false>; using G_WordSelect_6x74 = G_WordSelectT_6x74<false>;
@@ -5170,14 +5167,12 @@ struct G_SetBattleModeData_6x7D {
// 6x7F: Battle scores and places (not valid on Episode 3) // 6x7F: Battle scores and places (not valid on Episode 3)
template <bool IsBigEndian> template <bool BE>
struct G_BattleScoresT_6x7F { struct G_BattleScoresT_6x7F {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
struct Entry { struct Entry {
U16T client_id = 0; U16T<BE> client_id = 0;
U16T place = 0; U16T<BE> place = 0;
U32T score = 0; U32T<BE> score = 0;
} __packed_ws__(Entry, 8); } __packed_ws__(Entry, 8);
G_UnusedHeader header; G_UnusedHeader header;
parray<Entry, 4> entries; parray<Entry, 4> entries;
@@ -5513,15 +5508,14 @@ struct G_ModifyTradeProposal_6xA6 {
// 6xA8: Gol Dragon boss actions (not valid on pre-V3 or Episode 3) // 6xA8: Gol Dragon boss actions (not valid on pre-V3 or Episode 3)
template <bool IsBigEndian> template <bool BE>
struct G_GolDragonBossActionsT_6xA8 { struct G_GolDragonBossActionsT_6xA8 {
using F32T = typename std::conditional<IsBigEndian, be_float, le_float>::type;
G_EnemyIDHeader header; G_EnemyIDHeader header;
le_uint16_t unknown_a2 = 0; le_uint16_t unknown_a2 = 0;
le_uint16_t unknown_a3 = 0; le_uint16_t unknown_a3 = 0;
le_uint32_t unknown_a4 = 0; le_uint32_t unknown_a4 = 0;
F32T x = 0.0f; F32T<BE> x = 0.0f;
F32T z = 0.0f; F32T<BE> z = 0.0f;
uint8_t unknown_a5 = 0; uint8_t unknown_a5 = 0;
parray<uint8_t, 3> unused; parray<uint8_t, 3> unused;
} __packed__; } __packed__;
+43 -45
View File
@@ -4,12 +4,13 @@
#include "EnemyType.hh" #include "EnemyType.hh"
#include "GSLArchive.hh" #include "GSLArchive.hh"
#include "StaticGameData.hh" #include "StaticGameData.hh"
#include "Types.hh"
using namespace std; using namespace std;
template <typename IntT, size_t Count> template <typename IntT, size_t Count>
JSON to_json(const parray<IntT, Count>& v) { phosg::JSON to_json(const parray<IntT, Count>& v) {
auto ret = JSON::list(); auto ret = phosg::JSON::list();
for (size_t z = 0; z < Count; z++) { for (size_t z = 0; z < Count; z++) {
ret.emplace_back(v[z]); ret.emplace_back(v[z]);
} }
@@ -17,7 +18,7 @@ JSON to_json(const parray<IntT, Count>& v) {
} }
template <typename IntT, size_t Count> template <typename IntT, size_t Count>
void from_json_into(const JSON& json, parray<IntT, Count>& ret) { void from_json_into(const phosg::JSON& json, parray<IntT, Count>& ret) {
if (json.size() != Count) { if (json.size() != Count) {
throw runtime_error("incorrect array length"); throw runtime_error("incorrect array length");
} }
@@ -27,8 +28,8 @@ void from_json_into(const JSON& json, parray<IntT, Count>& ret) {
} }
template <typename IntT, size_t Count> template <typename IntT, size_t Count>
JSON to_json(const parray<CommonItemSet::Table::Range<IntT>, Count>& v) { phosg::JSON to_json(const parray<CommonItemSet::Table::Range<IntT>, Count>& v) {
auto ret = JSON::list(); auto ret = phosg::JSON::list();
for (size_t z = 0; z < Count; z++) { for (size_t z = 0; z < Count; z++) {
ret.emplace_back(to_json(v[z])); ret.emplace_back(to_json(v[z]));
} }
@@ -36,7 +37,7 @@ JSON to_json(const parray<CommonItemSet::Table::Range<IntT>, Count>& v) {
} }
template <typename IntT, size_t Count> template <typename IntT, size_t Count>
void from_json_into(const JSON& json, parray<CommonItemSet::Table::Range<IntT>, Count>& ret) { void from_json_into(const phosg::JSON& json, parray<CommonItemSet::Table::Range<IntT>, Count>& ret) {
if (json.size() != Count) { if (json.size() != Count) {
throw runtime_error("incorrect array length"); throw runtime_error("incorrect array length");
} }
@@ -46,16 +47,16 @@ void from_json_into(const JSON& json, parray<CommonItemSet::Table::Range<IntT>,
} }
template <typename IntT> template <typename IntT>
JSON to_json(const CommonItemSet::Table::Range<IntT>& v) { phosg::JSON to_json(const CommonItemSet::Table::Range<IntT>& v) {
if (v.min == v.max) { if (v.min == v.max) {
return JSON(v.min); return phosg::JSON(v.min);
} else { } else {
return JSON::list({v.min, v.max}); return phosg::JSON::list({v.min, v.max});
} }
} }
template <typename IntT> template <typename IntT>
void from_json_into(const JSON& json, CommonItemSet::Table::Range<IntT>& ret) { void from_json_into(const phosg::JSON& json, CommonItemSet::Table::Range<IntT>& ret) {
if (json.is_int()) { if (json.is_int()) {
IntT v = json.as_int(); IntT v = json.as_int();
ret.min = v; ret.min = v;
@@ -71,8 +72,8 @@ void from_json_into(const JSON& json, CommonItemSet::Table::Range<IntT>& ret) {
} }
template <typename IntT, size_t Count1, size_t Count2> template <typename IntT, size_t Count1, size_t Count2>
JSON to_json(const parray<parray<IntT, Count2>, Count1>& v) { phosg::JSON to_json(const parray<parray<IntT, Count2>, Count1>& v) {
auto ret = JSON::list(); auto ret = phosg::JSON::list();
for (size_t z = 0; z < Count1; z++) { for (size_t z = 0; z < Count1; z++) {
ret.emplace_back(to_json(v[z])); ret.emplace_back(to_json(v[z]));
} }
@@ -80,7 +81,7 @@ JSON to_json(const parray<parray<IntT, Count2>, Count1>& v) {
} }
template <typename IntT, size_t Count1, size_t Count2> template <typename IntT, size_t Count1, size_t Count2>
void from_json_into(const JSON& json, parray<parray<IntT, Count2>, Count1>& ret) { void from_json_into(const phosg::JSON& json, parray<parray<IntT, Count2>, Count1>& ret) {
if (json.size() != Count1) { if (json.size() != Count1) {
throw runtime_error("incorrect array length"); throw runtime_error("incorrect array length");
} }
@@ -90,7 +91,7 @@ void from_json_into(const JSON& json, parray<parray<IntT, Count2>, Count1>& ret)
} }
template <typename IntT, size_t Count1, size_t Count2> template <typename IntT, size_t Count1, size_t Count2>
void from_json_into(const JSON& json, parray<parray<CommonItemSet::Table::Range<IntT>, Count2>, Count1>& ret) { void from_json_into(const phosg::JSON& json, parray<parray<CommonItemSet::Table::Range<IntT>, Count2>, Count1>& ret) {
if (json.size() != Count1) { if (json.size() != Count1) {
throw runtime_error("incorrect array length"); throw runtime_error("incorrect array length");
} }
@@ -99,7 +100,7 @@ void from_json_into(const JSON& json, parray<parray<CommonItemSet::Table::Range<
} }
} }
CommonItemSet::Table::Table(const JSON& json, Episode episode) CommonItemSet::Table::Table(const phosg::JSON& json, Episode episode)
: episode(episode) { : episode(episode) {
from_json_into(json.at("BaseWeaponTypeProbTable"), this->base_weapon_type_prob_table); from_json_into(json.at("BaseWeaponTypeProbTable"), this->base_weapon_type_prob_table);
from_json_into(json.at("SubtypeBaseTable"), this->subtype_base_table); from_json_into(json.at("SubtypeBaseTable"), this->subtype_base_table);
@@ -128,7 +129,7 @@ CommonItemSet::Table::Table(const JSON& json, Episode episode)
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4}; static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (Episode episode : episodes) { for (Episode episode : episodes) {
for (auto type : enemy_types_for_rare_table_index(episode, z)) { for (auto type : enemy_types_for_rare_table_index(episode, z)) {
string name = string_printf("%s:%s", abbreviation_for_episode(episode), name_for_enum(type)); string name = phosg::string_printf("%s:%s", abbreviation_for_episode(episode), phosg::name_for_enum(type));
from_json_into(*enemy_meseta_ranges_json.at(name), this->enemy_meseta_ranges[z]); from_json_into(*enemy_meseta_ranges_json.at(name), this->enemy_meseta_ranges[z]);
this->enemy_type_drop_probs[z] = enemy_type_drop_probs_json.at(name)->as_int(); this->enemy_type_drop_probs[z] = enemy_type_drop_probs_json.at(name)->as_int();
this->enemy_item_classes[z] = enemy_item_classes_json.at(name)->as_int(); this->enemy_item_classes[z] = enemy_item_classes_json.at(name)->as_int();
@@ -170,7 +171,7 @@ void CommonItemSet::Table::print(FILE* stream) const {
if (!enemies_str.empty()) { if (!enemies_str.empty()) {
enemies_str += ", "; enemies_str += ", ";
} }
enemies_str += name_for_enum(enemy_type); enemies_str += phosg::name_for_enum(enemy_type);
} }
if (drop_probs[z]) { if (drop_probs[z]) {
fprintf(stream, " %02zX %5hu %5hu %3hhu%% %02hX:%s %s\n", fprintf(stream, " %02zX %5hu %5hu %3hhu%% %02hX:%s %s\n",
@@ -335,22 +336,22 @@ void CommonItemSet::Table::print(FILE* stream) const {
} }
} }
JSON CommonItemSet::Table::json() const { phosg::JSON CommonItemSet::Table::json() const {
JSON enemy_meseta_ranges_json = JSON::dict(); phosg::JSON enemy_meseta_ranges_json = phosg::JSON::dict();
JSON enemy_type_drop_probs_json = JSON::dict(); phosg::JSON enemy_type_drop_probs_json = phosg::JSON::dict();
JSON enemy_item_classes_json = JSON::dict(); phosg::JSON enemy_item_classes_json = phosg::JSON::dict();
for (size_t z = 0; z < 0x64; z++) { for (size_t z = 0; z < 0x64; z++) {
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4}; static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (Episode episode : episodes) { for (Episode episode : episodes) {
for (auto type : enemy_types_for_rare_table_index(episode, z)) { for (auto type : enemy_types_for_rare_table_index(episode, z)) {
string name = string_printf("%s:%s", abbreviation_for_episode(episode), name_for_enum(type)); string name = phosg::string_printf("%s:%s", abbreviation_for_episode(episode), phosg::name_for_enum(type));
enemy_meseta_ranges_json.emplace(name, to_json(this->enemy_meseta_ranges[z])); enemy_meseta_ranges_json.emplace(name, to_json(this->enemy_meseta_ranges[z]));
enemy_type_drop_probs_json.emplace(name, this->enemy_type_drop_probs[z]); enemy_type_drop_probs_json.emplace(name, this->enemy_type_drop_probs[z]);
enemy_item_classes_json.emplace(name, this->enemy_item_classes[z]); enemy_item_classes_json.emplace(name, this->enemy_item_classes[z]);
} }
} }
} }
return JSON::dict({ return phosg::JSON::dict({
{"BaseWeaponTypeProbTable", to_json(this->base_weapon_type_prob_table)}, {"BaseWeaponTypeProbTable", to_json(this->base_weapon_type_prob_table)},
{"SubtypeBaseTable", to_json(this->subtype_base_table)}, {"SubtypeBaseTable", to_json(this->subtype_base_table)},
{"SubtypeAreaLengthTable", to_json(this->subtype_area_length_table)}, {"SubtypeAreaLengthTable", to_json(this->subtype_area_length_table)},
@@ -376,16 +377,16 @@ JSON CommonItemSet::Table::json() const {
}); });
} }
JSON CommonItemSet::json() const { phosg::JSON CommonItemSet::json() const {
auto modes_dict = JSON::dict(); auto modes_dict = phosg::JSON::dict();
static const array<GameMode, 4> modes = {GameMode::NORMAL, GameMode::BATTLE, GameMode::CHALLENGE, GameMode::SOLO}; static const array<GameMode, 4> modes = {GameMode::NORMAL, GameMode::BATTLE, GameMode::CHALLENGE, GameMode::SOLO};
for (const auto& mode : modes) { for (const auto& mode : modes) {
auto episodes_dict = JSON::dict(); auto episodes_dict = phosg::JSON::dict();
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4}; static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (const auto& episode : episodes) { for (const auto& episode : episodes) {
auto difficulty_dict = JSON::dict(); auto difficulty_dict = phosg::JSON::dict();
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) { for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
auto section_id_dict = JSON::dict(); auto section_id_dict = phosg::JSON::dict();
for (uint8_t section_id = 0; section_id < 10; section_id++) { for (uint8_t section_id = 0; section_id < 10; section_id++) {
try { try {
auto table = this->get_table(episode, mode, difficulty, section_id); auto table = this->get_table(episode, mode, difficulty, section_id);
@@ -423,7 +424,7 @@ void CommonItemSet::print(FILE* stream) const {
} }
} }
CommonItemSet::Table::Table(const StringReader& r, bool is_big_endian, bool is_v3, Episode episode) CommonItemSet::Table::Table(const phosg::StringReader& r, bool is_big_endian, bool is_v3, Episode episode)
: episode(episode) { : episode(episode) {
if (is_big_endian) { if (is_big_endian) {
this->parse_itempt_t<true>(r, is_v3); this->parse_itempt_t<true>(r, is_v3);
@@ -432,12 +433,9 @@ CommonItemSet::Table::Table(const StringReader& r, bool is_big_endian, bool is_v
} }
} }
template <bool IsBigEndian> template <bool BE>
void CommonItemSet::Table::parse_itempt_t(const StringReader& r, bool is_v3) { void CommonItemSet::Table::parse_itempt_t(const phosg::StringReader& r, bool is_v3) {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; const auto& offsets = r.pget<OffsetsT<BE>>(r.pget<U32T<BE>>(r.size() - 0x10));
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
const auto& offsets = r.pget<OffsetsT<IsBigEndian>>(r.pget<U32T>(r.size() - 0x10));
this->base_weapon_type_prob_table = r.pget<parray<uint8_t, 0x0C>>(offsets.base_weapon_type_prob_table_offset); this->base_weapon_type_prob_table = r.pget<parray<uint8_t, 0x0C>>(offsets.base_weapon_type_prob_table_offset);
this->subtype_base_table = r.pget<parray<int8_t, 0x0C>>(offsets.subtype_base_table_offset); this->subtype_base_table = r.pget<parray<int8_t, 0x0C>>(offsets.subtype_base_table_offset);
@@ -445,14 +443,14 @@ void CommonItemSet::Table::parse_itempt_t(const StringReader& r, bool is_v3) {
this->grind_prob_table = r.pget<parray<parray<uint8_t, 4>, 9>>(offsets.grind_prob_table_offset); this->grind_prob_table = r.pget<parray<parray<uint8_t, 4>, 9>>(offsets.grind_prob_table_offset);
this->armor_shield_type_index_prob_table = r.pget<parray<uint8_t, 0x05>>(offsets.armor_shield_type_index_prob_table_offset); this->armor_shield_type_index_prob_table = r.pget<parray<uint8_t, 0x05>>(offsets.armor_shield_type_index_prob_table_offset);
this->armor_slot_count_prob_table = r.pget<parray<uint8_t, 0x05>>(offsets.armor_slot_count_prob_table_offset); this->armor_slot_count_prob_table = r.pget<parray<uint8_t, 0x05>>(offsets.armor_slot_count_prob_table_offset);
const auto& data = r.pget<parray<Range<U16T>, 0x64>>(offsets.enemy_meseta_ranges_offset); const auto& data = r.pget<parray<Range<U16T<BE>>, 0x64>>(offsets.enemy_meseta_ranges_offset);
for (size_t z = 0; z < data.size(); z++) { for (size_t z = 0; z < data.size(); z++) {
this->enemy_meseta_ranges[z] = Range<uint16_t>{data[z].min, data[z].max}; this->enemy_meseta_ranges[z] = Range<uint16_t>{data[z].min, data[z].max};
} }
this->enemy_type_drop_probs = r.pget<parray<uint8_t, 0x64>>(offsets.enemy_type_drop_probs_offset); this->enemy_type_drop_probs = r.pget<parray<uint8_t, 0x64>>(offsets.enemy_type_drop_probs_offset);
this->enemy_item_classes = r.pget<parray<uint8_t, 0x64>>(offsets.enemy_item_classes_offset); this->enemy_item_classes = r.pget<parray<uint8_t, 0x64>>(offsets.enemy_item_classes_offset);
{ {
const auto& data = r.pget<parray<Range<U16T>, 0x0A>>(offsets.box_meseta_ranges_offset); const auto& data = r.pget<parray<Range<U16T<BE>>, 0x0A>>(offsets.box_meseta_ranges_offset);
for (size_t z = 0; z < data.size(); z++) { for (size_t z = 0; z < data.size(); z++) {
this->box_meseta_ranges[z] = Range<uint16_t>{data[z].min, data[z].max}; this->box_meseta_ranges[z] = Range<uint16_t>{data[z].min, data[z].max};
} }
@@ -466,7 +464,7 @@ void CommonItemSet::Table::parse_itempt_t(const StringReader& r, bool is_v3) {
} }
} }
} else { // V3 } else { // V3
const auto& data = r.pget<parray<parray<U16T, 6>, 0x17>>(offsets.bonus_value_prob_table_offset); const auto& data = r.pget<parray<parray<U16T<BE>, 6>, 0x17>>(offsets.bonus_value_prob_table_offset);
for (size_t z = 0; z < data.size(); z++) { for (size_t z = 0; z < data.size(); z++) {
for (size_t x = 0; x < data[z].size(); x++) { for (size_t x = 0; x < data[z].size(); x++) {
this->bonus_value_prob_table[z][x] = data[z][x]; this->bonus_value_prob_table[z][x] = data[z][x];
@@ -478,7 +476,7 @@ void CommonItemSet::Table::parse_itempt_t(const StringReader& r, bool is_v3) {
this->special_mult = r.pget<parray<uint8_t, 0x0A>>(offsets.special_mult_offset); this->special_mult = r.pget<parray<uint8_t, 0x0A>>(offsets.special_mult_offset);
this->special_percent = r.pget<parray<uint8_t, 0x0A>>(offsets.special_percent_offset); this->special_percent = r.pget<parray<uint8_t, 0x0A>>(offsets.special_percent_offset);
{ {
const auto& data = r.pget<parray<parray<U16T, 0x0A>, 0x1C>>(offsets.tool_class_prob_table_offset); const auto& data = r.pget<parray<parray<U16T<BE>, 0x0A>, 0x1C>>(offsets.tool_class_prob_table_offset);
for (size_t z = 0; z < data.size(); z++) { for (size_t z = 0; z < data.size(); z++) {
for (size_t x = 0; x < data[z].size(); x++) { for (size_t x = 0; x < data[z].size(); x++) {
this->tool_class_prob_table[z][x] = data[z][x]; this->tool_class_prob_table[z][x] = data[z][x];
@@ -505,7 +503,7 @@ shared_ptr<const CommonItemSet::Table> CommonItemSet::get_table(
try { try {
return this->tables.at(this->key_for_table(episode, mode, difficulty, secid)); return this->tables.at(this->key_for_table(episode, mode, difficulty, secid));
} catch (const out_of_range&) { } catch (const out_of_range&) {
throw runtime_error(string_printf("common item table not available for episode=%s, mode=%s, difficulty=%hu, secid=%hu", throw runtime_error(phosg::string_printf("common item table not available for episode=%s, mode=%s, difficulty=%hu, secid=%hu",
name_for_episode(episode), name_for_mode(mode), difficulty, secid)); name_for_episode(episode), name_for_mode(mode), difficulty, secid));
} }
} }
@@ -518,7 +516,7 @@ AFSV2CommonItemSet::AFSV2CommonItemSet(
for (size_t difficulty = 0; difficulty < 4; difficulty++) { for (size_t difficulty = 0; difficulty < 4; difficulty++) {
for (size_t section_id = 0; section_id < 10; section_id++) { for (size_t section_id = 0; section_id < 10; section_id++) {
auto entry = pt_afs.get(difficulty * 10 + section_id); auto entry = pt_afs.get(difficulty * 10 + section_id);
StringReader r(entry.first, entry.second); phosg::StringReader r(entry.first, entry.second);
auto table = make_shared<Table>(r, false, false, Episode::EP1); auto table = make_shared<Table>(r, false, false, Episode::EP1);
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::NORMAL, difficulty, section_id), table); this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::NORMAL, difficulty, section_id), table);
this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::BATTLE, difficulty, section_id), table); this->tables.emplace(this->key_for_table(Episode::EP1, GameMode::BATTLE, difficulty, section_id), table);
@@ -556,7 +554,7 @@ GSLV3V4CommonItemSet::GSLV3V4CommonItemSet(std::shared_ptr<const std::string> gs
default: default:
throw runtime_error("invalid episode"); throw runtime_error("invalid episode");
} }
return string_printf( return phosg::string_printf(
"ItemPT%s%s%c%1hhu.rel", "ItemPT%s%s%c%1hhu.rel",
is_challenge ? "c" : "", is_challenge ? "c" : "",
episode_token, episode_token,
@@ -568,7 +566,7 @@ GSLV3V4CommonItemSet::GSLV3V4CommonItemSet(std::shared_ptr<const std::string> gs
for (Episode episode : episodes) { for (Episode episode : episodes) {
for (size_t difficulty = 0; difficulty < 4; difficulty++) { for (size_t difficulty = 0; difficulty < 4; difficulty++) {
for (size_t section_id = 0; section_id < 10; section_id++) { for (size_t section_id = 0; section_id < 10; section_id++) {
StringReader r; phosg::StringReader r;
try { try {
r = gsl.get_reader(filename_for_table(episode, difficulty, section_id, false)); r = gsl.get_reader(filename_for_table(episode, difficulty, section_id, false));
} catch (const exception&) { } catch (const exception&) {
@@ -602,7 +600,7 @@ GSLV3V4CommonItemSet::GSLV3V4CommonItemSet(std::shared_ptr<const std::string> gs
} }
} }
JSONCommonItemSet::JSONCommonItemSet(const JSON& json) { JSONCommonItemSet::JSONCommonItemSet(const phosg::JSON& json) {
for (const auto& mode_it : json.as_dict()) { for (const auto& mode_it : json.as_dict()) {
static const unordered_map<string, GameMode> mode_keys( static const unordered_map<string, GameMode> mode_keys(
{{"Normal", GameMode::NORMAL}, {"Battle", GameMode::BATTLE}, {"Challenge", GameMode::CHALLENGE}, {"Solo", GameMode::SOLO}}); {{"Normal", GameMode::NORMAL}, {"Battle", GameMode::BATTLE}, {"Challenge", GameMode::CHALLENGE}, {"Solo", GameMode::SOLO}});
@@ -791,7 +789,7 @@ const ProbabilityTable<uint8_t, 100>& TekkerAdjustmentSet::get_bonus_delta_prob_
} }
int8_t TekkerAdjustmentSet::get_luck(uint32_t start_offset, uint8_t delta_index) const { int8_t TekkerAdjustmentSet::get_luck(uint32_t start_offset, uint8_t delta_index) const {
StringReader sub_r = r.sub(start_offset); phosg::StringReader sub_r = r.sub(start_offset);
while (!sub_r.eof()) { while (!sub_r.eof()) {
const auto& entry = sub_r.get<LuckTableEntry>(); const auto& entry = sub_r.get<LuckTableEntry>();
if (entry.delta_index == 0xFF) { if (entry.delta_index == 0xFF) {
+31 -33
View File
@@ -8,14 +8,15 @@
#include "PSOEncryption.hh" #include "PSOEncryption.hh"
#include "StaticGameData.hh" #include "StaticGameData.hh"
#include "Text.hh" #include "Text.hh"
#include "Types.hh"
class CommonItemSet { class CommonItemSet {
public: public:
class Table { class Table {
public: public:
Table() = delete; Table() = delete;
Table(const JSON& json, Episode episode); Table(const phosg::JSON& json, Episode episode);
Table(const StringReader& r, bool big_endian, bool is_v3, Episode episode); Table(const phosg::StringReader& r, bool big_endian, bool is_v3, Episode episode);
template <typename IntT> template <typename IntT>
struct Range { struct Range {
@@ -47,18 +48,15 @@ public:
parray<uint8_t, 0x0A> unit_max_stars_table; parray<uint8_t, 0x0A> unit_max_stars_table;
parray<parray<uint8_t, 10>, 7> box_item_class_prob_table; parray<parray<uint8_t, 10>, 7> box_item_class_prob_table;
JSON json() const; phosg::JSON json() const;
void print(FILE* stream) const; void print(FILE* stream) const;
private: private:
template <bool IsBigEndian> template <bool BE>
void parse_itempt_t(const StringReader& r, bool is_v3); void parse_itempt_t(const phosg::StringReader& r, bool is_v3);
template <bool IsBigEndian> template <bool BE>
struct OffsetsT { struct OffsetsT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
// This data structure uses index probability tables in multiple places. An // This data structure uses index probability tables in multiple places. An
// index probability table is a table where each entry holds the probability // index probability table is a table where each entry holds the probability
// that that entry's index is used. For example, if the armor slot count // that that entry's index is used. For example, if the armor slot count
@@ -80,7 +78,7 @@ public:
// The indexes in this table correspond to the non-rare weapon types 01 // The indexes in this table correspond to the non-rare weapon types 01
// through 0C (Saber through Wand). // through 0C (Saber through Wand).
// V2/V3: -> parray<uint8_t, 0x0C> // V2/V3: -> parray<uint8_t, 0x0C>
/* 00 */ U32T base_weapon_type_prob_table_offset; /* 00 */ U32T<BE> base_weapon_type_prob_table_offset;
// This table specifies the base subtype for each weapon type. Negative // This table specifies the base subtype for each weapon type. Negative
// values here mean that the weapon cannot be found in the first N areas (so // values here mean that the weapon cannot be found in the first N areas (so
@@ -90,7 +88,7 @@ public:
// of weapon that actually appears depends on this value and a value from // of weapon that actually appears depends on this value and a value from
// the following table. // the following table.
// V2/V3: -> parray<int8_t, 0x0C> // V2/V3: -> parray<int8_t, 0x0C>
/* 04 */ U32T subtype_base_table_offset; /* 04 */ U32T<BE> subtype_base_table_offset;
// This table specifies how many areas each weapon subtype appears in. For // This table specifies how many areas each weapon subtype appears in. For
// example, if Sword (subtype 02, which is index 1 in this table and the // example, if Sword (subtype 02, which is index 1 in this table and the
@@ -99,7 +97,7 @@ public:
// through Mine 1), and Gigush (the next sword subtype) can be found in Mine // through Mine 1), and Gigush (the next sword subtype) can be found in Mine
// 1 through Ruins 3. // 1 through Ruins 3.
// V2/V3: -> parray<uint8_t, 0x0C> // V2/V3: -> parray<uint8_t, 0x0C>
/* 08 */ U32T subtype_area_length_table_offset; /* 08 */ U32T<BE> subtype_area_length_table_offset;
// This index probability table specifies how likely each possible grind // This index probability table specifies how likely each possible grind
// value is. The table is indexed as [grind][subtype_area_index], where the // value is. The table is indexed as [grind][subtype_area_index], where the
@@ -114,28 +112,28 @@ public:
// ... // ...
// C1 C2 C3 M1 // (Episode 1 area values from the example for reference) // C1 C2 C3 M1 // (Episode 1 area values from the example for reference)
// V2/V3: -> parray<parray<uint8_t, 4>, 9> // V2/V3: -> parray<parray<uint8_t, 4>, 9>
/* 0C */ U32T grind_prob_table_offset; /* 0C */ U32T<BE> grind_prob_table_offset;
// TODO: Figure out exactly how this table is used. Anchor: 80106D34 // TODO: Figure out exactly how this table is used. Anchor: 80106D34
// V2/V3: -> parray<uint8_t, 0x05> // V2/V3: -> parray<uint8_t, 0x05>
/* 10 */ U32T armor_shield_type_index_prob_table_offset; /* 10 */ U32T<BE> armor_shield_type_index_prob_table_offset;
// This index probability table specifies how common each possible slot // This index probability table specifies how common each possible slot
// count is for armor drops. // count is for armor drops.
// V2/V3: -> parray<uint8_t, 0x05> // V2/V3: -> parray<uint8_t, 0x05>
/* 14 */ U32T armor_slot_count_prob_table_offset; /* 14 */ U32T<BE> armor_slot_count_prob_table_offset;
// This array (indexed by enemy_type) specifies the range of meseta values // This array (indexed by enemy_type) specifies the range of meseta values
// that each enemy can drop. // that each enemy can drop.
// V2/V3: -> parray<Range<U16T>, 0x64> // V2/V3: -> parray<Range<U16T>, 0x64>
/* 18 */ U32T enemy_meseta_ranges_offset; /* 18 */ U32T<BE> enemy_meseta_ranges_offset;
// Each byte in this table (indexed by enemy_type) represents the percent // Each byte in this table (indexed by enemy_type) represents the percent
// chance that the enemy drops anything at all. (This check is done before // chance that the enemy drops anything at all. (This check is done before
// the rare drop check, so the chance of getting a rare item from an enemy // the rare drop check, so the chance of getting a rare item from an enemy
// is essentially this probability multiplied by the rare drop rate.) // is essentially this probability multiplied by the rare drop rate.)
// V2/V3: -> parray<uint8_t, 0x64> // V2/V3: -> parray<uint8_t, 0x64>
/* 1C */ U32T enemy_type_drop_probs_offset; /* 1C */ U32T<BE> enemy_type_drop_probs_offset;
// Each byte in this table (indexed by enemy_type) represents the class of // Each byte in this table (indexed by enemy_type) represents the class of
// item that the enemy can drop. The values are: // item that the enemy can drop. The values are:
@@ -147,12 +145,12 @@ public:
// 05 = meseta // 05 = meseta
// Anything else = no item // Anything else = no item
// V2/V3: -> parray<uint8_t, 0x64> // V2/V3: -> parray<uint8_t, 0x64>
/* 20 */ U32T enemy_item_classes_offset; /* 20 */ U32T<BE> enemy_item_classes_offset;
// This table (indexed by area - 1) specifies the ranges of meseta values // This table (indexed by area - 1) specifies the ranges of meseta values
// that can drop from boxes. // that can drop from boxes.
// V2/V3: -> parray<Range<U16T>, 0x0A> // V2/V3: -> parray<Range<U16T>, 0x0A>
/* 24 */ U32T box_meseta_ranges_offset; /* 24 */ U32T<BE> box_meseta_ranges_offset;
// This array specifies the chance that a rare weapon will have each // This array specifies the chance that a rare weapon will have each
// possible bonus value. This is indexed as [(bonus_value - 10 / 5)][spec], // possible bonus value. This is indexed as [(bonus_value - 10 / 5)][spec],
@@ -162,7 +160,7 @@ public:
// for rare items, spec is always 5. // for rare items, spec is always 5.
// V2: -> parray<parray<uint8_t, 5>, 0x17> // V2: -> parray<parray<uint8_t, 5>, 0x17>
// V3: -> parray<parray<U16T, 6>, 0x17> // V3: -> parray<parray<U16T, 6>, 0x17>
/* 28 */ U32T bonus_value_prob_table_offset; /* 28 */ U32T<BE> bonus_value_prob_table_offset;
// This array specifies the value of spec to be used in the above lookup for // This array specifies the value of spec to be used in the above lookup for
// non-rare items. This is NOT an index probability table; this is a direct // non-rare items. This is NOT an index probability table; this is a direct
@@ -178,7 +176,7 @@ public:
// bonus; in all other areas except Ruins 3, they can have at most two // bonus; in all other areas except Ruins 3, they can have at most two
// bonuses, and in Ruins 3, they can have up to three bonuses. // bonuses, and in Ruins 3, they can have up to three bonuses.
// V2/V3: // -> parray<parray<uint8_t, 10>, 3> // V2/V3: // -> parray<parray<uint8_t, 10>, 3>
/* 2C */ U32T nonrare_bonus_prob_spec_offset; /* 2C */ U32T<BE> nonrare_bonus_prob_spec_offset;
// This array specifies the chance that a weapon will have each bonus type. // This array specifies the chance that a weapon will have each bonus type.
// The table is indexed as [bonus_type][area - 1] for non-rare items; for // The table is indexed as [bonus_type][area - 1] for non-rare items; for
@@ -193,37 +191,37 @@ public:
// [00 00 00 00 00 01 01 01 01 01] // Chance of getting Hit bonus // [00 00 00 00 00 01 01 01 01 01] // Chance of getting Hit bonus
// F1 F2 C1 C2 C3 M1 M2 R1 R2 R3 // (Episode 1 areas, for reference) // F1 F2 C1 C2 C3 M1 M2 R1 R2 R3 // (Episode 1 areas, for reference)
// V2/V3: -> parray<parray<uint8_t, 10>, 6> // V2/V3: -> parray<parray<uint8_t, 10>, 6>
/* 30 */ U32T bonus_type_prob_table_offset; /* 30 */ U32T<BE> bonus_type_prob_table_offset;
// This array (indexed by area - 1) specifies a multiplier of used in // This array (indexed by area - 1) specifies a multiplier of used in
// special ability determination. It seems this uses the star values from // special ability determination. It seems this uses the star values from
// ItemPMT, but not yet clear exactly in what way. // ItemPMT, but not yet clear exactly in what way.
// TODO: Figure out exactly what this does. Anchor: 80106FEC // TODO: Figure out exactly what this does. Anchor: 80106FEC
// V2/V3: -> parray<uint8_t, 0x0A> // V2/V3: -> parray<uint8_t, 0x0A>
/* 34 */ U32T special_mult_offset; /* 34 */ U32T<BE> special_mult_offset;
// This array (indexed by area - 1) specifies the probability that any // This array (indexed by area - 1) specifies the probability that any
// non-rare weapon will have a special ability. // non-rare weapon will have a special ability.
// V2/V3: -> parray<uint8_t, 0x0A> // V2/V3: -> parray<uint8_t, 0x0A>
/* 38 */ U32T special_percent_offset; /* 38 */ U32T<BE> special_percent_offset;
// This index probability table is indexed by [tool_class][area - 1]. The // This index probability table is indexed by [tool_class][area - 1]. The
// tool class refers to an entry in ItemPMT, which links it to the actual // tool class refers to an entry in ItemPMT, which links it to the actual
// item code. // item code.
// V2/V3: -> parray<parray<U16T, 0x0A>, 0x1C> // V2/V3: -> parray<parray<U16T, 0x0A>, 0x1C>
/* 3C */ U32T tool_class_prob_table_offset; /* 3C */ U32T<BE> tool_class_prob_table_offset;
// This index probability table determines how likely each technique is to // This index probability table determines how likely each technique is to
// appear. The table is indexed as [technique_num][area - 1]. // appear. The table is indexed as [technique_num][area - 1].
// V2/V3: -> parray<parray<uint8_t, 0x0A>, 0x13> // V2/V3: -> parray<parray<uint8_t, 0x0A>, 0x13>
/* 40 */ U32T technique_index_prob_table_offset; /* 40 */ U32T<BE> technique_index_prob_table_offset;
// This table specifies the ranges for technique disk levels. The table is // This table specifies the ranges for technique disk levels. The table is
// indexed as [technique_num][area - 1]. If either min or max in the range // indexed as [technique_num][area - 1]. If either min or max in the range
// is 0xFF, or if max < min, technique disks are not dropped for that // is 0xFF, or if max < min, technique disks are not dropped for that
// technique and area pair. // technique and area pair.
// V2/V3: -> parray<parray<Range<uint8_t>, 0x0A>, 0x13> // V2/V3: -> parray<parray<Range<uint8_t>, 0x0A>, 0x13>
/* 44 */ U32T technique_level_ranges_offset; /* 44 */ U32T<BE> technique_level_ranges_offset;
/* 48 */ uint8_t armor_or_shield_type_bias; /* 48 */ uint8_t armor_or_shield_type_bias;
/* 49 */ parray<uint8_t, 3> unused1; /* 49 */ parray<uint8_t, 3> unused1;
@@ -234,7 +232,7 @@ public:
// game uniformly chooses a random number of stars in the acceptable // game uniformly chooses a random number of stars in the acceptable
// range, then uniformly chooses a random unit with that many stars. // range, then uniformly chooses a random unit with that many stars.
// V2/V3: -> parray<uint8_t, 0x0A> // V2/V3: -> parray<uint8_t, 0x0A>
/* 4C */ U32T unit_max_stars_offset; /* 4C */ U32T<BE> unit_max_stars_offset;
// This index probability table determines which type of items drop from // This index probability table determines which type of items drop from
// boxes. The table is indexed as [item_class][area - 1], with item_class // boxes. The table is indexed as [item_class][area - 1], with item_class
@@ -253,7 +251,7 @@ public:
// [16 16 11 11 11 11 11 0F 0C 0B] // Chances per area of an empty box // [16 16 11 11 11 11 11 0F 0C 0B] // Chances per area of an empty box
// F1 F2 C1 C2 C3 M1 M2 R1 R2 R3 // (Episode 1 areas, for reference) // F1 F2 C1 C2 C3 M1 M2 R1 R2 R3 // (Episode 1 areas, for reference)
// V2/V3: -> parray<parray<uint8_t, 10>, 7> // V2/V3: -> parray<parray<uint8_t, 10>, 7>
/* 50 */ U32T box_item_class_prob_table_offset; /* 50 */ U32T<BE> box_item_class_prob_table_offset;
// There are several unused fields here. // There are several unused fields here.
} __packed__; } __packed__;
@@ -264,7 +262,7 @@ public:
}; };
std::shared_ptr<const Table> get_table(Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const; std::shared_ptr<const Table> get_table(Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const;
JSON json() const; phosg::JSON json() const;
void print(FILE* stream) const; void print(FILE* stream) const;
protected: protected:
@@ -287,7 +285,7 @@ public:
class JSONCommonItemSet : public CommonItemSet { class JSONCommonItemSet : public CommonItemSet {
public: public:
explicit JSONCommonItemSet(const JSON& json); explicit JSONCommonItemSet(const phosg::JSON& json);
}; };
// Note: There are clearly better ways of doing this, but this implementation // Note: There are clearly better ways of doing this, but this implementation
@@ -348,7 +346,7 @@ public:
protected: protected:
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
StringReader r; phosg::StringReader r;
struct TableSpec { struct TableSpec {
be_uint32_t offset; be_uint32_t offset;
@@ -463,7 +461,7 @@ private:
int8_t get_luck(uint32_t start_offset, uint8_t delta_index) const; int8_t get_luck(uint32_t start_offset, uint8_t delta_index) const;
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
StringReader r; phosg::StringReader r;
struct DeltaProbabilityEntry { struct DeltaProbabilityEntry {
uint8_t delta_index; uint8_t delta_index;
+12 -12
View File
@@ -14,7 +14,7 @@
using namespace std; using namespace std;
template <> template <>
const char* name_for_enum<CompressPhase>(CompressPhase v) { const char* phosg::name_for_enum<CompressPhase>(CompressPhase v) {
switch (v) { switch (v) {
case CompressPhase::INDEX: case CompressPhase::INDEX:
return "INDEX"; return "INDEX";
@@ -118,7 +118,7 @@ struct WindowIndex {
}; };
struct LZSSInterleavedWriter { struct LZSSInterleavedWriter {
StringWriter w; phosg::StringWriter w;
size_t buf_offset; size_t buf_offset;
uint8_t next_control_bit; uint8_t next_control_bit;
uint8_t buf[0x19]; uint8_t buf[0x19];
@@ -166,7 +166,7 @@ struct LZSSInterleavedWriter {
class ControlStreamReader { class ControlStreamReader {
public: public:
ControlStreamReader(StringReader& r) ControlStreamReader(phosg::StringReader& r)
: r(r), : r(r),
bits(0x0000) {} bits(0x0000) {}
@@ -188,7 +188,7 @@ public:
} }
private: private:
StringReader& r; phosg::StringReader& r;
uint16_t bits; uint16_t bits;
}; };
@@ -493,7 +493,7 @@ void PRSCompressor::add(const void* data, size_t size) {
throw logic_error("compressor is closed"); throw logic_error("compressor is closed");
} }
StringReader r(data, size); phosg::StringReader r(data, size);
while (!r.eof()) { while (!r.eof()) {
this->add_byte(r.get_u8()); this->add_byte(r.get_u8());
} }
@@ -874,8 +874,8 @@ PRSDecompressResult prs_decompress_with_meta(
// is encountered partway through an opcode, we throw instead, because it's // is encountered partway through an opcode, we throw instead, because it's
// likely the input has been truncated or is malformed in some way. // likely the input has been truncated or is malformed in some way.
StringWriter w; phosg::StringWriter w;
StringReader r(data, size); phosg::StringReader r(data, size);
ControlStreamReader cr(r); ControlStreamReader cr(r);
while (!r.eof()) { while (!r.eof()) {
@@ -959,7 +959,7 @@ string prs_decompress(const string& data, size_t max_output_size, bool allow_unt
size_t prs_decompress_size(const void* data, size_t size, size_t max_output_size, bool allow_unterminated) { size_t prs_decompress_size(const void* data, size_t size, size_t max_output_size, bool allow_unterminated) {
size_t ret = 0; size_t ret = 0;
StringReader r(data, size); phosg::StringReader r(data, size);
ControlStreamReader cr(r); ControlStreamReader cr(r);
while (!r.eof()) { while (!r.eof()) {
@@ -1011,7 +1011,7 @@ size_t prs_decompress_size(const string& data, size_t max_output_size, bool allo
void prs_disassemble(FILE* stream, const void* data, size_t size) { void prs_disassemble(FILE* stream, const void* data, size_t size) {
size_t output_bytes = 0; size_t output_bytes = 0;
StringReader r(data, size); phosg::StringReader r(data, size);
ControlStreamReader cr(r); ControlStreamReader cr(r);
while (!r.eof()) { while (!r.eof()) {
@@ -1249,8 +1249,8 @@ string bc0_decompress(const string& data) {
} }
string bc0_decompress(const void* data, size_t size) { string bc0_decompress(const void* data, size_t size) {
StringReader r(data, size); phosg::StringReader r(data, size);
StringWriter w; phosg::StringWriter w;
// Unlike PRS, BC0 uses a memo which "rolls over" every 0x1000 bytes. The // Unlike PRS, BC0 uses a memo which "rolls over" every 0x1000 bytes. The
// boundaries of these "memo pages" are offset by -0x12 bytes for some reason, // boundaries of these "memo pages" are offset by -0x12 bytes for some reason,
@@ -1322,7 +1322,7 @@ void bc0_disassemble(FILE* stream, const string& data) {
} }
void bc0_disassemble(FILE* stream, const void* data, size_t size) { void bc0_disassemble(FILE* stream, const void* data, size_t size) {
StringReader r(data, size); phosg::StringReader r(data, size);
uint16_t control_stream_bits = 0x0000; uint16_t control_stream_bits = 0x0000;
size_t output_bytes = 0; size_t output_bytes = 0;
+2 -2
View File
@@ -18,7 +18,7 @@ enum class CompressPhase {
}; };
template <> template <>
const char* name_for_enum<CompressPhase>(CompressPhase v); const char* phosg::name_for_enum<CompressPhase>(CompressPhase v);
typedef std::function<void(CompressPhase phase, size_t input_progress, size_t input_size, size_t output_size)> ProgressCallback; typedef std::function<void(CompressPhase phase, size_t input_progress, size_t input_size, size_t output_size)> ProgressCallback;
@@ -146,7 +146,7 @@ private:
WrappedLog<0x101> forward_log; WrappedLog<0x101> forward_log;
IndexedLog<0x2000> reverse_log; IndexedLog<0x2000> reverse_log;
StringWriter output; phosg::StringWriter output;
}; };
// These functions use PRSCompressor to compress a buffer of data. This is // These functions use PRSCompressor to compress a buffer of data. This is
+20 -20
View File
@@ -1174,7 +1174,7 @@ static uint64_t decode_dc_serial_number_str(const string& s) {
if (new_ch == '\0') { if (new_ch == '\0') {
return INVALID_PRODUCT; return INVALID_PRODUCT;
} }
serial_number = (serial_number << 4) | value_for_hex_char(new_ch); serial_number = (serial_number << 4) | phosg::value_for_hex_char(new_ch);
} }
return serial_number; return serial_number;
} }
@@ -1291,12 +1291,12 @@ string generate_dc_serial_number(uint8_t domain, uint8_t subdomain) {
throw runtime_error("invalid domain"); throw runtime_error("invalid domain");
} }
size_t det1 = (subdomain == 0xFF) ? random_object<uint32_t>() : subdomain; size_t det1 = (subdomain == 0xFF) ? phosg::random_object<uint32_t>() : subdomain;
size_t index1 = offset1 + (det1 % (limit1 - offset1)); size_t index1 = offset1 + (det1 % (limit1 - offset1));
size_t index2 = random_object<uint32_t>() % (sizeof(primes2) / sizeof(primes2[0])); size_t index2 = phosg::random_object<uint32_t>() % (sizeof(primes2) / sizeof(primes2[0]));
size_t index3 = random_object<uint32_t>() % (sizeof(primes3) / sizeof(primes3[0])); size_t index3 = phosg::random_object<uint32_t>() % (sizeof(primes3) / sizeof(primes3[0]));
uint32_t value = primes1[index1] * primes2[index2] * primes3[index3]; uint32_t value = primes1[index1] * primes2[index2] * primes3[index3];
string s = string_printf("%08X", value); string s = phosg::string_printf("%08X", value);
string ret; string ret;
for (char ch : s) { for (char ch : s) {
@@ -1355,7 +1355,7 @@ unordered_map<uint32_t, string> generate_all_dc_serial_numbers(uint8_t domain, u
} }
void dc_serial_number_speed_test(uint64_t seed) { void dc_serial_number_speed_test(uint64_t seed) {
uint32_t effective_seed = (seed & 0xFFFFFFFF00000000) ? random_object<uint32_t>() : seed; uint32_t effective_seed = (seed & 0xFFFFFFFF00000000) ? phosg::random_object<uint32_t>() : seed;
fprintf(stderr, "Product speed test with seed=%08" PRIX32 "\n", effective_seed); fprintf(stderr, "Product speed test with seed=%08" PRIX32 "\n", effective_seed);
PSOV2Encryption crypt(effective_seed); PSOV2Encryption crypt(effective_seed);
uint64_t time_slow = 0; uint64_t time_slow = 0;
@@ -1363,15 +1363,15 @@ void dc_serial_number_speed_test(uint64_t seed) {
size_t num_disagreements = 0; size_t num_disagreements = 0;
static constexpr size_t count = 0x1000; static constexpr size_t count = 0x1000;
for (size_t z = 0; z < count; z++) { for (size_t z = 0; z < count; z++) {
string s = string_printf("%08X", crypt.next()); string s = phosg::string_printf("%08X", crypt.next());
uint64_t start = now(); uint64_t start = phosg::now();
bool is_valid_fast = dc_serial_number_is_valid_fast(s, 1, 0xFF); bool is_valid_fast = dc_serial_number_is_valid_fast(s, 1, 0xFF);
time_fast += now() - start; time_fast += phosg::now() - start;
start = now(); start = phosg::now();
bool is_valid_slow = dc_serial_number_is_valid_slow(s, 1, 0xFF); bool is_valid_slow = dc_serial_number_is_valid_slow(s, 1, 0xFF);
time_slow += now() - start; time_slow += phosg::now() - start;
if (((z & 0xF) == 0) || is_valid_slow || is_valid_fast) { if (((z & 0xF) == 0) || is_valid_slow || is_valid_fast) {
fprintf(stderr, "... %02zX: %s => %s %s%s\n", z, s.c_str(), is_valid_slow ? "SLOW" : "----", is_valid_fast ? "FAST" : "----", is_valid_slow != is_valid_fast ? " !!!" : ""); fprintf(stderr, "... %02zX: %s => %s %s%s\n", z, s.c_str(), is_valid_slow ? "SLOW" : "----", is_valid_fast ? "FAST" : "----", is_valid_slow != is_valid_fast ? " !!!" : "");
@@ -1391,13 +1391,13 @@ string decrypt_dp_address_jpn(
const string& executable, const string& executable,
const string& values, const string& values,
const string& indexes) { const string& indexes) {
StringReader values_r(values); phosg::StringReader values_r(values);
StringReader indexes_r(indexes); phosg::StringReader indexes_r(indexes);
size_t fixup_values_offset = values_r.pget_u32l(0x3FFC) - 0x8C004000; size_t fixup_values_offset = values_r.pget_u32l(0x3FFC) - 0x8C004000;
size_t fixup_steps_offset = indexes_r.pget_u32l(0x3BFC) - 0x8C008400; size_t fixup_steps_offset = indexes_r.pget_u32l(0x3BFC) - 0x8C008400;
StringReader fixup_values_r = values_r.sub(fixup_values_offset); phosg::StringReader fixup_values_r = values_r.sub(fixup_values_offset);
StringReader fixup_steps_r = indexes_r.sub(fixup_steps_offset); phosg::StringReader fixup_steps_r = indexes_r.sub(fixup_steps_offset);
auto decrypted = decrypt_pr2_data<false>(executable); auto decrypted = decrypt_pr2_data<false>(executable);
size_t fixup_offset = 0; size_t fixup_offset = 0;
@@ -1417,9 +1417,9 @@ EncryptedDCv2Executables encrypt_dp_address_jpn(const string& executable, const
EncryptedDCv2Executables ret; EncryptedDCv2Executables ret;
string compressed = prs_compress(executable); string compressed = prs_compress(executable);
ret.executable = encrypt_pr2_data<false>(compressed, executable.size(), random_object<uint32_t>() & 0x7FFFFF7F); ret.executable = encrypt_pr2_data<false>(compressed, executable.size(), phosg::random_object<uint32_t>() & 0x7FFFFF7F);
StringReader indexes_r(indexes); phosg::StringReader indexes_r(indexes);
size_t fixup_steps_offset = indexes_r.pget_u32l(0x3BFC) - 0x8C008400; size_t fixup_steps_offset = indexes_r.pget_u32l(0x3BFC) - 0x8C008400;
ret.indexes = indexes; ret.indexes = indexes;
ret.indexes.at(fixup_steps_offset) = 0; ret.indexes.at(fixup_steps_offset) = 0;
@@ -1431,7 +1431,7 @@ std::string crypt_dp_address_jpn_simple(const std::string& data, int64_t mask_ke
throw runtime_error("size is not a multiple of 4"); throw runtime_error("size is not a multiple of 4");
} }
StringReader r(data); phosg::StringReader r(data);
if (mask_key < 0) { if (mask_key < 0) {
unordered_map<uint32_t, size_t> key_freq; unordered_map<uint32_t, size_t> key_freq;
while (!r.eof()) { while (!r.eof()) {
@@ -1447,11 +1447,11 @@ std::string crypt_dp_address_jpn_simple(const std::string& data, int64_t mask_ke
if (mask_key < 0) { if (mask_key < 0) {
throw runtime_error("cannot determine mask key"); throw runtime_error("cannot determine mask key");
} }
log_info("Determined %08" PRIX64 " to be the most likely mask key", mask_key); phosg::log_info("Determined %08" PRIX64 " to be the most likely mask key", mask_key);
r.go(0); r.go(0);
} }
StringWriter w; phosg::StringWriter w;
while (!r.eof()) { while (!r.eof()) {
w.put_u32l(r.get_u32l() ^ mask_key); w.put_u32l(r.get_u32l() ^ mask_key);
} }
+5 -5
View File
@@ -34,15 +34,15 @@ DNSServer::~DNSServer() {
} }
void DNSServer::listen(const std::string& socket_path) { void DNSServer::listen(const std::string& socket_path) {
this->add_socket(::listen(socket_path, 0, 0)); this->add_socket(phosg::listen(socket_path, 0, 0));
} }
void DNSServer::listen(const std::string& addr, int port) { void DNSServer::listen(const std::string& addr, int port) {
this->add_socket(::listen(addr, port, 0)); this->add_socket(phosg::listen(addr, port, 0));
} }
void DNSServer::listen(int port) { void DNSServer::listen(int port) {
this->add_socket(::listen("", port, 0)); this->add_socket(phosg::listen("", port, 0));
} }
void DNSServer::add_socket(int fd) { void DNSServer::add_socket(int fd) {
@@ -66,7 +66,7 @@ string DNSServer::response_for_query(const void* vdata, size_t size, uint32_t re
const char* data = reinterpret_cast<const char*>(vdata); const char* data = reinterpret_cast<const char*>(vdata);
size_t name_len = strlen(&data[12]) + 1; size_t name_len = strlen(&data[12]) + 1;
be_uint32_t be_resolved_address = resolved_address; phosg::be_uint32_t be_resolved_address = resolved_address;
string response; string response;
response.append(data, 2); response.append(data, 2);
@@ -104,7 +104,7 @@ void DNSServer::on_receive_message(int fd, short) {
} else if (bytes < 0x0C) { } else if (bytes < 0x0C) {
dns_server_log.warning("input query too small"); dns_server_log.warning("input query too small");
print_data(stderr, input.data(), bytes); phosg::print_data(stderr, input.data(), bytes);
} else if (!this->banned_ipv4_ranges->check(remote)) { } else if (!this->banned_ipv4_ranges->check(remote)) {
input.resize(bytes); input.resize(bytes);
+6 -6
View File
@@ -10,7 +10,7 @@
using namespace std; using namespace std;
template <> template <>
const char* name_for_enum<EnemyType>(EnemyType type) { const char* phosg::name_for_enum<EnemyType>(EnemyType type) {
switch (type) { switch (type) {
case EnemyType::UNKNOWN: case EnemyType::UNKNOWN:
return "UNKNOWN"; return "UNKNOWN";
@@ -274,7 +274,7 @@ const char* name_for_enum<EnemyType>(EnemyType type) {
} }
template <> template <>
EnemyType enum_for_name<EnemyType>(const char* name) { EnemyType phosg::enum_for_name<EnemyType>(const char* name) {
static const unordered_map<string, EnemyType> names({ static const unordered_map<string, EnemyType> names({
{"UNKNOWN", EnemyType::UNKNOWN}, {"UNKNOWN", EnemyType::UNKNOWN},
{"NONE", EnemyType::NONE}, {"NONE", EnemyType::NONE},
@@ -672,7 +672,7 @@ uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type)
case EnemyType::SO_DIMENIAN: case EnemyType::SO_DIMENIAN:
return 0x55; return 0x55;
default: default:
throw runtime_error(string_printf("%s does not have battle parameters in Episode 1", name_for_enum(enemy_type))); throw runtime_error(phosg::string_printf("%s does not have battle parameters in Episode 1", phosg::name_for_enum(enemy_type)));
} }
break; break;
case Episode::EP2: case Episode::EP2:
@@ -787,7 +787,7 @@ uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type)
case EnemyType::SO_DIMENIAN: case EnemyType::SO_DIMENIAN:
return 0x55; return 0x55;
default: default:
throw runtime_error(string_printf("%s does not have battle parameters in Episode 2", name_for_enum(enemy_type))); throw runtime_error(phosg::string_printf("%s does not have battle parameters in Episode 2", phosg::name_for_enum(enemy_type)));
} }
break; break;
case Episode::EP4: case Episode::EP4:
@@ -847,7 +847,7 @@ uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type)
case EnemyType::KONDRIEU: case EnemyType::KONDRIEU:
return 0x2A; return 0x2A;
default: default:
throw runtime_error(string_printf("%s does not have battle parameters in Episode 4", name_for_enum(enemy_type))); throw runtime_error(phosg::string_printf("%s does not have battle parameters in Episode 4", phosg::name_for_enum(enemy_type)));
} }
break; break;
default: default:
@@ -1072,7 +1072,7 @@ uint8_t rare_table_index_for_enemy_type(EnemyType enemy_type) {
case EnemyType::ZU_ALT: case EnemyType::ZU_ALT:
return 0x4A; return 0x4A;
default: default:
throw runtime_error(string_printf("%s does not have a rare table entry", name_for_enum(enemy_type))); throw runtime_error(phosg::string_printf("%s does not have a rare table entry", phosg::name_for_enum(enemy_type)));
} }
} }
+3 -2
View File
@@ -5,6 +5,7 @@
#include <phosg/Tools.hh> #include <phosg/Tools.hh>
#include "StaticGameData.hh" #include "StaticGameData.hh"
#include "Types.hh"
enum class EnemyType { enum class EnemyType {
UNKNOWN = -1, UNKNOWN = -1,
@@ -138,9 +139,9 @@ enum class EnemyType {
}; };
template <> template <>
const char* name_for_enum<EnemyType>(EnemyType type); const char* phosg::name_for_enum<EnemyType>(EnemyType type);
template <> template <>
EnemyType enum_for_name<EnemyType>(const char* name); EnemyType phosg::enum_for_name<EnemyType>(const char* name);
bool enemy_type_valid_for_episode(Episode episode, EnemyType enemy_type); bool enemy_type_valid_for_episode(Episode episode, EnemyType enemy_type);
uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type); uint8_t battle_param_index_for_enemy_type(Episode episode, EnemyType enemy_type);
+25 -26
View File
@@ -12,10 +12,10 @@ namespace Episode3 {
void BattleRecord::PlayerEntry::print(FILE* stream) const { void BattleRecord::PlayerEntry::print(FILE* stream) const {
// TODO: Format this nicely somehow. Maybe factor out the functions in // TODO: Format this nicely somehow. Maybe factor out the functions in
// QuestScript that format some of these structures // QuestScript that format some of these structures
print_data(stream, this, sizeof(*this), 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stream, this, sizeof(*this), 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
} }
BattleRecord::Event::Event(StringReader& r) { BattleRecord::Event::Event(phosg::StringReader& r) {
this->type = r.get<Event::Type>(); this->type = r.get<Event::Type>();
this->timestamp = r.get_u64l(); this->timestamp = r.get_u64l();
switch (this->type) { switch (this->type) {
@@ -46,7 +46,7 @@ BattleRecord::Event::Event(StringReader& r) {
} }
} }
void BattleRecord::Event::serialize(StringWriter& w) const { void BattleRecord::Event::serialize(phosg::StringWriter& w) const {
w.put(this->type); w.put(this->type);
w.put_u64l(this->timestamp); w.put_u64l(this->timestamp);
switch (this->type) { switch (this->type) {
@@ -81,7 +81,7 @@ void BattleRecord::Event::serialize(StringWriter& w) const {
} }
void BattleRecord::Event::print(FILE* stream) const { void BattleRecord::Event::print(FILE* stream) const {
string time_str = format_time(this->timestamp); string time_str = phosg::format_time(this->timestamp);
fprintf(stream, "Event @%016" PRIX64 " (%s) ", this->timestamp, time_str.c_str()); fprintf(stream, "Event @%016" PRIX64 " (%s) ", this->timestamp, time_str.c_str());
switch (this->type) { switch (this->type) {
case Type::PLAYER_JOIN: case Type::PLAYER_JOIN:
@@ -103,23 +103,23 @@ void BattleRecord::Event::print(FILE* stream) const {
break; break;
case Type::BATTLE_COMMAND: case Type::BATTLE_COMMAND:
fprintf(stream, "BATTLE_COMMAND\n"); fprintf(stream, "BATTLE_COMMAND\n");
print_data(stream, this->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stream, this->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
break; break;
case Type::GAME_COMMAND: case Type::GAME_COMMAND:
fprintf(stream, "GAME_COMMAND\n"); fprintf(stream, "GAME_COMMAND\n");
print_data(stream, this->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stream, this->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
break; break;
case Type::EP3_GAME_COMMAND: case Type::EP3_GAME_COMMAND:
fprintf(stream, "EP3_GAME_COMMAND\n"); fprintf(stream, "EP3_GAME_COMMAND\n");
print_data(stream, this->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stream, this->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
break; break;
case Type::CHAT_MESSAGE: case Type::CHAT_MESSAGE:
fprintf(stream, "CHAT_MESSAGE %08" PRIX32 "\n", this->guild_card_number); fprintf(stream, "CHAT_MESSAGE %08" PRIX32 "\n", this->guild_card_number);
print_data(stream, this->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stream, this->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
break; break;
case Type::SERVER_DATA_COMMAND: case Type::SERVER_DATA_COMMAND:
fprintf(stream, "SERVER_DATA_COMMAND\n"); fprintf(stream, "SERVER_DATA_COMMAND\n");
print_data(stream, this->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stream, this->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
break; break;
default: default:
throw runtime_error("unknown event type in battle record"); throw runtime_error("unknown event type in battle record");
@@ -137,7 +137,7 @@ BattleRecord::BattleRecord(const string& data)
behavior_flags(0), behavior_flags(0),
battle_start_timestamp(0), battle_start_timestamp(0),
battle_end_timestamp(0) { battle_end_timestamp(0) {
StringReader r(data); phosg::StringReader r(data);
uint64_t signature = r.get_u64l(); uint64_t signature = r.get_u64l();
bool has_random_stream; bool has_random_stream;
@@ -161,7 +161,7 @@ BattleRecord::BattleRecord(const string& data)
} }
string BattleRecord::serialize() const { string BattleRecord::serialize() const {
StringWriter w; phosg::StringWriter w;
w.put_u64l(this->SIGNATURE_V2); w.put_u64l(this->SIGNATURE_V2);
w.put_u64l(this->battle_start_timestamp); w.put_u64l(this->battle_start_timestamp);
w.put_u64l(this->battle_end_timestamp); w.put_u64l(this->battle_end_timestamp);
@@ -202,7 +202,7 @@ void BattleRecord::add_player(
} }
Event& ev = this->events.emplace_back(); Event& ev = this->events.emplace_back();
ev.type = Event::Type::PLAYER_JOIN; ev.type = Event::Type::PLAYER_JOIN;
ev.timestamp = now(); ev.timestamp = phosg::now();
auto& player = ev.players.emplace_back(); auto& player = ev.players.emplace_back();
player.lobby_data = lobby_data; player.lobby_data = lobby_data;
player.inventory = inventory; player.inventory = inventory;
@@ -216,7 +216,7 @@ void BattleRecord::delete_player(uint8_t client_id) {
} }
Event& ev = this->events.emplace_back(); Event& ev = this->events.emplace_back();
ev.type = Event::Type::PLAYER_LEAVE; ev.type = Event::Type::PLAYER_LEAVE;
ev.timestamp = now(); ev.timestamp = phosg::now();
ev.leaving_client_id = client_id; ev.leaving_client_id = client_id;
} }
@@ -226,7 +226,7 @@ void BattleRecord::add_command(Event::Type type, const void* data, size_t size)
} }
Event& ev = this->events.emplace_back(); Event& ev = this->events.emplace_back();
ev.type = type; ev.type = type;
ev.timestamp = now(); ev.timestamp = phosg::now();
ev.data.assign(reinterpret_cast<const char*>(data), size); ev.data.assign(reinterpret_cast<const char*>(data), size);
} }
@@ -236,7 +236,7 @@ void BattleRecord::add_command(Event::Type type, string&& data) {
} }
Event& ev = this->events.emplace_back(); Event& ev = this->events.emplace_back();
ev.type = type; ev.type = type;
ev.timestamp = now(); ev.timestamp = phosg::now();
ev.data = std::move(data); ev.data = std::move(data);
} }
@@ -247,7 +247,7 @@ void BattleRecord::add_chat_message(
} }
Event& ev = this->events.emplace_back(); Event& ev = this->events.emplace_back();
ev.type = Event::Type::CHAT_MESSAGE; ev.type = Event::Type::CHAT_MESSAGE;
ev.timestamp = now(); ev.timestamp = phosg::now();
ev.guild_card_number = guild_card_number; ev.guild_card_number = guild_card_number;
ev.data = std::move(data); ev.data = std::move(data);
} }
@@ -287,7 +287,7 @@ void BattleRecord::set_battle_start_timestamp() {
if (this->battle_start_timestamp != 0) { if (this->battle_start_timestamp != 0) {
throw logic_error("battle start timestamp is already set"); throw logic_error("battle start timestamp is already set");
} }
this->battle_start_timestamp = now(); this->battle_start_timestamp = phosg::now();
// First, find the correct map definition subcommand to keep, and execute // First, find the correct map definition subcommand to keep, and execute
// player join/leave events to get the present players // player join/leave events to get the present players
@@ -357,12 +357,12 @@ void BattleRecord::set_battle_start_timestamp() {
} }
void BattleRecord::set_battle_end_timestamp() { void BattleRecord::set_battle_end_timestamp() {
this->battle_end_timestamp = now(); this->battle_end_timestamp = phosg::now();
} }
void BattleRecord::print(FILE* stream) const { void BattleRecord::print(FILE* stream) const {
string start_str = format_time(this->battle_start_timestamp); string start_str = phosg::format_time(this->battle_start_timestamp);
string end_str = format_time(this->battle_end_timestamp); string end_str = phosg::format_time(this->battle_end_timestamp);
fprintf(stream, "BattleRecord %s behavior_flags=%08" PRIX32 " start=%016" PRIX64 " (%s) end=%016" PRIX64 " (%s); %zu events\n", fprintf(stream, "BattleRecord %s behavior_flags=%08" PRIX32 " start=%016" PRIX64 " (%s) end=%016" PRIX64 " (%s); %zu events\n",
this->is_writable ? "writable" : "read-only", this->is_writable ? "writable" : "read-only",
this->behavior_flags, this->behavior_flags,
@@ -394,13 +394,12 @@ void BattleRecordPlayer::set_lobby(shared_ptr<Lobby> l) {
void BattleRecordPlayer::start() { void BattleRecordPlayer::start() {
if (this->play_start_timestamp == 0) { if (this->play_start_timestamp == 0) {
this->play_start_timestamp = now(); this->play_start_timestamp = phosg::now();
this->schedule_events(); this->schedule_events();
} }
} }
void BattleRecordPlayer::dispatch_schedule_events( void BattleRecordPlayer::dispatch_schedule_events(evutil_socket_t, short, void* ctx) {
evutil_socket_t, short, void* ctx) {
reinterpret_cast<BattleRecordPlayer*>(ctx)->schedule_events(); reinterpret_cast<BattleRecordPlayer*>(ctx)->schedule_events();
} }
@@ -413,7 +412,7 @@ void BattleRecordPlayer::schedule_events() {
} }
for (;;) { for (;;) {
uint64_t relative_ts = now() - this->play_start_timestamp + this->record->battle_start_timestamp; uint64_t relative_ts = phosg::now() - this->play_start_timestamp + this->record->battle_start_timestamp;
if (this->event_it == this->record->events.end()) { if (this->event_it == this->record->events.end()) {
if (relative_ts >= this->record->battle_end_timestamp) { if (relative_ts >= this->record->battle_end_timestamp) {
@@ -426,7 +425,7 @@ void BattleRecordPlayer::schedule_events() {
} else { } else {
// There are no more events to play, but the battle has not officially // There are no more events to play, but the battle has not officially
// ended yet - reschedule the event for the end time // ended yet - reschedule the event for the end time
auto tv = usecs_to_timeval(this->record->battle_end_timestamp - relative_ts); auto tv = phosg::usecs_to_timeval(this->record->battle_end_timestamp - relative_ts);
event_add(this->next_command_ev.get(), &tv); event_add(this->next_command_ev.get(), &tv);
} }
break; break;
@@ -467,7 +466,7 @@ void BattleRecordPlayer::schedule_events() {
} else { } else {
// The next event should not occur yet, so reschedule for the time when // The next event should not occur yet, so reschedule for the time when
// it should occur // it should occur
auto tv = usecs_to_timeval(this->event_it->timestamp - relative_ts); auto tv = phosg::usecs_to_timeval(this->event_it->timestamp - relative_ts);
event_add(this->next_command_ev.get(), &tv); event_add(this->next_command_ev.get(), &tv);
break; break;
} }
+3 -3
View File
@@ -53,8 +53,8 @@ public:
std::string data; std::string data;
Event() = default; Event() = default;
explicit Event(StringReader& r); explicit Event(phosg::StringReader& r);
void serialize(StringWriter& w) const; void serialize(phosg::StringWriter& w) const;
void print(FILE* stream) const; void print(FILE* stream) const;
}; };
@@ -126,7 +126,7 @@ private:
std::shared_ptr<struct event_base> base; std::shared_ptr<struct event_base> base;
std::weak_ptr<Lobby> lobby; std::weak_ptr<Lobby> lobby;
std::shared_ptr<struct event> next_command_ev; std::shared_ptr<struct event> next_command_ev;
StringReader random_r; phosg::StringReader random_r;
}; };
} // namespace Episode3 } // namespace Episode3
+9 -9
View File
@@ -123,7 +123,7 @@ ssize_t Card::apply_abnormal_condition(
int8_t dice_roll_value, int8_t dice_roll_value,
int8_t random_percent) { int8_t random_percent) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("apply_abnormal_condition(%02hhX, @%04X, @%04X, %hd, %hhd, %hhd): ", def_effect_index, target_card_ref, sc_card_ref, value, dice_roll_value, random_percent)); auto log = s->log_stack(phosg::string_printf("apply_abnormal_condition(%02hhX, @%04X, @%04X, %hd, %hhd, %hhd): ", def_effect_index, target_card_ref, sc_card_ref, value, dice_roll_value, random_percent));
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
ssize_t existing_cond_index; ssize_t existing_cond_index;
@@ -298,7 +298,7 @@ void Card::commit_attack(
size_t strike_number, size_t strike_number,
int16_t* out_effective_damage) { int16_t* out_effective_damage) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("commit_attack(@%04hX #%04hX, @%04hX #%04hX => %hd (str%zu)): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id(), damage, strike_number)); auto log = s->log_stack(phosg::string_printf("commit_attack(@%04hX #%04hX, @%04hX #%04hX => %hd (str%zu)): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id(), damage, strike_number));
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
int16_t effective_damage = damage; int16_t effective_damage = damage;
@@ -507,7 +507,7 @@ void Card::execute_attack(shared_ptr<Card> attacker_card) {
} }
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("execute_attack(@%04X #%04X, @%04X #%04X): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id())); auto log = s->log_stack(phosg::string_printf("execute_attack(@%04X #%04X, @%04X #%04X): ", this->get_card_ref(), this->get_card_id(), attacker_card->get_card_ref(), attacker_card->get_card_id()));
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
this->card_flags &= 0xFFFFFFF3; this->card_flags &= 0xFFFFFFF3;
@@ -905,7 +905,7 @@ void Card::clear_action_chain_and_metadata_and_most_flags() {
void Card::compute_action_chain_results(bool apply_action_conditions, bool ignore_this_card_ap_tp) { void Card::compute_action_chain_results(bool apply_action_conditions, bool ignore_this_card_ap_tp) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("compute_action_chain_results(@%04hX #%04hX): ", this->get_card_ref(), this->get_card_id())); auto log = s->log_stack(phosg::string_printf("compute_action_chain_results(@%04hX #%04hX): ", this->get_card_ref(), this->get_card_id()));
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
this->action_chain.compute_attack_medium(s); this->action_chain.compute_attack_medium(s);
@@ -914,7 +914,7 @@ void Card::compute_action_chain_results(bool apply_action_conditions, bool ignor
this->action_chain.chain.tp_effect_bonus = 0; this->action_chain.chain.tp_effect_bonus = 0;
log.debug("(initial) medium=%s, strike_count=%hhu, ap_effect_bonus=%hhd, tp_effect_bonus=%hhd", log.debug("(initial) medium=%s, strike_count=%hhu, ap_effect_bonus=%hhd, tp_effect_bonus=%hhd",
name_for_enum(this->action_chain.chain.attack_medium), phosg::name_for_enum(this->action_chain.chain.attack_medium),
this->action_chain.chain.strike_count, this->action_chain.chain.strike_count,
this->action_chain.chain.ap_effect_bonus, this->action_chain.chain.ap_effect_bonus,
this->action_chain.chain.tp_effect_bonus); this->action_chain.chain.tp_effect_bonus);
@@ -1220,7 +1220,7 @@ void Card::move_phase_before() {
void Card::unknown_80236374(shared_ptr<Card> other_card, const ActionState* as) { void Card::unknown_80236374(shared_ptr<Card> other_card, const ActionState* as) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("unknown_80236374(@%04hX #%04hX, @%04hX #%04hX): ", this->get_card_ref(), this->get_card_id(), other_card->get_card_ref(), other_card->get_card_id())); auto log = s->log_stack(phosg::string_printf("unknown_80236374(@%04hX #%04hX, @%04hX #%04hX): ", this->get_card_ref(), this->get_card_id(), other_card->get_card_ref(), other_card->get_card_id()));
auto check_card = [&](shared_ptr<Card> card) -> void { auto check_card = [&](shared_ptr<Card> card) -> void {
if (card) { if (card) {
@@ -1361,8 +1361,8 @@ bool Card::is_guard_item() const {
bool Card::unknown_80236554(shared_ptr<Card> other_card, const ActionState* as) { bool Card::unknown_80236554(shared_ptr<Card> other_card, const ActionState* as) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(other_card auto log = s->log_stack(other_card
? string_printf("unknown_80236554(@%04hX #%04hX, @%04hX #%04hX): ", this->get_card_ref(), this->get_card_id(), other_card->get_card_ref(), other_card->get_card_id()) ? phosg::string_printf("unknown_80236554(@%04hX #%04hX, @%04hX #%04hX): ", this->get_card_ref(), this->get_card_id(), other_card->get_card_ref(), other_card->get_card_id())
: string_printf("unknown_80236554(@%04hX #%04hX, null): ", this->get_card_ref(), this->get_card_id())); : phosg::string_printf("unknown_80236554(@%04hX #%04hX, null): ", this->get_card_ref(), this->get_card_id()));
if (as) { if (as) {
string as_str = as->str(s); string as_str = as->str(s);
log.debug("as = %s", as_str.c_str()); log.debug("as = %s", as_str.c_str());
@@ -1439,7 +1439,7 @@ void Card::apply_attack_result() {
auto ps = this->player_state(); auto ps = this->player_state();
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
auto log = s->log_stack(string_printf("apply_attack_result(@%04hX #%04hX): ", this->get_card_ref(), this->get_card_id())); auto log = s->log_stack(phosg::string_printf("apply_attack_result(@%04hX #%04hX): ", this->get_card_ref(), this->get_card_id()));
if (!this->action_chain.can_apply_attack()) { if (!this->action_chain.can_apply_attack()) {
return; return;
} }
+20 -21
View File
@@ -21,7 +21,7 @@ static string refs_str_for_cards_vector(const vector<shared_ptr<T>>& cards) {
if (!ret.empty()) { if (!ret.empty()) {
ret += ", "; ret += ", ";
} }
ret += string_printf("@%04hX", ref_for_card(card)); ret += phosg::string_printf("@%04hX", ref_for_card(card));
} }
return ret; return ret;
} }
@@ -453,7 +453,7 @@ bool CardSpecial::apply_stat_deltas_to_all_cards_from_all_conditions_with_card_r
bool CardSpecial::apply_stat_deltas_to_card_from_condition_and_clear_cond(Condition& cond, shared_ptr<Card> card) { bool CardSpecial::apply_stat_deltas_to_card_from_condition_and_clear_cond(Condition& cond, shared_ptr<Card> card) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("apply_stat_deltas_to_card_from_condition_and_clear_cond(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id())); auto log = s->log_stack(phosg::string_printf("apply_stat_deltas_to_card_from_condition_and_clear_cond(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id()));
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
string cond_str = cond.str(s); string cond_str = cond.str(s);
@@ -585,7 +585,7 @@ bool CardSpecial::apply_stat_deltas_to_card_from_condition_and_clear_cond(Condit
break; break;
trial_unimplemented: trial_unimplemented:
default: default:
log.debug("%s: no adjustments for condition type", name_for_enum(cond_type)); log.debug("%s: no adjustments for condition type", phosg::name_for_enum(cond_type));
break; break;
} }
@@ -1189,7 +1189,7 @@ shared_ptr<Card> CardSpecial::compute_replaced_target_based_on_conditions(
StatSwapType CardSpecial::compute_stat_swap_type(shared_ptr<const Card> card) const { StatSwapType CardSpecial::compute_stat_swap_type(shared_ptr<const Card> card) const {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("compute_stat_swap_type(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id())); auto log = s->log_stack(phosg::string_printf("compute_stat_swap_type(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id()));
if (!card) { if (!card) {
log.debug("card is missing"); log.debug("card is missing");
return StatSwapType::NONE; return StatSwapType::NONE;
@@ -1199,7 +1199,7 @@ StatSwapType CardSpecial::compute_stat_swap_type(shared_ptr<const Card> card) co
for (size_t cond_index = 0; cond_index < 9; cond_index++) { for (size_t cond_index = 0; cond_index < 9; cond_index++) {
auto& cond = card->action_chain.conditions[cond_index]; auto& cond = card->action_chain.conditions[cond_index];
if (cond.type != ConditionType::NONE) { if (cond.type != ConditionType::NONE) {
auto cond_log = log.sub(string_printf("(%zu) ", cond_index)); auto cond_log = log.sub(phosg::string_printf("(%zu) ", cond_index));
string cond_str = cond.str(s); string cond_str = cond.str(s);
cond_log.debug("%s", cond_str.c_str()); cond_log.debug("%s", cond_str.c_str());
if (!this->card_ref_has_ability_trap(cond)) { if (!this->card_ref_has_ability_trap(cond)) {
@@ -1675,7 +1675,7 @@ int32_t CardSpecial::evaluate_effect_expr(
const char* expr, const char* expr,
DiceRoll& dice_roll) const { DiceRoll& dice_roll) const {
auto log = this->server()->log_stack("evaluate_effect_expr: "); auto log = this->server()->log_stack("evaluate_effect_expr: ");
if (log.min_level == LogLevel::DEBUG) { if (log.min_level == phosg::LogLevel::DEBUG) {
log.debug("ast, expr=\"%s\", dice_roll=(client_id=%02hhX, a2=%02hhX, value=%02hhX, value_used_in_expr=%s, a5=%04hX)", expr, dice_roll.client_id, dice_roll.unknown_a2, dice_roll.value, dice_roll.value_used_in_expr ? "true" : "false", dice_roll.unknown_a5); log.debug("ast, expr=\"%s\", dice_roll=(client_id=%02hhX, a2=%02hhX, value=%02hhX, value_used_in_expr=%s, a5=%04hX)", expr, dice_roll.client_id, dice_roll.unknown_a2, dice_roll.value, dice_roll.value_used_in_expr ? "true" : "false", dice_roll.unknown_a5);
ast.print(stderr); ast.print(stderr);
} }
@@ -1769,10 +1769,10 @@ bool CardSpecial::execute_effect(
uint32_t unknown_p7, uint32_t unknown_p7,
uint16_t attacker_card_ref) { uint16_t attacker_card_ref) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("execute_effect(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id())); auto log = s->log_stack(phosg::string_printf("execute_effect(@%04hX #%04hX): ", card->get_card_ref(), card->get_card_id()));
{ {
string cond_str = cond.str(s); string cond_str = cond.str(s);
log.debug("cond=%s, card=@%04hX, expr_value=%hd, unknown_p5=%hd, cond_type=%s, unknown_p7=%" PRIu32 ", attacker_card_ref=@%04hX", cond_str.c_str(), ref_for_card(card), expr_value, unknown_p5, name_for_enum(cond_type), unknown_p7, attacker_card_ref); log.debug("cond=%s, card=@%04hX, expr_value=%hd, unknown_p5=%hd, cond_type=%s, unknown_p7=%" PRIu32 ", attacker_card_ref=@%04hX", cond_str.c_str(), ref_for_card(card), expr_value, unknown_p5, phosg::name_for_enum(cond_type), unknown_p7, attacker_card_ref);
} }
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
@@ -2804,7 +2804,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
int16_t p_target_type, int16_t p_target_type,
bool apply_usability_filters) const { bool apply_usability_filters) const {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("get_targeted_cards_for_condition(@%04hX, %hhu, @%04hX): ", card_ref, def_effect_index, setter_card_ref)); auto log = s->log_stack(phosg::string_printf("get_targeted_cards_for_condition(@%04hX, %hhu, @%04hX): ", card_ref, def_effect_index, setter_card_ref));
log.debug("card_ref=@%04hX, def_effect_index=%02hhX, setter_card_ref=@%04hX, as, p_target_type=%hd, apply_usability_filters=%s", card_ref, def_effect_index, setter_card_ref, p_target_type, apply_usability_filters ? "true" : "false"); log.debug("card_ref=@%04hX, def_effect_index=%02hhX, setter_card_ref=@%04hX, as, p_target_type=%hd, apply_usability_filters=%s", card_ref, def_effect_index, setter_card_ref, p_target_type, apply_usability_filters ? "true" : "false");
vector<shared_ptr<const Card>> ret; vector<shared_ptr<const Card>> ret;
@@ -2836,7 +2836,7 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
AttackMedium attack_medium = card2 AttackMedium attack_medium = card2
? card2->action_chain.chain.attack_medium ? card2->action_chain.chain.attack_medium
: AttackMedium::UNKNOWN; : AttackMedium::UNKNOWN;
log.debug("attack_medium=%s", name_for_enum(attack_medium)); log.debug("attack_medium=%s", phosg::name_for_enum(attack_medium));
auto add_card_refs = [&](const vector<uint16_t>& result_card_refs) -> void { auto add_card_refs = [&](const vector<uint16_t>& result_card_refs) -> void {
for (uint16_t result_card_ref : result_card_refs) { for (uint16_t result_card_ref : result_card_refs) {
@@ -3944,13 +3944,13 @@ void CardSpecial::evaluate_and_apply_effects(
bool apply_defense_condition_to_all_cards, bool apply_defense_condition_to_all_cards,
uint16_t apply_defense_condition_to_card_ref) { uint16_t apply_defense_condition_to_card_ref) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("evaluate_and_apply_effects(%s, @%04hX, @%04hX): ", name_for_enum(when), set_card_ref, sc_card_ref)); auto log = s->log_stack(phosg::string_printf("evaluate_and_apply_effects(%s, @%04hX, @%04hX): ", phosg::name_for_enum(when), set_card_ref, sc_card_ref));
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
{ {
string as_str = as.str(s); string as_str = as.str(s);
log.debug("when=%s, set_card_ref=@%04hX, as=%s, sc_card_ref=@%04hX, apply_defense_condition_to_all_cards=%s, apply_defense_condition_to_card_ref=@%04hX", log.debug("when=%s, set_card_ref=@%04hX, as=%s, sc_card_ref=@%04hX, apply_defense_condition_to_all_cards=%s, apply_defense_condition_to_card_ref=@%04hX",
name_for_enum(when), set_card_ref, as_str.c_str(), sc_card_ref, apply_defense_condition_to_all_cards ? "true" : "false", apply_defense_condition_to_card_ref); phosg::name_for_enum(when), set_card_ref, as_str.c_str(), sc_card_ref, apply_defense_condition_to_all_cards ? "true" : "false", apply_defense_condition_to_card_ref);
} }
if (!is_nte) { if (!is_nte) {
@@ -4010,12 +4010,12 @@ void CardSpecial::evaluate_and_apply_effects(
log.debug("inputs: dice_roll=%02hhX, random_percent=%hhu, unknown_v1=%s", dice_roll.value, random_percent, unknown_v1 ? "true" : "false"); log.debug("inputs: dice_roll=%02hhX, random_percent=%hhu, unknown_v1=%s", dice_roll.value, random_percent, unknown_v1 ? "true" : "false");
for (size_t def_effect_index = 0; (def_effect_index < 3) && !unknown_v1 && (ce->def.effects[def_effect_index].type != ConditionType::NONE); def_effect_index++) { for (size_t def_effect_index = 0; (def_effect_index < 3) && !unknown_v1 && (ce->def.effects[def_effect_index].type != ConditionType::NONE); def_effect_index++) {
auto effect_log = log.sub(string_printf("(effect:%zu) ", def_effect_index)); auto effect_log = log.sub(phosg::string_printf("(effect:%zu) ", def_effect_index));
const auto& card_effect = ce->def.effects[def_effect_index]; const auto& card_effect = ce->def.effects[def_effect_index];
string card_effect_str = card_effect.str(); string card_effect_str = card_effect.str();
effect_log.debug("effect: %s", card_effect_str.c_str()); effect_log.debug("effect: %s", card_effect_str.c_str());
if (card_effect.when != when) { if (card_effect.when != when) {
effect_log.debug("does not apply (effect.when=%s, when=%s)", name_for_enum(card_effect.when), name_for_enum(when)); effect_log.debug("does not apply (effect.when=%s, when=%s)", phosg::name_for_enum(card_effect.when), phosg::name_for_enum(when));
continue; continue;
} }
@@ -4067,7 +4067,7 @@ void CardSpecial::evaluate_and_apply_effects(
} }
for (size_t z = 0; z < targeted_cards.size(); z++) { for (size_t z = 0; z < targeted_cards.size(); z++) {
auto target_log = effect_log.sub(string_printf("(target:@%04hX) ", targeted_cards[z]->get_card_ref())); auto target_log = effect_log.sub(phosg::string_printf("(target:@%04hX) ", targeted_cards[z]->get_card_ref()));
dice_roll.value_used_in_expr = false; dice_roll.value_used_in_expr = false;
string arg2_str = card_effect.arg2.decode(); string arg2_str = card_effect.arg2.decode();
target_log.debug("arg2_str = %s", arg2_str.c_str()); target_log.debug("arg2_str = %s", arg2_str.c_str());
@@ -4075,8 +4075,7 @@ void CardSpecial::evaluate_and_apply_effects(
this->evaluate_effect_arg2_condition( this->evaluate_effect_arg2_condition(
as, targeted_cards[z], arg2_str.c_str(), dice_roll, set_card_ref, sc_card_ref, random_percent, when)) { as, targeted_cards[z], arg2_str.c_str(), dice_roll, set_card_ref, sc_card_ref, random_percent, when)) {
target_log.debug("arg2 condition passed"); target_log.debug("arg2 condition passed");
auto env_stats = this->compute_attack_env_stats( auto env_stats = this->compute_attack_env_stats(as, targeted_cards[z], dice_roll, set_card_ref, sc_card_ref);
as, targeted_cards[z], dice_roll, set_card_ref, sc_card_ref);
string expr_str = card_effect.expr.decode(); string expr_str = card_effect.expr.decode();
int16_t value = this->evaluate_effect_expr(env_stats, expr_str.c_str(), dice_roll); int16_t value = this->evaluate_effect_expr(env_stats, expr_str.c_str(), dice_roll);
target_log.debug("expr = %s, value = %hd", expr_str.c_str(), value); target_log.debug("expr = %s, value = %hd", expr_str.c_str(), value);
@@ -4767,7 +4766,7 @@ void CardSpecial::dice_phase_before_for_card(shared_ptr<Card> card) {
template <EffectWhen When1, EffectWhen When2> template <EffectWhen When1, EffectWhen When2>
void CardSpecial::apply_effects_on_phase_change_t(shared_ptr<Card> unknown_p2, const ActionState* existing_as) { void CardSpecial::apply_effects_on_phase_change_t(shared_ptr<Card> unknown_p2, const ActionState* existing_as) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("apply_effects_on_phase_change_t<%s, %s>(@%04hX #%04hX): ", name_for_enum(When1), name_for_enum(When2), unknown_p2->get_card_ref(), unknown_p2->get_card_id())); auto log = s->log_stack(phosg::string_printf("apply_effects_on_phase_change_t<%s, %s>(@%04hX #%04hX): ", phosg::name_for_enum(When1), phosg::name_for_enum(When2), unknown_p2->get_card_ref(), unknown_p2->get_card_id()));
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
ActionState as; ActionState as;
@@ -4818,7 +4817,7 @@ void CardSpecial::unknown_8024945C(shared_ptr<Card> unknown_p2, const ActionStat
} }
void CardSpecial::unknown_8024966C(shared_ptr<Card> unknown_p2, const ActionState* existing_as) { void CardSpecial::unknown_8024966C(shared_ptr<Card> unknown_p2, const ActionState* existing_as) {
auto log = this->server()->log_stack(string_printf("unknown_8024966C(@%04hX #%04hX): ", unknown_p2->get_card_ref(), unknown_p2->get_card_id())); auto log = this->server()->log_stack(phosg::string_printf("unknown_8024966C(@%04hX #%04hX): ", unknown_p2->get_card_ref(), unknown_p2->get_card_id()));
ActionState as; ActionState as;
if (!existing_as) { if (!existing_as) {
@@ -4969,8 +4968,8 @@ template <
EffectWhen WhenTargetsAndActionCards> EffectWhen WhenTargetsAndActionCards>
void CardSpecial::apply_effects_before_or_after_attack(shared_ptr<Card> unknown_p2) { void CardSpecial::apply_effects_before_or_after_attack(shared_ptr<Card> unknown_p2) {
auto s = this->server(); auto s = this->server();
auto log = s->log_stack(string_printf("apply_effects_before_or_after_attack<%s, %s, %s, %s>(@%04hX #%04hX): ", auto log = s->log_stack(phosg::string_printf("apply_effects_before_or_after_attack<%s, %s, %s, %s>(@%04hX #%04hX): ",
name_for_enum(WhenAllCards), name_for_enum(WhenAttackerAndActionCards), name_for_enum(WhenAttackerOrHunterSCCard), name_for_enum(WhenTargetsAndActionCards), unknown_p2->get_card_ref(), unknown_p2->get_card_id())); phosg::name_for_enum(WhenAllCards), phosg::name_for_enum(WhenAttackerAndActionCards), phosg::name_for_enum(WhenAttackerOrHunterSCCard), phosg::name_for_enum(WhenTargetsAndActionCards), unknown_p2->get_card_ref(), unknown_p2->get_card_id()));
ActionState as = this->create_attack_state_from_card_action_chain(unknown_p2); ActionState as = this->create_attack_state_from_card_action_chain(unknown_p2);
File diff suppressed because it is too large Load Diff
+30 -29
View File
@@ -16,6 +16,7 @@
#include "../PlayerSubordinates.hh" #include "../PlayerSubordinates.hh"
#include "../Text.hh" #include "../Text.hh"
#include "../TextIndex.hh" #include "../TextIndex.hh"
#include "../Types.hh"
namespace Episode3 { namespace Episode3 {
@@ -506,7 +507,7 @@ struct CardDefinition {
void decode_code(); void decode_code();
std::string str() const; std::string str() const;
JSON json() const; phosg::JSON json() const;
} __packed_ws__(Stat, 4); } __packed_ws__(Stat, 4);
struct Effect { struct Effect {
@@ -543,7 +544,7 @@ struct CardDefinition {
bool is_empty() const; bool is_empty() const;
static std::string str_for_arg(const std::string& arg); static std::string str_for_arg(const std::string& arg);
std::string str(const char* separator = ", ", const TextSet* text_archive = nullptr) const; std::string str(const char* separator = ", ", const TextSet* text_archive = nullptr) const;
JSON json() const; phosg::JSON json() const;
} __packed_ws__(Effect, 0x20); } __packed_ws__(Effect, 0x20);
/* 0000 */ be_uint32_t card_id; /* 0000 */ be_uint32_t card_id;
@@ -810,7 +811,7 @@ struct CardDefinition {
void decode_range(); void decode_range();
std::string str(bool single_line = true, const TextSet* text_archive = nullptr) const; std::string str(bool single_line = true, const TextSet* text_archive = nullptr) const;
JSON json() const; phosg::JSON json() const;
} __packed_ws__(CardDefinition, 0x128); } __packed_ws__(CardDefinition, 0x128);
struct CardDefinitionsFooter { struct CardDefinitionsFooter {
@@ -1029,8 +1030,8 @@ struct Rules {
// likely be more work than it's worth. // likely be more work than it's worth.
Rules() = default; Rules() = default;
explicit Rules(const JSON& json); explicit Rules(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
bool operator==(const Rules& other) const = default; bool operator==(const Rules& other) const = default;
bool operator!=(const Rules& other) const = default; bool operator!=(const Rules& other) const = default;
void clear(); void clear();
@@ -1225,7 +1226,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
/* 48 */ /* 48 */
std::string str() const; std::string str() const;
JSON json() const; phosg::JSON json() const;
} __packed_ws__(CameraSpec, 0x48); } __packed_ws__(CameraSpec, 0x48);
// This array specifies the camera zone maps. A camera zone map is a subset of // This array specifies the camera zone maps. A camera zone map is a subset of
@@ -1283,7 +1284,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
/* 00 */ pstring<TextEncoding::MARKED, 0x18> deck_name; /* 00 */ pstring<TextEncoding::MARKED, 0x18> deck_name;
/* 18 */ parray<be_uint16_t, 0x20> card_ids; // Last one appears to always be FFFF /* 18 */ parray<be_uint16_t, 0x20> card_ids; // Last one appears to always be FFFF
/* 58 */ /* 58 */
JSON json(uint8_t language) const; phosg::JSON json(uint8_t language) const;
} __packed_ws__(NPCDeck, 0x58); } __packed_ws__(NPCDeck, 0x58);
/* 1FE8 */ parray<NPCDeck, 3> npc_decks; // Unused if name[0] == 0 /* 1FE8 */ parray<NPCDeck, 3> npc_decks; // Unused if name[0] == 0
@@ -1299,7 +1300,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
// TODO: Figure out exactly how these are used and document here. // TODO: Figure out exactly how these are used and document here.
/* 0018 */ parray<be_uint16_t, 0x7E> params; /* 0018 */ parray<be_uint16_t, 0x7E> params;
/* 0114 */ /* 0114 */
JSON json(uint8_t language) const; phosg::JSON json(uint8_t language) const;
} __packed_ws__(AIParams, 0x114); } __packed_ws__(AIParams, 0x114);
/* 20F0 */ parray<AIParams, 3> npc_ai_params; // Unused if name[0] == 0 /* 20F0 */ parray<AIParams, 3> npc_ai_params; // Unused if name[0] == 0
@@ -1352,7 +1353,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
// strings, excluding any that are empty or begin with the character '^'. // strings, excluding any that are empty or begin with the character '^'.
/* 0004 */ parray<pstring<TextEncoding::MARKED, 0x40>, 4> strings; /* 0004 */ parray<pstring<TextEncoding::MARKED, 0x40>, 4> strings;
/* 0104 */ /* 0104 */
JSON json(uint8_t language) const; phosg::JSON json(uint8_t language) const;
} __packed_ws__(DialogueSet, 0x104); } __packed_ws__(DialogueSet, 0x104);
// There are up to 0x10 of these per valid NPC, but only the first 13 of them // There are up to 0x10 of these per valid NPC, but only the first 13 of them
@@ -1435,7 +1436,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
bool operator==(const EntryState& other) const = default; bool operator==(const EntryState& other) const = default;
bool operator!=(const EntryState& other) const = default; bool operator!=(const EntryState& other) const = default;
JSON json() const; phosg::JSON json() const;
} __packed_ws__(EntryState, 2); } __packed_ws__(EntryState, 2);
/* 5A10 */ parray<EntryState, 4> entry_states; /* 5A10 */ parray<EntryState, 4> entry_states;
/* 5A18 */ /* 5A18 */
@@ -1451,7 +1452,7 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
void assert_semantically_equivalent(const MapDefinition& other) const; void assert_semantically_equivalent(const MapDefinition& other) const;
std::string str(const CardIndex* card_index, uint8_t language) const; std::string str(const CardIndex* card_index, uint8_t language) const;
JSON json(uint8_t language) const; phosg::JSON json(uint8_t language) const;
} __packed_ws__(MapDefinition, 0x5A18); } __packed_ws__(MapDefinition, 0x5A18);
struct MapDefinitionTrial { struct MapDefinitionTrial {
@@ -1534,7 +1535,7 @@ public:
std::shared_ptr<const CardEntry> definition_for_name_normalized(const std::string& name) const; std::shared_ptr<const CardEntry> definition_for_name_normalized(const std::string& name) const;
std::set<uint32_t> all_ids() const; std::set<uint32_t> all_ids() const;
uint64_t definitions_mtime() const; uint64_t definitions_mtime() const;
JSON definitions_json() const; phosg::JSON definitions_json() const;
private: private:
static std::string normalize_card_name(const std::string& name); static std::string normalize_card_name(const std::string& name);
@@ -1615,37 +1616,37 @@ private:
// TODO: Figure out how to declare these inside the Episode3 namespace. // TODO: Figure out how to declare these inside the Episode3 namespace.
template <> template <>
Episode3::HPType enum_for_name<Episode3::HPType>(const char* name); Episode3::HPType phosg::enum_for_name<Episode3::HPType>(const char* name);
template <> template <>
const char* name_for_enum<Episode3::HPType>(Episode3::HPType hp_type); const char* phosg::name_for_enum<Episode3::HPType>(Episode3::HPType hp_type);
template <> template <>
Episode3::DiceExchangeMode enum_for_name<Episode3::DiceExchangeMode>(const char* name); Episode3::DiceExchangeMode phosg::enum_for_name<Episode3::DiceExchangeMode>(const char* name);
template <> template <>
const char* name_for_enum<Episode3::DiceExchangeMode>(Episode3::DiceExchangeMode dice_exchange_mode); const char* phosg::name_for_enum<Episode3::DiceExchangeMode>(Episode3::DiceExchangeMode dice_exchange_mode);
template <> template <>
Episode3::AllowedCards enum_for_name<Episode3::AllowedCards>(const char* name); Episode3::AllowedCards phosg::enum_for_name<Episode3::AllowedCards>(const char* name);
template <> template <>
const char* name_for_enum<Episode3::AllowedCards>(Episode3::AllowedCards allowed_cards); const char* phosg::name_for_enum<Episode3::AllowedCards>(Episode3::AllowedCards allowed_cards);
template <> template <>
const char* name_for_enum<Episode3::BattlePhase>(Episode3::BattlePhase phase); const char* phosg::name_for_enum<Episode3::BattlePhase>(Episode3::BattlePhase phase);
template <> template <>
const char* name_for_enum<Episode3::SetupPhase>(Episode3::SetupPhase phase); const char* phosg::name_for_enum<Episode3::SetupPhase>(Episode3::SetupPhase phase);
template <> template <>
const char* name_for_enum<Episode3::RegistrationPhase>(Episode3::RegistrationPhase phase); const char* phosg::name_for_enum<Episode3::RegistrationPhase>(Episode3::RegistrationPhase phase);
template <> template <>
const char* name_for_enum<Episode3::ActionSubphase>(Episode3::ActionSubphase phase); const char* phosg::name_for_enum<Episode3::ActionSubphase>(Episode3::ActionSubphase phase);
template <> template <>
const char* name_for_enum<Episode3::AttackMedium>(Episode3::AttackMedium medium); const char* phosg::name_for_enum<Episode3::AttackMedium>(Episode3::AttackMedium medium);
template <> template <>
const char* name_for_enum<Episode3::CriterionCode>(Episode3::CriterionCode code); const char* phosg::name_for_enum<Episode3::CriterionCode>(Episode3::CriterionCode code);
template <> template <>
const char* name_for_enum<Episode3::CardType>(Episode3::CardType type); const char* phosg::name_for_enum<Episode3::CardType>(Episode3::CardType type);
template <> template <>
const char* name_for_enum<Episode3::CardClass>(Episode3::CardClass cc); const char* phosg::name_for_enum<Episode3::CardClass>(Episode3::CardClass cc);
template <> template <>
const char* name_for_enum<Episode3::ConditionType>(Episode3::ConditionType cond_type); const char* phosg::name_for_enum<Episode3::ConditionType>(Episode3::ConditionType cond_type);
template <> template <>
const char* name_for_enum<Episode3::EffectWhen>(Episode3::EffectWhen when); const char* phosg::name_for_enum<Episode3::EffectWhen>(Episode3::EffectWhen when);
template <> template <>
const char* name_for_enum<Episode3::Direction>(Episode3::Direction d); const char* phosg::name_for_enum<Episode3::Direction>(Episode3::Direction d);
+4 -4
View File
@@ -1780,7 +1780,7 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) {
auto card = s->card_for_set_card_ref(pa.attacker_card_ref); auto card = s->card_for_set_card_ref(pa.attacker_card_ref);
if (card) { if (card) {
card->loc.direction = pa.facing_direction; card->loc.direction = pa.facing_direction;
log.debug("set facing direction to %s", name_for_enum(card->loc.direction)); log.debug("set facing direction to %s", phosg::name_for_enum(card->loc.direction));
G_AddToSetCardlog_Ep3_6xB4x4A cmd; G_AddToSetCardlog_Ep3_6xB4x4A cmd;
cmd.card_refs.clear(0xFFFF); cmd.card_refs.clear(0xFFFF);
@@ -1789,7 +1789,7 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) {
cmd.entry_count = 0; cmd.entry_count = 0;
size_t z = 0; size_t z = 0;
do { do {
if (log.should_log(LogLevel::DEBUG)) { if (log.should_log(phosg::LogLevel::DEBUG)) {
string ref_str = s->debug_str_for_card_ref(pa.action_card_refs[z]); string ref_str = s->debug_str_for_card_ref(pa.action_card_refs[z]);
log.debug("on action card ref %s", ref_str.c_str()); log.debug("on action card ref %s", ref_str.c_str());
} }
@@ -1826,7 +1826,7 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) {
for (size_t z = 0; (z < 4 * 9) && (pa.target_card_refs[z] != 0xFFFF); z++) { for (size_t z = 0; (z < 4 * 9) && (pa.target_card_refs[z] != 0xFFFF); z++) {
auto target_card = s->card_for_set_card_ref(pa.target_card_refs[z]); auto target_card = s->card_for_set_card_ref(pa.target_card_refs[z]);
if (target_card) { if (target_card) {
if (log.should_log(LogLevel::DEBUG)) { if (log.should_log(phosg::LogLevel::DEBUG)) {
string ref_str = s->debug_str_for_card_ref(pa.target_card_refs[z]); string ref_str = s->debug_str_for_card_ref(pa.target_card_refs[z]);
log.debug("on target card ref %s", ref_str.c_str()); log.debug("on target card ref %s", ref_str.c_str());
} }
@@ -1856,7 +1856,7 @@ bool PlayerState::set_action_cards_for_action_state(const ActionState& pa) {
this->subtract_or_check_atk_or_def_points_for_action(pa, 1); this->subtract_or_check_atk_or_def_points_for_action(pa, 1);
} }
for (size_t z = 0; (z < pa.action_card_refs.size()) && (pa.action_card_refs[z] != 0xFFFF); z++) { for (size_t z = 0; (z < pa.action_card_refs.size()) && (pa.action_card_refs[z] != 0xFFFF); z++) {
if (log.should_log(LogLevel::DEBUG)) { if (log.should_log(phosg::LogLevel::DEBUG)) {
string ref_str = s->debug_str_for_card_ref(pa.action_card_refs[z]); string ref_str = s->debug_str_for_card_ref(pa.action_card_refs[z]);
log.debug("discarding %s from hand", ref_str.c_str()); log.debug("discarding %s from hand", ref_str.c_str());
} }
+15 -15
View File
@@ -64,11 +64,11 @@ void Condition::clear_FF() {
std::string Condition::str(shared_ptr<const Server> s) const { std::string Condition::str(shared_ptr<const Server> s) const {
auto card_ref_str = s->debug_str_for_card_ref(this->card_ref); auto card_ref_str = s->debug_str_for_card_ref(this->card_ref);
auto giver_ref_str = s->debug_str_for_card_ref(this->condition_giver_card_ref); auto giver_ref_str = s->debug_str_for_card_ref(this->condition_giver_card_ref);
return string_printf( return phosg::string_printf(
"Condition[type=%s, turns=%hhu, a_arg=%hhd, dice=%hhu, flags=%02hhX, " "Condition[type=%s, turns=%hhu, a_arg=%hhd, dice=%hhu, flags=%02hhX, "
"def_eff_index=%hhu, ref=%s, value=%hd, giver_ref=%s " "def_eff_index=%hhu, ref=%s, value=%hd, giver_ref=%s "
"percent=%hhu value8=%hd order=%hu a8=%hu]", "percent=%hhu value8=%hd order=%hu a8=%hu]",
name_for_enum(this->type), phosg::name_for_enum(this->type),
this->remaining_turns, this->remaining_turns,
this->a_arg_value, this->a_arg_value,
this->dice_roll_value, this->dice_roll_value,
@@ -103,7 +103,7 @@ void EffectResult::clear() {
std::string EffectResult::str(shared_ptr<const Server> s) const { std::string EffectResult::str(shared_ptr<const Server> s) const {
string attacker_ref_str = s->debug_str_for_card_ref(this->attacker_card_ref); string attacker_ref_str = s->debug_str_for_card_ref(this->attacker_card_ref);
string target_ref_str = s->debug_str_for_card_ref(this->target_card_ref); string target_ref_str = s->debug_str_for_card_ref(this->target_card_ref);
return string_printf( return phosg::string_printf(
"EffectResult[att_ref=%s, target_ref=%s, value=%hhd, " "EffectResult[att_ref=%s, target_ref=%s, value=%hhd, "
"cur_hp=%hhd, ap=%hhd, tp=%hhd, flags=%02hhX, op=%hhd, " "cur_hp=%hhd, ap=%hhd, tp=%hhd, flags=%02hhX, op=%hhd, "
"cond_index=%hhu, dice=%hhu]", "cond_index=%hhu, dice=%hhu]",
@@ -139,7 +139,7 @@ bool CardShortStatus::operator!=(const CardShortStatus& other) const {
std::string CardShortStatus::str(shared_ptr<const Server> s) const { std::string CardShortStatus::str(shared_ptr<const Server> s) const {
string loc_s = this->loc.str(); string loc_s = this->loc.str();
string ref_str = s->debug_str_for_card_ref(this->card_ref); string ref_str = s->debug_str_for_card_ref(this->card_ref);
return string_printf( return phosg::string_printf(
"CardShortStatus[ref=%s, cur_hp=%hd, flags=%08" PRIX32 ", loc=%s, " "CardShortStatus[ref=%s, cur_hp=%hd, flags=%08" PRIX32 ", loc=%s, "
"u1=%04hX, max_hp=%hhd, u2=%hhu]", "u1=%04hX, max_hp=%hhd, u2=%hhu]",
ref_str.c_str(), ref_str.c_str(),
@@ -193,13 +193,13 @@ std::string ActionState::str(shared_ptr<const Server> s) const {
string original_attacker_ref_s = s->debug_str_for_card_ref(this->original_attacker_card_ref); string original_attacker_ref_s = s->debug_str_for_card_ref(this->original_attacker_card_ref);
string target_refs_s = s->debug_str_for_card_refs(this->target_card_refs); string target_refs_s = s->debug_str_for_card_refs(this->target_card_refs);
string action_refs_s = s->debug_str_for_card_refs(this->action_card_refs); string action_refs_s = s->debug_str_for_card_refs(this->action_card_refs);
return string_printf( return phosg::string_printf(
"ActionState[client=%hu, u=%hhu, facing=%s, attacker_ref=%s, " "ActionState[client=%hu, u=%hhu, facing=%s, attacker_ref=%s, "
"def_ref=%s, target_refs=%s, action_refs=%s, " "def_ref=%s, target_refs=%s, action_refs=%s, "
"orig_attacker_ref=%s]", "orig_attacker_ref=%s]",
this->client_id.load(), this->client_id.load(),
this->unused, this->unused,
name_for_enum(this->facing_direction), phosg::name_for_enum(this->facing_direction),
attacker_ref_s.c_str(), attacker_ref_s.c_str(),
defense_ref_s.c_str(), defense_ref_s.c_str(),
target_refs_s.c_str(), target_refs_s.c_str(),
@@ -243,7 +243,7 @@ std::string ActionChain::str(shared_ptr<const Server> s) const {
string unknown_card_ref_a3_s = s->debug_str_for_card_ref(this->unknown_card_ref_a3); string unknown_card_ref_a3_s = s->debug_str_for_card_ref(this->unknown_card_ref_a3);
string attack_action_card_refs_s = s->debug_str_for_card_refs(this->attack_action_card_refs); string attack_action_card_refs_s = s->debug_str_for_card_refs(this->attack_action_card_refs);
string target_card_refs_s = s->debug_str_for_card_refs(this->target_card_refs); string target_card_refs_s = s->debug_str_for_card_refs(this->target_card_refs);
return string_printf( return phosg::string_printf(
"ActionChain[eff_ap=%hhd, eff_tp=%hhd, ap_bonus=%hhd, damage=%hhd, " "ActionChain[eff_ap=%hhd, eff_tp=%hhd, ap_bonus=%hhd, damage=%hhd, "
"acting_ref=%s, unknown_ref_a3=%s, attack_action_refs=%s, " "acting_ref=%s, unknown_ref_a3=%s, attack_action_refs=%s, "
"attack_action_ref_count=%hhu, medium=%s, target_ref_count=%hhu, " "attack_action_ref_count=%hhu, medium=%s, target_ref_count=%hhu, "
@@ -258,9 +258,9 @@ std::string ActionChain::str(shared_ptr<const Server> s) const {
unknown_card_ref_a3_s.c_str(), unknown_card_ref_a3_s.c_str(),
attack_action_card_refs_s.c_str(), attack_action_card_refs_s.c_str(),
this->attack_action_card_ref_count, this->attack_action_card_ref_count,
name_for_enum(this->attack_medium), phosg::name_for_enum(this->attack_medium),
this->target_card_ref_count, this->target_card_ref_count,
name_for_enum(this->action_subphase), phosg::name_for_enum(this->action_subphase),
this->strike_count, this->strike_count,
this->damage_multiplier, this->damage_multiplier,
this->attack_number, this->attack_number,
@@ -341,7 +341,7 @@ std::string ActionChainWithConds::str(shared_ptr<const Server> s) const {
if (ret.back() != '[') { if (ret.back() != '[') {
ret += ", "; ret += ", ";
} }
ret += string_printf("%zu:", z); ret += phosg::string_printf("%zu:", z);
ret += this->conditions[z].str(s); ret += this->conditions[z].str(s);
} }
} }
@@ -580,7 +580,7 @@ std::string ActionMetadata::str(shared_ptr<const Server> s) const {
string target_card_refs_s = s->debug_str_for_card_refs(this->target_card_refs); string target_card_refs_s = s->debug_str_for_card_refs(this->target_card_refs);
string defense_card_refs_s = s->debug_str_for_card_refs(this->defense_card_refs); string defense_card_refs_s = s->debug_str_for_card_refs(this->defense_card_refs);
string original_attacker_card_refs_s = s->debug_str_for_card_refs(this->original_attacker_card_refs); string original_attacker_card_refs_s = s->debug_str_for_card_refs(this->original_attacker_card_refs);
return string_printf( return phosg::string_printf(
"ActionMetadata[ref=%s, target_ref_count=%hhu, def_ref_count=%hhu, " "ActionMetadata[ref=%s, target_ref_count=%hhu, def_ref_count=%hhu, "
"subphase=%s, def_power=%hhd, def_bonus=%hhd, " "subphase=%s, def_power=%hhd, def_bonus=%hhd, "
"att_bonus=%hhd, flags=%08" PRIX32 ", target_refs=%s, " "att_bonus=%hhd, flags=%08" PRIX32 ", target_refs=%s, "
@@ -588,7 +588,7 @@ std::string ActionMetadata::str(shared_ptr<const Server> s) const {
card_ref_s.c_str(), card_ref_s.c_str(),
this->target_card_ref_count, this->target_card_ref_count,
this->defense_card_ref_count, this->defense_card_ref_count,
name_for_enum(this->action_subphase), phosg::name_for_enum(this->action_subphase),
this->defense_power, this->defense_power,
this->defense_bonus, this->defense_bonus,
this->attack_bonus, this->attack_bonus,
@@ -683,7 +683,7 @@ std::string HandAndEquipState::str(shared_ptr<const Server> s) const {
string set_card_refs_s = s->debug_str_for_card_refs(this->set_card_refs); string set_card_refs_s = s->debug_str_for_card_refs(this->set_card_refs);
string hand_card_refs2_s = s->debug_str_for_card_refs(this->hand_card_refs2); string hand_card_refs2_s = s->debug_str_for_card_refs(this->hand_card_refs2);
string set_card_refs2_s = s->debug_str_for_card_refs(this->set_card_refs2); string set_card_refs2_s = s->debug_str_for_card_refs(this->set_card_refs2);
return string_printf( return phosg::string_printf(
"HandAndEquipState[dice=[%hhu, %hhu], atk=%hhu, def=%hhu, atk2=%hhu, " "HandAndEquipState[dice=[%hhu, %hhu], atk=%hhu, def=%hhu, atk2=%hhu, "
"a1=%hhu, total_set_cost=%hhu, is_cpu=%hhu, assist_flags=%08" PRIX32 ", " "a1=%hhu, total_set_cost=%hhu, is_cpu=%hhu, assist_flags=%08" PRIX32 ", "
"hand_refs=%s, assist_ref=%s, set_refs=%s, sc_ref=%s, hand_refs2=%s, " "hand_refs=%s, assist_ref=%s, set_refs=%s, sc_ref=%s, hand_refs2=%s, "
@@ -858,7 +858,7 @@ static bool is_card_within_range(
const parray<uint8_t, 9 * 9>& range, const parray<uint8_t, 9 * 9>& range,
const Location& anchor_loc, const Location& anchor_loc,
const CardShortStatus& ss, const CardShortStatus& ss,
PrefixedLogger* log) { phosg::PrefixedLogger* log) {
if (ss.card_ref == 0xFFFF) { if (ss.card_ref == 0xFFFF) {
if (log) { if (log) {
log->debug("is_card_within_range: (false) ss.card_ref missing"); log->debug("is_card_within_range: (false) ss.card_ref missing");
@@ -899,7 +899,7 @@ vector<uint16_t> get_card_refs_within_range(
const parray<uint8_t, 9 * 9>& range, const parray<uint8_t, 9 * 9>& range,
const Location& loc, const Location& loc,
const parray<CardShortStatus, 0x10>& short_statuses, const parray<CardShortStatus, 0x10>& short_statuses,
PrefixedLogger* log) { phosg::PrefixedLogger* log) {
vector<uint16_t> ret; vector<uint16_t> ret;
if (is_card_within_range(range, loc, short_statuses[0], log)) { if (is_card_within_range(range, loc, short_statuses[0], log)) {
if (log) { if (log) {
+1 -1
View File
@@ -329,6 +329,6 @@ std::vector<uint16_t> get_card_refs_within_range(
const parray<uint8_t, 9 * 9>& range, const parray<uint8_t, 9 * 9>& range,
const Location& loc, const Location& loc,
const parray<CardShortStatus, 0x10>& short_statuses, const parray<CardShortStatus, 0x10>& short_statuses,
PrefixedLogger* log = nullptr); phosg::PrefixedLogger* log = nullptr);
} // namespace Episode3 } // namespace Episode3
+5 -5
View File
@@ -15,8 +15,8 @@ void compute_effective_range(
uint16_t card_id, uint16_t card_id,
const Location& loc, const Location& loc,
shared_ptr<const MapAndRulesState> map_and_rules, shared_ptr<const MapAndRulesState> map_and_rules,
PrefixedLogger* log) { phosg::PrefixedLogger* log) {
if (log && log->should_log(LogLevel::DEBUG)) { if (log && log->should_log(phosg::LogLevel::DEBUG)) {
string loc_str = loc.str(); string loc_str = loc.str();
log->debug("compute_effective_range: card_id=#%04hX, loc=%s", card_id, loc_str.c_str()); log->debug("compute_effective_range: card_id=#%04hX, loc=%s", card_id, loc_str.c_str());
log->debug("compute_effective_range: map_and_rules->map:"); log->debug("compute_effective_range: map_and_rules->map:");
@@ -941,7 +941,7 @@ bool RulerServer::check_usability_or_condition_apply(
AttackMedium attack_medium) const { AttackMedium attack_medium) const {
auto s = this->server(); auto s = this->server();
bool is_nte = s->options.is_nte(); bool is_nte = s->options.is_nte();
auto log = s->log_stack(string_printf("check_usability_or_condition_apply(%02hhX, #%04hX, %02hhX, #%04hX, #%04hX, %02hhX, %s, %s): ", client_id1, card_id1, client_id2, card_id2, card_id3, def_effect_index, is_item_usability_check ? "true" : "false", name_for_enum(attack_medium))); auto log = s->log_stack(phosg::string_printf("check_usability_or_condition_apply(%02hhX, #%04hX, %02hhX, #%04hX, #%04hX, %02hhX, %s, %s): ", client_id1, card_id1, client_id2, card_id2, card_id3, def_effect_index, is_item_usability_check ? "true" : "false", phosg::name_for_enum(attack_medium)));
if (static_cast<uint8_t>(attack_medium) & 0x80) { if (static_cast<uint8_t>(attack_medium) & 0x80) {
attack_medium = AttackMedium::UNKNOWN; attack_medium = AttackMedium::UNKNOWN;
@@ -969,7 +969,7 @@ bool RulerServer::check_usability_or_condition_apply(
} }
criterion_code = ce1->def.effects[def_effect_index].apply_criterion; criterion_code = ce1->def.effects[def_effect_index].apply_criterion;
} }
log.debug("criterion_code=%s", name_for_enum(criterion_code)); log.debug("criterion_code=%s", phosg::name_for_enum(criterion_code));
// For item usability checks, prevent criteria that depend on player // For item usability checks, prevent criteria that depend on player
// positioning/team setup // positioning/team setup
@@ -2059,7 +2059,7 @@ shared_ptr<const CardIndex::CardEntry> RulerServer::definition_for_card_id(uint3
uint32_t RulerServer::get_card_id_with_effective_range( uint32_t RulerServer::get_card_id_with_effective_range(
uint16_t card_ref, uint16_t card_id_override, TargetMode* out_target_mode) const { uint16_t card_ref, uint16_t card_id_override, TargetMode* out_target_mode) const {
auto log = this->server()->log_stack(string_printf("get_card_id_with_effective_range(@%04hX, #%04hX): ", card_ref, card_id_override)); auto log = this->server()->log_stack(phosg::string_printf("get_card_id_with_effective_range(@%04hX, #%04hX): ", card_ref, card_id_override));
uint16_t card_id = (card_id_override == 0xFFFF) uint16_t card_id = (card_id_override == 0xFFFF)
? this->card_id_for_card_ref(card_ref) ? this->card_id_for_card_ref(card_ref)
+1 -1
View File
@@ -19,7 +19,7 @@ void compute_effective_range(
uint16_t card_id, uint16_t card_id,
const Location& loc, const Location& loc,
std::shared_ptr<const MapAndRulesState> map_and_rules, std::shared_ptr<const MapAndRulesState> map_and_rules,
PrefixedLogger* log = nullptr); phosg::PrefixedLogger* log = nullptr);
bool card_linkage_is_valid( bool card_linkage_is_valid(
std::shared_ptr<const CardIndex::CardEntry> right_def, std::shared_ptr<const CardIndex::CardEntry> right_def,
+24 -24
View File
@@ -82,7 +82,7 @@ Server::Server(shared_ptr<Lobby> lobby, Options&& options)
Server::~Server() noexcept(false) { Server::~Server() noexcept(false) {
if (this->logger_stack.size() != 1) { if (this->logger_stack.size() != 1) {
throw logic_error(string_printf("incorrect logger stack size: expected 1, received %zu", this->logger_stack.size())); throw logic_error(phosg::string_printf("incorrect logger stack size: expected 1, received %zu", this->logger_stack.size()));
} }
delete this->logger_stack.back(); delete this->logger_stack.back();
} }
@@ -125,7 +125,7 @@ Server::StackLogger::StackLogger(const Server* s, const std::string& prefix)
s->logger_stack.push_back(this); s->logger_stack.push_back(this);
} }
Server::StackLogger::StackLogger(const Server* s, const std::string& prefix, LogLevel min_level) Server::StackLogger::StackLogger(const Server* s, const std::string& prefix, phosg::LogLevel min_level)
: PrefixedLogger(prefix, min_level), : PrefixedLogger(prefix, min_level),
server(s) { server(s) {
s->logger_stack.push_back(this); s->logger_stack.push_back(this);
@@ -172,9 +172,9 @@ std::string Server::debug_str_for_card_ref(uint16_t card_ref) const {
auto ce = this->definition_for_card_ref(card_ref); auto ce = this->definition_for_card_ref(card_ref);
if (ce) { if (ce) {
string name = ce->def.en_name.decode(); string name = ce->def.en_name.decode();
return string_printf("@%04hX (#%04" PRIX32 " %s)", card_ref, ce->def.card_id.load(), name.c_str()); return phosg::string_printf("@%04hX (#%04" PRIX32 " %s)", card_ref, ce->def.card_id.load(), name.c_str());
} else { } else {
return string_printf("@%04hX (missing)", card_ref); return phosg::string_printf("@%04hX (missing)", card_ref);
} }
} }
@@ -185,9 +185,9 @@ std::string Server::debug_str_for_card_id(uint16_t card_id) const {
auto ce = this->definition_for_card_id(card_id); auto ce = this->definition_for_card_id(card_id);
if (ce) { if (ce) {
string name = ce->def.en_name.decode(); string name = ce->def.en_name.decode();
return string_printf("#%04hX (%s)", card_id, name.c_str()); return phosg::string_printf("#%04hX (%s)", card_id, name.c_str());
} else { } else {
return string_printf("#%04hX (missing)", card_id); return phosg::string_printf("#%04hX (missing)", card_id);
} }
} }
@@ -240,7 +240,7 @@ void Server::send(const void* data, size_t size, uint8_t command, bool enable_ma
!(this->options.behavior_flags & BehaviorFlag::DISABLE_MASKING) && !(this->options.behavior_flags & BehaviorFlag::DISABLE_MASKING) &&
(size >= 8)) { (size >= 8)) {
masked_data.assign(reinterpret_cast<const char*>(data), size); masked_data.assign(reinterpret_cast<const char*>(data), size);
uint8_t mask_key = (random_object<uint32_t>() % 0xFF) + 1; uint8_t mask_key = (phosg::random_object<uint32_t>() % 0xFF) + 1;
set_mask_for_ep3_game_command(masked_data.data(), masked_data.size(), mask_key); set_mask_for_ep3_game_command(masked_data.data(), masked_data.size(), mask_key);
data = masked_data.data(); data = masked_data.data();
size = masked_data.size(); size = masked_data.size();
@@ -260,7 +260,7 @@ void Server::send(const void* data, size_t size, uint8_t command, bool enable_ma
} else if ((this->options.behavior_flags & BehaviorFlag::LOG_COMMANDS_IF_LOBBY_MISSING) && } else if ((this->options.behavior_flags & BehaviorFlag::LOG_COMMANDS_IF_LOBBY_MISSING) &&
this->log().info("Generated command")) { this->log().info("Generated command")) {
print_data(stderr, data, size, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::DISABLE_COLOR | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, data, size, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::DISABLE_COLOR | phosg::PrintDataFlags::OFFSET_16_BITS);
} }
} }
@@ -272,9 +272,9 @@ void Server::send_6xB4x46() const {
// debugging easier. // debugging easier.
G_ServerVersionStrings_Ep3_6xB4x46 cmd; G_ServerVersionStrings_Ep3_6xB4x46 cmd;
cmd.version_signature.encode(this->options.is_nte() ? VERSION_SIGNATURE_NTE : VERSION_SIGNATURE, 1); cmd.version_signature.encode(this->options.is_nte() ? VERSION_SIGNATURE_NTE : VERSION_SIGNATURE, 1);
cmd.date_str1.encode(format_time(this->options.card_index->definitions_mtime() * 1000000), 1); cmd.date_str1.encode(phosg::format_time(this->options.card_index->definitions_mtime() * 1000000), 1);
string build_date = format_time(BUILD_TIMESTAMP); string build_date = phosg::format_time(BUILD_TIMESTAMP);
cmd.date_str2.encode(string_printf("newserv %s compiled at %s", GIT_REVISION_HASH, build_date.c_str()), 1); cmd.date_str2.encode(phosg::string_printf("newserv %s compiled at %s", GIT_REVISION_HASH, build_date.c_str()), 1);
this->send(cmd); this->send(cmd);
} }
@@ -283,7 +283,7 @@ string Server::prepare_6xB6x41_map_definition(shared_ptr<const MapIndex::Map> ma
const auto& compressed = vm->compressed(is_nte); const auto& compressed = vm->compressed(is_nte);
StringWriter w; phosg::StringWriter w;
uint32_t subcommand_size = (compressed.size() + sizeof(G_MapData_Ep3_6xB6x41) + 3) & (~3); uint32_t subcommand_size = (compressed.size() + sizeof(G_MapData_Ep3_6xB6x41) + 3) & (~3);
w.put<G_MapData_Ep3_6xB6x41>({{{{0xB6, 0, 0}, subcommand_size}, 0x41, {}}, vm->map->map_number.load(), compressed.size(), 0}); w.put<G_MapData_Ep3_6xB6x41>({{{{0xB6, 0, 0}, subcommand_size}, 0x41, {}}, vm->map->map_number.load(), compressed.size(), 0});
w.write(compressed); w.write(compressed);
@@ -347,7 +347,7 @@ __attribute__((format(printf, 2, 3))) void Server::send_debug_message_printf(con
if (l && (this->options.behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) { if (l && (this->options.behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
std::string buf = string_vprintf(fmt, va); std::string buf = phosg::string_vprintf(fmt, va);
va_end(va); va_end(va);
send_text_message(l, buf); send_text_message(l, buf);
} }
@@ -358,7 +358,7 @@ __attribute__((format(printf, 2, 3))) void Server::send_info_message_printf(cons
if (l) { if (l) {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
std::string buf = string_vprintf(fmt, va); std::string buf = phosg::string_vprintf(fmt, va);
va_end(va); va_end(va);
send_text_message(l, buf); send_text_message(l, buf);
} }
@@ -862,7 +862,7 @@ void Server::draw_phase_after() {
// facilities used are different. // facilities used are different.
uint64_t limit_5mins = this->map_and_rules->rules.overall_time_limit; uint64_t limit_5mins = this->map_and_rules->rules.overall_time_limit;
uint64_t end_usecs = this->battle_start_usecs + (limit_5mins * 300 * 1000 * 1000); uint64_t end_usecs = this->battle_start_usecs + (limit_5mins * 300 * 1000 * 1000);
if (now() >= end_usecs) { if (phosg::now() >= end_usecs) {
this->overall_time_expired = true; this->overall_time_expired = true;
} }
} }
@@ -972,7 +972,7 @@ void Server::end_action_phase() {
bool Server::enqueue_attack_or_defense(uint8_t client_id, ActionState* pa) { bool Server::enqueue_attack_or_defense(uint8_t client_id, ActionState* pa) {
auto log = this->log_stack("enqueue_attack_or_defense: "); auto log = this->log_stack("enqueue_attack_or_defense: ");
if (log.should_log(LogLevel::DEBUG)) { if (log.should_log(phosg::LogLevel::DEBUG)) {
string s = pa->str(this->shared_from_this()); string s = pa->str(this->shared_from_this());
log.debug("input: %s", s.c_str()); log.debug("input: %s", s.c_str());
} }
@@ -1022,7 +1022,7 @@ bool Server::enqueue_attack_or_defense(uint8_t client_id, ActionState* pa) {
size_t attack_index = this->num_pending_attacks++; size_t attack_index = this->num_pending_attacks++;
this->pending_attacks[attack_index] = *pa; this->pending_attacks[attack_index] = *pa;
if (log.should_log(LogLevel::DEBUG)) { if (log.should_log(phosg::LogLevel::DEBUG)) {
string pa_str = this->pending_attacks[attack_index].str(this->shared_from_this()); string pa_str = this->pending_attacks[attack_index].str(this->shared_from_this());
log.debug("set pending attack %zu: %s", attack_index, pa_str.c_str()); log.debug("set pending attack %zu: %s", attack_index, pa_str.c_str());
} }
@@ -1711,7 +1711,7 @@ void Server::setup_and_start_battle() {
cmd.start_battle = 1; cmd.start_battle = 1;
this->send(cmd); this->send(cmd);
} }
this->battle_start_usecs = now(); this->battle_start_usecs = phosg::now();
this->send_6xB4x46(); this->send_6xB4x46();
@@ -1831,8 +1831,8 @@ void Server::on_server_data_input(shared_ptr<Client> sender_c, const string& dat
auto header = check_size_t<G_CardBattleCommandHeader>(data, 0xFFFF); auto header = check_size_t<G_CardBattleCommandHeader>(data, 0xFFFF);
size_t expected_size = header.size * 4; size_t expected_size = header.size * 4;
if (expected_size < data.size()) { if (expected_size < data.size()) {
print_data(stderr, data); phosg::print_data(stderr, data);
throw runtime_error(string_printf("command is incomplete: expected %zX bytes, received %zX bytes", expected_size, data.size())); throw runtime_error(phosg::string_printf("command is incomplete: expected %zX bytes, received %zX bytes", expected_size, data.size()));
} }
if (header.subcommand != 0xB3) { if (header.subcommand != 0xB3) {
throw runtime_error("server data command is not 6xB3"); throw runtime_error("server data command is not 6xB3");
@@ -2259,7 +2259,7 @@ void Server::handle_CAx14_update_deck_during_setup(shared_ptr<Client>, const str
} }
} }
if (verify_error) { if (verify_error) {
throw runtime_error(string_printf("invalid deck: -0x%" PRIX32, verify_error)); throw runtime_error(phosg::string_printf("invalid deck: -0x%" PRIX32, verify_error));
} }
if (!this->options.is_nte() && !(this->options.behavior_flags & BehaviorFlag::SKIP_D1_D2_REPLACE)) { if (!this->options.is_nte() && !(this->options.behavior_flags & BehaviorFlag::SKIP_D1_D2_REPLACE)) {
this->ruler_server->replace_D1_D2_rank_cards_with_Attack(entry.card_ids); this->ruler_server->replace_D1_D2_rank_cards_with_Attack(entry.card_ids);
@@ -2579,7 +2579,7 @@ void Server::handle_CAx40_map_list_request(shared_ptr<Client> sender_c, const st
uint8_t language = sender_c ? sender_c->language() : 1; uint8_t language = sender_c ? sender_c->language() : 1;
const auto& list_data = this->options.map_index->get_compressed_list(num_players, language); const auto& list_data = this->options.map_index->get_compressed_list(num_players, language);
StringWriter w; phosg::StringWriter w;
uint32_t subcommand_size = (list_data.size() + sizeof(G_MapList_Ep3_6xB6x40) + 3) & (~3); uint32_t subcommand_size = (list_data.size() + sizeof(G_MapList_Ep3_6xB6x40) + 3) & (~3);
w.put<G_MapList_Ep3_6xB6x40>(G_MapList_Ep3_6xB6x40{{{{0xB6, 0, 0}, subcommand_size}, 0x40, {}}, list_data.size(), 0}); w.put<G_MapList_Ep3_6xB6x40>(G_MapList_Ep3_6xB6x40{{{{0xB6, 0, 0}, subcommand_size}, 0x40, {}}, list_data.size(), 0});
w.write(list_data); w.write(list_data);
@@ -2828,7 +2828,7 @@ void Server::unknown_8023EEF4() {
auto card = this->attack_cards[this->unknown_a14]; auto card = this->attack_cards[this->unknown_a14];
if (this->get_current_team_turn() == card->get_team_id()) { if (this->get_current_team_turn() == card->get_team_id()) {
ActionState as = this->pending_attacks_with_cards[this->unknown_a14]; ActionState as = this->pending_attacks_with_cards[this->unknown_a14];
if (log.should_log(LogLevel::DEBUG)) { if (log.should_log(phosg::LogLevel::DEBUG)) {
log.debug("card @%04hX #%04hX can attack", card->get_card_ref(), card->get_card_id()); log.debug("card @%04hX #%04hX can attack", card->get_card_ref(), card->get_card_id());
string as_str = as.str(this->shared_from_this()); string as_str = as.str(this->shared_from_this());
log.debug("as: %s", as_str.c_str()); log.debug("as: %s", as_str.c_str());
@@ -2838,7 +2838,7 @@ void Server::unknown_8023EEF4() {
} else { } else {
this->replace_targets_due_to_destruction_or_conditions(&as); this->replace_targets_due_to_destruction_or_conditions(&as);
} }
if (log.should_log(LogLevel::DEBUG)) { if (log.should_log(phosg::LogLevel::DEBUG)) {
string as_str = as.str(this->shared_from_this()); string as_str = as.str(this->shared_from_this());
log.debug("as after target replacement: %s", as_str.c_str()); log.debug("as after target replacement: %s", as_str.c_str());
} }
+4 -4
View File
@@ -72,7 +72,7 @@ public:
std::shared_ptr<const CardIndex> card_index; std::shared_ptr<const CardIndex> card_index;
std::shared_ptr<const MapIndex> map_index; std::shared_ptr<const MapIndex> map_index;
uint32_t behavior_flags; uint32_t behavior_flags;
std::shared_ptr<StringReader> opt_rand_stream; std::shared_ptr<phosg::StringReader> opt_rand_stream;
std::shared_ptr<PSOLFGEncryption> opt_rand_crypt; std::shared_ptr<PSOLFGEncryption> opt_rand_crypt;
std::shared_ptr<const Tournament> tournament; std::shared_ptr<const Tournament> tournament;
std::array<std::vector<uint16_t>, 5> trap_card_ids; std::array<std::vector<uint16_t>, 5> trap_card_ids;
@@ -85,10 +85,10 @@ public:
~Server() noexcept(false); ~Server() noexcept(false);
void init(); void init();
class StackLogger : public PrefixedLogger { class StackLogger : public phosg::PrefixedLogger {
public: public:
StackLogger(const Server* s, const std::string& prefix); StackLogger(const Server* s, const std::string& prefix);
StackLogger(const Server* s, const std::string& prefix, LogLevel min_level); StackLogger(const Server* s, const std::string& prefix, phosg::LogLevel min_level);
StackLogger(const StackLogger&) = delete; StackLogger(const StackLogger&) = delete;
StackLogger(StackLogger&&); StackLogger(StackLogger&&);
StackLogger& operator=(const StackLogger&) = delete; StackLogger& operator=(const StackLogger&) = delete;
@@ -109,7 +109,7 @@ public:
for (size_t z = 0; z < count; z++) { for (size_t z = 0; z < count; z++) {
if (refs[z] != 0xFFFF) { if (refs[z] != 0xFFFF) {
std::string ref_str = this->debug_str_for_card_ref(refs[z]); std::string ref_str = this->debug_str_for_card_ref(refs[z]);
ret += string_printf("%zu:%s ", z, ref_str.c_str()); ret += phosg::string_printf("%zu:%s ", z, ref_str.c_str());
} }
} }
if (ret.size() > 1) { if (ret.size() > 1) {
+26 -26
View File
@@ -49,16 +49,16 @@ string Tournament::Team::str() const {
num_com_players += player.is_com(); num_com_players += player.is_com();
} }
string ret = string_printf("[Team/%zu %s %zuH/%zuC/%zuP name=%s pass=%s rounds=%zu", string ret = phosg::string_printf("[Team/%zu %s %zuH/%zuC/%zuP name=%s pass=%s rounds=%zu",
this->index, this->is_active ? "active" : "inactive", this->index, this->is_active ? "active" : "inactive",
num_human_players, num_com_players, this->max_players, this->name.c_str(), num_human_players, num_com_players, this->max_players, this->name.c_str(),
this->password.c_str(), this->num_rounds_cleared); this->password.c_str(), this->num_rounds_cleared);
for (const auto& player : this->players) { for (const auto& player : this->players) {
if (player.is_human()) { if (player.is_human()) {
if (player.player_name.empty()) { if (player.player_name.empty()) {
ret += string_printf(" %08" PRIX32, player.account_id); ret += phosg::string_printf(" %08" PRIX32, player.account_id);
} else { } else {
ret += string_printf(" %08" PRIX32 " (%s)", player.account_id, player.player_name.c_str()); ret += phosg::string_printf(" %08" PRIX32 " (%s)", player.account_id, player.player_name.c_str());
} }
} }
} }
@@ -206,7 +206,7 @@ Tournament::Match::Match(
string Tournament::Match::str() const { string Tournament::Match::str() const {
string winner_str = this->winner_team ? this->winner_team->str() : "(none)"; string winner_str = this->winner_team ? this->winner_team->str() : "(none)";
return string_printf("[Match round=%zu winner=%s]", this->round_num, winner_str.c_str()); return phosg::string_printf("[Match round=%zu winner=%s]", this->round_num, winner_str.c_str());
} }
bool Tournament::Match::resolve_if_skippable() { bool Tournament::Match::resolve_if_skippable() {
@@ -230,7 +230,7 @@ bool Tournament::Match::resolve_if_skippable() {
// entirely and just make one team advance arbitrarily (note that this also // entirely and just make one team advance arbitrarily (note that this also
// handles the case where both preceding winner teams are empty) // handles the case where both preceding winner teams are empty)
if (!winner_a->has_any_human_players() && !winner_b->has_any_human_players()) { if (!winner_a->has_any_human_players() && !winner_b->has_any_human_players()) {
this->set_winner_team((random_object<uint8_t>() & 1) ? winner_b : winner_a); this->set_winner_team((phosg::random_object<uint8_t>() & 1) ? winner_b : winner_a);
return true; return true;
} }
@@ -318,7 +318,7 @@ Tournament::Tournament(
const Rules& rules, const Rules& rules,
size_t num_teams, size_t num_teams,
uint8_t flags) uint8_t flags)
: log(string_printf("[Tournament:%s] ", name.c_str())), : log(phosg::string_printf("[Tournament:%s] ", name.c_str())),
map_index(map_index), map_index(map_index),
com_deck_index(com_deck_index), com_deck_index(com_deck_index),
name(name), name(name),
@@ -342,8 +342,8 @@ Tournament::Tournament(
Tournament::Tournament( Tournament::Tournament(
shared_ptr<const MapIndex> map_index, shared_ptr<const MapIndex> map_index,
shared_ptr<const COMDeckIndex> com_deck_index, shared_ptr<const COMDeckIndex> com_deck_index,
const JSON& json) const phosg::JSON& json)
: log(string_printf("[Tournament:%s] ", json.get_string("name").c_str())), : log(phosg::string_printf("[Tournament:%s] ", json.get_string("name").c_str())),
map_index(map_index), map_index(map_index),
com_deck_index(com_deck_index), com_deck_index(com_deck_index),
source_json(json), source_json(json),
@@ -504,14 +504,14 @@ void Tournament::create_bracket_matches() {
this->final_match = current_round_matches.at(0); this->final_match = current_round_matches.at(0);
} }
JSON Tournament::json() const { phosg::JSON Tournament::json() const {
auto teams_list = JSON::list(); auto teams_list = phosg::JSON::list();
for (auto team : this->teams) { for (auto team : this->teams) {
auto players_list = JSON::list(); auto players_list = phosg::JSON::list();
for (const auto& player : team->players) { for (const auto& player : team->players) {
if (player.is_human()) { if (player.is_human()) {
if (!player.player_name.empty()) { if (!player.player_name.empty()) {
players_list.emplace_back(JSON::list({player.account_id, player.player_name})); players_list.emplace_back(phosg::JSON::list({player.account_id, player.player_name}));
} else { } else {
players_list.emplace_back(player.account_id); players_list.emplace_back(player.account_id);
} }
@@ -519,7 +519,7 @@ JSON Tournament::json() const {
players_list.emplace_back(player.com_deck->deck_name); players_list.emplace_back(player.com_deck->deck_name);
} }
} }
teams_list.emplace_back(JSON::dict({ teams_list.emplace_back(phosg::JSON::dict({
{"max_players", team->max_players}, {"max_players", team->max_players},
{"player_specs", std::move(players_list)}, {"player_specs", std::move(players_list)},
{"name", team->name}, {"name", team->name},
@@ -527,7 +527,7 @@ JSON Tournament::json() const {
{"num_rounds_cleared", team->num_rounds_cleared}, {"num_rounds_cleared", team->num_rounds_cleared},
})); }));
} }
return JSON::dict({ return phosg::JSON::dict({
{"name", this->name}, {"name", this->name},
{"map_number", this->map->map_number}, {"map_number", this->map->map_number},
{"rules", this->rules.json()}, {"rules", this->rules.json()},
@@ -649,7 +649,7 @@ void Tournament::start() {
if (this->flags & Flag::SHUFFLE_ENTRIES) { if (this->flags & Flag::SHUFFLE_ENTRIES) {
// Shuffle all the tournament entries // Shuffle all the tournament entries
for (size_t z = this->teams.size(); z > 0; z--) { for (size_t z = this->teams.size(); z > 0; z--) {
size_t index = random_object<uint32_t>() % z; size_t index = phosg::random_object<uint32_t>() % z;
if (index != z - 1) { if (index != z - 1) {
this->teams[z - 1].swap(this->teams[index]); this->teams[z - 1].swap(this->teams[index]);
} }
@@ -665,7 +665,7 @@ void Tournament::start() {
auto m = this->zero_round_matches[z]; auto m = this->zero_round_matches[z];
auto t = m->winner_team; auto t = m->winner_team;
if (t->name.empty()) { if (t->name.empty()) {
t->name = has_com_teams ? string_printf("COM:%zu", z) : "(no entrant)"; t->name = has_com_teams ? phosg::string_printf("COM:%zu", z) : "(no entrant)";
} }
for (const auto& player : t->players) { for (const auto& player : t->players) {
if (player.is_com()) { if (player.is_com()) {
@@ -791,16 +791,16 @@ TournamentIndex::TournamentIndex(
return; return;
} }
JSON json; phosg::JSON json;
try { try {
json = JSON::parse(load_file(this->state_filename)); json = phosg::JSON::parse(phosg::load_file(this->state_filename));
} catch (const cannot_open_file&) { } catch (const phosg::cannot_open_file&) {
json = JSON::list(); json = phosg::JSON::list();
} }
if (json.is_list()) { if (json.is_list()) {
if (json.size() > 0x20) { if (json.size() > 0x20) {
throw runtime_error("tournament JSON list length is incorrect"); throw runtime_error("tournament phosg::JSON list length is incorrect");
} }
for (size_t z = 0; z < min<size_t>(json.size(), 0x20); z++) { for (size_t z = 0; z < min<size_t>(json.size(), 0x20); z++) {
if (!json.at(z).is_null()) { if (!json.at(z).is_null()) {
@@ -815,13 +815,13 @@ TournamentIndex::TournamentIndex(
} }
} else if (json.is_dict()) { } else if (json.is_dict()) {
if (json.size() > 0x20) { if (json.size() > 0x20) {
throw runtime_error("tournament JSON dict length is incorrect"); throw runtime_error("tournament phosg::JSON dict length is incorrect");
} }
for (const auto& it : json.as_dict()) { for (const auto& it : json.as_dict()) {
auto tourn = make_shared<Tournament>(this->map_index, this->com_deck_index, *it.second); auto tourn = make_shared<Tournament>(this->map_index, this->com_deck_index, *it.second);
tourn->init(); tourn->init();
if (!this->name_to_tournament.emplace(tourn->get_name(), tourn).second) { if (!this->name_to_tournament.emplace(tourn->get_name(), tourn).second) {
// This is logic_error instead of runtime_error because JSON dicts are // This is logic_error instead of runtime_error because phosg::JSON dicts are
// supposed to already have unique keys // supposed to already have unique keys
throw logic_error("multiple tournaments have the same name: " + tourn->get_name()); throw logic_error("multiple tournaments have the same name: " + tourn->get_name());
} }
@@ -829,7 +829,7 @@ TournamentIndex::TournamentIndex(
this->menu_item_id_to_tournament.emplace_back(tourn); this->menu_item_id_to_tournament.emplace_back(tourn);
} }
} else { } else {
throw runtime_error("tournament state root JSON is not a list or dict"); throw runtime_error("tournament state root phosg::JSON is not a list or dict");
} }
} }
@@ -838,11 +838,11 @@ void TournamentIndex::save() const {
return; return;
} }
auto json = JSON::dict(); auto json = phosg::JSON::dict();
for (const auto& it : this->name_to_tournament) { for (const auto& it : this->name_to_tournament) {
json.emplace(it.second->get_name(), it.second->json()); json.emplace(it.second->get_name(), it.second->json());
} }
save_file(this->state_filename, json.serialize(JSON::SerializeOption::FORMAT | JSON::SerializeOption::HEX_INTEGERS | JSON::SerializeOption::ESCAPE_CONTROLS_ONLY)); phosg::save_file(this->state_filename, json.serialize(phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::HEX_INTEGERS | phosg::JSON::SerializeOption::ESCAPE_CONTROLS_ONLY));
} }
shared_ptr<Tournament> TournamentIndex::create_tournament( shared_ptr<Tournament> TournamentIndex::create_tournament(
+5 -5
View File
@@ -49,7 +49,7 @@ public:
bool is_com() const; bool is_com() const;
bool is_human() const; bool is_human() const;
JSON json() const; phosg::JSON json() const;
}; };
struct Team : public std::enable_shared_from_this<Team> { struct Team : public std::enable_shared_from_this<Team> {
@@ -115,11 +115,11 @@ public:
Tournament( Tournament(
std::shared_ptr<const MapIndex> map_index, std::shared_ptr<const MapIndex> map_index,
std::shared_ptr<const COMDeckIndex> com_deck_index, std::shared_ptr<const COMDeckIndex> com_deck_index,
const JSON& json); const phosg::JSON& json);
~Tournament() = default; ~Tournament() = default;
void init(); void init();
JSON json() const; phosg::JSON json() const;
inline const std::string& get_name() const { inline const std::string& get_name() const {
return this->name; return this->name;
@@ -165,11 +165,11 @@ public:
private: private:
void create_bracket_matches(); void create_bracket_matches();
PrefixedLogger log; phosg::PrefixedLogger log;
std::shared_ptr<const MapIndex> map_index; std::shared_ptr<const MapIndex> map_index;
std::shared_ptr<const COMDeckIndex> com_deck_index; std::shared_ptr<const COMDeckIndex> com_deck_index;
JSON source_json; phosg::JSON source_json;
std::string name; std::string name;
std::shared_ptr<const MapIndex::Map> map; std::shared_ptr<const MapIndex::Map> map;
Rules rules; Rules rules;
+3 -3
View File
@@ -20,7 +20,7 @@ FileContentsCache::File::File(
shared_ptr<const FileContentsCache::File> FileContentsCache::replace( shared_ptr<const FileContentsCache::File> FileContentsCache::replace(
const string& name, string&& data, uint64_t t) { const string& name, string&& data, uint64_t t) {
if (t == 0) { if (t == 0) {
t = now(); t = phosg::now();
} }
auto new_file = make_shared<File>(name, std::move(data), t); auto new_file = make_shared<File>(name, std::move(data), t);
auto emplace_ret = this->name_to_file.emplace(name, new_file); auto emplace_ret = this->name_to_file.emplace(name, new_file);
@@ -37,7 +37,7 @@ shared_ptr<const FileContentsCache::File> FileContentsCache::replace(
} }
FileContentsCache::GetResult FileContentsCache::get_or_load(const std::string& name) { FileContentsCache::GetResult FileContentsCache::get_or_load(const std::string& name) {
return this->get(name, load_file); return this->get(name, phosg::load_file);
} }
FileContentsCache::GetResult FileContentsCache::get_or_load(const char* name) { FileContentsCache::GetResult FileContentsCache::get_or_load(const char* name) {
@@ -59,7 +59,7 @@ shared_ptr<const FileContentsCache::File> FileContentsCache::get_or_throw(
FileContentsCache::GetResult FileContentsCache::get(const std::string& name, FileContentsCache::GetResult FileContentsCache::get(const std::string& name,
std::function<std::string(const std::string&)> generate) { std::function<std::string(const std::string&)> generate) {
uint64_t t = now(); uint64_t t = phosg::now();
try { try {
auto& entry = this->name_to_file.at(name); auto& entry = this->name_to_file.at(name);
if (this->ttl_usecs && (t - entry->load_time < this->ttl_usecs)) { if (this->ttl_usecs && (t - entry->load_time < this->ttl_usecs)) {
+1 -1
View File
@@ -78,7 +78,7 @@ public:
} }
template <typename T, typename NameT> template <typename T, typename NameT>
GetObjResult<T> get_obj(NameT name, std::function<T(const std::string&)> generate) { GetObjResult<T> get_obj(NameT name, std::function<T(const std::string&)> generate) {
uint64_t t = now(); uint64_t t = phosg::now();
try { try {
auto& f = this->name_to_file.at(name); auto& f = this->name_to_file.at(name);
if (f->data->size() != sizeof(T)) { if (f->data->size() != sizeof(T)) {
+49 -49
View File
@@ -59,7 +59,7 @@ string CompiledFunctionCode::generate_client_command_t(
footer.entrypoint_addr_offset = this->entrypoint_offset_offset; footer.entrypoint_addr_offset = this->entrypoint_offset_offset;
footer.unused2.clear(0); footer.unused2.clear(0);
StringWriter w; phosg::StringWriter w;
if (!label_writes.empty()) { if (!label_writes.empty()) {
string modified_code = this->code; string modified_code = this->code;
for (const auto& it : label_writes) { for (const auto& it : label_writes) {
@@ -91,7 +91,7 @@ string CompiledFunctionCode::generate_client_command_t(
footer.relocations_offset = override_relocations_offset; footer.relocations_offset = override_relocations_offset;
} else { } else {
for (uint16_t delta : this->relocation_deltas) { for (uint16_t delta : this->relocation_deltas) {
w.put<typename FooterT::U16T>(delta); w.put<U16T<FooterT::IsBE>>(delta);
} }
if (this->relocation_deltas.size() & 1) { if (this->relocation_deltas.size() & 1) {
w.put_u16(0); w.put_u16(0);
@@ -161,24 +161,24 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
} }
// Look in the function directory first, then the system directory // Look in the function directory first, then the system directory
string asm_filename = string_printf("%s/%s.%s.inc.s", function_directory.c_str(), name.c_str(), arch_name_token); string asm_filename = phosg::string_printf("%s/%s.%s.inc.s", function_directory.c_str(), name.c_str(), arch_name_token);
if (!isfile(asm_filename)) { if (!phosg::isfile(asm_filename)) {
asm_filename = string_printf("%s/%s.%s.inc.s", system_directory.c_str(), name.c_str(), arch_name_token); asm_filename = phosg::string_printf("%s/%s.%s.inc.s", system_directory.c_str(), name.c_str(), arch_name_token);
} }
if (isfile(asm_filename)) { if (phosg::isfile(asm_filename)) {
if (!get_include_stack.emplace(name).second) { if (!get_include_stack.emplace(name).second) {
throw runtime_error("mutual recursion between includes: " + name); throw runtime_error("mutual recursion between includes: " + name);
} }
ResourceDASM::EmulatorBase::AssembleResult ret; ResourceDASM::EmulatorBase::AssembleResult ret;
switch (arch) { switch (arch) {
case CompiledFunctionCode::Architecture::POWERPC: case CompiledFunctionCode::Architecture::POWERPC:
ret = ResourceDASM::PPC32Emulator::assemble(load_file(asm_filename), get_include); ret = ResourceDASM::PPC32Emulator::assemble(phosg::load_file(asm_filename), get_include);
break; break;
case CompiledFunctionCode::Architecture::X86: case CompiledFunctionCode::Architecture::X86:
ret = ResourceDASM::X86Emulator::assemble(load_file(asm_filename), get_include); ret = ResourceDASM::X86Emulator::assemble(phosg::load_file(asm_filename), get_include);
break; break;
case CompiledFunctionCode::Architecture::SH4: case CompiledFunctionCode::Architecture::SH4:
ret = ResourceDASM::SH4Emulator::assemble(load_file(asm_filename), get_include); ret = ResourceDASM::SH4Emulator::assemble(phosg::load_file(asm_filename), get_include);
break; break;
default: default:
throw runtime_error("unknown architecture"); throw runtime_error("unknown architecture");
@@ -188,12 +188,12 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
} }
string bin_filename = function_directory + "/" + name + ".inc.bin"; string bin_filename = function_directory + "/" + name + ".inc.bin";
if (isfile(bin_filename)) { if (phosg::isfile(bin_filename)) {
return load_file(bin_filename); return phosg::load_file(bin_filename);
} }
bin_filename = system_directory + "/" + name + ".inc.bin"; bin_filename = system_directory + "/" + name + ".inc.bin";
if (isfile(bin_filename)) { if (phosg::isfile(bin_filename)) {
return load_file(bin_filename); return phosg::load_file(bin_filename);
} }
throw runtime_error("data not found for include: " + name + " (from " + asm_filename + " or " + bin_filename + ")"); throw runtime_error("data not found for include: " + name + " (from " + asm_filename + " or " + bin_filename + ")");
}; };
@@ -229,7 +229,7 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
set<uint32_t> reloc_indexes; set<uint32_t> reloc_indexes;
for (const auto& it : ret->label_offsets) { for (const auto& it : ret->label_offsets) {
if (starts_with(it.first, "reloc")) { if (phosg::starts_with(it.first, "reloc")) {
reloc_indexes.emplace(it.second / 4); reloc_indexes.emplace(it.second / 4);
} }
} }
@@ -260,28 +260,28 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
return; return;
} }
string system_dir_path = ends_with(directory, "/") ? (directory + "System") : (directory + "/System"); string system_dir_path = phosg::ends_with(directory, "/") ? (directory + "System") : (directory + "/System");
uint32_t next_menu_item_id = 1; uint32_t next_menu_item_id = 1;
for (const auto& subdir_name : list_directory_sorted(directory)) { for (const auto& subdir_name : phosg::list_directory_sorted(directory)) {
string subdir_path = ends_with(directory, "/") ? (directory + subdir_name) : (directory + "/" + subdir_name); string subdir_path = phosg::ends_with(directory, "/") ? (directory + subdir_name) : (directory + "/" + subdir_name);
if (!isdir(subdir_path)) { if (!phosg::isdir(subdir_path)) {
function_compiler_log.warning("Skipping %s (not a directory)", subdir_name.c_str()); function_compiler_log.warning("Skipping %s (not a directory)", subdir_name.c_str());
continue; continue;
} }
for (const auto& filename : list_directory_sorted(subdir_path)) { for (const auto& filename : phosg::list_directory_sorted(subdir_path)) {
try { try {
if (!ends_with(filename, ".s")) { if (!phosg::ends_with(filename, ".s")) {
continue; continue;
} }
string name = filename.substr(0, filename.size() - 2); string name = filename.substr(0, filename.size() - 2);
if (ends_with(name, ".inc")) { if (phosg::ends_with(name, ".inc")) {
continue; continue;
} }
bool is_patch = ends_with(name, ".patch"); bool is_patch = phosg::ends_with(name, ".patch");
if (is_patch) { if (is_patch) {
name.resize(name.size() - 6); name.resize(name.size() - 6);
} }
@@ -290,15 +290,15 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
CompiledFunctionCode::Architecture arch = CompiledFunctionCode::Architecture::UNKNOWN; CompiledFunctionCode::Architecture arch = CompiledFunctionCode::Architecture::UNKNOWN;
uint32_t specific_version = 0; uint32_t specific_version = 0;
string short_name = name; string short_name = name;
if (ends_with(name, ".ppc")) { if (phosg::ends_with(name, ".ppc")) {
arch = CompiledFunctionCode::Architecture::POWERPC; arch = CompiledFunctionCode::Architecture::POWERPC;
name.resize(name.size() - 4); name.resize(name.size() - 4);
short_name = name; short_name = name;
} else if (ends_with(name, ".x86")) { } else if (phosg::ends_with(name, ".x86")) {
arch = CompiledFunctionCode::Architecture::X86; arch = CompiledFunctionCode::Architecture::X86;
name.resize(name.size() - 4); name.resize(name.size() - 4);
short_name = name; short_name = name;
} else if (ends_with(name, ".sh4")) { } else if (phosg::ends_with(name, ".sh4")) {
arch = CompiledFunctionCode::Architecture::SH4; arch = CompiledFunctionCode::Architecture::SH4;
name.resize(name.size() - 4); name.resize(name.size() - 4);
short_name = name; short_name = name;
@@ -321,11 +321,11 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
} }
string path = subdir_path + "/" + filename; string path = subdir_path + "/" + filename;
string text = load_file(path); string text = phosg::load_file(path);
auto code = compile_function_code(arch, subdir_path, system_dir_path, name, text); auto code = compile_function_code(arch, subdir_path, system_dir_path, name, text);
if (code->index != 0) { if (code->index != 0) {
if (!this->index_to_function.emplace(code->index, code).second) { if (!this->index_to_function.emplace(code->index, code).second) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"duplicate function index: %08" PRIX32, code->index)); "duplicate function index: %08" PRIX32, code->index));
} }
} }
@@ -338,11 +338,11 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
this->menu_item_id_and_specific_version_to_patch_function.emplace( this->menu_item_id_and_specific_version_to_patch_function.emplace(
static_cast<uint64_t>(code->menu_item_id) << 32 | specific_version, code); static_cast<uint64_t>(code->menu_item_id) << 32 | specific_version, code);
this->name_and_specific_version_to_patch_function.emplace( this->name_and_specific_version_to_patch_function.emplace(
string_printf("%s-%08" PRIX32, short_name.c_str(), specific_version), code); phosg::string_printf("%s-%08" PRIX32, short_name.c_str(), specific_version), code);
} }
string index_prefix = code->index ? string_printf("%02X => ", code->index) : ""; string index_prefix = code->index ? phosg::string_printf("%02X => ", code->index) : "";
string patch_prefix = is_patch ? string_printf("[%08" PRIX32 "/%08" PRIX32 "] ", code->menu_item_id, code->specific_version) : ""; string patch_prefix = is_patch ? phosg::string_printf("[%08" PRIX32 "/%08" PRIX32 "] ", code->menu_item_id, code->specific_version) : "";
function_compiler_log.info("Compiled function %s%s%s (%s)", function_compiler_log.info("Compiled function %s%s%s (%s)",
index_prefix.c_str(), patch_prefix.c_str(), name.c_str(), name_for_architecture(code->arch)); index_prefix.c_str(), patch_prefix.c_str(), name.c_str(), name_for_architecture(code->arch));
@@ -354,13 +354,13 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
} }
shared_ptr<const Menu> FunctionCodeIndex::patch_menu(uint32_t specific_version) const { shared_ptr<const Menu> FunctionCodeIndex::patch_menu(uint32_t specific_version) const {
auto suffix = string_printf("-%08" PRIX32, specific_version); auto suffix = phosg::string_printf("-%08" PRIX32, specific_version);
auto ret = make_shared<Menu>(MenuID::PATCHES, "Patches"); auto ret = make_shared<Menu>(MenuID::PATCHES, "Patches");
ret->items.emplace_back(PatchesMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0); ret->items.emplace_back(PatchesMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
for (const auto& it : this->name_and_specific_version_to_patch_function) { for (const auto& it : this->name_and_specific_version_to_patch_function) {
const auto& fn = it.second; const auto& fn = it.second;
if (fn->hide_from_patches_menu || !ends_with(it.first, suffix)) { if (fn->hide_from_patches_menu || !phosg::ends_with(it.first, suffix)) {
continue; continue;
} }
ret->items.emplace_back( ret->items.emplace_back(
@@ -374,13 +374,13 @@ shared_ptr<const Menu> FunctionCodeIndex::patch_menu(uint32_t specific_version)
shared_ptr<const Menu> FunctionCodeIndex::patch_switches_menu( shared_ptr<const Menu> FunctionCodeIndex::patch_switches_menu(
uint32_t specific_version, const std::unordered_set<std::string>& auto_patches_enabled) const { uint32_t specific_version, const std::unordered_set<std::string>& auto_patches_enabled) const {
auto suffix = string_printf("-%08" PRIX32, specific_version); auto suffix = phosg::string_printf("-%08" PRIX32, specific_version);
auto ret = make_shared<Menu>(MenuID::PATCH_SWITCHES, "Patch switches"); auto ret = make_shared<Menu>(MenuID::PATCH_SWITCHES, "Patch switches");
ret->items.emplace_back(PatchesMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0); ret->items.emplace_back(PatchesMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
for (const auto& it : this->name_and_specific_version_to_patch_function) { for (const auto& it : this->name_and_specific_version_to_patch_function) {
const auto& fn = it.second; const auto& fn = it.second;
if (fn->hide_from_patches_menu || !ends_with(it.first, suffix)) { if (fn->hide_from_patches_menu || !phosg::ends_with(it.first, suffix)) {
continue; continue;
} }
string name; string name;
@@ -404,7 +404,7 @@ bool FunctionCodeIndex::patch_menu_empty(uint32_t specific_version) const {
std::shared_ptr<const CompiledFunctionCode> FunctionCodeIndex::get_patch( std::shared_ptr<const CompiledFunctionCode> FunctionCodeIndex::get_patch(
const std::string& name, uint32_t specific_version) const { const std::string& name, uint32_t specific_version) const {
return this->name_and_specific_version_to_patch_function.at( return this->name_and_specific_version_to_patch_function.at(
string_printf("%s-%08" PRIX32, name.c_str(), specific_version)); phosg::string_printf("%s-%08" PRIX32, name.c_str(), specific_version));
} }
DOLFileIndex::DOLFileIndex(const string& directory) { DOLFileIndex::DOLFileIndex(const string& directory) {
@@ -412,7 +412,7 @@ DOLFileIndex::DOLFileIndex(const string& directory) {
function_compiler_log.info("Function compiler is not available"); function_compiler_log.info("Function compiler is not available");
return; return;
} }
if (!isdir(directory)) { if (!phosg::isdir(directory)) {
function_compiler_log.info("DOL file directory is missing"); function_compiler_log.info("DOL file directory is missing");
return; return;
} }
@@ -422,9 +422,9 @@ DOLFileIndex::DOLFileIndex(const string& directory) {
menu->items.emplace_back(ProgramsMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0); menu->items.emplace_back(ProgramsMenuItemID::GO_BACK, "Go back", "Return to the\nmain menu", 0);
uint32_t next_menu_item_id = 0; uint32_t next_menu_item_id = 0;
for (const auto& filename : list_directory_sorted(directory)) { for (const auto& filename : phosg::list_directory_sorted(directory)) {
bool is_dol = ends_with(filename, ".dol"); bool is_dol = phosg::ends_with(filename, ".dol");
bool is_compressed_dol = ends_with(filename, ".dol.prs"); bool is_compressed_dol = phosg::ends_with(filename, ".dol.prs");
if (!is_dol && !is_compressed_dol) { if (!is_dol && !is_compressed_dol) {
continue; continue;
} }
@@ -436,13 +436,13 @@ DOLFileIndex::DOLFileIndex(const string& directory) {
dol->name = name; dol->name = name;
string path = directory + "/" + filename; string path = directory + "/" + filename;
string file_data = load_file(path); string file_data = phosg::load_file(path);
string description; string description;
if (is_compressed_dol) { if (is_compressed_dol) {
size_t decompressed_size = prs_decompress_size(file_data); size_t decompressed_size = prs_decompress_size(file_data);
StringWriter w; phosg::StringWriter w;
w.put_u32b(file_data.size()); w.put_u32b(file_data.size());
w.put_u32b(decompressed_size); w.put_u32b(decompressed_size);
w.write(file_data); w.write(file_data);
@@ -451,15 +451,15 @@ DOLFileIndex::DOLFileIndex(const string& directory) {
} }
dol->data = std::move(w.str()); dol->data = std::move(w.str());
string compressed_size_str = format_size(file_data.size()); string compressed_size_str = phosg::format_size(file_data.size());
string decompressed_size_str = format_size(decompressed_size); string decompressed_size_str = phosg::format_size(decompressed_size);
function_compiler_log.info("Loaded compressed DOL file %s (%s -> %s)", function_compiler_log.info("Loaded compressed DOL file %s (%s -> %s)",
dol->name.c_str(), compressed_size_str.c_str(), decompressed_size_str.c_str()); dol->name.c_str(), compressed_size_str.c_str(), decompressed_size_str.c_str());
description = string_printf("$C6%s$C7\n%s\n%s (orig)", description = phosg::string_printf("$C6%s$C7\n%s\n%s (orig)",
dol->name.c_str(), compressed_size_str.c_str(), decompressed_size_str.c_str()); dol->name.c_str(), compressed_size_str.c_str(), decompressed_size_str.c_str());
} else { } else {
StringWriter w; phosg::StringWriter w;
w.put_u32b(0); w.put_u32b(0);
w.put_u32b(file_data.size()); w.put_u32b(file_data.size());
w.write(file_data); w.write(file_data);
@@ -468,9 +468,9 @@ DOLFileIndex::DOLFileIndex(const string& directory) {
} }
dol->data = std::move(w.str()); dol->data = std::move(w.str());
string size_str = format_size(dol->data.size()); string size_str = phosg::format_size(dol->data.size());
function_compiler_log.info("Loaded DOL file %s (%s)", filename.c_str(), size_str.c_str()); function_compiler_log.info("Loaded DOL file %s (%s)", filename.c_str(), size_str.c_str());
description = string_printf("$C6%s$C7\n%s", dol->name.c_str(), size_str.c_str()); description = phosg::string_printf("$C6%s$C7\n%s", dol->name.c_str(), size_str.c_str());
} }
this->name_to_file.emplace(dol->name, dol); this->name_to_file.emplace(dol->name, dol);
@@ -503,7 +503,7 @@ uint32_t specific_version_for_gc_header_checksum(uint32_t header_checksum) {
data.region_code = *region_code; data.region_code = *region_code;
for (uint8_t version_code = 0; version_code < 8; version_code++) { for (uint8_t version_code = 0; version_code < 8; version_code++) {
data.version_code = version_code; data.version_code = version_code;
uint32_t checksum = crc32(&data, sizeof(data)); uint32_t checksum = phosg::crc32(&data, sizeof(data));
uint32_t specific_version = 0x33000030 | (*game_code2 << 16) | (*region_code << 8) | version_code; uint32_t specific_version = 0x33000030 | (*game_code2 << 16) | (*region_code << 8) | version_code;
if (!checksum_to_specific_version.emplace(checksum, specific_version).second) { if (!checksum_to_specific_version.emplace(checksum, specific_version).second) {
throw logic_error("multiple specific_versions have same header checksum"); throw logic_error("multiple specific_versions have same header checksum");
@@ -515,7 +515,7 @@ uint32_t specific_version_for_gc_header_checksum(uint32_t header_checksum) {
data.region_code = 'J'; data.region_code = 'J';
data.system_code = 'D'; data.system_code = 'D';
data.version_code = 0; data.version_code = 0;
uint32_t checksum = crc32(&data, sizeof(data)); uint32_t checksum = phosg::crc32(&data, sizeof(data));
uint32_t specific_version = 0x33004A54 | (*game_code2 << 16); uint32_t specific_version = 0x33004A54 | (*game_code2 << 16);
if (!checksum_to_specific_version.emplace(checksum, specific_version).second) { if (!checksum_to_specific_version.emplace(checksum, specific_version).second) {
throw logic_error("multiple specific_versions have same header checksum"); throw logic_error("multiple specific_versions have same header checksum");
+13 -14
View File
@@ -5,16 +5,15 @@
#include <stdexcept> #include <stdexcept>
#include "Text.hh" #include "Text.hh"
#include "Types.hh"
using namespace std; using namespace std;
template <bool IsBigEndian> template <bool BE>
struct GSLHeaderEntryT { struct GSLHeaderEntryT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
pstring<TextEncoding::ASCII, 0x20> filename; pstring<TextEncoding::ASCII, 0x20> filename;
U32T offset; // In pages, so actual offset is this * 0x800 U32T<BE> offset; // In pages, so actual offset is this * 0x800
U32T size; U32T<BE> size;
uint64_t unused; uint64_t unused;
} __packed__; } __packed__;
@@ -23,12 +22,12 @@ using GSLHeaderEntryBE = GSLHeaderEntryT<true>;
check_struct_size(GSLHeaderEntry, 0x30); check_struct_size(GSLHeaderEntry, 0x30);
check_struct_size(GSLHeaderEntryBE, 0x30); check_struct_size(GSLHeaderEntryBE, 0x30);
template <bool IsBigEndian> template <bool BE>
void GSLArchive::load_t() { void GSLArchive::load_t() {
StringReader r(*this->data); phosg::StringReader r(*this->data);
uint64_t min_data_offset = 0xFFFFFFFFFFFFFFFF; uint64_t min_data_offset = 0xFFFFFFFFFFFFFFFF;
while (r.where() < min_data_offset) { while (r.where() < min_data_offset) {
const auto& entry = r.get<GSLHeaderEntryT<IsBigEndian>>(); const auto& entry = r.get<GSLHeaderEntryT<BE>>();
if (entry.filename.empty()) { if (entry.filename.empty()) {
break; break;
} }
@@ -71,10 +70,10 @@ string GSLArchive::get_copy(const string& name) const {
} }
} }
StringReader GSLArchive::get_reader(const string& name) const { phosg::StringReader GSLArchive::get_reader(const string& name) const {
try { try {
const auto& entry = this->entries.at(name); const auto& entry = this->entries.at(name);
return StringReader(this->data->data() + entry.offset, entry.size); return phosg::StringReader(this->data->data() + entry.offset, entry.size);
} catch (const out_of_range&) { } catch (const out_of_range&) {
throw out_of_range("GSL does not contain file: " + name); throw out_of_range("GSL does not contain file: " + name);
} }
@@ -84,16 +83,16 @@ string GSLArchive::generate(const unordered_map<string, string>& files, bool big
return big_endian ? GSLArchive::generate_t<true>(files) : GSLArchive::generate_t<false>(files); return big_endian ? GSLArchive::generate_t<true>(files) : GSLArchive::generate_t<false>(files);
} }
template <bool IsBigEndian> template <bool BE>
string GSLArchive::generate_t(const unordered_map<string, string>& files) { string GSLArchive::generate_t(const unordered_map<string, string>& files) {
StringWriter w; phosg::StringWriter w;
// Make sure there's enough space for a blank header entry before any file's // Make sure there's enough space for a blank header entry before any file's
// data pages begin // data pages begin
uint32_t data_start_offset = ((sizeof(GSLHeaderEntryT<IsBigEndian>) * (files.size() + 1)) + 0x7FF) & (~0x7FF); uint32_t data_start_offset = ((sizeof(GSLHeaderEntryT<BE>) * (files.size() + 1)) + 0x7FF) & (~0x7FF);
uint32_t data_offset = data_start_offset; uint32_t data_offset = data_start_offset;
for (const auto& file : files) { for (const auto& file : files) {
GSLHeaderEntryT<IsBigEndian> entry; GSLHeaderEntryT<BE> entry;
entry.filename.encode(file.first); entry.filename.encode(file.first);
entry.offset = data_offset >> 11; entry.offset = data_offset >> 11;
entry.size = file.second.size(); entry.size = file.second.size();
+3 -3
View File
@@ -21,14 +21,14 @@ public:
std::pair<const void*, size_t> get(const std::string& name) const; std::pair<const void*, size_t> get(const std::string& name) const;
std::string get_copy(const std::string& name) const; std::string get_copy(const std::string& name) const;
StringReader get_reader(const std::string& name) const; phosg::StringReader get_reader(const std::string& name) const;
static std::string generate(const std::unordered_map<std::string, std::string>& files, bool big_endian); static std::string generate(const std::unordered_map<std::string, std::string>& files, bool big_endian);
private: private:
template <bool IsBigEndian> template <bool BE>
void load_t(); void load_t();
template <bool IsBigEndian> template <bool BE>
static std::string generate_t(const std::unordered_map<std::string, std::string>& files); static std::string generate_t(const std::unordered_map<std::string, std::string>& files);
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
+2 -2
View File
@@ -34,7 +34,7 @@ struct GVRHeader {
be_uint16_t height; be_uint16_t height;
} __packed_ws__(GVRHeader, 0x10); } __packed_ws__(GVRHeader, 0x10);
string encode_gvm(const Image& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index) { string encode_gvm(const phosg::Image& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index) {
int8_t dimensions_field = -2; int8_t dimensions_field = -2;
{ {
size_t h = img.get_height(); size_t h = img.get_height();
@@ -66,7 +66,7 @@ string encode_gvm(const Image& img, GVRDataFormat data_format, const std::string
throw invalid_argument("cannot encode pixel format"); throw invalid_argument("cannot encode pixel format");
} }
StringWriter w; phosg::StringWriter w;
w.put<GVMFileHeader>({.signature = 0x47564D48, .header_size = 0x48, .flags = 0x000F, .num_files = 1}); w.put<GVMFileHeader>({.signature = 0x47564D48, .header_size = 0x48, .flags = 0x000F, .num_files = 1});
GVMFileEntry file_entry; GVMFileEntry file_entry;
file_entry.file_num = 0; file_entry.file_num = 0;
+1 -1
View File
@@ -19,7 +19,7 @@ enum class GVRDataFormat : uint8_t {
DXT1 = 0x0E, DXT1 = 0x0E,
}; };
std::string encode_gvm(const Image& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index); std::string encode_gvm(const phosg::Image& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index);
constexpr uint16_t encode_rgb565(uint8_t r, uint8_t g, uint8_t b) { constexpr uint16_t encode_rgb565(uint8_t r, uint8_t g, uint8_t b) {
return ((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | ((b >> 3) & 0x001F); return ((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | ((b >> 3) & 0x001F);
+153 -153
View File
@@ -110,7 +110,7 @@ unordered_multimap<string, string> HTTPServer::parse_url_params(const string& qu
if (query.empty()) { if (query.empty()) {
return params; return params;
} }
for (auto it : split(query, '&')) { for (auto it : phosg::split(query, '&')) {
size_t first_equals = it.find('='); size_t first_equals = it.find('=');
if (first_equals != string::npos) { if (first_equals != string::npos) {
string value(it, first_equals + 1); string value(it, first_equals + 1);
@@ -119,8 +119,8 @@ unordered_multimap<string, string> HTTPServer::parse_url_params(const string& qu
for (; read_offset < value.size(); write_offset++) { for (; read_offset < value.size(); write_offset++) {
if ((value[read_offset] == '%') && (read_offset < value.size() - 2)) { if ((value[read_offset] == '%') && (read_offset < value.size() - 2)) {
value[write_offset] = value[write_offset] =
static_cast<char>(value_for_hex_char(value[read_offset + 1]) << 4) | static_cast<char>(phosg::value_for_hex_char(value[read_offset + 1]) << 4) |
static_cast<char>(value_for_hex_char(value[read_offset + 2])); static_cast<char>(phosg::value_for_hex_char(value[read_offset + 2]));
read_offset += 3; read_offset += 3;
} else if (value[write_offset] == '+') { } else if (value[write_offset] == '+') {
value[write_offset] = ' '; value[write_offset] = ' ';
@@ -171,7 +171,7 @@ HTTPServer::HTTPServer(shared_ptr<ServerState> state)
} }
void HTTPServer::listen(const string& socket_path) { void HTTPServer::listen(const string& socket_path) {
int fd = ::listen(socket_path, 0, SOMAXCONN); int fd = phosg::listen(socket_path, 0, SOMAXCONN);
server_log.info("Listening on Unix socket %s on fd %d (HTTP)", socket_path.c_str(), fd); server_log.info("Listening on Unix socket %s on fd %d (HTTP)", socket_path.c_str(), fd);
this->add_socket(fd); this->add_socket(fd);
} }
@@ -180,8 +180,8 @@ void HTTPServer::listen(const string& addr, int port) {
if (port == 0) { if (port == 0) {
this->listen(addr); this->listen(addr);
} else { } else {
int fd = ::listen(addr, port, SOMAXCONN); int fd = phosg::listen(addr, port, SOMAXCONN);
string netloc_str = render_netloc(addr, port); string netloc_str = phosg::render_netloc(addr, port);
server_log.info("Listening on TCP interface %s on fd %d (HTTP)", netloc_str.c_str(), fd); server_log.info("Listening on TCP interface %s on fd %d (HTTP)", netloc_str.c_str(), fd);
this->add_socket(fd); this->add_socket(fd);
} }
@@ -207,7 +207,7 @@ HTTPServer::WebsocketClient::WebsocketClient(struct evhttp_connection* conn)
: conn(conn), : conn(conn),
bev(evhttp_connection_get_bufferevent(this->conn)), bev(evhttp_connection_get_bufferevent(this->conn)),
pending_opcode(0xFF), pending_opcode(0xFF),
last_communication_time(now()) {} last_communication_time(phosg::now()) {}
HTTPServer::WebsocketClient::~WebsocketClient() { HTTPServer::WebsocketClient::~WebsocketClient() {
evhttp_connection_free(this->conn); evhttp_connection_free(this->conn);
@@ -241,7 +241,7 @@ shared_ptr<HTTPServer::WebsocketClient> HTTPServer::enable_websockets(struct evh
// we're about to free the original // we're about to free the original
string sec_websocket_key = sec_websocket_key_header; string sec_websocket_key = sec_websocket_key_header;
string sec_websocket_accept_data = sec_websocket_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; string sec_websocket_accept_data = sec_websocket_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
string sec_websocket_accept = base64_encode(sha1(sec_websocket_accept_data)); string sec_websocket_accept = phosg::base64_encode(phosg::sha1(sec_websocket_accept_data));
// Hijack the bufferevent since it's no longer handling HTTP at all // Hijack the bufferevent since it's no longer handling HTTP at all
struct evhttp_connection* conn = evhttp_request_get_connection(req); struct evhttp_connection* conn = evhttp_request_get_connection(req);
@@ -290,13 +290,13 @@ void HTTPServer::on_websocket_read(struct bufferevent* bev) {
if (bytes_read < 10) { if (bytes_read < 10) {
break; // Full 64-bit header not yet available break; // Full 64-bit header not yet available
} }
payload_size = bswap64(*reinterpret_cast<const uint64_t*>(&header_data[2])); payload_size = phosg::bswap64(*reinterpret_cast<const uint64_t*>(&header_data[2]));
header_size = 10; header_size = 10;
} else if (payload_size == 0x7E) { } else if (payload_size == 0x7E) {
if (bytes_read < 4) { if (bytes_read < 4) {
break; // Full 16-bit size header not yet available break; // Full 16-bit size header not yet available
} }
payload_size = bswap16(*reinterpret_cast<const uint16_t*>(&header_data[2])); payload_size = phosg::bswap16(*reinterpret_cast<const uint16_t*>(&header_data[2]));
header_size = 4; header_size = 4;
} }
if (evbuffer_get_length(in_buf) < header_size + payload_size) { if (evbuffer_get_length(in_buf) < header_size + payload_size) {
@@ -312,7 +312,7 @@ void HTTPServer::on_websocket_read(struct bufferevent* bev) {
} }
shared_ptr<WebsocketClient> c = this->bev_to_websocket_client.at(bev); shared_ptr<WebsocketClient> c = this->bev_to_websocket_client.at(bev);
c->last_communication_time = now(); c->last_communication_time = phosg::now();
// Read and unmask message data // Read and unmask message data
string payload(payload_size, '\0'); string payload(payload_size, '\0');
@@ -392,11 +392,11 @@ void HTTPServer::send_websocket_message(struct bufferevent* bev,
if (message.size() > 65535) { if (message.size() > 65535) {
header.push_back(0x7F); header.push_back(0x7F);
header.resize(10); header.resize(10);
*reinterpret_cast<uint64_t*>(const_cast<char*>(header.data() + 2)) = bswap64(message.size()); *reinterpret_cast<uint64_t*>(const_cast<char*>(header.data() + 2)) = phosg::bswap64(message.size());
} else if (message.size() > 0x7D) { } else if (message.size() > 0x7D) {
header.push_back(0x7E); header.push_back(0x7E);
header.resize(4); header.resize(4);
*reinterpret_cast<uint16_t*>(const_cast<char*>(header.data() + 2)) = bswap16(message.size()); *reinterpret_cast<uint16_t*>(const_cast<char*>(header.data() + 2)) = phosg::bswap16(message.size());
} else { } else {
header.push_back(message.size()); header.push_back(message.size());
} }
@@ -418,7 +418,7 @@ void HTTPServer::handle_websocket_disconnect(shared_ptr<WebsocketClient> c) {
this->rare_drop_subscribers.erase(c); this->rare_drop_subscribers.erase(c);
} }
void HTTPServer::send_rare_drop_notification(shared_ptr<const JSON> message) { void HTTPServer::send_rare_drop_notification(shared_ptr<const phosg::JSON> message) {
forward_to_event_thread(this->base, [this, message]() -> void { forward_to_event_thread(this->base, [this, message]() -> void {
if (this->rare_drop_subscribers.empty()) { if (this->rare_drop_subscribers.empty()) {
return; return;
@@ -434,26 +434,26 @@ void HTTPServer::dispatch_handle_request(struct evhttp_request* req, void* ctx)
reinterpret_cast<HTTPServer*>(ctx)->handle_request(req); reinterpret_cast<HTTPServer*>(ctx)->handle_request(req);
} }
JSON HTTPServer::generate_quest_json_st(shared_ptr<const Quest> q) { phosg::JSON HTTPServer::generate_quest_json_st(shared_ptr<const Quest> q) {
if (!q) { if (!q) {
return nullptr; return nullptr;
} }
auto battle_rules_json = q->battle_rules ? q->battle_rules->json() : nullptr; auto battle_rules_json = q->battle_rules ? q->battle_rules->json() : nullptr;
auto challenge_template_index_json = (q->challenge_template_index >= 0) auto challenge_template_index_json = (q->challenge_template_index >= 0)
? q->challenge_template_index ? q->challenge_template_index
: JSON(nullptr); : phosg::JSON(nullptr);
return JSON::dict({ return phosg::JSON::dict({
{"Number", q->quest_number}, {"Number", q->quest_number},
{"Episode", name_for_episode(q->episode)}, {"Episode", name_for_episode(q->episode)},
{"Joinable", q->joinable}, {"Joinable", q->joinable},
{"LockStatusRegister", (q->lock_status_register >= 0) ? q->lock_status_register : JSON(nullptr)}, {"LockStatusRegister", (q->lock_status_register >= 0) ? q->lock_status_register : phosg::JSON(nullptr)},
{"Name", q->name}, {"Name", q->name},
{"BattleRules", std::move(battle_rules_json)}, {"BattleRules", std::move(battle_rules_json)},
{"ChallengeTemplateIndex", std::move(challenge_template_index_json)}, {"ChallengeTemplateIndex", std::move(challenge_template_index_json)},
}); });
} }
JSON HTTPServer::generate_client_config_json_st(const Client::Config& config) { phosg::JSON HTTPServer::generate_client_config_json_st(const Client::Config& config) {
const char* drop_notifications_mode = "unknown"; const char* drop_notifications_mode = "unknown";
switch (config.get_drop_notification_mode()) { switch (config.get_drop_notification_mode()) {
case Client::ItemDropNotificationMode::NOTHING: case Client::ItemDropNotificationMode::NOTHING:
@@ -470,7 +470,7 @@ JSON HTTPServer::generate_client_config_json_st(const Client::Config& config) {
break; break;
} }
auto ret = JSON::dict({ auto ret = phosg::JSON::dict({
{"SpecificVersion", config.specific_version}, {"SpecificVersion", config.specific_version},
{"SwitchAssistEnabled", (config.check_flag(Client::Flag::SWITCH_ASSIST_ENABLED) ? true : false)}, {"SwitchAssistEnabled", (config.check_flag(Client::Flag::SWITCH_ASSIST_ENABLED) ? true : false)},
{"InfiniteHPEnabled", (config.check_flag(Client::Flag::INFINITE_HP_ENABLED) ? true : false)}, {"InfiniteHPEnabled", (config.check_flag(Client::Flag::INFINITE_HP_ENABLED) ? true : false)},
@@ -486,46 +486,46 @@ JSON HTTPServer::generate_client_config_json_st(const Client::Config& config) {
{"ProxyBlockFunctionCalls", (config.check_flag(Client::Flag::PROXY_BLOCK_FUNCTION_CALLS) ? true : false)}, {"ProxyBlockFunctionCalls", (config.check_flag(Client::Flag::PROXY_BLOCK_FUNCTION_CALLS) ? true : false)},
{"ProxyEp3UnmaskWhispers", (config.check_flag(Client::Flag::PROXY_EP3_UNMASK_WHISPERS) ? true : false)}, {"ProxyEp3UnmaskWhispers", (config.check_flag(Client::Flag::PROXY_EP3_UNMASK_WHISPERS) ? true : false)},
}); });
ret.emplace("OverrideRandomSeed", config.check_flag(Client::Flag::USE_OVERRIDE_RANDOM_SEED) ? config.override_random_seed : JSON(nullptr)); ret.emplace("OverrideRandomSeed", config.check_flag(Client::Flag::USE_OVERRIDE_RANDOM_SEED) ? config.override_random_seed : phosg::JSON(nullptr));
ret.emplace("OverrideSectionID", (config.override_section_id != 0xFF) ? config.override_section_id : JSON(nullptr)); ret.emplace("OverrideSectionID", (config.override_section_id != 0xFF) ? config.override_section_id : phosg::JSON(nullptr));
ret.emplace("OverrideLobbyEvent", (config.override_lobby_event != 0xFF) ? config.override_lobby_event : JSON(nullptr)); ret.emplace("OverrideLobbyEvent", (config.override_lobby_event != 0xFF) ? config.override_lobby_event : phosg::JSON(nullptr));
ret.emplace("OverrideLobbyNumber", (config.override_lobby_number != 0x80) ? config.override_lobby_number : JSON(nullptr)); ret.emplace("OverrideLobbyNumber", (config.override_lobby_number != 0x80) ? config.override_lobby_number : phosg::JSON(nullptr));
return ret; return ret;
} }
JSON HTTPServer::generate_account_json_st(shared_ptr<const Account> a) { phosg::JSON HTTPServer::generate_account_json_st(shared_ptr<const Account> a) {
auto dc_nte_licenses_json = JSON::list(); auto dc_nte_licenses_json = phosg::JSON::list();
for (const auto& it : a->dc_nte_licenses) { for (const auto& it : a->dc_nte_licenses) {
dc_nte_licenses_json.emplace_back(it.first); dc_nte_licenses_json.emplace_back(it.first);
} }
auto dc_licenses_json = JSON::list(); auto dc_licenses_json = phosg::JSON::list();
for (const auto& it : a->dc_licenses) { for (const auto& it : a->dc_licenses) {
dc_licenses_json.emplace_back(it.first); dc_licenses_json.emplace_back(it.first);
} }
auto pc_licenses_json = JSON::list(); auto pc_licenses_json = phosg::JSON::list();
for (const auto& it : a->pc_licenses) { for (const auto& it : a->pc_licenses) {
pc_licenses_json.emplace_back(it.first); pc_licenses_json.emplace_back(it.first);
} }
auto gc_licenses_json = JSON::list(); auto gc_licenses_json = phosg::JSON::list();
for (const auto& it : a->gc_licenses) { for (const auto& it : a->gc_licenses) {
gc_licenses_json.emplace_back(it.first); gc_licenses_json.emplace_back(it.first);
} }
auto xb_licenses_json = JSON::list(); auto xb_licenses_json = phosg::JSON::list();
for (const auto& it : a->xb_licenses) { for (const auto& it : a->xb_licenses) {
xb_licenses_json.emplace_back(it.first); xb_licenses_json.emplace_back(it.first);
} }
auto bb_licenses_json = JSON::list(); auto bb_licenses_json = phosg::JSON::list();
for (const auto& it : a->bb_licenses) { for (const auto& it : a->bb_licenses) {
bb_licenses_json.emplace_back(it.first); bb_licenses_json.emplace_back(it.first);
} }
auto auto_patches_json = JSON::list(); auto auto_patches_json = phosg::JSON::list();
for (const auto& it : a->auto_patches_enabled) { for (const auto& it : a->auto_patches_enabled) {
auto_patches_json.emplace_back(it); auto_patches_json.emplace_back(it);
} }
return JSON::dict({ return phosg::JSON::dict({
{"AccountID", a->account_id}, {"AccountID", a->account_id},
{"Flags", a->flags}, {"Flags", a->flags},
{"BanEndTime", a->ban_end_time ? a->ban_end_time : JSON(nullptr)}, {"BanEndTime", a->ban_end_time ? a->ban_end_time : phosg::JSON(nullptr)},
{"Ep3CurrentMeseta", a->ep3_current_meseta}, {"Ep3CurrentMeseta", a->ep3_current_meseta},
{"Ep3TotalMesetaEarned", a->ep3_total_meseta_earned}, {"Ep3TotalMesetaEarned", a->ep3_total_meseta_earned},
{"BBTeamID", a->bb_team_id}, {"BBTeamID", a->bb_team_id},
@@ -542,11 +542,11 @@ JSON HTTPServer::generate_account_json_st(shared_ptr<const Account> a) {
}); });
}; };
JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared_ptr<const ItemNameIndex> item_name_index) { phosg::JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared_ptr<const ItemNameIndex> item_name_index) {
auto ret = JSON::dict({ auto ret = phosg::JSON::dict({
{"ID", c->id}, {"ID", c->id},
{"RemoteAddress", render_sockaddr_storage(c->channel.remote_addr)}, {"RemoteAddress", phosg::render_sockaddr_storage(c->channel.remote_addr)},
{"Version", name_for_enum(c->version())}, {"Version", phosg::name_for_enum(c->version())},
{"SubVersion", c->sub_version}, {"SubVersion", c->sub_version},
{"Config", HTTPServer::generate_client_config_json_st(c->config)}, {"Config", HTTPServer::generate_client_config_json_st(c->config)},
{"Language", name_for_language_code(c->language())}, {"Language", name_for_language_code(c->language())},
@@ -555,7 +555,7 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
{"LocationFloor", c->floor}, {"LocationFloor", c->floor},
{"CanChat", c->can_chat}, {"CanChat", c->can_chat},
}); });
ret.emplace("Account", c->login ? HTTPServer::generate_account_json_st(c->login->account) : JSON(nullptr)); ret.emplace("Account", c->login ? HTTPServer::generate_account_json_st(c->login->account) : phosg::JSON(nullptr));
auto l = c->lobby.lock(); auto l = c->lobby.lock();
if (l) { if (l) {
ret.emplace("LobbyID", l->lobby_id); ret.emplace("LobbyID", l->lobby_id);
@@ -580,10 +580,10 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
ret.emplace("NumLuckMaterialsUsed", p->get_material_usage(PSOBBCharacterFile::MaterialType::LUCK)); ret.emplace("NumLuckMaterialsUsed", p->get_material_usage(PSOBBCharacterFile::MaterialType::LUCK));
} }
} }
JSON items_json = JSON::list(); phosg::JSON items_json = phosg::JSON::list();
for (size_t z = 0; z < p->inventory.num_items; z++) { for (size_t z = 0; z < p->inventory.num_items; z++) {
const auto& item = p->inventory.items[z]; const auto& item = p->inventory.items[z];
auto item_dict = JSON::dict({ auto item_dict = phosg::JSON::dict({
{"Flags", item.flags.load()}, {"Flags", item.flags.load()},
{"Data", item.data.hex()}, {"Data", item.data.hex()},
{"ItemID", item.data.id.load()}, {"ItemID", item.data.id.load()},
@@ -602,17 +602,17 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
ret.emplace("LCK", p->disp.stats.char_stats.lck.load()); ret.emplace("LCK", p->disp.stats.char_stats.lck.load());
ret.emplace("EXP", p->disp.stats.experience.load()); ret.emplace("EXP", p->disp.stats.experience.load());
ret.emplace("Meseta", p->disp.stats.meseta.load()); ret.emplace("Meseta", p->disp.stats.meseta.load());
auto tech_levels_json = JSON::dict(); auto tech_levels_json = phosg::JSON::dict();
for (size_t z = 0; z < 0x13; z++) { for (size_t z = 0; z < 0x13; z++) {
auto level = p->get_technique_level(z); auto level = p->get_technique_level(z);
tech_levels_json.emplace(name_for_technique(z), (level != 0xFF) ? level : JSON(nullptr)); tech_levels_json.emplace(name_for_technique(z), (level != 0xFF) ? level : phosg::JSON(nullptr));
} }
ret.emplace("TechniqueLevels", std::move(tech_levels_json)); ret.emplace("TechniqueLevels", std::move(tech_levels_json));
} }
ret.emplace("Height", p->disp.stats.height.load()); ret.emplace("Height", p->disp.stats.height.load());
ret.emplace("Level", p->disp.stats.level.load()); ret.emplace("Level", p->disp.stats.level.load());
ret.emplace("NameColor", p->disp.visual.name_color.load()); ret.emplace("NameColor", p->disp.visual.name_color.load());
ret.emplace("ExtraModel", (p->disp.visual.validation_flags & 2) ? p->disp.visual.extra_model : JSON(nullptr)); ret.emplace("ExtraModel", (p->disp.visual.validation_flags & 2) ? p->disp.visual.extra_model : phosg::JSON(nullptr));
ret.emplace("SectionID", name_for_section_id(p->disp.visual.section_id)); ret.emplace("SectionID", name_for_section_id(p->disp.visual.section_id));
ret.emplace("CharClass", name_for_char_class(p->disp.visual.section_id)); ret.emplace("CharClass", name_for_char_class(p->disp.visual.section_id));
ret.emplace("Costume", p->disp.visual.costume.load()); ret.emplace("Costume", p->disp.visual.costume.load());
@@ -631,7 +631,7 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
ret.emplace("AutoReply", p->auto_reply.decode(c->language())); ret.emplace("AutoReply", p->auto_reply.decode(c->language()));
ret.emplace("InfoBoard", p->info_board.decode(c->language())); ret.emplace("InfoBoard", p->info_board.decode(c->language()));
auto battle_place_counts = JSON::list({ auto battle_place_counts = phosg::JSON::list({
p->battle_records.place_counts[0].load(), p->battle_records.place_counts[0].load(),
p->battle_records.place_counts[1].load(), p->battle_records.place_counts[1].load(),
p->battle_records.place_counts[2].load(), p->battle_records.place_counts[2].load(),
@@ -641,8 +641,8 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
ret.emplace("BattleDisconnectCount", p->battle_records.disconnect_count.load()); ret.emplace("BattleDisconnectCount", p->battle_records.disconnect_count.load());
if (!is_ep3(c->version())) { if (!is_ep3(c->version())) {
auto json_for_challenge_times = []<size_t Count>(const parray<ChallengeTime, Count>& times) -> JSON { auto json_for_challenge_times = []<size_t Count>(const parray<ChallengeTime, Count>& times) -> phosg::JSON {
auto times_json = JSON::list(); auto times_json = phosg::JSON::list();
for (size_t z = 0; z < times.size(); z++) { for (size_t z = 0; z < times.size(); z++) {
times_json.emplace_back(times[z].decode()); times_json.emplace_back(times[z].decode());
} }
@@ -662,7 +662,7 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
uint8_t day = (p->challenge_records.grave_time >> 16) & 0xFF; uint8_t day = (p->challenge_records.grave_time >> 16) & 0xFF;
uint8_t hour = (p->challenge_records.grave_time >> 8) & 0xFF; uint8_t hour = (p->challenge_records.grave_time >> 8) & 0xFF;
uint8_t minute = p->challenge_records.grave_time & 0xFF; uint8_t minute = p->challenge_records.grave_time & 0xFF;
ret.emplace("ChallengeGraveTime", string_printf("%04hu-%02hhu-%02hhu %02hhu:%02hhu:00", year, month, day, hour, minute)); ret.emplace("ChallengeGraveTime", phosg::string_printf("%04hu-%02hhu-%02hhu %02hhu:%02hhu:00", year, month, day, hour, minute));
} }
string grave_enemy_types; string grave_enemy_types;
if (p->challenge_records.grave_defeated_by_enemy_rt_index) { if (p->challenge_records.grave_defeated_by_enemy_rt_index) {
@@ -670,7 +670,7 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
if (!grave_enemy_types.empty()) { if (!grave_enemy_types.empty()) {
grave_enemy_types += "/"; grave_enemy_types += "/";
} }
grave_enemy_types += name_for_enum(type); grave_enemy_types += phosg::name_for_enum(type);
} }
} }
ret.emplace("ChallengeGraveDefeatedByEnemy", std::move(grave_enemy_types)); ret.emplace("ChallengeGraveDefeatedByEnemy", std::move(grave_enemy_types));
@@ -691,7 +691,7 @@ JSON HTTPServer::generate_game_client_json_st(shared_ptr<const Client> c, shared
return ret; return ret;
} }
JSON HTTPServer::generate_proxy_client_json_st(shared_ptr<const ProxyServer::LinkedSession> ses) { phosg::JSON HTTPServer::generate_proxy_client_json_st(shared_ptr<const ProxyServer::LinkedSession> ses) {
struct LobbyPlayer { struct LobbyPlayer {
uint32_t guild_card_number = 0; uint32_t guild_card_number = 0;
uint64_t xb_user_id = 0; uint64_t xb_user_id = 0;
@@ -702,35 +702,35 @@ JSON HTTPServer::generate_proxy_client_json_st(shared_ptr<const ProxyServer::Lin
}; };
std::vector<LobbyPlayer> lobby_players; std::vector<LobbyPlayer> lobby_players;
auto lobby_players_json = JSON::list(); auto lobby_players_json = phosg::JSON::list();
for (size_t z = 0; z < ses->lobby_players.size(); z++) { for (size_t z = 0; z < ses->lobby_players.size(); z++) {
const auto& p = ses->lobby_players[z]; const auto& p = ses->lobby_players[z];
if (p.guild_card_number) { if (p.guild_card_number) {
lobby_players_json.emplace_back(JSON::dict({ lobby_players_json.emplace_back(phosg::JSON::dict({
{"GuildCardNumber", p.guild_card_number}, {"GuildCardNumber", p.guild_card_number},
{"Name", p.name}, {"Name", p.name},
{"Language", name_for_language_code(p.language)}, {"Language", name_for_language_code(p.language)},
{"SectionID", name_for_section_id(p.section_id)}, {"SectionID", name_for_section_id(p.section_id)},
{"CharClass", name_for_char_class(p.char_class)}, {"CharClass", name_for_char_class(p.char_class)},
})); }));
lobby_players_json.back().emplace("XBUserID", p.xb_user_id ? p.xb_user_id : JSON(nullptr)); lobby_players_json.back().emplace("XBUserID", p.xb_user_id ? p.xb_user_id : phosg::JSON(nullptr));
} else { } else {
lobby_players_json.emplace_back(nullptr); lobby_players_json.emplace_back(nullptr);
} }
} }
auto ret = JSON::dict({ auto ret = phosg::JSON::dict({
{"ID", ses->id}, {"ID", ses->id},
{"RemoteClientAddress", render_sockaddr_storage(ses->client_channel.remote_addr)}, {"RemoteClientAddress", phosg::render_sockaddr_storage(ses->client_channel.remote_addr)},
{"RemoteServerAddress", render_sockaddr_storage(ses->server_channel.remote_addr)}, {"RemoteServerAddress", phosg::render_sockaddr_storage(ses->server_channel.remote_addr)},
{"LocalPort", ses->local_port}, {"LocalPort", ses->local_port},
{"NextDestination", render_sockaddr_storage(ses->next_destination)}, {"NextDestination", phosg::render_sockaddr_storage(ses->next_destination)},
{"Version", name_for_enum(ses->version())}, {"Version", phosg::name_for_enum(ses->version())},
{"SubVersion", ses->sub_version}, {"SubVersion", ses->sub_version},
{"Name", ses->character_name}, {"Name", ses->character_name},
{"DCHardwareID", ses->hardware_id}, {"DCHardwareID", ses->hardware_id},
{"RemoteGuildCardNumber", ses->remote_guild_card_number}, {"RemoteGuildCardNumber", ses->remote_guild_card_number},
{"RemoteClientConfigData", format_data_string(&ses->remote_client_config_data[0], ses->remote_client_config_data.size())}, {"RemoteClientConfigData", phosg::format_data_string(&ses->remote_client_config_data[0], ses->remote_client_config_data.size())},
{"Config", HTTPServer::generate_client_config_json_st(ses->config)}, {"Config", HTTPServer::generate_client_config_json_st(ses->config)},
{"Language", name_for_language_code(ses->language())}, {"Language", name_for_language_code(ses->language())},
{"LobbyClientID", ses->lobby_client_id}, {"LobbyClientID", ses->lobby_client_id},
@@ -759,19 +759,19 @@ JSON HTTPServer::generate_proxy_client_json_st(shared_ptr<const ProxyServer::Lin
ret.emplace("DropMode", "proxy"); ret.emplace("DropMode", "proxy");
break; break;
} }
ret.emplace("Account", ses->login ? HTTPServer::generate_account_json_st(ses->login->account) : JSON(nullptr)); ret.emplace("Account", ses->login ? HTTPServer::generate_account_json_st(ses->login->account) : phosg::JSON(nullptr));
return ret; return ret;
} }
JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<const ItemNameIndex> item_name_index) { phosg::JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<const ItemNameIndex> item_name_index) {
std::array<std::shared_ptr<Client>, 12> clients; std::array<std::shared_ptr<Client>, 12> clients;
auto client_ids_json = JSON::list(); auto client_ids_json = phosg::JSON::list();
for (size_t z = 0; z < l->max_clients; z++) { for (size_t z = 0; z < l->max_clients; z++) {
client_ids_json.emplace_back(l->clients[z] ? l->clients[z]->id : JSON(nullptr)); client_ids_json.emplace_back(l->clients[z] ? l->clients[z]->id : phosg::JSON(nullptr));
} }
auto ret = JSON::dict({ auto ret = phosg::JSON::dict({
{"ID", l->lobby_id}, {"ID", l->lobby_id},
{"AllowedVersions", l->allowed_versions}, {"AllowedVersions", l->allowed_versions},
{"Event", l->event}, {"Event", l->event},
@@ -796,7 +796,7 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
ret.emplace("QuestSelectionInProgress", l->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS)); ret.emplace("QuestSelectionInProgress", l->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS));
ret.emplace("QuestInProgress", l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS)); ret.emplace("QuestInProgress", l->check_flag(Lobby::Flag::QUEST_IN_PROGRESS));
ret.emplace("JoinableQuestInProgress", l->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS)); ret.emplace("JoinableQuestInProgress", l->check_flag(Lobby::Flag::JOINABLE_QUEST_IN_PROGRESS));
auto variations_json = JSON::list(); auto variations_json = phosg::JSON::list();
for (size_t z = 0; z < l->variations.size(); z++) { for (size_t z = 0; z < l->variations.size(); z++) {
variations_json.emplace_back(l->variations[z].load()); variations_json.emplace_back(l->variations[z].load());
} }
@@ -839,11 +839,11 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
} }
} }
auto floor_items_json = JSON::list(); auto floor_items_json = phosg::JSON::list();
for (size_t floor = 0; floor < l->floor_item_managers.size(); floor++) { for (size_t floor = 0; floor < l->floor_item_managers.size(); floor++) {
for (const auto& it : l->floor_item_managers[floor].items) { for (const auto& it : l->floor_item_managers[floor].items) {
const auto& item = it.second; const auto& item = it.second;
auto item_dict = JSON::dict({ auto item_dict = phosg::JSON::dict({
{"LocationFloor", floor}, {"LocationFloor", floor},
{"LocationX", item->x}, {"LocationX", item->x},
{"LocationZ", item->z}, {"LocationZ", item->z},
@@ -868,7 +868,7 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
auto ep3s = l->ep3_server; auto ep3s = l->ep3_server;
if (ep3s) { if (ep3s) {
auto players_json = JSON::list(); auto players_json = phosg::JSON::list();
for (size_t z = 0; z < 4; z++) { for (size_t z = 0; z < 4; z++) {
if (!ep3s->name_entries[z].present) { if (!ep3s->name_entries[z].present) {
players_json.emplace_back(nullptr); players_json.emplace_back(nullptr);
@@ -876,9 +876,9 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
auto lc = l->clients[z]; auto lc = l->clients[z];
auto deck_entry = ep3s->deck_entries[z]; auto deck_entry = ep3s->deck_entries[z];
JSON deck_json = nullptr; phosg::JSON deck_json = nullptr;
if (deck_entry) { if (deck_entry) {
auto cards_json = JSON::list(); auto cards_json = phosg::JSON::list();
for (size_t w = 0; w < deck_entry->card_ids.size(); w++) { for (size_t w = 0; w < deck_entry->card_ids.size(); w++) {
try { try {
const auto& ce = ep3s->options.card_index->definition_for_id(deck_entry->card_ids[w]); const auto& ce = ep3s->options.card_index->definition_for_id(deck_entry->card_ids[w]);
@@ -897,7 +897,7 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
cards_json.emplace_back(deck_entry->card_ids[w].load()); cards_json.emplace_back(deck_entry->card_ids[w].load());
} }
} }
deck_json = JSON::dict({ deck_json = phosg::JSON::dict({
{"Name", deck_entry->name.decode(lc ? lc->language() : 1)}, {"Name", deck_entry->name.decode(lc ? lc->language() : 1)},
{"TeamID", deck_entry->team_id.load()}, {"TeamID", deck_entry->team_id.load()},
{"Cards", std::move(cards_json)}, {"Cards", std::move(cards_json)},
@@ -906,7 +906,7 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
}); });
} }
auto player_json = JSON::dict({ auto player_json = phosg::JSON::dict({
{"PlayerName", ep3s->name_entries[z].name.decode(lc ? lc->language() : 1)}, {"PlayerName", ep3s->name_entries[z].name.decode(lc ? lc->language() : 1)},
{"ClientID", ep3s->name_entries[z].client_id}, {"ClientID", ep3s->name_entries[z].client_id},
{"IsCOM", !!ep3s->name_entries[z].is_cpu_player}, {"IsCOM", !!ep3s->name_entries[z].is_cpu_player},
@@ -915,13 +915,13 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
players_json.emplace_back(std::move(player_json)); players_json.emplace_back(std::move(player_json));
} }
} }
auto battle_state_json = JSON::dict({ auto battle_state_json = phosg::JSON::dict({
{"BehaviorFlags", ep3s->options.behavior_flags}, {"BehaviorFlags", ep3s->options.behavior_flags},
{"RandomSeed", ep3s->options.opt_rand_crypt ? ep3s->options.opt_rand_crypt->seed() : JSON(nullptr)}, {"RandomSeed", ep3s->options.opt_rand_crypt ? ep3s->options.opt_rand_crypt->seed() : phosg::JSON(nullptr)},
{"RandomOffset", ep3s->options.opt_rand_crypt ? ep3s->options.opt_rand_crypt->absolute_offset() : JSON(nullptr)}, {"RandomOffset", ep3s->options.opt_rand_crypt ? ep3s->options.opt_rand_crypt->absolute_offset() : phosg::JSON(nullptr)},
{"Tournament", ep3s->options.tournament ? ep3s->options.tournament->json() : nullptr}, {"Tournament", ep3s->options.tournament ? ep3s->options.tournament->json() : nullptr},
{"MapNumber", ep3s->last_chosen_map ? ep3s->last_chosen_map->map_number : JSON(nullptr)}, {"MapNumber", ep3s->last_chosen_map ? ep3s->last_chosen_map->map_number : phosg::JSON(nullptr)},
{"EnvironmentNumber", ep3s->map_and_rules ? ep3s->map_and_rules->environment_number : JSON(nullptr)}, {"EnvironmentNumber", ep3s->map_and_rules ? ep3s->map_and_rules->environment_number : phosg::JSON(nullptr)},
{"Rules", ep3s->map_and_rules ? ep3s->map_and_rules->rules.json() : nullptr}, {"Rules", ep3s->map_and_rules ? ep3s->map_and_rules->rules.json() : nullptr},
{"Players", std::move(players_json)}, {"Players", std::move(players_json)},
{"IsBattleFinished", ep3s->battle_finished}, {"IsBattleFinished", ep3s->battle_finished},
@@ -929,13 +929,13 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
{"RoundNumber", ep3s->round_num}, {"RoundNumber", ep3s->round_num},
{"FirstTeamTurn", ep3s->first_team_turn}, {"FirstTeamTurn", ep3s->first_team_turn},
{"CurrentTeamTurn", ep3s->current_team_turn1}, {"CurrentTeamTurn", ep3s->current_team_turn1},
{"BattlePhase", name_for_enum(ep3s->battle_phase)}, {"BattlePhase", phosg::name_for_enum(ep3s->battle_phase)},
{"SetupPhase", ep3s->setup_phase}, {"SetupPhase", ep3s->setup_phase},
{"RegistrationPhase", ep3s->registration_phase}, {"RegistrationPhase", ep3s->registration_phase},
{"ActionSubphase", ep3s->action_subphase}, {"ActionSubphase", ep3s->action_subphase},
{"BattleStartTimeUsecs", ep3s->battle_start_usecs}, {"BattleStartTimeUsecs", ep3s->battle_start_usecs},
{"TeamEXP", JSON::list({ep3s->team_exp[0], ep3s->team_exp[1]})}, {"TeamEXP", phosg::JSON::list({ep3s->team_exp[0], ep3s->team_exp[1]})},
{"TeamDiceBonus", JSON::list({ep3s->team_dice_bonus[0], ep3s->team_dice_bonus[1]})}, {"TeamDiceBonus", phosg::JSON::list({ep3s->team_dice_bonus[0], ep3s->team_dice_bonus[1]})},
}); });
// std::shared_ptr<StateFlags> state_flags; // std::shared_ptr<StateFlags> state_flags;
// std::array<std::shared_ptr<PlayerState>, 4> player_states; // std::array<std::shared_ptr<PlayerState>, 4> player_states;
@@ -947,7 +947,7 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
if (watched_lobby) { if (watched_lobby) {
ret.emplace("WatchedLobbyID", watched_lobby->lobby_id); ret.emplace("WatchedLobbyID", watched_lobby->lobby_id);
} }
auto watcher_lobby_ids_json = JSON::list(); auto watcher_lobby_ids_json = phosg::JSON::list();
for (const auto& watcher_lobby : l->watcher_lobbies) { for (const auto& watcher_lobby : l->watcher_lobbies) {
watcher_lobby_ids_json.emplace_back(watcher_lobby->lobby_id); watcher_lobby_ids_json.emplace_back(watcher_lobby->lobby_id);
} }
@@ -964,9 +964,9 @@ JSON HTTPServer::generate_lobby_json_st(shared_ptr<const Lobby> l, shared_ptr<co
return ret; return ret;
} }
JSON HTTPServer::generate_game_server_clients_json() const { phosg::JSON HTTPServer::generate_game_server_clients_json() const {
return call_on_event_thread<JSON>(this->state->base, [&]() { return call_on_event_thread<phosg::JSON>(this->state->base, [&]() {
auto res = JSON::list(); auto res = phosg::JSON::list();
for (const auto& it : this->state->channel_to_client) { for (const auto& it : this->state->channel_to_client) {
res.emplace_back(this->generate_game_client_json_st(it.second, this->state->item_name_index_opt(it.second->version()))); res.emplace_back(this->generate_game_client_json_st(it.second, this->state->item_name_index_opt(it.second->version())));
} }
@@ -974,9 +974,9 @@ JSON HTTPServer::generate_game_server_clients_json() const {
}); });
} }
JSON HTTPServer::generate_proxy_server_clients_json() const { phosg::JSON HTTPServer::generate_proxy_server_clients_json() const {
return call_on_event_thread<JSON>(this->state->base, [&]() { return call_on_event_thread<phosg::JSON>(this->state->base, [&]() {
JSON res = JSON::list(); phosg::JSON res = phosg::JSON::list();
if (this->state->proxy_server) { if (this->state->proxy_server) {
for (const auto& it : this->state->proxy_server->all_sessions()) { for (const auto& it : this->state->proxy_server->all_sessions()) {
res.emplace_back(this->generate_proxy_client_json_st(it.second)); res.emplace_back(this->generate_proxy_client_json_st(it.second));
@@ -986,8 +986,8 @@ JSON HTTPServer::generate_proxy_server_clients_json() const {
}); });
} }
JSON HTTPServer::generate_server_info_json() const { phosg::JSON HTTPServer::generate_server_info_json() const {
return call_on_event_thread<JSON>(this->state->base, [&]() { return call_on_event_thread<phosg::JSON>(this->state->base, [&]() {
size_t game_count = 0; size_t game_count = 0;
size_t lobby_count = 0; size_t lobby_count = 0;
for (const auto& it : this->state->id_to_lobby) { for (const auto& it : this->state->id_to_lobby) {
@@ -997,12 +997,12 @@ JSON HTTPServer::generate_server_info_json() const {
lobby_count++; lobby_count++;
} }
} }
uint64_t uptime_usecs = now() - this->state->creation_time; uint64_t uptime_usecs = phosg::now() - this->state->creation_time;
return JSON::dict({ return phosg::JSON::dict({
{"StartTimeUsecs", this->state->creation_time}, {"StartTimeUsecs", this->state->creation_time},
{"StartTime", format_time(this->state->creation_time)}, {"StartTime", phosg::format_time(this->state->creation_time)},
{"UptimeUsecs", uptime_usecs}, {"UptimeUsecs", uptime_usecs},
{"Uptime", format_duration(uptime_usecs)}, {"Uptime", phosg::format_duration(uptime_usecs)},
{"LobbyCount", lobby_count}, {"LobbyCount", lobby_count},
{"GameCount", game_count}, {"GameCount", game_count},
{"ClientCount", this->state->channel_to_client.size()}, {"ClientCount", this->state->channel_to_client.size()},
@@ -1012,9 +1012,9 @@ JSON HTTPServer::generate_server_info_json() const {
}); });
} }
JSON HTTPServer::generate_lobbies_json() const { phosg::JSON HTTPServer::generate_lobbies_json() const {
return call_on_event_thread<JSON>(this->state->base, [&]() { return call_on_event_thread<phosg::JSON>(this->state->base, [&]() {
JSON res = JSON::list(); phosg::JSON res = phosg::JSON::list();
for (const auto& it : this->state->id_to_lobby) { for (const auto& it : this->state->id_to_lobby) {
res.emplace_back(this->generate_lobby_json_st(it.second, this->state->item_name_index_opt(it.second->base_version))); res.emplace_back(this->generate_lobby_json_st(it.second, this->state->item_name_index_opt(it.second->base_version)));
} }
@@ -1022,46 +1022,46 @@ JSON HTTPServer::generate_lobbies_json() const {
}); });
} }
JSON HTTPServer::generate_summary_json() const { phosg::JSON HTTPServer::generate_summary_json() const {
auto ret = call_on_event_thread<JSON>(this->state->base, [&]() { auto ret = call_on_event_thread<phosg::JSON>(this->state->base, [&]() {
auto clients_json = JSON::list(); auto clients_json = phosg::JSON::list();
for (const auto& it : this->state->channel_to_client) { for (const auto& it : this->state->channel_to_client) {
auto c = it.second; auto c = it.second;
auto p = c->character(false, false); auto p = c->character(false, false);
auto l = c->lobby.lock(); auto l = c->lobby.lock();
clients_json.emplace_back(JSON::dict({ clients_json.emplace_back(phosg::JSON::dict({
{"ID", c->id}, {"ID", c->id},
{"AccountID", c->login ? c->login->account->account_id : JSON(nullptr)}, {"AccountID", c->login ? c->login->account->account_id : phosg::JSON(nullptr)},
{"Name", p ? p->disp.name.decode(it.second->language()) : JSON(nullptr)}, {"Name", p ? p->disp.name.decode(it.second->language()) : phosg::JSON(nullptr)},
{"Version", name_for_enum(it.second->version())}, {"Version", phosg::name_for_enum(it.second->version())},
{"Language", name_for_language_code(it.second->language())}, {"Language", name_for_language_code(it.second->language())},
{"Level", p ? p->disp.stats.level + 1 : JSON(nullptr)}, {"Level", p ? p->disp.stats.level + 1 : phosg::JSON(nullptr)},
{"Class", p ? name_for_char_class(p->disp.visual.char_class) : JSON(nullptr)}, {"Class", p ? name_for_char_class(p->disp.visual.char_class) : phosg::JSON(nullptr)},
{"SectionID", p ? name_for_section_id(p->disp.visual.section_id) : JSON(nullptr)}, {"SectionID", p ? name_for_section_id(p->disp.visual.section_id) : phosg::JSON(nullptr)},
{"LobbyID", l ? l->lobby_id : JSON(nullptr)}, {"LobbyID", l ? l->lobby_id : phosg::JSON(nullptr)},
})); }));
} }
auto proxy_clients_json = JSON::list(); auto proxy_clients_json = phosg::JSON::list();
if (this->state->proxy_server) { if (this->state->proxy_server) {
for (const auto& it : this->state->proxy_server->all_sessions()) { for (const auto& it : this->state->proxy_server->all_sessions()) {
proxy_clients_json.emplace_back(JSON::dict({ proxy_clients_json.emplace_back(phosg::JSON::dict({
{"AccountID", it.second->login ? it.second->login->account->account_id : JSON(nullptr)}, {"AccountID", it.second->login ? it.second->login->account->account_id : phosg::JSON(nullptr)},
{"Name", it.second->character_name}, {"Name", it.second->character_name},
{"Version", name_for_enum(it.second->version())}, {"Version", phosg::name_for_enum(it.second->version())},
{"Language", name_for_language_code(it.second->language())}, {"Language", name_for_language_code(it.second->language())},
})); }));
} }
} }
auto games_json = JSON::list(); auto games_json = phosg::JSON::list();
for (const auto& it : this->state->id_to_lobby) { for (const auto& it : this->state->id_to_lobby) {
auto l = it.second; auto l = it.second;
if (l->is_game()) { if (l->is_game()) {
auto game_json = JSON::dict({ auto game_json = phosg::JSON::dict({
{"ID", l->lobby_id}, {"ID", l->lobby_id},
{"Name", l->name}, {"Name", l->name},
{"BaseVersion", name_for_enum(l->base_version)}, {"BaseVersion", phosg::name_for_enum(l->base_version)},
{"Players", l->count_clients()}, {"Players", l->count_clients()},
{"CheatsEnabled", l->check_flag(Lobby::Flag::CHEATS_ENABLED)}, {"CheatsEnabled", l->check_flag(Lobby::Flag::CHEATS_ENABLED)},
{"Episode", name_for_episode(l->episode)}, {"Episode", name_for_episode(l->episode)},
@@ -1071,7 +1071,7 @@ JSON HTTPServer::generate_summary_json() const {
auto ep3s = l->ep3_server; auto ep3s = l->ep3_server;
game_json.emplace("BattleInProgress", l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS)); game_json.emplace("BattleInProgress", l->check_flag(Lobby::Flag::BATTLE_IN_PROGRESS));
game_json.emplace("IsSpectatorTeam", l->check_flag(Lobby::Flag::IS_SPECTATOR_TEAM)); game_json.emplace("IsSpectatorTeam", l->check_flag(Lobby::Flag::IS_SPECTATOR_TEAM));
game_json.emplace("MapNumber", (ep3s && ep3s->last_chosen_map) ? ep3s->last_chosen_map->map_number : JSON(nullptr)); game_json.emplace("MapNumber", (ep3s && ep3s->last_chosen_map) ? ep3s->last_chosen_map->map_number : phosg::JSON(nullptr));
game_json.emplace("Rules", (ep3s && ep3s->map_and_rules) ? ep3s->map_and_rules->rules.json() : nullptr); game_json.emplace("Rules", (ep3s && ep3s->map_and_rules) ? ep3s->map_and_rules->rules.json() : nullptr);
} else { } else {
game_json.emplace("QuestSelectionInProgress", l->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS)); game_json.emplace("QuestSelectionInProgress", l->check_flag(Lobby::Flag::QUEST_SELECTION_IN_PROGRESS));
@@ -1086,7 +1086,7 @@ JSON HTTPServer::generate_summary_json() const {
} }
} }
return JSON::dict({ return phosg::JSON::dict({
{"Clients", std::move(clients_json)}, {"Clients", std::move(clients_json)},
{"ProxyClients", std::move(proxy_clients_json)}, {"ProxyClients", std::move(proxy_clients_json)},
{"Games", std::move(games_json)}, {"Games", std::move(games_json)},
@@ -1096,8 +1096,8 @@ JSON HTTPServer::generate_summary_json() const {
return ret; return ret;
} }
JSON HTTPServer::generate_all_json() const { phosg::JSON HTTPServer::generate_all_json() const {
return JSON::dict({ return phosg::JSON::dict({
{"Clients", this->generate_game_server_clients_json()}, {"Clients", this->generate_game_server_clients_json()},
{"ProxyClients", this->generate_proxy_server_clients_json()}, {"ProxyClients", this->generate_proxy_server_clients_json()},
{"Lobbies", this->generate_lobbies_json()}, {"Lobbies", this->generate_lobbies_json()},
@@ -1105,43 +1105,43 @@ JSON HTTPServer::generate_all_json() const {
}); });
} }
JSON HTTPServer::generate_ep3_cards_json(bool trial) const { phosg::JSON HTTPServer::generate_ep3_cards_json(bool trial) const {
auto index = call_on_event_thread<shared_ptr<const Episode3::CardIndex>>(this->state->base, [&]() { auto index = call_on_event_thread<shared_ptr<const Episode3::CardIndex>>(this->state->base, [&]() {
return trial ? this->state->ep3_card_index_trial : this->state->ep3_card_index; return trial ? this->state->ep3_card_index_trial : this->state->ep3_card_index;
}); });
return index->definitions_json(); return index->definitions_json();
} }
JSON HTTPServer::generate_common_tables_json() const { phosg::JSON HTTPServer::generate_common_tables_json() const {
auto [set_v2, set_v3_v4] = call_on_event_thread<pair<shared_ptr<const CommonItemSet>, shared_ptr<const CommonItemSet>>>(this->state->base, [&]() { auto [set_v2, set_v3_v4] = call_on_event_thread<pair<shared_ptr<const CommonItemSet>, shared_ptr<const CommonItemSet>>>(this->state->base, [&]() {
return make_pair(this->state->common_item_set_v2, this->state->common_item_set_v3_v4); return make_pair(this->state->common_item_set_v2, this->state->common_item_set_v3_v4);
}); });
return JSON::dict({{"v1_v2", set_v2->json()}, {"v3_v4", set_v3_v4->json()}}); return phosg::JSON::dict({{"v1_v2", set_v2->json()}, {"v3_v4", set_v3_v4->json()}});
} }
JSON HTTPServer::generate_rare_tables_json() const { phosg::JSON HTTPServer::generate_rare_tables_json() const {
auto sets = call_on_event_thread<unordered_map<string, shared_ptr<const RareItemSet>>>(this->state->base, [&]() { auto sets = call_on_event_thread<unordered_map<string, shared_ptr<const RareItemSet>>>(this->state->base, [&]() {
return this->state->rare_item_sets; return this->state->rare_item_sets;
}); });
JSON ret = JSON::list(); phosg::JSON ret = phosg::JSON::list();
for (const auto& it : sets) { for (const auto& it : sets) {
ret.emplace_back(it.first); ret.emplace_back(it.first);
} }
return ret; return ret;
} }
JSON HTTPServer::generate_rare_table_json(const std::string& table_name) const { phosg::JSON HTTPServer::generate_rare_table_json(const std::string& table_name) const {
try { try {
auto colls = call_on_event_thread<pair<shared_ptr<const RareItemSet>, shared_ptr<const ItemNameIndex>>>(this->state->base, [&]() { auto colls = call_on_event_thread<pair<shared_ptr<const RareItemSet>, shared_ptr<const ItemNameIndex>>>(this->state->base, [&]() {
const auto& table = this->state->rare_item_sets.at(table_name); const auto& table = this->state->rare_item_sets.at(table_name);
shared_ptr<const ItemNameIndex> name_index; shared_ptr<const ItemNameIndex> name_index;
if (ends_with(table_name, "-v1")) { if (phosg::ends_with(table_name, "-v1")) {
name_index = this->state->item_name_index_opt(Version::DC_V1); name_index = this->state->item_name_index_opt(Version::DC_V1);
} else if (ends_with(table_name, "-v2")) { } else if (phosg::ends_with(table_name, "-v2")) {
name_index = this->state->item_name_index_opt(Version::PC_V2); name_index = this->state->item_name_index_opt(Version::PC_V2);
} else if (ends_with(table_name, "-v3")) { } else if (phosg::ends_with(table_name, "-v3")) {
name_index = this->state->item_name_index_opt(Version::GC_V3); name_index = this->state->item_name_index_opt(Version::GC_V3);
} else if (ends_with(table_name, "-v4")) { } else if (phosg::ends_with(table_name, "-v4")) {
name_index = this->state->item_name_index_opt(Version::BB_V4); name_index = this->state->item_name_index_opt(Version::BB_V4);
} }
return make_pair(table, name_index); return make_pair(table, name_index);
@@ -1153,9 +1153,9 @@ JSON HTTPServer::generate_rare_table_json(const std::string& table_name) const {
} }
void HTTPServer::handle_request(struct evhttp_request* req) { void HTTPServer::handle_request(struct evhttp_request* req) {
shared_ptr<const JSON> ret; shared_ptr<const phosg::JSON> ret;
uint32_t serialize_options = 0; uint32_t serialize_options = 0;
uint64_t start_time = now(); uint64_t start_time = phosg::now();
string uri = evhttp_request_get_uri(req); string uri = evhttp_request_get_uri(req);
try { try {
@@ -1168,14 +1168,14 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
static const string default_format_option = "false"; static const string default_format_option = "false";
if (this->get_url_param(query, "format", &default_format_option) == "true") { if (this->get_url_param(query, "format", &default_format_option) == "true") {
serialize_options |= JSON::SerializeOption::FORMAT | JSON::SerializeOption::SORT_DICT_KEYS; serialize_options |= phosg::JSON::SerializeOption::FORMAT | phosg::JSON::SerializeOption::SORT_DICT_KEYS;
} }
if (this->get_url_param(query, "hex", &default_format_option) == "true") { if (this->get_url_param(query, "hex", &default_format_option) == "true") {
serialize_options |= JSON::SerializeOption::HEX_INTEGERS; serialize_options |= phosg::JSON::SerializeOption::HEX_INTEGERS;
} }
if (uri == "/") { if (uri == "/") {
auto endpoints_json = JSON::list({ auto endpoints_json = phosg::JSON::list({
"/y/data/ep3-cards", "/y/data/ep3-cards",
"/y/data/ep3-cards-trial", "/y/data/ep3-cards-trial",
"/y/data/common-tables", "/y/data/common-tables",
@@ -1190,7 +1190,7 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
"/y/summary", "/y/summary",
"/y/all", "/y/all",
}); });
ret = make_shared<JSON>(JSON::dict({{"endpoints", std::move(endpoints_json)}})); ret = make_shared<phosg::JSON>(phosg::JSON::dict({{"endpoints", std::move(endpoints_json)}}));
} else if (uri == "/y/rare-drops/stream") { } else if (uri == "/y/rare-drops/stream") {
auto c = this->enable_websockets(req); auto c = this->enable_websockets(req);
@@ -1198,35 +1198,35 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
throw http_error(400, "this path requires a websocket connection"); throw http_error(400, "this path requires a websocket connection");
} else { } else {
this->rare_drop_subscribers.emplace(c); this->rare_drop_subscribers.emplace(c);
auto version_message = JSON::dict({{"ServerType", "newserv"}}); auto version_message = phosg::JSON::dict({{"ServerType", "newserv"}});
this->send_websocket_message(c, version_message.serialize()); this->send_websocket_message(c, version_message.serialize());
return; return;
} }
} else if (uri == "/y/data/ep3-cards") { } else if (uri == "/y/data/ep3-cards") {
ret = make_shared<JSON>(this->generate_ep3_cards_json(false)); ret = make_shared<phosg::JSON>(this->generate_ep3_cards_json(false));
} else if (uri == "/y/data/ep3-cards-trial") { } else if (uri == "/y/data/ep3-cards-trial") {
ret = make_shared<JSON>(this->generate_ep3_cards_json(true)); ret = make_shared<phosg::JSON>(this->generate_ep3_cards_json(true));
} else if (uri == "/y/data/common-tables") { } else if (uri == "/y/data/common-tables") {
ret = make_shared<JSON>(this->generate_common_tables_json()); ret = make_shared<phosg::JSON>(this->generate_common_tables_json());
} else if (uri == "/y/data/rare-tables") { } else if (uri == "/y/data/rare-tables") {
ret = make_shared<JSON>(this->generate_rare_tables_json()); ret = make_shared<phosg::JSON>(this->generate_rare_tables_json());
} else if (!strncmp(uri.c_str(), "/y/data/rare-tables/", 20)) { } else if (!strncmp(uri.c_str(), "/y/data/rare-tables/", 20)) {
ret = make_shared<JSON>(this->generate_rare_table_json(uri.substr(20))); ret = make_shared<phosg::JSON>(this->generate_rare_table_json(uri.substr(20)));
} else if (uri == "/y/data/config") { } else if (uri == "/y/data/config") {
ret = call_on_event_thread<shared_ptr<const JSON>>(this->state->base, [this]() { return this->state->config_json; }); ret = call_on_event_thread<shared_ptr<const phosg::JSON>>(this->state->base, [this]() { return this->state->config_json; });
} else if (uri == "/y/clients") { } else if (uri == "/y/clients") {
ret = make_shared<JSON>(this->generate_game_server_clients_json()); ret = make_shared<phosg::JSON>(this->generate_game_server_clients_json());
} else if (uri == "/y/proxy-clients") { } else if (uri == "/y/proxy-clients") {
ret = make_shared<JSON>(this->generate_proxy_server_clients_json()); ret = make_shared<phosg::JSON>(this->generate_proxy_server_clients_json());
} else if (uri == "/y/lobbies") { } else if (uri == "/y/lobbies") {
ret = make_shared<JSON>(this->generate_lobbies_json()); ret = make_shared<phosg::JSON>(this->generate_lobbies_json());
} else if (uri == "/y/server") { } else if (uri == "/y/server") {
ret = make_shared<JSON>(this->generate_server_info_json()); ret = make_shared<phosg::JSON>(this->generate_server_info_json());
} else if (uri == "/y/summary") { } else if (uri == "/y/summary") {
ret = make_shared<JSON>(this->generate_summary_json()); ret = make_shared<phosg::JSON>(this->generate_summary_json());
} else if (uri == "/y/all") { } else if (uri == "/y/all") {
ret = make_shared<JSON>(this->generate_all_json()); ret = make_shared<phosg::JSON>(this->generate_all_json());
} else { } else {
throw http_error(404, "unknown action"); throw http_error(404, "unknown action");
@@ -1246,20 +1246,20 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
return; return;
} }
uint64_t handler_end = now(); uint64_t handler_end = phosg::now();
unique_ptr<struct evbuffer, void (*)(struct evbuffer*)> out_buffer(evbuffer_new(), evbuffer_free); unique_ptr<struct evbuffer, void (*)(struct evbuffer*)> out_buffer(evbuffer_new(), evbuffer_free);
string* serialized = new string(ret->serialize(JSON::SerializeOption::ESCAPE_CONTROLS_ONLY | serialize_options)); string* serialized = new string(ret->serialize(phosg::JSON::SerializeOption::ESCAPE_CONTROLS_ONLY | serialize_options));
size_t size = serialized->size(); size_t size = serialized->size();
uint64_t serialize_end = now(); uint64_t serialize_end = phosg::now();
auto cleanup = +[](const void*, size_t, void* s) -> void { auto cleanup = +[](const void*, size_t, void* s) -> void {
delete reinterpret_cast<string*>(s); delete reinterpret_cast<string*>(s);
}; };
evbuffer_add_reference(out_buffer.get(), serialized->data(), serialized->size(), cleanup, serialized); evbuffer_add_reference(out_buffer.get(), serialized->data(), serialized->size(), cleanup, serialized);
this->send_response(req, 200, "application/json", out_buffer.get()); this->send_response(req, 200, "application/json", out_buffer.get());
string handler_time = format_duration(handler_end - start_time); string handler_time = phosg::format_duration(handler_end - start_time);
string serialize_time = format_duration(serialize_end - handler_end); string serialize_time = phosg::format_duration(serialize_end - handler_end);
string size_str = format_size(size); string size_str = phosg::format_size(size);
server_log.info("[HTTPServer] %s in [handler: %s, serialize: %s, size: %s]", server_log.info("[HTTPServer] %s in [handler: %s, serialize: %s, size: %s]",
uri.c_str(), handler_time.c_str(), serialize_time.c_str(), size_str.c_str()); uri.c_str(), handler_time.c_str(), serialize_time.c_str(), size_str.c_str());
} }
+17 -17
View File
@@ -28,7 +28,7 @@ public:
void schedule_stop(); void schedule_stop();
void wait_for_stop(); void wait_for_stop();
void send_rare_drop_notification(std::shared_ptr<const JSON> message); void send_rare_drop_notification(std::shared_ptr<const phosg::JSON> message);
protected: protected:
class http_error : public std::runtime_error { class http_error : public std::runtime_error {
@@ -94,21 +94,21 @@ protected:
const std::string& key, const std::string& key,
const std::string* _default = nullptr); const std::string* _default = nullptr);
static JSON generate_quest_json_st(std::shared_ptr<const Quest> q); static phosg::JSON generate_quest_json_st(std::shared_ptr<const Quest> q);
static JSON generate_client_config_json_st(const Client::Config& config); static phosg::JSON generate_client_config_json_st(const Client::Config& config);
static JSON generate_account_json_st(std::shared_ptr<const Account> a); static phosg::JSON generate_account_json_st(std::shared_ptr<const Account> a);
static JSON generate_game_client_json_st(std::shared_ptr<const Client> c, std::shared_ptr<const ItemNameIndex> item_name_index); static phosg::JSON generate_game_client_json_st(std::shared_ptr<const Client> c, std::shared_ptr<const ItemNameIndex> item_name_index);
static JSON generate_proxy_client_json_st(std::shared_ptr<const ProxyServer::LinkedSession> ses); static phosg::JSON generate_proxy_client_json_st(std::shared_ptr<const ProxyServer::LinkedSession> ses);
static JSON generate_lobby_json_st(std::shared_ptr<const Lobby> l, std::shared_ptr<const ItemNameIndex> item_name_index); static phosg::JSON generate_lobby_json_st(std::shared_ptr<const Lobby> l, std::shared_ptr<const ItemNameIndex> item_name_index);
JSON generate_game_server_clients_json() const; phosg::JSON generate_game_server_clients_json() const;
JSON generate_proxy_server_clients_json() const; phosg::JSON generate_proxy_server_clients_json() const;
JSON generate_server_info_json() const; phosg::JSON generate_server_info_json() const;
JSON generate_lobbies_json() const; phosg::JSON generate_lobbies_json() const;
JSON generate_summary_json() const; phosg::JSON generate_summary_json() const;
JSON generate_all_json() const; phosg::JSON generate_all_json() const;
JSON generate_ep3_cards_json(bool trial) const; phosg::JSON generate_ep3_cards_json(bool trial) const;
JSON generate_common_tables_json() const; phosg::JSON generate_common_tables_json() const;
JSON generate_rare_tables_json() const; phosg::JSON generate_rare_tables_json() const;
JSON generate_rare_table_json(const std::string& table_name) const; phosg::JSON generate_rare_table_json(const std::string& table_name) const;
}; };
+10 -10
View File
@@ -23,7 +23,7 @@ FrameInfo::FrameInfo(LinkType link_type, const void* header_start, size_t size)
this->total_size = size; this->total_size = size;
this->payload_size = size; this->payload_size = size;
StringReader r(header_start, size); phosg::StringReader r(header_start, size);
// Parse link-layer header // Parse link-layer header
Protocol proto = Protocol::NONE; Protocol proto = Protocol::NONE;
@@ -126,35 +126,35 @@ string FrameInfo::header_str() const {
string ret; string ret;
if (this->ether) { if (this->ether) {
ret = string_printf( ret = phosg::string_printf(
"ETHER:%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX->%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", "ETHER:%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX->%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
this->ether->src_mac[0], this->ether->src_mac[1], this->ether->src_mac[2], this->ether->src_mac[0], this->ether->src_mac[1], this->ether->src_mac[2],
this->ether->src_mac[3], this->ether->src_mac[4], this->ether->src_mac[5], this->ether->src_mac[3], this->ether->src_mac[4], this->ether->src_mac[5],
this->ether->dest_mac[0], this->ether->dest_mac[1], this->ether->dest_mac[2], this->ether->dest_mac[0], this->ether->dest_mac[1], this->ether->dest_mac[2],
this->ether->dest_mac[3], this->ether->dest_mac[4], this->ether->dest_mac[5]); this->ether->dest_mac[3], this->ether->dest_mac[4], this->ether->dest_mac[5]);
} else if (this->hdlc) { } else if (this->hdlc) {
ret = string_printf("HDLC:%02hhX/%02hhX", this->hdlc->address, this->hdlc->control); ret = phosg::string_printf("HDLC:%02hhX/%02hhX", this->hdlc->address, this->hdlc->control);
} else { } else {
return "<invalid-frame-info>"; return "<invalid-frame-info>";
} }
if (this->arp) { if (this->arp) {
ret += string_printf( ret += phosg::string_printf(
",ARP,hw_type=%04hX,proto_type=%04hX,hw_addr_len=%02hhX,proto_addr_len=%02hhX,op=%04hX", ",ARP,hw_type=%04hX,proto_type=%04hX,hw_addr_len=%02hhX,proto_addr_len=%02hhX,op=%04hX",
this->arp->hardware_type.load(), this->arp->protocol_type.load(), this->arp->hwaddr_len, this->arp->paddr_len, this->arp->operation.load()); this->arp->hardware_type.load(), this->arp->protocol_type.load(), this->arp->hwaddr_len, this->arp->paddr_len, this->arp->operation.load());
} else if (this->ipv4) { } else if (this->ipv4) {
ret += string_printf( ret += phosg::string_printf(
",IPv4,size=%04hX,src=%08" PRIX32 ",dest=%08" PRIX32, ",IPv4,size=%04hX,src=%08" PRIX32 ",dest=%08" PRIX32,
this->ipv4->size.load(), this->ipv4->src_addr.load(), this->ipv4->dest_addr.load()); this->ipv4->size.load(), this->ipv4->src_addr.load(), this->ipv4->dest_addr.load());
if (this->udp) { if (this->udp) {
ret += string_printf( ret += phosg::string_printf(
",UDP,src_port=%04hX,dest_port=%04hX,size=%04hX", ",UDP,src_port=%04hX,dest_port=%04hX,size=%04hX",
this->udp->src_port.load(), this->udp->dest_port.load(), this->udp->size.load()); this->udp->src_port.load(), this->udp->dest_port.load(), this->udp->size.load());
} else if (this->tcp) { } else if (this->tcp) {
ret += string_printf( ret += phosg::string_printf(
",TCP,src_port=%04hX,dest_port=%04hX,seq=%08" PRIX32 ",ack=%08" PRIX32 ",flags=%04hX(", ",TCP,src_port=%04hX,dest_port=%04hX,seq=%08" PRIX32 ",ack=%08" PRIX32 ",flags=%04hX(",
this->tcp->src_port.load(), this->tcp->dest_port.load(), this->tcp->seq_num.load(), this->tcp->ack_num.load(), this->tcp->flags.load()); this->tcp->src_port.load(), this->tcp->dest_port.load(), this->tcp->seq_num.load(), this->tcp->ack_num.load(), this->tcp->flags.load());
if (this->tcp->flags & TCPHeader::Flag::FIN) { if (this->tcp->flags & TCPHeader::Flag::FIN) {
@@ -175,14 +175,14 @@ string FrameInfo::header_str() const {
ret += ')'; ret += ')';
} else { } else {
ret += string_printf(",proto=%02hhX", this->ipv4->protocol); ret += phosg::string_printf(",proto=%02hhX", this->ipv4->protocol);
} }
} else { } else {
if (this->ether) { if (this->ether) {
ret += string_printf(",proto=%04hX", this->ether->protocol.load()); ret += phosg::string_printf(",proto=%04hX", this->ether->protocol.load());
} else if (this->hdlc) { } else if (this->hdlc) {
ret += string_printf(",proto=%04hX", this->hdlc->protocol.load()); ret += phosg::string_printf(",proto=%04hX", this->hdlc->protocol.load());
} }
} }
+2 -2
View File
@@ -161,8 +161,8 @@ struct FrameInfo {
std::string header_str() const; std::string header_str() const;
inline StringReader read_payload() const { inline phosg::StringReader read_payload() const {
return StringReader(this->payload, this->payload_size); return phosg::StringReader(this->payload, this->payload_size);
} }
void truncate(size_t new_total_size); void truncate(size_t new_total_size);
+50 -51
View File
@@ -22,7 +22,7 @@ using namespace std;
static const size_t DEFAULT_RESEND_PUSH_USECS = 200000; // 200ms static const size_t DEFAULT_RESEND_PUSH_USECS = 200000; // 200ms
static string unescape_hdlc_frame(const void* data, size_t size) { static string unescape_hdlc_frame(const void* data, size_t size) {
StringReader r(data, size); phosg::StringReader r(data, size);
if (r.get_u8(data) != 0x7E) { if (r.get_u8(data) != 0x7E) {
throw runtime_error("HDLC frame does not begin with 7E"); throw runtime_error("HDLC frame does not begin with 7E");
} }
@@ -53,7 +53,7 @@ static string escape_hdlc_frame(const void* data, size_t size, uint32_t escape_c
throw runtime_error("HDLC frame too small for start and end sentinels"); throw runtime_error("HDLC frame too small for start and end sentinels");
} }
StringReader r(data, size); phosg::StringReader r(data, size);
if (r.pget_u8(size - 1) != 0x7E) { if (r.pget_u8(size - 1) != 0x7E) {
throw runtime_error("HDLC frame does not end with 7E"); throw runtime_error("HDLC frame does not end with 7E");
} }
@@ -104,9 +104,9 @@ string IPStackSimulator::str_for_ipv4_netloc(uint32_t addr, uint16_t port) {
be_uint32_t be_addr = addr; be_uint32_t be_addr = addr;
char addr_str[INET_ADDRSTRLEN]; char addr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &be_addr, addr_str, INET_ADDRSTRLEN)) { if (!inet_ntop(AF_INET, &be_addr, addr_str, INET_ADDRSTRLEN)) {
return string_printf("<UNKNOWN>:%hu", port); return phosg::string_printf("<UNKNOWN>:%hu", port);
} else { } else {
return string_printf("%s:%hu", addr_str, port); return phosg::string_printf("%s:%hu", addr_str, port);
} }
} }
@@ -115,7 +115,7 @@ string IPStackSimulator::str_for_tcp_connection(shared_ptr<const IPClient> c, co
string server_netloc_str = str_for_ipv4_netloc(conn.server_addr, conn.server_port); string server_netloc_str = str_for_ipv4_netloc(conn.server_addr, conn.server_port);
string client_netloc_str = str_for_ipv4_netloc(c->ipv4_addr, conn.client_port); string client_netloc_str = str_for_ipv4_netloc(c->ipv4_addr, conn.client_port);
int fd = bufferevent_getfd(c->bev.get()); int fd = bufferevent_getfd(c->bev.get());
return string_printf("%d+%016" PRIX64 " (%s -> %s)", return phosg::string_printf("%d+%016" PRIX64 " (%s -> %s)",
fd, key, client_netloc_str.c_str(), server_netloc_str.c_str()); fd, key, client_netloc_str.c_str(), server_netloc_str.c_str());
} }
@@ -137,7 +137,7 @@ IPStackSimulator::~IPStackSimulator() {
} }
void IPStackSimulator::listen(const string& name, const string& socket_path, Protocol proto) { void IPStackSimulator::listen(const string& name, const string& socket_path, Protocol proto) {
int fd = ::listen(socket_path, 0, SOMAXCONN); int fd = phosg::listen(socket_path, 0, SOMAXCONN);
ip_stack_simulator_log.info("Listening on Unix socket %s on fd %d as %s", socket_path.c_str(), fd, name.c_str()); ip_stack_simulator_log.info("Listening on Unix socket %s on fd %d as %s", socket_path.c_str(), fd, name.c_str());
this->add_socket(name, fd, proto); this->add_socket(name, fd, proto);
} }
@@ -146,8 +146,8 @@ void IPStackSimulator::listen(const string& name, const string& addr, int port,
if (port == 0) { if (port == 0) {
this->listen(name, addr, proto); this->listen(name, addr, proto);
} else { } else {
int fd = ::listen(addr, port, SOMAXCONN); int fd = phosg::listen(addr, port, SOMAXCONN);
string netloc_str = render_netloc(addr, port); string netloc_str = phosg::render_netloc(addr, port);
ip_stack_simulator_log.info("Listening on TCP interface %s on fd %d as %s", netloc_str.c_str(), fd, name.c_str()); ip_stack_simulator_log.info("Listening on TCP interface %s on fd %d as %s", netloc_str.c_str(), fd, name.c_str());
this->add_socket(name, fd, proto); this->add_socket(name, fd, proto);
} }
@@ -195,7 +195,7 @@ IPStackSimulator::IPClient::IPClient(
ipv4_addr(0), ipv4_addr(0),
idle_timeout_event(event_new(sim->base.get(), -1, EV_TIMEOUT, &IPStackSimulator::IPClient::dispatch_on_idle_timeout, this), event_free) { idle_timeout_event(event_new(sim->base.get(), -1, EV_TIMEOUT, &IPStackSimulator::IPClient::dispatch_on_idle_timeout, this), event_free) {
uint64_t idle_timeout_usecs = sim->state->client_idle_timeout_usecs; uint64_t idle_timeout_usecs = sim->state->client_idle_timeout_usecs;
struct timeval tv = usecs_to_timeval(idle_timeout_usecs); struct timeval tv = phosg::usecs_to_timeval(idle_timeout_usecs);
event_add(this->idle_timeout_event.get(), &tv); event_add(this->idle_timeout_event.get(), &tv);
} }
@@ -247,7 +247,7 @@ void IPStackSimulator::dispatch_on_listen_accept(
void IPStackSimulator::on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr*, int) { void IPStackSimulator::on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr*, int) {
struct sockaddr_storage remote_addr; struct sockaddr_storage remote_addr;
get_socket_addresses(fd, nullptr, &remote_addr); phosg::get_socket_addresses(fd, nullptr, &remote_addr);
if (this->state->banned_ipv4_ranges->check(remote_addr)) { if (this->state->banned_ipv4_ranges->check(remote_addr)) {
close(fd); close(fd);
return; return;
@@ -304,7 +304,7 @@ void IPStackSimulator::IPClient::on_client_input(struct bufferevent* bev) {
} }
uint64_t idle_timeout_usecs = sim ? sim->state->client_idle_timeout_usecs : 60000000; uint64_t idle_timeout_usecs = sim ? sim->state->client_idle_timeout_usecs : 60000000;
struct timeval tv = usecs_to_timeval(idle_timeout_usecs); struct timeval tv = phosg::usecs_to_timeval(idle_timeout_usecs);
event_add(this->idle_timeout_event.get(), &tv); event_add(this->idle_timeout_event.get(), &tv);
switch (this->protocol) { switch (this->protocol) {
@@ -325,7 +325,7 @@ void IPStackSimulator::IPClient::on_client_input(struct bufferevent* bev) {
sim->on_client_frame(this->shared_from_this(), frame); sim->on_client_frame(this->shared_from_this(), frame);
} catch (const exception& e) { } catch (const exception& e) {
if (ip_stack_simulator_log.warning("Failed to process frame: %s", e.what())) { if (ip_stack_simulator_log.warning("Failed to process frame: %s", e.what())) {
print_data(stderr, frame); phosg::print_data(stderr, frame);
} }
} }
} }
@@ -360,7 +360,7 @@ void IPStackSimulator::IPClient::on_client_input(struct bufferevent* bev) {
sim->on_client_frame(this->shared_from_this(), frame); sim->on_client_frame(this->shared_from_this(), frame);
} catch (const exception& e) { } catch (const exception& e) {
if (ip_stack_simulator_log.warning("Failed to process frame: %s", e.what())) { if (ip_stack_simulator_log.warning("Failed to process frame: %s", e.what())) {
print_data(stderr, frame); phosg::print_data(stderr, frame);
} }
} }
} }
@@ -416,7 +416,7 @@ void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Prot
evbuffer_add(out_buf, &ether, sizeof(ether)); evbuffer_add(out_buf, &ether, sizeof(ether));
evbuffer_add(out_buf, data, size); evbuffer_add(out_buf, data, size);
if (this->pcap_text_log_file) { if (this->pcap_text_log_file) {
StringWriter w; phosg::StringWriter w;
w.write(&ether, sizeof(ether)); w.write(&ether, sizeof(ether));
w.write(data, size); w.write(data, size);
this->log_frame(w.str()); this->log_frame(w.str());
@@ -451,7 +451,7 @@ void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Prot
throw logic_error("unknown layer 3 protocol"); throw logic_error("unknown layer 3 protocol");
} }
StringWriter w; phosg::StringWriter w;
w.put(hdlc); w.put(hdlc);
w.write(data, size); w.write(data, size);
w.put_u16l(FrameInfo::computed_hdlc_checksum(w.str().data() + 1, w.size() - 1)); w.put_u16l(FrameInfo::computed_hdlc_checksum(w.str().data() + 1, w.size() - 1));
@@ -459,7 +459,7 @@ void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Prot
string escaped = escape_hdlc_frame(w.str(), c->hdlc_escape_control_character_flags); string escaped = escape_hdlc_frame(w.str(), c->hdlc_escape_control_character_flags);
if (ip_stack_simulator_log.debug("Sending HDLC frame to virtual network (escaped to %zX bytes)", escaped.size())) { if (ip_stack_simulator_log.debug("Sending HDLC frame to virtual network (escaped to %zX bytes)", escaped.size())) {
print_data(stderr, w.str()); phosg::print_data(stderr, w.str());
} }
if (c->protocol == Protocol::HDLC_TAPSERVER) { if (c->protocol == Protocol::HDLC_TAPSERVER) {
@@ -490,12 +490,12 @@ void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& fra
effective_data = &hdlc_unescaped_data; effective_data = &hdlc_unescaped_data;
} }
if (ip_stack_simulator_log.debug("Virtual network sent frame")) { if (ip_stack_simulator_log.debug("Virtual network sent frame")) {
print_data(stderr, *effective_data); phosg::print_data(stderr, *effective_data);
} }
this->log_frame(*effective_data); this->log_frame(*effective_data);
FrameInfo fi(link_type, *effective_data); FrameInfo fi(link_type, *effective_data);
if (ip_stack_simulator_log.should_log(LogLevel::DEBUG)) { if (ip_stack_simulator_log.should_log(phosg::LogLevel::DEBUG)) {
string fi_header = fi.header_str(); string fi_header = fi.header_str();
ip_stack_simulator_log.debug("Frame header: %s", fi_header.c_str()); ip_stack_simulator_log.debug("Frame header: %s", fi_header.c_str());
} }
@@ -510,7 +510,7 @@ void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& fra
uint16_t expected_checksum = fi.computed_hdlc_checksum(); uint16_t expected_checksum = fi.computed_hdlc_checksum();
uint16_t stored_checksum = fi.stored_hdlc_checksum(); uint16_t stored_checksum = fi.stored_hdlc_checksum();
if (expected_checksum != stored_checksum) { if (expected_checksum != stored_checksum) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"HDLC checksum is incorrect (%04hX expected, %04hX received)", "HDLC checksum is incorrect (%04hX expected, %04hX received)",
expected_checksum, stored_checksum)); expected_checksum, stored_checksum));
} }
@@ -533,7 +533,7 @@ void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& fra
} else if (fi.ipv4) { } else if (fi.ipv4) {
uint16_t expected_ipv4_checksum = fi.computed_ipv4_header_checksum(); uint16_t expected_ipv4_checksum = fi.computed_ipv4_header_checksum();
if (fi.ipv4->checksum != expected_ipv4_checksum) { if (fi.ipv4->checksum != expected_ipv4_checksum) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"IPv4 header checksum is incorrect (%04hX expected, %04hX received)", "IPv4 header checksum is incorrect (%04hX expected, %04hX received)",
expected_ipv4_checksum, fi.ipv4->checksum.load())); expected_ipv4_checksum, fi.ipv4->checksum.load()));
} }
@@ -545,7 +545,7 @@ void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& fra
if (fi.udp) { if (fi.udp) {
uint16_t expected_udp_checksum = fi.computed_udp4_checksum(); uint16_t expected_udp_checksum = fi.computed_udp4_checksum();
if (fi.udp->checksum != expected_udp_checksum) { if (fi.udp->checksum != expected_udp_checksum) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"UDP checksum is incorrect (%04hX expected, %04hX received)", "UDP checksum is incorrect (%04hX expected, %04hX received)",
expected_udp_checksum, fi.udp->checksum.load())); expected_udp_checksum, fi.udp->checksum.load()));
} }
@@ -554,7 +554,7 @@ void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& fra
} else if (fi.tcp) { } else if (fi.tcp) {
uint16_t expected_tcp_checksum = fi.computed_tcp4_checksum(); uint16_t expected_tcp_checksum = fi.computed_tcp4_checksum();
if (fi.tcp->checksum != expected_tcp_checksum) { if (fi.tcp->checksum != expected_tcp_checksum) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"TCP checksum is incorrect (%04hX expected, %04hX received)", "TCP checksum is incorrect (%04hX expected, %04hX received)",
expected_tcp_checksum, fi.tcp->checksum.load())); expected_tcp_checksum, fi.tcp->checksum.load()));
} }
@@ -576,7 +576,7 @@ void IPStackSimulator::on_client_lcp_frame(shared_ptr<IPClient> c, const FrameIn
while (!opts_r.eof()) { while (!opts_r.eof()) {
uint8_t opt = opts_r.get_u8(); uint8_t opt = opts_r.get_u8();
string opt_data = opts_r.read(opts_r.get_u8() - 2); string opt_data = opts_r.read(opts_r.get_u8() - 2);
StringReader opt_data_r(opt_data); phosg::StringReader opt_data_r(opt_data);
switch (opt) { switch (opt) {
case 0x01: // Maximum receive unit case 0x01: // Maximum receive unit
// TODO: Currently we ignore this, but we probably should use it. // TODO: Currently we ignore this, but we probably should use it.
@@ -593,7 +593,7 @@ void IPStackSimulator::on_client_lcp_frame(shared_ptr<IPClient> c, const FrameIn
case 0x04: // Quality protocol case 0x04: // Quality protocol
case 0x07: // Protocol field compression case 0x07: // Protocol field compression
case 0x08: // Address and control field compression case 0x08: // Address and control field compression
throw runtime_error(string_printf("unimplemented LCP option %02hhX (%zu bytes)", opt, opt_data.size())); throw runtime_error(phosg::string_printf("unimplemented LCP option %02hhX (%zu bytes)", opt, opt_data.size()));
default: default:
throw runtime_error("unknown LCP option"); throw runtime_error("unknown LCP option");
} }
@@ -602,7 +602,7 @@ void IPStackSimulator::on_client_lcp_frame(shared_ptr<IPClient> c, const FrameIn
// lazy to do this right now. In our situation, it should suffice to // lazy to do this right now. In our situation, it should suffice to
// simply always send a Configure-Request to the client with a magic // simply always send a Configure-Request to the client with a magic
// number not equal to the one we received. // number not equal to the one we received.
StringWriter opts_w; phosg::StringWriter opts_w;
opts_w.put_u8(0x01); // Maximum receive unit opts_w.put_u8(0x01); // Maximum receive unit
opts_w.put_u8(0x04); opts_w.put_u8(0x04);
opts_w.put_u16b(1500); opts_w.put_u16b(1500);
@@ -615,7 +615,7 @@ void IPStackSimulator::on_client_lcp_frame(shared_ptr<IPClient> c, const FrameIn
opts_w.put_u8(0x05); // Magic number (bitwise inverse of the remote end's) opts_w.put_u8(0x05); // Magic number (bitwise inverse of the remote end's)
opts_w.put_u8(0x06); opts_w.put_u8(0x06);
opts_w.put_u32b(~c->hdlc_remote_magic_number); opts_w.put_u32b(~c->hdlc_remote_magic_number);
StringWriter request_w; phosg::StringWriter request_w;
request_w.put<LCPHeader>(LCPHeader{ request_w.put<LCPHeader>(LCPHeader{
.command = 0x01, // Configure-Request .command = 0x01, // Configure-Request
.request_id = fi.lcp->request_id, .request_id = fi.lcp->request_id,
@@ -624,7 +624,7 @@ void IPStackSimulator::on_client_lcp_frame(shared_ptr<IPClient> c, const FrameIn
request_w.write(opts_w.str()); request_w.write(opts_w.str());
this->send_layer3_frame(c, FrameInfo::Protocol::LCP, request_w.str()); this->send_layer3_frame(c, FrameInfo::Protocol::LCP, request_w.str());
StringWriter ack_w; phosg::StringWriter ack_w;
ack_w.put<LCPHeader>(LCPHeader{ ack_w.put<LCPHeader>(LCPHeader{
.command = 0x02, // Configure-Ack .command = 0x02, // Configure-Ack
.request_id = fi.lcp->request_id, .request_id = fi.lcp->request_id,
@@ -679,7 +679,7 @@ void IPStackSimulator::on_client_pap_frame(shared_ptr<IPClient> c, const FrameIn
ip_stack_simulator_log.info("Client logged in with username \"%s\" and password", username.c_str()); ip_stack_simulator_log.info("Client logged in with username \"%s\" and password", username.c_str());
static const string login_message = "newserv PPP simulator"; static const string login_message = "newserv PPP simulator";
StringWriter w; phosg::StringWriter w;
w.put<PAPHeader>(PAPHeader{ w.put<PAPHeader>(PAPHeader{
.command = 0x02, // Authenticate-Ack .command = 0x02, // Authenticate-Ack
.request_id = fi.pap->request_id, .request_id = fi.pap->request_id,
@@ -698,11 +698,11 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
uint32_t remote_ip = 0; uint32_t remote_ip = 0;
uint32_t remote_primary_dns = 0; uint32_t remote_primary_dns = 0;
uint32_t remote_secondary_dns = 0; uint32_t remote_secondary_dns = 0;
StringWriter rejected_opts_w; phosg::StringWriter rejected_opts_w;
while (!opts_r.eof()) { while (!opts_r.eof()) {
uint8_t opt = opts_r.get_u8(); uint8_t opt = opts_r.get_u8();
string opt_data = opts_r.read(opts_r.get_u8() - 2); string opt_data = opts_r.read(opts_r.get_u8() - 2);
StringReader opt_data_r(opt_data); phosg::StringReader opt_data_r(opt_data);
switch (opt) { switch (opt) {
case 0x01: // IP addresses (deprecated as of 1992; we don't support it at all) case 0x01: // IP addresses (deprecated as of 1992; we don't support it at all)
throw runtime_error("IPCP client sent IP-Addresses option"); throw runtime_error("IPCP client sent IP-Addresses option");
@@ -723,7 +723,7 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
case 0x82: // Primary NBNS server address case 0x82: // Primary NBNS server address
case 0x84: // Secondary NBNS server address case 0x84: // Secondary NBNS server address
case 0x04: // Mobile IP address case 0x04: // Mobile IP address
throw runtime_error(string_printf("unimplemented IPCP option %02hhX (%zu bytes)", opt, opt_data.size())); throw runtime_error(phosg::string_printf("unimplemented IPCP option %02hhX (%zu bytes)", opt, opt_data.size()));
default: default:
throw runtime_error("unknown IPCP option"); throw runtime_error("unknown IPCP option");
} }
@@ -731,7 +731,7 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
if (!rejected_opts_w.str().empty()) { if (!rejected_opts_w.str().empty()) {
// Send a Configure-Reject if the client specified IP header compression // Send a Configure-Reject if the client specified IP header compression
StringWriter reject_w; phosg::StringWriter reject_w;
reject_w.put<IPCPHeader>(IPCPHeader{ reject_w.put<IPCPHeader>(IPCPHeader{
.command = 0x04, // Configure-Reject .command = 0x04, // Configure-Reject
.request_id = fi.ipcp->request_id, .request_id = fi.ipcp->request_id,
@@ -745,7 +745,7 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
(remote_secondary_dns != 0x24242424)) { (remote_secondary_dns != 0x24242424)) {
// Send a Configure-Nak if the client's request doesn't exactly match // Send a Configure-Nak if the client's request doesn't exactly match
// what we want them to use. // what we want them to use.
StringWriter opts_w; phosg::StringWriter opts_w;
opts_w.put_u8(0x03); // IP address opts_w.put_u8(0x03); // IP address
opts_w.put_u8(0x06); opts_w.put_u8(0x06);
opts_w.put_u32b(0x1E1E1E1E); opts_w.put_u32b(0x1E1E1E1E);
@@ -756,7 +756,7 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
opts_w.put_u8(0x06); opts_w.put_u8(0x06);
opts_w.put_u32b(0x24242424); opts_w.put_u32b(0x24242424);
StringWriter nak_w; phosg::StringWriter nak_w;
nak_w.put<IPCPHeader>(IPCPHeader{ nak_w.put<IPCPHeader>(IPCPHeader{
.command = 0x03, // Configure-Nak .command = 0x03, // Configure-Nak
.request_id = fi.ipcp->request_id, .request_id = fi.ipcp->request_id,
@@ -770,7 +770,7 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
// As with LCP, we technically should implement the state machine, but I // As with LCP, we technically should implement the state machine, but I
// continue to be lazy. // continue to be lazy.
StringWriter opts_w; phosg::StringWriter opts_w;
opts_w.put_u8(0x03); // IP address opts_w.put_u8(0x03); // IP address
opts_w.put_u8(0x06); opts_w.put_u8(0x06);
opts_w.put_u32b(0x39393939); opts_w.put_u32b(0x39393939);
@@ -781,7 +781,7 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
opts_w.put_u8(0x06); opts_w.put_u8(0x06);
opts_w.put_u32b(0x24242424); opts_w.put_u32b(0x24242424);
StringWriter request_w; phosg::StringWriter request_w;
request_w.put<IPCPHeader>(IPCPHeader{ request_w.put<IPCPHeader>(IPCPHeader{
.command = 0x01, // Configure-Request .command = 0x01, // Configure-Request
.request_id = fi.ipcp->request_id, .request_id = fi.ipcp->request_id,
@@ -790,7 +790,7 @@ void IPStackSimulator::on_client_ipcp_frame(shared_ptr<IPClient> c, const FrameI
request_w.write(opts_w.str()); request_w.write(opts_w.str());
this->send_layer3_frame(c, FrameInfo::Protocol::IPCP, request_w.str()); this->send_layer3_frame(c, FrameInfo::Protocol::IPCP, request_w.str());
StringWriter ack_w; phosg::StringWriter ack_w;
ack_w.put<IPCPHeader>(IPCPHeader{ ack_w.put<IPCPHeader>(IPCPHeader{
.command = 0x02, // Configure-Ack .command = 0x02, // Configure-Ack
.request_id = fi.ipcp->request_id, .request_id = fi.ipcp->request_id,
@@ -841,7 +841,7 @@ void IPStackSimulator::on_client_arp_frame(
reinterpret_cast<const uint8_t*>(fi.payload) + 6); reinterpret_cast<const uint8_t*>(fi.payload) + 6);
} }
StringWriter w; phosg::StringWriter w;
w.put<ARPHeader>(ARPHeader{ w.put<ARPHeader>(ARPHeader{
.hardware_type = fi.arp->hardware_type, .hardware_type = fi.arp->hardware_type,
.protocol_type = fi.arp->protocol_type, .protocol_type = fi.arp->protocol_type,
@@ -942,7 +942,7 @@ void IPStackSimulator::on_client_udp_frame(shared_ptr<IPClient> c, const FrameIn
throw runtime_error("client sent unknown DHCP command option"); throw runtime_error("client sent unknown DHCP command option");
} }
StringWriter w; phosg::StringWriter w;
DHCPHeader r_dhcp; DHCPHeader r_dhcp;
r_dhcp.opcode = 2; // Response r_dhcp.opcode = 2; // Response
r_dhcp.hardware_type = 1; // Ethernet r_dhcp.hardware_type = 1; // Ethernet
@@ -1027,13 +1027,13 @@ void IPStackSimulator::on_client_udp_frame(shared_ptr<IPClient> c, const FrameIn
r_udp.checksum = FrameInfo::computed_udp4_checksum( r_udp.checksum = FrameInfo::computed_udp4_checksum(
r_ipv4, r_udp, r_data.data(), r_data.size()); r_ipv4, r_udp, r_data.data(), r_data.size());
if (ip_stack_simulator_log.should_log(LogLevel::DEBUG)) { if (ip_stack_simulator_log.should_log(phosg::LogLevel::DEBUG)) {
string remote_str = this->str_for_ipv4_netloc(fi.ipv4->src_addr, fi.udp->src_port); string remote_str = this->str_for_ipv4_netloc(fi.ipv4->src_addr, fi.udp->src_port);
ip_stack_simulator_log.debug("Sending UDP response to %s", remote_str.c_str()); ip_stack_simulator_log.debug("Sending UDP response to %s", remote_str.c_str());
print_data(stderr, r_data); phosg::print_data(stderr, r_data);
} }
StringWriter w; phosg::StringWriter w;
w.put(r_ipv4); w.put(r_ipv4);
w.put(r_udp); w.put(r_udp);
w.write(r_data); w.write(r_data);
@@ -1079,7 +1079,7 @@ void IPStackSimulator::on_client_tcp_frame(
throw runtime_error("TCP SYN contains extra flags"); throw runtime_error("TCP SYN contains extra flags");
} }
StringReader options_r(fi.tcp + 1, fi.tcp_options_size); phosg::StringReader options_r(fi.tcp + 1, fi.tcp_options_size);
size_t max_frame_size = 1400; size_t max_frame_size = 1400;
while (!options_r.eof()) { while (!options_r.eof()) {
uint8_t option = options_r.get_u8(); uint8_t option = options_r.get_u8();
@@ -1135,7 +1135,7 @@ void IPStackSimulator::on_client_tcp_frame(
conn.server_port = fi.tcp->dest_port; conn.server_port = fi.tcp->dest_port;
conn.client_port = fi.tcp->src_port; conn.client_port = fi.tcp->src_port;
conn.next_client_seq = fi.tcp->seq_num + 1; conn.next_client_seq = fi.tcp->seq_num + 1;
conn.acked_server_seq = random_object<uint32_t>(); conn.acked_server_seq = phosg::random_object<uint32_t>();
conn.resend_push_usecs = DEFAULT_RESEND_PUSH_USECS; conn.resend_push_usecs = DEFAULT_RESEND_PUSH_USECS;
conn.next_push_max_frame_size = max_frame_size; conn.next_push_max_frame_size = max_frame_size;
conn.awaiting_first_ack = true; conn.awaiting_first_ack = true;
@@ -1240,7 +1240,7 @@ void IPStackSimulator::on_client_tcp_frame(
// server immediately. // server immediately.
} else if (fi.payload_size != 0) { } else if (fi.payload_size != 0) {
string conn_str = ip_stack_simulator_log.should_log(LogLevel::WARNING) string conn_str = ip_stack_simulator_log.should_log(phosg::LogLevel::WARNING)
? this->str_for_tcp_connection(c, *conn) ? this->str_for_tcp_connection(c, *conn)
: ""; : "";
@@ -1285,7 +1285,7 @@ void IPStackSimulator::on_client_tcp_frame(
conn_str.c_str()); conn_str.c_str());
} }
if (was_logged) { if (was_logged) {
print_data(stderr, payload, payload_size); phosg::print_data(stderr, payload, payload_size);
} }
// Send the new data to the server // Send the new data to the server
@@ -1388,7 +1388,7 @@ void IPStackSimulator::send_pending_push_frame(
conn.acked_server_seq, bytes_to_send, pending_bytes); conn.acked_server_seq, bytes_to_send, pending_bytes);
this->send_tcp_frame(c, conn, TCPHeader::Flag::PSH, conn.pending_data.get(), bytes_to_send); this->send_tcp_frame(c, conn, TCPHeader::Flag::PSH, conn.pending_data.get(), bytes_to_send);
struct timeval resend_push_timeout = usecs_to_timeval(conn.resend_push_usecs); struct timeval resend_push_timeout = phosg::usecs_to_timeval(conn.resend_push_usecs);
event_add(conn.resend_push_event.get(), &resend_push_timeout); event_add(conn.resend_push_event.get(), &resend_push_timeout);
// If the client isn't responding to our PSHes, back off exponentially up to // If the client isn't responding to our PSHes, back off exponentially up to
@@ -1441,7 +1441,7 @@ void IPStackSimulator::send_tcp_frame(
const void* linear_data = src_bytes ? evbuffer_pullup(src_buf, src_bytes) : nullptr; const void* linear_data = src_bytes ? evbuffer_pullup(src_buf, src_bytes) : nullptr;
tcp.checksum = FrameInfo::computed_tcp4_checksum(ipv4, tcp, linear_data, src_bytes); tcp.checksum = FrameInfo::computed_tcp4_checksum(ipv4, tcp, linear_data, src_bytes);
StringWriter w; phosg::StringWriter w;
w.put(ipv4); w.put(ipv4);
w.put(tcp); w.put(tcp);
if (src_bytes) { if (src_bytes) {
@@ -1488,7 +1488,7 @@ void IPStackSimulator::on_server_input(shared_ptr<IPClient> c, IPClient::TCPConn
auto sim = c->sim.lock(); auto sim = c->sim.lock();
uint64_t idle_timeout_usecs = sim ? sim->state->client_idle_timeout_usecs : 60000000; uint64_t idle_timeout_usecs = sim ? sim->state->client_idle_timeout_usecs : 60000000;
struct timeval tv = usecs_to_timeval(idle_timeout_usecs); struct timeval tv = phosg::usecs_to_timeval(idle_timeout_usecs);
event_add(c->idle_timeout_event.get(), &tv); event_add(c->idle_timeout_event.get(), &tv);
evbuffer_add_buffer(conn.pending_data.get(), buf); evbuffer_add_buffer(conn.pending_data.get(), buf);
@@ -1534,8 +1534,7 @@ void IPStackSimulator::on_server_error(
void IPStackSimulator::log_frame(const string& data) const { void IPStackSimulator::log_frame(const string& data) const {
if (this->pcap_text_log_file) { if (this->pcap_text_log_file) {
print_data(this->pcap_text_log_file, data, 0, nullptr, phosg::print_data(this->pcap_text_log_file, data, 0, nullptr, phosg::PrintDataFlags::SKIP_SEPARATOR);
PrintDataFlags::SKIP_SEPARATOR);
fputc('\n', this->pcap_text_log_file); fputc('\n', this->pcap_text_log_file);
fflush(this->pcap_text_log_file); fflush(this->pcap_text_log_file);
} }
+6 -6
View File
@@ -4,10 +4,10 @@
using namespace std; using namespace std;
IPV4RangeSet::IPV4RangeSet(const JSON& json) { IPV4RangeSet::IPV4RangeSet(const phosg::JSON& json) {
for (const auto& it : json.as_list()) { for (const auto& it : json.as_list()) {
// String should be of the form a.b.c.d or a.b.c.d/e // String should be of the form a.b.c.d or a.b.c.d/e
auto tokens = split(it->as_string(), '/'); auto tokens = phosg::split(it->as_string(), '/');
size_t mask_bits; size_t mask_bits;
if (tokens.size() == 1) { if (tokens.size() == 1) {
@@ -21,7 +21,7 @@ IPV4RangeSet::IPV4RangeSet(const JSON& json) {
throw runtime_error("invalid IPv4 address range"); throw runtime_error("invalid IPv4 address range");
} }
auto addr_tokens = split(tokens[0], '.'); auto addr_tokens = phosg::split(tokens[0], '.');
if (addr_tokens.size() != 4) { if (addr_tokens.size() != 4) {
throw runtime_error("invalid IPv4 address"); throw runtime_error("invalid IPv4 address");
} }
@@ -40,12 +40,12 @@ IPV4RangeSet::IPV4RangeSet(const JSON& json) {
} }
} }
JSON IPV4RangeSet::json() const { phosg::JSON IPV4RangeSet::json() const {
auto ret = JSON::list(); auto ret = phosg::JSON::list();
for (const auto& it : this->ranges) { for (const auto& it : this->ranges) {
uint32_t addr = it.first; uint32_t addr = it.first;
uint8_t mask_bits = it.second; uint8_t mask_bits = it.second;
ret.emplace_back(string_printf("%hhu.%hhu.%hhu.%hhu/%hhu", ret.emplace_back(phosg::string_printf("%hhu.%hhu.%hhu.%hhu/%hhu",
static_cast<uint8_t>((addr >> 24) & 0xFF), static_cast<uint8_t>((addr >> 24) & 0xFF),
static_cast<uint8_t>((addr >> 16) & 0xFF), static_cast<uint8_t>((addr >> 16) & 0xFF),
static_cast<uint8_t>((addr >> 8) & 0xFF), static_cast<uint8_t>((addr >> 8) & 0xFF),
+2 -2
View File
@@ -6,9 +6,9 @@
class IPV4RangeSet { class IPV4RangeSet {
public: public:
IPV4RangeSet() = default; IPV4RangeSet() = default;
explicit IPV4RangeSet(const JSON& json); explicit IPV4RangeSet(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
bool check(uint32_t addr) const; bool check(uint32_t addr) const;
bool check(const struct sockaddr_storage& ss) const; bool check(const struct sockaddr_storage& ss) const;
+3 -3
View File
@@ -184,7 +184,7 @@ int64_t IntegralExpression::FlagLookupNode::evaluate(const Env& env) const {
} }
string IntegralExpression::FlagLookupNode::str() const { string IntegralExpression::FlagLookupNode::str() const {
return string_printf("F_%04hX", this->flag_index); return phosg::string_printf("F_%04hX", this->flag_index);
} }
IntegralExpression::ChallengeCompletionLookupNode::ChallengeCompletionLookupNode( IntegralExpression::ChallengeCompletionLookupNode::ChallengeCompletionLookupNode(
@@ -214,7 +214,7 @@ int64_t IntegralExpression::ChallengeCompletionLookupNode::evaluate(const Env& e
} }
string IntegralExpression::ChallengeCompletionLookupNode::str() const { string IntegralExpression::ChallengeCompletionLookupNode::str() const {
return string_printf("CC_%s_%hhu", abbreviation_for_episode(this->episode), static_cast<uint8_t>(this->stage_index + 1)); return phosg::string_printf("CC_%s_%hhu", abbreviation_for_episode(this->episode), static_cast<uint8_t>(this->stage_index + 1));
} }
IntegralExpression::TeamRewardLookupNode::TeamRewardLookupNode(const string& reward_name) IntegralExpression::TeamRewardLookupNode::TeamRewardLookupNode(const string& reward_name)
@@ -296,7 +296,7 @@ int64_t IntegralExpression::ConstantNode::evaluate(const Env&) const {
} }
string IntegralExpression::ConstantNode::str() const { string IntegralExpression::ConstantNode::str() const {
return string_printf("%" PRId64, this->value); return phosg::string_printf("%" PRId64, this->value);
} }
unique_ptr<const IntegralExpression::Node> IntegralExpression::parse_expr(string_view text) { unique_ptr<const IntegralExpression::Node> IntegralExpression::parse_expr(string_view text) {
+7 -7
View File
@@ -36,7 +36,7 @@ ItemCreator::ItemCreator(
uint8_t section_id, uint8_t section_id,
std::shared_ptr<PSOLFGEncryption> opt_rand_crypt, std::shared_ptr<PSOLFGEncryption> opt_rand_crypt,
shared_ptr<const BattleRules> restrictions) shared_ptr<const BattleRules> restrictions)
: log(string_printf("[ItemCreator:%s/%s/%s/%c/%hhu] ", name_for_enum(stack_limits->version), abbreviation_for_episode(episode), abbreviation_for_mode(mode), abbreviation_for_difficulty(difficulty), section_id), lobby_log.min_level), : log(phosg::string_printf("[ItemCreator:%s/%s/%s/%c/%hhu] ", phosg::name_for_enum(stack_limits->version), abbreviation_for_episode(episode), abbreviation_for_mode(mode), abbreviation_for_difficulty(difficulty), section_id), lobby_log.min_level),
logic_version(stack_limits->version), logic_version(stack_limits->version),
stack_limits(stack_limits), stack_limits(stack_limits),
episode(episode), episode(episode),
@@ -63,8 +63,8 @@ void ItemCreator::set_random_crypt(shared_ptr<PSOLFGEncryption> new_random_crypt
void ItemCreator::set_section_id(uint8_t new_section_id) { void ItemCreator::set_section_id(uint8_t new_section_id) {
if (this->section_id != new_section_id) { if (this->section_id != new_section_id) {
this->section_id = new_section_id; this->section_id = new_section_id;
this->log.prefix = string_printf("[ItemCreator:%s/%s/%s/%c/%hhu] ", this->log.prefix = phosg::string_printf("[ItemCreator:%s/%s/%s/%c/%hhu] ",
name_for_enum(stack_limits->version), phosg::name_for_enum(stack_limits->version),
abbreviation_for_episode(episode), abbreviation_for_episode(episode),
abbreviation_for_mode(mode), abbreviation_for_mode(mode),
abbreviation_for_difficulty(difficulty), abbreviation_for_difficulty(difficulty),
@@ -298,13 +298,13 @@ ItemData ItemCreator::check_rare_specs_and_create_rare_box_item(uint8_t area_nor
for (const auto& spec : rare_specs) { for (const auto& spec : rare_specs) {
item = this->check_rate_and_create_rare_item(spec, area_norm); item = this->check_rate_and_create_rare_item(spec, area_norm);
if (!item.empty()) { if (!item.empty()) {
if (this->log.should_log(LogLevel::INFO)) { if (this->log.should_log(phosg::LogLevel::INFO)) {
auto hex = spec.data.hex(); auto hex = spec.data.hex();
this->log.info("Box spec %08" PRIX32 " produced item %s", spec.probability, hex.c_str()); this->log.info("Box spec %08" PRIX32 " produced item %s", spec.probability, hex.c_str());
} }
break; break;
} }
if (this->log.should_log(LogLevel::INFO)) { if (this->log.should_log(phosg::LogLevel::INFO)) {
auto hex = spec.data.hex(); auto hex = spec.data.hex();
this->log.info("Box spec %08" PRIX32 " did not produce item %s", spec.probability, hex.c_str()); this->log.info("Box spec %08" PRIX32 " did not produce item %s", spec.probability, hex.c_str());
} }
@@ -359,13 +359,13 @@ ItemData ItemCreator::check_rare_spec_and_create_rare_enemy_item(uint32_t enemy_
for (const auto& spec : rare_specs) { for (const auto& spec : rare_specs) {
item = this->check_rate_and_create_rare_item(spec, area_norm); item = this->check_rate_and_create_rare_item(spec, area_norm);
if (!item.empty()) { if (!item.empty()) {
if (this->log.should_log(LogLevel::INFO)) { if (this->log.should_log(phosg::LogLevel::INFO)) {
auto hex = spec.data.hex(); auto hex = spec.data.hex();
this->log.info("Enemy spec %08" PRIX32 " produced item %s", spec.probability, hex.c_str()); this->log.info("Enemy spec %08" PRIX32 " produced item %s", spec.probability, hex.c_str());
} }
break; break;
} }
if (this->log.should_log(LogLevel::INFO)) { if (this->log.should_log(phosg::LogLevel::INFO)) {
auto hex = spec.data.hex(); auto hex = spec.data.hex();
this->log.info("Enemy spec %08" PRIX32 " did not produce item %s", spec.probability, hex.c_str()); this->log.info("Enemy spec %08" PRIX32 " did not produce item %s", spec.probability, hex.c_str());
} }
+1 -1
View File
@@ -58,7 +58,7 @@ public:
void set_section_id(uint8_t new_section_id); void set_section_id(uint8_t new_section_id);
private: private:
PrefixedLogger log; phosg::PrefixedLogger log;
Version logic_version; Version logic_version;
std::shared_ptr<const ItemData::StackLimits> stack_limits; std::shared_ptr<const ItemData::StackLimits> stack_limits;
Episode episode; Episode episode;
+7 -7
View File
@@ -21,7 +21,7 @@ ItemData::StackLimits::StackLimits(
max_tool_stack_sizes_by_data1_1(max_tool_stack_sizes_by_data1_1), max_tool_stack_sizes_by_data1_1(max_tool_stack_sizes_by_data1_1),
max_meseta_stack_size(max_meseta_stack_size) {} max_meseta_stack_size(max_meseta_stack_size) {}
ItemData::StackLimits::StackLimits(Version version, const JSON& json) ItemData::StackLimits::StackLimits(Version version, const phosg::JSON& json)
: version(version) { : version(version) {
this->max_tool_stack_sizes_by_data1_1.clear(); this->max_tool_stack_sizes_by_data1_1.clear();
for (const auto& limit_json : json.at("ToolLimits").as_list()) { for (const auto& limit_json : json.at("ToolLimits").as_list()) {
@@ -53,8 +53,8 @@ ItemData::ItemData(const ItemData& other) {
ItemData::ItemData(uint64_t first, uint64_t second) { ItemData::ItemData(uint64_t first, uint64_t second) {
*reinterpret_cast<be_uint64_t*>(&this->data1[0]) = first; *reinterpret_cast<be_uint64_t*>(&this->data1[0]) = first;
this->data1d[2] = bswap32((second >> 32) & 0xFFFFFFFF); this->data1d[2] = phosg::bswap32((second >> 32) & 0xFFFFFFFF);
this->data2d = bswap32(second & 0xFFFFFFFF); this->data2d = phosg::bswap32(second & 0xFFFFFFFF);
} }
ItemData& ItemData::operator=(const ItemData& other) { ItemData& ItemData::operator=(const ItemData& other) {
@@ -400,7 +400,7 @@ void ItemData::decode_for_version(Version from_version) {
// data2d field, since internally it's actually a uint32_t. We treat it // data2d field, since internally it's actually a uint32_t. We treat it
// as individual bytes instead, so we correct for the client's // as individual bytes instead, so we correct for the client's
// byteswapping here. // byteswapping here.
this->data2d = bswap32(this->data2d); this->data2d = phosg::bswap32(this->data2d);
} }
break; break;
@@ -482,7 +482,7 @@ void ItemData::encode_for_version(Version to_version, shared_ptr<const ItemParam
this->data2w[1] = this->data2[0] | ((this->data2[2] << 15) & 0x8000); this->data2w[1] = this->data2[0] | ((this->data2[2] << 15) & 0x8000);
this->data2w[0] = this->data2[1]; this->data2w[0] = this->data2[1];
} else if (is_big_endian(to_version)) { } else if (is_big_endian(to_version)) {
this->data2d = bswap32(this->data2d); this->data2d = phosg::bswap32(this->data2d);
} }
break; break;
@@ -743,12 +743,12 @@ ItemData ItemData::from_primary_identifier(const StackLimits& limits, uint32_t p
} }
string ItemData::hex() const { string ItemData::hex() const {
return string_printf("%08" PRIX32 " %08" PRIX32 " %08" PRIX32 " (%08" PRIX32 ") %08" PRIX32, return phosg::string_printf("%08" PRIX32 " %08" PRIX32 " %08" PRIX32 " (%08" PRIX32 ") %08" PRIX32,
this->data1db[0].load(), this->data1db[1].load(), this->data1db[2].load(), this->id.load(), this->data2db.load()); this->data1db[0].load(), this->data1db[1].load(), this->data1db[2].load(), this->id.load(), this->data2db.load());
} }
string ItemData::short_hex() const { string ItemData::short_hex() const {
auto ret = string_printf("%08" PRIX32 "%08" PRIX32 "%08" PRIX32 "%08" PRIX32, auto ret = phosg::string_printf("%08" PRIX32 "%08" PRIX32 "%08" PRIX32 "%08" PRIX32,
this->data1db[0].load(), this->data1db[1].load(), this->data1db[2].load(), this->data2db.load()); this->data1db[0].load(), this->data1db[1].load(), this->data1db[2].load(), this->data2db.load());
size_t offset = ret.find_last_not_of('0'); size_t offset = ret.find_last_not_of('0');
if (offset != string::npos) { if (offset != string::npos) {
+1 -1
View File
@@ -62,7 +62,7 @@ struct ItemData {
uint32_t max_meseta_stack_size; uint32_t max_meseta_stack_size;
StackLimits(Version version, const std::vector<uint8_t>& max_tool_stack_sizes_by_data1_1, uint32_t max_meseta_stack_size); StackLimits(Version version, const std::vector<uint8_t>& max_tool_stack_sizes_by_data1_1, uint32_t max_meseta_stack_size);
StackLimits(Version version, const JSON& json); StackLimits(Version version, const phosg::JSON& json);
StackLimits(const StackLimits& other) = default; StackLimits(const StackLimits& other) = default;
StackLimits(StackLimits&& other) = default; StackLimits(StackLimits&& other) = default;
StackLimits& operator=(const StackLimits& other) = default; StackLimits& operator=(const StackLimits& other) = default;
+68 -68
View File
@@ -24,7 +24,7 @@ ItemNameIndex::ItemNameIndex(
meta->primary_identifier = primary_identifier; meta->primary_identifier = primary_identifier;
meta->name = *name; meta->name = *name;
this->primary_identifier_index.emplace(meta->primary_identifier, meta); this->primary_identifier_index.emplace(meta->primary_identifier, meta);
this->name_index.emplace(tolower(meta->name), meta); this->name_index.emplace(phosg::tolower(meta->name), meta);
} }
} }
} }
@@ -99,7 +99,7 @@ const array<const char*, 0x11> name_for_s_rank_special = {
std::string ItemNameIndex::describe_item(const ItemData& item, bool include_color_escapes) const { std::string ItemNameIndex::describe_item(const ItemData& item, bool include_color_escapes) const {
if (item.data1[0] == 0x04) { if (item.data1[0] == 0x04) {
return string_printf("%s%" PRIu32 " Meseta", include_color_escapes ? "$C7" : "", item.data2d.load()); return phosg::string_printf("%s%" PRIu32 " Meseta", include_color_escapes ? "$C7" : "", item.data2d.load());
} }
vector<string> ret_tokens; vector<string> ret_tokens;
@@ -120,7 +120,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
try { try {
ret_tokens.emplace_back(name_for_weapon_special.at(special_id)); ret_tokens.emplace_back(name_for_weapon_special.at(special_id));
} catch (const out_of_range&) { } catch (const out_of_range&) {
ret_tokens.emplace_back(string_printf("!SP:%02hhX", special_id)); ret_tokens.emplace_back(phosg::string_printf("!SP:%02hhX", special_id));
} }
} }
} }
@@ -128,7 +128,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
try { try {
ret_tokens.emplace_back(name_for_s_rank_special.at(item.data1[2])); ret_tokens.emplace_back(name_for_s_rank_special.at(item.data1[2]));
} catch (const out_of_range&) { } catch (const out_of_range&) {
ret_tokens.emplace_back(string_printf("!SSP:%02hhX", item.data1[2])); ret_tokens.emplace_back(phosg::string_printf("!SSP:%02hhX", item.data1[2]));
} }
} }
@@ -149,34 +149,34 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
technique_name = tech_id_to_name.at(item.data1[4]); technique_name = tech_id_to_name.at(item.data1[4]);
technique_name[0] = toupper(technique_name[0]); technique_name[0] = toupper(technique_name[0]);
} catch (const out_of_range&) { } catch (const out_of_range&) {
technique_name = string_printf("!TD:%02hhX", item.data1[4]); technique_name = phosg::string_printf("!TD:%02hhX", item.data1[4]);
} }
// Hide the level for Reverser and Ryuker, unless the level isn't 1 // Hide the level for Reverser and Ryuker, unless the level isn't 1
if ((item.data1[2] == 0) && ((item.data1[4] == 0x0E) || (item.data1[4] == 0x11))) { if ((item.data1[2] == 0) && ((item.data1[4] == 0x0E) || (item.data1[4] == 0x11))) {
ret_tokens.emplace_back(string_printf("Disk:%s", technique_name.c_str())); ret_tokens.emplace_back(phosg::string_printf("Disk:%s", technique_name.c_str()));
} else { } else {
ret_tokens.emplace_back(string_printf("Disk:%s Lv.%d", technique_name.c_str(), item.data1[2] + 1)); ret_tokens.emplace_back(phosg::string_printf("Disk:%s Lv.%d", technique_name.c_str(), item.data1[2] + 1));
} }
} else { } else {
try { try {
auto meta = this->primary_identifier_index.at(primary_identifier); auto meta = this->primary_identifier_index.at(primary_identifier);
ret_tokens.emplace_back(meta->name); ret_tokens.emplace_back(meta->name);
} catch (const out_of_range&) { } catch (const out_of_range&) {
ret_tokens.emplace_back(string_printf("!ID:%08" PRIX32, primary_identifier)); ret_tokens.emplace_back(phosg::string_printf("!ID:%08" PRIX32, primary_identifier));
} }
} }
// For weapons, add the grind and bonuses, or S-rank name if applicable // For weapons, add the grind and bonuses, or S-rank name if applicable
if (item.data1[0] == 0x00) { if (item.data1[0] == 0x00) {
if (item.data1[3] > 0) { if (item.data1[3] > 0) {
ret_tokens.emplace_back(string_printf("+%hhu", item.data1[3])); ret_tokens.emplace_back(phosg::string_printf("+%hhu", item.data1[3]));
} }
if (item.is_s_rank_weapon()) { if (item.is_s_rank_weapon()) {
// S-rank (has name instead of percent bonuses) // S-rank (has name instead of percent bonuses)
uint16_t be_data1w3 = bswap16(item.data1w[3]); uint16_t be_data1w3 = phosg::bswap16(item.data1w[3]);
uint16_t be_data1w4 = bswap16(item.data1w[4]); uint16_t be_data1w4 = phosg::bswap16(item.data1w[4]);
uint16_t be_data1w5 = bswap16(item.data1w[5]); uint16_t be_data1w5 = phosg::bswap16(item.data1w[5]);
uint8_t char_indexes[8] = { uint8_t char_indexes[8] = {
static_cast<uint8_t>((be_data1w3 >> 5) & 0x1F), static_cast<uint8_t>((be_data1w3 >> 5) & 0x1F),
static_cast<uint8_t>(be_data1w3 & 0x1F), static_cast<uint8_t>(be_data1w3 & 0x1F),
@@ -210,9 +210,9 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
} }
if (which & 0x80) { if (which & 0x80) {
uint16_t kill_count = ((which << 8) & 0x7F00) | (value & 0xFF); uint16_t kill_count = ((which << 8) & 0x7F00) | (value & 0xFF);
ret_tokens.emplace_back(string_printf("K:%hu", kill_count)); ret_tokens.emplace_back(phosg::string_printf("K:%hu", kill_count));
} else if (which > 5) { } else if (which > 5) {
ret_tokens.emplace_back(string_printf("!PC:%02hhX%02hhX", which, value)); ret_tokens.emplace_back(phosg::string_printf("!PC:%02hhX%02hhX", which, value));
} else { } else {
bonuses[which - 1] = value; bonuses[which - 1] = value;
} }
@@ -222,11 +222,11 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
bool should_highlight_hit = include_color_escapes && (bonuses[4] > 0); bool should_highlight_hit = include_color_escapes && (bonuses[4] > 0);
const char* color_prefix = include_color_escapes ? "$C7" : ""; const char* color_prefix = include_color_escapes ? "$C7" : "";
if (should_include_hit) { if (should_include_hit) {
ret_tokens.emplace_back(string_printf("%s%hhd/%hhd/%hhd/%hhd/%s%hhd", ret_tokens.emplace_back(phosg::string_printf("%s%hhd/%hhd/%hhd/%hhd/%s%hhd",
color_prefix, bonuses[0], bonuses[1], bonuses[2], bonuses[3], color_prefix, bonuses[0], bonuses[1], bonuses[2], bonuses[3],
(should_highlight_hit ? "$C6" : ""), bonuses[4])); (should_highlight_hit ? "$C6" : ""), bonuses[4]));
} else { } else {
ret_tokens.emplace_back(string_printf("%s%hhd/%hhd/%hhd/%hhd", ret_tokens.emplace_back(phosg::string_printf("%s%hhd/%hhd/%hhd/%hhd",
color_prefix, bonuses[0], bonuses[1], bonuses[2], bonuses[3])); color_prefix, bonuses[0], bonuses[1], bonuses[2], bonuses[3]));
} }
} }
@@ -245,7 +245,7 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
} else if (modifier <= -3) { } else if (modifier <= -3) {
ret_tokens.back().append("--"); ret_tokens.back().append("--");
} else if (modifier != 0) { } else if (modifier != 0) {
ret_tokens.emplace_back(string_printf("!MD:%04hX", modifier)); ret_tokens.emplace_back(phosg::string_printf("!MD:%04hX", modifier));
} }
} else { // Armor/shields } else { // Armor/shields
@@ -253,22 +253,22 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
if (item.data1[5] == 1) { if (item.data1[5] == 1) {
ret_tokens.emplace_back("(1 slot)"); ret_tokens.emplace_back("(1 slot)");
} else { } else {
ret_tokens.emplace_back(string_printf("(%hhu slots)", item.data1[5])); ret_tokens.emplace_back(phosg::string_printf("(%hhu slots)", item.data1[5]));
} }
} }
if (item.data1w[3] != 0) { if (item.data1w[3] != 0) {
ret_tokens.emplace_back(string_printf("+%hdDEF", ret_tokens.emplace_back(phosg::string_printf("+%hdDEF",
static_cast<int16_t>(item.data1w[3].load()))); static_cast<int16_t>(item.data1w[3].load())));
} }
if (item.data1w[4] != 0) { if (item.data1w[4] != 0) {
ret_tokens.emplace_back(string_printf("+%hdEVP", ret_tokens.emplace_back(phosg::string_printf("+%hdEVP",
static_cast<int16_t>(item.data1w[4].load()))); static_cast<int16_t>(item.data1w[4].load())));
} }
} }
// For mags, add tons of info // For mags, add tons of info
} else if (item.data1[0] == 0x02) { } else if (item.data1[0] == 0x02) {
ret_tokens.emplace_back(string_printf("LV%hhu", item.data1[2])); ret_tokens.emplace_back(phosg::string_printf("LV%hhu", item.data1[2]));
uint16_t def = item.data1w[2]; uint16_t def = item.data1w[2];
uint16_t pow = item.data1w[3]; uint16_t pow = item.data1w[3];
@@ -278,16 +278,16 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
uint16_t level = stat / 100; uint16_t level = stat / 100;
uint8_t partial = stat % 100; uint8_t partial = stat % 100;
if (partial == 0) { if (partial == 0) {
return string_printf("%hu", level); return phosg::string_printf("%hu", level);
} else if (partial % 10 == 0) { } else if (partial % 10 == 0) {
return string_printf("%hu.%hhu", level, static_cast<uint8_t>(partial / 10)); return phosg::string_printf("%hu.%hhu", level, static_cast<uint8_t>(partial / 10));
} else { } else {
return string_printf("%hu.%02hhu", level, partial); return phosg::string_printf("%hu.%02hhu", level, partial);
} }
}; };
ret_tokens.emplace_back(format_stat(def) + "/" + format_stat(pow) + "/" + format_stat(dex) + "/" + format_stat(mind)); ret_tokens.emplace_back(format_stat(def) + "/" + format_stat(pow) + "/" + format_stat(dex) + "/" + format_stat(mind));
ret_tokens.emplace_back(string_printf("%hhu%%", item.data2[0])); ret_tokens.emplace_back(phosg::string_printf("%hhu%%", item.data2[0]));
ret_tokens.emplace_back(string_printf("%hhuIQ", item.data2[1])); ret_tokens.emplace_back(phosg::string_printf("%hhuIQ", item.data2[1]));
uint8_t flags = item.data2[2]; uint8_t flags = item.data2[2];
if (flags & 7) { if (flags & 7) {
@@ -322,19 +322,19 @@ std::string ItemNameIndex::describe_item(const ItemData& item, bool include_colo
} }
try { try {
ret_tokens.emplace_back(string_printf("(%s)", name_for_mag_color.at(item.data2[3]))); ret_tokens.emplace_back(phosg::string_printf("(%s)", name_for_mag_color.at(item.data2[3])));
} catch (const out_of_range&) { } catch (const out_of_range&) {
ret_tokens.emplace_back(string_printf("(!CL:%02hhX)", item.data2[3])); ret_tokens.emplace_back(phosg::string_printf("(!CL:%02hhX)", item.data2[3]));
} }
// For tools, add the amount (if applicable) // For tools, add the amount (if applicable)
} else if (item.data1[0] == 0x03) { } else if (item.data1[0] == 0x03) {
if (item.max_stack_size(*this->limits) > 1) { if (item.max_stack_size(*this->limits) > 1) {
ret_tokens.emplace_back(string_printf("x%hhu", item.data1[5])); ret_tokens.emplace_back(phosg::string_printf("x%hhu", item.data1[5]));
} }
} }
string ret = join(ret_tokens, " "); string ret = phosg::join(ret_tokens, " ");
if (include_color_escapes) { if (include_color_escapes) {
if (is_unidentified) { if (is_unidentified) {
return "$C3" + ret; return "$C3" + ret;
@@ -361,13 +361,13 @@ ItemData ItemNameIndex::parse_item_description(const std::string& desc) const {
ret = this->parse_item_description_phase(desc, true); ret = this->parse_item_description_phase(desc, true);
} catch (const exception& e2) { } catch (const exception& e2) {
try { try {
ret = ItemData::from_data(parse_data_string(desc)); ret = ItemData::from_data(phosg::parse_data_string(desc));
} catch (const exception& ed) { } catch (const exception& ed) {
if (strcmp(e1.what(), e2.what())) { if (strcmp(e1.what(), e2.what())) {
throw runtime_error(string_printf("cannot parse item description \"%s\" (as text 1: %s) (as text 2: %s) (as data: %s)", throw runtime_error(phosg::string_printf("cannot parse item description \"%s\" (as text 1: %s) (as text 2: %s) (as data: %s)",
desc.c_str(), e1.what(), e2.what(), ed.what())); desc.c_str(), e1.what(), e2.what(), ed.what()));
} else { } else {
throw runtime_error(string_printf("cannot parse item description \"%s\" (as text: %s) (as data: %s)", throw runtime_error(phosg::string_printf("cannot parse item description \"%s\" (as text: %s) (as data: %s)",
desc.c_str(), e1.what(), ed.what())); desc.c_str(), e1.what(), ed.what()));
} }
} }
@@ -383,15 +383,15 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
ret.id = 0xFFFFFFFF; ret.id = 0xFFFFFFFF;
ret.data2d = 0; ret.data2d = 0;
string desc = tolower(description); string desc = phosg::tolower(description);
if (ends_with(desc, " meseta")) { if (phosg::ends_with(desc, " meseta")) {
ret.data1[0] = 0x04; ret.data1[0] = 0x04;
ret.data2d = stol(desc, nullptr, 10); ret.data2d = stol(desc, nullptr, 10);
return ret; return ret;
} }
if (starts_with(desc, "disk:")) { if (phosg::starts_with(desc, "disk:")) {
auto tokens = split(desc, ' '); auto tokens = phosg::split(desc, ' ');
tokens[0] = tokens[0].substr(5); // Trim off "disk:" tokens[0] = tokens[0].substr(5); // Trim off "disk:"
if ((tokens[0] == "reverser") || (tokens[0] == "ryuker")) { if ((tokens[0] == "reverser") || (tokens[0] == "ryuker")) {
uint8_t tech = technique_for_name(tokens[0]); uint8_t tech = technique_for_name(tokens[0]);
@@ -403,7 +403,7 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
if (tokens.size() != 2) { if (tokens.size() != 2) {
throw runtime_error("invalid tech disk format"); throw runtime_error("invalid tech disk format");
} }
if (!starts_with(tokens[1], "lv.")) { if (!phosg::starts_with(tokens[1], "lv.")) {
throw runtime_error("invalid tech disk level"); throw runtime_error("invalid tech disk level");
} }
uint8_t tech = technique_for_name(tokens[0]); uint8_t tech = technique_for_name(tokens[0]);
@@ -416,11 +416,11 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
return ret; return ret;
} }
bool is_wrapped = starts_with(desc, "wrapped "); bool is_wrapped = phosg::starts_with(desc, "wrapped ");
if (is_wrapped) { if (is_wrapped) {
desc = desc.substr(8); desc = desc.substr(8);
} }
bool is_unidentified = starts_with(desc, "?"); bool is_unidentified = phosg::starts_with(desc, "?");
if (is_unidentified) { if (is_unidentified) {
size_t z; size_t z;
for (z = 1; z < desc.size(); z++) { for (z = 1; z < desc.size(); z++) {
@@ -438,9 +438,9 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
if (!name_for_weapon_special[z]) { if (!name_for_weapon_special[z]) {
continue; continue;
} }
string prefix = tolower(name_for_weapon_special[z]); string prefix = phosg::tolower(name_for_weapon_special[z]);
prefix += ' '; prefix += ' ';
if (starts_with(desc, prefix)) { if (phosg::starts_with(desc, prefix)) {
weapon_special = z; weapon_special = z;
desc = desc.substr(prefix.size()); desc = desc.substr(prefix.size());
break; break;
@@ -454,7 +454,7 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
// then we'll see Sange & Yasha first, which we should skip. // then we'll see Sange & Yasha first, which we should skip.
size_t lookback = 0; size_t lookback = 0;
while (lookback < 4) { while (lookback < 4) {
if (name_it != this->name_index.end() && desc.starts_with(name_it->first)) { if (name_it != this->name_index.end() && phosg::starts_with(desc, name_it->first)) {
break; break;
} else if (name_it == this->name_index.begin()) { } else if (name_it == this->name_index.begin()) {
throw runtime_error("no such item"); throw runtime_error("no such item");
@@ -468,7 +468,7 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
} }
desc = desc.substr(name_it->first.size()); desc = desc.substr(name_it->first.size());
if (starts_with(desc, " ")) { if (phosg::starts_with(desc, " ")) {
desc = desc.substr(1); desc = desc.substr(1);
} }
@@ -483,12 +483,12 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
// Weapons: add special, grind and percentages (or name, if S-rank) // Weapons: add special, grind and percentages (or name, if S-rank)
ret.data1[4] = weapon_special | (is_wrapped ? 0x40 : 0x00) | (is_unidentified ? 0x80 : 0x00); ret.data1[4] = weapon_special | (is_wrapped ? 0x40 : 0x00) | (is_unidentified ? 0x80 : 0x00);
auto tokens = split(desc, ' '); auto tokens = phosg::split(desc, ' ');
for (auto& token : tokens) { for (auto& token : tokens) {
if (token.empty()) { if (token.empty()) {
continue; continue;
} }
if (starts_with(token, "+")) { if (phosg::starts_with(token, "+")) {
token = token.substr(1); token = token.substr(1);
ret.data1[3] = stoul(token, nullptr, 10); ret.data1[3] = stoul(token, nullptr, 10);
@@ -502,17 +502,17 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
char ch = toupper(token[z]); char ch = toupper(token[z]);
const char* pos = strchr(s_rank_name_characters, ch); const char* pos = strchr(s_rank_name_characters, ch);
if (!pos) { if (!pos) {
throw runtime_error(string_printf("s-rank name contains invalid character %02hhX (%c)", ch, ch)); throw runtime_error(phosg::string_printf("s-rank name contains invalid character %02hhX (%c)", ch, ch));
} }
char_indexes[z] = (pos - s_rank_name_characters); char_indexes[z] = (pos - s_rank_name_characters);
} }
ret.data1w[3] = bswap16(0x8000 | (char_indexes[1] & 0x1F) | ((char_indexes[0] & 0x1F) << 5)); ret.data1w[3] = phosg::bswap16(0x8000 | (char_indexes[1] & 0x1F) | ((char_indexes[0] & 0x1F) << 5));
ret.data1w[4] = bswap16(0x8000 | (char_indexes[4] & 0x1F) | ((char_indexes[3] & 0x1F) << 5) | ((char_indexes[2] & 0x1F) << 10)); ret.data1w[4] = phosg::bswap16(0x8000 | (char_indexes[4] & 0x1F) | ((char_indexes[3] & 0x1F) << 5) | ((char_indexes[2] & 0x1F) << 10));
ret.data1w[5] = bswap16(0x8000 | (char_indexes[7] & 0x1F) | ((char_indexes[6] & 0x1F) << 5) | ((char_indexes[5] & 0x1F) << 10)); ret.data1w[5] = phosg::bswap16(0x8000 | (char_indexes[7] & 0x1F) | ((char_indexes[6] & 0x1F) << 5) | ((char_indexes[5] & 0x1F) << 10));
} else { } else {
auto p_tokens = split(token, '/'); auto p_tokens = phosg::split(token, '/');
if (p_tokens.size() > 5) { if (p_tokens.size() > 5) {
throw runtime_error("invalid bonuses token"); throw runtime_error("invalid bonuses token");
} }
@@ -544,15 +544,15 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
ret.data1w[3] = modifiers.at(desc); ret.data1w[3] = modifiers.at(desc);
} else { // Armor/shield } else { // Armor/shield
for (const auto& token : split(desc, ' ')) { for (const auto& token : phosg::split(desc, ' ')) {
if (token.empty()) { if (token.empty()) {
continue; continue;
} else if (!starts_with(token, "+")) { } else if (!phosg::starts_with(token, "+")) {
throw runtime_error("invalid armor/shield modifier"); throw runtime_error("invalid armor/shield modifier");
} }
if (ends_with(token, "def")) { if (phosg::ends_with(token, "def")) {
ret.data1w[3] = static_cast<uint16_t>(stol(token.substr(1, token.size() - 4), nullptr, 10)); ret.data1w[3] = static_cast<uint16_t>(stol(token.substr(1, token.size() - 4), nullptr, 10));
} else if (ends_with(token, "evp")) { } else if (phosg::ends_with(token, "evp")) {
ret.data1w[4] = static_cast<uint16_t>(stol(token.substr(1, token.size() - 4), nullptr, 10)); ret.data1w[4] = static_cast<uint16_t>(stol(token.substr(1, token.size() - 4), nullptr, 10));
} else { } else {
ret.data1[5] = stoul(token.substr(1), nullptr, 10); ret.data1[5] = stoul(token.substr(1), nullptr, 10);
@@ -565,11 +565,11 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
} }
} else if (ret.data1[0] == 0x02) { } else if (ret.data1[0] == 0x02) {
for (const auto& token : split(desc, ' ')) { for (const auto& token : phosg::split(desc, ' ')) {
if (token.empty()) { if (token.empty()) {
continue; continue;
} else if (starts_with(token, "pb:")) { // Photon blasts } else if (phosg::starts_with(token, "pb:")) { // Photon blasts
auto pb_tokens = split(token.substr(3), ','); auto pb_tokens = phosg::split(token.substr(3), ',');
if (pb_tokens.size() > 3) { if (pb_tokens.size() > 3) {
throw runtime_error("too many photon blasts specified"); throw runtime_error("too many photon blasts specified");
} }
@@ -586,17 +586,17 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
for (const auto& pb_token : pb_tokens) { for (const auto& pb_token : pb_tokens) {
ret.add_mag_photon_blast(name_to_pb_num.at(pb_token)); ret.add_mag_photon_blast(name_to_pb_num.at(pb_token));
} }
} else if (ends_with(token, "%")) { // Synchro } else if (phosg::ends_with(token, "%")) { // Synchro
ret.data2[0] = stoul(token.substr(0, token.size() - 1), nullptr, 10); ret.data2[0] = stoul(token.substr(0, token.size() - 1), nullptr, 10);
} else if (ends_with(token, "iq")) { // IQ } else if (phosg::ends_with(token, "iq")) { // IQ
ret.data2[1] = stoul(token.substr(0, token.size() - 2), nullptr, 10); ret.data2[1] = stoul(token.substr(0, token.size() - 2), nullptr, 10);
} else if (!token.empty() && isdigit(token[0])) { // Stats } else if (!token.empty() && isdigit(token[0])) { // Stats
auto s_tokens = split(token, '/'); auto s_tokens = phosg::split(token, '/');
if (s_tokens.size() != 4) { if (s_tokens.size() != 4) {
throw runtime_error("incorrect stat count"); throw runtime_error("incorrect stat count");
} }
for (size_t z = 0; z < 4; z++) { for (size_t z = 0; z < 4; z++) {
auto n_tokens = split(s_tokens[z], '.'); auto n_tokens = phosg::split(s_tokens[z], '.');
if (n_tokens.size() == 0 || n_tokens.size() > 2) { if (n_tokens.size() == 0 || n_tokens.size() > 2) {
throw logic_error("incorrect stats argument format"); throw logic_error("incorrect stats argument format");
} else if ((n_tokens.size() == 1) || (n_tokens[1].size() == 0)) { } else if ((n_tokens.size() == 1) || (n_tokens[1].size() == 0)) {
@@ -620,7 +620,7 @@ ItemData ItemNameIndex::parse_item_description_phase(const std::string& descript
} }
} else if (ret.data1[0] == 0x03) { } else if (ret.data1[0] == 0x03) {
if (ret.max_stack_size(*this->limits) > 1) { if (ret.max_stack_size(*this->limits) > 1) {
if (starts_with(desc, "x")) { if (phosg::starts_with(desc, "x")) {
ret.data1[5] = stoul(desc.substr(1), nullptr, 10); ret.data1[5] = stoul(desc.substr(1), nullptr, 10);
} else { } else {
ret.data1[5] = 1; ret.data1[5] = 1;
@@ -650,7 +650,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
for (size_t data1_1 = 0; data1_1 < pmt->num_weapon_classes; data1_1++) { for (size_t data1_1 = 0; data1_1 < pmt->num_weapon_classes; data1_1++) {
uint8_t v1_replacement = pmt->get_weapon_v1_replacement(data1_1); uint8_t v1_replacement = pmt->get_weapon_v1_replacement(data1_1);
float sale_divisor = pmt->get_sale_divisor(0x00, data1_1); float sale_divisor = pmt->get_sale_divisor(0x00, data1_1);
string divisor_str = string_printf("%g", sale_divisor); string divisor_str = phosg::string_printf("%g", sale_divisor);
divisor_str.resize(13, ' '); divisor_str.resize(13, ' ');
size_t data1_2_limit = pmt->num_weapons_in_class(data1_1); size_t data1_2_limit = pmt->num_weapons_in_class(data1_1);
@@ -708,7 +708,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
fprintf(stream, "ARMOR => ---ID--- TYPE SKIN POINTS -DFP- -EVP- BP BE FLAG LVL EFR ETH EIC EDK ELT DFR EVR SB TB -A2- ST* ---DIVISOR--- NAME\n"); fprintf(stream, "ARMOR => ---ID--- TYPE SKIN POINTS -DFP- -EVP- BP BE FLAG LVL EFR ETH EIC EDK ELT DFR EVR SB TB -A2- ST* ---DIVISOR--- NAME\n");
for (size_t data1_1 = 1; data1_1 < 3; data1_1++) { for (size_t data1_1 = 1; data1_1 < 3; data1_1++) {
float sale_divisor = pmt->get_sale_divisor(0x01, data1_1); float sale_divisor = pmt->get_sale_divisor(0x01, data1_1);
string divisor_str = string_printf("%g", sale_divisor); string divisor_str = phosg::string_printf("%g", sale_divisor);
divisor_str.resize(13, ' '); divisor_str.resize(13, ' ');
size_t data1_2_limit = pmt->num_armors_or_shields_in_class(data1_1); size_t data1_2_limit = pmt->num_armors_or_shields_in_class(data1_1);
@@ -754,7 +754,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
fprintf(stream, "UNIT => ---ID--- TYPE SKIN POINTS STAT COUNT ST-MOD ST* ---DIVISOR--- NAME\n"); fprintf(stream, "UNIT => ---ID--- TYPE SKIN POINTS STAT COUNT ST-MOD ST* ---DIVISOR--- NAME\n");
{ {
float sale_divisor = pmt->get_sale_divisor(0x01, 0x03); float sale_divisor = pmt->get_sale_divisor(0x01, 0x03);
string divisor_str = string_printf("%g", sale_divisor); string divisor_str = phosg::string_printf("%g", sale_divisor);
divisor_str.resize(13, ' '); divisor_str.resize(13, ' ');
size_t data1_2_limit = pmt->num_units(); size_t data1_2_limit = pmt->num_units();
@@ -791,7 +791,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
uint8_t stars = pmt->get_item_stars(m.base.id); uint8_t stars = pmt->get_item_stars(m.base.id);
float sale_divisor = pmt->get_sale_divisor(0x02, data1_1); float sale_divisor = pmt->get_sale_divisor(0x02, data1_1);
string divisor_str = string_printf("%g", sale_divisor); string divisor_str = phosg::string_printf("%g", sale_divisor);
divisor_str.resize(13, ' '); divisor_str.resize(13, ' ');
ItemData item; ItemData item;
@@ -827,7 +827,7 @@ void ItemNameIndex::print_table(FILE* stream) const {
fprintf(stream, "TOOL => ---ID--- TYPE SKIN POINTS COUNT TECH -COST- ITEMFLAG ST* ---DIVISOR--- NAME\n"); fprintf(stream, "TOOL => ---ID--- TYPE SKIN POINTS COUNT TECH -COST- ITEMFLAG ST* ---DIVISOR--- NAME\n");
for (size_t data1_1 = 0; data1_1 < pmt->num_tool_classes; data1_1++) { for (size_t data1_1 = 0; data1_1 < pmt->num_tool_classes; data1_1++) {
float sale_divisor = pmt->get_sale_divisor(0x03, data1_1); float sale_divisor = pmt->get_sale_divisor(0x03, data1_1);
string divisor_str = string_printf("%g", sale_divisor); string divisor_str = phosg::string_printf("%g", sale_divisor);
divisor_str.resize(13, ' '); divisor_str.resize(13, ' ');
size_t data1_2_limit = pmt->num_tools_in_class(data1_1); size_t data1_2_limit = pmt->num_tools_in_class(data1_1);
+29 -31
View File
@@ -206,8 +206,8 @@ ItemParameterTable::WeaponV4 ItemParameterTable::WeaponGCNTE::to_v4() const {
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
ItemParameterTable::WeaponV4 ItemParameterTable::WeaponV3T<IsBigEndian>::to_v4() const { ItemParameterTable::WeaponV4 ItemParameterTable::WeaponV3T<BE>::to_v4() const {
WeaponV4 ret; WeaponV4 ret;
ret.base.id = this->base.id.load(); ret.base.id = this->base.id.load();
ret.base.type = this->base.type.load(); ret.base.type = this->base.type.load();
@@ -281,8 +281,8 @@ ItemParameterTable::ArmorOrShieldV4 ItemParameterTable::ArmorOrShieldV1V2::to_v4
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
ItemParameterTable::ArmorOrShieldV4 ItemParameterTable::ArmorOrShieldV3T<IsBigEndian>::to_v4() const { ItemParameterTable::ArmorOrShieldV4 ItemParameterTable::ArmorOrShieldV3T<BE>::to_v4() const {
ArmorOrShieldV4 ret; ArmorOrShieldV4 ret;
ret.base.id = this->base.id.load(); ret.base.id = this->base.id.load();
ret.base.type = this->base.type.load(); ret.base.type = this->base.type.load();
@@ -323,8 +323,8 @@ ItemParameterTable::UnitV4 ItemParameterTable::UnitV1V2::to_v4() const {
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
ItemParameterTable::UnitV4 ItemParameterTable::UnitV3T<IsBigEndian>::to_v4() const { ItemParameterTable::UnitV4 ItemParameterTable::UnitV3T<BE>::to_v4() const {
UnitV4 ret; UnitV4 ret;
ret.base.id = this->base.id.load(); ret.base.id = this->base.id.load();
ret.base.type = this->base.type.load(); ret.base.type = this->base.type.load();
@@ -370,8 +370,8 @@ ItemParameterTable::MagV4 ItemParameterTable::MagV2::to_v4() const {
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
ItemParameterTable::MagV4 ItemParameterTable::MagV3T<IsBigEndian>::to_v4() const { ItemParameterTable::MagV4 ItemParameterTable::MagV3T<BE>::to_v4() const {
MagV4 ret; MagV4 ret;
ret.base.id = this->base.id.load(); ret.base.id = this->base.id.load();
ret.base.type = this->base.type.load(); ret.base.type = this->base.type.load();
@@ -401,8 +401,8 @@ ItemParameterTable::ToolV4 ItemParameterTable::ToolV1V2::to_v4() const {
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
ItemParameterTable::ToolV4 ItemParameterTable::ToolV3T<IsBigEndian>::to_v4() const { ItemParameterTable::ToolV4 ItemParameterTable::ToolV3T<BE>::to_v4() const {
ToolV4 ret; ToolV4 ret;
ret.base.id = this->base.id.load(); ret.base.id = this->base.id.load();
ret.base.type = this->base.type.load(); ret.base.type = this->base.type.load();
@@ -414,15 +414,15 @@ ItemParameterTable::ToolV4 ItemParameterTable::ToolV3T<IsBigEndian>::to_v4() con
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
size_t indirect_lookup_2d_count(const StringReader& r, size_t root_offset, size_t co_index) { size_t indirect_lookup_2d_count(const phosg::StringReader& r, size_t root_offset, size_t co_index) {
using ArrayRefT = typename std::conditional_t<IsBigEndian, ItemParameterTable::ArrayRefBE, ItemParameterTable::ArrayRef>; using ArrayRefT = typename std::conditional_t<BE, ItemParameterTable::ArrayRefBE, ItemParameterTable::ArrayRef>;
return r.pget<ArrayRefT>(root_offset + sizeof(ArrayRefT) * co_index).count; return r.pget<ArrayRefT>(root_offset + sizeof(ArrayRefT) * co_index).count;
} }
template <typename T, bool IsBigEndian> template <typename T, bool BE>
const T& indirect_lookup_2d(const StringReader& r, size_t root_offset, size_t co_index, size_t item_index) { const T& indirect_lookup_2d(const phosg::StringReader& r, size_t root_offset, size_t co_index, size_t item_index) {
using ArrayRefT = typename std::conditional_t<IsBigEndian, ItemParameterTable::ArrayRefBE, ItemParameterTable::ArrayRef>; using ArrayRefT = typename std::conditional_t<BE, ItemParameterTable::ArrayRefBE, ItemParameterTable::ArrayRef>;
const auto& co = r.pget<ArrayRefT>(root_offset + sizeof(ArrayRefT) * co_index); const auto& co = r.pget<ArrayRefT>(root_offset + sizeof(ArrayRefT) * co_index);
if (item_index >= co.count) { if (item_index >= co.count) {
@@ -706,10 +706,10 @@ const ItemParameterTable::ToolV4& ItemParameterTable::get_tool(uint8_t data1_1,
} }
} }
template <typename ToolDefT, bool IsBigEndian> template <typename ToolDefT, bool BE>
pair<uint8_t, uint8_t> ItemParameterTable::find_tool_by_id_t(uint32_t tool_table_offset, uint32_t item_id) const { pair<uint8_t, uint8_t> ItemParameterTable::find_tool_by_id_t(uint32_t tool_table_offset, uint32_t item_id) const {
const auto* cos = &this->r.pget<ArrayRefT<IsBigEndian>>( const auto* cos = &this->r.pget<ArrayRefT<BE>>(
tool_table_offset, this->num_tool_classes * sizeof(ArrayRefT<IsBigEndian>)); tool_table_offset, this->num_tool_classes * sizeof(ArrayRefT<BE>));
for (size_t z = 0; z < this->num_tool_classes; z++) { for (size_t z = 0; z < this->num_tool_classes; z++) {
const auto& co = cos[z]; const auto& co = cos[z];
const auto* defs = &this->r.pget<ToolDefT>(co.offset, sizeof(ToolDefT) * co.count); const auto* defs = &this->r.pget<ToolDefT>(co.offset, sizeof(ToolDefT) * co.count);
@@ -719,7 +719,7 @@ pair<uint8_t, uint8_t> ItemParameterTable::find_tool_by_id_t(uint32_t tool_table
} }
} }
} }
throw out_of_range(string_printf("invalid tool class %08" PRIX32, item_id)); throw out_of_range(phosg::string_printf("invalid tool class %08" PRIX32, item_id));
} }
pair<uint8_t, uint8_t> ItemParameterTable::find_tool_by_id(uint32_t item_id) const { pair<uint8_t, uint8_t> ItemParameterTable::find_tool_by_id(uint32_t item_id) const {
@@ -740,19 +740,17 @@ pair<uint8_t, uint8_t> ItemParameterTable::find_tool_by_id(uint32_t item_id) con
} }
} }
template <bool IsBigEndian, typename OffsetsT> template <bool BE, typename OffsetsT>
float ItemParameterTable::get_sale_divisor_t(const OffsetsT* offsets, uint8_t data1_0, uint8_t data1_1) const { float ItemParameterTable::get_sale_divisor_t(const OffsetsT* offsets, uint8_t data1_0, uint8_t data1_1) const {
using FloatT = typename std::conditional<IsBigEndian, be_float, le_float>::type;
switch (data1_0) { switch (data1_0) {
case 0: case 0:
if (data1_1 >= this->num_weapon_classes) { if (data1_1 >= this->num_weapon_classes) {
return 0.0f; return 0.0f;
} }
return this->r.pget<FloatT>(offsets->weapon_sale_divisor_table + data1_1 * sizeof(FloatT)); return this->r.pget<F32T<BE>>(offsets->weapon_sale_divisor_table + data1_1 * sizeof(F32T<BE>));
case 1: { case 1: {
const auto& divisors = this->r.pget<NonWeaponSaleDivisorsT<IsBigEndian>>(offsets->sale_divisor_table); const auto& divisors = this->r.pget<NonWeaponSaleDivisorsT<BE>>(offsets->sale_divisor_table);
switch (data1_1) { switch (data1_1) {
case 1: case 1:
return divisors.armor_divisor; return divisors.armor_divisor;
@@ -765,7 +763,7 @@ float ItemParameterTable::get_sale_divisor_t(const OffsetsT* offsets, uint8_t da
} }
case 2: { case 2: {
const auto& divisors = this->r.pget<NonWeaponSaleDivisorsT<IsBigEndian>>(offsets->sale_divisor_table); const auto& divisors = this->r.pget<NonWeaponSaleDivisorsT<BE>>(offsets->sale_divisor_table);
return divisors.mag_divisor; return divisors.mag_divisor;
} }
@@ -1136,9 +1134,9 @@ const std::map<uint32_t, std::vector<ItemParameterTable::ItemCombination>>& Item
return this->item_combination_index; return this->item_combination_index;
} }
template <bool IsBigEndian> template <bool BE>
size_t ItemParameterTable::num_events_t(uint32_t base_offset) const { size_t ItemParameterTable::num_events_t(uint32_t base_offset) const {
return this->r.pget<ArrayRefT<IsBigEndian>>(base_offset).count; return this->r.pget<ArrayRefT<BE>>(base_offset).count;
} }
size_t ItemParameterTable::num_events() const { size_t ItemParameterTable::num_events() const {
@@ -1155,14 +1153,14 @@ size_t ItemParameterTable::num_events() const {
} }
} }
template <bool IsBigEndian> template <bool BE>
std::pair<const ItemParameterTable::EventItem*, size_t> ItemParameterTable::get_event_items_t( std::pair<const ItemParameterTable::EventItem*, size_t> ItemParameterTable::get_event_items_t(
uint32_t base_offset, uint8_t event_number) const { uint32_t base_offset, uint8_t event_number) const {
const auto& co = this->r.pget<ArrayRefT<IsBigEndian>>(base_offset); const auto& co = this->r.pget<ArrayRefT<BE>>(base_offset);
if (event_number >= co.count) { if (event_number >= co.count) {
throw out_of_range("invalid event number"); throw out_of_range("invalid event number");
} }
const auto& event_co = this->r.pget<ArrayRefT<IsBigEndian>>(co.offset + sizeof(ArrayRefT<IsBigEndian>) * event_number); const auto& event_co = this->r.pget<ArrayRefT<BE>>(co.offset + sizeof(ArrayRefT<BE>) * event_number);
const auto* defs = &this->r.pget<EventItem>(event_co.offset, event_co.count * sizeof(EventItem)); const auto* defs = &this->r.pget<EventItem>(event_co.offset, event_co.count * sizeof(EventItem));
return make_pair(defs, event_co.count); return make_pair(defs, event_co.count);
} }
+101 -122
View File
@@ -11,6 +11,7 @@
#include "ItemData.hh" #include "ItemData.hh"
#include "Text.hh" #include "Text.hh"
#include "Types.hh"
class ItemParameterTable { class ItemParameterTable {
public: public:
@@ -18,11 +19,10 @@ public:
// functions instead of manually branching on various offset table pointers // functions instead of manually branching on various offset table pointers
// being null or not in each public function. Rewrite this and make it better. // being null or not in each public function. Rewrite this and make it better.
template <bool IsBigEndian> template <bool BE>
struct ArrayRefT { struct ArrayRefT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; /* 00 */ U32T<BE> count;
/* 00 */ U32T count; /* 04 */ U32T<BE> offset;
/* 04 */ U32T offset;
/* 08 */ /* 08 */
} __packed__; } __packed__;
@@ -31,25 +31,22 @@ public:
check_struct_size(ArrayRef, 8); check_struct_size(ArrayRef, 8);
check_struct_size(ArrayRefBE, 8); check_struct_size(ArrayRefBE, 8);
template <bool IsBigEndian> template <bool BE>
struct ItemBaseV2T { struct ItemBaseV2T {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
// id specifies several things; notably, it doubles as the index of the // id specifies several things; notably, it doubles as the index of the
// item's name in the text archive (e.g. TextEnglish) collection 0. // item's name in the text archive (e.g. TextEnglish) collection 0.
/* 00 */ U32T id = 0xFFFFFFFF; /* 00 */ U32T<BE> id = 0xFFFFFFFF;
/* 04 */ /* 04 */
} __packed__; } __packed__;
template <bool IsBigEndian> template <bool BE>
struct ItemBaseV3T : ItemBaseV2T<IsBigEndian> { struct ItemBaseV3T : ItemBaseV2T<BE> {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; /* 04 */ U16T<BE> type = 0;
/* 04 */ U16T type = 0; /* 06 */ U16T<BE> skin = 0;
/* 06 */ U16T skin = 0;
/* 08 */ /* 08 */
} __packed__; } __packed__;
template <bool IsBigEndian> template <bool BE>
struct ItemBaseV4T : ItemBaseV3T<IsBigEndian> { struct ItemBaseV4T : ItemBaseV3T<BE> {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; /* 08 */ U32T<BE> team_points = 0;
/* 08 */ U32T team_points = 0;
/* 0C */ /* 0C */
} __packed__; } __packed__;
@@ -118,17 +115,16 @@ public:
WeaponV4 to_v4() const; WeaponV4 to_v4() const;
} __packed_ws__(WeaponGCNTE, 0x24); } __packed_ws__(WeaponGCNTE, 0x24);
template <bool IsBigEndian> template <bool BE>
struct WeaponV3T { struct WeaponV3T {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; /* 00 */ ItemBaseV3T<BE> base;
/* 00 */ ItemBaseV3T<IsBigEndian> base; /* 08 */ U16T<BE> class_flags = 0;
/* 08 */ U16T class_flags = 0; /* 0A */ U16T<BE> atp_min = 0;
/* 0A */ U16T atp_min = 0; /* 0C */ U16T<BE> atp_max = 0;
/* 0C */ U16T atp_max = 0; /* 0E */ U16T<BE> atp_required = 0;
/* 0E */ U16T atp_required = 0; /* 10 */ U16T<BE> mst_required = 0;
/* 10 */ U16T mst_required = 0; /* 12 */ U16T<BE> ata_required = 0;
/* 12 */ U16T ata_required = 0; /* 14 */ U16T<BE> mst = 0;
/* 14 */ U16T mst = 0;
/* 16 */ uint8_t max_grind = 0; /* 16 */ uint8_t max_grind = 0;
/* 17 */ uint8_t photon = 0; /* 17 */ uint8_t photon = 0;
/* 18 */ uint8_t special = 0; /* 18 */ uint8_t special = 0;
@@ -187,16 +183,15 @@ public:
/* 2C */ /* 2C */
} __packed_ws__(WeaponV4, 0x2C); } __packed_ws__(WeaponV4, 0x2C);
template <typename BaseT, bool IsBigEndian> template <typename BaseT, bool BE>
struct ArmorOrShieldT { struct ArmorOrShieldT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
/* V1/V2 offsets */ /* V1/V2 offsets */
/* 00 */ BaseT base; /* 00 */ BaseT base;
/* 04 */ U16T dfp = 0; /* 04 */ U16T<BE> dfp = 0;
/* 06 */ U16T evp = 0; /* 06 */ U16T<BE> evp = 0;
/* 08 */ uint8_t block_particle = 0; /* 08 */ uint8_t block_particle = 0;
/* 09 */ uint8_t block_effect = 0; /* 09 */ uint8_t block_effect = 0;
/* 0A */ U16T class_flags = 0x00FF; /* 0A */ U16T<BE> class_flags = 0x00FF;
/* 0C */ uint8_t required_level = 0; /* 0C */ uint8_t required_level = 0;
/* 0D */ uint8_t efr = 0; /* 0D */ uint8_t efr = 0;
/* 0E */ uint8_t eth = 0; /* 0E */ uint8_t eth = 0;
@@ -208,12 +203,11 @@ public:
/* 14 */ /* 14 */
} __packed__; } __packed__;
template <typename BaseT, bool IsBigEndian> template <typename BaseT, bool BE>
struct ArmorOrShieldFinalT : ArmorOrShieldT<BaseT, IsBigEndian> { struct ArmorOrShieldFinalT : ArmorOrShieldT<BaseT, BE> {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
/* 14 */ uint8_t stat_boost = 0; /* 14 */ uint8_t stat_boost = 0;
/* 15 */ uint8_t tech_boost = 0; /* 15 */ uint8_t tech_boost = 0;
/* 16 */ U16T unknown_a2 = 0; /* 16 */ U16T<BE> unknown_a2 = 0;
/* 18 */ /* 18 */
} __packed__; } __packed__;
using ArmorOrShieldV4 = ArmorOrShieldFinalT<ItemBaseV4T<false>, false>; using ArmorOrShieldV4 = ArmorOrShieldFinalT<ItemBaseV4T<false>, false>;
@@ -225,8 +219,8 @@ public:
struct ArmorOrShieldV1V2 : ArmorOrShieldFinalT<ItemBaseV2T<false>, false> { struct ArmorOrShieldV1V2 : ArmorOrShieldFinalT<ItemBaseV2T<false>, false> {
ArmorOrShieldV4 to_v4() const; ArmorOrShieldV4 to_v4() const;
} __packed_ws__(ArmorOrShieldV1V2, 0x18); } __packed_ws__(ArmorOrShieldV1V2, 0x18);
template <bool IsBigEndian> template <bool BE>
struct ArmorOrShieldV3T : ArmorOrShieldFinalT<ItemBaseV3T<IsBigEndian>, IsBigEndian> { struct ArmorOrShieldV3T : ArmorOrShieldFinalT<ItemBaseV3T<BE>, BE> {
ArmorOrShieldV4 to_v4() const; ArmorOrShieldV4 to_v4() const;
} __packed__; } __packed__;
using ArmorOrShieldV3 = ArmorOrShieldV3T<false>; using ArmorOrShieldV3 = ArmorOrShieldV3T<false>;
@@ -234,21 +228,18 @@ public:
check_struct_size(ArmorOrShieldV3, 0x1C); check_struct_size(ArmorOrShieldV3, 0x1C);
check_struct_size(ArmorOrShieldV3BE, 0x1C); check_struct_size(ArmorOrShieldV3BE, 0x1C);
template <typename BaseT, bool IsBigEndian> template <typename BaseT, bool BE>
struct UnitT { struct UnitT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using S16T = typename std::conditional<IsBigEndian, be_int16_t, le_int16_t>::type;
/* V1/V2 offsets */ /* V1/V2 offsets */
/* 00 */ BaseT base; /* 00 */ BaseT base;
/* 04 */ U16T stat = 0; /* 04 */ U16T<BE> stat = 0;
/* 06 */ U16T stat_amount = 0; /* 06 */ U16T<BE> stat_amount = 0;
/* 08 */ /* 08 */
} __packed__; } __packed__;
template <typename BaseT, bool IsBigEndian> template <typename BaseT, bool BE>
struct UnitFinalT : UnitT<BaseT, IsBigEndian> { struct UnitFinalT : UnitT<BaseT, BE> {
using S16T = typename std::conditional<IsBigEndian, be_int16_t, le_int16_t>::type; /* 08 */ S16T<BE> modifier_amount = 0;
/* 08 */ S16T modifier_amount = 0;
/* 0A */ parray<uint8_t, 2> unused; /* 0A */ parray<uint8_t, 2> unused;
/* 0C */ /* 0C */
} __packed__; } __packed__;
@@ -260,8 +251,8 @@ public:
struct UnitV1V2 : UnitFinalT<ItemBaseV2T<false>, false> { struct UnitV1V2 : UnitFinalT<ItemBaseV2T<false>, false> {
UnitV4 to_v4() const; UnitV4 to_v4() const;
} __packed_ws__(UnitV1V2, 0x0C); } __packed_ws__(UnitV1V2, 0x0C);
template <bool IsBigEndian> template <bool BE>
struct UnitV3T : UnitFinalT<ItemBaseV3T<IsBigEndian>, IsBigEndian> { struct UnitV3T : UnitFinalT<ItemBaseV3T<BE>, BE> {
UnitV4 to_v4() const; UnitV4 to_v4() const;
} __packed__; } __packed__;
using UnitV3 = UnitV3T<false>; using UnitV3 = UnitV3T<false>;
@@ -269,12 +260,11 @@ public:
check_struct_size(UnitV3, 0x10); check_struct_size(UnitV3, 0x10);
check_struct_size(UnitV3BE, 0x10); check_struct_size(UnitV3BE, 0x10);
template <typename BaseT, bool IsBigEndian> template <typename BaseT, bool BE>
struct MagT { struct MagT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
/* V1/V2 offsets */ /* V1/V2 offsets */
/* 00 */ BaseT base; /* 00 */ BaseT base;
/* 04 */ U16T feed_table = 0; /* 04 */ U16T<BE> feed_table = 0;
/* 06 */ uint8_t photon_blast = 0; /* 06 */ uint8_t photon_blast = 0;
/* 07 */ uint8_t activation = 0; /* 07 */ uint8_t activation = 0;
/* 08 */ uint8_t on_pb_full = 0; /* 08 */ uint8_t on_pb_full = 0;
@@ -317,10 +307,9 @@ public:
MagV4 to_v4() const; MagV4 to_v4() const;
} __packed_ws__(MagV2, 0x14); } __packed_ws__(MagV2, 0x14);
template <bool IsBigEndian> template <bool BE>
struct MagV3T : MagT<ItemBaseV3T<IsBigEndian>, IsBigEndian> { struct MagV3T : MagT<ItemBaseV3T<BE>, BE> {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; /* 10 */ U16T<BE> class_flags = 0x00FF;
/* 10 */ U16T class_flags = 0x00FF;
/* 12 */ parray<uint8_t, 2> unused; /* 12 */ parray<uint8_t, 2> unused;
/* 14 */ /* 14 */
@@ -331,16 +320,13 @@ public:
check_struct_size(MagV3, 0x18); check_struct_size(MagV3, 0x18);
check_struct_size(MagV3BE, 0x18); check_struct_size(MagV3BE, 0x18);
template <typename BaseT, bool IsBigEndian> template <typename BaseT, bool BE>
struct ToolT { struct ToolT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using S32T = typename std::conditional<IsBigEndian, be_int32_t, le_int32_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
/* V1/V2 offsets */ /* V1/V2 offsets */
/* 00 */ BaseT base; /* 00 */ BaseT base;
/* 04 */ U16T amount = 0; /* 04 */ U16T<BE> amount = 0;
/* 06 */ U16T tech = 0; /* 06 */ U16T<BE> tech = 0;
/* 08 */ S32T cost = 0; /* 08 */ S32T<BE> cost = 0;
// Bits in item_flags: // Bits in item_flags:
// 00000001 - ever usable by player ("Use" appears in inventory menu) // 00000001 - ever usable by player ("Use" appears in inventory menu)
// 00000002 - unknown // 00000002 - unknown
@@ -350,7 +336,7 @@ public:
// 00000020 - usable in boss arenas // 00000020 - usable in boss arenas
// 00000040 - usable in Challenge mode // 00000040 - usable in Challenge mode
// 00000080 - is rare (renders as red box; V3+) // 00000080 - is rare (renders as red box; V3+)
/* 0C */ U32T item_flags = 0; /* 0C */ U32T<BE> item_flags = 0;
/* 10 */ /* 10 */
} __packed__; } __packed__;
@@ -359,8 +345,8 @@ public:
struct ToolV1V2 : ToolT<ItemBaseV2T<false>, false> { struct ToolV1V2 : ToolT<ItemBaseV2T<false>, false> {
ToolV4 to_v4() const; ToolV4 to_v4() const;
} __packed_ws__(ToolV1V2, 0x10); } __packed_ws__(ToolV1V2, 0x10);
template <bool IsBigEndian> template <bool BE>
struct ToolV3T : ToolT<ItemBaseV3T<IsBigEndian>, IsBigEndian> { struct ToolV3T : ToolT<ItemBaseV3T<BE>, BE> {
ToolV4 to_v4() const; ToolV4 to_v4() const;
} __packed__; } __packed__;
using ToolV3 = ToolV3T<false>; using ToolV3 = ToolV3T<false>;
@@ -380,34 +366,31 @@ public:
using MagFeedResultsList = parray<MagFeedResult, 11>; using MagFeedResultsList = parray<MagFeedResult, 11>;
template <bool IsBigEndian> template <bool BE>
struct MagFeedResultsListOffsetsT { struct MagFeedResultsListOffsetsT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; parray<U32T<BE>, 8> offsets; // Offsets of MagFeedResultsList objects
parray<U32T, 8> offsets; // Offsets of MagFeedResultsList objects
} __packed__; } __packed__;
using MagFeedResultsListOffsets = MagFeedResultsListOffsetsT<false>; using MagFeedResultsListOffsets = MagFeedResultsListOffsetsT<false>;
using MagFeedResultsListOffsetsBE = MagFeedResultsListOffsetsT<true>; using MagFeedResultsListOffsetsBE = MagFeedResultsListOffsetsT<true>;
check_struct_size(MagFeedResultsListOffsets, 0x20); check_struct_size(MagFeedResultsListOffsets, 0x20);
check_struct_size(MagFeedResultsListOffsetsBE, 0x20); check_struct_size(MagFeedResultsListOffsetsBE, 0x20);
template <bool IsBigEndian> template <bool BE>
struct SpecialT { struct SpecialT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; U16T<BE> type = 0xFFFF;
U16T type = 0xFFFF; U16T<BE> amount = 0;
U16T amount = 0;
} __packed__; } __packed__;
using Special = SpecialT<false>; using Special = SpecialT<false>;
using SpecialBE = SpecialT<true>; using SpecialBE = SpecialT<true>;
check_struct_size(Special, 4); check_struct_size(Special, 4);
check_struct_size(SpecialBE, 4); check_struct_size(SpecialBE, 4);
template <bool IsBigEndian> template <bool BE>
struct StatBoostT { struct StatBoostT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
uint8_t stat1 = 0; uint8_t stat1 = 0;
uint8_t stat2 = 0; uint8_t stat2 = 0;
U16T amount1 = 0; U16T<BE> amount1 = 0;
U16T amount2 = 0; U16T<BE> amount2 = 0;
} __packed__; } __packed__;
using StatBoost = StatBoostT<false>; using StatBoost = StatBoostT<false>;
using StatBoostBE = StatBoostT<true>; using StatBoostBE = StatBoostT<true>;
@@ -428,16 +411,14 @@ public:
parray<uint8_t, 3> unused; parray<uint8_t, 3> unused;
} __packed_ws__(ItemCombination, 0x10); } __packed_ws__(ItemCombination, 0x10);
template <bool IsBigEndian> template <bool BE>
struct TechniqueBoostT { struct TechniqueBoostT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; U32T<BE> tech1 = 0;
using FloatT = typename std::conditional<IsBigEndian, be_float, le_float>::type; F32T<BE> boost1 = 0.0f;
U32T tech1 = 0; U32T<BE> tech2 = 0;
FloatT boost1 = 0.0f; F32T<BE> boost2 = 0.0f;
U32T tech2 = 0; U32T<BE> tech3 = 0;
FloatT boost2 = 0.0f; F32T<BE> boost3 = 0.0f;
U32T tech3 = 0;
FloatT boost3 = 0.0f;
} __packed__; } __packed__;
using TechniqueBoost = TechniqueBoostT<false>; using TechniqueBoost = TechniqueBoostT<false>;
using TechniqueBoostBE = TechniqueBoostT<true>; using TechniqueBoostBE = TechniqueBoostT<true>;
@@ -454,13 +435,12 @@ public:
uint8_t unused = 0; uint8_t unused = 0;
} __packed_ws__(UnsealableItem, 4); } __packed_ws__(UnsealableItem, 4);
template <bool IsBigEndian> template <bool BE>
struct NonWeaponSaleDivisorsT { struct NonWeaponSaleDivisorsT {
using FloatT = typename std::conditional<IsBigEndian, be_float, le_float>::type; F32T<BE> armor_divisor = 0.0f;
FloatT armor_divisor = 0.0f; F32T<BE> shield_divisor = 0.0f;
FloatT shield_divisor = 0.0f; F32T<BE> unit_divisor = 0.0f;
FloatT unit_divisor = 0.0f; F32T<BE> mag_divisor = 0.0f;
FloatT mag_divisor = 0.0f;
} __packed__; } __packed__;
using NonWeaponSaleDivisors = NonWeaponSaleDivisorsT<false>; using NonWeaponSaleDivisors = NonWeaponSaleDivisorsT<false>;
using NonWeaponSaleDivisorsBE = NonWeaponSaleDivisorsT<true>; using NonWeaponSaleDivisorsBE = NonWeaponSaleDivisorsT<true>;
@@ -587,33 +567,32 @@ private:
/* 4C / 6B1C */ be_uint32_t tech_boost_table; // -> [TechniqueBoost] (always 0x2C of them? from counts struct?) /* 4C / 6B1C */ be_uint32_t tech_boost_table; // -> [TechniqueBoost] (always 0x2C of them? from counts struct?)
} __packed_ws__(TableOffsetsGCNTE, 0x50); } __packed_ws__(TableOffsetsGCNTE, 0x50);
template <bool IsBigEndian> template <bool BE>
struct TableOffsetsV3V4T { struct TableOffsetsV3V4T {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
/* ## / GC / BB */ /* ## / GC / BB */
/* 00 / F078 / 14884 */ U32T weapon_table; // -> [{count, offset -> [WeaponV3/WeaponV4]}](0xED) /* 00 / F078 / 14884 */ U32T<BE> weapon_table; // -> [{count, offset -> [WeaponV3/WeaponV4]}](0xED)
/* 04 / EF90 / 1478C */ U32T armor_table; // -> [{count, offset -> [ArmorOrShieldV3/ArmorOrShieldV4]}](2; armors and shields) /* 04 / EF90 / 1478C */ U32T<BE> armor_table; // -> [{count, offset -> [ArmorOrShieldV3/ArmorOrShieldV4]}](2; armors and shields)
/* 08 / EFA0 / 1479C */ U32T unit_table; // -> {count, offset -> [UnitV3/UnitV4]} (last if out of range) /* 08 / EFA0 / 1479C */ U32T<BE> unit_table; // -> {count, offset -> [UnitV3/UnitV4]} (last if out of range)
/* 0C / EFB0 / 147AC */ U32T tool_table; // -> [{count, offset -> [ToolV3/ToolV4]}](0x1A) (last if out of range) /* 0C / EFB0 / 147AC */ U32T<BE> tool_table; // -> [{count, offset -> [ToolV3/ToolV4]}](0x1A) (last if out of range)
/* 10 / EFA8 / 147A4 */ U32T mag_table; // -> {count, offset -> [MagV3/MagV4]} /* 10 / EFA8 / 147A4 */ U32T<BE> mag_table; // -> {count, offset -> [MagV3/MagV4]}
/* 14 / B88C / 0F4B8 */ U32T v1_replacement_table; // -> [uint8_t](0xED) /* 14 / B88C / 0F4B8 */ U32T<BE> v1_replacement_table; // -> [uint8_t](0xED)
/* 18 / A7FC / 0DE7C */ U32T photon_color_table; // -> [0x24-byte structs](0x20) /* 18 / A7FC / 0DE7C */ U32T<BE> photon_color_table; // -> [0x24-byte structs](0x20)
/* 1C / AACC / 0E194 */ U32T weapon_range_table; // -> ??? /* 1C / AACC / 0E194 */ U32T<BE> weapon_range_table; // -> ???
/* 20 / B938 / 0F5A8 */ U32T weapon_sale_divisor_table; // -> [float](0xED) /* 20 / B938 / 0F5A8 */ U32T<BE> weapon_sale_divisor_table; // -> [float](0xED)
/* 24 / BBCC / 0F83C */ U32T sale_divisor_table; // -> NonWeaponSaleDivisors /* 24 / BBCC / 0F83C */ U32T<BE> sale_divisor_table; // -> NonWeaponSaleDivisors
/* 28 / F608 / 1502C */ U32T mag_feed_table; // -> MagFeedResultsTable /* 28 / F608 / 1502C */ U32T<BE> mag_feed_table; // -> MagFeedResultsTable
/* 2C / BE9C / 0FB0C */ U32T star_value_table; // -> [uint8_t](0x330) (indexed by .id from weapon, armor, etc.) /* 2C / BE9C / 0FB0C */ U32T<BE> star_value_table; // -> [uint8_t](0x330) (indexed by .id from weapon, armor, etc.)
/* 30 / C100 / 0FE3C */ U32T special_data_table; // -> [Special] /* 30 / C100 / 0FE3C */ U32T<BE> special_data_table; // -> [Special]
/* 34 / C1A4 / 0FEE0 */ U32T weapon_effect_table; // -> [16-byte structs] /* 34 / C1A4 / 0FEE0 */ U32T<BE> weapon_effect_table; // -> [16-byte structs]
/* 38 / DE50 / 1275C */ U32T stat_boost_table; // -> [StatBoost] /* 38 / DE50 / 1275C */ U32T<BE> stat_boost_table; // -> [StatBoost]
/* 3C / D6E4 / 11C80 */ U32T shield_effect_table; // -> [8-byte structs] /* 3C / D6E4 / 11C80 */ U32T<BE> shield_effect_table; // -> [8-byte structs]
/* 40 / DF88 / 12894 */ U32T max_tech_level_table; // -> MaxTechniqueLevels /* 40 / DF88 / 12894 */ U32T<BE> max_tech_level_table; // -> MaxTechniqueLevels
/* 44 / F5D0 / 14FF4 */ U32T combination_table; // -> {count, offset -> [ItemCombination]} /* 44 / F5D0 / 14FF4 */ U32T<BE> combination_table; // -> {count, offset -> [ItemCombination]}
/* 48 / DE48 / 12754 */ U32T unknown_a1; /* 48 / DE48 / 12754 */ U32T<BE> unknown_a1;
/* 4C / EB8C / 14278 */ U32T tech_boost_table; // -> [TechniqueBoost] (always 0x2C of them? from counts struct?) /* 4C / EB8C / 14278 */ U32T<BE> tech_boost_table; // -> [TechniqueBoost] (always 0x2C of them? from counts struct?)
/* 50 / F5F0 / 15014 */ U32T unwrap_table; // -> {count, offset -> [{count, offset -> [EventItem]}]} /* 50 / F5F0 / 15014 */ U32T<BE> unwrap_table; // -> {count, offset -> [{count, offset -> [EventItem]}]}
/* 54 / F5F8 / 1501C */ U32T unsealable_table; // -> {count, offset -> [UnsealableItem]} /* 54 / F5F8 / 1501C */ U32T<BE> unsealable_table; // -> {count, offset -> [UnsealableItem]}
/* 58 / F600 / 15024 */ U32T ranged_special_table; // -> {count, offset -> [4-byte structs]} /* 58 / F600 / 15024 */ U32T<BE> ranged_special_table; // -> {count, offset -> [4-byte structs]}
} __packed__; } __packed__;
using TableOffsetsV3V4 = TableOffsetsV3V4T<false>; using TableOffsetsV3V4 = TableOffsetsV3V4T<false>;
using TableOffsetsV3V4BE = TableOffsetsV3V4T<true>; using TableOffsetsV3V4BE = TableOffsetsV3V4T<true>;
@@ -622,7 +601,7 @@ private:
Version version; Version version;
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
StringReader r; phosg::StringReader r;
const TableOffsetsDCProtos* offsets_dc_protos; const TableOffsetsDCProtos* offsets_dc_protos;
const TableOffsetsV1V2* offsets_v1_v2; const TableOffsetsV1V2* offsets_v1_v2;
const TableOffsetsGCNTE* offsets_gc_nte; const TableOffsetsGCNTE* offsets_gc_nte;
@@ -644,13 +623,13 @@ private:
// equipped_item may contain wildcards, and the matching order matters. // equipped_item may contain wildcards, and the matching order matters.
mutable std::map<uint32_t, std::vector<ItemCombination>> item_combination_index; mutable std::map<uint32_t, std::vector<ItemCombination>> item_combination_index;
template <typename ToolDefT, bool IsBigEndian> template <typename ToolDefT, bool BE>
std::pair<uint8_t, uint8_t> find_tool_by_id_t(uint32_t tool_table_offset, uint32_t id) const; std::pair<uint8_t, uint8_t> find_tool_by_id_t(uint32_t tool_table_offset, uint32_t id) const;
template <bool IsBigEndian, typename OffsetsT> template <bool BE, typename OffsetsT>
float get_sale_divisor_t(const OffsetsT* offsets, uint8_t data1_0, uint8_t data1_1) const; float get_sale_divisor_t(const OffsetsT* offsets, uint8_t data1_0, uint8_t data1_1) const;
template <bool IsBigEndian> template <bool BE>
size_t num_events_t(uint32_t base_offset) const; size_t num_events_t(uint32_t base_offset) const;
template <bool IsBigEndian> template <bool BE>
std::pair<const ItemParameterTable::EventItem*, size_t> get_event_items_t(uint32_t base_offset, uint8_t event_number) const; std::pair<const ItemParameterTable::EventItem*, size_t> get_event_items_t(uint32_t base_offset, uint8_t event_number) const;
}; };
@@ -677,6 +656,6 @@ public:
private: private:
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
StringReader r; phosg::StringReader r;
const TableOffsets* offsets; const TableOffsets* offsets;
}; };
+9 -9
View File
@@ -54,13 +54,13 @@ LevelTableV2::LevelTableV2(const string& data, bool compressed) {
le_uint32_t unknown_a12; // -> u32[3] -> (0x14-byte struct)[0x0F] le_uint32_t unknown_a12; // -> u32[3] -> (0x14-byte struct)[0x0F]
} __packed_ws__(Offsets, 0x40); } __packed_ws__(Offsets, 0x40);
StringReader r; phosg::StringReader r;
string decompressed_data; string decompressed_data;
if (compressed) { if (compressed) {
decompressed_data = prs_decompress(data); decompressed_data = prs_decompress(data);
r = StringReader(decompressed_data); r = phosg::StringReader(decompressed_data);
} else { } else {
r = StringReader(data); r = phosg::StringReader(data);
} }
const auto& offsets = r.pget<Offsets>(r.pget_u32l(r.size() - 0x10)); const auto& offsets = r.pget<Offsets>(r.pget_u32l(r.size() - 0x10));
@@ -94,7 +94,7 @@ const LevelStatsDelta& LevelTableV2::stats_delta_for_level(uint8_t char_class, u
} }
LevelTableV3BE::LevelTableV3BE(const string& data, bool encrypted) { LevelTableV3BE::LevelTableV3BE(const string& data, bool encrypted) {
StringReader r; phosg::StringReader r;
string decompressed_data; string decompressed_data;
if (encrypted) { if (encrypted) {
auto decrypted = decrypt_pr2_data<true>(data); auto decrypted = decrypt_pr2_data<true>(data);
@@ -102,9 +102,9 @@ LevelTableV3BE::LevelTableV3BE(const string& data, bool encrypted) {
if (decompressed_data.size() != decrypted.decompressed_size) { if (decompressed_data.size() != decrypted.decompressed_size) {
throw runtime_error("decompressed data size does not match expected size"); throw runtime_error("decompressed data size does not match expected size");
} }
r = StringReader(decompressed_data); r = phosg::StringReader(decompressed_data);
} else { } else {
r = StringReader(data); r = phosg::StringReader(data);
} }
// The GC format is very simple (but everything is big-endian): // The GC format is very simple (but everything is big-endian):
@@ -160,13 +160,13 @@ LevelTableV4::LevelTableV4(const string& data, bool compressed) {
le_uint32_t level_deltas; // -> u32[12] -> LevelStatsDelta[200] le_uint32_t level_deltas; // -> u32[12] -> LevelStatsDelta[200]
} __packed_ws__(Offsets, 8); } __packed_ws__(Offsets, 8);
StringReader r; phosg::StringReader r;
string decompressed_data; string decompressed_data;
if (compressed) { if (compressed) {
decompressed_data = prs_decompress(data); decompressed_data = prs_decompress(data);
r = StringReader(decompressed_data); r = phosg::StringReader(decompressed_data);
} else { } else {
r = StringReader(data); r = phosg::StringReader(data);
} }
const auto& offsets = r.pget<Offsets>(r.pget_u32l(r.size() - 0x10)); const auto& offsets = r.pget<Offsets>(r.pget_u32l(r.size() - 0x10));
+22 -30
View File
@@ -11,21 +11,19 @@
class LevelTable; class LevelTable;
template <bool IsBigEndian> template <bool BE>
struct CharacterStatsT { struct CharacterStatsT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; /* 00 */ U16T<BE> atp = 0;
/* 02 */ U16T<BE> mst = 0;
/* 00 */ U16T atp = 0; /* 04 */ U16T<BE> evp = 0;
/* 02 */ U16T mst = 0; /* 06 */ U16T<BE> hp = 0;
/* 04 */ U16T evp = 0; /* 08 */ U16T<BE> dfp = 0;
/* 06 */ U16T hp = 0; /* 0A */ U16T<BE> ata = 0;
/* 08 */ U16T dfp = 0; /* 0C */ U16T<BE> lck = 0;
/* 0A */ U16T ata = 0;
/* 0C */ U16T lck = 0;
/* 0E */ /* 0E */
operator CharacterStatsT<!IsBigEndian>() const { operator CharacterStatsT<!BE>() const {
CharacterStatsT<!IsBigEndian> ret; CharacterStatsT<!BE> ret;
ret.atp = this->atp.load(); ret.atp = this->atp.load();
ret.mst = this->mst.load(); ret.mst = this->mst.load();
ret.evp = this->evp.load(); ret.evp = this->evp.load();
@@ -41,23 +39,19 @@ using CharacterStatsBE = CharacterStatsT<true>;
check_struct_size(CharacterStats, 0x0E); check_struct_size(CharacterStats, 0x0E);
check_struct_size(CharacterStatsBE, 0x0E); check_struct_size(CharacterStatsBE, 0x0E);
template <bool IsBigEndian> template <bool BE>
struct PlayerStatsT { struct PlayerStatsT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type; /* 00 */ CharacterStatsT<BE> char_stats;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; /* 0E */ U16T<BE> esp = 0;
using F32T = typename std::conditional<IsBigEndian, be_float, le_float>::type; /* 10 */ F32T<BE> height = 0.0;
/* 14 */ F32T<BE> unknown_a3 = 0.0;
/* 00 */ CharacterStatsT<IsBigEndian> char_stats; /* 18 */ U32T<BE> level = 0;
/* 0E */ U16T esp = 0; /* 1C */ U32T<BE> experience = 0;
/* 10 */ F32T height = 0.0; /* 20 */ U32T<BE> meseta = 0;
/* 14 */ F32T unknown_a3 = 0.0;
/* 18 */ U32T level = 0;
/* 1C */ U32T experience = 0;
/* 20 */ U32T meseta = 0;
/* 24 */ /* 24 */
operator PlayerStatsT<!IsBigEndian>() const { operator PlayerStatsT<!BE>() const {
PlayerStatsT<!IsBigEndian> ret; PlayerStatsT<!BE> ret;
ret.char_stats = this->char_stats; ret.char_stats = this->char_stats;
ret.esp = this->esp.load(); ret.esp = this->esp.load();
ret.height = this->height.load(); ret.height = this->height.load();
@@ -73,10 +67,8 @@ using PlayerStatsBE = PlayerStatsT<true>;
check_struct_size(PlayerStats, 0x24); check_struct_size(PlayerStats, 0x24);
check_struct_size(PlayerStatsBE, 0x24); check_struct_size(PlayerStatsBE, 0x24);
template <bool IsBigEndian> template <bool BE>
struct LevelStatsDeltaT { struct LevelStatsDeltaT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
/* 00 */ uint8_t atp; /* 00 */ uint8_t atp;
/* 01 */ uint8_t mst; /* 01 */ uint8_t mst;
/* 02 */ uint8_t evp; /* 02 */ uint8_t evp;
@@ -85,7 +77,7 @@ struct LevelStatsDeltaT {
/* 05 */ uint8_t ata; /* 05 */ uint8_t ata;
/* 06 */ uint8_t lck; /* 06 */ uint8_t lck;
/* 07 */ uint8_t tp; /* 07 */ uint8_t tp;
/* 08 */ U32T experience; /* 08 */ U32T<BE> experience;
/* 0C */ /* 0C */
void apply(CharacterStats& ps) const { void apply(CharacterStats& ps) const {
+9 -9
View File
@@ -16,7 +16,7 @@ bool Lobby::FloorItem::visible_to_client(uint8_t client_id) const {
} }
Lobby::FloorItemManager::FloorItemManager(uint32_t lobby_id, uint8_t floor) Lobby::FloorItemManager::FloorItemManager(uint32_t lobby_id, uint8_t floor)
: log(string_printf("[Lobby:%08" PRIX32 ":FloorItems:%02hhX] ", lobby_id, floor), lobby_log.min_level), : log(phosg::string_printf("[Lobby:%08" PRIX32 ":FloorItems:%02hhX] ", lobby_id, floor), lobby_log.min_level),
next_drop_number(0) {} next_drop_number(0) {}
bool Lobby::FloorItemManager::exists(uint32_t item_id) const { bool Lobby::FloorItemManager::exists(uint32_t item_id) const {
@@ -137,7 +137,7 @@ uint32_t Lobby::FloorItemManager::reassign_all_item_ids(uint32_t next_item_id) {
Lobby::Lobby(shared_ptr<ServerState> s, uint32_t id, bool is_game) Lobby::Lobby(shared_ptr<ServerState> s, uint32_t id, bool is_game)
: server_state(s), : server_state(s),
log(string_printf("[%s:%" PRIX32 "] ", is_game ? "Game" : "Lobby", id), lobby_log.min_level), log(phosg::string_printf("[%s:%" PRIX32 "] ", is_game ? "Game" : "Lobby", id), lobby_log.min_level),
lobby_id(id), lobby_id(id),
min_level(0), min_level(0),
max_level(0xFFFFFFFF), max_level(0xFFFFFFFF),
@@ -151,7 +151,7 @@ Lobby::Lobby(shared_ptr<ServerState> s, uint32_t id, bool is_game)
base_exp_multiplier(1), base_exp_multiplier(1),
exp_share_multiplier(0.5), exp_share_multiplier(0.5),
challenge_exp_multiplier(1.0f), challenge_exp_multiplier(1.0f),
random_seed(random_object<uint32_t>()), random_seed(phosg::random_object<uint32_t>()),
drop_mode(DropMode::CLIENT), drop_mode(DropMode::CLIENT),
event(0), event(0),
block(0), block(0),
@@ -325,7 +325,7 @@ shared_ptr<Map> Lobby::load_maps(
uint32_t random_seed, uint32_t random_seed,
shared_ptr<PSOLFGEncryption> opt_rand_crypt, shared_ptr<PSOLFGEncryption> opt_rand_crypt,
const parray<le_uint32_t, 0x20>& variations, const parray<le_uint32_t, 0x20>& variations,
const PrefixedLogger* log) { const phosg::PrefixedLogger* log) {
auto enemy_filenames = sdt->map_filenames_for_variations(variations, episode, mode, SetDataTable::FilenameType::ENEMIES); auto enemy_filenames = sdt->map_filenames_for_variations(variations, episode, mode, SetDataTable::FilenameType::ENEMIES);
auto object_filenames = sdt->map_filenames_for_variations(variations, episode, mode, SetDataTable::FilenameType::OBJECTS); auto object_filenames = sdt->map_filenames_for_variations(variations, episode, mode, SetDataTable::FilenameType::OBJECTS);
auto event_filenames = sdt->map_filenames_for_variations(variations, episode, mode, SetDataTable::FilenameType::EVENTS); auto event_filenames = sdt->map_filenames_for_variations(variations, episode, mode, SetDataTable::FilenameType::EVENTS);
@@ -360,7 +360,7 @@ shared_ptr<Map> Lobby::load_maps(
shared_ptr<const Map::RareEnemyRates> rare_rates, shared_ptr<const Map::RareEnemyRates> rare_rates,
uint32_t rare_seed, uint32_t rare_seed,
shared_ptr<PSOLFGEncryption> opt_rand_crypt, shared_ptr<PSOLFGEncryption> opt_rand_crypt,
const PrefixedLogger* log) { const phosg::PrefixedLogger* log) {
auto map = make_shared<Map>(version, lobby_id, rare_seed, opt_rand_crypt); auto map = make_shared<Map>(version, lobby_id, rare_seed, opt_rand_crypt);
// Don't load free-roam maps in Challenge mode, since players can't go to // Don't load free-roam maps in Challenge mode, since players can't go to
@@ -682,7 +682,7 @@ void Lobby::add_client(shared_ptr<Client> c, ssize_t required_client_id) {
void Lobby::remove_client(shared_ptr<Client> c) { void Lobby::remove_client(shared_ptr<Client> c) {
if (this->clients.at(c->lobby_client_id) != c) { if (this->clients.at(c->lobby_client_id) != c) {
auto other_c = this->clients[c->lobby_client_id].get(); auto other_c = this->clients[c->lobby_client_id].get();
throw logic_error(string_printf( throw logic_error(phosg::string_printf(
"client\'s lobby client id (%hhu) does not match client list (%u)", "client\'s lobby client id (%hhu) does not match client list (%u)",
c->lobby_client_id, c->lobby_client_id,
static_cast<uint8_t>(other_c ? other_c->lobby_client_id : 0xFF))); static_cast<uint8_t>(other_c ? other_c->lobby_client_id : 0xFF)));
@@ -743,7 +743,7 @@ void Lobby::remove_client(shared_ptr<Client> c) {
(this->idle_timeout_usecs > 0)) { (this->idle_timeout_usecs > 0)) {
// If the lobby is persistent but has an idle timeout, make it expire after // If the lobby is persistent but has an idle timeout, make it expire after
// the specified time // the specified time
auto tv = usecs_to_timeval(this->idle_timeout_usecs); auto tv = phosg::usecs_to_timeval(this->idle_timeout_usecs);
event_add(this->idle_timeout_event.get(), &tv); event_add(this->idle_timeout_event.get(), &tv);
this->log.info("Idle timeout scheduled"); this->log.info("Idle timeout scheduled");
} }
@@ -1031,7 +1031,7 @@ bool Lobby::compare_shared(const shared_ptr<const Lobby>& a, const shared_ptr<co
} }
template <> template <>
Lobby::DropMode enum_for_name<Lobby::DropMode>(const char* name) { Lobby::DropMode phosg::enum_for_name<Lobby::DropMode>(const char* name) {
if (!strcmp(name, "DISABLED")) { if (!strcmp(name, "DISABLED")) {
return Lobby::DropMode::DISABLED; return Lobby::DropMode::DISABLED;
} else if (!strcmp(name, "CLIENT")) { } else if (!strcmp(name, "CLIENT")) {
@@ -1048,7 +1048,7 @@ Lobby::DropMode enum_for_name<Lobby::DropMode>(const char* name) {
} }
template <> template <>
const char* name_for_enum<Lobby::DropMode>(Lobby::DropMode value) { const char* phosg::name_for_enum<Lobby::DropMode>(Lobby::DropMode value) {
switch (value) { switch (value) {
case Lobby::DropMode::DISABLED: case Lobby::DropMode::DISABLED:
return "DISABLED"; return "DISABLED";
+6 -6
View File
@@ -40,7 +40,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
bool visible_to_client(uint8_t client_id) const; bool visible_to_client(uint8_t client_id) const;
}; };
struct FloorItemManager { struct FloorItemManager {
PrefixedLogger log; phosg::PrefixedLogger log;
uint64_t next_drop_number; uint64_t next_drop_number;
// It's important that this is a map and not an unordered_map. See the // It's important that this is a map and not an unordered_map. See the
// comment in send_game_item_state for more details. // comment in send_game_item_state for more details.
@@ -92,7 +92,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
}; };
std::weak_ptr<ServerState> server_state; std::weak_ptr<ServerState> server_state;
PrefixedLogger log; phosg::PrefixedLogger log;
uint32_t lobby_id; uint32_t lobby_id;
@@ -231,7 +231,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
uint32_t random_seed, uint32_t random_seed,
std::shared_ptr<PSOLFGEncryption> opt_rand_crypt, std::shared_ptr<PSOLFGEncryption> opt_rand_crypt,
const parray<le_uint32_t, 0x20>& variations, const parray<le_uint32_t, 0x20>& variations,
const PrefixedLogger* log = nullptr); const phosg::PrefixedLogger* log = nullptr);
static std::shared_ptr<Map> load_maps( static std::shared_ptr<Map> load_maps(
const std::vector<std::string>& enemy_filenames, const std::vector<std::string>& enemy_filenames,
const std::vector<std::string>& object_filenames, const std::vector<std::string>& object_filenames,
@@ -246,7 +246,7 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
std::shared_ptr<const Map::RareEnemyRates> rare_rates, std::shared_ptr<const Map::RareEnemyRates> rare_rates,
uint32_t random_seed, uint32_t random_seed,
std::shared_ptr<PSOLFGEncryption> opt_rand_crypt, std::shared_ptr<PSOLFGEncryption> opt_rand_crypt,
const PrefixedLogger* log = nullptr); const phosg::PrefixedLogger* log = nullptr);
void load_maps(); void load_maps();
void create_ep3_server(); void create_ep3_server();
@@ -316,6 +316,6 @@ struct Lobby : public std::enable_shared_from_this<Lobby> {
}; };
template <> template <>
Lobby::DropMode enum_for_name<Lobby::DropMode>(const char* name); Lobby::DropMode phosg::enum_for_name<Lobby::DropMode>(const char* name);
template <> template <>
const char* name_for_enum<Lobby::DropMode>(Lobby::DropMode value); const char* phosg::name_for_enum<Lobby::DropMode>(Lobby::DropMode value);
+19 -19
View File
@@ -4,32 +4,32 @@
using namespace std; using namespace std;
PrefixedLogger ax_messages_log("[$ax message] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger ax_messages_log("[$ax message] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger channel_exceptions_log("[Channel] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger channel_exceptions_log("[Channel] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger client_log("", LogLevel::USE_DEFAULT); phosg::PrefixedLogger client_log("", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger command_data_log("[Commands] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger command_data_log("[Commands] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger config_log("[Config] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger config_log("[Config] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger dns_server_log("[DNSServer] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger dns_server_log("[DNSServer] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger function_compiler_log("[FunctionCompiler] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger function_compiler_log("[FunctionCompiler] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger ip_stack_simulator_log("[IPStackSimulator] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger ip_stack_simulator_log("[IPStackSimulator] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger lobby_log("", LogLevel::USE_DEFAULT); phosg::PrefixedLogger lobby_log("", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger patch_index_log("[PatchFileIndex] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger patch_index_log("[PatchFileIndex] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger player_data_log("", LogLevel::USE_DEFAULT); phosg::PrefixedLogger player_data_log("", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger proxy_server_log("[ProxyServer] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger proxy_server_log("[ProxyServer] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger replay_log("[ReplaySession] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger replay_log("[ReplaySession] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger server_log("[Server] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger server_log("[Server] ", phosg::LogLevel::USE_DEFAULT);
PrefixedLogger static_game_data_log("[StaticGameData] ", LogLevel::USE_DEFAULT); phosg::PrefixedLogger static_game_data_log("[StaticGameData] ", phosg::LogLevel::USE_DEFAULT);
static void set_log_level_from_json( static void set_log_level_from_json(
PrefixedLogger& log, const JSON& d, const char* json_key) { phosg::PrefixedLogger& log, const phosg::JSON& d, const char* json_key) {
try { try {
string name = toupper(d.at(json_key).as_string()); string name = phosg::toupper(d.at(json_key).as_string());
log.min_level = enum_for_name<LogLevel>(name.c_str()); log.min_level = phosg::enum_for_name<phosg::LogLevel>(name.c_str());
} catch (const out_of_range&) { } catch (const out_of_range&) {
} }
} }
void set_log_levels_from_json(const JSON& json) { void set_log_levels_from_json(const phosg::JSON& json) {
set_log_level_from_json(ax_messages_log, json, "AXMessages"); set_log_level_from_json(ax_messages_log, json, "AXMessages");
set_log_level_from_json(channel_exceptions_log, json, "ChannelExceptions"); set_log_level_from_json(channel_exceptions_log, json, "ChannelExceptions");
set_log_level_from_json(client_log, json, "Clients"); set_log_level_from_json(client_log, json, "Clients");
+16 -16
View File
@@ -3,20 +3,20 @@
#include <phosg/JSON.hh> #include <phosg/JSON.hh>
#include <phosg/Strings.hh> #include <phosg/Strings.hh>
extern PrefixedLogger ax_messages_log; extern phosg::PrefixedLogger ax_messages_log;
extern PrefixedLogger channel_exceptions_log; extern phosg::PrefixedLogger channel_exceptions_log;
extern PrefixedLogger client_log; extern phosg::PrefixedLogger client_log;
extern PrefixedLogger command_data_log; extern phosg::PrefixedLogger command_data_log;
extern PrefixedLogger config_log; extern phosg::PrefixedLogger config_log;
extern PrefixedLogger dns_server_log; extern phosg::PrefixedLogger dns_server_log;
extern PrefixedLogger function_compiler_log; extern phosg::PrefixedLogger function_compiler_log;
extern PrefixedLogger ip_stack_simulator_log; extern phosg::PrefixedLogger ip_stack_simulator_log;
extern PrefixedLogger lobby_log; extern phosg::PrefixedLogger lobby_log;
extern PrefixedLogger patch_index_log; extern phosg::PrefixedLogger patch_index_log;
extern PrefixedLogger player_data_log; extern phosg::PrefixedLogger player_data_log;
extern PrefixedLogger proxy_server_log; extern phosg::PrefixedLogger proxy_server_log;
extern PrefixedLogger replay_log; extern phosg::PrefixedLogger replay_log;
extern PrefixedLogger server_log; extern phosg::PrefixedLogger server_log;
extern PrefixedLogger static_game_data_log; extern phosg::PrefixedLogger static_game_data_log;
void set_log_levels_from_json(const JSON& json); void set_log_levels_from_json(const phosg::JSON& json);
+269 -269
View File
File diff suppressed because it is too large Load Diff
+72 -74
View File
@@ -583,7 +583,7 @@ Map::RareEnemyRates::RareEnemyRates(uint32_t enemy_rate, uint32_t boss_rate)
dorphon_eclair(enemy_rate), dorphon_eclair(enemy_rate),
kondrieu(boss_rate) {} kondrieu(boss_rate) {}
Map::RareEnemyRates::RareEnemyRates(const JSON& json) Map::RareEnemyRates::RareEnemyRates(const phosg::JSON& json)
: hildeblue(json.get_int("Hildeblue")), : hildeblue(json.get_int("Hildeblue")),
rappy(json.get_int("Rappy")), rappy(json.get_int("Rappy")),
nar_lily(json.get_int("NarLily")), nar_lily(json.get_int("NarLily")),
@@ -593,8 +593,8 @@ Map::RareEnemyRates::RareEnemyRates(const JSON& json)
dorphon_eclair(json.get_int("DorphonEclair")), dorphon_eclair(json.get_int("DorphonEclair")),
kondrieu(json.get_int("Kondrieu")) {} kondrieu(json.get_int("Kondrieu")) {}
JSON Map::RareEnemyRates::json() const { phosg::JSON Map::RareEnemyRates::json() const {
return JSON::dict({ return phosg::JSON::dict({
{"Hildeblue", this->hildeblue}, {"Hildeblue", this->hildeblue},
{"Rappy", this->rappy}, {"Rappy", this->rappy},
{"NarLily", this->nar_lily}, {"NarLily", this->nar_lily},
@@ -608,7 +608,7 @@ JSON Map::RareEnemyRates::json() const {
string Map::ObjectEntry::str() const { string Map::ObjectEntry::str() const {
string name_str = Map::name_for_object_type(this->base_type); string name_str = Map::name_for_object_type(this->base_type);
return string_printf("[ObjectEntry type=%04hX \"%s\" flags=%04hX index=%04hX a2=%04hX entity_id=%04hX group=%04hX section=%04hX a3=%04hX x=%g y=%g z=%g x_angle=%08" PRIX32 " y_angle=%08" PRIX32 " z_angle=%08" PRIX32 " params=[%g %g %g %08" PRIX32 " %08" PRIX32 " %08" PRIX32 "] unused=%08" PRIX32 "]", return phosg::string_printf("[ObjectEntry type=%04hX \"%s\" flags=%04hX index=%04hX a2=%04hX entity_id=%04hX group=%04hX section=%04hX a3=%04hX x=%g y=%g z=%g x_angle=%08" PRIX32 " y_angle=%08" PRIX32 " z_angle=%08" PRIX32 " params=[%g %g %g %08" PRIX32 " %08" PRIX32 " %08" PRIX32 "] unused=%08" PRIX32 "]",
this->base_type.load(), this->base_type.load(),
name_str.c_str(), name_str.c_str(),
this->flags.load(), this->flags.load(),
@@ -634,7 +634,7 @@ string Map::ObjectEntry::str() const {
} }
string Map::EnemyEntry::str() const { string Map::EnemyEntry::str() const {
return string_printf("[EnemyEntry type=%04hX flags=%04hX index=%04hX num_children=%04hX floor=%04hX entity_id=%04hX section=%04hX wave_number=%04hX wave_number2=%04hX a1=%04hX x=%g y=%g z=%g x_angle=%08" PRIX32 " y_angle=%08" PRIX32 " z_angle=%08" PRIX32 " params=[%g %g %g %g %g %04hX %04hX] unused=%08" PRIX32 "]", return phosg::string_printf("[EnemyEntry type=%04hX flags=%04hX index=%04hX num_children=%04hX floor=%04hX entity_id=%04hX section=%04hX wave_number=%04hX wave_number2=%04hX a1=%04hX x=%g y=%g z=%g x_angle=%08" PRIX32 " y_angle=%08" PRIX32 " z_angle=%08" PRIX32 " params=[%g %g %g %g %g %04hX %04hX] unused=%08" PRIX32 "]",
this->base_type.load(), this->base_type.load(),
this->flags.load(), this->flags.load(),
this->index.load(), this->index.load(),
@@ -681,10 +681,10 @@ Map::Enemy::Enemy(
server_flags(0) {} server_flags(0) {}
string Map::Enemy::str() const { string Map::Enemy::str() const {
return string_printf("[Map::Enemy E-%hX source %zX %s%s floor=%02hhX section=%04hX wave_number=%04hX server_flags=%02hhX]", return phosg::string_printf("[Map::Enemy E-%hX source %zX %s%s floor=%02hhX section=%04hX wave_number=%04hX server_flags=%02hhX]",
this->enemy_id, this->enemy_id,
this->source_index, this->source_index,
name_for_enum(this->type), phosg::name_for_enum(this->type),
enemy_type_is_rare(this->type) ? " RARE" : "", enemy_type_is_rare(this->type) ? " RARE" : "",
this->floor, this->floor,
this->section, this->section,
@@ -693,7 +693,7 @@ string Map::Enemy::str() const {
} }
string Map::Event::str() const { string Map::Event::str() const {
return string_printf("[Map::Event W-%02hhX-%" PRIX32 " flags=%04hX floor=%02hhX action_stream_offset=%" PRIX32 "]", return phosg::string_printf("[Map::Event W-%02hhX-%" PRIX32 " flags=%04hX floor=%02hhX action_stream_offset=%" PRIX32 "]",
this->floor, this->floor,
this->event_id, this->event_id,
this->flags, this->flags,
@@ -702,7 +702,7 @@ string Map::Event::str() const {
} }
string Map::Object::str() const { string Map::Object::str() const {
return string_printf("[Map::Object source %zX %04hX(%s) @%04hX p1=%g p456=[%08" PRIX32 " %08" PRIX32 " %08" PRIX32 "] floor=%02hhX item_drop_checked=%s]", return phosg::string_printf("[Map::Object source %zX %04hX(%s) @%04hX p1=%g p456=[%08" PRIX32 " %08" PRIX32 " %08" PRIX32 "] floor=%02hhX item_drop_checked=%s]",
this->source_index, this->source_index,
this->base_type, this->base_type,
Map::name_for_object_type(this->base_type), Map::name_for_object_type(this->base_type),
@@ -716,7 +716,7 @@ string Map::Object::str() const {
} }
Map::Map(Version version, uint32_t lobby_id, uint32_t rare_seed, std::shared_ptr<PSOLFGEncryption> opt_rand_crypt) Map::Map(Version version, uint32_t lobby_id, uint32_t rare_seed, std::shared_ptr<PSOLFGEncryption> opt_rand_crypt)
: log(string_printf("[Lobby:%08" PRIX32 ":map] ", lobby_id), lobby_log.min_level), : log(phosg::string_printf("[Lobby:%08" PRIX32 ":map] ", lobby_id), lobby_log.min_level),
version(version), version(version),
rare_seed(rare_seed), rare_seed(rare_seed),
opt_rand_crypt(opt_rand_crypt) {} opt_rand_crypt(opt_rand_crypt) {}
@@ -1254,7 +1254,7 @@ void Map::add_enemies_from_map_data(
throw runtime_error("data size is not a multiple of entry size"); throw runtime_error("data size is not a multiple of entry size");
} }
StringReader r(data, size); phosg::StringReader r(data, size);
for (size_t y = 0; y < entry_count; y++) { for (size_t y = 0; y < entry_count; y++) {
this->add_enemy(episode, difficulty, event, floor, y, r.get<EnemyEntry>(), rare_rates); this->add_enemy(episode, difficulty, event, floor, y, r.get<EnemyEntry>(), rare_rates);
} }
@@ -1284,12 +1284,12 @@ uint32_t Map::DATParserRandomState::next_location_index() {
} }
void Map::DATParserRandomState::generate_shuffled_location_table( void Map::DATParserRandomState::generate_shuffled_location_table(
const Map::RandomEnemyLocationsHeader& header, StringReader r, uint16_t section) { const Map::RandomEnemyLocationsHeader& header, phosg::StringReader r, uint16_t section) {
if (header.num_sections == 0) { if (header.num_sections == 0) {
throw runtime_error("no locations defined"); throw runtime_error("no locations defined");
} }
StringReader sections_r = r.sub(header.section_table_offset, header.num_sections * sizeof(Map::RandomEnemyLocationSection)); phosg::StringReader sections_r = r.sub(header.section_table_offset, header.num_sections * sizeof(Map::RandomEnemyLocationSection));
size_t bs_min = 0; size_t bs_min = 0;
size_t bs_max = header.num_sections - 1; size_t bs_max = header.num_sections - 1;
@@ -1330,9 +1330,9 @@ void Map::add_random_enemies_from_map_data(
uint8_t difficulty, uint8_t difficulty,
uint8_t event, uint8_t event,
uint8_t floor, uint8_t floor,
StringReader wave_events_segment_r, phosg::StringReader wave_events_segment_r,
StringReader locations_segment_r, phosg::StringReader locations_segment_r,
StringReader definitions_segment_r, phosg::StringReader definitions_segment_r,
std::shared_ptr<DATParserRandomState> random_state, std::shared_ptr<DATParserRandomState> random_state,
std::shared_ptr<const RareEnemyRates> rare_rates) { std::shared_ptr<const RareEnemyRates> rare_rates) {
@@ -1362,7 +1362,7 @@ void Map::add_random_enemies_from_map_data(
definitions_header.weight_entry_count * sizeof(RandomEnemyWeight)); definitions_header.weight_entry_count * sizeof(RandomEnemyWeight));
for (size_t wave_entry_index = 0; wave_entry_index < wave_events_header.entry_count; wave_entry_index++) { for (size_t wave_entry_index = 0; wave_entry_index < wave_events_header.entry_count; wave_entry_index++) {
auto entry_log = this->log.sub(string_printf("(Entry %zu/%" PRIu32 ") ", wave_entry_index, wave_events_header.entry_count.load())); auto entry_log = this->log.sub(phosg::string_printf("(Entry %zu/%" PRIu32 ") ", wave_entry_index, wave_events_header.entry_count.load()));
const auto& entry = wave_events_segment_r.get<Event2Entry>(); const auto& entry = wave_events_segment_r.get<Event2Entry>();
size_t remaining_waves = random_state->rand_int_biased(1, entry.max_waves); size_t remaining_waves = random_state->rand_int_biased(1, entry.max_waves);
@@ -1372,7 +1372,7 @@ void Map::add_random_enemies_from_map_data(
uint32_t wave_number = entry.wave_number; uint32_t wave_number = entry.wave_number;
while (remaining_waves) { while (remaining_waves) {
remaining_waves--; remaining_waves--;
auto wave_log = entry_log.sub(string_printf("(Wave %zu) ", remaining_waves)); auto wave_log = entry_log.sub(phosg::string_printf("(Wave %zu) ", remaining_waves));
size_t remaining_enemies = random_state->rand_int_biased(entry.min_enemies, entry.max_enemies); size_t remaining_enemies = random_state->rand_int_biased(entry.min_enemies, entry.max_enemies);
// Trace: at 0080E208 EDI is enemy count // Trace: at 0080E208 EDI is enemy count
@@ -1382,7 +1382,7 @@ void Map::add_random_enemies_from_map_data(
while (remaining_enemies) { while (remaining_enemies) {
remaining_enemies--; remaining_enemies--;
auto enemy_log = wave_log.sub(string_printf("(Enemy %zu) ", remaining_enemies)); auto enemy_log = wave_log.sub(phosg::string_printf("(Enemy %zu) ", remaining_enemies));
// TODO: Factor this sum out of the loops // TODO: Factor this sum out of the loops
weights_r.go(0); weights_r.go(0);
@@ -1506,7 +1506,7 @@ vector<const Map::Event*> Map::get_events(uint8_t floor, uint32_t event_id) cons
} }
void Map::add_events_from_map_data(uint8_t floor, const void* data, size_t size) { void Map::add_events_from_map_data(uint8_t floor, const void* data, size_t size) {
StringReader r(data, size); phosg::StringReader r(data, size);
const auto& header = r.get<EventsSectionHeader>(); const auto& header = r.get<EventsSectionHeader>();
if (header.format != 0) { if (header.format != 0) {
throw runtime_error("events section format is not zero"); throw runtime_error("events section format is not zero");
@@ -1525,7 +1525,7 @@ void Map::add_events_from_map_data(uint8_t floor, const void* data, size_t size)
vector<Map::DATSectionsForFloor> Map::collect_quest_map_data_sections(const void* data, size_t size) { vector<Map::DATSectionsForFloor> Map::collect_quest_map_data_sections(const void* data, size_t size) {
vector<DATSectionsForFloor> ret; vector<DATSectionsForFloor> ret;
StringReader r(data, size); phosg::StringReader r(data, size);
while (!r.eof()) { while (!r.eof()) {
size_t header_offset = r.where(); size_t header_offset = r.where();
const auto& header = r.get<SectionHeader>(); const auto& header = r.get<SectionHeader>();
@@ -1534,7 +1534,7 @@ vector<Map::DATSectionsForFloor> Map::collect_quest_map_data_sections(const void
break; break;
} }
if (header.section_size < sizeof(header)) { if (header.section_size < sizeof(header)) {
throw runtime_error(string_printf("quest layout has invalid section header at offset 0x%zX", r.where() - sizeof(header))); throw runtime_error(phosg::string_printf("quest layout has invalid section header at offset 0x%zX", r.where() - sizeof(header)));
} }
if (header.floor > 0x100) { if (header.floor > 0x100) {
@@ -1593,7 +1593,7 @@ void Map::add_entities_from_quest_data(
std::shared_ptr<const RareEnemyRates> rare_rates) { std::shared_ptr<const RareEnemyRates> rare_rates) {
auto all_floor_sections = this->collect_quest_map_data_sections(data, size); auto all_floor_sections = this->collect_quest_map_data_sections(data, size);
StringReader r(data, size); phosg::StringReader r(data, size);
shared_ptr<DATParserRandomState> random_state; shared_ptr<DATParserRandomState> random_state;
for (size_t floor = 0; floor < all_floor_sections.size(); floor++) { for (size_t floor = 0; floor < all_floor_sections.size(); floor++) {
const auto& floor_sections = all_floor_sections[floor]; const auto& floor_sections = all_floor_sections[floor];
@@ -1713,7 +1713,7 @@ std::vector<Map::Event*> Map::get_events(uint8_t floor) {
template <typename EntryT> template <typename EntryT>
static string disassemble_vector_file_t(const void* data, size_t size, size_t* entry_number, char type_ch) { static string disassemble_vector_file_t(const void* data, size_t size, size_t* entry_number, char type_ch) {
deque<string> ret; deque<string> ret;
StringReader r(data, size); phosg::StringReader r(data, size);
size_t local_entry_number = 0; size_t local_entry_number = 0;
if (!entry_number) { if (!entry_number) {
@@ -1722,14 +1722,14 @@ static string disassemble_vector_file_t(const void* data, size_t size, size_t* e
while (r.remaining() >= sizeof(EntryT)) { while (r.remaining() >= sizeof(EntryT)) {
string o_str = r.get<EntryT>().str(); string o_str = r.get<EntryT>().str();
ret.emplace_back(string_printf("/* %c-%zX */ %s", type_ch, (*entry_number)++, o_str.c_str())); ret.emplace_back(phosg::string_printf("/* %c-%zX */ %s", type_ch, (*entry_number)++, o_str.c_str()));
} }
if (r.remaining()) { if (r.remaining()) {
ret.emplace_back("// Warning: section size is not a multiple of entry size"); ret.emplace_back("// Warning: section size is not a multiple of entry size");
size_t size = r.remaining(); size_t size = r.remaining();
ret.emplace_back(format_data(r.getv(size), size)); ret.emplace_back(phosg::format_data(r.getv(size), size));
} }
return join(ret, "\n"); return phosg::join(ret, "\n");
} }
string Map::disassemble_objects_data(const void* data, size_t size, size_t* object_number) { string Map::disassemble_objects_data(const void* data, size_t size, size_t* object_number) {
@@ -1742,18 +1742,18 @@ string Map::disassemble_enemies_data(const void* data, size_t size, size_t* enem
string Map::disassemble_wave_events_data(const void* data, size_t size, uint8_t floor) { string Map::disassemble_wave_events_data(const void* data, size_t size, uint8_t floor) {
deque<string> ret; deque<string> ret;
StringReader r(data, size); phosg::StringReader r(data, size);
const auto& evt_header = r.get<EventsSectionHeader>(); const auto& evt_header = r.get<EventsSectionHeader>();
if (evt_header.format == 0x65767432) { // 'evt2' if (evt_header.format == 0x65767432) { // 'evt2'
ret.emplace_back(".evt2_format"); // TODO ret.emplace_back(".evt2_format"); // TODO
size_t size = r.remaining(); size_t size = r.remaining();
ret.emplace_back(format_data(r.getv(size), size)); ret.emplace_back(phosg::format_data(r.getv(size), size));
} else { } else {
auto action_stream_r = r.sub(evt_header.action_stream_offset); auto action_stream_r = r.sub(evt_header.action_stream_offset);
for (size_t z = 0; z < evt_header.entry_count; z++) { for (size_t z = 0; z < evt_header.entry_count; z++) {
const auto& entry = r.get<Event1Entry>(); const auto& entry = r.get<Event1Entry>();
ret.emplace_back(string_printf("/* W-%02hhX-%" PRIX32 " */ [Event1Entry flags=%04hX type=%04hX section=%04hX wave_number=%04hX delay=%" PRIu32 "]", ret.emplace_back(phosg::string_printf("/* W-%02hhX-%" PRIX32 " */ [Event1Entry flags=%04hX type=%04hX section=%04hX wave_number=%04hX delay=%" PRIu32 "]",
floor, floor,
entry.event_id.load(), entry.event_id.load(),
entry.flags.load(), entry.flags.load(),
@@ -1767,103 +1767,103 @@ string Map::disassemble_wave_events_data(const void* data, size_t size, uint8_t
uint8_t opcode = ev_actions_r.get_u8(); uint8_t opcode = ev_actions_r.get_u8();
switch (opcode) { switch (opcode) {
case 0x00: case 0x00:
ret.emplace_back(string_printf(" 00 nop")); ret.emplace_back(phosg::string_printf(" 00 nop"));
break; break;
case 0x01: case 0x01:
ret.emplace_back(string_printf(" 01 stop")); ret.emplace_back(phosg::string_printf(" 01 stop"));
should_continue = false; should_continue = false;
break; break;
case 0x08: { case 0x08: {
uint16_t section = ev_actions_r.get_u16l(); uint16_t section = ev_actions_r.get_u16l();
uint16_t group = ev_actions_r.get_u16l(); uint16_t group = ev_actions_r.get_u16l();
ret.emplace_back(string_printf(" 08 %04hX %04hX construct_objects section=%04hX group=%04hX", ret.emplace_back(phosg::string_printf(" 08 %04hX %04hX construct_objects section=%04hX group=%04hX",
section, group, section, group)); section, group, section, group));
break; break;
} }
case 0x09: { case 0x09: {
uint16_t section = ev_actions_r.get_u16l(); uint16_t section = ev_actions_r.get_u16l();
uint16_t wave_number = ev_actions_r.get_u16l(); uint16_t wave_number = ev_actions_r.get_u16l();
ret.emplace_back(string_printf(" 09 %04hX %04hX construct_enemies section=%04hX wave_number=%04hX", ret.emplace_back(phosg::string_printf(" 09 %04hX %04hX construct_enemies section=%04hX wave_number=%04hX",
section, wave_number, section, wave_number)); section, wave_number, section, wave_number));
break; break;
} }
case 0x0A: { case 0x0A: {
uint16_t id = ev_actions_r.get_u16l(); uint16_t id = ev_actions_r.get_u16l();
ret.emplace_back(string_printf(" 0A %04hX enable_switch_flag id=%04hX", id, id)); ret.emplace_back(phosg::string_printf(" 0A %04hX enable_switch_flag id=%04hX", id, id));
break; break;
} }
case 0x0B: { case 0x0B: {
uint16_t id = ev_actions_r.get_u16l(); uint16_t id = ev_actions_r.get_u16l();
ret.emplace_back(string_printf(" 0B %04hX disable_switch_flag id=%04hX", id, id)); ret.emplace_back(phosg::string_printf(" 0B %04hX disable_switch_flag id=%04hX", id, id));
break; break;
} }
case 0x0C: { case 0x0C: {
uint32_t event_id = ev_actions_r.get_u32l(); uint32_t event_id = ev_actions_r.get_u32l();
ret.emplace_back(string_printf(" 0C %08" PRIX32 " trigger_event event_id=%08" PRIX32, event_id, event_id)); ret.emplace_back(phosg::string_printf(" 0C %08" PRIX32 " trigger_event event_id=%08" PRIX32, event_id, event_id));
break; break;
} }
case 0x0D: { case 0x0D: {
uint16_t section = ev_actions_r.get_u16l(); uint16_t section = ev_actions_r.get_u16l();
uint16_t wave_number = ev_actions_r.get_u16l(); uint16_t wave_number = ev_actions_r.get_u16l();
ret.emplace_back(string_printf(" 0D %04hX %04hX construct_enemies_stop section=%04hX wave_number=%04hX", ret.emplace_back(phosg::string_printf(" 0D %04hX %04hX construct_enemies_stop section=%04hX wave_number=%04hX",
section, wave_number, section, wave_number)); section, wave_number, section, wave_number));
break; break;
} }
default: default:
ret.emplace_back(string_printf(" %02hhX .invalid", opcode)); ret.emplace_back(phosg::string_printf(" %02hhX .invalid", opcode));
} }
} }
} }
} }
return join(ret, "\n"); return phosg::join(ret, "\n");
} }
string Map::disassemble_quest_data(const void* data, size_t size) { string Map::disassemble_quest_data(const void* data, size_t size) {
auto all_floor_sections = Map::collect_quest_map_data_sections(data, size); auto all_floor_sections = Map::collect_quest_map_data_sections(data, size);
deque<string> ret; deque<string> ret;
StringReader r(data, size); phosg::StringReader r(data, size);
size_t object_number = 0; size_t object_number = 0;
size_t enemy_number = 0; size_t enemy_number = 0;
for (size_t floor = 0; floor < all_floor_sections.size(); floor++) { for (size_t floor = 0; floor < all_floor_sections.size(); floor++) {
const auto& floor_sections = all_floor_sections[floor]; const auto& floor_sections = all_floor_sections[floor];
if (floor_sections.objects != 0xFFFFFFFF) { if (floor_sections.objects != 0xFFFFFFFF) {
ret.emplace_back(string_printf(".objects %zu", floor)); ret.emplace_back(phosg::string_printf(".objects %zu", floor));
const auto& header = r.pget<SectionHeader>(floor_sections.objects); const auto& header = r.pget<SectionHeader>(floor_sections.objects);
size_t offset = floor_sections.objects + sizeof(SectionHeader); size_t offset = floor_sections.objects + sizeof(SectionHeader);
ret.emplace_back(Map::disassemble_objects_data(r.pgetv(offset, header.data_size), header.data_size, &object_number)); ret.emplace_back(Map::disassemble_objects_data(r.pgetv(offset, header.data_size), header.data_size, &object_number));
} }
if (floor_sections.enemies != 0xFFFFFFFF) { if (floor_sections.enemies != 0xFFFFFFFF) {
ret.emplace_back(string_printf(".enemies %zu", floor)); ret.emplace_back(phosg::string_printf(".enemies %zu", floor));
const auto& header = r.pget<SectionHeader>(floor_sections.enemies); const auto& header = r.pget<SectionHeader>(floor_sections.enemies);
size_t offset = floor_sections.enemies + sizeof(SectionHeader); size_t offset = floor_sections.enemies + sizeof(SectionHeader);
ret.emplace_back(Map::disassemble_enemies_data(r.pgetv(offset, header.data_size), header.data_size, &enemy_number)); ret.emplace_back(Map::disassemble_enemies_data(r.pgetv(offset, header.data_size), header.data_size, &enemy_number));
} }
if (floor_sections.wave_events != 0xFFFFFFFF) { if (floor_sections.wave_events != 0xFFFFFFFF) {
ret.emplace_back(string_printf(".wave_events %zu", floor)); ret.emplace_back(phosg::string_printf(".wave_events %zu", floor));
const auto& header = r.pget<SectionHeader>(floor_sections.wave_events); const auto& header = r.pget<SectionHeader>(floor_sections.wave_events);
size_t offset = floor_sections.wave_events + sizeof(SectionHeader); size_t offset = floor_sections.wave_events + sizeof(SectionHeader);
ret.emplace_back(Map::disassemble_wave_events_data(r.pgetv(offset, header.data_size), header.data_size, floor)); ret.emplace_back(Map::disassemble_wave_events_data(r.pgetv(offset, header.data_size), header.data_size, floor));
} }
if (floor_sections.random_enemy_locations != 0xFFFFFFFF) { if (floor_sections.random_enemy_locations != 0xFFFFFFFF) {
ret.emplace_back(string_printf(".random_enemy_locations %zu", floor)); ret.emplace_back(phosg::string_printf(".random_enemy_locations %zu", floor));
const auto& header = r.pget<SectionHeader>(floor_sections.random_enemy_locations); const auto& header = r.pget<SectionHeader>(floor_sections.random_enemy_locations);
size_t offset = floor_sections.random_enemy_locations + sizeof(SectionHeader); size_t offset = floor_sections.random_enemy_locations + sizeof(SectionHeader);
auto sub_r = r.sub(offset, header.data_size); auto sub_r = r.sub(offset, header.data_size);
ret.emplace_back(format_data(sub_r.getv(sub_r.remaining()), header.data_size, offset)); ret.emplace_back(phosg::format_data(sub_r.getv(sub_r.remaining()), header.data_size, offset));
} }
if (floor_sections.random_enemy_definitions != 0xFFFFFFFF) { if (floor_sections.random_enemy_definitions != 0xFFFFFFFF) {
ret.emplace_back(string_printf(".random_enemy_definitions %zu", floor)); ret.emplace_back(phosg::string_printf(".random_enemy_definitions %zu", floor));
const auto& header = r.pget<SectionHeader>(floor_sections.random_enemy_definitions); const auto& header = r.pget<SectionHeader>(floor_sections.random_enemy_definitions);
size_t offset = floor_sections.random_enemy_definitions + sizeof(SectionHeader); size_t offset = floor_sections.random_enemy_definitions + sizeof(SectionHeader);
auto sub_r = r.sub(offset, header.data_size); auto sub_r = r.sub(offset, header.data_size);
ret.emplace_back(format_data(sub_r.getv(sub_r.remaining()), header.data_size, offset)); ret.emplace_back(phosg::format_data(sub_r.getv(sub_r.remaining()), header.data_size, offset));
} }
} }
return join(ret, "\n") + "\n"; return phosg::join(ret, "\n") + "\n";
} }
SetDataTableBase::SetDataTableBase(Version version) : version(version) {} SetDataTableBase::SetDataTableBase(Version version) : version(version) {}
@@ -1925,21 +1925,19 @@ SetDataTable::SetDataTable(Version version, const string& data) : SetDataTableBa
} }
} }
template <bool IsBigEndian> template <bool BE>
void SetDataTable::load_table_t(const string& data) { void SetDataTable::load_table_t(const string& data) {
using U32T = typename conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; phosg::StringReader r(data);
StringReader r(data);
struct Footer { struct Footer {
U32T table3_offset; U32T<BE> table3_offset;
U32T table3_count; // In le_uint16_ts (so *2 for size in bytes) U32T<BE> table3_count; // In le_uint16_ts (so *2 for size in bytes)
U32T unknown_a3; // == 1 U32T<BE> unknown_a3; // == 1
U32T unknown_a4; // == 0 U32T<BE> unknown_a4; // == 0
U32T root_table_offset_offset; U32T<BE> root_table_offset_offset;
U32T unknown_a6; // == 0 U32T<BE> unknown_a6; // == 0
U32T unknown_a7; // == 0 U32T<BE> unknown_a7; // == 0
U32T unknown_a8; // == 0 U32T<BE> unknown_a8; // == 0
} __packed_ws__(Footer, 0x20); } __packed_ws__(Footer, 0x20);
if (r.size() < sizeof(Footer)) { if (r.size() < sizeof(Footer)) {
@@ -1947,23 +1945,23 @@ void SetDataTable::load_table_t(const string& data) {
} }
auto& footer = r.pget<Footer>(r.size() - sizeof(Footer)); auto& footer = r.pget<Footer>(r.size() - sizeof(Footer));
uint32_t root_table_offset = r.pget<U32T>(footer.root_table_offset_offset); uint32_t root_table_offset = r.pget<U32T<BE>>(footer.root_table_offset_offset);
auto root_r = r.sub(root_table_offset, footer.root_table_offset_offset - root_table_offset); auto root_r = r.sub(root_table_offset, footer.root_table_offset_offset - root_table_offset);
while (!root_r.eof()) { while (!root_r.eof()) {
auto& var1_v = this->entries.emplace_back(); auto& var1_v = this->entries.emplace_back();
uint32_t var1_table_offset = root_r.template get<U32T>(); uint32_t var1_table_offset = root_r.template get<U32T<BE>>();
uint32_t var1_table_count = root_r.template get<U32T>(); uint32_t var1_table_count = root_r.template get<U32T<BE>>();
auto var1_r = r.sub(var1_table_offset, var1_table_count * 0x08); auto var1_r = r.sub(var1_table_offset, var1_table_count * 0x08);
while (!var1_r.eof()) { while (!var1_r.eof()) {
auto& var2_v = var1_v.emplace_back(); auto& var2_v = var1_v.emplace_back();
uint32_t var2_table_offset = var1_r.get<U32T>(); uint32_t var2_table_offset = var1_r.get<U32T<BE>>();
uint32_t var2_table_count = var1_r.get<U32T>(); uint32_t var2_table_count = var1_r.get<U32T<BE>>();
auto var2_r = r.sub(var2_table_offset, var2_table_count * 0x0C); auto var2_r = r.sub(var2_table_offset, var2_table_count * 0x0C);
while (!var2_r.eof()) { while (!var2_r.eof()) {
auto& entry = var2_v.emplace_back(); auto& entry = var2_v.emplace_back();
entry.object_list_basename = r.pget_cstr(var2_r.get<U32T>()); entry.object_list_basename = r.pget_cstr(var2_r.get<U32T<BE>>());
entry.enemy_and_event_list_basename = r.pget_cstr(var2_r.get<U32T>()); entry.enemy_and_event_list_basename = r.pget_cstr(var2_r.get<U32T<BE>>());
entry.area_setup_filename = r.pget_cstr(var2_r.get<U32T>()); entry.area_setup_filename = r.pget_cstr(var2_r.get<U32T<BE>>());
} }
} }
} }
@@ -2066,19 +2064,19 @@ string SetDataTable::map_filename_for_variation(
string SetDataTable::str() const { string SetDataTable::str() const {
vector<string> lines; vector<string> lines;
lines.emplace_back(string_printf("FL/V1/V2 => ----------------------OBJECT -----------------ENEMY+EVENT -----------------------SETUP\n")); lines.emplace_back(phosg::string_printf("FL/V1/V2 => ----------------------OBJECT -----------------ENEMY+EVENT -----------------------SETUP\n"));
for (size_t a = 0; a < this->entries.size(); a++) { for (size_t a = 0; a < this->entries.size(); a++) {
const auto& v1_v = this->entries[a]; const auto& v1_v = this->entries[a];
for (size_t v1 = 0; v1 < v1_v.size(); v1++) { for (size_t v1 = 0; v1 < v1_v.size(); v1++) {
const auto& v2_v = v1_v[v1]; const auto& v2_v = v1_v[v1];
for (size_t v2 = 0; v2 < v2_v.size(); v2++) { for (size_t v2 = 0; v2 < v2_v.size(); v2++) {
const auto& e = v2_v[v2]; const auto& e = v2_v[v2];
lines.emplace_back(string_printf("%02zX/%02zX/%02zX => %28s %28s %28s\n", lines.emplace_back(phosg::string_printf("%02zX/%02zX/%02zX => %28s %28s %28s\n",
a, v1, v2, e.object_list_basename.c_str(), e.enemy_and_event_list_basename.c_str(), e.area_setup_filename.c_str())); a, v1, v2, e.object_list_basename.c_str(), e.enemy_and_event_list_basename.c_str(), e.area_setup_filename.c_str()));
} }
} }
} }
return join(lines, ""); return phosg::join(lines, "");
} }
struct AreaMapFileInfo { struct AreaMapFileInfo {
@@ -2515,10 +2513,10 @@ vector<string> map_filenames_for_variation_deprecated(
string filename = "map_"; string filename = "map_";
filename += a.name_token; filename += a.name_token;
if (!a.variation1_values.empty()) { if (!a.variation1_values.empty()) {
filename += string_printf("_%02" PRIX32, a.variation1_values.at(var1)); filename += phosg::string_printf("_%02" PRIX32, a.variation1_values.at(var1));
} }
if (!a.variation2_values.empty()) { if (!a.variation2_values.empty()) {
filename += string_printf("_%02" PRIX32, a.variation2_values.at(var2)); filename += phosg::string_printf("_%02" PRIX32, a.variation2_values.at(var2));
} }
vector<string> ret; vector<string> ret;
+8 -8
View File
@@ -200,9 +200,9 @@ struct Map {
uint32_t kondrieu; // {SAINT_MILLION, SHAMBERTIN} -> KONDRIEU uint32_t kondrieu; // {SAINT_MILLION, SHAMBERTIN} -> KONDRIEU
RareEnemyRates(uint32_t enemy_rate, uint32_t boss_rate); RareEnemyRates(uint32_t enemy_rate, uint32_t boss_rate);
explicit RareEnemyRates(const JSON& json); explicit RareEnemyRates(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
}; };
static const std::shared_ptr<const RareEnemyRates> NO_RARE_ENEMIES; static const std::shared_ptr<const RareEnemyRates> NO_RARE_ENEMIES;
@@ -295,7 +295,7 @@ struct Map {
DATParserRandomState(uint32_t rare_seed); DATParserRandomState(uint32_t rare_seed);
size_t rand_int_biased(size_t min_v, size_t max_v); size_t rand_int_biased(size_t min_v, size_t max_v);
uint32_t next_location_index(); uint32_t next_location_index();
void generate_shuffled_location_table(const Map::RandomEnemyLocationsHeader& header, StringReader r, uint16_t section); void generate_shuffled_location_table(const Map::RandomEnemyLocationsHeader& header, phosg::StringReader r, uint16_t section);
}; };
Map(Version version, uint32_t lobby_id, uint32_t rare_seed, std::shared_ptr<PSOLFGEncryption> opt_rand_crypt); Map(Version version, uint32_t lobby_id, uint32_t rare_seed, std::shared_ptr<PSOLFGEncryption> opt_rand_crypt);
@@ -327,9 +327,9 @@ struct Map {
uint8_t difficulty, uint8_t difficulty,
uint8_t event, uint8_t event,
uint8_t floor, uint8_t floor,
StringReader wave_events_r, phosg::StringReader wave_events_r,
StringReader random_enemy_locations_r, phosg::StringReader random_enemy_locations_r,
StringReader random_enemy_definitions_r, phosg::StringReader random_enemy_definitions_r,
std::shared_ptr<DATParserRandomState> random_state, std::shared_ptr<DATParserRandomState> random_state,
std::shared_ptr<const RareEnemyRates> rare_rates = DEFAULT_RARE_ENEMIES); std::shared_ptr<const RareEnemyRates> rare_rates = DEFAULT_RARE_ENEMIES);
@@ -373,7 +373,7 @@ struct Map {
static std::string disassemble_wave_events_data(const void* data, size_t size, uint8_t floor = 0xFF); static std::string disassemble_wave_events_data(const void* data, size_t size, uint8_t floor = 0xFF);
static std::string disassemble_quest_data(const void* data, size_t size); static std::string disassemble_quest_data(const void* data, size_t size);
PrefixedLogger log; phosg::PrefixedLogger log;
Version version; Version version;
uint32_t rare_seed; uint32_t rare_seed;
std::shared_ptr<PSOLFGEncryption> opt_rand_crypt; std::shared_ptr<PSOLFGEncryption> opt_rand_crypt;
@@ -438,7 +438,7 @@ public:
std::string str() const; std::string str() const;
private: private:
template <bool IsBigEndian> template <bool BE>
void load_table_t(const std::string& data); void load_table_t(const std::string& data);
// Indexes are [floor][variation1][variation2] // Indexes are [floor][variation1][variation2]
+6 -6
View File
@@ -19,8 +19,8 @@ using namespace std;
uint32_t resolve_address(const char* address) { uint32_t resolve_address(const char* address) {
struct addrinfo* res0; struct addrinfo* res0;
if (getaddrinfo(address, nullptr, nullptr, &res0)) { if (getaddrinfo(address, nullptr, nullptr, &res0)) {
auto e = string_for_error(errno); auto e = phosg::string_for_error(errno);
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"can\'t resolve hostname %s: %s", address, e.c_str())); "can\'t resolve hostname %s: %s", address, e.c_str()));
} }
@@ -32,7 +32,7 @@ uint32_t resolve_address(const char* address) {
} }
} }
if (!res4) { if (!res4) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"can\'t resolve hostname %s: no usable data", address)); "can\'t resolve hostname %s: no usable data", address));
} }
@@ -43,8 +43,8 @@ uint32_t resolve_address(const char* address) {
map<string, uint32_t> get_local_addresses() { map<string, uint32_t> get_local_addresses() {
struct ifaddrs* ifa_raw; struct ifaddrs* ifa_raw;
if (getifaddrs(&ifa_raw)) { if (getifaddrs(&ifa_raw)) {
auto s = string_for_error(errno); auto s = phosg::string_for_error(errno);
throw runtime_error(string_printf("failed to get interface addresses: %s", s.c_str())); throw runtime_error(phosg::string_printf("failed to get interface addresses: %s", s.c_str()));
} }
unique_ptr<struct ifaddrs, void (*)(struct ifaddrs*)> ifa(ifa_raw, freeifaddrs); unique_ptr<struct ifaddrs, void (*)(struct ifaddrs*)> ifa(ifa_raw, freeifaddrs);
@@ -80,7 +80,7 @@ bool is_local_address(const sockaddr_storage& daddr) {
} }
string string_for_address(uint32_t address) { string string_for_address(uint32_t address) {
return string_printf("%hhu.%hhu.%hhu.%hhu", return phosg::string_printf("%hhu.%hhu.%hhu.%hhu",
static_cast<uint8_t>(address >> 24), static_cast<uint8_t>(address >> 16), static_cast<uint8_t>(address >> 24), static_cast<uint8_t>(address >> 16),
static_cast<uint8_t>(address >> 8), static_cast<uint8_t>(address)); static_cast<uint8_t>(address >> 8), static_cast<uint8_t>(address));
} }
+10 -14
View File
@@ -37,44 +37,40 @@ uint32_t PSOLFGEncryption::next(bool advance) {
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
void PSOLFGEncryption::encrypt_t(void* vdata, size_t size, bool advance) { void PSOLFGEncryption::encrypt_t(void* vdata, size_t size, bool advance) {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
if (!advance && (size != 4)) { if (!advance && (size != 4)) {
throw logic_error("cannot peek-encrypt/decrypt with size > 4"); throw logic_error("cannot peek-encrypt/decrypt with size > 4");
} }
size_t uint32_count = size >> 2; size_t uint32_count = size >> 2;
size_t extra_bytes = size & 3; size_t extra_bytes = size & 3;
U32T* data = reinterpret_cast<U32T*>(vdata); U32T<BE>* data = reinterpret_cast<U32T<BE>*>(vdata);
for (size_t x = 0; x < uint32_count; x++) { for (size_t x = 0; x < uint32_count; x++) {
data[x] ^= this->next(advance); data[x] ^= this->next(advance);
} }
if (extra_bytes) { if (extra_bytes) {
U32T last = 0; U32T<BE> last = 0;
memcpy(&last, &data[uint32_count], extra_bytes); memcpy(&last, &data[uint32_count], extra_bytes);
last ^= this->next(advance); last ^= this->next(advance);
memcpy(&data[uint32_count], &last, extra_bytes); memcpy(&data[uint32_count], &last, extra_bytes);
} }
} }
template <bool IsBigEndian> template <bool BE>
void PSOLFGEncryption::encrypt_minus_t(void* vdata, size_t size, bool advance) { void PSOLFGEncryption::encrypt_minus_t(void* vdata, size_t size, bool advance) {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
if (!advance && (size != 4)) { if (!advance && (size != 4)) {
throw logic_error("cannot peek-encrypt/decrypt with size > 4"); throw logic_error("cannot peek-encrypt/decrypt with size > 4");
} }
size_t uint32_count = size >> 2; size_t uint32_count = size >> 2;
size_t extra_bytes = size & 3; size_t extra_bytes = size & 3;
U32T* data = reinterpret_cast<U32T*>(vdata); U32T<BE>* data = reinterpret_cast<U32T<BE>*>(vdata);
for (size_t x = 0; x < uint32_count; x++) { for (size_t x = 0; x < uint32_count; x++) {
data[x] = this->next(advance) - data[x]; data[x] = this->next(advance) - data[x];
} }
if (extra_bytes) { if (extra_bytes) {
U32T last = 0; U32T<BE> last = 0;
memcpy(&last, &data[uint32_count], extra_bytes); memcpy(&last, &data[uint32_count], extra_bytes);
last = this->next(advance) - last; last = this->next(advance) - last;
memcpy(&data[uint32_count], &last, extra_bytes); memcpy(&data[uint32_count], &last, extra_bytes);
@@ -699,11 +695,11 @@ void PSOV2OrV3DetectorEncryption::encrypt(void* data, size_t size, bool advance)
bool v2_match = this->v2_matches.count(decrypted_v2); bool v2_match = this->v2_matches.count(decrypted_v2);
bool v3_match = this->v3_matches.count(decrypted_v3); bool v3_match = this->v3_matches.count(decrypted_v3);
if (!v2_match && !v3_match) { if (!v2_match && !v3_match) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"unable to determine crypt version (input=%08" PRIX32 ", v2=%08" PRIX32 ", v3=%08" PRIX32 ")", "unable to determine crypt version (input=%08" PRIX32 ", v2=%08" PRIX32 ", v3=%08" PRIX32 ")",
encrypted.load(), decrypted_v2.load(), decrypted_v3.load())); encrypted.load(), decrypted_v2.load(), decrypted_v3.load()));
} else if (v2_match && v3_match) { } else if (v2_match && v3_match) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"ambiguous crypt version (v2=%08" PRIX32 ", v3=%08" PRIX32 ")", "ambiguous crypt version (v2=%08" PRIX32 ", v3=%08" PRIX32 ")",
decrypted_v2.load(), decrypted_v3.load())); decrypted_v2.load(), decrypted_v3.load()));
} else if (v2_match) { } else if (v2_match) {
@@ -881,9 +877,9 @@ uint32_t encrypt_challenge_time(uint16_t value) {
vector<uint8_t> available_bits({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}); vector<uint8_t> available_bits({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
uint16_t mask = 0; uint16_t mask = 0;
uint8_t num_one_bits = (random_object<uint8_t>() % 9) + 4; // Range [4, 12] uint8_t num_one_bits = (phosg::random_object<uint8_t>() % 9) + 4; // Range [4, 12]
for (; num_one_bits; num_one_bits--) { for (; num_one_bits; num_one_bits--) {
uint8_t index = random_object<uint8_t>() % available_bits.size(); uint8_t index = phosg::random_object<uint8_t>() % available_bits.size();
auto it = available_bits.begin() + index; auto it = available_bits.begin() + index;
mask |= (1 << *it); mask |= (1 << *it);
available_bits.erase(it); available_bits.erase(it);
+20 -24
View File
@@ -12,6 +12,7 @@
#include "Compression.hh" #include "Compression.hh"
#include "Text.hh" #include "Text.hh"
#include "Types.hh"
class PSOEncryption { class PSOEncryption {
public: public:
@@ -48,9 +49,9 @@ public:
void encrypt_big_endian_minus(void* data, size_t size, bool advance = true); void encrypt_big_endian_minus(void* data, size_t size, bool advance = true);
void encrypt_both_endian(void* le_data, void* be_data, size_t size, bool advance = true); void encrypt_both_endian(void* le_data, void* be_data, size_t size, bool advance = true);
template <bool IsBigEndian> template <bool BE>
void encrypt_t(void* data, size_t size, bool advance = true); void encrypt_t(void* data, size_t size, bool advance = true);
template <bool IsBigEndian> template <bool BE>
void encrypt_minus_t(void* data, size_t size, bool advance = true); void encrypt_minus_t(void* data, size_t size, bool advance = true);
uint32_t next(bool advance = true); uint32_t next(bool advance = true);
@@ -253,11 +254,10 @@ void decrypt_trivial_gci_data(void* data, size_t size, uint8_t basis);
uint32_t encrypt_challenge_time(uint16_t value); uint32_t encrypt_challenge_time(uint16_t value);
uint16_t decrypt_challenge_time(uint32_t value); uint16_t decrypt_challenge_time(uint32_t value);
template <bool IsBigEndian> template <bool BE>
class ChallengeTimeT { class ChallengeTimeT {
private: private:
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; U32T<BE> value;
U32T value;
public: public:
ChallengeTimeT() = default; ChallengeTimeT() = default;
@@ -287,8 +287,8 @@ public:
this->value = ((v == 0) || (v == 0xFFFF)) ? 0 : encrypt_challenge_time(v); this->value = ((v == 0) || (v == 0xFFFF)) ? 0 : encrypt_challenge_time(v);
} }
operator ChallengeTimeT<!IsBigEndian>() const { operator ChallengeTimeT<!BE>() const {
ChallengeTimeT<!IsBigEndian> ret; ChallengeTimeT<!BE> ret;
ret.store_raw(this->value); ret.store_raw(this->value);
return ret; return ret;
} }
@@ -305,19 +305,17 @@ struct DecryptedPR2 {
size_t decompressed_size; size_t decompressed_size;
}; };
template <bool IsBigEndian> template <bool BE>
DecryptedPR2 decrypt_pr2_data(const std::string& data) { DecryptedPR2 decrypt_pr2_data(const std::string& data) {
using U32T = std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t>;
if (data.size() < 8) { if (data.size() < 8) {
throw std::runtime_error("not enough data for PR2 header"); throw std::runtime_error("not enough data for PR2 header");
} }
StringReader r(data); phosg::StringReader r(data);
DecryptedPR2 ret = { DecryptedPR2 ret = {
.compressed_data = data.substr(8), .compressed_data = data.substr(8),
.decompressed_size = r.get<U32T>()}; .decompressed_size = r.get<U32T<BE>>()};
PSOV2Encryption crypt(r.get<U32T>()); PSOV2Encryption crypt(r.get<U32T<BE>>());
if (IsBigEndian) { if (BE) {
crypt.encrypt_big_endian(ret.compressed_data.data(), ret.compressed_data.size()); crypt.encrypt_big_endian(ret.compressed_data.data(), ret.compressed_data.size());
} else { } else {
crypt.decrypt(ret.compressed_data.data(), ret.compressed_data.size()); crypt.decrypt(ret.compressed_data.data(), ret.compressed_data.size());
@@ -325,9 +323,9 @@ DecryptedPR2 decrypt_pr2_data(const std::string& data) {
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
std::string decrypt_and_decompress_pr2_data(const std::string& data) { std::string decrypt_and_decompress_pr2_data(const std::string& data) {
auto decrypted = decrypt_pr2_data<IsBigEndian>(data); auto decrypted = decrypt_pr2_data<BE>(data);
std::string decompressed = prs_decompress(decrypted.compressed_data); std::string decompressed = prs_decompress(decrypted.compressed_data);
if (decompressed.size() != decrypted.decompressed_size) { if (decompressed.size() != decrypted.decompressed_size) {
throw std::runtime_error("decompressed size does not match expected size"); throw std::runtime_error("decompressed size does not match expected size");
@@ -335,18 +333,16 @@ std::string decrypt_and_decompress_pr2_data(const std::string& data) {
return decompressed; return decompressed;
} }
template <bool IsBigEndian> template <bool BE>
std::string encrypt_pr2_data(const std::string& data, size_t decompressed_size, uint32_t seed) { std::string encrypt_pr2_data(const std::string& data, size_t decompressed_size, uint32_t seed) {
using U32T = std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t>; phosg::StringWriter w;
w.put<U32T<BE>>(decompressed_size);
StringWriter w; w.put<U32T<BE>>(seed);
w.put<U32T>(decompressed_size);
w.put<U32T>(seed);
w.write(data); w.write(data);
std::string ret = std::move(w.str()); std::string ret = std::move(w.str());
PSOV2Encryption crypt(seed); PSOV2Encryption crypt(seed);
if (IsBigEndian) { if (BE) {
crypt.encrypt_big_endian(ret.data() + 8, ret.size() - 8); crypt.encrypt_big_endian(ret.data() + 8, ret.size() - 8);
} else { } else {
crypt.decrypt(ret.data() + 8, ret.size() - 8); crypt.decrypt(ret.data() + 8, ret.size() - 8);
@@ -355,5 +351,5 @@ std::string encrypt_pr2_data(const std::string& data, size_t decompressed_size,
} }
inline uint32_t random_from_optional_crypt(std::shared_ptr<PSOLFGEncryption> random_crypt) { inline uint32_t random_from_optional_crypt(std::shared_ptr<PSOLFGEncryption> random_crypt) {
return random_crypt ? random_crypt->next() : random_object<uint32_t>(); return random_crypt ? random_crypt->next() : phosg::random_object<uint32_t>();
} }
+17 -20
View File
@@ -5,33 +5,31 @@
using namespace std; using namespace std;
struct TObjectVTable { struct TObjectVTable {
be_uint32_t unused_a1; phosg::be_uint32_t unused_a1;
be_uint32_t unused_a2; phosg::be_uint32_t unused_a2;
be_uint32_t destroy; phosg::be_uint32_t destroy;
be_uint32_t update; phosg::be_uint32_t update;
be_uint32_t render; phosg::be_uint32_t render;
be_uint32_t render_shadow; phosg::be_uint32_t render_shadow;
} __packed_ws__(TObjectVTable, 0x18); } __packed_ws__(TObjectVTable, 0x18);
struct TObject { struct TObject {
be_uint32_t type_name_addr; phosg::be_uint32_t type_name_addr;
be_uint16_t flags; phosg::be_uint16_t flags;
parray<uint8_t, 2> unused; parray<uint8_t, 2> unused;
be_uint32_t prev_sibling_addr; phosg::be_uint32_t prev_sibling_addr;
be_uint32_t next_sibling_addr; phosg::be_uint32_t next_sibling_addr;
be_uint32_t parent_addr; phosg::be_uint32_t parent_addr;
be_uint32_t children_head_addr; phosg::be_uint32_t children_head_addr;
be_uint32_t vtable_addr; phosg::be_uint32_t vtable_addr;
} __packed_ws__(TObject, 0x1C); } __packed_ws__(TObject, 0x1C);
PSOGCObjectGraph::PSOGCObjectGraph( PSOGCObjectGraph::PSOGCObjectGraph(const string& memory_data, uint32_t root_address) {
const string& memory_data, uint32_t root_address) { phosg::StringReader r(memory_data);
StringReader r(memory_data);
this->root = this->parse_object_memo(r, root_address); this->root = this->parse_object_memo(r, root_address);
} }
shared_ptr<PSOGCObjectGraph::VTable> PSOGCObjectGraph::parse_vtable_memo( shared_ptr<PSOGCObjectGraph::VTable> PSOGCObjectGraph::parse_vtable_memo(phosg::StringReader& r, uint32_t addr) {
StringReader& r, uint32_t addr) {
try { try {
return this->all_vtables.at(addr); return this->all_vtables.at(addr);
} catch (const out_of_range&) { } catch (const out_of_range&) {
@@ -47,8 +45,7 @@ shared_ptr<PSOGCObjectGraph::VTable> PSOGCObjectGraph::parse_vtable_memo(
return ret; return ret;
} }
shared_ptr<PSOGCObjectGraph::Object> PSOGCObjectGraph::parse_object_memo( shared_ptr<PSOGCObjectGraph::Object> PSOGCObjectGraph::parse_object_memo(phosg::StringReader& r, uint32_t addr) {
StringReader& r, uint32_t addr) {
try { try {
return this->all_objects.at(addr); return this->all_objects.at(addr);
} catch (const out_of_range&) { } catch (const out_of_range&) {
+2 -2
View File
@@ -37,6 +37,6 @@ struct PSOGCObjectGraph {
std::unordered_map<uint32_t, std::shared_ptr<Object>> all_objects; std::unordered_map<uint32_t, std::shared_ptr<Object>> all_objects;
std::unordered_map<uint32_t, std::shared_ptr<VTable>> all_vtables; std::unordered_map<uint32_t, std::shared_ptr<VTable>> all_vtables;
std::shared_ptr<Object> parse_object_memo(StringReader& r, uint32_t addr); std::shared_ptr<Object> parse_object_memo(phosg::StringReader& r, uint32_t addr);
std::shared_ptr<VTable> parse_vtable_memo(StringReader& r, uint32_t addr); std::shared_ptr<VTable> parse_vtable_memo(phosg::StringReader& r, uint32_t addr);
}; };
+3 -3
View File
@@ -190,7 +190,7 @@ void PSOCommandHeader::set_flag(Version version, uint32_t flag) {
void check_size_v(size_t size, size_t min_size, size_t max_size) { void check_size_v(size_t size, size_t min_size, size_t max_size) {
if (size < min_size) { if (size < min_size) {
throw std::runtime_error(string_printf( throw std::runtime_error(phosg::string_printf(
"command too small (expected at least 0x%zX bytes, received 0x%zX bytes)", "command too small (expected at least 0x%zX bytes, received 0x%zX bytes)",
min_size, size)); min_size, size));
} }
@@ -198,7 +198,7 @@ void check_size_v(size_t size, size_t min_size, size_t max_size) {
max_size = min_size; max_size = min_size;
} }
if (size > max_size) { if (size > max_size) {
throw std::runtime_error(string_printf( throw std::runtime_error(phosg::string_printf(
"command too large (expected at most 0x%zX bytes, received 0x%zX bytes)", "command too large (expected at most 0x%zX bytes, received 0x%zX bytes)",
max_size, size)); max_size, size));
} }
@@ -210,7 +210,7 @@ std::string prepend_command_header(
uint16_t cmd, uint16_t cmd,
uint32_t flag, uint32_t flag,
const std::string& data) { const std::string& data) {
StringWriter ret; phosg::StringWriter ret;
switch (version) { switch (version) {
case Version::DC_NTE: case Version::DC_NTE:
case Version::DC_V1_11_2000_PROTOTYPE: case Version::DC_V1_11_2000_PROTOTYPE:
+2 -2
View File
@@ -56,12 +56,12 @@ RetT& check_size_generic(
size_t min_size, size_t min_size,
size_t max_size) { size_t max_size) {
if (size < min_size) { if (size < min_size) {
throw std::runtime_error(string_printf( throw std::runtime_error(phosg::string_printf(
"command too small (expected at least 0x%zX bytes, received 0x%zX bytes)", "command too small (expected at least 0x%zX bytes, received 0x%zX bytes)",
min_size, size)); min_size, size));
} }
if (size > max_size) { if (size > max_size) {
throw std::runtime_error(string_printf( throw std::runtime_error(phosg::string_printf(
"command too large (expected at most 0x%zX bytes, received 0x%zX bytes)", "command too large (expected at most 0x%zX bytes, received 0x%zX bytes)",
max_size, size)); max_size, size));
} }
+19 -19
View File
@@ -20,10 +20,10 @@ PatchFileIndex::File::File(PatchFileIndex* index)
std::shared_ptr<const std::string> PatchFileIndex::File::load_data() { std::shared_ptr<const std::string> PatchFileIndex::File::load_data() {
if (!this->loaded_data) { if (!this->loaded_data) {
string relative_path = join(this->path_directories, "/") + "/" + this->name; string relative_path = phosg::join(this->path_directories, "/") + "/" + this->name;
string full_path = this->index->root_dir + "/" + relative_path; string full_path = this->index->root_dir + "/" + relative_path;
patch_index_log.info("Loading data for %s", relative_path.c_str()); patch_index_log.info("Loading data for %s", relative_path.c_str());
this->loaded_data = make_shared<string>(load_file(full_path)); this->loaded_data = make_shared<string>(phosg::load_file(full_path));
this->size = this->loaded_data->size(); this->size = this->loaded_data->size();
} }
return this->loaded_data; return this->loaded_data;
@@ -33,49 +33,49 @@ PatchFileIndex::PatchFileIndex(const string& root_dir)
: root_dir(root_dir) { : root_dir(root_dir) {
string metadata_cache_filename = root_dir + "/.metadata-cache.json"; string metadata_cache_filename = root_dir + "/.metadata-cache.json";
JSON metadata_cache_json; phosg::JSON metadata_cache_json;
try { try {
string metadata_text = load_file(metadata_cache_filename); string metadata_text = phosg::load_file(metadata_cache_filename);
metadata_cache_json = JSON::parse(metadata_text); metadata_cache_json = phosg::JSON::parse(metadata_text);
patch_index_log.info("Loaded patch metadata cache from %s", metadata_cache_filename.c_str()); patch_index_log.info("Loaded patch metadata cache from %s", metadata_cache_filename.c_str());
} catch (const exception& e) { } catch (const exception& e) {
metadata_cache_json = JSON::dict(); metadata_cache_json = phosg::JSON::dict();
patch_index_log.warning("Cannot load patch metadata cache from %s: %s", metadata_cache_filename.c_str(), e.what()); patch_index_log.warning("Cannot load patch metadata cache from %s: %s", metadata_cache_filename.c_str(), e.what());
} }
// Assuming it's rare for patch files to change, we skip writing the metadata // Assuming it's rare for patch files to change, we skip writing the metadata
// cache if no files were changed at all (which should usually be the case) // cache if no files were changed at all (which should usually be the case)
bool should_write_metadata_cache = false; bool should_write_metadata_cache = false;
JSON new_metadata_cache_json = JSON::dict(); phosg::JSON new_metadata_cache_json = phosg::JSON::dict();
vector<string> path_directories; vector<string> path_directories;
function<void(const string&)> collect_dir = [&](const string& dir) -> void { function<void(const string&)> collect_dir = [&](const string& dir) -> void {
path_directories.emplace_back(dir); path_directories.emplace_back(dir);
string relative_dirs = join(path_directories, "/"); string relative_dirs = phosg::join(path_directories, "/");
string full_dir_path = root_dir + '/' + relative_dirs; string full_dir_path = root_dir + '/' + relative_dirs;
patch_index_log.info("Listing directory %s", full_dir_path.c_str()); patch_index_log.info("Listing directory %s", full_dir_path.c_str());
for (const auto& item : list_directory(full_dir_path)) { for (const auto& item : phosg::list_directory(full_dir_path)) {
// Skip invisible files (e.g. .DS_Store on macOS) // Skip invisible files (e.g. .DS_Store on macOS)
if (starts_with(item, ".")) { if (phosg::starts_with(item, ".")) {
continue; continue;
} }
string relative_item_path = relative_dirs + '/' + item; string relative_item_path = relative_dirs + '/' + item;
string full_item_path = root_dir + '/' + relative_item_path; string full_item_path = root_dir + '/' + relative_item_path;
if (isdir(full_item_path)) { if (phosg::isdir(full_item_path)) {
collect_dir(item); collect_dir(item);
} else if (isfile(full_item_path)) { } else if (phosg::isfile(full_item_path)) {
auto st = stat(full_item_path); auto st = phosg::stat(full_item_path);
auto f = make_shared<File>(this); auto f = make_shared<File>(this);
f->path_directories = path_directories; f->path_directories = path_directories;
f->name = item; f->name = item;
string compute_crc32s_message; // If not empty, should compute crc32s string compute_crc32s_message; // If not empty, should compute crc32s
JSON cache_item_json; phosg::JSON cache_item_json;
try { try {
cache_item_json = metadata_cache_json.at(relative_item_path); cache_item_json = metadata_cache_json.at(relative_item_path);
uint64_t cached_size = cache_item_json.get_int(0); uint64_t cached_size = cache_item_json.get_int(0);
@@ -98,19 +98,19 @@ PatchFileIndex::PatchFileIndex(const string& root_dir)
if (!compute_crc32s_message.empty()) { if (!compute_crc32s_message.empty()) {
auto data = f->load_data(); // Sets f->size auto data = f->load_data(); // Sets f->size
f->crc32 = crc32(data->data(), f->size); f->crc32 = phosg::crc32(data->data(), f->size);
for (size_t x = 0; x < data->size(); x += 0x4000) { for (size_t x = 0; x < data->size(); x += 0x4000) {
size_t chunk_bytes = min<size_t>(f->size - x, 0x4000); size_t chunk_bytes = min<size_t>(f->size - x, 0x4000);
f->chunk_crcs.emplace_back(::crc32(data->data() + x, chunk_bytes)); f->chunk_crcs.emplace_back(phosg::crc32(data->data() + x, chunk_bytes));
} }
// File was modified or cache item was missing; make a new cache item // File was modified or cache item was missing; make a new cache item
auto chunk_crcs_item = JSON::list(); auto chunk_crcs_item = phosg::JSON::list();
for (uint32_t chunk_crc : f->chunk_crcs) { for (uint32_t chunk_crc : f->chunk_crcs) {
chunk_crcs_item.emplace_back(chunk_crc); chunk_crcs_item.emplace_back(chunk_crc);
} }
new_metadata_cache_json.emplace( new_metadata_cache_json.emplace(
relative_item_path, JSON::list({f->size, st.st_mtime, f->crc32, std::move(chunk_crcs_item)})); relative_item_path, phosg::JSON::list({f->size, st.st_mtime, f->crc32, std::move(chunk_crcs_item)}));
should_write_metadata_cache = true; should_write_metadata_cache = true;
} else { } else {
@@ -141,7 +141,7 @@ PatchFileIndex::PatchFileIndex(const string& root_dir)
if (should_write_metadata_cache) { if (should_write_metadata_cache) {
try { try {
save_file(metadata_cache_filename, new_metadata_cache_json.serialize()); phosg::save_file(metadata_cache_filename, new_metadata_cache_json.serialize());
patch_index_log.info("Saved patch metadata cache to %s", metadata_cache_filename.c_str()); patch_index_log.info("Saved patch metadata cache to %s", metadata_cache_filename.c_str());
} catch (const exception& e) { } catch (const exception& e) {
patch_index_log.warning("Cannot save patch metadata cache to %s: %s", metadata_cache_filename.c_str(), e.what()); patch_index_log.warning("Cannot save patch metadata cache to %s: %s", metadata_cache_filename.c_str(), e.what());
+17 -17
View File
@@ -37,8 +37,8 @@ PatchServer::Client::Client(
bool hide_data_from_logs) bool hide_data_from_logs)
: server(server), : server(server),
id(next_id++), id(next_id++),
log(string_printf("[C-%" PRIX64 "] ", this->id), client_log.min_level), log(phosg::string_printf("[C-%" PRIX64 "] ", this->id), client_log.min_level),
channel(bev, 0, version, 1, nullptr, nullptr, this, string_printf("C-%" PRIX64, this->id), TerminalFormat::FG_YELLOW, TerminalFormat::FG_GREEN), channel(bev, 0, version, 1, nullptr, nullptr, this, phosg::string_printf("C-%" PRIX64, this->id), phosg::TerminalFormat::FG_YELLOW, phosg::TerminalFormat::FG_GREEN),
idle_timeout_usecs(idle_timeout_usecs), idle_timeout_usecs(idle_timeout_usecs),
idle_timeout_event( idle_timeout_event(
event_new(bufferevent_get_base(bev), -1, EV_TIMEOUT, &PatchServer::Client::dispatch_idle_timeout, this), event_new(bufferevent_get_base(bev), -1, EV_TIMEOUT, &PatchServer::Client::dispatch_idle_timeout, this),
@@ -49,15 +49,15 @@ PatchServer::Client::Client(
// protocol is fully understood and data logs for patch clients are generally // protocol is fully understood and data logs for patch clients are generally
// more annoying than helpful at this point. // more annoying than helpful at this point.
if (hide_data_from_logs) { if (hide_data_from_logs) {
this->channel.terminal_recv_color = TerminalFormat::END; this->channel.terminal_recv_color = phosg::TerminalFormat::END;
this->channel.terminal_send_color = TerminalFormat::END; this->channel.terminal_send_color = phosg::TerminalFormat::END;
} }
this->log.info("Created"); this->log.info("Created");
} }
void PatchServer::Client::reschedule_timeout_event() { void PatchServer::Client::reschedule_timeout_event() {
struct timeval idle_tv = usecs_to_timeval(this->idle_timeout_usecs); struct timeval idle_tv = phosg::usecs_to_timeval(this->idle_timeout_usecs);
event_add(this->idle_timeout_event.get(), &idle_tv); event_add(this->idle_timeout_event.get(), &idle_tv);
} }
@@ -78,8 +78,8 @@ void PatchServer::Client::idle_timeout() {
} }
void PatchServer::send_server_init(shared_ptr<Client> c) const { void PatchServer::send_server_init(shared_ptr<Client> c) const {
uint32_t server_key = random_object<uint32_t>(); uint32_t server_key = phosg::random_object<uint32_t>();
uint32_t client_key = random_object<uint32_t>(); uint32_t client_key = phosg::random_object<uint32_t>();
S_ServerInit_Patch_02 cmd; S_ServerInit_Patch_02 cmd;
cmd.copyright.encode("Patch Server. Copyright SonicTeam, LTD. 2001"); cmd.copyright.encode("Patch Server. Copyright SonicTeam, LTD. 2001");
@@ -92,7 +92,7 @@ void PatchServer::send_server_init(shared_ptr<Client> c) const {
} }
void PatchServer::send_message_box(shared_ptr<Client> c, const string& text) const { void PatchServer::send_message_box(shared_ptr<Client> c, const string& text) const {
StringWriter w; phosg::StringWriter w;
try { try {
if (c->version() == Version::PC_PATCH) { if (c->version() == Version::PC_PATCH) {
w.write(tt_encode_marked_optional(text, c->channel.language, true)); w.write(tt_encode_marked_optional(text, c->channel.language, true));
@@ -102,7 +102,7 @@ void PatchServer::send_message_box(shared_ptr<Client> c, const string& text) con
throw logic_error("non-patch client on patch server"); throw logic_error("non-patch client on patch server");
} }
} catch (const runtime_error& e) { } catch (const runtime_error& e) {
log_warning("Failed to encode message for patch message box command: %s", e.what()); phosg::log_warning("Failed to encode message for patch message box command: %s", e.what());
return; return;
} }
w.put_u16(0); w.put_u16(0);
@@ -168,13 +168,13 @@ void PatchServer::on_04(shared_ptr<Client> c, string& data) {
this->config->account_index->from_bb_credentials(username, &password, false); this->config->account_index->from_bb_credentials(username, &password, false);
} catch (const AccountIndex::incorrect_password& e) { } catch (const AccountIndex::incorrect_password& e) {
this->send_message_box(c, string_printf("Login failed: %s", e.what())); this->send_message_box(c, phosg::string_printf("Login failed: %s", e.what()));
this->disconnect_client(c); this->disconnect_client(c);
return; return;
} catch (const AccountIndex::missing_account& e) { } catch (const AccountIndex::missing_account& e) {
if (!this->config->allow_unregistered_users) { if (!this->config->allow_unregistered_users) {
this->send_message_box(c, string_printf("Login failed: %s", e.what())); this->send_message_box(c, phosg::string_printf("Login failed: %s", e.what()));
this->disconnect_client(c); this->disconnect_client(c);
return; return;
} }
@@ -184,7 +184,7 @@ void PatchServer::on_04(shared_ptr<Client> c, string& data) {
try { try {
this->config->account_index->from_bb_credentials(username, nullptr, false); this->config->account_index->from_bb_credentials(username, nullptr, false);
} catch (const AccountIndex::missing_account& e) { } catch (const AccountIndex::missing_account& e) {
this->send_message_box(c, string_printf("Login failed: %s", e.what())); this->send_message_box(c, phosg::string_printf("Login failed: %s", e.what()));
this->disconnect_client(c); this->disconnect_client(c);
return; return;
} }
@@ -300,7 +300,7 @@ void PatchServer::disconnect_client(shared_ptr<Client> c) {
} }
void PatchServer::enqueue_destroy_clients() { void PatchServer::enqueue_destroy_clients() {
auto tv = usecs_to_timeval(0); auto tv = phosg::usecs_to_timeval(0);
event_add(this->destroy_clients_ev.get(), &tv); event_add(this->destroy_clients_ev.get(), &tv);
} }
@@ -321,7 +321,7 @@ void PatchServer::dispatch_on_listen_error(
void PatchServer::on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr*, int) { void PatchServer::on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr*, int) {
struct sockaddr_storage remote_addr; struct sockaddr_storage remote_addr;
get_socket_addresses(fd, nullptr, &remote_addr); phosg::get_socket_addresses(fd, nullptr, &remote_addr);
if (this->config->banned_ipv4_ranges->check(remote_addr)) { if (this->config->banned_ipv4_ranges->check(remote_addr)) {
close(fd); close(fd);
return; return;
@@ -430,7 +430,7 @@ void PatchServer::wait_for_stop() {
} }
void PatchServer::listen(const std::string& addr_str, const string& socket_path, Version version) { void PatchServer::listen(const std::string& addr_str, const string& socket_path, Version version) {
int fd = ::listen(socket_path, 0, SOMAXCONN); int fd = phosg::listen(socket_path, 0, SOMAXCONN);
server_log.info("Listening on Unix socket %s on fd %d as %s", socket_path.c_str(), fd, addr_str.c_str()); server_log.info("Listening on Unix socket %s on fd %d as %s", socket_path.c_str(), fd, addr_str.c_str());
this->add_socket(addr_str, fd, version); this->add_socket(addr_str, fd, version);
} }
@@ -439,8 +439,8 @@ void PatchServer::listen(const std::string& addr_str, const string& addr, int po
if (port == 0) { if (port == 0) {
this->listen(addr_str, addr, version); this->listen(addr_str, addr, version);
} else { } else {
int fd = ::listen(addr, port, SOMAXCONN); int fd = phosg::listen(addr, port, SOMAXCONN);
string netloc_str = render_netloc(addr, port); string netloc_str = phosg::render_netloc(addr, port);
server_log.info("Listening on TCP interface %s on fd %d as %s", netloc_str.c_str(), fd, addr_str.c_str()); server_log.info("Listening on TCP interface %s on fd %d as %s", netloc_str.c_str(), fd, addr_str.c_str());
this->add_socket(addr_str, fd, version); this->add_socket(addr_str, fd, version);
} }
+1 -1
View File
@@ -50,7 +50,7 @@ private:
public: public:
std::weak_ptr<PatchServer> server; std::weak_ptr<PatchServer> server;
uint64_t id; uint64_t id;
PrefixedLogger log; phosg::PrefixedLogger log;
Channel channel; Channel channel;
std::vector<PatchFileChecksumRequest> patch_file_checksum_requests; std::vector<PatchFileChecksumRequest> patch_file_checksum_requests;
+1 -1
View File
@@ -24,7 +24,7 @@ PlayerFilesManager::PlayerFilesManager(std::shared_ptr<struct event_base> base)
clear_expired_files_event( clear_expired_files_event(
event_new(this->base.get(), -1, EV_TIMEOUT | EV_PERSIST, &PlayerFilesManager::clear_expired_files, this), event_new(this->base.get(), -1, EV_TIMEOUT | EV_PERSIST, &PlayerFilesManager::clear_expired_files, this),
event_free) { event_free) {
auto tv = usecs_to_timeval(30 * 1000 * 1000); auto tv = phosg::usecs_to_timeval(30 * 1000 * 1000);
event_add(this->clear_expired_files_event.get(), &tv); event_add(this->clear_expired_files_event.get(), &tv);
} }
+22 -28
View File
@@ -45,16 +45,14 @@ class ItemParameterTable;
// items[13].extension_data2 through items[15].extension_data2: // items[13].extension_data2 through items[15].extension_data2:
// Unknown. These are not an array, but do appear to be related. // Unknown. These are not an array, but do appear to be related.
template <bool IsBigEndian> template <bool BE>
struct PlayerInventoryItemT { struct PlayerInventoryItemT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
/* 00 */ uint8_t present = 0; /* 00 */ uint8_t present = 0;
/* 01 */ uint8_t unknown_a1 = 0; /* 01 */ uint8_t unknown_a1 = 0;
// See note above about these fields // See note above about these fields
/* 02 */ uint8_t extension_data1 = 0; /* 02 */ uint8_t extension_data1 = 0;
/* 03 */ uint8_t extension_data2 = 0; /* 03 */ uint8_t extension_data2 = 0;
/* 04 */ U32T flags = 0; // 8 = equipped /* 04 */ U32T<BE> flags = 0; // 8 = equipped
/* 08 */ ItemData data; /* 08 */ ItemData data;
/* 1C */ /* 1C */
@@ -68,15 +66,15 @@ struct PlayerInventoryItemT {
flags(equipped ? 8 : 0), flags(equipped ? 8 : 0),
data(item) {} data(item) {}
operator PlayerInventoryItemT<!IsBigEndian>() const { operator PlayerInventoryItemT<!BE>() const {
PlayerInventoryItemT<!IsBigEndian> ret; PlayerInventoryItemT<!BE> ret;
ret.present = this->present; ret.present = this->present;
ret.unknown_a1 = this->unknown_a1; ret.unknown_a1 = this->unknown_a1;
ret.extension_data1 = this->extension_data1; ret.extension_data1 = this->extension_data1;
ret.extension_data2 = this->extension_data2; ret.extension_data2 = this->extension_data2;
ret.flags = this->flags.load(); ret.flags = this->flags.load();
ret.data = this->data; ret.data = this->data;
ret.data.id.store_raw(bswap32(ret.data.id.load_raw())); ret.data.id.store_raw(phosg::bswap32(ret.data.id.load_raw()));
return ret; return ret;
} }
} __packed__; } __packed__;
@@ -85,21 +83,19 @@ using PlayerInventoryItemBE = PlayerInventoryItemT<true>;
check_struct_size(PlayerInventoryItem, 0x1C); check_struct_size(PlayerInventoryItem, 0x1C);
check_struct_size(PlayerInventoryItemBE, 0x1C); check_struct_size(PlayerInventoryItemBE, 0x1C);
template <bool IsBigEndian> template <bool BE>
struct PlayerBankItemT { struct PlayerBankItemT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
/* 00 */ ItemData data; /* 00 */ ItemData data;
/* 14 */ U16T amount = 0; /* 14 */ U16T<BE> amount = 0;
/* 16 */ U16T present = 0; /* 16 */ U16T<BE> present = 0;
/* 18 */ /* 18 */
inline bool operator<(const PlayerBankItemT<IsBigEndian>& other) const { inline bool operator<(const PlayerBankItemT<BE>& other) const {
return this->data < other.data; return this->data < other.data;
} }
operator PlayerBankItemT<!IsBigEndian>() const { operator PlayerBankItemT<!BE>() const {
PlayerBankItemT<!IsBigEndian> ret; PlayerBankItemT<!BE> ret;
ret.data = this->data; ret.data = this->data;
ret.amount = this->amount.load(); ret.amount = this->amount.load();
ret.present = this->present.load(); ret.present = this->present.load();
@@ -111,13 +107,13 @@ using PlayerBankItemBE = PlayerBankItemT<true>;
check_struct_size(PlayerBankItem, 0x18); check_struct_size(PlayerBankItem, 0x18);
check_struct_size(PlayerBankItemBE, 0x18); check_struct_size(PlayerBankItemBE, 0x18);
template <bool IsBigEndian> template <bool BE>
struct PlayerInventoryT { struct PlayerInventoryT {
/* 0000 */ uint8_t num_items = 0; /* 0000 */ uint8_t num_items = 0;
/* 0001 */ uint8_t hp_from_materials = 0; /* 0001 */ uint8_t hp_from_materials = 0;
/* 0002 */ uint8_t tp_from_materials = 0; /* 0002 */ uint8_t tp_from_materials = 0;
/* 0003 */ uint8_t language = 0; /* 0003 */ uint8_t language = 0;
/* 0004 */ parray<PlayerInventoryItemT<IsBigEndian>, 30> items; /* 0004 */ parray<PlayerInventoryItemT<BE>, 30> items;
/* 034C */ /* 034C */
size_t find_item(uint32_t item_id) const { size_t find_item(uint32_t item_id) const {
@@ -287,8 +283,8 @@ struct PlayerInventoryT {
} }
} }
operator PlayerInventoryT<!IsBigEndian>() const { operator PlayerInventoryT<!BE>() const {
PlayerInventoryT<!IsBigEndian> ret; PlayerInventoryT<!BE> ret;
ret.num_items = this->num_items; ret.num_items = this->num_items;
ret.hp_from_materials = this->hp_from_materials; ret.hp_from_materials = this->hp_from_materials;
ret.tp_from_materials = this->tp_from_materials; ret.tp_from_materials = this->tp_from_materials;
@@ -302,13 +298,11 @@ using PlayerInventoryBE = PlayerInventoryT<true>;
check_struct_size(PlayerInventory, 0x34C); check_struct_size(PlayerInventory, 0x34C);
check_struct_size(PlayerInventoryBE, 0x34C); check_struct_size(PlayerInventoryBE, 0x34C);
template <size_t SlotCount, bool IsBigEndian> template <size_t SlotCount, bool BE>
struct PlayerBankT { struct PlayerBankT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; /* 0000 */ U32T<BE> num_items = 0;
/* 0004 */ U32T<BE> meseta = 0;
/* 0000 */ U32T num_items = 0; /* 0008 */ parray<PlayerBankItemT<BE>, SlotCount> items;
/* 0004 */ U32T meseta = 0;
/* 0008 */ parray<PlayerBankItemT<IsBigEndian>, SlotCount> items;
/* 05A8 for 60 items (v1/v2), 12C8 for 200 items (v3/v4) */ /* 05A8 for 60 items (v1/v2), 12C8 for 200 items (v3/v4) */
void add_item(const ItemData& item, const ItemData::StackLimits& limits) { void add_item(const ItemData& item, const ItemData::StackLimits& limits) {
@@ -408,9 +402,9 @@ struct PlayerBankT {
} }
} }
template <size_t DestSlotCount, bool DestIsBigEndian> template <size_t DestSlotCount, bool DestBE>
operator PlayerBankT<DestSlotCount, DestIsBigEndian>() const { operator PlayerBankT<DestSlotCount, DestBE>() const {
PlayerBankT<DestSlotCount, DestIsBigEndian> ret; PlayerBankT<DestSlotCount, DestBE> ret;
ret.num_items = std::min<size_t>(ret.items.size(), this->num_items.load()); ret.num_items = std::min<size_t>(ret.items.size(), this->num_items.load());
ret.meseta = this->meseta.load(); ret.meseta = this->meseta.load();
for (size_t z = 0; z < std::min<size_t>(ret.items.size(), this->items.size()); z++) { for (size_t z = 0; z < std::min<size_t>(ret.items.size(), this->items.size()); z++) {
+21 -21
View File
@@ -324,8 +324,8 @@ QuestFlagsV1::operator QuestFlags() const {
return ret; return ret;
} }
BattleRules::BattleRules(const JSON& json) { BattleRules::BattleRules(const phosg::JSON& json) {
static const JSON empty_list = JSON::list(); static const phosg::JSON empty_list = phosg::JSON::list();
this->tech_disk_mode = json.get_enum("TechDiskMode", this->tech_disk_mode); this->tech_disk_mode = json.get_enum("TechDiskMode", this->tech_disk_mode);
this->weapon_and_armor_mode = json.get_enum("WeaponAndArmorMode", this->weapon_and_armor_mode); this->weapon_and_armor_mode = json.get_enum("WeaponAndArmorMode", this->weapon_and_armor_mode);
@@ -340,7 +340,7 @@ BattleRules::BattleRules(const JSON& json) {
this->hide_target_reticle = json.get_int("HideTargetReticle", this->hide_target_reticle); this->hide_target_reticle = json.get_int("HideTargetReticle", this->hide_target_reticle);
this->meseta_mode = json.get_enum("MesetaMode", this->meseta_mode); this->meseta_mode = json.get_enum("MesetaMode", this->meseta_mode);
this->death_level_up = json.get_int("DeathLevelUp", this->death_level_up); this->death_level_up = json.get_int("DeathLevelUp", this->death_level_up);
const JSON& trap_counts_json = json.get("TrapCounts", empty_list); const phosg::JSON& trap_counts_json = json.get("TrapCounts", empty_list);
for (size_t z = 0; z < trap_counts_json.size(); z++) { for (size_t z = 0; z < trap_counts_json.size(); z++) {
this->trap_counts[z] = trap_counts_json.at(z).as_int(); this->trap_counts[z] = trap_counts_json.at(z).as_int();
} }
@@ -355,8 +355,8 @@ BattleRules::BattleRules(const JSON& json) {
this->box_drop_area = json.get_int("BoxDropArea", this->box_drop_area); this->box_drop_area = json.get_int("BoxDropArea", this->box_drop_area);
} }
JSON BattleRules::json() const { phosg::JSON BattleRules::json() const {
return JSON::dict({ return phosg::JSON::dict({
{"TechDiskMode", this->tech_disk_mode}, {"TechDiskMode", this->tech_disk_mode},
{"WeaponAndArmorMode", this->weapon_and_armor_mode}, {"WeaponAndArmorMode", this->weapon_and_armor_mode},
{"MagMode", this->mag_mode}, {"MagMode", this->mag_mode},
@@ -370,7 +370,7 @@ JSON BattleRules::json() const {
{"HideTargetReticle", this->hide_target_reticle}, {"HideTargetReticle", this->hide_target_reticle},
{"MesetaMode", this->meseta_mode}, {"MesetaMode", this->meseta_mode},
{"DeathLevelUp", this->death_level_up}, {"DeathLevelUp", this->death_level_up},
{"TrapCounts", JSON::list({this->trap_counts[0], this->trap_counts[1], this->trap_counts[2], this->trap_counts[3]})}, {"TrapCounts", phosg::JSON::list({this->trap_counts[0], this->trap_counts[1], this->trap_counts[2], this->trap_counts[3]})},
{"EnableSonar", this->enable_sonar}, {"EnableSonar", this->enable_sonar},
{"SonarCount", this->sonar_count}, {"SonarCount", this->sonar_count},
{"ForbidScapeDolls", this->forbid_scape_dolls}, {"ForbidScapeDolls", this->forbid_scape_dolls},
@@ -384,7 +384,7 @@ JSON BattleRules::json() const {
} }
template <> template <>
const char* name_for_enum<BattleRules::TechDiskMode>(BattleRules::TechDiskMode v) { const char* phosg::name_for_enum<BattleRules::TechDiskMode>(BattleRules::TechDiskMode v) {
switch (v) { switch (v) {
case BattleRules::TechDiskMode::ALLOW: case BattleRules::TechDiskMode::ALLOW:
return "ALLOW"; return "ALLOW";
@@ -397,7 +397,7 @@ const char* name_for_enum<BattleRules::TechDiskMode>(BattleRules::TechDiskMode v
} }
} }
template <> template <>
BattleRules::TechDiskMode enum_for_name<BattleRules::TechDiskMode>(const char* name) { BattleRules::TechDiskMode phosg::enum_for_name<BattleRules::TechDiskMode>(const char* name) {
if (!strcmp(name, "ALLOW")) { if (!strcmp(name, "ALLOW")) {
return BattleRules::TechDiskMode::ALLOW; return BattleRules::TechDiskMode::ALLOW;
} else if (!strcmp(name, "FORBID_ALL")) { } else if (!strcmp(name, "FORBID_ALL")) {
@@ -410,7 +410,7 @@ BattleRules::TechDiskMode enum_for_name<BattleRules::TechDiskMode>(const char* n
} }
template <> template <>
const char* name_for_enum<BattleRules::WeaponAndArmorMode>(BattleRules::WeaponAndArmorMode v) { const char* phosg::name_for_enum<BattleRules::WeaponAndArmorMode>(BattleRules::WeaponAndArmorMode v) {
switch (v) { switch (v) {
case BattleRules::WeaponAndArmorMode::ALLOW: case BattleRules::WeaponAndArmorMode::ALLOW:
return "ALLOW"; return "ALLOW";
@@ -425,7 +425,7 @@ const char* name_for_enum<BattleRules::WeaponAndArmorMode>(BattleRules::WeaponAn
} }
} }
template <> template <>
BattleRules::WeaponAndArmorMode enum_for_name<BattleRules::WeaponAndArmorMode>(const char* name) { BattleRules::WeaponAndArmorMode phosg::enum_for_name<BattleRules::WeaponAndArmorMode>(const char* name) {
if (!strcmp(name, "ALLOW")) { if (!strcmp(name, "ALLOW")) {
return BattleRules::WeaponAndArmorMode::ALLOW; return BattleRules::WeaponAndArmorMode::ALLOW;
} else if (!strcmp(name, "CLEAR_AND_ALLOW")) { } else if (!strcmp(name, "CLEAR_AND_ALLOW")) {
@@ -440,7 +440,7 @@ BattleRules::WeaponAndArmorMode enum_for_name<BattleRules::WeaponAndArmorMode>(c
} }
template <> template <>
const char* name_for_enum<BattleRules::MagMode>(BattleRules::MagMode v) { const char* phosg::name_for_enum<BattleRules::MagMode>(BattleRules::MagMode v) {
switch (v) { switch (v) {
case BattleRules::MagMode::ALLOW: case BattleRules::MagMode::ALLOW:
return "ALLOW"; return "ALLOW";
@@ -451,7 +451,7 @@ const char* name_for_enum<BattleRules::MagMode>(BattleRules::MagMode v) {
} }
} }
template <> template <>
BattleRules::MagMode enum_for_name<BattleRules::MagMode>(const char* name) { BattleRules::MagMode phosg::enum_for_name<BattleRules::MagMode>(const char* name) {
if (!strcmp(name, "ALLOW")) { if (!strcmp(name, "ALLOW")) {
return BattleRules::MagMode::ALLOW; return BattleRules::MagMode::ALLOW;
} else if (!strcmp(name, "FORBID_ALL")) { } else if (!strcmp(name, "FORBID_ALL")) {
@@ -462,7 +462,7 @@ BattleRules::MagMode enum_for_name<BattleRules::MagMode>(const char* name) {
} }
template <> template <>
const char* name_for_enum<BattleRules::ToolMode>(BattleRules::ToolMode v) { const char* phosg::name_for_enum<BattleRules::ToolMode>(BattleRules::ToolMode v) {
switch (v) { switch (v) {
case BattleRules::ToolMode::ALLOW: case BattleRules::ToolMode::ALLOW:
return "ALLOW"; return "ALLOW";
@@ -475,7 +475,7 @@ const char* name_for_enum<BattleRules::ToolMode>(BattleRules::ToolMode v) {
} }
} }
template <> template <>
BattleRules::ToolMode enum_for_name<BattleRules::ToolMode>(const char* name) { BattleRules::ToolMode phosg::enum_for_name<BattleRules::ToolMode>(const char* name) {
if (!strcmp(name, "ALLOW")) { if (!strcmp(name, "ALLOW")) {
return BattleRules::ToolMode::ALLOW; return BattleRules::ToolMode::ALLOW;
} else if (!strcmp(name, "CLEAR_AND_ALLOW")) { } else if (!strcmp(name, "CLEAR_AND_ALLOW")) {
@@ -488,7 +488,7 @@ BattleRules::ToolMode enum_for_name<BattleRules::ToolMode>(const char* name) {
} }
template <> template <>
const char* name_for_enum<BattleRules::TrapMode>(BattleRules::TrapMode v) { const char* phosg::name_for_enum<BattleRules::TrapMode>(BattleRules::TrapMode v) {
switch (v) { switch (v) {
case BattleRules::TrapMode::DEFAULT: case BattleRules::TrapMode::DEFAULT:
return "DEFAULT"; return "DEFAULT";
@@ -499,7 +499,7 @@ const char* name_for_enum<BattleRules::TrapMode>(BattleRules::TrapMode v) {
} }
} }
template <> template <>
BattleRules::TrapMode enum_for_name<BattleRules::TrapMode>(const char* name) { BattleRules::TrapMode phosg::enum_for_name<BattleRules::TrapMode>(const char* name) {
if (!strcmp(name, "DEFAULT")) { if (!strcmp(name, "DEFAULT")) {
return BattleRules::TrapMode::DEFAULT; return BattleRules::TrapMode::DEFAULT;
} else if (!strcmp(name, "ALL_PLAYERS")) { } else if (!strcmp(name, "ALL_PLAYERS")) {
@@ -510,7 +510,7 @@ BattleRules::TrapMode enum_for_name<BattleRules::TrapMode>(const char* name) {
} }
template <> template <>
const char* name_for_enum<BattleRules::MesetaMode>(BattleRules::MesetaMode v) { const char* phosg::name_for_enum<BattleRules::MesetaMode>(BattleRules::MesetaMode v) {
switch (v) { switch (v) {
case BattleRules::MesetaMode::ALLOW: case BattleRules::MesetaMode::ALLOW:
return "ALLOW"; return "ALLOW";
@@ -523,7 +523,7 @@ const char* name_for_enum<BattleRules::MesetaMode>(BattleRules::MesetaMode v) {
} }
} }
template <> template <>
BattleRules::MesetaMode enum_for_name<BattleRules::MesetaMode>(const char* name) { BattleRules::MesetaMode phosg::enum_for_name<BattleRules::MesetaMode>(const char* name) {
if (!strcmp(name, "ALLOW")) { if (!strcmp(name, "ALLOW")) {
return BattleRules::MesetaMode::ALLOW; return BattleRules::MesetaMode::ALLOW;
} else if (!strcmp(name, "FORBID_ALL")) { } else if (!strcmp(name, "FORBID_ALL")) {
@@ -536,7 +536,7 @@ BattleRules::MesetaMode enum_for_name<BattleRules::MesetaMode>(const char* name)
} }
template <> template <>
const char* name_for_enum<BattleRules::RespawnMode>(BattleRules::RespawnMode v) { const char* phosg::name_for_enum<BattleRules::RespawnMode>(BattleRules::RespawnMode v) {
switch (v) { switch (v) {
case BattleRules::RespawnMode::ALLOW: case BattleRules::RespawnMode::ALLOW:
return "ALLOW"; return "ALLOW";
@@ -549,7 +549,7 @@ const char* name_for_enum<BattleRules::RespawnMode>(BattleRules::RespawnMode v)
} }
} }
template <> template <>
BattleRules::RespawnMode enum_for_name<BattleRules::RespawnMode>(const char* name) { BattleRules::RespawnMode phosg::enum_for_name<BattleRules::RespawnMode>(const char* name) {
if (!strcmp(name, "ALLOW")) { if (!strcmp(name, "ALLOW")) {
return BattleRules::RespawnMode::ALLOW; return BattleRules::RespawnMode::ALLOW;
} else if (!strcmp(name, "FORBID")) { } else if (!strcmp(name, "FORBID")) {
@@ -709,7 +709,7 @@ void RecentSwitchFlags::add(uint16_t flag_num) {
} }
string RecentSwitchFlags::enable_commands(uint8_t floor) const { string RecentSwitchFlags::enable_commands(uint8_t floor) const {
StringWriter w; phosg::StringWriter w;
uint64_t flag_nums = this->flag_nums; uint64_t flag_nums = this->flag_nums;
for (size_t z = 0; z < 4; z++) { for (size_t z = 0; z < 4; z++) {
uint16_t flag_num = flag_nums; uint16_t flag_num = flag_nums;
+74 -91
View File
@@ -25,15 +25,11 @@ class ItemParameterTable;
struct PlayerDispDataBB; struct PlayerDispDataBB;
template <bool IsBigEndian> template <bool BE>
struct PlayerVisualConfigT { struct PlayerVisualConfigT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
using F32T = typename std::conditional<IsBigEndian, be_float, le_float>::type;
/* 00 */ pstring<TextEncoding::ASCII, 0x10> name; /* 00 */ pstring<TextEncoding::ASCII, 0x10> name;
/* 10 */ parray<uint8_t, 8> unknown_a2; /* 10 */ parray<uint8_t, 8> unknown_a2;
/* 18 */ U32T name_color = 0xFFFFFFFF; // ARGB /* 18 */ U32T<BE> name_color = 0xFFFFFFFF; // ARGB
/* 1C */ uint8_t extra_model = 0; /* 1C */ uint8_t extra_model = 0;
/* 1D */ parray<uint8_t, 0x0F> unused; /* 1D */ parray<uint8_t, 0x0F> unused;
// See compute_name_color_checksum for details on how this is computed. If the // See compute_name_color_checksum for details on how this is computed. If the
@@ -41,7 +37,7 @@ struct PlayerVisualConfigT {
// default color instead. This field is ignored on GC; on BB (and presumably // default color instead. This field is ignored on GC; on BB (and presumably
// Xbox), if this has a nonzero value, the "Change Name" option appears in the // Xbox), if this has a nonzero value, the "Change Name" option appears in the
// character selection menu. // character selection menu.
/* 2C */ U32T name_color_checksum = 0; /* 2C */ U32T<BE> name_color_checksum = 0;
/* 30 */ uint8_t section_id = 0; /* 30 */ uint8_t section_id = 0;
/* 31 */ uint8_t char_class = 0; /* 31 */ uint8_t char_class = 0;
// validation_flags specifies that some parts of this structure are not valid // validation_flags specifies that some parts of this structure are not valid
@@ -57,22 +53,22 @@ struct PlayerVisualConfigT {
// F = force, R = ranger, H = hunter // F = force, R = ranger, H = hunter
// A = android, N = newman, M = human // A = android, N = newman, M = human
// f = female, m = male // f = female, m = male
/* 34 */ U32T class_flags = 0; /* 34 */ U32T<BE> class_flags = 0;
/* 38 */ U16T costume = 0; /* 38 */ U16T<BE> costume = 0;
/* 3A */ U16T skin = 0; /* 3A */ U16T<BE> skin = 0;
/* 3C */ U16T face = 0; /* 3C */ U16T<BE> face = 0;
/* 3E */ U16T head = 0; /* 3E */ U16T<BE> head = 0;
/* 40 */ U16T hair = 0; /* 40 */ U16T<BE> hair = 0;
/* 42 */ U16T hair_r = 0; /* 42 */ U16T<BE> hair_r = 0;
/* 44 */ U16T hair_g = 0; /* 44 */ U16T<BE> hair_g = 0;
/* 46 */ U16T hair_b = 0; /* 46 */ U16T<BE> hair_b = 0;
/* 48 */ F32T proportion_x = 0.0; /* 48 */ F32T<BE> proportion_x = 0.0;
/* 4C */ F32T proportion_y = 0.0; /* 4C */ F32T<BE> proportion_y = 0.0;
/* 50 */ /* 50 */
static uint32_t compute_name_color_checksum(uint32_t name_color) { static uint32_t compute_name_color_checksum(uint32_t name_color) {
uint8_t x = (random_object<uint32_t>() % 0xFF) + 1; uint8_t x = (phosg::random_object<uint32_t>() % 0xFF) + 1;
uint8_t y = (random_object<uint32_t>() % 0xFF) + 1; uint8_t y = (phosg::random_object<uint32_t>() % 0xFF) + 1;
// name_color (ARGB) = ABCDEFGHabcdefghIJKLMNOPijklmnop // name_color (ARGB) = ABCDEFGHabcdefghIJKLMNOPijklmnop
// name_color_checksum = 000000000ijklmabcdeIJKLM00000000 ^ xxxxxxxxyyyyyyyyxxxxxxxxyyyyyyyy // name_color_checksum = 000000000ijklmabcdeIJKLM00000000 ^ xxxxxxxxyyyyyyyyxxxxxxxxyyyyyyyy
uint32_t xbrgx95558 = ((name_color << 15) & 0x007C0000) | ((name_color >> 6) & 0x0003E000) | ((name_color >> 3) & 0x00001F00); uint32_t xbrgx95558 = ((name_color << 15) & 0x007C0000) | ((name_color >> 6) & 0x0003E000) | ((name_color >> 3) & 0x00001F00);
@@ -208,8 +204,8 @@ struct PlayerVisualConfigT {
this->name.clear_after_bytes(0x0C); this->name.clear_after_bytes(0x0C);
} }
operator PlayerVisualConfigT<!IsBigEndian>() const { operator PlayerVisualConfigT<!BE>() const {
PlayerVisualConfigT<!IsBigEndian> ret; PlayerVisualConfigT<!BE> ret;
ret.name = this->name; ret.name = this->name;
ret.unknown_a2 = this->unknown_a2; ret.unknown_a2 = this->unknown_a2;
ret.name_color = this->name_color.load(); ret.name_color = this->name_color.load();
@@ -239,10 +235,10 @@ using PlayerVisualConfigBE = PlayerVisualConfigT<true>;
check_struct_size(PlayerVisualConfig, 0x50); check_struct_size(PlayerVisualConfig, 0x50);
check_struct_size(PlayerVisualConfigBE, 0x50); check_struct_size(PlayerVisualConfigBE, 0x50);
template <bool IsBigEndian> template <bool BE>
struct PlayerDispDataDCPCV3T { struct PlayerDispDataDCPCV3T {
/* 00 */ PlayerStatsT<IsBigEndian> stats; /* 00 */ PlayerStatsT<BE> stats;
/* 24 */ PlayerVisualConfigT<IsBigEndian> visual; /* 24 */ PlayerVisualConfigT<BE> visual;
/* 74 */ parray<uint8_t, 0x48> config; /* 74 */ parray<uint8_t, 0x48> config;
/* BC */ parray<uint8_t, 0x14> technique_levels_v1; /* BC */ parray<uint8_t, 0x14> technique_levels_v1;
/* D0 */ /* D0 */
@@ -283,9 +279,9 @@ struct PlayerDispDataBB {
this->name.clear_after_bytes(0x18); // 12 characters this->name.clear_after_bytes(0x18); // 12 characters
} }
template <bool IsBigEndian> template <bool BE>
PlayerDispDataDCPCV3T<IsBigEndian> to_dcpcv3(uint8_t to_language, uint8_t from_language) const { PlayerDispDataDCPCV3T<BE> to_dcpcv3(uint8_t to_language, uint8_t from_language) const {
PlayerDispDataDCPCV3T<IsBigEndian> ret; PlayerDispDataDCPCV3T<BE> ret;
ret.stats = this->stats; ret.stats = this->stats;
ret.visual = this->visual; ret.visual = this->visual;
std::string decoded_name = this->name.decode(from_language); std::string decoded_name = this->name.decode(from_language);
@@ -299,8 +295,8 @@ struct PlayerDispDataBB {
void apply_dressing_room(const PlayerDispDataBBPreview&); void apply_dressing_room(const PlayerDispDataBBPreview&);
} __packed_ws__(PlayerDispDataBB, 0x190); } __packed_ws__(PlayerDispDataBB, 0x190);
template <bool IsBigEndian> template <bool BE>
PlayerDispDataBB PlayerDispDataDCPCV3T<IsBigEndian>::to_bb(uint8_t to_language, uint8_t from_language) const { PlayerDispDataBB PlayerDispDataDCPCV3T<BE>::to_bb(uint8_t to_language, uint8_t from_language) const {
PlayerDispDataBB bb; PlayerDispDataBB bb;
bb.stats = this->stats; bb.stats = this->stats;
bb.visual = this->visual; bb.visual = this->visual;
@@ -371,13 +367,11 @@ struct GuildCardPC {
// 0090 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | // 0090 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
// 00A0 | 00 00 00 00 00 00 00 00 01 00 06 00 | // 00A0 | 00 00 00 00 00 00 00 00 01 00 06 00 |
template <bool IsBigEndian, size_t DescriptionLength> template <bool BE, size_t DescriptionLength>
struct GuildCardGCT { struct GuildCardGCT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
/* NTE:Final */ /* NTE:Final */
/* 00:00 */ U32T player_tag = 0x00010000; /* 00:00 */ U32T<BE> player_tag = 0x00010000;
/* 04:04 */ U32T guild_card_number = 0; /* 04:04 */ U32T<BE> guild_card_number = 0;
/* 08:08 */ pstring<TextEncoding::ASCII, 0x18> name; /* 08:08 */ pstring<TextEncoding::ASCII, 0x18> name;
/* 20:20 */ pstring<TextEncoding::MARKED, DescriptionLength> description; /* 20:20 */ pstring<TextEncoding::MARKED, DescriptionLength> description;
/* 8C:8C */ uint8_t present = 0; /* 8C:8C */ uint8_t present = 0;
@@ -429,9 +423,9 @@ struct GuildCardBB {
operator GuildCardDCNTE() const; operator GuildCardDCNTE() const;
operator GuildCardDC() const; operator GuildCardDC() const;
operator GuildCardPC() const; operator GuildCardPC() const;
template <bool IsBigEndian, size_t DescriptionLength> template <bool BE, size_t DescriptionLength>
operator GuildCardGCT<IsBigEndian, DescriptionLength>() const { operator GuildCardGCT<BE, DescriptionLength>() const {
GuildCardGCT<IsBigEndian, DescriptionLength> ret; GuildCardGCT<BE, DescriptionLength> ret;
ret.player_tag = 0x00010000; ret.player_tag = 0x00010000;
ret.guild_card_number = this->guild_card_number.load(); ret.guild_card_number = this->guild_card_number.load();
ret.name.encode(this->name.decode(this->language), this->language); ret.name.encode(this->name.decode(this->language), this->language);
@@ -445,8 +439,8 @@ struct GuildCardBB {
operator GuildCardXB() const; operator GuildCardXB() const;
} __packed_ws__(GuildCardBB, 0x108); } __packed_ws__(GuildCardBB, 0x108);
template <bool IsBigEndian, size_t DescriptionLength> template <bool BE, size_t DescriptionLength>
GuildCardGCT<IsBigEndian, DescriptionLength>::operator GuildCardBB() const { GuildCardGCT<BE, DescriptionLength>::operator GuildCardBB() const {
GuildCardBB ret; GuildCardBB ret;
ret.guild_card_number = this->guild_card_number.load(); ret.guild_card_number = this->guild_card_number.load();
ret.name.encode(this->name.decode(this->language), this->language); ret.name.encode(this->name.decode(this->language), this->language);
@@ -524,14 +518,13 @@ struct PlayerLobbyDataBB {
void clear(); void clear();
} __packed_ws__(PlayerLobbyDataBB, 0x44); } __packed_ws__(PlayerLobbyDataBB, 0x44);
template <bool IsBigEndian> template <bool BE>
struct ChallengeAwardStateT { struct ChallengeAwardStateT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; U32T<BE> rank_award_flags = 0;
U32T rank_award_flags = 0; ChallengeTimeT<BE> maximum_rank;
ChallengeTimeT<IsBigEndian> maximum_rank;
operator ChallengeAwardStateT<!IsBigEndian>() const { operator ChallengeAwardStateT<!BE>() const {
ChallengeAwardStateT<!IsBigEndian> ret; ChallengeAwardStateT<!BE> ret;
ret.rank_award_flags = this->rank_award_flags.load(); ret.rank_award_flags = this->rank_award_flags.load();
ret.maximum_rank = this->maximum_rank; ret.maximum_rank = this->maximum_rank;
return ret; return ret;
@@ -575,38 +568,34 @@ using PlayerRecordsChallengePC = PlayerRecordsChallengeDCPCT<TextEncoding::UTF16
check_struct_size(PlayerRecordsChallengeDC, 0xA0); check_struct_size(PlayerRecordsChallengeDC, 0xA0);
check_struct_size(PlayerRecordsChallengePC, 0xD8); check_struct_size(PlayerRecordsChallengePC, 0xD8);
template <bool IsBigEndian> template <bool BE>
struct PlayerRecordsChallengeV3T { struct PlayerRecordsChallengeV3T {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
using F32T = typename std::conditional<IsBigEndian, be_float, le_float>::type;
// Offsets are (1) relative to start of C5 entry, and (2) relative to start // Offsets are (1) relative to start of C5 entry, and (2) relative to start
// of save file structure // of save file structure
struct Stats { struct Stats {
/* 00:1C */ U16T title_color = 0x7FFF; // XRGB1555 /* 00:1C */ U16T<BE> title_color = 0x7FFF; // XRGB1555
/* 02:1E */ parray<uint8_t, 2> unknown_u0; /* 02:1E */ parray<uint8_t, 2> unknown_u0;
/* 04:20 */ parray<ChallengeTimeT<IsBigEndian>, 9> times_ep1_online; /* 04:20 */ parray<ChallengeTimeT<BE>, 9> times_ep1_online;
/* 28:44 */ parray<ChallengeTimeT<IsBigEndian>, 5> times_ep2_online; /* 28:44 */ parray<ChallengeTimeT<BE>, 5> times_ep2_online;
/* 3C:58 */ parray<ChallengeTimeT<IsBigEndian>, 9> times_ep1_offline; /* 3C:58 */ parray<ChallengeTimeT<BE>, 9> times_ep1_offline;
/* 60:7C */ uint8_t grave_is_ep2 = 0; /* 60:7C */ uint8_t grave_is_ep2 = 0;
/* 61:7D */ uint8_t grave_stage_num = 0; /* 61:7D */ uint8_t grave_stage_num = 0;
/* 62:7E */ uint8_t grave_floor = 0; /* 62:7E */ uint8_t grave_floor = 0;
/* 63:7F */ uint8_t unknown_g0 = 0; /* 63:7F */ uint8_t unknown_g0 = 0;
/* 64:80 */ U16T grave_deaths = 0; /* 64:80 */ U16T<BE> grave_deaths = 0;
/* 66:82 */ parray<uint8_t, 2> unknown_u4; /* 66:82 */ parray<uint8_t, 2> unknown_u4;
/* 68:84 */ U32T grave_time = 0; // Encoded as in PlayerRecordsChallengeDCPC /* 68:84 */ U32T<BE> grave_time = 0; // Encoded as in PlayerRecordsChallengeDCPC
/* 6C:88 */ U32T grave_defeated_by_enemy_rt_index = 0; /* 6C:88 */ U32T<BE> grave_defeated_by_enemy_rt_index = 0;
/* 70:8C */ F32T grave_x = 0.0f; /* 70:8C */ F32T<BE> grave_x = 0.0f;
/* 74:90 */ F32T grave_y = 0.0f; /* 74:90 */ F32T<BE> grave_y = 0.0f;
/* 78:94 */ F32T grave_z = 0.0f; /* 78:94 */ F32T<BE> grave_z = 0.0f;
/* 7C:98 */ pstring<TextEncoding::ASCII, 0x14> grave_team; /* 7C:98 */ pstring<TextEncoding::ASCII, 0x14> grave_team;
/* 90:AC */ pstring<TextEncoding::ASCII, 0x20> grave_message; /* 90:AC */ pstring<TextEncoding::ASCII, 0x20> grave_message;
/* B0:CC */ parray<uint8_t, 4> unknown_m5; /* B0:CC */ parray<uint8_t, 4> unknown_m5;
/* B4:D0 */ parray<U32T, 3> unknown_t6; /* B4:D0 */ parray<U32T<BE>, 3> unknown_t6;
/* C0:DC */ ChallengeAwardStateT<IsBigEndian> ep1_online_award_state; /* C0:DC */ ChallengeAwardStateT<BE> ep1_online_award_state;
/* C8:E4 */ ChallengeAwardStateT<IsBigEndian> ep2_online_award_state; /* C8:E4 */ ChallengeAwardStateT<BE> ep2_online_award_state;
/* D0:EC */ ChallengeAwardStateT<IsBigEndian> ep1_offline_award_state; /* D0:EC */ ChallengeAwardStateT<BE> ep1_offline_award_state;
/* D8:F4 */ /* D8:F4 */
} __packed__; } __packed__;
/* 0000:001C */ Stats stats; /* 0000:001C */ Stats stats;
@@ -661,8 +650,8 @@ struct PlayerRecordsChallengeBB {
PlayerRecordsChallengeBB(const PlayerRecordsChallengeDC& rec); PlayerRecordsChallengeBB(const PlayerRecordsChallengeDC& rec);
PlayerRecordsChallengeBB(const PlayerRecordsChallengePC& rec); PlayerRecordsChallengeBB(const PlayerRecordsChallengePC& rec);
template <bool IsBigEndian> template <bool BE>
PlayerRecordsChallengeBB(const PlayerRecordsChallengeV3T<IsBigEndian>& rec) PlayerRecordsChallengeBB(const PlayerRecordsChallengeV3T<BE>& rec)
: title_color(rec.stats.title_color.load()), : title_color(rec.stats.title_color.load()),
unknown_u0(rec.stats.unknown_u0), unknown_u0(rec.stats.unknown_u0),
times_ep1_online(rec.stats.times_ep1_online), times_ep1_online(rec.stats.times_ep1_online),
@@ -694,9 +683,9 @@ struct PlayerRecordsChallengeBB {
operator PlayerRecordsChallengeDC() const; operator PlayerRecordsChallengeDC() const;
operator PlayerRecordsChallengePC() const; operator PlayerRecordsChallengePC() const;
template <bool IsBigEndian> template <bool BE>
operator PlayerRecordsChallengeV3T<IsBigEndian>() const { operator PlayerRecordsChallengeV3T<BE>() const {
PlayerRecordsChallengeV3T<IsBigEndian> ret; PlayerRecordsChallengeV3T<BE> ret;
ret.stats.title_color = this->title_color.load(); ret.stats.title_color = this->title_color.load();
ret.stats.unknown_u0 = this->unknown_u0; ret.stats.unknown_u0 = this->unknown_u0;
ret.stats.times_ep1_online = this->times_ep1_online; ret.stats.times_ep1_online = this->times_ep1_online;
@@ -728,20 +717,17 @@ struct PlayerRecordsChallengeBB {
} }
} __packed_ws__(PlayerRecordsChallengeBB, 0x140); } __packed_ws__(PlayerRecordsChallengeBB, 0x140);
template <bool IsBigEndian> template <bool BE>
struct PlayerRecordsBattleT { struct PlayerRecordsBattleT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
// On Episode 3, place_counts[0] is win count and [1] is loss count // On Episode 3, place_counts[0] is win count and [1] is loss count
/* 00 */ parray<U16T, 4> place_counts; /* 00 */ parray<U16T<BE>, 4> place_counts;
/* 08 */ U16T disconnect_count = 0; /* 08 */ U16T<BE> disconnect_count = 0;
/* 0A */ parray<U16T, 3> unknown_a1; /* 0A */ parray<U16T<BE>, 3> unknown_a1;
/* 10 */ parray<U32T, 2> unknown_a2; /* 10 */ parray<U32T<BE>, 2> unknown_a2;
/* 18 */ /* 18 */
operator PlayerRecordsBattleT<!IsBigEndian>() const { operator PlayerRecordsBattleT<!BE>() const {
PlayerRecordsBattleT<!IsBigEndian> ret; PlayerRecordsBattleT<!BE> ret;
for (size_t z = 0; z < this->place_counts.size(); z++) { for (size_t z = 0; z < this->place_counts.size(); z++) {
ret.place_counts[z] = this->place_counts[z].load(); ret.place_counts[z] = this->place_counts[z].load();
} }
@@ -762,7 +748,7 @@ check_struct_size(PlayerRecordsBattleBE, 0x18);
template <typename DestT, typename SrcT = DestT> template <typename DestT, typename SrcT = DestT>
DestT convert_player_disp_data(const SrcT&, uint8_t, uint8_t) { DestT convert_player_disp_data(const SrcT&, uint8_t, uint8_t) {
static_assert(always_false<DestT, SrcT>::v, static_assert(phosg::always_false<DestT, SrcT>::v,
"unspecialized convert_player_disp_data should never be called"); "unspecialized convert_player_disp_data should never be called");
} }
@@ -971,8 +957,8 @@ struct BattleRules {
/* 30 */ /* 30 */
BattleRules() = default; BattleRules() = default;
explicit BattleRules(const JSON& json); explicit BattleRules(const phosg::JSON& json);
JSON json() const; phosg::JSON json() const;
bool operator==(const BattleRules& other) const = default; bool operator==(const BattleRules& other) const = default;
bool operator!=(const BattleRules& other) const = default; bool operator!=(const BattleRules& other) const = default;
@@ -998,20 +984,17 @@ struct SymbolChatFacePart {
uint8_t flags = 0; uint8_t flags = 0;
} __packed_ws__(SymbolChatFacePart, 4); } __packed_ws__(SymbolChatFacePart, 4);
template <bool IsBigEndian> template <bool BE>
struct SymbolChatT { struct SymbolChatT {
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
// Bits: ----------------------DMSSSCCCFF // Bits: ----------------------DMSSSCCCFF
// S = sound, C = face color, F = face shape, D = capture, M = mute sound // S = sound, C = face color, F = face shape, D = capture, M = mute sound
/* 00 */ U32T spec = 0; /* 00 */ U32T<BE> spec = 0;
// Corner objects are specified in reading order ([0] is the top-left one). // Corner objects are specified in reading order ([0] is the top-left one).
// Bits (each entry): ---VHCCCZZZZZZZZ // Bits (each entry): ---VHCCCZZZZZZZZ
// V = reverse vertical, H = reverse horizontal, C = color, Z = object // V = reverse vertical, H = reverse horizontal, C = color, Z = object
// If Z is all 1 bits (0xFF), no corner object is rendered. // If Z is all 1 bits (0xFF), no corner object is rendered.
/* 04 */ parray<U16T, 4> corner_objects; /* 04 */ parray<U16T<BE>, 4> corner_objects;
/* 0C */ parray<SymbolChatFacePart, 12> face_parts; /* 0C */ parray<SymbolChatFacePart, 12> face_parts;
/* 3C */ /* 3C */
@@ -1020,8 +1003,8 @@ struct SymbolChatT {
corner_objects(0x00FF), corner_objects(0x00FF),
face_parts() {} face_parts() {}
operator SymbolChatT<!IsBigEndian>() const { operator SymbolChatT<!BE>() const {
SymbolChatT<!IsBigEndian> ret; SymbolChatT<!BE> ret;
ret.spec = this->spec.load(); ret.spec = this->spec.load();
for (size_t z = 0; z < this->corner_objects.size(); z++) { for (size_t z = 0; z < this->corner_objects.size(); z++) {
ret.corner_objects[z] = this->corner_objects[z].load(); ret.corner_objects[z] = this->corner_objects[z].load();
+59 -60
View File
@@ -95,8 +95,8 @@ static HandlerResult default_handler(shared_ptr<ProxyServer::LinkedSession>, uin
static HandlerResult S_invalid(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t command, uint32_t flag, string&) { static HandlerResult S_invalid(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t command, uint32_t flag, string&) {
ses->log.error("Server sent invalid command"); ses->log.error("Server sent invalid command");
string error_str = is_v4(ses->version()) string error_str = is_v4(ses->version())
? string_printf("Server sent invalid\ncommand: %04hX %08" PRIX32, command, flag) ? phosg::string_printf("Server sent invalid\ncommand: %04hX %08" PRIX32, command, flag)
: string_printf("Server sent invalid\ncommand: %02hX %02" PRIX32, command, flag); : phosg::string_printf("Server sent invalid\ncommand: %02hX %02" PRIX32, command, flag);
ses->send_to_game_server(error_str.c_str()); ses->send_to_game_server(error_str.c_str());
return HandlerResult::Type::SUPPRESS; return HandlerResult::Type::SUPPRESS;
} }
@@ -110,7 +110,7 @@ static HandlerResult C_05(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
static HandlerResult C_1D(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string&) { static HandlerResult C_1D(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string&) {
if (ses->client_ping_start_time) { if (ses->client_ping_start_time) {
uint64_t ping_usecs = now() - ses->client_ping_start_time; uint64_t ping_usecs = phosg::now() - ses->client_ping_start_time;
ses->client_ping_start_time = 0; ses->client_ping_start_time = 0;
double ping_ms = static_cast<double>(ping_usecs) / 1000.0; double ping_ms = static_cast<double>(ping_usecs) / 1000.0;
send_text_message_printf(ses->client_channel, "To proxy: %gms", ping_ms); send_text_message_printf(ses->client_channel, "To proxy: %gms", ping_ms);
@@ -138,7 +138,7 @@ static HandlerResult S_97(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
static HandlerResult C_G_9E(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string&) { static HandlerResult C_G_9E(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string&) {
if (ses->config.check_flag(Client::Flag::PROXY_SUPPRESS_REMOTE_LOGIN) && ses->login) { if (ses->config.check_flag(Client::Flag::PROXY_SUPPRESS_REMOTE_LOGIN) && ses->login) {
le_uint64_t checksum = random_object<uint64_t>() & 0x0000FFFFFFFFFFFF; le_uint64_t checksum = phosg::random_object<uint64_t>() & 0x0000FFFFFFFFFFFF;
ses->server_channel.send(0x96, 0x00, &checksum, sizeof(checksum)); ses->server_channel.send(0x96, 0x00, &checksum, sizeof(checksum));
S_UpdateClientConfig_V3_04 cmd; S_UpdateClientConfig_V3_04 cmd;
@@ -172,7 +172,7 @@ static HandlerResult S_G_9A(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t
cmd.sub_version = ses->effective_sub_version(); cmd.sub_version = ses->effective_sub_version();
cmd.is_extended = (ses->remote_guild_card_number < 0) ? 1 : 0; cmd.is_extended = (ses->remote_guild_card_number < 0) ? 1 : 0;
cmd.language = ses->language(); cmd.language = ses->language();
cmd.serial_number.encode(string_printf("%08" PRIX32 "", ses->login->account->account_id)); cmd.serial_number.encode(phosg::string_printf("%08" PRIX32 "", ses->login->account->account_id));
cmd.access_key.encode(ses->login->gc_license->access_key); cmd.access_key.encode(ses->login->gc_license->access_key);
cmd.serial_number2 = cmd.serial_number; cmd.serial_number2 = cmd.serial_number;
cmd.access_key2 = cmd.access_key; cmd.access_key2 = cmd.access_key;
@@ -259,7 +259,7 @@ static HandlerResult S_V123P_02_17(
} }
if (command == 0x17) { if (command == 0x17) {
C_LoginV1_DC_PC_V3_90 cmd; C_LoginV1_DC_PC_V3_90 cmd;
cmd.serial_number.encode(string_printf("%08" PRIX32 "", ses->login->account->account_id)); cmd.serial_number.encode(phosg::string_printf("%08" PRIX32 "", ses->login->account->account_id));
cmd.access_key.encode(ses->login->dc_license->access_key); cmd.access_key.encode(ses->login->dc_license->access_key);
cmd.access_key.clear_after_bytes(8); cmd.access_key.clear_after_bytes(8);
ses->server_channel.send(0x90, 0x00, &cmd, sizeof(cmd)); ses->server_channel.send(0x90, 0x00, &cmd, sizeof(cmd));
@@ -278,7 +278,7 @@ static HandlerResult S_V123P_02_17(
cmd.sub_version = ses->effective_sub_version(); cmd.sub_version = ses->effective_sub_version();
cmd.is_extended = 0; cmd.is_extended = 0;
cmd.language = ses->language(); cmd.language = ses->language();
cmd.serial_number.encode(string_printf("%08" PRIX32 "", ses->login->account->account_id)); cmd.serial_number.encode(phosg::string_printf("%08" PRIX32 "", ses->login->account->account_id));
cmd.access_key.encode(ses->login->dc_license->access_key); cmd.access_key.encode(ses->login->dc_license->access_key);
cmd.access_key.clear_after_bytes(8); cmd.access_key.clear_after_bytes(8);
cmd.hardware_id.encode(ses->hardware_id); cmd.hardware_id.encode(ses->hardware_id);
@@ -314,7 +314,7 @@ static HandlerResult S_V123P_02_17(
cmd.guild_card_number = ses->remote_guild_card_number; cmd.guild_card_number = ses->remote_guild_card_number;
} }
cmd.sub_version = ses->effective_sub_version(); cmd.sub_version = ses->effective_sub_version();
cmd.serial_number.encode(string_printf("%08" PRIX32 "", ses->login->account->account_id)); cmd.serial_number.encode(phosg::string_printf("%08" PRIX32 "", ses->login->account->account_id));
cmd.access_key.encode(*access_key); cmd.access_key.encode(*access_key);
if (ses->version() != Version::GC_NTE) { if (ses->version() != Version::GC_NTE) {
cmd.access_key.clear_after_bytes(8); cmd.access_key.clear_after_bytes(8);
@@ -340,7 +340,7 @@ static HandlerResult S_V123P_02_17(
cmd.sub_version = ses->effective_sub_version(); cmd.sub_version = ses->effective_sub_version();
cmd.is_extended = 0; cmd.is_extended = 0;
cmd.language = ses->language(); cmd.language = ses->language();
cmd.serial_number.encode(string_printf("%08" PRIX32 "", ses->login->account->account_id)); cmd.serial_number.encode(phosg::string_printf("%08" PRIX32 "", ses->login->account->account_id));
cmd.access_key.encode(*access_key); cmd.access_key.encode(*access_key);
if (ses->version() != Version::GC_NTE) { if (ses->version() != Version::GC_NTE) {
cmd.access_key.clear_after_bytes(8); cmd.access_key.clear_after_bytes(8);
@@ -365,7 +365,7 @@ static HandlerResult S_V123P_02_17(
} }
if (command == 0x17) { if (command == 0x17) {
C_VerifyAccount_V3_DB cmd; C_VerifyAccount_V3_DB cmd;
cmd.serial_number.encode(string_printf("%08" PRIX32 "", ses->login->account->account_id)); cmd.serial_number.encode(phosg::string_printf("%08" PRIX32 "", ses->login->account->account_id));
cmd.access_key.encode(ses->login->gc_license->access_key); cmd.access_key.encode(ses->login->gc_license->access_key);
cmd.sub_version = ses->effective_sub_version(); cmd.sub_version = ses->effective_sub_version();
cmd.serial_number2 = cmd.serial_number; cmd.serial_number2 = cmd.serial_number;
@@ -378,15 +378,15 @@ static HandlerResult S_V123P_02_17(
uint32_t guild_card_number; uint32_t guild_card_number;
if (ses->remote_guild_card_number >= 0) { if (ses->remote_guild_card_number >= 0) {
guild_card_number = ses->remote_guild_card_number; guild_card_number = ses->remote_guild_card_number;
log_info("Using Guild Card number %" PRIu32 " from session", guild_card_number); ses->log.info("Using Guild Card number %" PRIu32 " from session", guild_card_number);
} else { } else {
guild_card_number = random_object<uint32_t>(); guild_card_number = phosg::random_object<uint32_t>();
log_info("Using Guild Card number %" PRIu32 " from random generator", guild_card_number); ses->log.info("Using Guild Card number %" PRIu32 " from random generator", guild_card_number);
} }
uint32_t fake_serial_number = random_object<uint32_t>() & 0x7FFFFFFF; uint32_t fake_serial_number = phosg::random_object<uint32_t>() & 0x7FFFFFFF;
uint64_t fake_access_key = random_object<uint64_t>(); uint64_t fake_access_key = phosg::random_object<uint64_t>();
string fake_access_key_str = string_printf("00000000000%" PRIu64, fake_access_key); string fake_access_key_str = phosg::string_printf("00000000000%" PRIu64, fake_access_key);
if (fake_access_key_str.size() > 12) { if (fake_access_key_str.size() > 12) {
fake_access_key_str = fake_access_key_str.substr(fake_access_key_str.size() - 12); fake_access_key_str = fake_access_key_str.substr(fake_access_key_str.size() - 12);
} }
@@ -399,7 +399,7 @@ static HandlerResult S_V123P_02_17(
cmd.sub_version = ses->effective_sub_version(); cmd.sub_version = ses->effective_sub_version();
cmd.is_extended = 0; cmd.is_extended = 0;
cmd.language = ses->language(); cmd.language = ses->language();
cmd.serial_number.encode(string_printf("%08" PRIX32, fake_serial_number)); cmd.serial_number.encode(phosg::string_printf("%08" PRIX32, fake_serial_number));
cmd.access_key.encode(fake_access_key_str); cmd.access_key.encode(fake_access_key_str);
cmd.serial_number2 = cmd.serial_number; cmd.serial_number2 = cmd.serial_number;
cmd.access_key2 = cmd.access_key; cmd.access_key2 = cmd.access_key;
@@ -436,7 +436,7 @@ static HandlerResult S_V123P_02_17(
cmd.is_extended = (ses->remote_guild_card_number < 0) ? 1 : 0; cmd.is_extended = (ses->remote_guild_card_number < 0) ? 1 : 0;
cmd.language = ses->language(); cmd.language = ses->language();
cmd.serial_number.encode(ses->login->xb_license->gamertag); cmd.serial_number.encode(ses->login->xb_license->gamertag);
cmd.access_key.encode(string_printf("%016" PRIX64, ses->login->xb_license->user_id)); cmd.access_key.encode(phosg::string_printf("%016" PRIX64, ses->login->xb_license->user_id));
cmd.serial_number2 = cmd.serial_number; cmd.serial_number2 = cmd.serial_number;
cmd.access_key2 = cmd.access_key; cmd.access_key2 = cmd.access_key;
if (ses->config.check_flag(Client::Flag::PROXY_BLANK_NAME_ENABLED)) { if (ses->config.check_flag(Client::Flag::PROXY_BLANK_NAME_ENABLED)) {
@@ -519,7 +519,7 @@ static HandlerResult S_B_03(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t
static HandlerResult S_V123_04(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string& data) { static HandlerResult S_V123_04(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string& data) {
// Suppress extremely short commands from the server instead of disconnecting. // Suppress extremely short commands from the server instead of disconnecting.
if (data.size() < offsetof(S_UpdateClientConfig_V3_04, client_config)) { if (data.size() < offsetof(S_UpdateClientConfig_V3_04, client_config)) {
le_uint64_t checksum = random_object<uint64_t>() & 0x0000FFFFFFFFFFFF; le_uint64_t checksum = phosg::random_object<uint64_t>() & 0x0000FFFFFFFFFFFF;
ses->server_channel.send(0x96, 0x00, &checksum, sizeof(checksum)); ses->server_channel.send(0x96, 0x00, &checksum, sizeof(checksum));
return HandlerResult::Type::SUPPRESS; return HandlerResult::Type::SUPPRESS;
} }
@@ -539,7 +539,7 @@ static HandlerResult S_V123_04(shared_ptr<ProxyServer::LinkedSession> ses, uint1
ses->remote_guild_card_number = cmd.guild_card_number; ses->remote_guild_card_number = cmd.guild_card_number;
ses->log.info("Remote guild card number set to %" PRId64, ses->log.info("Remote guild card number set to %" PRId64,
ses->remote_guild_card_number); ses->remote_guild_card_number);
string message = string_printf( string message = phosg::string_printf(
"The remote server\nhas assigned your\nGuild Card number:\n$C6%" PRId64, "The remote server\nhas assigned your\nGuild Card number:\n$C6%" PRId64,
ses->remote_guild_card_number); ses->remote_guild_card_number);
send_ship_info(ses->client_channel, message); send_ship_info(ses->client_channel, message);
@@ -567,7 +567,7 @@ static HandlerResult S_V123_04(shared_ptr<ProxyServer::LinkedSession> ses, uint1
// the first 04 command the client has received. The client responds with a 96 // the first 04 command the client has received. The client responds with a 96
// (checksum) in that case. // (checksum) in that case.
if (!had_guild_card_number) { if (!had_guild_card_number) {
le_uint64_t checksum = random_object<uint64_t>() & 0x0000FFFFFFFFFFFF; le_uint64_t checksum = phosg::random_object<uint64_t>() & 0x0000FFFFFFFFFFFF;
ses->server_channel.send(0x96, 0x00, &checksum, sizeof(checksum)); ses->server_channel.send(0x96, 0x00, &checksum, sizeof(checksum));
} }
@@ -606,7 +606,7 @@ static HandlerResult S_41(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
if ((cmd.searcher_guild_card_number == ses->remote_guild_card_number) && if ((cmd.searcher_guild_card_number == ses->remote_guild_card_number) &&
(cmd.result_guild_card_number == ses->remote_guild_card_number) && (cmd.result_guild_card_number == ses->remote_guild_card_number) &&
ses->server_ping_start_time) { ses->server_ping_start_time) {
uint64_t ping_usecs = now() - ses->server_ping_start_time; uint64_t ping_usecs = phosg::now() - ses->server_ping_start_time;
ses->server_ping_start_time = 0; ses->server_ping_start_time = 0;
double ping_ms = static_cast<double>(ping_usecs) / 1000.0; double ping_ms = static_cast<double>(ping_usecs) / 1000.0;
send_text_message_printf(ses->client_channel, "To server: %gms", ping_ms); send_text_message_printf(ses->client_channel, "To server: %gms", ping_ms);
@@ -677,16 +677,16 @@ static HandlerResult S_B1(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
return HandlerResult::Type::SUPPRESS; return HandlerResult::Type::SUPPRESS;
} }
template <bool IsBigEndian> template <bool BE>
static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t flag, string& data) { static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t flag, string& data) {
const auto& cmd = check_size_t<S_ExecuteCode_B2>(data, 0xFFFF); const auto& cmd = check_size_t<S_ExecuteCode_B2>(data, 0xFFFF);
if (cmd.code_size && ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) { if (cmd.code_size && ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) {
uint64_t filename_timestamp = now(); uint64_t filename_timestamp = phosg::now();
string code = data.substr(sizeof(S_ExecuteCode_B2)); string code = data.substr(sizeof(S_ExecuteCode_B2));
if (ses->config.check_flag(Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL)) { if (ses->config.check_flag(Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL)) {
StringReader r(code); phosg::StringReader r(code);
bool is_big_endian = ::is_big_endian(ses->version()); bool is_big_endian = ::is_big_endian(ses->version());
uint32_t decompressed_size = is_big_endian ? r.get_u32b() : r.get_u32l(); uint32_t decompressed_size = is_big_endian ? r.get_u32b() : r.get_u32l();
uint32_t key = is_big_endian ? r.get_u32b() : r.get_u32l(); uint32_t key = is_big_endian ? r.get_u32b() : r.get_u32l();
@@ -694,7 +694,7 @@ static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
PSOV2Encryption crypt(key); PSOV2Encryption crypt(key);
string decrypted_data; string decrypted_data;
if (is_big_endian) { if (is_big_endian) {
StringWriter w; phosg::StringWriter w;
while (!r.eof()) { while (!r.eof()) {
w.put_u32b(r.get_u32b() ^ crypt.next()); w.put_u32b(r.get_u32b() ^ crypt.next());
} }
@@ -718,14 +718,13 @@ static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
} }
} }
string output_filename = string_printf("code.%" PRId64 ".bin", filename_timestamp); string output_filename = phosg::string_printf("code.%" PRId64 ".bin", filename_timestamp);
save_file(output_filename, data); phosg::save_file(output_filename, data);
ses->log.info("Wrote code from server to file %s", output_filename.c_str()); ses->log.info("Wrote code from server to file %s", output_filename.c_str());
#ifdef HAVE_RESOURCE_FILE #ifdef HAVE_RESOURCE_FILE
using FooterT = S_ExecuteCode_FooterT_B2<IsBigEndian>; using FooterT = S_ExecuteCode_FooterT_B2<BE>;
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
// TODO: Support SH-4 disassembly too // TODO: Support SH-4 disassembly too
bool is_ppc = ::is_ppc(ses->version()); bool is_ppc = ::is_ppc(ses->version());
bool is_x86 = ::is_x86(ses->version()); bool is_x86 = ::is_x86(ses->version());
@@ -738,19 +737,19 @@ static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
size_t footer_offset = code.size() - sizeof(FooterT); size_t footer_offset = code.size() - sizeof(FooterT);
StringReader r(code.data(), code.size()); phosg::StringReader r(code.data(), code.size());
const auto& footer = r.pget<FooterT>(footer_offset); const auto& footer = r.pget<FooterT>(footer_offset);
multimap<uint32_t, string> labels; multimap<uint32_t, string> labels;
r.go(footer.relocations_offset); r.go(footer.relocations_offset);
uint32_t reloc_offset = 0; uint32_t reloc_offset = 0;
for (size_t x = 0; x < footer.num_relocations; x++) { for (size_t x = 0; x < footer.num_relocations; x++) {
reloc_offset += (r.get<U16T>() * 4); reloc_offset += (r.get<U16T<BE>>() * 4);
labels.emplace(reloc_offset, string_printf("reloc%zu", x)); labels.emplace(reloc_offset, phosg::string_printf("reloc%zu", x));
} }
labels.emplace(footer.entrypoint_addr_offset.load(), "entry_ptr"); labels.emplace(footer.entrypoint_addr_offset.load(), "entry_ptr");
labels.emplace(footer_offset, "footer"); labels.emplace(footer_offset, "footer");
labels.emplace(r.pget<U32T>(footer.entrypoint_addr_offset), "start"); labels.emplace(r.pget<U32T<BE>>(footer.entrypoint_addr_offset), "start");
string disassembly; string disassembly;
if (is_ppc) { if (is_ppc) {
@@ -776,13 +775,13 @@ static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
throw logic_error("unsupported architecture"); throw logic_error("unsupported architecture");
} }
output_filename = string_printf("code.%" PRId64 ".txt", filename_timestamp); output_filename = phosg::string_printf("code.%" PRId64 ".txt", filename_timestamp);
{ {
auto f = fopen_unique(output_filename, "wt"); auto f = phosg::fopen_unique(output_filename, "wt");
fprintf(f.get(), "// code_size = 0x%" PRIX32 "\n", cmd.code_size.load()); fprintf(f.get(), "// code_size = 0x%" PRIX32 "\n", cmd.code_size.load());
fprintf(f.get(), "// checksum_addr = 0x%" PRIX32 "\n", cmd.checksum_start.load()); fprintf(f.get(), "// checksum_addr = 0x%" PRIX32 "\n", cmd.checksum_start.load());
fprintf(f.get(), "// checksum_size = 0x%" PRIX32 "\n", cmd.checksum_size.load()); fprintf(f.get(), "// checksum_size = 0x%" PRIX32 "\n", cmd.checksum_size.load());
fwritex(f.get(), disassembly); phosg::fwritex(f.get(), disassembly);
} }
ses->log.info("Wrote disassembly to file %s", output_filename.c_str()); ses->log.info("Wrote disassembly to file %s", output_filename.c_str());
@@ -825,8 +824,8 @@ static HandlerResult C_B3(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
static HandlerResult S_B_E7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string& data) { static HandlerResult S_B_E7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string& data) {
if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) { if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) {
string output_filename = string_printf("player.%" PRId64 ".bin", now()); string output_filename = phosg::string_printf("player.%" PRId64 ".bin", phosg::now());
save_file(output_filename, data); phosg::save_file(output_filename, data);
ses->log.info("Wrote player data to file %s", output_filename.c_str()); ses->log.info("Wrote player data to file %s", output_filename.c_str());
} }
return HandlerResult::Type::FORWARD; return HandlerResult::Type::FORWARD;
@@ -877,7 +876,7 @@ static HandlerResult S_B_22(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t
// hence the hash here instead of a direct string comparison. I'd love to hear // hence the hash here instead of a direct string comparison. I'd love to hear
// the story behind why they put that string there. // the story behind why they put that string there.
if ((data.size() == 0x2C) && if ((data.size() == 0x2C) &&
(fnv1a64(data.data(), data.size()) == 0x8AF8314316A27994)) { (phosg::fnv1a64(data.data(), data.size()) == 0x8AF8314316A27994)) {
ses->log.info("Enabling remote IP CRC patch"); ses->log.info("Enabling remote IP CRC patch");
ses->enable_remote_ip_crc_patch = true; ses->enable_remote_ip_crc_patch = true;
} }
@@ -902,7 +901,7 @@ static HandlerResult S_19_P_14(shared_ptr<ProxyServer::LinkedSession> ses, uint1
} }
if (ses->enable_remote_ip_crc_patch) { if (ses->enable_remote_ip_crc_patch) {
ses->remote_ip_crc = crc32(data.data(), 4); ses->remote_ip_crc = phosg::crc32(data.data(), 4);
} }
// Set the destination netloc appropriately // Set the destination netloc appropriately
@@ -1052,11 +1051,11 @@ static HandlerResult S_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
const auto& header = check_size_t<G_MapSubsubcommand_Ep3_6xB6>(data, 0xFFFF); const auto& header = check_size_t<G_MapSubsubcommand_Ep3_6xB6>(data, 0xFFFF);
if (header.subsubcommand == 0x00000041) { if (header.subsubcommand == 0x00000041) {
const auto& cmd = check_size_t<G_MapData_Ep3_6xB6x41>(data, 0xFFFF); const auto& cmd = check_size_t<G_MapData_Ep3_6xB6x41>(data, 0xFFFF);
string filename = string_printf("map%08" PRIX32 ".%" PRIu64 ".mnmd", string filename = phosg::string_printf("map%08" PRIX32 ".%" PRIu64 ".mnmd",
cmd.map_number.load(), now()); cmd.map_number.load(), phosg::now());
string map_data = prs_decompress( string map_data = prs_decompress(
data.data() + sizeof(cmd), data.size() - sizeof(cmd)); data.data() + sizeof(cmd), data.size() - sizeof(cmd));
save_file(filename, map_data); phosg::save_file(filename, map_data);
if (map_data.size() != sizeof(Episode3::MapDefinition) && map_data.size() != sizeof(Episode3::MapDefinitionTrial)) { if (map_data.size() != sizeof(Episode3::MapDefinition) && map_data.size() != sizeof(Episode3::MapDefinitionTrial)) {
ses->log.warning("Wrote %zu bytes to %s (expected %zu or %zu bytes; the file may be invalid)", ses->log.warning("Wrote %zu bytes to %s (expected %zu or %zu bytes; the file may be invalid)",
map_data.size(), filename.c_str(), sizeof(Episode3::MapDefinitionTrial), sizeof(Episode3::MapDefinition)); map_data.size(), filename.c_str(), sizeof(Episode3::MapDefinitionTrial), sizeof(Episode3::MapDefinition));
@@ -1285,10 +1284,10 @@ static HandlerResult S_44_A6(shared_ptr<ProxyServer::LinkedSession> ses, uint16_
} else { } else {
basename = filename; basename = filename;
} }
output_filename = string_printf("%s.%s.%" PRIu64 "%s", output_filename = phosg::string_printf("%s.%s.%" PRIu64 "%s",
basename.c_str(), basename.c_str(),
is_download ? "download" : "online", is_download ? "download" : "online",
now(), phosg::now(),
extension.c_str()); extension.c_str());
for (size_t x = 0; x < output_filename.size(); x++) { for (size_t x = 0; x < output_filename.size(); x++) {
@@ -1354,16 +1353,16 @@ static HandlerResult S_13_A7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_
if (sf->remaining_bytes == 0) { if (sf->remaining_bytes == 0) {
if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) { if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) {
ses->log.info("Writing file %s => %s", sf->basename.c_str(), sf->output_filename.c_str()); ses->log.info("Writing file %s => %s", sf->basename.c_str(), sf->output_filename.c_str());
string data = join(sf->blocks); string data = phosg::join(sf->blocks);
if (sf->is_download && (ends_with(sf->basename, ".bin") || ends_with(sf->basename, ".dat") || ends_with(sf->basename, ".pvr"))) { if (sf->is_download && (phosg::ends_with(sf->basename, ".bin") || phosg::ends_with(sf->basename, ".dat") || phosg::ends_with(sf->basename, ".pvr"))) {
data = decode_dlq_data(data); data = decode_dlq_data(data);
} }
save_file(sf->output_filename, data); phosg::save_file(sf->output_filename, data);
if (ends_with(sf->basename, ".bin")) { if (phosg::ends_with(sf->basename, ".bin")) {
try { try {
string decompressed = prs_decompress(data); string decompressed = prs_decompress(data);
auto disassembly = disassemble_quest_script(decompressed.data(), decompressed.size(), ses->version(), ses->language(), false); auto disassembly = disassemble_quest_script(decompressed.data(), decompressed.size(), ses->version(), ses->language(), false);
save_file(sf->output_filename + ".txt", disassembly); phosg::save_file(sf->output_filename + ".txt", disassembly);
} catch (const exception& e) { } catch (const exception& e) {
ses->log.warning("Failed to disassemble quest file: %s", e.what()); ses->log.warning("Failed to disassemble quest file: %s", e.what());
} }
@@ -1372,8 +1371,8 @@ static HandlerResult S_13_A7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_
ses->log.info("Download complete for file %s", sf->basename.c_str()); ses->log.info("Download complete for file %s", sf->basename.c_str());
} }
if (!sf->is_download && ends_with(sf->basename, ".dat")) { if (!sf->is_download && phosg::ends_with(sf->basename, ".dat")) {
auto quest_dat_data = make_shared<std::string>(join(sf->blocks)); auto quest_dat_data = make_shared<std::string>(phosg::join(sf->blocks));
try { try {
ses->map = Lobby::load_maps( ses->map = Lobby::load_maps(
ses->version(), ses->version(),
@@ -1419,15 +1418,15 @@ static HandlerResult S_G_B8(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t
return HandlerResult::Type::FORWARD; return HandlerResult::Type::FORWARD;
} }
StringReader r(data); phosg::StringReader r(data);
size_t size = r.get_u32l(); size_t size = r.get_u32l();
if (r.remaining() < size) { if (r.remaining() < size) {
ses->log.warning("Card list data size extends beyond end of command; not saving file"); ses->log.warning("Card list data size extends beyond end of command; not saving file");
return HandlerResult::Type::FORWARD; return HandlerResult::Type::FORWARD;
} }
string output_filename = string_printf("card-definitions.%" PRIu64 ".mnr", now()); string output_filename = phosg::string_printf("card-definitions.%" PRIu64 ".mnr", phosg::now());
save_file(output_filename, r.read(size)); phosg::save_file(output_filename, r.read(size));
ses->log.info("Wrote %zu bytes to %s", size, output_filename.c_str()); ses->log.info("Wrote %zu bytes to %s", size, output_filename.c_str());
} }
@@ -1450,7 +1449,7 @@ static HandlerResult S_G_B9(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t
string decompressed_data = prs_decompress( string decompressed_data = prs_decompress(
data.data() + sizeof(header), data.size() - sizeof(header)); data.data() + sizeof(header), data.size() - sizeof(header));
string output_filename = string_printf("media-update.%" PRIu64, now()); string output_filename = phosg::string_printf("media-update.%" PRIu64, phosg::now());
if (header.type == 1) { if (header.type == 1) {
output_filename += ".gvm"; output_filename += ".gvm";
} else if (header.type == 2 || header.type == 3) { } else if (header.type == 2 || header.type == 3) {
@@ -1458,7 +1457,7 @@ static HandlerResult S_G_B9(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t
} else { } else {
output_filename += ".bin"; output_filename += ".bin";
} }
save_file(output_filename, decompressed_data); phosg::save_file(output_filename, decompressed_data);
ses->log.info("Wrote %zu bytes to %s", ses->log.info("Wrote %zu bytes to %s",
decompressed_data.size(), output_filename.c_str()); decompressed_data.size(), output_filename.c_str());
} catch (const exception& e) { } catch (const exception& e) {
@@ -1862,7 +1861,7 @@ static HandlerResult C_06(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
const auto& cmd = check_size_t<SC_TextHeader_01_06_11_B0_EE>(data, 0xFFFF); const auto& cmd = check_size_t<SC_TextHeader_01_06_11_B0_EE>(data, 0xFFFF);
string text = data.substr(sizeof(cmd)); string text = data.substr(sizeof(cmd));
strip_trailing_zeroes(text); phosg::strip_trailing_zeroes(text);
uint8_t private_flags = 0; uint8_t private_flags = 0;
try { try {
+30 -30
View File
@@ -58,9 +58,9 @@ ProxyServer::ListeningSocket::ListeningSocket(
Version version, Version version,
const struct sockaddr_storage* default_destination) const struct sockaddr_storage* default_destination)
: server(server), : server(server),
log(string_printf("[ProxyServer:T-%hu] ", port), proxy_server_log.min_level), log(phosg::string_printf("[ProxyServer:T-%hu] ", port), proxy_server_log.min_level),
port(port), port(port),
fd(::listen(addr, port, SOMAXCONN)), fd(phosg::listen(addr, port, SOMAXCONN)),
listener(nullptr, evconnlistener_free), listener(nullptr, evconnlistener_free),
version(version) { version(version) {
if (!this->fd.is_open()) { if (!this->fd.is_open()) {
@@ -85,7 +85,7 @@ ProxyServer::ListeningSocket::ListeningSocket(
this->default_destination.ss_family = 0; this->default_destination.ss_family = 0;
} }
this->log.info("Listening on TCP port %hu (%s) on fd %d", this->port, name_for_enum(this->version), static_cast<int>(this->fd)); this->log.info("Listening on TCP port %hu (%s) on fd %d", this->port, phosg::name_for_enum(this->version), static_cast<int>(this->fd));
} }
void ProxyServer::ListeningSocket::dispatch_on_listen_accept( void ProxyServer::ListeningSocket::dispatch_on_listen_accept(
@@ -100,13 +100,13 @@ void ProxyServer::ListeningSocket::dispatch_on_listen_error(
void ProxyServer::ListeningSocket::on_listen_accept(int fd) { void ProxyServer::ListeningSocket::on_listen_accept(int fd) {
struct sockaddr_storage remote_addr; struct sockaddr_storage remote_addr;
get_socket_addresses(fd, nullptr, &remote_addr); phosg::get_socket_addresses(fd, nullptr, &remote_addr);
if (this->server->state->banned_ipv4_ranges->check(remote_addr)) { if (this->server->state->banned_ipv4_ranges->check(remote_addr)) {
close(fd); close(fd);
return; return;
} }
this->log.info("Client connected on fd %d (port %hu, version %s)", fd, this->port, name_for_enum(this->version)); this->log.info("Client connected on fd %d (port %hu, version %s)", fd, this->port, phosg::name_for_enum(this->version));
auto* bev = bufferevent_socket_new(this->server->base.get(), fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); auto* bev = bufferevent_socket_new(this->server->base.get(), fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
this->server->on_client_connect(bev, 0, this->port, this->version, this->server->on_client_connect(bev, 0, this->port, this->version,
(this->default_destination.ss_family == AF_INET) ? &this->default_destination : nullptr); (this->default_destination.ss_family == AF_INET) ? &this->default_destination : nullptr);
@@ -159,7 +159,7 @@ void ProxyServer::on_client_connect(
auto ses = emplace_ret.first->second; auto ses = emplace_ret.first->second;
ses->log.info("Opened linked session"); ses->log.info("Opened linked session");
Channel ch(bev, virtual_network_id, version, 1, nullptr, nullptr, ses.get(), "", TerminalFormat::FG_YELLOW, TerminalFormat::FG_GREEN); Channel ch(bev, virtual_network_id, version, 1, nullptr, nullptr, ses.get(), "", phosg::TerminalFormat::FG_YELLOW, phosg::TerminalFormat::FG_GREEN);
ses->resume(std::move(ch)); ses->resume(std::move(ch));
} else { } else {
@@ -200,8 +200,8 @@ void ProxyServer::on_client_connect(
case Version::GC_EP3_NTE: case Version::GC_EP3_NTE:
case Version::GC_EP3: case Version::GC_EP3:
case Version::XB_V3: { case Version::XB_V3: {
uint32_t server_key = random_object<uint32_t>(); uint32_t server_key = phosg::random_object<uint32_t>();
uint32_t client_key = random_object<uint32_t>(); uint32_t client_key = phosg::random_object<uint32_t>();
auto cmd = prepare_server_init_contents_console(server_key, client_key, 0); auto cmd = prepare_server_init_contents_console(server_key, client_key, 0);
ses->channel.send(0x02, 0x00, &cmd, sizeof(cmd)); ses->channel.send(0x02, 0x00, &cmd, sizeof(cmd));
if (uses_v2_encryption(version)) { if (uses_v2_encryption(version)) {
@@ -216,8 +216,8 @@ void ProxyServer::on_client_connect(
case Version::BB_V4: { case Version::BB_V4: {
parray<uint8_t, 0x30> server_key; parray<uint8_t, 0x30> server_key;
parray<uint8_t, 0x30> client_key; parray<uint8_t, 0x30> client_key;
random_data(server_key.data(), server_key.bytes()); phosg::random_data(server_key.data(), server_key.bytes());
random_data(client_key.data(), client_key.bytes()); phosg::random_data(client_key.data(), client_key.bytes());
auto cmd = prepare_server_init_contents_bb(server_key, client_key, 0); auto cmd = prepare_server_init_contents_bb(server_key, client_key, 0);
ses->channel.send(0x03, 0x00, &cmd, sizeof(cmd)); ses->channel.send(0x03, 0x00, &cmd, sizeof(cmd));
ses->detector_crypt = make_shared<PSOBBMultiKeyDetectorEncryption>( ses->detector_crypt = make_shared<PSOBBMultiKeyDetectorEncryption>(
@@ -248,7 +248,7 @@ ProxyServer::UnlinkedSession::UnlinkedSession(
Version version) Version version)
: server(server), : server(server),
id(id), id(id),
log(string_printf("[ProxyServer:US-%" PRIX64 "] ", this->id), proxy_server_log.min_level), log(phosg::string_printf("[ProxyServer:US-%" PRIX64 "] ", this->id), proxy_server_log.min_level),
channel( channel(
bev, bev,
virtual_network_id, virtual_network_id,
@@ -258,11 +258,11 @@ ProxyServer::UnlinkedSession::UnlinkedSession(
ProxyServer::UnlinkedSession::on_error, ProxyServer::UnlinkedSession::on_error,
this, this,
"", "",
TerminalFormat::FG_YELLOW, phosg::TerminalFormat::FG_YELLOW,
TerminalFormat::FG_GREEN), phosg::TerminalFormat::FG_GREEN),
local_port(local_port) { local_port(local_port) {
string ip_str = server->state->format_address_for_channel_name(this->channel.remote_addr, this->channel.virtual_network_id); string ip_str = server->state->format_address_for_channel_name(this->channel.remote_addr, this->channel.virtual_network_id);
this->channel.name = string_printf("US-%" PRIX64 " @ %s", this->id, ip_str.c_str()); this->channel.name = phosg::string_printf("US-%" PRIX64 " @ %s", this->id, ip_str.c_str());
memset(&this->next_destination, 0, sizeof(this->next_destination)); memset(&this->next_destination, 0, sizeof(this->next_destination));
} }
@@ -506,7 +506,7 @@ ProxyServer::LinkedSession::LinkedSession(
Version version) Version version)
: server(server), : server(server),
id(id), id(id),
log(string_printf("[ProxyServer:LS-%" PRIX64 "] ", this->id), proxy_server_log.min_level), log(phosg::string_printf("[ProxyServer:LS-%" PRIX64 "] ", this->id), proxy_server_log.min_level),
timeout_event(event_new(server->base.get(), -1, EV_TIMEOUT, &LinkedSession::dispatch_on_timeout, this), event_free), timeout_event(event_new(server->base.get(), -1, EV_TIMEOUT, &LinkedSession::dispatch_on_timeout, this), event_free),
login(nullptr), login(nullptr),
client_channel( client_channel(
@@ -515,18 +515,18 @@ ProxyServer::LinkedSession::LinkedSession(
nullptr, nullptr,
nullptr, nullptr,
this, this,
string_printf("LS-%" PRIX64 "-C", this->id), phosg::string_printf("LS-%" PRIX64 "-C", this->id),
TerminalFormat::FG_YELLOW, phosg::TerminalFormat::FG_YELLOW,
TerminalFormat::FG_GREEN), phosg::TerminalFormat::FG_GREEN),
server_channel( server_channel(
version, version,
1, 1,
nullptr, nullptr,
nullptr, nullptr,
this, this,
string_printf("LS-%" PRIX64 "-S", this->id), phosg::string_printf("LS-%" PRIX64 "-S", this->id),
TerminalFormat::FG_YELLOW, phosg::TerminalFormat::FG_YELLOW,
TerminalFormat::FG_RED), phosg::TerminalFormat::FG_RED),
local_port(local_port), local_port(local_port),
disconnect_action(DisconnectAction::LONG_TIMEOUT), disconnect_action(DisconnectAction::LONG_TIMEOUT),
remote_ip_crc(0), remote_ip_crc(0),
@@ -676,14 +676,14 @@ void ProxyServer::LinkedSession::connect() {
throw runtime_error("destination is not AF_INET"); throw runtime_error("destination is not AF_INET");
} }
string netloc_str = render_sockaddr_storage(this->next_destination); string netloc_str = phosg::render_sockaddr_storage(this->next_destination);
this->log.info("Connecting to %s", netloc_str.c_str()); this->log.info("Connecting to %s", netloc_str.c_str());
this->server_channel.set_bufferevent( this->server_channel.set_bufferevent(
bufferevent_socket_new(this->require_server()->base.get(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS), 0); bufferevent_socket_new(this->require_server()->base.get(), -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS), 0);
if (bufferevent_socket_connect(this->server_channel.bev.get(), if (bufferevent_socket_connect(this->server_channel.bev.get(),
reinterpret_cast<const sockaddr*>(dest_sin), sizeof(*dest_sin)) != 0) { reinterpret_cast<const sockaddr*>(dest_sin), sizeof(*dest_sin)) != 0) {
throw runtime_error(string_printf("failed to connect (%d)", EVUTIL_SOCKET_ERROR())); throw runtime_error(phosg::string_printf("failed to connect (%d)", EVUTIL_SOCKET_ERROR()));
} }
this->server_channel.on_command_received = ProxyServer::LinkedSession::on_input; this->server_channel.on_command_received = ProxyServer::LinkedSession::on_input;
@@ -701,8 +701,8 @@ void ProxyServer::LinkedSession::update_channel_names() {
auto client_ip_str = s->format_address_for_channel_name( auto client_ip_str = s->format_address_for_channel_name(
this->client_channel.remote_addr, this->client_channel.virtual_network_id); this->client_channel.remote_addr, this->client_channel.virtual_network_id);
auto server_ip_str = s->format_address_for_channel_name(this->server_channel.remote_addr, 0); auto server_ip_str = s->format_address_for_channel_name(this->server_channel.remote_addr, 0);
this->client_channel.name = string_printf("LS-%08" PRIX64 "-C @ %s", this->id, client_ip_str.c_str()); this->client_channel.name = phosg::string_printf("LS-%08" PRIX64 "-C @ %s", this->id, client_ip_str.c_str());
this->server_channel.name = string_printf("LS-%08" PRIX64 "-S @ %s", this->id, server_ip_str.c_str()); this->server_channel.name = phosg::string_printf("LS-%08" PRIX64 "-S @ %s", this->id, server_ip_str.c_str());
} }
ProxyServer::LinkedSession::SavingFile::SavingFile( ProxyServer::LinkedSession::SavingFile::SavingFile(
@@ -730,7 +730,7 @@ void ProxyServer::LinkedSession::on_error(Channel& ch, short events) {
if (events & BEV_EVENT_CONNECTED) { if (events & BEV_EVENT_CONNECTED) {
ses->log.info("%s channel connected", is_server_stream ? "Server" : "Client"); ses->log.info("%s channel connected", is_server_stream ? "Server" : "Client");
if (is_server_stream) { if (is_server_stream) {
get_socket_addresses(bufferevent_getfd(ch.bev.get()), &ch.local_addr, &ch.remote_addr); phosg::get_socket_addresses(bufferevent_getfd(ch.bev.get()), &ch.local_addr, &ch.remote_addr);
ses->update_channel_names(); ses->update_channel_names();
} }
@@ -853,11 +853,11 @@ void ProxyServer::LinkedSession::send_to_game_server(const char* error_message)
auto s = this->require_server_state(); auto s = this->require_server_state();
if (this->is_in_game) { if (this->is_in_game) {
send_ship_info(this->client_channel, string_printf("You cannot return\nto $C6%s$C7\nwhile in a game.\n\n%s", s->name.c_str(), error_message ? error_message : "")); send_ship_info(this->client_channel, phosg::string_printf("You cannot return\nto $C6%s$C7\nwhile in a game.\n\n%s", s->name.c_str(), error_message ? error_message : ""));
this->disconnect(); this->disconnect();
} else { } else {
send_ship_info(this->client_channel, string_printf("You\'ve returned to\n$C6%s$C7\n\n%s", s->name.c_str(), error_message ? error_message : "")); send_ship_info(this->client_channel, phosg::string_printf("You\'ve returned to\n$C6%s$C7\n\n%s", s->name.c_str(), error_message ? error_message : ""));
// Restore newserv_client_config, so the login server gets the client flags // Restore newserv_client_config, so the login server gets the client flags
if (is_v3(this->version())) { if (is_v3(this->version())) {
@@ -915,7 +915,7 @@ void ProxyServer::LinkedSession::disconnect() {
// Set a timeout to delete the session entirely (in case the client doesn't // Set a timeout to delete the session entirely (in case the client doesn't
// reconnect) // reconnect)
struct timeval tv = usecs_to_timeval(this->timeout_for_disconnect_action(this->disconnect_action)); struct timeval tv = phosg::usecs_to_timeval(this->timeout_for_disconnect_action(this->disconnect_action));
event_add(this->timeout_event.get(), &tv); event_add(this->timeout_event.get(), &tv);
} }
@@ -998,7 +998,7 @@ void ProxyServer::delete_session(uint64_t id) {
this->unlinked_sessions_to_destroy.emplace(std::move(it->second)); this->unlinked_sessions_to_destroy.emplace(std::move(it->second));
this->id_to_unlinked_session.erase(it); this->id_to_unlinked_session.erase(it);
auto tv = usecs_to_timeval(0); auto tv = phosg::usecs_to_timeval(0);
event_add(this->destroy_sessions_ev.get(), &tv); event_add(this->destroy_sessions_ev.get(), &tv);
} }
} }
+4 -4
View File
@@ -33,7 +33,7 @@ public:
struct LinkedSession : std::enable_shared_from_this<LinkedSession> { struct LinkedSession : std::enable_shared_from_this<LinkedSession> {
std::weak_ptr<ProxyServer> server; std::weak_ptr<ProxyServer> server;
uint64_t id; uint64_t id;
PrefixedLogger log; phosg::PrefixedLogger log;
std::unique_ptr<struct event, void (*)(struct event*)> timeout_event; std::unique_ptr<struct event, void (*)(struct event*)> timeout_event;
@@ -221,9 +221,9 @@ private:
struct ListeningSocket { struct ListeningSocket {
ProxyServer* server; ProxyServer* server;
PrefixedLogger log; phosg::PrefixedLogger log;
uint16_t port; uint16_t port;
scoped_fd fd; phosg::scoped_fd fd;
std::unique_ptr<struct evconnlistener, void (*)(struct evconnlistener*)> listener; std::unique_ptr<struct evconnlistener, void (*)(struct evconnlistener*)> listener;
Version version; Version version;
struct sockaddr_storage default_destination; struct sockaddr_storage default_destination;
@@ -246,7 +246,7 @@ private:
std::weak_ptr<ProxyServer> server; std::weak_ptr<ProxyServer> server;
uint64_t id; uint64_t id;
PrefixedLogger log; phosg::PrefixedLogger log;
Channel channel; Channel channel;
uint16_t local_port; uint16_t local_port;
struct sockaddr_storage next_destination; struct sockaddr_storage next_destination;
+72 -74
View File
@@ -21,7 +21,7 @@
using namespace std; using namespace std;
QuestCategoryIndex::Category::Category(uint32_t category_id, const JSON& json) QuestCategoryIndex::Category::Category(uint32_t category_id, const phosg::JSON& json)
: category_id(category_id) { : category_id(category_id) {
this->enabled_flags = json.get_int(0); this->enabled_flags = json.get_int(0);
this->directory_name = json.get_string(1); this->directory_name = json.get_string(1);
@@ -29,7 +29,7 @@ QuestCategoryIndex::Category::Category(uint32_t category_id, const JSON& json)
this->description = json.get_string(3); this->description = json.get_string(3);
} }
QuestCategoryIndex::QuestCategoryIndex(const JSON& json) { QuestCategoryIndex::QuestCategoryIndex(const phosg::JSON& json) {
uint32_t next_category_id = 1; uint32_t next_category_id = 1;
for (const auto& it : json.as_list()) { for (const auto& it : json.as_list()) {
this->categories.emplace_back(make_shared<Category>(next_category_id++, *it)); this->categories.emplace_back(make_shared<Category>(next_category_id++, *it));
@@ -42,15 +42,13 @@ shared_ptr<const QuestCategoryIndex::Category> QuestCategoryIndex::at(uint32_t c
// GCI decoding logic // GCI decoding logic
template <bool IsBigEndian> template <bool BE>
struct PSOMemCardDLQFileEncryptedHeaderT { struct PSOMemCardDLQFileEncryptedHeaderT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; U32T<BE> round2_seed;
U32T round2_seed;
// To compute checksum, set checksum to zero, then compute the CRC32 of the // To compute checksum, set checksum to zero, then compute the CRC32 of the
// entire data section, including this header struct (but not the unencrypted // entire data section, including this header struct (but not the unencrypted
// header struct). // header struct).
U32T checksum; U32T<BE> checksum;
le_uint32_t decompressed_size; le_uint32_t decompressed_size;
le_uint32_t round3_seed; le_uint32_t round3_seed;
// Data follows here. // Data follows here.
@@ -60,10 +58,10 @@ using PSOGCIDLQFileEncryptedHeader = PSOMemCardDLQFileEncryptedHeaderT<true>;
check_struct_size(PSOVMSDLQFileEncryptedHeader, 0x10); check_struct_size(PSOVMSDLQFileEncryptedHeader, 0x10);
check_struct_size(PSOGCIDLQFileEncryptedHeader, 0x10); check_struct_size(PSOGCIDLQFileEncryptedHeader, 0x10);
template <bool IsBigEndian> template <bool BE>
string decrypt_download_quest_data_section( string decrypt_download_quest_data_section(
const void* data_section, size_t size, uint32_t seed, bool skip_checksum = false, bool is_ep3_trial = false) { const void* data_section, size_t size, uint32_t seed, bool skip_checksum = false, bool is_ep3_trial = false) {
string decrypted = decrypt_data_section<IsBigEndian>(data_section, size, seed); string decrypted = decrypt_data_section<BE>(data_section, size, seed);
size_t orig_size = decrypted.size(); size_t orig_size = decrypted.size();
decrypted.resize((decrypted.size() + 3) & (~3)); decrypted.resize((decrypted.size() + 3) & (~3));
@@ -72,14 +70,14 @@ string decrypt_download_quest_data_section(
// not at the beginning. Presumably they did this because the system, // not at the beginning. Presumably they did this because the system,
// character, and Guild Card files are a constant size, but download quest // character, and Guild Card files are a constant size, but download quest
// files can vary in size. // files can vary in size.
using HeaderT = PSOMemCardDLQFileEncryptedHeaderT<IsBigEndian>; using HeaderT = PSOMemCardDLQFileEncryptedHeaderT<BE>;
auto* header = reinterpret_cast<HeaderT*>(decrypted.data()); auto* header = reinterpret_cast<HeaderT*>(decrypted.data());
PSOV2Encryption round2_crypt(header->round2_seed); PSOV2Encryption round2_crypt(header->round2_seed);
round2_crypt.encrypt_t<IsBigEndian>( round2_crypt.encrypt_t<BE>(
decrypted.data() + 4, (decrypted.size() - 4)); decrypted.data() + 4, (decrypted.size() - 4));
if (is_ep3_trial) { if (is_ep3_trial) {
StringReader r(decrypted); phosg::StringReader r(decrypted);
r.skip(16); r.skip(16);
if (r.readx(15) != "SONICTEAM,SEGA.") { if (r.readx(15) != "SONICTEAM,SEGA.") {
throw runtime_error("Episode 3 GCI file is not a quest"); throw runtime_error("Episode 3 GCI file is not a quest");
@@ -93,7 +91,7 @@ string decrypt_download_quest_data_section(
size_t decompressed_size = prs_decompress_size( size_t decompressed_size = prs_decompress_size(
r.getv(r.remaining(), false), r.remaining(), sizeof(Episode3::MapDefinitionTrial), true); r.getv(r.remaining(), false), r.remaining(), sizeof(Episode3::MapDefinitionTrial), true);
if (decompressed_size < sizeof(Episode3::MapDefinitionTrial)) { if (decompressed_size < sizeof(Episode3::MapDefinitionTrial)) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"decompressed size (%zu) does not match expected size (%zu)", "decompressed size (%zu) does not match expected size (%zu)",
decompressed_size, sizeof(Episode3::MapDefinitionTrial))); decompressed_size, sizeof(Episode3::MapDefinitionTrial)));
} }
@@ -101,17 +99,17 @@ string decrypt_download_quest_data_section(
} else { } else {
if (header->decompressed_size & 0xFFF00000) { if (header->decompressed_size & 0xFFF00000) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"decompressed_size too large (%08" PRIX32 ")", header->decompressed_size.load())); "decompressed_size too large (%08" PRIX32 ")", header->decompressed_size.load()));
} }
if (!skip_checksum) { if (!skip_checksum) {
uint32_t expected_crc = header->checksum; uint32_t expected_crc = header->checksum;
header->checksum = 0; header->checksum = 0;
uint32_t actual_crc = crc32(decrypted.data(), orig_size); uint32_t actual_crc = phosg::crc32(decrypted.data(), orig_size);
header->checksum = expected_crc; header->checksum = expected_crc;
if (expected_crc != actual_crc && expected_crc != bswap32(actual_crc)) { if (expected_crc != actual_crc && expected_crc != phosg::bswap32(actual_crc)) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"incorrect decrypted data section checksum: expected %08" PRIX32 "; received %08" PRIX32, "incorrect decrypted data section checksum: expected %08" PRIX32 "; received %08" PRIX32,
expected_crc, actual_crc)); expected_crc, actual_crc));
} }
@@ -132,7 +130,7 @@ string decrypt_download_quest_data_section(
size_t expected_decompressed_size = header->decompressed_size.load(); size_t expected_decompressed_size = header->decompressed_size.load();
if ((decompressed_size != expected_decompressed_size) && if ((decompressed_size != expected_decompressed_size) &&
(decompressed_size != expected_decompressed_size - 8)) { (decompressed_size != expected_decompressed_size - 8)) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"decompressed size (%zu) does not match expected size (%zu)", "decompressed size (%zu) does not match expected size (%zu)",
decompressed_size, expected_decompressed_size)); decompressed_size, expected_decompressed_size));
} }
@@ -142,7 +140,7 @@ string decrypt_download_quest_data_section(
} }
string decrypt_vms_v1_data_section(const void* data_section, size_t size) { string decrypt_vms_v1_data_section(const void* data_section, size_t size) {
StringReader r(data_section, size); phosg::StringReader r(data_section, size);
uint32_t expected_decompressed_size = r.get_u32l(); uint32_t expected_decompressed_size = r.get_u32l();
uint32_t seed = r.get_u32l(); uint32_t seed = r.get_u32l();
@@ -155,7 +153,7 @@ string decrypt_vms_v1_data_section(const void* data_section, size_t size) {
size_t actual_decompressed_size = prs_decompress_size(data); size_t actual_decompressed_size = prs_decompress_size(data);
if (actual_decompressed_size != expected_decompressed_size) { if (actual_decompressed_size != expected_decompressed_size) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"decompressed size (%zu) does not match size in header (%" PRId32 ")", "decompressed size (%zu) does not match size in header (%" PRId32 ")",
actual_decompressed_size, expected_decompressed_size)); actual_decompressed_size, expected_decompressed_size));
} }
@@ -163,14 +161,14 @@ string decrypt_vms_v1_data_section(const void* data_section, size_t size) {
return data; return data;
} }
template <bool IsBigEndian> template <bool BE>
string find_seed_and_decrypt_download_quest_data_section( string find_seed_and_decrypt_download_quest_data_section(
const void* data_section, size_t size, bool skip_checksum, bool is_ep3_trial, size_t num_threads) { const void* data_section, size_t size, bool skip_checksum, bool is_ep3_trial, size_t num_threads) {
mutex result_lock; mutex result_lock;
string result; string result;
uint64_t result_seed = parallel_range<uint64_t>([&](uint64_t seed, size_t) { uint64_t result_seed = phosg::parallel_range<uint64_t>([&](uint64_t seed, size_t) {
try { try {
string ret = decrypt_download_quest_data_section<IsBigEndian>( string ret = decrypt_download_quest_data_section<BE>(
data_section, size, seed, skip_checksum, is_ep3_trial); data_section, size, seed, skip_checksum, is_ep3_trial);
lock_guard<mutex> g(result_lock); lock_guard<mutex> g(result_lock);
result = std::move(ret); result = std::move(ret);
@@ -242,7 +240,7 @@ VersionedQuest::VersionedQuest(
auto* header = reinterpret_cast<const PSOQuestHeaderDCNTE*>(bin_decompressed.data()); auto* header = reinterpret_cast<const PSOQuestHeaderDCNTE*>(bin_decompressed.data());
this->episode = Episode::EP1; this->episode = Episode::EP1;
if (this->quest_number == 0xFFFFFFFF) { if (this->quest_number == 0xFFFFFFFF) {
this->quest_number = fnv1a32(header, sizeof(header)) & 0xFFFF; this->quest_number = phosg::fnv1a32(header, sizeof(header)) & 0xFFFF;
} }
this->name = header->name.decode(this->language); this->name = header->name.decode(this->language);
break; break;
@@ -343,9 +341,9 @@ VersionedQuest::VersionedQuest(
string VersionedQuest::bin_filename() const { string VersionedQuest::bin_filename() const {
if (this->episode == Episode::EP3) { if (this->episode == Episode::EP3) {
return string_printf("m%06" PRIu32 "p_e.bin", this->quest_number); return phosg::string_printf("m%06" PRIu32 "p_e.bin", this->quest_number);
} else { } else {
return string_printf("quest%" PRIu32 ".bin", this->quest_number); return phosg::string_printf("quest%" PRIu32 ".bin", this->quest_number);
} }
} }
@@ -353,7 +351,7 @@ string VersionedQuest::dat_filename() const {
if (this->episode == Episode::EP3) { if (this->episode == Episode::EP3) {
throw logic_error("Episode 3 quests do not have .dat files"); throw logic_error("Episode 3 quests do not have .dat files");
} else { } else {
return string_printf("quest%" PRIu32 ".dat", this->quest_number); return phosg::string_printf("quest%" PRIu32 ".dat", this->quest_number);
} }
} }
@@ -361,7 +359,7 @@ string VersionedQuest::pvr_filename() const {
if (this->episode == Episode::EP3) { if (this->episode == Episode::EP3) {
throw logic_error("Episode 3 quests do not have .pvr files"); throw logic_error("Episode 3 quests do not have .pvr files");
} else { } else {
return string_printf("quest%" PRIu32 ".pvr", this->quest_number); return phosg::string_printf("quest%" PRIu32 ".pvr", this->quest_number);
} }
} }
@@ -369,18 +367,18 @@ string VersionedQuest::xb_filename() const {
if (this->episode == Episode::EP3) { if (this->episode == Episode::EP3) {
throw logic_error("Episode 3 quests do not have Xbox filenames"); throw logic_error("Episode 3 quests do not have Xbox filenames");
} else { } else {
return string_printf("quest%" PRIu32 "_%c.dat", this->quest_number, tolower(char_for_language_code(this->language))); return phosg::string_printf("quest%" PRIu32 "_%c.dat", this->quest_number, tolower(char_for_language_code(this->language)));
} }
} }
string VersionedQuest::encode_qst() const { string VersionedQuest::encode_qst() const {
unordered_map<string, shared_ptr<const string>> files; unordered_map<string, shared_ptr<const string>> files;
files.emplace(string_printf("quest%" PRIu32 ".bin", this->quest_number), this->bin_contents); files.emplace(phosg::string_printf("quest%" PRIu32 ".bin", this->quest_number), this->bin_contents);
files.emplace(string_printf("quest%" PRIu32 ".dat", this->quest_number), this->dat_contents); files.emplace(phosg::string_printf("quest%" PRIu32 ".dat", this->quest_number), this->dat_contents);
if (this->pvr_contents) { if (this->pvr_contents) {
files.emplace(string_printf("quest%" PRIu32 ".pvr", this->quest_number), this->pvr_contents); files.emplace(phosg::string_printf("quest%" PRIu32 ".pvr", this->quest_number), this->pvr_contents);
} }
string xb_filename = string_printf("quest%" PRIu32 "_%c.dat", quest_number, tolower(char_for_language_code(language))); string xb_filename = phosg::string_printf("quest%" PRIu32 "_%c.dat", quest_number, tolower(char_for_language_code(language)));
return encode_qst_file(files, this->name, this->quest_number, xb_filename, this->version, this->is_dlq_encoded); return encode_qst_file(files, this->name, this->quest_number, xb_filename, this->version, this->is_dlq_encoded);
} }
@@ -525,11 +523,11 @@ QuestIndex::QuestIndex(
}; };
string cat_path = directory + "/" + cat->directory_name; string cat_path = directory + "/" + cat->directory_name;
if (!isdir(cat_path)) { if (!phosg::isdir(cat_path)) {
static_game_data_log.warning("Quest category directory %s is missing; skipping it", cat_path.c_str()); static_game_data_log.warning("Quest category directory %s is missing; skipping it", cat_path.c_str());
continue; continue;
} }
for (string filename : list_directory_sorted(cat_path)) { for (string filename : phosg::list_directory_sorted(cat_path)) {
if (filename == ".DS_Store") { if (filename == ".DS_Store") {
continue; continue;
} }
@@ -538,34 +536,34 @@ QuestIndex::QuestIndex(
try { try {
string orig_filename = filename; string orig_filename = filename;
string file_data; string file_data;
if (ends_with(filename, ".gci")) { if (phosg::ends_with(filename, ".gci")) {
file_data = decode_gci_data(load_file(file_path)); file_data = decode_gci_data(phosg::load_file(file_path));
filename.resize(filename.size() - 4); filename.resize(filename.size() - 4);
} else if (ends_with(filename, ".vms")) { } else if (phosg::ends_with(filename, ".vms")) {
file_data = decode_vms_data(load_file(file_path)); file_data = decode_vms_data(phosg::load_file(file_path));
filename.resize(filename.size() - 4); filename.resize(filename.size() - 4);
} else if (ends_with(filename, ".dlq")) { } else if (phosg::ends_with(filename, ".dlq")) {
file_data = decode_dlq_data(load_file(file_path)); file_data = decode_dlq_data(phosg::load_file(file_path));
filename.resize(filename.size() - 4); filename.resize(filename.size() - 4);
} else if (ends_with(filename, ".txt")) { } else if (phosg::ends_with(filename, ".txt")) {
string include_dir = dirname(file_path); string include_dir = phosg::dirname(file_path);
file_data = assemble_quest_script(load_file(file_path), include_dir); file_data = assemble_quest_script(phosg::load_file(file_path), include_dir);
filename.resize(filename.size() - 4); filename.resize(filename.size() - 4);
if (ends_with(filename, ".bin")) { if (phosg::ends_with(filename, ".bin")) {
filename.push_back('d'); filename.push_back('d');
} }
} else { } else {
file_data = load_file(file_path); file_data = phosg::load_file(file_path);
} }
size_t dot_pos = filename.rfind('.'); size_t dot_pos = filename.rfind('.');
string file_basename; string file_basename;
string extension; string extension;
if (dot_pos != string::npos) { if (dot_pos != string::npos) {
file_basename = tolower(filename.substr(0, dot_pos)); file_basename = phosg::tolower(filename.substr(0, dot_pos));
extension = tolower(filename.substr(dot_pos + 1)); extension = phosg::tolower(filename.substr(dot_pos + 1));
} else { } else {
file_basename = tolower(filename); file_basename = phosg::tolower(filename);
} }
if (extension == "json") { if (extension == "json") {
@@ -583,11 +581,11 @@ QuestIndex::QuestIndex(
} else if (extension == "qst") { } else if (extension == "qst") {
auto files = decode_qst_data(file_data); auto files = decode_qst_data(file_data);
for (auto& it : files) { for (auto& it : files) {
if (ends_with(it.first, ".bin")) { if (phosg::ends_with(it.first, ".bin")) {
add_file(bin_files, file_basename, orig_filename, std::move(it.second), true); add_file(bin_files, file_basename, orig_filename, std::move(it.second), true);
} else if (ends_with(it.first, ".dat")) { } else if (phosg::ends_with(it.first, ".dat")) {
add_file(dat_files, file_basename, orig_filename, std::move(it.second), true); add_file(dat_files, file_basename, orig_filename, std::move(it.second), true);
} else if (ends_with(it.first, ".pvr")) { } else if (phosg::ends_with(it.first, ".pvr")) {
add_file(pvr_files, file_basename, orig_filename, std::move(it.second), true); add_file(pvr_files, file_basename, orig_filename, std::move(it.second), true);
} else { } else {
throw runtime_error("qst file contains unsupported file type: " + it.first); throw runtime_error("qst file contains unsupported file type: " + it.first);
@@ -619,7 +617,7 @@ QuestIndex::QuestIndex(
// parse the remaining fields. // parse the remaining fields.
string quest_number_token, version_token, language_token; string quest_number_token, version_token, language_token;
{ {
vector<string> filename_tokens = split(basename, '-'); vector<string> filename_tokens = phosg::split(basename, '-');
if (filename_tokens.size() != 3) { if (filename_tokens.size() != 3) {
throw invalid_argument("incorrect filename format"); throw invalid_argument("incorrect filename format");
} }
@@ -686,7 +684,7 @@ QuestIndex::QuestIndex(
} }
} }
// Load the quest's metadata JSON file, if it exists // Load the quest's metadata phosg::JSON file, if it exists
const FileData* json_filedata = nullptr; const FileData* json_filedata = nullptr;
shared_ptr<BattleRules> battle_rules; shared_ptr<BattleRules> battle_rules;
ssize_t challenge_template_index = -1; ssize_t challenge_template_index = -1;
@@ -709,7 +707,7 @@ QuestIndex::QuestIndex(
} }
} }
if (json_filedata) { if (json_filedata) {
auto metadata_json = JSON::parse(*json_filedata->data); auto metadata_json = phosg::JSON::parse(*json_filedata->data);
try { try {
battle_rules = make_shared<BattleRules>(metadata_json.at("BattleRules")); battle_rules = make_shared<BattleRules>(metadata_json.at("BattleRules"));
} catch (const out_of_range&) { } catch (const out_of_range&) {
@@ -764,20 +762,20 @@ QuestIndex::QuestIndex(
auto category_name = this->category_index->at(vq->category_id)->name; auto category_name = this->category_index->at(vq->category_id)->name;
string filenames_str = bin_filedata->filename; string filenames_str = bin_filedata->filename;
if (dat_filedata) { if (dat_filedata) {
filenames_str += string_printf("/%s", dat_filedata->filename.c_str()); filenames_str += phosg::string_printf("/%s", dat_filedata->filename.c_str());
} }
if (pvr_filedata) { if (pvr_filedata) {
filenames_str += string_printf("/%s", pvr_filedata->filename.c_str()); filenames_str += phosg::string_printf("/%s", pvr_filedata->filename.c_str());
} }
if (json_filedata) { if (json_filedata) {
filenames_str += string_printf("/%s", json_filedata->filename.c_str()); filenames_str += phosg::string_printf("/%s", json_filedata->filename.c_str());
} }
auto q_it = this->quests_by_number.find(vq->quest_number); auto q_it = this->quests_by_number.find(vq->quest_number);
if (q_it != this->quests_by_number.end()) { if (q_it != this->quests_by_number.end()) {
q_it->second->add_version(vq); q_it->second->add_version(vq);
static_game_data_log.info("(%s) Added %s %c version of quest %" PRIu32 " (%s)", static_game_data_log.info("(%s) Added %s %c version of quest %" PRIu32 " (%s)",
filenames_str.c_str(), filenames_str.c_str(),
name_for_enum(vq->version), phosg::name_for_enum(vq->version),
char_for_language_code(vq->language), char_for_language_code(vq->language),
vq->quest_number, vq->quest_number,
vq->name.c_str()); vq->name.c_str());
@@ -788,7 +786,7 @@ QuestIndex::QuestIndex(
this->quests_by_category_id_and_number[q->category_id].emplace(vq->quest_number, q); this->quests_by_category_id_and_number[q->category_id].emplace(vq->quest_number, q);
static_game_data_log.info("(%s) Created %s %c quest %" PRIu32 " (%s) (%s, %s (%" PRIu32 "), %s)", static_game_data_log.info("(%s) Created %s %c quest %" PRIu32 " (%s) (%s, %s (%" PRIu32 "), %s)",
filenames_str.c_str(), filenames_str.c_str(),
name_for_enum(vq->version), phosg::name_for_enum(vq->version),
char_for_language_code(vq->language), char_for_language_code(vq->language),
vq->quest_number, vq->quest_number,
vq->name.c_str(), vq->name.c_str(),
@@ -869,7 +867,7 @@ string encode_download_quest_data(const string& compressed_data, size_t decompre
// header (PSODownloadQuestHeader) is prepended to the encrypted data. // header (PSODownloadQuestHeader) is prepended to the encrypted data.
if (encryption_seed == 0) { if (encryption_seed == 0) {
encryption_seed = random_object<uint32_t>(); encryption_seed = phosg::random_object<uint32_t>();
} }
if (decompressed_size == 0) { if (decompressed_size == 0) {
decompressed_size = prs_decompress_size(compressed_data); decompressed_size = prs_decompress_size(compressed_data);
@@ -969,7 +967,7 @@ string decode_gci_data(
ssize_t find_seed_num_threads, ssize_t find_seed_num_threads,
int64_t known_seed, int64_t known_seed,
bool skip_checksum) { bool skip_checksum) {
StringReader r(data); phosg::StringReader r(data);
const auto& header = r.get<PSOGCIFileHeader>(); const auto& header = r.get<PSOGCIFileHeader>();
header.check(); header.check();
@@ -1005,7 +1003,7 @@ string decode_gci_data(
size_t expected_decompressed_bytes = dlq_header.decompressed_size - 8; size_t expected_decompressed_bytes = dlq_header.decompressed_size - 8;
if (decompressed_bytes < expected_decompressed_bytes) { if (decompressed_bytes < expected_decompressed_bytes) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"GCI decompressed data is smaller than expected size (have 0x%zX bytes, expected 0x%zX bytes)", "GCI decompressed data is smaller than expected size (have 0x%zX bytes, expected 0x%zX bytes)",
decompressed_bytes, expected_decompressed_bytes)); decompressed_bytes, expected_decompressed_bytes));
} }
@@ -1054,7 +1052,7 @@ string decode_gci_data(
size_t decompressed_size = prs_decompress_size(decrypted); size_t decompressed_size = prs_decompress_size(decrypted);
if (decompressed_size != sizeof(Episode3::MapDefinition)) { if (decompressed_size != sizeof(Episode3::MapDefinition)) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"decompressed quest is 0x%zX bytes; expected 0x%zX bytes", "decompressed quest is 0x%zX bytes; expected 0x%zX bytes",
decompressed_size, sizeof(Episode3::MapDefinition))); decompressed_size, sizeof(Episode3::MapDefinition)));
} }
@@ -1071,7 +1069,7 @@ string decode_vms_data(
ssize_t find_seed_num_threads, ssize_t find_seed_num_threads,
int64_t known_seed, int64_t known_seed,
bool skip_checksum) { bool skip_checksum) {
StringReader r(data); phosg::StringReader r(data);
const auto& header = r.get<PSOVMSFileHeader>(); const auto& header = r.get<PSOVMSFileHeader>();
if (!header.checksum_correct()) { if (!header.checksum_correct()) {
throw runtime_error("VMS file unencrypted header checksum is incorrect"); throw runtime_error("VMS file unencrypted header checksum is incorrect");
@@ -1101,7 +1099,7 @@ string decode_vms_data(
} }
string decode_dlq_data(const string& data) { string decode_dlq_data(const string& data) {
StringReader r(data); phosg::StringReader r(data);
uint32_t decompressed_size = r.get_u32l(); uint32_t decompressed_size = r.get_u32l();
uint32_t key = r.get_u32l(); uint32_t key = r.get_u32l();
@@ -1125,7 +1123,7 @@ string decode_dlq_data(const string& data) {
template <typename HeaderT, typename OpenFileT> template <typename HeaderT, typename OpenFileT>
static unordered_map<string, string> decode_qst_data_t(const string& data) { static unordered_map<string, string> decode_qst_data_t(const string& data) {
StringReader r(data); phosg::StringReader r(data);
unordered_map<string, string> files; unordered_map<string, string> files;
unordered_map<string, size_t> file_remaining_bytes; unordered_map<string, size_t> file_remaining_bytes;
@@ -1201,7 +1199,7 @@ static unordered_map<string, string> decode_qst_data_t(const string& data) {
for (const auto& it : file_remaining_bytes) { for (const auto& it : file_remaining_bytes) {
if (it.second) { if (it.second) {
throw runtime_error(string_printf("expected %zu (0x%zX) more bytes for file %s", it.second, it.second, it.first.c_str())); throw runtime_error(phosg::string_printf("expected %zu (0x%zX) more bytes for file %s", it.second, it.second, it.first.c_str()));
} }
} }
@@ -1222,7 +1220,7 @@ unordered_map<string, string> decode_qst_data(const string& data) {
// - PC: 3C 00 44 ?? or 3C 00 A6 ?? // - PC: 3C 00 44 ?? or 3C 00 A6 ??
// - DC/GC: 44 ?? 3C 00 or A6 ?? 3C 00 // - DC/GC: 44 ?? 3C 00 or A6 ?? 3C 00
// - XB: 44 ?? 54 00 or A6 ?? 54 00 // - XB: 44 ?? 54 00 or A6 ?? 54 00
StringReader r(data); phosg::StringReader r(data);
uint32_t signature = r.get_u32b(); uint32_t signature = r.get_u32b();
if ((signature == 0x58004400) || (signature == 0x5800A600)) { if ((signature == 0x58004400) || (signature == 0x5800A600)) {
return decode_qst_data_t<PSOCommandHeaderBB, S_OpenFile_BB_44_A6>(data); return decode_qst_data_t<PSOCommandHeaderBB, S_OpenFile_BB_44_A6>(data);
@@ -1246,7 +1244,7 @@ unordered_map<string, string> decode_qst_data(const string& data) {
} }
template <typename HeaderT> template <typename HeaderT>
void add_command_header(StringWriter& w, uint8_t command, uint8_t flag, uint16_t size) { void add_command_header(phosg::StringWriter& w, uint8_t command, uint8_t flag, uint16_t size) {
HeaderT header; HeaderT header;
header.command = command; header.command = command;
header.flag = flag; header.flag = flag;
@@ -1256,7 +1254,7 @@ void add_command_header(StringWriter& w, uint8_t command, uint8_t flag, uint16_t
template <typename HeaderT, typename CmdT> template <typename HeaderT, typename CmdT>
void add_open_file_command_t( void add_open_file_command_t(
StringWriter& w, phosg::StringWriter& w,
const std::string& name, const std::string& name,
const std::string& filename, const std::string& filename,
const std::string&, const std::string&,
@@ -1276,7 +1274,7 @@ void add_open_file_command_t(
template <> template <>
void add_open_file_command_t<PSOCommandHeaderDCV3, S_OpenFile_XB_44_A6>( void add_open_file_command_t<PSOCommandHeaderDCV3, S_OpenFile_XB_44_A6>(
StringWriter& w, phosg::StringWriter& w,
const std::string& name, const std::string& name,
const std::string& filename, const std::string& filename,
const std::string& xb_filename, const std::string& xb_filename,
@@ -1296,7 +1294,7 @@ void add_open_file_command_t<PSOCommandHeaderDCV3, S_OpenFile_XB_44_A6>(
template <typename HeaderT> template <typename HeaderT>
void add_write_file_commands_t( void add_write_file_commands_t(
StringWriter& w, phosg::StringWriter& w,
const string& filename, const string& filename,
const string& data, const string& data,
bool is_download, bool is_download,
@@ -1325,7 +1323,7 @@ string encode_qst_file(
const string& xb_filename, const string& xb_filename,
Version version, Version version,
bool is_dlq_encoded) { bool is_dlq_encoded) {
StringWriter w; phosg::StringWriter w;
// Some tools expect both open file commands at the beginning, hence this // Some tools expect both open file commands at the beginning, hence this
// unfortunate abstraction-breaking. // unfortunate abstraction-breaking.
+2 -2
View File
@@ -42,7 +42,7 @@ struct QuestCategoryIndex {
std::string name; std::string name;
std::string description; std::string description;
explicit Category(uint32_t category_id, const JSON& json); explicit Category(uint32_t category_id, const phosg::JSON& json);
[[nodiscard]] inline bool check_flag(QuestMenuType menu_type) const { [[nodiscard]] inline bool check_flag(QuestMenuType menu_type) const {
return this->enabled_flags & (1 << static_cast<uint8_t>(menu_type)); return this->enabled_flags & (1 << static_cast<uint8_t>(menu_type));
@@ -57,7 +57,7 @@ struct QuestCategoryIndex {
std::vector<std::shared_ptr<Category>> categories; std::vector<std::shared_ptr<Category>> categories;
explicit QuestCategoryIndex(const JSON& json); explicit QuestCategoryIndex(const phosg::JSON& json);
std::shared_ptr<const Category> at(uint32_t category_id) const; std::shared_ptr<const Category> at(uint32_t category_id) const;
}; };
+219 -219
View File
@@ -74,10 +74,10 @@ static string escape_string(const string& data, TextEncoding encoding = TextEnco
decoded = tt_ascii_to_utf8(data); decoded = tt_ascii_to_utf8(data);
break; break;
default: default:
return format_data_string(data); return phosg::format_data_string(data);
} }
} catch (const runtime_error&) { } catch (const runtime_error&) {
return format_data_string(data); return phosg::format_data_string(data);
} }
string ret = "\""; string ret = "\"";
@@ -89,7 +89,7 @@ static string escape_string(const string& data, TextEncoding encoding = TextEnco
} else if (ch == '\t') { } else if (ch == '\t') {
ret += "\\t"; ret += "\\t";
} else if (static_cast<uint8_t>(ch) < 0x20) { } else if (static_cast<uint8_t>(ch) < 0x20) {
ret += string_printf("\\x%02hhX", ch); ret += phosg::string_printf("\\x%02hhX", ch);
} else if (ch == '\'') { } else if (ch == '\'') {
ret += "\\\'"; ret += "\\\'";
} else if (ch == '\"') { } else if (ch == '\"') {
@@ -108,7 +108,7 @@ static string format_and_indent_data(const void* data, size_t size, uint64_t sta
iov.iov_len = size; iov.iov_len = size;
string ret = " "; string ret = " ";
format_data( phosg::format_data(
[&ret](const void* vdata, size_t size) -> void { [&ret](const void* vdata, size_t size) -> void {
const char* data = reinterpret_cast<const char*>(vdata); const char* data = reinterpret_cast<const char*>(vdata);
for (size_t z = 0; z < size; z++) { for (size_t z = 0; z < size; z++) {
@@ -119,9 +119,9 @@ static string format_and_indent_data(const void* data, size_t size, uint64_t sta
} }
} }
}, },
&iov, 1, start_address, nullptr, 0, PrintDataFlags::PRINT_ASCII); &iov, 1, start_address, nullptr, 0, phosg::PrintDataFlags::PRINT_ASCII);
strip_trailing_whitespace(ret); phosg::strip_trailing_whitespace(ret);
return ret; return ret;
} }
@@ -878,7 +878,7 @@ opcodes_for_version(Version v) {
continue; continue;
} }
if (!index.emplace(def.opcode, &def).second) { if (!index.emplace(def.opcode, &def).second) {
throw logic_error(string_printf("duplicate definition for opcode %04hX", def.opcode)); throw logic_error(phosg::string_printf("duplicate definition for opcode %04hX", def.opcode));
} }
} }
} }
@@ -904,7 +904,7 @@ opcodes_by_name_for_version(Version v) {
continue; continue;
} }
if (!index.emplace(def.name, &def).second) { if (!index.emplace(def.name, &def).second) {
throw logic_error(string_printf("duplicate definition for opcode %04hX", def.opcode)); throw logic_error(phosg::string_printf("duplicate definition for opcode %04hX", def.opcode));
} }
} }
} }
@@ -912,9 +912,9 @@ opcodes_by_name_for_version(Version v) {
} }
std::string disassemble_quest_script(const void* data, size_t size, Version version, uint8_t override_language, bool reassembly_mode) { std::string disassemble_quest_script(const void* data, size_t size, Version version, uint8_t override_language, bool reassembly_mode) {
StringReader r(data, size); phosg::StringReader r(data, size);
deque<string> lines; deque<string> lines;
lines.emplace_back(string_printf(".version %s", name_for_enum(version))); lines.emplace_back(phosg::string_printf(".version %s", phosg::name_for_enum(version)));
bool use_wstrs = false; bool use_wstrs = false;
size_t code_offset = 0; size_t code_offset = 0;
@@ -942,8 +942,8 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} else { } else {
language = 1; language = 1;
} }
lines.emplace_back(string_printf(".quest_num %hu", header.quest_number.load())); lines.emplace_back(phosg::string_printf(".quest_num %hu", header.quest_number.load()));
lines.emplace_back(string_printf(".language %hhu", header.language)); lines.emplace_back(phosg::string_printf(".language %hhu", header.language));
lines.emplace_back(".name " + escape_string(header.name.decode(language))); lines.emplace_back(".name " + escape_string(header.name.decode(language)));
lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language))); lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language)));
lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language))); lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language)));
@@ -962,8 +962,8 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} else { } else {
language = 1; language = 1;
} }
lines.emplace_back(string_printf(".quest_num %hu", header.quest_number.load())); lines.emplace_back(phosg::string_printf(".quest_num %hu", header.quest_number.load()));
lines.emplace_back(string_printf(".language %hhu", header.language)); lines.emplace_back(phosg::string_printf(".language %hhu", header.language));
lines.emplace_back(".name " + escape_string(header.name.decode(language))); lines.emplace_back(".name " + escape_string(header.name.decode(language)));
lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language))); lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language)));
lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language))); lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language)));
@@ -984,9 +984,9 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} else { } else {
language = 1; language = 1;
} }
lines.emplace_back(string_printf(".quest_num %hhu", header.quest_number)); lines.emplace_back(phosg::string_printf(".quest_num %hhu", header.quest_number));
lines.emplace_back(string_printf(".language %hhu", header.language)); lines.emplace_back(phosg::string_printf(".language %hhu", header.language));
lines.emplace_back(string_printf(".episode %s", name_for_header_episode_number(header.episode))); lines.emplace_back(phosg::string_printf(".episode %s", name_for_header_episode_number(header.episode)));
lines.emplace_back(".name " + escape_string(header.name.decode(language))); lines.emplace_back(".name " + escape_string(header.name.decode(language)));
lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language))); lines.emplace_back(".short_desc " + escape_string(header.short_description.decode(language)));
lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language))); lines.emplace_back(".long_desc " + escape_string(header.long_description.decode(language)));
@@ -1002,9 +1002,9 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} else { } else {
language = 1; language = 1;
} }
lines.emplace_back(string_printf(".quest_num %hu", header.quest_number.load())); lines.emplace_back(phosg::string_printf(".quest_num %hu", header.quest_number.load()));
lines.emplace_back(string_printf(".episode %s", name_for_header_episode_number(header.episode))); lines.emplace_back(phosg::string_printf(".episode %s", name_for_header_episode_number(header.episode)));
lines.emplace_back(string_printf(".max_players %hhu", header.max_players ? header.max_players : 4)); lines.emplace_back(phosg::string_printf(".max_players %hhu", header.max_players ? header.max_players : 4));
if (header.joinable) { if (header.joinable) {
lines.emplace_back(".joinable"); lines.emplace_back(".joinable");
} }
@@ -1018,7 +1018,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} }
const auto& opcodes = opcodes_for_version(version); const auto& opcodes = opcodes_for_version(version);
StringReader cmd_r = r.sub(code_offset, function_table_offset - code_offset); phosg::StringReader cmd_r = r.sub(code_offset, function_table_offset - code_offset);
struct Label { struct Label {
string name; string name;
@@ -1042,11 +1042,11 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
vector<shared_ptr<Label>> function_table; vector<shared_ptr<Label>> function_table;
multimap<size_t, shared_ptr<Label>> offset_to_label; multimap<size_t, shared_ptr<Label>> offset_to_label;
StringReader function_table_r = r.sub(function_table_offset); phosg::StringReader function_table_r = r.sub(function_table_offset);
while (!function_table_r.eof()) { while (!function_table_r.eof()) {
try { try {
uint32_t function_id = function_table.size(); uint32_t function_id = function_table.size();
string name = (function_id == 0) ? "start" : string_printf("label%04" PRIX32, function_id); string name = (function_id == 0) ? "start" : phosg::string_printf("label%04" PRIX32, function_id);
uint32_t offset = function_table_r.get_u32l(); uint32_t offset = function_table_r.get_u32l();
auto l = make_shared<Label>(name, offset, function_id); auto l = make_shared<Label>(name, offset, function_id);
if (function_id == 0) { if (function_id == 0) {
@@ -1123,9 +1123,9 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} }
if (def == nullptr) { if (def == nullptr) {
dasm_line = string_printf(".unknown %04hX", opcode); dasm_line = phosg::string_printf(".unknown %04hX", opcode);
} else { } else {
dasm_line = def->name ? def->name : string_printf("[%04hX]", opcode); dasm_line = def->name ? def->name : phosg::string_printf("[%04hX]", opcode);
if (!version_has_args || !(def->flags & F_ARGS)) { if (!version_has_args || !(def->flags & F_ARGS)) {
dasm_line.resize(0x20, ' '); dasm_line.resize(0x20, ' ');
bool is_first_arg = true; bool is_first_arg = true;
@@ -1140,13 +1140,13 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
arg_stack_values.emplace_back(ArgStackValue::Type::LABEL, label_id); arg_stack_values.emplace_back(ArgStackValue::Type::LABEL, label_id);
} }
if (label_id >= function_table.size()) { if (label_id >= function_table.size()) {
dasm_arg = string_printf("label%04" PRIX32, label_id); dasm_arg = phosg::string_printf("label%04" PRIX32, label_id);
} else { } else {
auto& l = function_table.at(label_id); auto& l = function_table.at(label_id);
if (reassembly_mode) { if (reassembly_mode) {
dasm_arg = string_printf("label%04" PRIX32, label_id); dasm_arg = phosg::string_printf("label%04" PRIX32, label_id);
} else { } else {
dasm_arg = string_printf("label%04" PRIX32 " /* %04" PRIX32 " */", label_id, l->offset); dasm_arg = phosg::string_printf("label%04" PRIX32 " /* %04" PRIX32 " */", label_id, l->offset);
} }
l->references.emplace(opcode_start_offset); l->references.emplace(opcode_start_offset);
l->add_data_type(arg.data_type); l->add_data_type(arg.data_type);
@@ -1165,13 +1165,13 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
dasm_arg += (dasm_arg.empty() ? "[" : ", "); dasm_arg += (dasm_arg.empty() ? "[" : ", ");
uint32_t label_id = cmd_r.get_u16l(); uint32_t label_id = cmd_r.get_u16l();
if (label_id >= function_table.size()) { if (label_id >= function_table.size()) {
dasm_arg += string_printf("label%04" PRIX32, label_id); dasm_arg += phosg::string_printf("label%04" PRIX32, label_id);
} else { } else {
auto& l = function_table.at(label_id); auto& l = function_table.at(label_id);
if (reassembly_mode) { if (reassembly_mode) {
dasm_arg += string_printf("label%04" PRIX32, label_id); dasm_arg += phosg::string_printf("label%04" PRIX32, label_id);
} else { } else {
dasm_arg += string_printf("label%04" PRIX32 " /* %04" PRIX32 " */", label_id, l->offset); dasm_arg += phosg::string_printf("label%04" PRIX32 " /* %04" PRIX32 " */", label_id, l->offset);
} }
l->references.emplace(opcode_start_offset); l->references.emplace(opcode_start_offset);
l->add_data_type(arg.data_type); l->add_data_type(arg.data_type);
@@ -1192,7 +1192,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
if (def->flags & F_PASS) { if (def->flags & F_PASS) {
arg_stack_values.emplace_back((def->opcode == 0x004C) ? ArgStackValue::Type::REG_PTR : ArgStackValue::Type::REG, reg); arg_stack_values.emplace_back((def->opcode == 0x004C) ? ArgStackValue::Type::REG_PTR : ArgStackValue::Type::REG, reg);
} }
dasm_arg = string_printf("r%hhu", reg); dasm_arg = phosg::string_printf("r%hhu", reg);
break; break;
} }
case Type::REG_SET: { case Type::REG_SET: {
@@ -1201,7 +1201,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} }
uint8_t num_regs = cmd_r.get_u8(); uint8_t num_regs = cmd_r.get_u8();
for (size_t z = 0; z < num_regs; z++) { for (size_t z = 0; z < num_regs; z++) {
dasm_arg += string_printf("%sr%hhu", (dasm_arg.empty() ? "[" : ", "), cmd_r.get_u8()); dasm_arg += phosg::string_printf("%sr%hhu", (dasm_arg.empty() ? "[" : ", "), cmd_r.get_u8());
} }
if (dasm_arg.empty()) { if (dasm_arg.empty()) {
dasm_arg = "[]"; dasm_arg = "[]";
@@ -1215,7 +1215,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
throw logic_error("REG_SET_FIXED cannot be pushed to arg stack"); throw logic_error("REG_SET_FIXED cannot be pushed to arg stack");
} }
uint8_t first_reg = cmd_r.get_u8(); uint8_t first_reg = cmd_r.get_u8();
dasm_arg = string_printf("r%hhu-r%hhu", first_reg, static_cast<uint8_t>(first_reg + arg.count - 1)); dasm_arg = phosg::string_printf("r%hhu-r%hhu", first_reg, static_cast<uint8_t>(first_reg + arg.count - 1));
break; break;
} }
case Type::REG32_SET_FIXED: { case Type::REG32_SET_FIXED: {
@@ -1223,7 +1223,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
throw logic_error("REG32_SET_FIXED cannot be pushed to arg stack"); throw logic_error("REG32_SET_FIXED cannot be pushed to arg stack");
} }
uint32_t first_reg = cmd_r.get_u32l(); uint32_t first_reg = cmd_r.get_u32l();
dasm_arg = string_printf("r%" PRIu32 "-r%" PRIu32, first_reg, static_cast<uint32_t>(first_reg + arg.count - 1)); dasm_arg = phosg::string_printf("r%" PRIu32 "-r%" PRIu32, first_reg, static_cast<uint32_t>(first_reg + arg.count - 1));
break; break;
} }
case Type::INT8: { case Type::INT8: {
@@ -1231,7 +1231,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
if (def->flags & F_PASS) { if (def->flags & F_PASS) {
arg_stack_values.emplace_back(ArgStackValue::Type::INT, v); arg_stack_values.emplace_back(ArgStackValue::Type::INT, v);
} }
dasm_arg = string_printf("0x%02hhX", v); dasm_arg = phosg::string_printf("0x%02hhX", v);
break; break;
} }
case Type::INT16: { case Type::INT16: {
@@ -1239,7 +1239,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
if (def->flags & F_PASS) { if (def->flags & F_PASS) {
arg_stack_values.emplace_back(ArgStackValue::Type::INT, v); arg_stack_values.emplace_back(ArgStackValue::Type::INT, v);
} }
dasm_arg = string_printf("0x%04hX", v); dasm_arg = phosg::string_printf("0x%04hX", v);
break; break;
} }
case Type::INT32: { case Type::INT32: {
@@ -1247,7 +1247,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
if (def->flags & F_PASS) { if (def->flags & F_PASS) {
arg_stack_values.emplace_back(ArgStackValue::Type::INT, v); arg_stack_values.emplace_back(ArgStackValue::Type::INT, v);
} }
dasm_arg = string_printf("0x%08" PRIX32, v); dasm_arg = phosg::string_printf("0x%08" PRIX32, v);
break; break;
} }
case Type::FLOAT32: { case Type::FLOAT32: {
@@ -1255,12 +1255,12 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
if (def->flags & F_PASS) { if (def->flags & F_PASS) {
arg_stack_values.emplace_back(ArgStackValue::Type::INT, as_type<uint32_t>(v)); arg_stack_values.emplace_back(ArgStackValue::Type::INT, as_type<uint32_t>(v));
} }
dasm_arg = string_printf("%g", v); dasm_arg = phosg::string_printf("%g", v);
break; break;
} }
case Type::CSTRING: case Type::CSTRING:
if (use_wstrs) { if (use_wstrs) {
StringWriter w; phosg::StringWriter w;
for (uint16_t ch = cmd_r.get_u16l(); ch; ch = cmd_r.get_u16l()) { for (uint16_t ch = cmd_r.get_u16l(); ch; ch = cmd_r.get_u16l()) {
w.put_u16l(ch); w.put_u16l(ch);
} }
@@ -1295,7 +1295,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
dasm_line += "... "; dasm_line += "... ";
if (def->args.size() != arg_stack_values.size()) { if (def->args.size() != arg_stack_values.size()) {
dasm_line += string_printf("/* matching error: expected %zu arguments, received %zu arguments */", dasm_line += phosg::string_printf("/* matching error: expected %zu arguments, received %zu arguments */",
def->args.size(), arg_stack_values.size()); def->args.size(), arg_stack_values.size());
} else { } else {
bool is_first_arg = true; bool is_first_arg = true;
@@ -1309,11 +1309,11 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
case Arg::Type::LABEL32: case Arg::Type::LABEL32:
switch (arg_value.type) { switch (arg_value.type) {
case ArgStackValue::Type::REG: case ArgStackValue::Type::REG:
dasm_arg = string_printf("r%" PRIu32 "/* warning: cannot determine label data type */", arg_value.as_int); dasm_arg = phosg::string_printf("r%" PRIu32 "/* warning: cannot determine label data type */", arg_value.as_int);
break; break;
case ArgStackValue::Type::LABEL: case ArgStackValue::Type::LABEL:
case ArgStackValue::Type::INT: case ArgStackValue::Type::INT:
dasm_arg = string_printf("label%04" PRIX32, arg_value.as_int); dasm_arg = phosg::string_printf("label%04" PRIX32, arg_value.as_int);
try { try {
auto l = function_table.at(arg_value.as_int); auto l = function_table.at(arg_value.as_int);
l->add_data_type(arg_def.data_type); l->add_data_type(arg_def.data_type);
@@ -1329,10 +1329,10 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
case Arg::Type::REG32: case Arg::Type::REG32:
switch (arg_value.type) { switch (arg_value.type) {
case ArgStackValue::Type::REG: case ArgStackValue::Type::REG:
dasm_arg = string_printf("regs[r%" PRIu32 "]", arg_value.as_int); dasm_arg = phosg::string_printf("regs[r%" PRIu32 "]", arg_value.as_int);
break; break;
case ArgStackValue::Type::INT: case ArgStackValue::Type::INT:
dasm_arg = string_printf("r%" PRIu32, arg_value.as_int); dasm_arg = phosg::string_printf("r%" PRIu32, arg_value.as_int);
break; break;
default: default:
dasm_arg = "/* invalid-type */"; dasm_arg = "/* invalid-type */";
@@ -1342,10 +1342,10 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
case Arg::Type::REG32_SET_FIXED: case Arg::Type::REG32_SET_FIXED:
switch (arg_value.type) { switch (arg_value.type) {
case ArgStackValue::Type::REG: case ArgStackValue::Type::REG:
dasm_arg = string_printf("regs[r%" PRIu32 "]-regs[r%" PRIu32 "+%hhu]", arg_value.as_int, arg_value.as_int, static_cast<uint8_t>(arg_def.count - 1)); dasm_arg = phosg::string_printf("regs[r%" PRIu32 "]-regs[r%" PRIu32 "+%hhu]", arg_value.as_int, arg_value.as_int, static_cast<uint8_t>(arg_def.count - 1));
break; break;
case ArgStackValue::Type::INT: case ArgStackValue::Type::INT:
dasm_arg = string_printf("r%" PRIu32 "-r%hhu", arg_value.as_int, static_cast<uint8_t>(arg_value.as_int + arg_def.count - 1)); dasm_arg = phosg::string_printf("r%" PRIu32 "-r%hhu", arg_value.as_int, static_cast<uint8_t>(arg_value.as_int + arg_def.count - 1));
break; break;
default: default:
dasm_arg = "/* invalid-type */"; dasm_arg = "/* invalid-type */";
@@ -1356,13 +1356,13 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
case Arg::Type::INT32: case Arg::Type::INT32:
switch (arg_value.type) { switch (arg_value.type) {
case ArgStackValue::Type::REG: case ArgStackValue::Type::REG:
dasm_arg = string_printf("r%" PRIu32, arg_value.as_int); dasm_arg = phosg::string_printf("r%" PRIu32, arg_value.as_int);
break; break;
case ArgStackValue::Type::REG_PTR: case ArgStackValue::Type::REG_PTR:
dasm_arg = string_printf("&r%" PRIu32, arg_value.as_int); dasm_arg = phosg::string_printf("&r%" PRIu32, arg_value.as_int);
break; break;
case ArgStackValue::Type::INT: case ArgStackValue::Type::INT:
dasm_arg = string_printf("0x%" PRIX32 " /* %" PRIu32 " */", arg_value.as_int, arg_value.as_int); dasm_arg = phosg::string_printf("0x%" PRIX32 " /* %" PRIu32 " */", arg_value.as_int, arg_value.as_int);
break; break;
default: default:
dasm_arg = "/* invalid-type */"; dasm_arg = "/* invalid-type */";
@@ -1371,10 +1371,10 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
case Arg::Type::FLOAT32: case Arg::Type::FLOAT32:
switch (arg_value.type) { switch (arg_value.type) {
case ArgStackValue::Type::REG: case ArgStackValue::Type::REG:
dasm_arg = string_printf("f%" PRIu32, arg_value.as_int); dasm_arg = phosg::string_printf("f%" PRIu32, arg_value.as_int);
break; break;
case ArgStackValue::Type::INT: case ArgStackValue::Type::INT:
dasm_arg = string_printf("%g", as_type<float>(arg_value.as_int)); dasm_arg = phosg::string_printf("%g", as_type<float>(arg_value.as_int));
break; break;
default: default:
dasm_arg = "/* invalid-type */"; dasm_arg = "/* invalid-type */";
@@ -1409,21 +1409,21 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} }
} }
} catch (const exception& e) { } catch (const exception& e) {
dasm_line = string_printf(".failed (%s)", e.what()); dasm_line = phosg::string_printf(".failed (%s)", e.what());
} }
strip_trailing_whitespace(dasm_line); phosg::strip_trailing_whitespace(dasm_line);
string line_text; string line_text;
if (reassembly_mode) { if (reassembly_mode) {
line_text = string_printf(" %s", dasm_line.c_str()); line_text = phosg::string_printf(" %s", dasm_line.c_str());
} else { } else {
string hex_data = format_data_string(cmd_r.preadx(opcode_start_offset, cmd_r.where() - opcode_start_offset), nullptr, FormatDataFlags::HEX_ONLY); string hex_data = phosg::format_data_string(cmd_r.preadx(opcode_start_offset, cmd_r.where() - opcode_start_offset), nullptr, phosg::FormatDataFlags::HEX_ONLY);
if (hex_data.size() > 14) { if (hex_data.size() > 14) {
hex_data.resize(12); hex_data.resize(12);
hex_data += "..."; hex_data += "...";
} }
hex_data.resize(16, ' '); hex_data.resize(16, ' ');
line_text = string_printf(" %04zX %s %s", opcode_start_offset, hex_data.c_str(), dasm_line.c_str()); line_text = phosg::string_printf(" %04zX %s %s", opcode_start_offset, hex_data.c_str(), dasm_line.c_str());
} }
dasm_lines.emplace(opcode_start_offset, DisassemblyLine(std::move(line_text), cmd_r.where())); dasm_lines.emplace(opcode_start_offset, DisassemblyLine(std::move(line_text), cmd_r.where()));
} }
@@ -1438,23 +1438,23 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
lines.emplace_back(); lines.emplace_back();
} }
if (reassembly_mode) { if (reassembly_mode) {
lines.emplace_back(string_printf("%s@0x%04" PRIX32 ":", l->name.c_str(), l->function_id)); lines.emplace_back(phosg::string_printf("%s@0x%04" PRIX32 ":", l->name.c_str(), l->function_id));
} else { } else {
lines.emplace_back(string_printf("%s:", l->name.c_str())); lines.emplace_back(phosg::string_printf("%s:", l->name.c_str()));
if (l->references.size() == 1) { if (l->references.size() == 1) {
lines.emplace_back(string_printf(" // Referenced by instruction at %04zX", *l->references.begin())); lines.emplace_back(phosg::string_printf(" // Referenced by instruction at %04zX", *l->references.begin()));
} else if (!l->references.empty()) { } else if (!l->references.empty()) {
vector<string> tokens; vector<string> tokens;
tokens.reserve(l->references.size()); tokens.reserve(l->references.size());
for (size_t reference_offset : l->references) { for (size_t reference_offset : l->references) {
tokens.emplace_back(string_printf("%04zX", reference_offset)); tokens.emplace_back(phosg::string_printf("%04zX", reference_offset));
} }
lines.emplace_back(" // Referenced by instructions at " + join(tokens, ", ")); lines.emplace_back(" // Referenced by instructions at " + phosg::join(tokens, ", "));
} }
} }
if (l->type_flags == 0) { if (l->type_flags == 0) {
lines.emplace_back(string_printf(" // Could not determine data type; disassembling as code")); lines.emplace_back(phosg::string_printf(" // Could not determine data type; disassembling as code"));
l->add_data_type(Arg::DataType::SCRIPT); l->add_data_type(Arg::DataType::SCRIPT);
} }
@@ -1474,7 +1474,7 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
if (l->has_data_type(Arg::DataType::SCRIPT)) { if (l->has_data_type(Arg::DataType::SCRIPT)) {
add_disassembly_lines(l->offset, size); add_disassembly_lines(l->offset, size);
} else { } else {
lines.emplace_back(".data " + format_data_string(cmd_r.pgetv(l->offset, size), size)); lines.emplace_back(".data " + phosg::format_data_string(cmd_r.pgetv(l->offset, size), size));
} }
} else { } else {
@@ -1489,20 +1489,20 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
lines.emplace_back(format_and_indent_data(cmd_r.pgetv(struct_end_offset, remaining_size), remaining_size, struct_end_offset)); lines.emplace_back(format_and_indent_data(cmd_r.pgetv(struct_end_offset, remaining_size), remaining_size, struct_end_offset));
} }
} else { } else {
lines.emplace_back(string_printf(" // As raw data (0x%zX bytes; too small for referenced type)", size)); lines.emplace_back(phosg::string_printf(" // As raw data (0x%zX bytes; too small for referenced type)", size));
lines.emplace_back(format_and_indent_data(cmd_r.pgetv(l->offset, size), size, l->offset)); lines.emplace_back(format_and_indent_data(cmd_r.pgetv(l->offset, size), size, l->offset));
} }
} }
}; };
if (l->has_data_type(Arg::DataType::DATA)) { if (l->has_data_type(Arg::DataType::DATA)) {
lines.emplace_back(string_printf(" // As raw data (0x%zX bytes)", size)); lines.emplace_back(phosg::string_printf(" // As raw data (0x%zX bytes)", size));
lines.emplace_back(format_and_indent_data(cmd_r.pgetv(l->offset, size), size, l->offset)); lines.emplace_back(format_and_indent_data(cmd_r.pgetv(l->offset, size), size, l->offset));
} }
if (l->has_data_type(Arg::DataType::CSTRING)) { if (l->has_data_type(Arg::DataType::CSTRING)) {
lines.emplace_back(string_printf(" // As C string (0x%zX bytes)", size)); lines.emplace_back(phosg::string_printf(" // As C string (0x%zX bytes)", size));
string str_data = cmd_r.pread(l->offset, size); string str_data = cmd_r.pread(l->offset, size);
strip_trailing_zeroes(str_data); phosg::strip_trailing_zeroes(str_data);
if (use_wstrs) { if (use_wstrs) {
if (str_data.size() & 1) { if (str_data.size() & 1) {
str_data.push_back(0); str_data.push_back(0);
@@ -1510,100 +1510,100 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
str_data = tt_utf16_to_utf8(str_data); str_data = tt_utf16_to_utf8(str_data);
} }
string formatted = escape_string(str_data, use_wstrs ? TextEncoding::UTF16 : encoding_for_language(language)); string formatted = escape_string(str_data, use_wstrs ? TextEncoding::UTF16 : encoding_for_language(language));
lines.emplace_back(string_printf(" %04" PRIX32 " %s", l->offset, formatted.c_str())); lines.emplace_back(phosg::string_printf(" %04" PRIX32 " %s", l->offset, formatted.c_str()));
} }
print_as_struct.template operator()<Arg::DataType::PLAYER_VISUAL_CONFIG, PlayerVisualConfig>([&](const PlayerVisualConfig& visual) -> void { print_as_struct.template operator()<Arg::DataType::PLAYER_VISUAL_CONFIG, PlayerVisualConfig>([&](const PlayerVisualConfig& visual) -> void {
lines.emplace_back(" // As PlayerVisualConfig"); lines.emplace_back(" // As PlayerVisualConfig");
string name = escape_string(visual.name.decode(language)); string name = escape_string(visual.name.decode(language));
lines.emplace_back(string_printf(" %04zX name %s", l->offset + offsetof(PlayerVisualConfig, name), name.c_str())); lines.emplace_back(phosg::string_printf(" %04zX name %s", l->offset + offsetof(PlayerVisualConfig, name), name.c_str()));
lines.emplace_back(string_printf(" %04zX name_color %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, name_color), visual.name_color.load())); lines.emplace_back(phosg::string_printf(" %04zX name_color %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, name_color), visual.name_color.load()));
string a2_str = format_data_string(visual.unknown_a2.data(), sizeof(visual.unknown_a2)); string a2_str = phosg::format_data_string(visual.unknown_a2.data(), sizeof(visual.unknown_a2));
lines.emplace_back(string_printf(" %04zX a2 %s", l->offset + offsetof(PlayerVisualConfig, unknown_a2), a2_str.c_str())); lines.emplace_back(phosg::string_printf(" %04zX a2 %s", l->offset + offsetof(PlayerVisualConfig, unknown_a2), a2_str.c_str()));
lines.emplace_back(string_printf(" %04zX extra_model %02hhX", l->offset + offsetof(PlayerVisualConfig, extra_model), visual.extra_model)); lines.emplace_back(phosg::string_printf(" %04zX extra_model %02hhX", l->offset + offsetof(PlayerVisualConfig, extra_model), visual.extra_model));
string unused = format_data_string(visual.unused.data(), visual.unused.bytes()); string unused = phosg::format_data_string(visual.unused.data(), visual.unused.bytes());
lines.emplace_back(string_printf(" %04zX unused %s", l->offset + offsetof(PlayerVisualConfig, unused), unused.c_str())); lines.emplace_back(phosg::string_printf(" %04zX unused %s", l->offset + offsetof(PlayerVisualConfig, unused), unused.c_str()));
lines.emplace_back(string_printf(" %04zX name_color_checksum %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, name_color_checksum), visual.name_color_checksum.load())); lines.emplace_back(phosg::string_printf(" %04zX name_color_checksum %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, name_color_checksum), visual.name_color_checksum.load()));
lines.emplace_back(string_printf(" %04zX section_id %02hhX (%s)", l->offset + offsetof(PlayerVisualConfig, section_id), visual.section_id, name_for_section_id(visual.section_id))); lines.emplace_back(phosg::string_printf(" %04zX section_id %02hhX (%s)", l->offset + offsetof(PlayerVisualConfig, section_id), visual.section_id, name_for_section_id(visual.section_id)));
lines.emplace_back(string_printf(" %04zX char_class %02hhX (%s)", l->offset + offsetof(PlayerVisualConfig, char_class), visual.char_class, name_for_char_class(visual.char_class))); lines.emplace_back(phosg::string_printf(" %04zX char_class %02hhX (%s)", l->offset + offsetof(PlayerVisualConfig, char_class), visual.char_class, name_for_char_class(visual.char_class)));
lines.emplace_back(string_printf(" %04zX validation_flags %02hhX", l->offset + offsetof(PlayerVisualConfig, validation_flags), visual.validation_flags)); lines.emplace_back(phosg::string_printf(" %04zX validation_flags %02hhX", l->offset + offsetof(PlayerVisualConfig, validation_flags), visual.validation_flags));
lines.emplace_back(string_printf(" %04zX version %02hhX", l->offset + offsetof(PlayerVisualConfig, version), visual.version)); lines.emplace_back(phosg::string_printf(" %04zX version %02hhX", l->offset + offsetof(PlayerVisualConfig, version), visual.version));
lines.emplace_back(string_printf(" %04zX class_flags %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, class_flags), visual.class_flags.load())); lines.emplace_back(phosg::string_printf(" %04zX class_flags %08" PRIX32, l->offset + offsetof(PlayerVisualConfig, class_flags), visual.class_flags.load()));
lines.emplace_back(string_printf(" %04zX costume %04hX", l->offset + offsetof(PlayerVisualConfig, costume), visual.costume.load())); lines.emplace_back(phosg::string_printf(" %04zX costume %04hX", l->offset + offsetof(PlayerVisualConfig, costume), visual.costume.load()));
lines.emplace_back(string_printf(" %04zX skin %04hX", l->offset + offsetof(PlayerVisualConfig, skin), visual.skin.load())); lines.emplace_back(phosg::string_printf(" %04zX skin %04hX", l->offset + offsetof(PlayerVisualConfig, skin), visual.skin.load()));
lines.emplace_back(string_printf(" %04zX face %04hX", l->offset + offsetof(PlayerVisualConfig, face), visual.face.load())); lines.emplace_back(phosg::string_printf(" %04zX face %04hX", l->offset + offsetof(PlayerVisualConfig, face), visual.face.load()));
lines.emplace_back(string_printf(" %04zX head %04hX", l->offset + offsetof(PlayerVisualConfig, head), visual.head.load())); lines.emplace_back(phosg::string_printf(" %04zX head %04hX", l->offset + offsetof(PlayerVisualConfig, head), visual.head.load()));
lines.emplace_back(string_printf(" %04zX hair %04hX", l->offset + offsetof(PlayerVisualConfig, hair), visual.hair.load())); lines.emplace_back(phosg::string_printf(" %04zX hair %04hX", l->offset + offsetof(PlayerVisualConfig, hair), visual.hair.load()));
lines.emplace_back(string_printf(" %04zX hair_color %04hX, %04hX, %04hX", l->offset + offsetof(PlayerVisualConfig, hair_r), visual.hair_r.load(), visual.hair_g.load(), visual.hair_b.load())); lines.emplace_back(phosg::string_printf(" %04zX hair_color %04hX, %04hX, %04hX", l->offset + offsetof(PlayerVisualConfig, hair_r), visual.hair_r.load(), visual.hair_g.load(), visual.hair_b.load()));
lines.emplace_back(string_printf(" %04zX proportion %g, %g", l->offset + offsetof(PlayerVisualConfig, proportion_x), visual.proportion_x.load(), visual.proportion_y.load())); lines.emplace_back(phosg::string_printf(" %04zX proportion %g, %g", l->offset + offsetof(PlayerVisualConfig, proportion_x), visual.proportion_x.load(), visual.proportion_y.load()));
}); });
print_as_struct.template operator()<Arg::DataType::PLAYER_STATS, PlayerStats>([&](const PlayerStats& stats) -> void { print_as_struct.template operator()<Arg::DataType::PLAYER_STATS, PlayerStats>([&](const PlayerStats& stats) -> void {
lines.emplace_back(" // As PlayerStats"); lines.emplace_back(" // As PlayerStats");
lines.emplace_back(string_printf(" %04zX atp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.atp), stats.char_stats.atp.load(), stats.char_stats.atp.load())); lines.emplace_back(phosg::string_printf(" %04zX atp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.atp), stats.char_stats.atp.load(), stats.char_stats.atp.load()));
lines.emplace_back(string_printf(" %04zX mst %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.mst), stats.char_stats.mst.load(), stats.char_stats.mst.load())); lines.emplace_back(phosg::string_printf(" %04zX mst %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.mst), stats.char_stats.mst.load(), stats.char_stats.mst.load()));
lines.emplace_back(string_printf(" %04zX evp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.evp), stats.char_stats.evp.load(), stats.char_stats.evp.load())); lines.emplace_back(phosg::string_printf(" %04zX evp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.evp), stats.char_stats.evp.load(), stats.char_stats.evp.load()));
lines.emplace_back(string_printf(" %04zX hp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.hp), stats.char_stats.hp.load(), stats.char_stats.hp.load())); lines.emplace_back(phosg::string_printf(" %04zX hp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.hp), stats.char_stats.hp.load(), stats.char_stats.hp.load()));
lines.emplace_back(string_printf(" %04zX dfp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.dfp), stats.char_stats.dfp.load(), stats.char_stats.dfp.load())); lines.emplace_back(phosg::string_printf(" %04zX dfp %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.dfp), stats.char_stats.dfp.load(), stats.char_stats.dfp.load()));
lines.emplace_back(string_printf(" %04zX ata %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.ata), stats.char_stats.ata.load(), stats.char_stats.ata.load())); lines.emplace_back(phosg::string_printf(" %04zX ata %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.ata), stats.char_stats.ata.load(), stats.char_stats.ata.load()));
lines.emplace_back(string_printf(" %04zX lck %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.lck), stats.char_stats.lck.load(), stats.char_stats.lck.load())); lines.emplace_back(phosg::string_printf(" %04zX lck %04hX /* %hu */", l->offset + offsetof(PlayerStats, char_stats.lck), stats.char_stats.lck.load(), stats.char_stats.lck.load()));
lines.emplace_back(string_printf(" %04zX esp %04hX /* %hu */", l->offset + offsetof(PlayerStats, esp), stats.esp.load(), stats.esp.load())); lines.emplace_back(phosg::string_printf(" %04zX esp %04hX /* %hu */", l->offset + offsetof(PlayerStats, esp), stats.esp.load(), stats.esp.load()));
lines.emplace_back(string_printf(" %04zX height %08" PRIX32 " /* %g */", l->offset + offsetof(PlayerStats, height), stats.height.load_raw(), stats.height.load())); lines.emplace_back(phosg::string_printf(" %04zX height %08" PRIX32 " /* %g */", l->offset + offsetof(PlayerStats, height), stats.height.load_raw(), stats.height.load()));
lines.emplace_back(string_printf(" %04zX a3 %08" PRIX32 " /* %g */", l->offset + offsetof(PlayerStats, unknown_a3), stats.unknown_a3.load_raw(), stats.unknown_a3.load())); lines.emplace_back(phosg::string_printf(" %04zX a3 %08" PRIX32 " /* %g */", l->offset + offsetof(PlayerStats, unknown_a3), stats.unknown_a3.load_raw(), stats.unknown_a3.load()));
lines.emplace_back(string_printf(" %04zX level %08" PRIX32 " /* level %" PRIu32 " */", l->offset + offsetof(PlayerStats, level), stats.level.load(), stats.level.load() + 1)); lines.emplace_back(phosg::string_printf(" %04zX level %08" PRIX32 " /* level %" PRIu32 " */", l->offset + offsetof(PlayerStats, level), stats.level.load(), stats.level.load() + 1));
lines.emplace_back(string_printf(" %04zX experience %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(PlayerStats, experience), stats.experience.load(), stats.experience.load())); lines.emplace_back(phosg::string_printf(" %04zX experience %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(PlayerStats, experience), stats.experience.load(), stats.experience.load()));
lines.emplace_back(string_printf(" %04zX meseta %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(PlayerStats, meseta), stats.meseta.load(), stats.meseta.load())); lines.emplace_back(phosg::string_printf(" %04zX meseta %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(PlayerStats, meseta), stats.meseta.load(), stats.meseta.load()));
}); });
print_as_struct.template operator()<Arg::DataType::RESIST_DATA, ResistData>([&](const ResistData& resist) -> void { print_as_struct.template operator()<Arg::DataType::RESIST_DATA, ResistData>([&](const ResistData& resist) -> void {
lines.emplace_back(" // As ResistData"); lines.emplace_back(" // As ResistData");
lines.emplace_back(string_printf(" %04zX evp_bonus %04hX /* %hu */", l->offset + offsetof(ResistData, evp_bonus), resist.evp_bonus.load(), resist.evp_bonus.load())); lines.emplace_back(phosg::string_printf(" %04zX evp_bonus %04hX /* %hu */", l->offset + offsetof(ResistData, evp_bonus), resist.evp_bonus.load(), resist.evp_bonus.load()));
lines.emplace_back(string_printf(" %04zX efr %04hX /* %hu */", l->offset + offsetof(ResistData, efr), resist.efr.load(), resist.efr.load())); lines.emplace_back(phosg::string_printf(" %04zX efr %04hX /* %hu */", l->offset + offsetof(ResistData, efr), resist.efr.load(), resist.efr.load()));
lines.emplace_back(string_printf(" %04zX eic %04hX /* %hu */", l->offset + offsetof(ResistData, eic), resist.eic.load(), resist.eic.load())); lines.emplace_back(phosg::string_printf(" %04zX eic %04hX /* %hu */", l->offset + offsetof(ResistData, eic), resist.eic.load(), resist.eic.load()));
lines.emplace_back(string_printf(" %04zX eth %04hX /* %hu */", l->offset + offsetof(ResistData, eth), resist.eth.load(), resist.eth.load())); lines.emplace_back(phosg::string_printf(" %04zX eth %04hX /* %hu */", l->offset + offsetof(ResistData, eth), resist.eth.load(), resist.eth.load()));
lines.emplace_back(string_printf(" %04zX elt %04hX /* %hu */", l->offset + offsetof(ResistData, elt), resist.elt.load(), resist.elt.load())); lines.emplace_back(phosg::string_printf(" %04zX elt %04hX /* %hu */", l->offset + offsetof(ResistData, elt), resist.elt.load(), resist.elt.load()));
lines.emplace_back(string_printf(" %04zX edk %04hX /* %hu */", l->offset + offsetof(ResistData, edk), resist.edk.load(), resist.edk.load())); lines.emplace_back(phosg::string_printf(" %04zX edk %04hX /* %hu */", l->offset + offsetof(ResistData, edk), resist.edk.load(), resist.edk.load()));
lines.emplace_back(string_printf(" %04zX a6 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a6), resist.unknown_a6.load(), resist.unknown_a6.load())); lines.emplace_back(phosg::string_printf(" %04zX a6 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a6), resist.unknown_a6.load(), resist.unknown_a6.load()));
lines.emplace_back(string_printf(" %04zX a7 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a7), resist.unknown_a7.load(), resist.unknown_a7.load())); lines.emplace_back(phosg::string_printf(" %04zX a7 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a7), resist.unknown_a7.load(), resist.unknown_a7.load()));
lines.emplace_back(string_printf(" %04zX a8 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a8), resist.unknown_a8.load(), resist.unknown_a8.load())); lines.emplace_back(phosg::string_printf(" %04zX a8 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a8), resist.unknown_a8.load(), resist.unknown_a8.load()));
lines.emplace_back(string_printf(" %04zX a9 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a9), resist.unknown_a9.load(), resist.unknown_a9.load())); lines.emplace_back(phosg::string_printf(" %04zX a9 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, unknown_a9), resist.unknown_a9.load(), resist.unknown_a9.load()));
lines.emplace_back(string_printf(" %04zX dfp_bonus %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, dfp_bonus), resist.dfp_bonus.load(), resist.dfp_bonus.load())); lines.emplace_back(phosg::string_printf(" %04zX dfp_bonus %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(ResistData, dfp_bonus), resist.dfp_bonus.load(), resist.dfp_bonus.load()));
}); });
print_as_struct.template operator()<Arg::DataType::ATTACK_DATA, AttackData>([&](const AttackData& attack) -> void { print_as_struct.template operator()<Arg::DataType::ATTACK_DATA, AttackData>([&](const AttackData& attack) -> void {
lines.emplace_back(" // As AttackData"); lines.emplace_back(" // As AttackData");
lines.emplace_back(string_printf(" %04zX a1 %04hX /* %hd */", l->offset + offsetof(AttackData, unknown_a1), attack.unknown_a1.load(), attack.unknown_a1.load())); lines.emplace_back(phosg::string_printf(" %04zX a1 %04hX /* %hd */", l->offset + offsetof(AttackData, unknown_a1), attack.unknown_a1.load(), attack.unknown_a1.load()));
lines.emplace_back(string_printf(" %04zX atp %04hX /* %hd */", l->offset + offsetof(AttackData, atp), attack.atp.load(), attack.atp.load())); lines.emplace_back(phosg::string_printf(" %04zX atp %04hX /* %hd */", l->offset + offsetof(AttackData, atp), attack.atp.load(), attack.atp.load()));
lines.emplace_back(string_printf(" %04zX ata_bonus %04hX /* %hd */", l->offset + offsetof(AttackData, ata_bonus), attack.ata_bonus.load(), attack.ata_bonus.load())); lines.emplace_back(phosg::string_printf(" %04zX ata_bonus %04hX /* %hd */", l->offset + offsetof(AttackData, ata_bonus), attack.ata_bonus.load(), attack.ata_bonus.load()));
lines.emplace_back(string_printf(" %04zX a4 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a4), attack.unknown_a4.load(), attack.unknown_a4.load())); lines.emplace_back(phosg::string_printf(" %04zX a4 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a4), attack.unknown_a4.load(), attack.unknown_a4.load()));
lines.emplace_back(string_printf(" %04zX distance_x %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, distance_x), attack.distance_x.load_raw(), attack.distance_x.load())); lines.emplace_back(phosg::string_printf(" %04zX distance_x %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, distance_x), attack.distance_x.load_raw(), attack.distance_x.load()));
lines.emplace_back(string_printf(" %04zX angle_x %08" PRIX32 " /* %" PRIu32 "/65536 */", l->offset + offsetof(AttackData, angle_x), attack.angle_x.load_raw(), attack.angle_x.load())); lines.emplace_back(phosg::string_printf(" %04zX angle_x %08" PRIX32 " /* %" PRIu32 "/65536 */", l->offset + offsetof(AttackData, angle_x), attack.angle_x.load_raw(), attack.angle_x.load()));
lines.emplace_back(string_printf(" %04zX distance_y %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, distance_y), attack.distance_y.load_raw(), attack.distance_y.load())); lines.emplace_back(phosg::string_printf(" %04zX distance_y %08" PRIX32 " /* %g */", l->offset + offsetof(AttackData, distance_y), attack.distance_y.load_raw(), attack.distance_y.load()));
lines.emplace_back(string_printf(" %04zX a8 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a8), attack.unknown_a8.load(), attack.unknown_a8.load())); lines.emplace_back(phosg::string_printf(" %04zX a8 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a8), attack.unknown_a8.load(), attack.unknown_a8.load()));
lines.emplace_back(string_printf(" %04zX a9 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a9), attack.unknown_a9.load(), attack.unknown_a9.load())); lines.emplace_back(phosg::string_printf(" %04zX a9 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a9), attack.unknown_a9.load(), attack.unknown_a9.load()));
lines.emplace_back(string_printf(" %04zX a10 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a10), attack.unknown_a10.load(), attack.unknown_a10.load())); lines.emplace_back(phosg::string_printf(" %04zX a10 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a10), attack.unknown_a10.load(), attack.unknown_a10.load()));
lines.emplace_back(string_printf(" %04zX a11 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a11), attack.unknown_a11.load(), attack.unknown_a11.load())); lines.emplace_back(phosg::string_printf(" %04zX a11 %04hX /* %hu */", l->offset + offsetof(AttackData, unknown_a11), attack.unknown_a11.load(), attack.unknown_a11.load()));
lines.emplace_back(string_printf(" %04zX a12 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a12), attack.unknown_a12.load(), attack.unknown_a12.load())); lines.emplace_back(phosg::string_printf(" %04zX a12 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a12), attack.unknown_a12.load(), attack.unknown_a12.load()));
lines.emplace_back(string_printf(" %04zX a13 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a13), attack.unknown_a13.load(), attack.unknown_a13.load())); lines.emplace_back(phosg::string_printf(" %04zX a13 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a13), attack.unknown_a13.load(), attack.unknown_a13.load()));
lines.emplace_back(string_printf(" %04zX a14 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a14), attack.unknown_a14.load(), attack.unknown_a14.load())); lines.emplace_back(phosg::string_printf(" %04zX a14 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a14), attack.unknown_a14.load(), attack.unknown_a14.load()));
lines.emplace_back(string_printf(" %04zX a15 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a15), attack.unknown_a15.load(), attack.unknown_a15.load())); lines.emplace_back(phosg::string_printf(" %04zX a15 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a15), attack.unknown_a15.load(), attack.unknown_a15.load()));
lines.emplace_back(string_printf(" %04zX a16 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a16), attack.unknown_a16.load(), attack.unknown_a16.load())); lines.emplace_back(phosg::string_printf(" %04zX a16 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(AttackData, unknown_a16), attack.unknown_a16.load(), attack.unknown_a16.load()));
}); });
print_as_struct.template operator()<Arg::DataType::MOVEMENT_DATA, MovementData>([&](const MovementData& movement) -> void { print_as_struct.template operator()<Arg::DataType::MOVEMENT_DATA, MovementData>([&](const MovementData& movement) -> void {
lines.emplace_back(" // As MovementData"); lines.emplace_back(" // As MovementData");
lines.emplace_back(string_printf(" %04zX idle_move_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, idle_move_speed), movement.idle_move_speed.load_raw(), movement.idle_move_speed.load())); lines.emplace_back(phosg::string_printf(" %04zX idle_move_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, idle_move_speed), movement.idle_move_speed.load_raw(), movement.idle_move_speed.load()));
lines.emplace_back(string_printf(" %04zX idle_animation_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, idle_animation_speed), movement.idle_animation_speed.load_raw(), movement.idle_animation_speed.load())); lines.emplace_back(phosg::string_printf(" %04zX idle_animation_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, idle_animation_speed), movement.idle_animation_speed.load_raw(), movement.idle_animation_speed.load()));
lines.emplace_back(string_printf(" %04zX move_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, move_speed), movement.move_speed.load_raw(), movement.move_speed.load())); lines.emplace_back(phosg::string_printf(" %04zX move_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, move_speed), movement.move_speed.load_raw(), movement.move_speed.load()));
lines.emplace_back(string_printf(" %04zX animation_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, animation_speed), movement.animation_speed.load_raw(), movement.animation_speed.load())); lines.emplace_back(phosg::string_printf(" %04zX animation_speed %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, animation_speed), movement.animation_speed.load_raw(), movement.animation_speed.load()));
lines.emplace_back(string_printf(" %04zX a1 %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, unknown_a1), movement.unknown_a1.load_raw(), movement.unknown_a1.load())); lines.emplace_back(phosg::string_printf(" %04zX a1 %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, unknown_a1), movement.unknown_a1.load_raw(), movement.unknown_a1.load()));
lines.emplace_back(string_printf(" %04zX a2 %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, unknown_a2), movement.unknown_a2.load_raw(), movement.unknown_a2.load())); lines.emplace_back(phosg::string_printf(" %04zX a2 %08" PRIX32 " /* %g */", l->offset + offsetof(MovementData, unknown_a2), movement.unknown_a2.load_raw(), movement.unknown_a2.load()));
lines.emplace_back(string_printf(" %04zX a3 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a3), movement.unknown_a3.load(), movement.unknown_a3.load())); lines.emplace_back(phosg::string_printf(" %04zX a3 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a3), movement.unknown_a3.load(), movement.unknown_a3.load()));
lines.emplace_back(string_printf(" %04zX a4 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a4), movement.unknown_a4.load(), movement.unknown_a4.load())); lines.emplace_back(phosg::string_printf(" %04zX a4 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a4), movement.unknown_a4.load(), movement.unknown_a4.load()));
lines.emplace_back(string_printf(" %04zX a5 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a5), movement.unknown_a5.load(), movement.unknown_a5.load())); lines.emplace_back(phosg::string_printf(" %04zX a5 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a5), movement.unknown_a5.load(), movement.unknown_a5.load()));
lines.emplace_back(string_printf(" %04zX a6 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a6), movement.unknown_a6.load(), movement.unknown_a6.load())); lines.emplace_back(phosg::string_printf(" %04zX a6 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a6), movement.unknown_a6.load(), movement.unknown_a6.load()));
lines.emplace_back(string_printf(" %04zX a7 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a7), movement.unknown_a7.load(), movement.unknown_a7.load())); lines.emplace_back(phosg::string_printf(" %04zX a7 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a7), movement.unknown_a7.load(), movement.unknown_a7.load()));
lines.emplace_back(string_printf(" %04zX a8 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a8), movement.unknown_a8.load(), movement.unknown_a8.load())); lines.emplace_back(phosg::string_printf(" %04zX a8 %08" PRIX32 " /* %" PRIu32 " */", l->offset + offsetof(MovementData, unknown_a8), movement.unknown_a8.load(), movement.unknown_a8.load()));
}); });
if (l->has_data_type(Arg::DataType::IMAGE_DATA)) { if (l->has_data_type(Arg::DataType::IMAGE_DATA)) {
const void* data = cmd_r.pgetv(l->offset, size); const void* data = cmd_r.pgetv(l->offset, size);
auto decompressed = prs_decompress_with_meta(data, size); auto decompressed = prs_decompress_with_meta(data, size);
lines.emplace_back(string_printf(" // As decompressed image data (0x%zX bytes)", decompressed.data.size())); lines.emplace_back(phosg::string_printf(" // As decompressed image data (0x%zX bytes)", decompressed.data.size()));
lines.emplace_back(format_and_indent_data(decompressed.data.data(), decompressed.data.size(), 0)); lines.emplace_back(format_and_indent_data(decompressed.data.data(), decompressed.data.size(), 0));
if (decompressed.input_bytes_used < size) { if (decompressed.input_bytes_used < size) {
size_t compressed_end_offset = l->offset + decompressed.input_bytes_used; size_t compressed_end_offset = l->offset + decompressed.input_bytes_used;
@@ -1613,12 +1613,12 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} }
} }
if (l->has_data_type(Arg::DataType::UNKNOWN_F8F2_DATA)) { if (l->has_data_type(Arg::DataType::UNKNOWN_F8F2_DATA)) {
StringReader r = cmd_r.sub(l->offset, size); phosg::StringReader r = cmd_r.sub(l->offset, size);
lines.emplace_back(" // As F8F2 entries"); lines.emplace_back(" // As F8F2 entries");
while (r.remaining() >= sizeof(UnknownF8F2Entry)) { while (r.remaining() >= sizeof(UnknownF8F2Entry)) {
size_t offset = l->offset + cmd_r.where(); size_t offset = l->offset + cmd_r.where();
const auto& e = r.get<UnknownF8F2Entry>(); const auto& e = r.get<UnknownF8F2Entry>();
lines.emplace_back(string_printf(" %04zX entry %g, %g, %g, %g", offset, e.unknown_a1[0].load(), e.unknown_a1[1].load(), e.unknown_a1[2].load(), e.unknown_a1[3].load())); lines.emplace_back(phosg::string_printf(" %04zX entry %g, %g, %g, %g", offset, e.unknown_a1[0].load(), e.unknown_a1[1].load(), e.unknown_a1[2].load(), e.unknown_a1[3].load()));
} }
if (r.remaining() > 0) { if (r.remaining() > 0) {
size_t struct_end_offset = l->offset + r.where(); size_t struct_end_offset = l->offset + r.where();
@@ -1634,11 +1634,11 @@ std::string disassemble_quest_script(const void* data, size_t size, Version vers
} }
lines.emplace_back(); // Add a \n on the end lines.emplace_back(); // Add a \n on the end
return join(lines, "\n"); return phosg::join(lines, "\n");
} }
Episode find_quest_episode_from_script(const void* data, size_t size, Version version) { Episode find_quest_episode_from_script(const void* data, size_t size, Version version) {
StringReader r(data, size); phosg::StringReader r(data, size);
bool use_wstrs = false; bool use_wstrs = false;
size_t code_offset = 0; size_t code_offset = 0;
@@ -1680,7 +1680,7 @@ Episode find_quest_episode_from_script(const void* data, size_t size, Version ve
try { try {
const auto& opcodes = opcodes_for_version(version); const auto& opcodes = opcodes_for_version(version);
// The set_episode opcode should always be in the first function (0) // The set_episode opcode should always be in the first function (0)
StringReader cmd_r = r.sub(code_offset + r.pget_u32l(function_table_offset)); phosg::StringReader cmd_r = r.sub(code_offset + r.pget_u32l(function_table_offset));
while (!cmd_r.eof()) { while (!cmd_r.eof()) {
uint16_t opcode = cmd_r.get_u8(); uint16_t opcode = cmd_r.get_u8();
@@ -1695,7 +1695,7 @@ Episode find_quest_episode_from_script(const void* data, size_t size, Version ve
} }
if (def == nullptr) { if (def == nullptr) {
throw runtime_error(string_printf("unknown quest opcode %04hX", opcode)); throw runtime_error(phosg::string_printf("unknown quest opcode %04hX", opcode));
} }
if (def->flags & F_RET) { if (def->flags & F_RET) {
@@ -1772,7 +1772,7 @@ Episode find_quest_episode_from_script(const void* data, size_t size, Version ve
} }
} }
} catch (const exception& e) { } catch (const exception& e) {
log_warning("Cannot determine episode from quest script (%s)", e.what()); phosg::log_warning("Cannot determine episode from quest script (%s)", e.what());
} }
if (found_episodes.size() > 1) { if (found_episodes.size() > 1) {
@@ -1794,7 +1794,7 @@ Episode episode_for_quest_episode_number(uint8_t episode_number) {
case 0x02: case 0x02:
return Episode::EP4; return Episode::EP4;
default: default:
throw runtime_error(string_printf("invalid episode number %02hhX", episode_number)); throw runtime_error(phosg::string_printf("invalid episode number %02hhX", episode_number));
} }
} }
@@ -1807,7 +1807,7 @@ struct RegisterAssigner {
unordered_set<size_t> offsets; unordered_set<size_t> offsets;
std::string str() const { std::string str() const {
return string_printf("Register(%p, name=\"%s\", number=%hd)", this, this->name.c_str(), this->number); return phosg::string_printf("Register(%p, name=\"%s\", number=%hd)", this, this->name.c_str(), this->number);
} }
}; };
@@ -1853,7 +1853,7 @@ struct RegisterAssigner {
} }
this->numbered_regs.at(reg->number) = reg; this->numbered_regs.at(reg->number) = reg;
} else if (reg->number != number) { } else if (reg->number != number) {
throw runtime_error(string_printf("register %s is assigned multiple numbers", reg->name.c_str())); throw runtime_error(phosg::string_printf("register %s is assigned multiple numbers", reg->name.c_str()));
} }
} }
@@ -1861,10 +1861,10 @@ struct RegisterAssigner {
if (reg->name.empty()) { if (reg->name.empty()) {
reg->name = name; reg->name = name;
if (!this->named_regs.emplace(reg->name, reg).second) { if (!this->named_regs.emplace(reg->name, reg).second) {
throw runtime_error(string_printf("name %s is already assigned to a different register", reg->name.c_str())); throw runtime_error(phosg::string_printf("name %s is already assigned to a different register", reg->name.c_str()));
} }
} else if (reg->name != name) { } else if (reg->name != name) {
throw runtime_error(string_printf("register %hd is assigned multiple names", reg->number)); throw runtime_error(phosg::string_printf("register %hd is assigned multiple names", reg->number));
} }
} }
@@ -1875,11 +1875,11 @@ struct RegisterAssigner {
if (reg->number < 0) { if (reg->number < 0) {
reg->number = number; reg->number = number;
if (this->numbered_regs.at(reg->number)) { if (this->numbered_regs.at(reg->number)) {
throw logic_error(string_printf("register number %hd assigned multiple times", reg->number)); throw logic_error(phosg::string_printf("register number %hd assigned multiple times", reg->number));
} }
this->numbered_regs.at(reg->number) = reg; this->numbered_regs.at(reg->number) = reg;
} else if (reg->number != static_cast<int16_t>(number)) { } else if (reg->number != static_cast<int16_t>(number)) {
throw runtime_error(string_printf("assigning different register number %hhu over existing register number %hd", number, reg->number)); throw runtime_error(phosg::string_printf("assigning different register number %hhu over existing register number %hd", number, reg->number));
} }
} }
@@ -1887,15 +1887,15 @@ struct RegisterAssigner {
if (!first_reg->next) { if (!first_reg->next) {
first_reg->next = second_reg; first_reg->next = second_reg;
} else if (first_reg->next != second_reg) { } else if (first_reg->next != second_reg) {
throw runtime_error(string_printf("register %s must come after %s, but is already constrained to another register", second_reg->name.c_str(), first_reg->name.c_str())); throw runtime_error(phosg::string_printf("register %s must come after %s, but is already constrained to another register", second_reg->name.c_str(), first_reg->name.c_str()));
} }
if (!second_reg->prev) { if (!second_reg->prev) {
second_reg->prev = first_reg; second_reg->prev = first_reg;
} else if (second_reg->prev != first_reg) { } else if (second_reg->prev != first_reg) {
throw runtime_error(string_printf("register %s must come before %s, but is already constrained to another register", first_reg->name.c_str(), second_reg->name.c_str())); throw runtime_error(phosg::string_printf("register %s must come before %s, but is already constrained to another register", first_reg->name.c_str(), second_reg->name.c_str()));
} }
if ((first_reg->number >= 0) && (second_reg->number >= 0) && (first_reg->number != ((second_reg->number - 1) & 0xFF))) { if ((first_reg->number >= 0) && (second_reg->number >= 0) && (first_reg->number != ((second_reg->number - 1) & 0xFF))) {
throw runtime_error(string_printf("register %s must come before %s, but both registers already have non-consecutive numbers", first_reg->name.c_str(), second_reg->name.c_str())); throw runtime_error(phosg::string_printf("register %s must come before %s, but both registers already have non-consecutive numbers", first_reg->name.c_str(), second_reg->name.c_str()));
} }
} }
@@ -1952,13 +1952,13 @@ struct RegisterAssigner {
// At this point, all registers should be assigned // At this point, all registers should be assigned
for (const auto& it : this->named_regs) { for (const auto& it : this->named_regs) {
if (it.second->number < 0) { if (it.second->number < 0) {
throw logic_error(string_printf("register %s was not assigned", it.second->name.c_str())); throw logic_error(phosg::string_printf("register %s was not assigned", it.second->name.c_str()));
} }
} }
for (size_t z = 0; z < 0x100; z++) { for (size_t z = 0; z < 0x100; z++) {
auto reg = this->numbered_regs[z]; auto reg = this->numbered_regs[z];
if (reg && (reg->number != static_cast<int16_t>(z))) { if (reg && (reg->number != static_cast<int16_t>(z))) {
throw logic_error(string_printf("register %zu has incorrect number %hd", z, reg->number)); throw logic_error(phosg::string_printf("register %zu has incorrect number %hd", z, reg->number));
} }
} }
} }
@@ -1983,7 +1983,7 @@ struct RegisterAssigner {
}; };
std::string assemble_quest_script(const std::string& text, const std::string& include_directory) { std::string assemble_quest_script(const std::string& text, const std::string& include_directory) {
auto lines = split(text, '\n'); auto lines = phosg::split(text, '\n');
// Strip comments and whitespace // Strip comments and whitespace
for (auto& line : lines) { for (auto& line : lines) {
@@ -2000,8 +2000,8 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
if (comment_start != string::npos) { if (comment_start != string::npos) {
line.resize(comment_start); line.resize(comment_start);
} }
strip_trailing_whitespace(line); phosg::strip_trailing_whitespace(line);
strip_leading_whitespace(line); phosg::strip_leading_whitespace(line);
} }
// Collect metadata directives // Collect metadata directives
@@ -2019,24 +2019,24 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
continue; continue;
} }
if (line[0] == '.') { if (line[0] == '.') {
if (starts_with(line, ".version ")) { if (phosg::starts_with(line, ".version ")) {
string name = line.substr(9); string name = line.substr(9);
quest_version = enum_for_name<Version>(name.c_str()); quest_version = phosg::enum_for_name<Version>(name.c_str());
} else if (starts_with(line, ".name ")) { } else if (phosg::starts_with(line, ".name ")) {
quest_name = parse_data_string(line.substr(6)); quest_name = phosg::parse_data_string(line.substr(6));
} else if (starts_with(line, ".short_desc ")) { } else if (phosg::starts_with(line, ".short_desc ")) {
quest_short_desc = parse_data_string(line.substr(12)); quest_short_desc = phosg::parse_data_string(line.substr(12));
} else if (starts_with(line, ".long_desc ")) { } else if (phosg::starts_with(line, ".long_desc ")) {
quest_long_desc = parse_data_string(line.substr(11)); quest_long_desc = phosg::parse_data_string(line.substr(11));
} else if (starts_with(line, ".quest_num ")) { } else if (phosg::starts_with(line, ".quest_num ")) {
quest_num = stoul(line.substr(11), nullptr, 0); quest_num = stoul(line.substr(11), nullptr, 0);
} else if (starts_with(line, ".language ")) { } else if (phosg::starts_with(line, ".language ")) {
quest_language = stoul(line.substr(10), nullptr, 0); quest_language = stoul(line.substr(10), nullptr, 0);
} else if (starts_with(line, ".episode ")) { } else if (phosg::starts_with(line, ".episode ")) {
quest_episode = episode_for_token_name(line.substr(9)); quest_episode = episode_for_token_name(line.substr(9));
} else if (starts_with(line, ".max_players ")) { } else if (phosg::starts_with(line, ".max_players ")) {
quest_max_players = stoul(line.substr(12), nullptr, 0); quest_max_players = stoul(line.substr(12), nullptr, 0);
} else if (starts_with(line, ".joinable ")) { } else if (phosg::starts_with(line, ".joinable ")) {
quest_joinable = true; quest_joinable = true;
} }
} }
@@ -2061,7 +2061,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
map<ssize_t, shared_ptr<Label>> labels_by_index; map<ssize_t, shared_ptr<Label>> labels_by_index;
for (size_t line_num = 1; line_num <= lines.size(); line_num++) { for (size_t line_num = 1; line_num <= lines.size(); line_num++) {
const auto& line = lines[line_num - 1]; const auto& line = lines[line_num - 1];
if (ends_with(line, ":")) { if (phosg::ends_with(line, ":")) {
auto label = make_shared<Label>(); auto label = make_shared<Label>();
label->name = line.substr(0, line.size() - 1); label->name = line.substr(0, line.size() - 1);
size_t at_offset = label->name.find('@'); size_t at_offset = label->name.find('@');
@@ -2069,7 +2069,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
try { try {
label->index = stoul(label->name.substr(at_offset + 1), nullptr, 0); label->index = stoul(label->name.substr(at_offset + 1), nullptr, 0);
} catch (const exception& e) { } catch (const exception& e) {
throw runtime_error(string_printf("(line %zu) invalid index in label (%s)", line_num, e.what())); throw runtime_error(phosg::string_printf("(line %zu) invalid index in label (%s)", line_num, e.what()));
} }
label->name.resize(at_offset); label->name.resize(at_offset);
if (label->name == "start" && label->index != 0) { if (label->name == "start" && label->index != 0) {
@@ -2079,12 +2079,12 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
label->index = 0; label->index = 0;
} }
if (!labels_by_name.emplace(label->name, label).second) { if (!labels_by_name.emplace(label->name, label).second) {
throw runtime_error(string_printf("(line %zu) duplicate label name: %s", line_num, label->name.c_str())); throw runtime_error(phosg::string_printf("(line %zu) duplicate label name: %s", line_num, label->name.c_str()));
} }
if (label->index >= 0) { if (label->index >= 0) {
auto index_emplace_ret = labels_by_index.emplace(label->index, label); auto index_emplace_ret = labels_by_index.emplace(label->index, label);
if (label->index >= 0 && !index_emplace_ret.second) { if (label->index >= 0 && !index_emplace_ret.second) {
throw runtime_error(string_printf("(line %zu) duplicate label index: %zd (0x%zX) from %s and %s", line_num, label->index, label->index, label->name.c_str(), index_emplace_ret.first->second->name.c_str())); throw runtime_error(phosg::string_printf("(line %zu) duplicate label index: %zd (0x%zX) from %s and %s", line_num, label->index, label->index, label->name.c_str(), index_emplace_ret.first->second->name.c_str()));
} }
} }
} }
@@ -2120,7 +2120,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
string name; string name;
ssize_t number = -1; ssize_t number = -1;
if (arg[1] == ':') { if (arg[1] == ':') {
auto tokens = split(arg.substr(2), '@'); auto tokens = phosg::split(arg.substr(2), '@');
if (tokens.size() == 1) { if (tokens.size() == 1) {
name = std::move(tokens[0]); name = std::move(tokens[0]);
} else if (tokens.size() == 2) { } else if (tokens.size() == 2) {
@@ -2149,20 +2149,20 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
} }
vector<shared_ptr<RegisterAssigner::Register>> regs; vector<shared_ptr<RegisterAssigner::Register>> regs;
if ((name[0] == '(') && (name.back() == ')')) { if ((name[0] == '(') && (name.back() == ')')) {
auto tokens = split(name.substr(1, name.size() - 2), ','); auto tokens = phosg::split(name.substr(1, name.size() - 2), ',');
if (tokens.size() != expected_count) { if (tokens.size() != expected_count) {
throw runtime_error("incorrect number of registers in REG_SET_FIXED"); throw runtime_error("incorrect number of registers in REG_SET_FIXED");
} }
for (auto& token : tokens) { for (auto& token : tokens) {
strip_trailing_whitespace(token); phosg::strip_trailing_whitespace(token);
strip_leading_whitespace(token); phosg::strip_leading_whitespace(token);
regs.emplace_back(parse_reg(token)); regs.emplace_back(parse_reg(token));
if (regs.size() > 1) { if (regs.size() > 1) {
reg_assigner.constrain(regs.at(regs.size() - 2), regs.back()); reg_assigner.constrain(regs.at(regs.size() - 2), regs.back());
} }
} }
} else { } else {
auto tokens = split(name, '-'); auto tokens = phosg::split(name, '-');
if (tokens.size() == 1) { if (tokens.size() == 1) {
regs.emplace_back(parse_reg(tokens[0], false)); regs.emplace_back(parse_reg(tokens[0], false));
while (regs.size() < expected_count) { while (regs.size() < expected_count) {
@@ -2193,7 +2193,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
// Assemble code segment // Assemble code segment
bool version_has_args = F_HAS_ARGS & v_flag(quest_version); bool version_has_args = F_HAS_ARGS & v_flag(quest_version);
const auto& opcodes = opcodes_by_name_for_version(quest_version); const auto& opcodes = opcodes_by_name_for_version(quest_version);
StringWriter code_w; phosg::StringWriter code_w;
for (size_t line_num = 1; line_num <= lines.size(); line_num++) { for (size_t line_num = 1; line_num <= lines.size(); line_num++) {
try { try {
const auto& line = lines[line_num - 1]; const auto& line = lines[line_num - 1];
@@ -2201,7 +2201,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
continue; continue;
} }
if (ends_with(line, ":")) { if (phosg::ends_with(line, ":")) {
size_t at_offset = line.find('@'); size_t at_offset = line.find('@');
string label_name = line.substr(0, (at_offset == string::npos) ? (line.size() - 1) : at_offset); string label_name = line.substr(0, (at_offset == string::npos) ? (line.size() - 1) : at_offset);
labels_by_name.at(label_name)->offset = code_w.size(); labels_by_name.at(label_name)->offset = code_w.size();
@@ -2209,20 +2209,20 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
} }
if (line[0] == '.') { if (line[0] == '.') {
if (starts_with(line, ".data ")) { if (phosg::starts_with(line, ".data ")) {
code_w.write(parse_data_string(line.substr(6))); code_w.write(phosg::parse_data_string(line.substr(6)));
} else if (starts_with(line, ".zero ")) { } else if (phosg::starts_with(line, ".zero ")) {
size_t size = stoull(line.substr(6), nullptr, 0); size_t size = stoull(line.substr(6), nullptr, 0);
code_w.extend_by(size, 0x00); code_w.extend_by(size, 0x00);
} else if (starts_with(line, ".include_bin ")) { } else if (phosg::starts_with(line, ".include_bin ")) {
string filename = line.substr(13); string filename = line.substr(13);
strip_whitespace(filename); phosg::strip_whitespace(filename);
code_w.write(load_file(include_directory + "/" + filename)); code_w.write(phosg::load_file(include_directory + "/" + filename));
} else if (starts_with(line, ".include_native ")) { } else if (phosg::starts_with(line, ".include_native ")) {
#ifdef HAVE_RESOURCE_FILE #ifdef HAVE_RESOURCE_FILE
string filename = line.substr(16); string filename = line.substr(16);
strip_whitespace(filename); phosg::strip_whitespace(filename);
string native_text = load_file(include_directory + "/" + filename); string native_text = phosg::load_file(include_directory + "/" + filename);
string code; string code;
if (is_ppc(quest_version)) { if (is_ppc(quest_version)) {
code = std::move(ResourceDASM::PPC32Emulator::assemble(native_text).code); code = std::move(ResourceDASM::PPC32Emulator::assemble(native_text).code);
@@ -2241,7 +2241,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
continue; continue;
} }
auto line_tokens = split(line, ' ', 1); auto line_tokens = phosg::split(line, ' ', 1);
const auto& opcode_def = opcodes.at(line_tokens.at(0)); const auto& opcode_def = opcodes.at(line_tokens.at(0));
bool use_args = version_has_args && (opcode_def->flags & F_ARGS); bool use_args = version_has_args && (opcode_def->flags & F_ARGS);
@@ -2255,26 +2255,26 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
if (opcode_def->args.empty()) { if (opcode_def->args.empty()) {
if (line_tokens.size() > 1) { if (line_tokens.size() > 1) {
throw runtime_error(string_printf("(line %zu) arguments not allowed for %s", line_num, opcode_def->name)); throw runtime_error(phosg::string_printf("(line %zu) arguments not allowed for %s", line_num, opcode_def->name));
} }
continue; continue;
} }
if (line_tokens.size() < 2) { if (line_tokens.size() < 2) {
throw runtime_error(string_printf("(line %zu) arguments required for %s", line_num, opcode_def->name)); throw runtime_error(phosg::string_printf("(line %zu) arguments required for %s", line_num, opcode_def->name));
} }
strip_trailing_whitespace(line_tokens[1]); phosg::strip_trailing_whitespace(line_tokens[1]);
strip_leading_whitespace(line_tokens[1]); phosg::strip_leading_whitespace(line_tokens[1]);
if (starts_with(line_tokens[1], "...")) { if (phosg::starts_with(line_tokens[1], "...")) {
if (!use_args) { if (!use_args) {
throw runtime_error(string_printf("(line %zu) \'...\' can only be used with F_ARGS opcodes", line_num)); throw runtime_error(phosg::string_printf("(line %zu) \'...\' can only be used with F_ARGS opcodes", line_num));
} }
} else { // Not "..." } else { // Not "..."
auto args = split_context(line_tokens[1], ','); auto args = phosg::split_context(line_tokens[1], ',');
if (args.size() != opcode_def->args.size()) { if (args.size() != opcode_def->args.size()) {
throw runtime_error(string_printf("(line %zu) incorrect argument count for %s", line_num, opcode_def->name)); throw runtime_error(phosg::string_printf("(line %zu) incorrect argument count for %s", line_num, opcode_def->name));
} }
for (size_t z = 0; z < args.size(); z++) { for (size_t z = 0; z < args.size(); z++) {
@@ -2282,8 +2282,8 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
string& arg = args[z]; string& arg = args[z];
const auto& arg_def = opcode_def->args[z]; const auto& arg_def = opcode_def->args[z];
strip_trailing_whitespace(arg); phosg::strip_trailing_whitespace(arg);
strip_leading_whitespace(arg); phosg::strip_leading_whitespace(arg);
try { try {
auto add_cstr = [&](const string& text) -> void { auto add_cstr = [&](const string& text) -> void {
@@ -2374,7 +2374,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
if (write_as_str) { if (write_as_str) {
if (arg[0] == '\"') { if (arg[0] == '\"') {
code_w.put_u8(0x4E); // arg_pushs code_w.put_u8(0x4E); // arg_pushs
add_cstr(parse_data_string(arg)); add_cstr(phosg::parse_data_string(arg));
} else { } else {
throw runtime_error("invalid argument syntax"); throw runtime_error("invalid argument syntax");
} }
@@ -2402,10 +2402,10 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
}; };
auto split_set = [&](const string& text) -> vector<string> { auto split_set = [&](const string& text) -> vector<string> {
if (!starts_with(text, "[") || !ends_with(text, "]")) { if (!phosg::starts_with(text, "[") || !phosg::ends_with(text, "]")) {
throw runtime_error("incorrect syntax for set-valued argument"); throw runtime_error("incorrect syntax for set-valued argument");
} }
auto values = split(text.substr(1, text.size() - 2), ','); auto values = phosg::split(text.substr(1, text.size() - 2), ',');
if (values.size() > 0xFF) { if (values.size() > 0xFF) {
throw runtime_error("too many labels in set-valued argument"); throw runtime_error("too many labels in set-valued argument");
} }
@@ -2421,8 +2421,8 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
auto label_names = split_set(arg); auto label_names = split_set(arg);
code_w.put_u8(label_names.size()); code_w.put_u8(label_names.size());
for (auto name : label_names) { for (auto name : label_names) {
strip_trailing_whitespace(name); phosg::strip_trailing_whitespace(name);
strip_leading_whitespace(name); phosg::strip_leading_whitespace(name);
add_label(name, false); add_label(name, false);
} }
break; break;
@@ -2441,8 +2441,8 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
auto regs = split_set(arg); auto regs = split_set(arg);
code_w.put_u8(regs.size()); code_w.put_u8(regs.size());
for (auto reg_arg : regs) { for (auto reg_arg : regs) {
strip_trailing_whitespace(reg_arg); phosg::strip_trailing_whitespace(reg_arg);
strip_leading_whitespace(reg_arg); phosg::strip_leading_whitespace(reg_arg);
add_reg(parse_reg(reg_arg), false); add_reg(parse_reg(reg_arg), false);
} }
break; break;
@@ -2460,14 +2460,14 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
code_w.put_u32l(stof(arg, nullptr)); code_w.put_u32l(stof(arg, nullptr));
break; break;
case Type::CSTRING: case Type::CSTRING:
add_cstr(parse_data_string(arg)); add_cstr(phosg::parse_data_string(arg));
break; break;
default: default:
throw logic_error("unknown argument type"); throw logic_error("unknown argument type");
} }
} }
} catch (const exception& e) { } catch (const exception& e) {
throw runtime_error(string_printf("(arg %zu) %s", z + 1, e.what())); throw runtime_error(phosg::string_printf("(arg %zu) %s", z + 1, e.what()));
} }
} }
} }
@@ -2481,7 +2481,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
} }
} catch (const exception& e) { } catch (const exception& e) {
throw runtime_error(string_printf("(line %zu) %s", line_num, e.what())); throw runtime_error(phosg::string_printf("(line %zu) %s", line_num, e.what()));
} }
} }
while (code_w.size() & 3) { while (code_w.size() & 3) {
@@ -2524,7 +2524,7 @@ std::string assemble_quest_script(const std::string& text, const std::string& in
} }
// Generate header // Generate header
StringWriter w; phosg::StringWriter w;
switch (quest_version) { switch (quest_version) {
case Version::DC_NTE: { case Version::DC_NTE: {
PSOQuestHeaderDCNTE header; PSOQuestHeaderDCNTE header;
+45 -50
View File
@@ -11,9 +11,9 @@
using namespace std; using namespace std;
string RareItemSet::ExpandedDrop::str() const { string RareItemSet::ExpandedDrop::str() const {
auto frac = reduce_fraction<uint64_t>(this->probability, 0x100000000); auto frac = phosg::reduce_fraction<uint64_t>(this->probability, 0x100000000);
auto hex = this->data.hex(); auto hex = this->data.hex();
return string_printf( return phosg::string_printf(
"(%08" PRIX32 " => %" PRIu64 "/%" PRIu64 ") %s", "(%08" PRIX32 " => %" PRIu64 "/%" PRIu64 ") %s",
this->probability, frac.first, frac.second, hex.c_str()); this->probability, frac.first, frac.second, hex.c_str());
} }
@@ -92,21 +92,19 @@ RareItemSet::ExpandedDrop RareItemSet::ParsedRELData::PackedDrop::expand() const
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
void RareItemSet::ParsedRELData::parse_t(StringReader r, bool is_v1) { void RareItemSet::ParsedRELData::parse_t(phosg::StringReader r, bool is_v1) {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; uint32_t root_offset = r.pget<U32T<BE>>(r.size() - 0x10);
const auto& root = r.pget<OffsetsT<BE>>(root_offset);
uint32_t root_offset = r.pget<U32T>(r.size() - 0x10); phosg::StringReader monsters_r = r.sub(root.monster_rares_offset);
const auto& root = r.pget<OffsetsT<IsBigEndian>>(root_offset);
StringReader monsters_r = r.sub(root.monster_rares_offset);
for (size_t z = 0; z < (is_v1 ? 0x33 : 0x65); z++) { for (size_t z = 0; z < (is_v1 ? 0x33 : 0x65); z++) {
const auto& d = monsters_r.get<PackedDrop>(); const auto& d = monsters_r.get<PackedDrop>();
this->monster_rares.emplace_back(d.expand()); this->monster_rares.emplace_back(d.expand());
} }
StringReader box_areas_r = r.sub(root.box_areas_offset, root.box_count * sizeof(uint8_t)); phosg::StringReader box_areas_r = r.sub(root.box_areas_offset, root.box_count * sizeof(uint8_t));
StringReader box_drops_r = r.sub(root.box_rares_offset, root.box_count * sizeof(PackedDrop)); phosg::StringReader box_drops_r = r.sub(root.box_rares_offset, root.box_count * sizeof(PackedDrop));
for (size_t z = 0; z < root.box_count; z++) { for (size_t z = 0; z < root.box_count; z++) {
uint8_t area = box_areas_r.get_u8(); uint8_t area = box_areas_r.get_u8();
const auto& drop = box_drops_r.get<PackedDrop>(); const auto& drop = box_drops_r.get<PackedDrop>();
@@ -118,17 +116,14 @@ void RareItemSet::ParsedRELData::parse_t(StringReader r, bool is_v1) {
} }
} }
template <bool IsBigEndian> template <bool BE>
std::string RareItemSet::ParsedRELData::serialize_t(bool is_v1) const { std::string RareItemSet::ParsedRELData::serialize_t(bool is_v1) const {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
using U16T = typename std::conditional<IsBigEndian, be_uint16_t, le_uint16_t>::type;
static const PackedDrop empty_drop; static const PackedDrop empty_drop;
OffsetsT<IsBigEndian> root; OffsetsT<BE> root;
root.box_count = this->box_rares.size(); root.box_count = this->box_rares.size();
StringWriter w; phosg::StringWriter w;
root.monster_rares_offset = w.size(); root.monster_rares_offset = w.size();
for (const auto& drop : this->monster_rares) { for (const auto& drop : this->monster_rares) {
w.put(PackedDrop(drop)); w.put(PackedDrop(drop));
@@ -159,24 +154,24 @@ std::string RareItemSet::ParsedRELData::serialize_t(bool is_v1) const {
w.put_u8(0); w.put_u8(0);
} }
uint32_t relocations_offset = w.size(); uint32_t relocations_offset = w.size();
w.put<U16T>(root_offset >> 2); w.put<U16T<BE>>(root_offset >> 2);
w.put<U16T>(2); w.put<U16T<BE>>(2);
w.put<U16T>(1); w.put<U16T<BE>>(1);
while (w.size() & 0x1F) { while (w.size() & 0x1F) {
w.put_u8(0); w.put_u8(0);
} }
w.put<U32T>(relocations_offset); w.put<U32T<BE>>(relocations_offset);
w.put<U32T>(3); // num_relocations w.put<U32T<BE>>(3); // num_relocations
w.put<U32T>(1); // TODO: What is this used for? w.put<U32T<BE>>(1); // TODO: What is this used for?
w.put<U32T>(0); w.put<U32T<BE>>(0);
w.put<U32T>(root_offset); w.put<U32T<BE>>(root_offset);
w.put<U32T>(0); w.put<U32T<BE>>(0);
w.put<U32T>(0); w.put<U32T<BE>>(0);
w.put<U32T>(0); w.put<U32T<BE>>(0);
return std::move(w.str()); return std::move(w.str());
} }
RareItemSet::ParsedRELData::ParsedRELData(StringReader r, bool big_endian, bool is_v1) { RareItemSet::ParsedRELData::ParsedRELData(phosg::StringReader r, bool big_endian, bool is_v1) {
if (big_endian) { if (big_endian) {
this->parse_t<true>(r, is_v1); this->parse_t<true>(r, is_v1);
} else { } else {
@@ -258,7 +253,7 @@ RareItemSet::RareItemSet(const AFSArchive& afs, bool is_v1) {
} }
string RareItemSet::gsl_entry_name_for_table(GameMode mode, Episode episode, uint8_t difficulty, uint8_t section_id) { string RareItemSet::gsl_entry_name_for_table(GameMode mode, Episode episode, uint8_t difficulty, uint8_t section_id) {
return string_printf("ItemRT%s%s%c%1hhu.rel", return phosg::string_printf("ItemRT%s%s%c%1hhu.rel",
((mode == GameMode::CHALLENGE) ? "c" : ""), ((mode == GameMode::CHALLENGE) ? "c" : ""),
((episode == Episode::EP2) ? "l" : ""), ((episode == Episode::EP2) ? "l" : ""),
tolower(abbreviation_for_difficulty(difficulty)), // One of "nhvu" tolower(abbreviation_for_difficulty(difficulty)), // One of "nhvu"
@@ -288,7 +283,7 @@ RareItemSet::RareItemSet(const GSLArchive& gsl, bool is_big_endian) {
RareItemSet::RareItemSet(const string& rel_data, bool is_big_endian) { RareItemSet::RareItemSet(const string& rel_data, bool is_big_endian) {
// Tables are 0x280 bytes in size in this format, laid out sequentially // Tables are 0x280 bytes in size in this format, laid out sequentially
StringReader r(rel_data); phosg::StringReader r(rel_data);
array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4}; array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (size_t ep_index = 0; ep_index < episodes.size(); ep_index++) { for (size_t ep_index = 0; ep_index < episodes.size(); ep_index++) {
for (size_t difficulty = 0; difficulty < 4; difficulty++) { for (size_t difficulty = 0; difficulty < 4; difficulty++) {
@@ -306,7 +301,7 @@ RareItemSet::RareItemSet(const string& rel_data, bool is_big_endian) {
} }
} }
RareItemSet::RareItemSet(const JSON& json, shared_ptr<const ItemNameIndex> name_index) { RareItemSet::RareItemSet(const phosg::JSON& json, shared_ptr<const ItemNameIndex> name_index) {
for (const auto& mode_it : json.as_dict()) { for (const auto& mode_it : json.as_dict()) {
static const unordered_map<string, GameMode> mode_keys( static const unordered_map<string, GameMode> mode_keys(
{{"Normal", GameMode::NORMAL}, {"Battle", GameMode::BATTLE}, {"Challenge", GameMode::CHALLENGE}, {"Solo", GameMode::SOLO}}); {{"Normal", GameMode::NORMAL}, {"Battle", GameMode::BATTLE}, {"Challenge", GameMode::CHALLENGE}, {"Solo", GameMode::SOLO}});
@@ -328,14 +323,14 @@ RareItemSet::RareItemSet(const JSON& json, shared_ptr<const ItemNameIndex> name_
auto& collection = this->collections[this->key_for_params(mode, episode, difficulty, section_id)]; auto& collection = this->collections[this->key_for_params(mode, episode, difficulty, section_id)];
for (const auto& item_it : section_id_it.second->as_dict()) { for (const auto& item_it : section_id_it.second->as_dict()) {
vector<ExpandedDrop>* target; vector<ExpandedDrop>* target;
if (starts_with(item_it.first, "Box-")) { if (phosg::starts_with(item_it.first, "Box-")) {
uint8_t area = floor_for_name(item_it.first.substr(4)); uint8_t area = floor_for_name(item_it.first.substr(4));
if (collection.box_area_to_specs.size() <= area) { if (collection.box_area_to_specs.size() <= area) {
collection.box_area_to_specs.resize(area + 1); collection.box_area_to_specs.resize(area + 1);
} }
target = &collection.box_area_to_specs[area]; target = &collection.box_area_to_specs[area];
} else { } else {
size_t index = rare_table_index_for_enemy_type(enum_for_name<EnemyType>(item_it.first.c_str())); size_t index = rare_table_index_for_enemy_type(phosg::enum_for_name<EnemyType>(item_it.first.c_str()));
if (collection.rt_index_to_specs.size() <= index) { if (collection.rt_index_to_specs.size() <= index) {
collection.rt_index_to_specs.resize(index + 1); collection.rt_index_to_specs.resize(index + 1);
} }
@@ -349,7 +344,7 @@ RareItemSet::RareItemSet(const JSON& json, shared_ptr<const ItemNameIndex> name_
if (prob_desc.is_int()) { if (prob_desc.is_int()) {
d.probability = prob_desc.as_int(); d.probability = prob_desc.as_int();
} else if (prob_desc.is_string()) { } else if (prob_desc.is_string()) {
auto tokens = split(prob_desc.as_string(), '/'); auto tokens = phosg::split(prob_desc.as_string(), '/');
if (tokens.size() != 2) { if (tokens.size() != 2) {
throw runtime_error("invalid probability specification"); throw runtime_error("invalid probability specification");
} }
@@ -427,18 +422,18 @@ std::string RareItemSet::serialize_gsl(bool big_endian) const {
return GSLArchive::generate(files, big_endian); return GSLArchive::generate(files, big_endian);
} }
JSON RareItemSet::json(shared_ptr<const ItemNameIndex> name_index) const { phosg::JSON RareItemSet::json(shared_ptr<const ItemNameIndex> name_index) const {
auto modes_dict = JSON::dict(); auto modes_dict = phosg::JSON::dict();
static const array<GameMode, 4> modes = {GameMode::NORMAL, GameMode::BATTLE, GameMode::CHALLENGE, GameMode::SOLO}; static const array<GameMode, 4> modes = {GameMode::NORMAL, GameMode::BATTLE, GameMode::CHALLENGE, GameMode::SOLO};
for (const auto& mode : modes) { for (const auto& mode : modes) {
auto episodes_dict = JSON::dict(); auto episodes_dict = phosg::JSON::dict();
static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4}; static const array<Episode, 3> episodes = {Episode::EP1, Episode::EP2, Episode::EP4};
for (const auto& episode : episodes) { for (const auto& episode : episodes) {
auto difficulty_dict = JSON::dict(); auto difficulty_dict = phosg::JSON::dict();
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) { for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
auto section_id_dict = JSON::dict(); auto section_id_dict = phosg::JSON::dict();
for (uint8_t section_id = 0; section_id < 10; section_id++) { for (uint8_t section_id = 0; section_id < 10; section_id++) {
auto collection_dict = JSON::dict(); auto collection_dict = phosg::JSON::dict();
for (size_t rt_index = 0; rt_index < 0x80; rt_index++) { for (size_t rt_index = 0; rt_index < 0x80; rt_index++) {
const auto& enemy_types = enemy_types_for_rare_table_index(episode, rt_index); const auto& enemy_types = enemy_types_for_rare_table_index(episode, rt_index);
if (enemy_types.empty()) { if (enemy_types.empty()) {
@@ -449,8 +444,8 @@ JSON RareItemSet::json(shared_ptr<const ItemNameIndex> name_index) const {
if (spec.data.empty()) { if (spec.data.empty()) {
continue; continue;
} }
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000); auto frac = phosg::reduce_fraction<uint64_t>(spec.probability, 0x100000000);
auto spec_json = JSON::list({string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)}); auto spec_json = phosg::JSON::list({phosg::string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)});
if (spec.data.can_be_encoded_in_rel_rare_table()) { if (spec.data.can_be_encoded_in_rel_rare_table()) {
spec_json.emplace_back((spec.data.data1[0] << 16) | (spec.data.data1[1] << 8) | spec.data.data1[2]); spec_json.emplace_back((spec.data.data1[0] << 16) | (spec.data.data1[1] << 8) | spec.data.data1[2]);
} else { } else {
@@ -461,22 +456,22 @@ JSON RareItemSet::json(shared_ptr<const ItemNameIndex> name_index) const {
} }
for (const auto& enemy_type : enemy_types) { for (const auto& enemy_type : enemy_types) {
if (enemy_type_valid_for_episode(episode, enemy_type)) { if (enemy_type_valid_for_episode(episode, enemy_type)) {
JSON this_spec_json = spec_json; phosg::JSON this_spec_json = spec_json;
collection_dict.emplace(name_for_enum(enemy_type), JSON::list()).first->second->emplace_back(std::move(this_spec_json)); collection_dict.emplace(phosg::name_for_enum(enemy_type), phosg::JSON::list()).first->second->emplace_back(std::move(this_spec_json));
} }
} }
} }
} }
for (size_t area = 0; area < 0x12; area++) { for (size_t area = 0; area < 0x12; area++) {
auto area_list = JSON::list(); auto area_list = phosg::JSON::list();
for (const auto& spec : this->get_box_specs(GameMode::NORMAL, episode, difficulty, section_id, area)) { for (const auto& spec : this->get_box_specs(GameMode::NORMAL, episode, difficulty, section_id, area)) {
if (spec.data.empty()) { if (spec.data.empty()) {
continue; continue;
} }
auto frac = reduce_fraction<uint64_t>(spec.probability, 0x100000000); auto frac = phosg::reduce_fraction<uint64_t>(spec.probability, 0x100000000);
auto spec_json = JSON::list({string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)}); auto spec_json = phosg::JSON::list({phosg::string_printf("%" PRIu64 "/%" PRIu64, frac.first, frac.second)});
if (spec.data.can_be_encoded_in_rel_rare_table()) { if (spec.data.can_be_encoded_in_rel_rare_table()) {
spec_json.emplace_back((spec.data.data1[0] << 16) | (spec.data.data1[1] << 8) | spec.data.data1[2]); spec_json.emplace_back((spec.data.data1[0] << 16) | (spec.data.data1[1] << 8) | spec.data.data1[2]);
} else { } else {
@@ -490,7 +485,7 @@ JSON RareItemSet::json(shared_ptr<const ItemNameIndex> name_index) const {
if (!area_list.empty()) { if (!area_list.empty()) {
collection_dict.emplace( collection_dict.emplace(
string_printf("Box-%s", name_for_floor(episode, area)), phosg::string_printf("Box-%s", name_for_floor(episode, area)),
std::move(area_list)); std::move(area_list));
} }
} }
@@ -549,7 +544,7 @@ void RareItemSet::print_collection(
string enemy_types_str; string enemy_types_str;
const auto& enemy_types = enemy_types_for_rare_table_index(episode, z); const auto& enemy_types = enemy_types_for_rare_table_index(episode, z);
for (EnemyType enemy_type : enemy_types) { for (EnemyType enemy_type : enemy_types) {
enemy_types_str += name_for_enum(enemy_type); enemy_types_str += phosg::name_for_enum(enemy_type);
enemy_types_str.push_back(','); enemy_types_str.push_back(',');
} }
if (!enemy_types_str.empty()) { if (!enemy_types_str.empty()) {
+11 -12
View File
@@ -29,7 +29,7 @@ public:
RareItemSet(const AFSArchive& afs, bool is_v1); RareItemSet(const AFSArchive& afs, bool is_v1);
RareItemSet(const GSLArchive& gsl, bool is_big_endian); RareItemSet(const GSLArchive& gsl, bool is_big_endian);
RareItemSet(const std::string& rel, bool is_big_endian); RareItemSet(const std::string& rel, bool is_big_endian);
RareItemSet(const JSON& json, std::shared_ptr<const ItemNameIndex> name_index = nullptr); RareItemSet(const phosg::JSON& json, std::shared_ptr<const ItemNameIndex> name_index = nullptr);
~RareItemSet() = default; ~RareItemSet() = default;
std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const; std::vector<ExpandedDrop> get_enemy_specs(GameMode mode, Episode episode, uint8_t difficulty, uint8_t secid, uint8_t rt_index) const;
@@ -37,7 +37,7 @@ public:
std::string serialize_afs(bool is_v1) const; std::string serialize_afs(bool is_v1) const;
std::string serialize_gsl(bool big_endian) const; std::string serialize_gsl(bool big_endian) const;
JSON json(std::shared_ptr<const ItemNameIndex> name_index = nullptr) const; phosg::JSON json(std::shared_ptr<const ItemNameIndex> name_index = nullptr) const;
void multiply_all_rates(double factor); void multiply_all_rates(double factor);
@@ -66,13 +66,12 @@ protected:
ExpandedDrop expand() const; ExpandedDrop expand() const;
} __packed_ws__(PackedDrop, 4); } __packed_ws__(PackedDrop, 4);
template <bool IsBigEndian> template <bool BE>
struct OffsetsT { struct OffsetsT {
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type; /* 00 */ U32T<BE> monster_rares_offset; // -> parray<PackedDrop, 0x65> (or 0x33 on v1)
/* 00 */ U32T monster_rares_offset; // -> parray<PackedDrop, 0x65> (or 0x33 on v1) /* 04 */ U32T<BE> box_count; // Usually 30 (0x1E)
/* 04 */ U32T box_count; // Usually 30 (0x1E) /* 08 */ U32T<BE> box_areas_offset; // -> parray<uint8_t, 0x1E>
/* 08 */ U32T box_areas_offset; // -> parray<uint8_t, 0x1E> /* 0C */ U32T<BE> box_rares_offset; // -> parray<PackedDrop, 0x1E>
/* 0C */ U32T box_rares_offset; // -> parray<PackedDrop, 0x1E>
/* 10 */ /* 10 */
} __packed__; } __packed__;
using Offsets = OffsetsT<false>; using Offsets = OffsetsT<false>;
@@ -89,13 +88,13 @@ protected:
std::vector<BoxRare> box_rares; std::vector<BoxRare> box_rares;
ParsedRELData() = default; ParsedRELData() = default;
ParsedRELData(StringReader r, bool big_endian, bool is_v1); ParsedRELData(phosg::StringReader r, bool big_endian, bool is_v1);
explicit ParsedRELData(const SpecCollection& collection); explicit ParsedRELData(const SpecCollection& collection);
std::string serialize(bool big_endian, bool is_v1) const; std::string serialize(bool big_endian, bool is_v1) const;
template <bool IsBigEndian> template <bool BE>
void parse_t(StringReader r, bool is_v1); void parse_t(phosg::StringReader r, bool is_v1);
template <bool IsBigEndian> template <bool BE>
std::string serialize_t(bool is_v1) const; std::string serialize_t(bool is_v1) const;
SpecCollection as_collection() const; SpecCollection as_collection() const;
+52 -54
View File
@@ -311,7 +311,7 @@ static void send_main_menu(shared_ptr<Client> c) {
} }
} }
} }
return string_printf( return phosg::string_printf(
"$C6%zu$C7 players online\n$C6%zu$C7 games\n$C6%zu$C7 compatible games", "$C6%zu$C7 players online\n$C6%zu$C7 games\n$C6%zu$C7 compatible games",
num_players, num_games, num_compatible_games); num_players, num_games, num_compatible_games);
}, },
@@ -472,7 +472,7 @@ void on_disconnect(shared_ptr<Client> c) {
static void on_1D(shared_ptr<Client> c, uint16_t, uint32_t, string&) { static void on_1D(shared_ptr<Client> c, uint16_t, uint32_t, string&) {
if (c->ping_start_time) { if (c->ping_start_time) {
uint64_t ping_usecs = now() - c->ping_start_time; uint64_t ping_usecs = phosg::now() - c->ping_start_time;
c->ping_start_time = 0; c->ping_start_time = 0;
double ping_ms = static_cast<double>(ping_usecs) / 1000.0; double ping_ms = static_cast<double>(ping_usecs) / 1000.0;
send_text_message_printf(c, "To server: %gms", ping_ms); send_text_message_printf(c, "To server: %gms", ping_ms);
@@ -1065,12 +1065,12 @@ static void on_93_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
c->config.parse_from(config_data); c->config.parse_from(config_data);
} else { } else {
string version_string = config_data.as_string(); string version_string = config_data.as_string();
strip_trailing_zeroes(version_string); phosg::strip_trailing_zeroes(version_string);
// If the version string starts with "Ver.", assume it's Sega and apply the // If the version string starts with "Ver.", assume it's Sega and apply the
// normal version encoding logic. Otherwise, assume it's a community mod, // normal version encoding logic. Otherwise, assume it's a community mod,
// almost all of which are based on TethVer12513, so assume that version // almost all of which are based on TethVer12513, so assume that version
// otherwise. // otherwise.
if (starts_with(version_string, "Ver.")) { if (phosg::starts_with(version_string, "Ver.")) {
// Basic algorithm: take all numeric characters from the version string // Basic algorithm: take all numeric characters from the version string
// and ignore everything else. Treat that as a decimal integer, then // and ignore everything else. Treat that as a decimal integer, then
// base36-encode it into the low 3 bytes of specific_version. // base36-encode it into the low 3 bytes of specific_version.
@@ -1112,7 +1112,7 @@ static void on_93_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
// files replaced with English text/graphics/etc. For this reason, it still // files replaced with English text/graphics/etc. For this reason, it still
// reports its language as Japanese, so we have to account for that // reports its language as Japanese, so we have to account for that
// manually here. // manually here.
if (starts_with(version_string, "TethVer")) { if (phosg::starts_with(version_string, "TethVer")) {
c->log.info("Client is TethVer subtype; forcing English language"); c->log.info("Client is TethVer subtype; forcing English language");
c->config.set_flag(Client::Flag::FORCE_ENGLISH_LANGUAGE_BB); c->config.set_flag(Client::Flag::FORCE_ENGLISH_LANGUAGE_BB);
} }
@@ -1142,8 +1142,8 @@ static void on_93_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
// The BB data server protocol is fairly well-understood and has some large // The BB data server protocol is fairly well-understood and has some large
// commands, so we omit data logging for clients on the data server. // commands, so we omit data logging for clients on the data server.
c->log.info("Client is in the BB data server phase; disabling command data logging for the rest of this client\'s session"); c->log.info("Client is in the BB data server phase; disabling command data logging for the rest of this client\'s session");
c->channel.terminal_recv_color = TerminalFormat::END; c->channel.terminal_recv_color = phosg::TerminalFormat::END;
c->channel.terminal_send_color = TerminalFormat::END; c->channel.terminal_send_color = phosg::TerminalFormat::END;
} }
} }
@@ -1273,7 +1273,7 @@ static bool add_next_game_client(shared_ptr<Lobby> l) {
state_cmd.state.tournament_flag = 0x01; state_cmd.state.tournament_flag = 0x01;
state_cmd.state.client_sc_card_types.clear(Episode3::CardType::INVALID_FF); state_cmd.state.client_sc_card_types.clear(Episode3::CardType::INVALID_FF);
if ((c->version() != Version::GC_EP3_NTE) && !(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) { if ((c->version() != Version::GC_EP3_NTE) && !(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) {
uint8_t mask_key = (random_object<uint32_t>() % 0xFF) + 1; uint8_t mask_key = (phosg::random_object<uint32_t>() % 0xFF) + 1;
set_mask_for_ep3_game_command(&state_cmd, sizeof(state_cmd), mask_key); set_mask_for_ep3_game_command(&state_cmd, sizeof(state_cmd), mask_key);
} }
send_command_t(c, 0xC9, 0x00, state_cmd); send_command_t(c, 0xC9, 0x00, state_cmd);
@@ -1461,7 +1461,7 @@ static bool start_ep3_battle_table_game_if_ready(shared_ptr<Lobby> l, int16_t ta
send_self_leave_notification(other_c); send_self_leave_notification(other_c);
string message; string message;
if (tourn) { if (tourn) {
message = string_printf( message = phosg::string_printf(
"$C7Waiting to begin match in tournament\n$C6%s$C7...\n\n(Hold B+X+START to abort)", "$C7Waiting to begin match in tournament\n$C6%s$C7...\n\n(Hold B+X+START to abort)",
tourn->get_name().c_str()); tourn->get_name().c_str());
} else { } else {
@@ -1632,8 +1632,8 @@ static void on_CA_Ep3(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
} catch (const exception& e) { } catch (const exception& e) {
c->log.error("Episode 3 engine returned an error: %s", e.what()); c->log.error("Episode 3 engine returned an error: %s", e.what());
if (l->battle_record) { if (l->battle_record) {
string filename = string_printf("system/ep3/battle-records/exc.%" PRIu64 ".mzrd", now()); string filename = phosg::string_printf("system/ep3/battle-records/exc.%" PRIu64 ".mzrd", phosg::now());
save_file(filename, l->battle_record->serialize()); phosg::save_file(filename, l->battle_record->serialize());
c->log.error("Saved partial battle record as %s", filename.c_str()); c->log.error("Saved partial battle record as %s", filename.c_str());
} }
throw; throw;
@@ -1832,7 +1832,7 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
if (game_c.get()) { if (game_c.get()) {
auto player = game_c->character(); auto player = game_c->character();
string name = escape_player_name(player->disp.name.decode(game_c->language())); string name = escape_player_name(player->disp.name.decode(game_c->language()));
info += string_printf("%s\n %s Lv%" PRIu32 " %c\n", info += phosg::string_printf("%s\n %s Lv%" PRIu32 " %c\n",
name.c_str(), name.c_str(),
name_for_char_class(player->disp.visual.char_class), name_for_char_class(player->disp.visual.char_class),
player->disp.stats.level + 1, player->disp.stats.level + 1,
@@ -1845,15 +1845,15 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
// time, send page 2 (extended info) // time, send page 2 (extended info)
if (info.empty()) { if (info.empty()) {
c->last_game_info_requested = 0; c->last_game_info_requested = 0;
info += string_printf("Section ID: %s\n", name_for_section_id(game->effective_section_id())); info += phosg::string_printf("Section ID: %s\n", name_for_section_id(game->effective_section_id()));
if (game->max_level != 0xFFFFFFFF) { if (game->max_level != 0xFFFFFFFF) {
info += string_printf("Req. level: %" PRIu32 "-%" PRIu32 "\n", game->min_level + 1, game->max_level + 1); info += phosg::string_printf("Req. level: %" PRIu32 "-%" PRIu32 "\n", game->min_level + 1, game->max_level + 1);
} else if (game->min_level != 0) { } else if (game->min_level != 0) {
info += string_printf("Req. level: %" PRIu32 "+\n", game->min_level + 1); info += phosg::string_printf("Req. level: %" PRIu32 "+\n", game->min_level + 1);
} }
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) { if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
info += string_printf("%s\n", name_for_enum(game->base_version)); info += phosg::string_printf("%s\n", phosg::name_for_enum(game->base_version));
} }
if (game->check_flag(Lobby::Flag::CHEATS_ENABLED)) { if (game->check_flag(Lobby::Flag::CHEATS_ENABLED)) {
@@ -1893,7 +1893,7 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
break; break;
} }
} }
strip_trailing_whitespace(info); phosg::strip_trailing_whitespace(info);
send_ship_info(c, info); send_ship_info(c, info);
} }
break; break;
@@ -1928,13 +1928,13 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
if (team_name.empty()) { if (team_name.empty()) {
message = "(No registrant)"; message = "(No registrant)";
} else if (team->max_players == 1) { } else if (team->max_players == 1) {
message = string_printf("$C6%s$C7\n%zu %s (%s)\nPlayers:", message = phosg::string_printf("$C6%s$C7\n%zu %s (%s)\nPlayers:",
team_name.c_str(), team_name.c_str(),
team->num_rounds_cleared, team->num_rounds_cleared,
team->num_rounds_cleared == 1 ? "win" : "wins", team->num_rounds_cleared == 1 ? "win" : "wins",
team->is_active ? "active" : "defeated"); team->is_active ? "active" : "defeated");
} else { } else {
message = string_printf("$C6%s$C7\n%zu %s (%s)%s\nPlayers:", message = phosg::string_printf("$C6%s$C7\n%zu %s (%s)%s\nPlayers:",
team_name.c_str(), team_name.c_str(),
team->num_rounds_cleared, team->num_rounds_cleared,
team->num_rounds_cleared == 1 ? "win" : "wins", team->num_rounds_cleared == 1 ? "win" : "wins",
@@ -1944,15 +1944,15 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
for (const auto& player : team->players) { for (const auto& player : team->players) {
if (player.is_human()) { if (player.is_human()) {
if (player.player_name.empty()) { if (player.player_name.empty()) {
message += string_printf("\n $C6%08" PRIX32 "$C7", player.account_id); message += phosg::string_printf("\n $C6%08" PRIX32 "$C7", player.account_id);
} else { } else {
string player_name = escape_player_name(player.player_name); string player_name = escape_player_name(player.player_name);
message += string_printf("\n $C6%s$C7 (%08" PRIX32 ")", player_name.c_str(), player.account_id); message += phosg::string_printf("\n $C6%s$C7 (%08" PRIX32 ")", player_name.c_str(), player.account_id);
} }
} else { } else {
string player_name = escape_player_name(player.com_deck->player_name); string player_name = escape_player_name(player.com_deck->player_name);
string deck_name = escape_player_name(player.com_deck->deck_name); string deck_name = escape_player_name(player.com_deck->deck_name);
message += string_printf("\n $C3%s \"%s\"$C7", player_name.c_str(), deck_name.c_str()); message += phosg::string_printf("\n $C3%s \"%s\"$C7", player_name.c_str(), deck_name.c_str());
} }
} }
send_ship_info(c, message); send_ship_info(c, message);
@@ -2427,7 +2427,7 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
send_ep3_confirm_tournament_entry(c, nullptr); send_ep3_confirm_tournament_entry(c, nullptr);
} }
c->config.proxy_destination_address = resolve_ipv4(dest->first); c->config.proxy_destination_address = phosg::resolve_ipv4(dest->first);
c->config.proxy_destination_port = dest->second; c->config.proxy_destination_port = dest->second;
if (c->config.check_flag(Client::Flag::SHOULD_SEND_ENABLE_SAVE)) { if (c->config.check_flag(Client::Flag::SHOULD_SEND_ENABLE_SAVE)) {
c->should_send_to_proxy_server = true; c->should_send_to_proxy_server = true;
@@ -2496,13 +2496,13 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
send_lobby_message_box(c, "$C7Incorrect password."); send_lobby_message_box(c, "$C7Incorrect password.");
break; break;
case Lobby::JoinError::LEVEL_TOO_LOW: { case Lobby::JoinError::LEVEL_TOO_LOW: {
string msg = string_printf("$C7You must be level\n%zu or above to\njoin this game.", string msg = phosg::string_printf("$C7You must be level\n%zu or above to\njoin this game.",
static_cast<size_t>(game->min_level + 1)); static_cast<size_t>(game->min_level + 1));
send_lobby_message_box(c, msg); send_lobby_message_box(c, msg);
break; break;
} }
case Lobby::JoinError::LEVEL_TOO_HIGH: { case Lobby::JoinError::LEVEL_TOO_HIGH: {
string msg = string_printf("$C7You must be level\n%zu or below to\njoin this game.", string msg = phosg::string_printf("$C7You must be level\n%zu or below to\njoin this game.",
static_cast<size_t>(game->max_level + 1)); static_cast<size_t>(game->max_level + 1));
send_lobby_message_box(c, msg); send_lobby_message_box(c, msg);
break; break;
@@ -2684,7 +2684,7 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
} }
if (team_name.empty()) { if (team_name.empty()) {
team_name = c->character()->disp.name.decode(c->language()); team_name = c->character()->disp.name.decode(c->language());
team_name += string_printf("/%" PRIX32, c->login->account->account_id); team_name += phosg::string_printf("/%" PRIX32, c->login->account->account_id);
} }
auto s = c->require_server_state(); auto s = c->require_server_state();
uint16_t tourn_num = item_id >> 16; uint16_t tourn_num = item_id >> 16;
@@ -2697,7 +2697,7 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
team->register_player(c, team_name, password); team->register_player(c, team_name, password);
c->ep3_tournament_team = team; c->ep3_tournament_team = team;
tourn->send_all_state_updates(); tourn->send_all_state_updates();
string message = string_printf("$C7You are registered in $C6%s$C7.\n\ string message = phosg::string_printf("$C7You are registered in $C6%s$C7.\n\
\n\ \n\
After the tournament begins, start your matches\n\ After the tournament begins, start your matches\n\
by standing at any Battle Table along with your\n\ by standing at any Battle Table along with your\n\
@@ -2708,7 +2708,7 @@ partner (if any) and opponent(s).",
s->ep3_tournament_index->save(); s->ep3_tournament_index->save();
} catch (const exception& e) { } catch (const exception& e) {
string message = string_printf("Cannot join team:\n%s", e.what()); string message = phosg::string_printf("Cannot join team:\n%s", e.what());
send_lobby_message_box(c, message); send_lobby_message_box(c, message);
} }
} else { } else {
@@ -2845,7 +2845,7 @@ static void send_dol_file_chunk(shared_ptr<Client> c, uint32_t start_addr) {
send_function_call(c, fn, label_writes, data_to_send.data(), data_to_send.size()); send_function_call(c, fn, label_writes, data_to_send.data(), data_to_send.size());
size_t progress_percent = ((offset + bytes_to_send) * 100) / c->loading_dol_file->data.size(); size_t progress_percent = ((offset + bytes_to_send) * 100) / c->loading_dol_file->data.size();
send_ship_info(c, string_printf("%zu%%%%", progress_percent)); send_ship_info(c, phosg::string_printf("%zu%%%%", progress_percent));
} }
static void on_B3(shared_ptr<Client> c, uint16_t, uint32_t flag, string& data) { static void on_B3(shared_ptr<Client> c, uint16_t, uint32_t flag, string& data) {
@@ -2995,7 +2995,7 @@ static void on_AA(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
static void on_D7_GC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) { static void on_D7_GC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
string filename(data); string filename(data);
strip_trailing_zeroes(filename); phosg::strip_trailing_zeroes(filename);
if (filename.find('/') != string::npos) { if (filename.find('/') != string::npos) {
send_command(c, 0xD7, 0x00); send_command(c, 0xD7, 0x00);
} else { } else {
@@ -3005,19 +3005,17 @@ static void on_D7_GC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
send_open_quest_file(c, "", filename, "", 0, QuestFileType::GBA_DEMO, f->data); send_open_quest_file(c, "", filename, "", 0, QuestFileType::GBA_DEMO, f->data);
} catch (const out_of_range&) { } catch (const out_of_range&) {
send_command(c, 0xD7, 0x00); send_command(c, 0xD7, 0x00);
} catch (const cannot_open_file&) { } catch (const phosg::cannot_open_file&) {
send_command(c, 0xD7, 0x00); send_command(c, 0xD7, 0x00);
} }
} }
} }
static void on_13_A7_GC(shared_ptr<Client> c, uint16_t command, uint32_t flag, string& data) { static void on_13_A7_V3_V4(shared_ptr<Client> c, uint16_t command, uint32_t flag, string& data) {
// See comment in send_open_quest_file about why we only have logic here for
// GC clients, and ignore this command on all other versions
const auto& cmd = check_size_t<C_WriteFileConfirmation_V3_BB_13_A7>(data); const auto& cmd = check_size_t<C_WriteFileConfirmation_V3_BB_13_A7>(data);
bool is_download_quest = (command == 0xA7); bool is_download_quest = (command == 0xA7);
string filename = cmd.filename.decode(); string filename = cmd.filename.decode();
size_t chunk_to_send = flag + GC_QUEST_LOAD_MAX_CHUNKS_IN_FLIGHT; size_t chunk_to_send = flag + V3_V4_QUEST_LOAD_MAX_CHUNKS_IN_FLIGHT;
shared_ptr<const string> file_data; shared_ptr<const string> file_data;
try { try {
@@ -3085,7 +3083,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
c->import_blocked_senders(cmd.blocked_senders); c->import_blocked_senders(cmd.blocked_senders);
if (cmd.auto_reply_enabled) { if (cmd.auto_reply_enabled) {
string auto_reply = data.substr(sizeof(cmd)); string auto_reply = data.substr(sizeof(cmd));
strip_trailing_zeroes(auto_reply); phosg::strip_trailing_zeroes(auto_reply);
if (auto_reply.size() & 1) { if (auto_reply.size() & 1) {
auto_reply.push_back(0); auto_reply.push_back(0);
} }
@@ -3115,7 +3113,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
c->import_blocked_senders(cmd.blocked_senders); c->import_blocked_senders(cmd.blocked_senders);
if (cmd.auto_reply_enabled) { if (cmd.auto_reply_enabled) {
string auto_reply = data.substr(sizeof(cmd), 0xAC); string auto_reply = data.substr(sizeof(cmd), 0xAC);
strip_trailing_zeroes(auto_reply); phosg::strip_trailing_zeroes(auto_reply);
try { try {
string encoded = tt_decode_marked(auto_reply, player->inventory.language, false); string encoded = tt_decode_marked(auto_reply, player->inventory.language, false);
player->auto_reply.encode(encoded, player->inventory.language); player->auto_reply.encode(encoded, player->inventory.language);
@@ -3191,7 +3189,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
c->import_blocked_senders(cmd->blocked_senders); c->import_blocked_senders(cmd->blocked_senders);
if (cmd->auto_reply_enabled) { if (cmd->auto_reply_enabled) {
string auto_reply = data.substr(sizeof(cmd), 0xAC); string auto_reply = data.substr(sizeof(cmd), 0xAC);
strip_trailing_zeroes(auto_reply); phosg::strip_trailing_zeroes(auto_reply);
try { try {
string encoded = tt_decode_marked(auto_reply, player->inventory.language, false); string encoded = tt_decode_marked(auto_reply, player->inventory.language, false);
player->auto_reply.encode(encoded, player->inventory.language); player->auto_reply.encode(encoded, player->inventory.language);
@@ -3217,7 +3215,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
c->import_blocked_senders(cmd.blocked_senders); c->import_blocked_senders(cmd.blocked_senders);
if (cmd.auto_reply_enabled) { if (cmd.auto_reply_enabled) {
string auto_reply = data.substr(sizeof(cmd), 0xAC); string auto_reply = data.substr(sizeof(cmd), 0xAC);
strip_trailing_zeroes(auto_reply); phosg::strip_trailing_zeroes(auto_reply);
if (auto_reply.size() & 1) { if (auto_reply.size() & 1) {
auto_reply.push_back(0); auto_reply.push_back(0);
} }
@@ -3408,7 +3406,7 @@ static void on_6x_C9_CB(shared_ptr<Client> c, uint16_t command, uint32_t flag, s
static void on_06(shared_ptr<Client> c, uint16_t, uint32_t, string& data) { static void on_06(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
const auto& cmd = check_size_t<SC_TextHeader_01_06_11_B0_EE>(data, 0xFFFF); const auto& cmd = check_size_t<SC_TextHeader_01_06_11_B0_EE>(data, 0xFFFF);
string text = data.substr(sizeof(cmd)); string text = data.substr(sizeof(cmd));
strip_trailing_zeroes(text); phosg::strip_trailing_zeroes(text);
if (text.empty()) { if (text.empty()) {
return; return;
} }
@@ -3716,7 +3714,7 @@ static void on_E5_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
try { try {
c->character()->disp.apply_dressing_room(cmd.preview); c->character()->disp.apply_dressing_room(cmd.preview);
} catch (const exception& e) { } catch (const exception& e) {
send_message_box(c, string_printf("$C6Character could not be modified:\n%s", e.what())); send_message_box(c, phosg::string_printf("$C6Character could not be modified:\n%s", e.what()));
return; return;
} }
} else { } else {
@@ -3724,7 +3722,7 @@ static void on_E5_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
auto s = c->require_server_state(); auto s = c->require_server_state();
c->create_character_file(c->login->account->account_id, c->language(), cmd.preview, s->level_table(c->version())); c->create_character_file(c->login->account->account_id, c->language(), cmd.preview, s->level_table(c->version()));
} catch (const exception& e) { } catch (const exception& e) {
send_message_box(c, string_printf("$C6New character could not be created:\n%s", e.what())); send_message_box(c, phosg::string_printf("$C6New character could not be created:\n%s", e.what()));
return; return;
} }
} }
@@ -3881,7 +3879,7 @@ static void on_DF_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string& d
auto& threshold = cp->rank_thresholds[cmd.rank]; auto& threshold = cp->rank_thresholds[cmd.rank];
threshold.bitmask = cmd.rank_bitmask; threshold.bitmask = cmd.rank_bitmask;
threshold.seconds = cmd.seconds; threshold.seconds = cmd.seconds;
string time_str = format_duration(static_cast<uint64_t>(threshold.seconds) * 1000000); string time_str = phosg::format_duration(static_cast<uint64_t>(threshold.seconds) * 1000000);
l->log.info("(Challenge mode) Rank %c threshold set to %s (bitmask %08" PRIX32 ")", l->log.info("(Challenge mode) Rank %c threshold set to %s (bitmask %08" PRIX32 ")",
char_for_challenge_rank(cmd.rank), time_str.c_str(), threshold.bitmask); char_for_challenge_rank(cmd.rank), time_str.c_str(), threshold.bitmask);
break; break;
@@ -3968,18 +3966,18 @@ static void on_choice_search_t(shared_ptr<Client> c, const ChoiceSearchConfig& c
auto& result = results.emplace_back(); auto& result = results.emplace_back();
result.guild_card_number = lc->login->account->account_id; result.guild_card_number = lc->login->account->account_id;
result.name.encode(lp->disp.name.decode(lc->language()), c->language()); result.name.encode(lp->disp.name.decode(lc->language()), c->language());
string info_string = string_printf("%s Lv%zu\n%s\n", string info_string = phosg::string_printf("%s Lv%zu\n%s\n",
name_for_char_class(lp->disp.visual.char_class), name_for_char_class(lp->disp.visual.char_class),
static_cast<size_t>(lp->disp.stats.level + 1), static_cast<size_t>(lp->disp.stats.level + 1),
name_for_section_id(lp->disp.visual.section_id)); name_for_section_id(lp->disp.visual.section_id));
result.info_string.encode(info_string, c->language()); result.info_string.encode(info_string, c->language());
string location_string; string location_string;
if (l->is_game()) { if (l->is_game()) {
location_string = string_printf("%s,,BLOCK01,%s", l->name.c_str(), s->name.c_str()); location_string = phosg::string_printf("%s,,BLOCK01,%s", l->name.c_str(), s->name.c_str());
} else if (l->is_ep3()) { } else if (l->is_ep3()) {
location_string = string_printf("BLOCK01-C%02" PRIu32 ",,BLOCK01,%s", l->lobby_id - 15, s->name.c_str()); location_string = phosg::string_printf("BLOCK01-C%02" PRIu32 ",,BLOCK01,%s", l->lobby_id - 15, s->name.c_str());
} else { } else {
location_string = string_printf("BLOCK01-%02" PRIu32 ",,BLOCK01,%s", l->lobby_id, s->name.c_str()); location_string = phosg::string_printf("BLOCK01-%02" PRIu32 ",,BLOCK01,%s", l->lobby_id, s->name.c_str());
} }
result.location_string.encode(location_string, c->language()); result.location_string.encode(location_string, c->language());
result.reconnect_command_header.command = 0x19; result.reconnect_command_header.command = 0x19;
@@ -4133,7 +4131,7 @@ static void on_D8(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
} }
void on_D9(shared_ptr<Client> c, uint16_t, uint32_t, string& data) { void on_D9(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
strip_trailing_zeroes(data); phosg::strip_trailing_zeroes(data);
bool is_w = uses_utf16(c->version()); bool is_w = uses_utf16(c->version());
if (is_w && (data.size() & 1)) { if (is_w && (data.size() & 1)) {
data.push_back(0); data.push_back(0);
@@ -4146,7 +4144,7 @@ void on_D9(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
} }
void on_C7(shared_ptr<Client> c, uint16_t, uint32_t, string& data) { void on_C7(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
strip_trailing_zeroes(data); phosg::strip_trailing_zeroes(data);
bool is_w = uses_utf16(c->version()); bool is_w = uses_utf16(c->version());
if (is_w && (data.size() & 1)) { if (is_w && (data.size() & 1)) {
data.push_back(0); data.push_back(0);
@@ -4218,7 +4216,7 @@ shared_ptr<Lobby> create_game_generic(
if (!c->login->account->check_flag(Account::Flag::FREE_JOIN_GAMES) && (min_level > p->disp.stats.level)) { if (!c->login->account->check_flag(Account::Flag::FREE_JOIN_GAMES) && (min_level > p->disp.stats.level)) {
// Note: We don't throw here because this is a situation players might // Note: We don't throw here because this is a situation players might
// actually encounter while playing the game normally // actually encounter while playing the game normally
string msg = string_printf("You must be level %zu\nor above to play\nthis difficulty.", static_cast<size_t>(min_level + 1)); string msg = phosg::string_printf("You must be level %zu\nor above to play\nthis difficulty.", static_cast<size_t>(min_level + 1));
send_lobby_message_box(c, msg); send_lobby_message_box(c, msg);
return nullptr; return nullptr;
} }
@@ -4664,7 +4662,7 @@ static void on_6F(shared_ptr<Client> c, uint16_t command, uint32_t, string& data
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) { if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
string variations_str; string variations_str;
for (size_t z = 0; z < l->variations.size(); z++) { for (size_t z = 0; z < l->variations.size(); z++) {
variations_str += string_printf("%" PRIX32, l->variations[z].load()); variations_str += phosg::string_printf("%" PRIX32, l->variations[z].load());
} }
send_text_message_printf(c, "Rare seed: %08" PRIX32 "\nRare enemies: %zu\nVariations: %s\n", send_text_message_printf(c, "Rare seed: %08" PRIX32 "\nRare enemies: %zu\nVariations: %s\n",
l->random_seed, l->map->rare_enemy_indexes.size(), variations_str.c_str()); l->random_seed, l->map->rare_enemy_indexes.size(), variations_str.c_str());
@@ -5147,7 +5145,7 @@ static void on_EA_BB(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
if (team) { if (team) {
check_size_v(data.size(), sizeof(SC_TeamChat_BB_07EA) + 4, 0xFFFF); check_size_v(data.size(), sizeof(SC_TeamChat_BB_07EA) + 4, 0xFFFF);
static const string required_end("\0\0", 2); static const string required_end("\0\0", 2);
if (ends_with(data, required_end)) { if (phosg::ends_with(data, required_end)) {
for (const auto& it : team->members) { for (const auto& it : team->members) {
try { try {
auto target_c = s->find_client(nullptr, it.second.account_id); auto target_c = s->find_client(nullptr, it.second.account_id);
@@ -5383,7 +5381,7 @@ static on_command_t handlers[0x100][NUM_NON_PATCH_VERSIONS] = {
/* 10 */ {on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10}, /* 10 */ {on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10, on_10},
/* 11 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 11 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 12 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 12 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 13 */ {on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_13_A7_GC, on_13_A7_GC, on_13_A7_GC, on_13_A7_GC, on_ignored, on_ignored}, /* 13 */ {on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4},
/* 14 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 14 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 15 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 15 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 16 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 16 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
@@ -5540,7 +5538,7 @@ static on_command_t handlers[0x100][NUM_NON_PATCH_VERSIONS] = {
/* A4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* A4 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* A5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* A5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* A6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, nullptr}, /* A6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_ignored, on_ignored, on_ignored, on_ignored, on_ignored, nullptr},
/* A7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_13_A7_GC, on_13_A7_GC, on_13_A7_GC, on_13_A7_GC, on_ignored, nullptr}, /* A7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4, on_13_A7_V3_V4},
/* A8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* A8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* A9 */ {on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9}, /* A9 */ {on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9, on_A9},
/* AA */ {nullptr, nullptr, nullptr, nullptr, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA}, /* AA */ {nullptr, nullptr, nullptr, nullptr, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA, on_AA},
+50 -50
View File
@@ -364,7 +364,7 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) { if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
c->log.info("Decompressed sync data (%zX -> %zX bytes; expected %zX):", c->log.info("Decompressed sync data (%zX -> %zX bytes; expected %zX):",
compressed_size, decompressed.size(), decompressed_size); compressed_size, decompressed.size(), decompressed_size);
print_data(stderr, decompressed); phosg::print_data(stderr, decompressed);
} }
switch (subcommand_def->final_subcommand) { switch (subcommand_def->final_subcommand) {
@@ -372,7 +372,7 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
auto l = c->require_lobby(); auto l = c->require_lobby();
if (l->map) { if (l->map) {
l->log.info("Checking client enemy state against server state"); l->log.info("Checking client enemy state against server state");
StringReader r(decompressed); phosg::StringReader r(decompressed);
size_t count = r.size() / sizeof(G_SyncEnemyState_6x6B_Entry_Decompressed); size_t count = r.size() / sizeof(G_SyncEnemyState_6x6B_Entry_Decompressed);
if (count != l->map->enemies.size()) { if (count != l->map->enemies.size()) {
l->log.warning("Enemy count from client (%zu) does not match enemy count from map (%zu)", l->log.warning("Enemy count from client (%zu) does not match enemy count from map (%zu)",
@@ -410,7 +410,7 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
auto l = c->require_lobby(); auto l = c->require_lobby();
if (l->map) { if (l->map) {
l->log.info("Checking client object state against server state"); l->log.info("Checking client object state against server state");
StringReader r(decompressed); phosg::StringReader r(decompressed);
size_t count = r.size() / sizeof(G_SyncObjectState_6x6C_Entry_Decompressed); size_t count = r.size() / sizeof(G_SyncObjectState_6x6C_Entry_Decompressed);
if (count > l->map->objects.size()) { if (count > l->map->objects.size()) {
l->log.warning("Object count from client (%zu) exceeds object count from map (%zu)", l->log.warning("Object count from client (%zu) exceeds object count from map (%zu)",
@@ -446,7 +446,7 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
case 0x6D: { case 0x6D: {
if (decompressed.size() < sizeof(G_SyncItemState_6x6D_Decompressed)) { if (decompressed.size() < sizeof(G_SyncItemState_6x6D_Decompressed)) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"decompressed 6x6D data (0x%zX bytes) is too short for header (0x%zX bytes)", "decompressed 6x6D data (0x%zX bytes) is too short for header (0x%zX bytes)",
decompressed.size(), sizeof(G_SyncItemState_6x6D_Decompressed))); decompressed.size(), sizeof(G_SyncItemState_6x6D_Decompressed)));
} }
@@ -459,7 +459,7 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
size_t required_size = sizeof(G_SyncItemState_6x6D_Decompressed) + num_floor_items * sizeof(FloorItem); size_t required_size = sizeof(G_SyncItemState_6x6D_Decompressed) + num_floor_items * sizeof(FloorItem);
if (decompressed.size() < required_size) { if (decompressed.size() < required_size) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"decompressed 6x6D data (0x%zX bytes) is too short for all floor items (0x%zX bytes)", "decompressed 6x6D data (0x%zX bytes) is too short for all floor items (0x%zX bytes)",
decompressed.size(), required_size)); decompressed.size(), required_size));
} }
@@ -486,7 +486,7 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
break; break;
} }
case 0x6E: { case 0x6E: {
StringReader r(decompressed); phosg::StringReader r(decompressed);
const auto& dec_header = r.get<G_SyncSetFlagState_6x6E_Decompressed>(); const auto& dec_header = r.get<G_SyncSetFlagState_6x6E_Decompressed>();
if (dec_header.total_size != dec_header.entity_set_flags_size + dec_header.event_set_flags_size + dec_header.switch_flags_size) { if (dec_header.total_size != dec_header.entity_set_flags_size + dec_header.event_set_flags_size + dec_header.switch_flags_size) {
throw runtime_error("incorrect size fields in 6x6E header"); throw runtime_error("incorrect size fields in 6x6E header");
@@ -496,12 +496,12 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
if (l->map) { if (l->map) {
l->log.info("Checking client set flag state against server state"); l->log.info("Checking client set flag state against server state");
StringReader set_flags_r = r.sub(r.where(), dec_header.entity_set_flags_size); phosg::StringReader set_flags_r = r.sub(r.where(), dec_header.entity_set_flags_size);
const auto& set_flags_header = set_flags_r.get<G_SyncSetFlagState_6x6E_Decompressed::EntitySetFlags>(); const auto& set_flags_header = set_flags_r.get<G_SyncSetFlagState_6x6E_Decompressed::EntitySetFlags>();
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) { if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
c->log.info("Set flags data:"); c->log.info("Set flags data:");
print_data(stderr, set_flags_r.all()); phosg::print_data(stderr, set_flags_r.all());
} }
if (set_flags_header.num_object_sets > l->map->objects.size()) { if (set_flags_header.num_object_sets > l->map->objects.size()) {
@@ -539,10 +539,10 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
} }
} }
StringReader event_set_flags_r = r.sub(r.where() + dec_header.entity_set_flags_size, dec_header.event_set_flags_size); phosg::StringReader event_set_flags_r = r.sub(r.where() + dec_header.entity_set_flags_size, dec_header.event_set_flags_size);
if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) { if (c->config.check_flag(Client::Flag::DEBUG_ENABLED)) {
c->log.info("Event flags data:"); c->log.info("Event flags data:");
print_data(stderr, event_set_flags_r.all()); phosg::print_data(stderr, event_set_flags_r.all());
} }
size_t num_event_flags = event_set_flags_r.size() / sizeof(le_uint16_t); size_t num_event_flags = event_set_flags_r.size() / sizeof(le_uint16_t);
if (num_event_flags != l->map->events.size()) { if (num_event_flags != l->map->events.size()) {
@@ -571,7 +571,7 @@ static void on_sync_joining_player_compressed_state(shared_ptr<Client> c, uint8_
l->log.info("Switch flags size matches expected size (0x%zX)", expected_switch_flags_size); l->log.info("Switch flags size matches expected size (0x%zX)", expected_switch_flags_size);
} }
if (l->switch_flags) { if (l->switch_flags) {
StringReader switch_flags_r = r.sub(r.where() + dec_header.entity_set_flags_size + dec_header.event_set_flags_size); phosg::StringReader switch_flags_r = r.sub(r.where() + dec_header.entity_set_flags_size + dec_header.event_set_flags_size);
for (size_t floor = 0; floor < expected_switch_flag_num_floors; floor++) { for (size_t floor = 0; floor < expected_switch_flag_num_floors; floor++) {
// There is a bug in most (perhaps all) versions of the game, which // There is a bug in most (perhaps all) versions of the game, which
// causes this array to be too small. It looks like Sega forgot to // causes this array to be too small. It looks like Sega forgot to
@@ -948,7 +948,7 @@ G_SyncPlayerDispAndInventory_BB_6x70 Parsed6x70Data::as_bb(shared_ptr<ServerStat
G_SyncPlayerDispAndInventory_BB_6x70 ret; G_SyncPlayerDispAndInventory_BB_6x70 ret;
ret.base = this->base_v1(); ret.base = this->base_v1();
ret.name.encode(this->name, language); ret.name.encode(this->name, language);
ret.base.visual.name.encode(string_printf("%10" PRId32, this->guild_card_number), language); ret.base.visual.name.encode(phosg::string_printf("%10" PRId32, this->guild_card_number), language);
ret.stats = this->stats; ret.stats = this->stats;
ret.num_items = this->num_items; ret.num_items = this->num_items;
ret.items = this->items; ret.items = this->items;
@@ -1202,7 +1202,7 @@ static void on_ep3_battle_subs(shared_ptr<Client> c, uint8_t command, uint8_t fl
} }
if (!(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING) && (c->version() != Version::GC_EP3_NTE)) { if (!(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING) && (c->version() != Version::GC_EP3_NTE)) {
set_mask_for_ep3_game_command(data.data(), data.size(), (random_object<uint32_t>() % 0xFF) + 1); set_mask_for_ep3_game_command(data.data(), data.size(), (phosg::random_object<uint32_t>() % 0xFF) + 1);
} }
forward_subcommand(c, command, flag, data.data(), data.size()); forward_subcommand(c, command, flag, data.data(), data.size());
@@ -1267,9 +1267,9 @@ static void on_symbol_chat(shared_ptr<Client> c, uint8_t command, uint8_t flag,
} }
} }
template <bool SenderIsBigEndian> template <bool SenderBE>
static void on_word_select_t(shared_ptr<Client> c, uint8_t command, uint8_t, void* data, size_t size) { static void on_word_select_t(shared_ptr<Client> c, uint8_t command, uint8_t, void* data, size_t size) {
const auto& cmd = check_size_t<G_WordSelectT_6x74<SenderIsBigEndian>>(data, size); const auto& cmd = check_size_t<G_WordSelectT_6x74<SenderBE>>(data, size);
if (c->can_chat && (cmd.client_id == c->lobby_client_id)) { if (c->can_chat && (cmd.client_id == c->lobby_client_id)) {
if (command_is_private(command)) { if (command_is_private(command)) {
return; return;
@@ -1695,7 +1695,7 @@ static void on_player_drop_item(shared_ptr<Client> c, uint8_t command, uint8_t f
auto item = p->remove_item(cmd.item_id, 0, *s->item_stack_limits(c->version())); auto item = p->remove_item(cmd.item_id, 0, *s->item_stack_limits(c->version()));
l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F); l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto s = c->require_server_state(); auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu dropped item %08" PRIX32 " (%s) at %hu:(%g, %g)", l->log.info("Player %hu dropped item %08" PRIX32 " (%s) at %hu:(%g, %g)",
@@ -1764,7 +1764,7 @@ static void on_create_inventory_item_t(shared_ptr<Client> c, uint8_t command, ui
return; return;
} }
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu created inventory item %08" PRIX32 " (%s) in inventory of NPC %02hX; ignoring", c->lobby_client_id, item.id.load(), name.c_str(), cmd.header.client_id.load()); l->log.info("Player %hu created inventory item %08" PRIX32 " (%s) in inventory of NPC %02hX; ignoring", c->lobby_client_id, item.id.load(), name.c_str(), cmd.header.client_id.load());
} }
@@ -1772,7 +1772,7 @@ static void on_create_inventory_item_t(shared_ptr<Client> c, uint8_t command, ui
} else { } else {
c->character()->add_item(item, *s->item_stack_limits(c->version())); c->character()->add_item(item, *s->item_stack_limits(c->version()));
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu created inventory item %08" PRIX32 " (%s)", c->lobby_client_id, item.id.load(), name.c_str()); l->log.info("Player %hu created inventory item %08" PRIX32 " (%s)", c->lobby_client_id, item.id.load(), name.c_str());
c->print_inventory(stderr); c->print_inventory(stderr);
@@ -1812,7 +1812,7 @@ static void on_drop_partial_stack_t(shared_ptr<Client> c, uint8_t command, uint8
l->on_item_id_generated_externally(item.id); l->on_item_id_generated_externally(item.id);
l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F); l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto s = c->require_server_state(); auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu split stack to create floor item %08" PRIX32 " (%s) at %hu:(%g, %g)", l->log.info("Player %hu split stack to create floor item %08" PRIX32 " (%s) at %hu:(%g, %g)",
@@ -1862,7 +1862,7 @@ static void on_drop_partial_stack_bb(shared_ptr<Client> c, uint8_t command, uint
l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F); l->add_item(cmd.floor, item, cmd.x, cmd.z, 0x00F);
send_drop_stacked_item_to_lobby(l, item, cmd.floor, cmd.x, cmd.z); send_drop_stacked_item_to_lobby(l, item, cmd.floor, cmd.x, cmd.z);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto s = c->require_server_state(); auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu split stack %08" PRIX32 " (removed: %s) at %hu:(%g, %g)", l->log.info("Player %hu split stack %08" PRIX32 " (removed: %s) at %hu:(%g, %g)",
@@ -1897,7 +1897,7 @@ static void on_buy_shop_item(shared_ptr<Client> c, uint8_t command, uint8_t flag
size_t price = s->item_parameter_table(c->version())->price_for_item(item); size_t price = s->item_parameter_table(c->version())->price_for_item(item);
p->remove_meseta(price, c->version() != Version::BB_V4); p->remove_meseta(price, c->version() != Version::BB_V4);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu bought item %08" PRIX32 " (%s) from shop (%zu Meseta)", l->log.info("Player %hu bought item %08" PRIX32 " (%s) from shop (%zu Meseta)",
cmd.header.client_id.load(), item.id.load(), name.c_str(), price); cmd.header.client_id.load(), item.id.load(), name.c_str(), price);
@@ -2040,7 +2040,7 @@ static void on_pick_up_item_generic(
return; return;
} }
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto s = c->require_server_state(); auto s = c->require_server_state();
auto name = s->describe_item(c->version(), fi->data, false); auto name = s->describe_item(c->version(), fi->data, false);
l->log.info("Player %hu picked up %08" PRIX32 " (%s)", client_id, item_id, name.c_str()); l->log.info("Player %hu picked up %08" PRIX32 " (%s)", client_id, item_id, name.c_str());
@@ -2079,12 +2079,12 @@ static void on_pick_up_item_generic(
string desc_http = s->describe_item(c->version(), fi->data, false); string desc_http = s->describe_item(c->version(), fi->data, false);
if (s->http_server) { if (s->http_server) {
auto message = make_shared<JSON>(JSON::dict({ auto message = make_shared<phosg::JSON>(phosg::JSON::dict({
{"PlayerAccountID", c->login->account->account_id}, {"PlayerAccountID", c->login->account->account_id},
{"PlayerName", p_name}, {"PlayerName", p_name},
{"PlayerVersion", name_for_enum(c->version())}, {"PlayerVersion", phosg::name_for_enum(c->version())},
{"GameName", l->name}, {"GameName", l->name},
{"GameDropMode", name_for_enum(l->drop_mode)}, {"GameDropMode", phosg::name_for_enum(l->drop_mode)},
{"ItemData", fi->data.hex()}, {"ItemData", fi->data.hex()},
{"ItemDescription", desc_http}, {"ItemDescription", desc_http},
{"NotifyGame", should_send_game_notif}, {"NotifyGame", should_send_game_notif},
@@ -2093,8 +2093,8 @@ static void on_pick_up_item_generic(
s->http_server->send_rare_drop_notification(message); s->http_server->send_rare_drop_notification(message);
} }
string message = string_printf("$C6%s$C7 found\n%s", p_name.c_str(), desc_ingame.c_str()); string message = phosg::string_printf("$C6%s$C7 found\n%s", p_name.c_str(), desc_ingame.c_str());
string bb_message = string_printf("$C6%s$C7 has found %s", p_name.c_str(), desc_ingame.c_str()); string bb_message = phosg::string_printf("$C6%s$C7 has found %s", p_name.c_str(), desc_ingame.c_str());
if (should_send_global_notif) { if (should_send_global_notif) {
for (auto& it : s->channel_to_client) { for (auto& it : s->channel_to_client) {
if (it.second->login && if (it.second->login &&
@@ -2177,7 +2177,7 @@ static void on_use_item(
} }
player_use_item(c, index, l->opt_rand_crypt); player_use_item(c, index, l->opt_rand_crypt);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
l->log.info("Player %hhu used item %hu:%08" PRIX32 " (%s)", l->log.info("Player %hhu used item %hu:%08" PRIX32 " (%s)",
c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str()); c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str());
c->print_inventory(stderr); c->print_inventory(stderr);
@@ -2222,7 +2222,7 @@ static void on_feed_mag(
p->remove_item(cmd.fed_item_id, 1, *s->item_stack_limits(c->version())); p->remove_item(cmd.fed_item_id, 1, *s->item_stack_limits(c->version()));
} }
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
l->log.info("Player %hhu fed item %hu:%08" PRIX32 " (%s) to mag %hu:%08" PRIX32 " (%s)", l->log.info("Player %hhu fed item %hu:%08" PRIX32 " (%s) to mag %hu:%08" PRIX32 " (%s)",
c->lobby_client_id, cmd.header.client_id.load(), cmd.fed_item_id.load(), fed_name.c_str(), c->lobby_client_id, cmd.header.client_id.load(), cmd.fed_item_id.load(), fed_name.c_str(),
cmd.header.client_id.load(), cmd.mag_item_id.load(), mag_name.c_str()); cmd.header.client_id.load(), cmd.mag_item_id.load(), mag_name.c_str());
@@ -2372,7 +2372,7 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
bank.add_item(item, limits); bank.add_item(item, limits);
send_destroy_item_to_lobby(c, cmd.item_id, cmd.item_amount, true); send_destroy_item_to_lobby(c, cmd.item_id, cmd.item_amount, true);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
string name = s->describe_item(Version::BB_V4, item, false); string name = s->describe_item(Version::BB_V4, item, false);
l->log.info("Player %hu deposited item %08" PRIX32 " (x%hhu) (%s) in the bank", l->log.info("Player %hu deposited item %08" PRIX32 " (x%hhu) (%s) in the bank",
c->lobby_client_id, cmd.item_id.load(), cmd.item_amount, name.c_str()); c->lobby_client_id, cmd.item_id.load(), cmd.item_amount, name.c_str());
@@ -2402,7 +2402,7 @@ static void on_ep3_private_word_select_bb_bank_action(shared_ptr<Client> c, uint
p->add_item(item, limits); p->add_item(item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item); send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
string name = s->describe_item(Version::BB_V4, item, false); string name = s->describe_item(Version::BB_V4, item, false);
l->log.info("Player %hu withdrew item %08" PRIX32 " (x%hhu) (%s) from the bank", l->log.info("Player %hu withdrew item %08" PRIX32 " (x%hhu) (%s) from the bank",
c->lobby_client_id, item.id.load(), cmd.item_amount, name.c_str()); c->lobby_client_id, item.id.load(), cmd.item_amount, name.c_str());
@@ -2559,7 +2559,7 @@ G_SpecializableItemDropRequest_6xA2 normalize_drop_request(const void* data, siz
} }
DropReconcileResult reconcile_drop_request_with_map( DropReconcileResult reconcile_drop_request_with_map(
PrefixedLogger& log, phosg::PrefixedLogger& log,
Channel& client_channel, Channel& client_channel,
G_SpecializableItemDropRequest_6xA2& cmd, G_SpecializableItemDropRequest_6xA2& cmd,
Version version, Version version,
@@ -2605,7 +2605,7 @@ DropReconcileResult reconcile_drop_request_with_map(
} else { } else {
if (map) { if (map) {
map_enemy = &map->enemies.at(cmd.entity_id); map_enemy = &map->enemies.at(cmd.entity_id);
log.info("Drop check for E-%hX %s", map_enemy->enemy_id, name_for_enum(map_enemy->type)); log.info("Drop check for E-%hX %s", map_enemy->enemy_id, phosg::name_for_enum(map_enemy->type));
res.effective_rt_index = rare_table_index_for_enemy_type(map_enemy->type); res.effective_rt_index = rare_table_index_for_enemy_type(map_enemy->type);
// rt_indexes in Episode 4 don't match those sent in the command; we just // rt_indexes in Episode 4 don't match those sent in the command; we just
// ignore what the client sends. // ignore what the client sends.
@@ -2630,7 +2630,7 @@ DropReconcileResult reconcile_drop_request_with_map(
cmd.floor, map_enemy->floor); cmd.floor, map_enemy->floor);
} }
if (config.check_flag(Client::Flag::DEBUG_ENABLED)) { if (config.check_flag(Client::Flag::DEBUG_ENABLED)) {
send_text_message_printf(client_channel, "$C5E-%hX %s", map_enemy->enemy_id, name_for_enum(map_enemy->type)); send_text_message_printf(client_channel, "$C5E-%hX %s", map_enemy->enemy_id, phosg::name_for_enum(map_enemy->type));
} }
} }
} }
@@ -2835,7 +2835,7 @@ static void on_set_quest_flag(shared_ptr<Client> c, uint8_t command, uint8_t fla
} }
if (boss_enemy_type != EnemyType::NONE) { if (boss_enemy_type != EnemyType::NONE) {
l->log.info("Creating item from final boss (%s)", name_for_enum(boss_enemy_type)); l->log.info("Creating item from final boss (%s)", phosg::name_for_enum(boss_enemy_type));
uint16_t enemy_id = 0xFFFF; uint16_t enemy_id = 0xFFFF;
if (l->map) { if (l->map) {
try { try {
@@ -2959,7 +2959,7 @@ static void on_set_entity_set_flag(shared_ptr<Client> c, uint8_t command, uint8_
event->flags = (event->flags | 0x18) & (~4); event->flags = (event->flags | 0x18) & (~4);
l->log.info("Set flags on W-%02hhX-%" PRIX32 " to %04hX", event->floor, event->event_id, event->flags); l->log.info("Set flags on W-%02hhX-%" PRIX32 " to %04hX", event->floor, event->event_id, event->flags);
StringReader actions_r(l->map->event_action_stream); phosg::StringReader actions_r(l->map->event_action_stream);
actions_r.go(event->action_stream_offset); actions_r.go(event->action_stream_offset);
while (!actions_r.eof()) { while (!actions_r.eof()) {
uint8_t opcode = actions_r.get_u8(); uint8_t opcode = actions_r.get_u8();
@@ -3284,9 +3284,9 @@ static void send_max_level_notification_if_needed(shared_ptr<Client> c) {
if (p->disp.stats.level == max_level) { if (p->disp.stats.level == max_level) {
string name = p->disp.name.decode(c->language()); string name = p->disp.name.decode(c->language());
size_t level_for_str = max_level + 1; size_t level_for_str = max_level + 1;
string message = string_printf("$C6%s$C7\nGC: %" PRIu32 "\nhas reached Level $C6%zu", string message = phosg::string_printf("$C6%s$C7\nGC: %" PRIu32 "\nhas reached Level $C6%zu",
name.c_str(), c->login->account->account_id, level_for_str); name.c_str(), c->login->account->account_id, level_for_str);
string bb_message = string_printf("$C6%s$C7 (GC: %" PRIu32 ") has reached Level $C6%zu", string bb_message = phosg::string_printf("$C6%s$C7 (GC: %" PRIu32 ") has reached Level $C6%zu",
name.c_str(), c->login->account->account_id, level_for_str); name.c_str(), c->login->account->account_id, level_for_str);
for (auto& it : s->channel_to_client) { for (auto& it : s->channel_to_client) {
if ((it.second != c) && it.second->login && !is_patch(it.second->version()) && it.second->lobby.lock()) { if ((it.second != c) && it.second->login && !is_patch(it.second->version()) && it.second->lobby.lock()) {
@@ -3409,7 +3409,7 @@ static void on_steal_exp_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* data,
c->log.info("Stolen EXP with bp_index=%" PRIX32 " enemy_exp=%" PRIu32 " percent=%g stolen_exp=%" PRIu32, c->log.info("Stolen EXP with bp_index=%" PRIX32 " enemy_exp=%" PRIu32 " percent=%g stolen_exp=%" PRIu32,
bp_index, enemy_exp, percent, stolen_exp); bp_index, enemy_exp, percent, stolen_exp);
send_text_message_printf(c, "$C5+%" PRIu32 " E-%hX %s", send_text_message_printf(c, "$C5+%" PRIu32 " E-%hX %s",
stolen_exp, cmd.enemy_index.load(), name_for_enum(enemy.type)); stolen_exp, cmd.enemy_index.load(), phosg::name_for_enum(enemy.type));
} }
add_player_exp(c, stolen_exp); add_player_exp(c, stolen_exp);
} }
@@ -3500,7 +3500,7 @@ static void on_enemy_exp_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
lc, "$C5+%" PRIu32 " E-%hX %s", lc, "$C5+%" PRIu32 " E-%hX %s",
player_exp, player_exp,
cmd.enemy_index.load(), cmd.enemy_index.load(),
name_for_enum(e.type)); phosg::name_for_enum(e.type));
} }
if (lc->character()->disp.stats.level < 199) { if (lc->character()->disp.stats.level < 199) {
add_player_exp(lc, player_exp); add_player_exp(lc, player_exp);
@@ -3570,7 +3570,7 @@ void on_item_reward_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* dat
try { try {
c->character()->add_item(item, limits); c->character()->add_item(item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item); send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu created inventory item %08" PRIX32 " (%s) via quest command", l->log.info("Player %hu created inventory item %08" PRIX32 " (%s) via quest command",
c->lobby_client_id, item.id.load(), name.c_str()); c->lobby_client_id, item.id.load(), name.c_str());
@@ -3578,7 +3578,7 @@ void on_item_reward_request_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* dat
} }
} catch (const out_of_range&) { } catch (const out_of_range&) {
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hu attempted to create inventory item %08" PRIX32 " (%s) via quest command, but it cannot be placed in their inventory", l->log.info("Player %hu attempted to create inventory item %08" PRIX32 " (%s) via quest command, but it cannot be placed in their inventory",
c->lobby_client_id, item.id.load(), name.c_str()); c->lobby_client_id, item.id.load(), name.c_str());
@@ -3610,7 +3610,7 @@ void on_transfer_item_via_mail_message_bb(shared_ptr<Client> c, uint8_t command,
const auto& limits = *s->item_stack_limits(c->version()); const auto& limits = *s->item_stack_limits(c->version());
auto item = p->remove_item(cmd.item_id, cmd.amount, limits); auto item = p->remove_item(cmd.item_id, cmd.amount, limits);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hhu sent inventory item %hu:%08" PRIX32 " (%s) x%" PRIu32 " to player %08" PRIX32, l->log.info("Player %hhu sent inventory item %hu:%08" PRIX32 " (%s) x%" PRIu32 " to player %08" PRIX32,
c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), cmd.amount.load(), cmd.target_guild_card_number.load()); c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), cmd.amount.load(), cmd.target_guild_card_number.load());
@@ -3671,7 +3671,7 @@ void on_exchange_item_for_team_points_bb(shared_ptr<Client> c, uint8_t command,
size_t points = s->item_parameter_table(Version::BB_V4)->get_item_team_points(item); size_t points = s->item_parameter_table(Version::BB_V4)->get_item_team_points(item);
s->team_index->add_member_points(c->login->account->account_id, points); s->team_index->add_member_points(c->login->account->account_id, points);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hhu exchanged inventory item %hu:%08" PRIX32 " (%s) for %zu team points", l->log.info("Player %hhu exchanged inventory item %hu:%08" PRIX32 " (%s) for %zu team points",
c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), points); c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str(), points);
@@ -3696,7 +3696,7 @@ static void on_destroy_inventory_item(shared_ptr<Client> c, uint8_t command, uin
auto p = c->character(); auto p = c->character();
auto item = p->remove_item(cmd.item_id, cmd.amount, *s->item_stack_limits(c->version())); auto item = p->remove_item(cmd.item_id, cmd.amount, *s->item_stack_limits(c->version()));
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hhu destroyed inventory item %hu:%08" PRIX32 " (%s)", l->log.info("Player %hhu destroyed inventory item %hu:%08" PRIX32 " (%s)",
c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str()); c->lobby_client_id, cmd.header.client_id.load(), cmd.item_id.load(), name.c_str());
@@ -3843,7 +3843,7 @@ static void on_sell_item_at_shop_bb(shared_ptr<Client> c, uint8_t command, uint8
size_t price = (s->item_parameter_table(c->version())->price_for_item(item) >> 3) * cmd.amount; size_t price = (s->item_parameter_table(c->version())->price_for_item(item) >> 3) * cmd.amount;
p->add_meseta(price); p->add_meseta(price);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hhu sold inventory item %08" PRIX32 " (%s) for %zu Meseta", l->log.info("Player %hhu sold inventory item %08" PRIX32 " (%s) for %zu Meseta",
c->lobby_client_id, cmd.item_id.load(), name.c_str(), price); c->lobby_client_id, cmd.item_id.load(), name.c_str(), price);
@@ -3879,7 +3879,7 @@ static void on_buy_shop_item_bb(shared_ptr<Client> c, uint8_t, uint8_t, void* da
p->add_item(item, limits); p->add_item(item, limits);
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item, true); send_create_inventory_item_to_lobby(c, c->lobby_client_id, item, true);
if (l->log.should_log(LogLevel::INFO)) { if (l->log.should_log(phosg::LogLevel::INFO)) {
auto s = c->require_server_state(); auto s = c->require_server_state();
auto name = s->describe_item(c->version(), item, false); auto name = s->describe_item(c->version(), item, false);
l->log.info("Player %hhu purchased item %08" PRIX32 " (%s) for %zu meseta", l->log.info("Player %hhu purchased item %08" PRIX32 " (%s) for %zu meseta",
@@ -4395,7 +4395,7 @@ static void on_quest_F960_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
auto s = c->require_server_state(); auto s = c->require_server_state();
auto p = c->character(); auto p = c->character();
time_t t_secs = now() / 1000000; time_t t_secs = phosg::now() / 1000000;
struct tm t_parsed; struct tm t_parsed;
gmtime_r(&t_secs, &t_parsed); gmtime_r(&t_secs, &t_parsed);
size_t weekday = t_parsed.tm_wday; size_t weekday = t_parsed.tm_wday;
@@ -4442,12 +4442,12 @@ static void on_quest_F960_result_bb(shared_ptr<Client> c, uint8_t, uint8_t, void
try { try {
p->add_item(item, *s->item_stack_limits(c->version())); p->add_item(item, *s->item_stack_limits(c->version()));
send_create_inventory_item_to_lobby(c, c->lobby_client_id, item); send_create_inventory_item_to_lobby(c, c->lobby_client_id, item);
if (c->log.should_log(LogLevel::INFO)) { if (c->log.should_log(phosg::LogLevel::INFO)) {
string name = s->describe_item(c->version(), item, false); string name = s->describe_item(c->version(), item, false);
c->log.info("Awarded item %s", name.c_str()); c->log.info("Awarded item %s", name.c_str());
} }
} catch (const out_of_range&) { } catch (const out_of_range&) {
if (c->log.should_log(LogLevel::INFO)) { if (c->log.should_log(phosg::LogLevel::INFO)) {
string name = s->describe_item(c->version(), item, false); string name = s->describe_item(c->version(), item, false);
c->log.info("Attempted to award item %s, but inventory was full", name.c_str()); c->log.info("Attempted to award item %s, but inventory was full", name.c_str());
} }
+1 -1
View File
@@ -28,7 +28,7 @@ struct DropReconcileResult {
}; };
DropReconcileResult reconcile_drop_request_with_map( DropReconcileResult reconcile_drop_request_with_map(
PrefixedLogger& log, phosg::PrefixedLogger& log,
Channel& client_channel, Channel& client_channel,
G_SpecializableItemDropRequest_6xA2& cmd, G_SpecializableItemDropRequest_6xA2& cmd,
Version version, Version version,
+51 -53
View File
@@ -19,13 +19,13 @@ ReplaySession::Event::Event(Type type, uint64_t client_id, size_t line_num)
string ReplaySession::Event::str() const { string ReplaySession::Event::str() const {
string ret; string ret;
if (this->type == Type::CONNECT) { if (this->type == Type::CONNECT) {
ret = string_printf("Event[%" PRIu64 ", CONNECT", this->client_id); ret = phosg::string_printf("Event[%" PRIu64 ", CONNECT", this->client_id);
} else if (this->type == Type::DISCONNECT) { } else if (this->type == Type::DISCONNECT) {
ret = string_printf("Event[%" PRIu64 ", DISCONNECT", this->client_id); ret = phosg::string_printf("Event[%" PRIu64 ", DISCONNECT", this->client_id);
} else if (this->type == Type::SEND) { } else if (this->type == Type::SEND) {
ret = string_printf("Event[%" PRIu64 ", SEND %04zX", this->client_id, this->data.size()); ret = phosg::string_printf("Event[%" PRIu64 ", SEND %04zX", this->client_id, this->data.size());
} else if (this->type == Type::RECEIVE) { } else if (this->type == Type::RECEIVE) {
ret = string_printf("Event[%" PRIu64 ", RECEIVE %04zX", this->client_id, this->data.size()); ret = phosg::string_printf("Event[%" PRIu64 ", RECEIVE %04zX", this->client_id, this->data.size());
} }
if (this->allow_size_disparity) { if (this->allow_size_disparity) {
ret += ", size disparity allowed"; ret += ", size disparity allowed";
@@ -33,7 +33,7 @@ string ReplaySession::Event::str() const {
if (this->complete) { if (this->complete) {
ret += ", done"; ret += ", done";
} }
ret += string_printf(", ev-line %zu]", this->line_num); ret += phosg::string_printf(", ev-line %zu]", this->line_num);
return ret; return ret;
} }
@@ -48,11 +48,10 @@ ReplaySession::Client::Client(
&ReplaySession::dispatch_on_command_received, &ReplaySession::dispatch_on_command_received,
&ReplaySession::dispatch_on_error, &ReplaySession::dispatch_on_error,
session, session,
string_printf("R-%" PRIX64, this->id)) {} phosg::string_printf("R-%" PRIX64, this->id)) {}
string ReplaySession::Client::str() const { string ReplaySession::Client::str() const {
return string_printf("Client[%" PRIu64 ", T-%hu, %s]", return phosg::string_printf("Client[%" PRIu64 ", T-%hu, %s]", this->id, this->port, phosg::name_for_enum(this->version));
this->id, this->port, name_for_enum(this->version));
} }
shared_ptr<ReplaySession::Event> ReplaySession::create_event( shared_ptr<ReplaySession::Event> ReplaySession::create_event(
@@ -88,14 +87,14 @@ void ReplaySession::check_for_password(shared_ptr<const Event> ev) const {
auto check_pw = [&](const string& pw) { auto check_pw = [&](const string& pw) {
if (this->require_basic_credentials && !string_is_basic(pw)) { if (this->require_basic_credentials && !string_is_basic(pw)) {
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, ev->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
throw runtime_error(string_printf("(ev-line %zu) sent password is incorrect", ev->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) sent password is incorrect", ev->line_num));
} }
}; };
auto check_ak = [&](const string& ak) { auto check_ak = [&](const string& ak) {
if (this->require_basic_credentials && !ak.empty() && !string_is_basic(ak)) { if (this->require_basic_credentials && !ak.empty() && !string_is_basic(ak)) {
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, ev->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
throw runtime_error(string_printf("(ev-line %zu) sent access key is incorrect", ev->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) sent access key is incorrect", ev->line_num));
} }
}; };
auto check_either = [&](const string& s) { auto check_either = [&](const string& s) {
@@ -472,8 +471,8 @@ ReplaySession::ReplaySession(
size_t num_events = 0; size_t num_events = 0;
while (!feof(input_log)) { while (!feof(input_log)) {
line_num++; line_num++;
string line = fgets(input_log); string line = phosg::fgets(input_log);
if (ends_with(line, "\n")) { if (phosg::ends_with(line, "\n")) {
line.resize(line.size() - 1); line.resize(line.size() - 1);
} }
if (line.empty()) { if (line.empty()) {
@@ -481,12 +480,11 @@ ReplaySession::ReplaySession(
} }
if (parsing_command.get()) { if (parsing_command.get()) {
string expected_start = string_printf("%04zX |", parsing_command->data.size()); string expected_start = phosg::string_printf("%04zX |", parsing_command->data.size());
if (starts_with(line, expected_start)) { if (phosg::starts_with(line, expected_start)) {
// Parse out the hex part of the hex/ASCII dump // Parse out the hex part of the hex/ASCII dump
string mask_bytes; string mask_bytes;
string data_bytes = parse_data_string( string data_bytes = phosg::parse_data_string(line.substr(expected_start.size(), 16 * 3 + 1), &mask_bytes);
line.substr(expected_start.size(), 16 * 3 + 1), &mask_bytes);
parsing_command->data += data_bytes; parsing_command->data += data_bytes;
parsing_command->mask += mask_bytes; parsing_command->mask += mask_bytes;
continue; continue;
@@ -500,30 +498,30 @@ ReplaySession::ReplaySession(
} }
} }
if (starts_with(line, "I ")) { if (phosg::starts_with(line, "I ")) {
// I <pid/ts> - [Server] Client connected: C-%X on fd %d via %d (T-%hu-%s-%s-%s) // I <pid/ts> - [Server] Client connected: C-%X on fd %d via %d (T-%hu-%s-%s-%s)
// I <pid/ts> - [Server] Client connected: C-%X on virtual connection %p via T-%hu-VI // I <pid/ts> - [Server] Client connected: C-%X on virtual connection %p via T-%hu-VI
size_t offset = line.find(" - [Server] Client connected: C-"); size_t offset = line.find(" - [Server] Client connected: C-");
if (offset != string::npos) { if (offset != string::npos) {
auto tokens = split(line, ' '); auto tokens = phosg::split(line, ' ');
if (tokens.size() != 15) { if (tokens.size() != 15) {
throw runtime_error(string_printf("(ev-line %zu) client connection message has incorrect token count", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client connection message has incorrect token count", line_num));
} }
if (!starts_with(tokens[8], "C-")) { if (!phosg::starts_with(tokens[8], "C-")) {
throw runtime_error(string_printf("(ev-line %zu) client connection message missing client ID token", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client connection message missing client ID token", line_num));
} }
auto listen_tokens = split(tokens[14], '-'); auto listen_tokens = phosg::split(tokens[14], '-');
if (listen_tokens.size() < 4) { if (listen_tokens.size() < 4) {
throw runtime_error(string_printf("(ev-line %zu) client connection message listening socket token format is incorrect", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client connection message listening socket token format is incorrect", line_num));
} }
auto c = make_shared<Client>( auto c = make_shared<Client>(
this, this,
stoull(tokens[8].substr(2), nullptr, 16), stoull(tokens[8].substr(2), nullptr, 16),
stoul(listen_tokens[1], nullptr, 10), stoul(listen_tokens[1], nullptr, 10),
enum_for_name<Version>(listen_tokens[2].c_str())); phosg::enum_for_name<Version>(listen_tokens[2].c_str()));
if (!this->clients.emplace(c->id, c).second) { if (!this->clients.emplace(c->id, c).second) {
throw runtime_error(string_printf("(ev-line %zu) duplicate client ID in input log", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) duplicate client ID in input log", line_num));
} }
this->create_event(Event::Type::CONNECT, c, line_num); this->create_event(Event::Type::CONNECT, c, line_num);
num_events++; num_events++;
@@ -533,23 +531,23 @@ ReplaySession::ReplaySession(
// I <pid/ts> - [Server] Disconnecting C-%X on fd %d // I <pid/ts> - [Server] Disconnecting C-%X on fd %d
offset = line.find(" - [Server] Client disconnected: C-"); offset = line.find(" - [Server] Client disconnected: C-");
if (offset != string::npos) { if (offset != string::npos) {
auto tokens = split(line, ' '); auto tokens = phosg::split(line, ' ');
if (tokens.size() < 9) { if (tokens.size() < 9) {
throw runtime_error(string_printf("(ev-line %zu) client disconnection message has incorrect token count", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client disconnection message has incorrect token count", line_num));
} }
if (!starts_with(tokens[8], "C-")) { if (!phosg::starts_with(tokens[8], "C-")) {
throw runtime_error(string_printf("(ev-line %zu) client disconnection message missing client ID token", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client disconnection message missing client ID token", line_num));
} }
uint64_t client_id = stoul(tokens[8].substr(2), nullptr, 16); uint64_t client_id = stoul(tokens[8].substr(2), nullptr, 16);
try { try {
auto& c = this->clients.at(client_id); auto& c = this->clients.at(client_id);
if (c->disconnect_event.get()) { if (c->disconnect_event.get()) {
throw runtime_error(string_printf("(ev-line %zu) client has multiple disconnect events", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client has multiple disconnect events", line_num));
} }
c->disconnect_event = this->create_event(Event::Type::DISCONNECT, c, line_num); c->disconnect_event = this->create_event(Event::Type::DISCONNECT, c, line_num);
num_events++; num_events++;
} catch (const out_of_range&) { } catch (const out_of_range&) {
throw runtime_error(string_printf("(ev-line %zu) unknown disconnecting client ID in input log", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) unknown disconnecting client ID in input log", line_num));
} }
continue; continue;
} }
@@ -561,9 +559,9 @@ ReplaySession::ReplaySession(
offset = line.find(" - [Commands] Received from C-"); offset = line.find(" - [Commands] Received from C-");
} }
if (offset != string::npos) { if (offset != string::npos) {
auto tokens = split(line, ' '); auto tokens = phosg::split(line, ' ');
if (tokens.size() < 10) { if (tokens.size() < 10) {
throw runtime_error(string_printf("(ev-line %zu) command header line too short", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) command header line too short", line_num));
} }
bool from_client = (tokens[6] == "Received"); bool from_client = (tokens[6] == "Received");
uint64_t client_id = stoull(tokens[8].substr(2), nullptr, 16); uint64_t client_id = stoull(tokens[8].substr(2), nullptr, 16);
@@ -574,7 +572,7 @@ ReplaySession::ReplaySession(
line_num); line_num);
num_events++; num_events++;
} catch (const out_of_range&) { } catch (const out_of_range&) {
throw runtime_error(string_printf("(ev-line %zu) input log contains command for missing client", line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) input log contains command for missing client", line_num));
} }
continue; continue;
} }
@@ -605,7 +603,7 @@ void ReplaySession::update_timeout_event() {
event_new(this->base.get(), -1, EV_TIMEOUT, this->dispatch_on_timeout, this), event_new(this->base.get(), -1, EV_TIMEOUT, this->dispatch_on_timeout, this),
event_free); event_free);
} }
struct timeval tv = usecs_to_timeval(3000000); struct timeval tv = phosg::usecs_to_timeval(3000000);
event_add(this->timeout_ev.get(), &tv); event_add(this->timeout_ev.get(), &tv);
} }
@@ -624,7 +622,7 @@ void ReplaySession::execute_pending_events() {
switch (this->first_event->type) { switch (this->first_event->type) {
case Event::Type::CONNECT: { case Event::Type::CONNECT: {
if (c->channel.connected()) { if (c->channel.connected()) {
throw runtime_error(string_printf("(ev-line %zu) connect event on already-connected client", this->first_event->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) connect event on already-connected client", this->first_event->line_num));
} }
struct bufferevent* bevs[2]; struct bufferevent* bevs[2];
@@ -638,17 +636,17 @@ void ReplaySession::execute_pending_events() {
port_config = this->state->number_to_port_config.at(c->port); port_config = this->state->number_to_port_config.at(c->port);
} catch (const out_of_range&) { } catch (const out_of_range&) {
bufferevent_free(bevs[1]); bufferevent_free(bevs[1]);
throw runtime_error(string_printf("(ev-line %zu) client connected to port missing from configuration", this->first_event->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client connected to port missing from configuration", this->first_event->line_num));
} }
if (port_config->behavior == ServerBehavior::PROXY_SERVER) { if (port_config->behavior == ServerBehavior::PROXY_SERVER) {
// TODO: We should support this at some point in the future // TODO: We should support this at some point in the future
throw runtime_error(string_printf("(ev-line %zu) client connected to proxy server", this->first_event->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) client connected to proxy server", this->first_event->line_num));
} else if (this->state->game_server.get()) { } else if (this->state->game_server.get()) {
this->state->game_server->connect_virtual_client(bevs[1], 0, 0x20202020, this->state->game_server->connect_virtual_client(bevs[1], 0, 0x20202020,
1025, c->port, port_config->version, port_config->behavior); 1025, c->port, port_config->version, port_config->behavior);
} else { } else {
throw runtime_error(string_printf("(ev-line %zu) no server available for connection", this->first_event->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) no server available for connection", this->first_event->line_num));
bufferevent_free(bevs[1]); bufferevent_free(bevs[1]);
} }
break; break;
@@ -659,7 +657,7 @@ void ReplaySession::execute_pending_events() {
break; break;
case Event::Type::SEND: case Event::Type::SEND:
if (!c->channel.connected()) { if (!c->channel.connected()) {
throw runtime_error(string_printf("(ev-line %zu) send event attempted on unconnected client", this->first_event->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) send event attempted on unconnected client", this->first_event->line_num));
} }
c->channel.send(this->first_event->data); c->channel.send(this->first_event->data);
this->commands_sent++; this->commands_sent++;
@@ -706,7 +704,7 @@ void ReplaySession::dispatch_on_error(Channel& ch, short events) {
void ReplaySession::on_command_received( void ReplaySession::on_command_received(
shared_ptr<Client> c, uint16_t command, uint32_t flag, string& data) { shared_ptr<Client> c, uint16_t command, uint32_t flag, string& data) {
// TODO: Use the iovec form of print_data here instead of // TODO: Use the iovec form of phosg::print_data here instead of
// prepend_command_header (which copies the string) // prepend_command_header (which copies the string)
string full_command = prepend_command_header( string full_command = prepend_command_header(
c->version, c->channel.crypt_in.get(), command, flag, data); c->version, c->channel.crypt_in.get(), command, flag, data);
@@ -714,25 +712,25 @@ void ReplaySession::on_command_received(
this->bytes_received += full_command.size(); this->bytes_received += full_command.size();
if (c->receive_events.empty()) { if (c->receive_events.empty()) {
print_data(stderr, full_command, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, full_command, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
throw runtime_error("received unexpected command for client"); throw runtime_error("received unexpected command for client");
} }
auto& ev = c->receive_events.front(); auto& ev = c->receive_events.front();
if ((full_command.size() != ev->data.size()) && !ev->allow_size_disparity) { if ((full_command.size() != ev->data.size()) && !ev->allow_size_disparity) {
replay_log.error("Expected command:"); replay_log.error("Expected command:");
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, ev->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
replay_log.error("Received command:"); replay_log.error("Received command:");
print_data(stderr, full_command, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, full_command, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
throw runtime_error(string_printf("(ev-line %zu) received command sizes do not match", ev->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) received command sizes do not match", ev->line_num));
} }
for (size_t x = 0; x < min<size_t>(full_command.size(), ev->data.size()); x++) { for (size_t x = 0; x < min<size_t>(full_command.size(), ev->data.size()); x++) {
if ((full_command[x] & ev->mask[x]) != (ev->data[x] & ev->mask[x])) { if ((full_command[x] & ev->mask[x]) != (ev->data[x] & ev->mask[x])) {
replay_log.error("Expected command:"); replay_log.error("Expected command:");
print_data(stderr, ev->data, 0, nullptr, PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, ev->data, 0, nullptr, phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
replay_log.error("Received command:"); replay_log.error("Received command:");
print_data(stderr, full_command, 0, ev->data.data(), PrintDataFlags::PRINT_ASCII | PrintDataFlags::OFFSET_16_BITS); phosg::print_data(stderr, full_command, 0, ev->data.data(), phosg::PrintDataFlags::PRINT_ASCII | phosg::PrintDataFlags::OFFSET_16_BITS);
throw runtime_error(string_printf("(ev-line %zu) received command data does not match expected data", ev->line_num)); throw runtime_error(phosg::string_printf("(ev-line %zu) received command data does not match expected data", ev->line_num));
} }
} }
@@ -792,15 +790,15 @@ void ReplaySession::on_command_received(
void ReplaySession::on_error(shared_ptr<Client> c, short events) { void ReplaySession::on_error(shared_ptr<Client> c, short events) {
if (events & BEV_EVENT_ERROR) { if (events & BEV_EVENT_ERROR) {
throw runtime_error(string_printf("C-%" PRIX64 " caused stream error", c->id)); throw runtime_error(phosg::string_printf("C-%" PRIX64 " caused stream error", c->id));
} }
if (events & BEV_EVENT_EOF) { if (events & BEV_EVENT_EOF) {
if (!c->disconnect_event.get()) { if (!c->disconnect_event.get()) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"C-%" PRIX64 " disconnected, but has no disconnect event", c->id)); "C-%" PRIX64 " disconnected, but has no disconnect event", c->id));
} }
if (!c->receive_events.empty()) { if (!c->receive_events.empty()) {
throw runtime_error(string_printf( throw runtime_error(phosg::string_printf(
"C-%" PRIX64 " disconnected, but has pending receive events", c->id)); "C-%" PRIX64 " disconnected, but has pending receive events", c->id));
} }
c->disconnect_event->complete = true; c->disconnect_event->complete = true;
+15 -15
View File
@@ -144,13 +144,13 @@ bool PSOVMSFileHeader::checksum_correct() const {
} }
bool PSOGCIFileHeader::checksum_correct() const { bool PSOGCIFileHeader::checksum_correct() const {
uint32_t cs = crc32(&this->game_name, this->game_name.bytes()); uint32_t cs = phosg::crc32(&this->game_name, this->game_name.bytes());
cs = crc32(&this->embedded_seed, sizeof(this->embedded_seed), cs); cs = phosg::crc32(&this->embedded_seed, sizeof(this->embedded_seed), cs);
cs = crc32(&this->file_name, this->file_name.bytes(), cs); cs = phosg::crc32(&this->file_name, this->file_name.bytes(), cs);
cs = crc32(&this->banner, this->banner.bytes(), cs); cs = phosg::crc32(&this->banner, this->banner.bytes(), cs);
cs = crc32(&this->icon, this->icon.bytes(), cs); cs = phosg::crc32(&this->icon, this->icon.bytes(), cs);
cs = crc32(&this->data_size, sizeof(this->data_size), cs); cs = phosg::crc32(&this->data_size, sizeof(this->data_size), cs);
cs = crc32("\0\0\0\0", 4, cs); // this->checksum (treated as zero) cs = phosg::crc32("\0\0\0\0", 4, cs); // this->checksum (treated as zero)
return (cs == this->checksum); return (cs == this->checksum);
} }
@@ -217,8 +217,8 @@ string decrypt_gci_fixed_size_data_section_for_salvage(
} }
bool PSOGCSnapshotFile::checksum_correct() const { bool PSOGCSnapshotFile::checksum_correct() const {
uint32_t crc = crc32("\0\0\0\0", 4); uint32_t crc = phosg::crc32("\0\0\0\0", 4);
crc = crc32(&this->width, sizeof(*this) - sizeof(this->checksum), crc); crc = phosg::crc32(&this->width, sizeof(*this) - sizeof(this->checksum), crc);
return (crc == this->checksum); return (crc == this->checksum);
} }
@@ -231,7 +231,7 @@ static uint32_t decode_rgb565(uint16_t c) {
0x000000FF; // A 0x000000FF; // A
} }
Image PSOGCSnapshotFile::decode_image() const { phosg::Image PSOGCSnapshotFile::decode_image() const {
size_t width = this->width ? this->width.load() : 256; size_t width = this->width ? this->width.load() : 256;
size_t height = this->height ? this->height.load() : 192; size_t height = this->height ? this->height.load() : 192;
if (width != 256) { if (width != 256) {
@@ -242,7 +242,7 @@ Image PSOGCSnapshotFile::decode_image() const {
} }
// 4x4 blocks of pixels // 4x4 blocks of pixels
Image ret(width, height, false); phosg::Image ret(width, height, false);
size_t offset = 0; size_t offset = 0;
for (size_t y = 0; y < this->height; y += 4) { for (size_t y = 0; y < this->height; y += 4) {
for (size_t x = 0; x < this->width; x += 4) { for (size_t x = 0; x < this->width; x += 4) {
@@ -322,12 +322,12 @@ void PSOBBGuildCardFile::Entry::clear() {
} }
uint32_t PSOBBGuildCardFile::checksum() const { uint32_t PSOBBGuildCardFile::checksum() const {
return crc32(this, sizeof(*this)); return phosg::crc32(this, sizeof(*this));
} }
PSOBBBaseSystemFile::PSOBBBaseSystemFile() { PSOBBBaseSystemFile::PSOBBBaseSystemFile() {
// This field is based on 1/1/2000, not 1/1/1970, so adjust appropriately // This field is based on 1/1/2000, not 1/1/1970, so adjust appropriately
this->base.creation_timestamp = (now() - 946684800000000ULL) / 1000000; this->base.creation_timestamp = (phosg::now() - 946684800000000ULL) / 1000000;
for (size_t z = 0; z < DEFAULT_KEY_CONFIG.size(); z++) { for (size_t z = 0; z < DEFAULT_KEY_CONFIG.size(); z++) {
this->key_config[z] = DEFAULT_KEY_CONFIG[z]; this->key_config[z] = DEFAULT_KEY_CONFIG[z];
} }
@@ -1170,7 +1170,7 @@ static uint16_t crc16(const void* data, size_t size) {
}; };
uint16_t ret = 0xFFFF; uint16_t ret = 0xFFFF;
StringReader r(data, size); phosg::StringReader r(data, size);
while (!r.eof()) { while (!r.eof()) {
ret = (ret >> 8) ^ table[r.get_u8() ^ (ret & 0xFF)]; ret = (ret >> 8) ^ table[r.get_u8() ^ (ret & 0xFF)];
} }
@@ -1184,7 +1184,7 @@ string encode_psobb_hangame_credentials(const string& user_id, const string& tok
if (user_id.size() > 12) { if (user_id.size() > 12) {
throw runtime_error("user_id must be at most 12 characters"); throw runtime_error("user_id must be at most 12 characters");
} }
if (!ends_with(user_id, "@HG")) { if (!phosg::ends_with(user_id, "@HG")) {
throw runtime_error("user_id must end with \"@HG\""); throw runtime_error("user_id must end with \"@HG\"");
} }
if (token.empty()) { if (token.empty()) {
+51 -62
View File
@@ -98,14 +98,12 @@ struct ShuffleTables {
void shuffle(void* vdest, const void* vsrc, size_t size, bool reverse) const; void shuffle(void* vdest, const void* vsrc, size_t size, bool reverse) const;
}; };
template <bool IsBigEndian, TextEncoding Encoding, size_t NameLength> template <bool BE, TextEncoding Encoding, size_t NameLength>
struct SaveFileSymbolChatEntryT { struct SaveFileSymbolChatEntryT {
using U32T = std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t>;
/* PC:GC:XB:BB */ /* PC:GC:XB:BB */
/* 00:00:00:00 */ U32T present; /* 00:00:00:00 */ U32T<BE> present;
/* 04:04:04:04 */ pstring<Encoding, NameLength> name; /* 04:04:04:04 */ pstring<Encoding, NameLength> name;
/* 34:1C:1C:2C */ SymbolChatT<IsBigEndian> spec; /* 34:1C:1C:2C */ SymbolChatT<BE> spec;
/* 70:58:58:68 */ /* 70:58:58:68 */
} __packed__; } __packed__;
using SaveFileSymbolChatEntryPC = SaveFileSymbolChatEntryT<false, TextEncoding::UTF16, 0x18>; using SaveFileSymbolChatEntryPC = SaveFileSymbolChatEntryT<false, TextEncoding::UTF16, 0x18>;
@@ -117,19 +115,16 @@ check_struct_size(SaveFileSymbolChatEntryGC, 0x58);
check_struct_size(SaveFileSymbolChatEntryDCXB, 0x58); check_struct_size(SaveFileSymbolChatEntryDCXB, 0x58);
check_struct_size(SaveFileSymbolChatEntryBB, 0x68); check_struct_size(SaveFileSymbolChatEntryBB, 0x68);
template <bool IsBigEndian> template <bool BE>
struct WordSelectMessageT { struct WordSelectMessageT {
using U16T = std::conditional_t<IsBigEndian, be_uint16_t, le_uint16_t>; U16T<BE> num_tokens = 0;
using U32T = std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t>; U16T<BE> target_type = 0;
parray<U16T<BE>, 8> tokens;
U32T<BE> numeric_parameter = 0;
U32T<BE> unknown_a4 = 0;
U16T num_tokens = 0; operator WordSelectMessageT<!BE>() const {
U16T target_type = 0; WordSelectMessageT<!BE> ret;
parray<U16T, 8> tokens;
U32T numeric_parameter = 0;
U32T unknown_a4 = 0;
operator WordSelectMessageT<!IsBigEndian>() const {
WordSelectMessageT<!IsBigEndian> ret;
ret.num_tokens = this->num_tokens.load(); ret.num_tokens = this->num_tokens.load();
ret.target_type = this->target_type.load(); ret.target_type = this->target_type.load();
for (size_t z = 0; z < this->tokens.size(); z++) { for (size_t z = 0; z < this->tokens.size(); z++) {
@@ -145,14 +140,12 @@ using WordSelectMessageBE = WordSelectMessageT<true>;
check_struct_size(WordSelectMessage, 0x1C); check_struct_size(WordSelectMessage, 0x1C);
check_struct_size(WordSelectMessageBE, 0x1C); check_struct_size(WordSelectMessageBE, 0x1C);
template <bool IsBigEndian, TextEncoding Encoding, size_t MaxChars> template <bool BE, TextEncoding Encoding, size_t MaxChars>
struct SaveFileChatShortcutEntryT { struct SaveFileChatShortcutEntryT {
using U32T = std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t>;
union Definition { union Definition {
pstring<Encoding, MaxChars> text; pstring<Encoding, MaxChars> text;
WordSelectMessageT<IsBigEndian> word_select; WordSelectMessageT<BE> word_select;
SymbolChatT<IsBigEndian> symbol_chat; SymbolChatT<BE> symbol_chat;
Definition() : text() {} Definition() : text() {}
Definition(const Definition& other) : text(other.text) {} Definition(const Definition& other) : text(other.text) {}
@@ -163,13 +156,13 @@ struct SaveFileChatShortcutEntryT {
} __packed__; } __packed__;
/* DC:GC:BB */ /* DC:GC:BB */
/* 00:00:00 */ U32T type; // 1 = text, 2 = word select, 3 = symbol chat /* 00:00:00 */ U32T<BE> type; // 1 = text, 2 = word select, 3 = symbol chat
/* 04:04:04 */ Definition definition; /* 04:04:04 */ Definition definition;
/* 40:54:A4 */ /* 40:54:A4 */
template <bool RetIsBigEndian, TextEncoding RetEncoding, size_t RetMaxSize> template <bool RetBE, TextEncoding RetEncoding, size_t RetMaxSize>
SaveFileChatShortcutEntryT<RetIsBigEndian, RetEncoding, RetMaxSize> convert(uint8_t language) const { SaveFileChatShortcutEntryT<RetBE, RetEncoding, RetMaxSize> convert(uint8_t language) const {
SaveFileChatShortcutEntryT<RetIsBigEndian, RetEncoding, RetMaxSize> ret; SaveFileChatShortcutEntryT<RetBE, RetEncoding, RetMaxSize> ret;
ret.type = this->type.load(); ret.type = this->type.load();
switch (ret.type) { switch (ret.type) {
case 1: case 1:
@@ -835,7 +828,7 @@ struct PSOGCSnapshotFile {
/* 1818C */ /* 1818C */
bool checksum_correct() const; bool checksum_correct() const;
Image decode_image() const; phosg::Image decode_image() const;
} __packed_ws__(PSOGCSnapshotFile, 0x1818C); } __packed_ws__(PSOGCSnapshotFile, 0x1818C);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -882,7 +875,7 @@ struct LegacySavedAccountDataBB { // .nsa file format
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Encoding/decoding functions // Encoding/decoding functions
template <bool IsBigEndian> template <bool BE>
std::string decrypt_data_section(const void* data_section, size_t size, uint32_t round1_seed, size_t max_decrypt_bytes = 0) { std::string decrypt_data_section(const void* data_section, size_t size, uint32_t round1_seed, size_t max_decrypt_bytes = 0) {
if (max_decrypt_bytes == 0) { if (max_decrypt_bytes == 0) {
max_decrypt_bytes = size; max_decrypt_bytes = size;
@@ -899,19 +892,19 @@ std::string decrypt_data_section(const void* data_section, size_t size, uint32_t
decrypted.resize((decrypted.size() + 3) & (~3)); decrypted.resize((decrypted.size() + 3) & (~3));
PSOV2Encryption round1_crypt(round1_seed); PSOV2Encryption round1_crypt(round1_seed);
round1_crypt.encrypt_minus_t<IsBigEndian>(decrypted.data(), decrypted.size()); round1_crypt.encrypt_minus_t<BE>(decrypted.data(), decrypted.size());
decrypted.resize(orig_size); decrypted.resize(orig_size);
return decrypted; return decrypted;
} }
template <bool IsBigEndian> template <bool BE>
std::string encrypt_data_section(const void* data_section, size_t size, uint32_t round1_seed) { std::string encrypt_data_section(const void* data_section, size_t size, uint32_t round1_seed) {
std::string encrypted(reinterpret_cast<const char*>(data_section), size); std::string encrypted(reinterpret_cast<const char*>(data_section), size);
encrypted.resize((encrypted.size() + 3) & (~3)); encrypted.resize((encrypted.size() + 3) & (~3));
PSOV2Encryption crypt(round1_seed); PSOV2Encryption crypt(round1_seed);
crypt.encrypt_minus_t<IsBigEndian>(encrypted.data(), encrypted.size()); crypt.encrypt_minus_t<BE>(encrypted.data(), encrypted.size());
std::string ret(size, '\0'); std::string ret(size, '\0');
PSOV2Encryption shuf_crypt(round1_seed); PSOV2Encryption shuf_crypt(round1_seed);
@@ -921,38 +914,36 @@ std::string encrypt_data_section(const void* data_section, size_t size, uint32_t
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
std::string decrypt_fixed_size_data_section_s( std::string decrypt_fixed_size_data_section_s(
const void* data_section, const void* data_section,
size_t size, size_t size,
uint32_t round1_seed, uint32_t round1_seed,
bool skip_checksum = false, bool skip_checksum = false,
uint64_t override_round2_seed = 0xFFFFFFFFFFFFFFFF) { uint64_t override_round2_seed = 0xFFFFFFFFFFFFFFFF) {
using U32T = std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t>; if (size < 2 * sizeof(U32T<BE>)) {
if (size < 2 * sizeof(U32T)) {
throw std::runtime_error("data size is too small"); throw std::runtime_error("data size is too small");
} }
std::string decrypted = decrypt_data_section<IsBigEndian>(data_section, size, round1_seed); std::string decrypted = decrypt_data_section<BE>(data_section, size, round1_seed);
uint32_t round2_seed = override_round2_seed < 0x100000000 uint32_t round2_seed = override_round2_seed < 0x100000000
? static_cast<uint32_t>(override_round2_seed) ? static_cast<uint32_t>(override_round2_seed)
: reinterpret_cast<const U32T*>(decrypted.data() + decrypted.size() - sizeof(U32T))->load(); : reinterpret_cast<const U32T<BE>*>(decrypted.data() + decrypted.size() - sizeof(U32T<BE>))->load();
PSOV2Encryption round2_crypt(round2_seed); PSOV2Encryption round2_crypt(round2_seed);
if (IsBigEndian) { if (BE) {
round2_crypt.encrypt_big_endian(decrypted.data(), decrypted.size() - sizeof(U32T)); round2_crypt.encrypt_big_endian(decrypted.data(), decrypted.size() - sizeof(U32T<BE>));
} else { } else {
round2_crypt.encrypt(decrypted.data(), decrypted.size() - sizeof(U32T)); round2_crypt.encrypt(decrypted.data(), decrypted.size() - sizeof(U32T<BE>));
} }
if (!skip_checksum) { if (!skip_checksum) {
U32T& checksum = *reinterpret_cast<U32T*>(decrypted.data()); U32T<BE>& checksum = *reinterpret_cast<U32T<BE>*>(decrypted.data());
uint32_t expected_crc = checksum; uint32_t expected_crc = checksum;
checksum = 0; checksum = 0;
uint32_t actual_crc = crc32(decrypted.data(), decrypted.size()); uint32_t actual_crc = phosg::crc32(decrypted.data(), decrypted.size());
checksum = expected_crc; checksum = expected_crc;
if (expected_crc != actual_crc) { if (expected_crc != actual_crc) {
throw std::runtime_error(string_printf( throw std::runtime_error(phosg::string_printf(
"incorrect decrypted data section checksum: expected %08" PRIX32 "; received %08" PRIX32, "incorrect decrypted data section checksum: expected %08" PRIX32 "; received %08" PRIX32,
expected_crc, actual_crc)); expected_crc, actual_crc));
} }
@@ -961,7 +952,7 @@ std::string decrypt_fixed_size_data_section_s(
return decrypted; return decrypted;
} }
template <typename StructT, bool IsBigEndian> template <typename StructT, bool BE>
StructT decrypt_fixed_size_data_section_t( StructT decrypt_fixed_size_data_section_t(
const void* data_section, const void* data_section,
size_t size, size_t size,
@@ -969,14 +960,14 @@ StructT decrypt_fixed_size_data_section_t(
bool skip_checksum = false, bool skip_checksum = false,
uint64_t override_round2_seed = 0xFFFFFFFFFFFFFFFF) { uint64_t override_round2_seed = 0xFFFFFFFFFFFFFFFF) {
std::string decrypted = decrypt_data_section<IsBigEndian>(data_section, size, round1_seed); std::string decrypted = decrypt_data_section<BE>(data_section, size, round1_seed);
if (decrypted.size() < sizeof(StructT)) { if (decrypted.size() < sizeof(StructT)) {
throw std::runtime_error("file too small for structure"); throw std::runtime_error("file too small for structure");
} }
StructT ret = *reinterpret_cast<const StructT*>(decrypted.data()); StructT ret = *reinterpret_cast<const StructT*>(decrypted.data());
PSOV2Encryption round2_crypt(override_round2_seed < 0x100000000 ? override_round2_seed : ret.round2_seed.load()); PSOV2Encryption round2_crypt(override_round2_seed < 0x100000000 ? override_round2_seed : ret.round2_seed.load());
if (IsBigEndian) { if (BE) {
round2_crypt.encrypt_big_endian(&ret, offsetof(StructT, round2_seed)); round2_crypt.encrypt_big_endian(&ret, offsetof(StructT, round2_seed));
} else { } else {
round2_crypt.encrypt(&ret, offsetof(StructT, round2_seed)); round2_crypt.encrypt(&ret, offsetof(StructT, round2_seed));
@@ -985,10 +976,10 @@ StructT decrypt_fixed_size_data_section_t(
if (!skip_checksum) { if (!skip_checksum) {
uint32_t expected_crc = ret.checksum; uint32_t expected_crc = ret.checksum;
ret.checksum = 0; ret.checksum = 0;
uint32_t actual_crc = crc32(&ret, sizeof(ret)); uint32_t actual_crc = phosg::crc32(&ret, sizeof(ret));
ret.checksum = expected_crc; ret.checksum = expected_crc;
if (expected_crc != actual_crc) { if (expected_crc != actual_crc) {
throw std::runtime_error(string_printf( throw std::runtime_error(phosg::string_printf(
"incorrect decrypted data section checksum: expected %08" PRIX32 "; received %08" PRIX32, "incorrect decrypted data section checksum: expected %08" PRIX32 "; received %08" PRIX32,
expected_crc, actual_crc)); expected_crc, actual_crc));
} }
@@ -997,46 +988,44 @@ StructT decrypt_fixed_size_data_section_t(
return ret; return ret;
} }
template <bool IsBigEndian> template <bool BE>
std::string encrypt_fixed_size_data_section_s(const void* data, size_t size, uint32_t round1_seed) { std::string encrypt_fixed_size_data_section_s(const void* data, size_t size, uint32_t round1_seed) {
using U32T = std::conditional_t<IsBigEndian, be_uint32_t, le_uint32_t>; if (size < 2 * sizeof(U32T<BE>)) {
if (size < 2 * sizeof(U32T)) {
throw std::runtime_error("data size is too small"); throw std::runtime_error("data size is too small");
} }
uint32_t round2_seed = random_object<uint32_t>(); uint32_t round2_seed = phosg::random_object<uint32_t>();
std::string encrypted(reinterpret_cast<const char*>(data), size); std::string encrypted(reinterpret_cast<const char*>(data), size);
*reinterpret_cast<U32T*>(encrypted.data()) = 0; *reinterpret_cast<U32T<BE>*>(encrypted.data()) = 0;
*reinterpret_cast<U32T*>(encrypted.data() + encrypted.size() - sizeof(U32T)) = round2_seed; *reinterpret_cast<U32T<BE>*>(encrypted.data() + encrypted.size() - sizeof(U32T<BE>)) = round2_seed;
*reinterpret_cast<U32T*>(encrypted.data()) = crc32(encrypted.data(), encrypted.size()); *reinterpret_cast<U32T<BE>*>(encrypted.data()) = phosg::crc32(encrypted.data(), encrypted.size());
PSOV2Encryption round2_crypt(round2_seed); PSOV2Encryption round2_crypt(round2_seed);
if (IsBigEndian) { if (BE) {
round2_crypt.encrypt_big_endian(encrypted.data(), encrypted.size()); round2_crypt.encrypt_big_endian(encrypted.data(), encrypted.size());
} else { } else {
round2_crypt.encrypt(encrypted.data(), encrypted.size()); round2_crypt.encrypt(encrypted.data(), encrypted.size());
} }
return encrypt_data_section<IsBigEndian>(encrypted.data(), encrypted.size(), round1_seed); return encrypt_data_section<BE>(encrypted.data(), encrypted.size(), round1_seed);
} }
template <typename StructT, bool IsBigEndian> template <typename StructT, bool BE>
std::string encrypt_fixed_size_data_section_t(const StructT& s, uint32_t round1_seed) { std::string encrypt_fixed_size_data_section_t(const StructT& s, uint32_t round1_seed) {
StructT encrypted = s; StructT encrypted = s;
encrypted.checksum = 0; encrypted.checksum = 0;
encrypted.round2_seed = random_object<uint32_t>(); encrypted.round2_seed = phosg::random_object<uint32_t>();
encrypted.checksum = crc32(&encrypted, sizeof(encrypted)); encrypted.checksum = phosg::crc32(&encrypted, sizeof(encrypted));
PSOV2Encryption round2_crypt(encrypted.round2_seed); PSOV2Encryption round2_crypt(encrypted.round2_seed);
if (IsBigEndian) { if (BE) {
round2_crypt.encrypt_big_endian(&encrypted, offsetof(StructT, round2_seed)); round2_crypt.encrypt_big_endian(&encrypted, offsetof(StructT, round2_seed));
} else { } else {
round2_crypt.encrypt(&encrypted, offsetof(StructT, round2_seed)); round2_crypt.encrypt(&encrypted, offsetof(StructT, round2_seed));
} }
return encrypt_data_section<IsBigEndian>(&encrypted, sizeof(StructT), round1_seed); return encrypt_data_section<BE>(&encrypted, sizeof(StructT), round1_seed);
} }
std::string decrypt_gci_fixed_size_data_section_for_salvage( std::string decrypt_gci_fixed_size_data_section_for_salvage(
+43 -43
View File
@@ -171,8 +171,8 @@ prepare_server_init_contents_console(
void send_server_init_dc_pc_v3(shared_ptr<Client> c, uint8_t flags) { void send_server_init_dc_pc_v3(shared_ptr<Client> c, uint8_t flags) {
bool initial_connection = (flags & SendServerInitFlag::IS_INITIAL_CONNECTION); bool initial_connection = (flags & SendServerInitFlag::IS_INITIAL_CONNECTION);
uint8_t command = initial_connection ? 0x17 : 0x02; uint8_t command = initial_connection ? 0x17 : 0x02;
uint32_t server_key = random_object<uint32_t>(); uint32_t server_key = phosg::random_object<uint32_t>();
uint32_t client_key = random_object<uint32_t>(); uint32_t client_key = phosg::random_object<uint32_t>();
auto cmd = prepare_server_init_contents_console(server_key, client_key, initial_connection); auto cmd = prepare_server_init_contents_console(server_key, client_key, initial_connection);
send_command_t(c, command, 0x00, cmd); send_command_t(c, command, 0x00, cmd);
@@ -224,8 +224,8 @@ void send_server_init_bb(shared_ptr<Client> c, uint8_t flags) {
bool use_secondary_message = (flags & SendServerInitFlag::USE_SECONDARY_MESSAGE); bool use_secondary_message = (flags & SendServerInitFlag::USE_SECONDARY_MESSAGE);
parray<uint8_t, 0x30> server_key; parray<uint8_t, 0x30> server_key;
parray<uint8_t, 0x30> client_key; parray<uint8_t, 0x30> client_key;
random_data(server_key.data(), server_key.bytes()); phosg::random_data(server_key.data(), server_key.bytes());
random_data(client_key.data(), client_key.bytes()); phosg::random_data(client_key.data(), client_key.bytes());
auto cmd = prepare_server_init_contents_bb(server_key, client_key, flags); auto cmd = prepare_server_init_contents_bb(server_key, client_key, flags);
send_command_t(c, use_secondary_message ? 0x9B : 0x03, 0x00, cmd); send_command_t(c, use_secondary_message ? 0x9B : 0x03, 0x00, cmd);
@@ -408,11 +408,11 @@ string prepare_send_function_call_data(
data = code->generate_client_command(label_writes, suffix_data, suffix_size, override_relocations_offset); data = code->generate_client_command(label_writes, suffix_data, suffix_size, override_relocations_offset);
if (use_encrypted_format) { if (use_encrypted_format) {
uint32_t key = random_object<uint32_t>(); uint32_t key = phosg::random_object<uint32_t>();
// This format was probably never used on any little-endian system, but we // This format was probably never used on any little-endian system, but we
// implement the way it would probably work there if it was used. // implement the way it would probably work there if it was used.
StringWriter w; phosg::StringWriter w;
if (code->is_big_endian()) { if (code->is_big_endian()) {
w.put_u32b(data.size()); w.put_u32b(data.size());
w.put_u32b(key); w.put_u32b(key);
@@ -437,7 +437,7 @@ string prepare_send_function_call_data(
} }
} }
StringWriter w; phosg::StringWriter w;
w.put(S_ExecuteCode_B2{data.size(), checksum_addr, checksum_size}); w.put(S_ExecuteCode_B2{data.size(), checksum_addr, checksum_size});
w.write(data); w.write(data);
return std::move(w.str()); return std::move(w.str());
@@ -524,7 +524,7 @@ bool send_protected_command(std::shared_ptr<Client> c, const void* data, size_t
try { try {
auto s = c->require_server_state(); auto s = c->require_server_state();
auto fn = s->function_code_index->get_patch("CallProtectedHandler", c->config.specific_version); auto fn = s->function_code_index->get_patch("CallProtectedHandler", c->config.specific_version);
uint32_t size_label_value = is_big_endian(c->version()) ? data.size() : bswap32(data.size()); uint32_t size_label_value = is_big_endian(c->version()) ? data.size() : phosg::bswap32(data.size());
send_function_call(c, fn, {{"size", size_label_value}}, data.data(), data.size()); send_function_call(c, fn, {{"size", size_label_value}}, data.data(), data.size());
c->function_call_response_queue.emplace_back(empty_function_call_response_handler); c->function_call_response_queue.emplace_back(empty_function_call_response_handler);
if (echo_to_lobby) { if (echo_to_lobby) {
@@ -777,7 +777,7 @@ enum class ColorMode {
static void send_text( static void send_text(
Channel& ch, Channel& ch,
StringWriter& w, phosg::StringWriter& w,
uint16_t command, uint16_t command,
uint32_t flag, uint32_t flag,
const string& text, const string& text,
@@ -800,7 +800,7 @@ static void send_text(
break; break;
} }
} catch (const runtime_error& e) { } catch (const runtime_error& e) {
log_warning("Failed to encode message for %02hX command: %s", command, e.what()); phosg::log_warning("Failed to encode message for %02hX command: %s", command, e.what());
return; return;
} }
@@ -817,12 +817,12 @@ static void send_text(
} }
static void send_text(Channel& ch, uint16_t command, uint32_t flag, const string& text, ColorMode color_mode) { static void send_text(Channel& ch, uint16_t command, uint32_t flag, const string& text, ColorMode color_mode) {
StringWriter w; phosg::StringWriter w;
send_text(ch, w, command, flag, text, color_mode); send_text(ch, w, command, flag, text, color_mode);
} }
static void send_header_text(Channel& ch, uint16_t command, uint32_t guild_card_number, const string& text, ColorMode color_mode) { static void send_header_text(Channel& ch, uint16_t command, uint32_t guild_card_number, const string& text, ColorMode color_mode) {
StringWriter w; phosg::StringWriter w;
w.put(SC_TextHeader_01_06_11_B0_EE({0, guild_card_number})); w.put(SC_TextHeader_01_06_11_B0_EE({0, guild_card_number}));
send_text(ch, w, command, 0x00, text, color_mode); send_text(ch, w, command, 0x00, text, color_mode);
} }
@@ -861,10 +861,10 @@ void send_ep3_timed_message_box(Channel& ch, uint32_t frames, const string& mess
try { try {
encoded = tt_encode_marked(add_color(message), ch.language, false); encoded = tt_encode_marked(add_color(message), ch.language, false);
} catch (const runtime_error& e) { } catch (const runtime_error& e) {
log_warning("Failed to encode message for EA command: %s", e.what()); phosg::log_warning("Failed to encode message for EA command: %s", e.what());
return; return;
} }
StringWriter w; phosg::StringWriter w;
w.put<S_TimedMessageBoxHeader_Ep3_EA>({frames}); w.put<S_TimedMessageBoxHeader_Ep3_EA>({frames});
w.write(encoded); w.write(encoded);
w.put_u8(0); w.put_u8(0);
@@ -926,7 +926,7 @@ void send_text_message(shared_ptr<ServerState> s, const string& text) {
__attribute__((format(printf, 2, 3))) void send_ep3_text_message_printf(shared_ptr<ServerState> s, const char* format, ...) { __attribute__((format(printf, 2, 3))) void send_ep3_text_message_printf(shared_ptr<ServerState> s, const char* format, ...) {
va_list va; va_list va;
va_start(va, format); va_start(va, format);
string buf = string_vprintf(format, va); string buf = phosg::string_vprintf(format, va);
va_end(va); va_end(va);
for (auto& it : s->id_to_lobby) { for (auto& it : s->id_to_lobby) {
for (auto& c : it.second->clients) { for (auto& c : it.second->clients) {
@@ -976,7 +976,7 @@ string prepare_chat_data(
} }
data.append(from_name); data.append(from_name);
if (version == Version::DC_NTE) { if (version == Version::DC_NTE) {
data.append(string_printf(">%X", from_client_id)); data.append(phosg::string_printf(">%X", from_client_id));
} else { } else {
data.append(1, '\t'); data.append(1, '\t');
} }
@@ -1012,7 +1012,7 @@ void send_chat_message_from_client(Channel& ch, const string& text, char private
} }
void send_prepared_chat_message(shared_ptr<Client> c, uint32_t from_guild_card_number, const string& prepared_data) { void send_prepared_chat_message(shared_ptr<Client> c, uint32_t from_guild_card_number, const string& prepared_data) {
StringWriter w; phosg::StringWriter w;
w.put(SC_TextHeader_01_06_11_B0_EE{0, from_guild_card_number}); w.put(SC_TextHeader_01_06_11_B0_EE{0, from_guild_card_number});
w.write(prepared_data); w.write(prepared_data);
w.put_u8(0); w.put_u8(0);
@@ -1066,7 +1066,7 @@ void send_simple_mail_bb(shared_ptr<Client> c, uint32_t from_guild_card_number,
cmd.from_guild_card_number = from_guild_card_number; cmd.from_guild_card_number = from_guild_card_number;
cmd.from_name.encode(from_name, c->language()); cmd.from_name.encode(from_name, c->language());
cmd.to_guild_card_number = c->login->account->account_id; cmd.to_guild_card_number = c->login->account->account_id;
cmd.received_date.encode(format_time(now()), c->language()); cmd.received_date.encode(phosg::format_time(phosg::now()), c->language());
cmd.text.encode(text, c->language()); cmd.text.encode(text, c->language());
send_command_t(c, 0x81, 0x00, cmd); send_command_t(c, 0x81, 0x00, cmd);
} }
@@ -1191,11 +1191,11 @@ void send_card_search_result_t(
string location_string; string location_string;
if (result_lobby->is_game()) { if (result_lobby->is_game()) {
location_string = string_printf("%s,,BLOCK01,%s", result_lobby->name.c_str(), s->name.c_str()); location_string = phosg::string_printf("%s,,BLOCK01,%s", result_lobby->name.c_str(), s->name.c_str());
} else if (result_lobby->is_ep3()) { } else if (result_lobby->is_ep3()) {
location_string = string_printf("BLOCK01-C%02" PRIu32 ",,BLOCK01,%s", result_lobby->lobby_id - 15, s->name.c_str()); location_string = phosg::string_printf("BLOCK01-C%02" PRIu32 ",,BLOCK01,%s", result_lobby->lobby_id - 15, s->name.c_str());
} else { } else {
location_string = string_printf("BLOCK01-%02" PRIu32 ",,BLOCK01,%s", result_lobby->lobby_id, s->name.c_str()); location_string = phosg::string_printf("BLOCK01-%02" PRIu32 ",,BLOCK01,%s", result_lobby->lobby_id, s->name.c_str());
} }
cmd.location_string.encode(location_string, c->language()); cmd.location_string.encode(location_string, c->language());
cmd.extension.lobby_refs[0].menu_id = MenuID::LOBBY; cmd.extension.lobby_refs[0].menu_id = MenuID::LOBBY;
@@ -2610,7 +2610,7 @@ void send_game_join_sync_command_compressed(
uint8_t dc_nte_sc, uint8_t dc_nte_sc,
uint8_t dc_11_2000_sc, uint8_t dc_11_2000_sc,
uint8_t sc) { uint8_t sc) {
StringWriter w; phosg::StringWriter w;
if (is_pre_v1(c->version())) { if (is_pre_v1(c->version())) {
G_SyncGameStateHeader_DCNTE_6x6B_6x6C_6x6D_6x6E compressed_header; G_SyncGameStateHeader_DCNTE_6x6B_6x6C_6x6D_6x6E compressed_header;
compressed_header.header.basic_header.subcommand = (c->version() == Version::DC_NTE) ? dc_nte_sc : dc_11_2000_sc; compressed_header.header.basic_header.subcommand = (c->version() == Version::DC_NTE) ? dc_nte_sc : dc_11_2000_sc;
@@ -2648,7 +2648,7 @@ void send_game_join_sync_command_compressed(
void send_game_item_state(shared_ptr<Client> c) { void send_game_item_state(shared_ptr<Client> c) {
auto l = c->require_lobby(); auto l = c->require_lobby();
auto s = c->require_server_state(); auto s = c->require_server_state();
StringWriter floor_items_w; phosg::StringWriter floor_items_w;
G_SyncItemState_6x6D_Decompressed decompressed_header; G_SyncItemState_6x6D_Decompressed decompressed_header;
for (size_t z = 0; z < 12; z++) { for (size_t z = 0; z < 12; z++) {
@@ -2689,7 +2689,7 @@ void send_game_item_state(shared_ptr<Client> c) {
} }
} }
StringWriter decompressed_w; phosg::StringWriter decompressed_w;
decompressed_w.put(decompressed_header); decompressed_w.put(decompressed_header);
decompressed_w.write(floor_items_w.str()); decompressed_w.write(floor_items_w.str());
const auto& data = decompressed_w.str(); const auto& data = decompressed_w.str();
@@ -2756,7 +2756,7 @@ void send_game_set_state(shared_ptr<Client> c) {
header.switch_flags_size = is_v1(c->version()) ? 0x200 : 0x240; header.switch_flags_size = is_v1(c->version()) ? 0x200 : 0x240;
header.total_size = header.entity_set_flags_size + header.event_set_flags_size + header.switch_flags_size; header.total_size = header.entity_set_flags_size + header.event_set_flags_size + header.switch_flags_size;
StringWriter w; phosg::StringWriter w;
w.put(header); w.put(header);
w.put(entity_set_flags_header); w.put(entity_set_flags_header);
for (const auto& obj : l->map->objects) { for (const auto& obj : l->map->objects) {
@@ -2783,7 +2783,7 @@ void send_game_flag_state_t(shared_ptr<Client> c) {
auto l = c->require_lobby(); auto l = c->require_lobby();
if (l->quest_flags_known) { // Not all flags known; send multiple 6x75s if (l->quest_flags_known) { // Not all flags known; send multiple 6x75s
StringWriter w; phosg::StringWriter w;
bool use_v3_cmd = !is_v1_or_v2(c->version()) || (c->version() == Version::GC_NTE); bool use_v3_cmd = !is_v1_or_v2(c->version()) || (c->version() == Version::GC_NTE);
for (uint8_t difficulty = 0; difficulty < 4; difficulty++) { for (uint8_t difficulty = 0; difficulty < 4; difficulty++) {
if ((difficulty != l->difficulty) && !use_v3_cmd) { if ((difficulty != l->difficulty) && !use_v3_cmd) {
@@ -3053,7 +3053,7 @@ void send_bank(shared_ptr<Client> c) {
G_BankContentsHeader_BB_6xBC cmd = { G_BankContentsHeader_BB_6xBC cmd = {
{{0xBC, 0, 0}, sizeof(G_BankContentsHeader_BB_6xBC) + items.size() * sizeof(PlayerBankItem)}, {{0xBC, 0, 0}, sizeof(G_BankContentsHeader_BB_6xBC) + items.size() * sizeof(PlayerBankItem)},
random_object<uint32_t>(), phosg::random_object<uint32_t>(),
bank.num_items, bank.num_items,
bank.meseta}; bank.meseta};
@@ -3161,7 +3161,7 @@ void send_ep3_card_list_update(shared_ptr<Client> c) {
? s->ep3_card_index_trial->get_compressed_definitions() ? s->ep3_card_index_trial->get_compressed_definitions()
: s->ep3_card_index->get_compressed_definitions(); : s->ep3_card_index->get_compressed_definitions();
StringWriter w; phosg::StringWriter w;
w.put_u32l(data.size()); w.put_u32l(data.size());
w.write(data); w.write(data);
@@ -3174,7 +3174,7 @@ void send_ep3_media_update(
uint32_t type, uint32_t type,
uint32_t which, uint32_t which,
const string& compressed_data) { const string& compressed_data) {
StringWriter w; phosg::StringWriter w;
w.put<S_UpdateMediaHeader_Ep3_B9>({type, which, compressed_data.size(), 0}); w.put<S_UpdateMediaHeader_Ep3_B9>({type, which, compressed_data.size(), 0});
w.write(compressed_data); w.write(compressed_data);
while (w.size() & 3) { while (w.size() & 3) {
@@ -3371,7 +3371,7 @@ string ep3_description_for_client(shared_ptr<Client> c) {
throw runtime_error("client is not Episode 3"); throw runtime_error("client is not Episode 3");
} }
auto p = c->character(); auto p = c->character();
return string_printf( return phosg::string_printf(
"%s CLv%" PRIu32 " %c", "%s CLv%" PRIu32 " %c",
name_for_char_class(p->disp.visual.char_class), name_for_char_class(p->disp.visual.char_class),
p->disp.stats.level + 1, p->disp.stats.level + 1,
@@ -3558,7 +3558,7 @@ void send_ep3_set_tournament_player_decks_t(shared_ptr<Client> c) {
if ((c->version() != Version::GC_EP3_NTE) && if ((c->version() != Version::GC_EP3_NTE) &&
!(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) { !(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) {
uint8_t mask_key = (random_object<uint32_t>() % 0xFF) + 1; uint8_t mask_key = (phosg::random_object<uint32_t>() % 0xFF) + 1;
set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key); set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key);
} }
@@ -3604,8 +3604,8 @@ void send_ep3_tournament_match_result(shared_ptr<Lobby> l, uint32_t meseta_rewar
G_TournamentMatchResult_Ep3_6xB4x51 cmd; G_TournamentMatchResult_Ep3_6xB4x51 cmd;
cmd.match_description.encode((match == tourn->get_final_match()) cmd.match_description.encode((match == tourn->get_final_match())
? string_printf("(%s) Final match", tourn->get_name().c_str()) ? phosg::string_printf("(%s) Final match", tourn->get_name().c_str())
: string_printf("(%s) Round %zu", tourn->get_name().c_str(), match->round_num), : phosg::string_printf("(%s) Round %zu", tourn->get_name().c_str(), match->round_num),
lc->language()); lc->language());
cmd.names_entries[0].team_name.encode(match->preceding_a->winner_team->name, lc->language()); cmd.names_entries[0].team_name.encode(match->preceding_a->winner_team->name, lc->language());
write_player_names(cmd.names_entries[0], match->preceding_a->winner_team); write_player_names(cmd.names_entries[0], match->preceding_a->winner_team);
@@ -3620,7 +3620,7 @@ void send_ep3_tournament_match_result(shared_ptr<Lobby> l, uint32_t meseta_rewar
cmd.meseta_reward_text.encode("You got %s meseta!", 1); cmd.meseta_reward_text.encode("You got %s meseta!", 1);
if ((lc->version() != Version::GC_EP3_NTE) && if ((lc->version() != Version::GC_EP3_NTE) &&
!(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) { !(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) {
uint8_t mask_key = (random_object<uint32_t>() % 0xFF) + 1; uint8_t mask_key = (phosg::random_object<uint32_t>() % 0xFF) + 1;
set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key); set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key);
} }
send_command_t(lc, 0xC9, 0x00, cmd); send_command_t(lc, 0xC9, 0x00, cmd);
@@ -3656,7 +3656,7 @@ void send_ep3_update_game_metadata(shared_ptr<Lobby> l) {
cmd.total_spectators = total_spectators; cmd.total_spectators = total_spectators;
if ((l->base_version != Version::GC_EP3_NTE) && if ((l->base_version != Version::GC_EP3_NTE) &&
!(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) { !(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) {
uint8_t mask_key = (random_object<uint32_t>() % 0xFF) + 1; uint8_t mask_key = (phosg::random_object<uint32_t>() % 0xFF) + 1;
set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key); set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key);
} }
// Note: We can't use send_command_t(l, ...) here because that would send // Note: We can't use send_command_t(l, ...) here because that would send
@@ -3674,9 +3674,9 @@ void send_ep3_update_game_metadata(shared_ptr<Lobby> l) {
auto tourn = l->tournament_match ? l->tournament_match->tournament.lock() : 0; auto tourn = l->tournament_match ? l->tournament_match->tournament.lock() : 0;
if (l->tournament_match && tourn) { if (l->tournament_match && tourn) {
if (tourn->get_final_match() == l->tournament_match) { if (tourn->get_final_match() == l->tournament_match) {
text = string_printf("Viewing final match of tournament %s", tourn->get_name().c_str()); text = phosg::string_printf("Viewing final match of tournament %s", tourn->get_name().c_str());
} else { } else {
text = string_printf( text = phosg::string_printf(
"Viewing match in round %zu of tournament %s", "Viewing match in round %zu of tournament %s",
l->tournament_match->round_num, tourn->get_name().c_str()); l->tournament_match->round_num, tourn->get_name().c_str());
} }
@@ -3695,7 +3695,7 @@ void send_ep3_update_game_metadata(shared_ptr<Lobby> l) {
cmd.text.encode(text, 1); cmd.text.encode(text, 1);
if ((watcher_l->base_version != Version::GC_EP3_NTE) && if ((watcher_l->base_version != Version::GC_EP3_NTE) &&
!(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) { !(s->ep3_behavior_flags & Episode3::BehaviorFlag::DISABLE_MASKING)) {
uint8_t mask_key = (random_object<uint32_t>() % 0xFF) + 1; uint8_t mask_key = (phosg::random_object<uint32_t>() % 0xFF) + 1;
set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key); set_mask_for_ep3_game_command(&cmd, sizeof(cmd), mask_key);
} }
send_command_t(watcher_l, 0xC9, 0x00, cmd); send_command_t(watcher_l, 0xC9, 0x00, cmd);
@@ -3864,7 +3864,7 @@ void send_open_quest_file(
// the client should apply backpressure to avoid bad situations, but we have // the client should apply backpressure to avoid bad situations, but we have
// to deal with it here instead. // to deal with it here instead.
size_t total_chunks = (contents->size() + 0x3FF) / 0x400; size_t total_chunks = (contents->size() + 0x3FF) / 0x400;
size_t chunks_to_send = is_gc(c->version()) ? min<size_t>(GC_QUEST_LOAD_MAX_CHUNKS_IN_FLIGHT, total_chunks) : total_chunks; size_t chunks_to_send = is_v1_or_v2(c->version()) ? total_chunks : min<size_t>(V3_V4_QUEST_LOAD_MAX_CHUNKS_IN_FLIGHT, total_chunks);
for (size_t z = 0; z < chunks_to_send; z++) { for (size_t z = 0; z < chunks_to_send; z++) {
size_t offset = z * 0x400; size_t offset = z * 0x400;
@@ -3964,7 +3964,7 @@ void send_ep3_card_auction(shared_ptr<Lobby> l) {
num_cards = s->ep3_card_auction_min_size; num_cards = s->ep3_card_auction_min_size;
} else { } else {
num_cards = s->ep3_card_auction_min_size + num_cards = s->ep3_card_auction_min_size +
(random_object<uint16_t>() % (s->ep3_card_auction_max_size - s->ep3_card_auction_min_size + 1)); (phosg::random_object<uint16_t>() % (s->ep3_card_auction_max_size - s->ep3_card_auction_min_size + 1));
} }
num_cards = min<uint16_t>(num_cards, 0x14); num_cards = min<uint16_t>(num_cards, 0x14);
@@ -3980,7 +3980,7 @@ void send_ep3_card_auction(shared_ptr<Lobby> l) {
S_StartCardAuction_Ep3_EF cmd; S_StartCardAuction_Ep3_EF cmd;
cmd.points_available = s->ep3_card_auction_points; cmd.points_available = s->ep3_card_auction_points;
for (size_t z = 0; z < num_cards; z++) { for (size_t z = 0; z < num_cards; z++) {
uint64_t v = random_object<uint64_t>() % distribution_size; uint64_t v = phosg::random_object<uint64_t>() % distribution_size;
for (const auto& e : s->ep3_card_auction_pool) { for (const auto& e : s->ep3_card_auction_pool) {
if (v >= e.probability) { if (v >= e.probability) {
v -= e.probability; v -= e.probability;
@@ -4005,7 +4005,7 @@ void send_ep3_disband_watcher_lobbies(shared_ptr<Lobby> primary_l) {
} }
void send_server_time(shared_ptr<Client> c) { void send_server_time(shared_ptr<Client> c) {
uint64_t t = now(); uint64_t t = phosg::now();
time_t t_secs = t / 1000000; time_t t_secs = t / 1000000;
struct tm t_parsed; struct tm t_parsed;
@@ -4015,7 +4015,7 @@ void send_server_time(shared_ptr<Client> c) {
size_t len = strftime(time_str.data(), time_str.size(), size_t len = strftime(time_str.data(), time_str.size(),
"%Y:%m:%d: %H:%M:%S.000", &t_parsed); "%Y:%m:%d: %H:%M:%S.000", &t_parsed);
if (len == 0) { if (len == 0) {
throw runtime_error("format_time buffer too short"); throw runtime_error("phosg::format_time buffer too short");
} }
time_str.resize(len); time_str.resize(len);

Some files were not shown because too many files have changed in this diff Show More