Single/Multiplayer, Touch & Vive blueprint only Template

You have to mess around the RecastNavmesh/generation settings, with the height values. Under display put also draw offset to 0 to see the real navmesh on the terrain.

Thanks, found it, worked perfectly!

Sorry, picked up another thing.
I created a little UMG Menu, attached to an actor to have it in the world. the Menu is controlled with the right motioncontroller. this works like a charm.
however, the buttons will only set the “hovered” state when hovered with the left motion controller. Any idea what causes this behavior? and how to set it up to show the state when hovered with the right controller as well?

Thank you!

THANK YOU!!! YOU ARE BEAUTIFUL BAD*** PEOPLE! I applaud you all for your speechless work!! :):):):eek::eek::eek::eek::eek::eek:

Hi there,

My friend and I downloaded latest packaged version and tried it with 2 laptops and 2 Vives. We tried Steam and DirectIP with Steam closed but we couldnt find each other sessions in any of them. We tried turning Steam Home off too as recommended in this thread. That didnt work too. Lastly looked at Steam Servers if our servers are listed but they didnt listed there as well. Im sure this has nothing to do with project but any way to solve this?

Make sure steam is closed previusly to open the project (check the process in admin tasks) then open the project and then make sure steam is running. Every time you test, you need to force close steam.

Idk if you said it for me but I tried anyways. Didnt work. Addition to not finding sessions, I have the Steam Overlay on MainMenu map but I dont have it after I launch a server

Hi! Please take a look at \Saved\Logs files and look for the word “Steam”. There, you will see if steam was properly opened and running. Because it there is something wrong, you will see something like Steam was already running, and/or error messages like that. If the logs doest not show any error about steam, the issue could be because firewall, and or some router port settings. I am telling that because it was exactly the same issue I had for a few days until I find that.

Is it possible to make VR without navmesh just using collision volumes?

: Did you have a chance to discuss about avatar replication with Oculus/Epic at OC4? What’s your plan forward?

That’s what I’ doing presently. Honestly Oculus haven’t been of great help: they said they don’t even have an internal version to work with Unreal. So I’m taking the matters in my own hand. I’ll tell you in a few days if I’m successful!

Yes in fact you can arrange to teleport on anything. NavMesh recast settings are a bit tricky. You can make exceptions/allow teleport on anything in the Trace Teleport Destination (or something like that) in MotionControllerbp. Furthermore, it can be easiest to work like this if your world is small and the terrain is very uneven.

As of tonight I’ve succesfully updated the Avatar template to Unreal 4.18 and to Oculus Avatar SDK 1.16 (the latest available from Oculus).

Now that it’s done, so it works single player Avatar. The second part is now to replicate Avatar head and hand/finger position for multiplayer.
I’m back at my whiteboard (litterally) at the office and I’ve good vibes I should do that in the following days.
If it’s not good I’ll release anyway the singleplayer plugin anyway next week.

Can you fall off of things? Does the pawn have gravity?

Ok good! We are experimenting with the oculus fork of UE4.18 too. Not sure how to replicate the packet capture provided by the Avatar SDK. Are you planning to use UE4 replication or some sort of socket stream?

For now I’m trying to understand the Avatar Packets streaming

Ok so here’s my way of doing things. Of course other could decide to do otherwise

First of all, terminology. Let’s say there’s 3 players, each logged in Oculus Home under their respective ID.
First in MainMenu when connecting to Oculus, the Oculus ID is retrieved through my function OculusLogin and assigned to AvatarMaster, through the GameInfoInstance. This is true for all players.
First to login is the Authority, locally-controlled player 0 (listen-server). I call him AUT_LOC_CTRL0.
Then, another player connects. When he arrives on MultiMap, that’s where interesting things happens. This player is spawned on the server as Authority, Not Locally-controlled Player 1 (AUT_NOTLOC_CTRL1), and then replicated as Remote, Locally-controlled Player 1 (REM_LOC_CTRL1). At the same time, Player 0, as per replication dictates it, appears to REM_LOC_CTRL1 as Remote, Not Locally-Controlled Player 0 (REM_NOTLOC_CTRL0).
So if 2 players are connected (1 listen-server, the other one as client), 4 copies of AvatarMaster are live in the Unreal world: 2 on the server, and 2 on the client.
Every other client is connecting the same way; however special attention must be given to interactions/replications between clients (REM_LOC_CTRL1 <-> REM_LOC_CTRL2). Anyway.
How I made Avatar work / How I would make it work multiplayer

So everytime a client connects, he goes through all other clients and make them spawns an AvatarRemote together with his OculusID, so tada the AvatarRemote spawned by every other clients has the appearance of the original client connecting.
Furthermore, as the client connects, he make also the server spawns a copy of RemoteAvatar, for AUT_LOC_CTRL0 to see. Finally, the authority, not locally-controlled copy of the freshly connected client will also spawn a copy of AvatarRemote to previous clients in case there’s more than 2 players.
The problem with previous template (3.1.1 with Avatars, Unreal 4.16) was that multiplayer Avatars were all controlled by whatever the locally-controlled player that was. Bad.

So let’s dive in code.

**ProteusLocal.cpp: **Enable Record Packets
Actual code:
void AProteusLocal::BeginPlay()
{
Super::BeginPlay();
AProteusLocal::AdditionalSetup();
}
void AProteusLocal:: I’ll append this function to RegisterRemoteTalker:
{
AProteusLocal::EnableRecordPackets();
}
void AProteusLocal::EnableRecordPackets()
{
if (!AvatarComponent)
return;
AvatarComponent->StartPacketRecording();

   PacketSettings.AccumulatedTime = 0.f;
   PacketSettings.RecordingFrames = !PacketSettings.RecordingFrames;

}
OvrAvatar.cpp: Start Packet Recording
Actual code:
void UOvrAvatar::StartPacketRecording()
{
if (!Avatar)
return;

   ovrAvatarPacket_BeginRecording(Avatar);

}
Begin Recording leads to an Oculus header file library function with an opaque pointer as ovrAvatarPacket, so we’ll take it from there.
Then, the packets are updated in ProteusLocal.cpp in the tick, as UpdatePacketRecording.
Actual code:
void AProteusLocal::UpdatePacketRecording(float DeltaTime)
{
if (!AvatarComponent)
return;

   if (!PacketSettings.Initialized)
   {
          AvatarComponent-&gt;StartPacketRecording();
          PacketSettings.AccumulatedTime = 0.f;
          PacketSettings.RecordingFrames = true;
          PacketSettings.Initialized = true;
   }

   if (PacketSettings.RecordingFrames)
   {
          PacketSettings.AccumulatedTime += DeltaTime;

          if (PacketSettings.AccumulatedTime &gt;= PacketSettings.UpdateRate)
          {
                 PacketSettings.AccumulatedTime = 0.f;
                 FOvrAvatarManager::Get().QueueAvatarPacket(AvatarComponent-&gt;EndPacketRecording());
                 AvatarComponent-&gt;StartPacketRecording();
          }
   }

}
This is where it is becoming interesting. Update Packet Recording calls QueueA Avatar Packet in the** OVRAvatarManager**, where packets are serialized and queued:
Code:
// Setting a max in case there is no consumer and recording turned on.
static const uint32_t SANITY_SIZE = 500;
void FOvrAvatarManager::QueueAvatarPacket(ovrAvatarPacket* packet)
{
if (packet == nullptr)
{
return;
}

   SerializedPacketBuffer Buffer;

   for (auto& QueuePair : AvatarPacketQueues)
   {
          auto Queue = QueuePair.Value;
          if (Queue-&gt;PacketQueueSize &gt;= SANITY_SIZE)
          {
                 UE_LOG(LogAvatars, Warning, TEXT("[Avatars] Unexpectedly large amount of packets recorded, losing data"));
                 Queue-&gt;PacketQueue.Dequeue(Buffer);
                 Queue-&gt;PacketQueueSize--;
                 delete] Buffer.Buffer;
          }

          Queue-&gt;PacketQueueSize++;

          Buffer.Size = ovrAvatarPacket_GetSize(packet);
          Buffer.Buffer = new uint8_t[Buffer.Size];
          ovrAvatarPacket_Write(packet, Buffer.Size, Buffer.Buffer);
          Queue-&gt;PacketQueue.Enqueue(Buffer);
   }

   ovrAvatarPacket_Free(packet);

}

