Author Topic: Save To Profile -Realtime- A Variable's Value  (Read 5203 times)

Starblue7

  • Full Member
  • ***
  • Posts: 131
Save To Profile -Realtime- A Variable's Value
« on: May 26, 2023, 04:50:59 PM »
In reading through various things, and also spotting this old reply by Pfeil:

VoiceAttack only writes saved values to the profile database either when VoiceAttack is shut down gracefully, or when a change to a profile is saved manually (from the "Edit a Profile" window), so the chances are very slim (of course that does mean that data can be lost until it has actually been written to the database).

I'm to understand that the only way a variable with an assigned value will be saved between sessions with the 'Save To Profile' option checked in the command, is upon the CLOSE event of the Voice Attack application.

I would like to be incorrect, and I am searching for the ability/option to specify for particular variables to 'real-time' write said variable's assigned value to the profile.  This, so as to retain the set value in the case of an application/system crash.

Perhaps Voice Attack has, or can have, a temp cache saved on to disk of any information (like variables intended to be saved to the profile) and if that cache still exists on Voice Attack load-up, it means the application wasn't properly closed with a proper application shutdown (i.e. crash), and on load-up, Voice Attack can do a clean up and pull in those saved values from the temp cache on disk and pull in the intended 'Save To Profile' variables for a seamless recovery for the user.

ULTIMATELY

I'm looking for a way to retain several variable values over sessions without the worry of potentially losing those values if the application or system crashes.

If there is an existing method within VA currently to preserve variables in this manner, using VA functionality, please advise with example of how.

If it requires me to have my code actually write those particular values to a text file and do a compare on Profile Load, comparing those values which SHOULD be saved with Voice Attack's current saved profile values, please advise with example of how.

I really would prefer the FORMER, with the idea I mentioned above this section, and would request that to be considered for a future update/feature.

SemlerPDX

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 291
  • Upstanding Lunatic
    • My AVCS Homepage
Re: Save To Profile -Realtime- A Variable's Value
« Reply #1 on: May 27, 2023, 12:09:10 PM »
I ran into this issue myself. I ended up creating a save file system using inline functions that can write VA variables to a file, change a variable value already on file, or delete a variable from the file - and of course to load all variables and cast them as the appropriate type (or just one variable by name on request).

Because the profile variables are only saved to the ACTIVE profile, it is also a concern when you are working with global or included profile commands that you know WHERE these variables are being saved in order to load them.

If Profile A is the owner of TextVariableA, and Profile A is Global or included in another profile such as "Profile B", and we are in Profile B (where Profile B is the ACTIVE profile), when we execute the command in Profile A to "Save TextVariableA to profile", and then close VoiceAttack, that value will be saved.... to Profile B.  If we then launch VoiceAttack and switch to Profile A, tell it to load TextVariableA from profile, it will NOT contain the value we saved before the last close, not until we switch to Profile B and THEN load TextVariableA.

This is a powerful feature of VoiceAttack, but it is not perfect for all use case scenarios.  If you are developing profiles and command systems which are advanced enough to absolutely rely upon saved variables between sessions, the only way to ensure these retain value is to write your own save file system.

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #2 on: May 27, 2023, 06:01:41 PM »
I ran into this issue myself. I ended up creating a save file system using inline functions that can write VA variables to a file, change a variable value already on file, or delete a variable from the file - and of course to load all variables and cast them as the appropriate type (or just one variable by name on request).

Because the profile variables are only saved to the ACTIVE profile, it is also a concern when you are working with global or included profile commands that you know WHERE these variables are being saved in order to load them.

If Profile A is the owner of TextVariableA, and Profile A is Global or included in another profile such as "Profile B", and we are in Profile B (where Profile B is the ACTIVE profile), when we execute the command in Profile A to "Save TextVariableA to profile", and then close VoiceAttack, that value will be saved.... to Profile B.  If we then launch VoiceAttack and switch to Profile A, tell it to load TextVariableA from profile, it will NOT contain the value we saved before the last close, not until we switch to Profile B and THEN load TextVariableA.

This is a powerful feature of VoiceAttack, but it is not perfect for all use case scenarios.  If you are developing profiles and command systems which are advanced enough to absolutely rely upon saved variables between sessions, the only way to ensure these retain value is to write your own save file system.

