...

Package field

import "github.com/Diarkis/diarkis/field"
Overview
Index

Overview ▾

Package field ▷

Creates virtual space where all connected users share the same space and time.

Field allows automated synchronization based on user coordinates in the field space.

[IMPORTANT] Field module can be used along side with Room, Group, and MatchMaker.

Configurations

Field configurations are explained below.

The configuration file must be provided for both the front server (UDP or TCP) and the target node server (Default is HTTP).

{
  "fieldSize": 377970000,
  "fieldOfVisionSize": 1800,
  "syncInterval": 50,
}

▶︎ Configuration Values

fieldSize - Default is 377970000

The surface area size of the entire world to be auto-divided across the server nodes.

fieldOfVisionSize - Default is 1800

It controls the field of vision that the each user can see. This value will NOT be greater than the grid size. When the grid size decreases as the number of grids increase, fieldOfVisionSize may decrease along with it if configured value is greater than the grid size. fieldOfVisionSize is calculated as radius.

syncInterval - Default is 50 ms

It controls the interval of sync or disappear propagation in milliseconds. The minimum value of it is 17 milliseconds. The lower the value is more frequent the propagation is, but with increased server load.

Controls the interval in milliseconds of propagation of sync data to the users that "see" each other. If Sync is called multiple times within the interval, only the last Sync will be propagated to the remote users.

How Field Works

Field divides the whole field defined by "fieldSize" into "grids". Each server in the Diarkis cluster is responsible for one or more "grids". "grids" represent field map based on X and Y coordinates.

▶︎ When the number of servers in the Diarkis cluster changes, the number of "grids"
  and their size change.

▶︎ Users in different "field of view" do not see each other.

▶︎ Moving to a different "grid" that is on another server will cause the user to re-connect.

Users "see" each other if they are in the same "grid".

○ = User with no other users in view
● = User with other users in view

┏━━━━┓
┃    ┃ = Grid
┗━━━━┛

┌────┐
│    │ = Field of Vision
└────┘

╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━━╋
┃  ┌───────┐  ┃             ┃  ○          ┃              ┃
┃  │●      │  ┃      ○      ┃             ┃       ○      ┃
┃  │ ●     │  ┃             ┃         ┌───╂───┐          ┃
┃  └───────┘  ┃             ┃ ○       │●  ┃ ● │        ○ ┃
╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━┿━━━╋━━━┿━━━━━━━━━━╋
┃             ┃┌───────┐    ┃       ○ └───╂───┘          ┃
┃      ○      ┃│   ●   │    ┃             ┃              ┃
┃             ┃│  ●  ● │    ┃             ┃          ○   ┃
┃             ┃└───────┘  ○ ┃     ○       ┃              ┃
╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━━╋
┃             ┃             ┃┌───────┐  ○ ┃     ○        ┃
┃       ○     ┃             ┃│●      │    ┃              ┃
┃             ┃             ┃│● ● ●  │    ┃              ┃
┃             ┃      ○      ┃└───────┘    ┃              ┃
╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━━╋
┃             ┃ ┌───────┐   ┃     ○       ┃       ○      ┃
┃             ┃ │  ●●● ●│  ○┃             ┃              ┃
┃   ○         ┃ │  ●● ● │   ┃         ┌───╂───┐          ┃
┃             ┃ └───────┘   ┃    ○    │  ●┃●  │   ○      ┃
╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━┷━━━╋━━━┷━━━━━━━━━━╋

▶︎ Users that are close, but in different "grids"

Users that are in different grids may be able to "see" each other as long as they fit within the field of vision (Configured by fieldOfVisionSize).

[IMPORTANT] Synchronizing with users across multiple grids will add extra server load.

  The field of vision spans across two grids.
        ╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋
        ┃         ┌───╂───┐   ○     ┃
        ┃         │  ●┃ ● │         ┃
        ┃         │ ● ┃●  │         ┃
        ┃ ○       └───╂───┘   ○     ┃
        ╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋

How Grids and Front Servers (UDP/TCP) Interact With Storage Servers (By default HTTP) For Sync and Disappear

Field servers are structured with two separate server components:

1. Front Servers - The front servers communicate the clients directly.

2. Storage Servers - The storage servers manage grids and calculate each users vision. By Default HTTP is used as storage servers.

 The field of vision that fits in a single grid.

 ╋━━━━━━━━━━━━━━╋
 ┃   ┌───────┐○ ┃
 ┃   │ ●     │  ┃
 ┃   │  ●    │  ┃
 ┃○  └───────┘  ┃
 ╋━━━━━━━━━━━━━━╋

  Storage server (By default HTTP) manages grids and user visions.
  Every Sync will be propagated from the front servers to the storage servers (storage server address is resolved from the grid identifier key).
  The storage servers then retrieves the list of users and propagate Sync or Disappear data to appropriate front servers.

  [ NOTE ] Each storage and front server has their own sync loop.
  [ NOTE ] Key (Grid identifier) is created from the user coordinate.

      ┌─────────┐
      │ Storage ├─────────┬────────────┐
      └─────────┘         │            │
          ▲      [ Propagation of Sync or Disappear ]
          │               │            │
[ Sync or Disappear ]     │            │
          │               ▼            ▼
     ┌────┴────┐     ┌─────────┐  ┌─────────┐
     │  Front  │     │  Front  │  │  Front  │
     └─────────┘     └─────────┘  └─────────┘

How Users Across Multiple Grids Are Synchronized

 The field of vision spans across two grids.

       ╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋
       ┃         ┌───╂───┐   ○     ┃
       ┃         │  ●┃ ● │         ┃
       ┃         │ ● ┃●  │         ┃
       ┃ ○       └───╂───┘   ○     ┃
       ╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋

 If the field of vision spans across multiple grids,
 We synchronize multiple storage servers and propagate Sync data accordingly.
 More field of vision overlaps with different grids, the more storage servers need to be involved for Sync.

[NOTE] A single storage server may contain multiple grids.

       ┌────────────────────────────────────────────────────┬────────────┐
       │                                                    │            │
       │                                                    │            │
       │                                                    │            │
       │             ┌────────────┬────────────┐            │            │
       │             │            │            │            │            │
  ┌────┴────┐   ┌────┴────┐       │            │            │            │
  │ Storage │   │ Storage │       │            │            │            │
  └─────────┘   └─────────┘       │            │            │            │
      ▲              ▲            │            │            │            │
      └──────┬───────┘         [ ---- Propagation of Sync or Disappear ---- ]
             │                    │            │            │            │
   [ Sync or Disappear ]          │            │            │            │
             │                    ▼            ▼            ▼            ▼
        ┌────┴────┐          ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
        │  Front  │          │  Front  │  │  Front  │  │  Front  │  │  Front  │
        └─────────┘          └─────────┘  └─────────┘  └─────────┘  └─────────┘

Setting up Field Module

In order to use Field, you must invoke field.Setup() before calling diarkis.Start().

You must call field.Setup() in front servers (By default UDP and/or TCP) and storage servers (By default HTTP).

Optional Configurations for Field internal storage

Field module has internal storage to store user locations (who is on which server). The storage has multiple optional configurations.

storageTargetNodeType     - Target node type determines the storage to use which servers as storage: Default is HTTP

storageMigration          - Enables or Disables key migration when scaling: Default is true

storageMigrationBatchSize - Number of keys to be batched and migrated at a time.
                            Setting is value large will make the migration time shorter,
                            but setting the value too large may cause each migration packet to split and slow down the migration instead:
                            Default is 10.

storageMigrationInterval  - Interval in milliseconds for each migration batch (server-to-server key transfer) to be sent: Default is 1ms
                            Longer this value is the longer it takes to complete migration, but less server stress.

SyncLimit

Sync function has a parameter called syncLimit. This parameter controls how many Sync/Disappear packets you want to receive at once.

If you set syncLimit to 10, then you will not receive more than 10 Sync/Disappear packets at once. This allows you to control up to how many remote users you want to "see". With the example of syncLimit=10, this will makes sure that you will not "see" more than 10 remote users at a time.

Maximum Data Size For Sync

Each Sync call allows byte array to be synchronized with the users in sight. There is a size limit to the byte array per Sync call.

[IMPORTANT] Larger the data size is the higher the server stress.

Maximum allowed size - 3000 bytes

Index ▾

func AddUserPositionValidation(validator func(*user.User, int64, int64, int64) bool)
func AfterDisappearCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func AfterLeaveCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func AfterSyncCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func BeforeDisappearCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func BeforeLeaveCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func BeforeSyncCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func CalcDistance(myX, myY, yourX, yourY int64) int64
func Disappear(userData *user.User)
func ExposeCommands()
func GetFieldOfVisionSize() int64
func GetFieldSize() int64
func GetGridKeyByNodeType(x, y int64, nodeType string) string
func GetGridKeyByPosition(x, y, z int64) string
func GetGridSize() int64
func GetNodeNum() int
func GetNumberOfGrids() int
func GetUserPosition(userData *user.User) (int64, int64, int64)
func Join(userData *user.User, x, y, z int64, data []byte, syncLimit int, filterID uint8, reliable bool) error
func Leave(userData *user.User) error
func SetCustomFilter(customFilterID uint8, filter FilterCallback)
func Setup(confpath string)
func Sync(userData *user.User, x, y, z int64, data []byte, syncLimit int, filterID uint8, reliable bool) error
type FilterCallback
type MeshData

