27 Commits

Author SHA1 Message Date
Szymon Porwolik
f7f688d1a5 Modified event log 2019-03-10 00:48:32 +01:00
Szymon Porwolik
81ff34014a Added stats support 2019-03-10 00:48:32 +01:00
Szymon Porwolik
9e0c515af0 Added stats support 2019-03-10 00:48:32 +01:00
Szymon Porwolik
9391d8778f Added stats suport 2019-03-10 00:48:32 +01:00
Szymon Porwolik
1cfe5a1ea9 Added stats support 2019-03-10 00:48:32 +01:00
Szymon Porwolik
8d1835f6f5 - MOTD will be send only to player who is joining
- after mission end mission hash will be set to ""
2019-03-10 00:48:32 +01:00
Szymon Porwolik
3be5a8765f v0.4.1 Lua and DB modification to support multiple instances od DCS World 2019-03-03 15:38:18 +01:00
VladMordock
0f01624380 Update README.md 2019-03-03 13:23:49 +01:00
Szymon Porwolik
3ff2fff728 v0.4.0 major code cleanup 2019-03-01 02:09:06 +01:00
Szymon Porwolik
f383f3c056 Added #4 - only one instance will be allowed to run 2019-03-01 02:09:06 +01:00
Szymon Porwolik
69f995bd6d Basic error proofing for UDP (port al;ready in use) and MySQL (connection/access issues). 2019-03-01 02:09:06 +01:00
Szymon Porwolik
64a550e8e8 Project cleanup 2019-03-01 02:09:06 +01:00
Szymon Porwolik
31ed9ee875 Updated MySQL DB to v0.4.0 2019-03-01 02:09:06 +01:00
Szymon Porwolik
0722a9ca26 Updated README 2019-03-01 02:09:06 +01:00
Szymon Porwolik
a21bbd4459 Version updated to v0.4.0 2019-03-01 02:09:06 +01:00
Szymon Porwolik
4ff546b105 Improved, fixed #3 2019-03-01 02:09:06 +01:00
Szymon Porwolik
2463d4267d Fixed #10 2019-03-01 02:09:06 +01:00
Szymon Porwolik
6b37b05dbf Fixed #6 2019-03-01 02:09:06 +01:00
Szymon Porwolik
d34fdf00b3 Fixed formatting on sending Mission start/Mission end event 2019-02-28 19:49:26 +01:00
simpo
37543ec167 Fixed #8
Fixed polish characters, code clean up
2019-02-27 09:32:00 +01:00
simpo
7dda6a224d Update README.md 2019-02-27 08:38:53 +01:00
simpo
993ae2a755 Rename perun_export.json to perun_status_data.json 2019-02-27 01:51:23 +01:00
simpo
c79dc039e6 Fixed #7
For one mission lua2net keeps crashing - no possiblity for full lua2json export
2019-02-27 01:50:51 +01:00
simpo
a26c9d8f08 Update README.md 2019-02-26 23:27:43 +01:00
simpo
f55a117051 Fixed #1, #7
Additionaly diagostic package will carry total players connected as well.
2019-02-26 23:24:10 +01:00
simpo
e05cee514c Update Perun.lua
Fixed bug with JSON file not being generated.
2019-02-25 23:20:43 +01:00
Szymon Porwolik
d63c0fbfdf v0.3.6
MySQL database structure change - shall be less redundant.
2019-02-25 13:17:33 +01:00
21 changed files with 1414 additions and 915 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,128 @@
// This class handles MySQL communication
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using System;
internal class DatabaseController
{
public static string strMySQLConnectionString; // MySQL connection string
public static void SendToMySql(string strRawUDPFrame)
{
// Main function to send data to mysql
dynamic strUDPFrame = JsonConvert.DeserializeObject(strRawUDPFrame); // Deserialize raw data
string strUDPFrameType = strUDPFrame.type;
string strUDPFrameTimestamp = strUDPFrame.timestamp;
string strUDPFrameInstance = strUDPFrame.instance;
string strUDPFramePayload = "";
string strUDPFramePayload_Perun = "";
string strSQLQueryTxt = "";
// Some frames may come without timestamp, use database currrent timestampe then
if (strUDPFrameTimestamp != null)
{
strUDPFrameTimestamp = "'" + strUDPFrameTimestamp + "'";
}
else
{
strUDPFrameTimestamp = "CURRENT_TIMESTAMP()";
}
// Modify specific types
if (strUDPFrameType == "1")
{
strUDPFrame.payload["v_win"] = "v" + Globals.strPerunVersion; // Inject app version information
}
// Specific SQL
if (strUDPFrameType == "50")
{
// Add entry to chat log
strSQLQueryTxt = "INSERT INTO `pe_DataPlayers` (`pe_DataPlayers_ucid`) SELECT '" + strUDPFrame.payload.ucid + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_DataPlayers` where `pe_DataPlayers_ucid` = '" + strUDPFrame.payload.ucid + "' );";
strSQLQueryTxt += "UPDATE `pe_DataPlayers` SET `pe_DataPlayers_updated` = " + strUDPFrameTimestamp + ",`pe_DataPlayers_lastname`='" + strUDPFrame.payload.player + "' WHERE `pe_DataPlayers_ucid`='" + strUDPFrame.payload.ucid + "' ;";
strSQLQueryTxt += "INSERT INTO `pe_DataMissionHashes` (`pe_DataMissionHashes_hash`,`pe_DataMissionHashes_instance`) SELECT '" + strUDPFrame.payload.missionhash + "','" + strUDPFrameInstance + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_DataMissionHashes` where `pe_DataMissionHashes_hash` ='" + strUDPFrame.payload.missionhash + "' AND `pe_DataMissionHashes_instance`="+ strUDPFrameInstance + ");";
strSQLQueryTxt += "UPDATE `pe_DataMissionHashes` SET `pe_DataMissionHashes_datetime` = " + strUDPFrameTimestamp + " WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.missionhash + "' AND `pe_DataMissionHashes_instance`=" + strUDPFrameInstance + " ;";
strSQLQueryTxt += "INSERT INTO `pe_LogChat` (`pe_LogChat_id`,`pe_LogChat_datetime`, `pe_LogChat_playerid`, `pe_LogChat_msg`, `pe_LogChat_all`,`pe_LogChat_missionhash_id`) VALUES (NULL,'" + strUDPFrame.payload.datetime + "', (SELECT `pe_DataPlayers_id` from `pe_DataPlayers` WHERE `pe_DataPlayers_ucid` = '" + strUDPFrame.payload.ucid + "'), '" + strUDPFrame.payload.msg + "', '" + strUDPFrame.payload.all + "',(SELECT `pe_DataMissionHashes_id` FROM `pe_DataMissionHashes` WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.missionhash + "'));";
}
else if (strUDPFrameType == "51")
{
// Add entry to event log
strSQLQueryTxt = "INSERT INTO `pe_DataMissionHashes` (`pe_DataMissionHashes_hash`,`pe_DataMissionHashes_instance`) SELECT '" + strUDPFrame.payload.log_missionhash + "','" + strUDPFrameInstance + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_DataMissionHashes` where `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.log_missionhash + "' AND `pe_DataMissionHashes_instance`=" + strUDPFrameInstance + ");";
strSQLQueryTxt += "UPDATE `pe_DataMissionHashes` SET `pe_DataMissionHashes_datetime` = " + strUDPFrameTimestamp + " WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.log_missionhash + "' AND `pe_DataMissionHashes_instance`=" + strUDPFrameInstance + ";";
strSQLQueryTxt += "INSERT INTO `pe_LogEvent` (`pe_LogEvent_arg1`,`pe_LogEvent_arg2`,`pe_LogEvent_id`, `pe_LogEvent_datetime`, `pe_LogEvent_type`, `pe_LogEvent_content`,`pe_LogEvent_missionhash_id`) VALUES ('"+ strUDPFrame.payload.log_arg_1 + "','"+ strUDPFrame.payload.log_arg_2 + "', NULL, '" + strUDPFrame.payload.log_datetime + "', '" + strUDPFrame.payload.log_type + "', '" + strUDPFrame.payload.log_content + "', (SELECT `pe_DataMissionHashes_id` FROM `pe_DataMissionHashes` WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.log_missionhash + "'));";
}
else if (strUDPFrameType == "52")
{
// Update user stats
strUDPFramePayload = JsonConvert.SerializeObject(strUDPFrame.payload.stat_data_dcs); // Deserialize payload
strUDPFramePayload_Perun = JsonConvert.SerializeObject(strUDPFrame.payload.stat_data_perun); // Deserialize payload
strSQLQueryTxt = "INSERT INTO `pe_DataMissionHashes` (`pe_DataMissionHashes_hash`,`pe_DataMissionHashes_instance`) SELECT '" + strUDPFrame.payload.stat_missionhash + "','" + strUDPFrameInstance + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_DataMissionHashes` where `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.stat_missionhash + "' AND `pe_DataMissionHashes_instance`=" + strUDPFrameInstance + ");";
strSQLQueryTxt += "UPDATE `pe_DataMissionHashes` SET `pe_DataMissionHashes_datetime` = " + strUDPFrameTimestamp + " WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.stat_missionhash + "' AND `pe_DataMissionHashes_instance`=" + strUDPFrameInstance + " ;";
strSQLQueryTxt += "INSERT INTO `pe_DataPlayers` (`pe_DataPlayers_ucid`) SELECT '" + strUDPFrame.payload.stat_ucid + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_DataPlayers` where `pe_DataPlayers_ucid` = '" + strUDPFrame.payload.stat_ucid + "');";
strSQLQueryTxt += "UPDATE `pe_DataPlayers` SET `pe_DataPlayers_updated`=" + strUDPFrameTimestamp + " WHERE `pe_DataPlayers_ucid`='" + strUDPFrame.payload.stat_ucid + "';";
strSQLQueryTxt += "INSERT INTO `pe_LogStats` (`pe_LogStats_playerid`,`pe_LogStats_missionhash_id`,`pe_LogStats_type`) SELECT (SELECT `pe_DataPlayers_id` from `pe_DataPlayers` WHERE `pe_DataPlayers_ucid` = '" + strUDPFrame.payload.stat_ucid + "'), (SELECT `pe_DataMissionHashes_id` FROM `pe_DataMissionHashes` WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.stat_missionhash + "'),'" + strUDPFrame.payload.stat_data_type + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_LogStats` WHERE `pe_LogStats_missionhash_id`=(SELECT `pe_DataMissionHashes_id` FROM `pe_DataMissionHashes` WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.stat_missionhash + "') AND `pe_LogStats_playerid` = (SELECT `pe_DataPlayers_id` from `pe_DataPlayers` WHERE `pe_DataPlayers_ucid` = '" + strUDPFrame.payload.stat_ucid + "' AND `pe_LogStats_type`='"+ strUDPFrame.payload.stat_data_type + "') );";
strSQLQueryTxt += "UPDATE `pe_LogStats` SET `ps_kills`="+ strUDPFrame.payload.stat_data_perun.ps_kills + ",`ps_pvp`=" + strUDPFrame.payload.stat_data_perun.ps_pvp + ",`ps_deaths`=" + strUDPFrame.payload.stat_data_perun.ps_deaths + ",`ps_ejections`=" + strUDPFrame.payload.stat_data_perun.ps_ejections + ",`ps_crashes`=" + strUDPFrame.payload.stat_data_perun.ps_crashes + ",`ps_teamkills`=" + strUDPFrame.payload.stat_data_perun.ps_teamkills + ",`ps_kills_planes`=" + strUDPFrame.payload.stat_data_perun.ps_kills_planes + ",`ps_kills_helicopters`=" + strUDPFrame.payload.stat_data_perun.ps_kills_helicopters + ",`ps_kills_air_defense`=" + strUDPFrame.payload.stat_data_perun.ps_kills_air_defense + ",`ps_kills_armor`=" + strUDPFrame.payload.stat_data_perun.ps_kills_armor + ",`ps_kills_unarmed`=" + strUDPFrame.payload.stat_data_perun.ps_kills_unarmed + ",`ps_kills_infantry`=" + strUDPFrame.payload.stat_data_perun.ps_kills_infantry + ",`ps_kills_ships`=" + strUDPFrame.payload.stat_data_perun.ps_kills_ships + ",`ps_kills_other`=" + strUDPFrame.payload.stat_data_perun.ps_kills_other + ",`ps_airfield_takeoffs`=" + strUDPFrame.payload.stat_data_perun.ps_airfield_takeoffs + ",`ps_airfield_landings`=" + strUDPFrame.payload.stat_data_perun.ps_airfield_landings + ",`ps_ship_takeoffs`=" + strUDPFrame.payload.stat_data_perun.ps_ship_takeoffs + ",`ps_ship_landings`=" + strUDPFrame.payload.stat_data_perun.ps_ship_landings + ",`ps_farp_takeoffs`=" + strUDPFrame.payload.stat_data_perun.ps_farp_takeoffs + ",`ps_farp_landings`=" + strUDPFrame.payload.stat_data_perun.ps_farp_landings + ", `pe_LogStats_perun` = JSON_QUOTE('" + strUDPFramePayload_Perun + "'), `pe_LogStats_datetime`='" + strUDPFrame.payload.stat_datetime + "',`pe_LogStats_playerid` = (SELECT `pe_DataPlayers_id` from `pe_DataPlayers` WHERE `pe_DataPlayers_ucid` = '" + strUDPFrame.payload.stat_ucid + "'),`pe_LogStats_dcs`=JSON_QUOTE('" + strUDPFramePayload + "'),`pe_LogStats_missionhash_id`=(SELECT `pe_DataMissionHashes_id` FROM `pe_DataMissionHashes` WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.stat_missionhash + "') WHERE `pe_LogStats_missionhash_id`=(SELECT `pe_DataMissionHashes_id` FROM `pe_DataMissionHashes` WHERE `pe_DataMissionHashes_hash` = '" + strUDPFrame.payload.stat_missionhash + "') AND `pe_LogStats_playerid` = (SELECT `pe_DataPlayers_id` from `pe_DataPlayers` WHERE `pe_DataPlayers_ucid` = '" + strUDPFrame.payload.stat_ucid + "') AND `pe_LogStats_type`='" + strUDPFrame.payload.stat_data_type + "';";
}
else if (strUDPFrameType == "53")
{
// User logged in to DCS server
strSQLQueryTxt = "INSERT INTO `pe_DataPlayers` (`pe_DataPlayers_ucid`) SELECT '" + strUDPFrame.payload.login_ucid + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_DataPlayers` where pe_DataPlayers_ucid='" + strUDPFrame.payload.login_ucid + "');";
strSQLQueryTxt += "UPDATE `pe_DataPlayers` SET pe_DataPlayers_lastip='" + strUDPFrame.payload.login_ipaddr + "', pe_DataPlayers_lastname='" + strUDPFrame.payload.login_name + "',pe_DataPlayers_updated='" + strUDPFrame.payload.login_datetime + "' WHERE `pe_DataPlayers_ucid`= '" + strUDPFrame.payload.login_ucid + "';";
strSQLQueryTxt += "INSERT INTO `pe_LogLogins` (`pe_LogLogins_datetime`, `pe_LogLogins_playerid`, `pe_LogLogins_name`, `pe_LogLogins_ip`,`pe_LogLogins_instance`) VALUES ('" + strUDPFrame.payload.login_datetime + "', (SELECT pe_DataPlayers_id from pe_DataPlayers WHERE pe_DataPlayers_ucid = '" + strUDPFrame.payload.login_ucid + "'), '" + strUDPFrame.payload.login_name + "', '" + strUDPFrame.payload.login_ipaddr + "','"+ strUDPFrameInstance + "');";
}
else
{
// General definition used for 1-10 type packets
strUDPFramePayload = JsonConvert.SerializeObject(strUDPFrame.payload); // Deserialize payload
strSQLQueryTxt = "INSERT INTO `pe_DataRaw` (`pe_dataraw_type`,`pe_dataraw_instance`) SELECT '" + strUDPFrameType + "','"+ strUDPFrameInstance + "' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `pe_DataRaw` WHERE `pe_dataraw_type` = '" + strUDPFrameType + "' AND `pe_dataraw_instance` = " + strUDPFrameInstance + ");";
strSQLQueryTxt += "UPDATE `pe_DataRaw` SET `pe_dataraw_payload` = JSON_QUOTE('" + strUDPFramePayload + "'), `pe_dataraw_updated`=" + strUDPFrameTimestamp + " WHERE `pe_dataraw_type`=" + strUDPFrameType + " AND `pe_dataraw_instance` = "+ strUDPFrameInstance + ";";
}
// Connect to mysql and execute sql
MySqlConnection connMySQL = new MySqlConnection(DatabaseController.strMySQLConnectionString);
try
{
Console.WriteLine("Sending data to MySQL - Begin");
connMySQL.Open();
MySqlCommand cmdMySQL = new MySqlCommand(strSQLQueryTxt, connMySQL);
MySqlDataReader rdrMySQL = cmdMySQL.ExecuteReader();
while (rdrMySQL.Read())
{
Console.WriteLine(rdrMySQL[0] + " -- " + rdrMySQL[1]);
}
rdrMySQL.Close();
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "MySQL updated, package type: " + strUDPFrameType);
}
catch (ArgumentException a_ex)
{
// General exception found
Console.WriteLine(a_ex.ToString());
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - package type: " + strUDPFrameType);
}
catch (MySqlException m_ex)
{
// MySQL exception found
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - package type: " + strUDPFrameType);
switch (m_ex.Number)
{
case 1042: // Unable to connect to any of the specified MySQL hosts (Check Server,Port)
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - unable to connect");
break;
case 0: // Access denied (Check DB name,username,password)
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - access denied");
break;
default:
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "ERROR MySQL - " + m_ex.Number);
break;
}
}
connMySQL.Close();
Console.WriteLine("Sending data to MySQL - Done");
}
}

View File

@@ -0,0 +1,7 @@
// This class gathers all global variables
internal class Globals
{
public static string strPerunVersion = "DEBUG"; // Helper for pulling version definition
public static string[] arrLogHistory = new string[10]; // Log history for GUI
}

View File

@@ -0,0 +1,13 @@
// This class just wraps some Win32 stuff that we're going to use for blocking of multiple instances
using System;
using System.Runtime.InteropServices;
internal class NativeMethods
{
public const int HWND_BROADCAST = 0xffff;
public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
}

View File

@@ -0,0 +1,26 @@
// This class gathers all helper functions
using System;
internal class PerunHelper
{
public static void LogHistoryAdd(ref string[] arrLogHistory, string strEntryToAdd)
{
// Add entry to log history and rotate
for (int i = 0; i < arrLogHistory.Length - 1; i++)
{
arrLogHistory[i] = arrLogHistory[i + 1]; // Shift one down
}
arrLogHistory[arrLogHistory.Length - 1] = DateTime.Now.ToString("HH:mm:ss") + " > " + strEntryToAdd; // Add entry at the last position
}
public static string GetAppVersion(string strBeginning)
{
// Gets build version
if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
{
System.Deployment.Application.ApplicationDeployment cd = System.Deployment.Application.ApplicationDeployment.CurrentDeployment;
Globals.strPerunVersion = cd.CurrentVersion.ToString();
}
return strBeginning+"v" + Globals.strPerunVersion;
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Threading;
using System.Windows.Forms;
namespace Perun_v1
{
static class Program
{
/// <summary>
/// Main entry point to app
/// </summary>
// Mutex to block multiple instances
static Mutex mutex = new Mutex(true, "{5a710507-92e9-4664-9b91-918b8b82f107}");
[STAThread]
static void Main()
{
// Check if no other instances running
if (mutex.WaitOne(TimeSpan.Zero, true))
{
// Only instance
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
void Application_ApplicationExit(object sender, EventArgs e)
{
Properties.Settings.Default.Save(); // We will save settings on exit
}
Application.Run(new form_Main()); // Run main form
mutex.ReleaseMutex(); // Release mutex
}
else
{
// Multiple instance - send our Win32 message to make the currently running instance jump to front
NativeMethods.PostMessage(
(IntPtr)NativeMethods.HWND_BROADCAST,
NativeMethods.WM_SHOWME,
IntPtr.Zero,
IntPtr.Zero);
MessageBox.Show("Only one Perun instance is allowed.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}

View File

@@ -0,0 +1,91 @@
// This class handles UDP communication
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
internal class UDPController
{
// Main class for UDP listener
public static int intListenPort; // Port to listen at
public static bool boolDone; // Helper to exit main loop without killing thread
public static UdpClient udpListener; // Listener object
public static string[] arrLogHistory; // Log history for GUI
public static string[] arrSendBuffer; // Mysql send buffer
public static Thread thrUDPListener; // Seperate thread for UDP
public static void Create(int intListenPort, ref string[] arrLogHistory, ref string[] arrSendBuffer)
{
// Create class
UDPController.intListenPort = intListenPort;
UDPController.arrLogHistory = arrLogHistory;
UDPController.arrSendBuffer = arrSendBuffer;
}
public static void StopListen()
{
// FInish listening
UDPController.boolDone = true;
UDPController.udpListener.Close();
UDPController.udpListener = null;
for (int i = 0; i < arrSendBuffer.Length - 1; i++)
{
arrSendBuffer[i] = null;
}
}
public static void StartListen()
{
Console.WriteLine("UDP Listen start");
try
{
// Start listening to UDP
udpListener = new UdpClient(intListenPort);
IPEndPoint ipendpointGroupEP = new IPEndPoint(IPAddress.Loopback, intListenPort);
string strReceivedData;
byte[] arrReceiveByteArray;
// Start the main loop
UDPController.boolDone = false;
while (!UDPController.boolDone)
{
// Start listening
Console.WriteLine("UDP: Waiting for packet");
arrReceiveByteArray = udpListener.Receive(ref ipendpointGroupEP);
strReceivedData = Encoding.ASCII.GetString(arrReceiveByteArray, 0, arrReceiveByteArray.Length);
Console.WriteLine("Sender: {0} Payload: {1}", ipendpointGroupEP.ToString(), strReceivedData);
// Add to log history and rotate
dynamic dynamicRawUDPFrame = JsonConvert.DeserializeObject(strReceivedData); // Deserialize received frame
string strRawUDPFrameType = dynamicRawUDPFrame.type;
PerunHelper.LogHistoryAdd(ref arrLogHistory, "UDP packet received, type: " + strRawUDPFrameType);
// Add to mySQL send buffer (find first empty slot)
for (int i = 0; i < arrSendBuffer.Length - 1; i++)
{
if (arrSendBuffer[i] == null)
{
arrSendBuffer[i] = strReceivedData;
break;
}
}
}
udpListener.Close(); // Close port
}
catch (Exception e)
{
// General exception found
if (e.HResult != -2147467259) {
Console.WriteLine(e.ToString());
PerunHelper.LogHistoryAdd(ref arrLogHistory, "ERROR UDP - port may be in use");
}
}
Console.WriteLine("UDP listen stop");
}
}

View File

@@ -58,6 +58,8 @@
this.openFileDialog_SRS = new System.Windows.Forms.OpenFileDialog();
this.openFileDialog_LotATC = new System.Windows.Forms.OpenFileDialog();
this.tim_10000ms = new System.Windows.Forms.Timer(this.components);
this.tim_200ms = new System.Windows.Forms.Timer(this.components);
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
this.con_GroupBox_1.SuspendLayout();
this.con_GroupBox_2.SuspendLayout();
this.con_GroupBox_3.SuspendLayout();
@@ -68,16 +70,7 @@
this.con_List_Received.Enabled = false;
this.con_List_Received.FormattingEnabled = true;
this.con_List_Received.Items.AddRange(new object[] {
"Loading",
"Loading",
"Loading",
"Loading",
"Loading",
"Loading",
"Loading",
"Loading",
"Loading",
"Loading"});
"Welcome to Perun for DCS World!"});
this.con_List_Received.Location = new System.Drawing.Point(6, 19);
this.con_List_Received.Name = "con_List_Received";
this.con_List_Received.Size = new System.Drawing.Size(307, 134);
@@ -149,6 +142,7 @@
//
// con_txt_mysql_port
//
this.con_txt_mysql_port.Enabled = false;
this.con_txt_mysql_port.Location = new System.Drawing.Point(106, 45);
this.con_txt_mysql_port.Name = "con_txt_mysql_port";
this.con_txt_mysql_port.Size = new System.Drawing.Size(207, 20);
@@ -321,6 +315,15 @@
this.tim_10000ms.Interval = 30000;
this.tim_10000ms.Tick += new System.EventHandler(this.tim_10000ms_Tick);
//
// tim_200ms
//
this.tim_200ms.Tick += new System.EventHandler(this.tim_200ms_Tick);
//
// notifyIcon1
//
this.notifyIcon1.Text = "notifyIcon1";
this.notifyIcon1.Visible = true;
//
// form_Main
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -383,6 +386,8 @@
private System.Windows.Forms.Timer tim_10000ms;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox con_txt_mysql_port;
private System.Windows.Forms.Timer tim_200ms;
private System.Windows.Forms.NotifyIcon notifyIcon1;
}
}

View File

@@ -0,0 +1,376 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using Newtonsoft.Json;
namespace Perun_v1
{
public partial class form_Main : Form
{
// Variable definitions
public string[] arrSendBuffer = new string[100]; // Mysql send buffer
public bool boolLetMeOut = false; // Helper to handle system tray
// ################################ Main ################################
private void form_Main_Load(object sender, EventArgs e)
{
// Form loaded - fill controls with default values
Globals.arrLogHistory[0] = DateTime.Now.ToString("HH:mm:ss") + " > " + "Perun started";
form_Main_LoadSettings(); // Load settings
this.Text = PerunHelper.GetAppVersion(this.Text + " - "); // Display build version in title bar
}
public form_Main()
{
// Form init
InitializeComponent();
}
// ################################ Helpers ################################
private void form_Main_LoadSettings()
{
// Loads settings
con_txt_mysql_database.Text = Properties.Settings.Default.MYSQL_DB;
con_txt_mysql_username.Text = Properties.Settings.Default.MYSQL_User;
con_txt_mysql_password.Text = Properties.Settings.Default.MYSQL_Password;
con_txt_mysql_server.Text = Properties.Settings.Default.MYSQL_Server;
con_txt_mysql_port.Text = Properties.Settings.Default.MYSQL_Port;
con_txt_3rd_lotatc.Text = Properties.Settings.Default.OTHER_LOTATC_FILE;
con_txt_3rd_srs.Text = Properties.Settings.Default.OTHER_SRS_FILE;
con_check_3rd_lotatc.Checked = Properties.Settings.Default.OTHER_LOTATC_USE;
con_check_3rd_srs.Checked = Properties.Settings.Default.OTHER_SRS_USE;
}
private void form_Main_SaveSettings()
{
// Saves settings
Properties.Settings.Default.MYSQL_Server = con_txt_mysql_database.Text;
Properties.Settings.Default.MYSQL_DB = con_txt_mysql_database.Text;
Properties.Settings.Default.MYSQL_User = con_txt_mysql_username.Text;
Properties.Settings.Default.MYSQL_Password = con_txt_mysql_password.Text;
Properties.Settings.Default.MYSQL_Port = con_txt_mysql_port.Text;
Properties.Settings.Default.MYSQL_Server = con_txt_mysql_server.Text;
Properties.Settings.Default.MYSQL_Port = con_txt_mysql_port.Text;
Properties.Settings.Default.OTHER_LOTATC_FILE = con_txt_3rd_lotatc.Text;
Properties.Settings.Default.OTHER_SRS_FILE = con_txt_3rd_srs.Text;
Properties.Settings.Default.OTHER_LOTATC_USE = con_check_3rd_lotatc.Checked;
Properties.Settings.Default.OTHER_SRS_USE = con_check_3rd_srs.Checked;
Properties.Settings.Default.Save();
}
private void form_Main_DisableControls()
{
// Disables controls
con_Button_Listen_ON.Enabled = false;
con_Button_Listen_OFF.Enabled = true;
con_txt_mysql_database.Enabled = false;
con_txt_mysql_username.Enabled = false;
con_txt_mysql_password.Enabled = false;
con_txt_mysql_server.Enabled = false;
con_txt_mysql_port.Enabled = false;
con_txt_3rd_lotatc.Enabled = false;
con_txt_3rd_srs.Enabled = false;
con_check_3rd_lotatc.Enabled = false;
con_check_3rd_srs.Enabled = false;
}
private void form_Main_EnableControls()
{
// Enables controls
con_Button_Listen_ON.Enabled = true;
con_Button_Listen_OFF.Enabled = false;
con_txt_mysql_database.Enabled = true;
con_txt_mysql_username.Enabled = true;
con_txt_mysql_password.Enabled = true;
//con_txt_mysql_port.Enabled = true; // TBD - protect against writting text in the port field
con_txt_mysql_server.Enabled = true;
con_txt_3rd_lotatc.Enabled = true;
con_txt_3rd_srs.Enabled = true;
con_check_3rd_lotatc.Enabled = true;
con_check_3rd_srs.Enabled = true;
}
// ################################ User input ################################
private void con_Button_Listen_ON_Click(object sender, EventArgs e)
{
// Start listening
UDPController.Create(48620, ref Globals.arrLogHistory, ref arrSendBuffer);
UDPController.thrUDPListener = new Thread(UDPController.StartListen);
UDPController.thrUDPListener.Start();
UDPController.thrUDPListener.Name = "UDPThread";
form_Main_DisableControls(); // Disable controlls
form_Main_SaveSettings(); // Save settings
// Prepare connection string
DatabaseController.strMySQLConnectionString = "server=" + con_txt_mysql_server.Text + ";user=" + con_txt_mysql_username.Text + ";database=" + con_txt_mysql_database.Text + ";port=" + con_txt_mysql_port.Text + ";password=" + con_txt_mysql_password.Text;
// Start timmers
tim_200ms.Enabled = true;
tim_1000ms.Enabled = true;
tim_10000ms.Enabled = true;
}
private void con_Button_Listen_OFF_Click(object sender, EventArgs e)
{
// Stop listening
try
{
UDPController.StopListen();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
form_Main_EnableControls(); // Enable controls
// Stop timmers
tim_1000ms.Enabled = false;
tim_10000ms.Enabled = false;
tim_200ms.Enabled = false;
}
private void con_lab_github_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
// Open default browser with link to Perun repo
ProcessStartInfo sInfo = new ProcessStartInfo("https://github.com/szporwolik/perun");
Process.Start(sInfo);
}
private void con_txt_3rd_srs_Click(object sender, MouseEventArgs e)
{
// Chose SRS Json file
if (openFileDialog_SRS.ShowDialog() == DialogResult.OK)
{
con_txt_3rd_srs.Text = openFileDialog_SRS.FileName;
con_check_3rd_srs.Checked = true;
}
else
{
con_txt_3rd_srs.Text = "";
con_check_3rd_srs.Checked = false;
}
}
private void con_txt_3rd_lotatc_Click(object sender, MouseEventArgs e)
{
// Chose LotATC Json file
if (openFileDialog_LotATC.ShowDialog() == DialogResult.OK)
{
con_txt_3rd_lotatc.Text = openFileDialog_LotATC.FileName;
con_check_3rd_lotatc.Checked = true;
}
else
{
con_txt_3rd_lotatc.Text = "";
con_check_3rd_lotatc.Checked = false;
}
}
// ################################ Form state ################################
private void con_Button_Quit_Click(object sender, EventArgs e)
{
// Close app
DialogResult dialogResult = MessageBox.Show("Are you sure to exit Perun?", "Question", MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question);
if (dialogResult == DialogResult.Yes)
{
form_Main_SaveSettings();
boolLetMeOut = true; // Save settings on exit
this.Close(); // Allow to exit application
}
else if (dialogResult == DialogResult.No)
{
//do nothing
}
}
protected override void WndProc(ref Message m)
{
// Try to run of 2nd instance
if (m.Msg == NativeMethods.WM_SHOWME)
{
form_Main_BringFromTray();
}
base.WndProc(ref m);
}
private void form_Main_SendToTray()
{
// Sends app to system tray
trayIconMain.Visible = true;
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
}
private void form_Main_BringFromTray()
{
// Sends app from system tray
trayIconMain.Visible = false;
this.WindowState = FormWindowState.Normal;
this.ShowInTaskbar = true;
if (WindowState == FormWindowState.Minimized)
{
WindowState = FormWindowState.Normal;
}
// get our current "TopMost" value (ours will always be false though)
bool top = TopMost;
// make our form jump to the top of everything
TopMost = true;
// set it back to whatever it was
TopMost = top;
}
private void form_Main_FormClosing(object sender, FormClosingEventArgs e)
{
// Minimize to try on clicking "X"
if (e.CloseReason == CloseReason.UserClosing && !boolLetMeOut)
{
e.Cancel = true;
form_Main_SendToTray(); // Send app to system tray
}
}
private void trayIconMain_MouseDoubleClick(object sender, MouseEventArgs e)
{
// Maximize from tray
form_Main_BringFromTray(); // Bring app from system tray
}
// ################################ Timers ################################
private void timer1_Tick(object sender, EventArgs e)
{
// Main timer to sync GUI with background tasks and flush buffers
// Refresh Log Window
con_List_Received.Items.Clear();
foreach (string i in Globals.arrLogHistory)
{
if (i != null)
{
con_List_Received.Items.Add(i);
}
}
}
private void tim_200ms_Tick(object sender, EventArgs e)
{
// Send buffer to MySQL
for (int i = 0; i < arrSendBuffer.Length - 1; i++)
{
if (arrSendBuffer[i] != null)
{
DatabaseController.SendToMySql(arrSendBuffer[i]);
arrSendBuffer[i] = null;
}
}
}
private void tim_10000ms_Tick(object sender, EventArgs e)
{
// Main timer to send JSON files to MySQL
string strSRSJson = "";
string strLotATCJson = "";
bool boolSRSdefault = true;
bool boolLotATCdefault = true;
// Handle SRS
if (con_check_3rd_srs.Checked)
{
try
{
strSRSJson = System.IO.File.ReadAllText(con_txt_3rd_srs.Text);
dynamic raw_lotatc = JsonConvert.DeserializeObject(strSRSJson);
for (int i = 0; i < raw_lotatc.Count; i++)
{
if (raw_lotatc[i].RadioInfo != null)
{
int temp = raw_lotatc[i].RadioInfo.radios.Count - 1;
for (int j = temp; j >= 0; j--)
{
raw_lotatc[i].RadioInfo.radios[j].enc.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].encKey.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].encMode.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].freqMax.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].freqMin.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].modulation.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].freqMode.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].volMode.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].expansion.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].channel.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].simul.Parent.Remove();
if (raw_lotatc[i].RadioInfo.radios[j].name == "No Radio")
{
raw_lotatc[i].RadioInfo.radios[j].Remove();
}
}
raw_lotatc[i].ClientChannelId.Parent.Remove();
raw_lotatc[i].RadioInfo.simultaneousTransmission.Parent.Remove();
}
}
if (raw_lotatc.Count > 0)
{
strSRSJson = JsonConvert.SerializeObject(raw_lotatc);
strSRSJson = "{'type':'100','instance':'1','payload':'" + strSRSJson + "'}";
}
else
{
strSRSJson = "{'type':'100','instance':'1','payload':{'ignore':'false'}}"; // No SRS clients connected
}
boolSRSdefault = false;
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "SRS data loaded");
}
catch
{
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "SRS data ERROR");
}
}
if (boolSRSdefault)
{
strSRSJson = "{'type':'100','instance':'1','payload':{'ignore':'true'}}";
}
DatabaseController.SendToMySql(strSRSJson);
// Handle LotATC
if (con_check_3rd_lotatc.Checked)
{
try
{
strLotATCJson = System.IO.File.ReadAllText(con_txt_3rd_lotatc.Text);
dynamic raw_srs = JsonConvert.DeserializeObject(strLotATCJson);
strLotATCJson = "{'type':'101','instance':'1','payload':'" + strLotATCJson + "'}";
boolLotATCdefault = false;
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "LotATC data loaded");
}
catch
{
PerunHelper.LogHistoryAdd(ref Globals.arrLogHistory, "LotATC data ERROR");
}
}
if (boolLotATCdefault)
{
strLotATCJson = "{'type':'101','instance':'1','payload':{'ignore':'true'}}"; // No LotATC controller connected
}
DatabaseController.SendToMySql(strLotATCJson);
}
}
}

View File

@@ -416,6 +416,12 @@
<metadata name="tim_10000ms.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>563, 19</value>
</metadata>
<metadata name="tim_200ms.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>687, 19</value>
</metadata>
<metadata name="notifyIcon1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>797, 19</value>
</metadata>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAQD8AAAEAIAAgQQAAFgAAACgAAABAAAAAfgAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -33,7 +33,7 @@
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
<WebPage>Perun.htm</WebPage>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>0.3.5.%2a</ApplicationVersion>
<ApplicationVersion>0.5.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<CreateDesktopShortcut>true</CreateDesktopShortcut>
<PublishWizardCompleted>true</PublishWizardCompleted>
@@ -61,7 +61,7 @@
</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>perun_logo.ico</ApplicationIcon>
<ApplicationIcon>03_Resources\perun_logo.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>2ACE4C8C2C325A04CA5986B1CD76744B4B03755D</ManifestCertificateThumbprint>
@@ -116,15 +116,20 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="form_Main.cs">
<Compile Include="01_Classes\UDPController.cs" />
<Compile Include="01_Classes\Globals.cs" />
<Compile Include="01_Classes\DatabaseController.cs" />
<Compile Include="01_Classes\PerunHelper.cs" />
<Compile Include="01_Classes\NativeMethods.cs" />
<Compile Include="02_Forms\form_Main.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="form_Main.Designer.cs">
<Compile Include="02_Forms\form_Main.Designer.cs">
<DependentUpon>form_Main.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="01_Classes\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="form_Main.resx">
<EmbeddedResource Include="02_Forms\form_Main.resx">
<DependentUpon>form_Main.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
@@ -137,8 +142,8 @@
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="packages.config" />
<None Include="Perun_v1_TemporaryKey.pfx" />
<None Include="00_Config\packages.config" />
<None Include="00_Config\Perun_v1_TemporaryKey.pfx" />
<None Include="Properties\app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
@@ -151,7 +156,7 @@
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="00_Config\App.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.6.1">
@@ -166,10 +171,8 @@
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Content Include="perun_logo.ico" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Content Include="03_Resources\perun_logo.ico" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,32 +0,0 @@
using System;
using System.Windows.Forms;
namespace Perun_v1
{
static class Program
{
/// <summary>
/// Główny punkt wejścia dla aplikacji.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
void Application_ApplicationExit(object sender, EventArgs e)
{
Properties.Settings.Default.Save();
}
Application.Run(new form_Main());
}
}
}

View File

@@ -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
// przy użyciu symbolu „*”, tak jak pokazano poniżej:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.3.5.0")]
[assembly: AssemblyFileVersion("0.3.5.0")]
[assembly: AssemblyVersion("0.5.0.0")]
[assembly: AssemblyFileVersion("0.5.0.0")]
[assembly: NeutralResourcesLanguage("en")]

View File

@@ -1,488 +0,0 @@
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Perun_v1
{
public partial class form_Main : Form
{
// Variable definitions
public Thread thread_UDPListener; // Seperate thread for UDP
public class_UDPListener UDPListener; // Helper class for UDP comunication
public string[] LogHistory = new string[10]; // Log history for GUI
public string[] SendBuffer = new string[10]; // Mysql send buffer
public bool LetMeOut = false; // Helper to handle system tray
public string MySql_connStr; // MySQL connection string
public string publishVersion = "DEBUG"; // Helper for pulling version definition
public static void LogHistoryAdd(ref string[] LogHistory, string Comment)
{
// Add to log history and rotate
for (int i = 0; i < LogHistory.Length - 1; i++)
{
LogHistory[i] = LogHistory[i + 1];
}
LogHistory[9] = DateTime.Now.ToString("HH:mm:ss") + " > " + Comment;
}
public void SendToMySql(string raw_udp_frame)
{
// Main function to send data to mysql
dynamic udp_frame = JsonConvert.DeserializeObject(raw_udp_frame);
// Cut raw data to type and paylod for proper mysql insert
string type = udp_frame.type;
string payload = "";
string sql = "";
// Modify specific
if (type == "1") // Inject app version information
{
udp_frame.payload["v_win"] = "v" + publishVersion;
}
// Specific SQL
if (type == "50")
{
// Add entry to event log
sql = "INSERT INTO `pe_LogChat` (`pe_LogChat_id`,`pe_LogChat_datetime`, `pe_LogChat_playerid`, `pe_LogChat_msg`, `pe_LogChat_all`) VALUES (NULL,'" + udp_frame.payload.datetime + "', '" + udp_frame.payload.player + "', '" + udp_frame.payload.msg + "', '" + udp_frame.payload.all + "');";
}
else if (type == "51")
{
// Add entry to event log
sql = "INSERT INTO `pe_LogEvent` (`pe_LogEvent_id`, `pe_LogEvent_datetime`, `pe_LogEvent_type`, `pe_LogEvent_content`,`pe_LogEvent_missionhash`) VALUES ( NULL, '" + udp_frame.payload.log_datetime + "', '" + udp_frame.payload.log_type + "', '" + udp_frame.payload.log_content + "', '" + udp_frame.payload.log_missionhash + "');";
}
else if (type == "52")
{
// Update user stats
payload = JsonConvert.SerializeObject(udp_frame.payload.stat_data);
sql = "INSERT INTO `pe_LogStats` (`pe_LogStats_datetime`, `pe_LogStats_ucid`, `pe_LogStats_debug`,`pe_LogStats_missionhash`) VALUES ('" + udp_frame.payload.stat_datetime + "', '" + udp_frame.payload.stat_ucid + "', JSON_QUOTE('" + payload + "'), '" + udp_frame.payload.stat_missionhash + "') ON DUPLICATE KEY UPDATE pe_LogStats_datetime='" + udp_frame.payload.stat_datetime + "',pe_LogStats_ucid = '" + udp_frame.payload.stat_ucid + "', pe_LogStats_debug=JSON_QUOTE('" + payload + "'), pe_LogStats_missionhash='" + udp_frame.payload.stat_missionhash + "'";
}
else if (type == "53")
{
// User logged in to DCS server
payload = JsonConvert.SerializeObject(udp_frame.payload.stat_data);
sql = "INSERT INTO `pe_LogLogins` (`pe_LogLogins_datetime`, `pe_LogLogins_ucid`, `pe_LogLogins_name`, `pe_LogLogins_ip`) VALUES ('" + udp_frame.payload.login_datetime + "', '" + udp_frame.payload.login_ucid + "', '" + udp_frame.payload.login_name + "', '" + udp_frame.payload.login_ipaddr + "');";
sql = sql + "INSERT INTO `pe_DataPlayers` (`pe_DataPlayers_id`, `pe_DataPlayers_ucid`, `pe_DataPlayers_lastip`, `pe_DataPlayers_lastname`, `pe_DataPlayers_updated`) VALUES (NULL, '" + udp_frame.payload.login_ucid + "', '" + udp_frame.payload.login_ipaddr + "', '" + udp_frame.payload.login_name + "', '" + udp_frame.payload.login_datetime + "') ON DUPLICATE KEY UPDATE pe_DataPlayers_lastip='" + udp_frame.payload.login_ipaddr + "',pe_DataPlayers_lastname='" + udp_frame.payload.login_name + "',pe_DataPlayers_updated='" + udp_frame.payload.login_datetime + "'";
}
else
{
// General definition used for 1-10 packets
payload = JsonConvert.SerializeObject(udp_frame.payload);
sql = "INSERT INTO pe_DataRaw(pe_dataraw_type,pe_dataraw_payload) VALUES (" + type + ",JSON_QUOTE('" + payload + "')) ON DUPLICATE KEY UPDATE pe_dataraw_payload = JSON_QUOTE('" + payload + "')";
}
// Connect to mysql and execute sql
MySqlConnection conn = new MySqlConnection(MySql_connStr);
try
{
Console.WriteLine("Sending data to MySQL - Begin");
conn.Open();
MySqlCommand cmd = new MySqlCommand(sql, conn);
MySqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr[0] + " -- " + rdr[1]);
}
rdr.Close();
LogHistoryAdd(ref LogHistory, "MySQL updated, package type: " + type);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
LogHistoryAdd(ref LogHistory, "ERROR: MySQL");
}
conn.Close();
Console.WriteLine("Sending data to MySQL - Done");
}
public class class_UDPListener
{
// Main class for UDP listener
int listenPort; // Port to listen at
public bool done; // Helper to exit main loop without killing thread
public UdpClient listener; // Listener object
public string[] LogHistory; // Log history for GUI
public string[] SendBuffer; // Mysql send buffer
public class_UDPListener(int port, ref string[] LogHistory, ref string[] SendBuffer)
{
// Create clas - NOTE that there is reference passing
this.listenPort = port;
this.LogHistory = LogHistory;
this.SendBuffer = SendBuffer;
}
public void StartListen()
{
// Start listening to UDP
this.done = false;
listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Loopback, listenPort);
string received_data;
byte[] receive_byte_array;
Console.WriteLine("UDP Listen start");
try
{
while (!done)
{
Console.WriteLine("UDP: Waiting for packet");
receive_byte_array = listener.Receive(ref groupEP);
received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
Console.WriteLine("Sender: {0} Payload: {1}", groupEP.ToString(), received_data);
// Add to log history and rotate
dynamic udp_frame = JsonConvert.DeserializeObject(received_data);
string type = udp_frame.type;
LogHistoryAdd(ref LogHistory, "UDP packet received, type: " + type);
// Add to mySQL send buffer and rotate
for (int i = 0; i < SendBuffer.Length - 1; i++)
{
SendBuffer[i] = SendBuffer[i + 1];
}
SendBuffer[9] = received_data;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("UDP listen stop");
listener.Close();
}
}
public form_Main()
{
// Form init
InitializeComponent();
}
private void form_Main_Load(object sender, EventArgs e)
{
// Form loaded - fill controls with default values
LogHistory[0] = DateTime.Now.ToString("HH:mm:ss") + " > " + "Perun loaded...";
// Load settings
con_txt_mysql_database.Text = Properties.Settings.Default.MYSQL_DB;
con_txt_mysql_username.Text = Properties.Settings.Default.MYSQL_User;
con_txt_mysql_password.Text = Properties.Settings.Default.MYSQL_Password;
con_txt_mysql_server.Text = Properties.Settings.Default.MYSQL_Server;
con_txt_mysql_port.Text = Properties.Settings.Default.MYSQL_Port;
con_txt_3rd_lotatc.Text = Properties.Settings.Default.OTHER_LOTATC_FILE;
con_txt_3rd_srs.Text = Properties.Settings.Default.OTHER_SRS_FILE;
con_check_3rd_lotatc.Checked = Properties.Settings.Default.OTHER_LOTATC_USE;
con_check_3rd_srs.Checked = Properties.Settings.Default.OTHER_SRS_USE;
// Version to title header
if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
{
System.Deployment.Application.ApplicationDeployment cd = System.Deployment.Application.ApplicationDeployment.CurrentDeployment;
publishVersion = cd.CurrentVersion.ToString();
}
this.Text = this.Text + " - v" + publishVersion;
}
private void con_Button_Listen_ON_Click(object sender, EventArgs e)
{
// Start listening
UDPListener = new class_UDPListener(48620, ref LogHistory, ref SendBuffer);
thread_UDPListener = new Thread(UDPListener.StartListen);
thread_UDPListener.Start();
// Update form controls
con_Button_Listen_ON.Enabled = false;
con_Button_Listen_OFF.Enabled = true;
con_txt_mysql_database.Enabled = false;
con_txt_mysql_username.Enabled = false;
con_txt_mysql_password.Enabled = false;
con_txt_mysql_server.Enabled = false;
con_txt_mysql_port.Enabled = false;
con_txt_3rd_lotatc.Enabled = false;
con_txt_3rd_srs.Enabled = false;
con_check_3rd_lotatc.Enabled = false;
con_check_3rd_srs.Enabled = false;
// Save settings
Properties.Settings.Default.MYSQL_Server = con_txt_mysql_database.Text;
Properties.Settings.Default.MYSQL_DB = con_txt_mysql_database.Text;
Properties.Settings.Default.MYSQL_User = con_txt_mysql_username.Text;
Properties.Settings.Default.MYSQL_Password = con_txt_mysql_password.Text;
Properties.Settings.Default.MYSQL_Port = con_txt_mysql_port.Text;
Properties.Settings.Default.MYSQL_Server = con_txt_mysql_server.Text;
Properties.Settings.Default.MYSQL_Port = con_txt_mysql_port.Text;
Properties.Settings.Default.OTHER_LOTATC_FILE = con_txt_3rd_lotatc.Text;
Properties.Settings.Default.OTHER_SRS_FILE = con_txt_3rd_srs.Text;
Properties.Settings.Default.OTHER_LOTATC_USE = con_check_3rd_lotatc.Checked;
Properties.Settings.Default.OTHER_SRS_USE = con_check_3rd_srs.Checked;
// Prepare connection string
MySql_connStr = "server=" + con_txt_mysql_server.Text + ";user=" + con_txt_mysql_username.Text + ";database=" + con_txt_mysql_database.Text + ";port=" + con_txt_mysql_port.Text + ";password=" + con_txt_mysql_password.Text;
// Start timmers
tim_1000ms.Enabled = true;
tim_10000ms.Enabled = true;
}
private void con_Button_Listen_OFF_Click(object sender, EventArgs e)
{
// Stop listening
UDPListener.listener.Close();
// Update form controls
con_Button_Listen_ON.Enabled = true;
con_Button_Listen_OFF.Enabled = false;
con_txt_mysql_database.Enabled = true;
con_txt_mysql_username.Enabled = true;
con_txt_mysql_password.Enabled = true;
con_txt_mysql_port.Enabled = true;
con_txt_mysql_server.Enabled = true;
con_txt_3rd_lotatc.Enabled = true;
con_txt_3rd_srs.Enabled = true;
con_check_3rd_lotatc.Enabled = true;
con_check_3rd_srs.Enabled = true;
// Stop timmers
tim_1000ms.Enabled = false;
tim_10000ms.Enabled = false;
}
private void timer1_Tick(object sender, EventArgs e)
{
// Main timer to sync GUI with background tasks and flush buffers
// Refresh Log Window
con_List_Received.Items.Clear();
foreach (string i in LogHistory)
{
if (i != null)
{
con_List_Received.Items.Add(i);
}
}
// Send buffer to MySQL
for (int i = 0; i < SendBuffer.Length - 1; i++)
{
if (SendBuffer[i] != null)
{
SendToMySql(SendBuffer[i]);
SendBuffer[i] = null;
}
}
}
private void con_lab_github_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
// Open default browser with link to Perun repo
ProcessStartInfo sInfo = new ProcessStartInfo("https://github.com/szporwolik/perun");
Process.Start(sInfo);
}
private void con_Button_Quit_Click(object sender, EventArgs e)
{
// Close app
DialogResult dialogResult = MessageBox.Show("Are you sure to exit Perun?", "Question", MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question);
if (dialogResult == DialogResult.Yes)
{
// Save settings on exit
Properties.Settings.Default.MYSQL_Server = con_txt_mysql_database.Text;
Properties.Settings.Default.MYSQL_DB = con_txt_mysql_database.Text;
Properties.Settings.Default.MYSQL_User = con_txt_mysql_username.Text;
Properties.Settings.Default.MYSQL_Password = con_txt_mysql_password.Text;
Properties.Settings.Default.MYSQL_Port = con_txt_mysql_port.Text;
Properties.Settings.Default.MYSQL_Server = con_txt_mysql_server.Text;
Properties.Settings.Default.MYSQL_Port = con_txt_mysql_port.Text;
Properties.Settings.Default.OTHER_LOTATC_FILE = con_txt_3rd_lotatc.Text;
Properties.Settings.Default.OTHER_SRS_FILE = con_txt_3rd_srs.Text;
Properties.Settings.Default.OTHER_LOTATC_USE = con_check_3rd_lotatc.Checked;
Properties.Settings.Default.OTHER_SRS_USE = con_check_3rd_srs.Checked;
Properties.Settings.Default.Save();
LetMeOut = true;
this.Close();
}
else if (dialogResult == DialogResult.No)
{
//do nothing
}
}
private void form_Main_FormClosing(object sender, FormClosingEventArgs e)
{
// Minimize to try
if (e.CloseReason == CloseReason.UserClosing && !LetMeOut)
{
e.Cancel = true;
trayIconMain.Visible = true;
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
//this.Hide();
}
}
private void trayIconMain_MouseDoubleClick(object sender, MouseEventArgs e)
{
// Maximize from try
trayIconMain.Visible = false;
this.WindowState = FormWindowState.Normal;
this.ShowInTaskbar = true;
}
private void con_txt_3rd_srs_Click(object sender, MouseEventArgs e)
{
// Chose SRS Json file
if (openFileDialog_SRS.ShowDialog() == DialogResult.OK)
{
con_txt_3rd_srs.Text = openFileDialog_SRS.FileName;
con_check_3rd_srs.Checked = true;
}
else
{
con_txt_3rd_srs.Text = "";
con_check_3rd_srs.Checked = false;
}
}
private void con_txt_3rd_lotatc_Click(object sender, MouseEventArgs e)
{
// Chose LotATC Json file
if (openFileDialog_LotATC.ShowDialog() == DialogResult.OK)
{
con_txt_3rd_lotatc.Text = openFileDialog_LotATC.FileName;
con_check_3rd_lotatc.Checked = true;
}
else
{
con_txt_3rd_lotatc.Text = "";
con_check_3rd_lotatc.Checked = false;
}
}
private void tim_10000ms_Tick(object sender, EventArgs e)
{
// Main timer to send JSON files to MySQL
string strSRSJson = "";
string strLotATCJson = "";
bool SRSdefault = true;
bool LotATCdefault = true;
// Handle SRS
if (con_check_3rd_srs.Checked)
{
try
{
strSRSJson = System.IO.File.ReadAllText(con_txt_3rd_srs.Text);
dynamic raw_lotatc = JsonConvert.DeserializeObject(strSRSJson);
for (int i = 0; i < raw_lotatc.Count; i++)
{
if (raw_lotatc[i].RadioInfo != null)
{
int temp = raw_lotatc[i].RadioInfo.radios.Count - 1;
for (int j = temp; j >= 0; j--)
{
raw_lotatc[i].RadioInfo.radios[j].enc.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].encKey.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].encMode.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].freqMax.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].freqMin.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].modulation.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].freqMode.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].volMode.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].expansion.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].channel.Parent.Remove();
raw_lotatc[i].RadioInfo.radios[j].simul.Parent.Remove();
if (raw_lotatc[i].RadioInfo.radios[j].name == "No Radio")
{
raw_lotatc[i].RadioInfo.radios[j].Remove();
}
}
raw_lotatc[i].ClientChannelId.Parent.Remove();
raw_lotatc[i].RadioInfo.simultaneousTransmission.Parent.Remove();
}
}
if (raw_lotatc.Count > 0)
{
strSRSJson = JsonConvert.SerializeObject(raw_lotatc);
strSRSJson = "{'type':'100','payload':'" + strSRSJson + "'}";
}
else
{
strSRSJson = "{'type':'100','payload':{'ignore':'false'}}";
}
SRSdefault = false;
LogHistoryAdd(ref LogHistory, "SRS data loaded");
}
catch
{
LogHistoryAdd(ref LogHistory, "SRS data ERROR");
}
}
if (SRSdefault)
{
strSRSJson = "{'type':'100','payload':{'ignore':'true'}}";
}
SendToMySql(strSRSJson);
// Handle LotATC
if (con_check_3rd_lotatc.Checked)
{
try
{
strLotATCJson = System.IO.File.ReadAllText(con_txt_3rd_lotatc.Text);
dynamic raw_srs = JsonConvert.DeserializeObject(strLotATCJson);
strLotATCJson = "{'type':'101','payload':'" + strLotATCJson + "'}";
LotATCdefault = false;
LogHistoryAdd(ref LogHistory, "LotATC data loaded");
}
catch
{
LogHistoryAdd(ref LogHistory, "LotATC data ERROR");
}
}
if (LotATCdefault)
{
strLotATCJson = "{'type':'101','payload':{'ignore':'true'}}";
}
SendToMySql(strLotATCJson);
}
}
}

View File

@@ -1,4 +1,5 @@
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
@@ -18,6 +19,23 @@ USE `m1081_perun`;
-- --------------------------------------------------------
--
-- Struktura tabeli dla tabeli `pe_DataMissionHashes`
--
DROP TABLE IF EXISTS `pe_DataMissionHashes`;
CREATE TABLE IF NOT EXISTS `pe_DataMissionHashes` (
`pe_DataMissionHashes_id` bigint(20) NOT NULL AUTO_INCREMENT,
`pe_DataMissionHashes_instance` smallint(5) UNSIGNED NOT NULL,
`pe_DataMissionHashes_hash` varchar(150) NOT NULL,
`pe_DataMissionHashes_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`pe_DataMissionHashes_id`),
UNIQUE KEY `UNIQUE_hash` (`pe_DataMissionHashes_hash`),
KEY `pe_DataMissionHashes_instance` (`pe_DataMissionHashes_instance`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Struktura tabeli dla tabeli `pe_DataPlayers`
--
@@ -41,10 +59,11 @@ CREATE TABLE IF NOT EXISTS `pe_DataPlayers` (
DROP TABLE IF EXISTS `pe_DataRaw`;
CREATE TABLE IF NOT EXISTS `pe_DataRaw` (
`pe_dataraw_type` tinyint(4) NOT NULL AUTO_INCREMENT,
`pe_dataraw_type` tinyint(4) NOT NULL,
`pe_dataraw_instance` smallint(5) UNSIGNED NOT NULL,
`pe_dataraw_payload` text NOT NULL,
`pe_dataraw_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`pe_dataraw_type`)
PRIMARY KEY (`pe_dataraw_type`,`pe_dataraw_instance`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -57,10 +76,13 @@ DROP TABLE IF EXISTS `pe_LogChat`;
CREATE TABLE IF NOT EXISTS `pe_LogChat` (
`pe_LogChat_id` bigint(20) NOT NULL AUTO_INCREMENT,
`pe_LogChat_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`pe_LogChat_missionhash_id` bigint(20) DEFAULT NULL,
`pe_LogChat_playerid` varchar(100) NOT NULL,
`pe_LogChat_msg` text NOT NULL,
`pe_LogChat_all` varchar(10) NOT NULL,
PRIMARY KEY (`pe_LogChat_id`)
PRIMARY KEY (`pe_LogChat_id`),
KEY `pe_LogChat_missionhash_id` (`pe_LogChat_missionhash_id`),
KEY `pe_LogChat_playerid` (`pe_LogChat_playerid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -72,11 +94,14 @@ CREATE TABLE IF NOT EXISTS `pe_LogChat` (
DROP TABLE IF EXISTS `pe_LogEvent`;
CREATE TABLE IF NOT EXISTS `pe_LogEvent` (
`pe_LogEvent_id` bigint(20) NOT NULL AUTO_INCREMENT,
`pe_LogEvent_missionhash` varchar(150) DEFAULT NULL,
`pe_LogEvent_missionhash_id` bigint(20) DEFAULT NULL,
`pe_LogEvent_datetime` datetime DEFAULT CURRENT_TIMESTAMP,
`pe_LogEvent_type` varchar(100) NOT NULL,
`pe_LogEvent_content` text NOT NULL,
PRIMARY KEY (`pe_LogEvent_id`)
`pe_LogEvent_arg1` varchar(150) DEFAULT NULL,
`pe_LogEvent_arg2` varchar(150) DEFAULT NULL,
PRIMARY KEY (`pe_LogEvent_id`),
KEY `pe_LogEvent_missionhash_id` (`pe_LogEvent_missionhash_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -87,10 +112,14 @@ CREATE TABLE IF NOT EXISTS `pe_LogEvent` (
DROP TABLE IF EXISTS `pe_LogLogins`;
CREATE TABLE IF NOT EXISTS `pe_LogLogins` (
`pe_LogLogins_id` bigint(20) NOT NULL AUTO_INCREMENT,
`pe_LogLogins_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`pe_LogLogins_ucid` varchar(150) NOT NULL,
`pe_LogLogins_instance` smallint(5) UNSIGNED NOT NULL,
`pe_LogLogins_playerid` bigint(20) DEFAULT NULL,
`pe_LogLogins_name` varchar(150) NOT NULL,
`pe_LogLogins_ip` varchar(100) NOT NULL
`pe_LogLogins_ip` varchar(100) NOT NULL,
PRIMARY KEY (`pe_LogLogins_id`),
KEY `pe_LogLogins_playerid` (`pe_LogLogins_playerid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
@@ -102,12 +131,36 @@ CREATE TABLE IF NOT EXISTS `pe_LogLogins` (
DROP TABLE IF EXISTS `pe_LogStats`;
CREATE TABLE IF NOT EXISTS `pe_LogStats` (
`pe_LogStats_id` bigint(20) NOT NULL AUTO_INCREMENT,
`pe_LogStats_missionhash` varchar(150) DEFAULT NULL,
`pe_LogStats_missionhash_id` bigint(20) DEFAULT NULL,
`pe_LogStats_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`pe_LogStats_ucid` varchar(200) NOT NULL,
`pe_LogStats_playerid` bigint(20) DEFAULT NULL,
`pe_LogStats_type` varchar(50) DEFAULT NULL,
`pe_LogStats_debug` text,
`pe_LogStats_dcs` text,
`pe_LogStats_perun` text,
`ps_kills` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_pvp` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_deaths` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_ejections` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_crashes` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_teamkills` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_planes` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_helicopters` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_air_defense` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_armor` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_unarmed` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_infantry` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_ships` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_kills_other` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_airfield_takeoffs` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_airfield_landings` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_ship_takeoffs` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_ship_landings` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_farp_takeoffs` int(11) UNSIGNED NOT NULL DEFAULT '0',
`ps_farp_landings` int(11) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`pe_LogStats_id`),
UNIQUE KEY `UNIQUE_STATS_PER_MISSION_AND_UCID` (`pe_LogStats_ucid`,`pe_LogStats_missionhash`)
UNIQUE KEY `UNIQUE_STATS_PER_MISSION_AND_UCID_AND_TYPE` (`pe_LogStats_playerid`,`pe_LogStats_missionhash_id`,`pe_LogStats_type`) USING BTREE,
KEY `pe_LogStats_type` (`pe_LogStats_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
COMMIT;

View File

@@ -1,10 +1,15 @@
![alt text](https://img.shields.io/github/license/szporwolik/perun.svg "MIT")
![alt text](https://img.shields.io/github/release-pre/szporwolik/perun.svg "Latest release")
![alt text](https://img.shields.io/github/release-date-pre/szporwolik/perun.svg "Latest release date")
# Perun for DCS World
This toolset extracts data from DCS World server and sends information to the local Json file and UDP port.
This toolset extracts data from DCS World server and sends information to the local Json file and UDP port for further processing.
Provided windows app puts JSON data to MySQL database. Additionaly Perun windows app can be used to merge LotATC and DCS SRS data in one database making Perun for DCS World wannabe ultimate integration tool for the server admins.
Provided windows app puts received UDP packets to MySQL database. Additionaly Perun windows application can be used to merge LotATC and DCS SRS data in one database making Perun for DCS World wannabe ultimate integration tool for the server admins.
However this software is intended to be used by experienced users - the output is data Json and MySQL; you will need to process/display it yourself.
However, this software is intended to be used by experienced users - the output is Json data and MySQL; you will need to process/display it yourself.
![Perun in action](https://i.imgur.com/ougQMPq.png)
![Data flow](https://i.imgur.com/sHDQoLM.png)
@@ -15,15 +20,16 @@ Core:
* For JSON Export:
* DCS World stable or DCS World beta
* **(Optional)** For MySQL Export:
* MySQL server with read/write access
* MySQL server with read/write access (tested with v5.7.21)
* .NET Framework 4.6.1
3rd party support:
3rd party applications support:
* for [DCS SRS](https://github.com/ciribob/DCS-SimpleRadioStandalone/releases) integration location of the clients-list.json file will be required (by default: SRS Server folder), "Auto Export List" option has to be enabled - see [SRS documentation](https://github.com/ciribob/DCS-SimpleRadioStandalone/wiki)
* for [LotATC](https://www.lotatc.com/) you will need location of stats.json file and proper LotATC configuration with JSON data export enabled - see [LotATC documentation](https://www.lotatc.com/documentation/server_configuration.html)
### Installing
* Download latest [release](https://github.com/szporwolik/perun/releases), **optionaly** together with Win32 binary file for MySQL export - [DOWNLOAD](http://share.porwolik.com/ftp/perun/Perun.htm)
* Download latest [release](https://github.com/szporwolik/perun/releases), **optionaly** together with windows binary file for MySQL export - [DOWNLOAD](http://share.porwolik.com/ftp/perun/Perun.htm)
* Copy contents of [01_DCS](https://github.com/szporwolik/perun/tree/master/01_DCS) to your \Scripts folder (located inside DCS folder in your Saved Games)
* **optionaly** Create MySQL server using SQL script located in [03_MySQL](https://github.com/szporwolik/perun/tree/master/03_MySQL)
* **optionaly** Run the Win32 application
@@ -34,22 +40,23 @@ Core:
* Start DCS World and host multiplayer session
* by default the JSON is written into Scripts\Json folder located in your Saved Games DCS folder tree
* by default the UDP port 48620 is in use as target port
* Data shall be filling your MySQL database
## Data packets
* ID: 1, contains version information
* ID: 2, contains status data in the following sections
* mission - minimal information
* ```ID: 1```, contains version/diagnostic information
* ```ID: 2```, contains status data in the following sections
* mission - minimal information about mission
* players - connected players
* ID: 3, available slots list and coalitions
* ```ID: 3```, available slots list and coalitions
* coalitions - available coalitions
* slots - available slots
* ID: 4, stores mission data **ONLY JSON FILE**
* ID: 50, chat event
* ID: 51, game event
* ID: 52, player stats
* ID: 53, player login to DCS server
* ID: 100, DCS SRS's client-list.json
* ID: 101, LotATC's stats.json
* ```ID: 4```, stores mission data **WIP: not yet implemented**
* ```ID: 50```, chat event
* ```ID: 51```, game event
* ```ID: 52```, player stats **WIP: not yet implemented**
* ```ID: 53```, player login to DCS server
* ```ID: 100```, DCS SRS's client-list.json
* ```ID: 101```, LotATC's stats.json
## Built With