using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Timers;
using System.Xml;
using System.Xml.Serialization;
namespace AutobotManager
{
public enum BotState
{
BotState_Invalid = -1,
BotState_IDLE,
BotState_Running,
BotState_Dying,
BotState_Max,
};
public class BotManager
{
public class GameSettingsDefinition
{
[XmlElement("GameName")]
public string m_GameName;
[XmlElement("BotPath")]
public string m_BotPath;
[XmlElement("BotArgs")]
public string m_BotArgs;
[XmlArray("BotStyles"), XmlArrayItem("Item", typeof(string))]
public string[] m_BotStyles;
[XmlElement("AutobotServer")]
public string m_AutobotServer;
[XmlElement("AutobotServerPort")]
public string m_AutobotServerPort;
[XmlElement("AutobotScript")]
public string m_AutobotScript;
[XmlElement("BotIdentifierArg")]
public string m_BotIdentifierArg;
[XmlElement("BotStyleArg")]
public string m_BotStyleArg;
[XmlElement("BotStyleArgPassingMethod")]
public string m_BotStyleArgPassingMethod;
[XmlElement("BotScriptArg")]
public string m_BotScriptArg;
}
[XmlRootAttribute("root", ElementName = "BotManagerSettings", Namespace = "", IsNullable = false)]
public class SettingsDefinition
{
[XmlArray("Games"), XmlArrayItem("Game", typeof(GameSettingsDefinition))]
public GameSettingsDefinition[] m_Settings;
public bool m_valid;
}
#region Data
public SettingsDefinition m_Settings;
public String m_GameName;
private BindingList<BotClass> m_BotList;
private List<int> m_lFreeBotIDList;
private int m_iMaxActiveBotIdCounter;
private int m_iTotalNewInstanceCounter;
private String m_sAppPath;
private String m_sAppArgs;
private int m_iMaxDataPrefix;
private int m_iNextSim;
private int m_iNextDataPrefix;
private Form1 m_pParentForm;
private Random m_oRandom;
private BindingList<BotStyleRequired> m_BotStyleRequired;
private BindingList<BotStyleItem> m_BotStyleList;
private BindingList<BotStatusItem> m_BotStatusList;
private BindingList<BotStatusItem> m_BotMetricList;
private BindingList<BotStatusItem> m_BotGlobalStatusCountList;
private int[] m_aiTotalStateCount;
public int TotalCreated { get; set; }
public int TotalCrashed { get; set; }
public int TotalKilled { get; set; }
#endregion // Data
public BotManager(Form1 a_pParentForm)
{
m_BotList = new BindingList<BotClass>();
m_lFreeBotIDList = new List<int>();
m_oRandom = new Random();
m_iMaxDataPrefix = -1;
m_iNextDataPrefix = -1;
m_iMaxActiveBotIdCounter = 0;
m_iTotalNewInstanceCounter = 0;
m_sAppPath = "";
m_sAppArgs = "";
m_iNextSim = 0;
m_pParentForm = a_pParentForm;
m_aiTotalStateCount = new int[(int)BotState.BotState_Max];
m_BotStyleRequired = new BindingList<BotStyleRequired>();
m_BotStyleList = new BindingList<BotStyleItem>();
m_BotStatusList = new BindingList<BotStatusItem>();
m_BotMetricList = new BindingList<BotStatusItem>();
m_BotGlobalStatusCountList = new BindingList<BotStatusItem>();
m_oRandom = new Random();
TotalCreated = 0;
TotalCrashed = 0;
TotalKilled = 0;
m_GameName = "";
ParseSettings("GameBots.settings");
UpdateGameStyles();
}
public void UpdateGameStyles()
{
m_BotStyleRequired.Clear();
m_BotStyleList.Clear();
GameSettingsDefinition settings = GetGamesSettings();
if (settings != null)
{
String[] a_sBotStyles = settings.m_BotStyles;
for (int i = 0; i < a_sBotStyles.Count(); ++i)
{
m_BotStyleRequired.Add(new BotStyleRequired(a_sBotStyles[i], i, 0));
m_BotStyleList.Add(new BotStyleItem(a_sBotStyles[i], i));
}
}
}
#region Misc
public void UpdateFromCommandLine(String[] args)
{
for (int i = 0; i < args.Length; i++)
{
if (0 == String.Compare(args[i], "--botpair", true) && ((i + 2) < args.Length))
{
int iStyle = 0;
int iCount = 0;
bool bOkStyle = Int32.TryParse(args[i + 1], out iStyle);
bool bOkCount = Int32.TryParse(args[i + 2], out iCount);
if (bOkStyle && bOkCount)
{
SetBotPair(iStyle, iCount);
}
i += 2;
}
}
}
public void SetBotPair(int a_iStyle, int a_iCount)
{
if (a_iStyle >= 0 && a_iStyle < m_BotStyleRequired.Count() && a_iCount >= 0)
{
m_BotStyleRequired[a_iStyle].RequiredCount = a_iCount;
}
}
public void ParseSettings(string settings)
{
try
{
using (System.IO.TextReader reader = new System.IO.StreamReader(settings))
{
XmlSerializer serializer = new XmlSerializer(typeof(SettingsDefinition));
m_Settings = serializer.Deserialize(reader) as SettingsDefinition;
m_Settings.m_valid = true;
reader.Close();
}
}
catch (Exception e)
{
MessageBox.Show(
"Couldn't load '" + settings + "':\r\n" + e.Message,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
m_Settings.m_valid = false;
}
}
public GameSettingsDefinition GetGamesSettings()
{
if (m_Settings.m_valid)
{
for (int i = 0; i < m_Settings.m_Settings.Count(); ++i)
{
if (m_Settings.m_Settings[i].m_GameName == m_GameName)
{
return m_Settings.m_Settings[i];
}
}
}
return null;
}
public String[] GetGamesList()
{
String[] aList = {};
if (m_Settings.m_valid)
{
aList = new String[m_Settings.m_Settings.Count()];
for (int i = 0; i < m_Settings.m_Settings.Count(); ++i)
{
aList.SetValue(m_Settings.m_Settings[i].m_GameName, i);
}
}
return aList;
}
public String GetArgs(string a_sArgs, int a_iDataPrefix, int a_iNextBotid, int a_iSimId, string a_sAppPath)
{
String sTempArg = a_sArgs;
if (a_iDataPrefix >= 0)
{
sTempArg = sTempArg.Replace("\\data\\", "\\" + a_iDataPrefix.ToString() + "data\\");
sTempArg = sTempArg.Replace("\\iosdata", "\\" + a_iDataPrefix.ToString() + "iosdata");
}
GameSettingsDefinition settings = GetGamesSettings();
if (settings != null)
{
String sBotScript = settings.m_AutobotScript;
try
{
sBotScript = "\"" + System.IO.Path.GetDirectoryName(a_sAppPath) + "\\" + sBotScript + "\"";
}
catch
{
}
if (settings.m_BotStyleArgPassingMethod == "PassByIndex")
{
sTempArg += " " + String.Format(settings.m_BotStyleArg, a_iSimId);
}
else
{
Debug.Assert(settings.m_BotStyleArgPassingMethod == "PassByString");
sTempArg += " " + String.Format(settings.m_BotStyleArg, m_BotStyleList[a_iSimId].SimName);
}
sTempArg += " " + String.Format(settings.m_BotIdentifierArg, m_pParentForm.m_TcpClient.MachineShortID, a_iNextBotid);
sTempArg += " " + String.Format(settings.m_BotScriptArg, sBotScript);
}
return sTempArg;
}
public String GetPreviewArgs(int a_botStyle)
{
int iNextBotiD = PeekFreeBotiD();
return GetArgs(m_sAppArgs, m_iNextDataPrefix, iNextBotiD, a_botStyle, m_sAppPath);
}
#endregion
#region Bot Statistitics
public int GetStateTotalCount(BotState a_eState)
{
return m_aiTotalStateCount[(int)a_eState];
}
public void BotStateChanged(BotClass aBot, BotState a_eOldState)
{
BotState a_eNewState = aBot.GetBotState();
if (BotState.BotState_Invalid != a_eOldState)
{
m_BotStyleList[aBot.BotLogicID].ReduceStateType(a_eOldState);
--m_aiTotalStateCount[(int)a_eOldState];
}
if (BotState.BotState_Invalid != a_eNewState)
{
m_BotStyleList[aBot.BotLogicID].AddStateType(a_eNewState);
++m_aiTotalStateCount[(int)a_eNewState];
}
}
public void BotMetricEncountered(BotClass aBot, String a_sMetric)
{
foreach (var vMetric in m_BotMetricList)
{
if (vMetric.Status.Equals(a_sMetric))
{
vMetric.Increment();
return;
}
}
m_BotMetricList.Add(new BotStatusItem(a_sMetric, 1));
}
public void BotLuaStatusChanged(BotClass aBot, String a_sOldStatus)
{
foreach (var vStatus in m_BotStatusList)
{
if (vStatus.Status.Equals(a_sOldStatus))
{
vStatus.Decrement();
if (0 == vStatus.CurrentCount)
{
m_BotStatusList.Remove(vStatus);
}
break;
}
}
String sNewStatus = aBot.GetLuaBotState();
if(sNewStatus.Length > 0)
{
bool bFound = false;
foreach (var vStatus in m_BotGlobalStatusCountList)
{
if (vStatus.Status.Equals(sNewStatus))
{
vStatus.Increment();
bFound = true;
break;
}
}
if (!bFound)
{
m_BotGlobalStatusCountList.Add(new BotStatusItem(sNewStatus, 1));
}
foreach (var vStatus in m_BotStatusList)
{
if (vStatus.Status.Equals(sNewStatus))
{
vStatus.Increment();
return;
}
}
m_BotStatusList.Add(new BotStatusItem(sNewStatus, 1));
}
}
public int GetTotalRequiredCount()
{
int iTotal = 0;
for (int i = 0; i < m_BotStyleRequired.Count(); ++i)
{
iTotal += m_BotStyleRequired[i].RequiredCount;
}
return iTotal;
}
public int GetNextRandomSimToLaunch()
{
List<KeyValuePair<int, int>> oKList = new List<KeyValuePair<int, int>>();
int iCounter = 0;
//assert(m_BotStyleRequired.Count()==m_BotStyleList.Count());
for (int i = 0; i < m_BotStyleRequired.Count(); ++i)
{
int iNewRequired = m_BotStyleRequired[i].RequiredCount - m_BotStyleList[i].GetActiveCount();
if (iNewRequired > 0)
{
iCounter += iNewRequired;
oKList.Add(new KeyValuePair<int, int>(i, iCounter));
}
}
int iRandom = m_oRandom.Next(iCounter);
foreach (var oPair in oKList)
{
if (iRandom < oPair.Value)
{
return oPair.Key;
}
}
return 0;
}
#endregion
#region Bot management
public void Reset()
{
KillBots(m_BotList, true);
m_BotList.Clear();
m_lFreeBotIDList.Clear();
m_iMaxActiveBotIdCounter = 0;
m_iTotalNewInstanceCounter = 0;
m_iNextSim = 0;
m_aiTotalStateCount = new int[(int)BotState.BotState_Max];
m_BotStatusList = new BindingList<BotStatusItem>();
m_BotMetricList = new BindingList<BotStatusItem>();
m_BotGlobalStatusCountList = new BindingList<BotStatusItem>();
foreach(var oitem in m_BotStyleList)
{
oitem.Reset();
}
TotalCreated = 0;
TotalCrashed = 0;
TotalKilled = 0;
}
public void UpdateArguments(String sAppapth, String sCommandArgs, int a_iDataPrefix)
{
m_sAppPath = sAppapth;
m_sAppArgs = sCommandArgs;
m_iMaxDataPrefix = a_iDataPrefix;
if(m_iMaxDataPrefix < 0)
{
m_iNextDataPrefix = -1;
}
else if (m_iNextDataPrefix < 0 || m_iNextDataPrefix > m_iMaxDataPrefix)
{
m_iNextDataPrefix = 0;
}
}
public int PeekFreeBotiD()
{
int iBotId = m_iMaxActiveBotIdCounter;
if (m_lFreeBotIDList.Count > 0)
{
iBotId = m_lFreeBotIDList[0];
}
return iBotId;
}
private void TakeBotiD(int a_iID)
{
m_lFreeBotIDList.Add(a_iID);
}
private int GetFreeBotiD()
{
int iBotId = m_iMaxActiveBotIdCounter;
if (m_lFreeBotIDList.Count > 0)
{
iBotId = m_lFreeBotIDList[0];
m_lFreeBotIDList.RemoveAt(0);
}
else
{
++m_iMaxActiveBotIdCounter;
}
return iBotId;
}
public void CreateBotofType(int a_iSim)
{
int iNextBotiD = GetFreeBotiD();
string sArgs = GetArgs(m_sAppArgs, m_iNextDataPrefix, iNextBotiD, a_iSim, m_sAppPath);
BotClass oBot = new BotClass(m_iTotalNewInstanceCounter++
, iNextBotiD
, m_sAppPath
, m_BotStyleList[a_iSim].SimName
, a_iSim
, sArgs
, m_pParentForm
, this
);
m_BotList.Add(oBot);
if (m_iNextDataPrefix >= 0)
{
++m_iNextDataPrefix;
}
m_BotStyleList[a_iSim].AddStateType(BotState.BotState_IDLE);
++m_aiTotalStateCount[(int)BotState.BotState_IDLE];
}
public void BotDied(BotClass aBot)
{
if (aBot.GetBotState() != BotState.BotState_Dying)
{
m_BotStyleList[aBot.BotLogicID].AddCrashed();
++TotalCrashed;
}
else
{
m_BotStyleList[aBot.BotLogicID].AddKill();
++TotalKilled;
}
aBot.SetLuaBotState(""); // this should update our live statistics
aBot.SetBotState(BotState.BotState_Invalid); // this should update our live statistics
TakeBotiD(aBot.BotId);
m_BotList.Remove(aBot);
}
public int GetBotCount()
{
return m_BotList.Count();
}
public void KillBots(BindingList<BotClass> lSelectedItems, bool a_bForce)
{
List<BotClass> lBotstoPrune = new List<BotClass>();
for (int i = 0; i < lSelectedItems.Count(); ++i)
{
BotClass oBot = lSelectedItems[i];
if (oBot.GetBotState() == BotState.BotState_IDLE)
{
oBot.SetBotState(BotState.BotState_Invalid);
lBotstoPrune.Add(oBot);
}
else if (oBot.GetBotState() == BotState.BotState_Running || oBot.GetBotState() == BotState.BotState_Dying)
{
if(a_bForce)
{
oBot.ForceCancel();
}
else
{
oBot.Cancel();
}
}
}
foreach (var aBot in lBotstoPrune)
{
m_BotList.Remove(aBot);
}
}
public void KillAllBots()
{
KillBots(m_BotList, false);
}
public int KillRandomRunningBots(int a_iMaxKillThisFrame)
{
if (a_iMaxKillThisFrame <= 0)
{
return 0;
}
int iKillThisFrame = m_oRandom.Next(a_iMaxKillThisFrame + 1);
int iTotalKilled = 0;
while (iKillThisFrame > 0)
{
int iBottoKill = m_oRandom.Next(iKillThisFrame);
for (int i = 0; i < m_BotList.Count; ++i)
{
if (m_BotList[i].GetBotState() == BotState.BotState_Running)
{
iBottoKill--;
if (iBottoKill < 0)
{
m_BotList[i].Cancel();
++iTotalKilled;
break;
}
}
}
--iKillThisFrame;
}
return iTotalKilled;
}
public BotClass StartNextBot()
{
for (int i = 0; i < m_BotList.Count; ++i)
{
if (m_BotList[i].GetBotState() == BotState.BotState_IDLE)
{
m_BotList[i].Start();
m_BotStyleList[m_BotList[i].BotLogicID].AddCreated();
++TotalCreated;
return m_BotList[i];
}
}
return null;
}
#endregion // Bot management
#region Ui Interface Helper
public void BindingRequiredItemsUi(DataGridView a_dgStyleRequired)
{
a_dgStyleRequired.DataSource = m_BotStyleRequired;
a_dgStyleRequired.Columns["RequiredCount"].DefaultCellStyle.ForeColor = Color.Blue;
}
public void BindingBotList(DataGridView a_dgBots)
{
a_dgBots.DataSource = null;
a_dgBots.DataSource = m_BotList;
}
public void RefreshStatisticsUiBindings(DataGridView a_dgStyle, DataGridView a_dgStatus, DataGridView a_dgGlobalStatus, DataGridView a_dgGlobalMetrics, DataGridView a_dgBots)
{
//-----------------
a_dgStyle.DataSource = null;
a_dgStyle.DataSource = new List<BotStyleItem>(m_BotStyleList);
a_dgStyle.Columns["TotalCrashed"].DefaultCellStyle.ForeColor = Color.Red;
//-----------------
a_dgStatus.DataSource = null;
a_dgStatus.DataSource = new List<BotStatusItem>(m_BotStatusList);
//-----------------
a_dgGlobalStatus.DataSource = null;
a_dgGlobalStatus.DataSource = new List<BotStatusItem>(m_BotGlobalStatusCountList);
//-----------------
a_dgGlobalMetrics.DataSource = null;
a_dgGlobalMetrics.DataSource = new List<BotStatusItem>(m_BotMetricList);
//-----------------
}
public bool IsNumericColumn(DataGridView a_dg)
{
return (a_dg.CurrentCell.OwningColumn == a_dg.Columns["RequiredCount"]);
}
#endregion Ui Interface Helper
#region Summary
public String GetSummary()
{
String sData = "";
foreach(var oItem in m_BotStyleRequired)
{
if(sData.Length > 0)
{
sData = sData + ",";
}
sData = sData + "Required_" +oItem.SimName + ":" + oItem.RequiredCount.ToString();
}
foreach(var oItem in m_BotStyleList)
{
if (sData.Length > 0)
{
sData = sData + ",";
}
sData = sData + "Total_" + oItem.SimName + "_Created:" + oItem.CreatedCount.ToString()
+ ",Total_" + oItem.SimName + "_Crashed:" + oItem.TotalCrashed.ToString()
+ ",Total_" + oItem.SimName + "_Killed:" + oItem.TotalKilled.ToString()
+ ",Total_" + oItem.SimName + "_Idle:" + oItem.Active_IDLE.ToString()
+ ",Total_" + oItem.SimName + "_Running:" + oItem.Active_Running.ToString()
+ ",Total_" + oItem.SimName + "_Dying:" + oItem.Active_Dying.ToString();
}
foreach(var oItem in m_BotStatusList)
{
if (sData.Length > 0)
{
sData = sData + ",";
}
sData = sData + "Active_Status_" + oItem.Status + ":" + oItem.CurrentCount.ToString();
}
foreach (var oItem in m_BotMetricList)
{
if (sData.Length > 0)
{
sData = sData + ",";
}
sData = sData + "Metric_" + oItem.Status + ":" + oItem.CurrentCount.ToString();
}
foreach(var oItem in m_BotGlobalStatusCountList)
{
if (sData.Length > 0)
{
sData = sData + ",";
}
sData = sData + "Global_Status_" + oItem.Status + ":" + oItem.CurrentCount.ToString();
}
return sData;
}
#endregion // Summary
}
}