Array size of 1 doesn't work within enums
#1

If you have this code:
pawn Code:
new Houses[1];

public OnGameModeInit()
{
    Houses[0] = 5;

    return 1;
}
It works without problems.
The compiler doesn't generate an error here.

However, if you use the same idea, using an enum, like this:
pawn Code:
enum Test
{
    Houses[1]
}
new Arr[Test];

public OnGameModeInit()
{
    Arr[Houses][0] = 5; // Line 32

    return 1;
}
You get those errors:

Code:
D:\Test\gamemodes\Test.pwn(32) : warning 215: expression has no effect
D:\Test\gamemodes\Test.pwn(32) : error 001: expected token: ";", but found "["
D:\Test\gamemodes\Test.pwn(32) : error 029: invalid expression, assumed zero
D:\Test\gamemodes\Test.pwn(32) : warning 215: expression has no effect
D:\Test\gamemodes\Test.pwn(32) : error 001: expected token: ";", but found "]"
D:\Test\gamemodes\Test.pwn(32) : fatal error 107: too many error messages on one line

Compilation aborted.Pawn compiler 3.2.3664	 	 	Copyright © 1997-2006, ITB CompuPhase


4 Errors.
Using an array with size 2 doesn't generate errors:
pawn Code:
enum Test
{
    Houses[2]
}
new Arr[Test];

public OnGameModeInit()
{
    Arr[Houses][0] = 5;

    return 1;
}
This is causing problems in my housing system, as some players want only one house per player.
So they basically set the size of the Houses array to 1, and they get these errors.
The only solution for now is to use a minimum setting of 2 houses per player.

NOTE:
It seems creating an array of size 1 inside an enum converts the array to an integer, as this seems to work without errors:
pawn Code:
enum Test
{
    Houses[1] // Array with size 1 declared inside the enum
}
new Arr[Test];

public OnGameModeInit()
{
    Arr[Houses] = 5; // Array accessed as if it was an integer

    return 1;
}
Reply
#2

Array size is defaultly 1

if you don't understand, because it's defaulty 1, there's no point to make it 1 again

Also.. this does not happen to me, I have a few old vars in my gamemode that use[1] where I never went back and changed
Reply
#3

I understand arrays perfectly. I use them for years, in different languages too.
I even know the inner workings of arrays.
They are just a block of memory, which starts at a specific memory-address (this address is index 0).
The index of an array is just an offset for every index, in pawn these indices are 1 byte large.
Accessing index 5 means you're getting the value stored in the memory-address 5 bytes further than the starting-address of the array.
Say your array starts at memory-address 0x0000FA00, then index 5 would be at address 0x0000FA05. Simple.

It's just that pawn converts an array with size 1 into a normal integer when it's defined inside an enum, while it doesn't do that when it's declared outside an enum.
This is confusing for the programmer.
In one case, the compiler leaves the data as it is, in the other case it just converts stuff automatically without informing the programmer and only generates an error.
While you use both cases the same way.
The programmer's code is fine, but gets buggy because of this automatic conversion by the compiler.

When you declare an array with size 1 (only index 0), it should stay defined as an array, wether it's defined inside an enum or outside.
But declaring an array with only one index inside an enum is converted to an integer by PAWN automatically without the programmer's knowledge.
Declaring the same array outside an enum stays defined as an array, it isn't converted to an integer.

In my gamemode, I'm using this:
pawn Code:
#define MAX_HOUSESPERPLAYER 2

enum TPlayerData
{
    Houses[MAX_HOUSESPERPLAYER], // Holds the HouseID's of the houses that the player owns (index of the AHouseData array)
    CurrentHouse, // Holds the HouseID to track in which house the player currently is (used when accessing the housemenu)
    Business[MAX_BUSINESSPERPLAYER], // Holds the BusinessID's of the business that the player owns
    CurrentBusiness, // Holds the BusinessID to track in which business the player currently is (used when accessing the businessmenu)
}
// Create an array to hold the playerdata for every player
new APlayerData[MAX_PLAYERS][TPlayerData];



// This function returns the first free house-slot for the given player
Player_GetFreeHouseSlot(playerid)
{
    // Check if the player has room for another house (he hasn't bought the maximum amount of houses per player yet)
    // and get the slot-id
    for (new HouseIndex; HouseIndex < MAX_HOUSESPERPLAYER; HouseIndex++) // Loop through all house-slots of the player
        if (APlayerData[playerid][Houses][HouseIndex] == 0) // Check if this house slot is free
            return HouseIndex; // Return the free HouseIndex for this player

    // If there were no free house-slots, return "-1"
    return -1;
}
This is only part of my TPlayerData enum, but enough to see the problem.
And there is a function which checks the first free slot in the player's account to store the HouseID in case a player buys a new house.

Since the Houses[MAX_HOUSESPERPLAYER] is declared as an array and throughout the gamemode (like in the function) alot of code loops through this array to do something, it causes alot of problems when users of my gamemode set MAX_HOUSESPERPLAYER to 1 (I have it set to 20 and it doesn't generate errors).
Because pawn converts that array into an integer, it's not an array anymore and all the code accessing that array just fails.

An array with size 1 has should have only one index: index 0 (or offset).
Using the for-loop as in the function to loop through only one index is still fine.
It's just this line that causes a problem:
pawn Code:
if (APlayerData[playerid][Houses][HouseIndex] == 0) // Check if this house slot is free
Since there is no extra index anymore (the HouseIndex parameter is gone by the conversion from array to integer), that line fails.

I just hate that a compiler just converts such things automatically.
It should stay as an array, then the code would be fine.



I guess the only fix here (to prevent this automatic conversion), is to define the array inside the enum with a fixed size (say 20, since I have 20 houses per player on my own server).
And define the MAX_HOUSESPERPLAYER as 1.
Then only the loops use this value, but the array stays an array (with 20 indices, of which 19 are not used).
Like this:
pawn Code:
#define MAX_HOUSESPERPLAYER 1

enum TPlayerData
{
    Houses[20], // Holds the HouseID's of the houses that the player owns (index of the AHouseData array)
    CurrentHouse, // Holds the HouseID to track in which house the player currently is (used when accessing the housemenu)
    Business[10], // Holds the BusinessID's of the business that the player owns
    CurrentBusiness, // Holds the BusinessID to track in which business the player currently is (used when accessing the businessmenu)
}
// Create an array to hold the playerdata for every player
new APlayerData[MAX_PLAYERS][TPlayerData];



// This function returns the first free house-slot for the given player
Player_GetFreeHouseSlot(playerid)
{
    // Check if the player has room for another house (he hasn't bought the maximum amount of houses per player yet)
    // and get the slot-id
    for (new HouseIndex; HouseIndex < MAX_HOUSESPERPLAYER; HouseIndex++) // Loop through all house-slots of the player
        if (APlayerData[playerid][Houses][HouseIndex] == 0) // Check if this house slot is free
            return HouseIndex; // Return the free HouseIndex for this player

    // If there were no free house-slots, return "-1"
    return -1;
}
Reply
#4

Can confirm, some crap happens with a 8 bit array if it's small.
Reply
#5

That could by right, but this is PAWN bug, I guess that it was fixed in the some version (next for our currently version) of the language. SA-MP could do nothing with that.
Reply
#6

Yes, I figured this would be a pawn bug.
But by reporting it here, other users are informed if they encounter such problems too.
Reply
#7

Surely other PAWN versions have this fixed. The current compiler we're using is back in the 2006-2009's so yeah, the pawn developers have released a big update on pawn this year.
Reply
#8

In my opinion, enum's are the only way to get something, which is at least a bit similar to classes in object-orientated languages.

But they are not well-made, there are loads of problems.

E.g. if a variable in an enum does not exist, you get this error:

Quote:
Originally Posted by Pawno
error 022: must be lvalue (non-constant)
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)