view weekly/all-time
[carveJwlIkooP6JGAAIwe30JlM.git] / world_routes.c
index bd91b3c441bb41392593300ae87cb5f03c67aadf..52c2c2aa76ad4afad3d10211fcca13afb1e99c5b 100644 (file)
 #include "world_gate.h"
 #include "world_load.h"
 #include "highscores.h"
+#include "network.h"
 
 #include "font.h"
 #include "pointcloud.h"
 #include "gui.h"
 #include "steam.h"
+#include "network_msg.h"
+#include "network_common.h"
 
 #include "shaders/scene_route.h"
 #include "shaders/routeui.h"
 
-
-VG_STATIC 
+#if 0
+static 
 void world_routes_local_set_record( world_instance *world, ent_route *route,
                                     f64 lap_time )
 {
    vg_success( "  NEW LAP TIME: %f\n", lap_time );
 
-   if( route->official_track_id != 0xffffffff ){
+   if( route->anon.official_track_id != 0xffffffff ){
       double time_centiseconds = lap_time * 100.0;
       if( time_centiseconds > (float)0xfffe )   /* skill issue */
          return;
 
-      struct track_info *ti = &track_infos[ route->official_track_id ];
+      struct track_info *ti = &track_infos[ route->anon.official_track_id ];
       highscore_record *record = &ti->record;
-      record->trackid  = route->official_track_id;
+      record->trackid  = route->anon.official_track_id;
       record->datetime = time(NULL);
       record->playerid = 0;
       record->points   = 0;
@@ -50,9 +53,9 @@ void world_routes_local_set_record( world_instance *world, ent_route *route,
       vg_warn( "There is no associated track for this record...\n" );
    }
 }
+#endif
 
-
-VG_STATIC void world_routes_clear( world_instance *world )
+static void world_routes_clear( world_instance *world )
 {
    for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
       ent_route *route = mdl_arritm( &world->ent_route, i );
@@ -69,7 +72,7 @@ VG_STATIC void world_routes_clear( world_instance *world )
    world_static.last_use = 0.0;
 }
 
-VG_STATIC void world_routes_time_lap( world_instance *world, ent_route *route )
+static void world_routes_time_lap( world_instance *world, ent_route *route )
 {
    vg_info( "------- time lap %s -------\n", 
             mdl_pstr(&world->meta,route->pstr_name) );
@@ -114,8 +117,25 @@ VG_STATIC void world_routes_time_lap( world_instance *world, ent_route *route )
    vg_info( "%u %f\n", world_static.current_run_version, world_static.time );
 
    if( valid_count==route->checkpoints_count ){
-      double lap_time = world_static.time - start_time;
-      world_routes_local_set_record( world, route, lap_time );
+      f64 lap_time = world_static.time - start_time;
+      //world_routes_local_set_record( world, route, lap_time );
+
+      if( route->anon.official_track_id != 0xffffffff ){
+         struct track_info *ti = &track_infos[ route->anon.official_track_id ];
+         if( ti->achievement_id ){
+            steam_set_achievement( ti->achievement_id );
+            steam_store_achievements();
+         }
+      }
+
+      addon_alias *alias = 
+         &world_static.instance_addons[ world_static.active_instance ]->alias;
+
+      char mod_uid[ ADDON_UID_MAX ];
+      addon_alias_uid( alias, mod_uid );
+      network_publish_laptime( mod_uid, 
+                               mdl_pstr( &world->meta, route->pstr_name ),
+                               lap_time );
    }
 
    route->valid_checkpoints = valid_count+1;
@@ -127,7 +147,7 @@ VG_STATIC void world_routes_time_lap( world_instance *world, ent_route *route )
 /*
  * When going through a gate this is called for bookkeeping purposes
  */
-VG_STATIC void world_routes_activate_entry_gate( world_instance *world, 
+static void world_routes_activate_entry_gate( world_instance *world, 
                                                  ent_gate *rg )
 {
    world_static.last_use = world_static.time;
@@ -175,7 +195,7 @@ VG_STATIC void world_routes_activate_entry_gate( world_instance *world,
 }
 
 /* draw lines along the paths */
-VG_STATIC void world_routes_debug( world_instance *world )
+static void world_routes_debug( world_instance *world )
 {
    for( u32 i=0; i<mdl_arrcount(&world->ent_route_node); i++ ){
       ent_route_node *rn = mdl_arritm(&world->ent_route_node,i);
@@ -224,7 +244,7 @@ VG_STATIC void world_routes_debug( world_instance *world )
    }
 }
 
-VG_STATIC 
+static 
 void world_routes_pointcloud_spot( world_instance *world, 
                                    pointcloud_buffer *pcbuf, 
                                    v3f co, f32 radius, u32 samples, v4f colour )
@@ -268,7 +288,7 @@ void world_routes_pointcloud_spot( world_instance *world,
  *   /#\
  * -'###`-
  */
-VG_STATIC 
+static 
 void world_routes_pointcloud_tower( world_instance *world, 
                                     pointcloud_buffer *pcbuf, 
                                     v3f co, f32 radius, f32 height,
@@ -304,7 +324,7 @@ void world_routes_pointcloud_tower( world_instance *world,
    }
 }
 
-VG_STATIC 
+static 
 void world_routes_place_curve( world_instance *world, ent_route *route,
                                v4f h[3], v3f n0, v3f n2, scene_context *scene,
                                pointcloud_buffer *pcbuf )
@@ -365,8 +385,8 @@ void world_routes_place_curve( world_instance *world, ent_route *route,
       ha.dist = 8.0f;
       hb.dist = 8.0f;
 
-      int resa = ray_world( world, sa, down, &ha ),
-          resb = ray_world( world, sb, down, &hb );
+      int resa = ray_world( world, sa, down, &ha, k_material_flag_ghosts ),
+          resb = ray_world( world, sb, down, &hb, k_material_flag_ghosts );
       
       if( pcbuf && resa ){
          world_routes_pointcloud_spot( world, pcbuf, ha.pos, 
@@ -426,7 +446,7 @@ void world_routes_place_curve( world_instance *world, ent_route *route,
    }
 }
 
-VG_STATIC void world_routes_gen_meshes( world_instance *world, u32 route_id, 
+static void world_routes_gen_meshes( world_instance *world, u32 route_id, 
                                         scene_context *sc,
                                         pointcloud_buffer *pcbuf )
 {
@@ -549,11 +569,11 @@ VG_STATIC void world_routes_gen_meshes( world_instance *world, u32 route_id,
    scene_copy_slice( sc, &route->sm );
 }
 
-VG_STATIC 
+static 
 struct world_surface *world_tri_index_surface( world_instance *world, 
                                                  u32 index );
 
-VG_STATIC f64 world_routes_scatter_surface_points( world_instance *world,
+static f64 world_routes_scatter_surface_points( world_instance *world,
                                                    pointcloud_buffer *pcbuf,
                                                    f32 rate )
 {
@@ -675,7 +695,7 @@ VG_STATIC f64 world_routes_scatter_surface_points( world_instance *world,
    return total_area;
 }
 
-VG_STATIC void world_routes_surface_grid( world_instance *world,
+static void world_routes_surface_grid( world_instance *world,
                                           pointcloud_buffer *pcbuf )
 {
    i32 const k_gridlines = 32,
@@ -712,6 +732,10 @@ VG_STATIC void world_routes_surface_grid( world_instance *world,
                u32 *tri = &world->scene_geo.arrindices[ idx*3 ];
                v3f vs[3];
 
+               u16 mask = k_material_flag_preview_visibile;
+               if( !(world->scene_geo.arrvertices[tri[0]].flags & mask) ) 
+                  continue;
+
                for( u32 i=0; i<3; i++ ){
                   v3_copy( world->scene_geo.arrvertices[tri[i]].co, vs[i] );
                }
@@ -719,11 +743,6 @@ VG_STATIC void world_routes_surface_grid( world_instance *world,
                f32 t;
                if( ray_tri( vs, ro, dir, &t ) ){
                   v3_muladds( ro, dir, t, hit );
-                  struct world_surface *m1 = 
-                     world_tri_index_surface( world, tri[0] );
-
-                  if( !(m1->info.flags & k_material_flag_preview_visibile) )
-                     continue;
 
                   if( world->water.enabled )
                      if( hit[1] < world->water.height )
@@ -745,7 +764,7 @@ VG_STATIC void world_routes_surface_grid( world_instance *world,
    }
 }
 
-VG_STATIC void world_write_preview( addon_reg *reg, pointcloud_buffer *pcbuf ){
+static void world_write_preview( addon_reg *reg, pointcloud_buffer *pcbuf ){
    if( reg->alias.workshop_id ) return;
 
    /* 
@@ -774,7 +793,7 @@ VG_STATIC void world_write_preview( addon_reg *reg, pointcloud_buffer *pcbuf ){
 /* 
  * Create the strips of colour that run through the world along course paths
  */
-VG_STATIC void world_gen_routes_generate( u32 instance_id ){
+static void world_gen_routes_generate( u32 instance_id ){
    world_instance *world = &world_static.instances[ instance_id ];
    vg_info( "Generating route meshes\n" );
    vg_async_stall();
@@ -850,6 +869,8 @@ VG_STATIC void world_gen_routes_generate( u32 instance_id ){
 
    if( instance_id <= 1 /*world_loader.generate_point_cloud*/ ){
       f64 area = 0.0;
+
+#if VG_RELEASE
       area = world_routes_scatter_surface_points( world, pcbuf, 16.0f );
       world_routes_surface_grid( world, pcbuf );
 
@@ -860,13 +881,12 @@ VG_STATIC void world_gen_routes_generate( u32 instance_id ){
                                         2.0f, 50.0f, 128, 
                                         (v4f){0.2f,0.2f,0.2f,1.0f} );
       }
+#endif
 
-      vg_info( "Distrubuted %u points over %fkm^2!\n", 
+      vg_info( "Distributed %u points over %fkm^2!\n", 
                 pcbuf->count, area/1e6f );
 
-      world_write_preview( instance_id? world_static.addon_client:
-                                        world_static.addon_hub, 
-                                        pcbuf );
+      world_write_preview( world_static.instance_addons[ instance_id ], pcbuf );
       vg_async_dispatch( call_pointcloud, async_pointcloud_sub );
    }
 
@@ -875,7 +895,7 @@ VG_STATIC void world_gen_routes_generate( u32 instance_id ){
 }
 
 /* load all routes from model header */
-VG_STATIC void world_gen_routes_ent_init( world_instance *world ){
+static void world_gen_routes_ent_init( world_instance *world ){
    vg_info( "Initializing routes\n" );
 
    for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
@@ -887,13 +907,13 @@ VG_STATIC void world_gen_routes_ent_init( world_instance *world ){
 
    for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
       ent_route *route = mdl_arritm(&world->ent_route,i);
-      mdl_transform_m4x3( &route->transform, route->board_transform );
+      mdl_transform_m4x3( &route->anon.transform, route->board_transform );
 
-      route->official_track_id = 0xffffffff;
+      route->anon.official_track_id = 0xffffffff;
       for( u32 j=0; j<vg_list_size(track_infos); j ++ ){
          if( !strcmp(track_infos[j].name, 
                      mdl_pstr(&world->meta,route->pstr_name))){
-            route->official_track_id = j;
+            route->anon.official_track_id = j;
          }
       }
 
@@ -935,14 +955,37 @@ VG_STATIC void world_gen_routes_ent_init( world_instance *world ){
    world_routes_clear( world );
 }
 
+static void world_routes_recv_scoreboard( world_instance *world, 
+                                          vg_msg *body, u32 route_id,
+                                          enum request_status status ){
+   if( route_id >= mdl_arrcount( &world->ent_route ) ){
+      vg_error( "Scoreboard route_id out of range (%u)\n", route_id );
+      return;
+   }
+
+   struct leaderboard_cache *board = &world->leaderboard_cache[ route_id ];
+   board->status = status;
+
+   if( body == NULL )
+      board->data_len = 0;
+
+   if( body->max > NETWORK_LEADERBOARD_MAX_SIZE ){
+      vg_error( "Scoreboard leaderboard too big (%u>%u)\n", body->max,
+                NETWORK_LEADERBOARD_MAX_SIZE );
+      return;
+   }
+
+   memcpy( board->data, body->buf, body->max );
+   board->data_len = body->max;
+}
+
 /* 
  * -----------------------------------------------------------------------------
  *                                    Events
  * -----------------------------------------------------------------------------
  */
 
-VG_STATIC void world_routes_init(void)
-{
+static void world_routes_init(void){
    world_static.current_run_version = 200;
    world_static.time = 300.0;
    world_static.last_use = 0.0;
@@ -951,15 +994,16 @@ VG_STATIC void world_routes_init(void)
    shader_routeui_register();
 }
 
-VG_STATIC void world_routes_update( world_instance *world )
-{
+static void world_routes_update( world_instance *world ){
    world_static.time += vg.time_delta;
 
    for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
       ent_route *route = mdl_arritm( &world->ent_route, i );
       
-      int target = route->active_checkpoint == 0xffff? 0: 1;
-      route->factive = vg_lerpf( route->factive, target, 0.6f*vg.time_delta );
+      int target = (route->active_checkpoint == 0xffff? 0: 1) || 
+                    skaterift.activity == k_skaterift_respawning;
+      route->factive = vg_lerpf( route->factive, target, 
+                                 0.6f*vg.time_frame_delta );
    }
 
    for( u32 i=0; i<world_render.text_particle_count; i++ ){
@@ -968,8 +1012,7 @@ VG_STATIC void world_routes_update( world_instance *world )
    }
 }
 
-VG_STATIC void world_routes_fixedupdate( world_instance *world )
-{
+static void world_routes_fixedupdate( world_instance *world ){
    rb_solver_reset();
 
    for( u32 i=0; i<world_render.text_particle_count; i++ ){
@@ -980,7 +1023,8 @@ VG_STATIC void world_routes_fixedupdate( world_instance *world )
 
          int l = rb_sphere__scene( particle->obj.rb.to_world,
                                    &particle->obj.inf.sphere,
-                                   NULL, &world->rb_geo.inf.scene, buf );
+                                   NULL, &world->rb_geo.inf.scene, buf,
+                                   k_material_flag_ghosts );
 
          for( int j=0; j<l; j++ ){
             buf[j].rba = &particle->obj.rb;
@@ -1012,16 +1056,15 @@ VG_STATIC void world_routes_fixedupdate( world_instance *world )
    }
 }
 
-VG_STATIC void bind_terrain_noise(void);
-VG_STATIC void world_bind_light_array( world_instance *world,
+static void bind_terrain_noise(void);
+static void world_bind_light_array( world_instance *world,
                                        GLuint shader, GLuint location, 
                                        int slot );
-VG_STATIC void world_bind_light_index( world_instance *world,
+static void world_bind_light_index( world_instance *world,
                                        GLuint shader, GLuint location, 
                                        int slot );
 
-VG_STATIC void world_routes_update_timer_texts( world_instance *world )
-{
+static void world_routes_update_timer_texts( world_instance *world ){
    world_render.timer_text_count = 0;
 
    for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
@@ -1093,8 +1136,9 @@ VG_STATIC void world_routes_update_timer_texts( world_instance *world )
             highscore_intr( text->text+2, route->checkpoints_count+1, 1, ' ' );
             text->text[3] = '\0';
          }
-
-         float align_r  = font3d_string_width( &gui.font, 0, text->text );
+   
+         gui_font3d.font = &gui.font;
+         float align_r  = font3d_string_width( 0, text->text );
                align_r *= size;
 
          v3f positions[] = {
@@ -1122,7 +1166,7 @@ VG_STATIC void world_routes_update_timer_texts( world_instance *world )
    }
 }
 
-VG_STATIC void world_routes_fracture( world_instance *world, ent_gate *gate,
+static void world_routes_fracture( world_instance *world, ent_gate *gate,
                                       v3f imp_co, v3f imp_v )
 {
    world_render.text_particle_count = 0;
@@ -1196,9 +1240,20 @@ VG_STATIC void world_routes_fracture( world_instance *world, ent_gate *gate,
    }
 }
 
-VG_STATIC void render_world_routes( world_instance *world, camera *cam, 
-                                    int layer_depth )
-{
+static void render_gate_markers( int run_id, ent_gate *gate ){
+   for( u32 j=0; j<4; j++ ){
+      if( gate->routes[j] == run_id ){
+         m4x3f mmdl;
+         ent_gate_get_mdl_mtx( gate, mmdl );
+         shader_model_gate_uMdl( mmdl );
+         mdl_draw_submesh( &world_gates.sm_marker[j] );
+         break;
+      }
+   }
+}
+
+static void render_world_routes( world_instance *world, camera *cam, 
+                                    int layer_depth ){
    m4x3f identity_matrix;
    m4x3_identity( identity_matrix );
 
@@ -1234,7 +1289,7 @@ VG_STATIC void render_world_routes( world_instance *world, camera *cam,
    /* timers
     * ---------------------------------------------------- */
    if( layer_depth == 0 ){
-      font3d_bind( &gui.font, cam );
+      font3d_bind( &gui.font, k_font_shader_default, 0, world, cam );
 
       for( u32 i=0; i<world_render.timer_text_count; i++ ){
          struct timer_text *text = &world_render.timer_texts[i];
@@ -1245,7 +1300,7 @@ VG_STATIC void render_world_routes( world_instance *world, camera *cam,
          colour[3] = 1.0f-text->route->factive;
 
          shader_model_font_uColour( colour );
-         font3d_simple_draw( &gui.font, 0, text->text, cam, text->transform );
+         font3d_simple_draw( 0, text->text, cam, text->transform );
       }
 
       shader_model_font_uOffset( (v4f){0.0f,0.0f,0.0f,1.0f} );
@@ -1289,37 +1344,48 @@ VG_STATIC void render_world_routes( world_instance *world, camera *cam,
 
    /* skip writing into the motion vectors for this */
    glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } );
+   glDisable( GL_CULL_FACE );
 
-   for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
-      ent_route *route = mdl_arritm( &world->ent_route, i );
+   if( skaterift.activity == k_skaterift_respawning ){
+      for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
+         ent_route *route = mdl_arritm( &world->ent_route, i );
 
-      if( route->active_checkpoint != 0xffff ){
          v4f colour;
-         float brightness = 0.3f + world->ub_lighting.g_day_phase;
-         v3_muls( route->colour, brightness, colour );
-         colour[3] = 1.0f-route->factive;
+         v3_muls( route->colour, 1.6666f, colour );
+         colour[3] = 0.0f;
 
          shader_model_gate_uColour( colour );
 
-         u32 next = route->active_checkpoint+1+layer_depth;
-             next = next % route->checkpoints_count;
-             next += route->checkpoints_start;
+         for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
+            ent_gate *gate = mdl_arritm( &world->ent_gate, j );
+            if( !(gate->flags & k_ent_gate_nonlocal) )
+               render_gate_markers( i, gate );
+         }
+      }
+   }
+   else{
+      for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
+         ent_route *route = mdl_arritm( &world->ent_route, i );
 
-         ent_checkpoint *cp = mdl_arritm( &world->ent_checkpoint, next );
-         ent_gate *gate = mdl_arritm( &world->ent_gate, cp->gate_index );
+         if( route->active_checkpoint != 0xffff ){
+            v4f colour;
+            float brightness = 0.3f + world->ub_lighting.g_day_phase;
+            v3_muls( route->colour, brightness, colour );
+            colour[3] = 1.0f-route->factive;
 
-         m4x3f mmdl;
-         ent_gate_get_mdl_mtx( gate, mmdl );
-         shader_model_gate_uMdl( mmdl );
+            shader_model_gate_uColour( colour );
 
-         for( u32 j=0; j<4; j++ ){
-            if( gate->routes[j] == i ){
-               mdl_draw_submesh( &world_gates.sm_marker[j] );
-               break;
-            }
+            u32 next = route->active_checkpoint+1+layer_depth;
+                next = next % route->checkpoints_count;
+                next += route->checkpoints_start;
+
+            ent_checkpoint *cp = mdl_arritm( &world->ent_checkpoint, next );
+            ent_gate *gate = mdl_arritm( &world->ent_gate, cp->gate_index );
+            render_gate_markers( i, gate );
          }
       }
    }
+   glEnable( GL_CULL_FACE );
    glDrawBuffers( 2, (GLenum[]){ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 } );
 }