OSDN Git Service

Updated license year
[radegast/radegast.git] / Radegast / Core / Commands / GoCommand.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2012, Radegast Development Team
4 // All rights reserved.
5 // 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 
9 //     * Redistributions of source code must retain the above copyright notice,
10 //       this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //     * Neither the name of the application "Radegast", nor the names of its
15 //       contributors may be used to endorse or promote products derived from
16 //       this software without specific prior written permission.
17 // 
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // $Id$
30 //
31 using System;
32 using System.Collections.Generic;
33 using System.Text;
34 using System.Text.RegularExpressions;
35 using System.Windows.Forms;
36
37 using OpenMetaverse;
38
39 namespace Radegast.Commands
40 {
41     public class GoCommand : RadegastCommand
42     {
43         Regex subCommand;
44         RegexOptions regexOptions = RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase;
45         TabsConsole TC { get { return Instance.TabConsole; } }
46         ObjectsConsole Objects;
47         ChatConsole Chat;
48         bool displayEndWalk = false;
49         Vector3 targetPos = Vector3.Zero;
50         ConsoleWriteLine wl;
51
52         public GoCommand(RadegastInstance instance)
53             : base(instance)
54         {
55             Name = "go";
56             Description = "Moves avatar";
57             Usage = "go [tp] (distance|xyz|object|person|help) [additional args] (type \"" + CommandsManager.CmdPrefix + "go help\" for full usage)";
58
59             subCommand = new Regex(@"(?<subcmd>.*)\s*=\s*(?<subarg>.*)", regexOptions);
60             Chat = (ChatConsole)TC.Tabs["chat"].Control;
61             Instance.State.OnWalkStateCanged += new StateManager.WalkStateCanged(State_OnWalkStateCanged);
62         }
63
64         public override void Dispose()
65         {
66             Instance.State.OnWalkStateCanged -= new StateManager.WalkStateCanged(State_OnWalkStateCanged);
67             Objects = null;
68             Chat = null;
69             base.Dispose();
70         }
71
72         void State_OnWalkStateCanged(bool walking)
73         {
74             if (!walking && displayEndWalk)
75             {
76                 displayEndWalk = false;
77                 Vector3 p = Client.Self.SimPosition;
78                 string msg = "Finished walking";
79
80                 if (targetPos != Vector3.Zero)
81                 {
82                     System.Threading.Thread.Sleep(1000);
83                     msg += string.Format(" {0:0} meters from destination", Vector3.Distance(Client.Self.SimPosition, targetPos));
84                     targetPos = Vector3.Zero;
85                 }
86
87                 wl(msg);
88             }
89         }
90
91         void PrintUsage()
92         {
93             wl("Wrong arguments for \"go\" command. For detailed description type: " + CommandsManager.CmdPrefix + "go help");
94         }
95
96         void PrintFullUsage()
97         {
98             wl(@"Usage:
99
100 {0}go [tp] (distance|xyz|object|person|help) [additional args]
101 - tp is an optional parameter after go command. If speciefied use teleport instead of walking to reach the destination when parcel permits it.
102
103 Distance mode:
104 Specifies distance in meters to move with optional direction. If direction is not specified we move forward.
105 Examples:
106 {0}go 10 -- moves 10m forward
107 {0}go 15 e -- moves 15m to the east
108 {0}go tp 20 se -- teleports 20m to the southeast of our current position
109
110 XYZ mode:
111 Moves to X, Y and optionally Z coordinate
112 Examples:
113 {0}go xyz 128,128  -- walks toward the center of the sim, using our current elevation (Z)
114 {0}go tp xyz 32,32,128 -- teleports to postion 32,32,128 within our current region
115
116 Object mode:
117 Moves towards a named object
118 Examples:
119 {0}go object desk chair -- walk toward the closest object whose name begins with ""desk chair""
120 {0}go tp object dance floor -- teleports to the closest object whose name beings with ""dance floor""
121
122 Person mode:
123 Moves toward a person
124 Examples:
125 {0}go person Latif -- walk toward the closest person whose name begins with Latif
126 {0}go tp person John -- teleports to the closest person whose name begins with John", CommandsManager.CmdPrefix);
127         }
128
129         void MoveTo(Vector3 target, bool useTP)
130         {
131             Instance.State.SetSitting(false, UUID.Zero);
132
133             if (useTP)
134             {
135                 Client.Self.RequestTeleport(Client.Network.CurrentSim.Handle, targetPos);
136             }
137             else
138             {
139                 displayEndWalk = true;
140                 Client.Self.Movement.TurnToward(targetPos);
141                 Instance.State.WalkTo(Instance.State.GlobalPosition(Client.Network.CurrentSim, target));
142             }
143         }
144
145         public override void Execute(string name, string[] cmdArgs, ConsoleWriteLine WriteLine)
146         {
147             if (Chat.InvokeRequired)
148             {
149                 if (!Instance.MonoRuntime || Chat.IsHandleCreated)
150                     Chat.Invoke(new MethodInvoker(() => Execute(name, cmdArgs, WriteLine)));
151                 return;
152             }
153             wl = WriteLine;
154
155             string cmd = string.Join(" ", cmdArgs);
156             List<string> args = new List<string>(Regex.Split(cmd, @"\s", regexOptions));
157
158             if (args.Count == 0) { PrintUsage(); return; }
159
160             bool useTP = false;
161             if (args[0] == "tp")
162             {
163                 useTP = true;
164                 args.RemoveAt(0);
165             }
166
167             if (args.Count == 0) { PrintUsage(); return; }
168
169             string subcmd = args[0];
170             args.RemoveAt(0);
171             string subarg = string.Empty;
172
173             // Move certain distance
174             int distance = 0;
175             if (int.TryParse(subcmd, out distance))
176             {
177                 if (distance < 1) return;
178                 Quaternion heading = Client.Self.Movement.BodyRotation;
179                 KnownHeading kh = null;
180
181                 if (args.Count > 0)
182                 {
183                     kh = StateManager.KnownHeadings.Find((KnownHeading h) => { return h.ID == args[0].ToUpper(); });
184                     if (kh != null)
185                         heading = kh.Heading;
186                 }
187
188                 targetPos = Client.Self.SimPosition + new Vector3((float)distance, 0f, 0f) * heading;
189                 Client.Self.Movement.BodyRotation = Client.Self.Movement.HeadRotation = heading;
190                 Client.Self.Movement.Camera.LookAt(Client.Self.SimPosition, targetPos);
191                 Client.Self.Movement.SendUpdate(true);
192                 WriteLine("Going {0} to {1:0},{2:0},{3:0}", kh == null ? string.Empty : kh.Name, targetPos.X, targetPos.Y, targetPos.Z);
193                 MoveTo(targetPos, useTP);
194                 return;
195             }
196
197             if (subcmd == "help")
198             {
199                 PrintFullUsage();
200                 return;
201             }
202
203             if (args.Count == 0) { PrintUsage(); return; }
204             subarg = string.Join(" ", args.ToArray());
205
206             // Move towards
207             switch (subcmd)
208             {
209                 case "xyz":
210                     string[] coords = Regex.Split(subarg, @"\D+");
211                     if (coords.Length < 2) { PrintUsage(); return; }
212                     int x = int.Parse(coords[0]);
213                     int y = int.Parse(coords[1]);
214                     int z = coords.Length > 2 ? int.Parse(coords[2]) : (int)Client.Self.SimPosition.Z;
215                     targetPos = new Vector3(x, y, z);
216                     WriteLine("Going to {0:0},{1:0},{2:0}", targetPos.X, targetPos.Y, targetPos.Z);
217                     MoveTo(targetPos, useTP);
218                     return;
219                 
220                 case "person":
221                     List<UUID> people = Chat.GetAvatarList();
222                     UUID person = people.Find((UUID id) => { return Instance.Names.Get(id).ToLower().StartsWith(subarg.ToLower()); });
223                     if (person == UUID.Zero)
224                     {
225                         WriteLine("Could not find {0}", subarg);
226                         return;
227                     }
228                     string pname = Instance.Names.Get(person);
229
230                     targetPos = Vector3.Zero;
231
232                     // try to find where they are
233                     Avatar avi = Client.Network.CurrentSim.ObjectsAvatars.Find((Avatar av) => { return av.ID == person; });
234                     
235                     if (avi != null)
236                     {
237                         if (avi.ParentID == 0)
238                         {
239                             targetPos = avi.Position;
240                         }
241                         else
242                         {
243                             Primitive seat;
244                             if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
245                             {
246                                 targetPos = seat.Position + avi.Position;
247                             }
248                         }
249                     }
250                     else
251                     {
252                         if (Client.Network.CurrentSim.AvatarPositions.ContainsKey(person))
253                             targetPos = Client.Network.CurrentSim.AvatarPositions[person];
254                     }
255
256                     if (targetPos.Z < 0.01f)
257                     {
258                         WriteLine("Could not locate {0}", pname);
259                         return;
260                     }
261
262                     WriteLine("Going to {3} at {0:0},{1:0},{2:0}", targetPos.X, targetPos.Y, targetPos.Z, pname);
263                     MoveTo(targetPos, useTP);
264
265                     return;
266
267                 case "object":
268
269                     if (!TC.TabExists("objects"))
270                     {
271                         RadegastTab tab = TC.AddTab("objects", "Objects", new ObjectsConsole(Instance));
272                         tab.AllowClose = true;
273                         tab.AllowDetach = true;
274                         tab.Visible = true;
275                         tab.AllowHide = false;
276                         ((ObjectsConsole)tab.Control).RefreshObjectList();
277                         WriteLine("Objects list was not active. Started getting object names, please try again in a minute.");
278                         TC.Tabs["chat"].Select();
279                         return;
280                     }
281
282                     Objects = (ObjectsConsole)TC.Tabs["objects"].Control;
283                     List<Primitive> prims = Objects.GetObjectList();
284
285                     Primitive target = prims.Find((Primitive prim) =>
286                         {
287                             return prim.Properties != null
288                                 && prim.Properties.Name.ToLower().Contains(subarg.ToLower());
289                         });
290
291                     if (target == null)
292                     {
293                         WriteLine("Could not find '{0}' nearby", subarg);
294                         return;
295                     }
296
297                     targetPos = target.Position;
298
299                     WriteLine("Going to object '{0}' at {1:0},{2:0},{3:0}", target.Properties.Name, targetPos.X, targetPos.Y, targetPos.Z);
300                     MoveTo(targetPos, useTP);
301                     return;
302
303                 default:
304                     WriteLine("Unrecognized go command {0}", subcmd);
305                     return;
306             }
307
308         }
309     }
310 }