Photon Cloud API

UNREAL PLUGIN - QUICK SETUP

Made by Juan Belón - 2019 - Documentation made for Unreal Engine from 4.25
_____________________________________________________________________________________________________________

How to use Photon Cloud API plugin v1.6+

The third person example is just a quick example of how to start: https://github.com/juaxix/photon_api_ue4_sample/tree/master/UE4_256

Take a look ,test the projects, copy the method and try, then tell me how it went!

Unreal Online Subsystem versus Photon Cloud

The flow of the prototype system(using Onlinesubsystem) is -

1. The user opened the application and was presented with a menu to create or join a session. If they created this session they could set the number of players, name of the room and whether it was a LAN/Internet session.

With PhotonCloud plugin you just need to create your own Blueprint or C++ class inheriting from the UPhotonCloudObject class from the plugin and specify it in the project plugin preferences -blueprints- and in the code there you will add your network logic in a transparent way, this object will live in the Photon Cloud Subsystem instance (like a singleton per editor or client instance) from the moment the game is initialized. You will need to have 4.25 or 4.26 versions though. (4.24 still uses an old approach with the deprecated actor in the scene). In that PhotonCloudObject api -blueprint- logic you just do the same as with the OSS from Unreal, you create your hud and widgets, create the connection choosing the region ,server, and then join a lobby room or a game room, you can only use internet sessions with a Photon Server, unless you get the PhotonServer from Photonengine.com and launch it in your own machine, then you change the IP of the server and the type in the configuration.

2. Once this session was created, the host is placed in the default lobby map and other users could join by connecting directly via IP. All players now are located in this lobby map, which in our situation acts as the main hub.

This is something you do with delegates, you can load a map once you join the room, for example a waiting room like Among Us has, the subsystem is permanent during the game and the connection is kept by the tick from the engine. You spawn the players and you create replicas of the players when they join the room (the projects show examples)

3. This of course means the first user to create the session had server authority over the clients, and handled spawning, seamless travel between maps (lobby into game) etc.

With PhotonCloud the server authority is different, you can only change your own player properties , but there is a master player you can use to authorize over other clients using RPCs in the shape of sending actor data and sending player data, but the best way is setting room properties. The seamless travel is not needed for these properties, because they live in the server, but they are necessary for other actors that have variables and things you need in other maps.

4. From the lobby, the host can move the group into these real world maps (and back into the lobby).

You have 2 types of rooms, lobby rooms and game rooms. When you connect to photon you can auto join a lobby room and from there make queries for all the rooms available but once you create a game room, you need to add properties, and mark what of those properties must be readable from lobby room mode (without joining the game room), the logic to move groups between rooms must be done in the server or in the game.

Example:

PhotonCloud for Unreal v1.6 - now using a Game Instance subsystem

Playfab is a good choice to use together with Photon!.

Photon SDK Update

-if you already did this,skip to plugin setup-

For a reference project please go to

https://github.com/juaxix/photon_api_ue4_sample

  1. Download all the photon sdks you want to use in your project from:

https://www.photonengine.com/en-US/sdks#realtime

2. Copy the files from the SDKs to the plugin thirdparty Photon directory
copy the include files (.h)

Go to each, Common-cpp, LoadBalancing-cpp and Photon-cpp

and copy their inc directory to the corresponding Plugins\PhotonCloudAPI\Source\ThirdParty\Photon\Common-cpp\ , LoadBalancing-cpp and Photon-cpp directories

You may up having an structure like this

copy the libs files (*.lib)

copy the contents of each SDK->[Common-cpp|Load-Balancing-cpp|Photon-cpp]->lib  directory to Plugins\PhotonCloudAPI\Source\ThirdParty\Photon\libs

so you will end up with a structure like this

3. Modify the Photon headers to workaround any incompatibility with the UE4 headers

3.1: rename all FLOAT to EG_FLOAT in these files (case sensitive)

- Photon/Common-cpp/inc/Enums/TypeCode.h (around line 18)        
        - Photon/Common-cpp/inc/Helpers/ConfirmAllowed.h (around line 46)
        - Photon/Common-cpp/inc/Helpers/ConfirmAllowedKey.h (around line 73)

3.2. Left only this two precompiler checks in file
        
Photon/Common-cpp/inc/Helpers/TypeName.h around line 14

================================================

#if defined _CPPRTTI || defined __GXX_RTTI

================================================

3.3. If you want to compile for Android, remove all the JString template definitions (you will need to do your own if you want to compare JString from the plugin):

     - File: Photon/Common-cpp/inc/JString.h

     So comment all these functions (definition and implementation!!): //---------
/*
template<typename Etype> JString operator+(const JString& Lsh, const Etype& Rsh);
template<typename Etype> JString operator+(const Etype& Lsh, const JString& Rsh);        template<typename Etype> bool operator==(const JString& Lsh, const Etype& Rsh);        template<typename Etype> bool operator==(const Etype& Lsh, const JString& Rsh);        template<typename Etype> bool operator!=(const JString& Lsh, const Etype& Rsh);       template<typename Etype> bool operator!=(const Etype& Lsh, const JString& Rsh);        template<typename Etype> bool operator<(const JString& Lsh, const Etype& Rsh);        template<typename Etype> bool operator<(const Etype& Lsh, const JString& Rsh);        template<typename Etype> bool operator>(const JString& Lsh, const Etype& Rsh);        template<typename Etype> bool operator>(const Etype& Lsh, const JString& Rsh);        template<typename Etype> bool operator<=(const JString& Lsh, const Etype& Rsh);        template<typename Etype> bool operator<=(const Etype& Lsh, const JString& Rsh);        template<typename Etype> bool operator>=(const JString& Lsh, const Etype& Rsh);        template<typename Etype> bool operator>=(const Etype& Lsh, const JString& Rsh);        template<typename Etype> bool operator>=(const Etype& Lsh, const JString& Rsh);
*/

//--------------------------
see diff here:
https://www.diffchecker.com/CQp4QycZ

____________________________________________________________________________________________________


Plugin Setup and quick start with blueprint code

Once installed all the ThirdParty includes and libs, copy the plugin in your engine marketplace plugins directory or in your project Plugins directory. Open the project and you will find the plugin real fast (Edit -> Plugins -> Project -> Networking):

You will see there is a new option in your Project Preferences now: Main Window -> Edit -> Project Settings -> Photon Cloud API -> General:

all these options will be saved on your <YOUR PROJECT PATH>\Config\DefaultGame.ini ,

To create a new application in Photon Cloud webpage go to public-cloud

and create a new Real Time Application



DefaultGame.ini contents:
______________________________________________
[/Script/PhotonCloudAPI.
PhotonCloudConfig]
appVersion=1.0.0
AppID=<YOUR APP ID>
serverAddress=ns.exitgames.com
bAutoLobbyStats=True
______________________________________________

you can change them in blueprints too through the access to the PhotonCloudApi plugin with the Blueprint code -> Get Config


-
options to be found in the Photon Cloud API Config 


Custom Auth (optional)

If you want to have your custom login into the cloud app (auth) you should create a custom server provider for your App in the Photon Cloud Dashboard

here I’m using https://auth.xixgames.com with a simple PHP app that returns a JSON response (print out) {"ResultCode":1, "UserId": "<yourid>"} , you have to write your own login app in php that grabs the username and password (pass is encoded with MD5) and check the database.

More info about Custom Auth in Photon website

In your blueprints, before doing PhotonCloudAPI->Connect set the values:

Playfab auth login

Take a look to this guide:

https://doc.photonengine.com/en-us/realtime/current/reference/playfab

You need to first set the URL for your Title ID in the Photon Dashboard website of your app.And also set that URL in the plugin config:

Don't set the secret key from playfab in the configuration as it will crash if you do a subsequent login and the shared memory already have it. You set the secret dev api key in playfab after the login with blueprints.

Then you need to do a login first, with a valid user, if you don't own one, register it:

This is a typical register log:

----

LogPlayFab: Response : {"code":200,"status":"OK","data":{"PlayFabId":"9767E5513AD3F301","SessionTicket":"9767E5513AD3F301--435F8169EAB17A4A-DEF99-8D8F3B3F83CEA77-wO2vhhGAVMw3fIJcqn1PdOjtgp8jnOr8PP7sXIuhmCY=","Username":"jeremiyahmarion","SettingsForUser":{"NeedsAttribution":false,"GatherDeviceInfo":true,"GatherFocusInfo":true},"EntityToken":{"EntityToken":"M

3x7ImkiOiIyMDIxLTAzLTMwVDE5OjQyOjM2LjIzNjI0ODdaIiwiaWRwIjoiUGxheUZhYiIsImUiOiIyMDIxLTAzLTMxVDE5OjQyOjM2LjIzNjI0ODdaIiwiaCI6IkYwM0ZGN0VFNDRGQkMyM0MiLCJzIjoiR0NTL1cydUxzR09ocE50U0Y1VXFDVmtJL2lkR3EzaUJSODRtZVBmZ3laaz0iLCJlYyI6InRpdGxlX3BsYXllcl9hY2NvdW50ITVCMDhFNjhGNzBDNzhEMjQvREVGOTkvOTc2N0U1NTEzQUQzRjMwMS82ODY1RTMzQkYyRTA2QUJDLyIsImVpIjoiNjg2NUUzM0JGMkUwNkFCQ

yIsImV0IjoidGl0bGVfcGxheWVyX2FjY291bnQifQ==","TokenExpiration":"2021-03-31T19:42:36.236Z","Entity":{"Id":"6865E33BF2E06ABC","Type":"title_player_account","TypeString":"title_player_account"}}}}

LogBlueprintUserMessages: [BP_PhotonCloudObject_C_0] ID:9767E5513AD3F301, user:jeremiyahmarion

----

Finally, this is the correct way to do the login and pass the auth token:

Result

Photon Cloud API Subsystem

The bridget between the plugin and your game is an object named PhotonCloudAPIObject. You can create your own Blueprint or C++ class that inherits from this and then add the reference in the Project Preferences -> Photon Cloud -> Blueprints settings as the class to use.

-DEMO-

You can copy the blueprint used in the demo that contains all the events created for this purpose (old BP was an actor, new version is an UObject).


Events definitions using Photon Cloud API Object Blueprint

The bridge between Photon Cloud SDK and the PhotonCloudAPI Subsystem is made with delegates for each kind of event. These are some of the bindings available to link with your Blueprints

The first one you would need is the connection event delegate, like in the DEMO you can define it in the same PhotonCloudAPI BP you’ve created:

Connect

Or directly in the PhotonCloudAPI without blueprint, as in getting the reference from the

plugin directly from anywhere

After this event is defined, we can just call the Connect function.

In the example I’m connecting using my reference of the PhotonCloudAPI subsystem from the scene inside a widget plugin button event. Again, if you use the Join or Create Room

The next event to bind in the blueprint is the event to know when the room has been joined or error , failed to join event. But first, you can join or create a room in different ways:

Join Room only needs a room name, but join random and join_or_create will let you set a list of initial properties to create or match a room using a JSON and sql filters.

The random room uses a lobby name ,of course you could first join a lobby instead of a game room

and once you are in you can use this kind of events designed for lobby stats

finally, after joined a game room you will get the event related

all the join or create rooms are linked to this delegate

From here, you can spawn your player blueprint, or the other player blueprint and start sending data, like the position/rotation, speed, or anything else.

For the very basics, as in position,rotation and scale you have faster methods for that using a player reference,

Sending Player Location and Rotation:

Notice that you can set the reliable flag and generate a list of players to receive the message or just setting an empty array will send to everyone else than the sender. The options are, others, master or all players including the sender, -or custom array of course-
Receiving Player Location and Rotation

For other data example open the PhysicsBallPawn_BP and look in the example ,for

Simple player data send

Notice you can cache the data for any player who comes in the room after

received from the photon blueprint → directed to the player pawn:


How to sync Actors: Photon Mechanics

To sync the same object in different clients ,we use an unique hashed name based on the name of the actor. First, you need your actor to have a single name, the master can assign new names if you want, using a room property for example.

For your photon actor mechanics you need to assign this hashed name using your PhotonCloudAPI reference and in the Class Settings of your blueprint (or your c++ class) inherits from the Photon Mechanics interface:

Now you can perform operations with the actor over photon.But remember, if you want to sync the transform of a player, it’s better to use the methods only for players (faster and less bandwidth consumers).

You can use this data methods to call functions remotely when data changes.

Actor location/rotation send

Look at the example in PhotonMechanicsCube_Example_53_Blueprint

Room properties

To sync properties of the room you have various options

sending

Getting properties from the network


Players properties

Properties are JSON ,you can send and receive them from your player and receive from other players

This BP example will set only the NewProperty as int to value=6. You can receive it from a listener bind like this

or you can just ask photon for player properties passing the player number: