A Simple Multiplayer Game

Hello Jmonkey users, I’ve been trying to dig at the MonkeyZone server/client but it seems to be broken. I got it right off of the Google source trunk, and still, not working with multiplayer. It seems outdated. I was wondering if anyone had a BASIC EXAMPLE of a multiplier game. I’m taking basic with no nifty, intense graphics, etc. If anyone has the source for a basic game 2 clients that are boxes moving around on the server i’ll be extremely happy. I think MonkeyZone is the worst multiplayer example imaginable and doesn’t give the user any example because there is a bunch of nonsense nifty and AI in the game. My client and server are working for my basic game, but i cannot get the messages from server (sent from client) to MOVE THE #2 CLIENT PLAYER. If anyone has a extremely basic example of 2 box clients running around on a server, that would be amazing. And please don’t tell me to re-checkout MonkeyZone, or steam multiplayer methods. It’s total bogus, i’m sorry.

BASIC MULTIPLAYER:
*2 users (boxes) moving and updating to server and client seeing the moved players
*basic, no nifty, ai, nonsense.
*basic again. and thank u, if you can post source. =)

The best networking example is the test chat client and test chat server. It shows how to send messages around, including receiving them on a server and rebroadcasting to the other clients.

Beyond that, there is no such thing as a simple example because each game will do networking a little differently. Anyone with the skill to actually write a network game (10x harder than writing a single player game) should be able to figure out how from the chat example.

It’s a hard thing to do and thus simple examples won’t really help beyond showing basic networking functionality… which is what the test chat client and test chat server do.

pspeed, i’ve read many of your answers to other users. thank you for responding. My current client and server is based off of the test-chat example. Extremely good example. Messages go Client -> Server -> Client. The only thing i’m having a problem with is how to make a new user appear (as a box) and how to get the player #2 to move and player #1 to see player #2 moving. very basic.

I will send $30 through PayPal to the first user to create a basic example of multiplayer

What is needed:

Client - player is a blue box that connects to localhost
Server - gets all player location/rotation and make multiple clients visible to each other.

A very basic multiplayer “game” that simply shows other users as boxes and updates their currently location/rotation so the other players can see them.
There needs to be a more basic multiplayer example other than MonkeyZone. test-chat is a good example, but doesn’t have player movements.

Anyone who can do it first correctly gets $30 to their PayPal pronto.

@HunterLong said: pspeed, i've read many of your answers to other users. thank you for responding. My current client and server is based off of the test-chat example. Extremely good example. Messages go Client -> Server -> Client. The only thing i'm having a problem with is how to make a new user appear (as a box) and how to get the player #2 to move and player #1 to see player #2 moving. very basic.

New client connects to server. Server sends a PlayerJoined message to all other clients. Those clients keep a list of the players that they’ve seen join. Clients send their position to the server. The server, 20 times a second, sends all player state information to every player and they join that up to the boxes they created to set their positions.

That’s about as simple as it gets.

You could also broadcast per-player state updates when you receive them but no game in its right mind would ever do networking that way. Even the simple example above will not scale over a handful of players and will not work well except on a low-latency LAN, ie: on the internet you will see latencies of up to 1 second, easily.

For proper real time game networking, I’d have to refer you back to the valve articles which you’ve already mentioned weren’t helpful. That alone is indicative that you have some learning to do before continuing as those are chock full of absolutely great information.

1 Like

Here what i have right now,

SERVER:

[java]/*

  • Copyright © 2009-2010 jMonkeyEngine
  • All rights reserved.
  • Redistribution and use in source and binary forms, with or without
  • modification, are permitted provided that the following conditions are
  • met:
    • Redistributions of source code must retain the above copyright
  • notice, this list of conditions and the following disclaimer.
    • Redistributions in binary form must reproduce the above copyright
  • notice, this list of conditions and the following disclaimer in the
  • documentation and/or other materials provided with the distribution.
    • Neither the name of ‘jMonkeyEngine’ nor the names of its contributors
  • may be used to endorse or promote products derived from this software
  • without specific prior written permission.
  • THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  • TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  • PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  • CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  • EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  • PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  • PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  • LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  • NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  • SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */

package mygame;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.network.*;
import com.jme3.network.serializing.Serializable;
import com.jme3.network.serializing.Serializer;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.system.JmeContext;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MainServer extends SimpleApplication implements ConnectionListener {

 Server server;
        
@Serializable

public static class HelloUser extends AbstractMessage {
private String m; // message data
public HelloUser() {} // empty constructor
public HelloUser(String s) { m = s; } // custom constructor

public String Location(){
return m;
}
}

    @Serializable

public static class HelloLocation extends AbstractMessage {
private String m; // message data
public HelloLocation() {} // empty constructor
public HelloLocation(String s) { m = s; } // custom constructor

public String Location(){
return m;
}
}

           @Serializable

public static class ServerListener implements MessageListener {
public void messageReceived(HostedConnection source, Message message) {
if (message instanceof HelloUser) {
// do something with the message
HelloUser helloMessage = (HelloUser) message;
System.out.println("Player: “+source.getId()+” Moved To: " +helloMessage.Location());
source.send(new HelloUser(helloMessage.Location()));
} // else…

        if (message instanceof HelloLocation) {
  // do something with the message
  HelloLocation hellolocation = (HelloLocation) message;
  System.out.println("NEW PLACED: "+source.getId()+" To: " +hellolocation.Location());
    source.send(new HelloLocation(hellolocation.Location()));
} // else....

}
}

public static void main(String[] args) throws IOException, InterruptedException{
          
          
     Application app = new MainServer();

app.start(JmeContext.Type.Headless);

    Object obj = new Object();
    synchronized (obj){
        obj.wait();
    }
    

}

public void simpleInitApp() {

  try {
        server = Network.createServer(6143);
    } catch (IOException ex) {
        Logger.getLogger(MainServer.class.getName()).log(Level.SEVERE, "Error Starting Server", ex);
    }
    server.start();
    
            
            Serializer.registerClass(HelloUser.class);
            Serializer.registerClass(HelloLocation.class);
   
                            
                    server.addMessageListener(new ServerListener(), HelloUser.class);
                    server.addMessageListener(new ServerListener(), HelloLocation.class);
                     server.addConnectionListener(this);
 
      
  }




@Override

public void simpleUpdate(float tpf) {

}


@Override
public void simpleRender(RenderManager rm) {

//TODO: add render code
}

public void connectionAdded(Server server, HostedConnection conn) {
System.out.println(“Server knows that client #”
+ conn.getId() + " is ready.");

}

public void connectionRemoved(Server server, HostedConnection conn) {
System.out.println(“Server knows that client #”
+ conn.getId() + " has left.");
}

}[/java]

MAIN CLIENT:

[java]package mygame;

