This page has been translated automatically.
UnigineScript
The Language
Core Library
Engine Library
Node-Related Classes
GUI-Related Classes
Plugins Library
Samples
C++ API
API Reference
Integration Samples
Usage Examples
C++ Plugins
Content Creation
Materials
Unigine Material Library
Tutorials
Warning! This version of documentation is OUTDATED, as it describes an older SDK version! Please switch to the documentation for the latest SDK version.
Warning! This version of documentation describes an old SDK version which is no longer supported! Please upgrade to the latest SDK version.

Running Syncker for a Custom Project

To use Syncker most efficiently from the point of view of performance, selective synchronization of nodes and materials is needed. This is possible if Syncker is run from a script (and it does not matter if it will be a world, editor or a custom system one) for full control over synchronization.

Notice
If you use projectors to render your application, see the article on Running Syncker with AppProjection.

Script Implementation

To run Syncker from the world script of a custom project, to synchronize nodes, render parameters and the player over the network, implement your script according to instructions below. Notice that similar logic is used to synchronize materials.

  1. First of all, initialize Syncker in the script that is run on the master computer. Also you should initialize a console to enable the ability of running master command-line options. To synchronize creation of a node on all connected slaves, use the Unigine::Syncker::Master::createNode() function.
    Source code (UnigineScript)
    // my_project.cpp on a master computer
    
    #include <core/unigine.h>
    #include <core/systems/syncker/syncker_master.h>
    #include <core/systems/syncker/syncker_master_console.h>
    
    // It is more efficient to serialize nodes stored in an array and pass them as
    // one packet instead of sending them one by one.
    ObjectMesh meshes[0];
    
    int init() {
    	
    	// Set a fixed FPS value to make simulations consistent across all computers.
    	engine.game.setFTime(1.0f / 60.0f);
    	
    	// Initialize master console
    	Unigine::Syncker::Master::Console::init();
    	
    	// Initialize Syncker using a given broadcast address.
    	Unigine::Syncker::Master::init(master_address);
    	
    	PlayerSpectator camera = new PlayerSpectator();
    	camera.setPosition(Vec3(2.0f,0.0f,1.5f));
    	camera.setDirection(Vec3(-1.0f,0.0f,-0.5f));
    	engine.game.setPlayer(camera);
    	
    	// Fill the world with meshes that will be synchronized.
    	for(int j = 0; j < 2; j++) {
    			for(int i = 0; i < 2 - j; i++) {
    				// you can specify the path to any other mesh
    				ObjectMesh mesh = node_remove(new ObjectMesh("my_project/meshes/box.mesh"));
    				engine.editor.addNode(mesh);
    				mesh.setMaterial("mesh_base","*");
    				mesh.setProperty("surface_base","*");
    				mesh.setPosition(Vec3(i,j,j));
    				// Synchronize creation of the mesh on all slaves
    				Unigine::Syncker::Master::createNode(mesh);
    				meshes.append(mesh);
    			}
    		}
    	
    	return 1;
    }
    
  2. Implement logic, which allows loading the world for all of the slaves on the master side, and call it in the init() function after the Syncker initialization.
    Notice
    You can skip this step and load the world on each slave individually.
    Source code (UnigineScript)
    void sync_world() {
    	
    	// load slave world
    	Unigine::Syncker::Master::systemCall(~0,"engine.console.run",("world_load " + engine.world.getName()));
    		
    	// waiting for the slave world
    	int ret[0];
    	float begin = clock();
    		
    	while(clock() - begin < 2.0f) {
    		int is_loaded = 1;
    		Unigine::Syncker::Master::systemCall(~0,"engine.world.isLoaded",(),ret);
    		foreach(int i = 0; ret) is_loaded &= i;
    		if(is_loaded) break;
    	}
    }
    					
  3. Then, specify the shutdown logic for the console and Syncker:
    Source code (UnigineScript)
    // my_project.cpp on a master computer
    
    int shutdown() {
    	
    	// Run a console command on all slave applications, if necessary.
    	// The command being called is run from a system script of slaves.
    	Unigine::Syncker::Master::systemCall(~0,"engine.console.run",("world_quit"));
    	
    	// Shut down the console
    	Unigine::Syncker::Master::Console::shutdown();
    	
    	// Shut down Syncker.
    	Unigine::Syncker::Master::shutdown();
    	
    	return 1;
    }
    
  4. And synchronization logic in the script render() function. Such logic allows you to specify all nodes (and materials, if required), which have to be synchronized. Detailed function descriptions can be found here.
    Source code (UnigineScript)
    // my_project.cpp on a master computer
    
    int render() {
    
    	// Synchronize frame information
    	Unigine::Syncker::Master::syncFrame();
    	
    	// Synchronize player position
    	Unigine::Syncker::Master::syncPlayer();
    	
    	// Synchronize render parameters
    	Unigine::Syncker::Master::syncRender();
    	
    	// Synchronize nodes
    	Unigine::Syncker::Master::syncNodes(meshes);
    	
    	// End of the frame
    	Unigine::Syncker::Master::syncEnd();
    		
    	return 1;
    }
    

