Author Topic: Time advancement  (Read 488 times)

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Time advancement
« Reply #15 on: January 30, 2013, 06:00:42 am »


               

Lazarus Magni wrote...

I was told heartbeat scripts on the mod can cause lag, but I will give it a shot and see what happens. Thanks everyone.

This is common superstition. If you knew how many scripts, and how many instructions takes a single hostile creature, you would not seen a threat in module heartbeat.

Of course a script running each six seconds takes some resources. But if you are going to replace the heartbeat with a pseudoheartbeat that will also run each six seconds, you might end up worse, especially if the pseudo heartbeat transfere parameters into another recurse.

A module heartbeat is no way inefficient. If there are no players in module, you can use timestop effect to stop whole module which stops not only module's heatbeat but everything else.

Alternatively, a placeables also run hearbeats and placeables might be created and destroyed. Thus a placeable can be used to run module-wise heartbeat and builder will have controll to stop and run this heartbeat at any time.

Still its important to determine where a pseudo-HB makes a job of the heartbeat better and where not. Mostly, the pseudo-HB is better choice, but for time counting and custom events running a module's heartbeat is a best choice.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Time advancement
« Reply #16 on: January 30, 2013, 06:52:22 am »


               To me this is a case for a pseudo-HB.  The game clock does not show minutes on it anyway.  so just run a pseudo-HB every game hour.    

void UpdateClock(float fDelay)
{
 SetTime(GetTimeHour(), GetTimeMinute(), GetTimeSecond(), GetTimeMillisecond());
 DelayCommand( fDelay, UpdateClock(fDelay);
}

void main ()
{
 ...

  UpdateClock( HoursToSeconds(1) );
...
}


}
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Time advancement
« Reply #17 on: January 30, 2013, 07:43:52 am »


               Nah, module heartbeat for this one, so long as your mod isn't so bloated that it's barely firing. Even if it is, the pseudo will only make it worse. Rough rule of thumb is that pseudos use about 5 times the cpu as a functionally identical heartbeat. If it's for something you want running more than 20% of the time, use a normal heartbeat.

As for heartbeats, Shad is correct. Sure, they add load, but compared to everything else going on, it's negligible. Here's ours, by way of comparison. Our mod still runs as smoothly as it did without - smoother, thanks to other optimizations, actually, but that's missing the point. '<img'>


#include "hg_inc"

#include "fky_chat_inc"
#include "hg_client_inc"

#include "ac_effect_inc"
#include "ac_itemprop_inc"


void SendResetBroadcast (string sMessage, int bTell, object oMessenger) {
    sMessage = "<cþ þ>" + sMessage + "</c>";

    object oPC = GetFirstPC();

    while (GetIsObjectValid(oPC)) {
        SendChatLogMessage(oPC, sMessage, oMessenger, (bTell ? 4 : 5));
        oPC = GetNextPC();
    }
}


