// Chat example // This sample demonstrates: // - Starting up a network server or connecting to it // - Implementing simple chat functionality with network messages #include "Scripts/Utilities/Sample.as" // Identifier for the chat network messages const int MSG_CHAT = 32; // UDP port we will use const uint CHAT_SERVER_PORT = 2345; Array chatHistory; Text@ chatHistoryText; UIElement@ buttonContainer; LineEdit@ textEdit; Button@ sendButton; Button@ connectButton; Button@ disconnectButton; Button@ startServerButton; void Start() { // Execute the common startup for samples SampleStart(); // Enable OS cursor input.mouseVisible = true; // Create the user interface CreateUI(); // Subscribe to UI and network events SubscribeToEvents(); } void CreateUI() { SetLogoVisible(false); // We need the full rendering window XMLFile@ uiStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml"); // Set style to the UI root so that elements will inherit it ui.root.defaultStyle = uiStyle; Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"); chatHistoryText = ui.root.CreateChild("Text"); chatHistoryText.SetFont(font, 12); buttonContainer = ui.root.CreateChild("UIElement"); buttonContainer.SetFixedSize(graphics.width, 20); buttonContainer.SetPosition(0, graphics.height - 20); buttonContainer.layoutMode = LM_HORIZONTAL; textEdit = buttonContainer.CreateChild("LineEdit"); textEdit.SetStyleAuto(); sendButton = CreateButton("Send", 70); connectButton = CreateButton("Connect", 90); disconnectButton = CreateButton("Disconnect", 100); startServerButton = CreateButton("Start Server", 110); UpdateButtons(); chatHistory.Resize((graphics.height - 20) / chatHistoryText.rowHeight); // No viewports or scene is defined. However, the default zone's fog color controls the fill color renderer.defaultZone.fogColor = Color(0.0f, 0.0f, 0.1f); } void SubscribeToEvents() { // Subscribe to UI element events SubscribeToEvent(textEdit, "TextFinished", "HandleSend"); SubscribeToEvent(sendButton, "Released", "HandleSend"); SubscribeToEvent(connectButton, "Released", "HandleConnect"); SubscribeToEvent(disconnectButton, "Released", "HandleDisconnect"); SubscribeToEvent(startServerButton, "Released", "HandleStartServer"); // Subscribe to log messages so that we can pipe them to the chat window SubscribeToEvent("LogMessage", "HandleLogMessage"); // Subscribe to network events SubscribeToEvent("NetworkMessage", "HandleNetworkMessage"); SubscribeToEvent("ServerConnected", "HandleConnectionStatus"); SubscribeToEvent("ServerDisconnected", "HandleConnectionStatus"); SubscribeToEvent("ConnectFailed", "HandleConnectionStatus"); } Button@ CreateButton(const String&in text, int width) { Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"); Button@ button = buttonContainer.CreateChild("Button"); button.SetStyleAuto(); button.SetFixedWidth(width); Text@ buttonText = button.CreateChild("Text"); buttonText.SetFont(font, 12); buttonText.SetAlignment(HA_CENTER, VA_CENTER); buttonText.text = text; return button; } void ShowChatText(const String& row) { chatHistory.Erase(0); chatHistory.Push(row); // Concatenate all the rows in history String allRows; for (uint i = 0; i < chatHistory.length; ++i) allRows += chatHistory[i] + "\n"; chatHistoryText.text = allRows; } void UpdateButtons() { Connection@ serverConnection = network.serverConnection; bool serverRunning = network.serverRunning; // Show and hide buttons so that eg. Connect and Disconnect are never shown at the same time sendButton.visible = serverConnection !is null; connectButton.visible = serverConnection is null && !serverRunning; disconnectButton.visible = serverConnection !is null || serverRunning; startServerButton.visible = serverConnection is null && !serverRunning; } void HandleLogMessage(StringHash eventType, VariantMap& eventData) { ShowChatText(eventData["Message"].GetString()); } void HandleSend(StringHash eventType, VariantMap& eventData) { String text = textEdit.text; if (text.empty) return; // Do not send an empty message Connection@ serverConnection = network.serverConnection; if (serverConnection !is null) { // A VectorBuffer object is convenient for constructing a message to send VectorBuffer msg; msg.WriteString(text); // Send the chat message as in-order and reliable serverConnection.SendMessage(MSG_CHAT, true, true, msg); // Empty the text edit after sending textEdit.text = ""; } } void HandleConnect(StringHash eventType, VariantMap& eventData) { String address = textEdit.text.Trimmed(); if (address.empty) address = "localhost"; // Use localhost to connect if nothing else specified // Empty the text edit after reading the address to connect to textEdit.text = ""; // Connect to server, do not specify a client scene as we are not using scene replication, just messages. // At connect time we could also send identity parameters (such as username) in a VariantMap, but in this // case we skip it for simplicity network.Connect(address, CHAT_SERVER_PORT, null); UpdateButtons(); } void HandleDisconnect(StringHash eventType, VariantMap& eventData) { Connection@ serverConnection = network.serverConnection; // If we were connected to server, disconnect if (serverConnection !is null) serverConnection.Disconnect(); // Or if we were running a server, stop it else if (network.serverRunning) network.StopServer(); UpdateButtons(); } void HandleStartServer(StringHash eventType, VariantMap& eventData) { network.StartServer(CHAT_SERVER_PORT); UpdateButtons(); } void HandleNetworkMessage(StringHash eventType, VariantMap& eventData) { int msgID = eventData["MessageID"].GetInt(); if (msgID == MSG_CHAT) { VectorBuffer msg = eventData["Data"].GetBuffer(); String text = msg.ReadString(); // If we are the server, prepend the sender's IP address and port and echo to everyone // If we are a client, just display the message if (network.serverRunning) { Connection@ sender = eventData["Connection"].GetPtr(); text = sender.ToString() + " " + text; VectorBuffer sendMsg; sendMsg.WriteString(text); // Broadcast as in-order and reliable network.BroadcastMessage(MSG_CHAT, true, true, sendMsg); } ShowChatText(text); } } void HandleConnectionStatus(StringHash eventType, VariantMap& eventData) { UpdateButtons(); } // Create XML patch instructions for screen joystick layout specific to this sample app String patchInstructions = "" + " " + " " + " " + " " + " " + " " + "";