Return To Wiki

Foundation Lobby (4.0 3/15/2015)

Nicholas Ventimiglia | http://unity3dfoundation.com

The Lobby System has everything you need for rapid multiplayer game prototyping.

  • Slick UI built on top of Unity5, uGUI and Foundation.Databinding
  • Map selection, Options menu, High scores menu and multiplayer (lobby) views
  • Reusable dialogs including confirm, input, selection and notices.
  • Multiplayer lobby built in with support for UnityNetwork and PUN.
  • Rich player profiles with icon portraits and score data.
  • Optional Account Service with Sign in, Sign Up, and Password Recovery
  • Optional Support for the Foundation Cloud C# Http Web Server (Asp.net MVC)

Dependencies

Lobby depends on a number of other packages. These packages are open source and included.

Project Structure

  • Plugins
  • Foundation
    • Lobby
    • Scripts
      • Models : Core logic for the Lobby system. Includes objects, messages interfaces and managers
      • Providers : Includes pluggable services (Network and Repository interface implementations)
      • Views : Menu scripts and other things associated with the presentation layer
    • Resources
      • Animations
      • Localization : Csv localization texts
      • Portraits : Images used by the Portrait services. Freely add/remove textures.
      • Prefabs
      • Sfx
      • Sprites

Setup and Configuration

Once the package is unpacked, you will need to do some light configuration

  • On the main menu run Tools/Foundation/Instantiate ScriptableObjects
    • This will make sure the static scriptable object services are instantiated
  • Under /Assets/Resources/MapService Configure the map scriptable objects
    • Maps : Array of scenes to display in the map selection view.ed
  • Open the /Assets/Lobby/Lobby.unity Scene file. Select and configure the _LobbySystem game object.

    • MultiClientMode will force a 'fresh' user on each load. Game data will not be saved. I use this during development as it lets me run multiple client instances each with their own account.
    • LobyScene Name of the main lobby Level. Loaded when 'returning to lobby'
    • LobyScenePartial Name of the partial lobby Level. Use if Lobby is partial and loaded in background by other levels.
    • Roots The Canvas, Services and other game objects that should be activated by the LobbyController. These objects should be inactive while in the editor since having this active might cause issues during scene loading.
  • Optional Configure Photon Cloud

    • Install the Photon For Unity Package
    • Open on the main menu Edit/Project Settings/Player and focus on the inspector.
    • In Scripting Define Symbols add the tag Foundation_Pun this will reveal the Pun Network Provider
    • Open the LobbyScene. Expand the _LobbySystem game object
    • Remove the uNet GameObject (child to LobbyController).
    • Add a new child game object pNet with the PhotonNetworkProvider script
    • Update the LobbyController.Roots property with the new pNet object (replacing the uNet object)
  • Optional Configure Foundation Cloud

    • Install the Foundation Cloud Package
    • Open on the main menu Edit/Project Settings/Player and focus on the inspector.
    • In Scripting Define Symbols add the tag Foundation_Cloud.
    • New options will appear on the LobbyController
    • EnableCloud will enable the cloud. Turn this off when developing gameplay.
    • EnableOfflineMode will enable playing offline when connecting to the cloud server fails. Turn this on if the client absolutely must connect to the server and a local cache copy of their profile / account is not acceptable.

The package is pretty much good to go. Place any gameplay code in the respective scenes.

Scripting Guide

Foundation is big and intimidating. Ive tried to minimise the code by using a quality architecture. Namely the listener pattern and the model-view-viewmodel pattern.

The MVVM pattern allows for a separation of the business logic (the model) from the visual presentation (the views). In other words you probably dont need to edit the code at all. It is recommender that you only modify the presentation layer, that is that you only modify the game objects and UI elements within the scene view.

The one exception to this is the PlayerInfo object which uses a partial class for custom properties.

Lastly, before we begin please read the documentation on the other modules (included). Specifically make yourself familiar with the task, databinding and messaging modules as they are the ones the Lobby depends on most.

LobbyController

The Lobby Controller is the scene startup object. Here is its work flow.

  • Awake
    • Make sure it is the only instance. If it is not, suicide.
    • Confirm the Injector and TaskManager are initialized.
    • Initialize the PlayerInfoRepository and AccountService
    • Subscribe to the Messenger and Injector
    • Show the Splash, Activate the Root child objects
    • Start 'ReadyAsync'
  • ReadyAsync (Coroutine)
    • Show the Splash
    • Ready the AccountService
    • If no account is cached, show the Signup view
    • Ready the PlayerRepository
    • If no player data is cached, show the name and portrait selection view
    • If you have custom services place them here
    • Raise the SceneStarting message (notifies listeners that scene is loaded)
    • Show the MainMenu if this is the main lobby scene
    • Hide the Splash
  • OnLevelWasLoaded
    • Raise the SceneStarting message (notifies listeners that scene is loaded)
    • Show the MainMenu if this is the main lobby scene
  • OnApplicationPause
    • If pausing and connected to a network, disconnects and returns to the lobby scene.
    • If unpausing after a disconnect, calls Ready.
    • Raises the PauseMessage (notifies listeners of application pause)

