Jump to content
gc8

Return variables to class format

Recommended Posts

Hi

I have this dilemma where I am getting some values off from a class and then I need to return those values visually same way as they used to be in the class so that the class can be imported to clipboard exactly the same way it was.

 

Here's my example code to demonstrate the problem (Code not tested):

 class TestMain
 {
  test = 111;
  test2 = true;
  test3 = "hmmm";
  test4[] = {"one","two"};
 };


_items = missionconfigFile >> "TestMain";


for "_i" from 0 to (count _items - 1) do
{
private _item = _items select _i;


switch(true) do
{
 case (isNumber _item): { _value = str (getnumber _item); };
 case (isText _item):  {  _value = (getText _item); };
 case (isArray _item): { _value = str (getArray _item); };
};


_testCtrl ctrlSetText _value; // Use the value, no problem...

};



_text = ctrlText _testCtrl; // Back to the way it was, a bit of a propblem

copytoClipboard _text;

 

So my question is how to return to _value variable to the original class format

 

I have tried some call compile and typename check but didn't yet find the perfect solution so I thought I'd ask here.

 

One of the challenged is that test2 = true; is considered a text (isText)

 

 

Share this post


Link to post
Share on other sites

Use isEqualType and have a look at isEqual... family (isEqualTypeParams....).

Then, compile should work.

 

NOTE: It seems you're in display control, for classes, so boolean is not an option here. What kind of classes are you expecting with a boolean?

Share this post


Link to post
Share on other sites
2 hours ago, pierremgi said:

What kind of classes are you expecting with a boolean?

 

Some config classes in description.ext that I use in my mission. Don't know if boolean is often used but it's what I use.

 

Going to check isEqualType, thanks!

Share this post


Link to post
Share on other sites

Tried isEqualType but it did not work.

 

"true" isEqualType true

 

returns false

 

There's probably some other command to detect if boolean returned by getText is in fact a boolean in the class

 

Share this post


Link to post
Share on other sites

_test = call compile "true";

_test isEqualType true   // returns true

Share this post


Link to post
Share on other sites
9 hours ago, pierremgi said:

_test = call compile "true";

_test isEqualType true   // returns true

 

Right, but

 

call compile "some string";

 

gives error

 

 

Share this post


Link to post
Share on other sites
private _props = configProperties [missionconfigFile >> "TestMain","true",false];
private _attributeValues = [];

{
	private _ele = [_x] call BIS_fnc_getcfgdata;
	if (_ele isEqualType "") then {
		if (_ele isEqualTo "true") then {
			_ele = true;
		} else {
			if (_ele isEqualTo "false") then {
				_ele = false;
			};
		};
	};
	_attributeValues pushBack _ele;
} forEach _props;

//for example purposes, use returned array values as necessary
copyToClipboard str(_attributeValues);

//return: [111,true,"hmmm",["one","two"]]

 

Share this post


Link to post
Share on other sites

@jshock Thanks, I was thinking of similar solution. But the reason I didn't post that yet is because I have concern of covering all the types of config data.

What I am particularly interested to know is how you deal with stuff like this:

 

class TestClass 
{
 test1 = AString;
 test2 = a another string;
};

 

Both of those test variables are considered as text and return proper string with getText command. Now why such strings are allowed I don't know because I  rarely use classes and make mods. So maybe I need to cover these types as well? (and who knows what else)

Share this post


Link to post
Share on other sites

