cukunity 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }