Community

SCI Programming => SCI Syntax Help => Topic started by: Doan Sephim on December 12, 2020, 12:39:56 PM

Title: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 12:39:56 PM
Is it possible to tweak Restore in such a way that it doesn't reset certain variables?

Code: [Select]
(method (restore &tmp gameNum oldCursor hSound)
(= gameNum  -1)
(Load rsFONT gSaveRestoreFont)
(Load rsCURSOR gNormalCursor)
(Load rsCURSOR gLoadingCursor)
(= oldCursor (self setCursor: gNormalCursor))
(= hSound (Sound pause: 1))
(if (GetSaveDisk TRUE)
(if gPrintDlg (gPrintDlg dispose:))
(= gameNum (Restore doit: &rest))
(if (!= gameNum -1)
(self setCursor: gLoadingCursor)
(if (CheckSaveGame objectName gameNum gVersion)
(gCast eachElementDo: #dispose)
(gCast eachElementDo: #delete)
;(= saved 1)
;(FormatPrint {Saved %u} saved)
        (RestoreGame objectName gameNum gVersion)

This is in the "Game" script and I have set a test global variable there "(saved =1)" and I test a print to make sure it works before the "RestoreGame" is called. I do get confirmation that the variable is set to 1 before the restore, but after the restore it is predictably set back to its original value.

I looked everywhere in vain to find where "RestoreGame" is set up. It looks like a procedure to me, but I can't find it anywhere.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: OmerMor on December 12, 2020, 02:50:09 PM
Have you thought of looking in Codename: Iceman's scripts? IIRC, it has cheating prevention mechanism in the submarine that maintains its state even after restores.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: OmerMor on December 12, 2020, 02:52:13 PM
From wikipedia (https://en.wikipedia.org/wiki/Codename:_ICEMAN#Gameplay_and_technical_features):
Quote
At one point, the player must obtain a bottle from a crewman on the sub, but only if the player can beat him at a dice game. The crewman 'accuses' the player of cheating if the player repeatedly saves and restores in an effort to win at dice (he is allowed to do so only twice).
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 03:01:49 PM
Have you thought of looking in Codename: Iceman's scripts? IIRC, it has cheating prevention mechanism in the submarine that maintains its state even after restores.
That's very interesting. I have not looked at it. I will try, but I'm not the most savvy programmer, so I may overlook the solution even if it's there!
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 03:36:04 PM
I have looked at it and that is not the solution.

The anti-scum measures in Iceman use the replay method of the minigame's room to detect that you restored a game and increases an ordinary local variable. This doesn't normally happen but Iceman's Game::replay has the line (gRegions eachElementDo: #replay) in it. The dice game's restore counter is saved and loaded as any, then incremented and checked. And that's how it can tell.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 03:42:22 PM
I have looked at it and that is not the solution.

The anti-scum measures in Iceman use the replay method of the minigame's room to detect that you restored a game and increases an ordinary local variable. This doesn't normally happen but Iceman's Game::replay has the line (gRegions eachElementDo: #replay) in it. The dice game's restore counter is saved and loaded as any, then incremented and checked. And that's how it can tell.
Thanks for looking Kawa. You saved me time and trouble.

I've not had any further success finding anything about "RestoreGame." It looks like a procedure, but maybe it's something else? There doesn't seem to be anything like it in any of the Scripts the Game Script uses (or subheaders for that matter).
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 03:49:53 PM
Lemme just elaborate a bit on why your test variable gets reset and such: saved games are basically saved states, including all the variables. When you restore a game, the engine itself clears out everything, unpacks the heap from state to RAM, sets an internal flag, and resets itself to just before it calls your game's play method. Except it doesn't because the internal flag lets it know to call replay instead. This is all done by the engine itself, you can't influence that from inside the game.

I've not had any further success finding anything about "RestoreGame." It looks like a procedure, but maybe it's something else? There doesn't seem to be anything like it in any of the Scripts the Game Script uses (or subheaders for that matter).
Kernel procedure, part of the engine.

Edit: I just got an idea on how to make certain variables not reset. What you could try to do is have Game::restore write the specific globals you want to persist to a file. You do this right before the (RestoreGame objectName gameNum gVersion) call. Then in Game::replay, somewhere at the start, you check for that file's existance, read the values for those same globals back in, and delete the file. That way, if your persistent global was, say, 42 at the time you decide to restore, it'll save that 42 to the temp file, restore the game and reset the global to whatever that savegame says it was at the time (41?), and then immediately see the file and load 42 from it.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 04:08:32 PM
Edit: I just got an idea on how to make certain variables not reset. What you could try to do is have Game::restore write the specific globals you want to persist to a file. You do this right before the (RestoreGame objectName gameNum gVersion) call. Then in Game::replay, somewhere at the start, you check for that file's existance, read the values for those same globals back in, and delete the file. That way, if your persistent global was, say, 42 at the time you decide to restore, it'll save that 42 to the temp file, restore the game and reset the global to whatever that savegame says it was at the time (41?), and then immediately see the file and load 42 from it.
Thanks. I appreciate you explaining the goings on when the game restores. You mentioned "writing the specific globals to a file." I wonder if that is similar to how QFG allowed you to import characters - by writing certain variables to files?

Do you know how one would accomplish the writing of a variable to a file? I would like to test this out, but don't know how to do that (or check it for that matter).
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 04:34:59 PM
Thanks. I appreciate you explaining the goings on when the game restores. You mentioned "writing the specific globals to a file." I wonder if that is similar to how QFG allowed you to import characters - by writing certain variables to files?
Basically yes.
Quote
Do you know how one would accomplish the writing of a variable to a file? I would like to test this out, but don't know how to do that (or check it for that matter).
The big issue here is that SCI0's file kernels don't let you read and write anything but strings. You could go balls-out like QfG, or you could just read and write strings.

I've had persistent settings in Catdate at one point but that's SCI11, which can do a little better 😉

But this is SCI0 so let's just take one from LSL3's book. To save:
Code: [Select]
(= fileHandle (FOpen "persist.tmp" fCREATE))
(if (!= fileHandle -1)
(Format @str "%6d %6d %6d" gPersistMe gPersistMeToo gGuessWhat)
(FPuts fileHandle @str)
)
(FClose fileHandle)
Add as many "%6d" as you have variables you want to persist. To load:
Code: [Select]
(= fileHandle (FOpen "persist.tmp" 1)) ;there's a historical typo in SCI.SH
(if (!= fileHandle -1)
(= gPersistMe (ReadNumber (FGets @str 8 fileHandle)))
(= gAlsoMePlz (ReadNumber (FGets @str 8 fileHandle)))
)
(FClose fileHandle)
...and then I realize there is apparently no "delete" in SCI0, so you're stuck with a leftover file. Hm.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 04:42:38 PM
...and then I realize there is apparently no "delete" in SCI0, so you're stuck with a leftover file. Hm.
I look forward to tinkering around with this. Thank you for doing the leg-work, because there is 0.01% chance I would arrive at this info on my own.

As to your comment about no "delete" mechanism in SCI0 - would that suggest that it would create a new file every time there was a restore? I guess this wouldn't be terrible if I just created a folder that stored them...but then again, how would it know which file to read from on the restore?
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 04:48:43 PM
As to your comment about no "delete" mechanism in SCI0 - would that suggest that it would create a new file every time there was a restore? I guess this wouldn't be terrible if I just created a folder that stored them...but then again, how would it know which file to read from on the restore?
No, no, you just re-use the exact same file every time you restore, "persist.tmp".

It's why SCI0 games have "Replace" in their save dialogs instead of "Delete" -- they can't actually delete LL3SG.007, only reuse it.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 04:59:33 PM
That's good to know. I'm glad I won't be making tons and tons of new files.

Having some trouble with the code though

Code: [Select]
  [Error]: Expected something to which we could get a pointer: str  Line: 215, col: 15
  [Error]: Expected something to which we could get a pointer: str  Line: 216, col: 25

These errors are in reference to:
Code: [Select]
(Format @str "%6d %6d %6d" gPersistMe gPersistMeToo gGuessWhat)
(FPuts fileHandle @str)

I simply added the variables to the main Script without definition. Am I missing an obvious step?
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 05:06:19 PM
str would be a temporary, method/procedure-local variable, so something like (method (save &tmp [strDescBuf 20] gameNum oldCursor hSound [str 10])
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 05:14:24 PM
Right. I was missing something obvious.

Code: [Select]
(= fileHandle (FOpen "persist.tmp" 1)) ;there's a historical typo in SCI.SH
(if (!= fileHandle -1)
(= gPersistMe (ReadNumber (FGets @str 8 fileHandle)))
(= gAlsoMePlz (ReadNumber (FGets @str 8 fileHandle)))
)
(FClose fileHandle)

With this in the replay method, I also need to add str as a variable correct?

Also, what does the 8 stand for in the FGets?

Assuming I am saving 3 variables, how does it know which value to assign to each variable? Or does it just go in order?

EDIT: Good and bad news. I succesfully restored the game with a variable of a different value than saved. Bad new? It was the wrong value. I assigned it to 3 just before running the save to file code, but when I checked it after restoring, it said the value was 0. (I had the value set to 1 originally)
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 05:27:43 PM
The 8 is the maximum length of the string to read -- up to eight characters or up to the end of the line or file. And yes, it does read them in the same order you write them.

This is about as far as I can help.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 06:01:29 PM
This is about as far as I can help.
Thanks. I appreciate all the help. I'm going to tinker about with it to see if I can get it running smoothly
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 06:38:19 PM
One thing you could try is to open the persist file in Notepad to check what's actually in there.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 07:32:35 PM
One thing you could try is to open the persist file in Notepad to check what's actually in there.

I viewed the tmp file with notepad and it looks like it recorded the variables perfectly! the first value was 3 and the other two values were 1's (which is what they were originally designated as in the main script). So it looks like all I need to do is get the inputting of these values correctly in the replay method.

The current code only pulls "0" values for the variables. I'm not sure what's going wrong though

Code: [Select]
(= fileHandle (FOpen "persist.tmp" 1)) ;there's a historical typo in SCI.SH
(if (!= fileHandle -1)
(= gPersistMe (ReadNumber (FGets @str 8 fileHandle)))
(= gAlsoMePlz (ReadNumber (FGets @str 8 fileHandle)))
)
(FClose fileHandle)

Does it have anything to do with the "historical typo"? Mentioned in the comment?
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 12, 2020, 08:33:02 PM
The typo is that the two "open for reading" modes had their numbers switched around in Brian Provinciano's original SCI.SH file, from the SCI Studio SCI0 template. Phil kept the error in, switching them right-side-up when compiling SCI11 code, so as to not re-break SCI0 games. That's why there's a plain 1 in the snippet I wrote.

Look in SCI.SH yourself, it's documented on the spot.

I'm not sure why it's returning zeros though.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 12, 2020, 08:39:10 PM
You're a wealth of knowledge! I'll keep muddling
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 13, 2020, 11:50:41 AM
Okay! I have the code reading the file numbers into the variables now, so that's good! I'm just not finding the right place to PUT that code. I originally was putting in the Game script's "replay" method, but I don't think that's the right place. I'll keep looking.

So this is getting tricky. Basically, I don't think there is any method or procedure that runs exclusively when you restore the game, which is where I would need to put the code to re-orient the variables.

So the work-around would be to set up a variable (gRestoringTheGame) which I set to TRUE when I restore the game. Then in the Main Script's doit method, I check if this variable is true, run the "read the variable from the temp file" code, then set gRestoringTheGame back to FALSE.

Of course, the obvious hurdle I forgot about was that gRestoringTheGame ITSELF would be set back to FALSE upon the restore of the game, and then the doit method wouldn't read it as TRUE and run the code.

So, I have to write gRestoringTheGame into the Temp file also, then in the Main Script's doit method, read the Temp file for gRestoringTheGame to make it TRUE, which will in turn trigger to read the rest of the Temp file for the other variables, then set gRestoringTheGame to false, so it's not repeating this process every cycle of the game...and while I know this sounds superfluous, it's not.

If you start a new game and there is not gRestoringTheGame flag to stop the constant writing of variables from the temp file, the new game's variables will be overwritten before the player even does anything.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 13, 2020, 01:46:44 PM
Okay! I have the code reading the file numbers into the variables now, so that's good! I'm just not finding the right place to PUT that code. I originally was putting in the Game script's "replay" method, but I don't think that's the right place. I'll keep looking.

So this is getting tricky. Basically, I don't think there is any method or procedure that runs exclusively when you restore the game, which is where I would need to put the code to re-orient the variables.
But Game::replay (in game.sc) is almost explicitly what the engine invokes when you restore a game.

It actually invokes Template::replay (in main.sc, class name may vary), but that calls Game::replay at the end. Either one of them should be a fine place to put the "reload variables from persist.tmp" code.
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 13, 2020, 01:54:37 PM
Okay! I have the code reading the file numbers into the variables now, so that's good! I'm just not finding the right place to PUT that code. I originally was putting in the Game script's "replay" method, but I don't think that's the right place. I'll keep looking.

So this is getting tricky. Basically, I don't think there is any method or procedure that runs exclusively when you restore the game, which is where I would need to put the code to re-orient the variables.
But Game::replay (in game.sc) is almost explicitly what the engine invokes when you restore a game.

It actually invokes Template::replay (in main.sc, class name may vary), but that calls Game::replay at the end. Either one of them should be a fine place to put the "reload variables from persist.tmp" code.

Sounds good! I'll defer to your knowledge and give it another looking into. It would obviously be far superior than my convoluted workaround!

EDIT: Success! It does seem to work just right in the Main Script. Although I think I tried it before, I must have put the code in the wrong place:

Code: [Select]
(method (replay)
(TheMenuBar draw:)
(SL enable:)
        ; PUT IT HERE
(if (DoSound sndSET_SOUND)
(SetMenu MENU_TOGGLESOUND #text {Turn Off})
else
(SetMenu MENU_TOGGLESOUND #text {Turn On})
)
(super replay:)
; DON"T PUT IT HERE

)
Title: Re: SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on December 13, 2020, 02:38:25 PM
I'm going to go ahead and call this on solved! Thanks to Kawa who did all the heavy lifting. You have now provided me with 1 more tool to play with  ;D
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 13, 2020, 03:34:17 PM
If I can't be arsed to be productive myself, at least I've helped someone else be.
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Kawa on December 15, 2020, 02:57:08 PM
I have found a new trick thanks to this puzzle. Unfortunately it's not available in SCI0.

While studying the LSL5 source code, I noticed two uses of the MemorySegment kernel call, regarding which room the game should restart in.

According to the SCI11 interpreter source:
Code: [Select]
/* Allow up to 256 bytes of game data to be preserved when a restart/restore
 * is performed. The first argument is a function code that determines if
 * data is being SAVED FROM the game or being RESTORED TO it.
 * SAVE FROM:
 * Argument 2 - pointer to data area to be saved.
 * Argument 3 - size in bytes of data to be saved; 0 size indicates a
 * string is to be saved. If the size of the data to be
 * saved exceeds 256 bytes, then only the first 256 bytes
 * will be saved.
 * RESTORE TO:
 * Argument 2 - pointer to data area to receive saved data.
 * Argument 3 - *** NOT required because the RESTORE TO function uses
 * the size parameter from the last SAVE FROM function to
 * determine the size of the data area to be restored.
 */
There's a word memorySegment[129] that doesn't get cleared when the engine restarts. The zeroth entry is where the size of the last save is stored.

Larry 5, during initialization: (if (GameIsRestarting) (MemorySegment MS_RESTORE_TO @restartRoom))
During restart: (MemorySegment MS_SAVE_FROM @restartRoom 2)
Once the intro finishes: (= restartRoom 160)

So that once you've entered room 160, the PornProdCorp Lobby, restarting will put you right there instead of going through the whole introduction again, even though all variables including resetRoom are reset.

This is actually a common trick in SCI1 and later!

Edit: implemented it in The Dating Pool lol
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on July 08, 2022, 12:35:46 PM
My external file to keep track of deaths is not quite working properly, to say the least.
I've attached some pictures of the file open in the notepad and the first two look exactly as they should. The first number is the total times died, so the first one is 1, then 2 for the second, but then it goes to 29558 when it should be "3". The other numbers represent certain kinds of death, so there is a "1" in the first, two "1"s in the second picture, and then the numbers go crazy again. The "2" sticks out, but that is correct, as it means the player experienced the same "death" twice. But two of the huge number ones should still be 0.

Any idea how or what might be going on to get these numbers saved out?
My writing out of numbers code looks like this:
Code: [Select]
(= fileHandle (FOpen "persist.tmp" fCREATE))
(if (!= fileHandle -1)
(Format @str "%6d %6d %6d %6d %6d %6d %6d %6d" [gDeaths 0] [gDeaths 1] [gDeaths 2] [gDeaths 3] [gDeaths 4] [gDeaths 5] [gDeaths 6] [gDeaths 7])
(FPuts fileHandle @str)
)
(FClose fileHandle)
One question I do have is what the "6" in "%6d" stands for.

I don't think it's an error in my code to change the variable in the script itself, as my code for that is simply adding by ones:
Code: [Select]
(if (not [gDeaths 6])
(++ gUniqueDeaths)
)
(++ [gDeaths 6])
(= dyingScript (ScriptID DYING_SCRIPT))
(dyingScript
caller: 711
register:
{\nHungry things have to eat. But maybe next time try not letting the food be you!'}
)
(gGame setScript: dyingScript)
It feels like the numbers must be getting mangled in the saving "out" process, but I'm kinda at a loss.
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: troflip on July 08, 2022, 01:57:26 PM
I dunno if this helps, but those weird numbers are the following ascii letters:

svp[space]altn

which when you swap the order for each 16bit value (since SCI is little-endian), you get

"vs plant"

Sounds like maybe you overwrote the gDeath part of memory with a string? What variables come before the gDeath array in your global vars?
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on July 08, 2022, 02:04:24 PM
I dunno if this helps, but those weird numbers are the following ascii letters:

svp[space]altn

which when you swap the order for each 16bit value (since SCI is little-endian), you get

"vs plant"

Sounds like maybe you overwrote the gDeath part of memory with a string? What variables come before the gDeath array in your global vars?
Thanks for the explanation.
the gDeath array is near the top, but looks like this:
Code: [Select]
(local
fileHandle
[str 10] ; Used to read from an external file and update several variables
[gDeaths 10] = [0 0 0 0 0 0 0 0 0 0]
And the procedure I'm using to "write-in" the variables from the external file is:
Code: [Select]
(procedure (ReadTempFile i)
(= [gDeaths i] (ReadNumber (FGets @str 8 fileHandle)))
)
Is there an issue with this?
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: troflip on July 08, 2022, 02:11:56 PM
According to the docs, FGets takes 3 parameters:

http://scicompanion.com/Documentation/Kernels/FGets.html?highlight=fgets

And it returns the number of bytes read, not the string pointer.
Unless you're using some different kernel, or the docs are wrong, it doesn't look like this code works at all?
Title: Re: [RE-SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on July 08, 2022, 02:17:40 PM
According to the docs, FGets takes 3 parameters:

http://scicompanion.com/Documentation/Kernels/FGets.html?highlight=fgets

And it returns the number of bytes read, not the string pointer.
Unless you're using some different kernel, or the docs are wrong, it doesn't look like this code works at all?
I run it a series of times:
Code: [Select]
(= fileHandle (FOpen "persist.tmp" 1))
(if (!= fileHandle -1)
(ReadTempFile 0)
(ReadTempFile 1)
(ReadTempFile 2)
(ReadTempFile 3)
(ReadTempFile 4)
(ReadTempFile 5)
(ReadTempFile 6)
(ReadTempFile 7)
)
(FClose fileHandle)
My understanding is that each call will return the next value down the line - which it does appear to do when working properly. Even when it's not "working properly" it still will make the value of the [gDeaths] variable arrays the corresponding numbers (it's just that the numbers are all wrong!)

Edit: from the attachment of the external file, it will set my arrays as follows: [gDeaths 0] = 2, [gDeaths 3] = 1, [gDeaths 6] = 1, and the rest will be 0.
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on July 08, 2022, 02:30:03 PM
So this is weird. I simply moved the gDeaths array to the top of the variable list and everything seems to be working properly.

But other things are all screwy now...So is there something wrong with how I have declared [str 10]?
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: troflip on July 08, 2022, 02:36:50 PM
Again, unless the documentation is wrong, FGets returns the number of bytes read, not the string pointer. So ReadNumber is reading from the wrong thing.

Ok, looks like the documentation might be wrong then... it returns the string pointer, so that part is fine.

Does the "sv plant" thing ring a bell? Are you using the str local variable anywhere else?
Title: Re: [SOLVED] SCI0 - Variables that aren't reset by Restore
Post by: Doan Sephim on July 08, 2022, 02:41:25 PM
Again, unless the documentation is wrong, FGets returns the number of bytes read, not the string pointer. So ReadNumber is reading from the wrong thing.

Ok, looks like the documentation might be wrong then... it returns the string pointer, so that part is fine.

Does the "sv plant" thing ring a bell? Are you using the str local variable anywhere else?
The "sv plant" thing kinda went over my head. I thought I'd read a few times to see if I could make sense of it, but I haven't been able to do that quite yet.

Edit: Oh, maybe I do get it now. It'd be reading from the text resource perhaps.... makes me wonder if this isn't just an artifact of terrible naming conventions on my part...I'll have to work these out a little bit to see if I can't fix it, now that I see where the error is coming in.

I also use the str variable in another script where I display the number and kinds of deaths. Here's the procedure:
Code: [Select]
(procedure (deathCountIterator integer)
(Display
(Format @str 650 integer)
dsCOORD 20 textDown
dsFONT 4
)
(= textDown (+ textDown 9))
)

Yes, it looks like this code is actually writing the text resource onto the str...