The Table Realms Model

The Table Realms model is at the heart of all data communications. Essentially it is a distributed data model that is shared between the game and the Lua client code. If you are unfamiliar with the Model View Controller pattern you might want to investigate that for further understanding. MVC Wiki

The model is accessible from the Game and from each of the devices’ Lua. If you are executing the game in Peer-to-peer the model has other access limitation depending on the type of peer-to-peer implementation you are using. More on different peer-to-peer modes.

It is important when designing your model’s behavior and use you consider where a value is changed. It’s best to keep each value only modifiable from one place. We can not guarantee that data changed from two places at the same time will have the correct value ever.

Additionally model data can be stored locally or on the cloud for the user. This is made very easy with the Model storage Lua APIs.

There are three segments of model data.

  • Global
  • Local
  • Special

Each data model entry is of three possible data types

Type Description
string Any string value and nulls are in fact transported as string but they are removed after that.
bool Basic true or false value.
float Any kind of number value is passed as a float the range is double in Lua but float in unity for example1.

Local Model Data

Local model data is data that is localized to a specific player. Local data has the following attributes.

  • Is available (read/write) in the Clients Lua
  • Is available (read/write) from the Host game
  • Is available (read/write) from the Client game if P3 has been used (P# currently still in development)
  • Is not available for read or write on any other players Lua.
  • Is not available for read or write on any other players game (unless that game instance is the host).

Local model data example

For example in the Lua there would be a boolean for when a button is pressed. It would change from true to false as the button is pressed down. (All of this is handles in the Lua code and can be read or changed if needed).

In the case of a button the following entry is used to determine if a button is pressed.

Player/Global Key Client Key In game Type
Player Button.{name}.Pressed {id}.Button.{name}.Pressed bool

As you can see the data has a composite key build out of the fact it is a button, has a name and what we are looking for in that. Also you may notice the key differs between the Lua and the game. In the game the key is prefixed with the clients id this allows the game to have the same data for each of the clients.

As mentioned earlier it is wise to have each model data owned and manged from only one place. In this case that place is in fact the Lua. When the button is touched and if the Button has a name this value is set to true and then to false on release. We can use this to implement a fire mechanic in our game.

It should be noted here that it is possible for the button to be pressed and release before your game has a change to notice. This can be overcome by implementing a model change listener in your game alternatively link the button to send an Action to the game. This is guaranteed to happen and is a much cleaner solution. Use the pressed for things like fire.

So for our example lets assume we have a button named Fire and out player id is example_player

To access that value in Lua we would use the following code.

print(mode['Button.Fire.Pressed'])

You may note we didn’t say.

print(mode.Button.Fire.Pressed)

That is because this there is a single item with the key not a bunch of nested tables in Lua. This is important to understand for all model data.

How to read this model data in your game.

Unity

In the unity example below the code is expected to execute in your implementation of TableRealmsPlayerActionBehavior which has the function GetDeviceId() that would return the players id.

    public bool GetFire() {
        return TableRealmsModel.instance.GetData<bool>(GetDeviceID() + ".Button.Fire.Pressed");
    }

Unity Tiny

    public GetFire():boolean {
        return TableRealmsTiny.Model.GetData(TableRealmsTiny.P2PManager.GetMyInstanceID() + ".Button.Fire.Pressed");
    }

PlayCanvas

TODO:

Construct2/3

TODO:

Global

Global data is shared between all the systems. this means there should be one value for it in all places. In this case it is even more important then ever it has a single place where it will be set. Global data has the following attributes:

  • Has the same key in all places it is used.
  • Available for read/write in the host game.
  • Available for read/write in the client Lua.
  • Available for read/write in the client game.
  • If you are running a P3 game (Type of peer-to-peer mode) can be written in the client game.

Global Data example

In out game we wish to have a score we call this data score in the model.

In the Lua we can read this value as follows

print(mode['score'])

This will be available in all implementations of Lua. This value is only managed in the host game so there the score is calculated and set as follows.

Note that the score is only settable from the host game unless your client is running P3. If you are running P3 the value can be set from both (but for score that would be a disaster as they will clash over the network). The value is always readable from the client though.

Unity

    public int GetScore () {
        return TableRealmsModel.instance.GetData<int>("score");
    }

    public void SetScore (int score) {
        TableRealmsModel.instance.SetData("score", score);
    }

Unity Tiny

public GetScore():number {

       return TableRealmsTiny.Model.GetData("score");

   }    public SetScore (score:number) {

       TableRealmsTiny.Model.SetData("score", score);

   }

PlayCanvas

TODO:

Construct2/3

TODO:

Special Model data

In some cases we have added special data. This data is available to specific items only should only be read and is not strictly speaking part of the mode, but rather system data that is provided through the model.

Special mode data example

One example is qrcodeurl this value is available everywhere but should not be set. This is the url the game launched off. This can be useful if you wish to provide an additional QR code or share the URL through other means.


Now that the explanations are out of the way, let’s head into the model!

Player/Global Key Client Key In game Type ReadOnly Done Example Meaning
Special qrcodeurl qrcodeurl string yes This is the QR code URL that was used to start the game.
Special yourid string yes This is the ID of the player that is using the device. This is only set in embedded mode.
Special DESIGN_MODE bool yes This is true if you are running in the designer. Not set at all if not.
Special SELECTED_ITEM_ID float yes When in the Editor this is the ID of the correctly selected item. Used to display debugging information
Special instanceId instanceId string yes This is the instance id expected for the Lua server hosting assuming an instance is known at this point. No instance will default to the instance name {GameId}.Lobby. Also when you are running on the server this will be your instanceId. Since it is global it will be sent to players as they move from instance to instance.
Special arguments table yes This is an array (table with keys 1..) each paramater from the url in sequence added to this list.
Player id string yes 2 Players string id. This is sent from the game to the client. But the game model does not include this value.
Player latency {id}.latency long yes 80 The latency of that clients message processing. In ms
Player page {id}.page string Start The currently shown page for all. The page show will always be the last one set weather global or private
Player name {id}.name string yes Bob The player’s choosen name.
Player state {id}.state string yes Connecting The state of the communications.
Player playerIconB64 {id}.playerIconB64 string yes This is the player icon as a base64 string. If nil no player icon was supplied by the player.
Player loaded {id}.loaded float yes 0.5 How much of the design has been laoded by the game so far.
Player protocol {id}.protocol string yes Socket
Player designMd5 {id}.designMd5 string yes Set by the client at the start of the design phase. This enables the sever to see the client has the correct file and skip the download phase. Can be empty meaning no cached file. After loading will be set to the correct version from the client. (this is only needed if the client wants to save it.
Player localLoaded {id}.localLoaded bool yes Set by the Table Realms client environment when local variables have been loaded and all se in the model
Player onlineLoaded {id}.onlineLoaded bool yes Set by the Table Realms client environment when online variables have been loaded and all se in the model
Player savedModelDirty {id}.modelDirty bool yes This is true if the current model is dirty. (ie changed in Lua but not saved)
Player Button.{name}.Enabled {id}.Button.{name}.Enabled bool
Player Button.{name}.Pressed {id}.Button.{name}.Pressed bool
Player Slider.{name}.Enabled {id}.Slider.{name}.Enabled bool
Player Slider.{name}.Value {id}.Slider.{name}.Value float
Player ThumbStick.{name}.Enabled {id}.ThumbStick.{name}.Enabled bool
Player ThumbStick.{name}.Pressed {id}.ThumbStick.{name}.Pressed bool
Player ThumbStick.{name}.x {id}.ThumbStick.{name}.x float
Player ThumbStick.{name}.y {id}.ThumbStick.{name}.y float
Player Toggle.{name}.Enabled {id}.Toggle.{name}.Enabled bool
Player Toggle.{name}.Value {id}.Toggle.{name}.Value bool
Player Accelerometer.x {id}.Accelerometer.x float yes Acceleration force along the x axis (excluding gravity).
Player Accelerometer.y {id}.Accelerometer.y float yes Acceleration force along the y axis (excluding gravity).
Player Accelerometer.z {id}.Accelerometer.z float yes Acceleration force along the z axis (excluding gravity).
Player Velocity.x {id}.Velocity.x float yes
Player Velocity.y {id}.Velocity.y float yes
Player Velocity.z {id}.Velocity.z float yes
https://math.stackexchange.com/questions/381649/whats-the-best-3d-angular-co-ordinate-system-for-working-with-smartphone-apps
Player Orientation.x {id}.Orientation.x float yes
Player Orientation.y {id}.Orientation.y float yes
Player Orientation.z {id}.Orientation.z float yes
Player Orientation.w {id}.Orientation.w float yes
Player TouchPassthrough.{name}.{touchId}.x {id}.TouchPassthrough.{name}.{touchId}.x float yes
Player TouchPassthrough.{name}.{touchId}.y {id}.TouchPassthrough.{name}.{touchId}.y float yes
Player TouchPassthrough.{name}.{touchId}.pressed {id}.TouchPassthrough.{name}.{touchId}.pressed bool yes
Global players players string yes 52,123,453,652,132,100,000 A comma seperated list of player id’s currently connected to the game.
Global player.{id}.name player.{id}.name string yes Fred Each player in the game’s name. Shared to all devices and games.
Global player.{id}.state player.{id}.state string yes Connecting A specific player’s current connection status
Global player.{id}.loaded player.{id}.loaded float yes 0.5 A specific player’s current download status

  1. Floats are not sent immediately when changed. This is very important to understand. Because float values can be tied to events like screen touch (say for a thumbstick) they generate 60 changes for each axis per second. So with two on screen we generating 240 messages per second. With 4 players we have expanded that to almost 1k messages per second. This is unnecessary and causes a lot of bottlenecks. To fix this we only send model data changes every 1/16th of a second unless that float value has not changed for more then 1/16th of a second already.

    [return]