If you run the same world script on the master and slave sides, you need to wrap your code around with #ifndef DEFINE_NAME ... #else ... #endif as follows:

Notice
The DEFINE_NAME should be specified on the application start-up.
Source code (UnigineScript)
#include <core/unigine.h>

// logic to run on the master
#ifndef DEFINE_NAME

	#include <core/systems/syncker/syncker_master.h>
	#include <core/systems/syncker/syncker_master_console.h>
		
		ObjectMesh meshes[0];
		
		// init() function defined above
		// shutdown() functions defined above
		// render() function defined above
		
	#else

		// logic to run on a slave
		int init() {

			PlayerSpectator camera = new PlayerSpectator();
			camera.setPosition(Vec3(2.0f,0.0f,1.5f));
			camera.setDirection(Vec3(-1.0f,0.0f,-0.5f));
			engine.game.setPlayer(camera);
			
			return 1;
		}
	
#endif
				

Running Syncker

After the script is implemented, you need to run it on the slaves and master computers as follows:

  1. Run all slave applications that will be synchronized with the master.

    For that, specify the following option on the slave application start-up to override a default editor script with the Syncker script for slaves. In case you use the same world script on the master and slave sides, specify also the required definition:

    Shell commands
    main_x86 -data_path "../" -editor_script "core/systems/syncker/syncker_slave.cpp" -extern_define "DEFINE_NAME"
    
    Do not forget to add other required start-up arguments.
  2. Load the world for each slave if you didn't implement the loading logic in the script:
    Source code
    world_load my_project/my_project
    						
    You can also perform this command on the application start-up (see the previous step):
    Shell commands
    -console_command "world_load my_project/my_project"
    						
  3. If the editor on slave applications is not loaded, load it via the following console command:
    Source code
    editor_load
    
    If you open the console, you will see that a slave application listens on two ports for packets from a master (this default values can be left unchanged):
    Output
    ---- Syncker::Slave ----
    Name: unknown
    UDP: 8890
    TCP: 8891
    				
  4. Run the my_project script on the main computer to be used as the master. After that, in the console of the connected slaves you will see the following:
    Output
    ---- Syncker::Master ----
    Address: 192.168.0.255
    UDP: 8890
    TCP: 8891
    
  5. Change the broadcasting network address of the master:
    Source code
    master_address xxx.xxx.xxx.xxx
    						
    And reload the world by using the world_reload. After that, in the master console you will see messages that slaves have connected:
    Output
    Connection to "xxx.xxx.xxx.xxx" accepted in 0.00 seconds
    						
Notice
If the world on the slaves is not loaded programmatically, console commands world_reload or world_load with the same world as currently loaded are not run on slaves after the master. Only loading of a new world works.

Configuring Displays

After launching your application on the master and slave computers, you need to configure a viewport of each slave depending on the screen configuration:

  • If your screen configuration is represented by a grid of monitors, you can simply follow the instructions specified in the Changing Screen Configuration chapter of the main article on Syncker.
  • In case your screen configuration is represented as a mesh, set it for all of the connected slaves via the master_mesh console command.
    Notice
    Make sure that the name of each mesh surface matches the name of the corresponding slave.
    Source code
    master_mesh <mesh_name>
    						
    To set the slave name, run the slave_name console command:
    Source code
    slave_name <name>
    						
Last update: 2017-07-03
Build: ()