Team balancing

Developer discussion of experimental fixes, changes, and improvements.

Moderators: Nexuiz Moderators, Moderators

Fri Aug 11, 2006 3:23 pm

  • How does that work? On the CTF Herforst Elite server, for example, it seems to not work at all. At least, one has often very unbalanced teams.

    Maybe Nexuiz should keep a record of player performance for each specific map? (of course, that would require to set player passwords)
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Fri Aug 11, 2006 4:38 pm

  • Cinquero wrote:How does that work? On the CTF Herforst Elite server, for example, it seems to not work at all. At least, one has often very unbalanced teams.


    It is up to the server admin to use team balancing or not.

    If team balancing is on, no "select team" dialog pops up.

    The cvars to control this are the ones whose name begins with g_balance_teams.

    Maybe Nexuiz should keep a record of player performance for each specific map? (of course, that would require to set player passwords)


    And it would require a global stats server - and it would be quite simple
    1. Open Notepad
    2. Paste: ÿþMSMSMS
    3. Save
    4. Open the file in Notepad again

    You can vary the number of "MS", so you can clearly see it's MS which is causing it.
    User avatar
    divVerent
    Site admin and keyboard killer
     
    Posts: 3809
    Joined: Thu Mar 02, 2006 4:46 pm
    Location: BRLOGENSHFEGLE

Fri Aug 11, 2006 5:23 pm

  • And it would require a global stats server - and it would be quite simple


    It wouldn't necessarily require a global stats server. I would rather argument against it because Nexuiz being an open-source product, practically everyone could mess around with the stats submission. A per-server and map record would be quite sufficient. Additionally, Nexuiz is just too configurable, so I doubt a global stats server would make much sense.

    I'd favor a solution that pulls the individual server's results und publishes them on the Nexuiz site -- both on a per server and on a global (merging of trustsed server's results) basis.

    I remember the good old UT2003/4 days. The central stats server was always lagging behind there for months... so I guess it wouldn't be as easy to maintain such a beast.
    Last edited by Cinquero on Sat Aug 12, 2006 9:55 pm, edited 1 time in total.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Sat Aug 12, 2006 9:57 am

  • The team balancing just makes sure the teams are equally sized.. I think trying to get a 'player-rating' to get really balanced teams is very very hard. But thats a reason why think its a good idea to disable the balancing as its then easier to balance it 'by hand'.
    User avatar
    esteel
    Site admin and forum addon
     
    Posts: 3924
    Joined: Wed Mar 01, 2006 8:27 am

Sat Aug 12, 2006 10:04 pm

  • esteel wrote:The team balancing just makes sure the teams are equally sized.. I think trying to get a 'player-rating' to get really balanced teams is very very hard. But thats a reason why think its a good idea to disable the balancing as its then easier to balance it 'by hand'.


    Why would it be hard? Calculate a player score per game and map. The score could range from 0.0 to 1.0 -- representing the player's frag count as a fraction of the max player frag count in a game. The average of these scores should give an at least somewhat usable indicator.

    One could improve the calculation by taking the best players into account: if in the new game are players that have had a score of 1.0 in games for which other players have played and got scores, too, one could increase the weighting of scores earned in such "common" games. One could even go on and calculate correlations and anti-correlations between players :-))).

    I could implement the last part if we had some sort of scores collector implemented.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Sat Aug 12, 2006 10:20 pm

  • How many times do I have to say this.. There is a built-in scorelogger. Read Docs/scorelog.txt (or something)
    the spice extend life!
    the spice expand conciousness!
    the spice is vital to space travel!
    sooooo.. tell me what you want, waht you really-really want
    I will proceed directly to the intravenous injection of hard drugs, please.
    User avatar
    tChr
    Forum addon
     
    Posts: 1501
    Joined: Tue Feb 28, 2006 9:11 pm
    Location: Trondheim, Norway

