A core C library for writing applications related to Endless Online (migrated from GitHub)
Find a file
Richard Leek ab3a735eca
All checks were successful
Build Library / build (Release, clang, clang, clang++, ubuntu-24.04, Linux.Clang.x64, false) (push) Successful in 1m16s
Build Library / build (Release, gcc, gcc, g++, ubuntu-24.04, Linux.x64, true) (push) Successful in 1m1s
ci: restore ctest + lua-test steps
2026-10-30 18:32:07 +00:00
.forgejo/workflows ci: restore ctest + lua-test steps 2026-10-30 18:32:07 +00:00
.github Version bump 2026-07-16 14:13:25 -04:00
.vscode Fix cmake install 2026-03-12 18:32:43 -04:00
cmake initial commit 2026-03-10 18:44:40 -04:00
demos/win32 Add win32 demo 2026-03-13 21:40:50 -04:00
docs Version bump 2026-07-16 14:13:25 -04:00
eo-captured-packets@6770e79dfa update packet captures 2026-03-16 09:53:15 -04:00
eo-protocol@6959edeb15 initial commit 2026-03-10 18:44:40 -04:00
include Fix pedantic errors 2026-07-16 13:11:47 -04:00
lua Use C11 for the lua bindings 2026-07-16 13:05:20 -04:00
scripts Version bump 2026-03-13 14:27:29 -04:00
src Fix pedantic errors 2026-07-16 13:11:47 -04:00
tests Fix pedantic errors 2026-07-16 13:11:47 -04:00
tools Rename set_chunked_reading_mode to activate_chunked_reading_mode 2026-07-16 12:43:37 -04:00
wasm Version bump 2026-07-16 14:13:25 -04:00
.gitignore Fix lua stuff and improve docs 2026-03-12 21:47:20 -04:00
.gitmodules Add captured packets 2026-03-11 07:34:50 -04:00
CMakeLists.txt Version bump 2026-07-16 14:13:25 -04:00
Doxyfile Version bump 2026-07-16 14:13:25 -04:00
LICENSE.txt Update license 2026-03-10 21:12:58 -04:00
README.md Update docs 2026-07-16 14:01:51 -04:00
vcpkg-configuration.json Use cache and add vcpkg.json 2026-03-10 23:08:37 -04:00
vcpkg.json Version bump 2026-07-16 14:13:25 -04:00

EOLib

Build Status Docs License

A core C library for writing applications related to Endless Online

Features

Read and write the following EO data structures:

  • Client packets
  • Server packets
  • Endless Map Files (EMF)
  • Endless Item Files (EIF)
  • Endless NPC Files (ENF)
  • Endless Spell Files (ESF)
  • Endless Class Files (ECF)
  • Endless Server Files (Inns, Drops, Shops, etc.)

Utilities:

  • Data reader
  • Data writer
  • Number encoding
  • String encoding
  • Data encryption
  • Packet sequencer

Written in strict C89/C90 (-std=c90 -pedantic-errors on GCC/Clang) for maximum compiler and platform compatibility, including older toolchains like MSVC 2005/2008.

Installation

Download the release archive for your platform from the releases page. Packages are named eolib-{version}-{platform}.zip and include both the C library and the Lua bindings.

Option 1 — Use directly from the extracted directory (no install needed):

list(APPEND CMAKE_PREFIX_PATH "/path/to/eolib-{version}-{platform}")
find_package(eolib REQUIRED)
target_link_libraries(myapp PRIVATE eolib::eolib)

Option 2 — Copy files to a system prefix manually:

