ID:151773
 
If you've played Tomb Explorer, you know that you can make your own maps and place them in Tomb Explorer's /maps directory or sub-directories. That works all well and good when players download updates of the games and they get all the map files that are included in those directories, however there are some problems with this that I'm not sure how to fix.

1. If players want to download new maps by file, they'll have to place them in something like:

c:\program files\byond\myhub\foomer\tombexplorer\maps\mymaps

Its a bit of a hassle, especially if the player isn't familiar with BYOND's directory setup and doesn't know where to find the game's directory. I'd like to find a way to automatically send levels to where they need to be, but I can't think of any way to do that.

2. When players download updates of the game that include maps, any high scores that they'd accumulated on those maps are erased. However, since distributing maps via updates is the easiest way to get them where they need to be, this creates an issue... I suppose the best solution would be to separate scores from maps, but the idea was to keep the scores with the maps so that if they're distributed, they'll keep the scores with them...

Now, if I were to have players download the files and save them somewhere on their hard drive like a normal game, they'd still end up with the problem where the game's executable actually directs the player to download Foomer.TombExplorer from BYOND and run it...

Does anyone have any novel solutions to these problems?
Foomer wrote:
Its a bit of a hassle, especially if the player isn't familiar with BYOND's directory setup and doesn't know where to find the game's directory. I'd like to find a way to automatically send levels to where they need to be, but I can't think of any way to do that.

Byond's ftp() function lets you set a default filename. I was going to suggest setting it to a full path name, such as
player << ftp(file, "C:\Program Files\Byond\...\myMap.map")

But I just tested it out first, and Byond automatically truncates the directory information from the default text it puts on the input field for the client.

This doesn't seem like reasonable behavior unless it was for security reasons, such as someone not realizing that a naughty file sent to them defaulted to being saved in the startup folder.

Perhaps this is worth a feature suggestion.

2. When players download updates of the game that include maps, any high scores that they'd accumulated on those maps are erased. However, since distributing maps via updates is the easiest way to get them where they need to be, this creates an issue... I suppose the best solution would be to separate scores from maps, but the idea was to keep the scores with the maps so that if they're distributed, they'll keep the scores with them...

Perhaps you could keep a backup of all the maps, then the next time the server is run it could sort things out. Or you could have the maps downloaded with a different file extension and have it changed the first time the server is run. Perhaps have maps come as myMap.ma_ and have maps renamed to myMap.map with
world/New()
shell("ren maps\*.ma_ *.map")

(edit)
After the server handles extracting the score data first, and integrates it afterword...
(edit)
Bah, I need to think before I click submit.
Also, you'd need to delete the originals before renaming the new ones. Perhaps you could loop through the directory contents, see what .ma_ files have a .map alternative and extract from only those alternatives, then run the rename command, then update the ones you kept information for.
Foomer wrote:
1. I'd like to find a way to automatically send levels to where they need to be, but I can't think of any way to do that.
You could handle the file loading through the game itself. More effort, but would eliminate the annoyance of placing the files. Also would allow for automated updates of files (from inside the game) without updating the whole game.

2. When players download updates of the game that include maps, any high scores that they'd accumulated on those maps are erased. However, since distributing maps via updates is the easiest way to get them where they need to be, this creates an issue... I suppose the best solution would be to separate scores from maps, but the idea was to keep the scores with the maps so that if they're distributed, they'll keep the scores with them...

I'm slightly confused here.
If I'm playing on my compy and get a high score does it upload to a server so it will be distributed later? o.O

Either way: you could use a MySQL server or a BYOND server for central high score storage. Probably would be a good idea for each map to have a unique ID to avoid repeat name confusions (or abuse of scoreboard).

Centralizing all of this sort of thing would solve your problems but the problem is money and hosting... which is really the same problem. You can host it yourself, but thats taking a toll on your computer and bandwidth. You could have it hosted elsewhere but you probably don't want to pay for that.

The cheapest and possibly simplest idea would be to get a free website hosted that allows file downloading, then do the following:
Whenever a new map is added have it included in the 'directory' which keeps track of the file's download URL on the site, the map name, map description, and the high scores for it. Have the game parse this directory for downloading new maps and for keeping up on the high scores.


Not really 'novel' solutions but a few ideas. :p
1) The best way would probably be to create a separate "map adding" program that automatically executes when you try to open a map file. Then, you could automatically add the files. The only implementation for this would probably be through another language, though! The best BYOND method I could think of would probably be through the ftp() proc, like someone else already suggested.
In response to AJX
AJX wrote:
I'm slightly confused here.

