The following is not intended to be a complete list of CRYENGINE 5.4 C++ API changes, rather it is an indication of the most important changes that Programmers need to be aware of.
CRYENGINE 5.4.0 introduces support for Visual Studio 2017. In addition, Visual Studio 2015 users are required to install Update 3 in order to successfully compile the 5.4.0 version of Engine source code.
This release officially deprecates:
Keep in mind that the legacy GameSDK project uses many deprecated systems and it will be dropped in the future. However, we have not yet marked it as deprecated, because we are waiting for the templates to accurately match the functionality of the GameSDK first.
The new Entity Component system (that was introduced with CRYENGINE 5.3.0) has been adjusted in order to unify with the Schematyc setup. This means that any component exposed with the new 5.4.0 format (example below) will automatically become available in the Inspector and Schematyc so that Designers can build more complex logical entities.
The existing 5.3.0 method of creating components is still available, however we'll be phasing it out over time as the new unified setup matures. Part of evolving the new setup will be to reduce the amount of code required to expose a component, so keep in mind that the example below will not be as rough in the future:
#include <CrySchematyc/CoreAPI.h>
class CMyComponent final : public IEntityComponent
{
public:
static CryGUID& IID()
{
static CryGUID id = "{AD383B41-C144-4F99-9A2B-0FA2D9D86245}"_cry_guid;
return id;
}
void MyFunction()
{
// Print to the console
CryLogAlways("Hello world!");
// Signals can only be sent when the component was attached through Schematyc
if(Schematyc::IObject* pObject = m_pEntity->GetSchematycObject())
{
// Send the signal back to Schematyc, along with our instance GUID
pObject->ProcessSignal(SMySignal { m_bSignalResult }, GetGUID());
}
}
struct SMySignal { bool m_bReturnValue; };
bool m_bSignalResult = false;
};
void ReflectType(Schematyc::CTypeDesc<CMyComponent>& desc)
{
desc.SetGUID(CMyComponent::IID());
desc.SetEditorCategory("MyCategory");
desc.SetLabel("MyComponent");
desc.SetDescription("Does awesome things!");
desc.SetComponentFlags({ IEntityComponent::EFlags::Socket, IEntityComponent::EFlags::Attach });
desc.AddMember(&CMyComponent::m_myMember, 'memb', "MyMember", "My Member", "A property that can be changed", 10);
}
static void ReflectType(Schematyc::CTypeDesc<CMyComponent::SMySignal>& desc)
{
desc.SetGUID("{DBBDB49C-6C48-446E-9451-DAA32E6FA240}"_cry_guid);
desc.SetLabel("My Signal");
desc.AddMember(&CMyComponent::SMySignal::m_bReturnValue, 'ret', "ReturnVal", "Return Value", "Description", false);
}
static void RegisterMyComponent(Schematyc::IEnvRegistrar& registrar)
{
Schematyc::CEnvRegistrationScope scope = registrar.Scope(IEntity::GetEntityScopeGUID());
{
Schematyc::CEnvRegistrationScope componentScope = scope.Register(SCHEMATYC_MAKE_ENV_COMPONENT(CMyComponent));
// Functions
{
auto pFunction = SCHEMATYC_MAKE_ENV_FUNCTION(&CMyComponent::MyFunction, "{FE5B34ED-A5DD-4C3B-A81C-38B5D980A770}"_cry_guid, "MyFunction");
pFunction->SetDescription("Triggers our test function");
componentScope.Register(pFunction);
}
// Signals
componentScope.Register(SCHEMATYC_MAKE_ENV_SIGNAL(CMyComponent::SMySignal));
}
}
CRY_STATIC_AUTO_REGISTER_FUNCTION(&RegisterMyComponent);
The default entities introduced with CRYENGINE 5.3.0 are still part of the Engine, but are now considered deprecated and will be removed in a future Engine release. These entities are no longer available for creation in the Sandbox Editor, but existing instances will continue to work.
The new standard components can be used by Designers as well as Programmers using C++. For example, the updated 5.4 templates heavily utilize the new standard components in order to cut down on the amount of code required when getting started. The new components can be included with the path <DefaultComponents/...`>.
The components all reside in the Cry::DefaultComponents namespace.
The templates have been refactored to require much less code for the same end result. New systems have also been introduced, which have allowed us to remove dependencies on legacy systems:
Refactoring of our network is in progress and will start with the public API. The goal is to remove network dependencies (in the legacy CryAction module) in order to simplify how games can utilize networking in code. This is also preparation for a future refactoring of our network internals.
INetworkedClientListener and INetwork::AddNetworkedClientListener was added as an alternative for the legacy game rules system. This interface can be used to receive callbacks when clients connect over the network, making it possible to skip usage of game rules in projects. The templates have been updated to utilize this.
In the initial 5.3.0 Engine release, the new Entity Component system did not support RMI's, this has now been corrected and allows new entity code to be networked. See example below.
#include <CryNetwork/Rmi.h>
class CNetworkedComponent final : public IEntityComponent
{
virtual void Initialize() final
{
SRmi<RMI_WRAP(&CNetworkedComponent::RemoteEntityMethod)>::Register(this, eRAT_NoAttach, false, eNRT_ReliableOrdered);
m_pEntity->GetNetEntity()->BindToNetwork();
}
// Parameters to serialize an entity id across the network
struct SEntityParams
{
EntityId entityId;
void SerializeWith(TSerialize ser)
{
// Called to serialize and deserialize the entity id, note the 'eid' policy
// This policy is used to convert entity identifiers between machines as id's are not unique over the network.
ser.Value("entityId", entityId, 'eid');
};
};
bool RemoteEntityMethod(SEntityParams&& params, INetChannel* pNetChannel)
{
if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(params.entityId))
{
// Success!
}
// Return true to indicate that RMI was valid, a value of false indicates that something went wrong - for example validation of input indicates cheating.
return true;
}
void InvokeRemoteEntityMethod(EntityId id)
{
SRmi<RMI_WRAP(&CNetworkedComponent::RemoteEntityMethod)>::InvokeOnRemoteClients(this, SEntityParams{ id }, id);
}
};
In addition to RMI's, 5.4 also introduces support for serializing chunks of data as aspects over the network. This can be useful, for example to synchronize player input of a player. We've attached an example below:
class CNetworkedAspectComponent final : public IEntityComponent
{
virtual void Initialize() final
{
m_pEntity->GetNetEntity()->BindToNetwork();
}
virtual NetworkAspectType GetNetSerializeAspectMask() const final { return 1 << GetNetSerializationAspect(); }
// Called when serializing and deserializing
virtual bool NetSerialize(TSerialize ser, EEntityAspects aspect, uint8 profile, int flags) final
{
if (aspect == GetNetSerializationAspect())
{
// Serialize or deserialize our flags, note that the optional third parameter specifies the selected compression policy
ser.Value("m_flags", m_flags);
}
}
const EEntityAspects GetNetSerializationAspect() const { return eEA_GameClientD; }
// Call when m_flags changes and we want to serialize the data to the other machines.
void RequestNetSyncToOthers() { m_pEntity->GetNetEntity()->MarkAspectsDirty(GetNetSerializationAspect()); }
uint32 m_flags;
};