spookygames / gdx-gameservices

Game services wrapper for libgdx.
MIT License
6 stars 1 forks source link

SavedGame loading doesn't work on libgdx iOS game #3

Open DmitriySmerchinskiy opened 7 months ago

DmitriySmerchinskiy commented 7 months ago

Hi, and thank you so much for your library. It's very useful for my game.

It works pretty straightforward for my Android build, but doesn't work on iOS. I use emulator for iOS testing and see logs, that the library successfully performed game save, but when trying to load I see that there aren't any saved files. Of course, I logged in before trying to obtain saves. And on my emulator, I logged in with Apple ID and iCloud available also. I also tried to test on real device, but after removing game and reinstalling it saves didn't restore. Unfortunately I can't see logs from my real devices due to recent updates of iOS. So I only can see logs from the emulator.

This is my code how I create GameCenterServiceHandler:

@Override
    public GameServicesHandler getGameServicesHandler() {
        if (gameCenterServicesHandler == null) {
            gameCenterServicesHandler = new GameCenterServicesHandler(UIApplication.getSharedApplication().getKeyWindow().getRootViewController());
        }
        return gameCenterServicesHandler;
    }

public interface GameServiceWrapper {

    GameServicesHandler getGameServicesHandler();
}

This is my code how I login before trying to load saves:

public void login(final CompletionListener completionListener) {
        gameServiceWrapper.getGameServicesHandler().isLoggedIn().onCompletion(new ServiceCompletionCallback<Boolean>() {
            @Override
            public void onSuccess(Boolean isLoggedIn) {
                System.out.println("Games Service: Successfully checked is player logged in = " + isLoggedIn);
                if (!isLoggedIn) {
                    gameServiceWrapper.getGameServicesHandler().login().onCompletion(new ServiceCompletionCallback<Void>() {
                        @Override
                        public void onSuccess(Void result) {
                            System.out.println("Game Service: Player successfully logged in");
                            completionListener.completed();
                            gameServiceWrapper.getGameServicesHandler().getPlayerName().onCompletion(new ServiceCompletionCallback<String>() {
                                @Override
                                public void onSuccess(String result) {
                                    System.out.println("Game Service: Player name = " + result);
                                }

                                @Override
                                public void onError(ServiceError error) {
                                    System.err.println("Game Service: Unable to get player name, because " + error.getErrorMessage());
                                }
                            });
                        }

                        @Override
                        public void onError(ServiceError error) {
                            System.err.println("Games Service: Unable to log in player, because: " + error.getErrorMessage());
                            completionListener.completed();
                        }
                    });
                } else {
                    completionListener.completed();
                }
            }

            @Override
            public void onError(ServiceError error) {
                System.err.println("Games Service: Unable to check is player logged in");
                completionListener.completed();
            }
        });
    }

This is my code how I load save file:

public void loadFile(final String fileNameAndId, final FileLoadingCallback callback) {
        final FileHandle file = Gdx.files.local(fileNameAndId);
        gameServiceWrapper.getGameServicesHandler().getSavedGames().onCompletion(new ServiceCompletionCallback<Iterable<SavedGame>>() {
            @Override
            public void onSuccess(Iterable<SavedGame> result) {
                boolean found = false;
                System.out.println("Game Service: Saved Games loaded. List has next = " + result.iterator().hasNext());
                for (SavedGame savedGame : result) {
                    System.out.println("Game Service: Save found with id = " + savedGame.getId() + " and title = " + savedGame.getTitle());
                    if (savedGame.getId().contains(fileNameAndId)) {
                        if (!file.exists() || savedGame.getTimestamp() > file.lastModified()) {
                            System.out.println("Game Service: Service file more actual " + fileNameAndId);
                            loadAndRead(savedGame, file, callback);
                        } else {
                            System.out.println("Game Service: Local file is more actual than service file " + fileNameAndId);
                            callback.loadCompleted(file);
                        }
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    System.err.println("Game Service: Game save not found for file " + fileNameAndId);
                    callback.loadCompleted(file);
                }
            }

            @Override
            public void onError(ServiceError error) {
                System.err.println("Game Service: Unable to get saved games trying load " + fileNameAndId);
                callback.loadCompleted(file);
            }
        });
    }

private void loadAndRead(final SavedGame savedGame, final FileHandle file, final FileLoadingCallback callback) {
        gameServiceWrapper.getGameServicesHandler().loadSavedGameData(savedGame).onCompletion(new ServiceCompletionCallback<byte[]>() {
            @Override
            public void onSuccess(byte[] levelsAvailabilityBytes) {
                file.writeBytes(levelsAvailabilityBytes, false);
                callback.loadCompleted(file);
            }

            @Override
            public void onError(ServiceError error) {
                System.err.println("Game Service: Unable to load game save for " + savedGame.getId());
                callback.loadCompleted(file);
            }
        });
    }

This is my code how I save file:

public void saveFile(String fileNameAndId, FileHandle file) {
        saveFile(fileNameAndId, file, null);
    }

    public void saveFile(final String fileNameAndId, final FileHandle file, final CompletionListener completionListener) {
        gameServiceWrapper.getGameServicesHandler().submitSavedGame(new GameSave(fileNameAndId), file.readBytes()).onCompletion(new ServiceCompletionCallback<Void>() {
            @Override
            public void onError(ServiceError error) {
                System.err.println("Game Service: Error saving file " + fileNameAndId);
                if (completionListener != null) {
                    completionListener.completed();
                }
            }

            @Override
            public void onSuccess(Void result) {
                System.out.println("Game Service: Successfully saved file " + fileNameAndId);
                if (completionListener != null) {
                    completionListener.completed();
                }
            }
        });
    }

I load saves on app launch and save each time data is changed. So I see these logs on startup: (I show properties.json as an example)

Games Service: Successfully checked is player logged in = false
Game Service: Player successfully logged in
Game Service: Player name = dmytro-diviator
Game Service: Saved Games loaded. List has next = false
Game Service: Game save not found for file properties.json

When trying to save, I see these logs:

Game Service: Successfully saved file preferences.json

My environment:

MacOS Sonoma 14.4.1
Android Studio Iguana | 2023.2.1 Patch 1
iOS Simulator Version 15.3 (1019.2)

gdxVersion = '1.12.1'
roboVMVersion = '2.3.21'
gdxGameservicesVersion = '3.0.0'

classpath 'com.android.tools.build:gradle:8.1.2'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.20'

Also, I did everything according to this guide

Will be very glad to get help from you. Thanks in advance.

DmitriySmerchinskiy commented 7 months ago

Also added iCloud support turning iCloud documents checkbox on. Then, I found that iCloud stores data from my app, so looks like this issue is related to loading SavedGames:

gameServiceWrapper.getGameServicesHandler().getSavedGames()