Skip to content

Latest commit

 

History

History
179 lines (142 loc) · 9.82 KB

File metadata and controls

179 lines (142 loc) · 9.82 KB

Neolith Developer Reference

Coding Style

Indention

There was no consistent indention style in the original code base of LPMud and MudOS. You may find different part of code using different style of indention.

Neolith uses a relaxed version of GNU style indention, with some modifications to prevent extra line-of-code:

  • Indention with space only. No tabs.
  • Function definitions open curly brace at the same line of function name.
    This is from K&R style, but it allows finding function implementations much easier with grep or text editor's search tools.
  • Function return type and function name at the same line.
    For the same reason as above.

Balance between line-of-code and readability

Modern text editors are flexible at automatically wrapping text lines. It is not necessary for programmers to wrap code lines just to make it look pretty with the assumption on width of display.

You can still do line wrapping, but only for readability reason. And it is ok to not doing line wrapping at all.

Use the command to have an estimation on line-of-code:

git ls-files | egrep -v '^(docs|examples)' | xargs wc -l

Function and variable naming

  • C functions and variables are in all lower case (aka. snake case).

  • Avoid abbreviations and always choose an unique name for any global symbol name.

  • C++ code uses CamelCase for classes and methods.
    For unit-testing code, underscore is forbidden by Googletest.

Code Modularity

The original LPMud code base uses a lot of global variables in C code, making it difficult to refactor or extend the driver code. Neolith tried to enhance code modularity by removing unnecessary global variables or make them static whenever possible.

Some MudOS-forked projects such as FluffOS has managed to build the driver's C code with C++ compiler. However, the problem of lacking modularity still exists.

In Neolith, we take another bottom-up approach:

  • Start with improving C code modularity by separating the driver code into smaller static libraries.
    • Clarify dependencies of each static libraries.
    • Re-organize C code to create small modules with clear boundaries and exposes just-enough interfaces.
  • Fortify the architecture of driver by cascading init_*()/deinit_*() sequence.
    • Introduce of mud_state() to indicate availability of essential modules.
    • Add tear down code for essential modules and verify graceful tear down with trace logs.
  • Add C++ unit-testing code using Googletest framework.
    • Test modularity by creating "stem" (minimal runtime setup for testee) as test fixtures.
    • Refactor rarely used code, merge or remove redundant code to minimize module interfaces.
    • Add documentations for essential functions.

Eventually, as the name "Neolith" implies, we shall migrate LPMud Driver to modern C++ constructs and take advantage of new language features and more advanced compilers. (Not simply compile C code with C++ compiler)

Documentations

Neolith's documentations are written in Markdown format (*.md) for easier reading on github. If you use Windows + WSL as your development environment, the Visual Studio Code is a great editor to view these documentations. If you use something else, you may also read these markdown documents with the mdless tool in shell.

Note that Neolith documentation may use some Github Flavored Markdown syntax that may not display correctly in other viewers.

For mudlib-path security and resolution behavior, see:

Inline Function Documentations

Neolith prefers adding doxygen-style inline function documentations within the source code. It enables modern code editors like Visual Studio Code to show brief function descriptions when moving your mouse cursor over the function name.

Below is an example of inline function documentation:

/**
 * @brief Sum two integers.
 * @param a first number.
 * @param b second number.
 * @returns Returns sum of a and b.
 */
int sum (int a, int b) {
    return a + b;
}

Debug Logs

The log messages generated by the LPMud Driver goes to the file as specified by DebugLogFile in the configuration file. Typically you'll also want to enable the LogWithDate setting to automatically prefix each log message with an ISO-8601 format timestamp.

Debug Level

Neolith has added a command line argument '--debug' or '-d' to control the debug level. The default debug level is zero, and you can specify an integer equal or greater to zero for debug level to enable more detailed debug messages:

$ neolith -f neolith.conf -d 1

Debug Log Types

Neolith generates these types of debug log:

Type Description Affected by Debug Level
FATAL These are fatal errors that the LPMud Driver will begin shutdown immediately. No
ERROR An error occurs in the LPMud Driver. Evaluation of LPC code is interrupted and error_hander() is called in the master object. Yes
WARN An warning message that worth a look, but the LPMud Driver is able to tolerate or fall back to some reasonable behavior. Yes
INFO An informative message. This is similar to trace messages, but enabled by default. Yes
TRACE A trace message that is enabled through --trace. No, see tracing

