b126abf3a3defee29929916521ff765378568bee
[carveJwlIkooP6JGAAIwe30JlM.git] / ent_skateshop.c
1 #ifndef ENT_SKATESHOP_C
2 #define ENT_SKATESHOP_C
3
4 #include "world.h"
5 #include "player.h"
6
7 #define MAX_LOCAL_BOARDS 64
8 #define BILL_TIN_BOARDS 1
9 #define MAX_DYNAMIC_BOARDS 9
10
11 struct{
12 v3f look_target;
13 mdl_transform rack_root,
14 display_root,
15 info_root;
16
17 enum camera_mode prev_camera_mode;
18
19 int active;
20 float factive;
21
22 enum skateshop_loc{
23 k_skateshop_loc_page__viewing,
24
25 k_skateshop_loc_select_use,
26 k_skateshop_loc_select_cancel,
27 k_skateshop_loc_select_upload,
28 k_skateshop_loc_page__selected,
29
30 k_skateshop_loc_page__upload,
31 }
32 interface_loc;
33
34 struct dynamic_board
35 {
36 enum dynamic_board_state{
37 k_dynamic_board_state_none,
38 k_dynamic_board_state_loaded,
39 k_dynamic_board_state_loading,
40 }
41 state;
42
43 u32 ref_count;
44
45 struct player_board board;
46
47 u32 registry_id;
48
49 double last_use_time;
50 }
51 *dynamic_boards,
52 *localplayer_slot;
53
54 struct shop_view_slot
55 {
56 struct dynamic_board *db;
57 float view_blend;
58 }
59 shop_view_slots[6];
60
61 struct board_registry
62 {
63 int workshop;
64 u64 uid;
65
66 struct dynamic_board *dynamic;
67
68 char filename[64]; /* if workshop, string version of uid. */
69 u32 filename_hash;
70
71 int ghost;
72 }
73 *registry;
74 u32 registry_count;
75
76 int loading;
77 float interaction_cooldown;
78
79 u32 selected_registry_id;
80 }
81 static global_skateshop;
82
83 static inline int const_str_eq( u32 hash, const char *str, const char *cmp )
84 {
85 if( hash == vg_strdjb2(cmp) )
86 if( !strcmp( str, cmp ) )
87 return 1;
88 return 0;
89 }
90
91 static int skateshop_workshop_name_blacklisted( u32 hash, const char *name )
92 {
93 if( const_str_eq( hash, name, "skaterift_fish.mdl" ) ) return 1;
94 return 0;
95 }
96
97 VG_STATIC void skateshop_loader_start( void (*pfn)(void) )
98 {
99 if( global_skateshop.loading )
100 vg_fatal_error( "skateshop thread sync failure\n" );
101
102 global_skateshop.loading = 1;
103 vg_loader_start( pfn );
104 }
105
106 VG_STATIC void skateshop_async_post( void *payload, u32 size )
107 {
108 global_skateshop.loading = 0;
109 }
110
111 VG_STATIC
112 struct dynamic_board *skateshop_lru_alloc( u32 id )
113 {
114 double min_time = 1e300;
115 struct dynamic_board *min_board = NULL;
116
117 for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
118 struct dynamic_board *db = &global_skateshop.dynamic_boards[i];
119
120 if( db->state == k_dynamic_board_state_loading )
121 continue;
122
123 if( db->ref_count )
124 continue;
125
126 if( db->last_use_time < min_time ){
127 min_time = db->last_use_time;
128 min_board = db;
129 }
130 }
131
132 if( min_board ){
133 localplayer.board = NULL; /* temp */
134
135 if( min_board->state == k_dynamic_board_state_loaded ){
136 struct board_registry *other =
137 &global_skateshop.registry[min_board->registry_id];
138
139 vg_info( "Deallocating board: '%s'\n", min_board, other->filename );
140
141 player_board_unload( &min_board->board );
142 other->dynamic = NULL;
143 }
144
145 struct board_registry *reg = &global_skateshop.registry[id];
146
147 vg_info( "Allocating board '%s' @%p\n", reg->filename, min_board );
148
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;
153 }
154 else{
155 vg_error( "No free boards to load registry!\n" );
156 }
157
158 return min_board;
159 }
160
161 VG_STATIC
162 void skateshop_board_registry_path( struct board_registry *reg, char path[256] )
163 {
164 if( reg->workshop ){
165 snprintf( path, 256, "models/boards/workshop/%s/something.mdl",
166 reg->filename );
167 }
168 else{
169 snprintf( path, 256, "models/boards/%s", reg->filename );
170 }
171 }
172
173 VG_STATIC void skateshop_async_board_complete( void *payload, u32 size )
174 {
175 struct dynamic_board *db = payload;
176
177 if( db == global_skateshop.localplayer_slot ){
178 localplayer.board = &db->board;
179 db->ref_count ++;
180 }
181 else{
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 ){
184 db->ref_count ++;
185 }
186 }
187 }
188
189 db->last_use_time = vg.time;
190 db->state = k_dynamic_board_state_loaded;
191
192 struct board_registry *reg = &global_skateshop.registry[ db->registry_id ];
193 reg->dynamic = db;
194
195 vg_success( "Async board loaded (%s)\n", reg->filename );
196 }
197
198 VG_STATIC void skateshop_load_requested_boards(void)
199 {
200 char path[256];
201 for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
202 struct dynamic_board *db = &global_skateshop.dynamic_boards[i];
203
204 if( db->state == k_dynamic_board_state_loading ){
205 struct board_registry *reg =
206 &global_skateshop.registry[ db->registry_id ];
207
208 skateshop_board_registry_path( reg, path );
209 player_board_load( &db->board, path );
210 vg_async_call( skateshop_async_board_complete, db, 0 );
211 }
212 }
213 }
214
215 VG_STATIC void skateshop_thread1_refresh(void)
216 {
217 skateshop_load_requested_boards();
218 vg_async_call( skateshop_async_post, NULL, 0 );
219 }
220
221 VG_STATIC int skateshop_use_board( int argc, const char *argv[] )
222 {
223 if( global_skateshop.loading ){
224 vg_error( "Cannot use skateshop currently (loader thread missing)\n" );
225 return 0;
226 }
227
228 if( argc == 1 ){
229 u32 hash = vg_strdjb2( argv[0] );
230
231 for( u32 i=0; i<global_skateshop.registry_count; i++ ){
232 struct board_registry *reg = &global_skateshop.registry[i];
233
234 if( const_str_eq( hash, argv[0], reg->filename ) ){
235
236 if( reg->dynamic ){
237 struct dynamic_board *db = reg->dynamic;
238
239 if( db->state == k_dynamic_board_state_loaded ){
240 localplayer.board = &db->board;
241 db->last_use_time = vg.time;
242 }
243 else{
244 vg_fatal_error( "Invalid state while loading board\n" );
245 }
246 }
247 else{
248 struct dynamic_board *db = skateshop_lru_alloc( i );
249 db->state = k_dynamic_board_state_loading;
250 skateshop_loader_start( skateshop_thread1_refresh );
251 }
252 return 1;
253 }
254 }
255 }
256 return 0;
257 }
258
259 VG_STATIC void skateshop_use_board_suggest( int argc, const char *argv[] )
260 {
261 if( argc == 1 ){
262 for( u32 i=0; i<global_skateshop.registry_count; i++ ){
263 struct board_registry *reg = &global_skateshop.registry[i];
264
265 if( reg->ghost ) continue; /* we probably can't load these */
266
267 console_suggest_score_text( reg->filename, argv[0], 0 );
268 }
269 }
270 }
271
272 VG_STATIC void skateshop_scan_for_items(void)
273 {
274 vg_linear_clear( vg_mem.scratch );
275
276 for( u32 i=0; i<global_skateshop.registry_count; i++ ){
277 struct board_registry *reg = &global_skateshop.registry[i];
278 reg->ghost = 1;
279 }
280
281 tinydir_dir dir;
282 tinydir_open( &dir, "models/boards" );
283
284 while( dir.has_next ){
285 tinydir_file file;
286 tinydir_readfile( &dir, &file );
287
288 if( file.is_reg ){
289 u32 hash = vg_strdjb2( file.name );
290
291 for( u32 i=0; i<global_skateshop.registry_count; i++ ){
292 struct board_registry *reg = &global_skateshop.registry[i];
293
294 if( const_str_eq( hash, file.name, reg->filename ) ){
295 reg->ghost = 0;
296 goto next_file;
297 }
298 }
299
300 if( global_skateshop.registry_count == MAX_LOCAL_BOARDS ){
301 vg_error( "You have too many boards installed!\n" );
302 break;
303 }
304
305 vg_info( "new listing!: %s\n", file.name );
306
307 struct board_registry *reg = &global_skateshop.registry[
308 global_skateshop.registry_count ++ ];
309
310 reg->dynamic = NULL;
311 vg_strncpy( file.name, reg->filename, 64, k_strncpy_always_add_null );
312 reg->filename_hash = hash;
313 reg->uid = 0;
314 reg->workshop = 0;
315 reg->ghost = 0;
316 }
317
318 next_file: tinydir_next( &dir );
319 }
320
321 tinydir_close(&dir);
322
323 skateshop_load_requested_boards();
324 vg_async_call( skateshop_async_post, NULL, 0 );
325 }
326
327 VG_STATIC void global_skateshop_exit(void)
328 {
329 global_skateshop.active = 0;
330 localplayer.camera_mode = global_skateshop.prev_camera_mode;
331 }
332
333 VG_STATIC void skateshop_request_viewpage( u32 page )
334 {
335 u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
336 u32 start = page * slot_count;
337
338 for( u32 i=0; i<slot_count; i++ ){
339 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
340
341 if( slot->db ){
342 slot->db->ref_count --;
343 slot->db = NULL;
344 }
345
346 u32 reg_index = start+i;
347 if( reg_index < global_skateshop.registry_count ){
348 struct board_registry *reg = &global_skateshop.registry[ reg_index ];
349
350 if( reg->dynamic ){
351 struct dynamic_board *db = reg->dynamic;
352
353 if( db->state == k_dynamic_board_state_loaded ){
354 db->last_use_time = vg.time;
355 db->ref_count ++;
356 slot->db = db;
357 }
358 else{
359 vg_fatal_error( "Invalid state while loading page\n" );
360 }
361 }
362 else{
363 struct dynamic_board *db = skateshop_lru_alloc( reg_index );
364
365 if( db ){
366 db->ref_count ++;
367 slot->db = db;
368 }
369 }
370 }
371 }
372 }
373
374 VG_STATIC void ent_skateshop_call( world_instance *world, ent_call *call )
375 {
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" );
379
380 if( global_skateshop.loading ){
381 vg_error( "Cannot enter skateshop currently (loader thread missing)\n" );
382 return;
383 }
384
385 if( call->function == k_ent_function_trigger ){
386 if( localplayer.subsystem != k_player_subsystem_walk ){
387 return;
388 }
389
390 vg_info( "Entering skateshop\n" );
391
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;
397
398 v3_zero( localplayer.rb.v );
399 v3_zero( localplayer.rb.w );
400 localplayer._walk.move_speed = 0.0f;
401
402 struct{
403 mdl_transform *transform;
404 u32 id;
405 }
406 targets[] = {
407 { &global_skateshop.rack_root, shop->id_rack, },
408 { &global_skateshop.info_root, shop->id_info, },
409 { &global_skateshop.display_root, shop->id_display, },
410 };
411
412 v3_copy( shop->transform.co, global_skateshop.look_target );
413
414 for( u32 i=0; i<vg_list_size(targets); i++ ){
415
416 u32 type = mdl_entity_id_type( targets[i].id ),
417 index = mdl_entity_id_id( targets[i].id );
418
419 if( type == k_ent_marker ){
420 ent_marker *m = mdl_arritm( &world->ent_marker, index );
421
422 *targets[i].transform = m->transform;
423 }
424 else{
425 transform_identity( targets[i].transform );
426 }
427 }
428
429 skateshop_request_viewpage(0);
430 skateshop_loader_start( skateshop_scan_for_items );
431 }
432 }
433
434 VG_STATIC void global_skateshop_preupdate(void)
435 {
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 );
439
440
441 if( !global_skateshop.active ) return;
442
443 v3f delta;
444 v3_sub( global_skateshop.look_target, localplayer.cam.pos, delta );
445 v3_normalize( delta );
446
447 v3f target;
448 player_vector_angles( target, delta, 1.0f, 0.0f );
449
450 camera_lerp_angles( localplayer.angles, target,
451 global_skateshop.factive, localplayer.angles);
452
453 if( global_skateshop.interaction_cooldown > 0.0f ){
454 global_skateshop.interaction_cooldown -= vg.time_delta;
455 return;
456 }
457
458 float h = localplayer.input_js1h->axis.value;
459
460 if( global_skateshop.interface_loc <= k_skateshop_loc_page__viewing ){
461 if( fabsf(h) > 0.25f ){
462 if( h < 0.0f ){
463 if( global_skateshop.selected_registry_id > 0 )
464 global_skateshop.selected_registry_id --;
465 }
466 else{
467 if( global_skateshop.selected_registry_id <
468 global_skateshop.registry_count-1 )
469 {
470 global_skateshop.selected_registry_id ++;
471 }
472 }
473
474 vg_info( "Select registry: %u\n",
475 global_skateshop.selected_registry_id );
476 global_skateshop.interaction_cooldown = 0.125f;
477 return;
478 }
479
480 if( vg_input_button_down( &input_menu_back ) ){
481 global_skateshop.active = 0;
482 return;
483 }
484 }
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;
488 return;
489 }
490
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;
494 return;
495 }
496 }
497 else{
498 if( global_skateshop.interface_loc == k_skateshop_loc_select_cancel ){
499 global_skateshop.interface_loc = k_skateshop_loc_select_use;
500 return;
501 }
502 }
503 }
504 }
505
506 VG_STATIC void skateshop_init(void)
507 {
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 );
515
516 memset( global_skateshop.dynamic_boards, 0,
517 sizeof(struct dynamic_board)*MAX_DYNAMIC_BOARDS );
518
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;
525 }
526
527 vg_console_reg_cmd( "use_board",
528 skateshop_use_board, skateshop_use_board_suggest );
529
530 skateshop_scan_for_items();
531 }
532
533 VG_STATIC void skateshop_render(void)
534 {
535 if( !global_skateshop.active ) return;
536
537 world_instance *world = get_active_world();
538
539 u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
540
541 for( u32 i=0; i<slot_count; i++ ){
542 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
543
544 float selected = 0.0f;
545
546 if( !slot->db )
547 goto set_fade_amt;
548
549 if( slot->db->state != k_dynamic_board_state_loaded )
550 goto set_fade_amt;
551
552 mdl_transform rack_xform;
553 transform_identity( &rack_xform );
554
555 rack_xform.co[0] = -((float)i - ((float)slot_count)*0.5f)*0.45f;
556
557 mdl_transform_mul( &global_skateshop.rack_root,
558 &rack_xform, &rack_xform );
559
560 if( slot->db->registry_id == global_skateshop.selected_registry_id ){
561 selected = 1.0f;
562 }
563
564 float t = slot->view_blend;
565 v3_lerp( rack_xform.co, global_skateshop.display_root.co,
566 t, rack_xform.co );
567 q_nlerp( rack_xform.q, global_skateshop.display_root.q,
568 t, rack_xform.q );
569 v3_lerp( rack_xform.s, global_skateshop.display_root.s,
570 t, rack_xform.s );
571
572 m4x3f mmdl;
573 mdl_transform_m4x3( &rack_xform, mmdl );
574 render_board( &main_camera, world, &slot->db->board, mmdl,
575 k_board_shader_entity );
576
577 set_fade_amt:;
578 float rate = 5.0f*vg.time_delta;
579 slot->view_blend = vg_lerpf( slot->view_blend, selected, rate );
580 }
581
582 m4x3f mtext;
583 mdl_transform_m4x3( &global_skateshop.info_root, mtext );
584
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}
588 };
589
590 m4x3_mul( mtext, mlocal, mtext );
591
592 font3d_bind( &world_global.font, &main_camera );
593
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 );
597 }
598
599 #endif /* ENT_SKATESHOP_C */