LavishSettings and Passing Data Sequences Between Sessions
Moderators: Lavish Software Team, Moderators
LavishSettings and Passing Data Sequences Between Sessions
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
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
You can always tell if a method was successful by casting to (exists) and converting to string via ${}, like so:
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:
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:
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:
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:
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
echo Whatever:AddSetting[x,y] success=${Whatever:AddSetting[x,y](exists)}
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]}
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]}]
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"
Code: Select all
atom(global) myecho(string output)
{
UIElement[Output@Console]:Echo["${output.Escape}"]
}
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.
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.
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):
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.
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?
---
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}"
}
}
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
}
}
Code: Select all
atom(script) updateCharChat(int sessionNum, string Message)
{
UIElement[Char${sessionNum}Console@${tabName[${sessionNum}]}@CharTabs@controller]:Echo["${Message.Escape}"]
}
WTH am I doing wrong?
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?
I meant to post this question with my last one, sorry for the consecutive posts 
Thanks!
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}]

Thanks!
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:
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.
I would probably point the blame specifically at this line:
Code: Select all
relay "${MC_sessionName}" Script[controller]:ExecuteAtom[updateCharChat,${sessionNum},"${Speaker} ${pipChatChannel} ${Message}"]
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.
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?
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?
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.
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.