mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-23 22:37:55 +02:00
Imported all data from website wiki
This commit is contained in:
BIN
docs/developers/Architektura.png
Normal file
BIN
docs/developers/Architektura.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
BIN
docs/developers/BattleField.png
Normal file
BIN
docs/developers/BattleField.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 135 KiB |
140
docs/developers/Bonus system.md
Normal file
140
docs/developers/Bonus system.md
Normal file
@@ -0,0 +1,140 @@
|
||||
The bonus system of VCMI is a set of mechanisms that make handling of
|
||||
different bonuses for heroes, towns, players and units easier. The
|
||||
system consists of a set of nodes representing objects that can be a
|
||||
source or a subject of a bonus and two directed acyclic graphs (DAGs)
|
||||
representing inheritance and propagation of bonuses. Core of bonus
|
||||
system is defined in HeroBonus.h file.
|
||||
|
||||
Here is a brief sketch of the system (black arrows indicate the
|
||||
direction of inheritance and red arrows the direction of propagation):
|
||||
|
||||
<figure>
|
||||
<img src="Bonus_system.png" title="Bonus_system.png" />
|
||||
<figcaption>Bonus_system.png</figcaption>
|
||||
</figure>
|
||||
|
||||
## Propagation and inheritance
|
||||
|
||||
Each bonus originates from some node in the bonus system, and may have
|
||||
propagator and limiter objects attached to it. Bonuses are shared around
|
||||
as follows:
|
||||
|
||||
1. Bonuses with propagator are propagated to "matching" descendants in
|
||||
the red DAG - which descendants match is determined by the
|
||||
propagator. Bonuses without a propagator will not be propagated.
|
||||
2. Bonuses without limiters are inherited by all descendants in the
|
||||
black DAG. If limiters are present, they can restrict inheritance to
|
||||
certain nodes.
|
||||
|
||||
Inheritance is the default means of sharing bonuses. A typical example
|
||||
is an artefact granting a bonus to attack/defense stat, which is
|
||||
inherited by the hero wearing it, and then by creatures in the hero's
|
||||
army.
|
||||
|
||||
A common limiter is by creature - e.g. the hero Eric has a specialty
|
||||
that grants bonuses to attack, defense and speed, but only to griffins.
|
||||
|
||||
Propagation is used when bonuses need to be shared in a different
|
||||
direction than the black DAG for inheritance. E.g. Magi and Archmagi on
|
||||
the battlefield reduce the cost of spells for the controlling hero.
|
||||
|
||||
### Technical Details
|
||||
|
||||
- Propagation is done by copying bonuses to the target nodes. This
|
||||
happens when bonuses are added.
|
||||
- Inheritance is done on-the-fly when needed, by traversing the black
|
||||
DAG. Results are cached to improve performance.
|
||||
- Whenever a node changes (e.g. bonus added), a global counter gets
|
||||
increased which is used to check whether cached results are still
|
||||
current.
|
||||
|
||||
## Operations on the graph
|
||||
|
||||
There are two basic types of operations that can be performed on the
|
||||
graph:
|
||||
|
||||
### Adding a new node
|
||||
|
||||
When node is attached to a new black parent [1], the propagation system
|
||||
is triggered and works as follows:
|
||||
|
||||
|
||||
For the attached node and its all red ancestors
|
||||
|
||||
|
||||
For every bonus
|
||||
|
||||
|
||||
Call propagator giving the new descendant -\> then attach appropriately
|
||||
bonuses to the red descendant of attached node (or the node itself).
|
||||
|
||||
E.g. when a hero equips an artifact, the hero gets attached to the
|
||||
artifact to inherit its bonuses.
|
||||
|
||||
### Deleting an existing node
|
||||
|
||||
Analogically to the adding a new node, just remove propagated bonuses
|
||||
instead of adding them. Then update the hierarchy.
|
||||
|
||||
E.g. when a hero removes an artifact, the hero (which became a child of
|
||||
the artifact when equipping it) is removed from it.
|
||||
|
||||
Note that only *propagated* bonuses need to be handled when nodes are
|
||||
added or removed. *Inheritance* is done on-the-fly and thus automatic.
|
||||
|
||||
## Limiters
|
||||
|
||||
If multiple limiters are specified for a bonus, a child inherits the
|
||||
bonus only if all limiters say that it should.
|
||||
|
||||
So e.g. a list of multiple creature type limiters (with different
|
||||
creatures) would ensure that no creature inherits the bonus. In such a
|
||||
case, the solution is to use one bonus per creature.
|
||||
|
||||
## Propagators
|
||||
|
||||
## Updaters
|
||||
|
||||
Updaters are objects attached to bonuses. They can modify a bonus
|
||||
(typically by changing *val*) during inheritance, including bonuses that
|
||||
a node "inherits" from itself, based on properties (typically level) of
|
||||
the node it passes through. Which nodes update a bonus depends on the
|
||||
type of updater. E.g. updaters that perform updates based on hero level
|
||||
will update bonuses as the are inherited by heroes.
|
||||
|
||||
The following example shows an artifact providing a bonus based on the
|
||||
level of the hero that wears it:
|
||||
|
||||
` "core:greaterGnollsFlail":`
|
||||
` {`
|
||||
` "text" : { "description" : "This mighty flail increases the attack of all gnolls under the hero's command by twice the hero's level." },`
|
||||
` "bonuses" : [`
|
||||
` {`
|
||||
` "limiters" : [`
|
||||
` {`
|
||||
` "parameters" : [ "gnoll", true ],`
|
||||
` "type" : "CREATURE_TYPE_LIMITER"`
|
||||
` }`
|
||||
` ],`
|
||||
` "subtype" : "primSkill.attack",`
|
||||
` "type" : "PRIMARY_SKILL",`
|
||||
` "val" : 2,`
|
||||
` "updater" : "TIMES_HERO_LEVEL"`
|
||||
` }`
|
||||
` ]`
|
||||
` }`
|
||||
|
||||
## Calculating the total value of a bonus
|
||||
|
||||
- [List of bonus value types](List_of_bonus_value_types "wikilink")
|
||||
|
||||
## Automatic generation of bonus description
|
||||
|
||||
TBD
|
||||
|
||||
# Notes
|
||||
|
||||
<references/>
|
||||
|
||||
[1] the only possibility -\> adding parent is the same as adding a child
|
||||
to it
|
||||
213
docs/developers/Code_structure.md
Normal file
213
docs/developers/Code_structure.md
Normal file
@@ -0,0 +1,213 @@
|
||||
The code of VCMI is divided into several main parts: client, server, lib
|
||||
and AIs, each one in a separate binary file.
|
||||
|
||||
# The big picture
|
||||
|
||||
<figure>
|
||||
<img src="Architektura.png" title="Architektura.png" />
|
||||
<figcaption>Architektura.png</figcaption>
|
||||
</figure>
|
||||
|
||||
VCMI contains three core projects: VCMI_lib (dll / so), VCMI_client
|
||||
(executable) and VCMI_server (executable). [Server](Server "wikilink")
|
||||
handles all [game mechanics](game_mechanics "wikilink") and events.
|
||||
[Client](Client "wikilink") presents [game state](game_state "wikilink")
|
||||
and events to player and collects input from him.
|
||||
|
||||
During the game, we have one (and only one) server and one or more (one
|
||||
for each player computer) clients.
|
||||
|
||||
Important: State of the game and its mechanics are synchronized between
|
||||
clients and server. All changes to the game state or mechanics must be
|
||||
done by server which will send appropriate notices to clients.
|
||||
|
||||
## Game state
|
||||
|
||||
It's basically CGameState class object and everything that's accessible
|
||||
from it: map (with objects), player statuses, game options, etc.
|
||||
|
||||
## Bonus system
|
||||
|
||||
One of the more important pieces of VCMI is the [bonus
|
||||
system](bonus_system "wikilink"). It's described in a separate article.
|
||||
|
||||
## Configuration
|
||||
|
||||
Most of VCMI configuration files uses Json format and located in
|
||||
"config" directory
|
||||
|
||||
### [Json parser and writer](Json_parser_and_writer "wikilink")
|
||||
|
||||
# Client
|
||||
|
||||
## Main purposes of client
|
||||
|
||||
[Client](Client "wikilink") is responsible for:
|
||||
|
||||
- displaying state of game to human player
|
||||
- capturing player's actions and sending requests to server
|
||||
- displaying changes in state of game indicated by server
|
||||
|
||||
## Rendering of graphics
|
||||
|
||||
Rendering of graphics relies heavily on SDL. Currently we do not have
|
||||
any wrapper for SDL internal structures and most of rendering is about
|
||||
blitting surfaces using SDL_BlitSurface. We have a few function that
|
||||
make rendering easier or make specific parts of rendering (like printing
|
||||
text). They are places in client/SDL_Extensions and client/SDL_Framerate
|
||||
(the second one contains code responsible for keeping appropriate
|
||||
framerate, it should work more smart than just SDL_Delay(miliseconds)).
|
||||
In rendering, Interface object system is quite helpful. Its base is
|
||||
CIntObject class that is basically a base class for our library of GUI
|
||||
components and other objects.
|
||||
|
||||
### Video player
|
||||
|
||||
Located in client/VideoHandler.cpp/.h, have several platform-specific
|
||||
versions:
|
||||
|
||||
- For 32-bit Windows - using original 32-bit libraries (binkw32.dll,
|
||||
smackw32.dll)
|
||||
- For \*nix systems - using ffmpeg libraries.
|
||||
- Empty player for 64-bit Windows
|
||||
|
||||
### [Primitive controls](Primitive_controls "wikilink")
|
||||
|
||||
## [Adventure map interface](Adventure_map_interface "wikilink")
|
||||
|
||||
TBD
|
||||
|
||||
## [Town interface](Town_interface "wikilink")
|
||||
|
||||
TBD
|
||||
|
||||
## [Battle interface](Battle_interface "wikilink")
|
||||
|
||||
# Server
|
||||
|
||||
## Main purposes of server
|
||||
|
||||
[Server](Server "wikilink") is responsible for:
|
||||
|
||||
- maintaining state of the game
|
||||
- handling requests from all clients participating in game
|
||||
- informing all clients about changes in state of the game that are
|
||||
visible to them
|
||||
|
||||
# Lib
|
||||
|
||||
## Main purposes of lib
|
||||
|
||||
VCMI_Lib is a library that contains code common to server and client, so
|
||||
we avoid it's duplication. Important: the library code is common for
|
||||
client and server and used by them, but the library instance (in
|
||||
opposition to the library as file) is not shared by them! Both client
|
||||
and server create their own "copies" of lib with all its class
|
||||
instances.
|
||||
|
||||
iOS platform pioneered single process build, where server is a static
|
||||
library and not a dedicated executable. For that to work, the lib had to
|
||||
be wrapped into special namespace that is defined by client and server
|
||||
targets on iOS, so that single process is able to contain 2 versions of
|
||||
the library. To make it more convenient, a few macros were introduced
|
||||
that can be found in
|
||||
[Global.h](https://github.com/vcmi/vcmi/blob/develop/Global.h). The most
|
||||
important ones are `VCMI_LIB_NAMESPACE_BEGIN` and
|
||||
`VCMI_LIB_NAMESPACE_END` which must be used anywhere a symbol from the
|
||||
lib is needed, otherwise building iOS (or any other platform that would
|
||||
use single process approach) fails. See [#Wrapped namespace
|
||||
examples](#Wrapped_namespace_examples "wikilink").
|
||||
|
||||
[Lib](Lib "wikilink") contains code responsible for:
|
||||
|
||||
- handling most of Heroes III files (.lod, .txt setting files)
|
||||
- storing information common to server and client like state of the
|
||||
game
|
||||
- managing armies, buildings, artifacts, spells, bonuses and other
|
||||
game objects
|
||||
- handling general game mechanics and related actions (only adventure
|
||||
map objects; it's an unwanted remnant of past development - all game
|
||||
mechanics should be handled by the server)
|
||||
- networking and serialization
|
||||
|
||||
### [Serialization](Serialization "wikilink")
|
||||
|
||||
The serialization framework can serialize basic types, several standard
|
||||
containers among smart pointers and custom objects. Its design is based
|
||||
on the [boost serialization
|
||||
libraries](http://www.boost.org/doc/libs/1_52_0/libs/serialization/doc/index.html).
|
||||
In addition to the basic functionality it provides light-weight transfer
|
||||
of CGObjectInstance objects by sending only the index/id.
|
||||
|
||||
See the [Serialization](Serialization "wikilink") page for all the
|
||||
details.
|
||||
|
||||
### Wrapped namespace examples
|
||||
|
||||
#### Inside the lib
|
||||
|
||||
Both header and implementation of a new class inside the lib should have
|
||||
the following structure:
|
||||
|
||||
`<includes>`
|
||||
`VCMI_LIB_NAMESPACE_BEGIN`
|
||||
`<code>`
|
||||
`VCMI_LIB_NAMESPACE_END`
|
||||
|
||||
Example:
|
||||
[header](https://github.com/vcmi/vcmi/blob/develop/lib/CBuildingHandler.h)
|
||||
and
|
||||
[implementation](https://github.com/vcmi/vcmi/blob/develop/lib/CBuildingHandler.cpp)
|
||||
|
||||
#### Headers outside the lib
|
||||
|
||||
Forward declarations of the lib in headers of other parts of the project
|
||||
need to be wrapped in the macros:
|
||||
|
||||
`<includes>`
|
||||
`VCMI_LIB_NAMESPACE_BEGIN`
|
||||
`<lib forward declarations>`
|
||||
`VCMI_LIB_NAMESPACE_END`
|
||||
`<other forward declarations>`
|
||||
`<classes>`
|
||||
|
||||
Example:
|
||||
<https://github.com/vcmi/vcmi/blob/develop/server/CGameHandler.h>
|
||||
|
||||
#### New project part
|
||||
|
||||
If you're creating new project part, place `VCMI_LIB_USING_NAMESPACE` in
|
||||
its `StdInc.h` to be able to use lib classes without explicit namespace
|
||||
in implementation files. Example:
|
||||
<https://github.com/vcmi/vcmi/blob/develop/launcher/StdInc.h>
|
||||
|
||||
# [Artificial Intelligence](Artificial_Intelligence "wikilink") (AI)
|
||||
|
||||
## [StupidAI](StupidAI "wikilink")
|
||||
|
||||
Stupid AI is recent and used battle AI.
|
||||
|
||||
## [Adventure AI](Adventure_AI "wikilink")
|
||||
|
||||
VCAI module is currently developed agent-based system driven by goals
|
||||
and heroes.
|
||||
|
||||
## [Programming challenge](Programming_challenge "wikilink")
|
||||
|
||||
## [Fuzzy logic](Fuzzy_logic "wikilink")
|
||||
|
||||
VCMI includes [FuzzyLite](http://code.google.com/p/fuzzy-lite/) library
|
||||
to make use of fuzzy rule-based algorithms. They are useful to handle
|
||||
uncertanity and resemble human behaviour who takes decisions based on
|
||||
rough observations. FuzzyLite is linked as separate static library in
|
||||
AI/FuzzyLite.lib file.
|
||||
|
||||
# [Utilities](Utilities "wikilink")
|
||||
|
||||
## [Launcher](Launcher "wikilink")
|
||||
|
||||
## [Duels](Duels "wikilink")
|
||||
|
||||
[Mod system proposal](Mod_system_proposal "wikilink")
|
||||
|
||||
## [ERM parser](ERM_parser "wikilink")
|
||||
972
docs/developers/Coding Guidelines.md
Normal file
972
docs/developers/Coding Guidelines.md
Normal file
@@ -0,0 +1,972 @@
|
||||
## C++ Standard
|
||||
|
||||
VCMI implementation bases on C++14 standard. Any feature is acceptable
|
||||
as long as it's will pass build on our CI, but there is list below on
|
||||
what is already being used.
|
||||
|
||||
Any compiler supporting C++14 should work, but this has not been
|
||||
thoroughly tested. You can find information about extensions and
|
||||
compiler support at
|
||||
[1](http://en.cppreference.com/w/cpp/compiler_support).
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
In order to keep the code consistent, please use the following
|
||||
conventions. From here on \`good' and \`bad' are used to attribute
|
||||
things that would make the coding style match, or not match. It is not a
|
||||
judgment call on your coding abilities, but more of a style and look
|
||||
call. Please try to follow these guidelines to ensure prettiness.
|
||||
|
||||
### Indentation
|
||||
|
||||
Use tabs for indentation. If you are modifying someone else's code, try
|
||||
to keep the coding style similar.
|
||||
|
||||
### Where to put braces
|
||||
|
||||
Inside a code block put the opening brace on the next line after the
|
||||
current statement:
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
{
|
||||
code();
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if(a) {
|
||||
code();
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Avoid using unnecessary open/close braces, vertical space is usually
|
||||
limited:
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
code();
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if(a) {
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Unless there are either multiple hierarchical conditions being used or
|
||||
that the condition cannot fit into a single line.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
{
|
||||
if(b)
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
if(b)
|
||||
code();
|
||||
```
|
||||
|
||||
If there are brackets inside the body, outside brackets are required.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
{
|
||||
for(auto elem : list)
|
||||
{
|
||||
code();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
for(auto elem : list)
|
||||
{
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
If "else" branch has brackets then "if" should also have brackets even
|
||||
if it is one line.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
{
|
||||
code();
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto elem : list)
|
||||
{
|
||||
code();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
code();
|
||||
else
|
||||
{
|
||||
for(auto elem : list)
|
||||
{
|
||||
code();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you intentionally want to avoid usage of "else if" and keep if body
|
||||
indent make sure to use braces.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
{
|
||||
code();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(b)
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
code();
|
||||
else
|
||||
if(b)
|
||||
code();
|
||||
```
|
||||
|
||||
When defining a method, use a new line for the brace, like this:
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
void method()
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
void Method() {
|
||||
}
|
||||
```
|
||||
|
||||
### Use whitespace for clarity
|
||||
|
||||
Use white space in expressions liberally, except in the presence of
|
||||
parenthesis.
|
||||
|
||||
**Good:**
|
||||
|
||||
``` cpp
|
||||
if(a + 5 > method(blah('a') + 4))
|
||||
foo += 24;
|
||||
```
|
||||
|
||||
**Bad:**
|
||||
|
||||
``` cpp
|
||||
if(a+5>method(blah('a')+4))
|
||||
foo+=24;
|
||||
```
|
||||
|
||||
Between if, for, while,.. and the opening brace there shouldn't be a
|
||||
whitespace. The keywords are highlighted, so they don't need further
|
||||
separation.
|
||||
|
||||
### Where to put spaces
|
||||
|
||||
Use a space before and after the address or pointer character in a
|
||||
pointer declaration.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
CIntObject * images[100];
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
CIntObject* images[100]; or
|
||||
CIntObject *images[100];
|
||||
```
|
||||
|
||||
Do not use spaces before parentheses.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
code();
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if (a)
|
||||
code();
|
||||
```
|
||||
|
||||
Do not use extra spaces around conditions inside parentheses.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a && b)
|
||||
code();
|
||||
|
||||
if(a && (b || c))
|
||||
code();
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if( a && b )
|
||||
code();
|
||||
|
||||
if(a && ( b || c ))
|
||||
code();
|
||||
```
|
||||
|
||||
Do not use more than one space between operators.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if((a && b) || (c + 1 == d))
|
||||
code();
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if((a && b) || (c + 1 == d))
|
||||
code();
|
||||
|
||||
if((a && b) || (c + 1 == d))
|
||||
code();
|
||||
```
|
||||
|
||||
### Where to use parentheses
|
||||
|
||||
When allocating objects, don't use parentheses for creating stack-based
|
||||
objects by zero param c-tors to avoid c++ most vexing parse and use
|
||||
parentheses for creating heap-based objects.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
std::vector<int> v;
|
||||
CGBoat btn = new CGBoat();
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
std::vector<int> v(); // shouldn't compile anyway
|
||||
CGBoat btn = new CGBoat;
|
||||
```
|
||||
|
||||
Avoid overuse of parentheses:
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a && (b + 1))
|
||||
return c == d;
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if((a && (b + 1)))
|
||||
return (c == d);
|
||||
```
|
||||
|
||||
### Class declaration
|
||||
|
||||
Base class list must be on same line with class name.
|
||||
|
||||
``` cpp
|
||||
class CClass : public CClassBaseOne, public CClassBaseOne
|
||||
{
|
||||
int id;
|
||||
bool parameter;
|
||||
|
||||
public:
|
||||
CClass();
|
||||
~CClass();
|
||||
};
|
||||
```
|
||||
|
||||
When 'private:', 'public:' and other labels are not on the line after
|
||||
opening brackets there must be a new line before them.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
class CClass
|
||||
{
|
||||
int id;
|
||||
|
||||
public:
|
||||
CClass();
|
||||
};
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
class CClass
|
||||
{
|
||||
int id;
|
||||
public:
|
||||
CClass();
|
||||
};
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
class CClass
|
||||
{
|
||||
protected:
|
||||
int id;
|
||||
|
||||
public:
|
||||
CClass();
|
||||
};
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
class CClass
|
||||
{
|
||||
|
||||
protected:
|
||||
int id;
|
||||
|
||||
public:
|
||||
CClass();
|
||||
};
|
||||
```
|
||||
|
||||
### Constructor base class and member initialization
|
||||
|
||||
Constructor member and base class initialization must be on new line,
|
||||
indented with tab with leading colon.
|
||||
|
||||
``` cpp
|
||||
CClass::CClass()
|
||||
: CClassBaseOne(true, nullptr), id(0), bool parameters(false)
|
||||
{
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
### Switch statement
|
||||
|
||||
Switch statements have the case at the same indentation as the switch.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
switch(alignment)
|
||||
{
|
||||
case EAlignment::EVIL:
|
||||
do_that();
|
||||
break;
|
||||
case EAlignment::GOOD:
|
||||
do_that();
|
||||
break;
|
||||
case EAlignment::NEUTRAL:
|
||||
do_that();
|
||||
break;
|
||||
default:
|
||||
do_that();
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
switch(alignment)
|
||||
{
|
||||
case EAlignment::EVIL:
|
||||
do_that();
|
||||
break;
|
||||
default:
|
||||
do_that();
|
||||
break;
|
||||
}
|
||||
|
||||
switch(alignment)
|
||||
{
|
||||
case EAlignment::EVIL:
|
||||
do_that();
|
||||
break;
|
||||
default:
|
||||
do_that();
|
||||
break;
|
||||
}
|
||||
|
||||
switch(alignment)
|
||||
{
|
||||
case EAlignment::EVIL:
|
||||
{
|
||||
do_that();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
do_that();
|
||||
}
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
### Lambda expressions
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
auto lambda = [this, a, &b](int3 & tile, int index) -> bool
|
||||
{
|
||||
do_that();
|
||||
};
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
auto lambda = [this,a,&b](int3 & tile, int index)->bool{do_that();};
|
||||
```
|
||||
|
||||
Empty parameter list is required even if function takes no arguments.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
auto lambda = []()
|
||||
{
|
||||
do_that();
|
||||
};
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
auto lambda = []
|
||||
{
|
||||
do_that();
|
||||
};
|
||||
```
|
||||
|
||||
Do not use inline lambda expressions inside if-else, for and other
|
||||
conditions.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
auto lambda = []()
|
||||
{
|
||||
do_that();
|
||||
};
|
||||
if(lambda)
|
||||
{
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if([]()
|
||||
{
|
||||
do_that();
|
||||
})
|
||||
{
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Do not pass inline lambda expressions as parameter unless it's the last
|
||||
parameter.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
auto lambda = []()
|
||||
{
|
||||
do_that();
|
||||
};
|
||||
obj->someMethod(lambda, true);
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
obj->someMethod([]()
|
||||
{
|
||||
do_that();
|
||||
}, true);
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
obj->someMethod(true, []()
|
||||
{
|
||||
do_that();
|
||||
});
|
||||
```
|
||||
|
||||
### Serialization
|
||||
|
||||
Serialization of each element must be on it's own line since this make
|
||||
debugging easier.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & identifier;
|
||||
h & description;
|
||||
h & name;
|
||||
h & dependencies;
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & identifier & description & name & dependencies;
|
||||
}
|
||||
```
|
||||
|
||||
Save backward compatibility code is exception when extra brackets are
|
||||
always useful.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & identifier;
|
||||
h & description;
|
||||
if(version >= 123)
|
||||
{
|
||||
h & totalValue;
|
||||
}
|
||||
else if(!h.saving)
|
||||
{
|
||||
totalValue = 200;
|
||||
}
|
||||
h & name;
|
||||
h & dependencies;
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & identifier;
|
||||
h & description;
|
||||
if(version >= 123)
|
||||
h & totalValue;
|
||||
else if(!h.saving)
|
||||
totalValue = 200;
|
||||
h & name;
|
||||
h & dependencies;
|
||||
}
|
||||
```
|
||||
|
||||
### File headers
|
||||
|
||||
For any new files, please paste the following info block at the very top
|
||||
of the source file:
|
||||
|
||||
``` cpp
|
||||
/*
|
||||
* Name_of_File.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
```
|
||||
|
||||
The above notice have to be included both in header and source files
|
||||
(.h/.cpp).
|
||||
|
||||
### Code order in files
|
||||
|
||||
For any header or source file code must be in following order:
|
||||
|
||||
1. Licensing information
|
||||
2. pragma once preprocessor directive
|
||||
3. include directives
|
||||
4. Forward declarations
|
||||
5. All other code
|
||||
|
||||
``` cpp
|
||||
/*
|
||||
* Name_of_File.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Header.h"
|
||||
|
||||
class CGObjectInstance;
|
||||
struct CPackForClient;
|
||||
```
|
||||
|
||||
### Where and how to comment
|
||||
|
||||
If you comment on the same line with code there must be one single space
|
||||
between code and slashes.
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
{
|
||||
code(); //Do something
|
||||
}
|
||||
else // Do something.
|
||||
{
|
||||
code(); // Do something.
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if(a)
|
||||
{
|
||||
code();//Do something
|
||||
}
|
||||
else // Do something.
|
||||
{
|
||||
code(); // TODO:
|
||||
}
|
||||
```
|
||||
|
||||
If you add single-line comment on own line slashes must have same indent
|
||||
as code around:
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
// Do something
|
||||
if(a)
|
||||
{
|
||||
//Do something
|
||||
for(auto item : list)
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
// Do something
|
||||
if(a)
|
||||
{
|
||||
//Do something
|
||||
for(auto item : list)
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Avoid comments inside multi-line if-else conditions. If your conditions
|
||||
are too hard to understand without additional comments this usually
|
||||
means that code need refactoring. Example given below is need
|
||||
improvement though. **FIXME**
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
bool isMyHeroAlive = a && b || (c + 1 > 15);
|
||||
bool canMyHeroMove = myTurn && hero.movePoints > 0;
|
||||
if(isMyHeroAlive && canMyHeroMove)
|
||||
{
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
if((a && b || (c + 1 > 15)) //Check if hero still alive
|
||||
&& myTurn && hero.movePoints > 0) //Check if hero can move
|
||||
{
|
||||
code();
|
||||
}
|
||||
```
|
||||
|
||||
You should write a comment before the class definition which describes
|
||||
shortly the class. 1-2 sentences are enough. Methods and class data
|
||||
members should be commented if they aren't self-describing only.
|
||||
Getters/Setters, simple methods where the purpose is clear or similar
|
||||
methods shouldn't be commented, because vertical space is usually
|
||||
limited. The style of documentation comments should be the three
|
||||
slashes-style: ///.
|
||||
|
||||
``` cpp
|
||||
/// Returns true if a debug/trace log message will be logged, false if not.
|
||||
/// Useful if performance is important and concatenating the log message is a expensive task.
|
||||
bool isDebugEnabled() const;
|
||||
bool isTraceEnabled() const;
|
||||
```
|
||||
|
||||
The above example doesn't follow a strict scheme on how to comment a
|
||||
method. It describes two methods in one go. Comments should be kept
|
||||
short.
|
||||
|
||||
If you need a more detailed description for a method you can use such
|
||||
style:
|
||||
|
||||
``` cpp
|
||||
/// <A short one line description>
|
||||
///
|
||||
/// <Longer description>
|
||||
/// <May span multiple lines or paragraphs as needed>
|
||||
///
|
||||
/// @param Description of method's or function's input parameter
|
||||
/// @param ...
|
||||
/// @return Description of the return value
|
||||
```
|
||||
|
||||
A good essay about writing comments:
|
||||
[2](http://ardalis.com/when-to-comment-your-code)
|
||||
|
||||
### Casing
|
||||
|
||||
Local variables and methods start with a lowercase letter and use the
|
||||
camel casing. Classes/Structs start with an uppercase letter and use the
|
||||
camel casing as well. Macros and constants are written uppercase.
|
||||
|
||||
### Line length
|
||||
|
||||
The line length for c++ source code is 120 columns. If your function
|
||||
declaration arguments go beyond this point, please align your arguments
|
||||
to match the opening brace. For best results use the same number of tabs
|
||||
used on the first line followed by enough spaces to align the arguments.
|
||||
|
||||
### Warnings
|
||||
|
||||
Avoid use of #pragma to disable warnings. Compile at warning level 3.
|
||||
Avoid commiting code with new warnings.
|
||||
|
||||
### File/directory naming
|
||||
|
||||
Compilation units(.cpp,.h files) start with a uppercase letter and are
|
||||
named like the name of a class which resides in that file if possible.
|
||||
Header only files start with a uppercase letter. JSON files start with a
|
||||
lowercase letter and use the camel casing.
|
||||
|
||||
Directories start with a lowercase letter and use the camel casing where
|
||||
necessary.
|
||||
|
||||
### Logging
|
||||
|
||||
Outdated. There is separate entry for [Logging
|
||||
API](Logging_API "wikilink")
|
||||
|
||||
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:
|
||||
|
||||
``` cpp
|
||||
LOG_TRACE_PARAMS(logGlobal, "hero '%s', spellId '%d', pos '%s'.", hero, spellId, pos);
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
`{BattleAction: side '0', stackNumber '1', actionType 'Walk and attack', destinationTile '{BattleHex: x '7', y '1', hex '24'}', additionalInfo '7', selectedStack '-1'}`
|
||||
|
||||
The name of the type should be logged first, e.g. {TYPE_NAME:
|
||||
members...}. The members of the object will be logged like logging trace
|
||||
parameters. Collection types (vector, list, ...) should be logged this
|
||||
way: \[{BattleHex: ...}, {...}\] There is no format which has to be
|
||||
followed strictly, so if there is a reason to format members/objects in
|
||||
a different way, then this is ok.
|
||||
|
||||
## Best practices
|
||||
|
||||
### Avoid code duplication
|
||||
|
||||
Avoid code duplication or don't repeat yourself(DRY) is the most
|
||||
important aspect in programming. Code duplication of any kind can lead
|
||||
to inconsistency and is much harder to maintain. If one part of the
|
||||
system gets changed you have to change the code in several places. This
|
||||
process is error-prone and leads often to problems. Here you can read
|
||||
more about the DRY principle:
|
||||
[<http://en.wikipedia.org/wiki/Don%27t_repeat_yourself>](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
|
||||
|
||||
### Do not use uncommon abbrevations
|
||||
|
||||
Do not use uncommon abbrevations for class, method, parameter and global
|
||||
object names.
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
CArt * getRandomArt(...)
|
||||
class CIntObject
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
CArtifact * getRandomArtifact(...)
|
||||
class CInterfaceObject
|
||||
```
|
||||
|
||||
### Loop handling
|
||||
|
||||
Use range-based for loops. It should be used in any case except you
|
||||
absolutely need iterator, then you may use a simple for loop.
|
||||
|
||||
The loop counter should be of type int, unless you are sure you won't
|
||||
need negative indices -- then use size_t.
|
||||
|
||||
### Include guards
|
||||
|
||||
Use #pragma once instead of the traditional #ifndef/#define/#endif
|
||||
include guards.
|
||||
|
||||
### Pre compiled header file
|
||||
|
||||
The header StdInc.h should be included in every compilation unit. It has
|
||||
to be included before any C macro and before any c++ statements. Pre
|
||||
compiled header should not be changed, except any important thing is
|
||||
missing. The StdInc includes most Boost libraries and nearly all
|
||||
standard STL and C libraries, so you don’t have to include them by
|
||||
yourself.
|
||||
|
||||
### Enumeration handling
|
||||
|
||||
Do not declare enumerations in global namespace. It is better to use
|
||||
strongly typed enum or to wrap them in class or namespace to avoid
|
||||
polluting global namespace:
|
||||
|
||||
``` cpp
|
||||
enum class EAlignment
|
||||
{
|
||||
GOOD,
|
||||
EVIL,
|
||||
NEUTRAL
|
||||
};
|
||||
|
||||
namespace EAlignment
|
||||
{
|
||||
enum EAlignment
|
||||
{
|
||||
GOOD, EVIL, NEUTRAL
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Avoid senseless comments
|
||||
|
||||
If the comment duplicates the name of commented member, it's better if
|
||||
it wouldn't exist at all. It just increases maintenance cost. Bad:
|
||||
|
||||
``` cpp
|
||||
size_t getHeroesCount(); //gets count of heroes (surprise?)
|
||||
```
|
||||
|
||||
### Class handling
|
||||
|
||||
There is no definitive rule which has to be followed strictly. You can
|
||||
freely decide if you want to pack your own classes, where you are
|
||||
programming on, all in one file or each in one file. It's more important
|
||||
that you feel comfortable with the code, than consistency overall the
|
||||
project. VCMI has several container class files, so if you got one
|
||||
additional class to them than just add it to them instead of adding new
|
||||
files.
|
||||
|
||||
### Functions and interfaces
|
||||
|
||||
Don't return const objects or primitive types from functions -- it's
|
||||
pointless. Also, don't return pointers to non-const game data objects
|
||||
from callbacks to player interfaces.
|
||||
|
||||
Bad:
|
||||
|
||||
``` cpp
|
||||
const std::vector<CGObjectInstance *> guardingCreatures(int3 pos) const;
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
``` cpp
|
||||
std::vector<const CGObjectInstance *> guardingCreatures(int3 pos) const;
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
[Mono project coding
|
||||
guidelines](http://www.mono-project.com/Coding_Guidelines)
|
||||
49
docs/developers/Development_with_Qt_Creator.md
Normal file
49
docs/developers/Development_with_Qt_Creator.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Introduction to Qt Creator
|
||||
|
||||
Qt Creator is the recommended IDE for VCMI development on Linux
|
||||
distributions, but it may be used on other operating systems as well. It
|
||||
has the following advantages compared to other IDEs:
|
||||
|
||||
- Fast parser/indexer, stable.
|
||||
- Almost no manual configuration when used with CMake. Project
|
||||
configuration is read from CMake text files,
|
||||
- Easy to setup and use with multiple different compiler toolchains:
|
||||
GCC, Visual Studio, Clang
|
||||
|
||||
You can install Qt Creator from repository, but better to stick to
|
||||
latest version from Qt website:
|
||||
<https://www.qt.io/download-open-source/>
|
||||
|
||||
## Configuration
|
||||
|
||||
To open the project you have to click File -\> Open file or project...
|
||||
-\> Select /path/to/vcmi/src/CMakeLists.txt.
|
||||
|
||||
For the first time and for every CMake project configuration change you
|
||||
have to execute CMake. This step can be done when opening the project
|
||||
for the first time or alternatively via the left bar -\> Projects -\>
|
||||
Build Settings -\> Execute CMake. You have to specify CMake arguments
|
||||
and the build dir. CMake arguments can be the following:
|
||||
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
The build dir should be set to something like /trunk/build for the debug
|
||||
build and /trunk/buildrel for the release build. For cleaning the build
|
||||
dir a command like "make clean" may be not enough. Better way is to
|
||||
delete the build dir, re-create it and re-execute CMake. Steps for
|
||||
cleaning can be configured in the Projects tab as well.
|
||||
|
||||
## Debugging
|
||||
|
||||
There is a problem with QtCreator when debugging both vcmiclient and
|
||||
vcmiserver. If you debug the vcmiclient, start a game, attach the
|
||||
vcmiserver process to the gdb debugger(Debug \> Start Debugging \>
|
||||
Attach to Running External Application...) then breakpoints which are
|
||||
set for vcmiserver will be ignored. This looks like a bug, in any case
|
||||
it's not intuitively. Two workarounds are available luckily:
|
||||
|
||||
1\) Run vcmiclient (no debug mode), then attach server process to the
|
||||
debugger
|
||||
|
||||
2\) Open two instances of QtCreator and debug vcmiserver and vcmiclient
|
||||
separately(it works!)
|
||||
117
docs/developers/How to build VCMI (Android).md
Normal file
117
docs/developers/How to build VCMI (Android).md
Normal file
@@ -0,0 +1,117 @@
|
||||
The following instructions apply to **v1.2 and later**. For earlier
|
||||
versions the best documentation is
|
||||
<https://github.com/vcmi/vcmi-android/blob/master/building.txt> (and
|
||||
reading scripts in that repo), however very limited to no support will
|
||||
be provided from our side if you wish to go down that rabbit hole.
|
||||
|
||||
*Note*: building has been tested only on Linux and macOS. It may or may
|
||||
not work on Windows out of the box.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. CMake 3.20+: download from your package manager or from
|
||||
<https://cmake.org/download/>
|
||||
2. JDK 11, not necessarily from Oracle
|
||||
3. Android command line tools or Android Studio for your OS:
|
||||
<https://developer.android.com/studio/>
|
||||
4. Android NDK version **r25c (25.2.9519653)**, there're multiple ways
|
||||
to obtain it:
|
||||
- install with Android Studio
|
||||
- install with `sdkmanager` command line tool
|
||||
- download from <https://developer.android.com/ndk/downloads>
|
||||
- download with Conan, see [#NDK and
|
||||
Conan](#NDK_and_Conan "wikilink")
|
||||
5. (optional) Ninja: download from your package manager or from
|
||||
<https://github.com/ninja-build/ninja/releases>
|
||||
|
||||
## Obtaining source code
|
||||
|
||||
Clone <https://github.com/vcmi/vcmi> with submodules. Example for
|
||||
command line:
|
||||
|
||||
`git clone --recurse-submodules https://github.com/vcmi/vcmi.git`
|
||||
|
||||
## Obtaining dependencies
|
||||
|
||||
We use Conan package manager to build/consume dependencies, find
|
||||
detailed usage instructions
|
||||
[here](https://github.com/vcmi/vcmi/tree/develop/docs/conan.md). Note
|
||||
that the link points to the cutting-edge state in `develop` branch, for
|
||||
the latest release check the same document in the [master
|
||||
branch](https://github.com/vcmi/vcmi/tree/master/docs/conan.md).
|
||||
|
||||
On the step where you need to replace **PROFILE**, choose:
|
||||
|
||||
- `android-32` to build for 32-bit architecture (armeabi-v7a)
|
||||
- `android-64` to build for 64-bit architecture (aarch64-v8a)
|
||||
|
||||
### NDK and Conan
|
||||
|
||||
Conan must be aware of the NDK location when you execute
|
||||
`conan install`. There're multiple ways to achieve that as written in
|
||||
the [Conan
|
||||
docs](https://docs.conan.io/1/integrations/cross_platform/android.html):
|
||||
|
||||
- the easiest is to download NDK from Conan (option 1 in the docs),
|
||||
then all the magic happens automatically. You need to create your
|
||||
own Conan profile that imports our Android profile and adds 2 new
|
||||
lines (you can of course just copy everything from our profile into
|
||||
yours without including) and then pass this new profile to
|
||||
`conan install`:
|
||||
|
||||
`include(/path/to/vcmi/CI/conan/android-64)`
|
||||
`[tool_requires]`
|
||||
`android-ndk/r25c`
|
||||
|
||||
- to use an already installed NDK, you can simply pass it on the
|
||||
command line to `conan install`:
|
||||
|
||||
`conan install -c tools.android:ndk_path=/path/to/ndk ...`
|
||||
|
||||
## Build process
|
||||
|
||||
Building for Android is a 2-step process. First, native C++ code is
|
||||
compiled to a shared library (unlike executable on other platforms),
|
||||
then Java code is compiled to an actual executable which will be loading
|
||||
the native shared library at runtime.
|
||||
|
||||
### C++ code
|
||||
|
||||
This is a traditional CMake project, you can build it from command line
|
||||
or some IDE. You're not required to pass any custom options (except
|
||||
Conan toolchain file), defaults are already good. If you wish to use
|
||||
your own CMake presets, inherit them from our `build-with-conan` preset.
|
||||
Example:
|
||||
|
||||
`cmake -S . -B ../build -G Ninja -D CMAKE_BUILD_TYPE=Debug --toolchain ...`
|
||||
`cmake --build ../build`
|
||||
|
||||
You can also see a more detailed walkthrough on CMake configuration at
|
||||
[How to build VCMI (macOS)#Configuring project for
|
||||
building](How_to_build_VCMI_(macOS)#Configuring_project_for_building "wikilink").
|
||||
|
||||
### Java code
|
||||
|
||||
After the C++ part is built, native shared libraries are copied to the
|
||||
appropriate location of the Java project (they will be packaged in the
|
||||
APK). You can either open the Java project located in `android`
|
||||
directory of the repo in Android studio and work with it as with any
|
||||
Android project or build from command line.
|
||||
|
||||
Example how to build from command line in Bash shell, assumes that
|
||||
current working directory is VCMI repository:
|
||||
|
||||
`# the following environment variables must be set`
|
||||
`export JAVA_HOME=/path/to/jdk11`
|
||||
`export ANDROID_HOME=/path/to/android/sdk`
|
||||
``
|
||||
`cd android`
|
||||
`./gradlew assembleDebug`
|
||||
|
||||
APK will appear in `android/vcmi-app/build/outputs/apk/debug` directory
|
||||
which you can then install to your device with
|
||||
`adb install -r /path/to/apk` (adb command is from Android command line
|
||||
tools).
|
||||
|
||||
If you wish to build and install to your device in single action, use
|
||||
`installDebug` instead of `assembleDebug`.
|
||||
217
docs/developers/How to build VCMI (Linux).md
Normal file
217
docs/developers/How to build VCMI (Linux).md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Compiling VCMI
|
||||
|
||||
- Current baseline requirement for building is Ubuntu 20.04
|
||||
- Supported C++ compilers for UNIX-like systems are GCC 5.5+ and Clang
|
||||
13+
|
||||
|
||||
Older distributions and compilers might work, but they aren't tested by
|
||||
[Travis CI](https://travis-ci.org/vcmi/vcmi/)
|
||||
|
||||
# Installing dependencies
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To compile, the following packages (and their development counterparts)
|
||||
are needed to build:
|
||||
|
||||
- CMake 3.10 or newer
|
||||
- SDL2 with devel packages: mixer, image, ttf
|
||||
- zlib and zlib-devel
|
||||
- Recommended, if you want to build launcher or map editor: Qt 5,
|
||||
widget and network modules
|
||||
- Recommended, FFmpeg libraries, if you want to watch in-game videos:
|
||||
libavformat and libswscale. Their name could be libavformat-devel
|
||||
and libswscale-devel, or ffmpeg-libs-devel or similar names.
|
||||
- Boost C++ libraries v1.48+: program-options, filesystem, system,
|
||||
thread, locale
|
||||
- Optional, if you want to build scripting modules: LuaJIT
|
||||
|
||||
## On Debian-based systems (e.g. Ubuntu)
|
||||
|
||||
For Ubuntu 22.04 (jammy) or newer you need to install this list of
|
||||
packages, including **libtbb2-dev**:
|
||||
|
||||
sudo apt-get install cmake g++ libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev qtbase5-dev libtbb2-dev libluajit-5.1-dev qttools5-dev
|
||||
|
||||
For Ubuntu 21.10 (impish) or older and all versions of Debian (9
|
||||
stretch - 11 bullseye) you need to install this list of packages,
|
||||
including **libtbb-dev**:
|
||||
|
||||
sudo apt-get install cmake g++ libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev qtbase5-dev libtbb-dev libluajit-5.1-dev qttools5-dev
|
||||
|
||||
Alternatively if you have VCMI installed from repository or PPA you can
|
||||
use:
|
||||
|
||||
sudo apt-get build-dep vcmi
|
||||
|
||||
## On RPM-based distributions (e.g. Fedora)
|
||||
|
||||
sudo yum install cmake gcc-c++ SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale zlib-devel ffmpeg-devel ffmpeg-libs qt5-qtbase-devel tbb-devel luajit-devel fuzzylite-devel
|
||||
|
||||
## On Arch-based distributions
|
||||
|
||||
On Arch-based distributions, there is a development package available
|
||||
for VCMI on the AUR.
|
||||
|
||||
It can be found at: <https://aur.archlinux.org/packages/vcmi-git/>
|
||||
|
||||
Information about building packages from the Arch User Repository (AUR)
|
||||
can be found at the Arch wiki.
|
||||
|
||||
## Manual Installation
|
||||
|
||||
For older OS versions the latest prerequisite packages may not be
|
||||
readily available via the system installer. Some brief instructions for
|
||||
manual install are given below (tested on Ubuntu 14.04, update version
|
||||
numbers as desired).
|
||||
|
||||
- CMake (see also
|
||||
<https://askubuntu.com/questions/355565/how-do-i-install-the-latest-version-of-cmake-from-the-command-line/865294>)
|
||||
|
||||
<!-- -->
|
||||
|
||||
wget https://cmake.org/files/v3.11/cmake-3.11.0.tar.gz
|
||||
tar xfz cmake-3.11.0.tar.gz
|
||||
cd cmake-3.11.0
|
||||
./bootstrap
|
||||
make -j2
|
||||
sudo checkinstall --pkgname cmake --pkgversion 3.11.0 -y
|
||||
|
||||
Note: Will only be visible in new terminals. Test with cmake --version.
|
||||
|
||||
- Boost (see also <https://ubuntuforums.org/showthread.php?t=1180792>)
|
||||
|
||||
<!-- -->
|
||||
|
||||
wget https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz
|
||||
tar xfz boost_1_66_0.tar.gz
|
||||
cd boost_1_66_0
|
||||
./bootstrap.sh --with-libraries=program-options,filesystem,system,thread,locale
|
||||
./b2
|
||||
sudo ./b2 install
|
||||
|
||||
Note: Boost 1.66.0 produces a bug in asio.hpp when used with old gcc
|
||||
versions (see <https://svn.boost.org/trac10/ticket/13368>).
|
||||
|
||||
- GCC (for Ubuntu - compile from source is lengthy)
|
||||
|
||||
<!-- -->
|
||||
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-7 g++-7
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 --slave /usr/bin/g++ g++ /usr/bin/g++-7
|
||||
|
||||
Note: Test with gcc --version (and g++ --version).
|
||||
|
||||
- Clang (for Ubuntu 14.04 - for later versions first line is not
|
||||
needed, and 'trusty' should be replaced with version name)
|
||||
|
||||
<!-- -->
|
||||
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo add-apt-repository "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-6.0
|
||||
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 60 --slave /usr/bin/clang++ clang++ /usr/bin/clang++-6.0
|
||||
|
||||
Note: Test with clang --version (and clang++ --version).
|
||||
|
||||
# Getting the sources
|
||||
|
||||
VCMI is still in development. We recommend the following initial
|
||||
directory structure:
|
||||
|
||||
.
|
||||
├── vcmi -> contains sources and is under git control
|
||||
└── build -> contains build output, makefiles, object files,...
|
||||
|
||||
You can get latest sources with:
|
||||
|
||||
git clone -b develop --recursive https://github.com/vcmi/vcmi.git
|
||||
|
||||
# Compilation
|
||||
|
||||
## Configuring Makefiles
|
||||
|
||||
mkdir build && cd build
|
||||
cmake ../vcmi
|
||||
|
||||
# Additional options that you may want to use:
|
||||
## To enable debugging:
|
||||
cmake ../vcmi -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
**Notice**: The ../vcmi/ is not a typo, it will place makefile scripts
|
||||
into the build dir as the build dir is your working dir when calling
|
||||
CMake.
|
||||
|
||||
## Trigger build
|
||||
|
||||
cmake --build . -- -j2
|
||||
# -j2 = compile with 2 threads, you can specify any value
|
||||
|
||||
That will generate vcmiclient, vcmiserver, vcmilauncher as well as 4 .so
|
||||
libraries in **build/bin/** directory.
|
||||
|
||||
# Package building
|
||||
|
||||
## RPM package
|
||||
|
||||
The first step is to prepare a RPM build environment. On Fedora systems
|
||||
you can follow this guide:
|
||||
<http://fedoraproject.org/wiki/How_to_create_an_RPM_package#SPEC_file_overview>
|
||||
|
||||
1\. Download the file rpm/vcmi.spec from any tagged VCMI release for
|
||||
which you wish to build a RPM package via the SVN Browser trac at this
|
||||
URL for example(which is for VCMI 0.9):
|
||||
<http://sourceforge.net/apps/trac/vcmi/browser/tags/0.9/rpm/vcmi.spec>
|
||||
|
||||
2\. Copy the file to ~/rpmbuild/SPECS
|
||||
|
||||
3\. Follow instructions in the vcmi.spec. You have to export the
|
||||
corresponding SVN tag, compress it to a g-zipped archive and copy it to
|
||||
~/rpmbuild/SOURCES. Instructions are written as comments and you can
|
||||
copy/paste commands into terminal.
|
||||
|
||||
4\. Go to ~/rpmbuild/SPECS and open terminal in this folder and type:
|
||||
|
||||
rpmbuild -ba vcmi.spec (this will build rpm and source rpm)
|
||||
|
||||
5\. Generated RPM is in folder ~/rpmbuild/RPMS
|
||||
|
||||
If you want to package the generated RPM above for different processor
|
||||
architectures and operating systems you can use the tool mock. Moreover,
|
||||
it is necessary to install mock-rpmfusion_free due to the packages
|
||||
ffmpeg-devel and ffmpeg-libs which aren't available in the standard RPM
|
||||
repositories(at least for Fedora). Go to ~/rpmbuild/SRPMS in terminal
|
||||
and type:
|
||||
|
||||
mock -r fedora-17-i386-rpmfusion_free path_to_source_RPM
|
||||
mock -r fedora-17-x86_64-rpmfusion_free path_to_source_RPM
|
||||
|
||||
Available root environments and their names are listed in /etc/mock.
|
||||
|
||||
## Debian/Ubuntu
|
||||
|
||||
1\. Install debhelper and devscripts packages
|
||||
|
||||
2\. Run dpkg-buildpackage command from vcmi source directory
|
||||
|
||||
sudo apt-get install debhelper devscripts
|
||||
cd /path/to/source
|
||||
dpkg-buildpackage
|
||||
|
||||
To generate packages for different architectures see "-a" flag of
|
||||
dpkg-buildpackage command
|
||||
|
||||
## Documentation
|
||||
|
||||
To compile using Doxygen, the UseDoxygen CMake module must be installed.
|
||||
It can be fetched from: <http://tobias.rautenkranz.ch/cmake/doxygen/>
|
||||
|
||||
Once UseDoxygen is installed, run:
|
||||
|
||||
cmake .
|
||||
make doc
|
||||
|
||||
The built documentation will be available from ./doc
|
||||
165
docs/developers/How to build VCMI (Visual Studio 2015).md
Normal file
165
docs/developers/How to build VCMI (Visual Studio 2015).md
Normal file
@@ -0,0 +1,165 @@
|
||||
**Warning!** VCMI project only officially support building with CMake:
|
||||
[How to build VCMI
|
||||
(Windows/Vcpkg)](How_to_build_VCMI_(Windows/Vcpkg) "wikilink").
|
||||
|
||||
Guide below and VS solution found in source tree might be broken and not
|
||||
automatically tested. Use at your own risk only if you know what you're
|
||||
doing.
|
||||
|
||||
# Prerequisites
|
||||
|
||||
- Installed Heroes3 (can be bought for $10 at
|
||||
[gog.com](http://www.gog.com/en/gamecard/heroes_of_might_and_magic_3_complete_edition/))
|
||||
- Optionally, you can have also WoG or ERA installed.
|
||||
- IDE:
|
||||
- Microsoft Visual Studio 2015 (Community Edition recommended - it
|
||||
is free for non-commercial use). Earlier version support is
|
||||
deprecated and project may not compile anymore with them.
|
||||
- Git client:
|
||||
- Visual Studio 2015 has built-in Git support. It isn't complete,
|
||||
but having most important Git commands integrated in IDE is very
|
||||
convienent. Additional GitHub extension for Visual Studio
|
||||
[1](https://visualstudio.github.com/) gives few more features
|
||||
that may be useful.
|
||||
- Alternatively, you can use another Git client with better Git
|
||||
support, for example Sourcetree
|
||||
[2](https://www.sourcetreeapp.com/)
|
||||
- Libraries used by VCMI - where to get them will be explained later
|
||||
in this tutorial
|
||||
- Boost
|
||||
- SDL2
|
||||
- SDL2_image
|
||||
- SDL2_mixer
|
||||
- SDL2_TTF
|
||||
- FFmpeg
|
||||
- zlib
|
||||
- QT 5 (only used to compile VCMI launcher, which does not have to
|
||||
be rebuilt to test another VCMI parts)
|
||||
|
||||
# Preparing place
|
||||
|
||||
## Initial directory structure
|
||||
|
||||
Create a directory for VCMI development, eg. C:\VCMI. It will be base
|
||||
directory for VCMI source code.
|
||||
|
||||
It is recommended to avoid non-ascii characters in the path to your VCMI
|
||||
development folder. The folder should not be write-protected by system.
|
||||
Good location:
|
||||
|
||||
- C:\VCMI
|
||||
|
||||
Bad locations:
|
||||
|
||||
- C:\Users\Michał\VCMI (non-ascii character)
|
||||
- C:\Program Files (x86)\VCMI (write protection)
|
||||
|
||||
## Obtaining VCMI sources
|
||||
|
||||
### Using Sourcetree (version 1.9.6.1)
|
||||
|
||||
- Click "Clone / New" button in upper left part of the program
|
||||
- Make sure you are in first tab (Clone Repository). In "Source Path /
|
||||
URL:" type following link: <https://github.com/vcmi/vcmi.git>
|
||||
- Set "Destination Path" field to directory desired for VCMI
|
||||
development and press "Clone" button.
|
||||
|
||||
Now you have the local copy of the repository on the disk. It should
|
||||
appear in the Team Explorer under the "Local Git Repositories" section.
|
||||
Double click it and then select a solution to open.
|
||||
|
||||
# Getting Libraries
|
||||
|
||||
This section will show ways to get up-to-date versions of libraries
|
||||
required to build VCMI. When you have a choice if you want 32 or 64 bit
|
||||
version of library - choosing 32 bit will make things easier as you will
|
||||
not have to do additional configuration in Visual Studio to switch to 64
|
||||
bit etc.
|
||||
|
||||
## Boost
|
||||
|
||||
- Header files with extra things can be obtained from boost website
|
||||
download: [3](http://www.boost.org/users/download/)
|
||||
- To avoid rebuilding boost from sources, you can download prebuilt
|
||||
windows binaries (lib files) from there as well. MSVC 14 binaries
|
||||
are for Visual Studio 2015.
|
||||
|
||||
UPDATE: Somebody reported problem with boost newer than 1.62 when trying
|
||||
to build VCMI. To get all boost 1.62 required files use these links:
|
||||
[4](https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.7z/download)
|
||||
[5](https://sourceforge.net/projects/boost/files/boost-binaries/1.62.0/boost_1_62_0-msvc-14.0-32.exe/download)
|
||||
|
||||
## SDL2 and sublibraries
|
||||
|
||||
- You can get SDL2 from [6](http://libsdl.org/download-2.0.php) -
|
||||
download development libraries to get lib and header files
|
||||
- Similar to SDL2 package you can get SDL2_image from
|
||||
[7](https://www.libsdl.org/projects/SDL_image/), SDL2_mixer from
|
||||
[8](https://www.libsdl.org/projects/SDL_mixer/), SDL2_ttf from
|
||||
[9](https://www.libsdl.org/projects/SDL_ttf/).
|
||||
|
||||
## FFmpeg
|
||||
|
||||
- You can get this library from
|
||||
[10](https://ffmpeg.zeranoe.com/builds/). Both header and lib files
|
||||
are available if you choose "dev" download version.
|
||||
|
||||
## zlib
|
||||
|
||||
- most tricky to get - use NuGet package manager that is part of
|
||||
Visual Studio 2015 to get it. Link in NuGet gallery:
|
||||
[11](https://www.nuget.org/packages/zlib/)
|
||||
|
||||
## QT 5
|
||||
|
||||
- (TO BE ADDED)
|
||||
|
||||
# Compiling VCMI
|
||||
|
||||
To compile VCMI you need to be able to compile some of projects that
|
||||
VCMI solution provides, more information about them is in next part of
|
||||
this tutorial. Default build configuration for VCMI solution is RD, what
|
||||
means "release with debug information".
|
||||
|
||||
You need to resolve header and library directories to point to all
|
||||
required libraries in project settings to properly build VCMI. This is
|
||||
out of scope of this tutorial.
|
||||
|
||||
# VCMI solution details
|
||||
|
||||
VCMI solution consists of few separate projects that get compiled to
|
||||
separate output. Many of them rely on VCMI_lib, so making changes to
|
||||
VCMI_lib requires recompiling another projects. Some of the projects are
|
||||
dead or not updated for very long time, for example Editor or ERM.
|
||||
FuzzyLite and minizip are utility projects and are not meant to be
|
||||
currently changed. Projects in development and their purpose are:
|
||||
|
||||
- BattleAI - as name says this project is for artificial intelligence
|
||||
during battles. Gets compiled to DLL module.
|
||||
- VCAI - adventure map artificial intelligence. Gets compiled to DLL
|
||||
module.
|
||||
- VCMI_client - game client, "game display" and user interface related
|
||||
code is here. One of two main game game executables
|
||||
- VCMI_launcher - game launcher with ability to change some available
|
||||
game options, disable / enable VCMI mods etc.
|
||||
- VCMI_lib - contains shared code for client and server. Large part of
|
||||
game mechanics can be found here. Compilable to DLL module.
|
||||
- VCMI_server - game server. Server starts everytime a scenario is
|
||||
launched, and performs network-based communication with game client.
|
||||
Some parts of game mechanics can be found here. One of two main game
|
||||
executables.
|
||||
|
||||
Projects mentioned above need to be compiled "together" to work because
|
||||
of VCMI_lib dependency - for example compiling VCMI_lib and VCMI_client
|
||||
requires recompiling server, AI projects etc. because their equivalents
|
||||
from other sources such as VCMI windows package will not work with new
|
||||
VCMI_lib and raise "cannot find entry point..." error *(TODO: Maybe this
|
||||
can be worked around using another project code generation settings)*.
|
||||
Working launcher is not needed to run the game though, as mentioned in
|
||||
first part of this tutorial (prerequisites). Additional workaround to
|
||||
skip compiling launcher and have access to launcher settings is to use
|
||||
VCMI windows package as separate vcmi copy - changes made in launcher
|
||||
there affect all vcmi copies.
|
||||
|
||||
**There is also Test project for development purposes that can be used
|
||||
for unit tests and similar things that developers may want to do.**
|
||||
258
docs/developers/How to build VCMI (Windows Vcpkg).md
Normal file
258
docs/developers/How to build VCMI (Windows Vcpkg).md
Normal file
@@ -0,0 +1,258 @@
|
||||
# Prerequisites
|
||||
|
||||
- Windows Vista or newer.
|
||||
- Microsoft Visual Studio
|
||||
[2017](https://www.visualstudio.com/vs/older-downloads/) or
|
||||
[2019](http://www.visualstudio.com/downloads/download-visual-studio-vs)
|
||||
- CI use VS2019, so you are going to have less problems with it.
|
||||
- Git or git GUI, for example, SourceTree
|
||||
[download](http://www.sourcetreeapp.com/download)
|
||||
- CMake [download](https://cmake.org/download/). During install after
|
||||
accepting license agreement make sure to check "Add CMake to the
|
||||
system PATH for all users".
|
||||
- To unpack pre-build Vcpkg:
|
||||
[7-zip](http://www.7-zip.org/download.html)
|
||||
- To create installer: [NSIS](http://nsis.sourceforge.net/Main_Page)
|
||||
|
||||
# Choose directory
|
||||
|
||||
Create a directory for VCMI development, eg. **C:\VCMI** We will call
|
||||
this directory **%VCMI_DIR%**
|
||||
|
||||
**Warning!** Replace **%VCMI_DIR%** with path you chosen in following
|
||||
commands of this instruction.
|
||||
|
||||
## How to choose good directory
|
||||
|
||||
It is recommended to avoid non-ascii characters in the path to your
|
||||
working folders. The folder should not be write-protected by system.
|
||||
Good location:
|
||||
|
||||
- **C:\VCMI**
|
||||
|
||||
Bad locations:
|
||||
|
||||
- **C:\Users\Michał\VCMI** (non-ascii character)
|
||||
- **C:\Program Files (x86)\VCMI** (write protection)
|
||||
|
||||
# Install dependencies
|
||||
|
||||
You have two options: to use pre-built libraries or build your own. We
|
||||
strongly recommend start with using pre-built ones.
|
||||
|
||||
## Option A. Use pre-built Vcpkg
|
||||
|
||||
So you decide to start using Vcpkg packages pre-built by VCMI team.
|
||||
|
||||
Package guaranteed to work since they tested with every commit by
|
||||
[GitHub Actions](https://github.com/vcmi/vcmi/actions).
|
||||
|
||||
### Download and unpack archive
|
||||
|
||||
Archives are available from GitHub:
|
||||
<https://github.com/vcmi/vcmi-deps-windows/releases>
|
||||
|
||||
Only download latest version available.
|
||||
|
||||
- vcpkg-export-**x86**-windows-v140.7z to build for 32-bit no debug, 3
|
||||
times smaller file size
|
||||
- vcpkg-export-**x64**-windows-v140.7z to build for 64-bit no debug, 3
|
||||
times smaller file size
|
||||
- vcpkg-export-**x86**-windows-v140-debug.7z to build for 32-bit with
|
||||
debug configuration available
|
||||
- vcpkg-export-**x64**-windows-v140-debug.7z to build for 64-bit with
|
||||
debug configuration available
|
||||
|
||||
Extract archive by right clicking on it and choosing "7-zip -\> Extract
|
||||
Here".
|
||||
|
||||
### Move dependencies to target directory
|
||||
|
||||
Once extracted "vcpkg" directory will appear with "installed" and
|
||||
"scripts" inside it.
|
||||
|
||||
Move extracted "vcpkg" directory into your **%VCMI_DIR%**.
|
||||
|
||||
## Option B. Build Vcpkg on your own
|
||||
|
||||
Please be aware that if you're running 32-bit Windows version, then this
|
||||
is impossible due to <https://github.com/microsoft/vcpkg/issues/26036>
|
||||
|
||||
Be aware that building Vcpkg might take a lot of time depend on your CPU
|
||||
model and 10-20GB of disk space.
|
||||
|
||||
### Create initial directory
|
||||
|
||||
### Clone vcpkg
|
||||
|
||||
1. open SourceTree
|
||||
2. File -\> Clone
|
||||
3. select **<https://github.com/microsoft/vcpkg/>** as source
|
||||
4. select **%VCMI_DIR%/vcpkg** as destination
|
||||
5. click **Clone**
|
||||
|
||||
From command line use:
|
||||
|
||||
git clone https://github.com/microsoft/vcpkg.git %VCMI_DIR%/vcpkg
|
||||
|
||||
### Build vcpkg
|
||||
|
||||
- Run
|
||||
|
||||
<!-- -->
|
||||
|
||||
%VCMI_DIR%/vcpkg/bootstrap-vcpkg.bat
|
||||
|
||||
### Build dependencies
|
||||
|
||||
- For 32-bit build run:
|
||||
|
||||
<!-- -->
|
||||
|
||||
%VCMI_DIR%/vcpkg/vcpkg.exe install tbb:x64-windows fuzzylite:x64-windows sdl2:x64-windows sdl2-image:x64-windows sdl2-ttf:x64-windows sdl2-mixer[mpg123]:x64-windows boost:x64-windows qt5-base:x64-windows ffmpeg:x64-windows luajit:x64-windows
|
||||
|
||||
- For 64-bit build run
|
||||
|
||||
<!-- -->
|
||||
|
||||
%VCMI_DIR%/vcpkg/vcpkg.exe install install tbb:x86-windows fuzzylite:x86-windows sdl2:x86-windows sdl2-image:x86-windows sdl2-ttf:x86-windows sdl2-mixer[mpg123]:x86-windows boost:x86-windows qt5-base:x86-windows ffmpeg:x86-windows luajit:x86-windows
|
||||
|
||||
For the list of the packages used you can also consult
|
||||
[vcmi-deps-windows readme](https://github.com/vcmi/vcmi-deps-windows) in
|
||||
case this article gets outdated a bit.
|
||||
|
||||
# Build VCMI
|
||||
|
||||
## Clone VCMI
|
||||
|
||||
1. open SourceTree
|
||||
2. File -\> Clone
|
||||
3. select **<https://github.com/vcmi/vcmi/>** as source
|
||||
4. select **%VCMI_DIR%/source** as destination
|
||||
5. expand Advanced Options and change Checkout Branch to "develop"
|
||||
6. tick Recursive submodules
|
||||
7. click **Clone**
|
||||
|
||||
or From command line use:
|
||||
|
||||
git clone --recursive https://github.com/vcmi/vcmi.git %VCMI_DIR%/source
|
||||
|
||||
## Generate solution for VCMI
|
||||
|
||||
1. create **%VCMI_DIR%/build** folder
|
||||
2. open **%VCMI_DIR%/build** in command line:
|
||||
1. Run Command Prompt or Power Shell.
|
||||
2. Execute: cd %VCMI_DIR%/build
|
||||
3. execute one of following commands to generate project
|
||||
|
||||
**Visual Studio 2017 - 32-bit build**
|
||||
|
||||
cmake %VCMI_DIR%/source -DCMAKE_TOOLCHAIN_FILE=%VCMI_DIR%/vcpkg/scripts/buildsystems/vcpkg.cmake -G "Visual Studio 15 2017"
|
||||
|
||||
**Visual Studio 2017 - 64-bit build**
|
||||
|
||||
cmake %VCMI_DIR%/source -DCMAKE_TOOLCHAIN_FILE=%VCMI_DIR%/vcpkg/scripts/buildsystems/vcpkg.cmake -G "Visual Studio 15 2017 Win64"
|
||||
|
||||
**Visual Studio 2019 - 32-bit build**
|
||||
|
||||
cmake %VCMI_DIR%/source -DCMAKE_TOOLCHAIN_FILE=%VCMI_DIR%/vcpkg/scripts/buildsystems/vcpkg.cmake -G "Visual Studio 16 2019" -A Win32
|
||||
|
||||
**Visual Studio 2019 - 64-bit build**
|
||||
|
||||
cmake %VCMI_DIR%/source -DCMAKE_TOOLCHAIN_FILE=%VCMI_DIR%/vcpkg/scripts/buildsystems/vcpkg.cmake -G "Visual Studio 16 2019" -A x64
|
||||
|
||||
## Compile VCMI with Visual Studio
|
||||
|
||||
1. open **%VCMI_DIR%/build/VCMI.sln** in Visual Studio
|
||||
2. select "Release" build type in combobox
|
||||
3. right click on **BUILD_ALL** project - build project. This BUILD_ALL
|
||||
project should be in "CMakePredefinedTargets" tree in Solution
|
||||
Explorer.
|
||||
4. grab VCMI in **%VCMI_DIR%/build/bin** folder!
|
||||
|
||||
## Compile VCMI from command line
|
||||
|
||||
**For release build**
|
||||
|
||||
cmake --build %VCMI_DIR%/build --config Release
|
||||
|
||||
**For debug build**
|
||||
|
||||
cmake --build %VCMI_DIR%/build --config Debug
|
||||
|
||||
Debug will be used by default even "--config" if not specified.
|
||||
|
||||
# Create VCMI installer (This step is not required for just building & development)
|
||||
|
||||
Make sure NSIS is installed to default directory or have registry entry
|
||||
so CMake can find it.
|
||||
|
||||
After you build VCMI execute following commands from
|
||||
**%VCMI_DIR%/build**.
|
||||
|
||||
### Execute following if you built for Release:
|
||||
|
||||
cpack
|
||||
|
||||
### If you built for Debug:
|
||||
|
||||
cpack -C Debug
|
||||
|
||||
# Troubleshooting and workarounds
|
||||
|
||||
Vcpkg might be very unstable due to limited popularity and fact of using
|
||||
bleeding edge packages (such as most recent Boost). Using latest version
|
||||
of dependencies could also expose both problems in VCMI code or library
|
||||
interface changes that developers not checked yet. So if you're built
|
||||
Vcpkg yourself and can't get it working please try to use binary
|
||||
package.
|
||||
|
||||
Pre-built version we provide is always manually tested with all
|
||||
supported versions of MSVC for both Release and Debug builds and all
|
||||
known quirks are listed below.
|
||||
|
||||
### VCMI won't run since some library is missing
|
||||
|
||||
**If you open solution using vcmi.sln** Try to build INSTALL target and
|
||||
see if its output works as expected. Copy missing libraries or even all
|
||||
libraries from there to your build directory. Or run cpack and use
|
||||
produced installer and see if you can get libs from there. cpack -V will
|
||||
give more info. If cpack complains that it can not find dumpbin try
|
||||
Visual Studio Command Prompt (special version of cmd provided with
|
||||
Visual Studio with additional PATH) or modify PATH to have this tool
|
||||
available. Another alternative if you use prebuilt vcpkg package is to
|
||||
download latest msvc build, install it and copy missing/all libraries
|
||||
from there.
|
||||
|
||||
### Debug build is very slow
|
||||
|
||||
Debug builds with MSVC are generally extremely slow since it's not just
|
||||
VCMI binaries are built as debug, but every single dependency too and
|
||||
this usually means no optimizations at all. Debug information that
|
||||
available for release builds is often sufficient so just avoid full
|
||||
debug builds unless absolutely necessary. Instead use RelWithDebInfo
|
||||
configuration. Also Debug configuration might have some compilation
|
||||
issues because it is not checked via CI for now.
|
||||
|
||||
### I got crash within library XYZ.dll
|
||||
|
||||
VCPKG generated projects quite often have both debug and regular libs
|
||||
available to linker so it can select wrong lib. For stable
|
||||
RelWithDebInfo build you may try to remove debug folder from
|
||||
VCPKG/installed/x64-windows. Same is done on CI. Also it reduces package
|
||||
size at least twice.
|
||||
|
||||
### Some outdated problems
|
||||
|
||||
All problems of such kind should be solved with proper cmake INSTALL
|
||||
code.
|
||||
|
||||
**Build is successful but can not start new game**
|
||||
|
||||
Check that all non-VCMI dlls in AI and Scripting (vcmilua.dll and
|
||||
vcmierm.dll) folders are also copied to the parent folder so that they
|
||||
are available for vcmi_clent.exe. These are tbb.dll fuzzylite.dll
|
||||
lua51.dll. Also there should be as well folder scripts (lua scripts for
|
||||
ERM). If scripting folder is absent please build vcmiLua and vcmiErm
|
||||
projects. There is no direct dependency between them and vcmi_client for
|
||||
now (2021-08-28)
|
||||
111
docs/developers/How to build VCMI (iOS).md
Normal file
111
docs/developers/How to build VCMI (iOS).md
Normal file
@@ -0,0 +1,111 @@
|
||||
## Requirements
|
||||
|
||||
1. **macOS**
|
||||
2. Xcode: <https://developer.apple.com/xcode/>
|
||||
3. CMake 3.21+: `brew install --cask cmake` or get from
|
||||
<https://cmake.org/download/>
|
||||
|
||||
## Obtaining source code
|
||||
|
||||
Clone <https://github.com/vcmi/vcmi> with submodules. Example for
|
||||
command line:
|
||||
|
||||
`git clone --recurse-submodules https://github.com/vcmi/vcmi.git`
|
||||
|
||||
## Obtaining dependencies
|
||||
|
||||
There're 2 ways to get prebuilt dependencies:
|
||||
|
||||
- [Conan package
|
||||
manager](https://github.com/vcmi/vcmi/tree/develop/docs/conan.md) -
|
||||
recommended. Note that the link points to the cutting-edge state in
|
||||
`develop` branch, for the latest release check the same document in
|
||||
the [master
|
||||
branch](https://github.com/vcmi/vcmi/tree/master/docs/conan.md).
|
||||
- [legacy manually built
|
||||
libraries](https://github.com/vcmi/vcmi-ios-deps) - can be used if
|
||||
you have Xcode 11/12 or to build for simulator / armv7 device
|
||||
|
||||
## Configuring project
|
||||
|
||||
Only Xcode generator (`-G Xcode`) is supported!
|
||||
|
||||
As a minimum, you must pass the following variables to CMake:
|
||||
|
||||
- `BUNDLE_IDENTIFIER_PREFIX`: unique bundle identifier prefix,
|
||||
something like `com.MY-NAME`
|
||||
- (if using legacy dependencies) `CMAKE_PREFIX_PATH`: path to the
|
||||
downloaded dependencies, e.g.
|
||||
`~/Downloads/vcmi-ios-depends/build/iphoneos`
|
||||
|
||||
There're a few [CMake
|
||||
presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html):
|
||||
for device (Conan and legacy dependencies) and for simulator, named
|
||||
`ios-device-conan`, `ios-device` and `ios-simulator` respectively. You
|
||||
can also create your local "user preset" to avoid typing variables each
|
||||
time, see example
|
||||
[here](https://gist.github.com/kambala-decapitator/59438030c34b53aed7d3895aaa48b718).
|
||||
|
||||
Open terminal and `cd` to the directory with source code. Configuration
|
||||
example for device with Conan:
|
||||
|
||||
`cmake --preset ios-device-conan \`
|
||||
` -D BUNDLE_IDENTIFIER_PREFIX=com.MY-NAME`
|
||||
|
||||
By default build directory containing Xcode project will appear at
|
||||
`../build-ios-device-conan`, but you can change it with `-B` option.
|
||||
|
||||
### Building for device
|
||||
|
||||
To be able to build for iOS device, you must also specify codesigning
|
||||
settings. If you don't know your development team ID, open the generated
|
||||
Xcode project, open project settings (click **VCMI** with blue icon on
|
||||
the very top in the left panel with files), select **vcmiclient**
|
||||
target, open **Signing & Capabilities** tab and select yout team. Now
|
||||
you can copy the value from **Build Settings** tab - `DEVELOPMENT_TEAM`
|
||||
variable (paste it in the Filter field on the right) - click the
|
||||
greenish value - Other... - copy. Now you can pass it in
|
||||
`CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM` variable when configuring the
|
||||
project to avoid selecting the team manually every time CMake
|
||||
re-generates the project.
|
||||
|
||||
Advanced users who know exact private key and provisioning profile to
|
||||
sign with, can use `CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY` and
|
||||
`CMAKE_XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER` variables
|
||||
instead. In this case you must also pass
|
||||
|
||||
`-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_STYLE=Manual`.
|
||||
|
||||
## Building project
|
||||
|
||||
### From Xcode IDE
|
||||
|
||||
Open `VCMI.xcodeproj` from the build directory, select `vcmiclient`
|
||||
scheme (the only one with nice icon) with your destination
|
||||
device/simulator and hit Run (Cmd+R).
|
||||
|
||||
You must also install game files, see [Installation on
|
||||
iOS](Installation_on_iOS "wikilink"). But this is not necessary if you
|
||||
are going to run on simulator, as it is able to use game data from your
|
||||
Mac located at `~/Library/Application Support/vcmi`.
|
||||
|
||||
### From command line
|
||||
|
||||
`cmake --build `<path to build directory>` --target vcmiclient -- -quiet`
|
||||
|
||||
You can pass additional xcodebuild options after the `--`. Here `-quiet`
|
||||
is passed to reduce amount of output.
|
||||
|
||||
Alternatively, you can invoke `xcodebuild` directly.
|
||||
|
||||
There's also `ios-release-conan` configure and build preset that is used
|
||||
to create release build on CI.
|
||||
|
||||
## Creating ipa file for distribution
|
||||
|
||||
Invoke `cpack` after building:
|
||||
|
||||
`cpack -C Release`
|
||||
|
||||
This will generate file with extension **ipa** if you use CMake 3.25+
|
||||
and **zip** otherwise (simply change extension to ipa).
|
||||
170
docs/developers/How to build VCMI (macOS).md
Normal file
170
docs/developers/How to build VCMI (macOS).md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Requirements
|
||||
|
||||
1. C++ toolchain, either of:
|
||||
- Xcode Command Line Tools (aka CLT):
|
||||
`sudo xcode-select --install`
|
||||
- Xcode IDE: <https://developer.apple.com/xcode/>
|
||||
- (not tested) other C++ compilers, e.g. gcc/clang from
|
||||
[Homebrew](https://brew.sh/)
|
||||
2. CMake: `brew install --cask cmake` or get from
|
||||
<https://cmake.org/download/>
|
||||
3. (optional) Ninja: `brew install ninja` or get from
|
||||
<https://github.com/ninja-build/ninja/releases>
|
||||
|
||||
# Obtaining source code
|
||||
|
||||
Clone <https://github.com/vcmi/vcmi> with submodules. Example for
|
||||
command line:
|
||||
|
||||
`git clone --recurse-submodules https://github.com/vcmi/vcmi.git`
|
||||
|
||||
# Obtaining dependencies
|
||||
|
||||
There're 2 ways to get dependencies automatically.
|
||||
|
||||
## Conan package manager
|
||||
|
||||
Please find detailed instructions in [VCMI
|
||||
repository](https://github.com/vcmi/vcmi/tree/develop/docs/conan.md).
|
||||
Note that the link points to the cutting-edge state in `develop` branch,
|
||||
for the latest release check the same document in the [master
|
||||
branch](https://github.com/vcmi/vcmi/tree/master/docs/conan.md).
|
||||
|
||||
On the step where you need to replace **PROFILE**, choose:
|
||||
|
||||
- if you're on an Intel Mac: `macos-intel`
|
||||
- if you're on an Apple Silicon Mac: `macos-arm`
|
||||
|
||||
Note: if you wish to build 1.0 release in non-`Release` configuration,
|
||||
you should define `USE_CONAN_WITH_ALL_CONFIGS=1` environment variable
|
||||
when executing `conan install`.
|
||||
|
||||
## Homebrew
|
||||
|
||||
1. [Install Homebrew](https://brew.sh/)
|
||||
2. Install dependencies:
|
||||
`brew install boost minizip sdl2 sdl2_image sdl2_mixer sdl2_ttf tbb`
|
||||
3. If you want to watch in-game videos, also install FFmpeg:
|
||||
`brew install ffmpeg@4`
|
||||
4. Install Qt dependency in either of the ways (note that you can skip
|
||||
this if you're not going to build Launcher):
|
||||
- `brew install qt@5` for Qt 5 or `brew install qt` for Qt 6
|
||||
- using [Qt Online Installer](https://www.qt.io/download) - choose
|
||||
**Go open source**
|
||||
|
||||
# Preparing build environment
|
||||
|
||||
This applies only to Xcode-based toolchain. If `xcrun -f clang` prints
|
||||
errors, then use either of the following ways:
|
||||
|
||||
- select an Xcode instance from Xcode application - Preferences -
|
||||
Locations - Command Line Tools
|
||||
- use `xcode-select` utility to set Xcode or Xcode Command Line Tools
|
||||
path: for example,
|
||||
`sudo xcode-select -s /Library/Developer/CommandLineTools`
|
||||
- set `DEVELOPER_DIR` environment variable pointing to Xcode or Xcode
|
||||
Command Line Tools path: for example,
|
||||
`export DEVELOPER_DIR=/Applications/Xcode.app`
|
||||
|
||||
# Configuring project for building
|
||||
|
||||
Note that if you wish to use Qt Creator IDE, you should skip this step
|
||||
and configure respective variables inside the IDE.
|
||||
|
||||
1. In Terminal `cd` to the source code directory
|
||||
2. Start assembling CMake invocation: type `cmake -S . -B BUILD_DIR`
|
||||
where *BUILD_DIR* can be any path, **don't press Return**
|
||||
3. Decide which CMake generator you want to use:
|
||||
- Makefiles: no extra option needed or pass `-G 'Unix Makefiles'`
|
||||
- Ninja (if you have installed it): pass `-G Ninja`
|
||||
- Xcode IDE (if you have installed it): pass `-G Xcode`
|
||||
4. If you picked Makefiles or Ninja, pick desired *build type* - either
|
||||
of Debug / RelWithDebInfo / Release / MinSizeRel - and pass it in
|
||||
`CMAKE_BUILD_TYPE` option, for example:
|
||||
`-D CMAKE_BUILD_TYPE=Release`. If you don't pass this option,
|
||||
`RelWithDebInfo` will be used.
|
||||
5. If you don't want to build Launcher, pass `-D ENABLE_LAUNCHER=OFF`
|
||||
6. You can also pass `-Wno-dev` if you're not interested in CMake
|
||||
developer warnings
|
||||
7. Next step depends on the dependency manager you have picked:
|
||||
- Conan: pass
|
||||
`-D CMAKE_TOOLCHAIN_FILE=conan-generated/conan_toolchain.cmake`
|
||||
where **conan-generated** must be replaced with your directory
|
||||
choice
|
||||
- Homebrew: if you installed FFmpeg or Qt 5, you need to pass
|
||||
`-D "CMAKE_PREFIX_PATH="` variable. See below what you can
|
||||
insert after `=` (but **before the closing quote**), multiple
|
||||
values must be separated with `;` (semicolon):
|
||||
- if you installed FFmpeg, insert `$(brew --prefix ffmpeg@4)`
|
||||
- if you installed Qt 5 from Homebrew, insert:
|
||||
`$(brew --prefix qt@5)`
|
||||
- if you installed Qt from Online Installer, insert your path
|
||||
to Qt directory, for example:
|
||||
`/Users/kambala/dev/Qt-libs/5.15.2/Clang64`
|
||||
- example for FFmpeg + Qt 5:
|
||||
`-D "CMAKE_PREFIX_PATH=$(brew --prefix ffmpeg@4);$(brew --prefix qt@5)"`
|
||||
8. now press Return
|
||||
|
||||
# Building project
|
||||
|
||||
You must also install game files to be able to run the built version,
|
||||
see [Installation on macOS](Installation_on_macOS "wikilink").
|
||||
|
||||
## From Xcode IDE
|
||||
|
||||
Open `VCMI.xcodeproj` from the build directory, select `vcmiclient`
|
||||
scheme and hit Run (Cmd+R). To build Launcher, select `vcmilauncher`
|
||||
scheme instead.
|
||||
|
||||
## From command line
|
||||
|
||||
`cmake --build `<path to build directory>
|
||||
|
||||
- If using Makefiles generator, you'd want to utilize all your CPU
|
||||
cores by appending `-- -j$(sysctl -n hw.ncpu)` to the above
|
||||
- If using Xcode generator, you can also choose which configuration to
|
||||
build by appending `--config `<configuration name> to the above, for
|
||||
example: `--config Debug`
|
||||
|
||||
# Packaging project into DMG file
|
||||
|
||||
After building, run `cpack` from the build directory. If using Xcode
|
||||
generator, also pass `-C `<configuration name> with the same
|
||||
configuration that you used to build the project.
|
||||
|
||||
If you use Conan, it's expected that you use **conan-generated**
|
||||
directory at step 4 of [#Conan package
|
||||
manager](#Conan_package_manager "wikilink").
|
||||
|
||||
# Running VCMI
|
||||
|
||||
You can run VCMI from DMG, but it's will also work from your IDE be it
|
||||
Xcode or Qt Creator.
|
||||
|
||||
Alternatively you can run binaries directly from "bin" directory:
|
||||
|
||||
BUILD_DIR/bin/vcmilauncher
|
||||
BUILD_DIR/bin/vcmiclient
|
||||
BUILD_DIR/bin/vcmiserver
|
||||
|
||||
CMake include commands to copy all needed assets from source directory
|
||||
into "bin" on each build. They'll work when you build from Xcode too.
|
||||
|
||||
# Some useful debugging tips
|
||||
|
||||
Anyone who might want to debug builds, but new to macOS could find
|
||||
following commands useful:
|
||||
|
||||
# To attach DMG file from command line use
|
||||
hdiutil attach vcmi-1.0.dmg
|
||||
# Detach volume:
|
||||
hdiutil detach /Volumes/vcmi-1.0
|
||||
# To view dependency paths
|
||||
otool -L /Volumes/vcmi-1.0/VCMI.app/Contents/MacOS/vcmiclient
|
||||
# To display load commands such as LC_RPATH
|
||||
otool -l /Volumes/vcmi-1.0/VCMI.app/Contents/MacOS/vcmiclient
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
In case of troubles you can always consult our CI build scripts or
|
||||
contact the dev team via slack
|
||||
201
docs/developers/Logging API.md
Normal file
201
docs/developers/Logging API.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Features
|
||||
|
||||
- A logger belongs to a "domain", this enables us to change log level
|
||||
settings more selectively
|
||||
- The log format can be customized
|
||||
- The color of a log entry can be customized based on logger domain
|
||||
and logger level
|
||||
- Logger settings can be changed in the settings.json file
|
||||
- No std::endl at the end of a log entry required
|
||||
- Thread-safe
|
||||
- Macros for tracing the application flow
|
||||
- Provides stream-like and function-like logging
|
||||
|
||||
# Class diagram
|
||||
|
||||
<figure>
|
||||
<img src="Logging_Class_Diagram.jpg"
|
||||
title="Logging_Class_Diagram.jpg" />
|
||||
<figcaption>Logging_Class_Diagram.jpg</figcaption>
|
||||
</figure>
|
||||
|
||||
Some notes:
|
||||
|
||||
- There are two methods `configure` and `configureDefault` of the
|
||||
class `CBasicLogConfigurator` to initialize and setup the logging
|
||||
system. The latter one setups default logging and isn't dependent on
|
||||
VCMI's filesystem, whereas the first one setups logging based on the
|
||||
user's settings which can be configured in the settings.json.
|
||||
- The methods `isDebugEnabled` and `isTraceEnabled` return true if a
|
||||
log record of level debug respectively trace will be logged. This
|
||||
can be useful if composing the log message is a expensive task and
|
||||
performance is important.
|
||||
|
||||
# Usage
|
||||
|
||||
## Setup settings.json
|
||||
|
||||
``` javascript
|
||||
{
|
||||
"logging" : {
|
||||
"console" : {
|
||||
"threshold" : "debug",
|
||||
"colorMapping" : [
|
||||
{
|
||||
"domain" : "network",
|
||||
"level" : "trace",
|
||||
"color" : "magenta"
|
||||
}
|
||||
]
|
||||
},
|
||||
"loggers" : [
|
||||
{
|
||||
"domain" : "global",
|
||||
"level" : "debug"
|
||||
},
|
||||
{
|
||||
"domain" : "ai",
|
||||
"level" : "trace"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above code is an example on how to configure logging. It sets the
|
||||
log level to debug globally and the log level of the domain ai to trace.
|
||||
In addition, it tells the console to log debug messages as well with the
|
||||
threshold attribute. Finally, it configures the console so that it logs
|
||||
network trace messages in magenta.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following code shows how the logging system can be configured:
|
||||
|
||||
console = new CConsoleHandler;
|
||||
CBasicLogConfigurator logConfig(VCMIDirs::get().localPath() + "/VCMI_Server_log.txt", console);
|
||||
logConfig.configureDefault(); // Initialize default logging due to that the filesystem and settings are not available
|
||||
preinitDLL(console); // Init filesystem
|
||||
settings.init(); // Init settings
|
||||
logConfig.configure(); // Now setup "real" logging system, overwrites default settings
|
||||
|
||||
If `configureDefault` or `configure` won't be called, then logs aren't
|
||||
written either to the console or to the file. The default logging setups
|
||||
a system like this:
|
||||
|
||||
**Console**
|
||||
|
||||
Format: %m
|
||||
|
||||
Threshold: info
|
||||
|
||||
coloredOutputEnabled: true
|
||||
|
||||
colorMapping: trace -\> gray, debug -\> white, info -\> green, warn -\>
|
||||
yellow, error -\> red
|
||||
|
||||
**File**
|
||||
|
||||
Format: %d %l %n \[%t\] - %m
|
||||
|
||||
**Loggers**
|
||||
|
||||
global -\> info
|
||||
|
||||
## How to get a logger
|
||||
|
||||
There exist only one logger object per domain. A logger object cannot be
|
||||
copied. You can get access to a logger object by using the globally
|
||||
defined ones like `logGlobal` or `logAi`, etc... or by getting one
|
||||
manually:
|
||||
|
||||
CLogger * logger = CLogger::getLogger(CLoggerDomain("rmg"));
|
||||
|
||||
## Logging
|
||||
|
||||
Logging can be done via two ways, stream-like or function-like.
|
||||
|
||||
logGlobal->warnStream() << "Call to loadBitmap with void fname!";
|
||||
logGlobal->warn("Call to loadBitmap with void fname!");
|
||||
|
||||
Don't include a '\n' or std::endl at the end of your log message, a new
|
||||
line will be appended automatically.
|
||||
|
||||
The following list shows several log levels from the highest one to the
|
||||
lowest one:
|
||||
|
||||
- error -\> for errors, e.g. if resource is not available, if a
|
||||
initialization fault has occured, if a exception has been thrown
|
||||
(can result in program termination)
|
||||
- warn -\> for warnings, e.g. if sth. is wrong, but the program can
|
||||
continue execution "normally"
|
||||
- info -\> informational messages, e.g. Filesystem initialized, Map
|
||||
loaded, Server started, etc...
|
||||
- debug -\> for debugging, e.g. hero moved to (12,3,0), direction 3',
|
||||
'following artifacts influence X: .. or pattern detected at pos
|
||||
(10,15,0), p-nr. 30, flip 1, repl. 'D'
|
||||
- trace -\> for logging the control flow, the execution progress or
|
||||
fine-grained events, e.g. hero movement completed, entering
|
||||
CMapEditManager::updateTerrainViews: posx '10', posy '5', width
|
||||
'10', height '10', mapLevel '0',...
|
||||
|
||||
The following colors are available for console output:
|
||||
|
||||
- default
|
||||
- green
|
||||
- red
|
||||
- magenta
|
||||
- yellow
|
||||
- white
|
||||
- gray
|
||||
- teal
|
||||
|
||||
## How to trace execution
|
||||
|
||||
The program execution can be traced by using the macros TRACE_BEGIN,
|
||||
TRACE_END and their \_PARAMS counterparts. This can be important if you
|
||||
want to analyze the operations/internal workings of the AI or the
|
||||
communication of the client-server. In addition, it can help you to find
|
||||
bugs on a foreign VCMI installation with a custom mod configuration.
|
||||
|
||||
int calculateMovementPointsForPath(int3 start, int3 end, CHero * hero) // This is just an example, the function is fictive
|
||||
{
|
||||
TRACE_BEGIN_PARAMS(logGlobal, "start '%s', end '%s', hero '%s'", start.toString() % end.toString() % hero.getName()); // toString is fictive as well and returns a string representation of the int3 pos, ....
|
||||
int movPoints;
|
||||
// Do some stuff
|
||||
// ...
|
||||
TRACE_END_PARAMS(logGlobal, "movPoints '%i'", movPoints);
|
||||
return movPoints;
|
||||
}
|
||||
|
||||
# Concepts
|
||||
|
||||
## Domain
|
||||
|
||||
A domain is a specific part of the software. In VCMI there exist several
|
||||
domains:
|
||||
|
||||
- network
|
||||
- ai
|
||||
- bonus
|
||||
- network
|
||||
|
||||
In addition to these domains, there exist always a super domain called
|
||||
"global". Sub-domains can be created with "ai.battle" or "ai.adventure"
|
||||
for example. The dot between the "ai" and "battle" is important and
|
||||
notes the parent-child relationship of those two domains. A few examples
|
||||
how the log level will be inherited:
|
||||
|
||||
global, level=info
|
||||
network, level=not set, effective level=info
|
||||
|
||||
global, level=warn
|
||||
network, level=trace, effective level=trace
|
||||
|
||||
global, level=debug
|
||||
ai, level=not set, effective level=debug
|
||||
ai.battle, level=trace, effective level=trace
|
||||
|
||||
The same technique is applied to the console colors. If you want to have
|
||||
another debug color for the domain ai, you can explicitely set a color
|
||||
for that domain and level.
|
||||
BIN
docs/developers/Logging_Class_Diagram.png
Normal file
BIN
docs/developers/Logging_Class_Diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
352
docs/developers/Serialization.md
Normal file
352
docs/developers/Serialization.md
Normal file
@@ -0,0 +1,352 @@
|
||||
# Introduction
|
||||
|
||||
The serializer translates between objects living in our code (like int
|
||||
or CGameState\*) and stream of bytes. Having objects represented as a
|
||||
stream of bytes is useful. Such bytes can send through the network
|
||||
connection (so client and server can communicate) or written to the disk
|
||||
(savegames).
|
||||
|
||||
VCMI uses binary format. The primitive types are simply copied from
|
||||
memory, more complex structures are represented as a sequence of
|
||||
primitives.
|
||||
|
||||
## Typical tasks
|
||||
|
||||
### Bumping a version number
|
||||
|
||||
Different major version of VCMI likely change the format of the save
|
||||
game. Every save game needs a version identifier, that loading can work
|
||||
properly. Backward compatibility isn't supported for now. The version
|
||||
identifier is a constant named version in Connection.h and should be
|
||||
updated every major VCMI version or development version if the format
|
||||
has been changed. Do not change this constant if it's not required as it
|
||||
leads to full rebuilds. Why should the version be updated? If VCMI
|
||||
cannot detect "invalid" save games the program behaviour is random and
|
||||
undefined. It mostly results in a crash. The reason can be anything from
|
||||
null pointer exceptions, index out of bounds exceptions(ok, they aren't
|
||||
available in c++, but you know what I mean:) or invalid objects
|
||||
loading(too much elements in a vector, etc...) This should be avoided at
|
||||
least for public VCMI releases.
|
||||
|
||||
### Adding a new class
|
||||
|
||||
If you want your class to be serializable (eg. being storable in a
|
||||
savegame) you need to define a serialize method template, as described
|
||||
in [#User types](#User_types "wikilink")
|
||||
|
||||
Additionally, if your class is part of one of registered object
|
||||
hierarchies (basically: if it derives from CGObjectInstance,
|
||||
IPropagator, ILimiter, CBonusSystemNode, CPack) it needs to be
|
||||
registered. Just add an appropriate entry in the `RegisterTypes.h` file.
|
||||
See [#Polymorphic serialization](#Polymorphic_serialization "wikilink")
|
||||
for more information.
|
||||
|
||||
# How does it work
|
||||
|
||||
## Primitive types
|
||||
|
||||
They are simply stored in a binary form, as in memory. Compatibility is
|
||||
ensued through the following means:
|
||||
|
||||
- VCMI uses internally types that have constant, defined size (like
|
||||
si32 - has 32 bits on all platforms)
|
||||
- serializer stores information about its endianess
|
||||
|
||||
It's not "really" portable, yet it works properly across all platforms
|
||||
we currently support.
|
||||
|
||||
## Dependant types
|
||||
|
||||
### Pointers
|
||||
|
||||
Storing pointers mechanics can be and almost always is customized. See
|
||||
[#Additional features](#Additional_features "wikilink").
|
||||
|
||||
In the most basic form storing pointer simply sends the object state and
|
||||
loading pointer allocates an object (using "new" operator) and fills its
|
||||
state with the stored data.
|
||||
|
||||
### Arrays
|
||||
|
||||
Serializing array is simply serializing all its elements.
|
||||
|
||||
## Standard library types
|
||||
|
||||
### STL Containers
|
||||
|
||||
First the container size is stored, then every single contained element.
|
||||
|
||||
Supported STL types include:
|
||||
|
||||
`vector`
|
||||
`array`
|
||||
`set`
|
||||
`unordered_set`
|
||||
`list`
|
||||
`string`
|
||||
`pair`
|
||||
`map`
|
||||
|
||||
### Smart pointers
|
||||
|
||||
Smart pointers at the moment are treated as the raw C-style pointers.
|
||||
This is very bad and dangerous for shared_ptr and is expected to be
|
||||
fixed somewhen in the future.
|
||||
|
||||
The list of supported data types from standard library:
|
||||
|
||||
`shared_ptr (partial!!!)`
|
||||
`unique_ptr`
|
||||
|
||||
### Boost
|
||||
|
||||
Additionally, a few types for Boost are supported as well:
|
||||
|
||||
`variant`
|
||||
`optional`
|
||||
|
||||
## User types
|
||||
|
||||
To make the user-defined type serializable, it has to provide a template
|
||||
method serialize. The first argument (typed as template parameter) is a
|
||||
reference to serializer. The second one is version number.
|
||||
|
||||
Serializer provides an operator& that is internally expanded to \<\<
|
||||
when serialziing or \>\> when deserializing.
|
||||
|
||||
Serializer provides a public bool field `saving`that set to true during
|
||||
serialziation and to false for deserialziation.
|
||||
|
||||
Typically, serializing class involves serializing all its members (given
|
||||
that they are serializable). Sample:
|
||||
|
||||
``` cpp
|
||||
/// The rumor struct consists of a rumor name and text.
|
||||
struct DLL_LINKAGE Rumor
|
||||
{
|
||||
std::string name;
|
||||
std::string text;
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & name & text;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Backwards compatibility
|
||||
|
||||
Serializer, before sending any data, stores its version number. It is
|
||||
passed as the parameter to the serialize method, so conditional code
|
||||
ensuring backwards compatibility can be added.
|
||||
|
||||
Yet, because of numerous changes to our game data structure, providing
|
||||
means of backwards compatibility is not feasible. The versioning feature
|
||||
is rarely used.
|
||||
|
||||
Sample:
|
||||
|
||||
``` cpp
|
||||
/// The rumor struct consists of a rumor name and text.
|
||||
struct DLL_LINKAGE Rumor
|
||||
{
|
||||
std::string name; //introduced in version 1065
|
||||
std::string text;
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
if(version >= 1065)
|
||||
h & name;
|
||||
else if(!h.saving) //when loading old savegame
|
||||
name = "no name"; //set name to some default value [could be done in class constructor as well]
|
||||
|
||||
h & text;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Serializer classes
|
||||
|
||||
### Common information
|
||||
|
||||
Serializer classes provide iostream-like interface with operator\<\< for
|
||||
serialization and operator\>\> for deserialization. Serializer upon
|
||||
creation will retrieve/store some metadata (version number, endianess),
|
||||
so even if no object is actually serialized, some data will be passed.
|
||||
|
||||
### Serialization to file
|
||||
|
||||
CLoadFile/CSaveFile classes allow to read data to file and store data to
|
||||
file. They take filename as the first parameter in constructor and,
|
||||
optionally, the minimum supported version number (default to the current
|
||||
version). If the construction fails (no file or wrong file) the
|
||||
exception is thrown.
|
||||
|
||||
### Networking
|
||||
|
||||
CConnection class provides support for sending data structures over
|
||||
TCP/IP protocol. It provides 3 constructors: 1) connect to given
|
||||
hostname at given port (host must be accepting connection) 2) accept
|
||||
connection (takes boost.asio acceptor and io_service) 3) adapt
|
||||
boost.asio socket with already established connection
|
||||
|
||||
All three constructors take as the last parameter the name that will be
|
||||
used to identify the peer.
|
||||
|
||||
## Additional features
|
||||
|
||||
Here is the list of additional custom features serialzier provides. Most
|
||||
of them can be turned on and off.
|
||||
|
||||
- [#Polymorphic serialization](#Polymorphic_serialization "wikilink")
|
||||
— no flag to control it, turned on by calls to registerType.
|
||||
- [#Vectorized list member
|
||||
serialization](#Vectorized_list_member_serialization "wikilink") —
|
||||
enabled by smartVectorMembersSerialization flag.
|
||||
- [#Stack instance
|
||||
serialization](#Stack_instance_serialization "wikilink") — enabled
|
||||
by sendStackInstanceByIds flag.
|
||||
- [#Smart pointer
|
||||
serialization](#Smart_pointer_serialization "wikilink") — enabled by
|
||||
smartPointerSerialization flag.
|
||||
|
||||
### Polymorphic serialization
|
||||
|
||||
Serializer is to recognize the true type of object under the pointer if
|
||||
classes of that hierarchy were previously registered.
|
||||
|
||||
This means that following will work
|
||||
|
||||
``` cpp
|
||||
Derived *d = new Derived();
|
||||
Base *basePtr = d;
|
||||
CSaveFile output("test.dat");
|
||||
output << b;
|
||||
//
|
||||
Base *basePtr = nullptr;
|
||||
CLoadFile input("test.dat");
|
||||
input >> basePtr; //a new Derived object will be put under the pointer
|
||||
```
|
||||
|
||||
Class hierarchies that are now registered to benefit from this feature
|
||||
are mostly adventure map object (CGObjectInstance) and network packs
|
||||
(CPack). See the RegisterTypes.h file for the full list.
|
||||
|
||||
It is crucial that classes are registered in the same order in the both
|
||||
serializers (storing and loading).
|
||||
|
||||
### Vectorized list member serialization
|
||||
|
||||
Both client and server store their own copies of game state and VLC
|
||||
(handlers with data from config). Many game logic objects are stored in
|
||||
the vectors and possess a unique id number that represent also their
|
||||
position in such vector.
|
||||
|
||||
The vectorised game objects are:
|
||||
|
||||
`CGObjectInstance`
|
||||
`CGHeroInstance`
|
||||
`CCreature`
|
||||
`CArtifact`
|
||||
`CArtifactInstance`
|
||||
`CQuest`
|
||||
|
||||
For this to work, serializer needs an access to gamestate library
|
||||
classes. This is done by calling a method
|
||||
`CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)`.
|
||||
|
||||
When the game ends (or gamestate pointer is invaldiated for another
|
||||
reason) this feature needs to be turned off by toggling its flag.
|
||||
|
||||
When vectorized member serialization is turned on, serializing pointer
|
||||
to such object denotes not sending an object itself but rather its
|
||||
identity. For example:
|
||||
|
||||
``` cpp
|
||||
//Server code
|
||||
CCreature *someCreature = ...;
|
||||
connection << someCreature;
|
||||
```
|
||||
|
||||
the last line is equivalent to
|
||||
|
||||
``` cpp
|
||||
connection << someCreature->idNumber;
|
||||
```
|
||||
|
||||
//Client code
|
||||
|
||||
``` cpp
|
||||
CCreature *someCreature = nullptr;
|
||||
connection >> someCreature;
|
||||
```
|
||||
|
||||
the last line is equivalent to
|
||||
|
||||
``` cpp
|
||||
CreatureID id;
|
||||
connection >> id;
|
||||
someCreature = VLC->creh->creatures[id.getNum()];
|
||||
```
|
||||
|
||||
Important: this means that the object state is not serialized.
|
||||
|
||||
This feature makes sense only for server-client network communication.
|
||||
|
||||
### Stack instance serialization
|
||||
|
||||
This feature works very much like the vectorised object serialization.
|
||||
It is like its special case for stack instances that are not vectorised
|
||||
(each hero owns its map). When this option is turned on, sending
|
||||
CStackInstance\* will actually send an owning object (town, hero,
|
||||
garrison, etc) id and the stack slot position.
|
||||
|
||||
For this to work, obviously, both sides of the connection need to have
|
||||
exactly the same copies of an armed object and its stacks.
|
||||
|
||||
This feature depends on vectorised member serialization being turned on.
|
||||
(Sending owning object by id.)
|
||||
|
||||
### Smart pointer serialization
|
||||
|
||||
Note: name is unfortunate, this feature is not about smart pointers
|
||||
(like shared-ptr and unique_ptr). It is for raw C-style pointers, that
|
||||
happen to point to the same object.
|
||||
|
||||
This feature makes it that multiple pointers pointing to the same object
|
||||
are not stored twice.
|
||||
|
||||
Each time a pointer is stored, a unique id is given to it. If the same
|
||||
pointer is stored a second time, its contents is not serialized —
|
||||
serializer just stores a reference to the id.
|
||||
|
||||
For example:
|
||||
|
||||
``` cpp
|
||||
Foo * a = new Foo();
|
||||
Foo * b = b;
|
||||
|
||||
{
|
||||
CSaveFile test("test.txt");
|
||||
test << a << b;
|
||||
}
|
||||
|
||||
Foo *loadedA, *loadedB;
|
||||
{
|
||||
CLoadFile test("test.txt");
|
||||
test >> loadedA >> loadedB;
|
||||
//now both pointers point to the same object
|
||||
assert(loadedA == loadedB);
|
||||
}
|
||||
```
|
||||
|
||||
The feature recognizes pointers by addresses. Therefore it allows mixing
|
||||
pointers to base and derived classes. However, it does not allow
|
||||
serializing classes with multiple inheritance using a "non-first" base
|
||||
(other bases have a certain address offset from the actual object).
|
||||
|
||||
Pointer cycles are properly handled/
|
||||
|
||||
This feature makes sense for savegames and is turned on for them.
|
||||
Reference in New Issue
Block a user