Wow.  Thanks for the great information about how it works in VA currently @SemlerPDX!
I certainly appreciate that not everything can be done or designed to work to accommodate most use-cases.
However, it seems a bit of a shame to me that VA doesn't offer a more robust method in handling saved variables, in particular, for the case you mentioned above.

I would have thought that VA would have been able to determine the command origin (regardless of global, included profile) and would take that into account when performing it's internal save to the owning command's profile.

EDIT:  I mean, I'm working with perhaps some faulty logic that a 'Set Variable' action with a 'Save value to profile' setting within a profile's command will/can be tied to the command, and then the command tied to the owning profile of that command.

It would be nice if VA could:
1.  Resolve the situation you mentioned above
2.  Provide a more resilient way to preserve variables on a more real-time basis, like using some cache method or something.

I think this especially important for persistent 'states' over sessions that we're trying to maintain for our Voice Attack profiles.   The current design I guess for 'Save Value to Profile' assumes we're working with only one single profile.
I thought each profile and commands have their own unique GUIDs, in order to help with that ID determination, no?
It's probably what I might use if I have to re-create the wheel and make a file-save system, as you suggested.

However, in getting a Command's Profile GUID...  (not sure how possible it is to make this association)

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #3 on: May 27, 2023, 08:56:55 PM »
I suppose I could use something like below, but this doesn't tell me the actual Command's <ID> right?  Just the InternalID(Profile) of that command?

Guid? commandId = vaProxy.Command.InternalID();

When the above line runs, does it actually return the InternalID(Profile ID) GUID of the origin command?  Or will it return the InternalID of the active profile?

I don't see anything else in the document that actually allows one to retrieve the Command <ID> of a particular command itself within a particular profile.  Perhaps I'm missing something.


Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4790
  • RTFM
Re: Save To Profile -Realtime- A Variable's Value
« Reply #4 on: May 27, 2023, 09:02:36 PM »
Why are you expecting a command property to be a profile ID?

Commands have their own <InternalID> tag, as mentioned in the "VoiceAttack Author Flags" section of the documentation.

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #5 on: May 27, 2023, 09:11:10 PM »
I guess I'm obviously not reading it correctly then and failed to understand it's the ACTUAL Command's <ID> and not the profile's InternalID. ?

Appreciate the corrections and any explanations you'd like to impart.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4790
  • RTFM
Re: Save To Profile -Realtime- A Variable's Value
« Reply #6 on: May 27, 2023, 09:23:36 PM »
I can't know what you're reading or how you're interpreting it, but the documentation states
Quote
Command-level flags
Below are the available command-level flags that you can use. Again, you’ll only be able to
access this flag by editing an uncompressed .VAP file with a text editor.

<InternalID> - The InternalID element will allow you to specify your own GUID value to
identify an individual command. This value can be accessed from the proxy method
Command.InternalID(). See, ‘VoiceAttack Plugins (for the truly mad)’ earlier in this document.

"specify your own GUID value to identify an individual command"


As far as I'm aware there is no method for determining which profile a command originated from.
If I recall correctly that information isn't stored after included and global profiles are merged into the active profile.

SemlerPDX

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 291
  • Upstanding Lunatic
    • My AVCS Homepage
Re: Save To Profile -Realtime- A Variable's Value
« Reply #7 on: May 27, 2023, 10:57:54 PM »
... that actually allows one to retrieve the Command <ID> of a particular command itself within a particular profile.

When dealing with the Command.InternalID() flag, I think he means where is the part were we tell it which command we want the InteralID of in the example in the manual:

Code: [Select]
Guid? commandId = vaProxy.Command.InternalID();  // ?? OF what command? (answer: THIS command)
if (commandId.HasValue) //if the internal id was indicated
{
  //do something with the ID here
}

... The way something like this would be used is when a command is executed, inside that command in an inline function or in the plugin context executed by that command.  This vaProxy.Command object will refer to the command which has executed this inline/plugin, and through this, we can get a lot of information about that command, including this value.  Each command in an XML expanded .vap file will have a field we can set <InternalId xsi:nil="true" /> to a GUID value of our choosing such as <InternalId>71040209-abcd-4ef2-3dad-9da5aac27ab3</InternalID> (for example), and then perhaps if this had significance for our systems and we needed to check if the executing command has an InternalID which matches this known GUID value of some special command we are monitoring, we could use the above example to obtain that InternalID flag for that command and act accordingly (again, a rough example). Still not sure how this is useful to you, as you can always tell which command executed your inline or plugin context in other ways, but this exists nonetheless as needed. You can even get information about the command which is currently executing such as the 'when I say' phrase used, category, etc.

