How to synch a non-player entity between client and server

Post your help queries and engine programming questions here

How to synch a non-player entity between client and server

Postby Adam » Wed Feb 08, 2017 4:55 am

I'm new to Isogenic, and have a fairly basic question: what is the best way to create an entity (not a player) in a multiplayer game, and have it updated on the client when I make changes to it on the server?

I have started from the 24.2-multiplayer example. I've created an entity with its own class, based on the example's Player entity. I can instantiate and mount this on the client, but the entity's tick method never seems to be executed on the server, only on the client. Code is below.

Do I need to define events in ClientNetworkEvents and ServerNetworkEvents to handle synchronization of this entity between client and server, or to tell the server to synch this entity?

If so, is there an example I should look at?

Thanks for your help, and let me know if there's any more info I can provide.

Adam


Code:
gameClasses/SwarmEye.js
Code: Select all
var SwarmEye = IgeEntity.extend({
   classId: 'SwarmEye',

   init: function () {
      IgeEntity.prototype.init.call(this);

      var self = this;

      this.drawBounds(false);

      if (ige.isClient) {
         self.texture(ige.client.textures.eye)
         .width(40)
         .height(40);
      }


      // Define the data sections that will be included in the stream
      this.streamSections(['transform', 'score']);

   },

   /**
    * Override the default IgeEntity class streamSectionData() method
    * so that we can check for the custom1 section and handle how we deal
    * with it.
    * @param {String} sectionId A string identifying the section to
    * handle data get / set for.
    * @param {*=} data If present, this is the data that has been sent
    * from the server to the client for this entity.
    * @return {*}
    */
   streamSectionData: function (sectionId, data) {
      // Check if the section is one that we are handling
      if (sectionId === 'score') {
         // Check if the server sent us data, if not we are supposed
         // to return the data instead of set it
         if (data) {
            // We have been given new data!
            this._score = data;
         } else {
            // Return current data
            return this._score;
         }
      } else {
         // The section was not one that we handle here, so pass this
         // to the super-class streamSectionData() method - it handles
         // the "transform" section by itself
         return IgeEntity.prototype.streamSectionData.call(this, sectionId, data);
      }
   },

   /**
    * Called every frame by the engine when this entity is mounted to the
    * scenegraph.
    * @param ctx The canvas context to render to.
    */
   tick: function (ctx) {
      /* CEXCLUDE */
      if (ige.isServer) {
      // Code in here doesn't seem to ever get executed
         this.translateBy(0,-1,0);
      }
      /* CEXCLUDE */

      if (ige.isClient) {
       // Code in here does get executed
      }

      // Call the IgeEntity (super-class) tick() method
      IgeEntity.prototype.tick.call(this, ctx);
   }
});

if (typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = Player; }


