// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Standard Library using System; using System.Runtime.InteropServices; // GameKit using AWS.GameKit.Runtime.FeatureUtils; using AWS.GameKit.Runtime.Models; using AWS.GameKit.Runtime.Utils; namespace AWS.GameKit.Runtime.Features.GameKitGameSaving { /// /// Game Saving wrapper for GameKit C++ SDK calls /// public class GameSavingWrapper : GameKitFeatureWrapperBase { // Select the correct source path based on the platform #if UNITY_IPHONE && !UNITY_EDITOR private const string IMPORT = "__Internal"; #else private const string IMPORT = "aws-gamekit-game-saving"; #endif // DLL loading [DllImport(IMPORT)] private static extern IntPtr GameKitGameSavingInstanceCreateWithSessionManager(IntPtr sessionManager, FuncLoggingCallback logCb, string[] localSlotInformationFilePaths, uint arraySize, FileActions fileActions); [DllImport(IMPORT)] private static extern void GameKitGameSavingInstanceRelease(IntPtr gameSavingInstance); [DllImport(IMPORT)] private static extern void GameKitAddLocalSlots(IntPtr gameSavingInstance, string[] localSlotInformationFilePaths, uint arraySize); [DllImport(IMPORT)] private static extern void GameKitClearSyncedSlots(IntPtr gameSavingInstance); [DllImport(IMPORT)] private static extern void GameKitSetFileActions(IntPtr gameSavingInstance, FileActions fileActions); [DllImport(IMPORT)] private static extern uint GameKitGetAllSlotSyncStatuses(IntPtr gameSavingInstance, IntPtr dispatchReceiver, FuncGameSavingResponseCallback resultCb, bool waitForAllPages, uint pageSize); [DllImport(IMPORT)] private static extern uint GameKitGetSlotSyncStatus(IntPtr gameSavingInstance, IntPtr dispatchReceiver, FuncGameSavingSlotActionResponseCallback resultCb, string slotName); [DllImport(IMPORT)] private static extern uint GameKitDeleteSlot(IntPtr gameSavingInstance, IntPtr dispatchReceiver, FuncGameSavingSlotActionResponseCallback resultCb, string slotName); [DllImport(IMPORT)] private static extern uint GameKitSaveSlot(IntPtr gameSavingInstance, IntPtr dispatchReceiver, FuncGameSavingSlotActionResponseCallback resultCb, GameSavingModel model); [DllImport(IMPORT)] private static extern uint GameKitLoadSlot(IntPtr gameSavingInstance, IntPtr dispatchReceiver, FuncGameSavingDataResponseCallback resultCb, GameSavingModel model); [AOT.MonoPInvokeCallback(typeof(FuncGameSavingResponseCallback))] protected static void GameSavingResponseCallback(IntPtr dispatchReceiver, IntPtr cachedSlots, uint slotCount, bool complete, uint callStatus) { // retrieve SlotListResult object reference from encoded IntPtr SlotListResult result = Marshaller.GetDispatchObject(dispatchReceiver); // handle assignments to the result object result.CachedSlots = Marshaller.IntPtrToArray(cachedSlots, slotCount); // copy the GK Error status result.ResultCode = callStatus; } [AOT.MonoPInvokeCallback(typeof(FuncGameSavingSlotActionResponseCallback))] protected static void GameSavingSlotActionResponseCallback(IntPtr dispatchReceiver, IntPtr cachedSlots, uint slotCount, IntPtr activeSlot, uint callStatus) { // retrieve SlotActionResult object reference from encoded IntPtr SlotActionResult result = Marshaller.GetDispatchObject(dispatchReceiver); // handle assignments to the result object result.CachedSlots = Marshaller.IntPtrToArray(cachedSlots, slotCount); result.ActionedSlot = Marshal.PtrToStructure(activeSlot); // copy the GK Error status result.ResultCode = callStatus; } [AOT.MonoPInvokeCallback(typeof(FuncGameSavingDataResponseCallback))] protected static void GameSavingDataResponseCallback(IntPtr dispatchReceiver, IntPtr cachedSlots, uint slotCount, IntPtr slot, byte[] data, uint dataSize, uint callStatus) { // retrieve SlotDataResult object reference from encoded IntPtr SlotDataResult result = Marshaller.GetDispatchObject(dispatchReceiver); // handle assignments to the result object result.CachedSlots = Marshaller.IntPtrToArray(cachedSlots, slotCount); result.ActionedSlot = Marshal.PtrToStructure(slot); result.Data = data; result.DataSize = dataSize; // copy the GK Error status result.ResultCode = callStatus; } public void AddLocalSlots(AddLocalSlotsDesc addSlotDesc) { DllLoader.TryDll(() => GameKitAddLocalSlots(GetInstance(), addSlotDesc.LocalSlotInformationFilePaths, (uint)addSlotDesc.LocalSlotInformationFilePaths.Length), nameof(GameKitAddLocalSlots)); } public void ClearSyncedSlots() { DllLoader.TryDll(() => GameKitClearSyncedSlots(GetInstance()), nameof(GameKitClearSyncedSlots)); } public void SetFileActions(FileActions fileActions) { DllLoader.TryDll(() => GameKitSetFileActions(GetInstance(), fileActions), nameof(GameKitSetFileActions)); } public SlotListResult GetAllSlotSyncStatuses() { SlotListResult result = new SlotListResult(); DllLoader.TryDll(result, (IntPtr dispatchReceiver) => GameKitGetAllSlotSyncStatuses(GetInstance(), dispatchReceiver, GameSavingResponseCallback, true, GameSavingConstants.GET_ALL_SLOT_SYNC_STATUSES_DEFAULT_PAGE_SIZE), nameof(GameKitGetAllSlotSyncStatuses)); return result; } public SlotActionResult GetSlotSyncStatus(string slotName) { SlotActionResult result = new SlotActionResult(); DllLoader.TryDll(result, (IntPtr dispatchReceiver) => GameKitGetSlotSyncStatus(GetInstance(), dispatchReceiver, GameSavingSlotActionResponseCallback, slotName), nameof(GameKitGetSlotSyncStatus)); return result; } public SlotActionResult DeleteSlot(string slotName) { SlotActionResult result = new SlotActionResult(); DllLoader.TryDll(result, (IntPtr dispatchReceiver) => GameKitDeleteSlot(GetInstance(), dispatchReceiver, GameSavingSlotActionResponseCallback, slotName), nameof(GameKitDeleteSlot)); return result; } public SlotActionResult SaveSlot(SaveSlotDesc saveSlotDesc) { SlotActionResult result = new SlotActionResult(); GCHandle dataPinHandle = GCHandle.Alloc(saveSlotDesc.Data, GCHandleType.Pinned); GameSavingModel gameSavingModel = DefaultGameSavingModel.Make(); gameSavingModel.SlotName = saveSlotDesc.SlotName; gameSavingModel.Metadata = saveSlotDesc.Metadata; gameSavingModel.EpochTime = saveSlotDesc.EpochTime; gameSavingModel.OverrideSync = saveSlotDesc.OverrideSync; gameSavingModel.Data = dataPinHandle.AddrOfPinnedObject(); gameSavingModel.DataSize = (uint)saveSlotDesc.Data.Length; gameSavingModel.LocalSlotInformationFilePath = saveSlotDesc.SaveInfoFilePath; DllLoader.TryDll(result, (IntPtr dispatchReceiver) => GameKitSaveSlot(GetInstance(), dispatchReceiver, GameSavingSlotActionResponseCallback, gameSavingModel), nameof(GameKitSaveSlot)); dataPinHandle.Free(); return result; } public SlotDataResult LoadSlot(LoadSlotDesc loadSlotDesc) { SlotDataResult result = new SlotDataResult(); GCHandle dataPinHandle = GCHandle.Alloc(loadSlotDesc.Data, GCHandleType.Pinned); GameSavingModel gameSavingModel = DefaultGameSavingModel.Make(); gameSavingModel.SlotName = loadSlotDesc.SlotName; gameSavingModel.OverrideSync = loadSlotDesc.OverrideSync; gameSavingModel.Data = dataPinHandle.AddrOfPinnedObject(); gameSavingModel.DataSize = (uint)loadSlotDesc.Data.Length; gameSavingModel.LocalSlotInformationFilePath = loadSlotDesc.SaveInfoFilePath; DllLoader.TryDll(result, (IntPtr dispatchReceiver) => GameKitLoadSlot(GetInstance(), dispatchReceiver, GameSavingDataResponseCallback, gameSavingModel), nameof(GameKitLoadSlot)); dataPinHandle.Free(); return result; } protected override IntPtr Create(IntPtr sessionManager, FuncLoggingCallback logCb) { return DllLoader.TryDll(() => GameKitGameSavingInstanceCreateWithSessionManager(sessionManager, logCb, new string[] { }, 0, DefaultFileActions.Make()), nameof(GameKitGameSavingInstanceCreateWithSessionManager), IntPtr.Zero); } protected override void Release(IntPtr instance) { DllLoader.TryDll(() => GameKitGameSavingInstanceRelease(instance), nameof(GameKitGameSavingInstanceRelease)); } } }