Official Everybody Edits Forums

Do you think I could just leave this part blank and it'd be okay? We're just going to replace the whole thing with a header image anyway, right?

You are not logged in.

#1 2017-02-19 17:11:41

drunkbnu
Formerly HG
Joined: 2017-08-16
Posts: 2,306

Issue with exception handling

I have tried to search in other places for how to catch an exception thrown from an EventHandler (PlayerIOClient.MessageReceivedEventHandler), but I've had no luck.

Here's the code which is supposed to catch an Exception thrown when the user isn't the world owner. But the Exception isn't caught by the "catch" block. It doesn't even throw an un-handled exception box. But it can change the Connect button text to "Test", making it look like the Exception wasn't thrown.

using PlayerIOClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EEWorldSaver {
	public partial class Main : Form {
		public static Client cli;
		public static Connection con;
		public Main () { InitializeComponent (); }
		private void OnMessage (object sender, PlayerIOClient.Message e) {
			switch (e.Type) {
				case "init":
					if ((e.GetString (13) != e.GetString (0)) || !e.GetBoolean (12)) {
						button1.Text = "Test";
						throw new Exception ("You must be the world owner to use this bot.");
					} else con.Send ("init2");
					break;
				case "init2":
					button1.Text = "Disconnect";
					button1.Enabled = true;
					break;
			}
		}
		private void button1_Click (object sender, EventArgs e) {
			try {
				panel1.Enabled = false;
				button1.Enabled = false;
				if (string.IsNullOrWhiteSpace (textBox1.Text) || string.IsNullOrWhiteSpace (textBox2.Text) || string.IsNullOrWhiteSpace (textBox3.Text)) throw new Exception ("One or more fields were empty.");
				else if (textBox1.Text == "guest") throw new Exception ("You may not use this bot as guest.");
				else if (textBox3.Text.StartsWith ("OW")) throw new Exception ("This bot may not be used in open worlds.");
				else if ((!textBox3.Text.StartsWith ("BW") && !textBox3.Text.StartsWith ("PW")) || !textBox3.Text.EndsWith ("I")) throw new Exception ("Invalid world ID. A valid world ID starts with PW/BW and ends with I.");
				cli = PlayerIO.QuickConnect.SimpleConnect ("everybody-edits-su9rn58o40itdbnw69plyw", textBox1.Text, textBox2.Text, null);
				con = cli.Multiplayer.CreateJoinRoom (textBox3.Text, (textBox3.Text.StartsWith ("BW") ? "Beta" : "Everybodyedits") + cli.BigDB.Load ("config", "config")["version"], true, null, null);
				con.Send ("init");
				con.OnMessage += new MessageReceivedEventHandler (OnMessage);
			} catch (Exception ex) {
				MessageBox.Show (this, ex.Message, "Error", 0, MessageBoxIcon.Error);
				panel1.Enabled = true;
				button1.Enabled = true;
			}
		}
	}
}

Offline

#2 2017-02-19 17:22:44

hummerz5
Member
From: wait I'm not a secret mod huh
Joined: 2015-08-10
Posts: 5,852

Re: Issue with exception handling

Hmm. Given how you're using the exception, could you instead call some MessageOutput function and then just couple that with a return statement?

The way I figure, creating an event handler is all that happens in your button1_click; I would be surprised if for some reason we passed the error back somehow. Say you had multiple event handlers... wouldn't that get somewhat messy to make that connection that 'this' handler has 'this' exception handling that's rather distant from the one line used to set it up?

on another note, these would be on different threads anyway, so even if your code did meander its way back to that frame, you'd be doing illegal cross-thread calls. //forums.everybodyedits.com/img/smilies/sad

I don't think I helped you solve anything, but food for thought

Offline

#3 2017-02-19 17:36:05

XxAtillaxX
Member
Joined: 2015-11-28
Posts: 4,202

Re: Issue with exception handling

