a more comprehensive workshop system
[carveJwlIkooP6JGAAIwe30JlM.git] / ent_skateshop.c
index a667599bc31afaa5a07b95005d615db1f93f0a02..ce0ca5d2b55236f98164197d906a469df462b681 100644 (file)
@@ -4,6 +4,7 @@
 #define VG_GAME
 #include "vg/vg.h"
 #include "vg/vg_steam_ugc.h"
+#include "vg/vg_msg.h"
 #include "ent_skateshop.h"
 #include "world.h"
 #include "player.h"
@@ -11,6 +12,7 @@
 #include "menu.h"
 #include "pointcloud.h"
 #include "highscores.h"
+#include "steam.h"
 
 /*
  * Checks string equality but does a hash check first
@@ -61,7 +63,7 @@ VG_STATIC struct cache_board *skateshop_cache_fetch( u32 registry_index )
          struct registry_board *other = 
             &global_skateshop.registry[ min_board->registry_id ];
 
-         vg_info( "Deallocating board: '%s'\n", min_board, other->filename );
+         vg_info( "Deallocating board: '%s'\n", min_board, other->foldername );
 
          player_board_unload( &min_board->board );
          other->cache_ptr = NULL;
@@ -69,7 +71,7 @@ VG_STATIC struct cache_board *skateshop_cache_fetch( u32 registry_index )
 
       if( reg ){
          vg_info( "Allocating board (reg:%u) '%s'\n", 
-                  registry_index, reg->filename );
+                  registry_index, reg->foldername );
       }
       else{
          vg_info( "Pre-allocating board (reg:%u) 'null'\n", registry_index );
@@ -123,7 +125,7 @@ VG_STATIC void skateshop_async_board_loaded( void *payload, u32 size )
    reg->cache_ptr = cache_ptr;
    SDL_AtomicUnlock( &global_skateshop.sl_cache_access );
 
-   vg_success( "Async board loaded (%s)\n", reg->filename );
+   vg_success( "Async board loaded (%s)\n", reg->foldername );
 }
 
 /*
@@ -132,7 +134,9 @@ VG_STATIC void skateshop_async_board_loaded( void *payload, u32 size )
  */
 VG_STATIC void workshop_visibile_load_loop_thread( void *_args )
 {
-   char path[1024];
+   char path_buf[4096];
+   vg_str folder;
+
    for( u32 i=0; i<SKATESHOP_BOARD_CACHE_MAX; i++ ){
       struct cache_board *cache_ptr = &global_skateshop.cache[i];
 
@@ -156,31 +160,82 @@ VG_STATIC void workshop_visibile_load_loop_thread( void *_args )
                vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
 
             struct async_workshop_filepath_info *info = call->payload;
-            info->buf = path;
+            info->buf = path_buf;
             info->id = reg->workshop_id;
-            info->len = vg_list_size(path) - strlen("/board.mdl")-1;
+            info->len = vg_list_size(path_buf);
             vg_async_dispatch( call, async_workshop_get_filepath );
             vg_async_stall(); /* too bad! */
 
-            if( path[0] == '\0' ){
-               SDL_AtomicLock( &global_skateshop.sl_cache_access );
-               cache_ptr->state = k_cache_board_state_none;
-               SDL_AtomicUnlock( &global_skateshop.sl_cache_access );
-
+            if( path_buf[0] == '\0' ){
                vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64 ")\n",
                            reg->workshop_id );
-               continue;
-            }
-            else{
-               strcat( path, "/board.mdl" );
+
+               goto file_is_broken;
             }
+
+            folder.buffer = path_buf;
+            folder.i = strlen(path_buf);
+            folder.len = 4096;
          }
          else{
-            snprintf( path, 256, "models/boards/%s", reg->filename );
+            vg_strnull( &folder, path_buf, 4096 );
+            vg_strcat( &folder, "boards/" );
+            vg_strcat( &folder, reg->foldername );
+         }
+
+         vg_str meta_path = folder;
+         vg_strcat( &meta_path, "/addon.inf" );
+
+         if( !vg_strgood( &meta_path ) ) {
+            vg_error( "Metadata path too long\n" );
+            goto file_is_broken;
+         }
+
+         u8 meta[512];
+         FILE *fp = fopen( meta_path.buffer, "rb" );
+
+         if( !fp ) goto file_is_broken;
+
+         u32 l = fread( meta, 1, 512, fp );
+         if( l != 512 ){
+            if( !feof(fp) ){
+               fclose(fp);
+               vg_error( "unknown error codition" );
+               goto file_is_broken;
+            }
+         }
+         fclose(fp);
+
+         /* load content files
+          * --------------------------------- */
+
+         vg_str content_path = folder;
+
+         vg_msg msg;
+         vg_msg_init( &msg, meta, l );
+         vg_msg_cmd cmd;
+         while( vg_msg_next( &msg, &cmd ) ){
+            if( (msg.depth == 0) && (cmd.code == k_vg_msg_code_kvstring) ){
+               if( VG_STRDJB2_EQ( "content", cmd.key, cmd.key_djb2 ) ){
+                  vg_strcat( &content_path, "/" );
+                  vg_strcat( &content_path, cmd.value._buf );
+                  break;
+               }
+            }
+         }
+         if( !vg_strgood( &content_path ) ) {
+            vg_error( "Metadata path too long\n" );
+            goto file_is_broken;
          }
 
-         player_board_load( &cache_ptr->board, path );
+         player_board_load( &cache_ptr->board, content_path.buffer );
          vg_async_call( skateshop_async_board_loaded, cache_ptr, 0 );
+         continue;
+
+file_is_broken:;
+         SDL_AtomicLock( &global_skateshop.sl_cache_access );
+         cache_ptr->state = k_cache_board_state_none;
+         SDL_AtomicUnlock( &global_skateshop.sl_cache_access );
       }
       else
          SDL_AtomicUnlock( &global_skateshop.sl_cache_access );
