Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Runtime rope deserialization issue
#1
Hello,

I have a couple of player modified ropes that are generated in runtime. When the game is saved, I serialize the actor particles positions, velocities and rotations through the solver. When game is loaded, I create the same rope and load the particle data like this:

Code:
solver.positions.SetVector3(i, ParticlePositions[i]);
solver.velocities.SetVector3(i, ParticleVelocities[i]);
solver.angularVelocities.SetVector3(i, ParticleAngularVelocities[i]);

However the moment game is loaded and ObiFixedUpdater started running, my data gets overriden. If I wait for example 2-3 seconds before setting these parameters the rope is already initialized and then after setting these, it works as expected.

Is there any way that I can do this without waiting 2-3 seconds? I tried hooking on OnEndStep of the rope and doing the change there and I tried forcefully stepping the ObiFixedUpdater after I create the rope but none seems to be working.

Thanks in advance!
Reply
#2
(18-09-2023, 01:48 PM)aderae Wrote: Hello,

I have a couple of player modified ropes that are generated in runtime. When the game is saved, I serialize the actor particles positions, velocities and rotations through the solver. When game is loaded, I create the same rope and load the particle data like this:

Code:
solver.positions.SetVector3(i, ParticlePositions[i]);
solver.velocities.SetVector3(i, ParticleVelocities[i]);
solver.angularVelocities.SetVector3(i, ParticleAngularVelocities[i]);

However the moment game is loaded and ObiFixedUpdater started running, my data gets overriden. If I wait for example 2-3 seconds before setting these parameters the rope is already initialized and then after setting these, it works as expected.

Is there any way that I can do this without waiting 2-3 seconds? I tried hooking on OnEndStep of the rope and doing the change there and I tried forcefully stepping the ObiFixedUpdater after I create the rope but none seems to be working.

Thanks in advance!

Hi there,

The data in the solver arrays will be overriden when the actor gets its blueprint loaded. You should do any modifications after the blueprint is loaded, by subscribing a method to the ObiActor.OnBlueprintLoaded event and putting your code there.

kind regards,
Reply
#3
@josemendez as always thanks for the informative and very swift response! much appreciated.

However this is what happens now in order:

- create ObiRope
- create blueprint during runtime with 2 control points
- create 2 attachments
- subscribe to OnBlueprintLoaded
- set ropes blueprint to this newly loaded blueprint
- add solver to ObiFixedUpdater
- OnBlueprintLoaded is called and here I set positions and I set both velocities and angularVelocities to Vector3.zero in order to test
- game runs but all particles are somewhere else and rope is bouncing all around

it looks like somehow all my code is again overriden by the physics simulation
Reply
#4
Could you share the code you're using for setting the velocities? Note angular velocities are completely unused by ropes, they're only used by rods since rope particles are not oriented but just positions in space.

Also, could you share the code you use to create the blueprint? you mention "game runs but all particles are somewhere else and rope is bouncing all around" which is extremely strange.
Reply
#5
Code:
ObiRopeBlueprint blueprint = ScriptableObject.CreateInstance<ObiRopeBlueprint>();
            int filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 0);
            blueprint.pooledParticles = 0;
            blueprint.thickness = Config.Thickness;
            blueprint.resolution = 2;
            //particleCount = ropeLength / ropeThickness * resolution

            blueprint.path.Clear();
            blueprint.path.AddControlPoint(Config.Front.localPosition, -Vector3.right, Vector3.right, Vector3.up, 0.1f, 0.1f, 0.8f, filter, Color.white, "start");
            blueprint.path.AddControlPoint(Config.Back.localPosition, -Vector3.right, Vector3.right, Vector3.up, 0.1f, 0.1f, 0.8f, filter, Color.white, "end");
            blueprint.path.RecalculateLenght(Matrix4x4.identity, 0.00001f, 7);
           
            float totalParticleCount = 30;
            blueprint.resolution = totalParticleCount * Config.Thickness / blueprint.path.Length;
            blueprint.path.FlushEvents();

            ObiParticleAttachment frontAttachment = ObiRope.gameObject.AddComponent<ObiParticleAttachment>();
            frontAttachment.attachmentType = ObiParticleAttachment.AttachmentType.Static;
            frontAttachment.target = Config.Front;
            frontAttachment.particleGroup = blueprint.groups[0];

            ObiParticleAttachment backAttachment = ObiRope.gameObject.AddComponent<ObiParticleAttachment>();
            backAttachment.attachmentType = ObiParticleAttachment.AttachmentType.Static;
            backAttachment.target = Config.Back;
            backAttachment.particleGroup = blueprint.groups[1];

            ObiRope.OnBlueprintLoaded += ObiRopeLoaded;
            ObiRope.ropeBlueprint = blueprint;

            ObiFixedUpdater.solvers.Add(ObiSolver);

Code:
private void ObiRopeLoaded(ObiActor actor, ObiActorBlueprint blueprint)
        {
            // load particle positions
            for (int i = 0; i < ObiSolver.positions.count; i++)
            {
                if (i < ParticlePositions.Count)
                {
                    ObiSolver.positions.SetVector3(i, ParticlePositions[i]);
                }
                ObiSolver.velocities.SetVector3(i, Vector3.zero);
            }
           
            ParticlePositions.Clear();
        }

As I said, if I wait 2 seconds and run the code in ObiRopeLoaded part, all works perfectly fine
Reply
#6
(18-09-2023, 02:44 PM)aderae Wrote:
Code:
private void ObiRopeLoaded(ObiActor actor, ObiActorBlueprint blueprint)
        {
            // load particle positions
            for (int i = 0; i < ObiSolver.positions.count; i++)
            {
                if (i < ParticlePositions.Count)
                {
                    ObiSolver.positions.SetVector3(i, ParticlePositions[i]);
                }
                ObiSolver.velocities.SetVector3(i, Vector3.zero);
            }
           
            ParticlePositions.Clear();
        }

Hi,

This bit is completely incorrect. You're iterating trough all particles in the solver including inactive ones, and disregarding the order in which they appear in the rope. Might work purely out of luck, but most of the time this will result in wrong positions given to the particles and overall unpredictable behavior.

Each actor has a solverIndices array that contains the index of the actor's particles in the solver. So solver.positions[actor.solverIndices[0]]  would be the position of the first particle in the rope, solver.positions[actor.solverIndices[1]]  would be the position of the second particle, etc. The solver might have allocated space for 2000 particles, but if actor.solverIndices only has 20 entries, then only 20 of those particles are used. Note they might not be given consecutive indices in the solver, no guarantees are made about the order in which particles are allocated.

See:
http://obi.virtualmethodstudio.com/manua...icles.html

Using solverIndices to iterate trough all particles, it works just fine for me. Even then, setting all particle positions to zero also works fine, so there must be something else going on in your project. If you want, I can take a closer look at it if you send the project to support(at)virtualmethodstudio.com.

kind regards,
Reply
#7
I've fixed the code and it works now. thank you
Reply