Please note that Debug Log Type does not imply any default Debug Log Level. For example, when you specify debug level 1, an ERROR message of debug level 3 is not enabled while a WARN message of debug level 1 is enabled.

The DEBUG_CHECK* macros from MudOS are treated as ERROR type message at debug level 1.

Neolith Debug Log Format

In terms of troubleshooting, a structured log format brings many advantages to the administrator. Human-readbility is equally important for a LPMud's wizards, especially when the wizard has no access to the shell on the MUD server.

Neolith's log format is designed to balance both requirements while keeping the size of debug log as small as possible. The Neolith Debug Log Format (NDLF) is described as below:

  1. The debug log file is a stream of log messages separated by newline ('\n') character.
  2. If a log message starts with a hash sign ('#') or tab ('\t') character, the line is only for human read. Log processing tool may skip these lines safely.
  3. Otherwise, the log message can be parsed into multiple columns separated by tab character like below:
[timestamp \t] [log-meta \t] message-text \n

Timestamp

If LogWithDate is enabled in the configuration file, the LPMud Driver automatically preix each log message with a timestamp in ISO-8601 format that contains:

YYYY-MM-DD hh:mm:ss

Log-meta

The log-meta part is a JSON string that contains program-readable information to assist Log Processing tools. Neolith provides the following meta data in JSON:

Log-meta Description
A JSON array of 4 elements. An error or trace messages, and the elements are type, source-file, line, function.
A JSON object An informative log message. The contents of JSON object may have its own signature property for Log Processing tool to identify.

Mudlib Compatibility

As the log-meta can be easily identified by starting with '[' or '{' character, a mudlibe using Neolith can continue to write its own log format while keeping the compatibility with NDLF. A Log Processing tool can locate the log-meta generated by the LPMud Driver while skipping other log messages it can not recognize. We encourage mudlib designers to produce NDLF-compatible log messages for the advantages of structured log format.

Example below is a Neolith debug log file with ES2 mudlib (mixing NDLF messages and non-NDLF message produced by mudlib):

2022-10-05 13:10:54     {}      ===== neolith version 0.1.3 starting up =====
2022-10-05 13:10:54     {}      using locale "C.UTF-8"
2022-10-05 13:10:54     {}      using MudLibDir "/home/taedlar/github/es2_mudlib/mudlib"
2022-10-05 13:10:54     {}      ----- loading simul efuns -----
2022-10-05 13:10:54     simul_efun loaded successfully.
2022-10-05 13:10:54     {}      ----- loading master -----
2022-10-05 13:10:54     master object is created successfully.
2022-10-05 13:10:54     {}      ----- epilogue -----
2022-10-05 13:10:54     preloading /adm/daemons/securityd
2022-10-05 13:10:54     preloading /adm/daemons/virtuald
2022-10-05 13:10:54     preloading /adm/daemons/logind
2022-10-05 13:10:54     preloading /adm/daemons/cmd_d
2022-10-05 13:10:54     preloading /adm/daemons/chinesed
2022-10-05 13:10:54     dictionary restored 238 words
2022-10-05 13:10:54     preloading /adm/daemons/emoted
2022-10-05 13:10:54     preloading /adm/daemons/aliasd
2022-10-05 13:10:54     preloading /adm/daemons/fingerd
2022-10-05 13:10:54     preloading /adm/daemons/channeld
2022-10-05 13:10:54     preloading /adm/daemons/natured
2022-10-05 13:10:54     preloading /adm/daemons/enterd
2022-10-05 13:10:54     {}      ----- entering MUD -----
2022-10-05 13:10:57     new connection from ip address "127.0.0.1"
2022-10-05 13:11:03     ["ERROR","interpret.c",3639,"eval_instruction"] Bad stack after evaluation. Instruction 93
2022-10-05 13:11:03     ["ERROR","interpret.c",3639,"eval_instruction"] Bad stack after evaluation. Instruction 93
2022-10-05 13:11:03     ["ERROR","interpret.c",3639,"eval_instruction"] Bad stack after evaluation. Instruction 93
2022-10-05 13:11:03     ["ERROR","interpret.c",3639,"eval_instruction"] Bad stack after evaluation. Instruction 93