Misc

Table of content

Editor assembly

Mostly, database works inside Editor assembly the same way as it works at runtime, meaning you can develop your own Editor tools on top of the database. Use generated classes to access database.

To save database in Unity Editor via C# code from Editor assembly, use this line:

    //This will work ONLY inside Unity Editor from Editor Assembly
    BansheeGz.BGDatabase.Editor.BGRepoSaver.SaveRepo();

To save database in Unity Editor via C# code from Runtime assembly, use this line:

    //This will work ONLY inside Unity Editor from Runtime or Editor Assembly
    BansheeGz.BGDatabase.BGUtil.SaveDatabaseInUnityEditor();

To assign unity asset field values, use SetAsset method, defined on each unity asset field and available in Editor assembly (this method is not available at runtime assembly)

    SetAsset(int entityIndex, UnityEngine.Object asset)

The method is defined at the base Unity asset field, which is BGFieldUnityAssetA<T> (T is the value type), so you need to downcast BGField to this class if you do not use CodeGen addon. If you use CodeGen addon, you can access the field directly without need to downcast, using {TableClass}._{fieldName} notation, see more details here

Events

Events let use listen to database changes, like changing the field or entity, adding or removing entities. Make sure

  1. To pair adding a listener with removing a listener to prevent memory leaks
  2. all events handlers have try/catch block to prevent exception being fired from event handlers

Following events are available:

Event Description
Field value changed It is fired when provided field value change (any entity)
Entity is updated It is fired when provided entity value change (any field)
Entity is deleted It is fired when provided entity deleted
Any entity is updated It is fired when any entity updated (any field)
Any entity is added It is fired when new entity is added
Any entity is deleted It is fired when any entity deleted
Before any entity deleted It is fired before any entity is deleted
Batch update event Batch update event is fired when BGRepo.I.Events.Batch(Action action); method is used. When this method is used, no individual events will be fired while action is being executed and one single batch event will be fired when action is executed. This is required for performance's sake when massive changes to database should be done without firing individual events
Any change event It is fired on any database change

For usage example, see this demo C# script

Validation

Data validation allows to set the rules to validate data. Validation works in Unity Editor only and has no effect at runtime. To turn on validation, press on "Validation off" button at the top left of BGDatabase window.

Validation types
  1. Database data validation
  2. Scene objects validation (Binders and BGEntityGo components)
Database data validation
Validation rule Description
Entity name is unique If entity has a name, it should be unique
Entity name is empty Entities should have no name (names can be cleared under Configuration tab)
Entity is singleton Only one single entity should exist
Field is required Field should have some value. Only class-based fields are affected, cause struct-based fields always have a value
Key is unique Each key, marked as unique, should have 0-1 matching rows. If there are more than 1 matching row, it's considered to be a rule violation.

To review validation log, hover over red E icons as shown on the screenshot below. E icon is shown only if at least one error exists.

Scene objects validation

Following BGDatabase scene components can also be validated (using Scene Explorer tab).

  1. BGEntityGo components
  2. Generated Monobehaviour classes (extending from BGEntityGo)
  3. Data binders

Any component, which has an error, will be highlighted.

Keys and indexes

  1. Key consist of 1-n fields and can be used to look up row(s) quickly. It also can be used in rows validation
  2. Index has a reference to a single field and can be used for effective range scan

Here is a table, comparing different row(s) retrieval methods efficiency

Method Underlying structure Time complexity Comments
meta.GetEntity(int index) list O(1) fastest method
meta.GetEntity(BGId Id) hashtable O(1)
GetEntity(string name) hashtable O(1)
key.GetEntityByKey(params object[] keys) hashtable O(1)
index.FindEntitiesByIndex(indexOperator) b-tree O(log n) if index field data is not skewed
meta.FindEntity(predicate), meta.FindEntities(predicate) N/A O(n), fullscan
Keys

Following fields can be added to a key: bool, int, long, decimal, bool?, int?, long?, string, text, enum, relationSingle.

