McClient: Add DispatchBotEvent method

Facilitates event dispatching and error handling for ChatBots
This commit is contained in:
ORelio 2020-06-20 15:39:16 +02:00
parent f30dc4464c
commit c69e87bec3

View file

@ -1100,6 +1100,51 @@ namespace MinecraftClient
#region Event handlers: An event occurs on the Server #region Event handlers: An event occurs on the Server
/// <summary>
/// Dispatch a ChatBot event with automatic exception handling
/// </summary>
/// <example>
/// Example for calling SomeEvent() on all bots at once:
/// DispatchBotEvent(bot => bot.SomeEvent());
/// </example>
/// <param name="action">Action to execute on each bot</param>
/// <param name="botList">Only fire the event for the specified bot list (default: all bots)</param>
private void DispatchBotEvent(Action<ChatBot> action, IEnumerable<ChatBot> botList = null)
{
ChatBot[] selectedBots;
if (botList != null)
{
selectedBots = botList.ToArray();
}
else
{
selectedBots = bots.ToArray();
}
foreach (ChatBot bot in selectedBots)
{
try
{
action(bot);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
//Retrieve parent method name to determine which event caused the exception
System.Diagnostics.StackFrame frame = new System.Diagnostics.StackFrame(1);
System.Reflection.MethodBase method = frame.GetMethod();
string parentMethodName = method.Name;
//Display a meaningful error message to help debugging the ChatBot
ConsoleIO.WriteLogLine(parentMethodName + ": Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught here as in can happen when disconnecting from server
}
}
}
/// <summary> /// <summary>
/// Called when a server was successfully joined /// Called when a server was successfully joined
/// </summary> /// </summary>
@ -1118,27 +1163,7 @@ namespace MinecraftClient
Settings.MCSettings_Skin_All, Settings.MCSettings_Skin_All,
Settings.MCSettings_MainHand); Settings.MCSettings_MainHand);
if (inventoryHandlingEnabled) DispatchBotEvent(bot => bot.AfterGameJoined());
{
inventories.Clear();
inventories[0] = new Container(0, ContainerType.PlayerInventory, "Player Inventory");
}
foreach (ChatBot bot in bots.ToArray())
{
try
{
bot.AfterGameJoined();
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("AfterGameJoined: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
if (inventoryHandlingRequested) if (inventoryHandlingRequested)
{ {
@ -1146,6 +1171,8 @@ namespace MinecraftClient
inventoryHandlingEnabled = true; inventoryHandlingEnabled = true;
ConsoleIO.WriteLogLine("Inventory handling is now enabled."); ConsoleIO.WriteLogLine("Inventory handling is now enabled.");
} }
ClearInventories();
} }
/// <summary> /// <summary>
@ -1153,12 +1180,6 @@ namespace MinecraftClient
/// </summary> /// </summary>
public void OnRespawn() public void OnRespawn()
{ {
if (inventoryHandlingEnabled)
{
inventories.Clear();
inventories[0] = new Container(0, ContainerType.PlayerInventory, "Player Inventory");
}
if (terrainAndMovementsRequested) if (terrainAndMovementsRequested)
{ {
terrainAndMovementsEnabled = true; terrainAndMovementsEnabled = true;
@ -1170,6 +1191,8 @@ namespace MinecraftClient
{ {
world.Clear(); world.Clear();
} }
ClearInventories();
} }
/// <summary> /// <summary>
@ -1274,34 +1297,24 @@ namespace MinecraftClient
{ {
lastKeepAlive = DateTime.Now; lastKeepAlive = DateTime.Now;
} }
List<string> links = new List<string>(); List<string> links = new List<string>();
string json = null; string json = null;
if (isJson) if (isJson)
{ {
json = text; json = text;
text = ChatParser.ParseText(json, links); text = ChatParser.ParseText(json, links);
} }
ConsoleIO.WriteLineFormatted(text, true); ConsoleIO.WriteLineFormatted(text, true);
if (Settings.DisplayChatLinks) if (Settings.DisplayChatLinks)
foreach (string link in links) foreach (string link in links)
ConsoleIO.WriteLogLine("Link: " + link, false); ConsoleIO.WriteLogLine("Link: " + link, false);
foreach (ChatBot bot in bots.ToArray())
{ DispatchBotEvent(bot => bot.GetText(text));
try DispatchBotEvent(bot => bot.GetText(text, json));
{
bot.GetText(text);
if (bots.Contains(bot))
bot.GetText(text, json);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("GetText: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
/// <summary> /// <summary>
@ -1440,10 +1453,7 @@ namespace MinecraftClient
if (registeredBotPluginChannels.ContainsKey(channel)) if (registeredBotPluginChannels.ContainsKey(channel))
{ {
foreach (ChatBot bot in registeredBotPluginChannels[channel]) DispatchBotEvent(bot => bot.OnPluginMessage(channel, data), registeredBotPluginChannels[channel]);
{
bot.OnPluginMessage(channel, data);
}
} }
} }
@ -1457,22 +1467,7 @@ namespace MinecraftClient
OnDestroyEntities(new[] { entity.ID }); OnDestroyEntities(new[] { entity.ID });
entities.Add(entity.ID, entity); entities.Add(entity.ID, entity);
DispatchBotEvent(bot => bot.OnEntitySpawn(entity));
foreach (ChatBot bot in bots.ToArray())
{
try
{
bot.OnEntitySpawn(entity);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnEntitySpawn: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
/// <summary> /// <summary>
@ -1495,21 +1490,9 @@ namespace MinecraftClient
/// <param name="item"> Item)</param> /// <param name="item"> Item)</param>
public void OnEntityEquipment(int entityid, int slot, Item item) public void OnEntityEquipment(int entityid, int slot, Item item)
{ {
foreach (ChatBot bot in bots.ToArray()) if (entities.ContainsKey(entityid))
{ {
try DispatchBotEvent(bot => bot.OnEntityEquipment(entities[entityid], slot, item));
{
if (entities.ContainsKey(entityid))
bot.OnEntityEquipment(entities[entityid], slot, item);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnEntityEquipment: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
} }
} }
@ -1531,8 +1514,7 @@ namespace MinecraftClient
string playerName = onlinePlayers[uuid]; string playerName = onlinePlayers[uuid];
if (playerName == this.username) if (playerName == this.username)
this.gamemode = gamemode; this.gamemode = gamemode;
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnGamemodeUpdate(playerName, uuid, gamemode));
bot.OnGamemodeUpdate(playerName, uuid, gamemode);
} }
} }
@ -1545,21 +1527,7 @@ namespace MinecraftClient
{ {
if (entities.ContainsKey(a)) if (entities.ContainsKey(a))
{ {
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnEntityDespawn(entities[a]));
{
try
{
bot.OnEntityDespawn(entities[a]);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnEntityDespawn: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
entities.Remove(a); entities.Remove(a);
} }
} }
@ -1582,22 +1550,7 @@ namespace MinecraftClient
L.Y += Dy; L.Y += Dy;
L.Z += Dz; L.Z += Dz;
entities[EntityID].Location = L; entities[EntityID].Location = L;
DispatchBotEvent(bot => bot.OnEntityMove(entities[EntityID]));
foreach (ChatBot bot in bots.ToArray())
{
try
{
bot.OnEntityMove(entities[EntityID]);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnEntityMove: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
} }
@ -1616,22 +1569,7 @@ namespace MinecraftClient
{ {
Location location = new Location(X, Y, Z); Location location = new Location(X, Y, Z);
entities[EntityID].Location = location; entities[EntityID].Location = location;
DispatchBotEvent(bot => bot.OnEntityMove(entities[EntityID]));
foreach (ChatBot bot in bots.ToArray())
{
try
{
bot.OnEntityMove(entities[EntityID]);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnEntityMove: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
} }
@ -1644,21 +1582,7 @@ namespace MinecraftClient
{ {
if (EntityID == playerEntityID) if (EntityID == playerEntityID)
{ {
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnPlayerProperty(prop));
{
try
{
bot.OnPlayerProperty(prop);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnPlayerProperty: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
} }
@ -1680,22 +1604,7 @@ namespace MinecraftClient
if (tps <= 20.0 && tps >= 0.0 && serverTPS != tps) if (tps <= 20.0 && tps >= 0.0 && serverTPS != tps)
{ {
serverTPS = tps; serverTPS = tps;
// invoke ChatBot DispatchBotEvent(bot => bot.OnServerTpsUpdate(tps));
foreach (ChatBot bot in bots.ToArray())
{
try
{
bot.OnServerTpsUpdate(tps);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnServerTpsUpdate: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
} }
else else
@ -1713,6 +1622,7 @@ namespace MinecraftClient
{ {
playerHealth = health; playerHealth = health;
playerFoodSaturation = food; playerFoodSaturation = food;
if (health <= 0) if (health <= 0)
{ {
if (Settings.AutoRespawn) if (Settings.AutoRespawn)
@ -1725,21 +1635,8 @@ namespace MinecraftClient
ConsoleIO.WriteLogLine("You are dead. Type /respawn to respawn."); ConsoleIO.WriteLogLine("You are dead. Type /respawn to respawn.");
} }
} }
foreach (ChatBot bot in bots.ToArray())
{ DispatchBotEvent(bot => bot.OnHealthUpdate(health, food));
try
{
bot.OnHealthUpdate(health, food);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnHealthUpdate: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
/// <summary> /// <summary>
@ -1752,21 +1649,7 @@ namespace MinecraftClient
{ {
playerLevel = Level; playerLevel = Level;
playerTotalExperience = TotalExperience; playerTotalExperience = TotalExperience;
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnSetExperience(Experiencebar, Level, TotalExperience));
{
try
{
bot.OnSetExperience(Experiencebar, Level, TotalExperience);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnSetExperience: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
/// <summary> /// <summary>
@ -1777,21 +1660,7 @@ namespace MinecraftClient
/// <param name="affectedBlocks">Amount of affected blocks</param> /// <param name="affectedBlocks">Amount of affected blocks</param>
public void OnExplosion(Location location, float strength, int affectedBlocks) public void OnExplosion(Location location, float strength, int affectedBlocks)
{ {
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnExplosion(location, strength, affectedBlocks));
{
try
{
bot.OnExplosion(location, strength, affectedBlocks);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnExplosion: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
/// <summary> /// <summary>
@ -1805,21 +1674,7 @@ namespace MinecraftClient
if (onlinePlayers.ContainsKey(uuid)) if (onlinePlayers.ContainsKey(uuid))
{ {
playerName = onlinePlayers[uuid]; playerName = onlinePlayers[uuid];
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnLatencyUpdate(playerName, uuid, latency));
{
try
{
bot.OnLatencyUpdate(playerName, uuid, latency);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnLatencyUpdate: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
} }
@ -1829,22 +1684,8 @@ namespace MinecraftClient
/// <param name="slot"> item slot</param> /// <param name="slot"> item slot</param>
public void OnHeldItemChange(byte slot) public void OnHeldItemChange(byte slot)
{ {
foreach (ChatBot bot in bots.ToArray())
{
try
{
bot.OnHeldItemChange(slot);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnHeldItemChange: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
CurrentSlot = slot; CurrentSlot = slot;
DispatchBotEvent(bot => bot.OnHeldItemChange(slot));
} }
/// <summary> /// <summary>
@ -1857,21 +1698,7 @@ namespace MinecraftClient
/// <param name="iconcount"></param> /// <param name="iconcount"></param>
public void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount) public void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount)
{ {
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnMapData(mapid, scale, trackingposition, locked, iconcount));
{
try
{
bot.OnMapData(mapid, scale, trackingposition, locked, iconcount);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnMapData: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
/// <summary> /// <summary>
@ -1886,21 +1713,7 @@ namespace MinecraftClient
/// <param name="json"> json text</param> /// <param name="json"> json text</param>
public void OnTitle(int action, string titletext, string subtitletext, string actionbartext, int fadein, int stay, int fadeout, string json) public void OnTitle(int action, string titletext, string subtitletext, string actionbartext, int fadein, int stay, int fadeout, string json)
{ {
foreach (ChatBot bot in bots.ToArray()) DispatchBotEvent(bot => bot.OnTitle(action, titletext, subtitletext, actionbartext, fadein, stay, fadeout, json));
{
try
{
bot.OnTitle(action, titletext, subtitletext, actionbartext, fadein, stay, fadeout, json);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnTitle: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
} }
#endregion #endregion