+ if( inode->special_type == k_route_special_type_collector )
+ {
+ timings[sj ++] = &world.collectors[ inode->special_id ].timing;
+ }
+ else if( inode->special_type == k_route_special_type_gate )
+ {
+ timings[sj ++] = &world.gates[inode->special_id].timing;
+ }
+ }
+
+ for( u32 i=0; i<sj; i++ )
+ {
+ if( timings[i]->version > maxv )
+ {
+ maxv = timings[i]->version;
+ begin = i;
+ }
+ }
+
+ vg_info( "== begin verification (%u) ==\n", route );
+ vg_info( " current version: %u\n", world.current_run_version );
+
+ int verified = 0;
+ if( timings[begin]->version == world.current_run_version )
+ verified = 1;
+
+ int valid_segment_count = 0;
+
+ double lap_time = 0.0;
+
+ for( u32 i=0; i<sj; i++ )
+ {
+ u32 j = (sj+begin-i-1) % sj,
+ j1 = (j+1) % sj;
+
+ double diff = 0.0;
+
+ if( i<sj-1 )
+ {
+ /* j1v should equal jv+1 */
+ if( timings[j1]->version == timings[j]->version+1 )
+ {
+ diff = timings[j1]->time - timings[j]->time;
+ lap_time += diff;
+
+ if( verified && diff > 0.0 ) valid_segment_count ++;
+ }
+ else
+ verified = 0;
+ }
+
+ if( verified )
+ vg_success( " [ %u %f ] %f\n", timings[j1]->time,
+ timings[j1]->version, diff );
+ else
+ vg_warn( " [ %u %f ]\n", timings[j1]->time, timings[j1]->version );
+ }
+
+ pui->fade_start = pui->segment_start;
+ pui->fade_count = 0;
+ pui->fade_timer_start = world.time;
+
+ int orig_seg_count = pui->segment_count;
+
+ world_routes_ui_newseg( route );
+
+ if( verified )
+ {
+ world_routes_local_set_record( route, lap_time );
+ world_routes_ui_popfirst( pui );
+ pui->fade_count ++;
+ }
+ else
+ vg_info( " ctime: %f\n", lap_time );
+
+ /* remove any excess we had from previous runs */
+ int to_remove = orig_seg_count-valid_segment_count;
+ for( int i=0; i<to_remove; i++ )
+ {
+ world_routes_ui_popfirst( pui );
+ pui->fade_count ++;
+ }
+
+ world.routes[route].latest_pass = world.time;
+}
+
+/*
+ * When going through a gate this is called for bookkeeping purposes
+ */
+VG_STATIC void world_routes_activate_gate( u32 id )
+{
+ struct route_gate *rg = &world.gates[id];
+ struct route_node *pnode = &world.nodes[rg->node_id],
+ *pdest = &world.nodes[pnode->next[0]];
+
+ world.last_use = world.time;
+
+ struct route_collector *rc = &world.collectors[ pdest->special_id ];
+
+ world.active_gate = id;
+ rg->timing.version = world.current_run_version;
+ rg->timing.time = world.time;
+
+ for( u32 i=0; i<world.route_count; i++ )
+ {
+ struct route *route = &world.routes[i];
+
+ int was_active = route->active;
+
+ route->active = 0;
+ for( u32 j=0; j<pdest->ref_count; j++ )
+ {
+ if( pdest->route_ids[j] == i )
+ {
+ world_routes_verify_run( i );
+ route->active = 1;
+ break;
+ }
+ }
+
+ if( was_active && !route->active )
+ {
+ struct route_ui_bar *pui = &world.ui_bars[i];
+ pui->fade_start = pui->segment_start;
+ pui->fade_count = pui->segment_count;
+ pui->fade_timer_start = world.time;
+
+ world_routes_ui_clear( pui );
+ vg_success( "CLEARING -> %u %u \n", pui->fade_start,
+ pui->fade_count );
+ }
+ }
+
+ world.current_run_version ++;
+
+ rc->timing.version = world.current_run_version;
+ rc->timing.time = world.time;
+ world.current_run_version ++;
+}
+
+/*
+ * Notify the UI system that we've reset the player
+ */
+VG_STATIC void world_routes_notify_reset(void)
+{
+ world.rewind_from = world.time;
+ world.rewind_to = world.last_use;
+
+#if 0
+ for( int i=0; i<r->route_count; i++ )
+ {
+ struct route *route = &r->routes[i];
+
+ if( route->active )
+ world_routes_ui_notch( i, r->time - route->latest_pass );
+ }
+#endif
+}
+
+/* Rewind between the saved points in time */
+VG_STATIC void world_routes_rollback_time( double t )
+{
+ world.time = vg_lerp( world.rewind_to, world.rewind_from, t );
+}
+
+/* draw lines along the paths */
+VG_STATIC void world_routes_debug(void)
+{
+ for( int i=0; i<world.node_count; i++ )
+ {
+ struct route_node *rn = &world.nodes[i];
+ vg_line_pt3( rn->co, 1.0f, rn->special_type? 0xffffff00: 0xff00b2ff );
+ }
+
+ for( int i=0; i<world.route_count; i++ )
+ {
+ struct route *route = &world.routes[i];
+
+ u32 stack[64];
+ u32 si = world_routes_get_path( route->start, stack );
+
+ u32 colours[] = { 0xfff58142, 0xff42cbf5, 0xff42f56c, 0xfff542b3,
+ 0xff5442f5 };
+
+ u32 cc = colours[i%vg_list_size(colours)];
+
+ for( int sj=0; sj<si; sj++ )
+ {
+ int sk = (sj+1)%si;
+
+ struct route_node *pj = &world.nodes[stack[sj]],
+ *pk = &world.nodes[stack[sk]];
+ debug_sbpath( pj, pk, cc, (float)i );
+ }
+ }
+
+ for( int i=0; i<world.node_count; i++ )
+ {
+ struct route_node *ri = &world.nodes[i],
+ *rj = NULL;
+
+ for( int j=0; j<2; j++ )
+ {
+ if( ri->next[j] != 0xffffffff )