For some reason on our module, time does not advance. It is stuck at month 6, day 1, hour 13. Does anyone know what factors could cause this?
Also when I load the mod locally time does move forward, but for some reason on the server it doesn't.
Time advancement
Débuté par
Lazarus Magni
, janv. 23 2013 07:59
#1
Posté 23 janvier 2013 - 07:59
#2
Posté 23 janvier 2013 - 08:54
This can happen if your server load gets high. The server diverts processing time from less-important tasks (like updating the clock). If you have NWNX, the nwnx_fixes plugin takes care of it. If you don't, you can add the following to your module's OnHeartbeat script:
SetTime(GetTimeHour(), GetTimeMinute(), GetTimeSecond(), GetTimeMillisecond());
#3
Posté 23 janvier 2013 - 10:09
Thanks Monk, I may give that a try. Does that plugin still require NWNX_Core_2.7_Beta_4 (nwnx-module.dll)?
#4
Posté 23 janvier 2013 - 10:22
IIRC, yes. I use the 2.8 core, though, so I can't say from experience.
#5
Posté 24 janvier 2013 - 12:52
Hmm well I am trying nwnx_fixes right now, and no effect. Is there a specific ini setting I need to enable?
And on a side note is there a core 2.8 for Windows? I can't seem to find it.
And on a side note is there a core 2.8 for Windows? I can't seem to find it.
#6
Posté 24 janvier 2013 - 12:57
As I said in another thread, unfortunately, the Windows version of NWNX Fixes is outdated and doesn't contain the time advancement fix.
#7
Posté 24 janvier 2013 - 08:58
Thanks for the info virusman. If the fix does get ported to windows, I would happily use it.
#8
Posté 24 janvier 2013 - 09:47
Squatting Monk wrote...
This can happen if your server load gets high. The server diverts processing time from less-important tasks (like updating the clock). If you have NWNX, the nwnx_fixes plugin takes care of it. If you don't, you can add the following to your module's OnHeartbeat script:SetTime(GetTimeHour(), GetTimeMinute(), GetTimeSecond(), GetTimeMillisecond());
Everything there is a NWN function, It will work without nwnx.
#9
Posté 24 janvier 2013 - 10:19
We don't use a heart beat script, but if I made one as simple as this:
void main()
{
SetTime(GetTimeHour(), GetTimeMinute(), GetTimeSecond(), GetTimeMillisecond());
}
Would that work?
void main()
{
SetTime(GetTimeHour(), GetTimeMinute(), GetTimeSecond(), GetTimeMillisecond());
}
Would that work?
#10
Posté 24 janvier 2013 - 10:35
Ayup.
#11
Posté 24 janvier 2013 - 10:43
I was told heartbeat scripts on the mod can cause lag, but I will give it a shot and see what happens. Thanks everyone.
#12
Posté 25 janvier 2013 - 04:01
Well in case anyone is interested, we are using this now as our module event heartbeat script, and so far have not experienced any lag because of it.
#13
Posté 29 janvier 2013 - 08:32
I stand corrected. Although it's true we have not gotten any lag due to this, but this HB scripting solution seems to have resulted in:
spawns not rendering, party members not rendering, maps not getting explored, rest timer acting wonky, and restart times being extended way beyond the scheduled interval
I do not recommend this solution to anyone who has near the big or complex of a module as we have... It might work ok for a less complex mod, but I can not vouch for that.
spawns not rendering, party members not rendering, maps not getting explored, rest timer acting wonky, and restart times being extended way beyond the scheduled interval
I do not recommend this solution to anyone who has near the big or complex of a module as we have... It might work ok for a less complex mod, but I can not vouch for that.
#14
Posté 29 janvier 2013 - 10:47
This is how large, complex modules handled the issue before NWNX fixed it. I doubt these results are simply from updating the clock OnHeartbeat.
#15
Posté 30 janvier 2013 - 05:46
My apologies, you are correct, this doesn't seem to have caused the problem after all. We recently just changed to a new server, and apparently are having technical difficulties.
#16
Posté 30 janvier 2013 - 06:00
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.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.
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.
#17
Posté 30 janvier 2013 - 06:52
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) );
...
}
}
void UpdateClock(float fDelay)
{
SetTime(GetTimeHour(), GetTimeMinute(), GetTimeSecond(), GetTimeMillisecond());
DelayCommand( fDelay, UpdateClock(fDelay);
}
void main ()
{
...
UpdateClock( HoursToSeconds(1) );
...
}
}
#18
Posté 30 janvier 2013 - 07:43
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.
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
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.
#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
#19
Posté 30 janvier 2013 - 08:02
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.
#20
Posté 30 janvier 2013 - 04:43
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
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
#21
Posté 30 janvier 2013 - 05:00
#22
Posté 30 janvier 2013 - 08:43
Thanks guys.





Retour en haut







