Skip to main content

nwn-message

Message definitions and websocket client for the Neverwinter Nights networking protocol.

This library has the full message index from the game binary, and can encode and decode messages in a simplified wire format as implemented by NWNX_WSNetLayer.

It also ships a fully functional async websocket client that can connect to a server running the plugin, log in as a player, and send/receive messages as structured Python objects.

This message library can only connect to servers that run the NWNX_WSNetLayer plugin. The decision not to expose the current UDP-based transport was made to reduce the likelyhood of abuse for existing servers. Thus, any server that wishes to allow custom clients is required to run the NWNX plugin.

How to use this repository

This project serves two distinct purposes, and how you consume it depends on which one you need:

  • As a Python library: install from PyPI with pip install nwn-message or uv add nwn-message. You get the full message definitions, encoding/decoding layer, and async websocket client. This is the right choice for Python bots, custom clients, and server-side tooling.

  • As a codegen schema: the same message definitions can generate bindings for other languages (Godot, TypeScript). Because codegen requires the full source tree and the running codegen script, it is excluded from the PyPI package. Clone the repository from GitHub and see "Usage in other languages" below. This may change in the future.

Requirements

  • Python 3.14+
  • NWN:EE 37.17

Version compatibility

This package only speaks with 8193-37.17; which is the latest official stable version of NWN:EE as of this writing. Earlier (or later) versions are not supported.

The library has some base scaffolding for supporting past or future versions; however the divergences are not implemented to reduce the testing surface.

Message definitions

The source of truth for this library is a registry of Python dataclasses in src/nwn_message/messages/, indexed by the NWN protocol's (major, minor, direction) tuple. Each dataclass uses annotated type hints to describe its wire format: field types, sizes, conditional guards, tagged unions, and size prefixes are all expressed declaratively through Python's typing.Annotated and custom metadata types.

Most messages are fully declarative: their on-wire layout can be determined entirely from their type annotations. A handful of messages with highly irregular or context-dependent formats define custom read/write methods instead. These are the exception, not the rule.

Because the message definitions are plain Python dataclasses, they serve as both the runtime encoding/decoding layer and the schema for code generation. Any tool that wants to speak the WSNetLayer protocol can use these same types as its source of truth.

Client Usage

The supplied client library is fully async and meant to be wired up using the popular blinker library. It will emit signals for each message type received, and you can register handlers for those signals to process messages as they arrive. You can also register for sub-messages (such as specific game object updates); complex messages are decomposed inside the library for this purpose.

The example client at examples/client.py walks through the full connect-flow. It is meant to be copied out into your own parent project and changed there.

This library uses the standard logging framework to emit debug informations. Use the python builtin logging getters to mute the subsystems you don't care about.

Usage in other languages

Codegen to other languages is preliminary. Targets currently include Godot and TypeScript. The generator is deliberately not exposed through the package or public API until such time that it is stable and well-tested.

To invoke the codegen, clone the repository (codegen is currently excluded from the PyPI package) and run uv run run_codegen.py --help. Please note that the codegen command may be quite destructive to your checkout/generated files.

Not all messages are fully declarative (some are bespoke Python read/write). Codegen writes stubs for this into custom/. Implementing these is left as an exercise to the reader and only has to be done once, unless the message format changes.

Each codegen target also includes some glue code you need to import into your project; basically containing the wire reader/writer and helpers.

Stability

The message definitions and wire format are, while complete, not yet API-stable. All messages should be (!) implemented, but some types are stubs (e.g. a int might be a stand-in for a missing enum type, or some nested classes are needlessly complex). These will be filled in or amended as we go.

Changes to the message spec will necessitate changes to any client code that uses this library. If you do build on this library, you will need to watch for updates to message definitions.

The wire format (WSNetLayer) might also see changes but is at least major-versioned.

Contributing

There is no formal contribution process yet. All contributions will require to be licenced under the GPLv3. If in doubt, just open a discussion/issue.

License

This project is licensed under the GPLv3.

The spirit of this license choice is: if you build on this work, share it back. The NWN ecosystem thrives on open tools, not closed ones.

Whether you're building a custom client, a bot, or a whole new server, we hope you'll open-source your work too. And even if you can't open everything, come tell us what you're building anyway. We'd love to hear about it.

Get in touch

Metadata

Release files for nwn-message 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nwn-message 0.1.1
File Size Uploaded
nwn_message-0.1.1.tar.gz 161.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nwn-message 0.1.1
File Interpreter ABI Platform
nwn_message-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 283.5 kB

Release files / nwn_message-0.1.1.tar.gz

Download URL nwn_message-0.1.1.tar.gz
Size 161.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d8b9b361907bf277a96a10916825eebb12775a921776eb0b2fcec8739ba4e879
BLAKE2b-256 checksum
How to use checksums
cd180861f7e55c25ad3cd93c83b6fc38ef4884db3bbc798cbccafb2e6925e465
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / nwn_message-0.1.1-py3-none-any.whl

Download URL nwn_message-0.1.1-py3-none-any.whl
Size 121.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c0c975cbaa861c3ed8afff3b6a89e35648fde893fd1b794556e608d39b3cda45
BLAKE2b-256 checksum
How to use checksums
ba4598bc6524e25412b0a0452f0d6a9db2d7b996d57877d84ace0c5f2b4c8f9b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page