Jump to content
Sign in to follow this  
meatball

Converting / Building a Mission to support Headless Clients

Recommended Posts

I've decided to start building new missions and retrofit some of my old missions to support Headless clients. Does anyone have any links or guides on the best way to go about this?

In my guess, I'm using scripts to handle the spawning of 95% of my AI in missions, so I'm hoping it's just a few tweaks to those calls, but I'm not sure where to even start.

Share this post


Link to post
Share on other sites

Hey Naught, I actually saw that and it looks awesome, but I don't know if it'll work in my case.

Specifically I've already got caching set and ready, I just want to offload the AI processing to a HC. Plus I need to be able to count numbers of AI being cached and cache/support AI vehicles (mostly using spunFin's AI Spawn Script Pack ambientcombat and militarize scripts). Other challenge is that CBA is required. Not that I don't use CBA, I've just been trying to avoid forcing people to use any addons for my missions.

Edited by Meatball

Share this post


Link to post
Share on other sites
Hey Naught, I actually saw that and it looks awesome, but I don't know if it'll work in my case.

Specifically I've already got caching set and ready, I just want to offload the AI processing to a HC. Plus I need to be able to count numbers of AI being cached and cache/support AI vehicles (mostly using spunFin's AI Spawn Script Pack ambientcombat and militarize scripts). Other challenge is that CBA is required. Not that I don't use CBA, I've just been trying to avoid forcing people to use any addons for my missions.

Gotcha, yes once BI integrates some form of event handlers per CfgVehicle class I can remove CBA, but for now it's a necessity.

Anyways if you just want distribution you can disable the caching part: http://forums.unitedoperations.net/index.php/topic/21527-ai-caching-and-distribution-script/?p=264381

If you choose to make your own distribution system, it can be pretty challenging due to the possibility of none or multiple HC connections/disconnects.

What I chose to do, and what you can mirror, is a method as described below:

  • Spawn units on server as normal, in case no HC connects.
  • Use an asynchronous script (spawn|execVM script, you can integrate the entire async script within your caching system if it already has one running) to monitor each group, and hold a global variable (array) with all the available headless clients within it (I chose to serialize each HC as an array within the aforementioned global array, ie. [[hcUnit, hcNetID, hcPlayerUID], ...]).
  • When a HC loads into the mission, have it broadcast to the server that it's available and to add it to the HC gvar array.
  • Once the server receives the message that a HC has joined, set a "MPkilled" event handler on the HC's unit, and for the code if isServer then remove the HC from the HC gvar array, and if !hasInterface && !isDedicated then send a message to the server asking it to readd the HC to the list (preferably using the same method as it did when broadcasting the message on HC join). The point of this is to remove the HC from the array if it disconnects or dies, but then add it back if it respawns (ie. still connected, but just died). It's basically the most efficient way to handle HC disconnections, although you'll still lose units if they're not transferred.
  • Have the aforementioned async script check the HC gvar on a set interval, and if isServer && (count gvar_hcArr > 0) then choose randomly any HC from the list (with an equal probability distribution, ie. (gvar_hcArr select random((count gvar_hcArr) - 1))) to send the group to (I just cached the group, sent the cache variable, and then spawned all of the cached units).

Share this post


Link to post
Share on other sites

Thanks. I've been thinking on this for the last hour or so, and I'm wondering if I can make this work without too much effort. I've got my dedicated server, and I've got a headless client setup. I've set my mission up so it has a Civilian slot for the Headless Client and set up a parameter I can select at the briefing screen that will set a global variable "HCPresent" to true or false based on that the parameter selection. I've tested it out and assuming I connect and login as admin first, the HC connects and grabs the civvie slot correctly.

So, looking at everything, I now have a global variable that I can reference in game as to whether or not there's a HC connected, and I should be able to grab that HC profile name/client ID since I know the slot it's in.

Since almost every AI and the caching script I have in the game is created by simple triggers spawning the AI script call, there _has to be_ a way I can configure the triggers to run only the scripts on the Headless client if it's connected, or run them on the server if it's not.

I'm wondering if I duplicate every trigger and set one to have conditions of "(HCPresent==false) and isServer" and the other to have "(HCPresent==true) and (clientID==HCID)"

Of course, the more I'm diving into this, the more I'm thinking it might just be easier to figure out how to integrate your script in and save myself a lot of headaches ;)

Edited by Meatball

Share this post


Link to post
Share on other sites

Is it possible to have a mission init.sqf autodetect whether there's a HC connected and broadcast that as opposed to relying on parameters? I was thinking along the lines of something like this as the first lines of the mission init.sqf:

if (!hasInterface && !isServer) then{
    hcPresent = true;
    publicVariable "hcPresent";
} else {
    hcPresent = false;
    publicVariable "hcPresent";
};

Any reason why that wouldn't work? If it does, then you could pretty easily use the hcPresent variable to determine whether AI spawn calls run on the server or the HC.

Share this post


Link to post
Share on other sites
Is it possible to have a mission init.sqf autodetect whether there's a HC connected and broadcast that as opposed to relying on parameters? I was thinking along the lines of something like this as the first lines of the mission init.sqf:

if (!hasInterface && !isServer) then{
    hcPresent = true;
    publicVariable "hcPresent";
} else {
    hcPresent = false;
    publicVariable "hcPresent";
};

Any reason why that wouldn't work? If it does, then you could pretty easily use the hcPresent variable to determine whether AI spawn calls run on the server or the HC.

Change !isServer to !isDedicated.

It does, but then you would have to establish a reasonable timeout period, ie. 30 seconds, for which the server waits for the "hcPresent" variable to change. If it doesn't within that 30 seconds, then you spawn on the server, but if it does you spawn on the HC.

That also means you won't have AI for the first 30 seconds of your mission, and what if multiple HCs connect? Only one will be used (although that's an edge case).

Share this post


Link to post
Share on other sites

Man, this is starting to drive me batty. So, I've started to rethink how I'm going to go about this. I've not setup the parameter to choose Headless Client On/Off and then I added this into my init.sqf.

if(paramsArray select 4 == 1) then{
if(isServer) then{
	hcPresent = true;
	publicVariable "hcPresent";
};
if (!hasInterface && !isServer) then{
	hcName = name player; 
	publicVariable "hcName";
};
} else{
if(isServer) then{
	hcPresent = false;
	hcName = "NOONE";
	publicVariable "hcPresent";
	publicVariable "hcName";
};
};

....Other code....

if(hcPresent) then{
if(!hasInterface && !isServer) then{
	milSet = 1;
	publicVariable "milSet";
	execVM "miscScripts\milCache.sqf";
};
} else {
if(isServer) then{
	milSet = 2;
	publicVariable "milSet";
	execVM "miscScripts\milCache.sqf";
};
};

I set that milSet/variable so I could run a radio trigger to be certain the right code block was running and it all looks good. milCache.sqf is simply a bunch of calls to my AI spawn script of choice (AI Spawn Script pack) and looks something like this:

nul = ["task_60",2,450,[true,false],[false,false,false],false,(0.1*numEnemies),0,enemySkill,nil,"miliTroops = group this;",60] execVM "LV\militarize.sqf";
sleep 3;
nul = ["task_17",2,150,[true,false],[false,false,false],false,(0.166*numEnemies),0,enemySkill,nil,"miliTroops = group this;",17] execVM "LV\militarize.sqf";
sleep 3;
...

So, here's the results:

Situation 1: Locally hosted server with HC param off I get hcPresent false, hcName Noone and milSet 2, AI spawn as expected.

Situation 2: Dedicated server with HC param off I get hcPresent false, hcName Noone and milSet 2, AI spawn as expected

Situation 3: Dedicated server with HC param on and HC connected I get hcPresent true, hcName hc (name of my connected hc) and milSet 1, AI never spawns.

So in Situation 3 where the headless client should be running milCache.sqf, for some reason the AI just never spawn and I'm not sure where to go from here. Any thoughts would be mucho appreciated.

Share this post


Link to post
Share on other sites

Done a little bit more experimenting and think I know the problem, just not sure how to handle it. I know for certain that milCache.sqf is being run by the Headless Client. Which leads me to believe that for some reason a script spawning AI on a client that is not the server will not show up globally and the AI either just isn't being created at all, or it's only being created on the Headless Client. I have gone through the scripts and removed the 'if (!isServer)exitWith{};', so the script should definitely run.

Update: Bit more testing and I can actually see the militarize script creating the groups on the headless client, but it's creating empty groups for some reason. The script uses createUnit for infantry and createVehicle for vehicles, which I believe should both work fine in MP situations.

Edited by Meatball

Share this post


Link to post
Share on other sites

The Arma 2 Map Converter that lotherk created works pretty well if you want to transfer the whole mission over. I touched up his version where it will record trigger synchronizations and also replaces the old setVehicleInit command so that you can use the init box from the 2D editor. Inbox me if you want me to covert the mission over for you. All I need is the mission.sqm. https://github.com/lotherk/Arma2MapConverter

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
Sign in to follow this  

×