Title
Create new category
Edit page index title
Edit category
Edit link
Green logic game integration
In order to start game on dev02 env with the custom script, use url: https://ngp.dev02-gs-stakelogic.com/play
playerId = player with this id must be created on stakelogic test platfrom before this
gameId is provided by StakeLogic
platform - desktop, mobile
Client-server protocol
GC - game client.
GS - game server.
1. Basic information
• Communication is based on HTTP. Request is sent as JSON in request body in POST request. Response is sent as JSON in response body.
• Casino platform provides to GC an URL that must be used as endpoint for all communication with GS. This URL is later in this document referenced as $GAME_SESSION_URL.
• Protocol is using 1 universal request-response structure that contains multiple independent channels (Game, Operational, Configuration, Jackpot, Social). Operation channel may influence other channels while other channels are independent each with other.
• If any of attributes is null or empty it doesn’t have to be in JSON at all.
2. Request – response protocol
Idea behind having single request-response method for all calls is to spare unnecessary requests between GC and GS. Request and response consist of several channels:
• Game channel is used to send input events from client and receive game events from server as they are defined in game-event protocol. Also wallet data are transferred in game channel as this data are required during game-play. Jackpot wins are part of game channel as this wins are results of playing game.
• Operational channel is used to initialization and termination of whole game client.
• Jackpot channel is used to update current jackpot values.
• Configuration channel is used to save and load configuration parameters (key-value).
There are some general rules how this protocol should be used:
• Requests from GC may have its number (id attribute) that is increased by 1 with each new request.
- Requests that have id set are used to transfer important information that must be confirmed before game client can continue (order is important). Therefore GC must not send next request before it receives valid response from previous request. With this rule GC and GS can rely that their important data has been received by opposite site what makes algorithms much easier and deterministic. If communication between GC and GS fails, GC must retry by sending exactly same request. If GS receives request that has been already processed, responds with same response as when was request processed or with special status that particular request is just being processed.
- For some requests order of delivering them to GS is not important. Those requests can be sent without id. Original idea is use such as request for heartbeat requests or confirm request or request jackpot value so GC remains free to send input request as soon as player presses spin button.
• Game client starts communication with request with operation.init attribute set to true. We recommend to combine same request with game.init and configuration.init and jackpot.init attributes set to true. In response GC gets:
list of game events needed to setup GC to state ready for play
current player’s wallet + wallet after last bet
player’s locale
game-specific JS library
configuration parameters saved during previous game session
• After initializing GC interacts with player. When player triggers input event (button pressed), GC sends request using game channel (input set).
• When GC animates all events (or reasonable long block of events) to player, it is supposed to send confirm request via game channel. It is recommended to send this request without using request id.
• If player wasn’t active for certain period of time, GC sends heartbeat request to let GS know that it’s still active. Heartbeat request is request with game channel with all attributes null. GS responds with actual wallet status.
• All other channels may be used at will. We recommend to ask with each input and heartbeat (channel in request must not be null to be responded). Jackpot channel can be used in order to get current jackpot value with each request.
Game client full request structure
xxxxxxxxxx/** * Game client starts with id=1. Game client must retry same request until it gets valid response from server. Then * it can send another request with requestNumber+1. * * Request id might be null if request doesn't contain some specific sections (input, forfeit, save * configuration,...) If id is null, requests can be sent asynchronously and game client can send another request * (with id set) without getting response to previous request. */ id : number; /** * Client date and time when was this message generated (for logging purposes) */ date : Date; /** * Part of request related to state of game. */ game : {...} /** * Part of request related to overall state of game client */ operation {...} /** * Part of request related to configuration parameters */ configuration: { /** * When set to true, GS responds with current configuration for current player */ init: boolean; /** * Maps that allow Game Client to save configuration parameters for future game clients. * * This attribute can be used only in requests with ID set */ save {...} /** * Part of request related to jackpot */ jackpot: {...} /** * Part of request related to leaderboards */ leaderboard: {...} /** * Part of request related to gamble */ gamble: {...} /** * When game client is in replay mode, it sends request via replay channel to replay game session/round */ replay: {...}Game client full response structure
xxxxxxxxxx/** * Id of request message or null if request message or null if request was without id. */ id: number; /** * Date of request to which is this response generated. * Note that if you make another request with id of request t * hat was already responded, you get the original response with original response date. */ date: Date // pattern = "yyyy-MM-dd'T'HH:mm:ss.sss'Z'" /** * Specifies error code and error message if request wasn't processed OK */ status: {...} /** * Section with game-related data. It is set if request contained not-null game section. */ game: {...} jackpot: {...} gamble: {...} operation: {...} configuration: {...} replay: {...} leaderBoards: [...]Server response status codes
OK, /** * Unexpected error in game server that couldn't be resolved inside game server. * State of processing of request is unknown. Game client should do retry of same request. * Game server will do the best to not throw this error */ INTERNAL_SERVER_ERROR, /** * Structural validation of request has failed and therefore request won't be responded. */ INVALID_REQUEST, /** * First request id (from same game client) must be 1 and then it must be increased by 1. Also client can't send * next request before it gets valid response to previous request. */ INVALID_REQUEST_ID, /** * Defence code in game session url is invalid => game clien should be closed from security reasons */ INVALID_DEFENCE_CODE, /** * Game session does not exist, game client should be closed from security reasons */ UNKNOWN_GAME_SESSION, /** * Game session is already closed. Game client should display message that session is finished. */ GAME_SESSION_CLOSED, /** * Game client has been already closed and therefore no new requests are going to be responded */ GAME_CLIENT_CLOSED, /** * Another game client has been initialized therefore no more requests from previous game client will be accepted */ GAME_CLIENT_OBSOLETE, /** * Game that is supposed to be loaded is restricted in country from which is player playing (according to IP address * database) */ GAME_RESTRICTED_IN_COUNTRY, /** * Returned when there is communication problem between game server and casino platform. * Casino is either permanently not responding or it's responding with invalid response. * When this response was returned it means that input was consumed without proceeding in game. */ CASINO_PLATFORM_INTEGRATION_ERROR, /** * Same request is just being processed by game server, retry later to get original response (after game server * finishes its procesiing) */ REQUEST_IN_PROCESSING, /** * Returned when requested stake doesn't match limits set by server or game. */ INVALID_STAKE_VALUES, /** * Returned when game server can't place stake in same structure as requested by game client. * This response prevents user to unintentionally bet other funds type than presented to him in game client */ FUNDS_STRUCTURE_CHANGED, /** * Returned when there are not enough funds available at casino to make this round. * Note that response in this case contains attribute game.currentWallet set and * this wallet should be presented to player as actual funds structure. */ INSUFFICIENT_FUNDS, /** * Returned when bet limits for the game has been changed. * Game client must to reconfigure the lines, betperlines, denoms and bet modes * when it gets this response code. * Game events which should be processed to reconfigure the game client are * sent in game.events attribute (there should be one conf_enter event there). */ GAME_LIMITS_RECONFIGURED;2.1 Init a game
Game client sample request
xxxxxxxxxx{ "id" : null, "date" : "2018-04-23T18:25:43.511Z", "operation" : { "init": true }}Game client sample response
xxxxxxxxxx{ "id": null, "date": "2018-07-31T08:54:20.020Z", "status": { "code": "OK", "message": null, "externalCode": null, "externalMessage": null }, "game": null, "jackpot": null, "operation": { "game": { "brand": "relax", "platform": "desktop", "resolution": null, "mode": "credits" }, "player": { "locale": "en_US", "sounds": null }, "casino": { "brand": "testing_casino_demo" }, "gameScriptUrl": "https://cdn.../dragonsmystery.js", "closeGameClient": false, "gamebrand": "relax", "realityCheck": null, "loggingServiceUrl": "http://ngs.../api/log/" }, "configuration": null, "replay": null}2.2 Game play
Game client sample request
xxxxxxxxxx{ "id" : 4, "date" : "2015-04-23T18:25:43.511Z", "game" : { "init" : false, "input" : { "event" : { "type" : "evt_button_push", "button" : "btn_start", "lines" : "10", "betpl" : "2", "coinv" : "1" }, "currentWallet" : { ... }, }, "confirm" : { "count" : 5, "gameStepNo" : 431 }}, "operation" : { "init" : true, "exit" : false }, "configuration" : { "init" : false, "save" : { "general" : { "disableSounds" : true }, "game" : { "skipIntro" : true }}}, "jackpot" : { "init" : false, "timestamp" : "2015-04-23T18:25:43.511Z" }}Game client sample response
xxxxxxxxxx{ "id" : 3, "status" : { "code" : "OK", "message" : null }, "game" : { "gameStepNo" : 437, "events" : [ …. ], "numberOfAnimatedEvents" : 5, "walletAfterLastBet" : { …... }, "currentWallet" : { "currencySymbol" : "€", "currencyCode" : "EUR", "rm" : 452.20, "fm" : null, "bonuses" : [{ "id" : 411675, "amount" : 23.45, "priority" : 2.5, "forfeitable" : false }], "freeRounds" : { "id" : 421356, "available" : 5, "total" : 15, "priority" : -1, "forfeitable" : true, "totalWin" : 45.27, "bet" : 40, "roundConfig" : { "denom" : 10, "bpl" : 2, "lines" : 40, "bmode" : 0 }, } }, "messagesBeforeGameEvents" : null, "messagesAfterGameEvents" : null, "jackpotWins" : [{ "level" : 2, "gameFeatureJackpot" : true, "valueInPlayersCurrency" : 2415.37, "value" : 2415.37, "currencySymbol" : "€", "currencyCode" : "EUR" }], }, "jackpot" : { "values" : [{ "level" : 1, "value" : 45213.14 }], "timestamp" : "2015-04-23T18:25:43.511Z" }, "configuration" : { "general" : { "disableSounds" : true }, "game" : { "skipIntro" : "true", "defaultCoinValue" : "1", "defaultBetPerLine" : "10", } }, "operation" : { "gameScriptUrl" : "http://......../jokersFortune_v5142.js", "locale" : "en_UK", "closeGameClient" : false, "messages" : [{ "message" : "Do you want to try luck for real money?", "hasButton" : true, "buttonTitle" : "Deposit money", "buttonLink" : "http://......... ", }] }}Game wrapper
Events from game wrapper:
in - event from gcw to game client
out - event from game client to gcw
// Game preparation. // Can include: canvas creation, communication service initialization, // loading initial setup from server, assets loading, graphics preparation // { // containerElement: HTMLElement, // gameSessionUrl: string, // initConf: gcw.api.InitConf, // replayConf?: gcw.api.ReplayConf // } static INITIALIZE = 'INITIALIZE'; // in static INITIALIZE_SUCCESS = 'INITIALIZE_SUCCESS'; // out static INITIALIZE_FAILURE = 'INITIALIZE_FAILURE'; // out static START = 'START'; // in static START_SUCCESS = 'START_SUCCESS'; // out static START_FAILURE = 'START_FAILURE'; // out static STOP = 'STOP'; // in static STOP_SUCCESS = 'STOP_SUCCESS'; // out static STOP_FAILURE = 'STOP_FAILURE'; // out static TERMINATE = 'TERMINATE'; // in static TERMINATE_SUCCESS = 'TERMINATE_SUCCESS'; // out static TERMINATE_FAILURE = 'TERMINATE_FAILURE'; // out // Game state static HOME = 'HOME'; // out static REGISTER = 'REGISTER'; // out static CASHIER = 'CASHIER'; // out static JACKPOT = 'JACKPOT'; // out static BIG_WIN = 'BIG_WIN'; // out static MEGA_WIN = 'MEGA_WIN'; // out static BONUS_CONVERT = 'BONUS_CONVERT'; // out static OUT_OF_MONEY = 'OUT_OF_MONEY'; // out // NGS communication static NGS_REQUEST = 'NGS_REQUEST'; // out static NGS_RESPONSE = 'NGS_RESPONSE'; // in static NGS_ERROR = 'NGS_ERROR'; // in // NGS logging static NGS_LOG_REQUEST = 'NGS_LOG_REQUEST'; // Casino specific static FREE_ROUND_POSTPONE = 'FREE_ROUND_POSTPONE'; // in // Prepare the correct preloader events in the game to be called. // When the preload of the game is started executing, and BEFORE is shown: // The preloader should not be shown before sending the event. static PRELOADING_START = 'PRELOADING_START'; // out // When the preloader updates the loaded value execute an event with // the parameter of the total loaded percentage of the app (a number between 0 to 100): static PRELOADING_PROGRESS = 'PRELOADING_PROGRESS'; // out // When the preloader finishes loading all the required assets static PRELOADING_END = 'PRELOADING_END'; // out // Get the status of UI Elements. // In this case, the LOBBY button: specific casino gmApi.getLobbyActive() // return the visibility of the lobby button. Returns true or false. static LOBBY_ACTIVE = 'LOBBY_ACTIVE'; // in //TODO rename HOME_ACTIVE // Set the current version of the game to specific casino gmApi as a string parameter. static VERSION = 'VERSION'; // in static VERSION_RESPONSE = 'VERSION_RESPONSE'; // out // Sends the currency formatting object with 2 properties: // groupingSeparator and decimalSeparator. // The groupingSeparator determines the symbol to use for thousand separator. // The decimalSeparator determines the symbol used to separate decimal numbers. static CURRENCY_FORMATTING = 'CURRENCY_FORMATTING'; // in // The response is an object with properties: // { // prefix, // suffix, // decimalPlaces, // decimalSeparator, // groupingSeparator, // prefixSeparator, // suffixSeparator // } // example: {“$”, “”, 2, “,”, “.”, "", ""} static CURRENCY_FORMATTING_RESPONSE = 'CURRENCY_FORMATTING_RESPONSE'; // out // Get the status of music to set in the game. Returns true or false. static MUSIC_ACTIVE = 'MUSIC_ACTIVE'; // in // Get the status of sound effects to set in the game. Returns true or false. static SOUND_EFFECTS_ACTIVE = 'SOUND_EFFECTS_ACTIVE'; // in // Sound events status change. // If the game has only one audio control: static GENERAL_SOUND_STATUS_CHANGED = 'GENERAL_SOUND_STATUS_CHANGED'; // in // If the game has two audio controls: static MUSIC_STATUS_CHANGED = 'MUSIC_STATUS_CHANGED'; // in static SOUND_EFFECTS_STATUS_CHANGED = 'SOUND_EFFECTS_STATUS_CHANGED'; // in // Prepare to publish when the user make changes on the sound from within the game. static GENERAL_SOUND_STATUS_CHANGE = 'GENERAL_SOUND_STATUS_CHANGE'; // out // If the game has two audio controls: static MUSIC_STATUS_CHANGE = 'MUSIC_STATUS_CHANGE'; // out static SOUND_EFFECTS_STATUS_CHANGE = 'SOUND_EFFECTS_STATUS_CHANGE'; // out // Subscribe to the event to open the Control Panel / Options Panel / About page / Pay Table page when needed. static CONTROL_PANEL_STATUS_CHANGED = 'CONTROL_PANEL_STATUS_CHANGED'; // in static ABOUT_STATUS_CHANGED = 'ABOUT_STATUS_CHANGED'; // in static PAY_TABLE_STATUS_CHANGED = 'PAY_TABLE_STATUS_CHANGED'; // in // Prepare to publish when the user make changes on the sound from within the game. static CONTROL_PANEL_STATUS_CHANGE = 'CONTROL_PANEL_STATUS_CHANGE'; // out static ABOUT_STATUS_CHANGE = 'ABOUT_STATUS_CHANGE'; // out static PAY_TABLE_STATUS_CHANGE = 'PAY_TABLE_STATUS_CHANGE'; // out // Subscribe to events that listen to balance updates. // Remember that the balance is an object: {balance:number, free_balance: number} static WALLET_UPDATED = 'WALLET_UPDATED'; // in // Publish when the game updates it’s balance: // The object to set is: {balance:number, free_balance:number} static WALLET_UPDATE = 'WALLET_UPDATE'; // out // Call events when there’s is any change in the game. // The event receives a parameter that set the game state. Games states to be called: // When the game sends to the server a spin request static ROUND_START = 'ROUND_START'; // out // When the casino game id is obtained // Argument is game spinId:string static ROUND_ID = 'ROUND_ID'; // out // When the game has stopped spinning and a request to settle is sent to the server // Optional argument (deprecated, see ROUND_ID) is game spinId:string static ROUND_END = 'ROUND_END'; // out // Call an event when a spin/bonus call returns a win. // The event receives a parameter with the number of the total win (without any currency formatting) static TOTAL_WIN_UPDATE = 'TOTAL_WIN_UPDATE'; // out // Call an event when the bet of the game is changed. // The events receive a parameter with the number of the updated bet (without any currency formatting). static TOTAL_BET_UPDATE = 'TOTAL_BET_UPDATE'; // out // Call an event when the results are shown and the game settle is completed. // The game should be ready and waiting for a new spin from the user at this moment. static RESULTS_SHOWN = 'RESULTS_SHOWN'; // out //TODO merge with ROUND_END ??? // Call the ERROR_OCCURRE event. The event receives the error code // of the error occurred as an object with 2 properties:, the error code and the error object. // The error object will be sent to the game once the error handling is completed. // The list of possible errors is in the specific casino Client Integration document, // Error codes section. { data: errorCode, error: errorObject} // // ERROR data structure: // { // errorCode:string; // errorMessage:string; // data:any; // } static ERROR = 'ERROR'; // out // Call specific casino gmApi when there is an error or need to communicate with the user in any way. // First you need to subscribe to the event ERROR_OCCURRE_HANDLED. // ERROR data structure is enhanced about "severity" attribute with one of values: // "FATAL", "RECOVERABLE", "UNKNOWN" static ERROR_HANDLED = 'ERROR_HANDLED'; // in static ERROR_NOT_HANDLED = 'ERROR_NOT_HANDLED'; // in // Subscribe to an event to dispose the application. //static DISPOSE_APPLICATION = 'DISPOSE_APPLICATION'; // Once it´s ready to close, you need to call an event to communicate the game is ready to be unloaded. //static GAME_READY_FOR_UNLOAD = 'GAME_READY_FOR_UNLOAD'; // Implement the AUTOPLAY UKGC functionality in the game. // Publish specific casino gmApi.publications.AUTOPLAY_ACTIVATED_GAME event every time // the AUTOPLAY feature is enabled by the user/game. static AUTOPLAY_ACTIVATE = 'AUTOPLAY_ACTIVATE'; // out // Listen to the confirmation or cancellation of that request in static AUTOPLAY_ACTIVATE_SUCCESS = 'AUTOPLAY_ACTIVATE_SUCCESS'; // in static AUTOPLAY_ACTIVATE_FAILURE = 'AUTOPLAY_ACTIVATE_FAILURE'; // in // Use the specific casino gmApi.publications.AUTOPLAY_DEACTIVATE event to inform the specific casino gmApi // that the AUTOPLAY was cancelled, static AUTOPLAY_DEACTIVATE = 'AUTOPLAY_DEACTIVATE'; // out // and the specific casino gmApi.publications.AUTOPLAY_LIMIT_REACHED to listen to // automatic cancellation of AUTOPLAY when a limit imposed by the user is reached. static AUTOPLAY_LIMIT_REACHED = 'AUTOPLAY_LIMIT_REACHED'; // in static AUTOPLAY_CUSTOM_FEATURE = 'AUTOPLAY_CUSTOM_FEATURE'; // out static AUTOPLAY_CUSTOM_FEATURE_SETTINGS = 'AUTOPLAY_CUSTOM_FEATURE_SETTINGS'; // out // Implement the Reality check feature in the game. // Perform the specific casino gmApi.publications.PLAY_REQUEST event when requesting a new play, static ROUND_REQUEST = 'ROUND_REQUEST'; // out // and listen to the confirmation of that request is the specific casino gmApi.publications.PLAY_CONFIRMED event. static ROUND_REQUEST_CONFIRMED = 'ROUND_REQUEST_CONFIRMED'; // in // Also check the method specific casino gmApi.isGUIBlocked() before requesting a new play // when the AUTOPLAY feature is active. static GUI_BLOCKED = 'GUI_BLOCKED'; // out static GUI_BLOCKED_RESPONSE = 'GUI_BLOCKED_RESPONSE'; // in static FULLSCREEN_MODE_ON = 'FULLSCREEN_MODE_ON'; // out static FULLSCREEN_MODE_OFF = 'FULLSCREEN_MODE_OFF'; // out static FULLSCREEN_MODE_HANDLED = 'FULLSCREEN_MODE_HANDLED'; // in static FULLSCREEN_MODE_NOT_HANDLED = 'FULLSCREEN_MODE_NOT_HANDLED'; // in // UKGC compliance mode static COMPLIANCE_MODE = 'COMPLIANCE_MODE'; // inGamble flow
Gamble data is included to initialize response.
In response server will provide following values:
active - if gamble feature is available for this game/casino;
maxRoundCount - maximum number of rounds of gamble feature, that can be played after win;
maxStake - maximum value that user can set as stake for gamble feature in coins.
gambleMode - mode, that defines if player can bet on color only (2), or color and suits (1).
xxxxxxxxxx"gamble": {"maxRoundCount": 5, "maxStake": 2500, "active": true, "gambleMode": 1},After players has got a win if a gamble feature is enabled for the game - client will receive event "evt__gmbl__enter".
{"type": "evt_gmbl_enter", "id": 0, "winmeter": 10, "featmeter": 0, "gmblstep": 0, "gmblmeter": 5, "maxgmbl": 25, "card": "-","history": ""}After that player has to choose: he can send collect event and get the win or gamble. Client should send an option from user - button push event with one of the following:
'btn_black' - red
'btn_red' - black
'btn_num0' - hearts
'btn_num1' - diamonds
'btn_num2' - spades
'btn_num3' - clubs
'btn_collect' - collect
xxxxxxxxxx{"event":{"type":"evt_btnpush","button":"btn_collect"}}