gameserver_send_to_all( client_id, prop, msg->m_cbSize,
k_nSteamNetworkingSend_Reliable );
}
+ else if( tmp->inetmsg_id == k_inetmsg_chat ){
+ netmsg_chat *chat = msg->m_pData,
+ *prop = alloca( sizeof(netmsg_chat) + NETWORK_MAX_CHAT );
+ prop->inetmsg_id = k_inetmsg_chat;
+ prop->client = client_id;
+
+ u32 l = network_msgstring( chat->msg, msg->m_cbSize, sizeof(netmsg_chat),
+ prop->msg, NETWORK_MAX_CHAT );
+ vg_info( "[%d]: %s\n", client_id, prop->msg );
+
+ gameserver_send_to_all( client_id, prop, sizeof(netmsg_chat)+l,
+ k_nSteamNetworkingSend_Reliable );
+ }
else {
vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
tmp->inetmsg_id );
k_srbind_world_right,
k_srbind_home,
k_srbind_lobby,
+ k_srbind_chat,
k_srbind_max,
};
[k_srbind_replay_freecam]=controller_glyph(SDL_CONTROLLER_BUTTON_Y ),
[k_srbind_replay_resume]=controller_glyph( SDL_CONTROLLER_BUTTON_A ),
[k_srbind_sit] = controller_glyph( SDL_CONTROLLER_BUTTON_B ),
- [k_srbind_lobby] = controller_glyph( SDL_CONTROLLER_BUTTON_DPAD_LEFT )
+ [k_srbind_lobby] = controller_glyph( SDL_CONTROLLER_BUTTON_DPAD_LEFT ),
+ [k_srbind_chat] = ""
};
const char *keyboard_table[ k_srbind_max ] = {
[k_srbind_replay_freecam] = KEYBOARD_GLYPH( "F" ),
[k_srbind_replay_resume]= "\xa1",
[k_srbind_sit] = KEYBOARD_GLYPH( "Z" ),
- [k_srbind_lobby] = KEYBOARD_GLYPH( "" ) // FIXME: what is tab?
+ [k_srbind_lobby] = KEYBOARD_GLYPH( "" ), // FIXME: what is tab?
+ [k_srbind_chat] = KEYBOARD_GLYPH( "Y" )
};
if( vg_input.display_input_method == k_input_method_controller )
else return keyboard_table[ joystick ][axis];
}
-static int buttons_filter_fixed(void)
-{
- if( !srinput.enabled ) return 1;
- if( vg_ui.wants_mouse ) return 1;
+static int input_filter_generic(void){
+ if( !srinput.enabled || vg_ui.wants_mouse || vg_console.enabled )
+ return 1;
+ else
+ return 0;
+}
+
+static int buttons_filter_fixed(void){
+ if( input_filter_generic() )
+ return 1;
if( vg.engine_stage == k_engine_stage_update_fixed )
if( vg.fixed_iterations > 0 )
}
/* Rising edge of button */
-static int button_down( enum sr_bind button )
-{
+static int button_down( enum sr_bind button ){
if( buttons_filter_fixed() ) return 0;
if( srinput.button_states[ button ][0] &&
}
/* Falling edge of button */
-static int button_up( enum sr_bind button )
-{
+static int button_up( enum sr_bind button ){
if( buttons_filter_fixed() ) return 0;
if( !srinput.button_states[ button ][0] &&
}
/* State of button */
-static int button_press( enum sr_bind button )
-{
- if( vg_ui.wants_mouse ) return 0;
- return srinput.button_states[ button ][0];
+static int button_press( enum sr_bind button ){
+ if( input_filter_generic() )
+ return 0;
+ return
+ srinput.button_states[ button ][0];
}
-static void joystick_state( enum sr_joystick joystick, v2f state )
-{
- if( vg_ui.wants_mouse )
+static void joystick_state( enum sr_joystick joystick, v2f state ){
+ if( input_filter_generic() )
v2_zero( state );
else
v2_copy( srinput.joystick_states[ joystick ][0], state );
}
static float axis_state( enum sr_axis axis ){
- if( vg_ui.wants_mouse ) return 0.0f;
- else return srinput.axis_states[axis][0];
+ if( input_filter_generic() )
+ return 0.0f;
+ else
+ return srinput.axis_states[axis][0];
}
static void setbtn( enum sr_bind button, u8 value )
setbtn( k_srbind_replay_resume, vg_getkey(SDLK_SPACE) );
setbtn( k_srbind_sit, vg_getkey(SDLK_z) );
setbtn( k_srbind_lobby, vg_getkey(SDLK_TAB) );
+ setbtn( k_srbind_chat, vg_getkey(SDLK_y) );
/* axis
* --------------------------------------------*/
setbtn( k_srbind_replay_freecam, buttons[ SDL_CONTROLLER_BUTTON_Y ] );
setbtn( k_srbind_sit, buttons[ SDL_CONTROLLER_BUTTON_B ] );
setbtn( k_srbind_lobby, buttons[ SDL_CONTROLLER_BUTTON_DPAD_LEFT ] );
+ // k_srbind_chat
float *axis = controller->axises;
float *steer = srinput.joystick_states[ k_srjoystick_steer ][0],
}
}
+static void chat_send_message( const char *message ){
+ if( !network_connected() ){
+ return;
+ }
+
+ netmsg_chat *chat = alloca( sizeof(netmsg_chat) + NETWORK_MAX_CHAT );
+ chat->inetmsg_id = k_inetmsg_chat;
+ chat->client = 0;
+
+ u32 l = vg_strncpy( message, chat->msg, NETWORK_MAX_CHAT,
+ k_strncpy_always_add_null );
+
+ SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+ hSteamNetworkingSockets, network_client.remote,
+ chat, sizeof(netmsg_chat)+l+1,
+ k_nSteamNetworkingSend_Reliable, NULL );
+}
+
+static int cmd_network_send_message( int argc, const char *argv[] ){
+ char buf[ NETWORK_MAX_CHAT ];
+ vg_str str;
+ vg_strnull( &str, buf, NETWORK_MAX_CHAT );
+
+ for( int i=0; i<argc; i ++ ){
+ vg_strcat( &str, argv[i] );
+
+ if( i < argc-1 )
+ vg_strcatch( &str, ' ' );
+ }
+
+ chat_send_message( buf );
+ return 0;
+}
+
static void network_init(void){
vg_console_reg_var( "network_info", &network_client.network_info,
k_var_dtype_i32, VG_VAR_PERSISTENT );
steam_register_callback( k_iPersonaStateChange,
on_persona_state_change );
request_auth_ticket();
+
+ vg_console_reg_cmd( "say", cmd_network_send_message, NULL );
}
}
u32 week, u64 userdata );
static void network_publish_laptime( const char *mod_uid,
const char *route_uid, f64 lap_time );
+static void chat_send_message( const char *message );
static int network_connected(void){
return network_client.state == k_ESteamNetworkingConnectionState_Connected;
#define NETWORK_FRAMERATE 0.1
#define NETWORK_BUFFERFRAMES 6
#define NETWORK_LEADERBOARD_MAX_SIZE 1024
+#define NETWORK_MAX_CHAT 128
#define NETWORK_LEADERBOARD_ALLTIME 0
#define NETWORK_LEADERBOARD_CURRENT_WEEK 1
instance_id, sound_effects;
u16 boundary_hash; /* used for animating correctly through gates, teleport..
msb is a flip flop for teleporting
- second msb is flip flop for gate
-
-TODO: disable oblique clipping on cam mtx when rendering remote players
- also render over the portal stencil? somehow.
-
- detransform, interp, retransform. render in dest world. */
+ second msb is flip flop for gate */
u8 animdata[];
};
k_remote_player_gui_type_you,
};
-/* TODO:
- * line of sight / distance culling
+/*
+ * Given players' root_co, get the screen point where we should draw tag info.
*/
-static void remote_player_nametag( m4x4f pv, v3f co, const char *name,
- enum remote_player_gui_type type,
- u32 medals[3] ){
- vg_ui.font = &vg_ui_font_big;
+static int player_tag_position( m4x4f pv, v3f root_co, ui_point out_point ){
v4f wpos;
- v3_copy( co, wpos );
+ v3_copy( root_co, wpos );
wpos[1] += 2.0f;
wpos[3] = 1.0f;
if( wpos[3] > 0.0f ){
v2_muls( wpos, (1.0f/wpos[3]) * 0.5f, wpos );
v2_add( wpos, (v2f){ 0.5f, 0.5f }, wpos );
+
+ float k_max = 32000.0f;
- vg_ui.font = &vg_ui_font_big;
- ui_rect wr;
- wr[2] = VG_MAX( ui_text_line_width( name ), 140 ) + 8;
- wr[0] = vg_clampf(wpos[0] * vg.window_x, -32000.0f,32000.0f)-(wr[2]/2);
- wr[1] = vg_clampf((1.0f-wpos[1]) * vg.window_y, -32000.0f, 32000.0f );
- wr[3] = 32;
-
- ui_fill( wr, ui_opacity( ui_colour(k_ui_bg), 0.23f ) );
- ui_text( wr, name, 1, k_ui_align_middle_center, 0 );
-
- vg_ui.font = &vg_ui_font_small;
-
- /* medals */
- int cols = 0;
- if( medals ){
- for( int i=0; i<3; i ++ )
- if( medals[i] )
- cols ++;
-
- char buf[32];
- vg_str str;
-
- if( cols ){
- f32 w = (f32)wr[2] / (f32)cols;
- cols = 0;
-
- for( int i=0; i<3; i ++ ){
- if( medals[i] ){
- ui_rect col = { wr[0] + (f32)cols*w, wr[1] + wr[3], w,
- vg_ui.font->glyph_height };
-
- vg_strnull( &str, buf, 32 );
- vg_strcatch( &str, (char)k_SRglyph_vg_circle );
- vg_strcati32( &str, medals[i] );
-
- ui_text( col, buf, 1, k_ui_align_middle_center,
- ui_colour( (enum ui_scheme_colour[]){
- k_ui_yellow, k_ui_gray, k_ui_orange }[i] ) );
-
- cols ++;
- }
- }
+ out_point[0] = vg_clampf(wpos[0] * vg.window_x, -k_max, k_max );
+ out_point[1] = vg_clampf((1.0f-wpos[1]) * vg.window_y, -k_max, k_max );
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/*
+ * Draw chat box relative to the root tag position on the screen
+ */
+static void chat_box( ui_point tag_root, f64 time, const char *message ){
+ if( (vg.time_real - time) > 15.0 )
+ return;
+
+ ui_rect wr;
+ wr[2] = ui_text_line_width( message ) + 8;
+ wr[3] = vg_ui.font->glyph_height + 2;
+ wr[0] = tag_root[0]-(wr[2]/2);
+ wr[1] = tag_root[1] - wr[3] - 8;
+
+ ui_fill( wr, ui_opacity( ui_colour(k_ui_bg), 0.23f ) );
+ ui_text( wr, message, 1, k_ui_align_middle_center, 0 );
+}
+
+/*
+ * Draw full imgui for remote player
+ */
+static void remote_player_nametag( ui_point tag_root,
+ struct network_player *player ){
+ vg_ui.font = &vg_ui_font_big;
+
+ ui_rect wr;
+ wr[2] = VG_MAX( ui_text_line_width( player->username ), 140 ) + 8;
+ wr[3] = 32;
+ wr[0] = tag_root[0]-(wr[2]/2);
+ wr[1] = tag_root[1]-(wr[3]/2);
+
+ ui_fill( wr, ui_opacity( ui_colour(k_ui_bg), 0.23f ) );
+ ui_text( wr, player->username, 1, k_ui_align_middle_center, 0 );
+
+ vg_ui.font = &vg_ui_font_small;
+
+ /* medals */
+ int cols = 0;
+ for( int i=0; i<3; i ++ )
+ if( player->medals[i] )
+ cols ++;
+
+ char buf[32];
+ vg_str str;
+
+ if( cols ){
+ f32 w = (f32)wr[2] / (f32)cols;
+ cols = 0;
+
+ for( int i=0; i<3; i ++ ){
+ if( player->medals[i] ){
+ ui_rect col = { wr[0] + (f32)cols*w, wr[1] + wr[3], w,
+ vg_ui.font->glyph_height };
+
+ vg_strnull( &str, buf, 32 );
+ vg_strcatch( &str, (char)k_SRglyph_vg_circle );
+ vg_strcati32( &str, player->medals[i] );
+
+ ui_text( col, buf, 1, k_ui_align_middle_center,
+ ui_colour( (enum ui_scheme_colour[]){
+ k_ui_yellow, k_ui_gray, k_ui_orange }[i] ) );
+
+ cols ++;
}
}
+ }
+}
+
+static void remote_player_world_gui( m4x4f pv, v3f root_co,
+ struct network_player *player ){
+ ui_point tag_root;
+ if( !player_tag_position( pv, root_co, tag_root ) )
+ return;
+ if( player ){
+ remote_player_nametag( tag_root, player );
+ chat_box( tag_root, player->chat_time, player->chat );
+ }
+ else {
+ if( netplayers.chatting )
+ chat_box( tag_root, vg.time_real, netplayers.chat_buffer );
+ else
+ chat_box( tag_root, netplayers.chat_time, netplayers.chat_message );
}
- vg_ui.font = &vg_ui_font_small;
}
static void remote_player_gui_info( ui_rect box,
player->opacity = vg_lerpf( player->opacity, opacity,
vg.time_frame_delta * 2.0f );
-
- remote_player_nametag(
- pv,
- netplayers.final_mtx[localplayer.skeleton.bone_count*i][3],
- player->username, player->isfriend, player->medals );
+
+ remote_player_world_gui(
+ pv, netplayers.final_mtx[localplayer.skeleton.bone_count*i][3],
+ player );
vg_ui.colour[3] = player->opacity;
ui_flush( k_ui_shader_colour );
}
vg_ui.colour[3] = 1.0f;
+
+ remote_player_world_gui( pv, localplayer.rb.co, NULL );
+ ui_flush( k_ui_shader_colour );
+}
+
+static void chat_escape(void){
+ netplayers.chatting = -1;
+}
+
+static void chat_enter( char *buf, u32 len ){
+ vg_strncpy( buf, netplayers.chat_message, NETWORK_MAX_CHAT,
+ k_strncpy_always_add_null );
+ netplayers.chatting = -1;
+ netplayers.chat_time = vg.time_real;
+ chat_send_message( buf );
+}
+
+static void remote_players_chat_imgui(void){
+ if( netplayers.chatting == 1 ){
+ ui_rect box = { 0, 0, 400, 40 },
+ window = { 0, 0, vg.window_x, vg.window_y };
+ ui_rect_center( window, box );
+
+ struct ui_textbox_callbacks callbacks = {
+ .enter = chat_enter,
+ .escape = chat_escape
+ };
+
+ ui_textbox( box, NULL,
+ netplayers.chat_buffer, NETWORK_MAX_CHAT, 1,
+ UI_TEXTBOX_AUTOFOCUS, &callbacks );
+ }
+ else {
+ /* TODO: we gotta fix this input fighting crap. */
+ if( netplayers.chatting == -1 ){
+ netplayers.chatting = 0;
+ }
+ else {
+ if( (skaterift.activity == k_skaterift_default) &&
+ button_down( k_srbind_chat ) ){
+ netplayers.chatting = 1;
+ netplayers.chat_buffer[0] = '\0';
+ srinput.enabled = 0;
+ }
+ }
+ }
}
/* TODO: Compression with server code */
char username[ NETWORK_USERNAME_MAX ];
char items[k_netmsg_playeritem_max][ADDON_UID_MAX];
+ char chat[ NETWORK_MAX_CHAT ];
+ f64 chat_time;
/* ui */
u32 medals[3];
u32 up_bytes;
f32 up_kbs, down_kbs;
f64 last_data_measurement;
+
+ int chatting;
+ char chat_buffer[ NETWORK_MAX_CHAT ], chat_message[ NETWORK_MAX_CHAT ];
+ f64 chat_time;
}
static netplayers;
* ---------------------------------------------------------------------------*/
static void vg_pre_update(void){
- srinput.enabled = 1;
+ if( !netplayers.chatting ) /* FIXME */
+ srinput.enabled = 1;
+
skaterift_preupdate_inputs();
if( k_tools_mode ) return;
remote_players_imgui_lobby();
}
else {
+ remote_players_chat_imgui(); /* TODO: conditional */
remote_players_imgui_world( world_current_instance(), vg.pv, 100.0f, 1 );
}
}