• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM Setting up a list in a script can't be read by objects even if it's global?

X

XirmiX

Guest
Well... the title pretty much says it all. Even when the list is set to global, no object can find it for some reason. Am I using scripts wrong or am I missing something?
 
W

whale_cancer

Guest
Well... the title pretty much says it all. Even when the list is set to global, no object can find it for some reason. Am I using scripts wrong or am I missing something?
If you set the list to global or access it by using the id of the executing object... well, there is no reason you shouldn't be able to access it normally. We will need to see your code to say anything more.
 
X

XirmiX

Guest
If you set the list to global or access it by using the id of the executing object... well, there is no reason you shouldn't be able to access it normally. We will need to see your code to say anything more.
Okay:
Script code:
Code:
//Account login details and mechanisms
username = "username";
global.password = ds_list_create();
ds_list_add(global.password, "password");
Login button Step event code:
Code:
if keyboard_check(vk_enter)
{
    if script_exists(obj_login_bar.username_login_text)
    {
        if obj_password_bar.password_login_text == ds_list_find_value(global.password, 0)
        { 
            room_goto_next();
        }
        else
        {
            show_message("The username and/or password you've entered is incorrect");
        }
    }
    else
    {
        show_message("The username and/or password you've entered is incorrect");
    }
}
obj_login_bar is an object within which you can enter a username and obj_password_bar is the same, but in terms of password.
 
W

whale_cancer

Guest
Looks like you are using script_exists incorrectly. Scripts exist as assets in GM, they do not belong to the instance or object that executes them. Simply deleting that if statement should fix your problem.

Edit: There doesn't seem to be any reason to include a failsafe script_exists in your application here.
 
X

XirmiX

Guest
Looks like you are using script_exists incorrectly. Scripts exist as assets in GM, they do not belong to the instance or object that executes them. Simply deleting that if statement should fix your problem.

Edit: There doesn't seem to be any reason to include a failsafe script_exists in your application here.
The thing is that within that script, I have created a list. And I need that list to be within that script and for the object to take that list and carry out a check when necessary. If this is not possible... I'll have to go turn that script into a text file and "ugh" whilst trying to make the code within the object read the text file where necessary. Unless there's another way to go about these things.
 
W

whale_cancer

Guest
The thing is that within that script, I have created a list. And I need that list to be within that script and for the object to take that list and carry out a check when necessary. If this is not possible... I'll have to go turn that script into a text file and "ugh" whilst trying to make the code within the object read the text file where necessary. Unless there's another way to go about these things.
Can you post the script in question?
 
X

XirmiX

Guest
Can you post the script in question?
Well... I did; in my last post:
Code:
//Account login details and mechanisms
username = "username";
global.password = ds_list_create();
ds_list_add(global.password, "password");
That's the code that is of importance in relation to the login button and such. There is more, but it's unrelated and unused atm.
 
W

whale_cancer

Guest
Well... I did; in my last post:
Code:
//Account login details and mechanisms
username = "username";
global.password = ds_list_create();
ds_list_add(global.password, "password");
That's the code that is of importance in relation to the login button and such. There is more, but it's unrelated and unused atm.
So you haven't changed your code at all? Have you tried my suggestion a few posts back already? What happened?

Edit: I define various data structures in scripts to initialize them all the time for my RPG project. I know there is no reason you can't normally access those data structures from outside the script without something unusual going on. Please let me know what happens when you try my suggestion.
 
X

XirmiX

Guest
So you haven't changed your code at all? Have you tried my suggestion a few posts back already? What happened?

Edit: I define various data structures in scripts to initialize them all the time for my RPG project. I know there is no reason you can't normally access those data structures from outside the script without something unusual going on. Please let me know what happens when you try my suggestion.
It does the same thing it did before; give me the following error:
FATAL ERROR in
action number 1
of Step Event0
for object obj_login_button:


global variable password(100000, -2147483648) not set before reading it.
at gml_Object_obj_login_button_StepNormalEvent_1 (line 11) - if obj_password_bar.password_login_text == ds_list_find_value(global.password, 0)
############################################################################################

But the thing is that global.password does exist, but as a list and not a variable and it exists inside the script not the object, which, considering it is global doesn't seem to make any sense.
 

TheouAegis

Member
Post your project (the gmz). Because obviously you're doing something wrong somewhere in your project and not where the aforementioned codes are concerned.

Also, I can't remember if this was ever touched upon, but is the code that creates the list being run from a different object? If so, is that object in a room that is run prior to the one with the player/?
 
X

XirmiX

Guest
Post your project (the gmz). Because obviously you're doing something wrong somewhere in your project and not where the aforementioned codes are concerned.

Also, I can't remember if this was ever touched upon, but is the code that creates the list being run from a different object? If so, is that object in a room that is run prior to the one with the player/?
The list is created in the script. I explained this a multitude of times and showed the script code myself! And I don't think giving away the file would be a good idea. Regardless, the error itself explains that the problem arises from the code that I've already presented and it's with the list called password; it cannot find it, even though it's within a script.
 
T

TimothyAllen

