Yeah, the file creates and its name is my guid...
Yeah, the file creates and its name is my guid...
EvoloZz (10th February 2013),kung foo man (10th February 2013)
Ok, I found out what the problem is - once a file has been created using the "write" function, it wont update. So, you are fine entering data into file the very first time. After that, it simply doesn't update any more. So, you have to use the "append" function, and read the data back from that basis.
Here is what I have:
I was using a simple player name for the data file name, but obviously you simply replace that with a more robust player GUID name (although I would shorten the file name to the last 8 digits).Code:onPlayerConnect() { // initialize the player kills flag if( getPlayerKills() ) self.pers["kills"] = self.kills; else self.pers["kills"] = 0; } onPlayerKilled() { attacker.pers["score"]++; attacker.score = attacker.pers["score"]; // update the player kills flag along with player score attacker.pers["kills"]++; // save the new player kills value attacker thread saveKills(); } saveKills() { filename = self.name + ".txt"; filehandle = openfile( filename, "append" ); if( filehandle != -1 ) { value = ""; if( value != "" ) value += " "; value += self.pers["kills"]; fprintln( filehandle, value ); closefile( filehandle ); } } getPlayerKills() { filename = self.name + ".txt"; file = OpenFile( filename, "read" ); if( file == -1 ) return( false ); for( ;; ) { elems = freadln( file ); if( elems == -1 ) break; if( elems == 0 ) continue; line = ""; for( pos = 0; pos < elems; pos++ ) { line = line + fgetarg( file, pos ); if( pos < elems - 1 ) line = line + ","; } array = strtok( line, "," ); self.kills = array.size; } CloseFile( file ); return( true ); }
I didn't do anything with a HUD element showing these values. I will take it that aspect of the thing can be easily created yourself.
EvoloZz (10th February 2013),kung foo man (10th February 2013)
Thanks alot for helping me and sorry for wasting your time, but that did not fix the problem... the error is still exactly same...
I couldn't make a video about it because it would take ages to upload it to xfire, but i hope a screenshot is enough
The hud elem is still exactly the same:
Code:kills() { self endon("joined_spectators"); self endon("disconnect"); if(!isDefined(self.killhud)) { self.killhud = newClientHudElem(self); self.killhud.vertAlign = "fullscreen"; self.killhud.horzAlign = "fullscreen"; self.killhud.alignX = "left"; self.killhud.alignY = "middle"; self.killhud.x = 25; self.killhud.y = 474; self.killhud.sort = 1; self.killhud.alpha = 1; self.killhud.fontScale = 0.8; self.killhud.archived = true; self.killhud.label = (game["ratio"]); self.killhud setValue(self.kills); } }
Last edited by EvoloZz; 10th February 2013 at 17:29.
I got it to work with the file function, no problem at all:
Hud:
File functions:Code:init() { game["ratio"] = &"DEMON_TEST"; precacheString( game["ratio"] ); level thread onPlayerConnect(); } onPlayerConnect() { for( ;; ) { level waittill( "connected", player ); player thread onPlayerSpawned(); player thread onPlayerKilled(); } } onPlayerSpawned() { self endon( "disconnect" ); for( ;; ) { self waittill( "spawned_player" ); self thread ratio(); } } onPlayerKilled() { self endon( "disconnect" ); for( ;; ) { self waittill( "killed_player" ); if( isDefined( self.ratiohud ) ) self.ratiohud destroy(); } } ratio() { self endon( "killed_player" ); self endon( "disconnect" ); if( isDefined( self.ratiohud ) ) self.ratiohud destroy(); if( !isDefined( self.ratiohud ) ) { self.ratiohud = newClientHudElem( self ); self.ratiohud.vertAlign = "fullscreen"; self.ratiohud.horzAlign = "fullscreen"; self.ratiohud.alignX = "left"; self.ratiohud.alignY = "middle"; self.ratiohud.x = 25; self.ratiohud.y = 474; self.ratiohud.sort = 1; self.ratiohud.alpha = 1; self.ratiohud.fontScale = 0.8; self.ratiohud.archived = true; self.ratiohud.label = (game["ratio"]); } self thread UpdateHud(); } UpdateHud() { value = int( self.pers["kills"] ); if( isDefined( self.ratiohud ) ) self.ratiohud setValue( value ); }
From within the gametype file:Code:onPlayerConnect() { // initialize the player kills flag if( getPlayerKills() ) self.pers["kills"] = self.kills; else self.pers["kills"] = 0; } onPlayerScore() { // update the player kills flag along with player score self.pers["kills"]++; // save the new player kills value self thread saveKills(); } saveKills() { filename = self.name + ".txt"; filehandle = openfile( filename, "append" ); if( filehandle != -1 ) { value = ""; if( value != "" ) value += " "; value += self.pers["kills"]; fprintln( filehandle, value ); closefile( filehandle ); } self thread demon\_playerhud::UpdateHud(); } getPlayerKills() { filename = self.name + ".txt"; file = OpenFile( filename, "read" ); if( file == -1 ) return( false ); for( ;; ) { elems = freadln( file ); if( elems == -1 ) break; if( elems == 0 ) continue; line = ""; for( pos = 0; pos < elems; pos++ ) { line = line + fgetarg( file, pos ); if( pos < elems - 1 ) line = line + ","; } array = strtok( line, "," ); self.kills = array.size; } CloseFile( file ); return( true ); }
Code:Callback_PlayerConnect() { self demon\_playerdata::onPlayerConnect(); }No errors at all.Code:Callback_PlayerKilled() { attacker.pers["score"]++; attacker.score = attacker.pers["score"]; attacker thread demon\_playerdata::onPlayerScore(); }
EvoloZz (11th February 2013),kung foo man (10th February 2013)
I wasn't happy with the above attempt because it was clumsy and updated the data file every single kill. As the data file is appended, it would eventually become very large, very quickly. So, I worked on a way to update the data file either when the player disconnects, or at the end of a match/game. That would mean much less appending to the file, and thus much smaller in size. This is what I have now:
File Function:
Player Hud:Code:init() { level thread onPlayerConnect(); level thread onGameEnd(); } onPlayerConnect() { for( ;; ) { level waittill( "connected", player ); // initialize the player kills flag if( player getPlayerKills() ) player.pers["kills"] = player.kills; else player.pers["kills"] = 0; } } onGameEnd() { for( ;; ) { level waittill( "intermission" ); players = getentarray( "player", "classname" ); for(i = 0; i < players.size; i++) { player = players[i]; player thread saveKills( player.pers["kills"] ); } } } onPlayerScore() { // update the player kills flag self.pers["kills"]++; self thread demon\_playerhud::UpdateHud(); } saveKills( kills ) { filename = self.name + ".txt"; filehandle = openfile( filename, "append" ); if( filehandle != -1 ) { fprintln( filehandle, kills ); closefile( filehandle ); } } getPlayerKills() { filename = self.name + ".txt"; file = OpenFile( filename, "read" ); if( file == -1 ) return( false ); for( ;; ) { elems = freadln( file ); if( elems == -1 ) break; if( elems == 0 ) continue; line = ""; for( pos = 0; pos < elems; pos++ ) { line = line + fgetarg( file, pos ); if( pos < elems - 1 ) line = line + ","; } array = strtok( line, "," ); for( i=0; i < array.size; i++ ) self.kills = int( array[i] ); } CloseFile( file ); return( true ); }
There are 2 callbacks in the gametype files:Code:init() { game["ratio"] = &"DEMON_TEST"; precacheString( game["ratio"] ); level thread onPlayerConnect(); } onPlayerConnect() { for( ;; ) { level waittill( "connected", player ); player thread onPlayerSpawned(); player thread onPlayerKilled(); } } onPlayerSpawned() { self endon( "disconnect" ); for( ;; ) { self waittill( "spawned_player" ); self thread ratio(); } } onPlayerKilled() { self endon( "disconnect" ); for( ;; ) { self waittill( "killed_player" ); if( isDefined( self.ratiohud ) ) self.ratiohud destroy(); } } ratio() { self endon( "killed_player" ); self endon( "disconnect" ); if( isDefined( self.ratiohud ) ) self.ratiohud destroy(); if( !isDefined( self.ratiohud ) ) { self.ratiohud = newClientHudElem( self ); self.ratiohud.vertAlign = "fullscreen"; self.ratiohud.horzAlign = "fullscreen"; self.ratiohud.alignX = "left"; self.ratiohud.alignY = "middle"; self.ratiohud.x = 25; self.ratiohud.y = 474; self.ratiohud.sort = 1; self.ratiohud.alpha = 1; self.ratiohud.fontScale = 0.8; self.ratiohud.archived = true; self.ratiohud.label = (game["ratio"]); } self thread UpdateHud(); } UpdateHud() { if( isDefined( self.ratiohud ) ) self.ratiohud setValue( self.pers["kills"] ); }
Code:Callback_PlayerDisconnect() { iprintln( &"MP_DISCONNECTED", self ); self thread demon\_playerdata::saveKills( self.pers["kills"] ); }I've never worked much with the "write" file function. I've always only really used the "read" function. It was an interesting, if somewhat frustrating, experience. I never knew that a data file will not overwrite itself when the "write" function is used. Now, to work out how to create a new line using "append". If anyone knows how, you can perhaps share and save me some experimentation time.Code:Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ) { attacker thread demon\_playerdata::onPlayerScore(); }
Last edited by Tally; 10th February 2013 at 23:27.
if you just call "write" on a file, then close it again, it will be empty. Comes in handy when trying to prevent files from getting larger.
Also, here is my account system, use it for inspiration:
http://codepad.org/vdQM3aAj
EvoloZz (11th February 2013),kung foo man (11th February 2013)
Finally I got it to work, thanks a lot everyone for helping me out. The main problem (type undefined is not an int) was already fixed by Tally in an earlier post, but the same error came because of the bots (I forgot that their guid is always 0 ), so i made the script compatible for bots also, and now there ain't any problems no more, big thanks to you guys again!