Group Utility units into subsystem folders and require OFFSET provenance

Move Lexicon*, Text (TextTokens, TextEscapes, Base64), Math/RadialGrid, Hash (MD5, XxHash32) and Cipher (Rijndael, XorBytes) into Source/Utility subfolders; update includes, guards, compile.json and CMakeLists.txt. Backfill // OFFSET: above every standalone // FUNCTION: block (89 IDs, addresses from the symbol database) and make it mandatory in CODING_RULES.md and AGENTS.md. Remove the MatchLexicon cast chain.
This commit is contained in:
ragnarok-clanker 2026-10-26 23:41:07 +01:00 • committed by ragnarok-clanker
commit bf6a44c117
58 changed files with 161 additions and 70 deletions

View file

@ -48,6 +48,7 @@ td sync
(imported IDA pseudocode where available, a starting point only).
4. **Write each function** in its file, directly preceded by its annotation:
```cpp
// OFFSET: 0x00AE97D0
// FUNCTION: fn_00123
void Player::Update(float dt)
{
@ -115,8 +116,9 @@ other contributors' agents: a function merges once "same" leads
## Rules
- **Annotations contain stable IDs, never addresses.** Addresses live in the
symbol database, so the source survives new versions of the executable.
- **Stable-ID annotations contain IDs, never addresses.** The symbol database is
authoritative for addresses. Every standalone function additionally carries
`// OFFSET: 0x...` above its `// FUNCTION:` line, copied from `td symbol <id>`.
If you need a new global, vtable or string, call `td_new_symbol` and use the
returned annotation (`// GLOBAL: gl_00045`).
- **Globals have one real definition.** Put a global's stable data annotation on its owning
@ -138,7 +140,7 @@ other contributors' agents: a function merges once "same" leads
- Prefer real names and struct members over raw offsets and casts. Use
`// TODO:` comments for things you are unsure about.
- **No comments, no invented strings.** A submission may not add comments other
than annotations (`// FUNCTION: fn_00123`), offset markers (`/* 0010 */`) and
than annotations (`// OFFSET: 0x00AE97D0`, `// FUNCTION: fn_00123`), offset markers (`/* 0010 */`) and
`// INLINED` markers, and may only use string literals that exist in the
original executable. Everything else is rejected before compiling. Names of
functions, variables and types are the only free text.

View file

@ -8,15 +8,15 @@ endif()
add_subdirectory(ThirdParty)
add_library(RagnarokUtility STATIC
Source/Utility/XorBytes.cpp
Source/Utility/Base64.cpp
Source/Utility/Cipher/XorBytes.cpp
Source/Utility/Text/Base64.cpp
Source/Utility/Text/GroupedInteger.cpp
Source/Utility/Text/LanguageCharset.cpp
Source/Utility/Math/ClientAngles.cpp
Source/Utility/Math/AffineMatrix.cpp
Source/Utility/Math/AffineLookAt.cpp
Source/Utility/Math/RayTriangle.cpp
Source/Utility/Rijndael.cpp
Source/Utility/Cipher/Rijndael.cpp
)
target_include_directories(RagnarokUtility PUBLIC

View file

@ -7,7 +7,7 @@ These apply to rodecomp: Ragnarok Online Ragexe 2026-02-19 (x86), built with MSV
Code carries no explanatory comments: none inside functions, none above them, no file headers, no
commented-out code. Allowed comments are Clank stable-ID annotations (`// FUNCTION:`, `// GLOBAL:`,
`// STRING:`, `// VTABLE:`), existing `// OFFSET:` / `// STATIC:` provenance where permitted below,
`// STRING:`, `// VTABLE:`), `// OFFSET:` provenance on standalone functions, existing `// STATIC:` provenance,
exact bare `// INLINED` markers, and field-offset markers (`/* XXXX */`). Use only string literals evidenced in the original executable.
Put explanations in submission notes rather than adding source comments or creating documentation by default.
@ -17,19 +17,22 @@ or disabling the gate. This document does not change the server's accepted synta
## 2. Stable IDs identify implementations and data
Every reconstructed standalone function gets its existing stable ID directly above its definition:
Every reconstructed standalone function gets its `// OFFSET:` address and its existing stable ID directly above its definition:
```cpp
// OFFSET: 0x00AE97D0
// FUNCTION: fn_00123
void Player::Update(float dt) {
...
}
```
- Stable-ID annotations contain IDs, never addresses. Addresses live in the symbol database.
- Preserve existing `// OFFSET: 0x...` provenance for standalone functions and `// STATIC: 0x...` provenance
for data. Inline-only functions must not carry `OFFSET` provenance. Do not invent addresses or require
new address comments as a substitute for stable IDs.
- `// OFFSET: 0x...` is mandatory on every standalone `// FUNCTION:` definition: one line per stacked ID, placed above
the `FUNCTION` lines, with the address `td symbol <id>` reports (eight uppercase hex digits). Never type an address
from memory or a decompiler listing that disagrees with the symbol database.
- `FUNCTION`/`GLOBAL`/`STRING`/`VTABLE` annotations contain IDs, never addresses; the symbol database stays
authoritative. Preserve existing `// STATIC: 0x...` provenance for data. Inline-only functions must not carry
`OFFSET` provenance.
- Use the existing ID of the actual original function. Do not annotate an ordinary destructor with a
scalar-deleting destructor's ID, or stack a thunk's ID onto its target.
- For symbols missing from the database, use `td_new_symbol` and its returned annotation.