Guest
The list is created in the script. I explained this a multitude of times and showed the script code myself! And I don't think giving away the file would be a good idea. Regardless, the error itself explains that the problem arises from the code that I've already presented and it's with the list called password; it cannot find it, even though it's within a script.
The script MUST BE CALLED from an object or room creation code... having it in a script doesnt make it exist.
 
X

XirmiX

Guest
The script MUST BE CALLED from an object or room creation code... having it in a script doesnt make it exist.
Okay, I tried a few things and the problem is that I can't seem to be able to do one thing that I want to do. This being; I want the program to check whether the script, of who's name the input from the user (that is held in a completely different object than from the one that this exact code I am writing exists in) has been provided actually exists (so, if the user typed in "username", the game would go and look for a script called "username"). This is for the username. After that, I want the program to go inside the same script as before and check for whether the user has also entered the password correctly (this text input is held in a completely different object), which would be different for each script/username. Remember that I cannot just ask it to check for an argument in this specific script, but it has to be the script that the user has typed in and if that script doesn't even exist, then the program should display the following message: "The username and/or password you've entered is incorrect".

And I cannot do the above, because the program doesn't understand that the user input IS the script that it needs to check for. So, how would I even do this?
 

TheouAegis

Member
So if the script's name is username and the player enters the text "username" somewhere, then you'd use asset_get_index() to get the ID of script username (which would return -1 if the user entered an incorrect script name). Then the first line of the script would check if the password_login_text is the same as the value in wherever the original password was saved.

But if we're storing username-password pairs, why not just store the username as the key in a ds_map and the password as the index and use ds_map_secure_write (or whatever the function is) to save the map somewhere, then load the map at startup if it exists. It's less dynamic and should have fewer issues.

Code:
var a = ds_map_find_value(user_list, username_login_text);
if !is_undefined(a)
    if a == password_login_text
        //do whatever
 
X

XirmiX

Guest
So if the script's name is username and the player enters the text "username" somewhere, then you'd use asset_get_index() to get the ID of script username (which would return -1 if the user entered an incorrect script name). Then the first line of the script would check if the password_login_text is the same as the value in wherever the original password was saved.

But if we're storing username-password pairs, why not just store the username as the key in a ds_map and the password as the index and use ds_map_secure_write (or whatever the function is) to save the map somewhere, then load the map at startup if it exists. It's less dynamic and should have fewer issues.

Code:
var a = ds_map_find_value(user_list, username_login_text);
if !is_undefined(a)
    if a == password_login_text
        //do whatever
1) Well... not exactly. This could bring up some problems with other asset names being typed in, such as sprite names and other scripts, which are not accounts. Although I could do this via locking away some names, this can potentially be bad when I'm considering adding new content to the game whilst the game itself is already out for public and can interfere with public usernames (although making sure that each asset has an underscore and making it so that users can't type in underscores themselves when creating an account/logging in could solve the problem... yeah, I'll do that if I have not already!). And for the password, perhaps I could use an alarm and checking for in which room the game is in in order to make sure that the script is still functioning well in other rooms to check for the player's inventory (because the script where the password and the username of an account is stored will also include inventory or garage items that the player has on that particular account and also their experience, in-game currency and stuff like that).

2) I do not see this being feasible, after checking a bit of the ds_map stuff and considering the last sentence of the above point I made.

Now I'm at a point where still, the game cannot understand that the following:
Code:
asset_get_index(obj_login_bar.username_login_text).list_add
Means [name of the script defined].list_add and NOT [name of the object that this code is being written in].list_add
Why does it do this? And no, I cannot simply add a script command so that the game checks the script every step, because the script itself is an account, which is something that MAY or MAY NOT exist. Ugh, so annoying, I've been stuck on this bull💩💩💩💩 for like over a week now. The error the game gives me, btw is this:
ERROR!!! :: ############################################################################################
FATAL ERROR in
action number 1
of Step Event0
for object obj_login_button:


Variable obj_login_button.list_add(100041, -2147483648) not set before reading it.
at gml_Object_obj_login_button_StepNormalEvent_1 (line 11) - obj_login_bar.username_login_text = list_add;
############################################################################################

And the script code is almost the same as before:
Code:
list_add = argument0;
list_check_value = argument1;

list_add = ds_list_add(password, "password");
list_check_value = ds_list_find_value(password, 0);
 

Yal

🐧 *penguin noises*
GMC Elder
Well... the title pretty much says it all. Even when the list is set to global, no object can find it for some reason. Am I using scripts wrong or am I missing something?
Yes.

To be a little more helpful, one of the more likely reasons is that the list is referred before actually created - Room Start and Game Start events are run AFTER the Create events, and Create events are run in the order stuff is placed in the room, so if you refer to the list in a Create event chances are it's not just created yet. (I usually make a mock title screen very early in development so I can create global stuff like this there so it's ready for all the game rooms).
 
X

XirmiX

Guest
Yes.

To be a little more helpful, one of the more likely reasons is that the list is referred before actually created - Room Start and Game Start events are run AFTER the Create events, and Create events are run in the order stuff is placed in the room, so if you refer to the list in a Create event chances are it's not just created yet. (I usually make a mock title screen very early in development so I can create global stuff like this there so it's ready for all the game rooms).
But the action that refers to a list inside a script is inside a Step event... AND it is only activated once I press Enter. So this does not make sense, considering the above post, for some reason.
 