The section just above this in the manual describes how all these work:
Quote
Below are the attributes that belong to the Command object of vaProxy. These attributes
pertain to commands (including the command that has invoked the plugin function or inline
function).

Since this value is wholly up to the designer to add to a command, they would very well know which profile it comes from, or should, as there would be no question unless they copied that same GUID to the command InternalID of another command in another profile, which would absolutely defeat the purpose.

If needed, you can set up events to fire when certain command(s) execute.

SemlerPDX

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 291
  • Upstanding Lunatic
    • My AVCS Homepage
Re: Save To Profile -Realtime- A Variable's Value
« Reply #8 on: May 27, 2023, 11:46:21 PM »
It would be nice if VA could:
1.  Resolve the situation you mentioned above
2.  Provide a more resilient way to preserve variables on a more real-time basis, like using some cache method or something.

I think this especially important for persistent 'states' over sessions that we're trying to maintain for our Voice Attack profiles.   The current design I guess for 'Save Value to Profile' assumes we're working with only one single profile.
I thought each profile and commands have their own unique GUIDs, in order to help with that ID determination, no?
It's probably what I might use if I have to re-create the wheel and make a file-save system, as you suggested.

The action is literally to save the variable value to the active profile, has nothing to do with commands. This is sufficient for like 99% of the cases for how variables are typically used in VoiceAttack profiles, even multiple profile setups. If you are in a particular state, such as "in" an Active Profile, it is likely for a reason - such as using commands within that profile.  Variables changed by that profile and saved are saved to that profile which makes logical sense that to restore that value in another session, we simply need to make that profile the Active Profile once again, and load the variable value.

The use of more advanced profile management such as some sort of "hub" profile is just that - a niche application for advanced non-standard purposes.  In those cases, a simple save-to-file and load-from-file system would be far more appropriate, and quite simple to code as well.  Parsing text files, or XML or JSON files should be an essential area of study for someone interested in inlines and/or plugins for more advanced control and systems development in VoiceAttack, and is also a great place for beginners to start as it's fairly straightforward logic and not too complicated.

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #9 on: May 28, 2023, 01:11:37 AM »
This explains it better, thanks.

I think I'm interpreting the Profile ID (GUID Identifier) to be the <InternalID> at the tail-end/very-end of the .vap xml file of the profile, and that the CommandID would be equal to the <ID> within the first section at the top of the command within <Command>.

However, I guess it's just sufficient that every time I need to store a variable, and recall a variable, it's perhaps sufficient to simply do that using the <InteranID> of the Source Profile as the identifier, and upon import, use that to somehow apply the variable value read from a file to that profile.

I mean, I won't need to store EVERY variable defined in my profile, just a very limited amount.
This, I suppose could be handled by a call routine to a single command within my profile, and this command would have an inline function specifically meant to capture the state of particular variables throughout my profile and save/update to external file.  When needing to recover these values, just do that in reverse.

Maybe it's not as simple as I'm portraying it.

Though.  Still.  It'd be nice if VA allowed variable save per profile (without any merging) so even if the user is running included commands and variables from Profile A while in Profile B, that those variables will still only apply to the intended Profile 'A'.

@SemlerPDX, would you mind helping me in the right direction for the coding of something like that above?  I don't expect you to share all your secrets and full code.  But having some examples def. goes a long way.

Thanks in any case in advance!   ;)

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4790
  • RTFM
Re: Save To Profile -Realtime- A Variable's Value
« Reply #10 on: May 28, 2023, 01:46:52 AM »
The "<ID>" tag is set by VoiceAttack itself, and is not intended to be modified by the user.


Again, the documentation, which I quoted in my previous post, clearly references the <InternalID> tag, and notes that said tag needs to be explicitly populated by the profile creator.

That tag exists both at the profile level, as well as for each individual command. XML tags don't need to be unique if what they apply to can be disambiguated by their nesting.

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #11 on: May 28, 2023, 04:55:42 AM »
Pfeil,

Yes, I've already generated an <AuthorID>, <ProductID> and <InternalID>

I'm not touching <ID>'s within <CommandActions>s, nor the <BaseID> or top-level <Id>jus above the <Name> tag of the Profile Name.

