IslandDemo MMO

Scoppio
edited March 2011 in DotNet
Hi

I'm moving my problem from Unity forum to here, and I'll try to explain everything here before I arrive in the problem.

I gathered a small group of professionals (writer, musician, illustrator, a web designer, a programmer, a DB developer and other folks) to start our small project of an MMO, because of that we are looking for some server solutions and ready engines(unity 3D in this case, mainly because of the c# scripts) to cut development time.

So I found the Photon (after some forum searching too), the boot camp is awesome and the MMO demo has alot of fuctions that solves a few problems (mainly by "inexperience"), now I'm trying to make the Island demo work (its more simple and the FPScam is more what we are looking for)

So here it goes, the problem:

- I've downloaded the island demo from the unity3d resourse
- Unpacked the Island demo form the SDK and I DIDN'T replaced any of the files
- opened the unity - island demo - and placed in the scene the "Game Manager" and the other one too...
- opened the server, installed the instance and set it to start
- Pressed play on the game and opened the "MMO ISLAND GRID" and added 15 bots and opened a client of the game
- four errors happened

1 - System.NullReferenceException: Object reference not set to an instance of an object
at Radar.OnGUI () [0x00015] in E:\Users\User\Documents\Unity Projects\IslandDemo\Assets\Photon\Radar.cs:90
UnityEngine.Debug:Log(Object)
Radar:OnGUI() (at Assets/Photon/Radar.cs:144)
MmoEngine:OnGUI() (at Assets/Photon/MmoEngine.cs:75)

2 - System.NullReferenceException: Object reference not set to an instance of an object
at Player.Update () [0x00026] in E:\Users\User\Documents\Unity Projects\IslandDemo\Assets\Photon\Player.cs:120
UnityEngine.Debug:Log(Object)
Player:Update() (at Assets/Photon/Player.cs:127)

3 - All players/bots were invisible and "intangible" from the client, and there was no radar ingame.

4 - the MMO Grid didn't showed any of the two clients that were logged in the server.

[solution]

Well... its stupid, i know, but I forgot to add the ViewDistancePrefab :\
I found that out when I added the "island.scene" from the /unityIsland/ located in the SDK to the project...

Now I'm trying to open the server to the web so my colleagues may help me with the development (I'm the worst programmer in the world when it comes to network connection)

