How to change a map on the fly?

Designed a level that creates new, exciting, and challenging Armagetron game play? Or maybe just something funky. Put it right here.
User avatar
wrtlprnft
Reverse Outside Corner Grinder
Posts: 1679
Joined: Wed Jan 04, 2006 4:42 am
Location: 0x08048000
Contact:

How to change a map on the fly?

Post by wrtlprnft »

I've created a small script that creates random maps for a race server (you can find it on the server list under "race server").

It works fine and creates good maps, but if i change map_file and map_uri on the server, the client won't download the new file... The server and client will only use the new map if everyone logs out and back in...

Since there was a server that used random maps, it must be somehow possible to change maps on-the-fly... how?
Last edited by wrtlprnft on Thu Mar 09, 2006 8:37 pm, edited 1 time in total.
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

Do it in everytime.cfg, which gets loaded every round. Somewhere around here (check the development section), I posted the script that did the actual work.

Also, better check on map_uri settings, because I think that one got removed.

Finally, you have to have the new map file named differently than the old one, otherwise clients won't update it. When the client checks its cache, it checks only the filename, so if you change the file, but not the name, the client thinks it has the correct map and won't download the new one.
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
wrtlprnft
Reverse Outside Corner Grinder
Posts: 1679
Joined: Wed Jan 04, 2006 4:42 am
Location: 0x08048000
Contact:

Post by wrtlprnft »

Currently I'm using map_uri, and the client downloads the file from my server as it should. Do I maybe have to use the alpha version of the server? Currently im using the latest beta...

Browsing the development docs is going to be fun, the wiki seems to be down, so i have to use google cache...

Btw what happens with all the downloaded files? do they get deleted or will they stay in the cache forever?
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

If the client is working with map_uri, then it should work, but you still need to update to what the wiki has on it (I'll dig up a link in a second) because I don't think the final 0.2.8 will support map_uri anymore.

I think the downloaded files currently stay in the cache forever.

(I really need to get the wiki moved to my other machine. The two extra servers I setup have both failed me, so all that's left is to move the original server to a Linux distribution that I can upgrade piecemeal, which I'm working on)

http://wiki.armagetronad.net/index.php/Playing_Maps (wiki's back up, thanks for the heads up, restarted the machine)
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
wrtlprnft
Reverse Outside Corner Grinder
Posts: 1679
Joined: Wed Jan 04, 2006 4:42 am
Location: 0x08048000
Contact:

Post by wrtlprnft »

Ok, thanks ;)

resource_repository_client doesn't seem to have any effect, but resource_repository_server works :)

The server is now online...

Btw i dont really like the idea of downloading files and keeping them without asking... If a server would get the client to download a .jpg file that really is a .wmf that exploits a certain security hole in a windows library... and then some google desktop search finds it... i consider that dangerous. but i can feel pretty safe under linux ;)

(btw the wiki seems to be down exactly when i need it most... good luck making it more stable)

Thanks for the help ;)
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

I seem to recall saying something about "we should ask instead of automatically downloading something". ;)

So I played your race server, and it's more or less exactly how I had envisioned one. :) I would have built it almost the same, and had wanted to do something like it. We should start a "Armagetron Olympics" group of servers, and periodically run a tournament on each server, giving a final ranking, and your race server should be part of it. ;)

Some suggestions:

* Put another length of the grid on the other side of the winzone. As it is, when you make that last mad rush for the zone to beat the other guy, you usually die. Give some room to slow down.

* Invisible walls would be...interesting. You do that by making a wall with a height="0.00001".

* Less obstacles and a longer course, I'd like to try that. Also, less obstacles, longer course, and WALLS_LENGTH 10 or something like that. A semen race. ;)

* Make the course path vary. Right now it's a straight run. Add some turns, some areas where the course narrows to a straightaway, but the straightaway itself is only like 1/8 of the width of the course.

* Add some death zones as obstacles. It's fun like it is, but walls can be forgiving if you hit them right. Death zones are never forgiving.

If you want to post your code for generating it, I'll be happy to see how I can add some of this stuff. :) Also, if you get some working bash script or something to tail the chat logs and change everytime.cfg when the round end/match end message appears, I'd love to have that. I'd bring the Crack Pipe back up with map rotator in an instant if I had that.

/me decides to kick the "we need the server to execute an external command between rounds" horse again.
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
gnorty
Core Dumper
Posts: 187
Joined: Wed Nov 02, 2005 2:45 am

Post by gnorty »

