|
-
Wie lasse ich den Mem_helper richtig Spawnen? Selbst wenn ich den WP auf mein Netzwerk ändere, sagt er nur folgendes:
Code:
19:16 Warn: 0 U: SPAWN: Spawnpoint WP_TIBBETS_DORF_HAUS_HELD_002_BETT1 not found. Npc MEM_HELPER_INST cannot be spawned. .... <oSpawn.cpp,#450>
Oder ist das amd Ende völlig egal und ich kann das ignorieren? Laut Forum muss der ja da sein um den Code richtig einzuschleusen.
Geändert von neocromicon (11.05.2021 um 18:16 Uhr)
-
Ist egal. Ich halte es sogar für einen Vorteil.
-
while(); - end; data-stack corruption ?
Hello folks,
I have a problem with function NPC_GetInfoInstanceTradeCount below - function returns number of dialog instances assigned to NPC with attribute oCInfo.trade == TRUE.
I use it within NPC instance - when NPC is inserted into a world, function will check if NPC is a trader, if not - default inventory will be created:
Code:
INSTANCE KDW_604_Cronos (Npc_Default) {
Name[0] = "Cronos";
...
//Something like this
if (NPC_GetInfoInstanceTradeCount (self) == 0) {
NPC_CreateDefaultInventory (self);
};
...
daily_routine = Rtn_START_604;
};
Now - where do I have a problem - when NPC is a trader, function should increase count by 1 (in red) - as soon as this is executed Gothic crashes:
Code:
/*
* Function will loop through all dialog instances and count number of dialogues which are assigned to NPC and have trade attribute == TRUE
*/
func int NPC_GetInfoInstanceTradeCount (var int slfInstance) {
//Convert to NPC
var oCNPC slf; slf = Hlp_GetNPC (slfInstance);
if (!Hlp_IsValidNPC (slf)) { return 0; };
var int slfInstanceID; slfInstanceID = Hlp_GetInstanceID (slf);
var oCInfo dlgInstance;
var zCListSort list;
var int count; count = 0;
var int infoPtr; infoPtr = MEM_InfoMan.infoList_next;
while (infoPtr);
list = _^ (infoPtr);
if (list.data) {
dlgInstance = _^ (list.data);
if (dlgInstance.npc == slfInstanceID) {
if (dlgInstance.trade) {
count += 1;
};
};
};
infoPtr = list.next;
end;
return +count;
};
After dozens of experiments - I found out that if I just add an empty variable (in green) then everything works ok:
Code:
/*
* Function will loop through all dialog instances and count number of dialogues which are assigned to NPC and have trade attribute == TRUE
*/
func int NPC_GetInfoInstanceTradeCount (var int slfInstance) {
//Convert to NPC
var oCNPC slf; slf = Hlp_GetNPC (slfInstance);
if (!Hlp_IsValidNPC (slf)) { return 0; };
var int slfInstanceID; slfInstanceID = Hlp_GetInstanceID (slf);
var oCInfo dlgInstance;
var zCListSort list;
var int i; i = 0;
var int count; count = 0;
var int infoPtr; infoPtr = MEM_InfoMan.infoList_next;
while (infoPtr);
list = _^ (infoPtr);
if (list.data) {
dlgInstance = _^ (list.data);
if (dlgInstance.npc == slfInstanceID) {
if (dlgInstance.trade) {
i;
count += 1;
};
};
};
infoPtr = list.next;
end;
return +count;
};
Same if I clear data-stack (inspired by LeGo) - everything works ok:
Code:
/*
* Function will loop through all dialog instances and count number of dialogues which are assigned to NPC and have trade attribute == TRUE
*/
func int NPC_GetInfoInstanceTradeCount (var int slfInstance) {
//Convert to NPC
var oCNPC slf; slf = Hlp_GetNPC (slfInstance);
if (!Hlp_IsValidNPC (slf)) { return 0; };
var int slfInstanceID; slfInstanceID = Hlp_GetInstanceID (slf);
var oCInfo dlgInstance;
var zCListSort list;
var int count; count = 0;
var int infoPtr; infoPtr = MEM_InfoMan.infoList_next;
while (infoPtr);
list = _^ (infoPtr);
if (list.data) {
dlgInstance = _^ (list.data);
if (dlgInstance.npc == slfInstanceID) {
if (dlgInstance.trade) {
MEM_Parser.datastack_sptr = 0;
count += 1;
};
};
};
infoPtr = list.next;
end;
return +count;
};
So in the end function works - I just don't understand WHY is there like a corruption of data stack that this function is causing, am I doing something wrong, or is it possible while(); end; is causing this somehow?
Does anyone know how to explain this behaviour?
Geändert von F a w k e s (24.06.2021 um 21:10 Uhr)
-
Given that the crash is so fickle, it looks like a bug in while() to me. You really shouldn't just be clearing the data stack like that, though, and I'm not convinced it even does anything helpful. You can try rewriting the loop via LeGo's list-functions or even just use MEM_StackPos.position to confirm that your code is fine.
-
Hello Lehona,
thank you for you reply - I tried both - and still same issue, if I don't use 'empty' variable (in green) game crashes, when I use it, Gothic does not crash:
List
Code:
/*
* Function will loop through all dialog instances and count number of dialogues which are assigned to NPC and have trade attribute == TRUE
*/
var int InfoMan_TotalCount;
var int InfoMan_NpcInstanceID;
func void NPC_InfoMan_GetTradeCount_Sub (var int node) {
var zCListSort list; list = _^ (node);
if (list.data) {
var oCInfo dlgInstance;
dlgInstance = _^ (list.data);
if ((dlgInstance.npc == InfoMan_NpcInstanceID) && (dlgInstance.trade)) {
var int i; i;
InfoMan_TotalCount += 1;
};
};
};
func int NPC_GetInfoInstanceTradeCount (var int slfInstance) {
//Convert to NPC
var oCNPC slf; slf = Hlp_GetNPC (slfInstance);
if (!Hlp_IsValidNPC (slf)) { return 0; };
if (!MEM_InfoMan.infoList_next) { return 0; };
InfoMan_TotalCount = 0;
InfoMan_NpcInstanceID = Hlp_GetInstanceID (slf);
List_ForFS (MEM_InfoMan.infoList_next, NPC_InfoMan_GetTradeCount_Sub);
return +InfoMan_TotalCount;
};
MEM_StackPos.position
Code:
func int NPC_GetInfoInstanceTradeCount (var int slfInstance) {
//Convert to NPC
var oCNPC slf; slf = Hlp_GetNPC (slfInstance);
if (!Hlp_IsValidNPC (slf)) { return 0; };
if (!MEM_InfoMan.infoList_next) { return 0; };
var int count; count = 0;
var int slfInstanceID; slfInstanceID = Hlp_GetInstanceID (slf);
var int infoPtr; infoPtr = MEM_InfoMan.infoList_next;
var int p;
p = MEM_StackPos.position;
var zCListSort list; list = _^ (infoPtr);
if (list.data) {
var oCInfo dlgInstance;
dlgInstance = _^ (list.data);
if ((dlgInstance.npc == slfInstanceID) && (dlgInstance.trade)) {
var int i; i;
count += 1;
};
infoPtr = list.next;
};
if (infoPtr) {
MEM_StackPos.position = p;
};
return +count;
};
It's super weird
-
I think that this may have nothing to do with while at all, but may just be an odd side-effect of calling the function from an instance function without backing up the UseInstance. There is also a limitation when assigning and working with instances during instance functions.
To me, the easiest fix appears to be to not call that function from the NPC instance function, but afterwards.
-
function called once topic is created
Hi everyone !
Can somebody help me to create a condition regarding counting entries of the topic.
I want to use function called only once when topic is just created . So In other words - condition if topic has only one entry.
-
You can have a look at the oCLogTopic class. It is documented and easily accessible in Ikarus through the zCList pointer oCLogManager_Ptr
PS: Not everything needs complicated solutions. In your situation, it sounds like it may suffice to just set a variable on topic creation and check that variable going forward.
Geändert von mud-freak (26.11.2021 um 10:06 Uhr)
-
Zitat von mud-freak
You can have a look at the oCLogTopic class. It is documented and easily accessible in Ikarus through the zCList pointer oCLogManager_Ptr
PS: Not everything needs complicated solutions. In your situation, it sounds like it may suffice to just set a variable on topic creation and check that variable going forward.
Yes I made second solution with succes.
But anyway I have to create variable for every mission - besides I want to create patch (for own purposes not publish) to work on most of the mods I want to play.
I am trying to modify an old code I had in my library , but cant find connection with it I want to create...
Code:
const int Log_GetLogManager_Ptr = 10328172;
CONST INT LogStatus_RUNNING = 1 ;
CONST INT LogStatus_SUCCESS = 2 ;
CONST INT LogStatus_FAILED = 3 ;
CONST INT LogStatus_OBSOLETE = 4 ;
func int Log_GetTopicStatus(var string topic) {
var zCList list; list = _^(Log_GetLogManager_Ptr);
while (list.next);
list = _^(list.next);
if (list.data) {
if (Hlp_StrCmp(MEM_ReadString(list.data), topic)) {
return MEM_ReadInt(list.data +24); // oCLogTopic.m_enuSection, oCLogTopic class doesn't exist in g1
//return MEM_ReadInt(list.data +20); // do log_note or log_mission
};
};
end;
return -1;
};
So the proper condition should looks
if (Log_GetTopicStatus (topic) == 2)// running
&& (variable decribing one entry for a log)
Geändert von pawbuj (26.11.2021 um 10:27 Uhr)
-
Hlp_Is_oCNpc crashing
Hello mud-freak, Lehona,
I've been trying to loop through symbol table - to be able to loop through all NPC instances - but when I used function Hlp_Is_oCNpc to validate whether symbol.offset was an NPC game would always crash, so I tried old Ikarus method - checking vtbl of the symbol and this worked fine. I wanted to check with you - is current Ikarus version of Hlp_Is_oCNpc function not safe enough to use, or am I using it incorrectly in the code below?
Code:
var int i;
var int symOffset;
var zCPar_Symbol symb;
repeat (i, currSymbolTableLength);
symb = _^ (MEM_GetSymbolByIndex (i));
if (symb.offset) {
if ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_INSTANCE) {
//Hlp_Is_oCNpc will crash!
//if (Hlp_Is_oCNpc (symb.offset)) {
if (MEM_ReadInt (symb.offset) == oCNpc_vtbl) {
var oCNPC slf; slf = _^ (symb.offset);
MEM_Info (slf.Name);
};
};
};
-
Neither is correct. Like you are saying, you are iterating over the symbols, not over the NPCs. After an NPC is created the content of the associated NPC instance is no longer guaranteed to point to the NPC object. That it works in some cases has to do with recent calls to external engine functions related to that symbol, e.g. Wld_InsertNpc and Hlp_GetNpc.
What you actually want to do is just that. Use Hlp_GetNpc(symb.instanz).
-
Thank you!
-
@F a w k e s, the new version (comes only with Ninja?) of the function requires that the passed in pointer be a pointer to a zCObject descendant (or zero). And, for example, C_INFO instances are not. That's why you get a crash.
Also, going through the whole character table doesn't seem optimal. What's wrong with oCWorld::voblist_npcs? It contains all the NPCs managed by the routine manager (i.e. usually all the humans here). It also contains all NPCs that are physically present in the world (not despawned).
In any case, parser symbols declared as instance SomeName(C_NPC /* or C_NPC proto */) {}; have C_NPC symbol as ancestor. You can check this, for example, using int zCParser :: GetBaseClass (int nr), which should return the index of C_NPC symbol. Also, unlike var C_NPC SomeInstance, such symbols will have a constant flag.
-
Hello TopLayer,
Thank you for your suggestion - I was thinking about using symbol table, because in the code I was working on I was looping through it anyway to find all routine functions, so thought I might collect all NPCs in the loop anyway but I ended up using oCWorld::voblist_npcs in the end.
-
STR_IndexOf crashing
Hello Lehona, mud-freak,
Hope you can help me with this one - randomly (at least I didn't find any pattern behind this behaviour) function STR_IndexOf crashes game with similar stacktrace log (only string parameters are changing):
Code:
-2- 13706:14 Fault: 0 Q: [start of stacktrace]
-2- 13706:14 Fault: 0 Q: MEM_READINT_() + 13 bytes
-2- 13706:14 Fault: 0 Q: MEM_COMPAREBYTES(442052605, 411582897, 2) + 289 bytes
-2- 13706:14 Fault: 0 Q: STR_INDEXOF('Okay, what do I need to know about this place?', 'o@') + 225 bytes
-2- 13706:14 Fault: 0 Q: _HOOK_OCINFORMATIONMANAGER_UPDATE_ENHANCEDINFOMANAGER() + 7610 bytes
-2- 13706:14 Fault: 0 Q: MEM_CALLBYID(31367) + 224 bytes
-2- 13706:14 Fault: 0 Q: _HOOK(503557192, 10328072, 500171680, 493528576, 19331612, 0, 8250828, 10328072, -1) + 940 bytes
-2- 13706:14 Fault: 0 Q: [UNKNOWN] +288584328 bytes
-2- 13706:14 Fault: 0 Q: [end of stacktrace]
-2- 13706:14 Fault: 0 Q: Exception handler was invoked. Ikarus tried to print a Daedalus-Stacktrace to zSpy. Gothic will now crash and probably give you a stacktrace of its own.
What I am doing is searching for index of strings, for example 'o@' in dialogue description:
STR_INDEXOF('Okay, what do I need to know about this place?', 'o@')
Would you have an idea why this crashes?
-
I think Ikarus is reading across page boundaries into unallocated memory, because if it's e.g. comparing two bytes, it still does a full 4 byte read (usually this over-read will not cross page boundaries and hence go unnoticed). At least on GitHub MEM_ReadByte works correctly by reading only a single byte (see MEM_ReadByte_ function), not quite sure if it ever made its way into a release. The solution to your crash is to fix the last few lines of MEM_CompareBytes to use MEM_ReadByte instead of MEM_ReadInt.
-
Good catch. I think the updated MEM_ReadByte is already in the latest release. We must have overlooked that MEM_CompareBytes still uses MEM_ReadInt to read bytes.
I think we can update MEM_CompareBytes to just use memcmp. That may be also more efficient for longer sequences.
PS: Maybe worth noting: if you manage to fix it in the way Lehona suggests (or other), feel free to add a pull-request on the Github repository.
Geändert von mud-freak (16.03.2022 um 10:23 Uhr)
-
I've changed it as per advice from Lehona - so far it looks good, but I will keep testing for day or two, before creating pull request
Code:
func int MEM_CompareBytes(var int ptr1, var int ptr2, var int byteCount) {
if (byteCount < 0) {
MEM_Error ("MEM_CompareBytes: Cannot compare less than 0 bytes!");
return 0;
};
if (byteCount == 0) {
//in this case the addresses may be invalid.
return 1;
};
if (ptr1 == 0)
|| (ptr2 == 0) {
MEM_Error ("MEM_CompareBytes: ptr1 or ptr2 is Null");
return 0;
};
var int loopPos; loopPos = MEM_StackPos.position;
if (byteCount >= 4) {
if (MEM_ReadInt(ptr1) != MEM_ReadInt(ptr2)) {
return 0;
};
ptr1 += 4; ptr2 += 4;
byteCount -= 4;
MEM_StackPos.position = loopPos;
};
//var int mask; mask = (1 << byteCount * 8) - 1;
//return (MEM_ReadInt(ptr1) & mask) == (MEM_ReadInt(ptr2) & mask);
//--> update
if (byteCount > 0) {
if (MEM_ReadByte(ptr1) != MEM_ReadByte(ptr2)) {
return 0;
};
ptr1 += 1; ptr2 += 1;
byteCount -= 1;
MEM_StackPos.position = loopPos;
};
return 1;
//<--
};
-
Neuling
Eine kurze Frage: Unzwar habe ich Ikarus / LeGo in meine Mod eingebaut. Das klappt auch soweit gut, allerdings crashen manche Nutzer beim starten des Spiels. Ich konnte mit Ein/Auskommentieren herausfinden, dass diese immer beim MEM_InitAll() crashen. Die betroffenen Spieler crashen auch nicht nur manchmal, sondern immer. Bei mir hingegen (und auch anderen) läuft es wie gesagt komplett Problemlos.
Ich habe um sicher zu gehen auch mal die ganzen "neuen" .src Dateien rausgenommen, sodass nur Ikarus geladen wird. Das MEM_InitAll() hatte ich bei Tests also als einziges eingebaut und in der INIT_GLOBALS einmal ganz am Anfang, nach dem InitGameGerman und ganz am Ende aufgerufen. Bei allen drei erzeugten .mod Dateien ist das Spiel gecrasht.
Pastebin eines zspylogs https://pastebin.com/e7g40b61
Jemand eine Idee?
-
Zitat von KnightGotha
...
Jemand eine Idee?
Ich werfe einfach mal "Haben die Spieler auch den Report-Version Patch installiert?" rein.
Ohne ReportVersion Patch funktioniert Ikarus und LeGo nicht.
Berechtigungen
- Neue Themen erstellen: Nein
- Themen beantworten: Nein
- Anhänge hochladen: Nein
- Beiträge bearbeiten: Nein
|
|