Merge pull request #96 from rtw1x1/main

FreeType2 & Networking Overhaul
This commit is contained in:
rtw1x1
2026-02-08 20:03:55 +00:00
committed by GitHub
91 changed files with 4441 additions and 6479 deletions

View File

@@ -67,6 +67,7 @@ add_compile_definitions("$<$<CONFIG:Release>:_DISTRIBUTE>")
include_directories("src")
include_directories("extern/include")
include_directories("vendor/libsodium/src/libsodium/include")
include_directories("vendor/freetype-2.13.3/include")
# Add subdirectories for libraries and executables
add_subdirectory(vendor)

194
README.md
View File

@@ -55,13 +55,199 @@ The entire legacy encryption system has been replaced with [libsodium](https://d
* **libsodium-based pack encryption** — `PackLib` now uses XChaCha20-Poly1305 for pack file encryption, replacing the legacy Camellia/XTEA system
* **Secure key derivation** — Pack encryption keys are derived using `crypto_pwhash` (Argon2id)
<br>
<br>
---
### Networking Modernization Roadmap
A 5-phase modernization of the entire client/server networking stack — packet format, buffer management, handshake protocol, connection architecture, and packet dispatching. Every phase is complete and verified on both client and server.
---
<br>
<br>
#### Phase 1 — Packet Format + Buffer System + Memory Safety
Replaced the legacy 1-byte packet headers and raw C-style buffers with a modern, uniform protocol.
##### What changed
* **2-byte headers + 2-byte length prefix** — All packet types (`CG::`, `GC::`, `GG::`, `GD::`, `DG::`) now use `uint16_t` header + `uint16_t` length. This increases the addressable packet space from 256 to 65,535 unique packet types and enables safe variable-length parsing
* **Namespaced packet headers** — All headers moved from flat `HEADER_CG_*` defines to C++ namespaces: `CG::MOVE`, `GC::PING`, `GG::LOGIN`, `GD::PLAYER_SAVE`, `DG::BOOT`. Subheaders similarly namespaced: `GuildSub::GC::LOGIN`, `ShopSub::CG::BUY`, etc.
* **RAII RingBuffer** — All raw `buffer_t` / `LPBUF` / `new[]`/`delete[]` patterns replaced with a single `RingBuffer` class featuring lazy compaction at 50% read position, exponential growth, and inlined accessors
* **PacketReader / PacketWriter** — Type-safe helpers that wrap buffer access with bounds checking, eliminating raw pointer arithmetic throughout the codebase
* **Sequence system modernized** — Packet sequence tracking retained for debugging but fixed to byte offset 4 (after header + length)
* **SecureCipher** — XChaCha20-Poly1305 stream cipher for all post-handshake traffic (see Encryption section above)
##### What was removed
* `buffer.h` / `buffer.cpp` (legacy C buffer library)
* All `LPBUF`, `buffer_new()`, `buffer_delete()`, `buffer_read()`, `buffer_write()` calls
* Raw `new[]`/`delete[]` buffer allocations in DESC classes
* 1-byte header constants (`HEADER_CG_*`, `HEADER_GC_*`, etc.)
##### Why
The legacy 1-byte header system limited the protocol to 256 packet types (already exhausted), raw C buffers had no bounds checking and were prone to buffer overflows, and the flat namespace caused header collisions between subsystems.
---
#### Phase 2 — Modern Buffer System *(merged into Phase 1)*
All connection types now use `RingBuffer` uniformly.
##### What changed
* **All DESC types** (`DESC`, `CLIENT_DESC`, `DESC_P2P`) use `RingBuffer` for `m_inputBuffer`, `m_outputBuffer`, and `m_bufferedOutputBuffer`
* **PeerBase** (db layer) ported to `RingBuffer`
* **TEMP_BUFFER** (local utility for building packets) backed by `RingBuffer`
##### What was removed
* `libthecore/buffer.h` and `libthecore/buffer.cpp` — the entire legacy buffer library
##### Why
The legacy buffer system used separate implementations across different connection types, had no RAII semantics (manual malloc/free), and offered no protection against buffer overflows.
---
#### Phase 3 — Simplified Handshake
Replaced the legacy multi-step handshake (4+ round trips with time synchronization and UDP binding) with a streamlined 1.5 round-trip flow.
##### What changed
* **1.5 round-trip handshake** — Server sends `GC::KEY_CHALLENGE` (with embedded time sync), client responds with `CG::KEY_RESPONSE`, server confirms with `GC::KEY_COMPLETE`. Session is encrypted from that point forward
* **Time sync embedded** — Initial time synchronization folded into `GC::KEY_CHALLENGE`; periodic time sync handled by `GC::PING` / `CG::PONG`
* **Handshake timeout** — 5-second expiry on handshake phase; stale connections are automatically cleaned up in `DestroyClosed()`
##### What was removed
* **6 dead packet types**: `CG_HANDSHAKE`, `GC_HANDSHAKE`, `CG_TIME_SYNC`, `GC_TIME_SYNC`, `GC_HANDSHAKE_OK`, `GC_BINDUDP`
* **Server functions**: `StartHandshake()`, `SendHandshake()`, `HandshakeProcess()`, `CreateHandshake()`, `FindByHandshake()`, `m_map_handshake`
* **Client functions**: `RecvHandshakePacket()`, `RecvHandshakeOKPacket()`, `m_HandshakeData`, `SendHandshakePacket()`
* ~12 server files and ~10 client files modified
##### Why
The original handshake required 4+ round trips, included dead UDP binding steps, had no timeout protection (stale connections could linger indefinitely), and the time sync was a separate multi-step sub-protocol that added latency to every new connection.
---
#### Phase 4 — Unified Connection (Client-Side Deduplication)
Consolidated duplicated connection logic into the base `CNetworkStream` class.
##### What changed
* **Key exchange** (`RecvKeyChallenge` / `RecvKeyComplete`) moved from 4 separate implementations to `CNetworkStream` base class
* **Ping/pong** (`RecvPingPacket` / `SendPongPacket`) moved from 3 separate implementations to `CNetworkStream` base class
* **CPythonNetworkStream** overrides `RecvKeyChallenge` only for time sync, delegates all crypto to base
* **CGuildMarkDownloader/Uploader** — `RecvKeyCompleteAndLogin` wraps base + sends `CG::MARK_LOGIN`
* **CAccountConnector** — Fixed raw `crypto_aead` bug (now uses base class `cipher.DecryptToken`)
* **Control-plane structs** extracted to `EterLib/ControlPackets.h` (Phase, Ping, Pong, KeyChallenge, KeyResponse, KeyComplete)
* **CGuildMarkUploader** — `m_pbySymbolBuf` migrated from `new[]`/`delete[]` to `std::vector<uint8_t>`
##### What was removed
* ~200 lines of duplicated code across `CAccountConnector`, `CGuildMarkDownloader`, `CGuildMarkUploader`, and `CPythonNetworkStream`
##### Why
The same key exchange and ping/pong logic was copy-pasted across 3-4 connection subclasses, leading to inconsistent behavior (the `CAccountConnector` had a raw crypto bug), difficult maintenance, and unnecessary code volume.
---
#### Phase 5 — Packet Handler Registration / Dispatcher
Replaced giant `switch` statements with `std::unordered_map` dispatch tables for O(1) packet routing.
##### What changed
**Client:**
* `CPythonNetworkStream` — Phase-specific handler maps for Game, Loading, Login, Select, and Handshake phases
* Registration pattern: `m_gameHandlers[GC::MOVE] = &CPythonNetworkStream::RecvCharacterMovePacket;`
* Dispatch: `DispatchPacket(m_gameHandlers)` — reads header, looks up handler, calls it
**Server:**
* `CInputMain`, `CInputDead`, `CInputAuth`, `CInputLogin`, `CInputP2P`, `CInputHandshake`, `CInputDB` — all converted to dispatch tables
* `CInputDB` uses 3 template adapters (`DataHandler`, `DescHandler`, `TypedHandler`) + 14 custom adapters for the diverse DB callback signatures
##### What was removed
* All `switch (header)` blocks across 7 server input processors and 5 client phase handlers
* ~3,000 lines of switch/case boilerplate
##### Why
The original dispatch used switch statements with 50-100+ cases each. Adding a new packet required modifying a massive switch block, which was error-prone and caused merge conflicts. The table-driven approach enables O(1) lookup, self-documenting handler registration, and trivial addition of new packet types.
---
### Post-Phase 5 Cleanup
Follow-up tasks after the core roadmap was complete.
#### One-Liner Adapter Reformat
* 24 adapter methods across 4 server files (`input_main.cpp`, `input_p2p.cpp`, `input_auth.cpp`, `input_login.cpp`) reformatted from single-line to multi-line for readability
#### MAIN_CHARACTER Packet Merge
* **4 mutually exclusive packets** (`GC::MAIN_CHARACTER`, `MAIN_CHARACTER2_EMPIRE`, `MAIN_CHARACTER3_BGM`, `MAIN_CHARACTER4_BGM_VOL`) merged into a single unified `GC::MAIN_CHARACTER` packet
* Single struct always includes BGM fields (zero when unused — 29 extra bytes on a one-time-per-load packet)
* 4 nearly identical client handlers merged into 1
* 3 redundant server send paths merged into 1
#### UDP Leftover Removal
* **7 client files deleted**: `NetDatagram.h/.cpp`, `NetDatagramReceiver.h/.cpp`, `NetDatagramSender.h/.cpp`, `PythonNetworkDatagramModule.cpp`
* **8 files edited**: Removed dead stubs (`PushUDPState`, `initudp`, `netSetUDPRecvBufferSize`, `netConnectUDP`), declarations, and Python method table entries
* **Server**: Removed `socket_udp_read()`, `socket_udp_bind()`, `__UDP_BLOCK__` define
#### Subheader Dispatch
* Extended the Phase 5 table-driven pattern to subheader switches with 8+ cases
* **Client**: Guild (19 sub-handlers), Shop (10), Exchange (8) in `PythonNetworkStreamPhaseGame.cpp`
* **Server**: Guild (15 sub-handlers) in `input_main.cpp`
* Small switches intentionally kept as-is: Messenger (5), Fishing (6), Dungeon (2), Server Shop (4)
---
### Performance Audit & Optimization
Comprehensive audit of all Phase 1-5 changes to identify and eliminate performance overhead.
#### Debug Logging Cleanup
* **Removed all hot-path `TraceError`/`Tracef`/`sys_log`** from networking code on both client and server
* Client: `NetStream.cpp`, `SecureCipher.cpp`, `PythonNetworkStream*.cpp` — eliminated per-frame and per-packet traces that caused disk I/O every frame
* Server: `desc.cpp`, `input.cpp`, `input_login.cpp`, `input_auth.cpp`, `SecureCipher.cpp` — eliminated `[SEND]`, `[RECV]`, `[CIPHER]` logs that fired on every packet
#### Packet Processing Throughput
* **`MAX_RECV_COUNT` 4 → 32** — Game phase now processes up to 32 packets per frame (was 4, severely limiting entity spawning on map entry)
* **Loading phase while-loop** — Changed from processing 1 packet per frame to draining all available packets, making phase transitions near-instant
#### Flood Check Optimization
* **Replaced `get_dword_time()` with `thecore_pulse()`** in `DESC::CheckPacketFlood()` — eliminates a `gettimeofday()` syscall on every single packet received. `thecore_pulse()` is cached once per game-loop iteration
#### Flood Protection
* **Per-IP connection limits** — Configurable maximum connections per IP address (`flood_max_connections_per_ip`, default: 10)
* **Global connection limits** — Configurable maximum total connections (`flood_max_global_connections`, default: 8192)
* **Per-second packet rate limiting** — Connections exceeding `flood_max_packets_per_sec` (default: 300) are automatically disconnected
* **Handshake timeout** — 5-second expiry prevents connection slot exhaustion from incomplete handshakes
---
### Pre-Phase 3 Cleanup
Preparatory cleanup performed before the handshake simplification.
* **File consolidation** — Merged scattered packet definitions into centralized header files
* **Alias removal** — Removed legacy `#define` aliases that mapped old names to new identifiers
* **Monarch system removal** — Completely removed the unused Monarch (emperor) system from both client and server, including all related packets, commands, quest functions, and UI code
* **TrafficProfiler removal** — Removed the `TrafficProfiler` class and all references (unnecessary runtime overhead)
* **Quest management stub removal** — Removed empty `questlua_mgmt.cpp` (monarch-era placeholder with no functions)
---
### Summary of Removed Legacy Systems
A consolidated reference of all legacy systems, files, and dead code removed across the entire modernization effort.
| System | What was removed | Replaced by |
|--------|-----------------|-------------|
| **Legacy C buffer** | `buffer.h`, `buffer.cpp`, all `LPBUF`/`buffer_new()`/`buffer_delete()` calls, raw `new[]`/`delete[]` buffer allocations | RAII `RingBuffer` class |
| **1-byte packet headers** | All `HEADER_CG_*`, `HEADER_GC_*`, `HEADER_GG_*`, `HEADER_GD_*`, `HEADER_DG_*` defines | 2-byte namespaced headers (`CG::`, `GC::`, `GG::`, `GD::`, `DG::`) |
| **Old handshake protocol** | 6 packet types (`CG_HANDSHAKE`, `GC_HANDSHAKE`, `CG_TIME_SYNC`, `GC_TIME_SYNC`, `GC_HANDSHAKE_OK`, `GC_BINDUDP`), all handshake functions and state | 1.5 round-trip key exchange (`KEY_CHALLENGE`/`KEY_RESPONSE`/`KEY_COMPLETE`) |
| **UDP networking** | 7 client files (`NetDatagram*.h/.cpp`, `PythonNetworkDatagramModule.cpp`), server `socket_udp_read()`/`socket_udp_bind()`/`__UDP_BLOCK__` | Removed entirely (game is TCP-only) |
| **Old sequence system** | `m_seq`, `SetSequence()`, `GetSequence()`, old sequence variables | Modernized sequence at fixed byte offset 4 |
| **TrafficProfiler** | `TrafficProfiler` class and all references | Removed entirely |
| **Monarch system** | All monarch/emperor packets, commands (`do_monarch_*`), quest functions (`questlua_monarch.cpp`, `questlua_mgmt.cpp`), UI code, GM commands | Removed entirely (unused feature) |
| **Legacy crypto** | Crypto++, Panama cipher, TEA, DH2, Camellia, XTEA, `adwClientKey[4]`, `LSS_SECURITY_KEY` | libsodium (X25519 + XChaCha20-Poly1305) |
| **Switch-based dispatch** | Giant `switch (header)` blocks (50-100+ cases each) across 7 server input processors and 5 client phase handlers | `std::unordered_map` dispatch tables |
| **Duplicated connection code** | Key exchange and ping/pong copy-pasted across 3-4 client subclasses | Consolidated in `CNetworkStream` base class |
---
# Installation/Configuration
This is the third part of the entire project and it's about the client binary, the executable of the game.

View File

@@ -7,35 +7,6 @@ void CEffectElementBase::GetPosition(float fTime, D3DXVECTOR3 & rPosition)
rPosition = GetTimeEventBlendValue(fTime, m_TimeEventTablePosition);
}
/*
bool CEffectElementBase::isVisible(float fTime)
{
for (DWORD i = 0; i < m_TimeEventTableVisible.size(); ++i)
{
float fPointTime = m_TimeEventTableVisible[i];
if (fTime < fPointTime)
{
if (1 == i % 2)
return true;
else
return false;
}
}
return 1 == (m_TimeEventTableVisible.size() % 2);
}
void CEffectElementBase::GetAlpha(float fTime, float * pAlpha)
{
GetTimeEventBlendValue<TTimeEventTableFloat, float>(fTime, m_TimeEventAlpha, pAlpha);
}
void CEffectElementBase::GetScale(float fTime, float * pScale)
{
GetTimeEventBlendValue<TTimeEventTableFloat, float>(fTime, m_TimeEventScale, pScale);
}
*/
bool CEffectElementBase::isData()
{

View File

@@ -60,34 +60,6 @@ void CLightData::GetRange(float fTime, float& rRange)
if (rRange<0.0f)
rRange = 0.0f;
return;
/*
float vecLastRange = m_TimeEventTableRange[0].m_Value;
for (DWORD dwIndex = 0; dwIndex < m_TimeEventTableRange.size(); ++dwIndex)
{
if(fTime < m_TimeEventTableRange[dwIndex].m_fTime)
{
break;
}
}
if (dwIndex >= m_TimeEventTableRange.size())
{
rRange = m_TimeEventTableRange[m_TimeEventTableRange.size()-1].m_Value * m_fMaxRange;
if (rRange<0.0f)
rRange = 0.0f;
return;
}
TTimeEventTypeFloat & rEffectRange = m_TimeEventTableRange[dwIndex];
TTimeEventTypeFloat & rPrevEffectRange = m_TimeEventTableRange[dwIndex-1];
float Head = fabs(rEffectRange.m_fTime - fTime) / fabs(rEffectRange.m_fTime - rPrevEffectRange.m_fTime);
float Tail = 1.0f - fabs(rEffectRange.m_fTime - fTime) / fabs(rEffectRange.m_fTime - rPrevEffectRange.m_fTime);
rRange = ((rPrevEffectRange.m_Value*Head) + (rEffectRange.m_Value*Tail) )*m_fMaxRange;
if (rRange<0.0f)
rRange = 0.0f;
*/
}
bool CLightData::OnIsData()

View File

@@ -345,9 +345,8 @@ static struct TSyserrBuffer
memcpy(buffer + pos, msg, len);
pos += len;
DWORD now = ELTimer_GetMSec();
if (now - lastFlushMs > 500 || pos > BUFFER_SIZE * 3 / 4)
Flush();
// DEBUG: Force flush every write to capture crash traces
Flush();
}
void Flush()

View File

@@ -1,5 +1,6 @@
#include "StdAfx.h"
#include "SecureCipher.h"
#include "Debug.h"
// Static initialization flag for libsodium
static bool s_sodiumInitialized = false;
@@ -57,6 +58,7 @@ bool SecureCipher::Initialize()
void SecureCipher::CleanUp()
{
// Securely erase all sensitive key material
sodium_memzero(m_pk, sizeof(m_pk));
sodium_memzero(m_sk, sizeof(m_sk));
sodium_memzero(m_tx_key, sizeof(m_tx_key));
sodium_memzero(m_rx_key, sizeof(m_rx_key));
@@ -95,6 +97,7 @@ bool SecureCipher::ComputeClientKeys(const uint8_t* server_pk)
sodium_memzero(m_rx_stream_nonce, NONCE_SIZE);
m_rx_stream_nonce[0] = 0x01;
Tracef("[CIPHER] Client keys computed\n");
return true;
}
@@ -172,64 +175,6 @@ void SecureCipher::ApplyStreamCipher(void* buffer, size_t len,
}
}
size_t SecureCipher::Encrypt(const void* plaintext, size_t plaintext_len, void* ciphertext)
{
if (!m_activated)
{
return 0;
}
// AEAD encryption uses a random nonce (not the stream nonce)
uint8_t nonce[NONCE_SIZE];
randombytes_buf(nonce, NONCE_SIZE);
unsigned long long ciphertext_len = 0;
if (crypto_aead_xchacha20poly1305_ietf_encrypt(
(uint8_t*)ciphertext, &ciphertext_len,
(const uint8_t*)plaintext, plaintext_len,
nullptr, 0,
nullptr,
nonce,
m_tx_key) != 0)
{
return 0;
}
return (size_t)ciphertext_len;
}
size_t SecureCipher::Decrypt(const void* ciphertext, size_t ciphertext_len, void* plaintext)
{
if (!m_activated)
{
return 0;
}
if (ciphertext_len < TAG_SIZE)
{
return 0;
}
uint8_t nonce[NONCE_SIZE];
randombytes_buf(nonce, NONCE_SIZE);
unsigned long long plaintext_len = 0;
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
(uint8_t*)plaintext, &plaintext_len,
nullptr,
(const uint8_t*)ciphertext, ciphertext_len,
nullptr, 0,
nonce,
m_rx_key) != 0)
{
return 0;
}
return (size_t)plaintext_len;
}
void SecureCipher::EncryptInPlace(void* buffer, size_t len)
{
if (!m_activated || len == 0)

View File

@@ -37,14 +37,6 @@ public:
void ComputeChallengeResponse(const uint8_t* challenge, uint8_t* out_response);
bool VerifyChallengeResponse(const uint8_t* challenge, const uint8_t* response);
// AEAD encryption - output is len + TAG_SIZE bytes
// Returns actual ciphertext length (plaintext_len + TAG_SIZE)
size_t Encrypt(const void* plaintext, size_t plaintext_len, void* ciphertext);
// AEAD decryption - input must be ciphertext_len bytes (includes TAG_SIZE)
// Returns actual plaintext length, or 0 on failure
size_t Decrypt(const void* ciphertext, size_t ciphertext_len, void* plaintext);
// In-place stream encryption for network buffers (XChaCha20, no tag overhead)
// Same length in/out. Nonce counter prevents replay.
void EncryptInPlace(void* buffer, size_t len);
@@ -69,14 +61,8 @@ public:
uint64_t GetTxNonce() const { return m_tx_nonce; }
uint64_t GetRxNonce() const { return m_rx_nonce; }
// Access keys directly (for special decrypt operations like session token)
// Direct key access (for session token decryption)
const uint8_t* GetRxKey() const { return m_rx_key; }
const uint8_t* GetTxKey() const { return m_tx_key; }
// Alias for convenience
void ComputeResponse(const uint8_t* challenge, uint8_t* out_response) {
ComputeChallengeResponse(challenge, out_response);
}
private:
bool m_initialized = false;

View File

@@ -508,53 +508,3 @@ DWORD CGrannyMaterialPalette::GetMaterialCount() const
return m_mtrlVector.size();
}
/*
void CActorInstance::BeginSpecularRender()
{
// NOTE - Blending해서 찍는 부분은 Specular를 적용시키지 않는다 - [levites]
STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, D3DXCOLOR(1.0f, 1.0f, 1.0f, m_AddColor.r));
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATEALPHA_ADDCOLOR);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
// STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
// STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
// STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
// STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
//
// STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
// STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TEXTURE);
// STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATEALPHA_ADDCOLOR);
// STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
// STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
// D3DXMATRIX texMatrix;
// GetSphereMatrix(&texMatrix);
// STATEMANAGER.SetTransform(D3DTS_TEXTURE1, &texMatrix);
// STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
// Type 1
// STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
// // Type 2
// STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL);
}
void CActorInstance::EndSpecularRender()
{
// STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
// STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
*/

View File

@@ -214,33 +214,7 @@ bool CGrannyMesh::LoadTriGroupNodeList(CGrannyMaterialPalette& rkMtrlPal)
void CGrannyMesh::RebuildTriGroupNodeList()
{
assert(!"CGrannyMesh::RebuildTriGroupNodeList() - 왜 리빌드를 하는가- -?");
/*
int mtrlCount = m_pgrnMesh->MaterialBindingCount;
int GroupNodeCount = GrannyGetMeshTriangleGroupCount(m_pgrnMesh);
if (GroupNodeCount <= 0)
return;
const granny_tri_material_group * c_pgrnTriGroups = GrannyGetMeshTriangleGroups(m_pgrnMesh);
for (int g = 0; g < GroupNodeCount; ++g)
{
const granny_tri_material_group& c_rgrnTriGroup = c_pgrnTriGroups[g];
TTriGroupNode * pTriGroupNode = m_triGroupNodes + g;
int iMtrl = c_rgrnTriGroup.MaterialIndex;
if (iMtrl >= 0 && iMtrl < mtrlCount)
{
CGrannyMaterial & rMtrl = m_mtrls[iMtrl];
pTriGroupNode->lpd3dTextures[0] = rMtrl.GetD3DTexture(0);
pTriGroupNode->lpd3dTextures[1] = rMtrl.GetD3DTexture(1);
}
}
*/
assert(!"CGrannyMesh::RebuildTriGroupNodeList() - should not be called");
}
bool CGrannyMesh::LoadMaterials(CGrannyMaterialPalette& rkMtrlPal)

View File

@@ -90,90 +90,6 @@ bool CGrannyModelInstance::Intersect(const D3DXMATRIX * c_pMatrix,
return true;
/*
TBoundBox* boundBoxs = s_boundBoxPool.base();
for (int i = 0; i < s_boundBoxPool.size(); ++i)
{
TBoundBox& rcurBoundBox=boundBoxs[i];
if (!IntersectBoundBox(c_pMatrix, rcurBoundBox, &u, &v, &t))
continue;
granny_matrix_4x4* pgrnMatCompositeBuffer = GrannyGetWorldPoseComposite4x4Array(m_pgrnWorldPose);
const CGrannyMesh* c_pMesh = m_pModel->GetMeshPointer(rcurBoundBox.meshIndex);
const granny_mesh* c_pgrnMesh = c_pMesh->GetGrannyMeshPointer();
if (!GrannyMeshIsRigid(c_pgrnMesh))
{
//continue;
ret = true;
}
else
{
D3DXMATRIX matMesh;
int* toBoneIndices = c_pMesh->GetBoneIndices();
D3DXMatrixMultiply(&matMesh, (D3DXMATRIX*) pgrnMatCompositeBuffer[toBoneIndices[0]], c_pMatrix);
granny_tri_material_group* pgrnTriGroups = GrannyGetMeshTriangleGroups(c_pgrnMesh);
int mtrlCount = c_pMesh->GetGrannyMeshPointer()->MaterialBindingCount;
int vtxCount = GrannyGetMeshVertexCount(c_pgrnMesh);
int groupCount = GrannyGetMeshTriangleGroupCount(c_pgrnMesh);
TIndex* modelIndices;
TPNTVertex* modelVertices;
if (m_pModel->LockVertices((void**)&modelIndices, (void**)&modelVertices))
{
TIndex* meshIndices = modelIndices + c_pMesh->GetIndexBasePosition();
TPNTVertex* meshVertices = modelVertices + c_pMesh->GetVertexBasePosition();
for (int i = 0; i < groupCount; ++i)
{
granny_tri_material_group& rgrnTriGroup = pgrnTriGroups[i];
if (rgrnTriGroup.MaterialIndex < 0 || rgrnTriGroup.MaterialIndex >= mtrlCount)
continue;
if (IntersectMesh(&matMesh,
meshVertices,
sizeof(TPNTVertex),
vtxCount,
meshIndices,
GrannyGetMeshIndexCount(c_pgrnMesh),
ms_vtPickRayOrig,
ms_vtPickRayDir,
&u, &v, &t))
{
ret = true;
break;
}
}
m_pModel->UnlockVertices();
}
}
if (ret)
{
*pu = u;
*pv = v;
*pt = -t;
if (c_szModelName)
{
if (!strncmp(c_pgrnMesh->Name, c_szModelName, strlen(c_szModelName)))
return ret;
ret = false;
continue;
}
return ret;
}
}
return (ret);
*/
}
#include "EterBase/Timer.h"
@@ -226,42 +142,3 @@ bool CGrannyModelInstance::GetMeshMatrixPointer(int iMesh, const D3DXMATRIX ** c
return true;
}
/*
void CGraphicThingInstance::DrawBoundBox()
{
if (!mc_pMeshVector)
return;
if (!m_pgrnWorldPose)
return;
D3DXVECTOR3 vtMin;
D3DXVECTOR3 vtMax;
SetDiffuseColor(0.0f, 1.0f, 0.0f);
// 캐릭터 꽉차는 바운딩 박스
//GetBoundBox(&vtMin, &vtMax);
//DrawLineCube(vtMin.x, vtMin.y, vtMin.z, vtMax.x, vtMax.y, vtMax.z);
//const CThing::TMeshVector& rmeshVector=mc_pModel->meshVector;
ms_lpd3dMatStack->LoadMatrix(&m_Matrix);
for (size_t m=0; m<mc_pMeshVector->size(); ++m)
{
const CThing::TMesh& rmesh=mc_pMeshVector->at(m);
for (int b=0; b<rmesh.pgrnMesh->BoneBindingCount; ++b)
{
granny_bone_binding& rgrnBoneBinding=rmesh.pgrnMesh->BoneBindings[b];
int* toBoneIndices=GrannyGetMeshBindingToBoneIndices(rmesh.pgrnMeshBinding);
D3DXMATRIX* pmat=(D3DXMATRIX*)GrannyGetWorldPose4x4(m_pgrnWorldPose, toBoneIndices[b]);
D3DXVec3TransformCoord(&vtMin, &D3DXVECTOR3(rgrnBoneBinding.OBBMin), pmat);
D3DXVec3TransformCoord(&vtMax, &D3DXVECTOR3(rgrnBoneBinding.OBBMax), pmat);
DrawLineCube(vtMin.x, vtMin.y, vtMin.z, vtMax.x, vtMax.y, vtMax.z);
}
}
}
*/

View File

@@ -299,109 +299,3 @@ void CGrannyModelInstance::RenderMeshNodeListWithoutTexture(CGrannyMesh::EType e
}
}
/*
void CGrannyModelInstance::RenderMeshNodeList(CGrannyMesh::EType eMeshType, CGrannyMaterial::EType eMtrlType)
{
assert(m_pModel != NULL);
LPDIRECT3DINDEXBUFFER9 lpd3dIdxBuf = m_pModel->GetD3DIndexBuffer();
assert(lpd3dIdxBuf != NULL);
const CGrannyModel::TMeshNode * pMeshNode = m_pModel->GetMeshNodeList(eMeshType, eMtrlType);
while (pMeshNode)
{
const CGrannyMesh * pMesh = pMeshNode->pMesh;
int vtxMeshBasePos = pMesh->GetVertexBasePosition();
STATEMANAGER.SetIndices(lpd3dIdxBuf, vtxMeshBasePos);
STATEMANAGER.SetTransform(D3DTS_WORLD, &m_meshMatrices[pMeshNode->iMesh]);
/////
const CGrannyMesh::TTriGroupNode* pTriGroupNode = pMesh->GetTriGroupNodeList(eMtrlType);
int vtxCount = pMesh->GetVertexCount();
while (pTriGroupNode)
{
ms_faceCount += pTriGroupNode->triCount;
STATEMANAGER.SetTexture(0, pTriGroupNode->lpd3dTextures[0]);
if (pTriGroupNode->lpd3dTextures[1])
STATEMANAGER.SetTexture(1, pTriGroupNode->lpd3dTextures[1]);
else
{
STATEMANAGER.SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
STATEMANAGER.SetTexture(1, m_FogInstance.GetTexturePointer()->GetD3DTexture());
D3DXMATRIX mat;
memset(&mat, 0, sizeof(D3DXMATRIX));
mat._31 = -0.001f;
mat._41 = -7.0f;
mat._42 = 0.5f;
STATEMANAGER.SetTransform(D3DTS_TEXTURE1, &mat);
}
STATEMANAGER.DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, vtxCount, pTriGroupNode->idxPos, pTriGroupNode->triCount);
if (!pTriGroupNode->lpd3dTextures[1])
{
STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
STATEMANAGER.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
pTriGroupNode = pTriGroupNode->pNextTriGroupNode;
}
/////
pMeshNode = pMeshNode->pNextMeshNode;
}
}
void CGrannyModelInstance::RenderToShadowMap()
{
if (IsEmpty())
return;
STATEMANAGER.SetFVF(ms_pntVS);
// LPDIRECT3DVERTEXBUFFER9 lpd3dDynamicPNTVtxBuf = m_dynamicPNTVtxBuf.GetD3DVertexBuffer();
LPDIRECT3DVERTEXBUFFER9 lpd3dDeformPNTVtxBuf = m_dynamicPNTVtxBuf.GetD3DVertexBuffer();
LPDIRECT3DVERTEXBUFFER9 lpd3dRigidPNTVtxBuf = m_pModel->GetPNTD3DVertexBuffer();
// STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, TRUE);
// STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0);
// STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL);
//
// if (lpd3dDynamicPNTVtxBuf)
// {
// STATEMANAGER.SetStreamSource(0, lpd3dDynamicPNTVtxBuf, sizeof(TPNTVertex));
// RenderMeshNodeListWithoutTexture(CGrannyMesh::TYPE_DEFORM, CGrannyMaterial::TYPE_BLEND_PNT);
// }
//
// STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
// STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
// STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
if (lpd3dDeformPNTVtxBuf)
{
STATEMANAGER.SetStreamSource(0, lpd3dDeformPNTVtxBuf, sizeof(TPNTVertex));
RenderMeshNodeListWithoutTexture(CGrannyMesh::TYPE_DEFORM, CGrannyMaterial::TYPE_DIFFUSE_PNT);
}
if (lpd3dRigidPNTVtxBuf)
{
STATEMANAGER.SetStreamSource(0, lpd3dRigidPNTVtxBuf, sizeof(TPNTVertex));
RenderMeshNodeListWithoutTexture(CGrannyMesh::TYPE_RIGID, CGrannyMaterial::TYPE_DIFFUSE_PNT);
}
}
*/

View File

@@ -1,50 +1,7 @@
#include "StdAfx.h"
#include "Util.h"
/*
bool GrannyMeshGetTextureAnimation(granny_mesh* pgrnMesh, float* puVelocity, float* pvVelocity)
{
static granny_data_type_definition s_UVType[] =
{
{GrannyInt32Member, "UV Animation Flag"},
{GrannyInt32Member, "X Velocity"},
{GrannyInt32Member, "Y Velocity"},
{GrannyEndMember}
};
typedef struct SUVData
{
granny_int32 UVAnimationFlag;
granny_int32 xVelocity;
granny_int32 yVelocity;
} TUVData;
TUVData UVData;
granny_variant& rExtendedData = pgrnMesh->ExtendedData;
GrannyConvertSingleObject(rExtendedData.Type, rExtendedData.Object, s_UVType, &UVData);
*puVelocity = float(UVData.xVelocity) / 100000.0f;
*pvVelocity = float(UVData.yVelocity) / 100000.0f;
return UVData.UVAnimationFlag ? true : false;
}
*/
/*
bool GrannyMeshIsTextureAnimation(granny_mesh* pgrnMesh)
{
if (GrannyMeshIsRigid(pgrnMesh))
{
float xVelocity, yVelocity;
if (GrannyMeshGetTextureAnimation(pgrnMesh, &xVelocity, &yVelocity))
return true;
}
return false;
}
*/
bool GrannyMeshIsDeform(granny_mesh* pgrnMesh)
{

View File

@@ -94,7 +94,16 @@ void CBlockTexture::Render(int ix, int iy)
STATEMANAGER.SetTexture(0, m_lpd3dTexture);
STATEMANAGER.SetTexture(1, NULL);
STATEMANAGER.SetFVF(D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_DIFFUSE);
STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
STATEMANAGER.SaveRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
STATEMANAGER.DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2);
STATEMANAGER.RestoreRenderState(D3DRS_DESTBLEND);
STATEMANAGER.RestoreRenderState(D3DRS_SRCBLEND);
STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);
}
}
@@ -137,14 +146,11 @@ void CBlockTexture::InvalidateRect(const RECT & c_rsrcRect)
DWORD * pdwDst = (DWORD *)lockedRect.pBits;
DWORD dwDstWidth = lockedRect.Pitch>>2;
DWORD dwSrcWidth = m_pDIB->GetWidth();
for (int i = 0; i < iclipHeight; ++i)
for (int y = 0; y < iclipHeight; ++y)
{
for (int i = 0; i < iclipWidth; ++i)
for (int x = 0; x < iclipWidth; ++x)
{
if (pdwSrc[i])
pdwDst[i] = pdwSrc[i] | 0xff000000;
else
pdwDst[i] = 0;
pdwDst[x] = pdwSrc[x];
}
pdwDst += dwDstWidth;
pdwSrc += dwSrcWidth;

View File

@@ -5,6 +5,7 @@ add_library(EterLib STATIC ${FILE_SOURCES})
target_link_libraries(EterLib
sodium
mio
freetype
)
GroupSourcesByFolder(EterLib)

View File

@@ -374,61 +374,14 @@ D3DXVECTOR3 CPlaneCollisionInstance::OnGetCollisionMovementAdjust(const CDynamic
const auto vv = (s.v3Position - m_attribute.v3Position);
float t= - D3DXVec3Dot(&m_attribute.v3Normal, &vv)/d;
//D3DXVECTOR3 onplane = s.v3Position+t*advance;
if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
{
//return m_attribute.v3Normal*((-s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
return t*advance -s.fRadius*m_attribute.v3Normal;
}
else
{
//return m_attribute.v3Normal*((s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
return t*advance +s.fRadius*m_attribute.v3Normal;
}
/*if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
{
Tracef("%f %f\n",s.fRadius,-(D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position))));
return m_attribute.v3Normal*((-s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
}
else
{
Tracef("%f %f\n",(s.fRadius),(D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position))));
return m_attribute.v3Normal*((s.fRadius+D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position-m_attribute.v3Position)))*gc_fReduceMove);
}*/
/*
D3DXVECTOR3 advance = s.v3Position-s.v3LastPosition;
D3DXVECTOR3 slide(-advance.y,advance.x,advance.z);
slide = m_attribute.v3Normal;
D3DXVECTOR3 radius_adjust = advance;
D3DXVec3Normalize(&radius_adjust,&radius_adjust);
radius_adjust*=s.fRadius;
float d = D3DXVec3Dot(&m_attribute.v3Normal, &slide);
if (d>=-0.0001 && d<=0.0001)
return D3DXVECTOR3(0.0f,0.0f,0.0f);
float t= - D3DXVec3Dot(&m_attribute.v3Normal, &(s.v3Position+radius_adjust-m_attribute.v3Position))
/ d;*/
//D3DXVECTOR3 nextposition;
//nextposition = s.v3Position + t*slide;
//Tracef("$T %f",t);
//if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
// return (t*slide - m_attribute.v3Normal * s.fRadius)/**gc_fReduceMove*/;
//else
// return (t*slide + m_attribute.v3Normal * s.fRadius)/*gc_fReduceMove*/;
//if (D3DXVec3Dot(&m_attribute.v3Normal, &advance)>=0)
// return (t*slide + m_attribute.v3Normal * D3DXVec3Dot(&m_attribute.v3Normal,&(s.v3LastPosition-m_attribute.v3Position))/** s.fRadius*/)*gc_fReduceMove;
//else
// return (t*slide + m_attribute.v3Normal * D3DXVec3Dot(&m_attribute.v3Normal,&(s.v3LastPosition-m_attribute.v3Position))/*s.fRadius*/)*gc_fReduceMove;
//
}
void CPlaneCollisionInstance::Render(D3DFILLMODE /*d3dFillMode*/)
@@ -462,12 +415,6 @@ bool CCylinderCollisionInstance::CollideCylinderVSDynamicSphere(const TCylinderD
if (s.v3Position.z - s.fRadius > c_rattribute.v3Position.z + c_rattribute.fHeight)
return false;
/*D3DXVECTOR2 v2curDistance(s.v3Position.x - c_rattribute.v3Position.x, s.v3Position.y - c_rattribute.v3Position.y);
float fDistance = D3DXVec2Length(&v2curDistance);
if (fDistance <= s.fRadius + c_rattribute.fRadius)
return true;
*/
D3DXVECTOR3 oa, ob;
IntersectLineSegments(c_rattribute.v3Position, D3DXVECTOR3(c_rattribute.v3Position.x,c_rattribute.v3Position.y,c_rattribute.v3Position.z+c_rattribute.fHeight), s.v3LastPosition, s.v3Position, oa, ob);
const auto vv = (oa - ob);
@@ -671,32 +618,6 @@ bool CAABBCollisionInstance::OnCollisionDynamicSphere(const CDynamicSphereInstan
D3DXVECTOR3 CAABBCollisionInstance::OnGetCollisionMovementAdjust(const CDynamicSphereInstance & s) const
{
//Tracef("OnGetCollisionMovementAdjust v3Min.x = %f, v3Max.x = %f\n", m_attribute.v3Min.x, m_attribute.v3Max.x);
/*
float fARadius = D3DXVec3Length(&(m_attribute.v3Min - m_attribute.v3Max));
if (D3DXVec3LengthSq(&(s.v3Position-(m_attribute.v3Max + m_attribute.v3Min)))>=(s.fRadius+fARadius)*(fARadius+s.fRadius))
return D3DXVECTOR3(0.0f,0.0f,0.0f);
D3DXVECTOR3 c;
D3DXVec3Cross(&c, &(s.v3Position-s.v3LastPosition), &D3DXVECTOR3(0.0f,0.0f,1.0f) );
float sum = - D3DXVec3Dot(&c,&(s.v3Position-(m_attribute.v3Max + m_attribute.v3Min)));
float mul = (s.fRadius+fARadius)*(s.fRadius+fARadius)-D3DXVec3LengthSq(&(s.v3Position-(m_attribute.v3Max + m_attribute.v3Min)));
if (sum*sum-4*mul<=0)
return D3DXVECTOR3(0.0f,0.0f,0.0f);
float sq = sqrt(sum*sum-4*mul);
float t1=-sum-sq, t2=-sum+sq;
t1*=0.5f;
t2*=0.5f;
if (fabs(t1)<=fabs(t2))
{
return (gc_fReduceMove*t1)*c;
}
else
return (gc_fReduceMove*t2)*c;
*/
D3DXVECTOR3 v3Temp;
if(s.v3Position.x + s.fRadius <= m_attribute.v3Min.x) { v3Temp.x = m_attribute.v3Min.x; }
else if(s.v3Position.x - s.fRadius >= m_attribute.v3Max.x) { v3Temp.x = m_attribute.v3Max.x; }

View File

@@ -0,0 +1,73 @@
#pragma once
// Control-plane packet structs used by all CNetworkStream subclasses.
// Extracted from UserInterface/Packet.h so the base class (EterLib)
// can handle key exchange, ping/pong, and phase transitions without
// depending on UserInterface.
#include <cstdint>
// Control-plane header constants (subset of CG::/GC:: namespaces).
// The full CG/GC namespaces live in Packet.h which includes this file,
// so all existing code sees these via Packet.h as before.
namespace CG
{
constexpr uint16_t PONG = 0x0006;
constexpr uint16_t KEY_RESPONSE = 0x000A;
}
namespace GC
{
constexpr uint16_t PING = 0x0007;
constexpr uint16_t PHASE = 0x0008;
constexpr uint16_t KEY_CHALLENGE = 0x000B;
constexpr uint16_t KEY_COMPLETE = 0x000C;
}
#pragma pack(push, 1)
struct TPacketGCPhase
{
uint16_t header;
uint16_t length;
uint8_t phase;
};
struct TPacketGCPing
{
uint16_t header;
uint16_t length;
uint32_t server_time;
};
struct TPacketCGPong
{
uint16_t header;
uint16_t length;
};
struct TPacketGCKeyChallenge
{
uint16_t header;
uint16_t length;
uint8_t server_pk[32];
uint8_t challenge[32];
uint32_t server_time;
};
struct TPacketCGKeyResponse
{
uint16_t header;
uint16_t length;
uint8_t client_pk[32];
uint8_t challenge_response[32];
};
struct TPacketGCKeyComplete
{
uint16_t header;
uint16_t length;
uint8_t encrypted_token[32 + 16];
uint8_t nonce[24];
};
#pragma pack(pop)

View File

@@ -240,48 +240,3 @@ void CDecal::Render()
sizeof(TPDTVertex));
}
/*
//////////////////////////////////////////////////////////////////////////
// CDecalManager
//////////////////////////////////////////////////////////////////////////
CDecalManager aDecalManager;
CDecalManager::CDecalManager()
{
m_DecalPtrVector.clear();
}
CDecalManager::~CDecalManager()
{
m_DecalPtrVector.clear();
}
void CDecalManager::Add(CDecal * pDecal)
{
m_DecalPtrVector.push_back(pDecal);
}
void CDecalManager::Remove(CDecal * pDecal)
{
std::vector<CDecal *>::iterator aIterator;
for (aIterator = m_DecalPtrVector.begin(); aIterator != m_DecalPtrVector.end();)
{
if (*aIterator == pDecal)
aIterator = m_DecalPtrVector.erase(aIterator);
else
++aIterator;
}
}
void CDecalManager::Update()
{
for (DWORD dwi = 0; dwi < m_DecalPtrVector.size(); ++dwi)
m_DecalPtrVector[dwi]->Update();
}
void CDecalManager::Render()
{
for (DWORD dwi = 0; dwi < m_DecalPtrVector.size(); ++dwi)
m_DecalPtrVector[dwi]->Render();
}
*/

View File

@@ -138,9 +138,9 @@ void CDibBar::__BuildTextureBlockList(DWORD dwWidth, DWORD dwHeight, DWORD dwMax
}
}
bool CDibBar::Create(HDC hdc, DWORD dwWidth, DWORD dwHeight)
bool CDibBar::Create(DWORD dwWidth, DWORD dwHeight)
{
if (!m_dib.Create(hdc, dwWidth, dwHeight))
if (!m_dib.Create(dwWidth, dwHeight))
{
Tracef(" Failed to create CDibBar\n");
return false;

View File

@@ -10,7 +10,7 @@ class CDibBar
CDibBar();
virtual ~CDibBar();
bool Create(HDC hdc, DWORD dwWidth, DWORD dwHeight);
bool Create(DWORD dwWidth, DWORD dwHeight);
void Invalidate();
void SetClipRect(const RECT & c_rRect);
void ClearBar();

195
src/EterLib/FontManager.cpp Normal file
View File

@@ -0,0 +1,195 @@
#include "StdAfx.h"
#include "FontManager.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_LCD_FILTER_H
#include <algorithm>
#include <cctype>
#include <sys/stat.h>
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
#endif
static std::string ToLower(const std::string& s)
{
std::string result = s;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::tolower(c); });
return result;
}
static bool FileExists(const std::string& path)
{
struct stat st;
return stat(path.c_str(), &st) == 0;
}
CFontManager::CFontManager()
: m_ftLibrary(nullptr)
, m_bInitialized(false)
{
}
CFontManager::~CFontManager()
{
Destroy();
}
CFontManager& CFontManager::Instance()
{
static CFontManager instance;
return instance;
}
bool CFontManager::Initialize()
{
if (m_bInitialized)
return true;
if (FT_Init_FreeType(&m_ftLibrary) != 0)
{
TraceError("CFontManager::Initialize - FT_Init_FreeType failed");
return false;
}
m_bInitialized = true;
// Enable LCD subpixel filter to reduce color fringing
FT_Library_SetLcdFilter(m_ftLibrary, FT_LCD_FILTER_DEFAULT);
// Register default font name -> file mappings
// Korean system fonts
m_fontPathMap["gulim"] = "gulim.ttc";
m_fontPathMap["\xea\xb5\xb4\xeb\xa6\xbc"] = "gulim.ttc"; // 굴림 (UTF-8)
m_fontPathMap["\xea\xb5\xb4\xeb\xa6\xbc\xec\xb2\xb4"] = "gulimche.ttc"; // 굴림체
// Common Latin fonts
m_fontPathMap["arial"] = "arial.ttf";
m_fontPathMap["arial bold"] = "arialbd.ttf";
m_fontPathMap["tahoma"] = "tahoma.ttf";
m_fontPathMap["tahoma bold"] = "tahomabd.ttf";
m_fontPathMap["verdana"] = "verdana.ttf";
m_fontPathMap["verdana bold"] = "verdanab.ttf";
m_fontPathMap["times new roman"] = "times.ttf";
m_fontPathMap["courier new"] = "cour.ttf";
m_fontPathMap["segoe ui"] = "segoeui.ttf";
return true;
}
void CFontManager::Destroy()
{
m_resolvedPathCache.clear();
m_fontPathMap.clear();
if (m_ftLibrary)
{
FT_Done_FreeType(m_ftLibrary);
m_ftLibrary = nullptr;
}
m_bInitialized = false;
}
std::string CFontManager::ResolveFontPath(const char* faceName)
{
if (!faceName || !faceName[0])
return "";
std::string lowerName = ToLower(faceName);
// 1. Check explicit mappings
auto it = m_fontPathMap.find(lowerName);
std::string fileName;
if (it != m_fontPathMap.end())
fileName = it->second;
else
fileName = lowerName + ".ttf";
// 2. Check local fonts/ directory first
std::string localPath = "fonts/" + fileName;
if (FileExists(localPath))
return localPath;
// 3. Fall back to C:\Windows\Fonts
#ifdef _WIN32
static std::string s_fontsDir;
if (s_fontsDir.empty())
{
char winDir[MAX_PATH];
if (GetWindowsDirectoryA(winDir, MAX_PATH))
s_fontsDir = std::string(winDir) + "\\Fonts\\";
}
if (!s_fontsDir.empty())
{
std::string systemPath = s_fontsDir + fileName;
if (FileExists(systemPath))
return systemPath;
}
// 4. Try .ttc variant if .ttf wasn't found
if (fileName.size() > 4 && fileName.substr(fileName.size() - 4) == ".ttf")
{
std::string ttcName = fileName.substr(0, fileName.size() - 4) + ".ttc";
localPath = "fonts/" + ttcName;
if (FileExists(localPath))
return localPath;
if (!s_fontsDir.empty())
{
std::string systemPath = s_fontsDir + ttcName;
if (FileExists(systemPath))
return systemPath;
}
}
#endif
TraceError("CFontManager::ResolveFontPath - Could not find font: %s", faceName);
return "";
}
FT_Face CFontManager::CreateFace(const char* faceName)
{
if (!m_bInitialized)
{
if (!Initialize())
return nullptr;
}
if (!faceName || !faceName[0])
return nullptr;
std::string lowerName = ToLower(faceName);
// Check resolved path cache (avoids repeated disk stat calls)
std::string path;
auto cacheIt = m_resolvedPathCache.find(lowerName);
if (cacheIt != m_resolvedPathCache.end())
{
path = cacheIt->second;
}
else
{
path = ResolveFontPath(faceName);
if (path.empty())
return nullptr;
m_resolvedPathCache[lowerName] = path;
}
// Create a new FT_Face — caller owns it
FT_Face face = nullptr;
FT_Error err = FT_New_Face(m_ftLibrary, path.c_str(), 0, &face);
if (err != 0 || !face)
{
TraceError("CFontManager::CreateFace - FT_New_Face failed for '%s' (error %d)", path.c_str(), err);
return nullptr;
}
return face;
}

39
src/EterLib/FontManager.h Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#include <ft2build.h>
#include FT_FREETYPE_H
#include <string>
#include <unordered_map>
class CFontManager
{
public:
static CFontManager& Instance();
bool Initialize();
void Destroy();
// Create a NEW FT_Face for the given font name.
// The caller OWNS the returned face and must call FT_Done_Face on it when done.
FT_Face CreateFace(const char* faceName);
FT_Library GetLibrary() const { return m_ftLibrary; }
private:
CFontManager();
~CFontManager();
CFontManager(const CFontManager&) = delete;
CFontManager& operator=(const CFontManager&) = delete;
std::string ResolveFontPath(const char* faceName);
FT_Library m_ftLibrary;
bool m_bInitialized;
// faceName (lowercase) -> file path
std::unordered_map<std::string, std::string> m_fontPathMap;
// faceName (lowercase) -> resolved file system path (caches disk lookups)
std::unordered_map<std::string, std::string> m_resolvedPathCache;
};

View File

@@ -1,6 +1,5 @@
#include "StdAfx.h"
#include "GrpDIB.h"
#include <utf8.h>
CGraphicDib::CGraphicDib()
{
@@ -14,98 +13,30 @@ CGraphicDib::~CGraphicDib()
void CGraphicDib::Initialize()
{
m_hDC=NULL;
m_hBmp=NULL;
m_pvBuf=NULL;
m_width=0;
m_height=0;
m_pvBuf = NULL;
m_width = 0;
m_height = 0;
}
void CGraphicDib::Destroy()
{
if (m_hBmp) DeleteObject(m_hBmp);
if (m_hDC) DeleteDC(m_hDC);
Initialize();
{
delete[] (DWORD*)m_pvBuf;
Initialize();
}
bool CGraphicDib::Create(HDC hDC, int width, int height)
bool CGraphicDib::Create(int width, int height)
{
Destroy();
m_width = width;
m_height = height;
ZeroMemory(&m_bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bmi.bmiHeader.biWidth = m_width;
m_bmi.bmiHeader.biHeight = -m_height;
m_bmi.bmiHeader.biPlanes = 1;
m_bmi.bmiHeader.biBitCount = 32;
m_bmi.bmiHeader.biCompression = BI_RGB;
m_hDC=CreateCompatibleDC(hDC);
if (!m_hDC)
{
assert(!"CGraphicDib::Create CreateCompatibleDC Error");
return false;
}
m_hBmp=CreateDIBSection(m_hDC, &m_bmi, DIB_RGB_COLORS, &m_pvBuf, NULL, 0);
if (!m_hBmp)
{
assert(!"CGraphicDib::Create CreateDIBSection Error");
return false;
}
SelectObject(m_hDC, m_hBmp);
::SetTextColor(m_hDC, RGB(255, 255, 255));
m_pvBuf = new DWORD[width * height];
memset(m_pvBuf, 0, width * height * sizeof(DWORD));
return true;
}
HDC CGraphicDib::GetDCHandle()
{
return m_hDC;
}
void CGraphicDib::SetBkMode(int iBkMode)
{
::SetBkMode(m_hDC, iBkMode);
}
void CGraphicDib::TextOut(int ix, int iy, const char* c_szText)
{
::SetBkColor(m_hDC, 0);
if (!c_szText || !*c_szText)
return;
std::wstring wText = Utf8ToWide(c_szText);
if (!wText.empty())
::TextOutW(m_hDC, ix, iy, wText.c_str(), (int)wText.length());
}
void CGraphicDib::Put(HDC hDC, int x, int y)
{
SetDIBitsToDevice(
hDC,
x,
y,
m_width,
m_height,
0,
0,
0,
m_height,
m_pvBuf,
&m_bmi,
DIB_RGB_COLORS
);
}
void* CGraphicDib::GetPointer()
{
return m_pvBuf;
@@ -119,4 +50,4 @@ int CGraphicDib::GetWidth()
int CGraphicDib::GetHeight()
{
return m_height;
}
}

View File

@@ -1,33 +1,23 @@
#pragma once
class CGraphicDib
class CGraphicDib
{
public:
CGraphicDib();
virtual ~CGraphicDib();
void Destroy();
bool Create(HDC hDC, int width, int height);
void SetBkMode(int iBkMode);
void TextOut(int ix, int iy, const char * c_szText);
void Put(HDC hDC, int x, int y);
void Destroy();
bool Create(int width, int height);
int GetWidth();
int GetHeight();
void* GetPointer();
HDC GetDCHandle();
protected:
void Initialize();
protected:
HDC m_hDC;
HBITMAP m_hBmp;
BITMAPINFO m_bmi;
protected:
int m_width;
int m_height;

View File

@@ -1,9 +1,24 @@
#include "StdAfx.h"
#include "GrpText.h"
#include "FontManager.h"
#include "EterBase/Stl.h"
#include "Util.h"
#include <utf8.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <cmath>
// Gamma LUT to sharpen grayscale anti-aliasing edges.
static struct SAlphaGammaLUT {
unsigned char table[256];
SAlphaGammaLUT() {
table[0] = 0;
for (int i = 1; i < 256; ++i)
table[i] = (unsigned char)(pow(i / 255.0, 0.85) * 255.0 + 0.5);
}
} s_alphaGammaLUT;
CGraphicFontTexture::CGraphicFontTexture()
{
@@ -18,63 +33,91 @@ CGraphicFontTexture::~CGraphicFontTexture()
void CGraphicFontTexture::Initialize()
{
CGraphicTexture::Initialize();
m_hFontOld = NULL;
m_hFont = NULL;
m_ftFace = nullptr;
m_pAtlasBuffer = nullptr;
m_atlasWidth = 0;
m_atlasHeight = 0;
m_isDirty = false;
m_bItalic = false;
m_ascender = 0;
m_lineHeight = 0;
m_hasKerning = false;
m_x = 0;
m_y = 0;
m_step = 0;
m_fontSize = 0;
}
bool CGraphicFontTexture::IsEmpty() const
{
return m_fontMap.size() == 0;
return m_ftFace == nullptr;
}
void CGraphicFontTexture::Destroy()
{
HDC hDC = m_dib.GetDCHandle();
if (hDC)
SelectObject(hDC, m_hFontOld);
m_dib.Destroy();
delete[] m_pAtlasBuffer;
m_pAtlasBuffer = nullptr;
m_lpd3dTexture = NULL;
CGraphicTexture::Destroy();
stl_wipe(m_pFontTextureVector);
m_charInfoMap.clear();
if (m_fontMap.size())
if (m_ftFace)
{
TFontMap::iterator i = m_fontMap.begin();
while(i != m_fontMap.end())
{
DeleteObject((HGDIOBJ)i->second);
++i;
}
m_fontMap.clear();
FT_Done_Face(m_ftFace);
m_ftFace = nullptr;
}
Initialize();
}
bool CGraphicFontTexture::CreateDeviceObjects()
{
if (!m_ftFace)
return true;
// After device reset: wipe GPU textures, clear atlas state, and
// re-render all previously cached characters on demand.
// We keep m_charInfoMap keys but clear the entries so glyphs get re-rasterized.
std::vector<TCharacterKey> cachedKeys;
cachedKeys.reserve(m_charInfoMap.size());
for (const auto& pair : m_charInfoMap)
cachedKeys.push_back(pair.first);
stl_wipe(m_pFontTextureVector);
m_charInfoMap.clear();
m_x = 0;
m_y = 0;
m_step = 0;
m_isDirty = false;
// Reset CPU atlas buffer
if (m_pAtlasBuffer)
memset(m_pAtlasBuffer, 0, m_atlasWidth * m_atlasHeight * sizeof(DWORD));
// Create first GPU texture page
if (!AppendTexture())
return false;
// Re-rasterize all previously cached glyphs
for (TCharacterKey key : cachedKeys)
UpdateCharacterInfomation(key);
UpdateTexture();
return true;
}
void CGraphicFontTexture::DestroyDeviceObjects()
{
m_lpd3dTexture = NULL;
stl_wipe(m_pFontTextureVector);
}
bool CGraphicFontTexture::Create(const char* c_szFontName, int fontSize, bool bItalic)
{
Destroy();
// UTF-8 -> UTF-16 for font name
std::wstring wFontName = Utf8ToWide(c_szFontName ? c_szFontName : "");
wcsncpy_s(m_fontName, wFontName.c_str(), _TRUNCATE);
m_fontSize = fontSize;
m_bItalic = bItalic;
@@ -82,22 +125,54 @@ bool CGraphicFontTexture::Create(const char* c_szFontName, int fontSize, bool bI
m_y = 0;
m_step = 0;
// Determine atlas dimensions
DWORD width = 256, height = 256;
if (GetMaxTextureWidth() > 512)
width = 512;
if (GetMaxTextureHeight() > 512)
height = 512;
if (!m_dib.Create(ms_hDC, width, height))
m_atlasWidth = width;
m_atlasHeight = height;
// Allocate CPU-side atlas buffer
m_pAtlasBuffer = new DWORD[width * height];
memset(m_pAtlasBuffer, 0, width * height * sizeof(DWORD));
// Create a per-instance FT_Face (this instance owns it)
m_ftFace = CFontManager::Instance().CreateFace(c_szFontName);
if (!m_ftFace)
{
TraceError("CGraphicFontTexture::Create - Failed to create face for '%s'", c_szFontName ? c_szFontName : "(null)");
return false;
}
HDC hDC = m_dib.GetDCHandle();
int pixelSize = (fontSize < 0) ? -fontSize : fontSize;
if (pixelSize == 0)
pixelSize = 12;
m_hFont = GetFont();
FT_Set_Pixel_Sizes(m_ftFace, 0, pixelSize);
m_hFontOld = (HFONT)SelectObject(hDC, m_hFont);
SetTextColor(hDC, RGB(255, 255, 255));
SetBkColor(hDC, 0);
m_hasKerning = FT_HAS_KERNING(m_ftFace) != 0;
// Apply italic via shear matrix if needed
if (bItalic)
{
FT_Matrix matrix;
matrix.xx = 0x10000L;
matrix.xy = 0x5800L; // ~0.34 shear for synthetic italic
matrix.yx = 0;
matrix.yy = 0x10000L;
FT_Set_Transform(m_ftFace, &matrix, NULL);
}
else
{
FT_Set_Transform(m_ftFace, NULL, NULL);
}
// Cache font metrics
m_ascender = (int)(m_ftFace->size->metrics.ascender >> 6);
m_lineHeight = (int)(m_ftFace->size->metrics.height >> 6);
if (!AppendTexture())
return false;
@@ -105,48 +180,11 @@ bool CGraphicFontTexture::Create(const char* c_szFontName, int fontSize, bool bI
return true;
}
HFONT CGraphicFontTexture::GetFont()
{
HFONT hFont = nullptr;
// For Unicode, codePage should NOT affect font selection anymore
static const WORD kUnicodeFontKey = 0;
TFontMap::iterator it = m_fontMap.find(kUnicodeFontKey);
if (it != m_fontMap.end())
return it->second;
LOGFONTW logFont{};
logFont.lfHeight = m_fontSize;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = (BYTE)m_bItalic;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = ANTIALIASED_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
// Copy Unicode font face name safely
wcsncpy_s(logFont.lfFaceName, m_fontName, _TRUNCATE);
hFont = CreateFontIndirectW(&logFont);
if (hFont)
m_fontMap.insert(TFontMap::value_type(kUnicodeFontKey, hFont));
return hFont;
}
bool CGraphicFontTexture::AppendTexture()
{
CGraphicImageTexture * pNewTexture = new CGraphicImageTexture;
CGraphicImageTexture* pNewTexture = new CGraphicImageTexture;
if (!pNewTexture->Create(m_dib.GetWidth(), m_dib.GetHeight(), D3DFMT_A4R4G4B4))
if (!pNewTexture->Create(m_atlasWidth, m_atlasHeight, D3DFMT_A8R8G8B8))
{
delete pNewTexture;
return false;
@@ -158,37 +196,53 @@ bool CGraphicFontTexture::AppendTexture()
bool CGraphicFontTexture::UpdateTexture()
{
if(!m_isDirty)
if (!m_isDirty)
return true;
m_isDirty = false;
CGraphicImageTexture * pFontTexture = m_pFontTextureVector.back();
CGraphicImageTexture* pFontTexture = m_pFontTextureVector.back();
if (!pFontTexture)
return false;
WORD* pwDst;
DWORD* pdwDst;
int pitch;
if (!pFontTexture->Lock(&pitch, (void**)&pwDst))
if (!pFontTexture->Lock(&pitch, (void**)&pdwDst))
return false;
pitch /= 2;
pitch /= 4; // pitch in DWORDs (A8R8G8B8 = 4 bytes per pixel)
int width = m_dib.GetWidth();
int height = m_dib.GetHeight();
DWORD* pdwSrc = m_pAtlasBuffer;
DWORD * pdwSrc = (DWORD*)m_dib.GetPointer();
for (int y = 0; y < m_atlasHeight; ++y, pdwDst += pitch, pdwSrc += m_atlasWidth)
{
memcpy(pdwDst, pdwSrc, m_atlasWidth * sizeof(DWORD));
}
for (int y = 0; y < height; ++y, pwDst += pitch, pdwSrc += width)
for (int x = 0; x < width; ++x)
pwDst[x]=pdwSrc[x];
pFontTexture->Unlock();
return true;
}
float CGraphicFontTexture::GetKerning(wchar_t prev, wchar_t cur)
{
if (!m_hasKerning || !m_ftFace || prev == 0)
return 0.0f;
FT_UInt prevIndex = FT_Get_Char_Index(m_ftFace, prev);
FT_UInt curIndex = FT_Get_Char_Index(m_ftFace, cur);
if (prevIndex == 0 || curIndex == 0)
return 0.0f;
FT_Vector delta;
if (FT_Get_Kerning(m_ftFace, prevIndex, curIndex, FT_KERNING_DEFAULT, &delta) != 0)
return 0.0f;
return (float)(delta.x) / 64.0f;
}
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::GetCharacterInfomation(wchar_t keyValue)
{
TCharacterKey code = keyValue;
@@ -207,68 +261,114 @@ CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::GetCharacterInfo
CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterInfomation(TCharacterKey keyValue)
{
HDC hDC = m_dib.GetDCHandle();
SelectObject(hDC, GetFont());
if (keyValue == 0x08)
keyValue = L' '; // 탭은 공백으로 바꾼다 (아랍 출력시 탭 사용: NAME:\tTEXT -> TEXT\t:NAME 로 전환됨 )
ABCFLOAT stABC;
SIZE size;
if (!GetTextExtentPoint32W(hDC, &keyValue, 1, &size) || !GetCharABCWidthsFloatW(hDC, keyValue, keyValue, &stABC))
if (!m_ftFace)
return NULL;
size.cx = stABC.abcfB;
if( stABC.abcfA > 0.0f )
size.cx += ceilf(stABC.abcfA);
if( stABC.abcfC > 0.0f )
size.cx += ceilf(stABC.abcfC);
size.cx++;
if (keyValue == 0x08)
keyValue = L' ';
LONG lAdvance = ceilf( stABC.abcfA + stABC.abcfB + stABC.abcfC );
// Load and render the glyph
FT_UInt glyphIndex = FT_Get_Char_Index(m_ftFace, keyValue);
if (glyphIndex == 0 && keyValue != L' ')
{
// Try space as fallback for unknown characters
glyphIndex = FT_Get_Char_Index(m_ftFace, L' ');
if (glyphIndex == 0)
return NULL;
}
int width = m_dib.GetWidth();
int height = m_dib.GetHeight();
if (FT_Load_Glyph(m_ftFace, glyphIndex, FT_LOAD_TARGET_LCD) != 0)
return NULL;
if (m_x + size.cx >= (width - 1))
if (FT_Render_Glyph(m_ftFace->glyph, FT_RENDER_MODE_LCD) != 0)
return NULL;
FT_GlyphSlot slot = m_ftFace->glyph;
FT_Bitmap& bitmap = slot->bitmap;
int glyphBitmapWidth = bitmap.width / 3; // LCD bitmap is 3x wider (R,G,B per pixel)
int glyphBitmapHeight = bitmap.rows;
int bearingX = slot->bitmap_left;
int bearingY = slot->bitmap_top;
float advance = ceilf((float)(slot->advance.x) / 64.0f);
// Normalize glyph placement to common baseline
// yOffset = distance from atlas row top to where the glyph bitmap starts
int yOffset = m_ascender - bearingY;
if (yOffset < 0)
yOffset = 0;
// The effective cell height is the full line height
int cellHeight = m_lineHeight;
int cellWidth = glyphBitmapWidth;
// For spacing characters (space, etc.)
if (glyphBitmapWidth == 0 || glyphBitmapHeight == 0)
{
TCharacterInfomation& rNewCharInfo = m_charInfoMap[keyValue];
rNewCharInfo.index = static_cast<short>(m_pFontTextureVector.size() - 1);
rNewCharInfo.width = 0;
rNewCharInfo.height = (short)cellHeight;
rNewCharInfo.left = 0;
rNewCharInfo.top = 0;
rNewCharInfo.right = 0;
rNewCharInfo.bottom = 0;
rNewCharInfo.advance = advance;
rNewCharInfo.bearingX = 0.0f;
return &rNewCharInfo;
}
// Make sure cell fits the glyph including offset
int requiredHeight = yOffset + glyphBitmapHeight;
if (requiredHeight > cellHeight)
cellHeight = requiredHeight;
int width = m_atlasWidth;
int height = m_atlasHeight;
// Atlas packing (row-based)
if (m_x + cellWidth >= (width - 1))
{
m_y += (m_step + 1);
m_step = 0;
m_x = 0;
if (m_y + size.cy >= (height - 1))
if (m_y + cellHeight >= (height - 1))
{
if (!UpdateTexture())
{
return NULL;
}
if (!AppendTexture())
return NULL;
// Reset atlas buffer for new texture
memset(m_pAtlasBuffer, 0, m_atlasWidth * m_atlasHeight * sizeof(DWORD));
m_y = 0;
}
}
TextOutW(hDC, m_x, m_y, &keyValue, 1);
int nChrX;
int nChrY;
int nChrWidth = size.cx;
int nChrHeight = size.cy;
int nDIBWidth = m_dib.GetWidth();
DWORD*pdwDIBData=(DWORD*)m_dib.GetPointer();
DWORD*pdwDIBBase=pdwDIBData+nDIBWidth*m_y+m_x;
DWORD*pdwDIBRow;
pdwDIBRow=pdwDIBBase;
for (nChrY=0; nChrY<nChrHeight; ++nChrY, pdwDIBRow+=nDIBWidth)
// Copy LCD subpixel FreeType bitmap into atlas buffer (R,G,B per-channel coverage)
for (int row = 0; row < glyphBitmapHeight; ++row)
{
for (nChrX=0; nChrX<nChrWidth; ++nChrX)
int atlasY = m_y + yOffset + row;
if (atlasY < 0 || atlasY >= height)
continue;
unsigned char* srcRow = bitmap.buffer + row * bitmap.pitch;
DWORD* dstRow = m_pAtlasBuffer + atlasY * m_atlasWidth + m_x;
for (int col = 0; col < glyphBitmapWidth; ++col)
{
pdwDIBRow[nChrX]=(pdwDIBRow[nChrX]&0xff) ? 0xffff : 0;
unsigned char r = srcRow[col * 3 + 0];
unsigned char g = srcRow[col * 3 + 1];
unsigned char b = srcRow[col * 3 + 2];
if (r | g | b)
{
unsigned char a = (r > g) ? r : g;
if (b > a) a = b;
// A8R8G8B8: A=max_coverage, R=r_cov, G=g_cov, B=b_cov
dstRow[col] = ((DWORD)a << 24) | ((DWORD)r << 16) | ((DWORD)g << 8) | (DWORD)b;
}
}
}
@@ -278,18 +378,19 @@ CGraphicFontTexture::TCharacterInfomation* CGraphicFontTexture::UpdateCharacterI
TCharacterInfomation& rNewCharInfo = m_charInfoMap[keyValue];
rNewCharInfo.index = static_cast<short>(m_pFontTextureVector.size() - 1);
rNewCharInfo.width = size.cx;
rNewCharInfo.height = size.cy;
rNewCharInfo.width = (short)cellWidth;
rNewCharInfo.height = (short)cellHeight;
rNewCharInfo.left = float(m_x) * rhwidth;
rNewCharInfo.top = float(m_y) * rhheight;
rNewCharInfo.right = float(m_x+size.cx) * rhwidth;
rNewCharInfo.bottom = float(m_y+size.cy) * rhheight;
rNewCharInfo.advance = (float) lAdvance;
rNewCharInfo.right = float(m_x + cellWidth) * rhwidth;
rNewCharInfo.bottom = float(m_y + cellHeight) * rhheight;
rNewCharInfo.advance = advance;
rNewCharInfo.bearingX = (float)bearingX;
m_x += size.cx;
m_x += cellWidth + 1; // +1 horizontal padding to prevent bilinear bleed
if (m_step < size.cy)
m_step = size.cy;
if (m_step < cellHeight)
m_step = cellHeight;
m_isDirty = true;

View File

@@ -2,7 +2,9 @@
#include "GrpTexture.h"
#include "GrpImageTexture.h"
#include "GrpDIB.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include <vector>
#include <map>
@@ -22,6 +24,7 @@ class CGraphicFontTexture : public CGraphicTexture
float right;
float bottom;
float advance;
float bearingX;
} TCharacterInfomation;
typedef std::vector<TCharacterInfomation*> TPCharacterInfomationVector;
@@ -44,6 +47,8 @@ class CGraphicFontTexture : public CGraphicTexture
TCharacterInfomation* GetCharacterInfomation(wchar_t keyValue);
TCharacterInfomation* UpdateCharacterInfomation(TCharacterKey keyValue);
float GetKerning(wchar_t prev, wchar_t cur);
bool IsEmpty() const;
protected:
@@ -51,31 +56,32 @@ class CGraphicFontTexture : public CGraphicTexture
bool AppendTexture();
HFONT GetFont();
protected:
typedef std::vector<CGraphicImageTexture*> TGraphicImageTexturePointerVector;
typedef std::map<TCharacterKey, TCharacterInfomation> TCharacterInfomationMap;
typedef std::map<WORD, HFONT> TFontMap;
protected:
CGraphicDib m_dib;
FT_Face m_ftFace;
HFONT m_hFontOld;
HFONT m_hFont;
// CPU-side atlas buffer (replaces CGraphicDib)
DWORD* m_pAtlasBuffer;
int m_atlasWidth;
int m_atlasHeight;
TGraphicImageTexturePointerVector m_pFontTextureVector;
TCharacterInfomationMap m_charInfoMap;
TFontMap m_fontMap;
int m_x;
int m_y;
int m_step;
bool m_isDirty;
TCHAR m_fontName[LF_FACESIZE];
LONG m_fontSize;
bool m_bItalic;
// FreeType metrics cached per-font
int m_ascender;
int m_lineHeight;
bool m_hasKerning;
};

View File

@@ -33,7 +33,7 @@ CGraphicText::TType CGraphicText::Type()
bool CGraphicText::OnLoad(int /*iSize*/, const void* /*c_pvBuf*/)
{
static char strName[32];
char strName[32];
int size;
bool bItalic = false;
@@ -45,10 +45,12 @@ bool CGraphicText::OnLoad(int /*iSize*/, const void* /*c_pvBuf*/)
if (p)
{
strncpy(strName, GetFileName(), MIN(31, p - GetFileName()));
int nameLen = MIN(31, (int)(p - GetFileName()));
strncpy(strName, GetFileName(), nameLen);
strName[nameLen] = '\0';
++p;
static char num[8];
char num[8];
int i = 0;
while (*p && isdigit(*p))
@@ -71,8 +73,12 @@ bool CGraphicText::OnLoad(int /*iSize*/, const void* /*c_pvBuf*/)
strName[0] = '\0';
}
else
strncpy(strName, GetFileName(), MIN(31, p - GetFileName()));
{
int nameLen = MIN(31, (int)(p - GetFileName()));
strncpy(strName, GetFileName(), nameLen);
strName[nameLen] = '\0';
}
size = 12;
}

View File

@@ -38,18 +38,23 @@ int CGraphicTextInstance::Hyperlink_GetText(char* buf, int len)
return (written > 0) ? written : 0;
}
int CGraphicTextInstance::__DrawCharacter(CGraphicFontTexture * pFontTexture, wchar_t text, DWORD dwColor)
int CGraphicTextInstance::__DrawCharacter(CGraphicFontTexture * pFontTexture, wchar_t text, DWORD dwColor, wchar_t prevChar)
{
CGraphicFontTexture::TCharacterInfomation* pInsCharInfo = pFontTexture->GetCharacterInfomation(text);
if (pInsCharInfo)
{
// Round kerning to nearest pixel to keep glyphs on the pixel grid.
// Fractional offsets cause bilinear interpolation blur in D3D9.
float kern = floorf(pFontTexture->GetKerning(prevChar, text) + 0.5f);
m_dwColorInfoVector.push_back(dwColor);
m_pCharInfoVector.push_back(pInsCharInfo);
m_kernVector.push_back(kern);
m_textWidth += pInsCharInfo->advance;
m_textWidth += (int)(pInsCharInfo->advance + kern);
m_textHeight = std::max((WORD)pInsCharInfo->height, m_textHeight);
return pInsCharInfo->advance;
return (int)(pInsCharInfo->advance + kern);
}
return 0;
@@ -99,6 +104,7 @@ void CGraphicTextInstance::Update()
auto ResetState = [&, spaceHeight]()
{
m_pCharInfoVector.clear();
m_kernVector.clear();
m_dwColorInfoVector.clear();
m_hyperlinkVector.clear();
m_textWidth = 0;
@@ -121,6 +127,7 @@ void CGraphicTextInstance::Update()
}
m_pCharInfoVector.clear();
m_kernVector.clear();
m_dwColorInfoVector.clear();
m_hyperlinkVector.clear();
@@ -154,8 +161,12 @@ void CGraphicTextInstance::Update()
// Secret mode: draw '*' instead of actual characters
if (m_isSecret)
{
wchar_t prevCh = 0;
for (int i = 0; i < wTextLen; ++i)
__DrawCharacter(pFontTexture, L'*', dwColor);
{
__DrawCharacter(pFontTexture, L'*', dwColor, prevCh);
prevCh = L'*';
}
pFontTexture->UpdateTexture();
m_isUpdate = true;
@@ -183,8 +194,12 @@ void CGraphicTextInstance::Update()
wMsg.data(), (int)wMsg.size(),
m_computedRTL);
wchar_t prevCh = 0;
for (size_t i = 0; i < visual.size(); ++i)
__DrawCharacter(pFontTexture, visual[i], dwColor);
{
__DrawCharacter(pFontTexture, visual[i], dwColor, prevCh);
prevCh = visual[i];
}
pFontTexture->UpdateTexture();
m_isUpdate = true;
@@ -245,8 +260,7 @@ void CGraphicTextInstance::Update()
int hyperlinkStep = 0; // 0=normal, 1=collecting metadata, 2=visible hyperlink
std::wstring hyperlinkMetadata;
// Use thread-local buffer to avoid per-call allocation
thread_local static std::vector<wchar_t> s_currentSegment;
static std::vector<wchar_t> s_currentSegment;
s_currentSegment.clear();
SHyperlink currentHyperlink;
@@ -267,10 +281,12 @@ void CGraphicTextInstance::Update()
std::vector<wchar_t> visual = BuildVisualBidiText_Tagless(
s_currentSegment.data(), (int)s_currentSegment.size(), forceRTLForBidi);
wchar_t prevCh = m_pCharInfoVector.empty() ? 0 : 0; // no prev across segments
for (size_t j = 0; j < visual.size(); ++j)
{
int w = __DrawCharacter(pFontTexture, visual[j], segColor);
int w = __DrawCharacter(pFontTexture, visual[j], segColor, prevCh);
totalWidth += w;
prevCh = visual[j];
}
s_currentSegment.clear();
@@ -285,13 +301,15 @@ void CGraphicTextInstance::Update()
{
outWidth = 0;
// Use thread-local buffers to avoid allocation
thread_local static std::vector<CGraphicFontTexture::TCharacterInfomation*> s_newCharInfos;
thread_local static std::vector<DWORD> s_newColors;
static std::vector<CGraphicFontTexture::TCharacterInfomation*> s_newCharInfos;
static std::vector<DWORD> s_newColors;
static std::vector<float> s_newKerns;
s_newCharInfos.clear();
s_newColors.clear();
s_newKerns.clear();
s_newCharInfos.reserve(chars.size());
s_newColors.reserve(chars.size());
s_newKerns.reserve(chars.size());
for (size_t k = 0; k < chars.size(); ++k)
{
@@ -301,16 +319,16 @@ void CGraphicTextInstance::Update()
s_newCharInfos.push_back(pInfo);
s_newColors.push_back(color);
s_newKerns.push_back(0.0f);
outWidth += pInfo->advance;
m_textHeight = std::max((WORD)pInfo->height, m_textHeight);
}
// Insert at the beginning of the draw list.
m_pCharInfoVector.insert(m_pCharInfoVector.begin(), s_newCharInfos.begin(), s_newCharInfos.end());
m_dwColorInfoVector.insert(m_dwColorInfoVector.begin(), s_newColors.begin(), s_newColors.end());
m_kernVector.insert(m_kernVector.begin(), s_newKerns.begin(), s_newKerns.end());
// Shift any already-recorded hyperlinks to the right.
for (auto& link : m_hyperlinkVector)
{
link.sx += outWidth;
@@ -366,7 +384,7 @@ void CGraphicTextInstance::Update()
if (!s_currentSegment.empty())
{
// OPTIMIZED: Use thread-local buffer for visible rendering
thread_local static std::vector<wchar_t> s_visibleToRender;
static std::vector<wchar_t> s_visibleToRender;
s_visibleToRender.clear();
// Find bracket positions: [ ... ]
@@ -385,7 +403,7 @@ void CGraphicTextInstance::Update()
s_visibleToRender.push_back(L'[');
// Extract inside content and apply BiDi
thread_local static std::vector<wchar_t> s_content;
static std::vector<wchar_t> s_content;
s_content.assign(
s_currentSegment.begin() + openBracket + 1,
s_currentSegment.begin() + closeBracket);
@@ -430,10 +448,12 @@ void CGraphicTextInstance::Update()
{
// LTR or non-chat: keep original "append" behavior
currentHyperlink.sx = currentHyperlink.ex;
wchar_t prevCh = 0;
for (size_t j = 0; j < s_visibleToRender.size(); ++j)
{
int w = __DrawCharacter(pFontTexture, s_visibleToRender[j], currentColor);
int w = __DrawCharacter(pFontTexture, s_visibleToRender[j], currentColor, prevCh);
currentHyperlink.ex += w;
prevCh = s_visibleToRender[j];
}
m_hyperlinkVector.push_back(currentHyperlink);
}
@@ -471,8 +491,14 @@ void CGraphicTextInstance::Update()
// Simple LTR rendering for plain text (no tags, no RTL)
// Just draw characters in logical order
for (int i = 0; i < wTextLen; ++i)
__DrawCharacter(pFontTexture, wTextBuf[i], dwColor);
{
wchar_t prevCh = 0;
for (int i = 0; i < wTextLen; ++i)
{
__DrawCharacter(pFontTexture, wTextBuf[i], dwColor, prevCh);
prevCh = wTextBuf[i];
}
}
pFontTexture->UpdateTexture();
m_isUpdate = true;
@@ -533,10 +559,10 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
break;
}
static std::unordered_map<LPDIRECT3DTEXTURE9, std::vector<SVertex>> s_vtxBatches;
for (auto& [pTexture, vtxBatch] : s_vtxBatches) {
vtxBatch.clear();
}
static std::unordered_map<LPDIRECT3DTEXTURE9, std::vector<SVertex>> s_outlineBatches;
static std::unordered_map<LPDIRECT3DTEXTURE9, std::vector<SVertex>> s_mainBatches;
s_outlineBatches.clear();
s_mainBatches.clear();
STATEMANAGER.SaveRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
STATEMANAGER.SaveRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
@@ -553,6 +579,10 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
// LCD subpixel rendering: mask alpha writes to prevent corruption during two-pass blending
STATEMANAGER.SaveRenderState(D3DRS_COLORWRITEENABLE,
D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);
{
const float fFontHalfWeight=1.0f;
@@ -582,13 +612,18 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
fCurY=fStanY;
fFontMaxHeight=0.0f;
int charIdx = 0;
CGraphicFontTexture::TPCharacterInfomationVector::iterator i;
for (i=m_pCharInfoVector.begin(); i!=m_pCharInfoVector.end(); ++i)
for (i=m_pCharInfoVector.begin(); i!=m_pCharInfoVector.end(); ++i, ++charIdx)
{
pCurCharInfo = *i;
float fKern = (charIdx < (int)m_kernVector.size()) ? m_kernVector[charIdx] : 0.0f;
fCurX += fKern;
fFontWidth=float(pCurCharInfo->width);
fFontHeight=float(pCurCharInfo->height);
fFontMaxHeight=(std::max)(fFontMaxHeight, fFontHeight);
fFontAdvance=float(pCurCharInfo->advance);
if ((fCurX+fFontWidth)-m_v3Position.x > m_fLimitWidth) [[unlikely]] {
@@ -612,13 +647,13 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
}
}
fFontSx = fCurX - 0.5f;
fFontSx = fCurX + pCurCharInfo->bearingX - 0.5f;
fFontSy = fCurY - 0.5f;
fFontEx = fFontSx + fFontWidth;
fFontEy = fFontSy + fFontHeight;
pFontTexture->SelectTexture(pCurCharInfo->index);
std::vector<SVertex>& vtxBatch = s_vtxBatches[pFontTexture->GetD3DTexture()];
std::vector<SVertex>& vtxBatch = s_outlineBatches[pFontTexture->GetD3DTexture()];
akVertex[0].u=pCurCharInfo->left;
akVertex[0].v=pCurCharInfo->top;
@@ -644,7 +679,8 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
akVertex[2].x=fFontEx-fFontHalfWeight+feather;
akVertex[3].x=fFontEx-fFontHalfWeight+feather;
vtxBatch.insert(vtxBatch.end(), std::begin(akVertex), std::end(akVertex));
vtxBatch.push_back(akVertex[0]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[2]);
vtxBatch.push_back(akVertex[2]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[3]);
// 오른
akVertex[0].x=fFontSx+fFontHalfWeight-feather;
@@ -652,7 +688,8 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
akVertex[2].x=fFontEx+fFontHalfWeight+feather;
akVertex[3].x=fFontEx+fFontHalfWeight+feather;
vtxBatch.insert(vtxBatch.end(), std::begin(akVertex), std::end(akVertex));
vtxBatch.push_back(akVertex[0]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[2]);
vtxBatch.push_back(akVertex[2]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[3]);
akVertex[0].x=fFontSx-feather;
akVertex[1].x=fFontSx-feather;
@@ -665,7 +702,8 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
akVertex[2].y=fFontSy-fFontHalfWeight-feather;
akVertex[3].y=fFontEy-fFontHalfWeight+feather;
vtxBatch.insert(vtxBatch.end(), std::begin(akVertex), std::end(akVertex));
vtxBatch.push_back(akVertex[0]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[2]);
vtxBatch.push_back(akVertex[2]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[3]);
// 아래
akVertex[0].y=fFontSy+fFontHalfWeight-feather;
@@ -673,7 +711,8 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
akVertex[2].y=fFontSy+fFontHalfWeight-feather;
akVertex[3].y=fFontEy+fFontHalfWeight+feather;
vtxBatch.insert(vtxBatch.end(), std::begin(akVertex), std::end(akVertex));
vtxBatch.push_back(akVertex[0]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[2]);
vtxBatch.push_back(akVertex[2]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[3]);
fCurX += fFontAdvance;
}
@@ -683,13 +722,16 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
fCurY=fStanY;
fFontMaxHeight=0.0f;
for (int i = 0; i < m_pCharInfoVector.size(); ++i)
for (int i = 0; i < (int)m_pCharInfoVector.size(); ++i)
{
pCurCharInfo = m_pCharInfoVector[i];
float fKern = (i < (int)m_kernVector.size()) ? m_kernVector[i] : 0.0f;
fCurX += fKern;
fFontWidth=float(pCurCharInfo->width);
fFontHeight=float(pCurCharInfo->height);
fFontMaxHeight=(std::max)(fFontHeight, (float)pCurCharInfo->height);
fFontMaxHeight=(std::max)(fFontMaxHeight, fFontHeight);
fFontAdvance=float(pCurCharInfo->advance);
if ((fCurX + fFontWidth) - m_v3Position.x > m_fLimitWidth) [[unlikely]] {
@@ -713,13 +755,13 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
}
}
fFontSx = fCurX-0.5f;
fFontSx = fCurX + pCurCharInfo->bearingX - 0.5f;
fFontSy = fCurY-0.5f;
fFontEx = fFontSx + fFontWidth;
fFontEy = fFontSy + fFontHeight;
pFontTexture->SelectTexture(pCurCharInfo->index);
std::vector<SVertex>& vtxBatch = s_vtxBatches[pFontTexture->GetD3DTexture()];
std::vector<SVertex>& vtxBatch = s_mainBatches[pFontTexture->GetD3DTexture()];
akVertex[0].x=fFontSx;
akVertex[0].y=fFontSy;
@@ -743,7 +785,8 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
akVertex[0].color = akVertex[1].color = akVertex[2].color = akVertex[3].color = m_dwColorInfoVector[i];
vtxBatch.insert(vtxBatch.end(), std::begin(akVertex), std::end(akVertex));
vtxBatch.push_back(akVertex[0]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[2]);
vtxBatch.push_back(akVertex[2]); vtxBatch.push_back(akVertex[1]); vtxBatch.push_back(akVertex[3]);
fCurX += fFontAdvance;
}
@@ -822,13 +865,46 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
}
}
for (const auto& [pTexture, vtxBatch] : s_vtxBatches) {
if (vtxBatch.empty())
continue;
// LCD subpixel two-pass rendering: correct per-channel alpha blending
auto DrawBatchLCD = [](const std::unordered_map<LPDIRECT3DTEXTURE9, std::vector<SVertex>>& batches, bool skipPass2) {
for (const auto& [pTexture, vtxBatch] : batches) {
if (vtxBatch.empty())
continue;
STATEMANAGER.SetTexture(0, pTexture);
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, vtxBatch.size() - 2, vtxBatch.data(), sizeof(SVertex));
}
STATEMANAGER.SetTexture(0, pTexture);
// Pass 1: dest.rgb *= (1 - coverage.rgb)
STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLELIST,
vtxBatch.size() / 3, vtxBatch.data(), sizeof(SVertex));
if (!skipPass2) {
// Pass 2: dest.rgb += textColor.rgb * coverage.rgb
STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLELIST,
vtxBatch.size() / 3, vtxBatch.data(), sizeof(SVertex));
}
}
};
// Draw outline batches first (skip Pass 2 for black outlines — MODULATE with black = 0)
bool outlineIsBlack = ((m_dwOutLineColor & 0x00FFFFFF) == 0);
DrawBatchLCD(s_outlineBatches, outlineIsBlack);
// Draw main text batches (always both passes)
DrawBatchLCD(s_mainBatches, false);
if (m_isCursor)
{
@@ -936,6 +1012,7 @@ void CGraphicTextInstance::Render(RECT * pClipRect)
}
}
STATEMANAGER.RestoreRenderState(D3DRS_COLORWRITEENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_SRCBLEND);
STATEMANAGER.RestoreRenderState(D3DRS_DESTBLEND);
@@ -1264,6 +1341,7 @@ void CGraphicTextInstance::Destroy()
{
m_stText="";
m_pCharInfoVector.clear();
m_kernVector.clear();
m_dwColorInfoVector.clear();
m_hyperlinkVector.clear();
m_logicalToVisualPos.clear();

View File

@@ -90,7 +90,7 @@ class CGraphicTextInstance
protected:
void __Initialize();
int __DrawCharacter(CGraphicFontTexture * pFontTexture, wchar_t text, DWORD dwColor);
int __DrawCharacter(CGraphicFontTexture * pFontTexture, wchar_t text, DWORD dwColor, wchar_t prevChar = 0);
void __GetTextPos(DWORD index, float* x, float* y);
protected:
@@ -130,7 +130,6 @@ class CGraphicTextInstance
private:
bool m_isUpdate;
bool m_isUpdateFontTexture;
bool m_computedRTL; // Result of BiDi analysis (used when m_direction == Auto)
bool m_isChatMessage; // True if this text was set via SetChatValue (has separated name/message)
std::string m_chatName; // Chat sender name (only used when m_isChatMessage is true)
@@ -138,6 +137,7 @@ class CGraphicTextInstance
CGraphicText::TRef m_roText;
CGraphicFontTexture::TPCharacterInfomationVector m_pCharInfoVector;
std::vector<float> m_kernVector;
std::vector<DWORD> m_dwColorInfoVector;
std::vector<SHyperlink> m_hyperlinkVector;
std::vector<int> m_logicalToVisualPos; // Maps logical cursor pos (UTF-16 with tags) to visual pos (rendered chars)

View File

@@ -1,99 +0,0 @@
#include "StdAfx.h"
#include "NetDatagram.h"
CNetworkDatagram::CNetworkDatagram()
{
__Initialize();
}
CNetworkDatagram::~CNetworkDatagram()
{
Destroy();
}
void CNetworkDatagram::Destroy()
{
if (INVALID_SOCKET==m_sock)
return;
closesocket(m_sock);
__Initialize();
}
bool CNetworkDatagram::Create(UINT uPort)
{
assert(INVALID_SOCKET==m_sock);
m_sock = socket(AF_INET, SOCK_DGRAM, 0);
DWORD arg = 1;
ioctlsocket(m_sock, FIONBIO, &arg); // Non-blocking mode
SOCKADDR_IN sockAddrIn;
memset(&sockAddrIn, 0, sizeof(SOCKADDR_IN));
sockAddrIn.sin_family = AF_INET;
sockAddrIn.sin_addr.s_addr = INADDR_ANY;
sockAddrIn.sin_port = htons(uPort);
if (SOCKET_ERROR == bind(m_sock, (PSOCKADDR)&sockAddrIn, sizeof(SOCKADDR_IN)))
{
return false;
}
return true;
}
#pragma warning(push)
#pragma warning(disable:4127)
void CNetworkDatagram::Update()
{
if (m_sock == INVALID_SOCKET)
return;
FD_ZERO(&m_fdsRecv);
FD_ZERO(&m_fdsSend);
FD_SET(m_sock, &m_fdsRecv);
FD_SET(m_sock, &m_fdsSend);
TIMEVAL delay;
delay.tv_sec = 0;
delay.tv_usec = 0;
if (select(0, &m_fdsRecv, &m_fdsSend, NULL, &delay) == SOCKET_ERROR)
return;
}
#pragma warning(pop)
bool CNetworkDatagram::CanRecv()
{
if (FD_ISSET(m_sock, &m_fdsRecv))
return true;
return false;
}
int CNetworkDatagram::PeekRecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn)
{
int nSockAddrInLen=sizeof(SOCKADDR_IN);
return recvfrom(m_sock, (char*)pvBuf, uBufLen, MSG_PEEK, (PSOCKADDR)pkSockAddrIn, &nSockAddrInLen);
}
int CNetworkDatagram::RecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn)
{
int nSockAddrInLen=sizeof(SOCKADDR_IN);
return recvfrom(m_sock, (char*)pvBuf, uBufLen, 0, (PSOCKADDR)pkSockAddrIn, &nSockAddrInLen);
}
int CNetworkDatagram::SendTo(UINT uBufLen, const void* c_pvBuf, const SOCKADDR_IN& c_rkSockAddrIn)
{
return sendto(m_sock, (const char *)c_pvBuf, uBufLen, 0, (PSOCKADDR)&c_rkSockAddrIn, sizeof(SOCKADDR_IN));
}
void CNetworkDatagram::__Initialize()
{
m_sock=INVALID_SOCKET;
}

View File

@@ -1,28 +0,0 @@
#pragma once
class CNetworkDatagram
{
public:
CNetworkDatagram();
virtual ~CNetworkDatagram();
void Destroy();
bool Create(UINT uPort);
void Update();
bool CanRecv();
int PeekRecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn);
int RecvFrom(UINT uBufLen, void* pvBuf, SOCKADDR_IN* pkSockAddrIn);
int SendTo(UINT uBufLen, const void* c_pvBuf, const SOCKADDR_IN& c_rkSockAddrIn);
private:
void __Initialize();
private:
SOCKET m_sock;
fd_set m_fdsRecv;
fd_set m_fdsSend;
};

View File

@@ -1,105 +0,0 @@
#include "StdAfx.h"
#include "NetDatagramReceiver.h"
BOOL CNetDatagramReceiver::Process()
{
m_recvBufCurrentPos = 0;
m_recvBufCurrentSize = 0;
int irecvAddrLength = sizeof(SOCKADDR_IN);
m_recvBufCurrentSize = recvfrom(m_Socket, (char *)m_recvBuf, m_recvBufSize, 0, (PSOCKADDR)&m_SockAddr, &irecvAddrLength);
if (m_recvBufCurrentSize <= 0)
{
return FALSE;
}
return TRUE;
}
BOOL CNetDatagramReceiver::Recv(void * pBuffer, int iSize)
{
if (!Peek(pBuffer, iSize))
return FALSE;
m_recvBufCurrentPos += iSize;
return TRUE;
}
BOOL CNetDatagramReceiver::Peek(void * pBuffer, int iSize)
{
if (m_recvBufCurrentSize < m_recvBufCurrentPos+iSize)
return FALSE;
memcpy(pBuffer, m_recvBuf + m_recvBufCurrentPos, iSize);
return TRUE;
}
BOOL CNetDatagramReceiver::isBind()
{
return m_isBind;
}
BOOL CNetDatagramReceiver::Bind(DWORD /*dwAddress*/, WORD wPortIndex)
{
m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
DWORD arg = 1;
ioctlsocket(m_Socket, FIONBIO, &arg); // Non-blocking mode
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
m_SockAddr.sin_family = AF_INET;
// m_SockAddr.sin_addr.s_addr = dwAddress;
m_SockAddr.sin_addr.s_addr = INADDR_ANY;
m_SockAddr.sin_port = htons(wPortIndex);
if (bind(m_Socket, (PSOCKADDR)&m_SockAddr, sizeof(SOCKADDR_IN)) < 0)
{
Tracef("Failed binding socket\n");
return FALSE;
}
m_isBind = TRUE;
return TRUE;
}
void CNetDatagramReceiver::SetRecvBufferSize(int recvBufSize)
{
if (m_recvBuf)
{
if (m_recvBufSize>recvBufSize)
return;
delete [] m_recvBuf;
}
m_recvBufSize=recvBufSize;
m_recvBuf=new char[m_recvBufSize];
}
void CNetDatagramReceiver::Clear()
{
m_isBind = FALSE;
m_dwPortIndex = 1000;
m_Socket = 0;
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
m_recvBufCurrentPos = 0;
m_recvBufCurrentSize = 0;
}
CNetDatagramReceiver::CNetDatagramReceiver()
{
m_recvBuf = NULL;
m_recvBufSize = 0;
Clear();
}
CNetDatagramReceiver::~CNetDatagramReceiver()
{
if (m_recvBuf)
delete [] m_recvBuf;
}

View File

@@ -1,36 +0,0 @@
#pragma once
#ifndef VC_EXTRALEAN
class CNetDatagramReceiver
{
public:
CNetDatagramReceiver();
virtual ~CNetDatagramReceiver();
void Clear();
BOOL Bind(DWORD dwAddress, WORD wPortIndex);
BOOL isBind();
BOOL Process();
BOOL Recv(void * pBuffer, int iSize);
BOOL Peek(void * pBuffer, int iSize);
void SetRecvBufferSize(int recvBufSize);
protected:
BOOL m_isBind;
DWORD m_dwPortIndex;
SOCKET m_Socket;
SOCKADDR_IN m_SockAddr;
int m_recvBufCurrentPos;
int m_recvBufCurrentSize;
char* m_recvBuf;
int m_recvBufSize;
};
#endif

View File

@@ -1,58 +0,0 @@
#include "StdAfx.h"
#include "NetDatagramSender.h"
BOOL CNetDatagramSender::SetSocket(const char * c_szIP, WORD wPortIndex)
{
return SetSocket(inet_addr(c_szIP), wPortIndex);
}
BOOL CNetDatagramSender::SetSocket(DWORD dwAddress, WORD wPortIndex)
{
m_isSocket = TRUE;
m_dwAddress = dwAddress;
m_wPortIndex = wPortIndex;
m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
m_SockAddr.sin_family = AF_INET;
m_SockAddr.sin_addr.s_addr = dwAddress;
m_SockAddr.sin_port = htons(wPortIndex);
return TRUE;
}
BOOL CNetDatagramSender::Send(const void * pBuffer, int iSize)
{
assert(isSocket());
int iSendingLength = sendto(m_Socket, (const char *)pBuffer, iSize, 0, (PSOCKADDR)&m_SockAddr, sizeof(SOCKADDR_IN));
if (iSendingLength < 0)
{
Tracef("Failed sending packet\n");
return FALSE;
}
return TRUE;
}
BOOL CNetDatagramSender::isSocket()
{
return m_isSocket;
}
CNetDatagramSender::CNetDatagramSender()
{
m_isSocket = FALSE;
m_dwAddress = 0;
m_wPortIndex = 1000;
m_Socket = 0;
memset(&m_SockAddr, 0, sizeof(SOCKADDR_IN));
}
CNetDatagramSender::~CNetDatagramSender()
{
}

View File

@@ -1,27 +0,0 @@
#pragma once
#ifndef VC_EXTRALEAN
class CNetDatagramSender
{
public:
CNetDatagramSender();
virtual ~CNetDatagramSender();
BOOL isSocket();
BOOL SetSocket(const char * c_szIP, WORD wPortIndex);
BOOL SetSocket(DWORD dwAddress, WORD wPortIndex);
BOOL Send(const void * pBuffer, int iSize);
protected:
BOOL m_isSocket;
WORD m_dwAddress;
WORD m_wPortIndex;
SOCKET m_Socket;
SOCKADDR_IN m_SockAddr;
};
#endif

View File

@@ -7,14 +7,12 @@ class CNetworkPacketHeaderMap
public:
typedef struct SPacketType
{
SPacketType(int iSize = 0, bool bFlag = false)
SPacketType(int iSize = 0)
: iPacketSize(iSize)
{
iPacketSize = iSize;
isDynamicSizePacket = bFlag;
}
int iPacketSize;
bool isDynamicSizePacket;
int iPacketSize; // Expected/minimum packet size (actual size from wire length field)
} TPacketType;
public:

View File

@@ -7,6 +7,11 @@
#define _PACKETDUMP
#endif
#ifdef _PACKETDUMP
#include <unordered_map>
#include "../UserInterface/Packet.h"
#endif
bool CNetworkStream::IsSecurityMode()
{
return m_secureCipher.IsActivated();
@@ -14,58 +19,29 @@ bool CNetworkStream::IsSecurityMode()
void CNetworkStream::DecryptPendingRecvData()
{
int remaining = m_recvBufInputPos - m_recvBufOutputPos;
size_t remaining = m_recvBuf.ReadableBytes();
if (remaining > 0 && m_secureCipher.IsActivated())
{
m_secureCipher.DecryptInPlace(m_recvBuf + m_recvBufOutputPos, remaining);
}
m_secureCipher.DecryptInPlace(m_recvBuf.DataAt(m_recvBuf.ReadPos()), remaining);
}
void CNetworkStream::SetRecvBufferSize(int recvBufSize)
{
if (m_recvBuf)
{
if (m_recvBufSize > recvBufSize)
return;
delete [] m_recvBuf;
}
m_recvBufSize = recvBufSize;
m_recvBuf = new char[m_recvBufSize];
m_recvBuf.Reserve(static_cast<size_t>(recvBufSize));
}
void CNetworkStream::SetSendBufferSize(int sendBufSize)
{
if (m_sendBuf)
{
if (m_sendBufSize > sendBufSize)
return;
delete [] m_sendBuf;
}
m_sendBufSize = sendBufSize;
m_sendBuf = new char[m_sendBufSize];
m_sendBuf.Reserve(static_cast<size_t>(sendBufSize));
}
bool CNetworkStream::__RecvInternalBuffer()
{
if (m_recvBufOutputPos > 0)
{
int recvBufDataSize = m_recvBufInputPos - m_recvBufOutputPos;
if (recvBufDataSize > 0)
{
memmove(m_recvBuf, m_recvBuf + m_recvBufOutputPos, recvBufDataSize);
}
m_recvBuf.EnsureWritable(4096);
m_recvBufInputPos -= m_recvBufOutputPos;
m_recvBufOutputPos = 0;
}
int restSize = m_recvBufSize - m_recvBufInputPos;
int restSize = static_cast<int>(m_recvBuf.WritableBytes());
if (restSize > 0)
{
int recvSize = recv(m_sock, m_recvBuf + m_recvBufInputPos, restSize, 0);
int recvSize = recv(m_sock, reinterpret_cast<char*>(m_recvBuf.WritePtr()), restSize, 0);
if (recvSize < 0)
{
@@ -80,47 +56,33 @@ bool CNetworkStream::__RecvInternalBuffer()
else
{
if (m_secureCipher.IsActivated())
{
m_secureCipher.DecryptInPlace(m_recvBuf + m_recvBufInputPos, recvSize);
}
m_recvBufInputPos += recvSize;
m_secureCipher.DecryptInPlace(m_recvBuf.WritePtr(), recvSize);
m_recvBuf.CommitWrite(recvSize);
}
}
return true;
}
bool CNetworkStream::__SendInternalBuffer()
{
int dataSize = __GetSendBufferSize();
if (dataSize <= 0)
return true;
int sendSize = send(m_sock, m_sendBuf + m_sendBufOutputPos, dataSize, 0);
int sendSize = send(m_sock, reinterpret_cast<const char*>(m_sendBuf.ReadPtr()), dataSize, 0);
if (sendSize < 0)
return false;
m_sendBufOutputPos += sendSize;
__PopSendBuffer();
return true;
}
void CNetworkStream::__PopSendBuffer()
{
if (m_sendBufOutputPos <= 0)
return;
int sendBufDataSize = m_sendBufInputPos - m_sendBufOutputPos;
if (sendBufDataSize > 0)
{
memmove(m_sendBuf, m_sendBuf + m_sendBufOutputPos, sendBufDataSize);
int err = WSAGetLastError();
TraceError("__SendInternalBuffer: send() failed, sock=%llu, dataSize=%d, error=%d",
(unsigned long long)m_sock, dataSize, err);
return false;
}
m_sendBufInputPos = sendBufDataSize;
m_sendBufOutputPos = 0;
m_sendBuf.Discard(sendSize);
return true;
}
#pragma warning(push)
@@ -163,7 +125,7 @@ void CNetworkStream::Process()
return;
}
if (FD_ISSET(m_sock, &fdsSend) && (m_sendBufInputPos > m_sendBufOutputPos))
if (FD_ISSET(m_sock, &fdsSend) && (m_sendBuf.ReadableBytes() > 0))
{
if (!__SendInternalBuffer())
{
@@ -206,24 +168,20 @@ void CNetworkStream::Disconnect()
void CNetworkStream::Clear()
{
if (m_sock == INVALID_SOCKET)
return;
// Always clean cipher state (erase key material promptly)
m_secureCipher.CleanUp();
closesocket(m_sock);
m_sock = INVALID_SOCKET;
if (m_sock != INVALID_SOCKET)
{
closesocket(m_sock);
m_sock = INVALID_SOCKET;
}
m_isOnline = false;
m_connectLimitTime = 0;
m_recvBufInputPos = 0;
m_recvBufOutputPos = 0;
m_sendBufInputPos = 0;
m_sendBufOutputPos = 0;
m_SequenceGenerator.seed(SEQUENCE_SEED);
m_recvBuf.Clear();
m_sendBuf.Clear();
}
bool CNetworkStream::Connect(const CNetworkAddress& c_rkNetAddr, int limitSec)
@@ -294,251 +252,229 @@ bool CNetworkStream::Connect(const char* c_szAddr, int port, int /*limitSec*/)
void CNetworkStream::ClearRecvBuffer()
{
m_recvBufOutputPos = m_recvBufInputPos = 0;
m_recvBuf.Clear();
}
int CNetworkStream::GetRecvBufferSize()
{
return m_recvBufInputPos - m_recvBufOutputPos;
return static_cast<int>(m_recvBuf.ReadableBytes());
}
bool CNetworkStream::Peek(int size)
{
if (GetRecvBufferSize() < size)
return false;
return true;
return m_recvBuf.HasBytes(static_cast<size_t>(size));
}
bool CNetworkStream::Peek(int size, char * pDestBuf)
bool CNetworkStream::Peek(int size, char* pDestBuf)
{
if (GetRecvBufferSize() < size)
return false;
memcpy(pDestBuf, m_recvBuf + m_recvBufOutputPos, size);
return true;
return m_recvBuf.Peek(pDestBuf, static_cast<size_t>(size));
}
#ifdef _PACKETDUMP
const char * GetSendHeaderName(BYTE header)
static const char* GetHeaderName(uint16_t header)
{
static bool b = false;
static std::string stringList[UCHAR_MAX+1];
if (b==false)
{
for (DWORD i = 0; i < UCHAR_MAX+1; i++)
{
char buf[10];
sprintf(buf,"%d",i);
stringList[i] = buf;
}
stringList[2] = "HEADER_CG_ATTACK";
stringList[3] = "HEADER_CG_CHAT";
stringList[4] = "HEADER_CG_PLAYER_CREATE";
stringList[5] = "HEADER_CG_PLAYER_DESTROY";
stringList[6] = "HEADER_CG_PLAYER_SELECT";
stringList[7] = "HEADER_CG_CHARACTER_MOVE";
stringList[8] = "HEADER_CG_SYNC_POSITION";
stringList[9] = "HEADER_CG_DIRECT_ENTER";
stringList[10] = "HEADER_CG_ENTERGAME";
stringList[11] = "HEADER_CG_ITEM_USE";
stringList[12] = "HEADER_CG_ITEM_DROP";
stringList[13] = "HEADER_CG_ITEM_MOVE";
stringList[15] = "HEADER_CG_ITEM_PICKUP";
stringList[16] = "HEADER_CG_QUICKSLOT_ADD";
stringList[17] = "HEADER_CG_QUICKSLOT_DEL";
stringList[18] = "HEADER_CG_QUICKSLOT_SWAP";
stringList[19] = "HEADER_CG_WHISPER";
stringList[20] = "HEADER_CG_ITEM_DROP2";
stringList[26] = "HEADER_CG_ON_CLICK";
stringList[27] = "HEADER_CG_EXCHANGE";
stringList[28] = "HEADER_CG_CHARACTER_POSITION";
stringList[29] = "HEADER_CG_SCRIPT_ANSWER";
stringList[30] = "HEADER_CG_QUEST_INPUT_STRING";
stringList[31] = "HEADER_CG_QUEST_CONFIRM";
stringList[41] = "HEADER_CG_PVP";
stringList[50] = "HEADER_CG_SHOP";
stringList[51] = "HEADER_CG_FLY_TARGETING";
stringList[52] = "HEADER_CG_USE_SKILL";
stringList[53] = "HEADER_CG_ADD_FLY_TARGETING";
stringList[54] = "HEADER_CG_SHOOT";
stringList[55] = "HEADER_CG_MYSHOP";
stringList[60] = "HEADER_CG_ITEM_USE_TO_ITEM";
stringList[61] = "HEADER_CG_TARGET";
stringList[65] = "HEADER_CG_WARP";
stringList[66] = "HEADER_CG_SCRIPT_BUTTON";
stringList[67] = "HEADER_CG_MESSENGER";
stringList[69] = "HEADER_CG_MALL_CHECKOUT";
stringList[70] = "HEADER_CG_SAFEBOX_CHECKIN";
stringList[71] = "HEADER_CG_SAFEBOX_CHECKOUT";
stringList[72] = "HEADER_CG_PARTY_INVITE";
stringList[73] = "HEADER_CG_PARTY_INVITE_ANSWER";
stringList[74] = "HEADER_CG_PARTY_REMOVE";
stringList[75] = "HEADER_CG_PARTY_SET_STATE";
stringList[76] = "HEADER_CG_PARTY_USE_SKILL";
stringList[77] = "HEADER_CG_SAFEBOX_ITEM_MOVE";
stringList[78] = "HEADER_CG_PARTY_PARAMETER";
stringList[80] = "HEADER_CG_GUILD";
stringList[81] = "HEADER_CG_ANSWER_MAKE_GUILD";
stringList[82] = "HEADER_CG_FISHING";
stringList[83] = "HEADER_CG_GIVE_ITEM";
stringList[90] = "HEADER_CG_EMPIRE";
stringList[96] = "HEADER_CG_REFINE";
stringList[100] = "HEADER_CG_MARK_LOGIN";
stringList[101] = "HEADER_CG_MARK_CRCLIST";
stringList[102] = "HEADER_CG_MARK_UPLOAD";
stringList[103] = "HEADER_CG_CRC_REPORT";
stringList[105] = "HEADER_CG_HACK";
stringList[106] = "HEADER_CG_CHANGE_NAME";
stringList[107] = "HEADER_CG_SMS";
stringList[108] = "HEADER_CG_MATRIX_CARD";
stringList[109] = "HEADER_CG_LOGIN2";
stringList[110] = "HEADER_CG_DUNGEON";
stringList[111] = "HEADER_CG_LOGIN3";
stringList[112] = "HEADER_CG_GUILD_SYMBOL_UPLOAD";
stringList[113] = "HEADER_CG_GUILD_SYMBOL_CRC";
stringList[114] = "HEADER_CG_SCRIPT_SELECT_ITEM";
stringList[0xf9] = "HEADER_CG_KEY_RESPONSE";
stringList[0xfc] = "HEADER_CG_TIME_SYNC";
stringList[0xfd] = "HEADER_CG_CLIENT_VERSION";
stringList[0xfe] = "HEADER_CG_PONG";
stringList[0xff] = "HEADER_CG_HANDSHAKE";
}
return stringList[header].c_str();
}
static const std::unordered_map<uint16_t, const char*> s_headerNames = {
// Control
{ CG::PONG, "CG_PONG" },
{ GC::PING, "GC_PING" },
{ GC::PHASE, "GC_PHASE" },
{ CG::KEY_RESPONSE, "CG_KEY_RESPONSE" },
{ GC::KEY_CHALLENGE, "GC_KEY_CHALLENGE" },
{ GC::KEY_COMPLETE, "GC_KEY_COMPLETE" },
{ CG::CLIENT_VERSION, "CG_CLIENT_VERSION" },
{ CG::STATE_CHECKER, "CG_STATE_CHECKER" },
{ GC::RESPOND_CHANNELSTATUS, "GC_RESPOND_CHANNELSTATUS" },
{ CG::TEXT, "CG_TEXT" },
// Authentication
{ CG::LOGIN2, "CG_LOGIN2" },
{ CG::LOGIN3, "CG_LOGIN3" },
{ CG::LOGIN_SECURE, "CG_LOGIN_SECURE" },
{ GC::LOGIN_SUCCESS3, "GC_LOGIN_SUCCESS3" },
{ GC::LOGIN_SUCCESS4, "GC_LOGIN_SUCCESS4" },
{ GC::LOGIN_FAILURE, "GC_LOGIN_FAILURE" },
{ GC::LOGIN_KEY, "GC_LOGIN_KEY" },
{ GC::AUTH_SUCCESS, "GC_AUTH_SUCCESS" },
{ GC::EMPIRE, "GC_EMPIRE" },
{ CG::EMPIRE, "CG_EMPIRE" },
{ CG::CHANGE_NAME, "CG_CHANGE_NAME" },
{ GC::CHANGE_NAME, "GC_CHANGE_NAME" },
// Character
{ CG::CHARACTER_CREATE, "CG_CHARACTER_CREATE" },
{ CG::CHARACTER_DELETE, "CG_CHARACTER_DELETE" },
{ CG::CHARACTER_SELECT, "CG_CHARACTER_SELECT" },
{ CG::ENTERGAME, "CG_ENTERGAME" },
{ GC::CHARACTER_ADD, "GC_CHARACTER_ADD" },
{ GC::CHARACTER_ADD2, "GC_CHARACTER_ADD2" },
{ GC::CHAR_ADDITIONAL_INFO, "GC_CHAR_ADDITIONAL_INFO" },
{ GC::CHARACTER_DEL, "GC_CHARACTER_DEL" },
{ GC::CHARACTER_UPDATE, "GC_CHARACTER_UPDATE" },
{ GC::CHARACTER_UPDATE2, "GC_CHARACTER_UPDATE2" },
{ GC::CHARACTER_POSITION, "GC_CHARACTER_POSITION" },
{ GC::PLAYER_CREATE_SUCCESS, "GC_PLAYER_CREATE_SUCCESS" },
{ GC::PLAYER_CREATE_FAILURE, "GC_PLAYER_CREATE_FAILURE" },
{ GC::PLAYER_DELETE_SUCCESS, "GC_PLAYER_DELETE_SUCCESS" },
{ GC::PLAYER_DELETE_WRONG_SOCIAL_ID, "GC_PLAYER_DELETE_WRONG_SOCIAL_ID" },
{ GC::MAIN_CHARACTER, "GC_MAIN_CHARACTER" },
{ GC::PLAYER_POINTS, "GC_PLAYER_POINTS" },
{ GC::PLAYER_POINT_CHANGE, "GC_PLAYER_POINT_CHANGE" },
{ GC::STUN, "GC_STUN" },
{ GC::DEAD, "GC_DEAD" },
{ GC::CHANGE_SPEED, "GC_CHANGE_SPEED" },
{ GC::WALK_MODE, "GC_WALK_MODE" },
{ GC::SKILL_LEVEL, "GC_SKILL_LEVEL" },
{ GC::SKILL_LEVEL_NEW, "GC_SKILL_LEVEL_NEW" },
{ GC::SKILL_COOLTIME_END, "GC_SKILL_COOLTIME_END" },
{ GC::CHANGE_SKILL_GROUP, "GC_CHANGE_SKILL_GROUP" },
{ GC::VIEW_EQUIP, "GC_VIEW_EQUIP" },
// Movement
{ CG::MOVE, "CG_MOVE" },
{ GC::MOVE, "GC_MOVE" },
{ CG::SYNC_POSITION, "CG_SYNC_POSITION" },
{ GC::SYNC_POSITION, "GC_SYNC_POSITION" },
{ CG::WARP, "CG_WARP" },
{ GC::WARP, "GC_WARP" },
{ GC::MOTION, "GC_MOTION" },
{ GC::DIG_MOTION, "GC_DIG_MOTION" },
// Combat
{ CG::ATTACK, "CG_ATTACK" },
{ CG::USE_SKILL, "CG_USE_SKILL" },
{ CG::SHOOT, "CG_SHOOT" },
{ CG::FLY_TARGETING, "CG_FLY_TARGETING" },
{ CG::ADD_FLY_TARGETING, "CG_ADD_FLY_TARGETING" },
{ GC::DAMAGE_INFO, "GC_DAMAGE_INFO" },
{ GC::FLY_TARGETING, "GC_FLY_TARGETING" },
{ GC::ADD_FLY_TARGETING, "GC_ADD_FLY_TARGETING" },
{ GC::CREATE_FLY, "GC_CREATE_FLY" },
{ GC::PVP, "GC_PVP" },
{ GC::DUEL_START, "GC_DUEL_START" },
// Items
{ CG::ITEM_USE, "CG_ITEM_USE" },
{ CG::ITEM_DROP, "CG_ITEM_DROP" },
{ CG::ITEM_DROP2, "CG_ITEM_DROP2" },
{ CG::ITEM_MOVE, "CG_ITEM_MOVE" },
{ CG::ITEM_PICKUP, "CG_ITEM_PICKUP" },
{ CG::ITEM_USE_TO_ITEM, "CG_ITEM_USE_TO_ITEM" },
{ CG::ITEM_GIVE, "CG_ITEM_GIVE" },
{ CG::EXCHANGE, "CG_EXCHANGE" },
{ CG::QUICKSLOT_ADD, "CG_QUICKSLOT_ADD" },
{ CG::QUICKSLOT_DEL, "CG_QUICKSLOT_DEL" },
{ CG::QUICKSLOT_SWAP, "CG_QUICKSLOT_SWAP" },
{ CG::REFINE, "CG_REFINE" },
{ CG::DRAGON_SOUL_REFINE, "CG_DRAGON_SOUL_REFINE" },
{ GC::ITEM_DEL, "GC_ITEM_DEL" },
{ GC::ITEM_SET, "GC_ITEM_SET" },
{ GC::ITEM_USE, "GC_ITEM_USE" },
{ GC::ITEM_DROP, "GC_ITEM_DROP" },
{ GC::ITEM_UPDATE, "GC_ITEM_UPDATE" },
{ GC::ITEM_GROUND_ADD, "GC_ITEM_GROUND_ADD" },
{ GC::ITEM_GROUND_DEL, "GC_ITEM_GROUND_DEL" },
{ GC::ITEM_OWNERSHIP, "GC_ITEM_OWNERSHIP" },
{ GC::ITEM_GET, "GC_ITEM_GET" },
{ GC::QUICKSLOT_ADD, "GC_QUICKSLOT_ADD" },
{ GC::QUICKSLOT_DEL, "GC_QUICKSLOT_DEL" },
{ GC::QUICKSLOT_SWAP, "GC_QUICKSLOT_SWAP" },
{ GC::EXCHANGE, "GC_EXCHANGE" },
{ GC::REFINE_INFORMATION, "GC_REFINE_INFORMATION" },
{ GC::DRAGON_SOUL_REFINE, "GC_DRAGON_SOUL_REFINE" },
// Chat
{ CG::CHAT, "CG_CHAT" },
{ CG::WHISPER, "CG_WHISPER" },
{ GC::CHAT, "GC_CHAT" },
{ GC::WHISPER, "GC_WHISPER" },
// Social
{ CG::PARTY_INVITE, "CG_PARTY_INVITE" },
{ CG::PARTY_INVITE_ANSWER, "CG_PARTY_INVITE_ANSWER" },
{ CG::PARTY_REMOVE, "CG_PARTY_REMOVE" },
{ CG::PARTY_SET_STATE, "CG_PARTY_SET_STATE" },
{ CG::PARTY_USE_SKILL, "CG_PARTY_USE_SKILL" },
{ CG::PARTY_PARAMETER, "CG_PARTY_PARAMETER" },
{ GC::PARTY_INVITE, "GC_PARTY_INVITE" },
{ GC::PARTY_ADD, "GC_PARTY_ADD" },
{ GC::PARTY_UPDATE, "GC_PARTY_UPDATE" },
{ GC::PARTY_REMOVE, "GC_PARTY_REMOVE" },
{ GC::PARTY_LINK, "GC_PARTY_LINK" },
{ GC::PARTY_UNLINK, "GC_PARTY_UNLINK" },
{ GC::PARTY_PARAMETER, "GC_PARTY_PARAMETER" },
{ CG::GUILD, "CG_GUILD" },
{ CG::ANSWER_MAKE_GUILD, "CG_ANSWER_MAKE_GUILD" },
{ CG::GUILD_SYMBOL_UPLOAD, "CG_GUILD_SYMBOL_UPLOAD" },
{ CG::SYMBOL_CRC, "CG_SYMBOL_CRC" },
{ GC::GUILD, "GC_GUILD" },
{ GC::REQUEST_MAKE_GUILD, "GC_REQUEST_MAKE_GUILD" },
{ GC::SYMBOL_DATA, "GC_SYMBOL_DATA" },
{ CG::MESSENGER, "CG_MESSENGER" },
{ GC::MESSENGER, "GC_MESSENGER" },
{ GC::LOVER_INFO, "GC_LOVER_INFO" },
{ GC::LOVE_POINT_UPDATE, "GC_LOVE_POINT_UPDATE" },
// Shop / Trade
{ CG::SHOP, "CG_SHOP" },
{ CG::MYSHOP, "CG_MYSHOP" },
{ GC::SHOP, "GC_SHOP" },
{ GC::SHOP_SIGN, "GC_SHOP_SIGN" },
{ CG::SAFEBOX_CHECKIN, "CG_SAFEBOX_CHECKIN" },
{ CG::SAFEBOX_CHECKOUT, "CG_SAFEBOX_CHECKOUT" },
{ CG::SAFEBOX_ITEM_MOVE, "CG_SAFEBOX_ITEM_MOVE" },
{ GC::SAFEBOX_SET, "GC_SAFEBOX_SET" },
{ GC::SAFEBOX_DEL, "GC_SAFEBOX_DEL" },
{ GC::SAFEBOX_WRONG_PASSWORD, "GC_SAFEBOX_WRONG_PASSWORD" },
{ GC::SAFEBOX_SIZE, "GC_SAFEBOX_SIZE" },
{ GC::SAFEBOX_MONEY_CHANGE, "GC_SAFEBOX_MONEY_CHANGE" },
{ CG::MALL_CHECKOUT, "CG_MALL_CHECKOUT" },
{ GC::MALL_OPEN, "GC_MALL_OPEN" },
{ GC::MALL_SET, "GC_MALL_SET" },
{ GC::MALL_DEL, "GC_MALL_DEL" },
// Quest
{ CG::SCRIPT_ANSWER, "CG_SCRIPT_ANSWER" },
{ CG::SCRIPT_BUTTON, "CG_SCRIPT_BUTTON" },
{ CG::SCRIPT_SELECT_ITEM, "CG_SCRIPT_SELECT_ITEM" },
{ CG::QUEST_INPUT_STRING, "CG_QUEST_INPUT_STRING" },
{ CG::QUEST_CONFIRM, "CG_QUEST_CONFIRM" },
{ CG::QUEST_CANCEL, "CG_QUEST_CANCEL" },
{ GC::SCRIPT, "GC_SCRIPT" },
{ GC::QUEST_CONFIRM, "GC_QUEST_CONFIRM" },
{ GC::QUEST_INFO, "GC_QUEST_INFO" },
// UI / Effects
{ CG::TARGET, "CG_TARGET" },
{ CG::ON_CLICK, "CG_ON_CLICK" },
{ GC::TARGET, "GC_TARGET" },
{ GC::TARGET_UPDATE, "GC_TARGET_UPDATE" },
{ GC::TARGET_DELETE, "GC_TARGET_DELETE" },
{ GC::TARGET_CREATE_NEW, "GC_TARGET_CREATE_NEW" },
{ GC::AFFECT_ADD, "GC_AFFECT_ADD" },
{ GC::AFFECT_REMOVE, "GC_AFFECT_REMOVE" },
{ GC::SEPCIAL_EFFECT, "GC_SPECIAL_EFFECT" },
{ GC::SPECIFIC_EFFECT, "GC_SPECIFIC_EFFECT" },
{ GC::MOUNT, "GC_MOUNT" },
{ GC::OWNERSHIP, "GC_OWNERSHIP" },
{ GC::NPC_POSITION, "GC_NPC_POSITION" },
{ CG::CHARACTER_POSITION, "CG_CHARACTER_POSITION" },
// World
{ CG::FISHING, "CG_FISHING" },
{ CG::DUNGEON, "CG_DUNGEON" },
{ CG::HACK, "CG_HACK" },
{ GC::FISHING, "GC_FISHING" },
{ GC::DUNGEON, "GC_DUNGEON" },
{ GC::LAND_LIST, "GC_LAND_LIST" },
{ GC::TIME, "GC_TIME" },
{ GC::CHANNEL, "GC_CHANNEL" },
{ GC::MARK_UPDATE, "GC_MARK_UPDATE" },
// Guild Marks
{ CG::MARK_LOGIN, "CG_MARK_LOGIN" },
{ CG::MARK_CRCLIST, "CG_MARK_CRCLIST" },
{ CG::MARK_UPLOAD, "CG_MARK_UPLOAD" },
{ CG::MARK_IDXLIST, "CG_MARK_IDXLIST" },
{ GC::MARK_BLOCK, "GC_MARK_BLOCK" },
{ GC::MARK_IDXLIST, "GC_MARK_IDXLIST" },
};
const char * GetRecvHeaderName(BYTE header)
{
static bool b = false;
static std::string stringList[UCHAR_MAX+1];
if (b==false)
{
for (DWORD i = 0; i < UCHAR_MAX+1; i++)
{
char buf[10];
sprintf(buf,"%d",i);
stringList[i] = buf;
}
stringList[1] = "HEADER_GC_CHARACTER_ADD";
stringList[2] = "HEADER_GC_CHARACTER_DEL";
stringList[3] = "HEADER_GC_CHARACTER_MOVE";
stringList[4] = "HEADER_GC_CHAT";
stringList[5] = "HEADER_GC_SYNC_POSITION";
stringList[6] = "HEADER_GC_LOGIN_SUCCESS";
stringList[7] = "HEADER_GC_LOGIN_FAILURE";
stringList[8] = "HEADER_GC_PLAYER_CREATE_SUCCESS";
stringList[9] = "HEADER_GC_PLAYER_CREATE_FAILURE";
stringList[10] = "HEADER_GC_PLAYER_DELETE_SUCCESS";
stringList[11] = "HEADER_GC_PLAYER_DELETE_WRONG_SOCIAL_ID";
auto it = s_headerNames.find(header);
if (it != s_headerNames.end())
return it->second;
stringList[13] = "HEADER_GC_STUN";
stringList[14] = "HEADER_GC_DEAD";
stringList[15] = "HEADER_GC_MAIN_CHARACTER";
stringList[16] = "HEADER_GC_PLAYER_POINTS";
stringList[17] = "HEADER_GC_PLAYER_POINT_CHANGE";
stringList[18] = "HEADER_GC_CHANGE_SPEED";
stringList[19] = "HEADER_GC_CHARACTER_UPDATE";
stringList[20] = "HEADER_GC_ITEM_DEL";
stringList[21] = "HEADER_GC_ITEM_SET";
stringList[22] = "HEADER_GC_ITEM_USE";
stringList[23] = "HEADER_GC_ITEM_DROP";
stringList[25] = "HEADER_GC_ITEM_UPDATE";
stringList[26] = "HEADER_GC_ITEM_GROUND_ADD";
stringList[27] = "HEADER_GC_ITEM_GROUND_DEL";
stringList[28] = "HEADER_GC_QUICKSLOT_ADD";
stringList[29] = "HEADER_GC_QUICKSLOT_DEL";
stringList[30] = "HEADER_GC_QUICKSLOT_SWAP";
stringList[31] = "HEADER_GC_ITEM_OWNERSHIP";
stringList[33] = "HEADER_GC_ITEM_UNBIND_TIME";
stringList[34] = "HEADER_GC_WHISPER";
stringList[35] = "HEADER_GC_ALERT";
stringList[36] = "HEADER_GC_MOTION";
stringList[38] = "HEADER_GC_SHOP";
stringList[39] = "HEADER_GC_SHOP_SIGN";
stringList[41] = "HEADER_GC_PVP";
stringList[42] = "HEADER_GC_EXCHANGE";
stringList[43] = "HEADER_GC_CHARACTER_POSITION";
stringList[44] = "HEADER_GC_PING";
stringList[45] = "HEADER_GC_SCRIPT";
stringList[46] = "HEADER_GC_QUEST_CONFIRM";
stringList[61] = "HEADER_GC_MOUNT";
stringList[62] = "HEADER_GC_OWNERSHIP";
stringList[63] = "HEADER_GC_TARGET";
stringList[65] = "HEADER_GC_WARP";
stringList[69] = "HEADER_GC_ADD_FLY_TARGETING";
stringList[70] = "HEADER_GC_CREATE_FLY";
stringList[71] = "HEADER_GC_FLY_TARGETING";
stringList[72] = "HEADER_GC_SKILL_LEVEL";
stringList[73] = "HEADER_GC_SKILL_COOLTIME_END";
stringList[74] = "HEADER_GC_MESSENGER";
stringList[75] = "HEADER_GC_GUILD";
stringList[76] = "HEADER_GC_SKILL_LEVEL_NEW";
stringList[77] = "HEADER_GC_PARTY_INVITE";
stringList[78] = "HEADER_GC_PARTY_ADD";
stringList[79] = "HEADER_GC_PARTY_UPDATE";
stringList[80] = "HEADER_GC_PARTY_REMOVE";
stringList[81] = "HEADER_GC_QUEST_INFO";
stringList[82] = "HEADER_GC_REQUEST_MAKE_GUILD";
stringList[83] = "HEADER_GC_PARTY_PARAMETER";
stringList[84] = "HEADER_GC_SAFEBOX_MONEY_CHANGE";
stringList[85] = "HEADER_GC_SAFEBOX_SET";
stringList[86] = "HEADER_GC_SAFEBOX_DEL";
stringList[87] = "HEADER_GC_SAFEBOX_WRONG_PASSWORD";
stringList[88] = "HEADER_GC_SAFEBOX_SIZE";
stringList[89] = "HEADER_GC_FISHING";
stringList[90] = "HEADER_GC_EMPIRE";
stringList[91] = "HEADER_GC_PARTY_LINK";
stringList[92] = "HEADER_GC_PARTY_UNLINK";
stringList[95] = "HEADER_GC_REFINE_INFORMATION";
stringList[96] = "HEADER_GC_OBSERVER_ADD";
stringList[97] = "HEADER_GC_OBSERVER_REMOVE";
stringList[98] = "HEADER_GC_OBSERVER_MOVE";
stringList[99] = "HEADER_GC_VIEW_EQUIP";
stringList[100] = "HEADER_GC_MARK_BLOCK";
stringList[101] = "HEADER_GC_MARK_DIFF_DATA";
stringList[106] = "HEADER_GC_TIME";
stringList[107] = "HEADER_GC_CHANGE_NAME";
stringList[110] = "HEADER_GC_DUNGEON";
stringList[111] = "HEADER_GC_WALK_MODE";
stringList[112] = "HEADER_GC_CHANGE_SKILL_GROUP";
stringList[113] = "HEADER_GC_MAIN_CHARACTER_NEW";
stringList[114] = "HEADER_GC_USE_POTION";
stringList[115] = "HEADER_GC_NPC_POSITION";
stringList[116] = "HEADER_GC_MATRIX_CARD";
stringList[117] = "HEADER_GC_CHARACTER_UPDATE2";
stringList[118] = "HEADER_GC_LOGIN_KEY";
stringList[119] = "HEADER_GC_REFINE_INFORMATION_NEW";
stringList[120] = "HEADER_GC_CHARACTER_ADD2";
stringList[121] = "HEADER_GC_CHANNEL";
stringList[122] = "HEADER_GC_MALL_OPEN";
stringList[123] = "HEADER_GC_TARGET_UPDATE";
stringList[124] = "HEADER_GC_TARGET_DELETE";
stringList[125] = "HEADER_GC_TARGET_CREATE_NEW";
stringList[126] = "HEADER_GC_AFFECT_ADD";
stringList[127] = "HEADER_GC_AFFECT_REMOVE";
stringList[128] = "HEADER_GC_MALL_SET";
stringList[129] = "HEADER_GC_MALL_DEL";
stringList[130] = "HEADER_GC_LAND_LIST";
stringList[131] = "HEADER_GC_LOVER_INFO";
stringList[132] = "HEADER_GC_LOVE_POINT_UPDATE";
stringList[133] = "HEADER_GC_GUILD_SYMBOL_DATA";
stringList[134] = "HEADER_GC_DIG_MOTION";
stringList[135] = "HEADER_GC_DAMAGE_INFO";
stringList[136] = "HEADER_GC_CHAR_ADDITIONAL_INFO";
stringList[150] = "HEADER_GC_AUTH_SUCCESS";
stringList[0xf7] = "HEADER_GC_KEY_COMPLETE";
stringList[0xf8] = "HEADER_GC_KEY_CHALLENGE";
stringList[0xfc] = "HEADER_GC_HANDSHAKE_OK";
stringList[0xfd] = "HEADER_GC_PHASE";
stringList[0xfe] = "HEADER_GC_BINDUDP";
stringList[0xff] = "HEADER_GC_HANDSHAKE";
}
return stringList[header].c_str();
static thread_local char buf[16];
snprintf(buf, sizeof(buf), "0x%04X", header);
return buf;
}
#endif
@@ -548,7 +484,7 @@ bool CNetworkStream::Recv(int size)
if (!Peek(size))
return false;
m_recvBufOutputPos += size;
m_recvBuf.Discard(static_cast<size_t>(size));
return true;
}
@@ -575,46 +511,61 @@ bool CNetworkStream::Recv(int size, char * pDestBuf)
return false;
#ifdef _PACKETDUMP
if (*pDestBuf != 0)
if (size >= 2)
{
const auto kHeader = *pDestBuf;
TraceError("RECV< %s %u(0x%X) (%d)", GetRecvHeaderName(kHeader), kHeader, kHeader, size);
const uint16_t kHeader = *reinterpret_cast<const uint16_t*>(pDestBuf);
TraceError("RECV< %s 0x%04X (%d bytes)", GetHeaderName(kHeader), kHeader, size);
const auto contents = dump_hex(reinterpret_cast<const uint8_t*>(pDestBuf), size);
TraceError("%s", contents.c_str());
}
#endif
m_recvBufOutputPos += size;
m_recvBuf.Discard(static_cast<size_t>(size));
return true;
}
int CNetworkStream::__GetSendBufferSize()
{
return m_sendBufInputPos - m_sendBufOutputPos;
return static_cast<int>(m_sendBuf.ReadableBytes());
}
bool CNetworkStream::Send(int size, const char * pSrcBuf)
{
int sendBufRestSize = m_sendBufSize - m_sendBufInputPos;
if ((size + 1) > sendBufRestSize)
return false;
memcpy(m_sendBuf + m_sendBufInputPos, pSrcBuf, size);
if (m_secureCipher.IsActivated())
// Track packet sends: detect new packet start by checking [header:2][length:2] framing
if (size >= 4)
{
m_secureCipher.EncryptInPlace(m_sendBuf + m_sendBufInputPos, size);
const uint16_t wHeader = *reinterpret_cast<const uint16_t*>(pSrcBuf);
const uint16_t wLength = *reinterpret_cast<const uint16_t*>(pSrcBuf + 2);
if (wHeader != 0 && wLength >= 4)
{
auto& e = m_aSentPacketLog[m_dwSentPacketSeq % SENT_PACKET_LOG_SIZE];
e.seq = m_dwSentPacketSeq;
e.header = wHeader;
e.length = wLength;
m_dwSentPacketSeq++;
}
}
m_sendBufInputPos += size;
m_sendBuf.EnsureWritable(static_cast<size_t>(size));
// Copy data to send buffer
std::memcpy(m_sendBuf.WritePtr(), pSrcBuf, static_cast<size_t>(size));
// Encrypt in-place before committing
if (m_secureCipher.IsActivated())
{
m_secureCipher.EncryptInPlace(m_sendBuf.WritePtr(), size);
}
m_sendBuf.CommitWrite(static_cast<size_t>(size));
#ifdef _PACKETDUMP
if (*pSrcBuf != 0)
if (size >= 2)
{
const auto kHeader = *pSrcBuf;
TraceError("SEND> %s %u(0x%X) (%d)", GetSendHeaderName(kHeader), kHeader, kHeader, size);
const uint16_t kHeader = *reinterpret_cast<const uint16_t*>(pSrcBuf);
TraceError("SEND> %s 0x%04X (%d bytes)", GetHeaderName(kHeader), kHeader, size);
const auto contents = dump_hex(reinterpret_cast<const uint8_t*>(pSrcBuf), size);
TraceError("%s", contents.c_str());
@@ -652,25 +603,6 @@ bool CNetworkStream::IsOnline()
return m_isOnline;
}
void CNetworkStream::SetPacketSequenceMode(bool isOn)
{
m_bUseSequence = isOn;
}
bool CNetworkStream::SendSequence()
{
if (!m_bUseSequence)
return true;
BYTE bSeq = m_SequenceGenerator(UINT8_MAX + 1);
return Send(sizeof(BYTE), &bSeq);
}
uint8_t CNetworkStream::GetNextSequence()
{
return m_SequenceGenerator(UINT8_MAX + 1);
}
bool CNetworkStream::OnProcess()
{
return true;
@@ -694,6 +626,96 @@ void CNetworkStream::OnConnectFailure()
Tracen("Failed to connect.");
}
// ---------------------------------------------------------------------------
// Control-plane packet handlers (shared by all connection types)
// ---------------------------------------------------------------------------
bool CNetworkStream::RecvKeyChallenge()
{
TPacketGCKeyChallenge packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracen("KEY_CHALLENGE RECV");
SecureCipher& cipher = GetSecureCipher();
if (!cipher.Initialize())
{
TraceError("SecureCipher initialization failed");
Disconnect();
return false;
}
if (!cipher.ComputeClientKeys(packet.server_pk))
{
TraceError("Failed to compute client session keys");
Disconnect();
return false;
}
TPacketCGKeyResponse response;
response.header = CG::KEY_RESPONSE;
response.length = sizeof(response);
cipher.GetPublicKey(response.client_pk);
cipher.ComputeChallengeResponse(packet.challenge, response.challenge_response);
if (!Send(sizeof(response), &response))
{
TraceError("Failed to send key response");
return false;
}
Tracen("KEY_RESPONSE SENT");
return true;
}
bool CNetworkStream::RecvKeyComplete()
{
TPacketGCKeyComplete packet;
if (!Recv(sizeof(packet), &packet))
return false;
SecureCipher& cipher = GetSecureCipher();
uint8_t decrypted_token[SecureCipher::SESSION_TOKEN_SIZE];
if (!cipher.DecryptToken(packet.encrypted_token, sizeof(packet.encrypted_token),
packet.nonce, decrypted_token))
{
TraceError("Failed to decrypt session token");
Disconnect();
return false;
}
cipher.SetSessionToken(decrypted_token);
cipher.SetActivated(true);
DecryptPendingRecvData();
return true;
}
bool CNetworkStream::RecvPingPacket()
{
TPacketGCPing kPacketPing;
if (!Recv(sizeof(kPacketPing), &kPacketPing))
return false;
return SendPongPacket();
}
bool CNetworkStream::SendPongPacket()
{
TPacketCGPong kPacketPong;
kPacketPong.header = CG::PONG;
kPacketPong.length = sizeof(kPacketPong);
if (!Send(sizeof(kPacketPong), &kPacketPong))
return false;
return true;
}
// ---------------------------------------------------------------------------
CNetworkStream::CNetworkStream()
{
m_sock = INVALID_SOCKET;
@@ -701,33 +723,9 @@ CNetworkStream::CNetworkStream()
m_isOnline = false;
m_connectLimitTime = 0;
m_recvBuf = NULL;
m_recvBufSize = 0;
m_recvBufOutputPos = 0;
m_recvBufInputPos = 0;
m_sendBuf = NULL;
m_sendBufSize = 0;
m_sendBufOutputPos = 0;
m_sendBufInputPos = 0;
m_SequenceGenerator.seed(SEQUENCE_SEED);
m_bUseSequence = false;
}
CNetworkStream::~CNetworkStream()
{
Clear();
if (m_recvBuf)
{
delete [] m_recvBuf;
m_recvBuf = NULL;
}
if (m_sendBuf)
{
delete [] m_sendBuf;
m_sendBuf = NULL;
}
}

View File

@@ -2,10 +2,9 @@
#include "EterBase/SecureCipher.h"
#include "NetAddress.h"
#include "RingBuffer.h"
#include "ControlPackets.h"
#include <pcg_random.hpp>
#define SEQUENCE_SEED 0
class CNetworkStream
{
@@ -44,10 +43,6 @@ class CNetworkStream
bool IsOnline();
void SetPacketSequenceMode(bool isOn);
bool SendSequence();
uint8_t GetNextSequence();
protected:
virtual void OnConnectSuccess();
virtual void OnConnectFailure();
@@ -58,8 +53,6 @@ class CNetworkStream
bool __SendInternalBuffer();
bool __RecvInternalBuffer();
void __PopSendBuffer();
int __GetSendBufferSize();
// Secure cipher methods (libsodium)
@@ -71,18 +64,31 @@ class CNetworkStream
// Must be called after activating the cipher mid-stream
void DecryptPendingRecvData();
// Control-plane packet handlers (shared by all connection types)
virtual bool RecvKeyChallenge();
virtual bool RecvKeyComplete();
bool RecvPingPacket();
bool SendPongPacket();
// Packet send tracking (for debug sequence correlation)
protected:
struct SentPacketLogEntry
{
uint32_t seq;
uint16_t header;
uint16_t length;
};
static constexpr size_t SENT_PACKET_LOG_SIZE = 32;
SentPacketLogEntry m_aSentPacketLog[SENT_PACKET_LOG_SIZE] = {};
uint32_t m_dwSentPacketSeq = 0;
private:
time_t m_connectLimitTime;
char* m_recvBuf;
int m_recvBufSize;
int m_recvBufInputPos;
int m_recvBufOutputPos;
char* m_sendBuf;
int m_sendBufSize;
int m_sendBufInputPos;
int m_sendBufOutputPos;
RingBuffer m_recvBuf;
RingBuffer m_sendBuf;
bool m_isOnline;
@@ -93,7 +99,4 @@ class CNetworkStream
CNetworkAddress m_addr;
// Sequence
pcg32 m_SequenceGenerator;
bool m_bUseSequence;
};

157
src/EterLib/PacketReader.h Normal file
View File

@@ -0,0 +1,157 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <cassert>
// PacketReader: Safe, bounds-checked packet deserialization from a read-only buffer.
// Used to parse incoming packets after the dispatch loop validates the header and length.
//
// Usage:
// PacketReader r(packetData, packetLength);
// uint16_t header = r.ReadU16();
// uint16_t length = r.ReadU16();
// uint8_t chatType = r.ReadU8();
// char message[128];
// r.ReadString(message, sizeof(message));
class PacketReader
{
public:
PacketReader(const void* data, size_t size)
: m_buf(static_cast<const uint8_t*>(data))
, m_size(size)
, m_pos(0)
{
assert(data != nullptr || size == 0);
}
// --- Read primitives ---
uint8_t ReadU8()
{
assert(m_pos + sizeof(uint8_t) <= m_size);
return m_buf[m_pos++];
}
uint16_t ReadU16()
{
assert(m_pos + sizeof(uint16_t) <= m_size);
uint16_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
uint32_t ReadU32()
{
assert(m_pos + sizeof(uint32_t) <= m_size);
uint32_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
int8_t ReadI8() { return static_cast<int8_t>(ReadU8()); }
int16_t ReadI16() { return static_cast<int16_t>(ReadU16()); }
int32_t ReadI32() { return static_cast<int32_t>(ReadU32()); }
uint64_t ReadU64()
{
assert(m_pos + sizeof(uint64_t) <= m_size);
uint64_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
float ReadFloat()
{
assert(m_pos + sizeof(float) <= m_size);
float v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
m_pos += sizeof(v);
return v;
}
// Read raw bytes
bool ReadBytes(void* dest, size_t len)
{
if (m_pos + len > m_size)
return false;
std::memcpy(dest, m_buf + m_pos, len);
m_pos += len;
return true;
}
// Read a fixed-length string (null-terminated in dest)
bool ReadString(char* dest, size_t fixedLen)
{
if (m_pos + fixedLen > m_size)
return false;
std::memcpy(dest, m_buf + m_pos, fixedLen);
dest[fixedLen - 1] = '\0'; // ensure null termination
m_pos += fixedLen;
return true;
}
// Skip bytes without reading
bool Skip(size_t len)
{
if (m_pos + len > m_size)
return false;
m_pos += len;
return true;
}
// --- Peek (non-consuming) ---
uint8_t PeekU8() const
{
assert(m_pos + sizeof(uint8_t) <= m_size);
return m_buf[m_pos];
}
uint16_t PeekU16() const
{
assert(m_pos + sizeof(uint16_t) <= m_size);
uint16_t v;
std::memcpy(&v, m_buf + m_pos, sizeof(v));
return v;
}
uint16_t PeekU16At(size_t offset) const
{
assert(offset + sizeof(uint16_t) <= m_size);
uint16_t v;
std::memcpy(&v, m_buf + offset, sizeof(v));
return v;
}
// --- Read struct (for backward compatibility during migration) ---
// Reads a struct directly via memcpy. Use sparingly — prefer typed reads.
template<typename T>
bool ReadStruct(T& out)
{
if (m_pos + sizeof(T) > m_size)
return false;
std::memcpy(&out, m_buf + m_pos, sizeof(T));
m_pos += sizeof(T);
return true;
}
// --- State ---
bool HasBytes(size_t n) const { return (m_pos + n) <= m_size; }
size_t Remaining() const { return m_size - m_pos; }
size_t Position() const { return m_pos; }
size_t Size() const { return m_size; }
const uint8_t* Current() const { return m_buf + m_pos; }
void Reset() { m_pos = 0; }
private:
const uint8_t* m_buf;
size_t m_size;
size_t m_pos;
};

139
src/EterLib/PacketWriter.h Normal file
View File

@@ -0,0 +1,139 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <cassert>
// PacketWriter: Safe, bounds-checked packet serialization into a fixed buffer.
// Used to build outgoing packets before writing to the send buffer.
//
// Usage:
// uint8_t buf[128];
// PacketWriter w(buf, sizeof(buf));
// w.WriteU16(CG::CHAT);
// w.WriteU16(0); // placeholder for length
// w.WriteU8(chatType);
// w.WriteString(message, 128);
// w.PatchU16(2, w.Written()); // patch length at offset 2
// stream.Send(w.Written(), buf);
class PacketWriter
{
public:
PacketWriter(void* buf, size_t capacity)
: m_buf(static_cast<uint8_t*>(buf))
, m_capacity(capacity)
, m_pos(0)
{
assert(buf != nullptr);
assert(capacity > 0);
}
// --- Write primitives ---
bool WriteU8(uint8_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
m_buf[m_pos++] = v;
return true;
}
bool WriteU16(uint16_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
bool WriteU32(uint32_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
bool WriteI8(int8_t v) { return WriteU8(static_cast<uint8_t>(v)); }
bool WriteI16(int16_t v) { return WriteU16(static_cast<uint16_t>(v)); }
bool WriteI32(int32_t v) { return WriteU32(static_cast<uint32_t>(v)); }
bool WriteU64(uint64_t v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
bool WriteFloat(float v)
{
if (m_pos + sizeof(v) > m_capacity)
return false;
std::memcpy(m_buf + m_pos, &v, sizeof(v));
m_pos += sizeof(v);
return true;
}
// Write raw bytes
bool WriteBytes(const void* data, size_t len)
{
if (len == 0)
return true;
if (m_pos + len > m_capacity)
return false;
std::memcpy(m_buf + m_pos, data, len);
m_pos += len;
return true;
}
// Write a fixed-length null-padded string
bool WriteString(const char* str, size_t fixedLen)
{
if (m_pos + fixedLen > m_capacity)
return false;
size_t srcLen = str ? std::strlen(str) : 0;
size_t copyLen = (srcLen < fixedLen) ? srcLen : (fixedLen - 1);
std::memcpy(m_buf + m_pos, str, copyLen);
std::memset(m_buf + m_pos + copyLen, 0, fixedLen - copyLen);
m_pos += fixedLen;
return true;
}
// --- Patch: overwrite data at a previous offset ---
bool PatchU16(size_t offset, uint16_t v)
{
if (offset + sizeof(v) > m_pos)
return false;
std::memcpy(m_buf + offset, &v, sizeof(v));
return true;
}
bool PatchU32(size_t offset, uint32_t v)
{
if (offset + sizeof(v) > m_pos)
return false;
std::memcpy(m_buf + offset, &v, sizeof(v));
return true;
}
// --- State ---
size_t Written() const { return m_pos; }
size_t Remaining() const { return m_capacity - m_pos; }
const uint8_t* Data() const { return m_buf; }
void Reset() { m_pos = 0; }
private:
uint8_t* m_buf;
size_t m_capacity;
size_t m_pos;
};

View File

@@ -1,264 +1 @@
#pragma once
#include "EterBase/Timer.h"
#include "EterBase/Debug.h"
/*
class CProfiler : public CSingleton<CProfiler>
{
public:
enum
{
STACK_DATA_MAX_NUM = 64,
};
public:
typedef struct SProfileStackData
{
int iCallStep;
long iStartTime;
long iEndTime;
std::string strName;
} TProfileStackData;
typedef struct SProfileAccumulationData
{
int iStartTime;
int iCallingCount;
int iCollapsedTime;
std::string strName;
} TProfileAccumulationData;
typedef std::map<std::string, CGraphicTextInstance*> TGraphicTextInstanceMap;
typedef std::map<std::string, TProfileAccumulationData> TProfileAccumulationDataMap;
public:
CProfiler()
{
Clear();
m_ProfileAccumulationDataMap.clear();
}
virtual ~CProfiler()
{
}
void Clear()
{
m_ProfileStackDataCount = 0;
m_iCallStep = 0;
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.begin();
for (; itor != m_ProfileAccumulationDataMap.end(); ++itor)
{
TProfileAccumulationData & rData = itor->second;
rData.iCallingCount = 0;
rData.iCollapsedTime = 0;
}
}
void Push(const char * c_szName)
{
assert(m_ProfileStackDataCount < STACK_DATA_MAX_NUM);
TProfileStackData & rProfileStackData = m_ProfileStackDatas[m_ProfileStackDataCount++];
rProfileStackData.iCallStep = m_iCallStep;
rProfileStackData.iStartTime = ELTimer_GetMSec();
rProfileStackData.strName = c_szName;
++m_iCallStep;
TGraphicTextInstanceMap::iterator itor = m_GraphicTextInstanceMap.find(c_szName);
if (m_GraphicTextInstanceMap.end() == itor)
{
CGraphicTextInstance * pGraphicTextInstance = CGraphicTextInstance::New();
CResource * pResource = CResourceManager::Instance().GetResourcePointer("굴림체.fnt");
pGraphicTextInstance->Clear();
pGraphicTextInstance->SetTextPointer(static_cast<CGraphicText*>(pResource));
m_GraphicTextInstanceMap.insert(TGraphicTextInstanceMap::value_type(c_szName, pGraphicTextInstance));
}
}
void Pop(const char * c_szName)
{
TProfileStackData * pProfileStackData;
if (!GetProfileStackDataPointer(c_szName, &pProfileStackData))
{
assert(!"The name doesn't exist");
return;
}
pProfileStackData->iEndTime = ELTimer_GetMSec();
--m_iCallStep;
}
void PushAccumulation(const char * c_szName)
{
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.find(c_szName);
if (itor == m_ProfileAccumulationDataMap.end())
{
TProfileAccumulationData ProfileAccumulationData;
ProfileAccumulationData.iCollapsedTime = 0;
ProfileAccumulationData.iCallingCount = 0;
ProfileAccumulationData.strName = c_szName;
m_ProfileAccumulationDataMap.insert(TProfileAccumulationDataMap::value_type(c_szName, ProfileAccumulationData));
itor = m_ProfileAccumulationDataMap.find(c_szName);
/////
CGraphicTextInstance * pGraphicTextInstance = m_GraphicTextInstancePool.Alloc();
CResource * pResource = CResourceManager::Instance().GetResourcePointer("굴림체.fnt");
pGraphicTextInstance->Clear();
pGraphicTextInstance->SetTextPointer(static_cast<CGraphicText*>(pResource));
m_GraphicTextInstanceMap.insert(TGraphicTextInstanceMap::value_type(c_szName, pGraphicTextInstance));
}
TProfileAccumulationData & rData = itor->second;
rData.iStartTime = ELTimer_GetMSec();
}
void PopAccumulation(const char * c_szName)
{
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.find(c_szName);
if (itor == m_ProfileAccumulationDataMap.end())
return;
TProfileAccumulationData & rData = itor->second;
rData.iCollapsedTime += ELTimer_GetMSec() - rData.iStartTime;
++rData.iCallingCount;
}
void ProfileByConsole()
{
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
TProfileStackData & rProfileStackData = m_ProfileStackDatas[i];
// for (int i = 0; i < rProfileStackData.iCallStep; ++i)
// Tracef("\t");
Tracef("%-10s: %2d\t", rProfileStackData.strName.c_str(), rProfileStackData.iEndTime - rProfileStackData.iStartTime);
}
Tracef("\n");
}
void ProfileOneStackDataByConsole(const char * c_szName)
{
TProfileStackData * pProfileStackData;
if (!GetProfileStackDataPointer(c_szName, &pProfileStackData))
{
return;
}
Tracef("%-10s: %3d\n", pProfileStackData->strName.c_str(), pProfileStackData->iEndTime - pProfileStackData->iStartTime);
}
void ProfileOneAccumulationDataByConsole(const char * c_szName)
{
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.find(c_szName);
if (itor == m_ProfileAccumulationDataMap.end())
return;
TProfileAccumulationData & rData = itor->second;
Tracef("%-10s : [CollapsedTime : %3d] / [CallingCount : %3d]\n", rData.strName.c_str(),
rData.iCollapsedTime,
rData.iCallingCount);
}
void ProfileByScreen()
{
float fxPosition = 0;
float fyPosition = 10;
char szText[128];
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
TProfileStackData & rProfileStackData = m_ProfileStackDatas[i];
TGraphicTextInstanceMap::iterator itor = m_GraphicTextInstanceMap.find(rProfileStackData.strName);
if (m_GraphicTextInstanceMap.end() != itor)
{
CGraphicTextInstance * pGraphicTextInstance = itor->second;
fxPosition = 10 + (float) rProfileStackData.iCallStep * 10 * 4;
sprintf(szText, "%-10s : %3d", rProfileStackData.strName.c_str(), rProfileStackData.iEndTime - rProfileStackData.iStartTime);
pGraphicTextInstance->SetColor(0.7f, 0.7f, 0.7f);
pGraphicTextInstance->SetValue(szText, strlen(szText));
pGraphicTextInstance->SetPosition(fxPosition, fyPosition);
pGraphicTextInstance->Update();
pGraphicTextInstance->Render();
fyPosition += 17;
}
}
fxPosition = 10;
fyPosition += 10;
TProfileAccumulationDataMap::iterator itor = m_ProfileAccumulationDataMap.begin();
for (; itor != m_ProfileAccumulationDataMap.end(); ++itor)
{
TProfileAccumulationData & rData = itor->second;
TGraphicTextInstanceMap::iterator itor = m_GraphicTextInstanceMap.find(rData.strName);
if (m_GraphicTextInstanceMap.end() != itor)
{
CGraphicTextInstance * pGraphicTextInstance = itor->second;
sprintf(szText, "%-10s : [CollapsedTime : %3d] / [CallingCount : %3d]", rData.strName.c_str(),
rData.iCollapsedTime,
rData.iCallingCount);
pGraphicTextInstance->SetColor(0.7f, 0.7f, 0.7f);
pGraphicTextInstance->SetValue(szText, strlen(szText));
pGraphicTextInstance->SetPosition(fxPosition, fyPosition);
pGraphicTextInstance->Update();
pGraphicTextInstance->Render();
fyPosition += 17;
}
}
}
protected:
bool GetProfileStackDataPointer(const char * c_szName, TProfileStackData ** ppProfileStackData)
{
for (int i = 0; i < m_ProfileStackDataCount; ++i)
{
if (0 == m_ProfileStackDatas[i].strName.compare(c_szName))
{
*ppProfileStackData = &m_ProfileStackDatas[i];
return true;
}
}
return false;
}
protected:
// Profile Stack Data
int m_ProfileStackDataCount;
TProfileStackData m_ProfileStackDatas[STACK_DATA_MAX_NUM];
// Profile Increase Data
TProfileAccumulationDataMap m_ProfileAccumulationDataMap;
int m_iCallStep;
TGraphicTextInstanceMap m_GraphicTextInstanceMap;
};
*/

191
src/EterLib/RingBuffer.h Normal file
View File

@@ -0,0 +1,191 @@
#pragma once
#include <vector>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <algorithm>
class RingBuffer
{
public:
explicit RingBuffer(size_t initialCapacity = 0)
{
if (initialCapacity > 0)
m_data.resize(initialCapacity);
}
~RingBuffer() = default;
// Non-copyable, movable
RingBuffer(const RingBuffer&) = delete;
RingBuffer& operator=(const RingBuffer&) = delete;
RingBuffer(RingBuffer&&) noexcept = default;
RingBuffer& operator=(RingBuffer&&) noexcept = default;
// --- Capacity ---
size_t ReadableBytes() const { return m_writePos - m_readPos; }
size_t WritableBytes() const { return m_data.size() - m_writePos; }
size_t Capacity() const { return m_data.size(); }
void Reserve(size_t capacity)
{
if (capacity > m_data.size())
{
Compact();
m_data.resize(capacity);
}
}
void EnsureWritable(size_t len)
{
if (WritableBytes() >= len)
return;
// Try compaction first
Compact();
if (WritableBytes() >= len)
return;
// Must grow
size_t needed = m_writePos + len;
size_t newSize = m_data.size();
if (newSize == 0)
newSize = 1024;
while (newSize < needed)
newSize *= 2;
m_data.resize(newSize);
}
// --- Write operations ---
void Write(const void* data, size_t len)
{
if (len == 0)
return;
assert(data != nullptr);
EnsureWritable(len);
std::memcpy(m_data.data() + m_writePos, data, len);
m_writePos += len;
}
// Direct write access for socket recv()
uint8_t* WritePtr()
{
return m_data.data() + m_writePos;
}
void CommitWrite(size_t len)
{
assert(m_writePos + len <= m_data.size());
m_writePos += len;
}
// --- Read operations ---
bool HasBytes(size_t n) const { return ReadableBytes() >= n; }
bool Peek(void* dest, size_t len) const
{
if (ReadableBytes() < len)
return false;
std::memcpy(dest, m_data.data() + m_readPos, len);
return true;
}
// Peek at a specific offset from read position (non-consuming)
bool PeekAt(size_t offset, void* dest, size_t len) const
{
if (ReadableBytes() < offset + len)
return false;
std::memcpy(dest, m_data.data() + m_readPos + offset, len);
return true;
}
bool Read(void* dest, size_t len)
{
if (!Peek(dest, len))
return false;
m_readPos += len;
MaybeCompact();
return true;
}
// Discard bytes without reading them
bool Discard(size_t len)
{
if (ReadableBytes() < len)
return false;
m_readPos += len;
MaybeCompact();
return true;
}
// Direct read access for socket send() and packet processing
const uint8_t* ReadPtr() const
{
return m_data.data() + m_readPos;
}
size_t ReadPos() const { return m_readPos; }
size_t WritePos() const { return m_writePos; }
// --- Encryption support ---
// Get writable pointer to already-written data at a specific position
// Used for in-place encryption of data that was just written
uint8_t* DataAt(size_t pos)
{
assert(pos < m_data.size());
return m_data.data() + pos;
}
// --- Reset ---
void Clear()
{
m_readPos = 0;
m_writePos = 0;
}
// --- Compaction ---
void Compact()
{
if (m_readPos == 0)
return;
size_t readable = ReadableBytes();
if (readable > 0)
std::memmove(m_data.data(), m_data.data() + m_readPos, readable);
m_readPos = 0;
m_writePos = readable;
}
private:
void MaybeCompact()
{
// Compact when read position passes halfway and there's no readable data
// or when read position is more than half the buffer
if (m_readPos == m_writePos)
{
m_readPos = 0;
m_writePos = 0;
}
else if (m_readPos > m_data.size() / 2)
{
Compact();
}
}
std::vector<uint8_t> m_data;
size_t m_readPos = 0;
size_t m_writePos = 0;
};

View File

@@ -1,37 +1,55 @@
#include "StdAfx.h"
#include "TextBar.h"
#include "EterLib/Util.h"
#include "FontManager.h"
#include "Util.h"
#include <utf8.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <cmath>
// Gamma LUT matching GrpFontTexture for consistent text sharpness
static struct STextBarGammaLUT {
unsigned char table[256];
STextBarGammaLUT() {
table[0] = 0;
for (int i = 1; i < 256; ++i)
table[i] = (unsigned char)(pow(i / 255.0, 0.85) * 255.0 + 0.5);
}
} s_textBarGammaLUT;
void CTextBar::__SetFont(int fontSize, bool isBold)
{
LOGFONTW logFont{};
// Load bold font variant if available, otherwise fall back to regular
if (isBold)
{
m_ftFace = CFontManager::Instance().CreateFace("Tahoma Bold");
if (!m_ftFace)
m_ftFace = CFontManager::Instance().CreateFace("Tahoma");
}
else
{
m_ftFace = CFontManager::Instance().CreateFace("Tahoma");
}
if (!m_ftFace)
return;
logFont.lfHeight = fontSize;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = isBold ? FW_BOLD : FW_NORMAL;
logFont.lfItalic = FALSE;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = ANTIALIASED_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
wcscpy_s(logFont.lfFaceName, LF_FACESIZE, L"Tahoma");
int pixelSize = (m_fontSize < 0) ? -m_fontSize : m_fontSize;
if (pixelSize == 0)
pixelSize = 12;
m_hFont = CreateFontIndirect(&logFont);
FT_Set_Pixel_Sizes(m_ftFace, 0, pixelSize);
FT_Set_Transform(m_ftFace, NULL, NULL);
HDC hdc = m_dib.GetDCHandle();
m_hOldFont = (HFONT)SelectObject(hdc, m_hFont);
m_ascender = (int)(m_ftFace->size->metrics.ascender >> 6);
m_lineHeight = (int)(m_ftFace->size->metrics.height >> 6);
}
void CTextBar::SetTextColor(int r, int g, int b)
{
HDC hDC = m_dib.GetDCHandle();
::SetTextColor(hDC, RGB(r, g, b));
m_textColor = ((DWORD)r) | ((DWORD)g << 8) | ((DWORD)b << 16);
}
void CTextBar::GetTextExtent(const char* c_szText, SIZE* p_size)
@@ -46,35 +64,143 @@ void CTextBar::GetTextExtent(const char* c_szText, SIZE* p_size)
return;
}
HDC hDC = m_dib.GetDCHandle();
if (!m_ftFace)
{
p_size->cx = 0;
p_size->cy = 0;
return;
}
// UTF-8 → UTF-16
std::wstring wText = Utf8ToWide(c_szText);
GetTextExtentPoint32W(hDC, wText.c_str(), static_cast<int>(wText.length()), p_size);
bool hasKerning = FT_HAS_KERNING(m_ftFace) != 0;
FT_UInt prevIndex = 0;
int totalAdvance = 0;
for (size_t i = 0; i < wText.size(); ++i)
{
FT_UInt glyphIndex = FT_Get_Char_Index(m_ftFace, wText[i]);
if (glyphIndex == 0)
glyphIndex = FT_Get_Char_Index(m_ftFace, L' ');
if (hasKerning && prevIndex && glyphIndex)
{
FT_Vector delta;
if (FT_Get_Kerning(m_ftFace, prevIndex, glyphIndex, FT_KERNING_DEFAULT, &delta) == 0)
totalAdvance += (int)(delta.x / 64);
}
if (FT_Load_Glyph(m_ftFace, glyphIndex, FT_LOAD_DEFAULT) == 0)
totalAdvance += (int)ceilf((float)(m_ftFace->glyph->advance.x) / 64.0f) + 1; // +1px letter spacing
prevIndex = glyphIndex;
}
p_size->cx = totalAdvance;
p_size->cy = m_lineHeight;
}
void CTextBar::TextOut(int ix, int iy, const char * c_szText)
{
m_dib.TextOut(ix, iy, c_szText);
if (!c_szText || !*c_szText || !m_ftFace)
return;
DWORD* pdwBuf = (DWORD*)m_dib.GetPointer();
if (!pdwBuf)
return;
int bufWidth = m_dib.GetWidth();
int bufHeight = m_dib.GetHeight();
std::wstring wText = Utf8ToWide(c_szText);
int penX = ix;
int penY = iy;
DWORD colorRGB = m_textColor; // 0x00BBGGRR in memory
bool hasKerning = FT_HAS_KERNING(m_ftFace) != 0;
FT_UInt prevIndex = 0;
for (size_t i = 0; i < wText.size(); ++i)
{
FT_UInt glyphIndex = FT_Get_Char_Index(m_ftFace, wText[i]);
if (glyphIndex == 0)
glyphIndex = FT_Get_Char_Index(m_ftFace, L' ');
if (hasKerning && prevIndex && glyphIndex)
{
FT_Vector delta;
if (FT_Get_Kerning(m_ftFace, prevIndex, glyphIndex, FT_KERNING_DEFAULT, &delta) == 0)
penX += (int)(delta.x / 64);
}
if (FT_Load_Glyph(m_ftFace, glyphIndex, FT_LOAD_DEFAULT) != 0)
continue;
if (FT_Render_Glyph(m_ftFace->glyph, FT_RENDER_MODE_NORMAL) != 0)
continue;
FT_GlyphSlot slot = m_ftFace->glyph;
FT_Bitmap& bitmap = slot->bitmap;
int bmpX = penX + slot->bitmap_left;
int bmpY = penY + m_ascender - slot->bitmap_top;
for (int row = 0; row < (int)bitmap.rows; ++row)
{
int destY = bmpY + row;
if (destY < 0 || destY >= bufHeight)
continue;
unsigned char* srcRow = bitmap.buffer + row * bitmap.pitch;
DWORD* dstRow = pdwBuf + destY * bufWidth;
for (int col = 0; col < (int)bitmap.width; ++col)
{
int destX = bmpX + col;
if (destX < 0 || destX >= bufWidth)
continue;
unsigned char alpha = srcRow[col];
if (alpha)
{
alpha = s_textBarGammaLUT.table[alpha];
DWORD r = (colorRGB >> 0) & 0xFF;
DWORD g = (colorRGB >> 8) & 0xFF;
DWORD b = (colorRGB >> 16) & 0xFF;
dstRow[destX] = ((DWORD)alpha << 24) | (r << 16) | (g << 8) | b;
}
}
}
penX += (int)ceilf((float)(slot->advance.x) / 64.0f) + 1; // +1px letter spacing
prevIndex = glyphIndex;
}
Invalidate();
}
void CTextBar::OnCreate()
{
m_dib.SetBkMode(TRANSPARENT);
__SetFont(m_fontSize, m_isBold);
}
CTextBar::CTextBar(int fontSize, bool isBold)
{
m_hOldFont = NULL;
m_ftFace = nullptr;
m_textColor = 0x00FFFFFF; // White (RGB)
m_fontSize = fontSize;
m_isBold = isBold;
m_ascender = 0;
m_lineHeight = 0;
}
CTextBar::~CTextBar()
{
HDC hdc = m_dib.GetDCHandle();
SelectObject(hdc, m_hOldFont);
if (m_ftFace)
{
FT_Done_Face(m_ftFace);
m_ftFace = nullptr;
}
}

View File

@@ -2,12 +2,15 @@
#include "DibBar.h"
#include <ft2build.h>
#include FT_FREETYPE_H
class CTextBar : public CDibBar
{
public:
CTextBar(int fontSize, bool isBold);
virtual ~CTextBar();
void TextOut(int ix, int iy, const char * c_szText);
void SetTextColor(int r, int g, int b);
void GetTextExtent(const char * c_szText, SIZE* p_size);
@@ -18,9 +21,12 @@ class CTextBar : public CDibBar
void OnCreate();
protected:
HFONT m_hFont;
HFONT m_hOldFont;
FT_Face m_ftFace;
DWORD m_textColor;
int m_fontSize;
bool m_isBold;
int m_ascender;
int m_lineHeight;
};

View File

@@ -16,7 +16,7 @@ PyObject* grpCreateTextBar(PyObject* poSelf, PyObject* poArgs)
return Py_BuildException();
CTextBar * pTextBar = new CTextBar(12, false);
if (!pTextBar->Create(NULL, iWidth, iHeight))
if (!pTextBar->Create(iWidth, iHeight))
{
delete pTextBar;
return Py_BuildValue("K", NULL);
@@ -38,8 +38,8 @@ PyObject* grpCreateBigTextBar(PyObject* poSelf, PyObject* poArgs)
if (!PyTuple_GetInteger(poArgs, 2, &iFontSize))
return Py_BuildException();
CTextBar * pTextBar = new CTextBar(iFontSize, true);
if (!pTextBar->Create(NULL, iWidth, iHeight))
CTextBar * pTextBar = new CTextBar(iFontSize, false);
if (!pTextBar->Create(iWidth, iHeight))
{
delete pTextBar;
return Py_BuildValue("K", NULL);

View File

@@ -44,33 +44,6 @@ void CActorInstance::INSTANCEBASE_Transform()
UpdateAttribute();
}
/*
void CActorInstance::TEMP_Update()
{
//DWORD t1=ELTimer_GetMSec();
OnUpdate();
//DWORD t2=ELTimer_GetMSec();
UpdateBoundingSphere();
//DWORD t3=ELTimer_GetMSec();
#ifdef __PERFORMANCE_CHECKER__
{
static FILE* fp=fopen("perf_actor_update.txt", "w");
if (t3-t1>3)
{
fprintf(fp, "AIU.Total %d (Time %f)\n",
t3-t1, ELTimer_GetMSec()/1000.0f);
fprintf(fp, "AIU.UP %d\n", t2-t1);
fprintf(fp, "AIU.UBS %d\n", t3-t2);
fprintf(fp, "-------------------------------- \n");
fflush(fp);
}
fflush(fp);
}
#endif
}
*/
void CActorInstance::OnUpdate()
{

View File

@@ -294,36 +294,6 @@ void CActorInstance::ChangeMaterial(const char * c_szFileName)
SetMaterialImagePointer(c_rkSkinItem.m_ePart, c_rkSkinItem.m_stSrcFileName.c_str(), static_cast<CGraphicImage*>(pkRes));
}
/*
void CActorInstance::SetPart(DWORD dwPartIndex, DWORD dwItemID)
{
if (dwPartIndex>=CRaceData::PART_MAX_NUM)
return;
if (!m_pkCurRaceData)
{
assert(m_pkCurRaceData);
return;
}
CItemData * pItemData;
if (!CItemManager::Instance().GetItemDataPointer(dwItemID, &pItemData))
return;
RegisterModelThing(dwPartIndex, pItemData->GetModelThing());
for (DWORD i = 0; i < pItemData->GetLODModelThingCount(); ++i)
{
CGraphicThing * pThing;
if (!pItemData->GetLODModelThingPointer(i, &pThing))
continue;
RegisterLODThing(dwPartIndex, pThing);
}
SetModelInstance(dwPartIndex, dwPartIndex, 0);
m_adwPartItemID[dwPartIndex] = dwItemID;
}
*/
DWORD CActorInstance::GetPartItemID(DWORD dwPartIndex)
{

View File

@@ -737,107 +737,6 @@ void CArea::__LoadAttribute(TObjectInstance * pObjectInstance, const char * c_sz
}
/*
void CArea::__LoadAttribute(TObjectInstance * pObjectInstance, const char * c_szAttributeFileName)
{
// AABB를 사용한 충돌 정보 자동 생성.
const bool bFileExist = CResourceManager::Instance().IsFileExist(c_szAttributeFileName);
CAttributeData * pAttributeData = (CAttributeData *) CResourceManager::Instance().GetResourcePointer(c_szAttributeFileName);
CAttributeInstance * pAttrInstance = ms_AttributeInstancePool.Alloc();
pAttrInstance->Clear();
pAttrInstance->SetObjectPointer(pAttributeData);
if (false == bFileExist)
{
if (pAttributeData->IsEmpty())
{
if (NULL != pObjectInstance && NULL != pObjectInstance->pThingInstance)
{
CGraphicThingInstance* object = pObjectInstance->pThingInstance;
D3DXVECTOR3 v3Min, v3Max;
object->GetBoundingAABB(v3Min, v3Max);
CStaticCollisionData collision;
collision.dwType = COLLISION_TYPE_AABB;
collision.quatRotation = D3DXQUATERNION(0.0f, 0.0f, 0.0f, 1.0f);
strcpy(collision.szName, "DummyCollisionAABB");
collision.v3Position = (v3Min + v3Max) * 0.5f;
D3DXVECTOR3 vDelta = (v3Max - v3Min);
collision.fDimensions[0] = vDelta.x * 0.5f; // v3Min, v3Max를 구하기 위한 가로, 세로, 높이의 절반값 저장
collision.fDimensions[1] = vDelta.y * 0.5f;
collision.fDimensions[2] = vDelta.z * 0.5f;
pAttributeData->AddCollisionData(collision);
}
}
}
if (!pAttributeData->IsEmpty())
{
pObjectInstance->pAttributeInstance = pAttrInstance;
}
else
{
pAttrInstance->Clear();
ms_AttributeInstancePool.Free(pAttrInstance);
}
}
*/
/*
void CArea::__LoadAttribute(TObjectInstance * pObjectInstance, const char * c_szAttributeFileName)
{
// Sphere를 사용한 충돌 정보 자동 생성.
const bool bFileExist = CResourceManager::Instance().IsFileExist(c_szAttributeFileName);
CAttributeData * pAttributeData = (CAttributeData *) CResourceManager::Instance().GetResourcePointer(c_szAttributeFileName);
CAttributeInstance * pAttrInstance = ms_AttributeInstancePool.Alloc();
pAttrInstance->Clear();
pAttrInstance->SetObjectPointer(pAttributeData);
if (false == bFileExist)
{
if (pAttributeData->IsEmpty())
{
if (NULL != pObjectInstance && NULL != pObjectInstance->pThingInstance)
{
CGraphicThingInstance* object = pObjectInstance->pThingInstance;
D3DXVECTOR3 v3Center;
float fRadius = 0.0f;
object->GetBoundingSphere(v3Center, fRadius);
CStaticCollisionData collision;
collision.dwType = COLLISION_TYPE_SPHERE;
collision.quatRotation = D3DXQUATERNION(0.0f, 0.0f, 0.0f, 1.0f);
strcpy(collision.szName, "DummyCollisionSphere");
collision.fDimensions[0] = fRadius * 0.25;
collision.v3Position = v3Center;
pAttributeData->AddCollisionData(collision);
}
}
}
if (!pAttributeData->IsEmpty())
{
pObjectInstance->pAttributeInstance = pAttrInstance;
}
else
{
pAttrInstance->Clear();
ms_AttributeInstancePool.Free(pAttrInstance);
}
}
*/
bool CArea::Load(const char * c_szPathName)
{

View File

@@ -47,72 +47,6 @@ bool DetectCollisionDynamicSphereVSDynamicSphere(const CDynamicSphereInstance &
float r = c_rSphere1.fRadius+c_rSphere2.fRadius;
float rsq = r*r;
/*if (D3DXVec3LengthSq(&(c_rSphere1.v3Position -c_rSphere2.v3Position ))<=rsq) return true;
if (D3DXVec3LengthSq(&(c_rSphere1.v3Position -c_rSphere2.v3LastPosition ))<=rsq) return true;
if (D3DXVec3LengthSq(&(c_rSphere1.v3LastPosition -c_rSphere2.v3Position ))<=rsq) return true;
if (D3DXVec3LengthSq(&(c_rSphere1.v3LastPosition -c_rSphere2.v3LastPosition ))<=rsq) return true;*/
/*
if (square_distance_between_linesegment_and_point(
c_rSphere1.v3Position,
c_rSphere1.v3LastPosition,
c_rSphere2.v3Position
)<=rsq) return true;
if (square_distance_between_linesegment_and_point(
c_rSphere1.v3Position,
c_rSphere1.v3LastPosition,
c_rSphere2.v3LastPosition
)<=rsq) return true;
if (square_distance_between_linesegment_and_point(
c_rSphere2.v3Position,
c_rSphere2.v3LastPosition,
c_rSphere1.v3Position
)<=rsq) return true;
if (square_distance_between_linesegment_and_point(
c_rSphere2.v3Position,
c_rSphere2.v3LastPosition,
c_rSphere1.v3LastPosition
)<=rsq) return true;
D3DXVECTOR3 da=c_rSphere1.v3Position-c_rSphere1.v3LastPosition;
D3DXVECTOR3 db=c_rSphere2.v3Position-c_rSphere2.v3LastPosition;
D3DXVECTOR3 n;
float la = D3DXVec3Length(&da);
float lb = D3DXVec3Length(&db);
if (la==0||lb==0)
{
D3DXVECTOR3 vA, vB;
IntersectLineSegments(
c_rSphere1.v3LastPosition.x,c_rSphere1.v3LastPosition.y,c_rSphere1.v3LastPosition.z,
c_rSphere1.v3Position.x, c_rSphere1.v3Position.y, c_rSphere1.v3Position.z,
c_rSphere2.v3LastPosition.x,c_rSphere2.v3LastPosition.y,c_rSphere2.v3LastPosition.z,
c_rSphere2.v3Position.x, c_rSphere2.v3Position.y, c_rSphere2.v3Position.z,
false, 1.e-5f, vA.x, vA.y, vA.z, vB.x, vB.y, vB.z);
return (D3DXVec3LengthSq(&(vA-vB))<=r*r);
}
D3DXVECTOR3 p=c_rSphere2.v3Position - c_rSphere1.v3LastPosition;
D3DXVec3Cross(&n, &da, &db);
float from_plane = D3DXVec3Dot(&n,&p)/la/lb;
if (from_plane>r || from_plane<-r)
return false;
p-=(from_plane/la/lb)*n;
float ta = D3DXVec3Dot(&p,&da)/la/la;
float tb = D3DXVec3Dot(&p,&db)/lb/lb;
// FIXME 구 체크가 아니다
if (ta<0)
return false;
if (tb<0)
return false;
if (ta>1)
return false;
if (tb>1)
return false;
return true;
*/
//*/
// using gpg line-collision
// AABB check
@@ -133,144 +67,14 @@ bool DetectCollisionDynamicSphereVSDynamicSphere(const CDynamicSphereInstance &
if (mi4.y<mi1.y || mi2.y<mi3.y) return false;
if (mi4.z<mi1.z || mi2.z<mi3.z) return false;
D3DXVECTOR3 vA, vB;/*
IntersectLineSegments(
c_rSphere1.v3LastPosition.x,c_rSphere1.v3LastPosition.y,c_rSphere1.v3LastPosition.z,
c_rSphere1.v3Position.x, c_rSphere1.v3Position.y, c_rSphere1.v3Position.z,
c_rSphere2.v3LastPosition.x,c_rSphere2.v3LastPosition.y,c_rSphere2.v3LastPosition.z,
c_rSphere2.v3Position.x, c_rSphere2.v3Position.y, c_rSphere2.v3Position.z,
false, 1.e-1f, vA.x, vA.y, vA.z, vB.x, vB.y, vB.z);*/
D3DXVECTOR3 vA, vB;
IntersectLineSegments(c_rSphere1.v3LastPosition, c_rSphere1.v3Position,
c_rSphere2.v3LastPosition, c_rSphere2.v3Position,
vA, vB);
const auto vvv = (vA - vB);
return (D3DXVec3LengthSq(&vvv)<=rsq);
//*/
/*
// NOTE : AABB 체크 할 것
///////////////////////////////////////////////////////////////////////////////////////////////
D3DXVECTOR3 v3Distance = c_rSphere1.v3Position - c_rSphere2.v3Position;
float fDistance = D3DXVec3Length(&v3Distance);
float fRadiusSummary = c_rSphere1.fRadius + c_rSphere2.fRadius;
if (fDistance < fRadiusSummary)
return true;
///////////////////////////////////////////////////////////////////////////////////////////////
D3DXVECTOR3 v3LastDistance = c_rSphere1.v3LastPosition - c_rSphere2.v3LastPosition; // A
D3DXVECTOR3 v3Advance = c_rSphere1.v3Advance - c_rSphere2.v3Advance; // B
float fdotAdvanceAdvance = D3DXVec3Dot(&v3Advance, &v3Advance);
if (0.0f == fdotAdvanceAdvance)
return false;
float fdotDistanceAdvance = D3DXVec3Dot(&v3LastDistance, &v3Advance);
float fdotDistanceDistance = D3DXVec3Dot(&v3LastDistance, &v3LastDistance);
float Value1 = fdotDistanceAdvance - fdotAdvanceAdvance * (fdotDistanceDistance - (fRadiusSummary * fRadiusSummary));
if (Value1 < 0.0f)
return false;
float Value2 = (-fdotDistanceAdvance - sqrtf(Value1)) / fdotAdvanceAdvance;
if (Value2 < 0.0f)
return false;
if (Value2 >= 1.0f)
return false;
return true;*/
}
/*
// Dynamic VS Static
bool DetectCollisionDynamicSphereVSStaticPlane(const CDynamicSphereInstance & c_rSphere, const TPlaneData & c_rPlane)
{
D3DXVECTOR3 v3SpherePosition = c_rSphere.v3Position - c_rPlane.v3Position;
D3DXVECTOR3 v3SphereLastPosition = c_rSphere.v3LastPosition - c_rPlane.v3Position;
float fPosition1 = D3DXVec3Dot(&c_rPlane.v3Normal, &v3SpherePosition);
float fPosition2 = D3DXVec3Dot(&c_rPlane.v3Normal, &v3SphereLastPosition);
if (fPosition1 >0.0f && fPosition2 < 0.0f || fPosition1 <0.0f && fPosition2 >0.0f || (fPosition1) <= c_rSphere.fRadius && fPosition1 >= -c_rSphere.fRadius)
{
D3DXVECTOR3 v3QuadPosition1 = c_rSphere.v3Position - c_rPlane.v3QuadPosition[0];
D3DXVECTOR3 v3QuadPosition2 = c_rSphere.v3Position - c_rPlane.v3QuadPosition[3];
if (D3DXVec3Dot(&v3QuadPosition1, &c_rPlane.v3InsideVector[0]) < c_rSphere.fRadius)
if (D3DXVec3Dot(&v3QuadPosition1, &c_rPlane.v3InsideVector[1]) < c_rSphere.fRadius)
if (D3DXVec3Dot(&v3QuadPosition2, &c_rPlane.v3InsideVector[2]) < c_rSphere.fRadius)
if (D3DXVec3Dot(&v3QuadPosition2, &c_rPlane.v3InsideVector[3]) < c_rSphere.fRadius)
return true;
}
return false;
}
bool DetectCollisionDynamicSphereVSStaticSphere(const CDynamicSphereInstance & c_rSphere, const TSphereData & c_rSphereData)
{
D3DXVECTOR3 v3Distance = c_rSphere.v3Position - c_rSphereData.v3Position;
float fDistanceSq = D3DXVec3LengthSq(&v3Distance);
float fRadiusSummary = c_rSphere.fRadius + c_rSphereData.fRadius;
if (fDistanceSq < fRadiusSummary*fRadiusSummary)
return true;
//D3DXVECTOR3 v3LastDistance = c_rSphere.v3LastPosition - c_rSphereData.v3Position;
//if (D3DXVec3Dot(&v3LastDistance, &v3Distance) < 0.0f)
// return true;
return false;
}
bool DetectCollisionDynamicSphereVSStaticCylinder(const CDynamicSphereInstance & c_rSphere, const TCylinderData & c_rCylinderData)
{
if (c_rSphere.v3Position.z + c_rSphere.fRadius < c_rCylinderData.v3Position.z)
return false;
if (c_rSphere.v3Position.z - c_rSphere.fRadius > c_rCylinderData.v3Position.z + c_rCylinderData.fHeight)
return false;
D3DXVECTOR3 v3curDistance = c_rSphere.v3Position - c_rCylinderData.v3Position;
float fDistance = D3DXVec3Length(&v3curDistance);
if (fDistance <= c_rSphere.fRadius + c_rCylinderData.fRadius)
return true;
//D3DXVECTOR3 v3lastDistance = c_rSphere.v3LastPosition - c_rCylinderData.v3Position;
//if (D3DXVec3Dot(&v3curDistance, &v3lastDistance) < 0.0f)
// return true;
return false;
}
*/
/*
bool DetectCollisionDynamicSphereVSStaticBox(const TSphereInstance & c_rSphere, const TBoxData & c_rBoxData)
{
return false;
}
*/
// Static VS Static
/*
bool DetectCollisionStaticSphereVSStaticSphere(const TSphereData & c_rSphere1, const TSphereData & c_rSphere2)
{
D3DXVECTOR3 v3Distance = c_rSphere1.v3Position - c_rSphere2.v3Position;
float fDistance = D3DXVec3Length(&v3Distance);
if (fDistance < c_rSphere1.fRadius + c_rSphere2.fRadius)
return true;
return false;
}
bool DetectCollisionStaticSphereVSStaticCylinder(const TSphereData & c_rSphere, const TCylinderData & c_rCylinder)
{
return false;
}
*/
/*bool DetectCollisionStaticSphereVSStaticBox(const TSphereData & c_rSphere, const TBoxData & c_rBox)
{
return false;
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////
bool IsCWAcuteAngle(float begin, float end)
@@ -402,33 +206,3 @@ float CharacterRotationToCameraRotation(float fCharacterRotation)
return fmod((540.0f - fCharacterRotation), 360.0f);
}
/*
bool DetectCollisionDynamicSphereVSStaticPlane(const TSphereInstance & c_rSphere, const TPlaneData & c_rPlane)
{
D3DXVECTOR3 v3SpherePosition = c_rSphere.v3Position - c_rPlane.v3Position;
D3DXVECTOR3 v3SphereLastPosition = c_rSphere.v3LastPosition - c_rPlane.v3Position;
float fPosition1 = D3DXVec3Dot(&c_rPlane.v3Normal, &v3SpherePosition);
float fPosition2 = D3DXVec3Dot(&c_rPlane.v3Normal, &v3SphereLastPosition);
if (fPosition1 * fPosition2 < 0.0f || fabs(fPosition1) <= c_rSphere.fRadius)
{
float fT = -fPosition1 / D3DXVec3Dot(&c_rPlane.v3Normal, &c_rSphere.v3Advance);
D3DXVECTOR3 v3CollisionPosition = c_rSphere.v3LastPosition + c_rSphere.v3Advance * fT;
D3DXVECTOR3 v3QuadPosition1 = v3CollisionPosition - c_rPlane.v3BeginPosition;
D3DXVECTOR3 v3QuadPosition2 = v3CollisionPosition - c_rPlane.v3EndPosition;
D3DXVec3Normalize(&v3QuadPosition1, &v3QuadPosition1);
D3DXVec3Normalize(&v3QuadPosition2, &v3QuadPosition2);
if (D3DXVec3Dot(&v3QuadPosition1, &c_rPlane.v3InsideVector[0]) < 0.0f)
if (D3DXVec3Dot(&v3QuadPosition1, &c_rPlane.v3InsideVector[1]) < 0.0f)
if (D3DXVec3Dot(&v3QuadPosition2, &c_rPlane.v3InsideVector[2]) < 0.0f)
if (D3DXVec3Dot(&v3QuadPosition2, &c_rPlane.v3InsideVector[3]) < 0.0f)
{
return true;
}
}
return false;
}
*/

View File

@@ -565,61 +565,6 @@ bool CMapOutdoor::GetPickingPointWithRayOnlyTerrain(const CRay & rRay, D3DXVECTO
return false;
}
/*
{
bool bTerrainPick = false;
D3DXVECTOR3 v3TerrainPick;
CTerrain * pTerrain;
D3DXVECTOR3 v3Start, v3End, v3Dir, v3CurPos;
float fRayRange;
rRay.GetStartPoint(&v3Start);
rRay.GetDirection(&v3Dir, &fRayRange);
rRay.GetEndPoint(&v3End);
Vector3d v3dStart, v3dEnd;
v3dStart.Set(v3Start.x, v3Start.y, v3Start.z);
v3dEnd.Set(v3End.x - v3Start.x, v3End.y - v3Start.y, v3End.z - v3Start.z);
float fAdd = 1.0f / fRayRange;
float ft = 0.0f;
while (ft < 1.0f)
{
D3DXVec3Lerp(&v3CurPos, &v3Start, &v3End, ft);
BYTE byTerrainNum;
float fMultiplier = 1.0f;
if (GetTerrainNum(v3CurPos.x, v3CurPos.y, &byTerrainNum))
{
if (GetTerrainPointer(byTerrainNum, &pTerrain))
{
int ix, iy;
PR_FLOAT_TO_INT(v3CurPos.x, ix);
PR_FLOAT_TO_INT(fabs(v3CurPos.y), iy);
float fMapHeight = pTerrain->GetHeight(ix, iy);
if ( fMapHeight >= v3CurPos.z)
{
bTerrainPick = true;
v3TerrainPick = v3CurPos;
break;
}
else
fMultiplier = fMAX(1.0f, 0.01f * ( v3CurPos.z - fMapHeight ) );
}
}
ft += fAdd * fMultiplier;
}
if (bTerrainPick)
{
*v3IntersectPt = v3TerrainPick;
return true;
}
return false;
}
*/
void CMapOutdoor::GetHeightMap(const BYTE & c_rucTerrainNum, WORD ** pwHeightMap)
{

View File

@@ -47,27 +47,6 @@ CTerrainQuadtreeNode * CMapOutdoor::AllocQuadTreeNode(long x0, long y0, long x1,
Node->PatchNum = y0 * m_wPatchCount + x0;
/*
const float fTerrainMin = -(float) (m_lViewRadius * m_lCellScale);
minx = fTerrainMin + x0 * c_byPatchSize * m_lCellScale;
maxx = fTerrainMin + (x1 + 1) * c_byPatchSize * m_lCellScale;
miny = fTerrainMin + y0 * c_byPatchSize * m_lCellScale;
maxy = fTerrainMin + (y1 + 1) * c_byPatchSize * m_lCellScale;
minz = 0.0f;
maxz = 0.0f;
/ * Set up 8 vertices that belong to the bounding box * /
Node->center.x = minx + (maxx - minx) * 0.5f;
Node->center.y = miny + (maxy - miny) * 0.5f;
Node->center.z = minz + (maxz - minz) * 0.5f;
Node->radius = sqrtf(
(maxx-minx)*(maxx-minx)+
(maxy-miny)*(maxy-miny)+
(maxz-minz)*(maxz-minz)
)/2.0f;
*/
Node->center.x = 0.0f;
Node->center.y = 0.0f;
@@ -105,36 +84,6 @@ void CMapOutdoor::SubDivideNode(CTerrainQuadtreeNode * Node)
SubDivideNode (tempnode);
}
/*
void CMapOutdoor::RecurseDeleteQuadTree(CTerrainQuadtreeNode *Node)
{
if (Node == NULL)
return;
if (Node->NW_Node != NULL)
{
RecurseDeleteQuadTree(Node->NW_Node);
Node->NW_Node = NULL;
}
if (Node->NE_Node != NULL)
{
RecurseDeleteQuadTree(Node->NE_Node);
Node->NE_Node = NULL;
}
if (Node->SW_Node != NULL)
{
RecurseDeleteQuadTree(Node->SW_Node);
Node->SW_Node = NULL;
}
if (Node->SE_Node != NULL)
{
RecurseDeleteQuadTree(Node->SE_Node);
Node->SE_Node = NULL;
}
free(Node);
}
*/
void CMapOutdoor::FreeQuadTree()
{

View File

@@ -52,7 +52,6 @@ class IAbstractPlayer : public TAbstractSingleton<IAbstractPlayer>
virtual void NotifyChangePKMode() = 0;
virtual void SetObserverMode(bool isEnable) = 0;
virtual void SetMobileFlag(BOOL bFlag) = 0;
virtual void SetComboSkillFlag(BOOL bFlag) = 0;
virtual void StartEmotionProcess() = 0;

View File

@@ -63,19 +63,16 @@ bool CAccountConnector::__StateProcess()
bool CAccountConnector::__HandshakeState_Process()
{
if (!__AnalyzePacket(HEADER_GC_PHASE, sizeof(TPacketGCPhase), &CAccountConnector::__AuthState_RecvPhase))
if (!__AnalyzePacket(GC::PHASE, sizeof(TPacketGCPhase), &CAccountConnector::__AuthState_RecvPhase))
return false;
if (!__AnalyzePacket(HEADER_GC_HANDSHAKE, sizeof(TPacketGCHandshake), &CAccountConnector::__AuthState_RecvHandshake))
if (!__AnalyzePacket(GC::PING, sizeof(TPacketGCPing), &CAccountConnector::__AuthState_RecvPingBase))
return false;
if (!__AnalyzePacket(HEADER_GC_PING, sizeof(TPacketGCPing), &CAccountConnector::__AuthState_RecvPing))
if (!__AnalyzePacket(GC::KEY_CHALLENGE, sizeof(TPacketGCKeyChallenge), &CAccountConnector::__AuthState_RecvKeyChallengeBase))
return false;
if (!__AnalyzePacket(HEADER_GC_KEY_CHALLENGE, sizeof(TPacketGCKeyChallenge), &CAccountConnector::__AuthState_RecvKeyChallenge))
return false;
if (!__AnalyzePacket(HEADER_GC_KEY_COMPLETE, sizeof(TPacketGCKeyComplete), &CAccountConnector::__AuthState_RecvKeyComplete))
if (!__AnalyzePacket(GC::KEY_COMPLETE, sizeof(TPacketGCKeyComplete), &CAccountConnector::__AuthState_RecvKeyCompleteBase))
return false;
return true;
@@ -86,25 +83,22 @@ bool CAccountConnector::__AuthState_Process()
if (!__AnalyzePacket(0, sizeof(BYTE), &CAccountConnector::__AuthState_RecvEmpty))
return true;
if (!__AnalyzePacket(HEADER_GC_PHASE, sizeof(TPacketGCPhase), &CAccountConnector::__AuthState_RecvPhase))
if (!__AnalyzePacket(GC::PHASE, sizeof(TPacketGCPhase), &CAccountConnector::__AuthState_RecvPhase))
return false;
if (!__AnalyzePacket(HEADER_GC_PING, sizeof(TPacketGCPing), &CAccountConnector::__AuthState_RecvPing))
if (!__AnalyzePacket(GC::PING, sizeof(TPacketGCPing), &CAccountConnector::__AuthState_RecvPingBase))
return false;
if (!__AnalyzePacket(HEADER_GC_AUTH_SUCCESS, sizeof(TPacketGCAuthSuccess), &CAccountConnector::__AuthState_RecvAuthSuccess))
if (!__AnalyzePacket(GC::AUTH_SUCCESS, sizeof(TPacketGCAuthSuccess), &CAccountConnector::__AuthState_RecvAuthSuccess))
return true;
if (!__AnalyzePacket(HEADER_GC_LOGIN_FAILURE, sizeof(TPacketGCAuthSuccess), &CAccountConnector::__AuthState_RecvAuthFailure))
if (!__AnalyzePacket(GC::LOGIN_FAILURE, sizeof(TPacketGCAuthSuccess), &CAccountConnector::__AuthState_RecvAuthFailure))
return true;
if (!__AnalyzePacket(HEADER_GC_HANDSHAKE, sizeof(TPacketGCHandshake), &CAccountConnector::__AuthState_RecvHandshake))
if (!__AnalyzePacket(GC::KEY_CHALLENGE, sizeof(TPacketGCKeyChallenge), &CAccountConnector::__AuthState_RecvKeyChallengeBase))
return false;
if (!__AnalyzePacket(HEADER_GC_KEY_CHALLENGE, sizeof(TPacketGCKeyChallenge), &CAccountConnector::__AuthState_RecvKeyChallenge))
return false;
if (!__AnalyzePacket(HEADER_GC_KEY_COMPLETE, sizeof(TPacketGCKeyComplete), &CAccountConnector::__AuthState_RecvKeyComplete))
if (!__AnalyzePacket(GC::KEY_COMPLETE, sizeof(TPacketGCKeyComplete), &CAccountConnector::__AuthState_RecvKeyCompleteBase))
return false;
return true;
@@ -130,7 +124,8 @@ bool CAccountConnector::__AuthState_RecvPhase()
else if (kPacketPhase.phase == PHASE_AUTH)
{
TPacketCGLogin3 LoginPacket;
LoginPacket.header = HEADER_CG_LOGIN3;
LoginPacket.header = CG::LOGIN3;
LoginPacket.length = sizeof(LoginPacket);
strncpy(LoginPacket.name, m_strID.c_str(), ID_MAX_NUM);
strncpy(LoginPacket.pwd, m_strPassword.c_str(), PASS_MAX_NUM);
@@ -149,133 +144,15 @@ bool CAccountConnector::__AuthState_RecvPhase()
return false;
}
if (!SendSequence())
{
return false;
}
__AuthState_Set();
}
return true;
}
bool CAccountConnector::__AuthState_RecvHandshake()
{
TPacketGCHandshake kPacketHandshake;
if (!Recv(sizeof(kPacketHandshake), &kPacketHandshake))
return false;
Tracenf("HANDSHAKE RECV %u %d", kPacketHandshake.dwTime, kPacketHandshake.lDelta);
ELTimer_SetServerMSec(kPacketHandshake.dwTime+ kPacketHandshake.lDelta);
kPacketHandshake.dwTime = kPacketHandshake.dwTime + kPacketHandshake.lDelta + kPacketHandshake.lDelta;
kPacketHandshake.lDelta = 0;
Tracenf("HANDSHAKE SEND %u", kPacketHandshake.dwTime);
if (!Send(sizeof(kPacketHandshake), &kPacketHandshake))
{
Tracen(" CAccountConnector::__AuthState_RecvHandshake - SendHandshake Error");
return false;
}
return true;
}
bool CAccountConnector::__AuthState_RecvKeyChallenge()
{
TPacketGCKeyChallenge packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracen("KEY_CHALLENGE RECV - Starting secure key exchange");
SecureCipher& cipher = GetSecureCipher();
if (!cipher.Initialize())
{
Tracen("SecureCipher initialization failed");
Disconnect();
return false;
}
if (!cipher.ComputeClientKeys(packet.server_pk))
{
Tracen("Failed to compute client session keys");
Disconnect();
return false;
}
TPacketCGKeyResponse response;
response.bHeader = HEADER_CG_KEY_RESPONSE;
cipher.GetPublicKey(response.client_pk);
cipher.ComputeResponse(packet.challenge, response.challenge_response);
if (!Send(sizeof(response), &response))
{
Tracen("Failed to send key response");
return false;
}
Tracen("KEY_RESPONSE SEND - Awaiting key completion");
return true;
}
bool CAccountConnector::__AuthState_RecvKeyComplete()
{
TPacketGCKeyComplete packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracen("KEY_COMPLETE RECV - Decrypting session token");
SecureCipher& cipher = GetSecureCipher();
uint8_t session_token[SecureCipher::SESSION_TOKEN_SIZE];
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
session_token, nullptr,
nullptr,
packet.encrypted_token, sizeof(packet.encrypted_token),
nullptr, 0,
packet.nonce,
cipher.GetRxKey()) != 0)
{
Tracen("Failed to decrypt session token - authentication failed");
Disconnect();
return false;
}
cipher.SetSessionToken(session_token);
cipher.SetActivated(true);
DecryptPendingRecvData();
Tracen("Secure channel established - encryption activated");
return true;
}
bool CAccountConnector::__AuthState_RecvPing()
{
TPacketGCPing kPacketPing;
if (!Recv(sizeof(kPacketPing), &kPacketPing))
return false;
__AuthState_SendPong();
return true;
}
bool CAccountConnector::__AuthState_SendPong()
{
TPacketCGPong kPacketPong;
kPacketPong.bHeader = HEADER_CG_PONG;
kPacketPong.bSequence = GetNextSequence();
if (!Send(sizeof(kPacketPong), &kPacketPong))
return false;
return true;
}
// Key exchange (RecvKeyChallenge, RecvKeyComplete) and ping/pong (RecvPingPacket)
// are now handled by CNetworkStream base class. Thin wrappers in the header
// delegate __AnalyzePacket dispatch to those base methods.
bool CAccountConnector::__AuthState_RecvAuthSuccess()
{
@@ -315,11 +192,11 @@ bool CAccountConnector::__AuthState_RecvAuthFailure()
bool CAccountConnector::__AnalyzePacket(UINT uHeader, UINT uPacketSize, bool (CAccountConnector::*pfnDispatchPacket)())
{
BYTE bHeader;
if (!Peek(sizeof(bHeader), &bHeader))
uint16_t wHeader;
if (!Peek(sizeof(wHeader), &wHeader))
return true;
if (bHeader!=uHeader)
if (wHeader != uHeader)
return true;
if (!Peek(uPacketSize))

View File

@@ -44,13 +44,13 @@ class CAccountConnector : public CNetworkStream, public CSingleton<CAccountConne
bool __AuthState_RecvEmpty();
bool __AuthState_RecvPhase();
bool __AuthState_RecvHandshake();
bool __AuthState_RecvPing();
bool __AuthState_SendPong();
bool __AuthState_RecvAuthSuccess();
bool __AuthState_RecvAuthFailure();
bool __AuthState_RecvKeyChallenge();
bool __AuthState_RecvKeyComplete();
// Thin wrappers for __AnalyzePacket dispatch (delegates to CNetworkStream base)
bool __AuthState_RecvPingBase() { return RecvPingPacket(); }
bool __AuthState_RecvKeyChallengeBase() { return RecvKeyChallenge(); }
bool __AuthState_RecvKeyCompleteBase() { return RecvKeyComplete(); }
bool __AnalyzePacket(UINT uHeader, UINT uPacketSize, bool (CAccountConnector::*pfnDispatchPacket)());

View File

@@ -52,55 +52,6 @@ void CCamera::ProcessTerrainCollision()
}
else
SetCameraState(CAMERA_STATE_NORMAL);
/*
if (rPythonBackground.GetPickingPointWithRayOnlyTerrain(m_kCameraFrontToTerrainRay, &v3CollisionPoint))
{
if (D3DXVec3Length(&(m_v3Eye - v3CollisionPoint)) < 4.0f * m_fTerrainCollisionRadius)
{
D3DXVECTOR3 v3NewEye = v3CollisionPoint - 4.0f * m_fTerrainCollisionRadius * m_v3View;
//printf("CameraFrontToTerrain new %f > old %f", v3NewEye.z, m_v3Eye.z);
SetEye(v3NewEye);
}
}
if (rPythonBackground.GetPickingPointWithRayOnlyTerrain(m_kCameraBackToTerrainRay, &v3CollisionPoint))
{
if (D3DXVec3Length(&(m_v3Eye - v3CollisionPoint)) < m_fTerrainCollisionRadius)
{
D3DXVECTOR3 v3NewEye = v3CollisionPoint + m_fTerrainCollisionRadius * m_v3View;
//printf("CameraBackToTerrain new %f > old %f", v3NewEye.z, m_v3Eye.z);
SetEye(v3NewEye);
}
}
// Left
if (rPythonBackground.GetPickingPointWithRayOnlyTerrain(m_kCameraLeftToTerrainRay, &v3CollisionPoint))
{
SetCameraState(CAMERA_STATE_CANTGOLEFT);
if (D3DXVec3Length(&(m_v3Eye - v3CollisionPoint)) < 3.0f * m_fTerrainCollisionRadius)
{
D3DXVECTOR3 v3NewEye = v3CollisionPoint + 3.0f * m_fTerrainCollisionRadius * m_v3Cross;
//printf("CameraLeftToTerrain new %f > old %f", v3NewEye.z, m_v3Eye.z);
SetEye(v3NewEye);
}
}
else
SetCameraState(CAMERA_STATE_NORMAL);
// Right
if (rPythonBackground.GetPickingPointWithRayOnlyTerrain(m_kCameraRightToTerrainRay, &v3CollisionPoint))
{
SetCameraState(CAMERA_STATE_CANTGORIGHT);
if (D3DXVec3Length(&(m_v3Eye - v3CollisionPoint)) < 3.0f * m_fTerrainCollisionRadius)
{
D3DXVECTOR3 v3NewEye = v3CollisionPoint - 3.0f * m_fTerrainCollisionRadius * m_v3Cross;
//printf("CameraRightToTerrain new %f > old %f", v3NewEye.z, m_v3Eye.z);
SetEye(v3NewEye);
}
}
else
SetCameraState(CAMERA_STATE_NORMAL);
*/
}
struct CameraCollisionChecker

View File

@@ -147,9 +147,9 @@ void CGuildMarkDownloader::__LoginState_Set()
bool CGuildMarkDownloader::__LoginState_Process()
{
BYTE header;
uint16_t header;
if (!Peek(sizeof(BYTE), &header))
if (!Peek(sizeof(uint16_t), &header))
return true;
if (IsSecurityMode())
@@ -158,11 +158,11 @@ bool CGuildMarkDownloader::__LoginState_Process()
{
if (!Recv(sizeof(header), &header))
return false;
return true;
}
}
UINT needPacketSize = __GetPacketSize(header);
if (!needPacketSize)
@@ -180,23 +180,21 @@ UINT CGuildMarkDownloader::__GetPacketSize(UINT header)
{
switch (header)
{
case HEADER_GC_PHASE:
case GC::PHASE:
return sizeof(TPacketGCPhase);
case HEADER_GC_HANDSHAKE:
return sizeof(TPacketGCHandshake);
case HEADER_GC_PING:
case GC::PING:
return sizeof(TPacketGCPing);
case HEADER_GC_MARK_IDXLIST:
case GC::MARK_IDXLIST:
return sizeof(TPacketGCMarkIDXList);
case HEADER_GC_MARK_BLOCK:
case GC::MARK_BLOCK:
return sizeof(TPacketGCMarkBlock);
case HEADER_GC_GUILD_SYMBOL_DATA:
case GC::SYMBOL_DATA:
return sizeof(TPacketGCGuildSymbolData);
case HEADER_GC_MARK_DIFF_DATA:
case GC::MARK_DIFF_DATA:
return sizeof(BYTE);
case HEADER_GC_KEY_CHALLENGE:
case GC::KEY_CHALLENGE:
return sizeof(TPacketGCKeyChallenge);
case HEADER_GC_KEY_COMPLETE:
case GC::KEY_COMPLETE:
return sizeof(TPacketGCKeyComplete);
}
return 0;
@@ -206,63 +204,28 @@ bool CGuildMarkDownloader::__DispatchPacket(UINT header)
{
switch (header)
{
case HEADER_GC_PHASE:
case GC::PHASE:
return __LoginState_RecvPhase();
case HEADER_GC_HANDSHAKE:
return __LoginState_RecvHandshake();
case HEADER_GC_PING:
return __LoginState_RecvPing();
case HEADER_GC_MARK_IDXLIST:
case GC::PING:
return RecvPingPacket();
case GC::MARK_IDXLIST:
return __LoginState_RecvMarkIndex();
case HEADER_GC_MARK_BLOCK:
case GC::MARK_BLOCK:
return __LoginState_RecvMarkBlock();
case HEADER_GC_GUILD_SYMBOL_DATA:
case GC::SYMBOL_DATA:
return __LoginState_RecvSymbolData();
case HEADER_GC_MARK_DIFF_DATA:
case GC::MARK_DIFF_DATA:
return true;
case HEADER_GC_KEY_CHALLENGE:
return __LoginState_RecvKeyChallenge();
case HEADER_GC_KEY_COMPLETE:
return __LoginState_RecvKeyComplete();
case GC::KEY_CHALLENGE:
return RecvKeyChallenge();
case GC::KEY_COMPLETE:
return __LoginState_RecvKeyCompleteAndLogin();
}
return false;
}
// END_OF_MARK_BUG_FIX
bool CGuildMarkDownloader::__LoginState_RecvHandshake()
{
TPacketGCHandshake kPacketHandshake;
if (!Recv(sizeof(kPacketHandshake), &kPacketHandshake))
return false;
TPacketCGMarkLogin kPacketMarkLogin;
kPacketMarkLogin.header = HEADER_CG_MARK_LOGIN;
kPacketMarkLogin.handle = m_dwHandle;
kPacketMarkLogin.random_key = m_dwRandomKey;
if (!Send(sizeof(kPacketMarkLogin), &kPacketMarkLogin))
return false;
return true;
}
bool CGuildMarkDownloader::__LoginState_RecvPing()
{
TPacketGCPing kPacketPing;
if (!Recv(sizeof(kPacketPing), &kPacketPing))
return false;
TPacketCGPong kPacketPong;
kPacketPong.bHeader = HEADER_CG_PONG;
kPacketPong.bSequence = GetNextSequence();
if (!Send(sizeof(TPacketCGPong), &kPacketPong))
return false;
return true;
}
// Ping/pong now handled by CNetworkStream::RecvPingPacket()
bool CGuildMarkDownloader::__LoginState_RecvPhase()
{
@@ -304,7 +267,8 @@ bool CGuildMarkDownloader::__LoginState_RecvPhase()
bool CGuildMarkDownloader::__SendMarkIDXList()
{
TPacketCGMarkIDXList kPacketMarkIDXList;
kPacketMarkIDXList.header = HEADER_CG_MARK_IDXLIST;
kPacketMarkIDXList.header = CG::MARK_IDXLIST;
kPacketMarkIDXList.length = sizeof(kPacketMarkIDXList);
if (!Send(sizeof(kPacketMarkIDXList), &kPacketMarkIDXList))
return false;
@@ -354,7 +318,8 @@ bool CGuildMarkDownloader::__SendMarkCRCList()
}
else
{
kPacketMarkCRCList.header = HEADER_CG_MARK_CRCLIST;
kPacketMarkCRCList.header = CG::MARK_CRCLIST;
kPacketMarkCRCList.length = sizeof(kPacketMarkCRCList);
kPacketMarkCRCList.imgIdx = m_currentRequestingImageIndex;
++m_currentRequestingImageIndex;
@@ -417,62 +382,24 @@ bool CGuildMarkDownloader::__LoginState_RecvMarkBlock()
}
// END_OF_MARK_BUG_FIX
bool CGuildMarkDownloader::__LoginState_RecvKeyChallenge()
// RecvKeyChallenge now handled by CNetworkStream::RecvKeyChallenge()
// RecvKeyComplete + mark-specific login authentication
bool CGuildMarkDownloader::__LoginState_RecvKeyCompleteAndLogin()
{
TPacketGCKeyChallenge packet;
if (!Recv(sizeof(packet), &packet))
if (!CNetworkStream::RecvKeyComplete())
return false;
Tracen("KEY_CHALLENGE RECV");
// Send mark login (authentication) now that secure channel is established
TPacketCGMarkLogin kPacketMarkLogin;
kPacketMarkLogin.header = CG::MARK_LOGIN;
kPacketMarkLogin.length = sizeof(kPacketMarkLogin);
kPacketMarkLogin.handle = m_dwHandle;
kPacketMarkLogin.random_key = m_dwRandomKey;
SecureCipher& cipher = GetSecureCipher();
if (!cipher.Initialize())
{
Disconnect();
return false;
}
if (!cipher.ComputeClientKeys(packet.server_pk))
{
Disconnect();
return false;
}
TPacketCGKeyResponse response;
response.bHeader = HEADER_CG_KEY_RESPONSE;
cipher.GetPublicKey(response.client_pk);
cipher.ComputeResponse(packet.challenge, response.challenge_response);
if (!Send(sizeof(response), &response))
if (!Send(sizeof(kPacketMarkLogin), &kPacketMarkLogin))
return false;
Tracen("KEY_RESPONSE SENT");
return true;
}
bool CGuildMarkDownloader::__LoginState_RecvKeyComplete()
{
TPacketGCKeyComplete packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracen("KEY_COMPLETE RECV");
SecureCipher& cipher = GetSecureCipher();
uint8_t session_token[SecureCipher::SESSION_TOKEN_SIZE];
if (!cipher.DecryptToken(packet.encrypted_token, sizeof(packet.encrypted_token),
packet.nonce, session_token))
{
Disconnect();
return false;
}
cipher.SetSessionToken(session_token);
cipher.SetActivated(true);
DecryptPendingRecvData();
Tracen("SECURE CIPHER ACTIVATED");
return true;
}
@@ -481,7 +408,8 @@ bool CGuildMarkDownloader::__SendSymbolCRCList()
for (DWORD i=0; i<m_kVec_dwGuildID.size(); ++i)
{
TPacketCGSymbolCRC kSymbolCRCPacket;
kSymbolCRCPacket.header = HEADER_CG_GUILD_SYMBOL_CRC;
kSymbolCRCPacket.header = CG::SYMBOL_CRC;
kSymbolCRCPacket.length = sizeof(kSymbolCRCPacket);
kSymbolCRCPacket.dwGuildID = m_kVec_dwGuildID[i];
std::string strFileName = GetGuildSymbolFileName(m_kVec_dwGuildID[i]);
@@ -504,9 +432,9 @@ bool CGuildMarkDownloader::__LoginState_RecvSymbolData()
return true;
#ifdef _DEBUG
printf("__LoginState_RecvSymbolData [%d/%d]\n", GetRecvBufferSize(), packet.size);
printf("__LoginState_RecvSymbolData [%d/%d]\n", GetRecvBufferSize(), packet.length);
#endif
if (packet.size > GetRecvBufferSize())
if (packet.length > GetRecvBufferSize())
return true;
//////////////////////////////////////////////////////////////
@@ -515,7 +443,7 @@ bool CGuildMarkDownloader::__LoginState_RecvSymbolData()
if (!Recv(sizeof(kPacketSymbolData), &kPacketSymbolData))
return false;
WORD wDataSize = kPacketSymbolData.size - sizeof(kPacketSymbolData);
WORD wDataSize = kPacketSymbolData.length - sizeof(kPacketSymbolData);
DWORD dwGuildID = kPacketSymbolData.guild_id;
BYTE * pbyBuf = new BYTE [wDataSize];

View File

@@ -49,13 +49,10 @@ class CGuildMarkDownloader : public CNetworkStream, public CSingleton<CGuildMark
void __LoginState_Set();
bool __LoginState_Process();
bool __LoginState_RecvPhase();
bool __LoginState_RecvHandshake();
bool __LoginState_RecvPing();
bool __LoginState_RecvMarkIndex();
bool __LoginState_RecvMarkBlock();
bool __LoginState_RecvSymbolData();
bool __LoginState_RecvKeyChallenge();
bool __LoginState_RecvKeyComplete();
bool __LoginState_RecvKeyCompleteAndLogin();
bool __SendMarkIDXList();
bool __SendMarkCRCList();
bool __SendSymbolCRCList();

View File

@@ -9,7 +9,6 @@
#else
CGuildMarkUploader::CGuildMarkUploader()
: m_pbySymbolBuf(NULL)
{
SetRecvBufferSize(1024);
SetSendBufferSize(1024);
@@ -115,7 +114,7 @@ bool CGuildMarkUploader::__LoadSymbol(const char* c_szFileName, UINT* peError)
stbi_image_free(data);
// Now read raw file into m_pbySymbolBuf (same as original code did)
// Read raw file into m_symbolBuf
FILE* file = fopen(c_szFileName, "rb");
if (!file) {
*peError = ERROR_LOAD;
@@ -123,11 +122,11 @@ bool CGuildMarkUploader::__LoadSymbol(const char* c_szFileName, UINT* peError)
}
fseek(file, 0, SEEK_END);
m_dwSymbolBufSize = ftell(file);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
m_pbySymbolBuf = new uint8_t[m_dwSymbolBufSize];
fread(m_pbySymbolBuf, m_dwSymbolBufSize, 1, file);
m_symbolBuf.resize(static_cast<size_t>(fileSize));
fread(m_symbolBuf.data(), m_symbolBuf.size(), 1, file);
fclose(file);
m_dwSymbolCRC32 = GetFileCRC32(c_szFileName);
@@ -222,13 +221,7 @@ void CGuildMarkUploader::__Inialize()
m_dwHandle = 0;
m_dwRandomKey = 0;
if (m_pbySymbolBuf)
{
delete[] m_pbySymbolBuf;
}
m_dwSymbolBufSize = 0;
m_pbySymbolBuf = NULL;
m_symbolBuf.clear();
}
bool CGuildMarkUploader::__StateProcess()
@@ -263,19 +256,16 @@ void CGuildMarkUploader::__LoginState_Set()
bool CGuildMarkUploader::__LoginState_Process()
{
if (!__AnalyzePacket(HEADER_GC_PHASE, sizeof(TPacketGCPhase), &CGuildMarkUploader::__LoginState_RecvPhase))
if (!__AnalyzePacket(GC::PHASE, sizeof(TPacketGCPhase), &CGuildMarkUploader::__LoginState_RecvPhase))
return false;
if (!__AnalyzePacket(HEADER_GC_HANDSHAKE, sizeof(TPacketGCHandshake), &CGuildMarkUploader::__LoginState_RecvHandshake))
if (!__AnalyzePacket(GC::PING, sizeof(TPacketGCPing), &CGuildMarkUploader::__LoginState_RecvPingBase))
return false;
if (!__AnalyzePacket(HEADER_GC_PING, sizeof(TPacketGCPing), &CGuildMarkUploader::__LoginState_RecvPing))
if (!__AnalyzePacket(GC::KEY_CHALLENGE, sizeof(TPacketGCKeyChallenge), &CGuildMarkUploader::__LoginState_RecvKeyChallengeBase))
return false;
if (!__AnalyzePacket(HEADER_GC_KEY_CHALLENGE, sizeof(TPacketGCKeyChallenge), &CGuildMarkUploader::__LoginState_RecvKeyChallenge))
return false;
if (!__AnalyzePacket(HEADER_GC_KEY_COMPLETE, sizeof(TPacketGCKeyComplete), &CGuildMarkUploader::__LoginState_RecvKeyComplete))
if (!__AnalyzePacket(GC::KEY_COMPLETE, sizeof(TPacketGCKeyComplete), &CGuildMarkUploader::__LoginState_RecvKeyCompleteAndLogin))
return false;
return true;
@@ -284,7 +274,8 @@ bool CGuildMarkUploader::__LoginState_Process()
bool CGuildMarkUploader::__SendMarkPacket()
{
TPacketCGMarkUpload kPacketMarkUpload;
kPacketMarkUpload.header=HEADER_CG_MARK_UPLOAD;
kPacketMarkUpload.header=CG::MARK_UPLOAD;
kPacketMarkUpload.length = sizeof(kPacketMarkUpload);
kPacketMarkUpload.gid=m_dwGuildID;
assert(sizeof(kPacketMarkUpload.image) == sizeof(m_kMark.m_apxBuf));
@@ -297,21 +288,21 @@ bool CGuildMarkUploader::__SendMarkPacket()
}
bool CGuildMarkUploader::__SendSymbolPacket()
{
if (!m_pbySymbolBuf)
if (m_symbolBuf.empty())
return false;
TPacketCGSymbolUpload kPacketSymbolUpload;
kPacketSymbolUpload.header=HEADER_CG_GUILD_SYMBOL_UPLOAD;
kPacketSymbolUpload.header=CG::GUILD_SYMBOL_UPLOAD;
kPacketSymbolUpload.handle=m_dwGuildID;
kPacketSymbolUpload.size=sizeof(TPacketCGSymbolUpload) + m_dwSymbolBufSize;
kPacketSymbolUpload.length=sizeof(TPacketCGSymbolUpload) + static_cast<uint16_t>(m_symbolBuf.size());
if (!Send(sizeof(TPacketCGSymbolUpload), &kPacketSymbolUpload))
return false;
if (!Send(m_dwSymbolBufSize, m_pbySymbolBuf))
if (!Send(static_cast<int>(m_symbolBuf.size()), m_symbolBuf.data()))
return false;
#ifdef _DEBUG
printf("__SendSymbolPacket : [GuildID:%d/PacketSize:%d/BufSize:%d/CRC:%d]\n", m_dwGuildID, kPacketSymbolUpload.size, m_dwSymbolBufSize, m_dwSymbolCRC32);
printf("__SendSymbolPacket : [GuildID:%d/PacketSize:%d/BufSize:%d/CRC:%d]\n", m_dwGuildID, kPacketSymbolUpload.length, (int)m_symbolBuf.size(), m_dwSymbolCRC32);
#endif
CNetworkStream::__SendInternalBuffer();
@@ -343,106 +334,35 @@ bool CGuildMarkUploader::__LoginState_RecvPhase()
return true;
}
bool CGuildMarkUploader::__LoginState_RecvHandshake()
// Ping/pong and key challenge now handled by CNetworkStream base class.
// Thin wrappers in the header delegate __AnalyzePacket dispatch to those base methods.
// RecvKeyComplete + mark-specific login authentication
bool CGuildMarkUploader::__LoginState_RecvKeyCompleteAndLogin()
{
TPacketGCHandshake kPacketHandshake;
if (!Recv(sizeof(kPacketHandshake), &kPacketHandshake))
if (!CNetworkStream::RecvKeyComplete())
return false;
{
TPacketCGMarkLogin kPacketMarkLogin;
kPacketMarkLogin.header=HEADER_CG_MARK_LOGIN;
kPacketMarkLogin.handle=m_dwHandle;
kPacketMarkLogin.random_key=m_dwRandomKey;
if (!Send(sizeof(kPacketMarkLogin), &kPacketMarkLogin))
return false;
}
// Send mark login (authentication) now that secure channel is established
TPacketCGMarkLogin kPacketMarkLogin;
kPacketMarkLogin.header = CG::MARK_LOGIN;
kPacketMarkLogin.length = sizeof(kPacketMarkLogin);
kPacketMarkLogin.handle = m_dwHandle;
kPacketMarkLogin.random_key = m_dwRandomKey;
return true;
}
bool CGuildMarkUploader::__LoginState_RecvPing()
{
TPacketGCPing kPacketPing;
if (!Recv(sizeof(kPacketPing), &kPacketPing))
if (!Send(sizeof(kPacketMarkLogin), &kPacketMarkLogin))
return false;
TPacketCGPong kPacketPong;
kPacketPong.bHeader = HEADER_CG_PONG;
kPacketPong.bSequence = GetNextSequence();
if (!Send(sizeof(TPacketCGPong), &kPacketPong))
return false;
return true;
}
bool CGuildMarkUploader::__LoginState_RecvKeyChallenge()
{
TPacketGCKeyChallenge packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracen("KEY_CHALLENGE RECV");
SecureCipher& cipher = GetSecureCipher();
if (!cipher.Initialize())
{
Disconnect();
return false;
}
if (!cipher.ComputeClientKeys(packet.server_pk))
{
Disconnect();
return false;
}
TPacketCGKeyResponse response;
response.bHeader = HEADER_CG_KEY_RESPONSE;
cipher.GetPublicKey(response.client_pk);
cipher.ComputeResponse(packet.challenge, response.challenge_response);
if (!Send(sizeof(response), &response))
return false;
Tracen("KEY_RESPONSE SENT");
return true;
}
bool CGuildMarkUploader::__LoginState_RecvKeyComplete()
{
TPacketGCKeyComplete packet;
if (!Recv(sizeof(packet), &packet))
return false;
Tracen("KEY_COMPLETE RECV");
SecureCipher& cipher = GetSecureCipher();
uint8_t session_token[SecureCipher::SESSION_TOKEN_SIZE];
if (!cipher.DecryptToken(packet.encrypted_token, sizeof(packet.encrypted_token),
packet.nonce, session_token))
{
Disconnect();
return false;
}
cipher.SetSessionToken(session_token);
cipher.SetActivated(true);
DecryptPendingRecvData();
Tracen("SECURE CIPHER ACTIVATED");
return true;
}
bool CGuildMarkUploader::__AnalyzePacket(UINT uHeader, UINT uPacketSize, bool (CGuildMarkUploader::*pfnDispatchPacket)())
{
BYTE bHeader;
if (!Peek(sizeof(bHeader), &bHeader))
uint16_t wHeader;
if (!Peek(sizeof(wHeader), &wHeader))
return true;
if (bHeader!=uHeader)
if (wHeader != uHeader)
return true;
if (!Peek(uPacketSize))

View File

@@ -86,13 +86,14 @@ class CGuildMarkUploader : public CNetworkStream, public CSingleton<CGuildMarkUp
void __LoginState_Set();
bool __LoginState_Process();
bool __LoginState_RecvPhase();
bool __LoginState_RecvHandshake();
bool __LoginState_RecvPing();
bool __LoginState_RecvKeyChallenge();
bool __LoginState_RecvKeyComplete();
bool __LoginState_RecvKeyCompleteAndLogin();
bool __AnalyzePacket(UINT uHeader, UINT uPacketSize, bool (CGuildMarkUploader::*pfnDispatchPacket)());
// Thin wrappers for __AnalyzePacket dispatch (delegates to CNetworkStream base)
bool __LoginState_RecvPingBase() { return RecvPingPacket(); }
bool __LoginState_RecvKeyChallengeBase() { return RecvKeyChallenge(); }
bool __SendMarkPacket();
bool __SendSymbolPacket();
@@ -106,9 +107,8 @@ class CGuildMarkUploader : public CNetworkStream, public CSingleton<CGuildMarkUp
SGuildMark m_kMark;
DWORD m_dwSymbolBufSize;
DWORD m_dwSymbolCRC32;
uint8_t * m_pbySymbolBuf;
std::vector<uint8_t> m_symbolBuf;
};
#endif

View File

@@ -1164,11 +1164,6 @@ float CInstanceBase::GetLocalTime()
return m_GraphicThingInstance.GetLocalTime();
}
void CInstanceBase::PushUDPState(DWORD dwCmdTime, const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg)
{
}
DWORD ELTimer_GetServerFrameMSec();
void CInstanceBase::PushTCPStateExpanded(DWORD dwCmdTime, const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg, UINT uTargetVID)
@@ -2688,29 +2683,6 @@ DWORD CInstanceBase::GetWeaponType()
return pItemData->GetWeaponType();
}
/*
void CInstanceBase::SetParts(const WORD * c_pParts)
{
if (IsPoly())
return;
if (__IsShapeAnimalWear())
return;
UINT eWeapon=c_pParts[CRaceData::PART_WEAPON];
if (__IsChangableWeapon(eWeapon) == false)
eWeapon = 0;
if (eWeapon != m_GraphicThingInstance.GetPartItemID(CRaceData::PART_WEAPON))
{
m_GraphicThingInstance.AttachPart(CRaceData::PART_MAIN, CRaceData::PART_WEAPON, eWeapon);
m_awPart[CRaceData::PART_WEAPON] = eWeapon;
}
__AttachHorseSaddle();
}
*/
void CInstanceBase::__ClearWeaponRefineEffect()
{

View File

@@ -621,7 +621,6 @@ class CInstanceBase
// Battle
void SetEventHandler(CActorInstance::IEventHandler* pkEventHandler);
void PushUDPState(DWORD dwCmdTime, const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg);
void PushTCPState(DWORD dwCmdTime, const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg);
void PushTCPStateExpanded(DWORD dwCmdTime, const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg, UINT uTargetVID);

View File

@@ -17,26 +17,6 @@ std::string CInstanceBase::ms_astAffectEffectAttachBone[EFFECT_NUM];
#define BYTE_COLOR_TO_D3DX_COLOR(r, g, b) D3DXCOLOR(float(r)/255.0f, float(g)/255.0f, float(b)/255.0f, 1.0f)
/*
D3DXCOLOR CInstanceBase::ms_kD3DXClrPC(0xFFFFD84D);//1.0f, 0.8470f, 0.3f, 1.0f
D3DXCOLOR CInstanceBase::ms_kD3DXClrNPC(0xFF7BE85E);//0.4823f, 0.9098f, 0.3686f, 1.0f
D3DXCOLOR CInstanceBase::ms_kD3DXClrMOB(0xFFEC170a);//0.9254f, 0.0901f, 0.0392f, 1.0f
D3DXCOLOR CInstanceBase::ms_kD3DXClrPVP(0xFF8532D9);
D3DXCOLOR CInstanceBase::ms_kD3DXClrPVPSelf(0xFFEE36DF);
D3DXCOLOR CInstanceBase::ms_kD3DXClrKiller = BYTE_COLOR_TO_D3DX_COLOR(180, 100, 0);
D3DXCOLOR CInstanceBase::ms_kD3DXClrTitle[CInstanceBase::TITLE_MAX_NUM] =
{
BYTE_COLOR_TO_D3DX_COLOR( 0, 204, 255),
BYTE_COLOR_TO_D3DX_COLOR( 0, 144, 255),
BYTE_COLOR_TO_D3DX_COLOR( 92, 110, 255),
BYTE_COLOR_TO_D3DX_COLOR(155, 155, 255),
0xFFFFFFFF, // None
BYTE_COLOR_TO_D3DX_COLOR(207, 117, 0),
BYTE_COLOR_TO_D3DX_COLOR(235, 83, 0),
BYTE_COLOR_TO_D3DX_COLOR(227, 0, 0),
BYTE_COLOR_TO_D3DX_COLOR(255, 0, 0),
};
*/
D3DXCOLOR g_akD3DXClrTitle[CInstanceBase::TITLE_NUM];
D3DXCOLOR g_akD3DXClrName[CInstanceBase::NAMECOLOR_NUM];
@@ -86,14 +66,17 @@ const D3DXCOLOR& CInstanceBase::GetIndexedNameColor(UINT eNameColor)
void CInstanceBase::AddDamageEffect(DWORD damage, BYTE flag, BOOL bSelf, BOOL bTarget)
{
TraceError("AddDamageEffect: damage=%u flag=%u bSelf=%d bTarget=%d IsShowDamage=%d",
damage, flag, bSelf, bTarget, CPythonSystem::Instance().IsShowDamage());
if(CPythonSystem::Instance().IsShowDamage())
{
{
SEffectDamage sDamage;
sDamage.bSelf = bSelf;
sDamage.bTarget = bTarget;
sDamage.damage = damage;
sDamage.flag = flag;
m_DamageQueue.push_back(sDamage);
TraceError("AddDamageEffect: Queued, queue size now=%d", m_DamageQueue.size());
}
}
@@ -102,6 +85,8 @@ void CInstanceBase::ProcessDamage()
if(m_DamageQueue.empty())
return;
TraceError("ProcessDamage: Queue not empty, processing...");
SEffectDamage sDamage = m_DamageQueue.front();
m_DamageQueue.pop_front();
@@ -111,11 +96,13 @@ void CInstanceBase::ProcessDamage()
BOOL bSelf = sDamage.bSelf;
BOOL bTarget = sDamage.bTarget;
CCamera * pCamera = CCameraManager::Instance().GetCurrentCamera();
TraceError("ProcessDamage: damage=%u flag=%u bSelf=%d bTarget=%d", damage, flag, bSelf, bTarget);
CCamera * pCamera = CCameraManager::Instance().GetCurrentCamera();
float cameraAngle = GetDegreeFromPosition2(pCamera->GetTarget().x,pCamera->GetTarget().y,pCamera->GetEye().x,pCamera->GetEye().y);
DWORD FONT_WIDTH = 30;
CEffectManager& rkEftMgr=CEffectManager::Instance();
D3DXVECTOR3 v3Pos = m_GraphicThingInstance.GetPosition();
@@ -125,6 +112,7 @@ void CInstanceBase::ProcessDamage()
if ( (flag & DAMAGE_DODGE) || (flag & DAMAGE_BLOCK) )
{
TraceError("ProcessDamage: DODGE or BLOCK");
if(bSelf)
rkEftMgr.CreateEffect(ms_adwCRCAffectEffect[EFFECT_DAMAGE_MISS],v3Pos,v3Rot);
else
@@ -134,6 +122,7 @@ void CInstanceBase::ProcessDamage()
}
else if (flag & DAMAGE_CRITICAL)
{
TraceError("ProcessDamage: CRITICAL");
//rkEftMgr.CreateEffect(ms_adwCRCAffectEffect[EFFECT_DAMAGE_CRITICAL],v3Pos,v3Rot);
//return; 숫자도 표시.
}
@@ -151,6 +140,7 @@ void CInstanceBase::ProcessDamage()
{
if (bSelf)
{
TraceError("ProcessDamage: bSelf path - damage_");
strDamageType = "damage_";
if (m_bDamageEffectType == 0)
@@ -162,6 +152,8 @@ void CInstanceBase::ProcessDamage()
}
else if (!bTarget || ((IsAffect(AFFECT_INVISIBILITY) || IsAffect(AFFECT_EUNHYEONG)) && bTarget))
{
TraceError("ProcessDamage: non-target path (early return) bTarget=%d INVIS=%d EUNHYEONG=%d",
bTarget, IsAffect(AFFECT_INVISIBILITY), IsAffect(AFFECT_EUNHYEONG));
strDamageType = "nontarget_";
rdwCRCEft = EFFECT_DAMAGE_NOT_TARGET;
@@ -169,11 +161,15 @@ void CInstanceBase::ProcessDamage()
}
else
{
TraceError("ProcessDamage: target path - target_");
strDamageType = "target_";
rdwCRCEft = EFFECT_DAMAGE_TARGET;
}
}
TraceError("ProcessDamage: Creating effect strDamageType=%s rdwCRCEft=%u effectCRC=%u",
strDamageType.c_str(), rdwCRCEft, ms_adwCRCAffectEffect[rdwCRCEft]);
DWORD index = 0;
DWORD num = 0;
std::vector<std::string> textures;
@@ -192,9 +188,11 @@ void CInstanceBase::ProcessDamage()
char numBuf[MAX_PATH];
sprintf(numBuf, "%d.dds", num);
textures.push_back("d:/ymir work/effect/affect/damagevalue/" +strDamageType + numBuf);
TraceError("ProcessDamage: texture path=%s", textures.back().c_str());
rkEftMgr.SetEffectTextures(ms_adwCRCAffectEffect[rdwCRCEft],textures);
D3DXMATRIX matrix, matTrans;
D3DXMatrixIdentity(&matrix);
@@ -210,9 +208,10 @@ void CInstanceBase::ProcessDamage()
matrix = matTrans*matrix;
D3DXMatrixMultiply(&matrix, &pCamera->GetViewMatrix(), &matrix);
rkEftMgr.CreateEffect(ms_adwCRCAffectEffect[rdwCRCEft], D3DXVECTOR3(matrix._41, matrix._42, matrix._43)
,v3Rot);
DWORD effectResult = rkEftMgr.CreateEffect(ms_adwCRCAffectEffect[rdwCRCEft], D3DXVECTOR3(matrix._41, matrix._42, matrix._43)
,v3Rot);
TraceError("ProcessDamage: CreateEffect returned %u", effectResult);
textures.clear();
@@ -887,35 +886,6 @@ void CInstanceBase::__SetAffect(UINT eAffect, bool isVisible)
if (IsAffect(AFFECT_INVISIBILITY))
return;
break;
/*
case AFFECT_GWIGEOM: // 전기 속성 공격으로 바뀔 예정
if (isVisible)
{
m_GraphicThingInstance.SetBattleHitEffect(ms_adwCRCAffectEffect[EFFECT_ELECTRIC_HIT]);
m_GraphicThingInstance.SetBattleAttachEffect(ms_adwCRCAffectEffect[EFFECT_ELECTRIC_ATTACH]);
}
else
{
m_GraphicThingInstance.SetBattleHitEffect(ms_adwCRCAffectEffect[EFFECT_HIT]);
m_GraphicThingInstance.SetBattleAttachEffect(0);
}
return;
break;
case AFFECT_HWAYEOM: // 화염 속성 공격으로 바뀔 예정
if (isVisible)
{
m_GraphicThingInstance.SetBattleHitEffect(ms_adwCRCAffectEffect[EFFECT_FLAME_HIT]);
m_GraphicThingInstance.SetBattleAttachEffect(ms_adwCRCAffectEffect[EFFECT_FLAME_ATTACH]);
}
else
{
m_GraphicThingInstance.SetBattleHitEffect(ms_adwCRCAffectEffect[EFFECT_HIT]);
m_GraphicThingInstance.SetBattleAttachEffect(0);
}
// 화염참은 공격할 때만 일시적으로 Visible 합니다.
return;
break;
*/
case AFFECT_CHEONGEUN:
m_GraphicThingInstance.SetResistFallen(isVisible);
break;

File diff suppressed because it is too large Load Diff

View File

@@ -424,94 +424,6 @@ bool CPythonApplication::Process()
#ifdef __VTUNE__
s_bFrameSkip = false;
#endif
/*
static bool s_isPrevFrameSkip=false;
static DWORD s_dwFrameSkipCount=0;
static DWORD s_dwFrameSkipEndTime=0;
static DWORD ERROR_FRAME_SKIP_COUNT = 60*5;
static DWORD ERROR_FRAME_SKIP_TIME = ERROR_FRAME_SKIP_COUNT*18;
//static DWORD MAX_FRAME_SKIP=0;
if (IsActive())
{
DWORD dwFrameSkipCurTime=ELTimer_GetMSec();
if (s_bFrameSkip)
{
// ÀÌÀü ÇÁ·¹ÀÓµµ ½ºÅµÀ̶ó¸é..
if (s_isPrevFrameSkip)
{
if (s_dwFrameSkipEndTime==0)
{
s_dwFrameSkipCount=0; // ÇÁ·¹ÀÓ Ã¼Å©´Â ·Îµù ´ëºñ
s_dwFrameSkipEndTime=dwFrameSkipCurTime+ERROR_FRAME_SKIP_TIME; // ½Ã°£ üũ´Â ·ÎµùÈÄ ÇÁ·¹ÀÓ ½ºÅµ üũ
//printf("FrameSkipCheck Start\n");
}
++s_dwFrameSkipCount;
//if (MAX_FRAME_SKIP<s_dwFrameSkipCount)
// MAX_FRAME_SKIP=s_dwFrameSkipCount;
//printf("u %d c %d/%d t %d\n",
// dwUpdateTime9-dwUpdateTime1,
// s_dwFrameSkipCount,
// MAX_FRAME_SKIP,
// s_dwFrameSkipEndTime);
//#ifndef _DEBUG
// ÀÏÁ¤ ½Ã°£µ¿¾È °è¼Ó ÇÁ·¹ÀÓ ½ºÅµ¸¸ ÇÑ´Ù¸é...
if (s_dwFrameSkipCount>ERROR_FRAME_SKIP_COUNT && s_dwFrameSkipEndTime<dwFrameSkipCurTime)
{
s_isPrevFrameSkip=false;
s_dwFrameSkipEndTime=0;
s_dwFrameSkipCount=0;
//m_pyNetworkStream.AbsoluteExitGame();
/*
TraceError("¹«ÇÑ ÇÁ·¹ÀÓ ½ºÅµÀ¸·Î Á¢¼ÓÀ» Á¾·áÇÕ´Ï´Ù");
{
FILE* fp=fopen("errorlog.txt", "w");
if (fp)
{
fprintf(fp, "FRAMESKIP\n");
fprintf(fp, "Total %d\n", dwUpdateTime9-dwUpdateTime1);
fprintf(fp, "Timer %d\n", dwUpdateTime2-dwUpdateTime1);
fprintf(fp, "Network %d\n", dwUpdateTime3-dwUpdateTime2);
fprintf(fp, "Keyboard %d\n", dwUpdateTime4-dwUpdateTime3);
fprintf(fp, "Controll %d\n", dwUpdateTime5-dwUpdateTime4);
fprintf(fp, "Resource %d\n", dwUpdateTime6-dwUpdateTime5);
fprintf(fp, "Camera %d\n", dwUpdateTime7-dwUpdateTime6);
fprintf(fp, "Mouse %d\n", dwUpdateTime8-dwUpdateTime7);
fprintf(fp, "UI %d\n", dwUpdateTime9-dwUpdateTime8);
fclose(fp);
WinExec("errorlog.exe", SW_SHOW);
}
}
}
}
s_isPrevFrameSkip=true;
}
else
{
s_isPrevFrameSkip=false;
s_dwFrameSkipCount=0;
s_dwFrameSkipEndTime=0;
}
}
else
{
s_isPrevFrameSkip=false;
s_dwFrameSkipCount=0;
s_dwFrameSkipEndTime=0;
}
*/
if (!s_bFrameSkip)
{
// static double pos=0.0f;

View File

@@ -26,7 +26,6 @@
#include "PythonTextTail.h"
#include "PythonSkill.h"
#include "PythonSystem.h"
//#include "PythonNetworkDatagram.h"
#include "PythonNetworkStream.h"
#include "PythonCharacterManager.h"
#include "PythonQuest.h"
@@ -327,7 +326,6 @@ class CPythonApplication : public CMSApplication, public CInputKeyboard, public
CServerStateChecker m_kServerStateChecker;
CPythonGraphic m_pyGraphic;
CPythonNetworkStream m_pyNetworkStream;
//CPythonNetworkDatagram m_pyNetworkDatagram;
CPythonPlayer m_pyPlayer;
CPythonIME m_pyIme;
CPythonItem m_pyItem;

View File

@@ -25,14 +25,6 @@ void CPythonMessenger::OnFriendLogout(const char * c_szKey)
PyCallClassMemberFunc(m_poMessengerHandler, "OnLogout", Py_BuildValue("(is)", MESSENGER_GRUOP_INDEX_FRIEND, c_szKey));
}
void CPythonMessenger::SetMobile(const char * c_szKey, BYTE byState)
{
m_FriendNameMap.insert(c_szKey);
if (m_poMessengerHandler)
PyCallClassMemberFunc(m_poMessengerHandler, "OnMobile", Py_BuildValue("(isi)", MESSENGER_GRUOP_INDEX_FRIEND, c_szKey, byState));
}
BOOL CPythonMessenger::IsFriendByKey(const char * c_szKey)
{
return m_FriendNameMap.end() != m_FriendNameMap.find(c_szKey);

View File

@@ -24,7 +24,6 @@ class CPythonMessenger : public CSingleton<CPythonMessenger>
void RemoveFriend(const char * c_szKey);
void OnFriendLogin(const char * c_szKey);
void OnFriendLogout(const char * c_szKey);
void SetMobile(const char * c_szKey, BYTE byState);
BOOL IsFriendByKey(const char * c_szKey);
BOOL IsFriendByName(const char * c_szName);

View File

@@ -1,213 +0,0 @@
#include "StdAfx.h"
/*
#include "PythonNetworkDatagram.h"
#include "PythonNetworkStream.h"
class CDatagramPacketHeaderMap : public CNetworkPacketHeaderMap
{
public:
CDatagramPacketHeaderMap()
{
Set(HEADER_CC_STATE_WALKING, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketCCState), false));
}
};
void CPythonNetworkDatagram::Destroy()
{
m_NetSenderPool.Clear();
}
BOOL CPythonNetworkDatagram::CheckPacket(TPacketHeader * piRetHeader)
{
static CDatagramPacketHeaderMap s_packetHeaderMap;
if (!m_NetReceiver.isBind())
return FALSE;
*piRetHeader = 0;
TPacketHeader header;
if (!m_NetReceiver.Peek(&header, sizeof(TPacketHeader)))
return false;
CNetworkPacketHeaderMap::TPacketType PacketType;
if (!s_packetHeaderMap.Get(header, &PacketType))
{
Tracef("Unknown UDP packet header");
assert(!"Unknown UDP packet header");
return FALSE;
}
if (!header)
return FALSE;
*piRetHeader = header;
return TRUE;
}
void CPythonNetworkDatagram::Process()
{
while (m_NetReceiver.Process())
{
TPacketHeader iHeader;
if (!CheckPacket(&iHeader))
continue;
switch(iHeader)
{
case HEADER_CC_STATE_WALKING:
RecvStateWalkingPacket();
break;
case HEADER_CC_STATE_WAITING:
case HEADER_CC_STATE_GOING:
case HEADER_CC_EVENT_NORMAL_ATTACKING:
case HEADER_CC_EVENT_COMBO_ATTACKING:
case HEADER_CC_EVENT_HIT:
break;
}
}
}
void CPythonNetworkDatagram::SetConnection(const char * c_szIP, WORD wPortIndex)
{
m_NetSender.SetSocket(c_szIP, wPortIndex);
}
void CPythonNetworkDatagram::SetRecvBufferSize(DWORD dwSize)
{
m_NetReceiver.SetRecvBufferSize(dwSize);
}
void CPythonNetworkDatagram::SendToServer(const void * c_pBuffer, DWORD dwSize)
{
if (!m_NetSender.isSocket())
{
assert(!"UDP Socket has not set!");
return;
}
m_NetSender.Send(c_pBuffer, dwSize);
}
void CPythonNetworkDatagram::Bind(DWORD dwAddress, WORD wPortIndex)
{
m_NetReceiver.Bind(dwAddress, wPortIndex);
}
void CPythonNetworkDatagram::RegisterSender(DWORD dwID, DWORD dwAddress, WORD wPortIndex)
{
CNetDatagramSender * pSender = m_NetSenderPool.Alloc();
pSender->SetSocket(dwAddress, wPortIndex);
m_NetSenderMap.insert(TNetSenderMap::value_type(dwID, pSender));
}
void CPythonNetworkDatagram::DeleteSender(DWORD dwID)
{
CNetDatagramSender * pSender;
if (!GetSenderPointer(dwID, &pSender))
return;
m_NetSenderPool.Free(pSender);
m_NetSenderMap.erase(dwID);
}
void CPythonNetworkDatagram::Select(DWORD dwID)
{
CNetDatagramSender * pSender;
if (!GetSenderPointer(dwID, &pSender))
return;
m_NetSenderList.push_back(pSender);
}
void CPythonNetworkDatagram::SendToSenders(const void * c_pBuffer, DWORD dwSize)
{
// NOTE : Temporary Code
// Now, Send to every around client.
for (TNetSenderMapIterator itorMap = m_NetSenderMap.begin(); itorMap != m_NetSenderMap.end(); ++itorMap)
{
CNetDatagramSender * pSender = itorMap->second;
m_NetSenderList.push_back(pSender);
}
// NOTE : Temporary Code
for (TNetSenderListIterator itor = m_NetSenderList.begin(); itor != m_NetSenderList.end(); ++itor)
{
CNetDatagramSender * pSender = *itor;
pSender->Send(c_pBuffer, dwSize);
}
m_NetSenderList.clear();
}
BOOL CPythonNetworkDatagram::GetSenderPointer(DWORD dwID, CNetDatagramSender ** ppSender)
{
TNetSenderMapIterator itor = m_NetSenderMap.find(dwID);
if (m_NetSenderMap.end() == itor)
return FALSE;
*ppSender = itor->second;
return TRUE;
}
//////////////////////////////////
// Walking
void CPythonNetworkDatagram::SendCharacterStatePacket(DWORD dwVID, DWORD dwCmdTime, const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg)
{
fDstRot=fmod(fDstRot, 360.0f);
if (fDstRot<0)
fDstRot=360.0f-fDstRot;
TPacketCCState kStatePacket;
kStatePacket.bHeader=HEADER_CC_STATE_WALKING;
kStatePacket.dwVID=dwVID;
kStatePacket.bFunc=eFunc;
kStatePacket.bArg=uArg;
kStatePacket.bRot=fDstRot/5.0f;
kStatePacket.dwTime=dwCmdTime;
kStatePacket.kPPos=c_rkPPosDst;
//SendToSenders(&kStatePacket, sizeof(kStatePacket));
}
BOOL CPythonNetworkDatagram::RecvStateWalkingPacket()
{
TPacketCCState kStatePacket;
if (!m_NetReceiver.Recv(&kStatePacket, sizeof(kStatePacket)))
{
assert(!"CPythonNetworkDatagram::RecvStatePacket - PAKCET READ ERROR");
Tracenf("CPythonNetworkDatagram::RecvStatePacket - PAKCET READ ERROR");
return FALSE;
}
CInstanceBase * pkChrInst = CPythonCharacterManager::Instance().GetInstancePtr(kStatePacket.dwVID);
if (!pkChrInst)
{
//Tracenf("CPythonNetworkDatagram::RecvStatePacket - NOT EXIST VID(kStateWaitingPacket.vid = %d)", kStatePacket.m_dwVID);
return TRUE;
}
pkChrInst->PushUDPState(kStatePacket.dwTime, kStatePacket.kPPos, kStatePacket.bRot*5.0f, kStatePacket.bFunc, kStatePacket.bArg);
return TRUE;
}
CPythonNetworkDatagram::CPythonNetworkDatagram()
{
}
CPythonNetworkDatagram::~CPythonNetworkDatagram()
{
}
*/

View File

@@ -1,58 +0,0 @@
#pragma once
/*
#include "EterLib/NetDatagramReceiver.h"
#include "EterLib/NetDatagramSender.h"
#include "Packet.h"
class CPythonNetworkDatagram : public CSingleton<CPythonNetworkDatagram>
{
public:
CPythonNetworkDatagram();
virtual ~CPythonNetworkDatagram();
void Destroy();
// With Server
void SetRecvBufferSize(DWORD dwSize);
void SetConnection(const char * c_szIP, WORD wPortIndex);
void SendToServer(const void * c_pBuffer, DWORD dwSize);
void Bind(DWORD dwAddress, WORD wPortIndex);
// With UDP Senders
void RegisterSender(DWORD dwID, DWORD dwAddress, WORD wPortIndex);
void DeleteSender(DWORD dwID);
void Select(DWORD dwID);
void SendToSenders(const void * c_pBuffer, DWORD dwSize);
// Regulary update function
void Process();
void SendCharacterStatePacket(DWORD dwVID, DWORD dwCmdTime, const TPixelPosition& c_rkPPosDst, float fDstRot, UINT eFunc, UINT uArg);
protected:
BOOL CheckPacket(TPacketHeader * piRetHeader);
BOOL GetSenderPointer(DWORD dwID, CNetDatagramSender ** ppSender);
BOOL RecvStateWalkingPacket();
protected:
// Sender Map
typedef std::map<DWORD, CNetDatagramSender*> TNetSenderMap;
typedef TNetSenderMap::iterator TNetSenderMapIterator;
// Sender List
typedef std::list<CNetDatagramSender*> TNetSenderList;
typedef TNetSenderList::iterator TNetSenderListIterator;
protected:
// Sender
TNetSenderMap m_NetSenderMap;
TNetSenderList m_NetSenderList;
// Connection with server
CNetDatagramSender m_NetSender;
CNetDatagramReceiver m_NetReceiver;
private:
CDynamicPool<CNetDatagramSender> m_NetSenderPool;
};
*/

View File

@@ -1,29 +0,0 @@
#include "StdAfx.h"
#include "PythonNetworkDatagram.h"
/*
PyObject * udpEnable(PyObject* poSelf, PyObject* poArgs)
{
CPythonNetworkDatagram::Instance().Enable();
return Py_BuildNone();
}
PyObject * udpDisable(PyObject* poSelf, PyObject* poArgs)
{
CPythonNetworkDatagram::Instance().Disable();
return Py_BuildNone();
}
*/
void initudp()
{
/*
static PyMethodDef s_methods[] =
{
{ "Enable", udpEnable, METH_VARARGS },
{ "Disable", udpDisable, METH_VARARGS },
{ NULL, NULL, NULL }
};
PyObject * poModule = Py_InitModule("udp", s_methods);
*/
}

View File

@@ -1,5 +1,4 @@
#include "StdAfx.h"
#include "EterLib/NetPacketHeaderMap.h"
#include "PythonNetworkStream.h"
#include "Packet.h"
@@ -15,172 +14,6 @@
static DWORD gs_nextDownloadMarkTime = 0;
// END_OF_MARK_BUG_FIX
// Packet ---------------------------------------------------------------------------
class CMainPacketHeaderMap : public CNetworkPacketHeaderMap
{
public:
enum
{
STATIC_SIZE_PACKET = false,
DYNAMIC_SIZE_PACKET = true,
};
public:
CMainPacketHeaderMap()
{
Set(HEADER_GC_EMPIRE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCEmpire), STATIC_SIZE_PACKET));
Set(HEADER_GC_WARP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCWarp), STATIC_SIZE_PACKET));
Set(HEADER_GC_SKILL_COOLTIME_END, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSkillCoolTimeEnd), STATIC_SIZE_PACKET));
Set(HEADER_GC_QUEST_INFO, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCQuestInfo), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_REQUEST_MAKE_GUILD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCBlank), STATIC_SIZE_PACKET));
Set(HEADER_GC_PVP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPVP), STATIC_SIZE_PACKET));
Set(HEADER_GC_DUEL_START, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCDuelStart), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_CHARACTER_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCharacterAdd), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHAR_ADDITIONAL_INFO, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCharacterAdditionalInfo), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHARACTER_ADD2, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCharacterAdd2), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHARACTER_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCharacterUpdate), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHARACTER_UPDATE2, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCharacterUpdate2), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHARACTER_DEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCharacterDelete), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHARACTER_MOVE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMove), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHAT, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCChat), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_SYNC_POSITION, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCC2C), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_LOGIN_SUCCESS3, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCLoginSuccess3), STATIC_SIZE_PACKET));
Set(HEADER_GC_LOGIN_SUCCESS4, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCLoginSuccess4), STATIC_SIZE_PACKET));
Set(HEADER_GC_LOGIN_FAILURE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCLoginFailure), STATIC_SIZE_PACKET));
Set(HEADER_GC_PLAYER_CREATE_SUCCESS, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPlayerCreateSuccess), STATIC_SIZE_PACKET));
Set(HEADER_GC_PLAYER_CREATE_FAILURE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCreateFailure), STATIC_SIZE_PACKET));
Set(HEADER_GC_PLAYER_DELETE_SUCCESS, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCBlank), STATIC_SIZE_PACKET));
Set(HEADER_GC_PLAYER_DELETE_WRONG_SOCIAL_ID, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCBlank), STATIC_SIZE_PACKET));
Set(HEADER_GC_STUN, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCStun), STATIC_SIZE_PACKET));
Set(HEADER_GC_DEAD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCDead), STATIC_SIZE_PACKET));
Set(HEADER_GC_MAIN_CHARACTER, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMainCharacter), STATIC_SIZE_PACKET));
// SUPPORT_BGM
Set(HEADER_GC_MAIN_CHARACTER2_EMPIRE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMainCharacter2_EMPIRE), STATIC_SIZE_PACKET));
Set(HEADER_GC_MAIN_CHARACTER3_BGM, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMainCharacter3_BGM), STATIC_SIZE_PACKET));
Set(HEADER_GC_MAIN_CHARACTER4_BGM_VOL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMainCharacter4_BGM_VOL), STATIC_SIZE_PACKET));
// END_OFSUPPORT_BGM
Set(HEADER_GC_PLAYER_POINTS, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPoints), STATIC_SIZE_PACKET));
Set(HEADER_GC_PLAYER_POINT_CHANGE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPointChange), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_DEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemDel), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_SET, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemSet), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_GET, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemGet), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_USE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemUse), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemUpdate), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_GROUND_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemGroundAdd), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_GROUND_DEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemGroundDel), STATIC_SIZE_PACKET));
Set(HEADER_GC_ITEM_OWNERSHIP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemOwnership), STATIC_SIZE_PACKET));
Set(HEADER_GC_QUICKSLOT_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCQuickSlotAdd), STATIC_SIZE_PACKET));
Set(HEADER_GC_QUICKSLOT_DEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCQuickSlotDel), STATIC_SIZE_PACKET));
Set(HEADER_GC_QUICKSLOT_SWAP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCQuickSlotSwap), STATIC_SIZE_PACKET));
Set(HEADER_GC_WHISPER, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCWhisper), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHARACTER_POSITION, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPosition), STATIC_SIZE_PACKET));
Set(HEADER_GC_MOTION, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMotion), STATIC_SIZE_PACKET));
Set(HEADER_GC_SHOP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCShop), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_SHOP_SIGN, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCShopSign), STATIC_SIZE_PACKET));
Set(HEADER_GC_EXCHANGE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCExchange), STATIC_SIZE_PACKET));
Set(HEADER_GC_PING, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPing), STATIC_SIZE_PACKET));
Set(HEADER_GC_SCRIPT, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCScript), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_QUEST_CONFIRM, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCQuestConfirm), STATIC_SIZE_PACKET));
Set(HEADER_GC_TARGET, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCTarget), STATIC_SIZE_PACKET));
Set(HEADER_GC_MOUNT, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMount), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHANGE_SPEED, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCChangeSpeed), STATIC_SIZE_PACKET));
Set(HEADER_GC_HANDSHAKE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCHandshake), STATIC_SIZE_PACKET));
Set(HEADER_GC_HANDSHAKE_OK, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCBlank), STATIC_SIZE_PACKET));
Set(HEADER_GC_BINDUDP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCBindUDP), STATIC_SIZE_PACKET));
Set(HEADER_GC_OWNERSHIP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCOwnership), STATIC_SIZE_PACKET));
Set(HEADER_GC_CREATE_FLY, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCCreateFly), STATIC_SIZE_PACKET));
// Secure key exchange (libsodium)
Set(HEADER_GC_KEY_CHALLENGE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCKeyChallenge), STATIC_SIZE_PACKET));
Set(HEADER_GC_KEY_COMPLETE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCKeyComplete), STATIC_SIZE_PACKET));
Set(HEADER_GC_ADD_FLY_TARGETING, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCFlyTargeting), STATIC_SIZE_PACKET));
Set(HEADER_GC_FLY_TARGETING, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCFlyTargeting), STATIC_SIZE_PACKET));
Set(HEADER_GC_PHASE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPhase), STATIC_SIZE_PACKET));
Set(HEADER_GC_SKILL_LEVEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSkillLevel), STATIC_SIZE_PACKET));
Set(HEADER_GC_SKILL_LEVEL_NEW, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSkillLevelNew), STATIC_SIZE_PACKET));
Set(HEADER_GC_MESSENGER, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMessenger), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_GUILD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCGuild), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_MARK_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMarkUpdate), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_INVITE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyInvite), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyAdd), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyUpdate), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_REMOVE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyRemove), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_LINK, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyLink), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_UNLINK, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyUnlink), STATIC_SIZE_PACKET));
Set(HEADER_GC_PARTY_PARAMETER, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCPartyParameter), STATIC_SIZE_PACKET));
Set(HEADER_GC_SAFEBOX_SET, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemSet), STATIC_SIZE_PACKET));
Set(HEADER_GC_SAFEBOX_DEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemDel), STATIC_SIZE_PACKET));
Set(HEADER_GC_SAFEBOX_WRONG_PASSWORD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSafeboxWrongPassword), STATIC_SIZE_PACKET));
Set(HEADER_GC_SAFEBOX_SIZE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSafeboxSize), STATIC_SIZE_PACKET));
Set(HEADER_GC_SAFEBOX_MONEY_CHANGE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSafeboxMoneyChange), STATIC_SIZE_PACKET));
Set(HEADER_GC_FISHING, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCFishing), STATIC_SIZE_PACKET));
Set(HEADER_GC_DUNGEON, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCDungeon), DYNAMIC_SIZE_PACKET));
//Set(HEADER_GC_SLOW_TIMER, CNetworkPacketHeaderMap::TPacketType(sizeof(BYTE), STATIC_SIZE_PACKET));
Set(HEADER_GC_TIME, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCTime), STATIC_SIZE_PACKET));
Set(HEADER_GC_WALK_MODE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCWalkMode), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHANGE_SKILL_GROUP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCChangeSkillGroup), STATIC_SIZE_PACKET));
Set(HEADER_GC_REFINE_INFORMATION, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCRefineInformation), STATIC_SIZE_PACKET));
Set(HEADER_GC_REFINE_INFORMATION_NEW, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCRefineInformationNew), STATIC_SIZE_PACKET));
Set(HEADER_GC_SEPCIAL_EFFECT, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSpecialEffect), STATIC_SIZE_PACKET));
Set(HEADER_GC_NPC_POSITION, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCNPCPosition), DYNAMIC_SIZE_PACKET));
Set(HEADER_GC_CHANGE_NAME, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCChangeName), STATIC_SIZE_PACKET));
Set(HEADER_GC_LOGIN_KEY, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCLoginKey), STATIC_SIZE_PACKET));
Set(HEADER_GC_AUTH_SUCCESS, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCAuthSuccess), STATIC_SIZE_PACKET));
Set(HEADER_GC_CHANNEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCChannel), STATIC_SIZE_PACKET));
Set(HEADER_GC_VIEW_EQUIP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCViewEquip), STATIC_SIZE_PACKET));
Set(HEADER_GC_LAND_LIST, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCLandList), DYNAMIC_SIZE_PACKET));
//Set(HEADER_GC_TARGET_CREATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCTargetCreate), STATIC_SIZE_PACKET));
Set(HEADER_GC_TARGET_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCTargetUpdate), STATIC_SIZE_PACKET));
Set(HEADER_GC_TARGET_DELETE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCTargetDelete), STATIC_SIZE_PACKET));
Set(HEADER_GC_TARGET_CREATE_NEW, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCTargetCreateNew), STATIC_SIZE_PACKET));
Set(HEADER_GC_AFFECT_ADD, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCAffectAdd), STATIC_SIZE_PACKET));
Set(HEADER_GC_AFFECT_REMOVE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCAffectRemove), STATIC_SIZE_PACKET));
Set(HEADER_GC_MALL_OPEN, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCMallOpen), STATIC_SIZE_PACKET));
Set(HEADER_GC_MALL_SET, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemSet), STATIC_SIZE_PACKET));
Set(HEADER_GC_MALL_DEL, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemDel), STATIC_SIZE_PACKET));
Set(HEADER_GC_LOVER_INFO, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCLoverInfo), STATIC_SIZE_PACKET));
Set(HEADER_GC_LOVE_POINT_UPDATE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCLovePointUpdate), STATIC_SIZE_PACKET));
Set(HEADER_GC_DIG_MOTION, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCDigMotion), STATIC_SIZE_PACKET));
Set(HEADER_GC_DAMAGE_INFO, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCDamageInfo), STATIC_SIZE_PACKET));
Set(HEADER_GC_SPECIFIC_EFFECT, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCSpecificEffect), STATIC_SIZE_PACKET));
Set(HEADER_GC_DRAGON_SOUL_REFINE, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCDragonSoulRefine), STATIC_SIZE_PACKET));
}
};
static std::vector <uint8_t> gs_vecLastHeaders;
void CPythonNetworkStream::ExitApplication()
{
if (__IsNotPing())
@@ -486,107 +319,70 @@ void CPythonNetworkStream::SetLoginKey(DWORD dwLoginKey)
m_dwLoginKey = dwLoginKey;
}
bool CPythonNetworkStream::CheckPacket(TPacketHeader * pRetHeader)
// Table-driven packet dispatch — replaces CheckPacket() + per-phase switch statements.
// Returns true if a packet was processed and more may follow.
// Returns false to exit the phase loop (no data, error, or exitPhase handler).
bool CPythonNetworkStream::DispatchPacket(const PacketHandlerMap& handlers)
{
*pRetHeader = 0;
static CMainPacketHeaderMap s_packetHeaderMap;
TPacketHeader header;
if (!Peek(sizeof(TPacketHeader), &header))
return false;
if (0 == header)
// Skip zero-padding (can occur from encryption alignment)
while (0 == header)
{
if (!Recv(sizeof(TPacketHeader), &header))
return false;
while (Peek(sizeof(TPacketHeader), &header))
{
if (0 == header)
{
if (!Recv(sizeof(TPacketHeader), &header))
return false;
}
else
{
break;
}
}
if (0 == header)
if (!Peek(sizeof(TPacketHeader), &header))
return false;
}
CNetworkPacketHeaderMap::TPacketType PacketType;
if (!s_packetHeaderMap.Get(header, &PacketType))
// Look up handler in this phase's table
auto it = handlers.find(header);
if (it == handlers.end())
{
TraceError("Unknown packet header: %u(0x%X), Phase: %s, Last packets:", header, header, m_strPhase.c_str());
for (const auto& it : gs_vecLastHeaders)
TraceError("%u(0x%X)", it, it);
TraceError("Unknown packet header: 0x%04X (recv_seq #%u), Phase: %s", header, m_dwRecvPacketSeq, m_strPhase.c_str());
DumpRecentPackets();
ClearRecvBuffer();
return false;
}
// All packets use uniform framing: [header:2][length:2][payload...]
TDynamicSizePacketHeader packetFrame;
if (!Peek(sizeof(TDynamicSizePacketHeader), &packetFrame))
return false;
constexpr uint16_t MAX_PACKET_LENGTH = 65000;
if (packetFrame.length < PACKET_HEADER_SIZE || packetFrame.length > MAX_PACKET_LENGTH)
{
TraceError("DispatchPacket: Invalid packet length: header 0x%04X length: %u (min %u, max %u), recv_seq #%u",
header, packetFrame.length, PACKET_HEADER_SIZE, MAX_PACKET_LENGTH, m_dwRecvPacketSeq);
DumpRecentPackets();
ClearRecvBuffer();
PostQuitMessage(0);
return false;
}
// Code for dynamic size packet
if (PacketType.isDynamicSizePacket)
{
TDynamicSizePacketHeader DynamicSizePacketHeader;
if (!Peek(sizeof(TDynamicSizePacketHeader), &DynamicSizePacketHeader))
return false;
if (!Peek(DynamicSizePacketHeader.size))
{
TraceError("CPythonNetworkStream::CheckPacket - Not enough dynamic packet size: header %d packet size: %d",
DynamicSizePacketHeader.header,
DynamicSizePacketHeader.size);
return false;
}
}
else
{
if (!Peek(PacketType.iPacketSize))
{
TraceError("Not enough packet size: header %d packet size: %d, recv buffer size: %d last packets:",
header,
PacketType.iPacketSize,
GetRecvBufferSize()
);
for (const auto& it : gs_vecLastHeaders)
TraceError("%u(0x%X)", it, it);
return false;
}
}
if (!header)
// Wait for full packet to be received
if (!Peek(packetFrame.length))
return false;
*pRetHeader = header;
// Log this packet
LogRecvPacket(header, packetFrame.length);
// Add to last headers, if last header is contain more than 10 headers, remove first header
if (gs_vecLastHeaders.size() > 10)
gs_vecLastHeaders.erase(gs_vecLastHeaders.begin());
// Call handler
bool ret = (this->*(it->second.handler))();
gs_vecLastHeaders.push_back(header);
if (!ret || it->second.exitPhase)
return false;
//Tracenf("header %d size %d", header, PacketType.iPacketSize);
//Tracenf("header %d size %d outputpos[%d] security %u", header, PacketType.iPacketSize, m_recvBufOutputPos, IsSecurityMode());
return true;
}
bool CPythonNetworkStream::RecvErrorPacket(int header)
{
TraceError("Phase %s does not handle this header (header: %u(0x%X)) Last packets: ", m_strPhase.c_str(), header, header);
for (const auto& it : gs_vecLastHeaders)
TraceError("%u(0x%X)", it, it);
TraceError("Phase %s does not handle header 0x%04X (recv_seq #%u)", m_strPhase.c_str(), header, m_dwRecvPacketSeq - 1);
DumpRecentPackets();
ClearRecvBuffer();
return true;
@@ -601,43 +397,41 @@ bool CPythonNetworkStream::RecvPhasePacket()
switch (packet_phase.phase)
{
case PHASE_CLOSE: // 끊기는 상태 (또는 끊기 전 상태)
case PHASE_CLOSE:
ClosePhase();
break;
case PHASE_HANDSHAKE: // 악수..;;
case PHASE_HANDSHAKE:
SetHandShakePhase();
break;
case PHASE_LOGIN: // 로그인 중
case PHASE_LOGIN:
SetLoginPhase();
break;
case PHASE_SELECT: // 캐릭터 선택 화면
case PHASE_SELECT:
SetSelectPhase();
#if defined(ENABLE_DISCORD_RPC)
Discord_Update(false);
#endif
BuildProcessCRC();
// MARK_BUG_FIX
__DownloadMark();
// END_OF_MARK_BUG_FIX
break;
case PHASE_LOADING: // 선택 후 로딩 화면
case PHASE_LOADING:
SetLoadingPhase();
break;
case PHASE_GAME: // 게임 화면
case PHASE_GAME:
SetGamePhase();
#if defined(ENABLE_DISCORD_RPC)
Discord_Update(true);
#endif
break;
case PHASE_DEAD: // 죽었을 때.. (게임 안에 있는 것일 수도..)
case PHASE_DEAD:
break;
}
@@ -646,8 +440,6 @@ bool CPythonNetworkStream::RecvPhasePacket()
bool CPythonNetworkStream::RecvPingPacket()
{
Tracef("recv ping packet. (securitymode %u)\n", IsSecurityMode());
TPacketGCPing kPacketPing;
if (!Recv(sizeof(TPacketGCPing), &kPacketPing))
@@ -655,9 +447,12 @@ bool CPythonNetworkStream::RecvPingPacket()
m_dwLastGamePingTime = ELTimer_GetMSec();
// Sync server time from ping
ELTimer_SetServerMSec(kPacketPing.server_time);
TPacketCGPong kPacketPong;
kPacketPong.bHeader = HEADER_CG_PONG;
kPacketPong.bSequence = GetNextSequence();
kPacketPong.header = CG::PONG;
kPacketPong.length = sizeof(kPacketPong);
if (!Send(sizeof(TPacketCGPong), &kPacketPong))
return false;
@@ -665,36 +460,20 @@ bool CPythonNetworkStream::RecvPingPacket()
return true;
}
bool CPythonNetworkStream::RecvDefaultPacket(int header)
{
if (!header)
return true;
TraceError("처리되지 않은 패킷 헤더 %d, state %s\n", header, m_strPhase.c_str());
ClearRecvBuffer();
return true;
}
bool CPythonNetworkStream::OnProcess()
{
if (m_isStartGame)
{
m_isStartGame = FALSE;
PyCallClassMemberFunc(m_poHandler, "SetGamePhase", Py_BuildValue("()"));
// PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "StartGame", Py_BuildValue("()"));
}
m_rokNetActorMgr->Update();
if (m_phaseProcessFunc.IsEmpty())
return true;
//TPacketHeader header;
//while(CheckPacket(&header))
{
m_phaseProcessFunc.Run();
}
m_phaseProcessFunc.Run();
return true;
}
@@ -706,6 +485,7 @@ void CPythonNetworkStream::SetOffLinePhase()
if ("OffLine" != m_strPhase)
m_phaseLeaveFunc.Run();
Tracef("[PHASE] Entering phase: OffLine\n");
m_strPhase = "OffLine";
Tracen("");
@@ -908,6 +688,15 @@ CPythonNetworkStream::CPythonNetworkStream()
std::fill(m_apoPhaseWnd, m_apoPhaseWnd+PHASE_WINDOW_NUM, (PyObject*)NULL);
m_poSerCommandParserWnd = NULL;
// Register packet handlers for all phases
// Note: GameHandlers must be registered before LoadingHandlers (loading copies game handlers as fallback)
RegisterOfflineHandlers();
RegisterHandshakeHandlers();
RegisterLoginHandlers();
RegisterSelectHandlers();
RegisterGameHandlers();
RegisterLoadingHandlers();
SetOffLinePhase();
}
@@ -915,3 +704,256 @@ CPythonNetworkStream::~CPythonNetworkStream()
{
Tracen("PythonNetworkMainStream Clear");
}
// ---------------------------------------------------------------------------
// Phase 5: Packet handler registration tables
// Each phase registers {header → handler, minSize, exitPhase}
// ---------------------------------------------------------------------------
void CPythonNetworkStream::RegisterOfflineHandlers()
{
auto& h = m_offlineHandlers;
h[GC::PHASE] = { &CPythonNetworkStream::RecvPhasePacket, sizeof(TPacketGCPhase), true };
}
void CPythonNetworkStream::RegisterHandshakeHandlers()
{
auto& h = m_handshakeHandlers;
h[GC::PHASE] = { &CPythonNetworkStream::RecvPhasePacket, sizeof(TPacketGCPhase), true };
h[GC::PING] = { &CPythonNetworkStream::RecvPingPacket, sizeof(TPacketGCPing), true };
h[GC::KEY_CHALLENGE] = { &CPythonNetworkStream::RecvKeyChallenge, sizeof(TPacketGCKeyChallenge), true };
h[GC::KEY_COMPLETE] = { &CPythonNetworkStream::RecvKeyComplete, sizeof(TPacketGCKeyComplete), true };
}
void CPythonNetworkStream::RegisterLoginHandlers()
{
auto& h = m_loginHandlers;
h[GC::PHASE] = { &CPythonNetworkStream::RecvPhasePacket, sizeof(TPacketGCPhase), true };
h[GC::LOGIN_SUCCESS3] = { &CPythonNetworkStream::__RecvLoginSuccessPacket3, sizeof(TPacketGCLoginSuccess3), false };
h[GC::LOGIN_SUCCESS4] = { &CPythonNetworkStream::__RecvLoginSuccessPacket4, sizeof(TPacketGCLoginSuccess4), false };
h[GC::LOGIN_FAILURE] = { &CPythonNetworkStream::__RecvLoginFailurePacket, sizeof(TPacketGCLoginFailure), false };
h[GC::EMPIRE] = { &CPythonNetworkStream::__RecvEmpirePacket, sizeof(TPacketGCEmpire), false };
h[GC::LOGIN_KEY] = { &CPythonNetworkStream::__RecvLoginKeyPacket, sizeof(TPacketGCLoginKey), false };
h[GC::PING] = { &CPythonNetworkStream::RecvPingPacket, sizeof(TPacketGCPing), false };
h[GC::KEY_CHALLENGE] = { &CPythonNetworkStream::RecvKeyChallenge, sizeof(TPacketGCKeyChallenge), true };
h[GC::KEY_COMPLETE] = { &CPythonNetworkStream::RecvKeyComplete, sizeof(TPacketGCKeyComplete), true };
}
void CPythonNetworkStream::RegisterSelectHandlers()
{
auto& h = m_selectHandlers;
h[GC::PHASE] = { &CPythonNetworkStream::RecvPhasePacket, sizeof(TPacketGCPhase), true };
h[GC::EMPIRE] = { &CPythonNetworkStream::__RecvEmpirePacket, sizeof(TPacketGCEmpire), false };
h[GC::LOGIN_SUCCESS3] = { &CPythonNetworkStream::__RecvLoginSuccessPacket3, sizeof(TPacketGCLoginSuccess3), false };
h[GC::LOGIN_SUCCESS4] = { &CPythonNetworkStream::__RecvLoginSuccessPacket4, sizeof(TPacketGCLoginSuccess4), false };
h[GC::PLAYER_CREATE_SUCCESS] = { &CPythonNetworkStream::__RecvPlayerCreateSuccessPacket, sizeof(TPacketGCPlayerCreateSuccess), false };
h[GC::PLAYER_CREATE_FAILURE] = { &CPythonNetworkStream::__RecvPlayerCreateFailurePacket, sizeof(TPacketGCCreateFailure), false };
h[GC::PLAYER_DELETE_WRONG_SOCIAL_ID] = { &CPythonNetworkStream::__RecvPlayerDestroyFailurePacket, sizeof(TPacketGCBlank), false };
h[GC::PLAYER_DELETE_SUCCESS] = { &CPythonNetworkStream::__RecvPlayerDestroySuccessPacket, sizeof(TPacketGCDestroyCharacterSuccess), false };
h[GC::CHANGE_NAME] = { &CPythonNetworkStream::__RecvChangeName, sizeof(TPacketGCChangeName), false };
h[GC::PLAYER_POINT_CHANGE] = { &CPythonNetworkStream::RecvPointChange, sizeof(TPacketGCPointChange), false };
h[GC::PING] = { &CPythonNetworkStream::RecvPingPacket, sizeof(TPacketGCPing), false };
h[GC::KEY_CHALLENGE] = { &CPythonNetworkStream::RecvKeyChallenge, sizeof(TPacketGCKeyChallenge), true };
h[GC::KEY_COMPLETE] = { &CPythonNetworkStream::RecvKeyComplete, sizeof(TPacketGCKeyComplete), true };
}
void CPythonNetworkStream::RegisterGameHandlers()
{
auto& h = m_gameHandlers;
// Phase / control
h[GC::PHASE] = { &CPythonNetworkStream::RecvPhasePacket, sizeof(TPacketGCPhase), true };
h[GC::KEY_CHALLENGE] = { &CPythonNetworkStream::RecvKeyChallenge, sizeof(TPacketGCKeyChallenge), true };
h[GC::KEY_COMPLETE] = { &CPythonNetworkStream::RecvKeyComplete, sizeof(TPacketGCKeyComplete), true };
h[GC::PING] = { &CPythonNetworkStream::RecvPingPacket, sizeof(TPacketGCPing), false };
// Observer
h[GC::OBSERVER_ADD] = { &CPythonNetworkStream::RecvObserverAddPacket, sizeof(TPacketGCObserverAdd), false };
h[GC::OBSERVER_REMOVE] = { &CPythonNetworkStream::RecvObserverRemovePacket, sizeof(TPacketGCObserverRemove), false };
h[GC::OBSERVER_MOVE] = { &CPythonNetworkStream::RecvObserverMovePacket, sizeof(TPacketGCObserverMove), false };
// Warp / PVP
h[GC::WARP] = { &CPythonNetworkStream::RecvWarpPacket, sizeof(TPacketGCWarp), false };
h[GC::PVP] = { &CPythonNetworkStream::RecvPVPPacket, sizeof(TPacketGCPVP), false };
h[GC::DUEL_START] = { &CPythonNetworkStream::RecvDuelStartPacket, sizeof(TPacketGCDuelStart), false };
// Character
h[GC::CHARACTER_ADD] = { &CPythonNetworkStream::RecvCharacterAppendPacket, sizeof(TPacketGCCharacterAdd), false };
h[GC::CHAR_ADDITIONAL_INFO] = { &CPythonNetworkStream::RecvCharacterAdditionalInfo, sizeof(TPacketGCCharacterAdditionalInfo), false };
h[GC::CHARACTER_ADD2] = { &CPythonNetworkStream::RecvCharacterAppendPacketNew, sizeof(TPacketGCCharacterAdd2), false };
h[GC::CHARACTER_UPDATE] = { &CPythonNetworkStream::RecvCharacterUpdatePacket, sizeof(TPacketGCCharacterUpdate), false };
h[GC::CHARACTER_UPDATE2] = { &CPythonNetworkStream::RecvCharacterUpdatePacketNew, sizeof(TPacketGCCharacterUpdate2), false };
h[GC::CHARACTER_DEL] = { &CPythonNetworkStream::RecvCharacterDeletePacket, sizeof(TPacketGCCharacterDelete), false };
h[GC::CHAT] = { &CPythonNetworkStream::RecvChatPacket, sizeof(TPacketGCChat), false };
h[GC::SYNC_POSITION] = { &CPythonNetworkStream::RecvSyncPositionPacket, sizeof(TPacketGCC2C), false };
h[GC::OWNERSHIP] = { &CPythonNetworkStream::RecvOwnerShipPacket, sizeof(TPacketGCOwnership), false };
h[GC::WHISPER] = { &CPythonNetworkStream::RecvWhisperPacket, sizeof(TPacketGCWhisper), false };
h[GC::MOVE] = { &CPythonNetworkStream::RecvCharacterMovePacket, sizeof(TPacketGCMove), false };
h[GC::CHARACTER_POSITION] = { &CPythonNetworkStream::RecvCharacterPositionPacket, sizeof(TPacketGCPosition), false };
// Combat
h[GC::STUN] = { &CPythonNetworkStream::RecvStunPacket, sizeof(TPacketGCStun), false };
h[GC::DEAD] = { &CPythonNetworkStream::RecvDeadPacket, sizeof(TPacketGCDead), false };
h[GC::PLAYER_POINT_CHANGE] = { &CPythonNetworkStream::RecvPointChange, sizeof(TPacketGCPointChange), false };
h[GC::DAMAGE_INFO] = { &CPythonNetworkStream::RecvDamageInfoPacket, sizeof(TPacketGCDamageInfo), false };
// Items
h[GC::ITEM_DEL] = { &CPythonNetworkStream::RecvItemDelPacket, sizeof(TPacketGCItemDel), false };
h[GC::ITEM_SET] = { &CPythonNetworkStream::RecvItemSetPacket, sizeof(TPacketGCItemSet), false };
h[GC::ITEM_GET] = { &CPythonNetworkStream::RecvItemGetPacket, sizeof(TPacketGCItemGet), false };
h[GC::ITEM_USE] = { &CPythonNetworkStream::RecvItemUsePacket, sizeof(TPacketGCItemUse), false };
h[GC::ITEM_UPDATE] = { &CPythonNetworkStream::RecvItemUpdatePacket, sizeof(TPacketGCItemUpdate), false };
h[GC::ITEM_GROUND_ADD] = { &CPythonNetworkStream::RecvItemGroundAddPacket, sizeof(TPacketGCItemGroundAdd), false };
h[GC::ITEM_GROUND_DEL] = { &CPythonNetworkStream::RecvItemGroundDelPacket, sizeof(TPacketGCItemGroundDel), false };
h[GC::ITEM_OWNERSHIP] = { &CPythonNetworkStream::RecvItemOwnership, sizeof(TPacketGCItemOwnership), false };
// Quickslot
h[GC::QUICKSLOT_ADD] = { &CPythonNetworkStream::RecvQuickSlotAddPacket, sizeof(TPacketGCQuickSlotAdd), false };
h[GC::QUICKSLOT_DEL] = { &CPythonNetworkStream::RecvQuickSlotDelPacket, sizeof(TPacketGCQuickSlotDel), false };
h[GC::QUICKSLOT_SWAP] = { &CPythonNetworkStream::RecvQuickSlotMovePacket, sizeof(TPacketGCQuickSlotSwap), false };
// Motion / Movement
h[GC::MOTION] = { &CPythonNetworkStream::RecvMotionPacket, sizeof(TPacketGCMotion), false };
h[GC::CHANGE_SPEED] = { &CPythonNetworkStream::RecvChangeSpeedPacket, sizeof(TPacketGCChangeSpeed), false };
// Shop / Exchange
h[GC::SHOP] = { &CPythonNetworkStream::RecvShopPacket, sizeof(TPacketGCShop), false };
h[GC::SHOP_SIGN] = { &CPythonNetworkStream::RecvShopSignPacket, sizeof(TPacketGCShopSign), false };
h[GC::EXCHANGE] = { &CPythonNetworkStream::RecvExchangePacket, sizeof(TPacketGCExchange), false };
// Quest
h[GC::QUEST_INFO] = { &CPythonNetworkStream::RecvQuestInfoPacket, sizeof(TPacketGCQuestInfo), false };
h[GC::REQUEST_MAKE_GUILD] = { &CPythonNetworkStream::RecvRequestMakeGuild, sizeof(TPacketGCBlank), false };
h[GC::SCRIPT] = { &CPythonNetworkStream::RecvScriptPacket, sizeof(TPacketGCScript), false };
h[GC::QUEST_CONFIRM] = { &CPythonNetworkStream::RecvQuestConfirmPacket, sizeof(TPacketGCQuestConfirm), false };
// Target / Mount
h[GC::TARGET] = { &CPythonNetworkStream::RecvTargetPacket, sizeof(TPacketGCTarget), false };
h[GC::MOUNT] = { &CPythonNetworkStream::RecvMountPacket, sizeof(TPacketGCMount), false };
// Points
h[GC::PLAYER_POINTS] = { &CPythonNetworkStream::__RecvPlayerPoints, sizeof(TPacketGCPoints), false };
// Fly
h[GC::CREATE_FLY] = { &CPythonNetworkStream::RecvCreateFlyPacket, sizeof(TPacketGCCreateFly), false };
h[GC::FLY_TARGETING] = { &CPythonNetworkStream::RecvFlyTargetingPacket, sizeof(TPacketGCFlyTargeting), false };
h[GC::ADD_FLY_TARGETING] = { &CPythonNetworkStream::RecvAddFlyTargetingPacket, sizeof(TPacketGCFlyTargeting), false };
// Skills
h[GC::SKILL_LEVEL] = { &CPythonNetworkStream::RecvSkillLevel, sizeof(TPacketGCSkillLevel), false };
h[GC::SKILL_LEVEL_NEW] = { &CPythonNetworkStream::RecvSkillLevelNew, sizeof(TPacketGCSkillLevelNew), false };
h[GC::SKILL_COOLTIME_END] = { &CPythonNetworkStream::RecvSkillCoolTimeEnd, sizeof(TPacketGCSkillCoolTimeEnd), false };
// Messenger / Guild
h[GC::MESSENGER] = { &CPythonNetworkStream::RecvMessenger, sizeof(TPacketGCMessenger), false };
h[GC::GUILD] = { &CPythonNetworkStream::RecvGuild, sizeof(TPacketGCGuild), false };
h[GC::MARK_UPDATE] = { &CPythonNetworkStream::RecvMarkUpdate, sizeof(TPacketGCMarkUpdate), false };
// Party
h[GC::PARTY_INVITE] = { &CPythonNetworkStream::RecvPartyInvite, sizeof(TPacketGCPartyInvite), false };
h[GC::PARTY_ADD] = { &CPythonNetworkStream::RecvPartyAdd, sizeof(TPacketGCPartyAdd), false };
h[GC::PARTY_UPDATE] = { &CPythonNetworkStream::RecvPartyUpdate, sizeof(TPacketGCPartyUpdate), false };
h[GC::PARTY_REMOVE] = { &CPythonNetworkStream::RecvPartyRemove, sizeof(TPacketGCPartyRemove), false };
h[GC::PARTY_LINK] = { &CPythonNetworkStream::RecvPartyLink, sizeof(TPacketGCPartyLink), false };
h[GC::PARTY_UNLINK] = { &CPythonNetworkStream::RecvPartyUnlink, sizeof(TPacketGCPartyUnlink), false };
h[GC::PARTY_PARAMETER] = { &CPythonNetworkStream::RecvPartyParameter, sizeof(TPacketGCPartyParameter), false };
// Safebox
h[GC::SAFEBOX_SET] = { &CPythonNetworkStream::RecvSafeBoxSetPacket, sizeof(TPacketGCItemSet), false };
h[GC::SAFEBOX_DEL] = { &CPythonNetworkStream::RecvSafeBoxDelPacket, sizeof(TPacketGCItemDel), false };
h[GC::SAFEBOX_WRONG_PASSWORD] = { &CPythonNetworkStream::RecvSafeBoxWrongPasswordPacket, sizeof(TPacketGCSafeboxWrongPassword), false };
h[GC::SAFEBOX_SIZE] = { &CPythonNetworkStream::RecvSafeBoxSizePacket, sizeof(TPacketGCSafeboxSize), false };
h[GC::SAFEBOX_MONEY_CHANGE] = { &CPythonNetworkStream::RecvSafeBoxMoneyChangePacket, sizeof(TPacketGCSafeboxMoneyChange), false };
// Fishing / Dungeon / Time
h[GC::FISHING] = { &CPythonNetworkStream::RecvFishing, sizeof(TPacketGCFishing), false };
h[GC::DUNGEON] = { &CPythonNetworkStream::RecvDungeon, sizeof(TPacketGCDungeon), false };
h[GC::TIME] = { &CPythonNetworkStream::RecvTimePacket, sizeof(TPacketGCTime), false };
// Walk / Skill group / Refine
h[GC::WALK_MODE] = { &CPythonNetworkStream::RecvWalkModePacket, sizeof(TPacketGCWalkMode), false };
h[GC::CHANGE_SKILL_GROUP] = { &CPythonNetworkStream::RecvChangeSkillGroupPacket, sizeof(TPacketGCChangeSkillGroup), false };
h[GC::REFINE_INFORMATION] = { &CPythonNetworkStream::RecvRefineInformationPacket, sizeof(TPacketGCRefineInformation), false };
h[GC::REFINE_INFORMATION_NEW] = { &CPythonNetworkStream::RecvRefineInformationPacketNew, sizeof(TPacketGCRefineInformationNew), false };
// Effects
h[GC::SEPCIAL_EFFECT] = { &CPythonNetworkStream::RecvSpecialEffect, sizeof(TPacketGCSpecialEffect), false };
h[GC::SPECIFIC_EFFECT] = { &CPythonNetworkStream::RecvSpecificEffect, sizeof(TPacketGCSpecificEffect), false };
// Map / NPC
h[GC::NPC_POSITION] = { &CPythonNetworkStream::RecvNPCList, sizeof(TPacketGCNPCPosition), false };
h[GC::CHANNEL] = { &CPythonNetworkStream::RecvChannelPacket, sizeof(TPacketGCChannel), false };
h[GC::VIEW_EQUIP] = { &CPythonNetworkStream::RecvViewEquipPacket, sizeof(TPacketGCViewEquip), false };
h[GC::LAND_LIST] = { &CPythonNetworkStream::RecvLandPacket, sizeof(TPacketGCLandList), false };
// Target
h[GC::TARGET_CREATE_NEW] = { &CPythonNetworkStream::RecvTargetCreatePacketNew, sizeof(TPacketGCTargetCreateNew), false };
h[GC::TARGET_UPDATE] = { &CPythonNetworkStream::RecvTargetUpdatePacket, sizeof(TPacketGCTargetUpdate), false };
h[GC::TARGET_DELETE] = { &CPythonNetworkStream::RecvTargetDeletePacket, sizeof(TPacketGCTargetDelete), false };
// Affect
h[GC::AFFECT_ADD] = { &CPythonNetworkStream::RecvAffectAddPacket, sizeof(TPacketGCAffectAdd), false };
h[GC::AFFECT_REMOVE] = { &CPythonNetworkStream::RecvAffectRemovePacket, sizeof(TPacketGCAffectRemove), false };
// Mall
h[GC::MALL_OPEN] = { &CPythonNetworkStream::RecvMallOpenPacket, sizeof(TPacketGCMallOpen), false };
h[GC::MALL_SET] = { &CPythonNetworkStream::RecvMallItemSetPacket, sizeof(TPacketGCItemSet), false };
h[GC::MALL_DEL] = { &CPythonNetworkStream::RecvMallItemDelPacket, sizeof(TPacketGCItemDel), false };
// Lover
h[GC::LOVER_INFO] = { &CPythonNetworkStream::RecvLoverInfoPacket, sizeof(TPacketGCLoverInfo), false };
h[GC::LOVE_POINT_UPDATE] = { &CPythonNetworkStream::RecvLovePointUpdatePacket, sizeof(TPacketGCLovePointUpdate), false };
// Misc
h[GC::DIG_MOTION] = { &CPythonNetworkStream::RecvDigMotionPacket, sizeof(TPacketGCDigMotion), false };
h[GC::DRAGON_SOUL_REFINE] = { &CPythonNetworkStream::RecvDragonSoulRefine, sizeof(TPacketGCDragonSoulRefine), false };
}
void CPythonNetworkStream::RegisterLoadingHandlers()
{
// Loading phase: start with ALL game handlers as fallback (old code: default -> GamePhase())
m_loadingHandlers = m_gameHandlers;
// Override/add loading-specific handlers
m_loadingHandlers[GC::PHASE] = { &CPythonNetworkStream::RecvPhasePacket, sizeof(TPacketGCPhase), true };
m_loadingHandlers[GC::MAIN_CHARACTER] = { &CPythonNetworkStream::RecvMainCharacter, sizeof(TPacketGCMainCharacter), false };
}
// --- Packet sequence tracking ---
void CPythonNetworkStream::LogRecvPacket(uint16_t header, uint16_t length)
{
auto& e = m_aRecentRecvPackets[m_dwRecvPacketSeq % PACKET_LOG_SIZE];
e.seq = m_dwRecvPacketSeq;
e.header = header;
e.length = length;
m_dwRecvPacketSeq++;
}
void CPythonNetworkStream::DumpRecentPackets() const
{
const uint32_t recvCount = std::min(m_dwRecvPacketSeq, (uint32_t)PACKET_LOG_SIZE);
const uint32_t sentCount = std::min(m_dwSentPacketSeq, (uint32_t)SENT_PACKET_LOG_SIZE);
TraceError("=== Recent RECV packets (last %u of %u total) ===", recvCount, m_dwRecvPacketSeq);
for (uint32_t i = 0; i < recvCount; i++)
{
uint32_t idx = (m_dwRecvPacketSeq > PACKET_LOG_SIZE)
? (m_dwRecvPacketSeq - PACKET_LOG_SIZE + i)
: i;
const auto& e = m_aRecentRecvPackets[idx % PACKET_LOG_SIZE];
TraceError(" RECV #%u: header=0x%04X len=%u", e.seq, e.header, e.length);
}
TraceError("=== Recent SENT packets (last %u of %u total) ===", sentCount, m_dwSentPacketSeq);
for (uint32_t i = 0; i < sentCount; i++)
{
uint32_t idx = (m_dwSentPacketSeq > SENT_PACKET_LOG_SIZE)
? (m_dwSentPacketSeq - SENT_PACKET_LOG_SIZE + i)
: i;
const auto& e = m_aSentPacketLog[idx % SENT_PACKET_LOG_SIZE];
TraceError(" SENT #%u: header=0x%04X len=%u", e.seq, e.header, e.length);
}
}

View File

@@ -1,8 +1,10 @@
#pragma once
#include <unordered_map>
#include <vector>
#include "EterLib/FuncObject.h"
#include "EterLib/NetStream.h"
#include "EterLib/NetPacketHeaderMap.h"
#include "InsultChecker.h"
@@ -15,6 +17,15 @@ struct SNetworkUpdateActorData;
class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNetworkStream>
{
public:
// Table-driven packet dispatch (Phase 5)
struct PacketHandlerEntry {
bool (CPythonNetworkStream::*handler)();
uint16_t minSize;
bool exitPhase; // true = stop dispatch loop after handling (phase-changing packets)
};
using PacketHandlerMap = std::unordered_map<uint16_t, PacketHandlerEntry>;
public:
enum
{
@@ -266,13 +277,9 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
// 용홍석 강화
bool SendDragonSoulRefinePacket(BYTE bRefineType, TItemPos* pos);
// Handshake
bool RecvHandshakePacket();
bool RecvHandshakeOKPacket();
// Secure key exchange (libsodium/XChaCha20-Poly1305)
bool RecvKeyChallenge();
bool RecvKeyComplete();
// Secure key exchange override (adds time sync on top of base class crypto)
bool RecvKeyChallenge() override;
bool RecvKeyComplete() override;
// ETC
DWORD GetMainActorVID();
@@ -311,7 +318,6 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
bool SendC2CPacket(DWORD dwSize, void * pData);
bool SendChatPacket(const char * c_szChat, BYTE byType = CHAT_TYPE_TALKING);
bool SendWhisperPacket(const char * name, const char * c_szChat);
bool SendMobileMessagePacket(const char * name, const char * c_szChat);
bool SendMessengerAddByVIDPacket(DWORD vid);
bool SendMessengerAddByNamePacket(const char * c_szName);
bool SendMessengerRemovePacket(const char * c_szKey, const char * c_szName);
@@ -389,7 +395,6 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
// Common
bool RecvErrorPacket(int header);
bool RecvPingPacket();
bool RecvDefaultPacket(int header);
bool RecvPhasePacket();
// Login Phase
@@ -409,10 +414,7 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
bool __RecvChangeName();
// Loading Phase
bool RecvMainCharacter();
bool RecvMainCharacter2_EMPIRE();
bool RecvMainCharacter3_BGM();
bool RecvMainCharacter4_BGM_VOL();
bool RecvMainCharacter();
void __SetFieldMusicFileName(const char* musicName);
void __SetFieldMusicFileInfo(const char* musicName, float vol);
@@ -457,8 +459,30 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
bool RecvMotionPacket();
bool RecvShopPacket();
// Shop sub-handlers
bool RecvShopSub_Start(const std::vector<char>& buf);
bool RecvShopSub_StartEx(const std::vector<char>& buf);
bool RecvShopSub_End(const std::vector<char>& buf);
bool RecvShopSub_UpdateItem(const std::vector<char>& buf);
bool RecvShopSub_UpdatePrice(const std::vector<char>& buf);
bool RecvShopSub_NotEnoughMoney(const std::vector<char>& buf);
bool RecvShopSub_NotEnoughMoneyEx(const std::vector<char>& buf);
bool RecvShopSub_Soldout(const std::vector<char>& buf);
bool RecvShopSub_InventoryFull(const std::vector<char>& buf);
bool RecvShopSub_InvalidPos(const std::vector<char>& buf);
bool RecvShopSignPacket();
bool RecvExchangePacket();
// Exchange sub-handlers
bool RecvExchangeSub_Start(const TPacketGCExchange& pack);
bool RecvExchangeSub_ItemAdd(const TPacketGCExchange& pack);
bool RecvExchangeSub_ItemDel(const TPacketGCExchange& pack);
bool RecvExchangeSub_ElkAdd(const TPacketGCExchange& pack);
bool RecvExchangeSub_Accept(const TPacketGCExchange& pack);
bool RecvExchangeSub_End(const TPacketGCExchange& pack);
bool RecvExchangeSub_Already(const TPacketGCExchange& pack);
bool RecvExchangeSub_LessElk(const TPacketGCExchange& pack);
// Quest
bool RecvScriptPacket();
@@ -489,6 +513,28 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
// Guild
bool RecvGuild();
// Guild sub-handlers
bool RecvGuildSub_Login(const TPacketGCGuild& pack);
bool RecvGuildSub_Logout(const TPacketGCGuild& pack);
bool RecvGuildSub_Remove(const TPacketGCGuild& pack);
bool RecvGuildSub_List(const TPacketGCGuild& pack);
bool RecvGuildSub_Grade(const TPacketGCGuild& pack);
bool RecvGuildSub_GradeName(const TPacketGCGuild& pack);
bool RecvGuildSub_GradeAuth(const TPacketGCGuild& pack);
bool RecvGuildSub_Info(const TPacketGCGuild& pack);
bool RecvGuildSub_Comments(const TPacketGCGuild& pack);
bool RecvGuildSub_ChangeExp(const TPacketGCGuild& pack);
bool RecvGuildSub_ChangeMemberGrade(const TPacketGCGuild& pack);
bool RecvGuildSub_SkillInfo(const TPacketGCGuild& pack);
bool RecvGuildSub_ChangeMemberGeneral(const TPacketGCGuild& pack);
bool RecvGuildSub_Invite(const TPacketGCGuild& pack);
bool RecvGuildSub_War(const TPacketGCGuild& pack);
bool RecvGuildSub_Name(const TPacketGCGuild& pack);
bool RecvGuildSub_WarList(const TPacketGCGuild& pack);
bool RecvGuildSub_WarEndList(const TPacketGCGuild& pack);
bool RecvGuildSub_WarPoint(const TPacketGCGuild& pack);
bool RecvGuildSub_MoneyChange(const TPacketGCGuild& pack);
bool RecvMarkUpdate();
// Party
@@ -566,8 +612,16 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
BOOL IsGameOnline();
protected:
bool CheckPacket(TPacketHeader * pRetHeader);
// Table-driven packet dispatch
bool DispatchPacket(const PacketHandlerMap& handlers);
void RegisterOfflineHandlers();
void RegisterHandshakeHandlers();
void RegisterLoginHandlers();
void RegisterSelectHandlers();
void RegisterLoadingHandlers();
void RegisterGameHandlers();
void __InitializeGamePhase();
void __InitializeMarkAuth();
void __GlobalPositionToLocalPosition(int32_t& rGlobalX, int32_t& rGlobalY);
@@ -606,9 +660,7 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
void __SetGuildID(DWORD id);
protected:
TPacketGCHandshake m_HandshakeData;
DWORD m_dwChangingPhaseTime;
DWORD m_dwBindupRetryCount;
DWORD m_dwMainActorVID;
DWORD m_dwMainActorRace;
DWORD m_dwMainActorEmpire;
@@ -700,6 +752,14 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
std::deque<std::string> m_kQue_stHack;
// Per-phase handler dispatch tables
PacketHandlerMap m_offlineHandlers;
PacketHandlerMap m_handshakeHandlers;
PacketHandlerMap m_loginHandlers;
PacketHandlerMap m_selectHandlers;
PacketHandlerMap m_loadingHandlers;
PacketHandlerMap m_gameHandlers;
private:
struct SDirectEnterMode
{
@@ -726,4 +786,23 @@ class CPythonNetworkStream : public CNetworkStream, public CSingleton<CPythonNet
void __BettingGuildWar_Initialize();
void __BettingGuildWar_SetObserverCount(UINT uObserverCount);
void __BettingGuildWar_SetBettingMoney(UINT uBettingMoney);
// --- Packet sequence tracking (debug aid) ---
// Send tracking lives on CNetworkStream (base class); recv tracking is here.
public:
struct PacketLogEntry
{
uint32_t seq;
uint16_t header;
uint16_t length;
};
static constexpr size_t PACKET_LOG_SIZE = 32;
void LogRecvPacket(uint16_t header, uint16_t length);
void DumpRecentPackets() const;
private:
PacketLogEntry m_aRecentRecvPackets[PACKET_LOG_SIZE] = {};
uint32_t m_dwRecvPacketSeq = 0;
};

View File

@@ -399,20 +399,6 @@ void CPythonNetworkStream::ServerCommand(char * c_szCommand)
IAbstractPlayer& rPlayer=IAbstractPlayer::GetSingleton();
rPlayer.StopStaminaConsume(dwCurrentStamina);
}
else if (!strcmpi(szCmd, "sms"))
{
IAbstractPlayer& rPlayer=IAbstractPlayer::GetSingleton();
rPlayer.SetMobileFlag(TRUE);
}
else if (!strcmpi(szCmd, "nosms"))
{
IAbstractPlayer& rPlayer=IAbstractPlayer::GetSingleton();
rPlayer.SetMobileFlag(FALSE);
}
else if (!strcmpi(szCmd, "mobile_auth"))
{
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "OnMobileAuthority", Py_BuildValue("()"));
}
else if (!strcmpi(szCmd, "messenger_auth"))
{
const std::string & c_rstrName = TokenVector[1].c_str();

View File

@@ -283,16 +283,6 @@ PyObject* netSetTCPSendBufferSize(PyObject* poSelf, PyObject* poArgs)
return Py_BuildNone();
}
PyObject* netSetUDPRecvBufferSize(PyObject* poSelf, PyObject* poArgs)
{
int bufSize;
if (!PyTuple_GetInteger(poArgs, 0, &bufSize))
return Py_BuildException();
//CPythonNetworkDatagram::Instance().SetRecvBufferSize(bufSize);
return Py_BuildNone();
}
PyObject* netSetMarkServer(PyObject* poSelf, PyObject* poArgs)
{
char* szAddr;
@@ -323,19 +313,6 @@ PyObject* netConnectTCP(PyObject* poSelf, PyObject* poArgs)
return Py_BuildNone();
}
PyObject* netConnectUDP(PyObject* poSelf, PyObject* poArgs)
{
char * c_szIP;
if (!PyTuple_GetString(poArgs, 0, &c_szIP))
return Py_BuildException();
int iPort;
if (!PyTuple_GetInteger(poArgs, 1, &iPort))
return Py_BuildException();
//CPythonNetworkDatagram::Instance().SetConnection(c_szIP, iPort);
return Py_BuildNone();
}
PyObject* netConnectToAccountServer(PyObject* poSelf, PyObject* poArgs)
{
char* addr;
@@ -495,21 +472,6 @@ PyObject* netSendWhisperPacket(PyObject* poSelf, PyObject* poArgs)
return Py_BuildNone();
}
PyObject* netSendMobileMessagePacket(PyObject* poSelf, PyObject* poArgs)
{
char* szName;
char* szLine;
if (!PyTuple_GetString(poArgs, 0, &szName))
return Py_BuildException();
if (!PyTuple_GetString(poArgs, 1, &szLine))
return Py_BuildException();
CPythonNetworkStream& rkNetStream=CPythonNetworkStream::Instance();
rkNetStream.SendMobileMessagePacket(szName, szLine);
return Py_BuildNone();
}
PyObject* netSendCharacterPositionPacket(PyObject* poSelf, PyObject* poArgs)
{
int iPosition;
@@ -1565,16 +1527,6 @@ PyObject* netSendSelectItemPacket(PyObject* poSelf, PyObject* poArgs)
return Py_BuildNone();
}
PyObject* netSetPacketSequenceMode(PyObject* poSelf, PyObject* poArgs)
{
CPythonNetworkStream& rns=CPythonNetworkStream::Instance();
CAccountConnector & rkAccountConnector = CAccountConnector::Instance();
rns.SetPacketSequenceMode(true);
rkAccountConnector.SetPacketSequenceMode(true);
return Py_BuildNone();
}
PyObject* netSetEmpireLanguageMode(PyObject* poSelf, PyObject* poArgs)
{
int iMode;
@@ -1717,14 +1669,12 @@ void initnet()
{ "SetHandler", netSetHandler, METH_VARARGS },
{ "SetTCPRecvBufferSize", netSetTCPRecvBufferSize, METH_VARARGS },
{ "SetTCPSendBufferSize", netSetTCPSendBufferSize, METH_VARARGS },
{ "SetUDPRecvBufferSize", netSetUDPRecvBufferSize, METH_VARARGS },
{ "DirectEnter", netDirectEnter, METH_VARARGS },
{ "LogOutGame", netLogOutGame, METH_VARARGS },
{ "ExitGame", netExitGame, METH_VARARGS },
{ "ExitApplication", netExitApplication, METH_VARARGS },
{ "ConnectTCP", netConnectTCP, METH_VARARGS },
{ "ConnectUDP", netConnectUDP, METH_VARARGS },
{ "ConnectToAccountServer", netConnectToAccountServer, METH_VARARGS },
{ "SendLoginPacket", netSendLoginPacket, METH_VARARGS },
@@ -1752,7 +1702,6 @@ void initnet()
{ "SendChatPacket", netSendChatPacket, METH_VARARGS },
{ "SendEmoticon", netSendEmoticon, METH_VARARGS },
{ "SendWhisperPacket", netSendWhisperPacket, METH_VARARGS },
{ "SendMobileMessagePacket", netSendMobileMessagePacket, METH_VARARGS },
{ "SendCharacterPositionPacket", netSendCharacterPositionPacket, METH_VARARGS },
@@ -1824,7 +1773,6 @@ void initnet()
{ "SendSelectItemPacket", netSendSelectItemPacket, METH_VARARGS },
// SYSTEM
{ "SetPacketSequenceMode", netSetPacketSequenceMode, METH_VARARGS },
{ "SetEmpireLanguageMode", netSetEmpireLanguageMode, METH_VARARGS },
// For Test
@@ -1886,11 +1834,11 @@ void initnet()
PyModule_AddIntConstant(poModule, "EMPIRE_A", 1);
PyModule_AddIntConstant(poModule, "EMPIRE_B", 2);
PyModule_AddIntConstant(poModule, "EMPIRE_C", 3);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL", DS_SUB_HEADER_REFINE_FAIL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE", DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL", DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY", DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL", DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL", DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_SUCCEED", DS_SUB_HEADER_REFINE_SUCCEED);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL", DragonSoulSub::REFINE_FAIL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE", DragonSoulSub::REFINE_FAIL_MAX_REFINE);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL", DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY", DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MONEY);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL", DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MATERIAL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL", DragonSoulSub::REFINE_FAIL_TOO_MUCH_MATERIAL);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_REFINE_SUCCEED", DragonSoulSub::REFINE_SUCCEED);
}

File diff suppressed because it is too large Load Diff

View File

@@ -414,7 +414,7 @@ bool CPythonNetworkStream::RecvSyncPositionPacket()
TPacketGCSyncPositionElement kSyncPos;
UINT uSyncPosCount=(kPacketSyncPos.wSize-sizeof(kPacketSyncPos))/sizeof(kSyncPos);
UINT uSyncPosCount=(kPacketSyncPos.length-sizeof(kPacketSyncPos))/sizeof(kSyncPos);
for (UINT iSyncPos=0; iSyncPos<uSyncPosCount; ++iSyncPos)
{
if (!Recv(sizeof(TPacketGCSyncPositionElement), &kSyncPos))

View File

@@ -18,13 +18,12 @@ bool CPythonNetworkStream::SendSafeBoxMoneyPacket(BYTE byState, DWORD dwMoney)
return false;
// TPacketCGSafeboxMoney kSafeboxMoney;
// kSafeboxMoney.bHeader = HEADER_CG_SAFEBOX_MONEY;
// kSafeboxMoney.bHeader = CG::SAFEBOX_MONEY;
// kSafeboxMoney.bState = byState;
// kSafeboxMoney.dwMoney = dwMoney;
// if (!Send(sizeof(kSafeboxMoney), &kSafeboxMoney))
// return false;
//
// return SendSequence();
}
bool CPythonNetworkStream::SendSafeBoxCheckinPacket(TItemPos InventoryPos, BYTE bySafeBoxPos)
@@ -32,13 +31,14 @@ bool CPythonNetworkStream::SendSafeBoxCheckinPacket(TItemPos InventoryPos, BYTE
__PlayInventoryItemDropSound(InventoryPos);
TPacketCGSafeboxCheckin kSafeboxCheckin;
kSafeboxCheckin.bHeader = HEADER_CG_SAFEBOX_CHECKIN;
kSafeboxCheckin.header = CG::SAFEBOX_CHECKIN;
kSafeboxCheckin.length = sizeof(kSafeboxCheckin);
kSafeboxCheckin.ItemPos = InventoryPos;
kSafeboxCheckin.bSafePos = bySafeBoxPos;
if (!Send(sizeof(kSafeboxCheckin), &kSafeboxCheckin))
return false;
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendSafeBoxCheckoutPacket(BYTE bySafeBoxPos, TItemPos InventoryPos)
@@ -46,13 +46,14 @@ bool CPythonNetworkStream::SendSafeBoxCheckoutPacket(BYTE bySafeBoxPos, TItemPos
__PlaySafeBoxItemDropSound(bySafeBoxPos);
TPacketCGSafeboxCheckout kSafeboxCheckout;
kSafeboxCheckout.bHeader = HEADER_CG_SAFEBOX_CHECKOUT;
kSafeboxCheckout.header = CG::SAFEBOX_CHECKOUT;
kSafeboxCheckout.length = sizeof(kSafeboxCheckout);
kSafeboxCheckout.bSafePos = bySafeBoxPos;
kSafeboxCheckout.ItemPos = InventoryPos;
if (!Send(sizeof(kSafeboxCheckout), &kSafeboxCheckout))
return false;
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendSafeBoxItemMovePacket(BYTE bySourcePos, BYTE byTargetPos, BYTE byCount)
@@ -60,14 +61,15 @@ bool CPythonNetworkStream::SendSafeBoxItemMovePacket(BYTE bySourcePos, BYTE byTa
__PlaySafeBoxItemDropSound(bySourcePos);
TPacketCGItemMove kItemMove;
kItemMove.header = HEADER_CG_SAFEBOX_ITEM_MOVE;
kItemMove.header = CG::SAFEBOX_ITEM_MOVE;
kItemMove.length = sizeof(kItemMove);
kItemMove.pos = TItemPos(INVENTORY, bySourcePos);
kItemMove.num = byCount;
kItemMove.change_pos = TItemPos(INVENTORY, byTargetPos);
if (!Send(sizeof(kItemMove), &kItemMove))
return false;
return SendSequence();
return true;
}
bool CPythonNetworkStream::RecvSafeBoxSetPacket()
@@ -136,7 +138,7 @@ bool CPythonNetworkStream::RecvSafeBoxMoneyChangePacket()
if (!Recv(sizeof(kMoneyChange), &kMoneyChange))
return false;
CPythonSafeBox::Instance().SetMoney(kMoneyChange.dwMoney);
CPythonSafeBox::Instance().SetMoney(kMoneyChange.lMoney);
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "RefreshSafeboxMoney", Py_BuildValue("()"));
return true;
@@ -152,13 +154,14 @@ bool CPythonNetworkStream::SendMallCheckoutPacket(BYTE byMallPos, TItemPos Inven
__PlayMallItemDropSound(byMallPos);
TPacketCGMallCheckout kMallCheckoutPacket;
kMallCheckoutPacket.bHeader = HEADER_CG_MALL_CHECKOUT;
kMallCheckoutPacket.header = CG::MALL_CHECKOUT;
kMallCheckoutPacket.length = sizeof(kMallCheckoutPacket);
kMallCheckoutPacket.bMallPos = byMallPos;
kMallCheckoutPacket.ItemPos = InventoryPos;
if (!Send(sizeof(kMallCheckoutPacket), &kMallCheckoutPacket))
return false;
return SendSequence();
return true;
}
bool CPythonNetworkStream::RecvMallOpenPacket()
@@ -412,8 +415,9 @@ bool CPythonNetworkStream::SendShopEndPacket()
return true;
TPacketCGShop packet_shop;
packet_shop.header = HEADER_CG_SHOP;
packet_shop.subheader = SHOP_SUBHEADER_CG_END;
packet_shop.header = CG::SHOP;
packet_shop.length = sizeof(packet_shop);
packet_shop.subheader = ShopSub::CG::END;
if (!Send(sizeof(packet_shop), &packet_shop))
{
@@ -421,7 +425,7 @@ bool CPythonNetworkStream::SendShopEndPacket()
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendShopBuyPacket(BYTE bPos)
@@ -430,8 +434,9 @@ bool CPythonNetworkStream::SendShopBuyPacket(BYTE bPos)
return true;
TPacketCGShop PacketShop;
PacketShop.header = HEADER_CG_SHOP;
PacketShop.subheader = SHOP_SUBHEADER_CG_BUY;
PacketShop.header = CG::SHOP;
PacketShop.length = sizeof(PacketShop) + sizeof(BYTE) + sizeof(BYTE);
PacketShop.subheader = ShopSub::CG::BUY;
if (!Send(sizeof(TPacketCGShop), &PacketShop))
{
@@ -452,7 +457,7 @@ bool CPythonNetworkStream::SendShopBuyPacket(BYTE bPos)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendShopSellPacket(BYTE bySlot)
@@ -461,8 +466,9 @@ bool CPythonNetworkStream::SendShopSellPacket(BYTE bySlot)
return true;
TPacketCGShop PacketShop;
PacketShop.header = HEADER_CG_SHOP;
PacketShop.subheader = SHOP_SUBHEADER_CG_SELL;
PacketShop.header = CG::SHOP;
PacketShop.length = sizeof(PacketShop) + sizeof(BYTE);
PacketShop.subheader = ShopSub::CG::SELL;
if (!Send(sizeof(TPacketCGShop), &PacketShop))
{
@@ -475,7 +481,7 @@ bool CPythonNetworkStream::SendShopSellPacket(BYTE bySlot)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendShopSellPacketNew(BYTE bySlot, BYTE byCount)
@@ -484,8 +490,9 @@ bool CPythonNetworkStream::SendShopSellPacketNew(BYTE bySlot, BYTE byCount)
return true;
TPacketCGShop PacketShop;
PacketShop.header = HEADER_CG_SHOP;
PacketShop.subheader = SHOP_SUBHEADER_CG_SELL2;
PacketShop.header = CG::SHOP;
PacketShop.length = sizeof(PacketShop) + sizeof(BYTE) + sizeof(BYTE);
PacketShop.subheader = ShopSub::CG::SELL2;
if (!Send(sizeof(TPacketCGShop), &PacketShop))
{
@@ -505,7 +512,7 @@ bool CPythonNetworkStream::SendShopSellPacketNew(BYTE bySlot, BYTE byCount)
Tracef(" SendShopSellPacketNew(bySlot=%d, byCount=%d)\n", bySlot, byCount);
return SendSequence();
return true;
}
// Send
@@ -535,7 +542,8 @@ bool CPythonNetworkStream::SendItemUsePacket(TItemPos pos)
__PlayInventoryItemUseSound(pos);
TPacketCGItemUse itemUsePacket;
itemUsePacket.header = HEADER_CG_ITEM_USE;
itemUsePacket.header = CG::ITEM_USE;
itemUsePacket.length = sizeof(itemUsePacket);
itemUsePacket.pos = pos;
if (!Send(sizeof(TPacketCGItemUse), &itemUsePacket))
@@ -544,7 +552,7 @@ bool CPythonNetworkStream::SendItemUsePacket(TItemPos pos)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendItemUseToItemPacket(TItemPos source_pos, TItemPos target_pos)
@@ -553,7 +561,8 @@ bool CPythonNetworkStream::SendItemUseToItemPacket(TItemPos source_pos, TItemPos
return true;
TPacketCGItemUseToItem itemUseToItemPacket;
itemUseToItemPacket.header = HEADER_CG_ITEM_USE_TO_ITEM;
itemUseToItemPacket.header = CG::ITEM_USE_TO_ITEM;
itemUseToItemPacket.length = sizeof(itemUseToItemPacket);
itemUseToItemPacket.source_pos = source_pos;
itemUseToItemPacket.target_pos = target_pos;
@@ -567,7 +576,7 @@ bool CPythonNetworkStream::SendItemUseToItemPacket(TItemPos source_pos, TItemPos
Tracef(" << SendItemUseToItemPacket(src=%d, dst=%d)\n", source_pos, target_pos);
#endif
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendItemDropPacket(TItemPos pos, DWORD elk)
@@ -576,7 +585,8 @@ bool CPythonNetworkStream::SendItemDropPacket(TItemPos pos, DWORD elk)
return true;
TPacketCGItemDrop itemDropPacket;
itemDropPacket.header = HEADER_CG_ITEM_DROP;
itemDropPacket.header = CG::ITEM_DROP;
itemDropPacket.length = sizeof(itemDropPacket);
itemDropPacket.pos = pos;
itemDropPacket.elk = elk;
@@ -586,7 +596,7 @@ bool CPythonNetworkStream::SendItemDropPacket(TItemPos pos, DWORD elk)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendItemDropPacketNew(TItemPos pos, DWORD elk, DWORD count)
@@ -595,7 +605,8 @@ bool CPythonNetworkStream::SendItemDropPacketNew(TItemPos pos, DWORD elk, DWORD
return true;
TPacketCGItemDrop2 itemDropPacket;
itemDropPacket.header = HEADER_CG_ITEM_DROP2;
itemDropPacket.header = CG::ITEM_DROP2;
itemDropPacket.length = sizeof(itemDropPacket);
itemDropPacket.pos = pos;
itemDropPacket.gold = elk;
itemDropPacket.count = count;
@@ -606,7 +617,7 @@ bool CPythonNetworkStream::SendItemDropPacketNew(TItemPos pos, DWORD elk, DWORD
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::__IsEquipItemInSlot(TItemPos uSlotPos)
@@ -698,7 +709,8 @@ bool CPythonNetworkStream::SendItemMovePacket(TItemPos pos, TItemPos change_pos,
__PlayInventoryItemDropSound(pos);
TPacketCGItemMove itemMovePacket;
itemMovePacket.header = HEADER_CG_ITEM_MOVE;
itemMovePacket.header = CG::ITEM_MOVE;
itemMovePacket.length = sizeof(itemMovePacket);
itemMovePacket.pos = pos;
itemMovePacket.change_pos = change_pos;
itemMovePacket.num = num;
@@ -709,7 +721,7 @@ bool CPythonNetworkStream::SendItemMovePacket(TItemPos pos, TItemPos change_pos,
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendItemPickUpPacket(DWORD vid)
@@ -718,7 +730,8 @@ bool CPythonNetworkStream::SendItemPickUpPacket(DWORD vid)
return true;
TPacketCGItemPickUp itemPickUpPacket;
itemPickUpPacket.header = HEADER_CG_ITEM_PICKUP;
itemPickUpPacket.header = CG::ITEM_PICKUP;
itemPickUpPacket.length = sizeof(itemPickUpPacket);
itemPickUpPacket.vid = vid;
if (!Send(sizeof(TPacketCGItemPickUp), &itemPickUpPacket))
@@ -727,7 +740,7 @@ bool CPythonNetworkStream::SendItemPickUpPacket(DWORD vid)
return false;
}
return SendSequence();
return true;
}
@@ -738,7 +751,8 @@ bool CPythonNetworkStream::SendQuickSlotAddPacket(BYTE wpos, BYTE type, BYTE pos
TPacketCGQuickSlotAdd quickSlotAddPacket;
quickSlotAddPacket.header = HEADER_CG_QUICKSLOT_ADD;
quickSlotAddPacket.header = CG::QUICKSLOT_ADD;
quickSlotAddPacket.length = sizeof(quickSlotAddPacket);
quickSlotAddPacket.pos = wpos;
quickSlotAddPacket.slot.Type = type;
quickSlotAddPacket.slot.Position = pos;
@@ -749,7 +763,7 @@ bool CPythonNetworkStream::SendQuickSlotAddPacket(BYTE wpos, BYTE type, BYTE pos
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendQuickSlotDelPacket(BYTE pos)
@@ -759,7 +773,8 @@ bool CPythonNetworkStream::SendQuickSlotDelPacket(BYTE pos)
TPacketCGQuickSlotDel quickSlotDelPacket;
quickSlotDelPacket.header = HEADER_CG_QUICKSLOT_DEL;
quickSlotDelPacket.header = CG::QUICKSLOT_DEL;
quickSlotDelPacket.length = sizeof(quickSlotDelPacket);
quickSlotDelPacket.pos = pos;
if (!Send(sizeof(TPacketCGQuickSlotDel), &quickSlotDelPacket))
@@ -768,7 +783,7 @@ bool CPythonNetworkStream::SendQuickSlotDelPacket(BYTE pos)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendQuickSlotMovePacket(BYTE pos, BYTE change_pos)
@@ -778,7 +793,8 @@ bool CPythonNetworkStream::SendQuickSlotMovePacket(BYTE pos, BYTE change_pos)
TPacketCGQuickSlotSwap quickSlotSwapPacket;
quickSlotSwapPacket.header = HEADER_CG_QUICKSLOT_SWAP;
quickSlotSwapPacket.header = CG::QUICKSLOT_SWAP;
quickSlotSwapPacket.length = sizeof(quickSlotSwapPacket);
quickSlotSwapPacket.pos = pos;
quickSlotSwapPacket.change_pos = change_pos;
@@ -788,7 +804,7 @@ bool CPythonNetworkStream::SendQuickSlotMovePacket(BYTE pos, BYTE change_pos)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::RecvSpecialEffect()
@@ -946,19 +962,19 @@ bool CPythonNetworkStream::RecvDragonSoulRefine()
switch (kDragonSoul.bSubType)
{
case DS_SUB_HEADER_OPEN:
case DragonSoulSub::OPEN:
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_DragonSoulRefineWindow_Open", Py_BuildValue("()"));
break;
case DS_SUB_HEADER_REFINE_FAIL:
case DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE:
case DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL:
case DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY:
case DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL:
case DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL:
case DragonSoulSub::REFINE_FAIL:
case DragonSoulSub::REFINE_FAIL_MAX_REFINE:
case DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL:
case DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MONEY:
case DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MATERIAL:
case DragonSoulSub::REFINE_FAIL_TOO_MUCH_MATERIAL:
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_DragonSoulRefineWindow_RefineFail", Py_BuildValue("(iii)",
kDragonSoul.bSubType, kDragonSoul.Pos.window_type, kDragonSoul.Pos.cell));
break;
case DS_SUB_HEADER_REFINE_SUCCEED:
case DragonSoulSub::REFINE_SUCCEED:
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_DragonSoulRefineWindow_RefineSucceed",
Py_BuildValue("(ii)", kDragonSoul.Pos.window_type, kDragonSoul.Pos.cell));
break;

View File

@@ -6,71 +6,7 @@
// HandShake ---------------------------------------------------------------------------
void CPythonNetworkStream::HandShakePhase()
{
TPacketHeader header;
if (!CheckPacket(&header))
return;
switch (header)
{
case HEADER_GC_PHASE:
if (RecvPhasePacket())
return;
break;
case HEADER_GC_BINDUDP:
{
TPacketGCBindUDP BindUDP;
if (!Recv(sizeof(TPacketGCBindUDP), &BindUDP))
return;
return;
}
break;
case HEADER_GC_HANDSHAKE:
{
if (!Recv(sizeof(TPacketGCHandshake), &m_HandshakeData))
return;
Tracenf("HANDSHAKE RECV %u %d", m_HandshakeData.dwTime, m_HandshakeData.lDelta);
ELTimer_SetServerMSec(m_HandshakeData.dwTime+ m_HandshakeData.lDelta);
m_HandshakeData.dwTime = m_HandshakeData.dwTime + m_HandshakeData.lDelta + m_HandshakeData.lDelta;
m_HandshakeData.lDelta = 0;
Tracenf("HANDSHAKE SEND %u", m_HandshakeData.dwTime);
if (!Send(sizeof(TPacketGCHandshake), &m_HandshakeData))
{
assert(!"Failed Sending Handshake");
return;
}
CTimer::Instance().SetBaseTime();
return;
}
break;
case HEADER_GC_PING:
RecvPingPacket();
return;
break;
case HEADER_GC_KEY_CHALLENGE:
RecvKeyChallenge();
return;
break;
case HEADER_GC_KEY_COMPLETE:
RecvKeyComplete();
return;
break;
}
RecvErrorPacket(header);
DispatchPacket(m_handshakeHandlers);
}
void CPythonNetworkStream::SetHandShakePhase()
@@ -78,6 +14,7 @@ void CPythonNetworkStream::SetHandShakePhase()
if ("HandShake"!=m_strPhase)
m_phaseLeaveFunc.Run();
Tracef("[PHASE] Entering phase: HandShake\n");
Tracen("");
Tracen("## Network - Hand Shake Phase ##");
Tracen("");
@@ -99,114 +36,29 @@ void CPythonNetworkStream::SetHandShakePhase()
}
}
bool CPythonNetworkStream::RecvHandshakePacket()
{
TPacketGCHandshake kHandshakeData;
if (!Recv(sizeof(TPacketGCHandshake), &kHandshakeData))
return false;
Tracenf("HANDSHAKE RECV %u %d", kHandshakeData.dwTime, kHandshakeData.lDelta);
m_kServerTimeSync.m_dwChangeServerTime = kHandshakeData.dwTime + kHandshakeData.lDelta;
m_kServerTimeSync.m_dwChangeClientTime = ELTimer_GetMSec();
kHandshakeData.dwTime = kHandshakeData.dwTime + kHandshakeData.lDelta + kHandshakeData.lDelta;
kHandshakeData.lDelta = 0;
Tracenf("HANDSHAKE SEND %u", kHandshakeData.dwTime);
kHandshakeData.header = HEADER_CG_TIME_SYNC;
if (!Send(sizeof(TPacketGCHandshake), &kHandshakeData))
{
assert(!"Failed Sending Handshake");
return false;
}
SendSequence();
return true;
}
bool CPythonNetworkStream::RecvHandshakeOKPacket()
{
TPacketGCBlank kBlankPacket;
if (!Recv(sizeof(TPacketGCBlank), &kBlankPacket))
return false;
DWORD dwDelta=ELTimer_GetMSec()-m_kServerTimeSync.m_dwChangeClientTime;
ELTimer_SetServerMSec(m_kServerTimeSync.m_dwChangeServerTime+dwDelta);
Tracenf("HANDSHAKE OK RECV %u %u", m_kServerTimeSync.m_dwChangeServerTime, dwDelta);
return true;
}
// Secure key exchange handlers (libsodium/XChaCha20-Poly1305)
// Override: extract time sync before delegating crypto to base class
bool CPythonNetworkStream::RecvKeyChallenge()
{
// Peek to extract server_time before base class Recv() consumes the packet
TPacketGCKeyChallenge packet;
if (!Recv(sizeof(packet), &packet))
{
if (!Peek(sizeof(packet), &packet))
return false;
}
Tracen("SECURE KEY_CHALLENGE RECV");
// Time sync from server (game connection only)
m_kServerTimeSync.m_dwChangeServerTime = packet.server_time;
m_kServerTimeSync.m_dwChangeClientTime = ELTimer_GetMSec();
ELTimer_SetServerMSec(packet.server_time);
CTimer::Instance().SetBaseTime();
SecureCipher& cipher = GetSecureCipher();
if (!cipher.Initialize())
{
TraceError("Failed to initialize SecureCipher");
Disconnect();
return false;
}
Tracef("[HANDSHAKE] KeyChallenge: server_time=%u, client_time=%u, offset=%d\n",
packet.server_time, ELTimer_GetMSec(), (int)(packet.server_time - ELTimer_GetMSec()));
if (!cipher.ComputeClientKeys(packet.server_pk))
{
TraceError("Failed to compute client session keys");
Disconnect();
return false;
}
TPacketCGKeyResponse response;
response.bHeader = HEADER_CG_KEY_RESPONSE;
cipher.GetPublicKey(response.client_pk);
cipher.ComputeChallengeResponse(packet.challenge, response.challenge_response);
if (!Send(sizeof(response), &response))
{
TraceError("Failed to send KeyResponse");
return false;
}
Tracen("SECURE KEY_RESPONSE SENT");
return true;
// Base class handles cipher init, key computation, and response
return CNetworkStream::RecvKeyChallenge();
}
// RecvKeyComplete: no game-specific additions, delegate entirely to base
bool CPythonNetworkStream::RecvKeyComplete()
{
TPacketGCKeyComplete packet;
if (!Recv(sizeof(packet), &packet))
{
return false;
}
Tracen("SECURE KEY_COMPLETE RECV");
SecureCipher& cipher = GetSecureCipher();
uint8_t decrypted_token[SecureCipher::SESSION_TOKEN_SIZE];
if (!cipher.DecryptToken(packet.encrypted_token, sizeof(packet.encrypted_token),
packet.nonce, decrypted_token))
{
TraceError("Failed to decrypt session token");
Disconnect();
return false;
}
cipher.SetSessionToken(decrypted_token);
cipher.SetActivated(true);
DecryptPendingRecvData();
Tracen("SECURE CIPHER ACTIVATED");
return true;
return CNetworkStream::RecvKeyComplete();
}

View File

@@ -77,88 +77,8 @@ bool CPythonNetworkStream::LoadConvertTable(DWORD dwEmpireID, const char* c_szFi
// Loading ---------------------------------------------------------------------------
void CPythonNetworkStream::LoadingPhase()
{
TPacketHeader header;
if (!CheckPacket(&header))
return;
switch (header)
{
case HEADER_GC_PHASE:
if (RecvPhasePacket())
return;
break;
case HEADER_GC_MAIN_CHARACTER:
if (RecvMainCharacter())
return;
break;
// SUPPORT_BGM
case HEADER_GC_MAIN_CHARACTER2_EMPIRE:
if (RecvMainCharacter2_EMPIRE())
return;
break;
case HEADER_GC_MAIN_CHARACTER3_BGM:
if (RecvMainCharacter3_BGM())
return;
break;
case HEADER_GC_MAIN_CHARACTER4_BGM_VOL:
if (RecvMainCharacter4_BGM_VOL())
return;
break;
// END_OF_SUPPORT_BGM
case HEADER_GC_CHARACTER_UPDATE:
if (RecvCharacterUpdatePacket())
return;
break;
case HEADER_GC_PLAYER_POINTS:
if (__RecvPlayerPoints())
return;
break;
case HEADER_GC_PLAYER_POINT_CHANGE:
if (RecvPointChange())
return;
break;
case HEADER_GC_ITEM_DEL:
if (RecvItemSetPacket())
return;
break;
case HEADER_GC_PING:
if (RecvPingPacket())
return;
break;
case HEADER_GC_QUICKSLOT_ADD:
if (RecvQuickSlotAddPacket())
return;
break;
case HEADER_GC_KEY_CHALLENGE:
RecvKeyChallenge();
return;
break;
case HEADER_GC_KEY_COMPLETE:
RecvKeyComplete();
return;
break;
default:
GamePhase();
return;
break;
}
RecvErrorPacket(header);
while (DispatchPacket(m_loadingHandlers))
;
}
void CPythonNetworkStream::SetLoadingPhase()
@@ -166,6 +86,7 @@ void CPythonNetworkStream::SetLoadingPhase()
if ("Loading"!=m_strPhase)
m_phaseLeaveFunc.Run();
Tracef("[PHASE] Entering phase: Loading\n");
Tracen("");
Tracen("## Network - Loading Phase ##");
Tracen("");
@@ -187,104 +108,30 @@ void CPythonNetworkStream::SetLoadingPhase()
bool CPythonNetworkStream::RecvMainCharacter()
{
TPacketGCMainCharacter MainChrPacket;
if (!Recv(sizeof(TPacketGCMainCharacter), &MainChrPacket))
TPacketGCMainCharacter pack;
if (!Recv(sizeof(pack), &pack))
return false;
m_dwMainActorVID = MainChrPacket.dwVID;
m_dwMainActorRace = MainChrPacket.wRaceNum;
m_dwMainActorEmpire = 0;
m_dwMainActorSkillGroup = MainChrPacket.bySkillGroup;
m_dwMainActorVID = pack.dwVID;
m_dwMainActorRace = pack.wRaceNum;
m_dwMainActorEmpire = pack.byEmpire;
m_dwMainActorSkillGroup = pack.bySkillGroup;
m_rokNetActorMgr->SetMainActorVID(m_dwMainActorVID);
CPythonPlayer& rkPlayer=CPythonPlayer::Instance();
rkPlayer.SetName(MainChrPacket.szName);
CPythonPlayer& rkPlayer = CPythonPlayer::Instance();
rkPlayer.SetName(pack.szName);
rkPlayer.SetMainCharacterIndex(GetMainActorVID());
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_LOAD], "LoadData", Py_BuildValue("(ii)", MainChrPacket.lX, MainChrPacket.lY));
if (pack.szBGMName[0] != '\0')
{
if (pack.fBGMVol > 0.0f)
__SetFieldMusicFileInfo(pack.szBGMName, pack.fBGMVol);
else
__SetFieldMusicFileName(pack.szBGMName);
}
//Tracef(" >> RecvMainCharacter\n");
SendClientVersionPacket();
return true;
}
// SUPPORT_BGM
bool CPythonNetworkStream::RecvMainCharacter2_EMPIRE()
{
TPacketGCMainCharacter2_EMPIRE mainChrPacket;
if (!Recv(sizeof(mainChrPacket), &mainChrPacket))
return false;
m_dwMainActorVID = mainChrPacket.dwVID;
m_dwMainActorRace = mainChrPacket.wRaceNum;
m_dwMainActorEmpire = mainChrPacket.byEmpire;
m_dwMainActorSkillGroup = mainChrPacket.bySkillGroup;
m_rokNetActorMgr->SetMainActorVID(m_dwMainActorVID);
CPythonPlayer& rkPlayer=CPythonPlayer::Instance();
rkPlayer.SetName(mainChrPacket.szName);
rkPlayer.SetMainCharacterIndex(GetMainActorVID());
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_LOAD], "LoadData", Py_BuildValue("(ii)", mainChrPacket.lX, mainChrPacket.lY));
//Tracef(" >> RecvMainCharacterNew : %d\n", m_dwMainActorEmpire);
SendClientVersionPacket();
return true;
}
bool CPythonNetworkStream::RecvMainCharacter3_BGM()
{
TPacketGCMainCharacter3_BGM mainChrPacket;
if (!Recv(sizeof(mainChrPacket), &mainChrPacket))
return false;
m_dwMainActorVID = mainChrPacket.dwVID;
m_dwMainActorRace = mainChrPacket.wRaceNum;
m_dwMainActorEmpire = mainChrPacket.byEmpire;
m_dwMainActorSkillGroup = mainChrPacket.bySkillGroup;
m_rokNetActorMgr->SetMainActorVID(m_dwMainActorVID);
CPythonPlayer& rkPlayer=CPythonPlayer::Instance();
rkPlayer.SetName(mainChrPacket.szUserName);
rkPlayer.SetMainCharacterIndex(GetMainActorVID());
__SetFieldMusicFileName(mainChrPacket.szBGMName);
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_LOAD], "LoadData", Py_BuildValue("(ii)", mainChrPacket.lX, mainChrPacket.lY));
//Tracef(" >> RecvMainCharacterNew : %d\n", m_dwMainActorEmpire);
SendClientVersionPacket();
return true;
}
bool CPythonNetworkStream::RecvMainCharacter4_BGM_VOL()
{
TPacketGCMainCharacter4_BGM_VOL mainChrPacket;
if (!Recv(sizeof(mainChrPacket), &mainChrPacket))
return false;
m_dwMainActorVID = mainChrPacket.dwVID;
m_dwMainActorRace = mainChrPacket.wRaceNum;
m_dwMainActorEmpire = mainChrPacket.byEmpire;
m_dwMainActorSkillGroup = mainChrPacket.bySkillGroup;
m_rokNetActorMgr->SetMainActorVID(m_dwMainActorVID);
CPythonPlayer& rkPlayer=CPythonPlayer::Instance();
rkPlayer.SetName(mainChrPacket.szUserName);
rkPlayer.SetMainCharacterIndex(GetMainActorVID());
__SetFieldMusicFileInfo(mainChrPacket.szBGMName, mainChrPacket.fBGMVol);
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_LOAD], "LoadData", Py_BuildValue("(ii)", mainChrPacket.lX, mainChrPacket.lY));
//Tracef(" >> RecvMainCharacterNew : %d\n", m_dwMainActorEmpire);
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_LOAD], "LoadData", Py_BuildValue("(ii)", pack.lX, pack.lY));
SendClientVersionPacket();
return true;
@@ -348,20 +195,15 @@ void CPythonNetworkStream::StartGame()
{
m_isStartGame=TRUE;
}
bool CPythonNetworkStream::SendEnterGame()
{
TPacketCGEnterFrontGame EnterFrontGamePacket;
EnterFrontGamePacket.header = HEADER_CG_ENTERGAME;
EnterFrontGamePacket.header = CG::ENTERGAME;
EnterFrontGamePacket.length = sizeof(EnterFrontGamePacket);
if (!Send(sizeof(EnterFrontGamePacket), &EnterFrontGamePacket))
{
Tracen("Send EnterFrontGamePacket");
return false;
}
if (!SendSequence())
return false;
__SendInternalBuffer();

View File

@@ -6,64 +6,7 @@
// Login ---------------------------------------------------------------------------
void CPythonNetworkStream::LoginPhase()
{
TPacketHeader header;
if (!CheckPacket(&header))
return;
switch (header)
{
case HEADER_GC_PHASE:
if (RecvPhasePacket())
return;
break;
case HEADER_GC_LOGIN_SUCCESS3:
if (__RecvLoginSuccessPacket3())
return;
break;
case HEADER_GC_LOGIN_SUCCESS4:
if (__RecvLoginSuccessPacket4())
return;
break;
case HEADER_GC_LOGIN_FAILURE:
if (__RecvLoginFailurePacket())
return;
break;
case HEADER_GC_EMPIRE:
if (__RecvEmpirePacket())
return;
break;
case HEADER_GC_LOGIN_KEY:
if (__RecvLoginKeyPacket())
return;
break;
case HEADER_GC_PING:
if (RecvPingPacket())
return;
break;
case HEADER_GC_KEY_CHALLENGE:
RecvKeyChallenge();
return;
break;
case HEADER_GC_KEY_COMPLETE:
RecvKeyComplete();
return;
break;
default:
if (RecvDefaultPacket(header))
return;
break;
}
RecvErrorPacket(header);
DispatchPacket(m_loginHandlers);
}
void CPythonNetworkStream::SetLoginPhase()
@@ -71,6 +14,7 @@ void CPythonNetworkStream::SetLoginPhase()
if ("Login" != m_strPhase)
m_phaseLeaveFunc.Run();
Tracef("[PHASE] Entering phase: Login\n");
Tracen("");
Tracen("## Network - Login Phase ##");
Tracen("");
@@ -84,7 +28,6 @@ void CPythonNetworkStream::SetLoginPhase()
if (0 == m_dwLoginKey)
{
TraceError("SetLoginPhase: no login key - cannot login without auth server");
ClearLoginInfo();
return;
}
@@ -166,10 +109,7 @@ bool CPythonNetworkStream::__RecvLoginSuccessPacket4()
m_kMarkAuth.m_dwHandle=kPacketLoginSuccess.handle;
m_kMarkAuth.m_dwRandomKey=kPacketLoginSuccess.random_key;
if (__DirectEnterMode_IsSet())
{
}
else
if (!__DirectEnterMode_IsSet())
{
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_SELECT], "Refresh", Py_BuildValue("()"));
}
@@ -205,7 +145,8 @@ bool CPythonNetworkStream::__RecvLoginFailurePacket()
bool CPythonNetworkStream::SendLoginPacketNew(const char * c_szName, const char * c_szPassword)
{
TPacketCGLogin2 LoginPacket;
LoginPacket.header = HEADER_CG_LOGIN2;
LoginPacket.header = CG::LOGIN2;
LoginPacket.length = sizeof(LoginPacket);
LoginPacket.login_key = m_dwLoginKey;
strncpy(LoginPacket.name, c_szName, sizeof(LoginPacket.name)-1);
@@ -217,12 +158,6 @@ bool CPythonNetworkStream::SendLoginPacketNew(const char * c_szName, const char
return false;
}
if (!SendSequence())
{
Tracen("SendLogin Error");
return false;
}
__SendInternalBuffer();
return true;

View File

@@ -5,18 +5,5 @@
void CPythonNetworkStream::OffLinePhase()
{
TPacketHeader header;
if (!CheckPacket(&header))
return;
switch (header)
{
case HEADER_GC_PHASE:
if (RecvPhasePacket())
return;
break;
}
RecvErrorPacket(header);
DispatchPacket(m_offlineHandlers);
}

View File

@@ -8,10 +8,6 @@ void CPythonNetworkStream::SetSelectPhase()
if ("Select" != m_strPhase)
m_phaseLeaveFunc.Run();
Tracen("");
Tracen("## Network - Select Phase ##");
Tracen("");
m_strPhase = "Select";
m_dwChangingPhaseTime = ELTimer_GetMSec();
@@ -20,7 +16,7 @@ void CPythonNetworkStream::SetSelectPhase()
if (__DirectEnterMode_IsSet())
{
PyCallClassMemberFunc(m_poHandler, "SetLoadingPhase", Py_BuildValue("()"));
PyCallClassMemberFunc(m_poHandler, "SetLoadingPhase", Py_BuildValue("()"));
}
else
{
@@ -33,99 +29,14 @@ void CPythonNetworkStream::SetSelectPhase()
void CPythonNetworkStream::SelectPhase()
{
TPacketHeader header;
if (!CheckPacket(&header))
return;
switch (header)
{
case HEADER_GC_PHASE:
if (RecvPhasePacket())
return;
break;
case HEADER_GC_EMPIRE:
if (__RecvEmpirePacket())
return;
break;
case HEADER_GC_LOGIN_SUCCESS3:
if (__RecvLoginSuccessPacket3())
return;
break;
case HEADER_GC_LOGIN_SUCCESS4:
if (__RecvLoginSuccessPacket4())
return;
break;
case HEADER_GC_PLAYER_CREATE_SUCCESS:
if (__RecvPlayerCreateSuccessPacket())
return;
break;
case HEADER_GC_PLAYER_CREATE_FAILURE:
if (__RecvPlayerCreateFailurePacket())
return;
break;
case HEADER_GC_PLAYER_DELETE_WRONG_SOCIAL_ID:
if (__RecvPlayerDestroyFailurePacket())
return;
break;
case HEADER_GC_PLAYER_DELETE_SUCCESS:
if (__RecvPlayerDestroySuccessPacket())
return;
break;
case HEADER_GC_CHANGE_NAME:
if (__RecvChangeName())
return;
break;
case HEADER_GC_HANDSHAKE:
RecvHandshakePacket();
return;
break;
case HEADER_GC_HANDSHAKE_OK:
RecvHandshakeOKPacket();
return;
break;
case HEADER_GC_KEY_CHALLENGE:
RecvKeyChallenge();
return;
break;
case HEADER_GC_KEY_COMPLETE:
RecvKeyComplete();
return;
break;
case HEADER_GC_PLAYER_POINT_CHANGE:
TPacketGCPointChange PointChange;
Recv(sizeof(TPacketGCPointChange), &PointChange);
return;
break;
///////////////////////////////////////////////////////////////////////////////////////////
case HEADER_GC_PING:
if (RecvPingPacket())
return;
break;
}
RecvErrorPacket(header);
DispatchPacket(m_selectHandlers);
}
bool CPythonNetworkStream::SendSelectEmpirePacket(DWORD dwEmpireID)
{
TPacketCGEmpire kPacketEmpire;
kPacketEmpire.bHeader=HEADER_CG_EMPIRE;
kPacketEmpire.header=CG::EMPIRE;
kPacketEmpire.length = sizeof(kPacketEmpire);
kPacketEmpire.bEmpire=dwEmpireID;
if (!Send(sizeof(kPacketEmpire), &kPacketEmpire))
@@ -135,14 +46,15 @@ bool CPythonNetworkStream::SendSelectEmpirePacket(DWORD dwEmpireID)
}
SetEmpireID(dwEmpireID);
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendSelectCharacterPacket(BYTE Index)
{
TPacketCGSelectCharacter SelectCharacterPacket;
SelectCharacterPacket.header = HEADER_CG_PLAYER_SELECT;
SelectCharacterPacket.header = CG::CHARACTER_SELECT;
SelectCharacterPacket.length = sizeof(SelectCharacterPacket);
SelectCharacterPacket.player_index = Index;
if (!Send(sizeof(TPacketCGSelectCharacter), &SelectCharacterPacket))
@@ -151,14 +63,15 @@ bool CPythonNetworkStream::SendSelectCharacterPacket(BYTE Index)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendDestroyCharacterPacket(BYTE index, const char * szPrivateCode)
{
TPacketCGDestroyCharacter DestroyCharacterPacket;
DestroyCharacterPacket.header = HEADER_CG_PLAYER_DESTROY;
DestroyCharacterPacket.header = CG::CHARACTER_DELETE;
DestroyCharacterPacket.length = sizeof(DestroyCharacterPacket);
DestroyCharacterPacket.index = index;
strncpy(DestroyCharacterPacket.szPrivateCode, szPrivateCode, PRIVATE_CODE_LENGTH-1);
@@ -168,14 +81,15 @@ bool CPythonNetworkStream::SendDestroyCharacterPacket(BYTE index, const char * s
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendCreateCharacterPacket(BYTE index, const char *name, BYTE job, BYTE shape, BYTE byCON, BYTE byINT, BYTE bySTR, BYTE byDEX)
{
TPacketCGCreateCharacter createCharacterPacket;
createCharacterPacket.header = HEADER_CG_PLAYER_CREATE;
createCharacterPacket.header = CG::CHARACTER_CREATE;
createCharacterPacket.length = sizeof(createCharacterPacket);
createCharacterPacket.index = index;
strncpy(createCharacterPacket.name, name, CHARACTER_NAME_MAX_LEN);
createCharacterPacket.job = job;
@@ -191,13 +105,14 @@ bool CPythonNetworkStream::SendCreateCharacterPacket(BYTE index, const char *nam
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::SendChangeNamePacket(BYTE index, const char *name)
{
TPacketCGChangeName ChangeNamePacket;
ChangeNamePacket.header = HEADER_CG_CHANGE_NAME;
ChangeNamePacket.header = CG::CHANGE_NAME;
ChangeNamePacket.length = sizeof(ChangeNamePacket);
ChangeNamePacket.index = index;
strncpy(ChangeNamePacket.name, name, CHARACTER_NAME_MAX_LEN);
@@ -207,7 +122,7 @@ bool CPythonNetworkStream::SendChangeNamePacket(BYTE index, const char *name)
return false;
}
return SendSequence();
return true;
}
bool CPythonNetworkStream::__RecvPlayerCreateSuccessPacket()

View File

@@ -1598,17 +1598,6 @@ DWORD CPythonPlayer::GetPKMode()
return pInstance->GetPKMode();
}
void CPythonPlayer::SetMobileFlag(BOOL bFlag)
{
m_bMobileFlag = bFlag;
PyCallClassMemberFunc(m_ppyGameWindow, "RefreshMobile", Py_BuildValue("()"));
}
BOOL CPythonPlayer::HasMobilePhoneNumber()
{
return m_bMobileFlag;
}
void CPythonPlayer::SetGameWindow(PyObject * ppyObject)
{
m_ppyGameWindow = ppyObject;
@@ -1692,8 +1681,6 @@ void CPythonPlayer::ClearSkillDict()
m_fConsumeStaminaPerSec = 0.0f;
m_fCurrentStamina = 0.0f;
m_bMobileFlag = FALSE;
__ClearAutoAttackTargetActorID();
}
@@ -1765,8 +1752,6 @@ void CPythonPlayer::Clear()
m_inGuildAreaID = 0xffffffff;
m_bMobileFlag = FALSE;
__ClearAutoAttackTargetActorID();
}

View File

@@ -403,11 +403,6 @@ class CPythonPlayer : public CSingleton<CPythonPlayer>, public IAbstractPlayer
DWORD GetPKMode();
// Mobile
void SetMobileFlag(BOOL bFlag);
BOOL HasMobilePhoneNumber();
// Combo
void SetComboSkillFlag(BOOL bFlag);
@@ -651,9 +646,6 @@ class CPythonPlayer : public CSingleton<CPythonPlayer>, public IAbstractPlayer
// Guild
DWORD m_inGuildAreaID;
// Mobile
BOOL m_bMobileFlag;
// System
BOOL m_sysIsCoolTime;
BOOL m_sysIsLevelLimit;

View File

@@ -203,8 +203,8 @@ void CPythonPlayerEventHandler::FlushVictimList()
CPythonNetworkStream& rkStream=CPythonNetworkStream::Instance();
TPacketCGSyncPosition kPacketSyncPos;
kPacketSyncPos.bHeader=HEADER_CG_SYNC_POSITION;
kPacketSyncPos.wSize=sizeof(kPacketSyncPos)+sizeof(TPacketCGSyncPositionElement) * uiVictimCount;
kPacketSyncPos.header=CG::SYNC_POSITION;
kPacketSyncPos.length=sizeof(kPacketSyncPos)+sizeof(TPacketCGSyncPositionElement) * uiVictimCount;
rkStream.Send(sizeof(kPacketSyncPos), &kPacketSyncPos);
@@ -214,7 +214,6 @@ void CPythonPlayerEventHandler::FlushVictimList()
rkStream.SendSyncPositionElementPacket(rkVictim.m_dwVID, rkVictim.m_lPixelX, rkVictim.m_lPixelY);
}
rkStream.SendSequence();
m_kVctkVictim.clear();
}

View File

@@ -706,33 +706,6 @@ bool CPythonPlayer::__CanMove()
return true;
}
/*
bool CPythonPlayer::__OLD_CanMove()
{
if (__IsProcessingEmotion())
{
return false;
}
CInstanceBase* pkInstMain=NEW_GetMainActorPtr();
if (!pkInstMain)
return false;
if (pkInstMain->IsDead())
return false;
if (pkInstMain->IsStun())
return false;
if (pkInstMain->isLock())
return false;
if (pkInstMain->IsParalysis())
return false;
return true;
}
*/
bool CPythonPlayer::__CanAttack()
{
@@ -947,65 +920,3 @@ void CPythonPlayer::__ReserveProcess_ClickActor()
pkInstMain->NEW_AttackToDestInstanceDirection(*pkInstReserved);
__ClearReservedAction();
}
/*
CInstanceBase* pkInstReserved=NEW_FindActorPtr(m_dwVIDReserved);
if (pkInstReserved)
{
if (pkInstMain->NEW_IsClickableDistanceDestInstance(*pkInstReserved))
{
if (pkInstMain->IsAttackableInstance(*pkInstReserved) )
{
if (!pkInstReserved->IsDead())
{
if (pkInstMain->IsInSafe())
{
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotAttack", Py_BuildValue("(is)", GetMainCharacterIndex(), "IN_SAFE"));
pkInstMain->NEW_Stop();
}
else if (pkInstReserved->IsInSafe())
{
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotAttack", Py_BuildValue("(is)", GetMainCharacterIndex(), "DEST_IN_SAFE"));
pkInstMain->NEW_Stop();
}
else
{
if (pkInstMain->IsBowMode())
{
if (!__HasEnoughArrow())
{
PyCallClassMemberFunc(m_ppyGameWindow, "OnCannotShot", Py_BuildValue("(is)", GetMainCharacterIndex(), "EMPTY_ARROW"));
pkInstMain->NEW_Stop();
__ClearReservedAction();
break;
}
}
if (pkInstReserved->GetVirtualID() != GetTargetVID())
{
SetTarget(pkInstReserved->GetVirtualID());
}
pkInstMain->NEW_AttackToDestInstanceDirection(*pkInstReserved);
}
}
}
else
{
__SendClickActorPacket(*pkInstReserved);
pkInstMain->NEW_Stop();
}
__ClearReservedAction();
}
else
{
//Tracen("ReservedMode: MOVE");
pkInstMain->NEW_MoveToDestInstanceDirection(*pkInstReserved);
}
}
else
{
__ClearReservedAction();
}
*/

View File

@@ -1882,11 +1882,6 @@ PyObject * playerGetPKMode(PyObject* poSelf, PyObject* poArgs)
return Py_BuildValue("i", CPythonPlayer::Instance().GetPKMode());
}
PyObject * playerHasMobilePhoneNumber(PyObject* poSelf, PyObject* poArgs)
{
return Py_BuildValue("i", CPythonPlayer::Instance().HasMobilePhoneNumber());
}
PyObject * playerSetWeaponAttackBonusFlag(PyObject* poSelf, PyObject* poArgs)
{
int iFlag;
@@ -2138,11 +2133,11 @@ PyObject* playerSendDragonSoulRefine(PyObject* poSelf, PyObject* poArgs)
return Py_BuildException();
switch (bSubHeader)
{
case DS_SUB_HEADER_CLOSE:
case DragonSoulSub::CLOSE:
break;
case DS_SUB_HEADER_DO_UPGRADE:
case DS_SUB_HEADER_DO_IMPROVEMENT:
case DS_SUB_HEADER_DO_REFINE:
case DragonSoulSub::DO_UPGRADE:
case DragonSoulSub::DO_IMPROVEMENT:
case DragonSoulSub::DO_REFINE:
{
if (!PyTuple_GetObject(poArgs, 1, &pDic))
return Py_BuildException();
@@ -2317,9 +2312,6 @@ void initPlayer()
// PK Mode
{ "GetPKMode", playerGetPKMode, METH_VARARGS },
// Mobile
{ "HasMobilePhoneNumber", playerHasMobilePhoneNumber, METH_VARARGS },
// Emotion
{ "RegisterEmotionIcon", playerRegisterEmotionIcon, METH_VARARGS },
{ "GetEmotionIconImage", playerGetEmotionIconImage, METH_VARARGS },
@@ -2568,9 +2560,9 @@ void initPlayer()
PyModule_AddIntConstant(poModule, "DRAGON_SOUL_EQUIPMENT_FIRST_SIZE", c_DragonSoul_Equip_Slot_Max);
// 용혼석 개량창
PyModule_AddIntConstant(poModule, "DRAGON_SOUL_REFINE_CLOSE", DS_SUB_HEADER_CLOSE);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_DO_UPGRADE", DS_SUB_HEADER_DO_UPGRADE);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_DO_IMPROVEMENT", DS_SUB_HEADER_DO_IMPROVEMENT);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_DO_REFINE", DS_SUB_HEADER_DO_REFINE);
PyModule_AddIntConstant(poModule, "DRAGON_SOUL_REFINE_CLOSE", DragonSoulSub::CLOSE);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_DO_UPGRADE", DragonSoulSub::DO_UPGRADE);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_DO_IMPROVEMENT", DragonSoulSub::DO_IMPROVEMENT);
PyModule_AddIntConstant(poModule, "DS_SUB_HEADER_DO_REFINE", DragonSoulSub::DO_REFINE);
}

View File

@@ -57,8 +57,10 @@ void CServerStateChecker::Request()
m_kStream.SetSendBufferSize(1024);
m_kStream.SetRecvBufferSize(1024);
BYTE bHeader = HEADER_CG_STATE_CHECKER;
if (!m_kStream.Send(sizeof(bHeader), &bHeader))
TPacketGCBlank pack;
pack.header = CG::STATE_CHECKER;
pack.length = sizeof(pack);
if (!m_kStream.Send(sizeof(pack), &pack))
{
for (std::list<TChannel>::const_iterator it = m_lstChannel.begin(); it != m_lstChannel.end(); ++it) {
PyCallClassMemberFunc(m_poWnd, "NotifyChannelState", Py_BuildValue("(ii)", it->uServerIndex, 0));
@@ -72,13 +74,31 @@ void CServerStateChecker::Update()
{
m_kStream.Process();
BYTE bHeader;
if (!m_kStream.Recv(sizeof(bHeader), &bHeader)) {
return;
}
if (HEADER_GC_RESPOND_CHANNELSTATUS != bHeader) {
return;
// Skip packets until we find GC::RESPOND_CHANNELSTATUS.
// The server may send other packets first, which we need to discard.
while (true)
{
TDynamicSizePacketHeader packHeader;
if (!m_kStream.Peek(sizeof(packHeader), &packHeader))
return;
if (packHeader.header == GC::RESPOND_CHANNELSTATUS)
{
// Consume the header we peeked
m_kStream.Recv(sizeof(packHeader));
break;
}
// Not our packet — skip it using its length field
if (packHeader.length < sizeof(packHeader))
return;
if (!m_kStream.Peek(packHeader.length))
return; // Not enough data yet
m_kStream.Recv(packHeader.length);
}
int nSize;
if (!m_kStream.Recv(sizeof(nSize), &nSize)) {
return;

View File

@@ -35,7 +35,6 @@ enum
PLAYER_NAME_MAX_LEN = 12,
};
void initudp();
void initapp();
void initime();
void initsystem();

View File

@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <utf8.h>
#include <sodium.h>
#include "EterLib/FontManager.h"
extern "C" {
extern int _fltused;
@@ -224,7 +225,6 @@ bool RunMainScript(CPythonLauncher& pyLauncher, const char* lpCmdLine)
initgrpText();
initwndMgr();
initudp();
initapp();
initsystem();
initchr();
@@ -297,6 +297,12 @@ static bool Main(HINSTANCE hInstance, LPSTR lpCmdLine)
return false;
}
if (!CFontManager::Instance().Initialize())
{
LogBox("FreeType initialization failed");
return false;
}
static CLZO lzo;
CPackManager packMgr;
@@ -324,6 +330,8 @@ static bool Main(HINSTANCE hInstance, LPSTR lpCmdLine)
app->Destroy();
delete app;
CFontManager::Instance().Destroy();
return 0;
}

11
vendor/CMakeLists.txt vendored
View File

@@ -7,10 +7,19 @@ set(ZSTD_BUILD_SHARED OFF CACHE BOOL "BUILD SHARED LIBRARIES" FORCE)
add_subdirectory(zstd-1.5.7/build/cmake zstd)
include_directories("zstd/lib")
## FreeType - disable optional dependencies we don't need
set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE)
set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE)
set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE)
set(FT_DISABLE_BZIP2 ON CACHE BOOL "" FORCE)
set(FT_DISABLE_ZLIB ON CACHE BOOL "" FORCE)
add_subdirectory(freetype-2.13.3)
if (WIN32)
set_target_properties(lzo2 PROPERTIES FOLDER vendor)
set_target_properties(sodium PROPERTIES FOLDER vendor)
set_target_properties(freetype PROPERTIES FOLDER vendor)
## zstd stuff
set_target_properties(zstd PROPERTIES FOLDER vendor/zstd)
set_target_properties(libzstd_static PROPERTIES FOLDER vendor/zstd)

1
vendor/freetype-2.13.3 vendored Submodule

Submodule vendor/freetype-2.13.3 added at 42608f77f2