-- ========================================================= -- Here are the values which can be customized. -- Here are the default values. -- IP_ADDRESSE -> "localhost" -- PORT_NUMBER -> 10310 -- LOG_FILE -> "c:/Mission.log" -- SAMPLING_PERIOD -> 1 IP_ADDRESSE = "localhost" PORT_NUMBER = 10310 SAMPLING_PERIOD = 1.0 -- End of customization zone -- ========================================================= -- -------------------------------------------------------- -- Used to convert lockon Subtype in la otact Id -- IGNORED_TYPE is used when we have no interest for an object IGNORED_TYPE = 100 AIRPLANE = 32 HELICOPTER = 33 CHAFF_FLARE = IGNORED_TYPE MISSILE = IGNORED_TYPE BOMB = IGNORED_TYPE SHELL = IGNORED_TYPE ROCKET = IGNORED_TYPE GROUND_MOVING = 37 GROUND_STANDING = 38 SHIP = 39 AERODROME = 40 SAM = 41 TANK = 42 ObjectTypeLUT= { [ 1] = AIRPLANE, [ 2] = HELICOPTER, [ 3] = CHAFF_FLARE, [ 4] = MISSILE, [ 5] = BOMB, [ 6] = SHELL, [ 7] = ROCKET, [ 8] = GROUND_MOVING, [ 9] = GROUND_STANDING, [12] = SHIP, [13] = AERODROME, [16] = SAM, [17] = TANK, } -- -------------------------------------------------------- -- Name of the log file. Same format than tacview LOG_FILE = "./Temp/Lotatc2-"..os.date("%Y%m%d-%H%M%S")..".log" -- -------------------------------------------------------- -- Use to convert lockon coalition name in lotatc Id coalitionLUT= { ["Allies"] = 0, ["Enemies"] = 1, } -- -------------------------------------------------------- -- List of message codes sent to lotatc server START_OF_MISSION = 0 START_OF_TIME_SLOT = 1 NEW_OBJECT = 2 UPDATE_OBJECT = 3 END_OF_TIME_SLOT = 4 END_OF_MISSION = 5 -- ------------------------------------------------------------------------------------------------------ -- There are two lists of object, the primaryLotatcObject which contains the initial position of each object, -- and the processedLotatcObject which contains the current position of the processed objects. -- An object is tagged as processed when it is a static object and also as soon as we detect a move for moving objects. primaryLotatcObject = {} processedLotatcObject = {} do previousLuaExportStart=LuaExportStart LuaExportStart=function() dofile "lua.lua" -- -------------------------------------------------------- -- Create the comminucation socket with Lotact server socket = require("socket") -- Often, the lotact server is located on the same machine -- If it is not the case, you can change here the IP address. -- Keep the port number unchanged local host = IP_ADDRESSE local port = PORT_NUMBER cnxObj = socket.connect(host, port) if cnxObj then -- set immediate transmission mode cnxObj:setoption("tcp-nodelay",true) end -- -------------------------------------------------------- -- Create a log file used to playback the mission. local file = io.open(LOG_FILE, "w") if file then io.output(file) end -- -------------------------------------------------------- -- Send/log Mission start Time only one Time message = string.format("%d|%d|%s\n", START_OF_MISSION, LoGetMissionStartTime(), SAMPLING_PERIOD) io.write(message) if cnxObj then socket.try(cnxObj:send(message)) end -- -------------------------------------------------------- -- Create an empty data base processedLotatcObject={} if previousLuaExportStart then previousLuaExportStart() end end end do previousLuaExportBeforeNextFrame=LuaExportBeforeNextFrame LuaExportBeforeNextFrame=function() if previousLuaExportBeforeNextFrame then previousLuaExportBeforeNextFrame() end end end -- Function called every x second do local previousLuaExportActivityNextEvent = LuaExportActivityNextEvent LuaExportActivityNextEvent=function(t) local tNext = t -- Flag set when a new object is declared to be processed. local createObject -- Flag used when an object is to be updated local updateObject -- Fill the buffer with START_OF_TIME_SLOT message. local message = string.format("%s|%.2f\n", START_OF_TIME_SLOT, LoGetModelTime()) -- --------------------------------------------------- -- Retrieve and process all the lockon objects local worldObjects = LoGetWorldObjects() for objectId, objectInfo in pairs(worldObjects) do -- --------------------------------------------------- -- Use lookUpTable to convert Lockon SubType local objectType = ObjectTypeLUT[objectInfo.Subtype] if objectType ~= IGNORED_TYPE then -- --------------------------------------------------- -- Init processing flag createObject = false updateObject = false -- --------------------------------------------------- -- Is this object in the list of processed object <-- it has already moved if processedLotatcObject[objectId] then -- --------------------------------------------------- -- Yes, so we have just to prepare the update message -> UPDATE_OBJECT message = message..string.format("%s|%s", UPDATE_OBJECT, objectId) updateObject = true -- --------------------------------------------------- -- Check if this object is part of the primary list. elseif not primaryLotatcObject[objectId] then -- No, insert this object in the primary list primaryLotatcObject[objectId] = objectInfo -- If it is not a PLANE nor an HELICO, insert object in the processed object list if (objectType ~= AIRPLANE) and (objectType ~= HELICOPTER) then -- Update flag, it will be inserted later createObject = true updateObject = true end -- End of: if (objectType ~= AIRPLANE) and (objectType ~= HELICOPTER) then -- --------------------------------------------------- -- Object is in the primary list but not yet in the processed list -- Check if the object has moved else local primaryObjectValue = primaryLotatcObject[objectId] if ((objectInfo.LatLongAlt.Lat ~= primaryObjectValue.LatLongAlt.Lat ) or (objectInfo.LatLongAlt.Long ~= primaryObjectValue.LatLongAlt.Long) ) then -- Update flag, it will be inserted later updateObject = true createObject = true end end -- end of: if processedLotatcObject[objectId] then -- --------------------------------------------------- -- Process new processed object if createObject == true then -- --------------------------------------------------- -- Retrieve coalition local coalition if objectInfo.Coalition then coalition = coalitionLUT[objectInfo.Coalition] if not coalition then coalition = "" end else coalition = "" end -- --------------------------------------------------- -- Retrieve Unit name and Pilot name local lockonName = objectInfo.Name local pilotName local unitName -- Replace lotatc message separator "|" if there is any with "-" lockonName = string.gsub(lockonName, "|", "-") -- Remove " (Me)" if there is one lockonName = string.gsub(lockonName, " %(Me%)", "") -- Extract Pilot name if there is one if string.find(lockonName,"%(.*%)") then pilotName = string.gsub(lockonName, "(.*)%((.*)%)", "%2") else pilotName = "" end -- Extract Unit name unitName = string.gsub(lockonName, "%(.*%)", "") if not unitName then unitName = "" end -- --------------------------------------------------- -- Fill the buffer with NEW_OBJECT message message = message..string.format("%s|%s|%s|%s|%s|%s", NEW_OBJECT, objectId, objectType, unitName, pilotName, coalition) end -- end of: if createObject==true then -- --------------------------------------------------- -- Now it is time to complete the message with dynamic part. -- In order to decrease CPU load related to the transmition -- we only transmit info when there is a change if updateObject == true then -- --------------------------------------------------- -- Latitude objectChange = false local previousObjectValue = processedLotatcObject[objectId] if (createObject == true) or (objectInfo.LatLongAlt.Lat ~= previousObjectValue.LatLongAlt.Lat) then message = message..string.format("|%.6f", objectInfo.LatLongAlt.Lat) objectChange = true else message = message.."|" end -- Longitude if (createObject == true) or (objectInfo.LatLongAlt.Long ~= previousObjectValue.LatLongAlt.Long) then message = message..string.format("|%.6f", objectInfo.LatLongAlt.Long) objectChange = true else message = message.."|" end -- Altitude if (createObject == true) or (objectInfo.LatLongAlt.Alt ~= previousObjectValue.LatLongAlt.Alt) then message = message..string.format("|%.6f", objectInfo.LatLongAlt.Alt) objectChange = true else message = message.."|" end -- Bearing if (createObject == true) or (objectInfo.Heading ~= previousObjectValue.Heading) then message = message..string.format("|%.6f", objectInfo.Heading) objectChange = true else message = message.."|" end message = message.."\n" -- Add/update object info in the processed object list if objectChange == true then processedLotatcObject[objectId] = objectInfo end end -- end of: if updateObject == true then end -- end of: if objectType ~= IGNORED_TYPE then -- As there is constraint about the size of the buffer -- log/send now the buffer if there is enough data if string.len(message) > 1000 then io.write(message) if cnxObj then socket.try(cnxObj:send(message)) end message="" end -- End of: if string.len(message) > 1000 then end -- End of: for objectId, objectInfo in pairs(worldObjects) -- Notify Lotatc about end of time slot. message = message..string.format("%s\n", END_OF_TIME_SLOT) -- --------------------------------------------------- -- Now it is time to log/send the message. io.write(message) if cnxObj then socket.try(cnxObj:send(message)) end -- --------------------------------------------------- -- Remove killed objects.There is no need to log/save -- this info, it will be computed again by lotatc server for objectId, objectInfo in pairs(processedLotatcObject) do if not worldObjects[objectId] then processedLotatcObject[objectId] = nil end end if previousLuaExportActivityNextEvent then previousLuaExportActivityNextEvent() end -- Provide to caller next call time return tNext + SAMPLING_PERIOD end end do previousLuaExportAfterNextFrame = LuaExportAfterNextFrame LuaExportAfterNextFrame=function() if previousLuaExportAfterNextFrame then previousLuaExportAfterNextFrame() end end end do previousLuaExportStop = LuaExportStop LuaExportStop=function() -- Function called at the end of the mission -- Notify for end of mission message = string.format("%d\n", END_OF_MISSION) io.write(message) -- Close log file io.close() -- Close communication socket if cnxObj then socket.try(cnxObj:send(message)) cnxObj:close() end if previousLuaExportStop then previousLuaExportStop() end end end