SRL Archive - Help and Support

Reading/Writing to text files


Footy

2012-10-21 18:19:43

Hey guys, I'm kind of stumped with this one. I'm trying to save usernames and passwords to a .txt file, and then be able to retreive this info on later run's. However, the problem is I've never, ever done anything with files. The idea was to do something like:

Write how many usernames and passwords there currently are in the first two lines(so I know what lines to check for usernames and passwords)

Write Usernames from a TStringArray into the file

Write Passwords directly after.

Then when I want to, I need to be able to read the numbers in the first two lines to know where the usernames and passwords are located, and then read them and save them into a TStringArray. If someone could show me how to do this, or atleast point me in the right direction, that would be awesome! :)

Thanks!
~Footy

This is the part so far…

program new;
{$i srl/srl.simba}

const
filepath = 'Accounts.txt';

var
handle:integer;

begin
SetupSRL
handle := openfile(filepath, true);


end.

Sin

2012-10-21 18:23:33

I'd like to know this too!

Le Jingle

2012-10-21 18:28:56

.ini files are the way to go.
"INI files are simple text files with a basic structure composed of "sections" and "properties"."

I used one in my GUI (which is now universal for anyone to use in their scripts) for the Cooking Guild scripting competition;

program test;
{$i srl/srl.simba}
{===============================================================================
There are so many people to thank for the outcome of the form portion of
my script. W/o their efforts, I wouldn't know what I'm doing!

* Narcle (had a great way to display a wide variety of options + use them)
* CynicRus (git source for help on convert/review lazarus to pascal script)
* Chris (several mini features)
* abu_jwka (background form setting + freeing)
================================================================================}

const
FilePath = AppPath + 'CookGuildSettings.ini';
scriptCGname = 'Your Name/Script Here';

var
{ - Parent - }
TForm1 : TForm;
{ - Start : To Add / Design - }
Buttons: Array of TButton;
ckBox: Array of TCheckBox;
ComboBox1: TComboBox;
Label1, Label2: TLabel;
EditArr: Array of TEdit;
Background: TImage;
{ - End : To Add / Design - }

procedure DeclarePlayers;
begin
HowManyPlayers:= 1;
NumberOfPlayers(HowManyPlayers);
CurrentPlayer:= 0;
with Players[0] do
begin
Name := ''; // If you fill this out, the GUI shouldn't pop-up.
Pass := '';
Pin := '';
WorldInfo := [True, 89];
Active := True;

Booleans[0] := false; // Log on randoms? (true = log out upon random event)
Booleans[1] := true; // use antiban? (true = use the antiban)
Booleans[2] := false; // Debug mode? (true = will show debug)
Booleans[3] := false; // Cooking urn click box (true = use urn)
Strings[0] := ''; // stats user, leave blank if unknown
Strings[1] := ''; // stats pass, leave blank if unknown
Strings[2] := 'Cook - Raw salmon'; // Main script action (what the scrip will do for the session)

end;
end;

procedure debug;
begin
end;

Procedure SavePlayerSettings(ToFolder: boolean);
var
i: integer;
General: String;
begin
With Players[0] do
begin
Name := EditArr[0].Caption;
Pass := EditArr[1].Caption;
Pin := EditArr[2].Caption;
WorldInfo := [True, EditArr[3].Caption];
Booleans[0] := ckBox[0].CHECKED;
Booleans[1] := ckBox[1].CHECKED;
Booleans[2] := ckBox[2].CHECKED;
Booleans[3] := ckBox[3].CHECKED;
Strings[0] := EditArr[4].Caption;
Strings[1] := EditArr[5].Caption;
Strings[2] := ComboBox1.Caption;
end;

General := 'Player Info [0]';
if ToFolder then
with Players[0] do
begin
WriteINI(General, 'Name', Name, FilePath);
WriteINI(General, 'Pass', Pass, FilePath);
WriteINI(General, 'Pin', Pin, FilePath);
WriteINI(General, 'World', WorldInfo[1], FilePath);
for i := 0 to 3 do
WriteINI(General, 'Booleans['+ToStr(i)+']', BoolToStr(ckBox[i].Checked), FilePath);
WriteINI(General, 'Strings[0]', Strings[0], FilePath);
WriteINI(General, 'Strings[1]', Strings[1], FilePath);
WriteINI(General, 'Strings[2]', Strings[2], FilePath);
end;
end;