I was thinking, at first, similarly to how you are, and I even wrote up a post about keeping track of things client-side. Then I realised that he was probably talking about things from the server's point of view, so I deleted most of my post and started over.

He was talking about downloading updates of the game. From that, I take it that he's talking about a player going to his hub page and clicking a link to download the new version of the game, overwriting similarly named files that already existed in their place, and therefor losing any data that was saved in them since last update.
In response to Loduwijk
Ideally I'd like to not release a new version of the game every time I include more maps, since that gets pretty tedious and its not good for the game if I stop maintaining it (electrocute myself while working on the computer, etc...). I really want people to just be able to download the new map files and toss them into the map's directory, but that's very difficult to do with BYOND's structure.

I'd really like to come up with some better way for people to download maps and have them automatically included with the game, without them having to download the whole game over again...
In response to Foomer
Foomer wrote:
I'd really like to come up with some better way for people to download maps and have them automatically included with the game, without them having to download the whole game over again...

Have the game server handle it all. It could check every time the world starts up. Store the files in your members file section, or wherever, and have it look there.
In response to Foomer
Would you be interested in an external (non-BYOND) program that can read a map listing and download maps to their expected location?
In response to Nadrew
Could the regular game be programmed to download map files from, say, a text file full of links? If I could do that, I could just include a "download latest levels", have the game do a quick check to see what you've got, and then download anything that looks new.

I'd still much rather have people able to download maps and place them in the game's directory - you know, the way it works for virtually every other custom-map game out there.
In response to Foomer
The problem with that is you can't really pick where you want the files to go, especially if it's outside of the core directory. You have to remember not everyone's My Hub folder is in the same place.

The approach I suggest is an XML file that gets parsed by say, a C# program, which loads a list of avaliable maps and provides a means to download them to the directory needed. You'd specify the directory if you wanted, but it would be loaded to default based on the registry entries BYOND sets.
In response to Foomer
Foomer wrote:
Could the regular game be programmed to download map files from, say, a text file full of links? If I could do that, I could just include a "download latest levels", have the game do a quick check to see what you've got, and then download anything that looks new.
A list full of links would be more complicated than having a BYOND server handle it for you.
If you used two BYOND servers communicating with one another then you could just use Export() and Import() to transfer the map files.
<s>As for the links I would ASSUME that</s> you could use Export() to connect to a website and download a file<s>, though I haven't tried it myself... </s>

EDIT: This is as close as I could get.

mob/verb/Test()
var/HTTP[]=world.Export("http://www.byond.com/download/build/440.1018_byond.exe")
if(!HTTP)
usr<<"FAIL!"
return

var/F=HTTP["CONTENT"]
if(F)
usr<<ftp(F)
usr<<"Done"


I can't seem to save the file without prompting the user though, *BUT* it will set the default folder as the game's directory. So it is a step in the right direction?
In response to Foomer
Foomer wrote:
Could the regular game be programmed to download map files from, say, a text file full of links? If I could do that, I could just include a "download latest levels", have the game do a quick check to see what you've got, and then download anything that looks new.

mob/proc/Download(EntryNumber)
var/URL=LURL[EntryNumber]
var/Name=LName[EntryNumber]//in case of different file names from map names
var/HTTP[]=world.Export("[URL]")
if(!HTTP)
world<<"FAIL!"
return

var/F=HTTP["CONTENT"]
if(F)
src<<ftp(F,Name)

mob/verb/IWantMapNumber(N as num)
if(N>LName.len)
world<<"Sorry, entry [N] does not exist"
return
if(N<1)
world<<"Please enter a number greater than 0"
return
Selected=N
world<<"You chose [LName[N]], Confirm? (Click confirm verb)"

mob/verb/Confirm()
if(!Selected)
world<<"You did not make a selection"
return
if(Selected>LName.len)
world<<"You made an invalid selection, please try again"
return
if(Selected<1)
world<<"You hax. Quit it"
return 0
Download(Selected)

mob
var/Selected
var/LName[0]
var/LDesc[0]
var/LURL[0]

mob/verb/IWantsMaps()


//Get the text file here

ParseTextFile(ThisIsYourTextFile,LName,LDesc,LURL)

for(var/i=1,i<=LName.len,i++)
world<<"Map [i]: [LName[i]]"
world<<"Desc: [LDesc[i]]"
world<<"URL: [LURL[i]]"
world<<"<br>"

