implement v1-encoding for v2 items
This commit is contained in:
+2
-2
@@ -1316,8 +1316,8 @@ static void proxy_command_item(shared_ptr<ProxyServer::LinkedSession> ses, const
|
|||||||
send_text_message(ses->client_channel, "$C7Next drop:\n" + name);
|
send_text_message(ses->client_channel, "$C7Next drop:\n" + name);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
send_drop_stacked_item(ses->client_channel, item, ses->area, ses->x, ses->z);
|
send_drop_stacked_item(s, ses->client_channel, item, ses->area, ses->x, ses->z);
|
||||||
send_drop_stacked_item(ses->server_channel, item, ses->area, ses->x, ses->z);
|
send_drop_stacked_item(s, ses->server_channel, item, ses->area, ses->x, ses->z);
|
||||||
|
|
||||||
string name = s->describe_item(ses->version(), item, true);
|
string name = s->describe_item(ses->version(), item, true);
|
||||||
send_text_message(ses->client_channel, "$C7Item created:\n" + name);
|
send_text_message(ses->client_channel, "$C7Item created:\n" + name);
|
||||||
|
|||||||
+177
-44
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "ItemParameterTable.hh"
|
||||||
#include "StaticGameData.hh"
|
#include "StaticGameData.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -279,61 +280,193 @@ void ItemData::add_mag_photon_blast(uint8_t pb_num) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemData::decode_if_mag(GameVersion from_version) {
|
void ItemData::decode_for_version(GameVersion from_version) {
|
||||||
if (this->data1[0] != 2) {
|
bool is_v2 = (from_version == GameVersion::DC) || (from_version == GameVersion::PC);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from_version == GameVersion::GC) {
|
uint8_t encoded_v2_data = this->get_encoded_v2_data();
|
||||||
// PSO GC erroneously byteswaps the data2d field, even though it's actually
|
bool should_decode_v2_data = is_v2 && (encoded_v2_data != 0x00) && this->has_encoded_v2_data();
|
||||||
// just four individual bytes, so we correct for that here.
|
|
||||||
this->data2d = bswap32(this->data2d);
|
|
||||||
|
|
||||||
} else if (from_version == GameVersion::DC || from_version == GameVersion::PC) {
|
switch (this->data1[0]) {
|
||||||
// PSO PC encodes mags in a tediously annoying manner. The first four bytes are the same, but then...
|
case 0x00:
|
||||||
// V2: pHHHHHHHHHHHHHHc pIIIIIIIIIIIIIIc JJJJJJJJJJJJJJJc KKKKKKKKKKKKKKKc QQQQQQQQ QQQQQQQQ YYYYYYYY pYYYYYYY
|
if (should_decode_v2_data) {
|
||||||
// V3: HHHHHHHHHHHHHHHH IIIIIIIIIIIIIIII JJJJJJJJJJJJJJJJ KKKKKKKKKKKKKKKK YYYYYYYY QQQQQQQQ PPPPPPPP CCCCCCCC
|
this->data1[5] = ((encoded_v2_data < 0x89) || (this->data1[1] == 0x0F)) ? 0x00 : this->data1[1];
|
||||||
// c = color in V2 (4 bits; low bit first)
|
this->data1[1] = encoded_v2_data;
|
||||||
// C = color in V3
|
}
|
||||||
// p = PB flag bits in V2 (3 bits; ordered 1, 2, 0)
|
break;
|
||||||
// P = PB flag bits in V3
|
|
||||||
// H, I, J, K = DEF, POW, DEX, MIND
|
|
||||||
// Q = IQ (little-endian in V2)
|
|
||||||
// Y = synchro (little-endian in V2)
|
|
||||||
|
|
||||||
// Order is important; data2[0] must not be written before data2w[0] is read
|
case 0x01:
|
||||||
this->data2[1] = this->data2w[0]; // IQ
|
if (should_decode_v2_data) {
|
||||||
this->data2[0] = this->data2w[1] & 0x7FFF; // Synchro
|
this->data1[3] = 0x00;
|
||||||
this->data2[2] = ((this->data2[3] >> 7) & 1) | ((this->data1w[2] >> 14) & 2) | ((this->data1w[3] >> 13) & 4); // PB flags
|
this->data1[2] = encoded_v2_data;
|
||||||
this->data2[3] = (this->data1w[2] & 1) | ((this->data1w[3] & 1) << 1) | ((this->data1w[4] & 1) << 2) | ((this->data1w[5] & 1) << 3); // Color
|
}
|
||||||
this->data1w[2] &= 0x7FFE;
|
break;
|
||||||
this->data1w[3] &= 0x7FFE;
|
|
||||||
this->data1w[4] &= 0xFFFE;
|
case 0x02:
|
||||||
this->data1w[5] &= 0xFFFE;
|
if (should_decode_v2_data) {
|
||||||
|
this->data1[2] = 0xC8;
|
||||||
|
this->data1[1] = encoded_v2_data + 0x2B;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from_version == GameVersion::GC) {
|
||||||
|
// PSO GC erroneously byteswaps the data2d field, even though it's actually
|
||||||
|
// just four individual bytes, so we correct for that here.
|
||||||
|
this->data2d = bswap32(this->data2d);
|
||||||
|
|
||||||
|
} else if (from_version == GameVersion::DC || from_version == GameVersion::PC) {
|
||||||
|
// PSO PC encodes mags in a tediously annoying manner. The first four bytes are the same, but then...
|
||||||
|
// V2: pHHHHHHHHHHHHHHc pIIIIIIIIIIIIIIc JJJJJJJJJJJJJJJc KKKKKKKKKKKKKKKc QQQQQQQQ QQQQQQQQ YYYYYYYY pYYYYYYY
|
||||||
|
// V3: HHHHHHHHHHHHHHHH IIIIIIIIIIIIIIII JJJJJJJJJJJJJJJJ KKKKKKKKKKKKKKKK YYYYYYYY QQQQQQQQ PPPPPPPP CCCCCCCC
|
||||||
|
// c = color in V2 (4 bits; low bit first)
|
||||||
|
// C = color in V3
|
||||||
|
// p = PB flag bits in V2 (3 bits; ordered 1, 2, 0)
|
||||||
|
// P = PB flag bits in V3
|
||||||
|
// H, I, J, K = DEF, POW, DEX, MIND
|
||||||
|
// Q = IQ (little-endian in V2)
|
||||||
|
// Y = synchro (little-endian in V2)
|
||||||
|
|
||||||
|
// Order is important; data2[0] must not be written before data2w[0] is read
|
||||||
|
this->data2[1] = this->data2w[0]; // IQ
|
||||||
|
this->data2[0] = this->data2w[1] & 0x7FFF; // Synchro
|
||||||
|
this->data2[2] = ((this->data2[3] >> 7) & 1) | ((this->data1w[2] >> 14) & 2) | ((this->data1w[3] >> 13) & 4); // PB flags
|
||||||
|
this->data2[3] = (this->data1w[2] & 1) | ((this->data1w[3] & 1) << 1) | ((this->data1w[4] & 1) << 2) | ((this->data1w[5] & 1) << 3); // Color
|
||||||
|
this->data1w[2] &= 0x7FFE;
|
||||||
|
this->data1w[3] &= 0x7FFE;
|
||||||
|
this->data1w[4] &= 0xFFFE;
|
||||||
|
this->data1w[5] &= 0xFFFE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x03:
|
||||||
|
if (should_decode_v2_data) {
|
||||||
|
this->data1[3] = 0x00;
|
||||||
|
if (this->data1[1] == 0x02) {
|
||||||
|
this->data1[2] = encoded_v2_data + 0x0E;
|
||||||
|
} else if (this->data1[1] == 0x0D) {
|
||||||
|
if (this->data1[2] == 0x06) {
|
||||||
|
this->data1[1] = 0x0E;
|
||||||
|
this->data1[2] = encoded_v2_data + -1;
|
||||||
|
} else if (this->data1[2] == 0x07) {
|
||||||
|
this->data1[1] = this->data1[6];
|
||||||
|
this->data1[2] = encoded_v2_data + -1;
|
||||||
|
this->data1[6] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x04:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw runtime_error("invalid item class");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemData::encode_if_mag(GameVersion to_version) {
|
void ItemData::encode_for_version(GameVersion to_version, shared_ptr<const ItemParameterTable> item_parameter_table) {
|
||||||
if (this->data1[0] != 2) {
|
bool is_v2 = (to_version == GameVersion::DC) || (to_version == GameVersion::PC);
|
||||||
return;
|
bool should_encode_v2_data = is_v2 && !this->has_encoded_v2_data();
|
||||||
}
|
|
||||||
|
|
||||||
// This function is the inverse of decode_v2_mag; see that function for a
|
switch (this->data1[0]) {
|
||||||
// description of what's going on here.
|
case 0x00:
|
||||||
if (to_version == GameVersion::GC) {
|
if (should_encode_v2_data && (this->data1[1] > 0x26)) {
|
||||||
this->data2d = bswap32(this->data2d);
|
if (this->data1[1] < 0x89) {
|
||||||
|
this->data1[5] = this->data1[1];
|
||||||
|
this->data1[1] = item_parameter_table->get_weapon_v1_replacement(this->data1[1]);
|
||||||
|
if (this->data1[1] == 0x00) {
|
||||||
|
this->data1[1] = 0x0F;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint8_t data1_5 = this->data1[5];
|
||||||
|
if (this->data1[1] > data1_5) {
|
||||||
|
this->data1[5] = this->data1[1];
|
||||||
|
this->data1[1] = (data1_5 != 0) ? data1_5 : 0x0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
} else if (to_version == GameVersion::DC || to_version == GameVersion::PC) {
|
case 0x01: {
|
||||||
this->data1w[2] = (this->data1w[2] & 0x7FFE) | ((this->data2[2] << 14) & 0x8000) | (this->data2[3] & 1);
|
static const array<uint8_t, 4> armor_limits = {0x00, 0x29, 0x27, 0x44};
|
||||||
this->data1w[3] = (this->data1w[3] & 0x7FFE) | ((this->data2[2] << 13) & 0x8000) | ((this->data2[3] >> 1) & 1);
|
if (should_encode_v2_data && (this->data1[2] >= armor_limits[this->data1[1]])) {
|
||||||
this->data1w[4] = (this->data1w[4] & 0xFFFE) | ((this->data2[3] >> 2) & 1);
|
this->data1[3] = this->data1[2];
|
||||||
this->data1w[5] = (this->data1w[5] & 0xFFFE) | ((this->data2[3] >> 3) & 1);
|
this->data1[2] = 0x00;
|
||||||
// Order is important; data2w[0] must not be written before data2[0] is read
|
}
|
||||||
this->data2w[1] = this->data2[0] | ((this->data2[2] << 15) & 0x8000);
|
break;
|
||||||
this->data2w[0] = this->data2[1];
|
}
|
||||||
|
|
||||||
|
case 0x02:
|
||||||
|
if (should_encode_v2_data && (this->data1[1] > 0x2B)) {
|
||||||
|
this->data1[2] = this->data1[1] - 0x2B - 0x38;
|
||||||
|
this->data1[1] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This logic is the inverse of the corresponding logic in
|
||||||
|
// decode_for_version; see that function for a description of what's
|
||||||
|
// going on here.
|
||||||
|
if (to_version == GameVersion::GC) {
|
||||||
|
this->data2d = bswap32(this->data2d);
|
||||||
|
} else if (to_version == GameVersion::DC || to_version == GameVersion::PC) {
|
||||||
|
this->data1w[2] = (this->data1w[2] & 0x7FFE) | ((this->data2[2] << 14) & 0x8000) | (this->data2[3] & 1);
|
||||||
|
this->data1w[3] = (this->data1w[3] & 0x7FFE) | ((this->data2[2] << 13) & 0x8000) | ((this->data2[3] >> 1) & 1);
|
||||||
|
this->data1w[4] = (this->data1w[4] & 0xFFFE) | ((this->data2[3] >> 2) & 1);
|
||||||
|
this->data1w[5] = (this->data1w[5] & 0xFFFE) | ((this->data2[3] >> 3) & 1);
|
||||||
|
// Order is important; data2w[0] must not be written before data2[0] is read
|
||||||
|
this->data2w[1] = this->data2[0] | ((this->data2[2] << 15) & 0x8000);
|
||||||
|
this->data2w[0] = this->data2[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x03:
|
||||||
|
if (should_encode_v2_data) {
|
||||||
|
if (this->data1[1] == 2) {
|
||||||
|
if (this->data1[2] > 0x0E) {
|
||||||
|
this->data1[3] = this->data1[2] - 0x0E;
|
||||||
|
this->data1[2] %= 0x0F;
|
||||||
|
}
|
||||||
|
} else if (this->data1[1] == 0x0E) {
|
||||||
|
this->data1[3] = this->data1[2] + 1;
|
||||||
|
this->data1[1] = 0x0D;
|
||||||
|
this->data1[2] = 0x06;
|
||||||
|
} else if (this->data1[1] > 0x0E) {
|
||||||
|
this->data1[6] = this->data1[1];
|
||||||
|
this->data1[3] = this->data1[2] + 0x01;
|
||||||
|
this->data1[1] = 0x0D;
|
||||||
|
this->data1[2] = 0x07;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x04:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw runtime_error("invalid item class");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t ItemData::get_encoded_v2_data() const {
|
||||||
|
switch (this->data1[0]) {
|
||||||
|
case 0x00:
|
||||||
|
return this->data1[5];
|
||||||
|
case 0x01:
|
||||||
|
case 0x03:
|
||||||
|
return this->data1[3];
|
||||||
|
case 0x02:
|
||||||
|
if (this->data1[2] > 0xC8) {
|
||||||
|
return this->data1[2] + 0x38;
|
||||||
|
}
|
||||||
|
return 0x00;
|
||||||
|
default:
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemData::has_encoded_v2_data() const {
|
||||||
|
return (this->data1[0] == 0)
|
||||||
|
? (this->data1[1] < this->get_encoded_v2_data())
|
||||||
|
: (this->get_encoded_v2_data() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t ItemData::get_sealed_item_kill_count() const {
|
uint16_t ItemData::get_sealed_item_kill_count() const {
|
||||||
return ((this->data1[10] << 8) | this->data1[11]) & 0x7FFF;
|
return ((this->data1[10] << 8) | this->data1[11]) & 0x7FFF;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
constexpr uint32_t MESETA_IDENTIFIER = 0x00040000;
|
constexpr uint32_t MESETA_IDENTIFIER = 0x00040000;
|
||||||
|
|
||||||
|
class ItemParameterTable;
|
||||||
|
|
||||||
struct ItemMagStats {
|
struct ItemMagStats {
|
||||||
uint16_t iq;
|
uint16_t iq;
|
||||||
uint16_t synchro;
|
uint16_t synchro;
|
||||||
@@ -86,7 +88,7 @@ struct ItemData { // 0x14 bytes
|
|||||||
// Related note: PSO V2 has an annoyingly complicated format for mags that
|
// Related note: PSO V2 has an annoyingly complicated format for mags that
|
||||||
// doesn't match the above table. We decode this upon receipt and encode it
|
// doesn't match the above table. We decode this upon receipt and encode it
|
||||||
// imemdiately before sending when interacting with V2 clients; see the
|
// imemdiately before sending when interacting with V2 clients; see the
|
||||||
// implementation of decode_if_mag() for details.
|
// implementation of decode_for_version() for details.
|
||||||
|
|
||||||
union {
|
union {
|
||||||
parray<uint8_t, 12> data1;
|
parray<uint8_t, 12> data1;
|
||||||
@@ -130,8 +132,10 @@ struct ItemData { // 0x14 bytes
|
|||||||
uint8_t mag_photon_blast_for_slot(uint8_t slot) const;
|
uint8_t mag_photon_blast_for_slot(uint8_t slot) const;
|
||||||
bool mag_has_photon_blast_in_any_slot(uint8_t pb_num) const;
|
bool mag_has_photon_blast_in_any_slot(uint8_t pb_num) const;
|
||||||
void add_mag_photon_blast(uint8_t pb_num);
|
void add_mag_photon_blast(uint8_t pb_num);
|
||||||
void decode_if_mag(GameVersion version);
|
void decode_for_version(GameVersion version);
|
||||||
void encode_if_mag(GameVersion version);
|
void encode_for_version(GameVersion version, std::shared_ptr<const ItemParameterTable> item_parameter_table);
|
||||||
|
uint8_t get_encoded_v2_data() const;
|
||||||
|
bool has_encoded_v2_data() const;
|
||||||
|
|
||||||
uint16_t get_sealed_item_kill_count() const;
|
uint16_t get_sealed_item_kill_count() const;
|
||||||
void set_sealed_item_kill_count(uint16_t v);
|
void set_sealed_item_kill_count(uint16_t v);
|
||||||
|
|||||||
@@ -566,6 +566,23 @@ uint8_t ItemParameterTable::get_max_tech_level(uint8_t char_class, uint8_t tech_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t ItemParameterTable::get_weapon_v1_replacement(uint8_t data1_1) const {
|
||||||
|
uint32_t offset;
|
||||||
|
if (this->offsets_v2) {
|
||||||
|
offset = this->offsets_v2->v1_replacement_table;
|
||||||
|
} else if (this->offsets_v3) {
|
||||||
|
offset = this->offsets_v3->v1_replacement_table;
|
||||||
|
} else if (this->offsets_v4) {
|
||||||
|
offset = this->offsets_v4->v1_replacement_table;
|
||||||
|
} else {
|
||||||
|
throw logic_error("table is not v2, v3, or v4");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (data1_1 < this->num_weapon_classes)
|
||||||
|
? this->r.pget_u8(offset + data1_1)
|
||||||
|
: 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ItemParameterTable::get_item_id(const ItemData& item) const {
|
uint32_t ItemParameterTable::get_item_id(const ItemData& item) const {
|
||||||
switch (item.data1[0]) {
|
switch (item.data1[0]) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -321,6 +321,7 @@ public:
|
|||||||
uint8_t get_special_stars(uint8_t det) const;
|
uint8_t get_special_stars(uint8_t det) const;
|
||||||
const Special<false>& get_special(uint8_t special) const;
|
const Special<false>& get_special(uint8_t special) const;
|
||||||
uint8_t get_max_tech_level(uint8_t char_class, uint8_t tech_num) const;
|
uint8_t get_max_tech_level(uint8_t char_class, uint8_t tech_num) const;
|
||||||
|
uint8_t get_weapon_v1_replacement(uint8_t data1_1) const;
|
||||||
|
|
||||||
uint32_t get_item_id(const ItemData& item) const;
|
uint32_t get_item_id(const ItemData& item) const;
|
||||||
uint8_t get_item_base_stars(const ItemData& item) const;
|
uint8_t get_item_base_stars(const ItemData& item) const;
|
||||||
@@ -353,7 +354,7 @@ private:
|
|||||||
/* 0C / 5A6C */ le_uint32_t unit_table; // -> {count, offset -> [UnitV2]} (last if out of range)
|
/* 0C / 5A6C */ le_uint32_t unit_table; // -> {count, offset -> [UnitV2]} (last if out of range)
|
||||||
/* 10 / 5A7C */ le_uint32_t tool_table; // -> [{count, offset -> [ToolV2]}](0x10) (last if out of range)
|
/* 10 / 5A7C */ le_uint32_t tool_table; // -> [{count, offset -> [ToolV2]}](0x10) (last if out of range)
|
||||||
/* 14 / 5A74 */ le_uint32_t mag_table; // -> {count, offset -> [MagV2]}
|
/* 14 / 5A74 */ le_uint32_t mag_table; // -> {count, offset -> [MagV2]}
|
||||||
/* 18 / 3DF8 */ le_uint32_t attack_animation_table; // -> [uint8_t](0x89)
|
/* 18 / 3DF8 */ le_uint32_t v1_replacement_table; // -> [uint8_t](0x89)
|
||||||
/* 1C / 2E4C */ le_uint32_t photon_color_table; // -> [0x24-byte structs](0x20)
|
/* 1C / 2E4C */ le_uint32_t photon_color_table; // -> [0x24-byte structs](0x20)
|
||||||
/* 20 / 32CC */ le_uint32_t weapon_range_table; // -> ???
|
/* 20 / 32CC */ le_uint32_t weapon_range_table; // -> ???
|
||||||
/* 24 / 3E84 */ le_uint32_t weapon_sale_divisor_table; // -> [float](0x89)
|
/* 24 / 3E84 */ le_uint32_t weapon_sale_divisor_table; // -> [float](0x89)
|
||||||
@@ -375,7 +376,7 @@ private:
|
|||||||
/* 08 / EFA0 / 1479C */ U32T unit_table; // -> {count, offset -> [UnitV3/UnitV4]} (last if out of range)
|
/* 08 / EFA0 / 1479C */ U32T unit_table; // -> {count, offset -> [UnitV3/UnitV4]} (last if out of range)
|
||||||
/* 0C / EFB0 / 147AC */ U32T tool_table; // -> [{count, offset -> [ToolV3/ToolV4]}](0x1A) (last if out of range)
|
/* 0C / EFB0 / 147AC */ U32T tool_table; // -> [{count, offset -> [ToolV3/ToolV4]}](0x1A) (last if out of range)
|
||||||
/* 10 / EFA8 / 147A4 */ U32T mag_table; // -> {count, offset -> [MagV3/MagV4]}
|
/* 10 / EFA8 / 147A4 */ U32T mag_table; // -> {count, offset -> [MagV3/MagV4]}
|
||||||
/* 14 / B88C / 0F4B8 */ U32T attack_animation_table; // -> [uint8_t](0xED)
|
/* 14 / B88C / 0F4B8 */ U32T v1_replacement_table; // -> [uint8_t](0xED)
|
||||||
/* 18 / A7FC / 0DE7C */ U32T photon_color_table; // -> [0x24-byte structs](0x20)
|
/* 18 / A7FC / 0DE7C */ U32T photon_color_table; // -> [0x24-byte structs](0x20)
|
||||||
/* 1C / AACC / 0E194 */ U32T weapon_range_table; // -> ???
|
/* 1C / AACC / 0E194 */ U32T weapon_range_table; // -> ???
|
||||||
/* 20 / B938 / 0F5A8 */ U32T weapon_sale_divisor_table; // -> [float](0xED)
|
/* 20 / B938 / 0F5A8 */ U32T weapon_sale_divisor_table; // -> [float](0xED)
|
||||||
|
|||||||
+46
-2
@@ -227,7 +227,7 @@ The actions are:\n\
|
|||||||
Print the name of the item given by DATA (in hex). DATA must not contain\n\
|
Print the name of the item given by DATA (in hex). DATA must not contain\n\
|
||||||
spaces. If DATA is 20 bytes, newserv assumes it contains an unused item ID\n\
|
spaces. If DATA is 20 bytes, newserv assumes it contains an unused item ID\n\
|
||||||
field; if it is fewer bytes, up to 16 bytes are used.\n\
|
field; if it is fewer bytes, up to 16 bytes are used.\n\
|
||||||
encode-item DESCRIPTION\n\
|
encode-item DESCRIPTION [--pc|--bb]\n\
|
||||||
Encode the description of an item into its corresponding ItemData (hex)\n\
|
Encode the description of an item into its corresponding ItemData (hex)\n\
|
||||||
representation. If DESCRIPTION contains spaces, it must be quoted, such as\n\
|
representation. If DESCRIPTION contains spaces, it must be quoted, such as\n\
|
||||||
\"L&K14 COMBAT +10 0/10/15/0/35\".\n\
|
\"L&K14 COMBAT +10 0/10/15/0/35\".\n\
|
||||||
@@ -1598,14 +1598,58 @@ int main(int argc, char** argv) {
|
|||||||
JSON::parse(load_file("system/item-tables/names-v2.json")),
|
JSON::parse(load_file("system/item-tables/names-v2.json")),
|
||||||
JSON::parse(load_file("system/item-tables/names-v3.json")),
|
JSON::parse(load_file("system/item-tables/names-v3.json")),
|
||||||
JSON::parse(load_file("system/item-tables/names-v4.json")));
|
JSON::parse(load_file("system/item-tables/names-v4.json")));
|
||||||
|
shared_ptr<string> pmt_data_v2(new string(prs_decompress(load_file("system/item-tables/ItemPMT-v2.prs"))));
|
||||||
|
auto pmt_v2 = make_shared<ItemParameterTable>(pmt_data_v2, ItemParameterTable::Version::V2);
|
||||||
|
shared_ptr<string> pmt_data_v3(new string(prs_decompress(load_file("system/item-tables/ItemPMT-gc.prs"))));
|
||||||
|
auto pmt_v3 = make_shared<ItemParameterTable>(pmt_data_v3, ItemParameterTable::Version::V3);
|
||||||
|
|
||||||
ItemData item = name_index->parse_item_description(cli_version, input_filename);
|
ItemData item = name_index->parse_item_description(cli_version, input_filename);
|
||||||
|
|
||||||
string desc = name_index->describe_item(cli_version, item);
|
string desc = name_index->describe_item(cli_version, item);
|
||||||
log_info("Data: %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX -------- %02hhX%02hhX%02hhX%02hhX",
|
log_info("Data (decoded): %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX -------- %02hhX%02hhX%02hhX%02hhX",
|
||||||
item.data1[0], item.data1[1], item.data1[2], item.data1[3],
|
item.data1[0], item.data1[1], item.data1[2], item.data1[3],
|
||||||
item.data1[4], item.data1[5], item.data1[6], item.data1[7],
|
item.data1[4], item.data1[5], item.data1[6], item.data1[7],
|
||||||
item.data1[8], item.data1[9], item.data1[10], item.data1[11],
|
item.data1[8], item.data1[9], item.data1[10], item.data1[11],
|
||||||
item.data2[0], item.data2[1], item.data2[2], item.data2[3]);
|
item.data2[0], item.data2[1], item.data2[2], item.data2[3]);
|
||||||
|
|
||||||
|
ItemData item_v1 = item;
|
||||||
|
item_v1.encode_for_version(GameVersion::PC, pmt_v2);
|
||||||
|
ItemData item_v1_decoded = item_v1;
|
||||||
|
item_v1_decoded.decode_for_version(GameVersion::PC);
|
||||||
|
|
||||||
|
log_info("Data (V1-encoded): %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX -------- %02hhX%02hhX%02hhX%02hhX",
|
||||||
|
item_v1.data1[0], item_v1.data1[1], item_v1.data1[2], item_v1.data1[3],
|
||||||
|
item_v1.data1[4], item_v1.data1[5], item_v1.data1[6], item_v1.data1[7],
|
||||||
|
item_v1.data1[8], item_v1.data1[9], item_v1.data1[10], item_v1.data1[11],
|
||||||
|
item_v1.data2[0], item_v1.data2[1], item_v1.data2[2], item_v1.data2[3]);
|
||||||
|
if (item_v1_decoded != item) {
|
||||||
|
log_warning("V1-decoded data does not match original data");
|
||||||
|
log_warning("Data (V1-decoded): %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX -------- %02hhX%02hhX%02hhX%02hhX",
|
||||||
|
item_v1_decoded.data1[0], item_v1_decoded.data1[1], item_v1_decoded.data1[2], item_v1_decoded.data1[3],
|
||||||
|
item_v1_decoded.data1[4], item_v1_decoded.data1[5], item_v1_decoded.data1[6], item_v1_decoded.data1[7],
|
||||||
|
item_v1_decoded.data1[8], item_v1_decoded.data1[9], item_v1_decoded.data1[10], item_v1_decoded.data1[11],
|
||||||
|
item_v1_decoded.data2[0], item_v1_decoded.data2[1], item_v1_decoded.data2[2], item_v1_decoded.data2[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData item_gc = item;
|
||||||
|
item_gc.encode_for_version(GameVersion::GC, pmt_v3);
|
||||||
|
ItemData item_gc_decoded = item_gc;
|
||||||
|
item_gc_decoded.decode_for_version(GameVersion::GC);
|
||||||
|
|
||||||
|
log_info("Data (GC-encoded): %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX -------- %02hhX%02hhX%02hhX%02hhX",
|
||||||
|
item_gc.data1[0], item_gc.data1[1], item_gc.data1[2], item_gc.data1[3],
|
||||||
|
item_gc.data1[4], item_gc.data1[5], item_gc.data1[6], item_gc.data1[7],
|
||||||
|
item_gc.data1[8], item_gc.data1[9], item_gc.data1[10], item_gc.data1[11],
|
||||||
|
item_gc.data2[0], item_gc.data2[1], item_gc.data2[2], item_gc.data2[3]);
|
||||||
|
if (item_gc_decoded != item) {
|
||||||
|
log_warning("GC-decoded data does not match original data");
|
||||||
|
log_warning("Data (GC-decoded): %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX -------- %02hhX%02hhX%02hhX%02hhX",
|
||||||
|
item_gc_decoded.data1[0], item_gc_decoded.data1[1], item_gc_decoded.data1[2], item_gc_decoded.data1[3],
|
||||||
|
item_gc_decoded.data1[4], item_gc_decoded.data1[5], item_gc_decoded.data1[6], item_gc_decoded.data1[7],
|
||||||
|
item_gc_decoded.data1[8], item_gc_decoded.data1[9], item_gc_decoded.data1[10], item_gc_decoded.data1[11],
|
||||||
|
item_gc_decoded.data2[0], item_gc_decoded.data2[1], item_gc_decoded.data2[2], item_gc_decoded.data2[3]);
|
||||||
|
}
|
||||||
|
|
||||||
log_info("Description: %s", desc.c_str());
|
log_info("Description: %s", desc.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "ItemData.hh"
|
#include "ItemData.hh"
|
||||||
|
#include "ItemParameterTable.hh"
|
||||||
#include "Loggers.hh"
|
#include "Loggers.hh"
|
||||||
#include "PSOEncryption.hh"
|
#include "PSOEncryption.hh"
|
||||||
#include "StaticGameData.hh"
|
#include "StaticGameData.hh"
|
||||||
@@ -566,15 +567,15 @@ size_t PlayerInventory::remove_all_items_of_type(uint8_t data1_0, int16_t data1_
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerInventory::decode_mags(GameVersion version) {
|
void PlayerInventory::decode_for_version(GameVersion version) {
|
||||||
for (size_t z = 0; z < this->items.size(); z++) {
|
for (size_t z = 0; z < this->items.size(); z++) {
|
||||||
this->items[z].data.decode_if_mag(version);
|
this->items[z].data.decode_for_version(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerInventory::encode_mags(GameVersion version) {
|
void PlayerInventory::encode_for_version(GameVersion version, shared_ptr<const ItemParameterTable> item_parameter_table) {
|
||||||
for (size_t z = 0; z < this->items.size(); z++) {
|
for (size_t z = 0; z < this->items.size(); z++) {
|
||||||
this->items[z].data.encode_if_mag(version);
|
this->items[z].data.encode_for_version(version, item_parameter_table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,7 +828,7 @@ static PlayerInventoryItem make_template_item(bool equipped, uint64_t first_data
|
|||||||
|
|
||||||
static PlayerInventoryItem v2_item(bool equipped, uint64_t first_data, uint64_t second_data) {
|
static PlayerInventoryItem v2_item(bool equipped, uint64_t first_data, uint64_t second_data) {
|
||||||
auto ret = make_template_item(equipped, first_data, second_data);
|
auto ret = make_template_item(equipped, first_data, second_data);
|
||||||
ret.data.decode_if_mag(GameVersion::PC);
|
ret.data.decode_for_version(GameVersion::PC);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
#include "Text.hh"
|
#include "Text.hh"
|
||||||
#include "Version.hh"
|
#include "Version.hh"
|
||||||
|
|
||||||
|
class ItemParameterTable;
|
||||||
|
|
||||||
extern FileContentsCache player_files_cache;
|
extern FileContentsCache player_files_cache;
|
||||||
|
|
||||||
// PSO V2 stored some extra data in the character structs in a format that I'm
|
// PSO V2 stored some extra data in the character structs in a format that I'm
|
||||||
@@ -79,8 +81,8 @@ struct PlayerInventory {
|
|||||||
|
|
||||||
size_t remove_all_items_of_type(uint8_t data0, int16_t data1 = -1);
|
size_t remove_all_items_of_type(uint8_t data0, int16_t data1 = -1);
|
||||||
|
|
||||||
void decode_mags(GameVersion version);
|
void decode_for_version(GameVersion version);
|
||||||
void encode_mags(GameVersion version);
|
void encode_for_version(GameVersion version, std::shared_ptr<const ItemParameterTable> item_parameter_table);
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct PlayerBank {
|
struct PlayerBank {
|
||||||
|
|||||||
@@ -877,6 +877,8 @@ static HandlerResult S_V3_BB_DA(shared_ptr<ProxyServer::LinkedSession> ses, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
static HandlerResult S_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string& data) {
|
static HandlerResult S_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string& data) {
|
||||||
|
auto s = ses->require_server_state();
|
||||||
|
|
||||||
if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) {
|
if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) {
|
||||||
if ((ses->version() == GameVersion::GC) && (data.size() >= 0x14)) {
|
if ((ses->version() == GameVersion::GC) && (data.size() >= 0x14)) {
|
||||||
if (static_cast<uint8_t>(data[0]) == 0xB6) {
|
if (static_cast<uint8_t>(data[0]) == 0xB6) {
|
||||||
@@ -963,8 +965,8 @@ static HandlerResult S_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
|
|||||||
const auto& cmd = check_size_t<G_StandardDropItemRequest_DC_6x60>(
|
const auto& cmd = check_size_t<G_StandardDropItemRequest_DC_6x60>(
|
||||||
data, sizeof(G_StandardDropItemRequest_PC_V3_BB_6x60));
|
data, sizeof(G_StandardDropItemRequest_PC_V3_BB_6x60));
|
||||||
ses->next_drop_item.id = ses->next_item_id++;
|
ses->next_drop_item.id = ses->next_item_id++;
|
||||||
send_drop_item(ses->server_channel, ses->next_drop_item, true, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
send_drop_item(s, ses->server_channel, ses->next_drop_item, true, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
||||||
send_drop_item(ses->client_channel, ses->next_drop_item, true, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
send_drop_item(s, ses->client_channel, ses->next_drop_item, true, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
||||||
ses->next_drop_item.clear();
|
ses->next_drop_item.clear();
|
||||||
return HandlerResult::Type::SUPPRESS;
|
return HandlerResult::Type::SUPPRESS;
|
||||||
|
|
||||||
@@ -975,8 +977,8 @@ static HandlerResult S_6x(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
|
|||||||
} else if ((static_cast<uint8_t>(data[0]) == 0xA2) && ses->next_drop_item.data1d[0] && (ses->version() != GameVersion::BB)) {
|
} else if ((static_cast<uint8_t>(data[0]) == 0xA2) && ses->next_drop_item.data1d[0] && (ses->version() != GameVersion::BB)) {
|
||||||
const auto& cmd = check_size_t<G_SpecializableItemDropRequest_6xA2>(data);
|
const auto& cmd = check_size_t<G_SpecializableItemDropRequest_6xA2>(data);
|
||||||
ses->next_drop_item.id = ses->next_item_id++;
|
ses->next_drop_item.id = ses->next_item_id++;
|
||||||
send_drop_item(ses->server_channel, ses->next_drop_item, false, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
send_drop_item(s, ses->server_channel, ses->next_drop_item, false, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
||||||
send_drop_item(ses->client_channel, ses->next_drop_item, false, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
send_drop_item(s, ses->client_channel, ses->next_drop_item, false, cmd.area, cmd.x, cmd.z, cmd.entity_id);
|
||||||
ses->next_drop_item.clear();
|
ses->next_drop_item.clear();
|
||||||
return HandlerResult::Type::SUPPRESS;
|
return HandlerResult::Type::SUPPRESS;
|
||||||
|
|
||||||
|
|||||||
@@ -2725,7 +2725,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
|
|||||||
default:
|
default:
|
||||||
throw logic_error("player data command not implemented for version");
|
throw logic_error("player data command not implemented for version");
|
||||||
}
|
}
|
||||||
player->inventory.decode_mags(c->version());
|
player->inventory.decode_for_version(c->version());
|
||||||
c->channel.language = player->inventory.language;
|
c->channel.language = player->inventory.language;
|
||||||
|
|
||||||
string name_str = player->disp.name.decode(c->language());
|
string name_str = player->disp.name.decode(c->language());
|
||||||
@@ -3752,7 +3752,7 @@ static void on_D0_V3_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
|||||||
c->game_data.pending_item_trade->other_client_id = cmd.target_client_id;
|
c->game_data.pending_item_trade->other_client_id = cmd.target_client_id;
|
||||||
for (size_t x = 0; x < cmd.item_count; x++) {
|
for (size_t x = 0; x < cmd.item_count; x++) {
|
||||||
auto& item = c->game_data.pending_item_trade->items.emplace_back(cmd.item_datas[x]);
|
auto& item = c->game_data.pending_item_trade->items.emplace_back(cmd.item_datas[x]);
|
||||||
item.decode_if_mag(c->version());
|
item.decode_for_version(c->version());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the other player has a pending trade as well, assume this is the second
|
// If the other player has a pending trade as well, assume this is the second
|
||||||
|
|||||||
+16
-12
@@ -222,7 +222,7 @@ static void on_sync_joining_player_item_state(shared_ptr<Client> c, uint8_t comm
|
|||||||
// NOTE: If we use this codepath for non-V3 in the future, we'll need to
|
// NOTE: If we use this codepath for non-V3 in the future, we'll need to
|
||||||
// change this hardcoded version. This only works because GC's mag
|
// change this hardcoded version. This only works because GC's mag
|
||||||
// encoding/decoding is symmetric (encode and decode do the same thing).
|
// encoding/decoding is symmetric (encode and decode do the same thing).
|
||||||
floor_items[z].item.decode_if_mag(GameVersion::GC);
|
floor_items[z].item.decode_for_version(GameVersion::GC);
|
||||||
}
|
}
|
||||||
|
|
||||||
string out_compressed_data = bc0_compress(decompressed);
|
string out_compressed_data = bc0_compress(decompressed);
|
||||||
@@ -289,7 +289,7 @@ static void on_sync_joining_player_disp_and_inventory(
|
|||||||
// NOTE: If we use this codepath for non-V3 in the future, we'll need to
|
// NOTE: If we use this codepath for non-V3 in the future, we'll need to
|
||||||
// change this hardcoded version. This only works because GC's mag
|
// change this hardcoded version. This only works because GC's mag
|
||||||
// encoding/decoding is symmetric (encode and decode do the same thing).
|
// encoding/decoding is symmetric (encode and decode do the same thing).
|
||||||
out_cmd.inventory.items[z].data.decode_if_mag(GameVersion::GC);
|
out_cmd.inventory.items[z].data.decode_for_version(GameVersion::GC);
|
||||||
}
|
}
|
||||||
send_command_t(target, command, flag, out_cmd);
|
send_command_t(target, command, flag, out_cmd);
|
||||||
}
|
}
|
||||||
@@ -712,16 +712,19 @@ void forward_subcommand_with_mag_transcode_t(shared_ptr<Client> c, uint8_t comma
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto l = c->require_lobby();
|
auto l = c->require_lobby();
|
||||||
|
auto s = c->require_server_state();
|
||||||
for (auto& other_c : l->clients) {
|
for (auto& other_c : l->clients) {
|
||||||
if (!other_c || other_c == c) {
|
if (!other_c || other_c == c) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CmdT out_cmd = cmd;
|
|
||||||
if (c->version() != other_c->version()) {
|
if (c->version() != other_c->version()) {
|
||||||
out_cmd.item_data.decode_if_mag(c->version());
|
CmdT out_cmd = cmd;
|
||||||
out_cmd.item_data.encode_if_mag(other_c->version());
|
out_cmd.item_data.decode_for_version(c->version());
|
||||||
|
out_cmd.item_data.encode_for_version(other_c->version(), s->item_parameter_table_for_version(other_c->version()));
|
||||||
|
send_command_t(other_c, command, flag, out_cmd);
|
||||||
|
} else {
|
||||||
|
send_command_t(other_c, command, flag, cmd);
|
||||||
}
|
}
|
||||||
send_command_t(other_c, command, flag, out_cmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,7 +745,7 @@ static void on_create_inventory_item_t(shared_ptr<Client> c, uint8_t command, ui
|
|||||||
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||||
auto p = c->game_data.player();
|
auto p = c->game_data.player();
|
||||||
ItemData item = cmd.item_data;
|
ItemData item = cmd.item_data;
|
||||||
item.decode_if_mag(c->version());
|
item.decode_for_version(c->version());
|
||||||
l->on_item_id_generated_externally(item.id);
|
l->on_item_id_generated_externally(item.id);
|
||||||
p->add_item(item);
|
p->add_item(item);
|
||||||
|
|
||||||
@@ -786,7 +789,7 @@ static void on_drop_partial_stack_t(shared_ptr<Client> c, uint8_t command, uint8
|
|||||||
// TODO: Should we delete anything from the inventory here? Does the client
|
// TODO: Should we delete anything from the inventory here? Does the client
|
||||||
// send an appropriate 6x29 alongside this?
|
// send an appropriate 6x29 alongside this?
|
||||||
ItemData item = cmd.item_data;
|
ItemData item = cmd.item_data;
|
||||||
item.decode_if_mag(c->version());
|
item.decode_for_version(c->version());
|
||||||
l->on_item_id_generated_externally(item.id);
|
l->on_item_id_generated_externally(item.id);
|
||||||
l->add_item(item, cmd.area, cmd.x, cmd.z);
|
l->add_item(item, cmd.area, cmd.x, cmd.z);
|
||||||
|
|
||||||
@@ -879,7 +882,7 @@ static void on_buy_shop_item(shared_ptr<Client> c, uint8_t command, uint8_t flag
|
|||||||
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||||
auto p = c->game_data.player();
|
auto p = c->game_data.player();
|
||||||
ItemData item = cmd.item_data;
|
ItemData item = cmd.item_data;
|
||||||
item.decode_if_mag(c->version());
|
item.decode_for_version(c->version());
|
||||||
l->on_item_id_generated_externally(item.id);
|
l->on_item_id_generated_externally(item.id);
|
||||||
p->add_item(item);
|
p->add_item(item);
|
||||||
|
|
||||||
@@ -908,6 +911,7 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, uint8_t command, u
|
|||||||
|
|
||||||
const auto& cmd = check_size_t<CmdT>(data, size);
|
const auto& cmd = check_size_t<CmdT>(data, size);
|
||||||
|
|
||||||
|
auto s = c->require_server_state();
|
||||||
auto l = c->require_lobby();
|
auto l = c->require_lobby();
|
||||||
if (!l->is_game() || (c->lobby_client_id != l->leader_id)) {
|
if (!l->is_game() || (c->lobby_client_id != l->leader_id)) {
|
||||||
return;
|
return;
|
||||||
@@ -918,7 +922,7 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, uint8_t command, u
|
|||||||
|
|
||||||
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
if (l->check_flag(Lobby::Flag::ITEM_TRACKING_ENABLED)) {
|
||||||
ItemData item = cmd.item.item;
|
ItemData item = cmd.item.item;
|
||||||
item.decode_if_mag(c->version());
|
item.decode_for_version(c->version());
|
||||||
l->on_item_id_generated_externally(item.id);
|
l->on_item_id_generated_externally(item.id);
|
||||||
l->add_item(item, cmd.item.area, cmd.item.x, cmd.item.z);
|
l->add_item(item, cmd.item.area, cmd.item.x, cmd.item.z);
|
||||||
|
|
||||||
@@ -938,8 +942,8 @@ static void on_box_or_enemy_item_drop_t(shared_ptr<Client> c, uint8_t command, u
|
|||||||
}
|
}
|
||||||
CmdT out_cmd = cmd;
|
CmdT out_cmd = cmd;
|
||||||
if (c->version() != lc->version()) {
|
if (c->version() != lc->version()) {
|
||||||
out_cmd.item.item.decode_if_mag(c->version());
|
out_cmd.item.item.decode_for_version(c->version());
|
||||||
out_cmd.item.item.encode_if_mag(lc->version());
|
out_cmd.item.item.encode_for_version(lc->version(), s->item_parameter_table_for_version(lc->version()));
|
||||||
}
|
}
|
||||||
send_command_t(lc, command, flag, out_cmd);
|
send_command_t(lc, command, flag, out_cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-17
@@ -1475,6 +1475,8 @@ static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l)
|
|||||||
throw runtime_error("lobby is not a spectator team");
|
throw runtime_error("lobby is not a spectator team");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto s = c->require_server_state();
|
||||||
|
|
||||||
S_JoinSpectatorTeam_GC_Ep3_E8 cmd;
|
S_JoinSpectatorTeam_GC_Ep3_E8 cmd;
|
||||||
|
|
||||||
cmd.variations.clear(0);
|
cmd.variations.clear(0);
|
||||||
@@ -1501,7 +1503,7 @@ static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l)
|
|||||||
p.lobby_data.client_id = wc->lobby_client_id;
|
p.lobby_data.client_id = wc->lobby_client_id;
|
||||||
p.lobby_data.name.encode(wc_p->disp.name.decode(wc_p->inventory.language), c->language());
|
p.lobby_data.name.encode(wc_p->disp.name.decode(wc_p->inventory.language), c->language());
|
||||||
p.inventory = wc_p->inventory;
|
p.inventory = wc_p->inventory;
|
||||||
p.inventory.encode_mags(c->version());
|
p.inventory.encode_for_version(c->version(), s->item_parameter_table_for_version(c->version()));
|
||||||
p.disp = wc_p->disp.to_dcpcv3(c->language(), p.inventory.language);
|
p.disp = wc_p->disp.to_dcpcv3(c->language(), p.inventory.language);
|
||||||
p.disp.enforce_lobby_join_limits(c->version());
|
p.disp.enforce_lobby_join_limits(c->version());
|
||||||
|
|
||||||
@@ -1539,7 +1541,7 @@ static void send_join_spectator_team(shared_ptr<Client> c, shared_ptr<Lobby> l)
|
|||||||
auto& p = cmd.players[client_id];
|
auto& p = cmd.players[client_id];
|
||||||
p.lobby_data = entry.lobby_data;
|
p.lobby_data = entry.lobby_data;
|
||||||
p.inventory = entry.inventory;
|
p.inventory = entry.inventory;
|
||||||
p.inventory.encode_mags(c->version());
|
p.inventory.encode_for_version(c->version(), s->item_parameter_table_for_version(c->version()));
|
||||||
p.disp = entry.disp;
|
p.disp = entry.disp;
|
||||||
p.disp.enforce_lobby_join_limits(c->version());
|
p.disp.enforce_lobby_join_limits(c->version());
|
||||||
|
|
||||||
@@ -1671,11 +1673,12 @@ void send_join_game(shared_ptr<Client> c, shared_ptr<Lobby> l) {
|
|||||||
if (c->config.check_flag(Client::Flag::IS_EPISODE_3)) {
|
if (c->config.check_flag(Client::Flag::IS_EPISODE_3)) {
|
||||||
S_JoinGame_GC_Ep3_64 cmd;
|
S_JoinGame_GC_Ep3_64 cmd;
|
||||||
size_t player_count = populate_v3_cmd(cmd);
|
size_t player_count = populate_v3_cmd(cmd);
|
||||||
|
auto s = c->require_server_state();
|
||||||
for (size_t x = 0; x < 4; x++) {
|
for (size_t x = 0; x < 4; x++) {
|
||||||
if (l->clients[x]) {
|
if (l->clients[x]) {
|
||||||
auto other_p = l->clients[x]->game_data.player();
|
auto other_p = l->clients[x]->game_data.player();
|
||||||
cmd.players_ep3[x].inventory = other_p->inventory;
|
cmd.players_ep3[x].inventory = other_p->inventory;
|
||||||
cmd.players_ep3[x].inventory.encode_mags(c->version());
|
cmd.players_ep3[x].inventory.encode_for_version(c->version(), s->item_parameter_table_for_version(c->version()));
|
||||||
cmd.players_ep3[x].disp = convert_player_disp_data<PlayerDispDataDCPCV3>(other_p->disp, c->language(), other_p->inventory.language);
|
cmd.players_ep3[x].disp = convert_player_disp_data<PlayerDispDataDCPCV3>(other_p->disp, c->language(), other_p->inventory.language);
|
||||||
cmd.players_ep3[x].disp.enforce_lobby_join_limits(c->version());
|
cmd.players_ep3[x].disp.enforce_lobby_join_limits(c->version());
|
||||||
}
|
}
|
||||||
@@ -1712,6 +1715,8 @@ void send_join_game(shared_ptr<Client> c, shared_ptr<Lobby> l) {
|
|||||||
|
|
||||||
template <typename LobbyDataT, typename DispDataT, typename RecordsT, bool UseLanguageMarkerInName>
|
template <typename LobbyDataT, typename DispDataT, typename RecordsT, bool UseLanguageMarkerInName>
|
||||||
void send_join_lobby_t(shared_ptr<Client> c, shared_ptr<Lobby> l, shared_ptr<Client> joining_client = nullptr) {
|
void send_join_lobby_t(shared_ptr<Client> c, shared_ptr<Lobby> l, shared_ptr<Client> joining_client = nullptr) {
|
||||||
|
auto s = c->require_server_state();
|
||||||
|
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
if (l->is_game()) {
|
if (l->is_game()) {
|
||||||
if (joining_client) {
|
if (joining_client) {
|
||||||
@@ -1789,7 +1794,7 @@ void send_join_lobby_t(shared_ptr<Client> c, shared_ptr<Lobby> l, shared_ptr<Cli
|
|||||||
e.lobby_data.name.encode(lp->disp.name.decode(lp->inventory.language), c->language());
|
e.lobby_data.name.encode(lp->disp.name.decode(lp->inventory.language), c->language());
|
||||||
}
|
}
|
||||||
e.inventory = lp->inventory;
|
e.inventory = lp->inventory;
|
||||||
e.inventory.encode_mags(c->version());
|
e.inventory.encode_for_version(c->version(), s->item_parameter_table_for_version(c->version()));
|
||||||
e.disp = convert_player_disp_data<DispDataT>(lp->disp, c->language(), lp->inventory.language);
|
e.disp = convert_player_disp_data<DispDataT>(lp->disp, c->language(), lp->inventory.language);
|
||||||
e.disp.enforce_lobby_join_limits(c->version());
|
e.disp.enforce_lobby_join_limits(c->version());
|
||||||
}
|
}
|
||||||
@@ -1826,6 +1831,8 @@ void send_join_lobby_dc_nte(shared_ptr<Client> c, shared_ptr<Lobby> l,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto s = c->require_server_state();
|
||||||
|
|
||||||
size_t used_entries = 0;
|
size_t used_entries = 0;
|
||||||
for (const auto& lc : lobby_clients) {
|
for (const auto& lc : lobby_clients) {
|
||||||
auto lp = lc->game_data.player();
|
auto lp = lc->game_data.player();
|
||||||
@@ -1835,7 +1842,7 @@ void send_join_lobby_dc_nte(shared_ptr<Client> c, shared_ptr<Lobby> l,
|
|||||||
e.lobby_data.client_id = lc->lobby_client_id;
|
e.lobby_data.client_id = lc->lobby_client_id;
|
||||||
e.lobby_data.name.encode(lp->disp.name.decode(lp->inventory.language), c->language());
|
e.lobby_data.name.encode(lp->disp.name.decode(lp->inventory.language), c->language());
|
||||||
e.inventory = lp->inventory;
|
e.inventory = lp->inventory;
|
||||||
e.inventory.encode_mags(c->version());
|
e.inventory.encode_for_version(c->version(), s->item_parameter_table_for_version(c->version()));
|
||||||
e.disp = convert_player_disp_data<PlayerDispDataDCPCV3>(lp->disp, c->language(), lp->inventory.language);
|
e.disp = convert_player_disp_data<PlayerDispDataDCPCV3>(lp->disp, c->language(), lp->inventory.language);
|
||||||
e.disp.enforce_lobby_join_limits(c->version());
|
e.disp.enforce_lobby_join_limits(c->version());
|
||||||
}
|
}
|
||||||
@@ -1939,6 +1946,8 @@ void send_get_player_info(shared_ptr<Client> c) {
|
|||||||
// Trade window
|
// Trade window
|
||||||
|
|
||||||
void send_execute_item_trade(shared_ptr<Client> c, const vector<ItemData>& items) {
|
void send_execute_item_trade(shared_ptr<Client> c, const vector<ItemData>& items) {
|
||||||
|
auto s = c->require_server_state();
|
||||||
|
|
||||||
SC_TradeItems_D0_D3 cmd;
|
SC_TradeItems_D0_D3 cmd;
|
||||||
if (items.size() > cmd.item_datas.size()) {
|
if (items.size() > cmd.item_datas.size()) {
|
||||||
throw logic_error("too many items in execute trade command");
|
throw logic_error("too many items in execute trade command");
|
||||||
@@ -1947,7 +1956,7 @@ void send_execute_item_trade(shared_ptr<Client> c, const vector<ItemData>& items
|
|||||||
cmd.item_count = items.size();
|
cmd.item_count = items.size();
|
||||||
for (size_t x = 0; x < items.size(); x++) {
|
for (size_t x = 0; x < items.size(); x++) {
|
||||||
cmd.item_datas[x] = items[x];
|
cmd.item_datas[x] = items[x];
|
||||||
cmd.item_datas[x].encode_if_mag(c->version());
|
cmd.item_datas[x].encode_for_version(c->version(), s->item_parameter_table_for_version(c->version()));
|
||||||
}
|
}
|
||||||
send_command_t(c, 0xD3, 0x00, cmd);
|
send_command_t(c, 0xD3, 0x00, cmd);
|
||||||
}
|
}
|
||||||
@@ -2072,39 +2081,38 @@ void send_set_player_visibility(shared_ptr<Lobby> l, shared_ptr<Client> c,
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BB game commands
|
// BB game commands
|
||||||
|
|
||||||
void send_drop_item(Channel& ch, const ItemData& item,
|
void send_drop_item(shared_ptr<ServerState> s, Channel& ch, const ItemData& item,
|
||||||
bool from_enemy, uint8_t area, float x, float z, uint16_t entity_id) {
|
bool from_enemy, uint8_t area, float x, float z, uint16_t entity_id) {
|
||||||
G_DropItem_PC_V3_BB_6x5F cmd = {
|
G_DropItem_PC_V3_BB_6x5F cmd = {
|
||||||
{{0x5F, 0x0B, 0x0000}, {area, from_enemy, entity_id, x, z, 0, 0, item}}, 0};
|
{{0x5F, 0x0B, 0x0000}, {area, from_enemy, entity_id, x, z, 0, 0, item}}, 0};
|
||||||
cmd.item.item.encode_if_mag(ch.version);
|
cmd.item.item.encode_for_version(ch.version, s->item_parameter_table_for_version(ch.version));
|
||||||
ch.send(0x60, 0x00, &cmd, sizeof(cmd));
|
ch.send(0x60, 0x00, &cmd, sizeof(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_drop_item(shared_ptr<Lobby> l, const ItemData& item,
|
void send_drop_item(shared_ptr<Lobby> l, const ItemData& item,
|
||||||
bool from_enemy, uint8_t area, float x, float z, uint16_t entity_id) {
|
bool from_enemy, uint8_t area, float x, float z, uint16_t entity_id) {
|
||||||
|
auto s = l->require_server_state();
|
||||||
for (auto& c : l->clients) {
|
for (auto& c : l->clients) {
|
||||||
if (!c) {
|
if (!c) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
send_drop_item(c->channel, item, from_enemy, area, x, z, entity_id);
|
send_drop_item(s, c->channel, item, from_enemy, area, x, z, entity_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_drop_stacked_item(Channel& ch, const ItemData& item,
|
void send_drop_stacked_item(shared_ptr<ServerState> s, Channel& ch, const ItemData& item, uint8_t area, float x, float z) {
|
||||||
uint8_t area, float x, float z) {
|
G_DropStackedItem_PC_V3_BB_6x5D cmd = {{{0x5D, 0x0A, 0x0000}, area, 0, x, z, item}, 0};
|
||||||
G_DropStackedItem_PC_V3_BB_6x5D cmd = {
|
cmd.item_data.encode_for_version(ch.version, s->item_parameter_table_for_version(ch.version));
|
||||||
{{0x5D, 0x0A, 0x0000}, area, 0, x, z, item}, 0};
|
|
||||||
cmd.item_data.encode_if_mag(ch.version);
|
|
||||||
ch.send(0x60, 0x00, &cmd, sizeof(cmd));
|
ch.send(0x60, 0x00, &cmd, sizeof(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_drop_stacked_item(shared_ptr<Lobby> l, const ItemData& item,
|
void send_drop_stacked_item(shared_ptr<Lobby> l, const ItemData& item, uint8_t area, float x, float z) {
|
||||||
uint8_t area, float x, float z) {
|
auto s = l->require_server_state();
|
||||||
for (auto& c : l->clients) {
|
for (auto& c : l->clients) {
|
||||||
if (!c) {
|
if (!c) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
send_drop_stacked_item(c->channel, item, area, x, z);
|
send_drop_stacked_item(s, c->channel, item, area, x, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -292,11 +292,11 @@ void send_ep3_change_music(Channel& ch, uint32_t song);
|
|||||||
void send_set_player_visibility(std::shared_ptr<Client> c, bool visible);
|
void send_set_player_visibility(std::shared_ptr<Client> c, bool visible);
|
||||||
void send_revive_player(std::shared_ptr<Client> c);
|
void send_revive_player(std::shared_ptr<Client> c);
|
||||||
|
|
||||||
void send_drop_item(Channel& ch, const ItemData& item,
|
void send_drop_item(std::shared_ptr<ServerState> s, Channel& ch, const ItemData& item,
|
||||||
bool from_enemy, uint8_t area, float x, float z, uint16_t request_id);
|
bool from_enemy, uint8_t area, float x, float z, uint16_t request_id);
|
||||||
void send_drop_item(std::shared_ptr<Lobby> l, const ItemData& item,
|
void send_drop_item(std::shared_ptr<Lobby> l, const ItemData& item,
|
||||||
bool from_enemy, uint8_t area, float x, float z, uint16_t request_id);
|
bool from_enemy, uint8_t area, float x, float z, uint16_t request_id);
|
||||||
void send_drop_stacked_item(Channel& ch, const ItemData& item,
|
void send_drop_stacked_item(std::shared_ptr<ServerState> s, Channel& ch, const ItemData& item,
|
||||||
uint8_t area, float x, float z);
|
uint8_t area, float x, float z);
|
||||||
void send_drop_stacked_item(std::shared_ptr<Lobby> l, const ItemData& item,
|
void send_drop_stacked_item(std::shared_ptr<Lobby> l, const ItemData& item,
|
||||||
uint8_t area, float x, float z);
|
uint8_t area, float x, float z);
|
||||||
|
|||||||
+68
-69
@@ -627,17 +627,17 @@ Proxy session commands:\n\
|
|||||||
}
|
}
|
||||||
data.resize((data.size() + 3) & (~3));
|
data.resize((data.size() + 3) & (~3));
|
||||||
|
|
||||||
shared_ptr<ProxyServer::LinkedSession> proxy_session;
|
shared_ptr<ProxyServer::LinkedSession> ses;
|
||||||
try {
|
try {
|
||||||
proxy_session = this->get_proxy_session(session_name);
|
ses = this->get_proxy_session(session_name);
|
||||||
} catch (const exception&) {
|
} catch (const exception&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxy_session.get()) {
|
if (ses.get()) {
|
||||||
if (command_name[1] == 's') {
|
if (command_name[1] == 's') {
|
||||||
proxy_session->server_channel.send(data);
|
ses->server_channel.send(data);
|
||||||
} else {
|
} else {
|
||||||
proxy_session->client_channel.send(data);
|
ses->client_channel.send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -645,8 +645,7 @@ Proxy session commands:\n\
|
|||||||
if (session_name.empty()) {
|
if (session_name.empty()) {
|
||||||
c = this->state->game_server->get_client();
|
c = this->state->game_server->get_client();
|
||||||
} else {
|
} else {
|
||||||
auto clients = this->state->game_server->get_clients_by_identifier(
|
auto clients = this->state->game_server->get_clients_by_identifier(session_name);
|
||||||
session_name);
|
|
||||||
if (clients.empty()) {
|
if (clients.empty()) {
|
||||||
throw runtime_error("no such client");
|
throw runtime_error("no such client");
|
||||||
}
|
}
|
||||||
@@ -668,9 +667,9 @@ Proxy session commands:\n\
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (command_name == "show-slots") {
|
} else if (command_name == "show-slots") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
for (size_t z = 0; z < session->lobby_players.size(); z++) {
|
for (size_t z = 0; z < ses->lobby_players.size(); z++) {
|
||||||
const auto& player = session->lobby_players[z];
|
const auto& player = ses->lobby_players[z];
|
||||||
if (player.guild_card_number) {
|
if (player.guild_card_number) {
|
||||||
auto secid_name = name_for_section_id(player.section_id);
|
auto secid_name = name_for_section_id(player.section_id);
|
||||||
fprintf(stderr, " %zu: %" PRIu32 " => %s (%c, %s, %s)\n",
|
fprintf(stderr, " %zu: %" PRIu32 " => %s (%c, %s, %s)\n",
|
||||||
@@ -683,11 +682,11 @@ Proxy session commands:\n\
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if ((command_name == "c") || (command_name == "chat") || (command_name == "dchat")) {
|
} else if ((command_name == "c") || (command_name == "chat") || (command_name == "dchat")) {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
bool is_dchat = (command_name == "dchat");
|
bool is_dchat = (command_name == "dchat");
|
||||||
|
|
||||||
if (!is_dchat && (session->version() == GameVersion::PC || session->version() == GameVersion::BB)) {
|
if (!is_dchat && (ses->version() == GameVersion::PC || ses->version() == GameVersion::BB)) {
|
||||||
send_chat_message_from_client(session->server_channel, command_args, 0);
|
send_chat_message_from_client(ses->server_channel, command_args, 0);
|
||||||
} else {
|
} else {
|
||||||
string data(8, '\0');
|
string data(8, '\0');
|
||||||
data.push_back('\x09');
|
data.push_back('\x09');
|
||||||
@@ -699,13 +698,13 @@ Proxy session commands:\n\
|
|||||||
data.push_back('\0');
|
data.push_back('\0');
|
||||||
}
|
}
|
||||||
data.resize((data.size() + 3) & (~3));
|
data.resize((data.size() + 3) & (~3));
|
||||||
session->server_channel.send(0x06, 0x00, data);
|
ses->server_channel.send(0x06, 0x00, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ((command_name == "wc") || (command_name == "wchat")) {
|
} else if ((command_name == "wc") || (command_name == "wchat")) {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
if ((session->version() != GameVersion::GC) ||
|
if ((ses->version() != GameVersion::GC) ||
|
||||||
!session->config.check_flag(Client::Flag::IS_EPISODE_3)) {
|
!ses->config.check_flag(Client::Flag::IS_EPISODE_3)) {
|
||||||
throw runtime_error("wchat can only be used on Episode 3");
|
throw runtime_error("wchat can only be used on Episode 3");
|
||||||
}
|
}
|
||||||
string data(8, '\0');
|
string data(8, '\0');
|
||||||
@@ -715,27 +714,27 @@ Proxy session commands:\n\
|
|||||||
data += command_args;
|
data += command_args;
|
||||||
data.push_back('\0');
|
data.push_back('\0');
|
||||||
data.resize((data.size() + 3) & (~3));
|
data.resize((data.size() + 3) & (~3));
|
||||||
session->server_channel.send(0x06, 0x00, data);
|
ses->server_channel.send(0x06, 0x00, data);
|
||||||
|
|
||||||
} else if (command_name == "marker") {
|
} else if (command_name == "marker") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
session->server_channel.send(0x89, stoul(command_args));
|
ses->server_channel.send(0x89, stoul(command_args));
|
||||||
|
|
||||||
} else if ((command_name == "warp") || (command_name == "warpme")) {
|
} else if ((command_name == "warp") || (command_name == "warpme")) {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
|
|
||||||
uint8_t area = stoul(command_args);
|
uint8_t area = stoul(command_args);
|
||||||
send_warp(session->client_channel, session->lobby_client_id, area, true);
|
send_warp(ses->client_channel, ses->lobby_client_id, area, true);
|
||||||
|
|
||||||
} else if (command_name == "warpall") {
|
} else if (command_name == "warpall") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
|
|
||||||
uint8_t area = stoul(command_args);
|
uint8_t area = stoul(command_args);
|
||||||
send_warp(session->client_channel, session->lobby_client_id, area, false);
|
send_warp(ses->client_channel, ses->lobby_client_id, area, false);
|
||||||
send_warp(session->server_channel, session->lobby_client_id, area, false);
|
send_warp(ses->server_channel, ses->lobby_client_id, area, false);
|
||||||
|
|
||||||
} else if ((command_name == "info-board") || (command_name == "info-board-data")) {
|
} else if ((command_name == "info-board") || (command_name == "info-board-data")) {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
|
|
||||||
string data;
|
string data;
|
||||||
if (command_name == "info-board-data") {
|
if (command_name == "info-board-data") {
|
||||||
@@ -746,98 +745,98 @@ Proxy session commands:\n\
|
|||||||
data.push_back('\0');
|
data.push_back('\0');
|
||||||
data.resize((data.size() + 3) & (~3));
|
data.resize((data.size() + 3) & (~3));
|
||||||
|
|
||||||
session->server_channel.send(0xD9, 0x00, data);
|
ses->server_channel.send(0xD9, 0x00, data);
|
||||||
|
|
||||||
} else if (command_name == "set-override-section-id") {
|
} else if (command_name == "set-override-section-id") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
if (command_args.empty()) {
|
if (command_args.empty()) {
|
||||||
session->config.override_section_id = 0xFF;
|
ses->config.override_section_id = 0xFF;
|
||||||
} else {
|
} else {
|
||||||
session->config.override_section_id = section_id_for_name(command_args);
|
ses->config.override_section_id = section_id_for_name(command_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (command_name == "set-override-event") {
|
} else if (command_name == "set-override-event") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
if (command_args.empty()) {
|
if (command_args.empty()) {
|
||||||
session->config.override_lobby_event = 0xFF;
|
ses->config.override_lobby_event = 0xFF;
|
||||||
} else {
|
} else {
|
||||||
session->config.override_lobby_event = event_for_name(command_args);
|
ses->config.override_lobby_event = event_for_name(command_args);
|
||||||
if ((session->version() != GameVersion::DC) &&
|
if ((ses->version() != GameVersion::DC) &&
|
||||||
(session->version() != GameVersion::PC) &&
|
(ses->version() != GameVersion::PC) &&
|
||||||
!((session->version() == GameVersion::GC) && session->config.check_flag(Client::Flag::IS_GC_TRIAL_EDITION))) {
|
!((ses->version() == GameVersion::GC) && ses->config.check_flag(Client::Flag::IS_GC_TRIAL_EDITION))) {
|
||||||
session->client_channel.send(0xDA, session->config.override_lobby_event);
|
ses->client_channel.send(0xDA, ses->config.override_lobby_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (command_name == "set-override-lobby-number") {
|
} else if (command_name == "set-override-lobby-number") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
if (command_args.empty()) {
|
if (command_args.empty()) {
|
||||||
session->config.override_lobby_number = 0x80;
|
ses->config.override_lobby_number = 0x80;
|
||||||
} else {
|
} else {
|
||||||
session->config.override_lobby_number = lobby_type_for_name(command_args);
|
ses->config.override_lobby_number = lobby_type_for_name(command_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (command_name == "set-challenge-rank-title") {
|
} else if (command_name == "set-challenge-rank-title") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
session->challenge_rank_title_override = command_args;
|
ses->challenge_rank_title_override = command_args;
|
||||||
|
|
||||||
} else if (command_name == "set-challenge-rank-color") {
|
} else if (command_name == "set-challenge-rank-color") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
session->challenge_rank_color_override = stoul(command_args, nullptr, 16);
|
ses->challenge_rank_color_override = stoul(command_args, nullptr, 16);
|
||||||
|
|
||||||
} else if (command_name == "set-chat-filter") {
|
} else if (command_name == "set-chat-filter") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
set_flag(session->config, Client::Flag::PROXY_CHAT_FILTER_ENABLED, command_args);
|
set_flag(ses->config, Client::Flag::PROXY_CHAT_FILTER_ENABLED, command_args);
|
||||||
|
|
||||||
} else if (command_name == "set-infinite-hp") {
|
} else if (command_name == "set-infinite-hp") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
set_flag(session->config, Client::Flag::INFINITE_HP_ENABLED, command_args);
|
set_flag(ses->config, Client::Flag::INFINITE_HP_ENABLED, command_args);
|
||||||
|
|
||||||
} else if (command_name == "set-infinite-tp") {
|
} else if (command_name == "set-infinite-tp") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
set_flag(session->config, Client::Flag::INFINITE_TP_ENABLED, command_args);
|
set_flag(ses->config, Client::Flag::INFINITE_TP_ENABLED, command_args);
|
||||||
|
|
||||||
} else if (command_name == "set-switch-assist") {
|
} else if (command_name == "set-switch-assist") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
set_flag(session->config, Client::Flag::SWITCH_ASSIST_ENABLED, command_args);
|
set_flag(ses->config, Client::Flag::SWITCH_ASSIST_ENABLED, command_args);
|
||||||
|
|
||||||
} else if (command_name == "set-save-files" && this->state->proxy_allow_save_files) {
|
} else if (command_name == "set-save-files" && this->state->proxy_allow_save_files) {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
set_flag(session->config, Client::Flag::PROXY_SAVE_FILES, command_args);
|
set_flag(ses->config, Client::Flag::PROXY_SAVE_FILES, command_args);
|
||||||
|
|
||||||
} else if (command_name == "set-block-function-calls") {
|
} else if (command_name == "set-block-function-calls") {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
set_flag(session->config, Client::Flag::PROXY_BLOCK_FUNCTION_CALLS, command_args);
|
set_flag(ses->config, Client::Flag::PROXY_BLOCK_FUNCTION_CALLS, command_args);
|
||||||
|
|
||||||
} else if ((command_name == "create-item") || (command_name == "set-next-item")) {
|
} else if ((command_name == "create-item") || (command_name == "set-next-item")) {
|
||||||
auto session = this->get_proxy_session(session_name);
|
auto ses = this->get_proxy_session(session_name);
|
||||||
|
|
||||||
if (session->version() == GameVersion::BB) {
|
if (ses->version() == GameVersion::BB) {
|
||||||
throw runtime_error("proxy session is BB");
|
throw runtime_error("proxy session is BB");
|
||||||
}
|
}
|
||||||
if (!session->is_in_game) {
|
if (!ses->is_in_game) {
|
||||||
throw runtime_error("proxy session is not in a game");
|
throw runtime_error("proxy session is not in a game");
|
||||||
}
|
}
|
||||||
if (session->lobby_client_id != session->leader_client_id) {
|
if (ses->lobby_client_id != ses->leader_client_id) {
|
||||||
throw runtime_error("proxy session is not game leader");
|
throw runtime_error("proxy session is not game leader");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s = session->require_server_state();
|
auto s = ses->require_server_state();
|
||||||
ItemData item = s->item_name_index->parse_item_description(session->version(), command_args);
|
ItemData item = s->item_name_index->parse_item_description(ses->version(), command_args);
|
||||||
item.id = random_object<uint32_t>();
|
item.id = random_object<uint32_t>();
|
||||||
|
|
||||||
if (command_name == "set-next-item") {
|
if (command_name == "set-next-item") {
|
||||||
session->next_drop_item = item;
|
ses->next_drop_item = item;
|
||||||
|
|
||||||
string name = s->describe_item(session->version(), session->next_drop_item, true);
|
string name = s->describe_item(ses->version(), ses->next_drop_item, true);
|
||||||
send_text_message(session->client_channel, "$C7Next drop:\n" + name);
|
send_text_message(ses->client_channel, "$C7Next drop:\n" + name);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
send_drop_stacked_item(session->client_channel, item, session->area, session->x, session->z);
|
send_drop_stacked_item(s, ses->client_channel, item, ses->area, ses->x, ses->z);
|
||||||
send_drop_stacked_item(session->server_channel, item, session->area, session->x, session->z);
|
send_drop_stacked_item(s, ses->server_channel, item, ses->area, ses->x, ses->z);
|
||||||
|
|
||||||
string name = s->describe_item(session->version(), session->next_drop_item, true);
|
string name = s->describe_item(ses->version(), ses->next_drop_item, true);
|
||||||
send_text_message(session->client_channel, "$C7Item created:\n" + name);
|
send_text_message(ses->client_channel, "$C7Item created:\n" + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (command_name == "close-idle-sessions") {
|
} else if (command_name == "close-idle-sessions") {
|
||||||
|
|||||||
Reference in New Issue
Block a user