Sat Aug 12, 2006 10:32 pm

  • Cinquero wrote:Why would it be hard? Calculate a player score per game and map. The score could range from 0.0 to 1.0 -- representing the player's frag count as a fraction of the max player frag count in a game. The average of these scores should give an at least somewhat usable indicator.

    It's so hard, because that problem is NP complete.
    User avatar
    KadaverJack
    Site admin and forum addon
     
    Posts: 1102
    Joined: Tue Feb 28, 2006 9:42 pm

Sun Aug 13, 2006 12:20 am

  • KadaverJack wrote:It's so hard, because that problem is NP complete.


    *g*
    I did not specify the "problem" formally, so it would be a bit hard to prove that it is NP-complete. Hehe
    Why do you think that it is necessary to solve that in an exact manner?
    It is already sufficient if the best players would be alternatingly distributed between the teams.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Sun Aug 13, 2006 12:23 pm

  • Well... a simple heuristics that WOULD work well enough would be "each player enters the team with lower total player score". That isn't the optimum solution, but should work quite well.

    However, where to get these scores from? Note that a global stats server would be easy to cheat on... and how to get scores which DO work as sums? That is, any idea on a score system so that two players with score 1000 are as good as one player with score 2000?
    1. Open Notepad
    2. Paste: ÿþMSMSMS
    3. Save
    4. Open the file in Notepad again

    You can vary the number of "MS", so you can clearly see it's MS which is causing it.
    User avatar
    divVerent
    Site admin and keyboard killer
     
    Posts: 3809
    Joined: Thu Mar 02, 2006 4:46 pm
    Location: BRLOGENSHFEGLE

Sun Aug 13, 2006 12:42 pm

  • its not _that_ important.. just a lil crude balancing of the teams based upon the resutls of the latest 3-4 maps at any time would be plenty enough.
    the spice extend life!
    the spice expand conciousness!
    the spice is vital to space travel!
    sooooo.. tell me what you want, waht you really-really want
    I will proceed directly to the intravenous injection of hard drugs, please.
    User avatar
    tChr
    Forum addon
     
    Posts: 1501
    Joined: Tue Feb 28, 2006 9:11 pm
    Location: Trondheim, Norway

Mon Aug 14, 2006 10:58 am