Should be easy to do a

system("<command>");


in there somewhere... Why not make a lil mod?
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

What header file would that be in? ;) (I googled for something like that and didn't find it) Adding it is fairly straightforward, except that I'd hate to have clients timeout because the server's busy in an external process, but we'll have to see how it works out.
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

Solution found. :) At least, this is what's needed if we still have to update clients while waiting for the task to complete. If not, we can just use system(). I can't believe I forgot system(), since python has the same function in it.

http://pstreams.sourceforge.net/

I'll screw with it in a bit. If I get it to work, I'll put a patch on the wiki. As much as I'd like to see it in a release, it's not worth arguing over, to me, anyway, and I think there's some resistance to it. ;) (I could be wrong, but I remember there being some, anyway)
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Jonathan
A Brave Victim
Posts: 3391
Joined: Thu Feb 03, 2005 12:50 am
Location: Not really lurking anymore

Post by Jonathan »

Lucifer wrote:* Invisible walls would be...interesting. You do that by making a wall with a height="0.00001".
I haven't looked at the code lately, but why not 0 or less? The engine is 2D, and near 0 the line segments would still show up, badly aliased, right?
Lucifer wrote:Death zones are never forgiving.
Indeed. They spawn on top of me too often. And avoiding the danger zone is not worth it.
ˌɑrməˈɡɛˌtrɑn
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

I don't know why not 0 or less, it hadn't occurred to me to try it, I just assumed you'd drive right over them. At 0.00001, on my screen, at 1280x800 blahblah, they don't show at all.
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
wrtlprnft
Reverse Outside Corner Grinder
Posts: 1679
Joined: Wed Jan 04, 2006 4:42 am
Location: 0x08048000
Contact:

Post by wrtlprnft »

K... I found out how i can change the maps every five rounds. The server prints "New Round" in var/scores.txt every time it starts a new round... Here's my script that uses it:

Code: Select all

#!/bin/sh

i=0
#num stores the current map number to avoid overlapping on restart
test -e num || echo 1 >num
num=`cat num`
while true
do
    line=""
    read line
    test "$line" == "New Round" || continue
    echo New Round. \$i = $i
    i=`expr $i + 1`
    test $i -ge 4 || continue
    i=0
    num=`expr $num + 1`
    echo $num >num
    echo new map number $num
    #test.php is the script to create the mazes
    #/www2 is my public htdocs
    ./test.php >/www2/wrtlprnft/maze$num
    echo "SAY At the end of this maze is a winzone. Try and get it ;)" > tronsrv2/etc/games/armagetronad-dedicated/everytime.cfg
    echo "SAY The maze changes every 5 rounds. Have fun." >> tronsrv2/etc/games/armagetronad-dedicated/everytime.cfg
    echo "MAP_FILE wrtlprnft/maze$num" >> tronsrv2/etc/games/armagetronad-dedicated/everytime.cfg
done
and here's the code for test.php:

Code: Select all

#!/usr/bin/php
<?='<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>'?>

<!DOCTYPE Resource SYSTEM "map-0.2.8_beta3.dtd">

<Resource name="Racing maze" version="0.2" author="wrtlprnft" category="OktaTRON">

<Map version="0.2.8">
    <Settings>
        <Setting name="TEAMS_MIN" value="2" />
        <Setting name="TEAMS_MAX" value="9" />
        <Setting name="SP_TEAMS_MIN" value="2" />
        <Setting name="SP_TEAMS_MAX" value="10" />
    </Settings>
<World>
    <Field>
        <Axes number="8" />
