完善客户端功能并同步差距文档

This commit is contained in:
shenlei
2026-09-03 18:40:01 +09:00
parent f93a172296
commit 13ccb8d02d
135 changed files with 21881 additions and 1259 deletions
+17 -3
View File
@@ -271,6 +271,9 @@ bool ClassicParser::on_gc(uint8_t header, const uint8_t *body, uint32_t len) {
(float)p.z, p.angle, p.moving_speed, p.attack_speed);
m_world.mut_char_info(p.vid, {}, p.parts, p.empire, (int32_t)p.guild, 0,
p.alignment, p.pk_mode, p.mount_vnum);
// §2.5 (W1↔W2 G1 wiring): affect flags travel in their own two-word
// segment, not through mut_char_info.
m_world.mut_affect_flags(p.vid, p.affect_flag[0], p.affect_flag[1]);
return true;
}
case HDR_GC_CHARACTER_DEL: { // 2
@@ -286,9 +289,11 @@ bool ClassicParser::on_gc(uint8_t header, const uint8_t *body, uint32_t len) {
if (!fill(p, header, body, len)) {
return false;
}
// classic wire heading: deg = bRot * 5 (client NetStream Send/Recv Move)
// classic wire heading: deg = bRot * 5 (client NetStream Send/Recv Move).
// §3.2: p.arg is the motion index, p.time the server command time that
// gates when the queued state command is released.
m_world.mut_move(p.vid, (float)p.rot * 5.0f, p.func, (float)p.x, (float)p.y,
p.duration);
p.duration, p.arg, p.time);
return true;
}
case HDR_GC_CHARACTER_POINTS: { // 16
@@ -367,6 +372,8 @@ bool ClassicParser::on_gc(uint8_t header, const uint8_t *body, uint32_t len) {
}
m_world.mut_char_update(p.vid, p.parts, p.moving_speed, p.attack_speed,
(int32_t)p.guild_id, p.alignment, p.pk_mode, p.mount_vnum);
// §2.5 (W1↔W2 G1 wiring): mut_char_update carries no affect segment.
m_world.mut_affect_flags(p.vid, p.affect_flag[0], p.affect_flag[1]);
return true;
}
case HDR_GC_CHARACTER_POSITION: { // 43
@@ -687,9 +694,16 @@ bool ClassicParser::on_gc(uint8_t header, const uint8_t *body, uint32_t len) {
m_world.mut_exchange_start(p.arg1);
break;
case EXCHANGE_GC_ITEM_ADD:
{
ItemAttr attrs[ITEM_ATTRIBUTE_MAX_NUM]{};
for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i) {
attrs[i].type = p.attrs[i].type;
attrs[i].value = p.attrs[i].value;
}
m_world.mut_exchange_item(self, static_cast<uint8_t>(p.arg2.cell), p.arg1,
static_cast<uint8_t>(p.arg3));
static_cast<uint8_t>(p.arg3), p.sockets, attrs);
break;
}
case EXCHANGE_GC_ITEM_DEL:
m_world.mut_exchange_item_del(self, static_cast<uint8_t>(p.arg1));
break;
@@ -301,6 +301,10 @@ void ClassicSession::pump() {
set_stage(Stage::Failed);
}
}
// §3.2 — feed the server frame clock (from the GC_HANDSHAKE lDelta exchange)
// so EntityStore::drain_state_queue() gates queued StateCmds on server time
// instead of releasing immediately. 0 until the first handshake lands.
m_world.set_server_frame_ms(m_stream.server_frame_ms());
m_world.tick();
}
@@ -45,6 +45,16 @@ void ClassicStream::set_state(State s) {
}
}
uint32_t ClassicStream::server_frame_ms() const {
// §3.2 — mirror EterLib ELTimer_GetServerFrameMSec(): the handshake stored
// (m_server_time_base, m_client_time_base); the server clock advances with
// local wall time from there. 0 until the first handshake lands.
if (m_client_time_base == 0) {
return 0;
}
return now_ms() - m_client_time_base + m_server_time_base;
}
// --------------------------------------------------------------------- socket
bool ClassicStream::connect(const std::string &host, uint16_t port) {
disconnect();
@@ -99,6 +99,14 @@ public:
bool cipher_active() const { return m_cipher.activated(); }
void set_polarity(bool client) { m_polarity = client; }
// §3.2 — ELTimer_GetServerFrameMSec() equivalent. The GC_HANDSHAKE exchange
// (handle_control HDR_HANDSHAKE) stores m_server_time_base = hs.time + lDelta
// and m_client_time_base = local now; the server frame clock is then
// local_now - m_client_time_base + m_server_time_base. Returns 0 until the
// first handshake has landed (EntityStore treats 0 as "release immediately").
uint32_t server_frame_ms() const;
bool has_server_clock() const { return m_client_time_base != 0; }
private:
void set_state(State s);
bool recv_into_buffer();