func AddUserPositionValidation

func AddUserPositionValidation(validator func(*user.User, int64, int64, int64) bool)

AddUserPositionValidation registers a validation function to be called on Sync

[IMPORTANT] This function can be used ONLY on the front servers (UDP or TCP).

validator - Custom function to be invoked for position validation.

func AfterDisappearCmd

func AfterDisappearCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))

AfterDisappearCmd registers a command to be executed after field disappear: Must be called before ExposeCommands()

Parameters

ver      - Command ver sent from the client.
cmd      - Command ID sent from the client.
payload  - Command payload sent from the client.
userData - User data representing the client that sent the command.
next     - The function to signal the command to move on to the next operation of the same ver and command ID.
           This function must be called at the end of all operations in the callback.
           If you pass an error, it will not proceed to the next operations of the same command ver and ID.

func AfterLeaveCmd

func AfterLeaveCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))

AfterLeaveCmd registers a command to be executed after field leave: Must be called before ExposeCommands()

Parameters

ver      - Command ver sent from the client.
cmd      - Command ID sent from the client.
payload  - Command payload sent from the client.
userData - User data representing the client that sent the command.
next     - The function to signal the command to move on to the next operation of the same ver and command ID.
           This function must be called at the end of all operations in the callback.
           If you pass an error, it will not proceed to the next operations of the same command ver and ID.

func AfterSyncCmd

func AfterSyncCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))

AfterSyncCmd registers a command to be executed after field sync: Must be called before ExposeCommands()

Parameters

ver      - Command ver sent from the client.
cmd      - Command ID sent from the client.
payload  - Command payload sent from the client.
userData - User data representing the client that sent the command.
next     - The function to signal the command to move on to the next operation of the same ver and command ID.
           This function must be called at the end of all operations in the callback.
           If you pass an error, it will not proceed to the next operations of the same command ver and ID.

func BeforeDisappearCmd

func BeforeDisappearCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))

BeforeDisappearCmd registers a command to be executed before field disappear: Must be called before ExposeCommands()

Parameters

ver      - Command ver sent from the client.
cmd      - Command ID sent from the client.
payload  - Command payload sent from the client.
userData - User data representing the client that sent the command.
next     - The function to signal the command to move on to the next operation of the same ver and command ID.
           This function must be called at the end of all operations in the callback.
           If you pass an error, it will not proceed to the next operations of the same command ver and ID.

func BeforeLeaveCmd

func BeforeLeaveCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))

BeforeLeaveCmd registers a command to be executed before field leave: Must be called before ExposeCommands()

Parameters

ver      - Command ver sent from the client.
cmd      - Command ID sent from the client.
payload  - Command payload sent from the client.
userData - User data representing the client that sent the command.
next     - The function to signal the command to move on to the next operation of the same ver and command ID.
           This function must be called at the end of all operations in the callback.
           If you pass an error, it will not proceed to the next operations of the same command ver and ID.

func BeforeSyncCmd

func BeforeSyncCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))

BeforeSyncCmd registers a command to be executed before field sync: Must be called before ExposeCommands()

Parameters

ver      - Command ver sent from the client.
cmd      - Command ID sent from the client.
payload  - Command payload sent from the client.
userData - User data representing the client that sent the command.
next     - The function to signal the command to move on to the next operation of the same ver and command ID.
           This function must be called at the end of all operations in the callback.
           If you pass an error, it will not proceed to the next operations of the same command ver and ID.

func CalcDistance

func CalcDistance(myX, myY, yourX, yourY int64) int64

CalcDistance calculates distance using triangle

     ┌───────────────▶︎ (Me)
     │                ╱│
     │               ╱ │
     │              ╱  │
Distance           ╱   │ Y
     │            ╱    │
     │           ╱     │
     │          ╱    ┏━┥
     └──▶︎ (You) ─────┸─┘
                  X

Parameters

myX   - X coordinate to calculate the distance against yourX.
myY   - Y coordinate to calculate the distance against yourY.
yourX - X coordinate to calculate the distance against myX.
yourY - Y coordinate to calculate the distance against myY.

func Disappear

func Disappear(userData *user.User)

Disappear removes the user from the user entity list to stop from synchronization.

[IMPORTANT] This function is the alias for Leave
[IMPORTANT] This function can be used ONLY on the front servers (UDP or TCP).

