LavishSettings and Passing Data Sequences Between Sessions

Discussion of Inner Space

Moderators: Lavish Software Team, Moderators

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

LavishSettings and Passing Data Sequences Between Sessions

Post by agitated » Mon Feb 11, 2008 2:41 pm

I'm not getting any responses to my IS questions at other locations so I'm back here, but I think these are relatively straight forward questions so hopefully won't need long explanations (and if they do, a quick pointer should suffice and I can puzzle out the rest).

First Question:

When my script runs, it creates a generic LavishSettings XML file. When the script is rerun and finds that file to exist, it does an import only. While the script is running, changes to settings are made and the settings file is exported right there at the time of change. When I look at the settings file right after that tho, none of the changes are there or in memory. Why? And how do I force a setting change and write it out?

I tried to just update with AddSetting but that might only be used to define the setting, not update it. Then I tried to :Remove the setting followed by an :AddSetting with the new value, but still no go.

Second Question:

I have a session that reads in the settings XML file mentioned above. After it's loaded, when the user presses a button, the script looks in the settings to find which command to execute. These commands are data sequences that need to be passed to another session. How can I do this without the data sequences being interpreted?

I tried .Escape and also '\' and double '\' with limited success. I also see that .Escape doesn't escape commas. How can I protect the commas and any text that follows them?

So if someone tells me 'you suck, nub' the only thing that gets relayed is 'you suck'. How can I get the full text?

OK that sounds like lots of questions and I apologize. I'm so close to finishing my little app and am desperate for clarification.

If you don't feel like long explanations, don't. I can figure most stuff out with just a nudge in the right direction.

Thanks for any help!

~a

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Mon Feb 11, 2008 7:13 pm

First question has been resolved, at least partially. Even though my syntax for creating settingsetref variables looks ok, something in my use of them prevented updates to the settings in memory and, subsequently, to disk.

Using the full 'LavishSettings[]...' syntax does update the settings.

Lax
Owner
Posts: 6634
Joined: Fri Jun 18, 2004 6:08 pm

Post by Lax » Tue Feb 12, 2008 9:53 am

You can always tell if a method was successful by casting to (exists) and converting to string via ${}, like so:

Code: Select all

echo Whatever:AddSetting[x,y] success=${Whatever:AddSetting[x,y](exists)}
As far as using settingsetref, the most common mistake is using the "variable" keyword and expecting it to execute on that line in order as if it were a command. So people do something like this:

Code: Select all