Accounts

The logic for the accounts system is located under Lobby/_Scripts/Models/LobbyAccount.cs. It is not recommended that you modify this unless you are a very advanced developer.

  • The LobbyAccount object describes the User's authenticated identity. It contains three properties.
    • Id A randomly generated unique id
    • Email The users submitted email address
    • Current Accessor to the current LobbyAccount in use
    • Service Accessor to the current AccountService provider in use.

The AccountService uses a provider pattern. Simply put it is designed to support multiple implementations of the IAccountService. Specifically there is a MockAccountService which saves account data to PlayerPrefs (locally) and CloudAccountService which uses the WWW class to save account data to a web server.

If you would like to write your own custom IAccountService, Great! Just inherit from IAccountService and implement the interface as demonstrated in the other two implementations. Remember to set the LobbyAccount.Service static accessor in the LobbyController (in awake).

Players

Like the AccountSystem the Player system follows the Model-Provider pattern. The PlayerInfo is the player's shared profile and includes information on his name, score and portrait. Unlike the Account object, PlayerInfo is intended to be customized by the use of the PlayerInfo partial class.

Located in Lobby/_Scripts/MyPlayerInfo.cs is a partial class intended to be customized by you with custom fields for the player. Because the services use Json serialization in the back, most new fields or properties will be saved automatically. If you add an observable property (non automatic property) please include the [fsProperty] annotation.

  • The PlayerInfo object describes the User's shared profile.
  • Static
    • Repository : Service for getting and saving PlayerInfo's
    • Manager : Service for caching the local player and sharing the local player over the network
    • LocalPlayer : Accessor to the local player
  • Identity
    • AccountId: unique id for this player. Acquired from authentication
    • IsLocalPlayer : Flag for the LocalPlayer
  • Network
    • NetworkId : NetworkConnection Id (from Pun or UnityNetwork)
    • IsNetworkLocal : True if this player originated from the local client (Self or local AI)
    • IsNetworkAuthority : True if Disconnected, Host or MasterClient
    • Profile
    • IsAI : For AI Players added to the PlayerManager
    • Name : UserName
    • Score : Main Score value. Used in Leaderboard sorting.
  • Portrait
    • PortraitType : Describes the datasource for the portrait (Resource or Web)
    • PortraitParamater : Datasource parameter (texture name or Url)
    • Portrait : The Texture2d Image.
    • Customization
    • Add properties at will to MyPlayerInfo
    • Add [fsProperty] annotation to non automatic properties
    • Update the PartialCopyTo method with new properties.

The PlayerRepository uses a provider pattern. Simply put it is designed to support multiple implementations of the IPlayerRepository. Specifically there is a MockPlayerRepository which saves account data to PlayerPrefs (locally) and CloudPlayerRepository which uses the WWW class to save account data to a web server.

If you would like to write your own custom IPlayerRepository, Great! Just inherit from IPlayerRepository and implement the interface as demonstrated in the other two implementations. Remember to set the PlayerInfo.Repository static accessor in the LobbyController (in awake).

Player Customization Example

namespace Foundation.Lobby.Models
{
    // Partial PlayerInfo ready for Customization !
    public partial class  PlayerInfo
    {
        // Example Observable Property 
        // Note that [fsProperty] is required for observable properties
        private int _teamId = -1;
        [fsProperty("TeamId")]
        public int TeamId
        {
            get { return _networkId; }
            set
            {
                if (_teamId == value)
                    return;
                _teamId = value;
                NotifyProperty("TeamId", value);
            }
        }


        //secondary score
        public int Games { get; set; }
        public int Wins { get; set; }
        public int Losses { get; set; }
        public int Kills { get; set; }

        // CopyTo for partial properties
        public void PartialCopyTo(PlayerInfo info)
        {
            info.Games = Games;
            info.Kills = Kills;
            info.Wins = Wins;
            info.Losses = Losses;
        }

        // Mock Partial Properties
        public void MakeMock()
        {
            Games = UnityEngine.Random.Range(100, 1000);
            Wins = UnityEngine.Random.Range(10, 1000);
            Losses = UnityEngine.Random.Range(10, 1000);
            Kills = UnityEngine.Random.Range(1, 100);
        }
    }
}

Networking

The NetworkService uses a provider pattern. Simply put it is designed to support multiple implementations of the IPlayerRepository. Specifically there is a UnityNetworkService which uses the default Unity Networking stack and PhotonNetworkService which uses Photon cloud.

If you would like to write your own custom INetworkService, Great! Just inherit from INetworkService and implement the interface as demonstrated in the other two implementations. Remember to set the NetworkContext.Service static accessor in the LobbyController (in awake).

The INetworkService wraps around the network providers and for the most part just normalizes the logic. For instance The concept of a Host and a MasterClient is simply considered Authority to the Lobby's network. The INetworkService is not intended to be consumed when you make your game logic, but, as an interface for the lobby's internal components.

Return To Wiki