mirror of
https://github.com/vcmi/vcmi.git
synced 2025-09-16 09:26:28 +02:00
Add comprehensive developer documentation suite
- Create API Reference with detailed engine API documentation - Add Developer Quickstart Guide for new contributors - Create Testing and Debugging guide with practical examples - Add Contributing Guidelines for community standards - Create Engine Architecture overview document - Update Lua Scripting documentation (remove outdated warning) - Fix outdated Logging section in Coding Guidelines - Update main README with organized documentation structure - Remove "may be outdated" warning from engine docs Co-authored-by: dydzio0614 <9436577+dydzio0614@users.noreply.github.com>
This commit is contained in:
@@ -69,24 +69,33 @@ See also installation guide for [Heroes Chronicles](players/Heroes_Chronicles.md
|
||||
|
||||
## Documentation and guidelines for developers
|
||||
|
||||
Development environment setup instructions:
|
||||
### Development Environment Setup
|
||||
|
||||
- [Developer Quickstart Guide](developers/Developer_Quickstart.md) - Quick setup and first steps
|
||||
- [Building VCMI for Android](developers/Building_Android.md)
|
||||
- [Building VCMI for iOS](developers/Building_iOS.md)
|
||||
- [Building VCMI for Linux](developers/Building_Linux.md)
|
||||
- [Building VCMI for macOS](developers/Building_macOS.md)
|
||||
- [Building VCMI for Windows](developers/Building_Windows.md)
|
||||
- [Conan](developers/Conan.md)
|
||||
- [Conan Package Management](developers/Conan.md)
|
||||
|
||||
Engine documentation: (NOTE: may be outdated)
|
||||
### Engine Documentation
|
||||
|
||||
- [Engine Architecture](developers/Engine_Architecture.md) - High-level architecture overview
|
||||
- [API Reference](developers/API_Reference.md) - Comprehensive engine API documentation
|
||||
- [Code Structure](developers/Code_Structure.md) - Detailed code organization
|
||||
- [Coding Guidelines](developers/Coding_Guidelines.md) - Code style and best practices
|
||||
- [Contributing Guidelines](developers/Contributing_Guidelines.md) - How to contribute effectively
|
||||
- [Testing and Debugging](developers/Testing_and_Debugging.md) - Testing strategies and debugging techniques
|
||||
|
||||
### Specialized Topics
|
||||
|
||||
- [Development with Qt Creator](developers/Development_with_Qt_Creator.md)
|
||||
- [Coding Guidelines](developers/Coding_Guidelines.md)
|
||||
- [Bonus System](developers/Bonus_System.md)
|
||||
- [Code Structure](developers/Code_Structure.md)
|
||||
- [Logging API](developers/Logging_API.md)
|
||||
- [Lua Scripting System](developers/Lua_Scripting_System.md)
|
||||
- [Serialization](developers/Serialization.md)
|
||||
- [Bonus System](developers/Bonus_System.md) - Core gameplay mechanic system
|
||||
- [Serialization](developers/Serialization.md) - Save/load and networking system
|
||||
- [Networking](developers/Networking.md) - Network protocol documentation
|
||||
- [Logging API](developers/Logging_API.md) - Logging system usage
|
||||
- [Lua Scripting System](developers/Lua_Scripting_System.md) - Scripting API reference
|
||||
|
||||
## Documentation and guidelines for maintainers
|
||||
|
||||
|
317
docs/developers/API_Reference.md
Normal file
317
docs/developers/API_Reference.md
Normal file
@@ -0,0 +1,317 @@
|
||||
# VCMI Engine API Reference
|
||||
|
||||
This document provides a comprehensive reference for developers working with the VCMI engine APIs.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Core Architecture](#core-architecture)
|
||||
- [Game State API](#game-state-api)
|
||||
- [Object System](#object-system)
|
||||
- [Bonus System API](#bonus-system-api)
|
||||
- [Scripting API](#scripting-api)
|
||||
- [Networking API](#networking-api)
|
||||
- [Serialization API](#serialization-api)
|
||||
- [Graphics and UI](#graphics-and-ui)
|
||||
|
||||
## Core Architecture
|
||||
|
||||
### Client-Server Model
|
||||
|
||||
VCMI uses a client-server architecture where:
|
||||
- **Server** (`VCMI_server`) handles game logic, state management, and validation
|
||||
- **Client** (`VCMI_client`) handles user interface, input, and rendering
|
||||
- **Lib** (`VCMI_lib`) contains shared code used by both client and server
|
||||
|
||||
### Key Base Classes
|
||||
|
||||
#### CGameState
|
||||
Main class containing the complete game state.
|
||||
|
||||
```cpp
|
||||
class CGameState
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<CMap> map;
|
||||
std::array<PlayerState, PlayerColor::PLAYER_LIMIT_I> players;
|
||||
BattleInfo *curB; // current battle
|
||||
|
||||
// Game state queries
|
||||
const CGHeroInstance * getHero(ObjectInstanceID objid) const;
|
||||
const CGTownInstance * getTown(ObjectInstanceID objid) const;
|
||||
// ... other methods
|
||||
};
|
||||
```
|
||||
|
||||
#### CGObjectInstance
|
||||
Base class for all map objects.
|
||||
|
||||
```cpp
|
||||
class CGObjectInstance : public IObjectInterface
|
||||
{
|
||||
public:
|
||||
ObjectInstanceID id;
|
||||
Obj ID; // object type
|
||||
si32 subID; // object subtype
|
||||
int3 pos; // position on map
|
||||
|
||||
virtual void onHeroVisit(const CGHeroInstance * h) const;
|
||||
virtual void initObj(vstd::RNG & rand);
|
||||
// ... other virtual methods
|
||||
};
|
||||
```
|
||||
|
||||
## Game State API
|
||||
|
||||
### Player Management
|
||||
|
||||
```cpp
|
||||
// Get player information
|
||||
const PlayerState * getPlayerState(PlayerColor player) const;
|
||||
|
||||
// Check player status
|
||||
bool isPlayerActive(PlayerColor player) const;
|
||||
```
|
||||
|
||||
### Hero Management
|
||||
|
||||
```cpp
|
||||
// Create and manage heroes
|
||||
CGHeroInstance * createHero(HeroTypeID type, PlayerColor owner);
|
||||
|
||||
// Hero movement and actions
|
||||
void moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting);
|
||||
void giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact *art, ArtifactPosition pos);
|
||||
```
|
||||
|
||||
### Town Management
|
||||
|
||||
```cpp
|
||||
// Building construction
|
||||
void buildStructure(ObjectInstanceID tid, BuildingID building, bool force = false);
|
||||
|
||||
// Creature recruitment
|
||||
void recruitCreatures(ObjectInstanceID obj, ObjectInstanceID dst, CreatureID crid, ui32 cram, si32 level);
|
||||
```
|
||||
|
||||
## Object System
|
||||
|
||||
### Creating Custom Objects
|
||||
|
||||
To create a custom map object:
|
||||
|
||||
1. Inherit from `CGObjectInstance`
|
||||
2. Override required virtual methods
|
||||
3. Register the object type in `RegisterTypes.h`
|
||||
|
||||
```cpp
|
||||
class MyCustomObject : public CGObjectInstance
|
||||
{
|
||||
public:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void initObj(vstd::RNG & rand) override;
|
||||
|
||||
template<typename Handler>
|
||||
void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this);
|
||||
// serialize custom data
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Object Interaction
|
||||
|
||||
```cpp
|
||||
// Visit callbacks
|
||||
virtual void onHeroVisit(const CGHeroInstance * h) const;
|
||||
virtual void onHeroLeave(const CGHeroInstance * h) const;
|
||||
|
||||
// Battle integration
|
||||
virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const;
|
||||
```
|
||||
|
||||
## Bonus System API
|
||||
|
||||
The bonus system is VCMI's core mechanism for handling all stat modifications and special abilities.
|
||||
|
||||
### Basic Bonus Usage
|
||||
|
||||
```cpp
|
||||
// Create a bonus
|
||||
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
||||
bonus->type = Bonus::PRIMARY_SKILL;
|
||||
bonus->subtype = PrimarySkill::ATTACK;
|
||||
bonus->val = 5; // +5 attack
|
||||
|
||||
// Apply to object
|
||||
bonusSystemNode->addNewBonus(bonus);
|
||||
```
|
||||
|
||||
### Bonus Types
|
||||
|
||||
- `PRIMARY_SKILL` - Hero primary skills (Attack, Defense, Spell Power, Knowledge)
|
||||
- `SECONDARY_SKILL_PREMY` - Secondary skill bonuses
|
||||
- `STACKS_SPEED` - Stack speed modifications
|
||||
- `MAGIC_RESISTANCE` - Magic resistance
|
||||
- And many more...
|
||||
|
||||
For complete reference, see [Bonus System](Bonus_System.md) documentation.
|
||||
|
||||
## Scripting API
|
||||
|
||||
### Lua Integration
|
||||
|
||||
VCMI supports Lua scripting for game logic extension.
|
||||
|
||||
#### Basic Script Structure
|
||||
|
||||
```lua
|
||||
local function onVisit(player, object)
|
||||
-- Script logic here
|
||||
return true
|
||||
end
|
||||
|
||||
return {
|
||||
onVisit = onVisit
|
||||
}
|
||||
```
|
||||
|
||||
#### Available APIs
|
||||
|
||||
```lua
|
||||
-- Game state access
|
||||
local hero = game:getHero(heroId)
|
||||
local town = game:getTown(townId)
|
||||
|
||||
-- Object manipulation
|
||||
object:addReward(reward)
|
||||
object:setProperty(property, value)
|
||||
|
||||
-- Player interaction
|
||||
player:addResource(resourceType, amount)
|
||||
player:giveArtifact(artifactId)
|
||||
```
|
||||
|
||||
For detailed scripting reference, see [Lua Scripting System](Lua_Scripting_System.md).
|
||||
|
||||
## Networking API
|
||||
|
||||
### Network Packets
|
||||
|
||||
All communication between client and server uses serializable packet classes inheriting from `CPack`.
|
||||
|
||||
#### Creating Custom Packets
|
||||
|
||||
```cpp
|
||||
class MyCustomPack : public CPack
|
||||
{
|
||||
public:
|
||||
ObjectInstanceID objectId;
|
||||
si32 customData;
|
||||
|
||||
void applyGs(CGameState *gs); // Server-side application
|
||||
|
||||
template<typename Handler>
|
||||
void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & objectId;
|
||||
h & customData;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Sending Packets
|
||||
|
||||
```cpp
|
||||
// From client to server
|
||||
sendRequest(new MyCustomPack(objectId, data));
|
||||
|
||||
// From server to client
|
||||
sendToAllClients(new MyCustomPack(objectId, data));
|
||||
```
|
||||
|
||||
## Serialization API
|
||||
|
||||
VCMI uses a custom serialization system for save games and network communication.
|
||||
|
||||
### Making Objects Serializable
|
||||
|
||||
```cpp
|
||||
template<typename Handler>
|
||||
void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & member1;
|
||||
h & member2;
|
||||
|
||||
// Conditional serialization based on version
|
||||
if(version >= SOME_VERSION)
|
||||
h & newMember;
|
||||
}
|
||||
```
|
||||
|
||||
### Polymorphic Serialization
|
||||
|
||||
For objects that need polymorphic serialization:
|
||||
|
||||
1. Register the type in `RegisterTypes.h`
|
||||
2. Ensure proper inheritance from base serializable class
|
||||
|
||||
For complete serialization guide, see [Serialization](Serialization.md).
|
||||
|
||||
## Graphics and UI
|
||||
|
||||
### Interface Objects
|
||||
|
||||
All UI elements inherit from `CIntObject`:
|
||||
|
||||
```cpp
|
||||
class MyWidget : public CIntObject
|
||||
{
|
||||
public:
|
||||
void showAll(SDL_Surface * to) override; // Rendering
|
||||
void clickLeft(tribool down, bool previousState) override; // Mouse handling
|
||||
void keyPressed(const SDL_KeyboardEvent & key) override; // Keyboard handling
|
||||
};
|
||||
```
|
||||
|
||||
### Resource Management
|
||||
|
||||
```cpp
|
||||
// Loading graphics
|
||||
auto texture = GH.renderHandler().loadImage("path/to/image.png");
|
||||
|
||||
// Animation handling
|
||||
auto animation = std::make_shared<CAnimation>("CREATURE");
|
||||
animation->setCustom("MY_CREATURE", 0, 0);
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Error Handling
|
||||
|
||||
```cpp
|
||||
// Use VCMI logging system
|
||||
logGlobal->error("Error message: %s", errorDetails);
|
||||
logGlobal->warn("Warning message");
|
||||
logGlobal->info("Info message");
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
|
||||
- Use smart pointers (`std::shared_ptr`, `std::unique_ptr`) for automatic memory management
|
||||
- Follow RAII principles
|
||||
- Be careful with circular references in bonus system
|
||||
|
||||
### Thread Safety
|
||||
|
||||
- Game state modifications must happen on the main thread
|
||||
- Use proper synchronization for multi-threaded operations
|
||||
- Client and server run in separate processes, not threads
|
||||
|
||||
## See Also
|
||||
|
||||
- [Code Structure](Code_Structure.md) - Overall architecture overview
|
||||
- [Bonus System](Bonus_System.md) - Detailed bonus system documentation
|
||||
- [Serialization](Serialization.md) - Serialization system details
|
||||
- [Networking](Networking.md) - Network protocol documentation
|
||||
- [Lua Scripting System](Lua_Scripting_System.md) - Scripting API details
|
@@ -771,12 +771,16 @@ Directories start with a lowercase letter and use the camel casing where necessa
|
||||
|
||||
### Logging
|
||||
|
||||
Outdated. There is separate entry for [Logging API](Logging_API.md)
|
||||
For comprehensive logging information, see the [Logging API](Logging_API.md) documentation.
|
||||
|
||||
If you want to trace the control flow of VCMI, then you should use the macro LOG_TRACE or LOG_TRACE_PARAMS. The first one prints a message when the function is entered or leaved. The name of the function will also be logged. In addition to this the second macro, let's you specify parameters which you want to print. You should print traces with parameters like this:
|
||||
Use the appropriate logging macros for different severity levels:
|
||||
|
||||
```cpp
|
||||
LOG_TRACE_PARAMS(logGlobal, "hero '%s', spellId '%d', pos '%s'.", hero, spellId, pos);
|
||||
logGlobal->error("Critical error occurred: %s", errorDetails);
|
||||
logGlobal->warn("Warning: %s", warningMessage);
|
||||
logGlobal->info("Information: %s", infoMessage);
|
||||
logGlobal->debug("Debug information: %s", debugInfo);
|
||||
logGlobal->trace("Detailed trace: %s", traceInfo);
|
||||
```
|
||||
|
||||
When using the macro every "simple" parameter should be logged. The parameter can be a number, a string or a type with a ostream operator\<\<. You should not log contents of a whole text file, a byte array or sth. like this. If there is a simple type with a few members you want to log, you should write an ostream operator\<\<. The produced message can look like this:
|
||||
|
275
docs/developers/Contributing_Guidelines.md
Normal file
275
docs/developers/Contributing_Guidelines.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
Welcome to VCMI development! This guide will help you contribute effectively to the project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Before contributing, please:
|
||||
1. Read the [Developer Quickstart Guide](Developer_Quickstart.md)
|
||||
2. Check our [Coding Guidelines](Coding_Guidelines.md)
|
||||
3. Join our [Discord community](https://discord.gg/chBT42V) for discussion
|
||||
|
||||
## Types of Contributions
|
||||
|
||||
### Bug Reports
|
||||
- Use [GitHub Issues](https://github.com/vcmi/vcmi/issues) for bug reports
|
||||
- Follow the [Bug Reporting Guidelines](../players/Bug_Reporting_Guidelines.md)
|
||||
- Include minimal reproduction steps
|
||||
- Provide system information and log files
|
||||
|
||||
### Feature Requests
|
||||
- Discuss major features on Discord or forums first
|
||||
- Create detailed GitHub issues with use cases
|
||||
- Consider backward compatibility and existing code
|
||||
|
||||
### Code Contributions
|
||||
- Start with issues labeled "good first issue"
|
||||
- Fork the repository and create feature branches
|
||||
- Follow coding standards and include tests
|
||||
- Submit pull requests with clear descriptions
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### 1. Fork and Clone
|
||||
```bash
|
||||
# Fork on GitHub, then:
|
||||
git clone https://github.com/YOUR_USERNAME/vcmi.git
|
||||
cd vcmi
|
||||
git remote add upstream https://github.com/vcmi/vcmi.git
|
||||
```
|
||||
|
||||
### 2. Create Feature Branch
|
||||
```bash
|
||||
git checkout develop
|
||||
git pull upstream develop
|
||||
git checkout -b feature/my-new-feature
|
||||
```
|
||||
|
||||
### 3. Make Changes
|
||||
- Follow [Coding Guidelines](Coding_Guidelines.md)
|
||||
- Write tests for new functionality
|
||||
- Update documentation as needed
|
||||
- Test thoroughly on your platform
|
||||
|
||||
### 4. Commit Changes
|
||||
```bash
|
||||
# Use clear, descriptive commit messages
|
||||
git add .
|
||||
git commit -m "Add new battle spell effect system
|
||||
|
||||
- Implements customizable spell animations
|
||||
- Adds configuration options for effect duration
|
||||
- Includes unit tests for spell effect parsing
|
||||
- Updates documentation for new API"
|
||||
```
|
||||
|
||||
### 5. Push and Submit PR
|
||||
```bash
|
||||
git push origin feature/my-new-feature
|
||||
# Create pull request on GitHub
|
||||
```
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
### Before Submitting
|
||||
- [ ] Code follows our style guidelines
|
||||
- [ ] All tests pass locally
|
||||
- [ ] New functionality includes tests
|
||||
- [ ] Documentation is updated
|
||||
- [ ] Commit messages are clear
|
||||
- [ ] No merge conflicts with develop branch
|
||||
|
||||
### PR Description Template
|
||||
```markdown
|
||||
## Description
|
||||
Brief description of changes and motivation.
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Documentation update
|
||||
|
||||
## Testing
|
||||
- [ ] Unit tests pass
|
||||
- [ ] Manual testing completed
|
||||
- [ ] Regression testing on affected features
|
||||
|
||||
## Screenshots (if applicable)
|
||||
Include screenshots for UI changes.
|
||||
|
||||
## Checklist
|
||||
- [ ] Code follows coding guidelines
|
||||
- [ ] Self-review completed
|
||||
- [ ] Documentation updated
|
||||
- [ ] Tests added/updated
|
||||
```
|
||||
|
||||
## Code Review Process
|
||||
|
||||
### What to Expect
|
||||
1. **Automated checks** run on all PRs (CI/CD)
|
||||
2. **Maintainer review** for code quality and design
|
||||
3. **Community feedback** on significant changes
|
||||
4. **Iterative improvements** based on feedback
|
||||
|
||||
### Review Criteria
|
||||
- **Functionality**: Does it work as intended?
|
||||
- **Design**: Is the approach sound and maintainable?
|
||||
- **Testing**: Are there adequate tests?
|
||||
- **Documentation**: Is it properly documented?
|
||||
- **Style**: Does it follow our guidelines?
|
||||
|
||||
## Coding Standards
|
||||
|
||||
### Code Style
|
||||
Follow our [Coding Guidelines](Coding_Guidelines.md):
|
||||
- Use tabs for indentation
|
||||
- CamelCase for classes, camelCase for variables
|
||||
- Meaningful names and comments
|
||||
- Modern C++ practices (C++17+)
|
||||
|
||||
### Architecture Principles
|
||||
- **Client-Server separation**: UI logic vs game logic
|
||||
- **Serializable state**: All game state must be serializable
|
||||
- **Bonus system**: Use for all stat modifications
|
||||
- **Type safety**: Prefer strong typing over raw values
|
||||
|
||||
### Testing Requirements
|
||||
- **Unit tests** for all new algorithms and logic
|
||||
- **Integration tests** for complex interactions
|
||||
- **Manual testing** for UI and gameplay changes
|
||||
- **Regression testing** for bug fixes
|
||||
|
||||
## Documentation Standards
|
||||
|
||||
### Code Documentation
|
||||
```cpp
|
||||
/**
|
||||
* Brief description of the class/function.
|
||||
*
|
||||
* Detailed description explaining purpose, behavior,
|
||||
* and any important implementation details.
|
||||
*
|
||||
* @param parameter Description of parameter
|
||||
* @return Description of return value
|
||||
* @throws ExceptionType When this might be thrown
|
||||
*/
|
||||
class MyClass
|
||||
{
|
||||
/**
|
||||
* Brief method description.
|
||||
* More details if needed.
|
||||
*/
|
||||
void myMethod(int parameter);
|
||||
};
|
||||
```
|
||||
|
||||
### User Documentation
|
||||
- Update relevant `.md` files for user-facing changes
|
||||
- Include examples and screenshots for complex features
|
||||
- Test documentation accuracy
|
||||
|
||||
## Platform Considerations
|
||||
|
||||
### Cross-Platform Code
|
||||
- Test on multiple platforms when possible
|
||||
- Use CMake for build configuration
|
||||
- Avoid platform-specific code without proper abstraction
|
||||
- Consider endianness and architecture differences
|
||||
|
||||
### Mobile Platforms
|
||||
- Consider touch interface for UI changes
|
||||
- Test performance on resource-constrained devices
|
||||
- Account for different screen sizes and orientations
|
||||
|
||||
## Specific Contribution Areas
|
||||
|
||||
### Game Logic
|
||||
- Location: `lib/` directory
|
||||
- Requires: Understanding of Heroes 3 mechanics
|
||||
- Testing: Unit tests + gameplay verification
|
||||
|
||||
### User Interface
|
||||
- Location: `client/` directory
|
||||
- Requires: SDL2/Qt knowledge
|
||||
- Testing: Visual verification + usability testing
|
||||
|
||||
### AI Development
|
||||
- Location: `AI/` directory
|
||||
- Requires: Understanding of game strategy
|
||||
- Testing: AI vs AI battles, performance metrics
|
||||
|
||||
### Modding Support
|
||||
- Location: `config/` and related systems
|
||||
- Requires: JSON schema knowledge
|
||||
- Testing: Mod loading and validation
|
||||
|
||||
### Map Editor
|
||||
- Location: `mapeditor/` directory
|
||||
- Requires: Qt knowledge
|
||||
- Testing: Map creation and validation
|
||||
|
||||
## Community Guidelines
|
||||
|
||||
### Communication
|
||||
- **Be respectful** and constructive in all interactions
|
||||
- **Ask questions** when you're unsure about something
|
||||
- **Help others** when you can share knowledge
|
||||
- **Stay on topic** in discussions
|
||||
|
||||
### Decision Making
|
||||
- **Discuss major changes** before implementation
|
||||
- **Consider impact** on existing users and mods
|
||||
- **Seek consensus** on controversial decisions
|
||||
- **Document decisions** for future reference
|
||||
|
||||
## Getting Help
|
||||
|
||||
### Resources
|
||||
- [Developer Quickstart](Developer_Quickstart.md) - Quick setup guide
|
||||
- [API Reference](API_Reference.md) - Comprehensive API documentation
|
||||
- [Testing Guide](Testing_and_Debugging.md) - Testing and debugging help
|
||||
|
||||
### Community Support
|
||||
- **Discord**: Real-time chat and quick questions
|
||||
- **Forums**: In-depth discussions and announcements
|
||||
- **GitHub Issues**: Bug reports and feature requests
|
||||
- **Code Review**: Learning opportunity through PR feedback
|
||||
|
||||
### Mentorship
|
||||
- New contributors can request mentorship on Discord
|
||||
- Experienced developers help with architecture questions
|
||||
- Code review provides ongoing learning opportunities
|
||||
|
||||
## Recognition
|
||||
|
||||
### Contributors
|
||||
- All contributors are acknowledged in AUTHORS.h
|
||||
- Significant contributions are highlighted in release notes
|
||||
- Active contributors may be invited to maintainer discussions
|
||||
|
||||
### Maintainers
|
||||
- Long-term contributors may become maintainers
|
||||
- Maintainers have additional responsibilities and privileges
|
||||
- See [Maintainer Guidelines](../maintainers/Project_Infrastructure.md)
|
||||
|
||||
## Legal
|
||||
|
||||
### License
|
||||
- All contributions are licensed under GPL v2+
|
||||
- By contributing, you agree to license your work under these terms
|
||||
- Include license headers in new files
|
||||
|
||||
### Copyright
|
||||
- Contributors retain copyright to their contributions
|
||||
- VCMI Team maintains project copyright
|
||||
- Large contributions may require contributor agreement
|
||||
|
||||
## Thank You!
|
||||
|
||||
Thank you for contributing to VCMI! Your efforts help bring Heroes of Might & Magic III to new platforms and add exciting features for players worldwide.
|
||||
|
||||
Whether you're fixing a small bug, adding a major feature, or improving documentation, every contribution makes a difference. We appreciate your time and effort in making VCMI better for everyone.
|
||||
|
||||
Happy coding! 🎮✨
|
307
docs/developers/Developer_Quickstart.md
Normal file
307
docs/developers/Developer_Quickstart.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# Developer Quickstart Guide
|
||||
|
||||
This guide will help you get started with VCMI development as quickly as possible.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before starting, make sure you have:
|
||||
- Basic knowledge of C++ (C++17 or later)
|
||||
- Git for version control
|
||||
- CMake 3.21+ for building
|
||||
- A code editor or IDE (Qt Creator recommended, see [Development with Qt Creator](Development_with_Qt_Creator.md))
|
||||
|
||||
## Quick Setup (5 minutes)
|
||||
|
||||
### 1. Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules https://github.com/vcmi/vcmi.git
|
||||
cd vcmi
|
||||
```
|
||||
|
||||
### 2. Install Dependencies
|
||||
|
||||
Choose your platform:
|
||||
|
||||
#### Windows
|
||||
Follow the [Windows building guide](Building_Windows.md) or use [Conan](Conan.md):
|
||||
```bash
|
||||
conan install . -pr:b default -pr:h windows-msvc --build=missing
|
||||
```
|
||||
|
||||
#### macOS
|
||||
```bash
|
||||
# Using Conan (recommended)
|
||||
conan install . -pr:b default -pr:h macos-intel --build=missing # Intel
|
||||
conan install . -pr:b default -pr:h macos-arm --build=missing # Apple Silicon
|
||||
|
||||
# Or using Homebrew
|
||||
brew install cmake sdl2 sdl2_image sdl2_mixer sdl2_ttf boost qt5
|
||||
```
|
||||
|
||||
#### Linux
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt install cmake build-essential libsdl2-dev libsdl2-image-dev \
|
||||
libsdl2-mixer-dev libsdl2-ttf-dev libboost-all-dev qtbase5-dev
|
||||
|
||||
# Or use Conan
|
||||
conan install . -pr:b default -pr:h linux-gcc --build=missing
|
||||
```
|
||||
|
||||
### 3. Build the Project
|
||||
|
||||
```bash
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build . --parallel
|
||||
```
|
||||
|
||||
### 4. Test Your Build
|
||||
|
||||
```bash
|
||||
# Run basic tests (if available)
|
||||
ctest
|
||||
|
||||
# Run VCMI client (make sure you have Heroes 3 data files)
|
||||
./client/vcmiclient
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
vcmi/
|
||||
├── client/ # Game client (UI, rendering, input)
|
||||
├── server/ # Game server (logic, AI, validation)
|
||||
├── lib/ # Shared library (game mechanics, data)
|
||||
├── AI/ # AI implementations
|
||||
├── launcher/ # Game launcher utility
|
||||
├── mapeditor/ # Map editor
|
||||
├── test/ # Unit tests
|
||||
├── config/ # Game configuration files
|
||||
└── docs/ # Documentation
|
||||
```
|
||||
|
||||
### Key Directories in Detail
|
||||
|
||||
- **`lib/`** - Core game mechanics, serialization, map objects
|
||||
- **`client/windows/`** - Game UI windows and dialogs
|
||||
- **`client/battle/`** - Battle interface components
|
||||
- **`server/`** - Game state management and AI
|
||||
- **`scripting/`** - Lua scripting system
|
||||
|
||||
### Making Your First Change
|
||||
|
||||
Let's add a simple debug message when the game starts:
|
||||
|
||||
1. **Edit the client main file:**
|
||||
```bash
|
||||
# Open client/vcmiclient.cpp in your editor
|
||||
```
|
||||
|
||||
2. **Add a debug message:**
|
||||
```cpp
|
||||
// Find the main() function and add near the beginning:
|
||||
logGlobal->info("Hello from my VCMI build!");
|
||||
```
|
||||
|
||||
3. **Rebuild and test:**
|
||||
```bash
|
||||
cmake --build . --parallel
|
||||
./client/vcmiclient
|
||||
```
|
||||
|
||||
You should see your message in the log output.
|
||||
|
||||
## Common Development Tasks
|
||||
|
||||
### Adding a New Map Object
|
||||
|
||||
1. **Create the object class** in `lib/mapObjects/`:
|
||||
```cpp
|
||||
// MyObject.h
|
||||
class MyObject : public CGObjectInstance
|
||||
{
|
||||
public:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
|
||||
template<typename Handler>
|
||||
void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
2. **Register the object** in `lib/serializer/RegisterTypes.h`:
|
||||
```cpp
|
||||
s.template registerType<MyObject>(NEXT_AVAILABLE_ID);
|
||||
```
|
||||
|
||||
3. **Add object configuration** in `config/objects/`:
|
||||
```json
|
||||
{
|
||||
"myObject": {
|
||||
"handler": "myObject",
|
||||
"types": {
|
||||
"object": {
|
||||
"rmg": {
|
||||
"value": 100,
|
||||
"rarity": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adding a New Bonus Type
|
||||
|
||||
1. **Define the bonus** in `lib/Bonus.h`:
|
||||
```cpp
|
||||
enum BonusType
|
||||
{
|
||||
// ... existing bonuses
|
||||
MY_NEW_BONUS,
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
2. **Handle the bonus** in relevant calculation code
|
||||
3. **Add configuration** in `config/bonusnames.json`
|
||||
|
||||
### Adding UI Elements
|
||||
|
||||
1. **Create the interface class** inheriting from `CIntObject`
|
||||
2. **Override rendering and input methods**
|
||||
3. **Add to parent window or interface**
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Debug Build
|
||||
```bash
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
```
|
||||
|
||||
### Useful Debug Options
|
||||
```bash
|
||||
# Enable additional logging
|
||||
cmake .. -DENABLE_DEBUG_CONSOLE=ON
|
||||
|
||||
# Enable debugging symbols
|
||||
cmake .. -DCMAKE_CXX_FLAGS="-g3 -O0"
|
||||
```
|
||||
|
||||
### Using GDB (Linux/macOS)
|
||||
```bash
|
||||
gdb ./client/vcmiclient
|
||||
(gdb) run
|
||||
(gdb) bt # backtrace on crash
|
||||
```
|
||||
|
||||
### Using Visual Studio Debugger (Windows)
|
||||
1. Generate Visual Studio project: `cmake .. -G "Visual Studio 16 2019"`
|
||||
2. Open `VCMI.sln` in Visual Studio
|
||||
3. Set breakpoints and debug normally
|
||||
|
||||
## Testing
|
||||
|
||||
### Running Unit Tests
|
||||
```bash
|
||||
cd build
|
||||
ctest --verbose
|
||||
```
|
||||
|
||||
### Manual Testing
|
||||
1. Copy Heroes 3 data files to appropriate directory
|
||||
2. Run `vcmilauncher` to configure
|
||||
3. Start a new game to test changes
|
||||
|
||||
### Creating Tests
|
||||
Add test files in `test/` directory following existing patterns:
|
||||
```cpp
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(MyTest, TestSomething)
|
||||
{
|
||||
EXPECT_EQ(1 + 1, 2);
|
||||
}
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
### Follow the Guidelines
|
||||
- Read [Coding Guidelines](Coding_Guidelines.md) thoroughly
|
||||
- Use tabs for indentation
|
||||
- Follow naming conventions:
|
||||
- Classes: `CMyClass` or `MyClass`
|
||||
- Variables: `camelCase`
|
||||
- Constants: `ALL_CAPS`
|
||||
|
||||
### Useful Tools
|
||||
```bash
|
||||
# Format code with clang-format
|
||||
clang-format -i file.cpp
|
||||
|
||||
# Check style
|
||||
clang-tidy file.cpp
|
||||
```
|
||||
|
||||
## Common Gotchas
|
||||
|
||||
### 1. Client vs Server Code
|
||||
- **Client**: UI, graphics, input handling
|
||||
- **Server**: Game logic, state changes, validation
|
||||
- **Never** modify game state directly from client code
|
||||
|
||||
### 2. Serialization
|
||||
- Always update `serialize()` methods when adding new members
|
||||
- Bump serialization version for breaking changes
|
||||
- Test save/load compatibility
|
||||
|
||||
### 3. Memory Management
|
||||
- Use smart pointers (`std::shared_ptr`, `std::unique_ptr`)
|
||||
- Be careful with circular references in bonus system
|
||||
- Don't store raw pointers to game objects
|
||||
|
||||
### 4. Threading
|
||||
- Game state is single-threaded
|
||||
- UI updates must happen on main thread
|
||||
- Use proper synchronization for background tasks
|
||||
|
||||
## Getting Help
|
||||
|
||||
### Documentation
|
||||
- [API Reference](API_Reference.md) - Engine API documentation
|
||||
- [Code Structure](Code_Structure.md) - Architecture overview
|
||||
- [Bonus System](Bonus_System.md) - Bonus system details
|
||||
|
||||
### Community
|
||||
- **Discord**: <https://discord.gg/chBT42V>
|
||||
- **Forums**: <https://forum.vcmi.eu/>
|
||||
- **GitHub Issues**: For bug reports and feature requests
|
||||
|
||||
### Code Navigation
|
||||
- Use an IDE with good C++ support (Qt Creator, CLion, Visual Studio)
|
||||
- Enable `CMAKE_EXPORT_COMPILE_COMMANDS` for language servers
|
||||
- Use `git grep` to search codebase: `git grep "functionName"`
|
||||
|
||||
## Next Steps
|
||||
|
||||
Once you're comfortable with the basics:
|
||||
|
||||
1. **Pick an issue** from GitHub issues labeled "good first issue"
|
||||
2. **Read architecture docs** to understand the bigger picture
|
||||
3. **Study existing code** similar to what you want to implement
|
||||
4. **Start small** - simple fixes and improvements first
|
||||
5. **Ask for help** when you get stuck
|
||||
|
||||
### Recommended Reading Order
|
||||
1. [Code Structure](Code_Structure.md) - Understand the architecture
|
||||
2. [Bonus System](Bonus_System.md) - Core gameplay mechanic
|
||||
3. [Serialization](Serialization.md) - Save/load and networking
|
||||
4. [API Reference](API_Reference.md) - Detailed API documentation
|
||||
|
||||
Happy coding! 🎮
|
365
docs/developers/Engine_Architecture.md
Normal file
365
docs/developers/Engine_Architecture.md
Normal file
@@ -0,0 +1,365 @@
|
||||
# Engine Architecture Overview
|
||||
|
||||
This document provides a high-level overview of VCMI's engine architecture, explaining how the major systems interact and the design principles behind them.
|
||||
|
||||
## Core Design Principles
|
||||
|
||||
### 1. Client-Server Architecture
|
||||
VCMI separates game logic from presentation using a strict client-server model:
|
||||
- **Server** (`VCMI_server`) - Authoritative game state, AI, validation
|
||||
- **Client** (`VCMI_client`) - User interface, graphics, input handling
|
||||
- **Shared Library** (`VCMI_lib`) - Common code, data structures, utilities
|
||||
|
||||
### 2. Deterministic Simulation
|
||||
The game state must be completely deterministic for:
|
||||
- Save/load compatibility
|
||||
- Network multiplayer synchronization
|
||||
- Replay functionality
|
||||
- AI consistency
|
||||
|
||||
### 3. Data-Driven Design
|
||||
Game content is defined through JSON configuration files:
|
||||
- Heroes, creatures, spells, artifacts
|
||||
- Map objects and their behaviors
|
||||
- UI layouts and graphics
|
||||
- Mod support through config overrides
|
||||
|
||||
## System Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ VCMI Client │ │ VCMI Server │
|
||||
│ │ │ │
|
||||
│ ┌─────────────┐ │ │ ┌─────────────┐ │
|
||||
│ │ UI Systems │ │ │ │ Game Logic │ │
|
||||
│ │ - Windows │ │ │ │ - Mechanics │ │
|
||||
│ │ - Adventure │ │ │ │ - Validation│ │
|
||||
│ │ - Battle │ │◄──►│ │ - Queries │ │
|
||||
│ │ - Launcher │ │ │ └─────────────┘ │
|
||||
│ └─────────────┘ │ │ ┌─────────────┐ │
|
||||
│ ┌─────────────┐ │ │ │ AI Systems │ │
|
||||
│ │ Graphics │ │ │ │ - VCAI │ │
|
||||
│ │ - SDL2 │ │ │ │ - Nullkiller│ │
|
||||
│ │ - Rendering │ │ │ │ - Battle AI │ │
|
||||
│ │ - Animation │ │ │ └─────────────┘ │
|
||||
│ └─────────────┘ │ └─────────────────┘
|
||||
└─────────────────┘ │
|
||||
│ │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌─────────────────┐
|
||||
│ VCMI Library │
|
||||
│ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ Game State │ │
|
||||
│ │ - CGameState│ │
|
||||
│ │ - Map Data │ │
|
||||
│ │ - Players │ │
|
||||
│ └─────────────┘ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ Bonus System│ │
|
||||
│ │ - Modifiers │ │
|
||||
│ │ - Effects │ │
|
||||
│ │ - Artifacts │ │
|
||||
│ └─────────────┘ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ Serializer │ │
|
||||
│ │ - Save/Load │ │
|
||||
│ │ - Network │ │
|
||||
│ │ - Packets │ │
|
||||
│ └─────────────┘ │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
## Core Components
|
||||
|
||||
### Game State (`CGameState`)
|
||||
The authoritative representation of the game world:
|
||||
|
||||
```cpp
|
||||
class CGameState
|
||||
{
|
||||
std::unique_ptr<CMap> map; // Game map
|
||||
std::array<PlayerState, PLAYER_LIMIT> players; // Player states
|
||||
std::unique_ptr<BattleInfo> curB; // Current battle
|
||||
si32 day; // Current day
|
||||
// ... other game state
|
||||
};
|
||||
```
|
||||
|
||||
**Responsibilities:**
|
||||
- Maintains all game objects and their states
|
||||
- Provides query interfaces for game information
|
||||
- Ensures state consistency and validation
|
||||
- Handles turn progression and time management
|
||||
|
||||
### Map System (`CMap`)
|
||||
Represents the game world layout and objects:
|
||||
|
||||
```cpp
|
||||
class CMap
|
||||
{
|
||||
int3 size; // Map dimensions
|
||||
TerrainTile*** terrain; // Terrain grid
|
||||
std::vector<CGObjectInstance*> objects; // Map objects
|
||||
std::vector<CGHeroInstance*> heroes; // All heroes
|
||||
std::vector<CGTownInstance*> towns; // All towns
|
||||
// ... other map data
|
||||
};
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- 3D coordinate system (x, y, underground level)
|
||||
- Dynamic object placement and removal
|
||||
- Pathfinding integration
|
||||
- Fog of war management
|
||||
|
||||
### Bonus System
|
||||
The core mechanic for all stat modifications and special abilities:
|
||||
|
||||
```cpp
|
||||
class Bonus
|
||||
{
|
||||
BonusType type; // What kind of bonus
|
||||
si32 val; // Numeric value
|
||||
si32 subtype; // Bonus subtype
|
||||
BonusDuration duration; // How long it lasts
|
||||
// ... bonus properties
|
||||
};
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
- Hero primary skills: `+5 Attack`
|
||||
- Artifact effects: `+2 to all skills`
|
||||
- Spell effects: `+50% Magic Resistance`
|
||||
- Terrain bonuses: `+1 Defense on plains`
|
||||
|
||||
**Benefits:**
|
||||
- Unified system for all game effects
|
||||
- Automatic stacking and conflict resolution
|
||||
- Save/load compatible
|
||||
- Easily extensible for mods
|
||||
|
||||
### Object System (`CGObjectInstance`)
|
||||
Base class for all interactive map objects:
|
||||
|
||||
```cpp
|
||||
class CGObjectInstance
|
||||
{
|
||||
ObjectInstanceID id; // Unique identifier
|
||||
Obj ID; // Object type (town, hero, mine, etc.)
|
||||
si32 subID; // Object subtype
|
||||
int3 pos; // Map position
|
||||
|
||||
virtual void onHeroVisit(const CGHeroInstance * h) const;
|
||||
virtual void newTurn() const;
|
||||
virtual void initObj(vstd::RNG & rand);
|
||||
};
|
||||
```
|
||||
|
||||
**Object Types:**
|
||||
- **Heroes** (`CGHeroInstance`) - Movable units with armies
|
||||
- **Towns** (`CGTownInstance`) - Buildable settlements
|
||||
- **Dwellings** (`CGDwelling`) - Creature recruitment
|
||||
- **Resources** (`CGResource`) - Collectible resources
|
||||
- **Artifacts** (`CGArtifact`) - Collectible items
|
||||
- **Custom Objects** - Scripted behaviors
|
||||
|
||||
## Communication Architecture
|
||||
|
||||
### Network Protocol
|
||||
Client-server communication uses typed message packets:
|
||||
|
||||
```cpp
|
||||
class CPack // Base packet class
|
||||
{
|
||||
virtual void applyGs(CGameState *gs) = 0; // Server application
|
||||
virtual void executeOnClient() = 0; // Client application
|
||||
};
|
||||
```
|
||||
|
||||
**Packet Flow:**
|
||||
1. **Client Request** → Server (user actions)
|
||||
2. **Server Validation** → Process or reject
|
||||
3. **Server Response** → All clients (state changes)
|
||||
4. **Client Update** → UI reflects new state
|
||||
|
||||
**Example Packets:**
|
||||
- `MoveHero` - Hero movement request
|
||||
- `BuyArtifact` - Purchase from market
|
||||
- `NewTurn` - Turn progression notification
|
||||
- `BattleStart` - Combat initiation
|
||||
|
||||
### Serialization System
|
||||
Unified system for save/load and network communication:
|
||||
|
||||
```cpp
|
||||
template<typename Handler>
|
||||
void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & membervariable1;
|
||||
h & membervariable2;
|
||||
// ... serialize all members
|
||||
}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Automatic type registration
|
||||
- Version compatibility handling
|
||||
- Polymorphic object support
|
||||
- Cross-platform compatibility
|
||||
|
||||
## Subsystem Details
|
||||
|
||||
### Battle System
|
||||
Turn-based tactical combat with hex grid:
|
||||
|
||||
**Components:**
|
||||
- `BattleInfo` - Battle state and rules
|
||||
- `CStack` - Individual creature stacks
|
||||
- `BattleAction` - Player/AI commands
|
||||
- `BattleSpellMechanics` - Spell effects
|
||||
|
||||
**Flow:**
|
||||
1. Battle initialization from map encounter
|
||||
2. Turn-based stack activation
|
||||
3. Action processing (move, attack, cast)
|
||||
4. Effect resolution and damage calculation
|
||||
5. Victory condition checking
|
||||
|
||||
### AI Framework
|
||||
Pluggable AI system with multiple implementations:
|
||||
|
||||
**VCAI (Default AI):**
|
||||
- Goal-driven decision making
|
||||
- Resource and building optimization
|
||||
- Army composition strategies
|
||||
- Adventure map exploration
|
||||
|
||||
**Nullkiller AI:**
|
||||
- Modern rewrite of VCAI
|
||||
- Improved performance and decision quality
|
||||
- Better pathfinding and strategic planning
|
||||
|
||||
### Graphics System
|
||||
SDL2-based rendering with custom optimizations:
|
||||
|
||||
**Components:**
|
||||
- Texture management and caching
|
||||
- Animation system with frame interpolation
|
||||
- UI widget library (`CIntObject` hierarchy)
|
||||
- Screen resolution scaling
|
||||
|
||||
**Rendering Pipeline:**
|
||||
1. Adventure map background
|
||||
2. Object sprites (heroes, buildings, etc.)
|
||||
3. UI overlays (windows, dialogs)
|
||||
4. Effect animations (spells, combat)
|
||||
|
||||
### Configuration System
|
||||
JSON-based data definition for game content:
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
config/
|
||||
├── creatures.json # Creature definitions
|
||||
├── heroes.json # Hero definitions
|
||||
├── spells.json # Spell definitions
|
||||
├── artifacts.json # Artifact definitions
|
||||
├── objects/ # Map object configurations
|
||||
└── schemas/ # JSON validation schemas
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Easy modding without code changes
|
||||
- Translation support
|
||||
- Version control friendly
|
||||
- Validation and error detection
|
||||
|
||||
## Data Flow Examples
|
||||
|
||||
### Hero Movement
|
||||
1. **Client**: User clicks on map tile
|
||||
2. **Client**: Sends `MoveHero` packet to server
|
||||
3. **Server**: Validates movement legality
|
||||
4. **Server**: Updates game state with new position
|
||||
5. **Server**: Sends `MoveHero` confirmation to all clients
|
||||
6. **Clients**: Update hero position in UI
|
||||
|
||||
### Combat Resolution
|
||||
1. **Client**: Player selects attack target
|
||||
2. **Client**: Sends `BattleAction` to server
|
||||
3. **Server**: Calculates damage using bonus system
|
||||
4. **Server**: Applies damage to target stack
|
||||
5. **Server**: Sends `BattleAttack` result to all clients
|
||||
6. **Clients**: Play attack animation and update HP
|
||||
|
||||
### Save Game Creation
|
||||
1. **Client**: Requests save game creation
|
||||
2. **Server**: Serializes complete `CGameState`
|
||||
3. **Server**: Writes binary data to file
|
||||
4. **Server**: Confirms save completion
|
||||
5. **Client**: Updates UI with save confirmation
|
||||
|
||||
## Extension Points
|
||||
|
||||
### Custom Map Objects
|
||||
1. Create class inheriting from `CGObjectInstance`
|
||||
2. Override virtual methods (`onHeroVisit`, etc.)
|
||||
3. Register type in `RegisterTypes.h`
|
||||
4. Add configuration in `config/objects/`
|
||||
|
||||
### New Bonus Types
|
||||
1. Add enum value to `BonusType`
|
||||
2. Handle in calculation code
|
||||
3. Add configuration entries
|
||||
4. Update UI descriptions
|
||||
|
||||
### Scripting Integration
|
||||
1. Lua scripts for object behaviors
|
||||
2. Event-driven architecture
|
||||
3. Sandbox execution environment
|
||||
4. Game state access APIs
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Memory Management
|
||||
- Smart pointers for automatic cleanup
|
||||
- Object pooling for frequently created objects
|
||||
- Copy-on-write for large data structures
|
||||
- Reference counting for shared resources
|
||||
|
||||
### Computational Efficiency
|
||||
- Pathfinding caching and optimization
|
||||
- Bonus system lazy evaluation
|
||||
- Graphics texture atlasing
|
||||
- Battle calculation vectorization
|
||||
|
||||
### Network Optimization
|
||||
- Packet compression for large data
|
||||
- Delta updates for state changes
|
||||
- Prediction for smooth movement
|
||||
- Connection timeout handling
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Adding New Features
|
||||
1. **Design Review** - Discuss architecture impact
|
||||
2. **Interface Definition** - Define clear APIs
|
||||
3. **Implementation** - Follow coding standards
|
||||
4. **Testing** - Unit and integration tests
|
||||
5. **Documentation** - Update relevant docs
|
||||
|
||||
### Debugging Strategies
|
||||
1. **Logging** - Use appropriate log levels
|
||||
2. **Assertions** - Validate assumptions
|
||||
3. **Reproducibility** - Ensure deterministic behavior
|
||||
4. **Isolation** - Test components independently
|
||||
|
||||
### Maintenance Practices
|
||||
1. **Code Review** - Peer review all changes
|
||||
2. **Refactoring** - Improve design over time
|
||||
3. **Performance Monitoring** - Profile critical paths
|
||||
4. **Technical Debt** - Address accumulated issues
|
||||
|
||||
This architecture has evolved over many years to support the complexity of Heroes of Might & Magic III while remaining maintainable and extensible. Understanding these core concepts will help you navigate the codebase and contribute effectively to the project.
|
@@ -38,7 +38,7 @@
|
||||
|
||||
### API Reference
|
||||
|
||||
TODO **In near future Lua API may change drastically several times. Information here may be outdated**
|
||||
The Lua scripting API provides access to core game functionality and is continuously improved. For the latest API changes, check the Git history of the `scripting/lua/api/` directory.
|
||||
|
||||
#### Globals
|
||||
|
||||
|
488
docs/developers/Testing_and_Debugging.md
Normal file
488
docs/developers/Testing_and_Debugging.md
Normal file
@@ -0,0 +1,488 @@
|
||||
# Testing and Debugging Guide
|
||||
|
||||
This guide covers testing strategies, debugging techniques, and troubleshooting for VCMI development.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Testing Framework](#testing-framework)
|
||||
- [Unit Testing](#unit-testing)
|
||||
- [Integration Testing](#integration-testing)
|
||||
- [Manual Testing](#manual-testing)
|
||||
- [Debugging Techniques](#debugging-techniques)
|
||||
- [Performance Profiling](#performance-profiling)
|
||||
- [Common Issues](#common-issues)
|
||||
|
||||
## Testing Framework
|
||||
|
||||
VCMI uses Google Test (gtest) for unit testing and custom frameworks for integration testing.
|
||||
|
||||
### Building with Tests
|
||||
|
||||
```bash
|
||||
# Configure with tests enabled
|
||||
cmake .. -DENABLE_TEST=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
# Build tests
|
||||
cmake --build . --target vcmitest
|
||||
|
||||
# Run all tests
|
||||
ctest --verbose
|
||||
```
|
||||
|
||||
### Test Directory Structure
|
||||
|
||||
```
|
||||
test/
|
||||
├── googletest/ # Google Test framework
|
||||
├── battle/ # Battle system tests
|
||||
├── bonus/ # Bonus system tests
|
||||
├── map/ # Map loading tests
|
||||
├── serializer/ # Serialization tests
|
||||
└── vcai/ # AI tests
|
||||
```
|
||||
|
||||
## Unit Testing
|
||||
|
||||
### Writing Unit Tests
|
||||
|
||||
Create test files in the appropriate `test/` subdirectory:
|
||||
|
||||
```cpp
|
||||
// test/bonus/BonusTest.cpp
|
||||
#include <gtest/gtest.h>
|
||||
#include "../../lib/bonus/Bonus.h"
|
||||
|
||||
TEST(BonusTest, BasicBonus)
|
||||
{
|
||||
auto bonus = std::make_shared<Bonus>(Bonus::PRIMARY_SKILL, 5, PrimarySkill::ATTACK);
|
||||
|
||||
EXPECT_EQ(bonus->type, Bonus::PRIMARY_SKILL);
|
||||
EXPECT_EQ(bonus->val, 5);
|
||||
EXPECT_EQ(bonus->subtype, PrimarySkill::ATTACK);
|
||||
}
|
||||
|
||||
TEST(BonusTest, BonusStacking)
|
||||
{
|
||||
CBonusSystemNode node;
|
||||
|
||||
auto bonus1 = std::make_shared<Bonus>(Bonus::PRIMARY_SKILL, 3, PrimarySkill::ATTACK);
|
||||
auto bonus2 = std::make_shared<Bonus>(Bonus::PRIMARY_SKILL, 2, PrimarySkill::ATTACK);
|
||||
|
||||
node.addNewBonus(bonus1);
|
||||
node.addNewBonus(bonus2);
|
||||
|
||||
EXPECT_EQ(node.getBonuses(Selector::type(Bonus::PRIMARY_SKILL))->size(), 2);
|
||||
}
|
||||
```
|
||||
|
||||
### Test Fixtures
|
||||
|
||||
For complex setup, use test fixtures:
|
||||
|
||||
```cpp
|
||||
class GameStateTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
gameState = std::make_unique<CGameState>();
|
||||
// Initialize test game state
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
gameState.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<CGameState> gameState;
|
||||
};
|
||||
|
||||
TEST_F(GameStateTest, HeroCreation)
|
||||
{
|
||||
auto hero = gameState->createHero(HeroTypeID(0), PlayerColor::RED);
|
||||
ASSERT_NE(hero, nullptr);
|
||||
EXPECT_EQ(hero->tempOwner, PlayerColor::RED);
|
||||
}
|
||||
```
|
||||
|
||||
### Mocking
|
||||
|
||||
For testing components that depend on external systems:
|
||||
|
||||
```cpp
|
||||
class MockGameCallback : public IGameCallback
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD(void, giveResource, (PlayerColor player, Res::ERes which, int val));
|
||||
MOCK_METHOD(void, giveCreatures, (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove));
|
||||
// ... other mock methods
|
||||
};
|
||||
|
||||
TEST(HeroTest, GainExperience)
|
||||
{
|
||||
MockGameCallback mockCb;
|
||||
CGHeroInstance hero;
|
||||
|
||||
EXPECT_CALL(mockCb, giveResource(PlayerColor::RED, Res::EXPERIENCE, 1000));
|
||||
|
||||
hero.gainExp(1000);
|
||||
}
|
||||
```
|
||||
|
||||
## Integration Testing
|
||||
|
||||
### Map Loading Tests
|
||||
|
||||
Test map loading and validation:
|
||||
|
||||
```cpp
|
||||
TEST(MapTest, LoadValidMap)
|
||||
{
|
||||
auto map = std::make_unique<CMap>();
|
||||
CMapLoaderH3M loader;
|
||||
|
||||
EXPECT_NO_THROW(loader.loadMap("test/maps/valid_map.h3m", map.get()));
|
||||
EXPECT_GT(map->width, 0);
|
||||
EXPECT_GT(map->height, 0);
|
||||
}
|
||||
```
|
||||
|
||||
### Battle System Tests
|
||||
|
||||
Test battle mechanics:
|
||||
|
||||
```cpp
|
||||
TEST(BattleTest, BasicCombat)
|
||||
{
|
||||
// Set up battle
|
||||
BattleInfo battle;
|
||||
auto attacker = battle.getBattleHero(BattleSide::ATTACKER);
|
||||
auto defender = battle.getBattleHero(BattleSide::DEFENDER);
|
||||
|
||||
// Test combat calculations
|
||||
auto damage = BattleInfo::calculateDmg(attacker, defender, true, false, battle.getStack(0));
|
||||
EXPECT_GT(damage.first, 0);
|
||||
}
|
||||
```
|
||||
|
||||
### Serialization Tests
|
||||
|
||||
Test save/load functionality:
|
||||
|
||||
```cpp
|
||||
TEST(SerializationTest, SaveLoadGameState)
|
||||
{
|
||||
CGameState originalState;
|
||||
// Initialize state...
|
||||
|
||||
// Save to memory buffer
|
||||
std::ostringstream oss;
|
||||
COSer<CSaveFile> saver(oss);
|
||||
saver << originalState;
|
||||
|
||||
// Load from buffer
|
||||
std::istringstream iss(oss.str());
|
||||
CISer<CLoadFile> loader(iss);
|
||||
CGameState loadedState;
|
||||
loader >> loadedState;
|
||||
|
||||
// Verify state matches
|
||||
EXPECT_EQ(originalState.day, loadedState.day);
|
||||
EXPECT_EQ(originalState.players.size(), loadedState.players.size());
|
||||
}
|
||||
```
|
||||
|
||||
## Manual Testing
|
||||
|
||||
### Test Game Setup
|
||||
|
||||
1. **Create test scenarios** in `test/testdata/`:
|
||||
```
|
||||
testdata/
|
||||
├── maps/ # Test maps
|
||||
├── saves/ # Test save files
|
||||
└── configs/ # Test configurations
|
||||
```
|
||||
|
||||
2. **Use debug commands** in-game:
|
||||
```
|
||||
vcmiistari # Enable debug mode
|
||||
vcmiarmenelos # Give all resources
|
||||
vcmiainur # Give all artifacts
|
||||
```
|
||||
|
||||
### Cheat Codes for Testing
|
||||
|
||||
Enable cheats in game and use:
|
||||
- `vcmiistari` - Enable other cheats
|
||||
- `vcmiarmenelos` - Add 100000 of each resource
|
||||
- `vcmiainur` - Give all artifacts
|
||||
- `vcmiangband` - Give all spells
|
||||
- `vcmilostsoul` - Lose game
|
||||
- `vcmiwinwin` - Win game
|
||||
|
||||
### Custom Test Maps
|
||||
|
||||
Create minimal test maps for specific features:
|
||||
|
||||
```json
|
||||
// minimal_test.json (map template)
|
||||
{
|
||||
"size": { "width": 36, "height": 36, "depth": 1 },
|
||||
"players": ["red", "blue"],
|
||||
"objects": [
|
||||
{
|
||||
"type": "town",
|
||||
"subtype": "castle",
|
||||
"pos": [17, 17, 0],
|
||||
"template": "avctcas0.def",
|
||||
"owner": "red"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Debugging Techniques
|
||||
|
||||
### Debug Builds
|
||||
|
||||
Always use debug builds for development:
|
||||
|
||||
```bash
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_CXX_FLAGS="-g3 -O0 -fno-omit-frame-pointer" \
|
||||
-DENABLE_DEBUG_CONSOLE=ON
|
||||
```
|
||||
|
||||
### Logging
|
||||
|
||||
Use VCMI's logging system extensively:
|
||||
|
||||
```cpp
|
||||
#include "lib/logging/CLogger.h"
|
||||
|
||||
// Different log levels
|
||||
logGlobal->error("Critical error: %s", errorMessage);
|
||||
logGlobal->warn("Warning: %s", warningMessage);
|
||||
logGlobal->info("Info: %s", infoMessage);
|
||||
logGlobal->debug("Debug: %s", debugMessage);
|
||||
logGlobal->trace("Trace: %s", traceMessage);
|
||||
|
||||
// Category-specific logging
|
||||
logAi->info("AI decision: %s", decision);
|
||||
logNetwork->debug("Network packet: %s", packet);
|
||||
```
|
||||
|
||||
### GDB Debugging (Linux/macOS)
|
||||
|
||||
```bash
|
||||
# Start with GDB
|
||||
gdb ./client/vcmiclient
|
||||
|
||||
# Set breakpoints
|
||||
(gdb) break CGHeroInstance::gainExp
|
||||
(gdb) break BattleInfo::calculateDmg
|
||||
|
||||
# Run with arguments
|
||||
(gdb) run --testgame
|
||||
|
||||
# Examine variables
|
||||
(gdb) print hero->name
|
||||
(gdb) print *this
|
||||
|
||||
# Stack trace
|
||||
(gdb) bt
|
||||
(gdb) frame 3
|
||||
```
|
||||
|
||||
### Visual Studio Debugging (Windows)
|
||||
|
||||
1. **Set up debugging:**
|
||||
- Generate VS project: `cmake .. -G "Visual Studio 16 2019"`
|
||||
- Set vcmiclient as startup project
|
||||
- Configure debugging arguments in project properties
|
||||
|
||||
2. **Useful debugging features:**
|
||||
- Set conditional breakpoints
|
||||
- Use the Autos/Locals windows
|
||||
- Watch expressions for complex objects
|
||||
- Memory dumps for pointer debugging
|
||||
|
||||
### Memory Debugging
|
||||
|
||||
#### Valgrind (Linux/macOS)
|
||||
|
||||
```bash
|
||||
# Check for memory leaks
|
||||
valgrind --leak-check=full --show-leak-kinds=all ./client/vcmiclient
|
||||
|
||||
# Check for threading issues
|
||||
valgrind --tool=helgrind ./client/vcmiclient
|
||||
```
|
||||
|
||||
#### AddressSanitizer
|
||||
|
||||
```bash
|
||||
# Build with AddressSanitizer
|
||||
cmake .. -DCMAKE_CXX_FLAGS="-fsanitize=address -g"
|
||||
|
||||
# Run to detect memory errors
|
||||
./client/vcmiclient
|
||||
```
|
||||
|
||||
## Performance Profiling
|
||||
|
||||
### CPU Profiling
|
||||
|
||||
#### Using perf (Linux)
|
||||
|
||||
```bash
|
||||
# Record performance data
|
||||
perf record -g ./client/vcmiclient
|
||||
|
||||
# Analyze results
|
||||
perf report
|
||||
|
||||
# Profile specific function
|
||||
perf record -g -e cpu-clock --call-graph dwarf ./client/vcmiclient
|
||||
```
|
||||
|
||||
#### Using Instruments (macOS)
|
||||
|
||||
1. Open Instruments app
|
||||
2. Choose "Time Profiler" template
|
||||
3. Target vcmiclient executable
|
||||
4. Analyze call trees and hot spots
|
||||
|
||||
### Memory Profiling
|
||||
|
||||
#### Heap profiling with gperftools
|
||||
|
||||
```bash
|
||||
# Build with profiling
|
||||
cmake .. -DCMAKE_CXX_FLAGS="-lprofiler"
|
||||
|
||||
# Run with heap profiler
|
||||
HEAPPROFILE=/tmp/vcmi.hprof ./client/vcmiclient
|
||||
|
||||
# Analyze heap usage
|
||||
google-pprof --gv ./client/vcmiclient /tmp/vcmi.hprof.0001.heap
|
||||
```
|
||||
|
||||
### Benchmarking
|
||||
|
||||
Create performance benchmarks for critical code:
|
||||
|
||||
```cpp
|
||||
#include <chrono>
|
||||
|
||||
void benchmarkBattleCalculation()
|
||||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Run calculation 1000 times
|
||||
for(int i = 0; i < 1000; ++i)
|
||||
{
|
||||
auto damage = BattleInfo::calculateDmg(attacker, defender, true, false, stack);
|
||||
}
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
|
||||
std::cout << "Average calculation time: " << duration.count() / 1000.0 << " μs" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Build Issues
|
||||
|
||||
#### Missing Dependencies
|
||||
```bash
|
||||
# Check what's missing
|
||||
cmake .. 2>&1 | grep -i "not found"
|
||||
|
||||
# Install missing packages (Ubuntu)
|
||||
sudo apt install libsdl2-dev libboost-all-dev
|
||||
```
|
||||
|
||||
#### CMake Cache Issues
|
||||
```bash
|
||||
# Clear cache and reconfigure
|
||||
rm -rf CMakeCache.txt CMakeFiles/
|
||||
cmake ..
|
||||
```
|
||||
|
||||
### Runtime Issues
|
||||
|
||||
#### Segmentation Faults
|
||||
1. **Use GDB** to get stack trace
|
||||
2. **Check null pointers** - common in object interactions
|
||||
3. **Verify object lifetimes** - especially with smart pointers
|
||||
4. **Check array bounds** - use vector::at() instead of operator[]
|
||||
|
||||
#### Memory Leaks
|
||||
1. **Use smart pointers** instead of raw pointers
|
||||
2. **Break circular references** in bonus system
|
||||
3. **Check for proper cleanup** in destructors
|
||||
|
||||
#### Performance Issues
|
||||
1. **Profile first** - don't guess where bottlenecks are
|
||||
2. **Check for N+1 queries** in database-like operations
|
||||
3. **Optimize hot paths** identified by profiler
|
||||
4. **Use const references** to avoid unnecessary copies
|
||||
|
||||
### Network Issues
|
||||
|
||||
#### Desynchronization
|
||||
1. **Check RNG usage** - ensure deterministic behavior
|
||||
2. **Verify packet ordering** - order matters for game state
|
||||
3. **Test save/load** - state must be perfectly reproducible
|
||||
|
||||
#### Connection Problems
|
||||
1. **Check firewall settings**
|
||||
2. **Verify port availability**
|
||||
3. **Test with localhost** first
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
VCMI uses GitHub Actions for CI. Check `.github/workflows/` for:
|
||||
- Build verification on multiple platforms
|
||||
- Unit test execution
|
||||
- Code quality checks
|
||||
|
||||
### Local CI Simulation
|
||||
|
||||
```bash
|
||||
# Run the same checks locally
|
||||
cmake --build . --target test
|
||||
ctest --output-on-failure
|
||||
|
||||
# Static analysis
|
||||
clang-tidy src/*.cpp
|
||||
cppcheck src/
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Testing
|
||||
1. **Write tests first** for new features (TDD)
|
||||
2. **Test edge cases** and error conditions
|
||||
3. **Keep tests independent** - no shared state
|
||||
4. **Use descriptive test names** - explain what's being tested
|
||||
|
||||
### Debugging
|
||||
1. **Reproduce issues reliably** before debugging
|
||||
2. **Use version control** to identify when issues were introduced
|
||||
3. **Document solutions** for future reference
|
||||
4. **Share knowledge** with the team through comments and docs
|
||||
|
||||
### Performance
|
||||
1. **Measure before optimizing** - profile first
|
||||
2. **Optimize algorithms** before micro-optimizations
|
||||
3. **Consider memory locality** for cache efficiency
|
||||
4. **Test performance impact** of changes
|
||||
|
||||
Remember: Good testing and debugging practices save significant time in the long run and improve code quality for the entire project.
|
Reference in New Issue
Block a user