code is no longer based :(
[carveJwlIkooP6JGAAIwe30JlM.git] / ent_skateshop.c
1 #ifndef ENT_SKATESHOP_C
2 #define ENT_SKATESHOP_C
3
4 #define VG_GAME
5 #include "vg/vg.h"
6 #include "vg/vg_steam_ugc.h"
7 #include "vg/vg_msg.h"
8 #include "ent_skateshop.h"
9 #include "world.h"
10 #include "player.h"
11 #include "gui.h"
12 #include "menu.h"
13 #include "highscores.h"
14 #include "steam.h"
15 #include "addon.h"
16 #include "save.h"
17 #include "network.h"
18
19 /*
20 * Checks string equality but does a hash check first
21 */
22 static inline int const_str_eq( u32 hash, const char *str, const char *cmp )
23 {
24 if( hash == vg_strdjb2(cmp) )
25 if( !strcmp( str, cmp ) )
26 return 1;
27 return 0;
28 }
29
30 static void skateshop_update_viewpage(void){
31 u32 page = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
32
33 for( u32 i=0; i<SKATESHOP_VIEW_SLOT_MAX; i++ ){
34 u32 j = SKATESHOP_VIEW_SLOT_MAX-1-i;
35 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[j];
36 addon_cache_unwatch( k_addon_type_board, slot->cache_id );
37 }
38
39 for( u32 i=0; i<SKATESHOP_VIEW_SLOT_MAX; i++ ){
40 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
41 u32 request_id = page*SKATESHOP_VIEW_SLOT_MAX + i;
42 slot->cache_id = addon_cache_create_viewer( k_addon_type_board,
43 request_id );
44 }
45 }
46
47 /*
48 * op/subroutine: k_workshop_op_item_load
49 * -----------------------------------------------------------------------------
50 */
51
52 static void world_scan_thread( void *_args ){
53 addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" );
54 addon_mount_workshop_items();
55 vg_async_call( async_addon_reg_update, NULL, 0 );
56 }
57
58 /*
59 * Asynchronous scan of local disk for worlds
60 */
61 static void skateshop_op_world_scan(void){
62 vg_loader_start( world_scan_thread, NULL );
63 }
64
65 static void board_processview_thread( void *_args ){
66 addon_cache_load_loop();
67 }
68
69 static void board_scan_thread( void *_args ){
70 addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" );
71 addon_mount_workshop_items();
72 vg_async_call( async_addon_reg_update, NULL, 0 );
73 vg_async_stall();
74 board_processview_thread(NULL);
75 }
76
77 /* TODO: migrate to addon.c */
78 static void skateshop_op_board_scan(void){
79 vg_loader_start( board_scan_thread, NULL );
80 }
81
82 /* TODO: migrate to addon.c */
83 static void skateshop_autostart_loading(void){
84 if( !vg_loader_availible() ) return;
85
86 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
87 for( u32 type=0; type<k_addon_type_max; type++ ){
88 struct addon_cache *cache = &addon_system.cache[type];
89
90 for( u32 id=1; id<=cache->pool.count; id++ ){
91 addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
92 if( entry->state == k_addon_cache_state_load_request ){
93 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
94 goto launch;
95 }
96 }
97 }
98 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
99 return;
100 launch:
101 vg_loader_start( board_processview_thread, NULL );
102 }
103
104 /*
105 * Regular stuff
106 * -----------------------------------------------------------------------------
107 */
108
109 /*
110 * VG event init
111 */
112 static void skateshop_init(void){
113 }
114
115 static u16 skateshop_selected_cache_id(void){
116 if( addon_count(k_addon_type_board) ){
117 addon_reg *reg = get_addon_from_index(k_addon_type_board,
118 global_skateshop.selected_board_id);
119 return reg->cache_id;
120 }
121 else return 0;
122 }
123
124 /*
125 * VG event preupdate
126 */
127 void temp_update_playermodel(void);
128 static void ent_skateshop_preupdate( ent_skateshop *shop, int active ){
129 if( !active ) return;
130
131 /* input filter */
132 world_instance *world = world_current_instance();
133
134 /* camera positioning */
135 ent_camera *ref = mdl_arritm( &world->ent_camera,
136 mdl_entity_id_id(shop->id_camera) );
137
138 v3f dir = {0.0f,-1.0f,0.0f};
139 mdl_transform_vector( &ref->transform, dir, dir );
140 v3_angles( dir, world_static.focus_cam.angles );
141
142 v3f lookat;
143 if( shop->type == k_skateshop_type_boardshop ||
144 shop->type == k_skateshop_type_worldshop ){
145 ent_marker *display = mdl_arritm( &world->ent_marker,
146 mdl_entity_id_id(shop->boards.id_display) );
147 v3_sub( display->transform.co, localplayer.rb.co, lookat );
148 }
149 else if( shop->type == k_skateshop_type_charshop )
150 v3_sub( ref->transform.co, localplayer.rb.co, lookat );
151 else
152 vg_fatal_error( "Unknown store (%u)\n", shop->type );
153
154 q_axis_angle( localplayer.rb.q, (v3f){0.0f,1.0f,0.0f},
155 atan2f(lookat[0],lookat[2]) );
156
157 v3_copy( ref->transform.co, world_static.focus_cam.pos );
158 world_static.focus_cam.fov = ref->fov;
159
160 /* input */
161 if( shop->type == k_skateshop_type_boardshop ){
162 if( !vg_loader_availible() ) return;
163
164 u16 cache_id = skateshop_selected_cache_id();
165 global_skateshop.helper_pick->greyed = !cache_id;
166
167 /*
168 * Controls
169 * ----------------------
170 */
171 u32 opage = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
172
173 if( button_down( k_srbind_mleft ) ){
174 if( global_skateshop.selected_board_id > 0 ){
175 global_skateshop.selected_board_id --;
176 }
177 }
178
179 if( button_down( k_srbind_mright ) ){
180 if( global_skateshop.selected_board_id+1 <
181 addon_count(k_addon_type_board) )
182 {
183 global_skateshop.selected_board_id ++;
184 }
185 }
186
187 u32 npage = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
188
189 if( opage != npage ){
190 skateshop_update_viewpage();
191 //skateshop_op_processview();
192 }
193 else if( cache_id && button_down( k_srbind_maccept )){
194 vg_info( "chose board from skateshop (%u)\n",
195 global_skateshop.selected_board_id );
196
197 addon_cache_unwatch( k_addon_type_board, localplayer.board_view_slot );
198 addon_cache_watch( k_addon_type_board, cache_id );
199 localplayer.board_view_slot = cache_id;
200 network_send_item( k_netmsg_playeritem_board );
201
202 world_entity_unfocus();
203 gui_helper_clear();
204 skaterift_autosave(1);
205 return;
206 }
207 }
208 else if( shop->type == k_skateshop_type_charshop ){
209 if( !vg_loader_availible() ) return;
210
211 int changed = 0;
212
213 if( button_down( k_srbind_mleft ) ){
214 if( global_skateshop.selected_player_id > 0 ){
215 global_skateshop.selected_player_id --;
216 }
217 else{
218 global_skateshop.selected_player_id =
219 addon_count(k_addon_type_player) -1;
220 }
221
222 changed = 1;
223 }
224
225 if( button_down( k_srbind_mright ) ){
226 if( global_skateshop.selected_player_id+1 <
227 addon_count(k_addon_type_player) ){
228 global_skateshop.selected_player_id ++;
229 }
230 else{
231 global_skateshop.selected_player_id = 0;
232 }
233
234 changed = 1;
235 }
236
237 if( changed ){
238 player__use_model( global_skateshop.selected_player_id );
239 //skateshop_op_processview();
240 }
241
242 if( button_down( k_srbind_maccept ) ){
243 network_send_item( k_netmsg_playeritem_player );
244 world_entity_unfocus();
245 gui_helper_clear();
246 }
247 }
248 else if( shop->type == k_skateshop_type_worldshop ){
249 int browseable = 0,
250 loadable = 0;
251
252 if( addon_count(k_addon_type_world) && vg_loader_availible() )
253 browseable = 1;
254
255 if( vg_loader_availible() && global_skateshop.selected_world_id > 0 )
256 loadable = 1;
257
258 global_skateshop.helper_browse->greyed = !browseable;
259 global_skateshop.helper_pick->greyed = !loadable;
260
261 int change = 0;
262
263 if( browseable ){
264 if( button_down( k_srbind_mleft ) ){
265 if( global_skateshop.selected_world_id > 0 ){
266 global_skateshop.selected_world_id --;
267 change = 1;
268 }
269 }
270
271 if( button_down( k_srbind_mright ) ){
272 if( global_skateshop.selected_world_id+1 <
273 addon_count(k_addon_type_world) )
274 {
275 global_skateshop.selected_world_id ++;
276 change = 1;
277 }
278 }
279 }
280
281 #if 0
282 if( change && pointcloud_idle() ){
283 pointcloud_animate( k_pointcloud_anim_hiding );
284 }
285
286 if( vg_loader_availible() ){
287 addon_reg *reg = get_addon_from_index( k_addon_type_world,
288 global_skateshop.selected_world_id );
289
290 /* automatically load in clouds */
291 if( loadable && button_down( k_srbind_maccept ) ){
292 vg_info( "Select rift (%u)\n",
293 global_skateshop.selected_world_id );
294 skaterift_change_world_start( reg );
295 return;
296 }
297 else{
298 if( pointcloud.anim == k_pointcloud_anim_idle_closed ){
299 if( global_skateshop.pointcloud_world_id !=
300 global_skateshop.selected_world_id )
301 {
302 global_skateshop.pointcloud_world_id =
303 global_skateshop.selected_world_id;
304 skateshop_load_world_preview( reg );
305 }
306 else{
307 pointcloud_animate( k_pointcloud_anim_opening );
308 }
309 }
310 else if( pointcloud.anim == k_pointcloud_anim_idle_open ){
311 if( global_skateshop.pointcloud_world_id !=
312 global_skateshop.selected_world_id )
313 {
314 pointcloud_animate( k_pointcloud_anim_hiding );
315 }
316 }
317 }
318 }
319 #endif
320 }
321 else{
322 vg_fatal_error( "Unknown store (%u)\n", shop->type );
323 }
324
325 if( button_down( k_srbind_mback ) ){
326 if( shop->type == k_skateshop_type_charshop )
327 network_send_item( k_netmsg_playeritem_player );
328
329 world_entity_unfocus();
330 gui_helper_clear();
331 return;
332 }
333 }
334
335 static void skateshop_render_boardshop( ent_skateshop *shop ){
336 world_instance *world = world_current_instance();
337 u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
338
339 ent_marker *mark_rack = mdl_arritm( &world->ent_marker,
340 mdl_entity_id_id(shop->boards.id_rack)),
341 *mark_display = mdl_arritm( &world->ent_marker,
342 mdl_entity_id_id(shop->boards.id_display));
343
344 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
345 struct addon_cache *cache = &addon_system.cache[k_addon_type_board];
346
347 /* Render loaded boards in the view slots */
348 for( u32 i=0; i<slot_count; i++ ){
349 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
350 float selected = 0.0f;
351
352 if( !slot->cache_id )
353 goto fade_out;
354
355 addon_cache_entry *entry = vg_pool_item( &cache->pool, slot->cache_id );
356
357 if( entry->state != k_addon_cache_state_loaded )
358 goto fade_out;
359
360 struct player_board *board =
361 addon_cache_item( k_addon_type_board, slot->cache_id );
362
363 mdl_transform xform;
364 transform_identity( &xform );
365
366 xform.co[0] = -((float)i - ((float)slot_count)*0.5f)*0.45f;
367 mdl_transform_mul( &mark_rack->transform, &xform, &xform );
368
369
370 if( entry->reg_index == global_skateshop.selected_board_id ){
371 selected = 1.0f;
372 }
373
374 float t = slot->view_blend;
375 v3_lerp( xform.co, mark_display->transform.co, t, xform.co );
376 q_nlerp( xform.q, mark_display->transform.q, t, xform.q );
377 v3_lerp( xform.s, mark_display->transform.s, t, xform.s );
378
379 struct player_board_pose pose = {0};
380 m4x3f mmdl;
381 mdl_transform_m4x3( &xform, mmdl );
382 render_board( &skaterift.cam, world, board, mmdl,
383 &pose, k_board_shader_entity );
384
385 fade_out:;
386 float rate = 5.0f*vg.time_delta;
387 slot->view_blend = vg_lerpf( slot->view_blend, selected, rate );
388 }
389
390 ent_marker *mark_info = mdl_arritm( &world->ent_marker,
391 mdl_entity_id_id(shop->boards.id_info));
392 m4x3f mtext, mrack;
393 mdl_transform_m4x3( &mark_info->transform, mtext );
394 mdl_transform_m4x3( &mark_rack->transform, mrack );
395
396 #if 0
397 const char *text_title = "Fish - Title";
398 const char *text_author = "by Shaniqua";
399 #endif
400
401 m4x3f mlocal, mmdl;
402 m4x3_identity( mlocal );
403
404 float scale = 0.2f,
405 thickness = 0.03f;
406
407 font3d_bind( &gui.font, k_font_shader_default, 0, world, &skaterift.cam );
408 shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
409
410 /* Selection counter
411 * ------------------------------------------------------------------ */
412 m3x3_zero( mlocal );
413 v3_zero( mlocal[3] );
414 mlocal[0][0] = -scale*2.0f;
415 mlocal[1][2] = -scale*2.0f;
416 mlocal[2][1] = -thickness;
417 mlocal[3][2] = -0.7f;
418 m4x3_mul( mrack, mlocal, mmdl );
419
420 if( addon_count(k_addon_type_board) ){
421 char buf[16];
422 int i=0;
423 i+=highscore_intl( buf+i, global_skateshop.selected_board_id+1, 3 );
424 buf[i++] = '/';
425 i+=highscore_intl( buf+i, addon_count(k_addon_type_board), 3 );
426 buf[i++] = '\0';
427
428 font3d_simple_draw( 0, buf, &skaterift.cam, mmdl );
429 }
430 else{
431 font3d_simple_draw( 0, "Nothing installed", &skaterift.cam, mmdl );
432 }
433
434 u16 cache_id = skateshop_selected_cache_id();
435 struct addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
436 addon_reg *reg = NULL;
437
438 if( entry ) reg = entry->reg_ptr;
439
440 if( !reg ){
441 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
442 global_skateshop.render.item_title = "";
443 global_skateshop.render.item_desc = "";
444 return;
445 }
446
447 if( global_skateshop.render.reg_id != global_skateshop.selected_board_id ){
448 global_skateshop.render.item_title = "";
449 global_skateshop.render.item_desc = "";
450 vg_msg msg;
451 vg_msg_init( &msg, reg->metadata, reg->metadata_len );
452
453 if( vg_msg_seekframe( &msg, "workshop" ) ){
454 const char *title = vg_msg_getkvstr( &msg, "title" );
455 if( title ) global_skateshop.render.item_title = title;
456
457 const char *dsc = vg_msg_getkvstr( &msg, "author" );
458 if( dsc ) global_skateshop.render.item_desc = dsc;
459 vg_msg_skip_frame( &msg );
460 }
461
462 global_skateshop.render.reg_id = global_skateshop.selected_board_id;
463 }
464
465 /* Skin title
466 * ----------------------------------------------------------------- */
467 m3x3_zero( mlocal );
468 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
469 mlocal[3][0] = -font3d_string_width( 0, global_skateshop.render.item_title );
470 mlocal[3][0] *= scale*0.5f;
471 mlocal[3][1] = 0.1f;
472 mlocal[3][2] = 0.0f;
473 m4x3_mul( mtext, mlocal, mmdl );
474 font3d_simple_draw( 0, global_skateshop.render.item_title,
475 &skaterift.cam, mmdl );
476
477 /* Author name
478 * ----------------------------------------------------------------- */
479 scale *= 0.4f;
480 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
481 mlocal[3][0] = -font3d_string_width( 0, global_skateshop.render.item_desc );
482 mlocal[3][0] *= scale*0.5f;
483 mlocal[3][1] = 0.0f;
484 mlocal[3][2] = 0.0f;
485 m4x3_mul( mtext, mlocal, mmdl );
486 font3d_simple_draw( 0, global_skateshop.render.item_desc,
487 &skaterift.cam, mmdl );
488
489 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
490 }
491
492 static void skateshop_render_charshop( ent_skateshop *shop ){
493 }
494
495 static void skateshop_render_worldshop( ent_skateshop *shop ){
496 world_instance *world = world_current_instance();
497
498 ent_marker *mark_display = mdl_arritm( &world->ent_marker,
499 mdl_entity_id_id(shop->worlds.id_display)),
500 *mark_info = mdl_arritm( &world->ent_marker,
501 mdl_entity_id_id(shop->boards.id_info));
502
503 if( global_skateshop.render.world_reg != global_skateshop.selected_world_id){
504 global_skateshop.render.world_title = "";
505
506 addon_reg *reg = get_addon_from_index( k_addon_type_world,
507 global_skateshop.selected_world_id );
508 vg_msg msg;
509 vg_msg_init( &msg, reg->metadata, reg->metadata_len );
510 global_skateshop.render.world_loc = vg_msg_getkvstr( &msg, "location" );
511 global_skateshop.render.world_reg = global_skateshop.selected_world_id;
512
513 if( vg_msg_seekframe( &msg, "workshop" ) ){
514 global_skateshop.render.world_title = vg_msg_getkvstr( &msg, "title");
515 vg_msg_skip_frame( &msg );
516 }
517 }
518
519 /* Text */
520 char buftext[128], bufsubtext[128];
521 vg_str info, subtext;
522 vg_strnull( &info, buftext, 128 );
523 vg_strnull( &subtext, bufsubtext, 128 );
524
525 if( addon_count(k_addon_type_world) ){
526 addon_reg *reg = get_addon_from_index( k_addon_type_world,
527 global_skateshop.selected_world_id );
528
529 info.i+=highscore_intl( info.buffer+info.i,
530 global_skateshop.selected_world_id+1, 3 );
531 info.buffer[info.i++] = '/';
532 info.i+=highscore_intl( info.buffer+info.i,
533 addon_count(k_addon_type_world), 3 );
534 info.buffer[info.i++] = ' ';
535 info.buffer[info.i] = '\0';
536
537 vg_strcat( &info, global_skateshop.render.world_title );
538 if( !vg_loader_availible() ){
539 vg_strcat( &subtext, "Loading..." );
540 }
541 else{
542 addon_reg *reg = get_addon_from_index( k_addon_type_world,
543 global_skateshop.selected_world_id );
544
545 if( reg->alias.workshop_id )
546 vg_strcat( &subtext, "(Workshop) " );
547
548 vg_strcat( &subtext, global_skateshop.render.world_loc );
549 }
550 }
551 else{
552 vg_strcat( &info, "No worlds installed" );
553 }
554
555
556 m4x3f mtext,mlocal,mtextmdl;
557 mdl_transform_m4x3( &mark_info->transform, mtext );
558
559 font3d_bind( &gui.font, k_font_shader_default, 0, NULL, &skaterift.cam );
560 shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
561
562 float scale = 0.2f, thickness = 0.015f, scale1 = 0.08f;
563 m3x3_zero( mlocal );
564 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
565 mlocal[3][0] = -font3d_string_width( 0, buftext );
566 mlocal[3][0] *= scale*0.5f;
567 mlocal[3][1] = 0.1f;
568 mlocal[3][2] = 0.0f;
569 m4x3_mul( mtext, mlocal, mtextmdl );
570 font3d_simple_draw( 0, buftext, &skaterift.cam, mtextmdl );
571
572 m3x3_setdiagonalv3( mlocal, (v3f){ scale1, scale1, thickness } );
573 mlocal[3][0] = -font3d_string_width( 0, bufsubtext );
574 mlocal[3][0] *= scale1*0.5f;
575 mlocal[3][1] = -scale1*0.3f;
576 m4x3_mul( mtext, mlocal, mtextmdl );
577 font3d_simple_draw( 0, bufsubtext, &skaterift.cam, mtextmdl );
578
579 #if 0
580 /* pointcloud */
581 m4x3f mmdl;
582 mdl_transform_m4x3( &mark_display->transform, mmdl );
583 m4x3_rotate_y( mmdl, vg.time * 0.2 );
584
585 glEnable(GL_BLEND);
586 glBlendFunc(GL_ONE, GL_ONE);
587 glDisable(GL_DEPTH_TEST);
588 pointcloud_render( world, &skaterift.cam, mmdl );
589 glDisable(GL_BLEND);
590 glEnable(GL_DEPTH_TEST);
591 #endif
592 }
593
594 /*
595 * World: render event
596 */
597 static void skateshop_render( ent_skateshop *shop ){
598 if( shop->type == k_skateshop_type_boardshop )
599 skateshop_render_boardshop( shop );
600 else if( shop->type == k_skateshop_type_charshop )
601 skateshop_render_charshop( shop );
602 else if( shop->type == k_skateshop_type_worldshop )
603 skateshop_render_worldshop( shop );
604 else
605 vg_fatal_error( "Unknown store (%u)\n", shop->type );
606 }
607
608 static void ent_skateshop_helpers_pickable( const char *acceptance ){
609 vg_str text;
610
611 if( gui_new_helper( input_button_list[k_srbind_mback], &text ))
612 vg_strcat( &text, "exit" );
613
614 if( (global_skateshop.helper_pick = gui_new_helper(
615 input_button_list[k_srbind_maccept], &text))){
616 vg_strcat( &text, acceptance );
617 }
618
619 if( (global_skateshop.helper_browse = gui_new_helper(
620 input_axis_list[k_sraxis_mbrowse_h], &text ))){
621 vg_strcat( &text, "browse" );
622 }
623 }
624
625 /*
626 * Entity logic: entrance event
627 */
628 static void ent_skateshop_call( world_instance *world, ent_call *call ){
629 u32 index = mdl_entity_id_id( call->id );
630 ent_skateshop *shop = mdl_arritm( &world->ent_skateshop, index );
631 vg_info( "skateshop_call\n" );
632
633 if( skaterift.activity != k_skaterift_default ) return;
634 if( !vg_loader_availible() ) return;
635
636 if( call->function == k_ent_function_trigger ){
637 if( localplayer.subsystem != k_player_subsystem_walk ) return;
638
639 vg_info( "Entering skateshop\n" );
640
641 world_entity_focus( call->id );
642 gui_helper_clear();
643
644 if( shop->type == k_skateshop_type_boardshop ){
645 skateshop_update_viewpage();
646 skateshop_op_board_scan();
647 ent_skateshop_helpers_pickable( "pick" );
648 }
649 else if( shop->type == k_skateshop_type_charshop ){
650 ent_skateshop_helpers_pickable( "pick" );
651 }
652 else if( shop->type == k_skateshop_type_worldshop ){
653 ent_skateshop_helpers_pickable( "open rift" );
654 skateshop_op_world_scan();
655 }
656 }
657 }
658
659 #endif /* ENT_SKATESHOP_C */