Wireless, Cross-device, photo syncing in 2015

Once again I'm visiting my work flow for syncing photos wirelessly from my phone, to my computer and back to the phone. I have blogged about this a few times in the past. In my last blog post regarding photo sync, I had turned to Lightroom mobile. It worked well for photos, but lacked any kind of support for videos.

A lot has changed over the last year. Now both Apple and Google provide bi-directional, wireless, sync of both photos and videos to and from your mobile devices, while keeping originals synced on your desktop computer and stored in the cloud. Take a photo or record a video on your device, open your computer to edit it, view the changes later in the day on your phone. It's pretty slick.

Now that both companies support sync in this manor, I thought I'd go over my workflow. The changes in the way both services handle the sync have caused me to change my work flow a bit. Since I use iOS and OS X devices most, I will be writing about Apples services today. At some point in the future I'll try and write something up on using Google Photos + Google Drive on Macs and iOS for cross-device syncing of photos and videos.

iCloud Photo Library

In 2014 Apple introduced the new iCloud Photo Library and Photos app in iOS 8. The iCloud Photo Library handles synchronizing all of your full resolution photos and videos across every iOS and OS X based device you own. Unfortunately, this is not available on AppleTV.

So, we need to turn on iCloud Photo Library on the iOS devices. You can do that by going into the iOS Settings app and navigating to Photos & Camera.

I typically leave my iOS devices with Optimize iPhone Storage enabled. This will upload the original files to the iCloud Photo Library; saving a reduce size version for the smaller iOS screens on the device. In some cases, it will remove the photo all together and leave a thumbnail. The next time you view the photo, it will download it again. I've only seen this happen on old photos, or when re-installing iOS fresh.

When you make this change you will notice that the Camera Roll is no longer available. Instead it is replaced with All Photos. That is because the photos are no longer stored on-device. Now they are stored in a shared library with multiple iOS devices, which requires more than what the original Camera Roll provided.

Now that we have iCloud Photo Library setup on your iOS devices to upload all of their photos and movies, we need to setup OS X. The Mac works much the same as iOS. You open up the Photos app (requires Yosemite or newer) and open up it's preferences. The only difference is that we want to tell the app to download all of the originals onto our Mac's hard-drive. This way, we always have our originals locally and aren't depending on the cloud keeping them forever.

Now we have all of our photos (and videos!) synchronizing wireless between our iOS devices and the Mac.

iCloud Photo Library to Lightroom

So we now have our photos and videos locally on our internal or external hard-drives. What do we do with them then? We export them from iCloud Photo Library and move them into Lightroom! I use Lightroom to handle all of my keywording and orginization of my photos and videos. The new OS X based Photos app fully supports keywording and organizing into albums and folders. It does have some issues, like not being able to move an album in and out of folders once the album is created. Keywords will sync across all of your devices, but the folder/album organization will not. Albums are only synced to iOS in a flattened layout, with no nested folders. An example of this on iOS looks like the following screenshot, where all of the years are flattened out.

As a result of this, I will continue to use Lightroom for my photo organization. I keep Lightroom as my source of truth, where all of my originals will always live. In Lightroom, they are organized like this:

So how do I get my photos from the OS X Photos app into Lightroom? I use a Smart Album in the Photos app! With Smart Albums, I can keep track of what date I last pulled photos into my Lightroom library. There are two Smart Albums I create. One that filters all photos that I have already brought into my Lightroom library, and a second that filters all photos that I have yet to export from Photos, and import into Lightroom.

So before we create our Smart Albums, we must first actually export the photos from iCloud Photo Library and get them into Lightroom. When I first turned on iCloud Photo Library, I had to wait just a little over 24 hours while it got all of the photos synchornized across the devices and downloaded onto my Mac. Your mileage will vary, depending on how many you have. You can see in the Photos preferences picture above, that it tells me my Photos library was just updated. That means I am in sync and nothing is outstanding. During a first time sync, it will count down how many photos and/or videos it has remaining to download onto your Mac.

So, if your sync is done, select the Photos library

