Jump to content
Sign in to follow this  
engima

ASCOM Framework Release

Recommended Posts

ASCOM.png

ASCOM Framework 1.0

by Engima of Östgöta Ops

(Download at Armaholic)

Description

The Arma Script Communication (ASCOM) Framework is a framework that greatly simplifies SQF script communication between machines in a multiplayer mission. The ASCOM framework makes it possible to “call a function on another machine†in the same way that you call a function on the local machine. You can also return values to the caller in a usual manner, even when the caller is on another machine. These calls can be made in a script on any machine on the network. It is efficient, robust and does not require much bandwidth or CPU.

Within the ASCOM framework, these functions are called “Network Functionsâ€. A network function is actually just like any other function. The ASCOM framework (which comes with an editor) then generates code that handles communication between machines on the network, which enables you to execute your functions on machines of your choice at each call.

Examples

Assume you have a function named "ShowMessage" that shows a message on its client. With the ASCOM Framework you can run that function on all clients with the following call:

[“Mission completed!â€] call ShowMessageClients;

As an another example, assume you have an MP mission, and when a JIP player connects its client needs to get the current tasks and their status from the server. In the init.sqf for the client you can make the following call to execute the function GetCurrentTaskStates on the server and have it return the task states across the network:

_taskStateList = call GetCurrentTaskStatesServer;

As a third example, assume that you want the server to set state "SUCCEEDED" on the task "FreeHostage" on all machines:

["FreeHostage", "SUCCEEDED"] call SetTaskStateAll;

Installation

No installation. Simply execute the file "ASCOM Editor.exe".

Other

Works for Arma 2 and Arma 3.

Media

This video shows an older version of the editor. One function name has been changed, but principles are the same.

Content

Package contains:

  • The ASCOM Editor (.NET 4.0 executable).
  • The ASCOM Manual (.PDF)
  • Demo mission for Arma 3.
  • Demo mission for Arma 2.

Requirements

.NET framework 4.0.

Edited by Engima

Share this post


Link to post
Share on other sites

So it's essentially a code template wizard that makes client to client/server/combination easier?

Interesting idea.

Edited by Axek

Share this post


Link to post
Share on other sites

That's essentially correct. But it supports more combinations than that:

client/server to client/clients/server/all/some.

The idea is to hide the complicated code for the networking, and provide a super simple programming interface.

Edited by Engima

Share this post


Link to post
Share on other sites

This is exactly the tool I was looking for!

Thank you so much for developing this and saving me a ton of headaches!

Share this post


Link to post
Share on other sites
This is exactly the tool I was looking for!

Thank you so much for developing this and saving me a ton of headaches!

Glad you like it!

Good luck!

Share this post


Link to post
Share on other sites

Got used to this, it's unbelievably good and useful so thank you, I'll be using this on ever mission with saving myself hours of headaches.

Share this post


Link to post
Share on other sites

Quick question, I'm trying to make a task for a JIP player and I'm having problems getting ASCOM to call that player only.

init.sqf:

if (!isServer) then {
 if (isNull player) then {
   [] spawn {
     waitUntil {!(isNull player)};
     [player, missionType, taskNum] call fnc_CreateNewTaskClient;
   };
 };
};

The function, CreatNewTask, using FHQ Tasktracker to create a task using info from the variables "missionType" and "taskNum"

I'm getting an error, though, on the "player" part. I'm trying to only call this code for the JIP. Any clue on what I can do to solve this?

Share this post


Link to post
Share on other sites
Quick question, I'm trying to make a task for a JIP player and I'm having problems getting ASCOM to call that player only.

init.sqf:

if (!isServer) then {
 if (isNull player) then {
   [] spawn {
     waitUntil {!(isNull player)};
     [player, missionType, taskNum] call fnc_CreateNewTaskClient;
   };
 };
};

The function, CreatNewTask, using FHQ Tasktracker to create a task using info from the variables "missionType" and "taskNum"

I'm getting an error, though, on the "player" part. I'm trying to only call this code for the JIP. Any clue on what I can do to solve this?

I know this isn't really helpful but I'd just wait until the people who make FHQ Task Tracker fix it themselves and release an updated version.

Edited by clydefrog

Share this post


Link to post
Share on other sites
Quick question, I'm trying to make a task for a JIP player and I'm having problems getting ASCOM to call that player only.

init.sqf:

if (!isServer) then {
 if (isNull player) then {
   [] spawn {
     waitUntil {!(isNull player)};
     [player, missionType, taskNum] call fnc_CreateNewTaskClient;
   };
 };
};

The function, CreatNewTask, using FHQ Tasktracker to create a task using info from the variables "missionType" and "taskNum"

I'm getting an error, though, on the "player" part. I'm trying to only call this code for the JIP. Any clue on what I can do to solve this?

Use the players vehicleVarName instead of the user object:

[vehicleVarName player, missionType, taskNum] call fnc_CreateNewTaskClient;

This call will execute the function fnc_CreateNewTask on the machine that the player is local to. In your case that seems to be the current machine, which makes me wonder why you don't call fnc_CreateNewTask directly instead?

Another idea is to have the client ask server for the tasks on initialization. That's how I do it in the demo mission.

Edited by Engima

Share this post


Link to post
Share on other sites
Use the players vehicleVarName instead of the user object:

[vehicleVarName player, missionType, taskNum] call fnc_CreateNewTaskClient;

This call will execute the function fnc_CreateNewTask on the machine that the player is local to. In your case that seems to be the current machine, which makes me wonder why you don't call fnc_CreateNewTask directly instead?

Another idea is to have the client ask server for the tasks on initialization. That's how I do it in the demo mission.

I tried the [vehicleVarName player, missionType, taskNum] call lampCreateNewTaskClient; and it didn't work. I didn't get any errors, though i'm sure there were serverside, and it was probably because the variable "missionType and taskNum were nil.

Well here's how my mission is setup:

From init.sqf I call a missionControl.sqf

missionControl.sqf picks a random marker, task type (kill, rescue, steal, etc), and task objective (car, helicopter, infantry, hostage, etc) then makes an array called "missionType" with [marker, objective type, and task object] and the current task number (which I use to check to end the mission after so many tasks are completed) which is then pulled into a create task function:

missionControl.sqf:

markList = ["agia","airfield","airstation","campmax","camptemp","girna","kamino","killfarm","lzconnor"]; //Available Markers to choose from
taskList = ["Assault", "Rescue", "Destroy", "Steal","Kill"]; //Available Task Types to choose from
taskAssaultObjList = ["Infantry", "Infantry and Vehicles"]; //Available Assault Objects
etc... (more objlist would be here for each taskType)

tasksToComplete = 15; // How many tasks the mission will run till end
if (isNil "taskNum") then {
   taskNum = 0;    
};

while {taskNum <= tasksToComplete} do {
   [b]missionType = [markList, taskList, taskAssaultObjList, taskRescueObjList, taskDestroyObjList, taskStealObjList, taskKillObjList] call lampCreateMissionTypeServer;[/b]

   taskNum = (taskNum + 1);

   [b][missionType, taskNum] call lampCreateNewTaskServer;[/b]
   [missionType] call lampCreateUnitsServer; // This creates the units based on the missionType variable, sets them to group "vehGroup"

   _prevTask = missionType select 1;
   if (_prevTask == "Assault") then {
       if (!isNil "vehGroup") then {
           waitUntil {{alive _x} count units vehGroup == 0};    
       };
       if (!isNil "newGroup") then {
           waitUntil {{alive _x} count units newGroup == 0};
       };
       missionSuccess = true;
   };

   waitUntil {!isNil "missionSuccess"};
   [taskNum, missionType, missionSuccess] call lampCompleteTaskServer;

   if (taskNum >= tasksToComplete) then {
       call lampEndMissionAll;
   };
};

And here is my functions script for the CreateTask:

// Executed on the server
lampCreateNewTask = {
   private ["_missionType", "_taskNum"];

   _missionType = _this select 0;
   _taskNum = _this select 1;

   // Code goes here!
   private ["_markerNum", "_taskType", "_taskObject"];
   _markerNum = _missionType select 0;
   _taskType = _missionType select 1;
   _taskObject = _missionType select 2;
   [
       [
       format ["%1%2", _taskType, _taskNum], //task name
       format ["Mission %1, %2 %3", _taskNum, _taskType, _taskObject], //task long desc e.g. "Mission 2, Assault Infantry"
       format ["%1 %2", _taskType, _taskObject], //task short desc
       format ["%1 %2", _taskType, _taskObject], //Marker Text
       getMarkerPos _markerNum, //task waypoint
       "assigned" //task state
       ] 
   ] call FHQ_TT_addTasks;
};

This works as intended, but not for JIP.

