iOS, RealityKit, failed to move Entity towards a certain direction, with MotionSystem update function - swift

I am trying and trying to make my Entity move towards some previously described destination.
The entity moves on a microlevel over and over again but never reaches its destination. DestinationSystem checks with its update function if the Entity is close enough so it can choose a new destination for it.
I kindly ask you for help as I am absolutely out of ideas.
Here is my DestinationSystem's update function.
This system will only chose the current destination for the entity and then checks if the entity reached it.
func update(context: SceneUpdateContext) {
        let walkers = context.scene.performQuery(Self.query)
        walkers.forEach({ entity in
            guard var walker = entity.components[DestinationComponent.self] as? DestinationComponent,
                  let _ = entity.components[MotionComponent.self] as? MotionComponent else { return }
            defer {
                entity.components[DestinationComponent.self] = walker
            }
            // set the default destination to 0
            var distanceFromDestination: Float = 0
            // check if walker component for this specific entity has any destination
            if let destination = walker.destination {
                // distract distance from it
                distanceFromDestination = entity.distance(from: destination)
            }
            // check if the distance still is. If its tiny, then lets choose another distance
            if distanceFromDestination < 0.02 {
                var fixedDestination = SIMD3<Float>.spawnPoint(from: entity.transform.translation, radius: 0.7)
                fixedDestination.y = Float(0)
                // If there is any obstacle on the way to the destination, set that obstacle as the destination so it wont pass it, perhaps through the wall
                let obstacles = context.scene.raycast(
                    from: entity.position,
                    to: fixedDestination,
                    query: .nearest,
                    mask: .sceneUnderstanding,
                    relativeTo: nil
                )
                if let nearest = obstacles.first {
                    fixedDestination = nearest.position
                    fixedDestination.y = Float(0)
                }
                walker.destination = fixedDestination
            }
        })
    }
Here is my MotionSystem. Constant variable s calculates current translation to cross and multiplies it by the deltaTime of the context and 0.03 which I choose as a speed.
    func update(context: SceneUpdateContext) {
        context.scene.performQuery(Self.query).forEach { entity in
            let fixedDelta: Float = Float(context.deltaTime)
            guard let _ = entity.components[MotionComponent.self] as? MotionComponent,
                  let walker = entity.components[DestinationComponent.self] as? DestinationComponent
            else { return }
            var newTransform = entity.transform
            let s = (walker.destination! - entity.transform.translation) * 0.03 * fixedDelta
            newTransform.translation = s
            newTransform.translation.y = Float(0)
            entity.move(to: newTransform, relativeTo: entity.parent)
        }
    }
I believe it should take my Entity frame by frame to the destination point, then choose another one. It never will again.
Unless my math is terribly off?
Thank you for any help.

Related

Why does my Unity 3D Player Character jump ahead of the Cinemachine camera every few seconds?