@@ -220,8 +275,9 @@ VG_STATIC void workshop_steam_scan(void)
    vg_async_stall();
 
    for( u32 j=0; j<workshop_count; j++ ){
+      /* check for existance in both our caches
+       * ----------------------------------------------------------*/
       PublishedFileId_t id = workshop_ids[j];
-
       for( u32 i=0; i<global_skateshop.t1_registry_count; i++ ){
          struct registry_board *reg = &global_skateshop.registry[i];
 
@@ -230,41 +286,114 @@ VG_STATIC void workshop_steam_scan(void)
             goto next_file_workshop;
          }
       }
+      for( u32 i=0; i<global_skateshop.t1_world_registry_count; i++ ){
+         struct registry_world *reg = &global_skateshop.world_registry[i];
 
-      if( global_skateshop.t1_registry_count == SKATESHOP_REGISTRY_MAX ){
-         vg_error( "You have too many boards installed!\n" );
-         break;
+         if( reg->workshop_id == id ){
+            reg->state = k_registry_board_state_indexed;
+            goto next_file_workshop;
+         }
       }
 
+      /* new one, lets find out what type it is
+       * ---------------------------------------------------------------*/
       vg_info( "new listing from the steam workshop!: "PRINTF_U64"\n", id );
+      vg_async_item *call1 = 
+         vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
 
-      struct registry_board *reg = &global_skateshop.registry[
-                                       global_skateshop.t1_registry_count ++ ];
+      char path[ 4096 ];
 
-      reg->cache_ptr = NULL;
-      snprintf( reg->filename, 64, PRINTF_U64, id );
-      reg->filename_hash = vg_strdjb2( reg->filename );
-      reg->workshop_id = id;
-      reg->state = k_registry_board_state_indexed;
+      struct async_workshop_filepath_info *info = call1->payload;
+      info->buf = path;
+      info->id = id;
+      info->len = vg_list_size(path);
+      vg_async_dispatch( call1, async_workshop_get_filepath );
+      vg_async_stall(); /* too bad! */
 
-      workshop_file_info_clear( &reg->workshop );
-      strcpy( reg->workshop.title, "Workshop file" );
+      vg_info( "%s\n", path );
+      vg_str folder = {.buffer = path, .i=strlen(path), .len=4096};
+      vg_str meta_path = folder;
+      vg_strcat( &meta_path, "/addon.inf" );
+      if( !vg_strgood( &meta_path ) ){
+         vg_error( "The metadata path is too long\n" );
+         goto next_file_workshop;
+      }
 
-      /* load the metadata off the disk */
-      vg_async_item *call = 
-         vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
+      u8 meta[512];
+      FILE *fp = fopen( meta_path.buffer, "rb" );
+      if( !fp ){
+         vg_error( "Could not open the '%s'\n", meta_path.buffer );
+         goto next_file_workshop;
+      }
 
-      const char *meta_file = "/board.mdl.inf";
-      char path[ 1024 ];
-      struct async_workshop_filepath_info *info = call->payload;
-      info->buf = path;
-      info->id = reg->workshop_id;
-      info->len = vg_list_size(path) - strlen(meta_file)-1;
-      vg_async_dispatch( call, async_workshop_get_filepath );
-      vg_async_stall(); /* too bad! */
+      u32 l = fread( meta, 1, 512, fp );
+      if( l != 512 ){
+         if( !feof(fp) ){
+            fclose(fp);
+            vg_error( "unknown error codition" );
+            goto next_file_workshop;
+         }
+      }
+      fclose(fp);
+
+      enum workshop_file_type type = k_workshop_file_type_none;
+      vg_msg msg;
+      vg_msg_init( &msg, meta, l );
+
+      vg_msg_cmd cmd;
+      while( vg_msg_next( &msg, &cmd ) ){
+         if( (msg.depth == 1) && (cmd.code == k_vg_msg_code_frame) ){
+            if( VG_STRDJB2_EQ( "workshop", cmd.key, cmd.key_djb2 ) ){
+               u32 depth = msg.depth;
+               while( (msg.depth == depth) && vg_msg_next( &msg, &cmd ) ){
+                  if( cmd.code & k_vg_msg_code_unsigned ){
+                     if( VG_STRDJB2_EQ( "type", cmd.key, cmd.key_djb2 ) ){
+                        type = cmd.value._u32;
+                     }
+                  }
+               }
+            }
+         }
+      }
+
+      if( type == k_workshop_file_type_none ){
+         vg_error( "Cannot determine addon type\n" );
+         goto next_file_workshop;
+      }
+
+      /* now that we have the type
+       * ------------------------------------------------------------------*/
+
+      if( type == k_workshop_file_type_board ){
+         if( global_skateshop.t1_registry_count == SKATESHOP_REGISTRY_MAX ){
+            vg_error( "You have too many boards installed!\n" );
+            goto next_file_workshop;
+         }
+
+         struct registry_board *reg = &global_skateshop.registry[
+                                       global_skateshop.t1_registry_count ++ ];
+
+         reg->cache_ptr = NULL;
+         snprintf( reg->foldername, 64, PRINTF_U64, id );
+         reg->foldername_hash = vg_strdjb2( reg->foldername );
+         reg->workshop_id = id;
+         reg->state = k_registry_board_state_indexed;
+      }
+      else if( type == k_workshop_file_type_world ){
+         if( global_skateshop.t1_world_registry_count == SKATESHOP_WORLDS_MAX ){
+            vg_error( "You have too many worlds installed!\n" );
+            goto next_file_workshop;
+         }
 
-      strcat( path, meta_file );
-      workshop_load_metadata( path, &reg->workshop );
+         struct registry_world *reg = &global_skateshop.world_registry[
+                                 global_skateshop.t1_world_registry_count ++ ];
+         
+         snprintf( reg->foldername, 64, PRINTF_U64, id );
+         reg->foldername_hash = vg_strdjb2( reg->foldername );
+         reg->type = k_world_load_type_workshop;
+         reg->workshop_id = id;
+         reg->state = k_registry_board_state_indexed;
+      }
 
 next_file_workshop:;
    }
