PDA

View Full Version : Multi-Dimensional Array converted to Dynamic Array


Exolent[jNr]
04-27-2008, 03:01
I'm trying to convert some arrays into dynamic arrays so I can input as much info as I need.

Here are the default arrays:#define MAX_SERVERS 50
#define MAX_CHANNELS 50

new g_iServerCount;
new g_sServers[MAX_SERVERS][32];

new g_iChannelCount[MAX_SERVERS];
new g_sChannels[MAX_SERVERS][MAX_CHANNELS][32];

The way it works, is there are 50 possible servers, and for every server, there are 50 possible channels.
But, I don't want to make limits.

So far, I've gotten this:enum __serverdata
{
__serverdata_sName[32],
__serverdata_iChannelCount
};
new g_iServerCount;
new Array:g_aServerData;

public plugin_cfg()
{
g_aServerData = ArrayCreate(2);
}
But, I'm stumped on how to include the unlimited channel names for each server.

Note: I will be use ArrayGetArray() and ArrayPushArray() natives.

ConnorMcLeod
04-27-2008, 03:57
May you provide an example of how your arrays are filled.

Exolent[jNr]
04-27-2008, 04:22
#define MAX_SERVERS 50
#define MAX_CHANNELS 50

new g_iServerCount;
new g_sServers[MAX_SERVERS][32];

new g_iChannelCount[MAX_SERVERS];
new g_sChannels[MAX_SERVERS][MAX_CHANNELS][32];

public plugin_init()
{
load_servers();
}

bool:load_servers()
{
new sFileName[200];
new iFileNameLen = sizeof(sFileName) - 1;
get_configsdir(sFileName, iFileNameLen);
add(sFileName, iFileNameLen, "/voice_servers.ini");
if(!file_exists(sFileName))
{
log_amx("Couldn't find %s", sFileName);
return false;
}

new file = fopen(sFileName, "rt");
if(!file)
{
return false;
}

new iServer;
new iChannelLen = sizeof(g_sChannels[][]) - 1;
for(iServer = 0; iServer < MAX_SERVERS; iServer++)
{
copy(g_sChannels[iServer][g_iChannelCount[iServer]++], iChannelLen, "Lobby");
}

new sData[128];
new iDataLen = sizeof(sData) - 1;
new iLen;

new iServerLen = sizeof(g_sServers[]) - 1;

iServer = -1;
new iChannel;
while(!feof(file) && (g_iServerCount < MAX_SERVERS))
{
fgets(file, sData, iDataLen);
switch(sData[0])
{
case '[': // new server
{
if(iServer != -1)
{
g_iServerCount++;
}

iLen = strlen(sData) - 2; // calculate to last character
if(sData[iLen] == ']')
{
sData[iLen] = 0;
}

format(sData, iDataLen, "%s", sData[1]);
replace_all(sData, iDataLen, "^n", "");

iServer = g_iServerCount;
copy(g_sServers[iServer], iServerLen, sData);
}
case '+': // new channel
{
if(iServer == -1)
{
continue;
}

if(g_iChannelCount[iServer] >= MAX_CHANNELS)
{
continue;
}

format(sData, iDataLen, "%s", sData[1]);
replace_all(sData, iDataLen, "^n", "");

iChannel = g_iChannelCount[iServer]++;
copy(g_sChannels[iServer][iChannel], iChannelLen, sData);
}
}
}

if(iServer != -1)
{
g_iServerCount++;
}

fclose(file);

return (g_iServerCount > 0);
}

The file format is like so:

[Clan Server]
+Chill Channel
+Other

[Public Server]
+Channel 1
+Channel 2
+Channel 3

Arkshine
04-27-2008, 05:35
You can't save strings into an Array of array.

Either you create one Array per string array either you can create an Array of array but you have to convert the string input into number. Using :


EncodeText( const text[] )
{
return engfunc( EngFunc_AllocString, text )
}

DecodeText( const text, string[], const length )
{
global_get( glb_pStringBase, text, string, length )
}

Exolent[jNr]
04-27-2008, 13:47
Thanks arkshine.
Now, how do I add unlimited channel names per server as well?
I thought of an idea but I don't know how well it will work:

Create a global channel name Array and save start/end for each server

