Jump to content

net.dostring_in -> call mission environment functions?


Recommended Posts

Posted

Hello everyone,

I am trying to build a statistics script that should run on our server regardless of the map selected.

I've got a hook running in the server control environment and tried to use something like this:

 

 

return net.dostring_in('mission', [[

local function serialize(val)
   if type(val) == 'number' or type(val) == 'boolean' then
       return tostring(val)
   elseif type(val) == 'string' then
       return string.format("%q", val)
   elseif type(val) == 'table' then
       local k, v
       local str = '{'
       for k, v in pairs(val) do
           str = str .. '[' .. serialize(k) .. ']=' .. serialize(v) .. ','
       end
       str = str .. '}'
       return str
   end
   return 'nil'
end

return tostring(serialize(coalition == nil))
]])

 

 

As far as I have understood the documentation, net.dostring_in('mission', 'code here') should allow me to execute code in the mission environment.

Why am I not able to access the coalition singleton?

According to https://wiki.hoggitworld.com/view/Simulator_Scripting_Engine_Documentation it should be available in the mission environment?

 

 

Thanks in advance,

trampi

Posted (edited)

I may be wrong about this, but IIRC, net.dostring_in() only works with mission environment flags.

 

For instance, this should return the value of a given mission environment flag (note that both parameters must be valid strings):

net.dostring_in('server', " return trigger.misc.getUserFlag(\"[color="Red"]Name of the flag in ME[/color]\"); ")

 

 

What are you trying to accomplish with that serializer?

 

 

EDIT: I see that you already sorted it out on the MOOSE discord channel, which would've been my recommendation :thumbup:

Edited by Hardcard
Posted

Hi Hardcard,

 

I was a bit in a hurry yesterday, so I'll try to provide more Information :-)

 

I'll try to explain

1) What I want to achieve

2) How I thought I can achieve it

3) Where I am stuck and what I will try next

 

Lets start...

1) What I want to achieve

 

I want to track statistics on our wing servers.

Especially I want to track the follwing statistics:

 

* time in flight

* time on airport

* time on carrier

* a2a kills

* a2g kills (ships, vehicles)

* takeoffs

* landings

* player deaths

* ejects

* carrier traps

 

The statistics should then be visualized on our website.

Visualizing and getting the statistics on the website is not the main problem.

Exporting the data from DCS is where I am stuck right now.

I want the solution to be as minimal invasive as possible, so a Hook in the server would be nice!

That would also mean that we do not have to touch any mission files, as the hook is executed always.

 

2) How I thought I can achieve it

 

I use the DCS Control API in a Hook Script, so that I do not have to prepare each Mission with the score script, as the hook is always run.

Thanks to DCS.setUserCallbacks I am provided with the following events:

 

--"friendly_fire", playerID, weaponName, victimPlayerID

--"mission_end", winner, msg

--"kill", killerPlayerID, killerUnitType, killerSide, victimPlayerID, victimUnitType, victimSide, weaponName

--"self_kill", playerID

--"change_slot", playerID, slotID, prevSide

--"connect", playerID, name

--"disconnect", playerID, name, playerSide, reason_code

--"crash", playerID, unit_missionID

--"eject", playerID, unit_missionID

--"takeoff", playerID, unit_missionID, airdromeName

--"landing", playerID, unit_missionID, airdromeName

--"pilot_death", playerID, unit_missionID

 

Most of the things I want to track are provided here :-)

But lets look at time in flight / on airport / on carrier:

 

I want to sample each second the unit state. First, I would iterate over all player objects.

Next I would call the inAir method (https://wiki.hoggitworld.com/view/DCS_func_inAir) to check if the unit is in air / on ground.

If a user is on ground I would calculate the distance to carrier objects, so that I know if it is an airport or a carrier.

 

3) Where I am stuck and what I will try next

 

However, the Server Control API / Export API (which is accessible from the Sever Control API) does not allow me to call the mission environment API, e.g. inAir().

I thought that net.dostring_in would allow me to call the mission environment (and the mission API!) from the server api. The serialize-thing was thought to help me pass back data from the net.dostring_in('mission', code) to the server control environment.

So, how can I find out if a player is in air / on airport / on carrier?

I could determine heuristically if the unit is above ground, not moving very fast, and so on... but: what if the player is in a hovering helicopter not that far above the airport?

There is that little neat function inAir that would provide accurate information without any guesswork involved ;-)

So thats the idea why I want to call inAir via net.dostring_in('mission', code), but that does not seem to work.

 

Currently, I hope to still somehow access mission script functions, e.g. inAir, via the server control environment.

The other idea would be to write a small program that automatically repackages all mission files and injects the statistics script - this way I would be able to call all the DCS Mission API functions and it would not lead to more work for our mission designers - they do not have to check that the statistics script is up to date and so on.

 

MOOSE Discord is indeed helpful! I just got the following thing wrong:

1) The mission environment can not access the server control environment because of security reasons, so that a rogue mission file can not e.g. change maps (this is correct)

2) The server control environment can access the mission environment and all the mission API via net.dostring_in (this seems to be my wrong assumption)

 

So, my question still remains:

