package com.laex.cg2d.core.popup.actions; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Zip; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.ImageLoader; import org.eclipse.swt.widgets.Shell; import com.googlecode.protobuf.format.JsonFormat; import com.laex.cg2d.core.Activator; import com.laex.cg2d.core.popup.actions.UploadToSpritesProjectProvider.SlootProjectProvider; import com.laex.cg2d.model.ICGCProject; import com.laex.cg2d.model.ScreenModel.CGEditorShapeType; import com.laex.cg2d.model.ScreenModel.CGEntity; import com.laex.cg2d.model.ScreenModel.CGEntityAnimation; import com.laex.cg2d.model.ScreenModel.CGEntityCollisionType; import com.laex.cg2d.model.ScreenModel.CGLayer; import com.laex.cg2d.model.ScreenModel.CGResourceFile; import com.laex.cg2d.model.ScreenModel.CGScreenModel; import com.laex.cg2d.model.ScreenModel.CGShape; import com.laex.cg2d.model.SlootContent.SlootCollection; import com.laex.cg2d.model.SlootContent.SlootItem; import com.laex.cg2d.model.adapter.EntityAdapter; import com.laex.cg2d.model.model.Entity; import com.laex.cg2d.model.util.EntitiesUtil; import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; import com.ning.http.client.Response; import com.ning.http.multipart.FilePart; public class UploadToSpritesSlootController { public IResource toExport; public String targetDirectory; private SlootProjectProvider slootProjectProvider; public UploadToSpritesSlootController(IResource toExport, String targetDirectory, SlootProjectProvider slootProjectProvider) { this.toExport = toExport; this.targetDirectory = targetDirectory; this.slootProjectProvider = slootProjectProvider; } private IPath createDestinationFolderStructure(String destination) throws CoreException, IOException { IPath destinationPath = new Path(destination).append(toExport.getName()); FileUtils.forceMkdir(destinationPath.toFile()); return destinationPath; } private void exportSprites(IPath basePath, IResource resource) throws CoreException, IOException { /* Export Entities */ if (isEntity(resource)) { IFile file = (IFile) resource; CGEntity cgEntity = CGEntity.parseFrom(file.getContents()); /* Rewrite fixtures/spritesheet/spritesheetJsonFile path */ CGEntity.Builder bldr = CGEntity.newBuilder(cgEntity); for (CGEntityAnimation.Builder animBldr : bldr.getAnimationsBuilderList()) { IPath trimmedBasePath = basePath.removeFirstSegments(basePath.segmentCount() - 1); if (!animBldr.getSpritesheetFileBuilder().getResourceFile().isEmpty()) { String lastSegmentSpritesheetFile = new Path(animBldr.getSpritesheetFileBuilder().getResourceFile()) .lastSegment(); String rewrittenPath = trimmedBasePath.append(lastSegmentSpritesheetFile).toOSString(); animBldr.getSpritesheetFileBuilder().setResourceFile(rewrittenPath).setResourceFileAbsolute(""); } if (!animBldr.getSpritesheetJsonFile().getResourceFile().isEmpty()) { String lastSegmentSpritesheetJsonFile = new Path(animBldr.getSpritesheetJsonFileBuilder().getResourceFile()) .lastSegment(); String rewrittenPath = trimmedBasePath.append(lastSegmentSpritesheetJsonFile).toOSString(); animBldr.getSpritesheetJsonFileBuilder().setResourceFile(rewrittenPath).setResourceFileAbsolute(""); } /* For custom collision type */ if (animBldr.getCollisionType() == CGEntityCollisionType.CUSTOM) { String lastSegment = new Path(animBldr.getFixtureFileBuilder().getResourceFile()).lastSegment(); String rewrittenPath = trimmedBasePath.append(lastSegment).toOSString(); animBldr.getFixtureFileBuilder().setResourceFile(rewrittenPath).setResourceFileAbsolute(""); } } CGEntity modifiedCGEntity = bldr.build(); /* Step 1 : Generate JSON file and write it to file */ String json = JsonFormat.printToString(modifiedCGEntity); File outputFile = basePath.append(resource.getName()).addFileExtension("json").toFile(); FileUtils.writeByteArrayToFile(outputFile, json.getBytes()); /* Step 2 : Generate PNG preview file and write it to file */ Entity e = EntityAdapter.asEntity(cgEntity); // extract image from // unmodified information Image i = EntitiesUtil.getDefaultFrame(e, 1f); String imgOutputFilename = basePath.append(resource.getName()).addFileExtension("png").toOSString(); ImageLoader il = new ImageLoader(); il.data = new ImageData[] { i.getImageData() }; il.save(imgOutputFilename, SWT.IMAGE_PNG); } } private void exportScreens(IPath basePath, IResource resource) throws CoreException, IOException { if (isScreen(resource)) { IFile file = (IFile) resource; CGScreenModel screen = CGScreenModel.parseFrom(file.getContents()); /* Based on the prototype, we create a new builder */ CGScreenModel.Builder bldr = CGScreenModel.newBuilder(screen); /* Rewrite entities path */ for (CGLayer.Builder layerBuilder : bldr.getLayersBuilderList()) { for (CGShape.Builder shpBuilder : layerBuilder.getShapeBuilderList()) { boolean isEntity = shpBuilder.getEditorShapeType() == CGEditorShapeType.ENTITY_SHAPE; boolean isBg = shpBuilder.getEditorShapeType() == CGEditorShapeType.BACKGROUND_SHAPE; /* For entity */ if (isEntity) { CGResourceFile entityRefFile = shpBuilder.getEntityRefFile(); if (!entityRefFile.getResourceFile().isEmpty()) { String lastSegment = new Path(entityRefFile.getResourceFile()).lastSegment(); String rewrittenPath = basePath.removeFirstSegments(basePath.segmentCount() - 1).append(lastSegment) .addFileExtension("json").toOSString(); entityRefFile = CGResourceFile.newBuilder(entityRefFile).setResourceFile(rewrittenPath) .setResourceFileAbsolute("").build(); shpBuilder.setEntityRefFile(entityRefFile); } } if (isBg) { CGResourceFile bgResourceFile = shpBuilder.getBackgroundResourceFile(); if (!bgResourceFile.getResourceFile().isEmpty()) { String lastSegment = new Path(bgResourceFile.getResourceFile()).lastSegment(); /* * Background Resource File: has extension PNG, we dont append * JSON extend to this file */ String rewrittenPath = basePath.removeFirstSegments(basePath.segmentCount() - 1).append(lastSegment) .toOSString(); bgResourceFile = CGResourceFile.newBuilder(bgResourceFile).setResourceFile(rewrittenPath) .setResourceFileAbsolute("").build(); shpBuilder.setBackgroundResourceFile(bgResourceFile); } } } } screen = bldr.build(); String json = JsonFormat.printToString(screen); File outputFile = basePath.append(resource.getName()).addFileExtension("json").toFile(); FileUtils.writeByteArrayToFile(outputFile, json.getBytes()); } } public static boolean isScreen(IResource resource) { return resource.getName().endsWith(ICGCProject.SCREEN_EXTENSION); } public static boolean isEntity(IResource resource) { return resource.getName().endsWith(ICGCProject.ENTITIES_EXTENSION); } private String generateSlootContent(IPath basePath, String targetDir) throws IOException, CoreException { /* * We write sloot-content.json to a directory one step outside of the * collection */ File fileJson = basePath.removeLastSegments(1).append("sloot-content.json").toFile(); File fileProtobuf = basePath.removeLastSegments(1).append("sloot-content.cmf").toFile(); IPath imgFileBasePath = basePath.removeFirstSegments(basePath.segmentCount() - 1); final SlootCollection.Builder builder = SlootCollection.newBuilder().setCollectionTitle(slootProjectProvider.collectionTitle) .setDeveloperId(slootProjectProvider.developerID); /* Build sloot content */ for (IResource resource : slootProjectProvider.entities) { String imgUrlPath = imgFileBasePath.append(resource.getName()).addFileExtension(ICGCProject.PNG_EXTENSION) .toOSString(); String title = resource.getLocation().removeFileExtension().lastSegment(); String id = toExport.getName() + "_" + resource.getName(); SlootItem si = SlootItem.newBuilder().setId(id).setImgUrl(imgUrlPath).setTitle(title).setPrice(0).build(); builder.addSlootItems(si); } SlootCollection collection = builder.build(); String newJsonCollection = JsonFormat.printToString(collection); FileUtils.writeByteArrayToFile(fileJson, newJsonCollection.toString().getBytes()); FileUtils.writeByteArrayToFile(fileProtobuf, collection.toByteArray()); return newJsonCollection; } public void exportLocally(final String baseUrl, final Shell shell) throws CoreException, InvocationTargetException, InterruptedException, IOException { final IPath basePath = createDestinationFolderStructure(this.targetDirectory); /* Clear directory first */ FileUtils.deleteDirectory(basePath.toFile()); toExport.getProject().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); Job job = new Job("Upload to SpritesLoot") { private IStatus handleError(final Exception e) { Activator.log(e); shell.getDisplay().asyncExec(new Runnable() { @Override public void run() { MessageDialog.openError(shell, "Error Exporting", "An error occurred while exporting files. Please check Log view."); } }); return Status.CANCEL_STATUS; } @Override protected IStatus run(IProgressMonitor monitor) { monitor.beginTask("Exporting", slootProjectProvider.entities.size() + slootProjectProvider.screens.size() + slootProjectProvider.textures.size()); monitor.subTask("Exporting Sprites"); try { for (IResource cgEntityRes : slootProjectProvider.entities) { monitor.setTaskName(cgEntityRes.getName()); exportSprites(basePath, cgEntityRes); monitor.worked(1); } monitor.subTask("Exporting Screens"); for (IResource cgScreenRes : slootProjectProvider.screens) { monitor.setTaskName(cgScreenRes.getName()); exportScreens(basePath, cgScreenRes); monitor.worked(1); } monitor.subTask("Exportng Textures"); for (IResource cgTextureRes : slootProjectProvider.textures) { File outputFile = basePath.append(cgTextureRes.getName()).toFile(); monitor.setTaskName(cgTextureRes.getName()); FileUtils.writeByteArrayToFile(outputFile, IOUtils.toByteArray(((IFile) cgTextureRes).getContents())); monitor.worked(1); } monitor.subTask("Generating Sloot Content"); String slootContentJsonFile = generateSlootContent(basePath, targetDirectory); monitor.worked(1); monitor.subTask("Compressing folders"); File zipFile = zipFolder(toExport.getLocation().append("tmp").append(slootProjectProvider.collectionTitle)); monitor.subTask("Refreshing filesystem"); toExport.getProject().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); /* Finally upload */ monitor.subTask("Uploading...."); upload(baseUrl, zipFile, slootContentJsonFile); monitor.worked(1); monitor.done(); } catch (Exception e) { return handleError(e); } return Status.OK_STATUS; } }; job.setUser(true); job.schedule(); } BoundRequestBuilder clientBuilder; private File zipFolder(IPath folderPath) throws CoreException { Project p = new Project(); p.init(); Zip zip = new Zip(); zip.setProject(p); IPath zipFilePath = folderPath.addFileExtension("zip"); zip.setBasedir(folderPath.toFile()); zip.setDestFile(zipFilePath.toFile()); zip.setIncludes("**"); zip.perform(); return zipFilePath.toFile(); } private void upload(String baseUrl, File zipFile, String slootContentJson) throws IllegalArgumentException, IOException, CoreException { final AsyncHttpClient client = new AsyncHttpClient(); /* Send the Sloot Content */ AsyncCompletionHandler<String> handler = new AsyncCompletionHandler<String>() { @Override public String onCompleted(Response resp) throws Exception { System.err.println("Response: " + resp.getResponseBody()); return null; } }; String url = String.format("http://%s/api/slootContent", baseUrl); client.preparePost(url).addHeader("Content-Type", "application/json") .setBody(slootContentJson).execute(handler); /* Send all the generated files */ IPath genPath = toExport.getFullPath().append("tmp").append(slootProjectProvider.collectionTitle); IFolder tmpFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(genPath); final String putUrl = url + "/" + slootProjectProvider.collectionTitle; if (!tmpFolder.exists()) { return; } FilePart zipFilePart = new FilePart(zipFile.getName(), zipFile); client.preparePut(putUrl).addHeader("Content-Type", "multipart/form-data").addBodyPart(zipFilePart).execute(); } }