However, I wonder about this <Id> Tag above the <Name> tag.

I do wonder about the <SourceProfile> tag and how it can be used and to what benefit.

Anyways.  Thanks.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4790
  • RTFM
Re: Save To Profile -Realtime- A Variable's Value
« Reply #12 on: May 28, 2023, 02:12:30 PM »
Tags like <Id> and <SourceProfile> are not intended to be modified by the user.


Again, every command has its own <InternalId> tag, in addition to the profile-level <InternalID> tag

If you want Command.InternalID() to return a value, you need to set that <InternalId> tag, for each command individually.


Editing an XML-formatted .vap is only intended for changing the values the documentation specifically mentions can be changed by advanced users.

The vast majority of the data in an XML-formatted .vap is serialized only to facilitate reconstruction of the profile and its commands, as it existed within the profile database, and thus normally should not be edited at all.

SemlerPDX

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 291
  • Upstanding Lunatic
    • My AVCS Homepage
Re: Save To Profile -Realtime- A Variable's Value
« Reply #13 on: May 29, 2023, 11:41:55 AM »
@SemlerPDX, would you mind helping me in the right direction for the coding of something like that above?  I don't expect you to share all your secrets and full code.  But having some examples def. goes a long way.

Thanks in any case in advance!   ;)

How you proceed will depend on options you choose, how it will be executed (inline function code or from a plugin you create), and what you are capable of learning.

1. Choose whether you will execute this code from an inline or plugin
2. Decide on the data storage structure you will execute (text file, XML, JSON, even SQL, etc.)
3. Learn how to write and read entries in this structure
4. Build and test your functions for save all/save one/load all/load one (however you feel is best)
5. Implement your design and find some beta tester that is NOT on your local machine (this matters!!)

The basic "game loop" of learning to code is this:  study -> try -> fail -> learn -> repeat

Data structures such as a flat text file can be as simple as using a "name=value{NEWLINE}" structure. Loading involves reading all lines, splitting those lines at the "Environment.Newline" separating them, and then splitting each line at the "=", which provides access to the name and value which you can easily use such as 'VA.SetText(name, value)`.  Just know that such a flat text file system has limitations and drawbacks including replacing symbols such as "=" with some keyword you can replace after you have finished splitting the line at the "=" separating the name and value, else such a symbol in the value would throw off your parsing system.  Use TryParse (or just Parse) methods to get values such as Integers, Decimals, or Booleans back into their correct data type from strings for setting VA variables.

Code: (csharp) [Select]
// For example, if we had the string value from the file reading as "true":
string nameValue = "MyVarName";
string stringValue = "true";
bool booleanValue;

if (bool.TryParse(stringValue, out booleanValue))
{
    VA.SetBoolean(nameValue, booleanValue);
}
else
{
    // Conversion failed, handle the error case
}


If you use something like JSON or XML, you can read the file using systems that already have methods for iterating through and acquiring data values from each entry (such as `entry.Name` or `entry.Value` for a deserialized JSON file which contains fields of 'Name' and 'Value' for each entry), and so might be more structured and easy to work with. The benefit of these file types is that they are still human readable and can be manually opened in any Notepad to review their contents and values, or even manually change them.  These can become a pain to load in any Notepad or read into memory programmatically when their size grows to the realm of thousands or tens of thousands of entries. A plugin would be required for JSON, but you could get away with parsing an XML in an inline alone.

Code: (csharp) [Select]
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;

/// ...then in your class/method:

// Assuming you have a JSON file at the given file path
string filePath = @"path\to\your\file.json";

// Read the JSON file contents
string json = File.ReadAllText(filePath);

// Deserialize the JSON into a Dictionary<string, object>
Dictionary<string, object> deserializedObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);

...then you could iterate through each key/value pair in the `deserializedObject` dictionary and cast each value as the appropriate type while setting them to the appropriate VA.Set methods for that entry type.


SQL is a database structure which doesn't allow us to manually view the contents of the file without an interface of some kind. A plugin would be required for any sort of SQL. I prefer EntityFramework because it is perfectly suited for working with .NET objects as we already are in C# plugins for VoiceAttack. This type has the benefit of being able to grow in size to limits only dictated by the machine it runs on and other factors on such a massive scale that for tiny users like us could be considered limitless. It is extremely fast to query for an entry based on its key value, which is typically a unique integer but can be changed to any data type through annotation [Key] such as a string, so long as each entry has a unique string for this field (much like a save file would, no variable name is the same as another).