I think I kinda see what you're asking but I'm equally lost. You're thinking robustness of the returned attributes for the class, right? But there is a finite number of config data types: arrays, strings, and scalars. Now I'm thinking the engine defaults anything that is not one of those three types to be a string to avoid unforeseen complications (that's a guess though). So if you need to make sure each attribute is of an expected value you will have to run a unique robustness check on every class attribute where that is necessary. If you want certain attributes to be indirectly boolean you can make the attribute a scalar and use BIS_fnc_getCfgDataBool on that attribute where a value of zero returns false and anything greater than zero returns true.

  • Like 1

Share this post


Link to post
Share on other sites

@jshock Just trying to cover what ever is necessary to read the class properly and write back

Share this post


Link to post
Share on other sites

If you're worried about string defaulted attributes like you had above that have spaces you can test with the return of splitString:

 

count ((getText (missionConfigFile >> "TestClass" >> "test2")) splitString " ") > 1 //returns true
//if the returned array from splitString is greater than one element that means there is at least one space in the returned config attribute

count ((getText (missionConfigFile >> "TestClass" >> "test1")) splitString " ") > 1 //returns false

 

Of course you can add to what splitString looks for, so if you don't want spaces or dashes or underscores, etc....just add them into the list of delimiters and if the returned array is greater than one element, the value of the attribute is not proper and you can send a RPT report or otherwise notify the user of bad input.

  • Thanks 1

Share this post


Link to post
Share on other sites
15 hours ago, gc8 said:

Right, but


call compile "some string";

gives error

As you are setting the ctrls text to the contents of the string, some text rather than the string "some text". You are treating it differently to the rest, which are all a string of the properties value, and in doing so are stripping off its quotations. When compiled back this results in an error.

 

Spoiler

class TestMain
{
	test = 111;
	test2 = "true"; //There is only NUMBER, STRING and ARRAY
	test3 = "some text";
	test4[] = {"one","two"};
};

There is only NUMBER, STRING and ARRAY anything else is an error no matter how the engine decides to handle it.


waitUntil { time > 0 };

_display = findDisplay 46 createDisplay "RscDisplayEmpty";
_output = [];
_items = missionConfigFile >> "TestMain";

{
	_value = switch ( true ) do {
		case ( isNumber _x ): { getNumber _x; };
		case ( isArray _x ): { getArray _x; };
		case ( isText _x ):  {
			_propertyValue = getText _x;
			if ( toLower _propertyValue in [ "true", "false" ] ) then {
				toLower _propertyValue isEqualTo "true" //un-stringify the bool
			}else{
				_propertyValue
			};
		};
	};

	_propertyName = _display ctrlCreate [ "RscText", -1 ];
	_propertyName ctrlSetPosition[ 0, _forEachIndex * 0.1, 1, 0.1 ];
	_propertyName ctrlCommit 0;
	_propertyName ctrlSetText format[ "%1 = ", configName _x ];

	_testCtrl = _display ctrlCreate [ "RscText", -1 ];
	_testCtrl ctrlSetPosition[ 0.1, _forEachIndex * 0.1, 1, 0.1 ];
	_testCtrl ctrlCommit 0;

	_testCtrl ctrlSetText str _value; //All a string of the properties value '111', 'true', '"some text"', '[ "one", "two" ]'
	_text = call compile ctrlText _testCtrl; // 111, true, "some text", [ "one", "two" ]

	_valueType = switch ( true )  do {
		case ( _text isEqualType 0 ) : { "isNumber" };
		case ( _text isEqualType [] ) : { "isArray" };
		case ( _text isEqualType "" ) : { "isText" };
		case ( _text isEqualType true ) : { _text = str _text; "isBool" }; //stringify the bool
	};

	_propertyType = _display ctrlCreate [ "RscText", -1 ];
	_propertyType ctrlSetPosition[ 0.25, _forEachIndex * 0.1, 1, 0.1 ];
	_propertyType ctrlCommit 0;
	_propertyType ctrlSetText _valueType;

	_nul = _output pushBack [ _text, _valueType ];
}forEach configProperties[ _items ];

copyToClipboard str _output;
//[[111,"isNumber"],["true","isBool"],["some text","isText"],[["one","two"],"isArray"]]

 

 

  • Thanks 1

Share this post


Link to post
Share on other sites

@Larrow thanks I think we are on same pages here. But personally I'm going to keep booleans without quotes because while they are considered text the getnumber command returns either 0 or 1 for the boolean. So I can use them as boolean in my project.

Share this post


Link to post
Share on other sites
On 5/26/2019 at 7:12 PM, gc8 said:

One of the challenged is that test2 = true; is considered a text (isText)

Correct. the "true" thing doesn't exist in config. It's invalid.

 

22 hours ago, gc8 said:

Now why such strings are allowed I don't know

And the config parser tries to fallback to just converting invalid things to strings to make your game not error/crash.

 

 

On 5/26/2019 at 8:12 PM, pierremgi said:

Use isEqualType and have a look at isEqual... family (isEqualTypeParams....).

Doesn't work for config things. Doesn't help at all here.

 

On 5/26/2019 at 10:52 PM, gc8 said:

There's probably some other command to detect if boolean returned by getText is in fact a boolean in the class

No. At parse time it's converted to a string. Beyond that you cannot possibly know at all whether the input was true or "true"

But you could just assume that "true" == true.

 

On 5/27/2019 at 12:20 AM, pierremgi said:

_test = call compile "true";

_test isEqualType true   // returns true

But why?

Might aswell just do _text == "true"

 

22 hours ago, gc8 said:

I have concern of covering all the types of config data

config data can be:
array, string, number. That's it.

 

21 hours ago, jshock said:

that have spaces you can test with the return of splitString

Way more expensive than it needs to be

https://community.bistudio.com/wiki/find

Just use find to check if string contains a space. No need to split.

 

3 hours ago, gc8 said:

the getnumber command returns either 0 or 1 for the boolean. So I can use them as boolean in my project.

Keep in mind that everytime you retrieve the value, it gets compiled and executed as script, so you are paying a performance hit with that.

You could use a #define to just make the true be auto replaced by 1. You can still write true, but don't pay the performance hit.

 

 

Sorry if I'm answering things that have already been answered, first time I come online since weekend and I like to answer everything.

Share this post


Link to post
Share on other sites
14 minutes ago, Dedmen said:

Way more expensive than it needs to be

https://community.bistudio.com/wiki/find

Just use find to check if string contains a space. No need to split.

Indeed. General question though, if I did want to filter for more than just spaces (e.g. dashes and underscores) I would assume iterating with each special character using find would still be better than counting the return of splitString? Not at my computer to run the numbers atm.

Share this post


Link to post
Share on other sites
52 minutes ago, Dedmen said:
23 hours ago, gc8 said:

I have concern of covering all the types of config data

config data can be:
array, string, number. That's it.

 

Yes but what I was referring to is the case of booleans. That's one thing to cover. And I was thinking there maybe some string table stuff people use in their configs and what not that I need to cover/support. I don't know much about this area as I've never made a big addon. But yeah basically I need to cover whatever people use in configs

Share this post


Link to post
Share on other sites
1 hour ago, jshock said:

I would assume iterating with each special character using find would still be better than counting the return of splitString

Not sure about that one.

That's a case of SQF work vs engine work. splitString checks all the character in engine, the find variant would check them in SQF which is slower.

 

26 minutes ago, gc8 said:

Yes but what I was referring to is the case of booleans.

Booleans don't exist. simple.

 

26 minutes ago, gc8 said:

And I was thinking there maybe some string table stuff people use in their configs and what not that I need to cover/support.

That might be a concern indeed. But stringtable entries are resolved when the config is loaded. Afterwards you cannot infer what was in there previously. There are no commands to do that, plus I think even the engine couldn't do that, it doesn't store where a string came from.

 

For mission description.ext you can just load the bare textFile using loadFile and get the raw config that you put into it.

Share this post


Link to post
Share on other sites

If you want to know where I need this stuff, I just released my class editor

 

Share this post


Link to post
Share on other sites
1 hour ago, gc8 said:

If you want to know where I need this stuff, I just released my class editor

 

I'm quite sure that would have been easier to do as a desktop/web tool. And then you also wouldn't have all the problems from not actually being able to read the actual config.

Share this post


Link to post
Share on other sites
37 minutes ago, Dedmen said:

I'm quite sure that would have been easier to do as a desktop/web tool. And then you also wouldn't have all the problems from not actually being able to read the actual config.

 

What I thought was nice is the fact that all the configs are loaded by engine and can be easily accessed. So for me it was easiest to create the GUI in arma. (And I don't need to write custom parser)

Share this post


Link to post
Share on other sites
9 minutes ago, gc8 said:

And I don't need to write custom parser

There are open source config parsers in multiple languages freely available.

Share this post


Link to post
Share on other sites
4 minutes ago, Dedmen said:

There are open source config parsers in multiple languages freely available.

 

Ok , well I still think this was the simplest way, personally happy about it 🙂

 

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×