You can access the matching row(s) directly without searching, using BGKey class. Available options:

  1. Use generated methods (recommended)
  2. Use basic API. To access the key, use BGMetaEntity.GetKey({keyName}) method. To get a row(s), use BGKey.GetEntityByKey or BGKey.GetEntitiesByKey methods
  3. If you use Visual Scripting assets, you can use generated unit/node if it's supported

Keys make row(s) access faster, but uses extra memory and may slow down write (update) operations, so do not use keys for data, which is updated frequently.

Indexes

Indexes enables row(s) range scan fast operations, but uses extra memory and may slow down write (update) operations. Currently only single field index is supported. Available options to use an index:

  1. Use generated methods (recommended)
  2. Use basic API. To access the index use BGMetaEntity.GetIndex({indexName}) method. To query rows use index.FindEntitiesByIndex method

Views

Views are virtual table, which does not have its own rows and used with view relational fields. Read more about views here

Command Line

Command line utility (Settings->Command line) let you run DDL-like commands with simplified syntax.

Syntax is (use empty line to separate commands):

    COMMAND [Options]
    [Additional options]

Available commands:

  1. CREATE TABLE [TableName]
    [FieldName] [FieldType]
  2. ALTER TABLE [TableName]
    ADD [FieldName] [FieldType]
    DROP [FieldName]
  3. DROP TABLE [TableName]

Example:

    CREATE TABLE MyTable
    MyField1 int
    MyField2 bool

    ALTER TABLE MyTable
    ADD MyField3 int
    DROP MyField1

    DROP TABLE MyTable

Custom fields implementation guide

  1. Do not use custom fields unless all other alternatives are much worse. For example, if your custom field has two properties (int and float) there is no need to create a custom field, you can use two basic fields instead (int and float) to store the values.
  2. Do not try to create your custom field in your actual project. Create and test your custom field using a new, empty project. Make sure it works correctly before transferring this field to your project. A bug in your implementation can break the whole database
  3. Use existing fields implementations as examples. Fields implementation sources can be found in Assets\BansheeGz\BGDatabase\Scripts\BGDatabaseSourceCode.unitypackage package (Database\Field\*). Fields managers implementation sources can be found in Assets\BansheeGz\BGDatabase\Editor\Scripts\BGDatabaseEditorSourceCode.unitypackage package (Database\Field\*).
  4. To create a custom field you need to create two C# classes:
    1. Class for the field (in runtime assembly)
    2. Class for the field's manager (in Editor assembly)
  5. [Important] Do not try to create your classes from scratch, extend them from existing classes.
    For your field class:
    1. If your field value is a class extend your field class from BGFieldCachedClassA class
    2. If your field value is a struct extend your field class from BGFieldCachedStructA class
    For your field's manager class:
    1. If your field value can be edited "in place" (like primitive fields: int, float, string)- extend your field's manager class from BGFieldManagerInlinedA class
    2. If your field value can be edited in popup window, which can be opened by clicking on cell button (like complex fields: bounds, assets)- extend your field's manager class from BGFieldManagerWithButtonA class
  6. The methods/properties, which need to be implemented for your field class:
    1. ToBytes/FromBytes- for binary serialization
    2. ToString/FromString- for string serialization
    3. CreateFieldFactory- utility method for creating new fields
    4. Implement ICloneable interface for your value type if it's a class (not struct)
    5. ValueSize property if your value type is a struct
  7. If you have difficulties implementing your own custom field- contact us and send us full source code for your value type (class/struct). You can skip its methods but all fields which needs to be saved inside database need to be included.

Default field value

Default field value is the default value for new rows, i.g. it's the value for rows, created after this default value is set. Default field value is assigned at the moment a row is created and does not affect existing rows values.

Default field value is provided as a string value. Each field type has its own string format, for example for int values it's an int constant (10), for float value it's a float constant (10.1), for bool value it's 0 or 1. If you are not sure which string format to use for your particular field type- create a row with the value, you want to use as a default value and export it to Excel. Than copy Excel cell value and paste it to "Default value" column.

Overriding cell button text

There is an extension technique, which can be used for overriding cell button text for button-based fields. You can provide C# class or calculation graph, which can return custom text, based on database values. For example, let's say you have a Weapon table with a nested WeaponDamage table and each row of the nested table has power (int) and damageType (singleRelation) fields. The name field for the nested table is disabled and not used.

