Quantcast
Channel: Photon – Blog | Photonengine: Multiplayer Made Simple
Viewing all 41 articles
Browse latest View live

Released PUN v1.79

$
0
0
SDK Update

SDK Update

Changes in PUN v1.79

  • Changed:
    PUN will no longer aggregate the data from ALL objects in a group into ONE message.
    Instead, a maximum of 10 objects will be sent together.
    The idea is to avoid huge messages, which need fragmentation.
    Fragmentation needs to be avoided, because fragments are always reliable (and you basically lose “unreliable” updates when you send too much).
    There is a new variable for this: NetworkingPeer.ObjectsInOneUpdate.
  • Changed:
    As we send max 10 gameobject-updates in one message (by default), we can use a byte as type for their ID (instead of short).
    This minimally saves data but makes this PUN incompatible with older builds.
    We separate PUN versions for you so there won’t be a clash.
    PhotonNetwork.versionPUN is inserted into your Game Version to separate players.
  • Updated: PunTeams to keep PlayerPerTeams Listing up to date.
  • Updated: PlayerRoomIndexing improved consistency across various network contexts.
  • Fixed: SocketWebTcp for WebGL was time scale dependant and would stop receiving events when Time.TimeScale = 0.
  • Updated: DemoChat UI reworked to match demo Hub look and feel.
  • Updated: DemoHub pixel Perfect Canvas fix.
  • Added:
    Two more regions: Korea, Seoul (kr) and India, Chennai (in).
    If you’re using the hosting option “Best Region”, you may want to update the configuration in your PhotonServerSettings file.

Find PUN Free in the Asset Store at https://www.assetstore.unity3d.com/en/#!/content/1786 and
PUN+ at https://www.assetstore.unity3d.com/en/#!/content/12080.


Happy Holidays Sale: Get Any Photon 100 CCU Plan, PUN Plus & Photon Bolt 50% Off

$
0
0

1612_blog_50sale
Our Happy Holidays PUN Plus sale became quite a tradition over the last years, but this year we want to top it off:
+++ 100 CCU plans for Photon Realtime, PUN, Chat, Voice, Photon Bolt & all packages in the Unity Asset Store
+++ are all 50% off until Jan, 4, 2016.

You don’t have a paid Photon subscription yet?
Enter the following coupon code during the check-out process: PHOTON2016

The discounted price is not shown during check-out?
Due to technical restrictions the discounted price cannot be displayed during the check-out process.
You will receive an invoice by email stating the 50% discounted price immediately after you completed the check-out. Thanks for your trust.

You have already bought PUN Plus in Unity’s Asset Store and want to buy it a second time?
You cannot buy the same package twice in the the Asset Store, but just get a Photon Realtime 100 CCU plan on our site instead and use it for your PUN apps.

Take me to the 50% off deals >>

Thank You & Happy Holidays!

Dev Story ‘Tanks Multiplayer’: Switching from UNET to PUN

$
0
0

rbgameslogoThis guest post was written by Florian Bukmaier, co-founder and developer at Rebound Games.

Rebound Games is an indie studio founded by two brothers in 2013. They are frequently releasing new Unity assets on the Unity Asset Store, ranging from editor extensions and scripting tools to complete projects. The Asset Store is just their financial backup though – a perfect complement for funding games development and covering additional costs.

Florian shares what made them create their latest multiplayer project ‘Tanks Multiplayer’, some differences between Unity Networking (UNET) functionality and Photon Unity Networking (PUN), but also why they are doing the switch to Photon.

Get ‘Tanks Multiplayer’ on the Unity Asset Store

About the project

rbgamespic2

‘Tanks Multiplayer’ is a real time action shooter template, designed for Unity developers looking for a solid base or learning project for their own multiplayer game. Players are controlling a tank, shoot at other tanks and avoid hostile projectiles whenever possible. Each round consists of 1-12 players in teams of 3 people, trying to earn the most kills for their team.

There are several power-ups to collect during the game, such as shields, damage boosts or bouncing projectiles. The game is over, once the required kill score has been reached by one team. Also, the template makes use of additional Unity services, namely Unity Ads, Everyplay and Unity IAP – which are not the focus of this post.

Why did we create this? Simple – we thought it would be a fun thing to do. But fun alone does not pay any bills: even though Unity published a basic tank multiplayer project on the Asset Store after UNET (beta) was released, there is still a strong need for covering more advanced networking topics in great detail. Especially when parts of the network documentation are lacking, basically making UNET coding a quest of trial and error.
Months after UNET has been released, there are still questions showing up on the Unity forums, such as:

  • how do I add multiple player prefabs?
  • How do I implement networked object pooling?
  • Why aren’t my SyncVars working?
  • How to add teams?
  • How to handle host disconnects?
  • Where do I call RPCs in an authoritative manner?

We’ve wanted to solve these mysteries with a user-friendly project, well-documented code and comprehensive documentation.

Digging into UNET

Like every developer I guess, we weren’t born with a talent to magically understand a complex, new API on day 1 – especially when there is a low level (LLAPI) and high level API (HLAPI) to look at – we had to learn how to use it.

The open-source approach of UNET was of tremendous help in this process. We’ve heavily extended the default behaviors with custom callbacks and overrode many virtual methods, like those of the NetworkManager class, so it was inevitable taking a look at its inner workings. But first things first: synchronizing transform values, such as position and rotation, for a simple networked movement test is very easy thanks to the NetworkTransform component. Synchronizing player or game values across the network, like player health and remaining bullet count, is equally simple by using SyncVars – although there is one thing to be aware of: only the master client can change them, basically requiring an authoritative setup already.

After getting the basics right it was time to understand how UNET handles remote procedure calls, or Commands and ClientRpcs in this context. Why are there two different actions you might ask? Well, commands are instructions for and executed on the server, while ClientRpcs are actions delivered from the server to clients. Other than that, I don’t know – nevertheless we’ve immediately used this approach to not only execute critical methods (like calculating damage) authoritatively on the server and distribute the result via SyncVars to clients, but also for implementing an authorization concept where players send requests after successful user-initiated actions to the master. For example, this is done when a player died and has to watch a video ad for a few seconds. In this case, the server does not send a respawn call for this player to other clients, because it does not know the exact length of the video ad. Instead, the server waits until the player sends a respawn request after successfully watching the video ad and then executes the fulfillment procedure.

A glance at PUN

So far, everything worked well in the UNET version of ‘Tanks Multiplayer’. We’ve got the network concept down and several network modes (online/LAN/offline) running on desktop and mobile devices without issues. Now, why the sudden change in direction at the heart of it? To put it in a nutshell: while developing this asset, UNET really felt like a beta. Certainly it still has some rough edges with errors showing up in some situations but not others, or the need to work around something that is “deeply rooted” in the LLAPI, which could (or is already) fixed in a later patch release. Besides missing essential features for the foreseeable future, such as host migration on their relay servers, NAT punch-through and the ability to easily host your own server including load balancing (if you would ever need that), other developers reportedly experienced issues with the billing go-live process or the Unity cloud in general, where there have been outages for a whole weekend. If you put all your effort and motivation in your game, you don’t want it to fail on something like this. Don’t get me wrong – UNET is great for diving into networking topics right away or building a prototype with limited resources. The goal of this project has been accomplished to our full satisfaction. It’s just not something you want to use in production at this point; and that’s where Photon comes in. With PUN, there is a direct alternative including a reliable, battle-tested backend. Additionally, developers interested in our asset asked for supporting Photon through various channels. Also with Photon being the most popular networking solution for Unity (and providing a free version of PUN), meeting the demand felt like the right thing to do.

Doing the switch

The development phase for this project – this is from concept to release on the Unity Asset Store – took 3 months. The switch from UNET to PUN took roughly two weeks, with a networking prototype going after just one week. There are several reasons for the ease of transition: first of all, the component structure of UNET and PUN is very similar, although you won’t need as much NetworkIdentities / PhotonViews in the scene as in the UNET version. Secondly, because the asset was built with modularity and no cross-component interlacing in mind, nearly all methods could be used regardless of the networking implementation. This is a very critical design step at the beginning, even before writing the first line of code. Basically the structure stays the same, but obviously the network API has to be replaced. Let’s take a look at some conversion examples:

devstory__compatibility_mode_

devstory__compatibility_mode_

  • OWNERSHIP CHECKS
UNET

if (!isLocalPlayer)
{
//keep turret rotation updated for all clients
      OnTurretRotation(turretRotation);
      return;
}

PUN

if (!photonView.isMine)
{
//keep turret rotation updated for all clients
      OnTurretRotation(turretRotation);
      return;
}

  • SENDING RPCS
UNET

//on client
CmdShoot(pos, turretRotation);

//on server
[Command]
void CmdShoot(short[] position, short angle)
{   
      //instantiate shot
}

PUN

//on client
this.photonView.RPC("CmdShoot", PhotonTargets.AllViaServer, pos, turretRotation);

//on server
[PunRPC]
void CmdShoot(short[] position, short angle)
{   
      //instantiate shot
}
  • SYNCING VARIABLES
UNET

[SyncVar]
public int health = 10;

//on server
[Server]
public void TakeDamage(Bullet bullet)
{
//substract health by damage
      health -= bullet.damage;
}

PUN

//on server
public static void SetHealth(this PhotonPlayer player, int value)
{
player.SetCustomProperties(new Hashtable() { { "health", (byte)value } });
}

You might have noticed that the last section about syncing variables in PUN is quite different from the UNET version. This is because we are not actually syncing variables per se (where OnPhotonSerializeView could be a better fit), but replaced our SyncVars with player’s CustomProperties. Especially for player variables such as health or selected bullet, which do not need to be synchronized several times per second but more in an event-like fashion, custom properties save even more bandwidth than a constant update approach. Lastly, in order to support both UNET and PUN in the same Asset Store package, we are actively maintaining a separate Unity project for each version and are pulling distinct scripts into a unitypackage in a ‘main’ project. If the user downloads and imports ‘Tanks Multiplayer’, he can then choose which networking solution to use simply by importing the desired unitypackage. This also opens the possibility of supporting Photon Thunder later on – but that’s all for now!

For additional feedback or further questions, please reach out to us at info [at] rebound-games [dot] com.

Video: Albion Online – Building a PvP focused MMO with Unity & Photon Server

$
0
0

Albion Online is a fantastic mixture between Eve Online and League of Legends developed by Sandbox Interactive. The sandbox MMORPG is set in an open medieval fantasy world and comes with a fully player-driven economy where all equipment items are completely player-crafted.

Watch Sandbox’ CTO David Salz sharing their experiences and how they tackled the challenges of developing an open world MMO.

Looterkings: Re-connecting with Photon Bolt

$
0
0

This guest post was written by Frederik Reher, developer at Looterkings.

Looterkings is an indie studio founded by the Youtubers Manuel Schmitt (aka SgtRumpel), Erik Range (aka Gronkh) and Valentin Rahmel (aka Sarazar) in 2015.

Their first game, the roguelike dungeon-crawler Looterkings, has been released as Early Access on Steam in August 2016 and is currently in development.

It’s an action-multiplayer game for up to 4 players each of whom take control over a little monster-slaying goblin.

Frederik explains the difficulties the developers ran into when trying to let players reconnect to an already open game session and how Photon Bolt’s token system helped to resolve this issue.

Get ‘Looterkings’ on Steam >>

Obstacles

„How about we let players reconnect into a game?“, said the Game Designer and my job began. Up to then, we had stabilised Looterkings‘ multiplayer mode to the point where it did not crash frequently any more and where interaction between players did not cause major data desync between host and clients. We had finally implemented the ‚stacking‘ feature which enables 2 players to combine their goblins for more damage and other benefits, complete with animation synchronisation of 2 separate player-controlled units. How hard could it be?

Well, as it turns out, quite hard. At least if we had not used bolt. When we designed the
interaction system, we did not think about reconnecting. Getting it to work and getting it to
work fast were top priorities. So we ended up with a system relying heavily on global
events in order to prevent cluttering our scenes with BoltEntities. Every mushroom a goblin can pick up is synchronized using events. The same is true for crates, barrels, doors and shops.

A lifesaver – Bolt’s token system

So how to tell a clueless client everything that has happened in the level so far? In other networking solutions, we might have sent an RPC per interactive object, or – even worse -just made the objects into networked entities. But thankfully, bolt has tokens.

Tokens (named IProtocolToken in Bolt) are Bolt‘s way of serializing arbitrary data. They consist of a Read and a Write method, both accepting a UdpPacket. UdpPacket provides methods for serializing and deserializing standard data types. How you layout your data using those methods is up to you. You can add tokens to almost everything in bolt.

Whether it is a connection attempt and you want to send a passphrase to the host, whether it is spawning a unit and passing some parameters, not unlike using a constructor (the attach token is so useful, I wonder why Unity has not implemented a similar system for their Instantiate method). Tokens can also be added to entity states, player commands and, most importantly, to events.

______

public class MyToken : IProtocolToken
{
    public void Read( UdpPacket packet )
    {
        // deserialize data here
    }

    public void Write( UdpPacket packet )
    {
        // serialize data here
    }
}

______

Data of a running game

So what data does a client need when it connects into a running game? The first thing a client needs to know is how to build the level. Levels in Looterkings are procedurally assembled from pre-created Rooms, Intersections and Deadends. So the first token a
client receives after the level has loaded is the token with the level seed. Depending on the game mode, the next token a client receives contains data about a special mission players can try to accomplish for permanent buffs. Both tokens only require a single type of event which helps keeping the amount of different events manageable.

The next event sent contains information about the level‘s current condition. Our levels have multiple parts that change as players interact and progress. The most important part of those are interactive objects. To make sure crates are destroyed, mushrooms eaten and chests are open, every interactive object‘s state needs to be serialized. Our interactive objects all have an ID, a flag whether they are interactive at the moment and a byte denoting their current state in case of the object has more than two states, e.g. a puzzle using cardinal directions.

Additionally, information about rooms and doors has to be sent. Doors leading to rooms the players have not yet visited display a foggy white frame. Opening and closing doors is also done per event. This means we have to send data on whether a door is open and on whether a room has been visited before.

Lastly, there is information about the other players that needs to be sent. As alluded to in the introduction, two goblins can stack on top of each other, creating a single unit in the process. The new player needs to know who stacks with whom and who‘s on top.
Furthermore, players are surrounded by particle effects every time they level up. We send a player‘s current experience points in the attach token but since the new player is connecting into a level that may be running for minutes already, we have to provide other players‘ current experience points to prevent unwanted particle action from occurring. So the final Read and Write methods are looking like this:
______

public void Read( UdpPacket packet )
{
    // entitystatuses (ID, isUsable, state)
    entityStatuses = new NetworkEntityStatus[ packet.ReadInt() ];

    for ( int i = 0; i < entityStatuses.Length; i++ )
    {
        entityStatuses[ i ] = new NetworkEntityStatus(
            packet.ReadInt( NETWORK_ENTITY_ID_BITS ),
            packet.ReadBool(),
            packet.ReadByte() );
    }

    // doorStatuses (ID, isOpen, hasBeenOpen)
    doorStatuses = new DoorOpenStatus[ packet.ReadByte() ];
    for ( int i = 0; i < doorStatuses.Length; i++ )
        doorStatuses[ i ] = new DoorOpenStatus( packet.ReadByte(), packet.ReadBool(), packet.ReadBool() );

    // roomStatuses (ID, isCleared)
    roomStatuses = new RoomStatus[ packet.ReadByte() ];
    for ( int i = 0; i < roomStatuses.Length; i++ )
        sectorStatuses[ i ] = new RoomStatus( packet.ReadByte(), packet.ReadBool() );

    // playerStackPartnerIds (positive = on top)
    playerStackPartnerIds = new int[ 4 ];
    for ( int i = 0; i < 4; i++ )
        playerStackPartnerIds[ i ] = packet.ReadByte() - 4; // shift by -4 to revert +4 on write

    // playerCrawlStatuses (-1 = dc, 0 = dead, 1 = alive)
    playerCrawlStatuses = new int[ 4 ];
    for ( int i = 0; i < 4; i++ )
        playerCrawlStatuses[ i ] = packet.ReadByte() - 1; // shift by -1 to revert +1 on write

    // playerExps
    playerExps = new int[ 4 ];
    for ( int i = 0; i < 4; i++ )
        playerExps[ i ] = packet.ReadInt();
}

______

public void Write( UdpPacket packet )
{
    // entityStatuses (ID, isUsable, state)
    packet.WriteInt( entityStatuses.Length );
    for ( int i = 0; i < entityStatuses.Length; i++ )
    {
        packet.WriteInt( entityStatuses[ i ].id, NETWORK_ENTITY_ID_BITS );
        packet.WriteBool( entityStatuses[ i ].isUsable );
        packet.WriteByte( entityStatuses[ i ].state );
    }

    // doorStatuses (ID, isOpen, hasBeenOpen)
    packet.WriteByte( (byte)doorStatuses.Length );
    for ( int i = 0; i < doorStatuses.Length; i++ )
    {
        packet.WriteByte( (byte)doorStatuses[ i ].id );
        packet.WriteBool( doorStatuses[ i ].isOpen );
        packet.WriteBool( doorStatuses[ i ].hasBeenOpen );
    }

    // roomStatuses (ID, isCleared)
    packet.WriteByte( (byte)roomStatuses.Length );
    for ( int i = 0; i < roomStatuses.Length; i++ )
    {
        packet.WriteByte( (byte)roomStatuses[ i ].id );
        packet.WriteBool( roomStatuses[ i ].isCleared );
    }

    // playerStackPartnerIds (positive = on top)
    for ( int i = 0; i < 4; i++ )
        packet.WriteByte( (byte)( playerStackPartnerIds[ i ] + 4 ) ); // shift +4 so stack lower does not get lost

    // playerCrawlStatuses (-1 = dc, 0 = dead, 1 = alive)
    for ( int i = 0; i < 4; i++ )
        packet.WriteByte( (byte)( playerCrawlStatuses[ i ] + 1 ) ); // shift by +1 so -1 does not get lost

    // playerExps
    for ( int i = 0; i < 4; i++ )
        packet.WriteInt( playerExps[ i ] );
}

______

So now the client knows what the world around him looks like, there‘s only one thing missing: information about the client itself. Each player can buy multiple weapons, outfits and hats during a run. Only the server and the local player know what items a player possesses and this information changes how items in the shop are displayed. So we have to synchronize equipment manually as well. We can do that easily by serializing an array of ItemIDs which are basically bytes.

Round-up

So this is how we solved the problem of synchronizing reconnecting players usingBolt‘s token system. Could we have achieved similar functionality with other networking solutions? Most likely. Would it have required us to change every interactive object into some form of BoltEntity? Most definitely. Even so be aware that tokens have their drawbacks and limitations. We learned that the hard way when we bloated a token and the event refused to send it, effectively halting the game. But in a nutshell, tokens are a pretty handy tool and they made creating Looterkings an easier process.

SDK Release: Android NDK v4.1.8.1

SDK Release: Switch PUN Addon v1.86

Bannermen, a Classic RTS Game Using Lockstep with Photon and Unreal Engine

$
0
0


This guest post was written by Christoffer Andersson, co-founder and software architect at Pathos Interactive. Pathos Interactive is a game studio headquartered in Mölndal, Sweden. The studio was founded in 2015 and are currently using Kickstarter to fund their game Bannerman.

 

 

About the Game

Bannermen is an RTS game with the goal to refresh the classic RTS genre. Bannermen will contain a singleplayer campaign and several multiplayer modes, where the main tasks consist of base building, resource management and battling enemy armies. The maps and missions vary in both length and shape. The game also contains something we call dynamic environments which allows players to interact with the environment in several ways. One example of this is players being able to control different nature powers by controlling religious spots on the map. Depending on the level’s environment, different dynamic environments will be available. Our goal is to create more interesting combats with greater strategic depth while allowing the player to feel badass and in control. If you are interested in our work please check out our Kickstarter.

Choosing Lockstep

One big requirement for Bannermen was to support a modern networking solution. Nowadays most players would expect a seamless experience without having to worry about hosting, port forwarding, network bandwidth and you name it. Photon’s networking model was the perfect fit for those requirements. Since we also wanted to support a larger number of units while keeping the network bandwidth low, we chose to implement a lockstep model in Bannermen. If you not familiar with “lockstep”, it basically means that every frame is synced across all clients. It’s then enough to only send player input, keeping the network bandwidth usage minimal.

Bannermen is created in Unreal Engine 4 which is a very great engine. The only problem is that unlike Unity there is no support out of the box for lockstep at the moment. We implemented lockstep with the C++ SDK directly.

Keeping it synced

Implementing lockstep in your game will affect the whole architecture of the game and must be taken in consideration for every step in the designing process. Since every frame must be synced across all clients, input must be synced and each frame must be deterministic. Everything game logic related must be deterministic. If clients receive input a certain frame, the state must remain synced an arbitrary number of frames later. If not done correctly a big problem can arise which is desynchronization, meaning that the game must either be synced or terminated. If implemented correctly however this should never arise.

Unfortunately, desynchronization can arise in a lot ways so you have to be careful. E.g. using floats or doubles may not be deterministic across different platforms or even computers. With multithreading, it gets even harder. Multithreaded code must always result in the same state across all clients.

Input Evaluation

One problem we had in Bannermen was when two workers wanted to enter a resource at the same frame, if the resource only had room for one more worker we had to choose one worker in a deterministic way across all clients. It may sound like a small issue and it happens very rarely, but if it isn’t deterministic the game will suffer from desynchronization when it happens. It helps to always evaluate input in the same order across all clients but may not be enough. Also, we don’t want to give any player priority or an unfair advantage. This time we ended up breaking up the “enter resource” action into two phases. First allow all workers to register as candidates to enter. Then we use a deterministic random algorithm based on workers’ unique network ID that will be fair over the course of time. However, this is nothing a player can notice in practice.

 

 

Fixed Point Math

In Bannermen we wrote our own math library for fixed point math to avoid the floating-point issues. Using fixed point math, we then implemented our own navigation mesh, pathfinding, collision system, etc., all based on fixed point math. We run a separate simulation thread in parallel with Unreal Engine’s main thread. This thread simulates all the actual game logic. Then we sync the game state every frame with Unreal Engine’s main thread. This allow us to use a lot of graphical effect while still having great FPS, almost like running Unreal Engine without game logic or at least very light weight logic.

To get started implementing lockstep support in Unreal Engine I would recommend starting with implementing or using some existing fixed-point math library. You can play around with the precision or even support different amount of precision depending on your needs. Here is a very basic implementation to get started:

#pragma once
#include "FixedPoint.generated.h"
USTRUCT()
struct FFixedPoint
{
    GENERATED_USTRUCT_BODY()
    FFixedPoint();
    FFixedPoint(uint32 inValue);
    FFixedPoint(const FFixedPoint &otherFixedPoint);
    FFixedPoint& operator=(int32 intValue);
    FFixedPoint& operator=(const FFixedPoint &otherFixedPoint);
    FFixedPoint operator+(const FFixedPoint &otherFixedPoint) const;
    FFixedPoint operator-(const FFixedPoint &otherFixedPoint) const;
    FFixedPoint operator*(const FFixedPoint &otherFixedPoint) const;
    FFixedPoint operator/(const FFixedPoint &otherFixedPoint) const;
    static FFixedPoint createFromInt(int32 value);
    static FFixedPoint createFromFloat(float value);
    // use UPROPERTY so unreal engine can save the value!
    UPROPERTY()
    uint32 value;
    static const int32 FractionBits = 8;
    static const int32 FirstIntegerBitSet = 1 << FractionBits;
};

 

#include "YourHeader.h"
#include "FixedPoint.h"
FFixedPoint::FFixedPoint()
    : value { 0 }
{
}
FFixedPoint::FFixedPoint(uint32 inValue)
    : value { inValue }
{
}
FFixedPoint::FFixedPoint(const FFixedPoint &otherFixedPoint)
{
    value = otherFixedPoint.value;
}
FFixedPoint& FFixedPoint::operator=(const FFixedPoint &otherFixedPoint)
{
    value = otherFixedPoint.value;
    return *this;
}
FFixedPoint& FFixedPoint::operator=(int32 intValue)
{
    value = intValue << FractionBits;
    return *this;
}
FFixedPoint FFixedPoint::operator+(const FFixedPoint &otherFixedPoint) const
{
    int32 result = value + otherFixedPoint.value;
    return FFixedPoint(result);
}
FFixedPoint FFixedPoint::operator-(const FFixedPoint &otherFixedPoint) const
{
    int32 result = value - otherFixedPoint.value;
    return FFixedPoint(result);
}
FFixedPoint FFixedPoint::operator*(const FFixedPoint &otherFixedPoint) const
{
    int32 result = value * otherFixedPoint.value;
    // rounding of last bit, can be removed for performance
    result = result + ((result & 1 << (FractionBits - 1)) << 1);
    result = result >> FractionBits;
    return FFixedPoint(result);
}
FFixedPoint FFixedPoint::operator/(const FFixedPoint &otherFixedPoint) const
{
    int32 result = (value << FractionBits) / otherFixedPoint.value;
    return FFixedPoint(result);
}
FFixedPoint FFixedPoint::createFromInt(int32 value)
{
    int32 newValue = value << FractionBits;
    return FFixedPoint(newValue);
}
FFixedPoint FFixedPoint::createFromFloat(float value)
{
    int32 newValue = value * FirstIntegerBitSet;
    return FFixedPoint(newValue);
}

 

The only parts that may not be trivial are multiplication and division. Basically, if we multiply two 24.8 fixed point (i.e. 24 bits for integer part, 8 bits for fraction part) we will end up with a result that looks like 48.16. If we want the result to be in the form of 24.8, we simply ignore the upper bits of the integer part like an overflow. Then we shift right 8 bits in this case, resulting in a truncation of the 8 lowest fraction bits. There exist good articles regarding this subject for those who are interested in reading more. E.g. https://www.codeproject.com/Articles/37636/Fixed-Point-Class or http://x86asm.net/articles/fixed-point-arithmetic-and-tricks/.

I don’t recommend using the create from float method in game logic but it can be handy to initiate values from the editor that then can be saved. More operators and math function can of course be implemented and even exposed to blueprints easily (Unreal Engine’s visual scripting).

Last thing I must mention is how one can see the fixed-point value in an understandable format when debugging. I recommend using a “natvis” file to visualize the value as a float or double to make life easier. Here is an example with and without a “natvis” file.

Without “natvis” file:

With “natvis” file:

“natvis” file:

<?xml version="1.0" encoding="utf-8"?> 
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
  <Type Name="FFixedPoint">
    <DisplayString>{{{(double)value / FirstIntegerBitSet}}}</DisplayString>
  </Type>
  
</AutoVisualizer>

 

In Visual Studio 2017, the location to place a “natvis” file is something like “C:\Users\<username>\Documents\Visual Studio 2017\Visualizers”, depending on your setup.

Finally, it was a lot of work to implement lockstep for Bannermen in Unreal Engine. However, now when it’s done we can use the full power of Photon. Also, our design has drastically improved the performance compared to an early prototype we had running purely in Unreal Engine. The network bandwidth has been drastically reduced and since our simulation tick is running in parallel with Unreal Engine’s main thread, we have freed-up resources to do more cool stuff. Overall, we find the Photon integration combined with lockstep model to be a perfect fit for Bannermen and Unreal Engine.

 

Happy hacking!

Christoffer Andersson
Co-founder & Software architect, Pathos Interactive


SDK Release: PUN v.1.87

Photon Bolt: Fair Pricing or “Shameless money-grab”?

$
0
0

“On coming out of Beta, Photon have now decided that not only relayed clients but also fully peer-peer connected players will use up CCU allowances, which the developer has to pay for. So one of the main benefits that Bolt used to have, i.e. no server costs, has been snatched away.”

The above quote is a review about Photon Bolt by user psychicsoftware and published in the Asset Store. So far so good, but its headline is a real punch-in-the-face for us: “Shameless money-grab”. It is easy to guess that we completely disagree, but it seems that some people consider Photon Bolt’s pricing as inappropriate or even “shameless”.

The main reason behind this negative view is very likely that “fully peer-peer connected players will use up CCU allowances”. Yes, that is correct and we have discussed a lot if there is a better pricing option for us. You might think “hey, simply lower your pricing or change it, so p2p connected players are not counted against CCU allowances”, but here are the reasons why this is not really an option:

We want to offer future-proof products – not falling stars

You invest a lot of time and money in developing a great game and we want to be the partner you can rely on. Therefore we continuously update and improve Bolt for you. Not only this year, but also next year and the year after, and … you get it.

We are in the networking engine business since 2004 and we know the numbers: with e.g. a $100 one-off payment you cannot build-up a sustainable business, so we needed to change the Bolt pricing in order to provide you a product with long-term reliability. You should expect nothing less from a product in order to protect your own work.

There have been popping up networking packages in the Asset Store from time to time that charge only once and you can use them forever, but while those packages are slowly abandoned, Photon is stronger than ever and, most important, battle-proven by actually launched and successful games.

We know that our pricing has never been an issue for our customers

Ok, that is something that you might believe or not, but this is hopefully a convincing argument: PUN costs the same as Bolt and PUN is a successful product since years: if the pricing would be an issue for our customers, we would be in trouble and you would likely have heard or read about it.

Interestingly, when our customers are becoming successful with their games and their CCUs are growing to +3,000 and more they usually want to switch to Photon Enterprise to get e.g. priority support, as they are generating significant revenues.

Although Photon Enterprise costs them more per CCU, they understand the value of Photon: they can fully concentrate on improving their game to further grow their revenues while Photon takes care of devops, availability and scalability.

We believe our pricing is the fairest on the market (and likely the lowest)

Often people starkly misjudge the amount of CCU needed. Let me give you an example:

Rule of thumb: DAU = 20 x CCU and MAU = 20 x DAU
Example: 1,000 CCU = ~20,000 DAU = ~400,000 MAU

That means your game must have been installed on at least 400,000 devices in order to generate 1,000 CCU. Realistically your game is rather installed on about 600k-1million devices (actual value is depending on your user retention rate):
you won’t have any issues paying the $185 for Photon 1,000 CCU in case your game has at least some sort of monetization.

600k-1million installs and $185/month for Photon which includes a global cloud. We think that is an extremely fair deal especially as we include loads of traffic in our plans. The included traffic is calculated to be sufficient for even fast action games so you do not have to pay any overages. In the 1,000 CCU plan from the above example you get 3TB data traffic included which boils down to $0.05 per GB. Unity charges $0.49/GB which is nearly 10x more. That’s why we think our pricing is likely the lowest.

The general idea behind our pricing is to provide you a ‘worry-free’ path for your game’s life-cycle:
a) Pre-launch phase – you can use the free version (yep, Photon Bolt Free is coming) as long as you like. The included 20 CCU are enough for developing and testing your game. Or for playing around. No obligations, no costs.

b) Launch-phase – if you want to launch your game we recommend to choose a Photon plan with 500 CCU as it features ‘CCU burst’. It means that you can exceed your included CCU allowance and no user is blocked out from your game. We allow you two days – often much more – to upgrade your plan. That allows you to start with a small plan that you can upgrade whenever needed. No risk and predictable costs.

c) After-launch phase – in case your game is performing better you can upgrade anytime and you won’t loose any tracktion as Photon scales seamlessly. You pay only what you actually need.

d) End-of-lifecyle – in case your game is not performing as you hoped or your game reaches the end of its life-cycle you can simply downgrade to the free plan or choose the 100 CCU plan which is enough for most games anyway.

We are not Steam

Sometimes we are compared to Steam and their “free” Steamworks API. As you have to hand them over 30% of your revenue it is not really a free service and Steam can use the revenues to cover its costs for Steamworks. If you want to use Bolt with Steamworks we still charge per CCU as we cannot cross-subsidize. If you use Photon Bolt you have the huge advantage that you can port your game to other platforms including consoles. If you do not need that: Bolt still is a great networking engine.

And remember: when your game is not a success, you hardly pay us anything. If your game is a success, you will be happy to have a rock-solid engine that costs you only a very tiny fraction of what you earn.

Our advice: choose the technology which you like most and go for it.

 

 

 

 

 

Tome of Heroes – Making a Game by Yourself

$
0
0

 

This guest post was written by Stefan Pulciu, founder, developer and designer of Tome of Heroes.

Tome of Heroes is a real time player versus player game designed for mobile devices. It’s set in a fantasy world in which you build a team of heroes around your strategy and fight in the arena versus other opponents from around the world.

Stefan began working on it in October 2016 and published it as an open beta on both iOS and Android in April 2017. He’s still working on updating and adding new content to the game. Some of the things he’s working towards are dungeons & story lines and an open world system that combines both PvP and PvE.

 

 

The Intro

My name is Stefan Pulciu and I’ve been fortunate enough to be born around the time when PC video games first came out. By the time I was 10, I was already hooked on multiplayer games like Diablo and Counter-Strike and competing versus other people at LAN cafes. A few years later I got into graphic design doing fan art and slowly but surely I became a web designer and front-end developer.

All this time, I kept playing all sort of player versus player fantasy games and constantly dreamt to make a game of my own one day. It was that type of dream that you fantasize about during long car rides or during flights while staring out the window. About 15 years later, in October 2016, after working as a web design director for 2 years at a company in San Francisco, I decided it was time for something new and I figured that this was as good of a time as any to finally “bite the bullet” and give game development a try.

My dream was to make a game similar to the ones that I’ve been playing all these years, a fantasy game with awesome heroes, magical abilities and of course player versus player combat. While I have tried out Unity in the past and even completed the “doughnut tutorial” in Blender a long time ago, I didn’t remember much so I had to start over from scratch. I decided to drop everything that I was doing and focused entirely on the magical world of learning the ways of game making. Shortly after I got started, I quickly discovered that anything other than a mobile game would have been too much for one person to handle so I settled on building just that.

 

The Visuals

There wasn’t much need for 3d modeling or texturing in web design so I didn’t know a lot about it. I didn’t even know which software I should learn, but since I wanted to publish something and maybe even make some money with it, I figured Blender was the perfect choice for me, since it was free. When working by yourself on a project like this, all of your resources are pretty limited and money was no exception. I had just enough funds saved up to keep me going for a few months, maybe a year.

The first thing that I needed to consider when I built the visuals was that I really wanted the game to run smoothly even on devices that were 3 or 4 years older. That required a bit of optimization work on my end. I found two main aspects to be really important and that’s a smaller poly count for my geometry and packing my textures really well into as few texture atlases as possible. It’s “easier said than done” though and at first I really struggled building anything that I was happy with. Eventually though, after a lot of practice and analyzing, trying to figure out how other people built their models I figured it out. The trick was to try and simulate as much of the shadows and 3d details through textures instead of geometry.

‘Halfway There’

At each step of building my project, I constantly heard that I was halfway there. When the visuals were done, I was halfway there because I still needed to code the game mechanics, when those were done I was halfway there because I still needed to build the networking, when that was done I was halfway there because I needed to build the databases, user data and interface for it and when that was done, I was halfway there because marketing is just another domain of its own. That’s not far from the truth though as each of these steps are pretty complicated so I could say I guess that my loading bar has been stuck at 50% for some time now.

 

The Game Engine

Picking a game engine was the next step that I had to decide on. I had played around with Unity a few years back and all the reviews and forum posts that I read spoke nothing but great things about it as a game engine for mobile games. It also helped that there was a great amount of documentation, free project files, tutorials and so forth on how to do just about anything.

 

 

 

 

Unity Multiplayer vs. PUN

The next step in my journey was to pick a platform that would help me turn my game into a multiplayer one. For me, this was the most difficult decision in the entire project as I didn’t know anything about how multiplayer worked and what I would need for my game. Even though I was able to find a lot of blog or forum posts that compared all the available solutions, I didn’t know which characteristics would be important for me. I decided to move forward with Unity Multiplayer as that felt like the natural thing to do. They built the game engine so surely their multiplayer platform worked best with it. I can’t say anything negative about my experience with their service, however a few weeks later I decided to switch to Photon and I have to say that I’ve been very happy since.

One of my main concerns was that while the things that were being discussed in blog posts, forums and in Unity’s presentations sounded great, it didn’t feel like things were progressing very fast with Unity Networking. There wasn’t much information on the roadmap page about networking and at the time I found some presentations of “features to come” that were close to a year old and still not implemented.

As a result, I got the feeling that Unity’s Multiplayer platform was more of a secondary service they were providing and not something they were really focusing on. On the other hand, on Unity’s own forums I was constantly seeing updates on Photon’s posts with patches and fixes being released all the time. So my mindset changed from “surely Unity Multiplayer is the way to go, since they also made the game engine” to “maybe I should pick a platform whose main focus is multiplayer since they’ll put all their time into it”.

 

Pricing

For me pricing felt like a no-brainer and for obvious reasons. It didn’t take a genius to realize that Photon’s price of $0.05-$0.10 per GB of bandwidth (depends on region) was much better than Unity’s $0.49/GB. With Photon I also got 3GB of bandwidth per concurrent user for free so if I managed to do a great job at optimizing my game (which I did), I might not even have to pay for bandwidth at all.

Concurrent users (CCU) was something else that I needed to consider and with Unity I got 20CCU for free just like with Photon which was great for development and testing. If I wanted more though, Unity charged $35/mo for 50CCU or $125/mo for 200CCU. With Photon I was able to get 100CCU for 60 months for a single payment of $95 and I could also add another 500CCU if things went well for $95/mo which amounts to 600CCU in total which is 3 times more than what I could have gotten with Unity and $30 cheaper at the same time.

Even though all of this is from the perspective of a new and indie developer, it’s a bit hard to argue with the numbers. You might even think that maybe there’s a catch or maybe the quality isn’t that great, but from my personal experience at least, everything’s been great so far!

 

Traffic Optimization

Moving a hero from point A to point B can be done in many different ways. In the games that I’ve played, characters moved depending on which keys were being pressed. If you pressed forward, it would go forward, if you pressed right, it would move to the right. I also found some mobile RPG games that used a joystick in order to output a similar type of character control. The issue with this sort of movement however is that you have to constantly sync up your position with other players so you’re constantly sending data through the cloud server.

 

What I decided to do is to use an RTS type movement where you simply just tap on the ground to have your hero move to that location. This way, instead of having to constantly send data about the location of my hero, I only needed to send the destination point and the rest is handled on each player’s device.

Better yet, if you don’t have any elevation, you don’t even need to send a Vector3, you can just send the X and Z position as the Y doesn’t change. Even better, you can also convert the X and Z from floats to ints to decrease the size of the data as the position doesn’t need to be that specific. So as a result, players in my game are generally sending 2 ints every 1-2 seconds, depending on how fast and good they are at the game. New players, instead of costing me money for trying out the game, will likely use even less bandwidth than someone who plays regularly because they’re a bit slower at it.

 

Marketing

Often it’s not important what you’re selling but how you’re selling it. Regardless of how good your game is, you need to be able to promote it well enough so that people are interested in trying it out. This part of the project however is unique for every game and how you reach your potential players is up to you. You can advertise it through common platforms like facebook, twitter or youtube with posts, videos or even static images, you can try to find some streamers to review it and endorse it, join some communities of gamers who are interested in the same genre as your game or just hire someone to do that for you. I don’t think there’s a clear recipe for success  and you may find that the options that yield the best results may change depending on where your game is in terms of growth.

From my experience, starting from scratch, I found the best results to come from more “organic” channels. I introduced myself and my game on various forums or community websites and I interacted with the readers that replied to my post. This made my post stay popular for longer and a large percentage of the views converted into app installs as people wanted to try the game out and comment on it. By comparison, I also tried advertising on those same websites or platforms and even though analytics showed a high view number, a very very low percentage of those views converted into installs. So my conclusion is that it’s better if you can advertise and market your game while interacting with your audience directly. I’m sure advertising works well too as it’s a thriving business, but you need to be ready to spend quite a bit of money to get similar results. While you’re just getting started though, I would recommend spending that money on an awesome trailer and other marketing assets and trying a more “organic” route for spreading the word.

 

Conclusion

For me, the most important part in all of these steps was to keep an optimistic and positive attitude towards the work that I was doing. Each part felt like a mountain impossible to climb at first, but by taking things one step at a time I was able to learn and complete all the tasks that I set out to do.

So if you’re working on a game by yourself, don’t worry, even though it’s a lot of work, keep at it and you’ll get there! After all, you’re already halfway there 😉

You can learn more about my game ‘Tome of Heroes’, watch its awesome trailer and download it at www.tomeofheroes.com.

 

   
appstore android

SDK Release: Windows SDK v4.1.8.3

Buggy Blasters – Multiplayer HoloLens Considerations

$
0
0

 

 

This guest post was written by Bernard Francois, Kasper Geeroms, Matthew Cormack, and Jannes Plyson, respectively founder, project manager, and programmers of PreviewLabs, a company specialized in rapid prototyping with game technology. PreviewLabs was founded in 2010 and has been using Photon since 2013.

 

Buggy Blasters is the first multiplayer HoloLens game concept to appear on the Microsoft Store.  It’s single player mode allows driving a virtual RC buggy around in your living room, and the multiplayer mode turns it into a two-player real-time strategy concept with a hybrid of capture-the-flag and defend-the-base mechanics. The multiplayer mode works for two players in different locations, or as a shared holographic experience within the same location.

PreviewLabs developed the concept on request by it’s parent company Cronos Groep, who gave them carte blanche to come up with an interesting case for the HoloLens – and this is what we learned…

 

Getting to a Shared Play Space: Possible Approaches

Through the use of a feature called spatial mapping, the HoloLens generates a 3D mesh of your environment, which can be used for instance for z- buffering (allowing virtual objects to appear behind real world objects) and collision handling. This can greatly enhance the feeling of presence in augmented reality – the feeling of seamless integration of virtual content with the real environment.

 

Objects such as the buggy and traffic cones are able to interact naturally with the environment by using the environment mesh as a collider.

However, in a real-time competitive multiplayer game, you want to make sure to have a level playing field. Let’s take a look why it could lead to unfair situations if you would simply allow each HoloLens to use it’s own mesh in a game like Buggy Blasters:

  1. When the exact shape of the mesh has an impact on the gameplay (e.g. slight bumps in the floor surface mesh leading to variations in driving speed), players can feel disadvantaged.
  2. When real-world objects occlude the game, it could mean a serious disadvantage in the multiplayer game. You may simply miss that your opponent just stole your flag!

Note that this can be important even when you’re playing with two HoloLenses in the same physical location, since due to variations in the scanning process, no two meshes of the same room will be exactly the same.

Now here are two approaches that can be used:

  • Comparing the meshes generated by the two HoloLenses, and taking the differences into account in order to get to a single, shared mesh.

    When the two players are in the same room, the average between the two meshes could be taken, while also speeding up the scanning process by adding the results of the two HoloLenses together – allowing your HoloLens to gain understanding of a part of the space it didn’t even see yet.

    When the two players are not in the same room, the furniture from one player’s room could be copied to the other’s, and vice versa. For instance if you have a coffee table in the middle of your room, while I have a recliner, you’d get my recliner virtually added to your room, while I’d get your coffee table, so we both end up with the same environment. The furniture from the other player that gets ‘imported’ into your room could be visualized with a simple abstract shading effect.

  • Throwing everything away, and using a simple plane at the floor height, obtaining a perfectly level playing field. And heck, since we’re a prototyping company, we just went with this – after all, we like to get to something playable quickly.

 

To play Buggy Blasters, two players with the HoloLens can define a rectangular play space, in order to get to a common ‘play space’ based on the overlapping part of the two rectangles.

Since the game needs to take place in a shared space that is fair for both players, this play space needs to have the same size for both. It would definitely not be fair if your opponent with a larger living room would be able to hide behind – how you would perceive it – your wall. We used a very simple approach for this:

  • Each player defines a rectangle of free floor space. In the case of Buggy Blasters, this is done by tapping the floor to place traffic cones. The first corner of the resulting rectangle is seen as the origin of the play space.
  • We then combine both play spaces and choose the overlapping rectangle of the two spaces as the multiplayer play space.
  • Network communication about positions and rotations is all done relative to the origin of the combined play space.

Once this is implemented, playing in the same room with two HoloLenses becomes easy: all you have to do is to set up exactly the same play space on each HoloLens by having both players put their cones at exactly the same position. This definitely does the trick for a prototype!

Developing Efficiently for HoloLens with Unity

To get a Unity project running on a HoloLens, a Visual Studio solution is built. From there, you can build and deploy to the HoloLens. For the Buggy Blasters project, the whole process takes around 5 minutes. Testing the multiplayer gameplay meant that each time we had to deploy to two HoloLenses.

This is how we worked more efficiently, avoiding a long build-and-run loop:

  • Simulate moving around and Air tapping in the Unity Editor using an Xbox controller, speeding up the development.
  • Since you can’t wear two HoloLenses at the same time, it would be hard to have a single programmer test multiplayer features. Therefore, we allowed testing with a single HoloLens, while the other player client was tested in the Unity editor. This was made possible by setting up a Unity scene containing a saved scan of a room (since scanning a room is not possible without the actual HoloLens device) as well as a pre-set up play space.

For more info and download, see the Buggy Blasters page.

 

Photon Quantum – Join the Multiplayer Revolution

$
0
0

Introducing Photon Quantum

Quantum revolutionizes the way fast-paced multiplayer games are build. A revolution is always started by a few leaders and we spent over 2.5 years to develop Quantum before we gave it into their hands:

Quantum is a deterministic realtime multiplayer engine for Unity. It is the perfect engine  for MOBAs, RTS, brawlers, sports games, fighting games and other types of fast-paced action games.

Quantum speeds up your development process dramatically as your game code simply does not need to take into account that your game is multiplayer.

 

Deterministic Architecture1 – No Lockstepping – Blazing Performance

Photon Quantum extremely brushed performance allows e-sports grade multiplayer game development on all platforms, including mobiles, and runs in the Photon Cloud.

Key highlights are:

  • Super-low network overhead: send only inputs between players
  • Fully deterministic, state-of-the-art prediction/rollback simulation – without lockstepping
  • No network interpolation required, no artificial delay for game state interpolation
  • Blazing fast performance: Quantum game demo “Dropship Down” runs  at 2,000- 10,000 Hz

‘Dropship Down’ – Quantum Game Demo

Dropship Down is a realtime shooting demo made with Quantum. The video capture below shows a match between a player in Sweden (server ping 50ms) and a player in Brasil (server ping 260ms). It shows perfectly how Quantum eliminates lag and make the match a smooth experiences for the players.

 

Join the Revolution?

We are searching for great teams who want to leverage the full potential of Photon Quantum. Are you one of them?

Then please email to developer@exitgames and tell us what greatness you are planning to achieve with Quantum.


Roman Graebsch, Producer at SYBO Games


Linus Ekdahl, Senior Game Developer at Like A Boss Games

   

 


1 Some excellent background information about basic deterministic networking can be found here. Please note that Quantum goes far beyond these basics and does not require lockstepping.

 

 

 

 

Streamlined Photon Product Portfolio: TRUESYNC fuses into QUANTUM, THUNDER Development Ceased

$
0
0

In the last two years we introduced new products to our portfolio to better tackle the different challenges in multiplayer development. But with the growing portfolio it became more difficult for our customers to understand the differences between them.

We decided to streamline our portfolio and focus on less products:

This mainly affects two Photon products: TrueSync and Thunder.

But no rush: Photon protocol support for existing TrueSync or Thunder customers will continue, but we highly encourage customers to plan a migration to our other existing and new products.

Photon TRUESYNC: Fused into QUANTUM

Photon TrueSync and Quantum are both deterministic products and the initial idea was that TrueSync has a focus on ease of use (Unity style/approach using game-objects and behaviour scripts), while Quantum is all about high performance and support for fast-paced action and sports games.

In the past months it became obvious that Quantum is the next evolutionary step for us:

  • High performance: Custom physics and pathfinding. Allowing the simulation to run up to 10k Hz on a PC.
  • Fully decoupled, self-contained simulation with clear interfaces to the “view”.
  • Using a modern ECS (Entity Component System) approach with a  DSL (Domain Specific Language) to model the state.

Major Quantum parts came from an acquisition of a technology that was developed over the period of several years. This was then fused with TrueSync.

Customers who are actively using TrueSync can continue doing so, because the Photon transport protocols and relay servers will continue to support it for the time being. While there is no rush to change from TrueSync to Quantum, we encourage you to discuss the advantages of Quantum with us and to plan the migration to its higher performance and future proof API.

Photon THUNDER

With Thunder our mission was to provide the best cloud service for Unity’s UNET by leveraging Photon Cloud’s proven matchmaking, relay and punch-through service. Technically Thunder is a shell around the existing UNET – so in its core Thunder relies on Unity driving UNET forward.

We still believe the Thunder idea is good, but the development of UNET (and the HLAPI in particular) seems stalled and not driven forward by the Unity team. This was unexpected and so we recommend all Thunder customers to switch to Photon Bolt or even PUN.

The current quality of UNET and low market demand made us decide to cease any further development of Thunder. If you are actively using Thunder, you can still do so, but we will not provide any updates.

Please look into Bolt which is delivering on the Thunder promise and superior to UNET in most aspects (see the comparison table below). We offer source code access for selected Studios well.

 

UNet vs. BOLT Feature Comparison Chart

 


Pantropy – Massive Performance Boost by Using NetworkArrays / Photon Bolt

$
0
0

This guest post was written by Julian Kaulitzki, lead developer for Pantropy at indie game studio Brain Stone.

Pantropy is a faction-based, SciFi-themed mech-game  for PC and is, at the time of writing, in closed-alpha. Pantropy will eventually allow up to 128 players in one joint session. Conquer an alien world, farm ores, build bases and craft various items such as weapons and vehicles to defend yourself from players of the other faction and AI controlled mobs.

For more information about the game please check out Pantropy’s Kickstarter campaign.

 

Game Performance Issues During Pre-Alpha

In late 2016, we publicly launched a pre-alpha demo where players would test various features of our game. One of these features was building your own base using parts like foundations, walls, floors, generators, furnaces, and many others. During the pre-alpha we noticed that the server and client performance declined over time. Sometimes it got so bad that we had to wipe the servers.

We found that the frame rate was proportional to the amount of active BoltEntities on a server after some debugging. So with 10 players online, where each one had a base that likely exceeded 100 parts and each part having a BoltEntity attached, we ended up with 1000+ active BoltEntities at a time. Quite a lot.
(Quick disclaimer: we did not utilize scoping/freezing/idling/priority calculation during that time.)

The Solution

We were in need of a system that would use less BoltEntities without compromising the gameplay or the size of bases. The parts you would use to construct your base can be split into two main groups:

Passive parts – These parts only need to synchronize the following values over the network: Position, Rotation, Structural Integrity, Health and a PrefabID. For example: foundations, pillars, walls and, floors.

Active parts  – These parts need to synchronize more values than what is listed above. Parts like Generators, Furnaces, Storage Boxes and, Crafting-Stations store items and some extra values regarding electricity.

95% of a base consists of passive parts and, since they need to synchronize very little information, we figured tostore their data in a NetworkArray_Objects instead of individual BoltEntities.

A NetworkArray_Objects is a bolt class that stores BoltObjects in an array on a state.
In this case the
NetworkArray stores BoltObjects of type BaseElement_Obj.
Each of these BoltObjects represents a passive part of a base, so, naturally, a BaseElement_Obj stores the following values:

Position (Vector3) – Where the BasePart is located in World Space.
Rotation (Quaternion) – The orientation of the BasePart in World Space.
Structural Integrity (float) – How stable is this part.
Health (int) – How much health the part has.
PrefabID (int) – Not to be confused with the struct that comes with bolt that is also called PrefabID. This value is used to identify part types.
IsSpawned (bool) – Determines if this entry of the NetworkArray is a unused.

Bolt limits each state to a maximum of 1024 properties so the array can only be 170 entries long.

The BaseElementsManager is a script that inherits from Bolt’s EntityBehavior. It has on its state a property called “BaseElements” on its state that isa NetworkArray of type BaseElement_Obj.(see picture above).

Now here comes the important part:

Its main function is to store the data of passive parts and to handle the proxys of this data.
A proxy is a simple GameObject, without a BoltEntity attached, that represents an entry in the NetworkArray.
So every entry that is marked as “IsSpawned = True” has a GameObject(the proxy) in the world with which the players can interact. In this case the proxies are parts of a base.

A base can be made from more than one of these BaseElementsManagers so we need another script that manages all of these. The BaseManager script handles requests to add/remove/alter a passive part and manages the BaseElementsManagers of one base. For example, if we want to add a new part to the base but the base already has 170 passive parts-which means that the current BaseElementsManager‘s NetworkArray is full-a new BaseElementsManager is spawned and used to store the data of the new part.

The callback OnBaseElementsStateArrayChanged inside of the BaseElementsManager script is then called hence the NetworkArrayBaseElements“ changed.  The HandleBaseElement method is then called by passing the arrayIndex of the changed entry inside of the callback. The method HandleBaseElement then checks if the changed entry is marked as “IsSpawned = True” and, if this is the case, it checks if there is already a proxy; for that entry. If there is no proxy for that entry then it spawns one.
However, if the entry is marked as “IsSpawned = False” and the entry has a proxy, then this proxy will be removed.

private void OnBaseElementsStateArrayChanged(IState s, string path, ArrayIndices indices)
    {
        int ArrayIndex = indices[0];
        HandleBaseElement(ArrayIndex);
    }

    private void HandleBaseElement(int arrayIndex)
    {
        // state.BaseElements is the NetworkArray of type BaseElement_Obj
        BaseElement_Obj element_Obj = state.BaseElements[arrayIndex];
        if(element_Obj.IsSpawned)
        {
            // ProxyBaseElements is an array of type BaseElement with a length equivalent to the NetworkArray
            if (ProxyBaseElements[arrayIndex] == null)
                SpawnBaseElementProxy(element_Obj, arrayIndex);
        }else
        {
            if (ProxyBaseElements[arrayIndex] != null)
                RemoveBaseElementProxy(ProxyBaseElements[arrayIndex], arrayIndex);
        }
    }

Keep in mind that the callback to the NetworkArray is called whenever an entry’s value changes. So when the Health of a BaseElement_Obj inside of the NetworkArray is changed the callback is called.

Some Tweaks

In order to prevent memory leaks, we pool our proxys. We have a routine running on each BaseElementsManager that checks if the player is nearby and if so it should spawn a proxy. If not, then it should add the already spawned proxy back into the pool so another base can use it.

Whenever a new part is added/removed we calculate the average position of all of the passive parts to get the center point of the base. We then move the BaseManager and BaseElementsManagers to this point. Now we can use their positions for scoping/freezing/idling/priority calculations.

Conclusion

Using proxies to represent data stored in a NetworkArray in combination with scoping/freezing/idling/priority calculations is more efficient and easier than managing thousands of individual BoltEntities.

With this system, we were able to reduce the BoltEntity count for passive parts of ten bases from 1700 to only 10!

The same system finds place in our ores. We have 5000 ores scattered around the world and every one of them was originally an individual BoltEntity. We are now using 15 OreNodesManagers each one has a BoltEntity attached and manages 340 ore nodes.

You could also use this system to scatter trees around the world using a seed and manage 500 trees with only one BoltEntity.

Here are some numbers on how the performance improved with the proxy system:
I created a little script that spawns a cube that is made out of 3380 individual parts.

The cube’s dimensions: 13w x 13l x 20h

In the first run of the test, every part had a BoltEntity attatched. Each entity was active meaning it was not in idle or frozen. This resulted in an overhead of 32.20 ms caused by Bolt’s BoltPoll.FixedUpdate loop.(highlighted in the screenshot below)

The second testrun was performed using my Proxy system. So there were 25 BaseElementsManagers each one managed 140 proxys.  This means that the entire cube consits of only 25 BoltEntities. Each entity was active meaning it was not in idle or frozen. The result of that was 0.69 ms of Bolt’s BoltPoll.FixedUpdate loop. (highlighted in the screenshot below)

If you are interested in the resulting game or have any other question, please check out our Kickstarter:

SDK Release: Switch PUN Addon v1.86

$
0
0
SDK UpdateYou must be logged in and a verified Nintendo Switch developer to download this PUN addon.

Bannermen, a Classic RTS Game Using Lockstep with Photon and Unreal Engine

$
0
0
This guest post was written by Christoffer Andersson, co-founder and software architect at Pathos Interactive. Pathos Interactive is a game studio headquartered in Mölndal, Sweden. The studio was founded in 2015 and are currently developing...

SDK Release: PUN v.1.87

$
0
0
SDK UpdateChanges in PUN v1.87 Notable changes since 1.86: Fixes to demos and websocket implementation Performance update to RPC calls New selectable region Russia Download from https://www.assetstore.unity3d.com/en/#!/content/1786

Photon Bolt: Fair Pricing or “Shameless money-grab”?

$
0
0
“On coming out of Beta, Photon have now decided that not only relayed clients but also fully peer-peer connected players will use up CCU allowances, which the developer has to pay for. So one...
Viewing all 41 articles
Browse latest View live