Setting the Physics Owner

Let's learn about how physics is calculated in MapleStory Worlds. In the process, we will look into the changes seen when the Physics Owner is changed.

##### Reference Guide

[Using Physics](/docs?postId=757)

## Default Physics Calculations

To provide an optimized environment, MapleStory Worlds randomly selects one of the online clients as the entity making the physics calculations. The selected client is called the Host Client. The server then receives the calculation done by the Host Client and delivers it to all clients, which are synchronized. (`TransformComponent.position`, Rigid Body Postition, Speed, etc.) After an entity collision following this calculation method, the next command defined from `PhysicsContactEvent` by the creator will not be immediately synchronized with all clients. In other words, the default physics calculation method can't run something right after a rigid body collision.

  1. When a collision happens in the Host Client, this collision information is sent to the server.
  2. `PhysicsContactBeginEvent` is triggered in the server.
  3. The triggered event and the following work command written by the creator are delivered from the server to the Host Client.
  4. The Host Client delivers the result of the executed command to the server, and the result of the command is synchronized to all clients.



[png](1773385421236bc928b49892947e28f01412cef4384e4)

### Example

Let's take a look at how the default physics calculations are done with an example. We'll make snowballs come from different directions at the same speed and collide with each other, then stop without any kind of reaction. Making this example, the creator may think that both entities will stop where they collided without any kind of reaction afterwards. However, a slight shaking can be observed after the collision in the process of the server receiving the calculations from the host client and then synchronizing it with all other clients.

[gif](1773390295485056801bad3ec4fd4ba37fc379559362a)

  1. Create a new SnowBall model.

  2. Add a PhysicsRigidbodyComponent to the model and change the GravityScale and Restitution values.

     * GravityScale: 0
     * Restitution: 1

