17. Finishing the Multiplayer - Crossplay


Hello again! Jammu here. In my previous 2 posts I have already achieved multiplayer functionality on both Steam and Oculus platforms. So far we haven’t had any functionality to add those players together though.


To add cross platform support, we need a way to identify the rooms players are connected on. Currently we are just using Steam/Oculus ID’s, which is fine if the player does not need to write them to anywhere. But this quickly comes super frustrating if you are typing 15 numbers on a virtual keyboard to connect your Quest to your Steam friend’s game.


So we decided to use a 6 character string as a room code, this gives us around 1.8 trillion different combinations on the room code (alphabet and numbers 1-9), which should be plenty enough for our purposes. We bought an asset “VR UIKit ” where I grabbed a keyboard asset to use in the game. I added an Inputfield to enter the room code in, but apparently it has been bugged for years on the Quest. Oculus blames Unity and Unity blames Oculus and nobody has bothered to fix the problem, nice.


Luckily I found out a dirty way of fixing this error, when the user is typing on the virtual keyboard, I can directly modify the Inputfield text parameter and move the caret position according to the text length. This works well on one Inputfield, but would need more work on multiple. 


Okay, so now we have a room code and a way to input it. Next the hard part, implementation. This is the point where everything gets messy and hard. Instead of using the user’s ID when sending the room code to the friend, now we use the generated one. On Steam this was pretty easy, since the chat functionality doesn’t care if the room code is in ulong or string format. On the Oculus side this wasn’t so easy, since it uses a custom Oculus room code with ulong as an ID.


Solution was (not surprisingly) pretty weird, when a user is creating the Oculus room, I added an datastore to Matchmaking options with an key “roomCode” by using the matchMakingOptions.SetCreateRoomDataStore() function, when the Oculus user gets invited to the game, we receive the invitation with Rooms.SetRoomInviteReceivedNotificationCallback() callback, and from there we can grab the room that we are invited to, and so we can access the Oculus room’s datastore and grab the room code from there with message.Data.DataStore.TryGetValue(). I have no idea if this is the best way or right way to do this, but seems to work. Not a surprise anymore that Oculus’s documentation did not help on any part of this.


Now on to the connecting to the roomcode part. When a player inputs a new 6 digit code, we can now utilize the Photon’s own PhotonNetwork.JoinRoom() function. When a new player joins in the game, it already sends an RPC event to other players in that room with his/hers data, so we don’t need to worry about that. So when a player joins a game with room code, we don’t really care about any of the Steam or Oculus stuff, we just need to grab user’s data and show it in our party list. If the player does not input any room code, we use Photon’s random matchmaking. I also added an option to make the room publicly visible, so any player can join it via random matchmaking.


One minor UX improvement came to life pretty much on accident, if user inputs a invalid room code (meaning that no rooms exists with this code), player makes a new room with that room code, this allows players to easily make custom rooms with custom names that their friends can remember (e.g. MEKIWI is our test room’s code).


We also wanted the multiplayer experience to be as seamless as possible, so we allowed the players to invite their own friends to any game they want. So if User1 hosts a game on their Steam account, User2 joins the game via Oculus Quest, User2 can ask his/her Oculus friend to join User1’s game. Complicated to explain? Yes.


Next I can finally give this horrible development UI to our UX/UI developers and they can make it look pretty.


Finished dev UI:

This was almost a 4 week project for me and it’s finally done. 

Lines of code: ~2200

Energy drinks spent: too much

I you have anything to ask or have any suggestions on other blog posts you would like to read from the multiplayer side, pop in on our Discord server at https://discord.gg/qy4NXnWw


Random development quote: “Mää en oo kyl huomannu että oisin kännissä yhtää erilainen… Vähä tyhmempi vaan.

Join Cave Digger Discord!


Submit a Comment

Your email address will not be published. Required fields are marked *

MeKiwi Oy

Njetwork Inn
Isokatu 56
90100 OULU

VRkiwi is a trademark owned by MeKiwi Oy

MeKiwi Oy

Njetwork Inn
Isokatu 56
90100 OULU

VRkiwi is a trademark owned by MeKiwi Oy

This week our guest writer is Justus, our code guru and shader wizard. Take it away Justus!

Why bother making cool shaders? Why don’t you just go crazy with post-processing like everyone else?

Because we can’t. With Cave Digger 2 our first target platform is Oculus Quest. Quest is a standalone mobile device, and as such, it uses a rendering type called Tiled Rendering, which is really efficient for most rendering, but causes full screen effects like post-processing to be really slow. These effects will add significant fill-rate overhead and should almost always be avoided. Find out more about how Quest does Tiled Rendering here.

So in order to make fancy looking effects like custom fog, color grading or bloom, while maintaining stable 72 fps on Oculus Quest, we have to make the effects with shaders and particle effects.

But shaders are hard to make 🙁


It’s true that writing shaders can be annoying even if you’re an experience programmer. Cg/HLSL syntax is different from most programming languages. However there is a easier way. The trick is to use a node based editor like Amplify Shader or Shader Graph. You can find plenty of helpful guides and tutorials online. Also Amplify Shader has lots of good example shaders for you to learn from. This allows you to make shaders much faster, however the catch is that the shaders might not be as optimized as they would be if programmed by an experienced graphics programmer

Amplify Shader view of CD2 Gem shader. Cel Shaded lighting and Custom Fog are is done in a custom functions, which makes them more easy to reuse.

So what does it do?

*Slaps the roof of Cave Digger 2 Lit shader*

This bad boy has a custom fog that uses a cubemap for color. It uses a cell shaded lighting that’s similar to Breath of the Wild. It can do triplanar texturing and stochastic texturing.

Also we have a custom Gem Shader for making those loots look shiny and tasty.


How to make it work

To handle controlling the shader settings I created a scriptable object called Atmosphere and also created Atmosphere Manager to manage them

A scriptable object helps to quickly make different atmospheres for different areas. It currently controls the ambient lighting color and fog density.