...

Package field

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

Overview ▾

Package field ▷

Allows the users to connect in the same world MMO-style without server separation. Extremely low-latency and scalable. Easy to maintain as it auto-scales.

[IMPORTANT] Diarkis Field can NOT be used with Diarkis Room.
[IMPORTANT] Diarkis Field can NOT be used with Diarkis MatchMaker.
[IMPORTANT] There is a known edge case with position value calculation with negative values.
            If x and/or y are negative, it they will not be considered within the field of vision with positive values.

Field module requires the user client to re-connect to different servers, therefore it is not suitable to be used with other modules that also require the user client to re-connect or sensitive to user re-connection.

Configurations

Field configuratiuons are explained below.

{
  "syncInterval": 17,
  "allowMinusInMap": true,
  "fixedGridNumber": 0,
  "fieldSize": 377970000,
  "fieldOfVisionSize": 1800,
  "syncLimitOnDiscard": 50
}

▶︎ Configuration Values

syncInterval - Default is 100 ms

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.

allowMinusInMap - Default is true

If true, the map will have both positive negative coordinates.

fixedGridNumber - Default is 0

If fixedGridNumber is greater than 0, Field will be in "fixed-grid-number" mode where the number of grids does NOT change according to the number of server nodes. The value of fixedGridNumber's squre root must be a whole number, so the valid value for fixedGridNumber would be:

4, 9, 16, 25, 36, 49 64, 81 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400...

fieldSize - Default is 377970000

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

fieldOfVisionSize - Default is 1800

This is the size of field of vision. The field of vision does not change and remains the same for all clients.

syncLimitOnDiscard - Default is 50

Limit of how many other clients to sync on user discard (disappearance packet).

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 "grid" do not see each other.

▶︎ Users in the same "grid", but outside of "fieldOfVisionSize" 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 a same "grid" and within "fieldOfVisionSize".

○ = 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"

Since Field calculates based on "grids", if the users are in different "grids", regardless of the distance between them, they will not be able to "see" each other.

Diagram below shows a case for such condition:

     Grid 1        Grid 2
┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃            ○┃○◀︎───────────┃────┐
┃            ▲┃             ┃    ├─── These two users do NOT see each other
┃            │┃             ┃    │    bacause they are in different "grids".
┃            └┃─────────────┃────┘
┗━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛

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 AfterSyncCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func AfterSyncInitCmd(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 BeforeSyncCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func BeforeSyncInitCmd(callback func(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)))
func CalcDistance(myX, myY, yourX, yourY int64) int64
func CalculateField(nodeNum int) (int, int64)
func Disappear(userData *user.User, syncLimit int)
func ExposeCommands()
func GetGridKeyByNodeType(x, y int64, nodeType string) string
func GetGridRangeByGridKey(gridKey string) (int64, int64, int64, int64)
func GetGridSize() int64
func GetGrids() []string
func GetNodeGridID() string
func GetNodeGridIDName() string
func GetServerSyncLimit() int
func GetUserPosition(userData *user.User) (int64, int64, int64)
func IsInSight(myX, myY, yourX, yourY int64) bool
func IsUserInSight(mySID, otherSID string) bool
func IsWS()
func LoadConfig(confpath string)
func PrintGridLayout(gl *GridLayout)
func Reconnect(meshEndPoint string, userData *user.User, callback func(error, string))
func SetCustomFilter(customFilterID uint8, filter FilterCallback)
func SetOnGridUpdated(callback func([]string))
func Setup(confpath string)
func Sync(userData *user.User, x, y, z int64, syncLimit int, filterID uint8, msg []byte, respond bool, reliable bool) (string, [][]byte)
type FilterCallback
type GridData
    func GetMyGrids() []*GridData
    func (gd *GridData) GetKey() string
    func (gd *GridData) GetPosition() (int64, int64)
type GridLayout
    func NewGridLayout(gd *GridData, parent *GridLayout) *GridLayout
    func (gl *GridLayout) Add(gd *GridData)
type UserEntity
    func (ue *UserEntity) GetCoordinates() (int64, int64)
    func (ue *UserEntity) GetDistance() int64
    func (ue *UserEntity) GetID() string
    func (ue *UserEntity) GetSID() string

func AddUserPositionValidation

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

AddUserPositionValidation registers a validation function to be called on Sync

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 opeartions 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 opeartions of the same command ver and ID.

func AfterSyncInitCmd

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

AfterSyncInitCmd 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 opeartions 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 opeartions 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 opeartions of the same command ver and ID.

func BeforeSyncInitCmd

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

BeforeSyncInitCmd 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 opeartions 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 calculage the distance against myY.

func CalculateField

func CalculateField(nodeNum int) (int, int64)

CalculateField [INTERNAL USE ONLY]

func Disappear

func Disappear(userData *user.User, syncLimit int)

Disappear removes the user client from field map

userData  - User that will be disappear.
syncLimit - Maximum number of remote users to synchronize the disappearance.

func ExposeCommands

func ExposeCommands()

ExposeCommands exposes commands to the client to work with Field package

func GetGridKeyByNodeType

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

GetGridKeyByNodeType returns the calculated grid key of the node type given.

func GetGridRangeByGridKey

func GetGridRangeByGridKey(gridKey string) (int64, int64, int64, int64)

