allow replays to pass through rifts
[carveJwlIkooP6JGAAIwe30JlM.git] / addon.c
1 #ifndef ADDON_C
2 #define ADDON_C
3
4 #include "addon.h"
5 #include "addon_types.h"
6 #include "vg/vg_msg.h"
7 #include "steam.h"
8 #include "workshop.h"
9
10 static u32 addon_count( enum addon_type type, u32 ignoreflags ){
11 if( ignoreflags ){
12 u32 typecount = 0, count = 0;
13 for( u32 i=0; typecount<addon_count( type, 0 ); i++ ){
14 addon_reg *reg = &addon_system.registry[i];
15 if( reg->alias.type == type ){
16 typecount ++;
17
18 if( reg->flags & ignoreflags )
19 continue;
20
21 count ++;
22 }
23 }
24
25 return count;
26 }
27 else
28 return addon_system.registry_type_counts[ type ];
29 }
30
31
32 /* these kind of suck, oh well. */
33 static addon_reg *get_addon_from_index( enum addon_type type, u32 index,
34 u32 ignoreflags ){
35 u32 typecount = 0, count = 0;
36 for( u32 i=0; typecount<addon_count(type,0); i++ ){
37 addon_reg *reg = &addon_system.registry[i];
38 if( reg->alias.type == type ){
39 typecount ++;
40
41 if( reg->flags & ignoreflags )
42 continue;
43
44 if( index == count )
45 return reg;
46
47 count ++;
48 }
49 }
50
51 return NULL;
52 }
53
54 static u32 get_index_from_addon( enum addon_type type, addon_reg *a ){
55 u32 count = 0;
56 for( u32 i=0; count<addon_system.registry_type_counts[type]; i++ ){
57 addon_reg *reg = &addon_system.registry[i];
58 if( reg->alias.type == type ){
59 if( reg == a )
60 return count;
61
62 count ++;
63 }
64 }
65
66 return 0xffffffff;
67 }
68
69 static u32 addon_match( addon_alias *alias ){
70 if( alias->type == k_addon_type_none ) return 0xffffffff;
71
72 u32 foldername_djb2 = 0;
73 if( !alias->workshop_id )
74 foldername_djb2 = vg_strdjb2( alias->foldername );
75
76 u32 count = 0;
77 for( u32 i=0; count<addon_system.registry_type_counts[alias->type]; i++ ){
78 addon_reg *reg = &addon_system.registry[i];
79 if( reg->alias.type == alias->type ){
80
81 if( alias->workshop_id ){
82 if( alias->workshop_id == reg->alias.workshop_id )
83 return count;
84 }
85 else{
86 if( reg->foldername_hash == foldername_djb2 ){
87 if( !strcmp( reg->alias.foldername, alias->foldername ) ){
88 return count;
89 }
90 }
91 }
92
93 count ++;
94 }
95 }
96
97 return 0xffffffff;
98 }
99
100 /*
101 * Create a string version of addon alias in buf
102 */
103 static void addon_alias_uid( addon_alias *alias, char buf[ADDON_UID_MAX] ){
104 if( alias->workshop_id ){
105 snprintf( buf, 128, "sr%03d-steam-"PRINTF_U64,
106 alias->type, alias->workshop_id );
107 }
108 else {
109 snprintf( buf, 128, "sr%03d-local-%s",
110 alias->type, alias->foldername );
111 }
112 }
113
114 /*
115 * equality check
116 */
117 static int addon_alias_eq( addon_alias *a, addon_alias *b ){
118 if( a->type == b->type ){
119 if( a->workshop_id == b->workshop_id ){
120 if( a->workshop_id )
121 return 1;
122 else
123 return !strcmp( a->foldername, b->foldername );
124 }
125 else
126 return 0;
127 }
128 else return 0;
129 }
130
131 /*
132 * make alias represent NULL.
133 */
134 static void invalidate_addon_alias( addon_alias *alias ){
135 alias->type = k_addon_type_none;
136 alias->workshop_id = 0;
137 alias->foldername[0] = '\0';
138 }
139
140 /*
141 * parse uid to alias. returns 1 if successful
142 */
143 static int addon_uid_to_alias( const char *uid, addon_alias *alias ){
144 /* 1
145 * 01234567890123
146 * sr&&&-@@@@@-#*
147 * | | |
148 * type | id
149 * |
150 * location
151 */
152 if( strlen(uid) < 13 ){
153 invalidate_addon_alias( alias );
154 return 0;
155 }
156 if( !((uid[0] == 's') && (uid[1] == 'r')) ){
157 invalidate_addon_alias( alias );
158 return 0;
159 }
160
161 char type[4];
162 memcpy( type, uid+2, 3 );
163 type[3] = '\0';
164 alias->type = atoi(type);
165
166 char location[6];
167 memcpy( location, uid+6, 5 );
168 location[5] = '\0';
169
170 if( !strcmp(location,"steam") )
171 alias->workshop_id = atoll( uid+12 );
172 else if( !strcmp(location,"local") ){
173 alias->workshop_id = 0;
174 vg_strncpy( uid+12, alias->foldername, 64, k_strncpy_always_add_null );
175 }
176 else{
177 invalidate_addon_alias( alias );
178 return 0;
179 }
180
181 return 1;
182 }
183
184 static void addon_system_init( void ){
185 u32 reg_size = sizeof(addon_reg)*ADDON_MOUNTED_MAX;
186 addon_system.registry = vg_linear_alloc( vg_mem.rtmemory, reg_size );
187
188 for( u32 type=0; type<k_addon_type_max; type++ ){
189 struct addon_type_info *inf = &addon_type_infos[type];
190 struct addon_cache *cache = &addon_system.cache[type];
191
192 if( inf->cache_count ){
193 /* create the allocations pool */
194 u32 alloc_size = sizeof(struct addon_cache_entry)*inf->cache_count;
195 cache->allocs = vg_linear_alloc( vg_mem.rtmemory, alloc_size );
196 memset( cache->allocs, 0, alloc_size );
197
198 cache->pool.buffer = cache->allocs;
199 cache->pool.count = inf->cache_count;
200 cache->pool.stride = sizeof( struct addon_cache_entry );
201 cache->pool.offset = offsetof( struct addon_cache_entry, poolnode );
202 vg_pool_init( &cache->pool );
203
204 /* create the real memory */
205 u32 cache_size = inf->cache_stride*inf->cache_count;
206 cache->items = vg_linear_alloc( vg_mem.rtmemory, cache_size );
207 cache->stride = inf->cache_stride;
208 memset( cache->items, 0, cache_size );
209
210 for( i32 j=0; j<inf->cache_count; j++ ){
211 struct addon_cache_entry *alloc = &cache->allocs[j];
212 alloc->reg_ptr = NULL;
213 alloc->reg_index = 0xffffffff;
214 }
215 }
216 }
217 }
218
219 /*
220 * Scanning routines
221 * -----------------------------------------------------------------------------
222 */
223
224 /*
225 * Reciever for scan completion. copies the registry counts back into main fred
226 */
227 static void async_addon_reg_update( void *data, u32 size )
228 {
229 vg_info( "Registry update notify\n" );
230
231 for( u32 i=0; i<k_addon_type_max; i++ ){
232 addon_system.registry_type_counts[i] = 0;
233 }
234
235 for( u32 i=0; i<addon_system.registry_count; i++ ){
236 enum addon_type type = addon_system.registry[i].alias.type;
237 addon_system.registry_type_counts[ type ] ++;
238 }
239 }
240
241 static void addon_set_foldername( addon_reg *reg, const char name[64] ){
242 vg_strncpy( name, reg->alias.foldername, 64, k_strncpy_always_add_null );
243 reg->foldername_hash = vg_strdjb2( reg->alias.foldername );
244 }
245
246 /*
247 * Create a new registry
248 */
249 static addon_reg *addon_alloc_reg( PublishedFileId_t workshop_id,
250 enum addon_type type ){
251 if( addon_system.registry_count == ADDON_MOUNTED_MAX ){
252 vg_error( "You have too many addons installed!\n" );
253 return NULL;
254 }
255
256 addon_reg *reg = &addon_system.registry[ addon_system.registry_count ];
257 reg->flags = 0;
258 reg->metadata_len = 0;
259 reg->cache_id = 0;
260 reg->state = k_addon_state_indexed;
261 reg->alias.workshop_id = workshop_id;
262 reg->alias.foldername[0] = '\0';
263 reg->alias.type = type;
264
265 if( workshop_id ){
266 char foldername[64];
267 snprintf( foldername, 64, PRINTF_U64, workshop_id );
268 addon_set_foldername( reg, foldername );
269 }
270 return reg;
271 }
272
273 /*
274 * If the addon.inf exists int the folder, load into the reg
275 */
276 static int addon_try_load_metadata( addon_reg *reg, vg_str folder_path ){
277 vg_str meta_path = folder_path;
278 vg_strcat( &meta_path, "/addon.inf" );
279 if( !vg_strgood( &meta_path ) ){
280 vg_error( "The metadata path is too long\n" );
281 return 0;
282 }
283
284 FILE *fp = fopen( meta_path.buffer, "rb" );
285 if( !fp ){
286 vg_error( "Could not open the '%s'\n", meta_path.buffer );
287 return 0;
288 }
289
290 reg->metadata_len = fread( reg->metadata, 1, 512, fp );
291 if( reg->metadata_len != 512 ){
292 if( !feof(fp) ){
293 fclose(fp);
294 vg_error( "unknown error codition" );
295 reg->metadata_len = 0;
296 return 0;
297 }
298 }
299 fclose(fp);
300 return 1;
301 }
302
303 static void addon_print_info( addon_reg *reg ){
304 vg_info( "addon_reg #%u{\n", addon_system.registry_count );
305 vg_info( " type: %d\n", reg->alias.type );
306 vg_info( " workshop_id: " PRINTF_U64 "\n", reg->alias.workshop_id );
307 vg_info( " folder: [%u]%s\n", reg->foldername_hash, reg->alias.foldername );
308 vg_info( " metadata_len: %u\n", reg->metadata_len );
309 vg_info( " cache_id: %hu\n", reg->cache_id );
310 vg_info( "}\n" );
311 }
312
313 static void addon_mount_finish( addon_reg *reg ){
314 #if 0
315 addon_print_info( reg );
316 #endif
317 addon_system.registry_count ++;
318 }
319
320 /*
321 * Mount a fully packaged addon, one that certainly has a addon.inf
322 */
323 static addon_reg *addon_mount_workshop_folder( PublishedFileId_t workshop_id,
324 vg_str folder_path )
325 {
326 addon_reg *reg = addon_alloc_reg( workshop_id, k_addon_type_none );
327 if( !reg ) return NULL;
328
329 if( !addon_try_load_metadata( reg, folder_path ) ){
330 return NULL;
331 }
332
333 enum addon_type type = k_addon_type_none;
334 vg_msg msg;
335 vg_msg_init( &msg, reg->metadata, reg->metadata_len );
336
337 if( vg_msg_seekframe( &msg, "workshop" )){
338 type = vg_msg_getkvu32( &msg, "type", 0 );
339 }
340
341 if( type == k_addon_type_none ){
342 vg_error( "Cannot determine addon type\n" );
343 return NULL;
344 }
345
346 reg->alias.type = type;
347 addon_mount_finish( reg );
348 return reg;
349 }
350
351 /*
352 * Mount a local folder. may or may not have addon.inf
353 */
354 static addon_reg *addon_mount_local_addon( const char *folder,
355 enum addon_type type,
356 const char *content_ext )
357 {
358 char folder_path_buf[4096];
359 vg_str folder_path;
360 vg_strnull( &folder_path, folder_path_buf, 4096 );
361 vg_strcat( &folder_path, folder );
362
363 const char *folder_name = vg_strch( &folder_path, '/' )+1;
364 u32 folder_hash = vg_strdjb2(folder_name);
365 for( u32 i=0; i<addon_system.registry_count; i++ ){
366 addon_reg *reg = &addon_system.registry[i];
367
368 if( (reg->alias.type == type) && (reg->foldername_hash == folder_hash) ){
369 if( !strcmp( reg->alias.foldername, folder_name ) ){
370 reg->state = k_addon_state_indexed;
371 return reg;
372 }
373 }
374 }
375
376 addon_reg *reg = addon_alloc_reg( 0, type );
377 if( !reg ) return NULL;
378 addon_set_foldername( reg, folder_name );
379 addon_try_load_metadata( reg, folder_path );
380
381 if( reg->metadata_len == 0 ){
382 /* create our own content commands */
383 vg_msg msg;
384 vg_msg_init( &msg, reg->metadata, sizeof(reg->metadata) );
385
386 u32 content_count = 0;
387
388 vg_strcat( &folder_path, "" );
389 vg_warn( "Creating own metadata for: %s\n", folder_path.buffer );
390
391 vg_dir subdir;
392 if( !vg_dir_open(&subdir, folder_path.buffer) ){
393 vg_error( "Failed to open '%s'\n", folder_path.buffer );
394 return NULL;
395 }
396
397 while( vg_dir_next_entry(&subdir) ){
398 if( vg_dir_entry_type(&subdir) == k_vg_entry_type_file ){
399 const char *fname = vg_dir_entry_name(&subdir);
400 vg_str file = folder_path;
401 vg_strcat( &file, "/" );
402 vg_strcat( &file, fname );
403 if( !vg_strgood( &file ) ) continue;
404
405 char *ext = vg_strch( &file, '.' );
406 if( !ext ) continue;
407 if( strcmp(ext,content_ext) ) continue;
408
409 vg_msg_wkvstr( &msg, "content", fname );
410 content_count ++;
411 }
412 }
413 vg_dir_close(&subdir);
414
415 if( !content_count ) return NULL;
416 if( msg.error == k_vg_msg_error_OK )
417 reg->metadata_len = msg.cur.co;
418 else{
419 vg_error( "Error creating metadata: %d\n", msg.error );
420 return NULL;
421 }
422 }
423
424 addon_mount_finish( reg );
425 return reg;
426 }
427
428 /*
429 * Check all subscribed items
430 */
431 static void addon_mount_workshop_items(void){
432 if( skaterift.demo_mode ){
433 vg_info( "Won't load workshop items in demo mode\n" );
434 return;
435 }
436 if( !steam_ready ) return;
437
438 /*
439 * Steam workshop scan
440 */
441 vg_info( "Mounting steam workshop subscriptions\n" );
442 PublishedFileId_t workshop_ids[ ADDON_MOUNTED_MAX ];
443 u32 workshop_count = ADDON_MOUNTED_MAX;
444
445 vg_async_item *call = vg_async_alloc(
446 sizeof(struct async_workshop_installed_files_info));
447 struct async_workshop_installed_files_info *info = call->payload;
448 info->buffer = workshop_ids;
449 info->len = &workshop_count;
450 vg_async_dispatch( call, async_workshop_get_installed_files );
451 vg_async_stall();
452
453 for( u32 j=0; j<workshop_count; j++ ){
454 /* check for existance in both our caches
455 * ----------------------------------------------------------*/
456 PublishedFileId_t id = workshop_ids[j];
457 for( u32 i=0; i<addon_system.registry_count; i++ ){
458 addon_reg *reg = &addon_system.registry[i];
459
460 if( reg->alias.workshop_id == id ){
461 reg->state = k_addon_state_indexed;
462 goto next_file_workshop;
463 }
464 }
465
466 vg_async_item *call1 =
467 vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
468
469 char path[ 4096 ];
470
471 struct async_workshop_filepath_info *info = call1->payload;
472 info->buf = path;
473 info->id = id;
474 info->len = vg_list_size(path);
475 vg_async_dispatch( call1, async_workshop_get_filepath );
476 vg_async_stall(); /* too bad! */
477
478 vg_str folder = {.buffer = path, .i=strlen(path), .len=4096};
479 addon_mount_workshop_folder( id, folder );
480 next_file_workshop:;
481 }
482 }
483
484 /*
485 * Scan a local content folder for addons. It must find at least one file with
486 * the specified content_ext to be considered.
487 */
488 static void addon_mount_content_folder( enum addon_type type,
489 const char *base_folder,
490 const char *content_ext )
491 {
492 vg_info( "Mounting addons(type:%d) matching skaterift/%s/*/*%s\n",
493 type, base_folder, content_ext );
494
495 char path_buf[4096];
496 vg_str path;
497 vg_strnull( &path, path_buf, 4096 );
498 vg_strcat( &path, base_folder );
499
500 vg_dir dir;
501 if( !vg_dir_open(&dir,path.buffer) ){
502 vg_error( "vg_dir_open('%s') failed\n", path.buffer );
503 return;
504 }
505
506 vg_strcat(&path,"/");
507
508 while( vg_dir_next_entry(&dir) ){
509 if( vg_dir_entry_type(&dir) == k_vg_entry_type_dir ){
510 const char *d_name = vg_dir_entry_name(&dir);
511
512 vg_str folder = path;
513 if( strlen( d_name ) > ADDON_FOLDERNAME_MAX ){
514 vg_warn( "folder too long: %s\n", d_name );
515 continue;
516 }
517
518 vg_strcat( &folder, d_name );
519 if( !vg_strgood( &folder ) ) continue;
520
521 addon_mount_local_addon( folder.buffer, type, content_ext );
522 }
523 }
524 vg_dir_close(&dir);
525 }
526
527 /*
528 * write the full path of the addon's folder into the vg_str
529 */
530 static int addon_get_content_folder( addon_reg *reg, vg_str *folder, int async){
531 if( reg->alias.workshop_id ){
532 struct async_workshop_filepath_info *info = NULL;
533 vg_async_item *call = NULL;
534
535 if( async ){
536 call = vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
537 info = call->payload;
538 }
539 else
540 info = alloca( sizeof(struct async_workshop_filepath_info) );
541
542 info->buf = folder->buffer;
543 info->id = reg->alias.workshop_id;
544 info->len = folder->len;
545
546 if( async ){
547 vg_async_dispatch( call, async_workshop_get_filepath );
548 vg_async_stall(); /* too bad! */
549 }
550 else {
551 async_workshop_get_filepath( info, 0 );
552 }
553
554 if( info->buf[0] == '\0' ){
555 vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64 ")\n",
556 reg->alias.workshop_id );
557 return 0;
558 }
559 folder->i = strlen( folder->buffer );
560 return 1;
561 }
562 else{
563 folder->i = 0;
564
565 const char *local_folder =
566 addon_type_infos[reg->alias.type].local_content_folder;
567
568 if( !local_folder ) return 0;
569 vg_strcat( folder, local_folder );
570 vg_strcat( folder, reg->alias.foldername );
571 return 1;
572 }
573 }
574
575 /*
576 * Return existing cache id if reg_index points to a registry with its cache
577 * already set.
578 */
579 static u16 addon_cache_fetch( enum addon_type type, u32 reg_index ){
580 addon_reg *reg = NULL;
581
582 if( reg_index < addon_count( type, 0 ) ){
583 reg = get_addon_from_index( type, reg_index, 0 );
584 if( reg->cache_id )
585 return reg->cache_id;
586 }
587
588 return 0;
589 }
590
591 /*
592 * Allocate a new cache item from the pool
593 */
594 static u16 addon_cache_alloc( enum addon_type type, u32 reg_index ){
595 struct addon_cache *cache = &addon_system.cache[ type ];
596
597 u16 new_id = vg_pool_lru( &cache->pool );
598 struct addon_cache_entry *new_entry = vg_pool_item( &cache->pool, new_id );
599
600 addon_reg *reg = NULL;
601 if( reg_index < addon_count( type, 0 ) )
602 reg = get_addon_from_index( type, reg_index, 0 );
603
604 if( new_entry ){
605 if( new_entry->reg_ptr )
606 new_entry->reg_ptr->cache_id = 0;
607
608 if( reg )
609 reg->cache_id = new_id;
610
611 new_entry->reg_ptr = reg;
612 new_entry->reg_index = reg_index;
613 return new_id;
614 }
615 else{
616 vg_error( "cache full (type: %u)!\n", type );
617 return 0;
618 }
619 }
620
621 /*
622 * Get the real item data for cache id
623 */
624 static void *addon_cache_item( enum addon_type type, u16 id ){
625 if( !id ) return NULL;
626
627 struct addon_cache *cache = &addon_system.cache[type];
628 return cache->items + ((size_t)(id-1) * cache->stride);
629 }
630
631 /*
632 * Get the real item data for cache id ONLY if the item is completely loaded.
633 */
634 static void *addon_cache_item_if_loaded( enum addon_type type, u16 id ){
635 if( !id ) return NULL;
636
637 struct addon_cache *cache = &addon_system.cache[type];
638 struct addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
639
640 if( entry->state == k_addon_cache_state_loaded )
641 return addon_cache_item( type, id );
642 else return NULL;
643 }
644
645 /*
646 * Updates the item state from the main thread
647 */
648 static void async_addon_setstate( void *_entry, u32 _state ){
649 addon_cache_entry *entry = _entry;
650 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
651 entry->state = _state;
652 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
653 vg_success( " loaded (%s)\n", entry->reg_ptr->alias.foldername );
654 }
655
656 /*
657 * Handles the loading of an individual item
658 */
659 static int addon_cache_load_request( enum addon_type type, u16 id,
660 addon_reg *reg, vg_str folder ){
661
662 /* load content files
663 * --------------------------------- */
664 vg_str content_path = folder;
665
666 vg_msg msg;
667 vg_msg_init( &msg, reg->metadata, reg->metadata_len );
668
669 const char *kv_content = vg_msg_getkvstr( &msg, "content" );
670 if( kv_content ){
671 vg_strcat( &content_path, "/" );
672 vg_strcat( &content_path, kv_content );
673 }
674 else{
675 vg_error( " No content paths in metadata\n" );
676 return 0;
677 }
678
679 if( !vg_strgood( &content_path ) ) {
680 vg_error( " Metadata path too long\n" );
681 return 0;
682 }
683
684 if( type == k_addon_type_board ){
685 struct player_board *board = addon_cache_item( type, id );
686 player_board_load( board, content_path.buffer );
687 return 1;
688 }
689 else if( type == k_addon_type_player ){
690 struct player_model *model = addon_cache_item( type, id );
691 player_model_load( model, content_path.buffer );
692 return 1;
693 }
694 else {
695 return 0;
696 }
697
698 return 0;
699 }
700
701 static void addon_cache_free_item( enum addon_type type, u16 id ){
702 if( type == k_addon_type_board ){
703 struct player_board *board = addon_cache_item( type, id );
704 player_board_unload( board );
705 }
706 else if( type == k_addon_type_player ){
707 struct player_model *model = addon_cache_item( type, id );
708 player_model_unload( model );
709 }
710 }
711
712 /*
713 * Goes over cache item load requests and calls the above ^
714 */
715 static void addon_cache_load_loop(void){
716 vg_info( "Running load loop\n" );
717 char path_buf[4096];
718
719 for( u32 type=0; type<k_addon_type_max; type++ ){
720 struct addon_cache *cache = &addon_system.cache[type];
721
722 for( u32 id=1; id<=cache->pool.count; id++ ){
723 addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
724
725 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
726 if( entry->state == k_addon_cache_state_load_request ){
727 vg_info( "process cache load request (%u#%u, reg:%u)\n",
728 type, id, entry->reg_index );
729
730 if( entry->reg_index >= addon_count(type,0) ){
731 /* should maybe have a different value for this case */
732 entry->state = k_addon_cache_state_none;
733 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
734 continue;
735 }
736
737 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
738
739 /* continue with the request */
740 addon_reg *reg = get_addon_from_index( type, entry->reg_index, 0 );
741 entry->reg_ptr = reg;
742
743 vg_str folder;
744 vg_strnull( &folder, path_buf, 4096 );
745 if( addon_get_content_folder( reg, &folder, 1 ) ){
746 if( addon_cache_load_request( type, id, reg, folder ) ){
747 vg_async_call( async_addon_setstate,
748 entry, k_addon_cache_state_loaded );
749 continue;
750 }
751 }
752
753 vg_warn( "cache item did not load (%u#%u)\n", type, id );
754 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
755 entry->state = k_addon_cache_state_none;
756 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
757 }
758 else
759 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
760 }
761 }
762 }
763
764 /*
765 * Perform the cache interactions required to create a viewslot which will
766 * eventually be loaded by other parts of the system.
767 */
768 static u16 addon_cache_create_viewer( enum addon_type type, u16 reg_id ){
769 struct addon_cache *cache = &addon_system.cache[type];
770 vg_pool *pool = &cache->pool;
771
772 u16 cache_id = addon_cache_fetch( type, reg_id );
773 if( !cache_id ){
774 cache_id = addon_cache_alloc( type, reg_id );
775
776 if( cache_id ){
777 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
778 addon_cache_entry *entry = vg_pool_item( pool, cache_id );
779
780 if( entry->state == k_addon_cache_state_loaded ){
781 addon_cache_free_item( type, cache_id );
782 }
783
784 entry->state = k_addon_cache_state_load_request;
785 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
786 }
787 }
788
789 if( cache_id )
790 vg_pool_watch( pool, cache_id );
791
792 return cache_id;
793 }
794
795 static u16 addon_cache_create_viewer_from_uid( enum addon_type type,
796 char uid[ADDON_UID_MAX] ){
797 addon_alias q;
798 if( !addon_uid_to_alias( uid, &q ) ) return 0;
799 if( q.type != type ) return 0;
800
801 u32 reg_id = addon_match( &q );
802
803 if( reg_id == 0xffffffff ){
804 vg_warn( "We dont have the addon '%s' installed.\n", uid );
805 return 0;
806 }
807 else {
808 return addon_cache_create_viewer( type, reg_id );
809 }
810 }
811
812 static void addon_cache_watch( enum addon_type type, u16 cache_id ){
813 if( !cache_id ) return;
814
815 struct addon_cache *cache = &addon_system.cache[type];
816 vg_pool *pool = &cache->pool;
817 vg_pool_watch( pool, cache_id );
818 }
819
820 static void addon_cache_unwatch( enum addon_type type, u16 cache_id ){
821 if( !cache_id ) return;
822
823 struct addon_cache *cache = &addon_system.cache[type];
824 vg_pool *pool = &cache->pool;
825 vg_pool_unwatch( pool, cache_id );
826 }
827
828 #endif /* ADDON_C */