+#include "skaterift.h"
+#include "vg/vg_steam.h"
+#include "vg/vg_steam_networking.h"
+#include "vg/vg_steam_auth.h"
+#include "vg/vg_steam_friends.h"
#include "player.h"
#include "network.h"
#include "network_msg.h"
#include "vg/vg_imgui.h"
#include "gui.h"
#include "ent_region.h"
+#include "vg/vg_loader.h"
+
+#ifdef _WIN32
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+#else
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <netdb.h>
+#endif
+
+struct network_client network_client =
+{
+ .auth_mode = eServerModeAuthentication,
+ .state = k_ESteamNetworkingConnectionState_None,
+ .last_intent_change = -99999.9
+};
static void scores_update(void);
-static int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ){
+int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ){
if( msg->m_cbSize < size ) {
vg_error( "Invalid packet size (must be at least %u)\n", size );
return 0;
k_nSteamNetworkingSend_Reliable, NULL );
}
-static void network_send_region(void){
+void network_send_region(void)
+{
if( !network_connected() )
return;
* .
* 10+ specific week index
*/
-static void network_request_scoreboard( const char *mod_uid,
- const char *route_uid,
- u32 week, u64 userdata ){
+void network_request_scoreboard( const char *mod_uid,
+ const char *route_uid,
+ u32 week, u64 userdata ){
if( !network_connected() )
return;
vg_msg_wkvstr( &data, "endpoint", "scoreboard" );
vg_msg_wkvstr( &data, "mod", mod_uid );
vg_msg_wkvstr( &data, "route", route_uid );
- vg_msg_wkvu32( &data, "week", week );
+ vg_msg_wkvnum( &data, "week", k_vg_msg_u32, 1, &week );
network_send_request( req, &data, network_scoreboard_callback, userdata );
}
}
}
-static void network_publish_laptime( const char *mod_uid,
- const char *route_uid, f64 lap_time ){
+void network_publish_laptime( const char *mod_uid,
+ const char *route_uid, f64 lap_time ){
if( !network_connected() )
return;
vg_msg_wkvstr( &data, "endpoint", "setlap" );
vg_msg_wkvstr( &data, "mod", mod_uid );
vg_msg_wkvstr( &data, "route", route_uid );
- vg_msg_wkvi32( &data, "time", time_centiseconds );
+ vg_msg_wkvnum( &data, "time", k_vg_msg_i32, 1, &time_centiseconds );
network_send_request( req, &data, network_publish_callback, 0 );
}
}
}
-static void network_send_item( enum netmsg_playeritem_type type ){
+void network_send_item( enum netmsg_playeritem_type type )
+{
if( !network_connected() )
return;
view_id = localplayer.playermodel_view_slot;
addon_type = k_addon_type_player;
}
- else
- assert(0);
struct addon_cache *cache = &addon_system.cache[addon_type];
vg_pool *pool = &cache->pool;
}
}
-static void network_status_string( vg_str *str, u32 *colour ){
+void network_status_string( vg_str *str, u32 *colour )
+{
if( skaterift.demo_mode ){
vg_strcat( str, "Offline" );
return;
if( state == k_ESteamNetworkingConnectionState_None )
vg_strcat( str, "No Connection" );
- else if( state == k_ESteamNetworkingConnectionState_Connecting ){
- vg_strcat( str, "Connecting to:\nskaterift.com" );
+ else if( state == k_ESteamNetworkingConnectionState_Connecting )
+ {
+ vg_strcatf( str, "Connecting...\n%s", network_client.host_adress );
if( network_client.retries ){
vg_strcat( str, "\n(" );
}
}
else if( state == k_ESteamNetworkingConnectionState_Connected ){
- vg_strcat( str, "Connected to:\nskaterift.com" );
+ vg_strcatf( str, "Connected to:\n%s", network_client.host_adress );
*colour = 0xff00a020;
}
else if( state == k_ESteamNetworkingConnectionState_ClosedByPeer )
}
}
-static void render_server_status_gui(void){
+void render_server_status_gui(void)
+{
render_fb_bind( gpipeline.fb_workshop_preview, 0 );
/* HACK */
}
}
-static void network_connect(void){
- char ip_buf[128];
- vg_str str;
- vg_strnull( &str, ip_buf, sizeof(ip_buf) );
- vg_strcat( &str, network_client.server_adress );
- vg_strcat( &str, ":" );
- vg_strcati32( &str, NETWORK_PORT );
+void network_set_host( const char *host_str, const char *port_str )
+{
+ vg_strncpy( host_str, network_client.host_adress,
+ sizeof(network_client.host_adress), k_strncpy_overflow_fatal );
- if( !vg_strgood(&str) ) return;
+ memset( &network_client.ip, 0, sizeof(network_client.ip) );
+ network_client.ip_resolved = 0;
- /* Connect to server if not connected */
- SteamNetworkingIPAddr remoteAddr;
- SteamAPI_SteamNetworkingIPAddr_ParseString( &remoteAddr, str.buffer );
+ if( port_str )
+ {
+ vg_strncpy( port_str, network_client.host_port,
+ sizeof(network_client.host_port), k_strncpy_overflow_fatal );
+ }
+ else
+ {
+ vg_str str;
+ vg_strnull( &str, network_client.host_port,
+ sizeof(network_client.host_port) );
+ vg_strcati32( &str, NETWORK_PORT );
+ }
- char buf[256];
- SteamAPI_SteamNetworkingIPAddr_ToString( &remoteAddr, buf, 256, 1 );
- vg_info( "connect to: %s\n", buf );
+ network_client.ip.m_port = atoi( network_client.host_port );
+}
+static void network_connect(void)
+{
+ VG_ASSERT( network_client.ip_resolved );
+
+ vg_info( "connecting...\n" );
network_client.remote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(
- hSteamNetworkingSockets, &remoteAddr, 0, NULL );
+ hSteamNetworkingSockets, &network_client.ip, 0, NULL );
}
static void network_sign_on_complete(void){
}
}
-static void network_update(void){
+static void network_resolve_host_async( void *payload, u32 size )
+{
+ u32 *status = payload;
+ network_client.ip_resolved = *status;
+
+ char buf[256];
+ SteamAPI_SteamNetworkingIPAddr_ToString( &network_client.ip, buf, 256, 1 );
+ vg_info( "Resolved host address to: %s\n", buf );
+}
+
+static void network_resolve_host_thread( void *_ )
+{
+ vg_async_item *call = vg_async_alloc(8);
+ u32 *status = call->payload;
+ *status = 0;
+
+ if( (network_client.host_adress[0] >= '0') &&
+ (network_client.host_adress[0] <= '9') )
+ {
+ SteamAPI_SteamNetworkingIPAddr_ParseString(
+ &network_client.ip,
+ network_client.host_adress );
+ network_client.ip.m_port = atoi( network_client.host_port );
+ *status = 1;
+ goto end;
+ }
+
+ vg_info( "Resolving host.. %s (:%s)\n",
+ network_client.host_adress, network_client.host_port );
+
+ struct addrinfo hints;
+ struct addrinfo *result;
+
+ /* Obtain address(es) matching host/port. */
+
+ memset( &hints, 0, sizeof(hints) );
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+ hints.ai_protocol = 0;
+
+ int s = getaddrinfo( network_client.host_adress, network_client.host_port,
+ &hints, &result);
+ if( s != 0 )
+ {
+#ifndef _WIN32
+ vg_error( "getaddrinfo: %s\n", gai_strerror(s) );
+#endif
+
+ if( !strcmp( network_client.host_adress, "skaterift.com" ) )
+ {
+ vg_warn( "getaddrinfo failed for skaterift.com;\n "
+ "falling back to a hardcoded IPv4\n" );
+ strcpy( network_client.host_adress, "46.101.34.155" );
+ SteamAPI_SteamNetworkingIPAddr_ParseString(
+ &network_client.ip,
+ network_client.host_adress );
+ network_client.ip.m_port = NETWORK_PORT;
+ *status = 1;
+ }
+
+ goto end;
+ }
+
+ struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)result->ai_addr;
+ memcpy( network_client.ip.m_ipv6, &inaddr->sin6_addr, 16 );
+ freeaddrinfo( result );
+
+ *status = 1;
+
+end: vg_async_dispatch( call, network_resolve_host_async );
+}
+
+void network_update(void)
+{
if( !steam_ready )
return;
ESteamNetworkingConnectionState state = network_client.state;
- if( network_client.user_intent == k_server_intent_offline ){
+ if( network_client.user_intent == k_server_intent_offline )
+ {
if( state != k_ESteamNetworkingConnectionState_None )
network_disconnect();
return;
}
- if( state == k_ESteamNetworkingConnectionState_Connected ){
+ if( state == k_ESteamNetworkingConnectionState_Connected )
+ {
poll_remote_connection();
f64 frame_delta = vg.time_real - network_client.last_frame;
- if( frame_delta > NETWORK_FRAMERATE ){
+ if( frame_delta > NETWORK_FRAMERATE )
+ {
network_client.last_frame = vg.time_real;
remote_player_send_playerframe();
- player__clear_sfx_buffer();
+ localplayer.sfx_buffer_count = 0;
}
remote_player_debug_update();
}
- else {
+ else
+ {
if( (state == k_ESteamNetworkingConnectionState_Connecting) ||
- (state == k_ESteamNetworkingConnectionState_FindingRoute) ){
+ (state == k_ESteamNetworkingConnectionState_FindingRoute) )
+ {
return;
}
- else {
+ else
+ {
f64 waited = vg.time_real - network_client.last_attempt,
min_wait = 1.0;
if( waited < min_wait )
return;
+
+ if( !network_client.ip_resolved )
+ {
+ if( vg_loader_availible() )
+ {
+ vg_loader_start( network_resolve_host_thread, NULL );
+ }
+ else return;
+ }
+ else
+ network_connect();
- network_connect();
network_client.retries ++;
network_client.last_attempt = vg.time_real;
}
}
}
-static void chat_send_message( const char *message ){
+void chat_send_message( const char *message )
+{
if( !network_connected() ){
return;
}
return 0;
}
-static void network_init(void){
+void network_init(void)
+{
vg_console_reg_var( "network_info", &network_client.network_info,
k_var_dtype_i32, VG_VAR_PERSISTENT );
+ vg_console_reg_var( "auto_connect", &network_client.auto_connect,
+ k_var_dtype_i32, VG_VAR_PERSISTENT );
if( steam_ready ){
u32 alloc_size = sizeof(struct network_request)*NETWORK_MAX_REQUESTS;
network_client.request_buffer =
}
}
-static void network_end(void){
+void network_end(void)
+{
/* TODO: Send buffered highscores that were not already */
if( (network_client.state == k_ESteamNetworkingConnectionState_Connected) ||
(network_client.state == k_ESteamNetworkingConnectionState_Connecting) )