GetGridRangeByGridKey returns grid range of x and y. This function works only with grids of the node.

[NOTE] Uses mutex lock internally.

Returned Values:

return x1, x2, y1, y2

Grid key is obtained by GetGrids()

gridKey - Target grid key to retrive the grid positions.

func GetGridSize

func GetGridSize() int64

GetGridSize returns the size of the grid

func GetGrids

func GetGrids() []string

GetGrids returns a list of grids the node is assigned to

func GetNodeGridID

func GetNodeGridID() string

GetNodeGridID returns the node ID based on its own grid keys

[NOTE] Uses mutex lock internally.

func GetNodeGridIDName

func GetNodeGridIDName() string

GetNodeGridIDName returns node grid ID

func GetServerSyncLimit

func GetServerSyncLimit() int

GetServerSyncLimit returns serverSyncLimit

func GetUserPosition

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

GetUserPosition returns the current user position: x, y, z

[NOTE] Uses mutex lock internally.

Parameters

userData - Target user to retrieve the positions of.

func IsInSight

func IsInSight(myX, myY, yourX, yourY int64) bool

IsInSight returns true if my bounds overlaps with your X and Y point

func IsUserInSight

func IsUserInSight(mySID, otherSID string) bool

IsUserInSight evalutes if the remote user is in sight or not

[NOTE] Uses mutex lock internally.

Parameters

mySID    - Target SID of the user to check if the other user is in sight or not.
otherSID - Target SID of the other user to check if my user is in sight or not.

func IsWS

func IsWS()

IsWS called internally by commands.go

func LoadConfig

func LoadConfig(confpath string)

LoadConfig loads configuration file.

func PrintGridLayout

func PrintGridLayout(gl *GridLayout)

PrintGridLayout prints the grid layout into standard out

func Reconnect

func Reconnect(meshEndPoint string, userData *user.User, callback func(error, string))

Reconnect returns the end point of the node for the client to reconnect to

[NOTE] Uses mutex lock internally.

Parameters

meshEndPoint - Internal server address to direct the user for reconnection.
userData     - Target user to direct the reconnection.
callback     - Callback to be invoked when server operation of reconnection is completed.

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.

customFilterID - Unique ID to identify the cuntom filter.
filter         - Custom operation function to perform filterting.

func SetOnGridUpdated

func SetOnGridUpdated(callback func([]string))

SetOnGridUpdated registers a callback function on grid map updated.

[CRITITALLY IMPORTANT] Using pointer variables that are defined outside of the callback closure
                       in the callback closure will cause those pointers to be not garbage collected leading to memory leak.

[NOTE] Uses mutex lock internally.

The callback receives grid x1, y1 and grid x2, y2.

Each node has two sets of grid x and y

callback - Callback to be invoked when grids are updated.

func Setup

func Setup(confpath string)

Setup setup Field module

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

func Sync

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

Sync updates its own position and find others within the sight (fieldOfVisionSize) - z is used as a literal value instead of range like x and y. Use z value to create "different" area.

[NOTE] Uses mutex lock internally.

Returned Values

meshNodeEndPoint, usersInSight, usersNotInSight, userMessageListInsight

Parameters

userData  - User that will be synchronize the data.
x         - X position of the user to synchronize.
y         - Y position of the user to synchronize.
z         - Z space of the user to synchronize.
syncLimit - Maximum number of users to synchronize with.
msg       - Synchronize byte array data.

[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.

type FilterCallback

FilterCallback is a callback to decide if you want to send a sync messge to the receiver user or not. func(senderUserData, receiverUserData, senderX, senderY, receiverX, receiverY) bool

type FilterCallback func(*user.User, *user.User, int64, int64, int64, int64) bool

type GridData

GridData grid data with size and coordinate

type GridData struct {
    // contains filtered or unexported fields
}

func GetMyGrids

func GetMyGrids() []*GridData

GetMyGrids returns an array of grids of the node

[NOTE] Uses mutex lock internally.

func (*GridData) GetKey

func (gd *GridData) GetKey() string

GetKey returns the unique key of the grid

func (*GridData) GetPosition

func (gd *GridData) GetPosition() (int64, int64)

GetPosition returns X and Y coordinate of the grid

x, y := gd.GetPosition()

type GridLayout

GridLayout is a representation of the layout of grids

type GridLayout struct {
    N      *GridLayout
    E      *GridLayout
    S      *GridLayout
    W      *GridLayout
    Parent *GridLayout
    Root   *GridData
}

func NewGridLayout

func NewGridLayout(gd *GridData, parent *GridLayout) *GridLayout

NewGridLayout creates a new GridLayout

func (*GridLayout) Add

func (gl *GridLayout) Add(gd *GridData)

Add adds a GridData to GridLayout

type UserEntity

UserEntity a user data structure

type UserEntity struct {
    // contains filtered or unexported fields
}

func (*UserEntity) GetCoordinates

func (ue *UserEntity) GetCoordinates() (int64, int64)

GetCoordinates returns the X,Y position of UserEntity

func (*UserEntity) GetDistance

func (ue *UserEntity) GetDistance() int64

GetDistance returns the distance between the user and you

func (*UserEntity) GetID

func (ue *UserEntity) GetID() string

GetID returnns the user ID of the user

func (*UserEntity) GetSID

func (ue *UserEntity) GetSID() string

GetSID returns SID of the user