Adding GameObject rotation Update workflow

zoultrex
zoultrex
edited October 2010 in Photon Server
Before I go into hours of trial and error, with a lot of errors ;), could someone give me an idea of the main things I need to take care when implementing an Item rotation Update on the client and server side.

I think If I just duplicate everything related to the movement update but change the information from position values to rotation values it should work right?
«1

Comments

  • One of the things that I think i will need to duplicate and adapt is this event...
    public event Action<Item> Moved;
    
    ..that is called from this function...
    private void OnMoved()
    {
       if (this.Moved != null)
       {
          this.Moved(this);
       }
    }
    

    But I dont know what the event is really triggering
  • Boris
    Boris ✭✭
    If possible switch to the latest version - the event has been replaced with a virtual OnMove.
    The answer below applies to the newest version.

    The Move operation is executed at MmoActor.ItemOperationMove.
    You need to extend the operation "Move" and the event "ItemMoved" with a rotation parameter, and then implement a new method that accepts the rotation parameter:
    public void Move(Vector newPosition, Vector rotation, Reliability reliability)
    {
        // call base move method
        this.Move(newPosition, reliability);
    
        // send event
        var eventInstance = new ItemMoved { 
            ItemId = this.Id, 
            ItemType = this.Type, 
            OldPosition = this.Position, 
            Position = newPosition, 
            Rotation = rotation };
    
         EventData data = eventInstance.GetEventData(
             (byte)EventCode.ItemMoved, 
             reliability, 
             Settings.ItemEventChannel );
    
         var message = new ItemEventMessage( this, data );
         this.EventChannel.Publish(message);
    }
    

    To avoid sending two events remove the "MmoItem.OnMove" override.
  • Thanks, i'll give that a try.
    I was already going the wrong direction sending two events instead of aditional data in the same event.
    If possible switch to the latest version - the event has been replaced with a virtual OnMove.
    The answer below applies to the newest version.
    I have the version:
    ExitGames-Photon-MMO-Demo_v2-0-2-RC5
    I believe this is the latest Unity client isnt it?
  • Boris
    Boris ✭✭
    zoultrex wrote:
    I have the version:
    ExitGames-Photon-MMO-Demo_v2-0-2-RC5
    ouch, that wasn't updated with the release :cry:

    ok, then just remove the Move event listener, the rest stays the same.
  • After adding a reference to rotation almoust everywhere I could find I went to a quick test to see if I succeeded (obviously not) and I cant join the worlds anymore.
    Unity: unexpected operation error WorldAlreadyExists from operation CreateWorld in state Connected
    

    I know that the error says the world already exists, but its not true because im trying to join the world as soon as the server starts.

    My question is, when a player tries to join the server and sends the command to enter a world, where does the MmoWorldCache is called for the first time to either try to create the first world or to join an existing one?
  • Boris
    Boris ✭✭
    if EnterWorld returns with an error CreateWorld is called. See Class "Connected", method "OnOperationReturn". (line 105)
    Unfortunately the callback does not check the error code, so this could mean that there is another error returned than expected.
    It might be easier to test with the WinGrid client, it uses the same code here.
  • Boris wrote:
    If possible switch to the latest version - the event has been replaced with a virtual OnMove.
    The answer below applies to the newest version.

    The Move operation is executed at MmoActor.ItemOperationMove.
    You need to extend the operation "Move" and the event "ItemMoved" with a rotation parameter, and then implement a new method that accepts the rotation parameter:
    public void Move(Vector newPosition, Vector rotation, Reliability reliability)
    {
        // call base move method
        this.Move(newPosition, reliability);
    
        // send event
        var eventInstance = new ItemMoved { 
            ItemId = this.Id, 
            ItemType = this.Type, 
            OldPosition = this.Position, 
            Position = newPosition, 
            Rotation = rotation };
    
         EventData data = eventInstance.GetEventData(
             (byte)EventCode.ItemMoved, 
             reliability, 
             Settings.ItemEventChannel );
    
         var message = new ItemEventMessage( this, data );
         this.EventChannel.Publish(message);
    }
    

    To avoid sending two events remove the "MmoItem.OnMove" override.

    Ok I implemented the Move function in MmoItem class but as I suspected it never gets called.
    I tried to track down where the original move function "OnMove" gets called but I could not find, I searched the entire solution using Visual Studio search function but no results came up.
    I know that this "OnMove" function is virtual from "Item" but when I right click on the Item class and choose "go to definition" it brings a class from cache.
    I got into 2 dead ends now :cry:

    So how is this new "Move" function in MmoItem is ever going to be called? Or do I need to add it somewhere?
  • Boris
    Boris ✭✭
    change method MmoActor.ItemOperationMove to call the new function.
  • Not too sure how to do that... inside MmoActor we have the following...
    private OperationResponse ItemOperationMove(Item item, Move operation)
    {
       // should always be OK
       MethodReturnValue result = this.CheckAccess(item);
       if (result)
          {
             item.Move(operation.Position, operation.OperationRequest.Reliability);
    
    The function I want to call is in the class MmoItem, item subclass, so first step would be to change the Item reference on the parameter and inside the If statement to MmoItem.

    Im stuck here because once again searching all the files in the server solution I could not find any reference to ItemOperationMove method call, its like this function is called out of the air or something.
  • Boris
    Boris ✭✭
    You can simply cast the item to MmoItem.
    The method is called in the same class by the way, just follow the onoperationrequest path for operationcode move.
  • Hello, I'd like to implement the rotation too.

    I managed to do ALL the things you wrote above, however, my Unity client throws the following exception every time the player moves:
    Player: unexpected operation error Fatal from operation Move in state WorldEntered
    
    Client.Engine.Game:OnUnexpectedOperationError(OperationCode, ErrorCode, String, Hashtable)
    Client.Engine.GameStateStrategies.WorldEntered:OnOperationReturn(Game, OperationCode, ReturnCode, Hashtable)
    Client.Engine.Game:OperationResult(Byte, Int32, Hashtable, Int16)
    

    After some investigation, I noticed that this error is thrown when I add the rotation parameter to the ItemMoved class as following:
    [EventParameter(Code = (short)ParameterCode.Rotation)]
    public float[] Rotation { get; set; }
    
    ParameterCode.Rotation is set to 71;

    Unity client seems to successfully send the rotation parameter but server has a problem with understanding the operation and it fails with sending back the result.

    What can be the cause?
  • Boris
    Boris ✭✭
    A fatal error means that there has been an exception, check the server log file.
  • Thanks for response!

    I did and it shows nothing, the latest message is "Service is running..."

    Probably it could be in the app log but since I deployed my own server app based on MmoDemo there is no its own log as the MmoDemo.Server.log file. What can I do?
  • Boris
    Boris ✭✭
    You can configure the log file name and location with the log4net.config file.
  • Great, now that's something.

    The log file shows:
    2010-07-28 18:00:23,860 [9] ERROR Server.PhotonApplication - System.ArgumentException: Null value: 71 (ItemMoved.Rotation)
       w #dj.#tj.#Lk[TAttribute](Object )
       w Photon.SocketServer.EventData.Create(Int16 eventCode, Object source, Reliability reliability, Byte channelId)
       w Photon.SocketServer.Rpc.Event.GetEventData(Byte eventCode, Reliability reliability, Byte channelId)
       w Server.MmoItem.OnMove(Vector newPosition, Region region, Reliability reliability) w D:\MmoTest\src\Server\MmoItem.cs:wiersz 65
       w Photon.SocketServer.Mmo.Item.Move(Vector newPosition, Reliability reliability)
       w Server.MmoActor.ItemOperationMove(Item item, Move operation) w D:\MmoTest\src\Server\MmoActor.cs:wiersz 878
       w Server.MmoActor.OperationMove(Peer peer, OperationRequest request) w D:\MmoTest\src\Server\MmoActor.cs:wiersz 318
       w Server.MmoActor.OnOperationRequest(Peer peer, OperationRequest operationRequest) w D:\MmoTest\src\Server\MmoActor.cs:wiersz 647
       w Photon.SocketServer.Rpc.Peer.HandleOperationRequest(OperationRequest request)
       w Photon.SocketServer.Rpc.Peer.#s.#Dj.#dl()
       w Photon.SocketServer.Rpc.OperationQueue.#ek(Func`1 , Peer , OperationRequest )
    
    So, the rotation value was null in onMove function in MmoItem class. That's because it was called as a result of calling the "old" Move function in our new custom Move function (in the beginning: this.Move(newPosition, reliability);). I set the rotation parameter as optional in ItemMoved class and it's working now, no error ;)

    I haven't implemented the rotation of actors in Unity client yet so I can't actually see the result, but it should work now, I guess..

    Thanks for help!
  • Boris
    Boris ✭✭
    loock_ wrote:
    So, the rotation value was null in onMove function in MmoItem class. That's because it was called as a result of calling the "old" Move function in our new custom Move function (in the beginning: this.Move(newPosition, reliability);). I set the rotation parameter as optional in ItemMoved class and it's working now, no error ;)
    since you already send the event with the new Move method you can remove the onmove override, or you will send the event twice: once with and once without the rotation.
  • Boris
    Boris ✭✭
    @zoultrex: I double checked what's in ExitGames-Photon-MMO-Demo_v2-0-2-RC5 and it is the version with the OnMove override and not the one with the moved event. Where did you get the Moved event from?
    zoultrex wrote:
    public event Action<Item> Moved;
    
    ..that is called from this function...
    private void OnMoved()
    {
       if (this.Moved != null)
       {
          this.Moved(this);
       }
    }
    

    But I dont know what the event is really triggering
    zoultrex wrote:
    I have the version:
    ExitGames-Photon-MMO-Demo_v2-0-2-RC5
    I believe this is the latest Unity client isnt it?
  • What you want is in the MmoItem.cs file

    Here is a copy of my file that is handeling it no problem:
    http://pastebin.com/vv2WX3GX

    Please note that you have to change also the following:

    Go to MmoActor.cs and look for the line
    public OperationResponse OperationMove(Peer peer, OperationRequest request)
    
    Find the last line of this method and comment it out and replace with this one:
    return this.ItemOperationMove((MmoItem)item, operation);

    Let me know if it works, there are log entries comming into the MmoDemo.Server.log file where you will be able to see the rotation changing if it all works out.

    Also remember that after you receive the values from the server you have to update them into the game, thats what im about to do right now. Good luck :D
  • Boris
    Boris ✭✭
    the code is buggy :o
    protected override void OnMove(Vector newPosition, Region region, Reliability reliability)
            {
            //this is the original method that handles the move by default, once you implement the new one you can comment this out if you want
            //check below the next method is the new one that handles the rotation
                var eventInstance = new ItemMoved { ItemId = this.Id, ItemType = this.Type, OldPosition = this.Position, Position = newPosition, Rotation = this.Rotation };
                log.InfoFormat("[MmoItem] Item OnMove ROT[ {0} ] ", this.Rotation);
     
                var message = new ItemEventMessage(this, eventInstance.GetEventData((byte)EventCode.ItemMoved, reliability, Settings.ItemEventChannel));
                this.EventChannel.Publish(message);
            }
    
      public void Move(Vector newPosition, Vector rotation, Reliability reliability)
            {
            //this is the new move method, it should handle the new movement with the rotation
            //check aboxe the original onMove method that should be removed because its a duplicate
                log.InfoFormat("[MmoItem] new move this.ROT[ {0} ] param.rot. {1}", this.Rotation, rotation);
     
                // call base move method
                this.Move(newPosition, reliability);
                this.Rotation = rotation;
                // send event
                var eventInstance = new ItemMoved
                {
                    ItemId = this.Id,
                    ItemType = this.Type,
                    OldPosition = this.Position,
                    Position = newPosition,
                    Rotation = rotation
                };
     
                EventData data = eventInstance.GetEventData(
                    (byte)EventCode.ItemMoved,
                    reliability,
                    Settings.ItemEventChannel);
     
                var message = new ItemEventMessage(this, data);
                this.EventChannel.Publish(message);
            }
    

    base.Move() calls OnMove().
    OnMove sends ItemMoved with this.Rotation, but this.Rotation is set AFTER base.Move :!:
    Then you send another ItemMoved after Move: duplicate event.

    :arrow: Fix: remove the complete OnMove() override
  • Boris
    Boris ✭✭
    oh and then there is another one: OldPosition = this.Position is actually the new position.

    fixed version:
     public void Move(Vector newPosition, Vector rotation, Reliability reliability)
            {
                var oldPosition = this.Position;
    
                // call base move method
                this.Move(newPosition, reliability);
                this.Rotation = rotation;
    
                // send event
                var eventInstance = new ItemMoved
                {
                    ItemId = this.Id,
                    ItemType = this.Type,
                    OldPosition = oldPosition,
                    Position = newPosition,
                    Rotation = rotation
                };
    
                EventData data = eventInstance.GetEventData(
                    (byte)EventCode.ItemMoved,
                    reliability,
                    Settings.ItemEventChannel);
    
                var message = new ItemEventMessage(this, data);
                this.EventChannel.Publish(message);
            }
    

    you might want to include the old rotation in order to do a Vector3.Lerp.
  • Boris wrote:
    the code is buggy :o
    Hell yea im sure it is, 50% of the time im not even sure of what im doing, im just glad it works...
    Im still learning how the server works, Trial and error for the win! ;)
    base.Move() calls OnMove().
    OnMove sends ItemMoved with this.Rotation, but this.Rotation is set AFTER base.Move :!:
    Makes sense, i noted in the server log that the move operation was called twice, so thats why then...
    Then you send another ItemMoved after Move: duplicate event.

    :arrow: Fix: remove the complete OnMove() override

    Yep, thats why I put some comments on the code like that...
    //this is the new move method, it should handle the new movement with the rotation
    //check above the original onMove method that should be removed because its a duplicate
  • Boris
    Boris ✭✭
    zoultrex wrote:
    Yep, thats why I put some comments on the code like that...
    //this is the new move method, it should handle the new movement with the rotation
    //check above the original onMove method that should be removed because its a duplicate
    oh alright, I skipped that part when I read the code
  • Im planning on looking over all this again and make a simple step-by-step kinda how-to add rotation to the actor, in the near future, im sure it will help ppl, unless you guys plan to implement this already in one of the next releases...?
  • Boris
    Boris ✭✭
    zoultrex wrote:
    unless you guys plan to implement this already in one of the next releases...?
    yeah.. we probably should.
    The best would be to replace the mmo demo player barrel thingy with something better/more realistic where a rotation is actually needed - I'm just not good enough with the front-end stuff. So hey - if someone would like to contribute that part let me know :)
  • Boris wrote:
    zoultrex wrote:
    unless you guys plan to implement this already in one of the next releases...?
    yeah.. we probably should.
    The best would be to replace the mmo demo player barrel thingy with something better/more realistic where a rotation is actually needed - I'm just not good enough with the front-end stuff. So hey - if someone would like to contribute that part let me know :)
    You can count with me, I have the time and the will... so lets do it. Pm me if you want to exchange details.
  • Boris
    Boris ✭✭
    awesome :), check your inbox.
  • Thank you guys for your cooperation!

    I'm almost finished with this stuff on the client side too. I've decided also to send only an Y-axis angle as a rotation parameter instead of the whole array of floats, it works very nicely. Got the movement working even with animation clips ;)
  • Boris
    Boris ✭✭
    nice.. I'm dying to see it!
  • I will be posting a step by step word doc on how to add the xyz rotation tomorrow, I have just finishing implementing it and I will revise the word doc and all the steps necessary to do that to make sure its all fine, remove my debug entries, polish the codes etc...

    Im tired to do now, and pissed, spent 2 hours debugging a ridiculous typo error :x so ill get some sleep.
    Stay tuned to the post for those who are interested ;)
  • Boris wrote:
    awesome :), check your inbox.
    Your turn, check yours :)