Documentation
  • 🏠Home
    • Parallel-Origin Documentation
  • Server
    • Introduction
    • Database
    • Entity Component System
    • Networking
    • Physics
    • Workflow
  • Client
    • Introduction
    • Internal Database
    • Entity Component System
    • Networking
    • User Interface
    • Workflow
  • Core
    • Introduction
    • Shared Components
    • Shared Networking
    • Shared Utils
    • Workflow
Powered by GitBook
On this page
  • Introduction
  • Usages and structure
  • Configuration
  • Examples
Edit on GitHub
  1. Server

Database

The most basic about the integrated database.

PreviousIntroductionNextEntity Component System

Last updated 1 year ago

Introduction

Let's start with the database. Everything is stored there to save the state of the world, the players and the environment. To make this easier we use , a framework that abstracts the database logic for us.

The most important classes here are the and the . The Context connects to the (in memory) database, provides Methods to interact with the Database and the Model contains the database model. Each class in the model describes a table in the database, these tables represent the state of the world. These classes and tables are also called "entities".

As a rule, everything is stored that should survive a server start. This includes every account, every player, every item, every tree, every stone, every mob and all their attributes that are important. Important attributes differ from entity to entity, for example the position, HP what is left or how many items you have of which type. Attributes that are not unique per entity or do not change are stored in the server code and not saved.

Usages and structure

It is probably important to know WHERE the database is used. Pretty much everywhere. Towards the , database entities are loaded, including accounts and converted into game entities. During the game, on the other hand, the players and the environment are regularly saved and or loaded. This happens at a regular interval, every few minutes. This can be set in the code. The is responsible for the (interval) saving. In other places something is also loaded or saved on certain interactions, or during .

The is a group of different ECS systems that run in sequence to execute in-game loop logic. In this case, database logic and operations. It consists of the following ordered systems:

  • The iterates over all game entities without a stored database model and creates one for each. This ensures that all game entities are stored in the database. So you can simply create game entities and this system automatically takes care of transferring them to the database.

  • The iterates over all game entities marked with Destroy. This destroys them in the game and should therefore also remove them from the database. Some of them also need the Delete component to signal that they should be removed from the database. This depends on the context. The system makes sure that these marked entities are removed from the database appropriately.

  • The iterates over all game entities and their attached database model. In the process, the state of the entity is transferred to the database model. This ensures that the database model is up to date.

  • The stores the in the interval and thus all database operations that took place up to this point.

Configuration

By default, the uses an in-memory database. This means there is no need to worry about an external one and the server runs out of the box. In the constructor you can set if this should be used or an external one. If an external one is to be used, a must be set in the context and the table structure on the database must be created using EF-Core. More info .

Examples

Program.cs
// Loads account from the database and returns them as a list
var accounts = _gameDbContext.Accounts.ToList();
...
PersistenceAuthentificationExtensions.cs
public static Account Register(this GameDbContext context, string username, string password, string email, Gender gender, Vector2d position = default) {
        
    // Check if account or mail already exists to prevent another registration...
    var accountExists = context.AccountExists(username);
    accountExists.Wait();
    var emailExists = context.EmailExists(email);
    emailExists.Wait();
    
    // Create identity and position
    var identity = new Identity { Tag = "player", Type = "1:1" };
    var transform = new Transform { X = (float)position.X, Y = (float)position.Y, RotX = 0, RotY = 0, RotZ = 0 };
    
    // Create character
    var character = new Character
    {
        Identity = identity,
        Transform = transform,
        Chunk = null,
        Inventory = new HashSet<InventoryItem>(32),
        Health = 100.0f
    };
    
    // Create account and save
    var account = new Account
    {
        Username = username,
        Password = password,
        Email = email,
        Character = character,
        Gender = gender,
        Type = Type.NORMAL,
        Registered = DateTime.UtcNow,
        LastSeen = DateTime.UtcNow,
        AcceptedGdpr = DateTime.UtcNow
    };
    
    // Add some starting items
    var startWoodItem = new InventoryItem
    {
        Identity = new Identity { Id = (long)RandomExtensions.GetUniqueULong(), Type = Types.Gold, Tag = Tags.Item },
        Character = character,
        Amount = 10,
        Level = 0
    };
    character.Inventory.Add(startWoodItem);
    
    // Add to context
    context.Accounts.Add(account);
    context.Identities.Add(identity);
    context.Characters.Add(character);
    context.InventoryItems.Add(startWoodItem);
    
    context.SaveChanges();  // Saves newly added entity automatically
    return account;
}
var registeredAccount = _gameDBContext.Register("TestAccount", "TestPassword", "TestEmail@gmail.com", Gender.Male, new Position{ X = 9.1f, Y = 54.1f}); 

Pretty easy, right?

To learn you can take a look at the , where for example at the beginning the accounts are loaded. Since EF-Core is used, working with the Database is very easy (Example from ):

So to work on the database you always need the from the . Through it you can perform database operations in the normal EF core manner. These operations should mostly be outsourced to own (extension) methods to improve the read flow. Here is another more complex :

The code above should hopefully be self-evident. The extension method is used to create a new account and player. First, it checks asynchronously if the player already exists; if not, it continues and creates and persists the database model of the player. Thus it can be easily called to register new accounts, like this:

EF-Core
Context
Model
start
DatabaseGroup
for example when creating or entering chunks
login
DatabaseGroup
ModelSystem
DeleteAndDetachModelSystem
ModelUpdateSystem
PersistenceSystem
Context
Context
GameDBContext
connection string
here
main
main
_gameDBContext
Program.cs
example
Register