Connection to the server
In order to connect to the server, you need to:
Download and install Lasertag Operator (LTO) app from Play Market.
If the app is already installed on your device, update it.
Connect to a local network (LASERTAG, LASERTAG.NET, etc.) on your device. It will be displayed as a connection without internet.
Open the LTO application and from the “Lobby” menu go to the “Tools” menu.
From the “Tools” menu, go to the “API” setting - it will be displayed at the top of the list.
In the “API” menu, activate Automatic Start and Logging by sliding the switches, then click on the “Start server” button.
Return to the “Lobby” menu and make sure the server is connected (icon is green). If the icon is red, restart the server in the API menu.
If necessary, apply settings and connect the kits into the game.
LTO Api
Socket settings
LTO Api uses WebSocket to exchange data between the client and the server.
Attention
Do not use Windows hot-spot to connect between the client and server, as it may block broadcast messages.
The functionality is intended for work in a local network: Client < -- > Router < -- > Server.
Server URL
ws://< server ip address >:8080/lto
Instead of < server ip address > insert the IP address of the server (the device on which the Lasertag operator application is running).
Server auto discovery
To receive the IP address of a server, you can use server autodetection by sending a broadcast message.
Parameters for server autodetection:
Request tag - 0xc94222115fc942d3 (apply reverse to Request);
Response tag - 0xade7e97f3f51477b (apply reverse to Response);
Port – 4000.
After receiving a response from the server, subtract the first 8 bytes and compare them to the Response tag. After that you can get the IP address of the server and open the socket for operation.
Example of auto discovery server kotlin code:
val REQUEST_TAG =
ByteBuffer.allocate(8).putLong(Long.reverseBytes(0xC94222115FC942D3u.toLong())).array()
val RESPONSE_TAG =
ByteBuffer.allocate(8).putLong(Long.reverseBytes(0xADE7E97F3F51477Bu.toLong())).array()
val PORT = 4000
val BROADCAST_ADDR ="255.255.255.255" // socket sending to the server
val socket = DatagramSocket()
socket.broadcast = true val sendPacket = DatagramPacket(REQUEST_TAG, sendData.size,
InetAddress.getByName(BROADCAST_ADDR), PORT)
socket.send(sendPacket)
// reply from the server and get ip address
val recvData = ByteArray(128)
val recvPacket = DatagramPacket(recvData, recvData.size)
socket.receive(recvPacket)val responceTag = responseData.sliceArray(0 until 8)if (responceTag.contentEquals(RESPONSE_TAG))
val serverIp = recvPacket.address.hostAddressExample of auto discovery server js code:
const dgram = require('dgram');
const socket = dgram.createSocket('udp4');
const BROADCAST_ADDR = '255.255.255.255';
const PORT = 4000;
const REQUEST_TAG = new Uint8Array([0xC9, 0x42, 0x22, 0x11, 0x5F, 0xC9, 0x42, 0xD3]).reverse();
const RESPONSE_TAG = new Uint8Array([0xAD, 0xE7, 0xE9, 0x7F, 0x3F, 0x51, 0x47, 0x7B]).reverse();
async function sendBroadcast() {
return new Promise((resolve, reject) => {
socket.bind(() => {
socket.setBroadcast(true);
socket.send(REQUEST_TAG, 0, REQUEST_TAG.length, PORT, BROADCAST_ADDR, (err) => {
if (err) {
reject('Error sending broadcast message: ' + err);
} else {
console.log('Broadcast message sent');
}
}); // Listen for responses
socket.on('message', (msg, rinfo) => {
const response = msg.subarray(0, RESPONSE_TAG.length);
if (response.equals(RESPONSE_TAG)) {
const ws = new WebSocket(`ws://${response}:8080/lto`);
// Add work with socket
}
});
});
});
}
Protocol message structure
Protocol message headers
content-version : 1.0.0
message-format : message_type:{payload}
message-type : string
payload-type : json
First type of message with payload
Structure:
message_type:{payload}
Example:
StartGameType:{
"game Time": 1730308650362
}
Explanation:
message_type - StartGameType
payload - {
"gameTime": 1730308650362
}
Second type of message without payload
Structure:
message_type
Example:
PauseGameType
Explanation:
message_type - PauseGameType
The message consists of two parts: message_type and payload.
If the messages do not contain payload, only the message_type needs to be sent.
A list of all possible message_type is presented in the table below.
Server / client messages
Server to Client Messages
| Message info | Message type | Payload | Message example |
|---|---|---|---|
| Game start event. When the game starts, the round time is transmitted. Сonditions: Subscribtion to message on SubscribeOnGameEvents | StartGame | { “gameTime”: 1800 } | StartGame:{ “gameTime”: 1800 } |
| Game pause event. Сonditions: Subscribtion to message on SubscribeOnGameEvents | PauseGame | PauseGame | |
| The event of canceling the pause of the game. Сonditions: Subscribtion to message on SubscribeOnGameEvents | UnPauseGame | UnPauseGame | |
| End Game Event. Сonditions: Subscribtion to message on SubscribeOnGameEvents | EndGame | EndGame | |
| The event of a player being wounded by another player. Сonditions: Subscribtion to message on SubscribeOnGameEvents | PlayerHitPlayer | { “shooterId”: 1, “targetId”: 2, “time”: 1730114679815 } | PlayerHitPlayer:{ “shooterId”: 1, “targetId”: 2, “time”: 1730114679815 } |
| The event of a player being killed by another player. Сonditions: Subscribtion to message on SubscribeOnGameEvents | PlayerKillPlayer | { “shooterId”: 1, “targetId”: 2, “time”: 1730114680817 } | PlayerKillPlayer:{ “shooterId”: 1, “targetId”: 2, “time”: 1730114680817 } |
| SMART DB capture event in Capture by Shots mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | DbSmartCaptureShots | { “deviceID”: 1 } | DbSmartCaptureShots:{ “deviceID”: 1 } |
| SMART DB capture event in Capture by Time mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | DbSmartCaptureTime | { “deviceID”: 1 } | DbSmartCaptureTime:{ “deviceID”: 1 } |
| SMART DB capture event in Tug of War mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | DbSmartCaptureTugOfWar | { “deviceID”: 1 } | DbSmartCaptureTugOfWar:{ “deviceID”: 1 } |
| SMART DB capture event in “Triple Capture” mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | DbSmartCaptureThreePerson | { “deviceID”: 1 } | DbSmartCaptureThreePerson:{ “deviceID”: 1 } |
| SMART DB capture event in “Flag Raising” mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | DbSmartCaptureFlag | { “deviceID”: 1 } | DbSmartCaptureFlag:{ “deviceID”: 1 } |
| Multistation capture event in Control Point mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | MSCaptureControlPoint | { “deviceID”: 1 } | MSCaptureControlPoint:{ “deviceID”: 1 } |
| Multistation capture event in Base mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | MSCaptureBase | { “deviceID”: 1 } | MSCaptureBase:{ “deviceID”: 1 } |
| Multistation event “Bomb exploded” in “Bomb” mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | MSBombExplode | { “deviceID”: 1 } | MSBombExplode:{ “deviceID”: 1 } |
| Multistation event “Bomb is planted” in “Bomb” mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | MSBombMine | { “deviceID”: 1 } | MSBombMine:{ “deviceID”: 1 } |
| Multistation event “Bomb is demined” in the “Bomb” mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | MSBombDemine | { “deviceID”: 1 } | MSBombDemine:{ “deviceID”: 1 } |
| SIRIUS station capture event in the “Base” mode. Conditions: Subscribtion to message on SubscribeOnGameEvents | SiriusCaptureBase | { “deviceID”: 1 } | SiriusCaptureBase:{ “deviceID”: 1 } |
| SUPERNOVA bomb event “Bomb Activation”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaActivation | { “deviceID”: 1 } | SupernovaActivation:{ “deviceID”: 1 } |
| SUPERNOVA Bomb Event “Bomb is Activated”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaActivated | { “deviceID”: 1 } | SupernovaActivated:{ “deviceID”: 1 } |
| SUPERNOVA bomb event “Bomb activation interrupted”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaActivationBreak | { “deviceID”: 1 } | SupernovaActivationBreak:{ “deviceID”: 1 } |
| SUPERNOVA bomb event “Bomb Deactivation”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaDeactivation | { “deviceID”: 1 } | SupernovaDeactivation:{ “deviceID”: 1 } |
| SUPERNOVA Bomb event “Bomb is deactivated”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaDeactivated | { “deviceID”: 1 } | SupernovaDeactivated:{ “deviceID”: 1 } |
| SUPERNOVA bomb event “Deactivation interrupted”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaDeactivationBreak | { “deviceID”: 1 } | SupernovaDeactivationBreak:{ “deviceID”: 1 } |
| SUPERNOVA Bomb Event “Bomb detonated.” Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaExplode | { “deviceID”: 1 } | SupernovaExplode:{ “deviceID”: 1 } |
| SUPERNOVA Bomb event “Bomb is demined”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaDemine | { “deviceID”: 1 } | SupernovaDemine:{ “deviceID”: 1 } |
| SUPERNOVA Bomb Event “The bomb has been placed on the platform.” Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaInstalledOnPlatform | { “deviceID”: 1 } | SupernovaInstalledOnPlatform:{ “deviceID”: 1 } |
| SUPERNOVA Bomb Event “The bomb has been removed from the platform.” Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaDeInstalledOnPlatform | { “deviceID”: 1 } | SupernovaDeInstalledOnPlatform:{ “deviceID”: 1 } |
| SUPERNOVA Bomb event “Cheats were detected while using the bomb”. Conditions: Subscribtion to message on SubscribeOnGameEvents | SupernovaEventCheatHasBeenDetected | { “deviceID”: 1 } | SupernovaEventCheatHasBeenDetected:{ “deviceID”: 1 } |
| Player statistics. Conditions: Subscribtion to message on SubscribeOnGameEvents | PlayerState | { “playerId”: 0, “serialNumber”: 0, “shots”: 0, “hits”: 0, “kills”: 0, “hitsReceived”: 0, “accuracy”: 0.0, “points”: 0 } | PlayerState:{ “playerId”: 0, “serialNumber”: 0, “shots”: 0, “hits”: 0, “kills”: 0, “hitsReceived”: 0, “accuracy”: 0.0, “points”: 0 } |
| Players statistics. Сonditions: Subscribtion to message on SubscribeOnGameEvents Sent in response to a request from a customer GetAllPlayerState | PlayersState | { “players”: [ { “playerId”: 0, “serialNumber”: 0, “shots”: 0, “hits”: 0, “kills”: 0, “hitsReceived”: 0, “accuracy”: 0.0, “points”: 0 }, { “playerId”: 0, “serialNumber”: 0, “shots”: 0, “hits”: 0, “kills”: 0, “hitsReceived”: 0, “accuracy”: 0.0, “points”: 0 } ] } | PlayersState:{ “players”: [ { “playerId”: 0, “serialNumber”: 0, “shots”: 0, “hits”: 0, “kills”: 0, “hitsReceived”: 0, “accuracy”: 0.0, “points”: 0 }, { “playerId”: 0, “serialNumber”: 0, “shots”: 0, “hits”: 0, “kills”: 0, “hitsReceived”: 0, “accuracy”: 0.0, “points”: 0 } ] } |
Client to Server Messages
| Message info | Message type | Payload | Message example |
|---|---|---|---|
| Subscriptions to receive game events. Transmits a list of events that will notify the client when they occur. | SubscribeOnGameEvents | { "events":[ "StartGame", "EndGame", "PauseGame", "PlayerHitPlayer", "PlayerKillPlayer" ] } | SubscribeOnGameEvents:{ "events":[ "StartGame", "EndGame", "PauseGame", "PlayerHitPlayer", "PlayerKillPlayer" ] } |
| Subscription to player status changes | SubscribeOnPlayerStateChange | {“subscribe”:true} | SubscribeOnPlayerStateChange:{ “subscribe”:true } |
| Getting the status of all players | GetAllPlayerState | GetAllPlayerState |