How to create different levels for a client and a server

Hi!.

I’m very new at networking and I’m trying to make my first multiplayer game.

What I wanna do is a version of my single player where theclient is playing and the server can control some factors of the client’s game in real time.

I’ve based on the tutorial of the official site named:“MultiplayerTutorial”.

What I want is that in the initial menu where I choose the type of connection and then if I’m the server or not, (and the same for the client’s version) each one goes to one different level: client version starts to play the game and server’s version starts in a different level, where he receives the “in progress” game and has some buttons where to control some aspects of the client game.

If found with some troubles:
a).-How to deal with the different scene/level for both “players”: server and client.

function OnGUI ()
{
// When network is running (server or client) then display the level “StarTrooper”
if (Network.peerType != NetworkPeerType.Disconnected)
{
if (GUI.Button(new Rect(350,10,100,30),“juega”))
{
// Make sure no old RPC calls are buffered and then send load level command
Network.RemoveRPCsInGroup(0);
Network.RemoveRPCsInGroup(1);
// Load level with incremented level prefix (for view IDs)
if (Network.isServer)
{
networkView.RPC( “LoadLevel”, RPCMode.AllBuffered, “globo_server”,lastLevelPrefix + 1);
}
else
{
networkView.RPC( “LoadLevel”, RPCMode.AllBuffered, “globo”,lastLevelPrefix + 1);
}
}
}
}

And the problem is that when I run my editor “server” version and my webclient version and the first initiates a server and the second joins to the server as a client it returns me and error which says:

Level ‘globo’ (-1) couldn’t be loaded because it has not been added to the build settings.
To add a level to the build settings use the menu File->Build Settings…
UnityEngine.Application:LoadLevel(String)
$:MoveNext() (at Assets/Scripts/NetworkLevelLoad.js:40)
I tried to differenciate whether the player is a server or not and still is looking for the level I eliminated/changed for the building of the client version of my game when I click on the button “NameOfMyGame” (which calls to the scene/level of the single player version of my game)…

I think that what’s happening is that I can’t differenciate a version for the client and a version for the server and always are trying to execute the same levels and version of the game.

I want that when I execute my server version appears to me a level/scene with some buttons to control the game of the client version, which consists of a complete different scene/level where the action of the game takes place. The idea is that the server should can control some parameters and aspects of the client’s version game in real time via some buttons. But the first step is to connect them with different scenes/levels.

Anyway, I’ve added a script which trough a button in the scene of the server tries to disable a massive instantiation which occurs during all the game of the client game and it doesn’t work. the way I try to do this is adding a condition via an “if” sentence before the instantiation which depends on a global variable I created for this purpose.

How can I solve my both problems?.

Thank you in adavance.

That won’t work with Unity’s networking, client and server need to be in the same scene.
You could let the 2 instances be a server but then you can’t send packets from one server to the other.

So, what would you recommend me to do?. I’ve got clear what I want but I don’t know how to implement this. Because if I build two list of levels different for client and server version I can’t use them in the Unity’s Network.

Should I use one of the recommended servers for my case?. (Servers like Photon o Smart Fox)

Thank you.

Yes, SmartFox and alike have a room architecture where you can have a different scene per room for example.

Is it free?. I have to pay anything for use it?

Smartfox has a community edition which is free up to 100 users, but if you need more users then you need to purchase a license with them. The other solutions have similar options. You just need to evaluate them based on your needs.

I don’t understand you. My idea is: create a game in which one player starts to play in an scenario, in a forest, and there’s a “super-user” in other PC who controls certain parameters like the difficulty level and others. It’s strange that something so simple can’t be managed byself Unity: only two players but in different scenarios. I think I’m gonna start to study SmartFox… :frowning:

I think that the question is that I’ve got to create the same compilation, to build the same levels for both client and server and then I’ve got to segregate them for each one if I want different scenarios for each one via code through the instructions isClient or isServer. But I think that yes, I can do this and I don’t need a MMO server for something so simple.

Nope, try it out. It will never work.

I can connect a server and a client but I’m trying to access from the server version to some script in the client version and disable it via pressing a button and I’ve got the message:

NullReferenceException
UnityEngine.GameObject.GetComponent (System.String type) (at C:/BuildAgent/work/6bc5f79e0a4296d6/Runtime/ExportGenerated/Editor/BaseClass.cs:185)
Botones_menu.OnGUI () (at Assets/Scripts/Botones_menu.js:10)
It seems that can find the object but not the component (the script).

How can I access to the script or to a component from a server to a client or viceversa?. Has it be done via RPC for being through the Unity’s nertwork?

Maybe like this?:

    var go = GameObject.Find("Generator");
    print("object found");
    go.GetComponent("script_name");
    print("script_accessing");

All if I suppose that it’s possible.

you seem to be thinking that your scene is shared with all the players which isn’t the case. so again… it will never work like that.
read up on Unity’s networking, your wasting your time.

Thanks for your interest and advices: I was trying to do this from the server version of my game:

function OnGUI () {
if (GUI.Button(new Rect(500,500,250,20),“turn_off_the_script”))
print(“click_on_the_button”);
networkView.RPC (“off”, RPCMode.All);
print(“llamo a la función”);
}

@RPC
function off ()
{
var go = GameObject.Find(“Generator”);
print(“object_found”);
go.GetComponent(“script_to_turn_off”).enabled=false;
print(“script_turned_off”);
}

But unfortunatelly I received the next error message:

NullReferenceException
UnityEngine.GameObject.GetComponent (System.String type) (at C:/BuildAgent/work/6bc5f79e0a4296d6/Runtime/ExportGenerated/Editor/BaseClass.cs:185)
Botones_menu.deshabilita_lluvia () (at Assets/Scripts/Botones_menu.js:23)
UnityEngine.NetworkView:RPC(String, RPCMode, Object[ ])
Botones_menu:OnGUI() (at Assets/Scripts/Botones_menu.js:15)

This is because it can’t found the component/script I wanna change as an initial test.

Maybe you’ve got the reason…Maybe it’s the first time I write a RPC…Or maybe I’m not so good programming at Unity3D.

(I’ve built both projects with the same levels but in the code I select one level or another for server and client: it’s hard for me to believe that Unity can’t do this simple thing! ).