void main() {
    object oMod = GetModule();
    object oMes = GetMessenger();
    int nUptime = GetLocalInt(oMod, "uptime");
    int nMemory = GetProcessMemoryUsage();
    int nMessages = 0, nPlayers = 0;
    string sServer = GetLocalString(oMod, "ServerNumber");
    string sBootTime = IntToString(GetLocalInt(oMod, "boottime"));

    {
        object oPC;

        for (oPC = GetFirstPC(); GetIsObjectValid(oPC); oPC = GetNextPC()) {
            nPlayers++;
            RecalculateMovementRate(oPC);
            RecalculateDexModifier(oPC);

            int nAlarm = GetLocalInt(oPC, "AlarmUptime");
            if (nAlarm > 0 && nAlarm <= nUptime) {
                DeleteLocalInt(oPC, "AlarmUptime");
                SendChatLogMessage(oPC, C_PINK + "[Alarm] " + GetLocalString(oPC, "AlarmMessage") + C_END, oMes, 4);
            }
        }

        SetLocalInt(oMod, "ServerPlayers", nPlayers);
    }

    SQLExecDirect("SELECT UNIX_TIMESTAMP() - " + sBootTime + ", UTC_TIMESTAMP(), UNIX_TIMESTAMP(), " +
        "COUNT(*) FROM user_messages WHERE um_recipient = '*" + sServer + "'");

    if (SQLFetch() == SQL_SUCCESS) {
        nUptime = StringToInt(SQLGetData(1));
        nMessages = StringToInt(SQLGetData(4));

        SetLocalInt(oMod, "uptime", nUptime);
        SetLocalInt(oMod, "realtime", StringToInt(SQLGetData(3)));
        SetLocalString(oMod, "utctime", SQLGetData(2));

        SQLExecDirect("UPDATE server_list SET srv_utime = " + IntToString(nUptime) + ", srv_memory = " +
            IntToString(nMemory) + ", srv_players = " + IntToString(nPlayers) + " WHERE srv_id = '" + sServer + "'");

        SQLExecDirect("SELECT COUNT(*) FROM user_list WHERE u_active > 0");
        if (SQLFetch() == SQL_SUCCESS)
            SetLocalInt(oMod, "GlobalPlayers", StringToInt(SQLGetData(1)));

        SQLExecDirect("SELECT COUNT(*) FROM user_list WHERE u_active > 0 AND u_server_name REGEXP '" + GetStringLeft(sServer, 1) + ".[1-8]'");
        if (SQLFetch() == SQL_SUCCESS) {
            int nHubPlayers = StringToInt(SQLGetData(1));

            SetLocalInt(oMod, "HubPlayers", nHubPlayers);

            if (GetStringLeft(sServer, 1) != "1" && GetStringRight(sServer, 1) == "1")
                SetNumberOfPlayers(nHubPlayers);
        }
    }


    /* check for server messages if available */
    if (nMessages > 0) {
        int nGuild;
        string sMessage;
        string sSQL = "SELECT um_id, um_guild, um_text FROM user_messages WHERE um_recipient = '*" + sServer + "'";

        SQLExecDirect(sSQL);

        sSQL = "";

        while (SQLFetch() != SQL_ERROR) {
            if (sSQL == "")
                sSQL = "um_id = " + SQLGetData(1);
            else
                sSQL += " OR um_id = " + SQLGetData(1);

            nGuild   = StringToInt(SQLGetData(2));
            sMessage = SQLDecodeSpecialChars(SQLGetData(3));

            if (nGuild == -2) {
                object oPC = GetFirstPC();

                while (GetIsObjectValid(oPC)) {
                    if (!(GetPCFilter(oPC, PCFILTER_CHANNELS) & 1))
                        SendChatLogMessage(oPC, sMessage, oMes);

                    oPC = GetNextPC();
                }
            } else if (nGuild == -3) {
                object oPC = GetFirstPC();

                while (GetIsObjectValid(oPC)) {
                    if (!(GetPCFilter(oPC, PCFILTER_CHANNELS) & 2))
                        SendChatLogMessage(oPC, sMessage, oMes);

                    oPC = GetNextPC();
                }
            } else if (nGuild == -4) {
                object oPC = GetFirstPC();

                while (GetIsObjectValid(oPC)) {
                    if (!(GetPCFilter(oPC, PCFILTER_CHANNELS) & 4))
                        SendChatLogMessage(oPC, sMessage, oMes);

                    oPC = GetNextPC();
                }
            } else if (nGuild < 0) {
                SendMessageToDMDMs(sMessage);
                SendMessageToPCDMs(sMessage);
                SendMessageToDMAdmins(sMessage);
                SendMessageToPCAdmins(sMessage);
            } else if (nGuild > 0) {
                object oPC = GetFirstPC();

                while (GetIsObjectValid(oPC)) {
                    if (GetLocalInt(oPC, "Guild") == nGuild && !(GetPCFilter(oPC, PCFILTER_GUILD) & 1))
                        SendChatLogMessage(oPC, sMessage, oMes);

                    oPC = GetNextPC();
                }
            } else
                AssignCommand(oMod, SpeakString(sMessage, TALKVOLUME_SHOUT));
        }

        if (sSQL != "")
            SQLExecDirect("DELETE FROM user_messages WHERE " + sSQL);
    }


    /* scan players for inter-server messages every minute; also check for auto-reset */
    if (nUptime >= GetLocalInt(oMod, "LastMessageCheck") + 60) {
        SetLocalInt(oMod, "LastMessageCheck", nUptime);

        if (nMemory > GetLocalInt(oMod, "resetmemory") && !GetLocalInt(oMod, "resetforce")) {
            SetLocalInt(oMod, "resetforce", 1);

            if (GetLocalInt(oMod, "resetuptime") > nUptime)
                SetLocalInt(oMod, "resetuptime", nUptime - 1);
        }


        /* update PCs in the user list */
        UpdateAllClients(sServer, sBootTime, oMes);


        /* check for automatic reset */
        int nResetUptime = GetLocalInt(oMod, "resetuptime");
        if (nResetUptime > 0 && nUptime > nResetUptime) {

            if (!GetIsObjectValid(GetFirstPC()))
                SetLocalString(oMod, "NWNX!RESETPLUGIN!SHUTDOWN", "1");

            if (nUptime > nResetUptime + 900) {
                SendResetBroadcast("SERVER RESET IN 10 SECONDS - SERVER REBOOT IS NOW COMMITTED - CANCELLATION " +
                    "IS NO LONGER POSSIBLE - PLEASE STAY OUT OF BANK CHESTS - HAVE A NICE DAY!", 1, oMes);
                DelayCommand(10.0, SetLocalString(oMod, "NWNX!RESETPLUGIN!SHUTDOWN", "1"));
            } else {
                int bTell = 0;
                int nSeconds = (nResetUptime + 900) - nUptime;
                string sMinutes = IntToString((nSeconds / 60) + 1);

                if (sMinutes == "1" || sMinutes == "5" || sMinutes == "10" || sMinutes == "15")
                    bTell = 1;

                if (GetLocalInt(oMod, "resetforce"))
                    SendResetBroadcast("AUTOMATIC SERVER RESET IN " + sMinutes + " MINUTE" +
                        (sMinutes != "1" ? "S" : "") + " - THIS CANNOT BE ABORTED DUE TO A LOW MEMORY CONDITION", bTell, oMes);
                else
                    SendResetBroadcast("AUTOMATIC SERVER RESET IN " + sMinutes + " MINUTE" +
                        (sMinutes != "1" ? "S" : "") + " - USE !delayreset TO DELAY THE RESET", bTell, oMes);
            }
        }
    }


    /* scan players for epic buffs every minute */
    if (nUptime >= GetLocalInt(oMod, "LastImmunityBuffCheck") + 60) {
        int i;
        object oCreator, oArea, oItem, oPC = GetFirstPC();

        while (GetIsObjectValid(oPC)) {
            oArea = GetArea(oPC);

            if (GetIsDead(oPC)           ||
                !GetIsObjectValid(oArea) ||
                GetHasEffectOfType(EFFECT_TYPE_CONFUSED, oPC)) {
                oPC = GetNextPC();
                continue;
            }


            if (GetHasSpellEffect(HGSPELL_EPIC_AEGIS, oPC)) {
                oCreator = GetLocalObject(oPC, "EpicCreator_Aegis");

                if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
                    if (GetLocalInt(oPC, "EpicCollapse_Aegis") > 1) {
                        RemoveEffectsFromSpell(HGSPELL_EPIC_AEGIS, oPC);
                        FloatingTextStringOnCreature(
                            "* The Aegis spell on you collapses without the support of its caster! *",
                            oPC, FALSE);
                    } else
                        AddLocalInt(oPC, "EpicCollapse_Aegis", 1);
                } else
                    DeleteLocalInt(oPC, "EpicCollapse_Aegis");
            }


            if (GetHasSpellEffect(HGSPELL_EPIC_CHANT_OF_WARDING, oPC)) {
                oCreator = GetLocalObject(oPC, "EpicCreator_Chant");

                if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
                    if (GetLocalInt(oPC, "EpicCollapse_Chant") > 1) {
                        RemoveEffectsFromSpell(HGSPELL_EPIC_CHANT_OF_WARDING, oPC);
                        FloatingTextStringOnCreature(
                            "* The Chant of Warding spell on you collapses without the support of its caster! *",
                            oPC, FALSE);
                    } else
                        AddLocalInt(oPC, "EpicCollapse_Chant", 1);
                } else
                    DeleteLocalInt(oPC, "EpicCollapse_Chant");
            }


            if (GetHasSpellEffect(HGSPELL_EPIC_ELEMENTAL_SHUNT, oPC)) {
                oCreator = GetLocalObject(oPC, "EpicCreator_Shunt");

                if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
                    if (GetLocalInt(oPC, "EpicCollapse_Shunt") > 1) {
                        RemoveEffectsFromSpell(HGSPELL_EPIC_ELEMENTAL_SHUNT, oPC);
                        FloatingTextStringOnCreature(
                            "* The Elemental Shunt spell on you collapses without the support of its caster! *",
                            oPC, FALSE);
                    } else
                        AddLocalInt(oPC, "EpicCollapse_Shunt", 1);
                } else
                    DeleteLocalInt(oPC, "EpicCollapse_Shunt");
            }


            if (GetHasSpellEffect(HGSPELL_EPIC_SHROUD_OF_NATURE, oPC)) {
                oCreator = GetLocalObject(oPC, "EpicCreator_Shroud");

                if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
                    if (GetLocalInt(oPC, "EpicCollapse_Shroud") > 1) {
                        RemoveEffectsFromSpell(HGSPELL_EPIC_SHROUD_OF_NATURE, oPC);
                        FloatingTextStringOnCreature(
                            "* The Shroud of Nature spell on you collapses without the support of its caster! *",
                            oPC, FALSE);
                    } else
                        AddLocalInt(oPC, "EpicCollapse_Shroud", 1);
                } else
                    DeleteLocalInt(oPC, "EpicCollapse_Shroud");
            }


            oPC = GetNextPC();
        }

        SetLocalInt(oMod, "LastImmunityBuffCheck", (nUptime - 5) + Random(11));
    }


    if (nUptime >= GetLocalInt(oMod, "LastEquipmentBuffCheck") + 60) {
        int i;
        object oCreator, oArea, oItem, oPC = GetFirstPC();

        while (GetIsObjectValid(oPC)) {
            oArea = GetArea(oPC);

            if (GetIsDead(oPC)                                 ||
                !GetIsObjectValid(oArea)                       ||
                GetHasEffectOfType(EFFECT_TYPE_POLYMORPH, oPC) ||
                GetHasEffectOfType(EFFECT_TYPE_CONFUSED, oPC)) {
                oPC = GetNextPC();
                continue;
            }

            if ((GetLevelByclass(class_TYPE_BLACKGUARD, oPC) + GetLevelByclass(class_TYPE_PALADIN, oPC) + GetLevelByclass(class_TYPE_DIVINE_CHAMPION, oPC)) >= 40) {
                if (GetKnowsFeat(FEAT_SMITE_EVIL, oPC))
                    IncrementRemainingFeatUses(oPC, FEAT_SMITE_EVIL);
                if (GetKnowsFeat(FEAT_SMITE_GOOD, oPC))
                    IncrementRemainingFeatUses(oPC, FEAT_SMITE_GOOD);
                // Greater Smite failing to recharge fix.
                int nIndex = GetLocalInt(oPC, "GreaterSmiteAbility") - 1;
                struct SpecialAbilitySlot sa = GetSpecialAbility(oPC, nIndex);

                if ((sa.id == SPELLABILITY_GAZE_DESTROY_EVIL ||
                    sa.id == SPELLABILITY_GAZE_DESTROY_GOOD ||
                    sa.id == SPELLABILITY_PULSE_HOLY) && sa.ready == 0 && !GetLocalInt(oPC, "NeedsRest")) {
                    sa.ready = 1;
                    SetSpecialAbility(oPC, nIndex, sa);
                }
            }

            if (GetHasSpellEffect(HGSPELL_EPIC_GIRDING_OF_THE_FAITHFUL, oPC)) {
                oCreator = GetLocalObject(oPC, "EpicCreator_Gird");

                if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
                    if (GetLocalInt(oPC, "EpicCollapse_Gird") > 1) {
                        RemoveEffectsFromSpell(HGSPELL_EPIC_GIRDING_OF_THE_FAITHFUL, oPC);
                        DelayCommand(0.1, VoidRemoveAllItemPropertiesFromSpell(HGSPELL_EPIC_GIRDING_OF_THE_FAITHFUL, oPC));

                        FloatingTextStringOnCreature(
                            "* The Girding of the Faithful spell on you collapses without the support of its caster! *",
                            oPC, FALSE);
                    } else
                        AddLocalInt(oPC, "EpicCollapse_Gird", 1);
                } else
                    DeleteLocalInt(oPC, "EpicCollapse_Gird");
            }


            if (GetHasSpellEffect(HGSPELL_EPIC_INSTRUMENTS_OF_FAITH, oPC)) {
                oCreator = GetLocalObject(oPC, "EpicCreator_Instr");

                if (!GetIsObjectValid(oCreator) || GetArea(oCreator) != oArea || !GetFactionEqual(oCreator, oPC)) {
                    if (GetLocalInt(oPC, "EpicCollapse_Instr") > 1) {
                        RemoveEffectsFromSpell(HGSPELL_EPIC_INSTRUMENTS_OF_FAITH, oPC);
                        DelayCommand(0.1, VoidRemoveAllItemPropertiesFromSpell(HGSPELL_EPIC_INSTRUMENTS_OF_FAITH, oPC));

                        FloatingTextStringOnCreature(
                            "* The Instruments of Faith spell on you collapses without the support of its caster! *",
                            oPC, FALSE);
                    } else
                        AddLocalInt(oPC, "EpicCollapse_Instr", 1);
                } else
                    DeleteLocalInt(oPC, "EpicCollapse_Instr");
            }


            oPC = GetNextPC();
        }

        SetLocalInt(oMod, "LastEquipmentBuffCheck", (nUptime - 5) + Random(11));
    }
}

