From 60ee35e921d2c808540bfce91004fcc2c686f41a Mon Sep 17 00:00:00 2001 From: rtw1x1 Date: Sun, 8 Feb 2026 07:35:02 +0000 Subject: [PATCH] Networking Overhaul: Modern packets, buffers, handshake, dispatch & security hardening See Readme --- README.md | 273 +++ include/pcg_extras.hpp | 666 ------ include/pcg_random.hpp | 1951 ---------------- include/pcg_uint128.hpp | 1006 -------- src/common/length.h | 3 - src/common/packet_headers.h | 713 ++++++ src/common/service.h | 1 - src/common/tables.h | 310 +-- src/db/ClientManager.cpp | 705 ++---- src/db/ClientManager.h | 29 +- src/db/ClientManagerBoot.cpp | 15 +- src/db/ClientManagerEventFlag.cpp | 12 +- src/db/ClientManagerGuild.cpp | 24 +- src/db/ClientManagerHorseName.cpp | 6 +- src/db/ClientManagerLogin.cpp | 28 +- src/db/ClientManagerParty.cpp | 14 +- src/db/ClientManagerPlayer.cpp | 79 +- src/db/GuildManager.cpp | 28 +- src/db/ItemAwardManager.cpp | 4 +- src/db/Main.cpp | 2 - src/db/Marriage.cpp | 24 +- src/db/Monarch.cpp | 298 --- src/db/Monarch.h | 70 - src/db/MoneyLog.cpp | 4 +- src/db/Peer.cpp | 35 +- src/db/Peer.h | 10 +- src/db/PeerBase.cpp | 102 +- src/db/PeerBase.h | 13 +- src/db/PrivManager.cpp | 8 +- src/game/BlueDragon.cpp | 4 +- src/game/CMakeLists.txt | 2 + src/game/DragonSoul.cpp | 56 +- src/game/OXEvent.cpp | 8 +- src/game/PetSystem.cpp | 4 +- src/game/SecureCipher.cpp | 63 +- src/game/SecureCipher.h | 8 - src/game/TrafficProfiler.cpp | 92 - src/game/TrafficProfiler.h | 115 - src/game/arena.cpp | 16 +- src/game/battle.cpp | 21 +- src/game/buffer_manager.cpp | 33 +- src/game/buffer_manager.h | 15 +- src/game/building.cpp | 26 +- src/game/castle.cpp | 5 - src/game/char.cpp | 303 +-- src/game/char.h | 36 +- src/game/char_affect.cpp | 16 +- src/game/char_battle.cpp | 49 +- src/game/char_dragonsoul.cpp | 7 +- src/game/char_horse.cpp | 7 +- src/game/char_item.cpp | 43 +- src/game/char_manager.cpp | 9 +- src/game/char_quickslot.cpp | 13 +- src/game/char_skill.cpp | 12 +- src/game/char_state.cpp | 7 +- src/game/cmd.cpp | 31 - src/game/cmd.h | 1 - src/game/cmd_emotion.cpp | 8 +- src/game/cmd_general.cpp | 455 +--- src/game/cmd_gm.cpp | 187 +- src/game/config.cpp | 68 +- src/game/config.h | 6 +- src/game/cube.cpp | 2 +- src/game/db.cpp | 8 +- src/game/desc.cpp | 451 ++-- src/game/desc.h | 85 +- src/game/desc_client.cpp | 41 +- src/game/desc_client.h | 4 +- src/game/desc_manager.cpp | 81 +- src/game/desc_manager.h | 7 +- src/game/desc_p2p.cpp | 19 +- src/game/dungeon.cpp | 10 +- src/game/exchange.cpp | 35 +- src/game/firewall_manager.cpp | 227 ++ src/game/firewall_manager.h | 33 + src/game/fishing.cpp | 41 +- src/game/guild.cpp | 195 +- src/game/guild_manager.cpp | 32 +- src/game/guild_war.cpp | 41 +- src/game/horsename_manager.cpp | 4 +- src/game/input.cpp | 827 +++---- src/game/input.h | 230 +- src/game/input_auth.cpp | 55 +- src/game/input_db.cpp | 740 ++---- src/game/input_login.cpp | 297 ++- src/game/input_main.cpp | 1572 +++++++------ src/game/input_p2p.cpp | 288 +-- src/game/input_udp.cpp | 194 -- src/game/item.cpp | 27 +- src/game/item_manager.cpp | 6 +- src/game/item_manager_idrange.cpp | 4 +- src/game/log.cpp | 2 +- src/game/login_sim.h | 73 - src/game/main.cpp | 164 +- src/game/marriage.cpp | 18 +- src/game/messenger_manager.cpp | 48 +- src/game/monarch.cpp | 275 --- src/game/monarch.h | 61 - src/game/p2p.cpp | 8 +- src/game/packet_info.cpp | 259 +-- src/game/packet_info.h | 23 +- src/game/packet_reader.h | 157 ++ src/game/{packet.h => packet_structs.h} | 1199 ++++------ src/game/packet_writer.h | 139 ++ src/game/party.cpp | 60 +- src/game/priv_manager.cpp | 8 +- src/game/protocol.h | 24 +- src/game/pvp.cpp | 14 +- src/game/questlua.cpp | 2 - src/game/questlua.h | 2 - src/game/questlua_danceevent.cpp | 2 +- src/game/questlua_dungeon.cpp | 12 +- src/game/questlua_game.cpp | 12 +- src/game/questlua_global.cpp | 15 +- src/game/questlua_guild.cpp | 6 +- src/game/questlua_horse.cpp | 4 +- src/game/questlua_mgmt.cpp | 62 - src/game/questlua_monarch.cpp | 980 -------- src/game/questlua_party.cpp | 12 +- src/game/questlua_pc.cpp | 14 +- src/game/questmanager.cpp | 10 +- src/game/questnpc.cpp | 2 +- src/game/questpc.cpp | 24 +- src/game/safebox.cpp | 12 +- src/game/sectree.cpp | 4 +- src/game/sectree_manager.cpp | 13 +- src/game/sequence.cpp | 2055 ----------------- src/game/sequence.h | 3 - src/game/shop.cpp | 56 +- src/game/shopEx.cpp | 30 +- src/game/shop_manager.cpp | 14 +- src/game/target.cpp | 13 +- src/game/threeway_war.cpp | 8 +- src/game/war_map.cpp | 16 +- src/game/wedding.cpp | 4 +- src/libthecore/buffer.cpp | 276 --- src/libthecore/buffer.h | 43 - src/libthecore/ring_buffer.h | 191 ++ src/libthecore/socket.cpp | 16 +- src/libthecore/socket.h | 2 - src/libthecore/stdafx.h | 2 +- .../src/libsodium/include/sodium/version.h | 33 + 142 files changed, 5703 insertions(+), 14494 deletions(-) delete mode 100644 include/pcg_extras.hpp delete mode 100644 include/pcg_random.hpp delete mode 100644 include/pcg_uint128.hpp create mode 100644 src/common/packet_headers.h delete mode 100644 src/db/Monarch.cpp delete mode 100644 src/db/Monarch.h delete mode 100644 src/game/TrafficProfiler.cpp delete mode 100644 src/game/TrafficProfiler.h create mode 100644 src/game/firewall_manager.cpp create mode 100644 src/game/firewall_manager.h delete mode 100644 src/game/input_udp.cpp delete mode 100644 src/game/login_sim.h delete mode 100644 src/game/monarch.cpp delete mode 100644 src/game/monarch.h create mode 100644 src/game/packet_reader.h rename src/game/{packet.h => packet_structs.h} (58%) create mode 100644 src/game/packet_writer.h delete mode 100644 src/game/questlua_mgmt.cpp delete mode 100644 src/game/questlua_monarch.cpp delete mode 100644 src/game/sequence.cpp delete mode 100644 src/game/sequence.h delete mode 100644 src/libthecore/buffer.cpp delete mode 100644 src/libthecore/buffer.h create mode 100644 src/libthecore/ring_buffer.h create mode 100644 vendor/libsodium/src/libsodium/include/sodium/version.h diff --git a/README.md b/README.md index f543551..30d7615 100644 --- a/README.md +++ b/README.md @@ -60,3 +60,276 @@ The entire legacy encryption system has been replaced with [libsodium](https://d #### Pack File Encryption * **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) + +--- + +### 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. + +--- + +#### 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` + +##### 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 + +--- + +### DDoS / Flood Mitigation + +Two-layer defense against UDP floods and TCP SYN floods, integrated directly into the game server process. + +#### Layer 1 — UDP Sink Sockets + +Dummy UDP sockets bound to each game and P2P port with a minimal receive buffer (`SO_RCVBUF = 1`). The sockets are never read from — once the tiny kernel buffer fills, incoming UDP packets are silently dropped without generating ICMP port-unreachable replies. This prevents the server from being used as an ICMP reflection amplifier and reduces kernel CPU overhead from UDP floods. + +* **Zero overhead** — No threads, no polling, no syscalls. The kernel handles everything. +* **Always active** — Created unconditionally at startup alongside the TCP listeners +* **Defense-in-depth** — Acts as a fallback if iptables rules cannot be installed (e.g., non-root) + +#### Layer 2 — Kernel-Level Firewall (`FirewallManager`) + +The `FirewallManager` singleton programmatically installs firewall rules at server startup, dropping malicious traffic at the kernel level — before it reaches the socket/application layer. This is dramatically more efficient than socket-level drops at high packet rates (700k+ pps). + +* **FreeBSD** — Uses `ipfw` numbered rules (deterministic rule base per port) +* **Linux** — Uses `iptables` with a dedicated chain per process (e.g., `M2_GUARD_11011`) +* **Windows** — No-op stubs (compiles but does nothing). Windows is dev-only + +##### What it does +* **Drops all unsolicited inbound UDP** — Packets are rejected at the kernel firewall layer with near-zero CPU cost per packet +* **Rate-limits TCP SYN** on game and P2P ports — Default: 500 new connections/sec (per-source limit on FreeBSD, rate limit on Linux). Protects against SYN flood attacks while allowing legitimate mass logins (e.g., 1000 players at server launch) +* **Drops ICMP port-unreachable** — Prevents reflection/amplification attacks +* **Per-process isolation** — Each game process installs its own rules to avoid conflicts in multi-channel deployments +* **Crash recovery** — On startup, stale rules from previous crashes are automatically cleaned up before installing fresh rules +* **Graceful cleanup** — All rules are removed on normal shutdown + +##### Configuration (`conf/game.txt`) + +| Token | Default | Description | +|-------|---------|-------------| +| `firewall_enable` | `0` | Enable/disable the firewall manager (0=off, 1=on) | +| `firewall_tcp_syn_limit` | `500` | Max new TCP SYN connections/sec per port | +| `firewall_tcp_syn_burst` | `1000` | SYN burst allowance before rate limiting kicks in (Linux only) | + +##### FreeBSD setup (ipfw) + +Before enabling the firewall manager, the `ipfw` kernel module must be loaded with a default-allow policy. Without the allow rule, loading ipfw will block all traffic and lock you out. + +```bash +# Load ipfw module and immediately add a default allow rule +kldload ipfw && /sbin/ipfw -q add 65000 allow ip from any to any +``` + +To persist across reboots, add to `/boot/loader.conf`: +``` +ipfw_load="YES" +``` + +And to `/etc/rc.conf`: +``` +firewall_enable="YES" +firewall_type="open" +``` + +##### Verification + +FreeBSD: +```bash +# Check rules are installed (each process uses rule base 50000 + (port % 1000) * 10) +/sbin/ipfw list | grep 500 + +# Verify rules are cleaned up after shutdown +/sbin/ipfw list | grep 500 # should show no matching rules +``` + +Linux: +```bash +# Check rules are installed +iptables -L M2_GUARD_11011 -n -v + +# Verify chain is cleaned up after shutdown +iptables -L M2_GUARD_11011 # should fail with "No chain/target/match by that name" +``` + +##### Requirements +* **Root access** — Required on both FreeBSD and Linux for firewall rule installation. If not root, logs a warning and the server continues without firewall rules (Layer 1 UDP sinks still protect) + +--- + +### 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 | diff --git a/include/pcg_extras.hpp b/include/pcg_extras.hpp deleted file mode 100644 index 041724a..0000000 --- a/include/pcg_extras.hpp +++ /dev/null @@ -1,666 +0,0 @@ -/* - * PCG Random Number Generation for C++ - * - * Copyright 2014-2017 Melissa O'Neill , - * and the PCG Project contributors. - * - * SPDX-License-Identifier: (Apache-2.0 OR MIT) - * - * Licensed under the Apache License, Version 2.0 (provided in - * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0) - * or under the MIT license (provided in LICENSE-MIT.txt and at - * http://opensource.org/licenses/MIT), at your option. This file may not - * be copied, modified, or distributed except according to those terms. - * - * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See your chosen license for details. - * - * For additional information about the PCG random number generation scheme, - * visit http://www.pcg-random.org/. - */ - -/* - * This file provides support code that is useful for random-number generation - * but not specific to the PCG generation scheme, including: - * - 128-bit int support for platforms where it isn't available natively - * - bit twiddling operations - * - I/O of 128-bit and 8-bit integers - * - Handling the evilness of SeedSeq - * - Support for efficiently producing random numbers less than a given - * bound - */ - -#ifndef PCG_EXTRAS_HPP_INCLUDED -#define PCG_EXTRAS_HPP_INCLUDED 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __GNUC__ - #include -#endif - -/* - * Abstractions for compiler-specific directives - */ - -#ifdef __GNUC__ - #define PCG_NOINLINE __attribute__((noinline)) -#else - #define PCG_NOINLINE -#endif - -/* - * Some members of the PCG library use 128-bit math. When compiling on 64-bit - * platforms, both GCC and Clang provide 128-bit integer types that are ideal - * for the job. - * - * On 32-bit platforms (or with other compilers), we fall back to a C++ - * class that provides 128-bit unsigned integers instead. It may seem - * like we're reinventing the wheel here, because libraries already exist - * that support large integers, but most existing libraries provide a very - * generic multiprecision code, but here we're operating at a fixed size. - * Also, most other libraries are fairly heavyweight. So we use a direct - * implementation. Sadly, it's much slower than hand-coded assembly or - * direct CPU support. - * - */ -#if __SIZEOF_INT128__ && !PCG_FORCE_EMULATED_128BIT_MATH - namespace pcg_extras { - typedef __uint128_t pcg128_t; - } - #define PCG_128BIT_CONSTANT(high,low) \ - ((pcg_extras::pcg128_t(high) << 64) + low) -#else - #include "pcg_uint128.hpp" - namespace pcg_extras { - typedef pcg_extras::uint_x4 pcg128_t; - } - #define PCG_128BIT_CONSTANT(high,low) \ - pcg_extras::pcg128_t(high,low) - #define PCG_EMULATED_128BIT_MATH 1 -#endif - - -namespace pcg_extras { - -/* - * We often need to represent a "number of bits". When used normally, these - * numbers are never greater than 128, so an unsigned char is plenty. - * If you're using a nonstandard generator of a larger size, you can set - * PCG_BITCOUNT_T to have it define it as a larger size. (Some compilers - * might produce faster code if you set it to an unsigned int.) - */ - -#ifndef PCG_BITCOUNT_T - typedef uint8_t bitcount_t; -#else - typedef PCG_BITCOUNT_T bitcount_t; -#endif - -/* - * C++ requires us to be able to serialize RNG state by printing or reading - * it from a stream. Because we use 128-bit ints, we also need to be able - * ot print them, so here is code to do so. - * - * This code provides enough functionality to print 128-bit ints in decimal - * and zero-padded in hex. It's not a full-featured implementation. - */ - -template -std::basic_ostream& -operator<<(std::basic_ostream& out, pcg128_t value) -{ - auto desired_base = out.flags() & out.basefield; - bool want_hex = desired_base == out.hex; - - if (want_hex) { - uint64_t highpart = uint64_t(value >> 64); - uint64_t lowpart = uint64_t(value); - auto desired_width = out.width(); - if (desired_width > 16) { - out.width(desired_width - 16); - } - if (highpart != 0 || desired_width > 16) - out << highpart; - CharT oldfill = '\0'; - if (highpart != 0) { - out.width(16); - oldfill = out.fill('0'); - } - auto oldflags = out.setf(decltype(desired_base){}, out.showbase); - out << lowpart; - out.setf(oldflags); - if (highpart != 0) { - out.fill(oldfill); - } - return out; - } - constexpr size_t MAX_CHARS_128BIT = 40; - - char buffer[MAX_CHARS_128BIT]; - char* pos = buffer+sizeof(buffer); - *(--pos) = '\0'; - constexpr auto BASE = pcg128_t(10ULL); - do { - auto div = value / BASE; - auto mod = uint32_t(value - (div * BASE)); - *(--pos) = '0' + char(mod); - value = div; - } while(value != pcg128_t(0ULL)); - return out << pos; -} - -template -std::basic_istream& -operator>>(std::basic_istream& in, pcg128_t& value) -{ - typename std::basic_istream::sentry s(in); - - if (!s) - return in; - - constexpr auto BASE = pcg128_t(10ULL); - pcg128_t current(0ULL); - bool did_nothing = true; - bool overflow = false; - for(;;) { - CharT wide_ch = in.get(); - if (!in.good()) { - in.clear(std::ios::eofbit); - break; - } - auto ch = in.narrow(wide_ch, '\0'); - if (ch < '0' || ch > '9') { - in.unget(); - break; - } - did_nothing = false; - pcg128_t digit(uint32_t(ch - '0')); - pcg128_t timesbase = current*BASE; - overflow = overflow || timesbase < current; - current = timesbase + digit; - overflow = overflow || current < digit; - } - - if (did_nothing || overflow) { - in.setstate(std::ios::failbit); - if (overflow) - current = ~pcg128_t(0ULL); - } - - value = current; - - return in; -} - -/* - * Likewise, if people use tiny rngs, we'll be serializing uint8_t. - * If we just used the provided IO operators, they'd read/write chars, - * not ints, so we need to define our own. We *can* redefine this operator - * here because we're in our own namespace. - */ - -template -std::basic_ostream& -operator<<(std::basic_ostream&out, uint8_t value) -{ - return out << uint32_t(value); -} - -template -std::basic_istream& -operator>>(std::basic_istream& in, uint8_t& target) -{ - uint32_t value = 0xdecea5edU; - in >> value; - if (!in && value == 0xdecea5edU) - return in; - if (value > uint8_t(~0)) { - in.setstate(std::ios::failbit); - value = ~0U; - } - target = uint8_t(value); - return in; -} - -/* Unfortunately, the above functions don't get found in preference to the - * built in ones, so we create some more specific overloads that will. - * Ugh. - */ - -inline std::ostream& operator<<(std::ostream& out, uint8_t value) -{ - return pcg_extras::operator<< (out, value); -} - -inline std::istream& operator>>(std::istream& in, uint8_t& value) -{ - return pcg_extras::operator>> (in, value); -} - - - -/* - * Useful bitwise operations. - */ - -/* - * XorShifts are invertable, but they are someting of a pain to invert. - * This function backs them out. It's used by the whacky "inside out" - * generator defined later. - */ - -template -inline itype unxorshift(itype x, bitcount_t bits, bitcount_t shift) -{ - if (2*shift >= bits) { - return x ^ (x >> shift); - } - itype lowmask1 = (itype(1U) << (bits - shift*2)) - 1; - itype highmask1 = ~lowmask1; - itype top1 = x; - itype bottom1 = x & lowmask1; - top1 ^= top1 >> shift; - top1 &= highmask1; - x = top1 | bottom1; - itype lowmask2 = (itype(1U) << (bits - shift)) - 1; - itype bottom2 = x & lowmask2; - bottom2 = unxorshift(bottom2, bits - shift, shift); - bottom2 &= lowmask1; - return top1 | bottom2; -} - -/* - * Rotate left and right. - * - * In ideal world, compilers would spot idiomatic rotate code and convert it - * to a rotate instruction. Of course, opinions vary on what the correct - * idiom is and how to spot it. For clang, sometimes it generates better - * (but still crappy) code if you define PCG_USE_ZEROCHECK_ROTATE_IDIOM. - */ - -template -inline itype rotl(itype value, bitcount_t rot) -{ - constexpr bitcount_t bits = sizeof(itype) * 8; - constexpr bitcount_t mask = bits - 1; -#if PCG_USE_ZEROCHECK_ROTATE_IDIOM - return rot ? (value << rot) | (value >> (bits - rot)) : value; -#else - return (value << rot) | (value >> ((- rot) & mask)); -#endif -} - -template -inline itype rotr(itype value, bitcount_t rot) -{ - constexpr bitcount_t bits = sizeof(itype) * 8; - constexpr bitcount_t mask = bits - 1; -#if PCG_USE_ZEROCHECK_ROTATE_IDIOM - return rot ? (value >> rot) | (value << (bits - rot)) : value; -#else - return (value >> rot) | (value << ((- rot) & mask)); -#endif -} - -/* Unfortunately, both Clang and GCC sometimes perform poorly when it comes - * to properly recognizing idiomatic rotate code, so for we also provide - * assembler directives (enabled with PCG_USE_INLINE_ASM). Boo, hiss. - * (I hope that these compilers get better so that this code can die.) - * - * These overloads will be preferred over the general template code above. - */ -#if PCG_USE_INLINE_ASM && __GNUC__ && (__x86_64__ || __i386__) - -inline uint8_t rotr(uint8_t value, bitcount_t rot) -{ - asm ("rorb %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); - return value; -} - -inline uint16_t rotr(uint16_t value, bitcount_t rot) -{ - asm ("rorw %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); - return value; -} - -inline uint32_t rotr(uint32_t value, bitcount_t rot) -{ - asm ("rorl %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); - return value; -} - -#if __x86_64__ -inline uint64_t rotr(uint64_t value, bitcount_t rot) -{ - asm ("rorq %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); - return value; -} -#endif // __x86_64__ - -#elif defined(_MSC_VER) - // Use MSVC++ bit rotation intrinsics - -#pragma intrinsic(_rotr, _rotr64, _rotr8, _rotr16) - -inline uint8_t rotr(uint8_t value, bitcount_t rot) -{ - return _rotr8(value, rot); -} - -inline uint16_t rotr(uint16_t value, bitcount_t rot) -{ - return _rotr16(value, rot); -} - -inline uint32_t rotr(uint32_t value, bitcount_t rot) -{ - return _rotr(value, rot); -} - -inline uint64_t rotr(uint64_t value, bitcount_t rot) -{ - return _rotr64(value, rot); -} - -#endif // PCG_USE_INLINE_ASM - - -/* - * The C++ SeedSeq concept (modelled by seed_seq) can fill an array of - * 32-bit integers with seed data, but sometimes we want to produce - * larger or smaller integers. - * - * The following code handles this annoyance. - * - * uneven_copy will copy an array of 32-bit ints to an array of larger or - * smaller ints (actually, the code is general it only needing forward - * iterators). The copy is identical to the one that would be performed if - * we just did memcpy on a standard little-endian machine, but works - * regardless of the endian of the machine (or the weirdness of the ints - * involved). - * - * generate_to initializes an array of integers using a SeedSeq - * object. It is given the size as a static constant at compile time and - * tries to avoid memory allocation. If we're filling in 32-bit constants - * we just do it directly. If we need a separate buffer and it's small, - * we allocate it on the stack. Otherwise, we fall back to heap allocation. - * Ugh. - * - * generate_one produces a single value of some integral type using a - * SeedSeq object. - */ - - /* uneven_copy helper, case where destination ints are less than 32 bit. */ - -template -SrcIter uneven_copy_impl( - SrcIter src_first, DestIter dest_first, DestIter dest_last, - std::true_type) -{ - typedef typename std::iterator_traits::value_type src_t; - typedef typename std::iterator_traits::value_type dest_t; - - constexpr bitcount_t SRC_SIZE = sizeof(src_t); - constexpr bitcount_t DEST_SIZE = sizeof(dest_t); - constexpr bitcount_t DEST_BITS = DEST_SIZE * 8; - constexpr bitcount_t SCALE = SRC_SIZE / DEST_SIZE; - - size_t count = 0; - src_t value = 0; - - while (dest_first != dest_last) { - if ((count++ % SCALE) == 0) - value = *src_first++; // Get more bits - else - value >>= DEST_BITS; // Move down bits - - *dest_first++ = dest_t(value); // Truncates, ignores high bits. - } - return src_first; -} - - /* uneven_copy helper, case where destination ints are more than 32 bit. */ - -template -SrcIter uneven_copy_impl( - SrcIter src_first, DestIter dest_first, DestIter dest_last, - std::false_type) -{ - typedef typename std::iterator_traits::value_type src_t; - typedef typename std::iterator_traits::value_type dest_t; - - constexpr auto SRC_SIZE = sizeof(src_t); - constexpr auto SRC_BITS = SRC_SIZE * 8; - constexpr auto DEST_SIZE = sizeof(dest_t); - constexpr auto SCALE = (DEST_SIZE+SRC_SIZE-1) / SRC_SIZE; - - while (dest_first != dest_last) { - dest_t value(0UL); - unsigned int shift = 0; - - for (size_t i = 0; i < SCALE; ++i) { - value |= dest_t(*src_first++) << shift; - shift += SRC_BITS; - } - - *dest_first++ = value; - } - return src_first; -} - -/* uneven_copy, call the right code for larger vs. smaller */ - -template -inline SrcIter uneven_copy(SrcIter src_first, - DestIter dest_first, DestIter dest_last) -{ - typedef typename std::iterator_traits::value_type src_t; - typedef typename std::iterator_traits::value_type dest_t; - - constexpr bool DEST_IS_SMALLER = sizeof(dest_t) < sizeof(src_t); - - return uneven_copy_impl(src_first, dest_first, dest_last, - std::integral_constant{}); -} - -/* generate_to, fill in a fixed-size array of integral type using a SeedSeq - * (actually works for any random-access iterator) - */ - -template -inline void generate_to_impl(SeedSeq&& generator, DestIter dest, - std::true_type) -{ - generator.generate(dest, dest+size); -} - -template -void generate_to_impl(SeedSeq&& generator, DestIter dest, - std::false_type) -{ - typedef typename std::iterator_traits::value_type dest_t; - constexpr auto DEST_SIZE = sizeof(dest_t); - constexpr auto GEN_SIZE = sizeof(uint32_t); - - constexpr bool GEN_IS_SMALLER = GEN_SIZE < DEST_SIZE; - constexpr size_t FROM_ELEMS = - GEN_IS_SMALLER - ? size * ((DEST_SIZE+GEN_SIZE-1) / GEN_SIZE) - : (size + (GEN_SIZE / DEST_SIZE) - 1) - / ((GEN_SIZE / DEST_SIZE) + GEN_IS_SMALLER); - // this odd code ^^^^^^^^^^^^^^^^^ is work-around for - // a bug: http://llvm.org/bugs/show_bug.cgi?id=21287 - - if (FROM_ELEMS <= 1024) { - uint32_t buffer[FROM_ELEMS]; - generator.generate(buffer, buffer+FROM_ELEMS); - uneven_copy(buffer, dest, dest+size); - } else { - uint32_t* buffer = static_cast(malloc(GEN_SIZE * FROM_ELEMS)); - generator.generate(buffer, buffer+FROM_ELEMS); - uneven_copy(buffer, dest, dest+size); - free(static_cast(buffer)); - } -} - -template -inline void generate_to(SeedSeq&& generator, DestIter dest) -{ - typedef typename std::iterator_traits::value_type dest_t; - constexpr bool IS_32BIT = sizeof(dest_t) == sizeof(uint32_t); - - generate_to_impl(std::forward(generator), dest, - std::integral_constant{}); -} - -/* generate_one, produce a value of integral type using a SeedSeq - * (optionally, we can have it produce more than one and pick which one - * we want) - */ - -template -inline UInt generate_one(SeedSeq&& generator) -{ - UInt result[N]; - generate_to(std::forward(generator), result); - return result[i]; -} - -template -auto bounded_rand(RngType& rng, typename RngType::result_type upper_bound) - -> typename RngType::result_type -{ - typedef typename RngType::result_type rtype; - rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound) - % upper_bound; - for (;;) { - rtype r = rng() - RngType::min(); - if (r >= threshold) - return r % upper_bound; - } -} - -template -void shuffle(Iter from, Iter to, RandType&& rng) -{ - typedef typename std::iterator_traits::difference_type delta_t; - typedef typename std::remove_reference::type::result_type result_t; - auto count = to - from; - while (count > 1) { - delta_t chosen = delta_t(bounded_rand(rng, result_t(count))); - --count; - --to; - using std::swap; - swap(*(from + chosen), *to); - } -} - -/* - * Although std::seed_seq is useful, it isn't everything. Often we want to - * initialize a random-number generator some other way, such as from a random - * device. - * - * Technically, it does not meet the requirements of a SeedSequence because - * it lacks some of the rarely-used member functions (some of which would - * be impossible to provide). However the C++ standard is quite specific - * that actual engines only called the generate method, so it ought not to be - * a problem in practice. - */ - -template -class seed_seq_from { -private: - RngType rng_; - - typedef uint_least32_t result_type; - -public: - template - seed_seq_from(Args&&... args) : - rng_(std::forward(args)...) - { - // Nothing (else) to do... - } - - template - void generate(Iter start, Iter finish) - { - for (auto i = start; i != finish; ++i) - *i = result_type(rng_()); - } - - constexpr size_t size() const - { - return (sizeof(typename RngType::result_type) > sizeof(result_type) - && RngType::max() > ~size_t(0UL)) - ? ~size_t(0UL) - : size_t(RngType::max()); - } -}; - -/* - * Sometimes you might want a distinct seed based on when the program - * was compiled. That way, a particular instance of the program will - * behave the same way, but when recompiled it'll produce a different - * value. - */ - -template -struct static_arbitrary_seed { -private: - static constexpr IntType fnv(IntType hash, const char* pos) { - return *pos == '\0' - ? hash - : fnv((hash * IntType(16777619U)) ^ *pos, (pos+1)); - } - -public: - static constexpr IntType value = fnv(IntType(2166136261U ^ sizeof(IntType)), - __DATE__ __TIME__ __FILE__); -}; - -// Sometimes, when debugging or testing, it's handy to be able print the name -// of a (in human-readable form). This code allows the idiom: -// -// cout << printable_typename() -// -// to print out my_foo_type_t (or its concrete type if it is a synonym) - -#if __cpp_rtti || __GXX_RTTI - -template -struct printable_typename {}; - -template -std::ostream& operator<<(std::ostream& out, printable_typename) { - const char *implementation_typename = typeid(T).name(); -#ifdef __GNUC__ - int status; - char* pretty_name = - abi::__cxa_demangle(implementation_typename, nullptr, nullptr, &status); - if (status == 0) - out << pretty_name; - free(static_cast(pretty_name)); - if (status == 0) - return out; -#endif - out << implementation_typename; - return out; -} - -#endif // __cpp_rtti || __GXX_RTTI - -} // namespace pcg_extras - -#endif // PCG_EXTRAS_HPP_INCLUDED diff --git a/include/pcg_random.hpp b/include/pcg_random.hpp deleted file mode 100644 index d479a81..0000000 --- a/include/pcg_random.hpp +++ /dev/null @@ -1,1951 +0,0 @@ -/* - * PCG Random Number Generation for C++ - * - * Copyright 2014-2022 Melissa O'Neill , - * and the PCG Project contributors. - * - * SPDX-License-Identifier: (Apache-2.0 OR MIT) - * - * Licensed under the Apache License, Version 2.0 (provided in - * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0) - * or under the MIT license (provided in LICENSE-MIT.txt and at - * http://opensource.org/licenses/MIT), at your option. This file may not - * be copied, modified, or distributed except according to those terms. - * - * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See your chosen license for details. - * - * For additional information about the PCG random number generation scheme, - * visit http://www.pcg-random.org/. - */ - -/* - * This code provides the reference implementation of the PCG family of - * random number generators. The code is complex because it implements - * - * - several members of the PCG family, specifically members corresponding - * to the output functions: - * - XSH RR (good for 64-bit state, 32-bit output) - * - XSH RS (good for 64-bit state, 32-bit output) - * - XSL RR (good for 128-bit state, 64-bit output) - * - RXS M XS (statistically most powerful generator) - * - XSL RR RR (good for 128-bit state, 128-bit output) - * - and RXS, RXS M, XSH, XSL (mostly for testing) - * - at potentially *arbitrary* bit sizes - * - with four different techniques for random streams (MCG, one-stream - * LCG, settable-stream LCG, unique-stream LCG) - * - and the extended generation schemes allowing arbitrary periods - * - with all features of C++11 random number generation (and more), - * some of which are somewhat painful, including - * - initializing with a SeedSequence which writes 32-bit values - * to memory, even though the state of the generator may not - * use 32-bit values (it might use smaller or larger integers) - * - I/O for RNGs and a prescribed format, which needs to handle - * the issue that 8-bit and 128-bit integers don't have working - * I/O routines (e.g., normally 8-bit = char, not integer) - * - equality and inequality for RNGs - * - and a number of convenience typedefs to mask all the complexity - * - * The code employees a fairly heavy level of abstraction, and has to deal - * with various C++ minutia. If you're looking to learn about how the PCG - * scheme works, you're probably best of starting with one of the other - * codebases (see www.pcg-random.org). But if you're curious about the - * constants for the various output functions used in those other, simpler, - * codebases, this code shows how they are calculated. - * - * On the positive side, at least there are convenience typedefs so that you - * can say - * - * pcg32 myRNG; - * - * rather than: - * - * pcg_detail::engine< - * uint32_t, // Output Type - * uint64_t, // State Type - * pcg_detail::xsh_rr_mixin, true, // Output Func - * pcg_detail::specific_stream, // Stream Kind - * pcg_detail::default_multiplier // LCG Mult - * > myRNG; - * - */ - -#ifndef PCG_RAND_HPP_INCLUDED -#define PCG_RAND_HPP_INCLUDED 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER - #pragma warning(disable:4146) -#endif - -#ifdef _MSC_VER - #define PCG_ALWAYS_INLINE __forceinline -#elif __GNUC__ - #define PCG_ALWAYS_INLINE __attribute__((always_inline)) -#else - #define PCG_ALWAYS_INLINE inline -#endif - -/* - * The pcg_extras namespace contains some support code that is likely to - * be useful for a variety of RNGs, including: - * - 128-bit int support for platforms where it isn't available natively - * - bit twiddling operations - * - I/O of 128-bit and 8-bit integers - * - Handling the evilness of SeedSeq - * - Support for efficiently producing random numbers less than a given - * bound - */ - -#include "pcg_extras.hpp" - -namespace pcg_detail { - -using namespace pcg_extras; - -/* - * The LCG generators need some constants to function. This code lets you - * look up the constant by *type*. For example - * - * default_multiplier::multiplier() - * - * gives you the default multiplier for 32-bit integers. We use the name - * of the constant and not a generic word like value to allow these classes - * to be used as mixins. - */ - -template -struct default_multiplier { - // Not defined for an arbitrary type -}; - -template -struct default_increment { - // Not defined for an arbitrary type -}; - -#define PCG_DEFINE_CONSTANT(type, what, kind, constant) \ - template <> \ - struct what ## _ ## kind { \ - static constexpr type kind() { \ - return constant; \ - } \ - }; - -PCG_DEFINE_CONSTANT(uint8_t, default, multiplier, 141U) -PCG_DEFINE_CONSTANT(uint8_t, default, increment, 77U) - -PCG_DEFINE_CONSTANT(uint16_t, default, multiplier, 12829U) -PCG_DEFINE_CONSTANT(uint16_t, default, increment, 47989U) - -PCG_DEFINE_CONSTANT(uint32_t, default, multiplier, 747796405U) -PCG_DEFINE_CONSTANT(uint32_t, default, increment, 2891336453U) - -PCG_DEFINE_CONSTANT(uint64_t, default, multiplier, 6364136223846793005ULL) -PCG_DEFINE_CONSTANT(uint64_t, default, increment, 1442695040888963407ULL) - -PCG_DEFINE_CONSTANT(pcg128_t, default, multiplier, - PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL)) -PCG_DEFINE_CONSTANT(pcg128_t, default, increment, - PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL)) - -/* Alternative (cheaper) multipliers for 128-bit */ - -template -struct cheap_multiplier : public default_multiplier { - // For most types just use the default. -}; - -template <> -struct cheap_multiplier { - static constexpr uint64_t multiplier() { - return 0xda942042e4dd58b5ULL; - } -}; - - -/* - * Each PCG generator is available in four variants, based on how it applies - * the additive constant for its underlying LCG; the variations are: - * - * single stream - all instances use the same fixed constant, thus - * the RNG always somewhere in same sequence - * mcg - adds zero, resulting in a single stream and reduced - * period - * specific stream - the constant can be changed at any time, selecting - * a different random sequence - * unique stream - the constant is based on the memory address of the - * object, thus every RNG has its own unique sequence - * - * This variation is provided though mixin classes which define a function - * value called increment() that returns the necessary additive constant. - */ - - - -/* - * unique stream - */ - - -template -class unique_stream { -protected: - static constexpr bool is_mcg = false; - - // Is never called, but is provided for symmetry with specific_stream - void set_stream(...) - { - abort(); - } - -public: - typedef itype state_type; - - constexpr itype increment() const { - return itype(reinterpret_cast(this) | 1); - } - - constexpr itype stream() const - { - return increment() >> 1; - } - - static constexpr bool can_specify_stream = false; - - static constexpr size_t streams_pow2() - { - return (sizeof(itype) < sizeof(size_t) ? sizeof(itype) - : sizeof(size_t))*8 - 1u; - } - -protected: - constexpr unique_stream() = default; -}; - - -/* - * no stream (mcg) - */ - -template -class no_stream { -protected: - static constexpr bool is_mcg = true; - - // Is never called, but is provided for symmetry with specific_stream - void set_stream(...) - { - abort(); - } - -public: - typedef itype state_type; - - static constexpr itype increment() { - return 0; - } - - static constexpr bool can_specify_stream = false; - - static constexpr size_t streams_pow2() - { - return 0u; - } - -protected: - constexpr no_stream() = default; -}; - - -/* - * single stream/sequence (oneseq) - */ - -template -class oneseq_stream : public default_increment { -protected: - static constexpr bool is_mcg = false; - - // Is never called, but is provided for symmetry with specific_stream - void set_stream(...) - { - abort(); - } - -public: - typedef itype state_type; - - static constexpr itype stream() - { - return default_increment::increment() >> 1; - } - - static constexpr bool can_specify_stream = false; - - static constexpr size_t streams_pow2() - { - return 0u; - } - -protected: - constexpr oneseq_stream() = default; -}; - - -/* - * specific stream - */ - -template -class specific_stream { -protected: - static constexpr bool is_mcg = false; - - itype inc_ = default_increment::increment(); - -public: - typedef itype state_type; - typedef itype stream_state; - - constexpr itype increment() const { - return inc_; - } - - itype stream() - { - return inc_ >> 1; - } - - void set_stream(itype specific_seq) - { - inc_ = (specific_seq << 1) | 1; - } - - static constexpr bool can_specify_stream = true; - - static constexpr size_t streams_pow2() - { - return (sizeof(itype)*8) - 1u; - } - -protected: - specific_stream() = default; - - specific_stream(itype specific_seq) - : inc_(itype(specific_seq << 1) | itype(1U)) - { - // Nothing (else) to do. - } -}; - - -/* - * This is where it all comes together. This function joins together three - * mixin classes which define - * - the LCG additive constant (the stream) - * - the LCG multiplier - * - the output function - * in addition, we specify the type of the LCG state, and the result type, - * and whether to use the pre-advance version of the state for the output - * (increasing instruction-level parallelism) or the post-advance version - * (reducing register pressure). - * - * Given the high level of parameterization, the code has to use some - * template-metaprogramming tricks to handle some of the subtle variations - * involved. - */ - -template , - typename multiplier_mixin = default_multiplier > -class engine : protected output_mixin, - public stream_mixin, - protected multiplier_mixin { -protected: - itype state_; - - struct can_specify_stream_tag {}; - struct no_specifiable_stream_tag {}; - - using stream_mixin::increment; - using multiplier_mixin::multiplier; - -public: - typedef xtype result_type; - typedef itype state_type; - - static constexpr size_t period_pow2() - { - return sizeof(state_type)*8 - 2*stream_mixin::is_mcg; - } - - // It would be nice to use std::numeric_limits for these, but - // we can't be sure that it'd be defined for the 128-bit types. - - static constexpr result_type min() - { - return result_type(0UL); - } - - static constexpr result_type max() - { - return result_type(~result_type(0UL)); - } - -protected: - itype bump(itype state) - { - return state * multiplier() + increment(); - } - - itype base_generate() - { - return state_ = bump(state_); - } - - itype base_generate0() - { - itype old_state = state_; - state_ = bump(state_); - return old_state; - } - -public: - result_type operator()() - { - if (output_previous) - return this->output(base_generate0()); - else - return this->output(base_generate()); - } - - result_type operator()(result_type upper_bound) - { - return bounded_rand(*this, upper_bound); - } - -protected: - static itype advance(itype state, itype delta, - itype cur_mult, itype cur_plus); - - static itype distance(itype cur_state, itype newstate, itype cur_mult, - itype cur_plus, itype mask = ~itype(0U)); - - itype distance(itype newstate, itype mask = itype(~itype(0U))) const - { - return distance(state_, newstate, multiplier(), increment(), mask); - } - -public: - void advance(itype delta) - { - state_ = advance(state_, delta, this->multiplier(), this->increment()); - } - - void backstep(itype delta) - { - advance(-delta); - } - - void discard(itype delta) - { - advance(delta); - } - - bool wrapped() - { - if (stream_mixin::is_mcg) { - // For MCGs, the low order two bits never change. In this - // implementation, we keep them fixed at 3 to make this test - // easier. - return state_ == 3; - } else { - return state_ == 0; - } - } - - engine(itype state = itype(0xcafef00dd15ea5e5ULL)) - : state_(this->is_mcg ? state|state_type(3U) - : bump(state + this->increment())) - { - // Nothing else to do. - } - - // This function may or may not exist. It thus has to be a template - // to use SFINAE; users don't have to worry about its template-ness. - - template - engine(itype state, typename sm::stream_state stream_seed) - : stream_mixin(stream_seed), - state_(this->is_mcg ? state|state_type(3U) - : bump(state + this->increment())) - { - // Nothing else to do. - } - - template - engine(SeedSeq&& seedSeq, typename std::enable_if< - !stream_mixin::can_specify_stream - && !std::is_convertible::value - && !std::is_convertible::value, - no_specifiable_stream_tag>::type = {}) - : engine(generate_one(std::forward(seedSeq))) - { - // Nothing else to do. - } - - template - engine(SeedSeq&& seedSeq, typename std::enable_if< - stream_mixin::can_specify_stream - && !std::is_convertible::value - && !std::is_convertible::value, - can_specify_stream_tag>::type = {}) - { - itype seeddata[2]; - generate_to<2>(std::forward(seedSeq), seeddata); - seed(seeddata[1], seeddata[0]); - } - - - template - void seed(Args&&... args) - { - new (this) engine(std::forward(args)...); - } - - template - friend bool operator==(const engine&, - const engine&); - - template - friend itype1 operator-(const engine&, - const engine&); - - template - friend std::basic_ostream& - operator<<(std::basic_ostream& out, - const engine&); - - template - friend std::basic_istream& - operator>>(std::basic_istream& in, - engine& rng); -}; - -template -std::basic_ostream& -operator<<(std::basic_ostream& out, - const engine& rng) -{ - using pcg_extras::operator<<; - - auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left); - auto space = out.widen(' '); - auto orig_fill = out.fill(); - - out << rng.multiplier() << space - << rng.increment() << space - << rng.state_; - - out.flags(orig_flags); - out.fill(orig_fill); - return out; -} - - -template -std::basic_istream& -operator>>(std::basic_istream& in, - engine& rng) -{ - using pcg_extras::operator>>; - - auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws); - - itype multiplier, increment, state; - in >> multiplier >> increment >> state; - - if (!in.fail()) { - bool good = true; - if (multiplier != rng.multiplier()) { - good = false; - } else if (rng.can_specify_stream) { - rng.set_stream(increment >> 1); - } else if (increment != rng.increment()) { - good = false; - } - if (good) { - rng.state_ = state; - } else { - in.clear(std::ios::failbit); - } - } - - in.flags(orig_flags); - return in; -} - - -template -itype engine::advance( - itype state, itype delta, itype cur_mult, itype cur_plus) -{ - // The method used here is based on Brown, "Random Number Generation - // with Arbitrary Stride,", Transactions of the American Nuclear - // Society (Nov. 1994). The algorithm is very similar to fast - // exponentiation. - // - // Even though delta is an unsigned integer, we can pass a - // signed integer to go backwards, it just goes "the long way round". - - constexpr itype ZERO = 0u; // itype may be a non-trivial types, so - constexpr itype ONE = 1u; // we define some ugly constants. - itype acc_mult = 1; - itype acc_plus = 0; - while (delta > ZERO) { - if (delta & ONE) { - acc_mult *= cur_mult; - acc_plus = acc_plus*cur_mult + cur_plus; - } - cur_plus = (cur_mult+ONE)*cur_plus; - cur_mult *= cur_mult; - delta >>= 1; - } - return acc_mult * state + acc_plus; -} - -template -itype engine::distance( - itype cur_state, itype newstate, itype cur_mult, itype cur_plus, itype mask) -{ - constexpr itype ONE = 1u; // itype could be weird, so use constant - bool is_mcg = cur_plus == itype(0); - itype the_bit = is_mcg ? itype(4u) : itype(1u); - itype distance = 0u; - while ((cur_state & mask) != (newstate & mask)) { - if ((cur_state & the_bit) != (newstate & the_bit)) { - cur_state = cur_state * cur_mult + cur_plus; - distance |= the_bit; - } - assert((cur_state & the_bit) == (newstate & the_bit)); - the_bit <<= 1; - cur_plus = (cur_mult+ONE)*cur_plus; - cur_mult *= cur_mult; - } - return is_mcg ? distance >> 2 : distance; -} - -template -itype operator-(const engine& lhs, - const engine& rhs) -{ - static_assert( - std::is_same::value && - std::is_same::value, - "Incomparable generators"); - if (lhs.increment() == rhs.increment()) { - return rhs.distance(lhs.state_); - } else { - constexpr itype ONE = 1u; - itype lhs_diff = lhs.increment() + (lhs.multiplier()-ONE) * lhs.state_; - itype rhs_diff = rhs.increment() + (rhs.multiplier()-ONE) * rhs.state_; - if ((lhs_diff & itype(3u)) != (rhs_diff & itype(3u))) { - rhs_diff = -rhs_diff; - } - return rhs.distance(rhs_diff, lhs_diff, rhs.multiplier(), itype(0u)); - } -} - - -template -bool operator==(const engine& lhs, - const engine& rhs) -{ - return (lhs.multiplier() == rhs.multiplier()) - && (lhs.increment() == rhs.increment()) - && (lhs.state_ == rhs.state_); -} - -template -inline bool operator!=(const engine& lhs, - const engine& rhs) -{ - return !operator==(lhs,rhs); -} - - -template class output_mixin, - bool output_previous = (sizeof(itype) <= 8), - template class multiplier_mixin = default_multiplier> -using oneseq_base = engine, output_previous, - oneseq_stream, - multiplier_mixin >; - -template class output_mixin, - bool output_previous = (sizeof(itype) <= 8), - template class multiplier_mixin = default_multiplier> -using unique_base = engine, output_previous, - unique_stream, - multiplier_mixin >; - -template class output_mixin, - bool output_previous = (sizeof(itype) <= 8), - template class multiplier_mixin = default_multiplier> -using setseq_base = engine, output_previous, - specific_stream, - multiplier_mixin >; - -template class output_mixin, - bool output_previous = (sizeof(itype) <= 8), - template class multiplier_mixin = default_multiplier> -using mcg_base = engine, output_previous, - no_stream, - multiplier_mixin >; - -/* - * OUTPUT FUNCTIONS. - * - * These are the core of the PCG generation scheme. They specify how to - * turn the base LCG's internal state into the output value of the final - * generator. - * - * They're implemented as mixin classes. - * - * All of the classes have code that is written to allow it to be applied - * at *arbitrary* bit sizes, although in practice they'll only be used at - * standard sizes supported by C++. - */ - -/* - * XSH RS -- high xorshift, followed by a random shift - * - * Fast. A good performer. - */ - -template -struct xsh_rs_mixin { - static xtype output(itype internal) - { - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); - constexpr bitcount_t sparebits = bits - xtypebits; - constexpr bitcount_t opbits = - sparebits-5 >= 64 ? 5 - : sparebits-4 >= 32 ? 4 - : sparebits-3 >= 16 ? 3 - : sparebits-2 >= 4 ? 2 - : sparebits-1 >= 1 ? 1 - : 0; - constexpr bitcount_t mask = (1 << opbits) - 1; - constexpr bitcount_t maxrandshift = mask; - constexpr bitcount_t topspare = opbits; - constexpr bitcount_t bottomspare = sparebits - topspare; - constexpr bitcount_t xshift = topspare + (xtypebits+maxrandshift)/2; - bitcount_t rshift = - opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; - internal ^= internal >> xshift; - xtype result = xtype(internal >> (bottomspare - maxrandshift + rshift)); - return result; - } -}; - -/* - * XSH RR -- high xorshift, followed by a random rotate - * - * Fast. A good performer. Slightly better statistically than XSH RS. - */ - -template -struct xsh_rr_mixin { - static xtype output(itype internal) - { - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype)*8); - constexpr bitcount_t sparebits = bits - xtypebits; - constexpr bitcount_t wantedopbits = - xtypebits >= 128 ? 7 - : xtypebits >= 64 ? 6 - : xtypebits >= 32 ? 5 - : xtypebits >= 16 ? 4 - : 3; - constexpr bitcount_t opbits = - sparebits >= wantedopbits ? wantedopbits - : sparebits; - constexpr bitcount_t amplifier = wantedopbits - opbits; - constexpr bitcount_t mask = (1 << opbits) - 1; - constexpr bitcount_t topspare = opbits; - constexpr bitcount_t bottomspare = sparebits - topspare; - constexpr bitcount_t xshift = (topspare + xtypebits)/2; - bitcount_t rot = opbits ? bitcount_t(internal >> (bits - opbits)) & mask - : 0; - bitcount_t amprot = (rot << amplifier) & mask; - internal ^= internal >> xshift; - xtype result = xtype(internal >> bottomspare); - result = rotr(result, amprot); - return result; - } -}; - -/* - * RXS -- random xorshift - */ - -template -struct rxs_mixin { -static xtype output_rxs(itype internal) - { - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype)*8); - constexpr bitcount_t shift = bits - xtypebits; - constexpr bitcount_t extrashift = (xtypebits - shift)/2; - bitcount_t rshift = shift > 64+8 ? (internal >> (bits - 6)) & 63 - : shift > 32+4 ? (internal >> (bits - 5)) & 31 - : shift > 16+2 ? (internal >> (bits - 4)) & 15 - : shift > 8+1 ? (internal >> (bits - 3)) & 7 - : shift > 4+1 ? (internal >> (bits - 2)) & 3 - : shift > 2+1 ? (internal >> (bits - 1)) & 1 - : 0; - internal ^= internal >> (shift + extrashift - rshift); - xtype result = internal >> rshift; - return result; - } -}; - -/* - * RXS M XS -- random xorshift, mcg multiply, fixed xorshift - * - * The most statistically powerful generator, but all those steps - * make it slower than some of the others. We give it the rottenest jobs. - * - * Because it's usually used in contexts where the state type and the - * result type are the same, it is a permutation and is thus invertable. - * We thus provide a function to invert it. This function is used to - * for the "inside out" generator used by the extended generator. - */ - -/* Defined type-based concepts for the multiplication step. They're actually - * all derived by truncating the 128-bit, which was computed to be a good - * "universal" constant. - */ - -template -struct mcg_multiplier { - // Not defined for an arbitrary type -}; - -template -struct mcg_unmultiplier { - // Not defined for an arbitrary type -}; - -PCG_DEFINE_CONSTANT(uint8_t, mcg, multiplier, 217U) -PCG_DEFINE_CONSTANT(uint8_t, mcg, unmultiplier, 105U) - -PCG_DEFINE_CONSTANT(uint16_t, mcg, multiplier, 62169U) -PCG_DEFINE_CONSTANT(uint16_t, mcg, unmultiplier, 28009U) - -PCG_DEFINE_CONSTANT(uint32_t, mcg, multiplier, 277803737U) -PCG_DEFINE_CONSTANT(uint32_t, mcg, unmultiplier, 2897767785U) - -PCG_DEFINE_CONSTANT(uint64_t, mcg, multiplier, 12605985483714917081ULL) -PCG_DEFINE_CONSTANT(uint64_t, mcg, unmultiplier, 15009553638781119849ULL) - -PCG_DEFINE_CONSTANT(pcg128_t, mcg, multiplier, - PCG_128BIT_CONSTANT(17766728186571221404ULL, 12605985483714917081ULL)) -PCG_DEFINE_CONSTANT(pcg128_t, mcg, unmultiplier, - PCG_128BIT_CONSTANT(14422606686972528997ULL, 15009553638781119849ULL)) - - -template -struct rxs_m_xs_mixin { - static xtype output(itype internal) - { - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t opbits = xtypebits >= 128 ? 6 - : xtypebits >= 64 ? 5 - : xtypebits >= 32 ? 4 - : xtypebits >= 16 ? 3 - : 2; - constexpr bitcount_t shift = bits - xtypebits; - constexpr bitcount_t mask = (1 << opbits) - 1; - bitcount_t rshift = - opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; - internal ^= internal >> (opbits + rshift); - internal *= mcg_multiplier::multiplier(); - xtype result = internal >> shift; - result ^= result >> ((2U*xtypebits+2U)/3U); - return result; - } - - static itype unoutput(itype internal) - { - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t opbits = bits >= 128 ? 6 - : bits >= 64 ? 5 - : bits >= 32 ? 4 - : bits >= 16 ? 3 - : 2; - constexpr bitcount_t mask = (1 << opbits) - 1; - - internal = unxorshift(internal, bits, (2U*bits+2U)/3U); - - internal *= mcg_unmultiplier::unmultiplier(); - - bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0; - internal = unxorshift(internal, bits, opbits + rshift); - - return internal; - } -}; - - -/* - * RXS M -- random xorshift, mcg multiply - */ - -template -struct rxs_m_mixin { - static xtype output(itype internal) - { - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t opbits = xtypebits >= 128 ? 6 - : xtypebits >= 64 ? 5 - : xtypebits >= 32 ? 4 - : xtypebits >= 16 ? 3 - : 2; - constexpr bitcount_t shift = bits - xtypebits; - constexpr bitcount_t mask = (1 << opbits) - 1; - bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0; - internal ^= internal >> (opbits + rshift); - internal *= mcg_multiplier::multiplier(); - xtype result = internal >> shift; - return result; - } -}; - - -/* - * DXSM -- double xorshift multiply - * - * This is a new, more powerful output permutation (added in 2019). It's - * a more comprehensive scrambling than RXS M, but runs faster on 128-bit - * types. Although primarily intended for use at large sizes, also works - * at smaller sizes as well. - * - * This permutation is similar to xorshift multiply hash functions, except - * that one of the multipliers is the LCG multiplier (to avoid needing to - * have a second constant) and the other is based on the low-order bits. - * This latter aspect means that the scrambling applied to the high bits - * depends on the low bits, and makes it (to my eye) impractical to back - * out the permutation without having the low-order bits. - */ - -template -struct dxsm_mixin { - inline xtype output(itype internal) - { - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); - constexpr bitcount_t itypebits = bitcount_t(sizeof(itype) * 8); - static_assert(xtypebits <= itypebits/2, - "Output type must be half the size of the state type."); - - xtype hi = xtype(internal >> (itypebits - xtypebits)); - xtype lo = xtype(internal); - - lo |= 1; - hi ^= hi >> (xtypebits/2); - hi *= xtype(cheap_multiplier::multiplier()); - hi ^= hi >> (3*(xtypebits/4)); - hi *= lo; - return hi; - } -}; - - -/* - * XSL RR -- fixed xorshift (to low bits), random rotate - * - * Useful for 128-bit types that are split across two CPU registers. - */ - -template -struct xsl_rr_mixin { - static xtype output(itype internal) - { - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t sparebits = bits - xtypebits; - constexpr bitcount_t wantedopbits = xtypebits >= 128 ? 7 - : xtypebits >= 64 ? 6 - : xtypebits >= 32 ? 5 - : xtypebits >= 16 ? 4 - : 3; - constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits - : sparebits; - constexpr bitcount_t amplifier = wantedopbits - opbits; - constexpr bitcount_t mask = (1 << opbits) - 1; - constexpr bitcount_t topspare = sparebits; - constexpr bitcount_t bottomspare = sparebits - topspare; - constexpr bitcount_t xshift = (topspare + xtypebits) / 2; - - bitcount_t rot = - opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; - bitcount_t amprot = (rot << amplifier) & mask; - internal ^= internal >> xshift; - xtype result = xtype(internal >> bottomspare); - result = rotr(result, amprot); - return result; - } -}; - - -/* - * XSL RR RR -- fixed xorshift (to low bits), random rotate (both parts) - * - * Useful for 128-bit types that are split across two CPU registers. - * If you really want an invertable 128-bit RNG, I guess this is the one. - */ - -template struct halfsize_trait {}; -template <> struct halfsize_trait { typedef uint64_t type; }; -template <> struct halfsize_trait { typedef uint32_t type; }; -template <> struct halfsize_trait { typedef uint16_t type; }; -template <> struct halfsize_trait { typedef uint8_t type; }; - -template -struct xsl_rr_rr_mixin { - typedef typename halfsize_trait::type htype; - - static itype output(itype internal) - { - constexpr bitcount_t htypebits = bitcount_t(sizeof(htype) * 8); - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t sparebits = bits - htypebits; - constexpr bitcount_t wantedopbits = htypebits >= 128 ? 7 - : htypebits >= 64 ? 6 - : htypebits >= 32 ? 5 - : htypebits >= 16 ? 4 - : 3; - constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits - : sparebits; - constexpr bitcount_t amplifier = wantedopbits - opbits; - constexpr bitcount_t mask = (1 << opbits) - 1; - constexpr bitcount_t topspare = sparebits; - constexpr bitcount_t xshift = (topspare + htypebits) / 2; - - bitcount_t rot = - opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; - bitcount_t amprot = (rot << amplifier) & mask; - internal ^= internal >> xshift; - htype lowbits = htype(internal); - lowbits = rotr(lowbits, amprot); - htype highbits = htype(internal >> topspare); - bitcount_t rot2 = lowbits & mask; - bitcount_t amprot2 = (rot2 << amplifier) & mask; - highbits = rotr(highbits, amprot2); - return (itype(highbits) << topspare) ^ itype(lowbits); - } -}; - - -/* - * XSH -- fixed xorshift (to high bits) - * - * You shouldn't use this at 64-bits or less. - */ - -template -struct xsh_mixin { - static xtype output(itype internal) - { - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t sparebits = bits - xtypebits; - constexpr bitcount_t topspare = 0; - constexpr bitcount_t bottomspare = sparebits - topspare; - constexpr bitcount_t xshift = (topspare + xtypebits) / 2; - - internal ^= internal >> xshift; - xtype result = internal >> bottomspare; - return result; - } -}; - -/* - * XSL -- fixed xorshift (to low bits) - * - * You shouldn't use this at 64-bits or less. - */ - -template -struct xsl_mixin { - inline xtype output(itype internal) - { - constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8); - constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8); - constexpr bitcount_t sparebits = bits - xtypebits; - constexpr bitcount_t topspare = sparebits; - constexpr bitcount_t bottomspare = sparebits - topspare; - constexpr bitcount_t xshift = (topspare + xtypebits) / 2; - - internal ^= internal >> xshift; - xtype result = internal >> bottomspare; - return result; - } -}; - - -/* ---- End of Output Functions ---- */ - - -template -struct inside_out : private baseclass { - inside_out() = delete; - - typedef typename baseclass::result_type result_type; - typedef typename baseclass::state_type state_type; - static_assert(sizeof(result_type) == sizeof(state_type), - "Require a RNG whose output function is a permutation"); - - static bool external_step(result_type& randval, size_t i) - { - state_type state = baseclass::unoutput(randval); - state = state * baseclass::multiplier() + baseclass::increment() - + state_type(i*2); - result_type result = baseclass::output(state); - randval = result; - state_type zero = - baseclass::is_mcg ? state & state_type(3U) : state_type(0U); - return result == zero; - } - - static bool external_advance(result_type& randval, size_t i, - result_type delta, bool forwards = true) - { - state_type state = baseclass::unoutput(randval); - state_type mult = baseclass::multiplier(); - state_type inc = baseclass::increment() + state_type(i*2); - state_type zero = - baseclass::is_mcg ? state & state_type(3U) : state_type(0U); - state_type dist_to_zero = baseclass::distance(state, zero, mult, inc); - bool crosses_zero = - forwards ? dist_to_zero <= delta - : (-dist_to_zero) <= delta; - if (!forwards) - delta = -delta; - state = baseclass::advance(state, delta, mult, inc); - randval = baseclass::output(state); - return crosses_zero; - } -}; - - -template -class extended : public baseclass { -public: - typedef typename baseclass::state_type state_type; - typedef typename baseclass::result_type result_type; - typedef inside_out insideout; - -private: - static constexpr bitcount_t rtypebits = sizeof(result_type)*8; - static constexpr bitcount_t stypebits = sizeof(state_type)*8; - - static constexpr bitcount_t tick_limit_pow2 = 64U; - - static constexpr size_t table_size = 1UL << table_pow2; - static constexpr size_t table_shift = stypebits - table_pow2; - static constexpr state_type table_mask = - (state_type(1U) << table_pow2) - state_type(1U); - - static constexpr bool may_tick = - (advance_pow2 < stypebits) && (advance_pow2 < tick_limit_pow2); - static constexpr size_t tick_shift = stypebits - advance_pow2; - static constexpr state_type tick_mask = - may_tick ? state_type( - (uint64_t(1) << (advance_pow2*may_tick)) - 1) - // ^-- stupidity to appease GCC warnings - : ~state_type(0U); - - static constexpr bool may_tock = stypebits < tick_limit_pow2; - - result_type data_[table_size]; - - PCG_NOINLINE void advance_table(); - - PCG_NOINLINE void advance_table(state_type delta, bool isForwards = true); - - result_type& get_extended_value() - { - state_type state = this->state_; - if (kdd && baseclass::is_mcg) { - // The low order bits of an MCG are constant, so drop them. - state >>= 2; - } - size_t index = kdd ? state & table_mask - : state >> table_shift; - - if (may_tick) { - bool tick = kdd ? (state & tick_mask) == state_type(0u) - : (state >> tick_shift) == state_type(0u); - if (tick) - advance_table(); - } - if (may_tock) { - bool tock = state == state_type(0u); - if (tock) - advance_table(); - } - return data_[index]; - } - -public: - static constexpr size_t period_pow2() - { - return baseclass::period_pow2() + table_size*extvalclass::period_pow2(); - } - - PCG_ALWAYS_INLINE result_type operator()() - { - result_type rhs = get_extended_value(); - result_type lhs = this->baseclass::operator()(); - return lhs ^ rhs; - } - - result_type operator()(result_type upper_bound) - { - return bounded_rand(*this, upper_bound); - } - - void set(result_type wanted) - { - result_type& rhs = get_extended_value(); - result_type lhs = this->baseclass::operator()(); - rhs = lhs ^ wanted; - } - - void advance(state_type distance, bool forwards = true); - - void backstep(state_type distance) - { - advance(distance, false); - } - - extended(const result_type* data) - : baseclass() - { - datainit(data); - } - - extended(const result_type* data, state_type seed) - : baseclass(seed) - { - datainit(data); - } - - // This function may or may not exist. It thus has to be a template - // to use SFINAE; users don't have to worry about its template-ness. - - template - extended(const result_type* data, state_type seed, - typename bc::stream_state stream_seed) - : baseclass(seed, stream_seed) - { - datainit(data); - } - - extended() - : baseclass() - { - selfinit(); - } - - extended(state_type seed) - : baseclass(seed) - { - selfinit(); - } - - // This function may or may not exist. It thus has to be a template - // to use SFINAE; users don't have to worry about its template-ness. - - template - extended(state_type seed, typename bc::stream_state stream_seed) - : baseclass(seed, stream_seed) - { - selfinit(); - } - -private: - void selfinit(); - void datainit(const result_type* data); - -public: - - template::value - && !std::is_convertible::value>::type> - extended(SeedSeq&& seedSeq) - : baseclass(seedSeq) - { - generate_to(seedSeq, data_); - } - - template - void seed(Args&&... args) - { - new (this) extended(std::forward(args)...); - } - - template - friend bool operator==(const extended&, - const extended&); - - template - friend std::basic_ostream& - operator<<(std::basic_ostream& out, - const extended&); - - template - friend std::basic_istream& - operator>>(std::basic_istream& in, - extended&); - -}; - - -template -void extended::datainit( - const result_type* data) -{ - for (size_t i = 0; i < table_size; ++i) - data_[i] = data[i]; -} - -template -void extended::selfinit() -{ - // We need to fill the extended table with something, and we have - // very little provided data, so we use the base generator to - // produce values. Although not ideal (use a seed sequence, folks!), - // unexpected correlations are mitigated by - // - using XOR differences rather than the number directly - // - the way the table is accessed, its values *won't* be accessed - // in the same order the were written. - // - any strange correlations would only be apparent if we - // were to backstep the generator so that the base generator - // was generating the same values again - result_type lhs = baseclass::operator()(); - result_type rhs = baseclass::operator()(); - result_type xdiff = lhs - rhs; - for (size_t i = 0; i < table_size; ++i) { - data_[i] = baseclass::operator()() ^ xdiff; - } -} - -template -bool operator==(const extended& lhs, - const extended& rhs) -{ - auto& base_lhs = static_cast(lhs); - auto& base_rhs = static_cast(rhs); - return base_lhs == base_rhs - && std::equal( - std::begin(lhs.data_), std::end(lhs.data_), - std::begin(rhs.data_) - ); -} - -template -inline bool operator!=(const extended& lhs, - const extended& rhs) -{ - return !operator==(lhs, rhs); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& out, - const extended& rng) -{ - using pcg_extras::operator<<; - - auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left); - auto space = out.widen(' '); - auto orig_fill = out.fill(); - - out << rng.multiplier() << space - << rng.increment() << space - << rng.state_; - - for (const auto& datum : rng.data_) - out << space << datum; - - out.flags(orig_flags); - out.fill(orig_fill); - return out; -} - -template -std::basic_istream& -operator>>(std::basic_istream& in, - extended& rng) -{ - extended new_rng; - auto& base_rng = static_cast(new_rng); - in >> base_rng; - - if (in.fail()) - return in; - - using pcg_extras::operator>>; - - auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws); - - for (auto& datum : new_rng.data_) { - in >> datum; - if (in.fail()) - goto bail; - } - - rng = new_rng; - -bail: - in.flags(orig_flags); - return in; -} - - - -template -void -extended::advance_table() -{ - bool carry = false; - for (size_t i = 0; i < table_size; ++i) { - if (carry) { - carry = insideout::external_step(data_[i],i+1); - } - bool carry2 = insideout::external_step(data_[i],i+1); - carry = carry || carry2; - } -} - -template -void -extended::advance_table( - state_type delta, bool isForwards) -{ - typedef typename baseclass::state_type base_state_t; - typedef typename extvalclass::state_type ext_state_t; - constexpr bitcount_t basebits = sizeof(base_state_t)*8; - constexpr bitcount_t extbits = sizeof(ext_state_t)*8; - static_assert(basebits <= extbits || advance_pow2 > 0, - "Current implementation might overflow its carry"); - - base_state_t carry = 0; - for (size_t i = 0; i < table_size; ++i) { - base_state_t total_delta = carry + delta; - ext_state_t trunc_delta = ext_state_t(total_delta); - if (basebits > extbits) { - carry = total_delta >> extbits; - } else { - carry = 0; - } - carry += - insideout::external_advance(data_[i],i+1, trunc_delta, isForwards); - } -} - -template -void extended::advance( - state_type distance, bool forwards) -{ - static_assert(kdd, - "Efficient advance is too hard for non-kdd extension. " - "For a weak advance, cast to base class"); - state_type zero = - baseclass::is_mcg ? this->state_ & state_type(3U) : state_type(0U); - if (may_tick) { - state_type ticks = distance >> (advance_pow2*may_tick); - // ^-- stupidity to appease GCC - // warnings - state_type adv_mask = - baseclass::is_mcg ? tick_mask << 2 : tick_mask; - state_type next_advance_distance = this->distance(zero, adv_mask); - if (!forwards) - next_advance_distance = (-next_advance_distance) & tick_mask; - if (next_advance_distance < (distance & tick_mask)) { - ++ticks; - } - if (ticks) - advance_table(ticks, forwards); - } - if (forwards) { - if (may_tock && this->distance(zero) <= distance) - advance_table(); - baseclass::advance(distance); - } else { - if (may_tock && -(this->distance(zero)) <= distance) - advance_table(state_type(1U), false); - baseclass::advance(-distance); - } -} - -} // namespace pcg_detail - -namespace pcg_engines { - -using namespace pcg_detail; - -/* Predefined types for XSH RS */ - -typedef oneseq_base oneseq_xsh_rs_16_8; -typedef oneseq_base oneseq_xsh_rs_32_16; -typedef oneseq_base oneseq_xsh_rs_64_32; -typedef oneseq_base oneseq_xsh_rs_128_64; -typedef oneseq_base - cm_oneseq_xsh_rs_128_64; - -typedef unique_base unique_xsh_rs_16_8; -typedef unique_base unique_xsh_rs_32_16; -typedef unique_base unique_xsh_rs_64_32; -typedef unique_base unique_xsh_rs_128_64; -typedef unique_base - cm_unique_xsh_rs_128_64; - -typedef setseq_base setseq_xsh_rs_16_8; -typedef setseq_base setseq_xsh_rs_32_16; -typedef setseq_base setseq_xsh_rs_64_32; -typedef setseq_base setseq_xsh_rs_128_64; -typedef setseq_base - cm_setseq_xsh_rs_128_64; - -typedef mcg_base mcg_xsh_rs_16_8; -typedef mcg_base mcg_xsh_rs_32_16; -typedef mcg_base mcg_xsh_rs_64_32; -typedef mcg_base mcg_xsh_rs_128_64; -typedef mcg_base - cm_mcg_xsh_rs_128_64; - -/* Predefined types for XSH RR */ - -typedef oneseq_base oneseq_xsh_rr_16_8; -typedef oneseq_base oneseq_xsh_rr_32_16; -typedef oneseq_base oneseq_xsh_rr_64_32; -typedef oneseq_base oneseq_xsh_rr_128_64; -typedef oneseq_base - cm_oneseq_xsh_rr_128_64; - -typedef unique_base unique_xsh_rr_16_8; -typedef unique_base unique_xsh_rr_32_16; -typedef unique_base unique_xsh_rr_64_32; -typedef unique_base unique_xsh_rr_128_64; -typedef unique_base - cm_unique_xsh_rr_128_64; - -typedef setseq_base setseq_xsh_rr_16_8; -typedef setseq_base setseq_xsh_rr_32_16; -typedef setseq_base setseq_xsh_rr_64_32; -typedef setseq_base setseq_xsh_rr_128_64; -typedef setseq_base - cm_setseq_xsh_rr_128_64; - -typedef mcg_base mcg_xsh_rr_16_8; -typedef mcg_base mcg_xsh_rr_32_16; -typedef mcg_base mcg_xsh_rr_64_32; -typedef mcg_base mcg_xsh_rr_128_64; -typedef mcg_base - cm_mcg_xsh_rr_128_64; - - -/* Predefined types for RXS M XS */ - -typedef oneseq_base oneseq_rxs_m_xs_8_8; -typedef oneseq_base oneseq_rxs_m_xs_16_16; -typedef oneseq_base oneseq_rxs_m_xs_32_32; -typedef oneseq_base oneseq_rxs_m_xs_64_64; -typedef oneseq_base - oneseq_rxs_m_xs_128_128; -typedef oneseq_base - cm_oneseq_rxs_m_xs_128_128; - -typedef unique_base unique_rxs_m_xs_8_8; -typedef unique_base unique_rxs_m_xs_16_16; -typedef unique_base unique_rxs_m_xs_32_32; -typedef unique_base unique_rxs_m_xs_64_64; -typedef unique_base unique_rxs_m_xs_128_128; -typedef unique_base - cm_unique_rxs_m_xs_128_128; - -typedef setseq_base setseq_rxs_m_xs_8_8; -typedef setseq_base setseq_rxs_m_xs_16_16; -typedef setseq_base setseq_rxs_m_xs_32_32; -typedef setseq_base setseq_rxs_m_xs_64_64; -typedef setseq_base setseq_rxs_m_xs_128_128; -typedef setseq_base - cm_setseq_rxs_m_xs_128_128; - - // MCG versions don't make sense here, so aren't defined. - -/* Predefined types for RXS M */ - -typedef oneseq_base oneseq_rxs_m_16_8; -typedef oneseq_base oneseq_rxs_m_32_16; -typedef oneseq_base oneseq_rxs_m_64_32; -typedef oneseq_base oneseq_rxs_m_128_64; -typedef oneseq_base - cm_oneseq_rxs_m_128_64; - -typedef unique_base unique_rxs_m_16_8; -typedef unique_base unique_rxs_m_32_16; -typedef unique_base unique_rxs_m_64_32; -typedef unique_base unique_rxs_m_128_64; -typedef unique_base - cm_unique_rxs_m_128_64; - -typedef setseq_base setseq_rxs_m_16_8; -typedef setseq_base setseq_rxs_m_32_16; -typedef setseq_base setseq_rxs_m_64_32; -typedef setseq_base setseq_rxs_m_128_64; -typedef setseq_base - cm_setseq_rxs_m_128_64; - -typedef mcg_base mcg_rxs_m_16_8; -typedef mcg_base mcg_rxs_m_32_16; -typedef mcg_base mcg_rxs_m_64_32; -typedef mcg_base mcg_rxs_m_128_64; -typedef mcg_base - cm_mcg_rxs_m_128_64; - -/* Predefined types for DXSM */ - -typedef oneseq_base oneseq_dxsm_16_8; -typedef oneseq_base oneseq_dxsm_32_16; -typedef oneseq_base oneseq_dxsm_64_32; -typedef oneseq_base oneseq_dxsm_128_64; -typedef oneseq_base - cm_oneseq_dxsm_128_64; - -typedef unique_base unique_dxsm_16_8; -typedef unique_base unique_dxsm_32_16; -typedef unique_base unique_dxsm_64_32; -typedef unique_base unique_dxsm_128_64; -typedef unique_base - cm_unique_dxsm_128_64; - -typedef setseq_base setseq_dxsm_16_8; -typedef setseq_base setseq_dxsm_32_16; -typedef setseq_base setseq_dxsm_64_32; -typedef setseq_base setseq_dxsm_128_64; -typedef setseq_base - cm_setseq_dxsm_128_64; - -typedef mcg_base mcg_dxsm_16_8; -typedef mcg_base mcg_dxsm_32_16; -typedef mcg_base mcg_dxsm_64_32; -typedef mcg_base mcg_dxsm_128_64; -typedef mcg_base - cm_mcg_dxsm_128_64; - -/* Predefined types for XSL RR (only defined for "large" types) */ - -typedef oneseq_base oneseq_xsl_rr_64_32; -typedef oneseq_base oneseq_xsl_rr_128_64; -typedef oneseq_base - cm_oneseq_xsl_rr_128_64; - -typedef unique_base unique_xsl_rr_64_32; -typedef unique_base unique_xsl_rr_128_64; -typedef unique_base - cm_unique_xsl_rr_128_64; - -typedef setseq_base setseq_xsl_rr_64_32; -typedef setseq_base setseq_xsl_rr_128_64; -typedef setseq_base - cm_setseq_xsl_rr_128_64; - -typedef mcg_base mcg_xsl_rr_64_32; -typedef mcg_base mcg_xsl_rr_128_64; -typedef mcg_base - cm_mcg_xsl_rr_128_64; - - -/* Predefined types for XSL RR RR (only defined for "large" types) */ - -typedef oneseq_base - oneseq_xsl_rr_rr_64_64; -typedef oneseq_base - oneseq_xsl_rr_rr_128_128; -typedef oneseq_base - cm_oneseq_xsl_rr_rr_128_128; - -typedef unique_base - unique_xsl_rr_rr_64_64; -typedef unique_base - unique_xsl_rr_rr_128_128; -typedef unique_base - cm_unique_xsl_rr_rr_128_128; - -typedef setseq_base - setseq_xsl_rr_rr_64_64; -typedef setseq_base - setseq_xsl_rr_rr_128_128; -typedef setseq_base - cm_setseq_xsl_rr_rr_128_128; - - // MCG versions don't make sense here, so aren't defined. - -/* Extended generators */ - -template -using ext_std8 = extended; - -template -using ext_std16 = extended; - -template -using ext_std32 = extended; - -template -using ext_std64 = extended; - - -template -using ext_oneseq_rxs_m_xs_32_32 = - ext_std32; - -template -using ext_mcg_xsh_rs_64_32 = - ext_std32; - -template -using ext_oneseq_xsh_rs_64_32 = - ext_std32; - -template -using ext_setseq_xsh_rr_64_32 = - ext_std32; - -template -using ext_mcg_xsl_rr_128_64 = - ext_std64; - -template -using ext_oneseq_xsl_rr_128_64 = - ext_std64; - -template -using ext_setseq_xsl_rr_128_64 = - ext_std64; - -} // namespace pcg_engines - -typedef pcg_engines::setseq_xsh_rr_64_32 pcg32; -typedef pcg_engines::oneseq_xsh_rr_64_32 pcg32_oneseq; -typedef pcg_engines::unique_xsh_rr_64_32 pcg32_unique; -typedef pcg_engines::mcg_xsh_rs_64_32 pcg32_fast; - -typedef pcg_engines::setseq_xsl_rr_128_64 pcg64; -typedef pcg_engines::oneseq_xsl_rr_128_64 pcg64_oneseq; -typedef pcg_engines::unique_xsl_rr_128_64 pcg64_unique; -typedef pcg_engines::mcg_xsl_rr_128_64 pcg64_fast; - -typedef pcg_engines::setseq_rxs_m_xs_8_8 pcg8_once_insecure; -typedef pcg_engines::setseq_rxs_m_xs_16_16 pcg16_once_insecure; -typedef pcg_engines::setseq_rxs_m_xs_32_32 pcg32_once_insecure; -typedef pcg_engines::setseq_rxs_m_xs_64_64 pcg64_once_insecure; -typedef pcg_engines::setseq_xsl_rr_rr_128_128 pcg128_once_insecure; - -typedef pcg_engines::oneseq_rxs_m_xs_8_8 pcg8_oneseq_once_insecure; -typedef pcg_engines::oneseq_rxs_m_xs_16_16 pcg16_oneseq_once_insecure; -typedef pcg_engines::oneseq_rxs_m_xs_32_32 pcg32_oneseq_once_insecure; -typedef pcg_engines::oneseq_rxs_m_xs_64_64 pcg64_oneseq_once_insecure; -typedef pcg_engines::oneseq_xsl_rr_rr_128_128 pcg128_oneseq_once_insecure; - - -// These two extended RNGs provide two-dimensionally equidistributed -// 32-bit generators. pcg32_k2_fast occupies the same space as pcg64, -// and can be called twice to generate 64 bits, but does not required -// 128-bit math; on 32-bit systems, it's faster than pcg64 as well. - -typedef pcg_engines::ext_setseq_xsh_rr_64_32<1,16,true> pcg32_k2; -typedef pcg_engines::ext_oneseq_xsh_rs_64_32<1,32,true> pcg32_k2_fast; - -// These eight extended RNGs have about as much state as arc4random -// -// - the k variants are k-dimensionally equidistributed -// - the c variants offer are intended to be harder to predict -// -// (neither is intended for use in cryptographic applications) - -typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,true> pcg32_k64; -typedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,true> pcg32_k64_oneseq; -typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,true> pcg32_k64_fast; - -typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,false> pcg32_c64; -typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,false> pcg32_c64_oneseq; -typedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,false> pcg32_c64_fast; - -typedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,true> pcg64_k32; -typedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,true> pcg64_k32_oneseq; -typedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,true> pcg64_k32_fast; - -typedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,false> pcg64_c32; -typedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,false> pcg64_c32_oneseq; -typedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,false> pcg64_c32_fast; - -// These eight extended RNGs have more state than the Mersenne twister -// -// - the k variants are k-dimensionally equidistributed -// - the c variants offer are intended to be harder to predict -// -// (neither is intended for use in cryptographic applications) - -typedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,true> pcg32_k1024; -typedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,true> pcg32_k1024_fast; - -typedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,false> pcg32_c1024; -typedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,false> pcg32_c1024_fast; - -typedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,true> pcg64_k1024; -typedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,true> pcg64_k1024_fast; - -typedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,false> pcg64_c1024; -typedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,false> pcg64_c1024_fast; - -// These generators have an insanely huge period (2^524352), and is suitable -// for silly party tricks, such as dumping out 64 KB ZIP files at an arbitrary -// point in the future. [Actually, over the full period of the generator, it -// will produce every 64 KB ZIP file 2^64 times!] - -typedef pcg_engines::ext_setseq_xsh_rr_64_32<14,16,true> pcg32_k16384; -typedef pcg_engines::ext_oneseq_xsh_rs_64_32<14,32,true> pcg32_k16384_fast; - -#ifdef _MSC_VER - #pragma warning(default:4146) -#endif - -#endif // PCG_RAND_HPP_INCLUDED diff --git a/include/pcg_uint128.hpp b/include/pcg_uint128.hpp deleted file mode 100644 index 75c5699..0000000 --- a/include/pcg_uint128.hpp +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * PCG Random Number Generation for C++ - * - * Copyright 2014-2021 Melissa O'Neill , - * and the PCG Project contributors. - * - * SPDX-License-Identifier: (Apache-2.0 OR MIT) - * - * Licensed under the Apache License, Version 2.0 (provided in - * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0) - * or under the MIT license (provided in LICENSE-MIT.txt and at - * http://opensource.org/licenses/MIT), at your option. This file may not - * be copied, modified, or distributed except according to those terms. - * - * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either - * express or implied. See your chosen license for details. - * - * For additional information about the PCG random number generation scheme, - * visit http://www.pcg-random.org/. - */ - -/* - * This code provides a a C++ class that can provide 128-bit (or higher) - * integers. To produce 2K-bit integers, it uses two K-bit integers, - * placed in a union that allowes the code to also see them as four K/2 bit - * integers (and access them either directly name, or by index). - * - * It may seem like we're reinventing the wheel here, because several - * libraries already exist that support large integers, but most existing - * libraries provide a very generic multiprecision code, but here we're - * operating at a fixed size. Also, most other libraries are fairly - * heavyweight. So we use a direct implementation. Sadly, it's much slower - * than hand-coded assembly or direct CPU support. - */ - -#ifndef PCG_UINT128_HPP_INCLUDED -#define PCG_UINT128_HPP_INCLUDED 1 - -#include -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) // Use MSVC++ intrinsics -#include -#endif - -/* - * We want to lay the type out the same way that a native type would be laid - * out, which means we must know the machine's endian, at compile time. - * This ugliness attempts to do so. - */ - -#ifndef PCG_LITTLE_ENDIAN - #if defined(__BYTE_ORDER__) - #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - #define PCG_LITTLE_ENDIAN 1 - #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - #define PCG_LITTLE_ENDIAN 0 - #else - #error __BYTE_ORDER__ does not match a standard endian, pick a side - #endif - #elif __LITTLE_ENDIAN__ || _LITTLE_ENDIAN - #define PCG_LITTLE_ENDIAN 1 - #elif __BIG_ENDIAN__ || _BIG_ENDIAN - #define PCG_LITTLE_ENDIAN 0 - #elif __x86_64 || __x86_64__ || _M_X64 || __i386 || __i386__ || _M_IX86 - #define PCG_LITTLE_ENDIAN 1 - #elif __powerpc__ || __POWERPC__ || __ppc__ || __PPC__ \ - || __m68k__ || __mc68000__ - #define PCG_LITTLE_ENDIAN 0 - #else - #error Unable to determine target endianness - #endif -#endif - -#if INTPTR_MAX == INT64_MAX && !defined(PCG_64BIT_SPECIALIZATIONS) - #define PCG_64BIT_SPECIALIZATIONS 1 -#endif - -namespace pcg_extras { - -// Recent versions of GCC have intrinsics we can use to quickly calculate -// the number of leading and trailing zeros in a number. If possible, we -// use them, otherwise we fall back to old-fashioned bit twiddling to figure -// them out. - -#ifndef PCG_BITCOUNT_T - typedef uint8_t bitcount_t; -#else - typedef PCG_BITCOUNT_T bitcount_t; -#endif - -/* - * Provide some useful helper functions - * * flog2 floor(log2(x)) - * * trailingzeros number of trailing zero bits - */ - -#if defined(__GNUC__) // Any GNU-compatible compiler supporting C++11 has - // some useful intrinsics we can use. - -inline bitcount_t flog2(uint32_t v) -{ - return 31 - __builtin_clz(v); -} - -inline bitcount_t trailingzeros(uint32_t v) -{ - return __builtin_ctz(v); -} - -inline bitcount_t flog2(uint64_t v) -{ -#if UINT64_MAX == ULONG_MAX - return 63 - __builtin_clzl(v); -#elif UINT64_MAX == ULLONG_MAX - return 63 - __builtin_clzll(v); -#else - #error Cannot find a function for uint64_t -#endif -} - -inline bitcount_t trailingzeros(uint64_t v) -{ -#if UINT64_MAX == ULONG_MAX - return __builtin_ctzl(v); -#elif UINT64_MAX == ULLONG_MAX - return __builtin_ctzll(v); -#else - #error Cannot find a function for uint64_t -#endif -} - -#elif defined(_MSC_VER) // Use MSVC++ intrinsics - -#pragma intrinsic(_BitScanReverse, _BitScanForward) -#if defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64) -#pragma intrinsic(_BitScanReverse64, _BitScanForward64) -#endif - -inline bitcount_t flog2(uint32_t v) -{ - unsigned long i; - _BitScanReverse(&i, v); - return bitcount_t(i); -} - -inline bitcount_t trailingzeros(uint32_t v) -{ - unsigned long i; - _BitScanForward(&i, v); - return bitcount_t(i); -} - -inline bitcount_t flog2(uint64_t v) -{ -#if defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64) - unsigned long i; - _BitScanReverse64(&i, v); - return bitcount_t(i); -#else - // 32-bit x86 - uint32_t high = v >> 32; - uint32_t low = uint32_t(v); - return high ? 32+flog2(high) : flog2(low); -#endif -} - -inline bitcount_t trailingzeros(uint64_t v) -{ -#if defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64) - unsigned long i; - _BitScanForward64(&i, v); - return bitcount_t(i); -#else - // 32-bit x86 - uint32_t high = v >> 32; - uint32_t low = uint32_t(v); - return low ? trailingzeros(low) : trailingzeros(high)+32; -#endif -} - -#else // Otherwise, we fall back to bit twiddling - // implementations - -inline bitcount_t flog2(uint32_t v) -{ - // Based on code by Eric Cole and Mark Dickinson, which appears at - // https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn - - static const uint8_t multiplyDeBruijnBitPos[32] = { - 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 - }; - - v |= v >> 1; // first round down to one less than a power of 2 - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - - return multiplyDeBruijnBitPos[(uint32_t)(v * 0x07C4ACDDU) >> 27]; -} - -inline bitcount_t trailingzeros(uint32_t v) -{ - static const uint8_t multiplyDeBruijnBitPos[32] = { - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 - }; - - return multiplyDeBruijnBitPos[((uint32_t)((v & -v) * 0x077CB531U)) >> 27]; -} - -inline bitcount_t flog2(uint64_t v) -{ - uint32_t high = v >> 32; - uint32_t low = uint32_t(v); - - return high ? 32+flog2(high) : flog2(low); -} - -inline bitcount_t trailingzeros(uint64_t v) -{ - uint32_t high = v >> 32; - uint32_t low = uint32_t(v); - - return low ? trailingzeros(low) : trailingzeros(high)+32; -} - -#endif - -inline bitcount_t flog2(uint8_t v) -{ - return flog2(uint32_t(v)); -} - -inline bitcount_t flog2(uint16_t v) -{ - return flog2(uint32_t(v)); -} - -#if __SIZEOF_INT128__ -inline bitcount_t flog2(__uint128_t v) -{ - uint64_t high = uint64_t(v >> 64); - uint64_t low = uint64_t(v); - - return high ? 64+flog2(high) : flog2(low); -} -#endif - -inline bitcount_t trailingzeros(uint8_t v) -{ - return trailingzeros(uint32_t(v)); -} - -inline bitcount_t trailingzeros(uint16_t v) -{ - return trailingzeros(uint32_t(v)); -} - -#if __SIZEOF_INT128__ -inline bitcount_t trailingzeros(__uint128_t v) -{ - uint64_t high = uint64_t(v >> 64); - uint64_t low = uint64_t(v); - return low ? trailingzeros(low) : trailingzeros(high)+64; -} -#endif - -template -inline bitcount_t clog2(UInt v) -{ - return flog2(v) + ((v & (-v)) != v); -} - -template -inline UInt addwithcarry(UInt x, UInt y, bool carryin, bool* carryout) -{ - UInt half_result = y + carryin; - UInt result = x + half_result; - *carryout = (half_result < y) || (result < x); - return result; -} - -template -inline UInt subwithcarry(UInt x, UInt y, bool carryin, bool* carryout) -{ - UInt half_result = y + carryin; - UInt result = x - half_result; - *carryout = (half_result < y) || (result > x); - return result; -} - - -template -class uint_x4 { -// private: - static constexpr unsigned int UINT_BITS = sizeof(UInt) * CHAR_BIT; -public: - union { -#if PCG_LITTLE_ENDIAN - struct { - UInt v0, v1, v2, v3; - } w; - struct { - UIntX2 v01, v23; - } d; -#else - struct { - UInt v3, v2, v1, v0; - } w; - struct { - UIntX2 v23, v01; - } d; -#endif - // For the array access versions, the code that uses the array - // must handle endian itself. Yuck. - UInt wa[4]; - }; - -public: - uint_x4() = default; - - constexpr uint_x4(UInt v3, UInt v2, UInt v1, UInt v0) -#if PCG_LITTLE_ENDIAN - : w{v0, v1, v2, v3} -#else - : w{v3, v2, v1, v0} -#endif - { - // Nothing (else) to do - } - - constexpr uint_x4(UIntX2 v23, UIntX2 v01) -#if PCG_LITTLE_ENDIAN - : d{v01,v23} -#else - : d{v23,v01} -#endif - { - // Nothing (else) to do - } - - constexpr uint_x4(UIntX2 v01) -#if PCG_LITTLE_ENDIAN - : d{v01, UIntX2(0)} -#else - : d{UIntX2(0),v01} -#endif - { - // Nothing (else) to do - } - - template::value - && sizeof(Integral) <= sizeof(UIntX2)) - >::type* = nullptr> - constexpr uint_x4(Integral v01) -#if PCG_LITTLE_ENDIAN - : d{UIntX2(v01), UIntX2(0)} -#else - : d{UIntX2(0), UIntX2(v01)} -#endif - { - // Nothing (else) to do - } - - explicit constexpr operator UIntX2() const - { - return d.v01; - } - - template::value - && sizeof(Integral) <= sizeof(UIntX2)) - >::type* = nullptr> - explicit constexpr operator Integral() const - { - return Integral(d.v01); - } - - explicit constexpr operator bool() const - { - return d.v01 || d.v23; - } - - template - friend uint_x4 operator*(const uint_x4&, const uint_x4&); - - template - friend uint_x4 operator*(const uint_x4&, V); - - template - friend std::pair< uint_x4,uint_x4 > - divmod(const uint_x4&, const uint_x4&); - - template - friend uint_x4 operator+(const uint_x4&, const uint_x4&); - - template - friend uint_x4 operator-(const uint_x4&, const uint_x4&); - - template - friend uint_x4 operator<<(const uint_x4&, const bitcount_t shift); - - template - friend uint_x4 operator>>(const uint_x4&, const bitcount_t shift); - -#if PCG_64BIT_SPECIALIZATIONS - template - friend uint_x4 operator<<(const uint_x4&, const bitcount_t shift); - - template - friend uint_x4 operator>>(const uint_x4&, const bitcount_t shift); -#endif - - template - friend uint_x4 operator&(const uint_x4&, const uint_x4&); - - template - friend uint_x4 operator|(const uint_x4&, const uint_x4&); - - template - friend uint_x4 operator^(const uint_x4&, const uint_x4&); - - template - friend bool operator==(const uint_x4&, const uint_x4&); - - template - friend bool operator!=(const uint_x4&, const uint_x4&); - - template - friend bool operator<(const uint_x4&, const uint_x4&); - - template - friend bool operator<=(const uint_x4&, const uint_x4&); - - template - friend bool operator>(const uint_x4&, const uint_x4&); - - template - friend bool operator>=(const uint_x4&, const uint_x4&); - - template - friend uint_x4 operator~(const uint_x4&); - - template - friend uint_x4 operator-(const uint_x4&); - - template - friend bitcount_t flog2(const uint_x4&); - - template - friend bitcount_t trailingzeros(const uint_x4&); - -#if PCG_64BIT_SPECIALIZATIONS - template - friend bitcount_t flog2(const uint_x4&); - - template - friend bitcount_t trailingzeros(const uint_x4&); -#endif - - uint_x4& operator*=(const uint_x4& rhs) - { - uint_x4 result = *this * rhs; - return *this = result; - } - - uint_x4& operator*=(UIntX2 rhs) - { - uint_x4 result = *this * rhs; - return *this = result; - } - - uint_x4& operator/=(const uint_x4& rhs) - { - uint_x4 result = *this / rhs; - return *this = result; - } - - uint_x4& operator%=(const uint_x4& rhs) - { - uint_x4 result = *this % rhs; - return *this = result; - } - - uint_x4& operator+=(const uint_x4& rhs) - { - uint_x4 result = *this + rhs; - return *this = result; - } - - uint_x4& operator-=(const uint_x4& rhs) - { - uint_x4 result = *this - rhs; - return *this = result; - } - - uint_x4& operator&=(const uint_x4& rhs) - { - uint_x4 result = *this & rhs; - return *this = result; - } - - uint_x4& operator|=(const uint_x4& rhs) - { - uint_x4 result = *this | rhs; - return *this = result; - } - - uint_x4& operator^=(const uint_x4& rhs) - { - uint_x4 result = *this ^ rhs; - return *this = result; - } - - uint_x4& operator>>=(bitcount_t shift) - { - uint_x4 result = *this >> shift; - return *this = result; - } - - uint_x4& operator<<=(bitcount_t shift) - { - uint_x4 result = *this << shift; - return *this = result; - } - -}; - -template -bitcount_t flog2(const uint_x4& v) -{ -#if PCG_LITTLE_ENDIAN - for (uint8_t i = 4; i !=0; /* dec in loop */) { - --i; -#else - for (uint8_t i = 0; i < 4; ++i) { -#endif - if (v.wa[i] == 0) - continue; - return flog2(v.wa[i]) + uint_x4::UINT_BITS*i; - } - abort(); -} - -template -bitcount_t trailingzeros(const uint_x4& v) -{ -#if PCG_LITTLE_ENDIAN - for (uint8_t i = 0; i < 4; ++i) { -#else - for (uint8_t i = 4; i !=0; /* dec in loop */) { - --i; -#endif - if (v.wa[i] != 0) - return trailingzeros(v.wa[i]) + uint_x4::UINT_BITS*i; - } - return uint_x4::UINT_BITS*4; -} - -#if PCG_64BIT_SPECIALIZATIONS -template -bitcount_t flog2(const uint_x4& v) -{ - return v.d.v23 > 0 ? flog2(v.d.v23) + uint_x4::UINT_BITS*2 - : flog2(v.d.v01); -} - -template -bitcount_t trailingzeros(const uint_x4& v) -{ - return v.d.v01 == 0 ? trailingzeros(v.d.v23) + uint_x4::UINT_BITS*2 - : trailingzeros(v.d.v01); -} -#endif - -template -std::pair< uint_x4, uint_x4 > - divmod(const uint_x4& orig_dividend, - const uint_x4& divisor) -{ - // If the dividend is less than the divisor, the answer is always zero. - // This takes care of boundary cases like 0/x (which would otherwise be - // problematic because we can't take the log of zero. (The boundary case - // of division by zero is undefined.) - if (orig_dividend < divisor) - return { uint_x4(UIntX2(0)), orig_dividend }; - - auto dividend = orig_dividend; - - auto log2_divisor = flog2(divisor); - auto log2_dividend = flog2(dividend); - // assert(log2_dividend >= log2_divisor); - bitcount_t logdiff = log2_dividend - log2_divisor; - - constexpr uint_x4 ONE(UIntX2(1)); - if (logdiff == 0) - return { ONE, dividend - divisor }; - - // Now we change the log difference to - // floor(log2(divisor)) - ceil(log2(dividend)) - // to ensure that we *underestimate* the result. - logdiff -= 1; - - uint_x4 quotient(UIntX2(0)); - - auto qfactor = ONE << logdiff; - auto factor = divisor << logdiff; - - do { - dividend -= factor; - quotient += qfactor; - while (dividend < factor) { - factor >>= 1; - qfactor >>= 1; - } - } while (dividend >= divisor); - - return { quotient, dividend }; -} - -template -uint_x4 operator/(const uint_x4& dividend, - const uint_x4& divisor) -{ - return divmod(dividend, divisor).first; -} - -template -uint_x4 operator%(const uint_x4& dividend, - const uint_x4& divisor) -{ - return divmod(dividend, divisor).second; -} - - -template -uint_x4 operator*(const uint_x4& a, - const uint_x4& b) -{ - constexpr auto UINT_BITS = uint_x4::UINT_BITS; - uint_x4 r = {0U, 0U, 0U, 0U}; - bool carryin = false; - bool carryout; - UIntX2 a0b0 = UIntX2(a.w.v0) * UIntX2(b.w.v0); - r.w.v0 = UInt(a0b0); - r.w.v1 = UInt(a0b0 >> UINT_BITS); - - UIntX2 a1b0 = UIntX2(a.w.v1) * UIntX2(b.w.v0); - r.w.v2 = UInt(a1b0 >> UINT_BITS); - r.w.v1 = addwithcarry(r.w.v1, UInt(a1b0), carryin, &carryout); - carryin = carryout; - r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); - - UIntX2 a0b1 = UIntX2(a.w.v0) * UIntX2(b.w.v1); - carryin = false; - r.w.v2 = addwithcarry(r.w.v2, UInt(a0b1 >> UINT_BITS), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); - - carryin = false; - r.w.v1 = addwithcarry(r.w.v1, UInt(a0b1), carryin, &carryout); - carryin = carryout; - r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); - - UIntX2 a1b1 = UIntX2(a.w.v1) * UIntX2(b.w.v1); - carryin = false; - r.w.v2 = addwithcarry(r.w.v2, UInt(a1b1), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(a1b1 >> UINT_BITS), carryin, &carryout); - - r.d.v23 += a.d.v01 * b.d.v23 + a.d.v23 * b.d.v01; - - return r; -} - - -template -uint_x4 operator*(const uint_x4& a, - UIntX2 b01) -{ - constexpr auto UINT_BITS = uint_x4::UINT_BITS; - uint_x4 r = {0U, 0U, 0U, 0U}; - bool carryin = false; - bool carryout; - UIntX2 a0b0 = UIntX2(a.w.v0) * UIntX2(UInt(b01)); - r.w.v0 = UInt(a0b0); - r.w.v1 = UInt(a0b0 >> UINT_BITS); - - UIntX2 a1b0 = UIntX2(a.w.v1) * UIntX2(UInt(b01)); - r.w.v2 = UInt(a1b0 >> UINT_BITS); - r.w.v1 = addwithcarry(r.w.v1, UInt(a1b0), carryin, &carryout); - carryin = carryout; - r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); - - UIntX2 a0b1 = UIntX2(a.w.v0) * UIntX2(b01 >> UINT_BITS); - carryin = false; - r.w.v2 = addwithcarry(r.w.v2, UInt(a0b1 >> UINT_BITS), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); - - carryin = false; - r.w.v1 = addwithcarry(r.w.v1, UInt(a0b1), carryin, &carryout); - carryin = carryout; - r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout); - - UIntX2 a1b1 = UIntX2(a.w.v1) * UIntX2(b01 >> UINT_BITS); - carryin = false; - r.w.v2 = addwithcarry(r.w.v2, UInt(a1b1), carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(r.w.v3, UInt(a1b1 >> UINT_BITS), carryin, &carryout); - - r.d.v23 += a.d.v23 * b01; - - return r; -} - -#if PCG_64BIT_SPECIALIZATIONS -#if defined(_MSC_VER) -#pragma intrinsic(_umul128) -#endif - -#if defined(_MSC_VER) || __SIZEOF_INT128__ -template -uint_x4 operator*(const uint_x4& a, - const uint_x4& b) -{ -#if defined(_MSC_VER) - uint64_t hi; - uint64_t lo = _umul128(a.d.v01, b.d.v01, &hi); -#else - __uint128_t r = __uint128_t(a.d.v01) * __uint128_t(b.d.v01); - uint64_t lo = uint64_t(r); - uint64_t hi = r >> 64; -#endif - hi += a.d.v23 * b.d.v01 + a.d.v01 * b.d.v23; - return {hi, lo}; -} -#endif -#endif - - -template -uint_x4 operator+(const uint_x4& a, - const uint_x4& b) -{ - uint_x4 r = {0U, 0U, 0U, 0U}; - - bool carryin = false; - bool carryout; - r.w.v0 = addwithcarry(a.w.v0, b.w.v0, carryin, &carryout); - carryin = carryout; - r.w.v1 = addwithcarry(a.w.v1, b.w.v1, carryin, &carryout); - carryin = carryout; - r.w.v2 = addwithcarry(a.w.v2, b.w.v2, carryin, &carryout); - carryin = carryout; - r.w.v3 = addwithcarry(a.w.v3, b.w.v3, carryin, &carryout); - - return r; -} - -template -uint_x4 operator-(const uint_x4& a, - const uint_x4& b) -{ - uint_x4 r = {0U, 0U, 0U, 0U}; - - bool carryin = false; - bool carryout; - r.w.v0 = subwithcarry(a.w.v0, b.w.v0, carryin, &carryout); - carryin = carryout; - r.w.v1 = subwithcarry(a.w.v1, b.w.v1, carryin, &carryout); - carryin = carryout; - r.w.v2 = subwithcarry(a.w.v2, b.w.v2, carryin, &carryout); - carryin = carryout; - r.w.v3 = subwithcarry(a.w.v3, b.w.v3, carryin, &carryout); - - return r; -} - -#if PCG_64BIT_SPECIALIZATIONS -template -uint_x4 operator+(const uint_x4& a, - const uint_x4& b) -{ - uint_x4 r = {uint64_t(0u), uint64_t(0u)}; - - bool carryin = false; - bool carryout; - r.d.v01 = addwithcarry(a.d.v01, b.d.v01, carryin, &carryout); - carryin = carryout; - r.d.v23 = addwithcarry(a.d.v23, b.d.v23, carryin, &carryout); - - return r; -} - -template -uint_x4 operator-(const uint_x4& a, - const uint_x4& b) -{ - uint_x4 r = {uint64_t(0u), uint64_t(0u)}; - - bool carryin = false; - bool carryout; - r.d.v01 = subwithcarry(a.d.v01, b.d.v01, carryin, &carryout); - carryin = carryout; - r.d.v23 = subwithcarry(a.d.v23, b.d.v23, carryin, &carryout); - - return r; -} -#endif - -template -uint_x4 operator&(const uint_x4& a, - const uint_x4& b) -{ - return uint_x4(a.d.v23 & b.d.v23, a.d.v01 & b.d.v01); -} - -template -uint_x4 operator|(const uint_x4& a, - const uint_x4& b) -{ - return uint_x4(a.d.v23 | b.d.v23, a.d.v01 | b.d.v01); -} - -template -uint_x4 operator^(const uint_x4& a, - const uint_x4& b) -{ - return uint_x4(a.d.v23 ^ b.d.v23, a.d.v01 ^ b.d.v01); -} - -template -uint_x4 operator~(const uint_x4& v) -{ - return uint_x4(~v.d.v23, ~v.d.v01); -} - -template -uint_x4 operator-(const uint_x4& v) -{ - return uint_x4(0UL,0UL) - v; -} - -template -bool operator==(const uint_x4& a, const uint_x4& b) -{ - return (a.d.v01 == b.d.v01) && (a.d.v23 == b.d.v23); -} - -template -bool operator!=(const uint_x4& a, const uint_x4& b) -{ - return !operator==(a,b); -} - - -template -bool operator<(const uint_x4& a, const uint_x4& b) -{ - return (a.d.v23 < b.d.v23) - || ((a.d.v23 == b.d.v23) && (a.d.v01 < b.d.v01)); -} - -template -bool operator>(const uint_x4& a, const uint_x4& b) -{ - return operator<(b,a); -} - -template -bool operator<=(const uint_x4& a, const uint_x4& b) -{ - return !(operator<(b,a)); -} - -template -bool operator>=(const uint_x4& a, const uint_x4& b) -{ - return !(operator<(a,b)); -} - - - -template -uint_x4 operator<<(const uint_x4& v, - const bitcount_t shift) -{ - uint_x4 r = {0U, 0U, 0U, 0U}; - const bitcount_t bits = uint_x4::UINT_BITS; - const bitcount_t bitmask = bits - 1; - const bitcount_t shiftdiv = shift / bits; - const bitcount_t shiftmod = shift & bitmask; - - if (shiftmod) { - UInt carryover = 0; -#if PCG_LITTLE_ENDIAN - for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { -#else - for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { - --out, --in; -#endif - r.wa[out] = (v.wa[in] << shiftmod) | carryover; - carryover = (v.wa[in] >> (bits - shiftmod)); - } - } else { -#if PCG_LITTLE_ENDIAN - for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { -#else - for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { - --out, --in; -#endif - r.wa[out] = v.wa[in]; - } - } - - return r; -} - -template -uint_x4 operator>>(const uint_x4& v, - const bitcount_t shift) -{ - uint_x4 r = {0U, 0U, 0U, 0U}; - const bitcount_t bits = uint_x4::UINT_BITS; - const bitcount_t bitmask = bits - 1; - const bitcount_t shiftdiv = shift / bits; - const bitcount_t shiftmod = shift & bitmask; - - if (shiftmod) { - UInt carryover = 0; -#if PCG_LITTLE_ENDIAN - for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { - --out, --in; -#else - for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { -#endif - r.wa[out] = (v.wa[in] >> shiftmod) | carryover; - carryover = (v.wa[in] << (bits - shiftmod)); - } - } else { -#if PCG_LITTLE_ENDIAN - for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) { - --out, --in; -#else - for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) { -#endif - r.wa[out] = v.wa[in]; - } - } - - return r; -} - -#if PCG_64BIT_SPECIALIZATIONS -template -uint_x4 operator<<(const uint_x4& v, - const bitcount_t shift) -{ - constexpr bitcount_t bits2 = uint_x4::UINT_BITS * 2; - - if (shift >= bits2) { - return {v.d.v01 << (shift-bits2), uint64_t(0u)}; - } else { - return {shift ? (v.d.v23 << shift) | (v.d.v01 >> (bits2-shift)) - : v.d.v23, - v.d.v01 << shift}; - } -} - -template -uint_x4 operator>>(const uint_x4& v, - const bitcount_t shift) -{ - constexpr bitcount_t bits2 = uint_x4::UINT_BITS * 2; - - if (shift >= bits2) { - return {uint64_t(0u), v.d.v23 >> (shift-bits2)}; - } else { - return {v.d.v23 >> shift, - shift ? (v.d.v01 >> shift) | (v.d.v23 << (bits2-shift)) - : v.d.v01}; - } -} -#endif - -} // namespace pcg_extras - -#endif // PCG_UINT128_HPP_INCLUDED diff --git a/src/common/length.h b/src/common/length.h index 397f783..6c379e8 100644 --- a/src/common/length.h +++ b/src/common/length.h @@ -16,8 +16,6 @@ enum EMisc ABILITY_MAX_NUM = 50, EMPIRE_MAX_NUM = 4, BANWORD_MAX_LEN = 24, - SMS_MAX_LEN = 80, - MOBILE_MAX_LEN = 32, SOCIAL_ID_MAX_LEN = 18, GUILD_NAME_MAX_LEN = 12, @@ -251,7 +249,6 @@ enum EChatType CHAT_TYPE_SHOUT, /* 외치기 */ CHAT_TYPE_WHISPER, CHAT_TYPE_BIG_NOTICE, - CHAT_TYPE_MONARCH_NOTICE, CHAT_TYPE_MAX_NUM }; diff --git a/src/common/packet_headers.h b/src/common/packet_headers.h new file mode 100644 index 0000000..134904a --- /dev/null +++ b/src/common/packet_headers.h @@ -0,0 +1,713 @@ +#pragma once + +#include + +// +// Unified packet header constants (uint16_t) +// +// CG/GC framing: [header:2] [length:2] [payload...] +// - header: one of the CG:: / GC:: constants below +// - length: total packet size including header+length (minimum 4) +// - payload: packet-specific data +// +// GG framing: [header:2] [length:2] [payload...] +// - Same as CG/GC, used for inter-server P2P communication +// +// GD/DG framing: [header:2] [handle:4] [size:4] [payload...] +// - header: one of the GD:: / DG:: constants below +// - handle: descriptor handle (identifies the client connection) +// - size: payload size (NOT including the 10-byte frame) +// - payload: packet-specific data +// +// Ranges: +// CG: 0x0006-0x0CFF (Client -> Game) +// GC: 0x0007-0x0CFF (Game -> Client) +// GG: 0x8000-0x8FFF (Game <-> Game, P2P) +// GD: 0x9000-0x90FF (Game -> DB) +// DG: 0x9100-0x91FF (DB -> Game) +// + +// Packet header type (used by dispatch/registration systems) +typedef uint16_t TPacketHeader; + +// CG/GC minimum packet size: header(2) + length(2) +constexpr uint16_t PACKET_HEADER_SIZE = 4; + +// GD/DG frame overhead: header(2) + handle(4) + size(4) +constexpr uint32_t GD_FRAME_HEADER_SIZE = 10; + +// ============================================================================ +// CG -- Client -> Game +// ============================================================================ +namespace CG +{ + // Control + constexpr uint16_t PONG = 0x0006; + constexpr uint16_t KEY_RESPONSE = 0x000A; + constexpr uint16_t CLIENT_VERSION = 0x000D; + constexpr uint16_t STATE_CHECKER = 0x000F; + constexpr uint16_t TEXT = 0x0011; + + // Authentication + constexpr uint16_t LOGIN2 = 0x0101; + constexpr uint16_t LOGIN3 = 0x0102; + constexpr uint16_t LOGIN_SECURE = 0x0103; + constexpr uint16_t EMPIRE = 0x010A; + constexpr uint16_t CHANGE_NAME = 0x010B; + + // Character + constexpr uint16_t CHARACTER_CREATE = 0x0201; + constexpr uint16_t CHARACTER_DELETE = 0x0202; + constexpr uint16_t CHARACTER_SELECT = 0x0203; + constexpr uint16_t ENTERGAME = 0x0204; + + // Movement + constexpr uint16_t MOVE = 0x0301; + constexpr uint16_t SYNC_POSITION = 0x0303; + constexpr uint16_t WARP = 0x0305; + + // Combat + constexpr uint16_t ATTACK = 0x0401; + constexpr uint16_t USE_SKILL = 0x0402; + constexpr uint16_t SHOOT = 0x0403; + constexpr uint16_t FLY_TARGETING = 0x0404; + constexpr uint16_t ADD_FLY_TARGETING = 0x0405; + + // Items + constexpr uint16_t ITEM_USE = 0x0501; + constexpr uint16_t ITEM_DROP = 0x0502; + constexpr uint16_t ITEM_DROP2 = 0x0503; + constexpr uint16_t ITEM_MOVE = 0x0504; + constexpr uint16_t ITEM_PICKUP = 0x0505; + constexpr uint16_t ITEM_USE_TO_ITEM = 0x0506; + constexpr uint16_t ITEM_GIVE = 0x0507; + constexpr uint16_t EXCHANGE = 0x0508; + constexpr uint16_t QUICKSLOT_ADD = 0x0509; + constexpr uint16_t QUICKSLOT_DEL = 0x050A; + constexpr uint16_t QUICKSLOT_SWAP = 0x050B; + constexpr uint16_t REFINE = 0x050C; + constexpr uint16_t DRAGON_SOUL_REFINE = 0x050D; + + // Chat + constexpr uint16_t CHAT = 0x0601; + constexpr uint16_t WHISPER = 0x0602; + // Social + constexpr uint16_t PARTY_INVITE = 0x0701; + constexpr uint16_t PARTY_INVITE_ANSWER = 0x0702; + constexpr uint16_t PARTY_REMOVE = 0x0703; + constexpr uint16_t PARTY_SET_STATE = 0x0704; + constexpr uint16_t PARTY_USE_SKILL = 0x0705; + constexpr uint16_t PARTY_PARAMETER = 0x0706; + constexpr uint16_t GUILD = 0x0720; + constexpr uint16_t ANSWER_MAKE_GUILD = 0x0721; + constexpr uint16_t GUILD_SYMBOL_UPLOAD = 0x0722; + constexpr uint16_t SYMBOL_CRC = 0x0723; + constexpr uint16_t MESSENGER = 0x0740; + + // Shop / Safebox / Mall + constexpr uint16_t SHOP = 0x0801; + constexpr uint16_t MYSHOP = 0x0802; + constexpr uint16_t SAFEBOX_CHECKIN = 0x0820; + constexpr uint16_t SAFEBOX_CHECKOUT = 0x0821; + constexpr uint16_t SAFEBOX_ITEM_MOVE = 0x0822; + constexpr uint16_t MALL_CHECKOUT = 0x0840; + + // Quest + constexpr uint16_t SCRIPT_ANSWER = 0x0901; + constexpr uint16_t SCRIPT_BUTTON = 0x0902; + constexpr uint16_t SCRIPT_SELECT_ITEM = 0x0903; + constexpr uint16_t QUEST_INPUT_STRING = 0x0904; + constexpr uint16_t QUEST_CONFIRM = 0x0905; + constexpr uint16_t QUEST_CANCEL = 0x0906; + + // UI / Targeting + constexpr uint16_t TARGET = 0x0A01; + constexpr uint16_t ON_CLICK = 0x0A02; + constexpr uint16_t CHARACTER_POSITION = 0x0A60; + + // World + constexpr uint16_t FISHING = 0x0B01; + constexpr uint16_t DUNGEON = 0x0B02; + constexpr uint16_t HACK = 0x0B03; + + // Guild Marks + constexpr uint16_t MARK_LOGIN = 0x0C01; + constexpr uint16_t MARK_CRCLIST = 0x0C02; + constexpr uint16_t MARK_UPLOAD = 0x0C03; + constexpr uint16_t MARK_IDXLIST = 0x0C04; +} + +// ============================================================================ +// GC -- Game -> Client +// ============================================================================ +namespace GC +{ + // Control + constexpr uint16_t PING = 0x0007; + constexpr uint16_t PHASE = 0x0008; + constexpr uint16_t KEY_CHALLENGE = 0x000B; + constexpr uint16_t KEY_COMPLETE = 0x000C; + constexpr uint16_t RESPOND_CHANNELSTATUS = 0x0010; + + // Authentication + constexpr uint16_t LOGIN_SUCCESS3 = 0x0104; + constexpr uint16_t LOGIN_SUCCESS4 = 0x0105; + constexpr uint16_t LOGIN_FAILURE = 0x0106; + constexpr uint16_t LOGIN_KEY = 0x0107; + constexpr uint16_t AUTH_SUCCESS = 0x0108; + constexpr uint16_t EMPIRE = 0x0109; + constexpr uint16_t CHANGE_NAME = 0x010C; + + // Character + constexpr uint16_t CHARACTER_ADD = 0x0205; + constexpr uint16_t CHARACTER_ADD2 = 0x0206; + constexpr uint16_t CHAR_ADDITIONAL_INFO = 0x0207; + constexpr uint16_t CHARACTER_DEL = 0x0208; + constexpr uint16_t CHARACTER_UPDATE = 0x0209; + constexpr uint16_t CHARACTER_UPDATE2 = 0x020A; + constexpr uint16_t CHARACTER_POSITION = 0x020B; + constexpr uint16_t PLAYER_CREATE_SUCCESS = 0x020C; + constexpr uint16_t PLAYER_CREATE_FAILURE = 0x020D; + constexpr uint16_t PLAYER_DELETE_SUCCESS = 0x020E; + constexpr uint16_t PLAYER_DELETE_WRONG_SOCIAL_ID = 0x020F; + constexpr uint16_t MAIN_CHARACTER = 0x0210; + constexpr uint16_t PLAYER_POINTS = 0x0214; + constexpr uint16_t PLAYER_POINT_CHANGE = 0x0215; + constexpr uint16_t STUN = 0x0216; + constexpr uint16_t DEAD = 0x0217; + constexpr uint16_t CHANGE_SPEED = 0x0218; + constexpr uint16_t WALK_MODE = 0x0219; + constexpr uint16_t SKILL_LEVEL = 0x021A; + constexpr uint16_t SKILL_LEVEL_NEW = 0x021B; + constexpr uint16_t SKILL_COOLTIME_END = 0x021C; + constexpr uint16_t CHANGE_SKILL_GROUP = 0x021D; + constexpr uint16_t VIEW_EQUIP = 0x021E; + + // Movement + constexpr uint16_t MOVE = 0x0302; + constexpr uint16_t SYNC_POSITION = 0x0304; + constexpr uint16_t WARP = 0x0306; + constexpr uint16_t MOTION = 0x0307; + constexpr uint16_t DIG_MOTION = 0x0308; + + // Combat + constexpr uint16_t DAMAGE_INFO = 0x0410; + constexpr uint16_t FLY_TARGETING = 0x0411; + constexpr uint16_t ADD_FLY_TARGETING = 0x0412; + constexpr uint16_t CREATE_FLY = 0x0413; + constexpr uint16_t PVP = 0x0414; + constexpr uint16_t DUEL_START = 0x0415; + + // Items + constexpr uint16_t ITEM_DEL = 0x0510; + constexpr uint16_t ITEM_SET = 0x0511; + constexpr uint16_t ITEM_USE = 0x0512; + constexpr uint16_t ITEM_DROP = 0x0513; + constexpr uint16_t ITEM_UPDATE = 0x0514; + constexpr uint16_t ITEM_GROUND_ADD = 0x0515; + constexpr uint16_t ITEM_GROUND_DEL = 0x0516; + constexpr uint16_t ITEM_OWNERSHIP = 0x0517; + constexpr uint16_t ITEM_GET = 0x0518; + constexpr uint16_t QUICKSLOT_ADD = 0x0519; + constexpr uint16_t QUICKSLOT_DEL = 0x051A; + constexpr uint16_t QUICKSLOT_SWAP = 0x051B; + constexpr uint16_t EXCHANGE = 0x051C; + constexpr uint16_t REFINE_INFORMATION = 0x051D; + constexpr uint16_t REFINE_INFORMATION_NEW = 0x051E; + constexpr uint16_t DRAGON_SOUL_REFINE = 0x051F; + + // Chat + constexpr uint16_t CHAT = 0x0603; + constexpr uint16_t WHISPER = 0x0604; + + // Social + constexpr uint16_t PARTY_INVITE = 0x0710; + constexpr uint16_t PARTY_ADD = 0x0711; + constexpr uint16_t PARTY_UPDATE = 0x0712; + constexpr uint16_t PARTY_REMOVE = 0x0713; + constexpr uint16_t PARTY_LINK = 0x0714; + constexpr uint16_t PARTY_UNLINK = 0x0715; + constexpr uint16_t PARTY_PARAMETER = 0x0716; + constexpr uint16_t GUILD = 0x0730; + constexpr uint16_t REQUEST_MAKE_GUILD = 0x0731; + constexpr uint16_t SYMBOL_DATA = 0x0732; + constexpr uint16_t MESSENGER = 0x0741; + constexpr uint16_t LOVER_INFO = 0x0750; + constexpr uint16_t LOVE_POINT_UPDATE = 0x0751; + + // Shop / Safebox / Mall + constexpr uint16_t SHOP = 0x0810; + constexpr uint16_t SHOP_SIGN = 0x0811; + constexpr uint16_t SAFEBOX_SET = 0x0830; + constexpr uint16_t SAFEBOX_DEL = 0x0831; + constexpr uint16_t SAFEBOX_WRONG_PASSWORD = 0x0832; + constexpr uint16_t SAFEBOX_SIZE = 0x0833; + constexpr uint16_t SAFEBOX_MONEY_CHANGE = 0x0834; + constexpr uint16_t MALL_OPEN = 0x0841; + constexpr uint16_t MALL_SET = 0x0842; + constexpr uint16_t MALL_DEL = 0x0843; + + // Quest + constexpr uint16_t SCRIPT = 0x0910; + constexpr uint16_t QUEST_CONFIRM = 0x0911; + constexpr uint16_t QUEST_INFO = 0x0912; + + // UI / Effects / Targeting + constexpr uint16_t TARGET = 0x0A10; + constexpr uint16_t TARGET_UPDATE = 0x0A11; + constexpr uint16_t TARGET_DELETE = 0x0A12; + constexpr uint16_t TARGET_CREATE_NEW = 0x0A13; + constexpr uint16_t AFFECT_ADD = 0x0A20; + constexpr uint16_t AFFECT_REMOVE = 0x0A21; + constexpr uint16_t SEPCIAL_EFFECT = 0x0A30; + constexpr uint16_t SPECIFIC_EFFECT = 0x0A31; + constexpr uint16_t MOUNT = 0x0A40; + constexpr uint16_t OWNERSHIP = 0x0A41; + constexpr uint16_t NPC_POSITION = 0x0A50; + + // World + constexpr uint16_t FISHING = 0x0B10; + constexpr uint16_t DUNGEON = 0x0B11; + constexpr uint16_t LAND_LIST = 0x0B12; + constexpr uint16_t TIME = 0x0B13; + constexpr uint16_t CHANNEL = 0x0B14; + constexpr uint16_t MARK_UPDATE = 0x0B15; + constexpr uint16_t OBSERVER_ADD = 0x0B20; + constexpr uint16_t OBSERVER_REMOVE = 0x0B21; + constexpr uint16_t OBSERVER_MOVE = 0x0B22; + + // Guild Marks + constexpr uint16_t MARK_BLOCK = 0x0C10; + constexpr uint16_t MARK_IDXLIST = 0x0C11; + constexpr uint16_t MARK_DIFF_DATA = 0x0C12; +} + +// ============================================================================ +// Phase constants (used by GC::PHASE payload) +// ============================================================================ +enum EPhases +{ + PHASE_CLOSE, + PHASE_HANDSHAKE, + PHASE_LOGIN, + PHASE_SELECT, + PHASE_LOADING, + PHASE_GAME, + PHASE_DEAD, + + // Internal / server-side phases + PHASE_CLIENT_CONNECTING, + PHASE_DBCLIENT, + PHASE_P2P, + PHASE_AUTH, +}; + +// ============================================================================ +// GG -- Game <-> Game (P2P) +// ============================================================================ +namespace GG +{ + constexpr uint16_t LOGIN = 0x8001; + constexpr uint16_t LOGOUT = 0x8002; + constexpr uint16_t RELAY = 0x8003; + constexpr uint16_t NOTICE = 0x8004; + constexpr uint16_t SHUTDOWN = 0x8005; + constexpr uint16_t GUILD = 0x8006; + constexpr uint16_t DISCONNECT = 0x8007; + constexpr uint16_t SHOUT = 0x8008; + constexpr uint16_t SETUP = 0x8009; + constexpr uint16_t MESSENGER_ADD = 0x800A; + constexpr uint16_t MESSENGER_REMOVE = 0x800B; + constexpr uint16_t FIND_POSITION = 0x800C; + constexpr uint16_t WARP_CHARACTER = 0x800D; + constexpr uint16_t GUILD_WAR_ZONE_MAP_INDEX = 0x800F; + constexpr uint16_t TRANSFER = 0x8010; + constexpr uint16_t XMAS_WARP_SANTA = 0x8011; + constexpr uint16_t XMAS_WARP_SANTA_REPLY = 0x8012; + constexpr uint16_t RELOAD_CRC_LIST = 0x8013; + constexpr uint16_t LOGIN_PING = 0x8014; + constexpr uint16_t CHECK_CLIENT_VERSION = 0x8015; + constexpr uint16_t BLOCK_CHAT = 0x8016; + constexpr uint16_t MESSENGER_REQUEST_ADD = 0x8017; + constexpr uint16_t MESSENGER_RESPONSE = 0x8018; + constexpr uint16_t SIEGE = 0x8019; + constexpr uint16_t CHECK_AWAKENESS = 0x801C; + constexpr uint16_t MARK_UPDATE = 0x801D; +} + +// ============================================================================ +// GD -- Game -> DB +// ============================================================================ +namespace GD +{ + constexpr uint16_t LOGOUT = 0x9001; + constexpr uint16_t PLAYER_LOAD = 0x9002; + constexpr uint16_t PLAYER_SAVE = 0x9003; + constexpr uint16_t PLAYER_CREATE = 0x9004; + constexpr uint16_t PLAYER_DELETE = 0x9005; + constexpr uint16_t LOGIN_KEY = 0x9006; + constexpr uint16_t BOOT = 0x9007; + constexpr uint16_t PLAYER_COUNT = 0x9008; + constexpr uint16_t QUEST_SAVE = 0x9009; + constexpr uint16_t SAFEBOX_LOAD = 0x900A; + constexpr uint16_t SAFEBOX_SAVE = 0x900B; + constexpr uint16_t SAFEBOX_CHANGE_SIZE = 0x900C; + constexpr uint16_t EMPIRE_SELECT = 0x900D; + constexpr uint16_t SAFEBOX_CHANGE_PASSWORD = 0x900E; + constexpr uint16_t SAFEBOX_CHANGE_PASSWORD_SECOND = 0x900F; + constexpr uint16_t DIRECT_ENTER = 0x9010; + + // Guild + constexpr uint16_t GUILD_SKILL_UPDATE = 0x9011; + constexpr uint16_t GUILD_EXP_UPDATE = 0x9012; + constexpr uint16_t GUILD_ADD_MEMBER = 0x9013; + constexpr uint16_t GUILD_REMOVE_MEMBER = 0x9014; + constexpr uint16_t GUILD_CHANGE_GRADE = 0x9015; + constexpr uint16_t GUILD_CHANGE_MEMBER_DATA = 0x9016; + constexpr uint16_t GUILD_DISBAND = 0x9017; + constexpr uint16_t GUILD_WAR = 0x9018; + constexpr uint16_t GUILD_WAR_SCORE = 0x9019; + constexpr uint16_t GUILD_CREATE = 0x901A; + + // Items + constexpr uint16_t ITEM_SAVE = 0x901B; + constexpr uint16_t ITEM_DESTROY = 0x901C; + + // Affects + constexpr uint16_t ADD_AFFECT = 0x901D; + constexpr uint16_t REMOVE_AFFECT = 0x901E; + + // Misc + constexpr uint16_t HIGHSCORE_REGISTER = 0x901F; + constexpr uint16_t ITEM_FLUSH = 0x9020; + + // Party + constexpr uint16_t PARTY_CREATE = 0x9021; + constexpr uint16_t PARTY_DELETE = 0x9022; + constexpr uint16_t PARTY_ADD = 0x9023; + constexpr uint16_t PARTY_REMOVE = 0x9024; + constexpr uint16_t PARTY_STATE_CHANGE = 0x9025; + constexpr uint16_t PARTY_HEAL_USE = 0x9026; + + constexpr uint16_t FLUSH_CACHE = 0x9027; + constexpr uint16_t RELOAD_PROTO = 0x9028; + constexpr uint16_t CHANGE_NAME = 0x9029; + + // Guild Economy + constexpr uint16_t GUILD_CHANGE_LADDER_POINT = 0x902B; + constexpr uint16_t GUILD_USE_SKILL = 0x902C; + constexpr uint16_t REQUEST_EMPIRE_PRIV = 0x902D; + constexpr uint16_t REQUEST_GUILD_PRIV = 0x902E; + constexpr uint16_t MONEY_LOG = 0x902F; + constexpr uint16_t GUILD_DEPOSIT_MONEY = 0x9030; + constexpr uint16_t GUILD_WITHDRAW_MONEY = 0x9031; + constexpr uint16_t GUILD_WITHDRAW_MONEY_GIVE_REPLY = 0x9032; + constexpr uint16_t REQUEST_CHARACTER_PRIV = 0x9033; + constexpr uint16_t SET_EVENT_FLAG = 0x9034; + constexpr uint16_t PARTY_SET_MEMBER_LEVEL = 0x9035; + constexpr uint16_t GUILD_WAR_BET = 0x9036; + + // Land/Building + constexpr uint16_t CREATE_OBJECT = 0x9037; + constexpr uint16_t DELETE_OBJECT = 0x9038; + constexpr uint16_t UPDATE_LAND = 0x9039; + + // Marriage + constexpr uint16_t MARRIAGE_ADD = 0x903A; + constexpr uint16_t MARRIAGE_UPDATE = 0x903B; + constexpr uint16_t MARRIAGE_REMOVE = 0x903C; + constexpr uint16_t WEDDING_REQUEST = 0x903D; + constexpr uint16_t WEDDING_READY = 0x903E; + constexpr uint16_t WEDDING_END = 0x903F; + + // Auth + constexpr uint16_t AUTH_LOGIN = 0x9040; + constexpr uint16_t LOGIN_BY_KEY = 0x9041; + constexpr uint16_t MALL_LOAD = 0x9042; + + // MyShop + constexpr uint16_t MYSHOP_PRICELIST_UPDATE = 0x9043; + constexpr uint16_t MYSHOP_PRICELIST_REQ = 0x9044; + + constexpr uint16_t BLOCK_CHAT = 0x9045; + constexpr uint16_t HAMMER_OF_TOR = 0x9046; + constexpr uint16_t RELOAD_ADMIN = 0x9047; + constexpr uint16_t BREAK_MARRIAGE = 0x9048; + + constexpr uint16_t REQ_CHANGE_GUILD_MASTER = 0x9053; + constexpr uint16_t REQ_SPARE_ITEM_ID_RANGE = 0x9054; + constexpr uint16_t UPDATE_HORSE_NAME = 0x9055; + constexpr uint16_t REQ_HORSE_NAME = 0x9056; + constexpr uint16_t DC = 0x9057; + constexpr uint16_t VALID_LOGOUT = 0x9058; + constexpr uint16_t REQUEST_CHARGE_CASH = 0x9059; + constexpr uint16_t DELETE_AWARDID = 0x905A; + constexpr uint16_t UPDATE_CHANNELSTATUS = 0x905B; + constexpr uint16_t REQUEST_CHANNELSTATUS = 0x905C; + + constexpr uint16_t SETUP = 0x90FF; +} + +// ============================================================================ +// DG -- DB -> Game +// ============================================================================ +namespace DG +{ + constexpr uint16_t NOTICE = 0x9101; + + constexpr uint16_t LOGIN_SUCCESS = 0x9102; + constexpr uint16_t LOGIN_NOT_EXIST = 0x9103; + constexpr uint16_t LOGIN_WRONG_PASSWD = 0x9104; + constexpr uint16_t LOGIN_ALREADY = 0x9105; + + constexpr uint16_t PLAYER_LOAD_SUCCESS = 0x9106; + constexpr uint16_t PLAYER_LOAD_FAILED = 0x9107; + constexpr uint16_t PLAYER_CREATE_SUCCESS = 0x9108; + constexpr uint16_t PLAYER_CREATE_ALREADY = 0x9109; + constexpr uint16_t PLAYER_CREATE_FAILED = 0x910A; + constexpr uint16_t PLAYER_DELETE_SUCCESS = 0x910B; + constexpr uint16_t PLAYER_DELETE_FAILED = 0x910C; + + constexpr uint16_t ITEM_LOAD = 0x910D; + constexpr uint16_t BOOT = 0x910E; + constexpr uint16_t QUEST_LOAD = 0x910F; + + constexpr uint16_t SAFEBOX_LOAD = 0x9110; + constexpr uint16_t SAFEBOX_CHANGE_SIZE = 0x9111; + constexpr uint16_t SAFEBOX_WRONG_PASSWORD = 0x9112; + constexpr uint16_t SAFEBOX_CHANGE_PASSWORD_ANSWER = 0x9113; + constexpr uint16_t EMPIRE_SELECT = 0x9114; + constexpr uint16_t AFFECT_LOAD = 0x9115; + constexpr uint16_t MALL_LOAD = 0x9116; + + constexpr uint16_t DIRECT_ENTER = 0x9117; + + // Guild + constexpr uint16_t GUILD_SKILL_UPDATE = 0x9118; + constexpr uint16_t GUILD_SKILL_RECHARGE = 0x9119; + constexpr uint16_t GUILD_EXP_UPDATE = 0x911A; + + // Party + constexpr uint16_t PARTY_CREATE = 0x911B; + constexpr uint16_t PARTY_DELETE = 0x911C; + constexpr uint16_t PARTY_ADD = 0x911D; + constexpr uint16_t PARTY_REMOVE = 0x911E; + constexpr uint16_t PARTY_STATE_CHANGE = 0x911F; + constexpr uint16_t PARTY_HEAL_USE = 0x9120; + constexpr uint16_t PARTY_SET_MEMBER_LEVEL = 0x9121; + + constexpr uint16_t TIME = 0x9122; + constexpr uint16_t ITEM_ID_RANGE = 0x9123; + + // Guild (continued) + constexpr uint16_t GUILD_ADD_MEMBER = 0x9124; + constexpr uint16_t GUILD_REMOVE_MEMBER = 0x9125; + constexpr uint16_t GUILD_CHANGE_GRADE = 0x9126; + constexpr uint16_t GUILD_CHANGE_MEMBER_DATA = 0x9127; + constexpr uint16_t GUILD_DISBAND = 0x9128; + constexpr uint16_t GUILD_WAR = 0x9129; + constexpr uint16_t GUILD_WAR_SCORE = 0x912A; + constexpr uint16_t GUILD_TIME_UPDATE = 0x912B; + constexpr uint16_t GUILD_LOAD = 0x912C; + constexpr uint16_t GUILD_LADDER = 0x912D; + constexpr uint16_t GUILD_SKILL_USABLE_CHANGE = 0x912E; + constexpr uint16_t GUILD_MONEY_CHANGE = 0x912F; + constexpr uint16_t GUILD_WITHDRAW_MONEY_GIVE = 0x9130; + + constexpr uint16_t SET_EVENT_FLAG = 0x9131; + constexpr uint16_t GUILD_WAR_RESERVE_ADD = 0x9132; + constexpr uint16_t GUILD_WAR_RESERVE_DEL = 0x9133; + constexpr uint16_t GUILD_WAR_BET = 0x9134; + + constexpr uint16_t RELOAD_PROTO = 0x9135; + constexpr uint16_t CHANGE_NAME = 0x9136; + constexpr uint16_t AUTH_LOGIN = 0x9137; + + constexpr uint16_t CHANGE_EMPIRE_PRIV = 0x9138; + constexpr uint16_t CHANGE_GUILD_PRIV = 0x9139; + constexpr uint16_t MONEY_LOG = 0x913A; + constexpr uint16_t CHANGE_CHARACTER_PRIV = 0x913B; + + // Land/Building + constexpr uint16_t CREATE_OBJECT = 0x913C; + constexpr uint16_t DELETE_OBJECT = 0x913D; + constexpr uint16_t UPDATE_LAND = 0x913E; + + // Marriage + constexpr uint16_t MARRIAGE_ADD = 0x913F; + constexpr uint16_t MARRIAGE_UPDATE = 0x9140; + constexpr uint16_t MARRIAGE_REMOVE = 0x9141; + constexpr uint16_t WEDDING_REQUEST = 0x9142; + constexpr uint16_t WEDDING_READY = 0x9143; + constexpr uint16_t WEDDING_START = 0x9144; + constexpr uint16_t WEDDING_END = 0x9145; + + constexpr uint16_t MYSHOP_PRICELIST_RES = 0x9146; + constexpr uint16_t RELOAD_ADMIN = 0x9147; + constexpr uint16_t BREAK_MARRIAGE = 0x9148; + + constexpr uint16_t ACK_CHANGE_GUILD_MASTER = 0x9154; + constexpr uint16_t ACK_SPARE_ITEM_ID_RANGE = 0x9155; + constexpr uint16_t UPDATE_HORSE_NAME = 0x9156; + constexpr uint16_t ACK_HORSE_NAME = 0x9157; + constexpr uint16_t NEED_LOGIN_LOG = 0x9158; + constexpr uint16_t RESULT_CHARGE_CASH = 0x9159; + constexpr uint16_t ITEMAWARD_INFORMER = 0x915A; + constexpr uint16_t RESPOND_CHANNELSTATUS = 0x915B; + + constexpr uint16_t MAP_LOCATIONS = 0x91FE; + constexpr uint16_t P2P = 0x91FF; +} + +// ============================================================================ +// Subheader enums — grouped by feature +// ============================================================================ + +namespace GuildSub { + namespace GG { enum : uint8_t { + CHAT, + SET_MEMBER_COUNT_BONUS, + }; } + namespace CG { enum : uint8_t { + ADD_MEMBER, + REMOVE_MEMBER, + CHANGE_GRADE_NAME, + CHANGE_GRADE_AUTHORITY, + OFFER, + POST_COMMENT, + DELETE_COMMENT, + REFRESH_COMMENT, + CHANGE_MEMBER_GRADE, + USE_SKILL, + CHANGE_MEMBER_GENERAL, + GUILD_INVITE_ANSWER, + CHARGE_GSP, + DEPOSIT_MONEY, + WITHDRAW_MONEY, + }; } + namespace GC { enum : uint8_t { + LOGIN, + LOGOUT, + LIST, + GRADE, + ADD, + REMOVE, + GRADE_NAME, + GRADE_AUTH, + INFO, + COMMENTS, + CHANGE_EXP, + CHANGE_MEMBER_GRADE, + SKILL_INFO, + CHANGE_MEMBER_GENERAL, + GUILD_INVITE, + WAR, + GUILD_NAME, + GUILD_WAR_LIST, + GUILD_WAR_END_LIST, + WAR_SCORE, + MONEY_CHANGE, + }; } +} + +namespace ShopSub { + namespace CG { enum : uint8_t { + END, + BUY, + SELL, + SELL2, + }; } + namespace GC { enum : uint8_t { + START, + END, + UPDATE_ITEM, + UPDATE_PRICE, + OK, + NOT_ENOUGH_MONEY, + SOLDOUT, + INVENTORY_FULL, + INVALID_POS, + SOLD_OUT, + START_EX, + NOT_ENOUGH_MONEY_EX, + }; } +} + +namespace ExchangeSub { + namespace CG { enum : uint8_t { + START, + ITEM_ADD, + ITEM_DEL, + ELK_ADD, + ACCEPT, + CANCEL, + }; } + namespace GC { enum : uint8_t { + START, + ITEM_ADD, + ITEM_DEL, + GOLD_ADD, + ACCEPT, + END, + ALREADY, + LESS_GOLD, + }; } +} + +namespace MessengerSub { + namespace CG { enum : uint8_t { + ADD_BY_VID, + ADD_BY_NAME, + REMOVE, + INVITE_ANSWER, + }; } + namespace GC { enum : uint8_t { + LIST, + LOGIN, + LOGOUT, + INVITE, + REMOVE_FRIEND, + }; } +} + +namespace FishingSub { + namespace GC { enum : uint8_t { + START, + STOP, + REACT, + SUCCESS, + FAIL, + FISH, + }; } +} + +namespace DungeonSub { + namespace GC { enum : uint8_t { + TIME_ATTACK_START = 0, + DESTINATION_POSITION = 1, + }; } +} + +namespace PartySub { + namespace GG { enum : uint8_t { + CREATE, + DESTROY, + JOIN, + QUIT, + }; } +} + +namespace DragonSoulSub { enum : uint8_t { + OPEN, + CLOSE, + DO_REFINE_GRADE, + DO_REFINE_STEP, + DO_REFINE_STRENGTH, + REFINE_FAIL, + REFINE_FAIL_MAX_REFINE, + REFINE_FAIL_INVALID_MATERIAL, + REFINE_FAIL_NOT_ENOUGH_MONEY, + REFINE_FAIL_NOT_ENOUGH_MATERIAL, + REFINE_FAIL_TOO_MUCH_MATERIAL, + REFINE_SUCCEED, +}; } diff --git a/src/common/service.h b/src/common/service.h index 5505031..de266ee 100644 --- a/src/common/service.h +++ b/src/common/service.h @@ -4,6 +4,5 @@ #define ENABLE_AUTODETECT_INTERNAL_IP #define ENABLE_PROXY_IP #define __PET_SYSTEM__ -#define __UDP_BLOCK__ #endif diff --git a/src/common/tables.h b/src/common/tables.h index d34bf27..b623d9c 100644 --- a/src/common/tables.h +++ b/src/common/tables.h @@ -1,270 +1,9 @@ #pragma once #include "length.h" +#include "packet_headers.h" typedef uint32_t IDENT; -/** - * @version 05/06/10 Bang2ni - Myshop Pricelist 관련 패킷 HEADER_XX_MYSHOP_PRICELIST_XXX 추가 - */ -enum -{ - HEADER_GD_LOGOUT = 2, - - HEADER_GD_PLAYER_LOAD = 3, - HEADER_GD_PLAYER_SAVE = 4, - HEADER_GD_PLAYER_CREATE = 5, - HEADER_GD_PLAYER_DELETE = 6, - - HEADER_GD_LOGIN_KEY = 7, - // 8 empty - HEADER_GD_BOOT = 9, - HEADER_GD_PLAYER_COUNT = 10, - HEADER_GD_QUEST_SAVE = 11, - HEADER_GD_SAFEBOX_LOAD = 12, - HEADER_GD_SAFEBOX_SAVE = 13, - HEADER_GD_SAFEBOX_CHANGE_SIZE = 14, - HEADER_GD_EMPIRE_SELECT = 15, - - HEADER_GD_SAFEBOX_CHANGE_PASSWORD = 16, - HEADER_GD_SAFEBOX_CHANGE_PASSWORD_SECOND = 17, // Not really a packet, used internal - HEADER_GD_DIRECT_ENTER = 18, - - HEADER_GD_GUILD_SKILL_UPDATE = 19, - HEADER_GD_GUILD_EXP_UPDATE = 20, - HEADER_GD_GUILD_ADD_MEMBER = 21, - HEADER_GD_GUILD_REMOVE_MEMBER = 22, - HEADER_GD_GUILD_CHANGE_GRADE = 23, - HEADER_GD_GUILD_CHANGE_MEMBER_DATA = 24, - HEADER_GD_GUILD_DISBAND = 25, - HEADER_GD_GUILD_WAR = 26, - HEADER_GD_GUILD_WAR_SCORE = 27, - HEADER_GD_GUILD_CREATE = 28, - - HEADER_GD_ITEM_SAVE = 30, - HEADER_GD_ITEM_DESTROY = 31, - - HEADER_GD_ADD_AFFECT = 32, - HEADER_GD_REMOVE_AFFECT = 33, - - HEADER_GD_HIGHSCORE_REGISTER = 34, - HEADER_GD_ITEM_FLUSH = 35, - - HEADER_GD_PARTY_CREATE = 36, - HEADER_GD_PARTY_DELETE = 37, - HEADER_GD_PARTY_ADD = 38, - HEADER_GD_PARTY_REMOVE = 39, - HEADER_GD_PARTY_STATE_CHANGE = 40, - HEADER_GD_PARTY_HEAL_USE = 41, - - HEADER_GD_FLUSH_CACHE = 42, - HEADER_GD_RELOAD_PROTO = 43, - - HEADER_GD_CHANGE_NAME = 44, - HEADER_GD_SMS = 45, - - HEADER_GD_GUILD_CHANGE_LADDER_POINT = 46, - HEADER_GD_GUILD_USE_SKILL = 47, - - HEADER_GD_REQUEST_EMPIRE_PRIV = 48, - HEADER_GD_REQUEST_GUILD_PRIV = 49, - - HEADER_GD_MONEY_LOG = 50, - - HEADER_GD_GUILD_DEPOSIT_MONEY = 51, - HEADER_GD_GUILD_WITHDRAW_MONEY = 52, - HEADER_GD_GUILD_WITHDRAW_MONEY_GIVE_REPLY = 53, - - HEADER_GD_REQUEST_CHARACTER_PRIV = 54, - - HEADER_GD_SET_EVENT_FLAG = 55, - - HEADER_GD_PARTY_SET_MEMBER_LEVEL = 56, - - HEADER_GD_GUILD_WAR_BET = 57, - - HEADER_GD_CREATE_OBJECT = 60, - HEADER_GD_DELETE_OBJECT = 61, - HEADER_GD_UPDATE_LAND = 62, - - HEADER_GD_MARRIAGE_ADD = 70, - HEADER_GD_MARRIAGE_UPDATE = 71, - HEADER_GD_MARRIAGE_REMOVE = 72, - - HEADER_GD_WEDDING_REQUEST = 73, - HEADER_GD_WEDDING_READY = 74, - HEADER_GD_WEDDING_END = 75, - - HEADER_GD_AUTH_LOGIN = 100, - HEADER_GD_LOGIN_BY_KEY = 101, - HEADER_GD_MALL_LOAD = 107, - - HEADER_GD_MYSHOP_PRICELIST_UPDATE = 108, ///< 가격정보 갱신 요청 - HEADER_GD_MYSHOP_PRICELIST_REQ = 109, ///< 가격정보 리스트 요청 - - HEADER_GD_BLOCK_CHAT = 110, - - HEADER_GD_HAMMER_OF_TOR = 114, - HEADER_GD_RELOAD_ADMIN = 115, ///<운영자 정보 요청 - HEADER_GD_BREAK_MARRIAGE = 116, ///< 결혼 파기 - HEADER_GD_ELECT_MONARCH = 117, ///< 군주 투표 - HEADER_GD_CANDIDACY = 118, ///< 군주 등록 - HEADER_GD_ADD_MONARCH_MONEY = 119, ///< 군주 돈 증가 - HEADER_GD_TAKE_MONARCH_MONEY = 120, ///< 군주 돈 감소 - HEADER_GD_COME_TO_VOTE = 121, ///< 표결 - HEADER_GD_RMCANDIDACY = 122, ///< 후보 제거 (운영자) - HEADER_GD_SETMONARCH = 123, ///<군주설정 (운영자) - HEADER_GD_RMMONARCH = 124, ///<군주삭제 - HEADER_GD_DEC_MONARCH_MONEY = 125, - - HEADER_GD_CHANGE_MONARCH_LORD = 126, - - HEADER_GD_REQ_CHANGE_GUILD_MASTER = 129, - - HEADER_GD_REQ_SPARE_ITEM_ID_RANGE = 130, - - HEADER_GD_UPDATE_HORSE_NAME = 131, - HEADER_GD_REQ_HORSE_NAME = 132, - - HEADER_GD_DC = 133, // Login Key를 지움 - - HEADER_GD_VALID_LOGOUT = 134, - - HEADER_GD_REQUEST_CHARGE_CASH = 137, - - HEADER_GD_DELETE_AWARDID = 138, // delete gift notify icon - - HEADER_GD_UPDATE_CHANNELSTATUS = 139, - HEADER_GD_REQUEST_CHANNELSTATUS = 140, - - HEADER_GD_SETUP = 0xff, - - /////////////////////////////////////////////// - HEADER_DG_NOTICE = 1, - - HEADER_DG_LOGIN_SUCCESS = 30, - HEADER_DG_LOGIN_NOT_EXIST = 31, - HEADER_DG_LOGIN_WRONG_PASSWD = 33, - HEADER_DG_LOGIN_ALREADY = 34, - - HEADER_DG_PLAYER_LOAD_SUCCESS = 35, - HEADER_DG_PLAYER_LOAD_FAILED = 36, - HEADER_DG_PLAYER_CREATE_SUCCESS = 37, - HEADER_DG_PLAYER_CREATE_ALREADY = 38, - HEADER_DG_PLAYER_CREATE_FAILED = 39, - HEADER_DG_PLAYER_DELETE_SUCCESS = 40, - HEADER_DG_PLAYER_DELETE_FAILED = 41, - - HEADER_DG_ITEM_LOAD = 42, - - HEADER_DG_BOOT = 43, - HEADER_DG_QUEST_LOAD = 44, - - HEADER_DG_SAFEBOX_LOAD = 45, - HEADER_DG_SAFEBOX_CHANGE_SIZE = 46, - HEADER_DG_SAFEBOX_WRONG_PASSWORD = 47, - HEADER_DG_SAFEBOX_CHANGE_PASSWORD_ANSWER = 48, - - HEADER_DG_EMPIRE_SELECT = 49, - - HEADER_DG_AFFECT_LOAD = 50, - HEADER_DG_MALL_LOAD = 51, - - HEADER_DG_DIRECT_ENTER = 55, - - HEADER_DG_GUILD_SKILL_UPDATE = 56, - HEADER_DG_GUILD_SKILL_RECHARGE = 57, - HEADER_DG_GUILD_EXP_UPDATE = 58, - - HEADER_DG_PARTY_CREATE = 59, - HEADER_DG_PARTY_DELETE = 60, - HEADER_DG_PARTY_ADD = 61, - HEADER_DG_PARTY_REMOVE = 62, - HEADER_DG_PARTY_STATE_CHANGE = 63, - HEADER_DG_PARTY_HEAL_USE = 64, - HEADER_DG_PARTY_SET_MEMBER_LEVEL = 65, - - HEADER_DG_TIME = 90, - HEADER_DG_ITEM_ID_RANGE = 91, - - HEADER_DG_GUILD_ADD_MEMBER = 92, - HEADER_DG_GUILD_REMOVE_MEMBER = 93, - HEADER_DG_GUILD_CHANGE_GRADE = 94, - HEADER_DG_GUILD_CHANGE_MEMBER_DATA = 95, - HEADER_DG_GUILD_DISBAND = 96, - HEADER_DG_GUILD_WAR = 97, - HEADER_DG_GUILD_WAR_SCORE = 98, - HEADER_DG_GUILD_TIME_UPDATE = 99, - HEADER_DG_GUILD_LOAD = 100, - HEADER_DG_GUILD_LADDER = 101, - HEADER_DG_GUILD_SKILL_USABLE_CHANGE = 102, - HEADER_DG_GUILD_MONEY_CHANGE = 103, - HEADER_DG_GUILD_WITHDRAW_MONEY_GIVE = 104, - - HEADER_DG_SET_EVENT_FLAG = 105, - - HEADER_DG_GUILD_WAR_RESERVE_ADD = 106, - HEADER_DG_GUILD_WAR_RESERVE_DEL = 107, - HEADER_DG_GUILD_WAR_BET = 108, - - HEADER_DG_RELOAD_PROTO = 120, - HEADER_DG_CHANGE_NAME = 121, - - HEADER_DG_AUTH_LOGIN = 122, - - HEADER_DG_CHANGE_EMPIRE_PRIV = 124, - HEADER_DG_CHANGE_GUILD_PRIV = 125, - - HEADER_DG_MONEY_LOG = 126, - - HEADER_DG_CHANGE_CHARACTER_PRIV = 127, - - HEADER_DG_CREATE_OBJECT = 140, - HEADER_DG_DELETE_OBJECT = 141, - HEADER_DG_UPDATE_LAND = 142, - - HEADER_DG_MARRIAGE_ADD = 150, - HEADER_DG_MARRIAGE_UPDATE = 151, - HEADER_DG_MARRIAGE_REMOVE = 152, - - HEADER_DG_WEDDING_REQUEST = 153, - HEADER_DG_WEDDING_READY = 154, - HEADER_DG_WEDDING_START = 155, - HEADER_DG_WEDDING_END = 156, - - HEADER_DG_MYSHOP_PRICELIST_RES = 157, ///< 가격정보 리스트 응답 - HEADER_DG_RELOAD_ADMIN = 158, ///< 운영자 정보 리로드 - HEADER_DG_BREAK_MARRIAGE = 159, ///< 결혼 파기 - HEADER_DG_ELECT_MONARCH = 160, ///< 군주 투표 - HEADER_DG_CANDIDACY = 161, ///< 군주 등록 - HEADER_DG_ADD_MONARCH_MONEY = 162, ///< 군주 돈 증가 - HEADER_DG_TAKE_MONARCH_MONEY = 163, ///< 군주 돈 감소 - HEADER_DG_COME_TO_VOTE = 164, ///< 표결 - HEADER_DG_RMCANDIDACY = 165, ///< 후보 제거 (운영자) - HEADER_DG_SETMONARCH = 166, ///<군주설정 (운영자) - HEADER_DG_RMMONARCH = 167, ///<군주삭제 - HEADER_DG_DEC_MONARCH_MONEY = 168, - - HEADER_DG_CHANGE_MONARCH_LORD_ACK = 169, - HEADER_DG_UPDATE_MONARCH_INFO = 170, - - HEADER_DG_ACK_CHANGE_GUILD_MASTER = 173, - - HEADER_DG_ACK_SPARE_ITEM_ID_RANGE = 174, - - HEADER_DG_UPDATE_HORSE_NAME = 175, - HEADER_DG_ACK_HORSE_NAME = 176, - - HEADER_DG_NEED_LOGIN_LOG = 177, - - HEADER_DG_RESULT_CHARGE_CASH = 179, - HEADER_DG_ITEMAWARD_INFORMER = 180, //gift notify - HEADER_DG_RESPOND_CHANNELSTATUS = 181, - - HEADER_DG_MAP_LOCATIONS = 0xfe, - HEADER_DG_P2P = 0xff, - -}; - /* ---------------------------------------------- * table * ---------------------------------------------- @@ -419,8 +158,6 @@ typedef struct SPlayerTable uint8_t skill_group; int32_t lAlignment; - char szMobile[MOBILE_MAX_LEN + 1]; - int16_t stat_reset_count; THorseInfo horse; @@ -975,14 +712,6 @@ typedef struct SPacketGuildLadderPoint int32_t lChange; } TPacketGuildLadderPoint; -typedef struct SPacketGDSMS -{ - char szFrom[CHARACTER_NAME_MAX_LEN + 1]; - char szTo[CHARACTER_NAME_MAX_LEN + 1]; - char szMobile[MOBILE_MAX_LEN + 1]; - char szMsg[SMS_MAX_LEN + 1]; -} TPacketGDSMS; - typedef struct SPacketGuildUseSkill { uint32_t dwGuild; @@ -1277,43 +1006,6 @@ typedef struct SPacketReloadAdmin } TPacketReloadAdmin; //END_RELOAD_ADMIN -typedef struct TMonarchInfo -{ - uint32_t pid[4]; // 군주의 PID - int64_t money[4]; // 군주의 별개 돈 - char name[4][32]; // 군주의 이름 - char date[4][32]; // 군주 등록 날짜 -} MonarchInfo; - -typedef struct TMonarchElectionInfo -{ - uint32_t pid; // 투표 한사람 PID - uint32_t selectedpid; // 투표 당한 PID ( 군주 참가자 ) - char date[32]; // 투표 날짜 -} MonarchElectionInfo; - -// 군주 출마자 -typedef struct tMonarchCandidacy -{ - uint32_t pid; - char name[32]; - char date[32]; -} MonarchCandidacy; - -typedef struct tChangeMonarchLord -{ - uint8_t bEmpire; - uint32_t dwPID; -} TPacketChangeMonarchLord; - -typedef struct tChangeMonarchLordACK -{ - uint8_t bEmpire; - uint32_t dwPID; - char szName[32]; - char szDate[32]; -} TPacketChangeMonarchLordACK; - typedef struct tChangeGuildMaster { uint32_t dwGuildID; diff --git a/src/db/ClientManager.cpp b/src/db/ClientManager.cpp index ccf45ed..56b9e4e 100644 --- a/src/db/ClientManager.cpp +++ b/src/db/ClientManager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "common/building.h" #include "common/VnumHelper.h" @@ -15,7 +15,6 @@ #include "MoneyLog.h" #include "ItemAwardManager.h" #include "Marriage.h" -#include "Monarch.h" #include "ItemIDRangeManager.h" #include "Cache.h" @@ -273,11 +272,9 @@ void CClientManager::QUERY_BOOT(CPeer* peer, TPacketGDBoot * p) sizeof(WORD) + sizeof(WORD) + 16 * vHost.size() + sizeof(WORD) + sizeof(WORD) + sizeof(tAdminInfo) * vAdmin.size() + //END_ADMIN_MANAGER - sizeof(WORD) + sizeof(WORD) + sizeof(TMonarchInfo) + - sizeof(WORD) + sizeof(WORD) + sizeof(MonarchCandidacy)* CMonarch::instance().MonarchCandidacySize() + - sizeof(WORD); + sizeof(WORD); - peer->EncodeHeader(HEADER_DG_BOOT, 0, dwPacketSize); + peer->EncodeHeader(DG::BOOT, 0, dwPacketSize); peer->Encode(&dwPacketSize, sizeof(DWORD)); peer->Encode(&bPacketVersion, sizeof(BYTE)); @@ -298,8 +295,6 @@ void CClientManager::QUERY_BOOT(CPeer* peer, TPacketGDBoot * p) //ADMIN_MANAGER sys_log(0, "sizeof(tAdminInfo) = %d * %d ", sizeof(tAdminInfo) * vAdmin.size()); //END_ADMIN_MANAGER - sys_log(0, "sizeof(TMonarchInfo) = %d * %d", sizeof(TMonarchInfo)); - peer->EncodeWORD(sizeof(TMobTable)); peer->EncodeWORD(m_vec_mobTable.size()); peer->Encode(&m_vec_mobTable[0], sizeof(TMobTable) * m_vec_mobTable.size()); @@ -382,24 +377,6 @@ void CClientManager::QUERY_BOOT(CPeer* peer, TPacketGDBoot * p) } //END_ADMIN_MANAGER - //MONARCH - peer->EncodeWORD(sizeof(TMonarchInfo)); - peer->EncodeWORD(1); - peer->Encode(CMonarch::instance().GetMonarch(), sizeof(TMonarchInfo)); - - CMonarch::VEC_MONARCHCANDIDACY & rVecMonarchCandidacy = CMonarch::instance().GetVecMonarchCandidacy(); - - size_t num_monarch_candidacy = CMonarch::instance().MonarchCandidacySize(); - peer->EncodeWORD(sizeof(MonarchCandidacy)); - peer->EncodeWORD(num_monarch_candidacy); - if (num_monarch_candidacy != 0) { - peer->Encode(&rVecMonarchCandidacy[0], sizeof(MonarchCandidacy) * num_monarch_candidacy); - } - //END_MONARCE - - if (g_test_server) - sys_log(0, "MONARCHCandidacy Size %d", CMonarch::instance().MonarchCandidacySize()); - peer->EncodeWORD(0xffff); } @@ -410,18 +387,18 @@ void CClientManager::SendPartyOnSetup(CPeer* pkPeer) for (itertype(pm) it_party = pm.begin(); it_party != pm.end(); ++it_party) { sys_log(0, "PARTY SendPartyOnSetup Party [%u]", it_party->first); - pkPeer->EncodeHeader(HEADER_DG_PARTY_CREATE, 0, sizeof(TPacketPartyCreate)); + pkPeer->EncodeHeader(DG::PARTY_CREATE, 0, sizeof(TPacketPartyCreate)); pkPeer->Encode(&it_party->first, sizeof(DWORD)); for (itertype(it_party->second) it_member = it_party->second.begin(); it_member != it_party->second.end(); ++it_member) { sys_log(0, "PARTY SendPartyOnSetup Party [%u] Member [%u]", it_party->first, it_member->first); - pkPeer->EncodeHeader(HEADER_DG_PARTY_ADD, 0, sizeof(TPacketPartyAdd)); + pkPeer->EncodeHeader(DG::PARTY_ADD, 0, sizeof(TPacketPartyAdd)); pkPeer->Encode(&it_party->first, sizeof(DWORD)); pkPeer->Encode(&it_member->first, sizeof(DWORD)); pkPeer->Encode(&it_member->second.bRole, sizeof(BYTE)); - pkPeer->EncodeHeader(HEADER_DG_PARTY_SET_MEMBER_LEVEL, 0, sizeof(TPacketPartySetMemberLevel)); + pkPeer->EncodeHeader(DG::PARTY_SET_MEMBER_LEVEL, 0, sizeof(TPacketPartySetMemberLevel)); pkPeer->Encode(&it_party->first, sizeof(DWORD)); pkPeer->Encode(&it_member->first, sizeof(DWORD)); pkPeer->Encode(&it_member->second.bLevel, sizeof(BYTE)); @@ -480,7 +457,7 @@ void CClientManager::QUERY_SAFEBOX_LOAD(CPeer * pkPeer, DWORD dwHandle, TSafebox GetTablePostfix(), packet->dwID); if (g_log) - sys_log(0, "HEADER_GD_SAFEBOX_LOAD (handle: %d account.id %u is_mall %d)", dwHandle, packet->dwID, bMall ? 1 : 0); + sys_log(0, "GD::SAFEBOX_LOAD (handle: %d account.id %u is_mall %d)", dwHandle, packet->dwID, bMall ? 1 : 0); CDBManager::instance().ReturnQuery(szQuery, QID_SAFEBOX_LOAD, pkPeer->GetHandle(), pi); } @@ -509,7 +486,7 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg) { if (strcmp("000000", szSafeboxPassword)) { - pkPeer->EncodeHeader(HEADER_DG_SAFEBOX_WRONG_PASSWORD, dwHandle, 0); + pkPeer->EncodeHeader(DG::SAFEBOX_WRONG_PASSWORD, dwHandle, 0); delete pSafebox; delete pi; return; @@ -523,7 +500,7 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg) if (((!row[2] || !*row[2]) && strcmp("000000", szSafeboxPassword)) || ((row[2] && *row[2]) && strcmp(row[2], szSafeboxPassword))) { - pkPeer->EncodeHeader(HEADER_DG_SAFEBOX_WRONG_PASSWORD, dwHandle, 0); + pkPeer->EncodeHeader(DG::SAFEBOX_WRONG_PASSWORD, dwHandle, 0); delete pSafebox; delete pi; return; @@ -796,7 +773,7 @@ void CClientManager::RESULT_SAFEBOX_LOAD(CPeer * pkPeer, SQLMsg * msg) pi->pSafebox->wItemCount = s_items.size(); - pkPeer->EncodeHeader(pi->ip[0] == 0 ? HEADER_DG_SAFEBOX_LOAD : HEADER_DG_MALL_LOAD, dwHandle, sizeof(TSafeboxTable) + sizeof(TPlayerItem) * s_items.size()); + pkPeer->EncodeHeader(pi->ip[0] == 0 ? DG::SAFEBOX_LOAD : DG::MALL_LOAD, dwHandle, sizeof(TSafeboxTable) + sizeof(TPlayerItem) * s_items.size()); pkPeer->Encode(pi->pSafebox, sizeof(TSafeboxTable)); @@ -833,7 +810,7 @@ void CClientManager::RESULT_SAFEBOX_CHANGE_SIZE(CPeer * pkPeer, SQLMsg * msg) if (msg->Get()->uiNumRows > 0) { - pkPeer->EncodeHeader(HEADER_DG_SAFEBOX_CHANGE_SIZE, dwHandle, sizeof(BYTE)); + pkPeer->EncodeHeader(DG::SAFEBOX_CHANGE_SIZE, dwHandle, sizeof(BYTE)); pkPeer->EncodeBYTE(bSize); } } @@ -877,7 +854,7 @@ void CClientManager::RESULT_SAFEBOX_CHANGE_PASSWORD(CPeer * pkPeer, SQLMsg * msg delete p; // Wrong old password - pkPeer->EncodeHeader(HEADER_DG_SAFEBOX_CHANGE_PASSWORD_ANSWER, dwHandle, sizeof(BYTE)); + pkPeer->EncodeHeader(DG::SAFEBOX_CHANGE_PASSWORD_ANSWER, dwHandle, sizeof(BYTE)); pkPeer->EncodeBYTE(0); } @@ -888,7 +865,7 @@ void CClientManager::RESULT_SAFEBOX_CHANGE_PASSWORD_SECOND(CPeer * pkPeer, SQLMs DWORD dwHandle = p->dwHandle; delete p; - pkPeer->EncodeHeader(HEADER_DG_SAFEBOX_CHANGE_PASSWORD_ANSWER, dwHandle, sizeof(BYTE)); + pkPeer->EncodeHeader(DG::SAFEBOX_CHANGE_PASSWORD_ANSWER, dwHandle, sizeof(BYTE)); pkPeer->EncodeBYTE(1); } @@ -930,7 +907,7 @@ void CClientManager::RESULT_PRICELIST_LOAD(CPeer* peer, SQLMsg* pMsg) size_t sizePriceListSize = sizeof(TItemPriceInfo) * header.byCount; - peer->EncodeHeader(HEADER_DG_MYSHOP_PRICELIST_RES, pReqInfo->first, sizeof(header) + sizePriceListSize); + peer->EncodeHeader(DG::MYSHOP_PRICELIST_RES, pReqInfo->first, sizeof(header) + sizePriceListSize); peer->Encode(&header, sizeof(header)); peer->Encode(table.aPriceInfo, sizePriceListSize); @@ -1046,7 +1023,7 @@ void CClientManager::QUERY_EMPIRE_SELECT(CPeer * pkPeer, DWORD dwHandle, TEmpire } } - pkPeer->EncodeHeader(HEADER_DG_EMPIRE_SELECT, dwHandle, sizeof(BYTE)); + pkPeer->EncodeHeader(DG::EMPIRE_SELECT, dwHandle, sizeof(BYTE)); pkPeer->EncodeBYTE(p->bEmpire); } @@ -1102,7 +1079,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD thecore_memcpy(kMapLocation2.alMaps, tmp->GetMaps(), sizeof(kMapLocation2.alMaps)); vec_kMapLocations.push_back(kMapLocation2); - tmp->EncodeHeader(HEADER_DG_MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation)); + tmp->EncodeHeader(DG::MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation)); bMapCount = 1; tmp->EncodeBYTE(bMapCount); tmp->Encode(&kMapLocations, sizeof(TMapLocation)); @@ -1130,7 +1107,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD vec_kMapLocations.push_back(kMapLocation2); } - tmp->EncodeHeader(HEADER_DG_MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation)); + tmp->EncodeHeader(DG::MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation)); bMapCount = 1; tmp->EncodeBYTE(bMapCount); tmp->Encode(&kMapLocations, sizeof(TMapLocation)); @@ -1161,7 +1138,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD if (tmp->GetChannel() == peer->GetChannel()) { - tmp->EncodeHeader(HEADER_DG_MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation)); + tmp->EncodeHeader(DG::MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation)); bMapCount = 1; tmp->EncodeBYTE(bMapCount); tmp->Encode(&kMapLocations, sizeof(TMapLocation)); @@ -1171,7 +1148,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD vec_kMapLocations.push_back(kMapLocations); - peer->EncodeHeader(HEADER_DG_MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation) * vec_kMapLocations.size()); + peer->EncodeHeader(DG::MAP_LOCATIONS, 0, sizeof(BYTE) + sizeof(TMapLocation) * vec_kMapLocations.size()); bMapCount = vec_kMapLocations.size(); peer->EncodeBYTE(bMapCount); peer->Encode(&vec_kMapLocations[0], sizeof(TMapLocation) * vec_kMapLocations.size()); @@ -1197,7 +1174,7 @@ void CClientManager::QUERY_SETUP(CPeer * peer, DWORD dwHandle, const char * c_pD if (0 == tmp->GetChannel()) continue; - tmp->EncodeHeader(HEADER_DG_P2P, 0, sizeof(TPacketDGP2P)); + tmp->EncodeHeader(DG::P2P, 0, sizeof(TPacketDGP2P)); tmp->Encode(&p2pSetupPacket, sizeof(TPacketDGP2P)); } @@ -1243,7 +1220,7 @@ void CClientManager::QUERY_ITEM_FLUSH(CPeer * pkPeer, const char * c_pData) DWORD dwID = *(DWORD *) c_pData; if (g_log) - sys_log(0, "HEADER_GD_ITEM_FLUSH: %u", dwID); + sys_log(0, "GD::ITEM_FLUSH: %u", dwID); CItemCache * c = GetItemCache(dwID); @@ -1563,7 +1540,7 @@ void CClientManager::QUERY_ITEM_DESTROY(CPeer * pkPeer, const char * c_pData) snprintf(szQuery, sizeof(szQuery), "DELETE FROM item%s WHERE id=%u", GetTablePostfix(), dwID); if (g_log) - sys_log(0, "HEADER_GD_ITEM_DESTROY: PID %u ID %u", dwPID, dwID); + sys_log(0, "GD::ITEM_DESTROY: PID %u ID %u", dwPID, dwID); if (dwPID == 0) // 아무도 가진 사람이 없었다면, 비동기 쿼리 CDBManager::instance().AsyncQuery(szQuery); @@ -1590,22 +1567,6 @@ void CClientManager::QUERY_FLUSH_CACHE(CPeer * pkPeer, const char * c_pData) delete pkCache; } -void CClientManager::QUERY_SMS(CPeer * pkPeer, TPacketGDSMS * pack) -{ - char szQuery[QUERY_MAX_LEN]; - - char szMsg[256+1]; - //unsigned long len = CDBManager::instance().EscapeString(szMsg, pack->szMsg, strlen(pack->szMsg), SQL_ACCOUNT); - unsigned long len = CDBManager::instance().EscapeString(szMsg, pack->szMsg, strlen(pack->szMsg)); - szMsg[len] = '\0'; - - snprintf(szQuery, sizeof(szQuery), - "INSERT INTO sms_pool (server, sender, receiver, mobile, msg) VALUES(%d, '%s', '%s', '%s', '%s')", - (m_iPlayerIDStart + 2) / 3, pack->szFrom, pack->szTo, pack->szMobile, szMsg); - - CDBManager::instance().AsyncQuery(szQuery); -} - void CClientManager::QUERY_RELOAD_PROTO() { if (!InitializeTables()) @@ -1621,7 +1582,7 @@ void CClientManager::QUERY_RELOAD_PROTO() if (!tmp->GetChannel()) continue; - tmp->EncodeHeader(HEADER_DG_RELOAD_PROTO, 0, + tmp->EncodeHeader(DG::RELOAD_PROTO, 0, sizeof(WORD) + sizeof(TSkillTable) * m_vec_skillTable.size() + sizeof(WORD) + sizeof(TBanwordTable) * m_vec_banwordTable.size() + sizeof(WORD) + sizeof(TItemTable) * m_vec_itemTable.size() + @@ -1739,7 +1700,7 @@ void CClientManager::QUERY_AUTH_LOGIN(CPeer * pkPeer, DWORD dwHandle, TPacketGDA sys_err("LoginData already exist key %u login %s", p->dwLoginKey, p->szLogin); bResult = 0; - pkPeer->EncodeHeader(HEADER_DG_AUTH_LOGIN, dwHandle, sizeof(BYTE)); + pkPeer->EncodeHeader(DG::AUTH_LOGIN, dwHandle, sizeof(BYTE)); pkPeer->EncodeBYTE(bResult); } else @@ -1763,7 +1724,7 @@ void CClientManager::QUERY_AUTH_LOGIN(CPeer * pkPeer, DWORD dwHandle, TPacketGDA InsertLoginData(pkLD); - pkPeer->EncodeHeader(HEADER_DG_AUTH_LOGIN, dwHandle, sizeof(BYTE)); + pkPeer->EncodeHeader(DG::AUTH_LOGIN, dwHandle, sizeof(BYTE)); pkPeer->EncodeBYTE(bResult); } } @@ -1821,7 +1782,7 @@ void CClientManager::CreateObject(TPacketGDCreateObject * p) pkObj->zRot = p->zRot; pkObj->lLife = 0; - ForwardPacket(HEADER_DG_CREATE_OBJECT, pkObj, sizeof(TObject)); + ForwardPacket(DG::CREATE_OBJECT, pkObj, sizeof(TObject)); m_map_pkObjectTable.insert(std::make_pair(pkObj->dwID, pkObj)); } @@ -1848,7 +1809,7 @@ void CClientManager::DeleteObject(DWORD dwID) m_map_pkObjectTable.erase(it); } - ForwardPacket(HEADER_DG_DELETE_OBJECT, &dwID, sizeof(DWORD)); + ForwardPacket(DG::DELETE_OBJECT, &dwID, sizeof(DWORD)); } void CClientManager::UpdateLand(DWORD * pdw) @@ -1874,7 +1835,7 @@ void CClientManager::UpdateLand(DWORD * pdw) } if (i < m_vec_kLandTable.size()) - ForwardPacket(HEADER_DG_UPDATE_LAND, p, sizeof(building::TLand)); + ForwardPacket(DG::UPDATE_LAND, p, sizeof(building::TLand)); } // BLOCK_CHAT @@ -1933,14 +1894,14 @@ void CClientManager::MarriageRemove(TPacketMarriageRemove * p) void CClientManager::WeddingRequest(TPacketWeddingRequest * p) { sys_log(0, "WeddingRequest %u %u", p->dwPID1, p->dwPID2); - ForwardPacket(HEADER_DG_WEDDING_REQUEST, p, sizeof(TPacketWeddingRequest)); + ForwardPacket(DG::WEDDING_REQUEST, p, sizeof(TPacketWeddingRequest)); //marriage::CManager::instance().RegisterWedding(p->dwPID1, p->szName1, p->dwPID2, p->szName2); } void CClientManager::WeddingReady(TPacketWeddingReady * p) { sys_log(0, "WeddingReady %u %u", p->dwPID1, p->dwPID2); - ForwardPacket(HEADER_DG_WEDDING_READY, p, sizeof(TPacketWeddingReady)); + ForwardPacket(DG::WEDDING_READY, p, sizeof(TPacketWeddingReady)); marriage::CManager::instance().ReadyWedding(p->dwMapIndex, p->dwPID1, p->dwPID2); } @@ -2050,7 +2011,7 @@ void CClientManager::MyshopPricelistRequest(CPeer* peer, DWORD dwHandle, DWORD d size_t sizePriceListSize = sizeof(TItemPriceInfo) * pTable->byCount; - peer->EncodeHeader(HEADER_DG_MYSHOP_PRICELIST_RES, dwHandle, sizeof(header) + sizePriceListSize); + peer->EncodeHeader(DG::MYSHOP_PRICELIST_RES, dwHandle, sizeof(header) + sizePriceListSize); peer->Encode(&header, sizeof(header)); peer->Encode(pTable->aPriceInfo, sizePriceListSize); @@ -2083,7 +2044,7 @@ void CPacketInfo::Reset() void CClientManager::ProcessPackets(CPeer * peer) { - BYTE header; + uint16_t header; DWORD dwHandle; DWORD dwLength; const char * data = NULL; @@ -2095,7 +2056,7 @@ void CClientManager::ProcessPackets(CPeer * peer) // DISABLE_DB_HEADER_LOG // sys_log(0, "header %d %p size %d", header, this, dwLength); // END_OF_DISABLE_DB_HEADER_LOG - m_bLastHeader = header; + m_wLastHeader = header; ++iCount; #ifdef _TEST @@ -2110,378 +2071,332 @@ void CClientManager::ProcessPackets(CPeer * peer) switch (header) { - case HEADER_GD_BOOT: + case GD::BOOT: QUERY_BOOT(peer, (TPacketGDBoot *) data); break; - case HEADER_GD_HAMMER_OF_TOR: + case GD::HAMMER_OF_TOR: break; - case HEADER_GD_LOGIN_BY_KEY: + case GD::LOGIN_BY_KEY: QUERY_LOGIN_BY_KEY(peer, dwHandle, (TPacketGDLoginByKey *) data); break; - case HEADER_GD_LOGOUT: - //sys_log(0, "HEADER_GD_LOGOUT (handle: %d length: %d)", dwHandle, dwLength); + case GD::LOGOUT: + //sys_log(0, "GD::LOGOUT (handle: %d length: %d)", dwHandle, dwLength); QUERY_LOGOUT(peer, dwHandle, data); break; - case HEADER_GD_PLAYER_LOAD: - sys_log(1, "HEADER_GD_PLAYER_LOAD (handle: %d length: %d)", dwHandle, dwLength); + case GD::PLAYER_LOAD: + sys_log(1, "GD::PLAYER_LOAD (handle: %d length: %d)", dwHandle, dwLength); QUERY_PLAYER_LOAD(peer, dwHandle, (TPlayerLoadPacket *) data); break; - case HEADER_GD_PLAYER_SAVE: - sys_log(1, "HEADER_GD_PLAYER_SAVE (handle: %d length: %d)", dwHandle, dwLength); + case GD::PLAYER_SAVE: + sys_log(1, "GD::PLAYER_SAVE (handle: %d length: %d)", dwHandle, dwLength); QUERY_PLAYER_SAVE(peer, dwHandle, (TPlayerTable *) data); break; - case HEADER_GD_PLAYER_CREATE: - sys_log(0, "HEADER_GD_PLAYER_CREATE (handle: %d length: %d)", dwHandle, dwLength); + case GD::PLAYER_CREATE: + sys_log(0, "GD::PLAYER_CREATE (handle: %d length: %d)", dwHandle, dwLength); __QUERY_PLAYER_CREATE(peer, dwHandle, (TPlayerCreatePacket *) data); sys_log(0, "END"); break; - case HEADER_GD_PLAYER_DELETE: - sys_log(1, "HEADER_GD_PLAYER_DELETE (handle: %d length: %d)", dwHandle, dwLength); + case GD::PLAYER_DELETE: + sys_log(1, "GD::PLAYER_DELETE (handle: %d length: %d)", dwHandle, dwLength); __QUERY_PLAYER_DELETE(peer, dwHandle, (TPlayerDeletePacket *) data); break; - case HEADER_GD_PLAYER_COUNT: + case GD::PLAYER_COUNT: QUERY_PLAYER_COUNT(peer, (TPlayerCountPacket *) data); break; - case HEADER_GD_QUEST_SAVE: - sys_log(1, "HEADER_GD_QUEST_SAVE (handle: %d length: %d)", dwHandle, dwLength); + case GD::QUEST_SAVE: + sys_log(1, "GD::QUEST_SAVE (handle: %d length: %d)", dwHandle, dwLength); QUERY_QUEST_SAVE(peer, (TQuestTable *) data, dwLength); break; - case HEADER_GD_SAFEBOX_LOAD: + case GD::SAFEBOX_LOAD: QUERY_SAFEBOX_LOAD(peer, dwHandle, (TSafeboxLoadPacket *) data, 0); break; - case HEADER_GD_SAFEBOX_SAVE: - sys_log(1, "HEADER_GD_SAFEBOX_SAVE (handle: %d length: %d)", dwHandle, dwLength); + case GD::SAFEBOX_SAVE: + sys_log(1, "GD::SAFEBOX_SAVE (handle: %d length: %d)", dwHandle, dwLength); QUERY_SAFEBOX_SAVE(peer, (TSafeboxTable *) data); break; - case HEADER_GD_SAFEBOX_CHANGE_SIZE: + case GD::SAFEBOX_CHANGE_SIZE: QUERY_SAFEBOX_CHANGE_SIZE(peer, dwHandle, (TSafeboxChangeSizePacket *) data); break; - case HEADER_GD_SAFEBOX_CHANGE_PASSWORD: + case GD::SAFEBOX_CHANGE_PASSWORD: QUERY_SAFEBOX_CHANGE_PASSWORD(peer, dwHandle, (TSafeboxChangePasswordPacket *) data); break; - case HEADER_GD_MALL_LOAD: + case GD::MALL_LOAD: QUERY_SAFEBOX_LOAD(peer, dwHandle, (TSafeboxLoadPacket *) data, 1); break; - case HEADER_GD_EMPIRE_SELECT: + case GD::EMPIRE_SELECT: QUERY_EMPIRE_SELECT(peer, dwHandle, (TEmpireSelectPacket *) data); break; - case HEADER_GD_SETUP: + case GD::SETUP: QUERY_SETUP(peer, dwHandle, data); break; - case HEADER_GD_GUILD_CREATE: + case GD::GUILD_CREATE: GuildCreate(peer, *(DWORD *) data); break; - case HEADER_GD_GUILD_SKILL_UPDATE: + case GD::GUILD_SKILL_UPDATE: GuildSkillUpdate(peer, (TPacketGuildSkillUpdate *) data); break; - case HEADER_GD_GUILD_EXP_UPDATE: + case GD::GUILD_EXP_UPDATE: GuildExpUpdate(peer, (TPacketGuildExpUpdate *) data); break; - case HEADER_GD_GUILD_ADD_MEMBER: + case GD::GUILD_ADD_MEMBER: GuildAddMember(peer, (TPacketGDGuildAddMember*) data); break; - case HEADER_GD_GUILD_REMOVE_MEMBER: + case GD::GUILD_REMOVE_MEMBER: GuildRemoveMember(peer, (TPacketGuild*) data); break; - case HEADER_GD_GUILD_CHANGE_GRADE: + case GD::GUILD_CHANGE_GRADE: GuildChangeGrade(peer, (TPacketGuild*) data); break; - case HEADER_GD_GUILD_CHANGE_MEMBER_DATA: + case GD::GUILD_CHANGE_MEMBER_DATA: GuildChangeMemberData(peer, (TPacketGuildChangeMemberData*) data); break; - case HEADER_GD_GUILD_DISBAND: + case GD::GUILD_DISBAND: GuildDisband(peer, (TPacketGuild*) data); break; - case HEADER_GD_GUILD_WAR: + case GD::GUILD_WAR: GuildWar(peer, (TPacketGuildWar*) data); break; - case HEADER_GD_GUILD_WAR_SCORE: + case GD::GUILD_WAR_SCORE: GuildWarScore(peer, (TPacketGuildWarScore*) data); break; - case HEADER_GD_GUILD_CHANGE_LADDER_POINT: + case GD::GUILD_CHANGE_LADDER_POINT: GuildChangeLadderPoint((TPacketGuildLadderPoint*) data); break; - case HEADER_GD_GUILD_USE_SKILL: + case GD::GUILD_USE_SKILL: GuildUseSkill((TPacketGuildUseSkill*) data); break; - case HEADER_GD_FLUSH_CACHE: + case GD::FLUSH_CACHE: QUERY_FLUSH_CACHE(peer, data); break; - case HEADER_GD_ITEM_SAVE: + case GD::ITEM_SAVE: QUERY_ITEM_SAVE(peer, data); break; - case HEADER_GD_ITEM_DESTROY: + case GD::ITEM_DESTROY: QUERY_ITEM_DESTROY(peer, data); break; - case HEADER_GD_ITEM_FLUSH: + case GD::ITEM_FLUSH: QUERY_ITEM_FLUSH(peer, data); break; - case HEADER_GD_ADD_AFFECT: - sys_log(1, "HEADER_GD_ADD_AFFECT"); + case GD::ADD_AFFECT: + sys_log(1, "GD::ADD_AFFECT"); QUERY_ADD_AFFECT(peer, (TPacketGDAddAffect *) data); break; - case HEADER_GD_REMOVE_AFFECT: - sys_log(1, "HEADER_GD_REMOVE_AFFECT"); + case GD::REMOVE_AFFECT: + sys_log(1, "GD::REMOVE_AFFECT"); QUERY_REMOVE_AFFECT(peer, (TPacketGDRemoveAffect *) data); break; - case HEADER_GD_HIGHSCORE_REGISTER: + case GD::HIGHSCORE_REGISTER: QUERY_HIGHSCORE_REGISTER(peer, (TPacketGDHighscore *) data); break; - case HEADER_GD_PARTY_CREATE: + case GD::PARTY_CREATE: QUERY_PARTY_CREATE(peer, (TPacketPartyCreate*) data); break; - case HEADER_GD_PARTY_DELETE: + case GD::PARTY_DELETE: QUERY_PARTY_DELETE(peer, (TPacketPartyDelete*) data); break; - case HEADER_GD_PARTY_ADD: + case GD::PARTY_ADD: QUERY_PARTY_ADD(peer, (TPacketPartyAdd*) data); break; - case HEADER_GD_PARTY_REMOVE: + case GD::PARTY_REMOVE: QUERY_PARTY_REMOVE(peer, (TPacketPartyRemove*) data); break; - case HEADER_GD_PARTY_STATE_CHANGE: + case GD::PARTY_STATE_CHANGE: QUERY_PARTY_STATE_CHANGE(peer, (TPacketPartyStateChange*) data); break; - case HEADER_GD_PARTY_SET_MEMBER_LEVEL: + case GD::PARTY_SET_MEMBER_LEVEL: QUERY_PARTY_SET_MEMBER_LEVEL(peer, (TPacketPartySetMemberLevel*) data); break; - case HEADER_GD_RELOAD_PROTO: + case GD::RELOAD_PROTO: QUERY_RELOAD_PROTO(); break; - case HEADER_GD_CHANGE_NAME: + case GD::CHANGE_NAME: QUERY_CHANGE_NAME(peer, dwHandle, (TPacketGDChangeName *) data); break; - case HEADER_GD_SMS: - QUERY_SMS(peer, (TPacketGDSMS *) data); - break; - - case HEADER_GD_AUTH_LOGIN: + case GD::AUTH_LOGIN: QUERY_AUTH_LOGIN(peer, dwHandle, (TPacketGDAuthLogin *) data); break; - case HEADER_GD_REQUEST_GUILD_PRIV: + case GD::REQUEST_GUILD_PRIV: AddGuildPriv((TPacketGiveGuildPriv*)data); break; - case HEADER_GD_REQUEST_EMPIRE_PRIV: + case GD::REQUEST_EMPIRE_PRIV: AddEmpirePriv((TPacketGiveEmpirePriv*)data); break; - case HEADER_GD_REQUEST_CHARACTER_PRIV: + case GD::REQUEST_CHARACTER_PRIV: AddCharacterPriv((TPacketGiveCharacterPriv*) data); break; - case HEADER_GD_MONEY_LOG: + case GD::MONEY_LOG: MoneyLog((TPacketMoneyLog*)data); break; - case HEADER_GD_GUILD_DEPOSIT_MONEY: + case GD::GUILD_DEPOSIT_MONEY: GuildDepositMoney((TPacketGDGuildMoney*)data); break; - case HEADER_GD_GUILD_WITHDRAW_MONEY: + case GD::GUILD_WITHDRAW_MONEY: GuildWithdrawMoney(peer, (TPacketGDGuildMoney*)data); break; - case HEADER_GD_GUILD_WITHDRAW_MONEY_GIVE_REPLY: + case GD::GUILD_WITHDRAW_MONEY_GIVE_REPLY: GuildWithdrawMoneyGiveReply((TPacketGDGuildMoneyWithdrawGiveReply*)data); break; - case HEADER_GD_GUILD_WAR_BET: + case GD::GUILD_WAR_BET: GuildWarBet((TPacketGDGuildWarBet *) data); break; - case HEADER_GD_SET_EVENT_FLAG: + case GD::SET_EVENT_FLAG: SetEventFlag((TPacketSetEventFlag*) data); break; - case HEADER_GD_CREATE_OBJECT: + case GD::CREATE_OBJECT: CreateObject((TPacketGDCreateObject *) data); break; - case HEADER_GD_DELETE_OBJECT: + case GD::DELETE_OBJECT: DeleteObject(*(DWORD *) data); break; - case HEADER_GD_UPDATE_LAND: + case GD::UPDATE_LAND: UpdateLand((DWORD *) data); break; - case HEADER_GD_MARRIAGE_ADD: + case GD::MARRIAGE_ADD: MarriageAdd((TPacketMarriageAdd *) data); break; - case HEADER_GD_MARRIAGE_UPDATE: + case GD::MARRIAGE_UPDATE: MarriageUpdate((TPacketMarriageUpdate *) data); break; - case HEADER_GD_MARRIAGE_REMOVE: + case GD::MARRIAGE_REMOVE: MarriageRemove((TPacketMarriageRemove *) data); break; - case HEADER_GD_WEDDING_REQUEST: + case GD::WEDDING_REQUEST: WeddingRequest((TPacketWeddingRequest *) data); break; - case HEADER_GD_WEDDING_READY: + case GD::WEDDING_READY: WeddingReady((TPacketWeddingReady *) data); break; - case HEADER_GD_WEDDING_END: + case GD::WEDDING_END: WeddingEnd((TPacketWeddingEnd *) data); break; // BLOCK_CHAT - case HEADER_GD_BLOCK_CHAT: + case GD::BLOCK_CHAT: BlockChat((TPacketBlockChat *) data); break; // END_OF_BLOCK_CHAT // MYSHOP_PRICE_LIST - case HEADER_GD_MYSHOP_PRICELIST_UPDATE: + case GD::MYSHOP_PRICELIST_UPDATE: // MyshopPricelistUpdate((TPacketMyshopPricelistHeader*)data); MyshopPricelistUpdate((TItemPriceListTable*)data); break; - case HEADER_GD_MYSHOP_PRICELIST_REQ: + case GD::MYSHOP_PRICELIST_REQ: MyshopPricelistRequest(peer, dwHandle, *(DWORD*)data); break; // END_OF_MYSHOP_PRICE_LIST //RELOAD_ADMIN - case HEADER_GD_RELOAD_ADMIN: + case GD::RELOAD_ADMIN: ReloadAdmin(peer, (TPacketReloadAdmin*)data); break; //END_RELOAD_ADMIN - case HEADER_GD_BREAK_MARRIAGE: + case GD::BREAK_MARRIAGE: BreakMarriage(peer, data); break; - //MOANRCH - case HEADER_GD_ELECT_MONARCH: - Election(peer, dwHandle, data); - break; - - case HEADER_GD_CANDIDACY: - Candidacy(peer, dwHandle, data); - break; - - case HEADER_GD_ADD_MONARCH_MONEY: - AddMonarchMoney(peer, dwHandle, data); - break; - - case HEADER_GD_DEC_MONARCH_MONEY: - DecMonarchMoney(peer, dwHandle, data); - break; - - case HEADER_GD_TAKE_MONARCH_MONEY: - TakeMonarchMoney(peer, dwHandle, data); - break; - - case HEADER_GD_COME_TO_VOTE: - ComeToVote(peer, dwHandle, data); - break; - - case HEADER_GD_RMCANDIDACY: //< 후보 제거 (운영자) - RMCandidacy(peer, dwHandle, data); - break; - - case HEADER_GD_SETMONARCH: ///<군주설정 (운영자) - SetMonarch(peer, dwHandle, data); - break; - - case HEADER_GD_RMMONARCH: ///<군주삭제 - RMMonarch(peer, dwHandle, data); - break; - //END_MONARCH - - case HEADER_GD_CHANGE_MONARCH_LORD : - ChangeMonarchLord(peer, dwHandle, (TPacketChangeMonarchLord*)data); - break; - - case HEADER_GD_REQ_SPARE_ITEM_ID_RANGE : + case GD::REQ_SPARE_ITEM_ID_RANGE : SendSpareItemIDRange(peer); break; - case HEADER_GD_REQ_CHANGE_GUILD_MASTER : + case GD::REQ_CHANGE_GUILD_MASTER : GuildChangeMaster((TPacketChangeGuildMaster*) data); break; - case HEADER_GD_UPDATE_HORSE_NAME : + case GD::UPDATE_HORSE_NAME : UpdateHorseName((TPacketUpdateHorseName*) data, peer); break; - case HEADER_GD_REQ_HORSE_NAME : + case GD::REQ_HORSE_NAME : AckHorseName(*(DWORD*)data, peer); break; - case HEADER_GD_DC: + case GD::DC: DeleteLoginKey((TPacketDC*) data); break; - case HEADER_GD_VALID_LOGOUT: + case GD::VALID_LOGOUT: ResetLastPlayerID((TPacketNeedLoginLogInfo*)data); break; - case HEADER_GD_REQUEST_CHARGE_CASH: + case GD::REQUEST_CHARGE_CASH: ChargeCash((TRequestChargeCash*)data); break; //delete gift notify icon - case HEADER_GD_DELETE_AWARDID: + case GD::DELETE_AWARDID: DeleteAwardId((TPacketDeleteAwardID*) data); break; - case HEADER_GD_UPDATE_CHANNELSTATUS: + case GD::UPDATE_CHANNELSTATUS: UpdateChannelStatus((SChannelStatus*) data); break; - case HEADER_GD_REQUEST_CHANNELSTATUS: + case GD::REQUEST_CHANNELSTATUS: RequestChannelStatus(peer, dwHandle); break; @@ -2614,27 +2529,27 @@ int CClientManager::AnalyzeQueryResult(SQLMsg * msg) break; case QID_SAFEBOX_LOAD: - sys_log(0, "QUERY_RESULT: HEADER_GD_SAFEBOX_LOAD"); + sys_log(0, "QUERY_RESULT: GD::SAFEBOX_LOAD"); RESULT_SAFEBOX_LOAD(peer, msg); break; case QID_SAFEBOX_CHANGE_SIZE: - sys_log(0, "QUERY_RESULT: HEADER_GD_SAFEBOX_CHANGE_SIZE"); + sys_log(0, "QUERY_RESULT: GD::SAFEBOX_CHANGE_SIZE"); RESULT_SAFEBOX_CHANGE_SIZE(peer, msg); break; case QID_SAFEBOX_CHANGE_PASSWORD: - sys_log(0, "QUERY_RESULT: HEADER_GD_SAFEBOX_CHANGE_PASSWORD %p", msg); + sys_log(0, "QUERY_RESULT: GD::SAFEBOX_CHANGE_PASSWORD %p", msg); RESULT_SAFEBOX_CHANGE_PASSWORD(peer, msg); break; case QID_SAFEBOX_CHANGE_PASSWORD_SECOND: - sys_log(0, "QUERY_RESULT: HEADER_GD_SAFEBOX_CHANGE_PASSWORD %p", msg); + sys_log(0, "QUERY_RESULT: GD::SAFEBOX_CHANGE_PASSWORD %p", msg); RESULT_SAFEBOX_CHANGE_PASSWORD_SECOND(peer, msg); break; case QID_HIGHSCORE_REGISTER: - sys_log(0, "QUERY_RESULT: HEADER_GD_HIGHSCORE_REGISTER %p", msg); + sys_log(0, "QUERY_RESULT: GD::HIGHSCORE_REGISTER %p", msg); RESULT_HIGHSCORE_REGISTER(peer, msg); break; @@ -2945,16 +2860,16 @@ DWORD CClientManager::GetUserCount() void CClientManager::SendAllGuildSkillRechargePacket() { - ForwardPacket(HEADER_DG_GUILD_SKILL_RECHARGE, NULL, 0); + ForwardPacket(DG::GUILD_SKILL_RECHARGE, NULL, 0); } void CClientManager::SendTime() { time_t now = GetCurrentTime(); - ForwardPacket(HEADER_DG_TIME, &now, sizeof(time_t)); + ForwardPacket(DG::TIME, &now, sizeof(time_t)); } -void CClientManager::ForwardPacket(BYTE header, const void* data, int size, BYTE bChannel, CPeer* except) +void CClientManager::ForwardPacket(uint16_t wHeader, const void* data, int size, BYTE bChannel, CPeer* except) { for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it) { @@ -2969,7 +2884,7 @@ void CClientManager::ForwardPacket(BYTE header, const void* data, int size, BYTE if (bChannel && peer->GetChannel() != bChannel) continue; - peer->EncodeHeader(header, 0, size); + peer->EncodeHeader(wHeader, 0, size); if (size > 0 && data) peer->Encode(data, size); @@ -2986,7 +2901,7 @@ void CClientManager::SendNotice(const char * c_pszFormat, ...) va_end(args); szBuf[len] = '\0'; - ForwardPacket(HEADER_DG_NOTICE, szBuf, len + 1); + ForwardPacket(DG::NOTICE, szBuf, len + 1); } time_t CClientManager::GetCurrentTime() @@ -3524,7 +3439,7 @@ void CClientManager::ReloadAdmin(CPeer*, TPacketReloadAdmin* p) if (!peer->GetChannel()) continue; - peer->EncodeHeader(HEADER_DG_RELOAD_ADMIN, 0, dwPacketSize); + peer->EncodeHeader(DG::RELOAD_ADMIN, 0, dwPacketSize); peer->EncodeWORD(16); peer->EncodeWORD(vHost.size()); @@ -3582,362 +3497,6 @@ void CClientManager::UpdateItemCacheSet(DWORD pid) sys_log(0, "UPDATE_ITEMCACHESET : UpdateItemCachsSet pid(%d)", pid); } -void CClientManager::Election(CPeer * peer, DWORD dwHandle, const char* data) -{ - DWORD idx; - DWORD selectingpid; - - idx = *(DWORD *) data; - data += sizeof(DWORD); - - selectingpid = *(DWORD *) data; - data += sizeof(DWORD); - - int Success = 0; - - if (!(Success = CMonarch::instance().VoteMonarch(selectingpid, idx))) - { - if (g_test_server) - sys_log(0, "[MONARCH_VOTE] Failed %d %d", idx, selectingpid); - peer->EncodeHeader(HEADER_DG_ELECT_MONARCH, dwHandle, sizeof(int)); - peer->Encode(&Success, sizeof(int)); - return; - } - else - { - if (g_test_server) - sys_log(0, "[MONARCH_VOTE] Success %d %d", idx, selectingpid); - peer->EncodeHeader(HEADER_DG_ELECT_MONARCH, dwHandle, sizeof(int)); - peer->Encode(&Success, sizeof(int)); - return; - } - -} -void CClientManager::Candidacy(CPeer * peer, DWORD dwHandle, const char* data) -{ - DWORD pid; - - pid = *(DWORD *) data; - data += sizeof(DWORD); - - if (!CMonarch::instance().AddCandidacy(pid, data)) - { - if (g_test_server) - sys_log(0, "[MONARCH_CANDIDACY] Failed %d %s", pid, data); - - peer->EncodeHeader(HEADER_DG_CANDIDACY, dwHandle, sizeof(int) + 32); - peer->Encode(0, sizeof(int)); - peer->Encode(data, 32); - return; - } - else - { - if (g_test_server) - sys_log(0, "[MONARCH_CANDIDACY] Success %d %s", pid, data); - - for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it) - { - CPeer * p = *it; - - if (!p->GetChannel()) - continue; - - if (0 && p->GetChannel() != 0) - continue; - - if (p == peer) - { - p->EncodeHeader(HEADER_DG_CANDIDACY, dwHandle, sizeof(int) + 32); - p->Encode(&pid, sizeof(int)); - p->Encode(data, 32); - } - else - { - p->EncodeHeader(HEADER_DG_CANDIDACY, 0, sizeof(int) + 32); - p->Encode(&pid, sizeof(int)); - p->Encode(data, 32); - } - } - } -} - -void CClientManager::AddMonarchMoney(CPeer * peer, DWORD dwHandle, const char * data) -{ - int Empire = *(int *) data; - data += sizeof(int); - - int Money = *(int *) data; - data += sizeof(int); - - if (g_test_server) - sys_log(0, "[MONARCH] Add money Empire(%d) Money(%d)", Empire, Money); - - CMonarch::instance().AddMoney(Empire, Money); - - for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it) - { - CPeer * p = *it; - - if (!p->GetChannel()) - continue; - - if (p == peer) - { - p->EncodeHeader(HEADER_DG_ADD_MONARCH_MONEY, dwHandle, sizeof(int) + sizeof(int)); - p->Encode(&Empire, sizeof(int)); - p->Encode(&Money, sizeof(int)); - } - else - { - p->EncodeHeader(HEADER_DG_ADD_MONARCH_MONEY, 0, sizeof(int) + sizeof(int)); - p->Encode(&Empire, sizeof(int)); - p->Encode(&Money, sizeof(int)); - } - - } -} -void CClientManager::DecMonarchMoney(CPeer * peer, DWORD dwHandle, const char * data) -{ - int Empire = *(int *) data; - data += sizeof(int); - - int Money = *(int *) data; - data += sizeof(int); - - if (g_test_server) - sys_log(0, "[MONARCH] Dec money Empire(%d) Money(%d)", Empire, Money); - - CMonarch::instance().DecMoney(Empire, Money); - - for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it) - { - CPeer * p = *it; - - if (!p->GetChannel()) - continue; - - if (p == peer) - { - p->EncodeHeader(HEADER_DG_DEC_MONARCH_MONEY, dwHandle, sizeof(int) + sizeof(int)); - p->Encode(&Empire, sizeof(int)); - p->Encode(&Money, sizeof(int)); - } - else - { - p->EncodeHeader(HEADER_DG_DEC_MONARCH_MONEY, 0, sizeof(int) + sizeof(int)); - p->Encode(&Empire, sizeof(int)); - p->Encode(&Money, sizeof(int)); - } - } -} - -void CClientManager::TakeMonarchMoney(CPeer * peer, DWORD dwHandle, const char * data) -{ - int Empire = *(int *) data; - data += sizeof(int); - - DWORD pid = *(DWORD *) data; - data += sizeof(int); - - int Money = *(int *) data; - data += sizeof(int); - - if (g_test_server) - sys_log(0, "[MONARCH] Take money Empire(%d) Money(%d)", Empire, Money); - - if (CMonarch::instance().TakeMoney(Empire, pid, Money) == true) - { - peer->EncodeHeader(HEADER_DG_TAKE_MONARCH_MONEY, dwHandle, sizeof(int) + sizeof(int)); - peer->Encode(&Empire, sizeof(int)); - peer->Encode(&Money, sizeof(int)); - } - else - { - Money = 0; - peer->EncodeHeader(HEADER_DG_TAKE_MONARCH_MONEY, dwHandle, sizeof(int) + sizeof(int)); - peer->Encode(&Empire, sizeof(int)); - peer->Encode(&Money, sizeof(int)); - } -} - -void CClientManager::ComeToVote(CPeer * peer, DWORD dwHandle, const char * data) -{ - CMonarch::instance().ElectMonarch(); -} - -void CClientManager::RMCandidacy(CPeer * peer, DWORD dwHandle, const char * data) -{ - char szName[32]; - - strlcpy(szName, data, sizeof(szName)); - sys_log(0, "[MONARCH_GM] Remove candidacy name(%s)", szName); - - int iRet = CMonarch::instance().DelCandidacy(szName) ? 1 : 0; - - if (1 == iRet) - { - for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it) - { - CPeer * p = *it; - - if (!p->GetChannel()) - continue; - - if (p == peer) - { - p->EncodeHeader(HEADER_DG_RMCANDIDACY, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } - else - { - p->EncodeHeader(HEADER_DG_RMCANDIDACY, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } - } - } - else - { - CPeer * p = peer; - p->EncodeHeader(HEADER_DG_RMCANDIDACY, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } -} - -void CClientManager::SetMonarch(CPeer * peer, DWORD dwHandle, const char * data) -{ - char szName[32]; - - strlcpy(szName, data, sizeof(szName)); - - if (g_test_server) - sys_log(0, "[MONARCH_GM] Set Monarch name(%s)", szName); - - int iRet = CMonarch::instance().SetMonarch(szName) ? 1 : 0; - - if (1 == iRet) - { - for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it) - { - CPeer * p = *it; - - if (!p->GetChannel()) - continue; - - if (p == peer) - { - p->EncodeHeader(HEADER_DG_RMCANDIDACY, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } - else - { - p->EncodeHeader(HEADER_DG_RMCANDIDACY, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } - } - } - else - { - CPeer * p = peer; - p->EncodeHeader(HEADER_DG_RMCANDIDACY, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } -} - -void CClientManager::RMMonarch(CPeer * peer, DWORD dwHandle, const char * data) -{ - char szName[32]; - - strlcpy(szName, data, sizeof(szName)); - - if (g_test_server) - sys_log(0, "[MONARCH_GM] Remove Monarch name(%s)", szName); - - CMonarch::instance().DelMonarch(szName); - - int iRet = CMonarch::instance().DelMonarch(szName) ? 1 : 0; - - if (1 == iRet) - { - for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); ++it) - { - CPeer * p = *it; - - if (!p->GetChannel()) - continue; - - if (p == peer) - { - p->EncodeHeader(HEADER_DG_RMMONARCH, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } - else - { - p->EncodeHeader(HEADER_DG_RMMONARCH, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } - } - } - else - { - CPeer * p = peer; - p->EncodeHeader(HEADER_DG_RMCANDIDACY, dwHandle, sizeof(int) + sizeof(szName)); - p->Encode(&iRet, sizeof(int)); - p->Encode(szName, sizeof(szName)); - } -} - -void CClientManager::ChangeMonarchLord(CPeer * peer, DWORD dwHandle, TPacketChangeMonarchLord* info) -{ - char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), - "SELECT a.name, NOW() FROM player%s AS a, player_index%s AS b WHERE (a.account_id=b.id AND a.id=%u AND b.empire=%u) AND " - "(b.pid1=%u OR b.pid2=%u OR b.pid3=%u OR b.pid4=%u)", - GetTablePostfix(), GetTablePostfix(), info->dwPID, info->bEmpire, - info->dwPID, info->dwPID, info->dwPID, info->dwPID); - - auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER); - - if (pMsg->Get()->uiNumRows != 0) - { - TPacketChangeMonarchLordACK ack; - ack.bEmpire = info->bEmpire; - ack.dwPID = info->dwPID; - - MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult); - strlcpy(ack.szName, row[0], sizeof(ack.szName)); - strlcpy(ack.szDate, row[1], sizeof(ack.szDate)); - - snprintf(szQuery, sizeof(szQuery), "UPDATE monarch SET pid=%u, windate=NOW() WHERE empire=%d", ack.dwPID, ack.bEmpire); - auto pMsg2 = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER); - - if (pMsg2->Get()->uiAffectedRows > 0) - { - CMonarch::instance().LoadMonarch(); - - TMonarchInfo* newInfo = CMonarch::instance().GetMonarch(); - - for (itertype(m_peerList) it = m_peerList.begin(); it != m_peerList.end(); it++) - { - CPeer* client = *it; - - client->EncodeHeader(HEADER_DG_CHANGE_MONARCH_LORD_ACK, 0, sizeof(TPacketChangeMonarchLordACK)); - client->Encode(&ack, sizeof(TPacketChangeMonarchLordACK)); - - client->EncodeHeader(HEADER_DG_UPDATE_MONARCH_INFO, 0, sizeof(TMonarchInfo)); - client->Encode(newInfo, sizeof(TMonarchInfo)); - } - } - } -} - void CClientManager::SendSpareItemIDRange(CPeer* peer) { peer->SendSpareItemIDRange(); @@ -3996,7 +3555,7 @@ void CClientManager::UpdateChannelStatus(TChannelStatus* pData) void CClientManager::RequestChannelStatus(CPeer* peer, DWORD dwHandle) { const int nSize = m_mChannelStatus.size(); - peer->EncodeHeader(HEADER_DG_RESPOND_CHANNELSTATUS, dwHandle, sizeof(TChannelStatus)*nSize+sizeof(int)); + peer->EncodeHeader(DG::RESPOND_CHANNELSTATUS, dwHandle, sizeof(TChannelStatus)*nSize+sizeof(int)); peer->Encode(&nSize, sizeof(int)); for (TChannelStatusMap::iterator it = m_mChannelStatus.begin(); it != m_mChannelStatus.end(); it++) { peer->Encode(&it->first, sizeof(short)); diff --git a/src/db/ClientManager.h b/src/db/ClientManager.h index 0ce7ab3..b110780 100644 --- a/src/db/ClientManager.h +++ b/src/db/ClientManager.h @@ -1,4 +1,4 @@ -// vim:ts=8 sw=4 +// vim:ts=8 sw=4 #ifndef __INC_CLIENTMANAGER_H__ #define __INC_CLIENTMANAGER_H__ @@ -157,7 +157,7 @@ class CClientManager : public CNetBase, public singleton CPeer * GetAnyPeer(); - void ForwardPacket(BYTE header, const void* data, int size, BYTE bChannel = 0, CPeer * except = NULL); + void ForwardPacket(uint16_t wHeader, const void* data, int size, BYTE bChannel = 0, CPeer * except = NULL); void SendNotice(const char * c_pszFormat, ...); @@ -181,8 +181,6 @@ class CClientManager : public CNetBase, public singleton bool InitializeLandTable(); bool InitializeObjectProto(); bool InitializeObjectTable(); - bool InitializeMonarch(); - // mob_proto.txt, item_proto.txt에서 읽은 mob_proto, item_proto를 real db에 반영. // item_proto, mob_proto를 db에 반영하지 않아도, 게임 돌아가는데는 문제가 없지만, // 운영툴 등에서 db의 item_proto, mob_proto를 읽어 쓰기 때문에 문제가 발생한다. @@ -317,7 +315,6 @@ class CClientManager : public CNetBase, public singleton void QUERY_CHANGE_NAME(CPeer * peer, DWORD dwHandle, TPacketGDChangeName * p); void GetPlayerFromRes(TPlayerTable * player_table, MYSQL_RES* res); - void QUERY_SMS(CPeer * pkPeer, TPacketGDSMS * p); void QUERY_LOGIN_KEY(CPeer * pkPeer, TPacketGDLoginKey * p); void AddGuildPriv(TPacketGiveGuildPriv* p); @@ -349,14 +346,14 @@ class CClientManager : public CNetBase, public singleton // MYSHOP_PRICE_LIST // 개인상점 가격정보 - /// 아이템 가격정보 리스트 업데이트 패킷(HEADER_GD_MYSHOP_PRICELIST_UPDATE) 처리함수 + /// 아이템 가격정보 리스트 업데이트 패킷(GD::MYSHOP_PRICELIST_UPDATE) 처리함수 /** * @param [in] pPacket 패킷 데이터의 포인터 */ // void MyshopPricelistUpdate(const TPacketMyshopPricelistHeader* pPacket); void MyshopPricelistUpdate(const TItemPriceListTable* pPacket); - /// 아이템 가격정보 리스트 요청 패킷(HEADER_GD_MYSHOP_PRICELIST_REQ) 처리함수 + /// 아이템 가격정보 리스트 요청 패킷(GD::MYSHOP_PRICELIST_REQ) 처리함수 /** * @param peer 패킷을 보낸 Game server 의 peer 객체의 포인터 * @param [in] dwHandle 가격정보를 요청한 peer 의 핸들 @@ -452,7 +449,7 @@ class CClientManager : public CNetBase, public singleton typedef std::map TEventFlagMap; TEventFlagMap m_map_lEventFlag; - BYTE m_bLastHeader; + uint16_t m_wLastHeader; int m_iCacheFlushCount; int m_iCacheFlushCountLimit; @@ -507,22 +504,6 @@ class CClientManager : public CNetBase, public singleton void FlushPlayerCacheSet(DWORD pid); - //MONARCH - void Election(CPeer * peer, DWORD dwHandle, const char * p); - void Candidacy(CPeer * peer, DWORD dwHandle, const char * p); - void AddMonarchMoney(CPeer * peer, DWORD dwHandle, const char * p); - void TakeMonarchMoney(CPeer * peer, DWORD dwHandle, const char * p); - void ComeToVote(CPeer * peer, DWORD dwHandle, const char * p); - void RMCandidacy(CPeer * peer, DWORD dwHandle, const char * p); - void SetMonarch(CPeer * peer, DWORD dwHandle, const char * p); - void RMMonarch(CPeer * peer, DWORD dwHandle, const char * p); - - - void DecMonarchMoney(CPeer * peer, DWORD dwHandle, const char * p); - //END_MONARCH - - void ChangeMonarchLord(CPeer* peer, DWORD dwHandle, TPacketChangeMonarchLord* info); - void SendSpareItemIDRange(CPeer* peer); void UpdateHorseName(TPacketUpdateHorseName* data, CPeer* peer); diff --git a/src/db/ClientManagerBoot.cpp b/src/db/ClientManagerBoot.cpp index 0aa9408..1419646 100644 --- a/src/db/ClientManagerBoot.cpp +++ b/src/db/ClientManagerBoot.cpp @@ -4,7 +4,7 @@ #include "stdafx.h" #include "ClientManager.h" #include "Main.h" -#include "Monarch.h" + #include "CsvReader.h" #include "ProtoReader.h" @@ -92,13 +92,6 @@ bool CClientManager::InitializeTables() return false; } - if (!InitializeMonarch()) - { - sys_err("InitializeMonarch FAILED"); - return false; - } - - return true; } @@ -1339,12 +1332,6 @@ bool CClientManager::InitializeObjectTable() return true; } -bool CClientManager::InitializeMonarch() -{ - CMonarch::instance().LoadMonarch(); - - return true; -} bool CClientManager::MirrorMobTableIntoDB() { diff --git a/src/db/ClientManagerEventFlag.cpp b/src/db/ClientManagerEventFlag.cpp index e0f4282..3bb2b81 100644 --- a/src/db/ClientManagerEventFlag.cpp +++ b/src/db/ClientManagerEventFlag.cpp @@ -1,4 +1,4 @@ -// vim:ts=4 sw=4 +// vim:ts=4 sw=4 #include "stdafx.h" #include "ClientManager.h" #include "Main.h" @@ -23,14 +23,14 @@ void CClientManager::LoadEventFlag() str_to_number(p.lValue, row[1]); sys_log(0, "EventFlag Load %s %d", p.szFlagName, p.lValue); m_map_lEventFlag.insert(std::make_pair(std::string(p.szFlagName), p.lValue)); - ForwardPacket(HEADER_DG_SET_EVENT_FLAG, &p, sizeof(TPacketSetEventFlag)); + ForwardPacket(DG::SET_EVENT_FLAG, &p, sizeof(TPacketSetEventFlag)); } } } void CClientManager::SetEventFlag(TPacketSetEventFlag* p) { - ForwardPacket(HEADER_DG_SET_EVENT_FLAG, p, sizeof(TPacketSetEventFlag)); + ForwardPacket(DG::SET_EVENT_FLAG, p, sizeof(TPacketSetEventFlag)); bool bChanged = false; @@ -56,10 +56,10 @@ void CClientManager::SetEventFlag(TPacketSetEventFlag* p) //CDBManager::instance().ReturnQuery(szQuery, QID_QUEST_SAVE, 0, NULL); CDBManager::instance().AsyncQuery(szQuery); - sys_log(0, "HEADER_GD_SET_EVENT_FLAG : Changed CClientmanager::SetEventFlag(%s %d) ", p->szFlagName, p->lValue); + sys_log(0, "GD::SET_EVENT_FLAG : Changed CClientmanager::SetEventFlag(%s %d) ", p->szFlagName, p->lValue); return; } - sys_log(0, "HEADER_GD_SET_EVENT_FLAG : No Changed CClientmanager::SetEventFlag(%s %d) ", p->szFlagName, p->lValue); + sys_log(0, "GD::SET_EVENT_FLAG : No Changed CClientmanager::SetEventFlag(%s %d) ", p->szFlagName, p->lValue); } void CClientManager::SendEventFlagsOnSetup(CPeer* peer) @@ -69,7 +69,7 @@ void CClientManager::SendEventFlagsOnSetup(CPeer* peer) TPacketSetEventFlag p; strlcpy(p.szFlagName, it->first.c_str(), sizeof(p.szFlagName)); p.lValue = it->second; - peer->EncodeHeader(HEADER_DG_SET_EVENT_FLAG, 0, sizeof(TPacketSetEventFlag)); + peer->EncodeHeader(DG::SET_EVENT_FLAG, 0, sizeof(TPacketSetEventFlag)); peer->Encode(&p, sizeof(TPacketSetEventFlag)); } } diff --git a/src/db/ClientManagerGuild.cpp b/src/db/ClientManagerGuild.cpp index bf1191f..74587fd 100644 --- a/src/db/ClientManagerGuild.cpp +++ b/src/db/ClientManagerGuild.cpp @@ -1,4 +1,4 @@ -// vim:ts=4 sw=4 +// vim:ts=4 sw=4 #include "stdafx.h" #include "ClientManager.h" #include "Main.h" @@ -11,7 +11,7 @@ void CClientManager::GuildCreate(CPeer * peer, DWORD dwGuildID) { sys_log(0, "GuildCreate %u", dwGuildID); - ForwardPacket(HEADER_DG_GUILD_LOAD, &dwGuildID, sizeof(DWORD)); + ForwardPacket(DG::GUILD_LOAD, &dwGuildID, sizeof(DWORD)); CGuildManager::instance().Load(dwGuildID); } @@ -19,7 +19,7 @@ void CClientManager::GuildCreate(CPeer * peer, DWORD dwGuildID) void CClientManager::GuildChangeGrade(CPeer* peer, TPacketGuild* p) { sys_log(0, "GuildChangeGrade %u %u", p->dwGuild, p->dwInfo); - ForwardPacket(HEADER_DG_GUILD_CHANGE_GRADE, p, sizeof(TPacketGuild)); + ForwardPacket(DG::GUILD_CHANGE_GRADE, p, sizeof(TPacketGuild)); } void CClientManager::GuildAddMember(CPeer* peer, TPacketGDGuildAddMember * p) @@ -62,7 +62,7 @@ void CClientManager::GuildAddMember(CPeer* peer, TPacketGDGuildAddMember * p) str_to_number(dg.bJob, row[5]); strlcpy(dg.szName, row[6], sizeof(dg.szName)); - ForwardPacket(HEADER_DG_GUILD_ADD_MEMBER, &dg, sizeof(TPacketDGGuildMember)); + ForwardPacket(DG::GUILD_ADD_MEMBER, &dg, sizeof(TPacketDGGuildMember)); } void CClientManager::GuildRemoveMember(CPeer* peer, TPacketGuild* p) @@ -76,25 +76,25 @@ void CClientManager::GuildRemoveMember(CPeer* peer, TPacketGuild* p) snprintf(szQuery, sizeof(szQuery), "REPLACE INTO quest%s (dwPID, szName, szState, lValue) VALUES(%u, 'guild_manage', 'withdraw_time', %u)", GetTablePostfix(), p->dwInfo, (DWORD) GetCurrentTime()); CDBManager::instance().AsyncQuery(szQuery); - ForwardPacket(HEADER_DG_GUILD_REMOVE_MEMBER, p, sizeof(TPacketGuild)); + ForwardPacket(DG::GUILD_REMOVE_MEMBER, p, sizeof(TPacketGuild)); } void CClientManager::GuildSkillUpdate(CPeer* peer, TPacketGuildSkillUpdate* p) { sys_log(0, "GuildSkillUpdate %d", p->amount); - ForwardPacket(HEADER_DG_GUILD_SKILL_UPDATE, p, sizeof(TPacketGuildSkillUpdate)); + ForwardPacket(DG::GUILD_SKILL_UPDATE, p, sizeof(TPacketGuildSkillUpdate)); } void CClientManager::GuildExpUpdate(CPeer* peer, TPacketGuildExpUpdate* p) { sys_log(0, "GuildExpUpdate %d", p->amount); - ForwardPacket(HEADER_DG_GUILD_EXP_UPDATE, p, sizeof(TPacketGuildExpUpdate), 0, peer); + ForwardPacket(DG::GUILD_EXP_UPDATE, p, sizeof(TPacketGuildExpUpdate), 0, peer); } void CClientManager::GuildChangeMemberData(CPeer* peer, TPacketGuildChangeMemberData* p) { sys_log(0, "GuildChangeMemberData %u %u %d %d", p->pid, p->offer, p->level, p->grade); - ForwardPacket(HEADER_DG_GUILD_CHANGE_MEMBER_DATA, p, sizeof(TPacketGuildChangeMemberData), 0, peer); + ForwardPacket(DG::GUILD_CHANGE_MEMBER_DATA, p, sizeof(TPacketGuildChangeMemberData), 0, peer); } void CClientManager::GuildDisband(CPeer* peer, TPacketGuild* p) @@ -118,7 +118,7 @@ void CClientManager::GuildDisband(CPeer* peer, TPacketGuild* p) snprintf(szQuery, sizeof(szQuery), "DELETE FROM guild_comment%s WHERE guild_id=%u", GetTablePostfix(), p->dwGuild); CDBManager::instance().AsyncQuery(szQuery); - ForwardPacket(HEADER_DG_GUILD_DISBAND, p, sizeof(TPacketGuild)); + ForwardPacket(DG::GUILD_DISBAND, p, sizeof(TPacketGuild)); } const char* __GetWarType(int n) @@ -195,7 +195,7 @@ void CClientManager::GuildWar(CPeer* peer, TPacketGuildWar* p) break; } - ForwardPacket(HEADER_DG_GUILD_WAR, p, sizeof(TPacketGuildWar)); + ForwardPacket(DG::GUILD_WAR, p, sizeof(TPacketGuildWar)); } void CClientManager::GuildWarScore(CPeer* peer, TPacketGuildWarScore * p) @@ -226,7 +226,7 @@ void CClientManager::SendGuildSkillUsable(DWORD guild_id, DWORD dwSkillVnum, boo p.dwSkillVnum = dwSkillVnum; p.bUsable = bUsable; - ForwardPacket(HEADER_DG_GUILD_SKILL_USABLE_CHANGE, &p, sizeof(TPacketGuildSkillUsableChange)); + ForwardPacket(DG::GUILD_SKILL_USABLE_CHANGE, &p, sizeof(TPacketGuildSkillUsableChange)); } void CClientManager::GuildChangeMaster(TPacketChangeGuildMaster* p) @@ -238,7 +238,7 @@ void CClientManager::GuildChangeMaster(TPacketChangeGuildMaster* p) packet.idFrom = 0; packet.idTo = 0; - ForwardPacket(HEADER_DG_ACK_CHANGE_GUILD_MASTER, &packet, sizeof(packet)); + ForwardPacket(DG::ACK_CHANGE_GUILD_MASTER, &packet, sizeof(packet)); } } diff --git a/src/db/ClientManagerHorseName.cpp b/src/db/ClientManagerHorseName.cpp index 51af291..f8402a3 100644 --- a/src/db/ClientManagerHorseName.cpp +++ b/src/db/ClientManagerHorseName.cpp @@ -1,4 +1,4 @@ -// vim:ts=4 sw=4 +// vim:ts=4 sw=4 #include "stdafx.h" #include "ClientManager.h" @@ -10,7 +10,7 @@ void CClientManager::UpdateHorseName(TPacketUpdateHorseName* data, CPeer* peer) auto pmsg_insert = CDBManager::instance().DirectQuery(szQuery); - ForwardPacket(HEADER_DG_UPDATE_HORSE_NAME, data, sizeof(TPacketUpdateHorseName), 0, peer); + ForwardPacket(DG::UPDATE_HORSE_NAME, data, sizeof(TPacketUpdateHorseName), 0, peer); } void CClientManager::AckHorseName(DWORD dwPID, CPeer* peer) @@ -34,7 +34,7 @@ void CClientManager::AckHorseName(DWORD dwPID, CPeer* peer) strlcpy(packet.szHorseName, row[0], sizeof(packet.szHorseName)); } - peer->EncodeHeader(HEADER_DG_ACK_HORSE_NAME, 0, sizeof(TPacketUpdateHorseName)); + peer->EncodeHeader(DG::ACK_HORSE_NAME, 0, sizeof(TPacketUpdateHorseName)); peer->Encode(&packet, sizeof(TPacketUpdateHorseName)); } diff --git a/src/db/ClientManagerLogin.cpp b/src/db/ClientManagerLogin.cpp index 62ec95e..ad092c1 100644 --- a/src/db/ClientManagerLogin.cpp +++ b/src/db/ClientManagerLogin.cpp @@ -1,4 +1,4 @@ - + #include "stdafx.h" #include "ClientManager.h" @@ -87,7 +87,7 @@ void CClientManager::QUERY_LOGIN_BY_KEY(CPeer * pkPeer, DWORD dwHandle, TPacketG if (!pkLoginData) { sys_log(0, "LOGIN_BY_KEY key not exist %s %lu", szLogin, p->dwLoginKey); - pkPeer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, dwHandle); + pkPeer->EncodeReturn(DG::LOGIN_NOT_EXIST, dwHandle); return; } @@ -98,7 +98,7 @@ void CClientManager::QUERY_LOGIN_BY_KEY(CPeer * pkPeer, DWORD dwHandle, TPacketG sys_log(0, "LOGIN_BY_KEY already login %s %lu", r.login, p->dwLoginKey); TPacketDGLoginAlready ptog; strlcpy(ptog.szLogin, r.login, sizeof(ptog.szLogin)); - pkPeer->EncodeHeader(HEADER_DG_LOGIN_ALREADY, dwHandle, sizeof(TPacketDGLoginAlready)); + pkPeer->EncodeHeader(DG::LOGIN_ALREADY, dwHandle, sizeof(TPacketDGLoginAlready)); pkPeer->Encode(&ptog, sizeof(TPacketDGLoginAlready)); return; } @@ -106,7 +106,7 @@ void CClientManager::QUERY_LOGIN_BY_KEY(CPeer * pkPeer, DWORD dwHandle, TPacketG if (strcasecmp(r.login, szLogin)) { sys_log(0, "LOGIN_BY_KEY login differ %s %lu input %s", r.login, p->dwLoginKey, szLogin); - pkPeer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, dwHandle); + pkPeer->EncodeReturn(DG::LOGIN_NOT_EXIST, dwHandle); return; } @@ -136,7 +136,7 @@ void CClientManager::RESULT_LOGIN_BY_KEY(CPeer * peer, SQLMsg * msg) if (msg->uiSQLErrno != 0) { - peer->EncodeReturn(HEADER_DG_LOGIN_NOT_EXIST, info->dwHandle); + peer->EncodeReturn(DG::LOGIN_NOT_EXIST, info->dwHandle); delete info; return; } @@ -345,7 +345,7 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg) if (msg->Get()->uiNumRows == 0) { sys_log(0, "RESULT_LOGIN: no account"); - peer->EncodeHeader(HEADER_DG_LOGIN_NOT_EXIST, info->dwHandle, 0); + peer->EncodeHeader(DG::LOGIN_NOT_EXIST, info->dwHandle, 0); delete info; return; } @@ -355,7 +355,7 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg) if (!info->pAccountTable) { sys_log(0, "RESULT_LOGIN: no account : WRONG_PASSWD"); - peer->EncodeReturn(HEADER_DG_LOGIN_WRONG_PASSWD, info->dwHandle); + peer->EncodeReturn(DG::LOGIN_WRONG_PASSWD, info->dwHandle); delete info; } else @@ -385,7 +385,7 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg) { if (!info->pAccountTable) // 이럴리는 없겠지만;; { - peer->EncodeReturn(HEADER_DG_LOGIN_WRONG_PASSWD, info->dwHandle); + peer->EncodeReturn(DG::LOGIN_WRONG_PASSWD, info->dwHandle); delete info; return; } @@ -398,7 +398,7 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg) TPacketDGLoginAlready p; strlcpy(p.szLogin, info->pAccountTable->login, sizeof(p.szLogin)); - peer->EncodeHeader(HEADER_DG_LOGIN_ALREADY, info->dwHandle, sizeof(TPacketDGLoginAlready)); + peer->EncodeHeader(DG::LOGIN_ALREADY, info->dwHandle, sizeof(TPacketDGLoginAlready)); peer->Encode(&p, sizeof(p)); } else @@ -413,7 +413,7 @@ void CClientManager::RESULT_LOGIN(CPeer * peer, SQLMsg * msg) memcpy(&p->GetAccountRef(), info->pAccountTable, sizeof(TAccountTable)); //END_PREVENT_COPY_ITEM - peer->EncodeHeader(HEADER_DG_LOGIN_SUCCESS, info->dwHandle, sizeof(TAccountTable)); + peer->EncodeHeader(DG::LOGIN_SUCCESS, info->dwHandle, sizeof(TAccountTable)); peer->Encode(info->pAccountTable, sizeof(TAccountTable)); } @@ -480,7 +480,7 @@ void CClientManager::QUERY_CHANGE_NAME(CPeer * peer, DWORD dwHandle, TPacketGDCh { if (!pMsg->Get()->pSQLResult) { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } @@ -488,13 +488,13 @@ void CClientManager::QUERY_CHANGE_NAME(CPeer * peer, DWORD dwHandle, TPacketGDCh if (*row[0] != '0') { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0); return; } } else { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } @@ -504,7 +504,7 @@ void CClientManager::QUERY_CHANGE_NAME(CPeer * peer, DWORD dwHandle, TPacketGDCh auto pMsg0 = CDBManager::instance().DirectQuery(queryStr, SQL_PLAYER); TPacketDGChangeName pdg; - peer->EncodeHeader(HEADER_DG_CHANGE_NAME, dwHandle, sizeof(TPacketDGChangeName)); + peer->EncodeHeader(DG::CHANGE_NAME, dwHandle, sizeof(TPacketDGChangeName)); pdg.pid = p->pid; strlcpy(pdg.name, p->name, sizeof(pdg.name)); peer->Encode(&pdg, sizeof(TPacketDGChangeName)); diff --git a/src/db/ClientManagerParty.cpp b/src/db/ClientManagerParty.cpp index 1076c68..bf1a09b 100644 --- a/src/db/ClientManagerParty.cpp +++ b/src/db/ClientManagerParty.cpp @@ -1,4 +1,4 @@ -// vim:ts=4 sw=4 +// vim:ts=4 sw=4 #include "stdafx.h" #include "ClientManager.h" #include "Config.h" @@ -12,7 +12,7 @@ void CClientManager::QUERY_PARTY_CREATE(CPeer* peer, TPacketPartyCreate* p) if (pm.find(p->dwLeaderPID) == pm.end()) { pm.insert(make_pair(p->dwLeaderPID, TPartyMember())); - ForwardPacket(HEADER_DG_PARTY_CREATE, p, sizeof(TPacketPartyCreate), 0, peer); + ForwardPacket(DG::PARTY_CREATE, p, sizeof(TPacketPartyCreate), 0, peer); sys_log(0, "PARTY Create [%lu]", p->dwLeaderPID); } else @@ -33,7 +33,7 @@ void CClientManager::QUERY_PARTY_DELETE(CPeer* peer, TPacketPartyDelete* p) } pm.erase(it); - ForwardPacket(HEADER_DG_PARTY_DELETE, p, sizeof(TPacketPartyDelete), 0, peer); + ForwardPacket(DG::PARTY_DELETE, p, sizeof(TPacketPartyDelete), 0, peer); sys_log(0, "PARTY Delete [%lu]", p->dwLeaderPID); } @@ -51,7 +51,7 @@ void CClientManager::QUERY_PARTY_ADD(CPeer* peer, TPacketPartyAdd* p) if (it->second.find(p->dwPID) == it->second.end()) { it->second.insert(std::make_pair(p->dwPID, TPartyInfo())); - ForwardPacket(HEADER_DG_PARTY_ADD, p, sizeof(TPacketPartyAdd), 0, peer); + ForwardPacket(DG::PARTY_ADD, p, sizeof(TPacketPartyAdd), 0, peer); sys_log(0, "PARTY Add [%lu] to [%lu]", p->dwPID, p->dwLeaderPID); } else @@ -74,7 +74,7 @@ void CClientManager::QUERY_PARTY_REMOVE(CPeer* peer, TPacketPartyRemove* p) if (pit != it->second.end()) { it->second.erase(pit); - ForwardPacket(HEADER_DG_PARTY_REMOVE, p, sizeof(TPacketPartyRemove), 0, peer); + ForwardPacket(DG::PARTY_REMOVE, p, sizeof(TPacketPartyRemove), 0, peer); sys_log(0, "PARTY Remove [%lu] to [%lu]", p->dwPID, p->dwLeaderPID); } else @@ -105,7 +105,7 @@ void CClientManager::QUERY_PARTY_STATE_CHANGE(CPeer* peer, TPacketPartyStateChan else pit->second.bRole = 0; - ForwardPacket(HEADER_DG_PARTY_STATE_CHANGE, p, sizeof(TPacketPartyStateChange), 0, peer); + ForwardPacket(DG::PARTY_STATE_CHANGE, p, sizeof(TPacketPartyStateChange), 0, peer); sys_log(0, "PARTY StateChange [%lu] at [%lu] from %d %d",p->dwPID, p->dwLeaderPID, p->bRole, p->bFlag); } @@ -130,6 +130,6 @@ void CClientManager::QUERY_PARTY_SET_MEMBER_LEVEL(CPeer* peer, TPacketPartySetMe pit->second.bLevel = p->bLevel; - ForwardPacket(HEADER_DG_PARTY_SET_MEMBER_LEVEL, p, sizeof(TPacketPartySetMemberLevel)); + ForwardPacket(DG::PARTY_SET_MEMBER_LEVEL, p, sizeof(TPacketPartySetMemberLevel)); sys_log(0, "PARTY SetMemberLevel pid [%lu] level %d",p->dwPID, p->bLevel); } diff --git a/src/db/ClientManagerPlayer.cpp b/src/db/ClientManagerPlayer.cpp index 2dcffd6..0b59fa1 100644 --- a/src/db/ClientManagerPlayer.cpp +++ b/src/db/ClientManagerPlayer.cpp @@ -1,4 +1,4 @@ - + #include "stdafx.h" #include "ClientManager.h" @@ -237,7 +237,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad if (!pkLD || pkLD->IsPlay()) { sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0); - peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_LOAD_FAILED, dwHandle, 0); return; } @@ -246,7 +246,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad pkLD->SetPlay(true); thecore_memcpy(pTab->aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(pTab->aiPremiumTimes)); - peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, dwHandle, sizeof(TPlayerTable)); + peer->EncodeHeader(DG::PLAYER_LOAD_SUCCESS, dwHandle, sizeof(TPlayerTable)); peer->Encode(pTab, sizeof(TPlayerTable)); if (packet->player_id != pkLD->GetLastPlayerID()) @@ -256,7 +256,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad pkLD->SetLastPlayerID( packet->player_id ); - peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, dwHandle, sizeof(TPacketNeedLoginLogInfo) ); + peer->EncodeHeader( DG::NEED_LOGIN_LOG, dwHandle, sizeof(TPacketNeedLoginLogInfo) ); peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) ); } @@ -295,7 +295,7 @@ void CClientManager::QUERY_PLAYER_LOAD(CPeer * peer, DWORD dwHandle, TPlayerLoad if (g_test_server) sys_log(0, "ITEM_CACHE: HIT! %s count: %u", pTab->name, dwCount); - peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount); + peer->EncodeHeader(DG::ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount); peer->EncodeDWORD(dwCount); if (dwCount) @@ -425,7 +425,7 @@ void CClientManager::ItemAward(CPeer * peer,char* login) strcpy(giftData.login, pItemAward->szLogin); //로그인 아이디 복사 strcpy(giftData.command, command); //명령어 복사 giftData.vnum = pItemAward->dwVnum; //아이템 vnum도 복사 - ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER, &giftData, sizeof(TPacketItemAwardInfromer)); + ForwardPacket(DG::ITEMAWARD_INFORMER, &giftData, sizeof(TPacketItemAwardInfromer)); } } } @@ -512,12 +512,7 @@ bool CreatePlayerTableFromRes(MYSQL_RES * res, TPlayerTable * pkTab) str_to_number(pkTab->skill_group, row[col++]); str_to_number(pkTab->lAlignment, row[col++]); - if (row[col]) - { - strlcpy(pkTab->szMobile, row[col], sizeof(pkTab->szMobile)); - } - - col++; + col++; // skip mobile (removed feature) str_to_number(pkTab->horse.bLevel, row[col++]); str_to_number(pkTab->horse.bRiding, row[col++]); @@ -608,7 +603,7 @@ void CClientManager::RESULT_COMPOSITE_PLAYER(CPeer * peer, SQLMsg * pMsg, DWORD TPacketAffectElement pAffElem{}; DWORD dwCount = 0; - peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, info->dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount); + peer->EncodeHeader(DG::AFFECT_LOAD, info->dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount); peer->Encode(&info->player_id, sizeof(DWORD)); peer->Encode(&dwCount, sizeof(DWORD)); peer->Encode(&pAffElem, sizeof(TPacketAffectElement) * dwCount); @@ -661,7 +656,7 @@ void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHa if (!CreatePlayerTableFromRes(pRes, &tab)) { - peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0); return; } @@ -670,14 +665,14 @@ void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHa if (!pkLD || pkLD->IsPlay()) { sys_log(0, "PLAYER_LOAD_ERROR: LoginData %p IsPlay %d", pkLD, pkLD ? pkLD->IsPlay() : 0); - peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_LOAD_FAILED, pkInfo->dwHandle, 0); return; } pkLD->SetPlay(true); thecore_memcpy(tab.aiPremiumTimes, pkLD->GetPremiumPtr(), sizeof(tab.aiPremiumTimes)); - peer->EncodeHeader(HEADER_DG_PLAYER_LOAD_SUCCESS, pkInfo->dwHandle, sizeof(TPlayerTable)); + peer->EncodeHeader(DG::PLAYER_LOAD_SUCCESS, pkInfo->dwHandle, sizeof(TPlayerTable)); peer->Encode(&tab, sizeof(TPlayerTable)); if (tab.id != pkLD->GetLastPlayerID()) @@ -687,7 +682,7 @@ void CClientManager::RESULT_PLAYER_LOAD(CPeer * peer, MYSQL_RES * pRes, ClientHa pkLD->SetLastPlayerID( tab.id ); - peer->EncodeHeader( HEADER_DG_NEED_LOGIN_LOG, pkInfo->dwHandle, sizeof(TPacketNeedLoginLogInfo) ); + peer->EncodeHeader( DG::NEED_LOGIN_LOG, pkInfo->dwHandle, sizeof(TPacketNeedLoginLogInfo) ); peer->Encode( &logInfo, sizeof(TPacketNeedLoginLogInfo) ); } } @@ -699,7 +694,7 @@ void CClientManager::RESULT_ITEM_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwHa CreateItemTableFromRes(pRes, &s_items, dwPID); DWORD dwCount = s_items.size(); - peer->EncodeHeader(HEADER_DG_ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount); + peer->EncodeHeader(DG::ITEM_LOAD, dwHandle, sizeof(DWORD) + sizeof(TPlayerItem) * dwCount); peer->EncodeDWORD(dwCount); //CacheSet을 만든다 @@ -752,7 +747,7 @@ void CClientManager::RESULT_AFFECT_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dw DWORD dwCount = s_elements.size(); - peer->EncodeHeader(HEADER_DG_AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount); + peer->EncodeHeader(DG::AFFECT_LOAD, dwHandle, sizeof(DWORD) + sizeof(DWORD) + sizeof(TPacketAffectElement) * dwCount); peer->Encode(&dwPID, sizeof(DWORD)); peer->Encode(&dwCount, sizeof(DWORD)); peer->Encode(&s_elements[0], sizeof(TPacketAffectElement) * dwCount); @@ -765,7 +760,7 @@ void CClientManager::RESULT_QUEST_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwH if ((iNumRows = mysql_num_rows(pRes)) == 0) { DWORD dwCount = 0; - peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD)); + peer->EncodeHeader(DG::QUEST_LOAD, dwHandle, sizeof(DWORD)); peer->Encode(&dwCount, sizeof(DWORD)); return; } @@ -791,7 +786,7 @@ void CClientManager::RESULT_QUEST_LOAD(CPeer * peer, MYSQL_RES * pRes, DWORD dwH DWORD dwCount = s_table.size(); - peer->EncodeHeader(HEADER_DG_QUEST_LOAD, dwHandle, sizeof(DWORD) + sizeof(TQuestTable) * dwCount); + peer->EncodeHeader(DG::QUEST_LOAD, dwHandle, sizeof(DWORD) + sizeof(TQuestTable) * dwCount); peer->Encode(&dwCount, sizeof(DWORD)); peer->Encode(&s_table[0], sizeof(TQuestTable) * dwCount); } @@ -828,7 +823,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC if (curtime - it->second < 30) { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } } @@ -842,7 +837,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC { if (!pMsg0->Get()->pSQLResult) { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } @@ -851,14 +846,14 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC DWORD dwPID = 0; str_to_number(dwPID, row[0]); if (row[0] && dwPID > 0) { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0); sys_log(0, "ALREADY EXIST AccountChrIdx %d ID %d", packet->account_index, dwPID); return; } } else { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } @@ -876,7 +871,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC { if (!pMsg1->Get()->pSQLResult) { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } @@ -885,13 +880,13 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC if (*row[0] != '0') { sys_log(0, "ALREADY EXIST name %s, row[0] %s query %s", packet->player_table.name, row[0], queryStr); - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0); return; } } else { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } @@ -934,7 +929,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC if (pMsg2->Get()->uiAffectedRows <= 0) { - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_ALREADY, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_ALREADY, dwHandle, 0); sys_log(0, "ALREADY EXIST3 query: %s AffectedRows %lu", queryStr, pMsg2->Get()->uiAffectedRows); return; } @@ -952,7 +947,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC snprintf(queryStr, sizeof(queryStr), "DELETE FROM player%s WHERE id=%d", GetTablePostfix(), player_id); CDBManager::instance().DirectQuery(queryStr); - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_FAILED, dwHandle, 0); + peer->EncodeHeader(DG::PLAYER_CREATE_FAILED, dwHandle, 0); return; } @@ -974,7 +969,7 @@ void CClientManager::__QUERY_PLAYER_CREATE(CPeer *peer, DWORD dwHandle, TPlayerC pack.player.x = packet->player_table.x; pack.player.y = packet->player_table.y; - peer->EncodeHeader(HEADER_DG_PLAYER_CREATE_SUCCESS, dwHandle, sizeof(TPacketDGCreateSuccess)); + peer->EncodeHeader(DG::PLAYER_CREATE_SUCCESS, dwHandle, sizeof(TPacketDGCreateSuccess)); peer->Encode(&pack, sizeof(TPacketDGCreateSuccess)); sys_log(0, "7 name %s job %d", pack.player.szName, pack.player.byJob); @@ -994,7 +989,7 @@ void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerD if (!ld) { - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, dwHandle, 1); peer->EncodeBYTE(packet->account_index); return; } @@ -1009,7 +1004,7 @@ void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerD if (strlen(r.social_id) < 7 || strncmp(packet->private_code, r.social_id + strlen(r.social_id) - 7, 7)) { sys_log(0, "PLAYER_DELETE FAILED len(%d)", strlen(r.social_id)); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, dwHandle, 1); peer->EncodeBYTE(packet->account_index); return; } @@ -1022,7 +1017,7 @@ void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerD if (pTab->level >= m_iPlayerDeleteLevelLimit) { sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimit); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, dwHandle, 1); peer->EncodeBYTE(packet->account_index); return; } @@ -1030,7 +1025,7 @@ void CClientManager::__QUERY_PLAYER_DELETE(CPeer* peer, DWORD dwHandle, TPlayerD if (pTab->level < m_iPlayerDeleteLevelLimitLower) { sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", pTab->level, m_iPlayerDeleteLevelLimitLower); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, dwHandle, 1); peer->EncodeBYTE(packet->account_index); return; } @@ -1073,7 +1068,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg) if (deletedLevelLimit >= m_iPlayerDeleteLevelLimit && !IsChinaEventServer()) { sys_log(0, "PLAYER_DELETE FAILED LEVEL %u >= DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimit); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, pi->dwHandle, 1); peer->EncodeBYTE(pi->account_index); return; } @@ -1081,7 +1076,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg) if (deletedLevelLimit < m_iPlayerDeleteLevelLimitLower) { sys_log(0, "PLAYER_DELETE FAILED LEVEL %u < DELETE LIMIT %d", deletedLevelLimit, m_iPlayerDeleteLevelLimitLower); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, pi->dwHandle, 1); peer->EncodeBYTE(pi->account_index); return; } @@ -1096,7 +1091,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg) { sys_log(0, "PLAYER_DELETE FAILED %u CANNOT INSERT TO player%s_deleted", dwPID, GetTablePostfix()); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, pi->dwHandle, 1); peer->EncodeBYTE(pi->account_index); return; } @@ -1147,7 +1142,7 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg) if (pMsg->Get()->uiAffectedRows == 0 || pMsg->Get()->uiAffectedRows == (uint32_t)-1) { sys_log(0, "PLAYER_DELETE FAIL WHEN UPDATE account table"); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, pi->dwHandle, 1); peer->EncodeBYTE(pi->account_index); return; } @@ -1175,14 +1170,14 @@ void CClientManager::__RESULT_PLAYER_DELETE(CPeer *peer, SQLMsg* msg) snprintf(queryStr, sizeof(queryStr), "DELETE FROM messenger_list%s WHERE account='%s' OR companion='%s'", GetTablePostfix(), szName, szName); CDBManager::instance().AsyncQuery(queryStr); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_SUCCESS, pi->dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_SUCCESS, pi->dwHandle, 1); peer->EncodeBYTE(pi->account_index); } else { // 삭제 실패 sys_log(0, "PLAYER_DELETE FAIL NO ROW"); - peer->EncodeHeader(HEADER_DG_PLAYER_DELETE_FAILED, pi->dwHandle, 1); + peer->EncodeHeader(DG::PLAYER_DELETE_FAILED, pi->dwHandle, 1); peer->EncodeBYTE(pi->account_index); } } @@ -1240,7 +1235,7 @@ void CClientManager::QUERY_HIGHSCORE_REGISTER(CPeer* peer, TPacketGDHighscore * char szQuery[128]; snprintf(szQuery, sizeof(szQuery), "SELECT value FROM highscore%s WHERE board='%s' AND pid = %u", GetTablePostfix(), data->szBoard, data->dwPID); - sys_log(0, "HEADER_GD_HIGHSCORE_REGISTER: PID %u", data->dwPID); + sys_log(0, "GD::HIGHSCORE_REGISTER: PID %u", data->dwPID); ClientHandleInfo * pi = new ClientHandleInfo(0); strlcpy(pi->login, data->szBoard, sizeof(pi->login)); diff --git a/src/db/GuildManager.cpp b/src/db/GuildManager.cpp index 09274eb..b761fa9 100644 --- a/src/db/GuildManager.cpp +++ b/src/db/GuildManager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "GuildManager.h" #include "Main.h" #include "ClientManager.h" @@ -70,7 +70,7 @@ namespace if (peer->GetChannel() == 0) return; - peer->EncodeHeader(HEADER_DG_GUILD_WAR, 0, sizeof(TPacketGuildWar)); + peer->EncodeHeader(DG::GUILD_WAR, 0, sizeof(TPacketGuildWar)); peer->Encode(&p, sizeof(TPacketGuildWar)); } @@ -92,7 +92,7 @@ namespace if (peer->GetChannel() == 0) return; - peer->EncodeHeader(HEADER_DG_GUILD_WAR_SCORE, 0, sizeof(pck)); + peer->EncodeHeader(DG::GUILD_WAR_SCORE, 0, sizeof(pck)); peer->Encode(&pck, sizeof(pck)); } @@ -306,7 +306,7 @@ void CGuildManager::Update() p.dwGuildFrom = ws.GID[0]; p.dwGuildTo = ws.GID[1]; - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_WAR, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::GUILD_WAR, &p, sizeof(p)); sys_log(0, "GuildWar: GUILD sending start of wait start war %d %d", ws.GID[0], ws.GID[1]); } } @@ -754,7 +754,7 @@ void CGuildManager::ChangeLadderPoint(DWORD GID, int change) p.lDraw = r.draw; p.lLoss = r.loss; - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_LADDER, &p, sizeof(TPacketGuildLadder)); + CClientManager::instance().ForwardPacket(DG::GUILD_LADDER, &p, sizeof(TPacketGuildLadder)); } void CGuildManager::UseSkill(DWORD GID, DWORD dwSkillVnum, DWORD dwCooltime) @@ -772,7 +772,7 @@ void CGuildManager::MoneyChange(DWORD dwGuild, DWORD dwGold) TPacketDGGuildMoneyChange p; p.dwGuild = dwGuild; p.iTotalGold = dwGold; - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_MONEY_CHANGE, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::GUILD_MONEY_CHANGE, &p, sizeof(p)); char buf[1024]; snprintf(buf, sizeof(buf), "UPDATE guild%s SET gold=%u WHERE id = %u", GetTablePostfix(), dwGold, dwGuild); @@ -818,7 +818,7 @@ void CGuildManager::WithdrawMoney(CPeer* peer, DWORD dwGuild, INT iGold) p.dwGuild = dwGuild; p.iChangeGold = iGold; - peer->EncodeHeader(HEADER_DG_GUILD_WITHDRAW_MONEY_GIVE, 0, sizeof(TPacketDGGuildMoneyWithdraw)); + peer->EncodeHeader(DG::GUILD_WITHDRAW_MONEY_GIVE, 0, sizeof(TPacketDGGuildMoneyWithdraw)); peer->Encode(&p, sizeof(TPacketDGGuildMoneyWithdraw)); } } @@ -1077,7 +1077,7 @@ bool CGuildManager::ReserveWar(TPacketGuildWar * p) m_map_kWarReserve.insert(std::make_pair(t.dwID, new CGuildWarReserve(t))); - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_WAR_RESERVE_ADD, &t, sizeof(TGuildWarReserve)); + CClientManager::instance().ForwardPacket(DG::GUILD_WAR_RESERVE_ADD, &t, sizeof(TGuildWarReserve)); return true; } @@ -1109,7 +1109,7 @@ void CGuildManager::ProcessReserveWar() snprintf(szQuery, sizeof(szQuery), "UPDATE guild_war_reservation SET started=1 WHERE id=%u", r.dwID); CDBManager::instance().AsyncQuery(szQuery); - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_WAR_RESERVE_DEL, &r.dwID, sizeof(DWORD)); + CClientManager::instance().ForwardPacket(DG::GUILD_WAR_RESERVE_DEL, &r.dwID, sizeof(DWORD)); r.bStarted = true; @@ -1125,7 +1125,7 @@ void CGuildManager::ProcessReserveWar() pck.lWarPrice = r.lWarPrice; pck.lInitialScore = r.lInitialScore; - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_WAR, &pck, sizeof(TPacketGuildWar)); + CClientManager::instance().ForwardPacket(DG::GUILD_WAR, &pck, sizeof(TPacketGuildWar)); //m_map_kWarReserve.erase(it2); } else @@ -1244,7 +1244,7 @@ void CGuildWarReserve::OnSetup(CPeer * peer) FSendPeerWar(m_data.bType, GUILD_WAR_RESERVE, m_data.dwGuildFrom, m_data.dwGuildTo) (peer); - peer->EncodeHeader(HEADER_DG_GUILD_WAR_RESERVE_ADD, 0, sizeof(TGuildWarReserve)); + peer->EncodeHeader(DG::GUILD_WAR_RESERVE_ADD, 0, sizeof(TGuildWarReserve)); peer->Encode(&m_data, sizeof(TGuildWarReserve)); TPacketGDGuildWarBet pckBet; @@ -1258,7 +1258,7 @@ void CGuildWarReserve::OnSetup(CPeer * peer) pckBet.dwGuild = it->second.first; pckBet.dwGold = it->second.second; - peer->EncodeHeader(HEADER_DG_GUILD_WAR_BET, 0, sizeof(TPacketGDGuildWarBet)); + peer->EncodeHeader(DG::GUILD_WAR_BET, 0, sizeof(TPacketGDGuildWarBet)); peer->Encode(&pckBet, sizeof(TPacketGDGuildWarBet)); ++it; @@ -1304,7 +1304,7 @@ bool CGuildWarReserve::Bet(const char * pszLogin, DWORD dwGold, DWORD dwGuild) else m_data.dwBetTo += dwGold; - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_WAR_RESERVE_ADD, &m_data, sizeof(TGuildWarReserve)); + CClientManager::instance().ForwardPacket(DG::GUILD_WAR_RESERVE_ADD, &m_data, sizeof(TGuildWarReserve)); snprintf(szQuery, sizeof(szQuery), "UPDATE guild_war_reservation SET bet_from=%u,bet_to=%u WHERE id=%u", m_data.dwBetFrom, m_data.dwBetTo, m_data.dwID); @@ -1320,7 +1320,7 @@ bool CGuildWarReserve::Bet(const char * pszLogin, DWORD dwGold, DWORD dwGuild) pckBet.dwGuild = dwGuild; pckBet.dwGold = dwGold; - CClientManager::instance().ForwardPacket(HEADER_DG_GUILD_WAR_BET, &pckBet, sizeof(TPacketGDGuildWarBet)); + CClientManager::instance().ForwardPacket(DG::GUILD_WAR_BET, &pckBet, sizeof(TPacketGDGuildWarBet)); return true; } diff --git a/src/db/ItemAwardManager.cpp b/src/db/ItemAwardManager.cpp index e8a02e0..b119699 100644 --- a/src/db/ItemAwardManager.cpp +++ b/src/db/ItemAwardManager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "QID.h" #include "DBManager.h" #include "ItemAwardManager.h" @@ -67,7 +67,7 @@ void ItemAwardManager::Load(SQLMsg * pMsg) strcpy(giftData.login, kData->szLogin); //로그인 아이디 복사 strcpy(giftData.command, command); //명령어 복사 giftData.vnum = kData->dwVnum; //아이템 vnum도 복사 - CClientManager::instance().ForwardPacket(HEADER_DG_ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer)); + CClientManager::instance().ForwardPacket(DG::ITEMAWARD_INFORMER,&giftData,sizeof(TPacketItemAwardInfromer)); } } diff --git a/src/db/Main.cpp b/src/db/Main.cpp index df6dfaf..cd71952 100644 --- a/src/db/Main.cpp +++ b/src/db/Main.cpp @@ -9,7 +9,6 @@ #include "PrivManager.h" #include "MoneyLog.h" #include "Marriage.h" -#include "Monarch.h" #include "ItemIDRangeManager.h" #include #undef OS_FREEBSD @@ -77,7 +76,6 @@ int main() CMoneyLog MoneyLog; ItemAwardManager ItemAwardManager; marriage::CManager MarriageManager; - CMonarch Monarch; CItemIDRangeManager ItemIDRangeManager; if (!Start()) diff --git a/src/db/Marriage.cpp b/src/db/Marriage.cpp index e471d21..ee4b15b 100644 --- a/src/db/Marriage.cpp +++ b/src/db/Marriage.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Marriage.h" #include "Main.h" #include "DBManager.h" @@ -123,7 +123,7 @@ namespace marriage p.tMarryTime = now; strlcpy(p.szName1, szName1, sizeof(p.szName1)); strlcpy(p.szName2, szName2, sizeof(p.szName2)); - CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_ADD, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::MARRIAGE_ADD, &p, sizeof(p)); } void CManager::Update(DWORD dwPID1, DWORD dwPID2, INT iLovePoint, BYTE byMarried) @@ -159,7 +159,7 @@ namespace marriage p.dwPID2 = dwPID2; p.iLovePoint = pMarriage->love_point; p.byMarried = pMarriage->is_married; - CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_UPDATE, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::MARRIAGE_UPDATE, &p, sizeof(p)); } void CManager::Remove(DWORD dwPID1, DWORD dwPID2) @@ -205,7 +205,7 @@ namespace marriage TPacketMarriageRemove p; p.dwPID1 = dwPID1; p.dwPID2 = dwPID2; - CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_REMOVE, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::MARRIAGE_REMOVE, &p, sizeof(p)); delete pMarriage; } @@ -248,7 +248,7 @@ namespace marriage p.dwPID2 = dwPID2; p.iLovePoint = pMarriage->love_point; p.byMarried = pMarriage->is_married; - CClientManager::instance().ForwardPacket(HEADER_DG_MARRIAGE_UPDATE, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::MARRIAGE_UPDATE, &p, sizeof(p)); } void CManager::OnSetup(CPeer* peer) @@ -265,7 +265,7 @@ namespace marriage p.tMarryTime = pMarriage->time; strlcpy(p.szName1, pMarriage->name1.c_str(), sizeof(p.szName1)); strlcpy(p.szName2, pMarriage->name2.c_str(), sizeof(p.szName2)); - peer->EncodeHeader(HEADER_DG_MARRIAGE_ADD, 0, sizeof(p)); + peer->EncodeHeader(DG::MARRIAGE_ADD, 0, sizeof(p)); peer->Encode(&p, sizeof(p)); } @@ -275,7 +275,7 @@ namespace marriage p.dwPID2 = pMarriage->pid2; p.iLovePoint = pMarriage->love_point; p.byMarried = pMarriage->is_married; - peer->EncodeHeader(HEADER_DG_MARRIAGE_UPDATE, 0, sizeof(p)); + peer->EncodeHeader(DG::MARRIAGE_UPDATE, 0, sizeof(p)); peer->Encode(&p, sizeof(p)); } } @@ -290,14 +290,14 @@ namespace marriage p.dwPID2 = t.dwPID2; p.dwMapIndex = t.dwMapIndex; - peer->EncodeHeader(HEADER_DG_WEDDING_READY, 0, sizeof(p)); + peer->EncodeHeader(DG::WEDDING_READY, 0, sizeof(p)); peer->Encode(&p, sizeof(p)); TPacketWeddingStart p2; p2.dwPID1 = t.dwPID1; p2.dwPID2 = t.dwPID2; - peer->EncodeHeader(HEADER_DG_WEDDING_START, 0, sizeof(p2)); + peer->EncodeHeader(DG::WEDDING_START, 0, sizeof(p2)); peer->Encode(&p2, sizeof(p2)); } } @@ -322,7 +322,7 @@ namespace marriage TPacketWeddingEnd p; p.dwPID1 = w.dwPID1; p.dwPID2 = w.dwPID2; - CClientManager::instance().ForwardPacket(HEADER_DG_WEDDING_END, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::WEDDING_END, &p, sizeof(p)); m_mapRunningWedding.erase(it); } @@ -347,7 +347,7 @@ namespace marriage TPacketWeddingEnd p; p.dwPID1 = w.dwPID1; p.dwPID2 = w.dwPID2; - CClientManager::instance().ForwardPacket(HEADER_DG_WEDDING_END, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::WEDDING_END, &p, sizeof(p)); itertype(m_MarriageByPID) it_marriage = m_MarriageByPID.find(w.dwPID1); @@ -371,7 +371,7 @@ namespace marriage TPacketWeddingStart p; p.dwPID1 = w.dwPID1; p.dwPID2 = w.dwPID2; - CClientManager::instance().ForwardPacket(HEADER_DG_WEDDING_START, &p, sizeof(p)); + CClientManager::instance().ForwardPacket(DG::WEDDING_START, &p, sizeof(p)); w.dwTime += WEDDING_LENGTH; m_pqWeddingEnd.push(TWeddingInfo(w.dwTime, w.dwPID1, w.dwPID2)); diff --git a/src/db/Monarch.cpp b/src/db/Monarch.cpp deleted file mode 100644 index c7d8d21..0000000 --- a/src/db/Monarch.cpp +++ /dev/null @@ -1,298 +0,0 @@ -#include "Monarch.h" -#include "common/utils.h" -#include "Main.h" -#include "ClientManager.h" - -extern int g_test_server; - -CMonarch::CMonarch() -{ - memset(&m_MonarchInfo, 0, sizeof(MonarchInfo)); -} - -CMonarch::~CMonarch() -{ -} - -bool CMonarch::VoteMonarch(DWORD pid, DWORD selectdpid) -{ - MAP_MONARCHELECTION::iterator it = m_map_MonarchElection.find(pid); - - if (it == m_map_MonarchElection.end()) - { - MonarchElectionInfo * p = new MonarchElectionInfo; - p->pid = pid; - p->selectedpid= selectdpid; - m_map_MonarchElection.insert(MAP_MONARCHELECTION::value_type(pid, p)); - - char szQuery[256]; - snprintf(szQuery, sizeof(szQuery), - "INSERT INTO monarch_election(pid, selectedpid, electiondata) VALUES(%d, %d, now())", pid, selectdpid); - - CDBManager::instance().AsyncQuery(szQuery); - return 1; - } - - return 0; -} - -void CMonarch::ElectMonarch() -{ - int size = GetVecMonarchCandidacy().size(); - - int * s = new int[size]; - - itertype(m_map_MonarchElection) it = m_map_MonarchElection.begin(); - - int idx = 0; - - for (; it != m_map_MonarchElection.end(); ++it) - { - if ((idx = GetCandidacyIndex(it->second->pid)) < 0) - continue; - - ++s[idx]; - - if (g_test_server) - sys_log (0, "[MONARCH_VOTE] pid(%d) come to vote candidacy pid(%d)", it->second->pid, m_vec_MonarchCandidacy[idx].pid); - } - - delete [] s; -} - -bool CMonarch::IsCandidacy(DWORD pid) -{ - VEC_MONARCHCANDIDACY::iterator it = m_vec_MonarchCandidacy.begin(); - - for (; it != m_vec_MonarchCandidacy.end(); ++it) - { - if (it->pid == pid) - return false; - } - - return true; -} - -bool CMonarch::AddCandidacy(DWORD pid, const char * name) -{ - if (IsCandidacy(pid) == false) - return false; - - MonarchCandidacy info; - - info.pid = pid; - strlcpy(info.name, name, sizeof(info.name)); - m_vec_MonarchCandidacy.push_back(info); - - char szQuery[256]; - snprintf(szQuery, sizeof(szQuery), - "INSERT INTO monarch_candidacy(pid, date) VALUES(%d, now())", pid); - - CDBManager::instance().AsyncQuery(szQuery); - return true; -} - -bool CMonarch::DelCandidacy(const char * name) -{ - itertype(m_vec_MonarchCandidacy) it = m_vec_MonarchCandidacy.begin(); - for (; it != m_vec_MonarchCandidacy.end(); ++it) - { - if (0 == strncmp(it->name, name, sizeof(it->name))) - { - char szQuery[256]; - snprintf(szQuery, sizeof(szQuery), - "DELETE FROM monarch_candidacy WHERE pid=%d ", it->pid); - CDBManager::instance().AsyncQuery(szQuery); - - m_vec_MonarchCandidacy.erase (it); - return true; - } - } - return false; - -} - -bool CMonarch::IsMonarch(int Empire, DWORD pid) -{ - if (m_MonarchInfo.pid[Empire] != pid) - return false; - return true; -} - -bool CMonarch::AddMoney(int Empire, int64_t Money) -{ - if (m_MonarchInfo.money[Empire] + Money > 2000000000) - return true; - - m_MonarchInfo.money[Empire] += Money; - - int64_t Money64 = m_MonarchInfo.money[Empire]; - - char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), "UPDATE monarch set money=%lld where empire=%d", static_cast(Money64), Empire); - - CDBManager::instance().AsyncQuery(szQuery); - - return true; -} - -bool CMonarch::DecMoney(int Empire, int64_t Money) -{ - if (m_MonarchInfo.money[Empire] - Money < 0) - return false; - m_MonarchInfo.money[Empire] -= Money; - - int64_t Money64 = m_MonarchInfo.money[Empire]; - - char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), "UPDATE monarch set money=%lld where empire=%d", static_cast(Money64), Empire); - - CDBManager::instance().AsyncQuery(szQuery); - return true; -} - -bool CMonarch::TakeMoney(int Empire, DWORD pid, int64_t Money) -{ - if (IsMonarch(Empire, pid) == false) - return false; - - if (m_MonarchInfo.money[Empire] < Money) - return false; - - m_MonarchInfo.money[Empire] -= Money; - - char szQuery[1024]; - snprintf(szQuery, sizeof(szQuery), - "UPDATE monarch set money=%lld where empire=%d", static_cast(m_MonarchInfo.money[Empire]), Empire); - - CDBManager::instance().AsyncQuery(szQuery); - - if (g_test_server) - sys_log(0, "[MONARCH] Take money empire(%d) money(%lld)", Empire, static_cast(m_MonarchInfo.money[Empire])); - return true; -} - -bool CMonarch::LoadMonarch() -{ - MonarchInfo * p = &m_MonarchInfo; - char szQuery[256]; - snprintf(szQuery, sizeof(szQuery), "SELECT empire, pid, name, money, windate FROM monarch a, player%s b where a.pid=b.id", GetTablePostfix()); - auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER); - - if (pMsg->Get()->uiNumRows == 0) - { - return false; - } - - MYSQL_ROW row; - for (int n = 0; (row = mysql_fetch_row(pMsg->Get()->pSQLResult)) != NULL; ++n) - { - int idx = 0; - int Empire = 0; str_to_number(Empire, row[idx++]); - - str_to_number(p->pid[Empire], row[idx++]); - strlcpy(p->name[Empire], row[idx++], sizeof(p->name[Empire])); - - str_to_number(p->money[Empire], row[idx++]); - strlcpy(p->date[Empire], row[idx++], sizeof(p->date[Empire])); - - if (g_test_server) - sys_log(0, "[LOAD_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], static_cast(p->money[Empire]), p->date[Empire]); - } - - return true; -} - -bool CMonarch::SetMonarch(const char * name) -{ - MonarchInfo * p = &m_MonarchInfo; - char szQuery[256]; - - snprintf(szQuery, sizeof(szQuery), "SELECT empire, pid, name FROM player a where a.name = '%s'", name); - auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER); - - if (pMsg->Get()->uiNumRows == 0) - { - return false; - } - - MYSQL_ROW row; - int Empire = 0; - for (int n = 0; (row = mysql_fetch_row(pMsg->Get()->pSQLResult)) != NULL; ++n) - { - int idx = 0; - str_to_number(Empire, row[idx++]); - - str_to_number(p->pid[Empire], row[idx++]); - strlcpy(p->name[Empire], row[idx++], sizeof(p->name[Empire])); - p->money[Empire] = atoll(row[idx++]); - - if (g_test_server) - sys_log(0, "[Set_MONARCH] Empire %d pid %d money %lld windate %s", Empire, p->pid[Empire], static_cast(p->money[Empire]), p->date[Empire]); - } - - //db¿¡ ÀÔ·Â - snprintf(szQuery, sizeof(szQuery), - "REPLACE INTO monarch (empire, name, windate, money) VALUES(%d, %d, now(), %lld)", Empire, p->pid[Empire], static_cast(p->money[Empire])); - - CDBManager::instance().AsyncQuery(szQuery, SQL_PLAYER); - return true; -} - -bool CMonarch::DelMonarch(int Empire) -{ - char szQuery[256]; - - snprintf(szQuery, sizeof(szQuery), "DELETE from monarch where empire=%d", Empire); - auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER); - if (pMsg->Get()->uiNumRows == 0) - { - return false; - } - - memset(m_MonarchInfo.name[Empire], 0, sizeof(m_MonarchInfo.name[Empire])); - m_MonarchInfo.money[Empire] = 0; - m_MonarchInfo.pid[Empire] = 0; - return true; -} - -bool CMonarch::DelMonarch(const char * name) -{ - for (int n = 1; n < 4; ++n) - { - if (0 == strncmp(m_MonarchInfo.name[n], name, sizeof(m_MonarchInfo.name[n]))) - { - char szQuery[256]; - - int Empire = n; - snprintf(szQuery, sizeof(szQuery), "DELETE from monarch where name=%d", Empire); - auto pMsg = CDBManager::instance().DirectQuery(szQuery, SQL_PLAYER); - - if (pMsg->Get()->uiNumRows == 0) - { - sys_err(" DirectQuery failed(%s)", szQuery); - return false; - } - - memset(m_MonarchInfo.name[Empire], 0, 32); - m_MonarchInfo.money[Empire] = 0; - m_MonarchInfo.pid[Empire] = 0; - return true; - } - } - - return false; -} - -int CMonarch::GetCandidacyIndex(DWORD pid) -{ - itertype(m_vec_MonarchCandidacy) it = m_vec_MonarchCandidacy.begin(); - - for (int n = 0; it != m_vec_MonarchCandidacy.end(); ++it, ++n) - { - if (it->pid == pid) - return n; - } - - return -1; -} diff --git a/src/db/Monarch.h b/src/db/Monarch.h deleted file mode 100644 index 7fd1574..0000000 --- a/src/db/Monarch.h +++ /dev/null @@ -1,70 +0,0 @@ -// vim: ts=4 sw=4 -#ifndef METIN2_MONARCH_H -#define METIN2_MONARCH_H - -#include "libthecore/stdafx.h" -#include -#include -#include "common/singleton.h" -#include "common/tables.h" - -class CMonarch : public singleton -{ - public: - typedef std::map MAP_MONARCHELECTION; - typedef std::vector VEC_MONARCHCANDIDACY; - - CMonarch(); - virtual ~CMonarch(); - - bool VoteMonarch(DWORD pid, DWORD selectedpid); - void ElectMonarch(); - - bool IsCandidacy(DWORD pid); - bool AddCandidacy(DWORD pid, const char * name); - bool DelCandidacy(const char * name); - - bool LoadMonarch(); - bool SetMonarch(const char * name); - bool DelMonarch(int Empire); - bool DelMonarch(const char * name); - - bool IsMonarch(int Empire, DWORD pid); - bool AddMoney(int Empire, int64_t Money); - bool DecMoney(int Empire, int64_t Money); - bool TakeMoney(int Empire, DWORD pid, int64_t Money); - - TMonarchInfo* GetMonarch() - { - return &m_MonarchInfo; - } - - VEC_MONARCHCANDIDACY& GetVecMonarchCandidacy() - { - return m_vec_MonarchCandidacy; - } - - size_t MonarchCandidacySize() - { - return m_vec_MonarchCandidacy.size(); - } - - private: - int GetCandidacyIndex(DWORD pid); - - MAP_MONARCHELECTION m_map_MonarchElection; - VEC_MONARCHCANDIDACY m_vec_MonarchCandidacy; - TMonarchInfo m_MonarchInfo; - - MonarchElectionInfo* GetMonarchElection(DWORD pid) - { - MAP_MONARCHELECTION::iterator it = m_map_MonarchElection.find(pid); - - if (it != m_map_MonarchElection.end()) - return it->second; - - return NULL; - } -}; - -#endif diff --git a/src/db/MoneyLog.cpp b/src/db/MoneyLog.cpp index 4cd9002..0e19219 100644 --- a/src/db/MoneyLog.cpp +++ b/src/db/MoneyLog.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "MoneyLog.h" #include "ClientManager.h" #include "Peer.h" @@ -25,7 +25,7 @@ void CMoneyLog::Save() p.type = bType; p.vnum = it->first; p.gold = it->second; - peer->EncodeHeader(HEADER_DG_MONEY_LOG, 0, sizeof(p)); + peer->EncodeHeader(DG::MONEY_LOG, 0, sizeof(p)); peer->Encode(&p, sizeof(p)); } m_MoneyLogContainer[bType].clear(); diff --git a/src/db/Peer.cpp b/src/db/Peer.cpp index f663f56..4fd9077 100644 --- a/src/db/Peer.cpp +++ b/src/db/Peer.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Peer.h" #include "ItemIDRangeManager.h" @@ -67,15 +67,18 @@ void CPeer::SetUserCount(DWORD dwCount) m_dwUserCount = dwCount; } -bool CPeer::PeekPacket(int & iBytesProceed, BYTE & header, DWORD & dwHandle, DWORD & dwLength, const char ** data) +bool CPeer::PeekPacket(int & iBytesProceed, uint16_t & wHeader, DWORD & dwHandle, DWORD & dwLength, const char ** data) { - if (GetRecvLength() < iBytesProceed + 9) + static constexpr int FRAME_SIZE = sizeof(HEADER); // 10: header(2) + handle(4) + size(4) + + if (GetRecvLength() < iBytesProceed + FRAME_SIZE) return false; const char * buf = (const char *) GetRecvBuffer(); buf += iBytesProceed; - header = *(buf++); + wHeader = *((uint16_t *) buf); + buf += sizeof(uint16_t); dwHandle = *((DWORD *) buf); buf += sizeof(DWORD); @@ -83,35 +86,35 @@ bool CPeer::PeekPacket(int & iBytesProceed, BYTE & header, DWORD & dwHandle, DWO dwLength = *((DWORD *) buf); buf += sizeof(DWORD); - //sys_log(0, "%d header %d handle %u length %u", GetRecvLength(), header, dwHandle, dwLength); - if (iBytesProceed + dwLength + 9 > (DWORD) GetRecvLength()) + //sys_log(0, "%d header %d handle %u length %u", GetRecvLength(), wHeader, dwHandle, dwLength); + if (iBytesProceed + dwLength + FRAME_SIZE > (DWORD) GetRecvLength()) { - sys_log(0, "PeekPacket: not enough buffer size: len %u, recv %d", - 9+dwLength, GetRecvLength()-iBytesProceed); + sys_log(0, "PeekPacket: not enough buffer size: len %u, recv %d", + FRAME_SIZE+dwLength, GetRecvLength()-iBytesProceed); return false; } *data = buf; - iBytesProceed += dwLength + 9; + iBytesProceed += dwLength + FRAME_SIZE; return true; } -void CPeer::EncodeHeader(BYTE header, DWORD dwHandle, DWORD dwSize) +void CPeer::EncodeHeader(uint16_t wHeader, DWORD dwHandle, DWORD dwSize) { HEADER h; - sys_log(1, "EncodeHeader %u handle %u size %u", header, dwHandle, dwSize); + sys_log(1, "EncodeHeader %u handle %u size %u", wHeader, dwHandle, dwSize); - h.bHeader = header; + h.wHeader = wHeader; h.dwHandle = dwHandle; h.dwSize = dwSize; Encode(&h, sizeof(HEADER)); } -void CPeer::EncodeReturn(BYTE header, DWORD dwHandle) +void CPeer::EncodeReturn(uint16_t wHeader, DWORD dwHandle) { - EncodeHeader(header, dwHandle, 0); + EncodeHeader(wHeader, dwHandle, 0); } int CPeer::Send() @@ -136,7 +139,7 @@ void CPeer::SendSpareItemIDRange() { if (m_itemSpareRange.dwMin == 0 || m_itemSpareRange.dwMax == 0 || m_itemSpareRange.dwUsableItemIDMin == 0) { - EncodeHeader(HEADER_DG_ACK_SPARE_ITEM_ID_RANGE, 0, sizeof(TItemIDRangeTable)); + EncodeHeader(DG::ACK_SPARE_ITEM_ID_RANGE, 0, sizeof(TItemIDRangeTable)); Encode(&m_itemSpareRange, sizeof(TItemIDRangeTable)); } else @@ -149,7 +152,7 @@ void CPeer::SendSpareItemIDRange() m_itemSpareRange.dwMin = m_itemSpareRange.dwMax = m_itemSpareRange.dwUsableItemIDMin = 0; } - EncodeHeader(HEADER_DG_ACK_SPARE_ITEM_ID_RANGE, 0, sizeof(TItemIDRangeTable)); + EncodeHeader(DG::ACK_SPARE_ITEM_ID_RANGE, 0, sizeof(TItemIDRangeTable)); Encode(&m_itemSpareRange, sizeof(TItemIDRangeTable)); } } diff --git a/src/db/Peer.h b/src/db/Peer.h index f8477bc..13296c6 100644 --- a/src/db/Peer.h +++ b/src/db/Peer.h @@ -14,8 +14,8 @@ class CPeer : public CPeerBase public: #pragma pack(1) typedef struct _header - { - BYTE bHeader; + { + uint16_t wHeader; DWORD dwHandle; DWORD dwSize; } HEADER; @@ -29,9 +29,9 @@ class CPeer : public CPeerBase CPeer(); virtual ~CPeer(); - void EncodeHeader(BYTE header, DWORD dwHandle, DWORD dwSize); - bool PeekPacket(int & iBytesProceed, BYTE & header, DWORD & dwHandle, DWORD & dwLength, const char ** data); - void EncodeReturn(BYTE header, DWORD dwHandle); + void EncodeHeader(uint16_t wHeader, DWORD dwHandle, DWORD dwSize); + bool PeekPacket(int & iBytesProceed, uint16_t & wHeader, DWORD & dwHandle, DWORD & dwLength, const char ** data); + void EncodeReturn(uint16_t wHeader, DWORD dwHandle); void ProcessInput(); int Send(); diff --git a/src/db/PeerBase.cpp b/src/db/PeerBase.cpp index 938466c..675799d 100644 --- a/src/db/PeerBase.cpp +++ b/src/db/PeerBase.cpp @@ -1,7 +1,7 @@ -#include "stdafx.h" +#include "stdafx.h" #include "PeerBase.h" -CPeerBase::CPeerBase() : m_fd(INVALID_SOCKET), m_BytesRemain(0), m_outBuffer(NULL), m_inBuffer(NULL) +CPeerBase::CPeerBase() : m_fd(INVALID_SOCKET), m_BytesRemain(0) { } @@ -24,18 +24,8 @@ void CPeerBase::Disconnect() void CPeerBase::Destroy() { Disconnect(); - - if (m_outBuffer) - { - buffer_delete(m_outBuffer); - m_outBuffer = NULL; - } - - if (m_inBuffer) - { - buffer_delete(m_inBuffer); - m_inBuffer = NULL; - } + m_outBuffer.Clear(); + m_inBuffer.Clear(); } bool CPeerBase::Accept(socket_t fd_accept) @@ -53,14 +43,8 @@ bool CPeerBase::Accept(socket_t fd_accept) socket_rcvbuf(m_fd, 233016); strlcpy(m_host, inet_ntoa(peer.sin_addr), sizeof(m_host)); - m_outBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE); - m_inBuffer = buffer_new(MAX_INPUT_LEN); - - if (!m_outBuffer || !m_inBuffer) - { - Destroy(); - return false; - } + m_outBuffer.Reserve(DEFAULT_PACKET_BUFFER_SIZE); + m_inBuffer.Reserve(MAX_INPUT_LEN); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_READ, false); @@ -76,13 +60,7 @@ bool CPeerBase::Connect(const char* host, WORD port) if ((m_fd = socket_connect(host, port)) == INVALID_SOCKET) return false; - m_outBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE); - - if (!m_outBuffer) - { - Destroy(); - return false; - } + m_outBuffer.Reserve(DEFAULT_PACKET_BUFFER_SIZE); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_READ, false); @@ -97,63 +75,33 @@ void CPeerBase::Close() void CPeerBase::EncodeBYTE(uint8_t b) { - if (!m_outBuffer) - { - sys_err("Not ready to write"); - return; - } - - buffer_write(m_outBuffer, &b, sizeof(uint8_t)); + m_outBuffer.Write(&b, sizeof(uint8_t)); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); } void CPeerBase::EncodeWORD(uint16_t w) { - if (!m_outBuffer) - { - sys_err("Not ready to write"); - return; - } - - buffer_write(m_outBuffer, &w, sizeof(uint16_t)); + m_outBuffer.Write(&w, sizeof(uint16_t)); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); } void CPeerBase::EncodeDWORD(uint32_t dw) { - if (!m_outBuffer) - { - sys_err("Not ready to write"); - return; - } - - buffer_write(m_outBuffer, &dw, sizeof(uint32_t)); + m_outBuffer.Write(&dw, sizeof(uint32_t)); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); } void CPeerBase::Encode(const void* data, uint32_t size) { - if (!m_outBuffer) - { - sys_err("Not ready to write"); - return; - } - - buffer_write(m_outBuffer, data, size); + m_outBuffer.Write(data, size); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); } int CPeerBase::Recv() { - if (!m_inBuffer) - { - sys_err("input buffer nil"); - return -1; - } - - buffer_adjust_size(m_inBuffer, MAX_INPUT_LEN >> 2); - int bytes_to_read = buffer_has_space(m_inBuffer); - ssize_t bytes_read = socket_read(m_fd, (char *) buffer_write_peek(m_inBuffer), bytes_to_read); + m_inBuffer.EnsureWritable(MAX_INPUT_LEN >> 2); + int bytes_to_read = static_cast(m_inBuffer.WritableBytes()); + ssize_t bytes_read = socket_read(m_fd, (char *) m_inBuffer.WritePtr(), bytes_to_read); if (bytes_read < 0) { @@ -163,15 +111,15 @@ int CPeerBase::Recv() else if (bytes_read == 0) return 0; - buffer_write_proceed(m_inBuffer, bytes_read); - m_BytesRemain = buffer_size(m_inBuffer); + m_inBuffer.CommitWrite(bytes_read); + m_BytesRemain = static_cast(m_inBuffer.ReadableBytes()); return 1; } void CPeerBase::RecvEnd(int proceed_bytes) { - buffer_read_proceed(m_inBuffer, proceed_bytes); - m_BytesRemain = buffer_size(m_inBuffer); + m_inBuffer.Discard(proceed_bytes); + m_BytesRemain = static_cast(m_inBuffer.ReadableBytes()); } int CPeerBase::GetRecvLength() @@ -181,32 +129,32 @@ int CPeerBase::GetRecvLength() const void * CPeerBase::GetRecvBuffer() { - return buffer_read_peek(m_inBuffer); + return m_inBuffer.ReadPtr(); } int CPeerBase::GetSendLength() { - return buffer_size(m_outBuffer); + return static_cast(m_outBuffer.ReadableBytes()); } int CPeerBase::Send() { - if (buffer_size(m_outBuffer) <= 0) + if (m_outBuffer.ReadableBytes() <= 0) return 0; int iBufferLeft = fdwatch_get_buffer_size(m_fdWatcher, m_fd); - int iBytesToWrite = MIN(iBufferLeft, buffer_size(m_outBuffer)); + int iBytesToWrite = MIN(iBufferLeft, static_cast(m_outBuffer.ReadableBytes())); if (iBytesToWrite == 0) return 0; - int result = socket_write(m_fd, (const char *) buffer_read_peek(m_outBuffer), iBytesToWrite); + int result = socket_write(m_fd, (const char *) m_outBuffer.ReadPtr(), iBytesToWrite); if (result == 0) { - buffer_read_proceed(m_outBuffer, iBytesToWrite); + m_outBuffer.Discard(iBytesToWrite); - if (buffer_size(m_outBuffer) != 0) + if (m_outBuffer.ReadableBytes() != 0) fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); } diff --git a/src/db/PeerBase.h b/src/db/PeerBase.h index 95f5c9d..299ba99 100644 --- a/src/db/PeerBase.h +++ b/src/db/PeerBase.h @@ -1,14 +1,13 @@ -// vim: ts=8 sw=4 -#ifndef __INC_PEERBASE_H__ -#define __INC_PEERBASE_H__ +#pragma once #include "NetBase.h" +#include "libthecore/ring_buffer.h" class CPeerBase : public CNetBase { public: enum - { + { MAX_HOST_LENGTH = 30, MAX_INPUT_LEN = 1024 * 1024 * 2, DEFAULT_PACKET_BUFFER_SIZE = 1024 * 1024 * 2 @@ -54,8 +53,6 @@ class CPeerBase : public CNetBase private: int m_BytesRemain; - LPBUFFER m_outBuffer; - LPBUFFER m_inBuffer; + RingBuffer m_outBuffer; + RingBuffer m_inBuffer; }; - -#endif diff --git a/src/db/PrivManager.cpp b/src/db/PrivManager.cpp index 17c5254..f25ae50 100644 --- a/src/db/PrivManager.cpp +++ b/src/db/PrivManager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "PrivManager.h" #include "ClientManager.h" @@ -194,7 +194,7 @@ struct FSendChangeGuildPriv void operator() (CPeer* peer) { - peer->EncodeHeader(HEADER_DG_CHANGE_GUILD_PRIV, 0, sizeof(TPacketDGChangeGuildPriv)); + peer->EncodeHeader(DG::CHANGE_GUILD_PRIV, 0, sizeof(TPacketDGChangeGuildPriv)); peer->Encode(&p, sizeof(TPacketDGChangeGuildPriv)); p.bLog = 0; } @@ -217,7 +217,7 @@ struct FSendChangeEmpirePriv void operator ()(CPeer* peer) { - peer->EncodeHeader(HEADER_DG_CHANGE_EMPIRE_PRIV, 0, sizeof(TPacketDGChangeEmpirePriv)); + peer->EncodeHeader(DG::CHANGE_EMPIRE_PRIV, 0, sizeof(TPacketDGChangeEmpirePriv)); peer->Encode(&p, sizeof(TPacketDGChangeEmpirePriv)); p.bLog = 0; } @@ -236,7 +236,7 @@ struct FSendChangeCharPriv } void operator()(CPeer* peer) { - peer->EncodeHeader(HEADER_DG_CHANGE_CHARACTER_PRIV, 0, sizeof(TPacketDGChangeCharacterPriv)); + peer->EncodeHeader(DG::CHANGE_CHARACTER_PRIV, 0, sizeof(TPacketDGChangeCharacterPriv)); peer->Encode(&p, sizeof(TPacketDGChangeCharacterPriv)); p.bLog = 0; } diff --git a/src/game/BlueDragon.cpp b/src/game/BlueDragon.cpp index fc4f42c..99a94e8 100644 --- a/src/game/BlueDragon.cpp +++ b/src/game/BlueDragon.cpp @@ -1,4 +1,4 @@ - + #include "stdafx.h" #include "BlueDragon.h" @@ -15,7 +15,7 @@ extern int passes_per_sec; #include "affect.h" #include "BlueDragon_Binder.h" #include "BlueDragon_Skill.h" -#include "packet.h" +#include "packet_structs.h" #include "motion.h" time_t UseBlueDragonSkill(LPCHARACTER pChar, unsigned int idx) diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index 3472f80..6b9ccd6 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -19,6 +19,8 @@ target_link_libraries(game if (WIN32) target_link_libraries(game ws2_32) + # Suppress C4244 from STL template instantiations with Lua number types + target_compile_options(game PRIVATE /wd4244) else() target_link_libraries(game pthread) if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") diff --git a/src/game/DragonSoul.cpp b/src/game/DragonSoul.cpp index 272472f..6bdcb51 100644 --- a/src/game/DragonSoul.cpp +++ b/src/game/DragonSoul.cpp @@ -1,9 +1,9 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "item.h" #include "item_manager.h" #include "unique_item.h" -#include "packet.h" +#include "packet_structs.h" #include "desc.h" #include "char.h" #include "dragon_soul_table.h" @@ -582,7 +582,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL if (!pItem->IsDragonSoul()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 필요한 재료가 아닙니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -593,7 +593,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL if (set_items.size() == 0) { - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS); return false; } @@ -616,7 +616,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL if (!m_pTable->GetRefineGradeValues(ds_type, grade_idx, need_count, fee, vec_probs)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량할 수 없는 용혼석입니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -635,7 +635,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL if (ds_type != GetType(pItem->GetVnum()) || grade_idx != GetGradeIdx(pItem->GetVnum())) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 필요한 재료가 아닙니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -645,7 +645,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL if (count != need_count) { sys_err ("Possiblity of invalid client. Name %s", ch->GetName()); - BYTE bSubHeader = count < need_count? DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL : DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL; + BYTE bSubHeader = count < need_count? DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MATERIAL : DragonSoulSub::REFINE_FAIL_TOO_MUCH_MATERIAL; SendRefineResultPacket(ch, bSubHeader, NPOS); return false; @@ -654,7 +654,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL if (ch->GetGold() < fee) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); return false; } @@ -701,7 +701,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL sprintf(buf, "GRADE : %d -> %d", grade_idx, result_grade); LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_SUCCESS", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 성공했습니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); return true; } @@ -711,7 +711,7 @@ bool DSManager::DoRefineGrade(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL sprintf(buf, "GRADE : %d -> %d", grade_idx, result_grade); LogManager::instance().ItemLog(ch, pResultItem, "DS_GRADE_REFINE_FAIL", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("등급 개량에 실패했습니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); return false; } @@ -749,7 +749,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (!pItem->IsDragonSoul()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 필요한 재료가 아닙니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -760,7 +760,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (set_items.size() == 0) { - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS); return false; } @@ -783,7 +783,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (!m_pTable->GetRefineStepValues(ds_type, step_idx, need_count, fee, vec_probs)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량할 수 없는 용혼석입니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -802,7 +802,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (ds_type != GetType(pItem->GetVnum()) || grade_idx != GetGradeIdx(pItem->GetVnum()) || step_idx != GetStepIdx(pItem->GetVnum())) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 필요한 재료가 아닙니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -812,7 +812,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (count != need_count) { sys_err ("Possiblity of invalid client. Name %s", ch->GetName()); - BYTE bSubHeader = count < need_count? DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL : DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL; + BYTE bSubHeader = count < need_count? DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MATERIAL : DragonSoulSub::REFINE_FAIL_TOO_MUCH_MATERIAL; SendRefineResultPacket(ch, bSubHeader, NPOS); return false; @@ -821,7 +821,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ if (ch->GetGold() < fee) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); return false; } @@ -870,7 +870,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ sprintf(buf, "STEP : %d -> %d", step_idx, result_step); LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_SUCCESS", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 성공했습니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_SUCCEED, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); return true; } @@ -880,7 +880,7 @@ bool DSManager::DoRefineStep(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_SOUL_ sprintf(buf, "STEP : %d -> %d", step_idx, result_step); LogManager::instance().ItemLog(ch, pResultItem, "DS_STEP_REFINE_FAIL", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("단계 개량에 실패했습니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL, TItemPos (pResultItem->GetWindow(), pResultItem->GetCell())); return false; } @@ -952,7 +952,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S { if (pDragonSoul != NULL) { - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -962,7 +962,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S { if (pRefineStone != NULL) { - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_TOO_MUCH_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -971,7 +971,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S else { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 필요한 재료가 아닙니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pItem->GetWindow(), pItem->GetCell())); return false; } @@ -981,7 +981,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S if (!pDragonSoul || !pRefineStone) { - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MATERIAL, NPOS); return false; } @@ -996,7 +996,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S if (!m_pTable->GetWeight(bType, bGrade, bStep, bStrength + 1, fWeight)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); return false; } @@ -1004,7 +1004,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S if (fWeight < FLT_EPSILON) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_MAX_REFINE, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); return false; } } @@ -1014,7 +1014,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S if (!m_pTable->GetRefineStrengthValues(bType, pRefineStone->GetSubType(), bStrength, fee, fProb)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화할 수 없는 용혼석입니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_INVALID_MATERIAL, TItemPos(pDragonSoul->GetWindow(), pDragonSoul->GetCell())); return false; } @@ -1022,7 +1022,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S if (ch->GetGold() < fee) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개량을 하기 위한 돈이 부족합니다.")); - SendRefineResultPacket(ch, DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); + SendRefineResultPacket(ch, DragonSoulSub::REFINE_FAIL_NOT_ENOUGH_MONEY, NPOS); return false; } @@ -1055,7 +1055,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S LogManager::instance().ItemLog(ch, pDragonSoul, "DS_STRENGTH_REFINE_SUCCESS", buf); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("강화에 성공했습니다.")); ch->AutoGiveItem(pResult, true); - bSubHeader = DS_SUB_HEADER_REFINE_SUCCEED; + bSubHeader = DragonSoulSub::REFINE_SUCCEED; } else { @@ -1072,7 +1072,7 @@ bool DSManager::DoRefineStrength(LPCHARACTER ch, TItemPos (&aItemPoses)[DRAGON_S pDragonSoul->CopyAttributeTo(pResult); RefreshItemAttributes(pResult); } - bSubHeader = DS_SUB_HEADER_REFINE_FAIL; + bSubHeader = DragonSoulSub::REFINE_FAIL; char buf[128]; sprintf(buf, "STRENGTH : %d -> %d", bStrength, bStrength - 1); diff --git a/src/game/OXEvent.cpp b/src/game/OXEvent.cpp index ffcc9e6..d0bd98b 100644 --- a/src/game/OXEvent.cpp +++ b/src/game/OXEvent.cpp @@ -1,9 +1,9 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "config.h" #include "questmanager.h" #include "start_position.h" -#include "packet.h" +#include "packet_structs.h" #include "buffer_manager.h" #include "log.h" #include "char.h" @@ -325,8 +325,8 @@ bool COXEventManager::CheckAnswer(bool answer) ++len; TPacketGCChat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(TPacketGCChat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(TPacketGCChat) + len; pack_chat.type = CHAT_TYPE_COMMAND; pack_chat.id = 0; diff --git a/src/game/PetSystem.cpp b/src/game/PetSystem.cpp index b2935cd..ba68b1a 100644 --- a/src/game/PetSystem.cpp +++ b/src/game/PetSystem.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "vector.h" #include "char.h" @@ -7,7 +7,7 @@ #include "mob_manager.h" #include "PetSystem.h" #include "common/VnumHelper.h" -#include "packet.h" +#include "packet_structs.h" #include "item_manager.h" #include "item.h" diff --git a/src/game/SecureCipher.cpp b/src/game/SecureCipher.cpp index b34ffc9..1b35253 100644 --- a/src/game/SecureCipher.cpp +++ b/src/game/SecureCipher.cpp @@ -57,6 +57,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)); @@ -118,6 +119,10 @@ bool SecureCipher::ComputeServerKeys(const uint8_t* client_pk) sodium_memzero(m_rx_stream_nonce, NONCE_SIZE); m_rx_stream_nonce[0] = 0x02; + sys_log(0, "[CIPHER] Server keys computed (tx_key: %02x%02x%02x%02x, rx_key: %02x%02x%02x%02x)", + m_tx_key[0], m_tx_key[1], m_tx_key[2], m_tx_key[3], + m_rx_key[0], m_rx_key[1], m_rx_key[2], m_rx_key[3]); + return true; } @@ -172,64 +177,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) diff --git a/src/game/SecureCipher.h b/src/game/SecureCipher.h index 73b87dc..7cba45b 100644 --- a/src/game/SecureCipher.h +++ b/src/game/SecureCipher.h @@ -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); diff --git a/src/game/TrafficProfiler.cpp b/src/game/TrafficProfiler.cpp deleted file mode 100644 index d3844d3..0000000 --- a/src/game/TrafficProfiler.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * - * @file TrafficProfiler.cpp - * @brief TrafficProfiler class implementation file - * @author Bang2ni - * @version 05/07/07 Bang2ni - First release. - * - */ - -#include "stdafx.h" -#include "TrafficProfiler.h" - -TrafficProfiler::TrafficProfiler() - : m_pfProfileLogFile(NULL), m_dwFlushCycle(0), m_tmProfileStartTime(0), m_dwTotalTraffic(0), m_dwTotalPacket(0) -{ - m_aTrafficVec[ 0 ].resize( 256 ); - m_aTrafficVec[ 1 ].resize( 256 ); -} - -TrafficProfiler::~TrafficProfiler() -{ - if ( m_pfProfileLogFile ) - fclose( m_pfProfileLogFile ); -} - -bool TrafficProfiler::Initialize( DWORD dwFlushCycle, const char* pszFileName ) -{ - m_pfProfileLogFile = fopen( pszFileName, "w" ); - if ( !m_pfProfileLogFile ) - return false; - - m_dwFlushCycle = dwFlushCycle; - InitializeProfiling(); - - return true; -} - -bool TrafficProfiler::Flush() -{ - if ( !m_pfProfileLogFile ) - return false; - - // - // Profling result write to file - // - - fprintf( m_pfProfileLogFile, "# Profile Start: %s", ctime( &m_tmProfileStartTime ) ); - fprintf( m_pfProfileLogFile, "Total traffic: %u bytes\n", m_dwTotalTraffic ); - fprintf( m_pfProfileLogFile, "Total used packet: %u\n", m_dwTotalPacket ); - - fprintf( m_pfProfileLogFile, "------------------ Input ------------------\n" ); - - for ( int idx = 0; idx < (int)IODIR_MAX; idx++ ) - { - fprintf( m_pfProfileLogFile, "Packet\tCount\tTotal Size\tAverage\n" ); - - BYTE byHeader = 0; - for ( TrafficVec::iterator it = m_aTrafficVec[ idx ].begin(); it != m_aTrafficVec[ idx ].end(); ++it, byHeader++ ) - { - if ( it->second ) - fprintf( m_pfProfileLogFile, "%d\t%u\t%u\t\t%u\n", byHeader, it->second, it->first, it->first / it->second ); - } - - fprintf( m_pfProfileLogFile, "------------------ Output -----------------\n" ); - } - - time_t cur = time( NULL ); - fprintf( m_pfProfileLogFile, "# Profile End(Flush): %s", ctime( &cur ) ); - fflush( m_pfProfileLogFile ); - - // - // Initialization - // - - InitializeProfiling(); - - return true; -} - -void TrafficProfiler::InitializeProfiling() -{ - m_tmProfileStartTime = time( NULL ); - m_dwTotalPacket = 0; - m_dwTotalTraffic = 0; - - TrafficInfo empty( 0, 0 ); - for ( int idx = 0; idx < (int)IODIR_MAX; idx++ ) - { - for ( TrafficVec::iterator it = m_aTrafficVec[ idx ].begin(); it != m_aTrafficVec[ idx ].end(); ++it ) - *it = empty; - } -} diff --git a/src/game/TrafficProfiler.h b/src/game/TrafficProfiler.h deleted file mode 100644 index 5e5e061..0000000 --- a/src/game/TrafficProfiler.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * - * @file TrafficProfiler.h - * @brief TrafficProfiler class definition file - * @author Bang2ni - * @version 05/07/07 Bang2ni - First release. - * - */ - -#ifndef _METIN_II_TRAFFICPROFILER_H_ -#define _METIN_II_TRAFFICPROFILER_H_ - -/** - * @class TrafficProfiler - * @brief Network I/O traffic 을 패킷 단위로 측정하는 profiler. - * @author Bang2ni - * @version 05/07/07 Bang2ni - First release. - * - * 시간대 별로 Network I/O 의 traffic 을 패킷 단위로 측정하고, Text file 형태로 보고서를 작성한다. - */ -class TrafficProfiler : public singleton< TrafficProfiler > -{ - public: - - /// I/O 방향 - enum IODirection { - IODIR_INPUT = 0, ///< Input - IODIR_OUTPUT, ///< Output - IODIR_MAX - }; - - public: - - /// Constructor - TrafficProfiler( void ); - - /// Destructor - ~TrafficProfiler( void ); - - /// Profiling 에 필요한 초기화를 한다. - /** - * @param [in] dwFlushCycle Flush 주기. 초 단위이다. - * @param [in] pszLogFileName Profiling log file 의 이름 - * @return false 일 경우 profiling log file 을 open 하지 못했다. - * - * profiling log file 을 open(생성) 한다. - */ - bool Initialize( DWORD dwFlushCycle, const char* pszLogFileName ); - - /// Profiling 을 위해 전송됐거나 전송 할 Packet 을 Report 한다. - /** - * @param [in] dir Profiling 할 Packet 의 방향 - * @param [in] byHeader Packet 헤더 - * @param [in] dwSize Packet 의 총 size - * @return Initialize 되지 않았다면 false 를 반환한다. - * - * Packet 에 해당하는 size 를 누적시킨다. - * Initialize 이후나 최근 Flush 된 이후에 Flush 주기 만큼 시간이 흐른 후 호출된다면 Report 이후 Flush 한다. - */ - bool Report( IODirection dir, BYTE byHeader, DWORD dwSize ) - { - ComputeTraffic( dir, byHeader, dwSize ); - if ( (DWORD)(time( NULL ) - m_tmProfileStartTime) >= m_dwFlushCycle ) - return Flush(); - return true; - } - - /// 현재까지 Report 된 내용을 파일에 쓴다. - /** - * @return Initialize 되지 않았다. - */ - bool Flush( void ); - - private: - - /// Profling 에 관련된 variables 를 초기화 한다. - void InitializeProfiling( void ); - - /// Report 된 Packet 의 traffic 를 계산한다. - /** - * @param [in] dir Profiling 할 Packet 의 방향 - * @param [in] byHeader Packet 헤더 - * @param [in] dwSize Packet 의 총 size - */ - void ComputeTraffic( IODirection dir, BYTE byHeader, DWORD dwSize ) - { - - TrafficInfo& rTrafficInfo = m_aTrafficVec[ dir ][ byHeader ]; - - m_dwTotalTraffic += dwSize; - m_dwTotalPacket += !rTrafficInfo.second; - - rTrafficInfo.first += dwSize; - rTrafficInfo.second++; - } - - /// Traffic info type. - /** - * first: 누적된 총 size - * second: 이 packet 이 전송된 횟수 - */ - typedef std::pair< DWORD, DWORD > TrafficInfo; - - /// Traffic info vector. - typedef std::vector< TrafficInfo > TrafficVec; - - FILE* m_pfProfileLogFile; ///< Profile log file pointer - DWORD m_dwFlushCycle; ///< Flush 주기 - time_t m_tmProfileStartTime; ///< 프로파일을 시작한 시간. Flush 될 때마다 Update 된다. - DWORD m_dwTotalTraffic; ///< Report 된 총 Traffic 용량 - DWORD m_dwTotalPacket; ///< Report 된 총 Packet 수 - TrafficVec m_aTrafficVec[ IODIR_MAX ]; ///< Report 된 Traffic 을 저장할 vector의 배열. 각 방향마다 vector 를 가진다. -}; - -#endif // _METIN_II_TRAFFICPROFILER_H_ diff --git a/src/game/arena.cpp b/src/game/arena.cpp index d914bb7..08d2e7d 100644 --- a/src/game/arena.cpp +++ b/src/game/arena.cpp @@ -1,7 +1,7 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "config.h" -#include "packet.h" +#include "packet_structs.h" #include "desc.h" #include "buffer_manager.h" #include "start_position.h" @@ -294,8 +294,8 @@ EVENTFUNC(ready_to_start_event) pArena->SendChatPacketToObserver(CHAT_TYPE_INFO, LC_TEXT("대련이 시작되었습니다.")); TPacketGCDuelStart duelStart; - duelStart.header = HEADER_GC_DUEL_START; - duelStart.wSize = sizeof(TPacketGCDuelStart) + 4; + duelStart.header = GC::DUEL_START; + duelStart.length = sizeof(TPacketGCDuelStart) + 4; DWORD dwOppList[8]; // 최대 파티원 8명 이므로.. @@ -348,8 +348,8 @@ EVENTFUNC(ready_to_start_event) TEMP_BUFFER buf2; DWORD dwOppList[8]; // 최대 파티원 8명 이므로.. TPacketGCDuelStart duelStart; - duelStart.header = HEADER_GC_DUEL_START; - duelStart.wSize = sizeof(TPacketGCDuelStart) + 4; + duelStart.header = GC::DUEL_START; + duelStart.length = sizeof(TPacketGCDuelStart) + 4; dwOppList[0] = (DWORD)chB->GetVID(); buf.write(&duelStart, sizeof(TPacketGCDuelStart)); @@ -444,8 +444,8 @@ EVENTFUNC(duel_time_out) chB->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("10초뒤 마을로 이동합니다.")); TPacketGCDuelStart duelStart; - duelStart.header = HEADER_GC_DUEL_START; - duelStart.wSize = sizeof(TPacketGCDuelStart); + duelStart.header = GC::DUEL_START; + duelStart.length = sizeof(TPacketGCDuelStart); chA->GetDesc()->Packet(&duelStart, sizeof(TPacketGCDuelStart)); chA->GetDesc()->Packet(&duelStart, sizeof(TPacketGCDuelStart)); diff --git a/src/game/battle.cpp b/src/game/battle.cpp index 854a3f1..db5e2a1 100644 --- a/src/game/battle.cpp +++ b/src/game/battle.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "config.h" #include "desc.h" @@ -9,7 +9,7 @@ #include "item_manager.h" #include "mob_manager.h" #include "vector.h" -#include "packet.h" +#include "packet_structs.h" #include "pvp.h" #include "profiler.h" #include "guild.h" @@ -382,6 +382,16 @@ int CalcMeleeDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnoreDe LPITEM pWeapon = pkAttacker->GetWear(WEAR_WEAPON); bool bPolymorphed = pkAttacker->IsPolymorphed(); + // DEBUG: Log weapon and attack info + if (pkAttacker->IsPC()) + { + sys_log(0, "CalcMeleeDamage: attacker=%s weapon=%s vnum=%u ignoredef=%d", + pkAttacker->GetName(), + pWeapon ? pWeapon->GetName() : "NONE", + pWeapon ? pWeapon->GetVnum() : 0, + bIgnoreDefense); + } + if (pWeapon && !(bPolymorphed && !pkAttacker->IsPolyMaintainStat())) { if (pWeapon->GetType() != ITEM_WEAPON) @@ -485,6 +495,13 @@ int CalcMeleeDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnoreDe iDam = MAX(0, iAtk - iDef); + // DEBUG: Log damage calculation for players + if (pkAttacker->IsPC()) + { + sys_log(0, "CalcMeleeDamage RESULT: atk=%d def=%d dam=%d (weaponDam=%d, fAR=%.2f)", + iAtk, iDef, iDam, DEBUG_iDamCur, fAR); + } + if (test_server) { int DEBUG_iLV = pkAttacker->GetLevel()*2; diff --git a/src/game/buffer_manager.cpp b/src/game/buffer_manager.cpp index 235d4cc..03cb7bc 100644 --- a/src/game/buffer_manager.cpp +++ b/src/game/buffer_manager.cpp @@ -1,38 +1,41 @@ -#include "stdafx.h" +#include "stdafx.h" #include "buffer_manager.h" TEMP_BUFFER::TEMP_BUFFER(int Size, bool bForceDelete) { - forceDelete = bForceDelete; + if (bForceDelete) + Size = std::max(Size, 1024 * 128); - if (forceDelete) - Size = MAX(Size, 1024 * 128); - - buf = buffer_new(Size); -} - -TEMP_BUFFER::~TEMP_BUFFER() -{ - buffer_delete(buf); + m_buf.Reserve(static_cast(Size)); } const void * TEMP_BUFFER::read_peek() { - return (buffer_read_peek(buf)); + return m_buf.ReadPtr(); } void TEMP_BUFFER::write(const void * data, int size) { - buffer_write(buf, data, size); + m_buf.Write(data, static_cast(size)); } int TEMP_BUFFER::size() { - return buffer_size(buf); + return static_cast(m_buf.ReadableBytes()); } void TEMP_BUFFER::reset() { - buffer_reset(buf); + m_buf.Clear(); } +void* TEMP_BUFFER::write_peek(int size) +{ + m_buf.EnsureWritable(static_cast(size)); + return m_buf.WritePtr(); +} + +void TEMP_BUFFER::write_proceed(int size) +{ + m_buf.CommitWrite(static_cast(size)); +} diff --git a/src/game/buffer_manager.h b/src/game/buffer_manager.h index bb8f6f8..995b07e 100644 --- a/src/game/buffer_manager.h +++ b/src/game/buffer_manager.h @@ -1,22 +1,25 @@ -#ifndef __INC_METIN_II_GAME_BUFFER_MANAGER_H__ +#ifndef __INC_METIN_II_GAME_BUFFER_MANAGER_H__ #define __INC_METIN_II_GAME_BUFFER_MANAGER_H__ +#include "libthecore/ring_buffer.h" + class TEMP_BUFFER { public: - TEMP_BUFFER(int Size = 8192, bool ForceDelete = false ); - ~TEMP_BUFFER(); + TEMP_BUFFER(int Size = 8192, bool ForceDelete = false); + ~TEMP_BUFFER() = default; const void * read_peek(); void write(const void * data, int size); int size(); void reset(); - LPBUFFER getptr() { return buf; } + // Direct write access for building packets with deferred headers + void* write_peek(int size); + void write_proceed(int size); protected: - LPBUFFER buf; - bool forceDelete; + RingBuffer m_buf; }; #endif diff --git a/src/game/building.cpp b/src/game/building.cpp index c8e43d8..b1421d2 100644 --- a/src/game/building.cpp +++ b/src/game/building.cpp @@ -1,10 +1,10 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "sectree_manager.h" #include "item_manager.h" #include "buffer_manager.h" #include "config.h" -#include "packet.h" +#include "packet_structs.h" #include "char.h" #include "char_manager.h" #include "guild.h" @@ -103,7 +103,8 @@ void CObject::EncodeInsertPacket(LPENTITY entity) memset(&pack, 0, sizeof(TPacketGCCharacterAdd)); - pack.header = HEADER_GC_CHARACTER_ADD; + pack.header = GC::CHARACTER_ADD; + pack.length = sizeof(pack); pack.dwVID = m_dwVID; pack.bType = CHAR_TYPE_BUILDING; pack.angle = m_data.zRot; @@ -136,7 +137,8 @@ void CObject::EncodeRemovePacket(LPENTITY entity) TPacketGCCharacterDelete pack; - pack.header = HEADER_GC_CHARACTER_DEL; + pack.header = GC::CHARACTER_DEL; + pack.length = sizeof(pack); pack.id = m_dwVID; d->Packet(&pack, sizeof(TPacketGCCharacterDelete)); @@ -573,7 +575,7 @@ bool CLand::RequestCreateObject(DWORD dwVnum, long lMapIndex, long x, long y, fl p.yRot = yRot; p.zRot = zRot; - db_clientdesc->DBPacket(HEADER_GD_CREATE_OBJECT, 0, &p, sizeof(TPacketGDCreateObject)); + db_clientdesc->DBPacket(GD::CREATE_OBJECT, 0, &p, sizeof(TPacketGDCreateObject)); return true; } @@ -585,7 +587,7 @@ void CLand::RequestDeleteObject(DWORD dwID) return; } - db_clientdesc->DBPacket(HEADER_GD_DELETE_OBJECT, 0, &dwID, sizeof(DWORD)); + db_clientdesc->DBPacket(GD::DELETE_OBJECT, 0, &dwID, sizeof(DWORD)); sys_log(0, "RequestDeleteObject id %u", dwID); } @@ -600,7 +602,7 @@ void CLand::RequestDeleteObjectByVID(DWORD dwVID) } DWORD dwID = pkObj->GetID(); - db_clientdesc->DBPacket(HEADER_GD_DELETE_OBJECT, 0, &dwID, sizeof(DWORD)); + db_clientdesc->DBPacket(GD::DELETE_OBJECT, 0, &dwID, sizeof(DWORD)); sys_log(0, "RequestDeleteObject vid %u id %u", dwVID, dwID); } @@ -620,7 +622,7 @@ void CLand::RequestUpdate(DWORD dwGuild) a[0] = GetID(); a[1] = dwGuild; - db_clientdesc->DBPacket(HEADER_GD_UPDATE_LAND, 0, &a[0], sizeof(DWORD) * 2); + db_clientdesc->DBPacket(GD::UPDATE_LAND, 0, &a[0], sizeof(DWORD) * 2); sys_log(0, "RequestUpdate id %u guild %u", a[0], a[1]); } @@ -724,8 +726,8 @@ void CManager::UpdateLand(TLand * pTable) TPacketGCLandList p; - p.header = HEADER_GC_LAND_LIST; - p.size = sizeof(TPacketGCLandList) + sizeof(TLandPacketElement); + p.header = GC::LAND_LIST; + p.length = sizeof(TPacketGCLandList) + sizeof(TLandPacketElement); TLandPacketElement e; @@ -984,8 +986,8 @@ void CManager::SendLandList(LPDESC d, long lMapIndex) { TPacketGCLandList p; - p.header = HEADER_GC_LAND_LIST; - p.size = sizeof(TPacketGCLandList) + buf.size(); + p.header = GC::LAND_LIST; + p.length = sizeof(TPacketGCLandList) + buf.size(); d->BufferedPacket(&p, sizeof(TPacketGCLandList)); d->Packet(buf.read_peek(), buf.size()); diff --git a/src/game/castle.cpp b/src/game/castle.cpp index b9b6f41..fce72ab 100644 --- a/src/game/castle.cpp +++ b/src/game/castle.cpp @@ -15,7 +15,6 @@ #include "char_manager.h" #include "castle.h" #include "start_position.h" -#include "monarch.h" #include "questlua.h" #include "log.h" #include "char.h" @@ -838,7 +837,6 @@ void castle_frog_die(LPCHARACTER ch, LPCHARACTER killer) GET_FROG(empire, i) = NULL; killer->PointChange(POINT_GOLD, 10000000 /*1천만*/, true); - //CMonarch::instance().SendtoDBAddMoney(30000000/*3천만*/, killer->GetEmpire(), killer); castle_save(); return; } @@ -1041,9 +1039,6 @@ bool castle_frog_to_empire_money(LPCHARACTER ch) LPCHARACTER npc = GET_FROG(empire, i); - if (false == CMonarch::instance().SendtoDBAddMoney(CASTLE_FROG_PRICE, empire, ch)) - return false; - GET_FROG(empire, i) = NULL; // 등록해제 npc->Dead(/*killer*/NULL, /*immediate_dead*/true); return true; diff --git a/src/game/char.cpp b/src/game/char.cpp index b2e938f..db4aee8 100644 --- a/src/game/char.cpp +++ b/src/game/char.cpp @@ -14,7 +14,7 @@ #include "item_manager.h" #include "motion.h" #include "vector.h" -#include "packet.h" +#include "packet_structs.h" #include "cmd.h" #include "fishing.h" #include "exchange.h" @@ -43,7 +43,6 @@ #include "wedding.h" #include "mob_manager.h" #include "mining.h" -#include "monarch.h" #include "castle.h" #include "arena.h" #include "horsename_manager.h" @@ -263,8 +262,6 @@ void CHARACTER::Initialize() m_dwQuestByVnum = 0; m_pQuestItem = NULL; - m_szMobileAuth[0] = '\0'; - m_dwUnderGuildWarInfoMessageTime = get_dword_time()-60000; m_bUnderRefine = false; @@ -335,8 +332,6 @@ void CHARACTER::Initialize() m_iMyShopTime = 0; - InitMC(); - m_deposit_pulse = 0; SET_OVER_TIME(this, OT_NONE); @@ -715,7 +710,7 @@ void CHARACTER::OpenMyShop(const char * c_pszSign, TShopItemTable * pTable, BYTE // buf.write(&info, sizeof(info)); // } - // db_clientdesc->DBPacket(HEADER_GD_MYSHOP_PRICELIST_UPDATE, 0, buf.read_peek(), buf.size()); + // db_clientdesc->DBPacket(GD::MYSHOP_PRICELIST_UPDATE, 0, buf.read_peek(), buf.size()); // Fixed code: TItemPriceListTable header; @@ -732,7 +727,7 @@ void CHARACTER::OpenMyShop(const char * c_pszSign, TShopItemTable * pTable, BYTE idx++; } - db_clientdesc->DBPacket(HEADER_GD_MYSHOP_PRICELIST_UPDATE, GetDesc()->GetHandle(), &header, sizeof(TItemPriceListTable)); + db_clientdesc->DBPacket(GD::MYSHOP_PRICELIST_UPDATE, GetDesc()->GetHandle(), &header, sizeof(TItemPriceListTable)); } // END_OF_MYSHOP_PRICE_LIST else if (CountSpecifyItem(50200)) @@ -745,7 +740,8 @@ void CHARACTER::OpenMyShop(const char * c_pszSign, TShopItemTable * pTable, BYTE TPacketGCShopSign p; - p.bHeader = HEADER_GC_SHOP_SIGN; + p.header = GC::SHOP_SIGN; + p.length = sizeof(p); p.dwVID = GetVID(); strlcpy(p.szSign, c_pszSign, sizeof(p.szSign)); @@ -784,7 +780,8 @@ void CHARACTER::CloseMyShop() TPacketGCShopSign p; - p.bHeader = HEADER_GC_SHOP_SIGN; + p.header = GC::SHOP_SIGN; + p.length = sizeof(p); p.dwVID = GetVID(); p.szSign[0] = '\0'; @@ -797,7 +794,8 @@ void CHARACTER::CloseMyShop() void EncodeMovePacket(TPacketGCMove & pack, DWORD dwVID, BYTE bFunc, BYTE bArg, DWORD x, DWORD y, DWORD dwDuration, DWORD dwTime, BYTE bRot) { - pack.bHeader = HEADER_GC_MOVE; + pack.header = GC::MOVE; + pack.length = sizeof(pack); pack.bFunc = bFunc; pack.bArg = bArg; pack.dwVID = dwVID; @@ -862,7 +860,8 @@ void CHARACTER::EncodeInsertPacket(LPENTITY entity) TPacketGCCharacterAdd pack; - pack.header = HEADER_GC_CHARACTER_ADD; + pack.header = GC::CHARACTER_ADD; + pack.length = sizeof(pack); pack.dwVID = m_vid; pack.bType = GetCharType(); pack.angle = GetRotation(); @@ -904,7 +903,8 @@ void CHARACTER::EncodeInsertPacket(LPENTITY entity) TPacketGCCharacterAdditionalInfo addPacket; memset(&addPacket, 0, sizeof(TPacketGCCharacterAdditionalInfo)); - addPacket.header = HEADER_GC_CHAR_ADDITIONAL_INFO; + addPacket.header = GC::CHAR_ADDITIONAL_INFO; + addPacket.length = sizeof(addPacket); addPacket.dwVID = m_vid; addPacket.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN); @@ -967,8 +967,9 @@ void CHARACTER::EncodeInsertPacket(LPENTITY entity) d->Packet(&pack, sizeof(pack)); TPacketGCWalkMode p; + p.header = GC::WALK_MODE; + p.length = sizeof(p); p.vid = GetVID(); - p.header = HEADER_GC_WALK_MODE; p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN; d->Packet(&p, sizeof(p)); @@ -980,8 +981,9 @@ void CHARACTER::EncodeInsertPacket(LPENTITY entity) if (ch->IsWalking()) { TPacketGCWalkMode p; + p.header = GC::WALK_MODE; + p.length = sizeof(p); p.vid = ch->GetVID(); - p.header = HEADER_GC_WALK_MODE; p.mode = ch->m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN; GetDesc()->Packet(&p, sizeof(p)); } @@ -991,7 +993,8 @@ void CHARACTER::EncodeInsertPacket(LPENTITY entity) { TPacketGCShopSign p; - p.bHeader = HEADER_GC_SHOP_SIGN; + p.header = GC::SHOP_SIGN; + p.length = sizeof(p); p.dwVID = GetVID(); strlcpy(p.szSign, m_stShopSign.c_str(), sizeof(p.szSign)); @@ -1017,7 +1020,8 @@ void CHARACTER::EncodeRemovePacket(LPENTITY entity) TPacketGCCharacterDelete pack; - pack.header = HEADER_GC_CHARACTER_DEL; + pack.header = GC::CHARACTER_DEL; + pack.length = sizeof(pack); pack.id = m_vid; d->Packet(&pack, sizeof(TPacketGCCharacterDelete)); @@ -1036,7 +1040,8 @@ void CHARACTER::UpdatePacket() TPacketGCCharacterUpdate pack; TPacketGCCharacterUpdate pack2; - pack.header = HEADER_GC_CHARACTER_UPDATE; + pack.header = GC::CHARACTER_UPDATE; + pack.length = sizeof(pack); pack.dwVID = m_vid; pack.awPart[CHR_EQUIPPART_ARMOR] = GetPart(PART_MAIN); @@ -1275,9 +1280,6 @@ void CHARACTER::CreatePlayerProto(TPlayerTable & tab) for (int i = 0; i < QUICKSLOT_MAX_NUM; ++i) tab.quickslot[i] = m_quickslot[i]; - if (m_stMobile.length() && !*m_szMobileAuth) - strlcpy(tab.szMobile, m_stMobile.c_str(), sizeof(tab.szMobile)); - thecore_memcpy(tab.parts, m_pointsInstant.parts, sizeof(tab.parts)); // REMOVE_REAL_SKILL_LEVLES @@ -1302,7 +1304,7 @@ void CHARACTER::SaveReal() TPlayerTable table; CreatePlayerProto(table); - db_clientdesc->DBPacket(HEADER_GD_PLAYER_SAVE, GetDesc()->GetHandle(), &table, sizeof(TPlayerTable)); + db_clientdesc->DBPacket(GD::PLAYER_SAVE, GetDesc()->GetHandle(), &table, sizeof(TPlayerTable)); quest::PC * pkQuestPC = quest::CQuestManager::instance().GetPCForce(GetPlayerID()); @@ -1354,7 +1356,8 @@ void CHARACTER::Disconnect(const char * c_pszReason) // P2P Logout TPacketGGLogout p; - p.bHeader = HEADER_GG_LOGOUT; + p.header = GG::LOGOUT; + p.length = sizeof(p); strlcpy(p.szName, GetName(), sizeof(p.szName)); P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGLogout)); char buf[51]; @@ -1422,7 +1425,8 @@ void CHARACTER::Disconnect(const char * c_pszReason) PointsPacket(); packet_point_change pack; - pack.header = HEADER_GC_CHARACTER_POINT_CHANGE; + pack.header = GC::PLAYER_POINT_CHANGE; + pack.length = sizeof(pack); pack.dwVID = m_vid; pack.type = POINT_PLAYTIME; pack.value = GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000; @@ -1572,66 +1576,33 @@ void CHARACTER::MainCharacterPacket() const unsigned mapIndex = GetMapIndex(); const BGMInfo& bgmInfo = CHARACTER_GetBGMInfo(mapIndex); - // SUPPORT_BGM + TPacketGCMainCharacter pack; + pack.header = GC::MAIN_CHARACTER; + pack.length = sizeof(pack); + pack.dwVID = m_vid; + pack.wRaceNum = GetRaceNum(); + pack.lx = GetX(); + pack.ly = GetY(); + pack.lz = GetZ(); + pack.empire = GetDesc()->GetEmpire(); + pack.skill_group = GetSkillGroup(); + strlcpy(pack.szName, GetName(), sizeof(pack.szName)); + if (!bgmInfo.name.empty()) { - if (CHARACTER_IsBGMVolumeEnable()) - { - sys_log(1, "bgm_info.play_bgm_vol(%d, name='%s', vol=%f)", mapIndex, bgmInfo.name.c_str(), bgmInfo.vol); - TPacketGCMainCharacter4_BGM_VOL mainChrPacket; - mainChrPacket.header = HEADER_GC_MAIN_CHARACTER4_BGM_VOL; - mainChrPacket.dwVID = m_vid; - mainChrPacket.wRaceNum = GetRaceNum(); - mainChrPacket.lx = GetX(); - mainChrPacket.ly = GetY(); - mainChrPacket.lz = GetZ(); - mainChrPacket.empire = GetDesc()->GetEmpire(); - mainChrPacket.skill_group = GetSkillGroup(); - strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName)); - - mainChrPacket.fBGMVol = bgmInfo.vol; - strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName)); - GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter4_BGM_VOL)); - } - else - { - sys_log(1, "bgm_info.play(%d, '%s')", mapIndex, bgmInfo.name.c_str()); - TPacketGCMainCharacter3_BGM mainChrPacket; - mainChrPacket.header = HEADER_GC_MAIN_CHARACTER3_BGM; - mainChrPacket.dwVID = m_vid; - mainChrPacket.wRaceNum = GetRaceNum(); - mainChrPacket.lx = GetX(); - mainChrPacket.ly = GetY(); - mainChrPacket.lz = GetZ(); - mainChrPacket.empire = GetDesc()->GetEmpire(); - mainChrPacket.skill_group = GetSkillGroup(); - strlcpy(mainChrPacket.szChrName, GetName(), sizeof(mainChrPacket.szChrName)); - strlcpy(mainChrPacket.szBGMName, bgmInfo.name.c_str(), sizeof(mainChrPacket.szBGMName)); - GetDesc()->Packet(&mainChrPacket, sizeof(TPacketGCMainCharacter3_BGM)); - } - //if (m_stMobile.length()) - // ChatPacket(CHAT_TYPE_COMMAND, "sms"); + strlcpy(pack.szBGMName, bgmInfo.name.c_str(), sizeof(pack.szBGMName)); + pack.fBGMVol = CHARACTER_IsBGMVolumeEnable() ? bgmInfo.vol : 0.0f; + sys_log(1, "bgm_info.play(%d, name='%s', vol=%f)", mapIndex, bgmInfo.name.c_str(), pack.fBGMVol); } - // END_OF_SUPPORT_BGM else { + pack.szBGMName[0] = '\0'; + pack.fBGMVol = 0.0f; sys_log(0, "bgm_info.play(%d, DEFAULT_BGM_NAME)", mapIndex); - - TPacketGCMainCharacter pack; - pack.header = HEADER_GC_MAIN_CHARACTER; - pack.dwVID = m_vid; - pack.wRaceNum = GetRaceNum(); - pack.lx = GetX(); - pack.ly = GetY(); - pack.lz = GetZ(); - pack.empire = GetDesc()->GetEmpire(); - pack.skill_group = GetSkillGroup(); - strlcpy(pack.szName, GetName(), sizeof(pack.szName)); - GetDesc()->Packet(&pack, sizeof(TPacketGCMainCharacter)); - - if (m_stMobile.length()) - ChatPacket(CHAT_TYPE_COMMAND, "sms"); } + + GetDesc()->Packet(&pack, sizeof(pack)); + } void CHARACTER::PointsPacket() @@ -1641,7 +1612,8 @@ void CHARACTER::PointsPacket() TPacketGCPoints pack; - pack.header = HEADER_GC_CHARACTER_POINTS; + pack.header = GC::PLAYER_POINTS; + pack.length = sizeof(pack); pack.points[POINT_LEVEL] = GetLevel(); pack.points[POINT_EXP] = GetExp(); @@ -1853,8 +1825,6 @@ void CHARACTER::SetPlayerProto(const TPlayerTable * t) if (GetLevel() < PK_PROTECT_LEVEL) m_bPKMode = PK_MODE_PROTECT; - m_stMobile = t->szMobile; - SetHorseData(t->horse); if (GetHorseLevel() > 0) @@ -2598,7 +2568,8 @@ void CHARACTER::Standup() sys_log(1, "STANDUP: %s", GetName()); - pack_position.header = HEADER_GC_CHARACTER_POSITION; + pack_position.header = GC::CHARACTER_POSITION; + pack_position.length = sizeof(pack_position); pack_position.vid = GetVID(); pack_position.position = POSITION_GENERAL; @@ -2615,7 +2586,8 @@ void CHARACTER::Sitdown(int is_ground) SetPosition(POS_SITTING); sys_log(1, "SITDOWN: %s", GetName()); - pack_position.header = HEADER_GC_CHARACTER_POSITION; + pack_position.header = GC::CHARACTER_POSITION; + pack_position.length = sizeof(pack_position); pack_position.vid = GetVID(); pack_position.position = POSITION_SITTING_GROUND; PacketAround(&pack_position, sizeof(pack_position)); @@ -3768,7 +3740,8 @@ void CHARACTER::PointChange(BYTE type, int amount, bool bAmount, bool bBroadcast { struct packet_point_change pack; - pack.header = HEADER_GC_CHARACTER_POINT_CHANGE; + pack.header = GC::PLAYER_POINT_CHANGE; + pack.length = sizeof(pack); pack.dwVID = m_vid; pack.type = type; pack.value = val; @@ -3947,7 +3920,8 @@ void CHARACTER::ApplyPoint(BYTE bApplyType, int iVal) void CHARACTER::MotionPacketEncode(BYTE motion, LPCHARACTER victim, struct packet_motion * packet) { - packet->header = HEADER_GC_MOTION; + packet->header = GC::MOTION; + packet->length = sizeof(*packet); packet->vid = m_vid; packet->motion = motion; @@ -4027,8 +4001,8 @@ void CHARACTER::MonsterLog(const char* format, ...) TPacketGCChat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(TPacketGCChat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(TPacketGCChat) + len; pack_chat.type = CHAT_TYPE_TALKING; pack_chat.id = (DWORD)GetVID(); pack_chat.bEmpire = 0; @@ -4056,8 +4030,8 @@ void CHARACTER::ChatPacket(BYTE type, const char * format, ...) struct packet_chat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(struct packet_chat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(struct packet_chat) + len; pack_chat.type = type; pack_chat.id = 0; pack_chat.bEmpire = d->GetEmpire(); @@ -4080,7 +4054,8 @@ void CHARACTER::ItemGetPacket(DWORD dwItemVnum, BYTE bCount, const char* szName, return; TPacketGCItemGet pack; - pack.header = HEADER_GC_ITEM_GET; + pack.header = GC::ITEM_GET; + pack.length = sizeof(pack); pack.dwItemVnum = dwItemVnum; pack.bCount = bCount; // bArg: 0 = normal, 1 = from party member, 2 = delivered to party member @@ -4134,7 +4109,8 @@ void CHARACTER::mining(LPCHARACTER chLoad) // 채광 동작을 보여줌 TPacketGCDigMotion p; - p.header = HEADER_GC_DIG_MOTION; + p.header = GC::DIG_MOTION; + p.length = sizeof(p); p.vid = GetVID(); p.target_vid = chLoad->GetVID(); p.count = count; @@ -4391,7 +4367,8 @@ bool CHARACTER::SetSyncOwner(LPCHARACTER ch, bool bRemoveFromList) // 보내는 방식으로 하면 패킷을 줄일 수 있다. TPacketGCOwnership pack; - pack.bHeader = HEADER_GC_OWNERSHIP; + pack.header = GC::OWNERSHIP; + pack.length = sizeof(pack); pack.dwOwnerVID = ch ? ch->GetVID() : 0; pack.dwVictimVID = GetVID(); @@ -4757,7 +4734,8 @@ void CHARACTER::PartyInvite(LPCHARACTER pchInvitee) // TPacketGCPartyInvite p; - p.header = HEADER_GC_PARTY_INVITE; + p.header = GC::PARTY_INVITE; + p.length = sizeof(p); p.leader_vid = GetVID(); pchInvitee->GetDesc()->Packet(&p, sizeof(p)); } @@ -5232,7 +5210,8 @@ void CHARACTER::ClearTarget() TPacketGCTarget p; - p.header = HEADER_GC_TARGET; + p.header = GC::TARGET; + p.length = sizeof(p); p.dwVID = 0; p.bHPPercent = 0; @@ -5272,7 +5251,8 @@ void CHARACTER::SetTarget(LPCHARACTER pkChrTarget) TPacketGCTarget p; - p.header = HEADER_GC_TARGET; + p.header = GC::TARGET; + p.length = sizeof(p); if (m_pkChrTarget) { @@ -5329,7 +5309,8 @@ void CHARACTER::BroadcastTargetPacket() TPacketGCTarget p; - p.header = HEADER_GC_TARGET; + p.header = GC::TARGET; + p.length = sizeof(p); p.dwVID = GetVID(); if (IsPC()) @@ -5443,7 +5424,8 @@ bool CHARACTER::WarpSet(long x, long y, long lPrivateMapIndex) TPacketGCWarp p; - p.bHeader = HEADER_GC_WARP; + p.header = GC::WARP; + p.length = sizeof(p); p.lX = x; p.lY = y; p.lAddr = lAddr; @@ -5500,7 +5482,8 @@ void CHARACTER::WarpEnd() // P2P Login TPacketGGLogin p; - p.bHeader = HEADER_GG_LOGIN; + p.header = GG::LOGIN; + p.length = sizeof(p); strlcpy(p.szName, GetName(), sizeof(p.szName)); p.dwPID = GetPlayerID(); p.bEmpire = GetEmpire(); @@ -5750,7 +5733,7 @@ void CHARACTER::ReqSafeboxLoad(const char* pszPassword) strlcpy(p.szLogin, GetDesc()->GetAccountTable().login, sizeof(p.szLogin)); strlcpy(p.szPassword, pszPassword, sizeof(p.szPassword)); - db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_LOAD, GetDesc()->GetHandle(), &p, sizeof(p)); + db_clientdesc->DBPacket(GD::SAFEBOX_LOAD, GetDesc()->GetHandle(), &p, sizeof(p)); } void CHARACTER::LoadSafebox(int iSize, DWORD dwGold, int iItemCount, TPlayerItem * pItems) @@ -5773,7 +5756,8 @@ void CHARACTER::LoadSafebox(int iSize, DWORD dwGold, int iItemCount, TPlayerItem TPacketCGSafeboxSize p; - p.bHeader = HEADER_GC_SAFEBOX_SIZE; + p.header = GC::SAFEBOX_SIZE; + p.length = sizeof(p); p.bSize = iSize; GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize)); @@ -5814,7 +5798,8 @@ void CHARACTER::ChangeSafeboxSize(BYTE bSize) TPacketCGSafeboxSize p; - p.bHeader = HEADER_GC_SAFEBOX_SIZE; + p.header = GC::SAFEBOX_SIZE; + p.length = sizeof(p); p.bSize = bSize; GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize)); @@ -5868,7 +5853,8 @@ void CHARACTER::LoadMall(int iItemCount, TPlayerItem * pItems) TPacketCGSafeboxSize p; - p.bHeader = HEADER_GC_MALL_OPEN; + p.header = GC::MALL_OPEN; + p.length = sizeof(p); p.bSize = 3 * SAFEBOX_PAGE_SIZE; GetDesc()->Packet(&p, sizeof(TPacketCGSafeboxSize)); @@ -5920,7 +5906,8 @@ bool CHARACTER::BuildUpdatePartyPacket(TPacketGCPartyUpdate & out) memset(&out, 0, sizeof(out)); - out.header = HEADER_GC_PARTY_UPDATE; + out.header = GC::PARTY_UPDATE; + out.length = sizeof(out); out.pid = GetPlayerID(); out.percent_hp = MINMAX(0, GetHP() * 100 / GetMaxHP(), 100); out.role = GetParty()->GetRole(GetPlayerID()); @@ -5995,7 +5982,8 @@ void CHARACTER::SetNowWalking(bool bWalkFlag) { TPacketGCWalkMode p; p.vid = GetVID(); - p.header = HEADER_GC_WALK_MODE; + p.header = GC::WALK_MODE; + p.length = sizeof(p); p.mode = m_bNowWalking ? WALKMODE_WALK : WALKMODE_RUN; PacketView(&p, sizeof(p)); @@ -6176,7 +6164,8 @@ void CHARACTER::EffectPacket(int enumEffectType) { TPacketGCSpecialEffect p; - p.header = HEADER_GC_SEPCIAL_EFFECT; + p.header = GC::SEPCIAL_EFFECT; + p.length = sizeof(p); p.type = enumEffectType; p.vid = GetVID(); @@ -6187,7 +6176,8 @@ void CHARACTER::SpecificEffectPacket(const std::string& stEffectName) { TPacketGCSpecificEffect p; - p.header = HEADER_GC_SPECIFIC_EFFECT; + p.header = GC::SPECIFIC_EFFECT; + p.length = sizeof(p); p.vid = GetVID(); strlcpy(p.effect_file, stEffectName.c_str(), sizeof(p.effect_file)); @@ -6236,8 +6226,8 @@ void CHARACTER::MonsterChat(BYTE bMonsterChatType) struct packet_chat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(struct packet_chat) + text.size() + 1; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(struct packet_chat) + text.size() + 1; pack_chat.type = CHAT_TYPE_TALKING; pack_chat.id = GetVID(); pack_chat.bEmpire = 0; @@ -6430,7 +6420,8 @@ void CHARACTER::DetermineDropMetinStone() void CHARACTER::SendEquipment(LPCHARACTER ch) { TPacketViewEquip p; - p.header = HEADER_GC_VIEW_EQUIP; + p.header = GC::VIEW_EQUIP; + p.length = sizeof(p); p.vid = GetVID(); for (int i = 0; ipkDesc->Packet(&p, sizeof(TPacketGGFindPosition)); @@ -6894,24 +6887,14 @@ bool CHARACTER::IsHack(bool bSendMsg, bool bCheckShopOwner, int limittime) return false; } -BOOL CHARACTER::IsMonarch() const -{ - //MONARCH_LIMIT - if (CMonarch::instance().IsMonarch(GetPlayerID(), GetEmpire())) - return true; - - return false; - - //END_MONARCH_LIMIT -} void CHARACTER::Say(const std::string & s) { struct ::packet_script packet_script; - packet_script.header = HEADER_GC_SCRIPT; + packet_script.header = GC::SCRIPT; packet_script.skin = 1; packet_script.src_size = s.size(); - packet_script.size = packet_script.src_size + sizeof(struct packet_script); + packet_script.length = packet_script.src_size + sizeof(struct packet_script); TEMP_BUFFER buf; @@ -6924,72 +6907,6 @@ void CHARACTER::Say(const std::string & s) } } -// -// Monarch -// -void CHARACTER::InitMC() -{ - for (int n = 0; n < MI_MAX; ++n) - { - m_dwMonarchCooltime[n] = thecore_pulse(); - } - - m_dwMonarchCooltimelimit[MI_HEAL] = PASSES_PER_SEC(MC_HEAL); - m_dwMonarchCooltimelimit[MI_WARP] = PASSES_PER_SEC(MC_WARP); - m_dwMonarchCooltimelimit[MI_TRANSFER] = PASSES_PER_SEC(MC_TRANSFER); - m_dwMonarchCooltimelimit[MI_TAX] = PASSES_PER_SEC(MC_TAX); - m_dwMonarchCooltimelimit[MI_SUMMON] = PASSES_PER_SEC(MC_SUMMON); - - m_dwMonarchCooltime[MI_HEAL] -= PASSES_PER_SEC(GetMCL(MI_HEAL)); - m_dwMonarchCooltime[MI_WARP] -= PASSES_PER_SEC(GetMCL(MI_WARP)); - m_dwMonarchCooltime[MI_TRANSFER] -= PASSES_PER_SEC(GetMCL(MI_TRANSFER)); - m_dwMonarchCooltime[MI_TAX] -= PASSES_PER_SEC(GetMCL(MI_TAX)); - m_dwMonarchCooltime[MI_SUMMON] -= PASSES_PER_SEC(GetMCL(MI_SUMMON)); -} - -DWORD CHARACTER::GetMC(enum MONARCH_INDEX e) const -{ - return m_dwMonarchCooltime[e]; -} - -void CHARACTER::SetMC(enum MONARCH_INDEX e) -{ - m_dwMonarchCooltime[e] = thecore_pulse(); -} - -bool CHARACTER::IsMCOK(enum MONARCH_INDEX e) const -{ - int iPulse = thecore_pulse(); - - if ((iPulse - GetMC(e)) < GetMCL(e)) - { - if (test_server) - sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e)); - - return false; - } - - if (test_server) - sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e)); - - return true; -} - -DWORD CHARACTER::GetMCL(enum MONARCH_INDEX e) const -{ - return m_dwMonarchCooltimelimit[e]; -} - -DWORD CHARACTER::GetMCLTime(enum MONARCH_INDEX e) const -{ - int iPulse = thecore_pulse(); - - if (test_server) - sys_log(0, " Pulse %d cooltime %d, limit %d", iPulse, GetMC(e), GetMCL(e)); - - return (GetMCL(e)) / passes_per_sec - (iPulse - GetMC(e)) / passes_per_sec; -} - bool CHARACTER::IsSiegeNPC() const { return IsNPC() && (GetRaceNum() == 11000 || GetRaceNum() == 11002 || GetRaceNum() == 11004); @@ -7222,9 +7139,9 @@ void CHARACTER::SendGuildName(CGuild* pGuild) TPacketGCGuildName pack; memset(&pack, 0x00, sizeof(pack)); - pack.header = HEADER_GC_GUILD; - pack.subheader = GUILD_SUBHEADER_GC_GUILD_NAME; - pack.size = sizeof(TPacketGCGuildName); + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::GUILD_NAME; + pack.length = sizeof(TPacketGCGuildName); pack.guildID = pGuild->GetID(); memcpy(pack.guildName, pGuild->GetName(), GUILD_NAME_MAX_LEN); diff --git a/src/game/char.h b/src/game/char.h index 386455b..b7550e4 100644 --- a/src/game/char.h +++ b/src/game/char.h @@ -789,8 +789,6 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider DWORD m_dwPlayStartTime; BYTE m_bAddChrState; bool m_bSkipSave; - std::string m_stMobile; - char m_szMobileAuth[5]; BYTE m_bChatCounter; // End of Basic Points @@ -1249,7 +1247,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider void RewardGold(LPCHARACTER pkAttacker); bool Shoot(BYTE bType); - void FlyTarget(DWORD dwTargetVID, long x, long y, BYTE bHeader); + void FlyTarget(DWORD dwTargetVID, long x, long y, uint16_t wHeader); void ForgetMyAttacker(); void AggregateMonster(); @@ -1857,40 +1855,8 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider // Hack 방지를 위한 체크. bool IsHack(bool bSendMsg = true, bool bCheckShopOwner = true, int limittime = g_nPortalLimitTime); - // MONARCH - BOOL IsMonarch() const; - // END_MONARCH void Say(const std::string & s); - enum MONARCH_COOLTIME - { - MC_HEAL = 10, - MC_WARP = 60, - MC_TRANSFER = 60, - MC_TAX = (60 * 60 * 24 * 7), - MC_SUMMON = (60 * 60), - }; - - enum MONARCH_INDEX - { - MI_HEAL = 0, - MI_WARP, - MI_TRANSFER, - MI_TAX, - MI_SUMMON, - MI_MAX - }; - - DWORD m_dwMonarchCooltime[MI_MAX]; - DWORD m_dwMonarchCooltimelimit[MI_MAX]; - - void InitMC(); - DWORD GetMC(enum MONARCH_INDEX e) const; - void SetMC(enum MONARCH_INDEX e); - bool IsMCOK(enum MONARCH_INDEX e) const; - DWORD GetMCL(enum MONARCH_INDEX e) const; - DWORD GetMCLTime(enum MONARCH_INDEX e) const; - public: bool ItemProcess_Polymorph(LPITEM item); diff --git a/src/game/char_affect.cpp b/src/game/char_affect.cpp index d5029f3..0cd5c77 100644 --- a/src/game/char_affect.cpp +++ b/src/game/char_affect.cpp @@ -1,11 +1,11 @@ - + #include "stdafx.h" #include "config.h" #include "char.h" #include "char_manager.h" #include "affect.h" -#include "packet.h" +#include "packet_structs.h" #include "buffer_manager.h" #include "desc_client.h" #include "battle.h" @@ -24,7 +24,8 @@ void SendAffectRemovePacket(LPDESC d, DWORD pid, DWORD type, BYTE point) { TPacketGCAffectRemove ptoc; - ptoc.bHeader = HEADER_GC_AFFECT_REMOVE; + ptoc.header = GC::AFFECT_REMOVE; + ptoc.length = sizeof(ptoc); ptoc.dwType = type; ptoc.bApplyOn = point; d->Packet(&ptoc, sizeof(TPacketGCAffectRemove)); @@ -33,13 +34,14 @@ void SendAffectRemovePacket(LPDESC d, DWORD pid, DWORD type, BYTE point) ptod.dwPID = pid; ptod.dwType = type; ptod.bApplyOn = point; - db_clientdesc->DBPacket(HEADER_GD_REMOVE_AFFECT, 0, &ptod, sizeof(ptod)); + db_clientdesc->DBPacket(GD::REMOVE_AFFECT, 0, &ptod, sizeof(ptod)); } void SendAffectAddPacket(LPDESC d, CAffect * pkAff) { TPacketGCAffectAdd ptoc; - ptoc.bHeader = HEADER_GC_AFFECT_ADD; + ptoc.header = GC::AFFECT_ADD; + ptoc.length = sizeof(ptoc); ptoc.elem.dwType = pkAff->dwType; ptoc.elem.bApplyOn = pkAff->bApplyOn; ptoc.elem.lApplyValue = pkAff->lApplyValue; @@ -364,7 +366,7 @@ void CHARACTER::SaveAffect() p.elem.dwFlag = pkAff->dwFlag; p.elem.lDuration = pkAff->lDuration; p.elem.lSPCost = pkAff->lSPCost; - db_clientdesc->DBPacket(HEADER_GD_ADD_AFFECT, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::ADD_AFFECT, 0, &p, sizeof(p)); } } @@ -620,7 +622,7 @@ bool CHARACTER::AddAffect(DWORD dwType, BYTE bApplyOn, long lApplyValue, DWORD d p.elem.dwFlag = pkAff->dwFlag; p.elem.lDuration = pkAff->lDuration; p.elem.lSPCost = pkAff->lSPCost; - db_clientdesc->DBPacket(HEADER_GD_ADD_AFFECT, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::ADD_AFFECT, 0, &p, sizeof(p)); } return true; diff --git a/src/game/char_battle.cpp b/src/game/char_battle.cpp index d76674b..08f3fd1 100644 --- a/src/game/char_battle.cpp +++ b/src/game/char_battle.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "config.h" #include "desc.h" @@ -22,13 +22,12 @@ #include "marriage.h" #include "arena.h" #include "regen.h" -#include "monarch.h" #include "exchange.h" #include "shop_manager.h" #include "castle.h" #include "ani.h" #include "BattleArena.h" -#include "packet.h" +#include "packet_structs.h" #include "party.h" #include "affect.h" #include "guild.h" @@ -91,7 +90,8 @@ void CHARACTER::CreateFly(BYTE bType, LPCHARACTER pkVictim) { TPacketGCCreateFly packFly; - packFly.bHeader = HEADER_GC_CREATE_FLY; + packFly.header = GC::CREATE_FLY; + packFly.length = sizeof(packFly); packFly.bType = bType; packFly.dwStartVID = GetVID(); packFly.dwEndVID = pkVictim->GetVID(); @@ -232,12 +232,12 @@ bool CHARACTER::Attack(LPCHARACTER pkVictim, BYTE bType) break; case BATTLE_TYPE_RANGE: - FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING); + FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), CG::FLY_TARGETING); iRet = Shoot(0) ? BATTLE_DAMAGE : BATTLE_NONE; break; case BATTLE_TYPE_MAGIC: - FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING); + FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), CG::FLY_TARGETING); iRet = Shoot(1) ? BATTLE_DAMAGE : BATTLE_NONE; break; @@ -422,7 +422,8 @@ void CHARACTER::Stun() event_cancel(&m_pkRecoveryEvent); // 회복 이벤트를 죽인다. TPacketGCStun pack; - pack.header = HEADER_GC_STUN; + pack.header = GC::STUN; + pack.length = sizeof(pack); pack.vid = m_vid; PacketAround(&pack, sizeof(pack)); @@ -1491,7 +1492,8 @@ void CHARACTER::Dead(LPCHARACTER pkKiller, bool bImmediateDead) // END_OF_BOSS_KILL_LOG TPacketGCDead pack; - pack.header = HEADER_GC_DEAD; + pack.header = GC::DEAD; + pack.length = sizeof(pack); pack.vid = m_vid; PacketAround(&pack, sizeof(pack)); @@ -1613,7 +1615,8 @@ void CHARACTER::SendDamagePacket(LPCHARACTER pAttacker, int Damage, BYTE DamageF TPacketGCDamageInfo damageInfo; memset(&damageInfo, 0, sizeof(TPacketGCDamageInfo)); - damageInfo.header = HEADER_GC_DAMAGE_INFO; + damageInfo.header = GC::DAMAGE_INFO; + damageInfo.length = sizeof(damageInfo); damageInfo.dwVID = (DWORD)GetVID(); damageInfo.flag = DamageFlag; damageInfo.damage = Damage; @@ -1785,7 +1788,8 @@ bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // retu memset(&damageInfo, 0, sizeof(TPacketGCDamageInfo)); - damageInfo.header = HEADER_GC_DAMAGE_INFO; + damageInfo.header = GC::DAMAGE_INFO; + damageInfo.length = sizeof(damageInfo); damageInfo.dwVID = (DWORD)GetVID(); damageInfo.flag = DAMAGE_DODGE; damageInfo.damage = 0; @@ -2245,20 +2249,6 @@ bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // retu return true; } - // - // 군주의 금강권 & 사자후 - // - if (pAttacker->IsPC() && CMonarch::instance().IsPowerUp(pAttacker->GetEmpire())) - { - // 10% 피해 증가 - dam += dam / 10; - } - - if (IsPC() && CMonarch::instance().IsDefenceUp(GetEmpire())) - { - // 10% 피해 감소 - dam -= dam / 10; - } } //puAttr.Pop(); @@ -3235,7 +3225,7 @@ class CFuncShoot bool CHARACTER::Shoot(BYTE bType) { - sys_log(1, "Shoot %s type %u flyTargets.size %zu", GetName(), bType, m_vec_dwFlyTargets.size()); + sys_log(1, "Shoot %s type %u flyTargets.length %zu", GetName(), bType, m_vec_dwFlyTargets.size()); if (!CanMove()) { @@ -3256,13 +3246,14 @@ bool CHARACTER::Shoot(BYTE bType) return f.m_bSucceed; } -void CHARACTER::FlyTarget(DWORD dwTargetVID, long x, long y, BYTE bHeader) +void CHARACTER::FlyTarget(DWORD dwTargetVID, long x, long y, uint16_t wHeader) { LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID); TPacketGCFlyTargeting pack; - //pack.bHeader = HEADER_GC_FLY_TARGETING; - pack.bHeader = (bHeader == HEADER_CG_FLY_TARGETING) ? HEADER_GC_FLY_TARGETING : HEADER_GC_ADD_FLY_TARGETING; + //pack.header = GC::FLY_TARGETING; + pack.header = (wHeader == CG::FLY_TARGETING) ? GC::FLY_TARGETING : GC::ADD_FLY_TARGETING; + pack.length = sizeof(pack); pack.dwShooterVID = GetVID(); if (pkVictim) @@ -3271,7 +3262,7 @@ void CHARACTER::FlyTarget(DWORD dwTargetVID, long x, long y, BYTE bHeader) pack.x = pkVictim->GetX(); pack.y = pkVictim->GetY(); - if (bHeader == HEADER_CG_FLY_TARGETING) + if (wHeader == CG::FLY_TARGETING) m_dwFlyTargetID = dwTargetVID; else m_vec_dwFlyTargets.push_back(dwTargetVID); diff --git a/src/game/char_dragonsoul.cpp b/src/game/char_dragonsoul.cpp index 7136381..f3e712d 100644 --- a/src/game/char_dragonsoul.cpp +++ b/src/game/char_dragonsoul.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "char.h" #include "item.h" #include "desc.h" @@ -119,8 +119,9 @@ bool CHARACTER::DragonSoul_RefineWindow_Open(LPENTITY pEntity) } TPacketGCDragonSoulRefine PDS; - PDS.header = HEADER_GC_DRAGON_SOUL_REFINE; - PDS.bSubType = DS_SUB_HEADER_OPEN; + PDS.header = GC::DRAGON_SOUL_REFINE; + PDS.length = sizeof(PDS); + PDS.bSubType = DragonSoulSub::OPEN; LPDESC d = GetDesc(); if (NULL == d) diff --git a/src/game/char_horse.cpp b/src/game/char_horse.cpp index 76107e8..64a82e9 100644 --- a/src/game/char_horse.cpp +++ b/src/game/char_horse.cpp @@ -1,8 +1,8 @@ -#include "stdafx.h" +#include "stdafx.h" #include "config.h" #include "char.h" #include "char_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "guild.h" #include "vector.h" #include "questmanager.h" @@ -237,7 +237,8 @@ void CHARACTER::HorseSummon(bool bSummon, bool bFromFar, DWORD dwVnum, const cha if ((GetHorseHealth() <= 0)) { TPacketGCDead pack; - pack.header = HEADER_GC_DEAD; + pack.header = GC::DEAD; + pack.length = sizeof(pack); pack.vid = m_chHorse->GetVID(); PacketAround(&pack, sizeof(pack)); } diff --git a/src/game/char_item.cpp b/src/game/char_item.cpp index bd657dc..36b04ec 100644 --- a/src/game/char_item.cpp +++ b/src/game/char_item.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include @@ -10,7 +10,7 @@ #include "desc.h" #include "desc_client.h" #include "desc_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "affect.h" #include "skill.h" #include "start_position.h" @@ -28,7 +28,6 @@ #include "war_map.h" #include "xmas_event.h" #include "marriage.h" -#include "monarch.h" #include "polymorph.h" #include "blend_item.h" #include "castle.h" @@ -265,7 +264,7 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem) { WORD wCell = Cell.cell; BYTE window_type = Cell.window_type; - if ((unsigned long)((CItem*)pItem) == 0xff || (unsigned long)((CItem*)pItem) == 0xffffffff) + if (reinterpret_cast(pItem) == 0xff || reinterpret_cast(pItem) == 0xffffffff) { sys_err("!!! FATAL ERROR !!! item == 0xff (char: %s cell: %u)", GetName(), wCell); core_dump(); @@ -401,7 +400,8 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem) if (pItem) { TPacketGCItemSet pack; - pack.header = HEADER_GC_ITEM_SET; + pack.header = GC::ITEM_SET; + pack.length = sizeof(pack); pack.pos = Cell; pack.count = pItem->GetCount(); @@ -418,7 +418,8 @@ void CHARACTER::SetItem(TItemPos Cell, LPITEM pItem) else { TPacketGCItemDel pack; - pack.header = HEADER_GC_ITEM_DEL; + pack.header = GC::ITEM_DEL; + pack.length = sizeof(pack); pack.pos = Cell; GetDesc()->Packet(&pack, sizeof(TPacketGCItemDel)); } @@ -1284,7 +1285,8 @@ bool CHARACTER::RefineInformation(BYTE bCell, BYTE bType, int iAdditionalCell) TPacketGCRefineInformation p; - p.header = HEADER_GC_REFINE_INFORMATION; + p.header = GC::REFINE_INFORMATION; + p.length = sizeof(p); p.pos = bCell; p.src_vnum = item->GetVnum(); p.result_vnum = item->GetRefinedVnum(); @@ -1612,7 +1614,7 @@ void CHARACTER::UseSilkBotary(void) { if (m_bNoOpenedShop) { DWORD dwPlayerID = GetPlayerID(); - db_clientdesc->DBPacket(HEADER_GD_MYSHOP_PRICELIST_REQ, GetDesc()->GetHandle(), &dwPlayerID, sizeof(DWORD)); + db_clientdesc->DBPacket(GD::MYSHOP_PRICELIST_REQ, GetDesc()->GetHandle(), &dwPlayerID, sizeof(DWORD)); m_bNoOpenedShop = false; } else { __OpenPrivateShop(); @@ -2809,8 +2811,8 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) ++len; // \0 문자까지 보내기 TPacketGCChat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(TPacketGCChat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(TPacketGCChat) + len; pack_chat.type = CHAT_TYPE_COMMAND; pack_chat.id = 0; pack_chat.bEmpire = GetDesc()->GetEmpire(); @@ -2855,8 +2857,8 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) ++len; // \0 문자까지 보내기 TPacketGCChat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(TPacketGCChat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(TPacketGCChat) + len; pack_chat.type = CHAT_TYPE_COMMAND; pack_chat.id = 0; pack_chat.bEmpire = GetDesc()->GetEmpire(); @@ -3761,22 +3763,7 @@ bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell) } break; - //군주의 증표 case 70021: - { - int HealPrice = quest::CQuestManager::instance().GetEventFlag("MonarchHealGold"); - if (HealPrice == 0) - HealPrice = 2000000; - - if (CMonarch::instance().HealMyEmpire(this, HealPrice)) - { - char szNotice[256]; - snprintf(szNotice, sizeof(szNotice), LC_TEXT("군주의 축복으로 이지역 %s 유저는 HP,SP가 모두 채워집니다."), EMPIRE_NAME(GetEmpire())); - SendNoticeMap(szNotice, GetMapIndex(), false); - - ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주의 축복을 사용하였습니다.")); - } - } break; case 27995: @@ -7384,7 +7371,7 @@ void CHARACTER::AutoRecoveryItemProcess(const EAffectTypes type) { LPITEM pItem = FindItemByID(pAffect->dwFlag); - if (NULL != pItem && true == pItem->GetSocket(0)) + if (NULL != pItem && pItem->GetSocket(0) != 0) { if (false == CArenaManager::instance().IsArenaMap(GetMapIndex())) { diff --git a/src/game/char_manager.cpp b/src/game/char_manager.cpp index 0c4e4ba..514b9cd 100644 --- a/src/game/char_manager.cpp +++ b/src/game/char_manager.cpp @@ -1,4 +1,5 @@ -#include "stdafx.h" +#include "stdafx.h" +#include #include "constants.h" #include "utils.h" #include "desc.h" @@ -336,7 +337,7 @@ LPCHARACTER CHARACTER_MANAGER::SpawnMobRandomPosition(DWORD dwVnum, long lMapInd char buf[512+1]; long local_x = x - pkSectreeMap->m_setting.iBaseX; long local_y = y - pkSectreeMap->m_setting.iBaseY; - snprintf(buf, sizeof(buf), "spawn %s[%d] random position at %ld %ld %ld %ld (time: %ld)", ch->GetName(), dwVnum, x, y, local_x, local_y, get_global_time()); + snprintf(buf, sizeof(buf), "spawn %s[%d] random position at %ld %ld %ld %ld (time: %lld)", ch->GetName(), dwVnum, x, y, local_x, local_y, static_cast(get_global_time())); if (test_server) SendNotice(buf); @@ -1110,12 +1111,12 @@ void CHARACTER_MANAGER::SendScriptToMap(long lMapIndex, const std::string & s) struct packet_script p; - p.header = HEADER_GC_SCRIPT; + p.header = GC::SCRIPT; p.skin = 1; p.src_size = s.size(); quest::FSendPacket f; - p.size = p.src_size + sizeof(struct packet_script); + p.length = p.src_size + sizeof(struct packet_script); f.buf.write(&p, sizeof(struct packet_script)); f.buf.write(&s[0], s.size()); diff --git a/src/game/char_quickslot.cpp b/src/game/char_quickslot.cpp index d0269a3..12d13d8 100644 --- a/src/game/char_quickslot.cpp +++ b/src/game/char_quickslot.cpp @@ -1,9 +1,9 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "char.h" #include "desc.h" #include "desc_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "item.h" ///////////////////////////////////////////////////////////////////////////// @@ -87,7 +87,8 @@ bool CHARACTER::SetQuickslot(BYTE pos, TQuickslot & rSlot) if (GetDesc()) { - pack_quickslot_add.header = HEADER_GC_QUICKSLOT_ADD; + pack_quickslot_add.header = GC::QUICKSLOT_ADD; + pack_quickslot_add.length = sizeof(pack_quickslot_add); pack_quickslot_add.pos = pos; pack_quickslot_add.slot = m_quickslot[pos]; @@ -106,7 +107,8 @@ bool CHARACTER::DelQuickslot(BYTE pos) memset(&m_quickslot[pos], 0, sizeof(TQuickslot)); - pack_quickslot_del.header = HEADER_GC_QUICKSLOT_DEL; + pack_quickslot_del.header = GC::QUICKSLOT_DEL; + pack_quickslot_del.length = sizeof(pack_quickslot_del); pack_quickslot_del.pos = pos; GetDesc()->Packet(&pack_quickslot_del, sizeof(pack_quickslot_del)); @@ -127,7 +129,8 @@ bool CHARACTER::SwapQuickslot(BYTE a, BYTE b) m_quickslot[a] = m_quickslot[b]; m_quickslot[b] = quickslot; - pack_quickslot_swap.header = HEADER_GC_QUICKSLOT_SWAP; + pack_quickslot_swap.header = GC::QUICKSLOT_SWAP; + pack_quickslot_swap.length = sizeof(pack_quickslot_swap); pack_quickslot_swap.pos = a; pack_quickslot_swap.pos_to = b; diff --git a/src/game/char_skill.cpp b/src/game/char_skill.cpp index 1700829..93e7ce5 100644 --- a/src/game/char_skill.cpp +++ b/src/game/char_skill.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "utils.h" @@ -9,7 +9,7 @@ #include "battle.h" #include "desc.h" #include "desc_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "affect.h" #include "item.h" #include "sectree_manager.h" @@ -144,7 +144,8 @@ void CHARACTER::SetSkillGroup(BYTE bSkillGroup) m_points.skill_group = bSkillGroup; TPacketGCChangeSkillGroup p; - p.header = HEADER_GC_SKILL_GROUP; + p.header = GC::CHANGE_SKILL_GROUP; + p.length = sizeof(p); p.skill_group = m_points.skill_group; GetDesc()->Packet(&p, sizeof(TPacketGCChangeSkillGroup)); @@ -164,7 +165,8 @@ void CHARACTER::SkillLevelPacket() TPacketGCSkillLevel pack; - pack.bHeader = HEADER_GC_SKILL_LEVEL; + pack.header = GC::SKILL_LEVEL_NEW; // Use NEW header for TPlayerSkill array format + pack.length = sizeof(pack); thecore_memcpy(&pack.skills, m_pSkillLevels, sizeof(TPlayerSkill) * SKILL_MAX_NUM); GetDesc()->Packet(&pack, sizeof(TPacketGCSkillLevel)); } @@ -1188,7 +1190,7 @@ struct FuncSplashDamage m_pkSk->SetPointVar("chain", m_pkChr->GetChainLightningIndex()); m_pkChr->IncChainLightningIndex(); - bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung() > 0; // 이건 왜 여기서 하지?? + bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung(); // 이건 왜 여기서 하지?? m_pkSk->SetPointVar("ek", m_pkChr->GetAffectedEunhyung()*1./100); //m_pkChr->ClearAffectedEunhyung(); diff --git a/src/game/char_state.cpp b/src/game/char_state.cpp index 9bb16ba..9a73762 100644 --- a/src/game/char_state.cpp +++ b/src/game/char_state.cpp @@ -1,11 +1,11 @@ -#include "stdafx.h" +#include "stdafx.h" #include "config.h" #include "utils.h" #include "vector.h" #include "char.h" #include "battle.h" #include "char_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "motion.h" #include "party.h" #include "affect.h" @@ -567,7 +567,8 @@ void CHARACTER::__StateIdle_NPC() { // 다른 서버 입니다. TPacketGGXmasWarpSanta p; - p.bHeader = HEADER_GG_XMAS_WARP_SANTA; + p.header = GG::XMAS_WARP_SANTA; + p.length = sizeof(TPacketGGXmasWarpSanta); p.bChannel = g_bChannel; p.lMapIndex = lNextMapIndex; P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGXmasWarpSanta)); diff --git a/src/game/cmd.cpp b/src/game/cmd.cpp index 0de2583..2521091 100644 --- a/src/game/cmd.cpp +++ b/src/game/cmd.cpp @@ -111,8 +111,6 @@ ACMD(do_cancel_guild_war); ACMD(do_guild_state); ACMD(do_pkmode); -ACMD(do_mobile); -ACMD(do_mobile_auth); ACMD(do_messenger_auth); ACMD(do_getqf); @@ -184,21 +182,6 @@ ACMD(do_oxevent_get_attender); ACMD(do_effect); ACMD(do_threeway_war_info ); ACMD(do_threeway_war_myinfo ); -// -//군주 전용기능 -ACMD(do_monarch_warpto); -ACMD(do_monarch_transfer); -ACMD(do_monarch_info); -ACMD(do_elect); -ACMD(do_monarch_tax); -ACMD(do_monarch_mob); -ACMD(do_monarch_notice); - -//군주 관리 기능 -ACMD(do_rmcandidacy); -ACMD(do_setmonarch); -ACMD(do_rmmonarch); - ACMD(do_hair); //gift notify quest command ACMD(do_gift); @@ -210,8 +193,6 @@ ACMD(do_siege); ACMD(do_temp); ACMD(do_frog); -ACMD(do_check_monarch_money); - ACMD(do_reset_subskill ); ACMD(do_flush); @@ -479,28 +460,16 @@ struct command_info cmd_info[] = { "threeway_info", do_threeway_war_info, 0, POS_DEAD, GM_LOW_WIZARD}, { "threeway_myinfo", do_threeway_war_myinfo, 0, POS_DEAD, GM_LOW_WIZARD}, - { "mto", do_monarch_warpto, 0, POS_DEAD, GM_PLAYER}, - { "mtr", do_monarch_transfer, 0, POS_DEAD, GM_PLAYER}, - { "minfo", do_monarch_info, 0, POS_DEAD, GM_PLAYER}, - { "mtax", do_monarch_tax, 0, POS_DEAD, GM_PLAYER}, - { "mmob", do_monarch_mob, 0, POS_DEAD, GM_PLAYER}, - { "elect", do_elect, 0, POS_DEAD, GM_HIGH_WIZARD}, - { "rmcandidacy", do_rmcandidacy, 0, POS_DEAD, GM_LOW_WIZARD}, - { "setmonarch", do_setmonarch, 0, POS_DEAD, GM_LOW_WIZARD}, - { "rmmonarch", do_rmmonarch, 0, POS_DEAD, GM_LOW_WIZARD}, { "hair", do_hair, 0, POS_DEAD, GM_PLAYER }, { "inventory", do_inventory, 0, POS_DEAD, GM_LOW_WIZARD }, { "cube", do_cube, 0, POS_DEAD, GM_PLAYER }, { "siege", do_siege, 0, POS_DEAD, GM_LOW_WIZARD }, { "temp", do_temp, 0, POS_DEAD, GM_IMPLEMENTOR }, { "frog", do_frog, 0, POS_DEAD, GM_HIGH_WIZARD }, - { "check_mmoney", do_check_monarch_money, 0, POS_DEAD, GM_IMPLEMENTOR }, { "reset_subskill", do_reset_subskill, 0, POS_DEAD, GM_HIGH_WIZARD }, { "flush", do_flush, 0, POS_DEAD, GM_IMPLEMENTOR }, { "gift", do_gift, 0, POS_DEAD, GM_PLAYER }, //gift - { "mnotice", do_monarch_notice, 0, POS_DEAD, GM_PLAYER }, - { "eclipse", do_eclipse, 0, POS_DEAD, GM_HIGH_WIZARD }, { "weeklyevent", do_weeklyevent, 0, POS_DEAD, GM_LOW_WIZARD }, diff --git a/src/game/cmd.h b/src/game/cmd.h index 4d91e57..ac53219 100644 --- a/src/game/cmd.h +++ b/src/game/cmd.h @@ -55,7 +55,6 @@ extern void SendNotice(const char * c_pszBuf); // 이 게임서버에만 공지 extern void SendLog(const char * c_pszBuf); // 운영자에게만 공지 extern void BroadcastNotice(const char * c_pszBuf); // 전 서버에 공지 extern void SendNoticeMap(const char* c_pszBuf, int nMapIndex, bool bBigFont); // 지정 맵에만 공지 -extern void SendMonarchNotice(BYTE bEmpire, const char * c_pszBuf); // 같은 제국에게 공지 // LUA_ADD_BGM_INFO void CHARACTER_SetBGMVolumeEnable(); diff --git a/src/game/cmd_emotion.cpp b/src/game/cmd_emotion.cpp index c2aa103..6165b6a 100644 --- a/src/game/cmd_emotion.cpp +++ b/src/game/cmd_emotion.cpp @@ -1,9 +1,9 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "char.h" #include "char_manager.h" #include "motion.h" -#include "packet.h" +#include "packet_structs.h" #include "buffer_manager.h" #include "unique_item.h" #include "wedding.h" @@ -249,8 +249,8 @@ ACMD(do_emotion) ++len; // \0 문자 포함 TPacketGCChat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(TPacketGCChat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(TPacketGCChat) + len; pack_chat.type = CHAT_TYPE_COMMAND; pack_chat.id = 0; TEMP_BUFFER buf; diff --git a/src/game/cmd_general.cpp b/src/game/cmd_general.cpp index 816f81a..dceaeb7 100644 --- a/src/game/cmd_general.cpp +++ b/src/game/cmd_general.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "utils.h" @@ -8,7 +8,7 @@ #include "char.h" #include "char_manager.h" #include "motion.h" -#include "packet.h" +#include "packet_structs.h" #include "affect.h" #include "pvp.h" #include "start_position.h" @@ -20,7 +20,6 @@ #include "war_map.h" #include "questmanager.h" #include "item_manager.h" -#include "monarch.h" #include "mob_manager.h" #include "item.h" #include "arena.h" @@ -244,7 +243,8 @@ ACMD(do_shutdown) sys_err("Accept shutdown command from %s.", ch->GetName()); } TPacketGGShutdown p; - p.bHeader = HEADER_GG_SHUTDOWN; + p.header = GG::SHUTDOWN; + p.length = sizeof(TPacketGGShutdown); P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShutdown)); Shutdown(10); @@ -281,7 +281,7 @@ EVENTFUNC(timed_event) TPacketNeedLoginLogInfo acc_info; acc_info.dwPlayerID = ch->GetDesc()->GetAccountTable().id; - db_clientdesc->DBPacket( HEADER_GD_VALID_LOGOUT, 0, &acc_info, sizeof(acc_info) ); + db_clientdesc->DBPacket( GD::VALID_LOGOUT, 0, &acc_info, sizeof(acc_info) ); LogManager::instance().DetailLoginLog( false, ch ); } @@ -923,7 +923,7 @@ ACMD(do_safebox_change_password) strlcpy(p.szOldPassword, arg1, sizeof(p.szOldPassword)); strlcpy(p.szNewPassword, arg2, sizeof(p.szNewPassword)); - db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_CHANGE_PASSWORD, ch->GetDesc()->GetHandle(), &p, sizeof(p)); + db_clientdesc->DBPacket(GD::SAFEBOX_CHANGE_PASSWORD, ch->GetDesc()->GetHandle(), &p, sizeof(p)); } ACMD(do_mall_password) @@ -958,7 +958,7 @@ ACMD(do_mall_password) strlcpy(p.szLogin, ch->GetDesc()->GetAccountTable().login, sizeof(p.szLogin)); strlcpy(p.szPassword, arg1, sizeof(p.szPassword)); - db_clientdesc->DBPacket(HEADER_GD_MALL_LOAD, ch->GetDesc()->GetHandle(), &p, sizeof(p)); + db_clientdesc->DBPacket(GD::MALL_LOAD, ch->GetDesc()->GetHandle(), &p, sizeof(p)); } ACMD(do_mall_close) @@ -1459,277 +1459,6 @@ ACMD(do_party_request_deny) ch->DenyToParty(tch); } -ACMD(do_monarch_warpto) -{ - if (true == LC_IsYMIR() || true == LC_IsKorea()) - return; - - if (!CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire())) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다")); - return; - } - - //군주 쿨타임 검사 - if (!ch->IsMCOK(CHARACTER::MI_WARP)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_WARP)); - return; - } - - //군주 몹 소환 비용 - const int WarpPrice = 10000; - - //군주 국고 검사 - if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, WarpPrice); - return; - } - - int x = 0, y = 0; - char arg1[256]; - - one_argument(argument, arg1, sizeof(arg1)); - - if (!*arg1) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("사용법: warpto ")); - return; - } - - LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg1); - - if (!tch) - { - CCI * pkCCI = P2P_MANAGER::instance().Find(arg1); - - if (pkCCI) - { - if (pkCCI->bEmpire != ch->GetEmpire()) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("타제국 유저에게는 이동할수 없습니다")); - return; - } - - if (pkCCI->bChannel != g_bChannel) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("해당 유저는 %d 채널에 있습니다. (현재 채널 %d)"), pkCCI->bChannel, g_bChannel); - return; - } - if (!IsMonarchWarpZone(pkCCI->lMapIndex)) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return; - } - - PIXEL_POSITION pos; - - if (!SECTREE_MANAGER::instance().GetCenterPositionOfMap(pkCCI->lMapIndex, pos)) - ch->ChatPacket(CHAT_TYPE_INFO, "Cannot find map (index %d)", pkCCI->lMapIndex); - else - { - //ch->ChatPacket(CHAT_TYPE_INFO, "You warp to (%d, %d)", pos.x, pos.y); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 에게로 이동합니다"), arg1); - ch->WarpSet(pos.x, pos.y); - - //군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - - //쿨타임 초기화 - ch->SetMC(CHARACTER::MI_WARP); - } - } - else if (NULL == CHARACTER_MANAGER::instance().FindPC(arg1)) - { - ch->ChatPacket(CHAT_TYPE_INFO, "There is no one by that name"); - } - - return; - } - else - { - if (tch->GetEmpire() != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("타제국 유저에게는 이동할수 없습니다")); - return; - } - if (!IsMonarchWarpZone(tch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return; - } - x = tch->GetX(); - y = tch->GetY(); - } - - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 에게로 이동합니다"), arg1); - ch->WarpSet(x, y); - ch->Stop(); - - //군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - - //쿨타임 초기화 - ch->SetMC(CHARACTER::MI_WARP); -} - -ACMD(do_monarch_transfer) -{ - if (true == LC_IsYMIR() || true == LC_IsKorea()) - return; - - char arg1[256]; - one_argument(argument, arg1, sizeof(arg1)); - - if (!*arg1) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("사용법: transfer ")); - return; - } - - if (!CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire())) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다")); - return; - } - - //군주 쿨타임 검사 - if (!ch->IsMCOK(CHARACTER::MI_TRANSFER)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_TRANSFER)); - return; - } - - //군주 워프 비용 - const int WarpPrice = 10000; - - //군주 국고 검사 - if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, WarpPrice); - return; - } - - - LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg1); - - if (!tch) - { - CCI * pkCCI = P2P_MANAGER::instance().Find(arg1); - - if (pkCCI) - { - if (pkCCI->bEmpire != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다.")); - return; - } - if (pkCCI->bChannel != g_bChannel) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님은 %d 채널에 접속 중 입니다. (현재 채널: %d)"), arg1, pkCCI->bChannel, g_bChannel); - return; - } - if (!IsMonarchWarpZone(pkCCI->lMapIndex)) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return; - } - if (!IsMonarchWarpZone(ch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다.")); - return; - } - - TPacketGGTransfer pgg; - - pgg.bHeader = HEADER_GG_TRANSFER; - strlcpy(pgg.szName, arg1, sizeof(pgg.szName)); - pgg.lX = ch->GetX(); - pgg.lY = ch->GetY(); - - P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGTransfer)); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님을 소환하였습니다."), arg1); - - //군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - //쿨타임 초기화 - ch->SetMC(CHARACTER::MI_TRANSFER); - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("입력하신 이름을 가진 사용자가 없습니다.")); - } - - return; - } - - - if (ch == tch) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("자신을 소환할 수 없습니다.")); - return; - } - - if (tch->GetEmpire() != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다.")); - return; - } - if (!IsMonarchWarpZone(tch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return; - } - if (!IsMonarchWarpZone(ch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다.")); - return; - } - - //tch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ()); - tch->WarpSet(ch->GetX(), ch->GetY(), ch->GetMapIndex()); - - //군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - //쿨타임 초기화 - ch->SetMC(CHARACTER::MI_TRANSFER); -} - -ACMD(do_monarch_info) -{ - if (CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire())) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("나의 군주 정보")); - TMonarchInfo * p = CMonarch::instance().GetMonarch(); - for (int n = 1; n < 4; ++n) - { - if (n == ch->GetEmpire()) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[%s군주] : %s 보유금액 %lld "), EMPIRE_NAME(n), p->name[n], p->money[n]); - else - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[%s군주] : %s "), EMPIRE_NAME(n), p->name[n]); - - } - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주 정보")); - TMonarchInfo * p = CMonarch::instance().GetMonarch(); - for (int n = 1; n < 4; ++n) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[%s군주] : %s "), EMPIRE_NAME(n), p->name[n]); - - } - } - -} - -ACMD(do_elect) -{ - db_clientdesc->DBPacketHeader(HEADER_GD_COME_TO_VOTE, ch->GetDesc()->GetHandle(), 0); -} // LUA_ADD_GOTO_INFO struct GotoInfo @@ -1773,174 +1502,6 @@ struct GotoInfo extern void BroadcastNotice(const char * c_pszBuf); -ACMD(do_monarch_tax) -{ - char arg1[256]; - one_argument(argument, arg1, sizeof(arg1)); - - if (!*arg1) - { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: monarch_tax <1-50>"); - return; - } - - // 군주 검사 - if (!ch->IsMonarch()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용할수 있는 기능입니다")); - return; - } - - // 세금설정 - int tax = 0; - str_to_number(tax, arg1); - - if (tax < 1 || tax > 50) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("1-50 사이의 수치를 선택해주세요")); - - quest::CQuestManager::instance().SetEventFlag("trade_tax", tax); - - // 군주에게 메세지 하나 - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("세금이 %d %로 설정되었습니다")); - - // 공지 - char szMsg[1024]; - - snprintf(szMsg, sizeof(szMsg), "군주의 명으로 세금이 %d %% 로 변경되었습니다", tax); - BroadcastNotice(szMsg); - - snprintf(szMsg, sizeof(szMsg), "앞으로는 거래 금액의 %d %% 가 국고로 들어가게됩니다.", tax); - BroadcastNotice(szMsg); - - // 쿨타임 초기화 - ch->SetMC(CHARACTER::MI_TAX); -} - -static const DWORD cs_dwMonarchMobVnums[] = -{ - 191, // 산견신 - 192, // 저신 - 193, // 웅신 - 194, // 호신 - 391, // 미정 - 392, // 은정 - 393, // 세랑 - 394, // 진희 - 491, // 맹환 - 492, // 보우 - 493, // 구패 - 494, // 추흔 - 591, // 비류단대장 - 691, // 웅귀 족장 - 791, // 밀교교주 - 1304, // 누렁범귀 - 1901, // 구미호 - 2091, // 여왕거미 - 2191, // 거대사막거북 - 2206, // 화염왕i - 0, -}; - -ACMD(do_monarch_mob) -{ - char arg1[256]; - LPCHARACTER tch; - - one_argument(argument, arg1, sizeof(arg1)); - - if (!ch->IsMonarch()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용할수 있는 기능입니다")); - return; - } - - if (!*arg1) - { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: mmob "); - return; - } - - BYTE pcEmpire = ch->GetEmpire(); - BYTE mapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(ch->GetMapIndex()); - - if (LC_IsYMIR() == true || LC_IsKorea() == true) - { - if (mapEmpire != pcEmpire && mapEmpire != 0) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("자국 영토에서만 사용할 수 있는 기능입니다")); - return; - } - } - - // 군주 몹 소환 비용 - const int SummonPrice = 5000000; - - // 군주 쿨타임 검사 - if (!ch->IsMCOK(CHARACTER::MI_SUMMON)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_SUMMON)); - return; - } - - // 군주 국고 검사 - if (!CMonarch::instance().IsMoneyOk(SummonPrice, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, SummonPrice); - return; - } - - const CMob * pkMob; - DWORD vnum = 0; - - if (isdigit(*arg1)) - { - str_to_number(vnum, arg1); - - if ((pkMob = CMobManager::instance().Get(vnum)) == NULL) - vnum = 0; - } - else - { - pkMob = CMobManager::Instance().Get(arg1, true); - - if (pkMob) - vnum = pkMob->m_table.dwVnum; - } - - DWORD count; - - // 소환 가능 몹 검사 - for (count = 0; cs_dwMonarchMobVnums[count] != 0; ++count) - if (cs_dwMonarchMobVnums[count] == vnum) - break; - - if (0 == cs_dwMonarchMobVnums[count]) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소환할수 없는 몬스터 입니다. 소환가능한 몬스터는 홈페이지를 참조하세요")); - return; - } - - tch = CHARACTER_MANAGER::instance().SpawnMobRange(vnum, - ch->GetMapIndex(), - ch->GetX() - number(200, 750), - ch->GetY() - number(200, 750), - ch->GetX() + number(200, 750), - ch->GetY() + number(200, 750), - true, - pkMob->m_table.bType == CHAR_TYPE_STONE, - true); - - if (tch) - { - // 군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(SummonPrice, ch->GetEmpire(), ch); - - // 쿨타임 초기화 - ch->SetMC(CHARACTER::MI_SUMMON); - } -} - static const char* FN_point_string(int apply_number) { switch (apply_number) @@ -2356,7 +1917,7 @@ ACMD(do_in_game_mall) case LC_USA: country_code[0] = 'u'; country_code[1] = 's'; country_code[2] = '\0'; break; case LC_CANADA: country_code[0] = 'c'; country_code[1] = 'a'; country_code[2] = '\0'; break; default: - if (test_server == true) + if (test_server) { country_code[0] = 'd'; country_code[1] = 'e'; country_code[2] = '\0'; } diff --git a/src/game/cmd_gm.cpp b/src/game/cmd_gm.cpp index d605bdc..2b77ce7 100644 --- a/src/game/cmd_gm.cpp +++ b/src/game/cmd_gm.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "config.h" #include "desc_client.h" @@ -8,7 +8,7 @@ #include "item_manager.h" #include "sectree_manager.h" #include "mob_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "cmd.h" #include "regen.h" #include "guild.h" @@ -27,7 +27,6 @@ #include "arena.h" #include "start_position.h" #include "party.h" -#include "monarch.h" #include "castle.h" #include "BattleArena.h" #include "xmas_event.h" @@ -119,7 +118,8 @@ ACMD(do_transfer) TPacketGGTransfer pgg; - pgg.bHeader = HEADER_GG_TRANSFER; + pgg.header = GG::TRANSFER; + pgg.length = sizeof(pgg); strlcpy(pgg.szName, arg1, sizeof(pgg.szName)); pgg.lX = ch->GetX(); pgg.lY = ch->GetY(); @@ -1096,40 +1096,12 @@ struct notice_packet_func } }; -struct monarch_notice_packet_func -{ - const char * m_str; - BYTE m_bEmpire; - - monarch_notice_packet_func(BYTE bEmpire, const char * str) : m_str(str), m_bEmpire(bEmpire) - { - } - - void operator () (LPDESC d) - { - if (!d->GetCharacter()) - return; - - if (m_bEmpire == d->GetCharacter()->GetEmpire()) - { - d->GetCharacter()->ChatPacket(CHAT_TYPE_NOTICE, "%s", m_str); - } - } -}; - - void SendNotice(const char * c_pszBuf) { const DESC_MANAGER::DESC_SET & c_ref_set = DESC_MANAGER::instance().GetClientSet(); std::for_each(c_ref_set.begin(), c_ref_set.end(), notice_packet_func(c_pszBuf)); } -void SendMonarchNotice(BYTE bEmpire, const char* c_pszBuf) -{ - const DESC_MANAGER::DESC_SET & c_ref_set = DESC_MANAGER::instance().GetClientSet(); - std::for_each(c_ref_set.begin(), c_ref_set.end(), monarch_notice_packet_func(bEmpire, c_pszBuf)); -} - struct notice_map_packet_func { const char* m_str; @@ -1183,34 +1155,19 @@ void SendLog(const char * c_pszBuf) void BroadcastNotice(const char * c_pszBuf) { TPacketGGNotice p; - p.bHeader = HEADER_GG_NOTICE; + p.header = GG::NOTICE; p.lSize = strlen(c_pszBuf) + 1; + p.length = sizeof(TPacketGGNotice) + p.lSize; TEMP_BUFFER buf; buf.write(&p, sizeof(p)); buf.write(c_pszBuf, p.lSize); - P2P_MANAGER::instance().Send(buf.read_peek(), buf.size()); // HEADER_GG_NOTICE + P2P_MANAGER::instance().Send(buf.read_peek(), buf.size()); // GG::NOTICE SendNotice(c_pszBuf); } -void BroadcastMonarchNotice(BYTE bEmpire, const char * c_pszBuf) -{ - TPacketGGMonarchNotice p; - p.bHeader = HEADER_GG_MONARCH_NOTICE; - p.bEmpire = bEmpire; - p.lSize = strlen(c_pszBuf) + 1; - - TEMP_BUFFER buf; - buf.write(&p, sizeof(p)); - buf.write(c_pszBuf, p.lSize); - - P2P_MANAGER::instance().Send(buf.read_peek(), buf.size()); - - SendMonarchNotice(bEmpire, c_pszBuf); -} - ACMD(do_notice) { BroadcastNotice(argument); @@ -1226,18 +1183,6 @@ ACMD(do_big_notice) ch->ChatPacket(CHAT_TYPE_BIG_NOTICE, "%s", argument); } -ACMD(do_monarch_notice) -{ - if (ch->IsMonarch() == true) - { - BroadcastMonarchNotice(ch->GetEmpire(), argument); - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다")); - } -} - ACMD(do_who) { int iTotal; @@ -2095,7 +2040,7 @@ ACMD(do_reload) case 'p': ch->ChatPacket(CHAT_TYPE_INFO, "Reloading prototype tables,"); - db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, nullptr, 0); + db_clientdesc->DBPacket(GD::RELOAD_PROTO, 0, nullptr, 0); break; case 'q': @@ -2110,7 +2055,7 @@ ACMD(do_reload) //RELOAD_ADMIN case 'a': ch->ChatPacket(CHAT_TYPE_INFO, "Reloading Admin infomation."); - db_clientdesc->DBPacket(HEADER_GD_RELOAD_ADMIN, 0, nullptr, 0); + db_clientdesc->DBPacket(GD::RELOAD_ADMIN, 0, nullptr, 0); sys_log(0, "Reloading admin infomation."); break; //END_RELOAD_ADMIN @@ -2126,7 +2071,7 @@ ACMD(do_reload) LoadStateUserCount(); ch->ChatPacket(CHAT_TYPE_INFO, "Reloading prototype tables,"); - db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, NULL, 0); + db_clientdesc->DBPacket(GD::RELOAD_PROTO, 0, NULL, 0); } } @@ -2711,7 +2656,8 @@ ACMD(do_vote_block_chat) { TPacketGGBlockChat p; - p.bHeader = HEADER_GG_BLOCK_CHAT; + p.header = GG::BLOCK_CHAT; + p.length = sizeof(p); strlcpy(p.szName, name, sizeof(p.szName)); p.lBlockDuration = lBlockDuration; P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGBlockChat)); @@ -2722,7 +2668,7 @@ ACMD(do_vote_block_chat) strlcpy(p.szName, name, sizeof(p.szName)); p.lDuration = lBlockDuration; - db_clientdesc->DBPacket(HEADER_GD_BLOCK_CHAT, ch ? ch->GetDesc()->GetHandle() : 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::BLOCK_CHAT, ch ? ch->GetDesc()->GetHandle() : 0, &p, sizeof(p)); } @@ -2781,7 +2727,8 @@ ACMD(do_block_chat) { TPacketGGBlockChat p; - p.bHeader = HEADER_GG_BLOCK_CHAT; + p.header = GG::BLOCK_CHAT; + p.length = sizeof(p); strlcpy(p.szName, name, sizeof(p.szName)); p.lBlockDuration = lBlockDuration; P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGBlockChat)); @@ -2792,7 +2739,7 @@ ACMD(do_block_chat) strlcpy(p.szName, name, sizeof(p.szName)); p.lDuration = lBlockDuration; - db_clientdesc->DBPacket(HEADER_GD_BLOCK_CHAT, ch ? ch->GetDesc()->GetHandle() : 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::BLOCK_CHAT, ch ? ch->GetDesc()->GetHandle() : 0, &p, sizeof(p)); } if (ch) @@ -3534,7 +3481,7 @@ ACMD(do_break_marriage) str_to_number(pids.pid2, arg2); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("플레이어 %d 와 플레이어 %d를 파혼시킵니다.."), pids.pid1, pids.pid2); - db_clientdesc->DBPacket(HEADER_GD_BREAK_MARRIAGE, 0, &pids, sizeof(pids)); + db_clientdesc->DBPacket(GD::BREAK_MARRIAGE, 0, &pids, sizeof(pids)); } ACMD(do_effect) @@ -3596,85 +3543,6 @@ ACMD(do_threeway_war_myinfo) CThreeWayWar::instance().GetReviveTokenForPlayer(ch->GetPlayerID())); } -ACMD(do_rmcandidacy) -{ - char arg1[256]; - - one_argument(argument, arg1, sizeof(arg1)); - - if (!*arg1) - { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: rmcandidacy "); - return; - } - - LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg1); - - if (!tch) - { - CCI * pkCCI = P2P_MANAGER::instance().Find(arg1); - - if (pkCCI) - { - if (pkCCI->bChannel != g_bChannel) - { - ch->ChatPacket(CHAT_TYPE_INFO, "Target is in %d channel (my channel %d)", pkCCI->bChannel, g_bChannel); - return; - } - } - } - - db_clientdesc->DBPacket(HEADER_GD_RMCANDIDACY, 0, NULL, 32); - db_clientdesc->Packet(arg1, 32); -} - -ACMD(do_setmonarch) -{ - char arg1[256]; - - one_argument(argument, arg1, sizeof(arg1)); - - if (!*arg1) - { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: setmonarch "); - return; - } - - db_clientdesc->DBPacket(HEADER_GD_SETMONARCH, 0, NULL, 32); - db_clientdesc->Packet(arg1, 32); -} - -ACMD(do_rmmonarch) -{ - char arg1[256]; - - one_argument(argument, arg1, sizeof(arg1)); - - if (!*arg1) - { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: rmmonarch "); - return; - } - - db_clientdesc->DBPacket(HEADER_GD_RMMONARCH, 0, NULL, 32); - db_clientdesc->Packet(arg1, 32); -} - -ACMD(do_check_monarch_money) -{ - char arg1[256]; - - one_argument(argument, arg1, sizeof(arg1)); - - if (!*arg1) - return; - - int empire = 0; - str_to_number(empire, arg1); - int NationMoney = CMonarch::instance().GetMoney(empire); - - ch->ChatPacket(CHAT_TYPE_INFO, "국고: %d 원", NationMoney); -} ACMD(do_reset_subskill) { @@ -3709,7 +3577,8 @@ ACMD(do_siege) if (tower_count < 5 || tower_count > 10) tower_count = number(5, 10); TPacketGGSiege packet; - packet.bHeader = HEADER_GG_SIEGE; + packet.header = GG::SIEGE; + packet.length = sizeof(packet); packet.bEmpire = empire; packet.bTowerCount = tower_count; @@ -3733,22 +3602,6 @@ ACMD(do_temp) { if (false == test_server) return; - - char arg1[256], arg2[256]; - two_arguments(argument, arg1, sizeof(arg1), arg2, sizeof(arg2)); - - if (0 == arg1[0] || 0 == arg2[0]) - { - ch->ChatPacket(CHAT_TYPE_INFO, "Usage: empire money"); - return; - } - - int empire = 0; - str_to_number(empire, arg1); - int money = 0; - str_to_number(money, arg2); - - CMonarch::instance().SendtoDBAddMoney(money, empire, ch); } ACMD(do_frog) @@ -3799,7 +3652,7 @@ ACMD(do_flush) DWORD pid = (DWORD) strtoul(arg1, NULL, 10); - db_clientdesc->DBPacketHeader(HEADER_GD_FLUSH_CACHE, 0, sizeof(DWORD)); + db_clientdesc->DBPacketHeader(GD::FLUSH_CACHE, 0, sizeof(DWORD)); db_clientdesc->Packet(&pid, sizeof(DWORD)); } diff --git a/src/game/config.cpp b/src/game/config.cpp index fc2e102..8422297 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -31,11 +31,6 @@ int ping_event_second_cycle = passes_per_sec * 60; bool g_bNoMoreClient = false; bool g_bNoRegen = false; -// TRAFFIC_PROFILER -bool g_bTrafficProfileOn = false; -DWORD g_dwTrafficProfileFlushCycle = 3600; -// END_OF_TRAFFIC_PROFILER - int test_server = 0; bool china_event_server = false; bool guild_mark_server = true; @@ -106,6 +101,14 @@ bool g_bCheckMultiHack = true; int g_iSpamBlockMaxLevel = 10; +int g_iFloodMaxPacketsPerSec = 300; +int g_iFloodMaxConnectionsPerIP = 10; +int g_iFloodMaxGlobalConnections = 8192; + +bool g_bFirewallEnable = false; +int g_iFirewallTcpSynLimit = 500; +int g_iFirewallTcpSynBurst = 1000; + void LoadStateUserCount(); void LoadValidCRCList(); bool LoadClientVersion(); @@ -117,11 +120,11 @@ bool g_BlockCharCreation = false; bool is_string_true(const char * string) { - bool result = 0; + int result = 0; if (isnhdigit(*string)) { str_to_number(result, string); - return result > 0 ? true : false; + return result > 0; } else if (LOWER(*string) == 't') return true; @@ -603,12 +606,6 @@ void config_init(const string& st_localeServiceName) continue; } - TOKEN("traffic_profile") - { - g_bTrafficProfileOn = true; - continue; - } - TOKEN("no_wander") { no_wander = true; @@ -705,6 +702,42 @@ void config_init(const string& st_localeServiceName) { str_to_number(g_iSpamBlockMaxLevel, value_string); } + + TOKEN("flood_max_packets_per_sec") + { + str_to_number(g_iFloodMaxPacketsPerSec, value_string); + g_iFloodMaxPacketsPerSec = MAX(50, g_iFloodMaxPacketsPerSec); + } + + TOKEN("flood_max_connections_per_ip") + { + str_to_number(g_iFloodMaxConnectionsPerIP, value_string); + g_iFloodMaxConnectionsPerIP = MAX(1, g_iFloodMaxConnectionsPerIP); + } + + TOKEN("flood_max_global_connections") + { + str_to_number(g_iFloodMaxGlobalConnections, value_string); + g_iFloodMaxGlobalConnections = MAX(64, g_iFloodMaxGlobalConnections); + } + + TOKEN("firewall_enable") + { + str_to_number(g_bFirewallEnable, value_string); + } + + TOKEN("firewall_tcp_syn_limit") + { + str_to_number(g_iFirewallTcpSynLimit, value_string); + g_iFirewallTcpSynLimit = MAX(10, g_iFirewallTcpSynLimit); + } + + TOKEN("firewall_tcp_syn_burst") + { + str_to_number(g_iFirewallTcpSynBurst, value_string); + g_iFirewallTcpSynBurst = MAX(10, g_iFirewallTcpSynBurst); + } + TOKEN("protect_normal_player") { str_to_number(g_protectNormalPlayer, value_string); @@ -1199,14 +1232,7 @@ bool LoadClientVersion() void CheckClientVersion() { - if (LC_IsEurope()) - { - g_bCheckClientVersion = true; - } - else - { - g_bCheckClientVersion = false; - } + g_bCheckClientVersion = true; const DESC_MANAGER::DESC_SET & set = DESC_MANAGER::instance().GetClientSet(); DESC_MANAGER::DESC_SET::const_iterator it = set.begin(); diff --git a/src/game/config.h b/src/game/config.h index 3d5978c..13d3548 100644 --- a/src/game/config.h +++ b/src/game/config.h @@ -28,8 +28,6 @@ extern bool china_event_server; extern bool g_bNoMoreClient; extern bool g_bNoRegen; -extern bool g_bTrafficProfileOn; ///< true 이면 TrafficProfiler 를 켠다. - extern BYTE g_bChannel; extern bool map_allow_find(int index); @@ -107,5 +105,9 @@ extern int gPlayerMaxLevel; extern bool g_BlockCharCreation; +extern bool g_bFirewallEnable; +extern int g_iFirewallTcpSynLimit; +extern int g_iFirewallTcpSynBurst; + #endif /* __INC_METIN_II_GAME_CONFIG_H__ */ diff --git a/src/game/cube.cpp b/src/game/cube.cpp index 9eb500d..cc340b3 100644 --- a/src/game/cube.cpp +++ b/src/game/cube.cpp @@ -303,7 +303,7 @@ void Cube_open (LPCHARACTER ch) if ( FN_check_valid_npc(npc->GetRaceNum()) == false ) { - if ( test_server == true ) + if (test_server) { sys_log(1, "cube not valid NPC"); } diff --git a/src/game/db.cpp b/src/game/db.cpp index 0e83915..f18c797 100644 --- a/src/game/db.cpp +++ b/src/game/db.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "common/length.h" @@ -177,7 +177,7 @@ void DBManager::SendLoginPing(const char * c_pszLogin) { TPacketGGLoginPing ptog; - ptog.bHeader = HEADER_GG_LOGIN_PING; + ptog.header = GG::LOGIN_PING; ptog.length = sizeof(ptog); strlcpy(ptog.szLogin, c_pszLogin, sizeof(ptog.szLogin)); if (!g_pkAuthMasterDesc) // If I am master, broadcast to others @@ -208,7 +208,7 @@ void DBManager::SendAuthLogin(LPDESC d) thecore_memcpy(ptod.iPremiumTimes, pkLD->GetPremiumPtr(), sizeof(ptod.iPremiumTimes)); - db_clientdesc->DBPacket(HEADER_GD_AUTH_LOGIN, d->GetHandle(), &ptod, sizeof(TPacketGDAuthLogin)); + db_clientdesc->DBPacket(GD::AUTH_LOGIN, d->GetHandle(), &ptod, sizeof(TPacketGDAuthLogin)); sys_log(0, "SendAuthLogin %s key %u", ptod.szLogin, ptod.dwID); SendLoginPing(r.login); @@ -545,7 +545,7 @@ void DBManager::SendMoneyLog(BYTE type, DWORD vnum, int gold) p.type = type; p.vnum = vnum; p.gold = gold; - db_clientdesc->DBPacket(HEADER_GD_MONEY_LOG, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::MONEY_LOG, 0, &p, sizeof(p)); } size_t DBManager::EscapeString(char* dst, size_t dstSize, const char *src, size_t srcSize) diff --git a/src/game/desc.cpp b/src/game/desc.cpp index fabfde5..38017e9 100644 --- a/src/game/desc.cpp +++ b/src/game/desc.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include #include "config.h" #include "utils.h" #include "desc.h" @@ -6,15 +7,13 @@ #include "desc_manager.h" #include "char.h" #include "protocol.h" -#include "packet.h" +#include "packet_structs.h" #include "messenger_manager.h" #include "sectree_manager.h" #include "p2p.h" #include "buffer_manager.h" -#include "sequence.h" #include "guild.h" #include "guild_manager.h" -#include "TrafficProfiler.h" #include "locale_service.h" #include "log.h" @@ -29,6 +28,7 @@ DESC::DESC() DESC::~DESC() { + Destroy(); } void DESC::Initialize() @@ -44,25 +44,20 @@ void DESC::Initialize() m_wPort = 0; m_LastTryToConnectTime = 0; - m_lpInputBuffer = NULL; - m_iMinInputBufferLen = 0; + m_inputBuffer.Clear(); - m_dwHandshake = 0; - m_dwHandshakeSentTime = 0; - m_iHandshakeRetry = 0; m_dwClientTime = 0; - m_bHandshaking = false; m_handshake_time = get_dword_time(); - m_lpBufferedOutputBuffer = NULL; - m_lpOutputBuffer = NULL; + m_bufferedOutputBuffer.Clear(); + m_hasBufferedOutput = false; + m_outputBuffer.Clear(); m_pkPingEvent = NULL; m_lpCharacter = NULL; memset( &m_accountTable, 0, sizeof(m_accountTable) ); memset( &m_SockAddr, 0, sizeof(m_SockAddr) ); - memset( &m_UDPSockAddr, 0, sizeof(m_UDPSockAddr) ); m_pLogFile = NULL; @@ -73,10 +68,6 @@ void DESC::Initialize() m_bPong = true; m_bChannelStatusRequested = false; - m_SequenceGenerator.seed(SEQUENCE_SEED); - // Pre-generate the first expected sequence to match what client will send - m_bNextExpectedSequence = m_SequenceGenerator(UINT8_MAX + 1); - m_pkLoginKey = NULL; m_dwLoginKey = 0; @@ -90,6 +81,10 @@ void DESC::Initialize() m_offtime = 0; m_pkDisconnectEvent = NULL; + + m_iFloodCheckPulse = 0; + m_dwFloodPacketCount = 0; + m_bIPCountTracked = false; } void DESC::Destroy() @@ -117,8 +112,10 @@ void DESC::Destroy() m_lpCharacter = NULL; } - SAFE_BUFFER_DELETE(m_lpOutputBuffer); - SAFE_BUFFER_DELETE(m_lpInputBuffer); + m_outputBuffer.Clear(); + m_inputBuffer.Clear(); + m_bufferedOutputBuffer.Clear(); + m_hasBufferedOutput = false; event_cancel(&m_pkPingEvent); event_cancel(&m_pkDisconnectEvent); @@ -132,7 +129,7 @@ void DESC::Destroy() strlcpy(pack.login, m_accountTable.login, sizeof(pack.login)); strlcpy(pack.passwd, m_accountTable.passwd, sizeof(pack.passwd)); - db_clientdesc->DBPacket(HEADER_GD_LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket)); + db_clientdesc->DBPacket(GD::LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket)); } } @@ -175,13 +172,13 @@ EVENTFUNC(ping_event) else { TPacketGCPing p; - p.header = HEADER_GC_PING; + p.header = GC::PING; + p.length = sizeof(p); + p.server_time = get_dword_time(); desc->Packet(&p, sizeof(struct packet_ping)); desc->SetPong(false); } - desc->SendHandshake(get_dword_time(), 0); - return (ping_event_second_cycle); } @@ -195,7 +192,7 @@ void DESC::SetPong(bool b) m_bPong = b; } -bool DESC::Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSockAddr, DWORD _handle, DWORD _handshake) +bool DESC::Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSockAddr, DWORD _handle) { m_lpFdw = _fdw; m_sock = _fd; @@ -204,20 +201,14 @@ bool DESC::Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSoc m_wPort = c_rSockAddr.sin_port; m_dwHandle = _handle; - //if (LC_IsEurope() == true || LC_IsNewCIBN()) - // m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2); - //else - //NOTE: 이걸 나라별로 다르게 잡아야할 이유가 있나? - m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 3); // Default: 2 - - m_iMinInputBufferLen = MAX_INPUT_LEN >> 1; - m_lpInputBuffer = buffer_new(MAX_INPUT_LEN); + m_outputBuffer.Reserve(65536 * 3); + m_inputBuffer.Reserve(MAX_INPUT_LEN); m_SockAddr = c_rSockAddr; fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_READ, false); - // Ping Event + // Ping Event desc_event_info* info = AllocEventInfo(); info->desc = this; @@ -225,29 +216,26 @@ bool DESC::Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSoc m_pkPingEvent = event_create(ping_event, info, ping_event_second_cycle); - // Set Phase to handshake + // Set Phase to handshake and begin secure key exchange SetPhase(PHASE_HANDSHAKE); - StartHandshake(_handshake); + m_handshake_time = get_dword_time(); + SendKeyChallenge(); - sys_log(0, "SYSTEM: new connection from [%s] fd: %d handshake %u output input_len %d, ptr %p", - m_stHost.c_str(), m_sock, m_dwHandshake, buffer_size(m_lpInputBuffer), this); + sys_log(0, "[CONN] Setup complete for %s, KeyChallenge sent", GetHostName()); - Log("SYSTEM: new connection from [%s] fd: %d handshake %u ptr %p", m_stHost.c_str(), m_sock, m_dwHandshake, this); + sys_log(0, "SYSTEM: new connection from [%s] fd: %d input_capacity %zu, ptr %p", + m_stHost.c_str(), m_sock, m_inputBuffer.Capacity(), this); + + Log("SYSTEM: new connection from [%s] fd: %d ptr %p", m_stHost.c_str(), m_sock, this); return true; } int DESC::ProcessInput() { - ssize_t bytes_read; + m_inputBuffer.EnsureWritable(4096); - if (!m_lpInputBuffer) - { - sys_err("DESC::ProcessInput : nil input buffer"); - return -1; - } - - buffer_adjust_size(m_lpInputBuffer, m_iMinInputBufferLen); - bytes_read = socket_read(m_sock, (char *) buffer_write_peek(m_lpInputBuffer), buffer_has_space(m_lpInputBuffer)); + size_t writable = m_inputBuffer.WritableBytes(); + ssize_t bytes_read = socket_read(m_sock, (char*)m_inputBuffer.WritePtr(), writable); if (bytes_read < 0) return -1; @@ -256,10 +244,10 @@ int DESC::ProcessInput() // Decrypt only the newly received bytes before committing to the buffer if (m_secureCipher.IsActivated()) { - m_secureCipher.DecryptInPlace((void*)buffer_write_peek(m_lpInputBuffer), bytes_read); + m_secureCipher.DecryptInPlace(m_inputBuffer.WritePtr(), bytes_read); } - buffer_write_proceed(m_lpInputBuffer, bytes_read); + m_inputBuffer.CommitWrite(bytes_read); if (!m_pInputProcessor) sys_err("no input processor"); @@ -268,13 +256,13 @@ int DESC::ProcessInput() int iBytesProceed = 0; // false가 리턴 되면 다른 phase로 바뀐 것이므로 다시 프로세스로 돌입한다! - while (!m_pInputProcessor->Process(this, buffer_read_peek(m_lpInputBuffer), buffer_size(m_lpInputBuffer), iBytesProceed)) + while (!m_pInputProcessor->Process(this, m_inputBuffer.ReadPtr(), static_cast(m_inputBuffer.ReadableBytes()), iBytesProceed)) { - buffer_read_proceed(m_lpInputBuffer, iBytesProceed); + m_inputBuffer.Discard(iBytesProceed); iBytesProceed = 0; } - buffer_read_proceed(m_lpInputBuffer, iBytesProceed); + m_inputBuffer.Discard(iBytesProceed); } return (bytes_read); @@ -282,7 +270,7 @@ int DESC::ProcessInput() int DESC::ProcessOutput() { - if (buffer_size(m_lpOutputBuffer) <= 0) + if (m_outputBuffer.ReadableBytes() <= 0) return 0; int buffer_left = fdwatch_get_buffer_size(m_lpFdw, m_sock); @@ -290,25 +278,23 @@ int DESC::ProcessOutput() if (buffer_left <= 0) return 0; - int bytes_to_write = MIN(buffer_left, buffer_size(m_lpOutputBuffer)); + int bytes_to_write = MIN(buffer_left, static_cast(m_outputBuffer.ReadableBytes())); if (bytes_to_write == 0) return 0; - int result = socket_write(m_sock, (const char *) buffer_read_peek(m_lpOutputBuffer), bytes_to_write); + int result = socket_write(m_sock, (const char *) m_outputBuffer.ReadPtr(), bytes_to_write); if (result == 0) { - //sys_log(0, "%d bytes written to %s first %u", bytes_to_write, GetHostName(), *(BYTE *) buffer_read_peek(m_lpOutputBuffer)); - //Log("%d bytes written", bytes_to_write); max_bytes_written = MAX(bytes_to_write, max_bytes_written); total_bytes_written += bytes_to_write; current_bytes_written += bytes_to_write; - buffer_read_proceed(m_lpOutputBuffer, bytes_to_write); + m_outputBuffer.Discard(bytes_to_write); - if (buffer_size(m_lpOutputBuffer) != 0) + if (m_outputBuffer.ReadableBytes() != 0) fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true); } @@ -320,102 +306,82 @@ void DESC::BufferedPacket(const void * c_pvData, int iSize) if (m_iPhase == PHASE_CLOSE) return; - if (!m_lpBufferedOutputBuffer) - m_lpBufferedOutputBuffer = buffer_new(MAX(1024, iSize)); + if (!m_hasBufferedOutput) + { + m_bufferedOutputBuffer.Clear(); + m_hasBufferedOutput = true; + } -#ifdef _DEBUG - const std::string stName = GetCharacter() ? GetCharacter()->GetName() : GetHostName(); - const auto kHeader = *(static_cast(c_pvData)); - sys_log(0, "[B] SENT HEADER : %u(0x%X) to %s (size %d) ", kHeader, kHeader, stName.c_str(), iSize); -#endif + if (iSize >= (int)sizeof(uint16_t) * 2) + { + const uint16_t wHeader = *static_cast(c_pvData); + LogSentPacket(wHeader, static_cast(iSize)); + } - buffer_write(m_lpBufferedOutputBuffer, c_pvData, iSize); + m_bufferedOutputBuffer.Write(c_pvData, iSize); } void DESC::Packet(const void * c_pvData, int iSize) { assert(iSize > 0); - if (m_iPhase == PHASE_CLOSE) // 끊는 상태면 보내지 않는다. + if (m_iPhase == PHASE_CLOSE) return; - if (!m_lpOutputBuffer) + // Log the packet for sequence tracking (only for real packet sends, not buffered flushes) + if (!m_hasBufferedOutput && iSize >= (int)sizeof(uint16_t) * 2) { - sys_err("DESC::Packet: Trying to send packet but output buffer is NULL! (DESC: %p)", this); - SetPhase(PHASE_CLOSE); - return; + const uint16_t wHeader = *static_cast(c_pvData); + LogSentPacket(wHeader, static_cast(iSize)); } -#ifdef _DEBUG - const std::string stName = GetCharacter() ? GetCharacter()->GetName() : GetHostName(); - const auto kHeader = *(static_cast(c_pvData)); - sys_log(0, "[N] SENT HEADER : %u(0x%X) to %s (size %d) ", kHeader, kHeader, stName.c_str(), iSize); -#endif - if (m_stRelayName.length() != 0) { // Relay 패킷은 암호화하지 않는다. TPacketGGRelay p; - p.bHeader = HEADER_GG_RELAY; + p.header = GG::RELAY; strlcpy(p.szName, m_stRelayName.c_str(), sizeof(p.szName)); p.lSize = iSize; + p.length = sizeof(p) + iSize; - if (!packet_encode(m_lpOutputBuffer, &p, sizeof(p))) - { - m_iPhase = PHASE_CLOSE; - return; - } - + m_outputBuffer.Write(&p, sizeof(p)); m_stRelayName.clear(); - - if (!packet_encode(m_lpOutputBuffer, c_pvData, iSize)) - { - m_iPhase = PHASE_CLOSE; - return; - } + m_outputBuffer.Write(c_pvData, iSize); } else { - if (m_lpBufferedOutputBuffer) + if (m_hasBufferedOutput) { - buffer_write(m_lpBufferedOutputBuffer, c_pvData, iSize); + m_bufferedOutputBuffer.Write(c_pvData, iSize); - c_pvData = buffer_read_peek(m_lpBufferedOutputBuffer); - iSize = buffer_size(m_lpBufferedOutputBuffer); + c_pvData = m_bufferedOutputBuffer.ReadPtr(); + iSize = static_cast(m_bufferedOutputBuffer.ReadableBytes()); } - // TRAFFIC_PROFILE - if (g_bTrafficProfileOn) - TrafficProfiler::instance().Report(TrafficProfiler::IODIR_OUTPUT, *(BYTE *) c_pvData, iSize); - // END_OF_TRAFFIC_PROFILER + m_outputBuffer.EnsureWritable(iSize); + std::memcpy(m_outputBuffer.WritePtr(), c_pvData, iSize); - int write_point_pos = m_lpOutputBuffer->write_point_pos; - if (packet_encode(m_lpOutputBuffer, c_pvData, iSize)) - { - void* buf = m_lpOutputBuffer->mem_data + write_point_pos; - if (m_secureCipher.IsActivated()) { - m_secureCipher.EncryptInPlace(buf, iSize); - } - } - else - { - m_iPhase = PHASE_CLOSE; + if (m_secureCipher.IsActivated()) { + m_secureCipher.EncryptInPlace(m_outputBuffer.WritePtr(), iSize); } - SAFE_BUFFER_DELETE(m_lpBufferedOutputBuffer); + m_outputBuffer.CommitWrite(iSize); + + if (m_hasBufferedOutput) + { + m_bufferedOutputBuffer.Clear(); + m_hasBufferedOutput = false; + } } - //sys_log(0, "%d bytes written (first byte %d)", iSize, *(BYTE *) c_pvData); if (m_iPhase != PHASE_CLOSE) fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true); } void DESC::LargePacket(const void * c_pvData, int iSize) { - buffer_adjust_size(m_lpOutputBuffer, iSize); - sys_log(0, "LargePacket Size %d", iSize, buffer_size(m_lpOutputBuffer)); - + m_outputBuffer.EnsureWritable(iSize); Packet(c_pvData, iSize); } @@ -424,15 +390,14 @@ void DESC::SetPhase(int _phase) m_iPhase = _phase; TPacketGCPhase pack; - pack.header = HEADER_GC_PHASE; + pack.header = GC::PHASE; + pack.length = sizeof(pack); pack.phase = _phase; Packet(&pack, sizeof(TPacketGCPhase)); switch (m_iPhase) { case PHASE_CLOSE: - // 메신저가 캐릭터단위가 되면서 삭제 - //MessengerManager::instance().Logout(GetAccountTable().login); m_pInputProcessor = &m_inputClose; break; @@ -441,8 +406,6 @@ void DESC::SetPhase(int _phase) break; case PHASE_SELECT: - // 메신저가 캐릭터단위가 되면서 삭제 - //MessengerManager::instance().Logout(GetAccountTable().login); // 의도적으로 break 안검 case PHASE_LOGIN: case PHASE_LOADING: m_pInputProcessor = &m_inputLogin; @@ -467,19 +430,6 @@ void DESC::BindAccountTable(TAccountTable * pAccountTable) DESC_MANAGER::instance().ConnectAccount(m_accountTable.login, this); } -void DESC::UDPGrant(const struct sockaddr_in & c_rSockAddr) -{ - m_UDPSockAddr = c_rSockAddr; - - TPacketGCBindUDP pack; - - pack.header = HEADER_GC_BINDUDP; - pack.addr = m_UDPSockAddr.sin_addr.s_addr; - pack.port = m_UDPSockAddr.sin_port; - - Packet(&pack, sizeof(TPacketGCBindUDP)); -} - void DESC::Log(const char * format, ...) { if (!m_pLogFile) @@ -507,89 +457,6 @@ void DESC::Log(const char * format, ...) fflush(m_pLogFile); } -void DESC::StartHandshake(DWORD _handshake) -{ - // Handshake - m_dwHandshake = _handshake; - - SendHandshake(get_dword_time(), 0); - - m_iHandshakeRetry = 0; -} - -void DESC::SendHandshake(DWORD dwCurTime, int32_t lNewDelta) -{ - TPacketGCHandshake pack; - - pack.bHeader = HEADER_GC_HANDSHAKE; - pack.dwHandshake = m_dwHandshake; - pack.dwTime = dwCurTime; - pack.lDelta = lNewDelta; - - Packet(&pack, sizeof(TPacketGCHandshake)); - - m_dwHandshakeSentTime = dwCurTime; - m_bHandshaking = true; -} - -bool DESC::HandshakeProcess(DWORD dwTime, int32_t lDelta, bool bInfiniteRetry) -{ - DWORD dwCurTime = get_dword_time(); - - if (lDelta < 0) - { - sys_err("Desc::HandshakeProcess : value error (lDelta %" PRId32 ", ip %s)", lDelta, m_stHost.c_str()); - return false; - } - - int bias = (int) (dwCurTime - (dwTime + lDelta)); - - if (bias >= 0 && bias <= 50) - { - if (bInfiniteRetry) - { - BYTE bHeader = HEADER_GC_TIME_SYNC; - Packet(&bHeader, sizeof(BYTE)); - } - - if (GetCharacter()) - sys_log(0, "Handshake: client_time %u server_time %u name: %s", m_dwClientTime, dwCurTime, GetCharacter()->GetName()); - else - sys_log(0, "Handshake: client_time %u server_time %u", m_dwClientTime, dwCurTime, lDelta); - - m_dwClientTime = dwCurTime; - m_bHandshaking = false; - return true; - } - - int32_t lNewDelta = (int32_t) (dwCurTime - dwTime) / 2; - - if (lNewDelta < 0) - { - sys_log(0, "Handshake: lower than zero %d", lNewDelta); - lNewDelta = (dwCurTime - m_dwHandshakeSentTime) / 2; - } - - sys_log(1, "Handshake: ServerTime %u dwTime %u lDelta %" PRId32 " SentTime %u lNewDelta %" PRId32, dwCurTime, dwTime, lDelta, m_dwHandshakeSentTime, lNewDelta); - - if (!bInfiniteRetry) - if (++m_iHandshakeRetry > HANDSHAKE_RETRY_LIMIT) - { - sys_err("handshake retry limit reached! (limit %d character %s)", - HANDSHAKE_RETRY_LIMIT, GetCharacter() ? GetCharacter()->GetName() : "!NO CHARACTER!"); - SetPhase(PHASE_CLOSE); - return false; - } - - SendHandshake(dwCurTime, lNewDelta); - return false; -} - -bool DESC::IsHandshaking() -{ - return m_bHandshaking; -} - bool DESC::IsExpiredHandshake() const { if (m_handshake_time == 0) @@ -598,6 +465,34 @@ bool DESC::IsExpiredHandshake() const return (m_handshake_time + (5 * 1000)) < get_dword_time(); } +bool DESC::CheckPacketFlood() +{ + extern int g_iFloodMaxPacketsPerSec; + + // Use thecore_pulse() (cached per game-loop iteration) instead of + // get_dword_time() (gettimeofday syscall) to avoid per-packet syscall overhead. + int pulse = thecore_pulse(); + int pps = static_cast(thecore_pulse_per_second()); + + if (pulse - m_iFloodCheckPulse >= pps) + { + m_iFloodCheckPulse = pulse; + m_dwFloodPacketCount = 1; + return false; + } + + ++m_dwFloodPacketCount; + + if (m_dwFloodPacketCount > (uint32_t)g_iFloodMaxPacketsPerSec) + { + sys_log(0, "FLOOD: %s exceeded %d packets/sec (count: %u), disconnecting", + GetHostName(), g_iFloodMaxPacketsPerSec, m_dwFloodPacketCount); + return true; + } + + return false; +} + DWORD DESC::GetClientTime() { return m_dwClientTime; @@ -619,13 +514,17 @@ void DESC::SendKeyChallenge() // Build and send challenge packet TPacketGCKeyChallenge packet; - packet.bHeader = HEADER_GC_KEY_CHALLENGE; + packet.header = GC::KEY_CHALLENGE; + packet.length = sizeof(packet); m_secureCipher.GetPublicKey(packet.server_pk); memcpy(packet.challenge, m_challenge, SecureCipher::CHALLENGE_SIZE); + packet.server_time = get_dword_time(); Packet(&packet, sizeof(packet)); - sys_log(0, "SECURE KEY_CHALLENGE sent to %s", GetHostName()); + sys_log(0, "[HANDSHAKE] KeyChallenge sent to %s (server_time: %u, pk: %02x%02x%02x%02x)", + GetHostName(), packet.server_time, + packet.server_pk[0], packet.server_pk[1], packet.server_pk[2], packet.server_pk[3]); } bool DESC::HandleKeyResponse(const uint8_t* client_pk, const uint8_t* challenge_response) @@ -644,7 +543,8 @@ bool DESC::HandleKeyResponse(const uint8_t* client_pk, const uint8_t* challenge_ return false; } - sys_log(0, "SECURE KEY_RESPONSE verified for %s", GetHostName()); + sys_log(0, "[HANDSHAKE] KeyResponse verified for %s (tx_nonce: %llu, rx_nonce: %llu)", + GetHostName(), (unsigned long long)m_secureCipher.GetTxNonce(), (unsigned long long)m_secureCipher.GetRxNonce()); return true; } @@ -657,7 +557,8 @@ void DESC::SendKeyComplete() // Build and send complete packet TPacketGCKeyComplete packet; - packet.bHeader = HEADER_GC_KEY_COMPLETE; + packet.header = GC::KEY_COMPLETE; + packet.length = sizeof(packet); // Encrypt the session token if (!m_secureCipher.EncryptToken(session_token, sizeof(session_token), @@ -676,7 +577,8 @@ void DESC::SendKeyComplete() // Activate encryption m_secureCipher.SetActivated(true); - sys_log(0, "SECURE CIPHER ACTIVATED for %s", GetHostName()); + sys_log(0, "[HANDSHAKE] Cipher ACTIVATED for %s (tx_nonce: %llu, rx_nonce: %llu)", + GetHostName(), (unsigned long long)m_secureCipher.GetTxNonce(), (unsigned long long)m_secureCipher.GetRxNonce()); } void DESC::SetRelay(const char * c_pszName) @@ -695,7 +597,7 @@ void DESC::FlushOutput() return; } - if (buffer_size(m_lpOutputBuffer) <= 0) + if (m_outputBuffer.ReadableBytes() <= 0) return; struct timeval sleep_tv, now_tv, start_tv; @@ -704,9 +606,9 @@ void DESC::FlushOutput() gettimeofday(&start_tv, NULL); socket_block(m_sock); - sys_log(0, "FLUSH START %d", buffer_size(m_lpOutputBuffer)); + sys_log(0, "FLUSH START %zu", m_outputBuffer.ReadableBytes()); - while (buffer_size(m_lpOutputBuffer) > 0) + while (m_outputBuffer.ReadableBytes() > 0) { gettimeofday(&now_tv, NULL); @@ -763,7 +665,7 @@ void DESC::FlushOutput() break; } - if (buffer_size(m_lpOutputBuffer) == 0) + if (m_outputBuffer.ReadableBytes() == 0) sys_log(0, "FLUSH SUCCESS"); else sys_log(0, "FLUSH FAIL"); @@ -827,28 +729,21 @@ bool DESC::IsAdminMode() return m_bAdminMode; } -BYTE DESC::GetSequence() -{ - // Return the next expected sequence and then generate the one after that - BYTE bCurrentExpected = m_bNextExpectedSequence; - m_bNextExpectedSequence = m_SequenceGenerator(UINT8_MAX + 1); - return bCurrentExpected; -} - void DESC::SendLoginSuccessPacket() { TAccountTable & rTable = GetAccountTable(); TPacketGCLoginSuccess p; - p.bHeader = HEADER_GC_LOGIN_SUCCESS_NEWSLOT; + p.header = GC::LOGIN_SUCCESS4; + p.length = sizeof(p); p.handle = GetHandle(); p.random_key = DESC_MANAGER::instance().MakeRandomKey(GetHandle()); // FOR MARK thecore_memcpy(p.players, rTable.players, sizeof(rTable.players)); for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i) - { + { #ifdef ENABLE_PROXY_IP if (!g_stProxyIP.empty()) @@ -858,10 +753,10 @@ void DESC::SendLoginSuccessPacket() CGuild* g = CGuildManager::instance().GetLinkedGuild(rTable.players[i].dwID); if (g) - { + { p.guild_id[i] = g->GetID(); strlcpy(p.guild_name[i], g->GetName(), sizeof(p.guild_name[i])); - } + } else { p.guild_id[i] = 0; @@ -872,27 +767,6 @@ void DESC::SendLoginSuccessPacket() Packet(&p, sizeof(TPacketGCLoginSuccess)); } -//void DESC::SendServerStatePacket(int nIndex) -//{ -// TPacketGCStateCheck rp; -// -// int iTotal; -// int * paiEmpireUserCount; -// int iLocal; -// -// DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal); -// -// rp.header = 1; -// rp.key = 0; -// rp.index = nIndex; -// -// if (g_bNoMoreClient) rp.state = 0; -// else rp.state = iTotal > g_iFullUserCount ? 3 : iTotal > g_iBusyUserCount ? 2 : 1; -// -// this->Packet(&rp, sizeof(rp)); -// //printf("STATE_CHECK PACKET PROCESSED.\n"); -//} - void DESC::SetLoginKey(DWORD dwKey) { m_dwLoginKey = dwKey; @@ -943,6 +817,17 @@ BYTE DESC::GetEmpire() return m_accountTable.bEmpire; } +void DESC::RawPacket(const void * c_pvData, int iSize) +{ + if (m_iPhase == PHASE_CLOSE) + return; + + m_outputBuffer.Write(c_pvData, iSize); + + if (m_iPhase != PHASE_CLOSE) + fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, true); +} + void DESC::ChatPacket(BYTE type, const char * format, ...) { char chatbuf[CHAT_MAX_LEN + 1]; @@ -954,8 +839,8 @@ void DESC::ChatPacket(BYTE type, const char * format, ...) struct packet_chat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(struct packet_chat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(struct packet_chat) + len; pack_chat.type = type; pack_chat.id = 0; pack_chat.bEmpire = GetEmpire(); @@ -967,3 +852,51 @@ void DESC::ChatPacket(BYTE type, const char * format, ...) Packet(buf.read_peek(), buf.size()); } +// --- Packet sequence tracking --- + +void DESC::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 DESC::LogSentPacket(uint16_t header, uint16_t length) +{ + auto& e = m_aRecentSentPackets[m_dwSentPacketSeq % PACKET_LOG_SIZE]; + e.seq = m_dwSentPacketSeq; + e.header = header; + e.length = length; + m_dwSentPacketSeq++; +} + +void DESC::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)PACKET_LOG_SIZE); + + sys_err("=== Recent RECV packets (last %u of %u total) fd=%d host=%s ===", + recvCount, m_dwRecvPacketSeq, m_sock, m_stHost.c_str()); + + 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]; + sys_err(" RECV #%u: header=0x%04X len=%u", e.seq, e.header, e.length); + } + + sys_err("=== Recent SENT packets (last %u of %u total) ===", sentCount, m_dwSentPacketSeq); + + for (uint32_t i = 0; i < sentCount; i++) + { + uint32_t idx = (m_dwSentPacketSeq > PACKET_LOG_SIZE) + ? (m_dwSentPacketSeq - PACKET_LOG_SIZE + i) + : i; + const auto& e = m_aRecentSentPackets[idx % PACKET_LOG_SIZE]; + sys_err(" SENT #%u: header=0x%04X len=%u", e.seq, e.header, e.length); + } +} diff --git a/src/game/desc.h b/src/game/desc.h index 15a6a5e..3e54ad1 100644 --- a/src/game/desc.h +++ b/src/game/desc.h @@ -4,15 +4,11 @@ #include "constants.h" #include "input.h" #include "SecureCipher.h" +#include "libthecore/ring_buffer.h" -#include - -#define SEQUENCE_SEED 0 //#define MAX_INPUT_LEN 2048 #define MAX_INPUT_LEN 65536 -#define HANDSHAKE_RETRY_LIMIT 32 - class CInputProcessor; enum EDescType @@ -46,14 +42,6 @@ class CLoginKey }; -// sequence 버그 찾기용 데이타 -struct seq_t -{ - BYTE hdr; - BYTE seq; -}; -typedef std::vector seq_vector_t; -// sequence 버그 찾기용 데이타 class DESC { @@ -62,7 +50,7 @@ class DESC { LPDESC desc; - desc_event_info() + desc_event_info() : desc(0) { } @@ -78,7 +66,7 @@ class DESC void FlushOutput(); - bool Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSockAddr, DWORD _handle, DWORD _handshake); + bool Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSockAddr, DWORD _handle); socket_t GetSocket() const { return m_sock; } const char * GetHostName() { return m_stHost.c_str(); } @@ -99,7 +87,7 @@ class DESC CInputProcessor * GetInputProcessor() { return m_pInputProcessor; } DWORD GetHandle() const { return m_dwHandle; } - LPBUFFER GetOutputBuffer() { return m_lpOutputBuffer; } + size_t GetOutputBufferSize() const { return m_outputBuffer.ReadableBytes(); } void BindAccountTable(TAccountTable * pTable); TAccountTable & GetAccountTable() { return m_accountTable; } @@ -112,18 +100,8 @@ class DESC const struct sockaddr_in & GetAddr() { return m_SockAddr; } - void UDPGrant(const struct sockaddr_in & c_rSockAddr); - const struct sockaddr_in & GetUDPAddr() { return m_UDPSockAddr; } - void Log(const char * format, ...); - // 핸드쉐이크 (시간 동기화) - void StartHandshake(DWORD _dw); - void SendHandshake(DWORD dwCurTime, int32_t lNewDelta); - bool HandshakeProcess(DWORD dwTime, int32_t lDelta, bool bInfiniteRetry=false); - bool IsHandshaking(); - - DWORD GetHandshake() const { return m_dwHandshake; } DWORD GetClientTime(); // Secure key exchange (libsodium/XChaCha20-Poly1305) @@ -148,8 +126,6 @@ class DESC void SetPong(bool b); bool IsPong(); - BYTE GetSequence(); - void SendLoginSuccessPacket(); //void SendServerStatePacket(int nIndex); @@ -170,6 +146,11 @@ class DESC bool IsExpiredHandshake() const; void SetHandshakeTime(uint32_t handshake_time) { m_handshake_time = handshake_time; } + // Flood protection + bool CheckPacketFlood(); + void SetIPCountTracked(bool b) { m_bIPCountTracked = b; } + bool IsIPCountTracked() const { return m_bIPCountTracked; } + protected: void Initialize(); @@ -192,24 +173,19 @@ class DESC WORD m_wPort; time_t m_LastTryToConnectTime; - LPBUFFER m_lpInputBuffer; - int m_iMinInputBufferLen; - - DWORD m_dwHandshake; - DWORD m_dwHandshakeSentTime; - int m_iHandshakeRetry; - DWORD m_dwClientTime; - bool m_bHandshaking; + RingBuffer m_inputBuffer; - LPBUFFER m_lpBufferedOutputBuffer; - LPBUFFER m_lpOutputBuffer; + DWORD m_dwClientTime; + + RingBuffer m_bufferedOutputBuffer; + bool m_hasBufferedOutput; + RingBuffer m_outputBuffer; LPEVENT m_pkPingEvent; LPCHARACTER m_lpCharacter; TAccountTable m_accountTable; struct sockaddr_in m_SockAddr; - struct sockaddr_in m_UDPSockAddr; FILE * m_pLogFile; std::string m_stRelayName; @@ -221,9 +197,6 @@ class DESC bool m_bAdminMode; // Handshake 에서 어드민 명령을 쓸수있나? bool m_bPong; - pcg32 m_SequenceGenerator; - BYTE m_bNextExpectedSequence; // Next expected sequence number from client - CLoginKey * m_pkLoginKey; DWORD m_dwLoginKey; @@ -245,6 +218,11 @@ class DESC // Handshake timeout protection uint32_t m_handshake_time; + // Flood protection + int m_iFloodCheckPulse; + uint32_t m_dwFloodPacketCount; + bool m_bIPCountTracked; + // Secure cipher (libsodium/XChaCha20-Poly1305) SecureCipher m_secureCipher; uint8_t m_challenge[SecureCipher::CHALLENGE_SIZE]; @@ -263,6 +241,29 @@ class DESC void RawPacket(const void * c_pvData, int iSize); void ChatPacket(BYTE type, const char * format, ...); + + // --- Packet sequence tracking (debug aid) --- + 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 LogSentPacket(uint16_t header, uint16_t length); + void DumpRecentPackets() const; + uint32_t GetRecvPacketSeq() const { return m_dwRecvPacketSeq; } + uint32_t GetSentPacketSeq() const { return m_dwSentPacketSeq; } + + private: + PacketLogEntry m_aRecentRecvPackets[PACKET_LOG_SIZE] = {}; + PacketLogEntry m_aRecentSentPackets[PACKET_LOG_SIZE] = {}; + uint32_t m_dwRecvPacketSeq = 0; + uint32_t m_dwSentPacketSeq = 0; }; #endif diff --git a/src/game/desc_client.cpp b/src/game/desc_client.cpp index 4a1c0df..b77c60d 100644 --- a/src/game/desc_client.cpp +++ b/src/game/desc_client.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "config.h" #include "utils.h" #include "desc_client.h" @@ -106,7 +106,6 @@ bool CLIENT_DESC::Connect(int iPhaseWhenSucceed) void CLIENT_DESC::Setup(LPFDWATCH _fdw, const char * _host, WORD _port) { - // 1MB input/output buffer m_lpFdw = _fdw; m_stHost = _host; m_wPort = _port; @@ -140,7 +139,7 @@ void CLIENT_DESC::SetPhase(int iPhase) p.dwItemIDRange[0] = 0; p.dwItemIDRange[1] = 0; memcpy(p.szIP, g_szPublicIP, 16); - DBPacket(HEADER_GD_BOOT, 0, &p, sizeof(p)); + DBPacket(GD::BOOT, 0, &p, sizeof(p)); } } @@ -207,19 +206,16 @@ void CLIENT_DESC::SetPhase(int iPhase) buf.write(&p, sizeof(p)); } - DBPacket(HEADER_GD_SETUP, 0, buf.read_peek(), buf.size()); + DBPacket(GD::SETUP, 0, buf.read_peek(), buf.size()); m_pInputProcessor = &m_inputDB; } break; case PHASE_P2P: sys_log(1, "PHASE_P2P"); - - if (m_lpInputBuffer) - buffer_reset(m_lpInputBuffer); - if (m_lpOutputBuffer) - buffer_reset(m_lpOutputBuffer); + m_inputBuffer.Clear(); + m_outputBuffer.Clear(); m_pInputProcessor = &m_inputP2P; break; @@ -233,25 +229,25 @@ void CLIENT_DESC::SetPhase(int iPhase) m_iPhase = iPhase; } -void CLIENT_DESC::DBPacketHeader(BYTE bHeader, DWORD dwHandle, DWORD dwSize) +void CLIENT_DESC::DBPacketHeader(uint16_t wHeader, DWORD dwHandle, DWORD dwSize) { - buffer_write(m_lpOutputBuffer, encode_byte(bHeader), sizeof(BYTE)); - buffer_write(m_lpOutputBuffer, encode_4bytes(dwHandle), sizeof(DWORD)); - buffer_write(m_lpOutputBuffer, encode_4bytes(dwSize), sizeof(DWORD)); + m_outputBuffer.Write(&wHeader, sizeof(wHeader)); + m_outputBuffer.Write(&dwHandle, sizeof(dwHandle)); + m_outputBuffer.Write(&dwSize, sizeof(dwSize)); } -void CLIENT_DESC::DBPacket(BYTE bHeader, DWORD dwHandle, const void * c_pvData, DWORD dwSize) +void CLIENT_DESC::DBPacket(uint16_t wHeader, DWORD dwHandle, const void * c_pvData, DWORD dwSize) { if (m_sock == INVALID_SOCKET) { sys_log(0, "CLIENT_DESC [%s] trying DBPacket() while not connected", GetKnownClientDescName(this)); return; } - sys_log(1, "DB_PACKET: header %d handle %d size %d buffer_size %d", bHeader, dwHandle, dwSize, buffer_size(m_lpOutputBuffer)); - DBPacketHeader(bHeader, dwHandle, dwSize); + sys_log(1, "DB_PACKET: header %u handle %u size %u buffer_size %zu", wHeader, dwHandle, dwSize, m_outputBuffer.ReadableBytes()); + DBPacketHeader(wHeader, dwHandle, dwSize); if (c_pvData) - buffer_write(m_lpOutputBuffer, c_pvData, dwSize); + m_outputBuffer.Write(c_pvData, dwSize); } void CLIENT_DESC::Packet(const void * c_pvData, int iSize) @@ -261,7 +257,7 @@ void CLIENT_DESC::Packet(const void * c_pvData, int iSize) GetKnownClientDescName(this)); return; } - buffer_write(m_lpOutputBuffer, c_pvData, iSize); + m_outputBuffer.Write(c_pvData, iSize); } bool CLIENT_DESC::IsRetryWhenClosed() @@ -282,7 +278,7 @@ void CLIENT_DESC::UpdateChannelStatus(DWORD t, bool fForce) CHANNELSTATUS_UPDATE_PERIOD = 5*60*1000, // 5분마다 }; if (fForce || m_tLastChannelStatusUpdateTime+CHANNELSTATUS_UPDATE_PERIOD < t) { - int iTotal; + int iTotal; int * paiEmpireUserCount; int iLocal; DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal); @@ -293,7 +289,7 @@ void CLIENT_DESC::UpdateChannelStatus(DWORD t, bool fForce) if (g_bNoMoreClient) channelStatus.bStatus = 0; else channelStatus.bStatus = iTotal > g_iFullUserCount ? 3 : iTotal > g_iBusyUserCount ? 2 : 1; - DBPacket(HEADER_GD_UPDATE_CHANNELSTATUS, 0, &channelStatus, sizeof(channelStatus)); + DBPacket(GD::UPDATE_CHANNELSTATUS, 0, &channelStatus, sizeof(channelStatus)); m_tLastChannelStatusUpdateTime = t; } } @@ -318,7 +314,6 @@ void CLIENT_DESC::Reset() void CLIENT_DESC::InitializeBuffers() { - m_lpOutputBuffer = buffer_new(1024 * 1024); - m_lpInputBuffer = buffer_new(1024 * 1024); - m_iMinInputBufferLen = 1024 * 1024; + m_outputBuffer.Reserve(1024 * 1024); + m_inputBuffer.Reserve(1024 * 1024); } diff --git a/src/game/desc_client.h b/src/game/desc_client.h index 89e733c..7c6860c 100644 --- a/src/game/desc_client.h +++ b/src/game/desc_client.h @@ -18,8 +18,8 @@ class CLIENT_DESC : public DESC void SetRetryWhenClosed(bool); - void DBPacketHeader(BYTE bHeader, DWORD dwHandle, DWORD dwSize); - void DBPacket(BYTE bHeader, DWORD dwHandle, const void * c_pvData, DWORD dwSize); + void DBPacketHeader(uint16_t wHeader, DWORD dwHandle, DWORD dwSize); + void DBPacket(uint16_t wHeader, DWORD dwHandle, const void * c_pvData, DWORD dwSize); void Packet(const void * c_pvData, int iSize); bool IsRetryWhenClosed(); diff --git a/src/game/desc_manager.cpp b/src/game/desc_manager.cpp index 2bb0459..2a699a8 100644 --- a/src/game/desc_manager.cpp +++ b/src/game/desc_manager.cpp @@ -76,31 +76,6 @@ void DESC_MANAGER::Destroy() Initialize(); } -DWORD DESC_MANAGER::CreateHandshake() -{ - char crc_buf[8]; - crc_t crc; - DESC_HANDSHAKE_MAP::iterator it; - -RETRY: - do - { - DWORD val = number(0, (1024 * 1024)); - - *(DWORD *) (crc_buf ) = val; - *((DWORD *) crc_buf + 1) = get_global_time(); - - crc = GetCRC32(crc_buf, 8); - it = m_map_handshake.find(crc); - } - while (it != m_map_handshake.end()); - - if (crc == 0) - goto RETRY; - - return (crc); -} - LPDESC DESC_MANAGER::AcceptDesc(LPFDWATCH fdw, socket_t s) { socket_t desc; @@ -113,21 +88,45 @@ LPDESC DESC_MANAGER::AcceptDesc(LPFDWATCH fdw, socket_t s) strlcpy(host, inet_ntoa(peer.sin_addr), sizeof(host)); - newd = M2_NEW DESC; - crc_t handshake = CreateHandshake(); + // Global connection limit + extern int g_iFloodMaxGlobalConnections; + if (m_iSocketsConnected >= g_iFloodMaxGlobalConnections) + { + sys_log(0, "FLOOD: rejecting connection from %s (global limit %d/%d reached)", + host, m_iSocketsConnected, g_iFloodMaxGlobalConnections); + socket_close(desc); + return NULL; + } - if (!newd->Setup(fdw, desc, peer, ++m_iHandleCount, handshake)) + // Per-IP connection limit + extern int g_iFloodMaxConnectionsPerIP; + auto itIP = m_map_ipConnCount.find(host); + if (itIP != m_map_ipConnCount.end() && itIP->second >= g_iFloodMaxConnectionsPerIP) + { + sys_log(0, "FLOOD: rejecting connection from %s (%d/%d connections)", + host, itIP->second, g_iFloodMaxConnectionsPerIP); + socket_close(desc); + return NULL; + } + + newd = M2_NEW DESC; + + if (!newd->Setup(fdw, desc, peer, ++m_iHandleCount)) { socket_close(desc); M2_DELETE(newd); return NULL; } - m_map_handshake.insert(DESC_HANDSHAKE_MAP::value_type(handshake, newd)); m_map_handle.insert(DESC_HANDLE_MAP::value_type(newd->GetHandle(), newd)); m_set_pkDesc.insert(newd); ++m_iSocketsConnected; + + // Track per-IP count + ++m_map_ipConnCount[host]; + newd->SetIPCountTracked(true); + return (newd); } @@ -177,14 +176,22 @@ void DESC_MANAGER::DestroyDesc(LPDESC d, bool bEraseFromSet) if (bEraseFromSet) m_set_pkDesc.erase(d); - if (d->GetHandshake()) - m_map_handshake.erase(d->GetHandshake()); - if (d->GetHandle() != 0) m_map_handle.erase(d->GetHandle()); else m_set_pkClientDesc.erase((LPCLIENT_DESC) d); + // Decrement per-IP connection count (before Destroy invalidates state) + if (d->IsIPCountTracked()) + { + auto it = m_map_ipConnCount.find(d->GetHostName()); + if (it != m_map_ipConnCount.end()) + { + if (--it->second <= 0) + m_map_ipConnCount.erase(it); + } + } + // Explicit call to the virtual function Destroy() d->Destroy(); @@ -327,16 +334,6 @@ bool DESC_MANAGER::IsP2PDescExist(const char * szHost, WORD wPort) return false; } -LPDESC DESC_MANAGER::FindByHandshake(DWORD dwHandshake) -{ - DESC_HANDSHAKE_MAP::iterator it = m_map_handshake.find(dwHandshake); - - if (it == m_map_handshake.end()) - return NULL; - - return (it->second); -} - class FuncWho { public: diff --git a/src/game/desc_manager.h b/src/game/desc_manager.h index 3de49ac..335092c 100644 --- a/src/game/desc_manager.h +++ b/src/game/desc_manager.h @@ -14,7 +14,6 @@ class DESC_MANAGER : public singleton typedef std::unordered_set DESC_SET; typedef std::unordered_set CLIENT_DESC_SET; typedef std::map DESC_HANDLE_MAP; - typedef std::map DESC_HANDSHAKE_MAP; typedef std::map DESC_ACCOUNTID_MAP; typedef std::unordered_map DESC_LOGINNAME_MAP; typedef std::map DESC_HANDLE_RANDOM_KEY_MAP; @@ -30,13 +29,10 @@ class DESC_MANAGER : public singleton LPDESC AcceptP2PDesc(LPFDWATCH fdw, socket_t s); void DestroyDesc(LPDESC d, bool erase_from_set = true); - DWORD CreateHandshake(); - LPCLIENT_DESC CreateConnectionDesc(LPFDWATCH fdw, const char * host, WORD port, int iPhaseWhenSucceed, bool bRetryWhenClosed); void TryConnect(); LPDESC FindByHandle(DWORD handle); - LPDESC FindByHandshake(DWORD dwHandshake); LPDESC FindByCharacterName(const char* name); LPDESC FindByLoginName(const std::string& login); @@ -72,8 +68,9 @@ class DESC_MANAGER : public singleton CLIENT_DESC_SET m_set_pkClientDesc; DESC_SET m_set_pkDesc; + std::unordered_map m_map_ipConnCount; + DESC_HANDLE_MAP m_map_handle; - DESC_HANDSHAKE_MAP m_map_handshake; //DESC_ACCOUNTID_MAP m_AccountIDMap; DESC_LOGINNAME_MAP m_map_loginName; std::map m_map_pkLoginKey; diff --git a/src/game/desc_p2p.cpp b/src/game/desc_p2p.cpp index a9a9271..7dbe072 100644 --- a/src/game/desc_p2p.cpp +++ b/src/game/desc_p2p.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "desc_p2p.h" #include "protocol.h" #include "p2p.h" @@ -34,16 +34,11 @@ bool DESC_P2P::Setup(LPFDWATCH fdw, socket_t fd, const char * host, WORD wPort) m_wPort = wPort; m_sock = fd; - if (!(m_lpOutputBuffer = buffer_new(1024 * 1024))) - return false; - - if (!(m_lpInputBuffer = buffer_new(1024 * 1024))) - return false; + m_outputBuffer.Reserve(1024 * 1024); + m_inputBuffer.Reserve(1024 * 1024); fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_READ, false); - m_iMinInputBufferLen = 1024 * 1024; - SetPhase(PHASE_P2P); sys_log(0, "SYSTEM: new p2p connection from [%s] fd: %d", host, m_sock); @@ -59,11 +54,8 @@ void DESC_P2P::SetPhase(int iPhase) case PHASE_P2P: sys_log(1, "PHASE_P2P"); - if (m_lpInputBuffer) - buffer_reset(m_lpInputBuffer); - - if (m_lpOutputBuffer) - buffer_reset(m_lpOutputBuffer); + m_inputBuffer.Clear(); + m_outputBuffer.Clear(); m_pInputProcessor = &s_inputP2P; break; @@ -79,4 +71,3 @@ void DESC_P2P::SetPhase(int iPhase) m_iPhase = iPhase; } - diff --git a/src/game/dungeon.cpp b/src/game/dungeon.cpp index 8da3642..1c671b8 100644 --- a/src/game/dungeon.cpp +++ b/src/game/dungeon.cpp @@ -1,10 +1,10 @@ -#include "stdafx.h" +#include "stdafx.h" #include "dungeon.h" #include "char.h" #include "char_manager.h" #include "party.h" #include "affect.h" -#include "packet.h" +#include "packet_structs.h" #include "desc.h" #include "config.h" #include "regen.h" @@ -88,11 +88,11 @@ struct FSendDestPosition { FSendDestPosition(long x, long y) { - p1.bHeader = HEADER_GC_DUNGEON; - p1.subheader = DUNGEON_SUBHEADER_GC_DESTINATION_POSITION; + p1.header = GC::DUNGEON; + p1.subheader = DungeonSub::GC::DESTINATION_POSITION; p2.x = x; p2.y = y; - p1.size = sizeof(p1)+sizeof(p2); + p1.length = sizeof(p1)+sizeof(p2); } void operator()(LPCHARACTER ch) diff --git a/src/game/exchange.cpp b/src/game/exchange.cpp index 1e89ae9..8a0bb92 100644 --- a/src/game/exchange.cpp +++ b/src/game/exchange.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "libgame/grid.h" #include "utils.h" #include "desc.h" @@ -6,7 +6,7 @@ #include "char.h" #include "item.h" #include "item_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "log.h" #include "db.h" #include "locale_service.h" @@ -24,14 +24,15 @@ void exchange_packet(LPCHARACTER ch, BYTE sub_header, bool is_me, DWORD arg1, TI struct packet_exchange pack_exchg; - pack_exchg.header = HEADER_GC_EXCHANGE; + pack_exchg.header = GC::EXCHANGE; + pack_exchg.length = sizeof(pack_exchg); pack_exchg.sub_header = sub_header; pack_exchg.is_me = is_me; pack_exchg.arg1 = arg1; pack_exchg.arg2 = arg2; pack_exchg.arg3 = arg3; - if (sub_header == EXCHANGE_SUBHEADER_GC_ITEM_ADD && pvData) + if (sub_header == ExchangeSub::GC::ITEM_ADD && pvData) { thecore_memcpy(&pack_exchg.alSockets, ((LPITEM) pvData)->GetSockets(), sizeof(pack_exchg.alSockets)); thecore_memcpy(&pack_exchg.aAttr, ((LPITEM) pvData)->GetAttributes(), sizeof(pack_exchg.aAttr)); @@ -84,7 +85,7 @@ bool CHARACTER::ExchangeStart(LPCHARACTER victim) if (victim->GetExchange()) { - exchange_packet(this, EXCHANGE_SUBHEADER_GC_ALREADY, 0, 0, NPOS, 0); + exchange_packet(this, ExchangeSub::GC::ALREADY, 0, 0, NPOS, 0); return false; } @@ -104,8 +105,8 @@ bool CHARACTER::ExchangeStart(LPCHARACTER victim) SetExchangeTime(); victim->SetExchangeTime(); - exchange_packet(victim, EXCHANGE_SUBHEADER_GC_START, 0, GetVID(), NPOS, 0); - exchange_packet(this, EXCHANGE_SUBHEADER_GC_START, 0, victim->GetVID(), NPOS, 0); + exchange_packet(victim, ExchangeSub::GC::START, 0, GetVID(), NPOS, 0); + exchange_packet(this, ExchangeSub::GC::START, 0, victim->GetVID(), NPOS, 0); return true; } @@ -192,7 +193,7 @@ bool CExchange::AddItem(TItemPos item_pos, BYTE display_pos) item->SetExchanging(true); exchange_packet(m_pOwner, - EXCHANGE_SUBHEADER_GC_ITEM_ADD, + ExchangeSub::GC::ITEM_ADD, true, item->GetVnum(), TItemPos(RESERVED_WINDOW, display_pos), @@ -200,7 +201,7 @@ bool CExchange::AddItem(TItemPos item_pos, BYTE display_pos) item); exchange_packet(GetCompany()->GetOwner(), - EXCHANGE_SUBHEADER_GC_ITEM_ADD, + ExchangeSub::GC::ITEM_ADD, false, item->GetVnum(), TItemPos(RESERVED_WINDOW, display_pos), @@ -229,8 +230,8 @@ bool CExchange::RemoveItem(BYTE pos) m_pGrid->Get(m_abItemDisplayPos[pos], 1, m_apItems[pos]->GetSize()); - exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_ITEM_DEL, true, pos, NPOS, 0); - exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_ITEM_DEL, false, pos, PosOfInventory, 0); + exchange_packet(GetOwner(), ExchangeSub::GC::ITEM_DEL, true, pos, NPOS, 0); + exchange_packet(GetCompany()->GetOwner(), ExchangeSub::GC::ITEM_DEL, false, pos, PosOfInventory, 0); Accept(false); GetCompany()->Accept(false); @@ -249,7 +250,7 @@ bool CExchange::AddGold(long gold) if (GetOwner()->GetGold() < gold) { // 가지고 있는 돈이 부족. - exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_LESS_GOLD, 0, 0, NPOS, 0); + exchange_packet(GetOwner(), ExchangeSub::GC::LESS_GOLD, 0, 0, NPOS, 0); return false; } @@ -266,8 +267,8 @@ bool CExchange::AddGold(long gold) m_lGold = gold; - exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_GOLD_ADD, true, m_lGold, NPOS, 0); - exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_GOLD_ADD, false, m_lGold, NPOS, 0); + exchange_packet(GetOwner(), ExchangeSub::GC::GOLD_ADD, true, m_lGold, NPOS, 0); + exchange_packet(GetCompany()->GetOwner(), ExchangeSub::GC::GOLD_ADD, false, m_lGold, NPOS, 0); return true; } @@ -573,8 +574,8 @@ EXCHANGE_END: else { // 아니면 accept에 대한 패킷을 보내자. - exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, true, m_bAccept, NPOS, 0); - exchange_packet(GetCompany()->GetOwner(), EXCHANGE_SUBHEADER_GC_ACCEPT, false, m_bAccept, NPOS, 0); + exchange_packet(GetOwner(), ExchangeSub::GC::ACCEPT, true, m_bAccept, NPOS, 0); + exchange_packet(GetCompany()->GetOwner(), ExchangeSub::GC::ACCEPT, false, m_bAccept, NPOS, 0); return true; } } @@ -582,7 +583,7 @@ EXCHANGE_END: // 교환 취소 void CExchange::Cancel() { - exchange_packet(GetOwner(), EXCHANGE_SUBHEADER_GC_END, 0, 0, NPOS, 0); + exchange_packet(GetOwner(), ExchangeSub::GC::END, 0, 0, NPOS, 0); GetOwner()->SetExchange(NULL); for (int i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i) diff --git a/src/game/firewall_manager.cpp b/src/game/firewall_manager.cpp new file mode 100644 index 0000000..65fc291 --- /dev/null +++ b/src/game/firewall_manager.cpp @@ -0,0 +1,227 @@ +#include "stdafx.h" +#include "config.h" +#include "firewall_manager.h" + +#ifndef OS_WINDOWS +#include +#include +#include +#include +#include +#endif + +extern bool g_bFirewallEnable; +extern int g_iFirewallTcpSynLimit; +extern int g_iFirewallTcpSynBurst; + +FirewallManager::FirewallManager() = default; +FirewallManager::~FirewallManager() = default; + +#ifdef OS_WINDOWS + +// Windows: no-op stubs +bool FirewallManager::Initialize(WORD, WORD) { return false; } +void FirewallManager::Destroy() {} + +#else + +bool FirewallManager::RunCommand(const char* fmt, ...) +{ + char cmd[512]; + va_list args; + va_start(args, fmt); + vsnprintf(cmd, sizeof(cmd), fmt, args); + va_end(args); + + // Temporarily set SIGCHLD to SIG_DFL before calling system(). + // The game server sets SIGCHLD to SIG_IGN (auto-reap children), which + // causes waitpid() inside system() to return -1/ECHILD on FreeBSD + // because the child gets reaped before status can be collected. + struct sigaction saved, dflt; + memset(&dflt, 0, sizeof(dflt)); + dflt.sa_handler = SIG_DFL; + sigemptyset(&dflt.sa_mask); + sigaction(SIGCHLD, &dflt, &saved); + + int status = system(cmd); + + sigaction(SIGCHLD, &saved, NULL); + + if (status == -1) + { + sys_err("FirewallManager: system() failed for: %s", cmd); + return false; + } + + return (WIFEXITED(status) && WEXITSTATUS(status) == 0); +} + +#ifdef OS_FREEBSD + +// --------------------------------------------------------------- +// FreeBSD: ipfw +// Uses deterministic rule numbers based on port to avoid conflicts +// between multiple game processes on the same machine. +// Rule base = 50000 + (gamePort % 1000) * 10 +// --------------------------------------------------------------- + +void FirewallManager::CleanupRules() +{ + if (m_ruleBase == 0) + return; + + for (int i = 0; i < 10; ++i) + RunCommand("/sbin/ipfw -q delete %d 2>/dev/null", m_ruleBase + i); + + m_ruleCount = 0; +} + +bool FirewallManager::Initialize(WORD gamePort, WORD p2pPort) +{ + if (!g_bFirewallEnable) + return false; + + m_ruleBase = 50000 + (gamePort % 1000) * 10; + + // Clean up stale rules from previous crash + CleanupRules(); + + // Test if ipfw is available (use absolute path — popen() may have minimal PATH) + if (!RunCommand("/sbin/ipfw -q list >/dev/null 2>&1")) + { + sys_err("FirewallManager: ipfw not available (module not loaded? try: kldload ipfw)"); + m_ruleBase = 0; + return false; + } + + int r = m_ruleBase; + + // Drop inbound UDP to game and P2P ports + RunCommand("/sbin/ipfw -q add %d deny udp from any to me dst-port %d in", r++, gamePort); + RunCommand("/sbin/ipfw -q add %d deny udp from any to me dst-port %d in", r++, p2pPort); + + // Drop ICMP port-unreachable (type 3) + RunCommand("/sbin/ipfw -q add %d deny icmp from any to me icmptypes 3 in", r++); + + // TCP SYN rate limiting on game port (per-source concurrent connection limit) + RunCommand("/sbin/ipfw -q add %d allow tcp from any to me dst-port %d setup limit src-addr %d", + r++, gamePort, g_iFirewallTcpSynLimit); + RunCommand("/sbin/ipfw -q add %d deny tcp from any to me dst-port %d setup", + r++, gamePort); + + // TCP SYN rate limiting on P2P port + RunCommand("/sbin/ipfw -q add %d allow tcp from any to me dst-port %d setup limit src-addr %d", + r++, p2pPort, g_iFirewallTcpSynLimit); + RunCommand("/sbin/ipfw -q add %d deny tcp from any to me dst-port %d setup", + r++, p2pPort); + + m_ruleCount = r - m_ruleBase; + m_initialized = true; + sys_log(0, "FirewallManager: ipfw rules %d-%d installed (UDP DROP ports %d/%d, TCP SYN limit %d/src)", + m_ruleBase, r - 1, gamePort, p2pPort, g_iFirewallTcpSynLimit); + return true; +} + +#else + +// --------------------------------------------------------------- +// Linux: iptables +// Uses a dedicated chain per process (e.g., M2_GUARD_11011) +// --------------------------------------------------------------- + +void FirewallManager::CleanupRules() +{ + if (m_chainName.empty()) + return; + + // Unhook from INPUT (ignore failure — may not exist) + RunCommand("iptables -D INPUT -j %s 2>/dev/null", m_chainName.c_str()); + + // Flush and delete the chain (ignore failure) + RunCommand("iptables -F %s 2>/dev/null", m_chainName.c_str()); + RunCommand("iptables -X %s 2>/dev/null", m_chainName.c_str()); +} + +bool FirewallManager::Initialize(WORD gamePort, WORD p2pPort) +{ + if (!g_bFirewallEnable) + return false; + + // Chain name includes port to avoid conflicts with multi-channel servers + char buf[64]; + snprintf(buf, sizeof(buf), "M2_GUARD_%d", gamePort); + m_chainName = buf; + + // Always clean up stale rules first (handles crash recovery) + CleanupRules(); + + // Create fresh chain + if (!RunCommand("iptables -N %s", m_chainName.c_str())) + { + sys_err("FirewallManager: failed to create chain %s (not root? iptables not installed?)", m_chainName.c_str()); + m_chainName.clear(); + return false; + } + + // Allow established/related UDP (e.g. DNS replies from outbound queries) + RunCommand("iptables -A %s -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT", + m_chainName.c_str()); + + // DROP all unsolicited inbound UDP + RunCommand("iptables -A %s -p udp -j DROP", m_chainName.c_str()); + + // Rate-limit ICMP to prevent reflection attacks + RunCommand("iptables -A %s -p icmp --icmp-type port-unreachable -j DROP", + m_chainName.c_str()); + RunCommand("iptables -A %s -p icmp -m limit --limit 10/s --limit-burst 20 -j ACCEPT", + m_chainName.c_str()); + RunCommand("iptables -A %s -p icmp -j DROP", m_chainName.c_str()); + + // TCP SYN flood protection on game port + RunCommand("iptables -A %s -p tcp --dport %d --syn -m limit --limit %d/s --limit-burst %d -j ACCEPT", + m_chainName.c_str(), gamePort, g_iFirewallTcpSynLimit, g_iFirewallTcpSynBurst); + RunCommand("iptables -A %s -p tcp --dport %d --syn -j DROP", + m_chainName.c_str(), gamePort); + + // TCP SYN flood protection on P2P port + RunCommand("iptables -A %s -p tcp --dport %d --syn -m limit --limit %d/s --limit-burst %d -j ACCEPT", + m_chainName.c_str(), p2pPort, g_iFirewallTcpSynLimit, g_iFirewallTcpSynBurst); + RunCommand("iptables -A %s -p tcp --dport %d --syn -j DROP", + m_chainName.c_str(), p2pPort); + + // Hook chain into INPUT + if (!RunCommand("iptables -A INPUT -j %s", m_chainName.c_str())) + { + sys_err("FirewallManager: failed to hook chain into INPUT"); + CleanupRules(); + m_chainName.clear(); + return false; + } + + m_initialized = true; + sys_log(0, "FirewallManager: chain %s installed (UDP DROP, TCP SYN limit %d/s burst %d)", + m_chainName.c_str(), g_iFirewallTcpSynLimit, g_iFirewallTcpSynBurst); + return true; +} + +#endif // OS_FREEBSD + +void FirewallManager::Destroy() +{ + if (!m_initialized) + return; + + CleanupRules(); + m_initialized = false; + +#ifdef OS_FREEBSD + sys_log(0, "FirewallManager: ipfw rules %d-%d removed", m_ruleBase, m_ruleBase + m_ruleCount - 1); + m_ruleBase = 0; + m_ruleCount = 0; +#else + sys_log(0, "FirewallManager: chain %s removed", m_chainName.c_str()); + m_chainName.clear(); +#endif +} + +#endif // !OS_WINDOWS diff --git a/src/game/firewall_manager.h b/src/game/firewall_manager.h new file mode 100644 index 0000000..bdd8ff8 --- /dev/null +++ b/src/game/firewall_manager.h @@ -0,0 +1,33 @@ +#ifndef __INC_FIREWALL_MANAGER_H__ +#define __INC_FIREWALL_MANAGER_H__ + +// Kernel-level firewall management. +// Linux: iptables chains. FreeBSD: ipfw rules. +// Installs DROP rules for unsolicited UDP and rate-limits TCP SYN floods. +// Windows: no-op stubs. + +class FirewallManager : public singleton +{ +public: + FirewallManager(); + ~FirewallManager(); + + // Install firewall rules — call after config_init() + bool Initialize(WORD gamePort, WORD p2pPort); + + // Remove firewall rules — call during shutdown + void Destroy(); + +private: +#ifndef OS_WINDOWS + bool RunCommand(const char* fmt, ...); + void CleanupRules(); +#endif + + std::string m_chainName; // Linux: iptables chain name + int m_ruleBase = 0; // FreeBSD: ipfw rule number base + int m_ruleCount = 0; // FreeBSD: number of rules installed + bool m_initialized = false; +}; + +#endif diff --git a/src/game/fishing.cpp b/src/game/fishing.cpp index eb3094e..a3cd256 100644 --- a/src/game/fishing.cpp +++ b/src/game/fishing.cpp @@ -1,4 +1,4 @@ -//#define __FISHING_MAIN__ +//#define __FISHING_MAIN__ #include "stdafx.h" #include "constants.h" #include "fishing.h" @@ -8,7 +8,7 @@ #include "item_manager.h" #include "config.h" -#include "packet.h" +#include "packet_structs.h" #include "sectree_manager.h" #include "char.h" @@ -416,8 +416,9 @@ int DetermineFish(LPCHARACTER ch) void FishingReact(LPCHARACTER ch) { TPacketGCFishing p; - p.header = HEADER_GC_FISHING; - p.subheader = FISHING_SUBHEADER_GC_REACT; + p.header = GC::FISHING; + p.length = sizeof(p); + p.subheader = FishingSub::GC::REACT; p.info = ch->GetVID(); ch->PacketAround(&p, sizeof(p)); } @@ -425,8 +426,9 @@ void FishingReact(LPCHARACTER ch) void FishingSuccess(LPCHARACTER ch) { TPacketGCFishing p; - p.header = HEADER_GC_FISHING; - p.subheader = FISHING_SUBHEADER_GC_SUCCESS; + p.header = GC::FISHING; + p.length = sizeof(p); + p.subheader = FishingSub::GC::SUCCESS; p.info = ch->GetVID(); ch->PacketAround(&p, sizeof(p)); } @@ -434,8 +436,9 @@ void FishingSuccess(LPCHARACTER ch) void FishingFail(LPCHARACTER ch) { TPacketGCFishing p; - p.header = HEADER_GC_FISHING; - p.subheader = FISHING_SUBHEADER_GC_FAIL; + p.header = GC::FISHING; + p.length = sizeof(p); + p.subheader = FishingSub::GC::FAIL; p.info = ch->GetVID(); ch->PacketAround(&p, sizeof(p)); } @@ -510,8 +513,9 @@ EVENTFUNC(fishing_event) if (PredictFish(ch)) { TPacketGCFishing p; - p.header = HEADER_GC_FISHING; - p.subheader = FISHING_SUBHEADER_GC_FISH; + p.header = GC::FISHING; + p.length = sizeof(p); + p.subheader = FishingSub::GC::FISH; p.info = fish_info[info->fish_id].vnum; ch->GetDesc()->Packet(&p, sizeof(TPacketGCFishing)); } @@ -540,8 +544,9 @@ LPEVENT CreateFishingEvent(LPCHARACTER ch) int time = number(10, 40); TPacketGCFishing p; - p.header = HEADER_GC_FISHING; - p.subheader = FISHING_SUBHEADER_GC_START; + p.header = GC::FISHING; + p.length = sizeof(p); + p.subheader = FishingSub::GC::START; p.info = ch->GetVID(); p.dir = (BYTE)(ch->GetRotation()/5); ch->PacketAround(&p, sizeof(TPacketGCFishing)); @@ -644,8 +649,9 @@ void Take(fishing_event_info* info, LPCHARACTER ch) FishingSuccess(ch); TPacketGCFishing p; - p.header = HEADER_GC_FISHING; - p.subheader = FISHING_SUBHEADER_GC_FISH; + p.header = GC::FISHING; + p.length = sizeof(p); + p.subheader = FishingSub::GC::FISH; p.info = item_vnum; ch->GetDesc()->Packet(&p, sizeof(TPacketGCFishing)); @@ -675,7 +681,7 @@ void Take(fishing_event_info* info, LPCHARACTER ch) strlcpy(p.szBoard, LC_TEXT("낚시이벤트잉어"), sizeof(p.szBoard)); } - db_clientdesc->DBPacket(HEADER_GD_HIGHSCORE_REGISTER, 0, &p, sizeof(TPacketGDHighscore)); + db_clientdesc->DBPacket(GD::HIGHSCORE_REGISTER, 0, &p, sizeof(TPacketGDHighscore)); } } @@ -725,8 +731,9 @@ void Take(fishing_event_info* info, LPCHARACTER ch) else { TPacketGCFishing p; - p.header = HEADER_GC_FISHING; - p.subheader = FISHING_SUBHEADER_GC_STOP; + p.header = GC::FISHING; + p.length = sizeof(p); + p.subheader = FishingSub::GC::STOP; p.info = ch->GetVID(); ch->PacketAround(&p, sizeof(p)); } diff --git a/src/game/guild.cpp b/src/game/guild.cpp index d2d0f33..f17946b 100644 --- a/src/game/guild.cpp +++ b/src/game/guild.cpp @@ -1,8 +1,8 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "config.h" #include "char.h" -#include "packet.h" +#include "packet_structs.h" #include "desc_client.h" #include "buffer_manager.h" #include "char_manager.h" @@ -31,9 +31,9 @@ namespace { FGuildNameSender(uint32_t id, const char* guild_name) : id(id), name(guild_name) { - p.header = HEADER_GC_GUILD; - p.subheader = GUILD_SUBHEADER_GC_GUILD_NAME; - p.size = sizeof(p) + sizeof(uint32_t) + GUILD_NAME_MAX_LEN; + p.header = GC::GUILD; + p.subheader = GuildSub::GC::GUILD_NAME; + p.length = sizeof(p) + sizeof(uint32_t) + GUILD_NAME_MAX_LEN; } void operator() (LPCHARACTER ch) @@ -94,7 +94,7 @@ CGuild::CGuild(TGuildCreateParameter & cp) ComputeGuildPoints(); m_data.power = m_data.max_power; m_data.ladder_point = 0; - db_clientdesc->DBPacket(HEADER_GD_GUILD_CREATE, 0, &m_data.guild_id, sizeof(DWORD)); + db_clientdesc->DBPacket(GD::GUILD_CREATE, 0, &m_data.guild_id, sizeof(DWORD)); TPacketGuildSkillUpdate guild_skill; guild_skill.guild_id = m_data.guild_id; @@ -102,7 +102,7 @@ CGuild::CGuild(TGuildCreateParameter & cp) guild_skill.skill_point = 0; memset(guild_skill.skill_levels, 0, GUILD_SKILL_COUNT); - db_clientdesc->DBPacket(HEADER_GD_GUILD_SKILL_UPDATE, 0, &guild_skill, sizeof(guild_skill)); + db_clientdesc->DBPacket(GD::GUILD_SKILL_UPDATE, 0, &guild_skill, sizeof(guild_skill)); // TODO GUILD_NAME CHARACTER_MANAGER::instance().for_each_pc(FGuildNameSender(GetID(), GetName())); @@ -151,7 +151,7 @@ void CGuild::RequestAddMember(LPCHARACTER ch, int grade) gd.dwGuild = GetID(); gd.bGrade = grade; - db_clientdesc->DBPacket(HEADER_GD_GUILD_ADD_MEMBER, 0, &gd, sizeof(TPacketGDGuildAddMember)); + db_clientdesc->DBPacket(GD::GUILD_ADD_MEMBER, 0, &gd, sizeof(TPacketGDGuildAddMember)); } void CGuild::AddMember(TPacketDGGuildMember * p) @@ -200,7 +200,7 @@ bool CGuild::RequestRemoveMember(DWORD pid) gd_guild.dwGuild = GetID(); gd_guild.dwInfo = pid; - db_clientdesc->DBPacket(HEADER_GD_GUILD_REMOVE_MEMBER, 0, &gd_guild, sizeof(TPacketGuild)); + db_clientdesc->DBPacket(GD::GUILD_REMOVE_MEMBER, 0, &gd_guild, sizeof(TPacketGuild)); return true; } @@ -326,9 +326,9 @@ void CGuild::LogoutMember(LPCHARACTER ch) void CGuild::SendOnlineRemoveOnePacket(uint32_t pid) { TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+4; - pack.subheader = GUILD_SUBHEADER_GC_REMOVE; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+4; + pack.subheader = GuildSub::GC::REMOVE; TEMP_BUFFER buf; buf.write(&pack,sizeof(pack)); @@ -352,9 +352,9 @@ void CGuild::SendAllGradePacket(LPCHARACTER ch) return; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+1+GUILD_GRADE_COUNT*(sizeof(TGuildGrade)+1); - pack.subheader = GUILD_SUBHEADER_GC_GRADE; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+1+GUILD_GRADE_COUNT*(sizeof(TGuildGrade)+1); + pack.subheader = GuildSub::GC::GRADE; TEMP_BUFFER buf; @@ -384,9 +384,9 @@ void CGuild::SendListOneToAll(DWORD pid) return; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(TPacketGCGuild) + sizeof(TGuildMemberPacketData) + CHARACTER_NAME_MAX_LEN + 1; - pack.subheader = GUILD_SUBHEADER_GC_LIST; + pack.header = GC::GUILD; + pack.length = sizeof(TPacketGCGuild) + sizeof(TGuildMemberPacketData) + CHARACTER_NAME_MAX_LEN + 1; + pack.subheader = GuildSub::GC::LIST; char szName[CHARACTER_NAME_MAX_LEN + 1]; memset(szName, 0, sizeof(szName)); @@ -434,12 +434,12 @@ void CGuild::SendListPacket(LPCHARACTER ch) return; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(TPacketGCGuild); - pack.subheader = GUILD_SUBHEADER_GC_LIST; + pack.header = GC::GUILD; + pack.length = sizeof(TPacketGCGuild); + pack.subheader = GuildSub::GC::LIST; // Each member: struct + name (always sent with name_flag=1) - pack.size += (sizeof(TGuildMemberPacketData) + CHARACTER_NAME_MAX_LEN + 1) * m_member.size(); + pack.length += (sizeof(TGuildMemberPacketData) + CHARACTER_NAME_MAX_LEN + 1) * m_member.size(); TEMP_BUFFER buf; buf.write(&pack, sizeof(pack)); @@ -495,9 +495,9 @@ void CGuild::SendLoginPacket(LPCHARACTER ch, uint32_t pid) return; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+4; - pack.subheader = GUILD_SUBHEADER_GC_LOGIN; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+4; + pack.subheader = GuildSub::GC::LOGIN; TEMP_BUFFER buf; @@ -524,9 +524,9 @@ void CGuild::SendLogoutPacket(LPCHARACTER ch, uint32_t pid) return; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+4; - pack.subheader = GUILD_SUBHEADER_GC_LOGOUT; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+4; + pack.subheader = GuildSub::GC::LOGOUT; TEMP_BUFFER buf; @@ -661,7 +661,7 @@ void CGuild::SendDBSkillUpdate(int amount) guild_skill.skill_point = m_data.skill_point; thecore_memcpy(guild_skill.skill_levels, m_data.abySkill, sizeof(BYTE) * GUILD_SKILL_COUNT); - db_clientdesc->DBPacket(HEADER_GD_GUILD_SKILL_UPDATE, 0, &guild_skill, sizeof(guild_skill)); + db_clientdesc->DBPacket(GD::GUILD_SKILL_UPDATE, 0, &guild_skill, sizeof(guild_skill)); } void CGuild::SaveSkill() @@ -718,13 +718,13 @@ void CGuild::__P2PUpdateGrade(SQLMsg* pmsg) TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack); - pack.subheader = GUILD_SUBHEADER_GC_GRADE_NAME; + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::GRADE_NAME; + pack.length = sizeof(pack); TOneGradeNamePacket pack2; - pack.size += sizeof(pack2); + pack.length += sizeof(pack2); pack2.grade = grade + 1; strlcpy(pack2.grade_name, name, sizeof(pack2.grade_name)); @@ -747,12 +747,12 @@ void CGuild::__P2PUpdateGrade(SQLMsg* pmsg) m_data.grade_array[grade].auth_flag = auth; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack); - pack.subheader = GUILD_SUBHEADER_GC_GRADE_AUTH; + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::GRADE_AUTH; + pack.length = sizeof(pack); TOneGradeAuthPacket pack2; - pack.size+=sizeof(pack2); + pack.length+=sizeof(pack2); pack2.grade = grade+1; pack2.auth = auth; @@ -793,7 +793,7 @@ namespace void operator()() { - db_clientdesc->DBPacket(HEADER_GD_GUILD_CHANGE_GRADE, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_CHANGE_GRADE, 0, &p, sizeof(p)); } }; } @@ -824,12 +824,12 @@ void CGuild::ChangeGradeName(BYTE grade, const char* grade_name) strlcpy(m_data.grade_array[grade].grade_name, grade_name, sizeof(m_data.grade_array[grade].grade_name)); TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack); - pack.subheader = GUILD_SUBHEADER_GC_GRADE_NAME; + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::GRADE_NAME; + pack.length = sizeof(pack); TOneGradeNamePacket pack2; - pack.size+=sizeof(pack2); + pack.length+=sizeof(pack2); pack2.grade = grade+1; strlcpy(pack2.grade_name,grade_name, sizeof(pack2.grade_name)); @@ -864,12 +864,12 @@ void CGuild::ChangeGradeAuth(BYTE grade, BYTE auth) m_data.grade_array[grade].auth_flag=auth; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack); - pack.subheader = GUILD_SUBHEADER_GC_GRADE_AUTH; + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::GRADE_AUTH; + pack.length = sizeof(pack); TOneGradeAuthPacket pack2; - pack.size += sizeof(pack2); + pack.length += sizeof(pack2); pack2.grade = grade + 1; pack2.auth = auth; @@ -894,9 +894,9 @@ void CGuild::SendGuildInfoPacket(LPCHARACTER ch) return; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(TPacketGCGuild) + sizeof(TPacketGCGuildInfo); - pack.subheader = GUILD_SUBHEADER_GC_INFO; + pack.header = GC::GUILD; + pack.length = sizeof(TPacketGCGuild) + sizeof(TPacketGCGuildInfo); + pack.subheader = GuildSub::GC::INFO; TPacketGCGuildInfo pack_sub; @@ -948,22 +948,22 @@ bool CGuild::OfferExp(LPCHARACTER ch, int amount) TPacketGuildExpUpdate guild_exp; guild_exp.guild_id = GetID(); guild_exp.amount = amount / 100; - db_clientdesc->DBPacket(HEADER_GD_GUILD_EXP_UPDATE, 0, &guild_exp, sizeof(guild_exp)); + db_clientdesc->DBPacket(GD::GUILD_EXP_UPDATE, 0, &guild_exp, sizeof(guild_exp)); GuildPointChange(POINT_EXP, amount / 100, true); cit->second.offer_exp += amount / 100; cit->second._dummy = 0; TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; + pack.header = GC::GUILD; for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it) { LPDESC d = (*it)->GetDesc(); if (d) { - pack.subheader = GUILD_SUBHEADER_GC_LIST; - pack.size = sizeof(pack) + 13; + pack.subheader = GuildSub::GC::LIST; + pack.length = sizeof(pack) + 13; d->BufferedPacket(&pack, sizeof(pack)); d->Packet(&(cit->second), sizeof(DWORD) * 3 + 1); } @@ -979,7 +979,7 @@ bool CGuild::OfferExp(LPCHARACTER ch, int amount) gd_guild.level = ch->GetLevel(); gd_guild.grade = cit->second.grade; - db_clientdesc->DBPacket(HEADER_GD_GUILD_CHANGE_MEMBER_DATA, 0, &gd_guild, sizeof(gd_guild)); + db_clientdesc->DBPacket(GD::GUILD_CHANGE_MEMBER_DATA, 0, &gd_guild, sizeof(gd_guild)); return true; } @@ -1014,7 +1014,7 @@ void CGuild::RequestDisband(DWORD pid) TPacketGuild gd_guild; gd_guild.dwGuild = GetID(); gd_guild.dwInfo = 0; - db_clientdesc->DBPacket(HEADER_GD_GUILD_DISBAND, 0, &gd_guild, sizeof(TPacketGuild)); + db_clientdesc->DBPacket(GD::GUILD_DISBAND, 0, &gd_guild, sizeof(TPacketGuild)); // LAND_CLEAR building::CManager::instance().ClearLandByGuildID(GetID()); @@ -1071,9 +1071,9 @@ void CGuild::RefreshCommentForce(DWORD player_id) auto pmsg = DBManager::instance().DirectQuery("SELECT id, name, content FROM guild_comment%s WHERE guild_id = %u ORDER BY notice DESC, id DESC LIMIT %d", get_table_postfix(), m_data.guild_id, GUILD_COMMENT_MAX_COUNT); TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+1; - pack.subheader = GUILD_SUBHEADER_GC_COMMENTS; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+1; + pack.subheader = GuildSub::GC::COMMENTS; BYTE count = pmsg->Get()->uiNumRows; @@ -1082,7 +1082,7 @@ void CGuild::RefreshCommentForce(DWORD player_id) if (!d) return; - pack.size += (sizeof(DWORD)+CHARACTER_NAME_MAX_LEN+1+GUILD_COMMENT_MAX_LEN+1)*(WORD)count; + pack.length += (sizeof(DWORD)+CHARACTER_NAME_MAX_LEN+1+GUILD_COMMENT_MAX_LEN+1)*(WORD)count; d->BufferedPacket(&pack,sizeof(pack)); d->BufferedPacket(&count, 1); char szName[CHARACTER_NAME_MAX_LEN + 1]; @@ -1134,9 +1134,9 @@ bool CGuild::ChangeMemberGeneral(uint32_t pid, BYTE is_general) TGuildMemberOnlineContainer::iterator itOnline = m_memberOnline.begin(); TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+5; - pack.subheader = GUILD_SUBHEADER_GC_CHANGE_MEMBER_GENERAL; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+5; + pack.subheader = GuildSub::GC::CHANGE_MEMBER_GENERAL; while (itOnline != m_memberOnline.end()) { @@ -1169,9 +1169,9 @@ void CGuild::ChangeMemberGrade(uint32_t pid, BYTE grade) TGuildMemberOnlineContainer::iterator itOnline = m_memberOnline.begin(); TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+5; - pack.subheader = GUILD_SUBHEADER_GC_CHANGE_MEMBER_GRADE; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+5; + pack.subheader = GuildSub::GC::CHANGE_MEMBER_GRADE; while (itOnline != m_memberOnline.end()) { @@ -1195,7 +1195,7 @@ void CGuild::ChangeMemberGrade(uint32_t pid, BYTE grade) gd_guild.level = it->second.level; gd_guild.grade = grade; - db_clientdesc->DBPacket(HEADER_GD_GUILD_CHANGE_MEMBER_DATA, 0, &gd_guild, sizeof(gd_guild)); + db_clientdesc->DBPacket(GD::GUILD_CHANGE_MEMBER_DATA, 0, &gd_guild, sizeof(gd_guild)); } void CGuild::SkillLevelUp(DWORD dwVnum) @@ -1318,7 +1318,7 @@ void CGuild::UseSkill(DWORD dwVnum, LPCHARACTER ch, DWORD pid) p.dwGuild = GetID(); p.dwSkillVnum = pkSk->dwVnum; p.dwCooltime = iCooltime; - db_clientdesc->DBPacket(HEADER_GD_GUILD_USE_SKILL, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_USE_SKILL, 0, &p, sizeof(p)); } abSkillUsable[dwRealVnum] = false; //abSkillUsed[dwRealVnum] = true; @@ -1354,7 +1354,8 @@ void CGuild::UseSkill(DWORD dwVnum, LPCHARACTER ch, DWORD pid) else { TPacketGGFindPosition p; - p.header = HEADER_GG_FIND_POSITION; + p.header = GG::FIND_POSITION; + p.length = sizeof(p); p.dwFromPID = ch->GetPlayerID(); p.dwTargetPID = pid; pcci->pkDesc->Packet(&p, sizeof(TPacketGGFindPosition)); @@ -1412,9 +1413,9 @@ void CGuild::SendSkillInfoPacket(LPCHARACTER ch) const TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack) + 5 + GUILD_SKILL_COUNT; // 1 (skill_point) + GUILD_SKILL_COUNT (abySkill) + 2 (power) + 2 (max_power) - pack.subheader = GUILD_SUBHEADER_GC_SKILL_INFO; + pack.header = GC::GUILD; + pack.length = sizeof(pack) + 5 + GUILD_SKILL_COUNT; // 1 (skill_point) + GUILD_SKILL_COUNT (abySkill) + 2 (power) + 2 (max_power) + pack.subheader = GuildSub::GC::SKILL_INFO; d->BufferedPacket(&pack, sizeof(pack)); d->BufferedPacket(&m_data.skill_point, 1); @@ -1555,9 +1556,9 @@ void CGuild::GuildPointChange(BYTE type, int amount, bool save) } TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; - pack.size = sizeof(pack)+5; - pack.subheader = GUILD_SUBHEADER_GC_CHANGE_EXP; + pack.header = GC::GUILD; + pack.length = sizeof(pack)+5; + pack.subheader = GuildSub::GC::CHANGE_EXP; TEMP_BUFFER buf; buf.write(&pack,sizeof(pack)); @@ -1616,10 +1617,10 @@ void CGuild::LevelChange(DWORD pid, BYTE level) gd_guild.grade = cit->second.grade; gd_guild.level = level; - db_clientdesc->DBPacket(HEADER_GD_GUILD_CHANGE_MEMBER_DATA, 0, &gd_guild, sizeof(gd_guild)); + db_clientdesc->DBPacket(GD::GUILD_CHANGE_MEMBER_DATA, 0, &gd_guild, sizeof(gd_guild)); TPacketGCGuild pack; - pack.header = HEADER_GC_GUILD; + pack.header = GC::GUILD; cit->second._dummy = 0; for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it) @@ -1628,8 +1629,8 @@ void CGuild::LevelChange(DWORD pid, BYTE level) if (d) { - pack.subheader = GUILD_SUBHEADER_GC_LIST; - pack.size = sizeof(pack) + 13; + pack.subheader = GuildSub::GC::LIST; + pack.length = sizeof(pack) + 13; d->BufferedPacket(&pack, sizeof(pack)); d->Packet(&(cit->second), sizeof(DWORD) * 3 + 1); } @@ -1650,15 +1651,15 @@ void CGuild::ChangeMemberData(DWORD pid, DWORD offer, BYTE level, BYTE grade) TPacketGCGuild pack; memset(&pack, 0, sizeof(pack)); - pack.header = HEADER_GC_GUILD; + pack.header = GC::GUILD; for (TGuildMemberOnlineContainer::iterator it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it) { LPDESC d = (*it)->GetDesc(); if (d) { - pack.subheader = GUILD_SUBHEADER_GC_LIST; - pack.size = sizeof(pack) + 13; + pack.subheader = GuildSub::GC::LIST; + pack.length = sizeof(pack) + 13; d->BufferedPacket(&pack, sizeof(pack)); d->Packet(&(cit->second), sizeof(DWORD) * 3 + 1); } @@ -1694,8 +1695,9 @@ void CGuild::Chat(const char* c_pszText) TPacketGGGuild p1; TPacketGGGuildChat p2; - p1.bHeader = HEADER_GG_GUILD; - p1.bSubHeader = GUILD_SUBHEADER_GG_CHAT; + p1.header = GG::GUILD; + p1.length = sizeof(TPacketGGGuild) + sizeof(TPacketGGGuildChat); + p1.bSubHeader = GuildSub::GG::CHAT; p1.dwGuild = GetID(); strlcpy(p2.szText, c_pszText, sizeof(p2.szText)); @@ -1781,8 +1783,9 @@ void CGuild::BroadcastMemberCountBonus() { TPacketGGGuild p1; - p1.bHeader = HEADER_GG_GUILD; - p1.bSubHeader = GUILD_SUBHEADER_GG_SET_MEMBER_COUNT_BONUS; + p1.header = GG::GUILD; + p1.length = sizeof(TPacketGGGuild) + sizeof(int); + p1.bSubHeader = GuildSub::GG::SET_MEMBER_COUNT_BONUS; p1.dwGuild = GetID(); P2P_MANAGER::instance().Send(&p1, sizeof(TPacketGGGuild)); @@ -1838,7 +1841,7 @@ void CGuild::RequestDepositMoney(LPCHARACTER ch, int iGold) TPacketGDGuildMoney p; p.dwGuild = GetID(); p.iGold = iGold; - db_clientdesc->DBPacket(HEADER_GD_GUILD_DEPOSIT_MONEY, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_DEPOSIT_MONEY, 0, &p, sizeof(p)); char buf[64+1]; snprintf(buf, sizeof(buf), "%u %s", GetID(), GetName()); @@ -1871,7 +1874,7 @@ void CGuild::RequestWithdrawMoney(LPCHARACTER ch, int iGold) TPacketGDGuildMoney p; p.dwGuild = GetID(); p.iGold = iGold; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WITHDRAW_MONEY, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WITHDRAW_MONEY, 0, &p, sizeof(p)); ch->UpdateDepositPulse(); } @@ -1881,9 +1884,9 @@ void CGuild::RecvMoneyChange(int iGold) m_data.gold = iGold; TPacketGCGuild p; - p.header = HEADER_GC_GUILD; - p.size = sizeof(p) + sizeof(int); - p.subheader = GUILD_SUBHEADER_GC_MONEY_CHANGE; + p.header = GC::GUILD; + p.length = sizeof(p) + sizeof(int); + p.subheader = GuildSub::GC::MONEY_CHANGE; uint32_t gold = iGold; for (itertype(m_memberOnline) it = m_memberOnline.begin(); it != m_memberOnline.end(); ++it) @@ -1909,7 +1912,7 @@ void CGuild::RecvWithdrawMoneyGive(int iChangeGold) p.dwGuild = GetID(); p.iChangeGold = iChangeGold; p.bGiveSuccess = ch ? 1 : 0; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WITHDRAW_MONEY_GIVE_REPLY, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WITHDRAW_MONEY_GIVE_REPLY, 0, &p, sizeof(p)); } bool CGuild::HasLand() @@ -2025,9 +2028,9 @@ void CGuild::Invite( LPCHARACTER pchInviter, LPCHARACTER pchInvitee ) uint32_t gid = GetID(); TPacketGCGuild p; - p.header = HEADER_GC_GUILD; - p.size = sizeof(p) + sizeof(uint32_t) + GUILD_NAME_MAX_LEN; - p.subheader = GUILD_SUBHEADER_GC_GUILD_INVITE; + p.header = GC::GUILD; + p.length = sizeof(p) + sizeof(uint32_t) + GUILD_NAME_MAX_LEN; + p.subheader = GuildSub::GC::GUILD_INVITE; TEMP_BUFFER buf; buf.write( &p, sizeof(p) ); @@ -2117,7 +2120,7 @@ CGuild::GuildJoinErrCode CGuild::VerifyGuildJoinableCondition( const LPCHARACTER time_t limit_time=0; str_to_number( limit_time, row[0] ); - if ( test_server == true ) + if (test_server) { limit_time += quest::CQuestManager::instance().GetEventFlag("guild_invite_limit") * 60; } @@ -2143,7 +2146,7 @@ bool CGuild::ChangeMasterTo(DWORD dwPID) p.idFrom = GetMasterPID(); p.idTo = dwPID; - db_clientdesc->DBPacket(HEADER_GD_REQ_CHANGE_GUILD_MASTER, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::REQ_CHANGE_GUILD_MASTER, 0, &p, sizeof(p)); return true; } diff --git a/src/game/guild_manager.cpp b/src/game/guild_manager.cpp index a657bf2..f8f93c3 100644 --- a/src/game/guild_manager.cpp +++ b/src/game/guild_manager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "utils.h" #include "config.h" @@ -9,7 +9,7 @@ #include "desc_client.h" #include "buffer_manager.h" #include "char_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "war_map.h" #include "questmanager.h" #include "locale_service.h" @@ -23,9 +23,9 @@ namespace { FGuildNameSender(DWORD id, const char* guild_name) : id(id), name(guild_name) { - p.header = HEADER_GC_GUILD; - p.subheader = GUILD_SUBHEADER_GC_GUILD_NAME; - p.size = sizeof(p) + GUILD_NAME_MAX_LEN + sizeof(DWORD); + p.header = GC::GUILD; + p.subheader = GuildSub::GC::GUILD_NAME; + p.length = sizeof(p) + GUILD_NAME_MAX_LEN + sizeof(DWORD); } void operator()(LPCHARACTER ch) @@ -475,7 +475,7 @@ void CGuildManager::RequestCancelWar(DWORD guild_id1, DWORD guild_id2) p.bWar = GUILD_WAR_CANCEL; p.dwGuildFrom = guild_id1; p.dwGuildTo = guild_id2; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR, 0, &p, sizeof(p)); } void CGuildManager::RequestEndWar(DWORD guild_id1, DWORD guild_id2) @@ -486,7 +486,7 @@ void CGuildManager::RequestEndWar(DWORD guild_id1, DWORD guild_id2) p.bWar = GUILD_WAR_END; p.dwGuildFrom = guild_id1; p.dwGuildTo = guild_id2; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR, 0, &p, sizeof(p)); } void CGuildManager::RequestWarOver(DWORD dwGuild1, DWORD dwGuild2, DWORD dwGuildWinner, long lReward) @@ -520,7 +520,7 @@ void CGuildManager::RequestWarOver(DWORD dwGuild1, DWORD dwGuild2, DWORD dwGuild p.dwGuildTo = dwGuildWinner == dwGuild1 ? dwGuild2 : dwGuild1; } - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR, 0, &p, sizeof(p)); sys_log(0, "RequestWarOver : winner %u loser %u draw %u betprice %d", p.dwGuildFrom, p.dwGuildTo, p.bType, p.lWarPrice); } @@ -591,8 +591,8 @@ struct FSendWarList gid1 = guild_id1; gid2 = guild_id2; - p.header = HEADER_GC_GUILD; - p.size = sizeof(p) + sizeof(uint32_t) * 2; + p.header = GC::GUILD; + p.length = sizeof(p) + sizeof(uint32_t) * 2; p.subheader = subheader; } @@ -633,7 +633,7 @@ void CGuildManager::StartWar(DWORD guild_id1, DWORD guild_id2) if (guild_id1 > guild_id2) std::swap(guild_id1, guild_id2); - CHARACTER_MANAGER::instance().for_each_pc(FSendWarList(GUILD_SUBHEADER_GC_GUILD_WAR_LIST, guild_id1, guild_id2)); + CHARACTER_MANAGER::instance().for_each_pc(FSendWarList(GuildSub::GC::GUILD_WAR_LIST, guild_id1, guild_id2)); m_GuildWar.insert(std::make_pair(guild_id1, guild_id2)); } @@ -700,7 +700,7 @@ bool CGuildManager::EndWar(DWORD guild_id1, DWORD guild_id2) g2->EndWar(guild_id1); m_GuildWarEndTime[k] = get_global_time(); - CHARACTER_MANAGER::instance().for_each_pc(FSendWarList(GUILD_SUBHEADER_GC_GUILD_WAR_END_LIST, guild_id1, guild_id2)); + CHARACTER_MANAGER::instance().for_each_pc(FSendWarList(GuildSub::GC::GUILD_WAR_END_LIST, guild_id1, guild_id2)); m_GuildWar.erase(it); return true; @@ -796,9 +796,9 @@ void CGuildManager::SendGuildWar(LPCHARACTER ch) TEMP_BUFFER buf; TPacketGCGuild p; - p.header= HEADER_GC_GUILD; - p.subheader = GUILD_SUBHEADER_GC_GUILD_WAR_LIST; - p.size = sizeof(p) + (sizeof(uint32_t) * 2) * m_GuildWar.size(); + p.header= GC::GUILD; + p.subheader = GuildSub::GC::GUILD_WAR_LIST; + p.length = sizeof(p) + (sizeof(uint32_t) * 2) * m_GuildWar.size(); buf.write(&p, sizeof(p)); for (auto it = m_GuildWar.begin(); it != m_GuildWar.end(); ++it) @@ -820,7 +820,7 @@ void SendGuildWarScore(DWORD dwGuild, DWORD dwGuildOpp, int iDelta, int iBetScor p.lScore = iDelta; p.lBetScore = iBetScoreDelta; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR_SCORE, 0, &p, sizeof(TPacketGuildWarScore)); + db_clientdesc->DBPacket(GD::GUILD_WAR_SCORE, 0, &p, sizeof(TPacketGuildWarScore)); sys_log(0, "SendGuildWarScore %u %u %d", dwGuild, dwGuildOpp, iDelta); } diff --git a/src/game/guild_war.cpp b/src/game/guild_war.cpp index 7b08081..b61a3a8 100644 --- a/src/game/guild_war.cpp +++ b/src/game/guild_war.cpp @@ -1,10 +1,10 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "utils.h" #include "config.h" #include "log.h" #include "char.h" -#include "packet.h" +#include "packet_structs.h" #include "desc_client.h" #include "buffer_manager.h" #include "char_manager.h" @@ -30,9 +30,9 @@ void CGuild::GuildWarPacket(DWORD dwOppGID, BYTE bWarType, BYTE bWarState) TPacketGCGuild pack; TPacketGCGuildWar pack2; - pack.header = HEADER_GC_GUILD; - pack.subheader = GUILD_SUBHEADER_GC_WAR; - pack.size = sizeof(pack) + sizeof(pack2); + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::WAR; + pack.length = sizeof(pack) + sizeof(pack2); pack2.dwGuildSelf = GetID(); pack2.dwGuildOpp = dwOppGID; pack2.bWarState = bWarState; @@ -66,15 +66,15 @@ void CGuild::SendEnemyGuild(LPCHARACTER ch) TPacketGCGuild pack; TPacketGCGuildWar pack2; - pack.header = HEADER_GC_GUILD; - pack.subheader = GUILD_SUBHEADER_GC_WAR; - pack.size = sizeof(pack) + sizeof(pack2); + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::WAR; + pack.length = sizeof(pack) + sizeof(pack2); pack2.dwGuildSelf = GetID(); TPacketGCGuild p; - p.header = HEADER_GC_GUILD; - p.subheader = GUILD_SUBHEADER_GC_WAR_SCORE; - p.size = sizeof(p) + sizeof(DWORD) + sizeof(DWORD) + sizeof(long); + p.header = GC::GUILD; + p.subheader = GuildSub::GC::WAR_SCORE; + p.length = sizeof(p) + sizeof(DWORD) + sizeof(DWORD) + sizeof(long); for (itertype(m_EnemyGuild) it = m_EnemyGuild.begin(); it != m_EnemyGuild.end(); ++it) { @@ -199,9 +199,9 @@ void CGuild::SetWarScoreAgainstTo(DWORD dwOppGID, int iScore) { TPacketGCGuild p; - p.header = HEADER_GC_GUILD; - p.subheader = GUILD_SUBHEADER_GC_WAR_SCORE; - p.size = sizeof(p) + sizeof(DWORD) + sizeof(DWORD) + sizeof(long); + p.header = GC::GUILD; + p.subheader = GuildSub::GC::WAR_SCORE; + p.length = sizeof(p) + sizeof(DWORD) + sizeof(DWORD) + sizeof(long); TEMP_BUFFER buf; buf.write(&p, sizeof(p)); @@ -323,7 +323,7 @@ void CGuild::RequestDeclareWar(DWORD dwOppGID, BYTE type) p.bWar = GUILD_WAR_SEND_DECLARE; p.dwGuildFrom = GetID(); p.dwGuildTo = dwOppGID; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR, 0, &p, sizeof(p)); sys_log(0, "GuildWar.DeclareWar id(%d -> %d), type(%d)", GetID(), dwOppGID, type); return; } @@ -342,7 +342,7 @@ void CGuild::RequestDeclareWar(DWORD dwOppGID, BYTE type) p.bWar = GUILD_WAR_ON_WAR; p.dwGuildFrom = GetID(); p.dwGuildTo = dwOppGID; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR, 0, &p, sizeof(p)); sys_log(0, "GuildWar.AcceptWar id(%d -> %d), type(%d)", GetID(), dwOppGID, saved_type); return; } @@ -370,7 +370,7 @@ void CGuild::RequestDeclareWar(DWORD dwOppGID, BYTE type) if (test_server) p.lInitialScore /= 10; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR, 0, &p, sizeof(p)); sys_log(0, "GuildWar.WaitStartSendToDB id(%d vs %d), type(%d), bet(%d), map_index(%d)", GetID(), dwOppGID, saved_type, guildWarInfo.iWarPrice, guildWarInfo.lMapIndex); @@ -526,7 +526,8 @@ bool CGuild::WaitStartWar(DWORD dwOppGID) /////////////////////////////////////////////////////// TPacketGGGuildWarMapIndex p; - p.bHeader = HEADER_GG_GUILD_WAR_ZONE_MAP_INDEX; + p.header = GG::GUILD_WAR_ZONE_MAP_INDEX; + p.length = sizeof(p); p.dwGuildID1 = id1; p.dwGuildID2 = id2; p.lMapIndex = lMapIndex; @@ -552,7 +553,7 @@ void CGuild::RequestRefuseWar(DWORD dwOppGID) p.dwGuildFrom = GetID(); p.dwGuildTo = dwOppGID; - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR, 0, &p, sizeof(p)); } } @@ -742,7 +743,7 @@ void CGuild::ChangeLadderPoint(int iChange) TPacketGuildLadderPoint p; p.dwGuild = GetID(); p.lChange = iChange; - db_clientdesc->DBPacket(HEADER_GD_GUILD_CHANGE_LADDER_POINT, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_CHANGE_LADDER_POINT, 0, &p, sizeof(p)); } diff --git a/src/game/horsename_manager.cpp b/src/game/horsename_manager.cpp index 3edde96..1a20bef 100644 --- a/src/game/horsename_manager.cpp +++ b/src/game/horsename_manager.cpp @@ -1,4 +1,4 @@ - + #include "stdafx.h" #include "horsename_manager.h" #include "desc_client.h" @@ -52,7 +52,7 @@ void CHorseNameManager::BroadcastHorseName(DWORD dwPlayerID, const char* szHorse packet.dwPlayerID = dwPlayerID; strlcpy(packet.szHorseName, szHorseName, sizeof(packet.szHorseName)); - db_clientdesc->DBPacket(HEADER_GD_UPDATE_HORSE_NAME, 0, &packet, sizeof(TPacketUpdateHorseName)); + db_clientdesc->DBPacket(GD::UPDATE_HORSE_NAME, 0, &packet, sizeof(TPacketUpdateHorseName)); } void CHorseNameManager::Validate(LPCHARACTER pChar) diff --git a/src/game/input.cpp b/src/game/input.cpp index f268066..9463649 100644 --- a/src/game/input.cpp +++ b/src/game/input.cpp @@ -1,7 +1,8 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "desc.h" +#include "desc_client.h" #include "desc_manager.h" #include "char.h" #include "buffer_manager.h" @@ -11,9 +12,7 @@ #include "log.h" #include "db.h" #include "questmanager.h" -#include "login_sim.h" #include "fishing.h" -#include "TrafficProfiler.h" #include "priv_manager.h" #include "castle.h" @@ -49,7 +48,7 @@ bool CInputProcessor::Process(LPDESC lpDesc, const void * c_pvOrig, int iBytes, { const char * c_pData = (const char *) c_pvOrig; - BYTE bLastHeader = 0; + uint16_t wLastHeader = 0; int iLastPacketLen = 0; int iPacketLen; @@ -61,27 +60,59 @@ bool CInputProcessor::Process(LPDESC lpDesc, const void * c_pvOrig, int iBytes, for (m_iBufferLeft = iBytes; m_iBufferLeft > 0;) { - BYTE bHeader = (BYTE) *(c_pData); + uint16_t wHeader; const char * c_pszName; + int iRegisteredSize; - if (bHeader == 0) // 암호화 처리가 있으므로 0번 헤더는 스킵한다. - iPacketLen = 1; - else if (!m_pPacketInfo->Get(bHeader, &iPacketLen, &c_pszName)) + // 2-byte header + 2-byte wire length + if (m_iBufferLeft < (int)sizeof(uint16_t)) + return true; + + wHeader = *(uint16_t*)(c_pData); + + if (wHeader == 0) + { + // Skip zero-padding (2 bytes) + c_pData += sizeof(uint16_t); + m_iBufferLeft -= sizeof(uint16_t); + r_iBytesProceed += sizeof(uint16_t); + continue; + } + + // Need at least 4 bytes (header + length) to read the framing + if (m_iBufferLeft < (int)PACKET_HEADER_SIZE) + return true; + + // Read wire length from packet frame + iPacketLen = *(uint16_t*)(c_pData + 2); + + if (iPacketLen < (int)PACKET_HEADER_SIZE || iPacketLen > MAX_INPUT_LEN) + { + LPCHARACTER ch = lpDesc->GetCharacter(); + sys_err("INVALID PACKET LENGTH: header 0x%04X length %d (min %d, max %d), recv_seq %u, CHAR: %s, fd: %d host: %s", + wHeader, iPacketLen, (int)PACKET_HEADER_SIZE, MAX_INPUT_LEN, + lpDesc->GetRecvPacketSeq(), + ch ? ch->GetName() : "", + lpDesc->GetSocket(), lpDesc->GetHostName() + ); + lpDesc->DumpRecentPackets(); + lpDesc->SetPhase(PHASE_CLOSE); + return true; + } + + // Validate the header is registered + if (!m_pPacketInfo->Get(wHeader, &iRegisteredSize, &c_pszName)) { LPCHARACTER ch = lpDesc->GetCharacter(); - char szLogBuffer[1024]; - snprintf(szLogBuffer, sizeof(szLogBuffer), - "UNKNOWN HEADER: %u(0x%X) LAST HEADER: %u(0x%X)[%u], REMAIN BYTES: %d, CHAR: %s, PHASE: %d, fd: %d host: %s", - bHeader, bHeader, bLastHeader, bLastHeader, iLastPacketLen, m_iBufferLeft, + sys_err("UNKNOWN HEADER: 0x%04X (recv_seq #%u), LAST: 0x%04X[%u], REMAIN: %d, CHAR: %s, PHASE: %d, fd: %d host: %s", + wHeader, lpDesc->GetRecvPacketSeq(), + wLastHeader, iLastPacketLen, m_iBufferLeft, ch ? ch->GetName() : "", lpDesc->GetPhase(), lpDesc->GetSocket(), lpDesc->GetHostName() ); - if (lpDesc->GetPhase() < PHASE_SELECT) // early phase - sys_log(0, szLogBuffer); - else - sys_err(szLogBuffer); + lpDesc->DumpRecentPackets(); #if defined(_DEBUG) && defined(_WIN32) printdata((uint8_t*)c_pvOrig, m_iBufferLeft); @@ -90,66 +121,49 @@ bool CInputProcessor::Process(LPDESC lpDesc, const void * c_pvOrig, int iBytes, return true; } -#ifdef _DEBUG - const auto ch = lpDesc->GetCharacter(); - const std::string stName = ch ? ch->GetName() : lpDesc->GetHostName(); - sys_log(0, "RECEIVED HEADER : %u(0x%X) to %s (size %d) ", bHeader, bHeader, stName.c_str(), iBytes); -#endif - if (m_iBufferLeft < iPacketLen) - return true; - - if (bHeader) { - if (test_server && bHeader != HEADER_CG_MOVE) - sys_log(0, "Packet Analyze [Header %d][bufferLeft %d] ", bHeader, m_iBufferLeft); + return true; + } + + // Log this packet in the sequence tracker + lpDesc->LogRecvPacket(wHeader, static_cast(iPacketLen)); + + if (wHeader) + { + if (lpDesc->CheckPacketFlood()) + { + lpDesc->SetPhase(PHASE_CLOSE); + return true; + } m_pPacketInfo->Start(); - int iExtraPacketSize = Analyze(lpDesc, bHeader, c_pData); + int iExtraPacketSize = Analyze(lpDesc, wHeader, c_pData); if (iExtraPacketSize < 0) { LPCHARACTER ch = lpDesc->GetCharacter(); - sys_err("Failed to analyze header(%u) size: %d phase: %d host %s from %s (%u) in: %u", - bHeader, iPacketLen, lpDesc->GetPhase(), lpDesc->GetHostName(), + sys_err("Failed to analyze header(0x%04X) recv_seq #%u, size: %d phase: %d host %s from %s (%u) in: %u", + wHeader, lpDesc->GetRecvPacketSeq() - 1, + iPacketLen, lpDesc->GetPhase(), lpDesc->GetHostName(), ch ? ch->GetName() : "NO_CHAR", ch ? ch->GetPlayerID() : 0, ch ? ch->GetMapIndex() : 0 ); + lpDesc->DumpRecentPackets(); return true; } - iPacketLen += iExtraPacketSize; lpDesc->Log("%s %d", c_pszName, iPacketLen); + m_pPacketInfo->End(); } - // TRAFFIC_PROFILER - if (g_bTrafficProfileOn) - TrafficProfiler::instance().Report(TrafficProfiler::IODIR_INPUT, bHeader, iPacketLen); - // END_OF_TRAFFIC_PROFILER - - if (bHeader == HEADER_CG_PONG) - sys_log(0, "PONG! %u %u", m_pPacketInfo->IsSequence(bHeader), *(BYTE *) (c_pData + iPacketLen - sizeof(BYTE))); - - if (m_pPacketInfo->IsSequence(bHeader)) - { - BYTE bSeq = lpDesc->GetSequence(); - BYTE bSeqReceived = *(BYTE *) (c_pData + iPacketLen - sizeof(BYTE)); - - if (bSeq != bSeqReceived) - { - sys_err("SEQUENCE %x mismatch 0x%x != 0x%x header %u", get_pointer(lpDesc), bSeq, bSeqReceived, bHeader); - lpDesc->SetPhase(PHASE_CLOSE); - return true; - } - } - c_pData += iPacketLen; m_iBufferLeft -= iPacketLen; r_iBytesProceed += iPacketLen; iLastPacketLen = iPacketLen; - bLastHeader = bHeader; + wLastHeader = wHeader; if (GetType() != lpDesc->GetInputProcessor()->GetType()) return false; @@ -163,30 +177,6 @@ void CInputProcessor::Pong(LPDESC d) d->SetPong(true); } -void CInputProcessor::Handshake(LPDESC d, const char * c_pData) -{ - TPacketCGHandshake * p = (TPacketCGHandshake *) c_pData; - - if (d->GetHandshake() != p->dwHandshake) - { - sys_err("Invalid Handshake on %d", d->GetSocket()); - d->SetPhase(PHASE_CLOSE); - } - else - { - if (d->IsPhase(PHASE_HANDSHAKE)) - { - if (d->HandshakeProcess(p->dwTime, p->lDelta, false)) - { - // Use secure key exchange (libsodium/XChaCha20-Poly1305) - d->SendKeyChallenge(); - } - } - else - d->HandshakeProcess(p->dwTime, p->lDelta, true); - } -} - void CInputProcessor::Version(LPCHARACTER ch, const char* c_pData) { if (!ch) @@ -204,7 +194,8 @@ void LoginFailure(LPDESC d, const char * c_pszStatus) TPacketGCLoginFailure failurePacket; - failurePacket.header = HEADER_GC_LOGIN_FAILURE; + failurePacket.header = GC::LOGIN_FAILURE; + failurePacket.length = sizeof(failurePacket); strlcpy(failurePacket.szStatus, c_pszStatus, sizeof(failurePacket.szStatus)); d->Packet(&failurePacket, sizeof(failurePacket)); @@ -213,10 +204,10 @@ void LoginFailure(LPDESC d, const char * c_pszStatus) CInputHandshake::CInputHandshake() { CPacketInfoCG * pkPacketInfo = M2_NEW CPacketInfoCG; - pkPacketInfo->SetSequence(HEADER_CG_PONG, false); m_pMainPacketInfo = m_pPacketInfo; BindPacketInfo(pkPacketInfo); + RegisterHandlers(); } CInputHandshake::~CInputHandshake() @@ -229,59 +220,46 @@ CInputHandshake::~CInputHandshake() } -std::map g_sim; -std::map g_simByPID; std::vector g_vec_save; // BLOCK_CHAT ACMD(do_block_chat); // END_OF_BLOCK_CHAT -int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) +int CInputHandshake::HandleText(LPDESC d, const char * c_pData) { - if (bHeader == 10) // 엔터는 무시 - return 0; + c_pData += PACKET_HEADER_SIZE; // skip [header:2][length:2] + const char * c_pSep; - if (bHeader == HEADER_CG_TEXT) + if (!(c_pSep = strchr(c_pData, '\n'))) // \n을 찾는다. + return -1; + + if (*(c_pSep - 1) == '\r') + --c_pSep; + + std::string stResult; + std::string stBuf; + stBuf.assign(c_pData, 0, c_pSep - c_pData); + + sys_log(0, "SOCKET_CMD: FROM(%s) CMD(%s)", d->GetHostName(), stBuf.c_str()); + + if (!stBuf.compare("IS_SERVER_UP")) { - ++c_pData; - const char * c_pSep; - - if (!(c_pSep = strchr(c_pData, '\n'))) // \n을 찾는다. - return -1; - - if (*(c_pSep - 1) == '\r') - --c_pSep; - - std::string stResult; - std::string stBuf; - stBuf.assign(c_pData, 0, c_pSep - c_pData); - - sys_log(0, "SOCKET_CMD: FROM(%s) CMD(%s)", d->GetHostName(), stBuf.c_str()); - - if (!stBuf.compare("IS_SERVER_UP")) + if (g_bNoMoreClient) + stResult = "NO"; + else + stResult = "YES"; + } + //else if (!stBuf.compare("SHOWMETHEMONEY")) + else if (stBuf == g_stAdminPagePassword) + { + if (!IsEmptyAdminPage()) { - if (g_bNoMoreClient) - stResult = "NO"; - else - stResult = "YES"; - } - //else if (!stBuf.compare("SHOWMETHEMONEY")) - else if (stBuf == g_stAdminPagePassword) - { - if (!IsEmptyAdminPage()) + if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr))) { - if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr))) - { - char szTmp[64]; - snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr)); - stResult += szTmp; - } - else - { - d->SetAdminMode(); - stResult = "UNKNOWN"; - } + char szTmp[64]; + snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr)); + stResult += szTmp; } else { @@ -289,24 +267,21 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) stResult = "UNKNOWN"; } } - else if (!stBuf.compare("USER_COUNT")) + else { - char szTmp[64]; + d->SetAdminMode(); + stResult = "UNKNOWN"; + } + } + else if (!stBuf.compare("USER_COUNT")) + { + char szTmp[64]; - if (!IsEmptyAdminPage()) + if (!IsEmptyAdminPage()) + { + if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr))) { - if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr))) - { - snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr)); - } - else - { - int iTotal; - int * paiEmpireUserCount; - int iLocal; - DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal); - snprintf(szTmp, sizeof(szTmp), "%d %d %d %d %d", iTotal, paiEmpireUserCount[1], paiEmpireUserCount[2], paiEmpireUserCount[3], iLocal); - } + snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr)); } else { @@ -316,289 +291,321 @@ int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal); snprintf(szTmp, sizeof(szTmp), "%d %d %d %d %d", iTotal, paiEmpireUserCount[1], paiEmpireUserCount[2], paiEmpireUserCount[3], iLocal); } + } + else + { + int iTotal; + int * paiEmpireUserCount; + int iLocal; + DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal); + snprintf(szTmp, sizeof(szTmp), "%d %d %d %d %d", iTotal, paiEmpireUserCount[1], paiEmpireUserCount[2], paiEmpireUserCount[3], iLocal); + } + stResult += szTmp; + } + else if (!stBuf.compare("CHECK_P2P_CONNECTIONS")) + { + std::ostringstream oss(std::ostringstream::out); + + oss << "P2P CONNECTION NUMBER : " << P2P_MANAGER::instance().GetDescCount() << "\n"; + std::string hostNames; + P2P_MANAGER::Instance().GetP2PHostNames(hostNames); + oss << hostNames; + stResult = oss.str(); + TPacketGGCheckAwakeness packet; + packet.header = GG::CHECK_AWAKENESS; + packet.length = sizeof(packet); + + P2P_MANAGER::instance().Send(&packet, sizeof(packet)); + } + else if (!stBuf.compare("PACKET_INFO")) + { + m_pMainPacketInfo->Log("packet_info.txt"); + stResult = "OK"; + } + else if (!stBuf.compare("PROFILE")) + { + CProfiler::instance().Log("profile.txt"); + stResult = "OK"; + } + //gift notify delete command + else if (!stBuf.compare(0,15,"DELETE_AWARDID ")) + { + char szTmp[64]; + std::string msg = stBuf.substr(15,26); // item_award의 id범위? + + TPacketDeleteAwardID p; + p.dwID = (DWORD)(atoi(msg.c_str())); + snprintf(szTmp,sizeof(szTmp),"Sent to DB cache to delete ItemAward, id: %d",p.dwID); + //sys_log(0,"%d",p.dwID); + // strlcpy(p.login, msg.c_str(), sizeof(p.login)); + db_clientdesc->DBPacket(GD::DELETE_AWARDID, 0, &p, sizeof(p)); stResult += szTmp; } - else if (!stBuf.compare("CHECK_P2P_CONNECTIONS")) - { - std::ostringstream oss(std::ostringstream::out); - - oss << "P2P CONNECTION NUMBER : " << P2P_MANAGER::instance().GetDescCount() << "\n"; - std::string hostNames; - P2P_MANAGER::Instance().GetP2PHostNames(hostNames); - oss << hostNames; - stResult = oss.str(); - TPacketGGCheckAwakeness packet; - packet.bHeader = HEADER_GG_CHECK_AWAKENESS; - - P2P_MANAGER::instance().Send(&packet, sizeof(packet)); - } - else if (!stBuf.compare("PACKET_INFO")) - { - m_pMainPacketInfo->Log("packet_info.txt"); - stResult = "OK"; - } - else if (!stBuf.compare("PROFILE")) - { - CProfiler::instance().Log("profile.txt"); - stResult = "OK"; - } - //gift notify delete command - else if (!stBuf.compare(0,15,"DELETE_AWARDID ")) - { - char szTmp[64]; - std::string msg = stBuf.substr(15,26); // item_award의 id범위? - - TPacketDeleteAwardID p; - p.dwID = (DWORD)(atoi(msg.c_str())); - snprintf(szTmp,sizeof(szTmp),"Sent to DB cache to delete ItemAward, id: %d",p.dwID); - //sys_log(0,"%d",p.dwID); - // strlcpy(p.login, msg.c_str(), sizeof(p.login)); - db_clientdesc->DBPacket(HEADER_GD_DELETE_AWARDID, 0, &p, sizeof(p)); - stResult += szTmp; - } - else - { - stResult = "UNKNOWN"; - - if (d->IsAdminMode()) - { - // 어드민 명령들 - if (!stBuf.compare(0, 7, "NOTICE ")) - { - std::string msg = stBuf.substr(7, 50); - LogManager::instance().CharLog(0, 0, 0, 1, "NOTICE", msg.c_str(), d->GetHostName()); - BroadcastNotice(msg.c_str()); - } - else if (!stBuf.compare("SHUTDOWN")) - { - LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName()); - TPacketGGShutdown p; - p.bHeader = HEADER_GG_SHUTDOWN; - P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShutdown)); - sys_err("Accept shutdown command from %s.", d->GetHostName()); - Shutdown(10); - } - else if (!stBuf.compare("SHUTDOWN_ONLY")) - { - LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName()); - sys_err("Accept shutdown only command from %s.", d->GetHostName()); - Shutdown(10); - } - else if (!stBuf.compare(0, 3, "DC ")) - { - std::string msg = stBuf.substr(3, LOGIN_MAX_LEN); - - sys_log(1, "DC : '%s'", msg.c_str()); - - TPacketGGDisconnect pgg; - - pgg.bHeader = HEADER_GG_DISCONNECT; - strlcpy(pgg.szLogin, msg.c_str(), sizeof(pgg.szLogin)); - - P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGDisconnect)); - - // delete login key - { - TPacketDC p; - strlcpy(p.login, msg.c_str(), sizeof(p.login)); - db_clientdesc->DBPacket(HEADER_GD_DC, 0, &p, sizeof(p)); - } - } - else if (!stBuf.compare(0, 10, "RELOAD_CRC")) - { - LoadValidCRCList(); - - BYTE bHeader = HEADER_GG_RELOAD_CRC_LIST; - P2P_MANAGER::instance().Send(&bHeader, sizeof(BYTE)); - stResult = "OK"; - } - else if (!stBuf.compare(0, 20, "CHECK_CLIENT_VERSION")) - { - CheckClientVersion(); - - BYTE bHeader = HEADER_GG_CHECK_CLIENT_VERSION; - P2P_MANAGER::instance().Send(&bHeader, sizeof(BYTE)); - stResult = "OK"; - } - else if (!stBuf.compare(0, 6, "RELOAD")) - { - if (stBuf.size() == 6) - { - LoadStateUserCount(); - db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, NULL, 0); - } - else - { - char c = stBuf[7]; - - switch (LOWER(c)) - { - case 'u': - LoadStateUserCount(); - break; - - case 'p': - db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, NULL, 0); - break; - - case 'q': - quest::CQuestManager::instance().Reload(); - break; - - case 'f': - fishing::Initialize(); - break; - - case 'a': - db_clientdesc->DBPacket(HEADER_GD_RELOAD_ADMIN, 0, NULL, 0); - sys_log(0, "Reloading admin infomation."); - break; - } - } - } - else if (!stBuf.compare(0, 6, "EVENT ")) - { - std::istringstream is(stBuf); - std::string strEvent, strFlagName; - long lValue; - is >> strEvent >> strFlagName >> lValue; - - if (!is.fail()) - { - sys_log(0, "EXTERNAL EVENT FLAG name %s value %d", strFlagName.c_str(), lValue); - quest::CQuestManager::instance().RequestSetEventFlag(strFlagName, lValue); - stResult = "EVENT FLAG CHANGE "; - stResult += strFlagName; - } - else - { - stResult = "EVENT FLAG FAIL"; - } - } - // BLOCK_CHAT - else if (!stBuf.compare(0, 11, "BLOCK_CHAT ")) - { - std::istringstream is(stBuf); - std::string strBlockChat, strCharName; - long lDuration; - is >> strBlockChat >> strCharName >> lDuration; - - if (!is.fail()) - { - sys_log(0, "EXTERNAL BLOCK_CHAT name %s duration %d", strCharName.c_str(), lDuration); - - do_block_chat(NULL, const_cast(stBuf.c_str() + 11), 0, 0); - - stResult = "BLOCK_CHAT "; - stResult += strCharName; - } - else - { - stResult = "BLOCK_CHAT FAIL"; - } - } - // END_OF_BLOCK_CHAT - else if (!stBuf.compare(0, 12, "PRIV_EMPIRE ")) - { - int empire, type, value, duration; - std::istringstream is(stBuf); - std::string strPrivEmpire; - is >> strPrivEmpire >> empire >> type >> value >> duration; - - // 최대치 10배 - value = MINMAX(0, value, 1000); - stResult = "PRIV_EMPIRE FAIL"; - - if (!is.fail()) - { - // check parameter - if (empire < 0 || 3 < empire); - else if (type < 1 || 4 < type); - else if (value < 0); - else if (duration < 0); - else - { - stResult = "PRIV_EMPIRE SUCCEED"; - - // 시간 단위로 변경 - duration = duration * (60 * 60); - - sys_log(0, "_give_empire_privileage(empire=%d, type=%d, value=%d, duration=%d) by web", - empire, type, value, duration); - CPrivManager::instance().RequestGiveEmpirePriv(empire, type, value, duration); - } - } - } - } - } - - sys_log(1, "TEXT %s RESULT %s", stBuf.c_str(), stResult.c_str()); - stResult += "\n"; - d->Packet(stResult.c_str(), stResult.length()); - return (c_pSep - c_pData) + 1; - } - else if (bHeader == HEADER_CG_MARK_LOGIN) + else { - if (!guild_mark_server) + stResult = "UNKNOWN"; + + if (d->IsAdminMode()) { - // 끊어버려! - 마크 서버가 아닌데 마크를 요청하려고? - sys_err("Guild Mark login requested but i'm not a mark server!"); - d->SetPhase(PHASE_CLOSE); - return 0; - } + // 어드민 명령들 + if (!stBuf.compare(0, 7, "NOTICE ")) + { + std::string msg = stBuf.substr(7, 50); + LogManager::instance().CharLog(0, 0, 0, 1, "NOTICE", msg.c_str(), d->GetHostName()); + BroadcastNotice(msg.c_str()); + } + else if (!stBuf.compare("SHUTDOWN")) + { + LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName()); + TPacketGGShutdown p; + p.header = GG::SHUTDOWN; p.length = sizeof(p); + P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShutdown)); + sys_err("Accept shutdown command from %s.", d->GetHostName()); + Shutdown(10); + } + else if (!stBuf.compare("SHUTDOWN_ONLY")) + { + LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName()); + sys_err("Accept shutdown only command from %s.", d->GetHostName()); + Shutdown(10); + } + else if (!stBuf.compare(0, 3, "DC ")) + { + std::string msg = stBuf.substr(3, LOGIN_MAX_LEN); - // 무조건 인증 --; - sys_log(0, "MARK_SERVER: Login"); - d->SetPhase(PHASE_LOGIN); + sys_log(1, "DC : '%s'", msg.c_str()); + + TPacketGGDisconnect pgg; + + pgg.header = GG::DISCONNECT; pgg.length = sizeof(pgg); + strlcpy(pgg.szLogin, msg.c_str(), sizeof(pgg.szLogin)); + + P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGDisconnect)); + + // delete login key + { + TPacketDC p; + strlcpy(p.login, msg.c_str(), sizeof(p.login)); + db_clientdesc->DBPacket(GD::DC, 0, &p, sizeof(p)); + } + } + else if (!stBuf.compare(0, 10, "RELOAD_CRC")) + { + LoadValidCRCList(); + + struct { uint16_t header; uint16_t length; } pReloadCRC; + pReloadCRC.header = GG::RELOAD_CRC_LIST; + pReloadCRC.length = sizeof(pReloadCRC); + P2P_MANAGER::instance().Send(&pReloadCRC, sizeof(pReloadCRC)); + stResult = "OK"; + } + else if (!stBuf.compare(0, 20, "CHECK_CLIENT_VERSION")) + { + CheckClientVersion(); + + struct { uint16_t header; uint16_t length; } pCheckVer; + pCheckVer.header = GG::CHECK_CLIENT_VERSION; + pCheckVer.length = sizeof(pCheckVer); + P2P_MANAGER::instance().Send(&pCheckVer, sizeof(pCheckVer)); + stResult = "OK"; + } + else if (!stBuf.compare(0, 6, "RELOAD")) + { + if (stBuf.size() == 6) + { + LoadStateUserCount(); + db_clientdesc->DBPacket(GD::RELOAD_PROTO, 0, NULL, 0); + } + else + { + char c = stBuf[7]; + + switch (LOWER(c)) + { + case 'u': + LoadStateUserCount(); + break; + + case 'p': + db_clientdesc->DBPacket(GD::RELOAD_PROTO, 0, NULL, 0); + break; + + case 'q': + quest::CQuestManager::instance().Reload(); + break; + + case 'f': + fishing::Initialize(); + break; + + case 'a': + db_clientdesc->DBPacket(GD::RELOAD_ADMIN, 0, NULL, 0); + sys_log(0, "Reloading admin infomation."); + break; + } + } + } + else if (!stBuf.compare(0, 6, "EVENT ")) + { + std::istringstream is(stBuf); + std::string strEvent, strFlagName; + long lValue; + is >> strEvent >> strFlagName >> lValue; + + if (!is.fail()) + { + sys_log(0, "EXTERNAL EVENT FLAG name %s value %d", strFlagName.c_str(), lValue); + quest::CQuestManager::instance().RequestSetEventFlag(strFlagName, lValue); + stResult = "EVENT FLAG CHANGE "; + stResult += strFlagName; + } + else + { + stResult = "EVENT FLAG FAIL"; + } + } + // BLOCK_CHAT + else if (!stBuf.compare(0, 11, "BLOCK_CHAT ")) + { + std::istringstream is(stBuf); + std::string strBlockChat, strCharName; + long lDuration; + is >> strBlockChat >> strCharName >> lDuration; + + if (!is.fail()) + { + sys_log(0, "EXTERNAL BLOCK_CHAT name %s duration %d", strCharName.c_str(), lDuration); + + do_block_chat(NULL, const_cast(stBuf.c_str() + 11), 0, 0); + + stResult = "BLOCK_CHAT "; + stResult += strCharName; + } + else + { + stResult = "BLOCK_CHAT FAIL"; + } + } + // END_OF_BLOCK_CHAT + else if (!stBuf.compare(0, 12, "PRIV_EMPIRE ")) + { + int empire, type, value, duration; + std::istringstream is(stBuf); + std::string strPrivEmpire; + is >> strPrivEmpire >> empire >> type >> value >> duration; + + // 최대치 10배 + value = MINMAX(0, value, 1000); + stResult = "PRIV_EMPIRE FAIL"; + + if (!is.fail()) + { + // check parameter + if (empire < 0 || 3 < empire); + else if (type < 1 || 4 < type); + else if (value < 0); + else if (duration < 0); + else + { + stResult = "PRIV_EMPIRE SUCCEED"; + + // 시간 단위로 변경 + duration = duration * (60 * 60); + + sys_log(0, "_give_empire_privileage(empire=%d, type=%d, value=%d, duration=%d) by web", + empire, type, value, duration); + CPrivManager::instance().RequestGiveEmpirePriv(empire, type, value, duration); + } + } + } + } + } + + sys_log(1, "TEXT %s RESULT %s", stBuf.c_str(), stResult.c_str()); + stResult += "\n"; + d->Packet(stResult.c_str(), stResult.length()); + return (c_pSep - c_pData) + 1; +} + +int CInputHandshake::HandleMarkLogin(LPDESC d, const char*) +{ + if (!guild_mark_server) + { + sys_err("Guild Mark login requested but i'm not a mark server!"); + d->SetPhase(PHASE_CLOSE); return 0; } - else if (bHeader == HEADER_CG_STATE_CHECKER) - { - if (d->isChannelStatusRequested()) { - return 0; - } - d->SetChannelStatusRequested(true); - db_clientdesc->DBPacket(HEADER_GD_REQUEST_CHANNELSTATUS, d->GetHandle(), NULL, 0); - } - else if (bHeader == HEADER_CG_PONG) - Pong(d); - else if (bHeader == HEADER_CG_HANDSHAKE) - Handshake(d, c_pData); - // Secure key exchange (libsodium/XChaCha20-Poly1305) - else if (bHeader == HEADER_CG_KEY_RESPONSE) - { - TPacketCGKeyResponse* p = (TPacketCGKeyResponse*)c_pData; - - if (!d->GetSecureCipher().IsInitialized()) - { - sys_err("SecureCipher not initialized. %s maybe a Hacker.", inet_ntoa(d->GetAddr().sin_addr)); - d->DelayedDisconnect(5); - return 0; - } - - if (d->HandleKeyResponse(p->client_pk, p->challenge_response)) - { - // Key exchange succeeded, send completion - d->SendKeyComplete(); - - // Move to next phase - if (g_bAuthServer) { - d->SetPhase(PHASE_AUTH); - } else { - d->SetPhase(PHASE_LOGIN); - } - } - else - { - sys_err("[CInputHandshake] Secure key response verification failed for %s", - inet_ntoa(d->GetAddr().sin_addr)); - d->SetPhase(PHASE_CLOSE); - } - } - else - sys_err("Handshake phase does not handle packet %d (fd %d)", bHeader, d->GetSocket()); + sys_log(0, "MARK_SERVER: Login"); + d->SetPhase(PHASE_LOGIN); return 0; } +int CInputHandshake::HandleStateChecker(LPDESC d, const char*) +{ + if (d->isChannelStatusRequested()) { + return 0; + } + d->SetChannelStatusRequested(true); + db_clientdesc->DBPacket(GD::REQUEST_CHANNELSTATUS, d->GetHandle(), NULL, 0); + return 0; +} +int CInputHandshake::HandlePong(LPDESC d, const char*) +{ + Pong(d); + return 0; +} + +int CInputHandshake::HandleKeyResponse(LPDESC d, const char* c_pData) +{ + TPacketCGKeyResponse* p = (TPacketCGKeyResponse*)c_pData; + + if (!d->GetSecureCipher().IsInitialized()) + { + sys_err("SecureCipher not initialized. %s maybe a Hacker.", inet_ntoa(d->GetAddr().sin_addr)); + d->DelayedDisconnect(5); + return 0; + } + + if (d->HandleKeyResponse(p->client_pk, p->challenge_response)) + { + d->SendKeyComplete(); + + if (g_bAuthServer) { + sys_log(0, "[HANDSHAKE] Key exchange complete for %s, transitioning to PHASE_AUTH", d->GetHostName()); + d->SetPhase(PHASE_AUTH); + } else { + sys_log(0, "[HANDSHAKE] Key exchange complete for %s, transitioning to PHASE_LOGIN", d->GetHostName()); + d->SetPhase(PHASE_LOGIN); + } + } + else + { + sys_err("[HANDSHAKE] Secure key response verification FAILED for %s", + inet_ntoa(d->GetAddr().sin_addr)); + d->SetPhase(PHASE_CLOSE); + } + return 0; +} + +void CInputHandshake::RegisterHandlers() +{ + m_handlers[CG::TEXT] = &CInputHandshake::HandleText; + m_handlers[CG::MARK_LOGIN] = &CInputHandshake::HandleMarkLogin; + m_handlers[CG::STATE_CHECKER] = &CInputHandshake::HandleStateChecker; + m_handlers[CG::PONG] = &CInputHandshake::HandlePong; + m_handlers[CG::KEY_RESPONSE] = &CInputHandshake::HandleKeyResponse; +} + +int CInputHandshake::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) +{ + auto it = m_handlers.find(wHeader); + if (it == m_handlers.end()) + { + sys_err("Handshake phase does not handle packet %d (fd %d)", wHeader, d->GetSocket()); + return 0; + } + + return (this->*(it->second))(d, c_pData); +} diff --git a/src/game/input.h b/src/game/input.h index 5c7d347..d09e71b 100644 --- a/src/game/input.h +++ b/src/game/input.h @@ -1,6 +1,7 @@ -#ifndef __INC_METIN_II_GAME_INPUT_PROCESSOR__ +#ifndef __INC_METIN_II_GAME_INPUT_PROCESSOR__ #define __INC_METIN_II_GAME_INPUT_PROCESSOR__ +#include #include "packet_info.h" enum @@ -11,7 +12,6 @@ enum INPROC_MAIN, INPROC_DEAD, INPROC_DB, - INPROC_UDP, INPROC_P2P, INPROC_AUTH, }; @@ -33,11 +33,10 @@ class CInputProcessor void BindPacketInfo(CPacketInfo * pPacketInfo); void Pong(LPDESC d); - void Handshake(LPDESC d, const char * c_pData); void Version(LPCHARACTER ch, const char* c_pData); protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData) = 0; + virtual int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) = 0; CPacketInfo * m_pPacketInfo; int m_iBufferLeft; @@ -48,22 +47,32 @@ class CInputProcessor class CInputClose : public CInputProcessor { public: - virtual BYTE GetType() { return INPROC_CLOSE; } + BYTE GetType() override { return INPROC_CLOSE; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData) { return m_iBufferLeft; } + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override { return m_iBufferLeft; } }; class CInputHandshake : public CInputProcessor { public: CInputHandshake(); - virtual ~CInputHandshake(); + ~CInputHandshake() override; - virtual BYTE GetType() { return INPROC_HANDSHAKE; } + BYTE GetType() override { return INPROC_HANDSHAKE; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override; + + using HSHandler = int (CInputHandshake::*)(LPDESC, const char*); + std::unordered_map m_handlers; + void RegisterHandlers(); + + int HandleText(LPDESC d, const char* c_pData); + int HandleMarkLogin(LPDESC d, const char* c_pData); + int HandleStateChecker(LPDESC d, const char* c_pData); + int HandlePong(LPDESC d, const char* c_pData); + int HandleKeyResponse(LPDESC d, const char* c_pData); protected: void GuildMarkLogin(LPDESC d, const char* c_pData); @@ -74,10 +83,23 @@ class CInputHandshake : public CInputProcessor class CInputLogin : public CInputProcessor { public: - virtual BYTE GetType() { return INPROC_LOGIN; } + CInputLogin(); + BYTE GetType() override { return INPROC_LOGIN; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override; + + using LoginHandler = int (CInputLogin::*)(LPDESC, const char*); + std::unordered_map m_handlers; + void RegisterHandlers(); + + template + int SimpleHandler(LPDESC d, const char* p) { (this->*fn)(d, p); return 0; } + + int HandlePong(LPDESC d, const char*); + int HandleMarkLogin(LPDESC d, const char*); + int HandleGuildSymbolUpload(LPDESC d, const char*); + int HandleVersion(LPDESC d, const char*); protected: void LoginByKey(LPDESC d, const char * data); @@ -100,13 +122,50 @@ class CInputLogin : public CInputProcessor class CInputMain : public CInputProcessor { public: - virtual BYTE GetType() { return INPROC_MAIN; } + CInputMain(); + BYTE GetType() override { return INPROC_MAIN; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override; + + // Handler dispatch + using MainHandler = int (CInputMain::*)(LPDESC, const char*); + struct HandlerEntry { + MainHandler handler; + bool blockInObserverMode; + }; + std::unordered_map m_handlers; + virtual void RegisterHandlers(); + + // Template adapters for common handler patterns (defined in input_main.cpp) + template + int SimpleHandler(LPDESC d, const char* p); + + template + int SimpleHandlerV(LPDESC d, const char* p); + + // Custom adapters for non-standard handler signatures + int HandlePong(LPDESC d, const char* p); + int HandleChat(LPDESC d, const char* p); + int HandleWhisper(LPDESC d, const char* p); + int HandleMove(LPDESC d, const char* p); + int HandleAttack(LPDESC d, const char* p); + int HandleShoot(LPDESC d, const char* p); + int HandleShop(LPDESC d, const char* p); + int HandleMessenger(LPDESC d, const char* p); + int HandleSyncPosition(LPDESC d, const char* p); + int HandleFlyTargeting(LPDESC d, const char* p); + int HandleAddFlyTargeting(LPDESC d, const char* p); + int HandleQuestCancel(LPDESC d, const char* p); + int HandleSafeboxCheckout(LPDESC d, const char* p); + int HandleMallCheckout(LPDESC d, const char* p); + int HandleGuild(LPDESC d, const char* p); + int HandleMyShop(LPDESC d, const char* p); + int HandleClientVersion(LPDESC d, const char* p); + int HandleDragonSoulRefine(LPDESC d, const char* p); protected: - void Attack(LPCHARACTER ch, const BYTE header, const char* data); + void Attack(LPCHARACTER ch, const uint16_t header, const char* data); int Whisper(LPCHARACTER ch, const char * data, size_t uiBytes); int Chat(LPCHARACTER ch, const char * data, size_t uiBytes); @@ -125,9 +184,9 @@ class CInputMain : public CInputProcessor void Position(LPCHARACTER ch, const char * data); void Move(LPCHARACTER ch, const char * data); int SyncPosition(LPCHARACTER ch, const char * data, size_t uiBytes); - void FlyTarget(LPCHARACTER ch, const char * pcData, BYTE bHeader); + void FlyTarget(LPCHARACTER ch, const char * pcData, uint16_t wHeader); void UseSkill(LPCHARACTER ch, const char * pcData); - + void ScriptAnswer(LPCHARACTER ch, const void * pvData); void ScriptButton(LPCHARACTER ch, const void * pvData); void ScriptSelectItem(LPCHARACTER ch, const void * pvData); @@ -152,33 +211,84 @@ class CInputMain : public CInputProcessor int Guild(LPCHARACTER ch, const char * data, size_t uiBytes); void AnswerMakeGuild(LPCHARACTER ch, const char* c_pData); + // Guild sub-handlers (dispatched from Guild()) + int GuildSub_DepositMoney(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_WithdrawMoney(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_AddMember(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_RemoveMember(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_ChangeGradeName(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_ChangeGradeAuthority(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_Offer(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_ChargeGSP(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_PostComment(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_DeleteComment(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_RefreshComment(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_ChangeMemberGrade(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_UseSkill(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_ChangeMemberGeneral(LPCHARACTER ch, const char* data, size_t uiBytes); + int GuildSub_InviteAnswer(LPCHARACTER ch, const char* data, size_t uiBytes); + void Fishing(LPCHARACTER ch, const char* c_pData); void ItemGive(LPCHARACTER ch, const char* c_pData); void Hack(LPCHARACTER ch, const char * c_pData); int MyShop(LPCHARACTER ch, const char * c_pData, size_t uiBytes); void Refine(LPCHARACTER ch, const char* c_pData); - - void Roulette(LPCHARACTER ch, const char* c_pData); }; class CInputDead : public CInputMain { public: - virtual BYTE GetType() { return INPROC_DEAD; } + CInputDead(); + BYTE GetType() override { return INPROC_DEAD; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override; + void RegisterHandlers() override; }; class CInputDB : public CInputProcessor { public: - virtual bool Process(LPDESC d, const void * c_pvOrig, int iBytes, int & r_iBytesProceed); - virtual BYTE GetType() { return INPROC_DB; } + CInputDB(); + bool Process(LPDESC d, const void * c_pvOrig, int iBytes, int & r_iBytesProceed) override; + BYTE GetType() override { return INPROC_DB; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override; + + using DBHandler = int (CInputDB::*)(LPDESC, const char*); + std::unordered_map m_handlers; + void RegisterHandlers(); + LPDESC FindByHandle() const; + + // Template: void handler(const char*) — data-only + template + int DataHandler(LPDESC, const char* p) { (this->*fn)(p); return 0; } + + // Template: void handler(LPDESC, const char*) — desc from FindByHandle + template + int DescHandler(LPDESC, const char* p) { (this->*fn)(FindByHandle(), p); return 0; } + + // Template: void handler(T*) — cast c_pData to typed pointer + template + int TypedHandler(LPDESC, const char* p) { (this->*fn)((T*)p); return 0; } + + // Custom adapters for special signatures + int HandleLoginSuccess(LPDESC, const char*); + int HandleLoginNotExist(LPDESC, const char*); + int HandleLoginWrongPasswd(LPDESC, const char*); + int HandlePlayerCreateFailed(LPDESC, const char*); + int HandlePlayerCreateAlready(LPDESC, const char*); + int HandlePlayerDeleteFail(LPDESC, const char*); + int HandlePlayerLoadFailed(LPDESC, const char*); + int HandleSafeboxWrongPassword(LPDESC, const char*); + int HandleGuildSkillRecharge(LPDESC, const char*); + int HandleGuildWarReserveDelete(LPDESC, const char*); + int HandleSpareItemIDRange(LPDESC, const char*); + int HandleHorseName(LPDESC, const char*); + int HandleMyshopPricelistRes(LPDESC, const char*); + int HandleRespondChannelStatus(LPDESC, const char*); protected: void MapLocations(const char * c_pData); @@ -261,29 +371,15 @@ protected: void WeddingStart(TPacketWeddingStart* p); void WeddingEnd(TPacketWeddingEnd* p); - void TakeMonarchMoney(LPDESC d, const char * data ); - void AddMonarchMoney(LPDESC d, const char * data ); - void DecMonarchMoney(LPDESC d, const char * data ); - void SetMonarch( LPDESC d, const char * data ); - - void ChangeMonarchLord(TPacketChangeMonarchLordACK* data); - void UpdateMonarchInfo(TMonarchInfo* data); - // MYSHOP_PRICE_LIST - /// 아이템 가격정보 리스트 요청에 대한 응답 패킷(HEADER_DG_MYSHOP_PRICELIST_RES) 처리함수 - /** - * @param d 아이템 가격정보 리스트를 요청한 플레이어의 descriptor - * @param p 패킷데이터의 포인터 - */ void MyshopPricelistRes( LPDESC d, const TPacketMyshopPricelistHeader* p ); // END_OF_MYSHOP_PRICE_LIST - // + //RELOAD_ADMIN void ReloadAdmin( const char * c_pData ); //END_RELOAD_ADMIN void DetailLog(const TPacketNeedLoginLogInfo* info); - // 독일 선물 기능 테스트 void ItemAwardInformer(TPacketItemAwardInfromer* data); void RespondChannelStatus(LPDESC desc, const char* pcData); @@ -292,35 +388,32 @@ protected: DWORD m_dwHandle; }; -class CInputUDP : public CInputProcessor -{ - public: - CInputUDP(); - virtual bool Process(LPDESC d, const void * c_pvOrig, int iBytes, int & r_iBytesProceed); - - virtual BYTE GetType() { return INPROC_UDP; } - void SetSockAddr(struct sockaddr_in & rSockAddr) { m_SockAddr = rSockAddr; }; - - protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); - - protected: - void Handshake(LPDESC lpDesc, const char * c_pData); - void StateChecker(const char * c_pData); - - protected: - struct sockaddr_in m_SockAddr; - CPacketInfoUDP m_packetInfoUDP; -}; - class CInputP2P : public CInputProcessor { public: CInputP2P(); - virtual BYTE GetType() { return INPROC_P2P; } + BYTE GetType() override { return INPROC_P2P; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override; + + using P2PHandler = int (CInputP2P::*)(LPDESC, const char*); + std::unordered_map m_handlers; + void RegisterHandlers(); + + template + int DescHandler(LPDESC d, const char* p) { (this->*fn)(d, p); return 0; } + + template + int DataHandler(LPDESC, const char* p) { (this->*fn)(p); return 0; } + + int HandleRelay(LPDESC d, const char*); + int HandleNotice(LPDESC d, const char*); + int HandleGuild(LPDESC d, const char*); + int HandleShutdown(LPDESC d, const char*); + int HandleSiege(LPDESC d, const char*); + int HandleReloadCRC(LPDESC d, const char*); + int HandleCheckClientVersion(LPDESC d, const char*); public: void Setup(LPDESC d, const char * c_pData); @@ -328,14 +421,11 @@ class CInputP2P : public CInputProcessor void Logout(LPDESC d, const char * c_pData); int Relay(LPDESC d, const char * c_pData, size_t uiBytes); int Notice(LPDESC d, const char * c_pData, size_t uiBytes); - int MonarchNotice(LPDESC d, const char * c_pData, size_t uiBytes); - int MonarchTransfer(LPDESC d, const char * c_pData); int Guild(LPDESC d, const char* c_pData, size_t uiBytes); void Shout(const char * c_pData); void Disconnect(const char * c_pData); void MessengerAdd(const char * c_pData); void MessengerRemove(const char * c_pData); - void MessengerMobile(const char * c_pData); void FindPosition(LPDESC d, const char* c_pData); void WarpCharacter(const char* c_pData); void GuildWarZoneMapIndex(const char* c_pData); @@ -357,10 +447,17 @@ class CInputAuth : public CInputProcessor { public: CInputAuth(); - virtual BYTE GetType() { return INPROC_AUTH; } + BYTE GetType() override { return INPROC_AUTH; } protected: - virtual int Analyze(LPDESC d, BYTE bHeader, const char * c_pData); + int Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) override; + + using AuthHandler = int (CInputAuth::*)(LPDESC, const char*); + std::unordered_map m_handlers; + void RegisterHandlers(); + + int HandlePong(LPDESC d, const char*); + int HandleLogin3(LPDESC d, const char*); public: void Login(LPDESC d, const char * c_pData); @@ -368,4 +465,3 @@ class CInputAuth : public CInputProcessor }; #endif /* __INC_METIN_II_GAME_INPUT_PROCESSOR__ */ - diff --git a/src/game/input_auth.cpp b/src/game/input_auth.cpp index 9c1a6fc..6a2bb98 100644 --- a/src/game/input_auth.cpp +++ b/src/game/input_auth.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "config.h" #include "input.h" @@ -150,6 +150,25 @@ bool Login_IsInChannelService(const char* c_login) CInputAuth::CInputAuth() { + RegisterHandlers(); +} + +int CInputAuth::HandlePong(LPDESC d, const char*) +{ + Pong(d); + return 0; +} + +int CInputAuth::HandleLogin3(LPDESC d, const char* c_pData) +{ + Login(d, c_pData); + return 0; +} + +void CInputAuth::RegisterHandlers() +{ + m_handlers[CG::PONG] = &CInputAuth::HandlePong; + m_handlers[CG::LOGIN3] = &CInputAuth::HandleLogin3; } void CInputAuth::Login(LPDESC d, const char * c_pData) @@ -196,7 +215,8 @@ void CInputAuth::Login(LPDESC d, const char * c_pData) { TPacketGCLoginFailure failurePacket; - failurePacket.header = HEADER_GC_LOGIN_FAILURE; + failurePacket.header = GC::LOGIN_FAILURE; + failurePacket.length = sizeof(failurePacket); strlcpy(failurePacket.szStatus, "SHUTDOWN", sizeof(failurePacket.szStatus)); d->Packet(&failurePacket, sizeof(failurePacket)); @@ -259,39 +279,22 @@ void CInputAuth::Login(LPDESC d, const char * c_pData) } } -int CInputAuth::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) +int CInputAuth::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) { - if (!g_bAuthServer) { - sys_err ("CInputAuth class is not for game server. IP %s might be a hacker.", + sys_err ("CInputAuth class is not for game server. IP %s might be a hacker.", inet_ntoa(d->GetAddr().sin_addr)); d->DelayedDisconnect(5); return 0; } - int iExtraLen = 0; - - if (test_server) - sys_log(0, " InputAuth Analyze Header[%d] ", bHeader); - - switch (bHeader) + auto it = m_handlers.find(wHeader); + if (it == m_handlers.end()) { - case HEADER_CG_PONG: - Pong(d); - break; - - case HEADER_CG_LOGIN3: - Login(d, c_pData); - break; - - case HEADER_CG_HANDSHAKE: - break; - - default: - sys_err("This phase does not handle this header %d (0x%x)(phase: AUTH)", bHeader, bHeader); - break; + sys_err("This phase does not handle this header %d (0x%x)(phase: AUTH)", wHeader, wHeader); + return 0; } - return iExtraLen; + return (this->*(it->second))(d, c_pData); } diff --git a/src/game/input_db.cpp b/src/game/input_db.cpp index 49e18c9..2ab8e97 100644 --- a/src/game/input_db.cpp +++ b/src/game/input_db.cpp @@ -1,13 +1,15 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "config.h" #include "utils.h" +#include "desc.h" +#include "desc_client.h" #include "desc_manager.h" #include "char.h" #include "char_manager.h" #include "item.h" #include "item_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "protocol.h" #include "mob_manager.h" #include "shop_manager.h" @@ -24,12 +26,10 @@ #include "priv_manager.h" #include "db.h" #include "building.h" -#include "login_sim.h" #include "wedding.h" #include "login_data.h" #include "unique_item.h" -#include "monarch.h" #include "affect.h" #include "castle.h" #include "motion.h" @@ -106,23 +106,12 @@ bool GetServerLocation(TAccountTable & rTab, BYTE bEmpire) return bFound; } -extern std::map g_sim; -extern std::map g_simByPID; - void CInputDB::LoginSuccess(DWORD dwHandle, const char *data) { sys_log(0, "LoginSuccess"); TAccountTable * pTab = (TAccountTable *) data; - itertype(g_sim) it = g_sim.find(pTab->id); - if (g_sim.end() != it) - { - sys_log(0, "CInputDB::LoginSuccess - already exist sim [%s]", pTab->login); - it->second->SendLoad(); - return; - } - LPDESC d = DESC_MANAGER::instance().FindByHandle(dwHandle); if (!d) @@ -132,7 +121,7 @@ void CInputDB::LoginSuccess(DWORD dwHandle, const char *data) TLogoutPacket pack; strlcpy(pack.login, pTab->login, sizeof(pack.login)); - db_clientdesc->DBPacket(HEADER_GD_LOGOUT, dwHandle, &pack, sizeof(pack)); + db_clientdesc->DBPacket(GD::LOGOUT, dwHandle, &pack, sizeof(pack)); return; } @@ -143,7 +132,7 @@ void CInputDB::LoginSuccess(DWORD dwHandle, const char *data) TLogoutPacket pack; strlcpy(pack.login, pTab->login, sizeof(pack.login)); - db_clientdesc->DBPacket(HEADER_GD_LOGOUT, dwHandle, &pack, sizeof(pack)); + db_clientdesc->DBPacket(GD::LOGOUT, dwHandle, &pack, sizeof(pack)); LoginFailure(d, pTab->status); return; @@ -162,14 +151,16 @@ void CInputDB::LoginSuccess(DWORD dwHandle, const char *data) if (!bFound) // 캐릭터가 없으면 랜덤한 제국으로 보낸다.. -_- { TPacketGCEmpire pe; - pe.bHeader = HEADER_GC_EMPIRE; + pe.header = GC::EMPIRE; + pe.length = sizeof(pe); pe.bEmpire = number(1, 3); d->Packet(&pe, sizeof(pe)); } else { TPacketGCEmpire pe; - pe.bHeader = HEADER_GC_EMPIRE; + pe.header = GC::EMPIRE; + pe.length = sizeof(pe); pe.bEmpire = d->GetEmpire(); d->Packet(&pe, sizeof(pe)); } @@ -187,7 +178,8 @@ void CInputDB::PlayerCreateFailure(LPDESC d, BYTE bType) TPacketGCCreateFailure pack; - pack.header = HEADER_GC_CHARACTER_CREATE_FAILURE; + pack.header = GC::PLAYER_CREATE_FAILURE; + pack.length = sizeof(pack); pack.bType = bType; d->Packet(&pack, sizeof(pack)); @@ -202,7 +194,11 @@ void CInputDB::PlayerCreateSuccess(LPDESC d, const char * data) if (pPacketDB->bAccountCharacterIndex >= PLAYER_PER_ACCOUNT) { - d->Packet(encode_byte(HEADER_GC_CHARACTER_CREATE_FAILURE), 1); + TPacketGCCreateFailure pack; + pack.header = GC::PLAYER_CREATE_FAILURE; + pack.length = sizeof(pack); + pack.bType = 0; + d->Packet(&pack, sizeof(pack)); return; } @@ -225,7 +221,8 @@ void CInputDB::PlayerCreateSuccess(LPDESC d, const char * data) TPacketGCPlayerCreateSuccess pack; - pack.header = HEADER_GC_CHARACTER_CREATE_SUCCESS; + pack.header = GC::PLAYER_CREATE_SUCCESS; + pack.length = sizeof(pack); pack.bAccountCharacterIndex = pPacketDB->bAccountCharacterIndex; pack.player = pPacketDB->player; @@ -277,7 +274,7 @@ void CInputDB::PlayerCreateSuccess(LPDESC d, const char * data) t.pos = initialItems[job][i].pos; t.vnum = initialItems[job][i].dwVnum; - db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_SAVE, 0, sizeof(TPlayerItem)); + db_clientdesc->DBPacketHeader(GD::ITEM_SAVE, 0, sizeof(TPlayerItem)); db_clientdesc->Packet(&t, sizeof(TPlayerItem)); } } @@ -292,8 +289,12 @@ void CInputDB::PlayerDeleteSuccess(LPDESC d, const char * data) BYTE account_index; account_index = decode_byte(data); - d->BufferedPacket(encode_byte(HEADER_GC_CHARACTER_DELETE_SUCCESS), 1); - d->Packet(encode_byte(account_index), 1); + + TPacketGCDestroyCharacterSuccess pack; + pack.header = GC::PLAYER_DELETE_SUCCESS; + pack.length = sizeof(pack); + pack.account_index = account_index; + d->Packet(&pack, sizeof(pack)); d->GetAccountTable().players[account_index].dwID = 0; } @@ -303,10 +304,10 @@ void CInputDB::PlayerDeleteFail(LPDESC d) if (!d) return; - d->Packet(encode_byte(HEADER_GC_CHARACTER_DELETE_WRONG_SOCIAL_ID), 1); - //d->Packet(encode_byte(account_index), 1); - - //d->GetAccountTable().players[account_index].dwID = 0; + TPacketGCBlank pack; + pack.header = GC::PLAYER_DELETE_WRONG_SOCIAL_ID; + pack.length = sizeof(pack); + d->Packet(&pack, sizeof(pack)); } void CInputDB::ChangeName(LPDESC d, const char * data) @@ -329,7 +330,8 @@ void CInputDB::ChangeName(LPDESC d, const char * data) TPacketGCChangeName pgc; - pgc.header = HEADER_GC_CHANGE_NAME; + pgc.header = GC::CHANGE_NAME; + pgc.length = sizeof(pgc); pgc.pid = p->pid; strlcpy(pgc.name, p->name, sizeof(pgc.name)); @@ -409,7 +411,7 @@ void CInputDB::PlayerLoad(LPDESC d, const char * data) // P2P Login TPacketGGLogin p; - p.bHeader = HEADER_GG_LOGIN; + p.header = GG::LOGIN; p.length = sizeof(p); strlcpy(p.szName, ch->GetName(), sizeof(p.szName)); p.dwPID = ch->GetPlayerID(); p.bEmpire = ch->GetEmpire(); @@ -822,35 +824,6 @@ void CInputDB::Boot(const char* data) //END_ADMIN_MANAGER - //MONARCH - data += 2; - data += 2; - - TMonarchInfo& p = *(TMonarchInfo *) data; - data += sizeof(TMonarchInfo); - - CMonarch::instance().SetMonarchInfo(&p); - - for (int n = 1; n < 4; ++n) - { - if (p.name[n] && *p.name[n]) - sys_log(0, "[MONARCH] Empire %d Pid %d Money %d %s", n, p.pid[n], p.money[n], p.name[n]); - } - - int CandidacySize = decode_2bytes(data); - data += 2; - - int CandidacyCount = decode_2bytes(data); - data += 2; - - if (test_server) - sys_log (0, "[MONARCH] Size %d Count %d", CandidacySize, CandidacyCount); - - data += CandidacySize * CandidacyCount; - - - //END_MONARCH - WORD endCheck=decode_2bytes(data); if (endCheck != 0xffff) { @@ -1186,7 +1159,8 @@ void CInputDB::SafeboxWrongPassword(LPDESC d) return; TPacketCGSafeboxWrongPassword p; - p.bHeader = HEADER_GC_SAFEBOX_WRONG_PASSWORD; + p.header = GC::SAFEBOX_WRONG_PASSWORD; + p.length = sizeof(p); d->Packet(&p, sizeof(p)); d->GetCharacter()->CancelSafeboxLoad(); @@ -1247,7 +1221,7 @@ void CInputDB::LoginAlready(LPDESC d, const char * c_pData) { TPacketGGDisconnect pgg; - pgg.bHeader = HEADER_GG_DISCONNECT; + pgg.header = GG::DISCONNECT; pgg.length = sizeof(pgg); strlcpy(pgg.szLogin, p->szLogin, sizeof(pgg.szLogin)); P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGDisconnect)); @@ -1269,7 +1243,8 @@ void CInputDB::EmpireSelect(LPDESC d, const char * c_pData) rTable.bEmpire = *(BYTE *) c_pData; TPacketGCEmpire pe; - pe.bHeader = HEADER_GC_EMPIRE; + pe.header = GC::EMPIRE; + pe.length = sizeof(pe); pe.bEmpire = rTable.bEmpire; d->Packet(&pe, sizeof(pe)); @@ -1710,7 +1685,8 @@ void CInputDB::AuthLogin(LPDESC d, const char * c_pData) TPacketGCAuthSuccess ptoc; - ptoc.bHeader = HEADER_GC_AUTH_SUCCESS; + ptoc.header = GC::AUTH_SUCCESS; + ptoc.length = sizeof(ptoc); if (bResult) { @@ -1761,7 +1737,7 @@ void CInputDB::MoneyLog(const char* c_pData) if (p->type == 4) // QUEST_MONEY_LOG_SKIP return; - if (g_bAuthServer ==true ) + if (g_bAuthServer) return; LogManager::instance().MoneyLog(p->type, p->vnum, p->gold); @@ -1935,465 +1911,245 @@ void CInputDB::ReloadAdmin(const char * c_pData ) } //END_RELOAD_ADMIN +CInputDB::CInputDB() +{ + RegisterHandlers(); +} + +LPDESC CInputDB::FindByHandle() const +{ + return DESC_MANAGER::instance().FindByHandle(m_dwHandle); +} + +int CInputDB::HandleLoginSuccess(LPDESC, const char* c_pData) +{ + LoginSuccess(m_dwHandle, c_pData); + return 0; +} + +int CInputDB::HandleLoginNotExist(LPDESC, const char*) +{ + LoginFailure(FindByHandle(), "NOID"); + return 0; +} + +int CInputDB::HandleLoginWrongPasswd(LPDESC, const char*) +{ + LoginFailure(FindByHandle(), "WRONGPWD"); + return 0; +} + +int CInputDB::HandlePlayerCreateFailed(LPDESC, const char*) +{ + PlayerCreateFailure(FindByHandle(), 0); + return 0; +} + +int CInputDB::HandlePlayerCreateAlready(LPDESC, const char*) +{ + PlayerCreateFailure(FindByHandle(), 1); + return 0; +} + +int CInputDB::HandlePlayerDeleteFail(LPDESC, const char*) +{ + PlayerDeleteFail(FindByHandle()); + return 0; +} + +int CInputDB::HandlePlayerLoadFailed(LPDESC, const char*) +{ + return 0; +} + +int CInputDB::HandleSafeboxWrongPassword(LPDESC, const char*) +{ + SafeboxWrongPassword(FindByHandle()); + return 0; +} + +int CInputDB::HandleGuildSkillRecharge(LPDESC, const char*) +{ + GuildSkillRecharge(); + return 0; +} + +int CInputDB::HandleGuildWarReserveDelete(LPDESC, const char* c_pData) +{ + GuildWarReserveDelete(*(DWORD *) c_pData); + return 0; +} + +int CInputDB::HandleSpareItemIDRange(LPDESC, const char* c_pData) +{ + ITEM_MANAGER::instance().SetMaxSpareItemID(*((TItemIDRangeTable*)c_pData)); + return 0; +} + +int CInputDB::HandleHorseName(LPDESC, const char* c_pData) +{ + CHorseNameManager::instance().UpdateHorseName( + ((TPacketUpdateHorseName*)c_pData)->dwPlayerID, + ((TPacketUpdateHorseName*)c_pData)->szHorseName); + return 0; +} + +int CInputDB::HandleMyshopPricelistRes(LPDESC, const char* c_pData) +{ + MyshopPricelistRes(FindByHandle(), (TPacketMyshopPricelistHeader*) c_pData); + return 0; +} + +int CInputDB::HandleRespondChannelStatus(LPDESC, const char* c_pData) +{ + RespondChannelStatus(FindByHandle(), c_pData); + return 0; +} + +void CInputDB::RegisterHandlers() +{ + // Data-only: void handler(const char*) + m_handlers[DG::BOOT] = &CInputDB::DataHandler<&CInputDB::Boot>; + m_handlers[DG::MAP_LOCATIONS] = &CInputDB::DataHandler<&CInputDB::MapLocations>; + m_handlers[DG::P2P] = &CInputDB::DataHandler<&CInputDB::P2P>; + m_handlers[DG::GUILD_SKILL_UPDATE] = &CInputDB::DataHandler<&CInputDB::GuildSkillUpdate>; + m_handlers[DG::GUILD_LOAD] = &CInputDB::DataHandler<&CInputDB::GuildLoad>; + m_handlers[DG::GUILD_EXP_UPDATE] = &CInputDB::DataHandler<&CInputDB::GuildExpUpdate>; + m_handlers[DG::GUILD_ADD_MEMBER] = &CInputDB::DataHandler<&CInputDB::GuildAddMember>; + m_handlers[DG::GUILD_REMOVE_MEMBER] = &CInputDB::DataHandler<&CInputDB::GuildRemoveMember>; + m_handlers[DG::GUILD_CHANGE_GRADE] = &CInputDB::DataHandler<&CInputDB::GuildChangeGrade>; + m_handlers[DG::GUILD_CHANGE_MEMBER_DATA] = &CInputDB::DataHandler<&CInputDB::GuildChangeMemberData>; + m_handlers[DG::GUILD_DISBAND] = &CInputDB::DataHandler<&CInputDB::GuildDisband>; + m_handlers[DG::GUILD_WAR] = &CInputDB::DataHandler<&CInputDB::GuildWar>; + m_handlers[DG::GUILD_WAR_SCORE] = &CInputDB::DataHandler<&CInputDB::GuildWarScore>; + m_handlers[DG::GUILD_LADDER] = &CInputDB::DataHandler<&CInputDB::GuildLadder>; + m_handlers[DG::GUILD_SKILL_USABLE_CHANGE] = &CInputDB::DataHandler<&CInputDB::GuildSkillUsableChange>; + m_handlers[DG::GUILD_MONEY_CHANGE] = &CInputDB::DataHandler<&CInputDB::GuildMoneyChange>; + m_handlers[DG::GUILD_WITHDRAW_MONEY_GIVE] = &CInputDB::DataHandler<&CInputDB::GuildWithdrawMoney>; + m_handlers[DG::PARTY_CREATE] = &CInputDB::DataHandler<&CInputDB::PartyCreate>; + m_handlers[DG::PARTY_DELETE] = &CInputDB::DataHandler<&CInputDB::PartyDelete>; + m_handlers[DG::PARTY_ADD] = &CInputDB::DataHandler<&CInputDB::PartyAdd>; + m_handlers[DG::PARTY_REMOVE] = &CInputDB::DataHandler<&CInputDB::PartyRemove>; + m_handlers[DG::PARTY_STATE_CHANGE] = &CInputDB::DataHandler<&CInputDB::PartyStateChange>; + m_handlers[DG::PARTY_SET_MEMBER_LEVEL] = &CInputDB::DataHandler<&CInputDB::PartySetMemberLevel>; + m_handlers[DG::TIME] = &CInputDB::DataHandler<&CInputDB::Time>; + m_handlers[DG::RELOAD_PROTO] = &CInputDB::DataHandler<&CInputDB::ReloadProto>; + m_handlers[DG::CHANGE_EMPIRE_PRIV] = &CInputDB::DataHandler<&CInputDB::ChangeEmpirePriv>; + m_handlers[DG::CHANGE_GUILD_PRIV] = &CInputDB::DataHandler<&CInputDB::ChangeGuildPriv>; + m_handlers[DG::CHANGE_CHARACTER_PRIV] = &CInputDB::DataHandler<&CInputDB::ChangeCharacterPriv>; + m_handlers[DG::MONEY_LOG] = &CInputDB::DataHandler<&CInputDB::MoneyLog>; + m_handlers[DG::SET_EVENT_FLAG] = &CInputDB::DataHandler<&CInputDB::SetEventFlag>; + m_handlers[DG::CREATE_OBJECT] = &CInputDB::DataHandler<&CInputDB::CreateObject>; + m_handlers[DG::DELETE_OBJECT] = &CInputDB::DataHandler<&CInputDB::DeleteObject>; + m_handlers[DG::UPDATE_LAND] = &CInputDB::DataHandler<&CInputDB::UpdateLand>; + m_handlers[DG::NOTICE] = &CInputDB::DataHandler<&CInputDB::Notice>; + m_handlers[DG::RELOAD_ADMIN] = &CInputDB::DataHandler<&CInputDB::ReloadAdmin>; + + // Desc handlers: void handler(LPDESC, const char*) where LPDESC = FindByHandle() + m_handlers[DG::LOGIN_ALREADY] = &CInputDB::DescHandler<&CInputDB::LoginAlready>; + m_handlers[DG::PLAYER_LOAD_SUCCESS] = &CInputDB::DescHandler<&CInputDB::PlayerLoad>; + m_handlers[DG::PLAYER_CREATE_SUCCESS] = &CInputDB::DescHandler<&CInputDB::PlayerCreateSuccess>; + m_handlers[DG::PLAYER_DELETE_SUCCESS] = &CInputDB::DescHandler<&CInputDB::PlayerDeleteSuccess>; + m_handlers[DG::ITEM_LOAD] = &CInputDB::DescHandler<&CInputDB::ItemLoad>; + m_handlers[DG::QUEST_LOAD] = &CInputDB::DescHandler<&CInputDB::QuestLoad>; + m_handlers[DG::AFFECT_LOAD] = &CInputDB::DescHandler<&CInputDB::AffectLoad>; + m_handlers[DG::SAFEBOX_LOAD] = &CInputDB::DescHandler<&CInputDB::SafeboxLoad>; + m_handlers[DG::SAFEBOX_CHANGE_SIZE] = &CInputDB::DescHandler<&CInputDB::SafeboxChangeSize>; + m_handlers[DG::SAFEBOX_CHANGE_PASSWORD_ANSWER] = &CInputDB::DescHandler<&CInputDB::SafeboxChangePasswordAnswer>; + m_handlers[DG::MALL_LOAD] = &CInputDB::DescHandler<&CInputDB::MallLoad>; + m_handlers[DG::EMPIRE_SELECT] = &CInputDB::DescHandler<&CInputDB::EmpireSelect>; + m_handlers[DG::CHANGE_NAME] = &CInputDB::DescHandler<&CInputDB::ChangeName>; + m_handlers[DG::AUTH_LOGIN] = &CInputDB::DescHandler<&CInputDB::AuthLogin>; + + // Typed handlers: void handler(T*) -- cast c_pData to typed pointer + m_handlers[DG::GUILD_WAR_RESERVE_ADD] = &CInputDB::TypedHandler; + m_handlers[DG::GUILD_WAR_BET] = &CInputDB::TypedHandler; + m_handlers[DG::MARRIAGE_ADD] = &CInputDB::TypedHandler; + m_handlers[DG::MARRIAGE_UPDATE] = &CInputDB::TypedHandler; + m_handlers[DG::MARRIAGE_REMOVE] = &CInputDB::TypedHandler; + m_handlers[DG::WEDDING_REQUEST] = &CInputDB::TypedHandler; + m_handlers[DG::WEDDING_READY] = &CInputDB::TypedHandler; + m_handlers[DG::WEDDING_START] = &CInputDB::TypedHandler; + m_handlers[DG::WEDDING_END] = &CInputDB::TypedHandler; + m_handlers[DG::ACK_CHANGE_GUILD_MASTER] = &CInputDB::TypedHandler; + m_handlers[DG::NEED_LOGIN_LOG] = &CInputDB::TypedHandler; + m_handlers[DG::ITEMAWARD_INFORMER] = &CInputDB::TypedHandler; + + // Custom adapters for special signatures + m_handlers[DG::LOGIN_SUCCESS] = &CInputDB::HandleLoginSuccess; + m_handlers[DG::LOGIN_NOT_EXIST] = &CInputDB::HandleLoginNotExist; + m_handlers[DG::LOGIN_WRONG_PASSWD] = &CInputDB::HandleLoginWrongPasswd; + m_handlers[DG::PLAYER_CREATE_FAILED] = &CInputDB::HandlePlayerCreateFailed; + m_handlers[DG::PLAYER_CREATE_ALREADY] = &CInputDB::HandlePlayerCreateAlready; + m_handlers[DG::PLAYER_DELETE_FAILED] = &CInputDB::HandlePlayerDeleteFail; + m_handlers[DG::PLAYER_LOAD_FAILED] = &CInputDB::HandlePlayerLoadFailed; + m_handlers[DG::SAFEBOX_WRONG_PASSWORD] = &CInputDB::HandleSafeboxWrongPassword; + m_handlers[DG::GUILD_SKILL_RECHARGE] = &CInputDB::HandleGuildSkillRecharge; + m_handlers[DG::GUILD_WAR_RESERVE_DEL] = &CInputDB::HandleGuildWarReserveDelete; + m_handlers[DG::ACK_SPARE_ITEM_ID_RANGE] = &CInputDB::HandleSpareItemIDRange; + m_handlers[DG::UPDATE_HORSE_NAME] = &CInputDB::HandleHorseName; + m_handlers[DG::ACK_HORSE_NAME] = &CInputDB::HandleHorseName; + m_handlers[DG::MYSHOP_PRICELIST_RES] = &CInputDB::HandleMyshopPricelistRes; + m_handlers[DG::RESPOND_CHANNELSTATUS] = &CInputDB::HandleRespondChannelStatus; +} + //////////////////////////////////////////////////////////////////// // Analyze -// @version 05/06/10 Bang2ni - 아이템 가격정보 리스트 패킷(HEADER_DG_MYSHOP_PRICELIST_RES) 처리루틴 추가. //////////////////////////////////////////////////////////////////// -int CInputDB::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) +int CInputDB::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) { - switch (bHeader) - { - case HEADER_DG_BOOT: - Boot(c_pData); - break; - - case HEADER_DG_LOGIN_SUCCESS: - LoginSuccess(m_dwHandle, c_pData); - break; - - case HEADER_DG_LOGIN_NOT_EXIST: - LoginFailure(DESC_MANAGER::instance().FindByHandle(m_dwHandle), "NOID"); - break; - - case HEADER_DG_LOGIN_WRONG_PASSWD: - LoginFailure(DESC_MANAGER::instance().FindByHandle(m_dwHandle), "WRONGPWD"); - break; - - case HEADER_DG_LOGIN_ALREADY: - LoginAlready(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_PLAYER_LOAD_SUCCESS: - PlayerLoad(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_PLAYER_CREATE_SUCCESS: - PlayerCreateSuccess(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_PLAYER_CREATE_FAILED: - PlayerCreateFailure(DESC_MANAGER::instance().FindByHandle(m_dwHandle), 0); - break; - - case HEADER_DG_PLAYER_CREATE_ALREADY: - PlayerCreateFailure(DESC_MANAGER::instance().FindByHandle(m_dwHandle), 1); - break; - - case HEADER_DG_PLAYER_DELETE_SUCCESS: - PlayerDeleteSuccess(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_PLAYER_LOAD_FAILED: - //sys_log(0, "PLAYER_LOAD_FAILED"); - break; - - case HEADER_DG_PLAYER_DELETE_FAILED: - //sys_log(0, "PLAYER_DELETE_FAILED"); - PlayerDeleteFail(DESC_MANAGER::instance().FindByHandle(m_dwHandle)); - break; - - case HEADER_DG_ITEM_LOAD: - ItemLoad(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_QUEST_LOAD: - QuestLoad(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_AFFECT_LOAD: - AffectLoad(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_SAFEBOX_LOAD: - SafeboxLoad(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_SAFEBOX_CHANGE_SIZE: - SafeboxChangeSize(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_SAFEBOX_WRONG_PASSWORD: - SafeboxWrongPassword(DESC_MANAGER::instance().FindByHandle(m_dwHandle)); - break; - - case HEADER_DG_SAFEBOX_CHANGE_PASSWORD_ANSWER: - SafeboxChangePasswordAnswer(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_MALL_LOAD: - MallLoad(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_EMPIRE_SELECT: - EmpireSelect(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_MAP_LOCATIONS: - MapLocations(c_pData); - break; - - case HEADER_DG_P2P: - P2P(c_pData); - break; - - case HEADER_DG_GUILD_SKILL_UPDATE: - GuildSkillUpdate(c_pData); - break; - - case HEADER_DG_GUILD_LOAD: - GuildLoad(c_pData); - break; - - case HEADER_DG_GUILD_SKILL_RECHARGE: - GuildSkillRecharge(); - break; - - case HEADER_DG_GUILD_EXP_UPDATE: - GuildExpUpdate(c_pData); - break; - - case HEADER_DG_PARTY_CREATE: - PartyCreate(c_pData); - break; - - case HEADER_DG_PARTY_DELETE: - PartyDelete(c_pData); - break; - - case HEADER_DG_PARTY_ADD: - PartyAdd(c_pData); - break; - - case HEADER_DG_PARTY_REMOVE: - PartyRemove(c_pData); - break; - - case HEADER_DG_PARTY_STATE_CHANGE: - PartyStateChange(c_pData); - break; - - case HEADER_DG_PARTY_SET_MEMBER_LEVEL: - PartySetMemberLevel(c_pData); - break; - - case HEADER_DG_TIME: - Time(c_pData); - break; - - case HEADER_DG_GUILD_ADD_MEMBER: - GuildAddMember(c_pData); - break; - - case HEADER_DG_GUILD_REMOVE_MEMBER: - GuildRemoveMember(c_pData); - break; - - case HEADER_DG_GUILD_CHANGE_GRADE: - GuildChangeGrade(c_pData); - break; - - case HEADER_DG_GUILD_CHANGE_MEMBER_DATA: - GuildChangeMemberData(c_pData); - break; - - case HEADER_DG_GUILD_DISBAND: - GuildDisband(c_pData); - break; - - case HEADER_DG_RELOAD_PROTO: - ReloadProto(c_pData); - break; - - case HEADER_DG_GUILD_WAR: - GuildWar(c_pData); - break; - - case HEADER_DG_GUILD_WAR_SCORE: - GuildWarScore(c_pData); - break; - - case HEADER_DG_GUILD_LADDER: - GuildLadder(c_pData); - break; - - case HEADER_DG_GUILD_SKILL_USABLE_CHANGE: - GuildSkillUsableChange(c_pData); - break; - - case HEADER_DG_CHANGE_NAME: - ChangeName(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_AUTH_LOGIN: - AuthLogin(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - case HEADER_DG_CHANGE_EMPIRE_PRIV: - ChangeEmpirePriv(c_pData); - break; - - case HEADER_DG_CHANGE_GUILD_PRIV: - ChangeGuildPriv(c_pData); - break; - - case HEADER_DG_CHANGE_CHARACTER_PRIV: - ChangeCharacterPriv(c_pData); - break; - - case HEADER_DG_MONEY_LOG: - MoneyLog(c_pData); - break; - - case HEADER_DG_GUILD_WITHDRAW_MONEY_GIVE: - GuildWithdrawMoney(c_pData); - break; - - case HEADER_DG_GUILD_MONEY_CHANGE: - GuildMoneyChange(c_pData); - break; - - case HEADER_DG_SET_EVENT_FLAG: - SetEventFlag(c_pData); - break; - - case HEADER_DG_CREATE_OBJECT: - CreateObject(c_pData); - break; - - case HEADER_DG_DELETE_OBJECT: - DeleteObject(c_pData); - break; - - case HEADER_DG_UPDATE_LAND: - UpdateLand(c_pData); - break; - - case HEADER_DG_NOTICE: - Notice(c_pData); - break; - - case HEADER_DG_GUILD_WAR_RESERVE_ADD: - GuildWarReserveAdd((TGuildWarReserve *) c_pData); - break; - - case HEADER_DG_GUILD_WAR_RESERVE_DEL: - GuildWarReserveDelete(*(DWORD *) c_pData); - break; - - case HEADER_DG_GUILD_WAR_BET: - GuildWarBet((TPacketGDGuildWarBet *) c_pData); - break; - - case HEADER_DG_MARRIAGE_ADD: - MarriageAdd((TPacketMarriageAdd*) c_pData); - break; - - case HEADER_DG_MARRIAGE_UPDATE: - MarriageUpdate((TPacketMarriageUpdate*) c_pData); - break; - - case HEADER_DG_MARRIAGE_REMOVE: - MarriageRemove((TPacketMarriageRemove*) c_pData); - break; - - case HEADER_DG_WEDDING_REQUEST: - WeddingRequest((TPacketWeddingRequest*) c_pData); - break; - - case HEADER_DG_WEDDING_READY: - WeddingReady((TPacketWeddingReady*) c_pData); - break; - - case HEADER_DG_WEDDING_START: - WeddingStart((TPacketWeddingStart*) c_pData); - break; - - case HEADER_DG_WEDDING_END: - WeddingEnd((TPacketWeddingEnd*) c_pData); - break; - - // MYSHOP_PRICE_LIST - case HEADER_DG_MYSHOP_PRICELIST_RES: - MyshopPricelistRes(DESC_MANAGER::instance().FindByHandle(m_dwHandle), (TPacketMyshopPricelistHeader*) c_pData ); - break; - // END_OF_MYSHOP_PRICE_LIST - // - // RELOAD_ADMIN - case HEADER_DG_RELOAD_ADMIN: - ReloadAdmin(c_pData ); - break; - //END_RELOAD_ADMIN - - case HEADER_DG_ADD_MONARCH_MONEY: - AddMonarchMoney(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData ); - break; - - case HEADER_DG_DEC_MONARCH_MONEY: - DecMonarchMoney(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData ); - break; - - case HEADER_DG_TAKE_MONARCH_MONEY: - TakeMonarchMoney(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData ); - break; - - case HEADER_DG_CHANGE_MONARCH_LORD_ACK : - ChangeMonarchLord((TPacketChangeMonarchLordACK*)c_pData); - break; - - case HEADER_DG_UPDATE_MONARCH_INFO : - UpdateMonarchInfo((TMonarchInfo*)c_pData); - break; - - case HEADER_DG_ACK_CHANGE_GUILD_MASTER : - this->GuildChangeMaster((TPacketChangeGuildMaster*) c_pData); - break; - case HEADER_DG_ACK_SPARE_ITEM_ID_RANGE : - ITEM_MANAGER::instance().SetMaxSpareItemID(*((TItemIDRangeTable*)c_pData) ); - break; - - case HEADER_DG_UPDATE_HORSE_NAME : - case HEADER_DG_ACK_HORSE_NAME : - CHorseNameManager::instance().UpdateHorseName( - ((TPacketUpdateHorseName*)c_pData)->dwPlayerID, - ((TPacketUpdateHorseName*)c_pData)->szHorseName); - break; - - case HEADER_DG_NEED_LOGIN_LOG: - DetailLog( (TPacketNeedLoginLogInfo*) c_pData ); - break; - // 독일 선물 기능 테스트 - case HEADER_DG_ITEMAWARD_INFORMER: - ItemAwardInformer((TPacketItemAwardInfromer*) c_pData); - break; - case HEADER_DG_RESPOND_CHANNELSTATUS: - RespondChannelStatus(DESC_MANAGER::instance().FindByHandle(m_dwHandle), c_pData); - break; - - default: + auto it = m_handlers.find(wHeader); + if (it == m_handlers.end()) return (-1); - } - return 0; + return (this->*(it->second))(d, c_pData); } bool CInputDB::Process(LPDESC d, const void * orig, int bytes, int & r_iBytesProceed) { const char * c_pData = (const char *) orig; - BYTE bHeader, bLastHeader = 0; + uint16_t wHeader, wLastHeader = 0; int iSize; int iLastPacketLen = 0; + static constexpr int FRAME_SIZE = 10; // header(2) + handle(4) + size(4) + for (m_iBufferLeft = bytes; m_iBufferLeft > 0;) { - if (m_iBufferLeft < 9) + if (m_iBufferLeft < FRAME_SIZE) return true; - bHeader = *((BYTE *) (c_pData)); // 1 - m_dwHandle = *((DWORD *) (c_pData + 1)); // 4 - iSize = *((DWORD *) (c_pData + 5)); // 4 + wHeader = *((uint16_t *) (c_pData)); // 2 + m_dwHandle = *((DWORD *) (c_pData + 2)); // 4 + iSize = *((DWORD *) (c_pData + 6)); // 4 - sys_log(1, "DBCLIENT: header %d handle %d size %d bytes %d", bHeader, m_dwHandle, iSize, bytes); + sys_log(1, "DBCLIENT: header %u handle %u size %d bytes %d", wHeader, m_dwHandle, iSize, bytes); - if (m_iBufferLeft - 9 < iSize) + if (m_iBufferLeft - FRAME_SIZE < iSize) return true; - const char * pRealData = (c_pData + 9); + const char * pRealData = (c_pData + FRAME_SIZE); - if (Analyze(d, bHeader, pRealData) < 0) + if (Analyze(d, wHeader, pRealData) < 0) { - sys_err("in InputDB: UNKNOWN HEADER: %d, LAST HEADER: %d(%d), REMAIN BYTES: %d, DESC: %d", - bHeader, bLastHeader, iLastPacketLen, m_iBufferLeft, d->GetSocket()); + sys_err("in InputDB: UNKNOWN HEADER: %u, LAST HEADER: %u(%d), REMAIN BYTES: %d, DESC: %d", + wHeader, wLastHeader, iLastPacketLen, m_iBufferLeft, d->GetSocket()); //printdata((BYTE*) orig, bytes); //d->SetPhase(PHASE_CLOSE); } - c_pData += 9 + iSize; - m_iBufferLeft -= 9 + iSize; - r_iBytesProceed += 9 + iSize; + c_pData += FRAME_SIZE + iSize; + m_iBufferLeft -= FRAME_SIZE + iSize; + r_iBytesProceed += FRAME_SIZE + iSize; - iLastPacketLen = 9 + iSize; - bLastHeader = bHeader; + iLastPacketLen = FRAME_SIZE + iSize; + wLastHeader = wHeader; } return true; } -void CInputDB::AddMonarchMoney(LPDESC d, const char * data ) -{ - int Empire = *(int *) data; - data += sizeof(int); - - int Money = *(int *) data; - data += sizeof(int); - - CMonarch::instance().AddMoney(Money, Empire); - - DWORD pid = CMonarch::instance().GetMonarchPID(Empire); - - LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pid); - - if (ch) - { - if (number(1, 100) > 95) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("현재 %s 국고에는 %u 의 돈이 있습니다"), EMPIRE_NAME(Empire), CMonarch::instance().GetMoney(Empire)); - } -} - -void CInputDB::DecMonarchMoney(LPDESC d, const char * data) -{ - int Empire = *(int *) data; - data += sizeof(int); - - int Money = *(int *) data; - data += sizeof(int); - - CMonarch::instance().DecMoney(Money, Empire); - - DWORD pid = CMonarch::instance().GetMonarchPID(Empire); - - LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pid); - - if (ch) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("현재 %s 국고에는 %d 의 돈이 있습니다"), EMPIRE_NAME(Empire), CMonarch::instance().GetMoney(Empire)); - } -} - -void CInputDB::TakeMonarchMoney(LPDESC d, const char * data) -{ - int Empire = *(int *) data; - data += sizeof(int); - - int Money = *(int *) data; - data += sizeof(int); - - if (!CMonarch::instance().DecMoney(Money, Empire)) - { - if (!d) - return; - - if (!d->GetCharacter()) - return; - - LPCHARACTER ch = d->GetCharacter(); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족하거나 돈을 가져올수 없는 상황입니다")); - } -} - -void CInputDB::ChangeMonarchLord(TPacketChangeMonarchLordACK* info) -{ - char notice[256]; - snprintf(notice, sizeof(notice), LC_TEXT("%s의 군주가 %s 님으로 교체되었습니다."), EMPIRE_NAME(info->bEmpire), info->szName); - SendNotice(notice); -} - -void CInputDB::UpdateMonarchInfo(TMonarchInfo* info) -{ - CMonarch::instance().SetMonarchInfo(info); - sys_log(0, "MONARCH INFO UPDATED"); -} - void CInputDB::GuildChangeMaster(TPacketChangeGuildMaster* p) { CGuildManager::instance().ChangeMaster(p->dwGuildID); @@ -2442,8 +2198,10 @@ void CInputDB::RespondChannelStatus(LPDESC desc, const char* pcData) const int nSize = decode_4bytes(pcData); pcData += sizeof(nSize); - BYTE bHeader = HEADER_GC_RESPOND_CHANNELSTATUS; - desc->BufferedPacket(&bHeader, sizeof(BYTE)); + TPacketGCBlank packHeader; + packHeader.header = GC::RESPOND_CHANNELSTATUS; + packHeader.length = sizeof(packHeader) + sizeof(nSize) + sizeof(TChannelStatus) * nSize + sizeof(BYTE); + desc->BufferedPacket(&packHeader, sizeof(packHeader)); desc->BufferedPacket(&nSize, sizeof(nSize)); if (0 < nSize) { desc->BufferedPacket(pcData, sizeof(TChannelStatus)*nSize); diff --git a/src/game/input_login.cpp b/src/game/input_login.cpp index b7a441f..c6f7d35 100644 --- a/src/game/input_login.cpp +++ b/src/game/input_login.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "config.h" #include "utils.h" @@ -91,7 +91,8 @@ void CInputLogin::LoginByKey(LPDESC d, const char * data) { TPacketGCLoginFailure failurePacket; - failurePacket.header = HEADER_GC_LOGIN_FAILURE; + failurePacket.header = GC::LOGIN_FAILURE; + failurePacket.length = sizeof(failurePacket); strlcpy(failurePacket.szStatus, "SHUTDOWN", sizeof(failurePacket.szStatus)); d->Packet(&failurePacket, sizeof(TPacketGCLoginFailure)); return; @@ -109,7 +110,8 @@ void CInputLogin::LoginByKey(LPDESC d, const char * data) { TPacketGCLoginFailure failurePacket; - failurePacket.header = HEADER_GC_LOGIN_FAILURE; + failurePacket.header = GC::LOGIN_FAILURE; + failurePacket.length = sizeof(failurePacket); strlcpy(failurePacket.szStatus, "FULL", sizeof(failurePacket.szStatus)); d->Packet(&failurePacket, sizeof(TPacketGCLoginFailure)); @@ -127,7 +129,7 @@ void CInputLogin::LoginByKey(LPDESC d, const char * data) ptod.dwLoginKey = pinfo->dwLoginKey; strlcpy(ptod.szIP, d->GetHostName(), sizeof(ptod.szIP)); - db_clientdesc->DBPacket(HEADER_GD_LOGIN_BY_KEY, d->GetHandle(), &ptod, sizeof(TPacketGDLoginByKey)); + db_clientdesc->DBPacket(GD::LOGIN_BY_KEY, d->GetHandle(), &ptod, sizeof(TPacketGDLoginByKey)); } void CInputLogin::ChangeName(LPDESC d, const char * data) @@ -153,7 +155,8 @@ void CInputLogin::ChangeName(LPDESC d, const char * data) if (!check_name(p->name)) { TPacketGCCreateFailure pack; - pack.header = HEADER_GC_CHARACTER_CREATE_FAILURE; + pack.header = GC::PLAYER_CREATE_FAILURE; + pack.length = sizeof(pack); pack.bType = 0; d->Packet(&pack, sizeof(pack)); return; @@ -163,7 +166,7 @@ void CInputLogin::ChangeName(LPDESC d, const char * data) pdb.pid = c_r.players[p->index].dwID; strlcpy(pdb.name, p->name, sizeof(pdb.name)); - db_clientdesc->DBPacket(HEADER_GD_CHANGE_NAME, d->GetHandle(), &pdb, sizeof(TPacketGDChangeName)); + db_clientdesc->DBPacket(GD::CHANGE_NAME, d->GetHandle(), &pdb, sizeof(TPacketGDChangeName)); } void CInputLogin::CharacterSelect(LPDESC d, const char * data) @@ -205,7 +208,7 @@ void CInputLogin::CharacterSelect(LPDESC d, const char * data) player_load_packet.player_id = c_r.players[pinfo->index].dwID; player_load_packet.account_index = pinfo->index; - db_clientdesc->DBPacket(HEADER_GD_PLAYER_LOAD, d->GetHandle(), &player_load_packet, sizeof(TPlayerLoadPacket)); + db_clientdesc->DBPacket(GD::PLAYER_LOAD, d->GetHandle(), &player_load_packet, sizeof(TPlayerLoadPacket)); } bool NewPlayerTable(TPlayerTable * table, @@ -380,7 +383,8 @@ void CInputLogin::CharacterCreate(LPDESC d, const char * data) TPacketGCLoginFailure packFailure; memset(&packFailure, 0, sizeof(packFailure)); - packFailure.header = HEADER_GC_CHARACTER_CREATE_FAILURE; + packFailure.header = GC::PLAYER_CREATE_FAILURE; + packFailure.length = sizeof(packFailure); if (true == g_BlockCharCreation) { @@ -401,7 +405,8 @@ void CInputLogin::CharacterCreate(LPDESC d, const char * data) if (LC_IsCanada() == true) { TPacketGCCreateFailure pack; - pack.header = HEADER_GC_CHARACTER_CREATE_FAILURE; + pack.header = GC::PLAYER_CREATE_FAILURE; + pack.length = sizeof(pack); pack.bType = 1; d->Packet(&pack, sizeof(pack)); @@ -419,7 +424,8 @@ void CInputLogin::CharacterCreate(LPDESC d, const char * data) if (0 == strcmp(c_rAccountTable.login, pinfo->name)) { TPacketGCCreateFailure pack; - pack.header = HEADER_GC_CHARACTER_CREATE_FAILURE; + pack.header = GC::PLAYER_CREATE_FAILURE; + pack.length = sizeof(pack); pack.bType = 1; d->Packet(&pack, sizeof(pack)); @@ -450,7 +456,7 @@ void CInputLogin::CharacterCreate(LPDESC d, const char * data) sizeof(TPlayerCreatePacket), player_create_packet.player_table.gold); - db_clientdesc->DBPacket(HEADER_GD_PLAYER_CREATE, d->GetHandle(), &player_create_packet, sizeof(TPlayerCreatePacket)); + db_clientdesc->DBPacket(GD::PLAYER_CREATE, d->GetHandle(), &player_create_packet, sizeof(TPlayerCreatePacket)); } void CInputLogin::CharacterDelete(LPDESC d, const char * data) @@ -475,7 +481,10 @@ void CInputLogin::CharacterDelete(LPDESC d, const char * data) if (!c_rAccountTable.players[pinfo->index].dwID) { sys_err("PlayerDelete: Wrong Social ID index %d, login: %s", pinfo->index, c_rAccountTable.login); - d->Packet(encode_byte(HEADER_GC_CHARACTER_DELETE_WRONG_SOCIAL_ID), 1); + TPacketGCBlank pack_wrong; + pack_wrong.header = GC::PLAYER_DELETE_WRONG_SOCIAL_ID; + pack_wrong.length = sizeof(pack_wrong); + d->Packet(&pack_wrong, sizeof(pack_wrong)); return; } @@ -486,18 +495,9 @@ void CInputLogin::CharacterDelete(LPDESC d, const char * data) player_delete_packet.account_index = pinfo->index; strlcpy(player_delete_packet.private_code, pinfo->private_code, sizeof(player_delete_packet.private_code)); - db_clientdesc->DBPacket(HEADER_GD_PLAYER_DELETE, d->GetHandle(), &player_delete_packet, sizeof(TPlayerDeletePacket)); + db_clientdesc->DBPacket(GD::PLAYER_DELETE, d->GetHandle(), &player_delete_packet, sizeof(TPlayerDeletePacket)); } -#pragma pack(1) -typedef struct SPacketGTLogin -{ - BYTE header; - WORD empty; - DWORD id; -} TPacketGTLogin; -#pragma pack() - void CInputLogin::Entergame(LPDESC d, const char * data) { LPCHARACTER ch; @@ -566,12 +566,14 @@ void CInputLogin::Entergame(LPDESC d, const char * data) marriage::CManager::instance().Login(ch); TPacketGCTime p; - p.bHeader = HEADER_GC_TIME; + p.header = GC::TIME; + p.length = sizeof(p); p.time = get_global_time(); d->Packet(&p, sizeof(p)); TPacketGCChannel p2; - p2.header = HEADER_GC_CHANNEL; + p2.header = GC::CHANNEL; + p2.length = sizeof(p2); p2.channel = g_bChannel; d->Packet(&p2, sizeof(p2)); @@ -588,53 +590,41 @@ void CInputLogin::Entergame(LPDESC d, const char * data) sys_log(0, "PREMIUM: %s type %d %dmin", ch->GetName(), i, remain); } - if (LC_IsEurope()) + if (g_bCheckClientVersion) { - if (g_bCheckClientVersion) + int version = atoi(g_stClientVersion.c_str()); + int date = atoi(d->GetClientVersion()); + + sys_log(0, "VERSION CHECK %d %d %s %s", version, date, g_stClientVersion.c_str(), d->GetClientVersion()); + + if (!d->GetClientVersion()) { - int version = atoi(g_stClientVersion.c_str()); - int date = atoi(d->GetClientVersion()); - - sys_log(0, "VERSION CHECK %d %d %s %s", version, date, g_stClientVersion.c_str(), d->GetClientVersion()); - - if (!d->GetClientVersion()) - { - d->DelayedDisconnect(10); - } - else - { - //if (0 != g_stClientVersion.compare(d->GetClientVersion())) - // if (version > date) - if (version != date) // Fix - { - ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요.")); - d->DelayedDisconnect(10); - LogManager::instance().HackLog("VERSION_CONFLICT", ch); - - sys_log(0, "VERSION : WRONG VERSION USER : account:%s name:%s hostName:%s server_version:%s client_version:%s", - d->GetAccountTable().login, - ch->GetName(), - d->GetHostName(), - g_stClientVersion.c_str(), - d->GetClientVersion()); - } - } + d->DelayedDisconnect(10); } else { - sys_log(0, "VERSION : NO CHECK"); + if (version != date) + { + ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요.")); + d->DelayedDisconnect(10); + LogManager::instance().HackLog("VERSION_CONFLICT", ch); + + sys_log(0, "VERSION : WRONG VERSION USER : account:%s name:%s hostName:%s server_version:%s client_version:%s", + d->GetAccountTable().login, + ch->GetName(), + d->GetHostName(), + g_stClientVersion.c_str(), + d->GetClientVersion()); + } } } else { - sys_log(0, "VERSION : NO LOGIN"); + sys_log(0, "VERSION : NO CHECK"); } - if (LC_IsEurope() == true) - { - if (ch->IsGM() == true) - ch->ChatPacket(CHAT_TYPE_COMMAND, "ConsoleEnable"); - } + if (ch->IsGM()) + ch->ChatPacket(CHAT_TYPE_COMMAND, "ConsoleEnable"); if (ch->GetMapIndex() >= 10000) { @@ -688,8 +678,8 @@ void CInputLogin::Entergame(LPDESC d, const char * data) else if (memberFlag == MEMBER_DUELIST) { TPacketGCDuelStart duelStart; - duelStart.header = HEADER_GC_DUEL_START; - duelStart.wSize = sizeof(TPacketGCDuelStart); + duelStart.header = GC::DUEL_START; + duelStart.length = sizeof(TPacketGCDuelStart); ch->GetDesc()->Packet(&duelStart, sizeof(TPacketGCDuelStart)); @@ -747,7 +737,7 @@ void CInputLogin::Entergame(LPDESC d, const char * data) DWORD pid = ch->GetPlayerID(); if (pid != 0 && CHorseNameManager::instance().GetHorseName(pid) == NULL) - db_clientdesc->DBPacket(HEADER_GD_REQ_HORSE_NAME, 0, &pid, sizeof(DWORD)); + db_clientdesc->DBPacket(GD::REQ_HORSE_NAME, 0, &pid, sizeof(DWORD)); } // 중립맵에 들어갔을때 안내하기 @@ -791,7 +781,7 @@ void CInputLogin::Empire(LPDESC d, const char * c_pData) pd.dwAccountID = r.id; pd.bEmpire = p->bEmpire; - db_clientdesc->DBPacket(HEADER_GD_EMPIRE_SELECT, d->GetHandle(), &pd, sizeof(pd)); + db_clientdesc->DBPacket(GD::EMPIRE_SELECT, d->GetHandle(), &pd, sizeof(pd)); } int CInputLogin::GuildSymbolUpload(LPDESC d, const char* c_pData, size_t uiBytes) @@ -803,10 +793,10 @@ int CInputLogin::GuildSymbolUpload(LPDESC d, const char* c_pData, size_t uiBytes TPacketCGGuildSymbolUpload* p = (TPacketCGGuildSymbolUpload*) c_pData; - if (uiBytes < p->size) + if (uiBytes < p->length) return -1; - int iSymbolSize = p->size - sizeof(TPacketCGGuildSymbolUpload); + int iSymbolSize = p->length - sizeof(TPacketCGGuildSymbolUpload); if (iSymbolSize <= 0 || iSymbolSize > 64 * 1024) { @@ -835,7 +825,7 @@ void CInputLogin::GuildSymbolCRC(LPDESC d, const char* c_pData) { const TPacketCGSymbolCRC & CGPacket = *((TPacketCGSymbolCRC *) c_pData); - sys_log(0, "GuildSymbolCRC %u %u %u", CGPacket.guild_id, CGPacket.crc, CGPacket.size); + sys_log(0, "GuildSymbolCRC %u %u %u", CGPacket.guild_id, CGPacket.crc, CGPacket.length); const CGuildMarkManager::TGuildSymbol * pkGS = CGuildMarkManager::instance().GetGuildSymbol(CGPacket.guild_id); @@ -844,12 +834,12 @@ void CInputLogin::GuildSymbolCRC(LPDESC d, const char* c_pData) sys_log(0, " Server %u %u", pkGS->crc, pkGS->raw.size()); - if (pkGS->raw.size() != CGPacket.size || pkGS->crc != CGPacket.crc) + if (pkGS->raw.size() != CGPacket.length || pkGS->crc != CGPacket.crc) { TPacketGCGuildSymbolData GCPacket; - GCPacket.header = HEADER_GC_SYMBOL_DATA; - GCPacket.size = sizeof(GCPacket) + pkGS->raw.size(); + GCPacket.header = GC::SYMBOL_DATA; + GCPacket.length = sizeof(GCPacket) + pkGS->raw.size(); GCPacket.guild_id = CGPacket.guild_id; d->BufferedPacket(&GCPacket, sizeof(GCPacket)); @@ -902,7 +892,8 @@ void CInputLogin::GuildMarkUpload(LPDESC d, const char* c_pData) // Send P2P packet to all other game cores TPacketGGMarkUpdate p2pPacket; - p2pPacket.bHeader = HEADER_GG_MARK_UPDATE; + p2pPacket.header = GG::MARK_UPDATE; + p2pPacket.length = sizeof(p2pPacket); p2pPacket.dwGuildID = p->gid; p2pPacket.wImgIdx = imgIdx; P2P_MANAGER::instance().Send(&p2pPacket, sizeof(p2pPacket)); @@ -928,7 +919,8 @@ void CInputLogin::GuildMarkIDXList(LPDESC d, const char* c_pData) } TPacketGCMarkIDXList p; - p.header = HEADER_GC_MARK_IDXLIST; + p.header = GC::MARK_IDXLIST; + p.length = sizeof(p); p.bufSize = sizeof(p) + bufSize; p.count = rkMarkMgr.GetMarkCount(); @@ -968,7 +960,8 @@ void CInputLogin::GuildMarkCRCList(LPDESC d, const char* c_pData) TPacketGCMarkBlock pGC; - pGC.header = HEADER_GC_MARK_BLOCK; + pGC.header = GC::MARK_BLOCK; + pGC.length = sizeof(pGC); pGC.imgIdx = pCG->imgIdx; pGC.bufSize = buf.size() + sizeof(TPacketGCMarkBlock); pGC.count = blockCount; @@ -984,99 +977,71 @@ void CInputLogin::GuildMarkCRCList(LPDESC d, const char* c_pData) d->Packet(&pGC, sizeof(TPacketGCMarkBlock)); } -int CInputLogin::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) + +CInputLogin::CInputLogin() { - int iExtraLen = 0; - - switch (bHeader) - { - case HEADER_CG_PONG: - Pong(d); - break; - - case HEADER_CG_TIME_SYNC: - Handshake(d, c_pData); - break; - - case HEADER_CG_LOGIN2: - LoginByKey(d, c_pData); - break; - - case HEADER_CG_CHARACTER_SELECT: - CharacterSelect(d, c_pData); - break; - - case HEADER_CG_CHARACTER_CREATE: - CharacterCreate(d, c_pData); - break; - - case HEADER_CG_CHARACTER_DELETE: - CharacterDelete(d, c_pData); - break; - - case HEADER_CG_ENTERGAME: - Entergame(d, c_pData); - break; - - case HEADER_CG_EMPIRE: - Empire(d, c_pData); - break; - - case HEADER_CG_MOVE: - break; - - /////////////////////////////////////// - // Guild Mark - ///////////////////////////////////// - case HEADER_CG_MARK_CRCLIST: - GuildMarkCRCList(d, c_pData); - break; - - case HEADER_CG_MARK_IDXLIST: - GuildMarkIDXList(d, c_pData); - break; - - case HEADER_CG_MARK_UPLOAD: - GuildMarkUpload(d, c_pData); - break; - - ////////////////////////////////////// - // Guild Symbol - ///////////////////////////////////// - case HEADER_CG_GUILD_SYMBOL_UPLOAD: - if ((iExtraLen = GuildSymbolUpload(d, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_CG_SYMBOL_CRC: - GuildSymbolCRC(d, c_pData); - break; - ///////////////////////////////////// - - case HEADER_CG_MARK_LOGIN: - break; - - case HEADER_CG_HACK: - break; - - case HEADER_CG_CHANGE_NAME: - ChangeName(d, c_pData); - break; - - case HEADER_CG_CLIENT_VERSION: - Version(d->GetCharacter(), c_pData); - break; - - case HEADER_CG_CLIENT_VERSION2: - Version(d->GetCharacter(), c_pData); - break; - - default: - sys_err("login phase does not handle this packet! header %d", bHeader); - //d->SetPhase(PHASE_CLOSE); - return (0); - } - - return (iExtraLen); + RegisterHandlers(); } +int CInputLogin::HandlePong(LPDESC d, const char*) +{ + Pong(d); + return 0; +} + +int CInputLogin::HandleMarkLogin(LPDESC d, const char*) +{ + extern bool guild_mark_server; + if (!guild_mark_server) + { + sys_err("Guild Mark login requested but i'm not a mark server!"); + d->SetPhase(PHASE_CLOSE); + return 0; + } + + sys_log(0, "MARK_SERVER: Login (from LOGIN phase)"); + // Already in LOGIN phase — no phase change needed + return 0; +} + +int CInputLogin::HandleGuildSymbolUpload(LPDESC d, const char* c_pData) +{ + return GuildSymbolUpload(d, c_pData, m_iBufferLeft); +} + +int CInputLogin::HandleVersion(LPDESC d, const char* c_pData) +{ + Version(d->GetCharacter(), c_pData); + return 0; +} + +void CInputLogin::RegisterHandlers() +{ + m_handlers[CG::PONG] = &CInputLogin::HandlePong; + m_handlers[CG::MARK_LOGIN] = &CInputLogin::HandleMarkLogin; + m_handlers[CG::LOGIN2] = &CInputLogin::SimpleHandler<&CInputLogin::LoginByKey>; + m_handlers[CG::CHARACTER_SELECT] = &CInputLogin::SimpleHandler<&CInputLogin::CharacterSelect>; + m_handlers[CG::CHARACTER_CREATE] = &CInputLogin::SimpleHandler<&CInputLogin::CharacterCreate>; + m_handlers[CG::CHARACTER_DELETE] = &CInputLogin::SimpleHandler<&CInputLogin::CharacterDelete>; + m_handlers[CG::ENTERGAME] = &CInputLogin::SimpleHandler<&CInputLogin::Entergame>; + m_handlers[CG::EMPIRE] = &CInputLogin::SimpleHandler<&CInputLogin::Empire>; + m_handlers[CG::MARK_CRCLIST] = &CInputLogin::SimpleHandler<&CInputLogin::GuildMarkCRCList>; + m_handlers[CG::MARK_IDXLIST] = &CInputLogin::SimpleHandler<&CInputLogin::GuildMarkIDXList>; + m_handlers[CG::MARK_UPLOAD] = &CInputLogin::SimpleHandler<&CInputLogin::GuildMarkUpload>; + m_handlers[CG::GUILD_SYMBOL_UPLOAD]= &CInputLogin::HandleGuildSymbolUpload; + m_handlers[CG::SYMBOL_CRC] = &CInputLogin::SimpleHandler<&CInputLogin::GuildSymbolCRC>; + m_handlers[CG::CHANGE_NAME] = &CInputLogin::SimpleHandler<&CInputLogin::ChangeName>; + m_handlers[CG::CLIENT_VERSION] = &CInputLogin::HandleVersion; +} + +int CInputLogin::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) +{ + auto it = m_handlers.find(wHeader); + if (it == m_handlers.end()) + { + sys_err("CInputLogin::Analyze: unknown header %d (0x%04X) from %s", wHeader, wHeader, d->GetHostName()); + return 0; + } + + return (this->*(it->second))(d, c_pData); +} diff --git a/src/game/input_main.cpp b/src/game/input_main.cpp index 1c9e414..ea84b73 100644 --- a/src/game/input_main.cpp +++ b/src/game/input_main.cpp @@ -1,11 +1,11 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "config.h" #include "utils.h" #include "desc_client.h" #include "desc_manager.h" #include "buffer_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "protocol.h" #include "char.h" #include "char_manager.h" @@ -43,6 +43,21 @@ extern void SendShout(const char * szText, BYTE bEmpire); extern int g_nPortalLimitTime; +// Template adapter definitions (declared in input.h, defined here where DESC is complete) +template +int CInputMain::SimpleHandler(LPDESC d, const char* p) +{ + (this->*fn)(d->GetCharacter(), p); + return 0; +} + +template +int CInputMain::SimpleHandlerV(LPDESC d, const char* p) +{ + (this->*fn)(d->GetCharacter(), p); + return 0; +} + static int __deposit_limit() { return (1000*10000); // 1천만 @@ -281,14 +296,14 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) { const TPacketCGWhisper* pinfo = reinterpret_cast(data); - if (uiBytes < pinfo->wSize) + if (uiBytes < pinfo->length) return -1; - int iExtraLen = pinfo->wSize - sizeof(TPacketCGWhisper); + int iExtraLen = pinfo->length - sizeof(TPacketCGWhisper); if (iExtraLen < 0) { - sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->wSize, uiBytes); + sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->length, uiBytes); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } @@ -333,9 +348,9 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) if (ch->GetDesc()) { TPacketGCWhisper pack; - pack.bHeader = HEADER_GC_WHISPER; + pack.header = GC::WHISPER; pack.bType = WHISPER_TYPE_SENDER_BLOCKED; - pack.wSize = sizeof(TPacketGCWhisper); + pack.length = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(pack)); } @@ -368,9 +383,9 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) { TPacketGCWhisper pack; - pack.bHeader = HEADER_GC_WHISPER; + pack.header = GC::WHISPER; pack.bType = WHISPER_TYPE_NOT_EXIST; - pack.wSize = sizeof(TPacketGCWhisper); + pack.length = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(TPacketGCWhisper)); sys_log(0, "WHISPER: no player"); @@ -383,9 +398,9 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) if (ch->GetDesc()) { TPacketGCWhisper pack; - pack.bHeader = HEADER_GC_WHISPER; + pack.header = GC::WHISPER; pack.bType = WHISPER_TYPE_SENDER_BLOCKED; - pack.wSize = sizeof(TPacketGCWhisper); + pack.length = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(pack)); } @@ -395,9 +410,9 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) if (ch->GetDesc()) { TPacketGCWhisper pack; - pack.bHeader = HEADER_GC_WHISPER; + pack.header = GC::WHISPER; pack.bType = WHISPER_TYPE_TARGET_BLOCKED; - pack.wSize = sizeof(TPacketGCWhisper); + pack.length = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(pack)); } @@ -471,9 +486,9 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) TPacketGCWhisper pack; - pack.bHeader = HEADER_GC_WHISPER; + pack.header = GC::WHISPER; pack.bType = WHISPER_TYPE_ERROR; - pack.wSize = sizeof(TPacketGCWhisper) + len; + pack.length = sizeof(TPacketGCWhisper) + len; strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->BufferedPacket(&pack, sizeof(pack)); @@ -495,8 +510,8 @@ int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) { TPacketGCWhisper pack; - pack.bHeader = HEADER_GC_WHISPER; - pack.wSize = sizeof(TPacketGCWhisper) + buflen; + pack.header = GC::WHISPER; + pack.length = sizeof(TPacketGCWhisper) + buflen; pack.bType = bType; strlcpy(pack.szNameFrom, ch->GetName(), sizeof(pack.szNameFrom)); @@ -637,14 +652,14 @@ struct FYmirChatPacket d->GetCharacter()->GetGMLevel() > GM_PLAYER || d->GetCharacter()->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) { - packet.size = m_len_orig_msg + sizeof(TPacketGCChat); + packet.length = m_len_orig_msg + sizeof(TPacketGCChat); d->BufferedPacket(&packet, sizeof(packet_chat)); d->Packet(m_orig_msg, m_len_orig_msg); } else { - packet.size = m_len_conv_msg + sizeof(TPacketGCChat); + packet.length = m_len_conv_msg + sizeof(TPacketGCChat); d->BufferedPacket(&packet, sizeof(packet_chat)); d->Packet(m_conv_msg, m_len_conv_msg); @@ -656,14 +671,14 @@ int CInputMain::Chat(LPCHARACTER ch, const char * data, size_t uiBytes) { const TPacketCGChat* pinfo = reinterpret_cast(data); - if (uiBytes < pinfo->size) + if (uiBytes < pinfo->length) return -1; - const int iExtraLen = pinfo->size - sizeof(TPacketCGChat); + const int iExtraLen = pinfo->length - sizeof(TPacketCGChat); if (iExtraLen < 0) { - sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->size, uiBytes); + sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->length, uiBytes); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } @@ -753,7 +768,7 @@ int CInputMain::Chat(LPCHARACTER ch, const char * data, size_t uiBytes) TPacketGGShout p; - p.bHeader = HEADER_GG_SHOUT; + p.header = GG::SHOUT; p.length = sizeof(p); p.bEmpire = ch->GetEmpire(); strlcpy(p.szText, chatbuf, sizeof(p.szText)); @@ -766,8 +781,8 @@ int CInputMain::Chat(LPCHARACTER ch, const char * data, size_t uiBytes) TPacketGCChat pack_chat; - pack_chat.header = HEADER_GC_CHAT; - pack_chat.size = sizeof(TPacketGCChat) + len; + pack_chat.header = GC::CHAT; + pack_chat.length = sizeof(TPacketGCChat) + len; pack_chat.type = pinfo->type; pack_chat.id = ch->GetVID(); @@ -852,10 +867,6 @@ void CInputMain::ItemDrop(LPCHARACTER ch, const char * data) { struct command_item_drop * pinfo = (struct command_item_drop *) data; - //MONARCH_LIMIT - //if (ch->IsMonarch()) - // return; - //END_MONARCH_LIMIT if (!ch) return; @@ -868,11 +879,6 @@ void CInputMain::ItemDrop(LPCHARACTER ch, const char * data) void CInputMain::ItemDrop2(LPCHARACTER ch, const char * data) { - //MONARCH_LIMIT - //if (ch->IsMonarch()) - // return; - //END_MONARCH_LIMIT - TPacketCGItemDrop2 * pinfo = (TPacketCGItemDrop2 *) data; // 엘크가 0보다 크면 엘크를 버리는 것 이다. @@ -930,7 +936,7 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes) switch (p->subheader) { - case MESSENGER_SUBHEADER_CG_ADD_BY_VID: + case MessengerSub::CG::ADD_BY_VID: { if (uiBytes < sizeof(TPacketCGMessengerAddByVID)) return -1; @@ -969,7 +975,7 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes) } return sizeof(TPacketCGMessengerAddByVID); - case MESSENGER_SUBHEADER_CG_ADD_BY_NAME: + case MessengerSub::CG::ADD_BY_NAME: { if (uiBytes < CHARACTER_NAME_MAX_LEN) return -1; @@ -1027,7 +1033,7 @@ int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes) } return CHARACTER_NAME_MAX_LEN; - case MESSENGER_SUBHEADER_CG_REMOVE: + case MessengerSub::CG::REMOVE: { if (uiBytes < CHARACTER_NAME_MAX_LEN) return -1; @@ -1065,12 +1071,12 @@ int CInputMain::Shop(LPCHARACTER ch, const char * data, size_t uiBytes) switch (p->subheader) { - case SHOP_SUBHEADER_CG_END: + case ShopSub::CG::END: sys_log(1, "INPUT: %s SHOP: END", ch->GetName()); CShopManager::instance().StopShopping(ch); return 0; - case SHOP_SUBHEADER_CG_BUY: + case ShopSub::CG::BUY: { if (uiBytes < sizeof(BYTE) + sizeof(BYTE)) return -1; @@ -1081,7 +1087,7 @@ int CInputMain::Shop(LPCHARACTER ch, const char * data, size_t uiBytes) return (sizeof(BYTE) + sizeof(BYTE)); } - case SHOP_SUBHEADER_CG_SELL: + case ShopSub::CG::SELL: { if (uiBytes < sizeof(BYTE)) return -1; @@ -1093,7 +1099,7 @@ int CInputMain::Shop(LPCHARACTER ch, const char * data, size_t uiBytes) return sizeof(BYTE); } - case SHOP_SUBHEADER_CG_SELL2: + case ShopSub::CG::SELL2: { if (uiBytes < sizeof(BYTE) + sizeof(BYTE)) return -1; @@ -1162,20 +1168,11 @@ void CInputMain::Exchange(LPCHARACTER ch, const char * data) switch (pinfo->sub_header) { - case EXCHANGE_SUBHEADER_CG_START: // arg1 == vid of target character + case ExchangeSub::CG::START: // arg1 == vid of target character if (!ch->GetExchange()) { if ((to_ch = CHARACTER_MANAGER::instance().Find(pinfo->arg1))) { - //MONARCH_LIMIT - /* - if (to_ch->IsMonarch() || ch->IsMonarch()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주와는 거래를 할수가 없습니다"), g_nPortalLimitTime); - return; - } - //END_MONARCH_LIMIT - */ if (iPulse - ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고를 연후 %d초 이내에는 거래를 할수 없습니다."), g_nPortalLimitTime); @@ -1224,7 +1221,7 @@ void CInputMain::Exchange(LPCHARACTER ch, const char * data) } break; - case EXCHANGE_SUBHEADER_CG_ITEM_ADD: // arg1 == position of item, arg2 == position in exchange window + case ExchangeSub::CG::ITEM_ADD: // arg1 == position of item, arg2 == position in exchange window if (ch->GetExchange()) { if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true) @@ -1232,7 +1229,7 @@ void CInputMain::Exchange(LPCHARACTER ch, const char * data) } break; - case EXCHANGE_SUBHEADER_CG_ITEM_DEL: // arg1 == position of item + case ExchangeSub::CG::ITEM_DEL: // arg1 == position of item if (ch->GetExchange()) { if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true) @@ -1240,7 +1237,7 @@ void CInputMain::Exchange(LPCHARACTER ch, const char * data) } break; - case EXCHANGE_SUBHEADER_CG_ELK_ADD: // arg1 == amount of gold + case ExchangeSub::CG::ELK_ADD: // arg1 == amount of gold if (ch->GetExchange()) { const int64_t nTotalGold = static_cast(ch->GetExchange()->GetCompany()->GetOwner()->GetGold()) + static_cast(pinfo->arg1); @@ -1262,7 +1259,7 @@ void CInputMain::Exchange(LPCHARACTER ch, const char * data) } break; - case EXCHANGE_SUBHEADER_CG_ACCEPT: // arg1 == not used + case ExchangeSub::CG::ACCEPT: // arg1 == not used if (ch->GetExchange()) { sys_log(0, "CInputMain()::Exchange() ==> ACCEPT "); @@ -1271,7 +1268,7 @@ void CInputMain::Exchange(LPCHARACTER ch, const char * data) break; - case EXCHANGE_SUBHEADER_CG_CANCEL: // arg1 == not used + case ExchangeSub::CG::CANCEL: // arg1 == not used if (ch->GetExchange()) ch->GetExchange()->Cancel(); break; @@ -1603,7 +1600,7 @@ void CInputMain::Move(LPCHARACTER ch, const char * data) // DWORD dwCurTime = get_dword_time(); // 시간을 Sync하고 7초 후 부터 검사한다. (20090702 이전엔 5초였음) - bool CheckSpeedHack = (false == ch->GetDesc()->IsHandshaking() && dwCurTime - ch->GetDesc()->GetClientTime() > 7000); + bool CheckSpeedHack = (dwCurTime - ch->GetDesc()->GetClientTime() > 7000); if (CheckSpeedHack) { @@ -1689,7 +1686,8 @@ void CInputMain::Move(LPCHARACTER ch, const char * data) TPacketGCMove pack; - pack.bHeader = HEADER_GC_MOVE; + pack.header = GC::MOVE; + pack.length = sizeof(pack); pack.bFunc = pinfo->bFunc; pack.bArg = pinfo->bArg; pack.bRot = pinfo->bRot; @@ -1726,15 +1724,17 @@ void CInputMain::Move(LPCHARACTER ch, const char * data) */ } -void CInputMain::Attack(LPCHARACTER ch, const BYTE header, const char* data) +void CInputMain::Attack(LPCHARACTER ch, const uint16_t header, const char* data) { if (NULL == ch) return; + // Updated for new packet format: [header:2][length:2][bType:1] struct type_identifier { - BYTE header; - BYTE type; + uint16_t header; + uint16_t length; + uint8_t type; }; const struct type_identifier* const type = reinterpret_cast(data); @@ -1762,7 +1762,7 @@ void CInputMain::Attack(LPCHARACTER ch, const BYTE header, const char* data) case SKILL_NOEJEON: case SKILL_CHAIN: case SKILL_HORSE_WILDATTACK_RANGE: - if (HEADER_CG_SHOOT != type->header) + if (CG::SHOOT != type->header) { if (test_server) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Attack :name[%s] Vnum[%d] can't use skill by attack(warning)"), type->type); @@ -1774,25 +1774,43 @@ void CInputMain::Attack(LPCHARACTER ch, const BYTE header, const char* data) switch (header) { - case HEADER_CG_ATTACK: + case CG::ATTACK: { + sys_log(0, "ATTACK: Processing attack from %s", ch->GetName()); + if (NULL == ch->GetDesc()) + { + sys_log(0, "ATTACK: REJECTED - ch->GetDesc() is NULL"); return; + } const TPacketCGAttack* const packMelee = reinterpret_cast(data); + sys_log(0, "ATTACK: dwVID=%u bType=%d CRC1=%d CRC2=%d", + packMelee->dwVID, packMelee->bType, + packMelee->bCRCMagicCubeProcPiece, packMelee->bCRCMagicCubeFilePiece); ch->GetDesc()->AssembleCRCMagicCube(packMelee->bCRCMagicCubeProcPiece, packMelee->bCRCMagicCubeFilePiece); LPCHARACTER victim = CHARACTER_MANAGER::instance().Find(packMelee->dwVID); if (NULL == victim || ch == victim) + { + sys_log(0, "ATTACK: REJECTED - victim is NULL or self (victim=%p, ch=%p)", victim, ch); return; + } + + sys_log(0, "ATTACK: victim=%s charType=%d", victim->GetName(), victim->GetCharType()); switch (victim->GetCharType()) { case CHAR_TYPE_NPC: + sys_log(0, "ATTACK: REJECTED - victim is CHAR_TYPE_NPC"); + return; case CHAR_TYPE_WARP: + sys_log(0, "ATTACK: REJECTED - victim is CHAR_TYPE_WARP"); + return; case CHAR_TYPE_GOTO: + sys_log(0, "ATTACK: REJECTED - victim is CHAR_TYPE_GOTO"); return; } @@ -1800,15 +1818,17 @@ void CInputMain::Attack(LPCHARACTER ch, const BYTE header, const char* data) { if (false == ch->CheckSkillHitCount(packMelee->bType, victim->GetVID())) { + sys_log(0, "ATTACK: REJECTED - CheckSkillHitCount failed for bType=%d", packMelee->bType); return; } } + sys_log(0, "ATTACK: Calling ch->Attack(victim=%s, bType=%d)", victim->GetName(), packMelee->bType); ch->Attack(victim, packMelee->bType); } break; - case HEADER_CG_SHOOT: + case CG::SHOOT: { const TPacketCGShoot* const packShoot = reinterpret_cast(data); @@ -1822,21 +1842,21 @@ int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiByt { const TPacketCGSyncPosition* pinfo = reinterpret_cast( c_pcData ); - if (uiBytes < pinfo->wSize) + if (uiBytes < pinfo->length) return -1; - int iExtraLen = pinfo->wSize - sizeof(TPacketCGSyncPosition); + int iExtraLen = pinfo->length - sizeof(TPacketCGSyncPosition); if (iExtraLen < 0) { - sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->wSize, uiBytes); + sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->length, uiBytes); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } if (0 != (iExtraLen % sizeof(TPacketCGSyncPositionElement))) { - sys_err("invalid packet length %d (name: %s)", pinfo->wSize, ch->GetName()); + sys_err("invalid packet length %d (name: %s)", pinfo->length, ch->GetName()); return iExtraLen; } @@ -1857,10 +1877,9 @@ int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiByt } TEMP_BUFFER tbuf; - LPBUFFER lpBuf = tbuf.getptr(); - TPacketGCSyncPosition * pHeader = (TPacketGCSyncPosition *) buffer_write_peek(lpBuf); - buffer_write_proceed(lpBuf, sizeof(TPacketGCSyncPosition)); + TPacketGCSyncPosition * pHeader = (TPacketGCSyncPosition *) tbuf.write_peek(sizeof(TPacketGCSyncPosition)); + tbuf.write_proceed(sizeof(TPacketGCSyncPosition)); const TPacketCGSyncPositionElement* e = reinterpret_cast(c_pcData + sizeof(TPacketCGSyncPosition)); @@ -1960,25 +1979,25 @@ int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiByt { victim->SetLastSyncTime(tvCurTime); victim->Sync(e->lX, e->lY); - buffer_write(lpBuf, e, sizeof(TPacketCGSyncPositionElement)); + tbuf.write(e, sizeof(TPacketCGSyncPositionElement)); } } - if (buffer_size(lpBuf) != sizeof(TPacketGCSyncPosition)) + if (tbuf.size() != sizeof(TPacketGCSyncPosition)) { - pHeader->bHeader = HEADER_GC_SYNC_POSITION; - pHeader->wSize = buffer_size(lpBuf); + pHeader->header = GC::SYNC_POSITION; + pHeader->length = tbuf.size(); - ch->PacketAround(buffer_read_peek(lpBuf), buffer_size(lpBuf), ch); + ch->PacketAround(tbuf.read_peek(), tbuf.size(), ch); } return iExtraLen; } -void CInputMain::FlyTarget(LPCHARACTER ch, const char * pcData, BYTE bHeader) +void CInputMain::FlyTarget(LPCHARACTER ch, const char * pcData, uint16_t wHeader) { TPacketCGFlyTargeting * p = (TPacketCGFlyTargeting *) pcData; - ch->FlyTarget(p->dwTargetVID, p->x, p->y, bHeader); + ch->FlyTarget(p->dwTargetVID, p->x, p->y, wHeader); } void CInputMain::UseSkill(LPCHARACTER ch, const char * pcData) @@ -2071,7 +2090,8 @@ void CInputMain::Target(LPCHARACTER ch, const char * pcData) if (pkObj) { TPacketGCTarget pckTarget; - pckTarget.header = HEADER_GC_TARGET; + pckTarget.header = GC::TARGET; + pckTarget.length = sizeof(pckTarget); pckTarget.dwVID = p->dwVID; ch->GetDesc()->Packet(&pckTarget, sizeof(TPacketGCTarget)); } @@ -2227,7 +2247,7 @@ void CInputMain::SafeboxCheckout(LPCHARACTER ch, const char * c_pData, bool bMal } DWORD dwID = pkItem->GetID(); - db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_FLUSH, 0, sizeof(DWORD)); + db_clientdesc->DBPacketHeader(GD::ITEM_FLUSH, 0, sizeof(DWORD)); db_clientdesc->Packet(&dwID, sizeof(DWORD)); char szHint[128]; @@ -2342,7 +2362,7 @@ void CInputMain::PartySetState(LPCHARACTER ch, const char* c_pData) pack.dwPID = p->pid; pack.bRole = p->byRole; pack.bFlag = p->flag; - db_clientdesc->DBPacket(HEADER_GD_PARTY_STATE_CHANGE, 0, &pack, sizeof(pack)); + db_clientdesc->DBPacket(GD::PARTY_STATE_CHANGE, 0, &pack, sizeof(pack)); } /* else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 어태커 설정에 실패하였습니다.")); */ @@ -2567,41 +2587,45 @@ void CInputMain::PartyParameter(LPCHARACTER ch, const char * c_pData) ch->GetParty()->SetParameter(p->bDistributeMode); } -size_t GetSubPacketSize(const GUILD_SUBHEADER_CG& header) +size_t GetSubPacketSize(uint8_t header) { switch (header) { - case GUILD_SUBHEADER_CG_DEPOSIT_MONEY: return sizeof(int); - case GUILD_SUBHEADER_CG_WITHDRAW_MONEY: return sizeof(int); - case GUILD_SUBHEADER_CG_ADD_MEMBER: return sizeof(DWORD); - case GUILD_SUBHEADER_CG_REMOVE_MEMBER: return sizeof(DWORD); - case GUILD_SUBHEADER_CG_CHANGE_GRADE_NAME: return 10; - case GUILD_SUBHEADER_CG_CHANGE_GRADE_AUTHORITY: return sizeof(BYTE) + sizeof(BYTE); - case GUILD_SUBHEADER_CG_OFFER: return sizeof(DWORD); - case GUILD_SUBHEADER_CG_CHARGE_GSP: return sizeof(int); - case GUILD_SUBHEADER_CG_POST_COMMENT: return 1; - case GUILD_SUBHEADER_CG_DELETE_COMMENT: return sizeof(DWORD); - case GUILD_SUBHEADER_CG_REFRESH_COMMENT: return 0; - case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GRADE: return sizeof(DWORD) + sizeof(BYTE); - case GUILD_SUBHEADER_CG_USE_SKILL: return sizeof(TPacketCGGuildUseSkill); - case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GENERAL: return sizeof(DWORD) + sizeof(BYTE); - case GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER: return sizeof(DWORD) + sizeof(BYTE); + case GuildSub::CG::DEPOSIT_MONEY: return sizeof(int); + case GuildSub::CG::WITHDRAW_MONEY: return sizeof(int); + case GuildSub::CG::ADD_MEMBER: return sizeof(DWORD); + case GuildSub::CG::REMOVE_MEMBER: return sizeof(DWORD); + case GuildSub::CG::CHANGE_GRADE_NAME: return 10; + case GuildSub::CG::CHANGE_GRADE_AUTHORITY: return sizeof(BYTE) + sizeof(BYTE); + case GuildSub::CG::OFFER: return sizeof(DWORD); + case GuildSub::CG::CHARGE_GSP: return sizeof(int); + case GuildSub::CG::POST_COMMENT: return 1; + case GuildSub::CG::DELETE_COMMENT: return sizeof(DWORD); + case GuildSub::CG::REFRESH_COMMENT: return 0; + case GuildSub::CG::CHANGE_MEMBER_GRADE: return sizeof(DWORD) + sizeof(BYTE); + case GuildSub::CG::USE_SKILL: return sizeof(TPacketCGGuildUseSkill); + case GuildSub::CG::CHANGE_MEMBER_GENERAL: return sizeof(DWORD) + sizeof(BYTE); + case GuildSub::CG::GUILD_INVITE_ANSWER: return sizeof(DWORD) + sizeof(BYTE); } return 0; } +// --------------------------------------------------------------------------- +// Guild sub-handler type and dispatch table +// --------------------------------------------------------------------------- +using GuildSubHandler = int (CInputMain::*)(LPCHARACTER, const char*, size_t); + int CInputMain::Guild(LPCHARACTER ch, const char * data, size_t uiBytes) { if (uiBytes < sizeof(TPacketCGGuild)) return -1; const TPacketCGGuild* p = reinterpret_cast(data); - const char* c_pData = data + sizeof(TPacketCGGuild); uiBytes -= sizeof(TPacketCGGuild); - const GUILD_SUBHEADER_CG SubHeader = static_cast(p->subheader); + const uint8_t SubHeader = p->subheader; const size_t SubPacketLen = GetSubPacketSize(SubHeader); if (uiBytes < SubPacketLen) @@ -2613,347 +2637,439 @@ int CInputMain::Guild(LPCHARACTER ch, const char * data, size_t uiBytes) if (NULL == pGuild) { - if (SubHeader != GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER) + if (SubHeader != GuildSub::CG::GUILD_INVITE_ANSWER) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드에 속해있지 않습니다.")); return SubPacketLen; } } - switch (SubHeader) + static const std::unordered_map handlers = { + { GuildSub::CG::DEPOSIT_MONEY, &CInputMain::GuildSub_DepositMoney }, + { GuildSub::CG::WITHDRAW_MONEY, &CInputMain::GuildSub_WithdrawMoney }, + { GuildSub::CG::ADD_MEMBER, &CInputMain::GuildSub_AddMember }, + { GuildSub::CG::REMOVE_MEMBER, &CInputMain::GuildSub_RemoveMember }, + { GuildSub::CG::CHANGE_GRADE_NAME, &CInputMain::GuildSub_ChangeGradeName }, + { GuildSub::CG::CHANGE_GRADE_AUTHORITY, &CInputMain::GuildSub_ChangeGradeAuthority }, + { GuildSub::CG::OFFER, &CInputMain::GuildSub_Offer }, + { GuildSub::CG::CHARGE_GSP, &CInputMain::GuildSub_ChargeGSP }, + { GuildSub::CG::POST_COMMENT, &CInputMain::GuildSub_PostComment }, + { GuildSub::CG::DELETE_COMMENT, &CInputMain::GuildSub_DeleteComment }, + { GuildSub::CG::REFRESH_COMMENT, &CInputMain::GuildSub_RefreshComment }, + { GuildSub::CG::CHANGE_MEMBER_GRADE, &CInputMain::GuildSub_ChangeMemberGrade }, + { GuildSub::CG::USE_SKILL, &CInputMain::GuildSub_UseSkill }, + { GuildSub::CG::CHANGE_MEMBER_GENERAL, &CInputMain::GuildSub_ChangeMemberGeneral }, + { GuildSub::CG::GUILD_INVITE_ANSWER, &CInputMain::GuildSub_InviteAnswer }, + }; + + auto it = handlers.find(SubHeader); + if (it == handlers.end()) { - case GUILD_SUBHEADER_CG_DEPOSIT_MONEY: - { - // by mhh : 길드자금은 당분간 넣을 수 없다. - return SubPacketLen; - - const int gold = MIN(*reinterpret_cast(c_pData), __deposit_limit()); - - if (gold < 0) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다.")); - return SubPacketLen; - } - - if (ch->GetGold() < gold) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 가지고 있는 돈이 부족합니다.")); - return SubPacketLen; - } - - pGuild->RequestDepositMoney(ch, gold); - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_WITHDRAW_MONEY: - { - // by mhh : 길드자금은 당분간 뺄 수 없다. - return SubPacketLen; - - const int gold = MIN(*reinterpret_cast(c_pData), 500000); - - if (gold < 0) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다.")); - return SubPacketLen; - } - - pGuild->RequestWithdrawMoney(ch, gold); - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_ADD_MEMBER: - { - const DWORD vid = *reinterpret_cast(c_pData); - LPCHARACTER newmember = CHARACTER_MANAGER::instance().Find(vid); - - // if (!newmember) - if (!newmember || !newmember->IsPC()) // Fix - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다.")); - return SubPacketLen; - } - - if (!ch->IsPC()) - return SubPacketLen; - - if (LC_IsCanada() == true) - { - if (newmember->GetQuestFlag("change_guild_master.be_other_member") > get_global_time()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 아직 가입할 수 없는 캐릭터입니다")); - return SubPacketLen; - } - } - - pGuild->Invite(ch, newmember); - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_REMOVE_MEMBER: - { - if (pGuild->UnderAnyWar() != 0) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전 중에는 길드원을 탈퇴시킬 수 없습니다.")); - return SubPacketLen; - } - - const DWORD pid = *reinterpret_cast(c_pData); - const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); - - if (NULL == m) - return -1; - - LPCHARACTER member = CHARACTER_MANAGER::instance().FindByPID(pid); - - if (member) - { - if (member->GetGuild() != pGuild) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방이 같은 길드가 아닙니다.")); - return SubPacketLen; - } - - if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다.")); - return SubPacketLen; - } - - member->SetQuestFlag("guild_manage.new_withdraw_time", get_global_time()); - pGuild->RequestRemoveMember(member->GetPlayerID()); - - if (LC_IsBrazil() == true) - { - DBManager::instance().Query("REPLACE INTO guild_invite_limit VALUES(%d, %d)", pGuild->GetID(), get_global_time()); - } - } - else - { - if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다.")); - return SubPacketLen; - } - - if (pGuild->RequestRemoveMember(pid)) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시켰습니다.")); - else - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다.")); - } - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_CHANGE_GRADE_NAME: - { - char gradename[GUILD_GRADE_NAME_MAX_LEN + 1]; - strlcpy(gradename, c_pData + 1, sizeof(gradename)); - - const TGuildMember * m = pGuild->GetMember(ch->GetPlayerID()); - - if (NULL == m) - return -1; - - if (m->grade != GUILD_LEADER_GRADE) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 이름을 변경할 권한이 없습니다.")); - } - else if (*c_pData == GUILD_LEADER_GRADE) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위 이름은 변경할 수 없습니다.")); - } - else if (!check_name(gradename)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 적합하지 않은 직위 이름 입니다.")); - } - else - { - pGuild->ChangeGradeName(*c_pData, gradename); - } - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_CHANGE_GRADE_AUTHORITY: - { - const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); - - if (NULL == m) - return -1; - - if (m->grade != GUILD_LEADER_GRADE) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 권한을 변경할 권한이 없습니다.")); - } - else if (*c_pData == GUILD_LEADER_GRADE) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 권한은 변경할 수 없습니다.")); - } - else - { - pGuild->ChangeGradeAuth(*c_pData, *(c_pData + 1)); - } - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_OFFER: - { - DWORD offer = *reinterpret_cast(c_pData); - - if (pGuild->GetLevel() >= GUILD_MAX_LEVEL && LC_IsHongKong() == false) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드가 이미 최고 레벨입니다.")); - } - else - { - offer /= 100; - offer *= 100; - - if (pGuild->OfferExp(ch, offer)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> %u의 경험치를 투자하였습니다."), offer); - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 경험치 투자에 실패하였습니다.")); - } - } - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_CHARGE_GSP: - { - const int offer = *reinterpret_cast(c_pData); - const int gold = offer * 100; - - if (offer < 0 || gold < offer || gold < 0 || ch->GetGold() < gold) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 돈이 부족합니다.")); - return SubPacketLen; - } - - if (!pGuild->ChargeSP(ch, offer)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 용신력 회복에 실패하였습니다.")); - } - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_POST_COMMENT: - { - const size_t length = *c_pData; - - if (length > GUILD_COMMENT_MAX_LEN) - { - // 잘못된 길이.. 끊어주자. - sys_err("POST_COMMENT: %s comment too long (length: %u)", ch->GetName(), length); - ch->GetDesc()->SetPhase(PHASE_CLOSE); - return -1; - } - - if (uiBytes < 1 + length) - return -1; - - const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); - - if (NULL == m) - return -1; - - if (length && !pGuild->HasGradeAuth(m->grade, GUILD_AUTH_NOTICE) && *(c_pData + 1) == '!') - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 공지글을 작성할 권한이 없습니다.")); - } - else - { - std::string str(c_pData + 1, length); - pGuild->AddComment(ch, str); - } - - return (1 + length); - } - - case GUILD_SUBHEADER_CG_DELETE_COMMENT: - { - const DWORD comment_id = *reinterpret_cast(c_pData); - - pGuild->DeleteComment(ch, comment_id); - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_REFRESH_COMMENT: - pGuild->RefreshComment(ch); - return SubPacketLen; - - case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GRADE: - { - const DWORD pid = *reinterpret_cast(c_pData); - const BYTE grade = *(c_pData + sizeof(DWORD)); - const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); - - if (NULL == m) - return -1; - - if (m->grade != GUILD_LEADER_GRADE) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위를 변경할 권한이 없습니다.")); - else if (ch->GetPlayerID() == pid) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위는 변경할 수 없습니다.")); - else if (grade == 1) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장으로 직위를 변경할 수 없습니다.")); - else - pGuild->ChangeMemberGrade(pid, grade); - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_USE_SKILL: - { - const TPacketCGGuildUseSkill* p = reinterpret_cast(c_pData); - - pGuild->UseSkill(p->dwVnum, ch, p->dwPID); - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GENERAL: - { - const DWORD pid = *reinterpret_cast(c_pData); - const BYTE is_general = *(c_pData + sizeof(DWORD)); - const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); - - if (NULL == m) - return -1; - - if (m->grade != GUILD_LEADER_GRADE) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 장군을 지정할 권한이 없습니다.")); - } - else - { - if (!pGuild->ChangeMemberGeneral(pid, is_general)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 더이상 장수를 지정할 수 없습니다.")); - } - } - } - return SubPacketLen; - - case GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER: - { - const DWORD guild_id = *reinterpret_cast(c_pData); - const BYTE accept = *(c_pData + sizeof(DWORD)); - - CGuild * g = CGuildManager::instance().FindGuild(guild_id); - - if (g) - { - if (accept) - g->InviteAccept(ch); - else - g->InviteDeny(ch->GetPlayerID()); - } - } - return SubPacketLen; - + sys_err("Guild: unknown subheader %d from %s", SubHeader, ch->GetName()); + return 0; } - return 0; + return (this->*(it->second))(ch, data, uiBytes); +} + +// --------------------------------------------------------------------------- +// Guild sub-handlers — extracted from Guild() switch cases +// --------------------------------------------------------------------------- + +int CInputMain::GuildSub_DepositMoney(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::DEPOSIT_MONEY); + CGuild* pGuild = ch->GetGuild(); + + // by mhh : 길드자금은 당분간 넣을 수 없다. + return SubPacketLen; + + const int gold = MIN(*reinterpret_cast(c_pData), __deposit_limit()); + + if (gold < 0) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다.")); + return SubPacketLen; + } + + if (ch->GetGold() < gold) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 가지고 있는 돈이 부족합니다.")); + return SubPacketLen; + } + + pGuild->RequestDepositMoney(ch, gold); + return SubPacketLen; +} + +int CInputMain::GuildSub_WithdrawMoney(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::WITHDRAW_MONEY); + CGuild* pGuild = ch->GetGuild(); + + // by mhh : 길드자금은 당분간 뺄 수 없다. + return SubPacketLen; + + const int gold = MIN(*reinterpret_cast(c_pData), 500000); + + if (gold < 0) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다.")); + return SubPacketLen; + } + + pGuild->RequestWithdrawMoney(ch, gold); + return SubPacketLen; +} + +int CInputMain::GuildSub_AddMember(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::ADD_MEMBER); + CGuild* pGuild = ch->GetGuild(); + + const DWORD vid = *reinterpret_cast(c_pData); + LPCHARACTER newmember = CHARACTER_MANAGER::instance().Find(vid); + + // if (!newmember) + if (!newmember || !newmember->IsPC()) // Fix + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다.")); + return SubPacketLen; + } + + if (!ch->IsPC()) + return SubPacketLen; + + if (LC_IsCanada() == true) + { + if (newmember->GetQuestFlag("change_guild_master.be_other_member") > get_global_time()) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 아직 가입할 수 없는 캐릭터입니다")); + return SubPacketLen; + } + } + + pGuild->Invite(ch, newmember); + return SubPacketLen; +} + +int CInputMain::GuildSub_RemoveMember(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::REMOVE_MEMBER); + CGuild* pGuild = ch->GetGuild(); + + if (pGuild->UnderAnyWar() != 0) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전 중에는 길드원을 탈퇴시킬 수 없습니다.")); + return SubPacketLen; + } + + const DWORD pid = *reinterpret_cast(c_pData); + const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); + + if (NULL == m) + return -1; + + LPCHARACTER member = CHARACTER_MANAGER::instance().FindByPID(pid); + + if (member) + { + if (member->GetGuild() != pGuild) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방이 같은 길드가 아닙니다.")); + return SubPacketLen; + } + + if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다.")); + return SubPacketLen; + } + + member->SetQuestFlag("guild_manage.new_withdraw_time", get_global_time()); + pGuild->RequestRemoveMember(member->GetPlayerID()); + + if (LC_IsBrazil() == true) + { + DBManager::instance().Query("REPLACE INTO guild_invite_limit VALUES(%d, %d)", pGuild->GetID(), get_global_time()); + } + } + else + { + if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다.")); + return SubPacketLen; + } + + if (pGuild->RequestRemoveMember(pid)) + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시켰습니다.")); + else + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다.")); + } + + return SubPacketLen; +} + +int CInputMain::GuildSub_ChangeGradeName(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::CHANGE_GRADE_NAME); + CGuild* pGuild = ch->GetGuild(); + + char gradename[GUILD_GRADE_NAME_MAX_LEN + 1]; + strlcpy(gradename, c_pData + 1, sizeof(gradename)); + + const TGuildMember * m = pGuild->GetMember(ch->GetPlayerID()); + + if (NULL == m) + return -1; + + if (m->grade != GUILD_LEADER_GRADE) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 이름을 변경할 권한이 없습니다.")); + } + else if (*c_pData == GUILD_LEADER_GRADE) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위 이름은 변경할 수 없습니다.")); + } + else if (!check_name(gradename)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 적합하지 않은 직위 이름 입니다.")); + } + else + { + pGuild->ChangeGradeName(*c_pData, gradename); + } + + return SubPacketLen; +} + +int CInputMain::GuildSub_ChangeGradeAuthority(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::CHANGE_GRADE_AUTHORITY); + CGuild* pGuild = ch->GetGuild(); + + const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); + + if (NULL == m) + return -1; + + if (m->grade != GUILD_LEADER_GRADE) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 권한을 변경할 권한이 없습니다.")); + } + else if (*c_pData == GUILD_LEADER_GRADE) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 권한은 변경할 수 없습니다.")); + } + else + { + pGuild->ChangeGradeAuth(*c_pData, *(c_pData + 1)); + } + + return SubPacketLen; +} + +int CInputMain::GuildSub_Offer(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::OFFER); + CGuild* pGuild = ch->GetGuild(); + + DWORD offer = *reinterpret_cast(c_pData); + + if (pGuild->GetLevel() >= GUILD_MAX_LEVEL && LC_IsHongKong() == false) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드가 이미 최고 레벨입니다.")); + } + else + { + offer /= 100; + offer *= 100; + + if (pGuild->OfferExp(ch, offer)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> %u의 경험치를 투자하였습니다."), offer); + } + else + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 경험치 투자에 실패하였습니다.")); + } + } + + return SubPacketLen; +} + +int CInputMain::GuildSub_ChargeGSP(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::CHARGE_GSP); + CGuild* pGuild = ch->GetGuild(); + + const int offer = *reinterpret_cast(c_pData); + const int gold = offer * 100; + + if (offer < 0 || gold < offer || gold < 0 || ch->GetGold() < gold) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 돈이 부족합니다.")); + return SubPacketLen; + } + + if (!pGuild->ChargeSP(ch, offer)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 용신력 회복에 실패하였습니다.")); + } + + return SubPacketLen; +} + +int CInputMain::GuildSub_PostComment(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + CGuild* pGuild = ch->GetGuild(); + + const size_t length = *c_pData; + + if (length > GUILD_COMMENT_MAX_LEN) + { + // 잘못된 길이.. 끊어주자. + sys_err("POST_COMMENT: %s comment too long (length: %u)", ch->GetName(), length); + ch->GetDesc()->SetPhase(PHASE_CLOSE); + return -1; + } + + if (uiBytes < 1 + length) + return -1; + + const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); + + if (NULL == m) + return -1; + + if (length && !pGuild->HasGradeAuth(m->grade, GUILD_AUTH_NOTICE) && *(c_pData + 1) == '!') + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 공지글을 작성할 권한이 없습니다.")); + } + else + { + std::string str(c_pData + 1, length); + pGuild->AddComment(ch, str); + } + + return (1 + length); +} + +int CInputMain::GuildSub_DeleteComment(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::DELETE_COMMENT); + CGuild* pGuild = ch->GetGuild(); + + const DWORD comment_id = *reinterpret_cast(c_pData); + + pGuild->DeleteComment(ch, comment_id); + return SubPacketLen; +} + +int CInputMain::GuildSub_RefreshComment(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::REFRESH_COMMENT); + CGuild* pGuild = ch->GetGuild(); + + pGuild->RefreshComment(ch); + return SubPacketLen; +} + +int CInputMain::GuildSub_ChangeMemberGrade(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::CHANGE_MEMBER_GRADE); + CGuild* pGuild = ch->GetGuild(); + + const DWORD pid = *reinterpret_cast(c_pData); + const BYTE grade = *(c_pData + sizeof(DWORD)); + const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); + + if (NULL == m) + return -1; + + if (m->grade != GUILD_LEADER_GRADE) + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위를 변경할 권한이 없습니다.")); + else if (ch->GetPlayerID() == pid) + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위는 변경할 수 없습니다.")); + else if (grade == 1) + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장으로 직위를 변경할 수 없습니다.")); + else + pGuild->ChangeMemberGrade(pid, grade); + + return SubPacketLen; +} + +int CInputMain::GuildSub_UseSkill(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::USE_SKILL); + CGuild* pGuild = ch->GetGuild(); + + const TPacketCGGuildUseSkill* p = reinterpret_cast(c_pData); + + pGuild->UseSkill(p->dwVnum, ch, p->dwPID); + return SubPacketLen; +} + +int CInputMain::GuildSub_ChangeMemberGeneral(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::CHANGE_MEMBER_GENERAL); + CGuild* pGuild = ch->GetGuild(); + + const DWORD pid = *reinterpret_cast(c_pData); + const BYTE is_general = *(c_pData + sizeof(DWORD)); + const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); + + if (NULL == m) + return -1; + + if (m->grade != GUILD_LEADER_GRADE) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 장군을 지정할 권한이 없습니다.")); + } + else + { + if (!pGuild->ChangeMemberGeneral(pid, is_general)) + { + ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 더이상 장수를 지정할 수 없습니다.")); + } + } + + return SubPacketLen; +} + +int CInputMain::GuildSub_InviteAnswer(LPCHARACTER ch, const char* data, size_t uiBytes) +{ + const char* c_pData = data + sizeof(TPacketCGGuild); + const size_t SubPacketLen = GetSubPacketSize(GuildSub::CG::GUILD_INVITE_ANSWER); + + const DWORD guild_id = *reinterpret_cast(c_pData); + const BYTE accept = *(c_pData + sizeof(DWORD)); + + CGuild * g = CGuildManager::instance().FindGuild(guild_id); + + if (g) + { + if (accept) + g->InviteAccept(ch); + else + g->InviteDeny(ch->GetPlayerID()); + } + + return SubPacketLen; } void CInputMain::Fishing(LPCHARACTER ch, const char* c_pData) @@ -3089,350 +3205,288 @@ void CInputMain::Refine(LPCHARACTER ch, const char* c_pData) ch->ClearRefineMode(); } -int CInputMain::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) -{ - LPCHARACTER ch; +// --------------------------------------------------------------------------- +// Handler map constructors + registration +// --------------------------------------------------------------------------- - if (!(ch = d->GetCharacter())) +CInputMain::CInputMain() +{ + RegisterHandlers(); +} + +// Custom adapter methods — bridge varied handler signatures to unified MainHandler + +int CInputMain::HandlePong(LPDESC d, const char*) +{ + Pong(d); + return 0; +} + +int CInputMain::HandleChat(LPDESC d, const char* c_pData) +{ + if (test_server) + { + char* pBuf = (char*)c_pData; + sys_log(0, "%s", pBuf + sizeof(TPacketCGChat)); + } + return Chat(d->GetCharacter(), c_pData, m_iBufferLeft); +} + +int CInputMain::HandleWhisper(LPDESC d, const char* c_pData) +{ + return Whisper(d->GetCharacter(), c_pData, m_iBufferLeft); +} + +int CInputMain::HandleMove(LPDESC d, const char* c_pData) +{ + LPCHARACTER ch = d->GetCharacter(); + Move(ch, c_pData); + + if (g_bCheckClientVersion) + { + int version = atoi(g_stClientVersion.c_str()); + int date = atoi(d->GetClientVersion()); + + if (version != date) + { + ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요.")); + d->DelayedDisconnect(10); + LogManager::instance().HackLog("VERSION_CONFLICT", d->GetAccountTable().login, ch->GetName(), d->GetHostName()); + } + } + else if (!*d->GetClientVersion()) + { + sys_err("Version not recieved name %s", ch->GetName()); + d->SetPhase(PHASE_CLOSE); + } + return 0; +} + +int CInputMain::HandleAttack(LPDESC d, const char* c_pData) +{ + Attack(d->GetCharacter(), CG::ATTACK, c_pData); + return 0; +} + +int CInputMain::HandleShoot(LPDESC d, const char* c_pData) +{ + Attack(d->GetCharacter(), CG::SHOOT, c_pData); + return 0; +} + +int CInputMain::HandleShop(LPDESC d, const char* c_pData) +{ + return Shop(d->GetCharacter(), c_pData, m_iBufferLeft); +} + +int CInputMain::HandleMessenger(LPDESC d, const char* c_pData) +{ + return Messenger(d->GetCharacter(), c_pData, m_iBufferLeft); +} + +int CInputMain::HandleSyncPosition(LPDESC d, const char* c_pData) +{ + return SyncPosition(d->GetCharacter(), c_pData, m_iBufferLeft); +} + +int CInputMain::HandleFlyTargeting(LPDESC d, const char* c_pData) +{ + FlyTarget(d->GetCharacter(), c_pData, CG::FLY_TARGETING); + return 0; +} + +int CInputMain::HandleAddFlyTargeting(LPDESC d, const char* c_pData) +{ + FlyTarget(d->GetCharacter(), c_pData, CG::ADD_FLY_TARGETING); + return 0; +} + +int CInputMain::HandleQuestCancel(LPDESC d, const char*) +{ + QuestCancel(d->GetCharacter()); + return 0; +} + +int CInputMain::HandleSafeboxCheckout(LPDESC d, const char* c_pData) +{ + SafeboxCheckout(d->GetCharacter(), c_pData, false); + return 0; +} + +int CInputMain::HandleMallCheckout(LPDESC d, const char* c_pData) +{ + SafeboxCheckout(d->GetCharacter(), c_pData, true); + return 0; +} + +int CInputMain::HandleGuild(LPDESC d, const char* c_pData) +{ + return Guild(d->GetCharacter(), c_pData, m_iBufferLeft); +} + +int CInputMain::HandleMyShop(LPDESC d, const char* c_pData) +{ + return MyShop(d->GetCharacter(), c_pData, m_iBufferLeft); +} + +int CInputMain::HandleClientVersion(LPDESC d, const char* c_pData) +{ + Version(d->GetCharacter(), c_pData); + return 0; +} + +int CInputMain::HandleDragonSoulRefine(LPDESC d, const char* c_pData) +{ + LPCHARACTER ch = d->GetCharacter(); + TPacketCGDragonSoulRefine* p = reinterpret_cast((void*)c_pData); + switch (p->bSubType) + { + case DragonSoulSub::CLOSE: + ch->DragonSoul_RefineWindow_Close(); + break; + case DragonSoulSub::DO_REFINE_GRADE: + DSManager::instance().DoRefineGrade(ch, p->ItemGrid); + break; + case DragonSoulSub::DO_REFINE_STEP: + DSManager::instance().DoRefineStep(ch, p->ItemGrid); + break; + case DragonSoulSub::DO_REFINE_STRENGTH: + DSManager::instance().DoRefineStrength(ch, p->ItemGrid); + break; + } + return 0; +} + +// --------------------------------------------------------------------------- +// Handler registration tables +// --------------------------------------------------------------------------- + +void CInputMain::RegisterHandlers() +{ + auto reg = [this](uint16_t h, MainHandler fn, bool blockObs = false) { + m_handlers[h] = { fn, blockObs }; + }; + + // Pong + reg(CG::PONG, &CInputMain::HandlePong); + + // Variable-length (custom adapters) + reg(CG::CHAT, &CInputMain::HandleChat); + reg(CG::WHISPER, &CInputMain::HandleWhisper); + reg(CG::SHOP, &CInputMain::HandleShop); + reg(CG::MESSENGER, &CInputMain::HandleMessenger); + reg(CG::SYNC_POSITION, &CInputMain::HandleSyncPosition); + reg(CG::GUILD, &CInputMain::HandleGuild); + reg(CG::MYSHOP, &CInputMain::HandleMyShop); + + // Special (custom adapters) + reg(CG::MOVE, &CInputMain::HandleMove); + reg(CG::ATTACK, &CInputMain::HandleAttack, true); + reg(CG::SHOOT, &CInputMain::HandleShoot, true); + reg(CG::FLY_TARGETING, &CInputMain::HandleFlyTargeting); + reg(CG::ADD_FLY_TARGETING, &CInputMain::HandleAddFlyTargeting); + reg(CG::QUEST_CANCEL, &CInputMain::HandleQuestCancel); + reg(CG::SAFEBOX_CHECKOUT, &CInputMain::HandleSafeboxCheckout); + reg(CG::MALL_CHECKOUT, &CInputMain::HandleMallCheckout); + reg(CG::CLIENT_VERSION, &CInputMain::HandleClientVersion); + reg(CG::DRAGON_SOUL_REFINE,&CInputMain::HandleDragonSoulRefine); + + // Simple void(LPCHARACTER, const char*) — via template adapter + reg(CG::CHARACTER_POSITION,&CInputMain::SimpleHandler<&CInputMain::Position>); + reg(CG::ITEM_USE, &CInputMain::SimpleHandler<&CInputMain::ItemUse>, true); + reg(CG::ITEM_DROP, &CInputMain::SimpleHandler<&CInputMain::ItemDrop>, true); + reg(CG::ITEM_DROP2, &CInputMain::SimpleHandler<&CInputMain::ItemDrop2>, true); + reg(CG::ITEM_MOVE, &CInputMain::SimpleHandler<&CInputMain::ItemMove>, true); + reg(CG::ITEM_PICKUP, &CInputMain::SimpleHandler<&CInputMain::ItemPickup>, true); + reg(CG::ITEM_USE_TO_ITEM, &CInputMain::SimpleHandler<&CInputMain::ItemToItem>, true); + reg(CG::ITEM_GIVE, &CInputMain::SimpleHandler<&CInputMain::ItemGive>, true); + reg(CG::EXCHANGE, &CInputMain::SimpleHandler<&CInputMain::Exchange>, true); + reg(CG::USE_SKILL, &CInputMain::SimpleHandler<&CInputMain::UseSkill>, true); + reg(CG::QUICKSLOT_ADD, &CInputMain::SimpleHandler<&CInputMain::QuickslotAdd>); + reg(CG::QUICKSLOT_DEL, &CInputMain::SimpleHandler<&CInputMain::QuickslotDelete>); + reg(CG::QUICKSLOT_SWAP, &CInputMain::SimpleHandler<&CInputMain::QuickslotSwap>); + reg(CG::ON_CLICK, &CInputMain::SimpleHandler<&CInputMain::OnClick>); + reg(CG::TARGET, &CInputMain::SimpleHandler<&CInputMain::Target>); + reg(CG::WARP, &CInputMain::SimpleHandler<&CInputMain::Warp>); + reg(CG::SAFEBOX_CHECKIN, &CInputMain::SimpleHandler<&CInputMain::SafeboxCheckin>); + reg(CG::SAFEBOX_ITEM_MOVE, &CInputMain::SimpleHandler<&CInputMain::SafeboxItemMove>); + reg(CG::PARTY_INVITE, &CInputMain::SimpleHandler<&CInputMain::PartyInvite>); + reg(CG::PARTY_REMOVE, &CInputMain::SimpleHandler<&CInputMain::PartyRemove>); + reg(CG::PARTY_INVITE_ANSWER,&CInputMain::SimpleHandler<&CInputMain::PartyInviteAnswer>); + reg(CG::PARTY_SET_STATE, &CInputMain::SimpleHandler<&CInputMain::PartySetState>); + reg(CG::PARTY_USE_SKILL, &CInputMain::SimpleHandler<&CInputMain::PartyUseSkill>); + reg(CG::PARTY_PARAMETER, &CInputMain::SimpleHandler<&CInputMain::PartyParameter>); + reg(CG::ANSWER_MAKE_GUILD, &CInputMain::SimpleHandler<&CInputMain::AnswerMakeGuild>); + reg(CG::FISHING, &CInputMain::SimpleHandler<&CInputMain::Fishing>); + reg(CG::HACK, &CInputMain::SimpleHandler<&CInputMain::Hack>); + reg(CG::REFINE, &CInputMain::SimpleHandler<&CInputMain::Refine>); + + // void(LPCHARACTER, const void*) — via template adapter + reg(CG::SCRIPT_ANSWER, &CInputMain::SimpleHandlerV<&CInputMain::ScriptAnswer>); + reg(CG::SCRIPT_BUTTON, &CInputMain::SimpleHandlerV<&CInputMain::ScriptButton>); + reg(CG::SCRIPT_SELECT_ITEM, &CInputMain::SimpleHandlerV<&CInputMain::ScriptSelectItem>); + reg(CG::QUEST_INPUT_STRING, &CInputMain::SimpleHandlerV<&CInputMain::QuestInputString>); + reg(CG::QUEST_CONFIRM, &CInputMain::SimpleHandlerV<&CInputMain::QuestConfirm>); +} + +// --------------------------------------------------------------------------- +// Table-driven Analyze — replaces switch statement +// --------------------------------------------------------------------------- + +int CInputMain::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) +{ + LPCHARACTER ch = d->GetCharacter(); + + if (!ch) { sys_err("no character on desc"); d->SetPhase(PHASE_CLOSE); - return (0); + return 0; } - int iExtraLen = 0; - - if (test_server && bHeader != HEADER_CG_MOVE) - sys_log(0, "CInputMain::Analyze() ==> Header [%d] ", bHeader); - - switch (bHeader) + auto it = m_handlers.find(wHeader); + if (it == m_handlers.end()) { - case HEADER_CG_PONG: - Pong(d); - break; - - case HEADER_CG_TIME_SYNC: - Handshake(d, c_pData); - break; - - case HEADER_CG_CHAT: - if (test_server) - { - char* pBuf = (char*)c_pData; - sys_log(0, "%s", pBuf + sizeof(TPacketCGChat)); - } - - if ((iExtraLen = Chat(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_CG_WHISPER: - if ((iExtraLen = Whisper(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_CG_MOVE: - Move(ch, c_pData); - - if (LC_IsEurope()) - { - if (g_bCheckClientVersion) - { - int version = atoi(g_stClientVersion.c_str()); - int date = atoi(d->GetClientVersion()); - - //if (0 != g_stClientVersion.compare(d->GetClientVersion())) - // if (version > date) - if (version != date) // Fix - { - ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요.")); - d->DelayedDisconnect(10); - LogManager::instance().HackLog("VERSION_CONFLICT", d->GetAccountTable().login, ch->GetName(), d->GetHostName()); - } - } - } - else - { - if (!*d->GetClientVersion()) - { - sys_err("Version not recieved name %s", ch->GetName()); - d->SetPhase(PHASE_CLOSE); - } - } - break; - - case HEADER_CG_CHARACTER_POSITION: - Position(ch, c_pData); - break; - - case HEADER_CG_ITEM_USE: - if (!ch->IsObserverMode()) - ItemUse(ch, c_pData); - break; - - case HEADER_CG_ITEM_DROP: - if (!ch->IsObserverMode()) - { - ItemDrop(ch, c_pData); - } - break; - - case HEADER_CG_ITEM_DROP2: - if (!ch->IsObserverMode()) - ItemDrop2(ch, c_pData); - break; - - case HEADER_CG_ITEM_MOVE: - if (!ch->IsObserverMode()) - ItemMove(ch, c_pData); - break; - - case HEADER_CG_ITEM_PICKUP: - if (!ch->IsObserverMode()) - ItemPickup(ch, c_pData); - break; - - case HEADER_CG_ITEM_USE_TO_ITEM: - if (!ch->IsObserverMode()) - ItemToItem(ch, c_pData); - break; - - case HEADER_CG_ITEM_GIVE: - if (!ch->IsObserverMode()) - ItemGive(ch, c_pData); - break; - - case HEADER_CG_EXCHANGE: - if (!ch->IsObserverMode()) - Exchange(ch, c_pData); - break; - - case HEADER_CG_ATTACK: - case HEADER_CG_SHOOT: - if (!ch->IsObserverMode()) - { - Attack(ch, bHeader, c_pData); - } - break; - - case HEADER_CG_USE_SKILL: - if (!ch->IsObserverMode()) - UseSkill(ch, c_pData); - break; - - case HEADER_CG_QUICKSLOT_ADD: - QuickslotAdd(ch, c_pData); - break; - - case HEADER_CG_QUICKSLOT_DEL: - QuickslotDelete(ch, c_pData); - break; - - case HEADER_CG_QUICKSLOT_SWAP: - QuickslotSwap(ch, c_pData); - break; - - case HEADER_CG_SHOP: - if ((iExtraLen = Shop(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_CG_MESSENGER: - if ((iExtraLen = Messenger(ch, c_pData, m_iBufferLeft))<0) - return -1; - break; - - case HEADER_CG_ON_CLICK: - OnClick(ch, c_pData); - break; - - case HEADER_CG_SYNC_POSITION: - if ((iExtraLen = SyncPosition(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_CG_ADD_FLY_TARGETING: - case HEADER_CG_FLY_TARGETING: - FlyTarget(ch, c_pData, bHeader); - break; - - case HEADER_CG_SCRIPT_BUTTON: - ScriptButton(ch, c_pData); - break; - - // SCRIPT_SELECT_ITEM - case HEADER_CG_SCRIPT_SELECT_ITEM: - ScriptSelectItem(ch, c_pData); - break; - // END_OF_SCRIPT_SELECT_ITEM - - case HEADER_CG_SCRIPT_ANSWER: - ScriptAnswer(ch, c_pData); - break; - - case HEADER_CG_QUEST_INPUT_STRING: - QuestInputString(ch, c_pData); - break; - - case HEADER_CG_QUEST_CONFIRM: - QuestConfirm(ch, c_pData); - break; - - case HEADER_CG_QUEST_CANCEL: - QuestCancel(ch); - break; - - case HEADER_CG_TARGET: - Target(ch, c_pData); - break; - - case HEADER_CG_WARP: - Warp(ch, c_pData); - break; - - case HEADER_CG_SAFEBOX_CHECKIN: - SafeboxCheckin(ch, c_pData); - break; - - case HEADER_CG_SAFEBOX_CHECKOUT: - SafeboxCheckout(ch, c_pData, false); - break; - - case HEADER_CG_SAFEBOX_ITEM_MOVE: - SafeboxItemMove(ch, c_pData); - break; - - case HEADER_CG_MALL_CHECKOUT: - SafeboxCheckout(ch, c_pData, true); - break; - - case HEADER_CG_PARTY_INVITE: - PartyInvite(ch, c_pData); - break; - - case HEADER_CG_PARTY_REMOVE: - PartyRemove(ch, c_pData); - break; - - case HEADER_CG_PARTY_INVITE_ANSWER: - PartyInviteAnswer(ch, c_pData); - break; - - case HEADER_CG_PARTY_SET_STATE: - PartySetState(ch, c_pData); - break; - - case HEADER_CG_PARTY_USE_SKILL: - PartyUseSkill(ch, c_pData); - break; - - case HEADER_CG_PARTY_PARAMETER: - PartyParameter(ch, c_pData); - break; - - case HEADER_CG_ANSWER_MAKE_GUILD: - AnswerMakeGuild(ch, c_pData); - break; - - case HEADER_CG_GUILD: - if ((iExtraLen = Guild(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_CG_FISHING: - Fishing(ch, c_pData); - break; - - case HEADER_CG_HACK: - Hack(ch, c_pData); - break; - - case HEADER_CG_MYSHOP: - if ((iExtraLen = MyShop(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_CG_REFINE: - Refine(ch, c_pData); - break; - - case HEADER_CG_CLIENT_VERSION: - Version(ch, c_pData); - break; - - case HEADER_CG_DRAGON_SOUL_REFINE: - { - TPacketCGDragonSoulRefine* p = reinterpret_cast ((void*)c_pData); - switch(p->bSubType) - { - case DS_SUB_HEADER_CLOSE: - ch->DragonSoul_RefineWindow_Close(); - break; - case DS_SUB_HEADER_DO_REFINE_GRADE: - { - DSManager::instance().DoRefineGrade(ch, p->ItemGrid); - } - break; - case DS_SUB_HEADER_DO_REFINE_STEP: - { - DSManager::instance().DoRefineStep(ch, p->ItemGrid); - } - break; - case DS_SUB_HEADER_DO_REFINE_STRENGTH: - { - DSManager::instance().DoRefineStrength(ch, p->ItemGrid); - } - break; - } - } - - break; + sys_err("CInputMain::Analyze: unknown header %d (0x%04X) from %s", wHeader, wHeader, ch->GetName()); + return 0; } - return (iExtraLen); + + if (it->second.blockInObserverMode && ch->IsObserverMode()) + return 0; + + return (this->*(it->second.handler))(d, c_pData); } -int CInputDead::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) -{ - LPCHARACTER ch; +// --------------------------------------------------------------------------- +// CInputDead — only allows PONG, CHAT, WHISPER, HACK +// --------------------------------------------------------------------------- - if (!(ch = d->GetCharacter())) +CInputDead::CInputDead() +{ + RegisterHandlers(); +} + +void CInputDead::RegisterHandlers() +{ + m_handlers.clear(); + m_handlers[CG::PONG] = { &CInputDead::HandlePong, false }; + m_handlers[CG::CHAT] = { &CInputDead::HandleChat, false }; + m_handlers[CG::WHISPER] = { &CInputDead::HandleWhisper, false }; + m_handlers[CG::HACK] = { &CInputDead::SimpleHandler<&CInputDead::Hack>, false }; +} + +int CInputDead::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) +{ + if (!d->GetCharacter()) { sys_err("no character on desc"); return 0; } - int iExtraLen = 0; + auto it = m_handlers.find(wHeader); + if (it == m_handlers.end()) + return 0; - switch (bHeader) - { - case HEADER_CG_PONG: - Pong(d); - break; - - case HEADER_CG_TIME_SYNC: - Handshake(d, c_pData); - break; - - case HEADER_CG_CHAT: - if ((iExtraLen = Chat(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - - break; - - case HEADER_CG_WHISPER: - if ((iExtraLen = Whisper(ch, c_pData, m_iBufferLeft)) < 0) - return -1; - - break; - - case HEADER_CG_HACK: - Hack(ch, c_pData); - break; - - default: - return (0); - } - - return (iExtraLen); + return (this->*(it->second.handler))(d, c_pData); } diff --git a/src/game/input_p2p.cpp b/src/game/input_p2p.cpp index 8837a1f..8a76e58 100644 --- a/src/game/input_p2p.cpp +++ b/src/game/input_p2p.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "config.h" #include "desc_client.h" #include "desc_manager.h" @@ -25,6 +25,7 @@ CInputP2P::CInputP2P() { BindPacketInfo(&m_packetInfoGG); + RegisterHandlers(); } void CInputP2P::Login(LPDESC d, const char * c_pData) @@ -56,12 +57,12 @@ int CInputP2P::Relay(LPDESC d, const char * c_pData, size_t uiBytes) LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindPC(p->szName); - const BYTE* c_pbData = (const BYTE *) (c_pData + sizeof(TPacketGGRelay)); + const char* c_pbData = c_pData + sizeof(TPacketGGRelay); if (!pkChr) return p->lSize; - if (*c_pbData == HEADER_GC_WHISPER) + if (*(const uint16_t*)c_pbData == GC::WHISPER) { if (pkChr->IsBlockMode(BLOCK_WHISPER)) { @@ -86,7 +87,7 @@ int CInputP2P::Relay(LPDESC d, const char * c_pData, size_t uiBytes) { ConvertEmpireText(bToEmpire, buf + sizeof(TPacketGCWhisper), - p2->wSize - sizeof(TPacketGCWhisper), + p2->length - sizeof(TPacketGCWhisper), 10+2*pkChr->GetSkillPower(SKILL_LANGUAGE1 + bToEmpire - 1)); } } @@ -119,46 +120,6 @@ int CInputP2P::Notice(LPDESC d, const char * c_pData, size_t uiBytes) return (p->lSize); } -int CInputP2P::MonarchNotice(LPDESC d, const char * c_pData, size_t uiBytes) -{ - TPacketGGMonarchNotice * p = (TPacketGGMonarchNotice *) c_pData; - - if (uiBytes < p->lSize + sizeof(TPacketGGMonarchNotice)) - return -1; - - if (p->lSize < 0) - { - sys_err("invalid packet length %d", p->lSize); - d->SetPhase(PHASE_CLOSE); - return -1; - } - - char szBuf[256+1]; - strlcpy(szBuf, c_pData + sizeof(TPacketGGMonarchNotice), MIN(p->lSize + 1, sizeof(szBuf))); - SendMonarchNotice(p->bEmpire, szBuf); - return (p->lSize); -} - -int CInputP2P::MonarchTransfer(LPDESC d, const char* c_pData) -{ - TPacketMonarchGGTransfer* p = (TPacketMonarchGGTransfer*) c_pData; - LPCHARACTER pTargetChar = CHARACTER_MANAGER::instance().FindByPID(p->dwTargetPID); - - if (pTargetChar != NULL) - { - unsigned int qIndex = quest::CQuestManager::instance().GetQuestIndexByName("monarch_transfer"); - - if (qIndex != 0) - { - pTargetChar->SetQuestFlag("monarch_transfer.x", p->x); - pTargetChar->SetQuestFlag("monarch_transfer.y", p->y); - quest::CQuestManager::instance().Letter(pTargetChar->GetPlayerID(), qIndex, 0); - } - } - - return 0; -} - int CInputP2P::Guild(LPDESC d, const char* c_pData, size_t uiBytes) { TPacketGGGuild * p = (TPacketGGGuild *) c_pData; @@ -169,7 +130,7 @@ int CInputP2P::Guild(LPDESC d, const char* c_pData, size_t uiBytes) switch (p->bSubHeader) { - case GUILD_SUBHEADER_GG_CHAT: + case GuildSub::GG::CHAT: { if (uiBytes < sizeof(TPacketGGGuildChat)) return -1; @@ -182,7 +143,7 @@ int CInputP2P::Guild(LPDESC d, const char* c_pData, size_t uiBytes) return sizeof(TPacketGGGuildChat); } - case GUILD_SUBHEADER_GG_SET_MEMBER_COUNT_BONUS: + case GuildSub::GG::SET_MEMBER_COUNT_BONUS: { if (uiBytes < sizeof(int)) return -1; @@ -314,9 +275,9 @@ void CInputP2P::MessengerRemove(const char * c_pData) if (deletee && deletee->GetDesc()) { TPacketGCMessenger pack; - pack.header = HEADER_GC_MESSENGER; - pack.subheader = MESSENGER_SUBHEADER_GC_REMOVE_FRIEND; - pack.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + strlen(p->szAccount); + pack.header = GC::MESSENGER; + pack.subheader = MessengerSub::GC::REMOVE_FRIEND; + pack.length = sizeof(TPacketGCMessenger) + sizeof(BYTE) + strlen(p->szAccount); BYTE bLen = strlen(p->szAccount); deletee->GetDesc()->BufferedPacket(&pack, sizeof(pack)); @@ -336,7 +297,8 @@ void CInputP2P::FindPosition(LPDESC d, const char* c_pData) if (ch && ch->GetMapIndex() < 10000) { TPacketGGWarpCharacter pw; - pw.header = HEADER_GG_WARP_CHARACTER; + pw.header = GG::WARP_CHARACTER; + pw.length = sizeof(pw); pw.pid = p->dwFromPID; pw.x = ch->GetX(); pw.y = ch->GetY(); @@ -397,7 +359,8 @@ void CInputP2P::XmasWarpSanta(const char * c_pData) xmas::SpawnSanta(p->lMapIndex, iNextSpawnDelay); // 50분있다가 새로운 산타가 나타남 (한국은 20분) TPacketGGXmasWarpSantaReply pack_reply; - pack_reply.bHeader = HEADER_GG_XMAS_WARP_SANTA_REPLY; + pack_reply.header = GG::XMAS_WARP_SANTA_REPLY; + pack_reply.length = sizeof(pack_reply); pack_reply.bChannel = g_bChannel; P2P_MANAGER::instance().Send(&pack_reply, sizeof(pack_reply)); } @@ -461,7 +424,8 @@ void CInputP2P::IamAwake(LPDESC d, const char * c_pData) void BroadcastGuildMarkUpdate(DWORD dwGuildID, WORD wImgIdx) { TPacketGCMarkUpdate packet; - packet.header = HEADER_GC_MARK_UPDATE; + packet.header = GC::MARK_UPDATE; + packet.length = sizeof(packet); packet.guildID = dwGuildID; packet.imgIdx = wImgIdx; @@ -485,136 +449,96 @@ void CInputP2P::GuildMarkUpdate(const char * c_pData) BroadcastGuildMarkUpdate(p->dwGuildID, p->wImgIdx); } -int CInputP2P::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) + +// Custom adapters for non-standard handler signatures + +int CInputP2P::HandleRelay(LPDESC d, const char* c_pData) { - if (test_server) - sys_log(0, "CInputP2P::Anlayze[Header %d]", bHeader); - - int iExtraLen = 0; - - switch (bHeader) - { - case HEADER_GG_SETUP: - Setup(d, c_pData); - break; - - case HEADER_GG_LOGIN: - Login(d, c_pData); - break; - - case HEADER_GG_LOGOUT: - Logout(d, c_pData); - break; - - case HEADER_GG_RELAY: - if ((iExtraLen = Relay(d, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_GG_NOTICE: - if ((iExtraLen = Notice(d, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_GG_SHUTDOWN: - sys_err("Accept shutdown p2p command from %s.", d->GetHostName()); - Shutdown(10); - break; - - case HEADER_GG_GUILD: - if ((iExtraLen = Guild(d, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_GG_SHOUT: - Shout(c_pData); - break; - - case HEADER_GG_DISCONNECT: - Disconnect(c_pData); - break; - - case HEADER_GG_MESSENGER_ADD: - MessengerAdd(c_pData); - break; - - case HEADER_GG_MESSENGER_REQUEST_ADD: - MessengerRequestAdd(c_pData); - break; - - case HEADER_GG_MESSENGER_RESPONSE: - MessengerResponse(c_pData); - break; - - case HEADER_GG_MESSENGER_REMOVE: - MessengerRemove(c_pData); - break; - - case HEADER_GG_FIND_POSITION: - FindPosition(d, c_pData); - break; - - case HEADER_GG_WARP_CHARACTER: - WarpCharacter(c_pData); - break; - - case HEADER_GG_GUILD_WAR_ZONE_MAP_INDEX: - GuildWarZoneMapIndex(c_pData); - break; - - case HEADER_GG_TRANSFER: - Transfer(c_pData); - break; - - case HEADER_GG_XMAS_WARP_SANTA: - XmasWarpSanta(c_pData); - break; - - case HEADER_GG_XMAS_WARP_SANTA_REPLY: - XmasWarpSantaReply(c_pData); - break; - - case HEADER_GG_RELOAD_CRC_LIST: - LoadValidCRCList(); - break; - - case HEADER_GG_CHECK_CLIENT_VERSION: - CheckClientVersion(); - break; - - case HEADER_GG_LOGIN_PING: - LoginPing(d, c_pData); - break; - - case HEADER_GG_BLOCK_CHAT: - BlockChat(c_pData); - break; - - case HEADER_GG_SIEGE: - { - TPacketGGSiege* pSiege = (TPacketGGSiege*)c_pData; - castle_siege(pSiege->bEmpire, pSiege->bTowerCount); - } - break; - - case HEADER_GG_MONARCH_NOTICE: - if ((iExtraLen = MonarchNotice(d, c_pData, m_iBufferLeft)) < 0) - return -1; - break; - - case HEADER_GG_MONARCH_TRANSFER : - MonarchTransfer(d, c_pData); - break; - - case HEADER_GG_CHECK_AWAKENESS: - IamAwake(d, c_pData); - break; - - case HEADER_GG_MARK_UPDATE: - GuildMarkUpdate(c_pData); - break; - } - - return (iExtraLen); + return Relay(d, c_pData, m_iBufferLeft); } +int CInputP2P::HandleNotice(LPDESC d, const char* c_pData) +{ + return Notice(d, c_pData, m_iBufferLeft); +} + +int CInputP2P::HandleGuild(LPDESC d, const char* c_pData) +{ + return Guild(d, c_pData, m_iBufferLeft); +} + +int CInputP2P::HandleShutdown(LPDESC d, const char*) +{ + sys_err("Accept shutdown p2p command from %s.", d->GetHostName()); + Shutdown(10); + return 0; +} + +int CInputP2P::HandleSiege(LPDESC, const char* c_pData) +{ + TPacketGGSiege* p = (TPacketGGSiege*)c_pData; + castle_siege(p->bEmpire, p->bTowerCount); + return 0; +} + +int CInputP2P::HandleReloadCRC(LPDESC, const char*) +{ + LoadValidCRCList(); + return 0; +} + +int CInputP2P::HandleCheckClientVersion(LPDESC, const char*) +{ + CheckClientVersion(); + return 0; +} + +void CInputP2P::RegisterHandlers() +{ + // void(LPDESC, const char*) — via DescHandler template + m_handlers[GG::SETUP] = &CInputP2P::DescHandler<&CInputP2P::Setup>; + m_handlers[GG::LOGIN] = &CInputP2P::DescHandler<&CInputP2P::Login>; + m_handlers[GG::LOGOUT] = &CInputP2P::DescHandler<&CInputP2P::Logout>; + m_handlers[GG::FIND_POSITION] = &CInputP2P::DescHandler<&CInputP2P::FindPosition>; + m_handlers[GG::LOGIN_PING] = &CInputP2P::DescHandler<&CInputP2P::LoginPing>; + m_handlers[GG::CHECK_AWAKENESS] = &CInputP2P::DescHandler<&CInputP2P::IamAwake>; + + // void(const char*) — via DataHandler template + m_handlers[GG::SHOUT] = &CInputP2P::DataHandler<&CInputP2P::Shout>; + m_handlers[GG::DISCONNECT] = &CInputP2P::DataHandler<&CInputP2P::Disconnect>; + m_handlers[GG::MESSENGER_ADD] = &CInputP2P::DataHandler<&CInputP2P::MessengerAdd>; + m_handlers[GG::MESSENGER_REMOVE] = &CInputP2P::DataHandler<&CInputP2P::MessengerRemove>; + m_handlers[GG::MESSENGER_REQUEST_ADD] = &CInputP2P::DataHandler<&CInputP2P::MessengerRequestAdd>; + m_handlers[GG::MESSENGER_RESPONSE] = &CInputP2P::DataHandler<&CInputP2P::MessengerResponse>; + m_handlers[GG::WARP_CHARACTER] = &CInputP2P::DataHandler<&CInputP2P::WarpCharacter>; + m_handlers[GG::GUILD_WAR_ZONE_MAP_INDEX] = &CInputP2P::DataHandler<&CInputP2P::GuildWarZoneMapIndex>; + m_handlers[GG::TRANSFER] = &CInputP2P::DataHandler<&CInputP2P::Transfer>; + m_handlers[GG::XMAS_WARP_SANTA] = &CInputP2P::DataHandler<&CInputP2P::XmasWarpSanta>; + m_handlers[GG::XMAS_WARP_SANTA_REPLY] = &CInputP2P::DataHandler<&CInputP2P::XmasWarpSantaReply>; + m_handlers[GG::BLOCK_CHAT] = &CInputP2P::DataHandler<&CInputP2P::BlockChat>; + m_handlers[GG::MARK_UPDATE] = &CInputP2P::DataHandler<&CInputP2P::GuildMarkUpdate>; + + // Custom adapters (variable-length or special signatures) + m_handlers[GG::RELAY] = &CInputP2P::HandleRelay; + m_handlers[GG::NOTICE] = &CInputP2P::HandleNotice; + m_handlers[GG::GUILD] = &CInputP2P::HandleGuild; + m_handlers[GG::SHUTDOWN] = &CInputP2P::HandleShutdown; + m_handlers[GG::SIEGE] = &CInputP2P::HandleSiege; + m_handlers[GG::RELOAD_CRC_LIST] = &CInputP2P::HandleReloadCRC; + m_handlers[GG::CHECK_CLIENT_VERSION] = &CInputP2P::HandleCheckClientVersion; +} + +int CInputP2P::Analyze(LPDESC d, uint16_t wHeader, const char * c_pData) +{ + if (test_server) + sys_log(0, "CInputP2P::Anlayze[Header %d]", wHeader); + + auto it = m_handlers.find(wHeader); + if (it == m_handlers.end()) + { + sys_err("CInputP2P::Analyze: unknown header %d (0x%04X) from %s", wHeader, wHeader, d->GetHostName()); + return 0; + } + + return (this->*(it->second))(d, c_pData); +} diff --git a/src/game/input_udp.cpp b/src/game/input_udp.cpp deleted file mode 100644 index 22d816b..0000000 --- a/src/game/input_udp.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "stdafx.h" -#include "constants.h" -#include "config.h" -#include "input.h" -#include "desc.h" -#include "desc_manager.h" -#include "item_manager.h" -#include "char_manager.h" -#include "protocol.h" - -extern socket_t udp_socket; - -#define HEADER_CG_STATE_CHECKER 1 - -#pragma pack(1) - -typedef unsigned long ServerStateChecker_Key; -typedef unsigned long ServerStateChecker_Index; -typedef unsigned char ServerStateChecker_State; - -struct ServerStateChecker_RequestPacket -{ - BYTE header; - ServerStateChecker_Key key; - ServerStateChecker_Index index; -}; - -struct ServerStateChecker_ResponsePacket -{ - BYTE header; - ServerStateChecker_Key key; - ServerStateChecker_Index index; - ServerStateChecker_State state; -}; - -#pragma pack() - -///--------------------------------------------------------- - -CPacketInfoUDP::CPacketInfoUDP() -{ - Set(1, sizeof(ServerStateChecker_RequestPacket), "ServerStateRequest", false); -} - -CPacketInfoUDP::~CPacketInfoUDP() -{ - Log("udp_packet_info.txt"); -} - - -CInputUDP::CInputUDP() -{ - memset( &m_SockAddr, 0, sizeof(m_SockAddr) ); - - BindPacketInfo(&m_packetInfoUDP); -} - -void CInputUDP::Handshake(LPDESC pDesc, const char * c_pData) -{ - TPacketCGHandshake * pInfo = (TPacketCGHandshake *) c_pData; - - if (pDesc->GetHandshake() == pInfo->dwHandshake) - { - sys_log(0, "UDP: Grant %s:%d", inet_ntoa(m_SockAddr.sin_addr), m_SockAddr.sin_port); - pDesc->UDPGrant(m_SockAddr); - return; - } - else - sys_log(0, "UDP: Handshake differs %s", pDesc->GetHostName()); -} - -void CInputUDP::StateChecker(const char * c_pData) -{ - // NOTE : TCP 연결로 바꾸면서 사용 X - /* - struct ServerStateChecker_RequestPacket * p = (struct ServerStateChecker_RequestPacket *) c_pData; - ServerStateChecker_ResponsePacket rp; - - int iTotal; - int * paiEmpireUserCount; - int iLocal; - - DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal); - - rp.header = 1; - rp.key = p->key; - rp.index = p->index; - - if (g_bNoMoreClient) - rp.state = 0; - else - rp.state = iTotal > g_iFullUserCount ? 3 : iTotal > g_iBusyUserCount ? 2 : 1; - - if (sendto(udp_socket, (const char*)&rp, sizeof(rp), 0, (const struct sockaddr *) &m_SockAddr, sizeof(m_SockAddr)) < 0) - { - sys_err("cannot sendto datagram socket : %s, %d", inet_ntoa(m_SockAddr.sin_addr), inet_ntoa(m_SockAddr.sin_addr)); - return; - } - */ -} - -int CInputUDP::Analyze(LPDESC pDesc, BYTE bHeader, const char * c_pData) -{ - switch (bHeader) - { - /* - case HEADER_CG_HANDSHAKE: - Handshake(pDesc, c_pData); - break; - - case HEADER_CG_STATE_CHECKER: - StateChecker(c_pData); - break; - */ - - default: - sys_err("unknown UDP header %u", bHeader); - break; - } - - return 0; -} - -bool CInputUDP::Process(LPDESC pDesc, const void * c_pvOrig, int iBytes, int & r_iBytesProceed) -{ - /* - const char * c_pData = static_cast (c_pvOrig); - - BYTE bLastHeader = 0; - int iLastPacketLen = 0; - int iPacketLen; - - if (!m_pPacketInfo) - { - sys_err("No packet info has been binded to"); - return true; - } - - for (m_iBufferLeft = iBytes; m_iBufferLeft > 0;) - { - if (m_iBufferLeft < 5) - return true; - - BYTE bHeader = (BYTE) *(c_pData); - const char * c_pszName; - - if (!m_pPacketInfo->Get(bHeader, &iPacketLen, &c_pszName)) - { - sys_err("UNKNOWN HEADER: %d, LAST HEADER: %d(%d), REMAIN BYTES: %d", - bHeader, bLastHeader, iLastPacketLen, m_iBufferLeft); - //printdata((BYTE *) c_pvOrig, iBytes); - return true; - } - - //DWORD dwHandshake = *(DWORD *) (c_pData + 1); - //pDesc = DESC_MANAGER::instance().FindByHandshake(dwHandshake); - - //if (!pDesc) - //{ - //sys_err("No desc by handshake %u", dwHandshake); - //return true; - //} - - //if (m_SockAddr.sin_addr.s_addr != pDesc->GetAddr().sin_addr.s_addr) - //{ - //sys_err("Hostname Mismatch! %s != %s", inet_ntoa(m_SockAddr.sin_addr), pDesc->GetHostName()); - //return true; - //} - - if (m_iBufferLeft < iPacketLen) - return true; - - int iExtraPacketSize = Analyze(pDesc, bHeader, c_pData); - - if (iExtraPacketSize < 0) - return true; - - iPacketLen += iExtraPacketSize; - - c_pData += iPacketLen; - m_iBufferLeft -= iPacketLen; - r_iBytesProceed += iPacketLen; - - iLastPacketLen = iPacketLen; - bLastHeader = bHeader; - - //if (GetType() != pDesc->GetInputProcessor()->GetType()) - //return false; - } - - */ - return true; -} - diff --git a/src/game/item.cpp b/src/game/item.cpp index c620ff6..7735d21 100644 --- a/src/game/item.cpp +++ b/src/game/item.cpp @@ -1,10 +1,10 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "config.h" #include "char.h" #include "desc.h" #include "sectree_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "protocol.h" #include "log.h" #include "skill.h" @@ -126,7 +126,8 @@ void CItem::EncodeInsertPacket(LPENTITY ent) struct packet_item_ground_add pack; - pack.bHeader = HEADER_GC_ITEM_GROUND_ADD; + pack.header = GC::ITEM_GROUND_ADD; + pack.length = sizeof(pack); pack.x = c_pos.x; pack.y = c_pos.y; pack.z = c_pos.z; @@ -148,7 +149,8 @@ void CItem::EncodeInsertPacket(LPENTITY ent) TPacketGCItemOwnership p; - p.bHeader = HEADER_GC_ITEM_OWNERSHIP; + p.header = GC::ITEM_OWNERSHIP; + p.length = sizeof(p); p.dwVID = m_dwVID; strlcpy(p.szName, info->szOwnerName, sizeof(p.szName)); @@ -165,7 +167,8 @@ void CItem::EncodeRemovePacket(LPENTITY ent) struct packet_item_ground_del pack; - pack.bHeader = HEADER_GC_ITEM_GROUND_DEL; + pack.header = GC::ITEM_GROUND_DEL; + pack.length = sizeof(pack); pack.dwVID = m_dwVID; d->Packet(&pack, sizeof(pack)); @@ -184,7 +187,7 @@ void CItem::UsePacketEncode(LPCHARACTER ch, LPCHARACTER victim, struct packet_it if (!GetVnum()) return; - packet->header = HEADER_GC_ITEM_USE; + packet->header = GC::ITEM_USE; packet->ch_vid = ch->GetVID(); packet->victim_vid = victim->GetVID(); packet->Cell = TItemPos(GetWindow(), m_wCell); @@ -208,7 +211,8 @@ void CItem::UpdatePacket() TPacketGCItemUpdate pack; - pack.header = HEADER_GC_ITEM_UPDATE; + pack.header = GC::ITEM_UPDATE; + pack.length = sizeof(pack); pack.Cell = TItemPos(GetWindow(), m_wCell); pack.count = m_dwCount; @@ -1117,7 +1121,8 @@ EVENTFUNC(ownership_event) TPacketGCItemOwnership p; - p.bHeader = HEADER_GC_ITEM_OWNERSHIP; + p.header = GC::ITEM_OWNERSHIP; + p.length = sizeof(p); p.dwVID = pkItem->GetVID(); p.szName[0] = '\0'; @@ -1141,7 +1146,8 @@ void CItem::SetOwnership(LPCHARACTER ch, int iSec) TPacketGCItemOwnership p; - p.bHeader = HEADER_GC_ITEM_OWNERSHIP; + p.header = GC::ITEM_OWNERSHIP; + p.length = sizeof(p); p.dwVID = m_dwVID; p.szName[0] = '\0'; @@ -1169,7 +1175,8 @@ void CItem::SetOwnership(LPCHARACTER ch, int iSec) TPacketGCItemOwnership p; - p.bHeader = HEADER_GC_ITEM_OWNERSHIP; + p.header = GC::ITEM_OWNERSHIP; + p.length = sizeof(p); p.dwVID = m_dwVID; strlcpy(p.szName, ch->GetName(), sizeof(p.szName)); diff --git a/src/game/item_manager.cpp b/src/game/item_manager.cpp index 23ba2dd..f1d1e36 100644 --- a/src/game/item_manager.cpp +++ b/src/game/item_manager.cpp @@ -441,7 +441,7 @@ void ITEM_MANAGER::SaveSingleItem(LPITEM item) DWORD dwID = item->GetID(); DWORD dwOwnerID = item->GetLastOwnerPID(); - db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_DESTROY, 0, sizeof(DWORD) + sizeof(DWORD)); + db_clientdesc->DBPacketHeader(GD::ITEM_DESTROY, 0, sizeof(DWORD) + sizeof(DWORD)); db_clientdesc->Packet(&dwID, sizeof(DWORD)); db_clientdesc->Packet(&dwOwnerID, sizeof(DWORD)); @@ -462,7 +462,7 @@ void ITEM_MANAGER::SaveSingleItem(LPITEM item) thecore_memcpy(t.alSockets, item->GetSockets(), sizeof(t.alSockets)); thecore_memcpy(t.aAttr, item->GetAttributes(), sizeof(t.aAttr)); - db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_SAVE, 0, sizeof(TPlayerItem)); + db_clientdesc->DBPacketHeader(GD::ITEM_SAVE, 0, sizeof(TPlayerItem)); db_clientdesc->Packet(&t, sizeof(TPlayerItem)); } @@ -561,7 +561,7 @@ void ITEM_MANAGER::DestroyItem(LPITEM item, const char* file, size_t line) { DWORD dwOwnerID = item->GetLastOwnerPID(); - db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_DESTROY, 0, sizeof(DWORD) + sizeof(DWORD)); + db_clientdesc->DBPacketHeader(GD::ITEM_DESTROY, 0, sizeof(DWORD) + sizeof(DWORD)); db_clientdesc->Packet(&dwID, sizeof(DWORD)); db_clientdesc->Packet(&dwOwnerID, sizeof(DWORD)); } diff --git a/src/game/item_manager_idrange.cpp b/src/game/item_manager_idrange.cpp index e10d137..5a2b5d5 100644 --- a/src/game/item_manager_idrange.cpp +++ b/src/game/item_manager_idrange.cpp @@ -1,4 +1,4 @@ - + #include "stdafx.h" #include "desc_client.h" #include "item_manager.h" @@ -35,7 +35,7 @@ DWORD ITEM_MANAGER::GetNewID() sys_log(0, "ItemIDRange: First Range is full. Change to SpareRange %u ~ %u %u", m_ItemIDSpareRange.dwMin, m_ItemIDSpareRange.dwMax, m_ItemIDSpareRange.dwUsableItemIDMin); - db_clientdesc->DBPacket(HEADER_GD_REQ_SPARE_ITEM_ID_RANGE, 0, &m_ItemIDRange.dwMax, sizeof(DWORD)); + db_clientdesc->DBPacket(GD::REQ_SPARE_ITEM_ID_RANGE, 0, &m_ItemIDRange.dwMax, sizeof(DWORD)); SetMaxItemID(m_ItemIDSpareRange); diff --git a/src/game/log.cpp b/src/game/log.cpp index 0323b51..dc912ce 100644 --- a/src/game/log.cpp +++ b/src/game/log.cpp @@ -278,7 +278,7 @@ void LogManager::DetailLoginLog(bool isLogin, LPCHARACTER ch) { Query("INSERT INTO loginlog2(type, is_gm, login_time, channel, account_id, pid, ip, client_version) " "VALUES('INVALID', %s, NOW(), %d, %u, %u, inet_aton('%s'), '%s')", - ch->IsGM() == true ? "'Y'" : "'N'", + ch->IsGM() ? "'Y'" : "'N'", g_bChannel, ch->GetDesc()->GetAccountTable().id, ch->GetPlayerID(), diff --git a/src/game/login_sim.h b/src/game/login_sim.h deleted file mode 100644 index a59d4d5..0000000 --- a/src/game/login_sim.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __INC_METIN_II_SERVER_LOGINSIM__ -#define __INC_METIN_II_SERVER_LOGINSIM__ - -#include "desc_client.h" - -class CLoginSim -{ - public: - CLoginSim() - { - memset(&auth, 0, sizeof(auth)); - memset(&login, 0, sizeof(login)); - memset(&load, 0, sizeof(load)); - memset(&logout, 0, sizeof(logout)); - vecIdx = 0; - bCheck = false; - } - - void AddPlayer(DWORD dwID) - { - vecID.push_back(dwID); - sys_log(0, "AddPlayer %lu", dwID); - } - - bool IsCheck() - { - return bCheck; - } - - void SendLogin() - { - bCheck = true; - - if (IsDone()) - return; - - if (vecIdx == 0) - db_clientdesc->DBPacket(HEADER_GD_AUTH_LOGIN, 0, &auth, sizeof(TPacketGDAuthLogin)); - - load.player_id = vecID[vecIdx++]; - db_clientdesc->DBPacket(HEADER_GD_LOGIN_BY_KEY, 0, &login, sizeof(TPacketGDLoginByKey)); - } - - void SendLoad() - { - db_clientdesc->DBPacket(HEADER_GD_PLAYER_LOAD, 0, &load, sizeof(TPlayerLoadPacket)); - } - - void SendLogout() - { - db_clientdesc->DBPacket(HEADER_GD_LOGOUT, 0, &logout, sizeof(TLogoutPacket)); - SendLogin(); - } - - bool IsDone() - { - if (vecIdx >= vecID.size()) - return true; - - return false; - } - - TPacketGDAuthLogin auth; - TPacketGDLoginByKey login; - TPlayerLoadPacket load; - TLogoutPacket logout; - - std::vector vecID; - unsigned int vecIdx; - bool bCheck; -}; - -#endif diff --git a/src/game/main.cpp b/src/game/main.cpp index 31b6956..edc25de 100644 --- a/src/game/main.cpp +++ b/src/game/main.cpp @@ -1,9 +1,11 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "config.h" #include "event.h" #include "minilzo.h" -#include "packet.h" +#include "packet_structs.h" +#include "desc.h" +#include "desc_client.h" #include "desc_manager.h" #include "item_manager.h" #include "char.h" @@ -32,17 +34,14 @@ #include "priv_manager.h" #include "war_map.h" #include "building.h" -#include "login_sim.h" #include "target.h" #include "marriage.h" #include "wedding.h" #include "fishing.h" #include "item_addon.h" -#include "TrafficProfiler.h" #include "locale_service.h" #include "arena.h" #include "OXEvent.h" -#include "monarch.h" #include "polymorph.h" #include "blend_item.h" #include "castle.h" @@ -55,6 +54,7 @@ #include "DragonLair.h" #include "skill_power.h" #include "DragonSoul.h" +#include "firewall_manager.h" // #ifndef OS_WINDOWS // #include @@ -79,10 +79,6 @@ void WriteMallocMessage(const char* p1, const char* p2, const char* p3, const ch } #endif -// TRAFFIC_PROFILER -static const DWORD TRAFFIC_PROFILE_FLUSH_CYCLE = 3600; ///< TrafficProfiler 의 Flush cycle. 1시간 간격 -// END_OF_TRAFFIC_PROFILER - // 게임과 연결되는 소켓 volatile int num_events_called = 0; int max_bytes_written = 0; @@ -91,9 +87,13 @@ int total_bytes_written = 0; BYTE g_bLogLevel = 0; socket_t tcp_socket = 0; -socket_t udp_socket = 0; socket_t p2p_socket = 0; +// UDP sink sockets — bound but never read, prevents kernel ICMP port-unreachable generation +// during UDP floods (kernel silently drops once the tiny receive buffer fills) +static socket_t udp_sink_game = INVALID_SOCKET; +static socket_t udp_sink_p2p = INVALID_SOCKET; + LPFDWATCH main_fdw = NULL; int io_loop(LPFDWATCH fdw); @@ -200,8 +200,6 @@ namespace }; } -extern std::map g_sim; // first: AID -extern std::map g_simByPID; extern std::vector g_vec_save; unsigned int save_idx = 0; @@ -222,42 +220,21 @@ void heartbeat(LPHEART ht, int pulse) { TPlayerCountPacket pack; pack.dwCount = DESC_MANAGER::instance().GetLocalUserCount(); - db_clientdesc->DBPacket(HEADER_GD_PLAYER_COUNT, 0, &pack, sizeof(TPlayerCountPacket)); + db_clientdesc->DBPacket(GD::PLAYER_COUNT, 0, &pack, sizeof(TPlayerCountPacket)); } else { DESC_MANAGER::instance().ProcessExpiredLoginKey(); } + if (save_idx < g_vec_save.size()) { - int count = 0; - itertype(g_sim) it = g_sim.begin(); + int count = MIN(100, g_vec_save.size() - save_idx); - while (it != g_sim.end()) - { - if (!it->second->IsCheck()) - { - it->second->SendLogin(); + for (int i = 0; i < count; ++i, ++save_idx) + db_clientdesc->DBPacket(GD::PLAYER_SAVE, 0, &g_vec_save[save_idx], sizeof(TPlayerTable)); - if (++count > 50) - { - sys_log(0, "FLUSH_SENT"); - break; - } - } - - it++; - } - - if (save_idx < g_vec_save.size()) - { - count = MIN(100, g_vec_save.size() - save_idx); - - for (int i = 0; i < count; ++i, ++save_idx) - db_clientdesc->DBPacket(HEADER_GD_PLAYER_SAVE, 0, &g_vec_save[save_idx], sizeof(TPlayerTable)); - - sys_log(0, "SAVE_FLUSH %d", count); - } + sys_log(0, "SAVE_FLUSH %d", count); } } @@ -358,12 +335,10 @@ int main(int argc, char **argv) CItemAddonManager item_addon_manager; CArenaManager arena_manager; COXEventManager OXEvent_manager; - CMonarch Monarch; CHorseNameManager horsename_manager; DESC_MANAGER desc_manager; - TrafficProfiler trafficProfiler; CTableBySkill SkillPowerByLevel; CPolymorphUtils polymorph_utils; CProfiler profiler; @@ -372,6 +347,7 @@ int main(int argc, char **argv) CThreeWayWar threeway_war; CDragonLairManager dl_manager; DSManager dsManager; + FirewallManager firewall_manager; if (!start(argc, argv)) { CleanUpForEarlyExit(); @@ -394,9 +370,6 @@ int main(int argc, char **argv) Blend_Item_init(); ani_init(); - if ( g_bTrafficProfileOn ) - TrafficProfiler::instance().Initialize( TRAFFIC_PROFILE_FLUSH_CYCLE, "ProfileLog" ); - while (idle()); sys_log(0, " Starting..."); @@ -448,6 +421,8 @@ int main(int argc, char **argv) char_manager.Destroy(); sys_log(0, " Destroying ITEM_MANAGER..."); item_manager.Destroy(); + sys_log(0, " Destroying FirewallManager..."); + firewall_manager.Destroy(); sys_log(0, " Destroying DESC_MANAGER..."); desc_manager.Destroy(); sys_log(0, " Destroying quest::CQuestManager..."); @@ -455,9 +430,6 @@ int main(int argc, char **argv) sys_log(0, " Destroying building::CManager..."); building_manager.Destroy(); - sys_log(0, " Flushing TrafficProfiler..."); - trafficProfiler.Flush(); - destroy(); #ifdef DEBUG_ALLOC @@ -468,6 +440,49 @@ int main(int argc, char **argv) return 1; } +// Create a UDP sink socket: bind to ip:port with minimal receive buffer, never read. +// Prevents ICMP port-unreachable replies during UDP floods — the kernel silently drops +// packets once the tiny buffer fills. Returns INVALID_SOCKET on failure (non-fatal). +static socket_t create_udp_sink(const char* ip, WORD port) +{ +#ifdef OS_WINDOWS + (void)ip; (void)port; + return INVALID_SOCKET; +#else + socket_t s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + { + sys_err("create_udp_sink: socket() failed for port %d: %s", port, strerror(errno)); + return INVALID_SOCKET; + } + + // Allow rebind if previous instance didn't clean up + int reuse = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + + // Minimal receive buffer — kernel rounds up to its minimum (typically 256 bytes on Linux). + // Once full, incoming UDP is silently dropped with zero CPU overhead. + int rcvbuf = 1; + setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(ip); + + if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + sys_err("create_udp_sink: bind() failed for port %d: %s", port, strerror(errno)); + close(s); + return INVALID_SOCKET; + } + + sys_log(0, "UDP sink bound on %s:%d (fd %d) — ICMP suppression active", ip, port, s); + return s; +#endif +} + void usage() { printf("Option list\n" @@ -546,12 +561,6 @@ int start(int argc, char **argv) case 'r': g_bNoRegen = true; break; - - // TRAFFIC_PROFILER - case 't': - g_bTrafficProfileOn = true; - break; - // END_OF_TRAFFIC_PROFILER } } @@ -593,15 +602,6 @@ int start(int argc, char **argv) return 0; } - -#ifndef __UDP_BLOCK__ - if ((udp_socket = socket_udp_bind(g_szPublicIP, mother_port)) == INVALID_SOCKET) - { - perror("socket_udp_bind: udp_socket"); - return 0; - } -#endif - // if internal ip exists, p2p socket uses internal ip, if not use public ip //if ((p2p_socket = socket_tcp_bind(*g_szInternalIP ? g_szInternalIP : g_szPublicIP, p2p_port)) == INVALID_SOCKET) if ((p2p_socket = socket_tcp_bind(g_szPublicIP, p2p_port)) == INVALID_SOCKET) @@ -611,11 +611,15 @@ int start(int argc, char **argv) } fdwatch_add_fd(main_fdw, tcp_socket, NULL, FDW_READ, false); -#ifndef __UDP_BLOCK__ - fdwatch_add_fd(main_fdw, udp_socket, NULL, FDW_READ, false); -#endif fdwatch_add_fd(main_fdw, p2p_socket, NULL, FDW_READ, false); + // UDP sink sockets — suppress ICMP port-unreachable during UDP floods + udp_sink_game = create_udp_sink(g_szPublicIP, mother_port); + udp_sink_p2p = create_udp_sink(g_szPublicIP, p2p_port); + + // Kernel-level firewall — DROP unsolicited UDP + rate-limit TCP SYN at netfilter layer + FirewallManager::instance().Initialize(mother_port, p2p_port); + db_clientdesc = DESC_MANAGER::instance().CreateConnectionDesc(main_fdw, db_addr, db_port, PHASE_DBCLIENT, true); if (!g_bAuthServer) { db_clientdesc->UpdateChannelStatus(0, true); @@ -663,11 +667,11 @@ void destroy() sys_log(0, " Closing sockets..."); socket_close(tcp_socket); -#ifndef __UDP_BLOCK__ - socket_close(udp_socket); -#endif socket_close(p2p_socket); + if (udp_sink_game != INVALID_SOCKET) { socket_close(udp_sink_game); udp_sink_game = INVALID_SOCKET; } + if (udp_sink_p2p != INVALID_SOCKET) { socket_close(udp_sink_p2p); udp_sink_p2p = INVALID_SOCKET; } + sys_log(0, " fdwatch_delete()..."); fdwatch_delete(main_fdw); @@ -773,28 +777,6 @@ int io_loop(LPFDWATCH fdw) DESC_MANAGER::instance().AcceptP2PDesc(fdw, p2p_socket); fdwatch_clear_event(fdw, p2p_socket, event_idx); } - /* - else if (FDW_READ == fdwatch_check_event(fdw, udp_socket, event_idx)) - { - char buf[256]; - struct sockaddr_in cliaddr; - socklen_t socklen = sizeof(cliaddr); - - int iBytesRead; - - if ((iBytesRead = socket_udp_read(udp_socket, buf, 256, (struct sockaddr *) &cliaddr, &socklen)) > 0) - { - static CInputUDP s_inputUDP; - - s_inputUDP.SetSockAddr(cliaddr); - - int iBytesProceed; - s_inputUDP.Process(NULL, buf, iBytesRead, iBytesProceed); - } - - fdwatch_clear_event(fdw, udp_socket, event_idx); - } - */ continue; } @@ -824,7 +806,7 @@ int io_loop(LPFDWATCH fdw) case FDW_WRITE: if (db_clientdesc == d) { - int buf_size = buffer_size(d->GetOutputBuffer()); + int buf_size = static_cast(d->GetOutputBufferSize()); int sock_buf_size = fdwatch_get_buffer_size(fdw, d->GetSocket()); int ret = d->ProcessOutput(); diff --git a/src/game/marriage.cpp b/src/game/marriage.cpp index df959e3..26f6c46 100644 --- a/src/game/marriage.cpp +++ b/src/game/marriage.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "char.h" #include "char_manager.h" #include "sectree_manager.h" @@ -44,7 +44,8 @@ namespace marriage { TPacketGCLoverInfo p; - p.header = HEADER_GC_LOVER_INFO; + p.header = GC::LOVER_INFO; + p.length = sizeof(p); strlcpy(p.name, lover_name.c_str(), sizeof(p.name)); p.love_point = love_point; ch->GetDesc()->Packet(&p, sizeof(p)); @@ -348,7 +349,8 @@ namespace marriage { byLastLovePoint = GetMarriagePoint(); TPacketGCLovePointUpdate p; - p.header = HEADER_GC_LOVE_POINT_UPDATE; + p.header = GC::LOVE_POINT_UPDATE; + p.length = sizeof(p); p.love_point = byLastLovePoint; ch1->GetDesc()->Packet(&p, sizeof(p)); @@ -554,7 +556,7 @@ namespace marriage p.dwPID2 = dwPID2; strlcpy(p.szName1, szName1, sizeof(p.szName1)); strlcpy(p.szName2, szName2, sizeof(p.szName2)); - db_clientdesc->DBPacket(HEADER_GD_MARRIAGE_ADD, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::MARRIAGE_ADD, 0, &p, sizeof(p)); } void CManager::Add(DWORD dwPID1, DWORD dwPID2, time_t tMarryTime, const char* szName1, const char* szName2) @@ -585,7 +587,7 @@ namespace marriage TPacketWeddingRequest p; p.dwPID1 = dwPID1; p.dwPID2 = dwPID2; - db_clientdesc->DBPacket(HEADER_GD_WEDDING_REQUEST, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::WEDDING_REQUEST, 0, &p, sizeof(p)); } } } @@ -599,7 +601,7 @@ namespace marriage p.dwPID2 = dwPID2; p.iLovePoint = iUpdatePoint; p.byMarried = byMarried; - db_clientdesc->DBPacket(HEADER_GD_MARRIAGE_UPDATE, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::MARRIAGE_UPDATE, 0, &p, sizeof(p)); } void CManager::Update(DWORD dwPID1, DWORD dwPID2, long lTotalPoint, BYTE byMarried) @@ -623,7 +625,7 @@ namespace marriage TPacketMarriageRemove p; p.dwPID1 = dwPID1; p.dwPID2 = dwPID2; - db_clientdesc->DBPacket(HEADER_GD_MARRIAGE_REMOVE, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::MARRIAGE_REMOVE, 0, &p, sizeof(p)); } void CManager::Remove(DWORD dwPID1, DWORD dwPID2) @@ -746,6 +748,6 @@ namespace marriage p.dwPID1 = dwPID1; p.dwPID2 = dwPID2; - db_clientdesc->DBPacket(HEADER_GD_WEDDING_END, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::WEDDING_END, 0, &p, sizeof(p)); } } diff --git a/src/game/messenger_manager.cpp b/src/game/messenger_manager.cpp index af90199..32a5fae 100644 --- a/src/game/messenger_manager.cpp +++ b/src/game/messenger_manager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "gm.h" #include "messenger_manager.h" @@ -139,7 +139,8 @@ void MessengerManager::RegisterRequestToAdd(const char* name, const char* target { // Send P2P response back to requester's core TPacketGGMessengerResponse p2pResp{}; - p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE; + p2pResp.header = GG::MESSENGER_RESPONSE; + p2pResp.length = sizeof(p2pResp); strlcpy(p2pResp.szRequester, name, sizeof(p2pResp.szRequester)); strlcpy(p2pResp.szTarget, targetName, sizeof(p2pResp.szTarget)); p2pResp.bResponseType = 0; // already_sent @@ -185,7 +186,8 @@ void MessengerManager::P2PRequestToAdd_Stage1(LPCHARACTER ch, const char* target } TPacketGGMessengerRequest p2pp{}; - p2pp.header = HEADER_GG_MESSENGER_REQUEST_ADD; + p2pp.header = GG::MESSENGER_REQUEST_ADD; + p2pp.length = sizeof(p2pp); strlcpy(p2pp.account, ch->GetName(), CHARACTER_NAME_MAX_LEN + 1); strlcpy(p2pp.target, targetName, CHARACTER_NAME_MAX_LEN + 1); P2P_MANAGER::Instance().Send(&p2pp, sizeof(TPacketGGMessengerRequest)); @@ -206,7 +208,8 @@ void MessengerManager::P2PRequestToAdd_Stage2(const char* characterName, LPCHARA { // Send response back to requester's core TPacketGGMessengerResponse p2pResp{}; - p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE; + p2pResp.header = GG::MESSENGER_RESPONSE; + p2pResp.length = sizeof(p2pResp); strlcpy(p2pResp.szRequester, characterName, sizeof(p2pResp.szRequester)); strlcpy(p2pResp.szTarget, target->GetName(), sizeof(p2pResp.szTarget)); p2pResp.bResponseType = 2; // quest_running @@ -218,7 +221,8 @@ void MessengerManager::P2PRequestToAdd_Stage2(const char* characterName, LPCHARA { // Send response back to requester's core TPacketGGMessengerResponse p2pResp{}; - p2pResp.bHeader = HEADER_GG_MESSENGER_RESPONSE; + p2pResp.header = GG::MESSENGER_RESPONSE; + p2pResp.length = sizeof(p2pResp); strlcpy(p2pResp.szRequester, characterName, sizeof(p2pResp.szRequester)); strlcpy(p2pResp.szTarget, target->GetName(), sizeof(p2pResp.szTarget)); p2pResp.bResponseType = 3; // blocking_requests @@ -504,7 +508,8 @@ void MessengerManager::AddToList(MessengerManager::keyA account, MessengerManage TPacketGGMessenger p2ppck; - p2ppck.bHeader = HEADER_GG_MESSENGER_ADD; + p2ppck.header = GG::MESSENGER_ADD; + p2ppck.length = sizeof(p2ppck); strlcpy(p2ppck.szAccount, account.c_str(), sizeof(p2ppck.szAccount)); strlcpy(p2ppck.szCompanion, companion.c_str(), sizeof(p2ppck.szCompanion)); P2P_MANAGER::instance().Send(&p2ppck, sizeof(TPacketGGMessenger)); @@ -524,9 +529,9 @@ void MessengerManager::__RemoveFromList(MessengerManager::keyA account, Messenge { TPacketGCMessenger p; - p.header = HEADER_GC_MESSENGER; - p.subheader = MESSENGER_SUBHEADER_GC_REMOVE_FRIEND; - p.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + account.size(); + p.header = GC::MESSENGER; + p.subheader = MessengerSub::GC::REMOVE_FRIEND; + p.length = sizeof(TPacketGCMessenger) + sizeof(BYTE) + account.size(); BYTE bLen = account.size(); tch->GetDesc()->BufferedPacket(&p, sizeof(p)); @@ -578,8 +583,9 @@ void MessengerManager::RemoveFromList(MessengerManager::keyA account, MessengerM __RemoveFromList(account, companion); TPacketGGMessenger p2ppck; - - p2ppck.bHeader = HEADER_GG_MESSENGER_REMOVE; + + p2ppck.header = GG::MESSENGER_REMOVE; + p2ppck.length = sizeof(p2ppck); strlcpy(p2ppck.szAccount, account.c_str(), sizeof(p2ppck.szAccount)); strlcpy(p2ppck.szCompanion, companion.c_str(), sizeof(p2ppck.szCompanion)); P2P_MANAGER::instance().Send(&p2ppck, sizeof(TPacketGGMessenger)); @@ -640,9 +646,9 @@ void MessengerManager::SendList(MessengerManager::keyA account) TPacketGCMessenger pack; - pack.header = HEADER_GC_MESSENGER; - pack.subheader = MESSENGER_SUBHEADER_GC_LIST; - pack.size = sizeof(TPacketGCMessenger); + pack.header = GC::MESSENGER; + pack.subheader = MessengerSub::GC::LIST; + pack.length = sizeof(TPacketGCMessenger); TPacketGCMessengerListOffline pack_offline; TPacketGCMessengerListOnline pack_online; @@ -677,7 +683,7 @@ void MessengerManager::SendList(MessengerManager::keyA account) ++it; } - pack.size += buf.size(); + pack.length += buf.size(); d->BufferedPacket(&pack, sizeof(TPacketGCMessenger)); d->Packet(buf.read_peek(), buf.size()); @@ -701,9 +707,9 @@ void MessengerManager::SendLogin(MessengerManager::keyA account, MessengerManage TPacketGCMessenger pack; - pack.header = HEADER_GC_MESSENGER; - pack.subheader = MESSENGER_SUBHEADER_GC_LOGIN; - pack.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + bLen; + pack.header = GC::MESSENGER; + pack.subheader = MessengerSub::GC::LOGIN; + pack.length = sizeof(TPacketGCMessenger) + sizeof(BYTE) + bLen; d->BufferedPacket(&pack, sizeof(TPacketGCMessenger)); d->BufferedPacket(&bLen, sizeof(BYTE)); @@ -725,9 +731,9 @@ void MessengerManager::SendLogout(MessengerManager::keyA account, MessengerManag TPacketGCMessenger pack; - pack.header = HEADER_GC_MESSENGER; - pack.subheader = MESSENGER_SUBHEADER_GC_LOGOUT; - pack.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + bLen; + pack.header = GC::MESSENGER; + pack.subheader = MessengerSub::GC::LOGOUT; + pack.length = sizeof(TPacketGCMessenger) + sizeof(BYTE) + bLen; d->BufferedPacket(&pack, sizeof(TPacketGCMessenger)); d->BufferedPacket(&bLen, sizeof(BYTE)); diff --git a/src/game/monarch.cpp b/src/game/monarch.cpp deleted file mode 100644 index ec6765a..0000000 --- a/src/game/monarch.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "stdafx.h" -#include "constants.h" -#include "monarch.h" -#include "char.h" -#include "sectree_manager.h" -#include "desc_client.h" - -extern int test_server; -extern int passes_per_sec; - -CMonarch::CMonarch() -{ - memset( &m_MonarchInfo, 0, sizeof(m_MonarchInfo) ); - - Initialize(); -} - -CMonarch::~CMonarch() -{ -} - -bool CMonarch::Initialize() -{ - memset(m_PowerUp, 0, sizeof(m_PowerUp)); - memset(m_DefenseUp, 0, sizeof(m_DefenseUp)); - memset(m_PowerUpCT, 0, sizeof(m_PowerUpCT)); - memset(m_DefenseUpCT, 0, sizeof(m_DefenseUpCT)); - - return 0; -} - -struct FHealMyEmpire -{ - BYTE m_bEmpire; - void operator () (LPENTITY ent) - { - if (ent->IsType(ENTITY_CHARACTER)) - { - LPCHARACTER ch = (LPCHARACTER) ent; - - if (ch->IsPC() && m_bEmpire == ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주가 내린 축복으로 모든 에너지가 가득 채워집니다")); - ch->PointChange(POINT_HP, ch->GetMaxHP() - ch->GetHP()); - ch->PointChange(POINT_SP, ch->GetMaxSP() - ch->GetSP()); - ch->EffectPacket(SE_SPUP_BLUE); - ch->EffectPacket(SE_HPUP_RED); - } - } - } -}; - -int CMonarch::HealMyEmpire(LPCHARACTER ch ,DWORD price) -{ - BYTE Empire = ch->GetEmpire(); - DWORD pid = ch->GetPlayerID(); - - sys_log(0, "HealMyEmpire[%d] pid:%d price %d", pid, Empire, price); - - if (IsMonarch(pid, Empire) == 0) - { - if (!ch->IsGM()) - { - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 자격을 가지고 있지 않습니다")); - sys_err("No Monarch pid %d ", pid); - return 0; - } - } - - if (!ch->IsMCOK(CHARACTER::MI_HEAL)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초 후에 군주의 축복을 사용할 수 있습니다"), ch->GetMCLTime(CHARACTER::MI_HEAL)); - - return 0; - } - - if (!IsMoneyOk(price, Empire)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), GetMoney(Empire), price); - return 0; - } - - int iMapIndex = ch->GetMapIndex(); - - FHealMyEmpire f; - f.m_bEmpire = Empire; - SECTREE_MANAGER::instance().for_each(iMapIndex, f); - - // DB에 돈 삭감 보내기 - SendtoDBDecMoney(price, Empire, ch); - - // 쿨타임 설정 - ch->SetMC(CHARACTER::MI_HEAL); - - if (test_server) - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[TEST_ONLY]현재 국고 : %d "), GetMoney(Empire) - price); - return 1; -} - -void CMonarch::SetMonarchInfo(TMonarchInfo * pInfo) -{ - memcpy(&m_MonarchInfo, pInfo, sizeof(TMonarchInfo)); -} - -bool CMonarch::IsMonarch(DWORD pid, BYTE bEmpire) -{ - if (bEmpire >= _countof(m_MonarchInfo.pid)) - return false; - - return (m_MonarchInfo.pid[bEmpire] == pid); -} - -bool CMonarch::IsMoneyOk(int price, BYTE bEmpire) -{ - sys_log(1, "GetMoney(%d), price = (%d,%d)", bEmpire, GetMoney(bEmpire), price); - return (GetMoney(bEmpire) >= price); -} - -bool CMonarch::SendtoDBAddMoney(int Money, BYTE bEmpire, LPCHARACTER ch) -{ - if (GetMoney(bEmpire) + Money > 2000000000) - return false; - - if (GetMoney(bEmpire) + Money < 0) - return false; - - int nEmpire = bEmpire; - db_clientdesc->DBPacketHeader(HEADER_GD_ADD_MONARCH_MONEY, ch->GetDesc()->GetHandle(), sizeof(int) + sizeof(int)); - db_clientdesc->Packet(&nEmpire, sizeof(int)); - db_clientdesc->Packet(&Money, sizeof(int)); - return true; -} - -bool CMonarch::SendtoDBDecMoney(int Money, BYTE bEmpire, LPCHARACTER ch) -{ - if (bEmpire >= _countof(m_MonarchInfo.money)) - return false; - - if (GetMoney(bEmpire) - Money < 0) - return false; - - // 실제 줄이는 부분은 서버에 갔다 온 다음에 처리된다 - int nEmpire = bEmpire; - - db_clientdesc->DBPacketHeader(HEADER_GD_DEC_MONARCH_MONEY, ch->GetDesc()->GetHandle(), sizeof(int) + sizeof(int)); - db_clientdesc->Packet(&nEmpire, sizeof(int)); - db_clientdesc->Packet(&Money, sizeof(int)); - return true; -} - -bool CMonarch::AddMoney(int Money, BYTE bEmpire) -{ - if (bEmpire >= _countof(m_MonarchInfo.money)) - return false; - - // 20억 이상 입금 불가능 - if (GetMoney(bEmpire) + Money > 2000000000) - return false; - - m_MonarchInfo.money[bEmpire] += Money; - return true; -} - -bool CMonarch::DecMoney(int Money, BYTE bEmpire) -{ - if (bEmpire >= _countof(m_MonarchInfo.money)) - return false; - - if (GetMoney(bEmpire) - Money < 0) - return false; - - m_MonarchInfo.money[bEmpire] -= Money; - return true; -} - -int CMonarch::GetMoney(BYTE bEmpire) -{ - if (bEmpire >= _countof(m_MonarchInfo.money)) - return 0; - - return m_MonarchInfo.money[bEmpire]; -} - -TMonarchInfo* CMonarch::GetMonarch() -{ - return &m_MonarchInfo; -} - -DWORD CMonarch::GetMonarchPID(BYTE Empire) -{ - return Empire < _countof(m_MonarchInfo.pid) ? m_MonarchInfo.pid[Empire] : 0; -} - -bool CMonarch::IsPowerUp(BYTE Empire) -{ - return Empire < _countof(m_PowerUp) ? m_PowerUp[Empire] : false; -} - -bool CMonarch::IsDefenceUp(BYTE Empire) -{ - return Empire < _countof(m_DefenseUp) ? m_DefenseUp[Empire] : false; -} - -bool CMonarch::CheckPowerUpCT(BYTE Empire) -{ - if (Empire >= _countof(m_PowerUpCT)) - return false; - - if (m_PowerUpCT[Empire] > thecore_pulse()) - { - if (test_server) - sys_log(0, "[TEST_ONLY] : CheckPowerUpCT CT%d Now%d 60sec %d", m_PowerUpCT[Empire], thecore_pulse(), PASSES_PER_SEC(60 * 10)); - return false; - } - - return true; -} - -bool CMonarch::CheckDefenseUpCT(BYTE Empire) -{ - if (Empire >= _countof(m_DefenseUpCT)) - return false; - - if (m_DefenseUpCT[Empire] > thecore_pulse()) - { - if (test_server) - sys_log(0, "[TEST_ONLY] : CheckPowerUpCT CT%d Now%d 60sec %d", m_PowerUpCT[Empire], thecore_pulse(), PASSES_PER_SEC(60 * 10)); - return false; - } - - return true; -} - -void CMonarch::PowerUp(BYTE Empire, bool On) -{ - if (Empire >= _countof(m_PowerUpCT)) - return; - - m_PowerUp[Empire] = On; - - // 군주 사자후 쿨타임 - m_PowerUpCT[Empire] = thecore_pulse() + PASSES_PER_SEC(60 * 10); -} - -void CMonarch::DefenseUp(BYTE Empire, bool On) -{ - if (Empire >= _countof(m_DefenseUpCT)) - return; - - m_DefenseUp[Empire] = On; - - // 군주 금강권 쿨타임 - m_DefenseUpCT[Empire] = thecore_pulse() + PASSES_PER_SEC(60 * 10); -} - -bool IsMonarchWarpZone (int map_idx) -{ - // 아귀동굴, 천의동굴. - if (map_idx >= 10000) - map_idx /= 10000; - - switch (map_idx) - { - case 301: - case 302: - case 303: - case 304: - //던전 - case 351: // 적룡성 - case 352: // 백룡지성 - return false; - } - - return (map_idx != 208 && map_idx != 216 && map_idx != 217); -} \ No newline at end of file diff --git a/src/game/monarch.h b/src/game/monarch.h deleted file mode 100644 index ce778ac..0000000 --- a/src/game/monarch.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __INC_METIN_II_MONARCH_H__ -#define __INC_METIN_II_MONARCH_H__ - -#include "common/tables.h" - -class CMonarch : public singleton -{ - public: - CMonarch(); - virtual ~CMonarch(); - - bool Initialize(); - - int HealMyEmpire(LPCHARACTER ch, DWORD price); - void SetMonarchInfo(TMonarchInfo * pInfo); - - bool IsMonarch(DWORD pid, BYTE bEmpire); - bool IsMoneyOk(int price, BYTE bEmpire); - bool SendtoDBAddMoney(int Money, BYTE bEmpire, LPCHARACTER ch); - bool SendtoDBDecMoney(int Money, BYTE bEmpire, LPCHARACTER ch); - - bool AddMoney(int Money, BYTE bEmpire); - bool DecMoney(int Money, BYTE bEmpire); - int GetMoney(BYTE bEmpire); - - TMonarchInfo* GetMonarch(); - - DWORD GetMonarchPID(BYTE Empire); - - bool IsPowerUp(BYTE Empire); - bool IsDefenceUp(BYTE Empire); - - int GetPowerUpCT(BYTE Empire) - { - return Empire < _countof(m_PowerUpCT) ? m_PowerUpCT[Empire] : 0; - } - - bool CheckPowerUpCT(BYTE Empire); - bool CheckDefenseUpCT(BYTE Empire); - - int GetDefenseUpCT(BYTE Empire) - { - return Empire < _countof(m_DefenseUpCT) ? m_DefenseUpCT[Empire] : 0; - } - - void PowerUp(BYTE Empire, bool On); - void DefenseUp(BYTE Empire, bool On); - - private: - TMonarchInfo m_MonarchInfo; - - int m_PowerUp[4]; ///< 군주의 사자후 - int m_DefenseUp[4]; ///< 군주의 금강권 - - int m_PowerUpCT[4]; ///< 군주의 사자후 - int m_DefenseUpCT[4]; ///< 군주의 금강권 -}; - -bool IsMonarchWarpZone (int map_idx); - -#endif diff --git a/src/game/p2p.cpp b/src/game/p2p.cpp index c3429d0..658fe7d 100644 --- a/src/game/p2p.cpp +++ b/src/game/p2p.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "common/stl.h" #include "constants.h" @@ -40,7 +40,8 @@ void P2P_MANAGER::Boot(LPDESC d) LPCHARACTER ch = it->second; it++; - p.bHeader = HEADER_GG_LOGIN; + p.header = GG::LOGIN; + p.length = sizeof(p); strlcpy(p.szName, ch->GetName(), sizeof(p.szName)); p.dwPID = ch->GetPlayerID(); p.bEmpire = ch->GetEmpire(); @@ -83,7 +84,8 @@ void P2P_MANAGER::RegisterConnector(LPDESC d) Boot(d); TPacketGGSetup p; - p.bHeader = HEADER_GG_SETUP; + p.header = GG::SETUP; + p.length = sizeof(p); p.wPort = p2p_port; p.bChannel = g_bChannel; d->Packet(&p, sizeof(p)); diff --git a/src/game/packet_info.cpp b/src/game/packet_info.cpp index 3c87ed3..0edd9d2 100644 --- a/src/game/packet_info.cpp +++ b/src/game/packet_info.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "common/stl.h" #include "constants.h" #include "packet_info.h" @@ -10,35 +10,27 @@ CPacketInfo::CPacketInfo() CPacketInfo::~CPacketInfo() { - itertype(m_pPacketMap) it = m_pPacketMap.begin(); - for ( ; it != m_pPacketMap.end(); ++it) { - M2_DELETE(it->second); - } + // unique_ptr handles cleanup automatically } -void CPacketInfo::Set(int header, int iSize, const char * c_pszName, bool bSeq) +void CPacketInfo::Set(int header, int iSize, const char * c_pszName) { if (m_pPacketMap.find(header) != m_pPacketMap.end()) return; - TPacketElement * element = M2_NEW TPacketElement; + auto element = std::make_unique(); element->iSize = iSize; element->stName.assign(c_pszName); element->iCalled = 0; element->dwLoad = 0; - element->bSequencePacket = bSeq; - - if (element->bSequencePacket) - element->iSize += sizeof(BYTE); - - m_pPacketMap.insert(std::map::value_type(header, element)); + m_pPacketMap.emplace(header, std::move(element)); } bool CPacketInfo::Get(int header, int * size, const char ** c_ppszName) { - std::map::iterator it = m_pPacketMap.find(header); + auto it = m_pPacketMap.find(header); if (it == m_pPacketMap.end()) return false; @@ -46,45 +38,18 @@ bool CPacketInfo::Get(int header, int * size, const char ** c_ppszName) *size = it->second->iSize; *c_ppszName = it->second->stName.c_str(); - m_pCurrentPacket = it->second; + m_pCurrentPacket = it->second.get(); return true; } -bool CPacketInfo::IsSequence(int header) -{ - TPacketElement * pkElement = GetElement(header); - return pkElement ? pkElement->bSequencePacket : false; -} - -void CPacketInfo::SetSequence(int header, bool bSeq) -{ - TPacketElement * pkElem = GetElement(header); - - if (pkElem) - { - if (bSeq) - { - if (!pkElem->bSequencePacket) - pkElem->iSize++; - } - else - { - if (pkElem->bSequencePacket) - pkElem->iSize--; - } - - pkElem->bSequencePacket = bSeq; - } -} - TPacketElement * CPacketInfo::GetElement(int header) { - std::map::iterator it = m_pPacketMap.find(header); + auto it = m_pPacketMap.find(header); if (it == m_pPacketMap.end()) return NULL; - return it->second; + return it->second.get(); } void CPacketInfo::Start() @@ -108,14 +73,11 @@ void CPacketInfo::Log(const char * c_pszFileName) if (!fp) return; - std::map::iterator it = m_pPacketMap.begin(); - fprintf(fp, "Name Called Load Ratio\n"); - while (it != m_pPacketMap.end()) + for (auto it = m_pPacketMap.begin(); it != m_pPacketMap.end(); ++it) { - TPacketElement * p = it->second; - ++it; + TPacketElement * p = it->second.get(); fprintf(fp, "%-16s %-10d %-10u %.2f\n", p->stName.c_str(), @@ -130,96 +92,93 @@ void CPacketInfo::Log(const char * c_pszFileName) CPacketInfoCG::CPacketInfoCG() { - Set(HEADER_CG_TEXT, sizeof(TPacketCGText), "Text", false); - Set(HEADER_CG_HANDSHAKE, sizeof(TPacketCGHandshake), "Handshake", false); - Set(HEADER_CG_TIME_SYNC, sizeof(TPacketCGHandshake), "TimeSync", true); - Set(HEADER_CG_MARK_LOGIN, sizeof(TPacketCGMarkLogin), "MarkLogin", false); - Set(HEADER_CG_MARK_IDXLIST, sizeof(TPacketCGMarkIDXList), "MarkIdxList", false); - Set(HEADER_CG_MARK_CRCLIST, sizeof(TPacketCGMarkCRCList), "MarkCrcList", false); - Set(HEADER_CG_MARK_UPLOAD, sizeof(TPacketCGMarkUpload), "MarkUpload", false); - Set(HEADER_CG_KEY_RESPONSE, sizeof(TPacketCGKeyResponse), "KeyResponse", false); + Set(CG::TEXT, sizeof(TPacketCGText), "Text"); + Set(CG::MARK_LOGIN, sizeof(TPacketCGMarkLogin), "MarkLogin"); + Set(CG::MARK_IDXLIST, sizeof(TPacketCGMarkIDXList), "MarkIdxList"); + Set(CG::MARK_CRCLIST, sizeof(TPacketCGMarkCRCList), "MarkCrcList"); + Set(CG::MARK_UPLOAD, sizeof(TPacketCGMarkUpload), "MarkUpload"); + Set(CG::KEY_RESPONSE, sizeof(TPacketCGKeyResponse), "KeyResponse"); - Set(HEADER_CG_GUILD_SYMBOL_UPLOAD, sizeof(TPacketCGGuildSymbolUpload), "SymbolUpload", false); - Set(HEADER_CG_SYMBOL_CRC, sizeof(TPacketCGSymbolCRC), "SymbolCRC", false); - Set(HEADER_CG_LOGIN2, sizeof(TPacketCGLogin2), "Login2", true); - Set(HEADER_CG_LOGIN3, sizeof(TPacketCGLogin3), "Login3", true); - Set(HEADER_CG_ATTACK, sizeof(TPacketCGAttack), "Attack", true); - Set(HEADER_CG_CHAT, sizeof(TPacketCGChat), "Chat", true); - Set(HEADER_CG_WHISPER, sizeof(TPacketCGWhisper), "Whisper", true); + Set(CG::GUILD_SYMBOL_UPLOAD, sizeof(TPacketCGGuildSymbolUpload), "SymbolUpload"); + Set(CG::SYMBOL_CRC, sizeof(TPacketCGSymbolCRC), "SymbolCRC"); + Set(CG::LOGIN2, sizeof(TPacketCGLogin2), "Login2"); + Set(CG::LOGIN3, sizeof(TPacketCGLogin3), "Login3"); + Set(CG::ATTACK, sizeof(TPacketCGAttack), "Attack"); + Set(CG::CHAT, sizeof(TPacketCGChat), "Chat"); + Set(CG::WHISPER, sizeof(TPacketCGWhisper), "Whisper"); - Set(HEADER_CG_CHARACTER_SELECT, sizeof(TPacketCGPlayerSelect), "Select", true); - Set(HEADER_CG_CHARACTER_CREATE, sizeof(TPacketCGPlayerCreate), "Create", true); - Set(HEADER_CG_CHARACTER_DELETE, sizeof(TPacketCGPlayerDelete), "Delete", true); - Set(HEADER_CG_ENTERGAME, sizeof(TPacketCGEnterGame), "EnterGame", true); + Set(CG::CHARACTER_SELECT, sizeof(TPacketCGPlayerSelect), "Select"); + Set(CG::CHARACTER_CREATE, sizeof(TPacketCGPlayerCreate), "Create"); + Set(CG::CHARACTER_DELETE, sizeof(TPacketCGPlayerDelete), "Delete"); + Set(CG::ENTERGAME, sizeof(TPacketCGEnterGame), "EnterGame"); - Set(HEADER_CG_ITEM_USE, sizeof(TPacketCGItemUse), "ItemUse", true); - Set(HEADER_CG_ITEM_DROP, sizeof(TPacketCGItemDrop), "ItemDrop", true); - Set(HEADER_CG_ITEM_DROP2, sizeof(TPacketCGItemDrop2), "ItemDrop2", true); - Set(HEADER_CG_ITEM_MOVE, sizeof(TPacketCGItemMove), "ItemMove", true); - Set(HEADER_CG_ITEM_PICKUP, sizeof(TPacketCGItemPickup), "ItemPickup", true); + Set(CG::ITEM_USE, sizeof(TPacketCGItemUse), "ItemUse"); + Set(CG::ITEM_DROP, sizeof(TPacketCGItemDrop), "ItemDrop"); + Set(CG::ITEM_DROP2, sizeof(TPacketCGItemDrop2), "ItemDrop2"); + Set(CG::ITEM_MOVE, sizeof(TPacketCGItemMove), "ItemMove"); + Set(CG::ITEM_PICKUP, sizeof(TPacketCGItemPickup), "ItemPickup"); - Set(HEADER_CG_QUICKSLOT_ADD, sizeof(TPacketCGQuickslotAdd), "QuickslotAdd", true); - Set(HEADER_CG_QUICKSLOT_DEL, sizeof(TPacketCGQuickslotDel), "QuickslotDel", true); - Set(HEADER_CG_QUICKSLOT_SWAP, sizeof(TPacketCGQuickslotSwap), "QuickslotSwap", true); + Set(CG::QUICKSLOT_ADD, sizeof(TPacketCGQuickslotAdd), "QuickslotAdd"); + Set(CG::QUICKSLOT_DEL, sizeof(TPacketCGQuickslotDel), "QuickslotDel"); + Set(CG::QUICKSLOT_SWAP, sizeof(TPacketCGQuickslotSwap), "QuickslotSwap"); - Set(HEADER_CG_SHOP, sizeof(TPacketCGShop), "Shop", true); + Set(CG::SHOP, sizeof(TPacketCGShop), "Shop"); - Set(HEADER_CG_ON_CLICK, sizeof(TPacketCGOnClick), "OnClick", true); - Set(HEADER_CG_EXCHANGE, sizeof(TPacketCGExchange), "Exchange", true); - Set(HEADER_CG_CHARACTER_POSITION, sizeof(TPacketCGPosition), "Position", true); - Set(HEADER_CG_SCRIPT_ANSWER, sizeof(TPacketCGScriptAnswer), "ScriptAnswer", true); - Set(HEADER_CG_SCRIPT_BUTTON, sizeof(TPacketCGScriptButton), "ScriptButton", true); - Set(HEADER_CG_QUEST_INPUT_STRING, sizeof(TPacketCGQuestInputString), "QuestInputString", true); - Set(HEADER_CG_QUEST_CONFIRM, sizeof(TPacketCGQuestConfirm), "QuestConfirm", true); - Set(HEADER_CG_QUEST_CANCEL, sizeof(TPacketCGQuestCancel), "QuestCancel", true); + Set(CG::ON_CLICK, sizeof(TPacketCGOnClick), "OnClick"); + Set(CG::EXCHANGE, sizeof(TPacketCGExchange), "Exchange"); + Set(CG::CHARACTER_POSITION, sizeof(TPacketCGPosition), "Position"); + Set(CG::SCRIPT_ANSWER, sizeof(TPacketCGScriptAnswer), "ScriptAnswer"); + Set(CG::SCRIPT_BUTTON, sizeof(TPacketCGScriptButton), "ScriptButton"); + Set(CG::QUEST_INPUT_STRING, sizeof(TPacketCGQuestInputString), "QuestInputString"); + Set(CG::QUEST_CONFIRM, sizeof(TPacketCGQuestConfirm), "QuestConfirm"); + Set(CG::QUEST_CANCEL, sizeof(TPacketCGQuestCancel), "QuestCancel"); - Set(HEADER_CG_MOVE, sizeof(TPacketCGMove), "Move", true); - Set(HEADER_CG_SYNC_POSITION, sizeof(TPacketCGSyncPosition), "SyncPosition", true); + Set(CG::MOVE, sizeof(TPacketCGMove), "Move"); + Set(CG::SYNC_POSITION, sizeof(TPacketCGSyncPosition), "SyncPosition"); - Set(HEADER_CG_FLY_TARGETING, sizeof(TPacketCGFlyTargeting), "FlyTarget", true); - Set(HEADER_CG_ADD_FLY_TARGETING, sizeof(TPacketCGFlyTargeting), "AddFlyTarget", true); - Set(HEADER_CG_SHOOT, sizeof(TPacketCGShoot), "Shoot", true); + Set(CG::FLY_TARGETING, sizeof(TPacketCGFlyTargeting), "FlyTarget"); + Set(CG::ADD_FLY_TARGETING, sizeof(TPacketCGFlyTargeting), "AddFlyTarget"); + Set(CG::SHOOT, sizeof(TPacketCGShoot), "Shoot"); - Set(HEADER_CG_USE_SKILL, sizeof(TPacketCGUseSkill), "UseSkill", true); + Set(CG::USE_SKILL, sizeof(TPacketCGUseSkill), "UseSkill"); - Set(HEADER_CG_ITEM_USE_TO_ITEM, sizeof(TPacketCGItemUseToItem), "UseItemToItem", true); - Set(HEADER_CG_TARGET, sizeof(TPacketCGTarget), "Target", true); - Set(HEADER_CG_WARP, sizeof(TPacketCGWarp), "Warp", true); - Set(HEADER_CG_MESSENGER, sizeof(TPacketCGMessenger), "Messenger", true); + Set(CG::ITEM_USE_TO_ITEM, sizeof(TPacketCGItemUseToItem), "UseItemToItem"); + Set(CG::TARGET, sizeof(TPacketCGTarget), "Target"); + Set(CG::WARP, sizeof(TPacketCGWarp), "Warp"); + Set(CG::MESSENGER, sizeof(TPacketCGMessenger), "Messenger"); - Set(HEADER_CG_PARTY_REMOVE, sizeof(TPacketCGPartyRemove), "PartyRemove", true); - Set(HEADER_CG_PARTY_INVITE, sizeof(TPacketCGPartyInvite), "PartyInvite", true); - Set(HEADER_CG_PARTY_INVITE_ANSWER, sizeof(TPacketCGPartyInviteAnswer), "PartyInviteAnswer", true); - Set(HEADER_CG_PARTY_SET_STATE, sizeof(TPacketCGPartySetState), "PartySetState", true); - Set(HEADER_CG_PARTY_USE_SKILL, sizeof(TPacketCGPartyUseSkill), "PartyUseSkill", true); - Set(HEADER_CG_PARTY_PARAMETER, sizeof(TPacketCGPartyParameter), "PartyParam", true); + Set(CG::PARTY_REMOVE, sizeof(TPacketCGPartyRemove), "PartyRemove"); + Set(CG::PARTY_INVITE, sizeof(TPacketCGPartyInvite), "PartyInvite"); + Set(CG::PARTY_INVITE_ANSWER, sizeof(TPacketCGPartyInviteAnswer), "PartyInviteAnswer"); + Set(CG::PARTY_SET_STATE, sizeof(TPacketCGPartySetState), "PartySetState"); + Set(CG::PARTY_USE_SKILL, sizeof(TPacketCGPartyUseSkill), "PartyUseSkill"); + Set(CG::PARTY_PARAMETER, sizeof(TPacketCGPartyParameter), "PartyParam"); - Set(HEADER_CG_EMPIRE, sizeof(TPacketCGEmpire), "Empire", true); - Set(HEADER_CG_SAFEBOX_CHECKOUT, sizeof(TPacketCGSafeboxCheckout), "SafeboxCheckout", true); - Set(HEADER_CG_SAFEBOX_CHECKIN, sizeof(TPacketCGSafeboxCheckin), "SafeboxCheckin", true); + Set(CG::EMPIRE, sizeof(TPacketCGEmpire), "Empire"); + Set(CG::SAFEBOX_CHECKOUT, sizeof(TPacketCGSafeboxCheckout), "SafeboxCheckout"); + Set(CG::SAFEBOX_CHECKIN, sizeof(TPacketCGSafeboxCheckin), "SafeboxCheckin"); - Set(HEADER_CG_SAFEBOX_ITEM_MOVE, sizeof(TPacketCGItemMove), "SafeboxItemMove", true); + Set(CG::SAFEBOX_ITEM_MOVE, sizeof(TPacketCGItemMove), "SafeboxItemMove"); - Set(HEADER_CG_GUILD, sizeof(TPacketCGGuild), "Guild", true); - Set(HEADER_CG_ANSWER_MAKE_GUILD, sizeof(TPacketCGAnswerMakeGuild), "AnswerMakeGuild", true); + Set(CG::GUILD, sizeof(TPacketCGGuild), "Guild"); + Set(CG::ANSWER_MAKE_GUILD, sizeof(TPacketCGAnswerMakeGuild), "AnswerMakeGuild"); - Set(HEADER_CG_FISHING, sizeof(TPacketCGFishing), "Fishing", true); - Set(HEADER_CG_ITEM_GIVE, sizeof(TPacketCGGiveItem), "ItemGive", true); - Set(HEADER_CG_HACK, sizeof(TPacketCGHack), "Hack", true); - Set(HEADER_CG_MYSHOP, sizeof(TPacketCGMyShop), "MyShop", true); + Set(CG::FISHING, sizeof(TPacketCGFishing), "Fishing"); + Set(CG::ITEM_GIVE, sizeof(TPacketCGGiveItem), "ItemGive"); + Set(CG::HACK, sizeof(TPacketCGHack), "Hack"); + Set(CG::MYSHOP, sizeof(TPacketCGMyShop), "MyShop"); - Set(HEADER_CG_REFINE, sizeof(TPacketCGRefine), "Refine", true); - Set(HEADER_CG_CHANGE_NAME, sizeof(TPacketCGChangeName), "ChangeName", true); + Set(CG::REFINE, sizeof(TPacketCGRefine), "Refine"); + Set(CG::CHANGE_NAME, sizeof(TPacketCGChangeName), "ChangeName"); - Set(HEADER_CG_CLIENT_VERSION, sizeof(TPacketCGClientVersion), "Version", true); - Set(HEADER_CG_CLIENT_VERSION2, sizeof(TPacketCGClientVersion2), "Version", true); - Set(HEADER_CG_PONG, sizeof(BYTE), "Pong", true); - Set(HEADER_CG_MALL_CHECKOUT, sizeof(TPacketCGSafeboxCheckout), "MallCheckout", true); + Set(CG::CLIENT_VERSION, sizeof(TPacketCGClientVersion), "Version"); + Set(CG::PONG, sizeof(TPacketCGPong), "Pong"); + Set(CG::MALL_CHECKOUT, sizeof(TPacketCGSafeboxCheckout), "MallCheckout"); - Set(HEADER_CG_SCRIPT_SELECT_ITEM, sizeof(TPacketCGScriptSelectItem), "ScriptSelectItem", true); + Set(CG::SCRIPT_SELECT_ITEM, sizeof(TPacketCGScriptSelectItem), "ScriptSelectItem"); - Set(HEADER_CG_DRAGON_SOUL_REFINE, sizeof(TPacketCGDragonSoulRefine), "DragonSoulRefine", false); - Set(HEADER_CG_STATE_CHECKER, sizeof(BYTE), "ServerStateCheck", false); + Set(CG::DRAGON_SOUL_REFINE, sizeof(TPacketCGDragonSoulRefine), "DragonSoulRefine"); + Set(CG::STATE_CHECKER, sizeof(TPacketCGStateCheck), "ServerStateCheck"); } @@ -231,40 +190,32 @@ CPacketInfoCG::~CPacketInfoCG() //////////////////////////////////////////////////////////////////////////////// CPacketInfoGG::CPacketInfoGG() { - Set(HEADER_GG_SETUP, sizeof(TPacketGGSetup), "Setup", false); - Set(HEADER_GG_LOGIN, sizeof(TPacketGGLogin), "Login", false); - Set(HEADER_GG_LOGOUT, sizeof(TPacketGGLogout), "Logout", false); - Set(HEADER_GG_RELAY, sizeof(TPacketGGRelay), "Relay", false); - Set(HEADER_GG_NOTICE, sizeof(TPacketGGNotice), "Notice", false); - Set(HEADER_GG_SHUTDOWN, sizeof(TPacketGGShutdown), "Shutdown", false); - Set(HEADER_GG_GUILD, sizeof(TPacketGGGuild), "Guild", false); - Set(HEADER_GG_SHOUT, sizeof(TPacketGGShout), "Shout", false); - Set(HEADER_GG_DISCONNECT, sizeof(TPacketGGDisconnect), "Disconnect", false); - Set(HEADER_GG_MESSENGER_ADD, sizeof(TPacketGGMessenger), "MessengerAdd", false); - Set(HEADER_GG_MESSENGER_REQUEST_ADD, sizeof(TPacketGGMessengerRequest), "MessengerRequestAdd", false); - Set(HEADER_GG_MESSENGER_RESPONSE, sizeof(TPacketGGMessengerResponse), "MessengerResponse", false); - Set(HEADER_GG_MESSENGER_REMOVE, sizeof(TPacketGGMessenger), "MessengerRemove", false); - Set(HEADER_GG_FIND_POSITION, sizeof(TPacketGGFindPosition), "FindPosition", false); - Set(HEADER_GG_WARP_CHARACTER, sizeof(TPacketGGWarpCharacter), "WarpCharacter", false); - Set(HEADER_GG_MESSENGER_MOBILE, sizeof(TPacketGGMessengerMobile), "MessengerMobile", false); - Set(HEADER_GG_GUILD_WAR_ZONE_MAP_INDEX, sizeof(TPacketGGGuildWarMapIndex), "GuildWarMapIndex", false); - Set(HEADER_GG_TRANSFER, sizeof(TPacketGGTransfer), "Transfer", false); - Set(HEADER_GG_XMAS_WARP_SANTA, sizeof(TPacketGGXmasWarpSanta), "XmasWarpSanta", false); - Set(HEADER_GG_XMAS_WARP_SANTA_REPLY, sizeof(TPacketGGXmasWarpSantaReply), "XmasWarpSantaReply", false); - Set(HEADER_GG_RELOAD_CRC_LIST, sizeof(BYTE), "ReloadCRCList", false); - Set(HEADER_GG_CHECK_CLIENT_VERSION, sizeof(BYTE), "CheckClientVersion", false); - Set(HEADER_GG_LOGIN_PING, sizeof(TPacketGGLoginPing), "LoginPing", false); - - // BLOCK_CHAT - Set(HEADER_GG_BLOCK_CHAT, sizeof(TPacketGGBlockChat), "BlockChat", false); - // END_OF_BLOCK_CHAT - - Set(HEADER_GG_SIEGE, sizeof(TPacketGGSiege), "Siege", false); - - Set(HEADER_GG_MONARCH_NOTICE, sizeof(TPacketGGMonarchNotice), "MonarchNotice", false); - Set(HEADER_GG_MONARCH_TRANSFER, sizeof(TPacketMonarchGGTransfer), "MonarchTransfer", false); - Set(HEADER_GG_CHECK_AWAKENESS, sizeof(TPacketGGCheckAwakeness), "CheckAwakeness", false); - Set(HEADER_GG_MARK_UPDATE, sizeof(TPacketGGMarkUpdate), "MarkUpdate", false); + Set(GG::SETUP, sizeof(TPacketGGSetup), "Setup"); + Set(GG::LOGIN, sizeof(TPacketGGLogin), "Login"); + Set(GG::LOGOUT, sizeof(TPacketGGLogout), "Logout"); + Set(GG::RELAY, sizeof(TPacketGGRelay), "Relay"); + Set(GG::NOTICE, sizeof(TPacketGGNotice), "Notice"); + Set(GG::SHUTDOWN, sizeof(TPacketGGShutdown), "Shutdown"); + Set(GG::GUILD, sizeof(TPacketGGGuild), "Guild"); + Set(GG::SHOUT, sizeof(TPacketGGShout), "Shout"); + Set(GG::DISCONNECT, sizeof(TPacketGGDisconnect), "Disconnect"); + Set(GG::MESSENGER_ADD, sizeof(TPacketGGMessenger), "MessengerAdd"); + Set(GG::MESSENGER_REQUEST_ADD, sizeof(TPacketGGMessengerRequest), "MessengerRequestAdd"); + Set(GG::MESSENGER_RESPONSE, sizeof(TPacketGGMessengerResponse), "MessengerResponse"); + Set(GG::MESSENGER_REMOVE, sizeof(TPacketGGMessenger), "MessengerRemove"); + Set(GG::FIND_POSITION, sizeof(TPacketGGFindPosition), "FindPosition"); + Set(GG::WARP_CHARACTER, sizeof(TPacketGGWarpCharacter), "WarpCharacter"); + Set(GG::GUILD_WAR_ZONE_MAP_INDEX, sizeof(TPacketGGGuildWarMapIndex), "GuildWarMapIndex"); + Set(GG::TRANSFER, sizeof(TPacketGGTransfer), "Transfer"); + Set(GG::XMAS_WARP_SANTA, sizeof(TPacketGGXmasWarpSanta), "XmasWarpSanta"); + Set(GG::XMAS_WARP_SANTA_REPLY, sizeof(TPacketGGXmasWarpSantaReply), "XmasWarpSantaReply"); + Set(GG::RELOAD_CRC_LIST, PACKET_HEADER_SIZE, "ReloadCRCList"); + Set(GG::CHECK_CLIENT_VERSION, PACKET_HEADER_SIZE, "CheckClientVersion"); + Set(GG::LOGIN_PING, sizeof(TPacketGGLoginPing), "LoginPing"); + Set(GG::BLOCK_CHAT, sizeof(TPacketGGBlockChat), "BlockChat"); + Set(GG::SIEGE, sizeof(TPacketGGSiege), "Siege"); + Set(GG::CHECK_AWAKENESS, sizeof(TPacketGGCheckAwakeness), "CheckAwakeness"); + Set(GG::MARK_UPDATE, sizeof(TPacketGGMarkUpdate), "MarkUpdate"); } CPacketInfoGG::~CPacketInfoGG() diff --git a/src/game/packet_info.h b/src/game/packet_info.h index 4cc9c04..070b0eb 100644 --- a/src/game/packet_info.h +++ b/src/game/packet_info.h @@ -1,15 +1,15 @@ -#ifndef __INC_METIN_II_GAME_PACKET_HEADER_INFO_H__ +#ifndef __INC_METIN_II_GAME_PACKET_HEADER_INFO_H__ #define __INC_METIN_II_GAME_PACKET_HEADER_INFO_H__ -#include "packet.h" +#include "packet_structs.h" +#include typedef struct SPacketElement { - int iSize; + int iSize; // Expected/minimum packet size (for validation; CG actual size comes from wire length) std::string stName; int iCalled; DWORD dwLoad; - bool bSequencePacket; } TPacketElement; class CPacketInfo @@ -18,7 +18,7 @@ class CPacketInfo CPacketInfo(); virtual ~CPacketInfo(); - void Set(int header, int size, const char * c_pszName, bool bSeq=false); + void Set(int header, int size, const char * c_pszName); bool Get(int header, int * size, const char ** c_ppszName); void Start(); @@ -26,14 +26,11 @@ class CPacketInfo void Log(const char * c_pszFileName); - bool IsSequence(int header); - void SetSequence(int header, bool bSeq); - private: TPacketElement * GetElement(int header); protected: - std::map m_pPacketMap; + std::map> m_pPacketMap; TPacketElement * m_pCurrentPacket; DWORD m_dwStartTime; }; @@ -53,12 +50,4 @@ class CPacketInfoGG : public CPacketInfo virtual ~CPacketInfoGG(); }; -/// Implemented in input_udp.cpp -class CPacketInfoUDP : public CPacketInfo -{ - public: - CPacketInfoUDP(); - virtual ~CPacketInfoUDP(); -}; - #endif diff --git a/src/game/packet_reader.h b/src/game/packet_reader.h new file mode 100644 index 0000000..7d46379 --- /dev/null +++ b/src/game/packet_reader.h @@ -0,0 +1,157 @@ +#pragma once + +#include +#include +#include + +// 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(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(ReadU8()); } + int16_t ReadI16() { return static_cast(ReadU16()); } + int32_t ReadI32() { return static_cast(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 + 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; +}; diff --git a/src/game/packet.h b/src/game/packet_structs.h similarity index 58% rename from src/game/packet.h rename to src/game/packet_structs.h index e3657cb..23a5cf6 100644 --- a/src/game/packet.h +++ b/src/game/packet_structs.h @@ -1,327 +1,19 @@ -#pragma once - -enum -{ - HEADER_CG_HANDSHAKE = 0xff, - HEADER_CG_PONG = 0xfe, - HEADER_CG_TIME_SYNC = 0xfc, - HEADER_CG_KEY_RESPONSE = 0xf9, // Secure key exchange response (libsodium) - HEADER_CG_LOGIN_SECURE = 0xf6, // Secure login packet - - HEADER_CG_ATTACK = 2, - HEADER_CG_CHAT = 3, - HEADER_CG_CHARACTER_CREATE = 4, - HEADER_CG_CHARACTER_DELETE = 5, - HEADER_CG_CHARACTER_SELECT = 6, - HEADER_CG_MOVE = 7, - HEADER_CG_SYNC_POSITION = 8, - HEADER_CG_ENTERGAME = 10, - - HEADER_CG_ITEM_USE = 11, - HEADER_CG_ITEM_DROP = 12, - HEADER_CG_ITEM_MOVE = 13, - HEADER_CG_ITEM_PICKUP = 15, - - HEADER_CG_QUICKSLOT_ADD = 16, - HEADER_CG_QUICKSLOT_DEL = 17, - HEADER_CG_QUICKSLOT_SWAP = 18, - HEADER_CG_WHISPER = 19, - HEADER_CG_ITEM_DROP2 = 20, - - HEADER_CG_ON_CLICK = 26, - HEADER_CG_EXCHANGE = 27, - HEADER_CG_CHARACTER_POSITION = 28, - HEADER_CG_SCRIPT_ANSWER = 29, - HEADER_CG_QUEST_INPUT_STRING = 30, - HEADER_CG_QUEST_CONFIRM = 31, - HEADER_CG_QUEST_CANCEL = 32, - - HEADER_CG_SHOP = 50, - HEADER_CG_FLY_TARGETING = 51, - HEADER_CG_USE_SKILL = 52, - HEADER_CG_ADD_FLY_TARGETING = 53, - HEADER_CG_SHOOT = 54, - HEADER_CG_MYSHOP = 55, - - HEADER_CG_ITEM_USE_TO_ITEM = 60, - HEADER_CG_TARGET = 61, - - HEADER_CG_TEXT = 64, // @ 로 시작되면 텍스트를 파싱한다. - HEADER_CG_WARP = 65, - HEADER_CG_SCRIPT_BUTTON = 66, - HEADER_CG_MESSENGER = 67, - - HEADER_CG_MALL_CHECKOUT = 69, - HEADER_CG_SAFEBOX_CHECKIN = 70, // 아이템을 창고에 넣넎는다. - HEADER_CG_SAFEBOX_CHECKOUT = 71, // 아이템을 창고로 부터 빼온다. - - HEADER_CG_PARTY_INVITE = 72, - HEADER_CG_PARTY_INVITE_ANSWER = 73, - HEADER_CG_PARTY_REMOVE = 74, - HEADER_CG_PARTY_SET_STATE = 75, - HEADER_CG_PARTY_USE_SKILL = 76, - HEADER_CG_SAFEBOX_ITEM_MOVE = 77, - HEADER_CG_PARTY_PARAMETER = 78, - - HEADER_CG_GUILD = 80, - HEADER_CG_ANSWER_MAKE_GUILD = 81, - - HEADER_CG_FISHING = 82, - - HEADER_CG_ITEM_GIVE = 83, - - HEADER_CG_EMPIRE = 90, - - HEADER_CG_REFINE = 96, - - HEADER_CG_MARK_LOGIN = 100, - HEADER_CG_MARK_CRCLIST = 101, - HEADER_CG_MARK_UPLOAD = 102, - HEADER_CG_MARK_IDXLIST = 104, - - HEADER_CG_HACK = 105, - HEADER_CG_CHANGE_NAME = 106, - HEADER_CG_LOGIN2 = 109, - HEADER_CG_DUNGEON = 110, - HEADER_CG_LOGIN3 = 111, - - HEADER_CG_GUILD_SYMBOL_UPLOAD = 112, - HEADER_CG_SYMBOL_CRC = 113, - - // SCRIPT_SELECT_ITEM - HEADER_CG_SCRIPT_SELECT_ITEM = 114, - // END_OF_SCRIPT_SELECT_ITEM - -// HEADER_CG_ROULETTE = 200, - - //NOTE : 이런 개XXX 정말 이거 Packet설계한 사람은 누구냐. 이렇게 코딩하고 밥이 넘어가나. - //enum을 별도로 구별을 하던가. 아님 namepsace로 구별을 하던가.. - //정말 packet generator까지는 바라지도 않는다. 이런 씨XX - //이러다가 숫자 겹치면 누가 책임지는데??? - - HEADER_CG_DRAGON_SOUL_REFINE = 205, - HEADER_CG_STATE_CHECKER = 206, - - HEADER_CG_CLIENT_VERSION = 0xfd, - HEADER_CG_CLIENT_VERSION2 = 0xf1, - - /********************************************************/ - HEADER_GC_KEY_CHALLENGE = 0xf8, // Secure key exchange challenge (libsodium) - HEADER_GC_KEY_COMPLETE = 0xf7, // Secure key exchange complete (libsodium) - HEADER_GC_TIME_SYNC = 0xfc, - HEADER_GC_PHASE = 0xfd, - HEADER_GC_BINDUDP = 0xfe, - HEADER_GC_HANDSHAKE = 0xff, - - HEADER_GC_CHARACTER_ADD = 1, - HEADER_GC_CHARACTER_DEL = 2, - HEADER_GC_MOVE = 3, - HEADER_GC_CHAT = 4, - HEADER_GC_SYNC_POSITION = 5, - - HEADER_GC_LOGIN_SUCCESS = 6, - HEADER_GC_LOGIN_SUCCESS_NEWSLOT = 32, - HEADER_GC_LOGIN_FAILURE = 7, - - HEADER_GC_CHARACTER_CREATE_SUCCESS = 8, - HEADER_GC_CHARACTER_CREATE_FAILURE = 9, - HEADER_GC_CHARACTER_DELETE_SUCCESS = 10, - HEADER_GC_CHARACTER_DELETE_WRONG_SOCIAL_ID = 11, - - HEADER_GC_ATTACK = 12, - HEADER_GC_STUN = 13, - HEADER_GC_DEAD = 14, - - HEADER_GC_MAIN_CHARACTER_OLD = 15, - HEADER_GC_CHARACTER_POINTS = 16, - HEADER_GC_CHARACTER_POINT_CHANGE = 17, - HEADER_GC_CHANGE_SPEED = 18, - HEADER_GC_CHARACTER_UPDATE = 19, - HEADER_GC_CHARACTER_UPDATE_NEW = 24, - - HEADER_GC_ITEM_DEL = 20, - HEADER_GC_ITEM_SET = 21, - HEADER_GC_ITEM_USE = 22, - HEADER_GC_ITEM_DROP = 23, - HEADER_GC_ITEM_UPDATE = 25, - - HEADER_GC_ITEM_GROUND_ADD = 26, - HEADER_GC_ITEM_GROUND_DEL = 27, - - HEADER_GC_QUICKSLOT_ADD = 28, - HEADER_GC_QUICKSLOT_DEL = 29, - HEADER_GC_QUICKSLOT_SWAP = 30, - - HEADER_GC_ITEM_OWNERSHIP = 31, - - HEADER_GC_WHISPER = 34, - - HEADER_GC_MOTION = 36, - HEADER_GC_PARTS = 37, - - HEADER_GC_SHOP = 38, - HEADER_GC_SHOP_SIGN = 39, - - HEADER_GC_DUEL_START = 40, - HEADER_GC_PVP = 41, - HEADER_GC_EXCHANGE = 42, - HEADER_GC_CHARACTER_POSITION = 43, - - HEADER_GC_PING = 44, - HEADER_GC_SCRIPT = 45, - HEADER_GC_QUEST_CONFIRM = 46, - - HEADER_GC_MOUNT = 61, - HEADER_GC_OWNERSHIP = 62, - HEADER_GC_TARGET = 63, - - HEADER_GC_WARP = 65, - - HEADER_GC_ADD_FLY_TARGETING = 69, - HEADER_GC_CREATE_FLY = 70, - HEADER_GC_FLY_TARGETING = 71, - HEADER_GC_SKILL_LEVEL_OLD = 72, - HEADER_GC_SKILL_LEVEL = 76, - - HEADER_GC_MESSENGER = 74, - HEADER_GC_GUILD = 75, - - HEADER_GC_PARTY_INVITE = 77, - HEADER_GC_PARTY_ADD = 78, - HEADER_GC_PARTY_UPDATE = 79, - HEADER_GC_PARTY_REMOVE = 80, - HEADER_GC_QUEST_INFO = 81, - HEADER_GC_REQUEST_MAKE_GUILD = 82, - HEADER_GC_PARTY_PARAMETER = 83, - - HEADER_GC_SAFEBOX_SET = 85, - HEADER_GC_SAFEBOX_DEL = 86, - HEADER_GC_SAFEBOX_WRONG_PASSWORD = 87, - HEADER_GC_SAFEBOX_SIZE = 88, - - HEADER_GC_FISHING = 89, - - HEADER_GC_EMPIRE = 90, - - HEADER_GC_PARTY_LINK = 91, - HEADER_GC_PARTY_UNLINK = 92, - - HEADER_GC_REFINE_INFORMATION_OLD = 95, - - HEADER_GC_VIEW_EQUIP = 99, - - HEADER_GC_MARK_BLOCK = 100, - HEADER_GC_MARK_IDXLIST = 102, - HEADER_GC_MARK_UPDATE = 103, - - HEADER_GC_TIME = 106, - HEADER_GC_CHANGE_NAME = 107, - - HEADER_GC_DUNGEON = 110, - - HEADER_GC_WALK_MODE = 111, - HEADER_GC_SKILL_GROUP = 112, - HEADER_GC_MAIN_CHARACTER = 113, - - // HEADER_GC_USE_POTION = 114, - HEADER_GC_SEPCIAL_EFFECT = 114, - - HEADER_GC_NPC_POSITION = 115, - - HEADER_GC_LOGIN_KEY = 118, - HEADER_GC_REFINE_INFORMATION = 119, - HEADER_GC_CHANNEL = 121, - - // 122 HEADER_GC_MALL_OPEN - HEADER_GC_TARGET_UPDATE = 123, - HEADER_GC_TARGET_DELETE = 124, - HEADER_GC_TARGET_CREATE = 125, - - HEADER_GC_AFFECT_ADD = 126, - HEADER_GC_AFFECT_REMOVE = 127, - - HEADER_GC_MALL_OPEN = 122, - HEADER_GC_MALL_SET = 128, - HEADER_GC_MALL_DEL = 129, - - HEADER_GC_LAND_LIST = 130, - HEADER_GC_LOVER_INFO = 131, - HEADER_GC_LOVE_POINT_UPDATE = 132, - - HEADER_GC_SYMBOL_DATA = 133, - - // MINING - HEADER_GC_DIG_MOTION = 134, - // END_OF_MINING - - HEADER_GC_DAMAGE_INFO = 135, - HEADER_GC_CHAR_ADDITIONAL_INFO = 136, - - // SUPPORT_BGM - HEADER_GC_MAIN_CHARACTER3_BGM = 137, - HEADER_GC_MAIN_CHARACTER4_BGM_VOL = 138, - // END_OF_SUPPORT_BGM - - HEADER_GC_AUTH_SUCCESS = 150, - - // ROULETTE - HEADER_GC_ROULETTE = 200, - // END_ROULETTE - - HEADER_GC_SPECIFIC_EFFECT = 208, - - HEADER_GC_DRAGON_SOUL_REFINE = 209, - HEADER_GC_RESPOND_CHANNELSTATUS = 210, - - HEADER_GC_ITEM_GET = 211, - - ///////////////////////////////////////////////////////////////////////////// - - HEADER_GG_LOGIN = 1, - HEADER_GG_LOGOUT = 2, - HEADER_GG_RELAY = 3, - HEADER_GG_NOTICE = 4, - HEADER_GG_SHUTDOWN = 5, - HEADER_GG_GUILD = 6, - HEADER_GG_DISCONNECT = 7, // 누군가의 접속을 강제로 끊을 때 - HEADER_GG_SHOUT = 8, - HEADER_GG_SETUP = 9, - HEADER_GG_MESSENGER_ADD = 10, - HEADER_GG_MESSENGER_REMOVE = 11, - HEADER_GG_FIND_POSITION = 12, - HEADER_GG_WARP_CHARACTER = 13, - HEADER_GG_MESSENGER_MOBILE = 14, - HEADER_GG_GUILD_WAR_ZONE_MAP_INDEX = 15, - HEADER_GG_TRANSFER = 16, - HEADER_GG_XMAS_WARP_SANTA = 17, - HEADER_GG_XMAS_WARP_SANTA_REPLY = 18, - HEADER_GG_RELOAD_CRC_LIST = 19, - HEADER_GG_LOGIN_PING = 20, - HEADER_GG_CHECK_CLIENT_VERSION = 21, - HEADER_GG_BLOCK_CHAT = 22, - - HEADER_GG_MESSENGER_REQUEST_ADD = 23, - HEADER_GG_MESSENGER_RESPONSE = 24, - - HEADER_GG_SIEGE = 25, - HEADER_GG_MONARCH_NOTICE = 26, - HEADER_GG_MONARCH_TRANSFER = 27, - - HEADER_GG_CHECK_AWAKENESS = 29, - HEADER_GG_MARK_UPDATE = 30, -}; +#pragma once +#include "packet_headers.h" #pragma pack(1) typedef struct SPacketGGSetup { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint16_t wPort; uint8_t bChannel; } TPacketGGSetup; typedef struct SPacketGGLogin { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szName[CHARACTER_NAME_MAX_LEN + 1]; uint32_t dwPID; uint8_t bEmpire; @@ -331,59 +23,53 @@ typedef struct SPacketGGLogin typedef struct SPacketGGLogout { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szName[CHARACTER_NAME_MAX_LEN + 1]; } TPacketGGLogout; typedef struct SPacketGGRelay { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szName[CHARACTER_NAME_MAX_LEN + 1]; int32_t lSize; } TPacketGGRelay; typedef struct SPacketGGNotice { - uint8_t bHeader; + uint16_t header; + uint16_t length; int32_t lSize; } TPacketGGNotice; -typedef struct SPacketGGMonarchNotice -{ - uint8_t bHeader; - uint8_t bEmpire; - int32_t lSize; -} TPacketGGMonarchNotice; - //FORKED_ROAD typedef struct SPacketGGForkedMapInfo { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bPass; uint8_t bSungzi; } TPacketGGForkedMapInfo; //END_FORKED_ROAD typedef struct SPacketGGShutdown { - uint8_t bHeader; + uint16_t header; + uint16_t length; } TPacketGGShutdown; typedef struct SPacketGGGuild { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bSubHeader; uint32_t dwGuild; } TPacketGGGuild; -enum -{ - GUILD_SUBHEADER_GG_CHAT, - GUILD_SUBHEADER_GG_SET_MEMBER_COUNT_BONUS, -}; - typedef struct SPacketGGGuildChat { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bSubHeader; uint32_t dwGuild; char szText[CHAT_MAX_LEN + 1]; @@ -391,100 +77,91 @@ typedef struct SPacketGGGuildChat typedef struct SPacketGGParty { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t subheader; uint32_t pid; uint32_t leaderpid; } TPacketGGParty; -enum -{ - PARTY_SUBHEADER_GG_CREATE, - PARTY_SUBHEADER_GG_DESTROY, - PARTY_SUBHEADER_GG_JOIN, - PARTY_SUBHEADER_GG_QUIT, -}; - typedef struct SPacketGGDisconnect { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szLogin[LOGIN_MAX_LEN + 1]; } TPacketGGDisconnect; typedef struct SPacketGGShout { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bEmpire; char szText[CHAT_MAX_LEN + 1]; } TPacketGGShout; typedef struct SPacketGGXmasWarpSanta { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bChannel; int32_t lMapIndex; } TPacketGGXmasWarpSanta; typedef struct SPacketGGXmasWarpSantaReply { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bChannel; } TPacketGGXmasWarpSantaReply; -typedef struct SMessengerData -{ - char szMobile[MOBILE_MAX_LEN + 1]; -} TMessengerData; - typedef struct SPacketGGMessenger -{ - uint8_t bHeader; +{ + uint16_t header; + uint16_t length; char szAccount[CHARACTER_NAME_MAX_LEN + 1]; char szCompanion[CHARACTER_NAME_MAX_LEN + 1]; } TPacketGGMessenger; typedef struct SPacketGGMessengerRequest { - uint8_t header; + uint16_t header; + uint16_t length; char account[CHARACTER_NAME_MAX_LEN + 1]; char target[CHARACTER_NAME_MAX_LEN + 1]; } TPacketGGMessengerRequest; typedef struct SPacketGGMessengerResponse { - BYTE bHeader; + uint16_t header; + uint16_t length; char szRequester[CHARACTER_NAME_MAX_LEN + 1]; char szTarget[CHARACTER_NAME_MAX_LEN + 1]; BYTE bResponseType; // 0=already_sent, 1=already_received_reverse, 2=quest_running, 3=blocking_requests } TPacketGGMessengerResponse; -typedef struct SPacketGGMessengerMobile -{ - uint8_t bHeader; - char szName[CHARACTER_NAME_MAX_LEN + 1]; - char szMobile[MOBILE_MAX_LEN + 1]; -} TPacketGGMessengerMobile; - typedef struct SPacketGGFindPosition { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwFromPID; // 저 위치로 워프하려는 사람 uint32_t dwTargetPID; // 찾는 사람 } TPacketGGFindPosition; typedef struct SPacketGGWarpCharacter { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; int32_t x; int32_t y; } TPacketGGWarpCharacter; -// HEADER_GG_GUILD_WAR_ZONE_MAP_INDEX = 15, +// GG::GUILD_WAR_ZONE_MAP_INDEX = 15, typedef struct SPacketGGGuildWarMapIndex { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwGuildID1; uint32_t dwGuildID2; int32_t lMapIndex; @@ -492,27 +169,31 @@ typedef struct SPacketGGGuildWarMapIndex typedef struct SPacketGGTransfer { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szName[CHARACTER_NAME_MAX_LEN + 1]; int32_t lX, lY; } TPacketGGTransfer; typedef struct SPacketGGLoginPing { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szLogin[LOGIN_MAX_LEN + 1]; } TPacketGGLoginPing; typedef struct SPacketGGBlockChat { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szName[CHARACTER_NAME_MAX_LEN + 1]; int32_t lBlockDuration; } TPacketGGBlockChat; typedef struct packet_gg_mark_update { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwGuildID; uint16_t wImgIdx; } TPacketGGMarkUpdate; @@ -521,67 +202,66 @@ typedef struct packet_gg_mark_update typedef struct command_text { - uint8_t bHeader; + uint16_t header; + uint16_t length; } TPacketCGText; -/* 로그인 (1) */ -typedef struct command_handshake -{ - uint8_t bHeader; - uint32_t dwHandshake; - uint32_t dwTime; - int32_t lDelta; -} TPacketCGHandshake; - typedef struct command_login2 { - uint8_t header; + uint16_t header; + uint16_t length; char login[LOGIN_MAX_LEN + 1]; uint32_t dwLoginKey; } TPacketCGLogin2; typedef struct command_login3 { - uint8_t header; + uint16_t header; + uint16_t length; char login[LOGIN_MAX_LEN + 1]; char passwd[PASSWD_MAX_LEN + 1]; } TPacketCGLogin3; typedef struct packet_login_key { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwLoginKey; } TPacketGCLoginKey; typedef struct command_player_select { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t index; } TPacketCGPlayerSelect; typedef struct command_player_delete { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t index; char private_code[8]; } TPacketCGPlayerDelete; typedef struct command_player_create { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t index; char name[CHARACTER_NAME_MAX_LEN + 1]; uint16_t job; uint8_t shape; uint8_t Con; - uint8_t int32_t; + uint8_t Int; uint8_t Str; uint8_t Dex; } TPacketCGPlayerCreate; typedef struct command_player_create_success { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t bAccountCharacterIndex; TSimplePlayer player; } TPacketGCPlayerCreateSuccess; @@ -589,7 +269,8 @@ typedef struct command_player_create_success // 공격 typedef struct command_attack { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bType; uint32_t dwVID; uint8_t bCRCMagicCubeProcPiece; @@ -611,7 +292,8 @@ enum EMoveFuncType // 이동 typedef struct command_move { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bFunc; uint8_t bArg; uint8_t bRot; @@ -630,54 +312,59 @@ typedef struct command_sync_position_element // 위치 동기화 typedef struct command_sync_position // 가변 패킷 { - uint8_t bHeader; - uint16_t wSize; + uint16_t header; + uint16_t length; } TPacketCGSyncPosition; /* 채팅 (3) */ typedef struct command_chat // 가변 패킷 { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t type; } TPacketCGChat; /* 귓속말 */ typedef struct command_whisper { - uint8_t bHeader; - uint16_t wSize; + uint16_t header; + uint16_t length; char szNameTo[CHARACTER_NAME_MAX_LEN + 1]; } TPacketCGWhisper; typedef struct command_entergame { - uint8_t header; + uint16_t header; + uint16_t length; } TPacketCGEnterGame; typedef struct command_item_use { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; } TPacketCGItemUse; typedef struct command_item_use_to_item { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; TItemPos TargetCell; } TPacketCGItemUseToItem; typedef struct command_item_drop { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; uint32_t gold; } TPacketCGItemDrop; typedef struct command_item_drop2 { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; uint32_t gold; uint8_t count; @@ -685,7 +372,8 @@ typedef struct command_item_drop2 typedef struct command_item_move { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; TItemPos CellTo; uint8_t count; @@ -693,38 +381,34 @@ typedef struct command_item_move typedef struct command_item_pickup { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; } TPacketCGItemPickup; typedef struct command_quickslot_add { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; TQuickslot slot; } TPacketCGQuickslotAdd; typedef struct command_quickslot_del { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; } TPacketCGQuickslotDel; typedef struct command_quickslot_swap { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; uint8_t change_pos; } TPacketCGQuickslotSwap; -enum -{ - SHOP_SUBHEADER_CG_END, - SHOP_SUBHEADER_CG_BUY, - SHOP_SUBHEADER_CG_SELL, - SHOP_SUBHEADER_CG_SELL2 -}; - typedef struct command_shop_buy { uint8_t count; @@ -738,29 +422,22 @@ typedef struct command_shop_sell typedef struct command_shop { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t subheader; } TPacketCGShop; typedef struct command_on_click { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; } TPacketCGOnClick; -enum -{ - EXCHANGE_SUBHEADER_CG_START, /* arg1 == vid of target character */ - EXCHANGE_SUBHEADER_CG_ITEM_ADD, /* arg1 == position of item */ - EXCHANGE_SUBHEADER_CG_ITEM_DEL, /* arg1 == position of item */ - EXCHANGE_SUBHEADER_CG_ELK_ADD, /* arg1 == amount of gold */ - EXCHANGE_SUBHEADER_CG_ACCEPT, /* arg1 == not used */ - EXCHANGE_SUBHEADER_CG_CANCEL, /* arg1 == not used */ -}; - typedef struct command_exchange { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t sub_header; uint32_t arg1; uint8_t arg2; @@ -769,13 +446,15 @@ typedef struct command_exchange typedef struct command_position { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t position; } TPacketCGPosition; typedef struct command_script_answer { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t answer; //char file[32 + 1]; //uint8_t answer[16 + 1]; @@ -784,26 +463,30 @@ typedef struct command_script_answer typedef struct command_script_button { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t idx; } TPacketCGScriptButton; typedef struct command_quest_input_string { - uint8_t header; + uint16_t header; + uint16_t length; char msg[64+1]; } TPacketCGQuestInputString; typedef struct command_quest_confirm { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t answer; uint32_t requestPID; } TPacketCGQuestConfirm; typedef struct command_quest_cancel { - uint8_t header; + uint16_t header; + uint16_t length; } TPacketCGQuestCancel; /* @@ -811,49 +494,20 @@ typedef struct command_quest_cancel */ typedef struct packet_quest_confirm { - uint8_t header; + uint16_t header; + uint16_t length; char msg[64+1]; int32_t timeout; uint32_t requestPID; } TPacketGCQuestConfirm; -typedef struct packet_handshake -{ - uint8_t bHeader; - uint32_t dwHandshake; - uint32_t dwTime; - int32_t lDelta; -} TPacketGCHandshake; - -enum EPhase -{ - PHASE_CLOSE, - PHASE_HANDSHAKE, - PHASE_LOGIN, - PHASE_SELECT, - PHASE_LOADING, - PHASE_GAME, - PHASE_DEAD, - - PHASE_CLIENT_CONNECTING, - PHASE_DBCLIENT, - PHASE_P2P, - PHASE_AUTH, -}; - typedef struct packet_phase { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t phase; } TPacketGCPhase; -typedef struct packet_bindudp -{ - uint8_t header; - uint32_t addr; - uint16_t port; -} TPacketGCBindUDP; - enum { LOGIN_FAILURE_ALREADY = 1, @@ -867,7 +521,8 @@ enum typedef struct packet_login_success { - uint8_t bHeader; + uint16_t header; + uint16_t length; TSimplePlayer players[PLAYER_PER_ACCOUNT]; uint32_t guild_id[PLAYER_PER_ACCOUNT]; char guild_name[PLAYER_PER_ACCOUNT][GUILD_NAME_MAX_LEN+1]; @@ -878,23 +533,41 @@ typedef struct packet_login_success typedef struct packet_auth_success { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwLoginKey; uint8_t bResult; } TPacketGCAuthSuccess; typedef struct packet_login_failure { - uint8_t header; + uint16_t header; + uint16_t length; char szStatus[ACCOUNT_STATUS_MAX_LEN + 1]; } TPacketGCLoginFailure; typedef struct packet_create_failure { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t bType; } TPacketGCCreateFailure; +// Minimal header-only packet (no payload) +typedef struct packet_gc_blank +{ + uint16_t header; + uint16_t length; +} TPacketGCBlank; + +// Character delete success (returns the account slot index that was deleted) +typedef struct packet_player_delete_success +{ + uint16_t header; + uint16_t length; + uint8_t account_index; +} TPacketGCDestroyCharacterSuccess; + enum { ADD_CHARACTER_STATE_DEAD = (1 << 0), @@ -915,7 +588,8 @@ enum ECharacterEquipmentPart typedef struct packet_add_char { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; float angle; @@ -934,7 +608,8 @@ typedef struct packet_add_char typedef struct packet_char_additional_info { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; char name[CHARACTER_NAME_MAX_LEN + 1]; uint16_t awPart[CHR_EQUIPPART_NUM]; @@ -949,7 +624,8 @@ typedef struct packet_char_additional_info /* typedef struct packet_update_char_old { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; uint16_t awPart[CHR_EQUIPPART_NUM]; @@ -968,7 +644,8 @@ typedef struct packet_char_additional_info typedef struct packet_update_char { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; uint16_t awPart[CHR_EQUIPPART_NUM]; @@ -987,14 +664,15 @@ typedef struct packet_update_char typedef struct packet_del_char { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t id; } TPacketGCCharacterDelete; typedef struct packet_chat // 가변 패킷 { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t type; uint32_t id; uint8_t bEmpire; @@ -1002,75 +680,46 @@ typedef struct packet_chat // 가변 패킷 typedef struct packet_whisper // 가변 패킷 { - uint8_t bHeader; - uint16_t wSize; + uint16_t header; + uint16_t length; uint8_t bType; char szNameFrom[CHARACTER_NAME_MAX_LEN + 1]; } TPacketGCWhisper; typedef struct packet_main_character { - uint8_t header; + enum { MUSIC_NAME_LEN = 24 }; + + uint16_t header; + uint16_t length; uint32_t dwVID; uint16_t wRaceNum; char szName[CHARACTER_NAME_MAX_LEN + 1]; - int32_t lx, ly, lz; - uint8_t empire; - uint8_t skill_group; -} TPacketGCMainCharacter; - -// SUPPORT_BGM -typedef struct packet_main_character3_bgm -{ - enum - { - MUSIC_NAME_LEN = 24, - }; - - uint8_t header; - uint32_t dwVID; - uint16_t wRaceNum; - char szChrName[CHARACTER_NAME_MAX_LEN + 1]; - char szBGMName[MUSIC_NAME_LEN + 1]; - int32_t lx, ly, lz; - uint8_t empire; - uint8_t skill_group; -} TPacketGCMainCharacter3_BGM; - -typedef struct packet_main_character4_bgm_vol -{ - enum - { - MUSIC_NAME_LEN = 24, - }; - - uint8_t header; - uint32_t dwVID; - uint16_t wRaceNum; - char szChrName[CHARACTER_NAME_MAX_LEN + 1]; char szBGMName[MUSIC_NAME_LEN + 1]; float fBGMVol; int32_t lx, ly, lz; uint8_t empire; uint8_t skill_group; -} TPacketGCMainCharacter4_BGM_VOL; -// END_OF_SUPPORT_BGM +} TPacketGCMainCharacter; typedef struct packet_points { - uint8_t header; + uint16_t header; + uint16_t length; int32_t points[POINT_MAX_NUM]; } TPacketGCPoints; typedef struct packet_skill_level { - uint8_t bHeader; + uint16_t header; + uint16_t length; TPlayerSkill skills[SKILL_MAX_NUM]; } TPacketGCSkillLevel; typedef struct packet_point_change { - int32_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; uint8_t type; int32_t amount; @@ -1079,25 +728,29 @@ typedef struct packet_point_change typedef struct packet_stun { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; } TPacketGCStun; typedef struct packet_dead { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; } TPacketGCDead; typedef struct packet_del_item { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos pos; } TPacketGCItemDel; typedef struct packet_item_set { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos pos; uint32_t vnum; uint8_t count; @@ -1110,7 +763,8 @@ typedef struct packet_item_set typedef struct packet_item_get { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwItemVnum; uint8_t bCount; uint8_t bArg; // 0: normal, 1: from party member (need extra handling) @@ -1119,7 +773,8 @@ typedef struct packet_item_get struct packet_item_use { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; uint32_t ch_vid; uint32_t victim_vid; @@ -1128,14 +783,16 @@ struct packet_item_use struct packet_item_move { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; TItemPos CellTo; }; typedef struct packet_item_update { - uint8_t header; + uint16_t header; + uint16_t length; TItemPos Cell; uint8_t count; int32_t alSockets[ITEM_SOCKET_MAX_NUM]; @@ -1144,7 +801,8 @@ typedef struct packet_item_update typedef struct packet_item_ground_add { - uint8_t bHeader; + uint16_t header; + uint16_t length; int32_t x, y, z; uint32_t dwVID; uint32_t dwVnum; @@ -1152,61 +810,51 @@ typedef struct packet_item_ground_add typedef struct packet_item_ownership { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwVID; char szName[CHARACTER_NAME_MAX_LEN + 1]; } TPacketGCItemOwnership; typedef struct packet_item_ground_del { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwVID; } TPacketGCItemGroundDel; struct packet_quickslot_add { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; TQuickslot slot; }; struct packet_quickslot_del { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; }; struct packet_quickslot_swap { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; uint8_t pos_to; }; struct packet_motion { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; uint32_t victim_vid; uint16_t motion; }; -enum EPacketShopSubHeaders -{ - SHOP_SUBHEADER_GC_START, - SHOP_SUBHEADER_GC_END, - SHOP_SUBHEADER_GC_UPDATE_ITEM, - SHOP_SUBHEADER_GC_UPDATE_PRICE, - SHOP_SUBHEADER_GC_OK, - SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY, - SHOP_SUBHEADER_GC_SOLDOUT, - SHOP_SUBHEADER_GC_INVENTORY_FULL, - SHOP_SUBHEADER_GC_INVALID_POS, - SHOP_SUBHEADER_GC_SOLD_OUT, - SHOP_SUBHEADER_GC_START_EX, - SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY_EX, -}; - struct packet_shop_item { uint32_t vnum; @@ -1248,14 +896,15 @@ typedef struct packet_shop_update_price typedef struct packet_shop // 가변 패킷 { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t subheader; } TPacketGCShop; struct packet_exchange { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t sub_header; uint8_t is_me; uint32_t arg1; // vnum @@ -1265,48 +914,47 @@ struct packet_exchange TPlayerItemAttribute aAttr[ITEM_ATTRIBUTE_MAX_NUM]; }; -enum EPacketTradeSubHeaders -{ - EXCHANGE_SUBHEADER_GC_START, /* arg1 == vid */ - EXCHANGE_SUBHEADER_GC_ITEM_ADD, /* arg1 == vnum arg2 == pos arg3 == count */ - EXCHANGE_SUBHEADER_GC_ITEM_DEL, - EXCHANGE_SUBHEADER_GC_GOLD_ADD, /* arg1 == gold */ - EXCHANGE_SUBHEADER_GC_ACCEPT, /* arg1 == accept */ - EXCHANGE_SUBHEADER_GC_END, /* arg1 == not used */ - EXCHANGE_SUBHEADER_GC_ALREADY, /* arg1 == not used */ - EXCHANGE_SUBHEADER_GC_LESS_GOLD, /* arg1 == not used */ -}; - struct packet_position { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; uint8_t position; }; typedef struct packet_ping { - uint8_t header; + uint16_t header; + uint16_t length; + uint32_t server_time; } TPacketGCPing; +typedef struct packet_pong +{ + uint16_t header; + uint16_t length; +} TPacketCGPong; + struct packet_script { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t skin; uint16_t src_size; }; typedef struct packet_change_speed { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; uint16_t moving_speed; } TPacketGCChangeSpeed; struct packet_mount { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; uint32_t mount_vid; uint8_t pos; @@ -1315,7 +963,8 @@ struct packet_mount typedef struct packet_move { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bFunc; uint8_t bArg; uint8_t bRot; @@ -1329,7 +978,8 @@ typedef struct packet_move // 소유권 typedef struct packet_ownership { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwOwnerVID; uint32_t dwVictimVID; } TPacketGCOwnership; @@ -1345,13 +995,14 @@ typedef struct packet_sync_position_element // 위치 동기화 typedef struct packet_sync_position // 가변 패킷 { - uint8_t bHeader; - uint16_t wSize; // 개수 = (wSize - sizeof(TPacketGCSyncPosition)) / sizeof(TPacketGCSyncPositionElement) + uint16_t header; + uint16_t length; } TPacketGCSyncPosition; typedef struct packet_fly { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bType; uint32_t dwStartVID; uint32_t dwEndVID; @@ -1359,14 +1010,16 @@ typedef struct packet_fly typedef struct command_fly_targeting { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwTargetVID; int32_t x, y; } TPacketCGFlyTargeting; typedef struct packet_fly_targeting { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwShooterVID; uint32_t dwTargetVID; int32_t x, y; @@ -1374,14 +1027,15 @@ typedef struct packet_fly_targeting typedef struct packet_shoot { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bType; } TPacketCGShoot; typedef struct packet_duel_start { - uint8_t header; - uint16_t wSize; // uint32_t가 몇개? 개수 = (wSize - sizeof(TPacketGCPVPList)) / 4 + uint16_t header; + uint16_t length; } TPacketGCDuelStart; enum EPVPModes @@ -1394,7 +1048,8 @@ enum EPVPModes typedef struct packet_pvp { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwVIDSrc; uint32_t dwVIDDst; uint8_t bMode; // 0 이면 끔, 1이면 켬 @@ -1402,27 +1057,31 @@ typedef struct packet_pvp typedef struct command_use_skill { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwVnum; uint32_t dwVID; } TPacketCGUseSkill; typedef struct command_target { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; } TPacketCGTarget; typedef struct packet_target { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; uint8_t bHPPercent; } TPacketGCTarget; typedef struct packet_warp { - uint8_t bHeader; + uint16_t header; + uint16_t length; int32_t lX; int32_t lY; int32_t lAddr; @@ -1431,31 +1090,22 @@ typedef struct packet_warp typedef struct command_warp { - uint8_t bHeader; + uint16_t header; + uint16_t length; } TPacketCGWarp; struct packet_quest_info { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint16_t index; uint8_t flag; }; -enum -{ - MESSENGER_SUBHEADER_GC_LIST, - MESSENGER_SUBHEADER_GC_LOGIN, - MESSENGER_SUBHEADER_GC_LOGOUT, - MESSENGER_SUBHEADER_GC_INVITE, - MESSENGER_SUBHEADER_GC_MOBILE, - MESSENGER_SUBHEADER_GC_REMOVE_FRIEND -}; - typedef struct packet_messenger { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t subheader; } TPacketGCMessenger; @@ -1491,17 +1141,10 @@ typedef struct packet_messenger_list_online uint8_t length; } TPacketGCMessengerListOnline; -enum -{ - MESSENGER_SUBHEADER_CG_ADD_BY_VID, - MESSENGER_SUBHEADER_CG_ADD_BY_NAME, - MESSENGER_SUBHEADER_CG_REMOVE, - MESSENGER_SUBHEADER_CG_INVITE_ANSWER, -}; - typedef struct command_messenger { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t subheader; } TPacketCGMessenger; @@ -1524,14 +1167,16 @@ typedef struct command_messenger_remove typedef struct command_safebox_checkout { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bSafePos; TItemPos ItemPos; } TPacketCGSafeboxCheckout; typedef struct command_safebox_checkin { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bSafePos; TItemPos ItemPos; } TPacketCGSafeboxCheckin; @@ -1541,45 +1186,52 @@ typedef struct command_safebox_checkin typedef struct command_party_parameter { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bDistributeMode; } TPacketCGPartyParameter; typedef struct paryt_parameter { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bDistributeMode; } TPacketGCPartyParameter; typedef struct packet_party_add { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; char name[CHARACTER_NAME_MAX_LEN+1]; } TPacketGCPartyAdd; typedef struct command_party_invite { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; } TPacketCGPartyInvite; typedef struct packet_party_invite { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t leader_vid; } TPacketGCPartyInvite; typedef struct command_party_invite_answer { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t leader_vid; uint8_t accept; } TPacketCGPartyInviteAnswer; typedef struct packet_party_update { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; uint8_t role; uint8_t percent_hp; @@ -1588,33 +1240,38 @@ typedef struct packet_party_update typedef struct packet_party_remove { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; } TPacketGCPartyRemove; typedef struct packet_party_link { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; uint32_t vid; } TPacketGCPartyLink; typedef struct packet_party_unlink { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; uint32_t vid; } TPacketGCPartyUnlink; typedef struct command_party_remove { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; } TPacketCGPartyRemove; typedef struct command_party_set_state { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; uint8_t byRole; uint8_t flag; @@ -1628,31 +1285,36 @@ enum typedef struct command_party_use_skill { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t bySkillIndex; uint32_t vid; } TPacketCGPartyUseSkill; typedef struct packet_safebox_size { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bSize; } TPacketCGSafeboxSize; typedef struct packet_safebox_wrong_password { - uint8_t bHeader; + uint16_t header; + uint16_t length; } TPacketCGSafeboxWrongPassword; typedef struct command_empire { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bEmpire; } TPacketCGEmpire; typedef struct packet_empire { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bEmpire; } TPacketGCEmpire; @@ -1664,74 +1326,32 @@ enum typedef struct command_safebox_money { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bState; int32_t lMoney; } TPacketCGSafeboxMoney; typedef struct packet_safebox_money_change { - uint8_t bHeader; + uint16_t header; + uint16_t length; int32_t lMoney; } TPacketGCSafeboxMoneyChange; // Guild -enum -{ - GUILD_SUBHEADER_GC_LOGIN, - GUILD_SUBHEADER_GC_LOGOUT, - GUILD_SUBHEADER_GC_LIST, - GUILD_SUBHEADER_GC_GRADE, - GUILD_SUBHEADER_GC_ADD, - GUILD_SUBHEADER_GC_REMOVE, - GUILD_SUBHEADER_GC_GRADE_NAME, - GUILD_SUBHEADER_GC_GRADE_AUTH, - GUILD_SUBHEADER_GC_INFO, - GUILD_SUBHEADER_GC_COMMENTS, - GUILD_SUBHEADER_GC_CHANGE_EXP, - GUILD_SUBHEADER_GC_CHANGE_MEMBER_GRADE, - GUILD_SUBHEADER_GC_SKILL_INFO, - GUILD_SUBHEADER_GC_CHANGE_MEMBER_GENERAL, - GUILD_SUBHEADER_GC_GUILD_INVITE, - GUILD_SUBHEADER_GC_WAR, - GUILD_SUBHEADER_GC_GUILD_NAME, - GUILD_SUBHEADER_GC_GUILD_WAR_LIST, - GUILD_SUBHEADER_GC_GUILD_WAR_END_LIST, - GUILD_SUBHEADER_GC_WAR_SCORE, - GUILD_SUBHEADER_GC_MONEY_CHANGE, -}; - -enum GUILD_SUBHEADER_CG -{ - GUILD_SUBHEADER_CG_ADD_MEMBER, - GUILD_SUBHEADER_CG_REMOVE_MEMBER, - GUILD_SUBHEADER_CG_CHANGE_GRADE_NAME, - GUILD_SUBHEADER_CG_CHANGE_GRADE_AUTHORITY, - GUILD_SUBHEADER_CG_OFFER, - GUILD_SUBHEADER_CG_POST_COMMENT, - GUILD_SUBHEADER_CG_DELETE_COMMENT, - GUILD_SUBHEADER_CG_REFRESH_COMMENT, - GUILD_SUBHEADER_CG_CHANGE_MEMBER_GRADE, - GUILD_SUBHEADER_CG_USE_SKILL, - GUILD_SUBHEADER_CG_CHANGE_MEMBER_GENERAL, - GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER, - GUILD_SUBHEADER_CG_CHARGE_GSP, - GUILD_SUBHEADER_CG_DEPOSIT_MONEY, - GUILD_SUBHEADER_CG_WITHDRAW_MONEY, -}; - typedef struct packet_guild { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t subheader; } TPacketGCGuild; typedef struct packet_guild_name_t { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t subheader; uint32_t guildID; char guildName[GUILD_NAME_MAX_LEN]; @@ -1747,13 +1367,15 @@ typedef struct packet_guild_war typedef struct command_guild { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t subheader; } TPacketCGGuild; typedef struct command_guild_answer_make_guild { - uint8_t header; + uint16_t header; + uint16_t length; char guild_name[GUILD_NAME_MAX_LEN+1]; } TPacketCGAnswerMakeGuild; @@ -1766,33 +1388,38 @@ typedef struct command_guild_use_skill // Guild Mark typedef struct command_mark_login { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t handle; uint32_t random_key; } TPacketCGMarkLogin; typedef struct command_mark_upload { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t gid; uint8_t image[16*12*4]; } TPacketCGMarkUpload; typedef struct command_mark_idxlist { - uint8_t header; + uint16_t header; + uint16_t length; } TPacketCGMarkIDXList; typedef struct command_mark_crclist { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t imgIdx; uint32_t crclist[80]; } TPacketCGMarkCRCList; typedef struct packet_mark_idxlist { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t bufSize; uint16_t count; //뒤에 size * (uint16_t + uint16_t)만큼 데이터 붙음 @@ -1800,7 +1427,8 @@ typedef struct packet_mark_idxlist typedef struct packet_mark_block { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t bufSize; uint8_t imgIdx; uint32_t count; @@ -1809,21 +1437,23 @@ typedef struct packet_mark_block typedef struct packet_mark_update { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t guildID; uint16_t imgIdx; } TPacketGCMarkUpdate; typedef struct command_symbol_upload { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint32_t guild_id; } TPacketCGGuildSymbolUpload; typedef struct command_symbol_crc { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t guild_id; uint32_t crc; uint32_t size; @@ -1831,8 +1461,8 @@ typedef struct command_symbol_crc typedef struct packet_symbol_data { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint32_t guild_id; } TPacketGCGuildSymbolData; @@ -1840,31 +1470,24 @@ typedef struct packet_symbol_data typedef struct command_fishing { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t dir; } TPacketCGFishing; typedef struct packet_fishing { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t subheader; uint32_t info; uint8_t dir; } TPacketGCFishing; -enum -{ - FISHING_SUBHEADER_GC_START, - FISHING_SUBHEADER_GC_STOP, - FISHING_SUBHEADER_GC_REACT, - FISHING_SUBHEADER_GC_SUCCESS, - FISHING_SUBHEADER_GC_FAIL, - FISHING_SUBHEADER_GC_FISH, -}; - typedef struct command_give_item { - uint8_t byHeader; + uint16_t header; + uint16_t length; uint32_t dwTargetVID; TItemPos ItemPos; uint8_t byItemCount; @@ -1872,21 +1495,15 @@ typedef struct command_give_item typedef struct SPacketCGHack { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szBuf[255 + 1]; } TPacketCGHack; -// SubHeader - Dungeon -enum -{ - DUNGEON_SUBHEADER_GC_TIME_ATTACK_START = 0, - DUNGEON_SUBHEADER_GC_DESTINATION_POSITION = 1, -}; - typedef struct packet_dungeon { - uint8_t bHeader; - uint16_t size; + uint16_t header; + uint16_t length; uint8_t subheader; } TPacketGCDungeon; @@ -1898,21 +1515,24 @@ typedef struct packet_dungeon_dest_position typedef struct SPacketGCShopSign { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwVID; char szSign[SHOP_SIGN_MAX_LEN + 1]; } TPacketGCShopSign; typedef struct SPacketCGMyShop { - uint8_t bHeader; + uint16_t header; + uint16_t length; char szSign[SHOP_SIGN_MAX_LEN + 1]; uint8_t bCount; } TPacketCGMyShop; typedef struct SPacketGCTime { - uint8_t bHeader; + uint16_t header; + uint16_t length; time_t time; } TPacketGCTime; @@ -1924,33 +1544,38 @@ enum typedef struct SPacketGCWalkMode { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; uint8_t mode; } TPacketGCWalkMode; typedef struct SPacketGCChangeSkillGroup { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t skill_group; } TPacketGCChangeSkillGroup; typedef struct SPacketCGRefine { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; uint8_t type; } TPacketCGRefine; typedef struct SPacketCGRequestRefineInfo { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t pos; } TPacketCGRequestRefineInfo; typedef struct SPacketGCRefineInformaion { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t type; uint8_t pos; uint32_t src_vnum; @@ -1972,8 +1597,8 @@ struct TNPCPosition typedef struct SPacketGCNPCPosition { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; uint16_t count; // array of TNPCPosition @@ -1981,21 +1606,24 @@ typedef struct SPacketGCNPCPosition typedef struct SPacketGCSpecialEffect { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t type; uint32_t vid; } TPacketGCSpecialEffect; typedef struct SPacketCGChangeName { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t index; char name[CHARACTER_NAME_MAX_LEN+1]; } TPacketCGChangeName; typedef struct SPacketGCChangeName { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t pid; char name[CHARACTER_NAME_MAX_LEN+1]; } TPacketGCChangeName; @@ -2003,27 +1631,23 @@ typedef struct SPacketGCChangeName typedef struct command_client_version { - uint8_t header; + uint16_t header; + uint16_t length; char filename[32+1]; char timestamp[32+1]; } TPacketCGClientVersion; -typedef struct command_client_version2 -{ - uint8_t header; - char filename[32+1]; - char timestamp[32+1]; -} TPacketCGClientVersion2; - typedef struct packet_channel { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t channel; } TPacketGCChannel; typedef struct pakcet_view_equip { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; struct { uint32_t vnum; @@ -2043,13 +1667,14 @@ typedef struct typedef struct packet_land_list { - uint8_t header; - uint16_t size; + uint16_t header; + uint16_t length; } TPacketGCLandList; typedef struct { - uint8_t bHeader; + uint16_t header; + uint16_t length; int32_t lID; char szName[32+1]; uint32_t dwVID; @@ -2058,47 +1683,54 @@ typedef struct typedef struct { - uint8_t bHeader; + uint16_t header; + uint16_t length; int32_t lID; int32_t lX, lY; } TPacketGCTargetUpdate; typedef struct { - uint8_t bHeader; + uint16_t header; + uint16_t length; int32_t lID; } TPacketGCTargetDelete; typedef struct { - uint8_t bHeader; + uint16_t header; + uint16_t length; TPacketAffectElement elem; } TPacketGCAffectAdd; typedef struct { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint32_t dwType; uint8_t bApplyOn; } TPacketGCAffectRemove; typedef struct packet_lover_info { - uint8_t header; + uint16_t header; + uint16_t length; char name[CHARACTER_NAME_MAX_LEN + 1]; uint8_t love_point; } TPacketGCLoverInfo; typedef struct packet_love_point_update { - uint8_t header; + uint16_t header; + uint16_t length; uint8_t love_point; } TPacketGCLovePointUpdate; // MINING typedef struct packet_dig_motion { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; uint32_t target_vid; uint8_t count; @@ -2108,14 +1740,16 @@ typedef struct packet_dig_motion // SCRIPT_SELECT_ITEM typedef struct command_script_select_item { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t selection; } TPacketCGScriptSelectItem; // END_OF_SCRIPT_SELECT_ITEM typedef struct packet_damage_info { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t dwVID; uint8_t flag; int32_t damage; @@ -2123,22 +1757,16 @@ typedef struct packet_damage_info typedef struct tag_GGSiege { - uint8_t bHeader; + uint16_t header; + uint16_t length; uint8_t bEmpire; uint8_t bTowerCount; } TPacketGGSiege; -typedef struct SPacketGGMonarchTransfer -{ - uint8_t bHeader; - uint32_t dwTargetPID; - int32_t x; - int32_t y; -} TPacketMonarchGGTransfer; - typedef struct SPacketGGCheckAwakeness { - uint8_t bHeader; + uint16_t header; + uint16_t length; } TPacketGGCheckAwakeness; // Secure authentication packets (libsodium/XChaCha20-Poly1305) @@ -2147,15 +1775,18 @@ typedef struct SPacketGGCheckAwakeness // Server -> Client: Key exchange challenge struct TPacketGCKeyChallenge { - uint8_t bHeader; // HEADER_GC_KEY_CHALLENGE (0xf8) + uint16_t header; // GC::KEY_CHALLENGE (0xf8) + uint16_t length; uint8_t server_pk[32]; // Server's X25519 public key uint8_t challenge[32]; // Random challenge bytes + uint32_t server_time; // Server's current time for client sync }; // Client -> Server: Key exchange response struct TPacketCGKeyResponse { - uint8_t bHeader; // HEADER_CG_KEY_RESPONSE (0xf9) + uint16_t header; // CG::KEY_RESPONSE (0xf9) + uint16_t length; uint8_t client_pk[32]; // Client's X25519 public key uint8_t challenge_response[32]; // HMAC(challenge, rx_key) }; @@ -2163,7 +1794,8 @@ struct TPacketCGKeyResponse // Server -> Client: Key exchange complete struct TPacketGCKeyComplete { - uint8_t bHeader; // HEADER_GC_KEY_COMPLETE (0xf7) + uint16_t header; // GC::KEY_COMPLETE (0xf7) + uint16_t length; uint8_t encrypted_token[32 + 16]; // Session token + Poly1305 tag uint8_t nonce[24]; // XChaCha20 nonce }; @@ -2171,7 +1803,8 @@ struct TPacketGCKeyComplete // Client -> Server: Secure login struct TPacketCGLoginSecure { - uint8_t bHeader; // HEADER_CG_LOGIN_SECURE (0xf6) + uint16_t header; // CG::LOGIN_SECURE (0xf6) + uint16_t length; char name[LOGIN_MAX_LEN + 1]; char pwd[PASSWD_MAX_LEN + 1]; uint8_t session_token[32]; // Session token from KeyComplete @@ -2182,7 +1815,8 @@ struct TPacketCGLoginSecure #define MAX_EFFECT_FILE_NAME 128 typedef struct SPacketGCSpecificEffect { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t vid; char effect_file[MAX_EFFECT_FILE_NAME]; } TPacketGCSpecificEffect; @@ -2195,49 +1829,38 @@ enum EDragonSoulRefineWindowRefineType DragonSoulRefineWindow_REFINE, }; -enum EPacketCGDragonSoulSubHeaderType -{ - DS_SUB_HEADER_OPEN, - DS_SUB_HEADER_CLOSE, - DS_SUB_HEADER_DO_REFINE_GRADE, - DS_SUB_HEADER_DO_REFINE_STEP, - DS_SUB_HEADER_DO_REFINE_STRENGTH, - DS_SUB_HEADER_REFINE_FAIL, - DS_SUB_HEADER_REFINE_FAIL_MAX_REFINE, - DS_SUB_HEADER_REFINE_FAIL_INVALID_MATERIAL, - DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MONEY, - DS_SUB_HEADER_REFINE_FAIL_NOT_ENOUGH_MATERIAL, - DS_SUB_HEADER_REFINE_FAIL_TOO_MUCH_MATERIAL, - DS_SUB_HEADER_REFINE_SUCCEED, -}; typedef struct SPacketCGDragonSoulRefine { - SPacketCGDragonSoulRefine() : header (HEADER_CG_DRAGON_SOUL_REFINE) + SPacketCGDragonSoulRefine() : header(CG::DRAGON_SOUL_REFINE), length(sizeof(SPacketCGDragonSoulRefine)) {} - uint8_t header; + uint16_t header; + uint16_t length; uint8_t bSubType; TItemPos ItemGrid[DRAGON_SOUL_REFINE_GRID_SIZE]; } TPacketCGDragonSoulRefine; typedef struct SPacketGCDragonSoulRefine { - SPacketGCDragonSoulRefine() : header(HEADER_GC_DRAGON_SOUL_REFINE) + SPacketGCDragonSoulRefine() : header(GC::DRAGON_SOUL_REFINE), length(sizeof(SPacketGCDragonSoulRefine)) {} - uint8_t header; + uint16_t header; + uint16_t length; uint8_t bSubType; TItemPos Pos; } TPacketGCDragonSoulRefine; typedef struct SPacketCGStateCheck { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t key; uint32_t index; } TPacketCGStateCheck; typedef struct SPacketGCStateCheck { - uint8_t header; + uint16_t header; + uint16_t length; uint32_t key; uint32_t index; unsigned char state; diff --git a/src/game/packet_writer.h b/src/game/packet_writer.h new file mode 100644 index 0000000..c2823e7 --- /dev/null +++ b/src/game/packet_writer.h @@ -0,0 +1,139 @@ +#pragma once + +#include +#include +#include + +// 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(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(v)); } + bool WriteI16(int16_t v) { return WriteU16(static_cast(v)); } + bool WriteI32(int32_t v) { return WriteU32(static_cast(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; +}; diff --git a/src/game/party.cpp b/src/game/party.cpp index a2a6bae..58f1f09 100644 --- a/src/game/party.cpp +++ b/src/game/party.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "char.h" #include "party.h" @@ -138,14 +138,14 @@ LPPARTY CPartyManager::CreateParty(LPCHARACTER pLeader) if (pLeader->IsPC()) { //TPacketGGParty p; - //p.header = HEADER_GG_PARTY; - //p.subheader = PARTY_SUBHEADER_GG_CREATE; + //p.header = GG::PARTY; + //p.subheader = PartySub::GG::CREATE; //p.pid = pLeader->GetPlayerID(); //P2P_MANAGER::instance().Send(&p, sizeof(p)); TPacketPartyCreate p; p.dwLeaderPID = pLeader->GetPlayerID(); - db_clientdesc->DBPacket(HEADER_GD_PARTY_CREATE, 0, &p, sizeof(TPacketPartyCreate)); + db_clientdesc->DBPacket(GD::PARTY_CREATE, 0, &p, sizeof(TPacketPartyCreate)); sys_log(0, "PARTY: Create %s pid %u", pLeader->GetName(), pLeader->GetPlayerID()); pParty->SetPCParty(true); @@ -166,14 +166,14 @@ LPPARTY CPartyManager::CreateParty(LPCHARACTER pLeader) void CPartyManager::DeleteParty(LPPARTY pParty) { //TPacketGGParty p; - //p.header = HEADER_GG_PARTY; - //p.subheader = PARTY_SUBHEADER_GG_DESTROY; + //p.header = GG::PARTY; + //p.subheader = PartySub::GG::DESTROY; //p.pid = pParty->GetLeaderPID(); //P2P_MANAGER::instance().Send(&p, sizeof(p)); TPacketPartyDelete p; p.dwLeaderPID = pParty->GetLeaderPID(); - db_clientdesc->DBPacket(HEADER_GD_PARTY_DELETE, 0, &p, sizeof(TPacketPartyDelete)); + db_clientdesc->DBPacket(GD::PARTY_DELETE, 0, &p, sizeof(TPacketPartyDelete)); m_set_pkPCParty.erase(pParty); M2_DELETE(pParty); @@ -320,7 +320,8 @@ void CParty::Destroy() if (rMember.pCharacter->GetDesc()) { TPacketGCPartyRemove p; - p.header = HEADER_GC_PARTY_REMOVE; + p.header = GC::PARTY_REMOVE; + p.length = sizeof(p); p.pid = rMember.pCharacter->GetPlayerID(); rMember.pCharacter->GetDesc()->Packet(&p, sizeof(p)); rMember.pCharacter->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티가 해산 되었습니다.")); @@ -459,7 +460,7 @@ void CParty::Join(DWORD dwPID) p.dwLeaderPID = GetLeaderPID(); p.dwPID = dwPID; p.bState = PARTY_ROLE_NORMAL; // #0000790: [M2EU] CZ 크래쉬 증가: 초기화 중요! - db_clientdesc->DBPacket(HEADER_GD_PARTY_ADD, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::PARTY_ADD, 0, &p, sizeof(p)); } } @@ -519,15 +520,15 @@ void CParty::Quit(DWORD dwPID) if (m_bPCParty && dwPID != GetLeaderPID()) { //TPacketGGParty p; - //p.header = HEADER_GG_PARTY; - //p.subheader = PARTY_SUBHEADER_GG_QUIT; + //p.header = GG::PARTY; + //p.subheader = PartySub::GG::QUIT; //p.pid = dwPID; //p.leaderpid = GetLeaderPID(); //P2P_MANAGER::instance().Send(&p, sizeof(p)); TPacketPartyRemove p; p.dwPID = dwPID; p.dwLeaderPID = GetLeaderPID(); - db_clientdesc->DBPacket(HEADER_GD_PARTY_REMOVE, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::PARTY_REMOVE, 0, &p, sizeof(p)); } } @@ -596,7 +597,7 @@ void CParty::RequestSetMemberLevel(DWORD pid, BYTE level) p.dwLeaderPID = GetLeaderPID(); p.dwPID = pid; p.bLevel = level; - db_clientdesc->DBPacket(HEADER_GD_PARTY_SET_MEMBER_LEVEL, 0, &p, sizeof(TPacketPartySetMemberLevel)); + db_clientdesc->DBPacket(GD::PARTY_SET_MEMBER_LEVEL, 0, &p, sizeof(TPacketPartySetMemberLevel)); } void CParty::P2PSetMemberLevel(DWORD pid, BYTE level) @@ -671,7 +672,8 @@ void CParty::SendPartyRemoveOneToAll(DWORD pid) TMemberMap::iterator it; TPacketGCPartyRemove p; - p.header = HEADER_GC_PARTY_REMOVE; + p.header = GC::PARTY_REMOVE; + p.length = sizeof(p); p.pid = pid; for (it = m_memberMap.begin(); it != m_memberMap.end(); ++it) @@ -687,7 +689,8 @@ void CParty::SendPartyJoinOneToAll(DWORD pid) TPacketGCPartyAdd p; - p.header = HEADER_GC_PARTY_ADD; + p.header = GC::PARTY_ADD; + p.length = sizeof(p); p.pid = pid; strlcpy(p.name, r.strName.c_str(), sizeof(p.name)); @@ -705,7 +708,8 @@ void CParty::SendPartyJoinAllToOne(LPCHARACTER ch) TPacketGCPartyAdd p; - p.header = HEADER_GC_PARTY_ADD; + p.header = GC::PARTY_ADD; + p.length = sizeof(p); p.name[CHARACTER_NAME_MAX_LEN] = '\0'; for (TMemberMap::iterator it = m_memberMap.begin();it!= m_memberMap.end(); ++it) @@ -724,7 +728,8 @@ void CParty::SendPartyUnlinkOneToAll(LPCHARACTER ch) TMemberMap::iterator it; TPacketGCPartyLink p; - p.header = HEADER_GC_PARTY_UNLINK; + p.header = GC::PARTY_UNLINK; + p.length = sizeof(p); p.pid = ch->GetPlayerID(); p.vid = (DWORD)ch->GetVID(); @@ -745,7 +750,8 @@ void CParty::SendPartyLinkOneToAll(LPCHARACTER ch) TMemberMap::iterator it; TPacketGCPartyLink p; - p.header = HEADER_GC_PARTY_LINK; + p.header = GC::PARTY_LINK; + p.length = sizeof(p); p.vid = ch->GetVID(); p.pid = ch->GetPlayerID(); @@ -766,7 +772,8 @@ void CParty::SendPartyLinkAllToOne(LPCHARACTER ch) TMemberMap::iterator it; TPacketGCPartyLink p; - p.header = HEADER_GC_PARTY_LINK; + p.header = GC::PARTY_LINK; + p.length = sizeof(p); for (it = m_memberMap.begin();it!= m_memberMap.end(); ++it) { @@ -795,7 +802,8 @@ void CParty::SendPartyInfoOneToAll(DWORD pid) // Data Building TPacketGCPartyUpdate p; memset(&p, 0, sizeof(p)); - p.header = HEADER_GC_PARTY_UPDATE; + p.header = GC::PARTY_UPDATE; + p.length = sizeof(p); p.pid = pid; p.percent_hp = 255; p.role = it->second.bRole; @@ -843,7 +851,8 @@ void CParty::SendPartyInfoAllToOne(LPCHARACTER ch) { DWORD pid = it->first; memset(&p, 0, sizeof(p)); - p.header = HEADER_GC_PARTY_UPDATE; + p.header = GC::PARTY_UPDATE; + p.length = sizeof(p); p.pid = pid; p.percent_hp = 255; p.role = it->second.bRole; @@ -1438,7 +1447,8 @@ void CParty::UpdateOnlineState(DWORD dwPID, const char* name) TPacketGCPartyAdd p; - p.header = HEADER_GC_PARTY_ADD; + p.header = GC::PARTY_ADD; + p.length = sizeof(p); p.pid = dwPID; r.strName = name; strlcpy(p.name, name, sizeof(p.name)); @@ -1454,7 +1464,8 @@ void CParty::UpdateOfflineState(DWORD dwPID) //const TMember& r = m_memberMap[dwPID]; TPacketGCPartyAdd p; - p.header = HEADER_GC_PARTY_ADD; + p.header = GC::PARTY_ADD; + p.length = sizeof(p); p.pid = dwPID; memset(p.name, 0, CHARACTER_NAME_MAX_LEN+1); @@ -1575,7 +1586,8 @@ void CParty::SendParameter(LPCHARACTER ch) { TPacketGCPartyParameter p; - p.bHeader = HEADER_GC_PARTY_PARAMETER; + p.header = GC::PARTY_PARAMETER; + p.length = sizeof(p); p.bDistributeMode = m_iExpDistributionMode; LPDESC d = ch->GetDesc(); diff --git a/src/game/priv_manager.cpp b/src/game/priv_manager.cpp index 3d9e50e..fcacee9 100644 --- a/src/game/priv_manager.cpp +++ b/src/game/priv_manager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "priv_manager.h" #include "char.h" @@ -41,7 +41,7 @@ void CPrivManager::RequestGiveGuildPriv(DWORD guild_id, BYTE type, int value, ti p.guild_id = guild_id; p.duration_sec = duration_sec; - db_clientdesc->DBPacket(HEADER_GD_REQUEST_GUILD_PRIV, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::REQUEST_GUILD_PRIV, 0, &p, sizeof(p)); } void CPrivManager::RequestGiveEmpirePriv(BYTE empire, BYTE type, int value, time_t duration_sec) @@ -61,7 +61,7 @@ void CPrivManager::RequestGiveEmpirePriv(BYTE empire, BYTE type, int value, time p.empire = empire; p.duration_sec = duration_sec; - db_clientdesc->DBPacket(HEADER_GD_REQUEST_EMPIRE_PRIV, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::REQUEST_EMPIRE_PRIV, 0, &p, sizeof(p)); } void CPrivManager::RequestGiveCharacterPriv(DWORD pid, BYTE type, int value) @@ -79,7 +79,7 @@ void CPrivManager::RequestGiveCharacterPriv(DWORD pid, BYTE type, int value) p.value = value; p.pid = pid; - db_clientdesc->DBPacket(HEADER_GD_REQUEST_CHARACTER_PRIV, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::REQUEST_CHARACTER_PRIV, 0, &p, sizeof(p)); } void CPrivManager::GiveGuildPriv(DWORD guild_id, BYTE type, int value, BYTE bLog, time_t end_time_sec) diff --git a/src/game/protocol.h b/src/game/protocol.h index 78c7836..f5fa459 100644 --- a/src/game/protocol.h +++ b/src/game/protocol.h @@ -1,7 +1,6 @@ -#pragma once +#pragma once #include #include -#include "libthecore/buffer.h" inline const char *encode_byte(uint8_t ind) { @@ -38,24 +37,3 @@ inline uint32_t decode_4bytes(const void *a) { return (*((uint32_t*)a)); } - -#define packet_encode(buf, data, len) __packet_encode(buf, data, len, __FILE__, __LINE__) - -//#define DEFAULT_PACKET_BUFFER_SIZE 32768 -#define DEFAULT_PACKET_BUFFER_SIZE 65536 - -inline bool __packet_encode(LPBUFFER& pbuf, const void * data, int length, const char * file, int line) -{ - assert(NULL != pbuf); - assert(NULL != data); - - if (buffer_has_space(pbuf) < length) - { - //sys_err("buffer length exceeded buffer size: %d, encoding %d bytes (%s:%d)", buffer_size(pbuf), length, file, line); - return false; - } - - //buffer_adjust_size(pbuf, length); - buffer_write(pbuf, data, length); - return true; -} diff --git a/src/game/pvp.cpp b/src/game/pvp.cpp index f41051d..58e11f3 100644 --- a/src/game/pvp.cpp +++ b/src/game/pvp.cpp @@ -1,8 +1,8 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "pvp.h" #include "crc32.h" -#include "packet.h" +#include "packet_structs.h" #include "desc.h" #include "desc_manager.h" #include "char.h" @@ -65,7 +65,8 @@ void CPVP::Packet(bool bDelete) TPacketGCPVP pack; - pack.bHeader = HEADER_GC_PVP; + pack.header = GC::PVP; + pack.length = sizeof(pack); if (bDelete) { @@ -215,8 +216,8 @@ void CPVPManager::Insert(LPCHARACTER pkChr, LPCHARACTER pkVictim) int len = MIN(CHAT_MAX_LEN, strlen(msg) + 1); - pack.bHeader = HEADER_GC_WHISPER; - pack.wSize = sizeof(TPacketGCWhisper) + len; + pack.header = GC::WHISPER; + pack.length = sizeof(TPacketGCWhisper) + len; pack.bType = WHISPER_TYPE_SYSTEM; strlcpy(pack.szNameFrom, pkChr->GetName(), sizeof(pack.szNameFrom)); @@ -559,7 +560,8 @@ void CPVPManager::SendList(LPDESC d) TPacketGCPVP pack; - pack.bHeader = HEADER_GC_PVP; + pack.header = GC::PVP; + pack.length = sizeof(pack); while (it != m_map_pkPVP.end()) { diff --git a/src/game/questlua.cpp b/src/game/questlua.cpp index 40999a1..290c75a 100644 --- a/src/game/questlua.cpp +++ b/src/game/questlua.cpp @@ -480,9 +480,7 @@ namespace quest RegisterTargetFunctionTable(); RegisterArenaFunctionTable(); RegisterForkedFunctionTable(); - RegisterMonarchFunctionTable(); RegisterOXEventFunctionTable(); - RegisterMgmtFunctionTable(); RegisterBattleArenaFunctionTable(); RegisterDanceEventFunctionTable(); RegisterDragonLairFunctionTable(); diff --git a/src/game/questlua.h b/src/game/questlua.h index b289f5b..831c7d4 100644 --- a/src/game/questlua.h +++ b/src/game/questlua.h @@ -25,9 +25,7 @@ namespace quest extern void RegisterArenaFunctionTable(); extern void RegisterGlobalFunctionTable(lua_State* L); extern void RegisterForkedFunctionTable(); - extern void RegisterMonarchFunctionTable(); extern void RegisterOXEventFunctionTable(); - extern void RegisterMgmtFunctionTable(); extern void RegisterBattleArenaFunctionTable(); extern void RegisterDanceEventFunctionTable(); extern void RegisterDragonLairFunctionTable(); diff --git a/src/game/questlua_danceevent.cpp b/src/game/questlua_danceevent.cpp index 4fbbf59..4319c8e 100644 --- a/src/game/questlua_danceevent.cpp +++ b/src/game/questlua_danceevent.cpp @@ -14,7 +14,7 @@ namespace quest { LPCHARACTER ch = (LPCHARACTER) ent; - if ( ch->IsPC() == true && ch->IsGM() != true ) + if (ch->IsPC() && !ch->IsGM()) { if ( ((ch->GetX() >= 764503 && ch->GetX() <= 772362) && (ch->GetY() >= 22807 && ch->GetY() <= 26499)) == false ) { diff --git a/src/game/questlua_dungeon.cpp b/src/game/questlua_dungeon.cpp index a4a998f..fdceef6 100644 --- a/src/game/questlua_dungeon.cpp +++ b/src/game/questlua_dungeon.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "questmanager.h" #include "questlua.h" @@ -7,7 +7,7 @@ #include "party.h" #include "buffer_manager.h" #include "char_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "desc_client.h" #include "desc_manager.h" @@ -1268,10 +1268,10 @@ namespace quest { if(ch->CountSpecifyItem(it->first) >= it->second) { - packet_script.header = HEADER_GC_SCRIPT; + packet_script.header = GC::SCRIPT; packet_script.skin = quest::CQuestManager::QUEST_SKIN_NORMAL; packet_script.src_size = can_enter_ment.size(); - packet_script.size = packet_script.src_size + sizeof(struct packet_script); + packet_script.length = packet_script.src_size + sizeof(struct packet_script); buf.write(&packet_script, sizeof(struct packet_script)); buf.write(&can_enter_ment[0], can_enter_ment.size()); @@ -1280,10 +1280,10 @@ namespace quest } } - packet_script.header = HEADER_GC_SCRIPT; + packet_script.header = GC::SCRIPT; packet_script.skin = quest::CQuestManager::QUEST_SKIN_NORMAL; packet_script.src_size = cant_enter_ment.size(); - packet_script.size = packet_script.src_size + sizeof(struct packet_script); + packet_script.length = packet_script.src_size + sizeof(struct packet_script); buf.write(&packet_script, sizeof(struct packet_script)); buf.write(&cant_enter_ment[0], cant_enter_ment.size()); diff --git a/src/game/questlua_game.cpp b/src/game/questlua_game.cpp index 48388c6..426937b 100644 --- a/src/game/questlua_game.cpp +++ b/src/game/questlua_game.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "questlua.h" #include "questmanager.h" #include "desc_client.h" @@ -6,7 +6,7 @@ #include "item_manager.h" #include "item.h" #include "cmd.h" -#include "packet.h" +#include "packet_structs.h" #undef sys_err #define sys_err(fmt, ...) quest::CQuestManager::instance().QuestError(std::source_location::current(), fmt __VA_OPT__(, __VA_ARGS__)) @@ -43,8 +43,10 @@ namespace quest LPDESC d = q.GetCurrentCharacterPtr()->GetDesc(); if (d) { - BYTE header = HEADER_GC_REQUEST_MAKE_GUILD; - d->Packet(&header, 1); + TPacketGCBlank pack; + pack.header = GC::REQUEST_MAKE_GUILD; + pack.length = sizeof(pack); + d->Packet(&pack, sizeof(pack)); } return 0; } @@ -64,7 +66,7 @@ namespace quest TSafeboxChangeSizePacket p; p.dwID = q.GetCurrentCharacterPtr()->GetDesc()->GetAccountTable().id; p.bSize = (int)lua_tonumber(L,-1); - db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_CHANGE_SIZE, q.GetCurrentCharacterPtr()->GetDesc()->GetHandle(), &p, sizeof(p)); + db_clientdesc->DBPacket(GD::SAFEBOX_CHANGE_SIZE, q.GetCurrentCharacterPtr()->GetDesc()->GetHandle(), &p, sizeof(p)); q.GetCurrentCharacterPtr()->SetSafeboxSize(SAFEBOX_PAGE_SIZE * (int)lua_tonumber(L,-1)); return 0; diff --git a/src/game/questlua_global.cpp b/src/game/questlua_global.cpp index 1623f7a..ea9af10 100644 --- a/src/game/questlua_global.cpp +++ b/src/game/questlua_global.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "constants.h" #include "char.h" @@ -357,7 +357,7 @@ namespace quest sys_log(0, "QUEST: quest: %s player: %s : %s", pc->GetCurrentQuestName().c_str(), ch->GetName(), lua_tostring(L, 2)); - if (true == test_server) + if (test_server) { ch->ChatPacket(CHAT_TYPE_INFO, "QUEST_SYSLOG %s", lua_tostring(L, 2)); } @@ -872,14 +872,15 @@ namespace quest combine_lua_string(L, s); TPacketGGNotice p; - p.bHeader = HEADER_GG_NOTICE; + p.header = GG::NOTICE; p.lSize = strlen(s.str().c_str()) + 1; + p.length = sizeof(TPacketGGNotice) + p.lSize; TEMP_BUFFER buf; buf.write(&p, sizeof(p)); buf.write(s.str().c_str(), p.lSize); - P2P_MANAGER::instance().Send(buf.read_peek(), buf.size()); // HEADER_GG_NOTICE + P2P_MANAGER::instance().Send(buf.read_peek(), buf.size()); // GG::NOTICE SendNotice(s.str().c_str()); return 1; @@ -978,10 +979,10 @@ namespace quest struct ::packet_script packet_script; - packet_script.header = HEADER_GC_SCRIPT; + packet_script.header = GC::SCRIPT; packet_script.skin = CQuestManager::QUEST_SKIN_NORMAL; packet_script.src_size = Script.size(); - packet_script.size = packet_script.src_size + sizeof(struct packet_script); + packet_script.length = packet_script.src_size + sizeof(struct packet_script); FSendPacket f; f.buf.write(&packet_script, sizeof(struct packet_script)); @@ -1086,7 +1087,7 @@ namespace quest if (pChar != NULL) { - if (lua_isstring(L, 1) != true && lua_isstring(L, 2) != true) + if (!lua_isstring(L, 1) && !lua_isstring(L, 2)) { lua_pushboolean(L, false); return 1; diff --git a/src/game/questlua_guild.cpp b/src/game/questlua_guild.cpp index 82bc534..7706693 100644 --- a/src/game/questlua_guild.cpp +++ b/src/game/questlua_guild.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "questlua.h" #include "questmanager.h" @@ -194,7 +194,7 @@ namespace quest sys_log(0, "GUILD_WAR_BET: %s login %s war_id %u guild %u gold %u", ch->GetName(), p.szLogin, p.dwWarID, p.dwGuild, p.dwGold); - db_clientdesc->DBPacket(HEADER_GD_GUILD_WAR_BET, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::GUILD_WAR_BET, 0, &p, sizeof(p)); return 0; } @@ -386,7 +386,7 @@ namespace quest int nBeOtherLeader = pNewMaster->GetQuestFlag("change_guild_master.be_other_leader"); CQuestManager::instance().GetPC( ch->GetPlayerID() ); - if ( lua_toboolean(L, 6) == true ) nBeOtherLeader = 0; + if (lua_toboolean(L, 6)) nBeOtherLeader = 0; if ( nBeOtherLeader > get_global_time() ) { diff --git a/src/game/questlua_horse.cpp b/src/game/questlua_horse.cpp index 245e43e..e5c87eb 100644 --- a/src/game/questlua_horse.cpp +++ b/src/game/questlua_horse.cpp @@ -220,7 +220,7 @@ namespace quest // 1 : 잘못된 이름이다 // 2 : 이름 바꾸기 성공 - if ( lua_isstring(L, -1) != true ) return 0; + if (!lua_isstring(L, -1)) return 0; LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); @@ -234,7 +234,7 @@ namespace quest } else { - int nHorseNameDuration = test_server == true ? 60*5 : 60*60*24*30; + int nHorseNameDuration = test_server ? 60*5 : 60*60*24*30; ch->SetQuestFlag("horse_name.valid_till", get_global_time() + nHorseNameDuration); ch->AddAffect(AFFECT_HORSE_NAME, 0, 0, 0, PASSES_PER_SEC(nHorseNameDuration), 0, true); diff --git a/src/game/questlua_mgmt.cpp b/src/game/questlua_mgmt.cpp deleted file mode 100644 index 7edfef9..0000000 --- a/src/game/questlua_mgmt.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "stdafx.h" -#include "constants.h" -#include "questmanager.h" -#include "monarch.h" -#include "desc_client.h" - -namespace quest -{ - int mgmt_monarch_state(lua_State* L) - { - if ( lua_isnumber(L, 1) == false ) - { - return 0; - } - - int idx = (int)lua_tonumber(L, 1); - - if ( idx < 1 || idx > 3 ) - { - return 0; - } - - TMonarchInfo* info = CMonarch::instance().GetMonarch(); - - lua_pushstring(L, info->name[idx]); - lua_pushnumber(L, info->pid[idx]); - lua_pushstring(L, info->date[idx]); - lua_pushnumber(L, info->money[idx]); - - return 4; - } - - int mgmt_monarch_change_lord(lua_State* L) - { - if ( lua_isnumber(L, 1) == false || lua_isnumber(L, 2) == false ) - { - return 0; - } - - TPacketChangeMonarchLord info; - info.bEmpire = (BYTE)lua_tonumber(L, 1); - info.dwPID = (DWORD)lua_tonumber(L, 2); - - db_clientdesc->DBPacket(HEADER_GD_CHANGE_MONARCH_LORD, 0, &info, sizeof(info)); - - return 0; - } - - void RegisterMgmtFunctionTable() - { - luaL_reg mgmt_functions[] = - { - { "monarch_state", mgmt_monarch_state }, - { "monarch_change_lord", mgmt_monarch_change_lord }, - - { NULL, NULL} - }; - - CQuestManager::instance().AddLuaFunctionTable("mgmt", mgmt_functions); - } -} - diff --git a/src/game/questlua_monarch.cpp b/src/game/questlua_monarch.cpp deleted file mode 100644 index 8bbcff6..0000000 --- a/src/game/questlua_monarch.cpp +++ /dev/null @@ -1,980 +0,0 @@ -#include "stdafx.h" - -#include "questlua.h" -#include "questmanager.h" -#include "monarch.h" -#include "desc_client.h" -#include "start_position.h" -#include "config.h" -#include "mob_manager.h" -#include "castle.h" -#include "char.h" -#include "char_manager.h" -#include "utils.h" -#include "p2p.h" -#include "guild.h" -#include "sectree_manager.h" - -#undef sys_err -#define sys_err(fmt, ...) quest::CQuestManager::instance().QuestError(std::source_location::current(), fmt __VA_OPT__(, __VA_ARGS__)) - -ACMD(do_monarch_mob); - -namespace quest -{ - EVENTINFO(monarch_powerup_event_info) - { - int EmpireIndex; - - monarch_powerup_event_info() - : EmpireIndex( 0 ) - { - } - }; - - // NOTE: Copied from SPacketGGMonarchTransfer for event data - EVENTINFO(monarch_transfer2_event_info) - { - BYTE bHeader; - DWORD dwTargetPID; - long x; - long y; - - monarch_transfer2_event_info() - : bHeader( 0 ) - , dwTargetPID( 0 ) - , x( 0 ) - , y( 0 ) - { - } - }; - - EVENTFUNC(monarch_powerup_event) - { - monarch_powerup_event_info * info = dynamic_cast(event->info); - - if ( info == NULL ) - { - sys_err( "monarch_powerup_event> Null pointer" ); - return 0; - } - - CMonarch::instance().PowerUp(info->EmpireIndex, false); - return 0; - } - - EVENTINFO(monarch_defenseup_event_info) - { - int EmpireIndex; - - monarch_defenseup_event_info() - : EmpireIndex( 0 ) - { - } - }; - - EVENTFUNC(monarch_defenseup_event) - { - monarch_powerup_event_info * info = dynamic_cast(event->info); - - if ( info == NULL ) - { - sys_err( "monarch_defenseup_event> Null pointer" ); - return 0; - } - - CMonarch::instance().DefenseUp(info->EmpireIndex, false); - return 0; - } - - // - // "monarch_" lua functions - // - int takemonarchmoney(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - int nMoney = (int)lua_tonumber(L,1); - int nPID = ch->GetPlayerID(); - int nEmpire = ch->GetEmpire(); - nMoney = nMoney * 10000; - - sys_log(0 ,"[MONARCH] Take Money Empire(%d) pid(%d) Money(%d)", ch->GetEmpire(), ch->GetPlayerID(), nMoney); - - - db_clientdesc->DBPacketHeader(HEADER_GD_TAKE_MONARCH_MONEY, ch->GetDesc()->GetHandle(), sizeof(int) * 3); - db_clientdesc->Packet(&nEmpire, sizeof(int)); - db_clientdesc->Packet(&nPID, sizeof(int)); - db_clientdesc->Packet(&nMoney, sizeof(int)); - return 1; - } - - int is_guild_master(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (ch->GetGuild() ) - { - TGuildMember * pMember = ch->GetGuild()->GetMember(ch->GetPlayerID()); - - if (pMember) - { - if (pMember->grade <= 4) - { - lua_pushnumber(L ,1); - return 1; - } - } - - } - lua_pushnumber(L ,0); - - return 1; - } - - int monarch_bless(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (false==ch->IsMonarch()) - { - if (!ch->IsGM()) - { - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 자격을 가지고 있지 않습니다")); - sys_err("No Monarch pid %d ", ch->GetPlayerID()); - return 0; - } - } - - int HealPrice = quest::CQuestManager::instance().GetEventFlag("MonarchHealGold"); - if (HealPrice == 0) - HealPrice = 2000000; // 200만 - - if (CMonarch::instance().HealMyEmpire(ch, HealPrice)) - { - char szNotice[256]; - snprintf(szNotice, sizeof(szNotice), - LC_TEXT("군주의 축복으로 이지역 %s 유저는 HP,SP가 모두 채워집니다."), EMPIRE_NAME(ch->GetEmpire())); - SendNoticeMap(szNotice, ch->GetMapIndex(), false); - - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 축복을 사용하였습니다.")); - } - - return 1; - } - - // 군주의 사자후 퀘스트 함수 - int monarch_powerup(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (!ch) - return 0; - - //군주 체크 - if (false==ch->IsMonarch()) - { - if (!ch->IsGM()) - { - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 자격을 가지고 있지 않습니다")); - sys_err("No Monarch pid %d ", ch->GetPlayerID()); - return 0; - } - } - - //군주 국고 검사 - int money_need = 5000000; // 500만 - if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, money_need); - return 0; - } - - if (!CMonarch::instance().CheckPowerUpCT(ch->GetEmpire())) - { - int next_sec = CMonarch::instance().GetPowerUpCT(ch->GetEmpire()) / passes_per_sec; - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("쿨타임 적용중 %d 후 사용가능"), next_sec); - return 0; - } - - //군주의 사자후 적용 - CMonarch::instance().PowerUp(ch->GetEmpire(), true); - - //군주의 사자후 적용시간 - int g_nMonarchPowerUpCT = 60 * 3; - - monarch_powerup_event_info* info = AllocEventInfo(); - - info->EmpireIndex = ch->GetEmpire(); - - event_create(quest::monarch_powerup_event, info, PASSES_PER_SEC(g_nMonarchPowerUpCT)); - - CMonarch::instance().SendtoDBDecMoney(5000000, ch->GetEmpire(), ch); - - char szNotice[256]; - snprintf(szNotice, sizeof(szNotice), LC_TEXT("군주의 사자후 영향으로 이지역 %s 유저는 3분간 10 %% 의 공격력이 증가됩니다"), EMPIRE_NAME(ch->GetEmpire())); - - SendNoticeMap(szNotice, ch->GetMapIndex(), false); - - return 1; - } - // 군주의 금강권 퀘스트 함수 - int monarch_defenseup(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (!ch) - return 0; - - - //군주 체크 - - if (false==ch->IsMonarch()) - { - if (!ch->IsGM()) - { - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 자격을 가지고 있지 않습니다")); - sys_err("No Monarch pid %d ", ch->GetPlayerID()); - return 0; - } - } - - int money_need = 5000000; // 500만 - if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, money_need); - return 0; - } - - if (!CMonarch::instance().CheckDefenseUpCT(ch->GetEmpire())) - { - int next_sec = CMonarch::instance().GetDefenseUpCT(ch->GetEmpire()) / passes_per_sec; - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("쿨타임 적용중 %d 후 사용가능"), next_sec); - return 0; - } - - //군주의 금강권 적용 - CMonarch::instance().DefenseUp(ch->GetEmpire(), true); - - //군주의 금강권 적용 시간 - int g_nMonarchDefenseUpCT = 60 * 3; - - monarch_defenseup_event_info* info = AllocEventInfo(); - - info->EmpireIndex = ch->GetEmpire(); - - event_create(quest::monarch_defenseup_event, info, PASSES_PER_SEC(g_nMonarchDefenseUpCT)); - - CMonarch::instance().SendtoDBDecMoney(5000000, ch->GetEmpire(), ch); - - char szNotice[256]; - snprintf(szNotice, sizeof(szNotice), LC_TEXT("군주의 금강권 영향으로 이지역 %s 유저는 3분간 10 %% 의 방어력이 증가됩니다"), EMPIRE_NAME(ch->GetEmpire())); - - SendNoticeMap(szNotice, ch->GetMapIndex(), false); - - return 1; - } - - int is_monarch(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - if (!ch) - return 0; - lua_pushnumber(L, ch->IsMonarch()); - return 1; - } - - int spawn_mob(lua_State * L) - { - if (!lua_isnumber(L, 1)) - { - sys_err("invalid argument"); - return 0; - } - - DWORD mob_vnum = (DWORD)lua_tonumber(L, 1); - - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (!ch) - return 0; - - const CMob * pkMob = NULL; - - if (!(pkMob = CMobManager::Instance().Get(mob_vnum))) - if (pkMob == NULL) - { - ch->ChatPacket(CHAT_TYPE_INFO, "No such mob by that vnum"); - return 0; - } - - if (false == ch->IsMonarch()) - { - if (!ch->IsGM()) - { - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 자격을 가지고 있지 않습니다")); - sys_err("No Monarch pid %d ", ch->GetPlayerID()); - return 0; - } - } - - DWORD dwQuestIdx = CQuestManager::instance().GetCurrentPC()->GetCurrentQuestIndex(); - - bool ret = false; - LPCHARACTER mob = NULL; - - { - long x = ch->GetX(); - long y = ch->GetY(); -#if 0 - if (11505 == mob_vnum) // 황금두꺼비 - { - //군주 국고 검사 - if (!CMonarch::instance().IsMoneyOk(CASTLE_FROG_PRICE, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, CASTLE_FROG_PRICE); - return 0; - } - - mob = castle_spawn_frog(ch->GetEmpire()); - - if (mob) - { - // 국고감소 - CMonarch::instance().SendtoDBDecMoney(CASTLE_FROG_PRICE, ch->GetEmpire(), ch); - castle_save(); - } - } - else -#endif - { - mob = CHARACTER_MANAGER::instance().SpawnMob(mob_vnum, ch->GetMapIndex(), x, y, 0, pkMob->m_table.bType == CHAR_TYPE_STONE, -1); - } - - if (mob) - { - //if (bAggressive) - // mob->SetAggressive(); - - mob->SetQuestBy(dwQuestIdx); - - if (!ret) - { - ret = true; - lua_pushnumber(L, (DWORD) mob->GetVID()); - } - } - } - - return 1; - } - - int spawn_guard(lua_State * L) - { - // mob_level(0-2), region(0~3) - if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) - { - sys_err("invalid argument"); - return 0; - } - - DWORD group_vnum = (DWORD)lua_tonumber(L,1); - int region_index = (int)lua_tonumber(L, 2); - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - if (!ch) - return 0; - - /*----- - const CMob * pkMob = NULL; - if (!(pkMob = CMobManager::Instance().Get(mob_vnum))) - - if (pkMob == NULL) - { - ch->ChatPacket(CHAT_TYPE_INFO, "No such mob by that vnum"); - return 0; - } - -----*/ - - if (false==ch->IsMonarch()) - { - if (!ch->IsGM()) - { - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 자격을 가지고 있지 않습니다")); - sys_err("No Monarch pid %d ", ch->GetPlayerID()); - return 0; - } - } - - if (false==castle_is_my_castle(ch->GetEmpire(), ch->GetMapIndex())) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("성에서만 사용할 수 있는 기능입니다.")); - return 0; - } - - //DWORD dwQuestIdx = CQuestManager::instance().GetCurrentPC()->GetCurrentQuestIndex(); - - LPCHARACTER guard_leader = NULL; - { - int money_need = castle_cost_of_hiring_guard(group_vnum); - - //군주 국고 검사 - if (!CMonarch::instance().IsMoneyOk(money_need, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, money_need); - return 0; - } - guard_leader = castle_spawn_guard(ch->GetEmpire(), group_vnum, region_index); - - if (guard_leader) - { - // 국고감소 - CMonarch::instance().SendtoDBDecMoney(money_need, ch->GetEmpire(), ch); - castle_save(); - } - } - - return 1; - } - - int frog_to_empire_money(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (NULL==ch) - return false; - - if (!ch->IsMonarch()) - { - if (!ch->IsGM()) - { - ch->ChatPacket(CHAT_TYPE_INFO ,LC_TEXT("군주의 자격을 가지고 있지 않습니다")); - sys_err("No Monarch pid %d ", ch->GetPlayerID()); - return 0; - } - } - - if (castle_frog_to_empire_money(ch)) - { - int empire_money = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("TEST : 황금두꺼비가 국고로 환원되었습니다.")); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("TEST : 현재 국고 : %d"), empire_money); - castle_save(); - return 1; - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("TEST : 황금두꺼비를 국고로 환원할 수 없습니다.")); - return 0; - } - } - - int monarch_warp(lua_State * L) - { - if (!lua_isstring(L, 1)) - { - sys_err("invalid argument"); - return 0; - } - - std::string name = lua_tostring(L, 1); - - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - if (!ch) - return 0; - - - - if (!CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire())) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다")); - return 0; - } - - //군주 쿨타임 검사 - if (!ch->IsMCOK(CHARACTER::MI_WARP)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_WARP)); - return 0; - } - - - //군주 몹 소환 비용 - const int WarpPrice = 10000; - - //군주 국고 검사 - if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, WarpPrice); - return 0; - } - - int x, y; - - LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(name.c_str()); - - if (!tch) - { - CCI * pkCCI = P2P_MANAGER::instance().Find(name.c_str()); - - if (pkCCI) - { - if (pkCCI->bEmpire != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("타제국 유저에게는 이동할수 없습니다")); - return 0; - } - if (pkCCI->bChannel != g_bChannel) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("해당 유저는 %d 채널에 있습니다. (현재 채널 %d)"), pkCCI->bChannel, g_bChannel); - return 0; - } - - if (!IsMonarchWarpZone(pkCCI->lMapIndex)) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return 0; - } - - PIXEL_POSITION pos; - - if (!SECTREE_MANAGER::instance().GetCenterPositionOfMap(pkCCI->lMapIndex, pos)) - ch->ChatPacket(CHAT_TYPE_INFO, "Cannot find map (index %d)", pkCCI->lMapIndex); - else - { - //ch->ChatPacket(CHAT_TYPE_INFO, "You warp to (%d, %d)", pos.x, pos.y); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 에게로 이동합니다"), name.c_str()); - ch->WarpSet(pos.x, pos.y); - - //군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - - //쿨타임 초기화 - ch->SetMC(CHARACTER::MI_WARP); - } - - } - else if (NULL == CHARACTER_MANAGER::instance().FindPC(name.c_str())) - { - ch->ChatPacket(CHAT_TYPE_INFO, "There is no one by that name"); - } - - return 0; - } - else - { - if (tch->GetEmpire() != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("타제국 유저에게는 이동할수 없습니다")); - return 0; - } - - if (!IsMonarchWarpZone(tch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return 0; - } - - x = tch->GetX(); - y = tch->GetY(); - } - - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 에게로 이동합니다"), name.c_str()); - ch->WarpSet(x,y); - ch->Stop(); - - //군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - - //쿨타임 초기화 - ch->SetMC(CHARACTER::MI_WARP); - - return 0; - } - - int empire_info(lua_State * L) - { - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (NULL == ch) - return false; - - TMonarchInfo * p = CMonarch::instance().GetMonarch(); - - if (CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire())) - { - ch->ChatPacket(CHAT_TYPE_INFO,LC_TEXT("나의 군주 정보")); - - for (int n = 1; n < 4; ++n) - { - if (n == ch->GetEmpire()) - ch->ChatPacket(CHAT_TYPE_INFO,LC_TEXT("[%s군주] : %s 보유금액 %lld "), EMPIRE_NAME(n), p->name[n], p->money[n]); - else - ch->ChatPacket(CHAT_TYPE_INFO,LC_TEXT("[%s군주] : %s "), EMPIRE_NAME(n), p->name[n]); - } - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO,LC_TEXT("군주 정보")); - - for (int n = 1; n < 4; ++n) - ch->ChatPacket(CHAT_TYPE_INFO,LC_TEXT("[%s군주] : %s "), EMPIRE_NAME(n), p->name[n]); - } - - return 0; - } - - int monarch_transfer(lua_State * L) - { - if (!lua_isstring(L, 1)) - { - sys_err("invalid argument"); - return 0; - } - - std::string name = lua_tostring(L, 1); - - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (!ch) - return 0; - - if (!CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire())) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다")); - return 0; - } - - // 군주 쿨타임 검사 - if (!ch->IsMCOK(CHARACTER::MI_TRANSFER)) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_TRANSFER)); - return 0; - } - - // 군주 워프 비용 - const int WarpPrice = 10000; - - // 군주 국고 검사 - if (!CMonarch::instance().IsMoneyOk(WarpPrice, ch->GetEmpire())) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, WarpPrice); - return 0; - } - - LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(name.c_str()); - - if (!tch) - { - CCI * pkCCI = P2P_MANAGER::instance().Find(name.c_str()); - - if (pkCCI) - { - if (pkCCI->bEmpire != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다.")); - return 0; - } - - if (pkCCI->bChannel != g_bChannel) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님은 %d 채널에 접속 중 입니다. (현재 채널: %d)"), name.c_str(), pkCCI->bChannel, g_bChannel); - return 0; - } - - if (!IsMonarchWarpZone(pkCCI->lMapIndex)) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return 0; - } - if (!IsMonarchWarpZone(ch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다.")); - return 0; - } - - TPacketGGTransfer pgg; - - pgg.bHeader = HEADER_GG_TRANSFER; - strlcpy(pgg.szName, name.c_str(), sizeof(pgg.szName)); - pgg.lX = ch->GetX(); - pgg.lY = ch->GetY(); - - P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGTransfer)); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님을 소환하였습니다."), name.c_str()); - - // 군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - - // 쿨타임 초기화 - ch->SetMC(CHARACTER::MI_TRANSFER); - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("입력하신 이름을 가진 사용자가 없습니다.")); - } - - return 0; - } - - if (ch == tch) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("자신을 소환할 수 없습니다.")); - return 0; - } - - if (tch->GetEmpire() != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다.")); - return 0; - } - - if (!IsMonarchWarpZone(tch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return 0; - } - if (!IsMonarchWarpZone(ch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다.")); - return 0; - } - tch->WarpSet(ch->GetX(), ch->GetY(), ch->GetMapIndex()); - - // 군주 돈 삭감 - CMonarch::instance().SendtoDBDecMoney(WarpPrice, ch->GetEmpire(), ch); - // 쿨타임 초기화 - ch->SetMC(CHARACTER::MI_TRANSFER); - return 0; - } - - int monarch_notice(lua_State * L) - { - if (!lua_isstring(L, 1)) - return 0; - - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (ch == NULL) - return 0; - - if (ch->IsMonarch() == false) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다")); - return 0; - } - - std::string strNotice = lua_tostring(L, 1); - - if (strNotice.length() > 0) - SendMonarchNotice(ch->GetEmpire(), strNotice.c_str()); - - return 0; - } - - int monarch_mob(lua_State * L) - { - if (!lua_isstring(L, 1)) - return 0; - - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - - if (ch == NULL) - return 0; - - char vnum[256]; - strlcpy(vnum, lua_tostring(L, 1), sizeof(vnum)); - do_monarch_mob(ch, vnum, 0, 0); - return 0; - } - - EVENTFUNC(monarch_transfer2_event) - { - monarch_transfer2_event_info* info = dynamic_cast(event->info); - - if ( info == NULL ) - { - sys_err( "monarch_transfer2_event> Null pointer" ); - return 0; - } - - LPCHARACTER pTargetChar = CHARACTER_MANAGER::instance().FindByPID(info->dwTargetPID); - - if (pTargetChar != NULL) - { - unsigned int qIndex = quest::CQuestManager::instance().GetQuestIndexByName("monarch_transfer"); - - if (qIndex != 0) - { - pTargetChar->SetQuestFlag("monarch_transfer.x", info->x); - pTargetChar->SetQuestFlag("monarch_transfer.y", info->y); - quest::CQuestManager::instance().Letter(pTargetChar->GetPlayerID(), qIndex, 0); - } - } - - return 0; - } - - int monarch_transfer2(lua_State* L) - { - if (lua_isstring(L, 1) == false) return 0; - - LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr(); - if (ch == NULL) return false; - - if (CMonarch::instance().IsMonarch(ch->GetPlayerID(), ch->GetEmpire()) == false) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주만이 사용 가능한 기능입니다")); - return 0; - } - - if (ch->IsMCOK(CHARACTER::MI_TRANSFER) == false) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d 초간 쿨타임이 적용중입니다."), ch->GetMCLTime(CHARACTER::MI_TRANSFER)); - return 0; - } - - const int ciTransferCost = 10000; - - if (CMonarch::instance().IsMoneyOk(ciTransferCost, ch->GetEmpire()) == false) - { - int NationMoney = CMonarch::instance().GetMoney(ch->GetEmpire()); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("국고에 돈이 부족합니다. 현재 : %u 필요금액 : %u"), NationMoney, ciTransferCost); - return 0; - } - - std::string strTargetName = lua_tostring(L, 1); - - LPCHARACTER pTargetChar = CHARACTER_MANAGER::instance().FindPC(strTargetName.c_str()); - - if (pTargetChar == NULL) - { - CCI* pCCI = P2P_MANAGER::instance().Find(strTargetName.c_str()); - - if (pCCI != NULL) - { - if (pCCI->bEmpire != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다.")); - return 0; - } - - if (pCCI->bChannel != g_bChannel) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님은 %d 채널에 접속중입니다. (현재 채널: %d)"), - strTargetName.c_str(), pCCI->bChannel, g_bChannel); - return 0; - } - - if (!IsMonarchWarpZone(pCCI->lMapIndex)) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return 0; - } - if (!IsMonarchWarpZone(ch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다.")); - return 0; - } - - TPacketMonarchGGTransfer packet; - packet.bHeader = HEADER_GG_MONARCH_TRANSFER; - packet.dwTargetPID = pCCI->dwPID; - packet.x = ch->GetX(); - packet.y = ch->GetY(); - - P2P_MANAGER::instance().Send(&packet, sizeof(TPacketMonarchGGTransfer)); - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소환 요청을 보냈습니다")); - - CMonarch::instance().SendtoDBDecMoney(ciTransferCost, ch->GetEmpire(), ch); - ch->SetMC(CHARACTER::MI_TRANSFER); - } - else - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("입력하신 이름을 가진 사용자가 없습니다.")); - return 0; - } - } - else - { - if (pTargetChar == ch) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("자신을 소환할 수 없습니다.")); - return 0; - } - - if (pTargetChar->GetEmpire() != ch->GetEmpire()) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 제국 유저는 소환할 수 없습니다.")); - return 0; - } - - if (DISTANCE_APPROX(pTargetChar->GetX() - ch->GetX(), pTargetChar->GetY() - ch->GetY()) <= 5000) - { - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님은 근처에 있습니다"), pTargetChar->GetName()); - return 0; - } - - if (!IsMonarchWarpZone(pTargetChar->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 이동할 수 없습니다.")); - return 0; - } - if (!IsMonarchWarpZone(ch->GetMapIndex())) - { - ch->ChatPacket (CHAT_TYPE_INFO, LC_TEXT("해당 지역으로 소환할 수 없습니다.")); - return 0; - } - - monarch_transfer2_event_info* info = AllocEventInfo(); - - info->bHeader = HEADER_GG_MONARCH_TRANSFER; - info->dwTargetPID = pTargetChar->GetPlayerID(); - info->x = ch->GetX(); - info->y = ch->GetY(); - - event_create(monarch_transfer2_event, info, 1); - - ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소환 요청을 보냈습니다")); - - CMonarch::instance().SendtoDBDecMoney(ciTransferCost, ch->GetEmpire(), ch); - ch->SetMC(CHARACTER::MI_TRANSFER); - return 0; - } - - return 0; - } - - void RegisterMonarchFunctionTable() - { - luaL_reg Monarch_functions[] = - { - { "takemonarchmoney", takemonarchmoney }, - { "isguildmaster", is_guild_master }, - { "ismonarch", is_monarch }, - { "monarchbless", monarch_bless }, - { "monarchpowerup", monarch_powerup }, - { "monarchdefenseup", monarch_defenseup }, - { "spawnmob", spawn_mob }, - { "spawnguard", spawn_guard }, -// { "frog_to_empire_money", frog_to_empire_money }, - { "warp", monarch_warp }, - { "transfer", monarch_transfer }, - { "transfer2", monarch_transfer2 }, - { "info", empire_info }, - { "notice", monarch_notice }, - { "monarch_mob", monarch_mob }, - - { NULL, NULL } - }; - - CQuestManager::instance().AddLuaFunctionTable("oh", Monarch_functions); - } - -} - diff --git a/src/game/questlua_party.cpp b/src/game/questlua_party.cpp index 60e0a6b..187ada8 100644 --- a/src/game/questlua_party.cpp +++ b/src/game/questlua_party.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "desc.h" @@ -6,7 +6,7 @@ #include "char.h" #include "questlua.h" #include "questmanager.h" -#include "packet.h" +#include "packet_structs.h" #undef sys_err #define sys_err(fmt, ...) quest::CQuestManager::instance().QuestError(std::source_location::current(), fmt __VA_OPT__(, __VA_ARGS__)) @@ -53,11 +53,11 @@ namespace quest data += str; data += "]"; - pack.header = HEADER_GC_SCRIPT; + pack.header = GC::SCRIPT; pack.skin = CQuestManager::QUEST_SKIN_CINEMATIC; //pack.skin = CQuestManager::QUEST_SKIN_NOWINDOW; pack.src_size = data.size(); - pack.size = pack.src_size + sizeof(struct packet_script); + pack.length = pack.src_size + sizeof(struct packet_script); } void operator()(LPCHARACTER ch) @@ -103,10 +103,10 @@ namespace quest { len = strlen(str); - packet_script.header = HEADER_GC_SCRIPT; + packet_script.header = GC::SCRIPT; packet_script.skin = CQuestManager::QUEST_SKIN_CINEMATIC; packet_script.src_size = len; - packet_script.size = packet_script.src_size + sizeof(struct packet_script); + packet_script.length = packet_script.src_size + sizeof(struct packet_script); } void operator()(LPCHARACTER ch) diff --git a/src/game/questlua_pc.cpp b/src/game/questlua_pc.cpp index 4af12e8..72940ea 100644 --- a/src/game/questlua_pc.cpp +++ b/src/game/questlua_pc.cpp @@ -1,4 +1,4 @@ - + #include "stdafx.h" #include "config.h" @@ -1980,7 +1980,7 @@ teleport_area: int pc_give_polymorph_book(lua_State* L) { - if ( lua_isnumber(L, 1) != true && lua_isnumber(L, 2) != true && lua_isnumber(L, 3) != true && lua_isnumber(L, 4) != true ) + if (!lua_isnumber(L, 1) && !lua_isnumber(L, 2) && !lua_isnumber(L, 3) && !lua_isnumber(L, 4)) { sys_err("Wrong Quest Function Arguments: pc_give_polymorph_book"); return 0; @@ -2100,7 +2100,7 @@ teleport_area: return 1; } - if ( lua_isstring(L, 1) != true ) + if (!lua_isstring(L, 1)) { lua_pushnumber(L, 1); return 1; @@ -2134,7 +2134,7 @@ teleport_area: } DWORD pid = ch->GetPlayerID(); - // db_clientdesc->DBPacketHeader(HEADER_GD_FLUSH_CACHE, 0, sizeof(DWORD)); + // db_clientdesc->DBPacketHeader(GD::FLUSH_CACHE, 0, sizeof(DWORD)); // db_clientdesc->Packet(&pid, sizeof(DWORD)); ch->Save(); // Fix @@ -2169,7 +2169,7 @@ teleport_area: int pc_reset_status( lua_State* L ) { - if ( lua_isnumber(L, 1) == true ) + if (lua_isnumber(L, 1)) { int idx = (int)lua_tonumber(L, 1); @@ -2344,7 +2344,7 @@ teleport_area: int pc_is_near_vid( lua_State* L ) { - if ( lua_isnumber(L, 1) != true || lua_isnumber(L, 2) != true ) + if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { lua_pushboolean(L, false); } @@ -2699,7 +2699,7 @@ teleport_area: if ("mileage" == strChargeType) packet.eChargeType = ERequestCharge_Mileage; - db_clientdesc->DBPacketHeader(HEADER_GD_REQUEST_CHARGE_CASH, 0, sizeof(TRequestChargeCash)); + db_clientdesc->DBPacketHeader(GD::REQUEST_CHARGE_CASH, 0, sizeof(TRequestChargeCash)); db_clientdesc->Packet(&packet, sizeof(packet)); lua_pushboolean(L, 1); diff --git a/src/game/questmanager.cpp b/src/game/questmanager.cpp index 45e2a83..cfcde84 100644 --- a/src/game/questmanager.cpp +++ b/src/game/questmanager.cpp @@ -1,8 +1,8 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "constants.h" #include "buffer_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "desc_client.h" #include "desc_manager.h" #include "char.h" @@ -986,10 +986,10 @@ namespace quest //send -_-! struct ::packet_script packet_script; - packet_script.header = HEADER_GC_SCRIPT; + packet_script.header = GC::SCRIPT; packet_script.skin = m_iCurrentSkin; packet_script.src_size = m_strScript.size(); - packet_script.size = packet_script.src_size + sizeof(struct packet_script); + packet_script.length = packet_script.src_size + sizeof(struct packet_script); TEMP_BUFFER buf; buf.write(&packet_script, sizeof(struct packet_script)); @@ -1179,7 +1179,7 @@ namespace quest TPacketSetEventFlag p; strlcpy(p.szFlagName, name.c_str(), sizeof(p.szFlagName)); p.lValue = value; - db_clientdesc->DBPacket(HEADER_GD_SET_EVENT_FLAG, 0, &p, sizeof(TPacketSetEventFlag)); + db_clientdesc->DBPacket(GD::SET_EVENT_FLAG, 0, &p, sizeof(TPacketSetEventFlag)); } void CQuestManager::SetEventFlag(const string& name, int value) diff --git a/src/game/questnpc.cpp b/src/game/questnpc.cpp index ae31ad2..67c1f95 100644 --- a/src/game/questnpc.cpp +++ b/src/game/questnpc.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include #include "questmanager.h" diff --git a/src/game/questpc.cpp b/src/game/questpc.cpp index 6e3cc0a..19a8383 100644 --- a/src/game/questpc.cpp +++ b/src/game/questpc.cpp @@ -1,7 +1,7 @@ -#include "stdafx.h" +#include "stdafx.h" #include "constants.h" #include "questmanager.h" -#include "packet.h" +#include "packet_structs.h" #include "buffer_manager.h" #include "char.h" #include "desc_client.h" @@ -236,8 +236,8 @@ namespace quest packet_quest_info qi; - qi.header = HEADER_GC_QUEST_INFO; - qi.size = sizeof(struct packet_quest_info); + qi.header = GC::QUEST_INFO; + qi.length = sizeof(struct packet_quest_info); qi.index = m_RunningQuestState->iIndex; qi.flag = m_iSendToClient; @@ -248,7 +248,7 @@ namespace quest { BYTE temp = m_RunningQuestState->bStart?1:0; buf.write(&temp,1); - qi.size+=1; + qi.length+=1; sys_log(1, "QUEST BeginFlag %d", (int)temp); } @@ -256,7 +256,7 @@ namespace quest { m_RunningQuestState->_title.reserve(30+1); buf.write(m_RunningQuestState->_title.c_str(), 30+1); - qi.size+=30+1; + qi.length+=30+1; sys_log(1, "QUEST Title %s", m_RunningQuestState->_title.c_str()); } @@ -264,14 +264,14 @@ namespace quest { m_RunningQuestState->_clock_name.reserve(16+1); buf.write(m_RunningQuestState->_clock_name.c_str(), 16+1); - qi.size+=16+1; + qi.length+=16+1; sys_log(1, "QUEST Clock Name %s", m_RunningQuestState->_clock_name.c_str()); } if (m_iSendToClient & QUEST_SEND_CLOCK_VALUE) { buf.write(&m_RunningQuestState->_clock_value, sizeof(int)); - qi.size+=4; + qi.length+=4; sys_log(1, "QUEST Clock Value %d", m_RunningQuestState->_clock_value); } @@ -279,14 +279,14 @@ namespace quest { m_RunningQuestState->_counter_name.reserve(16+1); buf.write(m_RunningQuestState->_counter_name.c_str(), 16+1); - qi.size+=16+1; + qi.length+=16+1; sys_log(1, "QUEST Counter Name %s", m_RunningQuestState->_counter_name.c_str()); } if (m_iSendToClient & QUEST_SEND_COUNTER_VALUE) { buf.write(&m_RunningQuestState->_counter_value, sizeof(int)); - qi.size+=4; + qi.length+=4; sys_log(1, "QUEST Counter Value %d", m_RunningQuestState->_counter_value); } @@ -294,7 +294,7 @@ namespace quest { m_RunningQuestState->_icon_file.reserve(24+1); buf.write(m_RunningQuestState->_icon_file.c_str(), 24+1); - qi.size+=24+1; + qi.length+=24+1; sys_log(1, "QUEST Icon File %s", m_RunningQuestState->_icon_file.c_str()); } @@ -579,7 +579,7 @@ namespace quest if (i > 0) { sys_log(1, "QuestPC::Save %d", i); - db_clientdesc->DBPacketHeader(HEADER_GD_QUEST_SAVE, 0, sizeof(TQuestTable) * i); + db_clientdesc->DBPacketHeader(GD::QUEST_SAVE, 0, sizeof(TQuestTable) * i); db_clientdesc->Packet(&s_table[0], sizeof(TQuestTable) * i); } diff --git a/src/game/safebox.cpp b/src/game/safebox.cpp index e71c589..8ee3962 100644 --- a/src/game/safebox.cpp +++ b/src/game/safebox.cpp @@ -1,8 +1,8 @@ -#include "stdafx.h" +#include "stdafx.h" #include "libgame/grid.h" #include "constants.h" #include "safebox.h" -#include "packet.h" +#include "packet_structs.h" #include "char.h" #include "desc_client.h" #include "item.h" @@ -70,7 +70,8 @@ bool CSafebox::Add(DWORD dwPos, LPITEM pkItem) TPacketGCItemSet pack; - pack.header = m_bWindowMode == SAFEBOX ? HEADER_GC_SAFEBOX_SET : HEADER_GC_MALL_SET; + pack.header = m_bWindowMode == SAFEBOX ? GC::SAFEBOX_SET : GC::MALL_SET; + pack.length = sizeof(pack); pack.pos = TItemPos(m_bWindowMode, dwPos); pack.vnum = pkItem->GetVnum(); pack.count = pkItem->GetCount(); @@ -110,7 +111,8 @@ LPITEM CSafebox::Remove(DWORD dwPos) TPacketGCItemDel pack; - pack.header = m_bWindowMode == SAFEBOX ? HEADER_GC_SAFEBOX_DEL : HEADER_GC_MALL_DEL; + pack.header = m_bWindowMode == SAFEBOX ? GC::SAFEBOX_DEL : GC::MALL_DEL; + pack.length = sizeof(pack); pack.pos = TItemPos(m_bWindowMode, dwPos); m_pkChrOwner->GetDesc()->Packet(&pack, sizeof(pack)); @@ -127,7 +129,7 @@ void CSafebox::Save() t.dwID = m_pkChrOwner->GetDesc()->GetAccountTable().id; t.dwGold = m_lGold; - db_clientdesc->DBPacket(HEADER_GD_SAFEBOX_SAVE, 0, &t, sizeof(TSafeboxTable)); + db_clientdesc->DBPacket(GD::SAFEBOX_SAVE, 0, &t, sizeof(TSafeboxTable)); sys_log(1, "SAFEBOX: SAVE %s", m_pkChrOwner->GetName()); } diff --git a/src/game/sectree.cpp b/src/game/sectree.cpp index 21133fa..9be996f 100644 --- a/src/game/sectree.cpp +++ b/src/game/sectree.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "libgame/attribute.h" #include "sectree_manager.h" #include "char.h" @@ -6,7 +6,7 @@ #include "item.h" #include "item_manager.h" #include "desc_manager.h" -#include "packet.h" +#include "packet_structs.h" SECTREE::SECTREE() { diff --git a/src/game/sectree_manager.cpp b/src/game/sectree_manager.cpp index 861b83b..dfaf493 100644 --- a/src/game/sectree_manager.cpp +++ b/src/game/sectree_manager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "libgame/targa.h" #include "libgame/attribute.h" @@ -14,7 +14,7 @@ #include "item.h" #include "item_manager.h" #include "buffer_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "start_position.h" WORD SECTREE_MANAGER::current_sectree_version = MAKEWORD(0, 3); @@ -732,7 +732,7 @@ int SECTREE_MANAGER::GetMapIndex(long x, long y) int SECTREE_MANAGER::Build(const char * c_pszListFileName, const char* c_pszMapBasePath) { - if (true == test_server) + if (test_server) { sys_log ( 0, "[BUILD] Build %s %s ", c_pszListFileName, c_pszMapBasePath ); } @@ -777,7 +777,7 @@ int SECTREE_MANAGER::Build(const char * c_pszListFileName, const char* c_pszMapB return 0; } - if (true == test_server) + if (test_server) sys_log ( 0,"[BUILD] Build %s %s %d ",c_pszMapBasePath, szMapName, iIndex ); // 먼저 이 서버에서 이 맵의 몬스터를 스폰해야 하는가 확인 한다. @@ -1136,7 +1136,8 @@ void SECTREE_MANAGER::SendNPCPosition(LPCHARACTER ch) TEMP_BUFFER buf; TPacketGCNPCPosition p; - p.header = HEADER_GC_NPC_POSITION; + p.header = GC::NPC_POSITION; + p.length = sizeof(p); p.count = m_mapNPCPosition[lMapIndex].size(); TNPCPosition np; @@ -1152,7 +1153,7 @@ void SECTREE_MANAGER::SendNPCPosition(LPCHARACTER ch) buf.write(&np, sizeof(np)); } - p.size = sizeof(p) + buf.size(); + p.length = sizeof(p) + buf.size(); if (buf.size()) { diff --git a/src/game/sequence.cpp b/src/game/sequence.cpp deleted file mode 100644 index 5614eb1..0000000 --- a/src/game/sequence.cpp +++ /dev/null @@ -1,2055 +0,0 @@ -#include "stdafx.h" -#include "sequence.h" - -const BYTE gc_abSequence[SEQUENCE_MAX_NUM] = -{ - 0xaf,0xca,0x8a,0xcf,0x48,0xa7,0x54,0xc7,0xd7,0xdf,0x1,0x25,0x72,0xf7,0x6f,0x84, - 0xbc,0x37,0x46,0xe3,0x24,0xda,0xa1,0xc8,0xee,0x36,0x7c,0x33,0x2f,0x98,0x76,0x5e, - 0xe2,0x1,0x2e,0xab,0x29,0x3,0xf2,0x1,0xe2,0xf3,0xa5,0x56,0x6b,0x15,0x5a,0xa7, - 0xcc,0x21,0x8b,0x70,0xfb,0xac,0x3a,0x6b,0xe3,0x36,0x9e,0x92,0x4e,0x16,0xf1,0x31, - 0x96,0x9f,0x5c,0x3f,0xa2,0x50,0xbf,0x6,0xc3,0x66,0xdb,0x30,0xfa,0xb5,0xd7,0x47, - 0xd6,0xe3,0xb8,0x53,0x90,0x72,0xbe,0xf3,0xa8,0xdc,0x7,0x76,0x72,0x78,0xa7,0xa, - 0x18,0x84,0xc8,0x3b,0xd4,0x89,0x41,0x18,0xef,0x9c,0x48,0x6a,0x52,0xa0,0xb2,0xa9, - 0x4,0xea,0x7c,0x94,0xdc,0x3b,0x9,0x85,0x97,0x10,0x7b,0xb,0x88,0x23,0x94,0x20, - 0x27,0x5d,0xda,0xfb,0xe6,0x1c,0x15,0x56,0x38,0xdc,0xc1,0xb,0xfc,0xf3,0xb4,0x1, - 0xde,0x31,0x16,0xbb,0xeb,0x9e,0xc0,0x83,0x2e,0x3c,0xe,0x36,0xde,0xa2,0x56,0x86, - 0x80,0x32,0x82,0xe6,0xcd,0x17,0x3e,0x86,0x74,0x7f,0x91,0xf0,0x73,0x46,0xf2,0xd1, - 0xf6,0x88,0xd,0x62,0x27,0x4d,0x65,0x55,0x9,0x74,0xb,0x67,0x96,0x61,0xed,0x17, - 0x13,0xf0,0xfe,0xe1,0x87,0xbc,0xe7,0xfb,0x3c,0x79,0x6d,0xaf,0x3f,0x60,0x1,0x36, - 0x68,0xe,0x18,0xf,0x5b,0x7d,0xe3,0x64,0x71,0xee,0xcb,0x9,0xcf,0x3a,0x9f,0xe3, - 0x2b,0x1e,0x45,0xb2,0xda,0x2d,0x2f,0x96,0xa6,0x9c,0x46,0xe5,0x7c,0xc6,0x9b,0xe4, - 0xd4,0xb3,0x73,0xaf,0xb0,0x57,0x93,0x23,0x46,0xdf,0xab,0x16,0x1a,0x4b,0x79,0x45, - 0x6a,0xbe,0xf7,0xc4,0xeb,0xa6,0x5c,0x12,0x43,0x22,0x77,0xbf,0xe9,0x92,0x24,0x3e, - 0x46,0x97,0xee,0x77,0xee,0x82,0x9a,0xb4,0x62,0xc5,0x4b,0xfb,0x11,0xc4,0x41,0xfa, - 0x84,0xb9,0x40,0xef,0x60,0x9c,0x82,0xa4,0x3e,0xf9,0x64,0xa7,0x8d,0x89,0xe6,0x53, - 0xa0,0x55,0x4a,0x90,0x57,0x64,0x45,0x3a,0x2a,0x90,0x36,0x3c,0xd5,0x78,0xb6,0xd9, - 0x32,0xf6,0x49,0x12,0x13,0xcb,0xb6,0xd1,0x46,0x9b,0x79,0x53,0xa4,0xdf,0x26,0x45, - 0xb4,0x71,0x55,0xd,0xd5,0x9b,0x47,0x80,0xab,0x7d,0x3c,0x81,0x75,0xf2,0xda,0x27, - 0x6a,0x25,0x3a,0x7d,0xf0,0xf0,0xce,0xb6,0xc,0x49,0xa,0xb0,0xa8,0xb0,0x76,0x5e, - 0x22,0xcb,0x6b,0x77,0xe6,0x32,0x77,0x13,0x2f,0xb3,0x94,0xa5,0xa7,0xef,0x4c,0x12, - 0x15,0x86,0xf,0x85,0xf7,0xde,0x3d,0x83,0xa7,0x47,0x35,0x50,0x77,0x2b,0xae,0x99, - 0xf6,0x99,0x91,0xde,0xcb,0x9,0xf1,0x7b,0xbd,0x6,0x21,0xe4,0xf5,0x6d,0xf6,0x8a, - 0x74,0x85,0x11,0xeb,0x64,0x4e,0x6f,0xc,0x15,0xa4,0xdc,0x8d,0x4f,0xb,0xa6,0x47, - 0xa5,0xb7,0xa5,0xf0,0x41,0x17,0x6c,0xfe,0x9c,0xd,0x63,0x93,0x7b,0xd9,0x9d,0x6f, - 0x5f,0xae,0x5b,0x44,0xfc,0xca,0xcf,0x13,0xef,0xac,0x20,0x3f,0xb8,0xc6,0x6,0xdd, - 0xfe,0xab,0xce,0x40,0x42,0x3c,0x3f,0xdf,0x49,0x22,0xf2,0x44,0xfb,0x90,0xb3,0xda, - 0x40,0x8e,0x1f,0x3d,0xd9,0xef,0xcf,0xc9,0x1c,0xef,0x88,0xd4,0x37,0x8f,0xb2,0x36, - 0xba,0x82,0xf5,0xfd,0x3e,0xb4,0xdd,0x7,0xd6,0xd0,0x4c,0xd2,0x61,0x7f,0xad,0xa1, - 0xf,0x4d,0x5f,0xe8,0x3d,0x2f,0x32,0x59,0x9f,0xba,0xae,0x56,0xc9,0x61,0xc,0x85, - 0x63,0x2,0x3,0x21,0xb6,0xe0,0x29,0xd,0xb1,0xf4,0xdf,0x92,0x74,0xd,0xb4,0x3, - 0x5a,0x14,0x6b,0x17,0xc2,0x1d,0xf0,0xe1,0x58,0x9f,0x38,0x22,0x80,0xc3,0xa7,0x64, - 0x45,0xaa,0x85,0xfb,0xb,0x2e,0x88,0x3c,0x23,0x68,0xcf,0x18,0xf5,0x84,0x1b,0xcf, - 0x18,0x7,0xe7,0xda,0x24,0xd8,0xbd,0x7c,0xf7,0xf5,0x1f,0xf7,0x3a,0x46,0x5c,0x7f, - 0x71,0x62,0xfb,0x7c,0x90,0x84,0xb9,0x34,0x6d,0x9,0x4c,0x63,0xd,0xe6,0xb2,0x25, - 0x6d,0x1a,0x0,0x12,0x72,0x3d,0xe,0x6a,0xb3,0x2d,0x63,0xed,0x74,0x3f,0x6d,0xe5, - 0xa1,0x69,0xe1,0xb2,0x6e,0x1b,0xe6,0xdb,0x24,0x33,0xbe,0xb0,0x99,0x71,0xd5,0x8, - 0x8c,0x56,0x1a,0xfe,0x93,0x28,0xe9,0x47,0x56,0xcc,0xb4,0x4a,0xc,0x23,0xaf,0xae, - 0xc,0x91,0xe0,0x7a,0xad,0xc7,0xd5,0x51,0x7a,0x94,0x82,0x14,0x86,0x58,0x9b,0x13, - 0x2e,0xb5,0x91,0x42,0x5e,0xfa,0x9,0x34,0xc7,0xbe,0x7e,0xd4,0xe1,0x2e,0x3,0x6d, - 0x3f,0xe3,0x68,0x6c,0x2b,0x3e,0xbe,0xa5,0xd3,0x41,0x39,0x5a,0x19,0xd5,0xec,0xc7, - 0xb,0xfd,0xa,0x69,0xf9,0x92,0x9d,0xc1,0x51,0x9b,0x16,0xb2,0x49,0x98,0x21,0x9, - 0x7c,0x89,0x75,0xa7,0xc7,0x34,0xcc,0x1b,0xf4,0x7,0xf4,0x8e,0xdc,0xe1,0x56,0xe7, - 0x60,0xdf,0xd1,0x5a,0x72,0xee,0x9b,0x44,0xb,0x32,0xf6,0x54,0xca,0x18,0x5d,0xc7, - 0x21,0x53,0xee,0x69,0x7,0xbc,0x4,0xfc,0x43,0xf9,0xb,0x9f,0x5b,0xe0,0x7,0xbb, - 0x40,0xd8,0x16,0xb2,0x48,0x32,0xf6,0x53,0x64,0x6e,0x27,0xae,0x6,0x5,0x76,0x28, - 0x58,0xe5,0x11,0x5f,0x22,0x15,0xdb,0x65,0x8e,0xe6,0x5,0xea,0xc7,0x8b,0xa6,0x8, - 0x65,0x3d,0x3b,0xad,0x6f,0xb1,0x80,0x53,0x20,0xa7,0x2,0x27,0xac,0xf8,0xce,0x5, - 0xde,0x5f,0xe4,0x80,0xf3,0xc0,0xe5,0x83,0xa8,0x6a,0x6e,0xef,0xf5,0x94,0x78,0xda, - 0xd1,0x33,0x8,0xc0,0xe4,0x88,0x14,0x85,0xb0,0x96,0x2c,0x5d,0x8f,0xfa,0xe2,0xed, - 0xd9,0xc7,0x6e,0xcd,0x8,0x54,0x51,0x30,0x3e,0x3f,0x21,0xb3,0xd4,0x19,0x8f,0x26, - 0x4c,0x17,0x67,0xb0,0xa0,0x7b,0x36,0xd0,0x12,0x62,0x2e,0x21,0xdc,0x90,0xf,0xb6, - 0x58,0x7d,0x85,0xe0,0x51,0x56,0x11,0x8f,0x96,0x32,0xc3,0xea,0xca,0xd2,0x90,0x96, - 0xe9,0xf7,0x48,0xa,0xf3,0xfd,0xda,0x6,0x61,0x89,0xa7,0xbd,0x1a,0xb6,0xf4,0xf2, - 0x35,0x7a,0xd3,0x6,0x50,0xe4,0x16,0xe6,0x97,0xd9,0x51,0xe1,0xac,0xe2,0x79,0x16, - 0xda,0xc1,0x21,0xce,0xbf,0x7b,0x55,0xa0,0x5,0xfc,0xde,0x9f,0x33,0xd3,0x92,0xe7, - 0xcd,0xe5,0xee,0x1e,0x4a,0x5,0x6,0x61,0x5e,0xd6,0x44,0xb,0xb9,0xbd,0xa0,0x15, - 0xfe,0xc1,0x63,0xbe,0xbd,0xb8,0xdf,0x42,0x35,0xbe,0xe1,0xe8,0x92,0xf3,0xd0,0x60, - 0x59,0x3f,0x7e,0xa4,0x44,0x4,0x6,0x22,0xdb,0x4a,0x2d,0x15,0x87,0xce,0x2a,0x86, - 0x10,0x8e,0xc5,0x4d,0xc6,0xa5,0x90,0x7c,0x64,0xf1,0x65,0x76,0xe6,0xb5,0x56,0x40, - 0xf5,0x54,0xe4,0xb9,0xd8,0x6b,0xdc,0x34,0x35,0x89,0x49,0xbd,0xd7,0xf3,0xc3,0x68, - 0x2,0x89,0xb5,0xc8,0x2f,0x46,0xc4,0x13,0xb8,0xa9,0x9,0x9f,0x60,0x5f,0x5f,0xd5, - 0x34,0x45,0xf,0xd,0x30,0xeb,0x41,0x65,0x76,0x8a,0xa2,0xcd,0xfd,0x67,0x36,0x0, - 0xf0,0x6c,0x49,0xa0,0x32,0xe,0x33,0xea,0x38,0x3d,0x8a,0x18,0x1c,0xea,0xed,0x50, - 0xaf,0xfc,0x5d,0xdf,0x69,0x9e,0xc4,0x5f,0xa9,0xe7,0x2d,0xa7,0x4f,0x64,0xa8,0xbf, - 0x50,0xf1,0xdf,0x82,0x7f,0x14,0x6e,0xb7,0xd0,0xf8,0xcf,0xec,0x63,0x3d,0xbd,0x13, - 0xba,0x1b,0x72,0x24,0x3a,0xb7,0x83,0xe3,0x9f,0x30,0xb,0x6e,0x94,0x33,0xad,0x64, - 0xa4,0x8e,0xe7,0x25,0x22,0x56,0x5c,0x72,0x4f,0xac,0xde,0xb3,0x69,0x9c,0x46,0x24, - 0xb8,0x39,0x48,0x72,0xf0,0x4b,0xd5,0x10,0x7c,0xe0,0x7e,0x90,0x15,0x2c,0xf5,0xb9, - 0x3a,0xdd,0x5e,0xdb,0x34,0x3b,0x4e,0x3,0xe7,0x2e,0x36,0x51,0xca,0x7d,0x76,0x3, - 0x36,0x3e,0xf4,0x27,0x8a,0xca,0x37,0x7,0x2c,0x35,0x17,0xc0,0xe0,0xd,0x7a,0x1c, - 0xea,0x59,0xf7,0x9e,0x94,0xc6,0xa2,0x7c,0x74,0xd8,0x4d,0x3f,0xd5,0x43,0xc2,0xc, - 0x82,0x37,0xb2,0x8c,0x3,0x69,0x13,0x2f,0x9e,0x2a,0xef,0x80,0xb7,0xe9,0x1c,0x22, - 0xc2,0x93,0xc1,0x57,0x5a,0x64,0x53,0xce,0xbc,0xa1,0x8e,0x13,0x64,0xd0,0x9e,0x66, - 0x8,0x52,0x72,0xb,0xbb,0x85,0xb9,0xda,0x30,0x29,0x5b,0xe7,0x93,0xf6,0xa,0x56, - 0x8a,0x4b,0x2e,0x65,0x2f,0x81,0x34,0xec,0xa2,0x42,0x0,0x8,0x13,0x1e,0xed,0x9b, - 0x70,0x61,0x26,0xac,0xe6,0x60,0x87,0x96,0x89,0x62,0xfd,0x9c,0xd8,0x88,0xf3,0x63, - 0xd3,0xa1,0xc8,0x4,0x23,0x7d,0x70,0x46,0x3f,0xef,0xcd,0xd2,0xe,0xbb,0x6e,0x7f, - 0x1d,0x94,0xab,0x84,0xf4,0xb2,0x1b,0xfe,0x94,0x99,0x9b,0x6d,0x22,0xf,0xd0,0xf5, - 0xb0,0x1a,0x79,0x54,0x17,0x69,0x9a,0x56,0x59,0x68,0x29,0x68,0x24,0x97,0x67,0xc1, - 0xac,0x92,0x46,0xa1,0x45,0x61,0xa0,0xd9,0xfa,0xbc,0x47,0x9c,0xcb,0x97,0x13,0xfc, - 0x31,0xc,0x51,0x48,0x76,0x6b,0x1f,0xcf,0xd3,0xc7,0x38,0x77,0xdf,0x1f,0x39,0x8c, - 0xb1,0xfe,0xad,0xf6,0x61,0xce,0x50,0xdb,0x8b,0x17,0xf8,0xd6,0x2f,0xc,0xd3,0x60, - 0x18,0xa4,0x29,0x8e,0x10,0xc7,0xde,0x63,0x8f,0x96,0xdb,0x6f,0xb6,0x94,0x7b,0xe7, - 0x94,0x2a,0x5f,0x75,0xf8,0xaf,0xd0,0x4,0xc7,0xc9,0xda,0x76,0x55,0xaf,0xd6,0xed, - 0x54,0x7f,0x7c,0x65,0x47,0x5b,0xc8,0xd7,0xf2,0x24,0xc6,0x29,0xb9,0xc2,0x11,0xcd, - 0xec,0x70,0x43,0x65,0xa0,0x93,0x69,0xe7,0xdd,0xc3,0x5e,0x33,0x73,0xb4,0x21,0x48, - 0x35,0x1e,0xad,0x7c,0xf8,0xf5,0xd3,0x6b,0x9a,0x9b,0x94,0xd3,0x5e,0x26,0xa1,0xca, - 0x96,0x64,0xaf,0xb6,0xf7,0x98,0x9e,0xd5,0x5c,0x7c,0x89,0x50,0x32,0xaa,0x98,0x67, - 0x48,0x46,0xe3,0x42,0xbb,0xb8,0xad,0x56,0xd3,0x43,0x2a,0xb1,0xe8,0x4b,0xfb,0x7f, - 0xaf,0xab,0xb6,0x28,0xc3,0xd4,0x7d,0x9f,0x52,0x7,0xef,0x4,0x32,0x88,0xea,0x7a, - 0x4e,0xce,0xbc,0xb,0x7,0xea,0xe0,0x5a,0xad,0x8b,0xc,0x96,0x56,0x87,0x95,0x7, - 0xb2,0x4c,0xae,0x76,0xa1,0x2c,0x17,0x73,0xb3,0x7,0x77,0xe5,0x10,0x62,0xdf,0x5e, - 0xb0,0x1d,0xe8,0x38,0x8,0x4a,0x92,0xb5,0xd5,0x1f,0xcb,0x2c,0xa6,0x61,0xb2,0x5a, - 0x2e,0x61,0x50,0xcf,0xe,0x67,0x43,0xc1,0xee,0xba,0x27,0xfe,0x9c,0x7,0x5d,0x4d, - 0x24,0xc6,0x5,0x2c,0x11,0x98,0x61,0xe6,0x37,0x2d,0x92,0xdd,0xf,0xc5,0x38,0x3d, - 0xa6,0x89,0xd,0xb4,0x70,0xcf,0xf5,0x5f,0x8a,0x1d,0xdd,0xa6,0x25,0x3c,0x73,0xc8, - 0x3,0x79,0x75,0x14,0x91,0x56,0x7a,0xc8,0x84,0x8c,0xa6,0x13,0x52,0x5f,0x50,0xf9, - 0x68,0xdc,0x2e,0x58,0xac,0x25,0x38,0xb6,0xc1,0x16,0x5d,0x66,0x52,0x50,0x30,0xd4, - 0xc9,0xa5,0x68,0x5b,0xfb,0x62,0xa3,0x0,0xef,0x4b,0x13,0x42,0x2a,0xe2,0xbb,0x12, - 0xbf,0xea,0x6a,0x6c,0x10,0xa2,0xa2,0xd1,0xb9,0x0,0x39,0x8b,0x51,0xe8,0xe0,0x9a, - 0xe,0x49,0x76,0xa,0xac,0x1a,0x8a,0x1c,0x65,0x1d,0x5e,0xf,0x1,0x1b,0x21,0x40, - 0x85,0xc,0x2d,0x95,0xae,0xcf,0xe6,0xe7,0x50,0x9f,0x74,0xa1,0x88,0x55,0xbb,0x96, - 0x1e,0x32,0x21,0x4a,0x4d,0x2b,0x66,0x32,0x48,0xc5,0x42,0xc8,0x60,0xe2,0x89,0xe5, - 0xee,0xb6,0xfa,0x1e,0x6,0x61,0x6,0x56,0x2,0xf9,0x77,0xa,0xce,0x34,0xa1,0xed, - 0x66,0x42,0x38,0xb3,0x6d,0x9f,0xe6,0xb5,0xe4,0xa8,0xfe,0xc4,0x8b,0x88,0x2a,0xfa, - 0xbe,0x25,0x19,0xc4,0x6,0x9e,0x9b,0x8,0x99,0x13,0x13,0xe7,0x47,0x34,0xd5,0xae, - 0x76,0x8e,0x62,0xe3,0xad,0xc8,0x19,0x92,0x71,0x97,0x57,0xfd,0x9f,0x81,0xf8,0x5e, - 0x26,0x91,0xa3,0x2c,0x30,0x3f,0xb4,0x49,0xd1,0x47,0x32,0x1a,0x7b,0x87,0x48,0x71, - 0x16,0x2a,0x55,0xc3,0xf3,0xed,0xd5,0x65,0x6,0xac,0xe2,0xa5,0xad,0x5b,0x84,0xd3, - 0x6c,0x28,0x80,0x1d,0xe6,0x35,0x66,0xb8,0x7c,0x18,0xd2,0x77,0xa0,0x9a,0xe8,0x36, - 0xc5,0xbd,0x7a,0xb9,0x2b,0x50,0x9e,0x31,0x7d,0x2,0xd7,0x2b,0xdc,0x5c,0x7f,0x4a, - 0x4,0x0,0x67,0xea,0xb4,0x4d,0x23,0xb0,0x66,0x76,0x28,0x7,0x11,0x90,0xbc,0xd6, - 0x4e,0x37,0x10,0x79,0x8,0xaf,0x2b,0x85,0x31,0x3,0xb0,0xe,0xde,0x30,0xd7,0x62, - 0xaf,0xbe,0xcc,0xe3,0xd,0xef,0x14,0x73,0x66,0xbb,0xf9,0xf7,0x4c,0xb6,0xce,0x1a, - 0xee,0xdf,0x94,0x76,0xf,0xbf,0xfb,0xbf,0x42,0xac,0xcd,0xa0,0x5d,0x26,0x3,0x8c, - 0xe4,0xcf,0xf0,0xf1,0xbf,0x5,0xe4,0xa6,0xc1,0x5e,0x9e,0xe,0x16,0xec,0xa8,0x84, - 0xcc,0x3d,0xfa,0x5b,0x7c,0x76,0x1b,0x3e,0x23,0x69,0xde,0x0,0x8f,0xe1,0xd,0xf3, - 0xb1,0xfd,0x66,0xf0,0x82,0x4b,0x97,0x44,0x2a,0xb5,0xd2,0x40,0xa3,0x7b,0x44,0x70, - 0x38,0xbe,0x4c,0x34,0x35,0xe6,0x72,0xd7,0x50,0xd0,0xd8,0x5f,0xb2,0x65,0xd3,0xe3, - 0xe2,0x3a,0xd4,0x65,0x5,0xec,0x2a,0x2f,0xa2,0xfc,0xee,0x46,0xf7,0x33,0x37,0xaf, - 0x71,0x3,0xe3,0xa6,0xe9,0xd5,0x7f,0x3b,0xa6,0xd7,0x1a,0x59,0xbc,0xed,0x3d,0x9f, - 0xa7,0x91,0x5,0xad,0x7e,0x2f,0x5c,0xa1,0xab,0x4c,0x67,0xa3,0xfe,0x9e,0x53,0x71, - 0xa1,0xb6,0x97,0x8c,0x8c,0x17,0x47,0x33,0x6e,0xe0,0xc,0x2b,0x4f,0x49,0xca,0xf6, - 0x5b,0x50,0x24,0x59,0x7f,0x81,0xfa,0xab,0x4d,0xe2,0xce,0xcb,0x81,0xa2,0xbc,0xa3, - 0x59,0x55,0xaf,0xe6,0xeb,0xf6,0x99,0xda,0xd7,0xa6,0x6,0xa6,0x6f,0x51,0x9e,0xca, - 0xa1,0xc2,0xa4,0xa0,0xc3,0x1f,0xcb,0x11,0x2,0x9b,0xdd,0x84,0x3e,0x9a,0xa7,0x17, - 0x6f,0x57,0xfd,0x5c,0x4e,0x18,0x37,0xa5,0xbe,0xbc,0x4d,0x2e,0x8d,0x6b,0x79,0xae, - 0x2e,0x1e,0x50,0xf2,0x3d,0x9b,0x83,0xbf,0x37,0xe0,0x44,0xf4,0xfb,0x6b,0xd,0x6b, - 0xc2,0x8a,0x47,0x90,0xa2,0xfd,0x36,0x61,0xbb,0x3,0x90,0x49,0x6e,0xa,0x78,0x1d, - 0xa7,0xc8,0x8f,0x64,0xe3,0x13,0x24,0x1c,0x74,0xe7,0x90,0x70,0x53,0x9d,0x5b,0x16, - 0x29,0xa3,0xa6,0xcb,0xa1,0x5d,0xad,0xdc,0xdf,0xbd,0xa6,0x4f,0x47,0x1f,0xeb,0xee, - 0x67,0xfa,0x53,0x4b,0xe,0xf7,0xe6,0x2,0xdf,0x78,0x72,0x34,0x95,0x4e,0x4a,0xbe, - 0xf1,0x71,0xb,0x13,0xce,0xb8,0x70,0xae,0xf5,0x96,0x7d,0x3d,0xb5,0xe8,0x2c,0x9c, - 0xe3,0xfe,0x67,0x72,0xf6,0xce,0x74,0xd7,0x47,0x67,0x8b,0x5c,0xb5,0x55,0x1c,0x27, - 0xc6,0xa6,0x3a,0x15,0xde,0x2a,0x44,0xd4,0xc0,0x41,0x12,0xf5,0x2b,0xbd,0x92,0x8e, - 0xbc,0x7a,0x1,0x34,0x49,0xf5,0x8b,0x10,0xdc,0x17,0x6c,0x92,0xeb,0x88,0xb9,0xb3, - 0x2f,0x73,0x48,0x8d,0x9e,0x8c,0x62,0xde,0x4e,0x74,0xd5,0x79,0xb1,0x68,0x8,0x6f, - 0xe2,0x89,0x23,0x2c,0xfe,0x2e,0x3c,0xdb,0xc4,0x29,0xed,0xb0,0xb1,0xa7,0xe3,0x61, - 0x9a,0x2d,0xee,0xb8,0x39,0xd1,0x98,0x87,0x46,0xed,0x80,0xf8,0x56,0x9,0xe7,0xb9, - 0x12,0x8a,0x65,0x11,0xb8,0x22,0xec,0x7d,0x4b,0xda,0xad,0x7c,0x2,0x92,0x5d,0x1c, - 0x3f,0x4d,0xd5,0xf7,0x1f,0xed,0x80,0xe4,0xdb,0x80,0x5d,0xb1,0x89,0xc4,0xea,0x9b, - 0x4f,0x51,0x2c,0x87,0xf2,0x19,0x84,0xbd,0x73,0x33,0x3a,0x75,0x45,0x98,0x12,0x84, - 0x65,0x67,0x7c,0x4,0xd4,0x7c,0xe8,0xb0,0xfd,0xc6,0xe1,0x87,0x8b,0x4d,0xa3,0x5b, - 0x1e,0xcf,0x62,0x11,0x69,0xe7,0xce,0x5c,0x1b,0x88,0x52,0x60,0x21,0x64,0x64,0x86, - 0xcb,0xe0,0xa,0xa0,0x5e,0xf3,0xd0,0xdb,0x3a,0x32,0xe2,0x45,0x7f,0x86,0xa0,0x9d, - 0xd6,0x4,0x2e,0xbf,0x6b,0xfc,0x1c,0x86,0x86,0x6e,0x66,0x27,0xd2,0xca,0x2e,0x1e, - 0x2b,0x38,0x3e,0x89,0xab,0xf,0xe4,0x65,0xc1,0xc8,0xab,0x41,0x4f,0x4c,0x5f,0xa5, - 0xcf,0x8d,0xe4,0x3b,0xb,0x2,0x41,0x11,0x70,0xa7,0x38,0xc3,0xf1,0xe5,0x61,0x1e, - 0x1f,0xa0,0x27,0x4a,0x2f,0xd,0xb0,0xf0,0xd5,0x5c,0xb2,0xa4,0x28,0x12,0xca,0xf8, - 0x1f,0xaf,0xb3,0x2a,0xb1,0xf5,0x3b,0xa2,0x1d,0xf3,0xe5,0x8f,0xd9,0x47,0xad,0x78, - 0x67,0x54,0xc3,0x97,0xe0,0xf3,0x8,0x36,0x50,0x3a,0x5b,0xf7,0xcb,0xa5,0x70,0xeb, - 0x55,0x25,0x16,0x87,0x9a,0xd1,0xa9,0xb7,0xc5,0xf,0x47,0x9f,0xd5,0x74,0x98,0x3e, - 0x49,0xdb,0x55,0xa9,0xcf,0xdc,0x60,0x9f,0x18,0xbb,0x97,0xe3,0x61,0x9,0x4f,0x36, - 0xad,0xe5,0x3d,0x48,0xb7,0xe6,0x7f,0xfc,0xf5,0x47,0x1c,0x4c,0x3b,0xb4,0x8a,0x84, - 0x90,0x5f,0xae,0x60,0x3c,0xf,0x0,0xd3,0xca,0x18,0x38,0xab,0x21,0x87,0xe1,0x4e, - 0x6d,0x20,0x96,0x25,0x86,0x95,0xa1,0xfc,0xdc,0xbe,0x49,0x19,0x73,0x53,0x1d,0x5, - 0xb2,0xcb,0xe4,0x6e,0xda,0x65,0x43,0x25,0x7d,0x7b,0x50,0x1e,0x3,0x33,0x6c,0xf0, - 0xd2,0x82,0x95,0xd8,0x18,0x38,0xd5,0xf5,0xf6,0x1f,0x8e,0x6a,0xf1,0x2b,0xee,0xa4, - 0xf7,0xd4,0x14,0x52,0x3a,0xd6,0xf7,0xb7,0x52,0x48,0xd5,0xd4,0xfa,0xc1,0xc5,0xcd, - 0x44,0x5c,0x27,0x5c,0x94,0xfc,0xd1,0x8b,0x9c,0xdf,0x75,0x8e,0xc,0x65,0xb3,0x83, - 0x3a,0xc7,0x55,0xf3,0x1e,0x4d,0x2b,0x70,0x16,0x80,0x45,0x11,0x42,0x8b,0x5f,0x6, - 0xe7,0x86,0x62,0xfb,0x83,0xb4,0x7,0x9f,0x94,0x7c,0x2f,0x20,0xe1,0xe2,0xa3,0x9b, - 0x2a,0xf9,0xf,0x48,0xc6,0x3a,0x38,0xdc,0x3a,0xfc,0xee,0x7c,0x88,0x4e,0x82,0xef, - 0x54,0x65,0xeb,0xd7,0x99,0x72,0xf7,0x2e,0xef,0x27,0x4f,0x51,0x89,0x72,0x6d,0xb3, - 0xeb,0x7c,0x7b,0xb3,0x37,0xb3,0x90,0x71,0xb0,0xfe,0xee,0xb9,0xcc,0xf0,0xa9,0x21, - 0xd5,0x16,0x79,0x6f,0x88,0x71,0x1e,0xf7,0x18,0xec,0x4a,0xa1,0x5f,0xb7,0xd4,0x4c, - 0xb3,0xcf,0x7f,0xea,0x83,0x8f,0x5d,0xb3,0x8f,0xcb,0xec,0x5c,0x3c,0x97,0xfd,0x13, - 0x2d,0x77,0x82,0xb5,0x68,0xa0,0x2e,0x80,0xd,0x78,0xa1,0x6d,0xaf,0xf5,0x39,0x63, - 0xc5,0xb8,0x4f,0xc8,0xc7,0x2c,0xfb,0x57,0xf7,0xe9,0x34,0x34,0x1,0x32,0xc6,0x2e, - 0x29,0x4a,0x63,0x91,0x6a,0x91,0x91,0x78,0xa,0x33,0x65,0xb9,0xa8,0x1e,0x9d,0x6e, - 0x56,0x6c,0xb6,0x1e,0x98,0xb2,0x76,0x10,0x9c,0x2a,0xc3,0x9d,0xdb,0x8b,0x4b,0x5, - 0x55,0xaf,0x16,0x3f,0x41,0xa7,0x37,0xcb,0x5a,0x9c,0x5,0x3,0x3a,0xa2,0x71,0x90, - 0xf,0xa7,0xaf,0x27,0x5a,0x26,0x37,0x77,0xcf,0xfb,0x94,0xab,0x87,0xe0,0xb0,0x5c, - 0x10,0xc6,0x9b,0x51,0xed,0xd3,0x1d,0x48,0xef,0x23,0x4b,0x2b,0xc5,0x3c,0xbb,0x55, - 0xe3,0x6b,0x7c,0xbd,0x11,0x34,0x35,0xe0,0x30,0x4a,0x8c,0x37,0xaa,0xbc,0x93,0xba, - 0x3,0xae,0xc,0xf0,0x82,0xa9,0x39,0xf2,0xcc,0x84,0x1e,0x12,0x40,0x59,0xe6,0x24, - 0x45,0x64,0x62,0x56,0x18,0x97,0xb7,0x48,0x61,0xc3,0xfe,0xc,0x81,0x12,0xc6,0x84, - 0xc0,0xd3,0x76,0xc3,0x7d,0x2f,0xb6,0xc9,0x34,0x54,0xdb,0x74,0x2d,0xc3,0x19,0x72, - 0xa7,0x7b,0x49,0xbf,0x92,0x80,0x87,0xf4,0x44,0x6,0x1,0x45,0x18,0xc8,0xca,0xd8, - 0x1c,0xc0,0x1c,0x19,0x6f,0x52,0xe2,0xa3,0x26,0x3e,0x98,0x54,0x81,0x31,0x46,0xa8, - 0xac,0x8f,0xe7,0xbe,0x10,0xee,0xb3,0xd4,0xf4,0x35,0x1a,0xd,0x7d,0x64,0x66,0x19, - 0xa4,0x82,0x32,0x15,0xd5,0x94,0x38,0x7b,0x52,0xd0,0xcf,0x54,0x2,0x17,0x7c,0x2e, - 0x26,0x65,0xed,0xb6,0x54,0x21,0x8b,0xc9,0xd5,0xa5,0xd6,0x53,0xb,0xbc,0xeb,0xaf, - 0xbf,0x1e,0x44,0x15,0x32,0x7d,0x90,0x5,0xcd,0x61,0x59,0x50,0xf7,0xd5,0x7e,0x9d, - 0xba,0xeb,0x54,0x8f,0x8d,0xdf,0x59,0x63,0x6,0xaf,0x37,0x11,0xec,0x23,0x40,0xac, - 0xc1,0x85,0x41,0x73,0x82,0xd1,0x78,0x50,0xb2,0x51,0xa0,0x2a,0xa7,0x9f,0xc8,0x62, - 0xb,0x1d,0x71,0x18,0x7d,0x4a,0xfb,0x83,0x7a,0x33,0x14,0x67,0xd5,0x54,0x93,0x97, - 0x59,0xd4,0xc,0xdb,0x26,0x4,0xac,0xd9,0x56,0xcc,0x4,0xfd,0x6c,0xcc,0xdf,0xf7, - 0x6a,0x52,0x10,0xe7,0x1c,0x8b,0xea,0x96,0xbe,0xfe,0x7d,0x95,0x53,0x90,0xac,0x2d, - 0x65,0x38,0x88,0xc,0x3d,0x35,0xe5,0x13,0x3,0x69,0x90,0xee,0x37,0x70,0x66,0x21, - 0x42,0xf6,0x9,0xde,0x82,0xf3,0x75,0xc1,0x72,0x73,0xd6,0xc5,0x4,0x83,0x72,0xe9, - 0x3c,0xfb,0xf5,0xf8,0xb0,0x5b,0xc,0xb3,0xc4,0x1c,0x23,0x7b,0x8c,0x89,0x9c,0x4f, - 0x0,0x25,0x2e,0x83,0x98,0x23,0x45,0xb,0x16,0x1c,0x51,0x9a,0x1f,0xc3,0x84,0x5b, - 0x3f,0xf9,0xd3,0xf0,0x55,0x5f,0x24,0x99,0x7b,0x47,0x16,0x9,0x51,0x32,0xd7,0x51, - 0x58,0x85,0x54,0x70,0x28,0x19,0x7c,0x3f,0x35,0x4d,0xd9,0xd4,0x90,0xdd,0xaf,0xd0, - 0xd7,0x84,0x41,0xac,0xe3,0x65,0x46,0x60,0x2d,0x5c,0xe8,0x7e,0x8f,0x40,0x4f,0x67, - 0xc5,0x24,0xd7,0xed,0x3d,0xd3,0x2d,0xf2,0x21,0x86,0x47,0x32,0x64,0xf6,0x82,0x3c, - 0xfa,0xc3,0x68,0xdf,0x29,0xaf,0xbf,0xd5,0x8b,0x28,0xd3,0x9a,0x68,0xa3,0x81,0xad, - 0xc7,0x5a,0x9b,0x84,0xad,0x49,0x77,0x4f,0x4f,0xbe,0x81,0xb4,0x36,0x4,0x70,0x31, - 0xc7,0xd9,0x90,0x70,0x9,0x50,0x47,0x14,0x78,0x1b,0xaf,0x60,0x3e,0x31,0xe,0x6, - 0xb,0x2a,0x8b,0x39,0xf2,0x82,0x88,0x42,0xc1,0xa,0xf6,0xf7,0x8d,0xe7,0xa8,0x55, - 0xc1,0x3a,0x45,0x4a,0x8a,0xc,0x5e,0x83,0xa7,0xe,0xe3,0xe5,0xbf,0x72,0xec,0x4a, - 0x9c,0xf7,0x83,0xf,0x7a,0x8b,0x51,0x3c,0x95,0xc8,0xb3,0x23,0x30,0x5d,0xf7,0xf1, - 0x97,0xbd,0x3c,0xa1,0xc9,0x1a,0xa4,0x71,0x29,0x9,0xd7,0x68,0x7b,0x44,0x32,0x97, - 0x3c,0x36,0xa6,0x36,0xc1,0x77,0xf2,0xd7,0xbf,0xa6,0x7a,0xef,0x83,0xf2,0x61,0x9a, - 0xb0,0x1d,0xbc,0x7a,0x38,0x61,0x6c,0xe0,0x6a,0xc3,0xc8,0x65,0x8,0xfa,0x7c,0x44, - 0x31,0xa2,0xf9,0x73,0x1b,0xec,0x4b,0x5a,0x14,0x45,0x4b,0x97,0x38,0x2c,0xb2,0xe8, - 0x4a,0x6f,0xe3,0x82,0xd0,0xcf,0xe2,0xbb,0x93,0xab,0xa0,0x1b,0xa6,0x1e,0xde,0x58, - 0xc0,0xd8,0xcb,0x5b,0xc6,0x96,0xb6,0xda,0xdb,0x81,0xf1,0x94,0xad,0x24,0x7d,0xf7, - 0x93,0xe0,0xf9,0xe4,0xb0,0xdc,0xa0,0xc3,0x88,0x41,0xde,0xaf,0xde,0xbd,0x8,0xa0, - 0x97,0x53,0xfb,0xdd,0xe9,0x32,0x38,0x45,0xb3,0x2a,0xd9,0x62,0x4f,0xd7,0xd9,0x62, - 0xb8,0xd4,0x47,0x6a,0xb1,0x67,0xad,0xba,0x29,0x8d,0x6a,0x8,0x4b,0x72,0x28,0xe2, - 0x45,0x25,0xc0,0x2f,0x57,0xf8,0xf3,0xc,0xa3,0x4e,0xed,0x72,0x26,0xc7,0xd4,0xde, - 0x1c,0x9c,0xc8,0x4e,0x4,0x77,0x9,0xac,0x5,0x73,0xb5,0xcf,0x65,0x5d,0x33,0xaa, - 0x82,0x73,0x59,0x5a,0xec,0xcc,0xe5,0x90,0x1b,0xd3,0x82,0xc0,0x1b,0xd6,0x20,0x38, - 0x73,0xe8,0x86,0xf7,0xdf,0xf,0xa4,0x64,0x2,0xd9,0xb4,0xe6,0x38,0xe7,0x91,0x3a, - 0x5b,0x6a,0x14,0x48,0xb6,0xf9,0x58,0xd2,0x4d,0xda,0x93,0xe8,0x32,0xb3,0x21,0xa5, - 0x1d,0x27,0x1d,0x7c,0xb5,0x42,0x61,0xb7,0x1c,0x16,0x9e,0xd3,0xfd,0xaf,0x8e,0x59, - 0x1a,0xa2,0x22,0xd0,0x1d,0x7a,0x23,0x6a,0xd5,0x37,0x53,0x8,0x6a,0xf3,0xad,0x7, - 0x9a,0x4b,0x84,0x50,0x8d,0xe5,0x8,0x29,0xfb,0x26,0x7d,0xf9,0xd5,0xc,0xd2,0x6f, - 0x2e,0xf4,0xc0,0x4b,0xef,0x63,0xb6,0xc5,0x9a,0x89,0xcd,0x6,0xfd,0xfa,0x8c,0x98, - 0xc5,0x11,0x69,0x53,0x76,0xf0,0x7d,0x72,0x18,0xfa,0xeb,0x6d,0x86,0x3f,0xdd,0xb4, - 0xb3,0x1e,0x1,0xa3,0x81,0x37,0xe8,0x1d,0x40,0x36,0xa2,0x3e,0xb1,0xae,0x57,0x77, - 0xc0,0x40,0xcb,0x37,0x31,0xc8,0x2a,0xc8,0x43,0x95,0x37,0xc9,0xd4,0x94,0xfd,0x89, - 0xb2,0x7e,0xac,0x34,0x35,0x96,0xd0,0x76,0xcc,0xf2,0x34,0x7e,0xa2,0xb,0xf6,0xe2, - 0x4b,0x42,0x99,0xfc,0xb,0xc3,0xc5,0xcd,0xd9,0xfc,0x97,0xae,0x91,0x15,0xb7,0x44, - 0x94,0xe4,0xf8,0x49,0x7b,0x49,0xbf,0xc7,0x3d,0x74,0x47,0x5f,0xfe,0xbd,0xc1,0x4b, - 0x0,0x5b,0x48,0x8a,0x9f,0xe,0x58,0x79,0x8b,0x6f,0xa7,0x1d,0x4,0xdf,0xe1,0x18, - 0xc4,0x5a,0x62,0xbf,0xa3,0xa1,0x87,0x60,0x16,0x4e,0x3f,0x16,0xc,0x1,0xe0,0x8b, - 0x5d,0xa8,0x16,0xfc,0xb6,0xed,0xf5,0xc1,0xdc,0x1d,0xdf,0xe1,0xfc,0x41,0xf9,0x41, - 0x9b,0x5c,0x1,0x3f,0xfe,0x89,0x20,0x94,0xd7,0x5f,0x2a,0x64,0x61,0x8a,0xef,0xbe, - 0x33,0x86,0x3b,0x6a,0xf3,0xb0,0x2c,0xd1,0xcd,0x8b,0xb3,0x4b,0xcc,0x2d,0x8c,0xe7, - 0x8a,0x8e,0x28,0x9,0x97,0x48,0x1d,0xee,0x27,0xc7,0x53,0x88,0x52,0xc3,0xc6,0x6, - 0xc9,0x2,0x70,0xbd,0x32,0x1c,0x8f,0x1,0xa8,0xc2,0x4c,0xf4,0xf0,0x58,0xdd,0xfa, - 0x66,0x85,0x83,0xfd,0x4d,0xa0,0x6d,0x74,0xe7,0x40,0xfd,0xba,0x4,0xc4,0xc0,0xcd, - 0x47,0xb0,0xc,0x79,0x4c,0x9b,0xf9,0xf4,0xde,0xc5,0x6a,0xcf,0x1f,0x48,0xca,0x5, - 0xcd,0x4e,0x83,0x1b,0x6e,0xf0,0xf,0x57,0x31,0xd,0x12,0xb5,0x52,0x52,0x83,0x19, - 0x82,0xf,0x12,0xce,0xab,0xd,0x44,0x8a,0x52,0xae,0xd9,0xf0,0xf6,0x24,0xf6,0x44, - 0x72,0x7a,0xde,0x60,0x6b,0xed,0x37,0x1c,0x7b,0xc8,0xd1,0x4d,0x1b,0xd5,0xe5,0x1d, - 0xe4,0xf7,0xec,0x10,0x84,0x31,0x1a,0xd7,0x5f,0xf3,0xc8,0xd5,0x97,0x3f,0x1a,0xa, - 0xb9,0x78,0xea,0x25,0xe5,0x22,0xc1,0x61,0xeb,0x93,0x2e,0x86,0x69,0x14,0xa4,0xce, - 0xd,0x91,0xde,0x11,0x42,0xf9,0xe8,0x21,0x6d,0x32,0xf6,0x6,0x71,0x90,0x8f,0xab, - 0x9,0x7a,0x50,0xee,0x1d,0x12,0xd0,0x9,0xa6,0x7e,0x8f,0x8f,0x93,0xb3,0x5e,0x20, - 0x45,0x3e,0x31,0x7,0xb7,0x9a,0x28,0xa4,0x4c,0x1f,0xaa,0x3d,0x2f,0xba,0xe8,0x38, - 0xb4,0x3a,0xa7,0xd1,0x4c,0xf7,0x5a,0xf2,0xf5,0x6a,0x3,0x89,0x1e,0x61,0x29,0xe3, - 0x1f,0x5b,0xea,0x56,0x75,0x93,0xfb,0xc1,0x32,0x26,0xfe,0x62,0xe0,0xe8,0x1a,0x16, - 0xa2,0x41,0xe7,0xee,0xb8,0xc2,0x62,0xaf,0x2d,0x65,0x39,0xca,0x46,0xe2,0xae,0xe5, - 0xbd,0x1a,0x3c,0x33,0xad,0x38,0x74,0x5f,0x5f,0xf2,0xc1,0xbf,0x5b,0xdc,0xd5,0xfd, - 0x9d,0x3e,0xed,0x57,0x1,0xcf,0x7,0xad,0xb4,0xbf,0x78,0x7a,0xa2,0xa7,0x60,0x60, - 0xc1,0x9d,0x93,0xee,0xd5,0x87,0x4e,0xb4,0x7b,0x90,0xf4,0xd6,0x6d,0xca,0xd5,0x8a, - 0x88,0x43,0xe1,0x9,0x92,0xe8,0xb6,0x47,0x29,0xaf,0xc1,0xcb,0x57,0x23,0x2d,0x19, - 0x40,0x40,0x87,0x95,0x48,0xd5,0x4b,0xc3,0x66,0xbf,0x9a,0x53,0xa,0xef,0xde,0x93, - 0xb2,0x40,0x9c,0x45,0xa9,0xd3,0xc,0xd2,0x83,0x4e,0x9e,0xda,0x71,0x4b,0xf3,0x31, - 0xc,0xfa,0xc6,0x54,0xd0,0x91,0x97,0xb7,0x51,0x32,0x8a,0x5c,0xa2,0x69,0x6f,0x55, - 0x2a,0x8b,0x9b,0xd3,0x5f,0xa7,0xa6,0xe2,0xf5,0xc4,0xbd,0xe6,0x90,0x31,0x18,0x1c, - 0x2c,0x5f,0xef,0x7d,0xf0,0x87,0x35,0xc2,0xb9,0xbf,0x9e,0xdb,0xa9,0xe,0x32,0xd3, - 0x99,0xcd,0xa7,0xf9,0xf4,0xcd,0xdc,0x6b,0x12,0x1b,0xd1,0x22,0x4c,0x6a,0x3e,0xf8, - 0xc9,0x2e,0x76,0x3a,0xb5,0x2b,0xfc,0xef,0xea,0x9b,0xcb,0x14,0x29,0x7d,0xe7,0xc3, - 0xca,0xf,0x3d,0xc0,0x5c,0x99,0xab,0xee,0xb4,0x7d,0x11,0x81,0x67,0x50,0x7a,0xb0, - 0xfd,0x70,0xeb,0x34,0x9b,0x68,0xa3,0x6,0x5,0xee,0x1b,0x2e,0x6d,0x82,0x71,0x38, - 0x92,0x2e,0x78,0x6e,0xc8,0x24,0x5d,0xfc,0x22,0x6f,0xfd,0x89,0x3f,0xf7,0xba,0xbc, - 0xe7,0xa6,0xf0,0x83,0xf,0x94,0x8a,0x93,0x84,0x25,0x42,0x71,0xa7,0x33,0xa9,0xb9, - 0x62,0x23,0x29,0xaa,0x47,0x86,0x27,0xe8,0x75,0xa5,0xf2,0x34,0x9d,0xad,0xf1,0x86, - 0x54,0xe2,0x89,0xe2,0xf7,0x93,0xf6,0xfb,0xb8,0x39,0x6d,0x61,0x6c,0x17,0x9a,0x4e, - 0x3a,0xc3,0xf8,0x2,0xca,0xa0,0xea,0xbf,0x46,0xdd,0xf4,0xe3,0xb,0xe6,0xe9,0xde, - 0x49,0xf3,0xc2,0x41,0x87,0x39,0x3d,0x41,0xf1,0x2a,0x22,0x5e,0x42,0x3c,0x2d,0xfb, - 0x1,0xa5,0xfd,0x4b,0x46,0x69,0x8a,0xc,0xc6,0x7f,0x70,0xd2,0xe5,0x5a,0xb1,0xaf, - 0xcd,0xf3,0x70,0x56,0xac,0x2e,0x17,0x9e,0x58,0xb8,0x7d,0x9a,0xf4,0xaa,0x97,0x75, - 0xcf,0x15,0x40,0x17,0xfd,0xcb,0x23,0xc5,0xca,0x13,0x18,0x31,0xed,0x49,0xe0,0xbb, - 0xbd,0x51,0x12,0x6a,0x7f,0x29,0xa,0xd8,0x61,0x87,0xf2,0x57,0xb1,0xa,0x4c,0x81, - 0x9f,0x8d,0x18,0x9d,0xd8,0xbb,0x63,0xa3,0xce,0xfa,0xd4,0xbc,0x45,0x35,0x79,0x82, - 0x87,0x8b,0xec,0x86,0x35,0xf6,0xde,0x96,0xfd,0xd2,0x6d,0xaf,0x5c,0xba,0x32,0xfb, - 0xc7,0x4a,0x9a,0xa0,0x6,0x7d,0xc3,0xd5,0xf8,0x19,0x92,0x3e,0xcd,0x8b,0xc0,0xd4, - 0x18,0x2d,0x5c,0xcc,0x25,0xba,0x63,0xa2,0x8d,0x51,0x53,0x6a,0x8b,0x5,0x66,0x53, - 0x4f,0x80,0x73,0xd5,0xfe,0xb6,0x2b,0xf7,0x4f,0x3d,0xb5,0x1e,0xc9,0xf5,0xf2,0x61, - 0x23,0xce,0x2e,0xc7,0x8a,0x11,0xea,0x97,0x62,0x3e,0x2,0x6d,0xc2,0xe8,0x40,0x91, - 0x69,0x33,0x67,0xe7,0xea,0x92,0x5f,0xb9,0x50,0x15,0xd7,0x1a,0x8a,0x4b,0x7b,0x2e, - 0x1a,0xa9,0x75,0x24,0x3a,0x60,0xbc,0x1d,0x1e,0x3e,0x8a,0xe0,0x27,0xcb,0x73,0x91, - 0xfe,0x5a,0xf8,0x69,0xed,0x59,0x24,0xbd,0x6e,0x7b,0xd7,0x79,0x46,0xd2,0xa7,0x61, - 0xfb,0x1d,0x5,0x36,0x7e,0x41,0x53,0x1c,0x80,0xde,0xfd,0xa7,0x2a,0xf0,0xb8,0xa8, - 0x4b,0xb2,0x13,0xb8,0xc,0xb6,0x76,0xf9,0x32,0x4e,0x73,0xf8,0x21,0x9a,0x5a,0x1d, - 0x38,0xde,0xd3,0x36,0x21,0x27,0x52,0xa1,0x85,0x50,0xc8,0x2f,0x41,0x2,0xd8,0xd, - 0x34,0xeb,0xc5,0xbf,0x22,0x3d,0x39,0xd3,0xb,0x2d,0xcc,0xac,0xc7,0xa6,0xc9,0x0, - 0x86,0x1d,0xb5,0x27,0xc4,0x9,0xc8,0x4a,0xd8,0x11,0x7a,0x9a,0x92,0xd2,0xa7,0x46, - 0x3e,0x6d,0x6,0x60,0xaa,0x40,0x34,0x36,0xec,0x81,0xe2,0x34,0x28,0x2c,0xb4,0xae, - 0x4a,0x6a,0x55,0xf,0x73,0x1e,0xd8,0x4d,0xaf,0xd2,0xe7,0xc1,0xa5,0xf,0x9,0xe3, - 0x7c,0xf,0x44,0xa7,0xce,0xf8,0xdd,0x3b,0x7a,0xc0,0x70,0xa2,0x6c,0x25,0xd1,0xb6, - 0x8f,0x27,0x45,0x4,0xc5,0x1f,0xd0,0xf4,0xf1,0x38,0xb6,0x18,0x47,0x3f,0xfb,0xc3, - 0x4f,0xc0,0xea,0x9d,0x39,0x48,0xd9,0xb3,0x9,0xc9,0xd5,0xf5,0xee,0x27,0xac,0xfd, - 0xce,0xf2,0x81,0x14,0x91,0x52,0x88,0x3,0xa,0x3f,0x1b,0x51,0x7f,0x97,0x95,0x4e, - 0xd7,0x80,0x6b,0x11,0xc9,0xc4,0x44,0x52,0x8e,0x99,0x48,0xfc,0x41,0x75,0xfb,0x10, - 0xe7,0x7d,0xa3,0x79,0x50,0x2c,0xfb,0x5a,0xea,0x97,0x2c,0xe9,0xae,0xc1,0xb7,0x86, - 0xc1,0x24,0x17,0xb,0x68,0xda,0xdd,0xf7,0x74,0xa5,0x74,0xb5,0x1b,0x70,0x45,0x82, - 0x6e,0xe8,0x7b,0xbe,0x15,0x78,0x19,0x80,0x8f,0xc4,0x6a,0x3e,0x86,0xa2,0xc4,0xc8, - 0xc6,0x5b,0xd3,0xae,0x36,0x31,0x26,0xaa,0xd7,0x9b,0xe0,0x72,0xc,0x26,0x75,0x7a, - 0x10,0xf0,0xb8,0xa4,0xe8,0x52,0x25,0x78,0x17,0x10,0xb6,0x1e,0xb2,0xfa,0xe6,0xf8, - 0x56,0x3a,0x27,0x8c,0x6c,0x4e,0xb7,0xc3,0xe9,0x98,0xb5,0x75,0xbe,0x2b,0x70,0x4e, - 0x1d,0x29,0xf3,0x6,0x7b,0x98,0x7f,0x13,0x28,0x36,0x31,0x5a,0x32,0x97,0xd2,0x8, - 0xd1,0xfa,0x95,0xbd,0xc8,0xcc,0x81,0xb2,0x65,0x38,0x28,0x24,0x63,0x18,0xf2,0x0, - 0x42,0x66,0x7,0x3d,0x7e,0x6,0xcf,0xa7,0xbb,0x1,0x81,0x6d,0x98,0xd4,0x76,0xea, - 0x4f,0x8b,0xa8,0x18,0x58,0x2b,0xca,0xbd,0xe2,0x72,0x61,0xc5,0x8b,0x54,0xc6,0x4d, - 0x3a,0xcd,0x8a,0xb9,0x53,0x5b,0xe0,0xf,0xdb,0xe1,0x7d,0xf4,0xb6,0x73,0xdf,0x6, - 0xfe,0x88,0x1e,0x57,0xb3,0x68,0x94,0x16,0xdb,0xf5,0xdc,0x67,0xca,0xa3,0x34,0x5, - 0xf0,0xbe,0x3e,0x44,0x99,0x1f,0xd2,0xf5,0x2,0x50,0xea,0x38,0xc3,0xca,0x3f,0xc2, - 0xd2,0x5d,0x99,0x87,0xc6,0x2e,0x9d,0x22,0xa4,0xf9,0x9,0x6f,0x9d,0x3d,0xf3,0x8e, - 0x7b,0x33,0x52,0x95,0xd1,0x26,0x8b,0xd3,0x76,0xf5,0x8c,0xba,0xc0,0xcb,0xfc,0x93, - 0xa8,0x97,0x9a,0xee,0x45,0xb8,0x11,0xe9,0xb2,0x99,0xd8,0xd0,0xd6,0xcd,0x5f,0x53, - 0x80,0x32,0x68,0x52,0x58,0xf3,0xa6,0x4e,0xe9,0x33,0x9,0x2a,0x7e,0x86,0x3d,0x27, - 0x9d,0x58,0x96,0xe2,0x90,0x27,0x4d,0xc2,0xc1,0xa5,0x93,0x98,0xf2,0x73,0x6b,0x73, - 0xa5,0xd3,0x46,0xfd,0x47,0x6c,0x4c,0xb0,0x1f,0xd5,0x5a,0x9d,0xdb,0x18,0x44,0x79, - 0x70,0xda,0xdb,0x80,0x82,0x29,0x43,0x44,0xcf,0xd7,0x5c,0xc2,0x4b,0xc8,0xb6,0xf0, - 0x1c,0x7c,0x6e,0xe3,0xe8,0x3a,0x94,0x8,0x8f,0x6f,0x25,0x6b,0x87,0xe8,0xe4,0x77, - 0x44,0x41,0xf7,0xc6,0x6a,0x3b,0xb,0xb9,0x92,0x67,0xfc,0x5d,0xaf,0x33,0xcd,0x4c, - 0xaf,0x3c,0x30,0x18,0x77,0x44,0x9f,0x7,0xb3,0xc4,0xf2,0xba,0x2d,0xd7,0x32,0x71, - 0x19,0xa9,0x38,0x4,0x65,0x43,0x3d,0xf7,0x2b,0xb9,0xd5,0xda,0xec,0xa3,0x27,0x1c, - 0xe0,0xd6,0x34,0xd7,0x1c,0x53,0x5e,0x4f,0x97,0x51,0xb,0xc5,0xa9,0xbc,0x37,0x42, - 0xe6,0xef,0xc5,0x4c,0x33,0x4,0xc3,0xdd,0x3d,0x99,0x39,0xaa,0x3e,0xdf,0xc6,0x9e, - 0xb7,0x7b,0x76,0x53,0xce,0x54,0xa2,0x67,0xa6,0x2d,0x2d,0xcf,0x6a,0xe3,0x12,0x51, - 0xd3,0xd8,0x1d,0x87,0x5c,0x60,0x65,0x99,0x7a,0x1e,0x44,0xb8,0xfe,0x8b,0xd6,0xb6, - 0x7,0xcc,0xa,0x55,0x21,0x2c,0xbc,0x47,0xd9,0x69,0x17,0x44,0xcd,0xa9,0x15,0xa1, - 0x2,0x32,0x29,0xdd,0x92,0xf,0x77,0xd,0x2d,0x3c,0x45,0x2c,0x47,0x9b,0x62,0x4e, - 0x68,0xeb,0x23,0xa,0x98,0xe0,0x51,0x72,0xc9,0xe8,0xb6,0x97,0x12,0xcb,0xb9,0x14, - 0x7d,0x62,0xf1,0x8f,0xf0,0xe8,0x1d,0x9e,0xa4,0x62,0x4a,0xeb,0x7e,0xad,0xb9,0xe6, - 0x19,0xdd,0xf0,0xb1,0xbe,0xc2,0xa3,0x8,0x2b,0x5a,0x20,0x3d,0xa5,0x59,0xd0,0xa2, - 0xbb,0x42,0x33,0xad,0x2b,0x50,0x4c,0xd0,0x32,0x96,0x3c,0xb0,0xc3,0xf6,0x18,0xdd, - 0xd4,0x88,0xf,0x13,0x4b,0xb3,0x1b,0xf5,0x8d,0xba,0xb2,0xb3,0x14,0x83,0x56,0xd0, - 0xc5,0x9,0xfd,0x71,0xd8,0xc9,0xc1,0x8b,0x60,0xfd,0x3c,0xa4,0xf4,0xd3,0x2,0xc9, - 0x5d,0x11,0xdc,0x28,0x44,0x78,0x1f,0xd2,0x33,0xd1,0x6,0x48,0xd5,0x5c,0x98,0x9b, - 0xe5,0x16,0x8c,0x3e,0xdf,0x4e,0xc9,0xbf,0x4d,0x86,0x64,0x42,0x5a,0x66,0xd,0xb7, - 0xf7,0x69,0x60,0x3c,0xe1,0x7f,0xf,0x16,0xd0,0x15,0xdd,0xa6,0xf1,0x76,0xc2,0x57, - 0x8c,0x4f,0x95,0xeb,0x9e,0xdf,0xab,0xeb,0x66,0x11,0xad,0xc0,0xf6,0xba,0xf8,0xee, - 0xa4,0x59,0x2c,0x86,0x58,0xba,0x9c,0x29,0x50,0xf9,0x50,0xc1,0xef,0x13,0x19,0xfb, - 0xe1,0x2e,0xe7,0x80,0xe,0x94,0xeb,0x74,0x25,0x1a,0xb5,0x1c,0x54,0x2e,0x8b,0xf8, - 0x7,0xb7,0x80,0x5f,0xf1,0x9c,0x8,0x42,0x97,0x58,0x83,0x7,0xea,0x9c,0x4,0xcd, - 0x4b,0xeb,0xcd,0x59,0x0,0x3a,0x4e,0xa4,0x54,0x83,0x41,0xa8,0xb1,0xcc,0x22,0xb8, - 0x4,0xa2,0x18,0xf5,0x3f,0x9f,0xb8,0x56,0xf8,0x3c,0x5e,0xe3,0x59,0xe1,0x31,0xa4, - 0x4d,0x7f,0x7d,0x4e,0xb9,0xcb,0x72,0x8d,0x4f,0xb3,0xb5,0x80,0x80,0xd7,0x39,0x84, - 0x7a,0xd0,0xfa,0x3a,0x71,0x33,0x10,0xe9,0x6f,0xed,0x4d,0x48,0xcf,0x7f,0x6c,0x1e, - 0x7e,0xea,0xeb,0x38,0x36,0x5e,0x45,0x6,0x13,0xfa,0x86,0x13,0xd3,0x40,0x18,0xcd, - 0x90,0x13,0x8,0x81,0x46,0x19,0x6b,0x35,0x7,0x39,0xfd,0x57,0x38,0x6a,0x75,0xb6, - 0xd4,0x61,0xee,0xc,0x3f,0x34,0x12,0xd1,0xae,0x18,0xe5,0x82,0x58,0xfd,0x51,0xe9, - 0x90,0xd8,0xea,0x56,0x71,0xd6,0xb,0xf8,0x10,0x88,0x50,0x48,0xf3,0x45,0xfe,0xc8, - 0xa6,0x6d,0x54,0x65,0x21,0xe5,0x38,0xcf,0xfe,0x9d,0xd2,0x57,0x1b,0x24,0xc0,0xab, - 0x7c,0x2c,0x81,0xee,0x3,0xc,0xe7,0x13,0x95,0xb7,0x5b,0x89,0xfc,0xd9,0xd1,0x23, - 0xc6,0xa6,0x88,0xe7,0x8c,0xc0,0x37,0xb,0xdd,0xa,0x63,0xf8,0xad,0xa3,0x24,0x2b, - 0xcf,0xa5,0x1a,0xd2,0x32,0x81,0x65,0xc7,0x39,0x40,0xd0,0x36,0x1a,0x22,0x59,0xe0, - 0xc8,0xe1,0x48,0xd5,0x23,0x80,0xe0,0x80,0x8a,0xc3,0x7a,0xb8,0xe7,0x9e,0xe3,0x37, - 0xc4,0xfd,0x8a,0xf6,0x7f,0xef,0x3e,0x38,0x31,0xf,0x6e,0xca,0x31,0xc7,0x2c,0x7a, - 0x29,0x74,0x50,0xcb,0xf4,0xb0,0x4d,0x0,0x75,0x47,0x38,0x5d,0x65,0x1c,0x14,0x2a, - 0x99,0x9e,0xa0,0x19,0x8f,0xde,0xd0,0x40,0x6d,0x3f,0xb,0x9f,0x86,0x37,0x99,0x2f, - 0x2c,0xe9,0x7b,0xa0,0x1a,0xc8,0x20,0x8f,0x8f,0x58,0x6c,0xf4,0x74,0x1,0x9f,0xe, - 0x9f,0xbf,0xa6,0xae,0x9f,0x77,0xee,0xd,0xb6,0x7a,0x2c,0xbc,0x31,0xc5,0xec,0x5d, - 0x2f,0x68,0xfe,0x4a,0xb0,0x1f,0x59,0x40,0x78,0x46,0xb4,0xec,0x47,0x54,0x7b,0x66, - 0x94,0x22,0x16,0x34,0x9a,0x5,0xc0,0xd0,0xfe,0x6d,0xe,0x31,0x33,0xfa,0x8e,0xe2, - 0xe2,0x8d,0xac,0x93,0x2d,0x85,0x53,0xa5,0x4b,0x8,0x12,0x12,0xdc,0x8d,0x79,0xf0, - 0xb0,0x8f,0xa4,0xca,0x14,0x65,0x1b,0x14,0x52,0x29,0xc4,0x86,0xa3,0x53,0xe8,0x86, - 0x61,0x95,0x99,0x8e,0x9a,0xec,0xb3,0xe6,0x75,0xc5,0xf8,0xd1,0x54,0xf1,0xc2,0x84, - 0x1,0x67,0xce,0x16,0x4c,0x69,0xa9,0x9f,0x93,0x6e,0xa5,0xb6,0x41,0x8e,0x3e,0x22, - 0xa3,0xd7,0xb0,0xbd,0x45,0xe3,0xa4,0xba,0xaa,0x1e,0xc,0x7e,0x8f,0xce,0x3,0x91, - 0xb5,0x51,0xa7,0x2,0xba,0xd0,0x21,0xcd,0xbe,0xc6,0x5,0x0,0xd4,0x43,0x23,0x78, - 0x9a,0x53,0x37,0x5f,0x38,0x5b,0x99,0x62,0xf8,0xa5,0xe0,0x89,0xf3,0x63,0x1b,0xa9, - 0xb4,0x42,0x2c,0xee,0x13,0x4d,0x3d,0xd1,0x15,0x42,0x51,0xe9,0x5,0x74,0xe2,0x9f, - 0x48,0x99,0x7f,0x0,0x74,0x19,0x62,0x6e,0xbf,0x43,0x77,0x33,0x26,0x92,0x5d,0xda, - 0x54,0x89,0x49,0x67,0x56,0x86,0xb8,0xea,0x48,0xa,0x55,0x4d,0xfe,0x38,0x6d,0xc6, - 0x51,0xec,0xc6,0xc5,0x6,0x29,0xb3,0x45,0xeb,0x2b,0x79,0x12,0x3d,0xd6,0x6c,0x91, - 0x60,0xb5,0x78,0x36,0xbc,0x31,0x22,0x5,0xbb,0x77,0x53,0x3a,0x2f,0x40,0x1,0x0, - 0x2d,0xc7,0xc5,0x33,0x70,0xf9,0x79,0x5c,0xa4,0xf2,0x6e,0x62,0x49,0x5a,0x73,0x29, - 0x10,0xec,0x5f,0x4c,0x9d,0x1,0xd1,0xd8,0x78,0x25,0x13,0x27,0xe4,0x93,0x27,0x12, - 0x5b,0x6d,0xc4,0x4b,0x67,0x3e,0xa7,0x8b,0xb0,0x95,0xed,0x79,0xef,0x62,0xa2,0x80, - 0xce,0x3,0x4c,0xeb,0x4,0x1e,0x45,0xfc,0xc2,0xd7,0x24,0xa7,0x6c,0xcb,0xb9,0x47, - 0x39,0x7f,0x93,0x20,0x3d,0xba,0xab,0x6e,0x51,0x1a,0xe7,0xc0,0xfb,0xb,0xc0,0xca, - 0xe,0xe,0x36,0x91,0x2c,0xfa,0xe,0x6f,0xd3,0xb2,0x17,0xbf,0x7e,0x51,0x7,0x37, - 0x50,0x9a,0x57,0x8d,0x56,0x3,0x7b,0x27,0x1d,0x64,0xe7,0x19,0x6f,0x29,0x63,0xfc, - 0xb6,0x1a,0xe,0xe2,0x94,0x9c,0xd1,0x68,0x4f,0xe9,0x28,0x4d,0x3b,0x30,0x84,0xb, - 0x4a,0xdb,0x98,0x20,0x5e,0x94,0x47,0xfb,0xf8,0xaf,0x94,0xe7,0xd8,0x78,0x64,0x8f, - 0x12,0xf1,0xf1,0xa6,0x8e,0xc4,0x8f,0xdd,0x2e,0xb7,0x2b,0xe8,0x67,0x2f,0xf3,0x32, - 0x8a,0xc,0x52,0xe9,0xa0,0x9a,0x65,0x99,0x4a,0xf9,0x1,0xa2,0xf1,0xe4,0xb1,0x4, - 0xd7,0xa3,0x2b,0x66,0xe7,0xba,0xc4,0x16,0xf1,0x6f,0x7e,0xd9,0x9f,0x72,0xc,0x2a, - 0x7f,0x5e,0x93,0x20,0x78,0xf8,0x3a,0x42,0x73,0xba,0xe4,0xe4,0xa0,0x96,0x69,0xf7, - 0xba,0x94,0xdd,0xa2,0x4f,0xa2,0x39,0x41,0x92,0xb7,0x1b,0x32,0x2b,0xa6,0xdb,0x2a, - 0x6,0xef,0xc9,0xfd,0x68,0x4,0x41,0x5b,0x3f,0xa5,0x41,0x5f,0x3d,0xaa,0x57,0x77, - 0xbe,0x35,0x1a,0xe,0x58,0xd2,0xce,0xea,0x8b,0x6a,0x9c,0x36,0x11,0xf7,0xdf,0x96, - 0xe7,0xa9,0x95,0x51,0x2e,0xd6,0xac,0x6d,0xfb,0x6d,0xcc,0xb8,0x97,0x24,0x30,0x56, - 0xd8,0xca,0xe3,0x31,0x9d,0xb3,0x9b,0xa8,0x1e,0x38,0x5e,0xae,0xb0,0x3e,0x46,0x98, - 0xe8,0xdb,0x69,0x17,0x32,0x96,0x4,0x2e,0x4,0xd0,0x67,0x1c,0x74,0x97,0x72,0xcc, - 0x62,0x57,0x7e,0x80,0x8a,0x1a,0x29,0x28,0xd2,0x88,0xd6,0x83,0xc6,0x1d,0x9b,0x2f, - 0x78,0x6,0xc5,0x2a,0x9c,0xc9,0xd8,0x20,0x1a,0x40,0x3c,0xe,0xd7,0x2f,0xdb,0xba, - 0x6,0x5a,0x3b,0x10,0x74,0x64,0x38,0xc6,0x6c,0x8e,0xc9,0xb3,0xac,0x66,0x62,0xa4, - 0xeb,0x29,0x4f,0x88,0x72,0x28,0x28,0xd,0xe7,0xe4,0x1b,0xbf,0x14,0x76,0xf9,0x99, - 0xd0,0x35,0xa9,0xc5,0x1a,0x61,0x8c,0x6,0xef,0xd6,0xb9,0x1c,0x3d,0x9c,0xc1,0x29, - 0xc5,0x11,0x31,0xb7,0xb8,0xd8,0x44,0xa0,0xbd,0xdf,0xdf,0x51,0x56,0xda,0xea,0x28, - 0x8f,0x14,0xed,0xa9,0xf4,0xf9,0x30,0xe5,0x50,0xe9,0x2,0x8d,0x6,0x43,0x36,0xcb, - 0x54,0xe6,0x4,0x8c,0xc0,0xc7,0x2d,0xfd,0xa7,0xe,0x50,0xfe,0xe8,0xba,0xa6,0xf7, - 0x4f,0x14,0x22,0x44,0x8d,0x52,0x2a,0xde,0xbb,0xac,0xeb,0xc2,0xef,0x23,0xe,0x45, - 0x89,0x91,0x51,0x4a,0x5a,0x7f,0x49,0x81,0x8d,0x19,0x0,0xf5,0x53,0xa6,0x6d,0xa2, - 0x3a,0x8f,0xe7,0xc8,0xe1,0x91,0x27,0x9e,0x3e,0x13,0xe0,0x2f,0xb5,0xee,0xf3,0x40, - 0x81,0x45,0xa,0x5b,0xc4,0xd2,0xdc,0xd1,0xeb,0x5d,0x47,0x40,0x83,0xb5,0x62,0xbe, - 0x45,0xc9,0x7,0xa7,0x5c,0x2e,0xc5,0x9a,0xc0,0xa6,0x49,0x77,0x15,0x3d,0xb7,0x96, - 0x3,0xc1,0x71,0x47,0x15,0xce,0x1a,0x1,0x2c,0xe0,0xc0,0xaf,0x96,0xa3,0xed,0x5c, - 0x6d,0x74,0x83,0xc9,0xa2,0x49,0xe4,0x64,0xef,0xad,0x5b,0x5,0xeb,0x13,0x1c,0x6e, - 0x54,0xd,0xb5,0x69,0xdb,0x4f,0xea,0x87,0x31,0x2b,0xb7,0x47,0xce,0x25,0x23,0xbc, - 0x9a,0xa6,0x6,0x3d,0xef,0xea,0x21,0x5f,0x99,0x7c,0xe4,0x5,0xf,0x80,0x73,0x64, - 0x8d,0x29,0x4d,0xe9,0x79,0xb7,0xf0,0x2a,0xe3,0x28,0x71,0x32,0x4e,0x95,0xee,0xe8, - 0xbb,0x75,0xa5,0xac,0x60,0x47,0x8b,0x79,0xc3,0x70,0x7e,0x53,0xf0,0x71,0x37,0xfe, - 0x1b,0x84,0x68,0x14,0xbc,0x59,0x3e,0x20,0x82,0xaf,0x52,0x50,0xc4,0xc1,0x39,0x81, - 0x37,0xde,0xad,0x17,0x26,0x39,0x11,0x6a,0x2a,0xf,0x3d,0x9a,0x81,0x74,0x19,0x1c, - 0x78,0x81,0x30,0x35,0x5b,0x6e,0x55,0x5d,0x9d,0x28,0xad,0xe2,0x69,0x66,0xe3,0x20, - 0xc4,0x91,0xb6,0x6b,0x4a,0xc7,0xd5,0xf3,0xd7,0x13,0xf,0xd8,0x7,0x28,0xf4,0x7f, - 0xaa,0x25,0x35,0x85,0x93,0x8a,0x62,0xb0,0x32,0x8f,0x93,0x1b,0xf5,0x77,0x3b,0xba, - 0x88,0xf2,0x26,0x53,0x3a,0x7b,0xc6,0x12,0xe,0xd5,0xea,0x15,0xfe,0xdf,0x15,0x29, - 0x5,0x4a,0x2e,0x18,0x54,0x90,0xc9,0x87,0x20,0xdc,0xa2,0x16,0xd4,0x5e,0x50,0x5d, - 0xd0,0xf6,0x30,0xb,0x72,0xf7,0x1e,0x1,0xcd,0x88,0x16,0x4c,0x69,0xaa,0x75,0xed, - 0xf4,0xa3,0x86,0x4a,0xb3,0xcf,0xd1,0xd3,0xac,0xf3,0x69,0x81,0xd1,0x3a,0x5f,0xa2, - 0x31,0xf,0xae,0x23,0x7,0x4c,0x24,0x55,0xd4,0xba,0xa1,0xbd,0x65,0x97,0x2c,0x5b, - 0xba,0xb2,0x25,0x6f,0x2,0xf6,0x43,0xae,0x6a,0x2d,0xb0,0xbc,0x67,0x8f,0x5f,0x98, - 0x9e,0x8d,0x3b,0x26,0x59,0x60,0xfa,0xae,0x9a,0x1c,0x6c,0x7f,0xb3,0x18,0xda,0x6f, - 0x4a,0x0,0x5e,0x4c,0x76,0x21,0x7b,0x61,0x4e,0x2c,0x1e,0x35,0xbb,0xfc,0x4d,0xd9, - 0x8b,0x89,0x0,0xe4,0x69,0xfa,0x93,0x4,0x18,0x80,0x83,0x4b,0x18,0xde,0x3a,0x63, - 0x5e,0x98,0xaf,0x55,0xba,0x2b,0xb6,0x88,0xd6,0xd4,0xbe,0x12,0x51,0xc,0xec,0xdc, - 0x95,0x6c,0x42,0x7e,0xe7,0x55,0x82,0x0,0xd5,0x86,0xca,0x6e,0xe4,0x6,0xd1,0x43, - 0x1e,0x1,0x98,0xd8,0xac,0xce,0xe1,0x3,0x23,0xa0,0x16,0x75,0x2c,0x82,0x52,0xc2, - 0xee,0x94,0x41,0xd6,0x6a,0x44,0x56,0xbf,0x4a,0x22,0x2e,0x2f,0xa7,0x0,0x72,0xc5, - 0x81,0x8b,0x1f,0x2e,0x5a,0x1,0x31,0x7e,0xa1,0xc6,0xf3,0xcd,0x49,0xc5,0x10,0xb8, - 0xda,0xd1,0x8f,0x45,0x16,0x66,0x5,0xdf,0x8,0x34,0xf,0xaf,0xb3,0x1,0x75,0x35, - 0x8c,0x94,0xe2,0x67,0x95,0x15,0x65,0xb6,0xdb,0x59,0x5,0xa5,0x9e,0x15,0x5e,0x79, - 0x66,0x6d,0x3e,0x7c,0xd3,0x44,0xdb,0xdb,0xf7,0xea,0x8b,0x2b,0x6c,0x81,0x61,0xf8, - 0x16,0xc3,0xdf,0x2c,0xd8,0x45,0xe2,0x35,0x1e,0xe7,0x5a,0xbd,0x7d,0xb8,0x37,0xe3, - 0x26,0xf5,0xe0,0x7a,0x3a,0xbc,0x56,0xb1,0xa8,0x62,0xdc,0x15,0xe3,0xbd,0x8d,0x79, - 0x82,0xed,0xa5,0xda,0x33,0x89,0x8f,0x52,0xf0,0xe9,0x10,0x6e,0xa2,0xc6,0x53,0x49, - 0xbc,0x34,0xc3,0x76,0xf0,0x99,0xa7,0x19,0x7b,0x85,0xad,0xde,0xc2,0xbb,0x59,0xc4, - 0xa9,0xfe,0xa0,0x5c,0x8,0xaf,0xae,0xf9,0x9a,0x3e,0x68,0xbc,0x6,0x3b,0x6,0x42, - 0x6f,0x49,0x39,0xe0,0x63,0xe0,0x79,0xde,0xe5,0x28,0xbe,0x29,0x63,0x97,0xed,0xd, - 0x16,0xe,0x69,0x1f,0xbe,0x98,0x98,0xd8,0xd6,0x80,0x95,0x5c,0xbc,0x1c,0x1f,0xab, - 0xe4,0x58,0x8c,0x48,0xb8,0x7,0x28,0x1f,0xae,0x66,0x48,0x12,0xfd,0x36,0x9e,0x14, - 0xc4,0x87,0xb2,0x83,0x20,0x4b,0x5c,0x77,0xcc,0x71,0x53,0x9,0x8d,0x72,0xb4,0x73, - 0x4a,0xc1,0x3b,0x83,0x48,0x63,0xa2,0xf6,0x49,0x6a,0x88,0xc6,0x20,0xa6,0x5b,0xe4, - 0x2e,0xe,0x68,0xce,0xd9,0x44,0x46,0x26,0xb6,0x19,0x2f,0x44,0xc,0x63,0x37,0x56, - 0xa4,0x73,0x59,0xec,0x56,0x7b,0x63,0x20,0xe5,0x6b,0xe6,0x7,0x12,0x42,0xeb,0x41, - 0xd0,0xd4,0x8f,0x2a,0x98,0xd5,0x50,0x4f,0x6e,0xfe,0x14,0x7a,0xe1,0xca,0x51,0x87, - 0x3e,0xaa,0xf3,0x15,0x27,0xd7,0x35,0x8c,0xc2,0x9b,0x93,0xd5,0x5e,0x0,0x96,0x2f, - 0x54,0x26,0x59,0xec,0x7b,0x29,0xbc,0xe9,0x28,0x50,0x65,0x89,0x1b,0x36,0x90,0xd9, - 0xe0,0x85,0xee,0x87,0xdc,0x24,0x15,0x9f,0x3f,0x28,0xf4,0x9d,0xa7,0x8b,0xcc,0xfb, - 0x31,0xa5,0x69,0xac,0xce,0x26,0x17,0x76,0xf5,0xfb,0x1,0x11,0x32,0x91,0xea,0x13, - 0x96,0xd9,0x1b,0xf2,0x7d,0xaf,0x93,0xbd,0xd7,0x8,0x5b,0x0,0x14,0xa8,0x7b,0x45, - 0xcd,0xe4,0x72,0x1d,0x8a,0x9,0x93,0x80,0x5,0x14,0x92,0x37,0x26,0xfc,0xc9,0x3c, - 0x57,0x64,0x30,0xd4,0x14,0x43,0x12,0x6c,0x4b,0xed,0x6c,0x5f,0x16,0xe7,0x25,0xe3, - 0x4d,0x17,0x80,0xd7,0x20,0x15,0xd8,0x25,0xa8,0xea,0xdb,0x4e,0xe7,0xa5,0x8b,0x3f, - 0xb,0xbb,0x94,0x9e,0x7e,0x26,0xb,0xc9,0x93,0x77,0xa9,0xa9,0xdf,0x4e,0xe,0x2d, - 0x65,0x8e,0x84,0x85,0x23,0x5d,0x2a,0x4c,0x48,0x6,0x9a,0x31,0x2b,0x26,0xef,0xb5, - 0x61,0x84,0x55,0xdf,0x2b,0x60,0x2a,0xbe,0x58,0x53,0xe8,0x38,0xa1,0x76,0xe4,0x86, - 0x84,0x69,0xc,0x28,0xc7,0xb5,0x74,0x10,0xbb,0xf,0xc0,0xe6,0xb5,0xb1,0x9d,0x96, - 0xb5,0xf2,0x77,0x60,0xd2,0x21,0x20,0xaa,0x74,0x88,0x62,0x16,0xfe,0x47,0x9c,0x3, - 0xb1,0x28,0x2b,0xf8,0xdd,0x9f,0x88,0x19,0x2f,0xc9,0x7f,0x64,0xfa,0x9c,0xfa,0x30, - 0xf,0x72,0x91,0xe2,0x93,0xb1,0x8d,0x87,0xb9,0x70,0x1d,0xb8,0xb7,0x39,0xbb,0xe8, - 0x61,0x67,0x61,0xbe,0x7,0xea,0x57,0xb5,0x34,0xd7,0x1a,0x2f,0x74,0x16,0x5f,0x84, - 0x8,0xf0,0xe6,0x1c,0x22,0xf3,0xa3,0xdb,0x64,0xc1,0x14,0x1d,0x7a,0xd0,0x85,0xdc, - 0x38,0xe7,0x1b,0xbe,0x52,0x73,0x75,0x86,0xca,0xf,0xb5,0x3f,0xa4,0x15,0xc3,0xad, - 0x86,0x2a,0x49,0xa8,0x1f,0xec,0x85,0x83,0x2e,0x99,0xa0,0xa9,0xe9,0xa6,0x6,0xa1, - 0x8e,0xa0,0x61,0xe0,0x14,0x56,0xe6,0xde,0xe4,0x9c,0x9e,0x8a,0x31,0xe1,0xb7,0xb7, - 0xd,0x1,0xe0,0x2c,0x6d,0x66,0xaf,0x1c,0x7f,0xd0,0x45,0x6a,0xf6,0x4b,0xc,0x85, - 0x6b,0xec,0xe5,0x0,0xc2,0x4c,0x5e,0x28,0xe8,0xfc,0xb2,0x99,0xdf,0x6a,0xd1,0x6c, - 0xea,0xb2,0x18,0x58,0x98,0x47,0x74,0x18,0x97,0xb9,0x2,0x8e,0x84,0x8e,0x14,0xf0, - 0xfa,0x79,0xf0,0xbe,0xc5,0x4f,0xe6,0x2e,0xcc,0x19,0x48,0x2c,0x3,0x1a,0x98,0xed, - 0x4c,0x30,0x46,0x64,0x77,0x3b,0x7c,0x10,0xf4,0xfe,0x9e,0xf9,0x8d,0x33,0x6a,0x88, - 0x2c,0x5b,0xc6,0x72,0x2a,0x2d,0xa0,0xf6,0xc5,0x68,0xa2,0xc8,0x82,0x3b,0xb6,0x4e, - 0xea,0xfd,0xb2,0x63,0x39,0xaf,0x73,0xad,0xae,0x91,0x27,0xbb,0x44,0x91,0xc3,0x71, - 0x6c,0xb,0xe3,0x17,0x38,0x4,0xe,0xfe,0x6d,0x31,0xc7,0x6f,0xeb,0xfe,0xbe,0xd7, - 0x7c,0xf0,0x3b,0x35,0x20,0x2e,0xe2,0xce,0xbf,0x8a,0xa,0x5,0x1c,0xce,0xf5,0x9, - 0xd9,0x59,0x20,0x91,0x5d,0xad,0x10,0xca,0xde,0x58,0xba,0xcb,0x57,0xf8,0xa3,0xd3, - 0xe9,0xde,0x9,0xb,0x8c,0x6b,0x59,0xcb,0xf5,0xe3,0x50,0x92,0xb2,0x46,0x9b,0xc, - 0x9f,0xbb,0x9d,0x7d,0xe8,0x2e,0x48,0xc8,0x86,0x82,0x94,0xdd,0x7b,0xb7,0x31,0xe5, - 0x16,0xb9,0x70,0xa2,0x25,0x49,0x6e,0x9b,0x2d,0xbf,0xad,0x5f,0x85,0xc8,0x6b,0x26, - 0x4,0x89,0xa3,0xec,0xb7,0x6b,0xb5,0xbd,0xee,0xc9,0x1b,0xe9,0x81,0x4c,0xcf,0x97, - 0x6,0x40,0xb9,0xaa,0x8a,0x29,0xc5,0x37,0x68,0x73,0x97,0xed,0x3c,0x3,0x93,0x40, - 0xc,0xb6,0xad,0x43,0xa2,0x63,0x1,0x11,0x2e,0x1c,0xfa,0x2f,0xe7,0x4b,0x47,0xed, - 0x8b,0x1,0x19,0x95,0xa9,0xde,0xcd,0x91,0xd2,0xe4,0x80,0x8e,0xe7,0x93,0x4f,0x74, - 0x4b,0xfc,0xb7,0x6d,0xdf,0x39,0x7e,0x8d,0xd4,0xf8,0xbd,0xbd,0x44,0x84,0x2b,0x50, - 0x85,0xc3,0xe5,0xaf,0xa3,0x33,0x41,0xf5,0x18,0x41,0x84,0x80,0xd5,0x53,0x74,0xa0, - 0x50,0xab,0xe,0x31,0x64,0x8c,0xbe,0x3a,0x85,0xfb,0x77,0x4a,0x80,0x22,0x9a,0x86, - 0xe6,0x0,0x36,0xa,0xb3,0x77,0x0,0xcb,0xb9,0x4,0xcb,0xf,0x58,0xbf,0xaf,0xa8, - 0x6c,0xbd,0x59,0xd0,0xc9,0x98,0xb,0xce,0x94,0x2,0x19,0x95,0x25,0x33,0x1c,0xc, - 0x34,0x52,0x95,0xe7,0x49,0x95,0x33,0x82,0x19,0x7f,0x91,0x71,0x3f,0x41,0x9a,0xab, - 0x7e,0x73,0xfc,0xc7,0xc,0x87,0x17,0x21,0x8a,0x30,0xb6,0x2f,0xe3,0x52,0x3b,0x18, - 0xa4,0xd0,0x7f,0x6d,0xe5,0x32,0xf0,0x7e,0xb1,0x2,0xf0,0xf1,0xc3,0xb,0x1d,0xc1, - 0x7e,0x99,0x8a,0xb,0x22,0xa1,0x2c,0x2c,0x51,0x62,0x5b,0x35,0xb4,0x96,0xcc,0xd8, - 0xe6,0x4c,0x46,0x4c,0x7f,0xb6,0xca,0xb0,0x39,0x3b,0x22,0xfc,0xc5,0xbf,0x3e,0xc4, - 0x59,0x48,0xcf,0x7b,0xe9,0x7b,0xa7,0xbb,0xdd,0x82,0x70,0x92,0x19,0x3e,0xea,0x7f, - 0xa,0xb0,0x4b,0x9,0x68,0x17,0x3a,0x21,0xd1,0x5c,0x9d,0x98,0x1c,0xdb,0x5d,0xf5, - 0x25,0xac,0xf0,0x8e,0x28,0x19,0x4a,0x85,0x9b,0xbb,0x18,0x35,0x79,0x82,0xb4,0x3, - 0x33,0x80,0xd,0x1b,0x17,0x47,0x3c,0xe8,0x23,0xd9,0x1,0xbf,0xb6,0xdd,0xb5,0x5b, - 0x8a,0xa6,0xe9,0xb2,0x3f,0xb4,0x38,0xdb,0xef,0xcf,0x11,0x69,0x52,0x45,0x6c,0x6, - 0xc5,0xf8,0x21,0xdc,0x40,0x5e,0x46,0x64,0xb7,0x47,0x24,0xed,0x26,0x59,0x49,0xb0, - 0x7f,0x34,0xe3,0xbf,0xe8,0x9b,0x9b,0xd8,0xeb,0x2c,0xc1,0x3e,0x71,0xad,0xc3,0xb7, - 0xa7,0xe5,0x94,0xe7,0xc3,0xda,0xcb,0x7b,0xa2,0x6f,0x6a,0xc8,0x48,0xb3,0xf8,0xc8, - 0x67,0x5c,0x88,0xcf,0xf8,0x24,0x28,0xe4,0xcf,0xe9,0xa2,0x41,0x98,0x67,0xf8,0x40, - 0xcc,0xe,0xa7,0x90,0x68,0xf3,0xc,0xb,0xe2,0x76,0x53,0xab,0xaa,0x4d,0x74,0x12, - 0xa9,0x7c,0xe2,0x22,0xa0,0xb,0x7,0xef,0x75,0x2a,0x31,0xe,0x91,0xaa,0xcd,0x5e, - 0xb8,0xf4,0xee,0x21,0x68,0x7a,0x2d,0x4c,0xf1,0x80,0xf7,0x9c,0x4d,0xeb,0x2e,0x77, - 0x68,0x11,0x99,0x88,0x9c,0x21,0x78,0x12,0x4b,0xa9,0x9f,0x5c,0x54,0x6d,0xba,0x8c, - 0xe1,0x29,0xae,0x4b,0xa3,0xdb,0x17,0x15,0xdb,0x8e,0x31,0x2a,0x7a,0x60,0x21,0xe2, - 0x71,0xba,0xea,0x8d,0xdb,0x63,0x9f,0xa6,0x8c,0x3f,0x3,0x61,0x2c,0x3d,0xed,0x8e, - 0x66,0x9c,0xd9,0x8a,0xf7,0xf0,0x9f,0xd4,0x7f,0xd1,0x7e,0x79,0x32,0x9f,0x5c,0x23, - 0xd9,0x47,0xb1,0x36,0x2a,0xd0,0xdc,0xb6,0x90,0xe0,0x18,0x3c,0x1e,0x86,0xca,0x5, - 0x23,0xa4,0x8f,0x9b,0x15,0xae,0xef,0x14,0x0,0x6e,0x8d,0x32,0x8d,0x69,0xd5,0xe6, - 0x30,0x87,0x1d,0x5a,0x58,0x7a,0x91,0x68,0xda,0x29,0xa5,0x78,0xaf,0x70,0xfc,0x53, - 0x95,0x8c,0xee,0x2a,0xbb,0xde,0x3f,0xbb,0xcc,0x4c,0x6e,0xd9,0xb6,0x44,0x40,0x66, - 0x4b,0x5e,0x41,0x23,0x58,0x52,0x8c,0xb2,0x7b,0x32,0x2b,0xab,0xa2,0x29,0x7e,0xb7, - 0x35,0xec,0xe2,0xf0,0x4b,0x22,0x2d,0x18,0xed,0x9b,0x71,0x24,0xdf,0xb1,0x8b,0x2b, - 0x8f,0xcc,0xcd,0x67,0x1f,0x5a,0x1a,0x1a,0x8c,0x46,0x45,0xaf,0xee,0xc3,0x67,0x24, - 0xb0,0xc9,0x95,0xfb,0x6b,0xc2,0x93,0x5a,0x5e,0x84,0x7e,0xbd,0x37,0xa,0x68,0x46, - 0x56,0x36,0xae,0xf4,0x91,0xc8,0x8f,0x9d,0x8e,0xd4,0xcc,0xfc,0x19,0xb4,0x22,0xc9, - 0x7e,0x37,0x46,0xea,0x79,0x59,0xc4,0x57,0xde,0x43,0x15,0x95,0xcd,0xfc,0x5b,0x24, - 0x33,0xa,0x1a,0x44,0x53,0x29,0x62,0x61,0xfd,0xae,0x5f,0x17,0x63,0x1,0x61,0x62, - 0xb7,0x27,0xcc,0x31,0x80,0x91,0x88,0xde,0xd4,0x1d,0x74,0xa2,0x1a,0xd0,0x47,0xcc, - 0x5a,0xe0,0x91,0x2d,0xa,0x73,0x8f,0x8,0x22,0x6e,0x9f,0x86,0x6f,0x1,0x68,0x27, - 0x28,0x35,0xd7,0x28,0xc6,0xdf,0x8,0x1b,0xfc,0xfb,0x3e,0x96,0xcc,0x85,0xe2,0xa7, - 0xe5,0x74,0xd4,0xef,0xe7,0x64,0x77,0x8a,0xd2,0x17,0x90,0xc1,0x97,0xf8,0xe8,0x3f, - 0xad,0x40,0x68,0xf3,0x20,0xef,0xf,0x1d,0xeb,0xcc,0x33,0x39,0xd1,0x17,0xe0,0xb7, - 0xb,0xb5,0xa7,0x73,0x1b,0x9f,0xfd,0x6d,0x36,0x8e,0x30,0xce,0x87,0x98,0x8d,0x35, - 0xd9,0xf5,0x29,0xf9,0x65,0xb7,0x97,0x52,0x85,0x4a,0x8b,0xd6,0x61,0x6c,0x8f,0xec, - 0xa1,0xb6,0x60,0xbc,0x56,0x5e,0xaa,0x8d,0xec,0xda,0xdb,0xf3,0xf2,0x69,0xa8,0xcc, - 0xdf,0x51,0x47,0x45,0x9,0x5e,0x97,0xe,0xa8,0xa2,0xe5,0x8a,0x8e,0xf4,0x77,0x31, - 0xab,0xd7,0x6d,0x82,0x36,0x18,0x8f,0xa2,0x72,0x6b,0x96,0x66,0xd4,0x3f,0xb2,0x34, - 0x90,0x79,0x7a,0x19,0xd7,0x91,0xa7,0x1,0x35,0x8d,0x8b,0x43,0x2,0x3,0x74,0xad, - 0xda,0x62,0x30,0x90,0xf9,0xbf,0x33,0xec,0xaa,0xc9,0xd2,0x0,0x88,0x85,0x34,0x98, - 0x7f,0x2e,0x31,0x57,0xc0,0xd8,0xd7,0x75,0xe5,0x63,0xb8,0xe7,0x66,0xad,0x16,0xc0, - 0x8f,0x46,0x51,0x89,0x86,0x84,0x76,0x31,0xcd,0x49,0x31,0x56,0x4f,0xe5,0x6e,0xce, - 0x14,0xa0,0xa5,0x54,0xf8,0x7e,0xc9,0xdf,0xe1,0x3,0xc7,0xc8,0x30,0xdd,0x89,0xbf, - 0xa4,0xdb,0x49,0xaa,0xdf,0x40,0xdb,0xae,0x89,0x8d,0x84,0x58,0x73,0x73,0x27,0x7, - 0x14,0xcd,0x5c,0xd,0xcb,0x26,0x6c,0xad,0xa8,0x35,0xf5,0xd8,0x92,0x80,0x98,0xb6, - 0xdb,0x62,0x61,0xbb,0xa2,0xbd,0xe9,0xab,0x4b,0x6f,0x5,0x3e,0xe2,0x2c,0x45,0x76, - 0x79,0x21,0x83,0xc4,0xc7,0xf0,0xf2,0x70,0xa5,0xe8,0x4a,0xb7,0x69,0x62,0xee,0x45, - 0xc4,0x50,0x81,0xe6,0x8d,0x6b,0x93,0xd8,0x5a,0x18,0x96,0x3d,0xc3,0x5c,0x33,0x3e, - 0x7d,0x37,0x3,0x45,0xa7,0xf5,0xb6,0x4d,0x5f,0x80,0x84,0xc8,0xe2,0xf2,0x8e,0x28, - 0x44,0x8f,0x8e,0xd1,0xfa,0x22,0x2b,0x56,0xb9,0xc1,0x13,0x7e,0x1e,0xc6,0xbc,0x1c, - 0xfd,0x3f,0x61,0xa5,0xb5,0x18,0x72,0x15,0x18,0x76,0x5d,0xfb,0x6a,0x6b,0xa3,0xae, - 0xfa,0x32,0x0,0x76,0xd4,0xaa,0x4c,0x8e,0xec,0xde,0xd,0x8a,0xa5,0x49,0xa6,0xa3, - 0x9,0x9,0x49,0xbe,0xa0,0x3b,0x53,0xb9,0xb2,0x30,0x35,0x1d,0x9c,0xd8,0x4b,0x17, - 0x8a,0xca,0xd,0x5f,0x76,0x59,0x6e,0xe2,0x39,0x7b,0x6d,0x5e,0xc5,0x15,0x82,0xce, - 0x9d,0xcb,0xd,0x3e,0x87,0xdf,0x77,0x3a,0x10,0xac,0xd6,0x2c,0x5,0x22,0x44,0x90, - 0xec,0x51,0x6f,0xe2,0x2b,0xdd,0x45,0xe3,0xd9,0xb3,0x42,0x1f,0x48,0xc4,0xed,0xe5, - 0x11,0x7a,0xa3,0x18,0x5a,0x1c,0x52,0x6a,0x48,0x29,0x17,0xcd,0xca,0x5b,0xdd,0x37, - 0x2c,0x4d,0x9a,0xd6,0xab,0xdf,0xba,0x85,0x93,0x7d,0xa4,0xdb,0xc1,0x12,0x41,0x52, - 0x8c,0xe5,0x6a,0x66,0x81,0xbc,0x50,0xc9,0x65,0x67,0x17,0xaf,0x42,0xf4,0xe7,0xee, - 0x43,0x2,0xc5,0x6e,0xe1,0x1,0xf3,0xf5,0x7e,0x18,0x51,0xbf,0x2a,0x93,0x13,0x36, - 0xf8,0x7d,0x1c,0x7a,0xba,0x6c,0xc3,0x9f,0xd4,0xdb,0x50,0x96,0xd0,0xb7,0x85,0x93, - 0xb9,0x4c,0x2,0x9b,0xcc,0x75,0x91,0x4b,0xd,0xe3,0x8a,0x37,0xf6,0x9d,0xec,0xef, - 0x1c,0x9,0x6a,0xd6,0xf5,0xad,0x76,0x4a,0x89,0x46,0xe0,0xda,0xfd,0xe6,0xed,0xb7, - 0xb2,0x70,0xd3,0x7f,0xe5,0x65,0x4a,0x73,0xc8,0xd4,0xaa,0x3f,0x73,0x18,0x2f,0xf, - 0xa0,0x19,0xe5,0x96,0xc7,0xdb,0xe0,0xd0,0x23,0x42,0x2b,0xa0,0x29,0x1a,0x59,0xdb, - 0x8a,0x2d,0xda,0xef,0x12,0x25,0x63,0x5b,0xf9,0x8e,0x9a,0xec,0x26,0x4a,0xfb,0xc6, - 0xe2,0x61,0xdd,0x2a,0xbd,0x3e,0x7b,0xe0,0x0,0xa6,0x1,0xa8,0x40,0x5a,0x84,0x4a, - 0x7,0xde,0xba,0x99,0x4,0x9d,0xf4,0x7e,0xab,0xf,0xea,0xd1,0xd8,0xe7,0x19,0xbc, - 0xc8,0x76,0xe6,0x86,0xb4,0x62,0xe6,0xb5,0x89,0xe8,0x5e,0xc9,0x43,0x63,0x94,0xca, - 0xc1,0x4f,0x64,0xc6,0xec,0xd8,0xc4,0x99,0xe7,0xaf,0xea,0xc1,0x17,0x4,0xfd,0x60, - 0xf9,0xe4,0xe6,0xaf,0xc7,0xce,0xe4,0x51,0x37,0xc2,0x9a,0xf9,0xa5,0x2f,0xc4,0x68, - 0x7e,0x29,0xae,0xeb,0x2,0xf2,0x5,0x6a,0x22,0xef,0xab,0xb9,0x74,0xa9,0x1a,0x6e, - 0xe,0x1,0x9d,0xd5,0x4f,0x2,0xa6,0x86,0x45,0x42,0x81,0xea,0xf0,0x46,0xd2,0xef, - 0xef,0x1,0x5b,0x71,0xf3,0x60,0x5b,0x17,0xcf,0x7,0xd0,0x44,0x30,0xea,0x33,0x3f, - 0x6b,0x50,0x94,0xbb,0x53,0x3c,0x42,0x98,0xfd,0x43,0x3,0x6e,0xa,0xd6,0x5e,0xf9, - 0xd7,0xb9,0xea,0x4c,0x99,0x47,0xe2,0x6a,0xcd,0x33,0x2e,0xfe,0x9d,0x61,0xbd,0x9, - 0x32,0x52,0x44,0x85,0xe,0x87,0x1e,0x8b,0x4a,0xa0,0xfa,0x54,0x77,0xd8,0xcd,0xcf, - 0x13,0xb9,0x9b,0xac,0x80,0x7e,0x96,0xcd,0x31,0xc5,0x4c,0xce,0xa6,0xa,0x57,0xd8, - 0x5d,0x9c,0xdd,0xea,0xa3,0x7b,0x77,0xed,0x1d,0xf1,0x43,0x14,0xca,0x11,0xe3,0x5d, - 0x4a,0xfe,0xb,0x4a,0xfc,0x21,0x19,0x2e,0x66,0x65,0xfc,0xe,0x70,0x55,0x66,0x4d, - 0xf1,0xc4,0x38,0x95,0x40,0x2f,0x3,0x5d,0x21,0x46,0x72,0x6c,0xd7,0xd5,0xc9,0x22, - 0xd5,0x54,0x6d,0xd2,0x76,0x6,0x81,0xdc,0x6b,0xfd,0x6a,0x5b,0x53,0x51,0x28,0xc4, - 0x16,0xe0,0xd9,0x56,0x10,0xdd,0x34,0xb1,0xa3,0xa6,0x1e,0x7b,0xfb,0xe7,0x9e,0x51, - 0x3d,0x8b,0xa4,0x33,0x11,0x26,0x10,0x7c,0x24,0xfa,0x58,0xf7,0x4c,0x80,0x3c,0xe1, - 0x61,0x96,0x38,0xf1,0x74,0x6c,0xa3,0x97,0x92,0xc1,0x14,0xf,0x29,0x32,0x60,0xe5, - 0x3d,0x84,0x98,0x4e,0xaa,0x29,0x4a,0x4f,0x24,0xa2,0xc6,0xef,0xa3,0x3,0xd1,0x5, - 0x99,0xa,0x76,0x8d,0xf6,0x1a,0x26,0x9,0x5b,0x3a,0x97,0x5,0xeb,0xf8,0xea,0x29, - 0x7d,0x4,0x77,0xa8,0x2d,0x41,0x77,0x51,0xe4,0x3e,0x41,0x88,0x41,0x92,0xd,0xdb, - 0x1c,0x84,0xe8,0x13,0x1e,0xf,0x9c,0x7a,0xc8,0x34,0xfe,0xb4,0xac,0x69,0x5d,0xaa, - 0x6d,0x54,0xd2,0x9a,0x96,0x4a,0xeb,0x7b,0x88,0xac,0x83,0x49,0x3f,0x10,0x25,0x5c, - 0x14,0x8e,0xee,0x33,0x9d,0xb,0x2d,0xe6,0x40,0x2c,0x1b,0x6c,0x95,0x79,0x17,0x4, - 0x4d,0xe9,0x9e,0xe3,0x34,0xb,0xde,0x3c,0x37,0xe1,0x86,0xf6,0xf2,0x2b,0xd2,0x7, - 0xb9,0xc1,0x3a,0xd7,0xcd,0xe6,0xbe,0x8d,0x13,0x59,0xf9,0x29,0xd2,0x91,0xac,0xa0, - 0x7b,0x4b,0x84,0x30,0xd5,0xe3,0xeb,0xe,0xc5,0x72,0x84,0xb8,0x9e,0x57,0x40,0xd7, - 0x98,0xf9,0xaf,0xe5,0xe1,0xed,0x73,0x74,0xc7,0xed,0x9d,0x9a,0x7f,0x4a,0xba,0x7a, - 0x16,0x40,0x2a,0xeb,0x24,0x17,0x79,0x69,0x9,0x7d,0x23,0x27,0xd4,0x63,0x0,0x6e, - 0xdc,0x2f,0x54,0xbe,0x9d,0x48,0x34,0x65,0x36,0x51,0x7f,0x35,0x9c,0x3b,0x2f,0x32, - 0xfa,0xd9,0x9d,0x9e,0x70,0x18,0x8,0x79,0x15,0xaa,0xa1,0xea,0x8d,0xa1,0x59,0x6b, - 0x50,0x2d,0x2a,0xed,0x75,0xdd,0x53,0x2b,0x30,0x53,0xdf,0xcc,0x8e,0x10,0xfe,0x89, - 0x69,0x9c,0x28,0xd9,0x34,0xaf,0x53,0x4a,0x5b,0x74,0xb4,0xe8,0x95,0x8d,0x54,0xe6, - 0xba,0x7f,0x54,0xb0,0xdc,0xa8,0xdb,0xd,0x7b,0xbc,0xd9,0xa,0x4c,0x58,0x13,0x35, - 0x75,0xba,0xf,0x29,0x6a,0xe1,0xf2,0xc5,0x57,0xa7,0xaf,0xec,0x35,0x4,0xd3,0x70, - 0x3,0x29,0x21,0x60,0x51,0x7c,0x6d,0xcc,0xb8,0xc7,0x56,0x84,0x20,0x69,0xb9,0x15, - 0x24,0x48,0x3f,0x8e,0x2b,0xb1,0xd4,0x82,0x5a,0x84,0xee,0xf,0x8,0xc3,0xfe,0x8b, - 0x6c,0x9f,0xeb,0x3d,0x1d,0x59,0x89,0x55,0x21,0xdf,0x5a,0xc1,0x49,0x14,0x56,0xec, - 0xdc,0x15,0xfa,0x8,0xc7,0xcf,0xa,0x22,0x54,0x78,0xb0,0xdc,0xbb,0xb0,0x68,0x28, - 0xcf,0xd3,0xe4,0x6c,0x2d,0x6e,0xc2,0xce,0x4e,0x1d,0x10,0x17,0xb0,0xe5,0x4,0xd, - 0xfb,0x0,0x15,0xc3,0x4f,0x9e,0x65,0xa4,0x18,0x95,0x1,0xd3,0xc5,0x69,0x7c,0x96, - 0x3d,0x61,0x3,0xe9,0xd0,0x45,0x38,0x9e,0xe1,0xc7,0xb6,0x13,0xae,0xba,0x20,0x2a, - 0x3a,0x36,0xed,0x8a,0x54,0xd2,0xae,0xeb,0x68,0xaf,0xc0,0xae,0x98,0xbc,0x45,0x55, - 0x1e,0xc7,0xbe,0x6e,0xe,0x77,0xe,0xef,0x3f,0xc4,0x3,0x6d,0xfe,0x24,0x97,0xb9, - 0xd9,0x5,0xc3,0xad,0x57,0x72,0x9a,0xc0,0xa1,0xda,0xee,0x3a,0x97,0x34,0xf,0x35, - 0xfb,0xcd,0xa4,0x89,0x45,0x32,0xf9,0x5,0xf6,0x7c,0x72,0x75,0x20,0x8a,0x2f,0x79, - 0x8f,0xf2,0x28,0xe7,0xe4,0xc2,0x28,0x86,0x1d,0x17,0x40,0xb4,0xca,0x4f,0x69,0x46, - 0x1e,0xe,0x50,0x63,0x40,0x4a,0x68,0xb6,0xc6,0x5b,0x2d,0xe7,0xe5,0xdb,0x61,0xf4, - 0xcf,0x9,0xdc,0xb4,0x4b,0x84,0xbb,0x68,0x1b,0xfb,0x9c,0x65,0x4c,0x7,0xac,0x6a, - 0x15,0xfc,0x4d,0xd5,0xc6,0xb6,0xc,0x8d,0x91,0xb8,0xf4,0x77,0x95,0xd6,0x6c,0xe4, - 0xdf,0xc9,0x19,0xab,0xcd,0xd4,0x14,0xe9,0xd1,0xb1,0x4f,0x1e,0xb8,0x7b,0x8,0x4d, - 0x78,0x55,0xa2,0x3f,0x8b,0xaf,0x4d,0x1d,0xe7,0xc1,0x14,0x7d,0x98,0x81,0x62,0xf8, - 0xca,0x7c,0x24,0x98,0x51,0x38,0x2,0xa2,0x69,0x52,0x40,0x22,0x4d,0x48,0xef,0xc6, - 0x9e,0x92,0x85,0xa9,0xc1,0xd2,0xc7,0xaa,0x15,0xdb,0xa7,0xad,0xdc,0xb,0x26,0xa7, - 0x7,0x4a,0xc0,0xd7,0x3,0xc2,0x7b,0x6c,0x94,0xbb,0xf,0xe2,0x84,0xfe,0x29,0x23, - 0x11,0xae,0xcc,0x53,0x2,0x14,0x7d,0x17,0x70,0x25,0x44,0x4d,0xaf,0xea,0x75,0x36, - 0xb4,0xb5,0xf,0xb7,0x78,0xa,0xa4,0x8d,0x45,0xb3,0x70,0xc9,0xb2,0x99,0x6c,0x43, - 0xc7,0xb9,0x96,0xc9,0x4d,0x14,0x60,0xbd,0xb9,0x25,0x8b,0x69,0x10,0x80,0x20,0x44, - 0x36,0x2f,0xfc,0x2e,0xb8,0xa1,0xbb,0xfd,0xd4,0xab,0x48,0x7,0x45,0x34,0x4a,0x8d, - 0xed,0x61,0xd6,0xbb,0xf4,0x38,0x79,0xae,0xdc,0x84,0x98,0xec,0x5,0xb8,0x31,0x3b, - 0x67,0xad,0xe9,0x20,0xce,0xa5,0x9d,0xa3,0x52,0x65,0xaa,0x17,0x9a,0xf5,0xa4,0x8, - 0xd6,0xfb,0x43,0xcb,0x34,0xbd,0x7b,0x11,0xc1,0x93,0x7d,0xc7,0x4c,0x2e,0x82,0x33, - 0x5c,0x6c,0x53,0x2b,0x13,0x70,0x4f,0xe4,0x56,0xf9,0xfb,0x70,0x6f,0x21,0xf7,0x46, - 0x1d,0x3c,0x13,0xd0,0x79,0xe,0x61,0x3b,0xa1,0x5e,0x3,0x6d,0x8c,0x86,0xa0,0xe8, - 0x72,0xf3,0x94,0x5,0xe3,0xe3,0xe9,0x3a,0x5d,0x66,0x2a,0xcd,0x7,0x23,0x93,0xa3, - 0x5f,0xa6,0x74,0xd8,0x34,0x55,0x14,0xd5,0xb3,0x18,0x43,0xbf,0x1e,0xe3,0x29,0x90, - 0x57,0xbd,0x96,0xbb,0x21,0x0,0x75,0x7e,0x66,0xa0,0x4c,0xec,0xc3,0xe0,0x90,0x23, - 0x7,0x84,0x7b,0xbb,0xd9,0x8f,0x11,0x8d,0x27,0x55,0xcd,0xc4,0xb8,0xf6,0x56,0x90, - 0xb4,0x6c,0x4c,0x55,0xeb,0x41,0xd3,0xd2,0xe1,0x21,0xbf,0xa5,0x81,0x51,0x48,0x8, - 0xd5,0xc3,0x43,0xb0,0xd3,0x55,0xbd,0xfa,0xaa,0x8b,0xc0,0xe2,0x2,0x96,0xf2,0x36, - 0x82,0xbe,0x8b,0x6e,0x1,0x60,0x41,0x62,0x1,0x2,0x9,0x2,0xd2,0xd0,0x89,0xa8, - 0x15,0xcd,0xd8,0xe8,0x23,0x17,0x63,0x4d,0x22,0xa3,0xaf,0x25,0xb9,0xa3,0x5b,0xbb, - 0x62,0xe7,0x2b,0xe2,0x48,0xeb,0x46,0xc8,0x6d,0xce,0xca,0x40,0x9f,0x54,0x69,0x34, - 0xa1,0xc1,0x9c,0xc4,0xd8,0x80,0x12,0xfb,0x24,0xc2,0xa0,0x5e,0xe5,0xfb,0x1a,0x48, - 0xe3,0xc4,0x2c,0xab,0x31,0xf1,0xf3,0x9e,0xc0,0x3e,0x5f,0xdf,0x93,0xc8,0x15,0xb4, - 0xa,0xb1,0x7a,0xe3,0x32,0x8c,0x5f,0xd6,0xce,0x0,0xb4,0xb4,0x7b,0x4e,0x7d,0xdf, - 0x14,0x29,0xb,0x45,0x1b,0x0,0x63,0xdb,0x3e,0xc2,0xbb,0x51,0x8b,0x50,0x7,0x16, - 0x82,0x81,0x79,0xb4,0x8d,0xd8,0xb,0xdc,0x58,0x3f,0x11,0x53,0x8e,0x8e,0x33,0xa2, - 0xb7,0xbe,0x67,0x52,0xbe,0xca,0xad,0x7c,0x8e,0xe9,0x4e,0x99,0x3a,0x55,0xaf,0xbc, - 0x56,0x29,0xf1,0x63,0x81,0x7c,0xbf,0x59,0xbc,0xd1,0x2d,0x4b,0xdf,0x60,0x6d,0x98, - 0x9e,0xd4,0x6a,0x5d,0x1f,0x19,0x5a,0x2d,0x3,0xa8,0xc7,0x3d,0xfd,0xf6,0x7a,0xd3, - 0xa0,0x6c,0xb6,0xa1,0xe8,0x77,0x7b,0xa5,0xc8,0xa8,0x70,0xa8,0x88,0xdd,0xc0,0x28, - 0xb2,0x2c,0x5,0x52,0x45,0x5f,0x7f,0x48,0x87,0xc6,0x5,0x85,0x3e,0x7f,0xd8,0xde, - 0x6b,0x90,0x0,0xd4,0x87,0xfa,0x7a,0x50,0x23,0xeb,0xf8,0xac,0xc9,0x3a,0x54,0xfc, - 0x66,0xd8,0x4f,0x2b,0x39,0xce,0xf2,0xc0,0x96,0xf7,0xc6,0x54,0xf7,0x1f,0x33,0x63, - 0x2f,0xb2,0x38,0x36,0xae,0x33,0x86,0xd1,0x9e,0x0,0xfd,0xe7,0x3a,0xd1,0xe4,0x20, - 0xab,0xb3,0x4b,0x64,0x3,0x3e,0x25,0x19,0xb5,0x6b,0x6d,0xad,0xb,0x20,0x91,0x3a, - 0xd2,0xc9,0x71,0x1,0x7c,0x77,0xd3,0x1b,0xf6,0x51,0x4,0xb0,0x24,0x68,0xd0,0xcf, - 0x1d,0x9b,0x34,0x20,0xd9,0xd8,0xb8,0x10,0xc4,0x26,0xbd,0xcf,0x46,0x4f,0x89,0x19, - 0x99,0x7a,0x9a,0x16,0x72,0xed,0x32,0x69,0x3f,0xb5,0x1b,0x63,0x1e,0x6b,0xb2,0xba, - 0x8,0xe6,0xda,0x61,0x40,0x93,0x71,0x5,0x39,0xaf,0x54,0x7f,0x7e,0x5d,0x19,0x18, - 0xd8,0xb3,0xae,0x4b,0xa1,0x60,0x34,0xe0,0x16,0x4f,0xc4,0x34,0x3b,0x77,0xef,0x43, - 0xde,0x4a,0x24,0x1f,0x5e,0x16,0xa3,0x97,0xc5,0x77,0x97,0x44,0xd4,0xb0,0xdc,0xad, - 0xe3,0x8b,0x78,0x85,0xeb,0xad,0xe5,0x2,0x7c,0x2a,0xb5,0xb7,0x22,0x25,0x7a,0x1, - 0xef,0x9f,0x9f,0x4e,0xb5,0xc2,0x65,0x7b,0x3a,0x7c,0x3f,0xf,0xac,0x1c,0x3d,0x90, - 0x27,0x35,0x95,0x92,0xe2,0xfb,0x94,0x60,0x26,0xca,0x97,0xc7,0x6f,0x13,0x48,0x5f, - 0x32,0x67,0x2d,0xe7,0x2a,0x13,0xe2,0xe3,0x8f,0xa1,0xf3,0x3d,0x3e,0xb0,0xcd,0x65, - 0xe5,0xe3,0xf8,0x49,0xdf,0xd,0x29,0x85,0x57,0xc0,0x4e,0xc7,0x53,0x96,0x27,0x85, - 0x7e,0xd4,0x6d,0xa8,0xe7,0xcf,0x8d,0xf6,0x72,0x1,0x34,0xb0,0xb1,0x82,0x95,0x17, - 0xe5,0xe,0x60,0xc5,0x1c,0x89,0xca,0x73,0xca,0x98,0xba,0x1e,0xaf,0xe2,0xa4,0x2e, - 0x37,0x91,0xd6,0x1f,0x62,0xe3,0x95,0x54,0xe4,0xca,0x84,0x16,0xcc,0x1a,0xad,0xb2, - 0x29,0xe,0xf7,0xc4,0x18,0xc2,0xb7,0xe2,0x5c,0x73,0x1,0x8b,0xd5,0x25,0xb9,0xd, - 0xb7,0x90,0xab,0x99,0xf4,0x41,0xed,0xd9,0x8b,0x72,0x70,0xd7,0xc,0x1e,0x8a,0xb4, - 0xab,0x2,0x79,0x43,0x45,0x32,0x26,0xa1,0xa5,0xa7,0x2d,0xfa,0x4c,0x66,0x8,0x4, - 0xf6,0x33,0x1d,0xeb,0xf3,0xb,0x46,0x80,0xfc,0x36,0x58,0x89,0x54,0x63,0x3e,0x7f, - 0xe4,0xb8,0xc3,0x2a,0x6a,0x69,0xcb,0x8f,0x90,0x78,0x8a,0xdd,0xde,0x12,0x61,0x56, - 0x45,0x7f,0xc1,0x39,0xa,0x87,0x39,0x87,0xbd,0x12,0x11,0x91,0xf4,0x4f,0x12,0xd9, - 0x87,0x55,0x5,0x71,0x3e,0x50,0x1,0xcf,0x49,0xb,0x2d,0xa7,0x1d,0x8e,0x7d,0xe1, - 0x8d,0x40,0x9b,0x18,0xc7,0xd4,0x9f,0x6,0x66,0x30,0x97,0x5b,0xfe,0x29,0xb5,0x87, - 0xfd,0xba,0x78,0x3d,0x8a,0x7a,0x8c,0xd3,0x85,0xb9,0xfb,0x23,0xc7,0x79,0x5,0xd5, - 0xb9,0xa0,0xed,0x2,0xf5,0xd,0x8,0xdb,0x3d,0x1f,0xb7,0x3c,0x49,0x6d,0x43,0x47, - 0xa7,0xbc,0x84,0x32,0xb6,0x90,0x86,0xbb,0x4a,0x82,0xde,0x92,0xfb,0xe4,0x68,0x36, - 0x5,0xd5,0xb7,0x7a,0xe2,0xbf,0x57,0x9f,0xde,0xf,0xdb,0xa7,0xfb,0x9f,0xef,0xa3, - 0xdb,0xf3,0x55,0x92,0x85,0xdb,0x4e,0x4f,0xdd,0xad,0x61,0x5a,0x12,0xc9,0x90,0x17, - 0x9f,0x48,0x92,0x82,0x87,0x69,0x22,0xe5,0x78,0x7e,0x8e,0x74,0x9d,0xfd,0x97,0xf8, - 0x71,0xec,0xb,0xf6,0x49,0xd8,0xc6,0xa6,0x86,0x28,0x1,0x98,0x72,0x11,0xb0,0x91, - 0xd8,0xc2,0x15,0x60,0x2c,0xb6,0xc6,0x24,0xb4,0xd4,0x18,0xd1,0xd2,0xaf,0xca,0x44, - 0x1c,0xd5,0xbb,0x65,0xaf,0x2,0xd,0xb5,0x2a,0xe,0x4f,0x1c,0x9f,0x7f,0xae,0x78, - 0xc1,0x43,0x59,0xed,0x79,0x20,0x91,0x2f,0xf4,0xa9,0x80,0x47,0x59,0x4c,0x8b,0x75, - 0xa1,0x47,0x5b,0xd0,0x49,0x68,0x87,0xf3,0xf5,0xd6,0x10,0x15,0x56,0x3e,0x8e,0x18, - 0x81,0xe7,0x85,0xfb,0x87,0x96,0xaa,0xfb,0x40,0x2b,0x43,0x19,0x77,0x4e,0xe,0x99, - 0x16,0x69,0x6a,0x5f,0x51,0xf1,0xd2,0xc7,0x48,0x63,0xdc,0x1e,0xa1,0xea,0xb5,0x24, - 0x52,0x3b,0x9f,0x59,0x51,0x4a,0x55,0x91,0x75,0x18,0xaa,0x6d,0x67,0x39,0x7,0xfc, - 0x22,0x71,0xdb,0x74,0xe3,0xaf,0xbb,0x2c,0x92,0x18,0x4b,0x34,0x4,0x80,0xd7,0x56, - 0x3c,0x77,0xb0,0x8d,0xc1,0x85,0x20,0xb7,0x1e,0x4a,0x25,0x5,0x83,0xab,0x2,0xa6, - 0x9c,0xdd,0x9a,0x80,0x8d,0x56,0x2d,0x20,0xed,0xf7,0xd4,0xf1,0x78,0x2c,0xc8,0xb4, - 0xa4,0xf8,0x43,0xe5,0xfd,0x63,0x9d,0x1c,0x2d,0x42,0x21,0xb1,0xed,0xa2,0xd7,0x8b, - 0x81,0xf1,0x8b,0x8e,0xc7,0xb8,0x2f,0xb5,0xb0,0x83,0xa8,0x2a,0xaf,0xf0,0x5e,0x54, - 0x69,0xa1,0x3b,0x67,0x84,0x58,0x4,0xb2,0x9b,0xa4,0xe3,0x89,0x48,0xbb,0x94,0xc9, - 0x2d,0x21,0xd7,0xf4,0xd9,0x7,0xaa,0xb,0x8a,0xd2,0xb4,0x3b,0xc3,0x13,0xf,0x2d, - 0x35,0xc9,0x95,0xb9,0x23,0x19,0xeb,0x3e,0xbd,0xcf,0xc7,0x6,0xb,0x5d,0x4f,0x38, - 0xfd,0x28,0x2d,0xd7,0x2f,0xd8,0x62,0x3a,0xab,0x17,0xf4,0xef,0xaa,0x4,0x1d,0xdf, - 0xce,0x32,0x19,0x71,0x4b,0x6,0xaf,0xa,0x55,0xf6,0x8f,0x61,0xd3,0xdf,0x19,0xd1, - 0x8,0xc6,0x2a,0xb6,0x9f,0xc,0x70,0xca,0x24,0x65,0xba,0x4e,0xe9,0x58,0xad,0x38, - 0xa,0x46,0xa9,0xd5,0xcb,0xd8,0x5f,0x22,0xcf,0xee,0x3,0x24,0xce,0x1c,0xf5,0x56, - 0xe2,0x9f,0xe,0x2,0xac,0x7e,0x4d,0x50,0x64,0x8,0x9e,0x4e,0xdf,0xcb,0x86,0x6a, - 0x12,0xaf,0x40,0xde,0x88,0x1f,0x1,0x58,0x8d,0x83,0x7c,0xdc,0x9f,0xf2,0x33,0x3, - 0x92,0xc0,0x84,0x3f,0xbf,0xd1,0x8f,0x24,0x5a,0xad,0xf1,0x3a,0x79,0x78,0x24,0xc, - 0xa7,0xe3,0xea,0x30,0x3,0x6b,0x8,0x11,0xee,0x5,0xed,0xe,0xf7,0x21,0x90,0xa, - 0x62,0x16,0xc9,0x22,0x67,0xd8,0xc5,0xc1,0x7,0xb7,0x7c,0x0,0xaf,0xa0,0xc,0x57, - 0x5,0x76,0x7,0x8,0x61,0xf,0x19,0xcf,0x14,0x86,0x5e,0x8b,0xa8,0xee,0x16,0xb, - 0x84,0x5f,0xac,0xec,0x38,0x72,0x2e,0x3f,0xa9,0xaa,0x40,0x59,0xcb,0xcb,0x30,0xd0, - 0x43,0x37,0x58,0x24,0xc5,0x72,0xf4,0xda,0xf8,0x53,0xe5,0x21,0xc1,0x7b,0xab,0xc6, - 0xda,0x58,0x33,0x14,0x4a,0x61,0xd2,0xf3,0xd,0x92,0xcc,0x58,0x5f,0x7c,0x29,0x22, - 0xb3,0x81,0xc5,0xf9,0x73,0xba,0xd4,0xec,0x8d,0x3a,0x8d,0x50,0xb6,0x3a,0x96,0x91, - 0x12,0xc9,0x25,0x5d,0x2b,0xf8,0xd0,0xb7,0x8b,0x1e,0x8f,0x6a,0x9a,0xb8,0xc,0xce, - 0xba,0xd2,0xc8,0x2e,0xd,0x1d,0x9a,0x9b,0x57,0x29,0x6b,0x8d,0x63,0x2,0x20,0xf4, - 0x4b,0x45,0x52,0x76,0xbd,0xa3,0xae,0xc9,0xc1,0x3e,0xb3,0x5c,0x77,0xc0,0x2b,0x32, - 0x13,0x73,0xdf,0x20,0x90,0x7b,0xbb,0x68,0xa4,0xa6,0xf5,0x87,0x28,0x95,0x7c,0x73, - 0xdb,0x4f,0x6a,0x19,0xf2,0x98,0xe2,0x34,0x56,0x97,0x90,0xcd,0xd7,0x3c,0x7f,0xea, - 0xaf,0x60,0x8a,0xc0,0xdb,0xc6,0x29,0x0,0x6d,0x1f,0x7,0x96,0xb5,0x83,0x89,0x11, - 0x52,0xf3,0xa9,0xc4,0x8c,0xd,0xf8,0xe3,0x24,0xa,0xb1,0xfb,0x46,0xb1,0x66,0x75, - 0x12,0xf0,0xb5,0x6d,0xb7,0xde,0x6d,0xa5,0x7e,0x74,0xbb,0xb3,0x77,0x45,0x44,0xca, - 0x3a,0xed,0xf,0xc6,0xfa,0x9,0x2a,0x1f,0x92,0x5c,0x9a,0xd8,0xe,0x1,0xcd,0x20, - 0x72,0x4,0xd,0xa9,0xe2,0x7a,0x4f,0xe0,0x6e,0xb,0x14,0x65,0xd0,0x58,0xaf,0xb, - 0xc6,0xbf,0x51,0xc1,0x48,0x7c,0x61,0xda,0x58,0x7b,0x33,0x66,0xfc,0x1,0x6,0x6f, - 0x84,0x13,0x19,0x68,0xd,0xe8,0xc8,0xfa,0x73,0xdd,0x60,0x44,0x36,0x11,0xce,0x7c, - 0x50,0x21,0xbe,0x98,0x1d,0x20,0x73,0xf4,0x1b,0xa6,0x5b,0x18,0x27,0xe0,0x87,0xac, - 0x73,0x21,0x94,0x0,0x89,0x5d,0xfa,0xfc,0xba,0xda,0xc1,0x71,0x6b,0x90,0xed,0xbb, - 0x31,0xac,0x54,0xcd,0x4c,0x47,0xc2,0x68,0xed,0x1e,0x80,0x95,0x7e,0x88,0x42,0xf1, - 0x29,0x56,0x71,0xb2,0x33,0xeb,0x2f,0xee,0xc7,0xf0,0x60,0x33,0x82,0xcd,0x6f,0xb3, - 0x7b,0x43,0x82,0xc7,0x8b,0x45,0xaf,0xf8,0xe3,0xb0,0x8e,0xe1,0xb8,0x50,0x54,0xe1, - 0xa6,0xc5,0x14,0x5a,0xb2,0x43,0x49,0xf9,0x35,0x29,0xac,0xb7,0xf6,0x1c,0xea,0x72, - 0x60,0xec,0xba,0x6b,0xb2,0xe9,0x64,0x16,0x9a,0xf3,0xf7,0xd2,0xc3,0x4c,0xb4,0x6b, - 0x92,0xc8,0xc5,0xc4,0x8c,0x8e,0xbe,0xc1,0xb7,0xea,0xf8,0x2e,0x8,0xe3,0x21,0xe7, - 0x51,0x5b,0x53,0x4,0x45,0xb7,0x99,0x60,0x2b,0x91,0x33,0xef,0x5e,0x68,0xda,0x70, - 0xb0,0x20,0x35,0x3d,0x2e,0xf3,0x7e,0xe5,0xde,0x77,0x93,0x66,0xdb,0xb4,0xcd,0x2d, - 0x10,0xa0,0xb0,0xd5,0xd8,0x4a,0x36,0x4,0x5b,0xe8,0x73,0x39,0xd0,0x4e,0xa9,0x82, - 0xed,0xde,0x3f,0x1c,0x52,0xbe,0x81,0xb1,0xb5,0x16,0x18,0x91,0xca,0x66,0x3e,0xdb, - 0x7,0xee,0x31,0xdf,0xb8,0x67,0x64,0x94,0xcf,0xd7,0xcd,0xa1,0xa6,0x78,0xa3,0x14, - 0x57,0x62,0x31,0xaa,0x21,0xb2,0x5c,0x57,0x48,0xf3,0xe8,0x14,0xd9,0x28,0x6f,0xe1, - 0x96,0xa0,0x41,0xcf,0x87,0xa5,0x64,0x57,0xfd,0x32,0x78,0xa4,0xaa,0x1c,0xb8,0x3, - 0x7f,0x69,0x2d,0x20,0x9c,0x89,0x77,0xe4,0xfc,0x61,0xf8,0xd7,0x9,0xe7,0x39,0x1f, - 0x88,0x7a,0xee,0x8f,0xa0,0x53,0xe7,0x1e,0x6,0x60,0x42,0xb0,0xfc,0x7a,0x33,0x7c, - 0xe4,0x60,0x9c,0x81,0x69,0x94,0xe5,0x67,0xf5,0xdf,0xbe,0x7e,0x47,0x77,0x9d,0x50, - 0xf1,0xd,0xdf,0x12,0xdf,0x47,0x30,0xe5,0xa8,0x72,0x97,0x25,0xed,0xca,0xa1,0x52, - 0x2c,0xbd,0x53,0x15,0x52,0x39,0xfb,0xc7,0x19,0xba,0xc5,0xe0,0x32,0xe3,0x31,0xa4, - 0xf0,0x90,0x36,0xd0,0xd8,0x67,0xb7,0x1,0x59,0x4f,0x26,0xc6,0x99,0x47,0x19,0x45, - 0x5,0x6c,0x5b,0xd7,0xa6,0x57,0x1f,0x3f,0x92,0xe5,0x20,0xc4,0xc9,0xd0,0xe8,0xba, - 0x62,0x20,0xb,0x3b,0x7,0xc2,0x3c,0x60,0x91,0xe1,0x28,0x2c,0x29,0xc0,0xf0,0xad, - 0x2e,0x4c,0x85,0x54,0x24,0xa5,0x93,0xb6,0xb,0x34,0x7b,0xd4,0x84,0xe4,0xf,0xe6, - 0x5,0x1a,0xa1,0xc,0x5d,0x5d,0xeb,0xee,0x3f,0x14,0x9a,0x68,0x55,0x8c,0x96,0x3, - 0x58,0x1c,0x57,0x7c,0x41,0x6a,0x33,0xcb,0x1e,0x2f,0x20,0xa3,0x14,0x2f,0x8a,0x19, - 0xc9,0x2d,0xa4,0xa6,0x8a,0x90,0x15,0x4a,0x25,0xb0,0x32,0x7a,0xbc,0xc8,0x7d,0x15, - 0x65,0x54,0x12,0xa6,0xbe,0x45,0x73,0xdd,0x74,0x13,0x1,0x8,0x43,0x8b,0xa0,0x8c, - 0x38,0x45,0xb2,0x43,0xd6,0xc7,0x8d,0xfb,0xf7,0xbf,0xf5,0xb4,0x9,0xf2,0x4a,0x6e, - 0x47,0x5c,0x94,0x6,0x21,0x87,0x63,0x16,0x9b,0x64,0x1e,0x5e,0x70,0xbf,0x6a,0xa8, - 0x84,0x1d,0x6b,0x5b,0xe4,0xf8,0xd6,0x5d,0x39,0x4c,0x91,0x42,0x3f,0xdb,0x30,0x86, - 0xb7,0xc4,0xd,0x59,0x4d,0xef,0x6f,0xe8,0xd4,0xd,0xc6,0x45,0x4c,0x31,0x6d,0xd1, - 0x4e,0xd9,0xac,0xb2,0x52,0x4,0x8f,0x8b,0x50,0x22,0x4d,0x10,0x7d,0x7d,0x16,0x36, - 0xc2,0x23,0xf,0x8f,0x93,0x7e,0x78,0x68,0xb,0xbe,0xad,0x58,0xef,0x9a,0x2a,0xbd, - 0x74,0x56,0xef,0xc7,0x5a,0x80,0xd2,0x2b,0xa2,0xa0,0x3b,0x20,0x9d,0x51,0xd5,0xdf, - 0xf4,0xe4,0x6f,0x88,0xe2,0x67,0x70,0xee,0x26,0x1e,0xc6,0x16,0x38,0xf0,0x53,0xad, - 0xc6,0x44,0xf4,0xa1,0xc4,0x47,0xcc,0xe6,0x67,0x87,0x86,0x6,0x58,0x5d,0xe5,0xcc, - 0xc1,0x56,0xd4,0x25,0xbd,0x45,0x93,0x64,0x63,0x5a,0x7a,0x1c,0xca,0x4e,0xc9,0x91, - 0x92,0x3e,0x33,0xd6,0x5,0x7f,0xbd,0x6d,0x7,0x44,0xf2,0xdf,0x21,0x58,0xac,0xe3, - 0x2e,0x82,0x88,0x6c,0xc7,0x1c,0xd0,0xab,0xf5,0xca,0xc7,0xc0,0x19,0x11,0xd1,0xab, - 0x4f,0x6,0x2,0xd3,0x5,0xbf,0x41,0x8c,0x5,0x34,0x6c,0x26,0xd,0x19,0x89,0x3b, - 0x1b,0x91,0xa7,0x63,0xad,0xf7,0xf,0x23,0xc3,0x56,0xe3,0x5c,0x67,0xb6,0x88,0x36, - 0x3c,0x8a,0xa,0x41,0x4b,0xcb,0xcd,0xcf,0x7f,0xb9,0xf5,0x8c,0x53,0x0,0xc8,0x6e, - 0x91,0xef,0xd1,0xbf,0xe8,0x60,0xe2,0x2c,0xb6,0xc7,0x88,0x9d,0xfd,0x11,0x53,0xb9, - 0x9c,0xdd,0x7a,0xe7,0xa9,0xc8,0xb7,0x29,0x82,0x2d,0x36,0xd5,0xac,0xfe,0xc4,0x3f, - 0x6e,0x16,0xfe,0xd6,0x77,0x61,0x3,0xad,0xa8,0x8c,0xcb,0x26,0x1d,0x1f,0xdf,0xb9, - 0xfc,0x5b,0x21,0xa6,0xa3,0x58,0x50,0x26,0x6,0x86,0x7c,0xb2,0x5,0x41,0xf1,0xf2, - 0xd6,0x70,0xca,0x4e,0xd2,0x4d,0x7c,0xfa,0x59,0x48,0x22,0x77,0xe6,0x2,0x31,0xe4, - 0xdc,0xd2,0xb,0x80,0x2b,0x5b,0x27,0x31,0x61,0xa3,0xe4,0x66,0x64,0x56,0x5a,0x3b, - 0x47,0xa4,0xa,0x1a,0xf1,0x86,0x94,0x4c,0x4e,0xb6,0xc3,0x35,0x39,0x74,0x1a,0x16, - 0xc6,0xa5,0x17,0x72,0x80,0x3e,0x23,0xe2,0x61,0x87,0xc8,0x45,0xde,0xa2,0x80,0x26, - 0x47,0xa,0xbf,0x3a,0x10,0x54,0x6,0x5e,0xc,0x49,0x94,0x45,0x3d,0x2e,0xda,0x5, - 0x53,0x71,0x77,0xd4,0x2f,0x9a,0xb7,0x90,0x23,0x80,0x55,0x81,0x24,0x56,0xa7,0xea, - 0x60,0xe6,0xa4,0x71,0xba,0xaa,0x4f,0x46,0xf3,0x63,0x8b,0x32,0x12,0xe6,0xb6,0x65, - 0x58,0x2e,0x3a,0x8,0x48,0xf1,0x98,0x6b,0xf2,0x6e,0x6c,0x96,0xc4,0x93,0x81,0x25, - 0x7a,0x27,0x16,0x36,0x51,0x66,0x7c,0x46,0xc9,0x88,0xf7,0xdb,0xee,0xae,0xc1,0xc6, - 0x5c,0xfb,0xce,0xa4,0x6e,0xe7,0x90,0x61,0x56,0xfc,0x77,0x1b,0x91,0x78,0xbf,0x8b, - 0x9f,0x56,0x41,0x71,0xbc,0x3e,0x37,0x6,0xc6,0x2f,0x62,0x35,0x5d,0x24,0xfb,0x39, - 0x9f,0xcb,0xdd,0xe,0x33,0xed,0xee,0x89,0x6b,0x66,0x24,0xfc,0xdf,0x63,0x8,0xfe, - 0xb9,0x4a,0x70,0xf5,0x88,0xa7,0xfc,0xce,0x56,0xde,0x4,0x33,0x3,0x7f,0x6c,0xa2, - 0x4b,0xca,0x31,0xfd,0xb8,0x20,0x87,0x24,0x7,0x2b,0xa0,0x66,0x8f,0xa9,0xe4,0xc8, - 0x73,0x56,0xbf,0xfb,0x7d,0xbc,0x4a,0x54,0x1b,0x4e,0x87,0x9d,0xcd,0x74,0xbf,0x99, - 0x3f,0xf0,0x97,0xf7,0x91,0x9f,0x9c,0x98,0x4a,0x3d,0xfe,0x59,0x66,0x63,0x23,0xd9, - 0x39,0xe2,0x55,0xb7,0x1f,0x9f,0x8b,0x3a,0x6d,0x92,0xd7,0x3c,0x7,0x97,0x55,0xc5, - 0x89,0x6c,0x3e,0x1b,0x8b,0xda,0x33,0xd6,0x97,0xb1,0x30,0xfe,0x15,0x53,0x58,0x4f, - 0x36,0xae,0x86,0xd4,0xcd,0x91,0xf,0x3c,0x24,0x66,0xf7,0xab,0xfe,0x4d,0x71,0x8, - 0x39,0xaf,0xa2,0xc5,0xa,0x55,0x9c,0xa2,0x7,0x4c,0x21,0x9b,0x20,0xf8,0xea,0x56, - 0xa7,0xf0,0x2c,0x76,0x82,0xba,0x32,0x27,0x22,0x2a,0xd2,0xa0,0xf6,0x44,0x28,0x30, - 0x74,0xca,0xf5,0xfd,0x20,0x12,0xa0,0xa6,0xde,0x41,0x42,0xfe,0x3b,0xad,0xd4,0x62, - 0x1e,0x80,0x58,0xa1,0x3c,0x8a,0x48,0xdd,0xb4,0x1b,0x7e,0xab,0xde,0xa6,0x5c,0x53, - 0xf0,0xd1,0x52,0x90,0xe4,0x72,0x37,0x43,0x34,0xf8,0x42,0xee,0x26,0x17,0x51,0x45, - 0x98,0xaa,0x66,0x54,0x35,0xae,0x32,0x6a,0x49,0x30,0x95,0x28,0xd6,0xf1,0xfb,0x47, - 0xc4,0xcd,0xd7,0x29,0xbf,0x8e,0x6c,0xf3,0x7,0x2e,0x62,0xad,0x45,0xb4,0xf2,0xdd, - 0xde,0xd8,0x32,0x93,0x7,0xe3,0xfd,0xcf,0x14,0x14,0xf7,0x6a,0x6,0x73,0xb1,0x4a, - 0x41,0x9,0xf2,0x81,0x97,0xde,0xf4,0x1f,0xd,0x58,0xcc,0x53,0xd,0x3f,0xb0,0x6b, - 0x97,0x63,0xfe,0x1e,0x47,0x7d,0xed,0x5c,0x91,0x65,0xc6,0x17,0xd9,0xf8,0xe1,0x9a, - 0x2,0xd4,0x9b,0x1a,0xb4,0x91,0x39,0xc1,0xe9,0x85,0x94,0x76,0x44,0x46,0xe1,0xdb, - 0x29,0x60,0xf9,0x70,0xdd,0x67,0x4c,0xee,0xcc,0x14,0x7,0x26,0xd,0xe8,0x41,0x8e, - 0x3d,0xdc,0xa8,0x71,0xed,0x61,0xb3,0xd7,0xe6,0x48,0xcd,0x2b,0xe,0x2f,0x86,0x37, - 0x90,0x0,0xa8,0x6e,0x67,0x74,0x5e,0xb4,0x88,0xe4,0x5a,0x15,0x4d,0x9b,0xa4,0x8a, - 0xf8,0xcc,0x7c,0xe6,0x2f,0x30,0x3f,0x95,0x78,0xd,0xc1,0x7,0x3d,0xc7,0x3e,0x4d, - 0xc8,0x66,0xbb,0xaf,0xdb,0x99,0x64,0xe3,0xfd,0xbf,0x79,0x4b,0xda,0x1e,0x56,0x53, - 0xea,0xd2,0x3b,0x99,0x3,0xf9,0x30,0xfa,0x86,0x71,0x2,0xc3,0x39,0xc0,0x90,0x81, - 0xa6,0xcc,0x32,0x2,0x66,0x16,0x66,0x65,0x55,0xdf,0x30,0x31,0x7d,0x86,0x4,0xe7, - 0x59,0xbe,0x82,0xdb,0xb8,0x32,0xd7,0x40,0xa3,0x59,0x83,0x5c,0x99,0x15,0xde,0xc0, - 0xe1,0x90,0x42,0xc7,0xa6,0x28,0xac,0xfc,0x8,0xdd,0xad,0x5,0xe3,0xb1,0xed,0xbd, - 0x71,0xef,0x99,0xa9,0xa1,0xf0,0x69,0x45,0xca,0xed,0x21,0xe3,0x82,0x0,0x24,0x64, - 0x90,0xe6,0xab,0x38,0xf,0x59,0xb4,0x97,0xb6,0x62,0x9c,0x9a,0x14,0xa,0xd7,0x5, - 0xf9,0x72,0xaf,0x9b,0xe2,0x19,0x60,0xad,0x86,0x82,0x12,0x9,0x2,0x36,0xec,0x13, - 0x1d,0x19,0xca,0x2d,0xf1,0x7f,0x44,0xa8,0xe1,0xe0,0xc2,0x75,0xeb,0x9b,0xfa,0x65, - 0x8d,0xaa,0x81,0x70,0x43,0xe1,0x9e,0x4a,0xe3,0xb0,0xd2,0x66,0x66,0x40,0x79,0x84, - 0x59,0x44,0x31,0x4b,0x43,0x75,0x73,0x25,0xd5,0x36,0x1a,0xc1,0x51,0x15,0xa7,0xde, - 0x3f,0x29,0x50,0x3,0x8a,0xee,0x4d,0x6f,0x1f,0x9f,0x55,0x85,0xdf,0xce,0x89,0xb8, - 0x92,0x3a,0x83,0xd5,0x2f,0xf6,0x7a,0x6,0xad,0x94,0x47,0xfe,0xaa,0xee,0xde,0xe9, - 0x18,0xae,0x6c,0x23,0x1d,0x39,0x12,0x3c,0xd9,0x67,0xc1,0x39,0x36,0x4c,0x72,0xc8, - 0x6,0xf5,0x1e,0x36,0x6d,0x98,0x3c,0x9a,0x2d,0x83,0x99,0x57,0xf2,0xf7,0xc1,0x8a, - 0x26,0x2e,0xad,0x43,0x68,0xbf,0x7f,0xc1,0x27,0xc1,0x7a,0xdc,0x8d,0xec,0x25,0x93, - 0x63,0x43,0xc9,0x50,0x5b,0x85,0xea,0x89,0xa,0x84,0xe0,0x7c,0xfc,0x22,0x7,0x23, - 0x51,0xb5,0xe6,0x39,0xf4,0x66,0xfa,0x9c,0xa7,0xf4,0xf8,0x35,0x62,0x1f,0xc9,0xc5, - 0xe1,0x93,0x16,0x3e,0x1a,0x1,0x47,0xa3,0x5,0xa7,0x9f,0x81,0xca,0xa6,0x25,0x1c, - 0xdb,0xc,0xd4,0x51,0xf1,0x4f,0xed,0x9a,0x44,0xe6,0x4f,0xa6,0x85,0x19,0x6c,0xe7, - 0x2d,0x2,0x26,0xc6,0x82,0x6d,0xe9,0x8,0x15,0x89,0x89,0x5f,0xaf,0xae,0x7b,0x8c, - 0x3a,0x50,0xdd,0x2d,0x1f,0x4b,0x47,0x64,0xb1,0x96,0xb,0x38,0x30,0xf7,0x9f,0x5d, - 0x79,0xc5,0xa3,0x7c,0xb2,0x8d,0x84,0x47,0x96,0xe,0xa7,0x46,0x3d,0xa2,0xd2,0xf6, - 0x73,0x30,0x24,0x92,0x7b,0xea,0x76,0xad,0x82,0x82,0x65,0x32,0xf9,0x5,0x8f,0xf2, - 0x4a,0xb2,0x6f,0xfc,0xbf,0xf3,0xc3,0x56,0x82,0xea,0x9c,0x3f,0x8e,0xef,0x36,0x81, - 0x9f,0xda,0x14,0x9b,0xc5,0x8b,0x49,0xc7,0x8d,0xae,0xf9,0x7,0xb3,0x9,0x79,0x7d, - 0xbb,0xe9,0x7a,0x7b,0x5d,0xbd,0x51,0xdf,0xa9,0x6e,0x9e,0xb7,0x5e,0xd5,0xb8,0x7d, - 0xb0,0x4c,0x19,0xf5,0xd7,0x62,0xbe,0xe4,0x90,0x38,0x6b,0xc3,0x42,0xe5,0x41,0x7d, - 0x4f,0x3b,0x79,0xac,0xf9,0xca,0xd,0x23,0x39,0x2b,0x5a,0x17,0x1,0x13,0x95,0x31, - 0x5f,0xae,0x28,0xb7,0x91,0x66,0x1c,0x22,0x9e,0x88,0x66,0x60,0xed,0xa7,0xde,0xbc, - 0x63,0x58,0xe8,0xdc,0xa2,0xf5,0x0,0xdc,0x22,0xd9,0xf3,0xa2,0xec,0x89,0x54,0xcb, - 0xb8,0x7c,0x83,0x4a,0x62,0xa0,0xeb,0x80,0xa8,0x52,0xe1,0x16,0x7a,0x40,0xd2,0x5d, - 0x18,0xbb,0x3a,0x3a,0x32,0xb9,0x17,0xd3,0x93,0x8b,0x76,0x0,0x94,0xca,0xcb,0x4d, - 0xc6,0x50,0x17,0xa8,0x70,0x4,0x2a,0x98,0xd5,0x8b,0xae,0xcf,0x4b,0x1,0xac,0x63, - 0xbc,0xe6,0x9d,0x6e,0xa0,0x35,0x42,0xb3,0x40,0x39,0xb3,0xd4,0x83,0x80,0x23,0x4b, - 0x50,0xb9,0x73,0x40,0x3d,0x9d,0xd8,0x93,0x29,0x7,0x63,0x74,0x8,0x90,0x57,0x44, - 0x77,0x75,0xb3,0x98,0x2a,0xf5,0x4c,0x6a,0x2f,0x1,0x3f,0x33,0x1,0xe1,0xfd,0x51, - 0x1c,0x71,0x11,0x59,0x10,0xe9,0xec,0xb8,0xf0,0xd0,0xad,0xf8,0x61,0x84,0x3d,0x58, - 0xf9,0xf0,0xf0,0xa3,0x67,0x3e,0xe,0x16,0xbe,0xcd,0x49,0x3f,0x2f,0x47,0x90,0x4b, - 0x39,0xa1,0x25,0x49,0xb,0x12,0x81,0xfb,0x62,0x2f,0x74,0x43,0xb4,0x31,0x9c,0x2e, - 0xa2,0x8d,0xd2,0x89,0x4b,0x60,0x9f,0x89,0x2e,0x69,0xc8,0xdd,0xb0,0xd8,0xa8,0x69, - 0xf9,0xcd,0xb2,0x5,0x60,0x35,0x80,0xc2,0xe3,0x74,0x86,0x18,0xa6,0x23,0x47,0xc8, - 0x30,0x1a,0x52,0xfb,0x7a,0x71,0x85,0x29,0xda,0x4f,0x86,0xc,0xa7,0x2f,0x75,0xa2, - 0xfd,0xa8,0x27,0x5e,0x5d,0xa8,0xa0,0x41,0x9c,0x27,0x5a,0xc2,0x4a,0xa1,0x8b,0xfa, - 0x3b,0x5d,0xf6,0x35,0xcf,0x7c,0xdd,0xaa,0x4b,0x64,0xb6,0xf3,0x94,0xac,0x16,0x12, - 0x55,0x3d,0x70,0xb2,0xe5,0x90,0xf3,0x3,0xb8,0xcd,0xc5,0x82,0xee,0x52,0xfc,0x2a, - 0xaf,0xf3,0xdf,0xfe,0xf0,0xbd,0xaa,0x3c,0xa2,0xe0,0xaf,0xb6,0x8d,0xc5,0xc8,0xe2, - 0x4,0xb8,0x15,0x69,0x49,0x89,0x6c,0x81,0x57,0x33,0x84,0x47,0x5,0x81,0xf0,0x34, - 0x76,0x50,0x34,0x67,0x8e,0x5e,0x23,0x31,0x3f,0xd3,0xe7,0x4d,0x99,0xb0,0x30,0x9d, - 0x69,0xc5,0x87,0x32,0x4f,0xf3,0xb4,0xa6,0xa6,0x39,0x6d,0x2b,0xba,0xde,0x60,0xb0, - 0x2f,0x14,0x18,0xbd,0x72,0x3c,0x6e,0xb1,0x8f,0x56,0x7e,0x29,0x86,0x2f,0x47,0x6f, - 0xf4,0xce,0xa2,0x44,0x42,0xd6,0xea,0x69,0x8f,0xd8,0x94,0x4a,0xb7,0x74,0x7b,0x66, - 0x88,0x13,0x25,0xfa,0xce,0x93,0x2d,0x5e,0x6a,0xab,0x8,0x70,0xda,0x4f,0x60,0x4f, - 0x9d,0x82,0x93,0x5f,0x59,0xfe,0xc8,0xe8,0xd7,0xdd,0xb2,0xf,0x52,0xad,0x75,0xdb, - 0xc1,0x9a,0x56,0x90,0xae,0x83,0xef,0x98,0xaf,0xf7,0x88,0xa,0xc6,0xe8,0x5a,0x64, - 0x6b,0x6d,0x43,0x44,0x6c,0xd,0x2d,0x44,0x6a,0x60,0x53,0xbc,0xe,0x49,0x18,0xcf, - 0xe3,0x6f,0xe0,0x12,0x72,0xd0,0x2a,0xa1,0x48,0xb3,0xac,0xf,0x1c,0x86,0xf2,0x88, - 0xf3,0x36,0xcc,0xe0,0xc2,0x7a,0x25,0x2d,0xda,0xf8,0x6a,0x68,0xc1,0x82,0xb8,0xa5, - 0x71,0x99,0x38,0xe4,0xe9,0xe1,0x6,0x32,0x95,0xb2,0xc0,0xb2,0xb8,0xb3,0xba,0x2d, - 0x69,0x87,0xe,0x2d,0x2,0xb2,0xd9,0x5c,0x2b,0xc3,0x45,0xec,0x47,0x7d,0x13,0xb8, - 0x17,0xca,0x1d,0x80,0xac,0x24,0xb2,0xc2,0x56,0x73,0xf4,0x8f,0xa6,0xaf,0xbc,0x10, - 0xb6,0x4a,0xbc,0x39,0xfc,0x17,0x95,0x29,0xda,0x5a,0x95,0x22,0xd7,0xa8,0x5b,0x6e, - 0x73,0xf7,0xee,0xa0,0x9b,0x21,0x63,0xf2,0x14,0x58,0x2,0xba,0x87,0xbe,0x4b,0x3e, - 0x9,0x87,0x77,0x85,0x9e,0x8d,0x2e,0x7a,0xe7,0xc4,0x1c,0x40,0xec,0xf6,0xae,0xe0, - 0x6f,0x9e,0x81,0xb,0xbf,0x64,0x7d,0x54,0xbc,0x7f,0xf,0xc3,0x3e,0xd9,0x2,0xc6, - 0x62,0x7a,0x4d,0x1,0x8,0x7b,0xfa,0x6f,0xbf,0x97,0xaf,0xad,0xe,0x5f,0x8e,0x7d, - 0x7d,0x10,0x89,0xbc,0xf3,0x7,0x11,0x30,0x87,0xa0,0xf3,0x45,0x7a,0xf5,0x8c,0x5c, - 0xef,0xd9,0xdd,0x77,0xd4,0xd8,0xe7,0x95,0xef,0x97,0x43,0xfe,0x76,0x51,0x7c,0xf3, - 0x61,0x6,0x31,0xd4,0x8d,0x42,0x5,0x94,0xe2,0xf8,0xd9,0xdd,0xee,0x66,0x3a,0x5f, - 0xbf,0x18,0xd6,0x95,0x71,0xbe,0xaa,0x61,0xd6,0x6d,0x60,0x4d,0xbe,0x5d,0xc1,0x9f, - 0xe2,0x72,0x74,0x70,0xb4,0x79,0x5,0x18,0x72,0x5f,0x75,0xe0,0x45,0xaf,0x40,0x6, - 0x48,0x18,0x1b,0xb9,0xd6,0x45,0x9a,0x2d,0xb2,0x7b,0xfa,0x71,0xd8,0xbc,0x11,0xbb, - 0xae,0x85,0xac,0x63,0xfe,0xb1,0xfa,0xf0,0x90,0x70,0xd1,0xd6,0xa0,0x13,0x5c,0x68, - 0xaa,0xf6,0x22,0x1,0x3c,0x3c,0x2f,0xee,0xb7,0x2a,0xdf,0x90,0x66,0xf0,0xcc,0x15, - 0x76,0x79,0xf7,0xf4,0xaa,0x73,0xe5,0x3c,0x63,0x37,0x92,0x4,0x4a,0x6e,0x6c,0x74, - 0xe4,0xe,0x76,0x21,0xca,0xa5,0x8f,0x82,0x4f,0x6f,0x93,0xb5,0xdf,0x60,0x4a,0xd5, - 0xd9,0x42,0xca,0x84,0xb5,0x30,0x40,0x1a,0x67,0xd2,0x9d,0x32,0xc0,0x8a,0xa6,0xa5, - 0x18,0x1d,0x46,0xe2,0x42,0x55,0xe5,0x91,0xc4,0x79,0xc6,0x24,0xd9,0x11,0xf9,0xb3, - 0xd3,0xc4,0xb7,0x89,0xf4,0xf8,0x23,0x5d,0x4b,0xc1,0xf,0x8c,0xcb,0xb5,0xb1,0xe3, - 0xd3,0xf8,0xc7,0x95,0x4e,0xad,0x28,0x93,0xa6,0x6e,0xb7,0x80,0x80,0x32,0xb3,0x54, - 0xf6,0xea,0x5d,0x6c,0xe3,0x81,0x49,0xaf,0xc2,0x58,0xbb,0x8e,0xe,0x6d,0xf1,0x61, - 0x66,0xb9,0xf7,0x35,0xe6,0x9f,0x48,0x8d,0x8d,0x0,0x8d,0xe,0xb1,0xc0,0xe1,0xa9, - 0xac,0xbf,0x95,0x10,0xc0,0x5e,0xbf,0x3,0xb6,0xfa,0x91,0x44,0x69,0x83,0x26,0xcf, - 0xbd,0x9d,0x84,0x24,0x3d,0xcc,0x32,0x4a,0x4d,0x3f,0xd8,0xfe,0x1,0xba,0x28,0xad, - 0xf9,0xbd,0xbd,0xba,0x1c,0xfd,0x3d,0x52,0xf8,0xce,0x17,0x62,0xd2,0x3d,0xb2,0x10, - 0xda,0x37,0xb3,0x97,0x5,0x65,0xe1,0x52,0xa5,0xba,0x51,0x26,0xf5,0x7a,0xd3,0x6f, - 0xb7,0x11,0x2b,0x54,0x8e,0x68,0xa6,0x8,0xb7,0xbd,0xe9,0xa,0x7a,0x1c,0x99,0x55, - 0x54,0x4d,0xec,0xd8,0x33,0x4f,0xaa,0xd8,0x89,0x7b,0xfe,0x7f,0x75,0x52,0xef,0x2e, - 0xe2,0x9a,0x82,0xf1,0x82,0xa8,0xf9,0xb9,0xe6,0x63,0x43,0x61,0x80,0xdc,0x37,0xd4, - 0xaa,0xa3,0x2d,0xdd,0xf2,0xd7,0xb6,0x7d,0x53,0x35,0x7c,0xc9,0x7,0x6c,0x77,0x69, - 0x86,0x79,0x5b,0xa,0xa1,0xd4,0x43,0x88,0x39,0x87,0x6a,0xb9,0x64,0x21,0xe,0xf, - 0xc4,0x3b,0x6c,0xb8,0x92,0x23,0xb5,0x65,0xd7,0x32,0xae,0x5e,0x1f,0x26,0xc8,0x25, - 0x1f,0xa3,0x2f,0xc1,0x79,0xf2,0xc9,0xb2,0x7a,0xb3,0xeb,0x5e,0xd4,0xf9,0xed,0x9a, - 0xb4,0x5a,0xd2,0xc6,0xfd,0x88,0x2c,0x55,0x3a,0xdb,0xb4,0xd8,0x81,0xfc,0xfe,0xa1, - 0xa0,0xad,0x63,0x1a,0xa0,0xac,0x4c,0x9a,0x61,0x38,0xf9,0x36,0xb1,0x67,0xd0,0xe5, - 0xc1,0xa3,0xac,0xbf,0xab,0x59,0x16,0x66,0x35,0xca,0x3f,0xb6,0x47,0xbd,0x58,0xe7, - 0x6c,0x3b,0x3,0x8c,0xe8,0xce,0x28,0x4a,0x8,0xa1,0x0,0x39,0x9,0x51,0x9f,0x4a, - 0x74,0x4c,0xb,0x21,0xa5,0xa0,0x7,0x5a,0xea,0xc5,0x91,0x32,0x84,0x69,0x1a,0x70, - 0xa5,0x9c,0xfc,0xe,0x6c,0xa4,0xd7,0x74,0xc5,0xd7,0x2d,0x4e,0x29,0xcc,0x99,0x9e, - 0x99,0xa4,0x3f,0xbe,0xc4,0xc5,0x1a,0xaf,0x8b,0xab,0xe1,0x10,0x15,0xfb,0x0,0x3a, - 0x99,0x7d,0xc7,0x6,0x22,0x9f,0xf9,0xe8,0xf7,0xa6,0xb6,0xa0,0x74,0x50,0x3f,0xe, - 0x74,0xfd,0xcc,0x39,0xc3,0x66,0xe8,0x50,0x91,0xca,0xdf,0x27,0x47,0x60,0x61,0xe0, - 0xdd,0x2a,0x66,0x0,0x49,0xdf,0x68,0x41,0x86,0x20,0xe2,0xfa,0x70,0xa1,0x88,0x65, - 0xa0,0xd5,0x9e,0xe3,0x3c,0x88,0xb3,0xce,0x53,0x94,0xf5,0x1a,0xf4,0xd6,0xfa,0x52, - 0x80,0xe0,0x52,0xca,0xc0,0x3b,0x8b,0x48,0xda,0x6e,0xc2,0xca,0x90,0x4c,0x30,0xb0, - 0xa1,0xcf,0x94,0xdd,0x58,0x49,0x2c,0x2b,0x5d,0x22,0x46,0xd1,0x79,0xc0,0x24,0xf9, - 0xa2,0xf5,0xc4,0xe2,0x31,0xd0,0xaa,0xc,0xbe,0x6e,0x57,0x4f,0x3a,0x87,0x0,0x5b, - 0x57,0x15,0x39,0x2f,0x5e,0x66,0x5b,0x3b,0x8,0xa1,0x8c,0x81,0x62,0xb0,0x7c,0x84, - 0xa6,0xc0,0xe7,0x58,0x11,0x92,0xe3,0xd0,0x80,0x3b,0x20,0x3a,0x43,0xa0,0x95,0x9a, - 0x35,0x4f,0xca,0x13,0xb5,0x26,0x4e,0xbd,0x47,0xda,0xbf,0x29,0xb,0xbb,0x2e,0x31, - 0xfb,0x16,0x89,0xe,0xa8,0xed,0xde,0xa9,0xa8,0x7e,0xe3,0xeb,0x9e,0xf9,0x87,0xd3, - 0x49,0xd1,0xe6,0xfe,0x77,0xb4,0x3c,0x3e,0x8f,0x7b,0x67,0x1a,0x37,0x15,0x4c,0x34, - 0x2b,0x55,0x42,0x54,0x43,0xa0,0x7d,0xec,0x1f,0xe0,0x58,0xbe,0xda,0x5f,0x12,0x24, - 0x31,0xf9,0xa2,0x28,0x2e,0x5f,0x66,0x3e,0x5a,0x4e,0x58,0x92,0x63,0xa4,0x46,0xf, - 0x7a,0x8,0xe2,0xbd,0xa8,0x60,0x2a,0x47,0x41,0x83,0x85,0x1d,0x62,0x98,0xc0,0x14, - 0x12,0xe3,0x3c,0x40,0xc2,0x23,0xfd,0x1d,0x71,0x57,0x2f,0x54,0x7b,0x75,0xe2,0xf5, - 0x7d,0xc5,0x34,0xa5,0x26,0x5e,0xed,0xe7,0x61,0x73,0x84,0xc4,0x8b,0xc4,0xd8,0x1d, - 0xa8,0x94,0x5e,0x6b,0xb7,0x5c,0x9,0xa8,0x33,0x38,0xfd,0xaf,0xae,0xe0,0x25,0xab, - 0x27,0x59,0xd1,0xcc,0x38,0xbf,0xb4,0x99,0xb2,0xb8,0xdd,0xbe,0x7e,0x36,0xdb,0xa6, - 0xcb,0xb9,0x92,0x3,0x96,0x9b,0xac,0xc9,0xd3,0x2a,0xf8,0x2,0x8a,0x1f,0xae,0xb1, - 0xf7,0x0,0xfe,0x30,0xbf,0x33,0xca,0xf1,0xec,0x28,0x30,0xea,0xde,0xd,0x91,0x2a, - 0x46,0x24,0x2d,0xdc,0xbf,0x59,0x27,0x14,0x83,0x9f,0x16,0x8e,0x3e,0x44,0xbf,0x37, - 0x44,0xbe,0x67,0x83,0xf2,0xb1,0x76,0x5f,0x5a,0xa6,0x4a,0x39,0x33,0xdb,0x63,0x7a, - 0x1,0x90,0xd6,0x40,0x6a,0xfd,0x54,0xed,0x9e,0x6b,0x7c,0x5c,0xaf,0x3d,0x93,0x74, - 0x7b,0x7b,0xf7,0x6e,0xac,0xed,0x4d,0x7,0x95,0x97,0xbf,0x48,0x74,0x23,0xc2,0xf4, - 0x34,0x9a,0xb4,0x9e,0x18,0xa,0xc,0x36,0xf4,0x9,0x93,0xa4,0xc5,0xa6,0x98,0x41, - 0xa1,0x91,0x30,0x4f,0x7f,0x7d,0xd5,0x94,0x95,0x96,0xdd,0x89,0xb9,0x20,0x7e,0x6d, - 0x3a,0x33,0xc,0x53,0xbc,0x98,0x9,0xb1,0xa1,0x1c,0xd6,0x67,0xc3,0x6f,0x28,0x65, - 0x1,0xd7,0x34,0x1,0x56,0xb,0x95,0x6b,0xa1,0xf2,0xf4,0xda,0x93,0xf2,0x49,0xcd, - 0x26,0xd4,0xa0,0x63,0xec,0xaa,0x15,0x8e,0xc6,0xeb,0x75,0xa,0xdb,0x1e,0xef,0xdc, - 0xf5,0x24,0x5d,0xcb,0xae,0x73,0x37,0xcf,0x66,0x2c,0xab,0xf9,0x1f,0x74,0x48,0xc5, - 0xc8,0xe8,0xa8,0xb6,0x93,0xbd,0xc4,0xda,0x2a,0xba,0xe4,0x6,0xd8,0xd4,0x62,0x4e, - 0xf9,0x40,0x1b,0x28,0xb3,0xd1,0xf8,0x99,0x7e,0x24,0x94,0x9d,0x18,0x5c,0xe2,0xe0, - 0x45,0xb,0x17,0x59,0xc9,0x5c,0x34,0x73,0x17,0x19,0xf8,0x6f,0xee,0x5b,0xbd,0x68, - 0x1b,0xd8,0x90,0xce,0xab,0x9,0x69,0xa9,0x2d,0x7d,0xc6,0x45,0xd9,0xaa,0xa6,0x1f, - 0xb5,0x3d,0x78,0xfe,0x99,0xac,0xf1,0x30,0x46,0xea,0x9f,0xb4,0xc6,0x5e,0x1d,0xe1, - 0xb6,0x2d,0xb1,0xe1,0xb6,0x9a,0x8b,0xe3,0x18,0x53,0xa9,0xf1,0x7d,0xcf,0x90,0xb2, - 0xd,0xa,0xb2,0x27,0x36,0x24,0x57,0x7c,0x10,0xf7,0xb0,0xd6,0xd5,0xcd,0x38,0x8c, - 0x7b,0x69,0x6f,0x32,0x4,0xfa,0x95,0x1c,0xcd,0xbe,0x8d,0x4b,0x8e,0x1f,0xfe,0x1c, - 0xa8,0xb1,0x43,0x5e,0x55,0x1a,0x5b,0x65,0x91,0xc,0xbb,0x67,0x5a,0x74,0xf4,0xd5, - 0xdd,0xe3,0x87,0xe2,0x5e,0x9c,0x7e,0x2d,0x5c,0x8c,0x78,0x6a,0xab,0x77,0x6,0xd3, - 0xa8,0x49,0x32,0xfe,0xe3,0x8d,0xe3,0x75,0x9a,0xa0,0x5d,0xf4,0x15,0xd1,0x4a,0x72, - 0xb5,0x51,0xd4,0x93,0xed,0x54,0xc0,0xc9,0xe0,0xb9,0xb4,0xc,0xb0,0xba,0x5f,0x5a, - 0x84,0x91,0xd8,0x68,0x9f,0xbc,0x5d,0x3a,0xdc,0xba,0xae,0x71,0x8c,0xf8,0x64,0xc1, - 0xc9,0x39,0x56,0x37,0x8d,0x96,0x81,0xed,0x50,0x36,0x79,0x2,0x70,0xd8,0xdb,0xf4, - 0x6b,0x34,0xdc,0xb,0xf0,0xba,0xc4,0x4e,0x75,0x73,0x3f,0x82,0xeb,0xa3,0xc3,0xb5, - 0xdd,0x99,0xec,0xea,0x31,0x6e,0xd9,0x1,0x24,0x53,0x82,0x95,0xac,0xdd,0xa,0x18, - 0x12,0xe7,0xa2,0x83,0xa2,0x67,0x51,0x97,0x5a,0x90,0x99,0x46,0xb4,0xdd,0xfb,0x92, - 0x77,0x68,0x7d,0x28,0xd7,0xd6,0xa9,0xfb,0xaa,0xab,0x11,0x57,0x8a,0x1c,0xee,0x1c, - 0x83,0x11,0x9f,0x26,0x78,0xf0,0x3d,0x52,0x2,0x57,0x98,0xb6,0x35,0x14,0xc8,0xac, - 0xfb,0xc5,0x55,0xd3,0x9d,0xfe,0x50,0xc7,0xaa,0x61,0x9e,0xb4,0xfc,0xd,0xd1,0x80, - 0x1e,0xf0,0x26,0x16,0xe2,0xe3,0x68,0x64,0x3b,0x80,0x1b,0xef,0x14,0x63,0x9c,0x10, - 0x29,0x71,0x64,0x46,0xef,0x34,0x8d,0x1b,0x15,0x2c,0xcf,0x13,0xb8,0x21,0x93,0xd6, - 0x13,0x3a,0x6c,0x75,0x1e,0xd4,0xd9,0x59,0xd4,0x74,0x49,0x68,0xd7,0x65,0xf8,0x1, - 0x57,0x5d,0xc7,0x47,0x11,0x55,0x62,0x26,0x82,0x33,0xb8,0x3b,0x54,0xcc,0x92,0xe6, - 0x7,0xfe,0x5c,0x25,0x54,0x36,0xfd,0xa8,0x2a,0xc6,0x12,0x2,0xab,0xb,0x83,0x3, - 0xe7,0x4b,0x4b,0xf8,0xa0,0xad,0x9e,0xa2,0x60,0x58,0x5e,0x35,0xa4,0xf0,0x1c,0xab, - 0x6f,0x79,0x50,0xc3,0x2f,0xcd,0x6d,0x5a,0x94,0xfe,0xdb,0x40,0xa,0x5f,0x44,0x71, - 0x2a,0xf,0x6a,0xcb,0x3c,0x88,0x6e,0x9d,0x60,0xcc,0x52,0x5,0x3d,0x6e,0x30,0xad, - 0x67,0x80,0xf0,0x17,0xcd,0x5e,0xf0,0x62,0x5d,0xcc,0x23,0xe6,0xac,0xe6,0x58,0xd6, - 0xf5,0x42,0xa2,0x32,0x4b,0x91,0x4f,0xab,0xdd,0xa1,0x31,0x9b,0x90,0x61,0x49,0x77, - 0x62,0x3a,0x8e,0x30,0x19,0xfe,0x13,0xf5,0xcc,0x36,0x5d,0x79,0x1d,0xb5,0x50,0x13, - 0x78,0x73,0xc4,0xc3,0x84,0x94,0xee,0x62,0x36,0x20,0xfd,0x46,0x2,0xc6,0xbe,0x64, - 0x2,0xcc,0x14,0x9a,0x4c,0x27,0x90,0x19,0x5d,0xed,0x12,0xf9,0x24,0xe1,0x8c,0x1c, - 0xd4,0x52,0x5f,0x59,0xe6,0x4e,0xbc,0x9c,0xee,0x3a,0xe3,0xf0,0x2,0x22,0xd4,0x83, - 0x6e,0xe8,0x9d,0xba,0x90,0x2e,0x53,0x6d,0x9c,0xe4,0x68,0x40,0xc7,0xf4,0x5c,0x9c, - 0xc6,0xbb,0xf6,0xad,0x89,0x33,0xca,0x78,0x6d,0x2e,0x69,0xee,0xcf,0x3e,0xf1,0x3e, - 0xa7,0x8f,0x79,0x38,0x3e,0x4c,0xa5,0xda,0x32,0xe,0x1b,0xf9,0x83,0xf6,0x16,0x4a, - 0xb2,0xd,0x78,0xbb,0xbf,0x43,0x35,0xad,0x71,0x9e,0x1c,0x41,0x5d,0xf,0xfe,0x84, - 0x9e,0xf7,0x3c,0x5c,0x45,0xe1,0x37,0x77,0x70,0xd1,0xf0,0x73,0x48,0x7,0xbd,0x7a, - 0x94,0x36,0x37,0xd3,0xf8,0x6c,0x81,0x6a,0x8a,0x9e,0xab,0x67,0xad,0x2b,0xeb,0xcb, - 0x23,0x28,0x29,0x68,0x8a,0xdf,0x5f,0x7a,0x32,0x50,0xed,0x7a,0xd7,0x2b,0xf5,0xeb, - 0xe1,0x2d,0xbf,0xda,0x19,0x42,0x46,0xa3,0x60,0x71,0xc,0x8d,0x9c,0x77,0x59,0x40, - 0x20,0x2,0xa8,0x2a,0x62,0x88,0x24,0x94,0xd8,0x91,0x8e,0x30,0xbc,0x4,0x1c,0x1e, - 0x31,0xdc,0xf9,0xc9,0x9e,0xbf,0x6e,0xfe,0xb0,0xf9,0x8c,0xcd,0xf0,0x65,0xe,0x90, - 0xe7,0x36,0xba,0x4a,0xbe,0xde,0x5e,0x18,0xef,0xec,0x48,0x2d,0x71,0xe4,0x4b,0x22, - 0xc1,0xc4,0xec,0xdf,0x84,0x5b,0xde,0xb5,0xd4,0x6b,0x83,0xc5,0x50,0x91,0x57,0x38, - 0xc7,0x91,0x2,0x87,0xf0,0x60,0x9f,0xe0,0xcd,0x67,0xe,0x3f,0x4c,0xd9,0x61,0x8d, - 0x9e,0x4e,0x6d,0xa3,0x29,0x4c,0x59,0x7d,0x37,0xdc,0xc3,0x88,0xed,0x1b,0xc0,0x35, - 0x2c,0x43,0x3c,0x1d,0xa3,0xdb,0x7e,0xf0,0xc3,0xc,0xaf,0x10,0xe5,0x12,0x9e,0x5, - 0xdf,0xc,0xa8,0x89,0x59,0x81,0x7,0x10,0xdd,0xca,0x98,0xcb,0x65,0xd9,0x80,0x12, - 0x1d,0xbd,0xae,0x40,0x99,0x2d,0x32,0xdc,0xb9,0xe1,0xed,0x1f,0x73,0x8c,0x24,0xd3, - 0x18,0x4c,0xdc,0xf0,0xcd,0xe3,0x2,0xab,0x2f,0x9a,0xf6,0x14,0xf3,0x78,0x26,0x90, - 0x36,0x55,0xd1,0x4f,0x2,0x83,0x2d,0xbb,0xe4,0x1b,0xdb,0xd8,0x27,0x7f,0x2c,0x3f, - 0xcc,0x9,0x31,0x9a,0x6c,0xb2,0xc6,0x9b,0xcc,0xbd,0x30,0xc1,0x36,0xd5,0x52,0x6c, - 0x2b,0xa3,0xbc,0x2e,0xa6,0x69,0x69,0x8c,0x84,0xc4,0xe4,0xab,0x45,0x11,0x6a,0x91, - 0x1a,0x1b,0x2c,0x86,0xcd,0xf2,0xa2,0x9b,0x31,0x52,0xdc,0x67,0x28,0xae,0x54,0xd3, - 0xd2,0x90,0x81,0x79,0xf9,0xea,0x85,0x7e,0xb0,0x6a,0xa9,0x75,0xfa,0x93,0x7,0x15, - 0xaf,0xb2,0x1c,0xfc,0x26,0x3e,0x18,0x57,0x90,0xf4,0x3e,0x38,0x24,0x92,0x8b,0xf6, - 0xa2,0xd,0x70,0x9c,0x78,0xf6,0x9a,0xa8,0xe0,0xc3,0x1e,0xdc,0xd7,0xa4,0x71,0x7, - 0x57,0x8d,0x4,0x7d,0x4b,0x1d,0x54,0x5b,0x91,0x93,0x94,0xb5,0xa5,0x20,0x2c,0xc8, - 0xad,0x9d,0x65,0x26,0x14,0x80,0xce,0x74,0xc3,0xec,0x51,0x9b,0x11,0xc3,0xa2,0x68, - 0xd0,0x27,0x66,0x9c,0xc3,0xba,0xf7,0x55,0xcd,0xc,0x8b,0xf3,0x2d,0xb7,0xbc,0x5a, - 0xd4,0xa1,0x80,0x68,0x22,0x4f,0xdd,0x66,0xbb,0x2f,0x2,0xcc,0x72,0x25,0xb4,0xc3, - 0x4c,0x1b,0x60,0x8f,0xd6,0x58,0x64,0x24,0x65,0xef,0x18,0x12,0x28,0xd4,0x6c,0xfc, - 0x77,0x6c,0x66,0x19,0x3b,0xc3,0x7f,0xf6,0xf2,0x2,0x43,0xe5,0xa6,0xf7,0x29,0xf2, - 0x14,0x89,0x2,0x6a,0x61,0x66,0xe,0x46,0xd6,0x27,0xd7,0xfe,0xfb,0xc3,0x7b,0xf2, - 0x30,0x61,0x8c,0x6b,0x25,0x8b,0xe1,0x98,0x8d,0x25,0xfd,0x34,0x9d,0x27,0xa6,0xb1, - 0x30,0xa8,0x9b,0x91,0x8f,0xa9,0x58,0x66,0x50,0x30,0x65,0xcc,0xf4,0x60,0xbf,0x25, - 0xc2,0xcb,0x11,0xe7,0x58,0xf2,0x0,0xe5,0x98,0xfd,0x9a,0x36,0x25,0xc0,0x67,0x55, - 0xe9,0x3,0x67,0x79,0x2c,0xbf,0xdf,0xfc,0xef,0xc4,0xc9,0xe4,0x25,0x9,0x8a,0xe7, - 0xd5,0x1b,0x50,0x2e,0xe,0xcf,0x93,0xa6,0xce,0xad,0x5c,0x73,0x6f,0xc3,0xc9,0xd8, - 0x46,0xb0,0x52,0x73,0x70,0xb1,0x70,0xdf,0xf5,0xb9,0xc5,0x1b,0xc2,0xcf,0x83,0x98, - 0x6a,0x53,0x46,0x78,0x23,0xda,0x9f,0x71,0x8,0xfb,0xe5,0x77,0xc0,0x2f,0xcf,0x7, - 0xdf,0xa1,0xf9,0xcf,0x53,0xe9,0xaf,0x49,0xa3,0xf4,0xe4,0x67,0xc4,0x68,0x7f,0xae, - 0x3b,0xc6,0x28,0xdd,0x21,0x47,0x50,0x29,0xc2,0x36,0x21,0x3,0xe4,0xf0,0xb,0xc4, - 0x93,0x84,0x14,0x66,0xee,0xc3,0x30,0x92,0xb9,0x15,0x79,0xfd,0xfc,0xf9,0xad,0xb7, - 0x40,0x55,0x95,0x61,0x9c,0xe5,0xa,0xde,0x9b,0x2b,0xe2,0x80,0x9c,0x6d,0xc4,0xaf, - 0xf1,0xd8,0x95,0xe0,0x9d,0xc5,0xf3,0xd6,0x5a,0x6d,0xd4,0x57,0xe6,0x2,0x8e,0x27, - 0x57,0x25,0x8,0x73,0xb,0x13,0x53,0x27,0xbd,0x36,0xa7,0xd9,0x23,0xec,0x89,0x15, - 0xc5,0x9f,0x76,0xe2,0x65,0xe9,0x39,0xc0,0xd6,0x8e,0x97,0xbe,0x90,0x27,0x65,0xe8, - 0xcb,0x6e,0xdb,0x56,0x1,0xae,0x7d,0xbe,0x64,0xa5,0x19,0x87,0x92,0xa2,0x1d,0xd7, - 0x42,0x13,0x3b,0x28,0xfc,0x74,0x68,0xd3,0x3,0x0,0x92,0x14,0xa6,0xf8,0x7c,0x72, - 0xe6,0x58,0x49,0xe7,0x8,0xc6,0x26,0x6c,0xeb,0x3f,0xf4,0x7e,0x62,0x91,0xd6,0xa4, - 0xa4,0x91,0x4c,0xa1,0x6,0xb4,0xf4,0x89,0x35,0x88,0x9d,0x5b,0x1,0x1a,0xce,0x67, - 0xf1,0x18,0x4f,0x79,0x5e,0x75,0x66,0x4b,0xb5,0xda,0x49,0x18,0x6c,0x9f,0x3c,0x11, - 0x31,0x89,0xb2,0xb7,0xbd,0x27,0xc0,0xf2,0xaf,0x5e,0xce,0x30,0xf7,0x9d,0x97,0x69, - 0x35,0x66,0xe3,0x13,0xdc,0x4a,0xdd,0x12,0x25,0x28,0x2a,0x91,0xc7,0xe5,0x22,0xf9, - 0xee,0x54,0x31,0xad,0x7b,0xf1,0x20,0xab,0xcf,0xee,0x5b,0xc7,0xc,0xf3,0xb0,0xc0, - 0x5a,0x14,0x54,0xb6,0x5e,0x32,0xc8,0x3,0xd9,0x72,0x14,0xa2,0x59,0x36,0x1c,0x48, - 0xa,0xcc,0x75,0x86,0xbe,0x16,0x32,0x8e,0x84,0x8d,0xd5,0x91,0x1,0x86,0xd1,0xdb, - 0x9b,0x26,0x12,0x79,0xd8,0xdb,0xfc,0xb2,0xcd,0x11,0xd4,0xa6,0xc7,0xf0,0xef,0x51, - 0xbd,0xe4,0xd7,0xfb,0xfa,0x89,0x8a,0x0,0x97,0x60,0x11,0x98,0x67,0xe2,0xf3,0x82, - 0x89,0x7,0xfb,0x62,0x62,0x78,0x94,0xaf,0x8a,0x6a,0x57,0xd1,0xda,0xc6,0x23,0x19, - 0xab,0x7b,0x15,0x27,0x5,0x20,0x27,0x1c,0x0,0x38,0xb5,0x67,0x9a,0x29,0xe9,0xa3, - 0xaf,0x66,0x6,0x91,0xde,0x9b,0x42,0xe8,0x85,0x99,0x3a,0x60,0x60,0x5e,0x79,0x8b, - 0x59,0xf,0x32,0xdd,0x2f,0xd8,0xfa,0x2f,0x90,0x30,0x97,0x2c,0x59,0x1,0xcf,0xa, - 0xe6,0x56,0x1b,0x46,0x71,0x5d,0x2f,0xf6,0xf6,0x6a,0xd6,0xd6,0x48,0xd0,0xe2,0x21, - 0xdf,0x15,0xfe,0xf,0xee,0xf9,0x3e,0xfe,0x2a,0x55,0x2b,0x84,0xd6,0x7b,0xe,0xbd, - 0x51,0x29,0x4,0x42,0x7,0xb3,0xb8,0x7d,0x9d,0x8f,0x55,0x65,0x60,0xb7,0x86,0x40, - 0xcc,0x85,0xce,0x3b,0x80,0x8d,0x3b,0xaa,0xe2,0xe5,0xae,0x39,0xe0,0x3c,0xf7,0x32, - 0xe5,0x7b,0x74,0xec,0x2f,0x2d,0x6a,0x4c,0x3d,0x3f,0xb1,0x9d,0xf6,0x38,0x5e,0x44, - 0xbe,0x2d,0x7f,0xbe,0xba,0x3a,0xe8,0x1e,0x21,0x98,0x57,0x2,0x54,0xce,0xb4,0x3a, - 0xca,0xa8,0x27,0xf9,0xd6,0x12,0xc6,0x14,0x51,0x78,0x31,0x49,0xb1,0xf,0xd,0xef, - 0xbc,0x8c,0x2e,0x77,0xc7,0x17,0x15,0x68,0x2f,0xec,0xe9,0x84,0xbb,0x9e,0x3e,0x86, - 0x48,0xe5,0x1,0x9e,0x77,0x47,0x32,0xc8,0xbf,0xe2,0x91,0xf0,0xf2,0x9e,0x60,0xaf, - 0xab,0x8e,0xa6,0xf2,0x26,0xbc,0x5b,0x55,0x29,0xc4,0x59,0x64,0xe3,0x18,0x6b,0x2c, - 0xfd,0x6c,0x4a,0x75,0xb3,0xfb,0xbd,0xf2,0xde,0x50,0xe4,0xd1,0x6e,0xc4,0x1,0x1a, - 0x54,0xa8,0x8c,0x7a,0xe4,0xe7,0x4f,0x8d,0x2d,0xa9,0xf1,0x11,0x41,0x5d,0xbc,0x3f, - 0x49,0x7,0x34,0x7c,0x3,0x71,0x70,0x61,0x41,0xd4,0xb3,0xb0,0x99,0xb4,0x4a,0x6d, - 0xdc,0xd7,0x67,0x41,0x3f,0xb7,0xce,0x6c,0xe0,0xc1,0x7d,0xa1,0x1f,0xb9,0xe0,0x69, - 0xc0,0x94,0xe5,0x43,0x6,0x56,0x25,0x48,0xaa,0xd8,0x78,0xc4,0x8d,0xc2,0x32,0xea, - 0x1a,0x1a,0x2c,0x5a,0xd1,0xfb,0xc6,0x32,0xbd,0xc4,0xd3,0xdc,0x7e,0x34,0xc5,0xbf, - 0x48,0xac,0x82,0xcd,0x82,0xa7,0x95,0x2e,0x80,0xe,0xf2,0x8e,0x51,0xa4,0xf8,0x6b, - 0xbe,0x25,0xc5,0x10,0x21,0xd,0xc1,0x5e,0xd1,0x15,0xbb,0xcf,0xc8,0x81,0x8f,0x11, - 0xad,0x92,0xdf,0x31,0x3a,0xf4,0xde,0x3b,0x4,0x51,0x49,0x55,0x75,0x42,0xc0,0x35, - 0x67,0x7,0xc4,0x9,0x14,0x87,0xe6,0x65,0x1c,0xa2,0x35,0xe5,0xa4,0x45,0x76,0x52, - 0xd7,0xd5,0x3,0x12,0xcb,0x61,0xcc,0xcf,0xb2,0x16,0xa4,0x29,0x58,0xe4,0xdd,0x40, - 0xeb,0x22,0xc8,0x0,0xa9,0xaf,0x65,0x46,0xd2,0x1b,0x2c,0xf6,0x60,0xa2,0x49,0x38, - 0x79,0xcc,0x4a,0x45,0x2e,0x18,0x94,0x61,0xad,0x39,0xa,0x7,0x1e,0xe7,0xc6,0x8a, - 0xa,0xf,0x8a,0x34,0x3e,0x70,0x7a,0x11,0x8b,0x26,0x87,0x6b,0x48,0xd1,0xa3,0xc1, - 0x1e,0xed,0x86,0x4c,0x85,0x9a,0x2d,0x34,0xd3,0x37,0xba,0x72,0x1f,0x1,0xfc,0xa9, - 0x10,0x7,0x5d,0x4e,0xf6,0x57,0xdf,0x2,0x7d,0x67,0x6d,0x45,0xb8,0x11,0x8,0xd6, - 0x7f,0xe,0xa3,0x84,0xa9,0xd0,0x38,0xfc,0x9,0xf2,0xee,0xa7,0xf3,0x6b,0xd0,0x83, - 0xf2,0x2e,0xd2,0xe9,0x85,0x32,0x6c,0x82,0x99,0xd9,0xc8,0xd2,0x6b,0x50,0xa9,0x6a, - 0xdd,0xcc,0xee,0x7,0x9e,0x28,0x5,0x27,0x9a,0x73,0x4e,0xf,0xdf,0x20,0x92,0xd2, - 0x4e,0xe4,0x3c,0x54,0x17,0xa8,0x56,0x31,0x3,0x9e,0x4,0xed,0x6e,0x2d,0x58,0x4d, - 0x7a,0xc6,0x54,0x98,0x6e,0xd8,0xbf,0xa,0x4d,0xe,0x98,0x2d,0xad,0xaa,0x7f,0xfc, - 0x90,0xbb,0xd0,0x27,0xe4,0x27,0x58,0x67,0x46,0xdb,0x55,0xb4,0x89,0x2d,0x81,0x4, - 0xf3,0xd6,0x9c,0xe2,0x2f,0xdb,0xec,0x7c,0x69,0x5,0x29,0x18,0xaf,0xa8,0x94,0xbf, - 0xe4,0x65,0xe7,0xc9,0xc,0xbf,0x31,0xd1,0x1c,0x6,0x87,0xa5,0x33,0x9,0x29,0xa6, - 0x5f,0x45,0x89,0x8f,0x21,0xf5,0xc,0xa,0xfa,0xb5,0x22,0x2b,0x5e,0x36,0xea,0xc2, - 0x9b,0x52,0x8c,0x28,0x13,0x3d,0xf9,0xae,0x43,0x1,0xd3,0xf5,0xb,0xfc,0x9d,0xe9, - 0x42,0x27,0x79,0xe2,0x1e,0x6,0x6c,0x98,0xbb,0xf,0xc3,0x99,0x45,0xaf,0x5d,0x61, - 0x81,0x69,0x9,0x94,0x27,0x3,0xc2,0x6a,0x5,0x96,0xe0,0x8f,0x93,0x7e,0xf8,0x55, - 0xa5,0x73,0xb7,0x43,0xf8,0x25,0xdc,0x34,0xb3,0x20,0x4d,0xf8,0xcf,0x2a,0x5a,0x52, - 0x94,0x63,0x66,0xbb,0xe6,0xa9,0xa5,0x6b,0x40,0x86,0x7a,0x54,0x84,0x73,0xa9,0xaa, - 0x66,0xe1,0xed,0xde,0x86,0x4a,0x13,0x3a,0x6b,0x61,0x33,0xba,0xb,0xe,0x8c,0x9f, - 0xf0,0x73,0xda,0x57,0x1d,0x1,0xc2,0x5d,0x7,0xbc,0xb1,0x8c,0x31,0xdb,0x37,0x17, - 0x3d,0xa4,0xf6,0xc3,0x6f,0x89,0x7d,0x5a,0x6a,0x30,0x15,0x76,0x3e,0x22,0x16,0xaf, - 0x95,0x71,0x86,0xb2,0x72,0xc9,0x8f,0x79,0x86,0xc1,0x85,0x37,0x1d,0x3c,0x4f,0x5a, - 0xe1,0xc5,0x9d,0xd0,0x4f,0x1b,0x2b,0xba,0x4b,0xbf,0x31,0xa,0xe1,0xc6,0x39,0xf6, - 0xb7,0xbf,0x29,0x2a,0x89,0xb9,0x24,0x90,0xfa,0xa9,0xc7,0x18,0xe6,0x96,0xf1,0x48, - 0xdb,0xf,0x98,0x2c,0xa9,0xc3,0x66,0xf4,0x83,0x17,0x7e,0xe5,0x5d,0xb7,0xdc,0x16, - 0xf7,0x7,0x40,0x1,0x40,0xe3,0x91,0x3b,0x8e,0xd9,0xd2,0xf4,0xef,0x44,0x3d,0xcc, - 0x53,0xd5,0x78,0x7c,0x19,0x5e,0x71,0x1c,0x75,0x70,0x2,0xd2,0xa7,0x5f,0xe8,0x9f, - 0x66,0xa9,0x21,0xa6,0x8d,0x32,0x61,0x9b,0xc,0x34,0x90,0x7c,0xf7,0x4d,0xc8,0xca, - 0xa2,0x41,0x47,0xbb,0x9f,0x38,0x58,0x15,0xa8,0x5a,0x67,0x51,0x39,0xd0,0x70,0x9f, - 0x7a,0x91,0xc5,0x87,0xc4,0x27,0x24,0x50,0xda,0xb4,0xcc,0xd2,0x82,0x95,0x9d,0x25, - 0x56,0xe4,0x61,0xf5,0x1e,0xb9,0x8a,0x46,0x93,0x72,0x97,0xcd,0x43,0x88,0xec,0xbd, - 0x1a,0xb3,0xc4,0x5e,0xda,0xe8,0x2f,0xb6,0x1e,0x7b,0x9,0x20,0x91,0xa7,0x45,0xe7, - 0xc,0x26,0x5e,0xa9,0x5f,0x68,0xf0,0x73,0xda,0x8,0xc0,0x9d,0x90,0xad,0x5b,0x2b, - 0xe0,0xa0,0x9,0x3c,0x89,0x38,0x72,0x27,0xb4,0x7b,0x47,0x46,0xa2,0xd,0xad,0xaf, - 0x33,0xc,0xd8,0x13,0xf4,0xc9,0x86,0xcf,0xd2,0x47,0x6e,0xe2,0x74,0x49,0xe,0xd5, - 0xe9,0x97,0x12,0xf3,0xcf,0x84,0x1b,0x4,0x0,0xe2,0xc9,0xa3,0xef,0x78,0xd2,0x23, - 0x4,0xab,0x36,0xf8,0xf5,0x3c,0x49,0x48,0x3,0x37,0x2b,0x78,0x0,0xb9,0xcd,0x6a, - 0x51,0xdf,0x5e,0xa0,0x64,0xf8,0xa5,0xe3,0xdb,0x6f,0x7,0xcb,0x67,0xd9,0x6f,0x6c, - 0x6,0xa5,0xe4,0xfb,0x62,0x2e,0x44,0x65,0xe4,0xee,0x5d,0xe5,0xa8,0x2b,0x50,0xf9, - 0xb,0x2e,0x1b,0xee,0x27,0xc0,0x53,0x4,0xaf,0x5a,0x4f,0x18,0xb4,0xbe,0x4,0xba, - 0xe4,0xe8,0x36,0x47,0x97,0x7a,0xac,0xfb,0xe8,0x8a,0xe1,0x92,0xb5,0xb1,0xc,0x41, - 0xdf,0x27,0x30,0x8,0xe7,0x83,0x8b,0x18,0x5e,0xda,0x30,0x13,0x9a,0xb3,0x4d,0x7f, - 0x1c,0x83,0x46,0xb3,0x7d,0x72,0x30,0x66,0xfc,0x12,0x78,0xb3,0x44,0x85,0xf4,0x24, - 0xac,0xa4,0x2c,0x15,0xa8,0xb7,0x2d,0x7,0x13,0xdc,0x1a,0xad,0x90,0xe6,0xac,0x2c, - 0x6a,0xf2,0xe0,0x67,0x65,0x90,0xcd,0x63,0x22,0x47,0x96,0x66,0x4c,0xb,0x8b,0x78, - 0x2f,0x37,0x8d,0xd7,0xef,0x3a,0x5e,0x82,0x96,0xf7,0x30,0xa6,0xde,0xdc,0xd3,0x49, - 0x4f,0x34,0x30,0x34,0xc4,0xfe,0x97,0xe6,0xc5,0xad,0x4e,0x91,0xb8,0x59,0xa,0xe8, - 0x90,0x18,0x40,0x0,0x52,0x9f,0x82,0x69,0x97,0xb2,0x10,0x77,0xf,0xe3,0x40,0xdd, - 0x97,0x71,0x13,0x5c,0xef,0x2a,0xc3,0x35,0xd8,0x91,0xc6,0x11,0xea,0xd0,0xf9,0x7b, - 0xe8,0x3b,0xfb,0xbb,0x5a,0x7e,0x25,0xf1,0xb1,0xb4,0x69,0xc0,0x99,0x2a,0x1f,0xb0, - 0x9b,0x32,0xe,0x8b,0x5c,0x51,0x40,0xb4,0xe2,0x7,0xc6,0xcd,0xd7,0xc0,0xc8,0x41, - 0x7b,0xc4,0xfc,0xd5,0xc3,0xa1,0x48,0x75,0x56,0x31,0xb5,0xef,0x5b,0xd4,0x21,0xf6, - 0x86,0x2f,0x2,0xe3,0x0,0x42,0x98,0xe2,0xc8,0x5f,0x30,0xa1,0xa0,0x78,0x62,0x9b, - 0xbd,0x5f,0xf1,0x81,0x1,0x3a,0xf6,0x57,0xea,0xac,0xc7,0x47,0x2,0xe8,0xbd,0x88, - 0x97,0x40,0xeb,0x17,0x2,0x85,0xf9,0xcb,0x64,0xa9,0xec,0x84,0xa1,0x4f,0x21,0x5f, - 0x2e,0x13,0xe0,0x2f,0xcc,0x57,0x6,0xb7,0x84,0x4d,0x7e,0x86,0x36,0x3d,0x8e,0x4d, - 0xfc,0x7b,0x64,0xfe,0x1,0xdd,0xca,0xe4,0x7,0x37,0x6a,0xa9,0x86,0x8b,0x9,0xb4, - 0x1e,0x6a,0x63,0x6a,0x41,0xe9,0xa1,0xc5,0x37,0x21,0xcb,0xed,0xdd,0x5b,0x3b,0xda, - 0xd6,0x20,0x59,0xd7,0x7d,0xa4,0x3c,0x85,0xdb,0xa6,0x2f,0xe2,0xb1,0xb7,0x97,0x4f, - 0x22,0x7b,0xb9,0x64,0x65,0x5c,0xa9,0x1c,0xfc,0x76,0xa,0x5a,0xd1,0x46,0x35,0xa8, - 0xe5,0x8e,0x0,0x63,0x33,0x3c,0xe8,0x8f,0x63,0x97,0x72,0x15,0x50,0x89,0x65,0xf1, - 0x5,0x9e,0xd5,0xe9,0xfa,0x80,0x7,0x77,0xf6,0x11,0xd1,0x48,0xd6,0x86,0x70,0x3c, - 0x95,0x70,0xa0,0xc8,0x2c,0x9,0xd7,0x8f,0x21,0x4a,0x25,0x71,0xd4,0x8a,0xe2,0x59, - 0x29,0xb9,0x44,0xa4,0x3a,0xca,0x9b,0xb0,0x5b,0x6e,0x78,0xb2,0x74,0xe8,0xee,0xa, - 0x59,0xf,0x53,0x5,0x98,0x2b,0x95,0xb9,0x76,0xba,0x2b,0x4b,0xc4,0xe,0x24,0x6d, - 0x47,0x68,0x91,0x81,0xb2,0x2e,0xb1,0xf,0x1c,0x2a,0xc1,0x90,0x13,0x30,0x9b,0xeb, - 0x40,0x6e,0xf1,0xd8,0x99,0x7,0x12,0x10,0x41,0xbc,0xda,0x6,0x4a,0x0,0x73,0x92, - 0xe7,0x6,0x93,0x1b,0xb3,0xc5,0x2a,0xcf,0xef,0x6b,0xdf,0x83,0x1b,0x7b,0xee,0x5b, - 0xe9,0xe0,0xb3,0x4,0x67,0x45,0x93,0xa8,0x2,0xee,0x2e,0x4d,0x6e,0xa2,0x5f,0xd5, - 0x28,0xf2,0xf0,0x5b,0xb8,0x9a,0x2b,0x29,0x85,0xb,0x2c,0xa1,0x7,0x1b,0xfc,0x70, - 0xfc,0x31,0xf3,0x64,0x76,0x88,0x8d,0xf8,0x77,0xbb,0x46,0x65,0xdd,0xa5,0x3b,0x85, - 0x18,0x2d,0xe0,0x51,0x47,0x8b,0x7a,0xcd,0x17,0xa6,0x6f,0x1e,0xc1,0x6c,0xe,0x3e, - 0x1d,0x3,0x23,0x14,0xb,0xb0,0xd,0x2,0xeb,0x53,0x67,0xca,0x78,0xa2,0x50,0x10, - 0x4f,0xb1,0x61,0x97,0x3d,0xdb,0x65,0x54,0x2,0xd4,0xf1,0x44,0xc0,0x80,0x82,0x5e, - 0x83,0x25,0x72,0xe,0xd5,0x7f,0x10,0xc2,0x52,0xf6,0xd,0xca,0x99,0x5d,0xda,0x69, - 0xf,0xbc,0x80,0xcc,0x98,0xe5,0x21,0x1b,0x3a,0x93,0x5f,0x7a,0x14,0xe1,0xd8,0x17, - 0x8,0x4b,0x25,0x5d,0x4a,0xb4,0x9f,0x9c,0xab,0xac,0xe6,0xc4,0x8a,0x42,0x2e,0x19, - 0xfe,0xae,0xe5,0x17,0x14,0x87,0x32,0xcd,0x1b,0x91,0x49,0x2f,0xf3,0x22,0x46,0x7b, - 0xed,0xea,0x58,0xb7,0x9f,0xf8,0xd4,0xca,0x25,0xbb,0x8f,0xaf,0x7d,0x3e,0xc9,0xfb, - 0xec,0x2f,0x14,0x81,0xb6,0xc5,0x4f,0xd1,0xd7,0x98,0x80,0x4b,0x3b,0x46,0x46,0xa8, - 0xb0,0x9e,0x60,0x50,0x97,0xb4,0x9a,0xbd,0xf0,0x2b,0xec,0x6e,0x69,0x36,0xea,0xd5, - 0x66,0x7e,0xd6,0x1d,0xc3,0x27,0x6f,0x9b,0x3f,0x6f,0x66,0x7a,0x36,0xac,0xa2,0xe6, - 0x4c,0x83,0xb7,0xe3,0x38,0x52,0x21,0x29,0xfc,0xf,0x18,0xe5,0x45,0x3,0xbc,0x2b, - 0x1,0x13,0xc8,0xc4,0x3a,0x38,0x61,0x7a,0x27,0x47,0x74,0x5d,0xf4,0x97,0x45,0x41, - 0x1b,0xfc,0xa4,0xd2,0xce,0x46,0xfc,0xcc,0xd4,0x94,0xb2,0x1a,0x17,0xee,0x46,0x18, - 0x3,0xf,0xdc,0x3d,0xc6,0xbd,0x37,0x6d,0x6,0x2c,0xcb,0x7a,0xc3,0x90,0x3b,0xde, - 0xd,0x5f,0xb1,0xdb,0xa5,0x2e,0xa8,0x7a,0x42,0xdb,0x15,0x59,0xca,0x5b,0xf0,0xcd, - 0xe9,0x4e,0x8b,0x30,0xc,0x42,0x9d,0x91,0x6e,0xe8,0x8b,0x32,0xf8,0xc6,0x90,0x6, - 0x27,0xc2,0x62,0x4c,0xf0,0x8a,0xc7,0xb3,0x66,0xdc,0xd,0xb1,0xb7,0x7e,0x7f,0x21, - 0xcc,0x8a,0xd0,0x58,0xcd,0xed,0x6a,0x3c,0xd7,0xf5,0xee,0x50,0x3d,0x7f,0x57,0xe3, - 0x42,0x39,0x30,0xb3,0xc3,0xf7,0x67,0xaa,0x54,0xf3,0x5c,0x8b,0x72,0x5b,0xac,0xbe, - 0xe6,0x7d,0x18,0x34,0x6c,0x82,0xef,0xc3,0xf7,0xde,0x14,0x35,0x5f,0xea,0x19,0xa1, - 0x24,0xc9,0xd4,0x68,0xc1,0x3c,0x13,0x96,0x31,0x6f,0x22,0x23,0x4a,0x4f,0xe2,0xb0, - 0xcc,0x7a,0xe4,0xb8,0x7c,0xd5,0xfb,0x74,0xb4,0x11,0x2a,0x14,0x7b,0xc2,0x36,0x20, - 0x8c,0xb,0x88,0xce,0xc7,0x9b,0x65,0x78,0x8a,0x7,0x9b,0xd4,0x56,0xfd,0x86,0x24, - 0x78,0xea,0x5c,0x74,0xc0,0x59,0x69,0xf5,0xe9,0x13,0x89,0xe4,0xd5,0xbf,0x5,0xe2, - 0x4b,0x8d,0xb1,0x13,0x29,0x96,0x8b,0x33,0x9d,0xa6,0x9,0xf4,0xa5,0xf,0x98,0x9d, - 0xf9,0xf4,0x92,0x3b,0xcd,0xfb,0x31,0x37,0xf,0xba,0x1d,0x64,0xfa,0x22,0x47,0xc5, - 0xb0,0x78,0xd8,0x59,0x8e,0xe3,0xd,0xac,0xa,0x16,0xa1,0x2f,0xa4,0xb9,0x4d,0x1e, - 0x2e,0xdf,0x59,0xfc,0xdb,0xa,0xb3,0x6a,0xc5,0xd0,0xce,0x40,0xf3,0x96,0x6,0x24, - 0x8e,0x5e,0xfc,0x1e,0xc1,0xa,0xca,0xcb,0x9f,0xeb,0xfb,0xc3,0xa5,0x49,0xe2,0x53, - 0x29,0xbb,0xcf,0x84,0xc6,0x84,0xee,0xc,0x55,0x3d,0x4c,0xc8,0x53,0x52,0x6c,0xe2, - 0x30,0x6a,0x80,0xf1,0xf3,0xca,0xbd,0x94,0x36,0xb9,0x58,0x5b,0x82,0xba,0xae,0x2b, - 0x77,0x7f,0xaf,0x3e,0x4,0x1e,0x4a,0xd8,0x5c,0x16,0xa2,0x2f,0x68,0x8e,0x91,0x98, - 0xf8,0x12,0xa,0x6d,0x5c,0xc7,0x2,0x92,0x2,0xd9,0xed,0x84,0x95,0x1d,0xb0,0x8c, - 0x9c,0xdf,0xca,0x20,0xfe,0x94,0xf8,0xda,0xaa,0x1b,0x89,0x92,0xaa,0x1c,0xaa,0x23, - 0x2e,0xb4,0x90,0xb,0xfb,0x12,0x9d,0xfd,0xec,0xc,0x3,0x2,0xa8,0x33,0xe,0x45, - 0x13,0xd8,0xe4,0x91,0xec,0xdd,0xeb,0x97,0x79,0x76,0xa9,0x24,0x92,0x54,0x47,0xc0, - 0x88,0xd8,0x4b,0x84,0xea,0x69,0x83,0x57,0x75,0x86,0xd8,0x9d,0xb9,0xe6,0x62,0x4c, - 0x3f,0x47,0xde,0xab,0xa4,0xca,0xc2,0x1e,0x41,0x6c,0x42,0x53,0xc0,0xa,0x94,0x49, - 0x62,0xdf,0xce,0x4d,0x49,0xd1,0x25,0x3e,0xd7,0x7d,0xdb,0x11,0xe4,0x3e,0x5d,0xa3, - 0x85,0xbb,0x50,0xaa,0x7,0x13,0xc8,0xc7,0x80,0x8b,0x1c,0xc0,0x95,0xb0,0x8a,0xf7, - 0x90,0xd8,0xc4,0xda,0x2a,0x69,0x19,0x2,0x67,0x75,0x13,0x4c,0xb3,0xef,0x6f,0xb9, - 0x2c,0xbf,0x64,0x33,0x53,0x2d,0xfa,0x53,0x38,0x17,0x93,0xcd,0x47,0x1e,0x45,0xd8, - 0x76,0x8a,0x33,0xa0,0xf3,0xcb,0xa2,0x5b,0x41,0x35,0x27,0xf5,0xa5,0x97,0xaf,0xd1, - 0xd6,0x93,0x5,0x2a,0xc0,0x7f,0xfc,0x79,0x17,0x91,0x47,0x5e,0xaf,0xd,0x37,0x27, - 0x97,0xe9,0x47,0xb,0xb6,0xea,0x67,0xf7,0x9f,0xe,0x6d,0x45,0x25,0x9c,0x17,0xfc, - 0x30,0x9b,0xa6,0x71,0x1c,0xa4,0xea,0x33,0xb5,0xb1,0x11,0x65,0xbe,0xc8,0xc,0x56, - 0xb2,0xd3,0x62,0x69,0x3e,0x49,0xe1,0xdd,0xd6,0x4f,0xa3,0xfc,0x6c,0xba,0xf9,0x9c, - 0xd6,0x20,0x8d,0xf2,0x44,0x78,0xa5,0xf9,0x2b,0xb6,0x60,0x69,0x7f,0xeb,0x40,0x33, - 0x3f,0x22,0x1c,0x7d,0x6b,0x7d,0x5c,0xc1,0x4d,0x0,0xbe,0xb9,0x3a,0x38,0xd5,0x11, - 0x59,0x64,0x83,0x9d,0xdc,0x29,0x98,0x87,0x60,0x78,0x71,0xdf,0xe3,0xb1,0x92,0x24, - 0xd3,0x2f,0xa1,0xbe,0x2c,0xfd,0x80,0x79,0x7d,0x40,0xb2,0xb8,0x78,0x89,0x49,0x51, - 0xed,0xcd,0xef,0x4a,0x76,0x88,0x52,0xd6,0x80,0xc3,0x37,0x64,0x75,0xc9,0x88,0xc8, - 0x78,0x2b,0x87,0xa5,0xa8,0x87,0x9e,0xa6,0x47,0x52,0x5f,0x40,0x5b,0x28,0x91,0x49, - 0xf5,0x1,0x13,0x6d,0x9,0xe4,0x44,0x89,0xa8,0xfa,0xee,0x9d,0xc5,0xf6,0x66,0xbd, - 0xa1,0x6d,0x63,0xca,0x75,0x82,0x71,0xbc,0xd4,0x50,0xfc,0x30,0x78,0xf,0xf8,0xee, - 0x10,0x8b,0x5c,0x1a,0x71,0x20,0x23,0x99,0x1c,0x12,0xb7,0x61,0x89,0x1e,0x9e,0xaa, - 0xc,0x82,0x75,0x81,0x5,0x66,0xbd,0xd9,0xb6,0x3b,0xa,0xaf,0x4a,0x82,0x9e,0xd9, - 0xe,0x7a,0x73,0xfe,0x1a,0x97,0x99,0xb5,0x29,0x51,0x17,0xb2,0xee,0x36,0xdd,0x7a, - 0xb8,0x53,0x7b,0xbd,0xba,0x3a,0x97,0xf0,0x75,0x21,0xa0,0x3f,0xa3,0x3f,0x98,0x31, - 0xb9,0xd,0x31,0x54,0xa4,0x4a,0xa,0xcd,0x9b,0xa1,0x1,0xa,0xd7,0xde,0x85,0x90, - 0xb1,0x1,0x4e,0x6c,0xba,0x65,0x5e,0x30,0x86,0x7e,0xee,0xa9,0xbe,0x88,0x5a,0xf7, - 0x95,0x8b,0x4c,0xb9,0x55,0xd6,0x7,0xf0,0x78,0x8,0xfb,0x50,0x66,0x1,0xe0,0x19, - 0x2,0xae,0x5,0x3d,0x14,0xe2,0xec,0x1a,0x62,0xdc,0x43,0xa0,0xe4,0x1d,0x18,0xf9, - 0x29,0xe4,0xb3,0x7e,0xbb,0xba,0x70,0x34,0x43,0xeb,0x84,0xa9,0x6c,0xe4,0x42,0xed, - 0x13,0xc7,0x2b,0xa6,0xaa,0x19,0x40,0x8c,0xf5,0x3,0xac,0x5a,0x20,0xc5,0x54,0x49, - 0xaa,0x8,0xc8,0xe5,0xc2,0xb8,0x1a,0x6,0x24,0x1e,0x30,0x90,0x82,0x72,0x7e,0x95, - 0x3a,0xaa,0xbb,0x65,0xc3,0xfb,0x71,0x39,0xfe,0x1f,0x93,0x1f,0xe4,0xe7,0xe8,0xf, - 0xef,0xb1,0xf4,0x32,0x6a,0x8e,0xb8,0xe,0xac,0x68,0x9e,0xae,0xda,0x1d,0x44,0x95, - 0xc7,0x7f,0x7a,0xb,0x7b,0xeb,0x44,0x7a,0xb,0x57,0x19,0x6f,0x3f,0x2,0xfd,0xae, - 0x33,0x72,0xe1,0x1d,0x1,0x1a,0x2b,0x2d,0x82,0xc9,0xdb,0xdc,0xe7,0x9f,0xf1,0x2f, - 0x1f,0x6c,0x3b,0x9a,0xd8,0xfe,0x94,0x63,0x57,0x2e,0xd3,0x16,0x30,0x51,0xc5,0x64, - 0xc4,0x27,0x81,0xc5,0x41,0x2d,0xf3,0x43,0xf6,0x4f,0x20,0x5e,0xef,0x92,0x8e,0xf, - 0x7e,0x49,0x2a,0x57,0xc7,0xbe,0x3b,0x1f,0x6c,0x8e,0xb5,0x9d,0xdf,0x7b,0x81,0xa4, - 0x22,0x82,0x6b,0xe2,0xaf,0xde,0x26,0xa7,0x2e,0xc5,0x85,0x9d,0x58,0x14,0xad,0xd7, - 0xdc,0x57,0xae,0xa5,0x95,0xe9,0x44,0x3,0x78,0xf9,0xa0,0x59,0xf4,0xa1,0x7d,0x17, - 0xa3,0x68,0xf9,0x54,0x47,0x9f,0x7b,0xf5,0x66,0x1,0x93,0x3e,0x95,0xc0,0x95,0xf1, - 0x97,0x45,0x17,0x2e,0xae,0x5c,0x31,0x28,0xd5,0x51,0x1,0x4b,0x72,0x7e,0xe1,0x16, - 0xe7,0xdc,0x6a,0xae,0xfb,0x65,0x24,0xe1,0xe6,0x38,0x21,0x7c,0xf8,0xb6,0x6e,0x11, - 0xfb,0x86,0x3f,0xab,0x62,0xef,0x53,0xb7,0xc0,0x54,0x3,0x33,0x52,0xe5,0x49,0xb9, - 0x42,0x34,0x69,0xbd,0x19,0x8d,0xa0,0x0,0xc5,0xc1,0x7c,0x3f,0x78,0x6b,0x50,0xf4, - 0x71,0xf,0x20,0x53,0xfe,0x73,0xb,0xbf,0x47,0x8e,0xf2,0x99,0xf3,0xbb,0x54,0xb5, - 0x6f,0x3d,0x73,0x89,0xca,0x14,0x89,0x11,0x55,0x86,0x50,0xce,0x71,0x20,0x43,0x62, - 0x2f,0x63,0xb5,0x2e,0x56,0x40,0x6d,0x9d,0xce,0x60,0xb6,0x42,0x9b,0xb,0xf7,0xc, - 0xc7,0xeb,0x15,0x93,0x0,0x9e,0x24,0xd5,0xa4,0xf3,0xa4,0x95,0x14,0x67,0xf7,0xc2, - 0xca,0xad,0x70,0xa0,0x6e,0xdd,0x3e,0x3d,0xbd,0xf4,0x0,0x59,0x80,0xf7,0xe4,0x48, - 0x63,0xf9,0x5b,0x64,0x19,0x7f,0xb9,0x3d,0xf2,0xdd,0xd3,0x7,0x45,0xcb,0x49,0x8f, - 0xf9,0xb9,0x30,0x68,0x97,0xed,0x25,0x55,0xe2,0xa4,0x2f,0xe2,0x9d,0x14,0xab,0x1, - 0x8e,0x7,0xe4,0x27,0x7,0x9e,0x64,0xf9,0x7c,0xb7,0x81,0x41,0x4,0xca,0xd0,0xfd, - 0x85,0x80,0xe5,0x9c,0x6e,0x8a,0xf2,0xd1,0x30,0x22,0xb4,0x4d,0xb5,0x60,0xcd,0xc3, - 0xe7,0x33,0xea,0x6e,0x51,0x50,0x68,0x4e,0x8,0x69,0x8f,0xc,0xb4,0xe0,0x89,0x3a, - 0x61,0xee,0xd6,0xd0,0xf9,0x49,0xa2,0xa9,0xea,0xd6,0xf6,0x21,0x38,0x44,0xe4,0x9f, - 0x77,0xd0,0xe,0x49,0x21,0xf5,0x97,0xa8,0x60,0xa6,0x35,0x94,0x7,0x3e,0xce,0x69, - 0xad,0x25,0xb9,0xa7,0xee,0x5c,0x51,0xd9,0x33,0xc7,0xfa,0xea,0xc,0xe0,0xa,0x4, - 0x31,0x18,0xcc,0xd1,0x8e,0xe3,0x7a,0x6e,0x8a,0x2f,0x3,0x12,0xed,0x51,0x7b,0x9b, - 0xf5,0x35,0x43,0xe4,0x11,0x14,0x3f,0x44,0xdb,0xb9,0xaf,0x67,0x1a,0xb9,0xea,0x4b, - 0x52,0xb7,0x1d,0xe0,0x9b,0x18,0xce,0xa6,0x47,0xd1,0xb8,0xb4,0xa2,0xb3,0x50,0x98, - 0x68,0x13,0x7e,0x79,0x27,0xbd,0x3d,0x82,0xf6,0x6c,0xea,0x12,0x27,0x55,0x5d,0xf8, - 0xe,0x7b,0x59,0x29,0x13,0x28,0x4f,0x5a,0x79,0x87,0x10,0x1c,0xba,0xdf,0xb4,0x23, - 0xf3,0xb2,0x9c,0x1b,0xef,0x5a,0x1e,0xe7,0xc6,0x88,0xf9,0x6d,0xdd,0x57,0x66,0x6b, - 0x52,0xbf,0x95,0x65,0x67,0x64,0x40,0xe0,0x6c,0xcf,0x7c,0x27,0xaf,0xb1,0x4b,0x23, - 0x64,0x67,0xbe,0xd4,0xc1,0xdc,0xbc,0x89,0x65,0x36,0xf6,0x43,0xd,0xdd,0xaf,0x60, - 0x1d,0xc4,0x45,0x85,0xa8,0x5,0xe5,0x15,0xd4,0x63,0x3d,0x5,0x94,0x88,0x28,0x78, - 0xef,0xe6,0x4d,0x32,0x43,0x89,0x3b,0xa8,0xbf,0xb1,0x6c,0xcd,0x8f,0x1c,0xad,0xad, - 0x60,0xf2,0xb2,0x9,0xf8,0x98,0x9e,0x4d,0x7b,0xdb,0x52,0x8f,0xe3,0xfa,0x9,0x53, - 0x61,0x56,0x85,0xa5,0xe0,0x40,0x4e,0xa0,0xf2,0xba,0xed,0x2,0x56,0x9b,0x2f,0x36, - 0xf,0xe1,0xbf,0x87,0xfa,0x5e,0x54,0xf5,0x3a,0x27,0x86,0x9d,0xa1,0x8f,0xf0,0x3, - 0xe5,0xf6,0xa8,0x46,0xb6,0x77,0x67,0xa9,0x32,0x55,0x2c,0x9,0x71,0x5b,0x3f,0x0, - 0xbd,0xfe,0x7,0xb8,0xdc,0xda,0xae,0x96,0x2,0xb4,0x34,0xa3,0x44,0xa5,0xa7,0xaa, - 0x9c,0xcf,0x70,0x53,0x47,0xd7,0x7d,0xf9,0xad,0xa9,0x82,0x9e,0x84,0xc1,0x9e,0x42, - 0x41,0x25,0xfa,0x1e,0x0,0x2a,0xb5,0x82,0xde,0x69,0x26,0x24,0xf,0x4d,0x4e,0x2b, - 0x9d,0xbe,0xfe,0x64,0x97,0xfb,0xdd,0xc4,0xa5,0x60,0x63,0xa9,0xa2,0x81,0xec,0xe3, - 0xa6,0xe7,0x81,0x26,0x91,0xb6,0xa8,0x71,0x21,0x4f,0x15,0x30,0x1c,0x63,0xdb,0xb9, - 0xa1,0xda,0x9e,0xb8,0xd6,0x7c,0x7d,0xfb,0xdd,0x60,0xa5,0x80,0xe1,0x92,0xe3,0x8, - 0xfa,0xe4,0xae,0x8c,0x9c,0x57,0x7d,0x3d,0x26,0x92,0xec,0xc2,0x75,0xc8,0xfb,0x18, - 0x23,0x9a,0x50,0x79,0x18,0x4e,0xf4,0xf5,0xae,0x1b,0xf5,0x91,0x2d,0x59,0x19,0x28, - 0x3e,0xc7,0x35,0x5a,0x9f,0xb2,0x97,0x45,0xc5,0x85,0x8,0x3b,0xcd,0x5,0xd2,0xf1, - 0x9f,0x24,0xea,0xb7,0xf1,0xe0,0x2d,0xa0,0xfb,0xa2,0xb1,0x29,0xfb,0xcb,0xd1,0xba, - 0x13,0x86,0x15,0xb2,0x39,0xad,0x78,0x7e,0xb2,0x80,0xba,0x80,0x5,0xd,0xf1,0xa5, - 0xb0,0xdd,0xdc,0xa2,0x3e,0x8a,0x44,0xb9,0x2d,0x75,0xe2,0x2a,0x41,0x34,0xe4,0xd4, - 0xba,0x79,0x7,0x74,0xa6,0x7f,0xf2,0x59,0x80,0x2d,0x5a,0x85,0xba,0xcb,0xaa,0xea, - 0x29,0x8,0x8e,0x67,0x92,0x52,0xa0,0xbf,0xc7,0x4,0x69,0x89,0x38,0xcd,0x5e,0x73, - 0x48,0xe4,0x67,0xee,0x65,0x5a,0xc8,0x65,0x8,0xa2,0xea,0x42,0x6e,0x16,0x2d,0x18, - 0x1e,0x3b,0xfe,0xb0,0x8d,0xa0,0xef,0xd5,0xa4,0x5a,0xde,0x5c,0x28,0xbc,0xcf,0xef, - 0xa1,0x37,0x5f,0x86,0x12,0x28,0xeb,0x99,0xca,0xd7,0xdb,0xb8,0xed,0x88,0xd0,0x8b, - 0xc4,0x50,0x3c,0x52,0xf0,0x2c,0xa7,0x15,0x6,0x86,0x71,0x2f,0x43,0xc1,0x9e,0x65, - 0xf8,0xfd,0xeb,0x8a,0x26,0xd8,0x24,0x70,0x30,0x7f,0xa9,0x9d,0x88,0xf9,0x29,0x4d, - 0x4a,0xe4,0x1f,0xba,0x90,0xc7,0xcf,0x97,0xcd,0x42,0x46,0x91,0x4,0xe4,0xf6,0x7c, - 0xe3,0x62,0x8,0x89,0xba,0xab,0x7a,0x6a,0xab,0x24,0x87,0x34,0x1e,0x30,0x1,0xe8, - 0x15,0x20,0xa3,0xa6,0x67,0x74,0xbd,0x36,0x36,0x4,0x47,0xb9,0x68,0x3e,0x36,0x4c, - 0x20,0xbd,0x56,0xdb,0xe9,0xd0,0xc5,0x15,0xf4,0x4e,0xc8,0x92,0x7e,0xc9,0x7b,0x94, - 0xe9,0x9f,0xba,0x52,0x14,0x78,0x8,0xc9,0xfb,0x4f,0x83,0x64,0xd,0x39,0x31,0x2d, - 0x77,0x7,0x88,0xe0,0xd7,0x4f,0xf5,0x4c,0x9d,0x3e,0x5e,0x9b,0x8,0xda,0x30,0xf1, - 0xf9,0x6a,0xc3,0xe,0x62,0xcb,0x57,0xdd,0x9a,0x5a,0x43,0xa7,0x93,0xf3,0x55,0x8a, - 0xfa,0x5d,0xea,0x52,0x2c,0xe0,0x9e,0xc9,0x1f,0xfc,0xe5,0xa6,0x57,0x16,0x19,0x51, - 0x1,0xdc,0xde,0x63,0x29,0x36,0x42,0xc3,0x10,0x5,0xeb,0x24,0x78,0x41,0xae,0x73, - 0x1e,0x9a,0xc5,0x4b,0xfa,0xe3,0x94,0x9a,0xe0,0x7a,0x41,0xb8,0x11,0x5a,0xa,0x12, - 0xb7,0x69,0xf4,0xe0,0x1f,0xb6,0x24,0x30,0x3b,0x10,0x54,0xb3,0xd0,0x82,0x27,0x6f, - 0x9c,0x6c,0xba,0x98,0x50,0x4f,0xb2,0xb1,0x4a,0x73,0x6a,0x5b,0x4e,0xf3,0xec,0x6, - 0x5d,0xe1,0x66,0x7d,0x19,0xa,0x2d,0x54,0x9a,0x1,0x9,0x6b,0x83,0xaf,0xda,0x21, - 0x9c,0x15,0x39,0xec,0xe4,0x6b,0x1e,0x2f,0x5e,0x88,0x8a,0xac,0x7d,0x77,0x32,0x5a, - 0xd8,0x18,0x57,0xf1,0x23,0x84,0x47,0xbd,0x5,0xcf,0xa8,0x89,0x7f,0x4,0x2a,0x1c, - 0x19,0xe2,0x89,0xfd,0x4e,0xa7,0x2d,0x2c,0xb0,0x37,0xd9,0xad,0xae,0x8b,0x8,0x88, - 0xa4,0xdf,0x7a,0x47,0xe3,0x41,0x5,0xe9,0x11,0x2d,0xf2,0x11,0xb0,0x1d,0xac,0xca, - 0x7f,0x36,0x48,0x4d,0x5e,0xf5,0x79,0xf,0xac,0x53,0xbc,0xdb,0x5f,0x44,0xe3,0x4, - 0x24,0xdd,0xca,0x88,0x20,0x4f,0x72,0x31,0x7c,0x65,0xc1,0x2e,0x2,0x6f,0x78,0x81, - 0xa5,0x40,0xce,0x83,0xb5,0xc7,0x92,0x63,0x9b,0xce,0x3f,0xfa,0x14,0x23,0x7e,0xb7, - 0x1,0x49,0xbf,0xa0,0x98,0x32,0xd2,0x15,0x17,0x14,0xc2,0x98,0x83,0xba,0x99,0xa9, - 0xfb,0xe7,0x2d,0xb1,0xb0,0xc0,0x94,0x4c,0x8f,0x53,0x47,0x23,0x76,0x45,0x5b,0xf7, - 0x8e,0x1b,0x98,0x27,0xcd,0xea,0xbb,0x64,0x0,0x7f,0xfd,0x83,0x3a,0x17,0x2d,0xb5, - 0x0,0x5b,0xe7,0xb0,0x9b,0x7c,0x7c,0xaa,0xd0,0x43,0x4e,0xc6,0x88,0xa9,0x3e,0x17, - 0x44,0xd7,0xbd,0x91,0xc2,0x79,0xf6,0x42,0xf8,0x74,0x46,0xb3,0xb,0x73,0x69,0xb, - 0x4e,0xd0,0x3b,0x69,0xcd,0x37,0x15,0x1e,0x7a,0x63,0xe4,0x82,0x8c,0x24,0x19,0x50, - 0x7b,0xd6,0xe2,0xbd,0x51,0x59,0x1,0x4a,0x4d,0x47,0x7d,0x58,0x3a,0x67,0xe3,0x9, - 0x38,0x1f,0x72,0x6,0x57,0x87,0x24,0x51,0x6a,0x89,0x54,0x76,0x2d,0x6d,0x47,0xa8, - 0x45,0xa9,0x66,0x96,0x3,0x67,0x60,0xcf,0x2e,0xde,0xa7,0x69,0x46,0x8b,0xf1,0xfd, - 0x2b,0x64,0x84,0x2,0x6c,0xa8,0x53,0x56,0xb1,0xa7,0xcd,0xde,0x16,0x15,0x87,0xda, - 0xbe,0x6e,0x71,0x41,0xd5,0xd1,0x90,0x84,0x30,0x38,0xed,0x76,0xc4,0xdf,0xf4,0x6f, - 0xc3,0x79,0x71,0x30,0xa1,0x44,0x87,0x54,0xec,0xd4,0x33,0x82,0x69,0x3b,0x5d,0xa7, - 0xa9,0x4e,0x68,0xfe,0x20,0xf8,0x83,0x51,0xb0,0xf0,0x47,0xf4,0x50,0x3c,0x64,0x15, - 0x35,0xd5,0xc4,0xd7,0x1b,0xcb,0x2c,0x87,0xa0,0xde,0x89,0x89,0x1a,0xe6,0x31,0x43, - 0xb4,0x99,0x43,0xd4,0x12,0xc6,0xa5,0xc3,0x38,0x6d,0xb8,0x88,0x29,0x1e,0x9d,0x5f, - 0x73,0xe2,0x37,0x8e,0xae,0xe2,0x95,0x50,0xc1,0x1f,0xd9,0x5c,0x85,0x8b,0x9f,0x3a, - 0xa4,0xe2,0x10,0xb7,0x2a,0x35,0x7b,0x62,0xa2,0xb3,0x6a,0xcc,0xd1,0x88,0x2c,0xc5, - 0x6b,0xe2,0x54,0x1a,0xc5,0xea,0xe9,0x87,0xa,0x44,0xe3,0x10,0xcf,0x84,0x4a,0x74, - 0xe6,0xd9,0xab,0x11,0x10,0x27,0xf2,0x32,0x5b,0x5e,0xfe,0xac,0xe6,0xaa,0x72,0x52, - 0xd,0xc7,0xeb,0xd2,0x32,0xd6,0xda,0xbb,0x1b,0xbe,0xcb,0x6a,0xc2,0x96,0x5e,0x2a, - 0x70,0xb,0xba,0x0,0xb1,0xae,0x33,0xd,0x8c,0xb1,0xba,0xf2,0x5d,0xac,0xc4,0x6a, - 0xf3,0xb0,0xbd,0x26,0x7,0x98,0x62,0x22,0xd6,0xad,0xc,0x1a,0x44,0x6b,0x44,0x35, - 0xf5,0x7e,0x35,0xa7,0xac,0x68,0x35,0x39,0x1b,0x6f,0x2c,0xf7,0x1c,0x70,0xe1,0x11, - 0x22,0x9f,0xb6,0x29,0xb7,0x98,0xcb,0x8f,0x47,0xd7,0x29,0xb,0xc2,0x6d,0x40,0xb8, - 0x6b,0x76,0xe0,0x19,0x5e,0x16,0x52,0xf8,0x85,0xfe,0xf0,0x21,0x6f,0x53,0x32,0x11, - 0x72,0x69,0x3b,0x2b,0x2,0x7,0x3a,0x49,0x5e,0x63,0x55,0xa1,0x50,0x15,0x5a,0xbb, - 0x8b,0x3b,0xd4,0x6a,0xd0,0xa7,0x63,0xd5,0x26,0xd4,0xf7,0x15,0x28,0x2a,0x27,0x9a, - 0x93,0xe1,0x45,0x16,0x68,0xfe,0x5f,0x46,0x62,0x34,0xe7,0x32,0x4a,0xc2,0xee,0x55, - 0xfd,0x43,0xbf,0x4f,0x6a,0x24,0x25,0x10,0xf8,0x1d,0x26,0xa0,0xc7,0xcc,0xba,0xda, - 0x2e,0x1,0xf0,0x96,0x0,0x51,0x5c,0xe2,0x5,0x45,0x15,0x4f,0x8,0x83,0xa5,0x85, - 0x47,0xe4,0xd4,0xb1,0x9,0xfa,0xc2,0x81,0x97,0x68,0x22,0x5f,0xb4,0x5d,0x3b,0xe2, - 0xdd,0x2c,0xf8,0x5d,0xfc,0x55,0x40,0x3,0x9a,0xd5,0xd1,0x22,0xd8,0xf6,0xa8,0x20, - 0xdc,0xfc,0x52,0x65,0x77,0x15,0xe7,0x10,0xfc,0x89,0x6f,0xb1,0xe6,0xaa,0x94,0xc4, - 0x57,0x8d,0x23,0xd3,0x62,0xe2,0x56,0xfd,0xb8,0x29,0x9f,0x12,0x9f,0xc7,0x32,0x7c, - 0xc5,0x84,0xe2,0x3d,0x19,0x4a,0x4d,0x16,0xd3,0xbd,0x47,0xbb,0xe7,0xdb,0x0,0xbe, - 0xe8,0xa2,0x93,0xcb,0x86,0x69,0x49,0xbe,0x92,0xe8,0xd0,0x33,0xb1,0x83,0x2f,0x77, - 0x87,0x91,0x34,0xa1,0xdb,0x82,0x37,0xb0,0xbf,0xfe,0xeb,0x27,0x5a,0x6b,0xe6,0x44, - 0xf,0xf9,0x10,0x15,0x63,0x59,0xd3,0x76,0xc1,0x25,0x29,0x73,0xa8,0xd7,0x6a,0x30, - 0x6a,0x9f,0x51,0x46,0xa1,0x9,0x76,0x61,0x8,0xe1,0x88,0x62,0x4e,0xee,0x26,0xdc, - 0x68,0xb5,0xf1,0xcc,0x8e,0x45,0xc2,0x51,0xe9,0xeb,0xc4,0x92,0xc3,0xaf,0x43,0xad, - 0x4f,0x14,0xf4,0xf0,0x9c,0xea,0xd1,0xa4,0x4d,0xd9,0x87,0x1b,0xc9,0xad,0xf7,0x32, - 0x64,0x69,0x7e,0xf2,0x2e,0x41,0xc3,0x19,0x2d,0x9,0x2b,0x71,0xb8,0xed,0x1f,0x87, - 0x3,0x93,0xf7,0x9f,0xfe,0xc9,0xc4,0x4c,0xa3,0x4c,0x67,0x6d,0xf9,0xde,0x20,0xdd, - 0x48,0x9e,0x51,0xf5,0xe0,0x15,0xf,0x8d,0x1e,0x3b,0x7e,0x56,0x29,0x1e,0xdd,0xab, - 0xb1,0xd5,0x4c,0xb0,0x1f,0x90,0x7c,0xc3,0xdc,0xe3,0xb0,0x56,0x42,0x50,0xb4,0xa, - 0xef,0x6,0x1,0x50,0x9a,0x10,0x5d,0xb9,0xca,0xdc,0x10,0xf4,0xfa,0x6e,0xa0,0x2c, - 0xc3,0x6c,0x5d,0xe3,0x7c,0xd9,0xa7,0x59,0x3e,0xd7,0x30,0x80,0x29,0x64,0x8b,0x98, - 0x6a,0xc,0x68,0x84,0x1c,0xc5,0xbd,0x67,0x22,0x4e,0x5c,0x9c,0xbc,0x7c,0xc9,0x80, - 0x69,0xa6,0x64,0xe5,0x80,0x8b,0xbf,0x3e,0xe3,0x6f,0xbf,0x8c,0xd3,0xca,0x25,0xbd, - 0xd6,0xd,0x42,0x72,0xd2,0x80,0xd9,0x75,0xce,0xb5,0x12,0xb,0xb2,0x5b,0x8b,0x9b, - 0x2,0x70,0x81,0x3,0x7b,0xc0,0x41,0x5f,0xaf,0x80,0x6b,0x83,0xca,0x90,0xc0,0x21, - 0x1d,0x83,0x14,0xf0,0x4,0x6d,0xe5,0x52,0x24,0xf7,0x5d,0x56,0x54,0x68,0xf1,0xd5, - 0xd8,0xf2,0xd8,0xd4,0x34,0x9a,0x34,0xe3,0x9a,0xa0,0xe7,0x66,0xb0,0xa8,0x7,0x4e, - 0xab,0x1b,0x3f,0xaf,0x89,0x25,0x2,0x2d,0x9c,0xde,0x83,0x70,0x48,0xf4,0x47,0x21, - 0xe7,0x9f,0xf5,0x1c,0xb9,0xaa,0x1,0x55,0xca,0x68,0x3b,0xfa,0x11,0x42,0x49,0xbd, - 0x5e,0x8,0xec,0xe7,0xac,0x6f,0x15,0x4a,0x4e,0x18,0xba,0x96,0xd,0x81,0x38,0xf4, - 0xa1,0xad,0x91,0x5b,0x58,0x12,0xb0,0xa2,0x7a,0xeb,0x9e,0x8b,0xae,0x67,0xc8,0xd, - 0x70,0x36,0x74,0x1d,0xa5,0x89,0xe6,0x73,0xa1,0xa2,0xb,0x2e,0xa3,0xc2,0x23,0x45, - 0x70,0x34,0xa1,0xc9,0x46,0xd1,0xeb,0xc0,0x3e,0x8a,0xcc,0xec,0x72,0x15,0x79,0xe2, - 0x4b,0xed,0x7f,0x70,0x77,0x67,0xe4,0x98,0x89,0x6f,0x46,0x2d,0x32,0x69,0xf2,0xa2, - 0x9e,0x14,0xeb,0xe4,0xe5,0xd8,0x26,0x24,0xe2,0xf2,0x90,0x55,0x8,0xa,0x38,0xd3, - 0xf7,0x38,0x44,0xee,0x9f,0x29,0x7,0xa8,0x18,0x4d,0x55,0x4a,0x37,0x48,0xed,0x55, - 0x5c,0xd9,0xb9,0xc2,0x32,0xdf,0xe6,0x16,0x52,0xf7,0x6b,0xda,0x2,0x24,0xae,0x7a, - 0xdb,0xf2,0xe8,0x7b,0x9c,0xf0,0xa3,0xb4,0xbd,0xf8,0x7f,0xf4,0x42,0x6d,0xc9,0x1e, - 0xc6,0x84,0xe0,0xf9,0xe3,0x48,0x8f,0x37,0x40,0x7a,0x12,0xc1,0x1e,0x40,0xbb,0xf9, - 0xb2,0xa5,0xf4,0x4f,0x16,0x98,0x84,0xd3,0x12,0x4,0x49,0xd3,0xf0,0x13,0xf1,0x37, - 0x97,0x53,0xb0,0x7c,0x1b,0x40,0x33,0xda,0x3b,0x45,0x9c,0x59,0x5,0xd8,0xd3,0xb7, - 0x7e,0x48,0x87,0x94,0xe1,0xc,0xe7,0x73,0x8f,0x31,0x47,0x0,0xc4,0xb8,0xb6,0x5c, - 0x8b,0x68,0x58,0xa6,0x28,0xb,0x81,0x63,0x50,0x9e,0x3d,0x55,0x77,0x11,0x8d,0x75, - 0x59,0x15,0x89,0xba,0xa0,0x71,0xad,0xaf,0x23,0xf4,0xaf,0xe7,0x2e,0x66,0xc3,0xb9, - 0x4e,0x9c,0x61,0x77,0xa7,0x62,0xda,0x78,0x1,0x97,0x4d,0xf7,0xa8,0xda,0x6d,0x82, - 0xef,0xf6,0xbc,0x90,0xe8,0x6b,0x40,0x8b,0x60,0x6f,0x73,0xe,0x56,0xb6,0xc8,0xa4, - 0x53,0xa9,0x9b,0xfb,0xc,0xf6,0x74,0x8d,0x8e,0xc1,0x85,0x38,0x1d,0x73,0x3a,0xd, - 0xe9,0xf6,0x1e,0xd2,0x62,0x5e,0x5e,0x43,0x4e,0x51,0x51,0xa4,0x9,0x99,0xc8,0x5c, - 0x43,0x65,0xd7,0xcf,0x5c,0xcb,0xdc,0xea,0xe,0x62,0xa2,0x2b,0xd5,0xdc,0x38,0xc0, - 0x54,0xd5,0x13,0xb6,0x35,0xf1,0xf9,0x3,0x43,0xcb,0xa7,0xcb,0x65,0xef,0xa8,0x29, - 0xd4,0x80,0x78,0x31,0xcc,0x55,0x9c,0xda,0xb7,0xbe,0x6,0xe,0x1c,0xbd,0x4e,0x70, - 0x94,0xe0,0xa6,0x49,0xd2,0x21,0x4c,0x96,0xec,0x73,0x62,0x52,0x63,0x8a,0xfa,0xb8, - 0xc,0x73,0xe9,0xd8,0xc8,0x6,0x33,0x1,0xc5,0x39,0x8e,0x61,0x76,0x5c,0xd1,0x8a, - 0x3d,0x78,0xd3,0x90,0x99,0x9f,0xa6,0x6,0x13,0x9,0xd8,0xf6,0x14,0xd3,0xaf,0x9f, - 0x48,0x19,0xf7,0x90,0x9f,0x2b,0x11,0xe4,0xe3,0x9f,0x46,0x5a,0xfb,0x97,0x65,0xb9, - 0x10,0x39,0xc9,0x2a,0xd9,0x70,0x30,0x6c,0xf8,0x88,0xe2,0xd,0x5d,0x92,0xac,0x25, - 0x2c,0xa4,0x35,0xcb,0xcf,0x47,0xb0,0xb3,0x66,0xf6,0x8e,0x63,0x8e,0xf3,0x9c,0x1e, - 0xac,0x66,0xc7,0x6,0xd6,0x78,0x73,0xcf,0x1,0x56,0x5d,0xdd,0x69,0xa,0x3,0x95, - 0xaf,0xb8,0xe0,0xfe,0x0,0x91,0x33,0x66,0x8,0xc1,0x49,0x16,0x35,0x65,0x34,0x61, - 0x4b,0x7c,0x68,0x22,0xf4,0x5b,0x72,0x75,0x31,0x4f,0x54,0x1a,0x59,0xd6,0xaf,0x88, - 0x8f,0x10,0x88,0xf,0xa1,0xbb,0xf5,0x29,0xfc,0xbe,0x3f,0xb1,0xa4,0xf3,0x13,0xef, - 0x70,0x7b,0x92,0xe4,0x56,0x5,0xd9,0x88,0x54,0xad,0xa2,0x2d,0x85,0xd2,0xb6,0x94, - 0xe2,0x3f,0x24,0x5,0x7a,0x99,0xad,0x77,0x58,0xed,0x29,0xfc,0x61,0x3c,0xed,0x51, - 0x38,0x80,0xb5,0x8e,0x5,0x8f,0x96,0xd8,0x3e,0xb9,0x6,0x43,0x8c,0x3c,0xd7,0xee, - 0x7b,0x7b,0x73,0x75,0x15,0x22,0xec,0x6e,0x8f,0x95,0xea,0xf0,0x52,0x58,0x42,0x8a, - 0x58,0xf7,0x98,0x5d,0x87,0x30,0xb5,0x45,0x69,0x3c,0x88,0xf5,0x78,0xe0,0x64,0x74, - 0x5c,0xd8,0xe9,0x72,0x7a,0x57,0x60,0xa,0xec,0xca,0xfa,0x3f,0x24,0xbc,0xc9,0xfb, - 0xb4,0xe2,0x5a,0xbb,0x92,0x8f,0x81,0xfb,0xcb,0xa,0x71,0x45,0xea,0xd5,0x39,0x48, - 0x2e,0x23,0x3a,0x28,0x7a,0x1a,0x32,0x68,0xe4,0xac,0x27,0x88,0x69,0xf1,0x85,0x9d, - 0x54,0x5f,0xd9,0xe6,0xee,0x5b,0xe2,0x3b,0x65,0xd3,0x80,0xd0,0xa9,0x39,0x98,0x58, - 0x5c,0xd2,0x80,0x57,0x6c,0x33,0xbf,0x51,0x5f,0xe6,0x5a,0x49,0x58,0xdf,0xe6,0xac, - 0x3f,0x40,0x13,0xad,0x1b,0x75,0xe8,0x1,0x49,0xe8,0xd1,0xf3,0x22,0x6a,0xcb,0xfe, - 0xbc,0xcb,0x56,0xa8,0x7e,0x16,0xf9,0xde,0x7c,0xd3,0x28,0x55,0xb3,0x8e,0x81,0x72, - 0xcf,0x95,0x21,0x6a,0xb,0x89,0x6b,0x55,0xf2,0x3d,0xc8,0x15,0x27,0x94,0x14,0x63, - 0xdf,0xe9,0xc,0x5f,0x7f,0x86,0x3e,0xfc,0x5a,0xe5,0xd1,0xf,0x74,0x53,0x1,0xc3, - 0x68,0xa1,0x2f,0x74,0x2c,0x9a,0x49,0x1f,0x58,0x12,0xb3,0x7f,0x26,0x48,0x63,0x85, - 0x32,0x6f,0xe4,0xb2,0xf5,0xa2,0x2f,0xd0,0x88,0x1,0xdf,0x7d,0xd3,0x60,0x41,0x3d, - 0x3,0xef,0xb1,0x2f,0x8b,0x7a,0xcd,0x63,0x8c,0x1,0xe2,0x32,0x49,0x46,0xb7,0x7c, - 0x36,0x9d,0xae,0x2c,0xbf,0x5d,0x7c,0x49,0x5e,0xdb,0xc6,0xb1,0x3d,0x87,0xee,0x40, - 0x78,0x20,0xee,0x83,0x9a,0x3c,0xe6,0xa6,0x3d,0xc9,0xd8,0x87,0x90,0x11,0x83,0xc6, - 0x2e,0xb1,0x72,0xed,0xf,0xef,0x37,0xec,0xcb,0x7d,0x9e,0x88,0x6,0x8e,0xc8,0x7e, - 0xae,0x37,0x2,0xc9,0x73,0xe8,0x70,0x31,0x32,0xc9,0xb8,0x42,0xda,0xbb,0x88,0x9, - 0x6d,0x7b,0xf6,0x7c,0xea,0xae,0x69,0x36,0x2c,0x8,0xbf,0x32,0x16,0x8,0xb0,0x45, - 0x40,0x32,0xf,0x33,0x9a,0xfe,0x64,0xcd,0x48,0x9c,0x8f,0x23,0x58,0x19,0xab,0x45, - 0x14,0x23,0xc1,0xfe,0xd1,0xaa,0x35,0x7d,0x33,0x74,0xb0,0xc8,0x7d,0xe0,0xe,0x3d, - 0x93,0x9c,0x70,0x2e,0x1c,0x55,0x7b,0x64,0xf1,0xc,0x8,0xca,0xa4,0xb3,0x10,0xb8, - 0x56,0x52,0x37,0xa7,0xfc,0xeb,0x26,0xaf,0x61,0x56,0x79,0x5e,0xb6,0x7,0x9b,0x4a, - 0xa4,0x8b,0x79,0xc0,0xe0,0xf4,0xa4,0x53,0x80,0xac,0x1e,0x25,0xe0,0x2e,0x5d,0x37, - 0x0,0x14,0xdf,0x7d,0x1,0x85,0x2d,0xe1,0xdb,0x26,0x40,0x92,0x2e,0x5b,0x5d,0xd2, - 0xe6,0xd6,0x13,0x48,0x4b,0xb7,0x1b,0xcc,0x65,0x39,0x71,0x46,0xe6,0x4f,0xfc,0xe7, - 0x63,0xdc,0x65,0xe3,0x62,0x92,0xc5,0xbd,0x39,0x85,0x51,0x67,0xe0,0xae,0xb9,0x48, - 0x5,0xcc,0x10,0xcf,0x4,0x2b,0x9c,0x69,0x64,0x8e,0x2f,0xca,0x5d,0x2d,0xb2,0x40, - 0x89,0x18,0x25,0x6c,0x2b,0x6a,0x2a,0x64,0xf0,0xfa,0x4b,0x51,0x29,0x5,0x19,0xad, - 0xd1,0x29,0x7e,0xd5,0xd3,0x9a,0xbf,0xb7,0x29,0x6e,0x83,0x6,0x1b,0x36,0x47,0x25, - 0xce,0xeb,0x91,0x79,0x56,0xbb,0x5d,0xc6,0x37,0xa8,0x98,0x60,0xad,0xb1,0xf,0xfe, - 0x5b,0x8d,0x54,0x2f,0xa7,0x93,0xe7,0xd1,0x3,0x6b,0xd7,0x9d,0x21,0x9e,0xc2,0x6f, - 0x8a,0x54,0x68,0xe1,0x90,0xc5,0x28,0x47,0xed,0xc0,0x27,0x1b,0x73,0xb5,0x1a,0x4e, - 0xc2,0xee,0x7d,0x6b,0x82,0xe4,0x3d,0x5,0xcf,0x94,0xa3,0x71,0x34,0xe5,0xe0,0x3e, - 0x3b,0xc9,0x20,0x4b,0xf,0xc8,0x12,0xfd,0x89,0x39,0x19,0x7c,0xef,0xb3,0x4a,0xb2, - 0xa2,0xc8,0x1e,0x25,0x2d,0xda,0x2b,0xfd,0x70,0x4e,0x6f,0x24,0x34,0xcf,0x62,0xee, - 0x99,0x3,0xb9,0x29,0xcb,0xcb,0x27,0xd4,0x6,0xbf,0xd1,0xf5,0x73,0x1c,0x28,0x95, - 0x64,0x47,0x3b,0x92,0x22,0x66,0x90,0x92,0x34,0x7f,0x36,0x68,0x4f,0x99,0xd7,0x69, - 0x1c,0x91,0x92,0x67,0x5e,0x39,0xbb,0xe3,0xf8,0x8d,0x59,0xec,0x2a,0x81,0x82,0x8e, - 0xc8,0xbd,0x21,0xeb,0xa3,0x31,0xfd,0xd7,0xb0,0xb4,0xc0,0x1,0xcd,0x98,0xe9,0xe9, - 0xa9,0xfb,0x51,0x8,0x35,0x8c,0xeb,0x2e,0x1b,0xc4,0x9a,0x45,0x47,0x9d,0xd3,0x10, - 0x5b,0x75,0x7b,0x7f,0xa6,0x7a,0xd6,0x58,0xae,0x17,0xd8,0x7c,0xaf,0x42,0x66,0x5a, - 0x3e,0x37,0xe1,0x73,0xc3,0x4e,0x21,0x5e,0x13,0xbc,0xa3,0x5a,0x5a,0xf7,0xea,0x35, - 0x6d,0x66,0x34,0x93,0x60,0xc,0xeb,0xf,0x23,0x44,0x8b,0x53,0x86,0x71,0x2d,0xc4, - 0xa8,0xf,0xb7,0xec,0xdc,0xd9,0x4b,0xf0,0x16,0xef,0xca,0xef,0x67,0xb5,0xa4,0xd4, - 0x9c,0xd9,0x68,0xfc,0x65,0xd4,0xd,0x8,0x19,0x18,0x5b,0x20,0x8a,0x88,0xe4,0xb2, - 0x18,0x9d,0x9f,0x74,0xf6,0xeb,0xe4,0xd,0x5b,0xb0,0x7c,0xc2,0xe5,0x21,0x17,0x82, - 0xfa,0xfe,0x0,0x60,0xd3,0x8c,0x69,0x6d,0xa4,0x44,0x8d,0x2f,0x4d,0xf1,0xe2,0xe4, - 0xf,0x2,0x59,0x6,0xed,0x3f,0x92,0x49,0x6f,0xf,0x8b,0x55,0x31,0xa2,0x58,0xab, - 0x22,0x58,0xd,0xf5,0xe4,0xf5,0xe2,0x89,0x3a,0xef,0x39,0x7,0xe2,0x9b,0xeb,0x71, - 0x9d,0x46,0x78,0xc,0x5,0x8a,0xd4,0x74,0x9a,0x61,0xc9,0xcb,0x83,0x22,0x77,0xa5, - 0x7a,0x4,0x1c,0x5f,0x79,0xfe,0x69,0x34,0x6f,0x22,0x3b,0x52,0xbd,0x28,0x43,0xda, - 0xed,0xbb,0xe6,0xf2,0x47,0xbc,0x67,0x61,0x9d,0xb0,0x2d,0x21,0xd3,0x24,0xc7,0xcd, - 0xa8,0x63,0xad,0x22,0x62,0x17,0x56,0x51,0xb8,0x12,0x23,0x76,0xb9,0x67,0x51,0xa7, - 0x23,0xb8,0x1a,0xe9,0xf4,0x1,0x4b,0x92,0xb1,0xf7,0x33,0x5,0x9c,0x7a,0x53,0x45, - 0xdd,0x1,0xe6,0xc0,0x97,0x3e,0x12,0x50,0xcf,0x36,0x46,0x89,0x9d,0x17,0xb0,0x40, - 0xcf,0xca,0xaa,0x44,0x4b,0xf5,0xd6,0xfc,0x6e,0x8a,0x82,0xb,0x5,0xd5,0x50,0x63, - 0xd6,0x37,0x24,0xed,0xf4,0xb5,0x3e,0x44,0x6b,0x84,0xcd,0x9,0x9b,0xfd,0xc9,0xeb, - 0x48,0x74,0x30,0x93,0xe9,0x87,0x91,0x58,0x12,0x93,0xe2,0x96,0x69,0xb2,0xf9,0xbf, - 0x6a,0x9d,0xad,0xde,0x54,0xeb,0x24,0x3f,0xef,0xf1,0x49,0xb,0xf0,0x92,0xf6,0x39, - 0x7,0x28,0x4d,0x70,0x2f,0x5e,0x49,0xc0,0xf1,0x2c,0x57,0x5b,0xdf,0xd1,0x1b,0x4a, - 0xee,0xc8,0x29,0xc2,0x34,0xcc,0x3,0xa3,0xbf,0x4c,0xae,0x30,0x5e,0xa6,0xe8,0xe4, - 0x4e,0x36,0x55,0xfc,0x94,0x9e,0xbd,0x86,0xcb,0x15,0x61,0x2b,0x66,0x7c,0xf4,0x56, - 0xc4,0x9d,0x19,0x78,0x6b,0x1c,0x1c,0xaa,0xe7,0xcb,0xda,0x46,0xf1,0x43,0x2b,0x40, - 0xf9,0x1,0x3d,0x8e,0x1f,0x7a,0x95,0x6a,0x8f,0xf6,0x95,0x76,0xf3,0xa,0xcc,0x38, - 0xa8,0x65,0xb1,0x14,0x82,0xcd,0x3e,0xe9,0x19,0x19,0xb0,0xb,0xdb,0x5b,0xca,0xd5, - 0x5c,0x87,0xe4,0x7c,0x2,0x7a,0x66,0x12,0xf0,0xfc,0x88,0xe4,0x7,0xd4,0x1e,0x2f, - 0x3a,0x4f,0xc2,0x3c,0x9c,0x1,0xa6,0xb6,0x99,0x57,0xc1,0x76,0x32,0xd,0xcb,0xf, - 0x94,0xb0,0xb,0x17,0x2b,0x71,0xa8,0x1d,0x6e,0x31,0x81,0xf5,0x85,0x1f,0xa4,0x3f, - 0x6e,0x68,0xfb,0xc,0x69,0xa2,0xc2,0x83,0x79,0x4,0xf9,0xab,0x90,0x45,0xba,0xa5, - 0xf6,0x45,0xbc,0x22,0xb7,0x65,0xbe,0x26,0x16,0xc0,0x9b,0x1b,0xdf,0x41,0x5a,0x4f, - 0x29,0x56,0xda,0x92,0x78,0x9d,0x95,0x71,0x21,0x8f,0x9d,0xb2,0x55,0xd7,0xd7,0x4c, - 0x1e,0x14,0xed,0xd5,0x79,0x2d,0x7b,0xf,0xed,0x18,0x2a,0xcd,0xd8,0x4,0x1d,0x2, - 0xda,0xf7,0x14,0x53,0x15,0xaa,0x45,0xb6,0xb9,0xe2,0xe8,0xf,0x3a,0xc0,0x5b,0x58, - 0xd4,0xc9,0x2e,0xcd,0xf6,0xaa,0x5c,0xe4,0x42,0x6,0xb2,0x9a,0xa,0x50,0x9c,0xe4, - 0xc7,0xb0,0xb8,0x5d,0x5b,0x7d,0x14,0x95,0x60,0xfc,0xa4,0x9a,0x3d,0x80,0x73,0x91, - 0x4a,0xa1,0xde,0x41,0xcb,0x3b,0x26,0x8d,0xc0,0xd8,0x28,0xca,0xa8,0x44,0x30,0x71, - 0xf5,0x68,0xce,0xd0,0xe5,0x62,0x66,0xc5,0xde,0x8b,0xdf,0x1c,0xc,0x53,0x2d,0x56, - 0x75,0xc,0x97,0xc0,0xc6,0x3d,0x4f,0x87,0x16,0xf6,0xd1,0x3f,0x3c,0x2,0xb0,0x32, - 0x6a,0xfe,0x82,0xcf,0x61,0x69,0x95,0x40,0xf4,0x76,0xdb,0x1,0x49,0x9,0x57,0xbe, - 0x94,0x6e,0x80,0x5b,0xab,0xcf,0x62,0x41,0x46,0x34,0x80,0x82,0xb6,0xb0,0xb4,0xa0, - 0xaf,0xb7,0x71,0x90,0x21,0x86,0x50,0x16,0xfc,0x2c,0x96,0x47,0x35,0x6d,0x85,0x49, - 0xdb,0x6,0xa4,0x7,0x55,0x86,0x48,0x9c,0xbb,0x49,0x1f,0x72,0xf9,0x54,0x13,0x2a, - 0xc,0x4,0xba,0xac,0x8b,0x8b,0x42,0x8,0xb7,0xd8,0xce,0x6d,0x46,0x55,0xb6,0xa1, - 0xda,0xdb,0xa8,0x31,0x62,0x70,0x4d,0x9d,0xb9,0xeb,0x10,0x34,0x40,0xa3,0x5e,0xcb, - 0x27,0x98,0xf7,0xb2,0x24,0x3a,0xbb,0x5c,0x92,0x8a,0xc9,0x58,0x5f,0x0,0xf9,0x3b, - 0xdb,0x22,0x6c,0xbe,0x93,0x39,0x5c,0xcc,0x25,0xec,0x1,0xe5,0x90,0xde,0x31,0x37, - 0xf7,0x2a,0xea,0x9b,0xe3,0x26,0xf7,0xf6,0xb0,0x41,0x4f,0x11,0xc1,0x4a,0xcb,0x9d, - 0xeb,0x38,0xdb,0xfe,0xf0,0x39,0x4c,0x16,0x26,0x4d,0x7b,0x36,0xac,0x2d,0x6d,0x24, - 0xd6,0xd7,0x3f,0xba,0xfd,0xb7,0xb1,0x2f,0xf8,0x81,0xbf,0xba,0x4b,0x8b,0xd8,0x37, - 0x43,0xb4,0x37,0x34,0x6d,0x83,0xc9,0x93,0x50,0x46,0x49,0x7c,0x73,0xb7,0x20,0x4a, - 0x8f,0x60,0x84,0xe,0x18,0xb6,0x3d,0x11,0x38,0xfc,0x4c,0x83,0x8,0xa4,0x3a,0x4b, - 0xd8,0xf0,0x7f,0x47,0xf3,0xc8,0xda,0x45,0x8e,0x25,0x41,0x81,0x5c,0x62,0x4b,0x6b, - 0xc2,0xd0,0x79,0xda,0x7,0x36,0x6b,0x3f,0xb2,0x37,0x42,0xba,0x5b,0x7c,0x85,0x35, - 0x6e,0x84,0x7c,0x62,0x4e,0xd6,0x27,0xdc,0x7b,0x69,0x5f,0xd7,0x4b,0xaa,0xc3,0x8d, - 0xfa,0xbc,0xe7,0x2,0xf3,0xd2,0xc0,0x26,0xb,0x3,0x61,0x66,0x80,0xe6,0x1b,0xee, - 0x6c,0x97,0xd0,0xba,0x6f,0xf8,0x17,0x6a,0xe1,0xf5,0x43,0x2d,0xa1,0x7,0x3a,0x1c, - 0x43,0x22,0x1f,0x37,0xf4,0x5f,0xdd,0x7f,0x63,0x3f,0x66,0xe3,0x26,0x81,0x52,0x92, - 0x99,0x23,0xcc,0x88,0x9b,0xe4,0xf2,0x7d,0xda,0xb5,0x2a,0xfb,0xbc,0x64,0x19,0x80, - 0x6,0xb7,0xb7,0xfb,0x17,0x15,0xfa,0x7a,0x54,0xe0,0xdd,0x7b,0x63,0xaf,0x8d,0x7c, - 0x53,0x5b,0x5,0xee,0x40,0xf7,0xec,0x9a,0xae,0x17,0x17,0xea,0xfb,0x30,0x6b,0x2, - 0x67,0xa3,0x7d,0x7e,0x38,0x79,0x79,0x8d,0x5a,0xd6,0x9,0x3d,0x7,0x96,0xb9,0xd9, - 0x71,0x3e,0x48,0x31,0xb6,0x35,0x4c,0x65,0xcc,0x63,0xcf,0xc8,0x93,0xbb,0x4a,0xfa, - 0xde,0xc8,0xf8,0x17,0xc1,0xf1,0x24,0x9b,0x49,0x2d,0x59,0x50,0x44,0x92,0x2a,0x35, - 0xd1,0x72,0x67,0x88,0x28,0xb3,0x6d,0x74,0x17,0xbc,0xbc,0x2a,0xf7,0x7,0xa4,0x56, - 0x4f,0x1d,0x6e,0x90,0x10,0x12,0xac,0x59,0xbf,0x6,0xa9,0x83,0x98,0x53,0xb8,0xe9, - 0x45,0x9f,0x72,0x6d,0x53,0x5f,0xe1,0xe9,0x9c,0x1e,0x93,0x94,0x26,0x38,0xeb,0xf4, - 0x56,0xd9,0x86,0xe5,0xeb,0x33,0x3f,0xab,0xb8,0x68,0x2f,0xd0,0xbb,0xe8,0xbb,0x80, - 0x88,0xad,0x6e,0x5c,0xe,0x50,0xc5,0x2a,0xee,0x5a,0xbe,0x15,0x12,0xaa,0xa,0xe7, - 0x4,0x10,0xcd,0xf0,0xc2,0xd,0x1c,0x7b,0x75,0x4c,0x4d,0xb0,0xb4,0x88,0x32,0xbc, - 0x36,0xa0,0x19,0xc3,0x70,0x5f,0xed,0x5f,0x39,0x2d,0xf3,0x4b,0xd7,0x7e,0x34,0x5c, - 0xe,0x2,0x4d,0xd1,0x10,0x69,0xcc,0x5,0x35,0x99,0x36,0xe9,0xa1,0xe7,0xa7,0xd8, - 0x8,0x40,0x1c,0x78,0x9f,0xb,0x58,0xd8,0x38,0xcb,0xa4,0x8f,0x4a,0xd8,0x6b,0xd8, - 0xda,0xb8,0xaa,0x6a,0xa2,0xf6,0xef,0x57,0x11,0xa5,0x42,0xb2,0x8d,0x69,0x8b,0x95, - 0xa9,0x28,0x8d,0xc9,0xb2,0x65,0x22,0x6a,0x32,0xc6,0x79,0xfb,0x1f,0xe5,0xd4,0x7a, - 0x1e,0xfe,0xe4,0xc0,0x76,0x54,0x19,0x87,0xf9,0xda,0x3a,0x87,0x44,0x46,0x9c,0x6d, - 0xed,0x2b,0x37,0xa0,0x90,0xd9,0xb,0x42,0x20,0x84,0x3f,0x40,0x6a,0x93,0xba,0x89, - 0x93,0x1f,0xc9,0xa,0x74,0x62,0x11,0xed,0xbc,0xca,0xf5,0x1,0x90,0x92,0xee,0x7e, - 0x3d,0xa5,0x1f,0xce,0x7f,0x2a,0x11,0xa0,0x2f,0xcf,0xe0,0x19,0x64,0x1b,0xa2,0xf7, - 0x3a,0xec,0x81,0xae,0xce,0x92,0x1d,0x8c,0xdc,0x13,0xd,0x6e,0x25,0xfb,0xec,0x63, - 0xa2,0xd,0xb1,0xa1,0xb6,0xc2,0x42,0x65,0x93,0xa2,0x7f,0x77,0xbd,0xa1,0x6f,0x78, - 0xe,0x70,0xa6,0xdd,0x82,0xc3,0x6a,0x5f,0x56,0x77,0xcd,0x7c,0xf3,0x3b,0xdf,0x96, - 0xc7,0x91,0x38,0x7e,0xd3,0xfa,0x64,0xe6,0x1d,0xe3,0x5e,0x5b,0x85,0x4d,0xd3,0x94, - 0x3d,0x7a,0xf1,0xbf,0xbe,0x5c,0x9f,0x15,0x53,0xec,0x11,0x47,0x28,0xf0,0x5d,0x6f, - 0x2,0x96,0xee,0x56,0x11,0xd2,0xbc,0xad,0xb6,0x9b,0x88,0xbb,0xe8,0x5c,0xcf,0xa6, - 0x57,0xc1,0xe5,0x95,0x9d,0x85,0xaa,0xf1,0xf2,0xbc,0xb8,0x9a,0x2d,0x17,0xb,0xaf, - 0x2d,0x79,0x85,0xbd,0x4c,0x42,0x6b,0x82,0xdd,0xf4,0x3e,0x47,0xd0,0x8e,0xed,0xa7, - 0x50,0xd3,0x3d,0x6e,0xd9,0xe8,0xdf,0xcc,0x25,0x98,0xe6,0xd1,0xaf,0xf1,0x1,0x5c, - 0x6b,0x6,0x1a,0x37,0x49,0x86,0xb9,0xa6,0xfa,0xf8,0x6d,0xcb,0x87,0x5b,0x74,0x57, - 0xaf,0xb1,0xc5,0x9,0x1a,0xa5,0xd5,0xbe,0xbe,0xbc,0x11,0x6e,0x2f,0x91,0x4b,0x9a, - 0x98,0x65,0xd2,0x61,0x6b,0x8c,0x8,0x66,0x5,0x76,0xb2,0xc,0x51,0xa6,0x64,0x80, - 0x58,0xa9,0x89,0xf2,0xcf,0xde,0x31,0x8e,0x9c,0xc1,0x7c,0x4b,0x54,0xc7,0x65,0x6c, - 0x2e,0xb7,0xcd,0x19,0x45,0x55,0x80,0xc9,0xcb,0xb2,0xd6,0x9d,0x59,0xba,0x1e,0x31, - 0x64,0xa8,0xa3,0x34,0x87,0xd5,0x42,0xa3,0x17,0xbf,0xee,0x6b,0x7,0x55,0x57,0xb4, - 0xd,0x25,0xce,0xd1,0x7b,0x4f,0x1c,0xc6,0x81,0xf2,0x64,0xda,0x2d,0x3,0xc,0x91, - 0xab,0xb0,0x46,0x33,0x6,0x8,0x57,0x1d,0x47,0x46,0x9,0x4f,0x1b,0x60,0x4,0xa8, - 0x86,0xd2,0xf9,0x81,0xa1,0x16,0xc7,0x23,0x9,0xac,0xfd,0xb5,0xaf,0x8a,0xc7,0x5b, - 0x3b,0x8d,0xe,0x41,0x95,0xe4,0xdd,0xdd,0x2c,0xe6,0x2d,0xc6,0x48,0xb0,0xee,0x4e, - 0x4,0xe9,0x4f,0xa5,0x0,0x17,0x49,0x89,0xc3,0xc6,0x3f,0xf2,0x51,0x7,0xcd,0xc, - 0x94,0xdc,0xcc,0xaa,0x41,0xab,0x88,0xec,0x92,0x35,0xb4,0xda,0x65,0xa3,0xa8,0x69, - 0x8d,0xf7,0x8f,0xe,0x10,0xd8,0x97,0x53,0x1f,0xd6,0x47,0x71,0x5e,0x15,0xfc,0x72, - 0x71,0x4a,0x1d,0x33,0xf5,0xa5,0x20,0x8,0x5a,0xd4,0x63,0xc0,0xf8,0xc,0xa9,0x6, - 0x5,0x39,0x14,0x94,0x12,0xab,0x67,0x32,0x3,0xae,0x23,0x61,0x44,0x9f,0xd3,0x35, - 0xe9,0x71,0x68,0x5f,0x17,0x89,0xe7,0xf1,0xdd,0x4b,0x32,0x56,0xd6,0xdb,0x5d,0xdb, - 0x16,0x71,0xef,0xa7,0x9d,0x58,0x59,0xa0,0x86,0xfb,0x81,0x4a,0x9c,0x55,0x0,0x6, - 0x46,0xe7,0xe5,0x5e,0xf0,0xcd,0xcf,0xcf,0x19,0x81,0x26,0xef,0x5d,0x83,0x4c,0xf2, - 0x75,0xbb,0x9b,0x13,0x14,0x74,0xb3,0x1b,0x71,0xb4,0x65,0x8d,0x89,0xe4,0x13,0xd0, - 0xcd,0xf8,0xae,0xbe,0xc6,0x7e,0x8e,0x5f,0x0,0x35,0xcf,0xdc,0x38,0x9b,0xd0,0x2d, - 0x57,0xeb,0x40,0xeb,0x60,0x73,0x7,0xd1,0x28,0xeb,0xde,0xb2,0xd1,0xf2,0x83,0x9f, - 0xeb,0xb1,0xdd,0x33,0x30,0xec,0x92,0xaf,0x22,0xe1,0x8c,0xd9,0x7d,0xdc,0x8,0xd5, - 0xc8,0xc7,0xc1,0xa9,0xbb,0x48,0x7b,0xe3,0x34,0xda,0x16,0x85,0xcd,0x19,0xa4,0x39, - 0xca,0x83,0x6c,0x7a,0x70,0x7f,0x2a,0x12,0x61,0x37,0xeb,0xdf,0x14,0x73,0x35,0x5d, - 0x3c,0xf6,0x7,0xf7,0xbe,0x2,0x5b,0x72,0xdc,0xf1,0xf8,0x2a,0xb,0x1d,0x64,0xd6, - 0xa0,0xd0,0xd0,0x11,0x50,0xfb,0x23,0x32,0xb2,0x8f,0x12,0x46,0x3,0x47,0xa3,0xbe, - 0xbd,0x2a,0x36,0x7c,0x2d,0x12,0x6e,0x89,0x4,0xe6,0xb4,0xf,0x5,0x98,0x65,0xa5, - 0x69,0x37,0x37,0x3a,0xb2,0xd9,0x6c,0x65,0xe8,0xfd,0xab,0xec,0xc4,0xcf,0x2b,0x82, - 0xf9,0xe1,0x7e,0xa6,0xf3,0x6c,0xb0,0xf7,0x54,0xe4,0x7,0x59,0x7d,0xec,0x7e,0x66, - 0x24,0x35,0xa0,0x56,0x10,0x8c,0x3b,0xf8,0xa,0x66,0x65,0xce,0x36,0x11,0xd0,0xb0, - 0xf2,0xce,0xd6,0xe6,0x3c,0x87,0xde,0x10,0x6c,0x65,0x69,0x69,0x52,0x67,0xd0,0xf5, - 0x9d,0xf0,0xcb,0xad,0x7e,0x7,0x26,0x8,0x6e,0x8c,0x57,0xa4,0x9d,0xa7,0xd4,0x10, - 0x77,0x2c,0xf6,0x33,0xb3,0x55,0x43,0xa0,0xba,0x2c,0x89,0x8d,0x93,0x5a,0x83,0x31, - 0x4c,0xcf,0x5e,0x4a,0xd6,0x85,0x52,0x45,0x91,0x29,0x6a,0xae,0xd1,0x3f,0xbe,0x49, - 0xea,0xb5,0xfb,0x9f,0xb,0x3f,0xbf,0x45,0x6b,0x49,0xd2,0x7e,0x24,0xd6,0x30,0x70, - 0xa6,0x8e,0x3a,0x7d,0x93,0x8c,0x43,0xa4,0xb6,0xad,0x53,0x88,0x6c,0x12,0x51,0x58, - 0x47,0x4d,0x77,0xd1,0xc,0xb6,0x18,0xf6,0x7f,0xea,0x75,0xa3,0x41,0xa5,0x93,0xe7, - 0xb4,0xcd,0xe5,0x48,0xda,0x29,0xed,0x91,0x56,0xc0,0x99,0x42,0xd3,0x6a,0x9a,0x9a, - 0xb7,0x91,0x6d,0x43,0x48,0x85,0x3a,0xc8,0xef,0x2f,0xeb,0xb1,0xd5,0x80,0x19,0xa, - 0x4e,0x7e,0xd1,0x29,0x27,0x3f,0x3a,0x7d,0x1,0x53,0xc0,0x54,0xbd,0xda,0xee,0xf4, - 0x6d,0xdb,0x38,0x35,0xe0,0xf1,0x7d,0x51,0x22,0x6a,0x3,0x77,0x6a,0x1c,0x1,0x38, - 0x9b,0xd2,0x62,0xc2,0x13,0x1c,0xc0,0x93,0x70,0x1,0xe7,0xad,0xdb,0x56,0xa3,0xc8, - 0x33,0x5b,0x7e,0x14,0xcd,0xfb,0xe4,0xef,0xe5,0xe7,0xe6,0x50,0x84,0xe7,0x89,0x9f, - 0xba,0x6b,0xe1,0x4d,0x87,0xa2,0xe0,0x77,0xa3,0x48,0x26,0x0,0x9f,0x49,0x48,0x52, - 0x24,0xc6,0x66,0xf1,0xc3,0xcb,0x61,0xa9,0xb3,0x48,0x7a,0xb7,0xaf,0x4,0x57,0x6b, - 0x6f,0x3a,0x38,0x76,0x5c,0x1a,0xee,0x80,0x62,0x94,0x80,0x81,0xdd,0xc8,0xd3,0x81, - 0x10,0xba,0x74,0x53,0x86,0xd5,0xfc,0x3a,0x9e,0xf6,0x72,0x4e,0xfa,0xc9,0x39,0xe9, - 0x83,0xf1,0x61,0xe0,0x8b,0xcf,0x61,0xed,0x64,0xe1,0xef,0xc1,0x2a,0xc3,0x43,0xb9, - 0xfd,0x37,0xd,0x84,0x8d,0xb,0x3f,0x2c,0x2,0xb1,0xf9,0x7d,0x7b,0xb3,0x67,0x7f, - 0xa5,0x48,0x60,0x31,0x18,0xc1,0x9e,0xfb,0x23,0x8e,0xbd,0xcc,0xd2,0x81,0x87,0xd0, - 0xb8,0x94,0x56,0x46,0x1f,0x95,0x72,0xa1,0xc6,0xec,0x1f,0xc1,0xa0,0x6,0x41,0x46, - 0x4f,0xa1,0x77,0xe6,0xe2,0x16,0xe3,0x6,0x25,0xa1,0xd3,0xf7,0x23,0xda,0x48,0xdc, - 0x6f,0x9e,0xa2,0xf,0xb3,0x16,0xb0,0xf9,0x82,0x4f,0xbc,0x23,0x55,0xfd,0x69,0x24, - 0x20,0x60,0xc,0x3,0xf5,0x6f,0x89,0x1b,0x11,0xdc,0x92,0xb4,0xb7,0xdb,0x11,0xa6, - 0xf9,0xb3,0xb5,0xae,0x49,0x66,0xa8,0xcb,0xb5,0xe4,0xee,0x8b,0xe3,0xd7,0xaf,0x83, - 0x38,0x3b,0x86,0xae,0xaa,0x8f,0xc9,0x3c,0x6c,0xdc,0x70,0x24,0xb8,0x81,0xcb,0xb2, - 0xb4,0x1,0xe0,0xfe,0x68,0x8a,0x4a,0x9d,0xee,0xb9,0xa8,0xd2,0x91,0xd8,0xd5,0x4a, - 0x14,0xdc,0xf8,0x3f,0x6c,0x42,0x7b,0xd9,0x1f,0x6b,0x7d,0xd7,0xec,0xc8,0xb,0x21, - 0xca,0xeb,0x20,0xb2,0xf5,0xea,0xcf,0xe5,0xa4,0x79,0x38,0xb5,0x52,0xf,0x7f,0xe5, - 0x6b,0xf7,0x25,0xd7,0x3b,0x20,0x31,0xd9,0x8b,0xaf,0x32,0xf7,0xf7,0x3d,0x1a,0x42, - 0xa8,0xb9,0xf4,0x9f,0xa4,0x45,0x5,0xc8,0xbe,0x3d,0xfe,0x90,0xcb,0x7e,0x76,0x37, - 0xf6,0x1c,0x8f,0xb1,0x3c,0xc0,0x8b,0x48,0x70,0xbd,0xbf,0xe8,0x7a,0xd9,0x2b,0x24, - 0x94,0xa0,0x43,0xb8,0xe5,0x48,0x2,0xa4,0x5,0x1,0xb4,0x51,0xfe,0x2b,0x8,0xf5, - 0x47,0x97,0xa7,0x4,0x59,0xb3,0xcb,0x49,0xf0,0x8b,0x32,0x6c,0x66,0xdd,0x10,0x7a, - 0x7e,0xd2,0xb2,0x64,0x9a,0xb4,0x88,0x9f,0x35,0x3d,0x70,0xb4,0xe7,0x79,0xaa,0x30, - 0x90,0xd2,0xb3,0xe9,0x6,0xfe,0xb3,0xf6,0x8a,0x65,0xe2,0x70,0x43,0xf2,0x6a,0xc1, - 0xc5,0x1e,0xa5,0x60,0x52,0x2e,0x80,0x8,0xea,0x70,0xbc,0xd3,0x69,0xe6,0x83,0xfa, - 0x39,0xb6,0x64,0x3f,0xb5,0x18,0x37,0x40,0x7e,0x1a,0x31,0x41,0x8d,0x9b,0x4,0x53, - 0x39,0x29,0x34,0x8c,0xd7,0x34,0x14,0xc2,0x24,0xd0,0x96,0x8e,0xb7,0x99,0x89,0x71, - 0x50,0xed,0xb0,0x6,0x86,0xe7,0xc6,0x84,0x82,0xf7,0xc5,0x10,0x13,0x49,0xe2,0x4d, - 0x73,0x17,0x59,0x4b,0xca,0x6d,0xe,0xef,0xbd,0x25,0x7e,0xf4,0x3e,0x87,0x66,0x8f, - 0xf4,0x18,0x15,0x7b,0x7f,0x5b,0x0,0x2,0xd2,0xc6,0x12,0xe6,0x8f,0x75,0xb3,0x3, - 0xc,0xd,0x4e,0xd7,0xf9,0xdc,0x47,0xb7,0x81,0x45,0xac,0xbf,0xcc,0x93,0xce,0x41, - 0xab,0x64,0xbd,0x2b,0x3f,0x3d,0xad,0x13,0x83,0x3f,0x79,0x14,0xb4,0x2d,0x17,0xc1, - 0x3a,0xe5,0x19,0xb3,0x42,0x60,0xea,0x43,0xa5,0x17,0x82,0xf1,0xaa,0xd1,0x33,0xd5, - 0x36,0x70,0x2,0x75,0x2e,0x2f,0x8,0xb1,0x6e,0x81,0x45,0xa3,0xae,0xdc,0x65,0x68, - 0xc2,0x7e,0x9b,0x84,0x5e,0x86,0xc7,0x4,0x9e,0x4a,0x75,0x49,0x1c,0xa8,0x20,0xd1, - 0x99,0xa1,0xc7,0xc7,0xd0,0xcf,0xf8,0xbe,0xd1,0x3f,0x62,0x0,0x1c,0x47,0x69,0x5e, - 0xc5,0x5,0x62,0x24,0x8c,0x2a,0xa7,0xaa,0xf3,0x9c,0xf3,0x90,0xc5,0x93,0x62,0x5f, - 0xb4,0x2a,0xa6,0x5,0x7a,0x9f,0xc4,0xcb,0xde,0xa6,0xcb,0x7a,0xee,0x35,0x58,0x34, - 0xba,0xba,0xd8,0xc6,0xe4,0x0,0x71,0x59,0x9d,0xe4,0xe9,0x63,0xf8,0x4c,0xc2,0xad, - 0xf6,0x69,0x33,0xf0,0x88,0x77,0xbc,0x68,0x1e,0x88,0x62,0x8c,0x3e,0xbb,0xc1,0xf8, - 0x76,0x1a,0xbf,0xdb,0x1a,0xb0,0x35,0xb7,0x15,0x1f,0x1b,0xe,0xea,0x5d,0x3c,0x61, - 0xc6,0x6f,0x52,0x50,0xe6,0xf,0x38,0x5,0x18,0x9a,0x12,0x56,0x56,0xd3,0x4f,0x4d, - 0xed,0x8e,0x29,0x87,0x3f,0xdd,0x40,0xd3,0x7c,0x5b,0xe2,0x67,0xb9,0x9e,0x49,0x0, - 0xe,0x9b,0xcf,0xf4,0x2b,0x8,0x79,0x43,0x23,0x8b,0x99,0xf8,0xde,0xe8,0xc5,0x4c, - 0xf6,0xee,0xd4,0xb5,0x4c,0x94,0x89,0xc8,0xef,0xeb,0xb0,0x29,0x8a,0xf9,0xa9,0x98, - 0x15,0x79,0xd,0x40,0x2,0x87,0x3,0xa4,0x92,0x9c,0x9d,0xf1,0x5,0x64,0x3e,0xfb, - 0xd2,0x92,0xb1,0x20,0x27,0xbb,0x68,0x97,0xa7,0x98,0xc0,0x33,0x92,0xe9,0x4b,0x28, - 0x64,0x59,0x68,0xe5,0x60,0xeb,0x8a,0xf2,0x88,0xa7,0xe4,0x8e,0xc,0xa3,0xa,0x5f, - 0xb5,0x3c,0xfe,0xdd,0xf7,0xe6,0x75,0x1f,0x80,0xb5,0xd1,0x13,0xa0,0x1e,0xba,0x84, - 0x77,0xa3,0x6a,0xd7,0x8f,0xf4,0x4a,0x18,0x9c,0x30,0x26,0x29,0x53,0xb0,0x8,0x9, - 0xec,0x86,0x66,0x64,0x6d,0xdb,0x3,0xed,0x12,0xd5,0x81,0x32,0xf3,0x3c,0xb6,0xea, - 0xdf,0xa0,0xc2,0x6f,0x95,0x8c,0x8,0xb1,0x3c,0x2e,0x5a,0x8f,0x5e,0xe1,0x99,0xca, - 0x68,0x7f,0x2f,0xd6,0xdb,0x33,0xc4,0xed,0x9,0x46,0x9f,0x7c,0x83,0x56,0x67,0x63, - 0x76,0xa9,0x53,0xc,0x36,0x5b,0x3d,0x73,0x9,0x18,0x3,0x68,0xf9,0x1c,0x33,0xe2, - 0x9c,0xe2,0xb9,0x78,0x95,0x7e,0xe5,0x1e,0x45,0x85,0x9a,0x48,0x5b,0x2,0xab,0xd1, - 0xab,0x7e,0x5d,0x61,0xd9,0x1a,0xd4,0xe3,0x32,0x58,0xcb,0xac,0x74,0xfe,0x8f,0x90, - 0xe1,0x49,0x88,0xf6,0x47,0x6e,0x15,0x8c,0x73,0xaf,0xd4,0xce,0x31,0x1,0xa0,0x5c, - 0x7f,0x7d,0xbe,0xd9,0x98,0x93,0x3d,0x4a,0xeb,0x9,0xf6,0xe0,0x87,0x86,0xf0,0xe9, - 0x4f,0x7a,0xe0,0x17,0x68,0xf6,0x23,0xdc,0xa6,0xf8,0xab,0x58,0x79,0xcc,0xb4,0x78, - 0xc9,0x73,0xd1,0x62,0x87,0xf,0xad,0xf2,0x97,0x24,0x53,0x20,0xab,0x45,0xa,0x7a, - 0xbf,0xea,0x91,0xa7,0x61,0xb5,0x84,0x88,0x2e,0xb0,0xe0,0x27,0x7d,0x95,0x1f,0x47, - 0x89,0xf1,0x2a,0x90,0x1,0x57,0x83,0x99,0x7b,0x57,0x39,0xa6,0x9c,0x43,0x22,0xdb, - 0xad,0x33,0x83,0x10,0xe8,0x88,0x98,0x96,0x39,0xf8,0x3d,0x36,0x8e,0x5d,0x7d,0x97, - 0x4f,0x27,0x28,0xcf,0x7e,0x2c,0xe8,0xfa,0x83,0x22,0xa1,0x9f,0x65,0x43,0xfa,0x93, - 0x77,0xfd,0x23,0xdf,0x86,0x3b,0xf6,0xbf,0x34,0x34,0xf5,0xc2,0x91,0xf3,0x5b,0x60, - 0x9a,0x3,0x31,0x1a,0x2f,0x1a,0x94,0x32,0x3d,0x36,0x51,0x22,0xf9,0x4c,0x35,0x71, - 0xca,0x58,0xd0,0x51,0x93,0xc7,0x91,0xc7,0xfc,0x7,0xb,0xe,0x7a,0xe5,0x6f,0x16, - 0x68,0xa0,0x30,0x18,0x3a,0xc4,0x4a,0xf6,0x7a,0x1c,0x1a,0x74,0xe7,0xce,0x65,0xb2, - 0x28,0x37,0x84,0x3b,0x7e,0x95,0x83,0xfa,0x9c,0x8e,0xa,0x18,0xf3,0x79,0xad,0x5c, - 0x99,0x5d,0x74,0xd3,0x22,0x3f,0xcb,0x1c,0x5b,0x65,0x11,0x43,0x34,0xf5,0x76,0x5c, - 0xac,0xfa,0x18,0x2c,0x90,0x9b,0x27,0xac,0xa9,0xb0,0x44,0x1d,0x2a,0xf1,0xf8,0xc3, - 0x4f,0x6e,0x98,0xf0,0x2d,0xe3,0x8d,0x8,0x49,0x9e,0x4b,0x7d,0x94,0x41,0x5a,0xc1, - 0x3c,0x72,0xed,0x4c,0xe,0x94,0xf9,0x37,0x46,0x3e,0x54,0x70,0xb0,0x4d,0xb4,0x7f, - 0x3b,0xcc,0x71,0xe7,0xb0,0xfe,0xef,0xf9,0x1d,0xbb,0x77,0x31,0xfc,0xd1,0xf2,0xb9, - 0xc3,0x60,0x6,0x51,0xf5,0x7f,0x88,0xbb,0x3e,0x5c,0xab,0xee,0x2a,0x60,0x6e,0xe4, - 0xac,0x5f,0xcd,0x5d,0xdd,0x3d,0x57,0x7a,0x78,0x4f,0xac,0x76,0xa0,0x1f,0x30,0x65, - 0x0,0xb5,0xb6,0x75,0x36,0xbf,0x31,0x74,0x1c,0xdc,0x63,0xc5,0xbd,0x51,0xab,0x6a, - 0xb1,0xf8,0x48,0xf,0xb5,0x9f,0x8a,0x2f,0x6e,0xb6,0xa5,0x10,0x55,0x55,0x75,0x55, - 0xb,0xab,0xca,0xc0,0x6b,0x7b,0x35,0x8,0xd8,0x18,0x4d,0x96,0x6a,0xf8,0x80,0x9b, - 0x71,0xc8,0xaa,0x28,0xe8,0xb4,0xd6,0x57,0xea,0xfb,0xe6,0x41,0x51,0xdb,0x16,0xdb, - 0x88,0x61,0x9d,0x73,0xdc,0x52,0x7b,0x35,0x6b,0xc9,0x4b,0xd5,0x42,0xcc,0xf0,0x34, - 0x15,0x1b,0xdb,0xfd,0xd0,0xb2,0xd5,0x3b,0xae,0xbc,0x7c,0x0,0x19,0x13,0x5b,0xa1, - 0x74,0x78,0x15,0xd0,0xcb,0x11,0x7,0x37,0x5a,0x52,0x8c,0x1c,0x9e,0x7d,0x50,0xb4, - 0x98,0x2c,0x32,0xe8,0xde,0x87,0x25,0x8d,0xc4,0x21,0xd,0xdd,0xb3,0xe8,0x7f,0x28, - 0x61,0x14,0x79,0xac,0xa4,0x80,0x63,0x7e,0x52,0xef,0x9b,0xf1,0xec,0xeb,0x26,0x86, - 0x98,0x58,0xee,0xf6,0xe0,0x93,0x5,0x25,0xb5,0x12,0x3,0x69,0x7a,0x2,0x12,0x5c, - 0x16,0x8b,0x9,0x3b,0x8b,0x6d,0xb9,0xdd,0xdc,0x55,0x4f,0xca,0xc1,0x75,0x51,0x5a, - 0x4e,0xbf,0xd0,0xae,0x54,0xd5,0xd3,0x89,0x68,0xd6,0xf2,0xe2,0xd8,0x84,0x3f,0x6e, - 0x8f,0x49,0xa9,0x1b,0x36,0x64,0x79,0x13,0x39,0x48,0xdd,0xfa,0xbe,0xae,0xd4,0x8c, - 0x6f,0xa6,0x3b,0xc3,0x7c,0xf,0x4d,0xe4,0x65,0xbf,0x48,0xbd,0xc4,0x87,0x2c,0x54, - 0x50,0x56,0xef,0x86,0xba,0xe8,0x9a,0xf3,0x31,0xf7,0x6f,0x6f,0xa7,0x44,0xfb,0x17, - 0x6a,0xb6,0xda,0x67,0xc5,0xa7,0xcb,0xaa,0x67,0x14,0x68,0xab,0x9c,0x95,0x1,0x6c, - 0xeb,0xf0,0xf3,0x26,0x59,0xe,0x99,0x8a,0x6,0x9,0x7a,0xad,0xcd,0x76,0xc4,0xb7, - 0x2e,0x1f,0x9e,0x73,0x46,0x6b,0x1f,0x2e,0xfe,0x7,0xd9,0x1b,0x1c,0xda,0x88,0x87, - 0x4b,0x7c,0xad,0x24,0x8a,0xc7,0xaf,0x90,0x50,0x2a,0xbe,0x1e,0x20,0x3,0x56,0xcd, - 0x23,0xf4,0x42,0xe8,0xdf,0xe0,0x17,0xdf,0x67,0x71,0x7a,0x84,0xcb,0x3,0xc,0x18, - 0xfe,0x3a,0x3c,0x89,0x2,0x6b,0x9a,0x52,0x15,0x59,0xf0,0x36,0xdb,0xc6,0x4,0xfe, - 0xbb,0xc5,0x68,0x1c,0x26,0xfe,0x7b,0x8e,0x70,0xf5,0x13,0x3d,0xf9,0x1f,0xd4,0xf8, - 0xd8,0x90,0x3,0xda,0xfc,0x1d,0xad,0x12,0xf5,0x9e,0xc7,0xd1,0x65,0xcc,0x51,0xa0, - 0x12,0xb9,0xbc,0x39,0xb8,0xb7,0xc7,0x2a,0xae,0xda,0xe6,0x28,0x79,0xbb,0xa0,0x53, - 0x4c,0xa3,0xad,0x49,0x40,0x5b,0xdb,0x36,0x79,0xa3,0x88,0xde,0xef,0xd9,0x0,0x3, - 0x13,0x3c,0xbb,0xcb,0xf4,0x83,0x75,0x23,0xdd,0x5c,0x4b,0x57,0x18,0xeb,0x2a,0xe4, - 0x10,0x58,0x2e,0x50,0xb3,0x89,0x7,0x2e,0xad,0x8f,0x8c,0x1d,0xe8,0xc,0x9f,0xfb, - 0x49,0x5b,0x47,0xbd,0xde,0xbd,0xe0,0xbc,0x99,0x2c,0x94,0x32,0x97,0x3e,0x17,0xa7, - 0x96,0xc4,0x78,0xca,0x4f,0xfe,0x78,0x7c,0xe,0x84,0x99,0xf6,0x91,0x3a,0xf2,0x5a, - 0x95,0xb9,0x18,0xf4,0x77,0xf8,0xb1,0x91,0xa4,0xc5,0xc3,0x3c,0x84,0x5a,0x64,0x1b, - 0x1f,0x5c,0x65,0xed,0xda,0xdd,0xe9,0xe8,0x63,0x84,0x5f,0x74,0xbe,0xd1,0xce,0xd3, - 0x8b,0xe6,0xc8,0x4,0x5f,0xfa,0x15,0x4,0x40,0x58,0xbf,0xc4,0xb2,0xa3,0xe0,0x51, - 0x0,0xc5,0xbf,0xda,0xa4,0xa9,0x43,0x87,0x2e,0xa2,0xfb,0x6c,0x74,0xca,0xc0,0x1, - 0x31,0x89,0x84,0x90,0x4,0x99,0x14,0x45,0xf1,0x53,0x89,0x24,0xf7,0xe9,0x75,0xf7, - 0xb0,0x35,0x53,0x55,0xdf,0x96,0x5c,0x8d,0x3a,0x58,0xfa,0x2e,0xa2,0xbb,0x2f,0x53, - 0xc4,0xb3,0x63,0x49,0xcc,0x77,0xe,0x3e,0xca,0x97,0x62,0xc2,0x82,0xd8,0x3b,0x33, - 0xe,0xe,0x8,0x6d,0xa4,0x64,0xfb,0x5e,0x3c,0x76,0xd,0x5e,0xb1,0x3c,0xb1,0xf5, - 0x70,0x15,0x3f,0x3d,0xc,0x4d,0xfb,0x56,0xe5,0x5e,0x99,0x68,0x37,0xd4,0x1b,0xc5, - 0xe2,0xa2,0xb2,0x7,0x7,0x2e,0xe5,0xc2,0xa4,0xf2,0x21,0xd5,0xae,0xd2,0xcc,0x1f, - 0x67,0x8b,0xdc,0x73,0xd9,0xd8,0xc9,0x3f,0x37,0x63,0xa7,0xee,0xb7,0x42,0x34,0x1a, - 0xe4,0xe6,0xa1,0x6b,0x16,0x87,0x2e,0x3a,0xf9,0x4f,0x90,0xa8,0xa1,0xdc,0xc8,0x9, - 0x68,0x25,0xfb,0x42,0xfd,0xc5,0x81,0xb4,0xa9,0xa8,0x23,0xe0,0x6a,0x57,0xfb,0xce, - 0xbe,0x1d,0x3a,0x54,0xa4,0xe7,0xe,0x9e,0x37,0x9e,0x47,0x58,0x7b,0x8f,0xe0,0xe4, - 0xb4,0xdc,0xa6,0x32,0x23,0xa8,0x67,0xcc,0xd0,0x8a,0x2d,0x3c,0x62,0xa8,0xb,0x21, - 0xc5,0xc5,0x75,0xe9,0xad,0x83,0x88,0x65,0x23,0x50,0xbd,0x1e,0x5f,0x9f,0x82,0x15, - 0x7c,0xa9,0xc6,0x1f,0x52,0x2e,0x6b,0x23,0x39,0x99,0xde,0x9b,0x42,0xea,0x3c,0x88, - 0xb0,0xb1,0x72,0x5e,0xb4,0x7b,0x43,0x57,0xcb,0x2,0x76,0x2b,0x21,0x78,0xbf,0x1d, - 0x22,0x7,0x3d,0x74,0xb4,0xa8,0x18,0xed,0x42,0xf6,0x9,0x5,0xe1,0x45,0x8d,0x12, - 0xf6,0x0,0xf0,0xac,0x7b,0x34,0x4,0xc6,0xb5,0xf9,0x72,0xd6,0x73,0xb1,0xf4,0x95, - 0xb8,0x32,0x8a,0x6e,0x5a,0xa2,0xdb,0x1d,0x19,0xe5,0xa1,0x7b,0x2b,0x2f,0x8d,0xa2, - 0xae,0x7e,0x4f,0xaa,0x33,0xd2,0xf0,0xe8,0x4d,0x63,0xc0,0xc0,0x95,0x35,0xd5,0x4e, - 0xe6,0xdf,0x3c,0x41,0x2,0x19,0xdd,0x1c,0xfe,0x7f,0x97,0xa9,0xae,0x25,0x4c,0xdd, - 0x24,0x1b,0x8,0xd6,0xee,0xf8,0xbf,0xbb,0xdc,0x0,0xfb,0x72,0x35,0x51,0x40,0x9b, - 0x32,0x7d,0xdd,0x34,0x16,0xbb,0x50,0x94,0xbb,0x67,0x3e,0xe9,0xd,0x8b,0xc7,0x31, - 0xa6,0x4f,0x87,0x15,0xc8,0x47,0x50,0x25,0xc7,0x4c,0x17,0x7c,0x9e,0x57,0x19,0xd0, - 0x54,0x76,0x84,0xe9,0xb1,0x55,0x7e,0x6d,0xbc,0xbd,0x58,0xc9,0xc8,0x9f,0x7a,0x6f, - 0xef,0x2,0x5,0xb8,0xc9,0x55,0xdd,0x91,0xa2,0xf4,0xe,0xc0,0xcb,0xa6,0x11,0xa0, - 0x1d,0x95,0x8a,0xcf,0xea,0xa,0x3d,0x28,0xc7,0x15,0xf1,0x10,0xb5,0x6d,0xfe,0xa5, - 0xee,0x4,0xdd,0xb8,0xd9,0x3b,0xc9,0xfb,0x30,0x58,0xbc,0x7b,0xfe,0xcd,0x1c,0x9c, - 0xe2,0xa7,0x6c,0xce,0xb1,0x29,0xf6,0xf8,0x3f,0x68,0x9,0x74,0x55,0x87,0x1a,0x45, - 0x8c,0x77,0x7d,0xe5,0xb2,0xc7,0xe1,0x62,0x9f,0x1e,0xdd,0x9e,0xeb,0xfa,0xba,0x4e, - 0x22,0x27,0x1d,0x53,0xd0,0x93,0xcb,0x10,0x7c,0x54,0x4,0xd1,0xdb,0x1e,0x96,0x68, - 0x15,0x15,0xcd,0xc7,0x5c,0xaf,0xa9,0xfb,0x4d,0x87,0x1a,0xb8,0x2,0xd5,0x8,0xa3, - 0x7c,0x25,0xf6,0x4d,0x39,0xc2,0xdc,0xb5,0x17,0xe0,0x7,0xf3,0x7e,0x9e,0xdb,0x93, - 0x33,0xaa,0xda,0x8f,0xd9,0x84,0xb,0x28,0x8c,0x25,0xe0,0x8e,0xfa,0xe8,0xb2,0x78, - 0x8e,0xa9,0x45,0x47,0xec,0x23,0xfc,0x4,0x83,0x83,0x77,0x3,0x22,0x54,0x96,0x55, - 0x7e,0xf1,0x64,0x58,0x76,0x6f,0x0,0x3,0x95,0xe1,0x12,0x10,0x4a,0xc4,0x8,0xd8, - 0x6e,0x4e,0x20,0x5b,0x71,0x9c,0xdf,0x74,0x21,0x57,0x77,0xc2,0x2b,0x8e,0x19,0xa9, - 0x80,0xfc,0x82,0xf6,0x6d,0x82,0xfa,0x82,0xe3,0xd,0x92,0x2f,0x51,0x9b,0x87,0xbf, - 0x69,0xa8,0x9b,0x5a,0xc4,0x7b,0xce,0x65,0x52,0x47,0x29,0x7e,0xd5,0xc1,0xa7,0x56, - 0xbe,0xa9,0xcc,0xab,0x2d,0x47,0x2e,0x90,0xd3,0x41,0xbf,0x25,0x5c,0x48,0x65,0xc5, - 0x70,0x1,0x20,0xb4,0xfb,0xee,0x1b,0xcd,0x36,0xc3,0x4c,0x8b,0x85,0x74,0x61,0xc3, - 0x1e,0x2f,0x70,0xca,0xf5,0x1e,0x5c,0xca,0x5f,0x9b,0x6f,0xbb,0x63,0xd4,0x81,0xd3, - 0x55,0xa1,0x9,0x51,0x11,0x24,0x20,0x47,0xe7,0xeb,0x53,0xec,0xdf,0xb4,0x30,0xfe, - 0x63,0xa0,0x49,0x5a,0x3f,0xa5,0x25,0x9e,0xc1,0x94,0xda,0x25,0xe9,0xdb,0x79,0x3f, - 0xfd,0x82,0x11,0xf,0xa6,0xb0,0xd5,0xe,0x9c,0x29,0x7a,0xfc,0xde,0xaa,0xfb,0xc1, - 0xcb,0xc4,0x1c,0xb,0x6b,0xc0,0xa9,0xac,0xd5,0x4,0xd1,0xbf,0xe0,0x4b,0x7e,0xde, - 0x4d,0x8f,0x6d,0xf3,0x40,0x43,0x81,0x5d,0xec,0x7b,0x5a,0xcb,0x27,0xd5,0xd,0xf2, - 0x9a,0x2a,0x7d,0x85,0x6a,0xa6,0x32,0xbf,0xab,0x84,0xfe,0xc,0x4f,0x7e,0x6a,0x9d, - 0x8d,0xd7,0x11,0xce,0x9a,0x13,0xab,0x87,0x8e,0x6,0xd2,0x35,0x5b,0xe0,0x28,0xf5, - 0x8a,0x25,0xfb,0xf4,0xcc,0x2e,0xb5,0x78,0x32,0xb4,0x84,0x82,0xb2,0x6e,0x20,0x41, - 0x46,0x31,0x8f,0xe0,0xc3,0x3b,0x69,0x53,0xc0,0x3c,0x88,0x1c,0x1d,0x31,0x91,0xa7, - 0x56,0x8d,0x1d,0x23,0x3c,0x52,0x1b,0x6e,0x7,0x1f,0x70,0x3a,0x8d,0x10,0x7b,0x53, - 0x42,0xb,0x35,0x6,0xc5,0x1e,0xd8,0x86,0xd9,0x62,0x22,0xf7,0x13,0x33,0x1f,0x69, - 0x41,0xbb,0xd,0x7d,0xe,0x28,0x6b,0x95,0xc7,0x5c,0xcf,0x55,0x6c,0x4b,0xa9,0x2e, - 0xd5,0x5e,0xb4,0x9b,0x7c,0x8d,0xa1,0x56,0x6f,0xc3,0xcd,0x82,0x76,0x6d,0xec,0xb7, - 0xa8,0x79,0xb4,0xb7,0x21,0xa0,0x4d,0xe8,0xfc,0x9c,0xbe,0x69,0x67,0xe7,0x98,0x3d, - 0x46,0x4d,0x58,0x42,0xda,0xf9,0x18,0xca,0x3d,0x66,0x4d,0x33,0x53,0xb9,0xeb,0xfb, - 0x33,0xa0,0xb3,0x55,0xc0,0x80,0xbd,0xbd,0x1d,0x7c,0x28,0x4,0xe3,0x40,0x41,0x2a, - 0xd,0x19,0xeb,0x67,0x92,0x84,0x32,0xcf,0xea,0x80,0x4,0x3e,0xb9,0x6f,0x3a,0xed, - 0x8f,0x6e,0xc2,0x51,0x6e,0x0,0x8e,0x8c,0x7d,0x36,0x10,0xe0,0x76,0xd1,0xc,0x83, - 0xea,0x77,0xeb,0x7e,0xfb,0x1e,0xcd,0x66,0x1e,0x51,0x24,0xd8,0xc0,0xde,0x46,0x51, - 0x4d,0x88,0x22,0xbb,0x88,0xb0,0xc7,0x85,0xe7,0xd8,0x67,0x5e,0x2a,0xf2,0x62,0x15, - 0x6a,0xcd,0x13,0xe6,0x6b,0xe1,0xcc,0x8a,0x33,0xf1,0xe2,0x74,0xd0,0xa8,0xc5,0x9d, - 0x31,0x67,0x59,0x39,0x18,0xa1,0xbf,0x0,0xf9,0xa6,0xde,0x24,0x99,0x41,0xb8,0x83, - 0x8e,0xcc,0xe9,0xf9,0xae,0xb7,0x84,0x61,0x29,0xe6,0xd5,0xf9,0x8f,0x1b,0x97,0x40, - 0x82,0x70,0x7a,0x1b,0x91,0xb9,0x1b,0x8b,0x60,0x79,0xaf,0xf9,0xba,0x69,0xfc,0x49, - 0xb5,0xe7,0xc3,0x64,0x1f,0xc7,0x45,0x48,0xaf,0x9b,0x42,0xbe,0xb6,0x59,0x0,0xb9, - 0x49,0xf9,0xd4,0xdb,0xb3,0x6f,0x67,0x14,0xe9,0x97,0x8d,0x24,0x80,0x8a,0xed,0x36, - 0xf1,0xb1,0x1a,0x11,0x79,0x5f,0x59,0xa8,0xfa,0x1b,0x68,0x32,0x74,0xe7,0x6b,0xbe, - 0x61,0x40,0x9a,0x15,0x2f,0x81,0xa8,0x19,0x19,0x36,0xbd,0x99,0xc0,0xab,0xcf,0x33, - 0xdc,0xe9,0x44,0x56,0xc9,0x9e,0x7f,0x44,0xb9,0x67,0x76,0xae,0xce,0x61,0x6d,0x30, - 0x21,0x87,0x45,0x51,0x88,0xed,0xe9,0xa2,0xa3,0xa7,0xbb,0xe3,0xd2,0xc,0x17,0xaf, - 0x75,0x5c,0x86,0x3f,0xfa,0x85,0x4,0x34,0xec,0xf9,0xe2,0xbb,0x5c,0xcf,0x6b,0x7d, - 0xd6,0xb0,0x4e,0x60,0x1e,0x39,0x82,0x41,0x60,0xbd,0x25,0x34,0xc9,0x3d,0x63,0x40, - 0x99,0xe9,0xfe,0x14,0xee,0x3,0xc7,0xdb,0x7d,0x2b,0x17,0xd9,0xfa,0x82,0xd6,0x52, - 0xb2,0x26,0x32,0x50,0xde,0x34,0x91,0x3f,0xf1,0xb7,0xf2,0x3c,0xf4,0x57,0xfb,0xe, - 0xc0,0xfa,0x22,0xb0,0x7e,0x69,0xc,0xfb,0x94,0x24,0x55,0x10,0x26,0x2c,0x62,0xd9, - 0x52,0x14,0xa9,0x31,0x48,0x3c,0xf0,0xb9,0xf3,0xe3,0xf5,0x68,0xba,0xf1,0x76,0xfb, - 0x6d,0x18,0xac,0x6b,0x81,0x38,0xe6,0x96,0xdb,0x3c,0xa6,0x3,0x68,0x88,0x5c,0x3b, - 0x9c,0x6,0xeb,0x64,0x42,0xdc,0x9d,0xb5,0x41,0x94,0x1e,0xfb,0x6,0x14,0xf7,0xf2, - 0xab,0x24,0x5e,0xad,0x5d,0xc4,0x44,0x39,0x1,0x6a,0xbb,0xe9,0xf2,0x18,0xa4,0xf, - 0x1f,0x90,0xf2,0xe0,0xed,0x90,0x97,0x2f,0xa4,0x35,0x2b,0x2b,0xc9,0xa3,0x1e,0x75, - 0x47,0xfc,0xa2,0x24,0x41,0x66,0x5e,0xc2,0xd0,0x99,0xac,0xc3,0xb2,0xd0,0x52,0x51, - 0x61,0x45,0x32,0xce,0x56,0x49,0xfd,0x7a,0x7f,0xa9,0xa5,0xc8,0x4d,0x44,0xbd,0x14, - 0xc0,0x61,0x39,0x81,0xc7,0x17,0x44,0x99,0xb0,0x70,0xdc,0xe2,0x41,0xaf,0x34,0x23, - 0xf4,0xe6,0xf1,0xca,0x30,0x70,0x46,0x2f,0x1a,0x6b,0xf7,0xe6,0x2f,0xb6,0xfa,0x6f, - 0x18,0x34,0xf1,0x5f,0x4b,0x36,0x78,0xfc,0xa7,0xd5,0xdf,0x68,0x85,0x94,0x8b,0xf9, - 0x7b,0xfd,0xc5,0x2b,0x6e,0x8b,0x5b,0x8,0x76,0xd2,0xee,0x26,0x89,0x69,0x95,0x21, - 0x9e,0x7,0x1,0x69,0xbd,0x79,0xe5,0x65,0x4f,0x46,0x4d,0x54,0xda,0x59,0x4f,0xd5, - 0x57,0x94,0x1,0x45,0x9f,0xdb,0x4d,0x16,0xaf,0xbb,0x3c,0xb8,0x25,0x52,0xda,0xc3, - 0xd8,0x5b,0x2e,0x96,0x54,0x14,0x7b,0xa4,0x5a,0xc9,0x78,0xb4,0x23,0xc7,0x8a,0xf9, - 0xdb,0xc,0x3f,0x7b,0xe7,0xc,0x12,0x97,0xc7,0xcd,0xd0,0xec,0x20,0x2b,0x31,0xf9, - 0x86,0x5f,0x90,0xda,0xf2,0x8c,0xfe,0xcd,0x56,0x78,0x82,0xf8,0xbf,0x8d,0xf2,0x9c, - 0x99,0xb1,0x97,0x81,0xbd,0xa9,0x99,0x5,0x78,0x6a,0xf1,0x18,0x95,0x23,0x12,0x9b, - 0x2,0x23,0x76,0xf5,0xaf,0x76,0x43,0x85,0x6e,0xc5,0x7e,0x2e,0x53,0xf0,0x4a,0xec, - 0xa2,0xe2,0xee,0xdf,0xc,0x8,0xe4,0x84,0x72,0x56,0x9d,0x87,0xf9,0x2f,0x23,0xfb, - 0xd1,0x99,0x71,0x1,0x8f,0xb4,0x86,0xfd,0xfa,0x84,0xac,0x4e,0x75,0x76,0xbb,0x97, - 0x59,0x2a,0x77,0xe5,0x32,0xdb,0x6a,0xa4,0xb2,0x87,0xab,0xac,0x37,0xce,0xa8,0x88, - 0xe7,0x9a,0x8a,0x78,0x4f,0x90,0xf5,0x4a,0x16,0xa2,0x19,0xb,0x1a,0x54,0xa3,0xf2, - 0x7e,0x9a,0xd8,0xb0,0xf6,0xc3,0x55,0xa9,0x4b,0x1,0x56,0x2,0x4f,0x7e,0x8b,0x37, - 0x19,0x16,0xaf,0xe8,0x26,0x26,0xb2,0xbb,0xc8,0xcb,0xc7,0x62,0x20,0xea,0x56,0x1e, - 0x5,0xae,0xce,0xfb,0x72,0x24,0x25,0x3e,0xa4,0xfa,0x40,0x73,0x7a,0x4b,0xab,0x13, - 0xe0,0xda,0x7b,0x8,0x1,0x2f,0xc3,0x4a,0x7a,0x8b,0xac,0x1b,0xf5,0x3,0x39,0xfb, - 0x32,0x9,0xf7,0xa4,0xac,0x1e,0x62,0xd1,0x98,0x23,0x45,0x13,0x6e,0x70,0xa6,0x50, - 0x4c,0x22,0xd7,0x4d,0xd0,0x9b,0x97,0x4c,0xa7,0xc4,0xe6,0x9d,0x47,0x20,0x19,0x79, - 0xa8,0x12,0x1f,0xd5,0xaf,0x1,0xa7,0x48,0x24,0x6c,0xdb,0x93,0xdd,0x2,0x63,0x2a, - 0x24,0x3b,0xf6,0xf5,0x56,0xf,0xc1,0xfd,0xd3,0xa8,0x1c,0x1b,0x48,0x35,0x15,0x71, - 0xc6,0x34,0x47,0xf5,0xb4,0x6e,0xbe,0xd9,0xda,0x9a,0xec,0x38,0x9c,0xcf,0xe1,0x40, - 0xb,0xd9,0xb5,0xe0,0x68,0xf6,0xdf,0xbb,0x9f,0x7b,0x56,0x68,0xb0,0x6b,0xd9,0xf7, - 0x1f,0xa0,0xed,0xd4,0xf,0xac,0x2e,0xe9,0xc6,0x1b,0xa2,0xe2,0xea,0x84,0x24,0x75, - 0xdd,0x59,0x56,0x46,0x51,0xb5,0x81,0x70,0x31,0x58,0xd8,0x62,0xc3,0x32,0xd9,0x63, - 0xd2,0xc7,0x38,0xe1,0xf4,0xe5,0x4c,0x3b,0x1,0xee,0x1f,0x6b,0x73,0xc2,0x60,0xd1, - 0x1c,0xb6,0x97,0x6d,0xec,0x1a,0x5e,0x1e,0x72,0x37,0x0,0xb5,0xe9,0xd9,0x19,0xbc, - 0x22,0xd0,0x1f,0x96,0x36,0xea,0xd1,0x37,0xd9,0xf0,0x22,0xcc,0x33,0x82,0x9e,0x50, - 0xb9,0xb6,0x3d,0xa6,0xd0,0x9b,0x44,0xc2,0x53,0x45,0xf7,0x3d,0x9e,0x91,0x79,0x40, - 0xe1,0x98,0xd6,0x19,0x83,0x29,0x50,0xdc,0x99,0xf2,0x2a,0xcd,0x75,0x48,0x9d,0x2f, - 0xfe,0xda,0xd5,0x4f,0xf6,0x9a,0x91,0xc9,0x5f,0x8a,0x86,0xfd,0x1c,0x0,0xbe,0xfd, - 0x19,0x15,0x17,0x9c,0x3e,0xe7,0xf9,0xd8,0x5a,0x24,0xa6,0x4f,0xeb,0x44,0x7f,0xeb, - 0x9e,0xd4,0x3b,0x15,0x6f,0xcd,0xde,0xce,0xd7,0x65,0x4d,0xf3,0xe5,0x8b,0x71,0xfe, - 0x20,0x9,0x1b,0x5f,0x70,0x94,0xb7,0xca,0xb8,0xdd,0x99,0xa5,0xa1,0x19,0x11,0xbf, - 0x6e,0xcb,0xd5,0x5d,0x99,0x34,0xac,0xf0,0x1a,0x79,0x64,0x0,0x84,0xd6,0x7e,0xa4, - 0x5f,0x99,0x4,0x4f,0x2f,0x3b,0x99,0x67,0x98,0x33,0x8c,0x3a,0xcc,0x9d,0xfa,0x3b, - 0xe9,0x50,0x18,0x83,0x84,0x44,0xf4,0x9e,0xbd,0x59,0x1e,0x42,0x30,0x9c,0xe7,0xf, - 0x37,0x6b,0x5e,0xe5,0x27,0xf7,0xcc,0xbf,0xab,0x5a,0xfa,0x78,0x77,0x75,0x33,0x61, - 0xc5,0x4b,0x65,0xc9,0x90,0x5a,0xe8,0xcd,0xb3,0x7,0x90,0x64,0xa4,0xf7,0xf2,0x5b, - 0xe2,0x52,0xc0,0xa,0xc9,0x8d,0xca,0x75,0x67,0x45,0xed,0x5f,0x3a,0x21,0x40,0x7f, - 0xec,0x25,0x49,0xfc,0xfe,0xb1,0xca,0x33,0xb9,0x5b,0x97,0xdd,0xd2,0xa,0x39,0xb6, - 0xdb,0xf9,0xc0,0xa6,0x7,0xb,0x9b,0x6f,0xcf,0xa,0x4e,0x89,0xaa,0x8e,0x9,0x97, - 0xb4,0xd2,0x14,0xb3,0x84,0xdf,0x66,0x3e,0xba,0xfd,0x9b,0x8e,0x88,0xd4,0x45,0x64, - 0x4e,0x85,0xb,0x56,0x11,0x27,0x45,0x60,0x31,0x13,0xea,0xdb,0xa1,0xf3,0xf3,0xd5, - 0x46,0x8,0xa,0xcb,0x67,0x70,0x89,0xa2,0xee,0x26,0x31,0x77,0x7a,0xf5,0xdb,0xc9, - 0xfa,0x67,0x9f,0x8b,0x8e,0x64,0xec,0x3f,0x77,0xd7,0x9a,0x19,0x4b,0xe,0x6f,0x92, - 0x96,0x79,0xdd,0xfd,0x69,0xe6,0x20,0x58,0x8c,0x51,0x4f,0x8,0xc6,0x2c,0x51,0x42, - 0x13,0x70,0xcd,0xa1,0xd4,0xba,0x60,0xcb,0x12,0xfa,0x64,0x5e,0xa,0xd3,0x70,0xa0, - 0xcc,0xcd,0x1e,0x37,0xb4,0x3f,0xf,0xc1,0x10,0x5f,0x49,0x57,0xb,0x1a,0x99,0x1e, - 0x8a,0xe6,0x3f,0xde,0x22,0x9f,0xaa,0x34,0x9a,0xf,0x12,0x24,0x63,0x82,0xc4,0x30, - 0xcf,0x63,0xe6,0x5,0xa2,0x76,0xc6,0xb2,0xd5,0x10,0xa,0x60,0x2a,0x23,0xfd,0x34, - 0xb,0x3d,0x13,0x2d,0x5c,0xbd,0x61,0x76,0x4c,0xf3,0x9b,0xaf,0xf5,0xdf,0x60,0xc6, - 0x43,0x47,0xcb,0xe5,0x3d,0x92,0x99,0x13,0x22,0x23,0xf2,0x4c,0x47,0xf0,0x80,0xd1, - 0xad,0x13,0xfe,0xa,0xd0,0xdf,0x81,0x9c,0xd3,0x1d,0x4d,0xca,0xfc,0xad,0x11,0xc0, - 0x74,0xdc,0xa6,0xb2,0xee,0xbf,0x45,0x11,0xe3,0xb8,0xdc,0xaa,0xa9,0xdc,0x7c,0x58, - 0xef,0xfa,0xe1,0x40,0xda,0x63,0xdc,0x2f,0x0,0xa9,0x79,0x7d,0xd6,0x8a,0x3e,0xcb, - 0xe6,0xe4,0x7e,0xd5,0x25,0x43,0x66,0x88,0xfb,0x43,0x33,0x26,0x20,0x2f,0xfd,0x8f, - 0xa9,0xdf,0xcf,0x4,0x44,0x2c,0x33,0x44,0xd6,0x2c,0xc1,0x2d,0x36,0x7f,0xf8,0x1d, - 0xe4,0xf6,0x72,0xa,0x3b,0xd8,0x92,0xb6,0x9b,0x45,0xdc,0x3b,0xf3,0xda,0xca,0x9d, - 0xbb,0x1a,0xa1,0x7f,0xc6,0x55,0x43,0x9d,0x1,0x85,0x4a,0x38,0x5,0x44,0xd4,0xe9, - 0x3b,0x48,0x73,0xf5,0xa0,0x6,0xad,0x3d,0xca,0x8a,0xf7,0xbe,0xe5,0xc3,0xdb,0x21, - 0x5d,0xfd,0xa0,0x24,0xd2,0xe3,0x41,0xd3,0x69,0x8c,0x8b,0xee,0x50,0x61,0xd8,0x8b, - 0x29,0x4d,0x82,0xc9,0xd2,0x30,0x86,0x9e,0x3a,0x7f,0xdc,0x9f,0xc2,0x39,0xc0,0x9f, - 0x37,0xe0,0x44,0xa,0xc5,0x85,0x5d,0xae,0x91,0xe9,0x9d,0xe1,0x4b,0xf6,0x6e,0xf3, - 0xc3,0x70,0xbd,0x96,0x20,0xc4,0xb4,0x5a,0xc3,0x12,0x7a,0x6,0x4b,0x3b,0xa5,0x2, - 0x1d,0xe9,0x8b,0x62,0xef,0xe8,0x11,0x81,0xd2,0x2f,0xe3,0x9d,0x26,0xd1,0x91,0xe9, - 0x42,0xcf,0x0,0x62,0x94,0xb5,0x3c,0xd7,0x47,0xb6,0xdd,0x92,0x72,0x3,0x14,0x8f, - 0xed,0x9f,0x71,0x5d,0x88,0x2,0x5e,0xdb,0x31,0x42,0x79,0xd6,0x14,0xc,0x40,0xd5, - 0xdb,0x41,0xb7,0xef,0x76,0xf4,0xc7,0xbd,0x2b,0x25,0xcf,0x9d,0x28,0xe3,0xac,0x95, - 0x3,0x1e,0xf2,0x8b,0x21,0x52,0x67,0xd1,0x94,0x61,0x29,0x29,0x6d,0x69,0xfe,0xc8, - 0x2a,0xb7,0x38,0x20,0x2c,0x7f,0x5d,0x57,0xa4,0xac,0xf5,0xcc,0x90,0x22,0x63,0x93, - 0x41,0x56,0x9f,0x62,0x28,0x86,0xb3,0xbd,0xe7,0xdc,0x66,0xd4,0x47,0xe4,0x9d,0xf0, - 0x1c,0xd5,0x12,0x48,0x55,0xee,0x20,0x79,0x9c,0x16,0x47,0xac,0xb7,0x2a,0xc0,0xf8, - 0x0,0x60,0xda,0x29,0x66,0x8f,0x66,0x4f,0x6c,0x4c,0x24,0x33,0x31,0xc2,0xa4,0x4e, - 0x18,0x36,0x96,0xed,0x25,0xb6,0xe6,0xc1,0x4c,0xad,0x6f,0x5,0xd7,0x30,0x7d,0x58, - 0x10,0x59,0x1,0x76,0x68,0xe6,0xc5,0x54,0x33,0x6a,0x8,0x64,0xac,0xac,0x32,0x44, - 0xe2,0x49,0x32,0x87,0x7f,0x99,0x4a,0x4c,0x47,0x39,0xd0,0x9f,0xe8,0x4e,0xf7,0xf8, - 0x27,0xf8,0xee,0x8f,0x5f,0x35,0x64,0x92,0x9f,0x6c,0x76,0x4c,0x98,0x29,0x10,0xfa, - 0x72,0xc2,0x82,0xf1,0x5c,0xcc,0x3e,0xa3,0x85,0x8e,0x43,0x6e,0xdd,0xba,0xe6,0x84, - 0xb3,0xd6,0x15,0x92,0x8b,0xf8,0xa4,0x2b,0x65,0x1c,0xf6,0x7d,0x45,0x7,0x78,0x37, - 0x49,0xfa,0x29,0xa5,0x48,0xe7,0x4a,0xcd,0x76,0xd,0xbc,0xd3,0xc8,0xa3,0x59,0xfb, - 0xf9,0xed,0x8f,0x85,0xe6,0x34,0x30,0xcb,0xcf,0xa6,0x49,0x94,0x2e,0x41,0xcb,0x77, - 0x3c,0x75,0x9d,0x4,0x5d,0xe7,0x52,0x53,0x74,0xf,0x28,0x3d,0x32,0x1,0x3a,0xac, - 0xee,0x49,0xb1,0xd5,0xfc,0xe2,0x21,0xcd,0x9,0x6a,0x62,0xb6,0x2b,0x2f,0xae,0xe6, - 0x24,0x4c,0xeb,0x81,0xb3,0x3e,0x54,0x28,0xcc,0xfb,0xe5,0xfe,0xfc,0x9f,0xab,0xeb, - 0xe8,0xdd,0x41,0xe5,0xc0,0x62,0xb3,0x49,0x4c,0x96,0x80,0x77,0x45,0x2f,0x5f,0x69, - 0x7b,0xca,0x6a,0xae,0x9,0xbe,0xd6,0x55,0xbb,0xbc,0xd3,0x38,0xdb,0x0,0x25,0xc4, - 0xdd,0x66,0x2b,0x1e,0x49,0x5e,0x67,0x95,0xf4,0xe7,0x8d,0xb9,0x17,0xec,0x23,0x12, - 0xb7,0x8d,0xc0,0x40,0xcc,0x18,0x95,0x8,0x54,0x69,0x40,0x31,0x69,0x65,0x75,0x47, - 0x4c,0xa0,0x65,0x95,0x0,0x4d,0xaa,0x74,0xb4,0x38,0x2f,0x4c,0xa4,0x52,0x5e,0x5c, - 0x60,0x9f,0x1c,0xac,0x37,0x31,0xb4,0x8b,0x9b,0xf4,0x3c,0x84,0xda,0xb2,0x4c,0xa6, - 0x53,0x31,0xbb,0x53,0x7e,0x66,0x48,0xb3,0x1f,0x77,0x0,0xc3,0x49,0xdd,0xa0,0xa9, - 0xfc,0xbc,0x56,0x34,0xee,0x8a,0x40,0xa,0x0,0x7c,0xe,0xda,0x2f,0x5a,0x1,0x83, - 0x8c,0xbc,0x56,0x8a,0xa2,0x9e,0x3e,0xc1,0x95,0xbd,0x86,0xdf,0x9c,0xa6,0x9,0x19, - 0xe2,0xdf,0x4e,0x51,0x6a,0x8e,0x5b,0x6a,0xb,0xe9,0xc4,0x3b,0x44,0xc5,0x3e,0x50, - 0x82,0x94,0x5b,0x26,0xb3,0x99,0x67,0x49,0xd7,0x6d,0xa8,0x74,0x14,0xb2,0xd,0x77, - 0x92,0x5b,0xc8,0xfc,0x69,0xa4,0xe7,0x75,0x8e,0xac,0x30,0xd2,0x73,0x6e,0xa3,0x75, - 0x82,0xfe,0x1b,0x36,0x98,0x83,0x0,0xef,0x70,0xa8,0xe3,0x85,0x5b,0xf1,0xfc,0x6d, - 0x4d,0x45,0xea,0xb7,0xe9,0xd2,0xac,0x78,0x7f,0xdc,0xcb,0x72,0xca,0x6f,0x68,0xcc, - 0x6e,0x83,0x4,0x86,0x86,0x83,0x77,0xf7,0x2c,0x5b,0xfc,0x8,0x4d,0x79,0x75,0x9b, - 0xbe,0x60,0xd2,0x29,0xb2,0x7f,0xa1,0xb2,0xdb,0x6d,0x25,0xa6,0xdc,0x8d,0x73,0xca, - 0x91,0xf6,0x52,0x97,0xf9,0xc9,0xf,0xa6,0x25,0x8b,0x2e,0x73,0x5,0x23,0x8e,0x44, - 0x4,0x61,0xec,0xb6,0x60,0x8e,0x69,0xbb,0x7c,0xf,0x62,0xd8,0x9c,0x55,0xa4,0xad, - 0xcc,0xf6,0xc5,0x46,0xc0,0xd4,0xec,0xe5,0x61,0x1b,0xd8,0xe5,0x3f,0x67,0x2a,0x43, - 0x48,0x17,0x79,0xa8,0x26,0xe3,0x64,0x22,0xf2,0x46,0xfa,0xf,0x1c,0x1f,0x3d,0x68, - 0x16,0x3,0xae,0xd6,0xd7,0x1c,0x3d,0x39,0xb6,0x16,0x20,0xf5,0xfd,0xc9,0xb8,0x46, - 0x61,0x33,0x6f,0x7,0x17,0x53,0x29,0x89,0x1a,0xa3,0x98,0x36,0xc3,0xd5,0x1e,0xd9, - 0xd8,0x4c,0x31,0x31,0x68,0xed,0x6a,0x20,0x83,0xa,0x95,0x81,0x54,0x4f,0x48,0x35, - 0x2,0xb7,0x3c,0x19,0x8a,0xe4,0x22,0xa4,0x88,0xba,0x5a,0xcb,0x11,0x78,0xa6,0x69, - 0xc5,0x57,0x9a,0xad,0xc4,0x85,0xcd,0x48,0xf,0xe3,0x4a,0x63,0x33,0x92,0x18,0x35, - 0xc9,0x54,0xcd,0x54,0xb8,0xef,0x79,0x42,0x2a,0xd3,0xe,0x3b,0x4d,0x34,0x25,0x13, - 0xb,0xbf,0x40,0xcf,0xc4,0xf,0x19,0xd4,0xf2,0x63,0xb7,0xa5,0x75,0xd0,0x5a,0xbe, - 0xa4,0x28,0x13,0x5e,0x97,0x8c,0xa0,0xc1,0x61,0x2e,0x7d,0x2e,0xe2,0xa2,0xc0,0xed, - 0x62,0x1,0x3e,0xa7,0x8f,0xd6,0x7c,0x82,0x3a,0xb3,0xa7,0x2f,0x84,0x2,0xed,0x2a, - 0x2a,0x80,0x88,0x41,0x8d,0xa8,0x4,0x6e,0x56,0x81,0x9c,0xb8,0x24,0xdc,0x27,0x6, - 0xdd,0x65,0xad,0x6e,0x3c,0xa9,0x70,0xf5,0x5e,0x19,0xa4,0xe2,0x9a,0x92,0x8c,0x45, - 0x92,0x94,0x86,0x20,0x3d,0x8a,0xe,0x14,0xc,0xaa,0xcc,0xaf,0x87,0xf3,0xb6,0xe5, - 0x59,0xe3,0xd3,0x15,0x8e,0x44,0xb,0x6c,0xdc,0x2f,0xce,0x78,0xc1,0x5c,0xbd,0x55, - 0xf0,0x44,0xf4,0xae,0x4f,0x4,0xc2,0xda,0x2e,0x8f,0x8b,0x36,0x4,0xc1,0x1c,0xdc, - 0xa5,0xef,0xf2,0xb3,0xb3,0x7d,0x20,0x91,0xad,0xef,0x89,0xee,0xcb,0x47,0xc3,0xbc, - 0xb,0xb9,0x6b,0xd9,0x3d,0xad,0xb5,0x6b,0x3e,0xc0,0xa1,0xc1,0x82,0x3d,0x9e,0xa7, - 0xac,0x91,0xdb,0xe0,0x8f,0x7b,0x72,0x3d,0xea,0x7b,0xab,0xb6,0x42,0x70,0xf3,0x4d, - 0x2a,0x5f,0x28,0x67,0x8d,0x5d,0x52,0x4b,0x1e,0x74,0xd,0xa0,0xb1,0xab,0xc7,0xde, - 0xbd,0xa3,0xbf,0x4d,0x20,0xb1,0xa,0xb,0xac,0xb5,0x42,0xee,0x26,0x36,0xbb,0x50, - 0x15,0xe3,0x37,0xa2,0xc0,0x8a,0xed,0xde,0xfe,0xfa,0x7f,0x30,0xa7,0xc7,0x8e,0x65, - 0x6b,0xcd,0x32,0xb,0xfe,0x3c,0x96,0xab,0xf1,0xd8,0x9a,0x19,0xf,0x57,0xe8,0x24, - 0xba,0x21,0x47,0x7c,0x2b,0x35,0x5b,0xa9,0xb0,0x5b,0xd9,0xd7,0x23,0xe8,0x3d,0xe, - 0xb6,0xee,0x1a,0xb6,0x2b,0xb0,0x62,0x1d,0x9,0x7d,0xb5,0x18,0xd4,0x1f,0xbb,0xf, - 0xbf,0x82,0xb,0xea,0xb8,0x67,0x94,0xe8,0x42,0xed,0xc0,0xe4,0xd6,0x7d,0xf2,0x8e, - 0x6c,0x8c,0xc4,0x97,0xbc,0xa6,0x34,0xc5,0x24,0x6a,0x5d,0x78,0x89,0x99,0x88,0x49, - 0x1c,0x93,0xb3,0x54,0x7a,0x48,0x3d,0x3c,0xb5,0xfd,0x21,0xd,0x7b,0x94,0x1b,0x67, - 0x21,0xdf,0x7e,0x5e,0x86,0xb3,0x24,0xab,0x9d,0x82,0xa3,0x27,0x9b,0x2c,0xef,0xb7, - 0x40,0xa3,0xd,0x3a,0xeb,0xc9,0xf6,0x21,0xc8,0x18,0x2e,0xc3,0x2c,0x49,0xab,0xcd, - 0x29,0x2a,0x2c,0x30,0x5d,0x50,0xdb,0xfa,0x52,0xfe,0x22,0xed,0x2c,0x12,0x26,0xeb, - 0xb5,0x33,0xa5,0x21,0xfc,0x9c,0xc2,0x45,0x35,0xf0,0x89,0x61,0x3b,0x35,0x2f,0xe3, - 0xde,0x5b,0x14,0x3d,0x2c,0x6f,0x38,0xfd,0x6f,0xda,0xec,0x1b,0x6c,0x13,0x86,0xa2, - 0xc5,0xab,0x43,0x42,0xc8,0x6,0x8,0xfd,0x77,0x91,0xde,0x32,0x46,0x8e,0x16,0x25, - 0xe9,0xaa,0xe1,0x95,0x99,0x1b,0x94,0x88,0x75,0x81,0x23,0xe1,0x14,0x29,0x4,0x59, - 0xd5,0x48,0x9b,0x9e,0x4e,0x23,0x1c,0xc5,0xb4,0xfa,0xf7,0x7a,0x89,0x8e,0x20,0xf3, - 0xb8,0x2,0x89,0x52,0x9c,0x9d,0x5b,0x12,0x9e,0x7e,0x74,0xb2,0x28,0x78,0x8b,0xfd, - 0x40,0x28,0x1c,0x8f,0x4b,0xb7,0xd4,0x80,0xb2,0x4d,0x7a,0xbc,0x5b,0x9a,0x30,0x14, - 0x1d,0xb9,0xe5,0xb9,0xd7,0x41,0x4c,0x76,0x40,0x40,0x2a,0x68,0x38,0xb5,0xe5,0x79, - 0x5d,0x81,0x88,0x29,0x39,0xdc,0x29,0x6b,0x2a,0xa3,0x28,0x5,0xbe,0x58,0x98,0xdb, - 0x92,0x7f,0x15,0x6a,0x40,0xe0,0xe0,0x80,0x21,0x8a,0x68,0xd9,0xc0,0xcd,0x53,0x9d, - 0x4f,0xdb,0xc6,0x88,0xb8,0xef,0xf4,0x63,0x14,0x9c,0x68,0xd2,0xf5,0x2,0x2e,0x8, - 0x1,0xc2,0xf1,0x41,0xa4,0xd2,0x42,0x45,0xdd,0x2a,0x1f,0x9e,0xf8,0xf1,0x3c,0x48, - 0xcd,0x83,0x51,0x7,0xf2,0x46,0xe9,0x86,0xe2,0x52,0x59,0x58,0xd3,0x7,0x60,0x54, - 0xca,0x52,0x16,0xee,0xa5,0x58,0xb3,0x83,0x2,0x53,0xa1,0xfa,0x45,0x5d,0xc3,0x93, - 0x60,0x15,0x9a,0x54,0x5b,0x4,0xda,0xbd,0x56,0xb4,0x17,0xaa,0x3b,0x77,0x7e,0x6, - 0x4a,0x94,0x74,0x6f,0x6c,0xa8,0xf2,0x6f,0xfb,0x14,0x6a,0xc0,0xf0,0xad,0x54,0x52, - 0xc2,0x6e,0x26,0x1e,0x72,0x80,0xdc,0x49,0x35,0x73,0x73,0xf0,0x6a,0xf1,0xf6,0xb4, - 0x87,0xeb,0x24,0x73,0x94,0x96,0xe2,0x10,0x2a,0xcd,0xd0,0x1c,0x7b,0x26,0xed,0x3f, - 0x14,0x14,0xdc,0x87,0x94,0x39,0xd0,0x4a,0xac,0xc3,0x3b,0x97,0xb5,0xb1,0x4c,0xbc, - 0x1d,0xf0,0x31,0xb1,0x87,0x93,0xc1,0x32,0x61,0x13,0x4e,0x5d,0x39,0x3c,0x1c,0x4d, - 0xcf,0xf8,0x54,0x64,0xb2,0xa4,0x2e,0xde,0x68,0x69,0x76,0x9e,0x9b,0xc3,0x5b,0xb8, - 0x34,0xc,0xea,0x3b,0xa0,0x2c,0x6d,0x81,0x3f,0x3b,0xde,0xf7,0x77,0x7a,0xc5,0x47, - 0x74,0x1a,0x2c,0x27,0xbf,0xd9,0x85,0xa7,0x44,0xfc,0x46,0x5f,0x40,0x22,0x97,0x74, - 0xad,0x82,0xaf,0xcd,0x2f,0x9d,0x50,0xed,0xd8,0xae,0xe6,0x51,0x2a,0xac,0x18,0x1e, - 0xc6,0xc3,0xc4,0x6,0x9e,0x4a,0x2e,0x62,0x47,0x74,0xc1,0x87,0x16,0xd8,0x7b,0xc4, - 0xdb,0x2c,0x12,0xb,0x49,0x62,0xf8,0x22,0x91,0x5f,0xf2,0x3b,0xc,0xc,0xd8,0x53, - 0x4f,0x9d,0xd8,0xed,0x67,0x7,0xcf,0xaf,0xfb,0x11,0xb6,0x12,0xea,0x33,0x56,0xc6, - 0xde,0x69,0x51,0x28,0x4b,0xc9,0xc9,0x5c,0x2a,0xbd,0x17,0xb5,0x49,0xef,0x9,0x98, - 0x8d,0x62,0x7,0xf5,0x69,0x56,0x25,0xe4,0x68,0x5b,0x77,0xd2,0xe,0xcd,0x99,0xec, - 0xb6,0x6a,0x94,0x82,0x34,0xde,0x5e,0xdd,0x9c,0x76,0x94,0xe5,0x66,0x1d,0xfd,0xf4, - 0x7f,0x84,0x6a,0xe9,0xdb,0xf,0xce,0x44,0x6a,0x46,0x17,0x79,0x94,0x30,0xe5,0xca, - 0x1a,0xfa,0x4d,0xcd,0xd9,0xac,0xac,0x76,0xa2,0x41,0xdb,0x9,0x5e,0x59,0x7d,0xde, - 0xde,0x67,0x48,0xba,0x76,0x96,0x7e,0xe1,0xdd,0x15,0x5b,0xf1,0x45,0xc0,0xbc,0xde, - 0xbb,0x8a,0xac,0x15,0xb6,0x59,0xb,0x59,0x1a,0xe6,0x62,0x79,0x41,0x60,0xd7,0x9f, - 0xc7,0x20,0xd9,0x3f,0xb6,0x58,0xa0,0x14,0x6d,0x7b,0x6,0x32,0x3c,0x43,0x11,0x78, - 0xcd,0x3d,0x8d,0x4,0x97,0x99,0x5d,0xb1,0x0,0x3f,0xaa,0x41,0x9f,0x82,0x60,0x68, - 0x22,0x3a,0x27,0x59,0x92,0xc7,0x6d,0x7f,0x43,0xf3,0x31,0xfe,0xb6,0xc1,0x77,0x4, - 0x0,0x6,0x8,0x97,0x9f,0xe4,0xc8,0x9f,0x24,0xf3,0x61,0x44,0xf5,0x41,0x2c,0x19, - 0x7c,0xd2,0xf1,0x8e,0x9a,0xde,0x8e,0x5d,0xd2,0xbf,0x5c,0x9,0x82,0xd4,0xd,0x82, - 0x5a,0x94,0x99,0x79,0x79,0xe1,0x19,0x1e,0xd5,0xf9,0xe1,0xcc,0x3c,0xe,0x65,0xb8, - 0xe0,0x57,0xc6,0xfa,0x36,0x55,0xd7,0x89,0x16,0x34,0x12,0x18,0x88,0x20,0x1a,0x62, - 0x34,0xb3,0xdb,0x2e,0x15,0xf5,0x4c,0x6b,0x6f,0xad,0x38,0xab,0xbb,0x1d,0xe3,0x1c, - 0xf3,0xab,0x96,0xa9,0x1,0x6e,0x33,0x96,0x22,0xc5,0xae,0x2b,0x65,0xc8,0x8d,0x99, - 0xfb,0x6a,0xc7,0x12,0xdf,0x93,0xfc,0x4f,0x41,0x35,0xfb,0x7c,0xd1,0x5f,0x18,0xc5, - 0xb,0xae,0x6f,0x8c,0x9c,0x23,0xa2,0xbf,0xe8,0x52,0x6a,0x4e,0x9a,0xf7,0x67,0x97, - 0xe1,0x30,0x29,0xc1,0x43,0x26,0x12,0x85,0xda,0x8d,0x2,0xac,0xec,0x1b,0xf1,0x78, - 0x49,0xe0,0x84,0xe6,0x4,0x27,0x26,0x6c,0x79,0x90,0x3a,0x15,0x8,0xa2,0x2c,0xea, - 0x52,0x55,0xac,0x95,0xfa,0x3e,0x9a,0xd5,0xcb,0x9d,0x2,0x39,0x38,0x73,0x31,0x1, - 0x54,0xb5,0xe7,0xd8,0xdc,0x8d,0xc4,0xd6,0x9d,0x0,0x6b,0x26,0x22,0x97,0x11,0x74, - 0x6c,0x3d,0xa,0x67,0xfb,0xa5,0xbc,0x47,0xc2,0xbe,0x80,0x7a,0xb1,0xb1,0x7b,0x6, - 0x67,0xe3,0xde,0xc4,0x71,0xa4,0x9b,0x8f,0x24,0x7,0xb5,0x46,0x1e,0x46,0xba,0x8a, - 0x83,0x44,0x71,0x7f,0x69,0x2e,0xc7,0xab,0x6c,0xc7,0x26,0x1e,0xf9,0x22,0x24,0xe0, - 0x6,0x83,0xa5,0x77,0xa7,0xc0,0x7,0xcb,0xc7,0x3c,0x91,0xe5,0x82,0xcb,0xef,0x7, - 0x10,0x61,0x6,0xf9,0x8f,0x4d,0xa5,0xfb,0x95,0x4c,0x99,0x8f,0x6e,0xbe,0x70,0x74, - 0xc1,0x17,0x6b,0x69,0xd7,0xf2,0xb4,0x20,0x2f,0xc5,0x85,0xb2,0x91,0x76,0x39,0xa1, - 0xd7,0xbe,0x1b,0xe7,0x8c,0x41,0x63,0x22,0x8d,0xfd,0xb1,0x7b,0x3c,0x22,0xef,0xfd, - 0xb8,0xda,0xe6,0x11,0xcd,0x1b,0x31,0xfd,0xe0,0xb6,0x30,0x72,0xac,0xe8,0x93,0x5, - 0xa7,0x2f,0xec,0x34,0x70,0xcf,0x56,0xfd,0xcd,0x87,0x79,0x89,0x2a,0xe8,0x7,0xe2, - 0xc3,0xed,0xf3,0x12,0x88,0xa4,0x10,0x69,0xdb,0xbf,0x5b,0x88,0xa8,0x6f,0x8d,0xcf, - 0x9e,0xf9,0x5,0xf,0xca,0xda,0x8c,0x18,0xe2,0x85,0xa2,0xd,0x6e,0xa9,0xef,0xb1, - 0x18,0x64,0xc3,0xa0,0x88,0x53,0x8a,0x64,0x13,0x65,0xed,0x3b,0xd4,0xfa,0xc,0x73, - 0xf5,0x90,0x2,0x40,0xea,0x8e,0x58,0xcd,0x14,0x7a,0xda,0x2,0xa4,0x4b,0xb4,0xbc, - 0x2f,0x78,0xdc,0xb7,0xcc,0x67,0x1d,0x5f,0x4d,0x8a,0x9b,0x22,0x5,0x27,0x16,0x7a, - 0xb7,0x18,0xba,0x22,0xa7,0x93,0xf0,0x3b,0x8d,0x4b,0x3e,0x32,0x96,0xf2,0xee,0x45, - 0x6b,0xcc,0xfd,0xb7,0xb3,0x9a,0x18,0x1,0x25,0x33,0xa3,0x2a,0x5a,0xb9,0xa5,0x91, - 0xd1,0xdf,0xb3,0xf8,0xf2,0x24,0x35,0x81,0x70,0xf2,0xb3,0x86,0xe5,0xa3,0xcc,0xd0, - 0xef,0xca,0x89,0x23,0x65,0x21,0xa4,0xa,0xd3,0x48,0xb3,0xad,0x2,0xd8,0xbe,0x53, - 0xb9,0x72,0xcc,0xac,0x17,0x2,0xad,0x87,0xf4,0x62,0xe,0x5a,0x85,0xda,0x2b,0xf4, - 0x25,0x34,0x18,0xa,0xd4,0xbc,0x14,0xa8,0x84,0xc8,0xd5,0x86,0xa1,0x94,0x5a,0xda, - 0x87,0x27,0x8,0x9e,0xa8,0xb5,0xa5,0x1d,0x18,0xb3,0xf6,0x1d,0xf,0x22,0x12,0x34, - 0xd6,0xaa,0x3f,0xab,0xe6,0xd2,0xd4,0x6c,0x1b,0x2a,0x72,0xbd,0xbf,0xcc,0x18,0xc6, - 0x73,0x20,0xe4,0x9b,0xd6,0x8a,0xb8,0x6e,0xbd,0xaf,0xc,0xcc,0x52,0x1e,0x81,0xa8, - 0xc8,0x40,0x54,0xb0,0x13,0xa8,0x9c,0xae,0x53,0xf,0x6c,0x92,0x5c,0x84,0x59,0xcf, - 0x25,0x3e,0x6c,0x7b,0xc8,0xa4,0xe9,0x86,0xd4,0xf5,0xd3,0x27,0x94,0xd4,0xcf,0xdc, - 0x15,0xa3,0xd,0xa7,0xcc,0xa9,0x56,0x20,0xb9,0x42,0x32,0x16,0x47,0x8b,0x65,0x6c, - 0xc9,0xd1,0xe7,0x12,0xf6,0x51,0x18,0xcb,0xc7,0x6b,0x72,0xdb,0x40,0xc1,0xb8,0xd4, - 0xe4,0xc6,0xfc,0xb1,0x70,0x53,0x51,0xa9,0x16,0x83,0x3f,0xdc,0x8e,0xa5,0x49,0xd7, - 0xf6,0xb0,0xe9,0xed,0x81,0x82,0x39,0xc8,0xed,0xab,0xa4,0xae,0xec,0x5e,0x83,0xd2, - 0xa4,0x80,0x4,0x15,0x54,0xd5,0x3f,0x6a,0xd8,0x7e,0xc6,0x68,0xa3,0x10,0xbf,0x9b, - 0x40,0x2a,0x9,0x41,0xac,0x43,0xb,0x1a,0x6e,0xaf,0xc8,0x5c,0x8d,0x4d,0xae,0x32, - 0x4d,0xb2,0xc7,0xa1,0x8,0x7,0x8b,0xe1,0x5,0x52,0xc9,0xa9,0xe1,0x89,0x45,0xa1, - 0xb3,0xcd,0xe3,0xdf,0x11,0x6e,0xfa,0x0,0x9d,0xc3,0x5c,0x2c,0x90,0xb,0x5e,0xde, - 0x3d,0xa5,0x0,0x46,0xac,0x8c,0xa7,0x32,0x5e,0x71,0xdb,0xc0,0xfa,0xa0,0x62,0x2f, - 0xed,0xc5,0xf,0x0,0x34,0xa,0x0,0xd2,0x4e,0xdb,0x7e,0x5e,0x66,0xdc,0x3d,0xa3, - 0x3,0xbd,0x69,0x2f,0x4a,0x11,0x61,0x28,0x82,0xbc,0xe8,0xfd,0xdc,0xcb,0x2d,0xcb, - 0x91,0xbb,0x4b,0x46,0xc6,0x4b,0x98,0x94,0xa6,0x17,0xf2,0xd,0x73,0x31,0x30,0x76, - 0xee,0x1a,0xa6,0xb8,0x2b,0x8,0x60,0x2e,0x45,0x4a,0xab,0x22,0x95,0x58,0xed,0x27, - 0x14,0x39,0x6d,0x5a,0x4,0x85,0xee,0xaa,0x9c,0xe2,0x37,0x11,0x93,0xe7,0x87,0x2, - 0x2,0x2e,0x3a,0xac,0xb6,0x9a,0x5a,0xfb,0x64,0x85,0x9d,0xf9,0xdd,0x8c,0xa1,0xf2, - 0x45,0x8e,0xcc,0xc9,0x15,0xbc,0xf3,0xb1,0x1f,0x2c,0x42,0xb2,0x93,0xca,0x34,0x95, - 0x78,0x6e,0xc1,0xae,0x88,0x1d,0x2a,0x6d,0x22,0xc8,0xe6,0x1,0xd4,0x88,0x73,0x99, - 0x97,0x40,0x63,0x2c,0x7c,0x58,0x5d,0x9b,0x4,0xa0,0x4e,0x97,0xea,0x82,0xac,0xe2, - 0x70,0x6e,0x92,0x79,0xb,0xbc,0xe6,0x2e,0x85,0xcd,0xae,0xd9,0xd6,0x22,0x74,0xed, - 0xe1,0xd7,0x1a,0x5f,0xaf,0x77,0xfa,0xb3,0x97,0xc9,0xca,0x2,0xcb,0x77,0xe5,0xbc, - 0x66,0x78,0x36,0x71,0xb4,0x1d,0x1f,0xba,0xea,0x4d,0x94,0x41,0xee,0x88,0x2f,0xd1, - 0x61,0xc8,0xb0,0x90,0xc0,0x2b,0x45,0x58,0xf4,0x8f,0x5b,0x41,0x8,0xc0,0xfd,0x6e, - 0x39,0x34,0x5f,0x6d,0x51,0xfe,0x28,0xbb,0x4c,0x3d,0x7d,0x3c,0xc5,0xac,0xe,0xa6, - 0xf5,0xbe,0x38,0xb6,0x69,0xfc,0x8e,0x5f,0x8c,0xe9,0xa0,0x14,0x2a,0x1e,0x82,0x63, - 0x52,0x62,0x51,0x23,0x61,0x79,0x5e,0xad,0x36,0x5b,0xe9,0xfc,0x9,0x77,0x23,0x7e, - 0xb5,0x5b,0x35,0x20,0xd7,0xc3,0x7f,0x65,0x2e,0x9f,0x79,0x58,0x3d,0x7c,0x3c,0xf, - 0xde,0x8d,0x32,0x40,0x86,0x10,0x6d,0xbd,0x6c,0x58,0x3a,0xf4,0xcf,0x5d,0x73,0x6, - 0xb9,0x28,0x26,0x91,0xeb,0x25,0x76,0x1a,0x44,0x70,0x73,0x81,0xec,0xaf,0x90,0x4b, - 0xbc,0x42,0xb,0x43,0xd1,0x78,0x1,0xbd,0xd0,0x3b,0x32,0x21,0x19,0xa5,0x27,0xd2, - 0xcd,0xcc,0xe3,0x3a,0xf1,0xda,0x54,0x36,0x4b,0x47,0x37,0xb7,0x76,0xc7,0x3,0x33, - 0x89,0x8d,0xf6,0x5b,0x6,0x77,0x99,0x57,0x33,0xcb,0xf7,0x4c,0x72,0x1f,0x9e,0xbf, - 0x6b,0x2,0x79,0x5d,0xdc,0x4e,0x13,0xa7,0x95,0x4a,0x5f,0x8c,0x91,0xe1,0x3f,0x9a, - 0x6f,0x36,0xf5,0xf5,0xae,0xf,0x4d,0xe1,0xdb,0x45,0x2e,0xcd,0xe3,0x4c,0x8d,0x4f, - 0x4e,0x87,0x2c,0x2c,0xd5,0x3f,0xd3,0xea,0x9,0xb3,0x77,0x9a,0x15,0xb7,0x35,0x5, - 0x6d,0xaa,0xfa,0x9b,0xba,0x48,0x7d,0x96,0x8d,0x2b,0xe3,0xf0,0x77,0x71,0x40,0xc6, - 0x78,0x6c,0x72,0x4e,0x2b,0xc5,0x3a,0x34,0xf8,0x31,0xce,0xf,0x68,0x83,0x14,0xd6, - 0xad,0x8e,0x72,0xe7,0xd6,0x70,0xfd,0xe3,0x9b,0xe1,0xd4,0x93,0xd3,0x94,0xd9,0x4c, - 0x1,0x4c,0x9b,0xab,0x91,0x55,0xdf,0x8b,0x6,0x2e,0x9a,0x6f,0xb1,0x2e,0x46,0xde, - 0xbc,0x38,0xc7,0x13,0x28,0xc5,0x76,0x44,0x28,0x4b,0xd7,0xfb,0x5f,0x31,0x48,0xdf, - 0x7d,0x63,0x8b,0xf,0x38,0x6b,0x1a,0x3f,0x99,0x34,0xae,0xca,0x62,0x74,0xa9,0x9e, - 0x2c,0xf0,0x31,0x55,0xb7,0xa7,0x99,0xdf,0xf2,0xf0,0x5b,0xd1,0x22,0x23,0xb1,0x9f, - 0x87,0x3d,0x2e,0x3f,0xa8,0x49,0x7e,0x42,0xfc,0xac,0x8c,0x60,0xa0,0x37,0x7e,0xcd, - 0x28,0xb0,0x23,0x5f,0x58,0x3c,0xbe,0xcb,0x2d,0x1a,0x9d,0x4f,0x3e,0x50,0x6e,0x45, - 0x8d,0x9c,0x84,0xb6,0x65,0x83,0x78,0x63,0x30,0x6,0x43,0x51,0x3d,0x41,0x1f,0xe4, - 0xf1,0xc1,0x45,0xca,0xfd,0x83,0x96,0x2b,0x9e,0xb3,0x7a,0x5c,0x83,0xe8,0x21,0x91, - 0x5,0xa5,0x48,0xea,0xa8,0x40,0x4e,0x59,0x46,0x11,0xaa,0x3,0x52,0x49,0xe8,0xc4, - 0xb,0xad,0x8f,0x9,0x31,0xa5,0x34,0x4f,0xd8,0x2e,0xab,0x5d,0x96,0xcc,0x6e,0x9b, - 0xf2,0xb6,0x86,0x1b,0x76,0x54,0x74,0xbd,0xe4,0x9e,0xc0,0xb7,0xe7,0x29,0x7c,0xf2, - 0xd6,0x8b,0xfb,0x9,0x31,0xaf,0xd7,0x89,0xdd,0x84,0xe6,0xf3,0xd0,0xd4,0x90,0x43, - 0xb,0x96,0x5f,0x82,0x6b,0xd3,0x40,0x50,0xf2,0x80,0x8,0xda,0x2a,0x84,0xce,0x1, - 0x8f,0x4a,0x89,0xc0,0x7a,0x62,0xca,0xd7,0x66,0x31,0xcc,0x37,0x7,0x5d,0xfa,0x12, - 0x73,0x5a,0x94,0xde,0xad,0x54,0x30,0xa0,0x55,0xb7,0x7c,0x7f,0x3d,0xca,0x0,0xcc, - 0x94,0x8a,0xe,0xf,0x6c,0xd8,0xe7,0x52,0x89,0xb4,0x9,0x90,0x91,0x4,0xa3,0x5, - 0x5e,0xb7,0xe4,0xd,0xd,0x94,0x2d,0xe1,0x4c,0xa9,0x61,0x9,0xf3,0x61,0x56,0x89, - 0x6b,0xe3,0x18,0xd7,0x3c,0x0,0xa9,0xc5,0x34,0xb3,0x57,0xc5,0xb7,0x7a,0x4b,0x96, - 0x32,0xaf,0xa3,0xbe,0xc3,0xd0,0xa0,0x10,0xfa,0x81,0x99,0x6e,0xe3,0xef,0x77,0xce, - 0xd3,0x90,0x27,0x10,0x90,0xd0,0x55,0xc5,0x84,0x2c,0xb,0xbc,0xa6,0xd5,0x53,0x59, - 0x85,0xf6,0x97,0x49,0x47,0xb8,0xd9,0xc1,0x3a,0x73,0xb0,0x9d,0x63,0x28,0x6d,0xb6, - 0xb8,0x94,0x46,0xc9,0x65,0x9b,0x8f,0x6a,0xc8,0x1a,0x27,0xee,0xf0,0x7a,0xc7,0xf5, - 0xf0,0x60,0xbf,0x38,0x19,0x99,0x7a,0xd2,0xd,0xaa,0x71,0xef,0xd2,0x5e,0x26,0x8c, - 0xf2,0x6c,0x56,0xd7,0x87,0x65,0x42,0xcf,0xfe,0x69,0xbf,0x6f,0xe3,0x87,0x66,0xd4, - 0x67,0x26,0x8d,0x0,0x3f,0x87,0xd3,0x4c,0x32,0xc4,0xbb,0x5,0x23,0xe1,0x11,0x16, - 0x4e,0xe6,0x6d,0x55,0xcb,0xb0,0x26,0xcb,0x1a,0x65,0x3b,0x7e,0x6c,0x21,0xd2,0xd4, - 0xc6,0x60,0xd4,0x6,0x67,0x28,0xd1,0x99,0xec,0x8d,0x1f,0x10,0x6f,0xaf,0xa5,0x3d, - 0x97,0x14,0x93,0x63,0xc4,0x39,0xae,0x5e,0x9e,0x6a,0xdc,0x8a,0x8b,0xb0,0xde,0xd2, - 0x90,0xb4,0xd8,0xf8,0xdc,0xab,0x12,0xca,0x39,0xb0,0xda,0x29,0x61,0x81,0x66,0xf8, - 0x15,0x79,0x5c,0xd9,0x32,0x8b,0xb7,0x50,0xf5,0x15,0xdb,0x81,0x45,0xba,0x54,0xd5, - 0xee,0xad,0x4e,0xcc,0x59,0xe0,0x17,0x12,0x91,0x71,0xba,0xf2,0x72,0xa1,0xeb,0x87, - 0x1b,0xc8,0xe0,0xcd,0x54,0x99,0x1e,0x4a,0xae,0xf9,0x4b,0xf3,0x35,0x20,0x49,0x24, - 0xcd,0x98,0x70,0xa6,0xf8,0x87,0x38,0x8a,0x79,0xf3,0x7e,0xeb,0x95,0xe9,0xf3,0x30, - 0x32,0xd4,0xfd,0x6,0xed,0x9c,0x50,0x9c,0x96,0x1c,0x10,0xcb,0xbb,0x5a,0xf0,0x9, - 0x72,0xe0,0xaf,0xea,0x69,0xe7,0x75,0xe2,0x5b,0x73,0x4e,0x70,0x5e,0x42,0xa1,0x90, - 0x97,0x1f,0x97,0x85,0xbb,0x67,0xa2,0xd2,0x3,0xb2,0x1e,0xbe,0x8c,0x8e,0x47,0x7e, - 0x70,0xf6,0x69,0xd9,0x5f,0x5f,0x3c,0x3a,0xd2,0x8a,0xab,0xb0,0x4d,0xcc,0x42,0xe4, - 0xeb,0x59,0x6a,0x28,0x40,0xd,0xfa,0xc3,0x40,0x19,0x2,0xcc,0x28,0x4a,0xcb,0x98, - 0xc0,0x35,0x72,0x20,0x94,0x2e,0xda,0xe7,0xb8,0x86,0x98,0x85,0x53,0x5a,0x6a,0xbe, - 0xb3,0xd5,0x66,0x74,0x62,0xe0,0xb7,0xa2,0x7a,0xb9,0xef,0xa2,0x83,0xbb,0x3b,0x45, - 0x70,0x2d,0xe4,0x85,0x5b,0xbf,0x6d,0x93,0xc5,0x6,0x1a,0x19,0x61,0x84,0x58,0x94, - 0xd9,0xbe,0x88,0xbc,0xa0,0x40,0x5f,0x1b,0x7a,0xce,0xbd,0xfd,0xa,0x78,0x43,0xfa, - 0xa5,0xa8,0x80,0x80,0x68,0x6d,0x14,0x2f,0xf2,0xad,0xc7,0xd3,0x33,0x9f,0xe8,0x8c, - 0x5f,0x71,0x49,0x7f,0x32,0x29,0x1a,0x2c,0xf7,0x57,0x2a,0x82,0xcf,0xed,0x7d,0xf4, - 0x96,0x7d,0x75,0x7e,0xea,0x9,0x2d,0x5d,0xb7,0x75,0x32,0x6a,0x15,0x1b,0xf6,0xf3, - 0xc,0xc0,0xf2,0xbd,0xe9,0x8c,0xe9,0x61,0xe3,0x15,0x63,0x33,0x82,0xe0,0xa7,0x98, - 0x5e,0x1d,0x96,0xc8,0x27,0xc4,0x27,0x5e,0xb9,0x59,0xc8,0x4e,0xf3,0x3f,0x43,0x7f, - 0x0,0xb5,0x3e,0x69,0x43,0x28,0xcb,0xa6,0xbc,0xae,0xda,0x3f,0x90,0x82,0xd7,0x6e, - 0x20,0xee,0x38,0xc6,0xb3,0xde,0x25,0xec,0xb7,0xed,0x3b,0xab,0x2d,0xfd,0x2b,0xad, - 0xb4,0x69,0x17,0x77,0x12,0x62,0x1e,0xce,0x12,0x78,0x8e,0x22,0xfb,0xe5,0x90,0x9b, - 0xd4,0x48,0x62,0x88,0x27,0x87,0xf4,0xde,0xf4,0x31,0xa,0xa1,0x2f,0x36,0x4f,0x63, - 0x1f,0x67,0xda,0x31,0x49,0xf9,0x80,0xda,0x72,0xf,0xfc,0xed,0xf4,0x8e,0x89,0xca, - 0xd6,0xeb,0xd2,0xfe,0xf2,0xc8,0x5d,0xe7,0x79,0x68,0x8a,0xa8,0x9e,0xd9,0xd,0x3d, - 0xc0,0xe7,0xee,0x8a,0x61,0x6f,0x65,0xd4,0xfd,0x63,0x42,0xf2,0xf1,0xcc,0x3d,0x48, - 0x38,0x90,0xc6,0x2c,0xd8,0x25,0x14,0x52,0x8d,0x1e,0x7a,0xab,0x78,0x7,0xe8,0x39, - 0x6f,0x57,0xc3,0xd0,0x46,0xa9,0x25,0x44,0xd,0x68,0xb7,0x7e,0xb4,0xf4,0xc6,0xec, - 0x5,0x8e,0x19,0xdd,0x33,0xad,0xaf,0xc0,0xcb,0x2b,0x6c,0x44,0x32,0xd4,0xfd,0xa1, - 0x2d,0x41,0xf2,0x73,0xea,0x18,0x38,0xf7,0x0,0xef,0x76,0xb4,0x64,0xbd,0xa2,0x6a, - 0xcb,0xbb,0xc7,0xfe,0xe8,0x78,0xbf,0xb5,0xa3,0xab,0x79,0x55,0x0,0x77,0x77,0x2d, - 0xb9,0x6a,0x21,0xa4,0x2,0xd8,0x1d,0x3,0xc8,0x13,0xb7,0x2d,0x50,0x5a,0x17,0x1c, - 0x96,0xdf,0x1b,0x7f,0xd7,0x5a,0xb4,0xfa,0x85,0x2f,0x50,0x86,0x26,0xc7,0x33,0xdf, - 0xb1,0x54,0x5,0xb4,0x2d,0xa1,0xb7,0x75,0xb4,0xee,0x23,0x6,0xc9,0xb9,0xa1,0x60, - 0x19,0x3d,0x5f,0xf0,0x97,0x94,0xeb,0x1e,0x43,0xbc,0xa4,0x69,0x4,0xd7,0xc9,0xb6, - 0xac,0xce,0xea,0x59,0xef,0xa2,0x4f,0x24,0x91,0x72,0x2a,0xda,0x2c,0x4c,0xba,0x46, - 0x89,0x1b,0xb6,0xa0,0x2f,0xa3,0xbe,0x72,0xdf,0xe2,0xdb,0xe3,0x3b,0x25,0x1a,0x67, - 0x73,0x5,0xc0,0x63,0x27,0x10,0x88,0x39,0x2,0x32,0x14,0x2f,0x7e,0xcf,0xf4,0x87, - 0x6a,0xab,0x29,0x99,0xce,0x67,0x8b,0x2e,0x4b,0xe6,0x92,0x6,0xd,0xac,0x6d,0x80, - 0x32,0x2e,0xe4,0xd8,0xbe,0xec,0x12,0x40,0x1f,0x27,0x6f,0x1e,0x76,0xe3,0xa5,0xe0, - 0x10,0x4e,0xf9,0x5e,0xb6,0x85,0x8d,0x2,0x6c,0x20,0x87,0x79,0x4c,0xf4,0x7a,0xfd, - 0xa2,0xde,0xd7,0x61,0xcb,0xe9,0xa2,0x6a,0x90,0x91,0x8,0x7,0xf5,0x2e,0x67,0x6, - 0x7c,0xe0,0x64,0x33,0x66,0x71,0xb4,0x53,0x91,0x3c,0x4c,0x5e,0x31,0xc6,0x5c,0xd4, - 0xa5,0x34,0xb5,0xf0,0x1f,0xd7,0x5c,0x2f,0xe9,0x64,0xb6,0xdf,0x92,0x1e,0x65,0x10, - 0x0,0x49,0xc2,0xe5,0xbb,0x78,0x39,0xcc,0x34,0x86,0x2b,0xe5,0xcc,0x88,0x3a,0x73, - 0xbc,0x6f,0x64,0x5b,0x48,0x40,0x8b,0xb1,0xa5,0x42,0x11,0xb7,0xdf,0xf5,0x47,0x5f, - 0x3f,0xb,0xc5,0x7a,0x3,0xfe,0x48,0xb6,0x5,0xf2,0x9c,0x52,0x7b,0xd6,0xc5,0xb8, - 0x47,0xa9,0x14,0xf,0x6a,0x1f,0x40,0x8f,0xe0,0x51,0x47,0xc1,0x47,0xf,0xa0,0x6, - 0x99,0x66,0x81,0x9c,0xe5,0xc9,0xd2,0x6a,0xbc,0x70,0xbc,0xb8,0xc6,0x2,0x71,0x8d, - 0x2c,0x5,0x1c,0x96,0x25,0x5c,0x26,0x6,0xad,0xec,0x47,0x74,0xfb,0xe8,0x7b,0x95, - 0xce,0xfc,0xb1,0x34,0x46,0x5,0x9f,0x82,0x75,0xdb,0xba,0xbb,0xde,0x2c,0xc9,0x8a, - 0xb1,0xe5,0x21,0xd6,0xc2,0xc6,0x5c,0xef,0x33,0xa4,0x65,0xaf,0xd,0x60,0xc4,0x5b, - 0x5d,0xf6,0x90,0x23,0xfb,0x30,0x25,0xf0,0xc,0xe0,0xac,0x6a,0x8c,0xf5,0xf4,0x3e, - 0x5c,0x16,0x94,0x1f,0x5c,0xf1,0xf,0x90,0x16,0xf3,0xbf,0xa2,0x54,0x84,0xfd,0x31, - 0x7b,0x8e,0xd3,0x77,0x3e,0xf9,0x68,0x4b,0x5a,0x95,0xb5,0x66,0x8b,0x2b,0x25,0x67, - 0xc0,0xb9,0x86,0x1e,0x2b,0x16,0x2e,0xc0,0xa,0xed,0x63,0xde,0x72,0xe1,0x8f,0x6e, - 0x70,0x64,0xe5,0xaf,0xdd,0xce,0x7a,0x38,0xe3,0xaf,0x1e,0xee,0xda,0x43,0x57,0x9c, - 0x7d,0xdd,0x3a,0xa8,0x73,0xe7,0xe9,0xfd,0xd5,0x4d,0x5c,0xc7,0xae,0xeb,0x36,0x20, - 0x50,0x9c,0x4f,0x2e,0xea,0x49,0xe5,0xce,0xf8,0x5,0xbd,0x54,0xc7,0x15,0x70,0x45, - 0x73,0x2a,0x6e,0x66,0x12,0x58,0x64,0xe7,0x25,0xc0,0x2f,0xd4,0x2d,0xe5,0xf4,0x7d, - 0x2,0xc3,0x2c,0xec,0xd,0x91,0x3b,0x85,0x16,0xf8,0x59,0xde,0x8e,0x49,0x24,0x81, -}; - diff --git a/src/game/sequence.h b/src/game/sequence.h deleted file mode 100644 index e3f6a5d..0000000 --- a/src/game/sequence.h +++ /dev/null @@ -1,3 +0,0 @@ -#define SEQUENCE_MAX_NUM 32768 - -extern const BYTE gc_abSequence[SEQUENCE_MAX_NUM]; diff --git a/src/game/shop.cpp b/src/game/shop.cpp index d81b9e3..27cd3d4 100644 --- a/src/game/shop.cpp +++ b/src/game/shop.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "libgame/grid.h" #include "constants.h" #include "utils.h" @@ -11,11 +11,10 @@ #include "item.h" #include "item_manager.h" #include "buffer_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "log.h" #include "db.h" #include "questmanager.h" -#include "monarch.h" #include "mob_manager.h" #include "locale_service.h" @@ -30,9 +29,9 @@ CShop::~CShop() { TPacketGCShop pack; - pack.header = HEADER_GC_SHOP; - pack.subheader = SHOP_SUBHEADER_GC_END; - pack.size = sizeof(TPacketGCShop); + pack.header = GC::SHOP; + pack.subheader = ShopSub::GC::END; + pack.length = sizeof(TPacketGCShop); Broadcast(&pack, sizeof(pack)); @@ -192,7 +191,7 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) if (pos >= m_itemVector.size()) { sys_log(0, "Shop::Buy : invalid position %d : %s", pos, ch->GetName()); - return SHOP_SUBHEADER_GC_INVALID_POS; + return ShopSub::GC::INVALID_POS; } sys_log(0, "Shop::Buy : name %s pos %d", ch->GetName(), pos); @@ -200,7 +199,7 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) GuestMapType::iterator it = m_map_guest.find(ch); if (it == m_map_guest.end()) - return SHOP_SUBHEADER_GC_END; + return ShopSub::GC::END; SHOP_ITEM& r_item = m_itemVector[pos]; @@ -208,7 +207,7 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) if (r_item.price < 0) // Fix { LogManager::instance().HackLog("SHOP_BUY_GOLD_OVERFLOW", ch); - return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY; + return ShopSub::GC::NOT_ENOUGH_MONEY; } LPITEM pkSelectedItem = ITEM_MANAGER::instance().Find(r_item.itemid); @@ -242,7 +241,7 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) if (ch->GetGold() < (int) dwPrice) { sys_log(1, "Shop::Buy : Not enough money : %s has %d, price %d", ch->GetName(), ch->GetGold(), dwPrice); - return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY; + return ShopSub::GC::NOT_ENOUGH_MONEY; } LPITEM item; @@ -253,7 +252,7 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) item = ITEM_MANAGER::instance().CreateItem(r_item.vnum, r_item.count); if (!item) - return SHOP_SUBHEADER_GC_SOLD_OUT; + return ShopSub::GC::SOLD_OUT; if (!m_pkPC) { @@ -262,7 +261,7 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) //축복의 구슬 && 만년한철 이벤트 if (item->GetVnum() == 70024 || item->GetVnum() == 70035) { - return SHOP_SUBHEADER_GC_END; + return ShopSub::GC::END; } } } @@ -282,13 +281,13 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) if (m_pkPC) { sys_log(1, "Shop::Buy at PC Shop : Inventory full : %s size %d", ch->GetName(), item->GetSize()); - return SHOP_SUBHEADER_GC_INVENTORY_FULL; + return ShopSub::GC::INVENTORY_FULL; } else { sys_log(1, "Shop::Buy : Inventory full : %s size %d", ch->GetName(), item->GetSize()); M2_DESTROY_ITEM(item); - return SHOP_SUBHEADER_GC_INVENTORY_FULL; + return ShopSub::GC::INVENTORY_FULL; } } @@ -334,13 +333,6 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) } } - // 상점에서 살떄 세금 5% - if (!m_pkPC) - { - CMonarch::instance().SendtoDBAddMoney(dwTax, ch->GetEmpire(), ch); - } - - // 군주 시스템 : 세금 징수 if (m_pkPC) { m_pkPC->SyncQuickslot(QUICKSLOT_TYPE_ITEM, item->GetCell(), 255); @@ -376,7 +368,6 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) if (iVal > 0) m_pkPC->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("판매금액의 %d %% 가 세금으로 나가게됩니다"), iVal); - CMonarch::instance().SendtoDBAddMoney(dwTax, m_pkPC->GetEmpire(), m_pkPC); } else { @@ -400,7 +391,7 @@ int CShop::Buy(LPCHARACTER ch, BYTE pos) ch->Save(); - return (SHOP_SUBHEADER_GC_OK); + return (ShopSub::GC::OK); } bool CShop::AddGuest(LPCHARACTER ch, DWORD owner_vid, bool bOtherEmpire) @@ -420,8 +411,9 @@ bool CShop::AddGuest(LPCHARACTER ch, DWORD owner_vid, bool bOtherEmpire) TPacketGCShop pack; - pack.header = HEADER_GC_SHOP; - pack.subheader = SHOP_SUBHEADER_GC_START; + pack.header = GC::SHOP; + pack.length = sizeof(pack); + pack.subheader = ShopSub::GC::START; TPacketGCShopStart pack2; @@ -461,7 +453,7 @@ bool CShop::AddGuest(LPCHARACTER ch, DWORD owner_vid, bool bOtherEmpire) } } - pack.size = sizeof(pack) + sizeof(pack2); + pack.length = sizeof(pack) + sizeof(pack2); ch->GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCShop)); ch->GetDesc()->Packet(&pack2, sizeof(TPacketGCShopStart)); @@ -478,9 +470,9 @@ void CShop::RemoveGuest(LPCHARACTER ch) TPacketGCShop pack; - pack.header = HEADER_GC_SHOP; - pack.subheader = SHOP_SUBHEADER_GC_END; - pack.size = sizeof(TPacketGCShop); + pack.header = GC::SHOP; + pack.subheader = ShopSub::GC::END; + pack.length = sizeof(TPacketGCShop); ch->GetDesc()->Packet(&pack, sizeof(pack)); } @@ -511,9 +503,9 @@ void CShop::BroadcastUpdateItem(BYTE pos) TEMP_BUFFER buf; - pack.header = HEADER_GC_SHOP; - pack.subheader = SHOP_SUBHEADER_GC_UPDATE_ITEM; - pack.size = sizeof(pack) + sizeof(pack2); + pack.header = GC::SHOP; + pack.subheader = ShopSub::GC::UPDATE_ITEM; + pack.length = sizeof(pack) + sizeof(pack2); pack2.pos = pos; diff --git a/src/game/shopEx.cpp b/src/game/shopEx.cpp index be0e525..0484d3a 100644 --- a/src/game/shopEx.cpp +++ b/src/game/shopEx.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "libgame/grid.h" #include "constants.h" #include "utils.h" @@ -11,11 +11,10 @@ #include "item.h" #include "item_manager.h" #include "buffer_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "log.h" #include "db.h" #include "questmanager.h" -#include "monarch.h" #include "mob_manager.h" #include "locale_service.h" #include "desc_client.h" @@ -60,8 +59,9 @@ bool CShopEx::AddGuest(LPCHARACTER ch,DWORD owner_vid, bool bOtherEmpire) TPacketGCShop pack; - pack.header = HEADER_GC_SHOP; - pack.subheader = SHOP_SUBHEADER_GC_START_EX; + pack.header = GC::SHOP; + pack.length = sizeof(pack); + pack.subheader = ShopSub::GC::START_EX; TPacketGCShopStartEx pack2; @@ -104,7 +104,7 @@ bool CShopEx::AddGuest(LPCHARACTER ch,DWORD owner_vid, bool bOtherEmpire) size += sizeof(pack_tab); } - pack.size = sizeof(pack) + sizeof(pack2) + size; + pack.length = sizeof(pack) + sizeof(pack2) + size; ch->GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCShop)); ch->GetDesc()->BufferedPacket(&pack2, sizeof(TPacketGCShopStartEx)); @@ -120,7 +120,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) if (tabIdx >= GetTabCount()) { sys_log(0, "ShopEx::Buy : invalid position %d : %s", pos, ch->GetName()); - return SHOP_SUBHEADER_GC_INVALID_POS; + return ShopSub::GC::INVALID_POS; } sys_log(0, "ShopEx::Buy : name %s pos %d", ch->GetName(), pos); @@ -128,7 +128,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) GuestMapType::iterator it = m_map_guest.find(ch); if (it == m_map_guest.end()) - return SHOP_SUBHEADER_GC_END; + return ShopSub::GC::END; TShopTableEx& shopTab = m_vec_shopTabs[tabIdx]; TShopItemTable& r_item = shopTab.items[slotPos]; @@ -136,7 +136,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) if (r_item.price <= 0) { LogManager::instance().HackLog("SHOP_BUY_GOLD_OVERFLOW", ch); - return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY; + return ShopSub::GC::NOT_ENOUGH_MONEY; } DWORD dwPrice = r_item.price; @@ -150,7 +150,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) if (ch->GetGold() < (int) dwPrice) { sys_log(1, "ShopEx::Buy : Not enough money : %s has %d, price %d", ch->GetName(), ch->GetGold(), dwPrice); - return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY; + return ShopSub::GC::NOT_ENOUGH_MONEY; } break; case SHOP_COIN_TYPE_SECONDARY_COIN: @@ -159,7 +159,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) if (count < dwPrice) { sys_log(1, "ShopEx::Buy : Not enough myeongdojun : %s has %d, price %d", ch->GetName(), count, dwPrice); - return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY_EX; + return ShopSub::GC::NOT_ENOUGH_MONEY_EX; } } break; @@ -170,7 +170,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) item = ITEM_MANAGER::instance().CreateItem(r_item.vnum, r_item.count); if (!item) - return SHOP_SUBHEADER_GC_SOLD_OUT; + return ShopSub::GC::SOLD_OUT; int iEmptyPos; if (item->IsDragonSoul()) @@ -186,7 +186,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) { sys_log(1, "ShopEx::Buy : Inventory full : %s size %d", ch->GetName(), item->GetSize()); M2_DESTROY_ITEM(item); - return SHOP_SUBHEADER_GC_INVENTORY_FULL; + return ShopSub::GC::INVENTORY_FULL; } switch (shopTab.coinType) @@ -221,7 +221,7 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) if (LC_IsBrazil()) { ch->SaveReal(); - db_clientdesc->DBPacketHeader(HEADER_GD_FLUSH_CACHE, 0, sizeof(DWORD)); + db_clientdesc->DBPacketHeader(GD::FLUSH_CACHE, 0, sizeof(DWORD)); DWORD pid = ch->GetPlayerID(); db_clientdesc->Packet(&pid, sizeof(DWORD)); } @@ -230,6 +230,6 @@ int CShopEx::Buy(LPCHARACTER ch, BYTE pos) ch->Save(); } - return (SHOP_SUBHEADER_GC_OK); + return (ShopSub::GC::OK); } diff --git a/src/game/shop_manager.cpp b/src/game/shop_manager.cpp index aebc656..7a265a1 100644 --- a/src/game/shop_manager.cpp +++ b/src/game/shop_manager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "libgame/grid.h" #include "constants.h" #include "utils.h" @@ -11,11 +11,10 @@ #include "item.h" #include "item_manager.h" #include "buffer_manager.h" -#include "packet.h" +#include "packet_structs.h" #include "log.h" #include "db.h" #include "questmanager.h" -#include "monarch.h" #include "mob_manager.h" #include "locale_service.h" #include "desc_client.h" @@ -242,13 +241,13 @@ void CShopManager::Buy(LPCHARACTER ch, BYTE pos) int ret = pkShop->Buy(ch, pos); - if (SHOP_SUBHEADER_GC_OK != ret) // 문제가 있었으면 보낸다. + if (ShopSub::GC::OK != ret) // 문제가 있었으면 보낸다. { TPacketGCShop pack; - pack.header = HEADER_GC_SHOP; + pack.header = GC::SHOP; pack.subheader = ret; - pack.size = sizeof(TPacketGCShop); + pack.length = sizeof(TPacketGCShop); ch->GetDesc()->Packet(&pack, sizeof(pack)); } @@ -359,9 +358,6 @@ void CShopManager::Sell(LPCHARACTER ch, BYTE bCell, BYTE bCount) else item->SetCount(item->GetCount() - bCount); - //군주 시스템 : 세금 징수 - CMonarch::instance().SendtoDBAddMoney(dwTax, ch->GetEmpire(), ch); - ch->PointChange(POINT_GOLD, dwPrice, false); } diff --git a/src/game/target.cpp b/src/game/target.cpp index cdf60e9..d1c7c1e 100644 --- a/src/game/target.cpp +++ b/src/game/target.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "utils.h" #include "config.h" #include "questmanager.h" @@ -6,7 +6,7 @@ #include "char.h" #include "char_manager.h" #include "desc.h" -#include "packet.h" +#include "packet_structs.h" #include "target.h" ///////////////////////////////////////////////////////////////////// @@ -19,7 +19,8 @@ return; TPacketGCTargetCreate pck; -pck.bHeader = HEADER_GC_TARGET_CREATE; +pck.header = GC::TARGET_CREATE_NEW; +pck.length = sizeof(pck); pck.lID = info->iID; pck.bType = info->iType; pck.dwVID = info->iArg1; @@ -30,7 +31,8 @@ d->Packet(&pck, sizeof(TPacketGCTargetCreate)); void SendTargetUpdatePacket(LPDESC d, int iID, int x, int y) { TPacketGCTargetUpdate pck; -pck.bHeader = HEADER_GC_TARGET_UPDATE; +pck.header = GC::TARGET_UPDATE; +pck.length = sizeof(pck); pck.lID = iID; pck.lX = x; pck.lY = y; @@ -41,7 +43,8 @@ sys_log(0, "SendTargetUpdatePacket %d %dx%d", iID, x, y); void SendTargetDeletePacket(LPDESC d, int iID) { TPacketGCTargetDelete pck; -pck.bHeader = HEADER_GC_TARGET_DELETE; +pck.header = GC::TARGET_DELETE; +pck.length = sizeof(pck); pck.lID = iID; d->Packet(&pck, sizeof(TPacketGCTargetDelete)); } diff --git a/src/game/threeway_war.cpp b/src/game/threeway_war.cpp index 70244e3..168f3e5 100644 --- a/src/game/threeway_war.cpp +++ b/src/game/threeway_war.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "threeway_war.h" @@ -6,7 +6,7 @@ #include "common/tables.h" #include "p2p.h" #include "locale_service.h" -#include "packet.h" +#include "packet_structs.h" #include "char.h" #include "questmanager.h" #include "questlua.h" @@ -515,14 +515,14 @@ void CThreeWayWar::onDead(LPCHARACTER pChar, LPCHARACTER pkKiller) struct packet_script pack_script; - pack_script.header = HEADER_GC_SCRIPT; + pack_script.header = GC::SCRIPT; pack_script.skin = 1; pack_script.src_size = Script.size(); quest::FSendPacketToEmpire fSend; fSend.bEmpire = nVictoryEmpireIndex; - pack_script.size = pack_script.src_size + sizeof(struct packet_script); + pack_script.length = pack_script.src_size + sizeof(struct packet_script); fSend.buf.write(&pack_script, sizeof(struct packet_script)); fSend.buf.write(&Script[0], Script.size()); diff --git a/src/game/war_map.cpp b/src/game/war_map.cpp index 81c3635..377d00e 100644 --- a/src/game/war_map.cpp +++ b/src/game/war_map.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "war_map.h" #include "sectree_manager.h" #include "char.h" @@ -11,7 +11,7 @@ #include "guild_manager.h" #include "buffer_manager.h" #include "db.h" -#include "packet.h" +#include "packet_structs.h" #include "locale_service.h" EVENTINFO(war_map_info) @@ -625,9 +625,9 @@ void CWarMap::SendWarPacket(LPDESC d) TPacketGCGuild pack; TPacketGCGuildWar pack2; - pack.header = HEADER_GC_GUILD; - pack.subheader = GUILD_SUBHEADER_GC_WAR; - pack.size = sizeof(pack) + sizeof(pack2); + pack.header = GC::GUILD; + pack.subheader = GuildSub::GC::WAR; + pack.length = sizeof(pack) + sizeof(pack2); pack2.dwGuildSelf = m_TeamData[0].dwID; pack2.dwGuildOpp = m_TeamData[1].dwID; @@ -642,9 +642,9 @@ void CWarMap::SendScorePacket(BYTE bIdx, LPDESC d) { TPacketGCGuild p; - p.header = HEADER_GC_GUILD; - p.subheader = GUILD_SUBHEADER_GC_WAR_SCORE; - p.size = sizeof(p) + sizeof(DWORD) + sizeof(DWORD) + sizeof(long); + p.header = GC::GUILD; + p.subheader = GuildSub::GC::WAR_SCORE; + p.length = sizeof(p) + sizeof(DWORD) + sizeof(DWORD) + sizeof(long); TEMP_BUFFER buf; buf.write(&p, sizeof(p)); diff --git a/src/game/wedding.cpp b/src/game/wedding.cpp index a42cfad..fe59079 100644 --- a/src/game/wedding.cpp +++ b/src/game/wedding.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "desc_client.h" #include "desc_manager.h" #include "char_manager.h" @@ -379,7 +379,7 @@ namespace marriage p.dwPID2 = dwPID2; p.dwMapIndex = dwMapIndex; - db_clientdesc->DBPacket(HEADER_GD_WEDDING_READY, 0, &p, sizeof(p)); + db_clientdesc->DBPacket(GD::WEDDING_READY, 0, &p, sizeof(p)); } } diff --git a/src/libthecore/buffer.cpp b/src/libthecore/buffer.cpp deleted file mode 100644 index 08432f8..0000000 --- a/src/libthecore/buffer.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include "stdafx.h" - -static LPBUFFER normalized_buffer_pool[32] = { NULL, }; - -#define DEFAULT_POOL_SIZE 8192 - -// internal function forward -void buffer_realloc(LPBUFFER& buffer, int length); - -static int buffer_get_pool_index(int size) { - int i; - for (i = 0; i < 32; ++i) { - if ((1 << i) >= size) { - return i; - } - } - return -1; // too big... not pooled -} -static int buffer_get_exac_pool_index(int size) { - int i; - for (i = 0; i < 32; ++i) { - if ((1 << i) == size) { - return i; - } - } - return -1; // too big... not pooled -} -static void buffer_pool_free () -{ - for (int i = 31; i >= 0; i--) - { - if (normalized_buffer_pool[i] != NULL) - { - LPBUFFER next; - for (LPBUFFER p = normalized_buffer_pool[i]; p != NULL; p = next) - { - next = p->next; - free(p->mem_data); - free(p); - } - normalized_buffer_pool[i] = NULL; - } - } -} -static bool buffer_larger_pool_free (int n) -{ - for (int i = 31; i > n; i--) - { - if (normalized_buffer_pool[i] != NULL) - { - LPBUFFER buffer = normalized_buffer_pool[i]; - LPBUFFER next = buffer->next; - free(buffer->mem_data); - free(buffer); - normalized_buffer_pool[i] = next; - return true; - } - } - return false; -} -bool safe_create(char** pdata, int number) -{ - if (!((*pdata) = (char *) calloc (number, sizeof(char)))) - { - sys_err("calloc failed [%d] %s", errno, strerror(errno)); - return false; - } - else - { - return true; - } -} - -LPBUFFER buffer_new(int size) -{ - if (size < 0) { - return NULL; - } - - LPBUFFER buffer = NULL; - int pool_index = buffer_get_pool_index(size); - if (pool_index >= 0) { - BUFFER** buffer_pool = normalized_buffer_pool + pool_index; - size = 1 << pool_index; - - if (*buffer_pool) { - buffer = *buffer_pool; - *buffer_pool = buffer->next; - } - } - - if (buffer == NULL) - { - CREATE(buffer, BUFFER, 1); - buffer->mem_size = size; - if (!safe_create(&buffer->mem_data, size)) - { - if (!buffer_larger_pool_free(pool_index)) - buffer_pool_free(); - CREATE(buffer->mem_data, char, size); - sys_err ("buffer pool free success."); - } - } - assert(buffer != NULL); - assert(buffer->mem_size == size); - assert(buffer->mem_data != NULL); - - buffer_reset(buffer); - - return buffer; -} - -void buffer_delete(LPBUFFER buffer) -{ - if (buffer == NULL) { - return; - } - buffer_reset(buffer); - - int size = buffer->mem_size; - - int pool_index = buffer_get_exac_pool_index(size); - if (pool_index >= 0) { - BUFFER** buffer_pool = normalized_buffer_pool + pool_index; - buffer->next = *buffer_pool; - *buffer_pool = buffer; - } - else { - free(buffer->mem_data); - free(buffer); - } -} - -DWORD buffer_size(LPBUFFER buffer) -{ - return (buffer->length); -} - -void buffer_reset(LPBUFFER buffer) -{ - buffer->read_point = buffer->mem_data; - buffer->write_point = buffer->mem_data; - buffer->write_point_pos = 0; - buffer->length = 0; - buffer->next = NULL; - buffer->flag = 0; -} - -void buffer_write(LPBUFFER& buffer, const void *src, int length) -{ - if (buffer->write_point_pos + length >= buffer->mem_size) - buffer_realloc(buffer, buffer->mem_size + length + MIN(10240, length)); - - thecore_memcpy(buffer->write_point, src, length); - buffer_write_proceed(buffer, length); -} - -void buffer_read(LPBUFFER buffer, void * buf, int bytes) -{ - thecore_memcpy(buf, buffer->read_point, bytes); - buffer_read_proceed(buffer, bytes); -} - -BYTE buffer_byte(LPBUFFER buffer) -{ - BYTE val = *(BYTE *) buffer->read_point; - buffer_read_proceed(buffer, sizeof(BYTE)); - return val; -} - -WORD buffer_word(LPBUFFER buffer) -{ - WORD val = *(WORD *) buffer->read_point; - buffer_read_proceed(buffer, sizeof(WORD)); - return val; -} - -DWORD buffer_dword(LPBUFFER buffer) -{ - DWORD val = *(DWORD *) buffer->read_point; - buffer_read_proceed(buffer, sizeof(DWORD)); - return val; -} - -const void * buffer_read_peek(LPBUFFER buffer) -{ - return (const void *) buffer->read_point; -} - -void buffer_read_proceed(LPBUFFER buffer, int length) -{ - if (length == 0) - return; - - if (length < 0) - sys_err("buffer_proceed: length argument lower than zero (length: %d)", length); - else if (length > buffer->length) - { - sys_err("buffer_proceed: length argument bigger than buffer (length: %d, buffer: %d)", length, buffer->length); - length = buffer->length; - } - - if (length < buffer->length) - { - if (buffer->read_point + length - buffer->mem_data > buffer->mem_size) - { - sys_err("buffer_read_proceed: buffer overflow! length %d read_point %d", length, buffer->read_point - buffer->mem_data); - abort(); - } - - buffer->read_point += length; - buffer->length -= length; - } - else - { - buffer_reset(buffer); - } -} - -void * buffer_write_peek(LPBUFFER buffer) -{ - return (buffer->write_point); -} - -void buffer_write_proceed(LPBUFFER buffer, int length) -{ - buffer->length += length; - buffer->write_point += length; - buffer->write_point_pos += length; -} - -int buffer_has_space(LPBUFFER buffer) -{ - return (buffer->mem_size - buffer->write_point_pos); -} - -void buffer_adjust_size(LPBUFFER& buffer, int add_size) -{ - if (buffer->mem_size >= buffer->write_point_pos + add_size) - return; - - sys_log(0, "buffer_adjust %d current %d/%d", add_size, buffer->length, buffer->mem_size); - buffer_realloc(buffer, buffer->mem_size + add_size); -} - -void buffer_realloc(LPBUFFER& buffer, int length) -{ - int i, read_point_pos; - LPBUFFER temp; - - assert(length >= 0 && "buffer_realloc: length is lower than zero"); - - if (buffer->mem_size >= length) - return; - - i = length - buffer->mem_size; - - if (i <= 0) - return; - - temp = buffer_new (length); - sys_log(0, "reallocating buffer to %d, current %d", temp->mem_size, buffer->mem_size); - thecore_memcpy(temp->mem_data, buffer->mem_data, buffer->mem_size); - - read_point_pos = buffer->read_point - buffer->mem_data; - - temp->write_point = temp->mem_data + buffer->write_point_pos; - temp->write_point_pos = buffer->write_point_pos; - temp->read_point = temp->mem_data + read_point_pos; - temp->flag = buffer->flag; - temp->next = NULL; - temp->length = buffer->length; - - buffer_delete(buffer); - buffer = temp; -} diff --git a/src/libthecore/buffer.h b/src/libthecore/buffer.h deleted file mode 100644 index 59e1e60..0000000 --- a/src/libthecore/buffer.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#define SAFE_BUFFER_DELETE(buf) { if(buf != NULL) { buffer_delete(buf); buf = NULL; } } - -typedef struct buffer BUFFER; -typedef struct buffer * LPBUFFER; - -struct buffer -{ - struct buffer * next; - - char * write_point; - int write_point_pos; - - const char * read_point; - int length; - - char * mem_data; - int mem_size; - - long flag; -}; - -LPBUFFER buffer_new(int size); -void buffer_delete(LPBUFFER buffer); -void buffer_reset(LPBUFFER buffer); - -DWORD buffer_size(LPBUFFER buffer); -int buffer_has_space(LPBUFFER buffer); - -void buffer_write (LPBUFFER& buffer, const void* src, int length); -void buffer_read(LPBUFFER buffer, void * buf, int bytes); -BYTE buffer_get_byte(LPBUFFER buffer); -WORD buffer_get_word(LPBUFFER buffer); -DWORD buffer_get_dword(LPBUFFER buffer); - -const void* buffer_read_peek(LPBUFFER buffer); -void buffer_read_proceed(LPBUFFER buffer, int length); - -void* buffer_write_peek(LPBUFFER buffer); -void buffer_write_proceed(LPBUFFER buffer, int length); - -void buffer_adjust_size(LPBUFFER& buffer, int add_size); diff --git a/src/libthecore/ring_buffer.h b/src/libthecore/ring_buffer.h new file mode 100644 index 0000000..090346e --- /dev/null +++ b/src/libthecore/ring_buffer.h @@ -0,0 +1,191 @@ +#pragma once + +#include +#include +#include +#include +#include + +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 m_data; + size_t m_readPos = 0; + size_t m_writePos = 0; +}; diff --git a/src/libthecore/socket.cpp b/src/libthecore/socket.cpp index 1a440fb..df30784 100644 --- a/src/libthecore/socket.cpp +++ b/src/libthecore/socket.cpp @@ -10,16 +10,6 @@ void socket_timeout(socket_t s, long sec, long usec); void socket_reuse(socket_t s); void socket_keepalive(socket_t s); -int socket_udp_read(socket_t desc, char * read_point, size_t space_left, struct sockaddr * from, socklen_t * fromlen) -{ - /* - ssize_t recvfrom(int s, void * buf, size_t len, int flags, struct sockaddr * from, socklen_t * fromlen); - */ - ssize_t ret; - ret = recvfrom(desc, read_point, space_left, 0, from, fromlen); - return (ret); -} - int socket_read(socket_t desc, char* read_point, size_t space_left) { int ret; @@ -198,11 +188,6 @@ int socket_tcp_bind(const char * ip, int port) return socket_bind(ip, port, SOCK_STREAM); } -int socket_udp_bind(const char * ip, int port) -{ - return socket_bind(ip, port, SOCK_DGRAM); -} - void socket_close(socket_t s) { #ifdef OS_WINDOWS @@ -235,6 +220,7 @@ socket_t socket_accept(socket_t s, struct sockaddr_in *peer) socket_nonblock(desc); socket_lingeroff(desc); socket_nodelay(desc); + socket_keepalive(desc); return (desc); } diff --git a/src/libthecore/socket.h b/src/libthecore/socket.h index dfed657..e8f8b27 100644 --- a/src/libthecore/socket.h +++ b/src/libthecore/socket.h @@ -9,9 +9,7 @@ typedef int socklen_t; int socket_read(socket_t desc, char* read_point, size_t space_left); int socket_write(socket_t desc, const char *data, size_t length); -int socket_udp_read(socket_t desc, char * read_point, size_t space_left, struct sockaddr * from, socklen_t * fromlen); int socket_tcp_bind(const char * ip, int port); -int socket_udp_bind(const char * ip, int port); socket_t socket_accept(socket_t s, struct sockaddr_in *peer); void socket_close(socket_t s); diff --git a/src/libthecore/stdafx.h b/src/libthecore/stdafx.h index e9eafde..8a2def2 100644 --- a/src/libthecore/stdafx.h +++ b/src/libthecore/stdafx.h @@ -117,7 +117,7 @@ inline double rint(double x) #include "socket.h" #include "kstbl.h" #include "hangul.h" -#include "buffer.h" + #include "signal.h" #include "log.h" #include "main.h" diff --git a/vendor/libsodium/src/libsodium/include/sodium/version.h b/vendor/libsodium/src/libsodium/include/sodium/version.h new file mode 100644 index 0000000..e07ae90 --- /dev/null +++ b/vendor/libsodium/src/libsodium/include/sodium/version.h @@ -0,0 +1,33 @@ + +#ifndef sodium_version_H +#define sodium_version_H + +#include "export.h" + +#define SODIUM_VERSION_STRING "1.0.20" + +#define SODIUM_LIBRARY_VERSION_MAJOR 26 +#define SODIUM_LIBRARY_VERSION_MINOR 2 + + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +const char *sodium_version_string(void); + +SODIUM_EXPORT +int sodium_library_version_major(void); + +SODIUM_EXPORT +int sodium_library_version_minor(void); + +SODIUM_EXPORT +int sodium_library_minimal(void); + +#ifdef __cplusplus +} +#endif + +#endif