Facepunch / sbox-issues

178 stars 12 forks source link

`ModelCollider` from procedural Model not correctly replicated #6675

Open PolSpock opened 1 month ago

PolSpock commented 1 month ago

Describe the bug

Hi,

Edited 26/10/2024 17:30 CEST (simpler example)

I'm working with ModelCollider from a Procedural Model (sbox_procedural_model.vmld) attached to a Network GameObject that i refresh through GameObject.Network.Refresh() for other clients.

However, it seems that the Convex Hull collision model is not correctly replicated to other clients. Image

Let's jump to the reproduction steps

To Reproduce

1) Download the sbox-scenestaging repository. 2) Update the Gun.cs file with the provided OnUpdate() code.

protected override void OnUpdate()
{
    if ( IsProxy )
        return;

    var pc = Components.GetInAncestors<PlayerController>();
    if ( !pc.IsValid() )
        return;

    if ( Input.Pressed( "Attack1" ) && Game.ActiveScene.GetAllObjects( true ).FirstOrDefault( x => x.Name == "TestCollider" ) == null )
    {
        Log.Info( "Attack1" );

        var go = new GameObject();
        go.Name = "TestCollider";
        go.WorldPosition = pc.WorldPosition;

        /* */

        var goSubColumn = new GameObject();
        goSubColumn.Name = "Column";
        goSubColumn.SetParent( go, false );
        goSubColumn.WorldPosition = go.WorldPosition;
        goSubColumn.WorldRotation = go.WorldRotation;
        goSubColumn.LocalPosition = new Vector3( 0, 0, 0);

        go.NetworkSpawn();
    }

    if ( Input.Pressed( "Attack2" )  )
    {
        Log.Info( "Attack2" );

        var go = Game.ActiveScene.GetAllObjects( true ).FirstOrDefault( x => x.Name == "TestCollider" );
        if ( !go.IsValid() ) { return; }

        foreach ( var goColumn in go.GetAllObjects( true ).Where( x => x.Name.Contains( "Column" ) ) )
        {
            float factor = 64f;

            Vector3[] myCube = new Vector3[]
            {
                new Vector3(-0.5f, -0.5f, -0.5f) * factor,
                new Vector3(0.5f, -0.5f, -0.5f) * factor,
                new Vector3(0.5f, 0.5f, -0.5f) * factor,
                new Vector3(-0.5f, 0.5f, -0.5f) * factor,
                new Vector3(-0.5f, -0.5f, 0.5f) * factor,
                new Vector3(0.5f, -0.5f, 0.5f) * factor,
                new Vector3(0.5f, 0.5f, 0.5f) * factor,
                new Vector3(-0.5f, 0.5f, 0.5f) * factor
            };

            var modelBuilder = new ModelBuilder();
            modelBuilder.AddCollisionHull( myCube );
            var model = modelBuilder.Create();

            var mainCollider = goColumn.Components.GetOrCreate<ModelCollider>();
            mainCollider.Model = model;
        }

        go.Network.Refresh();
    }
}

4) Start the networking.scene. 5)

6) Extra:

Expected behavior

The ModelCollider from this Procedural Model must be correctly replicated

Also I’m wondering if I might be doing something wrong, as @Metapyziks has successfully worked on procedural models using the SDF library without encountering this issue. Could it be that each client needs to rebuild the collider logic on their side?

Media/Files

(old) Reproduction steps in video:

https://github.com/user-attachments/assets/58b1c149-f85a-4d76-bcfc-865f6ac5ba3e

Additional context

No response

PolSpock commented 1 month ago

I updated the issue with an easier example of the reproduction steps: 1) Edit Gun.cs -> OnUpdate()

protected override void OnUpdate()
{
    if ( IsProxy )
        return;

    var pc = Components.GetInAncestors<PlayerController>();
    if ( !pc.IsValid() )
        return;

    if ( Input.Pressed( "Attack1" ) && Game.ActiveScene.GetAllObjects( true ).FirstOrDefault( x => x.Name == "TestCollider" ) == null )
    {
        Log.Info( "Attack1" );

        var go = new GameObject();
        go.Name = "TestCollider";
        go.WorldPosition = pc.WorldPosition;

        /* */

        var goSubColumn = new GameObject();
        goSubColumn.Name = "Column";
        goSubColumn.SetParent( go, false );
        goSubColumn.WorldPosition = go.WorldPosition;
        goSubColumn.WorldRotation = go.WorldRotation;
        goSubColumn.LocalPosition = new Vector3( 0, 0, 0);

        go.NetworkSpawn();
    }

    if ( Input.Pressed( "Attack2" )  )
    {
        Log.Info( "Attack2" );

        var go = Game.ActiveScene.GetAllObjects( true ).FirstOrDefault( x => x.Name == "TestCollider" );
        if ( !go.IsValid() ) { return; }

        foreach ( var goColumn in go.GetAllObjects( true ).Where( x => x.Name.Contains( "Column" ) ) )
        {
            float factor = 64f;

            Vector3[] myCube = new Vector3[]
            {
                new Vector3(-0.5f, -0.5f, -0.5f) * factor,
                new Vector3(0.5f, -0.5f, -0.5f) * factor,
                new Vector3(0.5f, 0.5f, -0.5f) * factor,
                new Vector3(-0.5f, 0.5f, -0.5f) * factor,
                new Vector3(-0.5f, -0.5f, 0.5f) * factor,
                new Vector3(0.5f, -0.5f, 0.5f) * factor,
                new Vector3(0.5f, 0.5f, 0.5f) * factor,
                new Vector3(-0.5f, 0.5f, 0.5f) * factor
            };

            var modelBuilder = new ModelBuilder();
            modelBuilder.AddCollisionHull( myCube );
            var model = modelBuilder.Create();

            var mainCollider = goColumn.Components.GetOrCreate<ModelCollider>();
            mainCollider.Model = model;
        }

        go.Network.Refresh();
    }
}

Result on each client (except the one who ran the code): Image

Expected on each client : Image