@@ -283,6 +412,7 @@ VG_STATIC void workshop_scan_thread( void *_args )
       reg->state = k_registry_board_state_indexed_absent;
    }
 
+#if 0
    /*
     * Local disk scan
     */
@@ -318,19 +448,25 @@ VG_STATIC void workshop_scan_thread( void *_args )
 
          reg->cache_ptr = NULL;
          vg_strncpy( file.name, reg->filename, 64, k_strncpy_always_add_null );
+#if 0
          vg_strncpy( file.name, reg->workshop.title,
                      64, k_strncpy_always_add_null );
+#endif
          reg->filename_hash = hash;
          reg->workshop_id = 0;
          reg->state = k_registry_board_state_indexed;
+
+#if 0
          reg->workshop.author = 0;
          strcpy( reg->workshop.author_name, "custom" );
+#endif
       }
 
 next_file: tinydir_next( &dir );
    }
 
    tinydir_close(&dir);
+#endif
 
    if( steam_ready ) workshop_steam_scan();
    
@@ -527,6 +663,7 @@ VG_STATIC void callback_persona_statechange( CallbackMsg_t *msg )
    PersonaStateChange_t *info = (PersonaStateChange_t *)msg->m_pubParam;
    ISteamFriends *hSteamFriends = SteamAPI_SteamFriends();
 
+#if 0
    if( info->m_nChangeFlags & k_EPersonaChangeName ){
       for( u32 i=0; i<global_skateshop.registry_count; i++ ){
          struct registry_board *reg = &global_skateshop.registry[i];
@@ -537,6 +674,7 @@ VG_STATIC void callback_persona_statechange( CallbackMsg_t *msg )
          }
       }
    }
+#endif
 }
 
 /*
@@ -966,6 +1104,8 @@ fade_out:;
 
    struct registry_board *reg = 
       &global_skateshop.registry[cache_ptr->registry_id];
+
+#if 0
    struct workshop_file_info *info = &reg->workshop;
 
    /* Skin title
@@ -989,6 +1129,7 @@ fade_out:;
    mlocal[3][2] = 0.0f;
    m4x3_mul( mtext, mlocal, mmdl );
    font3d_simple_draw( &gui.font, 0, info->author_name, &main_camera, mmdl );
+#endif
 }
 
 VG_STATIC void skateshop_render_charshop(void)