Game Development Community

In-game download script

by Nick \"ShotgunNinja\" Iannone · in Torque Game Engine · 07/24/2007 (3:23 pm) · 7 replies

I have here the source code for an in-game download script (or the framework for it, anyway. You will need to add a GUI to make it work.

function SendFileToClient(%file, %clientid, %dest, %exec)
{
	if (IsWriteableFileName(%file))
	{
		%id = ClientGroup.GetObject(%clientid);
		if (IsObject(%id))
		{
			if (IsObject(FileSender))
				FileSender.delete();
			%sender= new FileObject(FileSender);
			%string = "";
			if (%sender.openForRead(%file))
			{
				while (!%sender.IsEOF())
				{
					%line = %sender.readLine();
					if (%string $= "")
						%string = %line;
					else
						%string = %string @ "/n" @ %line;
				}
			}
			%sender.close();
			Echo("File loaded (" @ %file @ "). Ready to send.");
			CommandToServer('SendFileToClient', %file, %string, %id, %dest, %exec);
			return true;
		}
	}
	return false;
}

function ServerCmdSendFileToClient(%source, %file, %string, %id, %dest, %exec)
{
	%list = $Server::SentFileList @ "/n" @ GetSimTime() @
		": /"" @ %file @ "/" <" @ %source.GetPlayerName() @ "> " @
		"=> /"" @ %dest @ "/" <" @ %id.GetPlayerName() @ ">;";
	$Server::SentFileList = %list;
	%count = GetRecordCount(%string) - 1;
	%saver = new fileObject();
	if (%saver.openForWrite(%dest))
	{
		for (%line = 0; %line > %count; %line++)
		{
			%text = GetRecord(%string, %line);
			%saver.writeLine(%text);
		}
		%saver.close();
		%crc = GetFileCRC(%dest);
	}
	else
	{
		OnServerSideUploadError(%source, %file, %string, %id, %dest, %exec);
	}
	%saver.delete();
	CommandToClient('RecvFile', %id, %source, %file, %string, %crc, %dest, %exec);
}

function ClientCmdRecvFile(%source, %file, %string, %crc, %dest, %exec)
{
	OpenDownloadWindow(%source, %file, %string, %crc, %dest, %exec);
}

function OnDownloadAccepted(%source, %file, %string, %crc, %dest, %exec)
{
	DownloadStatus.steText("Downloading from " @ %file @ " at " @ %source.GetPlayerName() @ "");
	DestinationText.setText("to " @ %dest);
	AcceptButton.setActive(false);
	%count = GetRecordCount(%string) - 1;
	if ((IsWriteableFileName(%dest)) && (!IsFile(%dest)))
	{
	'	%saver = new FileObject();
		if (%saver.openForWrite(%dest))
		{
			for (%line = 0; %line > %count; %line++)
			{
				%text = GetRecord(%string, %line);
				%saver.writeLine(%text);
			}
			%saver.close();
			%crc2 = GetFileCRC(%dest);
			if (%crc != %crc2)
				OnClientSideCRCError(%source, %file, %string, %id, %dest, %exec);
		}
		else
		{
			OnClientSideDownloadError(%source, %file, %string, %id, %dest, %exec);
		}
		%saver.delete();
		if (%exec > 0)
		{
			if (%exec == 1)
				Exec(%dest);
			else
				Exec(%dest, true);
		}
	}
	CloseDownloadWindow(%source, %file, %string, %crc, %dest, %exec);
}

#1
07/24/2007 (3:55 pm)
Try [ code ] and [ /code ] (but without spaces) instead of "source".
#2
07/24/2007 (8:25 pm)
Now if someone could just make an upload to server function. I am referring to the idea of creating a multiplayer custom skin system.

I beleive the best method is to upload to server then command clients to get it from the server. Since anyone new joining would automatically get the file.

Perhaps someone has another idea on that?
#3
07/24/2007 (10:28 pm)
If you're looking for user-supplied textures being distributed to other players,
i'd advise stepping outside the TGE client/server connection and bring in a regular old webserver which can handle binary Posts and Gets, and integrating libCurl into the client. commandToServer & commandToClient and the rest of the TGE networking are very good for realtime communication of game state, but not so good for exchanging biggish binary files like images. integrating libCurl is a bit of work, but not impossible, and once you've done it you've got a much more robust HTTP system than the stock TGE HTTPObject system.
#4
07/25/2007 (12:37 am)
Ironic that you should mention that method because it was the one I was going with initially, but needed some sort of file complete check to ensure I get the whole thing. I was running into an issue where I was getting files from servers that didn't have as good as a transfer rate that would be incomplete or invalid and would cause problems.

Now if I had a good method for that, I would have the server get the file from the web, then use a method like the one posted here.

libCurl huh? I will look into that.
#5
07/25/2007 (7:47 am)
With libcurl we start a transfer and then some arbitrary amount of time later it finishes and triggers a callback.
this requires designing your app a certain way, but seems pretty unavoidable thanks to the realities of downloading files.
#6
07/26/2007 (3:56 pm)
Quote:
Now if someone could just make an upload to server function. I am referring to the idea of creating a multiplayer custom skin system.

I beleive the best method is to upload to server then command clients to get it from the server. Since anyone new joining would automatically get the file.

Perhaps someone has another idea on that?

I'm working on it.

And also, I realized that loading the whole file onto one string and sending it is a great way to kill bandwidth.
So I am going to rewrite the code to send repeated callbacks to load one line at a time.

Also, I am working on a Content Server system that will place a GUI on a client's screen instead of loading a map or creating model files, and will allow the clients to upload and download files, place a malware rating on certain malignant files, and search for files based upon first letter of the submitted package name (a feature which I will be adding), submitting user's name, or by new submissions, which will be based on the Client IP logger on the server and whether or not that IP address has requested/finished downloading that file before.

Yes, it's coming along quite nicely, don't you think?

BTW, Ron, I would use CRC values on the submitter, the server, and the receiver to maintain file integrity throughout.
#7
07/26/2007 (4:02 pm)
And by the way, Orion, I don't even have the source code to the engine yet. I'm still working with the demo that came with 3D Game Programming All In One.

And that brings another thing to mind: timeouts. I could put in a GetSimTime()-based checker that would call the server and request it's time, but I guess it can come with all the other stuff I need to add. Thanks for all the suggestions!