Files
AdamuSw/docs/Readme.md
sven-n d04cbecae3 Merge pull request #820 from nolt/feature-bots
(cherry picked from commit b10de0645a869485fbb5771a739abd06b5708c2d)
2026-07-23 11:38:08 +03:00

164 lines
7.9 KiB
Markdown

# Documentation
This directory should contain all the (technical) documentation of the OpenMU
project, including [packets descriptions](Packets/Readme.md), game mechanics
and software architecture.
## Why not using the wiki?
We think that a lot of the documentation (especially packet descriptions) is
based on the actual code. So it makes sense that all the (technical)
documentation should be available within the code, so there is no point in
using the wiki.
However, documentation like getting the project run (like a users manual)
could be put on the wiki, of course.
## Game Server Architecture
Disclaimer (by [sven-n](https://github.com/sven-n)):
*This is not a perfect architecture, if such architecture exists anyway.
However, it makes sense to me for this purpose, as an enterprise business
application developer. I tried to make it flexible and I hope it's not too
complicated.*
For the big picture, you may have a look at the
[architecture overview](architecture%20overview.png).
There are interfaces for the interoperability between the different "servers"
or sub-systems in [MUnique.OpenMU.Interfaces](https://github.com/MUnique/OpenMU/tree/master/src/Interfaces).
### Communication between game client and server
The network communication between game client and the game server takes place
through the [Connection class](https://github.com/MUnique/OpenMU/tree/master/src/Network/Connection.cs).
MUnique.OpenMU.Network contains all what's required to connect from and to a
game server, using the MU Online network protocol. It also contains the
message structs of the messages in MUnique.OpenMU.Network.Packets.
#### Client -> Server
When receiving data from the game client, it gets forwarded to the packet
handlers located at namespace MUnique.OpenMU.GameServer.MessageHandler. Every
handler is an implementation of a IPacketHandlerPlugIn.
These message handlers are parsing the data packets and then calls the player
actions located at MUnique.OpenMU.GameLogic.PlayerActions, which should have no
knowledge of the packet structure or how the communication took place.
#### Server -> Client
The other way - data sent to the game game client - is done by views
(MUnique.OpenMU.GameServer.RemoteView).
These views are using the Connection class to send the data in the specified
protocol. The GameLogic has no knowledge about this protocol and just works
with the [view interface plugins](https://github.com/MUnique/OpenMU/tree/master/src/GameLogic/Views/IViewPlugIn.cs).
#### Benefits of this architecture
As you can see, the GameLogic itself does not know how the player actions are
triggered or how the "view" look like.
Instead of working with the network, there could be an implementation of
[view plugins](https://github.com/MUnique/OpenMU/tree/master/src/GameLogic/Views/IViewPlugIn.cs)
which is literally a graphical user interface.
Also instead of calling the player actions by packet handler plugins, a user
interface could call them instead.
So this project could be a base for a (non-MU) game client which then could
also support multiplayer and co-op with the existing server components.
All plugins are configurable over the AdminPanel. They can be activated or
deactivated, so that they can be replaced by extended or modified versions.
It's also possible to offer different protocols to work on the same game world,
by implementing multiple view and packet handlers with different client
versions attributes. Each game server can have multiple tcp listeners which can
be bound to separate tcp ports for different client versions, too.
### Data access
The access pattern is mainly this:
* At server start, the game configuration is loaded
* When a game client logged in, it's account is loaded
* During the game, the account data is saved at specific points and in an
time interval
#### Design goal
It should be possible to support multiple different databases, also NoSQL ones,
without changing the game logic.
For this purpose we don't just use SQL and database-specific code in the game
logic. The access patterns should keep this in mind. So instead of a lot single
calls to a lot of different repositories in the game logic, one big call should
be done.
For example, if we want to use a document based database, an account could be
one document and the game configuration as a whole could also be one document.
#### Abstractions
To accomplish the design goals, the game logic (and other parts) are using
abstractions, [Repositories](https://martinfowler.com/eaaCatalog/repository.html),
to access data.
These abstractions are located at the MUnique.OpenMU.Persistence namespace.
We use a context-based approach to access data, e.g. the [GameConfiguration](https://github.com/MUnique/OpenMU/tree/master/src/DataModel/Configuration/GameConfiguration.cs)
is loaded through a [GameConfigurationRepository](https://github.com/MUnique/OpenMU/tree/master/src/Persistence/EntityFramework/GameConfigurationRepository.cs)
while "using" a [context](https://github.com/MUnique/OpenMU/tree/master/src/Persistence/IContext.cs),
and each connected player uses its own [player context](https://github.com/MUnique/OpenMU/tree/master/src/Persistence/IPlayerContext.cs)
to load its [Account](https://github.com/MUnique/OpenMU/tree/master/src/DataModel/Entities/Account.cs).
When saving an account, we actually save the it's context. The context then
takes care that every required change is done at the database.
When accessing or creating new persistent objects, the [context](https://github.com/MUnique/OpenMU/tree/master/src/Persistence/IContext.cs)
needs to be "in use" on the current thread, because the actual context
implementation may need to track these objects.
It takes care of a lot of things, e.g. creating new objects. Contexts can be
created with the [PersistenceContextProvider](https://github.com/MUnique/OpenMU/tree/master/src/Persistence/IPersistenceContextProvider.cs).
#### Current implementation and supported database
At the moment the persistence layer is implemented by [MUnique.OpenMU.Persistence.EntityFramework](../src/Persistence/EntityFramework/Readme.md)
which uses the [Entity Framework Core](https://github.com/aspnet/EntityFrameworkCore)
and [PostgreSQL](https://www.postgresql.org/) as database.
#### Future
Because the data model is pretty complicated (which is required if the
configuration should be that flexible), a full relational model
on a database is probably not the best thing to do (performance wise).
Currently, we use an approach to load the game configuration or account with
just one big dynamically generated query which gives us the data as json.
That's suprisingly fast, as the query itself to load the really complex game
configuration finishes in about 1.5 seconds.
If there might be a problem in the future, we could go further and mix
relational tables with json columns or to fully switch to a document based
database (e.g. RavenDB).
### Further information
* [Packets](Packets/Readme.md): Information about the packet structures
* [Master Skill System](MasterSystem.md): Description about the master skill system
* [Server-side AI Bots](Bots.md): Description about the bots which populate
the server
* [GameMap](GameMap.md): Description about the GameMap implementation
* [Progress](Progress.md): Information about the feature implementation
progress of the project. See also:
* [Normal skill progress](https://github.com/MUnique/OpenMU/projects/9)
* [Master skill progress](https://github.com/MUnique/OpenMU/projects/10)
* [Admin Panel](https://github.com/MUnique/OpenMU/tree/master/src/Web/AdminPanel):
The user inferface of the server
* [Attribute System](https://github.com/MUnique/OpenMU/tree/master/src/AttributeSystem):
Damage calculation and player attributes are based on that
* [Network](https://github.com/MUnique/OpenMU/tree/master/src/Network): About the
network communication
* [Startup](https://github.com/MUnique/OpenMU/tree/master/src/Startup): It's the
project for the executeable which puts every piece of the puzzle together