import com.jme3.animation.SkeletonControl;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.audio.AudioNode;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.network.AbstractMessage;
import com.jme3.network.Client;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.serializing.Serializable;
import com.jme3.network.serializing.Serializer;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**

  • This demo shows a terrain with collision detection,
  • that you can walk around in with a first-person perspective.
  • This code combines HelloCollision and HelloTerrain.
    */
    public class Main extends SimpleApplication
    implements ActionListener {

private BulletAppState bulletAppState;
private RigidBodyControl landscape;
private CharacterControl player;
private Vector3f walkDirection = new Vector3f();
private boolean left = false, right = false, up = false, down = false, jump = false;
private Spatial terrain;
private Material mat_terrain;
Spatial sky;
Spatial gun;
CameraNode camFirstPerson;
Node playerNode;
Material gunmat;
BitmapText helloText;
Sphere sphere;
RigidBodyControl ball_phy;
Material mat;
Material womenmat;
Spatial women;
Material treemat;
Spatial treeobj;
AudioNode audioSource;
Material blockmat;
Spatial roadblock;
RigidBodyControl roadblock_phy;
Client client;

@Serializable

public static class HelloUser extends AbstractMessage {
private String m; // message data
public HelloUser() {} // empty constructor
public HelloUser(String s) { m = s; } // custom constructor

public String Location(){
return m;
}
}

    @Serializable

public static class HelloLocation extends AbstractMessage {
private String m; // message data
public HelloLocation() {} // empty constructor
public HelloLocation(String s) { m = s; } // custom constructor

public String Location(){
return m;
}
}

@Serializable
public class ClientListener implements MessageListener {

public void messageReceived(Client source, Message message) {
if (message instanceof HelloUser) {
// do something with the message
HelloUser helloMessage = (HelloUser) message;
System.out.println(“Client #”+source.getId()+" received: ‘"+helloMessage.Location()+"’");
helloText.setText(“Client #”+source.getId()+" received: ‘"+helloMessage.Location()+"’");
} // else…

        if (message instanceof HelloLocation) {
  // do something with the message
  HelloLocation hellolocation = (HelloLocation) message;
  System.out.println("NEW PLACED: "+source.getId()+" To: " +hellolocation.Location());
 helloText.setText("New Block #"+source.getId()+" received: '"+hellolocation.Location()+"'");
} // else....

}
}

public static void main(String[] args) throws IOException, InterruptedException{
Main appclient = new Main();
appclient.start();

}

@Override
public void simpleInitApp() {

    try {
        client = Network.connectToServer("localhost", 6143);
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }

client.start();

          Serializer.registerClass(HelloUser.class);
            Serializer.registerClass(HelloLocation.class);
   client.addMessageListener(new ClientListener(), HelloUser.class);
   client.addMessageListener(new ClientListener(), HelloLocation.class);
   
  
/** Set up Physics */
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
flyCam.setMoveSpeed(100);
setUpKeys();

   cam.setFrustumFar(5000);
   cam.onFrameChange();

CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 8f, 1);
player = new CharacterControl(capsuleShape, 0.05f);
player.setJumpSpeed(50);
player.setFallSpeed(95);
player.setGravity(100);
player.setPhysicsLocation(new Vector3f(0, 100, 0));

       assetManager.registerLocator("assets/", FileLocator.class);  
       
cam.setLocation(player.getPhysicsLocation());

initCrossHairs();

gunmat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
gun = assetManager.loadModel(“Models/m4a1gun.j3o”);
gun.rotate(0.05f,3.3f,0f); // Move it a bit
gun.setLocalScale(0.6f);
gun.setLocalTranslation( -1.8f,-0.6f,4f );
gunmat.setTexture(“ColorMap”, assetManager.loadTexture(“Models/gunskin.png”));
gun.setMaterial(gunmat);
rootNode.attachChild(gun);

        playerNode = new Node("pivot");
    rootNode.attachChild(playerNode); 
    playerNode.attachChild(gun);
    
           // Display a line of text with a default font
    //guiNode.detachAllChildren();
    guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
    helloText = new BitmapText(guiFont, false);
    helloText.setSize(guiFont.getCharSet().getRenderedSize());
    helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
    guiNode.attachChild(helloText);

mat_terrain = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
terrain= assetManager.loadModel(“Scenes/newScene.j3o”);
terrain.setLocalTranslation(0,0f,0); // Move it a bit
terrain.setLocalScale(5f);
//mat_terrain.setTexture(“ColorMap”, assetManager.loadTexture(“Scenes/mpmap2.jpg”));
//terrain.setMaterial(mat_terrain);
//TangentBinormalGenerator.generate(ogre);
//rootNode.attachChild(ogre);
rootNode.attachChild(terrain);

womenmat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
women= assetManager.loadModel(“Models/max.j3o”);
women.setLocalTranslation(0,53f,0); // Move it a bit
women.setLocalScale(0.07f);
womenmat.setTexture(“ColorMap”, assetManager.loadTexture(“Models/max.tga”));
women.setMaterial(womenmat);
//TangentBinormalGenerator.generate(ogre);
//rootNode.attachChild(ogre);
rootNode.attachChild(women);

SkeletonControl skeletonControl = women.getControl(SkeletonControl.class);
//Node n = skeletonControl.getAttachmentsNode(“hand.right”);
//rootNode.attachChild(n);

treemat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
treeobj= assetManager.loadModel(“Models/palm.j3o”);
treeobj.setLocalTranslation(-10f,53f,0); // Move it a bit
treeobj.setLocalScale(0.05f);
//treemat.setTexture(“ColorMap”, assetManager.loadTexture(“Models/max.tga”));
treeobj.setMaterial(treemat);
//TangentBinormalGenerator.generate(ogre);
//rootNode.attachChild(ogre);
rootNode.attachChild(treeobj);

// object of THE SPHERE BACKGROUND OF STARS
    mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");        
    mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Front);
Sphere thesky = new Sphere(128,128, 900f);
sky = new Geometry("AllSky", thesky);
//sky.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
mat.setTexture("ColorMap", assetManager.loadTexture("Textures/sky.jpg"));
//mat.setTexture("NormalMap", assetManager.loadTexture("Textures/stars.png"));
sky.setMaterial(mat);
sky.setLocalTranslation(0,0,0); // Move it a bit
sky.rotate(0, 0, 0);          // Rotate it a bit
rootNode.attachChild(sky);

AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(al);

sphere = new Sphere(32, 32, 0.2f, true, false);
sphere.setTextureMode(Sphere.TextureMode.Projected);


audioSource = new AudioNode(assetManager, "Sounds/gun.wav", false);
audioSource.setLooping(false);

/** 6. Add physics: */ 
// We set up collision detection for the scene by creating a
// compound collision shape and a static RigidBodyControl with mass zero.*/
CollisionShape terrainShape = CollisionShapeFactory.createMeshShape((Spatial) terrain);
landscape = new RigidBodyControl(terrainShape, 0);
terrain.addControl(landscape);



// We attach the scene and the player to the rootnode and the physics space,
// to make them appear in the game world.
bulletAppState.getPhysicsSpace().add(terrain);
bulletAppState.getPhysicsSpace().add(player);

}
/** We over-write some navigational key mappings here, so we can

  • add physics-controlled walking and jumping: */
    private void setUpKeys() {
    inputManager.addMapping(“Left”, new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping(“Right”, new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping(“Up”, new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping(“Down”, new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping(“Jump”, new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addMapping(“Shoot”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addMapping(“Place”, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
    inputManager.addMapping(“PlaceView”, new KeyTrigger(KeyInput.KEY_E));
    inputManager.addListener(this, “Left”);
    inputManager.addListener(this, “Right”);
    inputManager.addListener(this, “Up”);
    inputManager.addListener(this, “Down”);
    inputManager.addListener(this, “Jump”);
    inputManager.addListener(actionListener, “Shoot”);
    inputManager.addListener(actionListener, “Place”);
    inputManager.addListener(actionListener, “PlaceView”);
    }

/** These are our custom actions triggered by key presses.

  • We do not walk yet, we just keep track of the direction the user pressed. */
    public void onAction(String binding, boolean value, float tpf) {

    String type;

if (binding.equals("Left")) {
  if (value) { left = true; } else { left = false; }
} else if (binding.equals("Right")) {
  if (value) { right = true; } else { right = false; }
} else if (binding.equals("Up")) {
  if (value) { up = true; } else { up = false; }
} else if (binding.equals("Down")) {
  if (value) { down = true; } else { down = false; }
} else if (binding.equals("Jump")) {
    if (value) { jump = true; } else { jump = false; }
  player.jump();
}

}

   public void makeNewUser() {
/** Create a cannon ball geometry and attach to scene graph. */
Geometry ball_geo = new Geometry("cannon ball", sphere);
ball_geo.setMaterial(mat);
rootNode.attachChild(ball_geo);
/** Position the cannon ball  */
ball_geo.setLocalTranslation(cam.getLocation());
ball_geo.setLocalRotation( cam.getRotation() );
/** Make the ball physcial with a mass > 0.0f */
ball_phy = new RigidBodyControl(1f);
/** Add physical ball to physics space. */
ball_geo.addControl(ball_phy);
bulletAppState.getPhysicsSpace().add(ball_phy);

}

 public void makeCannonBall() {
/** Create a cannon ball geometry and attach to scene graph. */
Geometry ball_geo = new Geometry("cannon ball", sphere);
ball_geo.setMaterial(mat);
rootNode.attachChild(ball_geo);
/** Position the cannon ball  */
ball_geo.setLocalTranslation(cam.getLocation());
ball_geo.setLocalRotation( cam.getRotation() );
/** Make the ball physcial with a mass > 0.0f */
ball_phy = new RigidBodyControl(0.7f);
/** Add physical ball to physics space. */
ball_geo.addControl(ball_phy);
bulletAppState.getPhysicsSpace().add(ball_phy);
/** Accelerate the physcial ball to shoot it. */
ball_phy.setLinearVelocity(cam.getDirection().mult(1500));
audioSource.playInstance();

}

      public void makeRoadBlock(Vector3f pt) {

blockmat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
roadblock= assetManager.loadModel(“Models/roadblock.j3o”);
blockmat.setTexture(“ColorMap”, assetManager.loadTexture(“Models/roadblocktexture.tga”));
//blockmat.setTexture(“NormalMap”, assetManager.loadTexture(“Models/roadblock.tga”));
roadblock.setMaterial(blockmat);
roadblock.setLocalScale(2f);
rootNode.attachChild(roadblock);
roadblock.setLocalTranslation(pt);
//roadblock.setLocalRotation( cam.getRotation() );
/** Make the ball physcial with a mass > 0.0f /
roadblock_phy = new RigidBodyControl(1000f);
/
* Add physical ball to physics space. /
roadblock.addControl(roadblock_phy);
roadblock_phy.setMass(1000f);
roadblock_phy.setFriction(1000f);
bulletAppState.getPhysicsSpace().add(roadblock_phy);
/
* Accelerate the physcial ball to shoot it. */
//roadblock_phy.setLinearVelocity(cam.getDirection().mult(0));
audioSource.playInstance();
}

/** A centred plus sign to help the player aim. */
protected void initCrossHairs() {
//guiNode.detachAllChildren();
guiFont = assetManager.loadFont(“Interface/Fonts/Default.fnt”);
BitmapText ch = new BitmapText(guiFont, false);
ch.setSize(guiFont.getCharSet().getRenderedSize() * 1);
ch.setText("+"); // crosshairs
ch.setLocalTranslation( // center
settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
guiNode.attachChild(ch);
}

private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals(“Shoot”) && !keyPressed) {
makeCannonBall();
CollisionResults hitresults = new CollisionResults();
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
women.collideWith(ray, hitresults);

     for (int i = 0; i < hitresults.size(); i++) {
      // For each hit, we know distance, impact point, name of geometry.
      float dist = hitresults.getCollision(i).getDistance();
      Vector3f pt = hitresults.getCollision(i).getContactPoint();
      String hit = hitresults.getCollision(i).getGeometry().getName();
      helloText.setText("  You shot " + hit + " at " + pt + ", " + dist + " wu away.");
    }
  }
     
    if (name.equals("Place") && !keyPressed) {
        
     CollisionResults placing = new CollisionResults();
     Ray placeray = new Ray(cam.getLocation(), cam.getDirection());
     terrain.collideWith(placeray, placing);     
     for (int i = 0; i < placing.size(); i++) {
      // For each hit, we know distance, impact point, name of geometry.
      float dist = placing.getCollision(i).getDistance();
      Vector3f pt = placing.getCollision(i).getContactPoint();
      String hit = placing.getCollision(i).getGeometry().getName();
      helloText.setText("  You PLACED " + hit + " at " + pt + ", " + dist + " wu away.");
      if (dist<50){
     Message message = new HelloLocation(""+pt);
     client.send(message);
           makeRoadBlock(pt);
      } else { }
  
    }
    }
             if (name.equals("PlaceView") && !keyPressed) {
                 
               }
   
      //helloText.setText("You placed a Road Block");              
      
    }

};

@Override
public void simpleUpdate(float tpf) {

        Vector3f mylocation = player.getPhysicsLocation();
        
Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
walkDirection.set(0, 0, 0);
if (left)  { 
    walkDirection.addLocal(camLeft);
         Message message = new HelloUser(""+mylocation);
     client.send(message);}
if (right) { 
    walkDirection.addLocal(camLeft.negate());
         Message message = new HelloUser(""+mylocation);
     client.send(message);
}
if (up)    { 
    walkDirection.addLocal(camDir);
         Message message = new HelloUser(""+mylocation);
     client.send(message);}
if (down)  { 
    walkDirection.addLocal(camDir.negate());
         Message message = new HelloUser(""+mylocation);
     client.send(message);
}
    if (jump)  { 
         Message message = new HelloUser(""+mylocation);
     client.send(message);
}
player.setWalkDirection(walkDirection);
cam.setLocation(player.getPhysicsLocation());
playerNode.setLocalRotation( cam.getRotation() );
playerNode.setLocalTranslation(cam.getLocation()); // Move it a bit




        //helloText.setText("Your Position: "+cam.getLocation());

}

}[/java]

On SpiderMonkey tutorial, there is "… myClient.getId() …". Now how do I get the player ID, and use the player ID to move that ONE user. myClient.getId() .rotate(0,0,0) (EXAMPLE) how can i use that to change player movement.

Make the player ID part of the message that you send from the server. Then on the clients, keep a Map<PlayerId, Spatial> or whatever.

I will repeat that networked games are the hardest kinds of games to write. If you are getting tripped up at this stage then you may not be at the right skill level yet. There are 100 harder things to deal with after you get this working.

See… because let’s say we spend the next 8 or so hours working you step by step through getting this simple example to work. Then the next thing is “Why are my boxes moving so jerky?” And then we are back to the Valve articles, interpolation, server-side state tracking, etc., etc.

2 Likes

I know you must repeat yourself a ton pspeed. I’m sorry. jMonkey is a great engine, and your support is great. Jerkyness is fine, ill figure that out later. Ok, so lets so i pass the player id as a string through the message, how do i use the playerid to move THAT player.

You do not need to use strings for everything. You can use ints, floats, Vector3fs, whatever.

As I said, keep a java.util.Map on each client that tracks which box belongs to which player ID. When a new message comes in, look up the box for that player ID and move it.

I can’t break it down any simpler than that.

1 Like
@HunterLong said: Hello Jmonkey users, I've been trying to dig at the MonkeyZone server/client but it seems to be broken. I got it right off of the Google source trunk, and still, not working with multiplayer. It seems outdated. I was wondering if anyone had a BASIC EXAMPLE of a multiplier game. I'm taking basic with no nifty, intense graphics, etc. If anyone has the source for a basic game 2 clients that are boxes moving around on the server i'll be extremely happy. I think MonkeyZone is the worst multiplayer example imaginable and doesn't give the user any example because there is a bunch of nonsense nifty and AI in the game. My client and server are working for my basic game, but i cannot get the messages from server (sent from client) to MOVE THE #2 CLIENT PLAYER. If anyone has a extremely basic example of 2 box clients running around on a server, that would be amazing. And please don't tell me to re-checkout MonkeyZone, or steam multiplayer methods. It's total bogus, i'm sorry.

BASIC MULTIPLAYER:
*2 users (boxes) moving and updating to server and client seeing the moved players
*basic, no nifty, ai, nonsense.
*basic again. and thank u, if you can post source. =)

You don’t understand the MZ code, you cannot setup a simple networking connection, still you deduce such general opinions and demands. How do you think anyone could see a chance or even reason to help you? If a complete game example and extensive docs by experts of the matter don’t suffice for you I doubt anyone here can help you.

If you don’t like mz why not just write your own? It#s not like you are forced to use the stuff offerd by others in their freetime, but a normal dicussion instead of random ranting would be preferred.

norman, have you seen the source for MonkeyZone? lol That isn’t a multiplayer example. It’s a mess of an example, and won’t even support multiple users. Any multiplayer example, other than MonkeyZone and test-chat (great example) should be an example for jmonkey. Notice how test-chat doesn’t have nifty gui, AI, or any other nonsense/pointless classes that wont work.

Simply, jMonkey needs a better example of PLAYER multiplayer.

I wrote MonkeyZone so I do know the code, yeah ^^ And it does support multiple logins into the server just fine. Did you read the documentation for it in the wiki? The networking classes for the entities are a bit convoluted as I tried to make it easy for me by using java inheritance but that never is a good idea except you write Swing :wink:

Also, if you had in mind to do some other type of game you’d demand an exact example of that so I guess you’re the wrong guy at the wrong time ^^ MZ is too big, the chat example too small, you don’t want to learn using the docs we all used to learn… You really want to say we and our documentation and examples are the problem in this?

@HunterLong

You are asking for a simple example - but there is no such thing. Networking a game is not and never will be simple. We aren’t just telling you that to be awkward or keep you out of some super secret club. It’s hard. Even if we dressed things up in a simple example by making that example simple we would strip out all the stuff that makes it actually work in a real-world scenario.

normen, i’ve been using the documentation and it’s actually very good. The examples are perfect, expect for MZ. Currently, i run MZ server (both localhost and remote IP) and then I try to connect 2 clients, 1st one is fine, but then 2nd one cannot connect and the server is sending logs left and right about errors. I didn’t edit the MZ code, I am just trying to run it with multiple users. It doesn’t work, sadly. The niftygui also does not show online users and the chat doesn’t work. Most of MonkeyZone is broken.

I know client/server is extremely hard with java/jMonkey. But if there was an example of 2 clients moving on 1 server, that would help all other jmonkey users. I’m even offering $30 to PayPal. It can’t be THAT HARD, becuase my source above sends messages to and from client/server. I just need a push with actually moving those characters on the server then to the other clients. A message instance example that moves characters.

“logs left and right” huh? Can you be any more specific? 30$ is ridiculous for a programmer (or any service professional). Why not spend that money on a book on networking in games? :slight_smile:

1 Like
@HunterLong said: norman, have you seen the source for MonkeyZone? lol That isn't a multiplayer example. It's a mess of an example, and won't even support multiple users. Any multiplayer example, other than MonkeyZone and test-chat (great example) should be an example for jmonkey. Notice how test-chat doesn't have nifty gui, AI, or any other nonsense/pointless classes that wont work.

Simply, jMonkey needs a better example of PLAYER multiplayer.

As I have repeated examples of this, I can safely say that anyone with the skills to write a networked game can figure out how to use SpiderMonkey to do it just by looking at the test chat client and server.

This isn’t a “how do I learn SpiderMonkey” problem but a “how do I learn to write a networked game” problem. There are entire books on that subject. The chat example is only one message type away from being able to crappily move things around on the screen. This is a simple step to take… trivial by most standards. Just send the positions with the ID of the player. Easy… and much uglier than you imagine it will be.

The issue then comes that if you want to write an actual networked game, none of that is reusable. You throw it ALL away and start over with a proper synched object system. The Valve articles are then the next step. If you don’t understand the Valve articles then you will not succeed. It is that simple.

I will include them here for other readers that may stumble onto this thread:
https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization

When you understand those, how to implement the most basic parts of them, and what the trade offs are for doing that… then you will be ready to write a real time networked game. Until then, no simple example will help unless we wrote you a full object synch system.

I’m saying $30 to any user because IM SURE there’s gotta be a user that has done this before.

@HunterLong said: I'm saying $30 to any user because IM SURE there's gotta be a user that has done this before.

Why would they? It’s useless code otherwise, ie: it’s 100% throw-away when you actually make a game.

But good luck. Maybe there is someone who works cheap.