Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
*.pict filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.[tT][gG][aA] filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text

# Unity
*.unity filter=lfs diff=lfs merge=lfs text
*.prefab binary
*.asset filter=lfs diff=lfs merge=lfs -text
*.anim filter=lfs diff=lfs merge=lfs -text
*.anim filter=lfs diff=lfs merge=lfs -text
16 changes: 16 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.

# More details are here: https://help.github.com/articles/about-codeowners/

# The '*' pattern is global owners.

# Order is important. The last matching pattern has the most precedence.
# The folders are ordered as follows:

# In each subsection folders are ordered first by depth, then alphabetically.
# This should make it easy to add new rules without breaking existing ones.

# Global rule:
* @SamuelBellomo
106 changes: 61 additions & 45 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,71 @@
# Architecture

This document describes the high-level architecture of BossRoom.
This document describes the high-level architecture of Boss Room.
If you want to familiarize yourself with the code base, you are just in the right place!

> __IMPORTANT__:
> This doc is heavily WIP
Boss Room is an 8-player co-op RPG game experience, where players collaborate to take down some minions, and then a boss. Players can select between classes that each have skills with didactically interesting networking characteristics. Control model is click-to-move, with skills triggered by mouse button or hotkey.

Code is organized into three separate assemblies: `Client`, `Server` and `Shared` (which, as it's name implies, contains shared functionality that both client and the server require).

## Host model
Boss Room uses a Host model for its server. This means one client acts as a server and hosts the other clients.

A common pitfall of this pattern is writing the game in such a way that it is virtually impossible to adapt to a dedicated server model.

We attempted to combat this by using a compositional model for our client and server logic (rather than having it all combined is single modules):
- On the Host, each GameObject has `{Server, Shared, Client}` components.
- If you start up the game as a dedicated server, the client components will disable themselves, leaving you with `{Server, Shared}` components.
- If you start up as a client, you get the complementary set of `{Shared, Client}` components.

This approach works, but requires some care:
- if you have server and clients of a shared base class, you need to remember that the shared code will run twice on the host;
- you also need to take care about code executing in `Start` and `Awake`: if this code runs contemporaneously with the `NetworkingManager`'s initialization, it may not know yet whether the player is a host or client.
- We judged this extra complexity worth it, as it provides a clear road-map to supporting true dedicated servers.
- Client server separation also allows not having god-classes where both client and server code are intermingled. This way, when reading server code, you do not have to mentally skip client code and vice versa. This helps making bigger classes more readable and maintainable. Please note that this pattern can be applied on a case by case basis. If your class never grows too big, having a single `NetworkBehaviour` is perfectly fine.

## Connection flow
The Boss Room network connection flow is owned by the `GameNetPortal`:
- The Host will invoke either `GameNetPortal.StartHost`, or `StartRelayHost` (if Photon relay is being used).
- The client will invoke either `ClientGameNetPortal.StartClient`, or `StartClientRelayMode`.
- Boss Room's own connection validation logic is performed in `ServerGameNetPortal.ApprovalCheck`, which is plugged in to the `NetworkingManager`'s connection approval callback. Here some basic information about the connection is recorded (including a GUID, to facilitate future reconnect logic), and success or failure is returned. In the future, additional game-level failures will be detected and returned (such as a `ServerFull` scenario).

## Bird's Eye View
## Data model
Game data in Boss Room is defined in `ScriptableObjects`. The `ScriptableObjects` are organized by enum and made available in a singleton class: the `GameDataSource`, in particular `ActionDescription` and `CharacterData`. `Actions` represent discrete verbs (like swinging a weapon, or reviving someone), and are substantially data driven. Characters represent both the different player classes, and also monsters, and represent basic details like health, as well as what "Skill" Actions are available to each Character.

## Exploring the project
BossRoom is an 8-player co-op RPG game experience, where players collaborate to take down some minions, and then a boss. Players can select between classes that each have skills with didactically interesting networking characteristics. Control model is click-to-move, with skills triggered by mouse button or hotkey.
## Transports
Currently two network transport mechanisms are supported:
- IP based
- Relay Based

One of the 8 clients acts as the host/server. That client will use a compositional approach so that its entities have both server and client components.
In the former, the clients connect directy to a host via IP address. This will only work if both are in the same local area network or if the host forwards ports.

The game is server-authoritative, with latency-masking animations. Position updates are done through NetworkTransforms. NetworkedVars and RPC endpoints are isolated in a class that is shared between the server and client specialized logic components. All gamelogic runs in FixedUpdate at 30 Hz, matching our network update rate.
In the latter, some setup is required. Please see our guide [here](Documentation/Photon-Realtime/Readme.md) on how to setup our current relay.

Please see [Multiplayer over internet](README.md) section of our Readme for more information on using either one.

To allow for both of these options to be chosen at runtime we created `TransportPicker`. It allows to chose between an IP-based and a Relay-based transport and will hook up the game UI to use those transports. The transport field in the `NetworkManager` will be ignored. Currently we support the following transports:
- **UNet(IP):** UNet is the default MLAPI transport and the default IP transport for Boss Room.
- **LiteNetLib(IP):** We use LiteNetLib in Boss Room because it has a built in way to simulate latency which is useful for spotting networking issues early during development.
- **Photon Realtime (Relay):** Photon Realtime is a relay transport using the [Photon Realtime Service](https://www.photonengine.com/Realtime).

To add new transport in the project parts of `GameNetPortal` and `ClientGameNetPortal` (transport switches) need to be extended.

Code is organized into three separate assemblies: **Client**, **Shared** and **Server** which reference each other when appropriate.
## Game state / Scene flow
In Boss Room, scenes correspond to top-level Game States (see `GameStateBehaviour` class) in a 1:1 way. That is, there is a `MainMenu` scene, `Character Select` scene (and state), and so on.

For an in-depth overview of the project's architecture please check out our [ARCHITECTURE.md](ARCHITECTURE.md).
Because it is currently challenging to have a client be in a different scene than the server it's connected to, the options for MLAPI developers are either to not use scenes at all, or to use scenes, and let game state transitions on the host drive game state transitions on the client indirectly by forcing client scene transitions through MLAPI's networked scene management.

### Key classes
We chose the latter approach.

Each scene has exactly one `GameStateBehaviour` (a specialization of `MLAPI.NetworkBehaviour`), that is responsible for running the global state logic for that scene. States are transitioned by triggered scene transitions.

### Key classes
## Important classes

**Shared**
- `NetworkCharacterState` Contains all NetworkedVars, and both server and client RPC endpoints. The RPC endpoints only read out the call parameters and then raise events from them; they don’t do any logic internally.
- `NetworkCharacterState` Contains NetworkedVars that store the state of any given character, and both server and client RPC endpoints. The RPC endpoints only read out the call parameters and then raise events from them; they don’t do any logic internally.

**Server**
- `ServerCharacterMovement` manages the movement Finite State Machine (FSM) on the server. Updates the NetworkedVars that synchronize position, rotation and movement speed of the entity on its FixedUpdate.
- `ServerCharacter` has the AIBrain, as well as the ActionQueue. Receives action requests (either from the AIBrain in case of NPCs, or user input in case of player characters), and executes them.
- `ServerCharacter` has the `AIBrain`, as well as the ActionQueue. Receives action requests (either from the AIBrain in case of NPCs, or user input in case of player characters), and executes them.
- `AIBrain` contains main AI FSM.
- `Action` is the abstract base class for all server actions
- `MeleeAction`, `AoeAction`, etc. contain logic for their respective action types.
Expand All @@ -39,41 +75,21 @@ For an in-depth overview of the project's architecture please check out our [ARC
- `ClientInputSender `. On a shadow entity, will self-destruct. Listens to inputs, interprets them, and then calls appropriate RPCs on the RPCStateComponent.
- `ActionFX` is the abstract base class for all the client-side action visualizers
- `MeleeActionFX`, `AoeActionFX`, etc. Contain graphics information for their respective action types.



### Movement action flow

## Movement action flow
- Client clicks mouse on target destination.
- Client->server RPC, containing target destination.
- Anticipatory animation plays immediately on client.
- Server path-plans.
- Once path-plan is finished, server representation of entity starts updating its NetworkedTransform at 30fps. Graphics is on a separate GO and is connected to the networked GO via a spring, to smooth out small corrections.
- Graphics GO never passes the simulation GO; if it catches up to the sim due to a network delay, the user will see a hitch.

### Transports

Boss Room provides players with two ways to connect to a server.
- Server performs pathfinding.
- Once pathfinding is finished, server representation of entity starts updating it's NetworkVariables at 30fps.
- Visuals GameObject never outpaces the simulation GameObject, always slightly behind and interpolating towards the networked position and rotation.

- IP based: The clients connect directy to a host via IP address. This will only work if both are in the same local are network or if the host forwards ports.
- Relay Based: The clients and the host connect to a relay server with a room key and run all traffic over this relay server.
## Navigation System
Each scene which uses navigation or dynamic navigation objects should have a `NavigationSystem` component on a scene GameObject. That object also needs to have the `NavigationSystem` tag.

To allow for both of these options to be chosen at runtime we created `TransportPicker`. `Transport` picker allows to chose a ip based and a relay based transport and will hook up the game UI to use those transports. The transport field in the `NetworkManager` will be ignored. Currently we support the following transports:
- **UNet(IP):** UNet is the default MLAPI transport and the default IP transport for Boss Room.
- **LiteNetLib(IP):** We use LiteNetLib in Boss Room because it has a built in way to simulate latency which is useful for spotting networking issues early during development.
- **Photon Realtime (Relay):** Photon Realtime is a relay transport using the [Photon Realtime Service](https://www.photonengine.com/Realtime).
### Building a navigation mesh
The project is using `NavMeshComponents`. This means direct building from the Navigation window will not give the desired results. Instead find a `NavMeshComponent` in the given scene e.g. a **NavMeshSurface** and use the **Bake** button of that script. Also make sure that there is always only one navmesh file per scene. Navmesh files are stored in a folder with the same name as the corresponding scene. You can recognize them based on their icon in the editor. They follow the naming pattern "NavMesh-\<name-of-creating-object\.asset>"

To add new transport in the project parts of `GameNetPortal` and `ClientGameNetPortal` (transport switches) need to be extended.

### Navigation System

#### Building a navigation mesh
The project is using NavMeshComponents. This means direct building from the Navigation window will not give the desired results. Instead find a NavMeshComponent in the given scene e.g. a **NavMeshSurface** and use the **Bake** button of that script. Also make sure that there is always only one navmesh file per scene. Navmesh files are stored in a folder with the same name as the corresponding scene. You can recognize them based on their icon in the editor. They follow the naming pattern "NavMesh-\<name-of-creating-object\.asset>"

#### Dynamic Navigation Objects
### Dynamic Navigation Objects
A dynamic navigation object is an object which affects the state of the navigation mesh such as a door which can be openend or closed.
To create a dynamic navigation object add a NavMeshObstacle to it and configure the shape (in most cases this should just match the corresponding collider). Then add a DynamicNavObstacle component to it.

#### Navigation System
Each scene which uses navigation or dynamic navigation objects should have a NavigationSystem component on a scene gameobject. That object also needs to have the "NavigationSystem" tag.

---------------------------
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ private void OnCharacterAppearanceChanged(int oldValue, int newValue)
SetAppearanceSwap();
}

private void OnStealthyChanged(byte oldValue, byte newValue)
private void OnStealthyChanged(bool oldValue, bool newValue)
{
SetAppearanceSwap();
}
Expand All @@ -271,7 +271,7 @@ private void SetAppearanceSwap()
if (m_CharacterSwapper)
{
var specialMaterialMode = CharacterSwap.SpecialMaterialMode.None;
if (m_NetState.IsStealthy.Value != 0)
if (m_NetState.IsStealthy.Value)
{
if (m_NetState.IsOwner)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public override bool Start()
if (!movement.IsPerformingForcedMovement())
{
movement.CancelMove();
}
}
return true;
}

Expand All @@ -40,7 +40,7 @@ public override bool Update()
{
// start actual stealth-mode... NOW!
m_IsStealthStarted = true;
m_Parent.NetState.IsStealthy.Value = 1;
m_Parent.NetState.IsStealthy.Value = true;
}
return !m_IsStealthEnded;
}
Expand All @@ -66,7 +66,7 @@ private void EndStealth()
m_IsStealthEnded = true;
if (m_IsStealthStarted)
{
m_Parent.NetState.IsStealthy.Value = 0;
m_Parent.NetState.IsStealthy.Value = false;
}

// note that we cancel the ActionFX here, and NOT in Cancel(). That's to handle the case where someone
Expand Down
2 changes: 1 addition & 1 deletion Assets/BossRoom/Scripts/Server/Game/Character/AIBrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public bool IsAppropriateFoe(ServerCharacter potentialFoe)
if (potentialFoe == null ||
potentialFoe.IsNpc ||
potentialFoe.NetState.NetworkLifeState.Value != LifeState.Alive ||
potentialFoe.NetState.IsStealthy.Value != 0)
potentialFoe.NetState.IsStealthy.Value)
{
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,7 @@ public void InitNetworkPositionAndRotationY(Vector3 initPosition, float initRota
/// <summary>
/// Indicates whether this character is in "stealth mode" (invisible to monsters and other players).
/// </summary>
/// <remarks>
/// FIXME: this should be a bool, but NetworkedVarBool doesn't work at the moment! It's serialized
/// as a bit, but deserialized as a byte, which corrupts the whole network-var stream.
/// </remarks>
public NetworkVariableByte IsStealthy { get; } = new NetworkVariableByte(0);
public NetworkVariableBool IsStealthy { get; } = new NetworkVariableBool();

[SerializeField]
NetworkHealthState m_NetworkHealthState;
Expand Down
4 changes: 2 additions & 2 deletions Assets/Readme.asset
Git LFS file not shown
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
The BossRoom repository follows the same code of conduct as the MLAPI repository. Please read the [MLAPI code of conduct](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/blob/master/CODE_OF_CONDUCT.md), thank you!
The Boss Room repository follows the same code of conduct as the MLAPI repository. Please read the [MLAPI code of conduct](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/blob/master/CODE_OF_CONDUCT.md), thank you!
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ If you would like to implement a new feature then consider what kind of change i

### <a name="docs"></a> Documentation

We accept changes and improvements to our documentation. Just submit a Pull Request with your proposed changes as described in the [Pull Request Submission Guidelines](#submit-pr).
We accept changes and improvements to our documentation through the [MLAPI Documentation repo](https://github.com/Unity-Technologies/com.unity.multiplayer.docs).

## <a name="cla"></a> Contributor License Agreements

Expand Down
Loading