Next you will need to select every photo in that library. You can do this with Command+A or using the Edit menu.

Lastly, we will export the selected photos from the Photos app, so that we can import them into Lightroom. Note that exporting will not remove them from iCloud Photo Library. It will instead create a copy of every photo and place the copy in the desired export folder. This is ideal, so that we can continue to view the photos and videos on our devices without any issue.

You can set some settings on your photos prior to the export taking place. I typically use the following settings for my exports.

Clicking the Export button will prompt you with where you want to store the files. You can store them anywhere for now. When we do the import into Lightroom, the Lightroom application will move them into their final resting place within your Lightroom library. So just pick a temporary location for now.

Now that the photos and videos have been exported, we need to get them into Lightroom. We can do that by opening Lightroom and doing an import.

On the left-hand side of the Lightroom import screen is the source of the files you want to bring into Lightroom. You will navigate to your temporary folder that holds your exported iCloud Photos. On the right-hand side you will select where your Lightroom library is, this will be their permanent storage location.

Now your photos are all set in Lightroom. You can go ahead and organize them, keyword them and edit them as you want. Next, make a back up of your Lightroom library! It's always good to keep a back up of your photos elsewhere once you have them all imported. Lightroom handles backups automatically for you when ever you close the app.

Once you are done organizing and keywording all of your photos and videos, go ahead and select them all in iCloud Photo Library and delete them. Once they are deleted, you will drag and drop all of the photos from Lightroom, into iCloud Photo Library. This will sync all of the keywords, meta-data, and edits made to your photos on to all of your devices.

Now you have your photos in sync across all devices. The first time you do this, it will take a bit. If you do this every couple of weeks, it won't be to much of a hastle. Let's cover how to do that now, using the Smart Albums I mentioned earlier!

Smart Albums

We will create a new Smart Album that will keep track of what photos and videos you have already imported and processed into Lightroom, and brought back into the iCloud Photo Library. A second Smart Album keeps track of what photos and videos are in your iCloud Photo Library, but not in Lightroom. These are going to be handled simply by tracking dates.

The first smart album is called "Importing - Pending", meaning these photos and videos are pending the import process into our master Lightroom library. You could call it something else, like "Need exporting" if you want.

This Smart Album will show me all of the photos and videos I need to export from iCloud Photo Library, and import into Lightroom. The nice part of using a Smart Album like this, is that now I know all of the photos I need to delete, and re-upload once I am done organizing my stuff in Lightroom. I can open this Smart Album, select all of the photos and videos, delete them, then drag and drop my stuff from Lightroom back into iCloud Photo Library. I set the date to be the date that I exported all of those photos.

The next Smart Album is what we will use to track what has already been imported into our Lightroom library. This will be called "Importing - Processed" and will have a date set to the day of the day you exported your photos. There might be some overlap when you next do some importing, but that's alright. Lightroom does a good job of detecting duplicate photos and show which ones it thinks are duplicates and won't import. Worse case, you have to review each photo for that one day. That's typically not many photos and videos and is worth the extra step to make sure you don't miss any.

Another option would be to add a keyword to every photo in your Lightroom library with a Lightroom keyword. Then you can create Smart Albums that look for that keyword. This way, new photos will lack it and can be added. The only downside is that keywords can't be applied to videos, which is why I chose not to go that route.

Now you have everything you need to keep both Photos and videos in sync across every single device, while maintaining the original, full-resolution, files on your local computer. By adding keywords correctly, you can do full searches in iOS and find photos really fast. As an example, I performed a search in my iCloud Photo Library (with nearly 9,000 files) on iOS for photos of an old car I had 8 years ago. The search results came back instantaneously.