View file

@ -85,6 +85,7 @@ bool PakRegistry::Exists(const char* filename, bool looseOnly) const {
return true;
}
// OFFSET: 0x00AEA1F0
// FUNCTION: fn_18116
void PakRegistry::ApplyAuxiliary(const void*, std::uint32_t) {
}

View file

@ -114,6 +114,7 @@ const char* TraditionalKeyInput::NextCharArabic(const char* current, int) {
return CharNextExA(static_cast<WORD>(g_textCodePage), current, 0);
}
// OFFSET: 0x00ACD7D0
// FUNCTION: fn_17768
void TraditionalKeyInputNoop() {}

View file

@ -4,6 +4,7 @@
// GLOBAL: gl_24475
CWorld g_world = {1};
// OFFSET: 0x00AD6450
// FUNCTION: fn_17831
CGameMode* CWorld::ActiveGameMode() {
return this->state == 1 ? this->gameMode : nullptr;

View file

@ -3,6 +3,7 @@
#include <cmath>
// OFFSET: 0x00CA9580
// FUNCTION: fn_21007
float __stdcall CRenderObject::Heading(float x, float z, float targetX, float targetZ) {
const float deltaX = targetX - x;
@ -19,6 +20,7 @@ float __stdcall CRenderObject::Heading(float x, float z, float targetX, float ta
return angle;
}
// OFFSET: 0x00CA9610
// FUNCTION: fn_21008
void CRenderObject::Face(float x, float z) {
const float deltaX = x - this->render.position[0];
@ -37,6 +39,7 @@ void CRenderObject::Face(float x, float z) {
}
}
// OFFSET: 0x00CA96C0
// FUNCTION: fn_21009
float CRenderObject::HorizontalDistance(float x, float z) const {
const float deltaX = x - this->render.position[0];
@ -44,6 +47,7 @@ float CRenderObject::HorizontalDistance(float x, float z) const {
return SquareRoot(deltaZ * deltaZ + deltaX * deltaX);
}
// OFFSET: 0x00CA9700
// FUNCTION: fn_21010
float CRenderObject::Distance(float x, float y, float z) const {
const float deltaX = x - this->render.position[0];

View file

@ -2,6 +2,7 @@
// OFFSET: 0x005BEC80
// FUNCTION: fn_03487
void CActorNameCard::Reset() {
this->name.clear();
@ -13,15 +14,18 @@ void CActorNameCard::Reset() {
this->unknown_0094 = 0;
}
// OFFSET: 0x005BF080
// FUNCTION: fn_03491
CActorNameCardHolder::CActorNameCardHolder() = default;
// OFFSET: 0x005BFEF0
// FUNCTION: fn_03501
std::string CActorNameCardHolder::Name(std::uint32_t id) {
return this->cards[id].name;
}
// OFFSET: 0x005C0050
// FUNCTION: fn_03502
void CActorNameCardHolder::Clear() {
this->cards.clear();
@ -29,6 +33,7 @@ void CActorNameCardHolder::Clear() {
this->requests.clear();
}
// OFFSET: 0x005C03B0
// FUNCTION: fn_03505
void CActorNameCardHolder::Set(std::uint32_t id, std::string name, std::string value1, std::string value2, std::string value3, std::string value4,
std::string value5, std::uint32_t value) {
@ -61,6 +66,7 @@ void CActorNameCardHolder::Set(std::uint32_t id, std::string name, std::string v
card.received = 1;
}
// OFFSET: 0x005C0E60
// FUNCTION: fn_03507
void CActorNameCardHolder::SetName(std::uint32_t id, std::string name) {
CActorNameCard& card = this->cards[id];

View file

@ -41,6 +41,7 @@ inline RagEffectState::~RagEffectState() {
}
}
// OFFSET: 0x00BF84B0
// FUNCTION: fn_20007
AttachedEffect::AttachedEffect(ResourceMgr& resources, JobNames& names) : CRenderObject(resources, names) {
}

View file

@ -60,6 +60,7 @@ void EffectAttachments::DetachAll() {
this->second = nullptr;
}
// OFFSET: 0x00CADC20
// FUNCTION: fn_21063
bool EffectActor::EffectVisible() const {
return this->render.visible != 0 && this->render.enabled != 0;

View file

@ -1,12 +1,15 @@
#include "Contents/GuildMgr.h"
// OFFSET: 0x0065C440
// FUNCTION: fn_05147
CGuild::CGuild() : m_emblemVersion(0) {
}
// OFFSET: 0x0065C450
// FUNCTION: fn_05148
CGuild::~CGuild() = default;
// OFFSET: 0x0065E640
// FUNCTION: fn_05175
int CGuildMgr::GetEmblemVersion(std::uint32_t guildId) const {
const auto it = this->m_guilds.find(guildId);
@ -16,6 +19,7 @@ int CGuildMgr::GetEmblemVersion(std::uint32_t guildId) const {
return 0;
}
// OFFSET: 0x0065EEA0
// FUNCTION: fn_05181
void CGuildMgr::SetEmblemVersion(std::uint32_t guildId, int version) {
this->m_guilds[guildId].m_emblemVersion = version;

View file

@ -23,6 +23,7 @@ CGuildMgr::~CGuildMgr() {
}
}
// OFFSET: 0x0065E290
// FUNCTION: fn_05172
bool CGuildMgr::Create() {
if (g_guildMgr) {
@ -43,6 +44,7 @@ bool CGuildMgr::Create() {
return true;
}
// OFFSET: 0x0065E430
// FUNCTION: fn_05173
void CGuildMgr::Destroy() {
if (g_guildMgr) {

View file

@ -49,6 +49,7 @@ ITEM_DESC& ItemDescriptions::Find(int id) {
return entry == this->values.end() ? missing : entry->second;
}
// OFFSET: 0x006D3AE0
// FUNCTION: fn_06546
ItemCardName& EnsureItemCardName(int id, std::map<int, ItemCardName>& values) {
const auto entry = values.find(id);
@ -59,6 +60,7 @@ ItemCardName& EnsureItemCardName(int id, std::map<int, ItemCardName>& values) {
return values[id];
}
// OFFSET: 0x006D3C10
// FUNCTION: fn_06547
std::vector<const char*>& EnsureItemDescriptionLines(int id, std::map<int, std::vector<const char*>>& values) {
const auto entry = values.find(id);

View file

@ -116,6 +116,7 @@ void JobInheritance::InitializeSkillTree(CPlayerSkillBundle& bundle, int job) {
}
}
// OFFSET: 0x00DE0830
// FUNCTION: fn_23461
int __stdcall GetRealWeaponId(int weapon) {
int real = 0;

View file

@ -1,6 +1,6 @@
#include "Contents/MessageTable.h"
#include "Network/TextEncoding.h"
#include "Utility/Base64.h"
#include "Utility/Text/Base64.h"
#include "Utility/Text/LanguageCharset.h"
#include <cstdio>

View file

@ -30,10 +30,12 @@ C3dNodeV2::C3dNodeV2() = default;
// OFFSET: 0x00AB6C50
C3dNodeV2::~C3dNodeV2() = default;
// OFFSET: 0x00AB7040
// FUNCTION: fn_17481
void C3dNode::Initialize(const ModelNode&) {
}
// OFFSET: 0x00AB9110
// FUNCTION: fn_17506
void C3dNode::Animate(double) {
}

View file

@ -8,6 +8,7 @@ namespace {
return std::fabs(value);
}
// OFFSET: 0x00553850
// FUNCTION: fn_02019
bool Intersects(const float* ray, const OrientedBounds& bounds) {
const float delta[3] = {bounds.center[0] - ray[0], bounds.center[1] - ray[1], bounds.center[2] - ray[2]};

View file

@ -1,5 +1,6 @@
#include "Contents/MovementRouteInterpolation.h"
// OFFSET: 0x00AD92C0
// FUNCTION: fn_17876
int MovementRouteInterpolation::Sample(std::uint32_t tick, float* x, float* y, int* metadata) {
if (this->points.empty()) {
@ -57,6 +58,7 @@ int MovementRouteInterpolation::Sample(std::uint32_t tick, float* x, float* y, i
return static_cast<int>(index);
}
// OFFSET: 0x00AD9500
// FUNCTION: fn_17877
std::uint32_t MovementRouteInterpolation::Segment() const {
return this->segment;

View file

@ -87,6 +87,7 @@ void WorldModelLoading::Schedule(const WorldModelRecord& placement, const Terrai
}
}
// OFFSET: 0x00AC8BF0
// FUNCTION: fn_17680
DWORD WINAPI WorldModelLoading::ThreadEntry(void* context) {
static_cast<WorldModelLoading*>(context)->Run();

View file

@ -40,6 +40,7 @@ void MarkWorldOcclusionRay(const float* ray, float actorLimit, float groundLimit
}
}
// OFFSET: 0x00CD5AD0
// FUNCTION: fn_21286
void MarkScreenWorldOcclusion(
const RenderProjection& projection, int screenX, int screenY, float rendererScale, const float* origin, const float* cameraMatrix, float playerHeight,

View file

@ -31,6 +31,7 @@ namespace {
return static_cast<std::uint16_t>((value >> (channel.expansion & 31)) << (channel.shift & 31));
}
// OFFSET: 0x00543220
// FUNCTION: fn_01787
std::uint16_t Color(DeviceOwnerDX7& owner, unsigned red, unsigned green, unsigned blue) {
return static_cast<std::uint16_t>(Channel(red, owner.red) + Channel(green, owner.green) + Channel(blue, owner.blue));
@ -228,56 +229,67 @@ void CSurfaceDX7::Stretch(int, int, int width, int height) {
this->m_owner->renderTarget->Blt(&destination, this->m_surface, nullptr, DDBLT_WAIT, nullptr);
}
// OFFSET: 0x00543270
// FUNCTION: fn_01788
DWORD DeviceOwnerDX7::BlueMask() {
return this->blueMask;
}
// OFFSET: 0x00543280
// FUNCTION: fn_01789
DWORD DeviceOwnerDX7::BlueExpansion() {
return this->blue.expansion;
}
// OFFSET: 0x00543290
// FUNCTION: fn_01790
DWORD DeviceOwnerDX7::BlueShift() {
return this->blue.shift;
}
// OFFSET: 0x005432D0
// FUNCTION: fn_01792
IDirectDraw7* DeviceOwnerDX7::DirectDraw() {
return this->draw;
}
// OFFSET: 0x005432E0
// FUNCTION: fn_01793
DWORD DeviceOwnerDX7::GreenMask() {
return this->greenMask;
}
// OFFSET: 0x005432F0
// FUNCTION: fn_01794
DWORD DeviceOwnerDX7::GreenExpansion() {
return this->green.expansion;
}
// OFFSET: 0x00543300
// FUNCTION: fn_01795
DWORD DeviceOwnerDX7::GreenShift() {
return this->green.shift;
}
// OFFSET: 0x00543320
// FUNCTION: fn_01797
DWORD DeviceOwnerDX7::RedMask() {
return this->redMask;
}
// OFFSET: 0x00543330
// FUNCTION: fn_01798
DWORD DeviceOwnerDX7::RedExpansion() {
return this->red.expansion;
}
// OFFSET: 0x00543340
// FUNCTION: fn_01799
DWORD DeviceOwnerDX7::RedShift() {
return this->red.shift;
}
// OFFSET: 0x00543350
// FUNCTION: fn_01800
IDirectDrawSurface7* DeviceOwnerDX7::RenderTarget() {
return this->renderTarget;

View file

@ -31,6 +31,7 @@ DeviceOwnerDX9::DeviceOwnerDX9() {
this->lastPresent = 0;
}
// OFFSET: 0x0054B830
// FUNCTION: fn_01907
void DeviceOwnerDX9Noop() {}

View file

@ -10,16 +10,19 @@ std::shared_ptr<CSurface> AcquireBackBufferSurface(CRenderSystemBase* system) {
return system ? system->BackBufferSurface() : std::shared_ptr<CSurface>{};
}
// OFFSET: 0x00569F10
// FUNCTION: fn_02274
CRenderer* RenderSystemHolder::CreateRenderer() {
return this->system ? this->system->CreateRenderer() : nullptr;
}
// OFFSET: 0x00569F80
// FUNCTION: fn_02278
HRESULT RenderSystemHolder::Close() {
return this->system ? this->system->Close() : E_ILLEGAL_METHOD_CALL;
}
// OFFSET: 0x00569FC0
// FUNCTION: fn_02280
void RenderSystemHolder::UpdateOption() {
if (this->system) {
@ -27,6 +30,7 @@ void RenderSystemHolder::UpdateOption() {
}
}
// OFFSET: 0x00569FD0
// FUNCTION: fn_02281
void RenderSystemHolder::RestoreDisplayMode() {
if (this->system) {
@ -34,6 +38,7 @@ void RenderSystemHolder::RestoreDisplayMode() {
}
}
// OFFSET: 0x00569FE0
// FUNCTION: fn_02282
void RenderSystemHolder::PrepareErrorDialog() {
if (this->system) {
@ -41,31 +46,37 @@ void RenderSystemHolder::PrepareErrorDialog() {
}
}
// OFFSET: 0x0056A230
// FUNCTION: fn_02285
std::int32_t RenderSystemHolder::Backend() const {
return this->system ? this->system->Backend() : -1;
}
// OFFSET: 0x0056A280
// FUNCTION: fn_02287
CTexture* RenderSystemHolder::BackBufferTexture() const {
return this->system ? this->system->BackBufferTexture() : nullptr;
}
// OFFSET: 0x0056A290
// FUNCTION: fn_02288
std::uint32_t RenderSystemHolder::Height() const {
return this->system ? this->system->Height() : 0;
}
// OFFSET: 0x0056A690
// FUNCTION: fn_02292
std::uint32_t RenderSystemHolder::Width() const {
return this->system ? this->system->Width() : 0;
}
// OFFSET: 0x0056A790
// FUNCTION: fn_02294
bool RenderSystemHolder::IsWindowed() const {
return this->system ? this->system->IsWindowed() : false;
}
// OFFSET: 0x0056A7A0
// FUNCTION: fn_02295
HRESULT RenderSystemHolder::TestDevice() const {
return this->system ? this->system->TestDevice() : E_ILLEGAL_METHOD_CALL;

View file

@ -38,6 +38,7 @@ struct RenderSystemHolder {
HRESULT Present(bool option) const;
};
// OFFSET: 0x0055D340
// FUNCTION: fn_02102
__declspec(noinline) inline RenderSystemHolder* GetRenderSystemHolder() {
static RenderSystemHolder holder;

View file

@ -8,6 +8,7 @@
// GLOBAL: gl_24481
CRenderer* g_renderer;
// OFFSET: 0x00569270
// FUNCTION: fn_02251
RenderVertex* RenderVertex::Reset() {
this->x = 0;

View file

@ -68,6 +68,7 @@ void BitmapPixels::Create(int newWidth, int newHeight) {
this->previous = SelectObject(this->dc, this->bitmap);
}
// OFFSET: 0x00547A80
// FUNCTION: fn_01845
HGDIOBJ CDCBitmap::Create(int width, int height) {
this->m_bitmap.width = width;

View file

@ -68,6 +68,7 @@ std::uint32_t CTexture::SetImageSize(std::uint32_t width, std::uint32_t height)
return width;
}
// OFFSET: 0x00572480
// FUNCTION: fn_02470
int CTexture::SetName(const char* name) {
return strncpy_s(this->m_name, sizeof(this->m_name), name, _TRUNCATE);

View file

@ -1,5 +1,6 @@
#include "Render/Renderer.h"
// OFFSET: 0x0055D480
// FUNCTION: fn_02104
float* CRenderer::ProjectViewport(const float* position, const float* matrix, float* x, float* y, float* reciprocalDepth) {
const float inverse = 1.0f / (((matrix[2] * position[0] + matrix[5] * position[1]) + matrix[8] * position[2]) + matrix[11]);
@ -11,6 +12,7 @@ float* CRenderer::ProjectViewport(const float* position, const float* matrix, fl
return y;
}
// OFFSET: 0x0055D560
// FUNCTION: fn_02105
float* CRenderer::ProjectViewportCentered(
const float* position, const float* matrix, float* x, float* y, float* reciprocalDepth, float width, float height

View file

@ -53,6 +53,7 @@ void CRes::MissingFile(CRenderSystemBase* system, const char* name) {
ShowErrorDialog(system, text, 0);
}
// OFFSET: 0x00AEFAD0
// FUNCTION: fn_18183
std::uint32_t CRes::AddRef() {
return ++this->references;

View file

@ -28,6 +28,7 @@ CActRes::CActRes(ActionResourceContext& context) : maximumCells(0), m_context(&c
// INLINED
CActRes::~CActRes() = default;
// OFFSET: 0x007436B0
// FUNCTION: fn_07749
CActRes* CActRes::Create() {
return new CActRes(*this->m_context);

View file

@ -18,6 +18,7 @@ CSprRes::CSprRes(SpriteResourceContext& context) : indexedCount(0), m_context(&c
// INLINED
CSprRes::~CSprRes() = default;
// OFFSET: 0x0075FE90
// FUNCTION: fn_08053
CSprRes* CSprRes::Create() {
return new CSprRes(*this->m_context);

View file

@ -22,6 +22,7 @@ namespace {
return value < 0 ? (0 - value) : value;
}
// OFFSET: 0x007E2DB0
// FUNCTION: fn_09714
bool ContainsUpward(SnapObject* object, SnapObject* target) {
if (object == target) {

View file

@ -1,4 +1,4 @@
#include "Utility/Rijndael.h"
#include "Utility/Cipher/Rijndael.h"
#include <cstring>
#include <exception>

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_RIJNDAEL_H
#define RAGNAROK_SOURCE_UTILITY_RIJNDAEL_H
#ifndef RAGNAROK_SOURCE_UTILITY_CIPHER_RIJNDAEL_H
#define RAGNAROK_SOURCE_UTILITY_CIPHER_RIJNDAEL_H
#include <cstddef>
#include <cstdint>

View file

@ -1,4 +1,4 @@
#include "Utility/XorBytes.h"
#include "Utility/Cipher/XorBytes.h"
namespace utility {
// OFFSET: 0x005A45E0

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_XORBYTES_H
#define RAGNAROK_SOURCE_UTILITY_XORBYTES_H
#ifndef RAGNAROK_SOURCE_UTILITY_CIPHER_XORBYTES_H
#define RAGNAROK_SOURCE_UTILITY_CIPHER_XORBYTES_H
#include <cstdint>

View file

@ -1,4 +1,4 @@
#include "Utility/MD5.h"
#include "Utility/Hash/MD5.h"
#include <cstring>
#include <cwchar>
@ -14,6 +14,7 @@ namespace {
}
}
// OFFSET: 0x00401C40
// FUNCTION: fn_00121
MD5::MD5() {
}

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_MD5_H
#define RAGNAROK_SOURCE_UTILITY_MD5_H
#ifndef RAGNAROK_SOURCE_UTILITY_HASH_MD5_H
#define RAGNAROK_SOURCE_UTILITY_HASH_MD5_H
#include <cstdint>

View file

@ -1,4 +1,4 @@
#include "Utility/XxHash32.h"
#include "Utility/Hash/XxHash32.h"
#include <bit>
#include <cstring>
@ -12,6 +12,7 @@ namespace {
}
}
// OFFSET: 0x004D3490
// FUNCTION: fn_00163
std::uint32_t FinalizeXxHash32(std::uint32_t hash, const void* data, std::uint32_t remaining, int) {
const auto* current = static_cast<const unsigned char*>(data);
@ -38,6 +39,7 @@ std::uint32_t FinalizeXxHash32(std::uint32_t hash, const void* data, std::uint32
return hash;
}
// OFFSET: 0x004D3320
// FUNCTION: fn_00162
std::uint32_t XxHash32(const void* data, std::uint32_t length, std::uint32_t seed) {
const auto* current = static_cast<const unsigned char*>(data);

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_XXHASH32_H
#define RAGNAROK_SOURCE_UTILITY_XXHASH32_H
#ifndef RAGNAROK_SOURCE_UTILITY_HASH_XXHASH32_H
#define RAGNAROK_SOURCE_UTILITY_HASH_XXHASH32_H
#include <cstdint>

View file

@ -1,5 +1,6 @@
#include "Utility/LexiconBoundary.h"
#include "Utility/Lexicon/LexiconBoundary.h"
// OFFSET: 0x00AC4EA0
// FUNCTION: fn_17634
bool LexiconBoundary::Matches(unsigned char previous, unsigned char current, unsigned char options) const {
if (previous == 0xDD) {

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_LEXICONBOUNDARY_H
#define RAGNAROK_SOURCE_UTILITY_LEXICONBOUNDARY_H
#ifndef RAGNAROK_SOURCE_UTILITY_LEXICON_LEXICONBOUNDARY_H
#define RAGNAROK_SOURCE_UTILITY_LEXICON_LEXICONBOUNDARY_H
#include <cstdint>

View file

@ -1,7 +1,6 @@
#include "Utility/LexiconMatcher.h"
#include <cstdint>
#include "Utility/Lexicon/LexiconMatcher.h"
// OFFSET: 0x00AC48E0
// FUNCTION: fn_17631
int __stdcall MatchLexicon(const unsigned char* data, int, const unsigned char* text, const unsigned char* end, int) {
if (*text == 0) {
@ -17,14 +16,13 @@ int __stdcall MatchLexicon(const unsigned char* data, int, const unsigned char*
return matched;
}
std::uint32_t offset = (static_cast<std::uint32_t>(entry[0] & 0x3F) << 16) |
(static_cast<std::uint32_t>(entry[1]) << 8) | entry[2];
int offset = ((entry[0] & 0x3F) << 16) | (entry[1] << 8) | entry[2];
entry += 3;
const unsigned char* candidate = data + offset;
const unsigned int count = *candidate;
const int count = *candidate;
if (count < 0x20 && candidate[1] == *text) {
++offset;
for (unsigned int index = 0; index < count; ++index) {
for (int index = 0; index < count; ++index) {
if (data[offset++] != *text) {
failed = true;
break;
@ -54,7 +52,7 @@ int __stdcall MatchLexicon(const unsigned char* data, int, const unsigned char*
++matched;
entry = candidate + 1;
++text;
if (static_cast<signed char>(*entry) < 0) {
if ((*entry & 0x80) != 0) {
accepted = matched;
}
}

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_LEXICONMATCHER_H
#define RAGNAROK_SOURCE_UTILITY_LEXICONMATCHER_H
#ifndef RAGNAROK_SOURCE_UTILITY_LEXICON_LEXICONMATCHER_H
#define RAGNAROK_SOURCE_UTILITY_LEXICON_LEXICONMATCHER_H
int __stdcall MatchLexicon(const unsigned char* data, int mode, const unsigned char* text, const unsigned char* end, int options);

View file

@ -1,5 +1,6 @@
#include "Utility/LexiconSerializer.h"
#include "Utility/Lexicon/LexiconSerializer.h"
// OFFSET: 0x00AC3FF0
// FUNCTION: fn_17630
void LexiconSerializer::Destroy(LexiconNode* node) {
if (node != nullptr) {
@ -9,6 +10,7 @@ void LexiconSerializer::Destroy(LexiconNode* node) {
}
}
// OFFSET: 0x00AC4D40
// FUNCTION: fn_17633
std::uint32_t LexiconSerializer::Serialize(LexiconNode* node, std::uint32_t offset, unsigned char terminal) {
int siblings = 0;

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_LEXICONSERIALIZER_H
#define RAGNAROK_SOURCE_UTILITY_LEXICONSERIALIZER_H
#ifndef RAGNAROK_SOURCE_UTILITY_LEXICON_LEXICONSERIALIZER_H
#define RAGNAROK_SOURCE_UTILITY_LEXICON_LEXICONSERIALIZER_H
#include <cstdint>

View file

@ -1,7 +1,8 @@
#include "Utility/RadialGrid.h"
#include "Utility/Math/RadialGrid.h"
#include <cstdint>
// OFFSET: 0x00AF61A0
// FUNCTION: fn_18251
std::vector<RadialGridPoint> GenerateRadialGrid(const RadialGridPoint& center, int radius) {
std::vector<RadialGridPoint> points;

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_RADIALGRID_H
#define RAGNAROK_SOURCE_UTILITY_RADIALGRID_H
#ifndef RAGNAROK_SOURCE_UTILITY_MATH_RADIALGRID_H
#define RAGNAROK_SOURCE_UTILITY_MATH_RADIALGRID_H
#include <vector>

View file

@ -1,4 +1,4 @@
#include "Utility/Base64.h"
#include "Utility/Text/Base64.h"
#include <algorithm>

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_BASE64_H
#define RAGNAROK_SOURCE_UTILITY_BASE64_H
#ifndef RAGNAROK_SOURCE_UTILITY_TEXT_BASE64_H
#define RAGNAROK_SOURCE_UTILITY_TEXT_BASE64_H
#include <string>

View file

@ -26,6 +26,7 @@ int StringFormat(char* buffer, std::size_t sizeInBytes, std::size_t count, const
namespace {
class ThreadSafeBuffer {
public:
// OFFSET: 0x00733F00
// FUNCTION: fn_07592
ThreadSafeBuffer() {
InitializeCriticalSection(&this->m_criticalSection);

View file

@ -1,5 +1,6 @@
#include "Utility/TextEscapes.h"
#include "Utility/Text/TextEscapes.h"
// OFFSET: 0x00AF41D0
// FUNCTION: fn_18244
void DecodeTextEscapes(std::string& text) {
for (std::size_t position = text.find("\\r"); position != std::string::npos; position = text.find("\\r")) {

View file

@ -0,0 +1,8 @@
#ifndef RAGNAROK_SOURCE_UTILITY_TEXT_TEXTESCAPES_H
#define RAGNAROK_SOURCE_UTILITY_TEXT_TEXTESCAPES_H
#include <string>
void DecodeTextEscapes(std::string& text);
#endif

View file

@ -1,4 +1,4 @@
#include "Utility/TextTokens.h"
#include "Utility/Text/TextTokens.h"
#include <cstring>
@ -17,12 +17,14 @@ const unsigned char g_colorHexDigit[256] = {
// GLOBAL: gl_24543
unsigned char g_inlineCharset = 0xFF;
// OFFSET: 0x0054FF10
// FUNCTION: fn_01963
bool IsPipeColorToken(const char* text) {
return g_inlineCharset == 0 && std::strlen(text) >= 3 && *text == '|' &&
g_colorHexDigit[static_cast<unsigned char>(text[1])] != 0 && g_colorHexDigit[static_cast<unsigned char>(text[2])] != 0;
}
// OFFSET: 0x0054FF60
// FUNCTION: fn_01964
bool IsHexColorToken(const char* text, const char* end) {
if (*text != '^' || end - text <= 6) {
@ -38,6 +40,7 @@ bool IsHexColorToken(const char* text, const char* end) {
return true;
}
// OFFSET: 0x009BA740
// FUNCTION: fn_13883
std::string __stdcall StripColorTokens(const char* text, std::uint32_t length) {
std::string result;

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UTILITY_TEXTTOKENS_H
#define RAGNAROK_SOURCE_UTILITY_TEXTTOKENS_H
#ifndef RAGNAROK_SOURCE_UTILITY_TEXT_TEXTTOKENS_H
#define RAGNAROK_SOURCE_UTILITY_TEXT_TEXTTOKENS_H
#include <cstdint>
#include <string>

View file

@ -1,8 +0,0 @@
#ifndef RAGNAROK_SOURCE_UTILITY_TEXTESCAPES_H
#define RAGNAROK_SOURCE_UTILITY_TEXTESCAPES_H
#include <string>
void DecodeTextEscapes(std::string& text);
#endif

View file

@ -1,9 +1,11 @@
#include "Utility/Timestamp.h"
// OFFSET: 0x00AE81A0
// FUNCTION: fn_18084
Timestamp::~Timestamp() {
}
// OFFSET: 0x00AE81B0
// FUNCTION: fn_18085
TIMESTAMP_STRUCT Timestamp::ToSqlTimestamp() {
TIMESTAMP_STRUCT result{};
@ -22,11 +24,13 @@ TIMESTAMP_STRUCT Timestamp::ToSqlTimestamp() {
return result;
}
// OFFSET: 0x00AE8280
// FUNCTION: fn_18086
int Timestamp::IsBefore(__time32_t other) const {
return _difftime32(this->seconds, other) < 0.0;
}
// OFFSET: 0x00AE82B0
// FUNCTION: fn_18087
int Timestamp::IsBeforeNow() const {
__time32_t now;
@ -34,36 +38,43 @@ int Timestamp::IsBeforeNow() const {
return _difftime32(this->seconds, now) < 0.0;
}
// OFFSET: 0x00AE82F0
// FUNCTION: fn_18088
int Timestamp::Day() const {
return _localtime32(&this->seconds)->tm_mday;
}
// OFFSET: 0x00AE8300
// FUNCTION: fn_18089
int Timestamp::Hour() const {
return _localtime32(&this->seconds)->tm_hour;
}
// OFFSET: 0x00AE8310
// FUNCTION: fn_18090
int Timestamp::Minute() const {
return _localtime32(&this->seconds)->tm_min;
}
// OFFSET: 0x00AE8320
// FUNCTION: fn_18091
int Timestamp::Month() const {
return _localtime32(&this->seconds)->tm_mon + 1;
}
// OFFSET: 0x00AE8350
// FUNCTION: fn_18092
int Timestamp::Second() const {
return _localtime32(&this->seconds)->tm_sec;
}
// OFFSET: 0x00AE83B0
// FUNCTION: fn_18093
int Timestamp::Year() const {
return _localtime32(&this->seconds)->tm_year + 1900;
}
// OFFSET: 0x00AE83D0
// FUNCTION: fn_18094
__time32_t Timestamp::SetDate(short year, short month, short day, short hour) {
std::tm local{};

View file

@ -582,28 +582,28 @@
"Source/Utility/Async/NMessageQueue.cpp": 0,
"Source/Utility/Async/NObject.cpp": 0,
"Source/Utility/Async/NRecycleObjectPoolMgr.cpp": 0,
"Source/Utility/Base64.cpp": 0,
"Source/Utility/Text/Base64.cpp": 0,
"Source/Utility/GuidParse.cpp": 0,
"Source/Utility/LexiconBoundary.cpp": 0,
"Source/Utility/LexiconMatcher.cpp": 0,
"Source/Utility/LexiconSerializer.cpp": 0,
"Source/Utility/MD5.cpp": 0,
"Source/Utility/Lexicon/LexiconBoundary.cpp": 0,
"Source/Utility/Lexicon/LexiconMatcher.cpp": 0,
"Source/Utility/Lexicon/LexiconSerializer.cpp": 0,
"Source/Utility/Hash/MD5.cpp": 0,
"Source/Utility/Math/AffineLookAt.cpp": 0,
"Source/Utility/Math/AffineMatrix.cpp": 0,
"Source/Utility/Math/ClientAngles.cpp": 0,
"Source/Utility/Math/RayTriangle.cpp": 0,
"Source/Utility/RadialGrid.cpp": 0,
"Source/Utility/Rijndael.cpp": 0,
"Source/Utility/Math/RadialGrid.cpp": 0,
"Source/Utility/Cipher/Rijndael.cpp": 0,
"Source/Utility/Text/FormatString.cpp": 0,
"Source/Utility/Text/GroupedInteger.cpp": 0,
"Source/Utility/Text/LanguageCharset.cpp": 0,
"Source/Utility/TextEscapes.cpp": 0,
"Source/Utility/TextTokens.cpp": 0,
"Source/Utility/Text/TextEscapes.cpp": 0,
"Source/Utility/Text/TextTokens.cpp": 0,
"Source/Utility/Threading/NSyncObject.cpp": 0,
"Source/Utility/Threading/NThread.cpp": 0,
"Source/Utility/Timestamp.cpp": 0,
"Source/Utility/XorBytes.cpp": 0,
"Source/Utility/XxHash32.cpp": 0,
"Source/Utility/Cipher/XorBytes.cpp": 0,
"Source/Utility/Hash/XxHash32.cpp": 0,
"ThirdParty/jsoncpp/src/lib_json/json_reader.cpp": 8,
"ThirdParty/jsoncpp/src/lib_json/json_value.cpp": 8,
"ThirdParty/jsoncpp/src/lib_json/json_writer.cpp": 8,