As mentioned in IRC, the issue is from WinForms (as it's utterly disgusting and has quirky threading), so the only solution I can think of is subscribing to 'Application.ThreadException' and 'AppDomain.CurrentDomain.UnhandledException'.


signature.png
*u stinky*

Offline

#4 2017-02-19 17:38:39

Tomahawk
Forum Mod
From: UK
Joined: 2015-02-18
Posts: 2,835

Re: Issue with exception handling

I'm not really answering the question, but why throw an exception in that scenario when you could just display an error in a message box and disconnect the bot?

You just seem to be making life difficult for yourself.


One bot to rule them all, one bot to find them. One bot to bring them all... and with this cliché blind them.

Offline

#5 2017-02-19 17:39:57

XxAtillaxX
Member
Joined: 2015-11-28
Posts: 4,202

Re: Issue with exception handling

Tomahawk wrote:

I'm not really answering the question, but why throw an exception in that scenario when you could just display an error in a message box and disconnect the bot?

You just seem to be making life difficult for yourself.

Besides his spaghetti code, it is a valid issue for those that still use WinForms, for whatever god forsaken reason.


signature.png
*u stinky*

Offline

#6 2017-02-19 17:57:26, last edited by LukeM (2017-02-19 18:20:14)

LukeM
Member
From: England
Joined: 2016-06-03
Posts: 3,009
Website

Re: Issue with exception handling

XxAtillaxX wrote:

As mentioned in IRC, the issue is from WinForms (as it's utterly disgusting and has quirky threading), so the only solution I can think of is subscribing to 'Application.ThreadException' and 'AppDomain.CurrentDomain.UnhandledException'.

Once you understand it, how it works is actually quite sensible. This isnt a great solution, but its simple and (ive now tested it and it) works, so I would advise making these changes:

using PlayerIOClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EEWorldSaver {
	public partial class Main : Form {
		public static Client cli;
		public static Connection con;
		public static bool connected = false;
		public static bool hasEdit = false;
		public Main () { InitializeComponent (); }
		private void OnMessage (object sender, PlayerIOClient.Message e) {
			switch (e.Type) {
				case "init":
					hasEdit = e.GetBoolean(14); // Sets a hasEdit tag so it can be used later
					connected = true; // Indicates that the bot has recieved, and finished processing the init message, which allowd the other thread to continue
					break;
				case "init2":
					Invoke(new MethodInvoker(delegate // Need an invoke here, because this is running on a different thread
					{
						button1.Text = "Disconnect";
						button1.Enabled = true;
					}));
					break;
			}
		}
		private void button1_Click (object sender, EventArgs e) {
			try {
				panel1.Enabled = false;
				button1.Enabled = false;
				if (string.IsNullOrWhiteSpace (textBox1.Text) || string.IsNullOrWhiteSpace (textBox2.Text) || string.IsNullOrWhiteSpace (textBox3.Text)) throw new Exception ("One or more fields were empty.");
				else if (textBox1.Text == "guest") throw new Exception ("You may not use this bot as guest.");
				else if (textBox3.Text.StartsWith ("OW")) throw new Exception ("This bot may not be used in open worlds.");
				else if ((!textBox3.Text.StartsWith ("BW") && !textBox3.Text.StartsWith ("PW")) || !textBox3.Text.EndsWith ("I")) throw new Exception ("Invalid world ID. A valid world ID starts with PW/BW and ends with I.");
				cli = PlayerIO.QuickConnect.SimpleConnect ("everybody-edits-su9rn58o40itdbnw69plyw", textBox1.Text, textBox2.Text, null);
				con = cli.Multiplayer.CreateJoinRoom (textBox3.Text, (textBox3.Text.StartsWith ("BW") ? "Beta" : "Everybodyedits") + cli.BigDB.Load ("config", "config")["version"], true, null, null);
				con.OnMessage += new MessageReceivedEventHandler (OnMessage); // Setting onmessage should be before init, otherwise theoretically you could recieve a message before the handler is set
				con.Send ("init");
				while (!connected) { } // Waits until the bot has connected to continue
				if (!hasEdit) throw new Exception ("You must be the world owner to use this bot."); // Now the exception is thrown in the same thread as the form
				else con.Send ("init2");
			} catch (Exception ex) {
				MessageBox.Show (this, ex.Message, "Error", 0, MessageBoxIcon.Error);
				panel1.Enabled = true;
				button1.Enabled = true;
				// Check if connected, and disconnect if it is or whatever here
			}
		}
	}
}

Also I have a library which might help with the saving, and parsing of init / load messages: WorldSaver

Tomahawk wrote:

I'm not really answering the question, but why throw an exception in that scenario when you could just display an error in a message box and disconnect the bot?

You just seem to be making life difficult for yourself.

I dont think you could display the error message either, because that would also happen on the wrong thread (I might be wrong, I havent tried using message boxes from other threads)

Offline

#7 2017-02-19 18:26:39

drunkbnu
Formerly HG
Joined: 2017-08-16
Posts: 2,306

Re: Issue with exception handling

@destroyer123: The while (!connected) loop will make the program get stuck until the bot receives "init". What if the bot doesn't receive "init"? You would have to close the process via the Task Manager.

Following Tomahawk's suggestion, I think I wrote a solution to the exception handling trouble, by not throwing exceptions.

using PlayerIOClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EEWorldSaver {
	public partial class Main : Form {
		public Client cli;
		public Connection con;
		public Main () { InitializeComponent (); }
		private void RestoreControls () {
			panel1.Enabled = true;
			button1.Text = "Connect";
			button1.Enabled = true;
		}
		private void OnMessage (object sender, PlayerIOClient.Message e) {
			switch (e.Type) {
				case "init":
					if ((e.GetString (13) != e.GetString (0)) || !e.GetBoolean (15)) Disconnect ("You must be the world owner to use this bot.");
					con.Send ("init2");
					break;
				case "init2":
					button1.Text = "Disconnect";
					button1.Enabled = true;
					break;
			}
		}
		private void Disconnect (string reason) {
			if (reason != "User pressed the disconnect button") MessageBox.Show (this, reason, "Error", 0, MessageBoxIcon.Error);
			con.Disconnect ();
		}
		private void button1_Click (object sender, EventArgs a) {
			if (button1.Text == "Disconnect") Disconnect ("User pressed the disconnect button");
			else {
				try {
					panel1.Enabled = false;
					button1.Enabled = false;
					if (string.IsNullOrWhiteSpace (textBox1.Text) || string.IsNullOrWhiteSpace (textBox2.Text) || string.IsNullOrWhiteSpace (textBox3.Text)) throw new Exception ("One or more fields were empty.");
					else if (textBox1.Text == "guest") throw new Exception ("You may not use this bot as guest.");
					else if (textBox3.Text.StartsWith ("OW")) throw new Exception ("This bot may not be used in open worlds.");
					else if ((!textBox3.Text.StartsWith ("BW") && !textBox3.Text.StartsWith ("PW")) || !textBox3.Text.EndsWith ("I")) throw new Exception ("Invalid world ID. A valid world ID starts with PW/BW and ends with I.");
					cli = PlayerIO.QuickConnect.SimpleConnect ("everybody-edits-su9rn58o40itdbnw69plyw", textBox1.Text, textBox2.Text, null);
					con = cli.Multiplayer.CreateJoinRoom (textBox3.Text, (textBox3.Text.StartsWith ("BW") ? "Beta" : "Everybodyedits") + cli.BigDB.Load ("config", "config")["version"], true, null, null);
					con.OnMessage += new MessageReceivedEventHandler (OnMessage);
					con.Send ("init");
					con.OnDisconnect += (s, reason) => {
						if (reason != "Disconnect") MessageBox.Show (this, "Lost connection to the world.", "Error", 0, MessageBoxIcon.Error);
						RestoreControls ();
						return;
					};
				} catch (Exception ex) {
					MessageBox.Show (this, ex.Message, "Error", 0, MessageBoxIcon.Error);
					RestoreControls ();
				}
			}
		}
	}
}

Offline

#8 2017-02-19 18:35:42, last edited by LukeM (2017-02-19 18:43:03)

LukeM
Member
From: England
Joined: 2016-06-03
Posts: 3,009
Website

Re: Issue with exception handling

HG wrote:

@destroyer123: The while (!connected) loop will make the program get stuck until the bot receives "init". What if the bot doesn't receive "init"? You would have to close the process via the Task Manager.

Following Tomahawk's suggestion, I think I wrote a solution to the exception handling trouble, by not throwing exceptions.

using PlayerIOClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EEWorldSaver {
	public partial class Main : Form {
		public Client cli;
		public Connection con;
		public Main () { InitializeComponent (); }
		private void RestoreControls () {
			panel1.Enabled = true;
			button1.Text = "Connect";
			button1.Enabled = true;
		}
		private void OnMessage (object sender, PlayerIOClient.Message e) {
			switch (e.Type) {
				case "init":
					if ((e.GetString (13) != e.GetString (0)) || !e.GetBoolean (15)) Disconnect ("You must be the world owner to use this bot.");
					con.Send ("init2");
					break;
				case "init2":
					button1.Text = "Disconnect";
					button1.Enabled = true;
					break;
			}
		}
		private void Disconnect (string reason) {
			if (reason != "User pressed the disconnect button") MessageBox.Show (this, reason, "Error", 0, MessageBoxIcon.Error);
			con.Disconnect ();
		}
		private void button1_Click (object sender, EventArgs a) {
			if (button1.Text == "Disconnect") Disconnect ("User pressed the disconnect button");
			else {
				try {
					panel1.Enabled = false;
					button1.Enabled = false;
					if (string.IsNullOrWhiteSpace (textBox1.Text) || string.IsNullOrWhiteSpace (textBox2.Text) || string.IsNullOrWhiteSpace (textBox3.Text)) throw new Exception ("One or more fields were empty.");
					else if (textBox1.Text == "guest") throw new Exception ("You may not use this bot as guest.");
					else if (textBox3.Text.StartsWith ("OW")) throw new Exception ("This bot may not be used in open worlds.");
					else if ((!textBox3.Text.StartsWith ("BW") && !textBox3.Text.StartsWith ("PW")) || !textBox3.Text.EndsWith ("I")) throw new Exception ("Invalid world ID. A valid world ID starts with PW/BW and ends with I.");
					cli = PlayerIO.QuickConnect.SimpleConnect ("everybody-edits-su9rn58o40itdbnw69plyw", textBox1.Text, textBox2.Text, null);
					con = cli.Multiplayer.CreateJoinRoom (textBox3.Text, (textBox3.Text.StartsWith ("BW") ? "Beta" : "Everybodyedits") + cli.BigDB.Load ("config", "config")["version"], true, null, null);
					con.OnMessage += new MessageReceivedEventHandler (OnMessage);
					con.Send ("init");
					con.OnDisconnect += (s, reason) => {
						if (reason != "Disconnect") MessageBox.Show (this, "Lost connection to the world.", "Error", 0, MessageBoxIcon.Error);
						RestoreControls ();
						return;
					};
				} catch (Exception ex) {
					MessageBox.Show (this, ex.Message, "Error", 0, MessageBoxIcon.Error);
					RestoreControls ();
				}
			}
		}
	}
}

The problem with that is that I dont think it would prevent the other thread from running, which could cause a lot of problems when you actually start adding things.
If you are worried about not recieving the init message, you could do something like this:

using PlayerIOClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EEWorldSaver {
	public partial class Main : Form {
		public static Client cli;
		public static Connection con;
		public static bool connected = false;
		public static bool hasEdit = false;
		public Main () { InitializeComponent (); }
		private void OnMessage (object sender, PlayerIOClient.Message e) {
			switch (e.Type) {
				case "init":
					hasEdit = e.GetBoolean(14); // Sets a hasEdit tag so it can be used later
					connected = true; // Indicates that the bot has recieved, and finished processing the init message, which allowd the other thread to continue
					break;
				case "init2":
					Invoke(new MethodInvoker(delegate // Need an invoke here, because this is running on a different thread
					{
						button1.Text = "Disconnect";
						button1.Enabled = true;
					}));
					break;
			}
		}
		private void button1_Click (object sender, EventArgs e) {
			try {
				panel1.Enabled = false;
				button1.Enabled = false;
				if (string.IsNullOrWhiteSpace (textBox1.Text) || string.IsNullOrWhiteSpace (textBox2.Text) || string.IsNullOrWhiteSpace (textBox3.Text)) throw new Exception ("One or more fields were empty.");
				else if (textBox1.Text == "guest") throw new Exception ("You may not use this bot as guest.");
				else if (textBox3.Text.StartsWith ("OW")) throw new Exception ("This bot may not be used in open worlds.");
				else if ((!textBox3.Text.StartsWith ("BW") && !textBox3.Text.StartsWith ("PW")) || !textBox3.Text.EndsWith ("I")) throw new Exception ("Invalid world ID. A valid world ID starts with PW/BW and ends with I.");
				cli = PlayerIO.QuickConnect.SimpleConnect ("everybody-edits-su9rn58o40itdbnw69plyw", textBox1.Text, textBox2.Text, null);
				con = cli.Multiplayer.CreateJoinRoom (textBox3.Text, (textBox3.Text.StartsWith ("BW") ? "Beta" : "Everybodyedits") + cli.BigDB.Load ("config", "config")["version"], true, null, null);
				con.OnMessage += new MessageReceivedEventHandler (OnMessage); // Setting onmessage should be before init, otherwise theoretically you could recieve a message before the handler is set
				con.Send ("init");
				long timeout = DateTime.Now.Millisecond + 1000;
				while (!connected) // Waits until the bot has connected to continue
					if (DateTime.Now.Millisecond > timeout) throw new Exception ("Could not connect to the world."); // Prevents losing connection from freezing the bot
				if (!hasEdit) throw new Exception ("You must be the world owner to use this bot."); // Now the exception is thrown in the same thread as the form
				else con.Send ("init2");
			} catch (Exception ex) {
				MessageBox.Show (this, ex.Message, "Error", 0, MessageBoxIcon.Error);
				panel1.Enabled = true;
				button1.Enabled = true;
				// Check if connected, and disconnect if it is or whatever here
			}
		}
	}
}

Offline

LukeM1487525742648235

Board footer

Powered by FluxBB

[ Started around 1714004978.5319 - Generated in 0.093 seconds, 12 queries executed - Memory usage: 1.51 MiB (Peak: 1.68 MiB) ]