mirror of
https://github.com/DaKerboul/perun.git
synced 2026-08-09 21:15:39 +02:00
Compare commits
10 Commits
v0.12.0
...
event_rewo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d02b6d4e78 | ||
|
|
1bc0f142bd | ||
|
|
545298f26d | ||
|
|
0a0da5b5a9 | ||
|
|
957dc393bd | ||
|
|
b87276cfe3 | ||
|
|
f46ffd9385 | ||
|
|
7697e30fb3 | ||
|
|
3ec0e7bd15 | ||
|
|
727b026207 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -261,4 +261,6 @@ __pycache__/
|
|||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
# cmake folders
|
# cmake folders
|
||||||
cmake-build-debug
|
cmake-build-debug
|
||||||
|
cmake-build-release
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
-- Perun for DCS World https://github.com/szporwolik/perun -> DCS Hook config component
|
|
||||||
local PerunConfig = {}
|
|
||||||
|
|
||||||
-- ###################### SETTINGS - DO NOT MODIFY OUTSIDE THIS SECTION #############################
|
|
||||||
-- Connection
|
|
||||||
PerunConfig.TCPPerunHost = "localhost" -- (string) [default: "localhost"] IP adress of the Perun instance or "localhost"
|
|
||||||
PerunConfig.TCPTargetPort = 48621 -- (int) [default: 48621] TCP port to send data to
|
|
||||||
PerunConfig.Instance = 1 -- (int) [default: 1] Id number of instance (if multiple DCS instances are to run at the same PC)
|
|
||||||
PerunConfig.RefreshStatus = 60 -- (int) [default: 60] Base refresh rate in seconds to send status update
|
|
||||||
|
|
||||||
-- Mission Configuration
|
|
||||||
PerunConfig.MissionStartNoDeathWindow = 300 -- (int) [default: 300] Number of secounds after mission start when death of the pilot will not go to statistics, shall avoid death penalty during spawning DCS bugs
|
|
||||||
|
|
||||||
-- Localisation
|
|
||||||
PerunConfig.MOTD_L1 = "[Perun] Welcome to our server !" -- (string) Message send to players connecting the server - Line 1
|
|
||||||
PerunConfig.MOTD_L2 = "[Perun] Stats and event data integrated with Perun for DCS World" -- (string) Message send to players connecting the server - Line 2
|
|
||||||
PerunConfig.ConnectionError_L1 = "[Perun] ERROR: Connection broken - contact server admin!" -- (string) Information to send to players when Perun connection is broken
|
|
||||||
|
|
||||||
-- Misc
|
|
||||||
PerunConfig.BroadcastPerunErrors = 1 -- (int) [0 (default),1] Value greater than 0 will broadcast chat message about missing connection to Perun
|
|
||||||
|
|
||||||
-- Debug
|
|
||||||
PerunConfig.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
|
|
||||||
|
|
||||||
-- ###################### END OF SETTINGS - DO NOT MODIFY OUTSIDE THIS SECTION ######################
|
|
||||||
return PerunConfig
|
|
||||||
33
01_DCS/Mods/services/Perun/lua/pierog_config.lua
Normal file
33
01_DCS/Mods/services/Perun/lua/pierog_config.lua
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
-- Perun for DCS World https://github.com/szporwolik/perun -> DCS Hook config component
|
||||||
|
local config = {}
|
||||||
|
|
||||||
|
-- ###################### SETTINGS - DO NOT MODIFY OUTSIDE THIS SECTION #############################
|
||||||
|
-- Connection
|
||||||
|
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.delimiters = {"<SOT>", "<EOT>"}
|
||||||
|
config.Instance = 1 -- (int) [default: 1] Id number of instance (if multiple DCS instances run on the same machine)
|
||||||
|
config.keepAliveSeconds = 5 --
|
||||||
|
config.logPath = "c:\\temp" -- path for communication logs
|
||||||
|
|
||||||
|
config.bigUpdatesSeconds = 100 -- big updates (mission, unit IDs, slots) have to wait between being sent
|
||||||
|
-- deprecated, decrease greatly
|
||||||
|
config.refreshSlotsSeconds = 1200 -- delay between slot updates are sent
|
||||||
|
config.refreshMissionSeconds = 1200 -- delay between mission update is sent
|
||||||
|
|
||||||
|
-- Localisation
|
||||||
|
-- Server MOTD, sent to ALL players when entering cockpit
|
||||||
|
config.MOTD_line1 = "[Pierog] Welcome to our server!";
|
||||||
|
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
|
||||||
|
config.ConnectionError = "[Pierog] ERROR: Connection broken - contact server admin!"
|
||||||
|
|
||||||
|
-- Misc
|
||||||
|
config.BroadcastPierogErrors = 1 -- (int) [0 (default),1] Value greater than 0 will broadcast chat message about missing connection to Perun
|
||||||
|
config.BroadcastErrorEachSeconds = 600
|
||||||
|
|
||||||
|
-- Debug
|
||||||
|
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 ######################
|
||||||
|
return config
|
||||||
@@ -13,20 +13,21 @@ package.cpath = package.cpath..';'.. lfs.writedir()..'/Mods/services/Perun/bin/'
|
|||||||
Perun.DLL = require('perun')
|
Perun.DLL = require('perun')
|
||||||
|
|
||||||
-- Load config file
|
-- Load config file
|
||||||
local PerunConfig = require "perun_config"
|
local config = require "perun_config"
|
||||||
Perun.RefreshStatus = PerunConfig.RefreshStatus
|
|
||||||
Perun.TCPTargetPort = PerunConfig.TCPTargetPort
|
Perun.RefreshStatus = config.RefreshStatus
|
||||||
Perun.TCPPerunHost = PerunConfig.TCPPerunHost
|
Perun.TCPTargetPort = config.port
|
||||||
Perun.Instance = PerunConfig.Instance
|
Perun.TCPPerunHost = config.host
|
||||||
Perun.MissionStartNoDeathWindow = PerunConfig.MissionStartNoDeathWindow
|
Perun.Instance = config.Instance
|
||||||
Perun.DebugMode = PerunConfig.DebugMode
|
Perun.MissionStartNoDeathWindow = config.MissionStartNoDeathWindow
|
||||||
Perun.MOTD_L1 = PerunConfig.MOTD_L1
|
Perun.DebugMode = config.DebugMode
|
||||||
Perun.MOTD_L2 = PerunConfig.MOTD_L2
|
Perun.MOTD_L1 = config.MOTD_L1
|
||||||
Perun.ConnectionError = PerunConfig.ConnectionError_L1
|
Perun.MOTD_L2 = config.MOTD_L2
|
||||||
Perun.BroadcastPerunErrors = PerunConfig.BroadcastPerunErrors
|
Perun.ConnectionError = config.ConnectionError_L1
|
||||||
|
Perun.BroadcastPerunErrors = config.BroadcastPerunErrors
|
||||||
|
|
||||||
-- Variable init
|
-- Variable init
|
||||||
Perun.Version = "v0.12.0"
|
Perun.Version = "v0.12.1"
|
||||||
|
|
||||||
Perun.StatusData = {}
|
Perun.StatusData = {}
|
||||||
Perun.SlotsData = {}
|
Perun.SlotsData = {}
|
||||||
@@ -47,6 +48,23 @@ Perun.lastFrameTime = 0;
|
|||||||
Perun.ReconnectTimeout = 30;
|
Perun.ReconnectTimeout = 30;
|
||||||
Perun.RefreshKeepAlive = 3
|
Perun.RefreshKeepAlive = 3
|
||||||
|
|
||||||
|
Perun.State = {}
|
||||||
|
Perun.State.connected = 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.Coalitions = {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- ################################ Helper function definitions ################################
|
-- ################################ Helper function definitions ################################
|
||||||
Perun.GetCategory = function(id)
|
Perun.GetCategory = function(id)
|
||||||
-- Helper function returns object category basing on https://pastebin.com/GUAXrd2U
|
-- Helper function returns object category basing on https://pastebin.com/GUAXrd2U
|
||||||
@@ -75,14 +93,8 @@ end
|
|||||||
|
|
||||||
Perun.SideID2Name = function(id)
|
Perun.SideID2Name = function(id)
|
||||||
-- Helper function returns side name per side (coalition) id
|
-- Helper function returns side name per side (coalition) id
|
||||||
local _sides = {
|
|
||||||
[0] = 'SPECTATOR',
|
|
||||||
[1] = 'RED',
|
|
||||||
[2] = 'BLUE',
|
|
||||||
[3] = 'NEUTRAL', -- TBD check once this is released in DCS
|
|
||||||
}
|
|
||||||
if id > 0 and id <= 3 then
|
if id > 0 and id <= 3 then
|
||||||
return _sides[id]
|
return Perun.Globals.Sides[id]
|
||||||
else
|
else
|
||||||
return "?"
|
return "?"
|
||||||
end
|
end
|
||||||
@@ -91,11 +103,11 @@ end
|
|||||||
Perun.AddLog = function(text,LogLevel)
|
Perun.AddLog = function(text,LogLevel)
|
||||||
-- Adds logs to DCS.log file
|
-- Adds logs to DCS.log file
|
||||||
if Perun.DebugMode >= LogLevel then
|
if Perun.DebugMode >= LogLevel then
|
||||||
net.log("[Perun] ".. text)
|
net.log("[Perun] ", text)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Perun.GenerateMissionHash = function()
|
Perun.generate_mission_hash = function()
|
||||||
-- Generates unique simulation mission hash
|
-- Generates unique simulation mission hash
|
||||||
return DCS.getMissionName( ).."@".. Perun.Instance .. "@" .. Perun.Version .. "@".. os.date('%Y%m%d_%H%M%S')
|
return DCS.getMissionName( ).."@".. Perun.Instance .. "@" .. Perun.Version .. "@".. os.date('%Y%m%d_%H%M%S')
|
||||||
end
|
end
|
||||||
@@ -239,6 +251,7 @@ Perun.ConnectToPerun = function ()
|
|||||||
Perun.DLL.tcpConnect(Perun.TCPPerunHost, Perun.TCPTargetPort)
|
Perun.DLL.tcpConnect(Perun.TCPPerunHost, Perun.TCPTargetPort)
|
||||||
|
|
||||||
Perun.AddLog(string.format("Connecting to TCP server %s:%i", Perun.TCPPerunHost, Perun.TCPTargetPort), 2)
|
Perun.AddLog(string.format("Connecting to TCP server %s:%i", Perun.TCPPerunHost, Perun.TCPTargetPort), 2)
|
||||||
|
Perun.State.connected = true;
|
||||||
end
|
end
|
||||||
|
|
||||||
Perun.SendToPerun = function(data_id, data_package)
|
Perun.SendToPerun = function(data_id, data_package)
|
||||||
@@ -253,7 +266,7 @@ Perun.SendToPerun = function(data_id, data_package)
|
|||||||
_payload = net.lua2json(data_package);
|
_payload = net.lua2json(data_package);
|
||||||
end
|
end
|
||||||
|
|
||||||
local _TempData={"<SOT>","{\"dcs_current_frame_delay\":",((DCS.getRealTime() - Perun.lastFrameStart) * 1000000),",\"type\":",data_id,",\"dcs_frame_time\":",(Perun.lastFrameTime * 1000000),",\"instance\":",(Perun.Instance),",\"timestamp\":\"",(os.date('%Y-%m-%d %H:%M:%S')),"\",\"payload\":",(_payload),"}<EOT>"}
|
local _TempData={"<SOT>","{\"dcs_current_frame_delay\":",((DCS.getRealTime() - Perun.lastFrameStart) * 1000),",\"type\":",data_id,",\"dcs_frame_time\":",(Perun.lastFrameTime * 1000),",\"instance\":",(Perun.Instance),",\"timestamp\":\"",(os.date('%Y-%m-%d %H:%M:%S')),"\",\"payload\":",(_payload),"}<EOT>"}
|
||||||
local _tcpMessage= table.concat( _TempData )
|
local _tcpMessage= table.concat( _TempData )
|
||||||
|
|
||||||
-- TCP Part - sending
|
-- TCP Part - sending
|
||||||
@@ -620,7 +633,7 @@ end
|
|||||||
|
|
||||||
Perun.onSimulationStart = function()
|
Perun.onSimulationStart = function()
|
||||||
-- Simulation was started
|
-- Simulation was started
|
||||||
Perun.MissionHash=Perun.GenerateMissionHash()
|
Perun.MissionHash=Perun.generate_mission_hash()
|
||||||
Perun.LogEvent("SimStart","Mission " .. Perun.MissionHash .. " started",nil,nil);
|
Perun.LogEvent("SimStart","Mission " .. Perun.MissionHash .. " started",nil,nil);
|
||||||
Perun.StatData = {}
|
Perun.StatData = {}
|
||||||
Perun.StatDataLastType = {}
|
Perun.StatDataLastType = {}
|
||||||
@@ -634,7 +647,7 @@ Perun.onSimulationStop = function()
|
|||||||
-- Simulation was stopped
|
-- Simulation was stopped
|
||||||
Perun.LogEvent("SimStop","Mission " .. Perun.MissionHash .. " finished",nil,nil);
|
Perun.LogEvent("SimStop","Mission " .. Perun.MissionHash .. " finished",nil,nil);
|
||||||
Perun.LogAllStats()
|
Perun.LogAllStats()
|
||||||
Perun.MissionHash=Perun.GenerateMissionHash();
|
Perun.MissionHash=Perun.generate_mission_hash();
|
||||||
Perun.StatData = {}
|
Perun.StatData = {}
|
||||||
Perun.MissionData = {}
|
Perun.MissionData = {}
|
||||||
Perun.StatDataLastType = {}
|
Perun.StatDataLastType = {}
|
||||||
@@ -716,6 +729,24 @@ end
|
|||||||
Perun.onGameEvent = function (eventName,arg1,arg2,arg3,arg4,arg5,arg6,arg7)
|
Perun.onGameEvent = function (eventName,arg1,arg2,arg3,arg4,arg5,arg6,arg7)
|
||||||
-- Game event has occured
|
-- Game event has occured
|
||||||
local _now = DCS.getRealTime()
|
local _now = DCS.getRealTime()
|
||||||
|
|
||||||
|
local _payload = net.lua2json({eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7})
|
||||||
|
Perun.DLL.tcpSend("<SOT>" .. _payload .. "<EOT>")
|
||||||
|
|
||||||
|
for i, value in pairs({ "red", "blue" }) do
|
||||||
|
-- table { type, unit_missionID }
|
||||||
|
local slots = DCS.getAvailableSlots(value)
|
||||||
|
for slot in slots do
|
||||||
|
local idx = slot[1];
|
||||||
|
Perun.Mission.Coalitions[value][idx] = {}
|
||||||
|
Perun.Mission.Coalitions[value][idx]["type"] = slot[2];
|
||||||
|
Perun.DLL.tcpSend("<SOT>" .. net.lua2json(DCS.getUnitType(idx)) .. "<EOT>")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local _payload = net.lua2json(Perun.Mission.Coalitions)
|
||||||
|
Perun.DLL.tcpSend("<SOT> SLOTS " .. _payload .. "<EOT>")
|
||||||
|
|
||||||
Perun.AddLog("Event handler for ".. eventName .. " started",2)
|
Perun.AddLog("Event handler for ".. eventName .. " started",2)
|
||||||
|
|
||||||
if eventName == "friendly_fire" then
|
if eventName == "friendly_fire" then
|
||||||
@@ -873,7 +904,7 @@ end
|
|||||||
if DCS.isServer() then
|
if DCS.isServer() then
|
||||||
-- If this game instance is hosting multiplayer game, start Perun
|
-- If this game instance is hosting multiplayer game, start Perun
|
||||||
Perun.DLL.StartOfApp() -- Start the main Perun dll
|
Perun.DLL.StartOfApp() -- Start the main Perun dll
|
||||||
Perun.MissionHash=Perun.GenerateMissionHash() -- Generate initial missionhash
|
Perun.MissionHash=Perun.generate_mission_hash() -- Generate initial missionhash
|
||||||
DCS.setUserCallbacks(Perun) -- Set user callbacs, map DCS event handlers with functions defined above
|
DCS.setUserCallbacks(Perun) -- Set user callbacs, map DCS event handlers with functions defined above
|
||||||
Perun.AddLog("Loaded - Perun for DCS World - version: " .. Perun.Version,0) -- Display perun information in log
|
Perun.AddLog("Loaded - Perun for DCS World - version: " .. Perun.Version,0) -- Display perun information in log
|
||||||
Perun.ConnectToPerun() -- Connect to Perun server
|
Perun.ConnectToPerun() -- Connect to Perun server
|
||||||
|
|||||||
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
|
||||||
497
01_DCS/Scripts/Hooks/pierog_light_hook.lua
Normal file
497
01_DCS/Scripts/Hooks/pierog_light_hook.lua
Normal file
@@ -0,0 +1,497 @@
|
|||||||
|
-- Pierog for DCS World (evolution of Perun, name needs deconfliction for parallel runs)
|
||||||
|
-- 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")
|
||||||
|
|
||||||
|
Pierog.Globals = {}
|
||||||
|
Pierog.Globals.version = "v0.21.12"
|
||||||
|
|
||||||
|
net.log("[Pierog]", "Global variables initialised")
|
||||||
|
|
||||||
|
Pierog.ReconnectTimeout = 30;
|
||||||
|
Pierog.RefreshKeepAlive = 5
|
||||||
|
|
||||||
|
Pierog.State = {}
|
||||||
|
Pierog.State.connected = false;
|
||||||
|
|
||||||
|
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.LastConnectionError = 0
|
||||||
|
|
||||||
|
Pierog.func = {};
|
||||||
|
|
||||||
|
Pierog.func.initialiseMissionData = function()
|
||||||
|
Pierog.Mission = {}
|
||||||
|
Pierog.Mission.Hash= {}
|
||||||
|
Pierog.Mission.Slots = {}
|
||||||
|
Pierog.Mission.Players = {}
|
||||||
|
Pierog.Mission.Units = {}
|
||||||
|
Pierog.Mission.slotsInitialised = false;
|
||||||
|
Pierog.Mission.lastSent = 0;
|
||||||
|
|
||||||
|
Pierog.Mission.LastSentMission = 0;
|
||||||
|
Pierog.Mission.LastSentSlots = 0;
|
||||||
|
Pierog.Mission.LastBigUpdate = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.func.ensureSlots = function()
|
||||||
|
if(not Pierog.Mission.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.Mission.slotsInitialised = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.func.ensureUnitId = function(unitId)
|
||||||
|
net.log("[Pierog]", "Ensuring unit id: ", 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 = Pierog.DLL.tcpSend(payload);
|
||||||
|
net.log("[Pierog]", "Sending", payload)
|
||||||
|
|
||||||
|
if(connected < 1) and (now > Pierog.Stats.LastConnectionError + Pierog.ReconnectTimeout) then
|
||||||
|
Pierog.Stats.LastConnectionError = now;
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.func.sendMissionUpdate = function()
|
||||||
|
local payload = Pierog.Handlers["event"]("mission")
|
||||||
|
payload["mission"] = DCS.getCurrentMission()["mission"]
|
||||||
|
payload["missionName"] = DCS.getMissionName()
|
||||||
|
|
||||||
|
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_arg1, log_arg2)
|
||||||
|
-- Logs events messages
|
||||||
|
local data = Pierog.Handlers["event"]("customLog");
|
||||||
|
data['log_type']= log_type
|
||||||
|
data['log_arg_1']= log_arg1
|
||||||
|
data['log_arg_2']= log_arg2
|
||||||
|
data['log_content']=log_content
|
||||||
|
data['log_missionhash']=Pierog.Mission.Hash
|
||||||
|
|
||||||
|
Pierog.func.sendData(net.lua2json(data));
|
||||||
|
|
||||||
|
Pierog.AddLog("Sending event data, event: " .. log_type .. ", arg1:" .. log_arg1 .. ", arg2:" .. log_arg2 .. ", content: " .. log_content,1)
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onMissionLoadEnd = function()
|
||||||
|
Pierog.func.initialiseMissionData();
|
||||||
|
Pierog.Mission.Hash=Pierog.generate_mission_hash();
|
||||||
|
Pierog.DLL.markMissionStart(Pierog.Mission.Hash);
|
||||||
|
|
||||||
|
net.log("[Pierog]", "Mission loaded", Pierog.Mission.Hash);
|
||||||
|
end
|
||||||
|
|
||||||
|
--- ################################ Event callbacks ################################
|
||||||
|
|
||||||
|
Pierog.onSimulationStart = function()
|
||||||
|
Pierog.func.initialiseMissionData();
|
||||||
|
Pierog.Mission.Hash=Pierog.generate_mission_hash();
|
||||||
|
Pierog.DLL.markMissionStart(Pierog.Mission.Hash);
|
||||||
|
|
||||||
|
net.log("[Pierog]", "markMissionStart", Pierog.Mission.Hash);
|
||||||
|
|
||||||
|
Pierog.LogEvent("SimStart","Mission " .. Pierog.Mission.Hash .. " started",nil,nil);
|
||||||
|
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.Mission.LastBigUpdate < 1 or now > Pierog.Mission.LastBigUpdate + Pierog.bigUpdatesSeconds) then
|
||||||
|
--net.log("[Pierog]", "Big update evaluation at", now, ", Pierog.Mission.LastSentSlots", Pierog.Mission.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.Mission.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.Mission.LastSentSlots = now;
|
||||||
|
Pierog.Mission.LastBigUpdate = now;
|
||||||
|
end
|
||||||
|
elseif(now > Pierog.Mission.LastSentSlots + Pierog.refreshSlotsSeconds) then
|
||||||
|
--net.log("[Pierog]", "Slots")
|
||||||
|
|
||||||
|
Pierog.func.sendSlotUpdate();
|
||||||
|
Pierog.Mission.LastSentSlots = now;
|
||||||
|
Pierog.Mission.LastBigUpdate = now;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (now > Pierog.Mission.LastSentMission) then
|
||||||
|
--net.log("[Pierog]", "Mission")
|
||||||
|
|
||||||
|
Pierog.func.sendMissionUpdate()
|
||||||
|
Pierog.Mission.LastSentMission = now
|
||||||
|
Pierog.Mission.LastBigUpdate = now
|
||||||
|
end
|
||||||
|
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.onPlayerTryConnect= function(address, name, ucid, id)
|
||||||
|
net.log("[Pierog]", "onPlayerTryConnect", address, name, ucid, id);
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
|
||||||
|
Pierog.onGameEvent = function(eventName, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
||||||
|
local argCount = Pierog.HandlerArgCounts[eventName];
|
||||||
|
local handler = Pierog.Handlers[eventName];
|
||||||
|
|
||||||
|
--net.log("[Pierog]", 'Event', 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)
|
||||||
|
|
||||||
|
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")
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
@@ -31,8 +31,8 @@
|
|||||||
<PublisherName>szporwolik</PublisherName>
|
<PublisherName>szporwolik</PublisherName>
|
||||||
<SuiteName>Perun</SuiteName>
|
<SuiteName>Perun</SuiteName>
|
||||||
<WebPage>Perun.htm</WebPage>
|
<WebPage>Perun.htm</WebPage>
|
||||||
<ApplicationRevision>1</ApplicationRevision>
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
<ApplicationVersion>0.12.0.%2a</ApplicationVersion>
|
<ApplicationVersion>0.12.1.%2a</ApplicationVersion>
|
||||||
<UseApplicationTrust>false</UseApplicationTrust>
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
<CreateDesktopShortcut>true</CreateDesktopShortcut>
|
<CreateDesktopShortcut>true</CreateDesktopShortcut>
|
||||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ using System.Runtime.InteropServices;
|
|||||||
// Możesz określić wszystkie wartości lub użyć domyślnych numerów kompilacji i poprawki
|
// Możesz określić wszystkie wartości lub użyć domyślnych numerów kompilacji i poprawki
|
||||||
// przy użyciu symbolu „*”, tak jak pokazano poniżej:
|
// przy użyciu symbolu „*”, tak jak pokazano poniżej:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.12.0.0")]
|
[assembly: AssemblyVersion("0.12.1.0")]
|
||||||
[assembly: AssemblyFileVersion("0.12.0.0")]
|
[assembly: AssemblyFileVersion("0.12.1.0")]
|
||||||
[assembly: NeutralResourcesLanguage("en")]
|
[assembly: NeutralResourcesLanguage("en")]
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
# CMakeList.txt : CMake project for perun_dll, include source and define
|
# CMakeList.txt : CMake project for perun_dll, include source and define
|
||||||
# project specific logic here.
|
# project specific logic here.
|
||||||
#
|
#
|
||||||
cmake_minimum_required (VERSION 3.8)
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
|
||||||
project ("parent")
|
project ("parent")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.12.25835)
|
||||||
|
set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std:c++latest")
|
||||||
|
set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std:c++latest")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(lua-5.1.5)
|
add_subdirectory(lua-5.1.5)
|
||||||
add_subdirectory(perun)
|
add_subdirectory(pierog)
|
||||||
|
add_subdirectory(experimental)
|
||||||
21
03_Perun_Lua_Wrapper/experimental/CMakeLists.txt
Normal file
21
03_Perun_Lua_Wrapper/experimental/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
project(experimental)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
set (EXPERIMENTAL_SOURCES
|
||||||
|
"src/main.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(experimental ${EXPERIMENTAL_SOURCES})
|
||||||
|
|
||||||
|
include_directories(${pierog_SOURCE_DIR})
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
experimental
|
||||||
|
ws2_32
|
||||||
|
pierog
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories (pierog PUBLIC pierog)
|
||||||
|
#set_target_properties(main PROPERTIES OUTPUT_NAME "pierog")
|
||||||
@@ -28,7 +28,7 @@ set (LUA_RUNTIME_SOURCES
|
|||||||
"src/lua.h"
|
"src/lua.h"
|
||||||
"src/lualib.h"
|
"src/lualib.h"
|
||||||
"src/lzio.c" "src/lzio.h"
|
"src/lzio.c" "src/lzio.h"
|
||||||
)
|
../experimental/src/main.cpp)
|
||||||
|
|
||||||
|
|
||||||
add_library( lua-5.1.5 ${LUA_RUNTIME_SOURCES} )
|
add_library( lua-5.1.5 ${LUA_RUNTIME_SOURCES} )
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ void luaK_nil (FuncState *fs, int from, int n) {
|
|||||||
if (GET_OPCODE(*previous) == OP_LOADNIL) {
|
if (GET_OPCODE(*previous) == OP_LOADNIL) {
|
||||||
int pfrom = GETARG_A(*previous);
|
int pfrom = GETARG_A(*previous);
|
||||||
int pto = GETARG_B(*previous);
|
int pto = GETARG_B(*previous);
|
||||||
if (pfrom <= from && from <= pto+1) { /* can connect both? */
|
if (pfrom <= from && from <= pto+1) { /* can _connect both? */
|
||||||
if (from+n-1 > pto)
|
if (from+n-1 > pto)
|
||||||
SETARG_B(*previous, from+n-1);
|
SETARG_B(*previous, from+n-1);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
|
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
|
||||||
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua"
|
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua"
|
||||||
#define LUA_CPATH_DEFAULT \
|
#define LUA_CPATH_DEFAULT \
|
||||||
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
|
".\\?.bin;" LUA_CDIR"?.bin;" LUA_CDIR"loadall.bin"
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define LUA_ROOT "/usr/local/"
|
#define LUA_ROOT "/usr/local/"
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.17)
|
|
||||||
project(perun)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
|
||||||
|
|
||||||
set (PERUN_DLL_SOURCES
|
|
||||||
"src/library.h"
|
|
||||||
"src/library.cpp"
|
|
||||||
"src/Connection.h"
|
|
||||||
"src/Connecton.cpp"
|
|
||||||
)
|
|
||||||
|
|
||||||
include (GenerateExportHeader)
|
|
||||||
add_library(perun SHARED ${PERUN_DLL_SOURCES})
|
|
||||||
|
|
||||||
target_link_libraries(
|
|
||||||
perun
|
|
||||||
lua-5.1.5
|
|
||||||
ws2_32
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories (perun PUBLIC)
|
|
||||||
#set_target_properties(main PROPERTIES OUTPUT_NAME "perun")
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#ifndef PERUN_CONNECTION_H
|
|
||||||
#define PERUN_CONNECTION_H
|
|
||||||
|
|
||||||
#include "winsock.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <queue>
|
|
||||||
#include <mutex>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include "library.h"
|
|
||||||
|
|
||||||
enum enumConnectionState {
|
|
||||||
DISCONNECTED,
|
|
||||||
CONNECTED,
|
|
||||||
};
|
|
||||||
|
|
||||||
class SocketWrapper {
|
|
||||||
public:
|
|
||||||
SocketWrapper();
|
|
||||||
~SocketWrapper();
|
|
||||||
|
|
||||||
void disconnect();
|
|
||||||
void createConnection(std::string* host, const int* port);
|
|
||||||
void enqueueForSending(std::string* payload);
|
|
||||||
|
|
||||||
int getAndResetReconnected();
|
|
||||||
int getFlagConnected();
|
|
||||||
|
|
||||||
private:
|
|
||||||
SOCKET tcpSocket;
|
|
||||||
std::string* tcpHost;
|
|
||||||
int tcpPort;
|
|
||||||
|
|
||||||
int flagReconnected = 0;
|
|
||||||
volatile enumConnectionState connectionState = DISCONNECTED;
|
|
||||||
|
|
||||||
std::queue<std::string*> dataBuffer;
|
|
||||||
std::deque<std::string*> sendQueue;
|
|
||||||
|
|
||||||
std::mutex mutexLock;
|
|
||||||
|
|
||||||
void reconnect();
|
|
||||||
void tcpConnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
#include "Connection.h"
|
|
||||||
|
|
||||||
SocketWrapper::SocketWrapper() {
|
|
||||||
tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketWrapper::~SocketWrapper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
int SocketWrapper::getAndResetReconnected() {
|
|
||||||
int result = this->flagReconnected;
|
|
||||||
|
|
||||||
this->flagReconnected = 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SocketWrapper::getFlagConnected() {
|
|
||||||
return this->connectionState;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketWrapper::tcpConnect() {
|
|
||||||
// Create socket address object from TCP port and host
|
|
||||||
SOCKADDR_IN socketAddress;
|
|
||||||
socketAddress.sin_family = AF_INET;
|
|
||||||
socketAddress.sin_port = htons(u_short(this->tcpPort));
|
|
||||||
socketAddress.sin_addr.s_addr = *((unsigned long*)gethostbyname(this->tcpHost->c_str())->h_addr);
|
|
||||||
|
|
||||||
if (connect(tcpSocket, (sockaddr*)&socketAddress, sizeof(SOCKADDR_IN)) == 0) {
|
|
||||||
this->connectionState = CONNECTED;
|
|
||||||
this->flagReconnected = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketWrapper::createConnection(std::string* host, const int* port) {
|
|
||||||
// TCP connection - ConnectTo
|
|
||||||
this->tcpHost = host;
|
|
||||||
this->tcpPort = *port;
|
|
||||||
|
|
||||||
tcpConnect();
|
|
||||||
|
|
||||||
// Create new thread
|
|
||||||
std::thread thread_object([this]() {
|
|
||||||
// TCP sending loop
|
|
||||||
bool nothingToSend = false;
|
|
||||||
while (true) {
|
|
||||||
// Endless loop (will run after main dll thread is active)
|
|
||||||
if (connectionState == CONNECTED && mutexLock.try_lock()) {
|
|
||||||
if (sendQueue.empty()) {
|
|
||||||
nothingToSend = true;
|
|
||||||
} else {
|
|
||||||
// Payload in queue
|
|
||||||
auto payload = sendQueue.front();
|
|
||||||
int length = payload->length();
|
|
||||||
int bytesSent = send(tcpSocket, payload->c_str(), payload->length(), 0);
|
|
||||||
|
|
||||||
if (bytesSent == payload->length()) {
|
|
||||||
// All payload was sent
|
|
||||||
sendQueue.pop_front();
|
|
||||||
delete payload;
|
|
||||||
} else {
|
|
||||||
// Remaining paylad
|
|
||||||
if (bytesSent > 0) {
|
|
||||||
// Send remaining bytes
|
|
||||||
auto shortened = payload->substr(bytesSent, length - bytesSent);
|
|
||||||
sendQueue.pop_front();
|
|
||||||
sendQueue.push_front(&shortened);
|
|
||||||
delete payload;
|
|
||||||
} else {
|
|
||||||
// Payload was not sent - handle error
|
|
||||||
switch (WSAGetLastError()) {
|
|
||||||
// Connection was reset
|
|
||||||
case WSAECONNRESET:
|
|
||||||
// Connection aborted
|
|
||||||
case WSAECONNABORTED:
|
|
||||||
// Connection was closed
|
|
||||||
case WSAESHUTDOWN:
|
|
||||||
connectionState = DISCONNECTED;
|
|
||||||
reconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutexLock.unlock();
|
|
||||||
} else {
|
|
||||||
// Not connected
|
|
||||||
reconnect();
|
|
||||||
}
|
|
||||||
// sleep longer if nothing to send
|
|
||||||
if (nothingToSend) { Sleep(100); } else { Sleep(10); }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread_object.detach(); // Detach TCP thread from main thread
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketWrapper::reconnect() {
|
|
||||||
if (connectionState == DISCONNECTED) {
|
|
||||||
disconnect();
|
|
||||||
tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Reset socket
|
|
||||||
}
|
|
||||||
|
|
||||||
tcpConnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketWrapper::disconnect() {
|
|
||||||
// TCP connection - Disconnect
|
|
||||||
closesocket(tcpSocket);
|
|
||||||
connectionState = DISCONNECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketWrapper::enqueueForSending(std::string* payload) {
|
|
||||||
if (mutexLock.try_lock()) {
|
|
||||||
while (!dataBuffer.empty()) {
|
|
||||||
// Shift buffer to queue
|
|
||||||
sendQueue.push_back(dataBuffer.front());
|
|
||||||
dataBuffer.pop();
|
|
||||||
}
|
|
||||||
sendQueue.push_back(payload);
|
|
||||||
mutexLock.unlock();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dataBuffer.push(payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#include "library.h"
|
|
||||||
|
|
||||||
static SocketWrapper tcpConnection;
|
|
||||||
|
|
||||||
static int appStartHook(lua_State* luaState) {
|
|
||||||
// Starting the app - prepare
|
|
||||||
|
|
||||||
lua_pushinteger(luaState, 1); // First return value: confirmation that app was started
|
|
||||||
|
|
||||||
return (1); // Set return to number of arguments returned
|
|
||||||
}
|
|
||||||
|
|
||||||
static int appEndHook(lua_State* luaState) {
|
|
||||||
// Closing the app - clean up
|
|
||||||
|
|
||||||
tcpConnection.disconnect();
|
|
||||||
|
|
||||||
return (0); // No return values
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tcpConnect(lua_State* luaState) {
|
|
||||||
// Connect to the TCP socket
|
|
||||||
|
|
||||||
auto *host = new std::string(lua_tolstring(luaState, 1, 0));
|
|
||||||
const int *port = new int(lua_tointeger(luaState, 2));
|
|
||||||
tcpConnection.createConnection(host, port);
|
|
||||||
|
|
||||||
return (0); // No return values
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tcpSend(lua_State* luaState) {
|
|
||||||
// Send frame over TCP socket
|
|
||||||
|
|
||||||
tcpConnection.enqueueForSending(new std::string(lua_tolstring(luaState, 1, 0)));
|
|
||||||
|
|
||||||
lua_pushinteger(luaState, tcpConnection.getFlagConnected()); // First return value: information if there is TCP connection
|
|
||||||
lua_pushinteger(luaState, tcpConnection.getAndResetReconnected()); // Secound return value: information if there was recent reconnection to TCP server
|
|
||||||
|
|
||||||
return (2); // Set return to number of arguments returned
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int __declspec(dllexport) luaopen_perun(lua_State * L) {
|
|
||||||
static const luaL_Reg Map[] = {
|
|
||||||
{"StartOfApp", appStartHook}, // Called at the begining of the session
|
|
||||||
{"EndOfApp", appEndHook }, // Called at the end of the session out of LuaExportStop
|
|
||||||
{"tcpSend", tcpSend}, // Called to send data from lua over TCP
|
|
||||||
{"tcpConnect", tcpConnect}, // Create connection
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register the list of functions for lua
|
|
||||||
luaL_register(L, "perun", Map);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
25
03_Perun_Lua_Wrapper/pierog/CmakeLists.txt
Normal file
25
03_Perun_Lua_Wrapper/pierog/CmakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.17)
|
||||||
|
project(pierog)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
set(PIEROG_DLL_SOURCES
|
||||||
|
"src/library.h"
|
||||||
|
"src/library.cpp"
|
||||||
|
src/RotatingFileOutput.cpp
|
||||||
|
src/SocketOutput.cpp
|
||||||
|
src/DataDistributor.cpp
|
||||||
|
src/RotatingFileOutput.h
|
||||||
|
src/SocketOutput.h
|
||||||
|
src/DataDistributor.h)
|
||||||
|
|
||||||
|
include(GenerateExportHeader)
|
||||||
|
add_library(pierog SHARED ${PIEROG_DLL_SOURCES})
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
pierog
|
||||||
|
lua-5.1.5
|
||||||
|
ws2_32
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(pierog PUBLIC ${PIEROG_DLL_SOURCES})
|
||||||
102
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.cpp
Normal file
102
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.cpp
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include "DataDistributor.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
DataDistributor::DataDistributor(std::string logPath,
|
||||||
|
std::string host,
|
||||||
|
int port) {
|
||||||
|
|
||||||
|
fileOutput = new RotatingFileOutput(std::move(logPath));
|
||||||
|
socketOutput = new SocketOutput(std::move(host), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataDistributor::~DataDistributor() = default;
|
||||||
|
|
||||||
|
void DataDistributor::start() {
|
||||||
|
if(running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread thread_object([this]() {
|
||||||
|
long KEEP_ALIVE = 1000;
|
||||||
|
bool nothingToSend = false;
|
||||||
|
|
||||||
|
while(shouldRun) {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
if(lock.try_lock()) {
|
||||||
|
if(sendQueue.empty()) {
|
||||||
|
auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastSent);
|
||||||
|
if(delay.count() > KEEP_ALIVE) {
|
||||||
|
sendQueue.push_front(new std::string(" "));
|
||||||
|
} else {
|
||||||
|
nothingToSend = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto payload = sendQueue.front();
|
||||||
|
int sent = socketOutput->write(payload);
|
||||||
|
lastSent = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
if(sent > 0) {
|
||||||
|
everSentViaSocket = true;
|
||||||
|
sendQueue.pop_front();
|
||||||
|
if(sent == payload->length()) {
|
||||||
|
delete payload;
|
||||||
|
} else {
|
||||||
|
auto shortened = payload->substr(sent, payload->length() - sent);
|
||||||
|
sendQueue.push_front(&shortened);
|
||||||
|
delete payload;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// failed to send
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nothingToSend) {
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread_object.detach();
|
||||||
|
|
||||||
|
shouldRun = true;
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDistributor::stop() {
|
||||||
|
shouldRun = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDistributor::enqueueForSending(std::string *payload) {
|
||||||
|
fileOutput->write(payload);
|
||||||
|
if (lock.try_lock()) {
|
||||||
|
while (!dataBuffer.empty()) {
|
||||||
|
// Shift buffer to queue
|
||||||
|
sendQueue.push_back(dataBuffer.front());
|
||||||
|
dataBuffer.pop_front();
|
||||||
|
}
|
||||||
|
sendQueue.push_back(payload);
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dataBuffer.push_back(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDistributor::markNewRecording() {
|
||||||
|
fileOutput->markNewRecording();
|
||||||
|
if(!everSentViaSocket) {
|
||||||
|
lock.lock();
|
||||||
|
sendQueue.clear();
|
||||||
|
dataBuffer.clear();
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DataDistributor::isConnected() {
|
||||||
|
return socketOutput->isConnected();
|
||||||
|
}
|
||||||
40
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.h
Normal file
40
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef PARENT_DATADISTRIBUTOR_H
|
||||||
|
#define PARENT_DATADISTRIBUTOR_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <queue>
|
||||||
|
#include "SocketOutput.h"
|
||||||
|
#include "RotatingFileOutput.h"
|
||||||
|
|
||||||
|
class DataDistributor {
|
||||||
|
public:
|
||||||
|
DataDistributor(std::string logPath,
|
||||||
|
std::string host,
|
||||||
|
int port);
|
||||||
|
|
||||||
|
virtual ~DataDistributor();
|
||||||
|
|
||||||
|
void enqueueForSending(std::string* payload);
|
||||||
|
void markNewRecording();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
int isConnected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<boolean> shouldRun = true;
|
||||||
|
std::atomic<boolean> running = false;
|
||||||
|
std::atomic<boolean> everSentViaSocket = false;
|
||||||
|
std::deque<std::string*> dataBuffer;
|
||||||
|
std::deque<std::string*> sendQueue;
|
||||||
|
std::mutex lock;
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::system_clock> lastSent = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
SocketOutput* socketOutput;
|
||||||
|
RotatingFileOutput* fileOutput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PARENT_DATADISTRIBUTOR_H
|
||||||
41
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.cpp
Normal file
41
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.cpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#include "RotatingFileOutput.h"
|
||||||
|
|
||||||
|
RotatingFileOutput::~RotatingFileOutput() = default;
|
||||||
|
|
||||||
|
RotatingFileOutput::RotatingFileOutput(std::string outputPath): path(std::move(outputPath)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotatingFileOutput::markNewRecording() {
|
||||||
|
if(outputFile != nullptr && outputFile->good()) {
|
||||||
|
outputFile->flush();
|
||||||
|
outputFile->close();
|
||||||
|
delete outputFile;
|
||||||
|
outputFile = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotatingFileOutput::write(std::string *payload) {
|
||||||
|
if (outputFile == nullptr) {
|
||||||
|
std::string fileName = generateFileName();
|
||||||
|
outputFile = new std::ofstream(fileName, std::ofstream::app | std::ios::out);
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFile->write(payload->c_str(), payload->length());
|
||||||
|
bytesWritten += (long) payload->length();
|
||||||
|
if (payload->length() > 50) {
|
||||||
|
outputFile->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RotatingFileOutput::generateFileName() {
|
||||||
|
auto const now = std::chrono::system_clock::now();
|
||||||
|
auto const gmt = std::chrono::locate_zone("Etc/GMT");
|
||||||
|
auto const filename = std::format("pierog.{:%FT_%H%M%S}.log",
|
||||||
|
std::chrono::zoned_time{gmt, floor<std::chrono::milliseconds>(now)});
|
||||||
|
|
||||||
|
std::filesystem::path dir(this->path);
|
||||||
|
std::filesystem::path file(filename);
|
||||||
|
return (dir / file).string();
|
||||||
|
}
|
||||||
|
|
||||||
27
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.h
Normal file
27
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef PARENT_ROTATINGFILEOUTPUT_H
|
||||||
|
#define PARENT_ROTATINGFILEOUTPUT_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
class RotatingFileOutput {
|
||||||
|
public:
|
||||||
|
RotatingFileOutput(std::string outputPath);
|
||||||
|
virtual ~RotatingFileOutput();
|
||||||
|
|
||||||
|
void markNewRecording();
|
||||||
|
void write(std::string* payload);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string path;
|
||||||
|
|
||||||
|
std::atomic<long long> bytesWritten;
|
||||||
|
std::ofstream * outputFile = nullptr;
|
||||||
|
|
||||||
|
std::string generateFileName();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PARENT_ROTATINGFILEOUTPUT_H
|
||||||
56
03_Perun_Lua_Wrapper/pierog/src/SocketOutput.cpp
Normal file
56
03_Perun_Lua_Wrapper/pierog/src/SocketOutput.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "SocketOutput.h"
|
||||||
|
|
||||||
|
SocketOutput::SocketOutput(std::string host,
|
||||||
|
const int port): tcpHost(std::move(host)), tcpPort(port) {
|
||||||
|
|
||||||
|
address = new SOCKADDR_IN;
|
||||||
|
address->sin_family = AF_INET;
|
||||||
|
address->sin_port = htons(u_short(this->tcpPort));
|
||||||
|
address->sin_addr.s_addr = *((unsigned long*)gethostbyname(this->tcpHost.c_str())->h_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketOutput::~SocketOutput() = default;
|
||||||
|
|
||||||
|
int SocketOutput::write(std::string *payload) {
|
||||||
|
|
||||||
|
if(!(isConnected() || _connect())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytesSent = send(tcpSocket, payload->c_str(), payload->length(), 0);
|
||||||
|
if(bytesSent > 0) {
|
||||||
|
return bytesSent;
|
||||||
|
} else {
|
||||||
|
switch (WSAGetLastError()) {
|
||||||
|
case WSAECONNRESET: // Connection reset
|
||||||
|
case WSAECONNABORTED: // Connection aborted
|
||||||
|
case WSAESHUTDOWN: // Connection closed
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketOutput::isConnected() {
|
||||||
|
return connectionState == CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketOutput::_connect() {
|
||||||
|
if(tcpSocket == INVALID_SOCKET) {
|
||||||
|
tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
}
|
||||||
|
if(connectionState != CONNECTED) {
|
||||||
|
if (connect(tcpSocket, (sockaddr *) address, sizeof(SOCKADDR_IN)) == 0) {
|
||||||
|
connectionState = CONNECTED;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketOutput::disconnect() {
|
||||||
|
closesocket(tcpSocket);
|
||||||
|
tcpSocket = INVALID_SOCKET;
|
||||||
|
connectionState = DISCONNECTED;
|
||||||
|
}
|
||||||
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
|
||||||
99
03_Perun_Lua_Wrapper/pierog/src/library.cpp
Normal file
99
03_Perun_Lua_Wrapper/pierog/src/library.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "library.h"
|
||||||
|
#include "DataDistributor.h"
|
||||||
|
#include <format>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
static DataDistributor * dataDistributor = nullptr;
|
||||||
|
|
||||||
|
static std::string *startingDelimiter = nullptr;
|
||||||
|
static std::string *endingDelimiter = nullptr;
|
||||||
|
static std::string lastObservedHash = std::string("");
|
||||||
|
|
||||||
|
/* this method exists for comments */
|
||||||
|
static int valuesToReturn(int input) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int appStartHook(lua_State* luaState) {
|
||||||
|
// Starting the app - prepare
|
||||||
|
if(dataDistributor == nullptr) {
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
const std::string path = std::string(lua_tolstring(luaState, i++, 0));
|
||||||
|
const std::string host = std::string(lua_tolstring(luaState, i++, 0));
|
||||||
|
const int port = (int) lua_tointeger(luaState, i++);
|
||||||
|
|
||||||
|
dataDistributor = new DataDistributor(path, host, port);
|
||||||
|
dataDistributor->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushinteger(luaState, 1); // First return value: confirmation that app was started
|
||||||
|
|
||||||
|
return valuesToReturn(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int appEndHook(lua_State* luaState) {
|
||||||
|
// Closing the app - clean up
|
||||||
|
|
||||||
|
if(dataDistributor != nullptr) {
|
||||||
|
dataDistributor->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesToReturn(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setDelimiters(lua_State* luaState) {
|
||||||
|
startingDelimiter = new std::string(lua_tolstring(luaState, 1, 0));
|
||||||
|
endingDelimiter = new std::string(lua_tolstring(luaState, 2, 0));
|
||||||
|
|
||||||
|
return valuesToReturn(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int markMissionStart(lua_State* luaState) {
|
||||||
|
|
||||||
|
std::string missionHash = std::string(lua_tolstring(luaState, 1, 0));
|
||||||
|
|
||||||
|
if(dataDistributor != nullptr && missionHash != lastObservedHash) {
|
||||||
|
dataDistributor->markNewRecording();
|
||||||
|
lastObservedHash = missionHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesToReturn(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpSend(lua_State* luaState) {
|
||||||
|
// Send frame over TCP socket
|
||||||
|
|
||||||
|
if(dataDistributor != nullptr) {
|
||||||
|
if(startingDelimiter != nullptr) {
|
||||||
|
dataDistributor->enqueueForSending(new std::string(*startingDelimiter));
|
||||||
|
}
|
||||||
|
dataDistributor->enqueueForSending(new std::string(lua_tolstring(luaState, 1, 0)));
|
||||||
|
if(endingDelimiter != nullptr) {
|
||||||
|
dataDistributor->enqueueForSending(new std::string(*endingDelimiter));
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushinteger(luaState,
|
||||||
|
dataDistributor->isConnected()); // First return value: information if there is TCP connection
|
||||||
|
} else {
|
||||||
|
lua_pushinteger(luaState, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesToReturn(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int __declspec(dllexport) luaopen_pierog(lua_State * L) {
|
||||||
|
static const luaL_Reg Map[] = {
|
||||||
|
{"StartOfApp", appStartHook}, // Called at the begining of the session
|
||||||
|
{"EndOfApp", appEndHook }, // Called at the end of the session out of LuaExportStop
|
||||||
|
{"tcpSend", tcpSend}, // Called to send data from lua over TCP
|
||||||
|
{"delimiters", setDelimiters },
|
||||||
|
{"markMissionStart", markMissionStart },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register the list of functions for lua
|
||||||
|
luaL_register(L, "pierog", Map);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -12,6 +12,5 @@ extern "C" {
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include "Connection.h"
|
|
||||||
|
|
||||||
#endif //PERUN_LIBRARY_H
|
#endif //PERUN_LIBRARY_H
|
||||||
@@ -14,10 +14,10 @@ CREATE TABLE IF NOT EXISTS `pe_Config` (
|
|||||||
`pe_Config_id` int(11) NOT NULL,
|
`pe_Config_id` int(11) NOT NULL,
|
||||||
`pe_Config_payload` varchar(255) DEFAULT NULL,
|
`pe_Config_payload` varchar(255) DEFAULT NULL,
|
||||||
PRIMARY KEY (`pe_Config_id`)
|
PRIMARY KEY (`pe_Config_id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
INSERT INTO `pe_Config` (`pe_Config_id`, `pe_Config_payload`) VALUES
|
INSERT INTO `pe_Config` (`pe_Config_id`, `pe_Config_payload`) VALUES
|
||||||
(1, 'v0.12.0');
|
(1, 'v0.12.1');
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_DataMissionHashes`;
|
DROP TABLE IF EXISTS `pe_DataMissionHashes`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_DataMissionHashes` (
|
CREATE TABLE IF NOT EXISTS `pe_DataMissionHashes` (
|
||||||
@@ -28,7 +28,7 @@ CREATE TABLE IF NOT EXISTS `pe_DataMissionHashes` (
|
|||||||
PRIMARY KEY (`pe_DataMissionHashes_id`),
|
PRIMARY KEY (`pe_DataMissionHashes_id`),
|
||||||
UNIQUE KEY `UNIQUE_hash` (`pe_DataMissionHashes_hash`),
|
UNIQUE KEY `UNIQUE_hash` (`pe_DataMissionHashes_hash`),
|
||||||
KEY `pe_DataMissionHashes_instance` (`pe_DataMissionHashes_instance`)
|
KEY `pe_DataMissionHashes_instance` (`pe_DataMissionHashes_instance`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_DataPlayers`;
|
DROP TABLE IF EXISTS `pe_DataPlayers`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_DataPlayers` (
|
CREATE TABLE IF NOT EXISTS `pe_DataPlayers` (
|
||||||
@@ -39,7 +39,7 @@ CREATE TABLE IF NOT EXISTS `pe_DataPlayers` (
|
|||||||
`pe_DataPlayers_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`pe_DataPlayers_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`pe_DataPlayers_id`),
|
PRIMARY KEY (`pe_DataPlayers_id`),
|
||||||
UNIQUE KEY `UNIQUE_UCID` (`pe_DataPlayers_ucid`)
|
UNIQUE KEY `UNIQUE_UCID` (`pe_DataPlayers_ucid`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_DataRaw`;
|
DROP TABLE IF EXISTS `pe_DataRaw`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_DataRaw` (
|
CREATE TABLE IF NOT EXISTS `pe_DataRaw` (
|
||||||
@@ -50,7 +50,7 @@ CREATE TABLE IF NOT EXISTS `pe_DataRaw` (
|
|||||||
PRIMARY KEY (`pe_dataraw_type`,`pe_dataraw_instance`),
|
PRIMARY KEY (`pe_dataraw_type`,`pe_dataraw_instance`),
|
||||||
KEY `pe_dataraw_type_pe_dataraw_instance` (`pe_dataraw_type`,`pe_dataraw_instance`),
|
KEY `pe_dataraw_type_pe_dataraw_instance` (`pe_dataraw_type`,`pe_dataraw_instance`),
|
||||||
KEY `pe_dataraw_updated` (`pe_dataraw_updated`)
|
KEY `pe_dataraw_updated` (`pe_dataraw_updated`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_DataTypes`;
|
DROP TABLE IF EXISTS `pe_DataTypes`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_DataTypes` (
|
CREATE TABLE IF NOT EXISTS `pe_DataTypes` (
|
||||||
@@ -59,14 +59,14 @@ CREATE TABLE IF NOT EXISTS `pe_DataTypes` (
|
|||||||
`pe_DataTypes_update` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`pe_DataTypes_update` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`pe_DataTypes_id`),
|
PRIMARY KEY (`pe_DataTypes_id`),
|
||||||
UNIQUE KEY `UNIQUE_TYPE_NAME` (`pe_DataTypes_name`)
|
UNIQUE KEY `UNIQUE_TYPE_NAME` (`pe_DataTypes_name`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_LogChat`;
|
DROP TABLE IF EXISTS `pe_LogChat`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_LogChat` (
|
CREATE TABLE IF NOT EXISTS `pe_LogChat` (
|
||||||
`pe_LogChat_id` bigint(20) NOT NULL AUTO_INCREMENT,
|
`pe_LogChat_id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
`pe_LogChat_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`pe_LogChat_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`pe_LogChat_missionhash_id` bigint(20) DEFAULT NULL,
|
`pe_LogChat_missionhash_id` bigint DEFAULT NULL,
|
||||||
`pe_LogChat_playerid` varchar(100) NOT NULL,
|
`pe_LogChat_playerid` bigint NOT NULL,
|
||||||
`pe_LogChat_msg` text NOT NULL,
|
`pe_LogChat_msg` text NOT NULL,
|
||||||
`pe_LogChat_all` varchar(10) NOT NULL,
|
`pe_LogChat_all` varchar(10) NOT NULL,
|
||||||
PRIMARY KEY (`pe_LogChat_id`),
|
PRIMARY KEY (`pe_LogChat_id`),
|
||||||
@@ -74,7 +74,7 @@ CREATE TABLE IF NOT EXISTS `pe_LogChat` (
|
|||||||
KEY `pe_LogChat_playerid` (`pe_LogChat_playerid`),
|
KEY `pe_LogChat_playerid` (`pe_LogChat_playerid`),
|
||||||
KEY `pe_LogChat_datetime` (`pe_LogChat_datetime`),
|
KEY `pe_LogChat_datetime` (`pe_LogChat_datetime`),
|
||||||
KEY `pe_LogChat_all` (`pe_LogChat_all`)
|
KEY `pe_LogChat_all` (`pe_LogChat_all`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_LogEvent`;
|
DROP TABLE IF EXISTS `pe_LogEvent`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_LogEvent` (
|
CREATE TABLE IF NOT EXISTS `pe_LogEvent` (
|
||||||
@@ -90,7 +90,7 @@ CREATE TABLE IF NOT EXISTS `pe_LogEvent` (
|
|||||||
KEY `pe_LogEvent_missionhash_id` (`pe_LogEvent_missionhash_id`),
|
KEY `pe_LogEvent_missionhash_id` (`pe_LogEvent_missionhash_id`),
|
||||||
KEY `pe_LogEvent_datetime` (`pe_LogEvent_datetime`),
|
KEY `pe_LogEvent_datetime` (`pe_LogEvent_datetime`),
|
||||||
KEY `pe_LogEvent_type_2` (`pe_LogEvent_type`)
|
KEY `pe_LogEvent_type_2` (`pe_LogEvent_type`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_LogLogins`;
|
DROP TABLE IF EXISTS `pe_LogLogins`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_LogLogins` (
|
CREATE TABLE IF NOT EXISTS `pe_LogLogins` (
|
||||||
@@ -104,7 +104,7 @@ CREATE TABLE IF NOT EXISTS `pe_LogLogins` (
|
|||||||
KEY `pe_LogLogins_playerid` (`pe_LogLogins_playerid`),
|
KEY `pe_LogLogins_playerid` (`pe_LogLogins_playerid`),
|
||||||
KEY `pe_LogLogins_datetime` (`pe_LogLogins_datetime`),
|
KEY `pe_LogLogins_datetime` (`pe_LogLogins_datetime`),
|
||||||
KEY `pe_LogLogins_instance` (`pe_LogLogins_instance`)
|
KEY `pe_LogLogins_instance` (`pe_LogLogins_instance`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_LogStats`;
|
DROP TABLE IF EXISTS `pe_LogStats`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_LogStats` (
|
CREATE TABLE IF NOT EXISTS `pe_LogStats` (
|
||||||
@@ -149,7 +149,7 @@ CREATE TABLE IF NOT EXISTS `pe_LogStats` (
|
|||||||
KEY `pe_LogStats_masterslot` (`pe_LogStats_masterslot`),
|
KEY `pe_LogStats_masterslot` (`pe_LogStats_masterslot`),
|
||||||
KEY `pe_LogStats_mstatus` (`pe_LogStats_mstatus`),
|
KEY `pe_LogStats_mstatus` (`pe_LogStats_mstatus`),
|
||||||
KEY `pe_LogStats_seat` (`pe_LogStats_seat`)
|
KEY `pe_LogStats_seat` (`pe_LogStats_seat`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
DROP TRIGGER IF EXISTS `pe_LogStats_UPDATE`;
|
DROP TRIGGER IF EXISTS `pe_LogStats_UPDATE`;
|
||||||
DELIMITER $$
|
DELIMITER $$
|
||||||
CREATE TRIGGER `pe_LogStats_UPDATE` BEFORE UPDATE ON `pe_LogStats` FOR EACH ROW BEGIN
|
CREATE TRIGGER `pe_LogStats_UPDATE` BEFORE UPDATE ON `pe_LogStats` FOR EACH ROW BEGIN
|
||||||
@@ -182,7 +182,7 @@ CREATE TABLE IF NOT EXISTS `pe_OnlinePlayers` (
|
|||||||
`pe_OnlinePlayers_slot` varchar(255) DEFAULT NULL,
|
`pe_OnlinePlayers_slot` varchar(255) DEFAULT NULL,
|
||||||
`pe_OnlinePlayers_ucid` varchar(255) DEFAULT NULL,
|
`pe_OnlinePlayers_ucid` varchar(255) DEFAULT NULL,
|
||||||
`pe_OnlinePlayers_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
`pe_OnlinePlayers_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `pe_OnlineStatus`;
|
DROP TABLE IF EXISTS `pe_OnlineStatus`;
|
||||||
CREATE TABLE IF NOT EXISTS `pe_OnlineStatus` (
|
CREATE TABLE IF NOT EXISTS `pe_OnlineStatus` (
|
||||||
@@ -197,7 +197,7 @@ CREATE TABLE IF NOT EXISTS `pe_OnlineStatus` (
|
|||||||
`pe_OnlineStatus_perunversion_winapp` varchar(255) DEFAULT NULL,
|
`pe_OnlineStatus_perunversion_winapp` varchar(255) DEFAULT NULL,
|
||||||
`pe_OnlineStatus_perunversion_dcshook` varchar(255) DEFAULT NULL,
|
`pe_OnlineStatus_perunversion_dcshook` varchar(255) DEFAULT NULL,
|
||||||
`pe_OnlineStatus_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
`pe_OnlineStatus_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
|
||||||
ALTER TABLE `pe_DataMissionHashes` ADD FULLTEXT KEY `pe_DataMissionHashes_hash` (`pe_DataMissionHashes_hash`);
|
ALTER TABLE `pe_DataMissionHashes` ADD FULLTEXT KEY `pe_DataMissionHashes_hash` (`pe_DataMissionHashes_hash`);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ZBW8R5L25A8QW¤cy_code=EUR&source=url)
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ Core:
|
|||||||
## Installing
|
## Installing
|
||||||
* Download latest [release](https://github.com/szporwolik/perun/releases)
|
* Download latest [release](https://github.com/szporwolik/perun/releases)
|
||||||
* Copy contents of [01_DCS](https://github.com/szporwolik/perun/tree/master/01_DCS) to your DCS folder in your Saved Games
|
* Copy contents of [01_DCS](https://github.com/szporwolik/perun/tree/master/01_DCS) to your DCS folder in your Saved Games
|
||||||
* From the downloaded release package, put ```perun.dll``` into your DCS folder in your Saved Games,```Mods/services/Perun/dll```
|
* From the downloaded release package, put ```perun.dll``` into your DCS folder in your Saved Games,```Mods/services/Perun/bin```
|
||||||
* You can change your configuration settings in DCS\Mods\services\Perun\lua\perun_config
|
* You can change your configuration settings in DCS\Mods\services\Perun\lua\perun_config
|
||||||
* Create MySQL database using SQL script located in [04_MySQL](https://github.com/szporwolik/perun/tree/master/04_MySQL); note that you need just a one database per DCS server machine - multiple instances pushing data to the one database are supported
|
* Create MySQL database using SQL script located in [04_MySQL](https://github.com/szporwolik/perun/tree/master/04_MySQL); note that you need just a one database per DCS server machine - multiple instances pushing data to the one database are supported
|
||||||
* Ensure that your MySQL config is not using STRICT_TRANS_TABLES
|
* Ensure that your MySQL config is not using STRICT_TRANS_TABLES
|
||||||
|
|||||||
Reference in New Issue
Block a user