I was recently thinking about it, and went and threw together a mechanism for the server part of an engine to push files over to the client.
basically, it is rigged up in such a way that client-side file-open events are intercepted, and if the file is in the cache, this version will be used (otherwise it will fall back into checking in the engine's VFS).
as-is, the pushed files are not actually saved to the HDD, but are kept in RAM.
the idea could possibly be that of moving away from the client-end having its own permanent resource files (basically, the resource file that come with the game), and instead possibly working differently:
A, all resource data (textures / sounds / models / ...) are always streamed to the client (at the cost of potentially wasting bandwidth for network games, *1);
B, the client implements a persistent cache, with some sort of "precache" mechanism used to keep the cached files up to date (either a dynamically generated list, or possibly some sort of "general manifest");
C, leaving most resource-data as permanent files, with separate per-server streamed or cached files;
if a persistent cache were used, likely it would need to be kept server specific.
cache files would likely keep track of the file-sizes and a checksum, and if the "precache" server event contains files which aren't in the client-side cache, or the sizes or checksums are different, it will send a message back to the server, and the server will push over any of the files.
while this would save bandwidth (by not resending unchanged files), it would add some complexity to the handling of caches.
*1: basically, if every time the client would connect to the server, the server would send over any textures or sound-effects used by the world, which could potentially be a fairly big chunk of data (the worry is if whenever a client connects, it has to be sent 50 or 100MB or more of resource data, which could suck...).
ideally I guess, we would want the client to remember any files previously given to it, so that they don't have to be sent every time the client connects.
another minor uncertainty is how to best handle the case where the client has an out-of-date file:
simply invalidate the stale file, and wait for the new one to become available before loading the resource;
use the old file, and maybe "invalidate" the loaded copy somehow once the new one is downloaded, causing it to be reloaded (currently, no such invalidation mechanism exists);
alternatively, all file downloading/... is handled prior to the client being put into the world (*2).
*2: so, handshake process works like:
client connects to server socket (and does low-level handshake);
client sends, a "(connect)" message to server;
general server information;
a dump of the world contents (voxel terrain and map geometry, lists of lights and entities, ...);
a list of precached files (new).
client validates (upon seing a precache list) that all its files are up to date:
if true, sends back an "(connect_ok)";
if false, it sends back a list of stale files ("(precache_stale files...)").
server handles client messages:
if it sees a "(precache_stale)" message, it pushes any relevant files;
if it sees "(connect_ok)", it spawns the clients' player-entity and dumps them in the world.
handshake process until client sends "(connect_ok)";
(at this point, all resources are assumed up-to-date / ...)
client loads any data and begins rendering;
communication now consists primarily of "(impulse)" and "(wdelta)" messages (client input impulses, and world-deltas).
probably even with persistent caches, it could still make sense for the server to be able explicitly push data (say, because the data is session-specific or should never be saved to the HDD, which could probably be specially marked somehow, *3).
maybe "general pushes" ("(push_file)") should not be done during gameplay, but only during the initial handshake.
note that there are special "push" messages, namely "(push_sound)" and "(push_image)", which more explicitly patch over already loaded sounds or textures.
*3: say, ".volatile/...", where the prefix would basically tell the client "don't save this to disk!".
for the permanent-files scenario, this mostly works under the premise that all the resource data would need to be included for single-player to work anyways, so one may as well just use it also for network gameplay (these files would not be streamed by the server, leaving streaming mostly for server-local resources, rather than general game data).
nevermind, I still lack any really "good" way to handle client/server GUI stuff, but alas...
thoughts / comments?...