+/*
+ * Get the real item data for cache id
+ */
+static void *addon_cache_item( enum addon_type type, u16 id ){
+ if( !id ) return NULL;
+
+ struct addon_cache *cache = &addon_system.cache[type];
+ return cache->items + ((size_t)(id-1) * cache->stride);
+}
+
+/*
+ * Get the real item data for cache id ONLY if the item is completely loaded.
+ */
+static void *addon_cache_item_if_loaded( enum addon_type type, u16 id ){
+ if( !id ) return NULL;
+
+ struct addon_cache *cache = &addon_system.cache[type];
+ struct addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
+
+ if( entry->state == k_addon_cache_state_loaded )
+ return addon_cache_item( type, id );
+ else return NULL;
+}
+
+/*
+ * Updates the item state from the main thread
+ */
+static void async_addon_setstate( void *_entry, u32 _state ){
+ addon_cache_entry *entry = _entry;
+ SDL_AtomicLock( &addon_system.sl_cache_using_resources );
+ entry->state = _state;
+ SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
+ vg_success( " loaded (%s)\n", entry->reg_ptr->alias.foldername );
+}
+
+/*
+ * Handles the loading of an individual item
+ */
+static int addon_cache_load_request( enum addon_type type, u16 id,
+ addon_reg *reg, vg_str folder ){
+
+ /* load content files
+ * --------------------------------- */
+ vg_str content_path = folder;
+
+ vg_msg msg;
+ vg_msg_init( &msg, reg->metadata, reg->metadata_len );
+
+ const char *kv_content = vg_msg_getkvstr( &msg, "content" );
+ if( kv_content ){
+ vg_strcat( &content_path, "/" );
+ vg_strcat( &content_path, kv_content );
+ }
+ else{
+ vg_error( " No content paths in metadata\n" );
+ return 0;
+ }
+
+ if( !vg_strgood( &content_path ) ) {
+ vg_error( " Metadata path too long\n" );
+ return 0;
+ }
+
+ if( type == k_addon_type_board ){
+ struct player_board *board = addon_cache_item( type, id );
+ player_board_load( board, content_path.buffer );
+ return 1;
+ }
+ else if( type == k_addon_type_player ){
+ struct player_model *model = addon_cache_item( type, id );
+ player_model_load( model, content_path.buffer );
+ return 1;
+ }
+ else {
+ return 0;
+ }
+
+ return 0;
+}
+
+static void addon_cache_free_item( enum addon_type type, u16 id ){
+ if( type == k_addon_type_board ){
+ struct player_board *board = addon_cache_item( type, id );
+ player_board_unload( board );
+ }
+ else if( type == k_addon_type_player ){
+ struct player_model *model = addon_cache_item( type, id );
+ player_model_unload( model );
+ }
+}
+
+/*
+ * Goes over cache item load requests and calls the above ^
+ */
+static void addon_cache_load_loop(void){
+ vg_info( "Running load loop\n" );
+ char path_buf[4096];
+
+ for( u32 type=0; type<k_addon_type_max; type++ ){
+ struct addon_cache *cache = &addon_system.cache[type];