# Linux / macOS — copy into /usr/local (or any prefix you prefer)
cp -r eolib-{version}-{platform}/include/* /usr/local/include/
cp -r eolib-{version}-{platform}/lib/*     /usr/local/lib/
cp -r eolib-{version}-{platform}/share/*   /usr/local/share/

Then find_package(eolib REQUIRED) will find it automatically.

See the Getting Started guide for manual (non-CMake) linking instructions.

Building from source

eolib-c has two editions, controlled by the EOLIB_BUILD_PROTOCOL CMake option:

  • Full (EOLIB_BUILD_PROTOCOL=ON, the default) — everything below, including the generated EO packet/struct protocol layer.
  • Lite (EOLIB_BUILD_PROTOCOL=OFF) — just the core EoWriter/EoReader, encryption, sequencer, and RNG utilities. No code generation, no libxml2/json-c dependency, no eo-protocol submodule needed — just a C89/C90 compiler and CMake.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DEOLIB_BUILD_PROTOCOL=OFF
cmake --build build

Requirements

  • CMake 3.16+
  • A C89/C90-capable compiler
  • libxml2 (full edition only)
  • json-c (full edition only)

Install dependencies

Skip this section entirely for a lite (EOLIB_BUILD_PROTOCOL=OFF) build.

macOS (Homebrew):

brew install libxml2 json-c

Ubuntu/Debian:

sudo apt-get install -y libxml2-dev libjson-c-dev

Windows (MSVC): libxml2 and json-c are handled automatically via the bundled vcpkg configuration.

Windows (MinGW / MSYS2):

pacman -S --needed mingw-w64-x86_64-libxml2 mingw-w64-x86_64-json-c

Build

git clone --recurse-submodules https://github.com/sorokya/eolib-c.git
cd eolib-c

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build

Run tests

ctest --test-dir build

Install

cmake --install build

WebAssembly (WASM)

A WASM build exists solely to power the interactive demo. It is not intended for use in real projects.

If you need eolib in a JavaScript/TypeScript project, use eolib-ts instead — it is a proper TypeScript implementation of the same protocol.

Lua bindings

Native Lua 5.1+/LuaJIT bindings are available. See lua/README.md for full setup and API reference.

Download eolib-{version}-{platform}.zip from the releases page — the main archive includes both the C library and the Lua bindings.

Drop-in: Extract the archive into your project directory. require("eolib") will just work.

Building from source

Requires Lua development headers in addition to the dependencies above:

  • macOS: brew install lua
  • Ubuntu/Debian: sudo apt-get install -y liblua5.4-dev lua5.4
  • MinGW/MSYS2: pacman -S mingw-w64-x86_64-lua
cmake -S . -B build -DEOLIB_BUILD_LUA_BINDINGS=ON
cmake --build build --target lua_eolib

This produces build/lua/eolib.so (or .dll on Windows).

Run Lua tests

cmake --build build --target lua-test

Protocol Types

All generated structs and packets implement the EoSerialize interface (packets also implement EoPacket). Use the TypeName_init() function to create a zero-initialized instance with its vtable set, then use the eo_* dispatch functions to serialize, deserialize, query the size, or free heap memory:

#include "eolib/protocol.h"

// Initialize
LoginRequestClientPacket pkt = LoginRequestClientPacket_init();
pkt.username = "player";
pkt.password = "secret";

// Serialize
size_t needed = eo_get_size((const EoSerialize *)&pkt);
EoWriter writer = eo_writer_init_with_capacity(needed);
eo_serialize((const EoSerialize *)&pkt, &writer);
// writer.data now holds the bytes, writer.length is the byte count

// Free heap fields (e.g. strings, arrays) when done
eo_free((EoSerialize *)&pkt);
eo_writer_free(&writer);

// Deserialize
uint8_t *bytes = ...;
size_t len = ...;
EoReader reader = eo_reader_init(bytes, len);
LoginRequestClientPacket pkt2 = LoginRequestClientPacket_init();
eo_deserialize((EoSerialize *)&pkt2, &reader);
printf("username: %s\n", pkt2.username);
eo_free((EoSerialize *)&pkt2);

Packets additionally expose their family/action IDs:

uint8_t family = eo_packet_get_family((const EoPacket *)&pkt);
uint8_t action = eo_packet_get_action((const EoPacket *)&pkt);

See the full documentation for the complete API reference, memory safety guide, and worked examples.

All fallible functions return an EoResult value. A return value of EO_SUCCESS (0) means the operation completed without error. Any other value indicates a failure and describes what went wrong.

Code Value Meaning
EO_SUCCESS 0 Operation completed successfully.
EO_NULL_PTR 1 A required pointer argument was NULL (e.g. writer, reader, sequencer, or output buffer).
EO_OVERFLOW 2 An internal size calculation would overflow — growing the writer buffer would exceed SIZE_MAX.
EO_ALLOC_FAILED 3 malloc or realloc returned NULL; the system could not satisfy the allocation.
EO_NUMBER_TOO_LARGE 4 A value passed to an EO encode function exceeds the maximum encodable integer (EO_INT_MAX).
EO_BUFFER_UNDERRUN 5 The reader does not have enough bytes remaining to satisfy the requested read.
EO_CHUNKED_MODE_DISABLED 6 eo_reader_next_chunk was called but chunked reading mode is not enabled on the reader.
EO_INVALID_SEQUENCE_RANGE 7 The derived seq1 bounds produce an empty range; the start value is outside the representable sequence space.
EO_SEQUENCE_OUT_OF_RANGE 8 A derived sequence byte value falls outside [0, EO_CHAR_MAX - 1] and cannot be encoded.
EO_INVALID_DATA 9 Deserialization failed because a sentinel value, file magic string, or required constant field did not match the expected value.
EO_STR_OUT_OF_RANGE 10 A string operation would exceed the allowed length, such as adding a fixed-length string that is too long.
EO_STR_TOO_SHORT 11 A fixed-length string is shorter than expected and padding was not enabled.

Example

EoWriter writer = eo_writer_init_with_capacity(16);
EoResult result = eo_writer_add_int(&writer, 12345);
if (result != EO_SUCCESS) {
    fprintf(stderr, "write failed: %d\n", result);
}
free(writer.data);

License

This project is licensed under the MIT License. See the LICENSE file for details.