1 #ifndef ENT_SKATESHOP_C
2 #define ENT_SKATESHOP_C
7 #define MAX_LOCAL_BOARDS 64
8 #define BILL_TIN_BOARDS 1
9 #define MAX_DYNAMIC_BOARDS 9
13 mdl_transform rack_root
,
17 enum camera_mode prev_camera_mode
;
23 k_skateshop_loc_page__viewing
,
25 k_skateshop_loc_select_use
,
26 k_skateshop_loc_select_cancel
,
27 k_skateshop_loc_select_upload
,
28 k_skateshop_loc_page__selected
,
30 k_skateshop_loc_page__upload
,
36 enum dynamic_board_state
{
37 k_dynamic_board_state_none
,
38 k_dynamic_board_state_loaded
,
39 k_dynamic_board_state_loading
,
45 struct player_board board
;
56 struct dynamic_board
*db
;
66 struct dynamic_board
*dynamic
;
68 char filename
[64]; /* if workshop, string version of uid. */
77 float interaction_cooldown
;
79 u32 selected_registry_id
;
81 static global_skateshop
;
83 static inline int const_str_eq( u32 hash
, const char *str
, const char *cmp
)
85 if( hash
== vg_strdjb2(cmp
) )
86 if( !strcmp( str
, cmp
) )
91 static int skateshop_workshop_name_blacklisted( u32 hash
, const char *name
)
93 if( const_str_eq( hash
, name
, "skaterift_fish.mdl" ) ) return 1;
97 VG_STATIC
void skateshop_loader_start( void (*pfn
)(void) )
99 if( global_skateshop
.loading
)
100 vg_fatal_error( "skateshop thread sync failure\n" );
102 global_skateshop
.loading
= 1;
103 vg_loader_start( pfn
);
106 VG_STATIC
void skateshop_async_post( void *payload
, u32 size
)
108 global_skateshop
.loading
= 0;
112 struct dynamic_board
*skateshop_lru_alloc( u32 id
)
114 double min_time
= 1e300
;
115 struct dynamic_board
*min_board
= NULL
;
117 for( u32 i
=0; i
<MAX_DYNAMIC_BOARDS
; i
++ ){
118 struct dynamic_board
*db
= &global_skateshop
.dynamic_boards
[i
];
120 if( db
->state
== k_dynamic_board_state_loading
)
126 if( db
->last_use_time
< min_time
){
127 min_time
= db
->last_use_time
;
133 localplayer
.board
= NULL
; /* temp */
135 if( min_board
->state
== k_dynamic_board_state_loaded
){
136 struct board_registry
*other
=
137 &global_skateshop
.registry
[min_board
->registry_id
];
139 vg_info( "Deallocating board: '%s'\n", min_board
, other
->filename
);
141 player_board_unload( &min_board
->board
);
142 other
->dynamic
= NULL
;
145 struct board_registry
*reg
= &global_skateshop
.registry
[id
];
147 vg_info( "Allocating board '%s' @%p\n", reg
->filename
, min_board
);
149 min_board
->state
= k_dynamic_board_state_loading
;
150 min_board
->registry_id
= id
;
151 min_board
->last_use_time
= vg
.time
;
152 min_board
->ref_count
= 0;
155 vg_error( "No free boards to load registry!\n" );
162 void skateshop_board_registry_path( struct board_registry
*reg
, char path
[256] )
165 snprintf( path
, 256, "models/boards/workshop/%s/something.mdl",
169 snprintf( path
, 256, "models/boards/%s", reg
->filename
);
173 VG_STATIC
void skateshop_async_board_complete( void *payload
, u32 size
)
175 struct dynamic_board
*db
= payload
;
177 if( db
== global_skateshop
.localplayer_slot
){
178 localplayer
.board
= &db
->board
;
182 for( u32 i
=0; i
<vg_list_size(global_skateshop
.shop_view_slots
); i
++ ){
183 if( global_skateshop
.shop_view_slots
[i
].db
== db
){
189 db
->last_use_time
= vg
.time
;
190 db
->state
= k_dynamic_board_state_loaded
;
192 struct board_registry
*reg
= &global_skateshop
.registry
[ db
->registry_id
];
195 vg_success( "Async board loaded (%s)\n", reg
->filename
);
198 VG_STATIC
void skateshop_load_requested_boards(void)
201 for( u32 i
=0; i
<MAX_DYNAMIC_BOARDS
; i
++ ){
202 struct dynamic_board
*db
= &global_skateshop
.dynamic_boards
[i
];
204 if( db
->state
== k_dynamic_board_state_loading
){
205 struct board_registry
*reg
=
206 &global_skateshop
.registry
[ db
->registry_id
];
208 skateshop_board_registry_path( reg
, path
);
209 player_board_load( &db
->board
, path
);
210 vg_async_call( skateshop_async_board_complete
, db
, 0 );
215 VG_STATIC
void skateshop_thread1_refresh(void)
217 skateshop_load_requested_boards();
218 vg_async_call( skateshop_async_post
, NULL
, 0 );
221 VG_STATIC
int skateshop_use_board( int argc
, const char *argv
[] )
223 if( global_skateshop
.loading
){
224 vg_error( "Cannot use skateshop currently (loader thread missing)\n" );
229 u32 hash
= vg_strdjb2( argv
[0] );
231 for( u32 i
=0; i
<global_skateshop
.registry_count
; i
++ ){
232 struct board_registry
*reg
= &global_skateshop
.registry
[i
];
234 if( const_str_eq( hash
, argv
[0], reg
->filename
) ){
237 struct dynamic_board
*db
= reg
->dynamic
;
239 if( db
->state
== k_dynamic_board_state_loaded
){
240 localplayer
.board
= &db
->board
;
241 db
->last_use_time
= vg
.time
;
244 vg_fatal_error( "Invalid state while loading board\n" );
248 struct dynamic_board
*db
= skateshop_lru_alloc( i
);
249 db
->state
= k_dynamic_board_state_loading
;
250 skateshop_loader_start( skateshop_thread1_refresh
);
259 VG_STATIC
void skateshop_use_board_suggest( int argc
, const char *argv
[] )
262 for( u32 i
=0; i
<global_skateshop
.registry_count
; i
++ ){
263 struct board_registry
*reg
= &global_skateshop
.registry
[i
];
265 if( reg
->ghost
) continue; /* we probably can't load these */
267 console_suggest_score_text( reg
->filename
, argv
[0], 0 );
272 VG_STATIC
void skateshop_scan_for_items(void)
274 vg_linear_clear( vg_mem
.scratch
);
276 for( u32 i
=0; i
<global_skateshop
.registry_count
; i
++ ){
277 struct board_registry
*reg
= &global_skateshop
.registry
[i
];
282 tinydir_open( &dir
, "models/boards" );
284 while( dir
.has_next
){
286 tinydir_readfile( &dir
, &file
);
289 u32 hash
= vg_strdjb2( file
.name
);
291 for( u32 i
=0; i
<global_skateshop
.registry_count
; i
++ ){
292 struct board_registry
*reg
= &global_skateshop
.registry
[i
];
294 if( const_str_eq( hash
, file
.name
, reg
->filename
) ){
300 if( global_skateshop
.registry_count
== MAX_LOCAL_BOARDS
){
301 vg_error( "You have too many boards installed!\n" );
305 vg_info( "new listing!: %s\n", file
.name
);
307 struct board_registry
*reg
= &global_skateshop
.registry
[
308 global_skateshop
.registry_count
++ ];
311 vg_strncpy( file
.name
, reg
->filename
, 64, k_strncpy_always_add_null
);
312 reg
->filename_hash
= hash
;
318 next_file
: tinydir_next( &dir
);
323 skateshop_load_requested_boards();
324 vg_async_call( skateshop_async_post
, NULL
, 0 );
327 VG_STATIC
void global_skateshop_exit(void)
329 global_skateshop
.active
= 0;
330 localplayer
.camera_mode
= global_skateshop
.prev_camera_mode
;
333 VG_STATIC
void skateshop_request_viewpage( u32 page
)
335 u32 slot_count
= vg_list_size(global_skateshop
.shop_view_slots
);
336 u32 start
= page
* slot_count
;
338 for( u32 i
=0; i
<slot_count
; i
++ ){
339 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
342 slot
->db
->ref_count
--;
346 u32 reg_index
= start
+i
;
347 if( reg_index
< global_skateshop
.registry_count
){
348 struct board_registry
*reg
= &global_skateshop
.registry
[ reg_index
];
351 struct dynamic_board
*db
= reg
->dynamic
;
353 if( db
->state
== k_dynamic_board_state_loaded
){
354 db
->last_use_time
= vg
.time
;
359 vg_fatal_error( "Invalid state while loading page\n" );
363 struct dynamic_board
*db
= skateshop_lru_alloc( reg_index
);
374 VG_STATIC
void ent_skateshop_call( world_instance
*world
, ent_call
*call
)
376 u32 index
= mdl_entity_id_id( call
->id
);
377 ent_skateshop
*shop
= mdl_arritm( &world
->ent_skateshop
, index
);
378 vg_info( "skateshop_call\n" );
380 if( global_skateshop
.loading
){
381 vg_error( "Cannot enter skateshop currently (loader thread missing)\n" );
385 if( call
->function
== k_ent_function_trigger
){
386 if( localplayer
.subsystem
!= k_player_subsystem_walk
){
390 vg_info( "Entering skateshop\n" );
392 localplayer
.immobile
= 1;
393 global_skateshop
.prev_camera_mode
= localplayer
.camera_mode
;
394 localplayer
.camera_mode
= k_cam_firstperson
;
395 global_skateshop
.active
= 1;
396 global_skateshop
.interface_loc
= k_skateshop_loc_page__viewing
;
398 v3_zero( localplayer
.rb
.v
);
399 v3_zero( localplayer
.rb
.w
);
400 localplayer
._walk
.move_speed
= 0.0f
;
403 mdl_transform
*transform
;
407 { &global_skateshop
.rack_root
, shop
->id_rack
, },
408 { &global_skateshop
.info_root
, shop
->id_info
, },
409 { &global_skateshop
.display_root
, shop
->id_display
, },
412 v3_copy( shop
->transform
.co
, global_skateshop
.look_target
);
414 for( u32 i
=0; i
<vg_list_size(targets
); i
++ ){
416 u32 type
= mdl_entity_id_type( targets
[i
].id
),
417 index
= mdl_entity_id_id( targets
[i
].id
);
419 if( type
== k_ent_marker
){
420 ent_marker
*m
= mdl_arritm( &world
->ent_marker
, index
);
422 *targets
[i
].transform
= m
->transform
;
425 transform_identity( targets
[i
].transform
);
429 skateshop_request_viewpage(0);
430 skateshop_loader_start( skateshop_scan_for_items
);
434 VG_STATIC
void global_skateshop_preupdate(void)
436 float rate
= vg_minf( 1.0f
, vg
.time_frame_delta
* 2.0f
);
437 global_skateshop
.factive
= vg_lerpf( global_skateshop
.factive
,
438 global_skateshop
.active
, rate
);
441 if( !global_skateshop
.active
) return;
444 v3_sub( global_skateshop
.look_target
, localplayer
.cam
.pos
, delta
);
445 v3_normalize( delta
);
448 player_vector_angles( target
, delta
, 1.0f
, 0.0f
);
450 camera_lerp_angles( localplayer
.angles
, target
,
451 global_skateshop
.factive
, localplayer
.angles
);
453 if( global_skateshop
.interaction_cooldown
> 0.0f
){
454 global_skateshop
.interaction_cooldown
-= vg
.time_delta
;
458 float h
= localplayer
.input_js1h
->axis
.value
;
460 if( global_skateshop
.interface_loc
<= k_skateshop_loc_page__viewing
){
461 if( fabsf(h
) > 0.25f
){
463 if( global_skateshop
.selected_registry_id
> 0 )
464 global_skateshop
.selected_registry_id
--;
467 if( global_skateshop
.selected_registry_id
<
468 global_skateshop
.registry_count
-1 )
470 global_skateshop
.selected_registry_id
++;
474 vg_info( "Select registry: %u\n",
475 global_skateshop
.selected_registry_id
);
476 global_skateshop
.interaction_cooldown
= 0.125f
;
480 if( vg_input_button_down( &input_menu_back
) ){
481 global_skateshop
.active
= 0;
485 else if( global_skateshop
.interface_loc
<= k_skateshop_loc_page__selected
){
486 if( vg_input_button_down( &input_menu_back
) ){
487 global_skateshop
.interface_loc
= k_skateshop_loc_page__viewing
;
491 if( fabsf(h
) > 0.25f
){
492 if( global_skateshop
.interface_loc
== k_skateshop_loc_select_use
){
493 global_skateshop
.interface_loc
= k_skateshop_loc_select_cancel
;
498 if( global_skateshop
.interface_loc
== k_skateshop_loc_select_cancel
){
499 global_skateshop
.interface_loc
= k_skateshop_loc_select_use
;
506 VG_STATIC
void skateshop_init(void)
508 global_skateshop
.registry
=
509 vg_linear_alloc( vg_mem
.rtmemory
,
510 sizeof(struct board_registry
)*MAX_LOCAL_BOARDS
);
511 global_skateshop
.registry_count
= 0;
512 global_skateshop
.dynamic_boards
=
513 vg_linear_alloc( vg_mem
.rtmemory
,
514 sizeof(struct dynamic_board
)*MAX_DYNAMIC_BOARDS
);
516 memset( global_skateshop
.dynamic_boards
, 0,
517 sizeof(struct dynamic_board
)*MAX_DYNAMIC_BOARDS
);
519 for( u32 i
=0; i
<MAX_DYNAMIC_BOARDS
; i
++ ){
520 struct dynamic_board
*board
= &global_skateshop
.dynamic_boards
[i
];
521 board
->state
= k_dynamic_board_state_none
;
522 board
->registry_id
= 0xffffffff;
523 board
->last_use_time
= -99999.9;
524 board
->ref_count
= 0;
527 vg_console_reg_cmd( "use_board",
528 skateshop_use_board
, skateshop_use_board_suggest
);
530 skateshop_scan_for_items();
533 VG_STATIC
void skateshop_render(void)
535 if( !global_skateshop
.active
) return;
537 world_instance
*world
= get_active_world();
539 u32 slot_count
= vg_list_size(global_skateshop
.shop_view_slots
);
541 for( u32 i
=0; i
<slot_count
; i
++ ){
542 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
544 float selected
= 0.0f
;
549 if( slot
->db
->state
!= k_dynamic_board_state_loaded
)
552 mdl_transform rack_xform
;
553 transform_identity( &rack_xform
);
555 rack_xform
.co
[0] = -((float)i
- ((float)slot_count
)*0.5f
)*0.45f
;
557 mdl_transform_mul( &global_skateshop
.rack_root
,
558 &rack_xform
, &rack_xform
);
560 if( slot
->db
->registry_id
== global_skateshop
.selected_registry_id
){
564 float t
= slot
->view_blend
;
565 v3_lerp( rack_xform
.co
, global_skateshop
.display_root
.co
,
567 q_nlerp( rack_xform
.q
, global_skateshop
.display_root
.q
,
569 v3_lerp( rack_xform
.s
, global_skateshop
.display_root
.s
,
573 mdl_transform_m4x3( &rack_xform
, mmdl
);
574 render_board( &main_camera
, world
, &slot
->db
->board
, mmdl
,
575 k_board_shader_entity
);
578 float rate
= 5.0f
*vg
.time_delta
;
579 slot
->view_blend
= vg_lerpf( slot
->view_blend
, selected
, rate
);
583 mdl_transform_m4x3( &global_skateshop
.info_root
, mtext
);
585 m4x3f mlocal
= {{0.2f
,0.0f
,0.0f
},{0.0f
,0.2f
,0.0f
},{0.0f
,0.0f
,0.03f
},
586 {-font3d_string_width( &world_global
.font
,0,
587 "Made by... Bob man 123" )*0.2f
*0.5f
,0.0f
,0.0f
}
590 m4x3_mul( mtext
, mlocal
, mtext
);
592 font3d_bind( &world_global
.font
, &main_camera
);
594 shader_model_font_uColour( (v4f
){1.0f
,0.5f
,0.1f
,1.0f
} );
595 font3d_simple_draw( &world_global
.font
, 0, "Made by... Bob man 123",
596 &main_camera
, mtext
);
599 #endif /* ENT_SKATESHOP_C */