Release Notes

3.0.0

Preview

Build 1969 (May 07, 2026)

Breaking Changes

  • OnOwnershipRequest signature: bool(ObjectRoot*, PlayerId) -> void(ObjectRoot*, PlayerId). No longer a vote; owner replies asynchronously via Client::RespondToOwnershipRequest(obj, granted)
  • C API: obj_give_away_owner → obj_respond_to_ownership_request(client, obj, granted). C#: Object.GiveAwayOwner -> Object.RespondToOwnershipRequest
  • Removed Client::SetGiveAwayOwner and Client::RejectOwnershipRequest
  • Removed OnObjectOwnerAssigned — use OnObjectOwnerChanged and compare against LocalPlayerId()

Bug Fixes

  • Fixed: OnObjectOwnerChanged now also fires on first owner assignment during create
  • Fixed: Request cooldown only bumps when the owner is reachable
  • Fixed: Other consistency issues with ownership change behaviour

Build 1923 (May 05, 2026)

What's New

  • The former SharedClient SDK is renamed to Fusion Core. Almost every public surface changed: the SharedMode namespace becomes FusionCore, the single Fusion static library is split into PhotonCommonPhotonMatchmakingFusionCore, and a new optional FusionCAPI MODULE exposes a flat C ABI for engine bindings. The single-scene model is replaced by a multi-map session, PlayerPredicted ownership and SimulationMode::Authority enable server-authoritative prediction with input replay, and RealtimeClient gains a full Task<Result<T>> async API. C++20 is now required

