hSteamNetworkingSockets, con, userdata );
}
+static void gameserver_player_join( int index ){
+ for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
+ struct gameserver_client *client = &gameserver.clients[i];
+
+ if( (i==index) || !client->active )
+ continue;
+
+ netmsg_playerjoin join;
+ join.inetmsg_id = k_inetmsg_playerjoin;
+ join.index = index;
+ join.board_uid[0] = '\0';
+ join.playermodel_uid[0] = '\0';
+ join.username[0] = '\0';
+
+ SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+ hSteamNetworkingSockets, client->connection,
+ &join, sizeof(join), k_nSteamNetworkingSend_Reliable, NULL );
+ }
+}
+
+static void gameserver_player_leave( int index ){
+ for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
+ struct gameserver_client *client = &gameserver.clients[i];
+
+ if( (i==index) || !client->active )
+ continue;
+
+ netmsg_playerjoin leave;
+ leave.inetmsg_id = k_inetmsg_playerjoin;
+ leave.index = index;
+
+ SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+ hSteamNetworkingSockets, client->connection,
+ &leave, sizeof(leave), k_nSteamNetworkingSend_Reliable, NULL );
+ }
+}
+
static void new_client_connecting( HSteamNetConnection client ){
+ int index = -1;
+
+ /* TODO: LRU */
+ for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
+ if( !gameserver.clients[i].active ){
+ index = i;
+ break;
+ }
+ }
+
+ if( index == -1 ){
+ vg_error( "Server full\n" );
+ SteamAPI_ISteamNetworkingSockets_CloseConnection(
+ hSteamNetworkingSockets, client,
+ 4500,
+ NULL, 1 );
+ return;
+ }
+
EResult accept_status = SteamAPI_ISteamNetworkingSockets_AcceptConnection(
hSteamNetworkingSockets, client );
-
if( accept_status == k_EResultOK ){
- vg_success( "Accepted client (id: %u)\n", client );
+ vg_success( "Accepted client (id: %u, index: %d)\n", client, index );
+
+ gameserver.clients[index].active = 1;
+ gameserver.clients[index].connection = client;
+
SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
hSteamNetworkingSockets,
client, gameserver.client_group );
/* Just to be sure */
set_connection_authsteamid( client, -1 );
+ gameserver_player_join( index );
}
else{
vg_warn( "Error accepting client (id: %u)\n", client );
+ SteamAPI_ISteamNetworkingSockets_CloseConnection(
+ hSteamNetworkingSockets, client,
+ k_ESteamNetConnectionEnd_Misc_InternalError,
+ NULL, 1 );
+ gameserver.clients[index].active = 0;
+ gameserver.clients[index].connection = 0;
}
}
if( info->m_info.m_eState==k_ESteamNetworkingConnectionState_Connecting ){
new_client_connecting( info->m_hConn );
}
+
+ if( (info->m_info.m_eState ==
+ k_ESteamNetworkingConnectionState_ClosedByPeer ) ||
+ (info->m_info.m_eState ==
+ k_ESteamNetworkingConnectionState_ProblemDetectedLocally ) ){
+
+ for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
+ struct gameserver_client *client = &gameserver.clients[i];
+
+ if( client->active ){
+ if( client->connection == info->m_hConn ){
+ client->connection = 0;
+ client->active = 0;
+ gameserver_player_leave(i);
+ break;
+ }
+ }
+ }
+
+ vg_info( "End reason: %d\n", info->m_info.m_eEndReason );
+ SteamAPI_ISteamNetworkingSockets_CloseConnection(
+ hSteamNetworkingSockets, info->m_hConn, 0, NULL, 0 );
+ }
}
static void on_inet_auth( SteamNetworkingMessage_t *msg ){
if( get_connection_authsteamid( msg ) == k_connection_unauthorized ){
vg_warn( "Unauthorized request! Disconnecting client: %u\n",
- msg->m_conn );
+ msg->m_conn );
SteamAPI_ISteamNetworkingSockets_CloseConnection(
hSteamNetworkingSockets,
return;
}
-
netmsg_playerframe *info = msg->m_pData;
- vg_info( "... @: %.2f %.2f %.2f\n",
- //msg->m_identityPeer,
- info->pos_temp[0], info->pos_temp[1], info->pos_temp[2] );
}
static void poll_connections(void){
HSteamNetPollGroup client_group;
EServerMode auth_mode;
+ struct gameserver_client {
+ int active;
+ int authenticated;
+ HSteamNetConnection connection;
+ }
+ clients[ 32 ];
+
u8 app_symmetric_key[ k_nSteamEncryptedAppTicketSymmetricKeyLen ];
int monitor_fd;
#include "player.h"
#include "network.h"
+#include "network_msg.h"
+#include "player_remote.h"
static void scores_update(void);
if( info->m_hConn == network_client.remote ){
network_client.state = info->m_info.m_eState;
- if( info->m_info.m_eState == k_ESteamNetworkingConnectionState_Connected ){
+
+ if( info->m_info.m_eState ==
+ k_ESteamNetworkingConnectionState_Connected ){
vg_success(" Connected to remote server.. authenticating\n");
send_auth_ticket();
}
+ else if( info->m_info.m_eState ==
+ k_ESteamNetworkingConnectionState_ClosedByPeer ){
+
+ if( info->m_info.m_eEndReason ==
+ k_ESteamNetConnectionEnd_Remote_Max ){
+ network_client.retries = 40;
+ }
+
+ SteamAPI_ISteamNetworkingSockets_CloseConnection(
+ hSteamNetworkingSockets, info->m_hConn, 0, NULL, 0 );
+ network_client.remote = 0;
+ }
+ else if( info->m_info.m_eState ==
+ k_ESteamNetworkingConnectionState_ProblemDetectedLocally ){
+ SteamAPI_ISteamNetworkingSockets_CloseConnection(
+ hSteamNetworkingSockets, info->m_hConn, 0, NULL, 0 );
+ network_client.remote = 0;
+ }
}
else{
- vg_warn( " Recieved signal from unknown connection\n" );
+ //vg_warn( " Recieved signal from unknown connection\n" );
}
}
}
}
+#if 0
/* We dont need to stay on the server currently */
SteamAPI_ISteamNetworkingSockets_CloseConnection(
hSteamNetworkingSockets, network_client.remote, 0, NULL, 1 );
+#endif
network_scores_updated = 1;
}
if( tmp->inetmsg_id == k_inetmsg_scoreboard )
on_inet_scoreboard( msg );
+ if( (tmp->inetmsg_id >= 200) && (tmp->inetmsg_id < 300) ){
+ player_remote_packet( msg );
+ }
+
SteamAPI_SteamNetworkingMessage_t_Release( msg );
}
}
}
static void network_init(void){
+ vg_console_reg_var( "network_info", &network_client.network_info,
+ k_var_dtype_i32, VG_VAR_PERSISTENT );
if( steam_ready ){
steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
on_server_connect_status );
f64 last_attempt, last_frame;
u32 retries;
+
+ i32 network_info;
}
static network_client = {
.state = k_ESteamNetworkingConnectionState_None,
#include "vg/vg_stdint.h"
#include "world_info.h"
#include "vg/vg_platform.h"
+;
#pragma pack(push,1)
};
/* probably about 10k */
+/* server control 100 */
+
+
+/* player updates 200 */
+
typedef struct netmsg_playerframe netmsg_playerframe;
-enum{ k_inetmsg_playerframe = 20 };
+enum{ k_inetmsg_playerframe = 200 };
struct netmsg_playerframe{
u32 inetmsg_id;
v3f pos_temp;
};
+typedef struct netmsg_playerjoin netmsg_playerjoin;
+enum{ k_inetmsg_playerjoin = 201 };
+struct netmsg_playerjoin{
+ u32 inetmsg_id;
+
+ u32 index;
+ char username[32]; /* UNUSED */
+ char playermodel_uid[76]; /* UNUSED */
+ char board_uid[76]; /* UNUSED */
+};
+
+typedef struct netmsg_playerleave netmsg_playerleave;
+enum{ k_inetmsg_playerleave = 202 };
+struct netmsg_playerleave{
+ u32 inetmsg_id;
+ u32 index;
+};
+
#pragma pack(pop)
#endif /* NETWORK_MSG_H */
#include "player_common.h"
enum player_subsystem{
+ k_player_subsystem_invalid = -1,
k_player_subsystem_walk = 0,
k_player_subsystem_skate = 1,
k_player_subsystem_dead = 2,
- k_player_subsystem_drive = 3
+ k_player_subsystem_drive = 3,
+ k_player_subsystem_max
};
struct player_cam_controller {
void *animator_data;
u32 animator_size;
+
+ const char *name;
};
#include "player_ragdoll.h"
.im_gui = player__dead_im_gui,
.animator_data = &player_dead.animator,
- .animator_size = sizeof(player_dead.animator)
+ .animator_size = sizeof(player_dead.animator),
+ .name = "Dead"
};
#endif /* PLAYER_DEAD_H */
.reset = player__drive_reset,
.animator_data = NULL,
- .animator_size = 0
+ .animator_size = 0,
+ .name = "Drive"
};
#endif /* PLAYER_DRIVE_H */
--- /dev/null
+#include "player_remote.h"
+
+static void player_remote_unwatch( struct network_player *player ){
+ addon_cache_unwatch( k_addon_type_player, player->playermodel_view_slot );
+ addon_cache_unwatch( k_addon_type_board, player->board_view_slot );
+}
+
+static void player_remote_clear( struct network_player *player ){
+ player_remote_unwatch( player );
+ memset( player, 0, sizeof(*player) );
+ strcpy( player->username, "unknown" );
+ player->subsystem = k_player_subsystem_invalid;
+}
+
+static void player_remote_packet( SteamNetworkingMessage_t *msg ){
+ netmsg_blank *tmp = msg->m_pData;
+
+ if( tmp->inetmsg_id == k_inetmsg_playerjoin ){
+ netmsg_playerjoin *playerjoin = msg->m_pData;
+
+ if( playerjoin->index < vg_list_size(netplayers.list) ){
+ struct network_player *player = &netplayers.list[ playerjoin->index ];
+ player_remote_clear( player );
+ player->active = 1;
+
+ /* TODO: interpret the uids */
+ player->board_view_slot = 0;
+ player->playermodel_view_slot = 0;
+ }
+ else {
+ vg_error( "inetmsg_playerjoin: player index out of range\n" );
+ }
+ }
+ else if( tmp->inetmsg_id == k_inetmsg_playerleave ){
+ netmsg_playerleave *playerleave = msg->m_pData;
+
+ if( playerleave->index < vg_list_size(netplayers.list) ){
+ struct network_player *player = &netplayers.list[ playerleave->index ];
+ player_remote_unwatch( player );
+ player->active = 0;
+ }
+ else {
+ vg_error( "inetmsg_playerleave: player index out of range\n" );
+ }
+ }
+}
+
+static void remote_player_network_imgui(void){
+ if( !network_client.network_info )
+ return;
+
+ ui_rect panel = { (vg.window_x / 2) - 200, 0, 400, 600 };
+ ui_fill( panel, (ui_colour(k_ui_bg)&0x00ffffff)|0x50000000 );
+
+ char buf[512];
+ const char *netstatus = "PROGRAMMING ERROR";
+
+ struct { enum ESteamNetworkingConnectionState state; const char *str; }
+ states[] = {
+ { k_ESteamNetworkingConnectionState_None, "None" },
+ { k_ESteamNetworkingConnectionState_Connecting, "Connecting" },
+ { k_ESteamNetworkingConnectionState_FindingRoute, "Finding Route" },
+ { k_ESteamNetworkingConnectionState_Connected, "Connected" },
+ { k_ESteamNetworkingConnectionState_ClosedByPeer, "Closed by peer" },
+ { k_ESteamNetworkingConnectionState_ProblemDetectedLocally,
+ "Problem Detected Locally" },
+ { k_ESteamNetworkingConnectionState_FinWait, "Fin Wait" },
+ { k_ESteamNetworkingConnectionState_Linger, "Linger" },
+ { k_ESteamNetworkingConnectionState_Dead, "Dead" }
+ };
+ for( u32 i=0; i<vg_list_size(states); i ++ ){
+ if( states[i].state == network_client.state ){
+ netstatus = states[i].str;
+ break;
+ }
+ }
+ snprintf( buf, 512, "Network: %s", netstatus );
+ ui_info( panel, buf );
+ ui_info( panel, "---------------------" );
+
+ for( u32 i=0; i<vg_list_size(netplayers.list); i++ ){
+ struct network_player *player = &netplayers.list[i];
+ if( player->active ){
+ const char *sysname = "invalid";
+
+ if( (player->subsystem >= 0) &&
+ (player->subsystem < k_player_subsystem_max) ){
+ sysname = player_subsystems[ player->subsystem ]->name;
+ }
+ snprintf( buf, 512, "#%u: %s [%s]", i, player->username, sysname );
+ ui_info( panel, buf );
+ }
+ }
+}
--- /dev/null
+#ifndef PLAYER_REMOTE_H
+#define PLAYER_REMOTE_H
+
+#include "player.h"
+#include "network.h"
+
+struct {
+ struct network_player {
+ int active;
+ u16 board_view_slot, playermodel_view_slot;
+ player_pose pose;
+
+ char username[32];
+
+ enum player_subsystem subsystem;
+ union {
+ struct player_skate_animator _skate;
+ struct player_walk_animator _walk;
+ struct player_dead_animator _dead;
+ };
+ }
+ list[ 32 ];
+}
+static netplayers;
+
+static void player_remote_packet( SteamNetworkingMessage_t *msg );
+
+#endif /* PLAYER_REMOTE_H */
.post_animate = player__skate_post_animate,
.animator_data = &player_skate.animator,
- .animator_size = sizeof(player_skate.animator)
+ .animator_size = sizeof(player_skate.animator),
+ .name = "Skate"
};
#endif /* PLAYER_SKATE_H */
.pose = player__walk_pose,
.animator_data = &player_walk.animator,
- .animator_size = sizeof(player_walk.animator)
+ .animator_size = sizeof(player_walk.animator),
+ .name = "Walk"
};
#endif /* PLAYER_WALK_H */
#include "vehicle.h"
#include "pointcloud.h"
#include "save.h"
+#include "player_remote.h"
/* unity build
* ----------------- */
#include "save.c"
#include "respawn.c"
#include "network.c"
+#include "player_remote.c"
static struct player_avatar localplayer_avatar;
skaterift_replay_imgui();
workshop_form_gui();
render_view_framebuffer_ui();
+ remote_player_network_imgui();
}