diff options
Diffstat (limited to '')
-rw-r--r-- | tools/mass test client/TestClient.cs | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/tools/mass test client/TestClient.cs b/tools/mass test client/TestClient.cs new file mode 100644 index 0000000..cee218c --- /dev/null +++ b/tools/mass test client/TestClient.cs | |||
@@ -0,0 +1,324 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Reflection; | ||
4 | using System.Xml; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | using libsecondlife.AssetSystem; | ||
8 | |||
9 | namespace libsecondlife.TestClient | ||
10 | { | ||
11 | public class TestClient : SecondLife | ||
12 | { | ||
13 | public delegate void PrimCreatedCallback(Simulator simulator, Primitive prim); | ||
14 | |||
15 | public event PrimCreatedCallback OnPrimCreated; | ||
16 | |||
17 | public Dictionary<Simulator, Dictionary<uint, Primitive>> SimPrims; | ||
18 | public LLUUID GroupID = LLUUID.Zero; | ||
19 | public Dictionary<LLUUID, GroupMember> GroupMembers; | ||
20 | public Dictionary<uint, Avatar> AvatarList = new Dictionary<uint,Avatar>(); | ||
21 | public Dictionary<LLUUID, AvatarAppearancePacket> Appearances = new Dictionary<LLUUID, AvatarAppearancePacket>(); | ||
22 | public Dictionary<string, Command> Commands = new Dictionary<string,Command>(); | ||
23 | public bool Running = true; | ||
24 | public string MasterName = String.Empty; | ||
25 | public LLUUID MasterKey = LLUUID.Zero; | ||
26 | public ClientManager ClientManager; | ||
27 | public int regionX; | ||
28 | public int regionY; | ||
29 | |||
30 | //internal libsecondlife.InventorySystem.InventoryFolder currentDirectory; | ||
31 | |||
32 | private System.Timers.Timer updateTimer; | ||
33 | |||
34 | |||
35 | /// <summary> | ||
36 | /// | ||
37 | /// </summary> | ||
38 | public TestClient(ClientManager manager) | ||
39 | { | ||
40 | ClientManager = manager; | ||
41 | |||
42 | updateTimer = new System.Timers.Timer(1000); | ||
43 | updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed); | ||
44 | |||
45 | RegisterAllCommands(Assembly.GetExecutingAssembly()); | ||
46 | |||
47 | Settings.DEBUG = true; | ||
48 | Settings.STORE_LAND_PATCHES = true; | ||
49 | Settings.ALWAYS_REQUEST_OBJECTS = true; | ||
50 | |||
51 | Network.RegisterCallback(PacketType.AgentDataUpdate, new NetworkManager.PacketCallback(AgentDataUpdateHandler)); | ||
52 | |||
53 | Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim); | ||
54 | Objects.OnObjectUpdated += new ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated); | ||
55 | Objects.OnObjectKilled += new ObjectManager.KillObjectCallback(Objects_OnObjectKilled); | ||
56 | Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar); | ||
57 | Self.OnInstantMessage += new MainAvatar.InstantMessageCallback(Self_OnInstantMessage); | ||
58 | Groups.OnGroupMembers += new GroupManager.GroupMembersCallback(GroupMembersHandler); | ||
59 | this.OnLogMessage += new LogCallback(TestClient_OnLogMessage); | ||
60 | |||
61 | Network.RegisterCallback(PacketType.AvatarAppearance, new NetworkManager.PacketCallback(AvatarAppearanceHandler)); | ||
62 | |||
63 | updateTimer.Start(); | ||
64 | } | ||
65 | |||
66 | public void RegisterAllCommands(Assembly assembly) | ||
67 | { | ||
68 | foreach (Type t in assembly.GetTypes()) | ||
69 | { | ||
70 | try | ||
71 | { | ||
72 | if (t.IsSubclassOf(typeof(Command))) | ||
73 | { | ||
74 | ConstructorInfo info = t.GetConstructor(new Type[] { typeof(TestClient) }); | ||
75 | Command command = (Command)info.Invoke(new object[] { this }); | ||
76 | RegisterCommand(command); | ||
77 | } | ||
78 | } | ||
79 | catch (Exception e) | ||
80 | { | ||
81 | Console.WriteLine(e.ToString()); | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public void RegisterCommand(Command command) | ||
87 | { | ||
88 | command.Client = this; | ||
89 | if (!Commands.ContainsKey(command.Name.ToLower())) | ||
90 | { | ||
91 | Commands.Add(command.Name.ToLower(), command); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | //breaks up large responses to deal with the max IM size | ||
96 | private void SendResponseIM(SecondLife client, LLUUID fromAgentID, string data, LLUUID imSessionID) | ||
97 | { | ||
98 | for ( int i = 0 ; i < data.Length ; i += 1024 ) { | ||
99 | int y; | ||
100 | if ((i + 1023) > data.Length) | ||
101 | { | ||
102 | y = data.Length - i; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | y = 1023; | ||
107 | } | ||
108 | string message = data.Substring(i, y); | ||
109 | client.Self.InstantMessage(fromAgentID, message, imSessionID); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | public void DoCommand(string cmd, LLUUID fromAgentID, LLUUID imSessionID) | ||
114 | { | ||
115 | string[] tokens = Parsing.ParseArguments(cmd); | ||
116 | |||
117 | if (tokens.Length == 0) | ||
118 | return; | ||
119 | |||
120 | string firstToken = tokens[0].ToLower(); | ||
121 | |||
122 | // "all balance" will send the balance command to all currently logged in bots | ||
123 | if (firstToken == "all" && tokens.Length > 1) | ||
124 | { | ||
125 | cmd = String.Empty; | ||
126 | |||
127 | // Reserialize all of the arguments except for "all" | ||
128 | for (int i = 1; i < tokens.Length; i++) | ||
129 | { | ||
130 | cmd += tokens[i] + " "; | ||
131 | } | ||
132 | |||
133 | ClientManager.DoCommandAll(cmd, fromAgentID, imSessionID); | ||
134 | |||
135 | return; | ||
136 | } | ||
137 | |||
138 | if (Commands.ContainsKey(firstToken)) | ||
139 | { | ||
140 | string[] args = new string[tokens.Length - 1]; | ||
141 | Array.Copy(tokens, 1, args, 0, args.Length); | ||
142 | string response = Commands[firstToken].Execute(args, fromAgentID); | ||
143 | |||
144 | if (response.Length > 0) | ||
145 | { | ||
146 | Console.WriteLine(response); | ||
147 | |||
148 | if (fromAgentID != null && Network.Connected) | ||
149 | { | ||
150 | // IMs don't like \r\n line endings, clean them up first | ||
151 | response = response.Replace("\r", ""); | ||
152 | SendResponseIM(this, fromAgentID, response, imSessionID); | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) | ||
159 | { | ||
160 | foreach (Command c in Commands.Values) | ||
161 | if (c.Active) | ||
162 | c.Think(); | ||
163 | } | ||
164 | |||
165 | private void AgentDataUpdateHandler(Packet packet, Simulator sim) | ||
166 | { | ||
167 | AgentDataUpdatePacket p = (AgentDataUpdatePacket)packet; | ||
168 | if (p.AgentData.AgentID == sim.Client.Network.AgentID) | ||
169 | { | ||
170 | Console.WriteLine("Got the group ID for " + sim.Client.ToString() + ", requesting group members..."); | ||
171 | GroupID = p.AgentData.ActiveGroupID; | ||
172 | |||
173 | sim.Client.Groups.BeginGetGroupMembers(GroupID); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | private void TestClient_OnLogMessage(string message, Helpers.LogLevel level) | ||
178 | { | ||
179 | Console.WriteLine("<" + this.ToString() + "> " + level.ToString() + ": " + message); | ||
180 | } | ||
181 | |||
182 | private void GroupMembersHandler(Dictionary<LLUUID, GroupMember> members) | ||
183 | { | ||
184 | Console.WriteLine("Got " + members.Count + " group members."); | ||
185 | GroupMembers = members; | ||
186 | } | ||
187 | |||
188 | private void Objects_OnObjectKilled(Simulator simulator, uint objectID) | ||
189 | { | ||
190 | lock (SimPrims) | ||
191 | { | ||
192 | if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(objectID)) | ||
193 | SimPrims[simulator].Remove(objectID); | ||
194 | } | ||
195 | |||
196 | lock (AvatarList) | ||
197 | { | ||
198 | if (AvatarList.ContainsKey(objectID)) | ||
199 | AvatarList.Remove(objectID); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | private void Objects_OnObjectUpdated(Simulator simulator, ObjectUpdate update, ulong regionHandle, ushort timeDilation) | ||
204 | { | ||
205 | regionX = (int)(regionHandle >> 32); | ||
206 | regionY = (int)(regionHandle & 0xFFFFFFFF); | ||
207 | |||
208 | if (update.Avatar) | ||
209 | { | ||
210 | lock (AvatarList) | ||
211 | { | ||
212 | // TODO: We really need a solid avatar and object tracker in Utilities to use here | ||
213 | if (AvatarList.ContainsKey(update.LocalID)) | ||
214 | { | ||
215 | AvatarList[update.LocalID].CollisionPlane = update.CollisionPlane; | ||
216 | AvatarList[update.LocalID].Position = update.Position; | ||
217 | AvatarList[update.LocalID].Velocity = update.Velocity; | ||
218 | AvatarList[update.LocalID].Acceleration = update.Acceleration; | ||
219 | AvatarList[update.LocalID].Rotation = update.Rotation; | ||
220 | AvatarList[update.LocalID].AngularVelocity = update.AngularVelocity; | ||
221 | AvatarList[update.LocalID].Textures = update.Textures; | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | lock (SimPrims) | ||
228 | { | ||
229 | if (SimPrims.ContainsKey(simulator) && SimPrims[simulator].ContainsKey(update.LocalID)) | ||
230 | { | ||
231 | SimPrims[simulator][update.LocalID].Position = update.Position; | ||
232 | SimPrims[simulator][update.LocalID].Velocity = update.Velocity; | ||
233 | SimPrims[simulator][update.LocalID].Acceleration = update.Acceleration; | ||
234 | SimPrims[simulator][update.LocalID].Rotation = update.Rotation; | ||
235 | SimPrims[simulator][update.LocalID].AngularVelocity = update.AngularVelocity; | ||
236 | SimPrims[simulator][update.LocalID].Textures = update.Textures; | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | private void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation) | ||
243 | { | ||
244 | lock (SimPrims) | ||
245 | { | ||
246 | if (!SimPrims.ContainsKey(simulator)) | ||
247 | { | ||
248 | SimPrims[simulator] = new Dictionary<uint, Primitive>(10000); | ||
249 | } | ||
250 | |||
251 | SimPrims[simulator][prim.LocalID] = prim; | ||
252 | } | ||
253 | |||
254 | if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) != 0 && OnPrimCreated != null) | ||
255 | { | ||
256 | OnPrimCreated(simulator, prim); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | private void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation) | ||
261 | { | ||
262 | lock (AvatarList) | ||
263 | { | ||
264 | AvatarList[avatar.LocalID] = avatar; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | private void AvatarAppearanceHandler(Packet packet, Simulator simulator) | ||
269 | { | ||
270 | AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet; | ||
271 | |||
272 | lock (Appearances) Appearances[appearance.Sender.ID] = appearance; | ||
273 | } | ||
274 | |||
275 | private void Self_OnInstantMessage(LLUUID fromAgentID, string fromAgentName, LLUUID toAgentID, | ||
276 | uint parentEstateID, LLUUID regionID, LLVector3 position, MainAvatar.InstantMessageDialog dialog, | ||
277 | bool groupIM, LLUUID imSessionID, DateTime timestamp, string message, | ||
278 | MainAvatar.InstantMessageOnline offline, byte[] binaryBucket) | ||
279 | { | ||
280 | if (MasterKey != LLUUID.Zero) | ||
281 | { | ||
282 | if (fromAgentID != MasterKey) | ||
283 | { | ||
284 | // Received an IM from someone that is not the bot's master, ignore | ||
285 | Console.WriteLine("<IM>" + fromAgentName + " (not master): " + message + "@" + regionID.ToString() + ":" + position.ToString() ); | ||
286 | return; | ||
287 | } | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | if (GroupMembers != null && !GroupMembers.ContainsKey(fromAgentID)) | ||
292 | { | ||
293 | // Received an IM from someone outside the bot's group, ignore | ||
294 | Console.WriteLine("<IM>" + fromAgentName + " (not in group): " + message + "@" + regionID.ToString() + ":" + position.ToString()); | ||
295 | return; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | Console.WriteLine("<IM>" + fromAgentName + ": " + message); | ||
300 | |||
301 | if (dialog == MainAvatar.InstantMessageDialog.RequestTeleport) | ||
302 | { | ||
303 | Console.WriteLine("Accepting teleport lure."); | ||
304 | Self.TeleportLureRespond(fromAgentID, true); | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | if (dialog == MainAvatar.InstantMessageDialog.InventoryOffered) | ||
309 | { | ||
310 | Console.WriteLine("Accepting inventory offer."); | ||
311 | |||
312 | Self.InstantMessage(Self.FirstName + " " + Self.LastName, fromAgentID, String.Empty, | ||
313 | imSessionID, MainAvatar.InstantMessageDialog.InventoryAccepted, | ||
314 | MainAvatar.InstantMessageOnline.Offline, Self.Position, LLUUID.Zero, | ||
315 | Self.InventoryRootFolderUUID.GetBytes()); | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | DoCommand(message, fromAgentID, imSessionID); | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | } | ||