timothyboss Posted April 16, 2023 Posted April 16, 2023 Hello All. I have been working on a project to get items to export from DCS world using the local o = LoGetWorldObjects() and having great success for the most part. What I have been wrapping my head around is to get exported is also the unit type> AIRPLANE, SHIP, GROUND, HELICOPTER. to also be identified and exported. Below is the lua that I have been using with all working well except when I try to get the unitType or Group. Now I see 'group' might quantify the total number of each and I am searching for each line of my CSV Export.log file to also include HELICOPTER or AIRPLANE, etc. Please see lua. --This Export.lua illustrates how to export multiple data in 30 second intervals lat/long and flight alt etc. function LuaExportStart() -- create file object for writing default_output_file = io.open(lfs.writedir().."/Scripts/multiExportGS/Export.log", "w") end function LuaExportBeforeNextFrame() end function LuaExportAfterNextFrame() end function LuaExportStop() if default_output_file then default_output_file:close() default_output_file = nil end -- delete the Export.log file os.remove(lfs.writedir().."/Scripts/multiExportGS/Export.log") end function LuaExportActivityNextEvent(t) local tNext = t local o = LoGetWorldObjects() for k,v in pairs(o) do default_output_file:write(string.format("%.1f, %s, %f, %f, %f, %f, %s, %.1f\n", t, v.Name, v.LatLongAlt.Lat, v.LatLongAlt.Long, 3.28084*v.LatLongAlt.Alt, 57.2958*v.Heading, v.Coalition)) end tNext = tNext + 30.0 return tNext end tNext = tNext + 30.0 return tNext // I have tried to use a v.Type with no success. I have tried making some statements like this function LuaExportActivityNextEvent(t) local tNext = t local o = LoGetWorldObjects() for k,v in pairs(o) do print(v.Type) -- add this line for debugging purposes local objectType = "unknown" if v.Type == "Ship" then objectType = "ship" elseif v.Type == "Helicopter" then objectType = "helicopter" elseif v.Type == "Airplane" then objectType = "airplane" else objectType = "ground" end default_output_file:write(string.format("%.1f, %s, %f, %f, %f, %f, %s, %s\n", t, v.Name, v.LatLongAlt.Lat, v.LatLongAlt.Long, 3.28084*v.LatLongAlt.Alt, 57.2958*v.Heading, v.Coalition, objectType)) end tNext = tNext + 30.0 return tNext end and the only thing that is output is 'ground' as it is not finding the type correctly. Anyone have any ideas how i might be able to locate the level number or an ID 1,2,3,4 and I know what it is easily? Any help is greatly appreciated.
cfrag Posted April 17, 2023 Posted April 17, 2023 16 hours ago, timothyboss said: and the only thing that is output is 'ground' as it is not finding the type correctly. You are receiving "ground" because your catchall else objectType = "ground" end masks the uninitialized state. You may want to change that to "elseif" and you'll likely receive "unknown". To find out what is really returned, output the type of v.Type, and go from there. I've only glanced at LoGetWorldObjects description, and it appears to be old indeed ("Lo" is from "LockOn" - a game ED published 20 years ago). Since you 16 hours ago, timothyboss said: print(v.Type) -- add this line for debugging purposes already, what is the output? That should give you an indication what v.Type is. 1
timothyboss Posted April 17, 2023 Author Posted April 17, 2023 Hello cfrag. Thanks for the reply. I have been trying to get v.Type to output data but then the entire export.log is blank and nothing is written to it. The output right now is "time, name of unit (i.e. F-18C_Hornet), Lat, Long, Altitude, Heading, enemy or allied" lastly I am trying to determine if it is a ship, ground, airplane or helicopter, but with v.Type the output fails to write anything to my .log file.
timothyboss Posted April 17, 2023 Author Posted April 17, 2023 with ground being catchall at the end I was hoping it would at least generate something, it did where the v.Type did not, but its not the right thing. looking at the documentation i need to use something like getCategory or maybe getDesc and try to have that pull a class of the item from a table somewhere.
cfrag Posted April 17, 2023 Posted April 17, 2023 (edited) 8 hours ago, timothyboss said: I have been trying to get v.Type to output data but then the entire export.log is blank and nothing is written to it. In that case, in all likelihood, v.Type is nil. Test for that, and set objectType = "NIL!" in that case, so know it's nil. If it's not nil, set objectType to the type that is returned, e.g. objectType = "type is <" .. type(v.Type) .. ">" and dump the table contents if type is equal to "table" Or, try a different approach. If you know it's a unit, simpyl use Unit.GetByName, and then get its desc and type. Since you have the name of the unit, that should be possible. Nilcheck before you access desc/type so you don't crash. Edited April 17, 2023 by cfrag 1
timothyboss Posted April 18, 2023 Author Posted April 18, 2023 I haven't had much luck. I have a work around. Get the name of the unit and just use a lookup function to compare and if criteria is met...it's a SHIP, HELICOPTER etc. A little more work, but that's ok. Thanks for your help.
timothyboss Posted April 28, 2023 Author Posted April 28, 2023 in case I still have followers in this post. I did not have much luck in the previous posting so I instead used some info from the export and knowledge of units to have excel functions lookup and such. anyhow thank you all for your inputs. I do have a second question if anyone might have the answer (I will continue to search the forum too) I have the Export.lua script in my saved games with the following call outs. local wwtlfs=require('lfs');dofile(wwtlfs.writedir()..'Scripts/wwt/wwtExport.lua') local FlightPlannerlfs = require('lfs');dofile(FlightPlannerlfs.writedir()..'Scripts/FlightPlanner/FlightPlanner.lua') local multiExportGSlfs=require('lfs');dofile(multiExportGSlfs.writedir()..'Scripts/multiExportGS/latlongelev.lua') dofile(lfs.writedir()..[[Scripts\DCS-BIOS\BIOS.lua]]) local Tacviewlfs=require('lfs');dofile(Tacviewlfs.writedir()..'Scripts/TacviewGameExport.lua') local TheWayLfs=require('lfs');dofile(TheWayLfs.writedir()..'Scripts/TheWay.lua') pcall(function() local dcsSr=require('lfs');dofile(dcsSr.writedir()..[[Mods\Services\DCS-SRS\Scripts\DCS-SimpleRadioStandalone.lua]]); end,nil) Now my problem is that these two keep stepping on one another meaning which ever is in the bottom wins and thats is the lua that provides the output file. when I swap these two around then the one on the bottom wins etc. and writes. local FlightPlannerlfs = require('lfs');dofile(FlightPlannerlfs.writedir()..'Scripts/FlightPlanner/FlightPlanner.lua') local multiExportGSlfs=require('lfs');dofile(multiExportGSlfs.writedir()..'Scripts/multiExportGS/latlongelev.lua') so what are the two lua scripts it calls? see below, in order of the above post. function LuaExportStart() -- create file object for writing d_output_file = io.open(lfs.writedir().."/Scripts/FlightPlanner/data.json", "w") -- get the start time start_time = os.clock() end function LuaExportStop() -- close the file object if d_output_file then d_output_file:close() d_output_file = nil end -- delete the data.json file os.remove(lfs.writedir().."/Scripts/FlightPlanner/data.json") end function LuaExportActivityNextEvent(t) local currentTime = LoGetModelTime() if not lastExportTime or (currentTime - lastExportTime) >= 30.0 then lastExportTime = currentTime local o = LoGetWorldObjects() -- delete the data.json file before writing to it os.remove(lfs.writedir().."/Scripts/FlightPlanner/data.json") -- create file object for writing d_output_file = io.open(lfs.writedir().."/Scripts/FlightPlanner/data.json", "w") for k,v in pairs(o) do d_output_file:write(string.format("%.1f,%s,%f,%f,%.1f,%.1f,%s\n", t, v.Name, v.LatLongAlt.Lat, v.LatLongAlt.Long, 3.28084*v.LatLongAlt.Alt, 57.2958*v.Heading, v.Coalition)) end -- close the file object if d_output_file then d_output_file:close() d_output_file = nil end end end and function startServer() local folderPath = "E:/Saved Games/DCS.openbeta/Scripts/multiExportGS" -- Replace this with the desired folder location local command = 'start "" powershell.exe -noexit -command "cd \'' .. folderPath .. '\'; node import.js"' -- Concatenate the command to change directory and start the server os.execute(command) -- Execute the command in the system shell end function LuaExportStart() -- create file object for writing default_output_file = io.open(lfs.writedir().."/Scripts/multiExportGS/FltPlannerGPS.log", "w") -- get the start time start_time = os.clock() -- Start the server upon LuaExportStart() startServer() end function LuaExportStop() -- close the file object if default_output_file then default_output_file:close() default_output_file = nil end -- delete the Export.log file os.remove(lfs.writedir().."/Scripts/multiExportGS/FltPlannerGPS.log") -- Close the server upon LuaExportStop() if os.getenv("OS") == "Windows_NT" then os.execute("taskkill /IM node.exe /F") -- Terminate the node.exe process os.execute("taskkill /IM powershell.exe /F") -- Terminate the PowerShell process else os.execute("pkill node") -- Terminate the node process on Unix-like systems os.execute("pkill powershell") -- Terminate the PowerShell process on Unix-like systems end end function LuaExportActivityNextEvent(t) local currentTime = LoGetModelTime() if not lastExportTime or (currentTime - lastExportTime) >= 30.0 then lastExportTime = currentTime local o = LoGetWorldObjects() for k,v in pairs(o) do default_output_file:write(string.format("%.1f,%s,%f,%f,%.1f,%.1f,%s\n", t, v.Name, v.LatLongAlt.Lat, v.LatLongAlt.Long, 3.28084*v.LatLongAlt.Alt, 57.2958*v.Heading, v.Coalition)) end end end I suspect my problem is related to multiple calls to the same function at the same time, but I cannot wrap my head around it. I am suspecting the function: function LuaExportActivityNextEvent(t) is causing the binding or overwritten or stepping on issue. Does anyone know how I might be able to run these two lua scripts separately and independent of one another while both performing as they are intended to function? Thanks in advance.
Dangerzone Posted April 28, 2023 Posted April 28, 2023 Interesting time to be playing with such scripts as I'm wondering if the multi-threading stuff might be impacting what you're doing. Have you thought of setting a global variable that the other routine refers to and won't execute until the first is finished it's LoGetWorldObjects call. ie, something along the lines of: In your first script: if not lastExportTime or (currentTime - lastExportTime) >= 30.0 then lastExportTime = currentTime while script1_is_running do -- do nothing but wait end script2_is_running = true local o = LoGetWorldObjects() script2_is_running = false .... and if not lastExportTime or (currentTime - lastExportTime) >= 30.0 then lastExportTime = currentTime while script2_is_running do -- do nothing end script1_is_running = true local o = LoGetWorldObjects() script1_is_running = false for k,v in pairs(o) do default_output_file:write(string.format("%.1f,%s,%f,%f,%.1f,%.1f,%s\n", t, v.Name, v.LatLongAlt.Lat, v.LatLongAlt.Long, 3.28084*v.LatLongAlt.Alt, 57.2958*v.Heading, v.Coalition)) end ...Or better still maybe even if you just add an extra if condition to only run that code provided the other one isn't running, as it looks like you're just wanting this to run every 30 seconds anyway? 1
cfrag Posted April 28, 2023 Posted April 28, 2023 5 hours ago, timothyboss said: Now my problem is that these two keep stepping on one another Apologies, I'm having a slow brain day. Which two? I seem to see tons of dofile() in the script. I'm guessing "FlightPlannerlfs" and "multiExportGSlfs" 5 hours ago, timothyboss said: which ever is in the bottom wins and thats is the lua that provides the output file. when I swap these two around then the one on the bottom wins etc. and writes. I suspect that this has a simple reason: overwrite. The sequentially second erases and then rewrites the first. If they have the same output file name, that is. Use 'a' instead of 'w' in open to append. What are the file names of the output files that you expect to be written? If it's an overwrite issue, open and create/erase the save file in the main script, then have both dependent scripts simply write. I'm suspecting that the invoked dependent scripts each io.open(filename, "w") to the save file, creating a new one each time. Also (my brain is really hurting; yesterday evening was tremendously successful, I'm afraid) it seems to me that you redefine LuaExportStart() and LuaExportStop() in both scripts, so whatever you load last will win if they are invoked asynchronously (which the 'startServer' bit seems to imply). Hope this helps, -ch
timothyboss Posted April 28, 2023 Author Posted April 28, 2023 4 hours ago, cfrag said: Apologies, I'm having a slow brain day. Which two? I seem to see tons of dofile() in the script. I'm guessing "FlightPlannerlfs" and "multiExportGSlfs" I suspect that this has a simple reason: overwrite. The sequentially second erases and then rewrites the first. If they have the same output file name, that is. Use 'a' instead of 'w' in open to append. What are the file names of the output files that you expect to be written? If it's an overwrite issue, open and create/erase the save file in the main script, then have both dependent scripts simply write. I'm suspecting that the invoked dependent scripts each io.open(filename, "w") to the save file, creating a new one each time. Also (my brain is really hurting; yesterday evening was tremendously successful, I'm afraid) it seems to me that you redefine LuaExportStart() and LuaExportStop() in both scripts, so whatever you load last will win if they are invoked asynchronously (which the 'startServer' bit seems to imply). Hope this helps, -ch Hello and thanks for your reply. you are correct in that the two files called by the export.lua are in fact "FlightPlannerlfs" and "multiExportGSlfs" and the "w" to "a" did nothing as the ..'Scripts/FlightPlanner/FlightPlanner.lua') is being blocked by ..'Scripts/multiExportGS/latlongelev.lua'). Im still at it, but a good head scratcher. seems like I need to call on them separately, but having a heck of a time defining that process. 6 hours ago, Dangerzone said: Interesting time to be playing with such scripts as I'm wondering if the multi-threading stuff might be impacting what you're doing. Have you thought of setting a global variable that the other routine refers to and won't execute until the first is finished it's LoGetWorldObjects call. ie, something along the lines of: In your first script: if not lastExportTime or (currentTime - lastExportTime) >= 30.0 then lastExportTime = currentTime while script1_is_running do -- do nothing but wait end script2_is_running = true local o = LoGetWorldObjects() script2_is_running = false .... and if not lastExportTime or (currentTime - lastExportTime) >= 30.0 then lastExportTime = currentTime while script2_is_running do -- do nothing end script1_is_running = true local o = LoGetWorldObjects() script1_is_running = false for k,v in pairs(o) do default_output_file:write(string.format("%.1f,%s,%f,%f,%.1f,%.1f,%s\n", t, v.Name, v.LatLongAlt.Lat, v.LatLongAlt.Long, 3.28084*v.LatLongAlt.Alt, 57.2958*v.Heading, v.Coalition)) end ...Or better still maybe even if you just add an extra if condition to only run that code provided the other one isn't running, as it looks like you're just wanting this to run every 30 seconds anyway? That is correct. I wan them to both be independent of one another an each run at a set time after executed. they can be staggered, but I am going to attempt to go with your approach and see the outcome. thank you for your input. I let all know of the findings.
timothyboss Posted April 28, 2023 Author Posted April 28, 2023 I'm thinking that maybe for this project... If I have to start or stop or pause and wait with if statements in the exporting of the same or similar data, then I might just try to build a master export Lua that writes to multiple locations in the format I need for both separate projects. I should be able to set a global variable that starts say named function script1() and runs through the code in latlongelev.lua and then end with a continuation to function script2() run FlightPlannerGPS.lua end and then 30 seconds later repeat. That way both files should be written, and ended so the other can be written and ended without being stepped on. I will just have to start the server for node.js outside in a new global variable, remove the loops inside the independent Lua scripts so they complete and I should be good. When the game closes, the server closes and the problem should be solved? Maybe? Thoughts. If only DCS Lua environ would allow multiple calls of the LuaExportActivityNextEvent () by affixing a 1,2,3.... To the end. Or I just need to get better... The later.
timothyboss Posted April 28, 2023 Author Posted April 28, 2023 @Dangerzone is that what you meant. Above post.
cfrag Posted April 28, 2023 Posted April 28, 2023 2 hours ago, timothyboss said: is that what you meant I believe @Dangerzone was talking about a possible race condition between the two export scripts caused by two threads running concurrently that attempt to access the same resource, caused by the new multithreading ability in DCS. If that was the case, his kindly proposed solution is as likely to end in a deadlock as to resolve it, with both scripts waiting for the other to release the other scriptX_is_running, as Lua has no mutex or other semaphore to prevent this (the proposed lock-and-release solution is unsafe). I don't think your issue is caused by a contention issue. Have you verified that your LuaExportStart() and LuaExportStop() methods can't overwrite each other, i.e. that their name space isn't shared? If they are loaded into the same context, one will overwrite the other.
timothyboss Posted April 28, 2023 Author Posted April 28, 2023 20 minutes ago, cfrag said: I believe @Dangerzone was talking about a possible race condition between the two export scripts caused by two threads running concurrently that attempt to access the same resource, caused by the new multithreading ability in DCS. If that was the case, his kindly proposed solution is as likely to end in a deadlock as to resolve it, with both scripts waiting for the other to release the other scriptX_is_running, as Lua has no mutex or other semaphore to prevent this (the proposed lock-and-release solution is unsafe). I don't think your issue is caused by a contention issue. Have you verified that your LuaExportStart() and LuaExportStop() methods can't overwrite each other, i.e. that their name space isn't shared? If they are loaded into the same context, one will overwrite the other. Good question. I don't even see it reporting in the DCS.log file. I might need to print to. Should, normally, the Lua start / stop / exportActiveNextEvent function regardless if other scripts call the same functions?
timothyboss Posted April 28, 2023 Author Posted April 28, 2023 I have a suspicion it is probably overwriting the other because of how the scripts were written at one test point. The first (of two) dofile Lua's I am having issues with called the luaexportactivitynextevent() function and the second Lua actually performed the write to the location which confused me. But the second Lua exportnextevent was renamed something else, so I feel there might need to be a pause or delay in the dofile if possible. Maybe have a dofile that performs 1 script and then ends then performs the second then ends. Maybe like a subroutine?
timothyboss Posted April 28, 2023 Author Posted April 28, 2023 Maybe using the hooks is the way to go? This is not the first time this issues has been brought up either. There are some good talks across a couple forums of this same issue. People get creating by refining global variables that end up calling on the LuaExportStart () / stop / before frame / after frame / next event. I just need to get smarter on that part.
Dangerzone Posted April 29, 2023 Posted April 29, 2023 (edited) 10 hours ago, cfrag said: I believe @Dangerzone was talking about a possible race condition between the two export scripts caused by two threads running concurrently that attempt to access the same resource, caused by the new multithreading ability in DCS. If that was the case, his kindly proposed solution is as likely to end in a deadlock as to resolve it, with both scripts waiting for the other to release the other scriptX_is_running, as Lua has no mutex or other semaphore to prevent this (the proposed lock-and-release solution is unsafe). Thanks CFRAG for picking up on that problem. Sorry for misleading you @timothyboss, there's a lot more traps for me to learn about with lua it would seem. Thank goodness for the wealth of info shared in these forums. Would it be possible to set a lastran_x stamp instead. Then when starting a script you check to see if the 'other' script has been ran within the last 5 seconds and if it has you skip that instance and wait again. This way it may not end in a deadlock but rather uses timestamps so if something does go amiss - it would reset itself? Edited April 29, 2023 by Dangerzone
timothyboss Posted April 29, 2023 Author Posted April 29, 2023 13 hours ago, Dangerzone said: Thanks CFRAG for picking up on that problem. Sorry for misleading you @timothyboss, there's a lot more traps for me to learn about with lua it would seem. Thank goodness for the wealth of info shared in these forums. Would it be possible to set a lastran_x stamp instead. Then when starting a script you check to see if the 'other' script has been ran within the last 5 seconds and if it has you skip that instance and wait again. This way it may not end in a deadlock but rather uses timestamps so if something does go amiss - it would reset itself? @Dangerzone @cfrag what are your thoughts on the Export.lua making a call to a file that loads the two independently. So for the FlightPlanner Lua I would have a LuaExportStart () start the server, start to write directory. Perform the task to export and end. Start the write of the second Lua latlongelev.lua and just perform the script. No need for the second script to start at the LuaExportStart (). Once complete with the second Lua... Repeat until the game ends and then I can luaExportStop ().
Recommended Posts