load in preview images to dynamic rt textures
[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 NULL;
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( !steam_ready ) return;
433 /*
434 * Steam workshop scan
435 */
436 vg_info( "Mounting steam workshop subscriptions\n" );
437 PublishedFileId_t workshop_ids[ ADDON_MOUNTED_MAX ];
438 u32 workshop_count = ADDON_MOUNTED_MAX;
439
440 vg_async_item *call = vg_async_alloc(
441 sizeof(struct async_workshop_installed_files_info));
442 struct async_workshop_installed_files_info *info = call->payload;
443 info->buffer = workshop_ids;
444 info->len = &workshop_count;
445 vg_async_dispatch( call, async_workshop_get_installed_files );
446 vg_async_stall();
447
448 for( u32 j=0; j<workshop_count; j++ ){
449 /* check for existance in both our caches
450 * ----------------------------------------------------------*/
451 PublishedFileId_t id = workshop_ids[j];
452 for( u32 i=0; i<addon_system.registry_count; i++ ){
453 addon_reg *reg = &addon_system.registry[i];
454
455 if( reg->alias.workshop_id == id ){
456 reg->state = k_addon_state_indexed;
457 goto next_file_workshop;
458 }
459 }
460
461 vg_async_item *call1 =
462 vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
463
464 char path[ 4096 ];
465
466 struct async_workshop_filepath_info *info = call1->payload;
467 info->buf = path;
468 info->id = id;
469 info->len = vg_list_size(path);
470 vg_async_dispatch( call1, async_workshop_get_filepath );
471 vg_async_stall(); /* too bad! */
472
473 vg_str folder = {.buffer = path, .i=strlen(path), .len=4096};
474 addon_mount_workshop_folder( id, folder );
475 next_file_workshop:;
476 }
477 }
478
479 /*
480 * Scan a local content folder for addons. It must find at least one file with
481 * the specified content_ext to be considered.
482 */
483 static void addon_mount_content_folder( enum addon_type type,
484 const char *base_folder,
485 const char *content_ext )
486 {
487 vg_info( "Mounting addons(type:%d) matching skaterift/%s/*/*%s\n",
488 type, base_folder, content_ext );
489
490 char path_buf[4096];
491 vg_str path;
492 vg_strnull( &path, path_buf, 4096 );
493 vg_strcat( &path, base_folder );
494
495 vg_dir dir;
496 if( !vg_dir_open(&dir,path.buffer) ){
497 vg_error( "vg_dir_open('%s') failed\n", path.buffer );
498 return;
499 }
500
501 vg_strcat(&path,"/");
502
503 while( vg_dir_next_entry(&dir) ){
504 if( vg_dir_entry_type(&dir) == k_vg_entry_type_dir ){
505 const char *d_name = vg_dir_entry_name(&dir);
506
507 vg_str folder = path;
508 if( strlen( d_name ) > ADDON_FOLDERNAME_MAX ){
509 vg_warn( "folder too long: %s\n", d_name );
510 continue;
511 }
512
513 vg_strcat( &folder, d_name );
514 if( !vg_strgood( &folder ) ) continue;
515
516 addon_mount_local_addon( folder.buffer, type, content_ext );
517 }
518 }
519 vg_dir_close(&dir);
520 }
521
522 /*
523 * write the full path of the addon's folder into the vg_str
524 */
525 static int addon_get_content_folder( addon_reg *reg, vg_str *folder, int async){
526 if( reg->alias.workshop_id ){
527 struct async_workshop_filepath_info *info = NULL;
528 vg_async_item *call = NULL;
529
530 if( async ){
531 call = vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
532 info = call->payload;
533 }
534 else
535 info = alloca( sizeof(struct async_workshop_filepath_info) );
536
537 info->buf = folder->buffer;
538 info->id = reg->alias.workshop_id;
539 info->len = folder->len;
540
541 if( async ){
542 vg_async_dispatch( call, async_workshop_get_filepath );
543 vg_async_stall(); /* too bad! */
544 }
545 else {
546 async_workshop_get_filepath( info, 0 );
547 }
548
549 if( info->buf[0] == '\0' ){
550 vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64 ")\n",
551 reg->alias.workshop_id );
552 return 0;
553 }
554 folder->i = strlen( folder->buffer );
555 return 1;
556 }
557 else{
558 folder->i = 0;
559
560 const char *local_folder =
561 addon_type_infos[reg->alias.type].local_content_folder;
562
563 if( !local_folder ) return 0;
564 vg_strcat( folder, local_folder );
565 vg_strcat( folder, reg->alias.foldername );
566 return 1;
567 }
568 }
569
570 /*
571 * Return existing cache id if reg_index points to a registry with its cache
572 * already set.
573 */
574 static u16 addon_cache_fetch( enum addon_type type, u32 reg_index ){
575 addon_reg *reg = NULL;
576
577 if( reg_index < addon_count( type, 0 ) ){
578 reg = get_addon_from_index( type, reg_index, 0 );
579 if( reg->cache_id )
580 return reg->cache_id;
581 }
582
583 return 0;
584 }
585
586 /*
587 * Allocate a new cache item from the pool
588 */
589 static u16 addon_cache_alloc( enum addon_type type, u32 reg_index ){
590 struct addon_cache *cache = &addon_system.cache[ type ];
591
592 u16 new_id = vg_pool_lru( &cache->pool );
593 struct addon_cache_entry *new_entry = vg_pool_item( &cache->pool, new_id );
594
595 addon_reg *reg = NULL;
596 if( reg_index < addon_count( type, 0 ) )
597 reg = get_addon_from_index( type, reg_index, 0 );
598
599 if( new_entry ){
600 if( new_entry->reg_ptr )
601 new_entry->reg_ptr->cache_id = 0;
602
603 if( reg )
604 reg->cache_id = new_id;
605
606 new_entry->reg_ptr = reg;
607 new_entry->reg_index = reg_index;
608 return new_id;
609 }
610 else{
611 vg_error( "cache full (type: %u)!\n", type );
612 return 0;
613 }
614 }
615
616 /*
617 * Get the real item data for cache id
618 */
619 static void *addon_cache_item( enum addon_type type, u16 id ){
620 if( !id ) return NULL;
621
622 struct addon_cache *cache = &addon_system.cache[type];
623 return cache->items + ((size_t)(id-1) * cache->stride);
624 }
625
626 /*
627 * Get the real item data for cache id ONLY if the item is completely loaded.
628 */
629 static void *addon_cache_item_if_loaded( enum addon_type type, u16 id ){
630 if( !id ) return NULL;
631
632 struct addon_cache *cache = &addon_system.cache[type];
633 struct addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
634
635 if( entry->state == k_addon_cache_state_loaded )
636 return addon_cache_item( type, id );
637 else return NULL;
638 }
639
640 /*
641 * Updates the item state from the main thread
642 */
643 static void async_addon_setstate( void *_entry, u32 _state ){
644 addon_cache_entry *entry = _entry;
645 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
646 entry->state = _state;
647 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
648 vg_success( " loaded (%s)\n", entry->reg_ptr->alias.foldername );
649 }
650
651 /*
652 * Handles the loading of an individual item
653 */
654 static int addon_cache_load_request( enum addon_type type, u16 id,
655 addon_reg *reg, vg_str folder ){
656
657 /* load content files
658 * --------------------------------- */
659 vg_str content_path = folder;
660
661 vg_msg msg;
662 vg_msg_init( &msg, reg->metadata, reg->metadata_len );
663
664 const char *kv_content = vg_msg_getkvstr( &msg, "content" );
665 if( kv_content ){
666 vg_strcat( &content_path, "/" );
667 vg_strcat( &content_path, kv_content );
668 }
669 else{
670 vg_error( " No content paths in metadata\n" );
671 return 0;
672 }
673
674 if( !vg_strgood( &content_path ) ) {
675 vg_error( " Metadata path too long\n" );
676 return 0;
677 }
678
679 if( type == k_addon_type_board ){
680 struct player_board *board = addon_cache_item( type, id );
681 player_board_load( board, content_path.buffer );
682 return 1;
683 }
684 else if( type == k_addon_type_player ){
685 struct player_model *model = addon_cache_item( type, id );
686 player_model_load( model, content_path.buffer );
687 return 1;
688 }
689 else {
690 return 0;
691 }
692
693 return 0;
694 }
695
696 static void addon_cache_free_item( enum addon_type type, u16 id ){
697 if( type == k_addon_type_board ){
698 struct player_board *board = addon_cache_item( type, id );
699 player_board_unload( board );
700 }
701 else if( type == k_addon_type_player ){
702 struct player_model *model = addon_cache_item( type, id );
703 player_model_unload( model );
704 }
705 }
706
707 /*
708 * Goes over cache item load requests and calls the above ^
709 */
710 static void addon_cache_load_loop(void){
711 vg_info( "Running load loop\n" );
712 char path_buf[4096];
713
714 for( u32 type=0; type<k_addon_type_max; type++ ){
715 struct addon_cache *cache = &addon_system.cache[type];
716
717 for( u32 id=1; id<=cache->pool.count; id++ ){
718 addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
719
720 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
721 if( entry->state == k_addon_cache_state_load_request ){
722 vg_info( "process cache load request (%u#%u, reg:%u)\n",
723 type, id, entry->reg_index );
724
725 if( entry->reg_index >= addon_count(type,0) ){
726 /* should maybe have a different value for this case */
727 entry->state = k_addon_cache_state_none;
728 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
729 continue;
730 }
731
732 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
733
734 /* continue with the request */
735 addon_reg *reg = get_addon_from_index( type, entry->reg_index, 0 );
736 entry->reg_ptr = reg;
737
738 vg_str folder;
739 vg_strnull( &folder, path_buf, 4096 );
740 if( addon_get_content_folder( reg, &folder, 1 ) ){
741 if( addon_cache_load_request( type, id, reg, folder ) ){
742 vg_async_call( async_addon_setstate,
743 entry, k_addon_cache_state_loaded );
744 continue;
745 }
746 }
747
748 vg_warn( "cache item did not load (%u#%u)\n", type, id );
749 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
750 entry->state = k_addon_cache_state_none;
751 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
752 }
753 else
754 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
755 }
756 }
757 }
758
759 /*
760 * Perform the cache interactions required to create a viewslot which will
761 * eventually be loaded by other parts of the system.
762 */
763 static u16 addon_cache_create_viewer( enum addon_type type, u16 reg_id ){
764 struct addon_cache *cache = &addon_system.cache[type];
765 vg_pool *pool = &cache->pool;
766
767 u16 cache_id = addon_cache_fetch( type, reg_id );
768 if( !cache_id ){
769 cache_id = addon_cache_alloc( type, reg_id );
770
771 if( cache_id ){
772 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
773 addon_cache_entry *entry = vg_pool_item( pool, cache_id );
774
775 if( entry->state == k_addon_cache_state_loaded ){
776 addon_cache_free_item( type, cache_id );
777 }
778
779 entry->state = k_addon_cache_state_load_request;
780 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
781 }
782 }
783
784 if( cache_id )
785 vg_pool_watch( pool, cache_id );
786
787 return cache_id;
788 }
789
790 static u16 addon_cache_create_viewer_from_uid( enum addon_type type,
791 char uid[ADDON_UID_MAX] ){
792 addon_alias q;
793 if( !addon_uid_to_alias( uid, &q ) ) return 0;
794 if( q.type != type ) return 0;
795
796 u32 reg_id = addon_match( &q );
797
798 if( reg_id == 0xffffffff ){
799 vg_warn( "We dont have the addon '%s' installed.\n", uid );
800 return 0;
801 }
802 else {
803 return addon_cache_create_viewer( type, reg_id );
804 }
805 }
806
807 static void addon_cache_watch( enum addon_type type, u16 cache_id ){
808 if( !cache_id ) return;
809
810 struct addon_cache *cache = &addon_system.cache[type];
811 vg_pool *pool = &cache->pool;
812 vg_pool_watch( pool, cache_id );
813 }
814
815 static void addon_cache_unwatch( enum addon_type type, u16 cache_id ){
816 if( !cache_id ) return;
817
818 struct addon_cache *cache = &addon_system.cache[type];
819 vg_pool *pool = &cache->pool;
820 vg_pool_unwatch( pool, cache_id );
821 }
822
823 #endif /* ADDON_C */