I’m working with the Sun Game Server / Darkstar Server. I got the exact same list of errors as the original poster. It almost got me to stay with 2.5.1 to be honest. However the lure of the performance profiler proved strong enough to send me seeking a solution.
And so, this is my fix. There may be a million more better fixes out there, but this one is mine.
In essence, one must build a buffer of all incoming messages from servers that use threading communications API’s.
I separated the listener class and code from all other classes, and added a static List to it, along with a static method that returns the string at zero position in the list and deletes that string. All incoming messages from the server are added to that list of messages instead of being acted on directly. This includes special messages such as login confirmations which may actually appear to be separate functions in the communications interface.
I have one such object handling session communication (Only one instance per client) and a dictionary of them in a separate class handling channel communications (multiple channels per client).
Various monobehaviours now access the message lists according to their needs.
Eg: The update class for my login manager monobehaviour script starts with
void Update()
{
if (CityOSSession.msgList != null CityOSSession.msgList.Count > 0)
{
String receivedDataString = CityOSSession.msgList[0];
CityOSSession.msgList.RemoveAt(0);
String[] cmds = receivedDataString.Split(receivedDataString.ToCharArray()[0]);
if (cmds[1].Equals("UploadCharacter"))
{
MasterManager.characterManager.UploadedCharacter(cmds);
}
else if (cmds[1].Equals("LoggedIn"))
{
LoggedIn();
}
else if (cmds[1].Equals("CharacterList"))
{
...
....
(etc)
The incoming messages from the server are stuffed into the message lists quite simply.
class CityOSSession : SimpleClientListener
{
public static List<String> msgList;
public static byte[] reconnectKey;
private System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
...
public CityOSSession(String loginName, String loginPass, String server, int port)
{
msgList = new List<string>();
msgList.Add("~msg~Logging in!");
this.loginName = loginName;
this.loginPass = loginPass;
client = new SimpleClient(this);
try { client.login(server, port); }
catch (Exception e) { msgList.Add("client.login error [" + e.ToString()+"]"); }
}
...
public void LoggedIn(byte[] reconnectKey)
{
CityOSSession.reconnectKey = reconnectKey;
msgList.Add("~LoggedIn");
client.SessionSend(encode("~CharacterList"));
client.SessionSend(encode("~RaceList"));
client.SessionSend(encode("~ClassList"));
}
...
public void ReceivedMessage(byte[] message)
{
if (msgList == null) { msgList = new List<string>(); }
String receivedDataString = Encoding.UTF8.GetString(message);
msgList.Add(receivedDataString);
}
...
The actual access of the static lists is moved off to nice secure static functions on the session classes, but here is shown in the Update that uses it for clarity.
The methods that can be called by the server should not make any calls on any Unity methods, or even on any code that can call unity methods, (save only the Debug.Log apparently).
For clarity in my code I do not include a “Using UnityEngine;” in any classes that implement server communication.
There is concern at the back of my mind regarding the possibility of unity side code trying to read a string from the list before the server driven method has finished writing it. I’d like to assume that List.Add() is atomic, but it’d be a big assumption.
Hope this helps out any other folks who find their server communications being slapped with “Bad Thread! Bad!” errors.