function LoadPlayerSettings: boolean;
begin
result := false;
stats_Username := ReadINI('Player Info [0]', 'Strings[0]', FilePath);
stats_UserPass := ReadINI('Player Info [0]', 'Strings[1]', FilePath);
with Players[0] do
begin
Name := ReadINI('Player Info [0]', 'Name', FilePath);
if Name = '' then
exit;
Pass := ReadINI('Player Info [0]', 'Pass', FilePath);
Pin := ReadINI('Player Info [0]', 'Pin', FilePath);
WorldInfo[1] := ReadINI('Player Info [0]', 'World', FilePath);
Booleans[0] := StrToBool(ReadINI('Player Info [0]', 'Booleans[0]', FilePath));
Booleans[1] := StrToBool(ReadINI('Player Info [0]', 'Booleans[1]', FilePath));
Booleans[2] := StrToBool(ReadINI('Player Info [0]', 'Booleans[2]', FilePath));
Booleans[3] := StrToBool(ReadINI('Player Info [0]', 'Booleans[3]', FilePath));
Strings[0] := ReadINI('Player Info [0]', 'Strings[0]', FilePath);
Strings[1] := ReadINI('Player Info [0]', 'Strings[1]', FilePath);
Strings[2] := ReadINI('Player Info [0]', 'Strings[2]', FilePath);
end;
result := true;
end;

procedure OnSend(Sender: TObject);
var
i: integer;
GetNewArr: TStringArray;
begin
SetLength(EditArr, 6);

