Multiple player spray decals

Grab your favourite IDE and tinker with the innards of game engines

Multiple player spray decals

Postby SM Sith Lord on Wed Feb 06, 2013 6:56 pm

Hey lopers. I usually post my coding questions on the Steam forums, but they don't seem to be as active as they used to be so I'm going to ask this one here too, hope you don't mind. :D

Player spray decals are local texture files that get uploaded to the server by the client and distributed to all the other clients in the game allowing them all to see your custom decal image.

I want to allow each player to have MORE THAN ONE custom spray image. I'm working with the Alien Swarm SDK code base. Alien Swarm Skeleton to be specific (http://code.google.com/p/sourcesdk-skeleton/).

Examining cdll_int.h shows the following typedef for player_info_s:
Code: Select all
typedef struct player_info_s
{
   DECLARE_BYTESWAP_DATADESC();
   // network xuid
   uint64         xuid;
   // scoreboard information
   char         name[MAX_PLAYER_NAME_LENGTH];
   // local server user ID, unique while server is running
   int            userID;
   // global unique player identifer
   char         guid[SIGNED_GUID_LEN + 1];
   // friends identification number
   uint32         friendsID;
   // friends name
   char         friendsName[MAX_PLAYER_NAME_LENGTH];
   // true, if player is a bot controlled by game.dll
   bool         fakeplayer;
   // true if player is the HLTV proxy
   bool         ishltv;
   // true if player is the Replay proxy
   bool         isreplay;
   // custom files CRC for this player
   CRC32_t         customFiles[MAX_CUSTOM_FILES];
   // this counter increases each time the server downloaded a new file
   unsigned char   filesDownloaded;
} player_info_t;


What caught my eye was the CRC32_t array customFiles. The define for MAX_CUSTOM_FILES defaults to 4, and as far as I can tell 0 is the player's spray decal and 1 is some sort of custom "jingle" sound file.

The customFiles array of the player_info_t struct is used in many places, including in c_baseplayer.cpp as shown here:
Code: Select all
void C_BasePlayer::PlayPlayerJingle()
{
   if ( !cl_customsounds.GetBool() )
      return;

   // Find player sound for shooter
   player_info_t info;
   engine->GetPlayerInfo( entindex(), &info );

   // Doesn't have a jingle sound
    if ( !info.customFiles[1] )   
      return;

   char soundhex[ 16 ];
   Q_binarytohex( (byte *)&info.customFiles[1], sizeof( info.customFiles[1] ), soundhex, sizeof( soundhex ) );

   // See if logo has been downloaded.
   char fullsoundname[ 512 ];
   Q_snprintf( fullsoundname, sizeof( fullsoundname ), "sound/temp/%s.wav", soundhex );

   if ( !filesystem->FileExists( fullsoundname ) )
   {
      char custname[ 512 ];
      Q_snprintf( custname, sizeof( custname ), "downloads/%s.dat", soundhex );
      // it may have been downloaded but not copied under materials folder
      if ( !filesystem->FileExists( custname ) )
         return; // not downloaded yet

      // copy from download folder to materials/temp folder
      // this is done since material system can access only materials/*.vtf files

      if ( !engine->CopyFile( custname, fullsoundname) )
         return;
   }

   Q_snprintf( fullsoundname, sizeof( fullsoundname ), "temp/%s.wav", soundhex );

   CLocalPlayerFilter filter;

   EmitSound_t ep;
   ep.m_nChannel = CHAN_VOICE;
   ep.m_pSoundName =  fullsoundname;
   ep.m_flVolume = VOL_NORM;
   ep.m_SoundLevel = SNDLVL_NORM;

   C_BaseEntity::EmitSound( filter, GetSoundSourceIndex(), ep );
}

Doesn't seem to be very much info on these "Custom Files" for Alien Swarm, but it seems like they are allowing for a custom sound file to be used a lot like the custom spray decals.

If I could find the code where the customFiles array of the player_info_t gets populated, it should be easy to make the modifications I need.

Does anybody know where or when this happens?
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Multiple player spray decals

Postby dark0r on Thu Feb 07, 2013 2:13 am

cl_logofile and cl_soundfile are both handled engine side, and there is no engine-exposed functionality on adding mod-specific custom files.