E

Efrik

Guest
If the problem is that some "create" events run before others you can change the order objects are created in the room in room/settings/instance order. Ot that´s what I think.
 
T

TimothyAllen

Guest
Means [name of the script defined].list_add and NOT [name of the object that this code is being written in].list_add
Why does it do this? And no, I cannot simply add a script command so that the game checks the script every step, because the script itself is an account, which is something that MAY or MAY NOT exist. Ugh, so annoying, I've been stuck on this bull**** for like over a week now. The error the game gives me, btw is this:
You do not understand how scripts work. Scripts ARE NOT INSTANCES. Because a script exists in the asset tree does not mean that any variables declared or defined in the script exist. YOU MUST CALL THE SCRIPT. Let me show you a quick example:

SCRIPT: ExampleScript
Code:
var localVariable = 10;
instanceVariable = 15;
global.globalVariable = 20;
In the script above, NONE of the variables exist until the script is called! Once called, localVariable will only exist until the end of the script execution... thats why its called local. Its local to the current scope. instanceVariable will exist in any instance that calls this script. So if 5 instances call the script, each of those instance will have THEIR OWN VARIABLE called "instanceVariable"... ie, changing the value in one instance will not effect the value in other instances. globalVariable will be in the global scope. If 5 instances call this script ONLY ONE variable, "globalVariable" exists and must be accessed using global.globalVariable. BUT if the script never get called, regardless that it is in the asset tree, none of the variables will ever be declared nor initialized.

EDIT: Also, ds_list_add returns nothing.
 
X

XirmiX

Guest
You do not understand how scripts work. Scripts ARE NOT INSTANCES. Because a script exists in the asset tree does not mean that any variables declared or defined in the script exist. YOU MUST CALL THE SCRIPT. Let me show you a quick example:

SCRIPT: ExampleScript
Code:
var localVariable = 10;
instanceVariable = 15;
global.globalVariable = 20;
In the script above, NONE of the variables exist until the script is called! Once called, localVariable will only exist until the end of the script execution... thats why its called local. Its local to the current scope. instanceVariable will exist in any instance that calls this script. So if 5 instances call the script, each of those instance will have THEIR OWN VARIABLE called "instanceVariable"... ie, changing the value in one instance will not effect the value in other instances. globalVariable will be in the global scope. If 5 instances call this script ONLY ONE variable, "globalVariable" exists and must be accessed using global.globalVariable. BUT if the script never get called, regardless that it is in the asset tree, none of the variables will ever be declared nor initialized.

EDIT: Also, ds_list_add returns nothing.
So, in that case, how do I make an object call a script in a way I've described? Like, call out the script with the name that is typed inside the username bar (object) when Enter is pressed. And if the script exists, for the program to go to the next room, but if it doesn't to then display a message, saying that either the password or the username is incorrect? Because I cannot simply drag-and-drop in step event a command that tells me which script to call out, because 1) The script might not exist 2) The script which is called out is dependent on what the user types in and is not fixed to a particular script.

