2

I'm downloading the TMX map and the Tileset from my server, and saving them into the iOS apps documents directory:

- (void)downloadMap:(void (^)(NSURL *filePath))callback;
{
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

    NSURL *URL = [NSURL URLWithString:@"http://localhost:9950/download"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
        NSURL *documentsDirectoryPath = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]];
        return [documentsDirectoryPath URLByAppendingPathComponent:[response suggestedFilename]];
    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
        DLog(@"Saved: %@", filePath);
        [self downloadTileMap:^(NSURL *filePath) {
            if (callback) {
                callback(filePath);
            }
        }];
    }];
    [downloadTask resume];
}

This downloads both assets. I then try to load my Map:

[self downloadMap:^(NSURL *filePath) {
    self.map = [CCTMXTiledMap tiledMapWithTMXFile:[filePath absoluteString]];
}];

And Cocos2D refuses to load it. It doesn't find the files, even though the logs state:

Saved: file:///Users/ethan/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/2FDEA5E2-052D-4E7B-B7DD-3FA29B5BD4D0/Documents/test_map.tmx
Saved: file:///Users/ethan/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/2FDEA5E2-052D-4E7B-B7DD-3FA29B5BD4D0/Documents/tmw_desert_spacing.png
-[CCFileUtils fullPathForFilename:resolutionType:] : cocos2d: Warning: File not found: file:///Users/ethan/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/2FDEA5E2-052D-4E7B-B7DD-3FA29B5BD4D0/Documents/tmw_desert_spacing.png

And if I enumerate over all files in the Documents directory, I get:

Files: (
    "test_map.tmx",
    "tmw_desert_spacing.png"
)

I've convinced myself that the files are there. The TMX map loads the tileset as a relative path:

<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" width="16" height="40" tilewidth="32" tileheight="32">
 <tileset firstgid="1" name="tmw_desert_spacing" tilewidth="32" tileheight="32" spacing="1" margin="1">
  <image source="tmw_desert_spacing.png" width="265" height="199"/>
 </tileset>
 <layer name="Walkable" width="16" height="40">
  <data encoding="base64" compression="gzip">
   H4sIAAAAAAAAA+3DAQ0AAAzDoCqZf5kXckhYNVVV3zxRXBimAAoAAA==
  </data>
 </layer>
 <layer name="Collidable" width="16" height="40">
  <data encoding="base64" compression="gzip">
   H4sIAAAAAAAAA82TwQ5AMBBEV51wwgkHixP+//9cG9FNR2viJXMyk0llVgRDQT8TJXYwumIYA5o8z2D41oA2L78YviOg08vvhi83msnDwgEqH/I1oOYh3wHqE9+air789kXfFxSC7cHd8pVge6hv+VawPXQ5Hi28/8zqQYi5dWsXMbdu7SLm1q1d/AUl9cykHhYXallnFQAKAAA=
  </data>
 </layer>
</map>

If this were loading from the Bundle, it would be fine. Why doesn't it work from the Documents directory?

Ethan Mick
  • 9,517
  • 14
  • 58
  • 74
  • 1
    Step into ccfileutils as you try to load the tmx. It's cumbersome but ccfileutils does some odd things, so if you find exactly where it goes wrong that should help you understand the issue. Could even be a misleading warning telling you that it couldn't find the -hd tileset image. – CodeSmile Mar 09 '14 at 21:53

1 Answers1

3

I'm going to file this one away as a bug in cocos2d (or a feature request). Upon trying to load a file, it will attempt to only load it from the bundle. It simple won't load it from the Documents Directory.

So I fixed it!

In CCFileUtils.m:

- (NSString *)applicationDocumentsDirectory;
{
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
}

This is a convenience method to get the iOS application's directory.

I then change pathForResource:ofType:inDirectory: to be:

-(NSString*) pathForResource:(NSString*)resource ofType:(NSString *)ext inDirectory:(NSString *)subpath
{
    // An absolute path could be used if the searchPath contains absolute paths
    if( [subpath isAbsolutePath] ) {
        NSString *fullpath = [subpath stringByAppendingPathComponent:resource];
        if( ext )
            fullpath = [fullpath stringByAppendingPathExtension:ext];

        if( [_fileManager fileExistsAtPath:fullpath] )
            return fullpath;
        return nil;
    }

    if (resource) {
        NSString *fullPath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:resource];
        if( ext )
            fullPath = [fullPath stringByAppendingPathExtension:ext];

        if ([_fileManager fileExistsAtPath:fullPath]) {
            return fullPath;
        }
    }

    // Default to normal resource directory
    return [_bundle pathForResource:resource
                             ofType:ext
                        inDirectory:subpath];
}

Basically, before defaulting into the Bundle directory, check if the resource exists in the Documents Directory. If it does, return it!

Now my map loads without a problem.

Ethan Mick
  • 9,517
  • 14
  • 58
  • 74