<?php
        define('HEIGHT', 3000);
        define('WIDTH', 100);
        define('SPAWNPOINTS', 18);
        define('NUMOBJECTS', 1000);
        define('MAXTRIES', 60);


        $OBJECTS = array(
            array('TYPE' => 0, 'MINDISTANCE' => 15, 'RIMDISTANCE' => 3, 'POINTS' => array(array('X' => -10, 'Y' => 0), array('X' => 10, 'Y' => 0))),
            array('TYPE' => 0, 'MINDISTANCE' => 20, 'RIMDISTANCE' => 10, 'POINTS' => array(array('X' => 10, 'Y' => 20), array('X' => 0, 'Y' => 0), array('X' => 10, 'Y' => 0), array('X' => 0, 'Y' => 20), array('X' => 10, 'Y' => 20))),
            array('TYPE' => 0, 'MINDISTANCE' => 15, 'RIMDISTANCE' => 3, 'POINTS' => array(array('X' => 0, 'Y' => 10), array('X' => 0, 'Y' => -10))),
            array('TYPE' => 0, 'MINDISTANCE' => 15, 'RIMDISTANCE' => 6, 'POINTS' => array(array('X' => -10, 'Y' => -10), array('X' => 10, 'Y' => 10))),
            array('TYPE' => 0, 'MINDISTANCE' => 15, 'RIMDISTANCE' => 6, 'POINTS' => array(array('X' => 10, 'Y' => -10), array('X' => -10, 'Y' => 10))),
            array('TYPE' => 0, 'MINDISTANCE' => 15, 'RIMDISTANCE' => 10, 'POINTS' => array(array('X' => -10, 'Y' => 0), array('X' => 0, 'Y' => -10), array('X' => 10, 'Y' => 0))),
            array('TYPE' => 0, 'MINDISTANCE' => 20, 'RIMDISTANCE' => 10, 'POINTS' => array(array('X' => -10, 'Y' => -5), array('X' => 0, 'Y' => 5), array('X' => 10, 'Y' => -5))),
            array('TYPE' => 0, 'MINDISTANCE' => 20, 'RIMDISTANCE' => 10, 'POINTS' => array(array('X' => 10, 'Y' => 5), array('X' => 0, 'Y' => -5), array('X' => -10, 'Y' => 5))),
            array('TYPE' => 0, 'MINDISTANCE' => 20, 'RIMDISTANCE' => 10, 'POINTS' => array(array('X' => 10, 'Y' => -10), array('X' => 0, 'Y' => 10), array('X' => -10, 'Y' => -10))),
            array('TYPE' => 1, 'MINDISTANCE' => 20, 'RIMDISTANCE' => 1, 'r' => 5)
            //array('MINDISTANCE' => 8, 'RIMDISTANCE' => 3, 'POINTS' => array(array('X' => 5, 'Y' => 5), array('X' => 0, 'Y' => 5), array('X' => 0, 'Y' => 0), array('X' => 5, 'Y' => 0)), array('X' => 5, 'Y' => 5))
        );

        $usedobjs = array();

        for($i=0; $i<NUMOBJECTS; $i++)
        {
            $nextid = rand(0, count($OBJECTS) -1);
            $nextobj = $OBJECTS[$nextid];
            for($t=0; $t<MAXTRIES; $t++)
            {
                $newx=rand($nextobj['RIMDISTANCE'] -1, WIDTH - $nextobj['RIMDISTANCE']+2);
                $newy=rand(100, HEIGHT);
                $dist = $nextobj['MINDISTANCE'];
                $found=false;
                foreach($usedobjs as $obj)
                {
                    $olddist = $OBJECTS[$obj['id']]['MINDISTANCE'];
                    $totaldist = $olddist + $dist;
                    $xdiff = $newx - $obj['x'];
                    $ydiff = $newy - $obj['y'];
                    if(sqrt($xdiff*$xdiff + $ydiff*$ydiff) < $totaldist)
                    {
                        $found=true;
                        break;
                    }
                }
                if(!$found)
                {
                    $usedobjs[] = array('x' => $newx, 'y' => $newy, 'id' => $nextid);
                    break;
                }
            }
            if($t==MAXTRIES) break;
        }

?>
        <Spawn x="50" y="-50" angle="90" />
        <Spawn x="40" y="-50" angle="90" />
        <Spawn x="60" y="-50" angle="90" />
        <Spawn x="30" y="-50" angle="90" />
        <Spawn x="70" y="-50" angle="90" />
        <Spawn x="20" y="-50" angle="90" />
        <Spawn x="80" y="-50" angle="90" />
        <Spawn x="10" y="-50" angle="90" />
        <Spawn x="90" y="-50" angle="90" />
        <Zone effect="win">
            <ShapeCircle radius="100" growth="0">
                <Point x="<?=WIDTH/2?>" y="<?=HEIGHT+100?>" />
            </ShapeCircle>
        </Zone>
        <!--<Zone effect="death">
            <ShapeCircle radius="1" growth="70">
                <Point x="<?=WIDTH/2?>" y="-199" />
            </ShapeCircle>
        </Zone>-->
        <Wall>
            <Point x="0"            y="-200"           />
            <Point x="<?=WIDTH?>"          y="-200"           />
            <Point x="<?=WIDTH?>"          y="<?=HEIGHT*20?>"       />
            <Point x="0"            y="<?=HEIGHT*2?>"       />
            <Point x="0"            y="-200"           />
        </Wall>