Comments

  • - Unpacked the Island demo form the SDK and I DIDN'T replaced any of the files
    It sounds like you copied the demo project from the sdk INTO the island demo and did not replace the files?
    Should be the other way around: copy the island demo into the sdk project and don't replace...
    OR: copy the sdk project to the island demo AND overwrite
  • Boris wrote:
    - Unpacked the Island demo form the SDK and I DIDN'T replaced any of the files
    It sounds like you copied the demo project from the sdk INTO the island demo and did not replace the files?
    Should be the other way around: copy the island demo into the sdk project and don't replace...
    OR: copy the sdk project to the island demo AND overwrite

    Exactly, I did the wrong way ;)

    Now I'm trying to figure out how to make a login screen and a config menu to change the IP/port and correct the problem with the FPSWalker (bumping when walking down a slope), this way I may start to make some features, make a new map (i'm thinking about making a city)
  • The Chat Demo has something similar to a login screen, so you might want to take a look into that. It's GUI usage is very basic, however.
    http://developer.exitgames.com/liteandl ... bychatdemo
  • I'll be honest, I've got a small team of upcoming developers and we too are working with Unity3d/Photon. However, we are a bit confused on where to actually write the server code. I've seen a lot of functions written on the client, but we want the server to actually confirm most of the updates.

    P.S. I've heard that when you import a new terrain, there are a few spawn issues such as it being set to the position (wayy off to the side) of unity's island.
  • Server code is written in the server application, the code that you so far were using was purely client side.
  • Ahh thank you so much. I was looking through those projects, but I wasn't sure whether or not we would also use the common or netSync applications for any part of this. Is there any detailed documentation on the files for the server application? I've been looking through the code, but my mind is just completely blown right now.
  • there is inline doc and a Photon.MmoDemo.chm help file in the docs/aapplications folder
  • I see the inline citation, but I'd like a more explanatory description of each file and what it includes. As for the Photon.MmoDemo.chm help file, it doesn't display anything.
  • Photon.MmoDemo.chm: you might have to unblock the contents (right-click -> properties -> unblock)
  • /happiness

    Thank you so much.
  • I'm trying to add the chat to the Island Demo and to add a connection to the Database from the server side (so I can login or register a new user).

    I'll come back with other common questions soon ;)

    (actually I have a few, so here goes one)

    - where exactly should I call something (and what should I call, like, genericRaising? ) inside unity to send a string to the Server, this will solve 70% of my problems :)

    Based on what I read in other topics I'm looking at the OnRaiseGenericEvents
    *May I reproduce the code in here? its given freely, so I supose that I may post parts of the code in here, sorry if I may not.

    What I may say is that I can't understand some of the things that are happening here.

    I've coded in C for Microcontrolers firmwares, coded a few computer softwares for management of microcontrolers connected with bluetooth, RS232, RS485, modbus, control CLP's, and even to control other softwares and Databases, but never had to do anything over the internet or even a LAN.

    not long ago I've decided to go into game development... but of normal programming I know, there was no challenge to me other then to get/make/buy the visual and audio resouces and finish the game, so I decided to take a leap longer then my legs, so I ask to have patience and maybe point a better aproach so I can understand better what is happening
    [Operation(OperationCode = (byte)OperationCode.RaiseGenericEvent)]
    
    Feels like somekind of "case" statement.
            public OperationResponse OperationRaiseGenericEvent(Peer peer, OperationRequest request)
            {
    
    receive the peer data (what ever it is) and receive the requested operation (should have the operation id, item id, etcs id)
                var operation = new RaiseGenericEvent(request);
    
    put the requested data inside an object, to be used like an struct maybe, so its easier to manage the data.
                if (!operation.IsValid)
    
    Some inbuilt var that relates to a flag that is setted when operation is created, which evaluates all the data looking if everything is allright, so it sets "true" if its ok, or "false" if something is wrong.
                {
                    return new OperationResponse(request, (int)ErrorCode.InvalidOperationParameter, operation.GetErrorMessage());
                }
    
    send error message if the operation is not valid
                Item item;
                bool actorItem = true;
    
    creating a new item, creating a bool actorItem...
                if (false == operation.ItemType.HasValue || string.IsNullOrEmpty(operation.ItemId))
                {
                    item = this.Avatar;
    
                    // set return values
                    operation.ItemType = item.Type;
                    operation.ItemId = item.Id;
                }
    
    if operation has no item type or has no item id then it instantiates an ?avatar? (what for?) then sets the itemId and ItemType as those default values from Avatar
    So, I guess that this operation is actually generating a new avatar from a request that carries no information at all, would be like a "default operation" to save coding time?
                else if (this.TryGetItem(operation.ItemType.Value, operation.ItemId, out item) == false)
                {
                    if (this.World.ItemCache.TryGetItem(operation.ItemType.Value, operation.ItemId, out item) == false)
                    {
                        return operation.GetOperationResponse((int)ErrorCode.ItemNotFound, "ItemNotFound");
                    }
    
                    actorItem = false;
                }
    
    but, if it actually have something inside, then you try to see if the values inside of it are not correctly setted and there is this "out item" which I have no idea of what it means.
    if its false, then he looks for this item in the world itemCache... if its false (not there) then it generates an error and say "sorry guy, no donut for you".
    Being it, then the actorItem is setted false (yet, no idea what he is for so far).
                if (actorItem)
                {
                    // we are already in the item thread, invoke directly
                    return ItemOperationRaiseGenericEvent(item, operation);
                }
    
    Here it is, the actorItem seens to be the flag that says if the server MAY or MAY NOT send data back to the client.
    So, case positive then it will "return itemOperationRaiseGenericEven(item, operation)", which means something, the item should be the data that actually composes the item (item value, id, etc... but I yet don't know that Item is in its roots, ive no idea for real) and there is the operation... which actually is the "request"... but since operation is a buffer you pass the buffer forward.
    Also there is the "how do I use this on client side" and "how to apply it inside unity" problem... but first I must finish reading this.
                // second parameter (peer) allows us to send an error event to the client (in case of an error)
                item.OperationQueue.EnqueueOperation(() => ItemOperationRaiseGenericEvent(item, operation), this.Peer, request);
    
                // operation continued later
                return null;
            }
    
    if the actor was actually an error, it don't send back the requested operation, instead it send an error code, but it was returned back there, so this would be the case that "there is no item for the client, but it does exist for the world, in this case the actor will not receive this item (maybe its not subscribed into its interest area) and may receive an error even or something like that, but this itemOperationEnquenqueuequeuq is really complicated and I don't get what is happening there... imean, it actually does some kind of "() => xxx" which seens to be "this statement is equal or bigger then this another statement", and yet, this is calling for ItemOperaingRaiseGenericEven and calling for the same item, operation that you were actually using (or not, the item may now be an avatar).

    Thats basically it what I read in this part of the code, so what I guessed correctly and what is wrong (if its not everything wrong), there are alot of holes in my guesses, and there still is the question on how to work with it, i guess its mainly because of my experience mostly with microcontrolers where I have the full control of everything, from how the data enters in the processor and what interrupt takes precendence over what that I feel unconfortable with codes that I haven't done myself (with MCU's you have to build everything from scracth most part of the time).

    The one in the clientside seens to be easier to read, but tells me if I'm wrong
            public static void RaiseGenericEvent(
                Game game, string itemId, byte? itemType, byte customEventCode, object eventData, byte eventReliability, EventReceiver eventReceiver)
    
    bla bla bla
            {
                var data = new Hashtable
                    {
                        { (byte)ParameterCode.CustomEventCode, customEventCode }, 
                        { (byte)ParameterCode.EventReliability, eventReliability }, 
                        { (byte)ParameterCode.EventReceiver, (byte)eventReceiver }
                    };
    
    makes somekind of structure with bytes? (i've never used bytes as a kind of variable... Ill read about it later, that what I get by being new to c#)
    ok... itseens to be actually giving the value from a parameter to a byte.
                if (eventData != null)
                {
                    data.Add((byte)ParameterCode.EventData, eventData);
                }
    
                if (itemId != null)
                {
                    data.Add((byte)ParameterCode.ItemId, itemId);
                }
    
                if (itemType.HasValue)
                {
                    data.Add((byte)ParameterCode.ItemType, itemType.Value);
                }
    
    adding new bytes to the original one "hashtable"... it actually looks alot like a string, each byte has its value, but since its divided as a byte it has a limited space so ?its easy to manipulate?, i guess...
                game.SendOperation(OperationCode.RaiseGenericEvent, data, true, Settings.ItemChannel);
            }
    
    send the code to the server... I guess thats it, right? why does it sends so many things (4 statements) and the operationCode.RaiseGenericEvent receives only 2 statements? (peer and request).
    where actually the server side receive the data, takes it as an operation request and manipulate the data to send just the peer and the request? Sorry again for talking too much, but I realy wants to understand how the data is passed in this kind of system.

    I was trying the blank project test but it don't seen to work in my computer for an unknown reason so I'm stiking to what I got right now (ok... to be trying to manipulate the MMO demo code may seen a bit too much for a begginer, but I usually try it the hard way).
  • due to the length I will only make notes on points that seem to be unclear
    Scoppio wrote:
    [Operation(OperationCode = (byte)OperationCode.RaiseGenericEvent)]
    
    Feels like somekind of "case" statement.
    this is only used if you decide to dispatch your operations with the operation dispatcher (code enabled by setting compilation symbol "OperationDispatcher") - if you use switch/case statements at OnOperationRequest you can ignore this
    Scoppio wrote:
                if (false == operation.ItemType.HasValue || string.IsNullOrEmpty(operation.ItemId))
                {
                    item = this.Avatar;
    
                    // set return values
                    operation.ItemType = item.Type;
                    operation.ItemId = item.Id;
                }
    
    if operation has no item type or has no item id then it instantiates an ?avatar? (what for?) then sets the itemId and ItemType as those default values from Avatar
    So, I guess that this operation is actually generating a new avatar from a request that carries no information at all, would be like a "default operation" to save coding time?
    no, not instantiating a new avatar.. it just selects that avatar as default target if no itemid is submitted
    Scoppio wrote:
                else if (this.TryGetItem(operation.ItemType.Value, operation.ItemId, out item) == false)
                {
                    if (this.World.ItemCache.TryGetItem(operation.ItemType.Value, operation.ItemId, out item) == false)
                    {
                        return operation.GetOperationResponse((int)ErrorCode.ItemNotFound, "ItemNotFound");
                    }
    
                    actorItem = false;
                }
    
    but, if it actually have something inside, then you try to see if the values inside of it are not correctly setted and there is this "out item" which I have no idea of what it means.
    if its false, then he looks for this item in the world itemCache... if its false (not there) then it generates an error and say "sorry guy, no donut for you".
    Being it, then the actorItem is setted false (yet, no idea what he is for so far).
    if an itemid is is submitted we first look if it's an items that belongs to the actor, and if it doesn't we look if it belongs to someone else. "out" parameter is just another way to return objects from a method.
    Scoppio wrote:
                if (actorItem)
                {
                    // we are already in the item thread, invoke directly
                    return ItemOperationRaiseGenericEvent(item, operation);
                }
    
    Here it is, the actorItem seens to be the flag that says if the server MAY or MAY NOT send data back to the client.
    So, case positive then it will "return itemOperationRaiseGenericEven(item, operation)", which means something, the item should be the data that actually composes the item (item value, id, etc... but I yet don't know that Item is in its roots, ive no idea for real) and there is the operation... which actually is the "request"... but since operation is a buffer you pass the buffer forward.
    Also there is the "how do I use this on client side" and "how to apply it inside unity" problem... but first I must finish reading this.
                // second parameter (peer) allows us to send an error event to the client (in case of an error)
                item.OperationQueue.EnqueueOperation(() => ItemOperationRaiseGenericEvent(item, operation), this.Peer, request);
    
                // operation continued later
                return null;
            }
    
    if the actor was actually an error, it don't send back the requested operation, instead it send an error code, but it was returned back there, so this would be the case that "there is no item for the client, but it does exist for the world, in this case the actor will not receive this item (maybe its not subscribed into its interest area) and may receive an error even or something like that, but this itemOperationEnquenqueuequeuq is really complicated and I don't get what is happening there... imean, it actually does some kind of "() => xxx" which seens to be "this statement is equal or bigger then this another statement", and yet, this is calling for ItemOperaingRaiseGenericEven and calling for the same item, operation that you were actually using (or not, the item may now be an avatar).
    each item runs in a "fiber": a construct that executes actions async one after the other to avoid concurrency issues. your own items run in your peer's request fiber, so you can access them directly (first code snippet above). if it's not your item you have to queue it to the item fiber, otherwise the operation would not be thread safe. That's the whole idea here.
    Scoppio wrote:
            {
                var data = new Hashtable
                    {
                        { (byte)ParameterCode.CustomEventCode, customEventCode }, 
                        { (byte)ParameterCode.EventReliability, eventReliability }, 
                        { (byte)ParameterCode.EventReceiver, (byte)eventReceiver }
                    };
    
    makes somekind of structure with bytes? (i've never used bytes as a kind of variable... Ill read about it later, that what I get by being new to c#)
    ok... itseens to be actually giving the value from a parameter to a byte.
    are you asking what a hashtable is?
    http://msdn.microsoft.com/en-us/library ... table.aspx
    in this case it's a container for all operation parameters.
    Scoppio wrote:
                game.SendOperation(OperationCode.RaiseGenericEvent, data, true, Settings.ItemChannel);
            }
    
    send the code to the server... I guess thats it, right? why does it sends so many things (4 statements) and the operationCode.RaiseGenericEvent receives only 2 statements? (peer and request).
    where actually the server side receive the data, takes it as an operation request and manipulate the data to send just the peer and the request? Sorry again for talking too much, but I realy wants to understand how the data is passed in this kind of system.
    first parameter is the operation code --> OperationRequest.OperationCode on the server
    second parameter are the parameters --> OperationRequest.Params on the server
    third parameter determines if it MUST arrive - if true you can trust that it will either arrive or that the client disconnects.
    forth parameter is the networking channel that is used to send the packages. operations/events sent in the same channel will always arrive in order, while packages sent in different channels may arrive in a different order than you sent them.
    Scoppio wrote:
    I was trying the blank project test but it don't seen to work in my computer for an unknown reason so I'm stiking to what I got right now (ok... to be trying to manipulate the MMO demo code may seen a bit too much for a begginer, but I usually try it the hard way).
    maybe you should start here: http://developer.exitgames.com/quicksta ... worldpart1
    or follow the learning trail: http://developer.exitgames.com/demos/demolist
  • Thanks again.

    I'm trying the Hello World tutorial (not working yet) and the hello world 2 seens to be a good "power up" that explains how different opperations may be implemented (but not working so far ;) )