Is there any way to somehow access the Unit.inAir method from the server control api? Or do I have to embed a seperate script in the mission file?

Pseudo code for what I want to achieve in the server control hook code:

 

return net.dostring_in('mission', [[
   local blue = coalition.side.BLUE
   local bluePlayers = coalition.getPlayers(blue)
   return tostring(bluePlayers[1].inAir())
]])

 

Right now I get the error that coalition is a nil value.

 

Any help appreciated.

Posted
@trampi

 

I see, you want to create a gadget, like the BuddySpike people did -->http://gadget.buddyspike.net/

 

Xcom and Ciribob should be able to help you with it, you can contact them on the BF Discord channel, just keep in mind they're busy.

 

 

I only have limited experience with the DCS Control API, but I guess I can offer you my 2 cents:

 

  • Make sure that :inAir() works with carrier-based aircraft. Alternatively, use land events, I think they're more reliable (and work for helicopters as well).
    Note that land events also contain the landing location (provided it's an airbase area or carrier / warship)
     
     
  • I'd try to use custom flags to provide the environment information that you need for each unit.
    For instance, you could periodically populate a table with all active clients and then iterate that table to create / modify the status flags for each unit.
    Here's an example (contains MOOSE code):
    local function Status_Check()
         
         local Client_SET = SET_CLIENT:New():FilterActive(Active):FilterOnce() [color="Blue"]-- This set should be automatically populated with all active clients in the mission[/color]
         
         local Active_Unit_Table = Client_SET:GetSetObjects() [color="blue"]-- This should return a table containing all active clients in the mission[/color]
         
         for i, Active_Unit in pairs(Active_Unit_Table) do
             
             if Active_Unit and Active_Unit:GetDCSObject() then
                
                local DCS_Object = Active_Unit:GetDCSObject()  [color="blue"]-- Convert MOOSE objects to DCS[/color]
                local DCS_Object_Name = DCS_Object:getName()
                
                if DCS_Object:inAir() then
         
                   trigger.action.setUserFlag( "inAir_Flag_"..DCS_Object_Name , 1)[color="blue"] -- The server hook should be able to access this custom flag[/color]
      
                elseif DCS_Object:inAir() == false then  
         
                   trigger.action.setUserFlag( "inAir_Flag_"..DCS_Object_Name , 0) [color="blue"]-- The server hook should be able to access this custom flag[/color]
                end
             end
         end
      
      return timer.getTime() + 10 [color="blue"] -- Refresh is set to 10 seconds, feel free to experiment with lower values [/color]
    end
    
    timer.scheduleFunction(Status_Check, nil , timer.getTime() + 1)


Posted

My two cents.

 

You can load the entirety of moose into the server environment if you want, but don't. The way you do that is just as you described, I've done it, its unsupported and if something goes wrong you will be going down a path no one can help you in. Use the native lua in the server environment and give up on Moose. I do know people who have done this, but given the design I'm not smart enough to predict how it might go wrong for something.

 

Or, collect the data like we do on our server, from the mission environment and make tables and stick them in your SQL database. Even PHP reads CSV natively without effort, and making a CSV from events or literally any data is trivial.

 

BS is a very simple design. The entire status is kept as one table and saved to disk. They even make the gadget to read that table data, or at least did when I checked last which was a year or two back, and that was perfectly functional. Xcom even did a guide on importing stats to server that is buried under years of posts here. Just events, tables, wamp and some queries. Very simple.

___________________________________________________________________________

SIMPLE SCENERY SAVING * SIMPLE GROUP SAVING * SIMPLE STATIC SAVING *

Posted

Thank you for your answers, I've got it running now.

 

Below is a architecture diagram:

 

stats-architecture.png

 

My hook is running in the Server Control Environment (Saved Games/DCS/Scripts/Hooks/statsexport.lua).

 

I've discovered that in the Mission Environment ("Manager") I can execute code in the Mission Environment ("Real") via a_do_script. There I can access all Mission APIs.

 

After I've disabled the Mission Environment sanitizing calls in DCS_ROOT/Scripts/MissionScripting.lua I can now export all necessary data via UDP there as well.

 

Thanks for all the help! If anyone stumbles upon this and needs help just drop a PM.

  • 1 year later...
Posted (edited)

@trampi do you have have this hung on a Github repo, I'm trying to do the exact same thing and I'd like to look over your shoulder if possible.

Edited by kruzaavn
Posted

nope, unfortunately it is not public.

I am lacking the time to polish it for publication unfortunately 😕 but I agree that it would be in the interest of everyone to do it. I've replied to your PM.

If anyone else needs help with this approach, don't be afraid to post here or send me a message!

  • 3 years later...
Posted (edited)

As of DCS 2.9.13, a_do_script() finally has return value pass-thru:

Quote

Scripting API. Added possibility to pass args and return values from mission scripting a_do_script() and a_do_file() APIs.

Example code for the control/hooks environment that fetches a string value from the mission scripting environment:

return net.dostring_in("mission", [=[
    return a_do_script([[
        return "42"
    ]])
]=])

P.S.: Sorry for necro-posting. As these forum posts are DCS' scripting "documentation", it appeared appropriate to update said docs.

Edited by Actium
  • Thanks 1
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...