Author Topic: Issue with escaping curly brackets in a string, then passing that to a plugin  (Read 3148 times)

alterNERDtive

  • Jr. Member
  • **
  • Posts: 52
So I’m using EDDI as a VoiceAttack plugin. It has a couple neat features, including a proper function for pronouncing star system / body names, which follows somewhat different rules than your everyday speech.

In order to do that, I have to pass {P("<text>")} to the plugin’s “say” context via the “SCRIPT” text variable. Now, when I try escaping the brackets (|{ and |}), the pipes show up on the plugin’s side, messing up the parser:

2020-01-04T00:33:44 [Debug] SpeechService:speak Feeding normal text to synthesizer: |{P("Sagittarius A*")|} (EDDI log output)

When I remove the pipes, the expected thing happens: the brackets get swallowed before the string is passed on to the plugin:

2020-01-04T00:35:09 [Debug] SpeechService:speak Feeding normal text to synthesizer: P("Sagittarius A*")

And now fasten your seat belts, it’s about to get really weird. For debugging, I tried writing the value to the event log. When I straight up add a command to write |{P("Sagittarius A*")|} to the event log, it works as expected. The brackets are escaped, {P("Sagittarius A*")} appears in the log. But when I write the same thing to a variable (e.g. SCRIPT), then write that variable to the log, the brackets are swallowed.

Am I doing something horribly wrong or have I stumbled upon a bug in a feature that no sane person ever uses? :)

Gary

  • Administrator
  • Hero Member
  • *****
  • Posts: 2832
I'll have to code dive on that to see what's going on.  Unfortunately, I won't be able to get into for at least another week as I will be out of pocket for that time :(

alterNERDtive

  • Jr. Member
  • **
  • Posts: 52
No problem. I appreciate your fast response as usual and am content to have it put on your radar :)

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
I tried writing the value to the event log. When I straight up add a command to write |{P("Sagittarius A*")|} to the event log, it works as expected. The brackets are escaped, {P("Sagittarius A*")} appears in the log. But when I write the same thing to a variable (e.g. SCRIPT), then write that variable to the log, the brackets are swallowed.

That is normal. Both the "Text" field of the "Set a Text Value" action, and the "Value" field of the "Write a Value to the Event Log" action will parse tokens.

So, the former will strip the pipes from |{P("Sagittarius A*")|}, setting the variable to {P("Sagittarius A*")}, but then the latter will strip the brackets as they are not part of a valid token, resulting in P("Sagittarius A*").




The only way I can get the pipes to be preserved is to use the "SetText" method from within an inline function (which should be equivalent to a plugin, method-wise), as that method correctly does not process tokens.
If I set a text variable using the "Set a Text Value", the pipes get stripped, as proven by retrieving its value using the "GetText" method (which does not parse tokens either).

E.G.
Code: [Select]
MessageBox.Show(VA.GetText("test"));
VA.WriteToLog(VA.GetText("test"));
will both show "{P("Sagittarius A*")}".

Only if I set the value from within the inline function
Code: [Select]
VA.SetText("test", "|{P(\"Sagittarius A*\")|}");do the pipes remain in place.


EDDI's VoiceAttack plugin apparently uses an older version of the plugin interface, as Version 4 does not pass along any fields other than "Plugin Context".


EDIT: Just in case, I checked with a legacy plugin template using the following:
Code: [Select]
public static void VA_Invoke1(String context, ref Dictionary<string, object> state, ref Dictionary<string, Int16?> shortIntValues, ref Dictionary<string, string> textValues, ref Dictionary<string, int?> intValues, ref Dictionary<string, decimal?> decimalValues, ref Dictionary<string, Boolean?> booleanValues, ref Dictionary<string, object> extendedValues)
{
    dynamic VA = state["VA_PROXY"];
    VA.WriteToLog(textValues["SCRIPT"]);
}
If the variable is set using the "Set a Text Value" action, the pipes are still stripped correctly I.E. "{P("Sagittarius A*")}" is correctly written to the log).
« Last Edit: January 06, 2020, 12:20:19 PM by Pfeil »