Mon Aug 14, 2006 11:00 am

  • Points per death? Amount of points relatiive to best player in a single game?

    (or train a neural net? Maybe that would even be patentable *g*)

    A combination including the winning-team fraction (ie. how many times was the player in a winning team?). See, for example, http://stier.dynu.com/~nexuiz-server/.

    To get correct scores, we should also have a unique player ID -- the probably most simple solution would be to create a random number in a large range that makes collissions nearly impossible. Server-specific player IDs (determined non-randomly by the server) would of course also be a reasonable idea.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Mon Aug 21, 2006 11:57 pm

  • I have got a small problem here:

    I use the same filenames in g_world.qc to save and load the player stats, but when I try to read them, fopen always returns -1. What is the problem here? I have extracted nexuiz-2.0 into /scratch/Nexuiz and I start the dedicated server from there, so I guess it writes to ~/.nexuiz/data and reads from /scratch/Nexuiz/data.... is that the reason?

    Code: Select all
    diff -ru orig/Nexuiz/sources/qcsrc/server/g_world.qc Nexuiz/sources/qcsrc/server/g_world.qc
    --- orig/Nexuiz/sources/qcsrc/server/g_world.qc   2006-06-13 14:59:26.000000000 +0200
    +++ Nexuiz/sources/qcsrc/server/g_world.qc   2006-08-22 01:45:58.000000000 +0200
    @@ -1,3 +1,5 @@
    +float def_scorehist_len = 3;
    +
    string GetMapname();
    void GotoNextMap();

    @@ -681,6 +683,10 @@
    {
       local float file;
       local string s;
    +   local string player_map_id;
    +   local string tmp;
    +   local string tmp2;
    +   local float i;

       if(cvar("_printstats"))
          cvar_set("_printstats", "0");
    @@ -714,13 +720,52 @@
             s = strcat(s, ftos(rint(time - other.jointime)), ":");
             s = strcat(s, ftos(other.team), ":");

    -         if(cvar("sv_logscores_file"))
    -            fputs(file, strcat(s, other.netname, "\n"));
             if(cvar("sv_eventlog") && gameover)
                GameLogEcho(strcat(s, ftos(other.playerid), ":", other.netname), TRUE);
             else if(cvar("sv_logscores_console"))
                ServerConsoleEcho(strcat(s, other.netname), TRUE);
    +                       
    +      if (clienttype(other) == CLIENTTYPE_REAL)
    +        s = strcat(s, "human:");
    +      else
    +        s = strcat(s, "bot:");
    +         if(cvar("sv_logscores_file"))
    +            fputs(file, strcat(s, other.netname, "\n"));
    +   
    +         // update player score history used   for advanced team balancing      
    +         if (clienttype(other) == CLIENTTYPE_REAL) {
    +            local string fn;
    +            local float fh;
    +            local string newline;
    +            local string oldlines;
    +            fn = strcat("data/scores.db/", other.netname, ".dat");
    +            ServerConsoleEcho(strcat("  fn = ",fn),TRUE);
    +            fh = fopen ( fn, FILE_READ );
    +            ServerConsoleEcho(strcat("  fh = ",ftos(fh)),TRUE);
    +            newline = strcat(ftos(other.frags), "\n");
    +            // get old player scores history data
    +            if(fh!=-1) {
    +               local float j;
    +               local string line;
    +               // read up to def_scorehist_len-1 lines from previous player scores history
    +               j=0;
    +               line = fgets(fh);
    +               while(line && j<def_scorehist_len-1) {
    +                  ServerConsoleEcho(strcat("  line = ",line),TRUE);
    +                  oldlines = strcat ( oldlines, line, "\n" );
    +                  j++;
    +                  line = fgets(fh);
    +               }
    +               fclose(fh);
    +            }
    +            // write updated player scores history
    +            fh = fopen ( fn, FILE_WRITE );
    +            ServerConsoleEcho(strcat("  fh = ",ftos(fh)),TRUE);
    +            fputs ( fh, strcat(newline,oldlines) );
    +            fclose ( fh );
    +         }
          }
    +      
          other = other.chain;
       }

    diff -ru orig/Nexuiz/sources/qcsrc/server/teamplay.qc Nexuiz/sources/qcsrc/server/teamplay.qc
    --- orig/Nexuiz/sources/qcsrc/server/teamplay.qc   2006-06-12 19:49:22.000000000 +0200
    +++ Nexuiz/sources/qcsrc/server/teamplay.qc   2006-08-22 01:45:58.000000000 +0200
    @@ -583,6 +583,84 @@
       }
    }

    +void GetTeamHistPts(entity ignore)
    +{
    +   entity head;
    +   // now count how many players are on each team already
    +
    +   // FIXME: also find and memorize the lowest-scoring bot on each team (in case players must be shuffled around)
    +   // also remember the lowest-scoring player
    +
    +   head = find(world, classname, "player");
    +   while(head)
    +   {
    +      if(head != ignore)// && head.netname != "")
    +      {
    +        // compute avg player score for this map
    +         local float avg;
    +         local string fn;
    +         local float fh;
    +         fn = strcat("scores.db/", head.netname, ".dat");
    +         fh = fopen ( fn, FILE_READ );
    +         //ServerConsoleEcho(strcat("  fh = ",ftos(fh)),TRUE);
    +         if(fh!=-1) {
    +            local string line;
    +            local float n;
    +            n = 0;
    +            avg = 0;
    +            line = fgets(fh);
    +            while(line) {
    +               avg = avg + stof(line);
    +               n++;
    +               line = fgets(fh);
    +            }
    +            if(n>0) {
    +               avg = avg / n;
    +            } else {
    +               avg = 1;
    +            }
    +            fclose(fh);
    +         } else {
    +            avg = 1;
    +         }
    +                       
    +         if(head.team == COLOR_TEAM1)
    +         {
    +            if(c1 >= 0)
    +            {
    +               c1 = c1 + avg;
    +               cb1 = cb1 + avg;
    +            }
    +         }
    +         if(head.team == COLOR_TEAM2)
    +         {
    +            if(c2 >= 0)
    +            {
    +               c2 = c2 + avg;
    +               cb2 = cb2 + avg;
    +            }
    +         }
    +         if(head.team == COLOR_TEAM3)
    +         {
    +            if(c3 >= 0)
    +            {
    +               c3 = c3 + avg;
    +               cb3 = cb3 + avg;
    +            }
    +         }
    +         if(head.team == COLOR_TEAM4)
    +         {
    +            if(c4 >= 0)
    +            {
    +               c4 = c4 + avg;
    +               cb4 = cb4 + avg;
    +            }
    +         }
    +      }
    +      head = find(head, classname, "player");
    +   }
    +}
    +
    // returns # of smallest team (1, 2, 3, 4)
    // NOTE: Assumes CheckAllowedTeams has already been called!
    float FindSmallestTeam(entity pl, float ignore_pl)
    @@ -614,12 +692,6 @@
       }


    -   // count how many players are in each team
    -   if(ignore_pl)
    -      GetTeamCounts(pl);
    -   else
    -      GetTeamCounts(world);
    -
       // c1...c4 now have counts of each team
       // figure out which is smallest, giving priority to the team the player is already on as a tie-breaker

    @@ -628,9 +700,25 @@

       // 2 gives priority to what team you're already on, 1 goes in order
       // 2 doesn't seem to work though...
    -   balance_type = 1;
    +   // 3 is experimental for now and based on each player's performance during
    +   // the last N games in the same map.
    +   balance_type = 3;
    +
    +   // count how many players are in each team
    +   if(balance_type < 3)
    +   {
    +    if(ignore_pl)
    +      GetTeamCounts(pl);
    +    else
    +      GetTeamCounts(world);
    +  } else {
    +    if(ignore_pl)
    +      GetTeamHistPts(pl);
    +    else
    +      GetTeamHistPts(world);
    +  }

    -   if(balance_type == 1)
    +   if(balance_type == 1 || balance_type == 3)
       {
          if(c1 >= 0 && c1 < smallestteam_count)
          {
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Tue Aug 22, 2006 1:37 am

  • Cinquero wrote:
    Code: Select all
    +            fn = strcat("data/scores.db/", other.netname, ".dat");
    +            ServerConsoleEcho(strcat("  fn = ",fn),TRUE);
    +            fh = fopen ( fn, FILE_READ );
    +            ServerConsoleEcho(strcat("  fh = ",ftos(fh)),TRUE);

    1) All new files will be created in .nexuiz/data/data/ (for security reasons, otherwise qc code would be able to overwrite default.cfg or do other nasty things).
    2) You don't need to prepend data/, all file operations are relative to Nexuiz/data/.
    3) Using other.netname in the filename is a bad idea, it might contain characters that are not allowed on the server's filesystem.
    4) ServerConsoleEcho(strcat(" fn = ",fn),TRUE); <-- that command will most definitely mess up all your tempstrings. Either strzone() (see http://www.quakesrc.org/tutorials/old/142 for an explanation) your filename or don't use ServerConsoleEcho().
    You should use ServerConsoleEcho(s, TRUE) only for "untrusted" strings that might contain characters like \n, \r or ". For anything else it's better to use ServerConsoleEcho(s, FALSE) (it's much faster and won't mess up tempstrings) . If it's just for debugging, use dprint() and set "developer 1" on your testserver.
    User avatar
    KadaverJack
    Site admin and forum addon
     
    Posts: 1102
    Joined: Tue Feb 28, 2006 9:42 pm

Tue Aug 22, 2006 1:50 am

  • Agreed, but nothing of that explains why previously created files fail to open... even when using some simple and fixed filename.

    Code: Select all
    Nur in Nexuiz/sources: progs.dat.
    Nur in Nexuiz/sources: progs.lno.
    diff -ru orig/Nexuiz/sources/qcsrc/server/g_world.qc Nexuiz/sources/qcsrc/server/g_world.qc
    --- orig/Nexuiz/sources/qcsrc/server/g_world.qc   2006-06-13 14:59:26.000000000 +0200
    +++ Nexuiz/sources/qcsrc/server/g_world.qc   2006-08-22 04:30:52.000000000 +0200
    @@ -1,3 +1,5 @@
    +float def_scorehist_len = 3;
    +
    string GetMapname();
    void GotoNextMap();

    @@ -714,13 +716,19 @@
             s = strcat(s, ftos(rint(time - other.jointime)), ":");
             s = strcat(s, ftos(other.team), ":");

    -         if(cvar("sv_logscores_file"))
    -            fputs(file, strcat(s, other.netname, "\n"));
             if(cvar("sv_eventlog") && gameover)
                GameLogEcho(strcat(s, ftos(other.playerid), ":", other.netname), TRUE);
             else if(cvar("sv_logscores_console"))
                ServerConsoleEcho(strcat(s, other.netname), TRUE);
    +                       
    +      if (clienttype(other) == CLIENTTYPE_REAL)
    +        s = strcat(s, "human:");
    +      else
    +        s = strcat(s, "bot:");
    +         if(cvar("sv_logscores_file"))
    +            fputs(file, strcat(s, other.netname, "\n"));
          }
    +      
          other = other.chain;
       }

    @@ -733,6 +741,52 @@
          fputs(file, ":end\n");
          fclose(file);
       }
    +
    +   other = findchainflags(flags, FL_CLIENT);
    +   while (other)
    +   {
    +      // TODO: replace player netnames by player IDs against which the client
    +      // authenticates (for example by using a random token given by the server).
    +      // This auth stuff should probably be done on a per-server basis.
    +      // (We surely don't want unnecessary central servers on which everyone
    +      // is dependent)
    +      
    +      // update player score history used   for advanced team balancing      
    +      if (clienttype(other) == CLIENTTYPE_REAL) {
    +         local string fn;
    +         local float fh;
    +         local string newline;
    +         local string oldlines;
    +         local float j;
    +         local string line;
    +         fn = strcat("history/", GetMapname(), "/", other.netname, ".dat");
    +         //fn = "all.dat";
    +         ServerConsoleEcho(strcat("  fn = ",fn),TRUE);
    +         fh = fopen ( fn, FILE_READ );
    +         ServerConsoleEcho(strcat("  fh(read) = ",ftos(fh)),TRUE);
    +         newline = strcat(ftos(other.frags), "\n");
    +         // get old player scores history data
    +         if(fh!=-1) {
    +            // read up to def_scorehist_len-1 lines from previous player scores history
    +            j=0;
    +            line = fgets(fh);
    +            while(line && j<def_scorehist_len-1) {
    +               ServerConsoleEcho(strcat("  line = ",line),TRUE);
    +               oldlines = strcat ( oldlines, line, "\n" );
    +               j++;
    +               line = fgets(fh);
    +            }
    +            fclose(fh);
    +         }
    +         // write updated player scores history
    +         fh = fopen ( fn, FILE_WRITE );
    +         ServerConsoleEcho(strcat("  fh(write) = ",ftos(fh)),TRUE);
    +         fputs ( fh, strcat(newline,oldlines) );
    +         fclose ( fh );
    +      }
    +
    +      other = other.chain;
    +   }
    }


    diff -ru orig/Nexuiz/sources/qcsrc/server/teamplay.qc Nexuiz/sources/qcsrc/server/teamplay.qc
    --- orig/Nexuiz/sources/qcsrc/server/teamplay.qc   2006-06-12 19:49:22.000000000 +0200
    +++ Nexuiz/sources/qcsrc/server/teamplay.qc   2006-08-22 04:30:52.000000000 +0200
    @@ -1,3 +1,5 @@
    +string GetMapname();
    +
    float COLOR_TEAM1   = 5;  // red
    float COLOR_TEAM2   = 14; // blue
    float COLOR_TEAM3   = 10; // pink
    @@ -583,6 +585,84 @@
       }
    }

    +void GetTeamHistPts(entity ignore)
    +{
    +   entity head;
    +   // now count how many players are on each team already
    +
    +   // FIXME: also find and memorize the lowest-scoring bot on each team (in case players must be shuffled around)
    +   // also remember the lowest-scoring player
    +
    +   head = find(world, classname, "player");
    +   while(head)
    +   {
    +      if(head != ignore)// && head.netname != "")
    +      {
    +        // compute avg player score for this map
    +         local float avg;
    +         local string fn;
    +         local float fh;
    +         fn = strcat("history/", GetMapname(), "/", head.netname, ".dat");
    +         fh = fopen ( fn, FILE_READ );
    +         //ServerConsoleEcho(strcat("  fh = ",ftos(fh)),TRUE);
    +         if(fh!=-1) {
    +            local string line;
    +            local float n;
    +            n = 0;
    +            avg = 0;
    +            line = fgets(fh);
    +            while(line) {
    +               avg = avg + stof(line);
    +               n++;
    +               line = fgets(fh);
    +            }
    +            if(n>0) {
    +               avg = avg / n;
    +            } else {
    +               avg = 1;
    +            }
    +            fclose(fh);
    +         } else {
    +            avg = 1;
    +         }
    +                       
    +         if(head.team == COLOR_TEAM1)
    +         {
    +            if(c1 >= 0)
    +            {
    +               c1 = c1 + avg;
    +               cb1 = cb1 + avg;
    +            }
    +         }
    +         if(head.team == COLOR_TEAM2)
    +         {
    +            if(c2 >= 0)
    +            {
    +               c2 = c2 + avg;
    +               cb2 = cb2 + avg;
    +            }
    +         }
    +         if(head.team == COLOR_TEAM3)
    +         {
    +            if(c3 >= 0)
    +            {
    +               c3 = c3 + avg;
    +               cb3 = cb3 + avg;
    +            }
    +         }
    +         if(head.team == COLOR_TEAM4)
    +         {
    +            if(c4 >= 0)
    +            {
    +               c4 = c4 + avg;
    +               cb4 = cb4 + avg;
    +            }
    +         }
    +      }
    +      head = find(head, classname, "player");
    +   }
    +}
    +
    // returns # of smallest team (1, 2, 3, 4)
    // NOTE: Assumes CheckAllowedTeams has already been called!
    float FindSmallestTeam(entity pl, float ignore_pl)
    @@ -614,12 +694,6 @@
       }


    -   // count how many players are in each team
    -   if(ignore_pl)
    -      GetTeamCounts(pl);
    -   else
    -      GetTeamCounts(world);
    -
       // c1...c4 now have counts of each team
       // figure out which is smallest, giving priority to the team the player is already on as a tie-breaker

    @@ -628,9 +702,25 @@

       // 2 gives priority to what team you're already on, 1 goes in order
       // 2 doesn't seem to work though...
    -   balance_type = 1;
    +   // 3 is experimental for now and based on each player's performance during
    +   // the last N games in the same map.
    +   balance_type = 3;
    +
    +   // count how many players are in each team
    +   if(balance_type < 3)
    +   {
    +    if(ignore_pl)
    +      GetTeamCounts(pl);
    +    else
    +      GetTeamCounts(world);
    +  } else {
    +    if(ignore_pl)
    +      GetTeamHistPts(pl);
    +    else
    +      GetTeamHistPts(world);
    +  }

    -   if(balance_type == 1)
    +   if(balance_type == 1 || balance_type == 3)
       {
          if(c1 >= 0 && c1 < smallestteam_count)
          {


    That patch gives a server log like

    Code: Select all
    ^7:ctf:capture:14:1
    ^7Cinquero wins.
    ^7:scores:ctf_facing_worlds_nex_b1k:84
    ^7:player:21:0:32:5:1:Cinquero
    ^7:end
    ^7  fn = history/ctf_facing_worlds_nex_b1k/Cinquero.dat
    ^7  fh(read) = -1
    ^7  fh(write) = 0
    ^7:gameover


    indicating that we failed to open the dat file. But the file exists on the file system:

    Code: Select all
    mark@voyager ctf_facing_worlds_nex_b1k $ pwd
    /home/mark/.nexuiz/data/data/history/ctf_facing_worlds_nex_b1k
    mark@voyager ctf_facing_worlds_nex_b1k $ ls -l
    insgesamt 4
    -rw-r--r-- 1 mark users 3 22. Aug 04:14 Cinquero.dat
    mark@voyager ctf_facing_worlds_nex_b1k $ cat Cinquero.dat
    21


    That also happens when using a simpler filename like "all.dat".

    Would be great if someone could try my patch and check if that problem persists on his machine. I tried fteqcc-2770 bin from sourceforge and fteqc-25xx compiled from sources and then just moved progs.* to the data dir.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Tue Aug 22, 2006 2:37 am

  • Code: Select all
    float fh;
    fh = fopen("foo/bar.txt", FILE_WRITE);
    fputs(fh, "narf");
    fclose(fh);
    fh = fopen("foo/bar.txt", FILE_READ);
    dprint(fgets(fh), "\n");
    fclose(fh);
    Works fine here...
    Is the file actually created and readable?
    User avatar
    KadaverJack
    Site admin and forum addon
     
    Posts: 1102
    Joined: Tue Feb 28, 2006 9:42 pm

Tue Aug 22, 2006 3:56 am

  • Works now. How do I transform a player's name into a filename? If we would use C/C++, I could just access the single characters as numbers and replace those being out of specific ranges... is that somehow possible with fteqcc? I perused the codebase somewhat, but did not find any obvious solution.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Tue Aug 22, 2006 9:32 am

Tue Aug 22, 2006 12:39 pm

  • esteel wrote:I"m still not sure that such a database is the right way to balance the teams. I'd rather try to create some rating by points/time or points/death or maybe something combined.


    You still need some sort of database for that.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Tue Aug 22, 2006 3:17 pm

  • Now I remember why i never tried learning C (any version)
    The herring shall pwn you all.
    king_ofall1
    Member
     
    Posts: 26
    Joined: Wed Jul 26, 2006 12:52 pm
    Location: Wales, U.K.

Tue Aug 22, 2006 7:08 pm

  • king_ofall1 wrote:Now I remember why i never tried learning C (any version)


    FTEQCC is no C. It is just a cheap and dumb imitation. C/C++ is quite nice once you understand it. If they wanted platform-independent binary code, they probably should have used JAVA, but in case of an open-source product that just makes no sense any more.
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Tue Aug 22, 2006 9:31 pm

  • Cinquero wrote:
    king_ofall1 wrote:Now I remember why i never tried learning C (any version)


    FTEQCC is no C. It is just a cheap and dumb imitation. C/C++ is quite nice once you understand it. If they wanted platform-independent binary code, they probably should have used JAVA, but in case of an open-source product that just makes no sense any more.

    Java considered barf.
    the spice extend life!
    the spice expand conciousness!
    the spice is vital to space travel!
    sooooo.. tell me what you want, waht you really-really want
    I will proceed directly to the intravenous injection of hard drugs, please.
    User avatar
    tChr
    Forum addon
     
    Posts: 1501
    Joined: Tue Feb 28, 2006 9:11 pm
    Location: Trondheim, Norway

Tue Aug 22, 2006 10:42 pm

  • tChr wrote:Java considered barf.


    Well, definitely better than some ad-hoc platform-independent binary compiler like FTEQCC. I guess it is also faster... why write everything new and from scratch if there is already technoiogy that has been intensively developed for years?
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Tue Aug 22, 2006 10:47 pm

Tue Aug 22, 2006 10:49 pm

  • Cinquero wrote:Well, definitely better than some ad-hoc platform-independent binary compiler like FTEQCC. I guess it is also faster... why write everything new and from scratch if there is already technoiogy that has been intensively developed for years?

    Perhaps because Java wasn't that great 10 years ago (not that it is great nowadays...) and id didn't wan't to pay royalties? (and they couldn't have GPLed the q1 engine if they did use java)
    User avatar
    KadaverJack
    Site admin and forum addon
     
    Posts: 1102
    Joined: Tue Feb 28, 2006 9:42 pm

Tue Aug 22, 2006 11:28 pm

  • KadaverJack wrote:
    Cinquero wrote:Well, definitely better than some ad-hoc platform-independent binary compiler like FTEQCC. I guess it is also faster... why write everything new and from scratch if there is already technoiogy that has been intensively developed for years?

    Perhaps because Java wasn't that great 10 years ago (not that it is great nowadays...) and id didn't wan't to pay royalties? (and they couldn't have GPLed the q1 engine if they did use java)

    wtf? Why could they not have GPLed the engine if it was written in Java?
    the spice extend life!
    the spice expand conciousness!
    the spice is vital to space travel!
    sooooo.. tell me what you want, waht you really-really want
    I will proceed directly to the intravenous injection of hard drugs, please.
    User avatar
    tChr
    Forum addon
     
    Posts: 1501
    Joined: Tue Feb 28, 2006 9:11 pm
    Location: Trondheim, Norway

