Spawnpoints for different jobs, spawning crew members with job-specific items, fixed issues with non-matching entity IDs between client and server, Unity-like coroutine system (connecting to server doesn't freeze the game anymore), map drawing improvements
This commit is contained in:
@@ -15,7 +15,15 @@ namespace Subsurface.Networking
|
||||
private Character myCharacter;
|
||||
private CharacterInfo characterInfo;
|
||||
|
||||
GUIMessageBox reconnectBox;
|
||||
|
||||
private bool connected;
|
||||
|
||||
private int myID;
|
||||
|
||||
List<Client> otherClients;
|
||||
|
||||
private string serverIP;
|
||||
|
||||
public Character Character
|
||||
{
|
||||
@@ -37,8 +45,10 @@ namespace Subsurface.Networking
|
||||
otherClients = new List<Client>();
|
||||
}
|
||||
|
||||
public bool ConnectToServer(string hostIP)
|
||||
public void ConnectToServer(string hostIP)
|
||||
{
|
||||
serverIP = hostIP;
|
||||
|
||||
myCharacter = Character.Controlled;
|
||||
|
||||
// Create new instance of configs. Parameter is "application Id". It has to be same on client and server.
|
||||
@@ -65,7 +75,7 @@ namespace Subsurface.Networking
|
||||
catch (ArgumentNullException e)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't connect to "+hostIP+". Error message: "+e.Message);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create timespan of 30ms
|
||||
@@ -78,27 +88,24 @@ namespace Subsurface.Networking
|
||||
//update.Elapsed += new System.Timers.ElapsedEventHandler(Update);
|
||||
|
||||
// Funtion that waits for connection approval info from server
|
||||
WaitForStartingInfo();
|
||||
|
||||
if (Client.ConnectionStatus != NetConnectionStatus.Connected)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't connect to server");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CoroutineManager.StartCoroutine(WaitForStartingInfo());
|
||||
|
||||
// Start the timer
|
||||
//update.Start();
|
||||
|
||||
}
|
||||
|
||||
private bool RetryConnection(GUIButton button, object obj)
|
||||
{
|
||||
ConnectToServer(serverIP);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Before main looping starts, we loop here and wait for approval message
|
||||
private void WaitForStartingInfo()
|
||||
private IEnumerable<Status> WaitForStartingInfo()
|
||||
{
|
||||
reconnectBox = new GUIMessageBox("CONNECTING", "Connecting to "+serverIP, new string[0]);
|
||||
|
||||
// When this is set to true, we are approved and ready to go
|
||||
bool CanStart = false;
|
||||
|
||||
@@ -107,7 +114,9 @@ namespace Subsurface.Networking
|
||||
// Loop untill we are approved
|
||||
while (!CanStart)
|
||||
{
|
||||
if (DateTime.Now>timeOut) return;
|
||||
yield return Status.Running;
|
||||
|
||||
if (DateTime.Now > timeOut) break;
|
||||
|
||||
NetIncomingMessage inc;
|
||||
// If new messages arrived
|
||||
@@ -120,7 +129,9 @@ namespace Subsurface.Networking
|
||||
case NetIncomingMessageType.Data:
|
||||
if (inc.ReadByte() == (byte)PacketTypes.LoggedIn)
|
||||
{
|
||||
int myID = inc.ReadInt32();
|
||||
myID = inc.ReadInt32();
|
||||
|
||||
Game1.NetLobbyScreen.ClearPlayers();
|
||||
|
||||
//add the names of other connected clients to the lobby screen
|
||||
int existingClients = inc.ReadInt32();
|
||||
@@ -149,19 +160,50 @@ namespace Subsurface.Networking
|
||||
|
||||
break;
|
||||
default:
|
||||
// Should not happen and if happens, don't care
|
||||
Console.WriteLine(inc.ReadString() + " Strange message");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (reconnectBox != null)
|
||||
{
|
||||
reconnectBox.Close(null, null);
|
||||
reconnectBox = null;
|
||||
}
|
||||
|
||||
if (Client.ConnectionStatus != NetConnectionStatus.Connected)
|
||||
{
|
||||
reconnectBox = new GUIMessageBox("CONNECTION FAILED", "Failed to connect to server.", new string[] { "Retry", "Cancel" });
|
||||
reconnectBox.Buttons[0].OnClicked += RetryConnection;
|
||||
reconnectBox.Buttons[0].OnClicked += reconnectBox.Close;
|
||||
}
|
||||
else
|
||||
{
|
||||
Game1.NetLobbyScreen.Select();
|
||||
connected = true;
|
||||
}
|
||||
|
||||
yield return Status.Success;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (updateTimer > DateTime.Now) return;
|
||||
|
||||
if (myCharacter!=null)
|
||||
if (!connected || updateTimer > DateTime.Now) return;
|
||||
|
||||
if (reconnectBox != null)
|
||||
{
|
||||
ConnectToServer(serverIP);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Client.ConnectionStatus == NetConnectionStatus.Disconnected)
|
||||
{
|
||||
reconnectBox = new GUIMessageBox("CONNECTION LOST", "You have been disconnected from the server. Reconnecting...", new string[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (myCharacter != null)
|
||||
{
|
||||
if (myCharacter.IsDead)
|
||||
{
|
||||
@@ -190,7 +232,6 @@ namespace Subsurface.Networking
|
||||
|
||||
NetworkEvent.events.Clear();
|
||||
|
||||
|
||||
CheckServerMessages();
|
||||
|
||||
// Update current time
|
||||
@@ -236,13 +277,20 @@ namespace Subsurface.Networking
|
||||
Game1.GameSession = new GameSession(Submarine.Loaded);
|
||||
Game1.GameSession.StartShift(duration, levelSeed);
|
||||
|
||||
myCharacter = ReadCharacterData(inc);
|
||||
Character.Controlled = myCharacter;
|
||||
//myCharacter = ReadCharacterData(inc);
|
||||
//Character.Controlled = myCharacter;
|
||||
|
||||
int count = inc.ReadInt32();
|
||||
for (int n = 0; n < count; n++)
|
||||
{
|
||||
ReadCharacterData(inc);
|
||||
int id = inc.ReadInt32();
|
||||
Character newCharacter = ReadCharacterData(inc);
|
||||
|
||||
if (id == myID)
|
||||
{
|
||||
myCharacter = newCharacter;
|
||||
Character.Controlled = myCharacter;
|
||||
}
|
||||
}
|
||||
|
||||
gameStarted = true;
|
||||
@@ -275,7 +323,7 @@ namespace Subsurface.Networking
|
||||
case (byte)PacketTypes.KickedOut:
|
||||
string msg = inc.ReadString();
|
||||
|
||||
DebugConsole.ThrowError(msg);
|
||||
new GUIMessageBox("KICKED", msg);
|
||||
|
||||
Game1.MainMenuScreen.Select();
|
||||
|
||||
@@ -296,8 +344,8 @@ namespace Subsurface.Networking
|
||||
case (byte)PacketTypes.Traitor:
|
||||
string targetName = inc.ReadString();
|
||||
|
||||
Game1.GameSession.NewChatMessage("You are an agent of Ordo Europae", messageColor[(int)ChatMessageType.Server]);
|
||||
Game1.GameSession.NewChatMessage("Your secret task is to assassinate " + targetName + "!", messageColor[(int)ChatMessageType.Server]);
|
||||
new GUIMessageBox("You are the Traitor!", "Your secret task is to assassinate " + targetName + "!");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -356,20 +404,37 @@ namespace Subsurface.Networking
|
||||
bool isFemale = inc.ReadBoolean();
|
||||
int inventoryID = inc.ReadInt32();
|
||||
|
||||
int headSpriteID = inc.ReadInt32();
|
||||
|
||||
int headSpriteID = inc.ReadInt32();
|
||||
|
||||
Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat());
|
||||
|
||||
string jobName = inc.ReadString();
|
||||
JobPrefab jobPrefab = JobPrefab.List.Find(jp => jp.Name == jobName);
|
||||
|
||||
Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat());
|
||||
|
||||
CharacterInfo ch = new CharacterInfo("Content/Characters/Human/human.xml", newName, isFemale ? Gender.Female : Gender.Male, jobPrefab);
|
||||
ch.HeadSpriteId = headSpriteID;
|
||||
Character character = new Character(ch, position);
|
||||
|
||||
WayPoint closestWaypoint = null;
|
||||
float closestDist = 0.0f;
|
||||
foreach (WayPoint wp in WayPoint.WayPointList)
|
||||
{
|
||||
float dist = Vector2.Distance(wp.SimPosition, position);
|
||||
if (closestWaypoint != null && dist > closestDist) continue;
|
||||
|
||||
closestWaypoint = wp;
|
||||
closestDist = dist;
|
||||
continue;
|
||||
}
|
||||
|
||||
Character character = (closestWaypoint == null) ?
|
||||
new Character(ch, position) :
|
||||
new Character(ch, closestWaypoint);
|
||||
|
||||
character.ID = ID;
|
||||
character.Inventory.ID = inventoryID;
|
||||
|
||||
character.GiveJobItems();
|
||||
|
||||
return character;
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,9 @@ namespace Subsurface.Networking
|
||||
Game1.GameSession = new GameSession(selectedMap, Game1.NetLobbyScreen.SelectedMode);
|
||||
Game1.GameSession.StartShift(Game1.NetLobbyScreen.GameDuration, Game1.NetLobbyScreen.LevelSeed);
|
||||
//EventManager.SelectEvent(Game1.netLobbyScreen.SelectedEvent);
|
||||
|
||||
|
||||
List<CharacterInfo> characterInfos = new List<CharacterInfo>();
|
||||
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
client.inGame = true;
|
||||
@@ -302,10 +304,21 @@ namespace Subsurface.Networking
|
||||
{
|
||||
client.characterInfo = new CharacterInfo("Content/Characters/Human/human.xml", client.name);
|
||||
}
|
||||
characterInfos.Add(client.characterInfo);
|
||||
|
||||
client.character = new Character(client.characterInfo, (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition, true);
|
||||
//client.character = new Character(client.characterInfo, (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition, true);
|
||||
}
|
||||
|
||||
WayPoint[] assignedWayPoints = WayPoint.SelectCrewSpawnPoints(characterInfos);
|
||||
|
||||
for (int i = 0; i < connectedClients.Count; i++ )
|
||||
{
|
||||
connectedClients[i].character = new Character(
|
||||
connectedClients[i].characterInfo, assignedWayPoints[i], true);
|
||||
connectedClients[i].character.GiveJobItems();
|
||||
}
|
||||
|
||||
//todo: fix
|
||||
if (myClient != null)
|
||||
{
|
||||
WayPoint spawnPoint = WayPoint.GetRandom(SpawnType.Human);
|
||||
@@ -313,37 +326,38 @@ namespace Subsurface.Networking
|
||||
myClient.character = new Character(ch, (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition);
|
||||
}
|
||||
|
||||
//foreach (Client client in connectedClients)
|
||||
//{
|
||||
NetOutgoingMessage msg = Server.CreateMessage();
|
||||
msg.Write((byte)PacketTypes.StartGame);
|
||||
|
||||
msg.Write(seed);
|
||||
|
||||
msg.Write(Game1.NetLobbyScreen.LevelSeed);
|
||||
|
||||
msg.Write(Game1.NetLobbyScreen.SelectedMap.Name);
|
||||
msg.Write(Game1.NetLobbyScreen.SelectedMap.Hash.MD5Hash);
|
||||
|
||||
msg.Write(Game1.NetLobbyScreen.GameDuration.TotalMinutes);
|
||||
|
||||
//WriteCharacterData(msg, client.name, client.character);
|
||||
|
||||
msg.Write((myClient == null) ? connectedClients.Count : connectedClients.Count+1);
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
NetOutgoingMessage msg = Server.CreateMessage();
|
||||
msg.Write((byte)PacketTypes.StartGame);
|
||||
|
||||
msg.Write(seed);
|
||||
|
||||
msg.Write(Game1.NetLobbyScreen.LevelSeed);
|
||||
|
||||
msg.Write(Game1.NetLobbyScreen.SelectedMap.Name);
|
||||
msg.Write(Game1.NetLobbyScreen.SelectedMap.Hash.MD5Hash);
|
||||
|
||||
msg.Write(Game1.NetLobbyScreen.GameDuration.TotalMinutes);
|
||||
|
||||
//if (otherClient == client) continue;
|
||||
msg.Write(client.ID);
|
||||
WriteCharacterData(msg, client.name, client.character);
|
||||
|
||||
msg.Write((myClient == null) ? connectedClients.Count - 1 : connectedClients.Count);
|
||||
foreach (Client otherClient in connectedClients)
|
||||
{
|
||||
if (otherClient == client) continue;
|
||||
WriteCharacterData(msg, otherClient.name, otherClient.character);
|
||||
}
|
||||
|
||||
if (myClient!=null)
|
||||
{
|
||||
WriteCharacterData(msg, myClient.name, myClient.character);
|
||||
}
|
||||
|
||||
Server.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableUnordered, 0);
|
||||
}
|
||||
|
||||
if (myClient!=null)
|
||||
{
|
||||
WriteCharacterData(msg, myClient.name, myClient.character);
|
||||
}
|
||||
|
||||
SendMessage(msg, NetDeliveryMethod.ReliableUnordered, null);
|
||||
//}
|
||||
|
||||
gameStarted = true;
|
||||
|
||||
Game1.GameScreen.Cam.TargetPos = Vector2.Zero;
|
||||
@@ -580,7 +594,7 @@ namespace Subsurface.Networking
|
||||
//if there's enough crew members assigned to the job already, continue
|
||||
if (assignedClientCount[jobIndex] >= JobPrefab.List[jobIndex].MaxNumber) continue;
|
||||
|
||||
unassigned[i].assignedJob = JobPrefab.List[i];
|
||||
unassigned[i].assignedJob = JobPrefab.List[jobIndex];
|
||||
|
||||
assignedClientCount[jobIndex]++;
|
||||
unassigned.RemoveAt(i);
|
||||
|
||||
@@ -103,11 +103,12 @@ namespace Subsurface.Networking
|
||||
DebugConsole.ThrowError("Received invalid network message");
|
||||
return false;
|
||||
}
|
||||
|
||||
//288=id, 280=char
|
||||
Entity e = Entity.FindEntityByID(id);
|
||||
if (e == null)
|
||||
{
|
||||
//DebugConsole.ThrowError("Couldn't find an entity matching the ID ''" + id + "''");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,13 +28,16 @@ namespace Subsurface.Networking
|
||||
|
||||
class NetworkMember
|
||||
{
|
||||
protected static Color[] messageColor = { Color.Black, Color.DarkRed, Color.DarkBlue, Color.DarkGreen };
|
||||
protected static Color[] messageColor = { Color.White, Color.Red, Color.LightBlue, Color.LightGreen };
|
||||
|
||||
protected string name;
|
||||
|
||||
protected TimeSpan updateInterval;
|
||||
protected DateTime updateTimer;
|
||||
|
||||
protected GUIFrame inGameHUD;
|
||||
protected GUIListBox chatBox;
|
||||
|
||||
protected bool gameStarted;
|
||||
|
||||
public string Name
|
||||
@@ -46,11 +49,56 @@ namespace Subsurface.Networking
|
||||
name = value;
|
||||
}
|
||||
}
|
||||
|
||||
public GUIFrame InGameHUD
|
||||
{
|
||||
get { return inGameHUD; }
|
||||
}
|
||||
|
||||
public NetworkMember()
|
||||
{
|
||||
inGameHUD = new GUIFrame(new Rectangle(0,0,0,0), null, null);
|
||||
|
||||
int width = 350, height = 100;
|
||||
chatBox = new GUIListBox(new Rectangle(
|
||||
Game1.GraphicsWidth - 20 - width,
|
||||
Game1.GraphicsHeight - 40 - 25 - height,
|
||||
width, height),
|
||||
Color.White * 0.5f, GUI.style, inGameHUD);
|
||||
|
||||
var textBox = new GUITextBox(
|
||||
new Rectangle(chatBox.Rect.X, chatBox.Rect.Y + chatBox.Rect.Height + 20, chatBox.Rect.Width, 25),
|
||||
Color.White * 0.5f, Color.Black, Alignment.TopLeft, Alignment.Left, GUI.style, inGameHUD);
|
||||
textBox.OnEnter = EnterChatMessage;
|
||||
}
|
||||
|
||||
|
||||
public bool EnterChatMessage(GUITextBox textBox, string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message)) return false;
|
||||
|
||||
SendChatMessage(Game1.NetworkMember.Name + ": " + message);
|
||||
|
||||
textBox.Deselect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddChatMessage(string message, ChatMessageType messageType)
|
||||
{
|
||||
Game1.NetLobbyScreen.NewChatMessage(message, messageColor[(int)messageType]);
|
||||
if (Game1.GameSession != null) Game1.GameSession.NewChatMessage(message, messageColor[(int)messageType]);
|
||||
|
||||
GUITextBlock msg = new GUITextBlock(new Rectangle(0, 0, 0, 20), message,
|
||||
((chatBox.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f, messageColor[(int)messageType],
|
||||
Alignment.Left, null, null, true);
|
||||
|
||||
msg.Padding = new Vector4(20.0f, 0, 0, 0);
|
||||
chatBox.AddChild(msg);
|
||||
|
||||
while (chatBox.CountChildren > 20)
|
||||
{
|
||||
chatBox.RemoveChild(chatBox.children[0]);
|
||||
}
|
||||
|
||||
GUI.PlayMessageSound();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user