alterNERDtive

  • Jr. Member
  • **
  • Posts: 52
EDDI's VoiceAttack plugin apparently uses an older version of the plugin interface, as Version 4 does not pass along any fields other than "Plugin Context".

Well, words are hard. It’s not. I’m setting the SCRIPT text variable, then I’m calling the plugin, and it reads the variable. Not using the old interface.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
The author of the plugin confirmed to me that it is actually using the old interface.

Any fields other than "Plugin Context" are only accessed by plugins not using Version 4.


How are you setting the "SCRIPT" text variable?

alterNERDtive

  • Jr. Member
  • **
  • Posts: 52
So, just to make sure i’m not making a huge mess right now;

Old plugin interface: you choose a plugin and a context in the “execute an external plugin function” dialogue, and put variables you want to pass to the plugin into the various input fields for each type.

New plugin interface: you set variables the plugin expects to be set, then only choose a plugin and a context in the “execute an external plugin function” dialogue.

Correct?

Because if that is correct, EDDI is very much using the new interface. 1000%.

Edit: went and double-checked. While I do have an awful lot of commands that needlessly “try” to use the old interface, the attached example works just fine.

BUT trying to reproduce the original bug example, instruction for instruction, I do now see

2020-01-12T00:57:02 [Debug] SpeechService:speak Feeding normal text to synthesizer: {P("Sagittarius A*")}

in EDDI’s log file. I’m at a loss. Lost and confused.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4782
  • RTFM
Both the context (for Version 4 and Version 3) and the variable names (for Version 3) are not strictly required to call a plugin (though the methods inside that plugin may require that data to function correctly), but yes.

And yet, EDDI's github page states:
Quote from: https://github.com/EDCD/EDDI/wiki/VoiceAttack-Integration
say

This function uses EDDI's voice to read a script. It takes one mandatory and two optional parameters.

    'Script' (text variable) is a mandatory parameter containing the script to be read.
    'Priority' (integer variable) is an optional parameter defining the priority of the invoked speech (defaults to 3).
    'Voice' (text variable) is an optional parameter defining the name of the voice you want to use. Note that when you set this variable it will continue to be used until you unset it, at which point EDDI will use the voice configured in its text-to-speech settings.

To use this function in your own commands use the 'Execute an external plugin function' command with the plugin context set to 'say' and passing the parameters described above.
(bold emphasis mine)

The author (I say "The", an author, at least; I don't know who and how many people work on it) literally told me they're using "legacy v3 compatibility", and their help document seems to say you need to explicitly pass those variables.
Having a look through their source code now, it shows clearly that they are in fact using Version 4:
Code: [Select]
public static void VA_Invoke1(dynamic vaProxy)
It also shows they're not doing anything "exotic" to get the variable value for the "say" feature:
Code: [Select]
string script = vaProxy.GetText("Script");

Either way, I cannot replicate this issue. I have tried plugins using Version 3 and Version 4, had the latter retrieve the variable value directly while also passing the variable name from the action, and it never shows the pipes.

It makes no logical sense that it would ever show the pipes (if you are using the "Set a Text Value" action to set the variable), as the "Set a Text Value" action itself will remove the pipes before the variable is even set and passed to the plugin.


If you have a command that reliably replicates this issue, by all means share it.

Tkael

  • Newbie
  • *
  • Posts: 49
Pipes are not being passed via the "Set a Text Value" action. There's no issue on the VoiceAttack side here.

This is simply an edge case that EDDI's development team hadn't anticipated so I've written a pull request to address this from within EDDI.

Gary

  • Administrator
  • Hero Member
  • *****
  • Posts: 2832
Thanks for working this out while I was away, guys - I really appreciate that.

alterNERDtive

  • Jr. Member
  • **
  • Posts: 52
I’m just getting the feeling that my Windows PC has gained conscience and is trying to troll me, because I still can’t reproduce the issue I had initially (pipes ending up on EDDI’s side with the brackets) – and that’s the 2nd time I’ve had a weird issue that just resolved itself … (see https://forum.voiceattack.com/smf/index.php?topic=2977.msg13726#msg13726)