aboutsummaryrefslogtreecommitdiff
path: root/CONTRIBUTING.md
diff options
context:
space:
mode:
authorEthan Morgan <ethan@gweithio.com>2026-02-14 16:44:06 +0000
committerEthan Morgan <ethan@gweithio.com>2026-02-14 16:44:06 +0000
commit54409423f767d8b1cf30cb7d0efca6b4ca138823 (patch)
treed915ac7828703ce4b963efdd9728a1777ba18c1e /CONTRIBUTING.md
move to own git serverHEADmaster
Diffstat (limited to 'CONTRIBUTING.md')
-rw-r--r--CONTRIBUTING.md621
1 files changed, 621 insertions, 0 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8ba7cf8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,621 @@
+# C++ Coding Style Guide for OpenMB
+
+This document outlines the C++ coding standards for the OpenMB project. All contributors are expected to follow these guidelines to maintain consistency and code quality.
+
+## Table of Contents
+
+- [Code Formatting](#code-formatting)
+- [Naming Conventions](#naming-conventions)
+- [Code Organization](#code-organization)
+- [Best Practices](#best-practices)
+- [Tooling](#tooling)
+
+## Code Formatting
+
+### Automated Formatting
+
+OpenMB uses **clang-format** to enforce consistent code formatting. The configuration is defined in `.clang-format` at the repository root.
+
+**Before submitting a merge request:**
+```bash
+# Format your changed files
+clang-format -i path/to/your/file.cpp
+clang-format -i path/to/your/file.hpp
+```
+
+### Key Formatting Rules
+
+#### Brace Style
+We use **Allman/BSD style** - braces on their own line for all constructs:
+
+```cpp
+// Classes
+class MyClass
+{
+public:
+ void myMethod();
+};
+
+// Functions
+void MyClass::myMethod()
+{
+ // implementation
+}
+
+// Control statements
+if (condition)
+{
+ doSomething();
+}
+else
+{
+ doSomethingElse();
+}
+
+// Namespaces
+namespace MyNamespace
+{
+ // content
+}
+```
+
+#### Indentation
+- **4 spaces** (no tabs)
+- All namespaces are indented
+- Access modifiers are outdented by 4 spaces from the class body
+
+```cpp
+namespace MBWorld
+{
+ class MyClass
+ {
+ public: // Outdented by 4 spaces
+ void publicMethod();
+
+ private:
+ int mMemberVariable;
+ };
+}
+```
+
+#### Line Length
+- Maximum **120 columns**
+- Break long lines logically, preferring to break before operators
+
+```cpp
+// Good
+bool result = someVeryLongCondition
+ && anotherCondition
+ && yetAnotherCondition;
+
+// Bad - exceeds 120 columns
+bool result = someVeryLongCondition && anotherCondition && yetAnotherCondition && evenMoreConditions;
+```
+
+#### Pointer and Reference Alignment
+- **Left-aligned** with the type
+
+```cpp
+// Good
+Ptr* ptr;
+const std::string& name;
+
+// Bad
+Ptr *ptr;
+const std::string &name;
+```
+
+#### Spacing
+- Space after control statement keywords: `if (`, `for (`, `while (`
+- No space after function names: `myFunction(args)`
+- Single space before trailing comments
+- No spaces inside parentheses, brackets, or angle brackets
+
+```cpp
+// Good
+if (condition)
+{
+ myFunction(arg1, arg2);
+ std::vector<int> numbers; // A comment
+}
+
+// Bad
+if( condition ){
+ myFunction (arg1,arg2);
+ std::vector < int > numbers;//A comment
+}
+```
+
+## Naming Conventions
+
+These conventions are enforced by **clang-tidy**.
+
+### Classes and Structs
+**PascalCase** - capitalize the first letter of each word
+
+```cpp
+class CreatureStats { };
+class NpcStats { };
+struct CellState { };
+```
+
+### Functions and Methods
+**camelCase** - lowercase first letter, capitalize subsequent words
+
+```cpp
+void processData();
+bool isValid() const;
+float getMaxSpeed(const Ptr& ptr) const;
+```
+
+### Member Variables
+Prefix with `m` followed by **PascalCase**
+
+```cpp
+class MyClass
+{
+private:
+ int mHealthPoints;
+ std::string mPlayerName;
+ bool mIsActive;
+ ESM::RefId mRaceId;
+};
+```
+
+### Local Variables and Parameters
+**camelBack** (same as functions)
+
+```cpp
+void processPlayer(const Ptr& playerPtr, bool forceUpdate)
+{
+ int currentHealth = getHealth(playerPtr);
+ std::string characterName = getName(playerPtr);
+}
+```
+
+### Namespaces
+**PascalCase**
+
+```cpp
+namespace MBWorld { }
+namespace MBMechanics { }
+namespace ESM { }
+```
+
+**Exception:** External library namespaces may use their own conventions (e.g., `osg`, `osgDB`)
+
+### Constants and Enums
+**PascalCase** for enum types, members follow context
+
+```cpp
+enum class Specialization
+{
+ Combat,
+ Magic,
+ Stealth
+};
+
+// Enum class members use PascalCase
+enum RecordFlag
+{
+ Persistent = 0x0400,
+ Deleted = 0x0020
+};
+```
+
+### Template Parameters
+**PascalCase**
+
+```cpp
+template <class T>
+class Record : public RecordBase
+{
+ T mData;
+};
+```
+
+## Code Organization
+
+### Header Files
+
+#### Include Guards
+Use traditional `#ifndef` include guards:
+
+```cpp
+#ifndef OPENMB_COMPONENTS_ESM_UTIL_H
+#define OPENMB_COMPONENTS_ESM_UTIL_H
+
+// Header content
+
+#endif
+```
+
+**Format:** `OPENMB_<PATH_TO_FILE>_H`
+- Replace directory separators with underscores
+- Use uppercase
+- Path should be relative to project root (apps/ or components/)
+
+#### Include Order
+1. Related header (for .cpp files)
+2. C system headers
+3. C++ standard library headers
+4. External library headers
+5. Project headers
+
+```cpp
+#include "myclass.hpp" // Related header first
+
+#include <cmath>
+#include <cstdint>
+
+#include <string>
+#include <vector>
+
+#include <osg/Vec3f>
+#include <MyGUI_Gui.h>
+
+#include <components/esm/records.hpp>
+#include "../mbbase/environment.hpp"
+```
+
+#### Header Structure
+```cpp
+#ifndef OPENMB_APPS_OPENMB_MBWORLD_CLASS_H
+#define OPENMB_APPS_OPENMB_MBWORLD_CLASS_H
+
+// Includes
+
+// Forward declarations
+namespace ESM
+{
+ class ESMReader;
+}
+
+namespace MBWorld
+{
+ class Ptr;
+
+ /// Brief class description
+ class MyClass
+ {
+ public:
+ MyClass();
+ ~MyClass();
+
+ /// Brief method description
+ /// \param ptr Description of parameter
+ /// \return Description of return value
+ bool myMethod(const Ptr& ptr) const;
+
+ private:
+ int mData;
+ };
+}
+
+#endif
+```
+
+### Source Files
+
+```cpp
+#include "myclass.hpp"
+
+#include <other/includes>
+
+namespace MBWorld
+{
+ MyClass::MyClass()
+ : mData(0)
+ {
+ }
+
+ bool MyClass::myMethod(const Ptr& ptr) const
+ {
+ // Implementation
+ return true;
+ }
+}
+```
+
+## Best Practices
+
+### Modern C++ (C++20)
+
+OpenMB targets **C++20**. Use modern C++ features appropriately:
+
+```cpp
+// Use auto for complex types
+auto iterator = myMap.find(key);
+
+// Use smart pointers
+std::unique_ptr<Dialog> mDialog;
+
+// Use range-based for loops
+for (const auto& item : container)
+{
+ process(item);
+}
+
+// Use nullptr instead of NULL or 0
+Ptr* ptr = nullptr;
+
+// Use override keyword
+void myMethod() override;
+
+// Use constexpr where appropriate
+constexpr int MaxValue = 100;
+```
+
+### Const Correctness
+
+Be diligent about const correctness:
+
+```cpp
+class MyClass
+{
+public:
+ // Const methods don't modify the object
+ int getValue() const { return mValue; }
+
+ // Use const references for parameters
+ void setName(const std::string& name);
+
+ // Use const pointers when appropriate
+ void process(const MBWorld::ConstPtr& ptr) const;
+
+private:
+ int mValue;
+};
+```
+
+### Virtual Functions
+
+- Always use `override` keyword for overridden virtual functions
+- Use `const` on virtual functions when they don't modify state
+- Add `= 0` for pure virtual functions
+
+```cpp
+class Base
+{
+public:
+ virtual ~Base() = default;
+ virtual void myMethod() = 0;
+};
+
+class Derived : public Base
+{
+public:
+ void myMethod() override; // Use override, not virtual
+};
+```
+
+### Exception Handling
+
+Use exceptions for error conditions:
+
+```cpp
+void MyClass::someMethod()
+{
+ if (!isValid())
+ {
+ throw std::runtime_error("Invalid state");
+ }
+}
+```
+
+### Comments and Documentation
+
+Use Doxygen-style comments:
+
+```cpp
+/// Brief description of the class
+class MyClass
+{
+public:
+ /// Brief description of the method
+ /// \param input Description of parameter
+ /// \return Description of return value
+ int processData(int input);
+
+ int mPublicMember; ///< Brief description after member
+};
+
+// Regular comments for implementation details
+// This algorithm uses a binary search because...
+```
+
+### Memory Management
+
+- Prefer stack allocation over heap when possible
+- Use smart pointers (`std::unique_ptr`, `std::shared_ptr`) instead of raw `new`/`delete`
+- Follow RAII principles
+
+```cpp
+// Good - automatic cleanup
+{
+ std::unique_ptr<Dialog> dialog = std::make_unique<Dialog>();
+ dialog->show();
+} // Automatically deleted
+
+// Bad - manual memory management
+Dialog* dialog = new Dialog();
+dialog->show();
+delete dialog; // Easy to forget or miss in error paths
+```
+
+### Error Handling in Base Classes
+
+Use exceptions to indicate unsupported operations:
+
+```cpp
+class Base
+{
+public:
+ virtual ContainerStore& getContainerStore(const Ptr& ptr) const
+ {
+ throw std::runtime_error("class does not have a container store");
+ }
+};
+```
+
+### Type Aliases
+
+Use clear type aliases for complex types:
+
+```cpp
+using ExtraList = std::vector<ExtraPtr>;
+using OwnerMap = std::map<Owner, int>;
+```
+
+## Tooling
+
+### clang-tidy
+
+OpenMB uses **clang-tidy** for static analysis. The configuration is in `.clang-tidy`.
+
+```bash
+# Run clang-tidy on your files
+clang-tidy path/to/your/file.cpp -- -I/path/to/includes
+```
+
+**Key checks enabled:**
+- `portability-*` - Cross-platform compatibility
+- `clang-analyzer-*` - Static analysis
+- `modernize-avoid-bind` - Modern C++ practices
+- `readability-identifier-naming` - Naming conventions
+
+### Running Checks Locally
+
+```bash
+# Format code
+clang-format -i apps/openmb/myfile.cpp
+
+# Check formatting without modifying
+clang-format --dry-run --Werror apps/openmb/myfile.cpp
+
+# Run clang-tidy
+clang-tidy apps/openmb/myfile.cpp
+```
+
+## Common Pitfalls
+
+### Don't Mix Concerns
+- One class = one responsibility
+- One commit = one logical change
+- Don't combine formatting changes with functional changes
+
+### Avoid Unnecessary Changes
+- Don't reformat code you didn't modify
+- Don't change whitespace in unrelated files
+- Focus changes on what's necessary for your feature/fix
+
+### Platform Compatibility
+- OpenMB runs on Windows, Linux, and macOS
+- Avoid platform-specific code unless absolutely necessary
+- Use CMake for build configuration
+- Test on multiple platforms if possible
+
+## Examples
+
+### Good Class Example
+
+```cpp
+#ifndef OPENMB_APPS_OPENMB_MBWORLD_MYCLASS_H
+#define OPENMB_APPS_OPENMB_MBWORLD_MYCLASS_H
+
+#include <string>
+#include <vector>
+
+#include <components/esm/refid.hpp>
+
+namespace MBWorld
+{
+ class Ptr;
+
+ /// Manages player inventory and equipment
+ class InventoryManager
+ {
+ public:
+ InventoryManager();
+ ~InventoryManager() = default;
+
+ /// Add an item to the inventory
+ /// \param itemId The ID of the item to add
+ /// \param count Number of items to add
+ /// \return True if successful
+ bool addItem(const ESM::RefId& itemId, int count);
+
+ /// Check if an item is in inventory
+ /// \param itemId The ID to check
+ /// \return True if item exists in inventory
+ bool hasItem(const ESM::RefId& itemId) const;
+
+ /// Get the total weight of all items
+ float getTotalWeight() const;
+
+ private:
+ std::vector<ESM::RefId> mItems;
+ float mCurrentWeight;
+ int mMaxCapacity;
+ };
+}
+
+#endif
+```
+
+### Good Implementation Example
+
+```cpp
+#include "inventorymanager.hpp"
+
+#include <algorithm>
+
+#include "../mbbase/environment.hpp"
+#include "../mbworld/esmstore.hpp"
+
+namespace MBWorld
+{
+ InventoryManager::InventoryManager()
+ : mCurrentWeight(0.0f)
+ , mMaxCapacity(100)
+ {
+ }
+
+ bool InventoryManager::addItem(const ESM::RefId& itemId, int count)
+ {
+ if (count <= 0)
+ {
+ return false;
+ }
+
+ const MBWorld::ESMStore& store = *MBBase::Environment::get().getESMStore();
+
+ // Add item logic here
+ mItems.push_back(itemId);
+
+ return true;
+ }
+
+ bool InventoryManager::hasItem(const ESM::RefId& itemId) const
+ {
+ return std::find(mItems.begin(), mItems.end(), itemId) != mItems.end();
+ }
+
+ float InventoryManager::getTotalWeight() const
+ {
+ return mCurrentWeight;
+ }
+}
+```
+
+## Additional Resources
+
+- [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)
+- [Clang Format Documentation](https://clang.llvm.org/docs/ClangFormat.html)
+- [Clang Tidy Documentation](https://clang.llvm.org/extra/clang-tidy/)
+
+## Questions?
+
+If you're unsure about any aspect of the coding style, look at existing code in the codebase for examples.
+
+Remember: Consistency is more important than personal preference. When in doubt, follow the existing patterns in the codebase.