Changes

  • Changed: namespace SharedMode::*FusionCore::*. SharedModeCompat.h is included from every public header for partial source-compat
  • Changed: single Fusion static library replaced by PhotonCommonPhotonMatchmakingFusionCore chain
  • Added: optional FusionCAPI MODULE library exposing a flat C ABI — 235+ functions, opaque handles, polled event queue, blittable FusionEvent (28 B), unified FusionEventType enum (0–18 client / 100–116 realtime async / 200–220 realtime broadcasters), blittable FusionNetworkStats / FusionTrafficStats / FusionTrafficStatsGameLevel / FusionEMAReport. Header: FusionCore/libs/fusion_c_api/include/FusionCAPI.h
  • Added: cache flag FUSION_BUILD_CAPI (ON for standalone, OFF for engine presets, always OFF on WASM, STATIC on iOS with FUSION_CAPI_STATIC define)
  • Changed: library output filenames now embed the MSVC runtime suffix _mt / _md (e.g. fusion_windows_x64_release_mt.lib)
  • Added: cache var FUSION_MSVC_RUNTIME_LIBRARY (MultiThreaded / MultiThreadedDLL) drives the suffix and prebuilt PhotonRealtime variant filtering
  • Changed: CMake presets split across CommonConfigurePresets.json, CommonBuildPresets.json, PlatformPresets.json, StandalonePresets.json, UnrealPresets.json, GodotPresets.json, TestPresets.json. Configure presets named <platform>-<arch>-<engine>[-<runtime>], build presets <platform>-<engine>[-<runtime>]-{debug,release}
  • Changed: C++ standard bumped to C++20 (required for Task<T> coroutines)
  • Changed: CMake minimum bumped to 3.31
  • Changed: Version.h is generated from Version.h.in at configure time using version.txt
  • Removed: Client::ChangeScene(index, sequence, data) (single-scene model)
  • Added: Client::MapChange(data) returning Map, plus MapAdd(data), MapRemove(map), MapIsValid(map) and GetMaps() for additive multi-map sessions
  • Changed: Client::CreateSceneObject renamed to Client::CreateMapObject. Takes Map instead of uint32_t scene and uint32_t engineFlags instead of ObjectSpecialFlags
  • Changed: DestroyModes::SceneChange renamed to DestroyModes::MapChange
  • Changed: RPC_InternalSceneChange renamed to RPC_InternalMapChange
  • Added: RPC_InternalMapAdd, RPC_InternalMapRemove, RPC_InternalOwnershipRequest, RPC_InternalRejectSubObject, RPC_InternalDestroyedMapActors, RPC_InternalForceDestroyObject, RPC_InternalForceAliveObject, RPC_InternalInput, RPC_InternalPlayerInterest, RPC_InternalOwnershipResponse (12 reserved IDs total in 1..1023)
  • Removed: OnSceneChange(index, sequence, Data&) broadcaster
  • Added: OnMapChange(unordered_map<Map, Data>&, bool initial) broadcaster
  • Changed: room property fusion_scene_data renamed to fusion_map_data (now base64-encoded FusionMapStateBuilder payload)
  • Removed: public ObjectRoot::Scene field. Use ObjectRoot::GetMap() returning Id.Map
  • Changed: PlayerId narrowed from uint32_t to uint16_t. Sentinels: MasterClientPlayerId = 0xFFFF, PluginPlayerId = 0xFFFE, ObjectOwnerPlayerId = 0xFFFD
  • Added: Map typedef (uint16_t)
  • Changed: ObjectId is now {Origin, Map, Counter} (still 8 bytes — Origin@0 16-bit, Map@2 16-bit, Counter@4 32-bit)
  • Changed: ObjectId(packed) decoding is now Origin = packed & UINT16_MAX; Map = (packed >> 16) & UINT16_MAX; Counter = packed >> 32
  • Changed: Client::GetNewObjectId() is now Client::GetNewObjectId(Map map)
  • Changed: ObjectTail grew from 24 bytes to 72 bytes. Added Reserved[8], PredictingPlayer, RejectedSequence, InputSequence, InputTime. Renamed SendRateRoomSendRate
  • Changed: Object::ExtraTailWords is now 18 (was 6)
  • Added: ObjectOwnerModes::PlayerPredicted = 5
  • Added: enum class SimulationMode { Shared = 0, Authority = 1 }
  • Changed: RpcFlags reworked from a struct (uint32_t _value) into an enum class with bitwise operators and a HasFlag(flags, flag) helper
  • Added: RpcFlags::IncorrectTargetForward, DontReplyWithResult, MapIncorrect, MaxDeliveryAttemptsReached, plus ErrorFlags aggregate
  • Removed: Rpc::TargetComponent (uint16_t) field
  • Removed: Rpc::DescriptorTypeHash (uint64_t) field. Routing now uses (Id, EventHash) only
  • Added: Rpc::Sequence (uint64_t) and Rpc::DeliveryAttempts (uint32_t)
  • Removed: DescriptorTypeHash parameter from Client::CreateUserRpc. New signature: (id, targetPlayer, targetObject, EventHash, data, dataLength)
  • Changed: Client::SendUserRpc now takes Rpc& (non-const) — the SDK assigns Sequence in place
  • Changed: Client::SetSendRate(obj, rate) renamed to SetRoomSendRate(obj, rate). ResetSendRate(obj) renamed to ResetRoomSendRate(obj)
  • Added: Client::ResetLocalSendRate(obj) (counterpart to existing SetLocalSendRate)
  • Removed: Client::ClearAllKeys, ClearAreaKeys, ClearUserKeys, SetAreaKeys, AddUserKey, RemoveUserKey, GetAllAreaKeys, GetAllUserKeys, GetInterestKeys. Replaced by InterestKeySet
  • Added: Client::GetLocalInterestKeys() / GetPlayerInterestKeys(player) returning InterestKeySet& (with Set, Remove, Clear, ClearAreaKeys, ClearUserKeys, SetAreaKeys, AddUserKey, RemoveUserKey, GetAllAreaKeys, GetAllUserKeys, IsDirty, ClearDirty and area/user encoding in the low bit)
  • Changed: Client::Start() now returns bool (was void) — validates fusion_config and fusion_map_data room properties and returns false on precondition failure
  • Added: Client::RefreshRoomCache()
  • Added: Client::SetDynamicOwnerCooldown(seconds) / GetDynamicOwnerCooldown() (default 1.0/3 seconds, configurable at runtime)
  • Removed: Object::DynamicOwnerCooldownTime static constant
  • Added: Client::SetAuthoritySendRate(rate) / GetAuthoritySendRate() (default 30 Hz)
  • Added: prediction APIs Client::GetSimulationMode(), GetPredictingPlayer(obj), SetPredictingPlayer(obj, player), IsPredictingPlayer(obj), HasInputAuthority(obj), GetInputSequence(obj), SetInputSequence(obj, seq), NextInputSequence()
  • Added: ObjectRoot::QueueInput(dt, payload), ExecuteInputs(dt), GetInputQueueCount(), GetInputQueueDeltaTime(), GetInputTime()
  • Added: Client::SetGiveAwayOwner(obj, player) to initiate explicit ownership transfers
  • Added: Client::RejectOwnershipRequest(obj) to deny inbound OnOwnershipRequest requests
  • Changed: OnOwnerWasGiven renamed to OnObjectOwnerAssigned
  • Changed: OnObjectPredictionOverride renamed to OnPredictionOverride
  • Added: broadcasters OnRpcError, OnObjectForceAlive, OnSubObjectForceAlive, OnInput, OnPredictionReset, OnOwnershipRequest (returns bool, aggregate any-true grants), OnOwnershipResponse
  • Changed: OnDestroyedMapActor(uint32_t, ObjectId) simplified to OnDestroyedMapActor(ObjectId) (first parameter dropped)
  • Removed: public Object::Header field
  • Added: Object::EngineBlob (Data), Object::EngineHash (uint64_t), Object::EngineFlags (uint32_t) replacing Header
  • Removed: enum class ObjectSpecialFlags. engineFlags (uint32_t) is supplied to Create* calls and stored on the base class
  • Removed: Object::Status field and OBJECT_STATUS_NEW / OBJECT_STATUS_PENDING / OBJECT_STATUS_CREATED constants
  • Added: ObjectRoot::IsReady() and GetHasReceivedState() lifecycle queries
  • Removed: Object::GetBytesSendLastTick, GetBytesReceivedLastTick, ConsumeBytesSendLastTick, ConsumeBytesReceivedLastTick, ResetReceivedBytes
  • Added: EMA-based stats Object::GetSendReport() / GetRecvReport(), ObjectRoot::GetCombinedSendReport() / GetCombinedRecvReport(), Client::GetSendReport / GetRecvReport / GetSendStateReport / GetRecvStateReport / GetSendRpcReport / GetRecvRpcReport. Returns EMAReport { TotalAvg, TotalAvgPerSecond, CurrentAvgPerSecond, Min, Max }. New header: EMA.h
  • Removed: public ObjectChild::TargetObjectHash (uint32_t) field
  • Changed: Client::CreateSubObject parameter targetObjectHash (uint32_t) renamed to engineHash (uint64_t, widened); ObjectSpecialFlags parameter replaced by uint32_t engineFlags
  • Changed: ObjectChild::Parent is now private. Access via static ObjectChild::GetParent(obj)
  • Changed: most ObjectRoot state is private with getters (GetMap, GetOwner, GetOwnerMode, GetTime, IsReady, GetHasReceivedState, GetPluginVersion, GetClientVersion, GetSubObjects)
  • Changed: ObjectRoot::RequiredObjects() returns std::span<ObjectId> (was ObjectId*)
  • Changed: Object::StringHeap is lazy-allocated ({0}); was pre-allocated to 1024 bytes
  • Changed: Object::SetHasValidData() no longer takes a bool argument (always sets the flag)
  • Changed: LogLevel enum is now a bitmask (Trace = 1 << 0 ... Error = 1 << 4)
  • Added: WriteBuffer::WriteMap(Map) / ReadBuffer::ReadMap() wire codec for the new Map typedef
  • Added: public PhotonCommon types: Broadcaster<Sig>, Subscription, ScopedSubscription, SubscriptionBag, Result<T, CodeT>, Task<T> (C++20 coroutine), Error<CodeT>, LogOutput, LogUtils, SpanCompat, StringType, StringViewType, CoroutineCompat, PhotonAssert
  • Changed: every long-running RealtimeClient operation now returns Task<Result<T>> (Connect / Reconnect / Disconnect / CreateRoom / JoinRoom / JoinOrCreateRoom / JoinRandomRoom / JoinRandomOrCreateRoom / LeaveRoom / JoinLobby / LeaveLobby / GetLobbyStats / FindFriends / WebRpc / AvailableRegions / SelectRegion)
  • Added: RealtimeClient broadcasters OnRoomJoined, OnRoomLeft, OnDirectConnectionEstablished, OnDirectConnectionFailed, OnCustomOperationResponse, OnCacheSliceChanged, OnPropertiesChangeFailed, OnAppStatsUpdated, OnWarning
  • Added: RealtimeClient::SendCustomOperation, SendCustomAuthData, SetAutoJoinLobby, GetCountPlayersIngame, GetCountGamesRunning, GetCountPlayersOnline
  • Added: public PhotonMatchmaking option/value types ClientConstructOptions, ConnectOptions, CreateRoomOptions, JoinRoomOptions, MatchmakingOptions, EventOptions, DirectMessageOptions, MutableRoomView, PlayerView, RoomListing, LobbyStats, FriendInfo, NetworkStats, TrafficStats, TrafficStatsGameLevel, WebFlags, WebRpcResponse, PropertyValue, AuthenticationValues, RegionInfo, ConnectionState, DisconnectCause, LobbyType, MatchmakingMode, RegionSelectionMode, ServerType, DirectMode, ReceiverGroup, CustomAuthenticationType, EventCache, EventCallback, ConnectionProtocol, SerializationProtocol, ErrorCode
  • Added: FusionRoomProperties.h exposing canonical room property keys (Config / MapData / SdkVersion), FusionConfigDefaults::Json, FusionMapStateBuilder::Build / Empty / BuildBase64 / EmptyBase64, FusionSdkVersionBuilder::ToBytes / ToBase64, Base64::Encode / Decode
  • Added: CAPI helpers fusion_room_property_key_config / _map_data / _sdk_version, fusion_config_defaults_json, fusion_map_state_empty_base64, fusion_sdk_version_current_base64, fusion_base64_encode / _decode
  • Added: CAPI web-flag bitmask FUSION_WEB_FLAG_HTTP_FORWARD, FUSION_WEB_FLAG_SEND_AUTH_COOKIE, FUSION_WEB_FLAG_SEND_SYNC, FUSION_WEB_FLAG_SEND_STATE
  • Added: Tools/FusionCore/Fusion{Config,Build,Install,ConfigBuildInstallAll,PackagePlugin}.ps1 PowerShell wrappers around the preset matrix
  • Added: Tools/Common/{Logging,TeamCity}/*.psm1 shared PowerShell modules
  • Added: Tools/Changelog/generate_changelog.py Python changelog generator (with mapping.json categorization)
  • Changed: GoogleTest 1.17.0 fetched via FetchContent when PHOTON_BUILD_TESTS=ON. gtest_force_shared_crt is matched to FUSION_MSVC_RUNTIME_LIBRARY
  • Migration Notes
    1. Global rename SharedMode::FusionCore:: (the included SharedModeCompat.h covers some callers; plan for a real rename)
    1. PlayerId is uint16_t and ObjectId's middle 16 bits are now Map — re-derive any custom packing or wire serialization. Sentinels moved from the 0xFFFFFFFF family to the 0xFFFF family
    1. ObjectTail is 72 bytes (ExtraTailWords = 18); recompute any direct word offsets and rename SendRateRoomSendRate
    1. Replace ChangeScene(idx, seq, data) with MapChange(data) (or MapAdd); subscribe to OnMapChange(maps, initial) and diff the table; swap DestroyModes::SceneChangeMapChange
    1. Replace CreateSceneObject with CreateMapObject. Pass Map instead of uint32_t scene and uint32_t engineFlags instead of ObjectSpecialFlags. For sub-objects, targetObjectHash becomes engineHash (uint64_t)
    1. Drop DescriptorTypeHash from CreateUserRpc; SendUserRpc takes Rpc& (non-const). Replace RpcFlags{._value=...} with the strong enum and HasFlag()
    1. Rename SetSendRateSetRoomSendRate and ResetSendRateResetRoomSendRate. Pair SetLocalSendRate with the new ResetLocalSendRate
    1. Client-level interest-key methods are gone; use Client::GetLocalInterestKeys() / GetPlayerInterestKeys(player) and call methods on the returned InterestKeySet
    1. Drop reads of Object::Status / SpecialFlags / Header and the per-frame byte counters. Use ObjectRoot::IsReady() / GetHasReceivedState(), EngineBlob / EngineFlags / EngineHash, and the EMA reports
    1. Subscribe to OnObjectOwnerAssigned (replaces OnOwnerWasGiven) and OnPredictionOverride (replaces OnObjectPredictionOverride); add OnPredictionReset if you use PlayerPredicted
    1. Initiate ownership transfers via Client::SetGiveAwayOwner(obj, player); grant inbound requests by returning true from OnOwnershipRequest; deny via Client::RejectOwnershipRequest(obj)
    1. For C ABI integrations, switch to FusionCAPI.h (the old SDK had no C ABI). For CMake on MSVC, set FUSION_MSVC_RUNTIME_LIBRARY to MultiThreaded or MultiThreadedDLL and pick the matching preset
Back to top