-- Thanks to Drex from Dynamic DCS for all the help on sockets, go check his server out package.path = package.path .. ";.\\LuaSocket\\?.lua;" package.cpath = package.cpath .. ";.\\LuaSocket\\?.dll;" local socket = require("socket") local JSON = loadfile("Scripts\\JSON.lua")() niod = {} local triggers = {} local groupsSet = SET_GROUP:New():FilterStart() local triggerScheduler = SCHEDULER:New( nil, function() checkTriggers() --niod.send(formGroupInfoPayload(getGroupsInfo())) niod.checkTimeout() end, {}, 5, 30 ) niod.scope = "127.0.0.1" niod.port = 15487 niod.DATA_TIMEOUT_SEC = 0.2 niod.JSON = JSON niod.isDev = true niod.eventHandler = { handleEvents = true } niod.tcp = socket.tcp() niod.tcp:settimeout(0) -- Util functions function niod.log(message) if message then env.info(message) end end function niod.setDevEnv(isDev) env.setErrorMessageBoxEnabled(niod.isDev) end -- NIOD functions wrappers niod.functions = {} niod.trigger = {} -- This is an example trigger --niod.trigger["GroupPartlyOrCompletelyInZone"] = function(trigger) -- local group = GROUP:FindByName(trigger.data.groupName) -- local zone = ZONE:FindByName(trigger.data.zoneName) -- if not group or not zone then -- return -- end -- if group:IsPartlyOrCompletelyInZone(zone) then -- niod.sendTrigger( -- { -- type = "trigger", -- callbackId = trigger.callbackId, -- data = {} -- } -- ) -- if trigger.data.frequency == "once" then -- removeTrigger(trigger.callbackId) -- end -- end --end -- Triggers function addTrigger(args) table.insert(triggers, args) end function checkTriggers() for i = 1, #triggers do checkTrigger(triggers[i]) end end function checkTrigger(t) if t then niod.trigger[t.data.type](t) else niod.log("Tried to check trigger but it wasn't defined") end end function removeTrigger(id) for i = 1, #triggers do if triggers[i].callbackId == id then table.remove(triggers, i) end end end function getGroupsInfo() local groups = {} groupsSet:ForEach( function(group) local groupInfo = {} groupInfo.coalitionName = group:GetCoalitionName() groupInfo.categoryName = group:GetCategoryName() groupInfo.country = group:GetCountry() groupInfo.units = {} for UnitId, UnitData in pairs(group:GetUnits()) do local unit = {} unit.fuel = UnitData:GetFuel() unit.callsign = UnitData:GetCallsign() unit.inAir = UnitData:InAir() unit.isActive = UnitData:IsActive() unit.isAlive = UnitData:IsAlive() unit.name = UnitData:Name() unit.pitch = UnitData:GetPitch() unit.roll = UnitData:GetRoll() unit.yaw = UnitData:GetYaw() unit.position = UnitData:GetPosition() table.insert(groupInfo.units, unit) end table.insert(groups, groupInfo) end ) return groups end function formGroupInfoPayload(groups) return { type = "groupInfo", callbackId = "groupInfo", data = groups } end -- NIOD functions function niod.bind() local bound, error = niod.tcp:bind(niod.scope, niod.port) if not bound then niod.log("Could not bind: " .. error) return end niod.log("Port " .. niod.port .. " bound") local serverStarted, error = niod.tcp:listen(1) if not serverStarted then niod.log("Could not start server: " .. error) return end niod.log("Server started") end function niod.checkJSON(jsonstring, code) if code == "encode" then if type(niod.JSON:encode(jsonstring)) ~= "string" then error("encode expects a string after function") end end if code == "decode" then if type(jsonstring) ~= "string" then error("decode expects string") end end end function niod.eventHandler.onEvent(event) niod.log("event") niod.log(event) end function niod.processRequest(request) local response = {} if request and request.type and request.callbackId then response.type = request.type response.callbackId = request.callbackId if request.data then veaf.logTrace(string.format("NIOD - niod.processRequest(%s)",veaf.p(request))) if request.type == "function" and request.data.name then response.data = niod.functions[request.data.name](request.data.args) elseif request.type == "trigger" and request.data then addTrigger(request) response.type = "triggerInit" response.data = {} elseif request.type == "noTimeout" then response.data = {} end end end veaf.logTrace(string.format("NIOD - response=%s", veaf.p(request), veaf.p(response))) return response end function niod.step() if not niod.client then niod.client = niod.tcp:accept() if niod.client then niod.client:settimeout(0) niod.log("Connection established") end end if niod.client then local line, err = niod.client:receive("*l") --niod.client:send('\n') local data = {} if line ~= nil then local success, error = pcall(niod.checkJSON, line, "decode") if success then local incMsg = niod.JSON:decode(line) niod.log(incMsg) data = niod.processRequest(incMsg) else niod.log("Error: " .. error) end end -- if there was no error, send it back to the niod.client if not err and data then local dataPayload = data --getDataMessage() niod.send(dataPayload) end end end function niod.sendTrigger(data) local dataPayload = data niod.send(dataPayload) end function niod.checkTimeout() local dataPayload = { type = "noTimeout", callbackId = "noTimeout", data = {} } niod.send(dataPayload) end function niod.send(dataPayload) if not niod.client then niod.log("Error: Connection lost") return end local success, error = pcall(niod.checkJSON, dataPayload, "encode") if success then local outMsg = niod.JSON:encode(dataPayload) local bytes, status, lastbyte = niod.client:send(outMsg .. "\n") if not bytes then niod.log("Error: Connection lost") niod.client = nil end else niod.log("Error: " .. error) end end niod.setDevEnv() niod.bind() world.addEventHandler(niod.eventHandler) timer.scheduleFunction( function(arg, time) local success, error = pcall(niod.step) if not success then niod.log("Error: " .. error) end return timer.getTime() + niod.DATA_TIMEOUT_SEC end, nil, timer.getTime() + niod.DATA_TIMEOUT_SEC ) niod.log("Started NIOD")