<?php
        foreach($usedobjs as $obj)
        {
            switch($OBJECTS[$obj['id']]['TYPE'])
            {
            case 0:
                print('        <Wall height="2">' . "\n");
                foreach($OBJECTS[$obj['id']]['POINTS'] as $point)
                    print('            <Point x="' . ($obj['x'] + $point['X']) . '" y="' . ($obj['y'] + $point['Y']) . '" />' . "\n");
                print('        </Wall>' . "\n");
            break;
            case 1:
                print('<Zone effect="death">
                    <ShapeCircle radius="' . $OBJECTS[$obj['id']]['r'] . '" growth="0">
                        <Point x="' . $obj['x'] . '" y="' . $obj['y'] . '" />
                    </ShapeCircle>
                </Zone>');
            }
        }
?>
    </Field>
</World>
</Map>
</Resource>
You've been warned, the code is totally crazy.
User avatar
wrtlprnft
Reverse Outside Corner Grinder
Posts: 1679
Joined: Wed Jan 04, 2006 4:42 am
Location: 0x08048000
Contact:

Post by wrtlprnft »

oh, u need to call the script with "tail -f var/scorelog.txt | name.sh".
User avatar
Z-Man
God & Project Admin
Posts: 11587
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Cool server, I have to say. I liked the settings from my first visit best. I was winning then, so maybe that's not a significant opinion :)

Some things you may want to try:
Increase GAME_TIMEOUT, maybe to 30. This will make the server wait longer for clients to download the map, at the possible cost that specially coded clients exploit this to make the server wait every round.
Put more obstacles to the side walls. Often, maps have easy to hit free rides on the sides.
Exploit the obvious similarity to the fertilization process some more :)
Maybe disable rubber totally and get rid of the death zones? I dunno.

I'll try to disable the annoying death zone spawn messages for the next version. I've got the sneaky fealing that they are generated clientside...
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

How about a pause command? Something like "PAUSE seconds", where seconds is a float greater than 0. Then he can run a regular timeout, but trigger a pause in everytime.cfg to give clients time to download the map.

Also, it looks like libxml2 can retrieve gzipped content from a webserver (isn't it part of the some standard or other anyway?), so try setting apache to send gzipped stuff. That'll reduce bandwidth used, especially since apache will cache the gzipped page when it sends it. I don't know how much performance tuning apache will help you, but it seems like using sendfile (default setting, afaik) would help. The point, of course, is to make clients take less time to download the map, and to reduce load on the webserver so it can serve more clients in short period of time.

I liked the last settings I played under, but I still think there's lots of room for improvement. Several bottlenecks on the map would be nice, where the grid wall itself angles in and all players have to fit through the hole. Making the track octangular instead of straight, offshoot passages that shoot into winding tunnels, but provide a potentially faster route to the zone, if you can navigate them fast enough.

I'd like to see a slower server, though, one that requires more thought and less twitch to win. I dont' know if that's what you had in mind, but I'd like to see that. :)

So do you know python? Or do you prefer to work with php? Doesn't matter to me, I can go either way, although I have a strong preference for python. But I work professionally with php, so it's not like it's a language I neglect or anything. I'd like to see a labyrinth that incorporates elements from your generator, setup as either a deathmatch or a fortress arena, possibly it'll run 4 fortresses with a very quick conquer settings.

I'm not sure the maze generation algorithm has much to add. I didn't read your code yet (I'm really sleepy), so the only thing I can think that it might add is an algorithm that will evenly space the obstacles. It did look like the obstacles were placed with a spray pattern, which would make the inside denser than the outside. The maze generation algorithm doesn't work like that and has quite a different effect. I'll see how it goes. Combining the two into one script has other benefits, even if there's not as much convergence in the core stuff. You know, things like wrapping the track around a maze and making a few entrances into the maze from the track. Of course, the maze generator assumes a 4 axis layout, but it needs to be generalized anyway to allow any arbitrary number of axes.

Anyway, good work. Now let's hack the server to run the generation scripts so we don't have to do the other stuff. :)

Edit: Yeah, and don't worry about those guys that say "I liked it simple, don't change anything!" I kept hearing that when I was working on the Crack Pipe, and then the same people who said that would come back and say "This is great! Don't change it!" And I'd add something else, and then "This is even better! Leave it like this!" Some people just fear change. Don't sweat it, just make it as fun as you can. ;)
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
Post Reply