LavishSettings:AddSet[Uncle John's Uber Script]
LavishSettings[Uncle John's Uber Script]:AddSet[General]
variable settingsetref General=${LavishSettings[Uncle John's Uber Script].FindSet[General]}
LavishSettings[Uncle John's Uber Script]:AddSet[Users]
variable settingsetref Users=${LavishSettings[Uncle John's Uber Script].FindSet[Users]}
In the above example, neither settingsetref is going to be initialized properly, even though at first glance it looks like it would. The actual execution order is different than you might expect: the variable keywords are processed at the very top of the function, before any code executes, and therefore before the :AddSet methods are called at all. If I were to add an echo ${Users.Name} at the end, if it were successful it should output "Users", but since both initialized to NULL (there was no such sets when the variables were initialized) the settingsetref does not point to a set, and therefore ${Users.Name} doesn't exist and returns NULL. i.e. echo ${Users.Name(exists)} == NULL.

If this is what is happening in your case, simply use late initialization as the LavishSettings documentation shows:

Code: Select all

variable settingsetref General
variable settingsetref Users

LavishSettings:AddSet[Uncle John's Uber Script]
LavishSettings[Uncle John's Uber Script]:AddSet[General]
LavishSettings[Uncle John's Uber Script]:AddSet[Users]

General:Set[${LavishSettings[Uncle John's Uber Script].FindSet[General]}]
Users:Set[${LavishSettings[Uncle John's Uber Script].FindSet[Users]}]
Maybe I should have been more strict with the "variable" keyword, requiring it to actually appear in the first lines of the function. I'll have to consider that, and it would drastically reduce confusion.

So anyway I just gave you a couple tools you can use to help determine where your fault is -- if ${MySettingSetRef.Name(exists)} is NULL, then your settingsetref is not pointing at a set, and that's why the AddSetting would fail.

Now for your escaping question.

To prevent data sequences from being interpreted, escape the $ at the beginning. echo \${Display.FPS} will literally echo ${Display.FPS} rather than evaluating it and outputting a number. string.Escape does not escape commas, because commas are handled by quoting. This is what string.Escape DOES escape: "Uses slashes to escape \, ", carriage return, line feed, tab, as well as LavishScript data sequences"

You might need to play around with the escaping a little bit to finally arrive at your desired result. Say you have a command that takes 2 parameters, one being the name of whoever sent you a tell, and the other being the message, so when someone tells you "you suck, nub", you want the command executed to be:

Code: Select all

OnTellReceived Someone "you suck, nub"
The double quotes cancel any processing of commas and semi-colons. If you're passing that to SomeConsole:Echo, you need to make sure it's again quoted there. The previous example I gave takes care of this:

Code: Select all

atom(global) myecho(string output)
{
    UIElement[Output@Console]:Echo["${output.Escape}"]
}
The double quotes around the data sequence ensure that it is one parameter, and the .Escape ensures that any double quotes are escaped, so OnTellReceived could do something like this:

Code: Select all

myecho "${Sender} tells MyCharacterTwo, '${Message.Escape}'"
And that's going to produce the desired output no matter what.

Then you just need to get a handle on relay and any escaping that may be required.
[code]relay is1 -noredirect echo ${ParseLocal} \${ParseRemote} \\\${ParseNeither}[/code]
This little gem demonstrates 3 different escaping levels that you might find useful with relay. On the first pass (when relay is executed), this is going to turn into
[code]relay is1 -noredirect echo parsed ${ParseRemote} \${ParseNeither}[/code]
On the second pass (when echo is executed on the remote end), this is going to turn into
[code]relay is1 -noredirect echo parsed parsed ${ParseNeither}[/code]
This of course is because each pass strips one level of escaping, making \\\$ into \$ and then \$ into $, and any data sequence that isn't escaped is interpreted. Standard quoting rules should apply, so use double quotes around anything that should be enforced as a single parameter.

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Tue Feb 12, 2008 11:41 am

Thank you Lax. Your explanations are so thorough they really expedite understanding.

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Wed Feb 13, 2008 11:21 am

Well, damn. So much for puzzling it out. Here's a modified version of a post I made at isxgames, so far with no responses.:

---

I have chat text being passed from session 1 into the uplink, and then on to session 2.

Here is the function running on session 1. ${Message} is quoted and echoed before sending, and the commas are preserved; the message looks good.

Code: Select all

atom(script) EQ2_onIncomingChatText(int ChatType, string Message, string Speaker, string ChatTarget, string SpeakerIsNPC, string ChannelName)
{ 
  if "${Speaker.NotEqual[${Me.Name}]}"
  {
   echo "----> ${Message}"
   Uplink ccChat "${ChatType}" "${Message}" "${Speaker}" "${ChatTarget}" "${SpeakerIsNPC}" "${ChannelName}" "${sessNum}"
  }
}
Once the text arrives in the uplink's function, it still looks ok from the echo. Here's the uplink's function that receives the text from session 1 (just the relevant piece):

Code: Select all

atom(global) ccChat(int ChatType,string Message,string Speaker,string ChatTarget,string SpeakerIsNPC,string ChannelName,int sessionNum,string toSession)
{
  switch ${ChatType}
    {
      case 8
        echo "----> ${Message}"
        relay "${MC_sessionName}" Script[controller]:ExecuteAtom[updateCharChat,${sessionNum},"${Speaker} ${pipChatChannel} ${Message}"]
        break
    }
}
And finally, here's the receiving function in session 2. When this gets passed to the console.Echo, there are no commas and anything after a comma has been truncated.

Code: Select all

atom(script) updateCharChat(int sessionNum, string Message)
{
  UIElement[Char${sessionNum}Console@${tabName[${sessionNum}]}@CharTabs@controller]:Echo["${Message.Escape}"]
}
I tried various .Escape and \ combos between functions as well as adding single quotes around ${Message} within a double-quoted string, but the chat text either showed up in quotes but still truncated without the commas, or with each word of the text surrounded in quotes, or as an escaped, uninterpreted data sequence.

WTH am I doing wrong?

Lax
Owner
Posts: 6634
Joined: Fri Jun 18, 2004 6:08 pm

Post by Lax » Wed Feb 13, 2008 9:39 pm

The problem might actually be the uplink command, which I think uses an older system than relay. I'll have to check that. In the meantime, try using relay to the name of the uplink instead (which by default is your computer name, this is configurable)

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Wed Feb 13, 2008 11:37 pm

The output looks the same using the uplink name with relay instead of 'uplink': stripped and truncated.

I added an echo to session 2 (the destination of ${Message}) and it's the only one that looks incorrect, so it's being stripped on the outbound side of the uplink or the :Echo?

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Thu Feb 14, 2008 12:03 am

For \ escaping data sequences, if ${newCmd} is assigned \${Target.Name}, or even \\${Target.Name}, the value of ${newCmd} is the interpreted command (the actual target name) or NULL (tested to a depth of 5 \'s), instead of the raw data sequence itself.

When LavishSettings interprets ${newCmd}, should it write the setting value as ${Target.Name} or is there another layer of interpretation?

Code: Select all

LavishSettings[controller].FindSet[Char${sessionNum}].FindSet[${btnID}]:AddSetting[bCmd,${newCmd}]
I meant to post this question with my last one, sorry for the consecutive posts ;)

Thanks!

Lax
Owner
Posts: 6634
Joined: Fri Jun 18, 2004 6:08 pm

Post by Lax » Thu Feb 14, 2008 9:51 am

Oh. I just took a closer look at your post. Whenever you're passing Message around, you must use ${Message.Escape} to preserve it. If there are any double quotes in Message, then your parameterization is not preserved. Variables are expanded by the command processor before parameters are determined.

I would probably point the blame specifically at this line:

Code: Select all

relay "${MC_sessionName}" Script[controller]:ExecuteAtom[updateCharChat,${sessionNum},"${Speaker} ${pipChatChannel} ${Message}"] 
Make sure that's using ${Message.Escape}, though the line in EQ2_onIncomingChatText should be using .Escape as well.


There is not another layer of interpretation. If ${newCmd} contains ${Target.Name} at the time of execution, then that is what will literally be written via AddSetting. However, say newCmd contains Target.Name instead, now you can do ${${newCmd}}, which both data sequences will be processed, from the inside out. So the outer evaluates, which forces the inner to evaluate, so ${newCmd} is replaced with Target.Name, so the outer data sequence becomes ${Target.Name}, which then gets evaluated as if it were the data sequence in the first place. If ${newCmd} is passed around without escaping, and it contains ${Target.Name}, then as it is passed around, it will keep getting re-interpreted.

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Thu Feb 14, 2008 12:28 pm

I just tested using .Escape in all three functions, in the first function only, in the first two functions only, in the second function only, in the last function only (original code), in the first and last functions only, and in the second and last functions only.

The result is broken text in each case, although broken in different ways.

Sometimes only the first word of the text would show up, sometimes the text would be stripped of commas and truncated, sometimes it would be stripped and truncated with each word surrounded by double quotes, and on one occasion only three words of the text showed up and they were out of order.

If the syntax you recommend works for you, should I reinstall IS? Would corruption cause this kind of problem?

Lax
Owner
Posts: 6634
Joined: Fri Jun 18, 2004 6:08 pm

Post by Lax » Thu Feb 14, 2008 2:44 pm

No, reinstall won't help. I'll have to do some testing.

Lax
Owner
Posts: 6634
Joined: Fri Jun 18, 2004 6:08 pm

Post by Lax » Fri Feb 15, 2008 11:07 am

Ok. It's definitely from relaying the method execution. I did some testing and discovered that the command that should have worked was getting re-escaped in the process and not coming out right on the other end of the relay.

Inner Space build 4603 is up now as a development build, with this bug fixed. You can switch to it by opening up the IS Patcher window, check "Download Development Patches", close and restart Inner Space (you can switch back using the same process -- unchecking the development box and restart IS). Note that the "Patch Now" option does not re-query the server for a file list, and will only patch if the "Files changed on server" list has files in it, so this is why you must restart IS.

Give it a try and let me know how it goes with your own testing.

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Fri Feb 15, 2008 11:14 am

Sweet, testing now.

Thanks man!

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Fri Feb 15, 2008 6:42 pm

That fixed it, works flawlessly :D

agitated
GamingTools Subscriber
Posts: 30
Joined: Sat Apr 28, 2007 5:05 pm

Post by agitated » Fri Feb 15, 2008 9:52 pm

There is an issue. The patch breaks this:

"${LavishScript.HomeDirectory}/Scripts/UI/some.xml"

It resolves the variable to 'C:/Program', breaking on the space between Program and Files.

~a

Post Reply