clang-format everything
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
Standard: c++20
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 2
|
||||
ColumnLimit: 0
|
||||
AccessModifierOffset: -2
|
||||
NamespaceIndentation: None
|
||||
BreakBeforeBraces: Custom
|
||||
PointerAlignment: Left
|
||||
IndentCaseLabels: true
|
||||
PackConstructorInitializers: CurrentLine
|
||||
BraceWrapping:
|
||||
AfterEnum: false
|
||||
AfterStruct: false
|
||||
AfterClass: false
|
||||
SplitEmptyFunction: false
|
||||
AfterControlStatement: false
|
||||
AfterNamespace: false
|
||||
AfterFunction: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
AlignTrailingComments: false
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignOperands: DontAlign
|
||||
AlignEscapedNewlines: Left
|
||||
+1
-4
@@ -8,8 +8,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
template <bool IsBigEndian>
|
||||
struct BMLHeader {
|
||||
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
|
||||
@@ -54,8 +52,7 @@ void BMLArchive::load_t() {
|
||||
size_t gvm_offset = offset;
|
||||
offset = (offset + entry.compressed_gvm_size + 0x1F) & (~0x1F);
|
||||
|
||||
this->entries.emplace(entry.filename, Entry{
|
||||
data_offset, entry.compressed_size, gvm_offset, entry.compressed_gvm_size});
|
||||
this->entries.emplace(entry.filename, Entry{data_offset, entry.compressed_size, gvm_offset, entry.compressed_gvm_size});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
|
||||
class BMLArchive {
|
||||
public:
|
||||
BMLArchive(std::shared_ptr<const std::string> data, bool big_endian);
|
||||
|
||||
+4
-6
@@ -8,8 +8,8 @@
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -24,15 +24,13 @@
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "SendCommands.hh"
|
||||
#include "ProxyCommands.hh"
|
||||
#include "ReceiveCommands.hh"
|
||||
#include "ReceiveSubcommands.hh"
|
||||
#include "ProxyCommands.hh"
|
||||
#include "SendCommands.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
CatSession::CatSession(
|
||||
shared_ptr<struct event_base> base,
|
||||
const struct sockaddr_storage& remote,
|
||||
@@ -133,7 +131,7 @@ void CatSession::on_channel_error(short events) {
|
||||
}
|
||||
}
|
||||
|
||||
void CatSession::print_prompt() { }
|
||||
void CatSession::print_prompt() {}
|
||||
|
||||
void CatSession::execute_command(const std::string& command) {
|
||||
string full_cmd = parse_data_string(command, nullptr, ParseDataFlags::ALLOW_FILES);
|
||||
|
||||
+5
-7
@@ -2,22 +2,20 @@
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "PSOEncryption.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "ServerState.hh"
|
||||
#include "Shell.hh"
|
||||
|
||||
|
||||
|
||||
class CatSession : public Shell {
|
||||
public:
|
||||
CatSession(
|
||||
|
||||
+10
-22
@@ -1,9 +1,9 @@
|
||||
#include "Channel.hh"
|
||||
|
||||
#include <errno.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/event.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -15,19 +15,13 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
extern bool use_terminal_colors;
|
||||
|
||||
|
||||
|
||||
static void flush_and_free_bufferevent(struct bufferevent* bev) {
|
||||
bufferevent_flush(bev, EV_READ | EV_WRITE, BEV_FINISHED);
|
||||
bufferevent_free(bev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Channel::Channel(
|
||||
GameVersion version,
|
||||
on_command_received_t on_command_received,
|
||||
@@ -114,8 +108,6 @@ void Channel::set_bufferevent(struct bufferevent* bev) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Channel::disconnect() {
|
||||
if (this->bev.get()) {
|
||||
// If the output buffer is not empty, move the bufferevent into the draining
|
||||
@@ -157,15 +149,12 @@ void Channel::disconnect() {
|
||||
this->crypt_out.reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Channel::Message Channel::recv(bool print_contents) {
|
||||
struct evbuffer* buf = bufferevent_get_input(this->bev.get());
|
||||
|
||||
size_t header_size = (this->version == GameVersion::BB) ? 8 : 4;
|
||||
PSOCommandHeader header;
|
||||
if (evbuffer_copyout(buf, &header, header_size)
|
||||
< static_cast<ssize_t>(header_size)) {
|
||||
if (evbuffer_copyout(buf, &header, header_size) < static_cast<ssize_t>(header_size)) {
|
||||
throw out_of_range("no command available");
|
||||
}
|
||||
|
||||
@@ -179,7 +168,8 @@ Channel::Message Channel::recv(bool print_contents) {
|
||||
// is not reflected in the size field. This logic does not occur if encryption
|
||||
// is not yet enabled.
|
||||
size_t command_physical_size = (this->crypt_in.get() && (version == GameVersion::BB))
|
||||
? ((command_logical_size + 7) & ~7) : command_logical_size;
|
||||
? ((command_logical_size + 7) & ~7)
|
||||
: command_logical_size;
|
||||
if (evbuffer_get_length(buf) < command_physical_size) {
|
||||
throw out_of_range("no command available");
|
||||
}
|
||||
@@ -190,8 +180,7 @@ Channel::Message Channel::recv(bool print_contents) {
|
||||
// consistent state.
|
||||
|
||||
string header_data(header_size, '\0');
|
||||
if (evbuffer_remove(buf, header_data.data(), header_data.size())
|
||||
< static_cast<ssize_t>(header_data.size())) {
|
||||
if (evbuffer_remove(buf, header_data.data(), header_data.size()) < static_cast<ssize_t>(header_data.size())) {
|
||||
throw logic_error("enough bytes available, but could not remove them");
|
||||
}
|
||||
if (this->crypt_in.get()) {
|
||||
@@ -199,8 +188,7 @@ Channel::Message Channel::recv(bool print_contents) {
|
||||
}
|
||||
|
||||
string command_data(command_physical_size - header_size, '\0');
|
||||
if (evbuffer_remove(buf, command_data.data(), command_data.size())
|
||||
< static_cast<ssize_t>(command_data.size())) {
|
||||
if (evbuffer_remove(buf, command_data.data(), command_data.size()) < static_cast<ssize_t>(command_data.size())) {
|
||||
throw logic_error("enough bytes available, but could not remove them");
|
||||
}
|
||||
|
||||
@@ -222,12 +210,14 @@ Channel::Message Channel::recv(bool print_contents) {
|
||||
}
|
||||
|
||||
if (version == GameVersion::BB) {
|
||||
command_data_log.info("Received from %s (version=BB command=%04hX flag=%08" PRIX32 ")",
|
||||
command_data_log.info(
|
||||
"Received from %s (version=BB command=%04hX flag=%08" PRIX32 ")",
|
||||
this->name.c_str(),
|
||||
header.command(this->version),
|
||||
header.flag(this->version));
|
||||
} else {
|
||||
command_data_log.info("Received from %s (version=%s command=%02hX flag=%02" PRIX32 ")",
|
||||
command_data_log.info(
|
||||
"Received from %s (version=%s command=%02hX flag=%02" PRIX32 ")",
|
||||
this->name.c_str(),
|
||||
name_for_version(this->version),
|
||||
header.command(this->version),
|
||||
@@ -376,8 +366,6 @@ void Channel::send(const string& data, bool print_contents) {
|
||||
return this->send(data.data(), data.size(), print_contents);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Channel::dispatch_on_input(struct bufferevent*, void* ctx) {
|
||||
Channel* ch = reinterpret_cast<Channel*>(ctx);
|
||||
// The client can be disconnected during on_command_received, so we have to
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include "PSOProtocol.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
|
||||
|
||||
struct Channel {
|
||||
std::unique_ptr<struct bufferevent, void (*)(struct bufferevent*)> bev;
|
||||
struct sockaddr_storage local_addr;
|
||||
|
||||
+9
-20
@@ -2,12 +2,12 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Time.hh>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Client.hh"
|
||||
#include "Lobby.hh"
|
||||
@@ -21,16 +21,12 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Checks
|
||||
|
||||
|
||||
|
||||
class precondition_failed {
|
||||
public:
|
||||
precondition_failed(const std::u16string& user_msg) : user_msg(user_msg) { }
|
||||
precondition_failed(const std::u16string& user_msg) : user_msg(user_msg) {}
|
||||
~precondition_failed() = default;
|
||||
|
||||
const std::u16string& what() const {
|
||||
@@ -64,17 +60,13 @@ static void check_not_version(shared_ptr<Client> c, GameVersion version) {
|
||||
|
||||
static void check_is_game(shared_ptr<Lobby> l, bool is_game) {
|
||||
if (l->is_game() != is_game) {
|
||||
throw precondition_failed(is_game ?
|
||||
u"$C6This command cannot\nbe used in lobbies." :
|
||||
u"$C6This command cannot\nbe used in games.");
|
||||
throw precondition_failed(is_game ? u"$C6This command cannot\nbe used in lobbies." : u"$C6This command cannot\nbe used in games.");
|
||||
}
|
||||
}
|
||||
|
||||
static void check_is_ep3(shared_ptr<Client> c, bool is_ep3) {
|
||||
if (!!(c->flags & Client::Flag::IS_EPISODE_3) != is_ep3) {
|
||||
throw precondition_failed(is_ep3 ?
|
||||
u"$C6This command can only\nbe used in Episode 3." :
|
||||
u"$C6This command cannot\nbe used in Episode 3.");
|
||||
throw precondition_failed(is_ep3 ? u"$C6This command can only\nbe used in Episode 3." : u"$C6This command cannot\nbe used in Episode 3.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,8 +82,6 @@ static void check_is_leader(shared_ptr<Lobby> l, shared_ptr<Client> c) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Message commands
|
||||
|
||||
@@ -888,7 +878,8 @@ static void server_command_ban(shared_ptr<ServerState> s, shared_ptr<Lobby> l,
|
||||
uint64_t usecs = stoull(encode_sjis(args), nullptr, 0) * 1000000;
|
||||
|
||||
size_t unit_offset = 0;
|
||||
for (; isdigit(args[unit_offset]); unit_offset++);
|
||||
for (; isdigit(args[unit_offset]); unit_offset++)
|
||||
;
|
||||
if (args[unit_offset] == 'm') {
|
||||
usecs *= 60;
|
||||
} else if (args[unit_offset] == 'h') {
|
||||
@@ -1160,8 +1151,6 @@ static void proxy_command_item(shared_ptr<ServerState>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*server_handler_t)(shared_ptr<ServerState> s, shared_ptr<Lobby> l,
|
||||
@@ -1186,7 +1175,7 @@ static const unordered_map<u16string, ChatCommandDefinition> chat_commands({
|
||||
{u"$bbchar", {server_command_convert_char_to_bb, nullptr, u"Usage:\nbbchar <user> <pass> <1-4>"}},
|
||||
{u"$cheat", {server_command_cheat, nullptr, u"Usage:\ncheat"}},
|
||||
{u"$debug", {server_command_debug, nullptr, u"Usage:\ndebug"}},
|
||||
{u"$edit", {server_command_edit, nullptr , u"Usage:\nedit <stat> <value>"}},
|
||||
{u"$edit", {server_command_edit, nullptr, u"Usage:\nedit <stat> <value>"}},
|
||||
{u"$event", {server_command_lobby_event, proxy_command_lobby_event, u"Usage:\nevent <name>"}},
|
||||
{u"$exit", {server_command_exit, proxy_command_exit, u"Usage:\nexit"}},
|
||||
{u"$gc", {server_command_get_self_card, proxy_command_get_player_card, u"Usage:\ngc"}},
|
||||
|
||||
+2
-2
@@ -5,10 +5,10 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "ServerState.hh"
|
||||
#include "Lobby.hh"
|
||||
#include "Client.hh"
|
||||
#include "Lobby.hh"
|
||||
#include "ProxyServer.hh"
|
||||
#include "ServerState.hh"
|
||||
|
||||
void on_chat_command(std::shared_ptr<ServerState> s, std::shared_ptr<Lobby> l,
|
||||
std::shared_ptr<Client> c, const std::u16string& text);
|
||||
|
||||
+2
-11
@@ -1,9 +1,9 @@
|
||||
#include "Client.hh"
|
||||
|
||||
#include <errno.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/event.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -16,15 +16,10 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
const uint64_t CLIENT_CONFIG_MAGIC = 0x492A890E82AC9839;
|
||||
FileContentsCache client_options_cache(3600000000ULL);
|
||||
|
||||
static atomic<uint64_t> next_id(1);
|
||||
|
||||
|
||||
|
||||
ClientOptions::ClientOptions()
|
||||
: switch_assist(false),
|
||||
infinite_hp(false),
|
||||
@@ -43,9 +38,7 @@ ClientOptions::ClientOptions()
|
||||
ep3_infinite_meseta(false),
|
||||
red_name(false),
|
||||
blank_name(false),
|
||||
function_call_return_value(-1) { }
|
||||
|
||||
|
||||
function_call_return_value(-1) {}
|
||||
|
||||
Client::Client(
|
||||
struct bufferevent* bev,
|
||||
@@ -141,8 +134,6 @@ void Client::import_config(const ClientConfigBB& cc) {
|
||||
this->game_data.bb_player_index = cc.bb_player_index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Client::dispatch_save_game_data(evutil_socket_t, short, void* ctx) {
|
||||
reinterpret_cast<Client*>(ctx)->save_game_data();
|
||||
}
|
||||
|
||||
+5
-10
@@ -6,23 +6,18 @@
|
||||
|
||||
#include "Channel.hh"
|
||||
#include "CommandFormats.hh"
|
||||
#include "Episode3/BattleRecord.hh"
|
||||
#include "Episode3/Tournament.hh"
|
||||
#include "FileContentsCache.hh"
|
||||
#include "FunctionCompiler.hh"
|
||||
#include "License.hh"
|
||||
#include "PatchFileIndex.hh"
|
||||
#include "Player.hh"
|
||||
#include "PSOEncryption.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "PatchFileIndex.hh"
|
||||
#include "Player.hh"
|
||||
#include "Text.hh"
|
||||
#include "Episode3/BattleRecord.hh"
|
||||
#include "Episode3/Tournament.hh"
|
||||
|
||||
|
||||
|
||||
extern const uint64_t CLIENT_CONFIG_MAGIC;
|
||||
extern FileContentsCache client_options_cache;
|
||||
|
||||
|
||||
|
||||
struct ClientOptions {
|
||||
// Options used on both game and proxy server
|
||||
@@ -138,7 +133,7 @@ struct Client {
|
||||
uint8_t lobby_arrow_color; // lobby arrow color ID
|
||||
int64_t preferred_lobby_id; // <0 = no preference
|
||||
ClientGameData game_data;
|
||||
std::unique_ptr<struct event, void(*)(struct event*)> save_game_data_event;
|
||||
std::unique_ptr<struct event, void (*)(struct event*)> save_game_data_event;
|
||||
int16_t card_battle_table_number;
|
||||
uint16_t card_battle_table_seat_number;
|
||||
uint16_t card_battle_table_seat_state;
|
||||
|
||||
+96
-69
@@ -1,17 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "PSOProtocol.hh"
|
||||
#include "Text.hh"
|
||||
#include "Player.hh"
|
||||
#include "Episode3/DataIndex.hh"
|
||||
#include "Episode3/DeckState.hh"
|
||||
#include "Episode3/MapState.hh"
|
||||
#include "Episode3/PlayerStateSubordinates.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "Player.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
#define __packed__ __attribute__((packed))
|
||||
|
||||
@@ -45,8 +45,6 @@
|
||||
// Structures are sorted by command number. Long BB commands are placed in order
|
||||
// according to their low byte; for example, command 01EB is in position as EB.
|
||||
|
||||
|
||||
|
||||
// Text escape codes
|
||||
|
||||
// Most text fields allow the use of various escape codes to change decoding,
|
||||
@@ -85,8 +83,6 @@
|
||||
// - - $r: Right arrow
|
||||
// - - $u: Up arrow
|
||||
|
||||
|
||||
|
||||
// This is the format of newserv's security data, which we call the client
|
||||
// config. This data is opaque to the client, so this structure is not
|
||||
// technically part of the PSO protocol. Because it is opaque to the client, we
|
||||
@@ -124,8 +120,6 @@ struct ClientConfigBB {
|
||||
parray<uint8_t, 0x06> unused;
|
||||
} __packed__;
|
||||
|
||||
|
||||
|
||||
// Patch server commands
|
||||
|
||||
// The patch protocol is identical between PSO PC and PSO BB (the only versions
|
||||
@@ -309,7 +303,8 @@ struct S_Reconnect {
|
||||
le_uint16_t unused = 0;
|
||||
} __packed__;
|
||||
|
||||
struct S_Reconnect_Patch_14 : S_Reconnect<be_uint16_t> { } __packed__;
|
||||
struct S_Reconnect_Patch_14 : S_Reconnect<be_uint16_t> {
|
||||
} __packed__;
|
||||
|
||||
// 15 (S->C): Login failure
|
||||
// No arguments
|
||||
@@ -318,8 +313,6 @@ struct S_Reconnect_Patch_14 : S_Reconnect<be_uint16_t> { } __packed__;
|
||||
|
||||
// No commands beyond 15 are valid on the patch server.
|
||||
|
||||
|
||||
|
||||
// Game server commands
|
||||
|
||||
// 00: Invalid command
|
||||
@@ -482,8 +475,10 @@ struct S_UpdateClientConfig {
|
||||
ClientConfigT cfg;
|
||||
} __packed__;
|
||||
|
||||
struct S_UpdateClientConfig_DC_PC_V3_04 : S_UpdateClientConfig<ClientConfig> { } __packed__;
|
||||
struct S_UpdateClientConfig_BB_04 : S_UpdateClientConfig<ClientConfigBB> { } __packed__;
|
||||
struct S_UpdateClientConfig_DC_PC_V3_04 : S_UpdateClientConfig<ClientConfig> {
|
||||
} __packed__;
|
||||
struct S_UpdateClientConfig_BB_04 : S_UpdateClientConfig<ClientConfigBB> {
|
||||
} __packed__;
|
||||
|
||||
// 05: Disconnect
|
||||
// No arguments
|
||||
@@ -534,8 +529,10 @@ struct S_MenuEntry {
|
||||
le_uint16_t flags = 0x0F04; // Should be this value, apparently
|
||||
ptext<CharT, EntryLength> text;
|
||||
} __packed__;
|
||||
struct S_MenuEntry_PC_BB_07_1F : S_MenuEntry<char16_t, 0x11> { } __packed__;
|
||||
struct S_MenuEntry_DC_V3_07_1F : S_MenuEntry<char, 0x12> { } __packed__;
|
||||
struct S_MenuEntry_PC_BB_07_1F : S_MenuEntry<char16_t, 0x11> {
|
||||
} __packed__;
|
||||
struct S_MenuEntry_DC_V3_07_1F : S_MenuEntry<char, 0x12> {
|
||||
} __packed__;
|
||||
|
||||
// 08 (C->S): Request game list
|
||||
// No arguments
|
||||
@@ -569,8 +566,10 @@ struct S_GameMenuEntry {
|
||||
// 20 = Is challenge mode
|
||||
uint8_t flags = 0;
|
||||
} __packed__;
|
||||
struct S_GameMenuEntry_PC_BB_08 : S_GameMenuEntry<char16_t> { } __packed__;
|
||||
struct S_GameMenuEntry_DC_V3_08_Ep3_E6 : S_GameMenuEntry<char> { } __packed__;
|
||||
struct S_GameMenuEntry_PC_BB_08 : S_GameMenuEntry<char16_t> {
|
||||
} __packed__;
|
||||
struct S_GameMenuEntry_DC_V3_08_Ep3_E6 : S_GameMenuEntry<char> {
|
||||
} __packed__;
|
||||
|
||||
// 09 (C->S): Menu item info request
|
||||
// Server will respond with an 11 command, or an A3 or A5 if the specified menu
|
||||
@@ -660,16 +659,20 @@ struct C_MenuSelection_10_Flag01 {
|
||||
C_MenuSelection_10_Flag00 basic_cmd;
|
||||
ptext<CharT, 0x10> unknown_a1;
|
||||
} __packed__;
|
||||
struct C_MenuSelection_DC_V3_10_Flag01 : C_MenuSelection_10_Flag01<char> { } __packed__;
|
||||
struct C_MenuSelection_PC_BB_10_Flag01 : C_MenuSelection_10_Flag01<char16_t> { } __packed__;
|
||||
struct C_MenuSelection_DC_V3_10_Flag01 : C_MenuSelection_10_Flag01<char> {
|
||||
} __packed__;
|
||||
struct C_MenuSelection_PC_BB_10_Flag01 : C_MenuSelection_10_Flag01<char16_t> {
|
||||
} __packed__;
|
||||
|
||||
template <typename CharT>
|
||||
struct C_MenuSelection_10_Flag02 {
|
||||
C_MenuSelection_10_Flag00 basic_cmd;
|
||||
ptext<CharT, 0x10> password;
|
||||
} __packed__;
|
||||
struct C_MenuSelection_DC_V3_10_Flag02 : C_MenuSelection_10_Flag02<char> { } __packed__;
|
||||
struct C_MenuSelection_PC_BB_10_Flag02 : C_MenuSelection_10_Flag02<char16_t> { } __packed__;
|
||||
struct C_MenuSelection_DC_V3_10_Flag02 : C_MenuSelection_10_Flag02<char> {
|
||||
} __packed__;
|
||||
struct C_MenuSelection_PC_BB_10_Flag02 : C_MenuSelection_10_Flag02<char16_t> {
|
||||
} __packed__;
|
||||
|
||||
template <typename CharT>
|
||||
struct C_MenuSelection_10_Flag03 {
|
||||
@@ -677,8 +680,10 @@ struct C_MenuSelection_10_Flag03 {
|
||||
ptext<CharT, 0x10> unknown_a1;
|
||||
ptext<CharT, 0x10> password;
|
||||
} __packed__;
|
||||
struct C_MenuSelection_DC_V3_10_Flag03 : C_MenuSelection_10_Flag03<char> { } __packed__;
|
||||
struct C_MenuSelection_PC_BB_10_Flag03 : C_MenuSelection_10_Flag03<char16_t> { } __packed__;
|
||||
struct C_MenuSelection_DC_V3_10_Flag03 : C_MenuSelection_10_Flag03<char> {
|
||||
} __packed__;
|
||||
struct C_MenuSelection_PC_BB_10_Flag03 : C_MenuSelection_10_Flag03<char16_t> {
|
||||
} __packed__;
|
||||
|
||||
// 11 (S->C): Ship info
|
||||
// Same format as 01 command. The text appears in a small box in the lower-left
|
||||
@@ -748,7 +753,8 @@ struct C_WriteFileConfirmation_V3_BB_13_A7 {
|
||||
// Note: PSO XB seems to ignore the address field, which makes sense given its
|
||||
// networking architecture.
|
||||
|
||||
struct S_Reconnect_19 : S_Reconnect<le_uint16_t> { } __packed__;
|
||||
struct S_Reconnect_19 : S_Reconnect<le_uint16_t> {
|
||||
} __packed__;
|
||||
|
||||
// Because PSO PC and some versions of PSO DC/GC use the same port but different
|
||||
// protocols, we use a specially-crafted 19 command to send them to two
|
||||
@@ -915,11 +921,14 @@ struct S_GuildCardSearchResult {
|
||||
SC_MeetUserExtension<CharT> extension;
|
||||
} __packed__;
|
||||
struct S_GuildCardSearchResult_PC_41
|
||||
: S_GuildCardSearchResult<PSOCommandHeaderPC, char16_t> { } __packed__;
|
||||
: S_GuildCardSearchResult<PSOCommandHeaderPC, char16_t> {
|
||||
} __packed__;
|
||||
struct S_GuildCardSearchResult_DC_V3_41
|
||||
: S_GuildCardSearchResult<PSOCommandHeaderDCV3, char> { } __packed__;
|
||||
: S_GuildCardSearchResult<PSOCommandHeaderDCV3, char> {
|
||||
} __packed__;
|
||||
struct S_GuildCardSearchResult_BB_41
|
||||
: S_GuildCardSearchResult<PSOCommandHeaderBB, char16_t> { } __packed__;
|
||||
: S_GuildCardSearchResult<PSOCommandHeaderBB, char16_t> {
|
||||
} __packed__;
|
||||
|
||||
// 42: Invalid command
|
||||
// 43: Invalid command
|
||||
@@ -1084,8 +1093,10 @@ struct S_JoinGame {
|
||||
uint8_t unused3 = 0;
|
||||
} __packed__;
|
||||
|
||||
struct S_JoinGame_PC_64 : S_JoinGame<PlayerLobbyDataPC, PlayerDispDataDCPCV3> { } __packed__;
|
||||
struct S_JoinGame_DC_GC_64 : S_JoinGame<PlayerLobbyDataDCGC, PlayerDispDataDCPCV3> { } __packed__;
|
||||
struct S_JoinGame_PC_64 : S_JoinGame<PlayerLobbyDataPC, PlayerDispDataDCPCV3> {
|
||||
} __packed__;
|
||||
struct S_JoinGame_DC_GC_64 : S_JoinGame<PlayerLobbyDataDCGC, PlayerDispDataDCPCV3> {
|
||||
} __packed__;
|
||||
|
||||
struct S_JoinGame_GC_Ep3_64 : S_JoinGame_DC_GC_64 {
|
||||
// This field is only present if the game (and client) is Episode 3. Similarly
|
||||
@@ -1101,7 +1112,8 @@ struct S_JoinGame_XB_64 : S_JoinGame<PlayerLobbyDataXB, PlayerDispDataDCPCV3> {
|
||||
parray<le_uint32_t, 6> unknown_a1;
|
||||
} __packed__;
|
||||
|
||||
struct S_JoinGame_BB_64 : S_JoinGame<PlayerLobbyDataBB, PlayerDispDataBB> { } __packed__;
|
||||
struct S_JoinGame_BB_64 : S_JoinGame<PlayerLobbyDataBB, PlayerDispDataBB> {
|
||||
} __packed__;
|
||||
|
||||
// 65 (S->C): Add player to game
|
||||
// When a player joins an existing game, the joining player receives a 64
|
||||
@@ -1134,11 +1146,14 @@ struct S_JoinLobby {
|
||||
}
|
||||
} __packed__;
|
||||
struct S_JoinLobby_PC_65_67_68
|
||||
: S_JoinLobby<PlayerLobbyDataPC, PlayerDispDataDCPCV3> { } __packed__;
|
||||
: S_JoinLobby<PlayerLobbyDataPC, PlayerDispDataDCPCV3> {
|
||||
} __packed__;
|
||||
struct S_JoinLobby_DC_GC_65_67_68_Ep3_EB
|
||||
: S_JoinLobby<PlayerLobbyDataDCGC, PlayerDispDataDCPCV3> { } __packed__;
|
||||
: S_JoinLobby<PlayerLobbyDataDCGC, PlayerDispDataDCPCV3> {
|
||||
} __packed__;
|
||||
struct S_JoinLobby_BB_65_67_68
|
||||
: S_JoinLobby<PlayerLobbyDataBB, PlayerDispDataBB> { } __packed__;
|
||||
: S_JoinLobby<PlayerLobbyDataBB, PlayerDispDataBB> {
|
||||
} __packed__;
|
||||
|
||||
struct S_JoinLobby_XB_65_67_68 {
|
||||
uint8_t client_id = 0;
|
||||
@@ -1161,8 +1176,7 @@ struct S_JoinLobby_XB_65_67_68 {
|
||||
parray<Entry, 12> entries;
|
||||
|
||||
static inline size_t size(size_t used_entries) {
|
||||
return offsetof(S_JoinLobby_XB_65_67_68, entries)
|
||||
+ used_entries * sizeof(Entry);
|
||||
return offsetof(S_JoinLobby_XB_65_67_68, entries) + used_entries * sizeof(Entry);
|
||||
}
|
||||
} __packed__;
|
||||
|
||||
@@ -1267,8 +1281,10 @@ struct SC_SimpleMail_81 {
|
||||
ptext<CharT, 0x200> text;
|
||||
} __packed__;
|
||||
|
||||
struct SC_SimpleMail_PC_81 : SC_SimpleMail_81<char16_t> { } __packed__;
|
||||
struct SC_SimpleMail_DC_V3_81 : SC_SimpleMail_81<char> { } __packed__;
|
||||
struct SC_SimpleMail_PC_81 : SC_SimpleMail_81<char16_t> {
|
||||
} __packed__;
|
||||
struct SC_SimpleMail_DC_V3_81 : SC_SimpleMail_81<char> {
|
||||
} __packed__;
|
||||
|
||||
struct SC_SimpleMail_BB_81 {
|
||||
le_uint32_t player_tag = 0x00010000;
|
||||
@@ -1694,7 +1710,7 @@ struct C_Login_GC_9E : C_Login_DC_PC_GC_9D {
|
||||
union ClientConfigFields {
|
||||
ClientConfig cfg;
|
||||
parray<uint8_t, 0x20> data;
|
||||
ClientConfigFields() : data() { }
|
||||
ClientConfigFields() : data() {}
|
||||
} __packed__ client_config;
|
||||
} __packed__;
|
||||
struct C_LoginExtended_GC_9E : C_Login_GC_9E {
|
||||
@@ -1774,10 +1790,14 @@ struct S_QuestMenuEntry {
|
||||
ptext<CharT, 0x20> name;
|
||||
ptext<CharT, ShortDescLength> short_description;
|
||||
} __packed__;
|
||||
struct S_QuestMenuEntry_PC_A2_A4 : S_QuestMenuEntry<char16_t, 0x70> { } __packed__;
|
||||
struct S_QuestMenuEntry_DC_GC_A2_A4 : S_QuestMenuEntry<char, 0x70> { } __packed__;
|
||||
struct S_QuestMenuEntry_XB_A2_A4 : S_QuestMenuEntry<char, 0x80> { } __packed__;
|
||||
struct S_QuestMenuEntry_BB_A2_A4 : S_QuestMenuEntry<char16_t, 0x7A> { } __packed__;
|
||||
struct S_QuestMenuEntry_PC_A2_A4 : S_QuestMenuEntry<char16_t, 0x70> {
|
||||
} __packed__;
|
||||
struct S_QuestMenuEntry_DC_GC_A2_A4 : S_QuestMenuEntry<char, 0x70> {
|
||||
} __packed__;
|
||||
struct S_QuestMenuEntry_XB_A2_A4 : S_QuestMenuEntry<char, 0x80> {
|
||||
} __packed__;
|
||||
struct S_QuestMenuEntry_BB_A2_A4 : S_QuestMenuEntry<char16_t, 0x7A> {
|
||||
} __packed__;
|
||||
|
||||
// A3 (S->C): Quest information
|
||||
// Same format as 1A/D5 command (plain text)
|
||||
@@ -1948,8 +1968,10 @@ struct S_ExecuteCode_Footer_B2 {
|
||||
parray<U32T, 3> unused2;
|
||||
} __packed__;
|
||||
|
||||
struct S_ExecuteCode_Footer_GC_B2 : S_ExecuteCode_Footer_B2<true> { } __packed__;
|
||||
struct S_ExecuteCode_Footer_DC_PC_XB_BB_B2 : S_ExecuteCode_Footer_B2<false> { } __packed__;
|
||||
struct S_ExecuteCode_Footer_GC_B2 : S_ExecuteCode_Footer_B2<true> {
|
||||
} __packed__;
|
||||
struct S_ExecuteCode_Footer_DC_PC_XB_BB_B2 : S_ExecuteCode_Footer_B2<false> {
|
||||
} __packed__;
|
||||
|
||||
// B3 (C->S): Execute code and/or checksum memory result
|
||||
// Not used on versions that don't support the B2 command (see above).
|
||||
@@ -2138,9 +2160,12 @@ struct S_ChoiceSearchEntry {
|
||||
ItemIDT category_id = 0;
|
||||
ptext<CharT, 0x1C> text;
|
||||
} __packed__;
|
||||
struct S_ChoiceSearchEntry_DC_C0 : S_ChoiceSearchEntry<le_uint32_t, char> { } __packed__;
|
||||
struct S_ChoiceSearchEntry_V3_C0 : S_ChoiceSearchEntry<le_uint16_t, char> { } __packed__;
|
||||
struct S_ChoiceSearchEntry_PC_BB_C0 : S_ChoiceSearchEntry<le_uint16_t, char16_t> { } __packed__;
|
||||
struct S_ChoiceSearchEntry_DC_C0 : S_ChoiceSearchEntry<le_uint32_t, char> {
|
||||
} __packed__;
|
||||
struct S_ChoiceSearchEntry_V3_C0 : S_ChoiceSearchEntry<le_uint16_t, char> {
|
||||
} __packed__;
|
||||
struct S_ChoiceSearchEntry_PC_BB_C0 : S_ChoiceSearchEntry<le_uint16_t, char16_t> {
|
||||
} __packed__;
|
||||
|
||||
// Top-level categories are things like "Level", "Class", etc.
|
||||
// Choices for each top-level category immediately follow the category, so
|
||||
@@ -2175,8 +2200,10 @@ struct C_CreateGame {
|
||||
// players; if set to 1, it's v2-only.
|
||||
uint8_t episode = 0; // 1-4 on V3+ (3 on Episode 3); unused on DC/PC
|
||||
} __packed__;
|
||||
struct C_CreateGame_DC_V3_0C_C1_Ep3_EC : C_CreateGame<char> { } __packed__;
|
||||
struct C_CreateGame_PC_C1 : C_CreateGame<char16_t> { } __packed__;
|
||||
struct C_CreateGame_DC_V3_0C_C1_Ep3_EC : C_CreateGame<char> {
|
||||
} __packed__;
|
||||
struct C_CreateGame_PC_C1 : C_CreateGame<char16_t> {
|
||||
} __packed__;
|
||||
|
||||
struct C_CreateGame_BB_C1 : C_CreateGame<char16_t> {
|
||||
uint8_t solo_mode = 0;
|
||||
@@ -2187,8 +2214,10 @@ struct C_CreateGame_BB_C1 : C_CreateGame<char16_t> {
|
||||
// Server does not respond.
|
||||
// The ChoiceSearchConfig structure is defined in Player.hh.
|
||||
|
||||
struct C_ChoiceSearchSelections_DC_C2_C3 : ChoiceSearchConfig<le_uint32_t> { } __packed__;
|
||||
struct C_ChoiceSearchSelections_PC_V3_BB_C2_C3 : ChoiceSearchConfig<le_uint16_t> { } __packed__;
|
||||
struct C_ChoiceSearchSelections_DC_C2_C3 : ChoiceSearchConfig<le_uint32_t> {
|
||||
} __packed__;
|
||||
struct C_ChoiceSearchSelections_PC_V3_BB_C2_C3 : ChoiceSearchConfig<le_uint16_t> {
|
||||
} __packed__;
|
||||
|
||||
// C3 (C->S): Execute choice search (DCv2 and later versions)
|
||||
// Same format as C2. The disabled field is unused.
|
||||
@@ -2235,8 +2264,10 @@ struct C_SetBlockedSenders_C6 {
|
||||
parray<le_uint32_t, Count> blocked_senders;
|
||||
} __packed__;
|
||||
|
||||
struct C_SetBlockedSenders_V3_C6 : C_SetBlockedSenders_C6<30> { } __packed__;
|
||||
struct C_SetBlockedSenders_BB_C6 : C_SetBlockedSenders_C6<28> { } __packed__;
|
||||
struct C_SetBlockedSenders_V3_C6 : C_SetBlockedSenders_C6<30> {
|
||||
} __packed__;
|
||||
struct C_SetBlockedSenders_BB_C6 : C_SetBlockedSenders_C6<28> {
|
||||
} __packed__;
|
||||
|
||||
// C7 (C->S): Enable simple mail auto-reply (V3/BB)
|
||||
// Same format as 1A/D5 command (plain text).
|
||||
@@ -2402,8 +2433,10 @@ struct S_InfoBoardEntry_D8 {
|
||||
ptext<CharT, 0x10> name;
|
||||
ptext<CharT, 0xAC> message;
|
||||
} __packed__;
|
||||
struct S_InfoBoardEntry_BB_D8 : S_InfoBoardEntry_D8<char16_t> { } __packed__;
|
||||
struct S_InfoBoardEntry_V3_D8 : S_InfoBoardEntry_D8<char> { } __packed__;
|
||||
struct S_InfoBoardEntry_BB_D8 : S_InfoBoardEntry_D8<char16_t> {
|
||||
} __packed__;
|
||||
struct S_InfoBoardEntry_V3_D8 : S_InfoBoardEntry_D8<char> {
|
||||
} __packed__;
|
||||
|
||||
// D9 (C->S): Write info board (V3/BB)
|
||||
// Contents are plain text, like 1A/D5.
|
||||
@@ -3187,8 +3220,6 @@ struct S_SetShutdownCommand_BB_01EF {
|
||||
// FE: Invalid command
|
||||
// FF: Invalid command
|
||||
|
||||
|
||||
|
||||
// Now, the game subcommands (used in commands 60, 62, 6C, 6D, C9, and CB).
|
||||
// These are laid out similarly as above. These structs start with G_ to
|
||||
// indicate that they are (usually) bidirectional, and are (usually) generated
|
||||
@@ -3212,8 +3243,6 @@ struct S_SetShutdownCommand_BB_01EF {
|
||||
// commands must be used. The 60 and 62 commands exhibit undefined behavior if
|
||||
// this limit is exceeded.
|
||||
|
||||
|
||||
|
||||
// These common structures are used my many subcommands.
|
||||
struct G_ClientIDHeader {
|
||||
uint8_t subcommand = 0;
|
||||
@@ -3242,8 +3271,6 @@ struct G_ExtendedHeader {
|
||||
le_uint32_t size = 0;
|
||||
} __packed__;
|
||||
|
||||
|
||||
|
||||
// 6x00: Invalid subcommand
|
||||
// 6x01: Invalid subcommand
|
||||
|
||||
@@ -3295,8 +3322,10 @@ struct G_SendGuildCard_DC_PC_V3 {
|
||||
struct G_SendGuildCard_DC_6x06 : G_SendGuildCard_DC_PC_V3<char, 0x11> {
|
||||
parray<uint8_t, 3> unused3;
|
||||
} __packed__;
|
||||
struct G_SendGuildCard_PC_6x06 : G_SendGuildCard_DC_PC_V3<char16_t, 0x24> { } __packed__;
|
||||
struct G_SendGuildCard_V3_6x06 : G_SendGuildCard_DC_PC_V3<char, 0x24> { } __packed__;
|
||||
struct G_SendGuildCard_PC_6x06 : G_SendGuildCard_DC_PC_V3<char16_t, 0x24> {
|
||||
} __packed__;
|
||||
struct G_SendGuildCard_V3_6x06 : G_SendGuildCard_DC_PC_V3<char, 0x24> {
|
||||
} __packed__;
|
||||
|
||||
struct G_SendGuildCard_BB_6x06 {
|
||||
G_UnusedHeader header;
|
||||
@@ -5052,8 +5081,6 @@ struct G_EnemyKilled_6xC8 {
|
||||
// 6xFE: Invalid subcommand
|
||||
// 6xFF: Invalid subcommand
|
||||
|
||||
|
||||
|
||||
// Now, the Episode 3 CARD battle subsubcommands (used in commands 6xB3, 6xB4,
|
||||
// and 6xB5). Note that even though there's no overlap in the subsubcommand
|
||||
// number space, the various subsubcommands must be used with the correct 6xBx
|
||||
|
||||
+10
-19
@@ -2,15 +2,14 @@
|
||||
|
||||
#include "StaticGameData.hh"
|
||||
|
||||
|
||||
|
||||
CommonItemSet::CommonItemSet(shared_ptr<const string> data)
|
||||
: gsl(data, true) { }
|
||||
: gsl(data, true) {}
|
||||
|
||||
const CommonItemSet::Table<true>& CommonItemSet::get_table(
|
||||
Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const {
|
||||
// TODO: What should we do for Ep4?
|
||||
string filename = string_printf("ItemPT%s%s%c%1d.rel",
|
||||
string filename = string_printf(
|
||||
"ItemPT%s%s%c%1d.rel",
|
||||
((mode == GameMode::CHALLENGE) ? "c" : ""),
|
||||
((episode == Episode::EP2) ? "l" : ""),
|
||||
tolower(abbreviation_for_difficulty(difficulty)),
|
||||
@@ -24,12 +23,9 @@ const CommonItemSet::Table<true>& CommonItemSet::get_table(
|
||||
return *reinterpret_cast<const Table<true>*>(data.first);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RELFileSet::RELFileSet(std::shared_ptr<const std::string> data)
|
||||
: data(data), r(*this->data) { }
|
||||
|
||||
|
||||
: data(data),
|
||||
r(*this->data) {}
|
||||
|
||||
ArmorRandomSet::ArmorRandomSet(std::shared_ptr<const std::string> data)
|
||||
: RELFileSet(data) {
|
||||
@@ -54,15 +50,14 @@ ArmorRandomSet::get_unit_table(size_t index) const {
|
||||
return this->get_table<WeightTableEntry8>(this->tables->at(2), index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ToolRandomSet::ToolRandomSet(std::shared_ptr<const std::string> data)
|
||||
: RELFileSet(data) {
|
||||
uint32_t specs_offset = r.pget_u32b(data->size() - 0x10);
|
||||
this->common_recovery_table_spec = &r.pget<TableSpec>(r.pget_u32b(
|
||||
specs_offset));
|
||||
this->rare_recovery_table_spec = &r.pget<TableSpec>(r.pget_u32b(
|
||||
specs_offset + sizeof(uint32_t)), 2 * sizeof(TableSpec));
|
||||
this->rare_recovery_table_spec = &r.pget<TableSpec>(
|
||||
r.pget_u32b(specs_offset + sizeof(uint32_t)),
|
||||
2 * sizeof(TableSpec));
|
||||
this->tech_disk_table_spec = this->rare_recovery_table_spec + 1;
|
||||
this->tech_disk_level_table_spec = &r.pget<TableSpec>(r.pget_u32b(
|
||||
specs_offset + 2 * sizeof(uint32_t)));
|
||||
@@ -88,8 +83,6 @@ ToolRandomSet::get_tech_disk_level_table(size_t index) const {
|
||||
return this->get_table<TechDiskLevelEntry>(*this->tech_disk_level_table_spec, index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
WeaponRandomSet::WeaponRandomSet(std::shared_ptr<const std::string> data)
|
||||
: RELFileSet(data) {
|
||||
uint32_t offsets_offset = this->r.pget_u32b(data->size() - 0x10);
|
||||
@@ -107,16 +100,14 @@ WeaponRandomSet::get_weapon_type_table(size_t index) const {
|
||||
|
||||
const parray<WeaponRandomSet::WeightTableEntry32, 6>*
|
||||
WeaponRandomSet::get_bonus_type_table(size_t which, size_t index) const {
|
||||
uint32_t base_offset = which
|
||||
? this->offsets->bonus_type_table2 : this->offsets->bonus_type_table1;
|
||||
uint32_t base_offset = which ? this->offsets->bonus_type_table2 : this->offsets->bonus_type_table1;
|
||||
return &this->r.pget<parray<WeightTableEntry32, 6>>(
|
||||
base_offset + sizeof(parray<WeightTableEntry32, 6>) * index);
|
||||
}
|
||||
|
||||
const WeaponRandomSet::RangeTableEntry*
|
||||
WeaponRandomSet::get_bonus_range(size_t which, size_t index) const {
|
||||
uint32_t base_offset = which
|
||||
? this->offsets->bonus_range_table2 : this->offsets->bonus_range_table1;
|
||||
uint32_t base_offset = which ? this->offsets->bonus_range_table2 : this->offsets->bonus_range_table1;
|
||||
return &this->r.pget<RangeTableEntry>(
|
||||
base_offset + sizeof(RangeTableEntry) * index);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "StaticGameData.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
|
||||
class CommonItemSet {
|
||||
public:
|
||||
template <typename IntT>
|
||||
@@ -248,8 +247,6 @@ private:
|
||||
GSLArchive gsl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RELFileSet {
|
||||
public:
|
||||
template <typename ValueT, typename WeightT = ValueT>
|
||||
|
||||
+3
-12
@@ -1,9 +1,9 @@
|
||||
#include "Compression.hh"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <phosg/Strings.hh>
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
PRSCompressor::PRSCompressor(function<void(size_t, size_t)> progress_fn)
|
||||
: progress_fn(progress_fn),
|
||||
closed(false),
|
||||
@@ -204,8 +202,6 @@ void PRSCompressor::flush_control() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
string prs_compress(
|
||||
const void* vdata, size_t size, function<void(size_t, size_t)> progress_fn) {
|
||||
PRSCompressor prs(progress_fn);
|
||||
@@ -218,11 +214,10 @@ string prs_compress(
|
||||
return prs_compress(data.data(), data.size(), progress_fn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ControlStreamReader {
|
||||
public:
|
||||
ControlStreamReader(StringReader& r) : r(r), bits(0x0000) { }
|
||||
ControlStreamReader(StringReader& r) : r(r),
|
||||
bits(0x0000) {}
|
||||
|
||||
bool read() {
|
||||
if (!(this->bits & 0x0100)) {
|
||||
@@ -388,8 +383,6 @@ size_t prs_decompress_size(const string& data, size_t max_output_size) {
|
||||
return prs_decompress_size(data.data(), data.size(), max_output_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void prs_disassemble(FILE* stream, const void* data, size_t size) {
|
||||
size_t output_bytes = 0;
|
||||
StringReader r(data, size);
|
||||
@@ -439,8 +432,6 @@ void prs_disassemble(FILE* stream, const std::string& data) {
|
||||
return prs_disassemble(stream, data.data(), data.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// BC0 is a compression algorithm fairly similar to PRS, but with a simpler set
|
||||
// of commands. Like PRS, there is a control stream, indicating when to copy a
|
||||
// literal byte from the input and when to copy from a backreference; unlike
|
||||
|
||||
+2
-4
@@ -2,14 +2,12 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "Text.hh"
|
||||
|
||||
|
||||
|
||||
// Use this class if you need to compress from multiple input buffers, or need
|
||||
// to compress multiple chunks and don't want to copy their contents
|
||||
// unnecessarily. (For most common use cases, use prs_compress (below) instead.)
|
||||
|
||||
+12
-12
@@ -1,28 +1,28 @@
|
||||
#include "DNSServer.hh"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <phosg/Network.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "NetworkAddresses.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
DNSServer::DNSServer(shared_ptr<struct event_base> base,
|
||||
uint32_t local_connect_address, uint32_t external_connect_address) :
|
||||
base(base), local_connect_address(local_connect_address),
|
||||
external_connect_address(external_connect_address) { }
|
||||
DNSServer::DNSServer(
|
||||
shared_ptr<struct event_base> base,
|
||||
uint32_t local_connect_address, uint32_t external_connect_address)
|
||||
: base(base),
|
||||
local_connect_address(local_connect_address),
|
||||
external_connect_address(external_connect_address) {}
|
||||
|
||||
DNSServer::~DNSServer() {
|
||||
for (const auto& it : this->fd_to_receive_event) {
|
||||
@@ -43,9 +43,9 @@ void DNSServer::listen(int port) {
|
||||
}
|
||||
|
||||
void DNSServer::add_socket(int fd) {
|
||||
unique_ptr<struct event, void(*)(struct event*)> e(event_new(this->base.get(),
|
||||
fd, EV_READ | EV_PERSIST, &DNSServer::dispatch_on_receive_message,
|
||||
this), event_free);
|
||||
unique_ptr<struct event, void (*)(struct event*)> e(
|
||||
event_new(this->base.get(), fd, EV_READ | EV_PERSIST, &DNSServer::dispatch_on_receive_message, this),
|
||||
event_free);
|
||||
event_add(e.get(), nullptr);
|
||||
this->fd_to_receive_event.emplace(fd, move(e));
|
||||
}
|
||||
|
||||
+3
-4
@@ -3,10 +3,9 @@
|
||||
#include <event2/event.h>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class DNSServer {
|
||||
public:
|
||||
@@ -28,7 +27,7 @@ public:
|
||||
|
||||
private:
|
||||
std::shared_ptr<struct event_base> base;
|
||||
std::unordered_map<int, std::unique_ptr<struct event, void(*)(struct event*)>> fd_to_receive_event;
|
||||
std::unordered_map<int, std::unique_ptr<struct event, void (*)(struct event*)>> fd_to_receive_event;
|
||||
uint32_t local_connect_address;
|
||||
uint32_t external_connect_address;
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
// Note: This order matches the order that the cards are defined in the original
|
||||
// code. This is relevant for consistency of results when choosing a random card
|
||||
// (for God Whim).
|
||||
@@ -107,15 +105,13 @@ AssistEffect assist_effect_number_for_card_id(uint16_t card_id) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AssistServer::AssistServer(shared_ptr<Server> server)
|
||||
: w_server(server),
|
||||
assist_effects(AssistEffect::NONE),
|
||||
num_assist_cards_set(0),
|
||||
client_ids_with_assists(0xFF),
|
||||
active_assist_effects(AssistEffect::NONE),
|
||||
num_active_assists(0) { }
|
||||
num_active_assists(0) {}
|
||||
|
||||
shared_ptr<Server> AssistServer::server() {
|
||||
auto s = this->w_server.lock();
|
||||
@@ -281,6 +277,4 @@ void AssistServer::recompute_effects() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -6,13 +6,11 @@
|
||||
#include <vector>
|
||||
|
||||
#include "DataIndex.hh"
|
||||
#include "PlayerState.hh"
|
||||
#include "DeckState.hh"
|
||||
#include "PlayerState.hh"
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
class Server;
|
||||
|
||||
extern const std::vector<uint16_t> ALL_ASSIST_CARD_IDS;
|
||||
@@ -55,6 +53,4 @@ public:
|
||||
std::shared_ptr<parray<ActionMetadata, 9>> set_card_action_metadatas[4];
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -9,8 +9,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
BattleRecord::Event::Event(StringReader& r) {
|
||||
this->type = r.get<Event::Type>();
|
||||
this->timestamp = r.get_u64l();
|
||||
@@ -74,13 +72,11 @@ void BattleRecord::Event::serialize(StringWriter& w) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BattleRecord::BattleRecord(uint32_t behavior_flags)
|
||||
: is_writable(true),
|
||||
behavior_flags(behavior_flags),
|
||||
battle_start_timestamp(0),
|
||||
battle_end_timestamp(0) { }
|
||||
battle_end_timestamp(0) {}
|
||||
|
||||
BattleRecord::BattleRecord(const string& data)
|
||||
: is_writable(false),
|
||||
@@ -128,7 +124,6 @@ const BattleRecord::Event* BattleRecord::get_first_event() const {
|
||||
return &this->events.front();
|
||||
}
|
||||
|
||||
|
||||
void BattleRecord::add_player(
|
||||
const PlayerLobbyDataDCGC& lobby_data,
|
||||
const PlayerInventory& inventory,
|
||||
@@ -279,8 +274,6 @@ void BattleRecord::set_battle_end_timestamp() {
|
||||
this->battle_end_timestamp = now();
|
||||
}
|
||||
|
||||
|
||||
|
||||
BattleRecordPlayer::BattleRecordPlayer(
|
||||
shared_ptr<const BattleRecord> rec,
|
||||
shared_ptr<struct event_base> base)
|
||||
@@ -288,7 +281,7 @@ BattleRecordPlayer::BattleRecordPlayer(
|
||||
event_it(this->record->events.begin()),
|
||||
play_start_timestamp(0),
|
||||
base(base),
|
||||
next_command_ev(event_new(this->base.get(), -1, EV_TIMEOUT, &BattleRecordPlayer::dispatch_schedule_events, this), event_free) { }
|
||||
next_command_ev(event_new(this->base.get(), -1, EV_TIMEOUT, &BattleRecordPlayer::dispatch_schedule_events, this), event_free) {}
|
||||
|
||||
shared_ptr<const BattleRecord> BattleRecordPlayer::get_record() const {
|
||||
return this->record;
|
||||
@@ -377,6 +370,4 @@ void BattleRecordPlayer::schedule_events() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <event2/event.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <phosg/Strings.hh>
|
||||
|
||||
#include "../Player.hh"
|
||||
|
||||
@@ -17,8 +17,6 @@ namespace Episode3 {
|
||||
|
||||
// The comment in Server.hh does not apply to this file (and BattleRecord.cc).
|
||||
|
||||
|
||||
|
||||
class BattleRecord {
|
||||
public:
|
||||
struct PlayerEntry {
|
||||
@@ -118,7 +116,4 @@ private:
|
||||
std::shared_ptr<struct event> next_command_ev;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#include "Card.hh"
|
||||
|
||||
#include "Server.hh"
|
||||
#include "../CommandFormats.hh"
|
||||
#include "Server.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
Card::Card(
|
||||
uint16_t card_id,
|
||||
uint16_t card_ref,
|
||||
@@ -30,7 +28,7 @@ Card::Card(
|
||||
last_attack_preliminary_damage(0),
|
||||
last_attack_final_damage(0),
|
||||
num_destroyed_ally_fcs(0),
|
||||
current_defense_power(0) { }
|
||||
current_defense_power(0) {}
|
||||
|
||||
void Card::init() {
|
||||
this->clear_action_chain_and_metadata_and_most_flags();
|
||||
@@ -254,7 +252,6 @@ void Card::commit_attack(
|
||||
effective_damage = 0;
|
||||
}
|
||||
|
||||
|
||||
auto attacker_ps = attacker_card->player_state();
|
||||
attacker_ps->stats.damage_given += effective_damage;
|
||||
this->player_state()->stats.damage_taken += effective_damage;
|
||||
@@ -598,7 +595,6 @@ void Card::propagate_shared_hp_if_needed() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Card::send_6xB4x4E_4C_4D_if_needed(bool always_send) {
|
||||
ssize_t index = -1;
|
||||
if (this->card_ref == this->player_state()->get_sc_card_ref()) {
|
||||
@@ -1237,6 +1233,4 @@ void Card::unknown_80237734() {
|
||||
this->send_6xB4x4E_4C_4D_if_needed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../Text.hh"
|
||||
#include "../CommandFormats.hh"
|
||||
#include "../Text.hh"
|
||||
#include "DataIndex.hh"
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
class ServerBase;
|
||||
class Server;
|
||||
class PlayerState;
|
||||
@@ -126,6 +124,4 @@ public:
|
||||
int16_t current_defense_power;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
+39
-34
@@ -6,8 +6,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
CardSpecial::DiceRoll::DiceRoll() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -20,8 +18,6 @@ void CardSpecial::DiceRoll::clear() {
|
||||
this->unknown_a5 = 0xFFFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CardSpecial::AttackEnvStats::AttackEnvStats() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -73,10 +69,9 @@ uint32_t CardSpecial::AttackEnvStats::at(size_t offset) const {
|
||||
return reinterpret_cast<const parray<uint32_t, count>*>(this)->at(offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CardSpecial::CardSpecial(shared_ptr<Server> server)
|
||||
: w_server(server), unknown_a2(0) { }
|
||||
: w_server(server),
|
||||
unknown_a2(0) {}
|
||||
|
||||
shared_ptr<Server> CardSpecial::server() {
|
||||
auto s = this->w_server.lock();
|
||||
@@ -411,7 +406,7 @@ bool CardSpecial::apply_stat_deltas_to_card_from_condition_and_clear_cond(
|
||||
if (hp != ap) {
|
||||
this->send_6xB4x06_for_stat_delta(card, cond_card_ref, 0xA0, hp - ap, 0, 0);
|
||||
this->send_6xB4x06_for_stat_delta(card, cond_card_ref, 0x20, ap - hp, 0, 0);
|
||||
card->set_current_hp(ap,1,1);
|
||||
card->set_current_hp(ap, 1, 1);
|
||||
card->ap = hp;
|
||||
this->destroy_card_if_hp_zero(card, cond_card_ref);
|
||||
}
|
||||
@@ -532,7 +527,7 @@ void CardSpecial::compute_attack_ap(
|
||||
: AttackMedium::UNKNOWN;
|
||||
uint16_t target_card_ref = target_card->get_card_ref();
|
||||
|
||||
auto check_card = [&](shared_ptr<Card> card) -> void{
|
||||
auto check_card = [&](shared_ptr<Card> card) -> void {
|
||||
if (!card || (card->card_flags & 3)) {
|
||||
return;
|
||||
}
|
||||
@@ -570,7 +565,7 @@ void CardSpecial::compute_attack_ap(
|
||||
}
|
||||
|
||||
if (attacker_card &&
|
||||
attacker_card->get_attack_condition_value(ConditionType::UNKNOWN_7D, 0xFFFF,0xFF,0xFFFF, nullptr)) {
|
||||
attacker_card->get_attack_condition_value(ConditionType::UNKNOWN_7D, 0xFFFF, 0xFF, 0xFFFF, nullptr)) {
|
||||
*out_value = *out_value * 1.5f;
|
||||
}
|
||||
if (target_card &&
|
||||
@@ -611,7 +606,8 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats(
|
||||
ast.total_num_set_cards = ps_num_set_cards;
|
||||
|
||||
uint8_t target_card_team_id = target_card
|
||||
? target_card->player_state()->get_team_id() : 0xFF;
|
||||
? target_card->player_state()->get_team_id()
|
||||
: 0xFF;
|
||||
|
||||
size_t target_team_num_set_cards = 0;
|
||||
size_t condition_giver_team_num_set_cards = 0;
|
||||
@@ -629,19 +625,26 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats(
|
||||
ast.condition_giver_team_num_set_cards = condition_giver_team_num_set_cards;
|
||||
|
||||
ast.num_native_creatures = this->get_all_set_cards_by_team_and_class(
|
||||
CardClass::NATIVE_CREATURE, 0xFF, true).size();
|
||||
CardClass::NATIVE_CREATURE, 0xFF, true)
|
||||
.size();
|
||||
ast.num_a_beast_creatures = this->get_all_set_cards_by_team_and_class(
|
||||
CardClass::A_BEAST_CREATURE, 0xFF, true).size();
|
||||
CardClass::A_BEAST_CREATURE, 0xFF, true)
|
||||
.size();
|
||||
ast.num_machine_creatures = this->get_all_set_cards_by_team_and_class(
|
||||
CardClass::MACHINE_CREATURE, 0xFF, true).size();
|
||||
CardClass::MACHINE_CREATURE, 0xFF, true)
|
||||
.size();
|
||||
ast.num_dark_creatures = this->get_all_set_cards_by_team_and_class(
|
||||
CardClass::DARK_CREATURE, 0xFF, true).size();
|
||||
CardClass::DARK_CREATURE, 0xFF, true)
|
||||
.size();
|
||||
ast.num_sword_type_items = this->get_all_set_cards_by_team_and_class(
|
||||
CardClass::SWORD_ITEM, 0xFF, true).size();
|
||||
CardClass::SWORD_ITEM, 0xFF, true)
|
||||
.size();
|
||||
ast.num_gun_type_items = this->get_all_set_cards_by_team_and_class(
|
||||
CardClass::GUN_ITEM, 0xFF, true).size();
|
||||
CardClass::GUN_ITEM, 0xFF, true)
|
||||
.size();
|
||||
ast.num_cane_type_items = this->get_all_set_cards_by_team_and_class(
|
||||
CardClass::CANE_ITEM, 0xFF, true).size();
|
||||
CardClass::CANE_ITEM, 0xFF, true)
|
||||
.size();
|
||||
ast.num_sword_type_items_on_team = card
|
||||
? this->get_all_set_cards_by_team_and_class(CardClass::SWORD_ITEM, card->get_team_id(), true).size()
|
||||
: 0;
|
||||
@@ -672,11 +675,14 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats(
|
||||
ast.team_dice_boost = card ? this->server()->team_dice_boost[card->get_team_id()] : 0;
|
||||
|
||||
ast.effective_ap_if_not_tech = (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::TECH))
|
||||
? 0 : attacker_card->action_chain.chain.damage;
|
||||
? 0
|
||||
: attacker_card->action_chain.chain.damage;
|
||||
ast.effective_ap_if_not_tech2 = (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::TECH))
|
||||
? 0 : attacker_card->action_chain.chain.damage;
|
||||
? 0
|
||||
: attacker_card->action_chain.chain.damage;
|
||||
ast.effective_ap_if_not_physical = (!attacker_card || (attacker_card->action_chain.chain.attack_medium == AttackMedium::PHYSICAL))
|
||||
? 0 : attacker_card->action_chain.chain.damage;
|
||||
? 0
|
||||
: attacker_card->action_chain.chain.damage;
|
||||
ast.sc_effective_ap = attacker_card ? attacker_card->action_chain.chain.damage : 0;
|
||||
ast.attack_bonus = card->action_metadata.attack_bonus;
|
||||
ast.last_attack_preliminary_damage = card->last_attack_preliminary_damage;
|
||||
@@ -707,7 +713,8 @@ CardSpecial::AttackEnvStats CardSpecial::compute_attack_env_stats(
|
||||
// original code.
|
||||
for (z = 0;
|
||||
((target_card_ref != pa.attacker_card_ref) && (z < 9) && (pa.action_card_refs[z] != 0xFFFF));
|
||||
z++) { }
|
||||
z++) {
|
||||
}
|
||||
ast.action_cards_ap = 0;
|
||||
ast.action_cards_tp = 0;
|
||||
for (; (z < 9) && (pa.action_card_refs[z] != 0xFFFF); z++) {
|
||||
@@ -896,7 +903,7 @@ shared_ptr<Card> CardSpecial::compute_replaced_target_based_on_conditions(
|
||||
(unknown_p4 != 0) &&
|
||||
(target_card_ref == other_set_card->action_chain.conditions[z].condition_giver_card_ref)) {
|
||||
candidate_cards.emplace_back(other_set_card);
|
||||
if (unknown_p11 &&(def_effect_index != 0xFF) && (set_card_ref != 0xFFFF) &&
|
||||
if (unknown_p11 && (def_effect_index != 0xFF) && (set_card_ref != 0xFFFF) &&
|
||||
!this->server()->ruler_server->check_usability_or_apply_condition_for_card_refs(
|
||||
set_card_ref, sc_card_ref, other_set_card->get_card_ref(), def_effect_index, attack_medium)) {
|
||||
*unknown_p11 = 1;
|
||||
@@ -1887,8 +1894,7 @@ bool CardSpecial::execute_effect(
|
||||
|
||||
case ConditionType::BONUS_FROM_LEADER:
|
||||
if (unknown_p7 & 1) {
|
||||
clamped_unknown_p5 = this->count_cards_with_card_id_set_by_player_except_card_ref(expr_value, 0xFFFF)
|
||||
+ (card->action_chain).chain.ap_effect_bonus;
|
||||
clamped_unknown_p5 = this->count_cards_with_card_id_set_by_player_except_card_ref(expr_value, 0xFFFF) + (card->action_chain).chain.ap_effect_bonus;
|
||||
(card->action_chain).chain.ap_effect_bonus = clamp<int16_t>(clamped_unknown_p5, -99, 99);
|
||||
}
|
||||
return true;
|
||||
@@ -2391,7 +2397,7 @@ void CardSpecial::get_effective_ap_tp(
|
||||
}
|
||||
|
||||
const char* CardSpecial::get_next_expr_token(
|
||||
const char *expr, ExpressionTokenType* out_type, int32_t* out_value) const {
|
||||
const char* expr, ExpressionTokenType* out_type, int32_t* out_value) const {
|
||||
switch (*expr) {
|
||||
case '\0':
|
||||
*out_type = ExpressionTokenType::SPACE;
|
||||
@@ -2427,11 +2433,11 @@ const char* CardSpecial::get_next_expr_token(
|
||||
*out_type = ExpressionTokenType::SPACE;
|
||||
*out_value = 0x27;
|
||||
|
||||
static const vector<const char*> tokens({
|
||||
static const vector<const char*> tokens = {
|
||||
"f", "d", "ap", "tp", "hp", "mhp", "dm", "tdm", "tf", "ac", "php",
|
||||
"dc", "cs", "a", "kap", "ktp", "dn", "hf", "df", "ff", "ef", "bi",
|
||||
"ab", "mc", "dk", "sa", "gn", "wd", "tt", "lv", "adm", "ddm", "sat",
|
||||
"edm", "ldm", "rdm", "fdm", "ndm", "ehp"});
|
||||
"edm", "ldm", "rdm", "fdm", "ndm", "ehp"};
|
||||
for (size_t z = 0; z < tokens.size(); z++) {
|
||||
if (token_buf == tokens[z]) {
|
||||
*out_type = ExpressionTokenType::REFERENCE;
|
||||
@@ -2467,7 +2473,8 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
|
||||
}
|
||||
|
||||
auto card2 = this->server()->card_for_set_card_ref((as.attacker_card_ref == 0xFFFF)
|
||||
? as.original_attacker_card_ref : as.attacker_card_ref);
|
||||
? as.original_attacker_card_ref
|
||||
: as.attacker_card_ref);
|
||||
|
||||
Location card1_loc;
|
||||
if (!card1) {
|
||||
@@ -2526,7 +2533,8 @@ vector<shared_ptr<const Card>> CardSpecial::get_targeted_cards_for_condition(
|
||||
break;
|
||||
case 4:
|
||||
size_t z;
|
||||
for (z = 0; (z < 9) && (as.action_card_refs[z] != 0xFFFF) && (as.action_card_refs[z] != card_ref); z++) { }
|
||||
for (z = 0; (z < 9) && (as.action_card_refs[z] != 0xFFFF) && (as.action_card_refs[z] != card_ref); z++) {
|
||||
}
|
||||
for (; (z < 9) && (as.action_card_refs[z] != 0xFFFF); z++) {
|
||||
auto result_card = this->server()->card_for_set_card_ref(as.action_card_refs[z]);
|
||||
if (result_card) {
|
||||
@@ -3577,8 +3585,7 @@ void CardSpecial::unknown_8024C2B0(
|
||||
}
|
||||
|
||||
ssize_t applied_cond_index = -1;
|
||||
if ((unknown_v1 == 0) && !this->should_cancel_condition_due_to_anti_abnormality(
|
||||
card_effect, target_card, dice_cmd.effect.target_card_ref, sc_card_ref)) {
|
||||
if ((unknown_v1 == 0) && !this->should_cancel_condition_due_to_anti_abnormality(card_effect, target_card, dice_cmd.effect.target_card_ref, sc_card_ref)) {
|
||||
applied_cond_index = target_card->apply_abnormal_condition(
|
||||
card_effect, def_effect_index, dice_cmd.effect.target_card_ref, sc_card_ref, value, dice_roll.value, random_percent);
|
||||
// This debug_print call is in the original code.
|
||||
@@ -4526,6 +4533,4 @@ vector<shared_ptr<const Card>> CardSpecial::find_all_sc_cards_of_class(
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
struct InterferenceProbabilityEntry {
|
||||
uint16_t card_id;
|
||||
uint8_t attack_probability;
|
||||
@@ -22,8 +20,6 @@ const InterferenceProbabilityEntry* get_interference_probability_entry(
|
||||
uint16_t column_card_id,
|
||||
bool is_attack);
|
||||
|
||||
|
||||
|
||||
class CardSpecial {
|
||||
public:
|
||||
enum class ExpressionTokenType {
|
||||
@@ -224,7 +220,7 @@ public:
|
||||
int16_t ap,
|
||||
int16_t tp);
|
||||
const char* get_next_expr_token(
|
||||
const char *expr, ExpressionTokenType* out_type, int32_t* out_value) const;
|
||||
const char* expr, ExpressionTokenType* out_type, int32_t* out_value) const;
|
||||
std::vector<std::shared_ptr<const Card>> get_targeted_cards_for_condition(
|
||||
uint16_t card_ref,
|
||||
uint8_t def_effect_index,
|
||||
@@ -341,6 +337,4 @@ private:
|
||||
uint16_t unknown_a2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
+43
-56
@@ -8,18 +8,16 @@
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Time.hh>
|
||||
|
||||
#include "../Loggers.hh"
|
||||
#include "../Compression.hh"
|
||||
#include "../Loggers.hh"
|
||||
#include "../PSOEncryption.hh"
|
||||
#include "../Text.hh"
|
||||
#include "../Quest.hh"
|
||||
#include "../Text.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
const char* name_for_attack_medium(AttackMedium medium) {
|
||||
switch (medium) {
|
||||
case AttackMedium::UNKNOWN:
|
||||
@@ -37,12 +35,13 @@ const char* name_for_attack_medium(AttackMedium medium) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Location::Location() : Location(0, 0) { }
|
||||
Location::Location(uint8_t x, uint8_t y) : Location(x, y, Direction::RIGHT) { }
|
||||
Location::Location() : Location(0, 0) {}
|
||||
Location::Location(uint8_t x, uint8_t y) : Location(x, y, Direction::RIGHT) {}
|
||||
Location::Location(uint8_t x, uint8_t y, Direction direction)
|
||||
: x(x), y(y), direction(direction), unused(0) { }
|
||||
: x(x),
|
||||
y(y),
|
||||
direction(direction),
|
||||
unused(0) {}
|
||||
|
||||
bool Location::operator==(const Location& other) const {
|
||||
return (this->x == other.x) &&
|
||||
@@ -73,8 +72,6 @@ void Location::clear_FF() {
|
||||
this->unused = 0xFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Direction turn_left(Direction d) {
|
||||
switch (d) {
|
||||
case Direction::RIGHT:
|
||||
@@ -137,16 +134,12 @@ const char* name_for_direction(Direction d) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool card_class_is_tech_like(CardClass cc) {
|
||||
return (cc == CardClass::TECH) ||
|
||||
(cc == CardClass::PHOTON_BLAST) ||
|
||||
(cc == CardClass::BOSS_TECH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const vector<const char*> name_for_card_type({
|
||||
"HunterSC",
|
||||
"ArkzSC",
|
||||
@@ -445,8 +438,6 @@ const char* name_for_condition_type(ConditionType cond_type) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* name_for_action_subphase(ActionSubphase subphase) {
|
||||
switch (subphase) {
|
||||
case ActionSubphase::ATTACK:
|
||||
@@ -460,8 +451,6 @@ const char* name_for_action_subphase(ActionSubphase subphase) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CardDefinition::Stat::decode_code() {
|
||||
this->type = static_cast<Type>(this->code / 1000);
|
||||
int16_t value = this->code - (this->type * 1000);
|
||||
@@ -512,8 +501,6 @@ string CardDefinition::Stat::str() const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CardDefinition::Effect::is_empty() const {
|
||||
return (this->effect_num == 0 &&
|
||||
this->type == ConditionType::NONE &&
|
||||
@@ -588,7 +575,8 @@ string CardDefinition::Effect::str() const {
|
||||
cmd_str += ':';
|
||||
cmd_str += name;
|
||||
}
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
string expr_str = this->expr;
|
||||
if (!expr_str.empty()) {
|
||||
@@ -603,8 +591,6 @@ string CardDefinition::Effect::str() const {
|
||||
arg2str.data(), arg3str.data(), static_cast<uint8_t>(this->apply_criterion), this->unknown_a2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CardDefinition::is_sc() const {
|
||||
return (this->type == CardType::HUNTERS_SC) || (this->type == CardType::ARKZ_SC);
|
||||
}
|
||||
@@ -614,8 +600,7 @@ bool CardDefinition::is_fc() const {
|
||||
}
|
||||
|
||||
bool CardDefinition::is_named_android_sc() const {
|
||||
static const unordered_set<uint16_t> TARGET_IDS({
|
||||
0x0005, 0x0007, 0x0110, 0x0113, 0x0114, 0x0117, 0x011B, 0x011F});
|
||||
static const unordered_set<uint16_t> TARGET_IDS({0x0005, 0x0007, 0x0110, 0x0113, 0x0114, 0x0117, 0x011B, 0x011F});
|
||||
return TARGET_IDS.count(this->card_id);
|
||||
}
|
||||
|
||||
@@ -636,8 +621,6 @@ CardClass CardDefinition::card_class() const {
|
||||
return static_cast<CardClass>(this->be_card_class.load());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CardDefinition::decode_range() {
|
||||
// If the cell representing the FC is nonzero, the card has a range from a
|
||||
// list of constants. Otherwise, its range is already defined in the range
|
||||
@@ -837,8 +820,6 @@ string CardDefinition::str() const {
|
||||
effects_str.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Rules::Rules() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -974,8 +955,6 @@ string Rules::str() const {
|
||||
return "Rules[" + join(tokens, ", ") + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
StateFlags::StateFlags() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -1028,8 +1007,6 @@ void StateFlags::clear_FF() {
|
||||
this->client_sc_card_types.clear(CardType::INVALID_FF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
string MapDefinition::str(const DataIndex* data_index) const {
|
||||
deque<string> lines;
|
||||
auto add_map = [&](const parray<parray<uint8_t, 0x10>, 0x10>& tiles) {
|
||||
@@ -1049,7 +1026,8 @@ string MapDefinition::str(const DataIndex* data_index) const {
|
||||
lines.emplace_back(string_printf(" num_alt_maps=%02hhX", this->num_alt_maps));
|
||||
lines.emplace_back(" tiles:");
|
||||
add_map(this->map_tiles);
|
||||
lines.emplace_back(string_printf(" start_tile_definitions=[1p=%02hhX 2p=%02hhX,%02hhX 3p=%02hhX,%02hhX,%02hhX], [1p=%02hhX 2p=%02hhX,%02hhX 3p=%02hhX,%02hhX,%02hhX]",
|
||||
lines.emplace_back(string_printf(
|
||||
" start_tile_definitions=[1p=%02hhX 2p=%02hhX,%02hhX 3p=%02hhX,%02hhX,%02hhX], [1p=%02hhX 2p=%02hhX,%02hhX 3p=%02hhX,%02hhX,%02hhX]",
|
||||
this->start_tile_definitions[0][0], this->start_tile_definitions[0][1],
|
||||
this->start_tile_definitions[0][2], this->start_tile_definitions[0][3],
|
||||
this->start_tile_definitions[0][4], this->start_tile_definitions[0][5],
|
||||
@@ -1062,7 +1040,8 @@ string MapDefinition::str(const DataIndex* data_index) const {
|
||||
add_map(this->alt_maps1[w][z]);
|
||||
}
|
||||
for (size_t w = 0; w < 2; w++) {
|
||||
lines.emplace_back(string_printf(" alt tiles a3 %zu/%zu=%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", z, w,
|
||||
lines.emplace_back(string_printf(
|
||||
" alt tiles a3 %zu/%zu=%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", z, w,
|
||||
this->alt_maps_unknown_a3[w][z][0x00].load(), this->alt_maps_unknown_a3[w][z][0x01].load(),
|
||||
this->alt_maps_unknown_a3[w][z][0x02].load(), this->alt_maps_unknown_a3[w][z][0x03].load(),
|
||||
this->alt_maps_unknown_a3[w][z][0x04].load(), this->alt_maps_unknown_a3[w][z][0x05].load(),
|
||||
@@ -1076,7 +1055,8 @@ string MapDefinition::str(const DataIndex* data_index) const {
|
||||
}
|
||||
for (size_t w = 0; w < 3; w++) {
|
||||
for (size_t z = 0; z < 0x24; z += 3) {
|
||||
lines.emplace_back(string_printf(" a4[%zu][0x%02zX:0x%02zX]=%g %g %g", w, z, z + 3,
|
||||
lines.emplace_back(string_printf(
|
||||
" a4[%zu][0x%02zX:0x%02zX]=%g %g %g", w, z, z + 3,
|
||||
this->unknown_a4[w][z + 0].load(),
|
||||
this->unknown_a4[w][z + 1].load(),
|
||||
this->unknown_a4[w][z + 2].load()));
|
||||
@@ -1085,16 +1065,19 @@ string MapDefinition::str(const DataIndex* data_index) const {
|
||||
lines.emplace_back(" modification tiles:");
|
||||
add_map(this->modification_tiles);
|
||||
for (size_t z = 0; z < 0x70; z += 0x10) {
|
||||
lines.emplace_back(string_printf(" a5[0x%02zX:0x%02zX]=%02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX", z, z + 0x10,
|
||||
lines.emplace_back(string_printf(
|
||||
" a5[0x%02zX:0x%02zX]=%02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX", z, z + 0x10,
|
||||
this->unknown_a5[z + 0x00], this->unknown_a5[z + 0x01], this->unknown_a5[z + 0x02], this->unknown_a5[z + 0x03],
|
||||
this->unknown_a5[z + 0x04], this->unknown_a5[z + 0x05], this->unknown_a5[z + 0x06], this->unknown_a5[z + 0x07],
|
||||
this->unknown_a5[z + 0x08], this->unknown_a5[z + 0x09], this->unknown_a5[z + 0x0A], this->unknown_a5[z + 0x0B],
|
||||
this->unknown_a5[z + 0x0C], this->unknown_a5[z + 0x0D], this->unknown_a5[z + 0x0E], this->unknown_a5[z + 0x0F]));
|
||||
}
|
||||
lines.emplace_back(string_printf(" a5[0x70:0x74]=%02hhX %02hhX %02hhX %02hhX",
|
||||
lines.emplace_back(string_printf(
|
||||
" a5[0x70:0x74]=%02hhX %02hhX %02hhX %02hhX",
|
||||
this->unknown_a5[0x70], this->unknown_a5[0x71], this->unknown_a5[0x72], this->unknown_a5[0x73]));
|
||||
lines.emplace_back(" default_rules: " + this->default_rules.str());
|
||||
lines.emplace_back(string_printf(" a6=%02hhX %02hhX %02hhX %02hhX",
|
||||
lines.emplace_back(string_printf(
|
||||
" a6=%02hhX %02hhX %02hhX %02hhX",
|
||||
this->unknown_a6[0], this->unknown_a6[1], this->unknown_a6[2], this->unknown_a6[3]));
|
||||
lines.emplace_back(" name: " + string(this->name));
|
||||
lines.emplace_back(" location_name: " + string(this->location_name));
|
||||
@@ -1103,21 +1086,25 @@ string MapDefinition::str(const DataIndex* data_index) const {
|
||||
lines.emplace_back(string_printf(" map_xy: %hu %hu", this->map_x.load(), this->map_y.load()));
|
||||
for (size_t z = 0; z < 3; z++) {
|
||||
lines.emplace_back(string_printf(" npc_chars[%zu]:", z));
|
||||
lines.emplace_back(string_printf(" a1=%04hX %04hX",
|
||||
lines.emplace_back(string_printf(
|
||||
" a1=%04hX %04hX",
|
||||
this->npc_chars[z].unknown_a1[0].load(), this->npc_chars[z].unknown_a1[1].load()));
|
||||
lines.emplace_back(string_printf(" a2=%02hX %02hX %02hX %02hX",
|
||||
lines.emplace_back(string_printf(
|
||||
" a2=%02hX %02hX %02hX %02hX",
|
||||
this->npc_chars[z].unknown_a2[0], this->npc_chars[z].unknown_a2[1],
|
||||
this->npc_chars[z].unknown_a2[2], this->npc_chars[z].unknown_a2[3]));
|
||||
lines.emplace_back(" name: " + string(this->npc_chars[z].name));
|
||||
for (size_t w = 0; w < 0x78; w += 0x08) {
|
||||
lines.emplace_back(string_printf(" a3[0x%02zX:0x%02zX]=%04hX %04hX %04hX %04hX %04hX %04hX %04hX %04hX",
|
||||
lines.emplace_back(string_printf(
|
||||
" a3[0x%02zX:0x%02zX]=%04hX %04hX %04hX %04hX %04hX %04hX %04hX %04hX",
|
||||
w, w + 0x08,
|
||||
this->npc_chars[z].unknown_a3[w + 0x00].load(), this->npc_chars[z].unknown_a3[w + 0x01].load(),
|
||||
this->npc_chars[z].unknown_a3[w + 0x02].load(), this->npc_chars[z].unknown_a3[w + 0x03].load(),
|
||||
this->npc_chars[z].unknown_a3[w + 0x04].load(), this->npc_chars[z].unknown_a3[w + 0x05].load(),
|
||||
this->npc_chars[z].unknown_a3[w + 0x06].load(), this->npc_chars[z].unknown_a3[w + 0x07].load()));
|
||||
}
|
||||
lines.emplace_back(string_printf(" a3[0x78:0x7E]=%04hX %04hX %04hX %04hX %04hX %04hX",
|
||||
lines.emplace_back(string_printf(
|
||||
" a3[0x78:0x7E]=%04hX %04hX %04hX %04hX %04hX %04hX",
|
||||
this->npc_chars[z].unknown_a3[0x78].load(), this->npc_chars[z].unknown_a3[0x79].load(),
|
||||
this->npc_chars[z].unknown_a3[0x7A].load(), this->npc_chars[z].unknown_a3[0x7B].load(),
|
||||
this->npc_chars[z].unknown_a3[0x7C].load(), this->npc_chars[z].unknown_a3[0x7D].load()));
|
||||
@@ -1129,7 +1116,8 @@ string MapDefinition::str(const DataIndex* data_index) const {
|
||||
if (data_index) {
|
||||
try {
|
||||
entry = data_index->definition_for_card_id(card_id);
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
}
|
||||
if (entry) {
|
||||
string name = entry->def.en_name;
|
||||
@@ -1168,7 +1156,8 @@ string MapDefinition::str(const DataIndex* data_index) const {
|
||||
if (data_index) {
|
||||
try {
|
||||
entry = data_index->definition_for_card_id(card_id);
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
}
|
||||
if (entry) {
|
||||
string name = entry->def.en_name;
|
||||
@@ -1338,8 +1327,6 @@ bool Rules::check_and_reset_invalid_fields() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
|
||||
: behavior_flags(behavior_flags) {
|
||||
|
||||
@@ -1487,10 +1474,12 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
|
||||
if (this->behavior_flags & BehaviorFlag::LOAD_CARD_TEXT) {
|
||||
try {
|
||||
entry->text = move(card_text.at(defs[x].card_id));
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
try {
|
||||
entry->debug_tags = move(card_tags.at(defs[x].card_id));
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1567,10 +1556,12 @@ DataIndex::DataIndex(const string& directory, uint32_t behavior_flags)
|
||||
}
|
||||
|
||||
DataIndex::MapEntry::MapEntry(const MapDefinition& map, bool is_quest)
|
||||
: map(map), is_quest(is_quest) { }
|
||||
: map(map),
|
||||
is_quest(is_quest) {}
|
||||
|
||||
DataIndex::MapEntry::MapEntry(const string& compressed, bool is_quest)
|
||||
: is_quest(is_quest), compressed_data(compressed) {
|
||||
: is_quest(is_quest),
|
||||
compressed_data(compressed) {
|
||||
string decompressed = prs_decompress(this->compressed_data);
|
||||
if (decompressed.size() != sizeof(MapDefinition)) {
|
||||
throw runtime_error(string_printf(
|
||||
@@ -1711,8 +1702,6 @@ shared_ptr<const COMDeckDefinition> DataIndex::random_com_deck() const {
|
||||
return this->com_decks[random_object<size_t>() % this->com_decks.size()];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PlayerConfig::decrypt() {
|
||||
if (!this->is_encrypted) {
|
||||
return;
|
||||
@@ -1740,6 +1729,4 @@ void PlayerConfig::encrypt(uint8_t basis) {
|
||||
this->basis = basis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -2,28 +2,24 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <phosg/JSON.hh>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../Text.hh"
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
// The comment in Server.hh does not apply to this file (and DataIndex.cc).
|
||||
// Except for the Location structure, these structures and functions are not
|
||||
// based on Sega's original implementation.
|
||||
|
||||
class DataIndex;
|
||||
|
||||
|
||||
|
||||
enum BehaviorFlag {
|
||||
SKIP_DECK_VERIFY = 0x00000001,
|
||||
IGNORE_CARD_COUNTS = 0x00000002,
|
||||
@@ -36,8 +32,6 @@ enum BehaviorFlag {
|
||||
DISABLE_INTERFERENCE = 0x00000100,
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum class StatSwapType : uint8_t {
|
||||
NONE = 0,
|
||||
A_T_SWAP = 1,
|
||||
@@ -413,8 +407,6 @@ enum class RegistrationPhase : uint8_t {
|
||||
INVALID_FF = 0xFF,
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum class Direction : uint8_t {
|
||||
RIGHT = 0,
|
||||
UP = 1,
|
||||
@@ -711,8 +703,6 @@ struct StateFlags {
|
||||
void clear_FF();
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct MapList {
|
||||
be_uint32_t num_maps;
|
||||
be_uint32_t unknown_a1; // Always 0?
|
||||
@@ -875,10 +865,10 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
|
||||
/* 59B0 */ parray<be_uint16_t, 0x10> reward_card_ids;
|
||||
|
||||
/* 59D0 */be_uint32_t unknown_a9_a;
|
||||
/* 59D4 */be_uint32_t unknown_a9_b;
|
||||
/* 59D8 */be_uint16_t unknown_a9_c;
|
||||
/* 59DA */be_uint16_t unknown_a9_d;
|
||||
/* 59D0 */ be_uint32_t unknown_a9_a;
|
||||
/* 59D4 */ be_uint32_t unknown_a9_b;
|
||||
/* 59D8 */ be_uint16_t unknown_a9_c;
|
||||
/* 59DA */ be_uint16_t unknown_a9_d;
|
||||
|
||||
/* 59DC */ uint8_t unknown_a10;
|
||||
|
||||
@@ -931,8 +921,6 @@ struct MapDefinition { // .mnmd format; also the format of (decompressed) quests
|
||||
std::string str(const DataIndex* data_index = nullptr) const;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct COMDeckDefinition {
|
||||
size_t index;
|
||||
std::string player_name;
|
||||
@@ -940,8 +928,6 @@ struct COMDeckDefinition {
|
||||
parray<le_uint16_t, 0x1F> card_ids;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DataIndex {
|
||||
public:
|
||||
DataIndex(const std::string& directory, uint32_t behavior_flags);
|
||||
@@ -1004,6 +990,4 @@ private:
|
||||
std::unordered_map<std::string, std::shared_ptr<COMDeckDefinition>> com_decks_by_name;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -4,8 +4,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
NameEntry::NameEntry() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -17,8 +15,6 @@ void NameEntry::clear() {
|
||||
this->unused = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DeckEntry::DeckEntry() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -32,8 +28,6 @@ void DeckEntry::clear() {
|
||||
this->card_ids.clear(0xFFFF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t index_for_card_ref(uint16_t card_ref) {
|
||||
return card_ref & 0xFF;
|
||||
}
|
||||
@@ -42,8 +36,6 @@ uint8_t client_id_for_card_ref(uint16_t card_ref) {
|
||||
return (card_ref >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t DeckState::num_drawable_cards() const {
|
||||
return this->card_refs.size() - this->draw_index;
|
||||
}
|
||||
@@ -281,6 +273,4 @@ void DeckState::shuffle() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../Text.hh"
|
||||
#include "../PSOEncryption.hh"
|
||||
#include "../Text.hh"
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
struct NameEntry {
|
||||
parray<char, 0x10> name;
|
||||
uint8_t client_id;
|
||||
@@ -112,6 +110,4 @@ private:
|
||||
std::shared_ptr<PSOV2Encryption> random_crypt;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -4,8 +4,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
MapState::MapState() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -32,8 +30,6 @@ void MapState::print(FILE* stream) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MapAndRulesState::MapAndRulesState() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -54,8 +50,6 @@ void MapAndRulesState::clear() {
|
||||
this->unused5 = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool MapAndRulesState::loc_is_within_bounds(uint8_t x, uint8_t y) const {
|
||||
return (x < this->map.width) && (y < this->map.height);
|
||||
}
|
||||
@@ -75,8 +69,6 @@ void MapAndRulesState::clear_occupied_bit_for_tile(uint8_t x, uint8_t y) {
|
||||
this->map.tiles[y][x] &= 0xEF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
OverlayState::OverlayState() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -90,6 +82,4 @@ void OverlayState::clear() {
|
||||
this->unused3.clear(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
struct MapState {
|
||||
le_uint16_t width;
|
||||
le_uint16_t height;
|
||||
@@ -58,6 +56,4 @@ struct OverlayState {
|
||||
void clear();
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -6,8 +6,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
PlayerState::PlayerState(uint8_t client_id, shared_ptr<Server> server)
|
||||
: w_server(server),
|
||||
client_id(client_id),
|
||||
@@ -39,7 +37,7 @@ PlayerState::PlayerState(uint8_t client_id, shared_ptr<Server> server)
|
||||
start_facing_direction(Direction::RIGHT),
|
||||
num_destroyed_fcs(0),
|
||||
unknown_a16(0),
|
||||
unknown_a17(0) { }
|
||||
unknown_a17(0) {}
|
||||
|
||||
void PlayerState::init() {
|
||||
if (this->server()->player_states[this->client_id].get() != this) {
|
||||
@@ -1411,7 +1409,8 @@ void PlayerState::update_hand_and_equip_state_and_send_6xB4x02_if_needed(
|
||||
cmd.state.sc_card_ref = this->sc_card_ref;
|
||||
cmd.state.assist_card_ref2 = this->card_refs[6];
|
||||
cmd.state.assist_card_set_number = (this->card_refs[6] == 0xFFFF)
|
||||
? 0 : this->assist_card_set_number;
|
||||
? 0
|
||||
: this->assist_card_set_number;
|
||||
cmd.state.assist_card_id = this->set_assist_card_id;
|
||||
cmd.state.assist_remaining_turns = this->assist_remaining_turns;
|
||||
cmd.state.assist_delay_turns = this->assist_delay_turns;
|
||||
@@ -1830,6 +1829,4 @@ void PlayerState::compute_team_dice_boost_after_draw_phase() {
|
||||
this->update_hand_and_equip_state_and_send_6xB4x02_if_needed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -5,15 +5,13 @@
|
||||
#include <memory>
|
||||
|
||||
#include "../Text.hh"
|
||||
#include "DataIndex.hh"
|
||||
#include "Card.hh"
|
||||
#include "DataIndex.hh"
|
||||
#include "DeckState.hh"
|
||||
#include "PlayerStateSubordinates.hh"
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
class ServerBase;
|
||||
class Server;
|
||||
|
||||
@@ -25,8 +23,7 @@ public:
|
||||
std::shared_ptr<const Server> server() const;
|
||||
|
||||
bool draw_cards_allowed() const;
|
||||
void apply_assist_card_effect_on_set(
|
||||
std::shared_ptr<PlayerState> setter_ps);
|
||||
void apply_assist_card_effect_on_set(std::shared_ptr<PlayerState> setter_ps);
|
||||
void apply_dice_effects();
|
||||
uint16_t card_ref_for_hand_index(size_t hand_index) const;
|
||||
int16_t compute_attack_or_defense_atk_costs(const ActionState& pa) const;
|
||||
@@ -188,6 +185,4 @@ public:
|
||||
PlayerStats stats;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -6,8 +6,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
template <size_t Count>
|
||||
std::string string_for_refs(const parray<le_uint16_t, Count>& card_refs) {
|
||||
string ret = "[";
|
||||
@@ -24,8 +22,6 @@ std::string string_for_refs(const parray<le_uint16_t, Count>& card_refs) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Condition::Condition() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -101,8 +97,6 @@ std::string Condition::str() const {
|
||||
this->unknown_a8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
EffectResult::EffectResult() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -137,8 +131,6 @@ std::string EffectResult::str() const {
|
||||
this->dice_roll_value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CardShortStatus::CardShortStatus() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -190,8 +182,6 @@ void CardShortStatus::clear_FF() {
|
||||
this->unused2 = 0xFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ActionState::ActionState() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -224,8 +214,6 @@ std::string ActionState::str() const {
|
||||
this->original_attacker_card_ref.load());
|
||||
}
|
||||
|
||||
|
||||
|
||||
ActionChain::ActionChain() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -339,8 +327,6 @@ void ActionChain::clear_FF() {
|
||||
this->target_card_refs.clear(0xFFFF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ActionChainWithConds::ActionChainWithConds() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -495,8 +481,6 @@ bool ActionChainWithConds::unknown_8024DEC4() const {
|
||||
return this->check_flag(4) ? false : (this->chain.target_card_ref_count != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ActionMetadata::ActionMetadata() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -610,8 +594,6 @@ void ActionMetadata::add_defense_card_ref(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
HandAndEquipState::HandAndEquipState() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -706,8 +688,6 @@ void HandAndEquipState::clear_FF() {
|
||||
this->unused2.clear(0xFF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PlayerStats::PlayerStats() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -747,12 +727,7 @@ float PlayerStats::score(size_t num_rounds) const {
|
||||
// Ep3 PsoV3.dol, so it's presumably correct. Is the PSO-World formula simply
|
||||
// incorrect, or is it from e.g. the Japanese version, which may have a
|
||||
// different rank calculation function?
|
||||
return 38.0f
|
||||
+ 0.8f * this->action_card_negated_damage
|
||||
- 2.3f * num_rounds
|
||||
- 1.8f * this->sc_damage_taken
|
||||
+ 3.0f * this->max_attack_combo_size
|
||||
+ (this->damage_given - this->damage_taken);
|
||||
return 38.0f + 0.8f * this->action_card_negated_damage - 2.3f * num_rounds - 1.8f * this->sc_damage_taken + 3.0f * this->max_attack_combo_size + (this->damage_given - this->damage_taken);
|
||||
}
|
||||
|
||||
uint8_t PlayerStats::rank(size_t num_rounds) const {
|
||||
@@ -784,9 +759,6 @@ const char* PlayerStats::name_for_rank(uint8_t rank) {
|
||||
return RANK_NAMES[rank];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool is_card_within_range(
|
||||
const parray<uint8_t, 9 * 9>& range,
|
||||
const Location& anchor_loc,
|
||||
@@ -824,6 +796,4 @@ vector<uint16_t> get_card_refs_within_range(
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
class ServerBase;
|
||||
class Server;
|
||||
class Card;
|
||||
@@ -269,13 +267,9 @@ struct PlayerStats {
|
||||
static const char* name_for_rank(uint8_t rank);
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
std::vector<uint16_t> get_card_refs_within_range(
|
||||
const parray<uint8_t, 9 * 9>& range,
|
||||
const Location& loc,
|
||||
const parray<CardShortStatus, 0x10>& short_statuses);
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -6,8 +6,6 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
void compute_effective_range(
|
||||
parray<uint8_t, 9 * 9>& ret,
|
||||
shared_ptr<const DataIndex> data_index,
|
||||
@@ -189,14 +187,12 @@ bool card_linkage_is_valid(
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RulerServer::RulerServer(shared_ptr<Server> server)
|
||||
: w_server(server),
|
||||
team_id_for_client_id(0xFF),
|
||||
error_code1(0),
|
||||
error_code2(0),
|
||||
error_code3(0) { }
|
||||
error_code3(0) {}
|
||||
|
||||
shared_ptr<Server> RulerServer::server() {
|
||||
auto s = this->w_server.lock();
|
||||
@@ -457,7 +453,6 @@ bool RulerServer::attack_action_has_pierce_and_not_rampage(
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool RulerServer::card_exists_by_status(const CardShortStatus& stat) const {
|
||||
if ((stat.card_flags & 3) || (stat.card_ref == 0xFFFF)) {
|
||||
return false;
|
||||
@@ -1435,7 +1430,8 @@ bool RulerServer::compute_effective_range_and_target_mode_for_attack(
|
||||
TargetMode* out_effective_target_mode,
|
||||
uint16_t* out_orig_card_ref) const {
|
||||
size_t z;
|
||||
for (z = 0; (z < 9) && (pa.action_card_refs[z] != 0xFFFF); z++) { }
|
||||
for (z = 0; (z < 9) && (pa.action_card_refs[z] != 0xFFFF); z++) {
|
||||
}
|
||||
if (z >= 9) {
|
||||
return false;
|
||||
}
|
||||
@@ -1984,7 +1980,8 @@ shared_ptr<const DataIndex::CardEntry> RulerServer::definition_for_card_id(
|
||||
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_id = (card_id_override == 0xFFFF)
|
||||
? this->card_id_for_card_ref(card_ref) : card_id_override;
|
||||
? this->card_id_for_card_ref(card_ref)
|
||||
: card_id_override;
|
||||
|
||||
if (card_id != 0xFFFF) {
|
||||
auto ce = this->definition_for_card_id(card_id);
|
||||
@@ -2450,7 +2447,7 @@ RulerServer::MovePath::MovePath()
|
||||
: length(-1),
|
||||
remaining_distance(0),
|
||||
num_occupied_tiles(0),
|
||||
cost(0) { }
|
||||
cost(0) {}
|
||||
|
||||
void RulerServer::MovePath::add_step(const Location& loc) {
|
||||
this->step_locs[++this->length] = loc;
|
||||
@@ -2676,6 +2673,4 @@ int32_t RulerServer::verify_deck(
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "DataIndex.hh"
|
||||
#include "PlayerState.hh"
|
||||
#include "DeckState.hh"
|
||||
#include "AssistServer.hh"
|
||||
#include "DataIndex.hh"
|
||||
#include "DeckState.hh"
|
||||
#include "PlayerState.hh"
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
class Server;
|
||||
|
||||
void compute_effective_range(
|
||||
@@ -227,6 +225,4 @@ public:
|
||||
int32_t error_code3;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
+13
-27
@@ -1,7 +1,7 @@
|
||||
#include "Server.hh"
|
||||
|
||||
#include <phosg/Time.hh>
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Time.hh>
|
||||
|
||||
#include "../SendCommands.hh"
|
||||
|
||||
@@ -9,15 +9,11 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
// These strings in the original implementation did not contain the semicolons
|
||||
// (or anything after them).
|
||||
// This is (obviously) not the original string. The original string is:
|
||||
// "[V1][FINAL2.0] 03/09/13 15:30 by K.Toya"
|
||||
static const char* VERSION_SIGNATURE =
|
||||
"newserv Ep3 based on [V1][FINAL2.0] 03/09/13 15:30 by K.Toya";
|
||||
|
||||
|
||||
|
||||
ServerBase::PresenceEntry::PresenceEntry() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -28,8 +24,6 @@ void ServerBase::PresenceEntry::clear() {
|
||||
this->is_cpu_player = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ServerBase::ServerBase(
|
||||
shared_ptr<Lobby> lobby,
|
||||
shared_ptr<const DataIndex> data_index,
|
||||
@@ -40,7 +34,7 @@ ServerBase::ServerBase(
|
||||
log(lobby->log.prefix + "[Ep3::Server] "),
|
||||
random_seed(random_seed),
|
||||
is_tournament(!!map_if_tournament),
|
||||
last_chosen_map(map_if_tournament) { }
|
||||
last_chosen_map(map_if_tournament) {}
|
||||
|
||||
void ServerBase::init() {
|
||||
this->reset();
|
||||
@@ -65,8 +59,6 @@ void ServerBase::recreate_server() {
|
||||
this->server->init();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Server::Server(shared_ptr<ServerBase> base)
|
||||
: w_base(base),
|
||||
battle_finished(false),
|
||||
@@ -104,7 +96,7 @@ Server::Server(shared_ptr<ServerBase> base)
|
||||
chosen_trap_tile_index_of_type(0),
|
||||
has_done_pb(0),
|
||||
num_6xB4x06_commands_sent(0),
|
||||
prev_num_6xB4x06_commands_sent(0) { }
|
||||
prev_num_6xB4x06_commands_sent(0) {}
|
||||
|
||||
void Server::init() {
|
||||
this->card_special.reset(new CardSpecial(this->shared_from_this()));
|
||||
@@ -262,8 +254,7 @@ void Server::send_commands_for_joining_spectator(Channel& c) const {
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
void Server::log_debug(const char* fmt, ...) const {
|
||||
__attribute__((format(printf, 2, 3))) void Server::log_debug(const char* fmt, ...) const {
|
||||
auto l = this->base()->lobby.lock();
|
||||
if (l && (this->base()->data_index->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) {
|
||||
va_list va;
|
||||
@@ -273,8 +264,7 @@ void Server::log_debug(const char* fmt, ...) const {
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
void Server::send_debug_message_printf(const char* fmt, ...) const {
|
||||
__attribute__((format(printf, 2, 3))) void Server::send_debug_message_printf(const char* fmt, ...) const {
|
||||
auto l = this->base()->lobby.lock();
|
||||
if (l && (this->base()->data_index->behavior_flags & Episode3::BehaviorFlag::ENABLE_STATUS_MESSAGES)) {
|
||||
va_list va;
|
||||
@@ -286,8 +276,7 @@ void Server::send_debug_message_printf(const char* fmt, ...) const {
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
void Server::send_info_message_printf(const char* fmt, ...) const {
|
||||
__attribute__((format(printf, 2, 3))) void Server::send_info_message_printf(const char* fmt, ...) const {
|
||||
auto l = this->base()->lobby.lock();
|
||||
if (l) {
|
||||
va_list va;
|
||||
@@ -539,7 +528,8 @@ void Server::check_for_destroyed_cards_and_send_6xB4x05_6xB4x02() {
|
||||
|
||||
bool Server::check_presence_entry(uint8_t client_id) const {
|
||||
return (client_id < 4)
|
||||
? this->base()->presence_entries[client_id].player_present : false;
|
||||
? this->base()->presence_entries[client_id].player_present
|
||||
: false;
|
||||
}
|
||||
|
||||
void Server::clear_player_flags_after_dice_phase() {
|
||||
@@ -1220,7 +1210,6 @@ void Server::set_client_id_ready_to_advance_phase(uint8_t client_id) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Server::set_phase_after() {
|
||||
for (size_t client_id = 0; client_id < 4; client_id++) {
|
||||
auto ps = this->player_states[client_id];
|
||||
@@ -2025,7 +2014,7 @@ void Server::handle_6xB3x28_end_defense_list(const string& data) {
|
||||
this->send(out_cmd_fin);
|
||||
}
|
||||
|
||||
void Server::handle_6xB3x2B_ignored(const string&) { }
|
||||
void Server::handle_6xB3x2B_ignored(const string&) {}
|
||||
|
||||
void Server::handle_6xB3x34_subtract_ally_atk_points(const string& data) {
|
||||
const auto& in_cmd = check_size_t<G_PhotonBlastRequest_GC_Ep3_6xB3x34_CAx34>(data);
|
||||
@@ -2131,7 +2120,7 @@ void Server::handle_6xB3x37_client_ready_to_advance_from_starter_roll_phase(cons
|
||||
}
|
||||
}
|
||||
|
||||
void Server::handle_6xB3x3A_ignored(const string&) { }
|
||||
void Server::handle_6xB3x3A_ignored(const string&) {}
|
||||
|
||||
void Server::handle_6xB3x40_map_list_request(const string& data) {
|
||||
const auto& in_cmd = check_size_t<G_MapListRequest_GC_Ep3_6xB3x40_CAx40>(data);
|
||||
@@ -2379,7 +2368,7 @@ void Server::unknown_8023EEF4() {
|
||||
if (!this->attack_cards[this->unknown_a14]->action_chain.check_flag(0x40)) {
|
||||
this->card_special->unknown_8024945C(this->attack_cards[this->unknown_a14], as);
|
||||
}
|
||||
this->attack_cards[this->unknown_a14]->compute_action_chain_results(1,0);
|
||||
this->attack_cards[this->unknown_a14]->compute_action_chain_results(1, 0);
|
||||
this->attack_cards[this->unknown_a14]->unknown_80236374(this->attack_cards[this->unknown_a14], &as);
|
||||
if (!this->attack_cards[this->unknown_a14]->action_chain.check_flag(0x40)) {
|
||||
this->card_special->unknown_8024966C(this->attack_cards[this->unknown_a14], &as);
|
||||
@@ -2653,7 +2642,6 @@ void Server::send_6xB4x05() {
|
||||
this->send(cmd);
|
||||
}
|
||||
|
||||
|
||||
void Server::send_6xB4x02_for_all_players_if_needed(bool always_send) {
|
||||
for (size_t z = 0; z < 4; z++) {
|
||||
auto ps = this->player_states[z];
|
||||
@@ -2680,6 +2668,4 @@ void Server::send_6xB4x50_trap_tile_locations() const {
|
||||
this->send(this->prepare_6xB4x50_trap_tile_locations());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
+6
-14
@@ -4,9 +4,9 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../Text.hh"
|
||||
#include "../CommandFormats.hh"
|
||||
#include "../Channel.hh"
|
||||
#include "../CommandFormats.hh"
|
||||
#include "../Text.hh"
|
||||
#include "AssistServer.hh"
|
||||
#include "CardSpecial.hh"
|
||||
#include "MapState.hh"
|
||||
@@ -17,8 +17,6 @@ struct Lobby;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This implementation of Episode 3 battles (contained in all files in the
|
||||
* src/Episode3 directory, except for DataIndex.hh/cc) is derived from Sega's
|
||||
@@ -55,8 +53,6 @@ namespace Episode3 {
|
||||
|
||||
class Server;
|
||||
|
||||
|
||||
|
||||
class ServerBase : public std::enable_shared_from_this<ServerBase> {
|
||||
public:
|
||||
ServerBase(
|
||||
@@ -122,13 +118,10 @@ public:
|
||||
|
||||
void send_commands_for_joining_spectator(Channel& ch) const;
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
void log_debug(const char* fmt, ...) const;
|
||||
__attribute__((format(printf, 2, 3))) void log_debug(const char* fmt, ...) const;
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
void send_debug_message_printf(const char* fmt, ...) const;
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
void send_info_message_printf(const char* fmt, ...) const;
|
||||
__attribute__((format(printf, 2, 3))) void send_debug_message_printf(const char* fmt, ...) const;
|
||||
__attribute__((format(printf, 2, 3))) void send_info_message_printf(const char* fmt, ...) const;
|
||||
void send_debug_command_received_message(
|
||||
uint8_t client_id, uint8_t subsubcommand, const char* description) const;
|
||||
void send_debug_command_received_message(
|
||||
@@ -241,6 +234,7 @@ public:
|
||||
|
||||
std::vector<std::shared_ptr<Card>> const_cast_set_cards_v(
|
||||
const std::vector<std::shared_ptr<const Card>>& cards);
|
||||
|
||||
private:
|
||||
typedef void (Server::*handler_t)(const std::string&);
|
||||
static const std::unordered_map<uint8_t, handler_t> subcommand_handlers;
|
||||
@@ -301,6 +295,4 @@ public:
|
||||
mutable uint32_t prev_num_6xB4x06_commands_sent;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
+14
-25
@@ -9,14 +9,14 @@ using namespace std;
|
||||
|
||||
namespace Episode3 {
|
||||
|
||||
|
||||
|
||||
Tournament::PlayerEntry::PlayerEntry(uint32_t serial_number)
|
||||
: serial_number(serial_number), com_deck() { }
|
||||
: serial_number(serial_number),
|
||||
com_deck() {}
|
||||
|
||||
Tournament::PlayerEntry::PlayerEntry(
|
||||
shared_ptr<const COMDeckDefinition> com_deck)
|
||||
: serial_number(0), com_deck(com_deck) { }
|
||||
: serial_number(0),
|
||||
com_deck(com_deck) {}
|
||||
|
||||
bool Tournament::PlayerEntry::is_com() const {
|
||||
return (this->com_deck != nullptr);
|
||||
@@ -26,8 +26,6 @@ bool Tournament::PlayerEntry::is_human() const {
|
||||
return (this->serial_number != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Tournament::Team::Team(
|
||||
shared_ptr<Tournament> tournament, size_t index, size_t max_players)
|
||||
: tournament(tournament),
|
||||
@@ -36,7 +34,7 @@ Tournament::Team::Team(
|
||||
name(""),
|
||||
password(""),
|
||||
num_rounds_cleared(0),
|
||||
is_active(true) { }
|
||||
is_active(true) {}
|
||||
|
||||
string Tournament::Team::str() const {
|
||||
size_t num_human_players = 0;
|
||||
@@ -173,8 +171,6 @@ size_t Tournament::Team::num_com_players() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Tournament::Match::Match(
|
||||
shared_ptr<Tournament> tournament,
|
||||
shared_ptr<Match> preceding_a,
|
||||
@@ -197,7 +193,7 @@ Tournament::Match::Match(
|
||||
preceding_a(nullptr),
|
||||
preceding_b(nullptr),
|
||||
winner_team(winner_team),
|
||||
round_num(0) { }
|
||||
round_num(0) {}
|
||||
|
||||
string Tournament::Match::str() const {
|
||||
string winner_str = this->winner_team ? this->winner_team->str() : "(none)";
|
||||
@@ -216,7 +212,8 @@ bool Tournament::Match::resolve_if_no_human_players() {
|
||||
!this->preceding_a->winner_team->has_any_human_players() &&
|
||||
!this->preceding_b->winner_team->has_any_human_players()) {
|
||||
this->set_winner_team((random_object<uint8_t>() & 1)
|
||||
? this->preceding_b->winner_team : this->preceding_a->winner_team);
|
||||
? this->preceding_b->winner_team
|
||||
: this->preceding_a->winner_team);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -282,8 +279,6 @@ shared_ptr<Tournament::Team> Tournament::Match::opponent_team_for_team(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Tournament::Tournament(
|
||||
shared_ptr<const DataIndex> data_index,
|
||||
uint8_t number,
|
||||
@@ -320,7 +315,7 @@ Tournament::Tournament(
|
||||
data_index(data_index),
|
||||
source_json(json),
|
||||
number(number),
|
||||
current_state(State::REGISTRATION) { }
|
||||
current_state(State::REGISTRATION) {}
|
||||
|
||||
void Tournament::init() {
|
||||
vector<size_t> team_index_to_rounds_cleared;
|
||||
@@ -414,10 +409,8 @@ void Tournament::init() {
|
||||
if (!match->preceding_a->winner_team || !match->preceding_b->winner_team) {
|
||||
throw logic_error("preceding matches are not resolved");
|
||||
}
|
||||
size_t& a_rounds_cleared = team_index_to_rounds_cleared[
|
||||
match->preceding_a->winner_team->index];
|
||||
size_t& b_rounds_cleared = team_index_to_rounds_cleared[
|
||||
match->preceding_b->winner_team->index];
|
||||
size_t& a_rounds_cleared = team_index_to_rounds_cleared[match->preceding_a->winner_team->index];
|
||||
size_t& b_rounds_cleared = team_index_to_rounds_cleared[match->preceding_b->winner_team->index];
|
||||
if (a_rounds_cleared && b_rounds_cleared) {
|
||||
throw runtime_error("both teams won the same match");
|
||||
}
|
||||
@@ -469,8 +462,7 @@ std::shared_ptr<JSONObject> Tournament::json() const {
|
||||
dict.emplace("map_number", make_json_int(this->map->map.map_number));
|
||||
dict.emplace("rules", this->rules.json());
|
||||
dict.emplace("is_2v2", make_json_bool(this->is_2v2));
|
||||
dict.emplace("is_registration_complete", make_json_bool(
|
||||
this->current_state != State::REGISTRATION));
|
||||
dict.emplace("is_registration_complete", make_json_bool(this->current_state != State::REGISTRATION));
|
||||
|
||||
vector<shared_ptr<JSONObject>> teams_list;
|
||||
for (auto team : this->teams) {
|
||||
@@ -661,13 +653,12 @@ void Tournament::print_bracket(FILE* stream) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TournamentIndex::TournamentIndex(
|
||||
shared_ptr<const DataIndex> data_index,
|
||||
const string& state_filename,
|
||||
bool skip_load_state)
|
||||
: data_index(data_index), state_filename(state_filename) {
|
||||
: data_index(data_index),
|
||||
state_filename(state_filename) {
|
||||
if (this->state_filename.empty() || skip_load_state) {
|
||||
return;
|
||||
}
|
||||
@@ -768,6 +759,4 @@ shared_ptr<Tournament::Team> TournamentIndex::team_for_serial_number(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <event2/event.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <phosg/JSON.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "../Player.hh"
|
||||
|
||||
@@ -18,8 +18,6 @@ namespace Episode3 {
|
||||
|
||||
// The comment in Server.hh does not apply to this file (and Tournament.cc).
|
||||
|
||||
|
||||
|
||||
class Tournament : public std::enable_shared_from_this<Tournament> {
|
||||
public:
|
||||
enum class State {
|
||||
@@ -190,6 +188,4 @@ private:
|
||||
std::shared_ptr<Tournament> tournaments[0x20];
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Episode3
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
FileContentsCache::FileContentsCache(uint64_t ttl_usecs) : ttl_usecs(ttl_usecs) { }
|
||||
FileContentsCache::FileContentsCache(uint64_t ttl_usecs) : ttl_usecs(ttl_usecs) {}
|
||||
|
||||
FileContentsCache::File::File(
|
||||
const string& name,
|
||||
string&& data,
|
||||
uint64_t load_time)
|
||||
: name(name), data(new string(move(data))), load_time(load_time) { }
|
||||
: name(name),
|
||||
data(new string(move(data))),
|
||||
load_time(load_time) {}
|
||||
|
||||
shared_ptr<const FileContentsCache::File> FileContentsCache::replace(
|
||||
const string& name, string&& data, uint64_t t) {
|
||||
@@ -65,7 +65,8 @@ FileContentsCache::GetResult FileContentsCache::get(const std::string& name,
|
||||
if (this->ttl_usecs && (t - entry->load_time < this->ttl_usecs)) {
|
||||
return {entry, false};
|
||||
}
|
||||
} catch (const out_of_range& e) { }
|
||||
} catch (const out_of_range& e) {
|
||||
}
|
||||
return {this->replace(name, generate(name)), true};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#include <phosg/Time.hh>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class FileContentsCache {
|
||||
public:
|
||||
struct File {
|
||||
@@ -92,7 +91,8 @@ public:
|
||||
if (this->ttl_usecs && (t - f->load_time < this->ttl_usecs)) {
|
||||
return {*reinterpret_cast<const T*>(f->data->data()), f, false};
|
||||
}
|
||||
} catch (const out_of_range& e) { }
|
||||
} catch (const out_of_range& e) {
|
||||
}
|
||||
T value = generate(name);
|
||||
auto ret = this->replace_obj(name, value);
|
||||
ret.generate_called = true;
|
||||
|
||||
+2
-14
@@ -3,20 +3,18 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef HAVE_RESOURCE_FILE
|
||||
#include <resource_file/Emulators/PPC32Emulator.hh>
|
||||
#endif
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "CommandFormats.hh"
|
||||
#include "Loggers.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
bool function_compiler_available() {
|
||||
#ifndef HAVE_RESOURCE_FILE
|
||||
return false;
|
||||
@@ -25,8 +23,6 @@ bool function_compiler_available() {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* name_for_architecture(CompiledFunctionCode::Architecture arch) {
|
||||
switch (arch) {
|
||||
case CompiledFunctionCode::Architecture::POWERPC:
|
||||
@@ -38,8 +34,6 @@ const char* name_for_architecture(CompiledFunctionCode::Architecture arch) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename FooterT>
|
||||
string CompiledFunctionCode::generate_client_command_t(
|
||||
const unordered_map<string, uint32_t>& label_writes,
|
||||
@@ -99,8 +93,6 @@ bool CompiledFunctionCode::is_big_endian() const {
|
||||
return this->arch == Architecture::POWERPC;
|
||||
}
|
||||
|
||||
|
||||
|
||||
shared_ptr<CompiledFunctionCode> compile_function_code(
|
||||
CompiledFunctionCode::Architecture arch,
|
||||
const string& directory,
|
||||
@@ -159,8 +151,6 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
|
||||
if (!function_compiler_available()) {
|
||||
function_compiler_log.info("Function compiler is not available");
|
||||
@@ -217,8 +207,6 @@ vector<MenuItem> FunctionCodeIndex::patch_menu() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DOLFileIndex::DOLFileIndex(const string& directory) {
|
||||
if (!function_compiler_available()) {
|
||||
function_compiler_log.info("Function compiler is not available");
|
||||
|
||||
+2
-10
@@ -2,20 +2,16 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "Menu.hh"
|
||||
|
||||
|
||||
|
||||
bool function_compiler_available();
|
||||
|
||||
|
||||
|
||||
// TODO: Support x86 and SH4 function calls in the future. Currently we only
|
||||
// support PPC32 because I haven't written an appropriate x86 assembler yet.
|
||||
|
||||
@@ -54,8 +50,6 @@ std::shared_ptr<CompiledFunctionCode> compile_function_code(
|
||||
const std::string& name,
|
||||
const std::string& text);
|
||||
|
||||
|
||||
|
||||
struct FunctionCodeIndex {
|
||||
FunctionCodeIndex() = default;
|
||||
explicit FunctionCodeIndex(const std::string& directory);
|
||||
@@ -72,8 +66,6 @@ struct FunctionCodeIndex {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct DOLFileIndex {
|
||||
struct DOLFile {
|
||||
uint32_t menu_item_id;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
template <bool IsBigEndian>
|
||||
struct GSLHeaderEntry {
|
||||
using U32T = typename std::conditional<IsBigEndian, be_uint32_t, le_uint32_t>::type;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
|
||||
class GSLArchive {
|
||||
public:
|
||||
GSLArchive(std::shared_ptr<const std::string> data, bool big_endian);
|
||||
|
||||
+12
-11
@@ -6,8 +6,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
static inline uint16_t collapse_checksum(uint32_t sum) {
|
||||
// It's impossible for this to be necessary more than twice: the first
|
||||
// addition can carry out at most a single bit.
|
||||
@@ -15,8 +13,6 @@ static inline uint16_t collapse_checksum(uint32_t sum) {
|
||||
return (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FrameInfo::FrameInfo()
|
||||
: ether(nullptr),
|
||||
ether_protocol(0),
|
||||
@@ -28,9 +24,9 @@ FrameInfo::FrameInfo()
|
||||
payload(nullptr),
|
||||
total_size(0),
|
||||
tcp_options_size(0),
|
||||
payload_size(0) { }
|
||||
payload_size(0) {}
|
||||
|
||||
FrameInfo::FrameInfo(const string& data) : FrameInfo(data.data(), data.size()) { }
|
||||
FrameInfo::FrameInfo(const string& data) : FrameInfo(data.data(), data.size()) {}
|
||||
|
||||
FrameInfo::FrameInfo(const void* header_start, size_t size)
|
||||
: ether(nullptr),
|
||||
@@ -125,26 +121,31 @@ string FrameInfo::header_str() const {
|
||||
return "<invalid-frame-info>";
|
||||
}
|
||||
|
||||
string ret = string_printf("%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX->%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
|
||||
string ret = string_printf(
|
||||
"%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[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[3], this->ether->dest_mac[4], this->ether->dest_mac[5]);
|
||||
|
||||
if (this->arp) {
|
||||
ret += string_printf(",ARP,hw_type=%04hX,proto_type=%04hX,hw_addr_len=%02hhX,proto_addr_len=%02hhX,op=%04hX",
|
||||
ret += string_printf(
|
||||
",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());
|
||||
|
||||
} else if (this->ipv4) {
|
||||
ret += string_printf(",IPv4,size=%04hX,src=%08" PRIX32 ",dest=%08" PRIX32,
|
||||
ret += string_printf(
|
||||
",IPv4,size=%04hX,src=%08" PRIX32 ",dest=%08" PRIX32,
|
||||
this->ipv4->size.load(), this->ipv4->src_addr.load(), this->ipv4->dest_addr.load());
|
||||
|
||||
if (this->udp) {
|
||||
ret += string_printf(",UDP,src_port=%04hX,dest_port=%04hX,size=%04hX",
|
||||
ret += string_printf(
|
||||
",UDP,src_port=%04hX,dest_port=%04hX,size=%04hX",
|
||||
this->udp->src_port.load(), this->udp->dest_port.load(), this->udp->size.load());
|
||||
|
||||
} else if (this->tcp) {
|
||||
ret += string_printf(",TCP,src_port=%04hX,dest_port=%04hX,seq=%08" PRIX32 ",ack=%08" PRIX32 ",flags=%04hX(",
|
||||
ret += string_printf(
|
||||
",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());
|
||||
if (this->tcp->flags & TCPHeader::Flag::FIN) {
|
||||
ret += "FIN,";
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#include <phosg/Encoding.hh>
|
||||
|
||||
|
||||
|
||||
struct EthernetHeader {
|
||||
uint8_t dest_mac[6];
|
||||
uint8_t src_mac[6];
|
||||
@@ -63,8 +61,6 @@ struct TCPHeader {
|
||||
be_uint16_t urgent_ptr;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct FrameInfo {
|
||||
// This is always valid
|
||||
const EthernetHeader* ether;
|
||||
|
||||
+15
-46
@@ -1,30 +1,26 @@
|
||||
#include "IPStackSimulator.hh"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/listener.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <phosg/Network.hh>
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Time.hh>
|
||||
#include <string>
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "IPFrameInfo.hh"
|
||||
#include "DNSServer.hh"
|
||||
#include "IPFrameInfo.hh"
|
||||
#include "Loggers.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
static const size_t DEFAULT_RESEND_PUSH_USECS = 200000; // 200ms
|
||||
|
||||
|
||||
|
||||
// Note: these functions exist because seq nums are allowed to wrap around the
|
||||
// 32-bit integer space by design. We have to do the subtraction before the
|
||||
// comparison to allow integer overflow to occur if needed.
|
||||
@@ -45,8 +41,6 @@ static __attribute__((unused)) inline bool seq_num_greater_or_equal(uint32_t a,
|
||||
return (a == b) || seq_num_greater(a, b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
string IPStackSimulator::str_for_ipv4_netloc(uint32_t addr, uint16_t port) {
|
||||
be_uint32_t be_addr = addr;
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
@@ -67,8 +61,6 @@ string IPStackSimulator::str_for_tcp_connection(shared_ptr<const IPClient> c,
|
||||
fd, key, client_netloc_str.c_str(), server_netloc_str.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
IPStackSimulator::IPStackSimulator(
|
||||
std::shared_ptr<struct event_base> base,
|
||||
std::shared_ptr<ServerState> state)
|
||||
@@ -85,8 +77,6 @@ IPStackSimulator::~IPStackSimulator() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IPStackSimulator::listen(const std::string& socket_path) {
|
||||
this->add_socket(::listen(socket_path, 0, SOMAXCONN));
|
||||
}
|
||||
@@ -111,8 +101,6 @@ void IPStackSimulator::add_socket(int fd) {
|
||||
evconnlistener_free);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t IPStackSimulator::connect_address_for_remote_address(uint32_t remote_addr) {
|
||||
// Use an address not on the same subnet as the client, so that PSO Plus and
|
||||
// Episode III will think they're talking to a remote network and won't reject
|
||||
@@ -124,15 +112,12 @@ uint32_t IPStackSimulator::connect_address_for_remote_address(uint32_t remote_ad
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
IPStackSimulator::IPClient::IPClient(struct bufferevent* bev)
|
||||
: bev(bev, bufferevent_free), ipv4_addr(0) {
|
||||
: bev(bev, bufferevent_free),
|
||||
ipv4_addr(0) {
|
||||
memset(this->mac_addr, 0, 6);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void flush_and_free_bufferevent(struct bufferevent* bev) {
|
||||
bufferevent_flush(bev, EV_READ | EV_WRITE, BEV_FINISHED);
|
||||
bufferevent_free(bev);
|
||||
@@ -152,13 +137,11 @@ IPStackSimulator::IPClient::TCPConnection::TCPConnection()
|
||||
next_push_max_frame_size(1024),
|
||||
max_frame_size(1024),
|
||||
bytes_received(0),
|
||||
bytes_sent(0) { }
|
||||
|
||||
|
||||
bytes_sent(0) {}
|
||||
|
||||
void IPStackSimulator::dispatch_on_listen_accept(
|
||||
struct evconnlistener* listener, evutil_socket_t fd,
|
||||
struct sockaddr *address, int socklen, void* ctx) {
|
||||
struct sockaddr* address, int socklen, void* ctx) {
|
||||
reinterpret_cast<IPStackSimulator*>(ctx)->on_listen_accept(
|
||||
listener, fd, address, socklen);
|
||||
}
|
||||
@@ -168,7 +151,7 @@ void IPStackSimulator::on_listen_accept(struct evconnlistener* listener,
|
||||
int listen_fd = evconnlistener_get_fd(listener);
|
||||
ip_stack_simulator_log.info("Virtual network fd %d connected via fd %d", fd, listen_fd);
|
||||
|
||||
struct bufferevent *bev = bufferevent_socket_new(this->base.get(), fd,
|
||||
struct bufferevent* bev = bufferevent_socket_new(this->base.get(), fd,
|
||||
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
|
||||
shared_ptr<IPClient> c(new IPClient(bev));
|
||||
c->sim = this;
|
||||
@@ -191,8 +174,6 @@ void IPStackSimulator::on_listen_error(struct evconnlistener* listener) {
|
||||
event_base_loopexit(this->base.get(), nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IPStackSimulator::dispatch_on_client_input(
|
||||
struct bufferevent* bev, void* ctx) {
|
||||
reinterpret_cast<IPStackSimulator*>(ctx)->on_client_input(bev);
|
||||
@@ -250,8 +231,6 @@ void IPStackSimulator::on_client_error(struct bufferevent* bev,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IPStackSimulator::on_client_frame(
|
||||
shared_ptr<IPClient> c, const string& frame) {
|
||||
if (ip_stack_simulator_log.info("Virtual network sent frame")) {
|
||||
@@ -310,8 +289,6 @@ void IPStackSimulator::on_client_frame(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IPStackSimulator::on_client_arp_frame(
|
||||
shared_ptr<IPClient> c, const FrameInfo& fi) {
|
||||
if (fi.arp->hwaddr_len != 6 ||
|
||||
@@ -382,8 +359,6 @@ void IPStackSimulator::on_client_arp_frame(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IPStackSimulator::on_client_udp_frame(
|
||||
shared_ptr<IPClient> c, const FrameInfo& fi) {
|
||||
// We only implement the DNS server here
|
||||
@@ -453,8 +428,6 @@ void IPStackSimulator::on_client_udp_frame(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint64_t IPStackSimulator::tcp_conn_key_for_connection(
|
||||
const IPClient::TCPConnection& conn) {
|
||||
return (static_cast<uint64_t>(conn.server_addr) << 32) |
|
||||
@@ -476,14 +449,12 @@ uint64_t IPStackSimulator::tcp_conn_key_for_client_frame(const FrameInfo& fi) {
|
||||
return IPStackSimulator::tcp_conn_key_for_client_frame(*fi.ipv4, *fi.tcp);
|
||||
}
|
||||
|
||||
|
||||
void IPStackSimulator::on_client_tcp_frame(
|
||||
shared_ptr<IPClient> c, const FrameInfo& fi) {
|
||||
ip_stack_simulator_log.info("Virtual network sent TCP frame (seq=%08" PRIX32 ", ack=%08" PRIX32 ")",
|
||||
fi.tcp->seq_num.load(), fi.tcp->ack_num.load());
|
||||
|
||||
if (fi.tcp->flags & (TCPHeader::Flag::NS | TCPHeader::Flag::CWR |
|
||||
TCPHeader::Flag::ECE | TCPHeader::Flag::URG)) {
|
||||
if (fi.tcp->flags & (TCPHeader::Flag::NS | TCPHeader::Flag::CWR | TCPHeader::Flag::ECE | TCPHeader::Flag::URG)) {
|
||||
throw runtime_error("unsupported flag in TCP packet");
|
||||
}
|
||||
|
||||
@@ -536,7 +507,6 @@ void IPStackSimulator::on_client_tcp_frame(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t key = this->tcp_conn_key_for_client_frame(fi);
|
||||
auto emplace_ret = c->tcp_connections.emplace(key, IPClient::TCPConnection());
|
||||
auto& conn = emplace_ret.first->second;
|
||||
@@ -655,7 +625,8 @@ void IPStackSimulator::on_client_tcp_frame(
|
||||
} else if (fi.payload_size != 0) {
|
||||
|
||||
string conn_str = ip_stack_simulator_log.should_log(LogLevel::WARNING)
|
||||
? this->str_for_tcp_connection(c, *conn) : "";
|
||||
? this->str_for_tcp_connection(c, *conn)
|
||||
: "";
|
||||
|
||||
size_t payload_skip_bytes;
|
||||
if (fi.tcp->seq_num == conn->next_client_seq) {
|
||||
@@ -939,8 +910,6 @@ void IPStackSimulator::on_server_error(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IPStackSimulator::log_frame(const string& data) const {
|
||||
if (this->pcap_text_log_file) {
|
||||
print_data(this->pcap_text_log_file, data, 0, nullptr,
|
||||
|
||||
+10
-12
@@ -1,18 +1,16 @@
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <phosg/Process.hh>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Process.hh>
|
||||
#include <string>
|
||||
|
||||
#include "IPFrameInfo.hh"
|
||||
#include "Server.hh"
|
||||
#include "ProxyServer.hh"
|
||||
#include "Server.hh"
|
||||
#include "ServerState.hh"
|
||||
|
||||
|
||||
|
||||
class IPStackSimulator {
|
||||
public:
|
||||
IPStackSimulator(
|
||||
@@ -31,10 +29,10 @@ private:
|
||||
std::shared_ptr<struct event_base> base;
|
||||
std::shared_ptr<ServerState> state;
|
||||
|
||||
using unique_listener = std::unique_ptr<struct evconnlistener, void(*)(struct evconnlistener*)>;
|
||||
using unique_bufferevent = std::unique_ptr<struct bufferevent, void(*)(struct bufferevent*)>;
|
||||
using unique_evbuffer = std::unique_ptr<struct evbuffer, void(*)(struct evbuffer*)>;
|
||||
using unique_event = std::unique_ptr<struct event, void(*)(struct event*)>;
|
||||
using unique_listener = std::unique_ptr<struct evconnlistener, void (*)(struct evconnlistener*)>;
|
||||
using unique_bufferevent = std::unique_ptr<struct bufferevent, void (*)(struct bufferevent*)>;
|
||||
using unique_evbuffer = std::unique_ptr<struct evbuffer, void (*)(struct evbuffer*)>;
|
||||
using unique_event = std::unique_ptr<struct event, void (*)(struct event*)>;
|
||||
|
||||
struct IPClient {
|
||||
IPStackSimulator* sim;
|
||||
@@ -96,9 +94,9 @@ private:
|
||||
const IPClient::TCPConnection& conn);
|
||||
|
||||
static void dispatch_on_listen_accept(struct evconnlistener* listener,
|
||||
evutil_socket_t fd, struct sockaddr *address, int socklen, void* ctx);
|
||||
evutil_socket_t fd, struct sockaddr* address, int socklen, void* ctx);
|
||||
void on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd,
|
||||
struct sockaddr *address, int socklen);
|
||||
struct sockaddr* address, int socklen);
|
||||
static void dispatch_on_listen_error(struct evconnlistener* listener, void* ctx);
|
||||
void on_listen_error(struct evconnlistener* listener);
|
||||
|
||||
|
||||
+125
-61
@@ -5,8 +5,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
ItemCreator::ItemCreator(
|
||||
shared_ptr<const CommonItemSet> common_item_set,
|
||||
shared_ptr<const RareItemSet> rare_item_set,
|
||||
@@ -40,8 +38,6 @@ ItemCreator::ItemCreator(
|
||||
print_data(stderr, this->pt, sizeof(*this->pt));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ItemCreator::are_rare_drops_allowed() const {
|
||||
// Note: The client has an additional check here, which appears to be a subtle
|
||||
// anti-cheating measure. There is a flag on the client, initially zero, which
|
||||
@@ -109,8 +105,6 @@ uint8_t ItemCreator::normalize_area_number(uint8_t area) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ItemData ItemCreator::on_box_item_drop(uint8_t area) {
|
||||
return this->on_box_item_drop_with_norm_area(normalize_area_number(area) - 1);
|
||||
}
|
||||
@@ -174,8 +168,10 @@ ItemData ItemCreator::on_monster_item_drop_with_norm_area(
|
||||
|
||||
ItemData item = this->check_rare_spec_and_create_rare_enemy_item(enemy_type);
|
||||
if (item.empty()) {
|
||||
uint32_t item_class_determinant = this->should_allow_meseta_drops()
|
||||
? this->rand_int(3) : (this->rand_int(2) + 1);
|
||||
uint32_t item_class_determinant =
|
||||
this->should_allow_meseta_drops()
|
||||
? this->rand_int(3)
|
||||
: (this->rand_int(2) + 1);
|
||||
|
||||
uint32_t item_class;
|
||||
switch (item_class_determinant) {
|
||||
@@ -214,7 +210,8 @@ ItemData ItemCreator::on_monster_item_drop_with_norm_area(
|
||||
case 5: // Meseta
|
||||
item.data1[0] = 0x04;
|
||||
item.data2d = this->choose_meseta_amount(
|
||||
this->pt->enemy_meseta_ranges, enemy_type) & 0xFFFF;
|
||||
this->pt->enemy_meseta_ranges, enemy_type) &
|
||||
0xFFFF;
|
||||
break;
|
||||
default:
|
||||
return item;
|
||||
@@ -246,8 +243,6 @@ ItemData ItemCreator::check_rare_specs_and_create_rare_box_item(
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t ItemCreator::rand_int(uint64_t max) {
|
||||
return this->random_crypt.next() % max;
|
||||
}
|
||||
@@ -403,8 +398,6 @@ void ItemCreator::set_item_unidentified_flag_if_challenge(ItemData& item) const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemCreator::set_tool_item_amount_to_1(ItemData& item) const {
|
||||
if (item.data1[0] == 0x03) {
|
||||
item.set_tool_item_amount(1);
|
||||
@@ -418,8 +411,6 @@ void ItemCreator::clear_tool_item_if_invalid(ItemData& item) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemCreator::clear_item_if_restricted(ItemData& item) const {
|
||||
if (this->item_parameter_table->is_item_rare(item) && !this->are_rare_drops_allowed()) {
|
||||
this->log.info("Restricted: item is rare, but rares not allowed");
|
||||
@@ -432,8 +423,7 @@ void ItemCreator::clear_item_if_restricted(ItemData& item) const {
|
||||
// Note: PSO GC doesn't check for 0x61 or 0x62 here since those items
|
||||
// (HP/Resurrection and TP/Resurrection) only exist on BB.
|
||||
if (item.data1[0] == 1) {
|
||||
if ((item.data1[1] == 3) && (
|
||||
((item.data1[2] >= 0x33) && (item.data1[2] <= 0x38)) ||
|
||||
if ((item.data1[1] == 3) && (((item.data1[2] >= 0x33) && (item.data1[2] <= 0x38)) ||
|
||||
(item.data1[2] == 0x61) || (item.data1[2] == 0x62))) {
|
||||
this->log.info("Restricted: restore items not allowed in Challenge mode");
|
||||
item.clear();
|
||||
@@ -513,8 +503,6 @@ void ItemCreator::clear_item_if_restricted(ItemData& item) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemCreator::generate_common_item_variances(
|
||||
uint32_t norm_area, ItemData& item) {
|
||||
switch (item.data1[0]) {
|
||||
@@ -543,7 +531,8 @@ void ItemCreator::generate_common_item_variances(
|
||||
break;
|
||||
case 4:
|
||||
item.data2d = this->choose_meseta_amount(
|
||||
this->pt->box_meseta_ranges, norm_area) & 0xFFFF;
|
||||
this->pt->box_meseta_ranges, norm_area) &
|
||||
0xFFFF;
|
||||
break;
|
||||
default:
|
||||
// Note: The original code does the following here:
|
||||
@@ -590,8 +579,6 @@ void ItemCreator::generate_common_armor_slot_count(ItemData& item) {
|
||||
this->pt->armor_slot_count_prob_table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemCreator::generate_common_tool_variances(
|
||||
uint32_t area_norm, ItemData& item) {
|
||||
item.clear();
|
||||
@@ -633,8 +620,6 @@ void ItemCreator::generate_common_tool_type(
|
||||
item.data1[2] = data.second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemCreator::generate_common_mag_variances(ItemData& item) const {
|
||||
if (item.data1[0] == 0x02) {
|
||||
item.data1[1] = 0x00;
|
||||
@@ -642,8 +627,6 @@ void ItemCreator::generate_common_mag_variances(ItemData& item) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemCreator::generate_common_weapon_variances(
|
||||
uint8_t area_norm, ItemData& item) {
|
||||
item.clear();
|
||||
@@ -730,8 +713,6 @@ uint8_t ItemCreator::choose_weapon_special(uint8_t det) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemCreator::generate_unit_weights_tables() {
|
||||
// Note: This part of the function was originally in a different function,
|
||||
// since it had another callsite. Unlike the original code, we generate these
|
||||
@@ -817,8 +798,6 @@ void ItemCreator::generate_common_unit_variances(uint8_t det, ItemData& item) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Returns a weighted random result, indicating the chosen position in the
|
||||
// weighted table.
|
||||
//
|
||||
@@ -860,8 +839,6 @@ IntT ItemCreator::get_rand_from_weighted_tables_2d_vertical(
|
||||
offset, Y, X);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Note: There are clearly better ways of doing this, but this implementation
|
||||
// closely follows what the original code in the client does.
|
||||
template <typename ItemT, size_t MaxCount>
|
||||
@@ -869,7 +846,7 @@ struct ProbabilityTable {
|
||||
ItemT items[MaxCount];
|
||||
size_t count;
|
||||
|
||||
ProbabilityTable() : count(0) { }
|
||||
ProbabilityTable() : count(0) {}
|
||||
|
||||
void push(ItemT item) {
|
||||
if (this->count == MaxCount) {
|
||||
@@ -999,7 +976,7 @@ void ItemCreator::generate_armor_shop_armors(
|
||||
}
|
||||
pt.shuffle(this->random_crypt);
|
||||
|
||||
for (size_t items_generated = 0; items_generated < num_items; ) {
|
||||
for (size_t items_generated = 0; items_generated < num_items;) {
|
||||
ItemData item;
|
||||
item.data1[0] = 1;
|
||||
item.data1[1] = 1;
|
||||
@@ -1044,7 +1021,7 @@ void ItemCreator::generate_armor_shop_shields(
|
||||
}
|
||||
pt.shuffle(this->random_crypt);
|
||||
|
||||
for (size_t items_generated = 0; items_generated < num_items; ) {
|
||||
for (size_t items_generated = 0; items_generated < num_items;) {
|
||||
ItemData item;
|
||||
item.data1[0] = 1;
|
||||
item.data1[1] = 2;
|
||||
@@ -1088,7 +1065,7 @@ void ItemCreator::generate_armor_shop_units(
|
||||
}
|
||||
pt.shuffle(this->random_crypt);
|
||||
|
||||
for (size_t items_generated = 0; items_generated < num_items; ) {
|
||||
for (size_t items_generated = 0; items_generated < num_items;) {
|
||||
ItemData item;
|
||||
item.data1[0] = 1;
|
||||
item.data1[1] = 3;
|
||||
@@ -1100,8 +1077,6 @@ void ItemCreator::generate_armor_shop_units(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<ItemData> ItemCreator::generate_tool_shop_contents(size_t player_level) {
|
||||
vector<ItemData> shop;
|
||||
this->generate_common_tool_shop_recovery_items(shop, player_level);
|
||||
@@ -1288,8 +1263,6 @@ void ItemCreator::choose_tech_disk_level_for_tool_shop(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<ItemData> ItemCreator::generate_weapon_shop_contents(size_t player_level) {
|
||||
size_t num_items;
|
||||
if (player_level < 11) {
|
||||
@@ -1350,8 +1323,16 @@ vector<ItemData> ItemCreator::generate_weapon_shop_contents(size_t player_level)
|
||||
uint8_t which = pt.pop();
|
||||
if (which == 0x39) {
|
||||
static const vector<pair<uint8_t, uint8_t>> defs({
|
||||
{0x28, 0x00}, {0x2A, 0x00}, {0x2B, 0x00}, {0x35, 0x00}, {0x52, 0x00},
|
||||
{0x48, 0x00}, {0x64, 0x00}, {0x59, 0x00}, {0x8A, 0x00}, {0x99, 0x00},
|
||||
{0x28, 0x00},
|
||||
{0x2A, 0x00},
|
||||
{0x2B, 0x00},
|
||||
{0x35, 0x00},
|
||||
{0x52, 0x00},
|
||||
{0x48, 0x00},
|
||||
{0x64, 0x00},
|
||||
{0x59, 0x00},
|
||||
{0x8A, 0x00},
|
||||
{0x99, 0x00},
|
||||
});
|
||||
const auto& def = defs.at(this->section_id);
|
||||
item.data1[0] = 0;
|
||||
@@ -1360,8 +1341,16 @@ vector<ItemData> ItemCreator::generate_weapon_shop_contents(size_t player_level)
|
||||
|
||||
} else if (which == 0x3A) {
|
||||
static const vector<pair<uint8_t, uint8_t>> defs({
|
||||
{0x99, 0x00}, {0x64, 0x00}, {0x8A, 0x00}, {0x28, 0x00}, {0x59, 0x00},
|
||||
{0x2B, 0x00}, {0x52, 0x00}, {0x2A, 0x00}, {0x48, 0x00}, {0x35, 0x00},
|
||||
{0x99, 0x00},
|
||||
{0x64, 0x00},
|
||||
{0x8A, 0x00},
|
||||
{0x28, 0x00},
|
||||
{0x59, 0x00},
|
||||
{0x2B, 0x00},
|
||||
{0x52, 0x00},
|
||||
{0x2A, 0x00},
|
||||
{0x48, 0x00},
|
||||
{0x35, 0x00},
|
||||
});
|
||||
const auto& def = defs.at(this->section_id);
|
||||
item.data1[0] = 0;
|
||||
@@ -1370,21 +1359,78 @@ vector<ItemData> ItemCreator::generate_weapon_shop_contents(size_t player_level)
|
||||
|
||||
} else {
|
||||
static const vector<pair<uint8_t, uint8_t>> defs({
|
||||
{0x01, 0x00}, {0x01, 0x01}, {0x01, 0x02}, {0x01, 0x03}, {0x01, 0x04},
|
||||
{0x03, 0x00}, {0x03, 0x01}, {0x03, 0x02}, {0x03, 0x03}, {0x03, 0x04},
|
||||
{0x02, 0x00}, {0x02, 0x01}, {0x02, 0x02}, {0x02, 0x03}, {0x02, 0x04},
|
||||
{0x05, 0x00}, {0x05, 0x01}, {0x05, 0x02}, {0x05, 0x03}, {0x05, 0x04},
|
||||
{0x04, 0x00}, {0x04, 0x01}, {0x04, 0x02}, {0x04, 0x03}, {0x04, 0x04},
|
||||
{0x06, 0x00}, {0x06, 0x01}, {0x06, 0x02}, {0x06, 0x03}, {0x06, 0x04},
|
||||
{0x07, 0x00}, {0x07, 0x01}, {0x07, 0x02}, {0x07, 0x03}, {0x07, 0x04},
|
||||
{0x08, 0x00}, {0x08, 0x01}, {0x08, 0x02}, {0x08, 0x03}, {0x08, 0x04},
|
||||
{0x09, 0x00}, {0x09, 0x01}, {0x09, 0x02}, {0x09, 0x03}, {0x09, 0x04},
|
||||
{0x0A, 0x00}, {0x0A, 0x01}, {0x0A, 0x02}, {0x0A, 0x03}, {0x0B, 0x00},
|
||||
{0x0B, 0x01}, {0x0B, 0x02}, {0x0B, 0x03}, {0x0C, 0x00}, {0x0C, 0x01},
|
||||
{0x0C, 0x02}, {0x0C, 0x03}, {0xFF, 0xFF}, {0xFF, 0xFF}, {0x01, 0x05},
|
||||
{0x02, 0x05}, {0x06, 0x05}, {0x08, 0x05}, {0x0A, 0x04}, {0x0C, 0x04},
|
||||
{0x0B, 0x04}, {0x01, 0x06}, {0x03, 0x05}, {0x07, 0x05}, {0x0A, 0x05},
|
||||
{0x0C, 0x05}, {0x0B, 0x05},
|
||||
{0x01, 0x00},
|
||||
{0x01, 0x01},
|
||||
{0x01, 0x02},
|
||||
{0x01, 0x03},
|
||||
{0x01, 0x04},
|
||||
{0x03, 0x00},
|
||||
{0x03, 0x01},
|
||||
{0x03, 0x02},
|
||||
{0x03, 0x03},
|
||||
{0x03, 0x04},
|
||||
{0x02, 0x00},
|
||||
{0x02, 0x01},
|
||||
{0x02, 0x02},
|
||||
{0x02, 0x03},
|
||||
{0x02, 0x04},
|
||||
{0x05, 0x00},
|
||||
{0x05, 0x01},
|
||||
{0x05, 0x02},
|
||||
{0x05, 0x03},
|
||||
{0x05, 0x04},
|
||||
{0x04, 0x00},
|
||||
{0x04, 0x01},
|
||||
{0x04, 0x02},
|
||||
{0x04, 0x03},
|
||||
{0x04, 0x04},
|
||||
{0x06, 0x00},
|
||||
{0x06, 0x01},
|
||||
{0x06, 0x02},
|
||||
{0x06, 0x03},
|
||||
{0x06, 0x04},
|
||||
{0x07, 0x00},
|
||||
{0x07, 0x01},
|
||||
{0x07, 0x02},
|
||||
{0x07, 0x03},
|
||||
{0x07, 0x04},
|
||||
{0x08, 0x00},
|
||||
{0x08, 0x01},
|
||||
{0x08, 0x02},
|
||||
{0x08, 0x03},
|
||||
{0x08, 0x04},
|
||||
{0x09, 0x00},
|
||||
{0x09, 0x01},
|
||||
{0x09, 0x02},
|
||||
{0x09, 0x03},
|
||||
{0x09, 0x04},
|
||||
{0x0A, 0x00},
|
||||
{0x0A, 0x01},
|
||||
{0x0A, 0x02},
|
||||
{0x0A, 0x03},
|
||||
{0x0B, 0x00},
|
||||
{0x0B, 0x01},
|
||||
{0x0B, 0x02},
|
||||
{0x0B, 0x03},
|
||||
{0x0C, 0x00},
|
||||
{0x0C, 0x01},
|
||||
{0x0C, 0x02},
|
||||
{0x0C, 0x03},
|
||||
{0xFF, 0xFF},
|
||||
{0xFF, 0xFF},
|
||||
{0x01, 0x05},
|
||||
{0x02, 0x05},
|
||||
{0x06, 0x05},
|
||||
{0x08, 0x05},
|
||||
{0x0A, 0x04},
|
||||
{0x0C, 0x04},
|
||||
{0x0B, 0x04},
|
||||
{0x01, 0x06},
|
||||
{0x03, 0x05},
|
||||
{0x07, 0x05},
|
||||
{0x0A, 0x05},
|
||||
{0x0C, 0x05},
|
||||
{0x0B, 0x05},
|
||||
});
|
||||
const auto& def = defs.at(which);
|
||||
item.data1[0] = 0;
|
||||
@@ -1491,8 +1537,26 @@ void ItemCreator::generate_weapon_shop_item_special(
|
||||
}
|
||||
|
||||
static const array<int8_t, 20> bonus_values = {
|
||||
-50, -45, -40, -35, -30, -25, -20, -15, -10, -5,
|
||||
5, 10, 15, 20, 25, 30, 35, 40, 45, 50,
|
||||
-50,
|
||||
-45,
|
||||
-40,
|
||||
-35,
|
||||
-30,
|
||||
-25,
|
||||
-20,
|
||||
-15,
|
||||
-10,
|
||||
-5,
|
||||
5,
|
||||
10,
|
||||
15,
|
||||
20,
|
||||
25,
|
||||
30,
|
||||
35,
|
||||
40,
|
||||
45,
|
||||
50,
|
||||
};
|
||||
|
||||
void ItemCreator::generate_weapon_shop_item_bonus1(
|
||||
|
||||
+2
-4
@@ -3,12 +3,10 @@
|
||||
#include <memory>
|
||||
|
||||
#include "CommonItemSet.hh"
|
||||
#include "RareItemSet.hh"
|
||||
#include "ItemParameterTable.hh"
|
||||
#include "StaticGameData.hh"
|
||||
#include "PSOEncryption.hh"
|
||||
|
||||
|
||||
#include "RareItemSet.hh"
|
||||
#include "StaticGameData.hh"
|
||||
|
||||
struct ItemDropSub {
|
||||
uint8_t override_area;
|
||||
|
||||
+2
-13
@@ -4,8 +4,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
ItemData::ItemData() {
|
||||
this->clear();
|
||||
}
|
||||
@@ -78,8 +76,6 @@ size_t ItemData::max_stack_size() const {
|
||||
return max_stack_size_for_item(this->data1[0], this->data1[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemData::assign_mag_stats(const ItemMagStats& mag) {
|
||||
// this->data1[0] and [1] unchanged
|
||||
this->data1[2] = mag.level();
|
||||
@@ -102,8 +98,6 @@ void ItemData::clear_mag_stats() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ItemData::set_sealed_item_kill_count(uint16_t v) {
|
||||
this->data1[10] = (v >> 8) | 0x80;
|
||||
this->data1[11] = v;
|
||||
@@ -145,8 +139,6 @@ void ItemData::set_unit_bonus(int16_t bonus) {
|
||||
this->data1w[3] = bonus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ItemData::has_bonuses() const {
|
||||
switch (this->data1[0]) {
|
||||
case 0:
|
||||
@@ -197,8 +189,6 @@ bool ItemData::is_s_rank_weapon() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ItemData::compare_for_sort(const ItemData& a, const ItemData& b) {
|
||||
for (size_t z = 0; z < 12; z++) {
|
||||
if (a.data1[z] < b.data1[z]) {
|
||||
@@ -217,8 +207,6 @@ bool ItemData::compare_for_sort(const ItemData& a, const ItemData& b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const unordered_map<uint8_t, const char*> name_for_weapon_special({
|
||||
{0x00, nullptr},
|
||||
{0x01, "Draw"},
|
||||
@@ -285,7 +273,8 @@ struct ItemNameInfo {
|
||||
bool is_rare;
|
||||
|
||||
ItemNameInfo(const char* name, bool is_rare = true)
|
||||
: name(name), is_rare(is_rare) { }
|
||||
: name(name),
|
||||
is_rare(is_rare) {}
|
||||
};
|
||||
|
||||
const unordered_map<uint32_t, ItemNameInfo> name_info_for_primary_identifier({
|
||||
|
||||
+2
-4
@@ -1,12 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <string>
|
||||
|
||||
#include "Text.hh"
|
||||
|
||||
|
||||
|
||||
constexpr uint32_t MESETA_IDENTIFIER = 0x00040000;
|
||||
|
||||
struct ItemMagStats {
|
||||
@@ -29,7 +27,7 @@ struct ItemMagStats {
|
||||
mind(0),
|
||||
flags(0),
|
||||
photon_blasts(0),
|
||||
color(14) { }
|
||||
color(14) {}
|
||||
|
||||
inline uint16_t def_level() const {
|
||||
return this->def / 100;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
ItemParameterTable::ItemParameterTable(shared_ptr<const string> data)
|
||||
: data(data), r(*data) {
|
||||
size_t offset_table_offset = this->r.pget_u32l(this->data->size() - 0x10);
|
||||
@@ -139,8 +137,6 @@ uint8_t ItemParameterTable::get_max_tech_level(uint8_t char_class, uint8_t tech_
|
||||
return r.pget_u8(this->offsets->max_tech_level_table + tech_num * 12 + char_class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ItemParameterTable::ItemBase& ItemParameterTable::get_item_definition(
|
||||
const ItemData& item) const {
|
||||
switch (item.data1[0]) {
|
||||
@@ -225,8 +221,6 @@ bool ItemParameterTable::is_unsealable_item(const ItemData& item) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t ItemParameterTable::price_for_item(const ItemData& item) const {
|
||||
switch (item.data1[0]) {
|
||||
case 0: {
|
||||
@@ -281,8 +275,7 @@ size_t ItemParameterTable::price_for_item(const ItemData& item) const {
|
||||
const auto& def = this->get_armor_or_shield(item.data1[1], item.data1[2]);
|
||||
double power_factor = def.dfp + def.evp + def_bonus + evp_bonus;
|
||||
double power_factor_floor = static_cast<int32_t>((power_factor * power_factor) / sale_divisor);
|
||||
return power_factor_floor + (
|
||||
70.0 *
|
||||
return power_factor_floor + (70.0 *
|
||||
static_cast<double>(item.data1[5] + 1) *
|
||||
static_cast<double>(def.required_level + 1));
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <string>
|
||||
|
||||
#include "Text.hh"
|
||||
#include "ItemData.hh"
|
||||
|
||||
|
||||
#include "Text.hh"
|
||||
|
||||
class ItemParameterTable {
|
||||
public:
|
||||
|
||||
+1
-3
@@ -6,9 +6,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
/* these items all need some kind of special handling that hasn't been implemented yet.
|
||||
/* These items all need some kind of special handling that hasn't been implemented yet.
|
||||
|
||||
030B04 = TP Material (?)
|
||||
030C00 = Cell Of MAG 502
|
||||
|
||||
@@ -8,6 +8,4 @@
|
||||
#include "Client.hh"
|
||||
#include "StaticGameData.hh"
|
||||
|
||||
|
||||
|
||||
void player_use_item(std::shared_ptr<Client> c, size_t item_index);
|
||||
|
||||
+2
-4
@@ -8,8 +8,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
LevelTable::LevelTable(shared_ptr<const string> data, bool compressed) {
|
||||
if (compressed) {
|
||||
this->data.reset(new string(prs_decompress(*data)));
|
||||
@@ -30,8 +28,8 @@ const PlayerStats& LevelTable::base_stats_for_class(uint8_t char_class) const {
|
||||
return this->table->base_stats[char_class];
|
||||
}
|
||||
|
||||
const LevelTable::LevelStats& LevelTable::stats_for_level(uint8_t char_class,
|
||||
uint8_t level) const {
|
||||
const LevelTable::LevelStats& LevelTable::stats_for_level(
|
||||
uint8_t char_class, uint8_t level) const {
|
||||
if (char_class >= 12) {
|
||||
throw invalid_argument("invalid character class");
|
||||
}
|
||||
|
||||
+1
-3
@@ -3,10 +3,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <phosg/Encoding.hh>
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
struct PlayerStats {
|
||||
le_uint16_t atp;
|
||||
|
||||
+3
-9
@@ -5,14 +5,12 @@
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Time.hh>
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "License.hh"
|
||||
#include "Loggers.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
License::License() : serial_number(0), privileges(0), ban_end_time(0) { }
|
||||
License::License() : serial_number(0), privileges(0), ban_end_time(0) {}
|
||||
|
||||
string License::str() const {
|
||||
string ret = string_printf("License(serial_number=%" PRIu32, this->serial_number);
|
||||
@@ -39,9 +37,7 @@ string License::str() const {
|
||||
return ret + ")";
|
||||
}
|
||||
|
||||
|
||||
|
||||
LicenseManager::LicenseManager() : filename(""), autosave(false) { }
|
||||
LicenseManager::LicenseManager() : filename(""), autosave(false) {}
|
||||
|
||||
LicenseManager::LicenseManager(const string& filename)
|
||||
: filename(filename), autosave(true) {
|
||||
@@ -200,8 +196,6 @@ vector<License> LicenseManager::snapshot() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
shared_ptr<License> LicenseManager::create_license_pc(
|
||||
uint32_t serial_number, const string& access_key, bool temporary) {
|
||||
shared_ptr<License> l(new License());
|
||||
|
||||
+6
-6
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Text.hh"
|
||||
|
||||
@@ -48,17 +48,17 @@ struct License {
|
||||
|
||||
class incorrect_password : public std::invalid_argument {
|
||||
public:
|
||||
incorrect_password() : invalid_argument("incorrect password") { }
|
||||
incorrect_password() : invalid_argument("incorrect password") {}
|
||||
};
|
||||
|
||||
class incorrect_access_key : public std::invalid_argument {
|
||||
public:
|
||||
incorrect_access_key() : invalid_argument("incorrect access key") { }
|
||||
incorrect_access_key() : invalid_argument("incorrect access key") {}
|
||||
};
|
||||
|
||||
class missing_license : public std::invalid_argument {
|
||||
public:
|
||||
missing_license() : invalid_argument("missing license") { }
|
||||
missing_license() : invalid_argument("missing license") {}
|
||||
};
|
||||
|
||||
class LicenseManager {
|
||||
|
||||
+2
-9
@@ -10,8 +10,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
Lobby::Lobby(uint32_t id)
|
||||
: log(string_printf("[Lobby/%" PRIX32 "] ", id), lobby_log.min_level),
|
||||
lobby_id(id),
|
||||
@@ -135,7 +133,8 @@ void Lobby::add_client(shared_ptr<Client> c, ssize_t required_client_id) {
|
||||
lobby_data.player_tag = 0x00010000;
|
||||
lobby_data.guild_card = c->license->serial_number;
|
||||
lobby_data.name = encode_sjis(c->game_data.player()->disp.name);
|
||||
this->battle_record->add_player(lobby_data,
|
||||
this->battle_record->add_player(
|
||||
lobby_data,
|
||||
c->game_data.player()->inventory,
|
||||
c->game_data.player()->disp.to_dcpcv3());
|
||||
}
|
||||
@@ -215,8 +214,6 @@ void Lobby::move_client_to_lobby(
|
||||
dest_lobby->add_client(c, required_client_id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
shared_ptr<Client> Lobby::find_client(const u16string* identifier,
|
||||
uint64_t serial_number) {
|
||||
for (size_t x = 0; x < this->max_clients; x++) {
|
||||
@@ -235,8 +232,6 @@ shared_ptr<Client> Lobby::find_client(const u16string* identifier,
|
||||
throw out_of_range("client not found");
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t Lobby::game_event_for_lobby_event(uint8_t lobby_event) {
|
||||
if (lobby_event > 7) {
|
||||
return 0;
|
||||
@@ -250,8 +245,6 @@ uint8_t Lobby::game_event_for_lobby_event(uint8_t lobby_event) {
|
||||
return lobby_event;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Lobby::add_item(const PlayerInventoryItem& item, uint8_t area, float x, float z) {
|
||||
auto& fi = this->item_id_to_floor_item[item.data.id];
|
||||
fi.inv_item = item;
|
||||
|
||||
+4
-6
@@ -2,13 +2,13 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <random>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Client.hh"
|
||||
#include "Episode3/BattleRecord.hh"
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "StaticGameData.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
|
||||
|
||||
struct Lobby : public std::enable_shared_from_this<Lobby> {
|
||||
enum Flag {
|
||||
GAME = 0x00000001,
|
||||
|
||||
+31
-32
@@ -4,24 +4,22 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
PrefixedLogger ax_messages_log ("[$ax message] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger channel_exceptions_log("[Channel] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger client_log ("" , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger command_data_log ("[Commands] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger config_log ("[Config] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger dns_server_log ("[DNSServer] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger function_compiler_log ("[FunctionCompiler] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger ax_messages_log("[$ax message] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger channel_exceptions_log("[Channel] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger client_log("", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger command_data_log("[Commands] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger config_log("[Config] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger dns_server_log("[DNSServer] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger function_compiler_log("[FunctionCompiler] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger ip_stack_simulator_log("[IPStackSimulator] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger license_log ("[LicenseManager] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger lobby_log ("" , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger patch_index_log ("[PatchFileIndex] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger player_data_log ("" , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger proxy_server_log ("[ProxyServer] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger replay_log ("[ReplaySession] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger server_log ("[Server] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger static_game_data_log ("[StaticGameData] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger license_log("[LicenseManager] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger lobby_log("", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger patch_index_log("[PatchFileIndex] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger player_data_log("", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger proxy_server_log("[ProxyServer] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger replay_log("[ReplaySession] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger server_log("[Server] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger static_game_data_log("[StaticGameData] ", LogLevel::USE_DEFAULT);
|
||||
|
||||
static LogLevel log_level_for_name(const string& name) {
|
||||
static const unordered_map<string, LogLevel> levels({
|
||||
@@ -38,24 +36,25 @@ static void set_log_level_from_json(
|
||||
PrefixedLogger& log, shared_ptr<JSONObject> d, const char* json_key) {
|
||||
try {
|
||||
log.min_level = log_level_for_name(d->at(json_key)->as_string());
|
||||
} catch (const JSONObject::key_error&) { }
|
||||
} catch (const JSONObject::key_error&) {
|
||||
}
|
||||
}
|
||||
|
||||
void set_log_levels_from_json(shared_ptr<JSONObject> 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(client_log , json, "Clients");
|
||||
set_log_level_from_json(command_data_log , json, "CommandData");
|
||||
set_log_level_from_json(config_log , json, "Config");
|
||||
set_log_level_from_json(dns_server_log , json, "DNSServer");
|
||||
set_log_level_from_json(function_compiler_log , json, "FunctionCompiler");
|
||||
set_log_level_from_json(client_log, json, "Clients");
|
||||
set_log_level_from_json(command_data_log, json, "CommandData");
|
||||
set_log_level_from_json(config_log, json, "Config");
|
||||
set_log_level_from_json(dns_server_log, json, "DNSServer");
|
||||
set_log_level_from_json(function_compiler_log, json, "FunctionCompiler");
|
||||
set_log_level_from_json(ip_stack_simulator_log, json, "IPStackSimulator");
|
||||
set_log_level_from_json(license_log , json, "LicenseManager");
|
||||
set_log_level_from_json(lobby_log , json, "Lobbies");
|
||||
set_log_level_from_json(patch_index_log , json, "PatchFileIndex");
|
||||
set_log_level_from_json(player_data_log , json, "PlayerData");
|
||||
set_log_level_from_json(proxy_server_log , json, "ProxyServer");
|
||||
set_log_level_from_json(replay_log , json, "Replay");
|
||||
set_log_level_from_json(server_log , json, "GameServer");
|
||||
set_log_level_from_json(static_game_data_log , json, "StaticGameData");
|
||||
set_log_level_from_json(license_log, json, "LicenseManager");
|
||||
set_log_level_from_json(lobby_log, json, "Lobbies");
|
||||
set_log_level_from_json(patch_index_log, json, "PatchFileIndex");
|
||||
set_log_level_from_json(player_data_log, json, "PlayerData");
|
||||
set_log_level_from_json(proxy_server_log, json, "ProxyServer");
|
||||
set_log_level_from_json(replay_log, json, "Replay");
|
||||
set_log_level_from_json(server_log, json, "GameServer");
|
||||
set_log_level_from_json(static_game_data_log, json, "StaticGameData");
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/JSON.hh>
|
||||
|
||||
|
||||
#include <phosg/Strings.hh>
|
||||
|
||||
extern PrefixedLogger ax_messages_log;
|
||||
extern PrefixedLogger channel_exceptions_log;
|
||||
|
||||
+49
-28
@@ -4,8 +4,8 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Math.hh>
|
||||
#include <phosg/JSON.hh>
|
||||
#include <phosg/Math.hh>
|
||||
#include <phosg/Network.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Tools.hh>
|
||||
@@ -21,9 +21,9 @@
|
||||
#include "IPStackSimulator.hh"
|
||||
#include "Loggers.hh"
|
||||
#include "NetworkAddresses.hh"
|
||||
#include "PSOGCObjectGraph.hh"
|
||||
#include "Product.hh"
|
||||
#include "ProxyServer.hh"
|
||||
#include "PSOGCObjectGraph.hh"
|
||||
#include "ReplaySession.hh"
|
||||
#include "SaveFileFormats.hh"
|
||||
#include "SendCommands.hh"
|
||||
@@ -35,12 +35,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
bool use_terminal_colors = false;
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
vector<T> parse_int_vector(shared_ptr<const JSONObject> o) {
|
||||
vector<T> ret;
|
||||
@@ -50,8 +46,6 @@ vector<T> parse_int_vector(shared_ptr<const JSONObject> o) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void drop_privileges(const string& username) {
|
||||
if ((getuid() != 0) || (getgid() != 0)) {
|
||||
throw runtime_error(string_printf(
|
||||
@@ -79,8 +73,6 @@ void drop_privileges(const string& username) {
|
||||
config_log.info("Switched to user %s (%d:%d)", username.c_str(), pw->pw_uid, pw->pw_gid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void print_usage() {
|
||||
fputs("\
|
||||
Usage:\n\
|
||||
@@ -191,7 +183,8 @@ A few options apply to multiple modes described above:\n\
|
||||
a hex string before encrypting/decoding/etc.\n\
|
||||
--config=FILENAME\n\
|
||||
Use this file instead of system/config.json.\n\
|
||||
", stderr);
|
||||
",
|
||||
stderr);
|
||||
}
|
||||
|
||||
enum class Behavior {
|
||||
@@ -219,6 +212,7 @@ enum class Behavior {
|
||||
REPLAY_LOG,
|
||||
CAT_CLIENT,
|
||||
GENERATE_PRODUCT,
|
||||
INSPECT_PRODUCT,
|
||||
PRODUCT_SPEED_TEST,
|
||||
};
|
||||
|
||||
@@ -242,7 +236,8 @@ static bool behavior_takes_input_filename(Behavior b) {
|
||||
(b == Behavior::EXTRACT_BML) ||
|
||||
(b == Behavior::PARSE_OBJECT_GRAPH) ||
|
||||
(b == Behavior::REPLAY_LOG) ||
|
||||
(b == Behavior::CAT_CLIENT);
|
||||
(b == Behavior::CAT_CLIENT) ||
|
||||
(b == Behavior::INSPECT_PRODUCT);
|
||||
}
|
||||
|
||||
static bool behavior_takes_output_filename(Behavior b) {
|
||||
@@ -344,7 +339,8 @@ int main(int argc, char** argv) {
|
||||
if (!strcmp(argv[x], "help")) {
|
||||
print_usage();
|
||||
return 0;
|
||||
} if (!strcmp(argv[x], "compress-prs")) {
|
||||
}
|
||||
if (!strcmp(argv[x], "compress-prs")) {
|
||||
behavior = Behavior::COMPRESS_PRS;
|
||||
} else if (!strcmp(argv[x], "decompress-prs")) {
|
||||
behavior = Behavior::DECOMPRESS_PRS;
|
||||
@@ -400,6 +396,8 @@ int main(int argc, char** argv) {
|
||||
behavior = Behavior::EXTRACT_BML;
|
||||
} else if (!strcmp(argv[x], "generate-product")) {
|
||||
behavior = Behavior::GENERATE_PRODUCT;
|
||||
} else if (!strcmp(argv[x], "inspect-product")) {
|
||||
behavior = Behavior::INSPECT_PRODUCT;
|
||||
} else if (!strcmp(argv[x], "product-speed-test")) {
|
||||
behavior = Behavior::PRODUCT_SPEED_TEST;
|
||||
} else {
|
||||
@@ -756,7 +754,8 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, 0, 0x100000000, num_threads);
|
||||
},
|
||||
0, 0x100000000, num_threads);
|
||||
|
||||
if (seed < 0x100000000) {
|
||||
log_info("Found seed %08" PRIX64, seed);
|
||||
@@ -774,15 +773,15 @@ int main(int argc, char** argv) {
|
||||
string output_filename_base = input_filename;
|
||||
if (quest_file_type == QuestFileFormat::GCI) {
|
||||
int64_t dec_seed = seed.empty() ? -1 : stoul(seed, nullptr, 16);
|
||||
save_file(output_filename_base + ".dec", Quest::decode_gci(
|
||||
input_filename, num_threads, dec_seed));
|
||||
auto decoded = Quest::decode_gci(input_filename, num_threads, dec_seed);
|
||||
save_file(output_filename_base + ".dec", decoded);
|
||||
} else if (quest_file_type == QuestFileFormat::VMS) {
|
||||
int64_t dec_seed = seed.empty() ? -1 : stoul(seed, nullptr, 16);
|
||||
save_file(output_filename_base + ".dec", Quest::decode_vms(
|
||||
input_filename, num_threads, dec_seed));
|
||||
auto decoded = Quest::decode_vms(input_filename, num_threads, dec_seed);
|
||||
save_file(output_filename_base + ".dec", decoded);
|
||||
} else if (quest_file_type == QuestFileFormat::DLQ) {
|
||||
save_file(output_filename_base + ".dec", Quest::decode_dlq(
|
||||
input_filename));
|
||||
auto decoded = Quest::decode_dlq(input_filename);
|
||||
save_file(output_filename_base + ".dec", decoded);
|
||||
} else if (quest_file_type == QuestFileFormat::QST) {
|
||||
auto data = Quest::decode_qst(input_filename);
|
||||
save_file(output_filename_base + ".bin", data.first);
|
||||
@@ -874,7 +873,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
uint32_t expanded_probability = RareItemSet::expand_rate(r.probability);
|
||||
auto frac = reduce_fraction<uint64_t>(expanded_probability, 0x100000000);
|
||||
return string_printf("(%02hhX => %08" PRIX32 " => %" PRIu64 "/%" PRIu64 ") %02hhX%02hhX%02hhX (%s)",
|
||||
return string_printf(
|
||||
"(%02hhX => %08" PRIX32 " => %" PRIu64 "/%" PRIu64 ") %02hhX%02hhX%02hhX (%s)",
|
||||
r.probability, expanded_probability, frac.first, frac.second, r.item_code[0], r.item_code[1], r.item_code[2], name.c_str());
|
||||
};
|
||||
|
||||
@@ -913,7 +913,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
uint32_t expanded_probability = RareItemSet::expand_rate(r.probability);
|
||||
auto frac = reduce_fraction<uint64_t>(expanded_probability, 0x100000000);
|
||||
return string_printf("(%02hhX => %08" PRIX32 " => %" PRIu64 "/%" PRIu64 ") %02hhX%02hhX%02hhX (%s)",
|
||||
return string_printf(
|
||||
"(%02hhX => %08" PRIX32 " => %" PRIu64 "/%" PRIu64 ") %02hhX%02hhX%02hhX (%s)",
|
||||
r.probability, expanded_probability, frac.first, frac.second, r.item_code[0], r.item_code[1], r.item_code[2], name.c_str());
|
||||
};
|
||||
|
||||
@@ -1006,7 +1007,26 @@ int main(int argc, char** argv) {
|
||||
|
||||
case Behavior::GENERATE_PRODUCT: {
|
||||
auto product = generate_product(domain, subdomain);
|
||||
fprintf(stderr, "%s\n", product.c_str());
|
||||
fprintf(stdout, "%s\n", product.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
case Behavior::INSPECT_PRODUCT: {
|
||||
if (!input_filename) {
|
||||
throw invalid_argument("no product given");
|
||||
}
|
||||
size_t num_valid_subdomains = 0;
|
||||
for (uint8_t domain = 0; domain < 3; domain++) {
|
||||
for (uint8_t subdomain = 0; subdomain < 3; subdomain++) {
|
||||
if (product_is_valid_fast(input_filename, domain, subdomain)) {
|
||||
fprintf(stdout, "%s is valid in domain %hhu subdomain %hhu\n", input_filename, domain, subdomain);
|
||||
num_valid_subdomains++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_valid_subdomains == 0) {
|
||||
fprintf(stdout, "%s is not valid in any domain\n", input_filename);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1049,7 +1069,8 @@ int main(int argc, char** argv) {
|
||||
config_log.info("Starting game server");
|
||||
state->game_server.reset(new Server(base, state));
|
||||
|
||||
shared_ptr<FILE> log_f(stdin, +[](FILE*) { });
|
||||
shared_ptr<FILE> log_f(
|
||||
stdin, +[](FILE*) {});
|
||||
if (input_filename && strcmp(input_filename, "-")) {
|
||||
log_f = fopen_shared(input_filename, "rt");
|
||||
}
|
||||
@@ -1074,14 +1095,14 @@ int main(int argc, char** argv) {
|
||||
// destination is supported, and we have to manually specify the
|
||||
// destination netloc here.
|
||||
if (pc->version == GameVersion::PATCH) {
|
||||
struct sockaddr_storage ss = make_sockaddr_storage(
|
||||
auto [ss, size] = make_sockaddr_storage(
|
||||
state->proxy_destination_patch.first,
|
||||
state->proxy_destination_patch.second).first;
|
||||
state->proxy_destination_patch.second);
|
||||
state->proxy_server->listen(pc->port, pc->version, &ss);
|
||||
} else if (pc->version == GameVersion::BB) {
|
||||
struct sockaddr_storage ss = make_sockaddr_storage(
|
||||
auto [ss, size] = make_sockaddr_storage(
|
||||
state->proxy_destination_bb.first,
|
||||
state->proxy_destination_bb.second).first;
|
||||
state->proxy_destination_bb.second);
|
||||
state->proxy_server->listen(pc->port, pc->version, &ss);
|
||||
} else {
|
||||
state->proxy_server->listen(pc->port, pc->version);
|
||||
|
||||
+25
-34
@@ -8,8 +8,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
string BattleParamsIndex::Entry::str() const {
|
||||
string a1str = format_data_string(this->unknown_a1.data(), this->unknown_a1.bytes());
|
||||
return string_printf(
|
||||
@@ -56,8 +54,6 @@ void BattleParamsIndex::Table::print(FILE* stream) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BattleParamsIndex::BattleParamsIndex(
|
||||
shared_ptr<const string> data_on_ep1,
|
||||
shared_ptr<const string> data_on_ep2,
|
||||
@@ -112,9 +108,7 @@ const BattleParamsIndex::Entry& BattleParamsIndex::get(
|
||||
return this->files[!!solo][ep_index].table->difficulty[difficulty][monster_type];
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOEnemy::PSOEnemy(uint64_t id) : PSOEnemy(id, 0, 0, 0, 0, "__missing__") { }
|
||||
PSOEnemy::PSOEnemy(uint64_t id) : PSOEnemy(id, 0, 0, 0, 0, "__missing__") {}
|
||||
|
||||
PSOEnemy::PSOEnemy(
|
||||
uint64_t id,
|
||||
@@ -130,15 +124,13 @@ PSOEnemy::PSOEnemy(
|
||||
experience(experience),
|
||||
rt_index(rt_index),
|
||||
num_clones(num_clones),
|
||||
type_name(type_name) { }
|
||||
type_name(type_name) {}
|
||||
|
||||
string PSOEnemy::str() const {
|
||||
return string_printf("[Enemy E-%" PRIX64 " \"%s\" source_type=%hX hit=%02hhX/%hu exp=%" PRIu32 " rt_index=%" PRIX32 " clones=%zu]",
|
||||
this->id, this->type_name, this->source_type, this->hit_flags, this->last_hit, this->experience, this->rt_index, this->num_clones);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct EnemyEntry {
|
||||
uint32_t base;
|
||||
uint16_t reserved0;
|
||||
@@ -174,11 +166,7 @@ vector<PSOEnemy> parse_map(
|
||||
}
|
||||
};
|
||||
|
||||
auto create_enemy = [&](
|
||||
const EnemyEntry& e,
|
||||
ssize_t bp_index,
|
||||
uint32_t rt_index,
|
||||
const char* type_name) {
|
||||
auto create_enemy = [&](const EnemyEntry& e, ssize_t bp_index, uint32_t rt_index, const char* type_name) {
|
||||
const BattleParamsIndex::Entry& bp_entry = battle_params->get(
|
||||
is_solo, episode, difficulty, bp_index);
|
||||
enemies.emplace_back(
|
||||
@@ -423,7 +411,7 @@ vector<PSOEnemy> parse_map(
|
||||
create_enemy(e, 0x1F, 6, "Girtablulu");
|
||||
break;
|
||||
case 0x0114: // Zu and Pazuzu
|
||||
create_enemy(e, 0x0B + (e.skin & 0x01) + (alt_enemies ? 0x14: 0x00),
|
||||
create_enemy(e, 0x0B + (e.skin & 0x01) + (alt_enemies ? 0x14 : 0x00),
|
||||
7 + (e.skin & 0x01), "(Pazu)?zu");
|
||||
break;
|
||||
case 0x0115: // Boota family
|
||||
@@ -457,8 +445,6 @@ vector<PSOEnemy> parse_map(
|
||||
return enemies;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SetDataTable::SetDataTable(shared_ptr<const string> data, bool big_endian) {
|
||||
if (big_endian) {
|
||||
this->load_table_t<true>(data);
|
||||
@@ -523,8 +509,6 @@ void SetDataTable::print(FILE* stream) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct AreaMapFileIndex {
|
||||
const char* name_token;
|
||||
vector<uint32_t> variation1_values;
|
||||
@@ -536,13 +520,15 @@ struct AreaMapFileIndex {
|
||||
vector<uint32_t> variation2_values)
|
||||
: name_token(name_token),
|
||||
variation1_values(variation1_values),
|
||||
variation2_values(variation2_values) { }
|
||||
variation2_values(variation2_values) {}
|
||||
};
|
||||
|
||||
// These are indexed as [episode][is_solo][area], where episode is 0-2
|
||||
static const vector<vector<vector<AreaMapFileIndex>>> map_file_info = {
|
||||
{ // Episode 1
|
||||
{ // Non-solo
|
||||
{
|
||||
// Episode 1
|
||||
{
|
||||
// Non-solo
|
||||
{"city00", {}, {0}},
|
||||
{"forest01", {}, {0, 1, 2, 3, 4}},
|
||||
{"forest02", {}, {0, 1, 2, 3, 4}},
|
||||
@@ -560,7 +546,8 @@ static const vector<vector<vector<AreaMapFileIndex>>> map_file_info = {
|
||||
{"boss04", {}, {}},
|
||||
{nullptr, {}, {}},
|
||||
},
|
||||
{ // Solo
|
||||
{
|
||||
// Solo
|
||||
{"city00", {}, {0}},
|
||||
{"forest01", {}, {0, 2, 4}},
|
||||
{"forest02", {}, {0, 3, 4}},
|
||||
@@ -579,8 +566,10 @@ static const vector<vector<vector<AreaMapFileIndex>>> map_file_info = {
|
||||
{nullptr, {}, {}},
|
||||
},
|
||||
},
|
||||
{ // Episode 2
|
||||
{ // Non-solo
|
||||
{
|
||||
// Episode 2
|
||||
{
|
||||
// Non-solo
|
||||
{"labo00", {}, {0}},
|
||||
{"ruins01", {0, 1}, {0}},
|
||||
{"ruins02", {0, 1}, {0}},
|
||||
@@ -598,7 +587,8 @@ static const vector<vector<vector<AreaMapFileIndex>>> map_file_info = {
|
||||
{"boss07", {}, {}},
|
||||
{"boss08", {}, {}},
|
||||
},
|
||||
{ // Solo
|
||||
{
|
||||
// Solo
|
||||
{"labo00", {}, {0}},
|
||||
{"ruins01", {0, 1}, {0}},
|
||||
{"ruins02", {0, 1}, {0}},
|
||||
@@ -617,8 +607,10 @@ static const vector<vector<vector<AreaMapFileIndex>>> map_file_info = {
|
||||
{"boss08", {}, {}},
|
||||
},
|
||||
},
|
||||
{ // Episode 4
|
||||
{ // Non-solo
|
||||
{
|
||||
// Episode 4
|
||||
{
|
||||
// Non-solo
|
||||
{"city02", {0}, {0}},
|
||||
{"wilds01", {0}, {0, 1, 2}},
|
||||
{"wilds01", {1}, {0, 1, 2}},
|
||||
@@ -636,7 +628,8 @@ static const vector<vector<vector<AreaMapFileIndex>>> map_file_info = {
|
||||
{nullptr, {}, {}},
|
||||
{nullptr, {}, {}},
|
||||
},
|
||||
{ // Solo
|
||||
{
|
||||
// Solo
|
||||
{"city02", {0}, {0}},
|
||||
{"wilds01", {0}, {0, 1, 2}},
|
||||
{"wilds01", {1}, {0, 1, 2}},
|
||||
@@ -688,10 +681,8 @@ void generate_variations(
|
||||
variations[z * 2 + 0] = 0;
|
||||
variations[z * 2 + 1] = 0;
|
||||
} else {
|
||||
variations[z * 2 + 0] = (a->variation1_values.size() < 2) ? 0 :
|
||||
((*random)() % a->variation1_values.size());
|
||||
variations[z * 2 + 1] = (a->variation2_values.size() < 2) ? 0 :
|
||||
((*random)() % a->variation2_values.size());
|
||||
variations[z * 2 + 0] = (a->variation1_values.size() < 2) ? 0 : ((*random)() % a->variation1_values.size());
|
||||
variations[z * 2 + 1] = (a->variation2_values.size() < 2) ? 0 : ((*random)() % a->variation2_values.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#include "StaticGameData.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
|
||||
|
||||
class BattleParamsIndex {
|
||||
public:
|
||||
struct Entry {
|
||||
@@ -58,8 +56,6 @@ private:
|
||||
LoadedFile files[2][3];
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PSOEnemy {
|
||||
uint64_t id;
|
||||
uint16_t source_type;
|
||||
@@ -90,8 +86,6 @@ std::vector<PSOEnemy> parse_map(
|
||||
std::shared_ptr<const std::string> data,
|
||||
bool alt_enemies);
|
||||
|
||||
|
||||
|
||||
// TODO: This class is currently unused. It would be nice if we could use this
|
||||
// to generate variations and link to the corresponding map filenames, but it
|
||||
// seems that SetDataTable.rel files link to map filenames that don't actually
|
||||
@@ -121,8 +115,6 @@ private:
|
||||
std::vector<std::vector<std::vector<SetEntry>>> entries;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void generate_variations(
|
||||
parray<le_uint32_t, 0x20>& variations,
|
||||
std::shared_ptr<std::mt19937> random,
|
||||
|
||||
+7
-5
@@ -2,8 +2,10 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
MenuItem::MenuItem(uint32_t item_id, const u16string& name,
|
||||
const u16string& description, uint32_t flags) : item_id(item_id), name(name),
|
||||
description(description), flags(flags) { }
|
||||
MenuItem::MenuItem(
|
||||
uint32_t item_id, const u16string& name,
|
||||
const u16string& description, uint32_t flags)
|
||||
: item_id(item_id),
|
||||
name(name),
|
||||
description(description),
|
||||
flags(flags) {}
|
||||
|
||||
+45
-49
@@ -4,8 +4,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
// Note: These aren't enums because neither enum nor enum class does what we
|
||||
// want. Specifically, we need GO_BACK to be valid in multiple enums (and enums
|
||||
// aren't namespaced unless they're enum classes), so we can't use enums. But we
|
||||
@@ -13,68 +11,66 @@
|
||||
// casting values all over the place, so we can't use enum classes either.
|
||||
|
||||
namespace MenuID {
|
||||
constexpr uint32_t MAIN = 0x11000011;
|
||||
constexpr uint32_t INFORMATION = 0x22000022;
|
||||
constexpr uint32_t LOBBY = 0x33000033;
|
||||
constexpr uint32_t GAME = 0x44000044;
|
||||
constexpr uint32_t QUEST = 0x55000055;
|
||||
constexpr uint32_t QUEST_FILTER = 0x66000066;
|
||||
constexpr uint32_t PROXY_DESTINATIONS = 0x77000077;
|
||||
constexpr uint32_t PROGRAMS = 0x88000088;
|
||||
constexpr uint32_t PATCHES = 0x99000099;
|
||||
constexpr uint32_t PROXY_OPTIONS = 0xAA0000AA;
|
||||
constexpr uint32_t TOURNAMENTS = 0xBB0000BB;
|
||||
constexpr uint32_t TOURNAMENTS_FOR_SPEC = 0xBB1111BB;
|
||||
constexpr uint32_t TOURNAMENT_ENTRIES = 0xCC0000CC;
|
||||
}
|
||||
constexpr uint32_t MAIN = 0x11000011;
|
||||
constexpr uint32_t INFORMATION = 0x22000022;
|
||||
constexpr uint32_t LOBBY = 0x33000033;
|
||||
constexpr uint32_t GAME = 0x44000044;
|
||||
constexpr uint32_t QUEST = 0x55000055;
|
||||
constexpr uint32_t QUEST_FILTER = 0x66000066;
|
||||
constexpr uint32_t PROXY_DESTINATIONS = 0x77000077;
|
||||
constexpr uint32_t PROGRAMS = 0x88000088;
|
||||
constexpr uint32_t PATCHES = 0x99000099;
|
||||
constexpr uint32_t PROXY_OPTIONS = 0xAA0000AA;
|
||||
constexpr uint32_t TOURNAMENTS = 0xBB0000BB;
|
||||
constexpr uint32_t TOURNAMENTS_FOR_SPEC = 0xBB1111BB;
|
||||
constexpr uint32_t TOURNAMENT_ENTRIES = 0xCC0000CC;
|
||||
} // namespace MenuID
|
||||
|
||||
namespace MainMenuItemID {
|
||||
constexpr uint32_t GO_TO_LOBBY = 0x11222211;
|
||||
constexpr uint32_t INFORMATION = 0x11333311;
|
||||
constexpr uint32_t DOWNLOAD_QUESTS = 0x11444411;
|
||||
constexpr uint32_t PROXY_DESTINATIONS = 0x11555511;
|
||||
constexpr uint32_t PATCHES = 0x11666611;
|
||||
constexpr uint32_t PROGRAMS = 0x11777711;
|
||||
constexpr uint32_t DISCONNECT = 0x11888811;
|
||||
constexpr uint32_t CLEAR_LICENSE = 0x11999911;
|
||||
}
|
||||
constexpr uint32_t GO_TO_LOBBY = 0x11222211;
|
||||
constexpr uint32_t INFORMATION = 0x11333311;
|
||||
constexpr uint32_t DOWNLOAD_QUESTS = 0x11444411;
|
||||
constexpr uint32_t PROXY_DESTINATIONS = 0x11555511;
|
||||
constexpr uint32_t PATCHES = 0x11666611;
|
||||
constexpr uint32_t PROGRAMS = 0x11777711;
|
||||
constexpr uint32_t DISCONNECT = 0x11888811;
|
||||
constexpr uint32_t CLEAR_LICENSE = 0x11999911;
|
||||
} // namespace MainMenuItemID
|
||||
|
||||
namespace InformationMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x22FFFF22;
|
||||
constexpr uint32_t GO_BACK = 0x22FFFF22;
|
||||
}
|
||||
|
||||
namespace ProxyDestinationsMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x77FFFF77;
|
||||
constexpr uint32_t OPTIONS = 0x77EEEE77;
|
||||
}
|
||||
constexpr uint32_t GO_BACK = 0x77FFFF77;
|
||||
constexpr uint32_t OPTIONS = 0x77EEEE77;
|
||||
} // namespace ProxyDestinationsMenuItemID
|
||||
|
||||
namespace ProgramsMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x88FFFF88;
|
||||
constexpr uint32_t GO_BACK = 0x88FFFF88;
|
||||
}
|
||||
|
||||
namespace PatchesMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0x99FFFF99;
|
||||
constexpr uint32_t GO_BACK = 0x99FFFF99;
|
||||
}
|
||||
|
||||
namespace ProxyOptionsMenuItemID {
|
||||
constexpr uint32_t GO_BACK = 0xAAFFFFAA;
|
||||
constexpr uint32_t CHAT_COMMANDS = 0xAA0000AA;
|
||||
constexpr uint32_t CHAT_FILTER = 0xAA1111AA;
|
||||
constexpr uint32_t PLAYER_NOTIFICATIONS = 0xAA2222AA;
|
||||
constexpr uint32_t INFINITE_HP = 0xAA3333AA;
|
||||
constexpr uint32_t INFINITE_TP = 0xAA4444AA;
|
||||
constexpr uint32_t SWITCH_ASSIST = 0xAA5555AA;
|
||||
constexpr uint32_t BLOCK_EVENTS = 0xAA6666AA;
|
||||
constexpr uint32_t BLOCK_PATCHES = 0xAA7777AA;
|
||||
constexpr uint32_t SAVE_FILES = 0xAA8888AA;
|
||||
constexpr uint32_t RED_NAME = 0xAA9999AA;
|
||||
constexpr uint32_t BLANK_NAME = 0xAAAAAAAA;
|
||||
constexpr uint32_t SUPPRESS_LOGIN = 0xAABBBBAA;
|
||||
constexpr uint32_t SKIP_CARD = 0xAACCCCAA;
|
||||
constexpr uint32_t EP3_INFINITE_MESETA = 0xAADDDDAA;
|
||||
}
|
||||
|
||||
|
||||
constexpr uint32_t GO_BACK = 0xAAFFFFAA;
|
||||
constexpr uint32_t CHAT_COMMANDS = 0xAA0000AA;
|
||||
constexpr uint32_t CHAT_FILTER = 0xAA1111AA;
|
||||
constexpr uint32_t PLAYER_NOTIFICATIONS = 0xAA2222AA;
|
||||
constexpr uint32_t INFINITE_HP = 0xAA3333AA;
|
||||
constexpr uint32_t INFINITE_TP = 0xAA4444AA;
|
||||
constexpr uint32_t SWITCH_ASSIST = 0xAA5555AA;
|
||||
constexpr uint32_t BLOCK_EVENTS = 0xAA6666AA;
|
||||
constexpr uint32_t BLOCK_PATCHES = 0xAA7777AA;
|
||||
constexpr uint32_t SAVE_FILES = 0xAA8888AA;
|
||||
constexpr uint32_t RED_NAME = 0xAA9999AA;
|
||||
constexpr uint32_t BLANK_NAME = 0xAAAAAAAA;
|
||||
constexpr uint32_t SUPPRESS_LOGIN = 0xAABBBBAA;
|
||||
constexpr uint32_t SKIP_CARD = 0xAACCCCAA;
|
||||
constexpr uint32_t EP3_INFINITE_MESETA = 0xAADDDDAA;
|
||||
} // namespace ProxyOptionsMenuItemID
|
||||
|
||||
struct MenuItem {
|
||||
enum Flag {
|
||||
|
||||
+11
-15
@@ -1,14 +1,12 @@
|
||||
#include "NetworkAddresses.hh"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <phosg/Encoding.hh>
|
||||
@@ -17,19 +15,17 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
uint32_t resolve_address(const char* address) {
|
||||
struct addrinfo *res0;
|
||||
struct addrinfo* res0;
|
||||
if (getaddrinfo(address, nullptr, nullptr, &res0)) {
|
||||
auto e = string_for_error(errno);
|
||||
throw runtime_error(string_printf("can\'t resolve hostname %s: %s", address,
|
||||
e.c_str()));
|
||||
throw runtime_error(string_printf(
|
||||
"can\'t resolve hostname %s: %s", address, e.c_str()));
|
||||
}
|
||||
|
||||
std::unique_ptr<struct addrinfo, void(*)(struct addrinfo*)> res0_unique(
|
||||
std::unique_ptr<struct addrinfo, void (*)(struct addrinfo*)> res0_unique(
|
||||
res0, freeaddrinfo);
|
||||
struct addrinfo *res4 = nullptr;
|
||||
struct addrinfo* res4 = nullptr;
|
||||
for (struct addrinfo* res = res0; res; res = res->ai_next) {
|
||||
if (res->ai_family == AF_INET) {
|
||||
res4 = res;
|
||||
@@ -51,7 +47,7 @@ map<string, uint32_t> get_local_addresses() {
|
||||
throw runtime_error(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);
|
||||
|
||||
map<string, uint32_t> ret;
|
||||
for (struct ifaddrs* i = ifa.get(); i; i = i->ifa_next) {
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
// PSO is IPv4-only, so we just treat addresses as uint32_t everywhere because
|
||||
// it's easier
|
||||
|
||||
|
||||
+10
-33
@@ -3,29 +3,23 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
// TODO: fix style in this file, especially in psobb functions
|
||||
|
||||
|
||||
|
||||
// Most ciphers used by PSO are symmetric; alias decrypt to encrypt by default
|
||||
void PSOEncryption::decrypt(void* data, size_t size, bool advance) {
|
||||
this->encrypt(data, size, advance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOLFGEncryption::PSOLFGEncryption(
|
||||
uint32_t seed, size_t stream_length, size_t end_offset)
|
||||
: stream(stream_length, 0), offset(0), end_offset(end_offset), seed(seed) { }
|
||||
: stream(stream_length, 0), offset(0), end_offset(end_offset), seed(seed) {}
|
||||
|
||||
uint32_t PSOLFGEncryption::next(bool advance) {
|
||||
if (this->offset == this->end_offset) {
|
||||
@@ -109,8 +103,6 @@ void PSOLFGEncryption::encrypt_both_endian(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOV2Encryption::PSOV2Encryption(uint32_t seed)
|
||||
: PSOLFGEncryption(seed, this->STREAM_LENGTH + 1, this->STREAM_LENGTH) {
|
||||
uint32_t esi, ebx, edi, eax, edx, var1;
|
||||
@@ -163,8 +155,6 @@ PSOEncryption::Type PSOV2Encryption::type() const {
|
||||
return Type::V2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOV3Encryption::PSOV3Encryption(uint32_t seed)
|
||||
: PSOLFGEncryption(seed, this->STREAM_LENGTH, this->STREAM_LENGTH) {
|
||||
uint32_t x, y, basekey, source1, source2, source3;
|
||||
@@ -219,8 +209,6 @@ PSOEncryption::Type PSOV3Encryption::type() const {
|
||||
return Type::V3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOBBEncryption::PSOBBEncryption(
|
||||
const KeyFile& key, const void* original_seed, size_t seed_size)
|
||||
: state(key) {
|
||||
@@ -432,7 +420,8 @@ void PSOBBEncryption::tfs1_scramble(uint32_t* out1, uint32_t* out2) const {
|
||||
b ^= (((this->state.private_keys.as32[a >> 24] +
|
||||
this->state.private_keys.as32[((a >> 16) & 0xFF) + 0x100]) ^
|
||||
this->state.private_keys.as32[((a >> 8) & 0xFF) + 0x200]) +
|
||||
this->state.private_keys.as32[(a & 0xFF) + 0x300]) ^ this->state.initial_keys.as32[x + 1];
|
||||
this->state.private_keys.as32[(a & 0xFF) + 0x300]) ^
|
||||
this->state.initial_keys.as32[x + 1];
|
||||
a ^= ((this->state.private_keys.as32[b >> 24] +
|
||||
this->state.private_keys.as32[((b >> 16) & 0xFF) + 0x100]) ^
|
||||
this->state.private_keys.as32[((b >> 8) & 0xFF) + 0x200]) +
|
||||
@@ -608,7 +597,7 @@ void PSOBBEncryption::apply_seed(const void* original_seed, size_t seed_size) {
|
||||
esi = this->state.initial_keys.as32[17];
|
||||
esi = esi ^ eax;
|
||||
this->state.initial_keys.as32[(edi / 4)] = esi;
|
||||
this->state.initial_keys.as32[(edi / 4)+1] = ecx;
|
||||
this->state.initial_keys.as32[(edi / 4) + 1] = ecx;
|
||||
edi = edi + 8;
|
||||
}
|
||||
|
||||
@@ -695,13 +684,11 @@ void PSOBBEncryption::apply_seed(const void* original_seed, size_t seed_size) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOV2OrV3DetectorEncryption::PSOV2OrV3DetectorEncryption(
|
||||
uint32_t key,
|
||||
const std::unordered_set<uint32_t>& v2_matches,
|
||||
const std::unordered_set<uint32_t>& v3_matches)
|
||||
: key(key), v2_matches(v2_matches), v3_matches(v3_matches) { }
|
||||
: key(key), v2_matches(v2_matches), v3_matches(v3_matches) {}
|
||||
|
||||
void PSOV2OrV3DetectorEncryption::encrypt(void* data, size_t size, bool advance) {
|
||||
if (!this->active_crypt) {
|
||||
@@ -745,11 +732,9 @@ PSOEncryption::Type PSOV2OrV3DetectorEncryption::type() const {
|
||||
return this->active_crypt->type();
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOV2OrV3ImitatorEncryption::PSOV2OrV3ImitatorEncryption(
|
||||
uint32_t key, std::shared_ptr<PSOV2OrV3DetectorEncryption> detector_crypt)
|
||||
: key(key), detector_crypt(detector_crypt) { }
|
||||
: key(key), detector_crypt(detector_crypt) {}
|
||||
|
||||
void PSOV2OrV3ImitatorEncryption::encrypt(void* data, size_t size, bool advance) {
|
||||
if (!this->active_crypt) {
|
||||
@@ -772,8 +757,6 @@ PSOEncryption::Type PSOV2OrV3ImitatorEncryption::type() const {
|
||||
return this->active_crypt->type();
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOBBMultiKeyDetectorEncryption::PSOBBMultiKeyDetectorEncryption(
|
||||
const vector<shared_ptr<const PSOBBEncryption::KeyFile>>& possible_keys,
|
||||
const unordered_set<string>& expected_first_data,
|
||||
@@ -781,7 +764,7 @@ PSOBBMultiKeyDetectorEncryption::PSOBBMultiKeyDetectorEncryption(
|
||||
size_t seed_size)
|
||||
: possible_keys(possible_keys),
|
||||
expected_first_data(expected_first_data),
|
||||
seed(reinterpret_cast<const char*>(seed), seed_size) { }
|
||||
seed(reinterpret_cast<const char*>(seed), seed_size) {}
|
||||
|
||||
void PSOBBMultiKeyDetectorEncryption::encrypt(void* data, size_t size, bool advance) {
|
||||
if (!this->active_crypt.get()) {
|
||||
@@ -819,8 +802,6 @@ PSOEncryption::Type PSOBBMultiKeyDetectorEncryption::type() const {
|
||||
return Type::BB;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSOBBMultiKeyImitatorEncryption::PSOBBMultiKeyImitatorEncryption(
|
||||
shared_ptr<const PSOBBMultiKeyDetectorEncryption> detector_crypt,
|
||||
const void* seed,
|
||||
@@ -828,7 +809,7 @@ PSOBBMultiKeyImitatorEncryption::PSOBBMultiKeyImitatorEncryption(
|
||||
bool jsd1_use_detector_seed)
|
||||
: detector_crypt(detector_crypt),
|
||||
seed(reinterpret_cast<const char*>(seed), seed_size),
|
||||
jsd1_use_detector_seed(jsd1_use_detector_seed) { }
|
||||
jsd1_use_detector_seed(jsd1_use_detector_seed) {}
|
||||
|
||||
void PSOBBMultiKeyImitatorEncryption::encrypt(void* data, size_t size, bool advance) {
|
||||
this->ensure_crypt()->encrypt(data, size, advance);
|
||||
@@ -863,8 +844,6 @@ shared_ptr<PSOBBEncryption> PSOBBMultiKeyImitatorEncryption::ensure_crypt() {
|
||||
return this->active_crypt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
JSD0Encryption::JSD0Encryption(const void* seed, size_t seed_size) : key(0) {
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(seed);
|
||||
for (size_t z = 0; z < seed_size; z++) {
|
||||
@@ -892,8 +871,6 @@ PSOEncryption::Type JSD0Encryption::type() const {
|
||||
return Type::JSD0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void decrypt_trivial_gci_data(void* data, size_t size, uint8_t basis) {
|
||||
uint8_t* bytes = reinterpret_cast<uint8_t*>(data);
|
||||
uint8_t key = basis + 0x80;
|
||||
|
||||
+5
-20
@@ -4,14 +4,12 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <memory>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <phosg/Encoding.hh>
|
||||
|
||||
#include "Text.hh" // for parray
|
||||
|
||||
|
||||
|
||||
class PSOEncryption {
|
||||
public:
|
||||
enum class Type {
|
||||
@@ -39,8 +37,6 @@ protected:
|
||||
PSOEncryption() = default;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PSOLFGEncryption : public PSOEncryption {
|
||||
public:
|
||||
virtual void encrypt(void* data, size_t size, bool advance = true);
|
||||
@@ -91,8 +87,6 @@ protected:
|
||||
static constexpr size_t STREAM_LENGTH = 521;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PSOBBEncryption : public PSOEncryption {
|
||||
public:
|
||||
enum Subtype : uint8_t {
|
||||
@@ -109,14 +103,14 @@ public:
|
||||
uint8_t jsd1_stream_offset;
|
||||
parray<uint8_t, 0x48> as8;
|
||||
parray<le_uint32_t, 0x12> as32;
|
||||
InitialKeys() : as32() { }
|
||||
InitialKeys(const InitialKeys& other) : as32(other.as32) { }
|
||||
InitialKeys() : as32() {}
|
||||
InitialKeys(const InitialKeys& other) : as32(other.as32) {}
|
||||
} __attribute__((packed));
|
||||
union PrivateKeys {
|
||||
parray<uint8_t, 0x1000> as8;
|
||||
parray<le_uint32_t, 0x400> as32;
|
||||
PrivateKeys() : as32() { }
|
||||
PrivateKeys(const PrivateKeys& other) : as32(other.as32) { }
|
||||
PrivateKeys() : as32() {}
|
||||
PrivateKeys(const PrivateKeys& other) : as32(other.as32) {}
|
||||
} __attribute__((packed));
|
||||
InitialKeys initial_keys;
|
||||
PrivateKeys private_keys;
|
||||
@@ -137,9 +131,6 @@ protected:
|
||||
void apply_seed(const void* original_seed, size_t seed_size);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// The following classes provide support for automatically detecting which type
|
||||
// of encryption a client is using based on their initial response to the server
|
||||
|
||||
@@ -176,8 +167,6 @@ protected:
|
||||
std::shared_ptr<PSOEncryption> active_crypt;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// The following classes provide support for multiple PSOBB private keys, and
|
||||
// the ability to automatically detect which key the client is using based on
|
||||
// the first 8 bytes they send
|
||||
@@ -232,8 +221,6 @@ protected:
|
||||
bool jsd1_use_detector_seed;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class JSD0Encryption : public PSOEncryption {
|
||||
public:
|
||||
JSD0Encryption(const void* seed, size_t seed_size);
|
||||
@@ -247,6 +234,4 @@ private:
|
||||
uint8_t key;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void decrypt_trivial_gci_data(void* data, size_t size, uint8_t basis);
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
struct TObjectVTable {
|
||||
be_uint32_t unused_a1;
|
||||
be_uint32_t unused_a2;
|
||||
@@ -36,7 +34,8 @@ shared_ptr<PSOGCObjectGraph::VTable> PSOGCObjectGraph::parse_vtable_memo(
|
||||
StringReader& r, uint32_t addr) {
|
||||
try {
|
||||
return this->all_vtables.at(addr);
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
const auto& vt = r.pget<TObjectVTable>(addr & 0x01FFFFFF);
|
||||
auto ret = this->all_vtables.emplace(addr, new VTable()).first->second;
|
||||
@@ -52,7 +51,8 @@ shared_ptr<PSOGCObjectGraph::Object> PSOGCObjectGraph::parse_object_memo(
|
||||
StringReader& r, uint32_t addr) {
|
||||
try {
|
||||
return this->all_objects.at(addr);
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
const auto& obj = r.pget<TObject>(addr & 0x01FFFFFF);
|
||||
string type_name = r.pget_cstr(obj.type_name_addr & 0x01FFFFFF);
|
||||
@@ -79,8 +79,6 @@ void PSOGCObjectGraph::print(FILE* stream) const {
|
||||
this->root->print(stream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PSOGCObjectGraph::Object::print(FILE* stream, size_t indent_level) const {
|
||||
for (size_t z = 0; z < indent_level; z++) {
|
||||
fputc(' ', stream);
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
struct PSOGCObjectGraph {
|
||||
PSOGCObjectGraph(const std::string& memory_data, uint32_t root_address);
|
||||
|
||||
|
||||
+1
-9
@@ -2,19 +2,15 @@
|
||||
|
||||
#include <event2/buffer.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Text.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
extern bool use_terminal_colors;
|
||||
|
||||
|
||||
|
||||
PSOCommandHeader::PSOCommandHeader() {
|
||||
this->bb.size = 0;
|
||||
this->bb.command = 0;
|
||||
@@ -144,8 +140,6 @@ void PSOCommandHeader::set_flag(GameVersion version, uint32_t flag) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void check_size_v(size_t size, size_t min_size, size_t max_size) {
|
||||
if (size < min_size) {
|
||||
throw std::runtime_error(string_printf(
|
||||
@@ -162,8 +156,6 @@ void check_size_v(size_t size, size_t min_size, size_t max_size) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string prepend_command_header(
|
||||
GameVersion version,
|
||||
bool encryption_enabled,
|
||||
|
||||
+2
-2
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <functional>
|
||||
#include <phosg/Strings.hh>
|
||||
|
||||
#include "Version.hh"
|
||||
#include "PSOEncryption.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
struct PSOCommandHeaderPC {
|
||||
le_uint16_t size;
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Hash.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Loggers.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
PatchFileIndex::File::File(PatchFileIndex* index)
|
||||
: index(index), crc32(0), size(0) { }
|
||||
: index(index),
|
||||
crc32(0),
|
||||
size(0) {}
|
||||
|
||||
std::shared_ptr<const std::string> PatchFileIndex::File::load_data() {
|
||||
if (!this->loaded_data) {
|
||||
@@ -29,8 +29,6 @@ std::shared_ptr<const std::string> PatchFileIndex::File::load_data() {
|
||||
return this->loaded_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PatchFileIndex::PatchFileIndex(const string& root_dir)
|
||||
: root_dir(root_dir) {
|
||||
|
||||
@@ -132,10 +130,12 @@ PatchFileIndex::PatchFileIndex(const string& root_dir)
|
||||
this->files_by_patch_order.emplace_back(f);
|
||||
this->files_by_name.emplace(relative_item_path, f);
|
||||
if (compute_crc32s_message.empty()) {
|
||||
patch_index_log.info("Added file %s (%" PRIu32 " bytes; %zu chunks; %08" PRIX32 " from cache)",
|
||||
patch_index_log.info(
|
||||
"Added file %s (%" PRIu32 " bytes; %zu chunks; %08" PRIX32 " from cache)",
|
||||
full_item_path.c_str(), f->size, f->chunk_crcs.size(), f->crc32);
|
||||
} else {
|
||||
patch_index_log.info("Added file %s (%" PRIu32 " bytes; %zu chunks; %08" PRIX32 " [%s])",
|
||||
patch_index_log.info(
|
||||
"Added file %s (%" PRIu32 " bytes; %zu chunks; %08" PRIX32 " [%s])",
|
||||
full_item_path.c_str(), f->size, f->chunk_crcs.size(), f->crc32, compute_crc32s_message.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
|
||||
|
||||
struct PatchFileIndex {
|
||||
explicit PatchFileIndex(const std::string& root_dir);
|
||||
@@ -42,7 +40,10 @@ struct PatchFileChecksumRequest {
|
||||
bool response_received;
|
||||
|
||||
explicit PatchFileChecksumRequest(std::shared_ptr<PatchFileIndex::File> file)
|
||||
: file(file), crc32(0), size(0), response_received(false) { }
|
||||
: file(file),
|
||||
crc32(0),
|
||||
size(0),
|
||||
response_received(false) {}
|
||||
inline bool needs_update() const {
|
||||
return !this->response_received ||
|
||||
(this->crc32 != this->file->crc32) ||
|
||||
|
||||
+22
-36
@@ -4,12 +4,12 @@
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Hash.hh>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "ItemData.hh"
|
||||
#include "FileContentsCache.hh"
|
||||
#include "ItemData.hh"
|
||||
#include "Loggers.hh"
|
||||
#include "StaticGameData.hh"
|
||||
#include "Text.hh"
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
// Originally there was going to be a language-based header, but then I decided
|
||||
// against it. These strings were already in use for that parser, so I didn't
|
||||
// bother changing them.
|
||||
@@ -27,14 +25,16 @@ static const string PLAYER_FILE_SIGNATURE =
|
||||
static const string ACCOUNT_FILE_SIGNATURE =
|
||||
"newserv account file format; 7 sections present; sequential;";
|
||||
|
||||
|
||||
|
||||
static FileContentsCache player_files_cache(300 * 1000 * 1000);
|
||||
|
||||
|
||||
|
||||
PlayerStats::PlayerStats() noexcept
|
||||
: atp(0), mst(0), evp(0), hp(0), dfp(0), ata(0), lck(0) { }
|
||||
: atp(0),
|
||||
mst(0),
|
||||
evp(0),
|
||||
hp(0),
|
||||
dfp(0),
|
||||
ata(0),
|
||||
lck(0) {}
|
||||
|
||||
PlayerDispDataDCPCV3::PlayerDispDataDCPCV3() noexcept
|
||||
: level(0),
|
||||
@@ -58,7 +58,7 @@ PlayerDispDataDCPCV3::PlayerDispDataDCPCV3() noexcept
|
||||
hair_g(0),
|
||||
hair_b(0),
|
||||
proportion_x(0),
|
||||
proportion_y(0) { }
|
||||
proportion_y(0) {}
|
||||
|
||||
void PlayerDispDataDCPCV3::enforce_v2_limits() {
|
||||
// V1/V2 have fewer classes, so we'll substitute some here
|
||||
@@ -119,8 +119,6 @@ PlayerDispDataBB PlayerDispDataDCPCV3::to_bb() const {
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PlayerDispDataBB::PlayerDispDataBB() noexcept
|
||||
: level(0),
|
||||
experience(0),
|
||||
@@ -143,7 +141,7 @@ PlayerDispDataBB::PlayerDispDataBB() noexcept
|
||||
hair_g(0),
|
||||
hair_b(0),
|
||||
proportion_x(0),
|
||||
proportion_y(0) { }
|
||||
proportion_y(0) {}
|
||||
|
||||
PlayerDispDataDCPCV3 PlayerDispDataBB::to_dcpcv3() const {
|
||||
PlayerDispDataDCPCV3 ret;
|
||||
@@ -263,8 +261,6 @@ void PlayerDispDataBB::apply_dressing_room(const PlayerDispDataBBPreview& pre) {
|
||||
this->name = pre.name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PlayerDispDataBBPreview::PlayerDispDataBBPreview() noexcept
|
||||
: experience(0),
|
||||
level(0),
|
||||
@@ -287,9 +283,7 @@ PlayerDispDataBBPreview::PlayerDispDataBBPreview() noexcept
|
||||
hair_b(0),
|
||||
proportion_x(0),
|
||||
proportion_y(0),
|
||||
play_time(0) { }
|
||||
|
||||
|
||||
play_time(0) {}
|
||||
|
||||
GuildCardV3::GuildCardV3() noexcept
|
||||
: player_tag(0),
|
||||
@@ -297,14 +291,14 @@ GuildCardV3::GuildCardV3() noexcept
|
||||
present(0),
|
||||
language(0),
|
||||
section_id(0),
|
||||
char_class(0) { }
|
||||
char_class(0) {}
|
||||
|
||||
GuildCardBB::GuildCardBB() noexcept
|
||||
: guild_card_number(0),
|
||||
present(0),
|
||||
language(0),
|
||||
section_id(0),
|
||||
char_class(0) { }
|
||||
char_class(0) {}
|
||||
|
||||
void GuildCardBB::clear() {
|
||||
this->guild_card_number = 0;
|
||||
@@ -326,8 +320,6 @@ uint32_t GuildCardFileBB::checksum() const {
|
||||
return crc32(this, sizeof(*this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PlayerBank::load(const string& filename) {
|
||||
*this = player_files_cache.get_obj_or_load<PlayerBank>(filename).obj;
|
||||
for (uint32_t x = 0; x < this->num_items; x++) {
|
||||
@@ -342,8 +334,6 @@ void PlayerBank::save(const string& filename, bool save_to_filesystem) const {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClientGameData::ClientGameData()
|
||||
@@ -351,7 +341,7 @@ ClientGameData::ClientGameData()
|
||||
guild_card_number(0),
|
||||
should_update_play_time(false),
|
||||
bb_player_index(0),
|
||||
should_save(true) { }
|
||||
should_save(true) {}
|
||||
|
||||
ClientGameData::~ClientGameData() {
|
||||
if (!this->bb_username.empty()) {
|
||||
@@ -461,7 +451,8 @@ void ClientGameData::load_account_data() {
|
||||
player_files_cache.delete_key(filename);
|
||||
data.reset(new SavedAccountDataBB(
|
||||
player_files_cache.get_obj_or_load<SavedAccountDataBB>(
|
||||
"system/players/default.nsa").obj));
|
||||
"system/players/default.nsa")
|
||||
.obj));
|
||||
if (data->signature != ACCOUNT_FILE_SIGNATURE) {
|
||||
throw runtime_error("default account data header is incorrect");
|
||||
}
|
||||
@@ -592,8 +583,6 @@ PlayerBB ClientGameData::export_player_bb() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PlayerLobbyDataPC::clear() {
|
||||
this->player_tag = 0;
|
||||
this->guild_card = 0;
|
||||
@@ -638,7 +627,6 @@ void PlayerLobbyDataBB::clear() {
|
||||
this->unknown_a2 = 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PlayerInventoryItem::PlayerInventoryItem() {
|
||||
@@ -646,7 +634,9 @@ PlayerInventoryItem::PlayerInventoryItem() {
|
||||
}
|
||||
|
||||
PlayerInventoryItem::PlayerInventoryItem(const PlayerBankItem& src)
|
||||
: present(1), flags(0), data(src.data) { }
|
||||
: present(1),
|
||||
flags(0),
|
||||
data(src.data) {}
|
||||
|
||||
void PlayerInventoryItem::clear() {
|
||||
this->present = 0x00000000;
|
||||
@@ -661,7 +651,7 @@ PlayerBankItem::PlayerBankItem() {
|
||||
PlayerBankItem::PlayerBankItem(const PlayerInventoryItem& src)
|
||||
: data(src.data),
|
||||
amount(this->data.stack_size()),
|
||||
show_flags(1) { }
|
||||
show_flags(1) {}
|
||||
|
||||
void PlayerBankItem::clear() {
|
||||
this->data.clear();
|
||||
@@ -669,15 +659,11 @@ void PlayerBankItem::clear() {
|
||||
this->show_flags = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PlayerInventory::PlayerInventory()
|
||||
: num_items(0),
|
||||
hp_materials_used(0),
|
||||
tp_materials_used(0),
|
||||
language(0) { }
|
||||
|
||||
|
||||
language(0) {}
|
||||
|
||||
// TODO: Eliminate duplication between this function and the parallel function
|
||||
// in PlayerBank
|
||||
|
||||
+8
-32
@@ -4,18 +4,16 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "LevelTable.hh"
|
||||
#include "ItemData.hh"
|
||||
#include "Version.hh"
|
||||
#include "Text.hh"
|
||||
#include "Episode3/DataIndex.hh"
|
||||
|
||||
|
||||
#include "ItemData.hh"
|
||||
#include "LevelTable.hh"
|
||||
#include "Text.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
struct PlayerBankItem;
|
||||
|
||||
@@ -67,8 +65,6 @@ struct PlayerBank { // 0x12C8 bytes
|
||||
size_t find_item(uint32_t item_id);
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct PendingItemTrade {
|
||||
uint8_t other_client_id;
|
||||
bool confirmed; // true if client has sent a D2 command
|
||||
@@ -81,8 +77,6 @@ struct PendingCardTrade {
|
||||
std::vector<std::pair<uint32_t, uint32_t>> card_to_count;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PlayerDispDataBB;
|
||||
|
||||
struct PlayerDispDataDCPCV3 { // 0xD0 bytes
|
||||
@@ -192,15 +186,13 @@ struct PlayerDispDataBB {
|
||||
|
||||
PlayerDispDataBB() noexcept;
|
||||
|
||||
inline void enforce_v2_limits() { }
|
||||
inline void enforce_v2_limits() {}
|
||||
PlayerDispDataDCPCV3 to_dcpcv3() const;
|
||||
PlayerDispDataBBPreview to_preview() const;
|
||||
void apply_preview(const PlayerDispDataBBPreview&);
|
||||
void apply_dressing_room(const PlayerDispDataBBPreview&);
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
// TODO: Is this the same for XB as it is for GC? (This struct is based on the
|
||||
// GC format)
|
||||
struct GuildCardV3 {
|
||||
@@ -265,8 +257,6 @@ struct KeyAndTeamConfigBB {
|
||||
le_uint32_t team_rewards; // 0AEC
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct PlayerLobbyDataPC {
|
||||
le_uint32_t player_tag = 0;
|
||||
le_uint32_t guild_card = 0;
|
||||
@@ -328,8 +318,6 @@ struct PlayerLobbyDataBB {
|
||||
void clear();
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct PlayerChallengeDataV3 {
|
||||
le_uint32_t client_id;
|
||||
struct {
|
||||
@@ -365,8 +353,6 @@ struct PlayerChallengeDataBB {
|
||||
parray<uint8_t, 0x158> unknown_a1;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
template <typename ItemIDT>
|
||||
struct ChoiceSearchConfig {
|
||||
// 0 = enabled, 1 = disabled. Unused for command C3
|
||||
@@ -378,8 +364,6 @@ struct ChoiceSearchConfig {
|
||||
parray<Entry, 5> entries;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct PSOPlayerDataDCPC { // For command 61
|
||||
PlayerInventory inventory;
|
||||
PlayerDispDataDCPCV3 disp;
|
||||
@@ -450,8 +434,6 @@ struct PlayerBB { // Used in 00E7 command
|
||||
KeyAndTeamConfigBB key_config; // 2EA4-3994; account
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct SavedPlayerDataBB { // .nsc file format
|
||||
ptext<char, 0x40> signature;
|
||||
PlayerDispDataBBPreview preview;
|
||||
@@ -489,8 +471,6 @@ struct SavedAccountDataBB { // .nsa file format
|
||||
ptext<char16_t, 0x0010> team_name;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
class ClientGameData {
|
||||
private:
|
||||
std::shared_ptr<SavedAccountDataBB> account_data;
|
||||
@@ -547,12 +527,8 @@ public:
|
||||
PlayerBB export_player_bb();
|
||||
};
|
||||
|
||||
|
||||
|
||||
uint32_t compute_guild_card_checksum(const void* data, size_t size);
|
||||
|
||||
|
||||
|
||||
template <typename DestT, typename SrcT = DestT>
|
||||
DestT convert_player_disp_data(const SrcT&) {
|
||||
static_assert(always_false<DestT, SrcT>::v,
|
||||
|
||||
+1
-5
@@ -1,15 +1,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Time.hh>
|
||||
|
||||
#include "PSOEncryption.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
static const uint32_t primes1[] = {
|
||||
0x65, 0x67, 0x6B, 0x6D, 0x71, 0x7F, 0x83, 0x89, 0x8B, 0x95, 0x97, 0x9D,
|
||||
0xA3, 0xA7, 0xAD, 0xB3, 0xB5, 0xBF, 0xC1, 0xC5, 0xC7, 0xD3, 0xDF, 0xE3,
|
||||
@@ -1125,8 +1123,6 @@ static bool check_prime3(uint64_t prime3) {
|
||||
return primes3_set[offset];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char replace_char_forward(char ch) {
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
return "5A76D2C1F0"[ch - '0'];
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
bool product_is_valid(
|
||||
const std::string& s, uint8_t domain, uint8_t subdomain = 0xFF);
|
||||
bool product_is_valid_fast(
|
||||
|
||||
+12
-17
@@ -8,8 +8,8 @@
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -26,18 +26,16 @@
|
||||
#include <resource_file/Emulators/PPC32Emulator.hh>
|
||||
#endif
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "ChatCommands.hh"
|
||||
#include "Compression.hh"
|
||||
#include "Loggers.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "SendCommands.hh"
|
||||
#include "ReceiveCommands.hh"
|
||||
#include "ReceiveSubcommands.hh"
|
||||
#include "SendCommands.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
struct HandlerResult {
|
||||
enum class Type {
|
||||
FORWARD = 0,
|
||||
@@ -50,9 +48,13 @@ struct HandlerResult {
|
||||
int32_t new_command;
|
||||
int64_t new_flag;
|
||||
|
||||
HandlerResult(Type type) : type(type), new_command(-1), new_flag(-1) { }
|
||||
HandlerResult(Type type) : type(type),
|
||||
new_command(-1),
|
||||
new_flag(-1) {}
|
||||
HandlerResult(Type type, uint16_t new_command, uint32_t new_flag)
|
||||
: type(type), new_command(new_command), new_flag(new_flag) { }
|
||||
: type(type),
|
||||
new_command(new_command),
|
||||
new_flag(new_flag) {}
|
||||
};
|
||||
|
||||
typedef HandlerResult (*on_command_t)(
|
||||
@@ -62,8 +64,6 @@ typedef HandlerResult (*on_command_t)(
|
||||
uint32_t flag,
|
||||
string& data);
|
||||
|
||||
|
||||
|
||||
static void forward_command(ProxyServer::LinkedSession& session, bool to_server,
|
||||
uint16_t command, uint32_t flag, string& data, bool print_contents = true) {
|
||||
auto& ch = to_server ? session.server_channel : session.client_channel;
|
||||
@@ -86,8 +86,6 @@ static void check_implemented_subcommand(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Command handlers. These are called to preprocess or react to specific
|
||||
// commands in either direction. The functions have abbreviated names in order
|
||||
// to make the massive table more readable. The functions' names are, in
|
||||
@@ -148,8 +146,7 @@ static HandlerResult C_G_9E(shared_ptr<ServerState>,
|
||||
le_uint64_t checksum = random_object<uint64_t>() & 0x0000FFFFFFFFFFFF;
|
||||
session.server_channel.send(0x96, 0x00, &checksum, sizeof(checksum));
|
||||
|
||||
S_UpdateClientConfig_DC_PC_V3_04 cmd = {{
|
||||
0x00010000, session.license->serial_number, ClientConfig()}};
|
||||
S_UpdateClientConfig_DC_PC_V3_04 cmd = {{0x00010000, session.license->serial_number, ClientConfig()}};
|
||||
session.client_channel.send(0x04, 0x00, &cmd, sizeof(cmd));
|
||||
|
||||
return HandlerResult::Type::SUPPRESS;
|
||||
@@ -159,7 +156,6 @@ static HandlerResult C_G_9E(shared_ptr<ServerState>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static HandlerResult S_G_9A(shared_ptr<ServerState>,
|
||||
ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) {
|
||||
if (!session.license || session.options.suppress_remote_login) {
|
||||
@@ -1586,7 +1582,6 @@ constexpr on_command_t C_DGX_81 = &C_81<SC_SimpleMail_DC_V3_81>;
|
||||
constexpr on_command_t C_P_81 = &C_81<SC_SimpleMail_PC_81>;
|
||||
constexpr on_command_t C_B_81 = &C_81<SC_SimpleMail_BB_81>;
|
||||
|
||||
|
||||
template <typename CmdT>
|
||||
void C_6x_movement(ProxyServer::LinkedSession& session, const string& data) {
|
||||
const auto& cmd = check_size_t<CmdT>(data);
|
||||
@@ -1676,10 +1671,9 @@ static HandlerResult C_V123_A0_A1(shared_ptr<ServerState>,
|
||||
return HandlerResult::Type::SUPPRESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// [command][version][is_client]
|
||||
static on_command_t handlers[0x100][6][2] = {
|
||||
// clang-format off
|
||||
// CMD S-PATCH C-PATCH S-DC C-DC S-PC C-PC S-GC C-GC S-XB C-XB S-BB C-BB
|
||||
/* 00 */ {{S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}},
|
||||
/* 01 */ {{S_invalid, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {S_invalid, nullptr}},
|
||||
@@ -1945,6 +1939,7 @@ static on_command_t handlers[0x100][6][2] = {
|
||||
/* FE */ {{S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}},
|
||||
/* FF */ {{S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}},
|
||||
// CMD S-PATCH C-PATCH S-DC C-DC S-PC C-PC S-GC C-GC S-XB C-XB S-BB C-BB
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static on_command_t get_handler(GameVersion version, bool from_server, uint8_t command) {
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ServerState.hh"
|
||||
#include "ProxyServer.hh"
|
||||
|
||||
|
||||
#include "ServerState.hh"
|
||||
|
||||
void on_proxy_command(
|
||||
std::shared_ptr<ServerState> s,
|
||||
|
||||
+13
-41
@@ -8,8 +8,8 @@
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -25,23 +25,21 @@
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "SendCommands.hh"
|
||||
#include "ProxyCommands.hh"
|
||||
#include "ReceiveCommands.hh"
|
||||
#include "ReceiveSubcommands.hh"
|
||||
#include "ProxyCommands.hh"
|
||||
#include "SendCommands.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
|
||||
|
||||
|
||||
ProxyServer::ProxyServer(
|
||||
shared_ptr<struct event_base> base,
|
||||
shared_ptr<ServerState> state)
|
||||
: base(base),
|
||||
destroy_sessions_ev(event_new(this->base.get(), -1, EV_TIMEOUT, &ProxyServer::dispatch_destroy_sessions, this), event_free),
|
||||
state(state),
|
||||
next_unlicensed_session_id(0xFF00000000000001) { }
|
||||
next_unlicensed_session_id(0xFF00000000000001) {}
|
||||
|
||||
void ProxyServer::listen(uint16_t port, GameVersion version,
|
||||
const struct sockaddr_storage* default_destination) {
|
||||
@@ -114,8 +112,6 @@ void ProxyServer::ListeningSocket::on_listen_error() {
|
||||
event_base_loopexit(this->server->base.get(), nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProxyServer::connect_client(struct bufferevent* bev, uint16_t server_port) {
|
||||
// Look up the listening socket for the given port, and use that game version.
|
||||
// We don't support default-destination proxying for virtual connections (yet)
|
||||
@@ -135,8 +131,6 @@ void ProxyServer::connect_client(struct bufferevent* bev, uint16_t server_port)
|
||||
this->on_client_connect(bev, server_port, version, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProxyServer::on_client_connect(
|
||||
struct bufferevent* bev,
|
||||
uint16_t listen_port,
|
||||
@@ -151,8 +145,7 @@ void ProxyServer::on_client_connect(
|
||||
this->next_unlicensed_session_id = 0xFF00000000000001;
|
||||
}
|
||||
|
||||
auto emplace_ret = this->id_to_session.emplace(session_id, new LinkedSession(
|
||||
this, session_id, listen_port, version, *default_destination));
|
||||
auto emplace_ret = this->id_to_session.emplace(session_id, new LinkedSession(this, session_id, listen_port, version, *default_destination));
|
||||
if (!emplace_ret.second) {
|
||||
throw logic_error("linked session already exists for unlicensed client");
|
||||
}
|
||||
@@ -166,8 +159,7 @@ void ProxyServer::on_client_connect(
|
||||
// create an unlinked session - we'll have to get the destination from the
|
||||
// client's config, which we'll get via a 9E command soon.
|
||||
} else {
|
||||
auto emplace_ret = this->bev_to_unlinked_session.emplace(bev, new UnlinkedSession(
|
||||
this, bev, listen_port, version));
|
||||
auto emplace_ret = this->bev_to_unlinked_session.emplace(bev, new UnlinkedSession(this, bev, listen_port, version));
|
||||
if (!emplace_ret.second) {
|
||||
throw logic_error("stale unlinked session exists");
|
||||
}
|
||||
@@ -227,8 +219,6 @@ void ProxyServer::on_client_connect(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ProxyServer::UnlinkedSession::UnlinkedSession(
|
||||
ProxyServer* server,
|
||||
struct bufferevent* bev,
|
||||
@@ -440,8 +430,6 @@ void ProxyServer::UnlinkedSession::on_error(Channel& ch, short events) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ProxyServer::LinkedSession::LinkedSession(
|
||||
ProxyServer* server,
|
||||
uint64_t id,
|
||||
@@ -451,7 +439,8 @@ ProxyServer::LinkedSession::LinkedSession(
|
||||
id(id),
|
||||
log(string_printf("[ProxyServer:LinkedSession:%08" PRIX64 "] ", this->id), proxy_server_log.min_level),
|
||||
timeout_event(event_new(this->server->base.get(), -1, EV_TIMEOUT,
|
||||
&LinkedSession::dispatch_on_timeout, this), event_free),
|
||||
&LinkedSession::dispatch_on_timeout, this),
|
||||
event_free),
|
||||
license(nullptr),
|
||||
client_channel(
|
||||
version,
|
||||
@@ -606,8 +595,6 @@ void ProxyServer::LinkedSession::connect() {
|
||||
event_del(this->timeout_event.get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
ProxyServer::LinkedSession::SavingFile::SavingFile(
|
||||
const string& basename,
|
||||
const string& output_filename,
|
||||
@@ -620,21 +607,15 @@ ProxyServer::LinkedSession::SavingFile::SavingFile(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProxyServer::LinkedSession::dispatch_on_timeout(
|
||||
evutil_socket_t, short, void* ctx) {
|
||||
reinterpret_cast<LinkedSession*>(ctx)->on_timeout();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProxyServer::LinkedSession::on_timeout() {
|
||||
this->server->delete_session(this->id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProxyServer::LinkedSession::on_error(Channel& ch, short events) {
|
||||
auto* session = reinterpret_cast<LinkedSession*>(ch.context_obj);
|
||||
bool is_server_stream = (&ch == &session->server_channel);
|
||||
@@ -643,11 +624,9 @@ void ProxyServer::LinkedSession::on_error(Channel& ch, short events) {
|
||||
session->log.info("%s channel connected", is_server_stream ? "Server" : "Client");
|
||||
|
||||
if (is_server_stream && (session->options.override_lobby_event >= 0) &&
|
||||
(
|
||||
((session->version == GameVersion::GC) && !(session->newserv_client_config.cfg.flags & Client::Flag::IS_TRIAL_EDITION)) ||
|
||||
(((session->version == GameVersion::GC) && !(session->newserv_client_config.cfg.flags & Client::Flag::IS_TRIAL_EDITION)) ||
|
||||
(session->version == GameVersion::XB) ||
|
||||
(session->version == GameVersion::BB)
|
||||
)) {
|
||||
(session->version == GameVersion::BB))) {
|
||||
session->client_channel.send(0xDA, session->options.override_lobby_event);
|
||||
}
|
||||
}
|
||||
@@ -702,15 +681,11 @@ void ProxyServer::LinkedSession::send_to_game_server(const char* error_message)
|
||||
|
||||
string encoded_name = encode_sjis(this->server->state->name);
|
||||
if (this->is_in_game) {
|
||||
send_ship_info(this->client_channel, decode_sjis(string_printf(
|
||||
"You cannot return\nto $C6%s$C7\nwhile in a game.\n\n%s",
|
||||
encoded_name.c_str(), error_message ? error_message : "")));
|
||||
send_ship_info(this->client_channel, decode_sjis(string_printf("You cannot return\nto $C6%s$C7\nwhile in a game.\n\n%s", encoded_name.c_str(), error_message ? error_message : "")));
|
||||
this->disconnect();
|
||||
|
||||
} else {
|
||||
send_ship_info(this->client_channel, decode_sjis(string_printf(
|
||||
"You\'ve returned to\n\tC6%s$C7\n\n%s", encoded_name.c_str(),
|
||||
error_message ? error_message : "")));
|
||||
send_ship_info(this->client_channel, decode_sjis(string_printf("You\'ve returned to\n\tC6%s$C7\n\n%s", encoded_name.c_str(), error_message ? error_message : "")));
|
||||
|
||||
// Restore newserv_client_config, so the login server gets the client flags
|
||||
S_UpdateClientConfig_DC_PC_V3_04 update_client_config_cmd;
|
||||
@@ -722,8 +697,7 @@ void ProxyServer::LinkedSession::send_to_game_server(const char* error_message)
|
||||
const auto& port_name = version_to_login_port_name.at(static_cast<size_t>(
|
||||
this->version));
|
||||
|
||||
S_Reconnect_19 reconnect_cmd = {{
|
||||
0, this->server->state->name_to_port_config.at(port_name)->port, 0}};
|
||||
S_Reconnect_19 reconnect_cmd = {{0, this->server->state->name_to_port_config.at(port_name)->port, 0}};
|
||||
|
||||
// If the client is on a virtual connection, we can use any address
|
||||
// here and they should be able to connect back to the game server. If
|
||||
@@ -781,8 +755,6 @@ bool ProxyServer::LinkedSession::is_connected() const {
|
||||
return (this->server_channel.connected() && this->client_channel.connected());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProxyServer::LinkedSession::on_input(Channel& ch, uint16_t command, uint32_t flag, std::string& data) {
|
||||
auto* session = reinterpret_cast<LinkedSession*>(ch.context_obj);
|
||||
bool is_server_stream = (&ch == &session->server_channel);
|
||||
|
||||
+11
-11
@@ -3,21 +3,19 @@
|
||||
#include <event2/event.h>
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "PSOEncryption.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "ServerState.hh"
|
||||
|
||||
|
||||
|
||||
class ProxyServer {
|
||||
public:
|
||||
ProxyServer() = delete;
|
||||
@@ -38,7 +36,7 @@ public:
|
||||
uint64_t id;
|
||||
PrefixedLogger log;
|
||||
|
||||
std::unique_ptr<struct event, void(*)(struct event*)> timeout_event;
|
||||
std::unique_ptr<struct event, void (*)(struct event*)> timeout_event;
|
||||
|
||||
std::shared_ptr<const License> license;
|
||||
|
||||
@@ -80,7 +78,9 @@ public:
|
||||
std::string name;
|
||||
uint8_t section_id;
|
||||
uint8_t char_class;
|
||||
LobbyPlayer() : guild_card_number(0), section_id(0), char_class(0) { }
|
||||
LobbyPlayer() : guild_card_number(0),
|
||||
section_id(0),
|
||||
char_class(0) {}
|
||||
};
|
||||
std::vector<LobbyPlayer> lobby_players;
|
||||
size_t lobby_client_id;
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
PrefixedLogger log;
|
||||
uint16_t port;
|
||||
scoped_fd fd;
|
||||
std::unique_ptr<struct evconnlistener, void(*)(struct evconnlistener*)> listener;
|
||||
std::unique_ptr<struct evconnlistener, void (*)(struct evconnlistener*)> listener;
|
||||
GameVersion version;
|
||||
struct sockaddr_storage default_destination;
|
||||
|
||||
@@ -190,7 +190,7 @@ private:
|
||||
const struct sockaddr_storage* default_destination);
|
||||
|
||||
static void dispatch_on_listen_accept(struct evconnlistener* listener,
|
||||
evutil_socket_t fd, struct sockaddr *address, int socklen, void* ctx);
|
||||
evutil_socket_t fd, struct sockaddr* address, int socklen, void* ctx);
|
||||
static void dispatch_on_listen_error(struct evconnlistener* listener, void* ctx);
|
||||
void on_listen_accept(int fd);
|
||||
void on_listen_error();
|
||||
|
||||
+16
-29
@@ -2,26 +2,24 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Encoding.hh>
|
||||
#include <phosg/Filesystem.hh>
|
||||
#include <phosg/Hash.hh>
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Tools.hh>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "SaveFileFormats.hh"
|
||||
#include "CommandFormats.hh"
|
||||
#include "Compression.hh"
|
||||
#include "Loggers.hh"
|
||||
#include "PSOEncryption.hh"
|
||||
#include "SaveFileFormats.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
// GCI decoding logic
|
||||
|
||||
template <bool IsBigEndian>
|
||||
@@ -38,8 +36,10 @@ struct PSOMemCardDLQFileEncryptedHeader {
|
||||
// Data follows here.
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PSOVMSDLQFileEncryptedHeader : PSOMemCardDLQFileEncryptedHeader<false> { } __attribute__((packed));
|
||||
struct PSOGCIDLQFileEncryptedHeader : PSOMemCardDLQFileEncryptedHeader<true> { } __attribute__((packed));
|
||||
struct PSOVMSDLQFileEncryptedHeader : PSOMemCardDLQFileEncryptedHeader<false> {
|
||||
} __attribute__((packed));
|
||||
struct PSOGCIDLQFileEncryptedHeader : PSOMemCardDLQFileEncryptedHeader<true> {
|
||||
} __attribute__((packed));
|
||||
|
||||
template <bool IsBigEndian>
|
||||
string decrypt_gci_or_vms_v2_download_quest_data_section(
|
||||
@@ -78,9 +78,7 @@ string decrypt_gci_or_vms_v2_download_quest_data_section(
|
||||
// Unlike the above rounds, round 3 is always little-endian (it corresponds to
|
||||
// the round of encryption done on the server before sending the file to the
|
||||
// client in the first place)
|
||||
PSOV2Encryption(header->round3_seed).decrypt(
|
||||
decrypted.data() + sizeof(HeaderT),
|
||||
decrypted.size() - sizeof(HeaderT));
|
||||
PSOV2Encryption(header->round3_seed).decrypt(decrypted.data() + sizeof(HeaderT), decrypted.size() - sizeof(HeaderT));
|
||||
decrypted.resize(orig_size);
|
||||
|
||||
// Some download quest GCI files have decompressed_size fields that are 8
|
||||
@@ -136,7 +134,8 @@ string find_seed_and_decrypt_gci_or_vms_v2_download_quest_data_section(
|
||||
} catch (const runtime_error&) {
|
||||
return false;
|
||||
}
|
||||
}, 0, 0x100000000, num_threads);
|
||||
},
|
||||
0, 0x100000000, num_threads);
|
||||
|
||||
if (!result.empty() && (result_seed < 0x100000000)) {
|
||||
static_game_data_log.info("Found seed %08" PRIX64, result_seed);
|
||||
@@ -146,8 +145,6 @@ string find_seed_and_decrypt_gci_or_vms_v2_download_quest_data_section(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct PSOVMSFileHeader {
|
||||
ptext<char, 0x10> short_desc; // "PSO/DOWNLOAD " or "PSOV2/DOWNLOAD "
|
||||
ptext<char, 0x20> long_desc; // Usually quest name
|
||||
@@ -187,15 +184,11 @@ struct PSOVMSFileHeader {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
struct PSODownloadQuestHeader {
|
||||
le_uint32_t size;
|
||||
le_uint32_t encryption_seed;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
bool category_is_mode(QuestCategory category) {
|
||||
return (category == QuestCategory::BATTLE) ||
|
||||
(category == QuestCategory::CHALLENGE) ||
|
||||
@@ -237,8 +230,6 @@ const char* name_for_category(QuestCategory category) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct PSOQuestHeaderDC { // Same format for DC v1 and v2, thankfully
|
||||
uint32_t start_offset;
|
||||
uint32_t unknown_offset1;
|
||||
@@ -297,8 +288,6 @@ struct PSOQuestHeaderBB {
|
||||
ptext<char16_t, 0x120> long_description;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
Quest::Quest(const string& bin_filename)
|
||||
: internal_id(-1),
|
||||
menu_item_id(0),
|
||||
@@ -705,7 +694,8 @@ string Quest::decode_vms(
|
||||
const void* data_section = r.getv(header.data_size);
|
||||
try {
|
||||
return decrypt_vms_v1_data_section(data_section, header.data_size);
|
||||
} catch (const exception& e) { }
|
||||
} catch (const exception& e) {
|
||||
}
|
||||
|
||||
if (known_seed >= 0) {
|
||||
return decrypt_gci_or_vms_v2_download_quest_data_section<false>(
|
||||
@@ -973,8 +963,6 @@ string Quest::export_qst(GameVersion version) const {
|
||||
return move(w.str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
QuestIndex::QuestIndex(const string& directory) : directory(directory) {
|
||||
auto filename_set = list_directory(this->directory);
|
||||
vector<string> filenames(filename_set.begin(), filename_set.end());
|
||||
@@ -1004,7 +992,8 @@ QuestIndex::QuestIndex(const string& directory) : directory(directory) {
|
||||
q->menu_item_id = next_menu_item_id++;
|
||||
string ascii_name = encode_sjis(q->name);
|
||||
if (!this->version_menu_item_id_to_quest.emplace(
|
||||
make_pair(q->version, q->menu_item_id), q).second) {
|
||||
make_pair(q->version, q->menu_item_id), q)
|
||||
.second) {
|
||||
throw logic_error("duplicate quest menu item id");
|
||||
}
|
||||
static_game_data_log.info("Indexed quest %s (%s => %s-%" PRId64 " (%" PRIu32 "), %s, %s, joinable=%s, dcv1=%s)",
|
||||
@@ -1050,8 +1039,6 @@ vector<shared_ptr<const Quest>> QuestIndex::filter(
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static string create_download_quest_file(const string& compressed_data,
|
||||
size_t decompressed_size, uint32_t encryption_seed = 0) {
|
||||
// Download quest files are like normal (PRS-compressed) quest files, but they
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include "StaticGameData.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
|
||||
|
||||
enum class QuestCategory {
|
||||
UNKNOWN = -1,
|
||||
RETRIEVAL = 0,
|
||||
@@ -33,8 +31,6 @@ enum class QuestCategory {
|
||||
bool category_is_mode(QuestCategory category);
|
||||
const char* name_for_category(QuestCategory category);
|
||||
|
||||
|
||||
|
||||
class Quest {
|
||||
public:
|
||||
enum class FileFormat {
|
||||
|
||||
+1
-7
@@ -7,8 +7,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
uint32_t RareItemSet::expand_rate(uint8_t pc) {
|
||||
int8_t shift = ((pc >> 3) & 0x1F) - 4;
|
||||
if (shift < 0) {
|
||||
@@ -21,10 +19,8 @@ bool RareItemSet::sample(mt19937& random, uint8_t pc) {
|
||||
return (random() < RareItemSet::expand_rate(pc));
|
||||
}
|
||||
|
||||
|
||||
|
||||
GSLRareItemSet::GSLRareItemSet(shared_ptr<const string> data, bool is_big_endian)
|
||||
: gsl(data, is_big_endian) { }
|
||||
: gsl(data, is_big_endian) {}
|
||||
|
||||
const GSLRareItemSet::Table& GSLRareItemSet::get_table(
|
||||
Episode episode, GameMode mode, uint8_t difficulty, uint8_t secid) const {
|
||||
@@ -51,8 +47,6 @@ const GSLRareItemSet::Table& GSLRareItemSet::get_table(
|
||||
return *reinterpret_cast<const Table*>(entry.first);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RELRareItemSet::RELRareItemSet(shared_ptr<const string> data) : data(data) {
|
||||
if (this->data->size() != sizeof(Table) * 10 * 4 * 3) {
|
||||
throw runtime_error("data file size is incorrect");
|
||||
|
||||
+2
-6
@@ -3,13 +3,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include "StaticGameData.hh"
|
||||
#include "GSLArchive.hh"
|
||||
|
||||
|
||||
#include "StaticGameData.hh"
|
||||
|
||||
class RareItemSet {
|
||||
public:
|
||||
@@ -52,8 +50,6 @@ protected:
|
||||
RareItemSet() = default;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class GSLRareItemSet : public RareItemSet {
|
||||
public:
|
||||
GSLRareItemSet(std::shared_ptr<const std::string> data, bool is_big_endian);
|
||||
|
||||
+19
-57
@@ -16,8 +16,8 @@
|
||||
#include "FileContentsCache.hh"
|
||||
#include "ItemCreator.hh"
|
||||
#include "Loggers.hh"
|
||||
#include "ProxyServer.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "ProxyServer.hh"
|
||||
#include "ReceiveSubcommands.hh"
|
||||
#include "SendCommands.hh"
|
||||
#include "StaticGameData.hh"
|
||||
@@ -25,15 +25,11 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
const char* BATTLE_TABLE_DISCONNECT_HOOK_NAME = "battle_table_state";
|
||||
const char* QUEST_BARRIER_DISCONNECT_HOOK_NAME = "quest_barrier";
|
||||
const char* CARD_AUCTION_DISCONNECT_HOOK_NAME = "card_auction";
|
||||
const char* ADD_NEXT_CLIENT_DISCONNECT_HOOK_NAME = "add_next_game_client";
|
||||
|
||||
|
||||
|
||||
vector<MenuItem> quest_categories_menu({
|
||||
MenuItem(static_cast<uint32_t>(QuestCategory::RETRIEVAL), u"Retrieval", u"$E$C6Quests that involve\nretrieving an object", 0),
|
||||
MenuItem(static_cast<uint32_t>(QuestCategory::EXTERMINATION), u"Extermination", u"$E$C6Quests that involve\ndestroying all\nmonsters", 0),
|
||||
@@ -56,8 +52,8 @@ vector<MenuItem> quest_solo_menu({
|
||||
});
|
||||
|
||||
vector<MenuItem> quest_government_menu({
|
||||
MenuItem(static_cast<uint32_t>(QuestCategory::GOVERNMENT_EPISODE_1), u"Hero in Red",u"$E$CG-Red Ring Rico-\n$C6Quests that follow\nthe Episode 1\nstoryline", 0),
|
||||
MenuItem(static_cast<uint32_t>(QuestCategory::GOVERNMENT_EPISODE_2), u"The Military's Hero",u"$E$CG-Heathcliff Flowen-\n$C6Quests that follow\nthe Episode 2\nstoryline", 0),
|
||||
MenuItem(static_cast<uint32_t>(QuestCategory::GOVERNMENT_EPISODE_1), u"Hero in Red", u"$E$CG-Red Ring Rico-\n$C6Quests that follow\nthe Episode 1\nstoryline", 0),
|
||||
MenuItem(static_cast<uint32_t>(QuestCategory::GOVERNMENT_EPISODE_2), u"The Military's Hero", u"$E$CG-Heathcliff Flowen-\n$C6Quests that follow\nthe Episode 2\nstoryline", 0),
|
||||
MenuItem(static_cast<uint32_t>(QuestCategory::GOVERNMENT_EPISODE_4), u"The Meteor Impact Incident", u"$E$C6Quests that follow\nthe Episode 4\nstoryline", 0),
|
||||
});
|
||||
|
||||
@@ -130,8 +126,6 @@ static vector<MenuItem> proxy_options_menu_for_client(
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void send_client_to_lobby_server(shared_ptr<ServerState> s, shared_ptr<Client> c) {
|
||||
const auto& port_name = version_to_lobby_port_name.at(static_cast<size_t>(c->version()));
|
||||
send_reconnect(c, s->connect_address_for_client(c),
|
||||
@@ -174,8 +168,6 @@ static bool send_enable_send_function_call_if_applicable(
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void on_connect(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c) {
|
||||
@@ -264,8 +256,6 @@ void on_login_complete(shared_ptr<ServerState> s, shared_ptr<Client> c) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void on_disconnect(shared_ptr<ServerState> s, shared_ptr<Client> c) {
|
||||
// If the client was in a lobby, remove them and notify the other clients
|
||||
if (c->lobby_id) {
|
||||
@@ -279,8 +269,6 @@ void on_disconnect(shared_ptr<ServerState> s, shared_ptr<Client> c) {
|
||||
// shortly after this point
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void set_console_client_flags(
|
||||
@@ -860,8 +848,6 @@ static void on_B1(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_BA_Ep3(shared_ptr<ServerState>,
|
||||
shared_ptr<Client> c, uint16_t command, uint32_t, const string& data) {
|
||||
const auto& in_cmd = check_size_t<C_Meseta_GC_Ep3_BA>(data);
|
||||
@@ -1853,7 +1839,8 @@ static void on_10(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
const pair<string, uint16_t>* dest = nullptr;
|
||||
try {
|
||||
dest = &s->proxy_destinations_for_version(c->version()).at(item_id);
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
if (!dest) {
|
||||
send_message_box(c, u"$C6No such destination exists.");
|
||||
@@ -2120,7 +2107,8 @@ static void on_10(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
After registration ends, start your matches by\n\
|
||||
standing at the rightmost 4-player Battle Table\n\
|
||||
in the lobby along with your partner (if any) and\n\
|
||||
opponent(s).", tourn->get_name().c_str());
|
||||
opponent(s).",
|
||||
tourn->get_name().c_str());
|
||||
send_ep3_timed_message_box(c->channel, 240, message.c_str());
|
||||
|
||||
s->ep3_tournament_index->save();
|
||||
@@ -2243,8 +2231,6 @@ static void on_8F_DCNTE(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void send_dol_file_chunk(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint32_t start_addr) {
|
||||
size_t offset = start_addr - c->dol_base_addr;
|
||||
@@ -2293,8 +2279,6 @@ static void on_B3(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_A2(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t flag, const string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
@@ -2452,8 +2436,6 @@ static void on_13_A7_V3_BB(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
send_file_chunk(c, cmd.filename, flag + 1, (command == 0xA7));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_61_98(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t command, uint32_t flag, const string& data) {
|
||||
|
||||
@@ -2542,8 +2524,6 @@ static void on_61_98(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_6x_C9_CB(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t command, uint32_t flag, const string& data) {
|
||||
check_size_v(data.size(), 4, 0xFFFF);
|
||||
@@ -2556,8 +2536,6 @@ static void on_6x_C9_CB(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
on_subcommand(s, l, c, command, flag, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_chat_generic(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
const u16string& text) {
|
||||
|
||||
@@ -2628,8 +2606,6 @@ static void on_06_DC_V3(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
on_chat_generic(s, c, decoded_s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_00E0_BB(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t, const string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
@@ -2948,8 +2924,6 @@ static void on_00E2_BB(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
// TODO: We should probably send a response here, but I don't know which one!
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_89(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t flag, const string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
@@ -2968,7 +2942,8 @@ static void on_40(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
auto result = s->find_client(nullptr, cmd.target_guild_card_number);
|
||||
auto result_lobby = s->find_lobby(result->lobby_id);
|
||||
send_card_search_result(s, c, result, result_lobby);
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
}
|
||||
|
||||
static void on_C0(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
@@ -3009,7 +2984,8 @@ static void on_81(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
shared_ptr<Client> target;
|
||||
try {
|
||||
target = s->find_client(nullptr, to_guild_card_number);
|
||||
} catch (const out_of_range&) { }
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
// TODO: We should store pending messages for accounts somewhere, and send
|
||||
@@ -3042,8 +3018,6 @@ static void on_81(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_D8(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t, const string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
@@ -3103,8 +3077,6 @@ static void on_C6(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
shared_ptr<Lobby> create_game_generic(
|
||||
shared_ptr<ServerState> s,
|
||||
shared_ptr<Client> c,
|
||||
@@ -3183,7 +3155,8 @@ shared_ptr<Lobby> create_game_generic(
|
||||
game->password = password;
|
||||
game->version = c->version();
|
||||
game->section_id = c->options.override_section_id >= 0
|
||||
? c->options.override_section_id : c->game_data.player()->disp.section_id;
|
||||
? c->options.override_section_id
|
||||
: c->game_data.player()->disp.section_id;
|
||||
game->episode = episode;
|
||||
game->mode = mode;
|
||||
game->difficulty = difficulty;
|
||||
@@ -3450,14 +3423,11 @@ static void on_6F(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
watched_lobby->ep3_server_base->server->send_commands_for_joining_spectator(c->channel);
|
||||
}
|
||||
|
||||
|
||||
// If there are more players to bring in, try to do so
|
||||
c->disconnect_hooks.erase(ADD_NEXT_CLIENT_DISCONNECT_HOOK_NAME);
|
||||
add_next_game_client(s, l);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_D0_V3_BB(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t, const string& data) {
|
||||
auto& cmd = check_size_t<SC_TradeItems_D0_D3>(data);
|
||||
@@ -3560,8 +3530,6 @@ static void on_D4_V3_BB(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
send_command(target_c, 0xD4, 0x00);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_EE_Ep3(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t flag, const string& data) {
|
||||
if (!(c->flags & Client::Flag::IS_EPISODE_3)) {
|
||||
@@ -3687,8 +3655,6 @@ static void on_EF_Ep3(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
send_card_auction_if_all_clients_ready(s, l);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_xxEA_BB(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
uint16_t command, uint32_t, const string&) {
|
||||
|
||||
@@ -3703,8 +3669,6 @@ static void on_xxEA_BB(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_02_P(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t, const string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
@@ -3773,13 +3737,13 @@ static void on_04_P(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
// On BB we can use colors and newlines should be \n; on PC we can't use
|
||||
// colors, the text is auto-word-wrapped, and newlines should be \r\n.
|
||||
const u16string& message = (c->flags & Client::Flag::IS_BB_PATCH)
|
||||
? s->bb_patch_server_message : s->pc_patch_server_message;
|
||||
? s->bb_patch_server_message
|
||||
: s->pc_patch_server_message;
|
||||
if (!message.empty()) {
|
||||
send_message_box(c, message.c_str());
|
||||
}
|
||||
|
||||
auto index = (c->flags & Client::Flag::IS_BB_PATCH) ?
|
||||
s->bb_patch_file_index : s->pc_patch_file_index;
|
||||
auto index = (c->flags & Client::Flag::IS_BB_PATCH) ? s->bb_patch_file_index : s->pc_patch_file_index;
|
||||
if (index.get()) {
|
||||
send_command(c, 0x0B, 0x00); // Start patch session; go to root directory
|
||||
|
||||
@@ -3851,10 +3815,8 @@ static void on_10_P(shared_ptr<ServerState>,
|
||||
send_command(c, 0x12, 0x00);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_ignored(shared_ptr<ServerState>, shared_ptr<Client>,
|
||||
uint16_t, uint32_t, const string&) { }
|
||||
uint16_t, uint32_t, const string&) {}
|
||||
|
||||
static void on_unimplemented_command(shared_ptr<ServerState>,
|
||||
shared_ptr<Client> c, uint16_t command, uint32_t flag, const string& data) {
|
||||
@@ -3863,8 +3825,6 @@ static void on_unimplemented_command(shared_ptr<ServerState>,
|
||||
throw invalid_argument("unimplemented command");
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef void (*on_command_t)(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t command, uint32_t flag, const string& data);
|
||||
|
||||
@@ -3872,6 +3832,7 @@ typedef void (*on_command_t)(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
// entries in this table cause on_unimplemented_command to be called, which
|
||||
// disconnects the client.
|
||||
static on_command_t handlers[0x100][6] = {
|
||||
// clang-format off
|
||||
// PATCH DC PC GC XB BB
|
||||
/* 00 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 01 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
@@ -4137,6 +4098,7 @@ static on_command_t handlers[0x100][6] = {
|
||||
/* FE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* FF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
// PATCH DC PC GC XB BB
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static void check_unlicensed_command(GameVersion version, uint8_t command) {
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include "Client.hh"
|
||||
#include "ServerState.hh"
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<Lobby> create_game_generic(
|
||||
std::shared_ptr<ServerState> s,
|
||||
std::shared_ptr<Client> c,
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <phosg/Strings.hh>
|
||||
#include <phosg/Random.hh>
|
||||
#include <phosg/Strings.hh>
|
||||
|
||||
#include "Client.hh"
|
||||
#include "Items.hh"
|
||||
#include "Lobby.hh"
|
||||
#include "Loggers.hh"
|
||||
#include "Map.hh"
|
||||
#include "Player.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "Player.hh"
|
||||
#include "SendCommands.hh"
|
||||
#include "StaticGameData.hh"
|
||||
#include "Text.hh"
|
||||
@@ -22,14 +22,10 @@ using namespace std;
|
||||
// The functions in this file are called when a client sends a game command
|
||||
// (60, 62, 6C, 6D, C9, or CB).
|
||||
|
||||
|
||||
|
||||
bool command_is_private(uint8_t command) {
|
||||
return (command == 0x62) || (command == 0x6D);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename CmdT>
|
||||
const CmdT& check_size_sc(
|
||||
const string& data,
|
||||
@@ -62,8 +58,6 @@ const CmdT& check_size_sc(
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const unordered_set<uint8_t> watcher_subcommands({
|
||||
0x07, // Symbol chat
|
||||
0x74, // Word select
|
||||
@@ -130,8 +124,6 @@ static void forward_subcommand(shared_ptr<Lobby> l, shared_ptr<Client> c,
|
||||
forward_subcommand(l, c, command, flag, data.data(), data.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_invalid(shared_ptr<ServerState>,
|
||||
shared_ptr<Lobby>, shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||
const string& data) {
|
||||
@@ -161,8 +153,6 @@ static void on_unimplemented(shared_ptr<ServerState>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void on_forward_check_size(shared_ptr<ServerState>,
|
||||
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||
const string& data) {
|
||||
@@ -229,8 +219,6 @@ static void on_forward_check_size_ep3_game(shared_ptr<ServerState>,
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Ep3 subcommands
|
||||
|
||||
@@ -268,8 +256,6 @@ static void on_ep3_battle_subs(shared_ptr<ServerState> s,
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Chat commands and the like
|
||||
|
||||
@@ -689,7 +675,6 @@ static void on_box_or_enemy_item_drop(shared_ptr<ServerState>,
|
||||
forward_subcommand(l, c, command, flag, data);
|
||||
}
|
||||
|
||||
|
||||
static void on_pick_up_item(shared_ptr<ServerState>,
|
||||
shared_ptr<Lobby> l, shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||
const string& data) {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "PSOProtocol.hh"
|
||||
#include "Client.hh"
|
||||
#include "Lobby.hh"
|
||||
#include "Client.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "ServerState.hh"
|
||||
|
||||
|
||||
|
||||
void on_subcommand(std::shared_ptr<ServerState> s,
|
||||
std::shared_ptr<Lobby> l, std::shared_ptr<Client> c, uint8_t command,
|
||||
uint8_t flag, const std::string& data);
|
||||
void on_subcommand(
|
||||
std::shared_ptr<ServerState> s, std::shared_ptr<Lobby> l,
|
||||
std::shared_ptr<Client> c, uint8_t command, uint8_t flag,
|
||||
const std::string& data);
|
||||
|
||||
bool subcommand_is_implemented(uint8_t which);
|
||||
|
||||
+9
-12
@@ -5,19 +5,17 @@
|
||||
#include <phosg/Time.hh>
|
||||
|
||||
#include "Loggers.hh"
|
||||
#include "Shell.hh"
|
||||
#include "Server.hh"
|
||||
#include "Shell.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
ReplaySession::Event::Event(Type type, uint64_t client_id, size_t line_num)
|
||||
: type(type),
|
||||
client_id(client_id),
|
||||
allow_size_disparity(false),
|
||||
complete(false),
|
||||
line_num(line_num) { }
|
||||
line_num(line_num) {}
|
||||
|
||||
string ReplaySession::Event::str() const {
|
||||
string ret;
|
||||
@@ -40,8 +38,6 @@ string ReplaySession::Event::str() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ReplaySession::Client::Client(
|
||||
ReplaySession* session, uint64_t id, uint16_t port, GameVersion version)
|
||||
: id(id),
|
||||
@@ -52,15 +48,13 @@ ReplaySession::Client::Client(
|
||||
&ReplaySession::dispatch_on_command_received,
|
||||
&ReplaySession::dispatch_on_error,
|
||||
session,
|
||||
string_printf("R-%" PRIX64, this->id)) { }
|
||||
string_printf("R-%" PRIX64, this->id)) {}
|
||||
|
||||
string ReplaySession::Client::str() const {
|
||||
return string_printf("Client[%" PRIu64 ", T-%hu, %s]",
|
||||
this->id, this->port, name_for_version(this->version));
|
||||
}
|
||||
|
||||
|
||||
|
||||
shared_ptr<ReplaySession::Event> ReplaySession::create_event(
|
||||
Event::Type type, shared_ptr<Client> c, size_t line_num) {
|
||||
shared_ptr<Event> event(new Event(type, c->id, line_num));
|
||||
@@ -242,10 +236,12 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
||||
uint8_t command;
|
||||
if (version == GameVersion::PC) {
|
||||
command = check_size_t<PSOCommandHeaderPC>(
|
||||
ev->data, sizeof(PSOCommandHeaderPC), 0xFFFF).command;
|
||||
ev->data, sizeof(PSOCommandHeaderPC), 0xFFFF)
|
||||
.command;
|
||||
} else { // V3
|
||||
command = check_size_t<PSOCommandHeaderDCV3>(
|
||||
ev->data, sizeof(PSOCommandHeaderDCV3), 0xFFFF).command;
|
||||
ev->data, sizeof(PSOCommandHeaderDCV3), 0xFFFF)
|
||||
.command;
|
||||
}
|
||||
switch (command) {
|
||||
case 0x02:
|
||||
@@ -335,7 +331,8 @@ void ReplaySession::apply_default_mask(shared_ptr<Event> ev) {
|
||||
}
|
||||
case GameVersion::BB: {
|
||||
uint16_t command = check_size_t<PSOCommandHeaderBB>(
|
||||
ev->data, sizeof(PSOCommandHeaderBB), 0xFFFF).command;
|
||||
ev->data, sizeof(PSOCommandHeaderBB), 0xFFFF)
|
||||
.command;
|
||||
switch (command) {
|
||||
case 0x0003: {
|
||||
auto& mask = check_size_t<S_ServerInitDefault_BB_03_9B>(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user