Parameters

userData  - User that will propagate the synchronization the data to the users in view.

func ExposeCommands

func ExposeCommands()

ExposeCommands exposes commands to the client to work with Field package

func GetFieldOfVisionSize

func GetFieldOfVisionSize() int64

GetFieldOfVisionSize returns the current field of view size.

func GetFieldSize

func GetFieldSize() int64

GetFieldSize returns the current field size.

func GetGridKeyByNodeType

func GetGridKeyByNodeType(x, y int64, nodeType string) string

GetGridKeyByNodeType returns the calculated grid key based on X and Y coordinate given.

Deprecated

This function has been deprecated and should not be used.

[IMPORTANT] Use GetGridKeyByPosition instead.

func GetGridKeyByPosition

func GetGridKeyByPosition(x, y, z int64) string

GetGridKeyByPosition returns the grid key based on X, Y, and Z coordinate.

func GetGridSize

func GetGridSize() int64

GetGridSize returns the size of a grid.

func GetNodeNum

func GetNodeNum() int

GetNodeNum returns the number of grid storage servers

func GetNumberOfGrids

func GetNumberOfGrids() int

GetNumberOfGrids returns the current number of grids.

func GetUserPosition

func GetUserPosition(userData *user.User) (int64, int64, int64)

GetUserPosition returns the given user's current coordinate: X, Y, and Z.

[IMPORTANT] This function can be used ONLY on the front servers (UDP or TCP).
[IMPORTANT] This function uses mutex lock on userData internally.

func Join

func Join(userData *user.User, x, y, z int64, data []byte, syncLimit int, filterID uint8, reliable bool) error

Join initializes the user. The user must "Join" the Field in order to use Sync, Disappear, and Leave.

[IMPORTANT] This function can be used ONLY on the front servers (UDP or TCP).

[NOTE] Z space is not a coordinate, but it describes dimension or space.
       For example, users with the same x and y with different z will not "see" each other.

Parameters

userData  - User that will propagate the synchronization the data to the users in view.
x         - X position of the user to synchronize.
y         - Y position of the user to synchronize.
z         - Z space of the user to synchronize.
data      - Synchronize byte array data.
            The data byte array must NOT be empty.
syncLimit - Maximum number of the sync and disappear packets the user allows to receive.
            This limit applies to the packets the user receives NOT the packets the user sends.

func Leave

func Leave(userData *user.User) error

Leave allows the user to cleanly leave from the Field and resets all Field data of the user.

[IMPORTANT] This function can be used ONLY on the front servers (UDP or TCP).

Parameters

userData  - User that will propagate the synchronization the data to the users in view.

func SetCustomFilter

func SetCustomFilter(customFilterID uint8, filter FilterCallback)

SetCustomFilter defines a custom filter that will be invoked when user client indicates while synchronizing. The purpose of the filter is to manipulate the users in sight for synchronizing.

[IMPORTANT] Custom callbacks are executed on the front node servers (UDP or TCP).
[IMPORTANT] The callback will have both sender and receiver UID, however, the sender user data is not be accessible from the callback.

[NOTE]      If the callback returns false, the receiver will NOT receive the synchronizing message.

Parameters

customFilterID - Unique ID to identify the custom filter.
filter         - Custom operation function to perform filtering.

func Setup

func Setup(confpath string)

Setup setup Field module.

Parameters

confpath - Absolute path of the configuration file to be loaded.

func Sync

func Sync(userData *user.User, x, y, z int64, data []byte, syncLimit int, filterID uint8, reliable bool) error

Sync updates synchronization data.

[IMPORTANT] This function can be used ONLY on the front servers (UDP or TCP).

[NOTE]      Z space is not a coordinate, but it describes dimension or space.
            For example, users with the same x and y with different z will not "see" each other.

Parameters

userData  - User that will propagate the synchronization the data to the users in view.
x         - X position of the user to synchronize.
y         - Y position of the user to synchronize.
z         - Z space of the user to synchronize.
data      - Synchronize byte array data. maximum allowed length is 3000 bytes
            The data byte array must NOT be empty.
syncLimit - Maximum number of the sync and disappear packets the user allows to receive.
            This limit applies to the packets the user receives NOT the packets the user sends.

type FilterCallback

FilterCallback is a callback to decide if you want to send a sync message to the receiver user or not.

type FilterCallback func(receiverUser *user.User, senderUID string, distance int64, cmd uint16, payload []byte) bool

type MeshData

MeshData represents internally used data transport

type MeshData struct {
    Packed []byte `json:"p"`
    sync.RWMutex
}