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