The default button text for the nested table is composed of the nested rows names, but since we do not use the name field, the button caption is [2] [no name] | [no name], which is not very informative

The solution for this problem is providing your own C# class (or calculation graph), which can be used for button text calculation. Below is the C# class example, which includes the number of related rows with power and damageType fields values to the button text

The C# code for custom button text provider
using BansheeGz.BGDatabase.Editor;

//this class uses CodeGen addon generated classes
public class WeaponEffectsButtonText : BGButtonTextProviderI
{
    public BGButtonTextResponse GetButtonText(BGButtonTextRequest request)
    {
        var response = new BGButtonTextResponse();
        var entity = (D_Weapon)request.Entity;
        var damageTypes = entity.WeaponDamage;
        if (damageTypes == null || damageTypes.Count == 0) response.Text = "No value";
        else
        {
            response.Text += $"[{damageTypes.Count}] ";
            for (var i = 0; i < damageTypes.Count; i++)
            {
                var damageType = damageTypes[i];
                if (i != 0) response.Text += " | ";
                response.Text += (damageType.damageType?.name ?? "[not set]") + ": " + damageType.power;
            }
        }
        return response;
    }
}

To assign the custom button text provider to your field, use M field's menu and Custom button text provider menu item

Referencing tables, fields, rows and cells from your own MonoBehaviour scripts

This section described methods for creating a serializable references to tables, fields, rows and cells. For regular database access use CodeGen addon generated classes or basic API

How to reference a Method Screenshot
Table Use BGMetaReference class
Code example
using BansheeGz.BGDatabase;
using UnityEngine;

public class Temp : MonoBehaviour
{
    public BGMetaReference table;

    private void Start()
    {
        BGMetaEntity meta = table.Meta;
    }
}
Field Option #1. Use BGFieldReference class
Code example
using BansheeGz.BGDatabase;
using UnityEngine;

public class Temp : MonoBehaviour
{
    public BGFieldReference field;

    private void Start()
    {
        BGField dbField = field.Field;
    }
}
Option #2. Use field reference class, generated by CodeGen addon
Code example
using BansheeGz.BGDatabase;
using UnityEngine;

public class Temp : MonoBehaviour
{
    //D_Weapon_FieldRef class is generated by CodeGen addon
    public D_Weapon_FieldRef field;

    private void Start()
    {
        BGField dbField = field.Field;
    }
}
Row Option #1. Use MonoBehaviour generated components
Code example
using UnityEngine;

public class Temp : MonoBehaviour
{
    private void Start()
    {
        // M_Weapon is a generated class
        M_Weapon weapon = GetComponent<M_Weapon>();
        print($"Weapon {weapon.name}");
    }
}
Option #2. Use BGEntityGo component (can reference a row from any table but no generated properties/methods)
Code example
using BansheeGz.BGDatabase;
using UnityEngine;

public class Temp : MonoBehaviour
{
    private void Start()
    {
        BGEntityGo weapon = GetComponent<BGEntityGo>();
        BGEntity entity = weapon.Entity;
    }
}
Option #3. Use classes, generated by CodeGen addon
Code example
using UnityEngine;

public class Temp : MonoBehaviour
{
    public D_Weapon_RowRef row;

    private void Start()
    {
        // D_Weapon class is also generated by CodeGen addon
        D_Weapon dbRow = row.Entity;
    }
}
Option #4. Use BGEntityReference class
Code example
using BansheeGz.BGDatabase;
using UnityEngine;

public class Temp : MonoBehaviour
{
    public BGEntityReference row;

    private void Start()
    {
        BGEntity dbRow = row.GetEntity();
    }
}
Cell Cell includes table, field and row. Use BGCellReference class
Code example
using BansheeGz.BGDatabase;
using UnityEngine;

public class Temp : MonoBehaviour
{
    public BGCellReference cell;

    private void Start()
    {
        BGEntity dbRow = cell.GetEntity();
        BGField dbField = cell.Field;
        print(cell.Value);
    }
}