client.js:
(entity is instantiated after scene is created)
Code: Select all
var Client = IgeClass.extend({
   classId: 'Client',

   init: function () {
      //ige.timeScale(0.1);
      ige.addComponent(IgeEditorComponent);

      // Load our textures
      var self = this;

      // Enable networking
      ige.addComponent(IgeNetIoComponent);

      // Implement our game methods
      this.implement(ClientNetworkEvents);

      // Create the HTML canvas
      ige.createFrontBuffer(true);

      // Load the textures we want to use
      this.textures = {
         //ship: new IgeTexture('./assets/PlayerTexture.js')
       ship: new IgeTexture('assets/particles/star1.png'),
      eye: new IgeTexture('assets/particles/glow.png')
      };

      ige.on('texturesLoaded', function () {
         // Ask the engine to start
         ige.start(function (success) {
            // Check if the engine started successfully
            if (success) {
               // Start the networking (you can do this elsewhere if it
               // makes sense to connect to the server later on rather
               // than before the scene etc are created... maybe you want
               // a splash screen or a menu first? Then connect after you've
               // got a username or something?
               ige.network.start('http://localhost:2000', function () {
                  // Setup the network command listeners
                  ige.network.define('playerEntity', self._onPlayerEntity); // Defined in ./gameClasses/ClientNetworkEvents.js

                  ige.network.define('eyeEntity', self._onEyeEntity); // Defined in ./gameClasses/ClientNetworkEvents.js

                  // Setup the network stream handler
                  ige.network.addComponent(IgeStreamComponent)
                     .stream.renderLatency(80) // Render the simulation 160 milliseconds in the past
                     // Create a listener that will fire whenever an entity
                     // is created because of the incoming stream data
                     .stream.on('entityCreated', function (entity) {
                        self.log('Stream entity created with ID: ' + entity.id());

                     });

                  self.mainScene = new IgeScene2d()
                     .id('mainScene');

                  // Create the scene
                  self.scene1 = new IgeScene2d()
                     .id('scene1')
                     .mount(self.mainScene);

                  self.uiScene = new IgeScene2d()
                     .id('uiScene')
                     .ignoreCamera(true)
                     .mount(self.mainScene);

                  // Create the main viewport and set the scene
                  // it will "look" at as the new scene1 we just
                  // created above
                  self.vp1 = new IgeViewport()
                     .id('vp1')
                    .addComponent(IgeMousePanComponent) // Added
                    .mousePan.enabled(true) // Added
                     .autoSize(true)
                     .scene(self.mainScene)
                     .drawBounds(false)
                    .drawMouse(true)  // Added
                     .mount(ige);

                  // Define our player controls
                  //ige.input.mapAction('left', ige.input.key.left);
                  //ige.input.mapAction('right', ige.input.key.right);
                  //ige.input.mapAction('thrust', ige.input.key.up);
                  ige.input.mapAction('north', ige.input.key.up); // Added
                  ige.input.mapAction('south', ige.input.key.down); // Added
                  ige.input.mapAction('east', ige.input.key.right); // Added
                  ige.input.mapAction('west', ige.input.key.left); // Added

                  // Ask the server to create an entity for us
                  ige.network.send('playerEntity');

            self.eye = new SwarmEye()
             .streamMode(1)
             .mount(self.scene1)
             .translate().x(20);

                  // Ask the server to create an entity for us
                  ige.network.send('eyeEntity');

                  // We don't create any entities here because in this example the entities
                  // are created server-side and then streamed to the clients. If an entity
                  // is streamed to a client and the client doesn't have the entity in
                  // memory, the entity is automatically created. Woohoo!

                  // Enable console logging of network messages but only show 10 of them and
                  // then stop logging them. This is a demo of how to help you debug network
                  // data messages.
                  ige.network.debugMax(20); // Changed from 10
                  ige.network.debug(true);

                  // Create an IgeUiTimeStream entity that will allow us to "visualise" the
                  // timestream data being interpolated by the player entity
                  self.tsVis = new IgeUiTimeStream()
                     .height(140)
                     .width(400)
                     .top(0)
                     .center(0)
                     .mount(self.uiScene);

                  self.custom1 = {
                     name: 'Delta',
                     value: 0
                  };

                  self.custom2 = {
                     name: 'Data Delta',
                     value: 0
                  };

                  self.custom3 = {
                     name: 'Offset Delta',
                     value: 0
                  };

                  self.custom4 = {
                     name: 'Interpolate Time',
                     value: 0
                  };

                  ige.watchStart(self.custom1);
                  ige.watchStart(self.custom2);
                  ige.watchStart(self.custom3);
                  ige.watchStart(self.custom4);
               });
            }
         });
      });
   }
});

if (typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = Client; }

Adam
 
Posts: 3
Joined: Sun Feb 05, 2017 1:31 am

Re: How to synch a non-player entity between client and serv

Postby rob » Sat Feb 25, 2017 1:11 pm

Hi ya.

You are instantiating the entity on the client rather than on the server. This is why the server never sees it or updates it. You need to create entities on the server that will exist on the server-side simulation, then they get streamed to the client. The only things clients should directly instantiate should be things that only exist on that individual client - like scenes, UI bits etc.
CEO & Lead Developer
Irrelon Software Limited
http://www.isogenicengine.com
User avatar
rob
Site Admin
 
Posts: 316
Joined: Tue Oct 22, 2013 5:08 pm


Return to Help & Questions

Who is online

Users browsing this forum: No registered users and 1 guest
cron