16_Chat.as 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Chat example
  2. // This sample demonstrates:
  3. // - Starting up a network server or connecting to it
  4. // - Implementing simple chat functionality with network messages
  5. #include "Scripts/Utilities/Sample.as"
  6. // Identifier for the chat network messages
  7. const int MSG_CHAT = 32;
  8. // UDP port we will use
  9. const uint CHAT_SERVER_PORT = 2345;
  10. Array<String> chatHistory;
  11. Text@ chatHistoryText;
  12. UIElement@ buttonContainer;
  13. LineEdit@ textEdit;
  14. Button@ sendButton;
  15. Button@ connectButton;
  16. Button@ disconnectButton;
  17. Button@ startServerButton;
  18. void Start()
  19. {
  20. // Execute the common startup for samples
  21. SampleStart();
  22. // Enable OS cursor
  23. input.mouseVisible = true;
  24. // Create the user interface
  25. CreateUI();
  26. // Subscribe to UI and network events
  27. SubscribeToEvents();
  28. }
  29. void CreateUI()
  30. {
  31. SetLogoVisible(false); // We need the full rendering window
  32. XMLFile@ uiStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
  33. // Set style to the UI root so that elements will inherit it
  34. ui.root.defaultStyle = uiStyle;
  35. Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf");
  36. chatHistoryText = ui.root.CreateChild("Text");
  37. chatHistoryText.SetFont(font, 12);
  38. buttonContainer = ui.root.CreateChild("UIElement");
  39. buttonContainer.SetFixedSize(graphics.width, 20);
  40. buttonContainer.SetPosition(0, graphics.height - 20);
  41. buttonContainer.layoutMode = LM_HORIZONTAL;
  42. textEdit = buttonContainer.CreateChild("LineEdit");
  43. textEdit.SetStyleAuto();
  44. sendButton = CreateButton("Send", 70);
  45. connectButton = CreateButton("Connect", 90);
  46. disconnectButton = CreateButton("Disconnect", 100);
  47. startServerButton = CreateButton("Start Server", 110);
  48. UpdateButtons();
  49. chatHistory.Resize((graphics.height - 20) / chatHistoryText.rowHeight);
  50. // No viewports or scene is defined. However, the default zone's fog color controls the fill color
  51. renderer.defaultZone.fogColor = Color(0.0f, 0.0f, 0.1f);
  52. }
  53. void SubscribeToEvents()
  54. {
  55. // Subscribe to UI element events
  56. SubscribeToEvent(textEdit, "TextFinished", "HandleSend");
  57. SubscribeToEvent(sendButton, "Released", "HandleSend");
  58. SubscribeToEvent(connectButton, "Released", "HandleConnect");
  59. SubscribeToEvent(disconnectButton, "Released", "HandleDisconnect");
  60. SubscribeToEvent(startServerButton, "Released", "HandleStartServer");
  61. // Subscribe to log messages so that we can pipe them to the chat window
  62. SubscribeToEvent("LogMessage", "HandleLogMessage");
  63. // Subscribe to network events
  64. SubscribeToEvent("NetworkMessage", "HandleNetworkMessage");
  65. SubscribeToEvent("ServerConnected", "HandleConnectionStatus");
  66. SubscribeToEvent("ServerDisconnected", "HandleConnectionStatus");
  67. SubscribeToEvent("ConnectFailed", "HandleConnectionStatus");
  68. }
  69. Button@ CreateButton(const String&in text, int width)
  70. {
  71. Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf");
  72. Button@ button = buttonContainer.CreateChild("Button");
  73. button.SetStyleAuto();
  74. button.SetFixedWidth(width);
  75. Text@ buttonText = button.CreateChild("Text");
  76. buttonText.SetFont(font, 12);
  77. buttonText.SetAlignment(HA_CENTER, VA_CENTER);
  78. buttonText.text = text;
  79. return button;
  80. }
  81. void ShowChatText(const String& row)
  82. {
  83. chatHistory.Erase(0);
  84. chatHistory.Push(row);
  85. // Concatenate all the rows in history
  86. String allRows;
  87. for (uint i = 0; i < chatHistory.length; ++i)
  88. allRows += chatHistory[i] + "\n";
  89. chatHistoryText.text = allRows;
  90. }
  91. void UpdateButtons()
  92. {
  93. Connection@ serverConnection = network.serverConnection;
  94. bool serverRunning = network.serverRunning;
  95. // Show and hide buttons so that eg. Connect and Disconnect are never shown at the same time
  96. sendButton.visible = serverConnection !is null;
  97. connectButton.visible = serverConnection is null && !serverRunning;
  98. disconnectButton.visible = serverConnection !is null || serverRunning;
  99. startServerButton.visible = serverConnection is null && !serverRunning;
  100. }
  101. void HandleLogMessage(StringHash eventType, VariantMap& eventData)
  102. {
  103. ShowChatText(eventData["Message"].GetString());
  104. }
  105. void HandleSend(StringHash eventType, VariantMap& eventData)
  106. {
  107. String text = textEdit.text;
  108. if (text.empty)
  109. return; // Do not send an empty message
  110. Connection@ serverConnection = network.serverConnection;
  111. if (serverConnection !is null)
  112. {
  113. // A VectorBuffer object is convenient for constructing a message to send
  114. VectorBuffer msg;
  115. msg.WriteString(text);
  116. // Send the chat message as in-order and reliable
  117. serverConnection.SendMessage(MSG_CHAT, true, true, msg);
  118. // Empty the text edit after sending
  119. textEdit.text = "";
  120. }
  121. }
  122. void HandleConnect(StringHash eventType, VariantMap& eventData)
  123. {
  124. String address = textEdit.text.Trimmed();
  125. if (address.empty)
  126. address = "localhost"; // Use localhost to connect if nothing else specified
  127. // Empty the text edit after reading the address to connect to
  128. textEdit.text = "";
  129. // Connect to server, do not specify a client scene as we are not using scene replication, just messages.
  130. // At connect time we could also send identity parameters (such as username) in a VariantMap, but in this
  131. // case we skip it for simplicity
  132. network.Connect(address, CHAT_SERVER_PORT, null);
  133. UpdateButtons();
  134. }
  135. void HandleDisconnect(StringHash eventType, VariantMap& eventData)
  136. {
  137. Connection@ serverConnection = network.serverConnection;
  138. // If we were connected to server, disconnect
  139. if (serverConnection !is null)
  140. serverConnection.Disconnect();
  141. // Or if we were running a server, stop it
  142. else if (network.serverRunning)
  143. network.StopServer();
  144. UpdateButtons();
  145. }
  146. void HandleStartServer(StringHash eventType, VariantMap& eventData)
  147. {
  148. network.StartServer(CHAT_SERVER_PORT);
  149. UpdateButtons();
  150. }
  151. void HandleNetworkMessage(StringHash eventType, VariantMap& eventData)
  152. {
  153. int msgID = eventData["MessageID"].GetInt();
  154. if (msgID == MSG_CHAT)
  155. {
  156. VectorBuffer msg = eventData["Data"].GetBuffer();
  157. String text = msg.ReadString();
  158. // If we are the server, prepend the sender's IP address and port and echo to everyone
  159. // If we are a client, just display the message
  160. if (network.serverRunning)
  161. {
  162. Connection@ sender = eventData["Connection"].GetPtr();
  163. text = sender.ToString() + " " + text;
  164. VectorBuffer sendMsg;
  165. sendMsg.WriteString(text);
  166. // Broadcast as in-order and reliable
  167. network.BroadcastMessage(MSG_CHAT, true, true, sendMsg);
  168. }
  169. ShowChatText(text);
  170. }
  171. }
  172. void HandleConnectionStatus(StringHash eventType, VariantMap& eventData)
  173. {
  174. UpdateButtons();
  175. }
  176. // Create XML patch instructions for screen joystick layout specific to this sample app
  177. String patchInstructions =
  178. "<patch>" +
  179. " <add sel=\"/element/element[./attribute[@name='Name' and @value='Button2']]\">" +
  180. " <attribute name=\"Is Visible\" value=\"false\" />" +
  181. " </add>" +
  182. " <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" +
  183. " <attribute name=\"Is Visible\" value=\"false\" />" +
  184. " </add>" +
  185. "</patch>";