Multiplayer

From Blue Mars Developer Guidebook

Jump to: navigation, search

Back to Blue Mars Game Programming

Contents

Overview

The second half of this document is obsolete (beyond "High level API for minigame"). Please use higher level API: Multiplayer Minigame API

MMO object

The MMO object is defined globally by C++ script binding. You can use this object anywhere in Lua script. Note that MMO API requires a network connection and therefore should be tested in the client (Check city in BlueMars), rather than in the Editor's Preview Mode.


Game start hook

You can register some hook (callback) functions which allows you to do something when game is started.

MMO:RegisterStartCallback(thunk)

thunk is a function which has no parameters.

When the system finishes loading a level, the thunk will be called.


Example:

function ARMPMiniGameSample:OnInit ()
  MMO:RegisterStartCallback (function()
                               self:GameStart ()
                             end)
end

function ARMPMiniGameSample:GameStart ()
  MMO:DisableAutoAvatarSpawning()
  MMO:DisableVirtualWorldStateSync()

  System.SetCVar ("e_time_of_day", 14.75)

  ARMultiPlayerMiniGame.InitializeAndJoin(self, "ARMPMiniGameSample")
end


In this example, I register a hook function in OnInit method. OnInit method is called before the program finishes loading the level file. On the other hand, the hook function is called after the loading is complete, so now, you can start the game logic and join the minigame room on the server.


Setting the local character entity

To tell the MMO system the position of view (avatar), call SetLocalCharacterEntity() method.

MMO:SetLocalCharacterEntity(character_entity)

If you switch to a minigame from chat (from within a city) you don't need to call SetLocalCharacterEntity() since the entity is already set by chat system.


Getting local character data

As mentioned above, if an avatar is already walking around in a city, you can use the following function to get local character data from the chat system with the GetLocalCharacterData() method. In other words, this function returns data pertaining to the avatar of the logged-in user.

local localdata = MMO:GetLocalCharacterData()

This method returns a table like:

{
 Name = "Toru Hisai (toru)",
 NameWithoutShortName = "Toru Hisai",
 ShortName = "toru",
 AvatarID = "avt1234",
 ClientID = 1234,
 ChatColor = 0xffccff,
 Gender = "M",
 Entity = {... Entity Table ...}
}

Name: Full name and short name (user ID) in format "FIRSTNAME LASTNAME (SHORTNAME)"

NameWithoutShortName: Full name in format "FIRSTNAME LASTNAME"

NOTE: Name display option is applied to Name and NameWithoutShortName.

ShortName: User ID.

AvatarID: ID of the avatar which is unique in the world. Additionally, we use this name for entity name of the avatar. So you can get entity with EntityNamed() function like:

local ent = EntityNamed(localdata.AvatarID)

ClientID: ID number of the local client.

ChatColor: Color of the chat bubble in RGB 24bit integer.

Gender: Avatar's gender; "F" or "M".

Entity: Avatar's entity. See below for a short-cut function to directly grab this entity, MMO:GetLocalAvatarEntity().


Example: used in Golf.


Getting the local character entity

Use this function to grab the local avatar entity of the logged-in user

local ent = MMO:GetLocalAvatarEntity()


Enable/Disable avatar state syncing

MMO:DisableVirtualWorldStateSync() and MMO:EnableVirtualWorldStateSync() are obsolete. Use MMO:IsolateTemporarily() instead.

MMO:IsolateTemporarily (start_callback)

This function lets you get out of the current room to disable avatar synchronization and returns a function to get back to the original room.

Where start_callback is a callback function called when the client has left the room.

Example:

function callback()
  System.Log "Isolation mode start"
end

  local goback_func = MMO:IsolateTemporarily (callback)
  ... do something alone ...
  goback_func()  -- go back to the city


Show/Hide Chat UI - deprecated

 MMO:ShowChatUI()
 MMO:HideChatUI()

Original functionality: show and hide chat UI

NOTE: The Blue Mars chat UI steals all keyboard and mouse input.


High level API for minigame

Overview

Image:Master-player.png

ARMultiPlayerMiniGame is a framework for multiplayer minigame. This framework is based on the idea of "Game master-player" network.

You can implement the game master and player functions separately. Since this framework hides network data format and detail of data transfer, you don't need to think about them.


Match making system

See Minigame Matchmaking System

Image:Minigame-matchingsystem-dia.png

Preparation

On game start, call ARMultiPlayerMiniGame.InitializeAndJoin method.

function MyMiniGame:Start() 

  -- ...

  -- add multiplayer functionality and specify the room name
  ARMultiPlayerMiniGame.InitializeAndJoin (self, "MyMiniGame")
end

First argument is the minigame entity, usually "self" is OK. Second argument is the name of room to join.


Game master

Game master manages the flow of minigame. It receives state changes from each players. You can specify some condition which triggers events.


State data table

State data is a table which maps from key to value. Where key is a string and value can be number, string, boolean and table consist of these data types. Each player can update the value in the state table, then the Master can check the value and trigger some events.

You can directly access the table as

self.MP_Master.StateData

Image:State-table.png

The above figure shows a sample table. This sample shows that every player passed "Init" and "Title" state, and some player passwd "ShowCouse" state but other players didn't.


State update hanlder