proc/ParseTextFile(TFile,L1[],L2[],L3[])
var/T
if(isfile(TFile)) T=file2text(TFile)
else if(istext(TFile)) T=TFile
else
world<<"\red Invalid Parse Request"
return

var/Location
var/Name
var/Desc
var/URL



while(T)
while(findtext(T,ascii2text(10),1,2)||findtext(T," ",1,2)) T=copytext(T,2) //Clear out line breaks and spaces
Location=findtext(T,"%")
Name=copytext(T,1,Location) //Grab Name
T=copytext(T,Location+1) //Clear up to the %

Location=findtext(T,"%")
Desc=copytext(T,1,Location) //Grab Description
T=copytext(T,Location+1) //Clear up to % again

Location=findtext(T,"%")
URL=copytext(T,1,Location) //Grab URL
T=copytext(T,Location+1)

L1+=Name
L2+=Desc
L3+=URL




var/ThisIsYourTextFile={"
SuperCoolMap%Super Cool Description%http://www.byond.com/download/build/440.1018_byond.exe%
OtherSuperCoolMap%Even Cooler Description%http://www.byond.com/download/build/440.1018_byond.exe%"}

This is the general concept of what you would want.
You could grab the text file from a website, that would work fine.

You could also include a version number in the parsing, check to see if you already have the map, check if the version number is higher, and just update the map (for an 'UpdateMaps' button)

Problem is this *NEEDS* confirmation. FTP is the only way I know of giving the file to the user, but it requires confirmation. If someone else knows of a way to download files without telling the player then that would be more desirable... But I don't think it exists because that'd be 'dangerous'. (Browse_RSC() i believe puts files in BYOND's resource files... not in the game directory.)
In response to AJX
AJX wrote:
I can't seem to save the file without prompting the user though,

Naturally. BYOND is secure like that.

However, you can use fcopy() to save the file in the game's working directory (i.e., in the host's computer). Obviously this doesn't work for individual players but is suitable for the case at hand.
In response to Kaioken
Kaioken wrote:
AJX wrote:
I can't seem to save the file without prompting the user though,

Naturally. BYOND is secure like that.

However, you can use fcopy() to save the file in the game's working directory (i.e., in the host's computer). Obviously this doesn't work for individual players but is suitable for the case at hand.

Edit: **This doesn't work** (see end)

See, what you should have quoted is this:

If someone else knows of a way to download files without telling the player then that would be more desirable...

And then said 'AHAH! But I do!!!'... And I would have said, 'See? Thats what I was talking about.'
And the issue would be solved.

Since this is a single player game this works perfectly for what he is trying to accomplish, and it could be easily swapped out in my other post's code to accomplish everything he wanted.

(not that I expect anyone to actually USE that code. If I was going to actually spend more than 5 minutes on it I would set up a little skin interface to handle the map downloading and make it all purrrty... But yea. I was just trying to make an example.


EDIT:: So actually, this doesn't work. The reason is the file isn't actually typecasted as file and if it is you can't grab it.. So I need a new way to define the content from the export() as a file to then be FCopied... And I dont know how
In response to AJX
Typecasting wouldn't exactly be a problem here, rather the actual var's value (which should be a file reference), but anyway. There's generally no problem at all; works fine for me, without needing to try anything special. Have you handled Export() correctly? Perhaps the URL is wrong?
Well, here's what I've used to test.
mob/verb
copyFile()
var/list/L = world.Export("Direct URL to a random file")
if(!L) //couldn't download it...
src << "Error"
return
var/file = L["CONTENT"]
var/filename = "[file]" //embedding files in text gives the filename
src << "Filename: '[filename]'"

//copy the file into the 'directory' folder, name it as the original filename
fcopy(file,"directory/[filename]")
//or,
fcopy(file,filename) //to put it in the root of the game folder
In response to Kaioken
Don't forget to fdel() the original, don't want copies clogging your temporary files!
In response to Nadrew
Good call, but would it actually remain and clog otherwise? Likewise, would fdel(world.Export(...)) do anything? I almost never see people delete temporary files like those gotten from world.Export(), so I just assumed they automagically clear themselves later. Where are those stored, anyway? I searched around for the file I've just tested, and couldn't fine it anywhere relevant.
In response to Kaioken
I musta just did sumthin dum(b).
My execution was different than yours so thats probably it...