zapat 56 Posted April 25, 2013 (edited) I have read a lot about GUIs, but there is one(two) questions I cannot cope with. What is a good programflow-design decision for loadable permanent GUIs which can communicate with variables of the MissionNameSpace? I would like a permanent GUI on my screen. This GUI is a feedback for a variable (eg. player's exhaustion). I use RscTitles for this with onLoad = "uiNamespace setVariable ['myGui', _this select 0];"; I then start an endless loop, which updates the controls of the GUI every 1 second and eg. ctrlSetPosition / ctrlSetTextColor, like this: _display = uiNamespace getVariable "myGui"; _myCtrl = _display displayCtrl 1200; if (player getVariable "exhaustionLevel" > 100) then {_myCtrl ctrlSetTextColor RED;}; if (MissionVar > 1000) then {_myCtrl ctrlShow false;}; _myCtrl ctrlCommit 0.1; -> This needs missionNameSpace variables (and specific object vars eg. player getVariable "exhaustionLevel" ) What is a good design decision for this? Is using missionNamespace vars mixed with UInamespace a good idea in a disabledserializaton sqf? -> Since it is an UI file, I need to use disableserialization. This means my loop stops whenever I load the mission. What is a good design decision for restarting the loop so I have a permanent GUI? So how to do all this? Edited April 25, 2013 by zapat Share this post Link to post Share on other sites
MrSherenai 1 Posted April 26, 2013 I didnt work much with GUIs yet to be honest but I would write a lightweight GUI handler FSM that listens to the variables that have to be updated and/or is suspended for a fixed amount of time. But as I said, no experience with GUIs so this is propably the worst way to do it :D. Share this post Link to post Share on other sites
xxanimusxx 2 Posted April 26, 2013 Well what I did was saving the references of the child controls of my "display" into an global array so I could use them without having to switch between namespaces - I was forced to use disableSerialization nevertheless. But I'd be interested how others do this :D Share this post Link to post Share on other sites
zapat 56 Posted April 27, 2013 I have SOME advance. But it resulted in more questions. If I use only uinamespace variables (with uinamespace do{}) then no disableserialization is needed. So best practice seems to have the UI vars in the UI namespace, and don't use missionNamespace variables. Therefore I now save the vars -which are needed for communication- to the UI namespace too. It seems that these are saved and reloaded as well, so this separation does work good. Still don't know how to handle loading with cutRsc though. Constantly calling cutRsc seem to make more and more layers upon themselves. On the other hand Cutrsc is stopped by loading a game, (at least my variables stay now. :) ) There is an idea at the bottom of the disableserializaiton page. Do I really need to use this workaround to find if game was loaded, and cutRsc again? Share this post Link to post Share on other sites
killzone_kid 1331 Posted April 27, 2013 if you use defined layer cutrsc will just overwrite itself. Share this post Link to post Share on other sites
zapat 56 Posted April 28, 2013 (edited) After some hours of experimenting, I came up with the following solution - if somebody is interested. I guess I got the behaviour of the UIs after all. :) It is waaaaay lot more easier than I thought. All the shady disableserialization and all that detect load stuff is unnecessary. There are no complications at all. :) By using this setup you can make a permanent and loadable GUI, which communicates well with your mission variables. No diableserialization is needed. This is advanced topic and does not include full rscTitles file. It is of course easily expandable with other variables. rscTitles.hpp - without base classes class RscTitles { class MYUI_screen { idd = -1; duration = 1e+1000; //important to achieve unlimited display fadeIn = 0; fadeOut = 0; name = ""; onLoad = "uiNamespace setVariable ['MYUI_display', _this select 0];"; //important for later ID class Controls { class MYUI_text: RscText //parent class is not included { idc = 1000; //important for later ID text = "0"; x = 0.92 * safezoneW + safezoneX; y = 0.211 * safezoneH + safezoneY; w = 0.062 * safezoneW; h = 0.017 * safezoneH; }; } } } the display loop sqf. ExecVM it in init phase. After that the UI will be shown until the mission is finished. while {true} do { sleep 1; //save your data variables in uiNamespace, so you won't need disableserialization and other shady stuff uiNamespace setVariable ["MYUI_data", damage player]; //check if UI is alive. Reinit if not (eg. after loading) if (isNull (uiNamespace getvariable ["MYUI_display",displayNull])) then { cutRsc ["MYUI_screen", "PLAIN"]; //show Resource //you can save the controls for easy access later to uinamespace vars with uiNamespace do { MYUI_myctrl = MYUI_display displayCtrl 1000; }; }; //update controls. ONLY uinamespace from this point with uiNamespace do { MYUI_myctrl ctrlSetText str MYUI_data; MYUI_myctrl ctrlCommit 0.1; }; }; Edited April 30, 2013 by zapat Share this post Link to post Share on other sites
panther42 52 Posted April 29, 2013 Very similar in approach zapat, is one I use from Deadfast: Deadfast cutrsc Although it does use disableSerialization... His example for thirst and color coding is similar to what you're after. I will give your method a shot. Here's some more info for you, if you have not seen it: New to ArmA 2: (ui)Namespace Share this post Link to post Share on other sites
zapat 56 Posted April 29, 2013 (edited) Thanks panther! I've just checked Deadfast's solution. That is not made for SP as his while cycle would stop on a mission load. Which is not an issue in MP, but you load a lot in SP. This is why I wanted to avoid disableserialization. I just don't know what it really does... (I mean DF's while loop is inside a disabled sqf, so it behaves like an UI if you know what I mean (alive as long as current session is alive). What I did was that I used a normal sqf for looping and display checking (and re cutRsc if needed) and used the UI vars only where the UI was actually updated. ) So it comes to the same in the end again: it depends what do I want to do, right? :) Edited April 29, 2013 by zapat Share this post Link to post Share on other sites
panther42 52 Posted April 29, 2013 (edited) from what I understand, and part of Deadfast's notes, disableSerialization allows you to store UI information in normal variables... _display = uiNamespace getVariable "TAG_RscWhatever_display"; (information "stored" in _display) I'm not sure I understand fully your issue with SP and mission loading. (RE: That is not made for SP) Found another good explanation here. See responses from Spooner: OFPEC thread - disableSerialization Looks like your "way" would be the preferred method according to Spooner... Edited April 29, 2013 by panther42 Added additional link Share this post Link to post Share on other sites
zapat 56 Posted April 30, 2013 (edited) UI information is not saved with a game save. Thus it is not loaded. It is what Disableserialization does:it stops the vars of that sqf from saving in a savegame. (It disables serialization, which means the saving of variables to a file). Although I am not sure how exactly. What is disabled exactly? Vars after the command? Vars of the whole sqf? Called or spawned? UIvars, missionNamespace globals, local vars? How does it affect inherited (called) vars? Etc. There is no info about it anywhere. There is a While (!isNull _display) in DF's script. _display will be null when game is exited. Since this variable is not saved, _display will be null when you load a game. This means the cycle is finished by a game load. In MP you don't save and load games. You start a new one. In SP you do. Anyways, my code is safe. I always know what is happening with wich variable. They are separated. if something is not saved, it is reinitialized. Mission namespace vars are left alone totally, so no question there. Edited April 30, 2013 by zapat Share this post Link to post Share on other sites
zapat 56 Posted April 30, 2013 (edited) I changed a line in my code. This is important, and it is in connection with what I said earlier. It is hard to follow how uivariables are saved/not saved. So if anyone is using my code, change the line: if (isNull (uiNamespace getvariable ["MYUI_display",displayNull])) then (this both detects if isNull and if isNil) Without this your display won't show, if you restart the arma.exe application. This means the UIvariables stay until the arma application is running. No matter what mission you run. The display variable will be NULL (alive, without a value) once you restart the mission, but stays NULL(alive, without a value) and not NIL (not alive) until the application is restarted! It gets NIL if the application is restarted. 1. You start your arma application and load a saved mission. UIvariables are NON EXISTENT. Your MYUI_display is NON EXISTENT - (you cannot even check for isNull). 2. You detect it in your code (this has to be an endless loop as you need to detect it WHEN the application starts which can be anytime when a user saves your mission and exits the app.) , and reinit your UIvariables. Your MYUI_display is now alive and gets a value. 3. You die and reload a previous savegame. Your UIvariables EXIST and remember their previous state! Your display becomes NULL though! So you need to detect if your display is null (mission reloaded without application restart), and reinit your UI. This is very important info for a GUI. Probably it is known by many, but still it is needed for a permanent loadable GUI, so I handle this as important info. :) I don't dare to go into what is happening with disableserialized local/missionnamespace vars. :) Edited April 30, 2013 by zapat Share this post Link to post Share on other sites
killzone_kid 1331 Posted April 30, 2013 Or you can just with uiNamespace do { if (isNil "MYUI_display") then .... }; Share this post Link to post Share on other sites
zapat 56 Posted April 30, 2013 No, you can't. as it would only detect application restart and not loaded game. it only detects nil (not alive) and not null (alive, but without value). Share this post Link to post Share on other sites
killzone_kid 1331 Posted May 1, 2013 Eh? What alive? if MYUI_display variable is undefined it will be nil. What you do is you assign controlNull IF it is nil and then test if it is null, where as in my example you test if it is nil straight away. Share this post Link to post Share on other sites
zapat 56 Posted May 1, 2013 Yes, you are right. But you only test if it is nil. It will only be nil if the application is restarted. UIvars stays not nil but null if the mission is exited. So you need to check for both nil and null. My line does that, yours only checks for nil. What I am talking about is the following scenario. You START a SP game. All the init takes place. No problems here. MYUI_display gets a value, so it is not nil, nor null. BUT! The user can save and load a previous save any time. This is not a mission restart, so init does not take place. missionnamespace vars get loaded. Still MYUI_display becomes null. The user can exit the arma application anytime after saving. Then after a day start the application and load a previous savegame. Now, MYUI_display will be nil, and not null. This is my experience. I am not arguing if your line check for nil or null. You are of course right. You are testing for nil. What I am saying it is not enough. Share this post Link to post Share on other sites
killzone_kid 1331 Posted May 1, 2013 with uiNamespace do { if (isNil "MYUI_display" || {isNull MYUI_display}) then .... }; Share this post Link to post Share on other sites
zapat 56 Posted May 1, 2013 (edited) Okay, you win, man. :) That is definitely a lot better.... Edited May 1, 2013 by zapat Share this post Link to post Share on other sites
killzone_kid 1331 Posted May 1, 2013 didn't say it was better, just another way of doing it. Share this post Link to post Share on other sites