EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Archive::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=621)
-   -   Random fixes (https://www.eqemulator.org/forums/showthread.php?t=15117)

Branks 09-03-2004 12:18 PM

oh sweet im excited to see what you guys came up with, i kinda gave up on the current timers also since the more i looked into it the more it seems to be a simple rapid recast prevention thing than an actual timer, one of you two please say yalls system allows reenabling the button server side. currently the client does timers on its own to reenable the buttons which id like to have adjustable by the server op if possible. also monalin from what ive seen the timers in the DB arent meant to change constantly their simply there to check if current time hasnt passed the time when the timer was supposed to expire however the current system also only checks during zone changes. and fathernitwit would you mind filling me in on how much of this is broken in 5.8? im rather curious and just want a simple answer like "little different" or "omg start over" although i dont see how much of it can be broken other than actually recognizing an AA activation request, anyway thats just something ive been wondering about and one of the reasons i asked about the jr dev thing. anyway thanks again for work with the timers! guess ill spend the night playing with the monk AE attack skill as that one sounds kinda challenging.

also either of you happen to have a link to a decent code optimization tutorial or anything as i think i know enough to start working on good habbits and i still get nervous about tampering with the constantly run processes.

monalin crusader 09-03-2004 12:42 PM

Ok finnaly heres the source code.

client_process.cpp line 5251

before // try to send all packets that weren't send before
add

Code:

                database.UpdateTimersClientConnected(CharacterID());
database.h line 124
add

Code:

        bool    AATimerTest(int32 charid, int32 ability);
database.cpp line 2213

after #ifdef ZONE
add

Code:

bool Database::AATimerTest(int32 charid, int32 ability){
        char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
        MYSQL_ROW row;
       
        if (RunQuery(query, MakeAnyLenString(&query, "SELECT begin-end from aa_timers WHERE charid=%i AND ability=%i", charid, ability), errbuf, &result)) {
                while( ( row = mysql_fetch_row(result) ) ){

                        LogFile->write(EQEMuLog::Error, "Database::AATimerTest begin-end=%i for ability: %i and charid: %i",atoi(row[0]),ability,charid);

                        if(atoi(row[0]) >= 0){
                                LogFile->write(EQEMuLog::Error, "Database::AATimerTest begin <= end");
                                return false;
                        }
                        else{
                                return true;
                                LogFile->write(EQEMuLog::Error, "Database::AATimerTest begin >= end");
                        }

                }
                mysql_free_result(result);
        }
        else
                LogFile->write(EQEMuLog::Error, "Database::AATimerTest query '%s' %s", query, errbuf);       

        safe_delete_array(query);
}

and right before that function
where it has

void Database::UpdateTimersClientConnected(int32 charid)

change that function to

Code:

void Database::UpdateTimersClientConnected(int32 charid){
        char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
        if (!RunQuery(query, MakeAnyLenString(&query, "update aa_timers set begin=UNIX_TIMESTAMP(now()) where charid=%i",charid), errbuf)) {
                LogFile->write(EQEMuLog::Error, "UpdateAATimers query '%s' %s", query, errbuf);
        }
        safe_delete_array(query);
}

client.cpp line 3271

after int targ;
add

Code:

if(database.AATimerTest(CastToClient()->character_id,activate) == 0){
client.cpp line 4955 (about)

after safe_delete(outapp);
add

Code:

  }
  else
        CastToClient()->Message(0,"You cannot cast this spell at this time.");

And i think thats about it i might have forgotten something i dont think i did let me know if it works for you guys too i've tested it on my server and it works so if it doesnt work on yours.

if(code != "works)"{
Message(1,"I probly forgot something.");
}
else if (code == "works"){
Message(1,"enjoy ");
}

and branks
Quote:

also either of you happen to have a link to a decent code optimization tutorial or anything as i think i know enough to start working on good habbits and i still get nervous about tampering with the constantly run processes.
I dont know, i'm 17 and i taught myself everything i know. I believe you might be able to edit the aa timers in game by just messing with the db a little i'm not sure how it works i can look into it i hadent really thought of changing it much but i dont think it would be impossible.

**EDIT** dont emptry your aa_timers table it bugs you, also the errors you get in zone.exe mean nothign they're for me to debugg.

**EDIT** UPDATE THIS PLEASE

new AATimerTest function should be

Code:

bool Database::AATimerTest(int32 charid, int32 ability){
        char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
        MYSQL_ROW row;
       
        if (RunQuery(query, MakeAnyLenString(&query, "SELECT begin-end from aa_timers WHERE charid=%i AND ability=%i", charid, ability), errbuf, &result)) {
                while( ( row = mysql_fetch_row(result) ) ){

                        LogFile->write(EQEMuLog::Error, "Database::AATimerTest begin-end=%i for ability: %i and charid: %i",atoi(row[0]),ability,charid);

                        if(atoi(row[0]) >= 0){
                                LogFile->write(EQEMuLog::Error, "Database::AATimerTest begin <= end");
                                return false;
                        }
                        else if(row[0] == "NULL"){
                                time_t timestamp=time(NULL);
                                UpdateAATimers(charid,timestamp,timestamp,ability);
                                return true;
                        }
                        else{
                                LogFile->write(EQEMuLog::Error, "Database::AATimerTest begin >= end");
                        }

                }
                mysql_free_result(result);
        }
        else{
      LogFile->write(EQEMuLog::Error, "Database::AATimerTest query '%s' %s", query, errbuf);   
          }

        safe_delete_array(query);
}

it was found to be not adding new timers under certian conditions, with the help of Branks we came up with this it solved his problem he created when he emptied his aa_timer table.

Branks 09-03-2004 02:10 PM

worked out great! but... i was getting one of the errors from it although it was working fine so i decided maybe it didnt like the current numbers that were in the DB so i emptied my aa_timers table and then nothing worked, so it needs a function to handle if there is no table currntly there. working on this now and still trying to track down how to reenable the button when the timer expires.

edit: monalin just noticed the last part, the timers are easily changed they are set in client.cpp above and below the code you added, its the timermod which is in each case, their in seconds. and im self taught also and slowly getting better. also what i meant about the reuse thing was that id like to trackdown whatever it is thats sent to the client to let the client know the skill is avaliable, instead of the button appearing gray while its actually useable, this happens during zoneing currently but not without so its in here somewhere...

monalin crusader 09-03-2004 02:15 PM

Oh, explain please i'm confused that shouldnt be causing problems since i just created a new character and when i did that it added the values to db just as if it had been blank. It shouldnt be causing any problems. Maybe i forgot to add something in there, did u just empty it or did u delete it, and what errors are you getting.

Oh and the errors are just in there because, u can remove them really i had that in there when i was trying to find out what the hell was going on with the aa_timers table. Those Errors really mean nothing just lets me know what was commingo ut of hte function when i would call it.

Quote:

also what i meant about the reuse thing was that id like to trackdown whatever it is thats sent to the client to let the client know the skill is avaliable, instead of the button appearing gray while its actually useable, this happens during zoneing currently but not without so its in here somewhere...
They had it updateing the database only when it zoned they put the UpdateTimersClientConnected(charid) in wrong place it was only getting called on login or zone.

Branks 09-03-2004 02:20 PM

uh it kept saying begin <= end in the zone window which i assumed it shouldnt have been so i emptied the aa_timers table and rebooted the server.

and since then it wont work im playing with it now though, it may have been some of my other code that caused this as i have a lot thats not posted im playing with.

fathernitwit 09-03-2004 05:31 PM

alright, if your interested... heres my persistent timers:
http://eqemu.psend.com/files/ptimers.diff

apply on unix with patch -p0 <ptimers.diff from the source root.

This is basically an implementation of the Timer class, but is persistent on a per-client basis. You just have to give each timer type a unique type number... I show an example of this with AA_number... assuming that it is 0 <= AA_number <= 120... if this is not true, if there is a bigger range of AA IDs, then we can adjust the range in the header... it isnt a big deal.

heres some example code:
Code:


Client::something() {
  p_timers.Start(pTimerAAStart + AA_number, duration_in_sec);

  if(p_timers.Check(pTimerAAStart + AA_number, false)) {
    //timer expired, use the AA
  } else {
    //timer not expired...
  }
}

if your not in the Client:: scope, but you have a client ptr, use:
Client *c;
...
c->GetPTimers().Start(....)

heres my little writeup about them:
Code:

Persistent timers, By Father Nitwit

The idea of persistent timers is timers which follow a player
through zoning. You use operations on them much like regular
timers: Start, Check, Clear but they also provide methods
to store them in the DB: Load and Store.

Each persistent timer is attached to a character, and given
a specific type. A given character can only have one timer
of each type. While the type is just an arbitrary number,
please record what you are using it for in the enum for
pTimerType at the top of ptimer.h, and give it a UNIQUE number.

There should be little need to directly access ptimers. Each
client has a facility called p_timers which should handle
most of what you need. The idea is that instead of making
your own PersistentTimer, you use the methods on p_timers:
Start, Check, Clear, GetRemainingTime to access them. You
starting a timer which does not exist will create it. If
you need to do more than that with your timer, you should
still use p_timers, just use the Get() method to get direct
access to the PersistentTimer. All timers in the p_timers
list will automatically be loaded and stored to the database.
You should never need to call any Load or Store methods.

To get to p_timers when you are not in the Client:: scope,
use client->GetPTimers(). to access timers.

To use ptimers, you need to create the table below in your DB:

Schema:

CREATE TABLE timers (
        char_id INT(11) NOT NULL,
        type MEDIUMINT UNSIGNED NOT NULL,
        start INT UNSIGNED NOT NULL,
        duration INT UNSIGNED NOT NULL,
        enable TINYINT NOT NULL,
        PRIMARY KEY(char_id, type)
);


cavedude 09-04-2004 02:08 PM

I guess this is where I should put this... Just a heads up ptimer.h and cpp weren't added to the zone's common files list in the anon CVS build that is up.


All times are GMT -4. The time now is 12:42 PM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.