public void AddNode(int oid, ObjectNode objNode) { NameNode nameNode = new NameNode(); // nameNode.nameBar = (StaticText)WindowManager.Instance.CreateWindow( // "WindowsLook.WLStaticText", "Window/LabelText-" + oid); // nameNode.nameBar.Font = font; // nameNode.nameBar.Text = "Name: " + objNode.Name; // nameNode.nameBar.HorizontalFormat = HorizontalTextFormat.Center; // nameNode.nameBar.VerticalFormat = VerticalTextFormat.Top; // nameNode.nameBar.SetTextColor(new Color(1, 0, 0, 0)); // nameNode.nameBar.MetricsMode = MetricsMode.Absolute; // float chromeHeight = // nameNode.nameBar.UnclippedPixelRect.Height - nameNode.nameBar.UnclippedInnerRect.Height; // Logger.Log(0, "chromeHeight: {0} Line Spacing: {1}", chromeHeight, font.LineSpacing); // nameNode.nameBar.Size = new Size(60, chromeHeight + font.LineSpacing + 5); // FIXME (why do i need +5) nameDictionary[oid] = nameNode; // window.AddChild(nameNode.nameBar); // nameNode.nameBar.MetricsMode = MetricsMode.Relative; // Console.WriteLine("Adding node for: " + objNode.Name); NameWidget widget = new NameWidget(objNode.SceneNode, objNode.Name); widget.Initialize(); // Object will be clipped to this size widget.MetricsMode = MetricsMode.Relative; widget.Size = new Size(1.0f, 1.0f); widget.Position = new Point(0.0f, 0.0f); widget.Text = objNode.Name; widget.HorizontalFormat = HorizontalTextFormat.Center; widget.VerticalFormat = VerticalTextFormat.Centered; widget.Visible = true; window.AddChild(widget); }
/// <summary> /// Inform the name manager about an object node for which the name /// should be displayed. /// </summary> /// <param name="oid">the object id of the node (used as the key for lookups)</param> /// <param name="objNode">the object node whose name should be displayed</param> public void AddNode(long oid, ObjectNode objNode) { NameNode widgetNode = new NameNode(oid); Node attachNode = null; WidgetSceneObject attachObj = new WidgetSceneObject(); attachObj.WidgetNode = widgetNode; AttachmentPoint ap = objNode.GetAttachmentPoint("name-disabled"); if (ap == null) { // Default to a bit larger than the height of the bounding box float objectHeight = objNode.Entity.BoundingBox.Size.y * 1.02f; ap = new AttachmentPoint("name-disabled", null, Quaternion.Identity, Vector3.UnitY * objectHeight); } attachNode = objNode.AttachLocalObject(ap, attachObj); if (attachNode == null) { widgetNode.NodeVisible = true; widgetNode.Node = objNode.SceneNode; } else { // The node visible will be set by the attachObj widgetNode.Node = attachNode; } // FIXME //widgetNode.Widget.Text = objNode.Name; //widgetNode.Widget.Font = font; window.AddChild(widgetNode.Widget); widgetNode.Widget.Initialize(); widgetNode.SetFont(font); widgetNode.SetText(objNode.Name); lock (nameDictionary) { nameDictionary[oid] = widgetNode; } }
public void AddNode(int oid, ObjectNode objNode) { // Create a namebar scene node and entity to handle names Axiom.MathLib.Vector3 offset = new Axiom.MathLib.Vector3(0, 2 * Client.OneMeter, 0); SceneNode sceneNode = objNode.SceneNode.CreateChildSceneNode("namebar." + oid, offset); TexturedBillboardSet widget = new TexturedBillboardSet("billboard." + oid); widget.MaterialName = "font-material"; widget.BillboardType = BillboardType.Point; widget.CommonDirection = Axiom.MathLib.Vector3.NegativeUnitZ; sceneNode.AttachObject(widget); // Set the target mesh for methods like Font.DrawText meshRenderer.BeginRender(widget); Rect dummyRect = new Rect(); dummyRect.left = 0; dummyRect.top = 0; dummyRect.Height = 150; dummyRect.Width = 600; font.DrawText("This is a test", dummyRect, 0); meshRenderer.EndRender(); }
public void NodeRemoved(ObjectNode node) { if (RightKind(node)) nodesRemovedSinceLastRebuild++; }
protected bool RightKind(ObjectNode node) { return (kind == StaticGeometryKind.BigOrLittleNode || (node.PerceptionRadius == 0) == (kind == StaticGeometryKind.LittleNode)) && (node.Entity == null || node.Entity.Mesh.Skeleton == null); }
protected void input_MouseDown(object sender, Axiom.Input.MouseEventArgs e) { mouseDownEvent = e; mouseDownObject = mouseoverObject; if (e.Button != MouseButtons.None) { // Keep track of which mouse buttons we think are down, and // send those to the gui system. if (!mouseButtonsDown.Contains(e.Button)) { mouseButtonsDown.Add(e.Button); log.InfoFormat("Added mouse button {0} to list of down buttons", e.Button); GuiSystem.Instance.OnMouseDown(e); } } }
// By the time this method is called, we know for sure that // the object has collision volumes. protected float CheckCollisionWithCollisionShapes(ObjectNode objNode, Ray ray) { float distance = float.MaxValue; if (objNode.Collider != null) { MovingObject mo = objNode.Collider; foreach (MovingPart part in mo.parts) { CollisionShape partShape = mo.parts[0].shape; // Check for intersection of a line 1000 meters long from the ray origin toward the ray direction float distanceToShape = partShape.RayIntersectionDistance(ray.Origin, ray.Origin + ray.Direction * (1000f * OneMeter)); if (distanceToShape == float.MaxValue) continue; else if (distanceToShape < distance) distance = distanceToShape; } } else if (objNode.CollisionShapes != null) { foreach (CollisionShape shape in objNode.CollisionShapes) { // Check for intersection of a line 1000 meters long from the ray origin toward the ray direction float distanceToShape = shape.RayIntersectionDistance(ray.Origin, ray.Origin + ray.Direction * (1000f * OneMeter)); if (distanceToShape == float.MaxValue) continue; else if (distanceToShape < distance) { // log.DebugFormat("Client.CheckCollisionWithCollisionShapes: objNode {0}, distanceToShape {1}, shape {2}", // objNode.Name,distanceToShape, shape); distance = distanceToShape; } } } return distance; }
/// <summary> /// Helper method to target mobs. This is used to handle targetting. /// Typically F8 will invoke this to target nearest mob (last = null) /// Typically Tab will invoke this to target closest mob (or last) /// </summary> /// <param name="last">last mob targetted</param> /// <param name="reverse">whether we are spiraling in instead of out</param> /// <param name="onlyAttackable"> /// whether we should exclude objects that are not attackable /// </param> public void TargetMobHelper(ObjectNode last, bool reverse, bool onlyAttackable) { // Get a copy of the list of mobs List<MobNode> mobNodes = new List<MobNode>(worldManager.GetMobNodes()); mobNodes.Remove(client.Player); IComparer<MobNode> comparer = new DistanceComparer(client.Player); mobNodes.Sort(comparer); if (reverse) mobNodes.Reverse(); // Ideally, I would set lastMob to be the last mob within // targetting range, but for now, I'll just consider all. bool lastFound = (last == null) ? true : false; ObjectNode target = null; int lastIndex = -1; if (last != null) { for (int i = 0; i < mobNodes.Count; ++i) if (mobNodes[i] == last) { lastIndex = i; break; } } // Now, starting at lastIndex + 1, loop around the list for (int i = 1; i < mobNodes.Count; ++i) { int index = (i + lastIndex) % mobNodes.Count; if (!onlyAttackable || IsAttackable(mobNodes[index])) { target = mobNodes[index]; break; } } // If we found the 'last' object, and found another object if (target != null) client.Target = target; }
public void OnTick(object source, long time) { PointF mousePos = GuiSystem.Instance.MousePosition; UiSystem.InjectTick(); UiSystem.UpdateMouseOver(); if (!cursorEnabled) return; // If the mouse is over a UI widget, don't do the mouseover or mouse click // events for the world objects. if (client.GuiHasFocus) return; // At some point, I need this cast ray logic to have // a concept of only hostile or only friendly or not // player or stuff like that. For now, I just set this // up to not include the player object. ObjectNode target = client.CastRay(mousePos.X / client.Viewport.ActualWidth, mousePos.Y / client.Viewport.ActualHeight); // MouseExit/MouseEnter events if (mouseoverObject != target) { if (mouseoverObject != null) mouseoverObject.OnMouseExit(null); mouseoverObject = target; if (mouseoverObject != null) mouseoverObject.OnMouseEnter(null); } }
/// <summary> /// This method is called when we remove an object from the world. /// This method will unregister the mouse events, clear the /// name and bubble widgets, and remove the collision volumes. /// </summary> /// <param name="sender"></param> /// <param name="objNode"></param> private void OnObjectRemoved(object sender, ObjectNode objNode) { if (objNode == null) return; RemoveCollisionObject(objNode); }
/// <summary> /// This method is called when we add an object from the world. /// This method will register the mouse events, set up the /// name and bubble widgets, and add the collision volumes. /// </summary> /// <param name="sender"></param> /// <param name="objNode"></param> private void OnObjectAdded(object sender, ObjectNode objNode) { if (objNode == null) return; AddCollisionObject(objNode); if (objNode is Player) { PlayerEnteringWorld(); return; } }
/// <summary> /// Remove the associated collision data from an object. /// </summary> /// <param name="objNode">the object for which we are removing the collision data</param> public void RemoveCollisionObject(ObjectNode objNode) { if (worldManager.CollisionHelper == null) return; bool static_object = true; if ((objNode.ObjectType == ObjectNodeType.Npc) || (objNode.ObjectType == ObjectNodeType.User)) { static_object = false; } if (static_object) { worldManager.CollisionHelper.RemoveCollisionShapesWithHandle(objNode.Oid); RegionVolumes.Instance.RemoveCollisionShapesWithHandle(objNode.Oid); } else { if (objNode.Collider != null) objNode.Collider.Dispose(); objNode.Collider = null; } }
/// <summary> /// Add the collision data for an object. This involves looking /// for a physics file that matches the mesh file's name, and /// loading the information from that file to build collision /// volumes. /// </summary> /// <param name="objNode">the object for which we are adding the collision data</param> public void AddCollisionObject(ObjectNode objNode) { if (worldManager.CollisionHelper == null) return; if (!objNode.UseCollisionObject) return; // Create a set of collision shapes for the object List<CollisionShape> shapes = new List<CollisionShape>(); string meshName = objNode.Entity.Mesh.Name; PhysicsData pd = new PhysicsData(); PhysicsSerializer ps = new PhysicsSerializer(); bool static_object = true; if ((objNode.ObjectType == ObjectNodeType.Npc) || (objNode.ObjectType == ObjectNodeType.User)) { static_object = false; } if (meshName.EndsWith(".mesh")) { string physicsName = meshName.Substring(0, meshName.Length - 5) + ".physics"; try { Stream stream = ResourceManager.FindCommonResourceData(physicsName); ps.ImportPhysics(pd, stream); foreach (SubEntity subEntity in objNode.Entity.SubEntities) { if (subEntity.IsVisible) { string submeshName = subEntity.SubMesh.Name; List<CollisionShape> subEntityShapes = pd.GetCollisionShapes(submeshName); foreach (CollisionShape subShape in subEntityShapes) { // static objects will be transformed here, but movable objects // are transformed on the fly if (static_object) subShape.Transform(objNode.SceneNode.DerivedScale, objNode.SceneNode.DerivedOrientation, objNode.SceneNode.DerivedPosition); shapes.Add(subShape); log.DebugFormat("Added collision shape for oid {0}, subShape {1}, subMesh {2}", objNode.Oid, subShape, submeshName); } } } // Now populate the region volumes foreach (KeyValuePair<string, List<CollisionShape>> entry in pd.CollisionShapes) { string regionName = RegionVolumes.ExtractRegionName(entry.Key); if (regionName != "") { // We must record this region - - must be // a static object Debug.Assert(static_object); List<CollisionShape> subShapes = new List<CollisionShape>(); foreach (CollisionShape subShape in entry.Value) { subShape.Transform(objNode.SceneNode.DerivedScale, objNode.SceneNode.DerivedOrientation, objNode.SceneNode.DerivedPosition); subShapes.Add(subShape); } RegionVolumes.Instance.AddRegionShapes(objNode.Oid, regionName, subShapes); } } } catch (Exception) { // Unable to load physics data -- use a sphere or no collision data? log.InfoFormat("Unable to load physics data: {0}", physicsName); //// For now, I'm going to put in spheres. Later I should do something real. //CollisionShape shape = new CollisionSphere(Vector3.Zero, Client.OneMeter); //if (static_object) // // static objects will be transformed here, but movable objects // // are transformed on the fly // shape.Transform(objNode.SceneNode.DerivedScale, // objNode.SceneNode.DerivedOrientation, // objNode.SceneNode.DerivedPosition); //shapes.Add(shape); } } if (static_object) { foreach (CollisionShape shape in shapes) worldManager.CollisionHelper.AddCollisionShape(shape, objNode.Oid); objNode.CollisionShapes = shapes; } else { MovingObject mo = new MovingObject(worldManager.CollisionHelper); foreach (CollisionShape shape in shapes) worldManager.CollisionHelper.AddPartToMovingObject(mo, shape); objNode.Collider = mo; objNode.Collider.Transform(objNode.SceneNode.DerivedScale, objNode.SceneNode.DerivedOrientation, objNode.SceneNode.DerivedPosition); } }
/// <summary> /// Private function to do the work of ReplaceWorldObject. /// </summary> /// <param name="movie"> /// The movie we're going to play on the object. /// </param> /// <param name="on"> /// The scene object to replace. /// </param> /// <returns> /// True if the object was replaced, false if it wasn't. /// </returns> private static bool AttachToNode(IMovie movie, ObjectNode on) { SceneNode sn = on.SceneNode; IEnumerator ie = sn.Objects.GetEnumerator(); ie.MoveNext(); MovableObject mo = (MovableObject)ie.Current; Entity en = (Entity)mo; if (ReplaceEntity(en, MeshName(movie), MaterialName(movie), movie.TextureName(), movie.VideoSize(), movie.TextureSize())) { return movie.SetTextureCoordinates(MaterialName(movie)); } else { return false; } }