cukunity 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +0 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +15 -0
  5. data/Gemfile.lock +60 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.md +214 -0
  8. data/Rakefile +51 -0
  9. data/Unity/Assets/Demo/Art/Buttons/down.png +0 -0
  10. data/Unity/Assets/Demo/Art/Buttons/down.png.meta +28 -0
  11. data/Unity/Assets/Demo/Art/Buttons/left.png +0 -0
  12. data/Unity/Assets/Demo/Art/Buttons/left.png.meta +28 -0
  13. data/Unity/Assets/Demo/Art/Buttons/ok.png +0 -0
  14. data/Unity/Assets/Demo/Art/Buttons/ok.png.meta +28 -0
  15. data/Unity/Assets/Demo/Art/Buttons/options.png +0 -0
  16. data/Unity/Assets/Demo/Art/Buttons/options.png.meta +28 -0
  17. data/Unity/Assets/Demo/Art/Buttons/play.png +0 -0
  18. data/Unity/Assets/Demo/Art/Buttons/play.png.meta +28 -0
  19. data/Unity/Assets/Demo/Art/Buttons/quit.png +0 -0
  20. data/Unity/Assets/Demo/Art/Buttons/quit.png.meta +28 -0
  21. data/Unity/Assets/Demo/Art/Buttons/retry.png +0 -0
  22. data/Unity/Assets/Demo/Art/Buttons/retry.png.meta +28 -0
  23. data/Unity/Assets/Demo/Art/Buttons/right.png +0 -0
  24. data/Unity/Assets/Demo/Art/Buttons/right.png.meta +28 -0
  25. data/Unity/Assets/Demo/Art/Buttons/up.png +0 -0
  26. data/Unity/Assets/Demo/Art/Buttons/up.png.meta +28 -0
  27. data/Unity/Assets/Demo/Art/Buttons.meta +2 -0
  28. data/Unity/Assets/Demo/Art/clear.png +0 -0
  29. data/Unity/Assets/Demo/Art/clear.png.meta +28 -0
  30. data/Unity/Assets/Demo/Art/options.png +0 -0
  31. data/Unity/Assets/Demo/Art/options.png.meta +28 -0
  32. data/Unity/Assets/Demo/Art/sokoban.png +0 -0
  33. data/Unity/Assets/Demo/Art/sokoban.png.meta +28 -0
  34. data/Unity/Assets/Demo/Art.meta +2 -0
  35. data/Unity/Assets/Demo/Cubes/CrateCube.mat +0 -0
  36. data/Unity/Assets/Demo/Cubes/CrateCube.mat.meta +2 -0
  37. data/Unity/Assets/Demo/Cubes/CrateCube.prefab +0 -0
  38. data/Unity/Assets/Demo/Cubes/CrateCube.prefab.meta +2 -0
  39. data/Unity/Assets/Demo/Cubes/FloorCube.mat +0 -0
  40. data/Unity/Assets/Demo/Cubes/FloorCube.mat.meta +2 -0
  41. data/Unity/Assets/Demo/Cubes/FloorCube.prefab +0 -0
  42. data/Unity/Assets/Demo/Cubes/FloorCube.prefab.meta +2 -0
  43. data/Unity/Assets/Demo/Cubes/GoalCube.mat +0 -0
  44. data/Unity/Assets/Demo/Cubes/GoalCube.mat.meta +2 -0
  45. data/Unity/Assets/Demo/Cubes/GoalCube.prefab +0 -0
  46. data/Unity/Assets/Demo/Cubes/GoalCube.prefab.meta +2 -0
  47. data/Unity/Assets/Demo/Cubes/PlayerCube.mat +0 -0
  48. data/Unity/Assets/Demo/Cubes/PlayerCube.mat.meta +2 -0
  49. data/Unity/Assets/Demo/Cubes/PlayerCube.prefab +0 -0
  50. data/Unity/Assets/Demo/Cubes/PlayerCube.prefab.meta +2 -0
  51. data/Unity/Assets/Demo/Cubes/WallCube.mat +0 -0
  52. data/Unity/Assets/Demo/Cubes/WallCube.mat.meta +2 -0
  53. data/Unity/Assets/Demo/Cubes/WallCube.prefab +0 -0
  54. data/Unity/Assets/Demo/Cubes/WallCube.prefab.meta +2 -0
  55. data/Unity/Assets/Demo/Cubes.meta +2 -0
  56. data/Unity/Assets/Demo/Resources/MainMenu.prefab +0 -0
  57. data/Unity/Assets/Demo/Resources/MainMenu.prefab.meta +2 -0
  58. data/Unity/Assets/Demo/Resources/OptionsMenu.prefab +0 -0
  59. data/Unity/Assets/Demo/Resources/OptionsMenu.prefab.meta +2 -0
  60. data/Unity/Assets/Demo/Resources.meta +2 -0
  61. data/Unity/Assets/Demo/Scripts/CameraController.js +18 -0
  62. data/Unity/Assets/Demo/Scripts/CameraController.js.meta +2 -0
  63. data/Unity/Assets/Demo/Scripts/EnterPlayerName.js +21 -0
  64. data/Unity/Assets/Demo/Scripts/EnterPlayerName.js.meta +2 -0
  65. data/Unity/Assets/Demo/Scripts/GameLeftButton.js +18 -0
  66. data/Unity/Assets/Demo/Scripts/GameLeftButton.js.meta +2 -0
  67. data/Unity/Assets/Demo/Scripts/GameQuitButton.js +6 -0
  68. data/Unity/Assets/Demo/Scripts/GameQuitButton.js.meta +2 -0
  69. data/Unity/Assets/Demo/Scripts/GameRetryButton.js +7 -0
  70. data/Unity/Assets/Demo/Scripts/GameRetryButton.js.meta +2 -0
  71. data/Unity/Assets/Demo/Scripts/GameRightButton.js +18 -0
  72. data/Unity/Assets/Demo/Scripts/GameRightButton.js.meta +2 -0
  73. data/Unity/Assets/Demo/Scripts/GameUpButton.js +18 -0
  74. data/Unity/Assets/Demo/Scripts/GameUpButton.js.meta +2 -0
  75. data/Unity/Assets/Demo/Scripts/OnTouchGUIElementDown.js +34 -0
  76. data/Unity/Assets/Demo/Scripts/OnTouchGUIElementDown.js.meta +2 -0
  77. data/Unity/Assets/Demo/Scripts/PlayerData.js +3 -0
  78. data/Unity/Assets/Demo/Scripts/PlayerData.js.meta +2 -0
  79. data/Unity/Assets/Demo/Scripts/SokobanController.js +240 -0
  80. data/Unity/Assets/Demo/Scripts/SokobanController.js.meta +2 -0
  81. data/Unity/Assets/Demo/Scripts/TakeScreenShot.js +26 -0
  82. data/Unity/Assets/Demo/Scripts/TakeScreenShot.js.meta +2 -0
  83. data/Unity/Assets/Demo/Scripts/TitleOptionsButton.js +8 -0
  84. data/Unity/Assets/Demo/Scripts/TitleOptionsButton.js.meta +2 -0
  85. data/Unity/Assets/Demo/Scripts/TitleOptionsOkButton.js +8 -0
  86. data/Unity/Assets/Demo/Scripts/TitleOptionsOkButton.js.meta +2 -0
  87. data/Unity/Assets/Demo/Scripts/TitlePlayButton.js +6 -0
  88. data/Unity/Assets/Demo/Scripts/TitlePlayButton.js.meta +2 -0
  89. data/Unity/Assets/Demo/Scripts/TitleQuitButton.js +7 -0
  90. data/Unity/Assets/Demo/Scripts/TitleQuitButton.js.meta +2 -0
  91. data/Unity/Assets/Demo/Scripts/UpdateMovesLabel.js +26 -0
  92. data/Unity/Assets/Demo/Scripts/UpdateMovesLabel.js.meta +2 -0
  93. data/Unity/Assets/Demo/Scripts/UpdatePlayerName.js +14 -0
  94. data/Unity/Assets/Demo/Scripts/UpdatePlayerName.js.meta +2 -0
  95. data/Unity/Assets/Demo/Scripts.meta +2 -0
  96. data/Unity/Assets/Demo/demo_game.unity +0 -0
  97. data/Unity/Assets/Demo/demo_game.unity.meta +2 -0
  98. data/Unity/Assets/Demo/demo_title.unity +0 -0
  99. data/Unity/Assets/Demo/demo_title.unity.meta +2 -0
  100. data/Unity/Assets/Demo.meta +2 -0
  101. data/Unity/Assets/Plugins/CukunityInstance.prefab +0 -0
  102. data/Unity/Assets/Plugins/CukunityInstance.prefab.meta +2 -0
  103. data/Unity/Assets/Plugins/CukunityServer.cs +871 -0
  104. data/Unity/Assets/Plugins/CukunityServer.cs.meta +2 -0
  105. data/Unity/Assets/Plugins/JsonFx.Json.dll +0 -0
  106. data/Unity/Assets/Plugins/JsonFx.Json.dll.meta +2 -0
  107. data/Unity/Assets/Plugins/iOS/CukunityServer.mm +242 -0
  108. data/Unity/Assets/Plugins/iOS/CukunityServer.mm.meta +2 -0
  109. data/Unity/Assets/Plugins/iOS.meta +2 -0
  110. data/Unity/Assets/Plugins.meta +2 -0
  111. data/Unity/Library/AudioManager.asset +0 -0
  112. data/Unity/Library/BuildSettings.asset +0 -0
  113. data/Unity/Library/DynamicsManager.asset +0 -0
  114. data/Unity/Library/EditorBuildSettings.asset +0 -0
  115. data/Unity/Library/EditorSettings.asset +0 -0
  116. data/Unity/Library/EditorUserBuildSettings.asset +0 -0
  117. data/Unity/Library/EditorUserSettings.asset +0 -0
  118. data/Unity/Library/InputManager.asset +0 -0
  119. data/Unity/Library/InspectorExpandedItems.asset +0 -0
  120. data/Unity/Library/MonoManager.asset +0 -0
  121. data/Unity/Library/NetworkManager.asset +0 -0
  122. data/Unity/Library/ProjectSettings.asset +0 -0
  123. data/Unity/Library/QualitySettings.asset +0 -0
  124. data/Unity/Library/TagManager.asset +0 -0
  125. data/Unity/Library/TimeManager.asset +0 -0
  126. data/Unity/ProjectSettings/AudioManager.asset +0 -0
  127. data/Unity/ProjectSettings/DynamicsManager.asset +0 -0
  128. data/Unity/ProjectSettings/EditorBuildSettings.asset +0 -0
  129. data/Unity/ProjectSettings/EditorSettings.asset +0 -0
  130. data/Unity/ProjectSettings/InputManager.asset +0 -0
  131. data/Unity/ProjectSettings/NavMeshLayers.asset +0 -0
  132. data/Unity/ProjectSettings/NetworkManager.asset +0 -0
  133. data/Unity/ProjectSettings/ProjectSettings.asset +0 -0
  134. data/Unity/ProjectSettings/QualitySettings.asset +0 -0
  135. data/Unity/ProjectSettings/TagManager.asset +0 -0
  136. data/Unity/ProjectSettings/TimeManager.asset +0 -0
  137. data/VERSION +1 -0
  138. data/bin/cukunity +7 -0
  139. data/cukunity.gemspec +298 -0
  140. data/features/get_scene_command.feature +39 -0
  141. data/features/i18n/ja/sokoban_clear.feature +109 -0
  142. data/features/install.feature +23 -0
  143. data/features/keyboard_input.feature +26 -0
  144. data/features/load_level_command.feature +36 -0
  145. data/features/run.feature +33 -0
  146. data/features/select_visible.feature +29 -0
  147. data/features/support/env.rb +11 -0
  148. data/features/touch_input.feature +96 -0
  149. data/lib/cukunity/cli/argument_parser.rb +103 -0
  150. data/lib/cukunity/cli/bootstrap_command.rb +39 -0
  151. data/lib/cukunity/cli/doctor_command.rb +150 -0
  152. data/lib/cukunity/cli/features_command.rb +35 -0
  153. data/lib/cukunity/cli/main.rb +18 -0
  154. data/lib/cukunity/cli/options.rb +8 -0
  155. data/lib/cukunity/cli.rb +11 -0
  156. data/lib/cukunity/cucumber/step_definitions/get_scene_command_steps.rb +37 -0
  157. data/lib/cukunity/cucumber/step_definitions/i18n/ja/get_scene_command_steps.rb +37 -0
  158. data/lib/cukunity/cucumber/step_definitions/i18n/ja/install_steps.rb +25 -0
  159. data/lib/cukunity/cucumber/step_definitions/i18n/ja/keyboard_input_steps.rb +17 -0
  160. data/lib/cukunity/cucumber/step_definitions/i18n/ja/load_level_command_steps.rb +17 -0
  161. data/lib/cukunity/cucumber/step_definitions/i18n/ja/run_steps.rb +25 -0
  162. data/lib/cukunity/cucumber/step_definitions/i18n/ja/select_visible_steps.rb +9 -0
  163. data/lib/cukunity/cucumber/step_definitions/i18n/ja/touch_input_steps.rb +19 -0
  164. data/lib/cukunity/cucumber/step_definitions/i18n/ja.rb +9 -0
  165. data/lib/cukunity/cucumber/step_definitions/install_steps.rb +33 -0
  166. data/lib/cukunity/cucumber/step_definitions/keyboard_input_steps.rb +13 -0
  167. data/lib/cukunity/cucumber/step_definitions/load_level_command_steps.rb +17 -0
  168. data/lib/cukunity/cucumber/step_definitions/run_steps.rb +32 -0
  169. data/lib/cukunity/cucumber/step_definitions/select_visible_steps.rb +15 -0
  170. data/lib/cukunity/cucumber/step_definitions/touch_input_steps.rb +18 -0
  171. data/lib/cukunity/cucumber/support/platform_helpers.rb +105 -0
  172. data/lib/cukunity/cucumber/support/spec_helpers.rb +21 -0
  173. data/lib/cukunity/cucumber/support/transforms.rb +5 -0
  174. data/lib/cukunity/cucumber/support/unity_helpers.rb +35 -0
  175. data/lib/cukunity/cucumber.rb +28 -0
  176. data/lib/cukunity/drivers/android/app.rb +43 -0
  177. data/lib/cukunity/drivers/android/appkiller/.gitignore +9 -0
  178. data/lib/cukunity/drivers/android/appkiller/AndroidManifest.xml +17 -0
  179. data/lib/cukunity/drivers/android/appkiller/ant.properties +17 -0
  180. data/lib/cukunity/drivers/android/appkiller/build.xml +85 -0
  181. data/lib/cukunity/drivers/android/appkiller/proguard.cfg +40 -0
  182. data/lib/cukunity/drivers/android/appkiller/project.properties +11 -0
  183. data/lib/cukunity/drivers/android/appkiller/res/layout/main.xml +13 -0
  184. data/lib/cukunity/drivers/android/appkiller/res/values/strings.xml +4 -0
  185. data/lib/cukunity/drivers/android/appkiller/src/cukunity/appkiller/AppKiller.java +29 -0
  186. data/lib/cukunity/drivers/android/keyboard_input.rb +149 -0
  187. data/lib/cukunity/drivers/android/keycodes.rb +531 -0
  188. data/lib/cukunity/drivers/android/monkey_client.rb +65 -0
  189. data/lib/cukunity/drivers/android/process.rb +103 -0
  190. data/lib/cukunity/drivers/android/touch_input.rb +24 -0
  191. data/lib/cukunity/drivers/android/tunnel_client_methods.rb +22 -0
  192. data/lib/cukunity/drivers/android/unity_client.rb +27 -0
  193. data/lib/cukunity/drivers/android/utils.rb +50 -0
  194. data/lib/cukunity/drivers/android.rb +9 -0
  195. data/lib/cukunity/drivers/iOS/app.rb +32 -0
  196. data/lib/cukunity/drivers/iOS/keyboard_input.rb +104 -0
  197. data/lib/cukunity/drivers/iOS/process.rb +42 -0
  198. data/lib/cukunity/drivers/iOS/touch_input.rb +18 -0
  199. data/lib/cukunity/drivers/iOS/tunnel_client_methods.rb +27 -0
  200. data/lib/cukunity/drivers/iOS/uiautomation.rb +97 -0
  201. data/lib/cukunity/drivers/iOS/uiautomation_master.rb +152 -0
  202. data/lib/cukunity/drivers/iOS/uiautomation_slave.js +238 -0
  203. data/lib/cukunity/drivers/iOS/uiautomation_slave.rb +41 -0
  204. data/lib/cukunity/drivers/iOS/unity_client.rb +27 -0
  205. data/lib/cukunity/drivers/iOS/utils.rb +46 -0
  206. data/lib/cukunity/drivers/iOS.rb +9 -0
  207. data/lib/cukunity/exceptions.rb +24 -0
  208. data/lib/cukunity/keyboard_input_methods.rb +35 -0
  209. data/lib/cukunity/request_line_response_client_methods.rb +80 -0
  210. data/lib/cukunity/tasks/cucumber.rake +22 -0
  211. data/lib/cukunity/touch_input_methods.rb +19 -0
  212. data/lib/cukunity/unity/client_methods.rb +46 -0
  213. data/lib/cukunity/unity/command_facade.rb +67 -0
  214. data/lib/cukunity/unity/component.rb +39 -0
  215. data/lib/cukunity/unity/gameobject.rb +53 -0
  216. data/lib/cukunity/unity/hint.rb +27 -0
  217. data/lib/cukunity/unity/json_container.rb +48 -0
  218. data/lib/cukunity/unity/level.rb +6 -0
  219. data/lib/cukunity/unity/scene.rb +18 -0
  220. data/lib/cukunity/unity/screen.rb +45 -0
  221. data/lib/cukunity/unity/screen_hint_methods.rb +61 -0
  222. data/lib/cukunity/unity/text_hint_methods.rb +17 -0
  223. data/lib/cukunity/unity.rb +11 -0
  224. data/lib/cukunity/utils.rb +56 -0
  225. data/lib/cukunity.rb +19 -0
  226. metadata +411 -0