Therefore, your second logo file will have to be in cl_soundfile. This means that each connected client will have every other client's cl_logofile and cl_soundfile in their downloads folder (the file name is just <file hex>.dat).

If you need any more help or info, just let me know.
dark0r
Been Here A While
Been Here A While
 
Joined: Sat Mar 25, 2006 10:16 am
Location: de_hell

Re: Multiple player spray decals

Postby SM Sith Lord on Thu Feb 07, 2013 4:54 pm

Thanks for pointing out those console vars, I didn't notice those.

I can't find a reference to cl_soundfile anywhere in the code, but I did find cl_logofile being SET in optionssubmultiplayer.cpp using the COptionsSubMultiplayer::OnApplyChanges method. However, just like you said, the code that puts the CRC for cl_soundfile into the customFiles array of the info_player_t struct is nowhere to be seen. :(

Having 2 logo files is an over-simplification of what I'm actually trying to do. Here it is in more detail:
I'm trying to use Source engine's existing player spray system as a file transfer system to send a binary file (image) to the server. However, the client need to be able to upload as many files as they want to the server (1 at a time) and need to be able to initiate each transfer mid-game after making a selection off of a VGUI panel for example.

My confusion might come from the fact that I don't completely understand how the spray paint images are distributed. Does this scenario look about right? ...
1. You upload your logo.vtf file to the server upon connecting.
2. The server sends this file out to all connected clients, and any clients who connect in the future.

Assuming this is true and that the file transfer can be initiated mid-game, the server would just need to re-name the player's spray image once the transfer is done, and get ready to receive another file should the player choose to send one.

The important code segments being in the hidden code tiers makes this solution look dim. Some alternative solutions for allowing client to server uploads would be a series of user messages or *gasp* trying to implement a 3rd party library for file transfers. I know Source already has some basic client to server upload functionality implemented, so I'd really love to be able to take advantage of that if possible.

Any suggestions?

Thanks again for taking the time to consider my problem. :)
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Multiple player spray decals

Postby dark0r on Thu Feb 07, 2013 5:40 pm

Unfortunately all of the customisation file stuff is in the engine (I guess they've never made a game where they've had to expose it to mods).

Your idea of how sprays are distributed is completely correct. However, we can ignore the spray stuff altogether and just use Source to transfer the files for us. Here's how I'd do it... after the client makes a selection from the VGUI:

  1. Copy the file they selected to a hashed name (e.g., if they chose materials/mymod/test.vtf, copy it to downloads/<hash>.vtf)
  2. From the client, send a command to the server such as:
    requestfile <file hash>
  3. Upon receiving this command server-side, use static_cast<INetChannel*>(engine->GetPlayerNetInfo(player))->RequestFile("downloads/<hash>.vtf") to request that the client sends the file to the server.
  4. The client will automatically send the file (unless they have cl_allowupload disabled)
  5. To receive notification when the server fully receives the file, you have two options:
    a) Use SourceHook to hook the INetChannelHandler::FileReceived/FileDenied methods of the client. You can get a connected client's INetChannelHandler through the GetMsgHandler method of INetChannel.
    b) Poll the filesystem for the file you're expecting to receive every second or so, with a certain timeout (the easier but slower option)
When any new clients connect, you'd then have to use INetChannel::SendFile("downloads/<hash>.vtf") on them for the files to be distributed. However, the client can have cl_allowdownload disabled, and then this won't work.

Once again if you need me to elaborate on any steps, let me know.

A side note on player_info_t/customFiles
Each player has each other player's (including their own) player_info_t, as it is transmitted via stringtables from the engine. As it is populated in the engine-code, it's messy for us to modify it manually. When a player has a customisation file (cl_soundfile/cl_logofile), the client tells the server about this on connect. The server will then request these files from the client when they connect.
When a new client connects, it checks to see if it should download each other client's customFiles. It knows what these are as it has each other client's player_info_t.
When a client fully uploads its customisation file to the server, it triggers all other clients to download it from the server too.
dark0r
Been Here A While
Been Here A While
 
Joined: Sat Mar 25, 2006 10:16 am
Location: de_hell

Return to Programming

Who is online

Users browsing this forum: No registered users