Textdraws and timers not working
#1

Hey, I have a problem (well, not me, but friend).
So I have a script, and I tested it with ~5 different accounts, its all ok for others, but for my friend, when he joins, some textdraws begins to bug, they don't show up, and timers fk up. Is it something with my script or something bad with his SA:MP or san andreas?
Thanks
Reply
#2

Can you show the script for textdraw and timers?
Make sure the textdraw is player textdraw.
Reply
#3

You're probably having the classic ID problem. Can happen to anything that uses an ID - timers, textdraws, even players. This is because if you don't reset a variable that stores an ID after the ID is used, if another timer/player/textdraw etc. takes up that ID, you will be affecting that one, not the old one that doesn't exist any more.

FOr example, lets say you have timer1 and timer2. You start timer1 and assign it to a variable. It is ID 0. The timer gets killed. You start timer2 and store its ID in a different variable. It takes the old ID of timer1, which is 0. But 'timer1' is still ID 0. If you kill timer1 (which no longer exists), it will kill timer2.

Say you have this script:

pawn Код:
new ExampleTimer[MAX_PLAYERS]; // By default all values are 0

public OnPlayerDisconnect(playerid, reason)
{
    KillTimer(ExampleTimer[playerid]);
    return 1;
}
If 'ExampleTimer[playerid]' was never assigned to a timer, it will still be 0. You'll then be killing timer ID 0 when anyone disconnects. That's going to kill the timer with ID 0, which is most likely your 'main timer'. You need to initialise values to -1 like so:

pawn Код:
new ExampleTimer[MAX_PLAYERS] = {-1, ...}; // All values will be -1
That way, if the timer is never used, timer ID 0 won't be killed by mistake.

Alternatively, you could just use up ID 0 by setting a random timer and never using it, but that's not the 'right' way to do it. With this method, you can also detect whether a timer is running or not.

It is just as (or more) important to also set the timer IDs to -1 when they are killed or called, for example:

First, declare the timer ID variables and initialize them to -1
pawn Код:
new ExampleGlobalTimerID = -1;
new ExamplePlayerTimerID[MAX_PLAYERS] = {-1, ...};
Note that if you're using an enum or an array with multiple dimensions, you can't use the '= {-1, ...};' initialiser. You have to do it yourself under OnGameModeInit like so:

pawn Код:
new PlayerVehicleTimer[MAX_PLAYERS][MAX_VEHICLES+1];

public OnGameModeInit()
{
    for(new playerid=0; playerid<MAX_PLAYERS; playerid++)
    {
        for(new vehicleid=1; vehicleid<=MAX_VEHICLES; vehicleid++)
        {
            PlayerVehicleTimer[playerid][vehicleid] = -1;
        }
    }
    return 1;
}
Finally, as I said previously, make sure you set the values to -1 again both when (if) the timer is killed, AND when it is called.

pawn Код:
new ExamplePlayerTimerID[MAX_PLAYERS] = {-1, ...};

public OnPlayerDeath(playerid, killerid, reason)
{
    ExamplePlayerTimerID[playerid] = SetTimerEx("SomeTimerFunction", 1000, false, "i", playerid);
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    // They are leaving, so we will kill the timer AND RESET IT TO -1
    KillTimer(ExamplePlayerTimerID[playerid]);
    ExamplePlayerTimerID[playerid] = -1;
    return 1;
}

forward SomeTimerFunction(playerid);
public SomeTimerFunction(playerid)
{
    ExamplePlayerTimerID[playerid] = -1;

    // Timer code
    return 1;
}
I don't know if I explained this very well, I hope you understand.

NOTE: When killing a timer, you should check if it is running first, but it doesn't really matter as killing timer ID -1 won't harm anything.

pawn Код:
public OnPlayerDisconnect(playerid, reason)
{
    if(ExamplePlayerTimerID[playerid] != -1)
    {
        KillTimer(ExamplePlayerTimerID[playerid]);
        ExamplePlayerTimerID[playerid] = -1;
    }
    return 1;
}
Reply
#4

Quote:
Originally Posted by MP2
Посмотреть сообщение
You're probably having the classic ID problem. Can happen to anything that uses an ID - timers, textdraws, even players. This is because if you don't reset a variable that stores an ID after the ID is used, if another timer/player/textdraw etc. takes up that ID, you will be affecting that one, not the old one that doesn't exist any more.

FOr example, lets say you have timer1 and timer2. You start timer1 and assign it to a variable. It is ID 0. The timer gets killed. You start timer2 and store its ID in a different variable. It takes the old ID of timer1, which is 0. But 'timer1' is still ID 0. If you kill timer1 (which no longer exists), it will kill timer2.

Say you have this script:

pawn Код:
new ExampleTimer[MAX_PLAYERS]; // By default all values are 0

public OnPlayerDisconnect(playerid, reason)
{
    KillTimer(ExampleTimer[playerid]);
    return 1;
}
If 'ExampleTimer[playerid]' was never assigned to a timer, it will still be 0. You'll then be killing timer ID 0 when anyone disconnects. That's going to kill the timer with ID 0, which is most likely your 'main timer'. You need to initialise values to -1 like so:

pawn Код:
new ExampleTimer[MAX_PLAYERS] = {-1, ...}; // All values will be -1
That way, if the timer is never used, timer ID 0 won't be killed by mistake.

Alternatively, you could just use up ID 0 by setting a random timer and never using it, but that's not the 'right' way to do it. With this method, you can also detect whether a timer is running or not.

It is just as (or more) important to also set the timer IDs to -1 when they are killed or called, for example:

First, declare the timer ID variables and initialize them to -1
pawn Код:
new ExampleGlobalTimerID = -1;
new ExamplePlayerTimerID[MAX_PLAYERS] = {-1, ...};
Note that if you're using an enum or an array with multiple dimensions, you can't use the '= {-1, ...};' initialiser. You have to do it yourself under OnGameModeInit like so:

pawn Код:
new PlayerVehicleTimer[MAX_PLAYERS][MAX_VEHICLES+1];

public OnGameModeInit()
{
    for(new playerid=0; playerid<MAX_PLAYERS; playerid++)
    {
        for(new vehicleid=1; vehicleid<=MAX_VEHICLES; vehicleid++)
        {
            PlayerVehicleTimer[playerid][vehicleid] = -1;
        }
    }
    return 1;
}
Finally, as I said previously, make sure you set the values to -1 again both when (if) the timer is killed, AND when it is called.

pawn Код:
new ExamplePlayerTimerID[MAX_PLAYERS] = {-1, ...};

public OnPlayerDeath(playerid, killerid, reason)
{
    ExamplePlayerTimerID[playerid] = SetTimerEx("SomeTimerFunction", 1000, false, "i", playerid);
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    // They are leaving, so we will kill the timer AND RESET IT TO -1
    KillTimer(ExamplePlayerTimerID[playerid]);
    ExamplePlayerTimerID[playerid] = -1;
    return 1;
}

forward SomeTimerFunction(playerid);
public SomeTimerFunction(playerid)
{
    ExamplePlayerTimerID[playerid] = -1;

    // Timer code
    return 1;
}
I don't know if I explained this very well, I hope you understand.

NOTE: When killing a timer, you should check if it is running first, but it doesn't really matter as killing timer ID -1 won't harm anything.

pawn Код:
public OnPlayerDisconnect(playerid, reason)
{
    if(ExamplePlayerTimerID[playerid] != -1)
    {
        KillTimer(ExamplePlayerTimerID[playerid]);
        ExamplePlayerTimerID[playerid] = -1;
    }
    return 1;
}
Thank you for your explanation, I get it now, I'll try to do something ^^
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)