mirror of
https://github.com/DaKerboul/perun.git
synced 2026-08-09 17:05:39 +02:00
renamed hook to pierog
This commit is contained in:
@@ -5,24 +5,29 @@ local config = {}
|
|||||||
-- Connection
|
-- Connection
|
||||||
config.host = "localhost" -- (string) [default: "localhost"] IP adress of the Perun instance or "localhost"
|
config.host = "localhost" -- (string) [default: "localhost"] IP adress of the Perun instance or "localhost"
|
||||||
config.port = 48621 -- (int) [default: 48621] TCP port to send data to
|
config.port = 48621 -- (int) [default: 48621] TCP port to send data to
|
||||||
|
config.delimiters = {"<SOT>", "<EOT>"}
|
||||||
config.Instance = 1 -- (int) [default: 1] Id number of instance (if multiple DCS instances run on the same machine)
|
config.Instance = 1 -- (int) [default: 1] Id number of instance (if multiple DCS instances run on the same machine)
|
||||||
config.keepAliveSeconds = 5 --
|
config.keepAliveSeconds = 5 --
|
||||||
config.refreshSlotsSeconds = 300 -- delay between slot updates are sent
|
config.logPath = "c:\\temp" -- path for communication logs
|
||||||
config.refreshMissionSeconds = 600 -- delay between mission update is sent
|
|
||||||
config.bigUpdatesSeconds = 100 -- big updates (mission, unit IDs, slots) have to wait between being sent
|
config.bigUpdatesSeconds = 100 -- big updates (mission, unit IDs, slots) have to wait between being sent
|
||||||
|
-- deprecated, decrease greatly
|
||||||
|
config.refreshSlotsSeconds = 300 -- delay between slot updates are sent
|
||||||
|
config.refreshMissionSeconds = 200 -- delay between mission update is sent
|
||||||
|
|
||||||
-- Localisation
|
-- Localisation
|
||||||
-- Server MOTD, sent to ALL players when entering cockpit
|
-- Server MOTD, sent to ALL players when entering cockpit
|
||||||
config.MOTD_line1 = "[Perun] Welcome to our server!";
|
config.MOTD_line1 = "[Pierog] Welcome to our server!";
|
||||||
config.MOTD_line2 = "[Perun] Stats and event data integrated with Perun for DCS World";
|
config.MOTD_line2 = "[Pierog] Stats and event data integrated with Pierog for DCS World";
|
||||||
-- (string) Information to send to players when Perun connection is broken
|
-- (string) Information to send to players when Perun connection is broken
|
||||||
config.ConnectionError = "[Perun] ERROR: Connection broken - contact server admin!"
|
config.ConnectionError = "[Pierog] ERROR: Connection broken - contact server admin!"
|
||||||
|
|
||||||
-- Misc
|
-- Misc
|
||||||
config.BroadcastPerunErrors = 1 -- (int) [0 (default),1] Value greater than 0 will broadcast chat message about missing connection to Perun
|
config.BroadcastPierogErrors = 1 -- (int) [0 (default),1] Value greater than 0 will broadcast chat message about missing connection to Perun
|
||||||
|
config.BroadcastErrorEachSeconds = 600
|
||||||
|
|
||||||
-- Debug
|
-- Debug
|
||||||
config.DebugMode = 1 -- (int) [0 (default),1,2] Value greater than 0 will display Perun information in DCS log file, values: 1 - minimal verbose, 2 - all log information will be logged
|
config.DebugMode = 2 -- (int) [0 (default),1,2] Value greater than 0 will display Perun information in DCS log file, values: 1 - minimal verbose, 2 - all log information will be logged
|
||||||
|
|
||||||
-- ###################### END OF SETTINGS - DO NOT MODIFY OUTSIDE THIS SECTION ######################
|
-- ###################### END OF SETTINGS - DO NOT MODIFY OUTSIDE THIS SECTION ######################
|
||||||
return config
|
return config
|
||||||
@@ -1,480 +0,0 @@
|
|||||||
-- Perun for DCS World https://github.com/szporwolik/perun -> DCS Hook component
|
|
||||||
net.log("[Perun] Loading Perun")
|
|
||||||
|
|
||||||
-- Initial init
|
|
||||||
local Perun = {}
|
|
||||||
|
|
||||||
-- Load Luas
|
|
||||||
package.path = package.path..";"..lfs.currentdir().."/LuaSocket/?.lua"..";"..lfs.writedir() .. "/Mods/services/Perun/lua/?.lua"
|
|
||||||
package.cpath = package.cpath..";"..lfs.currentdir().."/LuaSocket/?.dll"
|
|
||||||
|
|
||||||
-- Load Dlls
|
|
||||||
package.cpath = package.cpath..';'.. lfs.writedir()..'/Mods/services/Perun/bin/' ..'?.dll;'
|
|
||||||
net.log("[Perun]", "Loading DLL")
|
|
||||||
Perun.DLL = require('perun')
|
|
||||||
net.log("[Perun]", "Loaded DLL, starting")
|
|
||||||
Perun.DLL.StartOfApp();
|
|
||||||
net.log("[Perun]", "DLL started")
|
|
||||||
|
|
||||||
-- Load config file
|
|
||||||
net.log("[Perun]", "Loading config")
|
|
||||||
local config = require "perun_config"
|
|
||||||
net.log("[Perun]", "Config loaded")
|
|
||||||
|
|
||||||
Perun.host = config.host
|
|
||||||
Perun.port = config.port
|
|
||||||
Perun.Instance = config.Instance
|
|
||||||
Perun.DebugMode = config.DebugMode
|
|
||||||
|
|
||||||
Perun.MOTD_line1 = config.MOTD_line1
|
|
||||||
Perun.MOTD_line2 = config.MOTD_line2
|
|
||||||
Perun.ConnectionError = config.ConnectionError
|
|
||||||
Perun.BroadcastPerunErrors = config.BroadcastPerunErrors
|
|
||||||
|
|
||||||
Perun.keepAliveSeconds = config.keepAliveSeconds
|
|
||||||
Perun.bigUpdatesSeconds = config.bigUpdatesSeconds
|
|
||||||
Perun.refreshSlotsSeconds = config.refreshSlotsSeconds
|
|
||||||
Perun.refreshMissionSeconds = config.refreshMissionSeconds
|
|
||||||
|
|
||||||
Perun.Version = "v0.12.1"
|
|
||||||
|
|
||||||
Perun.MissionHash=""
|
|
||||||
|
|
||||||
Perun.lastSentStatus = 0
|
|
||||||
Perun.lastSentMission = 0
|
|
||||||
Perun.lastSentKeepAlive = 0
|
|
||||||
Perun.lastConnectionError = 0
|
|
||||||
Perun.lastFrameStart = 0;
|
|
||||||
Perun.lastTimer = 0
|
|
||||||
Perun.lastFrameTime = 0;
|
|
||||||
|
|
||||||
Perun.ReconnectTimeout = 30;
|
|
||||||
Perun.RefreshKeepAlive = 5
|
|
||||||
|
|
||||||
Perun.State = {}
|
|
||||||
Perun.State.connected = false;
|
|
||||||
Perun.State.slotsInitialised = false;
|
|
||||||
|
|
||||||
-- to avoid declaring every time a function is run
|
|
||||||
Perun.Globals = {}
|
|
||||||
Perun.Globals.Sides = {
|
|
||||||
[0] = 'SPECTATOR',
|
|
||||||
[1] = 'RED',
|
|
||||||
[2] = 'BLUE',
|
|
||||||
[3] = 'NEUTRAL', -- TBD check once this is released in DCS
|
|
||||||
}
|
|
||||||
|
|
||||||
Perun.Mission = {}
|
|
||||||
Perun.Mission.Slots = {}
|
|
||||||
Perun.Mission.Slots["blue"] = {}
|
|
||||||
Perun.Mission.Slots["red"] = {}
|
|
||||||
Perun.Mission.Players = {}
|
|
||||||
Perun.Mission.Units = {}
|
|
||||||
|
|
||||||
Perun.HandlerArgCounts = {}
|
|
||||||
|
|
||||||
Perun.HandlerArgCounts["self_kill"] = 1
|
|
||||||
Perun.HandlerArgCounts["crash"] = 2
|
|
||||||
Perun.HandlerArgCounts["eject"] = 2
|
|
||||||
Perun.HandlerArgCounts["connect"] = 2
|
|
||||||
Perun.HandlerArgCounts["mission_end"] = 2
|
|
||||||
Perun.HandlerArgCounts["pilot_death"] = 2
|
|
||||||
Perun.HandlerArgCounts["takeoff"] = 3
|
|
||||||
Perun.HandlerArgCounts["landing"] = 3
|
|
||||||
Perun.HandlerArgCounts["change_slot"] = 3
|
|
||||||
Perun.HandlerArgCounts["friendly_fire"] = 3
|
|
||||||
Perun.HandlerArgCounts["disconnect"] = 4
|
|
||||||
Perun.HandlerArgCounts["kill"] = 7
|
|
||||||
|
|
||||||
net.log("[Perun]", "Global variables initialised")
|
|
||||||
|
|
||||||
Perun.Stats = {}
|
|
||||||
Perun.Stats.LastSentTCP = 0
|
|
||||||
Perun.Stats.LastSentSlots = 0
|
|
||||||
Perun.Stats.LastBigUpdate = 0
|
|
||||||
Perun.Stats.LastSentMission = 0
|
|
||||||
Perun.Stats.PreviousFrameStart = 0
|
|
||||||
Perun.Stats.LastConnectionError = 0
|
|
||||||
|
|
||||||
Perun.func = {};
|
|
||||||
Perun.func.ensureSlots = function()
|
|
||||||
if(not Perun.State.slotsInitialised) then
|
|
||||||
net.log("Perun", "initialising slots")
|
|
||||||
|
|
||||||
local blue = DCS.getAvailableSlots("blue");
|
|
||||||
for k, unit in pairs(blue) do
|
|
||||||
Perun.Mission.Slots["blue"][unit["unitId"]] = unit
|
|
||||||
end
|
|
||||||
|
|
||||||
local red = DCS.getAvailableSlots("red");
|
|
||||||
for k, unit in pairs(red) do
|
|
||||||
Perun.Mission.Slots["red"][unit["unitId"]] = unit
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.State.slotsInitialised = true;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.func.ensureUnitId = function(unitId)
|
|
||||||
if(not Perun.Mission.Units[unitId]) then
|
|
||||||
local unitData = DCS.getUnitType(unitId)
|
|
||||||
Perun.Mission.Units[unitId] = unitData
|
|
||||||
local payload = {}
|
|
||||||
payload["unit"] = unitData
|
|
||||||
|
|
||||||
Perun.func.sendData(net.lua2json(unitData))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.func.sendData = function(payload)
|
|
||||||
|
|
||||||
local now = DCS.getRealTime()
|
|
||||||
|
|
||||||
local connected, reconnected = Perun.DLL.tcpSend(payload)
|
|
||||||
net.log("[Perun]", connected, reconnected)
|
|
||||||
if(connected < 1) and (now > Perun.Stats.LastConnectionError + Perun.ReconnectTimeout) then
|
|
||||||
Perun.AddLog("ERROR - TCP connection is not available",0)
|
|
||||||
|
|
||||||
if Perun.BroadcastPerunErrors > 0 then
|
|
||||||
local _all_players = net.get_player_list()
|
|
||||||
for i, playerId in ipairs(_all_players) do
|
|
||||||
net.send_chat_to(Perun.ConnectionError , playerId)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Stats.LastConnectionError = now
|
|
||||||
else
|
|
||||||
Perun.Stats.LastSentTCP = now
|
|
||||||
|
|
||||||
if(reconnected > 0) then
|
|
||||||
net.log("Perun", "TCP reconnected")
|
|
||||||
Perun.Stats.LastBigUpdate = 0
|
|
||||||
Perun.Stats.LastSentSlots = 0
|
|
||||||
Perun.Stats.LastSentMission = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers = {}
|
|
||||||
Perun.Handlers["event"] = function(eventName)
|
|
||||||
local data = {};
|
|
||||||
data["event"] = eventName;
|
|
||||||
data["hash"] = Perun.MissionHash
|
|
||||||
data['datetime']=os.date('%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers["friendly_fire"] = function(playerID, weaponName, victimPlayerID)
|
|
||||||
local data = Perun.Handlers["event"]("friendly_fire")
|
|
||||||
|
|
||||||
data["killer"] = playerID;
|
|
||||||
data["victim"] = victimPlayerID;
|
|
||||||
data["weapon"] = weaponName;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers["mission_end"] = function(winner, msg)
|
|
||||||
local data = Perun.Handlers["event"]("mission_end")
|
|
||||||
|
|
||||||
data["winner"] = winner;
|
|
||||||
data["message"] = msg;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers["kill"] = function(killerPlayerID, killerUnitType, killerSide, victimPlayerID, victimUnitType, victimSide, weaponName)
|
|
||||||
local data = Perun.Handlers["event"]("kill")
|
|
||||||
|
|
||||||
data["killer"] = {killerPlayerID, killerUnitType, killerSide}
|
|
||||||
data["victim"] = {victimPlayerID, victimUnitType, victimSide}
|
|
||||||
data["weapon"] = weaponName;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers["self_kill"] = function(playerID)
|
|
||||||
local data = Perun.Handlers["event"]("self_kill")
|
|
||||||
data["who"] = playerID;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers["change_slot"] = function(playerID, slotID, prevSide)
|
|
||||||
local details = net.get_player_info(playerID, "side")
|
|
||||||
Perun.Mission.Players[playerID]["side"] = details
|
|
||||||
|
|
||||||
local data = Perun.Handlers["event"]("change_slot")
|
|
||||||
data["previousSlot"] = slotID
|
|
||||||
data["previousSide"] = prevSide
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers["connect"] = function(playerID, name)
|
|
||||||
net.log("Perun", "Getting player details")
|
|
||||||
local details = net.get_player_info(playerID)
|
|
||||||
Perun.Mission.Players[playerID] = details
|
|
||||||
|
|
||||||
net.log("Perun", "Preparing event")
|
|
||||||
local data = Perun.Handlers["event"]("connect")
|
|
||||||
data["who"] = playerID
|
|
||||||
data["details"] = details;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Handlers["disconnect"] = function(playerID, name, playerSide, reason_code)
|
|
||||||
local data = Perun.Handlers["event"]("disconnect")
|
|
||||||
data["who"] = playerID;
|
|
||||||
data["details"] = {name, playerSide, reason_code}
|
|
||||||
|
|
||||||
Perun.Mission.Players[playerID] = nil
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
--"crash", playerID, unit_missionID
|
|
||||||
Perun.Handlers["crash"] = function(playerID, unit_missionID)
|
|
||||||
Perun.func.ensureUnitId(unit_missionID)
|
|
||||||
|
|
||||||
local data = Perun.Handlers["event"]("crash")
|
|
||||||
data["who"] = playerID;
|
|
||||||
data["unitId"] = unit_missionID;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
--"eject", playerID, unit_missionID
|
|
||||||
Perun.Handlers["eject"] = function(playerID, unit_missionID)
|
|
||||||
Perun.func.ensureUnitId(unit_missionID)
|
|
||||||
|
|
||||||
local data = Perun.Handlers["event"]("eject")
|
|
||||||
data["who"] = playerID;
|
|
||||||
data["unitId"] = unit_missionID;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
--"takeoff", playerID, unit_missionID, airdromeName
|
|
||||||
Perun.Handlers["takeoff"] = function(playerID, unit_missionID, airdromeName)
|
|
||||||
Perun.func.ensureUnitId(unit_missionID)
|
|
||||||
|
|
||||||
local data = Perun.Handlers["event"]("takeoff")
|
|
||||||
data["who"] = playerID;
|
|
||||||
data["unitId"] = unit_missionID;
|
|
||||||
data["from"] = airdromeName;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
--"landing", playerID, unit_missionID, airdromeName
|
|
||||||
Perun.Handlers["landing"] = function(playerID, unit_missionID, airdromeName)
|
|
||||||
Perun.func.ensureUnitId(unit_missionID)
|
|
||||||
|
|
||||||
local data = Perun.Handlers["event"]("landing")
|
|
||||||
data["who"] = playerID;
|
|
||||||
data["unitId"] = unit_missionID;
|
|
||||||
data["at"] = airdromeName;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
--"pilot_death", playerID, unit_missionID
|
|
||||||
Perun.Handlers["pilot_death"] = function(playerID, unit_missionID)
|
|
||||||
Perun.func.ensureUnitId(unit_missionID)
|
|
||||||
|
|
||||||
local data = Perun.Handlers["event"]("pilot_death")
|
|
||||||
data["who"] = playerID;
|
|
||||||
data["unitId"] = unit_missionID;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
end
|
|
||||||
|
|
||||||
net.log("[Perun] Handlers defined")
|
|
||||||
|
|
||||||
--- ################################ Helper function definitions ################################
|
|
||||||
|
|
||||||
Perun.AddLog = function(text, LogLevel)
|
|
||||||
-- Adds logs to DCS.log file
|
|
||||||
if Perun.DebugMode >= LogLevel then
|
|
||||||
net.log("[Perun]", text)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.generate_mission_hash = function()
|
|
||||||
-- Generates unique simulation mission hash
|
|
||||||
return DCS.getMissionName( ).."@".. Perun.Instance .. "@" .. Perun.Version .. "@".. os.date('%Y%m%d_%H%M%S');
|
|
||||||
end
|
|
||||||
|
|
||||||
--- ################################ TCP Connection ################################
|
|
||||||
|
|
||||||
Perun.ConnectToPerun = function ()
|
|
||||||
|
|
||||||
Perun.AddLog(string.format("Connecting to TCP server %s:%i", Perun.host, Perun.port), 0);
|
|
||||||
|
|
||||||
local status = Perun.DLL.tcpConnect(Perun.host, Perun.port);
|
|
||||||
|
|
||||||
if(status == 0) then
|
|
||||||
Perun.AddLog(string.format("Connection failed: %s:%i", Perun.host, Perun.port), 0);
|
|
||||||
else
|
|
||||||
Perun.State.connected = true;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- ################################ Log functions ################################
|
|
||||||
|
|
||||||
Perun.LogChat = function(playerID, msg, all)
|
|
||||||
|
|
||||||
local data = Perun.Handlers["event"]("chat");
|
|
||||||
|
|
||||||
data['player']= Perun.Mission.Players[playerID]
|
|
||||||
data['msg']=msg
|
|
||||||
data['messageToAll']=all
|
|
||||||
data['missionhash']=Perun.MissionHash
|
|
||||||
|
|
||||||
Perun.func.sendData(net.lua2json(data));
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.LogEvent = function(log_type, log_content, log_arg_1, log_arg_2)
|
|
||||||
-- Logs events messages
|
|
||||||
local data = Perun.Handlers["event"]("customLog");
|
|
||||||
data['log_type']= log_type
|
|
||||||
data['log_arg_1']= log_arg_1
|
|
||||||
data['log_arg_2']= log_arg_2
|
|
||||||
data['log_content']=log_content
|
|
||||||
data['log_missionhash']=Perun.MissionHash
|
|
||||||
|
|
||||||
Perun.AddLog("Sending event data, event: " .. log_type .. ", arg1:" .. log_arg_1 .. ", arg2:" .. log_arg_2 .. ", content: " .. log_content,1)
|
|
||||||
|
|
||||||
Perun.func.sendData(net.lua2json(data));
|
|
||||||
end
|
|
||||||
|
|
||||||
--- ################################ Event callbacks ################################
|
|
||||||
|
|
||||||
Perun.onSimulationStart = function()
|
|
||||||
-- Simulation was started
|
|
||||||
Perun.MissionHash=Perun.generate_mission_hash()
|
|
||||||
Perun.LogEvent("SimStart","Mission " .. Perun.MissionHash .. " started",nil,nil);
|
|
||||||
Perun.lastSentMission = 0 -- reset so mission information will be send
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.onSimulationStop = function()
|
|
||||||
-- Simulation was stopped
|
|
||||||
Perun.LogEvent("SimStop","Mission " .. Perun.MissionHash .. " finished",nil,nil);
|
|
||||||
Perun.MissionHash=Perun.generate_mission_hash();
|
|
||||||
|
|
||||||
Perun.Mission = {}
|
|
||||||
Perun.Mission.Slots = {}
|
|
||||||
Perun.Mission.Slots["blue"] = {}
|
|
||||||
Perun.Mission.Slots["red"] = {}
|
|
||||||
Perun.Mission.Players = {}
|
|
||||||
Perun.Mission.Units = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.onPlayerDisconnect = function(id, err_code)
|
|
||||||
-- Player disconnected
|
|
||||||
Perun.LogEvent("disconnect", "Player " .. id .. " disconnected.",nil,nil);
|
|
||||||
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.onPlayerStop = function (id)
|
|
||||||
-- Player left the simulation (happens right before a disconnect, if player exited by desire)
|
|
||||||
|
|
||||||
|
|
||||||
Perun.LogEvent("quit", "Player " .. id .. " quit the server.",nil,nil);
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.onSimulationFrame = function()
|
|
||||||
|
|
||||||
if(not Perun.State.slotsInitialised) then
|
|
||||||
local foo = Perun.func.ensureSlots;
|
|
||||||
|
|
||||||
local status, error = pcall(foo);
|
|
||||||
if(status) then
|
|
||||||
Perun.AddLog( "slot information loaded")
|
|
||||||
else
|
|
||||||
Perun.AddLog( "error getting slot information", error)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local now = DCS.getRealTime()
|
|
||||||
--net.log("Perun", "big updates check, now", now, "last sent slots", Perun.Stats.LastSentSlots, "last sent mission", Perun.Stats.LastSentMission)
|
|
||||||
|
|
||||||
if(now - Perun.Stats.LastBigUpdate > Perun.bigUpdatesSeconds) then
|
|
||||||
if(now > Perun.Stats.LastSentSlots + Perun.refreshSlotsSeconds) then
|
|
||||||
local payload = Perun.Handlers["event"]("slots")
|
|
||||||
payload["slots"] = Perun.Mission.Slots;
|
|
||||||
|
|
||||||
local json = net.lua2json(payload)
|
|
||||||
--net.log("Perun, slots", json)
|
|
||||||
Perun.func.sendData(json)
|
|
||||||
Perun.Stats.LastSentSlots = now
|
|
||||||
Perun.Stats.LastBigUpdate = now
|
|
||||||
elseif (now > Perun.Stats.LastSentMission + Perun.refreshMissionSeconds) then
|
|
||||||
local payload = Perun.Handlers["event"]("mission")
|
|
||||||
payload["mission"] = DCS.getCurrentMission()["mission"]
|
|
||||||
|
|
||||||
local json = net.lua2json(payload);
|
|
||||||
--net.log("Perun, mission", json)
|
|
||||||
Perun.func.sendData(json)
|
|
||||||
Perun.Stats.LastSentMission = now
|
|
||||||
Perun.Stats.LastBigUpdate = now
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if(now > Perun.LastSentTCP + Perun.RefreshKeepAlive) then
|
|
||||||
Perun.func.sendData(" ")
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.Stats.PreviousFrameStart = DCS.getRealTime()
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.onPlayerStart = function (playerId)
|
|
||||||
-- Player entered cocpit
|
|
||||||
|
|
||||||
net.send_chat_to(Perun.MOTD_line1, playerId);
|
|
||||||
net.send_chat_to(Perun.MOTD_line2, playerId);
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.onPlayerTrySendChat = function (playerID, msg, all)
|
|
||||||
-- Somebody tries to send chat message
|
|
||||||
if (msg == Perun.ConnectionError or msg == Perun.MOTD_line1 or msg == Perun.MOTD_line2) then
|
|
||||||
return msg;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.LogChat(playerID,msg,all)
|
|
||||||
return msg;
|
|
||||||
end
|
|
||||||
|
|
||||||
Perun.onGameEvent = function (eventName,arg1,arg2,arg3,arg4,arg5,arg6,arg7)
|
|
||||||
local argCount = Perun.HandlerArgCounts[eventName]
|
|
||||||
local handler = Perun.Handlers[eventName]
|
|
||||||
|
|
||||||
local payload = {}
|
|
||||||
if(argCount == 1) then
|
|
||||||
payload = handler(arg1)
|
|
||||||
elseif argCount == 2 then
|
|
||||||
payload = handler(arg1, arg2)
|
|
||||||
elseif argCount == 3 then
|
|
||||||
payload = handler(arg1, arg2, arg3)
|
|
||||||
elseif argCount == 4 then
|
|
||||||
payload = handler(arg1, arg2, arg3, arg4)
|
|
||||||
else
|
|
||||||
payload = handler(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
|
||||||
end
|
|
||||||
|
|
||||||
local json = net.lua2json(payload)
|
|
||||||
Perun.func.sendData(json)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ########### Finalize and set callbacks ###########
|
|
||||||
if DCS.isServer() then
|
|
||||||
-- If this game instance is hosting multiplayer game, start Perun
|
|
||||||
Perun.DLL.StartOfApp(); -- Perun dll StartOfApp callback
|
|
||||||
Perun.MissionHash=Perun.generate_mission_hash(); -- Generate initial missionhash
|
|
||||||
DCS.setUserCallbacks(Perun); -- Set user callbacs, map DCS event handlers with functions defined above
|
|
||||||
Perun.ConnectToPerun(); -- Connect to Perun server
|
|
||||||
Perun.AddLog("Loaded - Perun for DCS World - version: " .. Perun.Version,0) -- Display perun information in log
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
99
01_DCS/Scripts/Hooks/lifecycle.lua
Normal file
99
01_DCS/Scripts/Hooks/lifecycle.lua
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
local explorer = {}
|
||||||
|
|
||||||
|
|
||||||
|
explorer.onMissionLoadBegin = function()
|
||||||
|
net.log("[Explorer]", "on mission load begin");
|
||||||
|
end
|
||||||
|
explorer.onMissionLoadProgress = function(progress, message)
|
||||||
|
net.log("[Explorer]", "on mission load progress", progress, message);
|
||||||
|
end
|
||||||
|
explorer.onMissionLoadEnd = function()
|
||||||
|
net.log("[Explorer]", "on mission load end");
|
||||||
|
end
|
||||||
|
explorer.onSimulationStart = function()
|
||||||
|
net.log("[Explorer]", "on simulation start");
|
||||||
|
end
|
||||||
|
explorer.onSimulationStop = function()
|
||||||
|
net.log("[Explorer]", "on simulation stop");
|
||||||
|
end
|
||||||
|
explorer.onSimulationFrame = function() end
|
||||||
|
explorer.onSimulationPause= function()
|
||||||
|
net.log("[Explorer]", "on simulation pause");
|
||||||
|
end
|
||||||
|
explorer.onSimulationResume= function()
|
||||||
|
net.log("[Explorer]", "on simulation resume");
|
||||||
|
end
|
||||||
|
|
||||||
|
explorer.onNetConnect= function()
|
||||||
|
et.log("[Explorer]", "onNetConnect");
|
||||||
|
end
|
||||||
|
explorer.onNetMissionChanged= function()
|
||||||
|
net.log("[Explorer]", "onNetMissionChanged");
|
||||||
|
end
|
||||||
|
explorer.onNetConnect= function()
|
||||||
|
net.log("[Explorer]", "onNetConnect");
|
||||||
|
end
|
||||||
|
explorer.onNetDisconnect= function()
|
||||||
|
net.log("[Explorer]", "onNetDisconnect");
|
||||||
|
end
|
||||||
|
explorer.onPlayerConnect= function()
|
||||||
|
net.log("[Explorer]", "onPlayerConnect");
|
||||||
|
end
|
||||||
|
explorer.onPlayerDisconnect= function()
|
||||||
|
net.log("[Explorer]", "onPlayerDisconnect");
|
||||||
|
end
|
||||||
|
explorer.onPlayerStart= function()
|
||||||
|
net.log("[Explorer]", "onPlayerStart");
|
||||||
|
end
|
||||||
|
explorer.onPlayerStop= function()
|
||||||
|
net.log("[Explorer]", "onPlayerStop");
|
||||||
|
end
|
||||||
|
explorer.onPlayerChangeSlot= function()
|
||||||
|
net.log("[Explorer]", "onPlayerChangeSlot");
|
||||||
|
end
|
||||||
|
explorer.onPlayerTryConnect= function(address, name, ucid, id)
|
||||||
|
net.log("[Explorer]", "onPlayerTryConnect", address, name, ucid, id);
|
||||||
|
end
|
||||||
|
explorer.onPlayerTrySendChat= function()
|
||||||
|
net.log("[Explorer]", "onPlayerTrySendChat");
|
||||||
|
end
|
||||||
|
explorer.onPlayerTryChangeSlot= function()
|
||||||
|
net.log("[Explorer]", "onPlayerTryChangeSlot");
|
||||||
|
end
|
||||||
|
|
||||||
|
explorer.onGameEvent = function(eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||||
|
|
||||||
|
local payload = {}
|
||||||
|
if(argCount == 1) then
|
||||||
|
payload = handler(arg1);
|
||||||
|
elseif argCount == 2 then
|
||||||
|
payload = handler(arg1, arg2);
|
||||||
|
elseif argCount == 3 then
|
||||||
|
payload = handler(arg1, arg2, arg3);
|
||||||
|
elseif argCount == 4 then
|
||||||
|
payload = handler(arg1, arg2, arg3, arg4);
|
||||||
|
elseif argCount == 7 then
|
||||||
|
payload = handler(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||||
|
end
|
||||||
|
|
||||||
|
local json = net.lua2json(payload);
|
||||||
|
net.log("[Explorer]", json);
|
||||||
|
|
||||||
|
--net.log("[Pierog] json", json)
|
||||||
|
|
||||||
|
--net.log("[Pierog]", "get_player_list", net.lua2json(net.get_player_list()))
|
||||||
|
--net.log("[Pierog]", "mission_data", net.lua2json(DCS.getCurrentMission()))
|
||||||
|
|
||||||
|
--net.log("[Pierog]", "DCS.getAvailableCoalitions()", net.lua2json(DCS.getAvailableCoalitions()))
|
||||||
|
--net.log("[Pierog]", "DCS.getAvailableSlots(0)", DCS.getAvailableSlots(0))
|
||||||
|
--net.log("[Pierog]", "DCS.getAvailableSlots(3)", DCS.getAvailableSlots(3))
|
||||||
|
--net.log("[Pierog]", "DCS.getMissionName()", DCS.getMissionName())
|
||||||
|
--net.log("[Pierog]", "DCS.getModelTime()", DCS.getModelTime())
|
||||||
|
--net.log("[Pierog]", "DCS.getRealTime()", DCS.getRealTime())
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if DCS.isServer() then
|
||||||
|
net.log("[Explorer]", "Initialising API explorer");
|
||||||
|
DCS.setUserCallbacks(explorer);
|
||||||
|
end
|
||||||
530
01_DCS/Scripts/Hooks/pierog_light_hook.lua
Normal file
530
01_DCS/Scripts/Hooks/pierog_light_hook.lua
Normal file
@@ -0,0 +1,530 @@
|
|||||||
|
-- Pierog for DCS World, inspired by
|
||||||
|
-- https://github.com/szporwolik/perun -> DCS Hook component
|
||||||
|
net.log("[Pierog] Loading Pierog")
|
||||||
|
|
||||||
|
-- Initial init
|
||||||
|
local Pierog = {}
|
||||||
|
|
||||||
|
-- Load Luas
|
||||||
|
package.path = package.path..";"..lfs.currentdir().."/LuaSocket/?.lua"..";"..lfs.writedir() .. "/Mods/services/Pierog/lua/?.lua"
|
||||||
|
package.cpath = package.cpath..";"..lfs.currentdir().."/LuaSocket/?.dll"
|
||||||
|
|
||||||
|
-- Load Dlls
|
||||||
|
package.cpath = package.cpath..';'.. lfs.writedir()..'/Mods/services/Pierog/bin/' ..'?.dll;'
|
||||||
|
net.log("[Pierog]", "Loading DLL")
|
||||||
|
Pierog.DLL = require('pierog')
|
||||||
|
|
||||||
|
-- Load config file
|
||||||
|
net.log("[Pierog]", "Loading config")
|
||||||
|
local config = require "pierog_config"
|
||||||
|
|
||||||
|
Pierog.host = config.host;
|
||||||
|
Pierog.port = config.port;
|
||||||
|
Pierog.delimiters = config.delimiters;
|
||||||
|
Pierog.Instance = config.Instance;
|
||||||
|
Pierog.DebugMode = config.DebugMode;
|
||||||
|
Pierog.logPath = config.logPath;
|
||||||
|
|
||||||
|
Pierog.MOTD_line1 = config.MOTD_line1
|
||||||
|
Pierog.MOTD_line2 = config.MOTD_line2
|
||||||
|
Pierog.ConnectionError = config.ConnectionError
|
||||||
|
Pierog.BroadcastPierogErrors = config.BroadcastPierogErrors
|
||||||
|
Pierog.BroadcastErrorEachSeconds = config.BroadcastErrorEachSeconds or 600
|
||||||
|
|
||||||
|
Pierog.keepAliveSeconds = config.keepAliveSeconds
|
||||||
|
Pierog.bigUpdatesSeconds = config.bigUpdatesSeconds
|
||||||
|
Pierog.refreshSlotsSeconds = config.refreshSlotsSeconds
|
||||||
|
Pierog.refreshMissionSeconds = config.refreshMissionSeconds
|
||||||
|
|
||||||
|
net.log("[Pierog]", "Config loaded")
|
||||||
|
|
||||||
|
-- to avoid declaring every time a function is run
|
||||||
|
Pierog.Globals = {}
|
||||||
|
Pierog.Globals.version = "v0.12.1"
|
||||||
|
Pierog.Globals.Sides = {
|
||||||
|
[0] = 'SPECTATOR',
|
||||||
|
[1] = 'RED',
|
||||||
|
[2] = 'BLUE',
|
||||||
|
[3] = 'NEUTRAL', -- TBD check once this is released in DCS
|
||||||
|
}
|
||||||
|
|
||||||
|
net.log("[Pierog]", "Global variables initialised")
|
||||||
|
|
||||||
|
--net.log("[Pierog]", "Dupa")
|
||||||
|
|
||||||
|
Pierog.lastSentStatus = 0
|
||||||
|
Pierog.lastSentMission = 0
|
||||||
|
Pierog.lastSentKeepAlive = 0
|
||||||
|
Pierog.lastConnectionError = 0
|
||||||
|
Pierog.lastFrameStart = 0;
|
||||||
|
Pierog.lastTimer = 0
|
||||||
|
Pierog.lastFrameTime = 0;
|
||||||
|
|
||||||
|
Pierog.ReconnectTimeout = 30;
|
||||||
|
Pierog.RefreshKeepAlive = 5
|
||||||
|
|
||||||
|
--net.log("[Pierog]", "Dupa2")
|
||||||
|
|
||||||
|
Pierog.State = {}
|
||||||
|
Pierog.State.connected = false;
|
||||||
|
Pierog.State.slotsInitialised = false;
|
||||||
|
|
||||||
|
--net.log("[Pierog]", "Dupa3")
|
||||||
|
|
||||||
|
Pierog.Mission = {}
|
||||||
|
Pierog.Mission.Hash = {}
|
||||||
|
Pierog.Mission.Slots = {}
|
||||||
|
Pierog.Mission.Players = {}
|
||||||
|
Pierog.Mission.Units = {}
|
||||||
|
|
||||||
|
net.log("[Pierog]", "Initialising handlers")
|
||||||
|
|
||||||
|
Pierog.HandlerArgCounts = {}
|
||||||
|
|
||||||
|
Pierog.HandlerArgCounts["self_kill"] = 1
|
||||||
|
Pierog.HandlerArgCounts["crash"] = 2
|
||||||
|
Pierog.HandlerArgCounts["eject"] = 2
|
||||||
|
Pierog.HandlerArgCounts["connect"] = 2
|
||||||
|
Pierog.HandlerArgCounts["mission_end"] = 2
|
||||||
|
Pierog.HandlerArgCounts["pilot_death"] = 2
|
||||||
|
Pierog.HandlerArgCounts["takeoff"] = 3
|
||||||
|
Pierog.HandlerArgCounts["landing"] = 3
|
||||||
|
Pierog.HandlerArgCounts["change_slot"] = 3
|
||||||
|
Pierog.HandlerArgCounts["friendly_fire"] = 3
|
||||||
|
Pierog.HandlerArgCounts["disconnect"] = 4
|
||||||
|
Pierog.HandlerArgCounts["kill"] = 7
|
||||||
|
|
||||||
|
Pierog.Stats = {}
|
||||||
|
Pierog.Stats.LastSentTCP = 0
|
||||||
|
Pierog.Stats.LastSentSlots = 0
|
||||||
|
Pierog.Stats.LastBigUpdate = 0
|
||||||
|
Pierog.Stats.LastSentMission = 0
|
||||||
|
Pierog.Stats.LastConnectionError = 0
|
||||||
|
|
||||||
|
Pierog.func = {};
|
||||||
|
Pierog.func.ensureSlots = function()
|
||||||
|
if(not Pierog.State.slotsInitialised) then
|
||||||
|
|
||||||
|
local count = 0;
|
||||||
|
local coalitions = DCS.getAvailableCoalitions();
|
||||||
|
for name, _ in pairs(coalitions) do
|
||||||
|
local slots = DCS.getAvailableSlots(name);
|
||||||
|
Pierog.Mission.Slots[name] = {}
|
||||||
|
for k, unit in pairs(slots) do
|
||||||
|
Pierog.Mission.Slots[name][unit["unitId"]] = unit
|
||||||
|
count = count + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if(count > 0) then
|
||||||
|
net.log("[Pierog]", "initialised ".. count .. " slots")
|
||||||
|
Pierog.State.slotsInitialised = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.func.ensureUnitId = function(unitId)
|
||||||
|
if(not Pierog.Mission.Units[unitId]) then
|
||||||
|
local unitType = DCS.getUnitType(unitId);
|
||||||
|
Pierog.Mission.Units[unitId] = unitType;
|
||||||
|
|
||||||
|
net.log("[Pierog]", unitId, "category:", DCS.getUnitTypeAttribute(unitType, "category"));
|
||||||
|
net.log("[Pierog]", unitId, "category via type -> Prop:", DCS.getUnitProperty(unitType, DCS.UNIT_CATEGORY));
|
||||||
|
net.log("[Pierog]", unitId, "category via id -> Prop:", DCS.getUnitProperty(unitId, DCS.UNIT_CATEGORY));
|
||||||
|
net.log("[Pierog]", unitId, "wing span:", DCS.getUnitTypeAttribute(unitType, "WingSpan"));
|
||||||
|
net.log("[Pierog]", unitId, "deck level", DCS.getUnitTypeAttribute(unitType, "DeckLevel"));
|
||||||
|
--
|
||||||
|
local payload = Pierog.Handlers["event"]("unit_definition");
|
||||||
|
payload["unitId"] = unitId;
|
||||||
|
payload["unitType"] = unitType;
|
||||||
|
payload["unitCategory"] = DCS.getUnitTypeAttribute(unitId, "category");
|
||||||
|
payload["wingSpan"] = DCS.getUnitTypeAttribute(unitType, "WingSpan");
|
||||||
|
payload["deckLevel"] = DCS.getUnitTypeAttribute(unitType, "DeckLevel");
|
||||||
|
--
|
||||||
|
Pierog.func.sendData(net.lua2json(payload))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.func.sendData = function(payload)
|
||||||
|
|
||||||
|
local now = DCS.getRealTime()
|
||||||
|
|
||||||
|
local connected, reconnected = Pierog.DLL.tcpSend(payload)
|
||||||
|
--net.log("[Pierog]", connected, reconnected)
|
||||||
|
if(connected < 1) and (now > Pierog.Stats.LastConnectionError + Pierog.ReconnectTimeout) then
|
||||||
|
Pierog.AddLog("ERROR - TCP connection not available",0)
|
||||||
|
|
||||||
|
if Pierog.BroadcastPierogErrors > 0 then
|
||||||
|
local _all_players = net.get_player_list()
|
||||||
|
for i, playerId in ipairs(_all_players) do
|
||||||
|
net.send_chat_to(Pierog.ConnectionError , playerId)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Stats.LastConnectionError = now
|
||||||
|
else
|
||||||
|
Pierog.Stats.LastSentTCP = now
|
||||||
|
|
||||||
|
if(reconnected > 0) then
|
||||||
|
net.log("[Pierog]", "TCP reconnected")
|
||||||
|
Pierog.Stats.LastBigUpdate = 0
|
||||||
|
Pierog.Stats.LastSentSlots = 0
|
||||||
|
Pierog.Stats.LastSentMission = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.func.sendMissionUpdate = function()
|
||||||
|
local payload = Pierog.Handlers["event"]("mission")
|
||||||
|
payload["mission"] = DCS.getCurrentMission()["mission"]
|
||||||
|
payload["missionName"] = DCS.getCurrentMission()
|
||||||
|
|
||||||
|
local json = net.lua2json(payload);
|
||||||
|
Pierog.func.sendData(json)
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.func.sendSlotUpdate = function()
|
||||||
|
local payload = Pierog.Handlers["event"]("slots")
|
||||||
|
payload["slots"] = Pierog.Mission.Slots;
|
||||||
|
|
||||||
|
local json = net.lua2json(payload)
|
||||||
|
Pierog.func.sendData(json)
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers = {}
|
||||||
|
Pierog.Handlers["event"] = function(eventName)
|
||||||
|
local data = {};
|
||||||
|
data["event"] = eventName;
|
||||||
|
data["missionHash"] = Pierog.Mission.Hash
|
||||||
|
data['datetime']=os.date('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers["friendly_fire"] = function(playerID, weaponName, victimPlayerID)
|
||||||
|
local data = Pierog.Handlers["event"]("friendly_fire")
|
||||||
|
|
||||||
|
data["killer"] = playerID;
|
||||||
|
data["victim"] = victimPlayerID;
|
||||||
|
data["weapon"] = weaponName;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers["mission_end"] = function(winner, msg)
|
||||||
|
local data = Pierog.Handlers["event"]("mission_end")
|
||||||
|
|
||||||
|
data["winner"] = winner;
|
||||||
|
data["message"] = msg;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers["kill"] = function(killerPlayerID, killerUnitType, killerSide, victimPlayerID, victimUnitType, victimSide, weaponName)
|
||||||
|
local data = Pierog.Handlers["event"]("kill")
|
||||||
|
|
||||||
|
data["killer"] = {id = killerPlayerID, side = killerSide, type = killerUnitType, ucid = net.get_player_info(killerPlayerID)["ucid"]}
|
||||||
|
data["victim"] = {id = victimPlayerID, side = victimSide, type = victimUnitType, ucid = net.get_player_info(victimPlayerID)["ucid"]}
|
||||||
|
data["weapon"] = weaponName;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers["self_kill"] = function(playerID)
|
||||||
|
local data = Pierog.Handlers["event"]("self_kill")
|
||||||
|
data["who"] = playerID;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers["change_slot"] = function(playerID, slotID, prevSide)
|
||||||
|
local newDetails = net.get_player_info(playerID);
|
||||||
|
local oldDetails = Pierog.Mission.Players[playerID];
|
||||||
|
|
||||||
|
Pierog.Mission.Players[playerID] = newDetails;
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("change_slot")
|
||||||
|
data["previousSlot"] = oldDetails["slot"]
|
||||||
|
data["previousSide"] = oldDetails["side"]
|
||||||
|
data["side"] = newDetails["side"]
|
||||||
|
data["slot"] = newDetails["slot"]
|
||||||
|
data["ucid"] = newDetails["ucid"]
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers["connect"] = function(playerID, name)
|
||||||
|
net.log("[Pierog]", "Getting player details")
|
||||||
|
local details = net.get_player_info(playerID)
|
||||||
|
Pierog.Mission.Players[playerID] = details
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("connect")
|
||||||
|
data["who"] = playerID
|
||||||
|
data["details"] = details;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.Handlers["disconnect"] = function(playerID, name, playerSide, reason_code)
|
||||||
|
local data = Pierog.Handlers["event"]("disconnect")
|
||||||
|
data["who"] = Pierog.Mission.Players[playerID]
|
||||||
|
data["reasonCode"] = reason_code;
|
||||||
|
|
||||||
|
Pierog.Mission.Players[playerID] = nil
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
--"crash", playerID, unit_missionID
|
||||||
|
Pierog.Handlers["crash"] = function(playerID, unit_missionID)
|
||||||
|
Pierog.func.ensureUnitId(unit_missionID)
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("crash")
|
||||||
|
data["who"] = playerID;
|
||||||
|
data["unitId"] = unit_missionID;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
--"eject", playerID, unit_missionID
|
||||||
|
Pierog.Handlers["eject"] = function(playerID, unit_missionID)
|
||||||
|
Pierog.func.ensureUnitId(unit_missionID)
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("eject")
|
||||||
|
data["who"] = playerID;
|
||||||
|
data["unitId"] = unit_missionID;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
--"takeoff", playerID, unit_missionID, airdromeName
|
||||||
|
Pierog.Handlers["takeoff"] = function(playerID, unit_missionID, airdromeName)
|
||||||
|
Pierog.func.ensureUnitId(unit_missionID)
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("takeoff")
|
||||||
|
data["who"] = playerID;
|
||||||
|
data["unitId"] = unit_missionID;
|
||||||
|
data["from"] = airdromeName;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
--"landing", playerID, unit_missionID, airdromeName
|
||||||
|
Pierog.Handlers["landing"] = function(playerID, unit_missionID, airdromeName)
|
||||||
|
Pierog.func.ensureUnitId(unit_missionID)
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("landing")
|
||||||
|
data["who"] = playerID;
|
||||||
|
data["unitId"] = unit_missionID;
|
||||||
|
data["at"] = airdromeName;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
--"pilot_death", playerID, unit_missionID
|
||||||
|
Pierog.Handlers["pilot_death"] = function(playerID, unit_missionID)
|
||||||
|
Pierog.func.ensureUnitId(unit_missionID)
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("pilot_death")
|
||||||
|
data["who"] = playerID;
|
||||||
|
data["unitId"] = unit_missionID;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
end
|
||||||
|
|
||||||
|
net.log("[Pierog] Handlers defined")
|
||||||
|
|
||||||
|
--- ################################ Helper function definitions ################################
|
||||||
|
|
||||||
|
Pierog.AddLog = function(text, logLevel)
|
||||||
|
-- Adds logs to DCS.log file
|
||||||
|
if(logLevel == nil) then
|
||||||
|
logLevel = -1
|
||||||
|
end
|
||||||
|
|
||||||
|
if Pierog.DebugMode >= logLevel then
|
||||||
|
net.log("[Pierog]", text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.generate_mission_hash = function()
|
||||||
|
-- Generates unique simulation mission hash
|
||||||
|
return DCS.getMissionName( ).."@".. Pierog.Instance .. "@" .. Pierog.Globals.version .. "@".. os.date('%Y%m%d_%H%M%S');
|
||||||
|
end
|
||||||
|
|
||||||
|
--- ################################ Log functions ################################
|
||||||
|
|
||||||
|
Pierog.LogChat = function(playerID, msg, all)
|
||||||
|
|
||||||
|
local data = Pierog.Handlers["event"]("chat");
|
||||||
|
|
||||||
|
data['who']= Pierog.Mission.Players[playerID]["ucid"]
|
||||||
|
data['msg']=msg
|
||||||
|
data['messageToAll']=all
|
||||||
|
data['missionhash']=Pierog.Mission.Hash
|
||||||
|
|
||||||
|
Pierog.func.sendData(net.lua2json(data));
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.LogEvent = function(log_type, log_content, log_arg_1, log_arg_2)
|
||||||
|
-- Logs events messages
|
||||||
|
local data = Pierog.Handlers["event"]("customLog");
|
||||||
|
data['log_type']= log_type
|
||||||
|
data['log_arg_1']= log_arg_1
|
||||||
|
data['log_arg_2']= log_arg_2
|
||||||
|
data['log_content']=log_content
|
||||||
|
data['log_missionhash']=Pierog.Mission.Hash
|
||||||
|
|
||||||
|
Pierog.AddLog("Sending event data, event: " .. log_type .. ", arg1:" .. log_arg_1 .. ", arg2:" .. log_arg_2 .. ", content: " .. log_content,1)
|
||||||
|
|
||||||
|
Pierog.func.sendData(net.lua2json(data));
|
||||||
|
end
|
||||||
|
|
||||||
|
--- ################################ Event callbacks ################################
|
||||||
|
|
||||||
|
Pierog.onSimulationStart = function()
|
||||||
|
Pierog.Mission.Hash=Pierog.generate_mission_hash()
|
||||||
|
Pierog.LogEvent("SimStart","Mission " .. Pierog.Mission.Hash .. " started",nil,nil);
|
||||||
|
Pierog.lastSentMission = 0 -- reset so mission information will be sent
|
||||||
|
Pierog.State.slotsInitialised = false;
|
||||||
|
|
||||||
|
Pierog.DLL.markMissionStart(Pierog.Mission.Hash);
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onSimulationStop = function()
|
||||||
|
Pierog.LogEvent("SimStop","Mission " .. Pierog.Mission.Hash .. " finished",nil,nil);
|
||||||
|
|
||||||
|
Pierog.Mission = {}
|
||||||
|
Pierog.Mission.Hash=Pierog.generate_mission_hash();
|
||||||
|
Pierog.Mission.Slots = {}
|
||||||
|
Pierog.Mission.Players = {}
|
||||||
|
Pierog.Mission.Units = {}
|
||||||
|
|
||||||
|
Pierog.Stats.LastSentSlots = 0
|
||||||
|
Pierog.Stats.LastBigUpdate = 0
|
||||||
|
Pierog.Stats.LastSentMission = 0
|
||||||
|
Pierog.DLL.markMissionStart(Pierog.Mission.Hash);
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onPlayerStop = function (id)
|
||||||
|
-- Player left the simulation (happens right before a disconnect, if player exited by desire)
|
||||||
|
|
||||||
|
Pierog.LogEvent("quit", "Player " .. id .. " quit the server.",nil,nil);
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onSimulationFrame = function()
|
||||||
|
|
||||||
|
if(DCS.getMissionName() == "") then
|
||||||
|
-- no mission loaded
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local now = DCS.getRealTime()
|
||||||
|
|
||||||
|
if(Pierog.Stats.LastBigUpdate < 1 or now > Pierog.Stats.LastBigUpdate + Pierog.bigUpdatesSeconds) then
|
||||||
|
--net.log("[Pierog]", "Big update evaluation at", now, ", Pierog.Stats.LastSentSlots", Pierog.Stats.LastSentSlots, ", Pierog.Stats.LastBigUpdate", Pierog.Stats.LastBigUpdate)
|
||||||
|
--net.log("[Pierog]", "Pierog.refreshSlotsSeconds: ".. Pierog.refreshSlotsSeconds)
|
||||||
|
--net.log("[Pierog]", "name: >"..DCS.getMissionName().."<");
|
||||||
|
--net.log("[Pierog]", "mission"..net.lua2json(DCS.getCurrentMission()))
|
||||||
|
|
||||||
|
if(not Pierog.State.slotsInitialised) then
|
||||||
|
local foo = Pierog.func.ensureSlots;
|
||||||
|
|
||||||
|
local status, error = pcall(foo);
|
||||||
|
if(error) then
|
||||||
|
Pierog.AddLog( "error getting slot information" .. error);
|
||||||
|
else
|
||||||
|
Pierog.func.sendSlotUpdate();
|
||||||
|
Pierog.Stats.LastSentSlots = now;
|
||||||
|
Pierog.Stats.LastBigUpdate = now;
|
||||||
|
end
|
||||||
|
elseif(now > Pierog.Stats.LastSentSlots + Pierog.refreshSlotsSeconds) then
|
||||||
|
--net.log("[Pierog]", "Slots")
|
||||||
|
|
||||||
|
Pierog.func.sendSlotUpdate();
|
||||||
|
Pierog.Stats.LastSentSlots = now;
|
||||||
|
Pierog.Stats.LastBigUpdate = now;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (now > Pierog.Stats.LastSentMission) then
|
||||||
|
--net.log("[Pierog]", "Mission")
|
||||||
|
|
||||||
|
Pierog.func.sendMissionUpdate()
|
||||||
|
Pierog.Stats.LastSentMission = now
|
||||||
|
Pierog.Stats.LastBigUpdate = now
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if(now > Pierog.LastSentTCP + Pierog.RefreshKeepAlive) then
|
||||||
|
Pierog.func.sendData(" ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onPlayerStart = function (playerId)
|
||||||
|
-- Player entered cocpit
|
||||||
|
net.send_chat_to(Pierog.MOTD_line1, playerId);
|
||||||
|
net.send_chat_to(Pierog.MOTD_line2, playerId);
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onPlayerTrySendChat = function (playerID, msg, all)
|
||||||
|
-- Somebody tries to send chat message
|
||||||
|
if (msg == Pierog.ConnectionError or msg == Pierog.MOTD_line1 or msg == Pierog.MOTD_line2) then
|
||||||
|
return msg;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.LogChat(playerID, msg, all)
|
||||||
|
return msg;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onGameEvent = function(eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||||
|
local argCount = Pierog.HandlerArgCounts[eventName]
|
||||||
|
local handler = Pierog.Handlers[eventName]
|
||||||
|
|
||||||
|
if(Pierog.Handlers[eventName] == nil) then
|
||||||
|
-- no handler found
|
||||||
|
net.log("[Pierog]", 'Event type not found'..eventName)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local payload = {}
|
||||||
|
if(argCount == 1) then
|
||||||
|
payload = handler(arg1)
|
||||||
|
elseif argCount == 2 then
|
||||||
|
payload = handler(arg1, arg2)
|
||||||
|
elseif argCount == 3 then
|
||||||
|
payload = handler(arg1, arg2, arg3)
|
||||||
|
elseif argCount == 4 then
|
||||||
|
payload = handler(arg1, arg2, arg3, arg4)
|
||||||
|
elseif argCount == 7 then
|
||||||
|
payload = handler(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||||
|
end
|
||||||
|
|
||||||
|
local json = net.lua2json(payload)
|
||||||
|
Pierog.func.sendData(json)
|
||||||
|
|
||||||
|
if(eventName == "mission_end") then
|
||||||
|
Pierog.DLL.markMissionStart(Pierog.Mission.Hash);
|
||||||
|
end
|
||||||
|
|
||||||
|
--net.log("[Pierog] json", json)
|
||||||
|
|
||||||
|
--net.log("[Pierog]", "get_player_list", net.lua2json(net.get_player_list()))
|
||||||
|
--net.log("[Pierog]", "mission_data", net.lua2json(DCS.getCurrentMission()))
|
||||||
|
|
||||||
|
--net.log("[Pierog]", "DCS.getAvailableCoalitions()", net.lua2json(DCS.getAvailableCoalitions()))
|
||||||
|
--net.log("[Pierog]", "DCS.getAvailableSlots(0)", DCS.getAvailableSlots(0))
|
||||||
|
--net.log("[Pierog]", "DCS.getAvailableSlots(3)", DCS.getAvailableSlots(3))
|
||||||
|
--net.log("[Pierog]", "DCS.getMissionName()", DCS.getMissionName())
|
||||||
|
--net.log("[Pierog]", "DCS.getModelTime()", DCS.getModelTime())
|
||||||
|
--net.log("[Pierog]", "DCS.getRealTime()", DCS.getRealTime())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ########### Finalize and set callbacks ###########
|
||||||
|
if DCS.isServer() then
|
||||||
|
-- If this game instance is hosting multiplayer game, start Pierog
|
||||||
|
net.log("[Pierog]", "In a server, setting DLL", Pierog.logPath, Pierog.host, Pierog.port)
|
||||||
|
Pierog.DLL.delimiters(Pierog.delimiters[1], Pierog.delimiters[2])
|
||||||
|
Pierog.DLL.StartOfApp(Pierog.logPath, Pierog.host, Pierog.port);
|
||||||
|
net.log("[Pierog]", "DLL started")
|
||||||
|
Pierog.Mission.Hash=Pierog.generate_mission_hash(); -- Generate initial missionhash
|
||||||
|
DCS.setUserCallbacks(Pierog); -- Set user callbacs, map DCS event handlers with functions defined above
|
||||||
|
Pierog.AddLog("Loaded - Pierog for DCS World - version: " .. Pierog.Globals.version,0) -- Display Pierog information in log
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
55
01_DCS/Scripts/notes.md
Normal file
55
01_DCS/Scripts/notes.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|call |return | meaning |
|
||||||
|
|-------- |---- |---- |
|
||||||
|
|`DCS.getAvailableSlots("blue")`|TBD|slots available for a side|
|
||||||
|
|`net.get_player_list()`|[1, 2]|players in the mission. As in, occupied player slots in the server|
|
||||||
|
|||
|
||||||
|
|||
|
||||||
|
|`DCS.getRealTime()` | `37.5899104` | seconds.micros after mission was started |
|
||||||
|
|`DCS.getModelTime()`|`37.413`|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Callbacks:
|
||||||
|
|
||||||
|
|callback|event||
|
||||||
|
|----|----|----|
|
||||||
|
|onMissionLoadBegin|||
|
||||||
|
|onMissionLoadProgress|||
|
||||||
|
|onMissionLoadEnd, |||
|
||||||
|
|onSimulationStart, |||
|
||||||
|
|onSimulationStop, |||
|
||||||
|
|onSimulationFrame, |||
|
||||||
|
|onSimulationPause, |||
|
||||||
|
|onSimulationResume, |||
|
||||||
|
|onGameEvent, |||
|
||||||
|
|onNetConnect, |||
|
||||||
|
|onNetMissionChanged,|||
|
||||||
|
|onNetConnect, |||
|
||||||
|
|onNetDisconnect, |||
|
||||||
|
|onPlayerTryConnect, |||
|
||||||
|
|onPlayerConnect, |_connect||
|
||||||
|
|onPlayerDisconnect, |disconnect||
|
||||||
|
|onPlayerStart, |||
|
||||||
|
|onPlayerStop, |||
|
||||||
|
|onPlayerTrySendChat, |||
|
||||||
|
|onPlayerTryChangeSlot|||
|
||||||
|
|onPlayerChangeSlot,|change_slot||
|
||||||
|
|
||||||
|
|
||||||
|
# Q's:
|
||||||
|
Is unit ID tracking needed?
|
||||||
|
|
||||||
|
# ToDos:
|
||||||
|
* file per mission hash
|
||||||
|
* start of mission cpp callback?
|
||||||
|
* hash as argument
|
||||||
|
* end as callback
|
||||||
|
* investigate DCS namespace (for pairs?)
|
||||||
|
|
||||||
|
* file creation and writing to file should only happen when there is something to be written
|
||||||
|
|
||||||
|
* mission update should happen every X seconds, only
|
||||||
|
* connection should only affect message to players, nothing else!
|
||||||
|
* detect monotonic time flow - back in time? new mission.
|
||||||
38
01_DCS/dcs_engine_events.puml
Normal file
38
01_DCS/dcs_engine_events.puml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
@startuml
|
||||||
|
'https://plantuml.com/sequence-diagram
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
participant UI
|
||||||
|
participant Server
|
||||||
|
participant Mission
|
||||||
|
participant Simulation
|
||||||
|
participant Paused
|
||||||
|
participant Active
|
||||||
|
|
||||||
|
UI -> Server: onNetMissionChange
|
||||||
|
note left: start server
|
||||||
|
Server -> Mission: onMissionLoadBegin
|
||||||
|
Server -> Mission: onMissionLoadEnd
|
||||||
|
|
||||||
|
Mission -> Paused: onSimulationStart
|
||||||
|
note right: if starting configured, will unpause automatically
|
||||||
|
Paused -> Active: onSimulationResume
|
||||||
|
|
||||||
|
|
||||||
|
Active -> Paused: onSimulationPaused
|
||||||
|
note left: when paused in the UI
|
||||||
|
Paused -> Active: onSimulationResume
|
||||||
|
note right: when simulation is unpaused
|
||||||
|
|
||||||
|
Simulation -> Mission: onSimulationStop
|
||||||
|
note right: when simulation is stopped
|
||||||
|
|
||||||
|
|
||||||
|
UI -> Server: onNetMissionChange
|
||||||
|
note left: change mission
|
||||||
|
Server -> Mission: onMissionLoadBegin
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "DataDistributor.h"
|
#include "DataDistributor.h"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
DataDistributor::DataDistributor(std::string logPath,
|
DataDistributor::DataDistributor(std::string logPath,
|
||||||
std::string host,
|
std::string host,
|
||||||
@@ -18,22 +19,24 @@ void DataDistributor::start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::thread thread_object([this]() {
|
std::thread thread_object([this]() {
|
||||||
bool anythingToSend = true;
|
|
||||||
long KEEP_ALIVE = 1000;
|
long KEEP_ALIVE = 1000;
|
||||||
auto now = std::chrono::system_clock::now();
|
bool nothingToSend = false;
|
||||||
|
|
||||||
while(shouldRun) {
|
while(shouldRun) {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
|
||||||
if(lock.try_lock()) {
|
if(lock.try_lock()) {
|
||||||
if(sendQueue.empty()) {
|
if(sendQueue.empty()) {
|
||||||
auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastSent);
|
auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastSent);
|
||||||
if(delay.count() > KEEP_ALIVE) {
|
if(delay.count() > KEEP_ALIVE) {
|
||||||
sendQueue.push_front(new std::string(" "));
|
sendQueue.push_front(new std::string(" "));
|
||||||
} else {
|
} else {
|
||||||
anythingToSend = false;
|
nothingToSend = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto payload = sendQueue.front();
|
auto payload = sendQueue.front();
|
||||||
int sent = socketOutput->write(payload);
|
int sent = socketOutput->write(payload);
|
||||||
|
lastSent = std::chrono::system_clock::now();
|
||||||
|
|
||||||
if(sent > 0) {
|
if(sent > 0) {
|
||||||
everSentViaSocket = true;
|
everSentViaSocket = true;
|
||||||
@@ -45,7 +48,6 @@ void DataDistributor::start() {
|
|||||||
sendQueue.push_front(&shortened);
|
sendQueue.push_front(&shortened);
|
||||||
delete payload;
|
delete payload;
|
||||||
}
|
}
|
||||||
lastSent = std::chrono::system_clock::now();
|
|
||||||
} else {
|
} else {
|
||||||
// failed to send
|
// failed to send
|
||||||
}
|
}
|
||||||
@@ -54,9 +56,7 @@ void DataDistributor::start() {
|
|||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(anythingToSend) {
|
if(nothingToSend) {
|
||||||
Sleep(10);
|
|
||||||
} else {
|
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,6 @@ int SocketOutput::write(std::string *payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int bytesSent = send(tcpSocket, payload->c_str(), payload->length(), 0);
|
int bytesSent = send(tcpSocket, payload->c_str(), payload->length(), 0);
|
||||||
if(bytesSent == payload->length()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bytesSent > 0) {
|
if(bytesSent > 0) {
|
||||||
return bytesSent;
|
return bytesSent;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
38
03_Perun_Lua_Wrapper/pierog/src/SocketOutput.h
Normal file
38
03_Perun_Lua_Wrapper/pierog/src/SocketOutput.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef PARENT_SOCKETOUTPUT_H
|
||||||
|
#define PARENT_SOCKETOUTPUT_H
|
||||||
|
|
||||||
|
#include "winsock.h"
|
||||||
|
#include <string>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
enum enumConnectionState {
|
||||||
|
DISCONNECTED,
|
||||||
|
CONNECTED,
|
||||||
|
NEVER_CONNECTED
|
||||||
|
};
|
||||||
|
|
||||||
|
class SocketOutput {
|
||||||
|
public:
|
||||||
|
SocketOutput(std::string host,
|
||||||
|
int port);
|
||||||
|
virtual ~SocketOutput();
|
||||||
|
|
||||||
|
int write(std::string* payload);
|
||||||
|
|
||||||
|
bool isConnected();
|
||||||
|
private:
|
||||||
|
SOCKET tcpSocket = INVALID_SOCKET;
|
||||||
|
SOCKADDR_IN* address = nullptr;
|
||||||
|
|
||||||
|
const std::string tcpHost = "localhost";
|
||||||
|
const int tcpPort = 0;
|
||||||
|
|
||||||
|
volatile enumConnectionState connectionState = NEVER_CONNECTED;
|
||||||
|
|
||||||
|
bool _connect();
|
||||||
|
// void reconnect();
|
||||||
|
void disconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PARENT_SOCKETOUTPUT_H
|
||||||
Reference in New Issue
Block a user