By contrast, the old heartbeat we had, which looped all equipment on all players, as well as much more, often more than once, was so poorly conceived and executed that you could actually feel a pause every time it ran (in part due to other poor practices at the time - see my delagging tutorial in the lexicon if you're curious about other optimizations). Moral of the story: be smart, tread lightly, and you have NOTHING to worry about when using mod heartbeats.

Funky
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Time advancement
« Reply #18 on: January 30, 2013, 08:02:04 am »


               

FunkySwerve wrote...

 see my delagging tutorial in the lexicon if you're curious about other optimizations


Got a link for this? I would certainly be interested in checking this out. But again, neither this heartbeat, nor our mod in general is what is causing our current problem.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Time advancement
« Reply #19 on: January 30, 2013, 04:43:44 pm »


               I understand that the heartbeat isn't the issue - I'm just reinforcing the point, as well as advocating for the use of a heartbeat rather than a pseudo here. You can find the 1.69 lexicon on the vault:
http://nwvault.ign.c....Detail&id=1340

You can find the tutorial under the Contents tab, in Lyceum/Tutorial/Toolset/Lag Busting - How to Make Your Server Run More Smoothly

Funky
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Time advancement
« Reply #20 on: January 30, 2013, 05:00:13 pm »


               <fading in...>

Lag Busting

<...and out on the hb>
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Time advancement
« Reply #21 on: January 30, 2013, 08:43:31 pm »


               Thanks guys.