aboutsummaryrefslogtreecommitdiff
path: root/.github/copilot-instructions.md
diff options
context:
space:
mode:
Diffstat (limited to '.github/copilot-instructions.md')
-rw-r--r--.github/copilot-instructions.md736
1 files changed, 736 insertions, 0 deletions
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..2249ade
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,736 @@
+# GitHub Copilot Instructions for OpenMB
+
+This document provides context and instructions for GitHub Copilot and other AI coding assistants when working on the OpenMB project.
+
+## Project Overview
+
+OpenMB is a C++20 game engine project that follows strict coding standards and conventions. When generating code or suggestions, always adhere to the guidelines outlined in this document.
+
+## Core Principles
+
+1. **Consistency over personal preference** - Follow existing patterns in the codebase
+2. **Modern C++20** - Use modern C++ features appropriately
+3. **Cross-platform compatibility** - Code must work on Windows, Linux, and macOS
+4. **Clear documentation** - All public APIs should have Doxygen comments
+5. **Memory safety** - Prefer RAII and smart pointers over manual memory management
+
+## Code Style Requirements
+
+### Formatting
+
+**CRITICAL: All code must follow these formatting rules:**
+
+```cpp
+// Braces - ALWAYS on their own line (Allman/BSD style)
+void myFunction()
+{
+ if (condition)
+ {
+ doSomething();
+ }
+ else
+ {
+ doSomethingElse();
+ }
+}
+
+// NOT this:
+void myFunction() {
+ if (condition) {
+ doSomething();
+ } else {
+ doSomethingElse();
+ }
+}
+```
+
+- **Indentation**: 4 spaces (NEVER tabs)
+- **Line length**: Maximum 120 columns
+- **Pointer alignment**: Left-aligned with type (`Ptr* ptr`, not `Ptr *ptr`)
+- **Spacing**: Space after control keywords (`if (`, `for (`, `while (`), no space after function names
+
+### Naming Conventions
+
+**CRITICAL: Follow these naming rules exactly:**
+
+```cpp
+// Classes and Structs - PascalCase
+class PlayerManager { };
+struct GameState { };
+
+// Functions and Methods - camelCase
+void processInput();
+bool isGameRunning() const;
+
+// Member Variables - 'm' prefix + PascalCase
+class MyClass
+{
+private:
+ int mHealthPoints;
+ std::string mPlayerName;
+ bool mIsActive;
+};
+
+// Local Variables and Parameters - camelBack
+void updatePlayer(const Ptr& playerPtr, int deltaTime)
+{
+ int currentHealth = getHealth(playerPtr);
+ float movementSpeed = calculateSpeed();
+}
+
+// Namespaces - PascalCase with MB prefix for project namespaces
+namespace MBWorld { }
+namespace MBMechanics { }
+namespace MBBase { }
+
+// Constants and Enums - PascalCase
+enum class GameState
+{
+ Loading,
+ Running,
+ Paused
+};
+
+constexpr int MaxPlayers = 64;
+```
+
+### Include Guards
+
+**ALWAYS use this format for include guards:**
+
+```cpp
+#ifndef OPENMB_<PATH_TO_FILE>_H
+#define OPENMB_<PATH_TO_FILE>_H
+
+// Header content
+
+#endif
+```
+
+Example: For file `apps/openmb/mbworld/player.hpp`
+```cpp
+#ifndef OPENMB_APPS_OPENMB_MBWORLD_PLAYER_H
+#define OPENMB_APPS_OPENMB_MBWORLD_PLAYER_H
+```
+
+### Include Order
+
+**ALWAYS organize includes in this order:**
+
+```cpp
+#include "relatedheader.hpp" // Related header first (for .cpp files)
+
+#include <cstdint> // C system headers
+#include <cmath>
+
+#include <string> // C++ standard library
+#include <vector>
+#include <memory>
+
+#include <osg/Vec3f> // External libraries
+#include <MyGUI_Widget.h>
+
+#include <components/esm/refid.hpp> // Project headers
+#include "../mbbase/environment.hpp"
+```
+
+### Namespace Structure
+
+```cpp
+namespace MBWorld
+{
+ // All namespace content indented
+ class MyClass
+ {
+ public: // Access modifiers outdented by 4 spaces
+ MyClass();
+
+ private:
+ int mData;
+ };
+
+ void freeFunction();
+}
+```
+
+## Code Generation Guidelines
+
+### When Creating New Classes
+
+**ALWAYS generate headers like this:**
+
+```cpp
+#ifndef OPENMB_APPS_OPENMB_MBWORLD_MYCLASS_H
+#define OPENMB_APPS_OPENMB_MBWORLD_MYCLASS_H
+
+#include <string>
+#include <vector>
+
+namespace MBWorld
+{
+ /// Brief description of what this class does
+ class MyClass
+ {
+ public:
+ MyClass();
+ ~MyClass() = default;
+
+ /// Brief description of method
+ /// \param input Description of parameter
+ /// \return Description of return value
+ bool processData(int input);
+
+ /// Get the current value
+ int getValue() const;
+
+ private:
+ int mValue;
+ std::string mName;
+ std::vector<int> mData;
+ };
+}
+
+#endif
+```
+
+**And implementations like this:**
+
+```cpp
+#include "myclass.hpp"
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace MBWorld
+{
+ MyClass::MyClass()
+ : mValue(0)
+ , mName()
+ , mData()
+ {
+ }
+
+ bool MyClass::processData(int input)
+ {
+ if (input < 0)
+ {
+ throw std::runtime_error("Invalid input");
+ }
+
+ mValue = input;
+ return true;
+ }
+
+ int MyClass::getValue() const
+ {
+ return mValue;
+ }
+}
+```
+
+### Modern C++ Patterns to Use
+
+```cpp
+// Smart pointers instead of raw pointers
+std::unique_ptr<Dialog> mDialog;
+std::shared_ptr<Resource> mResource;
+
+// Range-based for loops
+for (const auto& item : container)
+{
+ process(item);
+}
+
+// Auto for complex types
+auto iterator = myMap.find(key);
+auto result = complexFunction();
+
+// nullptr instead of NULL
+Ptr* ptr = nullptr;
+
+// override keyword for virtual functions
+void myMethod() override;
+
+// constexpr for compile-time constants
+constexpr int BufferSize = 1024;
+
+// Const correctness
+void processData(const std::string& input) const;
+
+// Structured bindings (C++17)
+for (const auto& [key, value] : myMap)
+{
+ // ...
+}
+```
+
+### Patterns to AVOID
+
+```cpp
+// DON'T use manual memory management
+MyClass* obj = new MyClass(); // BAD
+delete obj; // BAD
+
+// DO use smart pointers or stack allocation
+auto obj = std::make_unique<MyClass>(); // GOOD
+MyClass obj; // GOOD (when appropriate)
+
+// DON'T omit braces for single-line blocks
+if (condition)
+ doSomething(); // BAD
+
+// DO always use braces
+if (condition)
+{
+ doSomething(); // GOOD
+}
+
+// DON'T use raw pointers for ownership
+void takeOwnership(MyClass* ptr); // BAD
+
+// DO use smart pointers
+void takeOwnership(std::unique_ptr<MyClass> ptr); // GOOD
+
+// DON'T ignore const correctness
+void getData(Ptr& ptr); // BAD if not modifying
+
+// DO use const when appropriate
+void getData(const Ptr& ptr) const; // GOOD
+```
+
+### Virtual Functions and Inheritance
+
+```cpp
+class Base
+{
+public:
+ virtual ~Base() = default;
+
+ /// Pure virtual function
+ virtual void mustImplement() = 0;
+
+ /// Virtual function with default implementation
+ virtual void canOverride();
+};
+
+class Derived : public Base
+{
+public:
+ // Always use override keyword
+ void mustImplement() override;
+ void canOverride() override;
+
+ // Use final to prevent further overriding
+ void finalMethod() final;
+};
+```
+
+### Exception Handling
+
+```cpp
+// Throw exceptions for error conditions
+void MyClass::validate()
+{
+ if (!isValid())
+ {
+ throw std::runtime_error("Invalid state detected");
+ }
+
+ if (mData.empty())
+ {
+ throw std::logic_error("Data cannot be empty");
+ }
+}
+
+// Use specific exception types
+void processFile(const std::string& filename)
+{
+ if (!fileExists(filename))
+ {
+ throw std::invalid_argument("File does not exist: " + filename);
+ }
+}
+```
+
+### Documentation Comments
+
+**ALWAYS add Doxygen comments for:**
+- All public classes
+- All public methods
+- All public member variables
+- Complex private methods
+
+```cpp
+/// Manages the game's resource loading and caching
+///
+/// This class handles asynchronous loading of game resources
+/// and maintains a cache to avoid redundant disk access.
+class ResourceManager
+{
+public:
+ /// Load a resource by its identifier
+ ///
+ /// \param resourceId The unique identifier of the resource
+ /// \param async If true, load asynchronously
+ /// \return Pointer to the loaded resource, or nullptr if failed
+ /// \throws std::runtime_error if resource format is invalid
+ Resource* loadResource(const ESM::RefId& resourceId, bool async = false);
+
+ int mCacheSize; ///< Maximum number of cached resources
+};
+```
+
+## Common OpenMB Patterns
+
+### Using Project Types
+
+```cpp
+// ESM::RefId for game object identifiers
+ESM::RefId mItemId;
+ESM::RefId mSpellId;
+
+// Ptr and ConstPtr for game object references
+void processObject(const MBWorld::ConstPtr& ptr);
+void modifyObject(MBWorld::Ptr& ptr);
+
+// Common project classes
+MBWorld::CellStore* cell;
+MBBase::Environment& env = MBBase::Environment::get();
+```
+
+### Initialization Lists
+
+**ALWAYS use initialization lists for constructors:**
+
+```cpp
+MyClass::MyClass(int value, const std::string& name)
+ : mValue(value)
+ , mName(name)
+ , mCounter(0)
+ , mIsActive(false)
+{
+ // Constructor body for additional logic only
+}
+```
+
+### Const Correctness
+
+```cpp
+class DataManager
+{
+public:
+ // Non-const methods for modification
+ void addData(int value);
+ void clearData();
+
+ // Const methods for reading only
+ int getDataCount() const;
+ bool hasData() const;
+ const std::vector<int>& getData() const;
+
+ // Return const reference when not modifying
+ const std::string& getName() const { return mName; }
+
+private:
+ std::vector<int> mData;
+ std::string mName;
+};
+```
+
+### Error Handling in Base Classes
+
+```cpp
+// Use exceptions for unsupported operations in base classes
+class GameObjectBase
+{
+public:
+ virtual InventoryStore& getInventoryStore(const Ptr& ptr) const
+ {
+ throw std::runtime_error("This object type does not have an inventory");
+ }
+
+ virtual float getWeight(const Ptr& ptr) const
+ {
+ throw std::runtime_error("This object type does not have weight");
+ }
+};
+```
+
+## File Organization
+
+### Header File Template
+
+```cpp
+#ifndef OPENMB_<PATH>_H
+#define OPENMB_<PATH>_H
+
+// Includes in proper order
+#include <standard/library>
+
+#include <external/library>
+
+#include <components/project/header.hpp>
+
+// Forward declarations
+namespace MBWorld
+{
+ class Ptr;
+}
+
+namespace <YourNamespace>
+{
+ /// Class documentation
+ class ClassName
+ {
+ public:
+ // Public interface
+
+ protected:
+ // Protected members
+
+ private:
+ // Private members
+ // All member variables with 'm' prefix
+ };
+}
+
+#endif
+```
+
+### Implementation File Template
+
+```cpp
+#include "classname.hpp"
+
+#include <algorithm>
+#include <stdexcept>
+
+#include "../other/project/headers.hpp"
+
+namespace <YourNamespace>
+{
+ ClassName::ClassName()
+ : mMember1()
+ , mMember2(0)
+ {
+ }
+
+ void ClassName::method()
+ {
+ // Implementation
+ }
+}
+```
+
+## Platform Considerations
+
+```cpp
+// Avoid platform-specific code when possible
+// If necessary, use clear preprocessor guards
+
+#ifdef _WIN32
+ // Windows-specific code
+#elif defined(__linux__)
+ // Linux-specific code
+#elif defined(__APPLE__)
+ // macOS-specific code
+#else
+ #error "Unsupported platform"
+#endif
+
+// Prefer cross-platform solutions
+#include <filesystem> // C++17 cross-platform filesystem
+namespace fs = std::filesystem;
+```
+
+## Testing and Validation
+
+When generating code, consider:
+
+1. **Is the code cross-platform compatible?**
+2. **Are all member variables initialized?**
+3. **Is const correctness maintained?**
+4. **Are there proper Doxygen comments?**
+5. **Does it follow the naming conventions?**
+6. **Is memory managed safely (RAII/smart pointers)?**
+7. **Are exceptions used appropriately?**
+8. **Does it follow the brace style (Allman)?**
+
+## Quick Reference Checklist
+
+Before generating code, verify:
+
+- [ ] Braces on their own line (Allman style)
+- [ ] 4 space indentation (no tabs)
+- [ ] Member variables have 'm' prefix
+- [ ] Functions use camelCase
+- [ ] Classes use PascalCase
+- [ ] Include guards follow OPENMB_<PATH>_H format
+- [ ] Includes are in correct order
+- [ ] Const correctness is maintained
+- [ ] Smart pointers used instead of raw pointers for ownership
+- [ ] Override keyword used for virtual functions
+- [ ] Doxygen comments on public APIs
+- [ ] Initialization lists used in constructors
+- [ ] Namespaces properly indented
+- [ ] Line length under 120 columns
+- [ ] Exception handling for error conditions
+
+## Example: Complete Class Generation
+
+When asked to create a new class, generate both header and implementation following this pattern:
+
+**Header (playermanager.hpp):**
+```cpp
+#ifndef OPENMB_APPS_OPENMB_MBWORLD_PLAYERMANAGER_H
+#define OPENMB_APPS_OPENMB_MBWORLD_PLAYERMANAGER_H
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <components/esm/refid.hpp>
+
+namespace MBWorld
+{
+ class Ptr;
+ class CellStore;
+
+ /// Manages player state and interactions
+ ///
+ /// This class handles player initialization, state updates,
+ /// and interactions with the game world.
+ class PlayerManager
+ {
+ public:
+ PlayerManager();
+ ~PlayerManager() = default;
+
+ /// Initialize the player in the game world
+ /// \param playerId The unique identifier for the player
+ /// \param startCell The starting cell for the player
+ /// \return True if initialization succeeded
+ bool initialize(const ESM::RefId& playerId, CellStore* startCell);
+
+ /// Update player state
+ /// \param deltaTime Time elapsed since last update in seconds
+ void update(float deltaTime);
+
+ /// Get the current player pointer
+ /// \return Const reference to the player pointer
+ const Ptr& getPlayer() const;
+
+ /// Check if player is initialized
+ bool isInitialized() const;
+
+ private:
+ /// Load player data from save
+ void loadPlayerData(const ESM::RefId& playerId);
+
+ /// Validate player state
+ bool validateState() const;
+
+ Ptr mPlayer;
+ ESM::RefId mPlayerId;
+ bool mIsInitialized;
+ float mTimeSinceLastUpdate;
+ };
+}
+
+#endif
+```
+
+**Implementation (playermanager.cpp):**
+```cpp
+#include "playermanager.hpp"
+
+#include <stdexcept>
+
+#include "../mbbase/environment.hpp"
+#include "cellstore.hpp"
+#include "ptr.hpp"
+
+namespace MBWorld
+{
+ PlayerManager::PlayerManager()
+ : mPlayer()
+ , mPlayerId()
+ , mIsInitialized(false)
+ , mTimeSinceLastUpdate(0.0f)
+ {
+ }
+
+ bool PlayerManager::initialize(const ESM::RefId& playerId, CellStore* startCell)
+ {
+ if (!startCell)
+ {
+ throw std::invalid_argument("Start cell cannot be null");
+ }
+
+ if (playerId.empty())
+ {
+ throw std::invalid_argument("Player ID cannot be empty");
+ }
+
+ mPlayerId = playerId;
+ loadPlayerData(playerId);
+
+ // Additional initialization logic here
+
+ mIsInitialized = validateState();
+ return mIsInitialized;
+ }
+
+ void PlayerManager::update(float deltaTime)
+ {
+ if (!mIsInitialized)
+ {
+ throw std::runtime_error("Cannot update uninitialized player");
+ }
+
+ mTimeSinceLastUpdate += deltaTime;
+
+ // Update logic here
+ }
+
+ const Ptr& PlayerManager::getPlayer() const
+ {
+ if (!mIsInitialized)
+ {
+ throw std::runtime_error("Player not initialized");
+ }
+
+ return mPlayer;
+ }
+
+ bool PlayerManager::isInitialized() const
+ {
+ return mIsInitialized;
+ }
+
+ void PlayerManager::loadPlayerData(const ESM::RefId& playerId)
+ {
+ // Load implementation
+ }
+
+ bool PlayerManager::validateState() const
+ {
+ // Validation implementation
+ return true;
+ }
+}
+```
+
+## Summary
+
+When generating code for OpenMB:
+1. Follow Allman brace style (braces on own lines)
+2. Use proper naming (mMemberVars, camelCaseFunctions, PascalCaseClasses)
+3. Include Doxygen documentation
+4. Use modern C++20 features
+5. Maintain const correctness
+6. Use smart pointers and RAII
+7. Follow include order and guards
+8. Keep code cross-platform
+
+**Remember: Consistency with existing code is paramount. When in doubt, follow the patterns already established in the codebase.**