Explore what works best for you, and use google and/or ChatGPT to help explain concepts you are not familiar with - using the prompt qualifier "Explain this like I'm 5:" before your question can help ChatGPT form basic analogies to help with the learning curve - just don't expect it to be able to write all your code for you, it makes mistakes and assumptions frequently and should be used to get you started but only to proceed with private testing and appropriate modifications/alterations on your part before implementation.

Best wishes and good luck!!
« Last Edit: May 29, 2023, 02:06:34 PM by SemlerPDX »

EricM

  • Newbie
  • *
  • Posts: 15
  • VA user since 2017
Re: Save To Profile -Realtime- A Variable's Value
« Reply #14 on: May 29, 2023, 12:54:29 PM »
I love C#, and would encourage the learning of it. But for a similar scenario I found that the 'Write Text to a File' action with variable tokens for the path works quite simply.  For text you just 'Set Text' from file/URI and use the same tokens.

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #15 on: May 29, 2023, 06:54:05 PM »
@SemlerPDX, would you mind helping me in the right direction for the coding of something like that above?  I don't expect you to share all your secrets and full code.  But having some examples def. goes a long way.

Thanks in any case in advance!   ;)

How you proceed will depend on options you choose, how it will be executed (inline function code or from a plugin you create), and what you are capable of learning.   

Thanks @SemlerPDX.

I've done this years ago with VBA, but C# is a different beast.
The concepts I understand.  It's just the under-the-hood references, calls, methods, etc that I'm still getting up to speed with.

I mean, this doesn't necessarily have to be complex.  I might choose XML just for the logical structure, but I'm talking about maybe 10-15 variables at best and don't foresee need for scalability.  So it could be as simple as going to a txt file and looping through to find the pre-defined tag and read/write to it.  And/or finding end of line and adding another variable.

Anyways.  Thanks.




Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #16 on: May 29, 2023, 06:55:29 PM »
I love C#, and would encourage the learning of it. But for a similar scenario I found that the 'Write Text to a File' action with variable tokens for the path works quite simply.  For text you just 'Set Text' from file/URI and use the same tokens.

I mean.  Perhaps this is a viable option.  However, for storing multiple variables in one file, i.e. writing, reading and removing.  I'm not sure built in VA functions would be robust enough for that.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4790
  • RTFM
Re: Save To Profile -Realtime- A Variable's Value
« Reply #17 on: May 29, 2023, 07:04:04 PM »
storing multiple variables in one file
is not what EricM was referring to, in case that wasn't clear;
variable tokens for the path works quite simply
I.E. a separate file for each variable, due to which you wouldn't need to worry about manually parsing the contents of a given file, as the entire contents would be the variable value.


I'm not sure built in VA functions would be robust enough for that.
"robust" in the sense that they would yield reliably repeatable results? Certainly they would be.

Would they be the most efficient and maintainable solution to a problem of this complexity? Not necessarily, but they're not really intended to be.

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #18 on: May 29, 2023, 08:40:26 PM »
storing multiple variables in one file
is not what EricM was referring to, in case that wasn't clear;
variable tokens for the path works quite simply
I.E. a separate file for each variable, due to which you wouldn't need to worry about manually parsing the contents of a given file, as the entire contents would be the variable value.


I'm not sure built in VA functions would be robust enough for that.
"robust" in the sense that they would yield reliably repeatable results? Certainly they would be.

Would they be the most efficient and maintainable solution to a problem of this complexity? Not necessarily, but they're not really intended to be.

From a developer perspective, I wouldn't advise making a multitude of files to save a multitude of variables.
Just seems needlessly fragmented to me.  Not that it couldn't be done.
I'd prefer to put them all within one file.  Yes, that increases the complexity of the solution, but personally I feel it's a better design approach.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4790
  • RTFM
Re: Save To Profile -Realtime- A Variable's Value
« Reply #19 on: May 29, 2023, 08:57:33 PM »
To clarify: I'm not advocating for either approach. Both can have merits depending on the requirements.

As I intended to convey with
in case that wasn't clear
I was attempting to make sure there was no misinterpretation of the mentioned concept, in case said concept were to fit your requirements.

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #20 on: May 29, 2023, 09:13:34 PM »
To clarify: I'm not advocating for either approach. Both can have merits depending on the requirements.