@@ -0,0 +1,871 @@
1
+ using UnityEngine;
2
+ using System.Collections;
3
+
4
+ using System;
5
+ using System.Net;
6
+ using System.Net.Sockets;
7
+ using System.Text;
8
+ using System.Threading;
9
+ using System.Collections.Generic;
10
+
11
+ using JsonFx.Json;
12
+
13
+ using System.Runtime.InteropServices;
14
+
15
+ public class CukunityServer : MonoBehaviour
16
+ {
17
+ public string ip = "127.0.0.1";
18
+ public int port = 9921;
19
+ public bool excludeSelfFromScene = true;
20
+
21
+ private TcpListener listener = null;
22
+ private List<CukunityRequest> requests;
23
+
24
+ public static CukunityServer instance = null;
25
+
26
+ void Awake()
27
+ {
28
+ if (instance != null)
29
+ {
30
+ Destroy(gameObject);
31
+ return;
32
+ }
33
+ instance = this;
34
+ // prevent ourselves being removed from the scene when loading new levels
35
+ DontDestroyOnLoad(gameObject);
36
+ // start server
37
+ requests = new List<CukunityRequest>();
38
+ StartCoroutine(Listen());
39
+ }
40
+
41
+ private IEnumerator Listen()
42
+ {
43
+ yield return new WaitForEndOfFrame();
44
+
45
+ Debug.LogWarning("Cukunity: Listening on " + ip + ":" + port.ToString());
46
+
47
+ IPAddress localAddr = IPAddress.Parse(ip);
48
+ listener = new TcpListener(localAddr, port);
49
+
50
+ // start listening
51
+ listener.Start();
52
+
53
+ // wait for our first client
54
+ listener.BeginAcceptTcpClient(OnAcceptTcpClientComplete, this);
55
+ StartCoroutine(MainLoop());
56
+ }
57
+
58
+ private IEnumerator MainLoop()
59
+ {
60
+ List<CukunityRequest> pendingRequests;
61
+
62
+ while (true)
63
+ {
64
+ pendingRequests = null;
65
+ lock(requests)
66
+ {
67
+ if (requests.Count > 0)
68
+ {
69
+ pendingRequests = new List<CukunityRequest>(requests);
70
+ requests.Clear();
71
+ }
72
+ }
73
+ if (pendingRequests != null)
74
+ {
75
+ pendingRequests.ForEach(ProcessRequest);
76
+ yield return new WaitForEndOfFrame();
77
+ }
78
+ else
79
+ {
80
+ yield return new WaitForSeconds(0.1f);
81
+ }
82
+ }
83
+ }
84
+
85
+ private void ProcessRequest(CukunityRequest req)
86
+ {
87
+ Hashtable res = new Hashtable();
88
+ try
89
+ {
90
+ // read data from client as a JSON dictionary
91
+ Hashtable jsonReq = JsonReader.Deserialize<Hashtable>(req.Request);
92
+
93
+ string cmdName = GetJsonString(jsonReq, "command");
94
+
95
+ if ((cmdName == null) || (cmdName.Length == 0))
96
+ {
97
+ Debug.LogError("Cukunity: missing command in client's request (" + req.Request + ")");
98
+ res["error"] = "MissingCommandError";
99
+ req.OnProcessed(JsonWriter.Serialize(res));
100
+ return;
101
+ }
102
+
103
+ CukunityCommand cmd;
104
+
105
+ switch (cmdName)
106
+ {
107
+ case "get_screen":
108
+ cmd = new CukunityGetScreenCommand();
109
+ break;
110
+
111
+ case "get_scene":
112
+ cmd = new CukunityGetSceneCommand();
113
+ break;
114
+
115
+ case "get_level":
116
+ cmd = new CukunityGetLevelCommand();
117
+ break;
118
+
119
+ case "load_level":
120
+ cmd = new CukunityLoadLevelCommand();
121
+ break;
122
+
123
+ #if UNITY_IPHONE
124
+ case "touch_screen":
125
+ cmd = new CukunityTouchScreenCommand();
126
+ break;
127
+ #endif
128
+
129
+ default:
130
+ Debug.LogError("Cukunity: unknown command in client's request (" + req.Request + ")");
131
+ res["error"] = "UnknownCommandError";
132
+ req.OnProcessed(JsonWriter.Serialize(res));
133
+ return;
134
+ }
135
+
136
+ cmd.Process(jsonReq, res);
137
+ }
138
+ catch (Exception e)
139
+ {
140
+ Debug.LogError("Cukunity: exception while processing client's request (" + e + ")");
141
+ res["error"] = "ServerError";
142
+ }
143
+ // reply to client
144
+ req.OnProcessed(JsonWriter.Serialize(res));
145
+ }
146
+
147
+ private static string GetJsonString(Hashtable data, string key)
148
+ {
149
+ if ((data == null) ||
150
+ (!data.Contains(key)) ||
151
+ (data[key].GetType() != typeof(string)))
152
+ {
153
+ return null;
154
+ }
155
+ return data[key] as string;
156
+ }
157
+
158
+ private static bool GetJsonInt(Hashtable data, string key, ref int value)
159
+ {
160
+ if ((data == null) ||
161
+ (!data.Contains(key)) ||
162
+ (data[key].GetType() != typeof(int)))
163
+ {
164
+ return false;
165
+ }
166
+ value = (int)data[key];
167
+ return true;
168
+ }
169
+
170
+ void OnDestroy()
171
+ {
172
+ try
173
+ {
174
+ if (listener != null)
175
+ {
176
+ listener.Stop();
177
+ }
178
+ }
179
+ catch (SocketException)
180
+ {
181
+ }
182
+ }
183
+
184
+ public void EnqueueRequest(CukunityRequest req)
185
+ {
186
+ lock(requests)
187
+ {
188
+ requests.Add(req);
189
+ }
190
+ }
191
+
192
+ static private void OnAcceptTcpClientComplete(IAsyncResult result)
193
+ {
194
+ CukunityServer server = result.AsyncState as CukunityServer;
195
+ TcpClient client = server.listener.EndAcceptTcpClient(result);
196
+
197
+ Debug.LogWarning("Cukunity: client connected");
198
+
199
+ CukunityClient cukieClient = new CukunityClient(client, server);
200
+
201
+ // ready for a new client
202
+ server.listener.BeginAcceptTcpClient(OnAcceptTcpClientComplete, server);
203
+
204
+ // start client
205
+ cukieClient.SendAck();
206
+ }
207
+
208
+ public class CukunityCommand
209
+ {
210
+ public delegate object GameObjectVisitor(GameObject obj, object context);
211
+
212
+ public virtual void Process(Hashtable req, Hashtable res)
213
+ {
214
+ throw new System.Exception("Not implemented");
215
+ }
216
+
217
+ protected void Traverse(GameObject obj, GameObjectVisitor visitor, object context)
218
+ {
219
+ context = visitor(obj, context);
220
+ foreach (Transform child in obj.transform)
221
+ {
222
+ Traverse(child.gameObject, visitor, context);
223
+ }
224
+ }
225
+ }
226
+
227
+ public class CukunityGetSceneCommand : CukunityCommand
228
+ {
229
+ public delegate void SerializerMethod(Component c, Hashtable h);
230
+
231
+ public override void Process(Hashtable req, Hashtable res)
232
+ {
233
+ List<GameObject> objs = new List<GameObject>();
234
+
235
+ // get all objects on the root
236
+ foreach (GameObject obj in UnityEngine.Object.FindObjectsOfType(typeof(GameObject)))
237
+ {
238
+ if ((obj.transform.parent == null) &&
239
+ // exclude this game object?
240
+ ((!CukunityServer.instance.excludeSelfFromScene) ||
241
+ ((CukunityServer.instance.excludeSelfFromScene) &&
242
+ (obj != CukunityServer.instance.gameObject))))
243
+ {
244
+ objs.Add(obj);
245
+ }
246
+ }
247
+
248
+ // traverse all objects recursively
249
+ List<Hashtable> rootObjects = new List<Hashtable>();
250
+ res["gameObjects"] = rootObjects;
251
+ foreach (GameObject obj in objs)
252
+ {
253
+ Traverse(obj, SerializeGameObject, rootObjects);
254
+ }
255
+ }
256
+
257
+ private object SerializeGameObject(GameObject obj, object context)
258
+ {
259
+ Hashtable objHash = new Hashtable();
260
+ objHash["instanceID"] = obj.GetInstanceID();
261
+ objHash["name"] = obj.name;
262
+ objHash["tag"] = obj.tag;
263
+ objHash["active"] = obj.active;
264
+
265
+ Hashtable layerHash = new Hashtable();
266
+ layerHash["name"] = LayerMask.LayerToName(obj.layer);
267
+ layerHash["value"] = obj.layer;
268
+ objHash["layer"] = layerHash;
269
+
270
+ objHash["children"] = new List<Hashtable>();
271
+ objHash["components"] = SerializeComponents(obj);
272
+
273
+ List<Hashtable> objs = context as List<Hashtable>;
274
+ if (objs != null)
275
+ {
276
+ objs.Add(objHash);
277
+ }
278
+
279
+ return objHash["children"];
280
+ }
281
+
282
+ private List<Hashtable> SerializeComponents(GameObject obj)
283
+ {
284
+ List<Hashtable> components = new List<Hashtable>();
285
+ Component[] comps = obj.GetComponents<Component>();
286
+
287
+ foreach (Component comp in comps)
288
+ {
289
+ Hashtable compHash = new Hashtable();
290
+
291
+ compHash["instanceID"] = comp.GetInstanceID();
292
+ compHash["type"] = GetComponentTypeString(comp);
293
+
294
+ Behaviour behaviour = null;
295
+ // is this Component a Behaviour?
296
+ if (typeof(Behaviour).IsAssignableFrom(comp.GetType()))
297
+ {
298
+ behaviour = comp as Behaviour;
299
+ compHash["enabled"] = behaviour.enabled;
300
+ }
301
+ // serialize component
302
+ SerializeComponent(comp, compHash);
303
+
304
+ // add it to the list of components
305
+ components.Add(compHash);
306
+ }
307
+ return components;
308
+ }
309
+
310
+ public static string GetComponentTypeString(Component comp, Type t = null)
311
+ {
312
+ if (t == null)
313
+ {
314
+ t = comp.GetType();
315
+ }
316
+ string compType = t.ToString();
317
+
318
+ // I have seen this happen for a Camera's FlareLayer
319
+ if (compType == "UnityEngine.Behaviour")
320
+ {
321
+ // extract type while aavoiding reflection
322
+ int pos = comp.ToString().LastIndexOf("(UnityEngine.");
323
+ if (pos >= 0)
324
+ {
325
+ string compType2 = comp.ToString().Substring(pos);
326
+ if ((compType2.Length >= "(UnityEngine.x)".Length) &&
327
+ (compType2.EndsWith(")")))
328
+ {
329
+ // fix type
330
+ compType = compType2.Substring(1, compType2.Length - 2);
331
+ }
332
+ }
333
+ }
334
+
335
+ if (compType.StartsWith("UnityEngine."))
336
+ {
337
+ compType = compType.Remove(0, "UnityEngine.".Length);
338
+ }
339
+ return compType;
340
+ }
341
+
342
+ public static void SerializeComponent(Component comp, Hashtable compHash)
343
+ {
344
+ Type compType = comp.GetType();
345
+ Dictionary<Type, SerializerMethod> methods = new Dictionary<Type, SerializerMethod>()
346
+ {
347
+ { typeof(Transform), SerializeTransform },
348
+ { typeof(Camera), SerializeCamera },
349
+ { typeof(GUIElement), SerializeGUIElement },
350
+ { typeof(GUITexture), SerializeGUITexture },
351
+ { typeof(GUIText), SerializeGUIText }
352
+ };
353
+
354
+ // serialize subclasses first
355
+ foreach (KeyValuePair<Type, SerializerMethod> pair in methods)
356
+ {
357
+ if (compType.IsSubclassOf(pair.Key))
358
+ {
359
+ pair.Value(comp, compHash);
360
+ }
361
+ }
362
+ // serialize main classes after
363
+ foreach (KeyValuePair<Type, SerializerMethod> pair in methods)
364
+ {
365
+ if (compType == pair.Key)
366
+ {
367
+ pair.Value(comp, compHash);
368
+ }
369
+ }
370
+ }
371
+
372
+ public static void SerializeTransform(Component comp, Hashtable h)
373
+ {
374
+ Transform t = comp as Transform;
375
+ h["position"] = SerializeVector3(t.position);
376
+ h["rotation"] = SerializeQuaternion(t.rotation);
377
+ h["localScale"] = SerializeVector3(t.localScale);
378
+ }
379
+
380
+ public static void SerializeCamera(Component comp, Hashtable h)
381
+ {
382
+ Camera c = comp as Camera;
383
+ h["fieldOfView"] = c.fieldOfView;
384
+ h["nearClipPlane"] = c.nearClipPlane;
385
+ h["farClipPlane"] = c.farClipPlane;
386
+ h["renderingPath"] = c.renderingPath.ToString();
387
+ h["actualRenderingPath"] = c.actualRenderingPath.ToString();
388
+ h["orthographicSize"] = c.orthographicSize;
389
+ h["orthographic"] = c.orthographic;
390
+ h["depth"] = c.depth;
391
+ h["aspect"] = c.aspect;
392
+ h["cullingMask"] = c.cullingMask;
393
+ h["backgroundColor"] = SerializeColor(c.backgroundColor);
394
+ h["rect"] = SerializeRect(c.rect);
395
+ h["pixelRect"] = SerializeRect(c.pixelRect);
396
+ // FIXME: render texture
397
+ //h["targetTexture"] = SerializeTexture(c.targetTexture);
398
+ h["pixelWidth"] = c.pixelWidth;
399
+ h["pixelHeight"] = c.pixelHeight;
400
+ h["cameraToWorldMatrix"] = SerializeMatrix4x4(c.cameraToWorldMatrix);
401
+ h["worldToCameraMatrix"] = SerializeMatrix4x4(c.worldToCameraMatrix);
402
+ h["projectionMatrix"] = SerializeMatrix4x4(c.projectionMatrix);
403
+ h["velocity"] = SerializeVector3(c.velocity);
404
+ h["clearFlags"] = c.clearFlags.ToString();
405
+ h["layerCullDistances"] = c.layerCullDistances;
406
+ h["depthTextureMode"] = c.depthTextureMode.ToString();
407
+ }
408
+
409
+ public static void SerializeGUIElement(Component comp, Hashtable h)
410
+ {
411
+ GUIElement e = comp as GUIElement;
412
+ AppendHint<Hashtable>(h, "screen", SerializeRect(e.GetScreenRect()));
413
+ }
414
+
415
+ public static void SerializeGUITexture(Component comp, Hashtable h)
416
+ {
417
+ GUITexture t = comp as GUITexture;
418
+ h["color"] = SerializeColor(t.color);
419
+ h["pixelInset"] = SerializeRect(t.pixelInset);
420
+ // FIXME: render texture
421
+ //h["texture"] = SerializeTexture(t.texture);
422
+ }
423
+
424
+ public static void SerializeGUIText(Component comp, Hashtable h)
425
+ {
426
+ GUIText t = comp as GUIText;
427
+ h["text"] = t.text;
428
+ // FIXME: serialize Material
429
+ //h["material"] = ...
430
+ h["pixelOffset"] = SerializeVector2(t.pixelOffset);
431
+ // FIXME: serialize Material
432
+ //h["font"] = ...
433
+ h["alignment"] = t.alignment.ToString();
434
+ h["anchor"] = t.anchor.ToString();
435
+ h["lineSpacing"] = t.lineSpacing;
436
+ h["tabSize"] = t.tabSize;
437
+ h["fontSize"] = t.fontSize;
438
+ h["fontStyle"] = t.fontStyle.ToString();
439
+ AppendHint<string>(h, "text", t.text);
440
+ }
441
+
442
+ public static Hashtable AppendHint<T>(Hashtable h, string name, T hint)
443
+ {
444
+ Hashtable hints = h[".hints"] as Hashtable;
445
+ if (hints == null)
446
+ {
447
+ hints = new Hashtable();
448
+ h[".hints"] = hints;
449
+ }
450
+ List<T> hintsList;
451
+ if (hints.Contains(name))
452
+ {
453
+ hintsList = hints[name] as List<T>;
454
+ }
455
+ else
456
+ {
457
+ hintsList = new List<T>();
458
+ hints[name] = hintsList;
459
+ }
460
+ hintsList.Add(hint);
461
+ return hints;
462
+ }
463
+
464
+ public static Hashtable SerializeColor(Color c)
465
+ {
466
+ Hashtable h = new Hashtable();
467
+ h["r"] = c.r;
468
+ h["g"] = c.g;
469
+ h["b"] = c.b;
470
+ h["a"] = c.a;
471
+ h["grayscale"] = c.grayscale;
472
+ return h;
473
+ }
474
+
475
+ public static Hashtable SerializeRect(Rect r)
476
+ {
477
+ Hashtable h = new Hashtable();
478
+ h["x"] = r.x;
479
+ h["y"] = r.y;
480
+ h["width"] = r.width;
481
+ h["height"] = r.height;
482
+ return h;
483
+ }
484
+
485
+ public static Hashtable SerializeVector3(Vector3 v)
486
+ {
487
+ Hashtable h = new Hashtable();
488
+ h["x"] = v.x;
489
+ h["y"] = v.y;
490
+ h["z"] = v.z;
491
+ return h;
492
+ }
493
+
494
+ public static Hashtable SerializeVector2(Vector2 v)
495
+ {
496
+ Hashtable h = new Hashtable();
497
+ h["x"] = v.x;
498
+ h["y"] = v.y;
499
+ return h;
500
+ }
501
+
502
+ public static Hashtable SerializeQuaternion(Quaternion q)
503
+ {
504
+ Hashtable h = new Hashtable();
505
+ h["x"] = q.x;
506
+ h["y"] = q.y;
507
+ h["z"] = q.z;
508
+ h["w"] = q.w;
509
+ return h;
510
+ }
511
+
512
+ public static float[] SerializeMatrix4x4(Matrix4x4 m)
513
+ {
514
+ float[] matrix = new float[16];
515
+ for (int index = 0; index < matrix.Length; ++index)
516
+ {
517
+ matrix[index] = m[index];
518
+ }
519
+ return matrix;
520
+ }
521
+ }
522
+
523
+ public class CukunityGetScreenCommand : CukunityCommand
524
+ {
525
+ public override void Process(Hashtable req, Hashtable res)
526
+ {
527
+ res["width"] = Screen.width;
528
+ res["height"] = Screen.height;
529
+ }
530
+ }
531
+
532
+ public class CukunityGetLevelCommand : CukunityCommand
533
+ {
534
+ public override void Process(Hashtable req, Hashtable res)
535
+ {
536
+ res["number"] = Application.loadedLevel;
537
+ res["name"] = Application.loadedLevelName;
538
+ res["count"] = Application.levelCount;
539
+ }
540
+ }
541
+
542
+ public class CukunityLoadLevelCommand : CukunityCommand
543
+ {
544
+ public override void Process(Hashtable req, Hashtable res)
545
+ {
546
+ int levelNumber = -1;
547
+ string levelName = GetJsonString(req, "name");
548
+ string methodName = GetJsonString(req, "method");
549
+ bool hasLevelNumber = GetJsonInt(req, "number", ref levelNumber);
550
+
551
+ if ((hasLevelNumber) && (levelName != null))
552
+ {
553
+ Debug.LogError("Cukunity: cannot specify both level name and number");
554
+ res["error"] = "BothLevelNameOrNumberError";
555
+ return;
556
+ }
557
+
558
+ if (((levelNumber < 0) || (levelNumber >= Application.levelCount)) &&
559
+ ((levelName == null) || (levelName.Length == 0)))
560
+ {
561
+ Debug.LogError("Cukunity: missing level name/number");
562
+ res["error"] = "MissingLevelNameOrNumberError";
563
+ return;
564
+ }
565
+
566
+ if (methodName == null)
567
+ {
568
+ methodName = "sync";
569
+ }
570
+
571
+ switch (methodName.ToLower())
572
+ {
573
+ case "sync":
574
+ try
575
+ {
576
+ if (hasLevelNumber)
577
+ {
578
+ Application.LoadLevel(levelNumber);
579
+ }
580
+ else
581
+ {
582
+ Application.LoadLevel(levelName);
583
+ }
584
+ }
585
+ catch (Exception)
586
+ {
587
+ throw new System.Exception("Load level failed");
588
+ }
589
+ break;
590
+
591
+ case "async":
592
+ try
593
+ {
594
+ if (hasLevelNumber)
595
+ {
596
+ Application.LoadLevelAsync(levelNumber);
597
+ }
598
+ else
599
+ {
600
+ Application.LoadLevelAsync(levelName);
601
+ }
602
+ }
603
+ catch (Exception)
604
+ {
605
+ throw new System.Exception("Load level failed");
606
+ }
607
+ break;
608
+
609
+ case "additive":
610
+ try
611
+ {
612
+ if (hasLevelNumber)
613
+ {
614
+ Application.LoadLevelAdditive(levelNumber);
615
+ }
616
+ else
617
+ {
618
+ Application.LoadLevelAdditive(levelName);
619
+ }
620
+ }
621
+ catch (Exception)
622
+ {
623
+ throw new System.Exception("Load level failed");
624
+ }
625
+ break;
626
+
627
+ case "additiveasync":
628
+ try
629
+ {
630
+ if (hasLevelNumber)
631
+ {
632
+ Application.LoadLevelAdditiveAsync(levelNumber);
633
+ }
634
+ else
635
+ {
636
+ Application.LoadLevelAdditiveAsync(levelName);
637
+ }
638
+ }
639
+ catch (Exception)
640
+ {
641
+ throw new System.Exception("Load level failed");
642
+ }
643
+ break;
644
+
645
+ default:
646
+ Debug.LogError("Cukunity: unknown load level method in client's request");
647
+ res["error"] = "UnknownLoadLevelMethodError";
648
+ return;
649
+ }
650
+ }
651
+ }
652
+
653
+ #if UNITY_IPHONE
654
+ public class CukunityIOS
655
+ {
656
+ [DllImport("__Internal")]
657
+ extern static public int CukunityScreenInstantTap(int x, int y, int tapCount);
658
+ }
659
+
660
+ public class CukunityTouchScreenCommand : CukunityCommand
661
+ {
662
+ public override void Process(Hashtable req, Hashtable res)
663
+ {
664
+ int x = 0, y = 0, tapCount = 1;
665
+ string methodName = GetJsonString(req, "method");
666
+
667
+ if ((!GetJsonInt(req, "x", ref x)) ||
668
+ (!GetJsonInt(req, "y", ref y)))
669
+ {
670
+ Debug.LogError("Cukunity: must specify x and y for position to touch");
671
+ res["error"] = "MissingCoordinateError";
672
+ return;
673
+ }
674
+
675
+ GetJsonInt(req, "tapCount", ref tapCount);
676
+ if (tapCount <= 0)
677
+ {
678
+ Debug.LogError("Cukunity: must specify a tap count greater than 0");
679
+ res["error"] = "InvalidTapCountError";
680
+ return;
681
+ }
682
+
683
+ if (methodName == null)
684
+ {
685
+ methodName = "tap";
686
+ }
687
+
688
+ switch (methodName.ToLower())
689
+ {
690
+ case "tap":
691
+ CukunityIOS.CukunityScreenInstantTap(x, y, tapCount);
692
+ break;
693
+
694
+ default:
695
+ Debug.LogError("Cukunity: unknown touch method in client's request");
696
+ res["error"] = "UnknownTouchMethodError";
697
+ return;
698
+ }
699
+ }
700
+ }
701
+ #endif
702
+
703
+ public class CukunityRequest
704
+ {
705
+ private string request;
706
+ private ManualResetEvent signal;
707
+ private string response;
708
+
709
+ public CukunityRequest(string request, ManualResetEvent signal)
710
+ {
711
+ this.request = request;
712
+ this.signal = signal;
713
+ response = "";
714
+ }
715
+
716
+ public string Request
717
+ {
718
+ get
719
+ {
720
+ return request;
721
+ }
722
+ }
723
+
724
+ public string Response
725
+ {
726
+ get
727
+ {
728
+ return response;
729
+ }
730
+ }
731
+
732
+ public void OnProcessed(string response)
733
+ {
734
+ this.response = response;
735
+ // fire signal
736
+ signal.Set();
737
+ }
738
+ }
739
+
740
+ public class CukunityClient
741
+ {
742
+ private TcpClient client;
743
+ private NetworkStream stream;
744
+ private byte[] buffer;
745
+ private int bufferUsedCount;
746
+ private string bufferedString;
747
+ private CukunityServer server;
748
+ public ManualResetEvent signal;
749
+
750
+ private static readonly int BufferIncrease = 1024;
751
+ private static readonly Encoding enc = Encoding.UTF8;
752
+
753
+ public CukunityClient(TcpClient client, CukunityServer server)
754
+ {
755
+ this.client = client;
756
+ this.server = server;
757
+ stream = client.GetStream();
758
+ buffer = new byte[BufferIncrease];
759
+ bufferUsedCount = 0;
760
+ bufferedString = "";
761
+ signal = new ManualResetEvent(false);
762
+ }
763
+
764
+ public void SendAck()
765
+ {
766
+ Hashtable ack = new Hashtable();
767
+ byte[] ackBytes = enc.GetBytes(JsonWriter.Serialize(ack) + "\n");
768
+ stream.BeginWrite(ackBytes, 0, ackBytes.Length, OnSendAckComplete, this);
769
+ }
770
+
771
+ static private void OnSendAckComplete(IAsyncResult result)
772
+ {
773
+ CukunityClient cukieClient = result.AsyncState as CukunityClient;
774
+ cukieClient.stream.EndWrite(result);
775
+ cukieClient.BeginRead();
776
+ }
777
+
778
+ private void BeginRead()
779
+ {
780
+ // resize required?
781
+ if (bufferUsedCount >= buffer.Length)
782
+ {
783
+ byte[] newBuffer = new byte[bufferUsedCount + BufferIncrease];
784
+ Array.Copy(buffer, newBuffer, buffer.Length);
785
+ buffer = newBuffer;
786
+ }
787
+ stream.BeginRead(buffer, bufferUsedCount, buffer.Length - bufferUsedCount, OnReadComplete, this);
788
+ }
789
+
790
+ public void Close()
791
+ {
792
+ Debug.LogWarning("Cukunity: client disconnected");
793
+ try
794
+ {
795
+ stream.Close();
796
+ client.Close();
797
+ }
798
+ catch (Exception)
799
+ {
800
+ }
801
+ }
802
+
803
+ static private void OnReadComplete(IAsyncResult result)
804
+ {
805
+ CukunityClient cukieClient = result.AsyncState as CukunityClient;
806
+ int byteCount = cukieClient.stream.EndRead(result);
807
+ string line;
808
+
809
+ // nothing received?
810
+ if (byteCount <= 0)
811
+ {
812
+ cukieClient.Close();
813
+ return;
814
+ }
815
+
816
+ // append read data to internal buffer
817
+ cukieClient.bufferedString += enc.GetString(cukieClient.buffer, cukieClient.bufferUsedCount, byteCount);
818
+ cukieClient.bufferUsedCount += byteCount;
819
+
820
+ // can we extract a line from this buffer?
821
+ while ((line = cukieClient.ExtractLine(cukieClient.bufferedString)) != null)
822
+ {
823
+ int lineByteCount = enc.GetByteCount(line);
824
+ cukieClient.bufferedString = cukieClient.bufferedString.Remove(0, lineByteCount);
825
+ cukieClient.bufferUsedCount -= lineByteCount;
826
+
827
+ // process received line
828
+ string response = cukieClient.ProcessLineRequest(line);
829
+ if (response.Length > 0)
830
+ {
831
+ // respond to client
832
+ byte[] responseBytes = enc.GetBytes(response + "\n");
833
+ cukieClient.stream.BeginWrite(responseBytes, 0, responseBytes.Length, null, null);
834
+ }
835
+ else
836
+ {
837
+ cukieClient.Close();
838
+ return;
839
+ }
840
+ }
841
+
842
+ // next read
843
+ cukieClient.BeginRead();
844
+ }
845
+
846
+ private string ExtractLine(string data)
847
+ {
848
+ int newLine = data.IndexOf("\n");
849
+
850
+ if (newLine < 0)
851
+ {
852
+ return null;
853
+ }
854
+ return data.Substring(0, newLine + 1);
855
+ }
856
+
857
+ private string ProcessLineRequest(string line)
858
+ {
859
+ string request = line.TrimEnd('\r', '\n');
860
+ CukunityRequest req = new CukunityRequest(request, signal);
861
+
862
+ // reset signal
863
+ signal.Reset();
864
+ // add request to que
865
+ server.EnqueueRequest(req);
866
+ // wait for completion
867
+ signal.WaitOne();
868
+ return req.Response;
869
+ }
870
+ }
871
+ }