Problem:
When the Player Character is rolling and the camera is following, every 10-30 seconds there is a frame where the player character jumps ahead of the camera and then the next frame it's back to normal. It's hard to recreate this issue as it seems to happen completely at random. My terrain is just a Unity 3D Plain with no bumps in it and some prototyping objects strewn about.
Here's a video of the issue, fast forward to the 18 second mark:
https://youtu.be/QxAY-Ko2JrQ
Setup:
The player is a ball that can freely rotate as it rolls using Lerped changes in velocity via player input.
There is a GameObject named "DollyPivot" that follows the players exact transform.position and is the follow target of my Cinemachine (Body: 3rd Person Follow no damping, Aim: Hard Look At) virtual camera so the camera doesn't rotate with the player.
Player input rotates "DollyPivot" which rotates the Cinemachine virtual camera and seems to work just fine.
Code:
I removed as much unnecessary code as possible, like code for other inputs and includes.
Player character:
public class Player_Controller : MonoBehaviour
{
    public Player_Input playerControls;
    public Transform T_CameraTransform;
    public Rotate_Dolly Camera_DollyPivot;
    // Move Variables
    public float f_MoveSpeed = 10;
    public float f_MoveSmooth = 0.2f;
    public float f_MaxSpeed = 40f;
    // Gravity
    public float f_Gravity = -9.81f;
    public float f_GroundedGravity = -0.05f;
    public float f_CurrentGravity;
    private Vector2 V2_MoveDirection;
    private Vector2 V2_CameraDirection;
    private Transform T_Player;
    private Rigidbody RB_Player;
    void Awake()
    {
        playerControls = new Player_Input();
        f_CurrentGravity = f_Gravity;
    }
    void Start()
    {
        RB_Player = GetComponent<Rigidbody>();
        T_Player = GetComponent<Transform>();
        SetupJumpVariables();
    }
    void Update()
    {
        V2_MoveDirection = playerControls.Player.Move.ReadValue<Vector2>();
        V2_CameraDirection = playerControls.Player.Look.ReadValue<Vector2>();
        Camera_DollyPivot.SetLookRotation(V2_CameraDirection.x, -V2_CameraDirection.y);
        b_IsGrounded = Physics.Raycast(transform.position, Vector3.down, 1f);
        HandleJump();
    }
    void FixedUpdate()
    {
        Move();
        HandleGravity();
    }
    private void Move()
    {
// Get Camera Normalized Directional Vectors
        Vector3 V3_Forward = T_CameraTransform.forward;
        Vector3 V3_Right = T_CameraTransform.right;
        // Create direction-relative-input vectors
        Vector3 V3_ForwardRelativeVerticalInput = V2_MoveDirection.y * V3_Forward;
        Vector3 V3_RightRelativeVerticalInput = V2_MoveDirection.x * V3_Right;
        // Create and apply camera relative movement to the player
        Vector3 V3_CameraRelativeMovement = V3_ForwardRelativeVerticalInput + V3_RightRelativeVerticalInput;
        RB_Player.velocity = Vector3.Lerp(RB_Player.velocity, new Vector3(V3_CameraRelativeMovement.x * f_MoveSpeed * Time.deltaTime, f_CurrentGravity, V3_CameraRelativeMovement.z * f_MoveSpeed * Time.deltaTime), f_MoveSmooth);
    }
    void HandleGravity()
    {
        if (b_IsGrounded)
        {
            f_CurrentGravity = f_GroundedGravity * Time.deltaTime;
        } else {
            f_CurrentGravity += f_Gravity * Time.deltaTime;
        }
    }
    private void OnEnable()
    {
        playerControls.Enable();
    }
    private void OnDisable()
    {
        playerControls.Disable();
    }
}
DollyPivot GameObject (Cinemachine VCamera's follow target):
Handles player input as rotation to DollyPivot GameObject and in turn moves the camera.
public class Rotate_Dolly : MonoBehaviour
{
    public float f_Horizontal = 0f;
    public float f_Vertical = 0f;
    public float f_CameraSpeed = 2f;
    public float f_MinAngle = 40f;
    public float f_MaxAngle = 340f;
    private Transform T_Self;
    void Start()
    {
        T_Self = GetComponent<Transform>();
    }
    void FixedUpdate()
    {
        T_Self.rotation *= Quaternion.AngleAxis(f_Horizontal * f_CameraSpeed, Vector3.up);
        T_Self.rotation *= Quaternion.AngleAxis(f_Vertical * f_CameraSpeed, Vector3.right);
        var angles = T_Self.localEulerAngles;
        angles.z = 0;
        var angle = T_Self.localEulerAngles.x;
        if (angle > 180 && angle < f_MaxAngle)
        {
            angles.x = f_MaxAngle;
        }
        else if (angle < 180 && angle > f_MinAngle)
        {
            angles.x = f_MinAngle;
        }
        T_Self.localEulerAngles = angles;
    }
    public void SetLookRotation(float xRotation, float yRotation)
    {
        f_Horizontal = xRotation;
        f_Vertical = yRotation;
    }
}
Attached to DollyPivot to follow Player Character
public class Follow_Target : MonoBehaviour
{
    public float f_Smooth = 0.3f;
    public Transform T_Target;
    private Transform T_Self;
    void Start()
    {
        T_Self = GetComponent<Transform>();
    }
    void FixedUpdate()
    {
        T_Self.position = Vector3.Lerp(T_Self.position, T_Target.position, f_Smooth);
    }
}
I've been trying all sorts of things to get this to stop happening. Considering it is a very stripped down project there are only so many things I could think to try.
I've tried:
Completely removing the DollyPivot and switching the Cinemachine VCam to Orbital Transposer that just follows the player directly.
Moving everything into FixedUpdate() that I think should be in there.
Adding Lerping/Smoothing to anything that deals with positioning/velocity.
Adding, removing, and tweaking: Camera X and Y look at and follow damping, DollyPivot follow target smoothing, Lerping Player input movement velocities.
Changing the max speeds of the Player Character to see if it was velocity related.
Changing the player RigidBody interpolation mode to interpolate.
And probably other things I've forgotten about at this point.
I'm at a loss for what could be the problem, any help or insight would be greatly appreciated! Thank you!

Check if a file or directory has a specific alternative data stream attached to it?

I am writing a function or a commandlet (I want to call it Set-Metadata) that will allow me to attach metadata information to directories and files. Its for a file manager columns that expect ADS data
I am currently stuck on the logic part.
Before I write any metadata to a file via its NTFS ADS I would first like to check if the file has a specific stream so that I don't overwrite anything and instead append text to the stream.
function Set-MetaData(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
    [string]
    $Path,
    [Alias("C", "Cat")] #Replace Column Content
    [String]$Category,
    [Alias("PC", "PCat")] #Prefix to the content in  Column
    [String]$PCategory,
    [Alias("SC", "SCat")] #Suffix to the content in  Column
   
    [String]$SCategory){
        process {
        Switch ($PSBoundParameters.Keys){
            'Category'{
            }'PCategory'{
            }'SCategory'{
                if(...) #file has a stream called "multitags.txt"
                # Add-Content -Path $Path -Stream  multitags.txt -Value $Category
    }}
}
I have taken the liberty to cross post this question on other forums as well.
Any help would be greatly appreciated!

Unable to update content in xml tag using XML::Twig

I am unable to update content in xml tag using xml Twig module.
Here is my xml file :-
<?xml version="1.0"?>
<test customerProprietary="false">
  <classes>
    <class name="new" />
  </classes>
  <chars>
    <log>false</log>
  </chars>
</test>
Code snippet:-
my $twig = XML::Twig->new(
     pretty_print => 'indented',
     twig_handlers => {
             log => sub {
                             if ($_->text eq 'true'){
                               exit;
                             }
                             else{
                               print $_->text;
                               subp4open($xmlfile);
                               $_->set_text( 'true' );
                               exit;
                            }
}
);
$twig->parsefile($script_path);
$twig->print_to_file($script_path);
i have to update <log>false</log> to <log>true</log>. Am i missing something here?
That's because exit exits the program, so print_to_file is never reached. Remove the exits. You can replace them with returns, but they aren't needed.
When I run into these sorts of things, I like to put a statement like say "This far" to see that I've made it to a particular part of the code:
say "About to parse file";
$twig->parsefile($script_path);
say "About to print file";
$twig->print_to_file($script_path);
In your handler, there are some things that you can improve. Since you don't want to do anything in the case that the value is already true, don't even think about that case:
log => sub {
if ($_->text ne 'true'){
print $_->text;
subp4open($xmlfile);
$_->set_text( 'true' );
}
},
I might be inclined to always update the value if you want them all to be true. I don't care what it was before as long as I get what I want at the end (although this way tweak your source control a bit):
log => sub { $_->set_text( 'true' ) },
Also, I might consider doing any Perforce magic outside of the twig handler. Get the lock on the file before you give it to Twig. If you can't get that lock, you might as well not process it. Then, remember to release it later. If you do all of those operations close together, you're less likely to forget a step.

Callbacks not rendered as native Facebook messages?

According to this scenario.
Used to test it using sample message - text. And it works fine.
I should implement that by using buttons (callbacks).
The real problem is :
Sample text :
context.Activity.Id
"mid.$cAAOmNGtaSJ9i1_f223cprKylFOpb"
on button click (callback) :
context.Activity.Id
"9Yw5TAcq1qr"
This is the code i used to post human support button :
msg.AttachmentLayout = AttachmentLayoutTypes.Carousel;
                    msg.Attachments = new List<Attachment>();
 
                    ThumbnailCard thumbnailCard2 = new ThumbnailCard()
                    {
                        Buttons = new List<CardAction>
                        {
                                new CardAction ()
                            {
                                Value = "Method_Support",
                                Type = "postBack",
                                Title = "Human Support"
 
                            },
                        },
                    };
                    msg.Attachments.Add(thumbnailCard2.ToAttachment());
                    await context.PostAsync(msg);
It returns activity.Id : 9Yw5TAcq1qr - as i already mentioned. I can't use that id to query Facebook graph api.
What's the best way to handle scenario like this ?
Is it possible to render all incoming messages as native Facebook (sample-text) messages ?
Is it possible to make call to graph api using callback's activity.id ?
Following my previous answer about how to link the Activity from botFramework to the messages in Conversation in Facebook's Graph API, I had a look to your problem.
Analysis
From my point of view, there is a strange thing in this Activity.Id value because on Facebook's side, all messages have the same id format, even for callbacks.
Here is a capture of 2 messages (1st one is the latest one) from Facebook Graph API:
{
"data": [{
"messages": {
"data": [
{
"id": "m_mid.$cAAC3Jml0RcBi2JK3Clcp01uu8FFe",
"message": "Human support"
},
{
"id": "m_mid.$cAAC3Jml0RcBi2I5bXlcp0kScM7af",
"message": ""
}
]
},
"id": "t_mid.$..."
}]
}
Message with empty text is a ThumbnailCard with a CardAction inside (type = postback, Value = Method_HumanSupport)
Human support is what is sent on the click on the CardAction
What is surprising is that on the bot side, for those 2 messages we have the following values for Activity.Id:
For "id": "m_mid.$cAAC3Jml0RcBi2I5bXlcp0kScM7af" (my Thumbnail) => mid.$cAAC3Jml0RcBi2I5bXlcp0kScM7af, so it's matching
For "id": "m_mid.$cAAC3Jml0RcBi2JK3Clcp01uu8FFe" (the callback) => DWhE2C0VO79, no match at all
For information my ThumbnailCard is made like the OP said:
var msg = context.MakeMessage();
msg.AttachmentLayout = AttachmentLayoutTypes.Carousel;
msg.Attachments = new List<Attachment>();
msg.Text = "updates & support";
ThumbnailCard thumbnailCard2 = new ThumbnailCard()
{
Buttons = new List<CardAction>
{
new CardAction ()
{
Value = "Method_HumanSupport",
Type = "postBack",
Title = "Human support"
}
}
};
I will add a question on Bot Framework GitHub Project.
Edit: issue logged: https://github.com/Microsoft/BotBuilder/issues/2950
Workaround
There are several workaround that will depend on your global use cases: you could try to log the Activity.Id of a "normal" message in the discussion and use this value later when your callback is clicked, or you can also try to change your flow to avoid making this kind of link between Bot Framework and Facebook Graph API.

Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.

I have the following query:
SELECT QuoteReference,
       CreatedDate,
       StartDate,
       EndDate,
       Operation,
       TableName,
       OccurredAt,
       PerformedBy,
       FieldName,
       OldValue,
       NewValue,
       Quotes.CreatedByID,
       CompletedDate,
       EmailAddress = (SELECT ContactDetails.EmailAddress,
                              QuoteReference,
                              ContactDetails.MobilePhoneNumber
                       FROM   ContactDetails,
                              Quotes,
                              QuoteCustomers
                       WHERE  ContactDetails.ID = Quotes.ID
                              AND QuoteCustomers.QuoteID = ContactDetails.ID)
FROM   Quotes
       JOIN Audit
         ON Quotes.ID = Audit.RowId
WHERE  Quotes.CreatedDate BETWEEN '20100401' AND '20120830'
       AND PaymentReference IS NOT NULL
       AND Audit.OccurredAt > Quotes.CompletedDate
       AND Quotes.EmailAddress < > NULL
       AND TableName = 'Quotes'
       AND Quotes.PolicyReference = NULL
       AND Quotes.CreatedByID < > 2 
ORDER BY  Audit.OccurredAt desc
I get this error when executing:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
After adding the second where clause in the subquery. What can I do to fix this?
You are selecting three columns values into one variable.
Change
EmailAddress = (SELECT EmailAddress,
QuoteReference,
ContactDetails.MobilePhoneNumber
FROM ContactDetails,
Quotes,
QuoteCustomers
WHERE ContactDetails.ID = Quotes.ID
AND QuoteCustomers.QuoteID = ContactDetails.ID)
to
EmailAddress = (SELECT EmailAddress
FROM ContactDetails,
Quotes,
QuoteCustomers
WHERE ContactDetails.ID = Quotes.ID
AND QuoteCustomers.QuoteID = ContactDetails.ID)
Your subquery have to return ONE row and ONE column so it should looks like:
EmailAddress = (SELECT TOP 1 ContactDetails.EmailAddress
FROM ContactDetails,
Quotes,
QuoteCustomers
WHERE ContactDetails.ID = Quotes.ID
AND QuoteCustomers.QuoteID = ContactDetails.ID)