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:
Regalis
2015-07-09 01:40:27 +03:00
parent d56f7f3f77
commit 2254585dac
35 changed files with 831 additions and 312 deletions

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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();
}