I looked through your demo mission but all of the objectives/tasks were already planned out, so checks are able to be run to see if they are completed or not, for my mission its a bit more complex since the tasks are randomized.

I need a way to pull the variable missionType and markerNum into the init.sqf and have it available to create the same task JIP that's currently assigned to the already playing players.

I tried the [vehicleVarName player, missionType, taskNum] call lampCreateNewTaskClient; and it didn't work. I didn't get any errors, though i'm sure t, but it was probably because the variable "missionType and taskNum were nil.

Sorry if I'm overwhelming you with my messy code, but I'm not sure how to go about this. Thanks for your help.

Edited by zuff

Share this post


Link to post
Share on other sites

I cannot se the call to lampCreateNewTaskClient anywhere in your code.

Anyway, by the comment "Executed on the server" right above your lampCreateTask function my guess is that you have simply not selected the option in the editor that tells the framework to generate the necessary code for executing a function on a given client. Can it be so?

Also, if you simply want to "set a variable value" on clients or the server, you better use the publicVariable command. Then the current variable value is set from start on JIPs.

Share this post


Link to post
Share on other sites

Interesting.

The package seems to be very well prepared; documentation (manual and inline), and an application to assist the user.

Few remarks so far:

  • Cool to have the possibility of a return value. I haven't looked close enough to the locking system, but at least in my experience
    waitUntil { (drn_GetTimeAndWeatherResponseValue select 1) == _callID }; _response = drn_GetTimeAndWeatherResponseValue select 2;

    or similar situations could lead to data being out of date depending on load / scheduling. better use:

    _val = []; waitUntil { _val = drn_GetTimeAndWeatherResponseValue; _val select 1 == _callId }; _response = _val select 2;


  • You're using multiple publicvariables. Basically 1 or more per command. For JIP players this means that you sync the last value of each of these publicvariables to every JIP player,
  • this is probably not intended, you could combine them to a single PVEH.
  • An option to execute code where target object is local could be useful
  • Why use spawns in the PVEH code, instead of handle directly / call? spawns only add to script load and lag and should have no execution order guarantee
  • What about synchronization of tasks to JIP players, for the sample mission?

Edited by Sickboy

Share this post


Link to post
Share on other sites
I cannot se the call to lampCreateNewTaskClient anywhere in your code.

Anyway, by the comment "Executed on the server" right above your lampCreateTask function my guess is that you have simply not selected the option in the editor that tells the framework to generate the necessary code for executing a function on a given client. Can it be so?

Also, if you simply want to "set a variable value" on clients or the server, you better use the publicVariable command. Then the current variable value is set from start on JIPs.

That's because I removed it after it didn't work.

FHQ Tasktracker is suppose to run on the server and it broadcast to all players. I'm not entirely sure how it works but from what I understand is that it sends out the task to all playable units.

In the current state I have it now, everyone is receiving task even though it's ran on the server. It's just JIP that lose the task.

I'll see what I can do about the public variable, I've had bad luck with them in the past. Say I publicvariable something on the server, will a JIP client get that value?

Share this post


Link to post
Share on other sites

Yes, a JIP client will have the last publicVariabled value from start. Just make sure that you don't reset it in the init.sqf. Be careful to use only values that can be publicVariabled: http://community.bistudio.com/wiki/publicVariable

---------- Post added at 13:33 ---------- Previous post was at 12:50 ----------

Thanks for your feedback, Sickboy!

I'll look into your suggestions! Since it seems to work quite good right now I wanted to release it, but there are of course optimizations and things to improve.

You're using multiple publicvariables. Basically 1 or more per command. For JIP players this means that you sync the last value of each of these publicvariables to every JIP player, this is probably not intended, you could combine them to a single PVEH.

Actually it is intended, and I'm aware of the cost to synchronize these values for JIP players. I have tried to spread the load on the PVEHs. Maybe I underestimate the Arma script engine here, I don't know, but at the same time I would guess that the initial synchronization of variables when JIP connects is quite superable.

An option to execute code where target object is local could be useful

This is actually how the function that executes on a given client works. You can use the vehicle variable name for any object, it must not be a player unit object.

Why use spawns in the PVEH code, instead of handle directly / call? spawns only add to script load and lag and should have no execution order guarantee

I've had problems with waitUntil command in PVEHs, and I think that's why I did like this. This was a long time ago, so I will look into it again.

What about synchronization of tasks to JIP players, for the sample mission?

What do you mean? Is it not working?

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  

×