case Sender of
Buttons[0]: //Load
begin
try
LoadPlayerSettings;
{ Only refreshing the Visible Text, this isn't needed because we already
obtain the variables upon loading the last saved settings, but it will
provide the user with a better 'visual,' to know that they're settings were retrieved.}
GetNewArr := [Players[0].Name, Players[0].Pass, Players[0].Pin,
Players[0].WorldInfo[1],Players[0].Strings[0],
Players[0].Strings[1]];
for i := 0 to 5 do
EditArr[i].Text := GetNewArr[i];
TForm1.refresh;
TForm1.ModalResult := mrOk;
ShowMessage('Loaded last saved settings successfully!');
except
Writeln('No Settings Saved! :(');
end;
ClearDebug;
Writeln('Loaded last saved settings.');
end;
Buttons[1]: //Start
begin
ClearDebug;
Writeln('Starting the Script!');
TForm1.ModalResult := mrOk;
end;
Buttons[2]: //Save
begin
ClearDebug;
Writeln('Saved the current settings.');
SavePlayerSettings(True);
end;
//an array wasn't working quite how I wanted here. hence code
EditArr[0]: if EditArr[0].Text = 'Username' then EditArr[0].CLEAR;
EditArr[1]: if EditArr[1].Text = 'Password' then EditArr[1].CLEAR;
EditArr[2]: if EditArr[2].Text = 'Pin' then EditArr[2].CLEAR;
EditArr[3]: if EditArr[3].Text = 'W#' then EditArr[3].CLEAR;
EditArr[4]: if EditArr[4].Text = 'Stats User' then EditArr[4].CLEAR;
EditArr[5]: if EditArr[5].Text = 'Stats Pass' then EditArr[5].CLEAR;
end;
end;

procedure InitForm;
var
i: integer; // loop variable
b, w, h: Integer; // bitmap variables
p, ComboBox1Strings, ckBoxHints, ckBoxCaps, EditArrHints, EditArrText,
ButtonHints, ButtonCaps: TStringArray; // Form Array Assists
EditArrMaxL: TIntegerArray; // Max Length's for TEdit's
begin
SetLength(ckBox, 4);
SetLength(EditArr, 6);

TForm1 := TForm.Create(nil);
TForm1.Caption := scriptCGname;
TForm1.SetBounds(0, 0, 455, 367);

SetLength(ButtonHints, 3);
SetLength(ButtonCaps, 3);
ButtonHints := ['Load the last saved settings','Start the script!','Save the current settings?'];
ButtonCaps := ['Load Settings','Start','Save Settings'];
SetLength(Buttons, 3);
for i := 0 to 2 do
begin
Buttons[i] := TButton.Create(TForm1);
Buttons[i].Parent := TForm1;
Buttons[i].Hint := ButtonHints[i];
Buttons[i].Caption := ButtonCaps[i];
Buttons[i].OnClick := @OnSend;
Buttons[i].ParentShowHint := False;
Buttons[i].ShowHint := True;
end;
Buttons[0].SetBounds(24, 288, 104, 56);
Buttons[1].SetBounds(176, 288, 104, 56);
Buttons[2].SetBounds(328, 288, 104, 56);

Label1 := TLabel.Create(TForm1);
Label1.Parent := TForm1;
Label1.SetBounds(232, 72, 70, 31);
Label1.Caption := 'Actions';
Label1.Font.Height := -21;
Label1.ParentColor := False;
Label1.ParentFont := False;
Label2 := TLabel.Create(TForm1);
Label2.Parent := TForm1;
Label2.SetBounds(88, 16, 289, 38);
Label2.Caption := scriptCGname;
Label2.Font.Height := -32;
Label2.ParentColor := False;
Label2.ParentFont := False;
Label2.Font.Name := 'Roman';

SetLength(EditArrHints, 6);
EditArrHints := ['Enter your RS Username', 'Enter your RS Password',
'Have a pin? enter it. If not leave blank', 'The world to login to within RS',
'Leave blank if unknown', 'Leave blank if unknown'];
SetLength(EditArrMaxL, 6);
EditArrMaxL := [100, 100, 4, 3, 100, 100];
SetLength(EditArrText, 6);
EditArrText := ['Username', 'Password', 'Pin', 'W#', 'Stats User', 'Stats Pass'];
for i := 0 to 5 do
begin
EditArr[i] := TEdit.Create(TForm1);
EditArr[i].Parent := TForm1;
EditArr[i].Hint := EditArrHints[i];
EditArr[i].MaxLength := EditArrMaxL[i];
EditArr[i].Text := EditArrText[i];
EditArr[i].ParentShowHint := False;
EditArr[i].ShowHint := True;
EditArr[i].TabOrder := i;
if (i>=1) then EditArr[i].OnEnter := @OnSend;
if (i<=3) then EditArr[i].SetBounds(24, 72+(i*32), 80, 23);
end;
EditArr[0].OnClick := @OnSend;
EditArr[4].SetBounds(120, 72, 80, 23);
EditArr[5].SetBounds(120, 104, 80, 23);

SetLength(ckBoxHints, 4);
SetLength(ckBoxCaps, 4);
ckBoxHints := ['Checked = Logout', 'Checked = Use it', 'Checked = Show', 'Checked = Use'];
ckBoxCaps := ['Log on Randoms?', 'Use Antiban?', 'Debug Mode?', 'Use Urns? (For Cooking Only)'];
for i := 0 to 3 do
begin
ckBox[i] := TCheckBox.Create(TForm1);
ckBox[i].Parent := TForm1;
ckBox[i].ParentShowHint := False;
ckBox[i].ShowHint := True;
ckBox[i].TabOrder := 6+i;
ckBox[i].Hint := ckBoxHints[i];
ckBox[i].Caption := ckBoxCaps[i];
ckBox[i].Checked := False;
end;
ckBox[0].SetBounds(24, 208, 117, 19);
ckBox[1].SetBounds(24, 232, 89, 19);
ckBox[2].SetBounds(24, 256, 94, 19);
ckBox[3].SetBounds(232, 140, 175, 19);

ComboBox1 := TComboBox.Create(TForm1);
ComboBox1.Parent := TForm1;
ComboBox1.SetBounds(232, 104, 196, 23);
ComboBox1.ItemHeight := 15;
p := ['Cook - ', 'Gather - ']; // Prefix Text for Combo Options
ComboBox1Strings := ['Raw swordfish','Raw lobster','Raw tuna','Raw salmon',
'Raw pike','Raw trout','Raw anchovy','Raw herring','Raw sardine','Raw shrimp',
'Raw crayfish','Raw chicken','Raw meat','Bread dough','Uncooked redberry pie',
'Uncooked meat pie','Uncooked apple pie','Uncooked plain pizza',
'Uncooked meat pizza','Uncooked anchovy pizza','Uncooked stew',
'All (Low-High)','All (High-Low)','All Materials','High Profit Items',
'Cooking Apple','Grape','Chocolate bar','Cake tin','Empty pot','Wheat',
'Pot of flour','Pie tin','Jug','Jug of water','Pie crusts'];
for i := 0 to High(ComboBox1Strings) do
begin
if (i <= 22) then
ComboBox1.Items.Add(p[0]+ComboBox1Strings[i])
else
ComboBox1.Items.Add(p[1]+ComboBox1Strings[i])
end;
ComboBox1.Text := 'What to do?';
ComboBox1.TabOrder := 9;

Background := TImage.Create(TForm1);
with Background do
begin
Parent := TForm1;
SetBounds(0, 0, 455, 367);
// b := LoadBitmap('C:\Users\Nick\Desktop\23423.png');
b := BitmapFromString(455, 367, 'meJztwgEJAAAMA6D1j7F0i/EcB8U1U1'+replicate('V',644)+'X11QOlJCMv');
GetBitmapSize(b, w, h);
DrawBitmap(b, Background.CANVAS, 0, 0);
SendToBack;
FreeBitmap(b);
end;
end;

procedure SafeInitForm;
var
v: TVariantArray;
begin
setarraylength(V, 0);
ThreadSafeCall('InitForm', v);
end;

procedure ShowFormModal;
begin
tform1.ShowModal;
end;

procedure SafeShowFormModal;
var
v: TVariantArray;
begin
SetArrayLength(V, 0);
ThreadSafeCall('ShowFormModal', v);
end;

procedure ActionList(DoAction:string);
begin
case DoAction of
'': writeln('a');
end;
end;

begin
DeclarePlayers;
if (Players[0].Name = '') then
begin
SafeInitForm;
SafeShowFormModal;
end else
begin
HowManyPlayers := 1;
CurrentPlayer := 0;
DeclarePlayers;
NumberOfPlayers(HowManyPlayers);
end;
if (Players[0].Strings[0] = '') then
SetupSRLStats(1226, 'Anonymous', 'anon1337');

writeln('Using Player Named: '+Players[0].Name+'.');
writeln('Script will carry out: '+players[0].strings[2]+'.');
end.

Of course you can parse out all the unneeded information/Forms/etc. too and just take the .ini reading/writing.

Hope that helps.

Edit: WriteINI, ReadINI, DeleteINI are all helpful commands too. If you get confused with those, I could also post some examples of where they execute within a .ini file.

Footy

2012-10-21 18:32:07

I'll look into it and post if I have any questions, thanks!

Hobbit

2012-10-21 18:35:01

If you guys like this, you'll like what we have cooking for SRL 6 :stirthepot:

Sin

2012-10-21 18:40:47

You've got me excited :p

Footy

2012-10-21 18:44:16

Really? Sounds good! This stuff is so confusing!

And @Whoever, I'm trying to write to my accounts.ini file I made, but what is the section and keyname? The Documentation says this:

Section := 'What subsection in the INI it is being Writen.';
KeyName := 'Space in the specified Subsection in which you string is writen.';

Do I have to create these sections or subesctions??

Le Jingle

2012-10-21 19:05:25

Hope this helps illustrate it better, kind of got lazy explaining -.- but I think it might help.
Edit: That didn't look like pink when I picked it >.>


*Also note, AppPath + 'filename.ini' will store your filename.ini in the /simba/ folder directly.
*Brackets, [], are placed around the string that you use to write the Section, or first paramater in, WriteINI(Section, KeyName, NewString, FilePath: string);

Footy

2012-10-21 19:20:19

Oh gawd, this is more confusing then I thought… :p

The script I'm making actually doesn't use declareplayers, I found it easier to have my own login function for the specific task. Instead, I stored all the usernames and passwords in arrays.

I have this as my script at the moment:

program new;
{$i srl/srl.simba}

const
filepath = 'Accounts.ini';
Section = 'Usernames';

var
handle:integer;

begin
SetupSRL
handle := openfile(filepath, true);
Writeini(Section, 'Name1', 'Hello', filepath);
closefile(handle);


end.

and this in my Accounts.ini file:

[Usernames]
Name1=

Theoretically, that should write hello after Name1, correct? Well it doesn't seem to be doing anything… The script just runs and succesfully executes, nothing happens with the file. The file is in the same folder(desktop) as the script, so that's all I need for the path, I believe…

E: Shouldn't we have some sort of tutorial on this stuff? I remember seeing one a while back…

Le Jingle

2012-10-21 19:32:43

Here's an example that I think will help, now that I kinda understand whatcha are looking for:


program new;
{$i srl/srl.simba}

const
FilePath = AppPath + 'Accounts.ini'; // Writes/Reads from /simba/Accounts.ini

var
i: Integer;
names, pws: TStringArray;

begin
SetupSRL;
names := ['username1', 'username2', 'username3'];
pws := ['password1', 'password2', 'password3']
SetLength(names, Length(names));
for i := 0 to high(names) do
begin
writeINI('player :'+tostr(i), 'Name', names[i], FilePath);
writeINI('player :'+tostr(i), 'Pass', pws[i], FilePath);
end;

for i := 0 to high(names) do
begin
writeln(readINI('player :'+tostr(i), 'Name', FilePath));
writeln(readINI('player :'+tostr(i), 'Pass', FilePath));
end;
end.

Footy

2012-10-21 19:38:31

Ahh, there we go, atleast it wrote something this time. I'll study this more tomorrow, that should be all I need. Thanks a bunch, ++Rep!