MY IDEA

Serialized packet buffers are now converted into AvatarPacketQueues
AvatarPacketsQueues are in fact a TMap<FString, AvatarPacketQueue*> AvatarPacketQueues, and AvatarPacketQueue are a struct AvatarPacketQueue { TQueue<SerializedPacketBuffer> PacketQueue; uint32_t PacketQueueSize = 0;};

We find later the header file of ProteusRemote that the FString is an arbitrary identifier, there it is found to be GetName() but it could be more useful to be the Oculus ID.

SO
What I would do is Local gets AvatarPacketQueues (as a TMap) and exports it every tick to a class reachable to all clients. The string key in the TMap here would be the Oculus ID. Probably the GameInfo Instance?

Then, as Remote is spawned it register as a remote Avatar under its Oculus ID:

void FOvrAvatarManager::RegisterRemoteAvatar(const FString& key)
{
check(!AvatarPacketQueues.Find(key));

   AvatarPacketQueue* NewQueue = new AvatarPacketQueue();
   AvatarPacketQueues.Add(key, NewQueue);

}

Then it reaches every tick GameInfo instance via an interface, finds its key in the TMap, and retrieve its associated AvatarPacketQueue.
Then AvatarPAcketQueue is retranscribed to avatarpacket via the AvatarModuleManager RequestAvatarPacket:

ovrAvatarPacket* FOvrAvatarManager::RequestAvatarPacket(const FString& key)
{
ovrAvatarPacket* ReturnPacket = nullptr;

   if (auto Queue = AvatarPacketQueues.Find(key))
   {
          SerializedPacketBuffer Buffer;

          if ((*Queue)-&gt;PacketQueue.Peek(Buffer))
          {
                 (*Queue)-&gt;PacketQueueSize--;
                 (*Queue)-&gt;PacketQueue.Dequeue(Buffer);
                 ReturnPacket = ovrAvatarPacket_Read(Buffer.Size, Buffer.Buffer);
                 delete] Buffer.Buffer;
          }
   }

   return ReturnPacket;

}

Would it work? Would have to try it!

I’ll release this his week so we’ll be able to solve this!

Hi , any update about the avatars replication? Looking forward to test the new version, let me know if we can help!

Yeah finally I ditched the RemoteAvatar update with packets since it was giving me headaches.
So what I do now is that I simply capture controller/head transforms and buttons within a struct that I duplicate on the server, together with the Oculus ID. Then, the right DuplicateAvatar (that’s how I called them now) integrate the data via a uproperty. Data is then converted to HandInputState struct and sent directly to OVR_Avatar.h from the updated plugin. The rest is the voicevisualization that should be pretty straightforward). So working everyday on this, I’m that close of having finished.

Furthermore, I’ve succesfully integrated the template with WMR devices (tested with Samsung Odyssey and Dell Vizor).

So next update it should integrate both.

Ah, and I should also find time to fix direct IP voice, via a small cpp file.

I also found that there was a redundancy in functions in the template, robably explaining some lag some have experienced.

Working also on integrating ARCore and GoogleVR – needed for a client – but that’s another project!

I’m about to start programming a simple 1v1 RTS game using the 3.2.2 template. I was wondering if anyone would be interested in testing multiplayer on the VR template (3.2.2 edition UE engine version 4.17.2) some time in the next few days.

Hey Mavulus I should post and update tomorrow:

1)Updated Oculus and Steam versions - single and multiplayer 4.18.1
2)Updated Oculus Avatars single player – I give up for now multiplayer but I’ll post the fartest I’ve been 4.18.1
3)WIndows Mixed Reality Version - 4.16.2