So I made this simple example which reflects some of the ingame events such as positions, kills, smokes for the de_dust map. Feel free to further develop, or use this for inspiration for your own projects. If you have any questions feel free to contact me here or on github.
If anybody have some optimization ideérs, feel free to let me know! Since this, was one of the only ways I could see, how to reflect the ingame data and control it on a webpage the way you choose to. Hope some of you find some inspiration from this or can use part of it
The project is achieved with Javascript, JQuery, Node.js, MySQL and sourcemod.
Github link for the project https://github.com/jonaslagoni/csgoLiveServer
Updating the position data for players
First lets break down the timer used to control the interval for players positions. Ill start off with the sourcemod plugin located
here.
Code:
public Action Timer_player_positions(Handle timer){
//First I make sure that there are active players and not just an empty server. Since we dont want to update positions of no one.
if(activePlayersCount != 0){
//Next I prepare the query for the database.
StrCat(position_query, sizeof(position_query), "INSERT INTO positions (client_id, timestamp, pos_x, pos_y, pos_z) VALUES");
//This is used for determin if I already added a position to the query or not.
new ran = false;
//Go through each of the players
for(new i = 0; i < activePlayersCount; i++){
new clientId = GetArrayCell(activePlayers, i);
new client = GetClientOfUserId(clientId);
//Make sure they are in game and alive. Else we dont want to update their position
if(IsClientInGame(client) && IsPlayerAlive(client)){
if(ran){
StrCat(position_query, sizeof(position_query), ",");
}
char player_walked_name[64];
GetClientName(client, player_walked_name, sizeof(player_walked_name));
new float:position[3];
GetEntPropVector(client, Prop_Send, "m_vecOrigin", position);
float pos_x = position[0];
float pos_y = position[1];
float pos_z = position[2];
int timestamp = GetTime();
//Format the string with the correct values for this client
Format(pp_query, sizeof(pp_query), " (%d, %d, %f, %f, %f)", clientId, timestamp, pos_x, pos_y, pos_z);
//Add the String to the query
StrCat(position_query, sizeof(position_query), pp_query);
ran = true;
}
}
if(ran){
//When done end the query and send it async*
StrCat(position_query, sizeof(position_query), ";");
csgoDatabase.Query(T_queryDone, position_query);
//Reset the query for next time
position_query = "";
}
}
return Plugin_Continue;
}
When the position is updated from the game server the Node.js server takes over by checking each 100ms for new updates. The server code is located
here. Ill walk you though it here:
Code:
//Using setInterval as a timer to get the data each 100ms
setInterval(function(){
var query = "SELECT * FROM positions WHERE position_id > " + last_position_id;
con.query(query, function(error, rows, fields){
if(error) throw error;
//Check if the query returned some results
if(rows.length > 0){
console.log("found footstep");
//If there is only one new position only send 1 by socket to the clients
if(rows.length == 1){
io.emit('position', rows[0].pos_x, rows[0].pos_y, rows[0].pos_z, rows[0].client_id);
//Update the last retrieved position
last_position_id = rows[0].position_id;
}else{
//Since there are more then one position update send them all at once
console.log("length = " + rows.length);
var o = {};
var key = '0';
o[key] = [];
//Go though each position
for(var i = 0; i < rows.length; i++){
console.log("found footstep " + i + " of " + rows.length);
//Construct the data
var data = {
pos_x : rows[i].pos_x,
pos_y : rows[i].pos_y,
pos_z : rows[i].pos_z,
client_id : rows[i].client_id
};
//Push the data to the array
o[key].push(data);
//Update the last retrieved position
last_position_id = rows[i].position_id;
}
//Send all the positions by socket
io.emit('positions', o);
}
}
});
}, 100);
When the Node.js server, located
here, sends the message to the socket the client send the message to the map.js class located
here.
Code:
//On a single position update
socket.on('position', function(pos_x, pos_y, pos_z, client_id){
map.drawPlayer(pos_x, pos_y, pos_z, client_id);
});
//On multiple positions
socket.on('positions', function(data){
map.drawPlayers(data);
});
Code:
function getPosX(pos_x){
//Correct location on the de_dust map for x-axis
return ((Math.abs(pos_x+2850))/6.0)-10;
}
function getPosY(pos_y){
//Correct location on the de_dust map for y-axis
return ((Math.abs(pos_y-4073))/6.0)-10;
}
drawPlayer:function(pos_x, pos_y, pos_z, client_id){
//Get the correct positions of the user to reflect the correct position on the website
var real_pos_x = getPosX(pos_x);
var real_pos_y = getPosY(pos_y);
//Change the css to fit the correct position of the client
$("#player".concat(client_id)).css("left", real_pos_x + "px");
$("#player".concat(client_id)).css("top", real_pos_y + "px");
},
drawPlayers:function(data){
//Go through each of the positions in the array
for(var i = 0; i < data['0'].length; i++){
//Get the correct positions of the user to reflect the correct position on the website
var real_pos_x = getPosX(data['0'][i].pos_x);
var real_pos_y = getPosY(data['0'][i].pos_y);
//Change the css to fit the correct position of the client
$("#player".concat(data['0'][i].client_id)).css("left", real_pos_x + "px");
$("#player".concat(data['0'][i].client_id)).css("top", real_pos_y + "px");
}
},
__________________