16_Chat.as 7.6 KB

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