[png](1773385438260bac914e134e4403fb83577c2c6e71515)

  3. Add a PhysicsColliderComponent to the SnowBall model and set the EnableContactEvent as true. [png](1773385451235e00f637d82ba4a56ac8dcbe87f515daa)

  4. Create a new SnowBall component and add to the SnowBall model.

  5. Write the following to the SnowBall component, so the speed is reduced to 0 when it collides with a rigid body.
         
         @Component
         script CollisionStopper extends Component
         @EventSender("Self")
         handler HandlePhysicsContactBeginEvent(PhysicsContactBeginEvent event)
         --------------- Native Event Sender Info ----------------
         -- Sender: PhysicsColliderComponent
         -- Space: Server, Client
         ---------------------------------------------------------
         
         -- Parameters
         -- local ContactedBodyEntity = event.ContactedBodyEntity
         ---------------------------------------------------------
         if self:IsClient() then
             log("Client Collision Event")
         
         else 
             log("Server Collision Event")
             self.Entity.PhysicsRigidbodyComponent:SetLinearVelocity(Vector2.zero)
         end
         end
         end
         



    
    
    6. Create a new **SnowBallShooter** component.
    7. Add a **SnowBallShooter** to **map01**.
    [png](17733877162544bcb02557c164aa0a41d164ad9f95313)
    8. Write the following to the **SnowBallShooter component**.
    Spawn a ball in the server through `SpawnService` and use `ApplyLinearImpulse()` to write the following, so the rigid bodies can collide with each other.
    
        ```lua
    @Component
    script SnowballAttackPattern extends Component
        @Sync
        property string Model_SnowBall = "model://9aa7c347-c258-47d1-b92a-35d078e1f092"
        property table Dirs = {}
    
        method void OnBeginPlay()
        self:InitDirs()
        self:StartGame()
        end
    
        method void InitDirs()
        self.Dirs[1] = Vector3(math.sqrt(3)/2, 1/2, 0)
        self.Dirs[2] = Vector3(0, -1,0)
        self.Dirs[3] = Vector3(-math.sqrt(3)/2, 1/2, 0)
        end
    
        @ExecSpace("ServerOnly")
        method void StartGame()
        wait(2)
        log("launch snowballs")
    
        --Launch Snowballs from 3 Directions
        self:SpawnAndShoot(1)
        self:SpawnAndShoot(2)
        self:SpawnAndShoot(3)
        end
    
        @ExecSpace("ServerOnly")
        method void SpawnAndShoot(integer index)
        local myBall = _SpawnService:SpawnByModelId(self.Model_SnowBall, "ball"..tostring(index) , self.Dirs[index]*-6, self.Entity)
        myBall.PhysicsRigidbodyComponent:SetClientAsPhysicsOwner(_UserService.Users.Keys[1])
        myBall.PhysicsRigidbodyComponent:ApplyLinearImpulse(self.Dirs[index]:ToVector2()*4)  
        end
    end
    

## Physics Owner Designation

Physics Owner is used to designate who will calculate the physics around a set rigid body. Designating a PhysicsOwner means that the designated entity will process the physics calculation and the collision event. Server, certain Physics Owner Client, ClientOnly can be designated at the Physics Owner, and the calculation results will be applied to the TransformComponent update first. Based on the characteristics of the world of the creator, designating the Physics Owner appropriately can resolve collision detection errors, delays in collision, overall world instability, and more, which helps create a more optimized world.

### When the Physics Owner is the Client

You can delegate the physics calculations of certain rigid bodies using `SetClientAsPhysicsOwner()`. The client that calculates the rigid body's physics calculation will become the Physics Owner Client. Since `PhysicsContactBeginEvent` takes place in Physics Owner Client and Server, the Physics Owner Client is able to precisely know the timing of the designated rigid body entity collision. For example, let's assume that 3 rigid bodies are falling to the ground like the image below and that a Physics Owner Client has been designated to each. In this case, the collision trigger point can be found precisely from the rigid bodies that have been designated to each client.

[png](1773644417701290752d1e5e44fc9935dad6dd5f0ad91) [gif](17736443892644623df0598bc4d10b3daeab74de68e9f)

We can see that the Client value is more precise than the Server value in the logs below. This is because the Server's Y-axis log value is the value after the rigid body jumps up. [png](1773736003314057cdf9d44724cc2bdfc8583be24a3fc)

> Tip Unexpected results or values could result when rigid bodies with Physics Owner Clients collide, because the caluclation point for each client is different. So when designating a Physics Owner Client, it's recommended to check what the rigid body entity will collide with and avoid rigid bodies with Physics Owner Clients colliding with each other.

### When the Server is the Physics Owner

Setting the Physics Owner as the Server using `SetServerAsPhysicsOwner()` means the server will process all processes related to physics calculations like delivering collision events, delivering commands, etc. No delay after a collision is visible, because commands are executed and synchronized right after the collision. However, when the server is overloaded with calculations, it could slow the world down. It's recommended that you minimize any unneeded physics calculations from the sever and utilize the profiler and debugging to optimize the world's performance.

Let's assume that, in the default physics calculation example, the SnowBallShooter component's `SpawnAndShoot()` method was changed to `SetServerAsPhysicsOwner()`. Changing the code like the following will make it so that physics calculations will be done by the sever. Since the `PhysicsContactBeginEvent` that is triggered the moment rigid bodies collide will be processed by the server, we can observe the rigid bodies stopping immediately.

[gif](177339315661688ca00b333aa46a39ea4e3aeac32898d)
    
    
    @Component
    script BallLauncher extends Component
        @ExecSpace("ServerOnly")
        method void SpawnAndShoot(integer index)
        local myBall = _SpawnService:SpawnByModelId(self.Model_SnowBall, "ball"..tostring(index) , self.Dirs[index]*-6, self.Entity)
        myBall.PhysicsRigidbodyComponent:SetServerAsPhysicsOwner()
        myBall.PhysicsRigidbodyComponent:ApplyLinearImpulse(self.Dirs[index]:ToVector2()*4)  
        end
    end
    

### When Making Physics Calculations with ClientOnly

Setting the `ClientOnly` property for PhysicsColliderComponent as true will allow you to control the property and method in the client only. `PhysicsContactBeginEvent` will also just trigger in the client. Each client won't be able to see the screen that's synchronized in real-time. As such, the entity might be in a different position even if the world is being used together.

[png](177338552149387dce4cb11224832baa63fe841f654bf)