Proper keywording of your photos in Lightroom (or in iCloud Photo Library if you don't want to use Lightroom) can really make it easy to find your photos.

Why Lightroom?

I used Lightroom in this example just because it is the photo suite that I use. The entire section based on Lightroom can be applied to the old iPhoto app or Aperture. If you want to keep your photos in iCloud Photo Library, you can do all the keywording within that app and not both with the whole export/import process. Instead just build smart albums that have look for a "processed" keyword, and add that keyword to every photo you process in iCloud Photo Library directly.

AppleTv

Sadly, the new iCloud Photo Library is not supported by the current generation of AppleTV. I'm not sure why, other than the fact that storage on the device might be an issue (iCloud Photo Library includes videos, where Photostream does not). I'm not sure, so for the time being when you have visitors, you'll need to Airplay your photos to your TV from an iOS device or from your Mac.

Another option could be to use the Flickr app. I have not used the app personally, so I'm not sure what options it has. The app does exist on AppleTV and you can upload every photo in your Lightroom library up to Flickr for viewing on the AppleTV.

I'm hoping I'll be able to revise this post once the new AppleTV is released, with a guide on viewing the iCloud Photo Library on it. There's no official word yet that it will be supported.

Mud Designers new home on GitHub

I had previously been maintaining two different repositories for the Mud Designer. The first was on my personal GitHub account and the other was on Codeplex.

A few weeks ago I created a new team on Git Hub called Mud Designer. There are several repositories under the team, such as the Mud Engine, the new cross-platform server stuff and the documentation source for the real help docs.

In order to help people navigate the repositories, I have setup a Home repository. For all things Mud Designer, the Mud Designer Home should be your starting place.

Some of the repositories have source in a branch other than Master right now as its being developed. So be sure to check all of the branches out when exploring the code.

Project milestones have been defined on the Mud Engine repository and the server repository. Over the next couple of weeks I will be creating backlog work items in the issue tracker, so people can get an idea Of how far along the project is in each milestone.

The previous repositories found on Codeplex and under my account will be deprecated going forward.

Mud Engine + Server running on Mac OS X

As of tonight, the Mud Engine has been tested and runs on Macs running OS X. I was even able to wire up the server and get a OS X server running with the game.

Thanks to how the server was refactored into the adapter pattern I adopted a couple of weeks ago, it took very little code to wire up a OS X based server.

The code

class MainClass
{
    public static void Main(string[] args)
    {
        SetupMessageBrokering ();

        var bootstrap = new Bootstrap ();
        bool startupCompleted = false;
        bootstrap.Initialize ((game, server) =>
        {
            // Start the game loop.
            while(game.IsRunning)
            {
                if (!startupCompleted)
                {
                    startupCompleted = true;
                }

                Thread.Sleep(1);
            }
        });

        while(!startupCompleted)
        {
            Thread.Sleep (1);
        }
    }

    static void SetupMessageBrokering()
    {
        MessageBrokerFactory.Instance.Subscribe<InfoMessage>(
            (msg, subscription) => Console.WriteLine(msg.Content));

        MessageBrokerFactory.Instance.Subscribe<GameMessage>(
            (msg, subscription) => Console.WriteLine(msg.Content));

        MessageBrokerFactory.Instance.Subscribe<PlayerCreatedMessage>(
            (msg, sub) => Console.WriteLine("Player connected."));

        MessageBrokerFactory.Instance.Subscribe<PlayerDeletionMessage>(
            (msg, sub) =>
        {
            Console.WriteLine("Player disconnected.");
        });
    }
}

This code should look almost identical to the source previously posted showing the Mud Engine server running on Windows. The only difference is that I abstracted the code that can be shared across the two platforms into a bootstrap. The shared code is stuff like configuring the server and game, setting up the game and adapter and starting the game.

As development of the engine continues, I will regularly check and make sure it builds on OS X. The engine itself and its server should always run cross-platform without any issues.

I'm not sure yet what I am going to do in regards to the designer tools. Initially I was going to write it as a XAML app for Windows. Considering that the engine can now run on OS X (and I will be testing it on Linux soon), I might reconsider and look at a more cross-platform UI approach. Perhaps that would be a good excuse for me to pick up the new cross-platform ASP.Net MVC 6 stuff Microsoft is doing, and build a cross-platform self-contained web application for the designer.

Anyway, I wanted to share the progress on my cross-plat goals. At the moment, everything seems to be working just fine between Windows and OS X.

The new configurable Mud Engine Server Adapter

Back in May I posted about how you could configure the mud server for use with the Mud Engine. Since then, I have built out an implementation of the Adapter pattern. With that, I wanted to demonstrate how you would startup the server with the engine, and configure it.

Previously in the Mud Engine

In the last iteration of my configuration setup, you had to implement the abstract ServerBootstrap class, and then build out an implementation of IServerConfiguration. The bootstrap implementation looked something like this.

public class DefaultServerBootstrap : ServerBootstrap
{
    protected override void Run()
    {
        this.Server.GetCurrentGame()
            .NotificationCenter
            .Subscribe<ServerMessage>((msg, sub) => 
                Console.Write(msg.Content));

         while (this.Server.Status != ServerStatus.Stopped)
        {
            Thread.Sleep(100);
        }
    }

    protected override void RegisterAssemblies()
    {
        base.RegisterAssemblies();
    }

    protected override void ConfigureServices()
    {
    }

    protected override IServerConfiguration CreateServerConfiguration()
    {
        return new ServerConfiguration();
    }

    protected override IServer CreateServer()
    {
        var server = new Server();
        server.PlayerConnected += this.ExecuteInitialCommand;
        return server;
    }

    protected override IGame CreateGame()
    {
        return new DefaultGame();
    }

    protected override IInputCommand InitialConnectionCommand()
    {
        returnnew PlayerLoginCommand();
    }

    protected override void RegisterAllowedSecurityRoles(IEnumerable<ISecurityRole> roles)
    {
    }
}

Then in the application startup, you had to setup the bootstrap.

public static void Main(string[] args)
{
    var bootstrap = new DefaultServerBootstrap();    
    Task bootstrapTask = bootstrap.Initialize();
    bootstrapTask.Wait();
}

This was the minimum that had to be done in order to start the game with a server. There were several issues with this approach, one of which is violating SRP. The bootstrap does a lot of different things that aren't even related to the server. It defines the initial command, creates a player, and creates the game. None of which are specific to the server. These actions can be applicable in a single-player game as well.

The other thing that the bootstrap does is configures any services, and register security roles with the services. Gross. The server startup should be free of IoC dependency injection setup goo. So I set out to fix that with the new Mud Engine Adapters.

Setting up a server with adapters

Now that the server has been migrated over to use the adapter architecture, it's much more straight-forward to get a server running. Previously, the server owned the game. Now, the game owns the server - it just doesn't know it.

To start up the game, and give it a server, we do this.

static void Main(string[] args)
{        
    var serverConfig = new ServerConfiguration();
    IServer server = new WindowsServer(new TestPlayerFactory(), new ConnectionFactory(), serverConfig);

    var gameConfig = new GameConfiguration();
    gameConfig.UseAdapter(server);  

    var game = new MudGame();
    game.Configure(gameConfig);

    Task gameStartTask = game.StartAsync();
    gameStartTask.Wait();
}

In the code above, we create a serverconfiguration. Then we create a WindowsServer instance, giving it a couple of factories and our config. Next we we create a GameConfiguration and register our WindowsServer with the game config. When we call game.Configure(gameConfig), the game will consume the WindowsServer adapter and automatically configure the server using the ServerConfiguration.

Lastly, we start the game calling game.StartAsync(). This initialize and run all of the registered adapters that the game has. In our case, it initializes and runs the WindowsServer. At this point, the WindowsServer is running and can accept incoming client connections.

There is some flexability when it comes to configuring adapters. Each adapter can either skip configuration all-together, or opt into configuration by requiring a configuration class. This can be any class that implements the IConfiguration interface. Taking this approach allows each adapter to have their own config that can be tailored to what they want to expose. In the case of Server Configuration, there is quiet a bit we can do with it. For instance:

var serverConfig = new ServerConfiguration();
serverConfig.OnServerStartup = (context) => 
    Console.WriteLine($"Server running on port {context.Server.RunningPort}");

That code registers a callback that will be invoked when the server is starting. In this example, we just lookup the port the server is running on and write it out to the console. You can do more then just that however.

static void Main(string[] args)
{        
    var serverConfig = new ServerConfiguration();
    serverConfig.OnServerStartup = (context) =>
    {
        context.ListeningSocket.BeginAccept(
            new AsyncCallback(Program.HandleClientConnection), context.ListeningSocket);
        context.SetServerState(ServerStatus.Running);
        context.IsHandled = true;
    };

    IServer server = new WindowsServer(new TestPlayerFactory(), new ConnectionFactory(), serverConfig);

    var gameConfig = new GameConfiguration();
    gameConfig.UseAdapter(server);

    var game = new MudGame();
    game.Configure(gameConfig);

    Task gameStartTask = game.StartAsync();
    gameStartTask.Wait();
}

private static void HandleClientConnection(IAsyncResult result)
{
    Socket server = (Socket)result.AsyncState;
    Socket clientConnection = server.EndAccept(result);

    // Fetch the next incoming connection.
    server.BeginAccept(new AsyncCallback(HandleClientConnection), server);

    // Create player character here.
}

In this example, we used both the WindowsServer and it's Socket to completely replace the way incoming connections are handled. We're not replacing how client communication between the server and client are handled (that is planned) but allowing users to define custom server behavior without reimplementing IServer. At the end of the OnServerStartup callback, we set IsHandled to true, which tells the server to stop using its internal startup and rely on the custom logic being defined.

There are more things you can do, such as intercepting the shutdown of the server, client connections, disconnects and more.

Sharing information across adapters

The server publishes out messages that you can intercept and react to as well. An example is this:

static void Main(string[] args)
{
    SetupMessageBrokering();

    var serverConfig = new ServerConfiguration();
    IServer server = new WindowsServer(new TestPlayerFactory(), new ConnectionFactory(), serverConfig);

    var gameConfig = new GameConfiguration();
    gameConfig.UseAdapter(server);

    var game = new MudGame();
    game.Configure(gameConfig);

    Task gameStartTask = game.StartAsync();
    gameStartTask.Wait();
}

static void SetupMessageBrokering()
{
    MessageBrokerFactory.Instance.Subscribe<InfoMessage>(
        (msg, subscription) => Console.WriteLine(msg.Content));

    MessageBrokerFactory.Instance.Subscribe<GameMessage>(
        (msg, subscription) => Console.WriteLine(msg.Content));

    MessageBrokerFactory.Instance.Subscribe<PlayerCreatedMessage>(
        (msg, sub) => Console.WriteLine("Player connected."));

    MessageBrokerFactory.Instance.Subscribe<PlayerDeletionMessage>(
        (msg, sub) =>
        {
            Console.WriteLine("Player disconnected.");
        });
}

The first thing we do is subscribe, via the MessageBroker, to a series of messages that can be published by other objects. In this scenario, the WindowsServer will publish messages that are InfoMessage, PlayerCreatedMessage and PlayerDeletionMessage. The MudGame will publish GameMessage notifications. This looks like this when the server is running and has accepted several connections, and had a few disconnects.

The flexability given now with adapters and their custom configurators will make it easy to get up and running, and still provide you with a lot of flexability when you want to do more advanced things.

As always you can replace the IServer or IServerConfiguration implementations with your own all together. Since IServer inherits from IAdapter your custom implementation can plug straight into the game using the game.UseAdapter(customServer) call.

Handling what is missing

The original implementation shown at the start of this post had some other things being done. It handled the setup of security and commanding. That responsibility will be moved to additional adapters, which will run independent of the server and game. They can subscribe to messages sent from the server and react to them, launching the initial login command and handling security without knowing that the server even exists.

var gameConfig = new GameConfiguration();
gameConfig.UseAdapter(new WindowsServer());
gameConfig.UseAdapter(new CommandManager());
gameConfig.UseAdapter(new SecurityBroker());
gameConfig.UseAdapter(new WorldManager());

var game = new MudGame();
game.Configure(gameConfig);

Task gameStartTask = game.StartAsync();

Each one of the adapters shown above have not been written yet; they are coming. When they are ready, they will share the same level of flexability as the server, using configuration objects that you can intercept and interact with.

There is a lot of other new stuff happening in the engine that won't fit into this post, like a new home on GitHub (more on that in a different post), character APIs and real usage documentation.

More coming soon!

Introducing adapters in Mud Engine

I've had a pretty configurable startup sequence with the Mud Engine for a bit now, but I wasn't really happy with it. The issue that I had was that you still performed to much initialization logic in a boot strap class, or in the server app startup (not the server implementation themselves).

I wanted to make the whole configuration piece of the engine more extensible, and easier to plug into. The engine already uses a custom message brokering pipeline to publish messages to subscribers, and so I wanted to harness that a bit with the configuration.

Adapters

There is a new interface in the engine called IAdapter. It provides a series of methods for letting adapters subscribe to messages published from within the engine, along with publishing their own. It's an IInitializableComponent, so it can be initialized and deleted. This allows for adapters to perform cleanup, such as unsubscribing from the message broker, when they are being deleted.

The IAdapter includes a Name property so that the adapter can have a name; most importantly though is the Start(IGame) method. This method allows your adapters to spin off their own background tasks and do what ever they want while the game continues to run.

The engine currently has a WorldManager adapter, which initializes all of the worlds it is given and starts the world clocks/weather climate clocks etc. The engine server is being modified as well allowing it to become an adapter that starts up and runs when the game starts.

How it works

So how do adapters fit in to the workflow of the engine? Adapters are registered with a modified IGameConfiguration interface. This interface is then given to an IGame when you call Configure() on the game instance. The default IGame implementation (MudGame) pulls all of the adapters out of the configuration class and initializes them when IGame.Initialize() is invoked. It then starts each one of the adapters when the IGame.StartAsync() method is invoked. When IGame.StartAsync() is invoked, an internal game loop is created and the game will forever run. Because of this, adapters must not perform any long running or blocking tasks. If you have to perform a long running operation, such as running a server, spin it up on a worker thread and do the work there.

Example Game setup

I wrote a quick unit test to demonstrate how you can setup a game using adapters.

private async Task TestGameStartup()
{
    // Mocks & Adapters
    IWorldFactory worldFactory = Mock.Of<IWorldFactory>();
    IAdapter server = Mock.Of<AdapterBase>();
    IAdapter worldManager = new WorldManager(worldFactory);

    // Create our game configuration
    IGameConfiguration configuration = new GameConfiguration { Name = "Sample Mud Game", };
    configuration.UseAdapter(server);
    configuration.UseAdapter(worldManager);

    // Setup and run the game.
    IGame game = new MudGame();
    await game.Configure(configuration);
    await game.StartAsync();
}

The above code creates a fake world factory, as an IWorldFactory implementation is required by the WorldManager adapter. I also create a fake server by mocking an adapter base class that the engine provides.

Once my adapters are setup, I create a new GameConfiguration and pass the adapters in to the config using the UseAdapter method. There is also a generic version of this method (UseAdapter<T>).

Lastly, we create a new MudGame, configure the game using our new GameConfiguration instance and then we start the game. Note that game.Initialize() did not get called here. That is because the MudGame class checks if it has been initialized upon starting and initializes itself and all its adapters if that has not happened yet.

At this point, the awaited StartAsync method will not end until something within the engine signals it needs to end, or something calls game.Stop(). It creates an internal game loop and runs.

There is another approach that can be used for those that want a custom game loop.

game.BeginStart(runningGame =>
    {
        Task.Run(() =>
        {
            while (runningGame.IsRunning)
            {
                // Thread.Sleep(1) is not available on Portable Libraries.
                Task.Delay(1).Wait();
            }
        });
    });

This will instead start the game and invoke your callback. This lets you run the game loop in a Task for things like an editor, and not block and UI threads. Your editor or client can still stop the game by invoking game.Stop(). As long as your while loop checks for IsRunning, you're game loop will safely be shut down.

There's a lot of additional new stuff that I couldn't fit in to this post, so I'll work on making more frequent posts with the change that have taken place over the last couple of months.

For now, EOF.