DIV compiler is giving me an error that's not accurate: "It is not possible to access external PRIVATE data."
Struct declared in local:
Code:
local
struct ai
previousState;
currentState;
struct model
knownOpponentCount;
knownAllyCount;
targetOpponentIndex;
struct knownOpponents[MAX_CHARACTERS - 1]
x;
y;
visible;
end
struct knownAllies[MAX_CHARACTERS - 1]
x;
y;
visible;
end
end
end
Process:
Code:
process AIVisionManager(faction)
private
allOpponents[MAX_CHARACTERS - 1];
aiCharacters[MAX_CHARACTERS - 1];
knownOpponentIndex;
knownOpponent;
opponent;
aiCharacter;
begin
allOpponents = GetAllOpponents(faction);
aiCharacters = GetFactionList(faction);
loop
// foreach AI
for (x = 0; x < MAX_CHARACTERS; ++x)
if (aiCharacters[x] <= 0)
continue;
end
aiCharacter = aiCharacters[x];
// foreach opponent
for (y = 0; y < MAX_CHARACTERS; ++y)
if (allOpponents[y] <= 0)
continue;
end
opponent = allOpponents[y];
knownOpponentIndex = GetIndexOfValueInTable(
aiCharacter.ai.model.knownOpponents,
MAX_CHARACTERS - 1,
opponent);
// this AI character already knows this opponent, only update position
if (knownOpponentIndex > -1)
knownOpponent = aiCharacter.ai.model.knownOpponents[knownOpponentIndex];
else
// if AI can see opponent, update the AIs model
if (AILineOfSight(aiCharacter.x, aiCharacter.y, opponent.x, opponent.y))
knownOpponentIndex = FindFreeIndexInTable(
aiCharacter.ai.model.knownOpponents,
MAX_CHARACTERS - 1);
aiCharacter.ai.model.knownOpponents[knownOpponentIndex] = opponent;
aiCharacter.ai.model.knownOpponentCount++;
end
end
end
end
frame;
end
end
I get this error: "It is not possible to access external PRIVATE data." on this line:
What do you think about assigning to knownOpponent?
KnownOpponents is a STRUCT, while knownOpponent is an INT, in theory the compiler should not be able to assign anything because of the incompatibility
of the types, but in fact what it does in this case is assigning the value of the first member of the structure (ie, X) then interprets the previous
statement as if you had written it:
The X member in turn has the same name as a LOCAL variable, so it is likely that the compiler, for some bug or missing implementation, misread this
member as LOCAL x variable, which you can not access
If you can explain what you want to do in the example and what you would like to assign to the variables we can see a possible solution.
function GetFactionList(faction)
begin
switch (faction)
case FACTION_NEUTRAL:
return (&__neutralCharacters);
end
case FACTION_GOOD:
return (&__goodCharacters);
end
case FACTION_EVIL:
return (&__evilCharacters);
end
end
end
I use double underscore __ to indicate global variables, these three are tables that contains process ids or 0/-1. So, I'm trying to return a pointer
to a table, as I'd like to iterate over it.
2)
knownOpponent is supposed to hold a (temporary) single entry of the local ai.model.knownOpponents[] struct. I should use a pointer here, but posted
this in a hurry. I'm not sure if there's a cleaner syntax I could use, but I managed to get it compiling and working as intended with this code:
Code:
process AIVisionManager(faction)
private
pointer allOpponents[MAX_CHARACTERS - 1];
pointer aiCharacters[MAX_CHARACTERS - 1];
knownOpponentIndex = -1;
pointer opponent;
pointer aiCharacter;
isVisible = false;
begin
allOpponents = GetAllOpponents(faction);
aiCharacters = GetFactionList(faction);
loop
// foreach AI
for (x = 0; x < MAX_CHARACTERS; ++x)
if (*aiCharacters[x] <= 0)
continue;
end
aiCharacter = *aiCharacters[x];
// foreach opponent
for (y = 0; y < MAX_CHARACTERS; ++y)
if (*allOpponents[y] <= 0)
continue;
end
opponent = *allOpponents[y];
// can AI see opponent?
isVisible = AILineOfSight((*aiCharacter).x, (*aiCharacter).y, (*opponent).x, (*opponent).y);
knownOpponentIndex = -1;
// TODO: Clean this up into a function.
// find index of element where processId == opponent
for (z = 0; z < MAX_CHARACTERS - 1; ++z)
if ((*aiCharacter).ai.model.knownOpponents[z].processId == opponent)
knownOpponentIndex = z;
break;
end
end
if (knownOpponentIndex < 0 && isVisible)
// TODO: Clean this up into a function.
// find next free index
for (z = 0; z < MAX_CHARACTERS - 1; ++z)
if ((*aiCharacter).ai.model.knownOpponents[z].processId <= 0)
knownOpponentIndex = z;
break;
end
end
// visible but previously unknown opponents are added to AI's model
(*aiCharacter).ai.model.knownOpponents[z].processId = opponent;
(*aiCharacter).ai.model.knownOpponentCount++;
end
// if knownOpponentIndex is valid (>= 0), then update x, y and visible properties of AI's model
if (knownOpponentIndex >= 0)
z = knownOpponentIndex;
(*aiCharacter).ai.model.knownOpponents[z].visible = isVisible;
if (isVisible)
(*aiCharacter).ai.model.knownOpponents[z].x = opponent.x;
(*aiCharacter).ai.model.knownOpponents[z].y = opponent.y;
end
end
end
end
frame;
end
end
You'll notice I used the local 'z' variable as an index to access the structs... that is a workaround for the error in the title of this thread. If I
switch to using knownOpponentIndex directly then it complains that I'm accessing private data - which seems quite wrong to me. I'm using private data
in the private scope to access public data... shouldn't give an error...
This code will not work as you think, DIV does not support pointers arrays, the previous statement only tells the compiler an interval control for the
runtime, the pointer is always one, so the statement:
Code:
if(*aiCharacters[x] <= 0)
Does not produce the result you expect, and the compiler should produce a compile error, the correct code should be:
Code:
process AIVisionManager(faction)
private
pointer allOpponents;
pointer aiCharacters;
knownOpponentIndex = -1;
isVisible = false;
begin
allOpponents = GetAllOpponents(faction);
aiCharacters = GetFactionList(faction);
loop
// foreach AI
for (x = 0; x < MAX_CHARACTERS; ++x)
if(aiCharacters[x] <= 0)
continue;
end
// foreach opponent
for (y = 0; y < MAX_CHARACTERS; ++y)
if (allOpponents[y] <= 0)
continue;
end
// can AI see opponent?
isVisible = AILineOfSight(aiCharacters[x].x, aiCharacters[x].y, allOpponents[y].x, allOpponents[y].y);
knownOpponentIndex = -1;
// TODO: Clean this up into a function.
// find index of element where processId == opponent
for (z = 0; z < MAX_CHARACTERS - 1; ++z)
if (aiCharacters[x].ai.model.knownOpponents[z].processId == opponent)
knownOpponentIndex = z;
break;
end
end
if (knownOpponentIndex < 0 && isVisible)
// TODO: Clean this up into a function.
// find next free index
for (z = 0; z < MAX_CHARACTERS - 1; ++z)
if (aiCharacters[x].ai.model.knownOpponents[z].processId <= 0)
knownOpponentIndex = z;
break;
end
end
// visible but previously unknown opponents are added to AI's model
aiCharacter[x].ai.model.knownOpponents[z].processId = opponent;
aiCharacters[x].ai.model.knownOpponentCount++;
end
// if knownOpponentIndex is valid (>= 0), then update x, y and visible properties of AI's model
if (knownOpponentIndex >= 0)
z = knownOpponentIndex;
aiCharacters[x].ai.model.knownOpponents[z].visible = isVisible;
if (isVisible)
aiCharacters[x].ai.model.knownOpponents[z].x = allOpponent[y].x;
aiCharacters[x].ai.model.knownOpponents[z].y = allOpponent[y].y;
end
end
end
end
frame;
end
end
This should produce the correct result, but being only a piece of code I can not test it.
Thanks for taking your time to look through this code! You can actually test it if you like, the project is available here: https://github.com/cmvanb/faust2/
I know that the code I posted produced the desired output (the AI knows the position of the player and turns to look at them), so something is
working... I checked with the debugger, the AI is definitely receiving the player's position, via the global table __goodCharacters.
Maybe there is the issue with the arrays as you pointed out and I just can't see it without testing some more use cases with multiple characters
(right now there's only one AI and one player character).
I'm going to bed now, so I will check the code in action tomorrow... I'll get back to you once I know more
In this period I'm in Linux, I'll see these days if I can compile the latest build I've developed for windows and try out your game so that I can give
you more information/possible solutions.
I've build the last DIV for Linux, downloaded and tried your game.
I've found the cause of the "private external data" error, it's a bug in the compiler, here's an example:
Code:
program test_substructs_access;
global
gci = 3, gcj = 2;
local
struct st
a, b, c;
struct st2[9]
e, f, g;
struct st3[MAX_CHARACTERS - 1]
pID;
x, y;
end
end
end
lci = 3, lcj = 2;
private
pci = 3, pcj = 2;
pid;
pointer p_pid;
begin
pid = id;
p_pid = &pid;
// direct
st.st2[3].st3[2].pID = id; // works OK
st.st2[3].st3[pcj].pID = id; // works OK
st.st2[pci].st3[2].pID = id; // works OK
st.st2[pci].st3[pcj].pID = id; // works OK
// with ID and PRIVATE var as index
pid.st.st2[3].st3[2].pID = id; // works OK
pid.st.st2[3].st3[pcj].pID = id; // error external data
pid.st.st2[pci].st3[2].pID = id; // error external data
pid.st.st2[pci].st3[pcj].pID = id; // error external data
// with pointer ID and PRIVATE var as index
(*p_pid).st.st2[3].st3[2].pID = id; // works OK
(*p_pid).st.st2[3].st3[pcj].pID = id; // error external data
(*p_pid).st.st2[pci].st3[2].pID = id; // error external data
(*p_pid).st.st2[pci].st3[pcj].pID = id; // error external data
// with ID and LOCAL var as index
pid.st.st2[3].st3[2].pID = id; // works OK
pid.st.st2[3].st3[lcj].pID = id; // works OK
pid.st.st2[lci].st3[2].pID = id; // works OK
pid.st.st2[lci].st3[lcj].pID = id; // works OK
// with pointer ID and LOCAL var as index
(*p_pid).st.st2[3].st3[2].pID = id; // works OK
(*p_pid).st.st2[3].st3[lcj].pID = id; // works OK
(*p_pid).st.st2[lci].st3[2].pID = id; // works OK
(*p_pid).st.st2[lci].st3[lcj].pID = id; // works OK
// with ID and GLOBAL var as index
pid.st.st2[3].st3[2].pID = id; // works OK
pid.st.st2[3].st3[gcj].pID = id; // works OK
pid.st.st2[gci].st3[2].pID = id; // works OK
pid.st.st2[gci].st3[gcj].pID = id; // works OK
// with pointer ID and LOCAL var as index
(*p_pid).st.st2[3].st3[2].pID = id; // works OK
(*p_pid).st.st2[3].st3[gcj].pID = id; // works OK
(*p_pid).st.st2[gci].st3[2].pID = id; // works OK
(*p_pid).st.st2[gci].st3[gcj].pID = id; // works OK
end
As you can test from the example, it looks like a bug in the compiler recognizes the PRIVATE variables used as sub-structures indices as members of
the same structures when we access with an ID. Because these are PRIVATE, they make a compilation error that should not.
Returning to your game code, it happens the same when trying to access "if ((*actor).ai.model.knownOpponents[cj].processId <= 0)" if "cj" is
PRIVATE.
You also do not need pointers, "actors[x]" returns the ID you can save in a normal INT variable and then access LOCAL data with it, your code can be
written:
Code:
global
gci, gcj, gck; // global counters for loops
...
process AIModelManager(faction)
private
pointer opponents;
pointer actors;
knownOpponentIndex = -1;
opponent; // INT is sufficient
actor; // INT is sufficient
isVisible = false;
begin
opponents = GetFactionOpponents(faction);
actors = GetFactionActors(faction);
loop
// foreach AI
for (gci = 0; gci < MAX_CHARACTERS; ++gci)
if (actors[gci] <= 0)
continue;
end
actor = actors[gci];
for (gcj = 0; gcj < MAX_CHARACTERS - 1; ++gcj)
if(actor.ai.model.knownOpponents[gcj].processId <= 0)
continue;
end
...
I'm using global counters to avoid the waste of memory by declaring them LOCAL and the bug that prevents you from using the PRIVATE.
As a Suggestion: Avoid using the "x", "y" and especially "z" variables as counter in the cycles to avoid a bad performance impact from the internal
renderer using these variables.
I hope this solves the problems encountered in your game.
Thanks for taking a closer look, really appreciate it!
I will simplify my pointer access as you indicated, I think it got wonky because I was fighting compile errors and once it worked I just left it that
way.
I'm not sure using global counters is a good idea, since I have a lot of processes. If there are two instances of the same process, then every 'frame'
they use the same counter it will cause problems, no? I will just use private vars instead of x/y/z
Thanks for taking a closer look, really appreciate it!
I will simplify my pointer access as you indicated, I think it got wonky because I was fighting compile errors and once it worked I just left it that
way.
I'm happy that the new code has helped you solve problems and simplify things.
I'm not sure using global counters is a good idea, since I have a lot of processes. If there are two instances of the same process, then every 'frame'
they use the same counter it will cause problems, no? I will just use private vars instead of x/y/z
The best thing is to use PRIVATE variables, but the bug prevent you from using them as an index for access to sustructs, but you can use them safetly
for cycles, so you could mix the use of global for substrusts and private for all other uses.