public SplinePoint0Node(int idx, float x, float y, IMEPackage p, PathingGraphEditor grapheditor) : base(idx, p, grapheditor) { StructProperty splineInfo = export.GetProperty <StructProperty>("SplineInfo"); if (splineInfo != null) { var pointsProp = splineInfo.GetProp <ArrayProperty <StructProperty> >("Points"); StructProperty point0 = pointsProp[0]; StructProperty point1 = pointsProp[1]; a = SharedPathfinding.GetVector2(point0.GetProp <StructProperty>("OutVal")); tan1 = SharedPathfinding.GetVector2(point0.GetProp <StructProperty>("LeaveTangent")); tan2 = SharedPathfinding.GetVector2(point1.GetProp <StructProperty>("ArriveTangent")); d = SharedPathfinding.GetVector2(point1.GetProp <StructProperty>("OutVal")); const float w = 25; const float h = 25; shape = PPath.CreateEllipse(0, 0, w, h); outlinePen = new Pen(color); shape.Pen = outlinePen; shape.Brush = pathfindingNodeBrush; shape.Pickable = false; this.AddChild(shape); this.Bounds = new RectangleF(0, 0, w, h); SText val = new SText($"{export.Index}\nSpline Start"); val.Pickable = false; val.TextAlignment = StringAlignment.Center; val.X = w / 2 - val.Width / 2; val.Y = h / 2 - val.Height / 2; this.AddChild(val); this.TranslateBy(x, y); } }
public override void LoadTrack() { Keys.ClearEx(); var lookupstruct = Export.GetProperty <StructProperty>("LookupTrack"); if (lookupstruct != null) { var trackKeys = lookupstruct.GetProp <ArrayProperty <StructProperty> >("Points"); //on lookuptrack var posTrack = Export.GetProperty <StructProperty>("PosTrack"); ArrayProperty <StructProperty> points = posTrack?.GetProp <ArrayProperty <StructProperty> >("Points"); if (trackKeys != null) { int keyindex = 0; foreach (var trackKey in trackKeys) { string tooltip = null; if (points != null && points.Count > keyindex) { StructProperty vector = points[keyindex].GetProp <StructProperty>("OutVal"); var point = SharedPathfinding.GetLocationFromVector(vector); tooltip = $"X={point.X},Y={point.Y},Z={point.Z}"; } var time = trackKey.GetProp <FloatProperty>("Time"); Debug.WriteLine(time.Value); Keys.Add(new Key(time, tooltip)); keyindex++; } } } }
public override void LoadTrack() { Keys.ClearEx(); var vectorTrackProp = Export.GetProperty <StructProperty>("VectorTrack"); if (vectorTrackProp != null) { foreach (var curvePoint in vectorTrackProp.GetPropOrDefault <ArrayProperty <StructProperty> >("Points")) { var outval = SharedPathfinding.GetLocationFromVector(curvePoint.GetProp <StructProperty>("OutVal")); //gets X Y Z Keys.Add(new Key(curvePoint.GetProp <FloatProperty>("InVal"), $"X={outval.X},Y={outval.Y},Z={outval.Z}")); } } }
/// <summary> /// Creates the reachspec connections from this pathfinding node to others. /// </summary> public override void CreateConnections(List <PathfindingNodeMaster> graphNodes) { ReachSpecs = (SharedPathfinding.GetReachspecExports(export)); foreach (ExportEntry spec in ReachSpecs) { Pen penToUse = blackPen; switch (spec.ObjectName.Name) { case "SlotToSlotReachSpec": penToUse = slotToSlotPen; break; case "CoverSlipReachSpec": penToUse = coverSlipPen; break; case "SFXLadderReachSpec": penToUse = sfxLadderPen; break; case "SFXLargeBoostReachSpec": penToUse = sfxLargeBoostPen; break; case "SFXBoostReachSpec": penToUse = sfxBoostPen; break; case "SFXJumpDownReachSpec": penToUse = sfxJumpDownPen; break; } //Get ending PropertyCollection props = spec.GetProperties(); ExportEntry otherEndExport = SharedPathfinding.GetReachSpecEndExport(spec, props); /* * if (props.GetProp<StructProperty>("End") is StructProperty endProperty && * endProperty.GetProp<ObjectProperty>(SharedPathfinding.GetReachSpecEndName(spec)) is ObjectProperty otherNodeValue) * { * othernodeidx = otherNodeValue.Value; * }*/ if (otherEndExport != null) { bool isTwoWay = false; PathfindingNodeMaster othernode = graphNodes.FirstOrDefault(x => x.export == otherEndExport); if (othernode != null) { //Check for returning reachspec for pen drawing. This is going to incur a significant performance penalty... var othernodeSpecs = SharedPathfinding.GetReachspecExports(otherEndExport); foreach (var path in othernodeSpecs) { if (SharedPathfinding.GetReachSpecEndExport(path) == export) { isTwoWay = true; break; } } //var // PropertyCollection otherSpecProperties = possibleIncomingSpec.GetProperties(); // if (otherSpecProperties.GetProp<StructProperty>("End") is StructProperty endStruct) // { // if (endStruct.GetProp<ObjectProperty>(SharedPathfinding.GetReachSpecEndName(possibleIncomingSpec)) is ObjectProperty incomingTargetIdx) // { // if (incomingTargetIdx.Value == export.UIndex) // { // isTwoWay = true; // break; // } // } // } //} //if (othernode != null) //{ var radius = props.GetProp <IntProperty>("CollisionRadius"); var height = props.GetProp <IntProperty>("CollisionHeight"); bool penCloned = false; if (radius != null && height != null && (radius >= ReachSpecSize.MINIBOSS_RADIUS || height >= ReachSpecSize.MINIBOSS_HEIGHT)) { penCloned = true; penToUse = (Pen)penToUse.Clone(); if (radius >= ReachSpecSize.BOSS_RADIUS && height >= ReachSpecSize.BOSS_HEIGHT) { penToUse.Width = 3; } else { penToUse.Width = 2; } } if (!isTwoWay) { if (!penCloned) { penToUse = (Pen)penToUse.Clone(); penCloned = true; } penToUse.DashStyle = DashStyle.Dash; } if (!penCloned) { //This will prevent immutable modifications later if we delete or modify reachspecs without a full //graph redraw penToUse = (Pen)penToUse.Clone(); penCloned = true; } PathfindingEditorEdge edge = new PathfindingEditorEdge { Pen = penToUse, EndPoints = { [0] = this, [1] = othernode }, OutboundConnections = { [0] = true, [1] = isTwoWay } }; if (!Edges.Any(x => x.DoesEdgeConnectSameNodes(edge)) && !othernode.Edges.Any(x => x.DoesEdgeConnectSameNodes(edge))) { //Only add edge if neither node contains this edge Edges.Add(edge); othernode.Edges.Add(edge); g.edgeLayer.AddChild(edge); } } } } }
public void UpdateSplines(UpdateMode mode, bool save = false) { if (mode == UpdateMode.ArriveTangent || mode == UpdateMode.LeaveTangent) { Vector3 worldCoords; if (mode == UpdateMode.ArriveTangent) { worldCoords = new Vector3(ArriveTangentControlNode.OffsetX, ArriveTangentControlNode.OffsetY, ArriveTangentControlNode.Z); LeaveTangentControlNode.SetOffset(-worldCoords.X, -worldCoords.Y); worldCoords = -worldCoords; } else { worldCoords = new Vector3(LeaveTangentControlNode.OffsetX, LeaveTangentControlNode.OffsetY, LeaveTangentControlNode.Z); ArriveTangentControlNode.SetOffset(-worldCoords.X, -worldCoords.Y); } if (save) { //will cause a refresh,so no need to update UI export.WriteProperty(CommonStructs.Vector3Prop(ActorUtils.GetWorldToLocal(export).TransformNormal(worldCoords), "SplineActorTangent")); return; } foreach (Spline spline in Splines) { spline.SplineInfo.Points[0].ArriveTangent = -worldCoords; spline.SplineInfo.Points[0].LeaveTangent = worldCoords; UpdateSpline(spline); } foreach (SplineActorNode prevSplineActor in LinksFrom) { foreach (Spline spline in prevSplineActor.Splines) { if (spline.NextActor == export) { spline.SplineInfo.Points[1].ArriveTangent = worldCoords; spline.SplineInfo.Points[1].LeaveTangent = -worldCoords; UpdateSpline(spline); } } } } else { float z = (float)SharedPathfinding.GetLocation(export).Z; Vector3 location = new Vector3(OffsetX, OffsetY, z); if (save) { //will cause a refresh,so no need to update UI SharedPathfinding.SetLocation(export, location.X, location.Y, location.Z); return; } foreach (Spline spline in Splines) { spline.SplineInfo.Points[0].OutVal = location; UpdateSpline(spline); } foreach (SplineActorNode prevSplineActor in LinksFrom) { foreach (Spline spline in prevSplineActor.Splines) { if (spline.NextActor == export) { spline.SplineInfo.Points[1].OutVal = location; UpdateSpline(spline); } } } } PathingGraphEditor.UpdateEdgeStraight(ArriveTangentControlNode.Edge); PathingGraphEditor.UpdateEdgeStraight(LeaveTangentControlNode.Edge); void UpdateSpline(Spline spline) { spline.RegenerateReparamTable(); for (int i = 0; i < spline.ReparamTable.Points.Count; i++) { (float x, float y, _) = spline.SplineInfo.Eval(spline.ReparamTable.Points[i].OutVal, Vector3.Zero); spline.nodes[i].SetOffset(x, y); } if (spline.nodes.Count > 7) { var directionVector = new Vector2(spline.nodes[7].OffsetX, spline.nodes[7].OffsetY) - new Vector2(spline.nodes[5].OffsetX, spline.nodes[5].OffsetY); directionVector.Normalize(); spline.nodes[6].Rotation = (float)(Math.Atan2(directionVector.X, -directionVector.Y) * 180 / Math.PI); } foreach (PathfindingEditorEdge edge in spline.edges) { PathingGraphEditor.UpdateEdgeStraight(edge); } } }