basic features of replay editor
[carveJwlIkooP6JGAAIwe30JlM.git] / addon.c
diff --git a/addon.c b/addon.c
index c387edd6379a7f29cb893e15045e2a0e06bd5fb9..72083e3b503ddae15db766bcd6830417e9181125 100644 (file)
--- a/addon.c
+++ b/addon.c
@@ -1,22 +1,51 @@
-#ifndef ADDON_C
-#define ADDON_C
-
+#include "vg/vg_engine.h"
+#include "vg/vg_io.h"
+#include "vg/vg_loader.h"
 #include "addon.h"
 #include "addon_types.h"
 #include "vg/vg_msg.h"
 #include "steam.h"
 #include "workshop.h"
+#include <string.h>
+
+struct addon_system addon_system;
+
+u32 addon_count( enum addon_type type, u32 ignoreflags )
+{
+   if( ignoreflags ){
+      u32 typecount = 0, count = 0;
+      for( u32 i=0; typecount<addon_count( type, 0 ); i++ ){
+         addon_reg *reg = &addon_system.registry[i];
+         if( reg->alias.type == type ){
+            typecount ++;
 
-static u32 addon_count( enum addon_type type ){
-   return addon_system.registry_type_counts[ type ];
+            if( reg->flags & ignoreflags )
+               continue;
+            
+            count ++;
+         }
+      }
+
+      return count;
+   }
+   else
+      return addon_system.registry_type_counts[ type ];
 }
 
+
 /* these kind of suck, oh well. */
-static addon_reg *get_addon_from_index(enum addon_type type, u32 index){
-   u32 count = 0;
-   for( u32 i=0; count<addon_count(type); i++ ){
+addon_reg *get_addon_from_index( enum addon_type type, u32 index, 
+                                 u32 ignoreflags )
+{
+   u32 typecount = 0, count = 0;
+   for( u32 i=0; typecount<addon_count(type,0); i++ ){
       addon_reg *reg = &addon_system.registry[i];
       if( reg->alias.type == type ){
+         typecount ++;
+
+         if( reg->flags & ignoreflags )
+            continue;
+
          if( index == count )
             return reg;
 
@@ -27,7 +56,8 @@ static addon_reg *get_addon_from_index(enum addon_type type, u32 index){
    return NULL;
 }
 
-static u32 get_index_from_addon( enum addon_type type, addon_reg *a ){
+u32 get_index_from_addon( enum addon_type type, addon_reg *a )
+{
    u32 count = 0;
    for( u32 i=0; count<addon_system.registry_type_counts[type]; i++ ){
       addon_reg *reg = &addon_system.registry[i];
@@ -42,8 +72,13 @@ static u32 get_index_from_addon( enum addon_type type, addon_reg *a ){
    return 0xffffffff;
 }
 
-static u32 addon_match( addon_alias *alias ){
-   u32 foldername_djb2 = vg_strdjb2( alias->foldername );
+u32 addon_match( addon_alias *alias )
+{
+   if( alias->type == k_addon_type_none ) return 0xffffffff;
+
+   u32 foldername_djb2 = 0;
+   if( !alias->workshop_id )
+      foldername_djb2 = vg_strdjb2( alias->foldername );
 
    u32 count = 0;
    for( u32 i=0; count<addon_system.registry_type_counts[alias->type]; i++ ){
@@ -72,7 +107,8 @@ static u32 addon_match( addon_alias *alias ){
 /*
  * Create a string version of addon alias in buf
  */
-static void addon_alias_uid( addon_alias *alias, char buf[ADDON_UID_MAX] ){
+void addon_alias_uid( addon_alias *alias, char buf[ADDON_UID_MAX] )
+{
    if( alias->workshop_id ){
       snprintf( buf, 128, "sr%03d-steam-"PRINTF_U64, 
             alias->type, alias->workshop_id );
@@ -83,10 +119,39 @@ static void addon_alias_uid( addon_alias *alias, char buf[ADDON_UID_MAX] ){
    }
 }
 
+/*
+ * equality check
+ */
+int addon_alias_eq( addon_alias *a, addon_alias *b )
+{
+   if( a->type == b->type ){
+      if( a->workshop_id == b->workshop_id ){
+         if( a->workshop_id )
+            return 1;
+         else
+            return !strcmp( a->foldername, b->foldername );
+      }
+      else
+         return 0;
+   }
+   else return 0;
+}
+
+/*
+ * make alias represent NULL.
+ */
+void invalidate_addon_alias( addon_alias *alias )
+{
+   alias->type = k_addon_type_none;
+   alias->workshop_id = 0;
+   alias->foldername[0] = '\0';
+}
+
 /*
  * parse uid to alias. returns 1 if successful
  */
-static int addon_uid_to_alias( char uid[ADDON_UID_MAX], addon_alias *alias ){
+int addon_uid_to_alias( const char *uid, addon_alias *alias )
+{
 /*           1
  * 01234567890123
  * sr&&&-@@@@@-#*
@@ -95,8 +160,14 @@ static int addon_uid_to_alias( char uid[ADDON_UID_MAX], addon_alias *alias ){
  *         |
  *     location
  */
-   if( strlen(uid) < 13 ) return 0;
-   if( !((uid[0] == 's') && (uid[1] == 'r')) ) return 0;
+   if( strlen(uid) < 13 ){
+      invalidate_addon_alias( alias );
+      return 0;
+   }
+   if( !((uid[0] == 's') && (uid[1] == 'r')) ){
+      invalidate_addon_alias( alias );
+      return 0;
+   }
 
    char type[4];
    memcpy( type, uid+2, 3 );
@@ -109,15 +180,20 @@ static int addon_uid_to_alias( char uid[ADDON_UID_MAX], addon_alias *alias ){
 
    if( !strcmp(location,"steam") )
       alias->workshop_id = atoll( uid+12 );
-   else if( !strcmp(location,"local") )
+   else if( !strcmp(location,"local") ){
+      alias->workshop_id = 0;
       vg_strncpy( uid+12, alias->foldername, 64, k_strncpy_always_add_null );
-   else
+   }
+   else{
+      invalidate_addon_alias( alias );
       return 0;
+   }
 
    return 1;
 }
 
-static void addon_system_init( void ){
+void addon_system_init( void )
+{
    u32 reg_size   = sizeof(addon_reg)*ADDON_MOUNTED_MAX;
    addon_system.registry = vg_linear_alloc( vg_mem.rtmemory, reg_size );
 
@@ -160,7 +236,7 @@ static void addon_system_init( void ){
 /*
  * Reciever for scan completion. copies the registry counts back into main fred
  */
-static void async_addon_reg_update( void *data, u32 size )
+void async_addon_reg_update( void *data, u32 size )
 {
    vg_info( "Registry update notify\n" );
    
@@ -190,6 +266,7 @@ static addon_reg *addon_alloc_reg( PublishedFileId_t workshop_id,
    }
 
    addon_reg *reg = &addon_system.registry[ addon_system.registry_count ];
+   reg->flags = 0;
    reg->metadata_len = 0;
    reg->cache_id = 0;
    reg->state = k_addon_state_indexed;
@@ -266,14 +343,11 @@ static addon_reg *addon_mount_workshop_folder( PublishedFileId_t workshop_id,
    }
 
    enum addon_type type = k_addon_type_none;
-   vg_msg root = {0};
-   root.buf = reg->metadata;
-   root.len = reg->metadata_len;
-   root.max = sizeof(reg->metadata);
+   vg_msg msg;
+   vg_msg_init( &msg, reg->metadata, reg->metadata_len );
 
-   vg_msg workshop = root;
-   if( vg_msg_seekframe( &workshop, "workshop", k_vg_msg_first )){
-      type = vg_msg_seekkvu32( &workshop, "type", k_vg_msg_first );
+   if( vg_msg_seekframe( &msg, "workshop" )){
+      vg_msg_getkvintg( &msg, "type", k_vg_msg_u32, &type );
    }
 
    if( type == k_addon_type_none ){
@@ -289,9 +363,9 @@ static addon_reg *addon_mount_workshop_folder( PublishedFileId_t workshop_id,
 /*
  * Mount a local folder. may or may not have addon.inf
  */
-static addon_reg *addon_mount_local_addon( const char *folder,
-                                              enum addon_type type,
-                                              const char *content_ext )
+addon_reg *addon_mount_local_addon( const char *folder,
+                                    enum addon_type type,
+                                    const char *content_ext )
 {
    char folder_path_buf[4096];
    vg_str folder_path;
@@ -306,7 +380,7 @@ static addon_reg *addon_mount_local_addon( const char *folder,
       if( (reg->alias.type == type) && (reg->foldername_hash == folder_hash) ){
          if( !strcmp( reg->alias.foldername, folder_name ) ){
             reg->state = k_addon_state_indexed;
-            return NULL;
+            return reg;
          }
       }
    }
@@ -318,10 +392,8 @@ static addon_reg *addon_mount_local_addon( const char *folder,
 
    if( reg->metadata_len == 0 ){
       /* create our own content commands */
-      vg_msg msg = {0};
-      msg.buf = reg->metadata;
-      msg.len = 0;
-      msg.max = sizeof(reg->metadata);
+      vg_msg msg;
+      vg_msg_init( &msg, reg->metadata, sizeof(reg->metadata) );
 
       u32 content_count = 0;
 
@@ -354,7 +426,7 @@ static addon_reg *addon_mount_local_addon( const char *folder,
 
       if( !content_count ) return NULL;
       if( msg.error == k_vg_msg_error_OK )
-         reg->metadata_len = msg.cur;
+         reg->metadata_len = msg.cur.co;
       else{
          vg_error( "Error creating metadata: %d\n", msg.error );
          return NULL;
@@ -368,8 +440,14 @@ static addon_reg *addon_mount_local_addon( const char *folder,
 /*
  * Check all subscribed items
  */
-static void addon_mount_workshop_items(void){
+void addon_mount_workshop_items(void)
+{
+   if( skaterift.demo_mode ){
+      vg_info( "Won't load workshop items in demo mode\n" );
+      return;
+   }
    if( !steam_ready ) return;
+
    /*
     * Steam workshop scan
     */
@@ -420,9 +498,9 @@ next_file_workshop:;
  * Scan a local content folder for addons. It must find at least one file with 
  * the specified content_ext to be considered.
  */
-static void addon_mount_content_folder( enum addon_type type,
-                                           const char *base_folder, 
-                                           const char *content_ext )
+void addon_mount_content_folder( enum addon_type type,
+                                 const char *base_folder, 
+                                 const char *content_ext )
 {
    vg_info( "Mounting addons(type:%d) matching skaterift/%s/*/*%s\n", 
                   type, base_folder, content_ext );
@@ -462,16 +540,31 @@ static void addon_mount_content_folder( enum addon_type type,
 /*
  * write the full path of the addon's folder into the vg_str
  */
-static int addon_get_content_folder( addon_reg *reg, vg_str *folder ){
+int addon_get_content_folder( addon_reg *reg, vg_str *folder, int async)
+{
    if( reg->alias.workshop_id ){
-      vg_async_item *call = 
-         vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
-      struct async_workshop_filepath_info *info = call->payload;
+      struct async_workshop_filepath_info *info = NULL;
+      vg_async_item *call = NULL;
+
+      if( async ){
+         call = vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
+         info = call->payload;
+      }
+      else 
+         info = alloca( sizeof(struct async_workshop_filepath_info) );
+
       info->buf = folder->buffer;
       info->id = reg->alias.workshop_id;
       info->len = folder->len;
-      vg_async_dispatch( call, async_workshop_get_filepath );
-      vg_async_stall(); /* too bad! */
+
+      if( async ){
+         vg_async_dispatch( call, async_workshop_get_filepath );
+         vg_async_stall(); /* too bad! */
+      }
+      else {
+         async_workshop_get_filepath( info, 0 );
+      }
+
       if( info->buf[0] == '\0' ){
          vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64 ")\n",
                      reg->alias.workshop_id );
@@ -497,11 +590,12 @@ static int addon_get_content_folder( addon_reg *reg, vg_str *folder ){
  * Return existing cache id if reg_index points to a registry with its cache
  * already set.
  */
-static u16 addon_cache_fetch( enum addon_type type, u32 reg_index ){
+u16 addon_cache_fetch( enum addon_type type, u32 reg_index )
+{
    addon_reg *reg = NULL;
 
-   if( reg_index < addon_count( type ) ){
-      reg = get_addon_from_index( type, reg_index );
+   if( reg_index < addon_count( type, 0 ) ){
+      reg = get_addon_from_index( type, reg_index, 0 );
       if( reg->cache_id ) 
          return reg->cache_id;
    }
@@ -512,15 +606,16 @@ static u16 addon_cache_fetch( enum addon_type type, u32 reg_index ){
 /*
  * Allocate a new cache item from the pool
  */
-static u16 addon_cache_alloc( enum addon_type type, u32 reg_index ){
+u16 addon_cache_alloc( enum addon_type type, u32 reg_index )
+{
    struct addon_cache *cache = &addon_system.cache[ type ];
 
    u16 new_id = vg_pool_lru( &cache->pool );
    struct addon_cache_entry *new_entry = vg_pool_item( &cache->pool, new_id );
 
    addon_reg *reg = NULL;
-   if( reg_index < addon_count( type ) )
-      reg = get_addon_from_index( type, reg_index );
+   if( reg_index < addon_count( type, 0 ) )
+      reg = get_addon_from_index( type, reg_index, 0 );
 
    if( new_entry ){
       if( new_entry->reg_ptr )
@@ -542,7 +637,8 @@ static u16 addon_cache_alloc( enum addon_type type, u32 reg_index ){
 /*
  * Get the real item data for cache id 
  */
-static void *addon_cache_item( enum addon_type type, u16 id ){
+void *addon_cache_item( enum addon_type type, u16 id )
+{
    if( !id ) return NULL;
 
    struct addon_cache *cache = &addon_system.cache[type];
@@ -552,7 +648,8 @@ static void *addon_cache_item( enum addon_type type, u16 id ){
 /*
  * 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 ){
+void *addon_cache_item_if_loaded( enum addon_type type, u16 id )
+{
    if( !id ) return NULL;
 
    struct addon_cache *cache = &addon_system.cache[type];
@@ -566,7 +663,8 @@ static void *addon_cache_item_if_loaded( enum addon_type type, u16 id ){
 /* 
  * Updates the item state from the main thread
  */
-static void async_addon_setstate( void *_entry, u32 _state ){
+void async_addon_setstate( void *_entry, u32 _state )
+{
    addon_cache_entry *entry = _entry;
    SDL_AtomicLock( &addon_system.sl_cache_using_resources );
    entry->state = _state;
@@ -584,12 +682,10 @@ static int addon_cache_load_request( enum addon_type type, u16 id,
     * --------------------------------- */
    vg_str content_path = folder;
 
-   vg_msg root = {0};
-   root.buf = reg->metadata;
-   root.len = reg->metadata_len;
-   root.max = sizeof(reg->metadata);
+   vg_msg msg;
+   vg_msg_init( &msg, reg->metadata, reg->metadata_len );
 
-   const char *kv_content = vg_msg_seekkvstr( &root, "content", 0 );
+   const char *kv_content = vg_msg_getkvstr( &msg, "content" );
    if( kv_content ){
       vg_strcat( &content_path, "/" );
       vg_strcat( &content_path, kv_content );
@@ -635,22 +731,27 @@ static void addon_cache_free_item( enum addon_type type, u16 id ){
 /*
  * Goes over cache item load requests and calls the above ^
  */
-static void addon_cache_load_loop(void){
+static void T1_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++ ){
+   for( u32 type=0; type<k_addon_type_max; type++ )
+   {
       struct addon_cache *cache = &addon_system.cache[type];
 
-      for( u32 id=1; id<=cache->pool.count; id++ ){
+      for( u32 id=1; id<=cache->pool.count; id++ )
+      {
          addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
 
          SDL_AtomicLock( &addon_system.sl_cache_using_resources );
-         if( entry->state == k_addon_cache_state_load_request ){
+         if( entry->state == k_addon_cache_state_load_request )
+         {
             vg_info( "process cache load request (%u#%u, reg:%u)\n",
                         type, id, entry->reg_index );
 
-            if( entry->reg_index >= addon_count(type) ){
+            if( entry->reg_index >= addon_count(type,0) )
+            {
                /* should maybe have a different value for this case */
                entry->state = k_addon_cache_state_none;
                SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
@@ -660,13 +761,15 @@ static void addon_cache_load_loop(void){
             SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
 
             /* continue with the request */
-            addon_reg *reg = get_addon_from_index( type, entry->reg_index );
+            addon_reg *reg = get_addon_from_index( type, entry->reg_index, 0 );
             entry->reg_ptr = reg;
 
             vg_str folder;
             vg_strnull( &folder, path_buf, 4096 );
-            if( addon_get_content_folder( reg, &folder ) ){
-               if( addon_cache_load_request( type, id, reg, folder ) ){
+            if( addon_get_content_folder( reg, &folder, 1 ) )
+            {
+               if( addon_cache_load_request( type, id, reg, folder ) )
+               {
                   vg_async_call( async_addon_setstate, 
                                  entry, k_addon_cache_state_loaded );
                   continue;
@@ -684,11 +787,35 @@ static void addon_cache_load_loop(void){
    }
 }
 
+void addon_system_pre_update(void)
+{
+   if( !vg_loader_availible() ) return;
+
+   SDL_AtomicLock( &addon_system.sl_cache_using_resources );
+   for( u32 type=0; type<k_addon_type_max; type++ )
+   {
+      struct addon_cache *cache = &addon_system.cache[type];
+
+      for( u32 id=1; id<=cache->pool.count; id++ )
+      {
+         addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
+         if( entry->state == k_addon_cache_state_load_request )
+         {
+            SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
+            vg_loader_start( T1_addon_cache_load_loop, NULL );
+            return;
+         }
+      }
+   }
+   SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
+}
+
 /*
  * Perform the cache interactions required to create a viewslot which will
  * eventually be loaded by other parts of the system.
  */
-static u16 addon_cache_create_viewer( enum addon_type type, u16 reg_id ){
+u16 addon_cache_create_viewer( enum addon_type type, u16 reg_id )
+{
    struct addon_cache *cache = &addon_system.cache[type];
    vg_pool *pool = &cache->pool;
 
@@ -715,10 +842,11 @@ static u16 addon_cache_create_viewer( enum addon_type type, u16 reg_id ){
    return cache_id;
 }
 
-static u16 addon_cache_create_viewer_from_uid( enum addon_type type,
-                                               char uid[ADDON_UID_MAX] ){
+u16 addon_cache_create_viewer_from_uid( enum addon_type type,
+                                        char uid[ADDON_UID_MAX] )
+{
    addon_alias q;
-   addon_uid_to_alias( uid, &q );
+   if( !addon_uid_to_alias( uid, &q ) ) return 0;
    if( q.type != type ) return 0;
 
    u32 reg_id = addon_match( &q );
@@ -732,7 +860,8 @@ static u16 addon_cache_create_viewer_from_uid( enum addon_type type,
    }
 }
 
-static void addon_cache_watch( enum addon_type type, u16 cache_id ){
+void addon_cache_watch( enum addon_type type, u16 cache_id )
+{
    if( !cache_id ) return;
 
    struct addon_cache *cache = &addon_system.cache[type];
@@ -740,12 +869,11 @@ static void addon_cache_watch( enum addon_type type, u16 cache_id ){
    vg_pool_watch( pool, cache_id );
 }
 
-static void addon_cache_unwatch( enum addon_type type, u16 cache_id ){
+void addon_cache_unwatch( enum addon_type type, u16 cache_id )
+{
    if( !cache_id ) return;
 
    struct addon_cache *cache = &addon_system.cache[type];
    vg_pool *pool = &cache->pool;
    vg_pool_unwatch( pool, cache_id );
 }
-
-#endif /* ADDON_C */