When the game master received a state change data from a player, minigame entity's MP_OnRoomStateUpdate method is called.

function MyMiniGame:MP_OnRoomStateUpdate (avatar_id, key, value)

Where avatar_id is a string which specify the avatar, key is a state key, value is a state value. You can check the state and send event to player.

For convenience, there are some utility functions to know every player's state:

self.MP_Master:StateAllTrue (key)
self.MP_Master:StateAllFalse (key)
self.MP_Master:StateAnyTrue (key)
self.MP_Master:StateAnyFalse (key)

StateAllTrue() method returns true iff for all players the state indicated by key is true.

StateAllFalse() method returns true iff for all players the state indicated by key is false (not true).

StateAnyTrue() is equivalent to not StateAllFalse().

StateAnyFalse() is equivalent to not StateAllTrue().

NOTE: true means tha value is not false or nil. So number 0 and empty string are evaluated as true.

For example, if you want to wait until all players send the "state_ShowCourse" state, you can write like following:

if key == "state_ShowCourse" then
   if self.MP_Master:StateAllTrue (key) then
      self.MP_Master:SendEvent ({event = "gotostate", state = "WalkToPosition"})
   end
end


Event notification

Event data can contain name of event and optional data. This data can be number, string, boolean or table of these data type.

Use SendEvent method to send event data like:

self.MP_Master:SendEvent ({event = eventname[, data = ...}])

Event data is a table which contains at least "event" key. The value of "event" must be string.


Player

Sending state change data to game master

To send state change data, call SendState method:

self.MP_Player:SendState (statename, data)

Where statename is a string value, data can be a number, string, boolean or table of these data types.


Receiving room event from game master

Callback which is called when a room event is received from game master:

function MyMiniGame:MP_OnRoomEvent (data)

Data structure is same as event data from game master.


Broadcast data to all players

Player can send data to all players directly. It doesn't influence room status.

self.MP_Player:Broadcast (data)

When you receive message broadcast from a client, MP_OnBroadcast callback is called.

function MyMiniGame:MP_OnBroadcast (data)

Note that the data broadcasted will also be sent to the sender.


Summary

Image:Data-flow.png


Example

Here is an example script.


Code

ARMPMiniGameSample = {
  Properties = {
  },

  MP_Master = {},
  MP_Player = {},

  States = {
    "Stat0",
    "Stat1",
    "Stat2",
  },

  Editor = {
    Icon = "AR_Default.bmp",
  },
}

function ARMPMiniGameSample:OnInit ()
  System.Log("ARMPMiniGameSample:OnInit")

  MMO:RegisterStartCallback (function()
                               self:GameStart ()
                             end)
end

function ARMPMiniGameSample:GameStart ()
  System.Log("ARMPMiniGameSample:GameStart");    

  MMO:DisableAutoAvatarSpawning()
  MMO:DisableVirtualWorldStateSync()

  System.SetCVar ("e_time_of_day", 14.75)

  ARMultiPlayerMiniGame.InitializeAndJoin(self, "ARMPMiniGameSample")
end

-- master
function ARMPMiniGameSample:MP_OnRoomStateUpdate (avatar_id, key, value)
  System.Log ("ARMPMiniGameSample:MP_OnRoomStateUpdate: '"
              .. table.concat ({avatar_id, key, tostring (value)}, "', '") .. "'")
end

-- player
function ARMPMiniGameSample:MP_OnRoomEvent (data)
end

function ARMPMiniGameSample:MP_OnBroadcast (data)
  System.Log ("ARMPMiniGameSample:MP_OnBroadcast")
  dump (data)
end

function ARMPMiniGameSample:JoinCallback(numclients)
  self.num = numclients;
  self.ent = EntityNamed ("TakiVehicle" .. numclients)
  self:GotoState ("Stat0")

  if self.MP_IsMaster then
    -- set the "inProgress" global state
    self.MP_Master.GlobalState.inProgress = true
  end
end

ARMPMiniGameSample.Stat0 = {
  OnBeginState =
    function (self)
      System.Log ("ARMPMiniGameSample.Stat0")
      ARMultiPlayerMiniGame.QueryGlobalState (self, "inProgress",
                                              function (res)
                                                System.Log ("ARMPMiniGameSample.Stat0: Response!: "
                                                            .. tostring (res) .. ": " .. type (res))
                                                self:GotoState ("Stat1")
                                              end)
    end
}

ARMPMiniGameSample.Stat1 = {
  OnBeginState =
    function (self)
      System.Log ("ARMPMiniGameSample.Stat1")
      MMO:SetLocalCharacterEntity(self.ent)
      self.MP_Player:SendState ("stat1", true)

      MMO:ActivateUI()
      MMO:ShowChatUI()

      ARTextChat:LoadFlash()
      ARTextChat:ShowChat()
      ARTextChat:RegisterMinigameEntity (self)

      self.MP_Player:Broadcast ({broadcast = "BROADCAST MESSAGE!"})
    end
}

ARMultiPlayerMiniGame.SetMMOEventHandler (ARMPMiniGameSample)
Problems with this wiki page? Contact us either by: Support Email or Support Ticket System

Blue Mars Guidebook Privacy Policy
Blue Mars Guidebook Community Guidelines

Personal tools