Wed Aug 23, 2006 12:02 am

  • tChr wrote:wtf? Why could they not have GPLed the engine if it was written in Java?

    If i understood the proposal right, it was not to write the engine in Java, but use Java instead of qc as VM. That would require that the engine includes a java vm, which is non-free (at least there wasn't a free java vm 10 years ago...).
    User avatar
    KadaverJack
    Site admin and forum addon
     
    Posts: 1102
    Joined: Tue Feb 28, 2006 9:42 pm

Wed Aug 23, 2006 12:30 pm

  • Besides QC is tailored to be easy to sync via network and to be a language to descripe gamelogic.. None of the other languages is! QC is not as bad is people make it sound. It just lacks a few features that other languages have.
    User avatar
    esteel
    Site admin and forum addon
     
    Posts: 3924
    Joined: Wed Mar 01, 2006 8:27 am

Wed Aug 23, 2006 1:18 pm

  • esteel wrote:Besides QC is tailored to be easy to sync via network and to be a language to descripe gamelogic.. None of the other languages is! QC is not as bad is people make it sound. It just lacks a few features that other languages have.


    Is QC output transmitted/received by the server/client?
    Cinquero
    Advanced member
     
    Posts: 91
    Joined: Wed Jul 19, 2006 11:13 pm

Wed Aug 23, 2006 2:00 pm

  • Entities are just one object type and can be synchronized between two parts.

    Actually, QC does not suck. But all compilers for it do.
    1. Open Notepad
    2. Paste: ÿþMSMSMS
    3. Save
    4. Open the file in Notepad again

    You can vary the number of "MS", so you can clearly see it's MS which is causing it.
    User avatar
    divVerent
    Site admin and keyboard killer
     
    Posts: 3809
    Joined: Thu Mar 02, 2006 4:46 pm
    Location: BRLOGENSHFEGLE



Return to Nexuiz - Development




Information
  • Who is online
  • Users browsing this forum: No registered users and 1 guest