enum __serverdata
{
__serverdata_sName,
// __serverdata_iChannelCount, this can be found by (End - Start)
__serverdata_iChannelStart,
__serverdata_iChannelEnd
};
new g_iServerCount;
new Array:g_aServerData;

new g_iChannelCount;
new Array:g_aChannelNames;

public plugin_cfg()
{
g_aServerData = ArrayCreate(3);
g_aChannelNames = ArrayCreate(1);
}

myfunc(iServer)
{
new aServerData[__serverdata];
ArrayGetArray(g_aServerData, iServer, aServerData);

new sServerName[32];
DecodeText(aServerData[__serverdata_sName], sServerName, sizeof(sServerName) - 1;

new sChannelName[32];
new iChannelLen = sizeof(sChannelName) - 1;
for(new i = aServerData[__serverdata_iChannelStart]; i <= aServerData[__serverdata_iChannelEnd]; i++)
{
ArrayGetString(g_aChannelNames, i, sChannelName, iChannelLen);
// sChannelName should hold each channel for iServer
}
}

Now, am I wrong, or is this a good idea?

Exolent[jNr]
04-29-2008, 22:34
Okay, so I have this new way of doing it.
Now, I need to know how to make 2 global variables for players.
1. Has to relate player to server.
2. Has to relate player to channel of the server player is related to.
But, I need the channel one to not be dependent on one server.
I need the channel one to be able to check for every server loaded.

Here is what I have so far for the other data:enum __serverdata
{
__serverdata_iChannelCount,
__serverdata_aChannelNames
};
new g_iServerCount;
new g_aServerData;
new g_aServerNames;

bool:load_servers()
{
new sFileName[200];
new iFileNameLen = sizeof(sFileName) - 1;
get_configsdir(sFileName, iFileNameLen);
add(sFileName, iFileNameLen, "/voice_servers.ini");
if(!file_exists(sFileName))
{
log_amx("Couldn't find %s", sFileName);
return false;
}

new file = fopen(sFileName, "rt");
if(!file)
{
return false;
}

new sData[128];
new iDataLen = sizeof(sData) - 1;
new iLen;

new iChannelLen = sizeof(g_sChannels[][]) - 1;

new iServer = -1;
new iChannelCount;

new aServerData[__serverdata];
while(!feof(file))
{
fgets(file, sData, iDataLen);
log_amx("Found Data: %s", sData);
switch(sData[0])
{
case '[': // new server
{
if(iServer != -1)
{
aServerData[__serverdata_iChannelCount] = iChannelCount;
ArrayPushArray(g_aServerData, iServer, aServerData);
}
else
{
g_aServerData = ArrayCreate();
g_aServerNames = ArrayCreate();
}

iLen = strlen(sData) - 2; // calculate to last character
if(sData[iLen] == ']')
{
sData[iLen] = 0;
}

format(sData, iDataLen, "%s", sData[1]);
replace_all(sData, iDataLen, "^n", "");

iServer = g_iServerCount++;
iChannelCount = 0;
aServerData[__serverdata_aChannelNames] = ArrayCreate();
ArrayPushString(g_aServerNames, iServer, sData);
ArrayPushString(aServerData[__serverdata_aChannelNames], iChannelCount++, "Lobby");
}
case '+': // new channel
{
if(iServer == -1)
{
continue;
}

format(sData, iDataLen, "%s", sData[1]);
replace_all(sData, iDataLen, "^n", "");
ArrayPushString(aServerData[__serverdata_aChannelNames], iChannelCount++, sData);
}
}
}

if(iServer != -1)
{
aServerData[__serverdata_iChannelCount] = iChannelCount;
ArrayPushArray(g_aServerData, iServer, aServerData);
}

fclose(file);
return (g_iServerCount > 0);
}

And here are the two variables I need to convert:new bool:g_bInServer[33][MAX_SERVERS]; // is player in specific server?
new g_iChannel[33][MAX_SERVERS]; // channel player is in in that server

Now, this would be easy if it was 1 server and 1 channel to check, but I'd like multiple servers for each player.
Also, I thought of saving the users in the serverdata array,
but then I think that would be an inefficient way checking each time if a player is in the server, then iterating through all the channels to find which channel the player is in.