Any help?. (Apart of my good friend Appels . (Thank you again Appels, sincerely)

I’ve modified the receivers of my RPC: from “All” to “Others” and I don’t receive any error message but, still doesn’t work. :-(.

It doesn’t print any of my debugging “prints” so, It doesn’t entry in teh RPC function…:frowning:

AARRGGHHH. :frowning:

Sorry to jump in, and in advance, I might not fully understand your needs, but couldn’t you have the server and the client be on the same scene? And just activate or deactivate game objects?

If you have a game object called “Server”, and inside it you have everything for the server: terrain, objects, etc.
Another object called “Client”, and inside it you have the full hierarchy of the client: terrain, objects, etc.

Then, as the scene loads, you check if you’re the client or the server (Network.isServer), and deactivate (SetActiveRecursively) the corresponding game object?

Or, you could have them both interacting in the same scene and use camera layering to present two different scenarios for each player (the same could be achieved by having two worlds at different coordinates from each other).

I’m merely thinking of the scene as the entire universe you’re allowed to play on, so you have to sub-divide it in worlds. Actually, the Unity project is the Universe, and each Scene could be a world, but you can make that distinction.

I hope that helps!

Also, just to clarify (I think I understand what you’re asking), you can have the server on one scene and the clients on another.

It’s perfectly possible if that’s what you need.

This was what I was needding…But I’ve solved it with some conditions in the “main camera” and “first person controller” like “if (Network.isServer”)" when we have to llok via the related scripts in these GameObjects I’m talking about.

I based my solution in the tutorial “The zero To Hero Guide” . Here they demonstrate how to do this: the same scene for both!.

But the problem now is when I want to destroy an object in this scheme. I know how to instantiate objects in order that both “players” watch them but I don’t know how to destroy them after the right instantiation. I haven’t still needed any RPC. I say this because I suppose that It’s not necessary to destroy the buffered RPCs…

Any suggestion?

Thank you very much.

I can paste my code:
var rainbow:GameObject;
var rainbow_sound: AudioClip;

private var activate_rainbow:boolean=false;

var timer : float = 2;

function Awake () {
timer = Time.time;
}
function Update () {

//Called on the server only
if(Network.isServer)
{

if (global_counter.activate_rainbow==true)
{
var myNewTrans : Transform = Network.Instantiate(rainbow, transform.position, transform.rotation,0) as Transform;
global_counter.activate_rainbow=false;
//Get the networkview of this new transform

var newObjectsNetworkview : NetworkView = myNewTrans.networkView;

//Network.Destroy(myNewTrans,10);
if (Time.time - timer > 2)
{
Network.Destroy(gameObject);
}
}
}
}

Any idea of which is the sentences that I need to complete the right destruction of my instantiated objects through the network?

Thank you very much.

A couple of things from what I see:

  1. You seem to be using the same variable “timer” for two different things: getting the moment when something happened, and holding the amount of time you should wait. I can see you got it from the Unity’s documentation. What you’re doing is not coded wrong in terms of work, but might lead to confusions (you’re setting the default value of “timer” to 2 and that will have no effect whatsoever on the code). Use two variables for this kind of things, like so:
    var timerStart : float; // this will hold the Time.time value, so it will hold the moment when something happened
    var timerDelay : float = 2.0; // this will be the amount of seconds you want to wait

Then, use timerStart = Time.time on your Awake function.
And your “if” that checks if the object should be destroyed should look something like:
if (Time.time - timerStart > timerDelay)

  1. You’re checking if you should destroy the object inside the activate_rainbow “if” statement. Therefore, the timer check will only be executed the first time the activate_rainbow is true, since you set it to false right after that. Try putting the whole “if (Time.time - […]” outside the actiavate_rainbow “if” statement, so it’s executed on every frame on Update().

The Network.Destroy() you’re using is the correct way.

Let me know if this helps.

Oh, I’ve got to try your idea right now!!..I can’t wait to try your idea!!..I’m nervous…Oh my god…I will tell you in a moment…Let me see…

I’m not sure if it’s sarcastic or not :slight_smile:

If it’s not, I really like your enthusiasm.

If it is, not sure why.

Hi!.

You idea didn’t work for me. :frowning:

I’ve tried this code:

var rainbow:GameObject;
var rainbow_sound: AudioClip;

private var activate_rainbow:boolean=false;

private var timerStart : float;
var timerDelay : float = 5;

private var tiempo: float=0;

function Awake () {
timerStart = Time.time;
}

function Update ()
{

print(Time.time);

if(Network.isServer)
{

if (global_counter.activate_rainbow==true)
{

print(“enter_activate_rainbow”);
var myNewTrans : Transform = Network.Instantiate(rainbow, transform.position, transform.rotation,0) as Transform;
print(“instanciated”);
Contador_global.activate_arco_iris=false;
print(“activate_rainbow_false”);
//Get the networkview of this new transform
//var newObjectsNetworkview : NetworkView = myNewTrans.networkView;
if (Time.time - timerStart > timerDelay)
{
print(“enter_rainbow_destruction”);
print("networkview before destroying "+networkView.viewID);
Network.RemoveRPCs(networkView.viewID);
print("networkview after_destroying "+networkView.viewID);
Network.Destroy(gameObject);
print(“destroyed rainbow”);
}

}

}

}

If I put the “if” with the destroying sentences inside the checking of the boolean variable for the instantiation of the rainbow as I have pasted here I can instantiate but the destroying doesn’t work. I’ve added some prints for helping me in the “debuging” and all of them appear whithin the same second (even the “destroyed rainbow” ). Do the printings appear when they must or when I work with timers is not recommended the use these tricks (printings) for helping in my “debugging”?.

If I put out of the checking for the instantiation of the rainbow it’s the same.

It’s like if the timers didn’t work.

The ID of its networkView is correct.

And another question: when I make a Network.Instantiate I’ve got to make it as a Transform…?. Is it well done?.

Any idea?. Please?.

thank you very much jehos.