I also tried tried to make it work via the command "script_execute":
(Script code)
Code:
argument0 = list_add;
list_add = ds_list_add(password, "password");
(Object obj_login_button code (Step Event))
Code:
if keyboard_check(vk_enter)
{
        if script_exists(obj_login_bar.username_login_text)
        {
            var password = ds_list_create();
            script_execute(obj_login_bar.username_login_text, list_add);
            if obj_password_bar.password_login_text == ds_list_find_value(password, 0)
            {
                room_goto_next();
            }
            else
            {
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else
        {
            show_message("The username and/or password you've entered is incorrect");
        }
}
But it still gives me the same error:
Code:
############################################################################################
FATAL ERROR in
action number 1
of  Step Event0
for object obj_login_button:

Variable obj_login_button.list_add(100070, -2147483648) not set before reading it.
at gml_Object_obj_login_button_StepNormalEvent_1 (line 7) -             script_execute(obj_login_bar.username_login_text, list_add);
############################################################################################
 

TheouAegis

Member
The login text is a string. You cannot pass a string as the first argument in script_execute. You must get the asset index.

var user = asset_get_index(obj_login_bar.username_login_text);
if is_undefined(user) return 0; //if no such asset exists, end this script

You'd then pass the variable to script_execute.

script_execute(user, list_add)

Also, ds_list_add() doesn't return anything, so list_add will never be set. It will remain undefined.
 
X

XirmiX

Guest
The login text is a string. You cannot pass a string as the first argument in script_execute. You must get the asset index.

var user = asset_get_index(obj_login_bar.username_login_text);
if is_undefined(user) return 0; //if no such asset exists, end this script

You'd then pass the variable to script_execute.

script_execute(user, list_add)

Also, ds_list_add() doesn't return anything, so list_add will never be set. It will remain undefined.
Sorry for my stupidity, but how do I return the password string? How does it work? There isn't such a command as ds_list_return(). I tried searching for some string commands over here, but I couldn't find anything that could particularly help me out. I'm asking this because it keeps giving me the same error, even though I have the script being read, arguments taken from it, yet the program treats the arguments as if they're variables in the object itself and not within the script. Also wouldn't ds_list_find_value(id,value) return it to the object from the script or am I misunderstanding something?

Edit: Okay so why is it that when I do this in the object:
Code:
script_execute(user, list_add, list_return);
It gives me this error:
FATAL ERROR in
action number 1
of Step Event0
for object obj_login_button:

Variable obj_login_button.list_return(100071, -2147483648) not set before reading it.
at gml_Object_obj_login_button_StepNormalEvent_1 (line 12) - script_execute(user, list_add, list_return);
############################################################################################

It makes no sense! The function itself, in the manual says that script_execute opens up a script and then everything following with commas is the arguments that it should execute. So why does the program treat them like variables of the object?
 
Last edited by a moderator:

Tsa05

Member
I think there's a misunderstanding about what scripts are, maybe. Scripts are a GameMaker resource, and they show up in your resource tree. It sounds like you're asking the player to type in the name of a resource in your project. It would be like telling the player "Tell me the name of a sprite I packed into this game." And then, if the player happens to type in sprite0, you draw that sprite.

To clarify, is that what you are trying to do?


Edit:
Are you just trying to do a login box? If you have 2 objects that are storing some text: obj_login_bar.username_login_text and obj_password_bar.password_login_text. And when the user presses Enter, you just want to check whether the password was in a list somewhere. Right?

So, the stuff that you called your script code up in the first post--put that into the Create event of obj_login_button:
Code:
//Account login details and mechanisms
username = "username";
global.password = ds_list_create();
ds_list_add(global.password, "password");
That will solve the issue of no variable being defined.
It won't quite work like a login box, but at least it will advance to the next room whenever "password" is typed into the password box.
 
Last edited:
X

XirmiX

Guest
I think there's a misunderstanding about what scripts are, maybe. Scripts are a GameMaker resource, and they show up in your resource tree. It sounds like you're asking the player to type in the name of a resource in your project. It would be like telling the player "Tell me the name of a sprite I packed into this game." And then, if the player happens to type in sprite0, you draw that sprite.

To clarify, is that what you are trying to do?



Edit:
Are you just trying to do a login box? If you have 2 objects that are storing some text: obj_login_bar.username_login_text and obj_password_bar.password_login_text. And when the user presses Enter, you just want to check whether the password was in a list somewhere. Right?

So, the stuff that you called your script code up in the first post--put that into the Create event of obj_login_button:
Code:
//Account login details and mechanisms
username = "username";
global.password = ds_list_create();
ds_list_add(global.password, "password");
That will solve the issue of no variable being defined.
It won't quite work like a login box, but at least it will advance to the next room whenever "password" is typed into the password box.
Yes, thank you. That is exactly what I am trying to do. Of course, after login system is done and working, I'll be getting onto registering system afterwards, and then game's UI and then probably connection and finally adding the rest of the content that the player will be able to use as well (that's the current plan, more or less). It would be smart of me to store account information on text files and not scripts. However, the problem is that it is quite tedious and it just makes me go "Ugh" whenever I look back at a code someone gave me for making the program try and read an external file. If I can make the script be possible to be read, scripts to be possible to be created whilst the game is running or after the game has been shut down, then I would very much like to do this as it is much easier to work with scripts (code wise) that I've found than with external files.

There's gotta be a way I can make the game read the script and have the script return a value from a list that is either created in the script itself or the object that is calling it out. There's gotta be, otherwise... it's like they're some sort of icing on top in the engine, so why not just use objects for everything?
 

Tsa05

Member
Ahh, I see.
A future problem you will encounter with using scripts for this is that scripts must be packed within your game in order to be read. In other words, every time a new player registers, you will need to add their info to your game (manually), and then re-package the game with the new script. Instead of re-writing the whole player setup script over and ever for each username, your game really would benefit from external files.

First, let's look at the system you're working on and figure out the error.
You have a script that sets the value of list_add when it runs.
You have some code that runs when the Enter key is pressed that does this: script_execute(user, list_add, list_return);
That code can never work. When you press Enter, you're telling GameMaker the do the following steps:

1) Execute the script using the info I'm about to give you in step 2
2) The script is called user, and it has 2 pieces of data that it needs, called list_add and list_return
3) Now that the script called user is running, get the value of list_add
4) Finally, set the value of list_add

Do you see why this cannot work? List_add does not exist when you call script_execute. It only exists when the last line of the script has been run. The code that you are using tries to send the value of list_add into the script, but it does not exist yet!

Also, remember that when you send data into a script, the data is mapped onto the arguments variables...
For your login system, you need to send the password into the script, probably. Let's look at something like this:

Object obj_login_button code (Step Event)
Code:
if keyboard_check(vk_enter)
{
        if script_exists(obj_login_bar.username_login_text)
        {
            success = script_execute(obj_login_bar.username_login_text, obj_password_bar.password_login_text );
            if success == true
            {
                room_goto_next();
            }
            else
            {
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else
        {
            show_message("The username and/or password you've entered is incorrect");
        }
}
A script called "username"
Code:
if argument0 == "password"
{
     return true;
}else
{
     return false;
}
That's all you need!! There's no need to send back the password at all. When you do the script_execute line, you can pass along the password box text as a value to check. The script can check the value, and then return true or false depending on whether it matches the user's password. In the code example above, I stored the return value of script_execute() into a variable called success. If it's true, go to the next room. If false, show the error.

Does that make sense?

If so, I'll be happy to show you how to turn this system into a simple external file loading one.
 
X

XirmiX

Guest
Ahh, I see.
A future problem you will encounter with using scripts for this is that scripts must be packed within your game in order to be read. In other words, every time a new player registers, you will need to add their info to your game (manually), and then re-package the game with the new script. Instead of re-writing the whole player setup script over and ever for each username, your game really would benefit from external files.

First, let's look at the system you're working on and figure out the error.
You have a script that sets the value of list_add when it runs.
You have some code that runs when the Enter key is pressed that does this: script_execute(user, list_add, list_return);
That code can never work. When you press Enter, you're telling GameMaker the do the following steps:

1) Execute the script using the info I'm about to give you in step 2
2) The script is called user, and it has 2 pieces of data that it needs, called list_add and list_return
3) Now that the script called user is running, get the value of list_add
4) Finally, set the value of list_add

Do you see why this cannot work? List_add does not exist when you call script_execute. It only exists when the last line of the script has been run. The code that you are using tries to send the value of list_add into the script, but it does not exist yet!

Also, remember that when you send data into a script, the data is mapped onto the arguments variables...
For your login system, you need to send the password into the script, probably. Let's look at something like this:

Object obj_login_button code (Step Event)
Code:
if keyboard_check(vk_enter)
{
        if script_exists(obj_login_bar.username_login_text)
        {
            success = script_execute(obj_login_bar.username_login_text, obj_password_bar.password_login_text );
            if success == true
            {
                room_goto_next();
            }
            else
            {
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else
        {
            show_message("The username and/or password you've entered is incorrect");
        }
}
A script called "username"
Code:
if argument0 == "password"
{
     return true;
}else
{
     return false;
}
That's all you need!! There's no need to send back the password at all. When you do the script_execute line, you can pass along the password box text as a value to check. The script can check the value, and then return true or false depending on whether it matches the user's password. In the code example above, I stored the return value of script_execute() into a variable called success. If it's true, go to the next room. If false, show the error.

Does that make sense?

If so, I'll be happy to show you how to turn this system into a simple external file loading one.

So, I guess this clears something up about arguments... arguments are things that get received by the script? If so, what does the whole 0, 1, 2 behind them mean? Does it mean the order of which arguments have been passed onto the script from objects or whatever other files? So, object 1 calls out a script first, so if argument 0 exists, it gets executed? A bit strange, but ok.

Only one thing... if the script is not the first in the list that it checks, it display the message instead of going to the next room... this is bad for having multiple accounts and I would guess this happens because it only checks the first script in the list and not all of the lists to see which one has the entered name or something.
 

Tsa05

Member
=)

Yep, arguments are the things received by the script. So if I do this:
my_script("A", "B", "C", "D")

That's 4 things sent to the script. When the script runs, it knows 4 values:
argument0
argument1
argument2
argument3

(In programming, we often start counting at zero)

So, if I run this code my_script("A", "B", "C", "D") the script will know these things:
argument0 is "A"
argument1 is "B"
argument2 is "C"
argument3 is "D"
 
X

XirmiX

Guest
=)

Yep, arguments are the things received by the script. So if I do this:
my_script("A", "B", "C", "D")

That's 4 things sent to the script. When the script runs, it knows 4 values:
argument0
argument1
argument2
argument3

(In programming, we often start counting at zero)

So, if I run this code my_script("A", "B", "C", "D") the script will know these things:
argument0 is "A"
argument1 is "B"
argument2 is "C"
argument3 is "D"
Huh... that can get pretty tedious, but okay. But emm...

=> "Only one thing... if the script is not the first in the list that it checks, it display the message instead of going to the next room... this is bad for having multiple accounts and I would guess this happens because it only checks the first script in the list and not all of the lists to see which one has the entered name or something."

Any way to fix that? Because why would script_exists check only the first script and not run down the list of scripts in the whole game? Or perhaps the object checks the right script, but for whatever reason sends stuff to call out an argument in a completely different script (script first in the script folder)? Or if not, then what the heck is going on here?
 

TheouAegis

Member
username_login_text is a string, is it not? The player himself enters the value, correct? In which case, you did not retrieve the asset index yet. You must use the function

asset_get_index(obj_login_bar.username_login_text)

to retrieve the asset index for use in script_exists(). The reason it is returning only the first script is because you did not get the asset index and so the asset index is defaulting to 0.
 
X

XirmiX

Guest
username_login_text is a string, is it not? The player himself enters the value, correct? In which case, you did not retrieve the asset index yet. You must use the function

asset_get_index(obj_login_bar.username_login_text)

to retrieve the asset index for use in script_exists(). The reason it is returning only the first script is because you did not get the asset index and so the asset index is defaulting to 0.
Emm okay then... it works now :D

Now the login system works. Now off to registration and figuring out how to create a script whilst the game is running or after the game has been closed (a copy of an existing script, actually, which will be the basis of each new account).
 
X

XirmiX