As I intended to convey with
in case that wasn't clear
I was attempting to make sure there was no misinterpretation of the mentioned concept, in case said concept were to fit your requirements.

Understood.  Thank you.

Currently I'm thinking to have a command/inline kicked off to take a set of variable values from my profile and save them to a file.
Then, upon my profile load routine, I'm thinking to load in what those saved variable values were and reset them in my profile.

I'm not sure if I'll go with an Arraylist for any of this or not....  Maybe that's simply too overkill for the writing of variables to a file.  Though it's prob good to have on each line an ID(int), Variable Name(String), Variable Value(String)
I guess I could convert things like Bool to a string "True" or "False" and then upon load convert back to redefine the variable.

I am absolutely sure there's probably a better way of doing it versus what I'm imagining above..

SemlerPDX

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 291
  • Upstanding Lunatic
    • My AVCS Homepage
Re: Save To Profile -Realtime- A Variable's Value
« Reply #21 on: May 30, 2023, 12:39:08 PM »
There would be no point to an ID indexer for values saved to a flat text file.  The best structure IMHO is "name=value" where you read contents of the save file, it's how my save file system for AVCS CORE (and each AVCS4 profile) works - just use something like this:
Code: (csharp) [Select]
string[] fileLines = fileContents.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);*this assume that your document is a UTF-8 encoding with windows CRLF style newlines, should be only "\n" for a Unix (LF) encoded file. By default, VoiceAttack "write a value to file" action will produce a proper windows CRLF file, FTR.

...where 'fileContents' is a string that you retrieved from file, either using System.IO in your inline/plugin, or the Set a Text Variable action with the option to set the value from File/URI and pass that text variable to the inline to turn it into the string 'fileContents'.


Then, you iterate through each line and split at the "=", similar to how you split at the newline, where each line in fileLines would produce the variable name with line[0] and the variable value with line[1].

As I stated in a previous reply, you can use the Parse or TryParse (my personal preference for >90% of use cases), and cast the string directly into the appropriate type that a VA.Set variable action expects, whether boolean or integer or decimal -- of course strings can be directly applied to a VA.SetText() variable value without conversion.


NOTE REGARDING DECIMALS:
This likely won't apply to your case, unless you present any of your decimal variables in a manner that users can edit by typing out a new decimal. If this is the case, you need to know that some countries use a different decimal separator than "." (or "," if that is what you consider typical).  Again, likely won't be an issue for you, but if you get reports from international users, circle back to this note and read up on the {DECINV} token as well as C# methods for passing CultureInfo.InvariantCulture as the culture parameter, so you can ensure that both dot (.) and comma (,) separators are accepted.
Code: (csharp) [Select]
using System;
using System.Globalization;

/// ...then in some method:
string userInput = "123.45"; // Example user input  -OR-
string userInput = "123,45"; // Example international user input

decimal result;
if (decimal.TryParse(userInput, NumberStyles.Number, CultureInfo.InvariantCulture, out result))
{
VA.SetDecimal("myDecimalNameExample", result);
}
else
{
// Conversion failed, handle the error case
}

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #22 on: May 30, 2023, 08:23:06 PM »
Thanks @SemlerPDX

Will take above under advisement.  Currently I foresee no need to manage decimals.  Mostly Strings and Booleans.
Again, as there's no 'plan' to "ROLL OUT", even the thought of some distribution cross-border is simply out of the question.  Those concerns are simply not even in the room where the table is at this point.  Food for thought I guess when I'm feeling the need to nibble on something at this point.

First thing I need to do is determine where to place this file and how to determine its path etc.
While this is JUST for me at this point, I'd want the file to be placed where there's no need to get a user involved in being an Admin of the system.  I'll probably have a folder and file created on initial run of my profile.  i.e.   If folder path and file do not exist, create it.

Profile wouldn't continue further in operating unless the user does certain things and chooses certain options. (Would pop up automatically if all the mandatory options aren't set)
Once that happens, those settings will be saved to the file and used upon subsequent runs of the profile.

I mean.  I'd like to remove hard-coding certain settings within my profile commands, to be more flexible for myself.
So I'll likely be making at some point a simple forms interface to collect those settings and preferences.  Probably might just have that code itself do the initial writing of the settings to the file from the form interface code.
A separate inline would be created to run on startup and read the file and pull the variables from it upon load.

