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
- To pair adding a listener with removing a listener to prevent memory leaks
- 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
- Database data validation
- 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).
- BGEntityGo components
- Generated Monobehaviour classes (extending from BGEntityGo)
- Data binders
Any component, which has an error, will be highlighted.
Keys and indexes
- Key consist of 1-n fields and can be used to look up row(s) quickly. It also can be used in rows validation
- 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:
- Use generated methods (recommended)
- Use basic API. To access the key, use
BGMetaEntity.GetKey({keyName})
method. To get a row(s), useBGKey.GetEntityByKey
orBGKey.GetEntitiesByKey
methods - 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:
- Use generated methods (recommended)
- Use basic API. To access the index use
BGMetaEntity.GetIndex({indexName})
method. To query rows useindex.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:
- CREATE TABLE [TableName]
[FieldName] [FieldType] - ALTER TABLE [TableName]
ADD [FieldName] [FieldType]
DROP [FieldName] - 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
- 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.
- 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
- 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\*).
-
To create a custom field you need to create two C# classes:
- Class for the field (in runtime assembly)
- Class for the field's manager (in Editor assembly)
-
[Important] Do not try to create your classes from scratch, extend them from existing classes.
For your field class:- If your field value is a class extend your field class from BGFieldCachedClassA class
- If your field value is a struct extend your field class from BGFieldCachedStructA class
- If your field value can be edited "in place" (like primitive fields: int, float, string)- extend your field's manager class from BGFieldManagerInlinedA class
- 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
-
The methods/properties, which need to be implemented for your field class:
- ToBytes/FromBytes- for binary serialization
- ToString/FromString- for string serialization
- CreateFieldFactory- utility method for creating new fields
- Implement ICloneable interface for your value type if it's a class (not struct)
- ValueSize property if your value type is a struct
- 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
|
||
Field | Option #1. Use BGFieldReference class | |
Code example
|
||
Option #2. Use field reference class, generated by CodeGen addon | ||
Code example
|
||
Row | Option #1. Use MonoBehaviour generated components | |
Code example
|
||
Option #2. Use BGEntityGo component (can reference a row from any table but no generated properties/methods) | ||
Code example
|
||
Option #3. Use classes, generated by CodeGen addon | ||
Code example
|
||
Option #4. Use BGEntityReference class | ||
Code example
|
||
Cell | Cell includes table, field and row. Use BGCellReference class | |
Code example
|