Guest
Emm... actually... one more problem... it gives me an error when I enter a script that does not exist... when I explicitly stated for it to display that message instead if the script doesn't exist, so what the heck?
 
X

XirmiX

Guest
obj_login_button Step event:
Code:
if keyboard_check(vk_enter)
{
    if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
    {
        if script_exists(obj_login_bar.username_login_text)
        {
            script_index = asset_get_index(obj_login_bar.username_login_text)
            executing_script = script_execute(script_index, obj_password_bar.password_login_text);
            if executing_script == true
            {
                room_goto(menu);
            }
            else
            {
                return 0
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else if !script_exists(obj_login_bar.username_login_text)
        {
            return 0
            show_message("The username and/or password you've entered is incorrect");
        }
    }
}
Error:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Step Event0
for object obj_login_button:

call to non-existent script
at gml_Object_obj_login_button_StepNormalEvent_1 (line 8) - executing_script = script_execute(script_index, obj_password_bar.password_login_text);
############################################################################################
 
X

XirmiX

Guest
Still waiting :p

I'll get a response eventually... hopefully? This is just a small error before I can get this topic marked as solved.
 
S

SyntaxError

Guest
Problem.
Code:
if keyboard_check(vk_enter)
{
   if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
    {
        if script_exists(obj_login_bar.username_login_text)  // <- Your checking a string...
        {
            script_index = asset_get_index(obj_login_bar.username_login_text)
            executing_script = script_execute(script_index, obj_password_bar.password_login_text);
            if executing_script == true
            {
                room_goto(menu);
            }
            else
            {
                return 0
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else if !script_exists(obj_login_bar.username_login_text) // <- The if after the else is not necessary.
        {
            return 0
            show_message("The username and/or password you've entered is incorrect");
        }
    }
}
Solution.
Code:
if keyboard_check(vk_enter)
{
   if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
    {
    script_index = asset_get_index(obj_login_bar.username_login_text) 
    if script_exists(script_index)
        {
            executing_script = script_execute(script_index, obj_password_bar.password_login_text);
            if executing_script == true
            {
                room_goto(menu);
            }
            else
            {
                return 0
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else
        {
            return 0
            show_message("The username and/or password you've entered is incorrect");
        }
    }
}
 
P

ParodyKnaveBob

Guest
(Meanwhile, if you return from the script before you show_message(), you'll never see your message.)
 
  • Like
Reactions: Yal
M

montiedragon

Guest
Alright. If I'm interpreting your issue correctly this may fix it.

In the Create Event
Code:
global.password = noone;
Script
Code:
//Account login details and mechanisms
username = "username";
global.password = ds_list_create();
ds_list_add(global.password, "password");
Login Button Step Code
Code:
if keyboard_check(vk_enter)
{
    if (global.password != noone)
    {
        if obj_password_bar.password_login_text == ds_list_find_value(global.password, 0)
        {
            room_goto_next();
        }
        else
        {
            show_message("The username and/or password you've entered is incorrect");
        }
    }
    else
    {
        show_message("The username and/or password you've entered is incorrect");
    }
}
 
X

XirmiX

Guest
Problem.
Code:
if keyboard_check(vk_enter)
{
   if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
    {
        if script_exists(obj_login_bar.username_login_text)  // <- Your checking a string...
        {
            script_index = asset_get_index(obj_login_bar.username_login_text)
            executing_script = script_execute(script_index, obj_password_bar.password_login_text);
            if executing_script == true
            {
                room_goto(menu);
            }
            else
            {
                return 0
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else if !script_exists(obj_login_bar.username_login_text) // <- The if after the else is not necessary.
        {
            return 0
            show_message("The username and/or password you've entered is incorrect");
        }
    }
}
Solution.
Code:
if keyboard_check(vk_enter)
{
   if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
    {
    script_index = asset_get_index(obj_login_bar.username_login_text)
    if script_exists(script_index)
        {
            executing_script = script_execute(script_index, obj_password_bar.password_login_text);
            if executing_script == true
            {
                room_goto(menu);
            }
            else
            {
                return 0
                show_message("The username and/or password you've entered is incorrect");
            }
        }
        else
        {
            return 0
            show_message("The username and/or password you've entered is incorrect");
        }
    }
}
(Meanwhile, if you return from the script before you show_message(), you'll never see your message.)
Hmm, strange, but it keeps giving me the error, even though I've done things based on your examples :/ As in, the following code will still give the same exact error:

Code:
if keyboard_check(vk_enter)
{
   if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
    {
    script_index = asset_get_index(obj_login_bar.username_login_text)
    if script_exists(script_index)
        {
            executing_script = script_execute(script_index, obj_password_bar.password_login_text);
            if executing_script == true
            {
                room_goto(menu);
            }
            else
            {
                show_message("The username and/or password you've entered is incorrect");
                return 0
            }
        }
        else
        {
            show_message("The username and/or password you've entered is incorrect");
            return 0
        }
    }
}

Alright. If I'm interpreting your issue correctly this may fix it.

In the Create Event
Code:
global.password = noone;
Script
Code:
//Account login details and mechanisms
username = "username";
global.password = ds_list_create();
ds_list_add(global.password, "password");
Login Button Step Code
Code:
if keyboard_check(vk_enter)
{
    if (global.password != noone)
    {
        if obj_password_bar.password_login_text == ds_list_find_value(global.password, 0)
        {
            room_goto_next();
        }
        else
        {
            show_message("The username and/or password you've entered is incorrect");
        }
    }
    else
    {
        show_message("The username and/or password you've entered is incorrect");
    }
}
I think you're only taking password into consideration, cause first the code has to check for the script name, which it does currently, but when a script doesn't exist based on what you're entered (the username you entered is not the same as any script name), it will give you an error instead of following the following code:
Code:
    else
    {
        show_message("The username and/or password you've entered is incorrect");
    }
At this point I feel like it's not even possible to make the game put up the message and it'll just give you an error because the game engine has been programmed that way, but I might certainly be wrong and be missing something complex or very obvious here.
 
P

ParodyKnaveBob

Guest
In a big hurry, thus I haven't even looked at the consequences of this mistake, but check this out:
Code:
if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
This does not check like so...
Code:
if (obj_login_bar.username_login_text != {"local_account_00000" or "local_account_00000.txt"} )
It instead checks like so...
Code:
if ((obj_login_bar.username_login_text != "local_account_00000") or ("local_account_00000.txt" == true))
I suggest you read the manual under Reference->GML Overview->Expressions (I think is where this is .. the whole GML Overview section is good to read anyway).

Also, the first string you check has no ".txt" whereas the second does.

I hope this helps!
Bob
 

chamaeleon

Member
Reading all these messages leaves me very confused as to why a single script, perhaps named check_password, that takes two arguments wouldn't be sufficient.

Arguments would be a username string and a password string, and the script looks up the username in a ds_map and returns true or false depending on whether the password stored in the map match or does not match the password passed as argument to the script, or false if the username is not found in the map.

Any additional functionality that depends on the result of this function would then better be handled in other scripts or object events as needed, like in an event that handles the return key being pressed.

Initializing the map would be handled wherever appropriate. Calling some init function in a controller object create event or room start or whatever. Nothing would stop you from adding or removing username entries if it makes sense for the game as the game play progresses, etc. In particular you wouldn't have any need for checking whether a script exist or not for the purpose of password validation.
 
X

XirmiX

Guest
In a big hurry, thus I haven't even looked at the consequences of this mistake, but check this out:
Code:
if obj_login_bar.username_login_text != "local_account_00000" or "local_account_00000.txt"
This does not check like so...
Code:
if (obj_login_bar.username_login_text != {"local_account_00000" or "local_account_00000.txt"} )
It instead checks like so...
Code:
if ((obj_login_bar.username_login_text != "local_account_00000") or ("local_account_00000.txt" == true))
I suggest you read the manual under Reference->GML Overview->Expressions (I think is where this is .. the whole GML Overview section is good to read anyway).

Also, the first string you check has no ".txt" whereas the second does.

I hope this helps!
Bob
Ahh, wow, that makes a bit more sense, thanks. The .txt for one and not the other is supposed to be there, just in case, because as you might notice, aside from the .txt both have the same exact structure.

Reading all these messages leaves me very confused as to why a single script, perhaps named check_password, that takes two arguments wouldn't be sufficient.

Arguments would be a username string and a password string, and the script looks up the username in a ds_map and returns true or false depending on whether the password stored in the map match or does not match the password passed as argument to the script, or false if the username is not found in the map.

Any additional functionality that depends on the result of this function would then better be handled in other scripts or object events as needed, like in an event that handles the return key being pressed.

Initializing the map would be handled wherever appropriate. Calling some init function in a controller object create event or room start or whatever. Nothing would stop you from adding or removing username entries if it makes sense for the game as the game play progresses, etc. In particular you wouldn't have any need for checking whether a script exist or not for the purpose of password validation.
1) I already explained; the script that holds the password and also the username in a sense is the script, which will hold all of the information for the said account. The script IS the account. I've not planned to have multiple scripts just for one account. This is why a script dedicated to checking the password should not exist; it'll be even more of a hassle otherwise! Imagine having a script for a username, a script for a password a script for account currency, a script for account's experience, a script ti check whether the account has purchased this one item out of a thousand... and all of this for EACH account created. Now at what point do you goddamn stop? One script per account and that's it, because I'm 90% sure that's quite feasible, even if I add more content in the future.

2) Why would a script called "check_password" go and check username as well? This makes no sense! It would kind of make sense the other way round, but... I am really not understanding your train of thought here, man. As for ds_map... sure, but it seems to work in a different way for me without too much hassle (except for that error that happens when I've stated for it to not happen and do something else).

3) But why? Why shouldn't, lets say experience, rank, in-game currency, equipment bought and equipped etc. be handled in the same script when it comes to it?

4) Well, the method is simple and it works for the most part, so why try something more complex that will essentially do the exact same thing in the end?
 

chamaeleon

Member
1) I already explained; the script that holds the password and also the username in a sense is the script, which will hold all of the information for the said account. The script IS the account. I've not planned to have multiple scripts just for one account. This is why a script dedicated to checking the password should not exist; it'll be even more of a hassle otherwise! Imagine having a script for a username, a script for a password a script for account currency, a script for account's experience, a script ti check whether the account has purchased this one item out of a thousand... and all of this for EACH account created. Now at what point do you goddamn stop? One script per account and that's it, because I'm 90% sure that's quite feasible, even if I add more content in the future.

2) Why would a script called "check_password" go and check username as well? This makes no sense! It would kind of make sense the other way round, but... I am really not understanding your train of thought here, man. As for ds_map... sure, but it seems to work in a different way for me without too much hassle (except for that error that happens when I've stated for it to not happen and do something else).
I am very sorry, but in my opinion your data should not be code. Write code (check_password), that uses data (either created in an object create method, read/written from/to ini files, depending on how dynamic the set of user accounts are) in a ds_map. One script only, as many accounts as you want, and a simple ds_map lookup based on the username is all you need. This takes care of the user "authentication" (and that is all it is supposed to do).

I guess I missed anything about further account information. However, this is also just data, and can be stored in a ds_map for instance, with the username as the key value. Once the check_password function returns true (implying the user entered a correct username/password combination), your code is then free to look up an entry in the account data map, where the values stored are whatever you want/need, for instance an account specific ds_map (in other words, a ds_map with values being ds_maps), where you can look up the currency, experience, etc. Depending on how you do it, there's nothing stopping you from using this same ds_map structure for the password check either, the password would simply be another entry in the account map, that is checked against the password provided to the check_password function in that case.

Again, the username is the key to the ds_map (or ds_maps, if you use multiple ds_map for different purposes). No need for an exploding number of scripts except to the extent necessary to make your code readable for yourself. One script's sole purpose could be to return the ds_map for an account or "noone" if not found in the account map, or something like that. So despite your insistence of many scripts being needed, I am now "capped" at 2.
 
X

XirmiX

Guest
I am very sorry, but in my opinion your data should not be code. Write code (check_password), that uses data (either created in an object create method, read/written from/to ini files, depending on how dynamic the set of user accounts are) in a ds_map. One script only, as many accounts as you want, and a simple ds_map lookup based on the username is all you need. This takes care of the user "authentication" (and that is all it is supposed to do).

I guess I missed anything about further account information. However, this is also just data, and can be stored in a ds_map for instance, with the username as the key value. Once the check_password function returns true (implying the user entered a correct username/password combination), your code is then free to look up an entry in the account data map, where the values stored are whatever you want/need, for instance an account specific ds_map (in other words, a ds_map with values being ds_maps), where you can look up the currency, experience, etc. Depending on how you do it, there's nothing stopping you from using this same ds_map structure for the password check either, the password would simply be another entry in the account map, that is checked against the password provided to the check_password function in that case.

Again, the username is the key to the ds_map (or ds_maps, if you use multiple ds_map for different purposes). No need for an exploding number of scripts except to the extent necessary to make your code readable for yourself. One script's sole purpose could be to return the ds_map for an account or "noone" if not found in the account map, or something like that. So despite your insistence of many scripts being needed, I am now "capped" at 2.
Remember that all of this is local; each player would hold onto their account information on their own machine. And remember that they could not view or at the very least edit any of that. Deleting your account if you so desire could be done from within the game with your method, I guess and it would be a tad bit safer too, but what you could NOT do is take an account out from the game and pasting it to a different device in order to play from a different place... Although I guess you could just keep your account on a memory stick and perhaps cutting the whole game from one place to another if need be... Uff, I'm constantly making my brain work right now and this just getting me even more conflicted and confused doesn't help. I think I need some more time to think about all of this...
 

chamaeleon

Member
Remember that all of this is local; each player would hold onto their account information on their own machine. And remember that they could not view or at the very least edit any of that. Deleting your account if you so desire could be done from within the game with your method, I guess and it would be a tad bit safer too, but what you could NOT do is take an account out from the game and pasting it to a different device in order to play from a different place... Although I guess you could just keep your account on a memory stick and perhaps cutting the whole game from one place to another if need be... Uff, I'm constantly making my brain work right now and this just getting me even more conflicted and confused doesn't help. I think I need some more time to think about all of this...
I seriously recommend you read up on the ds_map, ds_list, etc. data structures in the manual, and write down on paper what data you wish to keep track of, and how you would store that in a map, for instance. Once you have your data representation nailed down (nothing stopping you from iterating this over time of course, if you think of additional account details to keep track of), you only need to work with scripts that perform tasks (check password, get or update currency, etc.) on the data structures you have come up with, perhaps one at a time, dealing with individual problems. Don't try to solve everything at once.

As for importing/exporting data between devices, that's an unrelated problem, but really just comes down to a serialization of the data, encrypted or not, depending on needs, and figuring out just what kind of experience you would want the player to have for transferring data. File-based (which is a little tricky given the sandbox nature of GM:S, unless you use extensions), or server based, where you run a server your program interacts with and the use logs into it, and sees the same information regardless of which device is in use, or maybe somehow display a string inside the program that represents the minimal amount of information for account to be copied/pasted/retyped (copy/paste may require an extension as I don't think GM:S can directly interact with the clipboard, but I could be wrong). Many options, I'm sure, some easier than others. But in any case, unless it's a critical component for you, I'd leave this for later until you feel more comfortable working with data structures within GM:S.
 
Top