Those are my thoughts at this time.

Thanks for providing more info in the above.



SemlerPDX

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 291
  • Upstanding Lunatic
    • My AVCS Homepage
Re: Save To Profile -Realtime- A Variable's Value
« Reply #23 on: May 31, 2023, 12:06:40 AM »
If your goal is to not require elevated permissions to write to a folder/file, best place is AppData.  The AppData folders are specifically designed for applications to store application data (as the name suggests) in Windows Operating Systems, and contain a Local, LocalLow, and Roaming folder. These will always exist, and you can count on that. You will not need elevated permissions (or 'run as admin') to write folders/files to these locations.

The Windows AppData Roaming folder is a directory that stores user-specific application data that can "roam" or be accessed from different computers within a network. It primarily contains settings, preferences, and other user-related data that should be synchronized across multiple devices.

Use case scenarios for the AppData Roaming folder include:
  • Applications can store personalized settings, such as custom configurations, layout preferences, and other user-specific choices.
  • Certain applications save data files, such as game progress, templates, or cached information, which need to be accessible regardless of the device used.
  • User profiles for software, such as web browsers, email clients, and productivity tools, are often stored in this folder to ensure consistency across devices.

On the other hand, the AppData Local folder contains data specific to a particular device and is not synchronized across different machines. It is generally used for temporary files, cached data, or data that doesn't need to be shared or transferred between devices.

The AppData LocalLow folder is similar to AppData Local, but it is intended for low-integrity and low-security applications, such as web-based applications running in a restricted environment. It is used to store data with minimal permissions and is isolated from regular local and roaming profiles.

You can access this through environment variables, and combine them into a path using the System.IO.Path.Combine() method, like this:
Code: (csharp) [Select]
/// <summary>
/// The folder path to the AppData Roaming folder, combined with your folder name, and your file name.
///
/// Example Path created from the variable shown below will be:
/// "%AppData%\YourFolderName\yourFileName.txt"
/// </summary>
public static readonly string ExampleSaveFilePath = System.IO.Path.Combine(
                                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                                "YourFolderName", "yourFileName.txt");

/// <summary>
/// The folder path to the AppData Local folder, combined with your folder name, and your file name.
///
/// Example Path created from the variable shown below will be equivalent to:
/// "%AppData%\..\Local\YourFolderName\yourFileName.txt"
/// </summary>
public static readonly string ExampleSaveFilePath = System.IO.Path.Combine(
                                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                                "YourFolderName", "yourFileName.txt");

/// <summary>
/// The folder path to the AppData LocalLow folder, combined with your folder name, and your file name.
///
/// Example Path created from the variable shown below will be equivalent to:
/// "%AppData%\..\LocalLow\YourFolderName\yourFileName.txt"
/// </summary>
public static readonly string ExampleSaveFilePath = System.IO.Path.Combine(
                                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                                "..\\LocalLow", "YourFolderName", "yourFileName.txt");

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #24 on: May 31, 2023, 01:49:37 AM »
Thanks @SemlerPDX  Awesome stuff!

Starblue7

  • Full Member
  • ***
  • Posts: 131
Re: Save To Profile -Realtime- A Variable's Value
« Reply #25 on: May 31, 2023, 05:02:53 AM »
@SemlerPDX
Following is what I have so far for creating the path/file if they don't exist:
I suppose the below code could be cleaned up or condensed.

Code: [Select]
if(!Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\My_Profile"))
     {
          Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\My_Profile");
          VA.WriteToLog("[[ MYPROFILE ]] Settings Folder:  My_Profile  Does Not Exist, created!", "purple");
     }
if(!File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\My_Profile\settings.txt"))
     {
          File.Create(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\My_Profile\settings.txt");
          VA.WriteToLog("[[ MYPROFILE ]] Settings File:  settings.txt  Does Not Exist, created!", "purple");
     }

Next Up..

Will create read routine for a list of variables that should be within the file.
If any 'Mandatory' variables are missing, will generate a call to a user form to capture the settings and then write them to the file.

The user form will be populated with any existing settings from the settings.txt file upon load.

The user form will be a bit complicated, as I want it to 'attempt' to find various applications installed on the system, the path and executable file.  (I suppose use the registry is one way to do it).
If that path and application isn't correct for some reason, give the user a button to open up file explorer and navigate to the application executable location and choose it, then save that path and file name to the settings file.