3 // Radegast SimpleBuilder plugin extension
5 // Copyright (c) 2014, Ano Nymous <anonymously@hotmail.de> | SecondLife-IM: anno1986 Resident
6 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
11 // * Redistributions of source code must retain the above copyright notice,
12 // this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 // * Neither the name of the application "Radegast", nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 using System.Collections.Generic;
38 using System.ComponentModel;
43 using System.Windows.Forms;
48 namespace SimpleBuilderNamespace
51 /// Example implementation of a control that can be used
52 /// as Radegast tab and loeaded as a plugin
54 [Radegast.Plugin(Name = "SimpleBuilder Plugin", Description = "Allows you to build some basic prims, like boxes, cylinder, tubes, ... (requires permission!)", Version = "1.0")]
55 public partial class SimpleBuilder : RadegastTabControl, IRadegastPlugin
57 private string pluginName = "SimpleBuilder";
58 // Methods needed for proper registration of a GUI tab
59 #region Template for GUI radegast tab
60 /// <summary>String for internal identification of the tab (change this!)</summary>
61 static string tabID = "simplebuilder_tab";
62 /// <summary>Text displayed in the plugins menu and the tab label (change this!)</summary>
63 static string tabLabel = "Build Prims";
65 /// <summary>Menu item that gets added to the Plugins menu</summary>
66 ToolStripMenuItem ActivateTabButton;
68 public List<Primitive> Prims = new List<Primitive>();
69 PropertiesQueue propRequester;
71 private Primitive m_selectedPrim;
72 public Primitive selectedPrim {
75 return m_selectedPrim;
80 btnSave.Enabled = false;
82 btnSave.Enabled = true;
84 m_selectedPrim = value;
88 /// <summary>Default constructor. Never used. Needed for VS designer</summary>
89 public SimpleBuilder()
94 /// Main constructor used when actually creating the tab control for display
95 /// Register client and instance events
97 /// <param name="instance">RadegastInstance</param>
98 /// <param name="unused">This param is not used, but needs to be there to keep the constructor signature</param>
99 public SimpleBuilder(RadegastInstance instance, bool unused)
102 InitializeComponent();
103 Disposed += new EventHandler(DemoTab_Disposed);
104 instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
105 RegisterClientEvents(client);
107 propRequester = new PropertiesQueue(instance);
108 propRequester.OnTick += new PropertiesQueue.TickCallback(propRequester_OnTick);
114 /// Cleanup after the tab is closed
115 /// Unregister event handler hooks we have installed
117 /// <param name="sender"></param>
118 /// <param name="e"></param>
119 void DemoTab_Disposed(object sender, EventArgs e)
121 UnregisterClientEvents(client);
122 instance.ClientChanged -= new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
126 /// Plugin loader calls this at the time plugin gets created
127 /// We add a button to the Plugins menu on the main window
130 /// <param name="inst">Main RadegastInstance</param>
131 public void StartPlugin(RadegastInstance inst)
133 this.instance = inst;
135 ActivateTabButton = new ToolStripMenuItem(tabLabel, null, MenuButtonClicked);
136 instance.MainForm.PluginsMenu.DropDownItems.Add(ActivateTabButton);
141 /// Called when the plugin manager unloads our plugin.
142 /// Close the tab if it's active and remove the menu button
144 /// <param name="inst"></param>
145 public void StopPlugin(RadegastInstance inst)
147 ActivateTabButton.Dispose();
148 if (instance.TabConsole.Tabs.ContainsKey(tabID))
150 instance.TabConsole.Tabs[tabID].Close();
153 propRequester.OnTick -= propRequester_OnTick;
156 void propRequester_OnTick(int remaining)
160 BeginInvoke(new MethodInvoker(delegate()
162 propRequester_OnTick(remaining);
168 StringBuilder sb = new StringBuilder();
169 sb.AppendFormat("Tracking {0} objects", Prims.Count);
173 sb.AppendFormat(", fetching {0} object names.", remaining);
183 lstPrims.VirtualListSize = Prims.Count;
186 lstPrims.Invalidate();
189 private bool IncludePrim(Primitive prim)
191 if (prim.ParentID == 0 && (prim.Flags & PrimFlags.ObjectYouOwner) == PrimFlags.ObjectYouOwner)
198 private string GetObjectName(Primitive prim, int distance)
200 string name = "Loading...";
201 string ownerName = "Loading...";
203 if (prim.Properties != null)
205 name = prim.Properties.Name;
206 // prim.Properties.GroupID is the actual group when group owned, not prim.GroupID
207 if (UUID.Zero == prim.Properties.OwnerID &&
208 PrimFlags.ObjectGroupOwned == (prim.Flags & PrimFlags.ObjectGroupOwned) &&
209 UUID.Zero != prim.Properties.GroupID)
211 System.Threading.AutoResetEvent nameReceivedSignal = new System.Threading.AutoResetEvent(false);
212 EventHandler<GroupNamesEventArgs> cbGroupName = new EventHandler<GroupNamesEventArgs>(
213 delegate(object sender, GroupNamesEventArgs e)
215 if (e.GroupNames.ContainsKey(prim.Properties.GroupID))
217 e.GroupNames.TryGetValue(prim.Properties.GroupID, out ownerName);
218 if (string.IsNullOrEmpty(ownerName))
219 ownerName = "Loading...";
220 if (null != nameReceivedSignal)
221 nameReceivedSignal.Set();
224 client.Groups.GroupNamesReply += cbGroupName;
225 client.Groups.RequestGroupName(prim.Properties.GroupID);
226 nameReceivedSignal.WaitOne(5000, false);
227 nameReceivedSignal.Close();
228 client.Groups.GroupNamesReply -= cbGroupName;
231 ownerName = instance.Names.Get(prim.Properties.OwnerID);
234 if (prim.ParentID == client.Self.LocalID)
236 return string.Format("{0} attached to {1}", name, prim.PrimData.AttachmentPoint.ToString());
238 else if (ownerName != "Loading...")
240 return String.Format("{0} ({1}m) owned by {2}", name, distance, ownerName);
244 return String.Format("{0} ({1}m)", name, distance);
249 private string GetObjectName(Primitive prim)
251 int distance = (int)Vector3.Distance(client.Self.SimPosition, prim.Position);
252 if (prim.ParentID == client.Self.LocalID) distance = 0;
253 return GetObjectName(prim, distance);
256 private void lstPrims_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
258 Primitive prim = null;
263 prim = Prims[e.ItemIndex];
268 e.Item = new ListViewItem();
272 string name = GetObjectName(prim);
273 var item = new ListViewItem(name);
275 item.Name = prim.ID.ToString();
280 /// Hadle case when GridClient is changed (relog haa occured without
281 /// quiting Radegast). We need to unregister events from the old client
282 /// and re-register them with the new
284 /// <param name="sender"></param>
285 /// <param name="e"></param>
286 void instance_ClientChanged(object sender, ClientChangedEventArgs e)
288 UnregisterClientEvents(e.OldClient);
289 RegisterClientEvents(e.Client);
293 /// Registration of all GridClient (libomv) events go here
295 /// <param name="client"></param>
296 void RegisterClientEvents(GridClient client)
298 client.Self.ChatFromSimulator += new EventHandler<ChatEventArgs>(Self_ChatFromSimulator);
302 /// Unregistration of GridClient (libomv) events.
303 /// Important that this be symetric to RegisterClientEvents() calls
305 /// <param name="client"></param>
306 void UnregisterClientEvents(GridClient client)
308 if (client == null) return;
309 client.Self.ChatFromSimulator -= new EventHandler<ChatEventArgs>(Self_ChatFromSimulator);
313 /// Handling the click on Plugins -> Demo Tab button
314 /// Check if we already have a tab. If we do make it active tab.
315 /// If not, create a new tab and make it active.
317 /// <param name="sender"></param>
318 /// <param name="e"></param>
319 void MenuButtonClicked(object sender, EventArgs e)
321 if (instance.TabConsole.TabExists(tabID))
323 instance.TabConsole.Tabs[tabID].Select();
327 instance.TabConsole.AddTab(tabID, tabLabel, new SimpleBuilder(instance, true));
328 instance.TabConsole.Tabs[tabID].Select();
331 #endregion Template for GUI radegast tab
333 #region Implementation of the custom tab functionality
334 void Self_ChatFromSimulator(object sender, ChatEventArgs e)
336 // Boilerplate, make sure to be on the GUI thread
339 BeginInvoke(new MethodInvoker(() => Self_ChatFromSimulator(sender, e)));
343 //txtChat.Text = e.Message;
346 private void btnBuild_Click(object sender, EventArgs e)
348 Button btn = sender as Button;
350 if (btn == null) return;
352 PrimType primType = (PrimType)Enum.Parse(typeof(PrimType), btn.Text);
354 this.BuildAndRez(primType);
357 private void BuildAndRez(PrimType primType)
359 float size, distance;
360 if (!float.TryParse(tbox_Size.Text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out size))
362 instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Invalid size", ChatBufferTextStyle.Error);
366 if (!float.TryParse(tbox_Distance.Text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out distance))
368 instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Invalid distance", ChatBufferTextStyle.Error);
372 Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(primType);
374 Vector3 rezpos = new Vector3(distance, 0, 0);
375 rezpos = client.Self.SimPosition + rezpos * client.Self.Movement.BodyRotation;
377 client.Objects.AddPrim(client.Network.CurrentSim, primData, UUID.Zero, rezpos, new Vector3(size), Quaternion.Identity);
379 instance.MainForm.TabConsole.DisplayNotificationInChat(pluginName + ": Object built and rezzed", ChatBufferTextStyle.Normal);
382 #endregion Implementation of the custom tab functionality
384 private void lstPrims_SelectedIndexChanged(object sender, EventArgs e)
386 if (lstPrims.SelectedIndices.Count > 0)
388 selectedPrim = Prims[lstPrims.SelectedIndices[0]];
389 getScaleFromSelection();
390 getRotFromSelection();
398 private void getScaleFromSelection(){
399 if (selectedPrim == null) return;
400 if (selectedPrim.Scale == null) return;
402 scaleX.Value = (Decimal)selectedPrim.Scale.X;
403 scaleY.Value = (Decimal)selectedPrim.Scale.Y;
404 scaleZ.Value = (Decimal)selectedPrim.Scale.Z;
407 private void getRotFromSelection()
409 if (selectedPrim == null) return;
410 if (selectedPrim.Rotation == null) return;
412 rotX.Value = (Decimal)selectedPrim.Rotation.X;
413 rotY.Value = (Decimal)selectedPrim.Rotation.Y;
414 rotZ.Value = (Decimal)selectedPrim.Rotation.Z;
417 private void setRotToSelection()
419 if (selectedPrim != null && selectedPrim.Rotation != null)
421 selectedPrim.Rotation.X = (float)rotX.Value;
422 selectedPrim.Rotation.Y = (float)rotY.Value;
423 selectedPrim.Rotation.Z = (float)rotZ.Value;
427 private void setScaleToSelection()
429 if (selectedPrim != null && selectedPrim.Scale != null)
431 selectedPrim.Scale.X = (float)scaleX.Value;
432 selectedPrim.Scale.Y = (float)scaleY.Value;
433 selectedPrim.Scale.Z = (float)scaleZ.Value;
437 private void button7_Click(object sender, EventArgs e)
440 Vector3 location = client.Self.SimPosition;
444 client.Network.CurrentSim.ObjectsPrimitives.ForEach(prim =>
446 int distance = (int)Vector3.Distance(prim.Position, location);
447 if (prim.ParentID == client.Self.LocalID)
451 if (IncludePrim(prim) && (prim.Position != Vector3.Zero) && (distance < (int)this.numRadius.Value))
454 if (prim.Properties == null)
456 propRequester.RequestProps(prim);
461 lstPrims.VirtualListSize = Prims.Count;
462 lstPrims.Invalidate();
465 private void btn_Save_Click(object sender, EventArgs e)
467 setScaleToSelection();