How do I access FOnlineSubsystemSteam instance? Static_Cast Compile Error

Dear Friends at Epic,

Please see my own answer and comment below for more info


I am trying to finish my steam integration,

I need to access the Steam online subsystem, I know this goes against the general way of using generic online subsystem

but I have my own independent service for getting a list of available games, so I am not using the advertising of games with steam


#How to Access This?
OnlineSubsystemSteam.h

class ONLINESUBSYSTEMSTEAM_API FOnlineSubsystemSteam : 
	public IOnlineSubsystem, 
	public FTickerObjectBase
{

When I compile using these includes and Online in the build target

//Online
    #include "Online.h"
    #include "OnlineSubsystemSteamPackage.h" //doesnt get found by compiler

when I take out the steam header that is not getting found

then I get

FOnlineSubsystemSteam

as not being found by compiler

when I try #include “OnlineSubsystemSteam.h”

I get this:

1>e:\rocketvictory\victorygame\intermediate\builddata\include\victorygame\../../../../Source/VictoryGame/Classes/Player/VictoryGamePlayerController.h(7): fatal error C1083: Cannot open include file: 'OnlineSubsystemSteam.h':

#OnlineSubsystemSteamClasses

the most likeely candidate of OnlineSubsystemSteamClasses does not work either

 Cannot open include file: 'OnlineSubsystemSteamClasses.h'

I am using

public class VictoryGame : ModuleRules
{
	public VictoryGame(TargetInfo Target)
	{
        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HTTP", "OnlineSubsystem" });

#Above Part Solved Using

public class VictoryGame : ModuleRules
{
    public VictoryGame(TargetInfo Target)
    {
        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HTTP", "OnlineSubsystem", "OnlineSubsystemSteam" });

#But how to I get FOnlineSubsystemSteam

I now have FOnlineSubsystemSteam being recognized as a class

but I still cant figure out how to access it!

I’ve tried things like:

FOnlineSubsystemSteam * VictoryOnline = InterfaceCast(OnlineSub);
	//FOnlineSubsystemSteam * VictoryOnline = Cast(OnlineSub);

FOnlineSubsystemSteam is not a standard object, it has no ::StaticClass so I can’t use ObjectIterator

and OnlineSub is a interface so I’d use interface cast

but FOnlineSubsystemSteam is not an interface!

and I cant use regular Cast on OnlineSub since it’s a n interface

so how do I get FOnlineSubsystemSteam instance?


#Protected

I would use

protected:

/** Single instantiation of the STEAM interface */
static FOnlineSubsystemSteam* SteamSingleton;

buuut

its protected :slight_smile:

Rama

I’ll try to answer all the questions above. It would be great if you would continue to modify the original question to clean things up for future readers.

The IOnlineSubsystem interface is implemented by FOnlineSubsystemSteam, but the part of confusion here is that neither of these are UObjects. These are plain old C++ classes that use inheritance and an interface pattern to achieve their goals. Cast(ObjectClass)(Object) is a UObject convention. InterfaceCast<> is also one, but I have never used that ever, in UE3 interfaces weren’t so stable and casting them was a recipe for disaster in many cases.

Now, dynamic_cast is definitely in the right direction, but we don’t support rtti in our engine, so this wouldn’t work either. You want a simple static_cast which is a better option than the original C style cast.

Now to cast to it, you’re going to need to be able to include the header file. I think you got past that issue with your module (build.cs) file change, but you may need to add some more header include paths to access the headers you want. Of course this also goes against the engine design, so you may hit a hurdle or two that I’ll try to help you clear.

#Most recent post

Thanks for your help Josh!

I tried using static_cast already, as per helpful suggestion by William Gaul

IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();
		IOnlineSessionPtr Sessions = NULL;
	if (OnlineSub)
	{
		Sessions = OnlineSub->GetSessionInterface();
		if (Sessions.IsValid())
		{
			Optimize("onlinesubsys was found!!!! yay!!");
			
		}
		else Optimize(" IOnlineSessionPtr not found, did you change config to enable steam?");
	}
	else Optimize("onlinesubsys not found, did you change config to enable steam?");
			
	//~~~ Steam? ~~~~
	FOnlineSubsystemSteam * VictoryOnline = static_cast(OnlineSub);
	if (VictoryOnline) Optimize("Steam Online Subsystem Found!");
	else return;
	OptInt("Steam Game Port for joining",VictoryOnline->GetGameServerGamePort());

I got this compile error

1>------ Build started: Project: VictoryGame, Configuration: Development_Editor x64 ------
1>  Parsing headers for VictoryGameEditor
1>  Code generation finished for VictoryGameEditor and took 1.776
1>  Module.VictoryGame.2_of_2.cpp
1>E:\RocketVictory\VictoryGame\Source\VictoryGame\Private\Player\VictoryGamePlayerController.cpp(4395): error C2440: 'static_cast' : cannot convert from 'IOnlineSubsystem *' to 'FOnlineSubsystemSteam'
1>          No constructor could take the source type, or constructor overload resolution was ambiguous
1>  -------- End Detailed Actions Stats -----------------------------------------------------

FOnlineSubsystemSteam * VictoryOnline = static_cast(OnlineSub);

Woohooo!!!

Thanks so much Josh!

You’re awesome!

Rama

public class VictoryGame : ModuleRules
{
public VictoryGame(TargetInfo Target)
{
PublicDependencyModuleNames.AddRange(new string[] { “Core”, “CoreUObject”, “Engine”, “InputCore”, “HTTP”, “OnlineSubsystem”, “OnlineSubsystemSteam” });

seems pretty obvious in hindsight hee hee

#But how to I get FOnlineSubsystemSteam

I now have FOnlineSubsystemSteam being recognized as a class

but I still cant figure out how to access it!

I’ve tried things like:

FOnlineSubsystemSteam * VictoryOnline = InterfaceCast(OnlineSub);
	//FOnlineSubsystemSteam * VictoryOnline = Cast(OnlineSub);

FOnlineSubsystemSteam is not a standard object, it has no ::StaticClass so I can’t use ObjectIterator

and OnlineSub is a interface so I’d use interface cast

but FOnlineSubsystemSteam is not an interface!

and I cant use regular Cast on OnlineSub since it’s a n interface

so how do I get FOnlineSubsystemSteam instance?


#Protected

I would use

protected:

/** Single instantiation of the STEAM interface */
static FOnlineSubsystemSteam* SteamSingleton;

buuut

its protected :slight_smile:

Rama

Well to answer the question in your answer…all online subsystems pipe through OnlineSubsystem.h, which has this function:

/** 
 * Get the online subsystem for a given service
 * @param SubsystemName - Name of the requested online service
 * @return pointer to the appropriate online subsystem
 */
static IOnlineSubsystem* Get(const FName& SubsystemName = NAME_None)
{
	FOnlineSubsystemModule& OSSModule = FModuleManager::GetModuleChecked("OnlineSubsystem"); 
	return OSSModule.GetOnlineSubsystem(SubsystemName); 
}

Or its analogue in OnlineSubsystemModule.h:

/** 
 * Main entry point for accessing an online subsystem by name
 * Will load the appropriate module if the subsystem isn't currently loaded
 * It's possible that the subsystem doesn't exist and therefore can return NULL
 *
 * @param SubsystemName - name of subsystem as referenced by consumers
 * @return Requested online subsystem, or NULL if that subsystem was unable to load or doesn't exist
 */
virtual class IOnlineSubsystem* GetOnlineSubsystem(const FName InSubsystemName = NAME_None);

Since FOnlineSubsystemSteam implements IOnlineSubsystem, this would be the way to go.

You would just need to grab the base OnlineSubsystem module (which is easy, FModuleManager::LoadModuleChecked("OnlineSubsystem");) and it should work…

Great to hear from you William!

#Can’t Use Cast

I’ve tried casting from IOnlineSubsystem to FOnlineSubsystemSteam

but that does not compile because IOnlineSubsystem is an interface, so you can’t use a regular Cast, you have to use InterfaceCast

#Can’t Use InterfaceCast

but InterfaceCast cannot work on a UObject*, which is what FOnlineSubsystemSteam is considered to be

so I can’t proceed

because FOnlineSubsystemSteam is NOT an interface, but it it is extending an interface,

#Obtaining OnlineSub as an interface

and the only way I know to get the online subsystem is:

IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();

Which is the interface… :slight_smile:


#ObjectIterator Does Not Work

I tried doing a ObjectIterator to find FOnlineSubsystemSteam instances but that did not compile because FOnlineSubsystemSteam does not have a ::StaticClass

:slight_smile:

Rama

Sorry replied to myself and not your comment. See below.

I am confused…

Interface cast does this:

Dynamically casts an object pointer to an interface pointer.

In other words, backwards from what you want to do. You want to cast an interface to an object! Could you try doing a low level static_cast or dynamic_cast instead? (really this is all the Epic Casts do, except with more parameter checking).

I actually have used interfaces quite a bit

and interfacecast is indeed the way to work with interfaces like IOnlineSubsystem

I use several interfaces in my own project :slight_smile:

I wrote tutorial on use of interface cast here:
http://forums.epicgames.com/threads/972861-23-TUTORIALS-C-for-UE4-gt-gt-New-Beta4-gt-Beta5-UE4-C-Transition-Guide?p=31703539&viewfull=1#post31703539

the problem I am having is that FOnlineSubsystemSteam is an Object class based on FTickerObjectBase and it uses IOnlineSubsystem interface

but I dont know how to get a reference to FOnlineSubsystemSteam because it is not also an interface like IOnlineSubsystem, so

IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();

is not a useful way to access FOnlineSubsystemSteam

#dynamic_cast

dynamic_cast requires a UObject* and so it will not work with IOnlineSubsystem which is an interface

Therein lies the problem I am having with Cast as well :slight_smile:

Nice to hear from you William!

#Summary

Here’s a summary of all my attempts, none of which compile because of FOnlineSubsystem being an Object* and IOnlineSubsystem being an interface :slight_smile:

        //~~~ Steam? ~~~~
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();

        	FOnlineSubsystemSteam * please =
     FOnlineSubsystemSteam::SteamSingleton; //protected
        
        	FOnlineSubsystemSteam * VictoryOnline = 
    InterfaceCast(OnlineSub);
    
        	FOnlineSubsystemSteam * VictoryOnline = 
    Cast(OnlineSub);

Right, but you use InterfaceCast to take an object reference and cast it to an interface reference. That interface still retains the information that it is of a particular object, which is why you can still call implementing subclass methods on it. This is all it does:

static_cast(Src->GetInterfaceAddress(InterfaceType::UClassType::StaticClass()))

The interface pointer still points to the same object in memory with the same methods.

This makes me wonder, since IOnlineSubsystem is just an interface, will it work just like the IToStringInterface in your tutorial? That is, does the IOnlineSubsystem reference “know” that it is of type Steam automatically?

That is, does the IOnlineSubsystem reference “know” that it is of type Steam

yes the functions that Steam implements from IOnlineSubsystem do work as the Steam version, but the function I want

/**
	 *	@return the port the game has registered for play 
	 */
	inline int32 GetGameServerGamePort() const
	{
		return GameServerGamePort;
	}

is not part of IOnlineSubsystem so I cannot call it from the generic interface pointer

I need to cast to FOnlineSubsystemSteam somehow :slight_smile:


"but you use InterfaceCast to take an object reference "

im not sure about that, based on what you posted

static_cast(Src->GetInterfaceAddress(InterfaceType::UClassType::StaticClass()))

StaticClass() does not mean Object reference :slight_smile:


#Taking it Further

If you set up your defaultengine.ini with steam

you can test my code yourself and see if you can find a way to get FOnlineSubsystemSteam!

[OnlineSubsystem]
;DefaultPlatformService=Null
DefaultPlatformService=Steam
PollingIntervalInMs=20

[OnlineSubsystemSteam]
bEnabled=true
SteamDevAppId=212960
GameServerQueryPort=27015
bRelaunchInSteam=false
GameVersion=1.0.0.0
bVACEnabled=1
bAllowP2PPacketRelay=true
P2PConnectionTimeout=90
Achievement_0_Id="ACH_FRAG_SOMEONE"
Achievement_1_Id="ACH_DIE_ONCE"
Achievement_2_Id="ACH_FINISH_MATCH"
; This is to prevent subsystem from reading other achievements that may be defined in parent .ini
Achievement_3_Id=""


[OnlineSubsystemNull]
Achievement_0_Id=frag-someone
Achievement_0_bIsHidden=false
Achievement_0_Title="Fragged"
Achievement_0_LockedDesc="Frag someone"
Achievement_0_UnlockedDesc="Fragged someone"

Achievement_1_Id=die-once
Achievement_1_bIsHidden=false
Achievement_1_Title="Died"
Achievement_1_LockedDesc="Die at least once"
Achievement_1_UnlockedDesc="Died at least once"

Achievement_2_Id=finish-match
Achievement_2_bIsHidden=false
Achievement_2_Title="Finished match"
Achievement_2_LockedDesc="Finish at least one match"
Achievement_2_UnlockedDesc="Finished at least one match"

; This is to prevent subsystem from reading other achievements that may be defined in parent .ini
Achievement_3_Id=""

[/Script/OnlineSubsystemSteam.SteamNetDriver]
NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"
AllowDownloads=false

#Epic Help Us Please

In Meantime, I’d love to hear from you folks at Epic about this, so I can finish Steam integration :slight_smile:

Rama

That is…quite unfortunate :stuck_out_tongue: I will definitely try this out and see if I can figure out something.

As for the InterfaceCast thing, well the entire template’s in Casts.h if you want to check it out. It does accept a UObject reference (well, pointer actually) as Src. I think the real magic happens in GetInterfaceAddress() though.

It can’t be this hard to access subsystems though. I’m sure there’s a simple solution we’re just overlooking :slight_smile:

im pretty sure this line explains my problem

you simply can’t use Cast with interfaces

casts.h

// it doesn't seem worthwhile to risk changing Cast<>/IsA() to work with interfaces at this time,
// so we'll just make sure it fails... spectacularly
#define CATCH_UNSUPPORTED_INTERFACECAST(TheType) checkAtCompileTime((TheType::StaticClassFlags & CLASS_Interface) == 0, __CASTING_TO_INTERFACE_TYPE_##TheType##_IS_UNSUPPORTED)

Thanks for your efforts William!

#Epic Please Help

I really am stuck on this one :slight_smile:

I really cant figure this out because

FOnlineSubsystemSteam does NOT have a ::StaticClass() functions, none of the normal casts work

and I am given an Interface to access FOnlineSubsystemSteam, but it itself is not an interface, so I cannot use InterfaceCast

IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();

Rama

I’m trying to also get this working to access the Steam subsystem, however I seem to be running into the same issues but the static cast doesn’t seem to fix it. I currently use:
The headers:

#include "Online.h"
#include "OnlineSubsystemSteam.h"

Code:

IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();
	IOnlineSessionPtr Sessions = NULL;
	if (OnlineSub)
	{
		Sessions = OnlineSub->GetSessionInterface();
		if (Sessions.IsValid())
			//Passed
		else
			// Failed
	}
	else 
		// Failed

FOnlineSubsystemSteam* steamOnline = static_cast(OnlineSub);

I get a compile error on the steamOnline line -
Error 1 error C2059: syntax error : ‘(’ C:\dev\GameTest\Source\GameTest\OnlineGameSession.cpp 52 1 GameTest

The OnlineSubsystem is found fine if I comment out the steamOnline line, and my target.cs and config I believe mirror what it asks you to do in the documentation. Am I missing something obvious somewhere?

Hello,

This is a question from the beta version of the engine. We are marking this answered for tracking purposes. If you are experiencing an issue similar to this please post a new question.

Thank you.