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