/* * Copyright (C) 2006-2011 IsmAvatar <IsmAvatar@gmail.com> * Copyright (C) 2006, 2007, 2008 Clam <clamisgood@gmail.com> * Copyright (C) 2007, 2008, 2009 Quadduc <quadduc@gmail.com> * Copyright (C) 2013, Robert B. Colton * * This file is part of LateralGM. * LateralGM is free software and comes with ABSOLUTELY NO WARRANTY. * See LICENSE for details. */ package org.lateralgm.file; import java.awt.Dimension; import java.awt.Point; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.charset.Charset; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; import java.util.zip.DataFormatException; import javax.swing.JProgressBar; import org.lateralgm.components.impl.ResNode; import org.lateralgm.file.ProjectFile.ResourceHolder; import org.lateralgm.file.iconio.ICOFile; import org.lateralgm.main.LGM; import org.lateralgm.main.Util; import org.lateralgm.messages.Messages; import org.lateralgm.resources.Background; import org.lateralgm.resources.Background.PBackground; import org.lateralgm.resources.Constants; import org.lateralgm.resources.Extension; import org.lateralgm.resources.ExtensionPackages; import org.lateralgm.resources.Font; import org.lateralgm.resources.Font.PFont; import org.lateralgm.resources.GameInformation; import org.lateralgm.resources.GameInformation.PGameInformation; import org.lateralgm.resources.GameSettings; import org.lateralgm.resources.GameSettings.IncludeFolder; import org.lateralgm.resources.GameSettings.PGameSettings; import org.lateralgm.resources.GameSettings.ProgressBar; import org.lateralgm.resources.GmObject; import org.lateralgm.resources.GmObject.PGmObject; import org.lateralgm.resources.Include; import org.lateralgm.resources.InstantiableResource; import org.lateralgm.resources.Path; import org.lateralgm.resources.Shader; import org.lateralgm.resources.Path.PPath; import org.lateralgm.resources.Resource; import org.lateralgm.resources.ResourceReference; import org.lateralgm.resources.Room; import org.lateralgm.resources.Room.PRoom; import org.lateralgm.resources.Script; import org.lateralgm.resources.Script.PScript; import org.lateralgm.resources.Sound; import org.lateralgm.resources.Sound.PSound; import org.lateralgm.resources.Sprite; import org.lateralgm.resources.Sprite.BBMode; import org.lateralgm.resources.Sprite.PSprite; import org.lateralgm.resources.Timeline; import org.lateralgm.resources.library.LibAction; import org.lateralgm.resources.library.LibArgument; import org.lateralgm.resources.library.LibManager; import org.lateralgm.resources.sub.Action; import org.lateralgm.resources.sub.ActionContainer; import org.lateralgm.resources.sub.Argument; import org.lateralgm.resources.sub.BackgroundDef; import org.lateralgm.resources.sub.BackgroundDef.PBackgroundDef; import org.lateralgm.resources.sub.Constant; import org.lateralgm.resources.sub.Event; import org.lateralgm.resources.sub.Instance; import org.lateralgm.resources.sub.Instance.PInstance; import org.lateralgm.resources.sub.MainEvent; import org.lateralgm.resources.sub.Moment; import org.lateralgm.resources.sub.PathPoint; import org.lateralgm.resources.sub.Tile; import org.lateralgm.resources.sub.Tile.PTile; import org.lateralgm.resources.sub.Trigger; import org.lateralgm.resources.sub.View; import org.lateralgm.resources.sub.View.PView; import org.lateralgm.util.PropertyMap; public final class GmFileReader { private GmFileReader() { } static Queue<PostponedRef> postpone = new LinkedList<PostponedRef>(); static interface PostponedRef { boolean invoke(); } static class DefaultPostponedRef<K extends Enum<K>> implements PostponedRef { ResourceList<?> list; String name; PropertyMap<K> p; K key; DefaultPostponedRef(ResourceList<?> list, PropertyMap<K> p, K key, String name) { this.list = list; this.p = p; this.key = key; this.name = name; } public boolean invoke() { Resource<?,?> temp = list.get(name); if (temp != null) p.put(key,temp.reference); return temp != null; } } //Workaround for Parameter limit private static class ProjectFileContext { ProjectFile f; GmStreamDecoder in; RefList<Timeline> timeids; RefList<GmObject> objids; RefList<Room> rmids; public ProjectFileContext(ProjectFile f, GmStreamDecoder in, RefList<Timeline> timeids, RefList<GmObject> objids, RefList<Room> rmids) { this.f = f; this.in = in; this.timeids = timeids; this.objids = objids; this.rmids = rmids; } public ProjectFileContext copy() { return new ProjectFileContext(f,in,timeids,objids,rmids); } } private static GmFormatException versionError(ProjectFile f, String error, String res, int ver) { return versionError(f,error,res,0,ver); } private static GmFormatException versionError(ProjectFile f, String error, String res, int i, int ver) { return new GmFormatException(f,Messages.format( "ProjectFileReader.ERROR_UNSUPPORTED",Messages.format( //$NON-NLS-1$ "ProjectFileReader." + error,Messages.getString("LGM." + res),i),ver)); //$NON-NLS-1$ //$NON-NLS-2$ } public static void readProjectFile(InputStream stream, ProjectFile file, URI uri, ResNode root) throws GmFormatException { readProjectFile(stream,file,uri,root,null); } public static void readProjectFile(InputStream stream, ProjectFile file, URI uri, ResNode root, Charset forceCharset) throws GmFormatException { GmStreamDecoder in = null; RefList<Timeline> timeids = new RefList<Timeline>(Timeline.class); // timeline ids RefList<GmObject> objids = new RefList<GmObject>(GmObject.class); // object ids RefList<Room> rmids = new RefList<Room>(Room.class); // room id try { long startTime = System.currentTimeMillis(); in = new GmStreamDecoder(stream); ProjectFileContext c = new ProjectFileContext(file,in,timeids,objids,rmids); int identifier = in.read4(); if (identifier != 1234321) throw new GmFormatException(file,Messages.format("ProjectFileReader.ERROR_INVALID",uri, //$NON-NLS-1$ identifier)); int ver = in.read4(); file.format = ProjectFile.FormatFlavor.getVersionFlavor(ver); if (ver != 530 && ver != 600 && ver != 701 && ver != 800 && ver != 810) { String msg = Messages.format("ProjectFileReader.ERROR_UNSUPPORTED",uri,ver); //$NON-NLS-1$ throw new GmFormatException(file,msg); } if (forceCharset == null) { if (ver >= 810) in.setCharset(Charset.forName("UTF-8")); else in.setCharset(Charset.defaultCharset()); } else in.setCharset(forceCharset); //TODO: fix exception here caused by trying to open file too soon after loading LGM JProgressBar progressBar = LGM.getProgressDialogBar(); progressBar.setMaximum(200); LGM.setProgressTitle(Messages.getString("ProgressDialog.GMK_LOADING")); //$NON-NLS-1$ GameSettings gs = c.f.gameSettings.get(0); LGM.setProgress(0,Messages.getString("ProgressDialog.SETTINGS")); //$NON-NLS-1$ if (ver == 530) in.skip(4); //reserved 0 if (ver == 701) { int s1 = in.read4(); int s2 = in.read4(); in.skip(s1 * 4); //since only the first byte of the game id isn't encrypted, we have to do some acrobatics here int seed = in.read4(); in.skip(s2 * 4); int b1 = in.read(); in.setSeed(seed); gs.put(PGameSettings.GAME_ID,b1 | in.read3() << 8); } else gs.put(PGameSettings.GAME_ID,in.read4()); in.read((byte[]) gs.get(PGameSettings.GAME_GUID)); //16 bytes readSettings(c,gs); if (ver >= 800) { LGM.setProgress(10,Messages.getString("ProgressDialog.TRIGGERS")); //$NON-NLS-1$ readTriggers(c); LGM.setProgress(20,Messages.getString("ProgressDialog.CONSTANTS")); //$NON-NLS-1$ readConstants(c,gs); } LGM.setProgress(30,Messages.getString("ProgressDialog.SOUNDS")); //$NON-NLS-1$ readSounds(c); LGM.setProgress(40,Messages.getString("ProgressDialog.SPRITES")); //$NON-NLS-1$ readSprites(c); LGM.setProgress(50,Messages.getString("ProgressDialog.BACKGROUNDS")); //$NON-NLS-1$ int bgVer = readBackgrounds(c); LGM.setProgress(60,Messages.getString("ProgressDialog.PATHS")); //$NON-NLS-1$ readPaths(c); LGM.setProgress(70,Messages.getString("ProgressDialog.SCRIPTS")); //$NON-NLS-1$ readScripts(c); LGM.setProgress(80,Messages.getString("ProgressDialog.SHADERS")); //$NON-NLS-1$ //TODO: GMK 820 reads shaders first LGM.setProgress(90,Messages.getString("ProgressDialog.FONTS")); //$NON-NLS-1$ int rver = in.read4(); readFonts(c,rver); LGM.setProgress(100,Messages.getString("ProgressDialog.TIMELINES")); //$NON-NLS-1$ readTimelines(c); LGM.setProgress(110,Messages.getString("ProgressDialog.OBJECTS")); //$NON-NLS-1$ readGmObjects(c); LGM.setProgress(120,Messages.getString("ProgressDialog.ROOMS")); //$NON-NLS-1$ readRooms(c); //If the "use as tileset" flag was not part of this version, try to infer it from the backgrounds used in room tiles. if (bgVer <= 400) { for (Room rm : file.resMap.getList(Room.class)) { for (Tile tl : rm.tiles) { ResourceReference<Background> bkg = tl.properties.get(PTile.BACKGROUND); if (bkg!=null && bkg.get()!=null) { bkg.get().properties.put(PBackground.USE_AS_TILESET, true); } } } } file.lastInstanceId = in.read4(); file.lastTileId = in.read4(); if (ver >= 700) { LGM.setProgress(130,Messages.getString("ProgressDialog.INCLUDEFILES")); //$NON-NLS-1$ readIncludedFiles(c); LGM.setProgress(140,Messages.getString("ProgressDialog.PACKAGES")); //$NON-NLS-1$ readPackages(c); } LGM.setProgress(150,Messages.getString("ProgressDialog.GAMEINFORMATION")); //$NON-NLS-1$ readGameInformation(c); LGM.setProgress(160,Messages.getString("ProgressDialog.POSTPONED")); //$NON-NLS-1$ //Resources read. Now we can invoke our postpones. int percent = 0; for (PostponedRef i : postpone) { i.invoke(); percent += 1; LGM.setProgress(160 + percent / postpone.size(), Messages.getString("ProgressDialog.POSTPONED")); //$NON-NLS-1$ } LGM.setProgress(170,Messages.getString("ProgressDialog.LIBRARYCREATION")); //$NON-NLS-1$ //Library Creation Code ver = in.read4(); if (ver != 500) throw new GmFormatException(file,Messages.format("ProjectFileReader.ERROR_UNSUPPORTED", //$NON-NLS-1$ Messages.getString("ProjectFileReader.AFTERINFO"),ver)); //$NON-NLS-1$ int no = in.read4(); for (int j = 0; j < no; j++) in.skip(in.read4()); LGM.setProgress(180,Messages.getString("ProgressDialog.ROOMEXECUTION")); //$NON-NLS-1$ //Room Execution Order ver = in.read4(); if (ver != 500 && ver != 540 && ver != 700) throw new GmFormatException(file,Messages.format("ProjectFileReader.ERROR_UNSUPPORTED", //$NON-NLS-1$ Messages.getString("ProjectFileReader.AFTERINFO2"),ver)); //$NON-NLS-1$ in.skip(in.read4() * 4); LGM.setProgress(190,Messages.getString("ProgressDialog.FILETREE")); //$NON-NLS-1$ readTree(c,root,ver); LGM.setProgress(200,Messages.getString("ProgressDialog.FINISHED")); //$NON-NLS-1$ System.out.println(Messages.format("ProjectFileReader.LOADTIME",System.currentTimeMillis() //$NON-NLS-1$ - startTime)); } catch (Exception e) { if ((e instanceof GmFormatException)) throw (GmFormatException) e; throw new GmFormatException(file,e); } finally { try { if (in != null) { in.close(); in = null; } } catch (IOException ex) { String key = Messages.getString("GmFileReader.ERROR_CLOSEFAILED"); //$NON-NLS-1$ throw new GmFormatException(file,key); } } } private static void readSettings(ProjectFileContext c, GameSettings g) throws IOException,GmFormatException, DataFormatException { GmStreamDecoder in = c.in; PropertyMap<PGameSettings> p = g.properties; int ver = in.read4(); if (ver != 530 && ver != 542 && ver != 600 && ver != 702 && ver != 800 && ver != 810) { String msg = Messages.format("ProjectFileReader.ERROR_UNSUPPORTED","",ver); //$NON-NLS-1$ //$NON-NLS-2$ throw new GmFormatException(c.f,msg); } if (ver >= 800) in.beginInflate(); in.readBool(p,PGameSettings.START_FULLSCREEN); if (ver >= 600) in.readBool(p,PGameSettings.INTERPOLATE); in.readBool(p,PGameSettings.DONT_DRAW_BORDER,PGameSettings.DISPLAY_CURSOR); in.read4(p,PGameSettings.SCALING); if (ver == 530) in.skip(8); //"fullscreen scale" & "only scale w/ hardware support" else { in.readBool(p,PGameSettings.ALLOW_WINDOW_RESIZE,PGameSettings.ALWAYS_ON_TOP); p.put(PGameSettings.COLOR_OUTSIDE_ROOM,Util.convertGmColor(in.read4())); } in.readBool(p,PGameSettings.SET_RESOLUTION); int colorDepth = 0, frequency; if (ver == 530) { in.skip(8); //Color Depth, Exclusive Graphics p.put(PGameSettings.RESOLUTION,ProjectFile.GS5_RESOLS[in.read4()]); byte b = (byte) in.read4(); frequency = (b == 4) ? 0 : (byte) (b + 1); in.skip(8); //vertical blank, caption in fullscreen } else { colorDepth = (byte) in.read4(); p.put(PGameSettings.RESOLUTION,ProjectFile.GS_RESOLS[in.read4()]); frequency = (byte) in.read4(); } p.put(PGameSettings.COLOR_DEPTH,ProjectFile.GS_DEPTHS[colorDepth]); p.put(PGameSettings.FREQUENCY,ProjectFile.GS_FREQS[frequency]); in.readBool(p,PGameSettings.DONT_SHOW_BUTTONS); if (ver > 530) in.readBool(p,PGameSettings.USE_SYNCHRONIZATION); if (ver >= 800) in.readBool(p,PGameSettings.DISABLE_SCREENSAVERS); in.readBool(p,PGameSettings.LET_F4_SWITCH_FULLSCREEN,PGameSettings.LET_F1_SHOW_GAME_INFO, PGameSettings.LET_ESC_END_GAME,PGameSettings.LET_F5_SAVE_F6_LOAD); if (ver == 530) in.skip(8); //unknown bytes, both 0 if (ver > 600) in.readBool(p,PGameSettings.LET_F9_SCREENSHOT,PGameSettings.TREAT_CLOSE_AS_ESCAPE); p.put(PGameSettings.GAME_PRIORITY,ProjectFile.GS_PRIORITIES[in.read4()]); in.readBool(p,PGameSettings.FREEZE_ON_LOSE_FOCUS); p.put(PGameSettings.LOAD_BAR_MODE,ProjectFile.GS_PROGBARS[in.read4()]); if (p.get(PGameSettings.LOAD_BAR_MODE) == ProgressBar.CUSTOM) { if (ver < 800) { if (in.read4() != -1) p.put(PGameSettings.BACK_LOAD_BAR,in.readZlibImage()); if (in.read4() != -1) p.put(PGameSettings.FRONT_LOAD_BAR,in.readZlibImage()); } //ver >= 800 else { if (in.readBool()) p.put(PGameSettings.BACK_LOAD_BAR,in.readZlibImage()); if (in.readBool()) p.put(PGameSettings.FRONT_LOAD_BAR,in.readZlibImage()); } } in.readBool(p,PGameSettings.SHOW_CUSTOM_LOAD_IMAGE); if (p.get(PGameSettings.SHOW_CUSTOM_LOAD_IMAGE)) { if (ver < 800) { if (in.read4() != -1) p.put(PGameSettings.LOADING_IMAGE,in.readZlibImage()); } else if (in.readBool()) p.put(PGameSettings.LOADING_IMAGE,in.readZlibImage()); } in.readBool(p,PGameSettings.IMAGE_PARTIALLY_TRANSPARENTY); in.read4(p,PGameSettings.LOAD_IMAGE_ALPHA); in.readBool(p,PGameSettings.SCALE_PROGRESS_BAR); int length = in.read4(); byte[] data = new byte[length]; in.read(data,0,length); try { g.put(PGameSettings.GAME_ICON,new ICOFile(data)); } catch (Exception e) { throw e; } in.readBool(p,PGameSettings.DISPLAY_ERRORS,PGameSettings.WRITE_TO_LOG, PGameSettings.ABORT_ON_ERROR); int errors = in.read4(); p.put(PGameSettings.TREAT_UNINIT_AS_0,((errors & 0x01) != 0)); p.put(PGameSettings.ERROR_ON_ARGS,((errors & 0x02) != 0)); in.readStr(p,PGameSettings.AUTHOR); if (ver > 600) in.readStr(p,PGameSettings.VERSION); else p.put(PGameSettings.VERSION,Integer.toString(in.read4())); in.readD(p,PGameSettings.LAST_CHANGED); in.readStr(p,PGameSettings.INFORMATION); if (ver < 800) { int no = in.read4(); for (int i = 0; i < no; i++) { Constant con = new Constant(); g.constants.constants.add(con); con.name = in.readStr(); con.value = in.readStr(); } } if (ver > 600) { in.read4(p,PGameSettings.VERSION_MAJOR,PGameSettings.VERSION_MINOR, PGameSettings.VERSION_RELEASE,PGameSettings.VERSION_BUILD); in.readStr(p,PGameSettings.COMPANY,PGameSettings.PRODUCT,PGameSettings.COPYRIGHT, PGameSettings.DESCRIPTION); if (ver >= 800) in.skip(8); //last changed } else if (ver > 530) readSettingsIncludes(c.f,in,g); in.endInflate(); } private static void readSettingsIncludes(ProjectFile f, GmStreamDecoder in, GameSettings gs) throws IOException { int no = in.read4(); for (int i = 0; i < no; i++) { Include inc = f.resMap.getList(Include.class).add(); inc.filepath = in.readStr(); inc.filename = new File(inc.filepath).getName(); } gs.put(PGameSettings.INCLUDE_FOLDER,ProjectFile.GS_INCFOLDERS[in.read4()]); // f.gameSettings.includeFolder = in.read4(); //0 = main, 1 = temp in.readBool(gs.properties,PGameSettings.OVERWRITE_EXISTING, PGameSettings.REMOVE_AT_GAME_END); for (Include inc : f.resMap.getList(Include.class)) { inc.export = gs.get(PGameSettings.INCLUDE_FOLDER) == IncludeFolder.TEMP ? 1 : 2; //1 = temp, 2 = main inc.overwriteExisting = gs.get(PGameSettings.OVERWRITE_EXISTING); inc.removeAtGameEnd = gs.get(PGameSettings.REMOVE_AT_GAME_END); } } private static void readTriggers(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 800) throw versionError(f,"BEFORE","SND",ver); //$NON-NLS-1$ //$NON-NLS-2$ int no = in.read4(); for (int i = 0; i < no; i++) { in.beginInflate(); if (!in.readBool()) { in.endInflate(); continue; } ver = in.read4(); if (ver != 800) throw versionError(f,"BEFORE","SND",ver); //$NON-NLS-1$ //$NON-NLS-2$ Trigger trig = new Trigger(); f.triggers.put(i,trig); trig.name = in.readStr(); trig.condition = in.readStr(); trig.checkStep = in.read4(); trig.constant = in.readStr(); in.endInflate(); } in.skip(8); //last changed } private static void readConstants(ProjectFileContext c, GameSettings gs) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 800) throw versionError(f,"BEFORE","SND",ver); //$NON-NLS-1$ //$NON-NLS-2$ int no = in.read4(); for (int i = 0; i < no; i++) { Constant con = new Constant(); gs.constants.constants.add(con); con.name = in.readStr(); con.value = in.readStr(); } in.skip(8); //last changed } private static void readSounds(ProjectFileContext c) throws IOException,GmFormatException, DataFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 400 && ver != 800) throw versionError(f,"BEFORE","SND",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noSounds = in.read4(); for (int i = 0; i < noSounds; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { f.resMap.getList(Sound.class).lastId++; in.endInflate(); continue; } Sound snd = f.resMap.getList(Sound.class).add(); snd.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed ver = in.read4(); if (ver != 440 && ver != 600 && ver != 800) throw versionError(f,"IN","SND",i,ver); //$NON-NLS-1$ //$NON-NLS-2$ int kind53 = -1; if (ver == 440) kind53 = in.read4(); //kind (wav, mp3, etc) else snd.put(PSound.KIND,ProjectFile.SOUND_KIND[in.read4()]); //normal, background, etc in.readStr(snd.properties,PSound.FILE_TYPE); if (ver == 440) { //-1 = no sound if (kind53 != -1) snd.data = in.decompress(in.read4()); in.skip(8); snd.put(PSound.PRELOAD,!in.readBool()); } else { snd.put(PSound.FILE_NAME,in.readStr()); if (in.readBool()) { if (ver == 600) snd.data = in.decompress(in.read4()); else { int s = in.read4(); snd.data = new byte[s]; in.read(snd.data); } } int effects = in.read4(); for (PSound k : ProjectFile.SOUND_FX_FLAGS) { snd.put(k,(effects & 1) != 0); effects >>= 1; } in.readD(snd.properties,PSound.VOLUME,PSound.PAN); snd.put(PSound.PRELOAD,in.readBool()); } in.endInflate(); } } private static void readSprites(ProjectFileContext c) throws IOException,GmFormatException, DataFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 400 && ver != 800 && ver != 810) throw versionError(f,"BEFORE","SPR",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noSprites = in.read4(); for (int i = 0; i < noSprites; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { f.resMap.getList(Sprite.class).lastId++; in.endInflate(); continue; } Sprite spr = f.resMap.getList(Sprite.class).add(); //temporarily set bbmode to manual so bbox doesn't get recalculated until bbmode is ready //TODO: This should be made a little less retarded, I added a null check to bbmode call - Robert spr.put(PSprite.BB_MODE,BBMode.MANUAL); BBMode actualBBMode = null; spr.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed ver = in.read4(); if (ver != 400 && ver != 542 && ver != 800 && ver != 810) throw versionError(f,"IN","SPR",i,ver); //$NON-NLS-1$ //$NON-NLS-2$ int w = 0, h = 0; if (ver < 800) { w = in.read4(); h = in.read4(); in.read4(spr.properties,PSprite.BB_LEFT,PSprite.BB_RIGHT,PSprite.BB_BOTTOM,PSprite.BB_TOP); spr.put(PSprite.TRANSPARENT,in.readBool()); //XXX: tends to cause an update... if (ver > 400) { in.readBool(spr.properties,PSprite.SMOOTH_EDGES,PSprite.PRELOAD); } actualBBMode = ProjectFile.SPRITE_BB_MODE[in.read4()]; // delay setting BBMode to avoid expensive recalculations boolean precise = in.readBool(); spr.put(PSprite.SHAPE,precise ? Sprite.MaskShape.PRECISE : Sprite.MaskShape.RECTANGLE); if (ver == 400) { in.skip(4); //use video memory spr.put(PSprite.PRELOAD,!in.readBool()); } } else spr.put(PSprite.TRANSPARENT,false); in.read4(spr.properties,PSprite.ORIGIN_X,PSprite.ORIGIN_Y); int nosub = in.read4(); for (int j = 0; j < nosub; j++) { if (ver >= 800) { int subver = in.read4(); if (subver != 800 && subver != 810) throw versionError(f,"IN","SPR",i,subver); //$NON-NLS-1$ //$NON-NLS-2$ w = in.read4(); h = in.read4(); if (w != 0 && h != 0) spr.subImages.add(in.readBGRAImage(w,h)); } else { if (in.read4() == -1) continue; spr.subImages.add(in.readZlibImage(w,h)); } } if (ver >= 800) { spr.put(PSprite.SHAPE,ProjectFile.SPRITE_MASK_SHAPE[in.read4()]); spr.put(PSprite.ALPHA_TOLERANCE,in.read4()); spr.put(PSprite.SEPARATE_MASK,in.readBool()); actualBBMode = ProjectFile.SPRITE_BB_MODE[in.read4()]; in.read4(spr.properties,PSprite.BB_LEFT,PSprite.BB_RIGHT,PSprite.BB_BOTTOM,PSprite.BB_TOP); } spr.put(PSprite.BB_MODE,actualBBMode); //now bbmode is ready in.endInflate(); } } private static int readBackgrounds(ProjectFileContext c) throws IOException,GmFormatException, DataFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 400 && ver != 800) throw versionError(f,"BEFORE","BKG",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noBackgrounds = in.read4(); for (int i = 0; i < noBackgrounds; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { f.resMap.getList(Background.class).lastId++; in.endInflate(); continue; } Background back = f.resMap.getList(Background.class).add(); back.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed ver = in.read4(); if (ver != 400 && ver != 543 && ver != 710) throw versionError(f,"IN","BKG",i,ver); //$NON-NLS-1$ //$NON-NLS-2$ if (ver < 710) { int w = in.read4(); int h = in.read4(); back.put(PBackground.TRANSPARENT,in.readBool()); if (ver > 400) { in.readBool(back.properties,PBackground.SMOOTH_EDGES,PBackground.PRELOAD, PBackground.USE_AS_TILESET); in.read4(back.properties,PBackground.TILE_WIDTH,PBackground.TILE_HEIGHT, PBackground.H_OFFSET,PBackground.V_OFFSET,PBackground.H_SEP,PBackground.V_SEP); } else { in.skip(4); //use video memory back.put(PBackground.PRELOAD,!in.readBool()); } if (in.readBool()) { if (in.read4() == -1) continue; back.setBackgroundImage(in.readZlibImage(w,h)); } } //ver >= 710 else { back.put(PBackground.USE_AS_TILESET,in.readBool()); in.read4(back.properties,PBackground.TILE_WIDTH,PBackground.TILE_HEIGHT, PBackground.H_OFFSET,PBackground.V_OFFSET,PBackground.H_SEP,PBackground.V_SEP); ver = in.read4(); if (ver != 800) throw versionError(f,"IN","BKG",i,ver); //$NON-NLS-1$ //$NON-NLS-2$ int w = in.read4(); int h = in.read4(); if (w != 0 && h != 0) back.setBackgroundImage(in.readBGRAImage(w,h)); } in.endInflate(); } return ver; } private static void readPaths(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 420 && ver != 800) throw versionError(f,"BEFORE","PTH",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noPaths = in.read4(); for (int i = 0; i < noPaths; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { f.resMap.getList(Path.class).lastId++; in.endInflate(); continue; } Path path = f.resMap.getList(Path.class).add(); path.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed int ver2 = in.read4(); if (ver2 != 530) throw versionError(f,"IN","PTH",i,ver2); //$NON-NLS-1$ //$NON-NLS-2$ in.readBool(path.properties,PPath.SMOOTH,PPath.CLOSED); path.put(PPath.PRECISION,in.read4()); path.put(PPath.BACKGROUND_ROOM,c.rmids.get(in.read4())); in.read4(path.properties,PPath.SNAP_X,PPath.SNAP_Y); int nopoints = in.read4(); for (int j = 0; j < nopoints; j++) { path.points.add(new PathPoint((int) in.readD(),(int) in.readD(),(int) in.readD())); } in.endInflate(); } } private static void readScripts(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 400 && ver != 800 && ver != 810) throw versionError(f,"BEFORE","SCR",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noScripts = in.read4(); for (int i = 0; i < noScripts; i++) { if (ver >= 800) in.beginInflate(); if (!in.readBool()) { f.resMap.getList(Script.class).lastId++; in.endInflate(); continue; } Script scr = f.resMap.getList(Script.class).add(); scr.setName(in.readStr()); if (ver >= 800) in.skip(8); //last changed ver = in.read4(); if (ver != 400 && ver != 800 && ver != 810) throw versionError(f,"IN","SCR",i,ver); //$NON-NLS-1$ //$NON-NLS-2$ String code = in.readStr(); scr.put(PScript.CODE,code); in.endInflate(); } } private static void readFonts(ProjectFileContext c, int ver) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; if (ver != 440 && ver != 540 && ver != 800) throw versionError(f,"BEFORE","FNT",(int) in.getPos()); //$NON-NLS-1$ //$NON-NLS-2$ if (ver == 440) //data files { int noDataFiles = in.read4(); for (int i = 0; i < noDataFiles; i++) { if (!in.readBool()) continue; in.skip(in.read4()); if (in.read4() != 440) throw new GmFormatException(f,Messages.format("ProjectFileReader.ERROR_UNSUPPORTED", //$NON-NLS-1$ Messages.getString("ProjectFileReader.INDATAFILES"),ver)); //$NON-NLS-1$ Include inc = f.resMap.getList(Include.class).add(); inc.filepath = in.readStr(); inc.filename = new File(inc.filepath).getName(); if (in.readBool()) //file data exists? { inc.size = in.read4(); inc.data = new byte[inc.size]; in.read(inc.data,0,inc.size); } inc.export = in.read4(); //FIXME: Deal with Font Includes //if (inc.export == 3) inc.exportFolder = Font Folder? inc.overwriteExisting = in.readBool(); inc.freeMemAfterExport = in.readBool(); inc.removeAtGameEnd = in.readBool(); } return; } int noFonts = in.read4(); for (int i = 0; i < noFonts; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { f.resMap.getList(Font.class).lastId++; in.endInflate(); continue; } Font font = f.resMap.getList(Font.class).add(); font.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed ver = in.read4(); if (ver != 540 && ver != 800) throw versionError(f,"IN","FNT",i,ver); //$NON-NLS-1$ //$NON-NLS-2$ font.put(PFont.FONT_NAME,in.readStr()); font.put(PFont.SIZE,in.read4()); in.readBool(font.properties,PFont.BOLD,PFont.ITALIC); int rangemin = in.read2(); font.put(PFont.CHARSET,in.read()); int aa = in.read(); if (aa == 0 && f.format != ProjectFile.FormatFlavor.GM_810) aa = 3; font.put(PFont.ANTIALIAS,aa); font.addRange(rangemin,in.read4()); in.endInflate(); } } private static void readTimelines(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 500 && ver != 800) throw versionError(f,"BEFORE","TML",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noTimelines = in.read4(); for (int i = 0; i < noTimelines; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { in.endInflate(); continue; } ResourceReference<Timeline> r = c.timeids.get(i); //includes ID Timeline time = r.get(); f.resMap.getList(Timeline.class).add(time); time.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed int ver2 = in.read4(); if (ver2 != 500) throw versionError(f,"IN","TML",i,ver2); //$NON-NLS-1$ //$NON-NLS-2$ int nomoms = in.read4(); for (int j = 0; j < nomoms; j++) { Moment mom = time.addMoment(); mom.stepNo = in.read4(); ProjectFileContext fc = c.copy(); fc.in = in; readActions(fc,mom,"INTIMELINEACTION",i,mom.stepNo); //$NON-NLS-1$ } in.endInflate(); } f.resMap.getList(Timeline.class).lastId = noTimelines - 1; } private static void readGmObjects(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 400 && ver != 800) throw versionError(f,"BEFORE","OBJ",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noGmObjects = in.read4(); for (int i = 0; i < noGmObjects; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { in.endInflate(); continue; } ResourceReference<GmObject> r = c.objids.get(i); //includes ID GmObject obj = r.get(); f.resMap.getList(GmObject.class).add(obj); obj.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed int ver2 = in.read4(); if (ver2 != 430) throw versionError(f,"IN","OBJ",i,ver2); //$NON-NLS-1$ //$NON-NLS-2$ Sprite temp = f.resMap.getList(Sprite.class).getUnsafe(in.read4()); if (temp != null) obj.put(PGmObject.SPRITE,temp.reference); in.readBool(obj.properties,PGmObject.SOLID,PGmObject.VISIBLE); obj.put(PGmObject.DEPTH,in.read4()); obj.put(PGmObject.PERSISTENT,in.readBool()); obj.put(PGmObject.PARENT,c.objids.get(in.read4())); temp = f.resMap.getList(Sprite.class).getUnsafe(in.read4()); if (temp != null) obj.put(PGmObject.MASK,temp.reference); int noEvents = in.read4() + 1; for (int j = 0; j < noEvents; j++) { MainEvent me = obj.mainEvents.get(j); boolean done = false; while (!done) { int first = in.read4(); if (first != -1) { Event ev = new Event(); me.events.add(0,ev); if (j == MainEvent.EV_COLLISION) ev.other = c.objids.get(first); else ev.id = first; ev.mainId = j; ProjectFileContext fc = c.copy(); fc.in = in; readActions(fc,ev,"INOBJECTACTION",i,j * 1000 + ev.id); //$NON-NLS-1$ } else done = true; } } in.endInflate(); } f.resMap.getList(GmObject.class).lastId = noGmObjects - 1; } private static void readRooms(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 420 && ver != 800) throw versionError(f,"BEFORE","RMM",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noRooms = in.read4(); for (int i = 0; i < noRooms; i++) { if (ver == 800) in.beginInflate(); if (!in.readBool()) { in.endInflate(); continue; } ResourceReference<Room> r = c.rmids.get(i); //includes ID Room rm = r.get(); f.resMap.getList(Room.class).add(rm); rm.setName(in.readStr()); if (ver == 800) in.skip(8); //last changed int ver2 = in.read4(); if (ver2 != 520 && ver2 != 541) throw versionError(f,"IN","RMM",i,ver2); //$NON-NLS-1$ //$NON-NLS-2$ rm.put(PRoom.CAPTION,in.readStr()); in.read4(rm.properties,PRoom.WIDTH,PRoom.HEIGHT,PRoom.SNAP_Y,PRoom.SNAP_X); rm.put(PRoom.ISOMETRIC,in.readBool()); rm.put(PRoom.SPEED,in.read4()); rm.put(PRoom.PERSISTENT,in.readBool()); rm.put(PRoom.BACKGROUND_COLOR,Util.convertGmColor(in.read4())); rm.put(PRoom.DRAW_BACKGROUND_COLOR,in.readBool()); rm.put(PRoom.CREATION_CODE,in.readStr()); int nobackgrounds = in.read4(); for (int j = 0; j < nobackgrounds; j++) { BackgroundDef bk = rm.backgroundDefs.get(j); in.readBool(bk.properties,PBackgroundDef.VISIBLE,PBackgroundDef.FOREGROUND); Background temp = f.resMap.getList(Background.class).getUnsafe(in.read4()); if (temp != null) bk.properties.put(PBackgroundDef.BACKGROUND,temp.reference); in.read4(bk.properties,PBackgroundDef.X,PBackgroundDef.Y); in.readBool(bk.properties,PBackgroundDef.TILE_HORIZ,PBackgroundDef.TILE_VERT); in.read4(bk.properties,PBackgroundDef.H_SPEED,PBackgroundDef.V_SPEED); bk.properties.put(PBackgroundDef.STRETCH,in.readBool()); } rm.put(PRoom.VIEWS_ENABLED,in.readBool()); int noviews = in.read4(); for (int j = 0; j < noviews; j++) { View vw = rm.views.get(j); in.readBool(vw.properties,PView.VISIBLE); //vw.properties.put(PView.VISIBLE,in.readBool()); in.read4(vw.properties,PView.VIEW_X,PView.VIEW_Y,PView.VIEW_W,PView.VIEW_H,PView.PORT_X, PView.PORT_Y); if (ver2 > 520) in.read4(vw.properties,PView.PORT_W,PView.PORT_H); else { //Older versions of GM assume port_size == view_size. vw.properties.put(PView.PORT_W,vw.properties.get(PView.VIEW_W)); vw.properties.put(PView.PORT_H,vw.properties.get(PView.VIEW_H)); } in.read4(vw.properties,PView.BORDER_H,PView.BORDER_V,PView.SPEED_H,PView.SPEED_V); GmObject temp = f.resMap.getList(GmObject.class).getUnsafe(in.read4()); if (temp != null) vw.properties.put(PView.OBJECT,temp.reference); } int noinstances = in.read4(); for (int j = 0; j < noinstances; j++) { Instance inst = rm.addInstance(); inst.setPosition(new Point(in.read4(),in.read4())); GmObject temp = f.resMap.getList(GmObject.class).getUnsafe(in.read4()); if (temp != null) inst.properties.put(PInstance.OBJECT,temp.reference); inst.properties.put(PInstance.ID,in.read4()); inst.setCreationCode(in.readStr()); inst.setLocked(in.readBool()); } int notiles = in.read4(); for (int j = 0; j < notiles; j++) { Tile t = new Tile(rm); t.setPosition(new Point(in.read4(),in.read4())); Background temp = f.resMap.getList(Background.class).getUnsafe(in.read4()); ResourceReference<Background> bkg = null; if (temp != null) bkg = temp.reference; t.properties.put(PTile.BACKGROUND,bkg); t.setBackgroundPosition(new Point(in.read4(),in.read4())); t.setSize(new Dimension(in.read4(),in.read4())); t.setDepth(in.read4()); t.properties.put(PTile.ID,in.read4()); t.setLocked(in.readBool()); rm.tiles.add(t); } rm.put(PRoom.REMEMBER_WINDOW_SIZE,in.readBool()); in.read4(rm.properties,PRoom.EDITOR_WIDTH,PRoom.EDITOR_HEIGHT); in.readBool(rm.properties,PRoom.SHOW_GRID,PRoom.SHOW_OBJECTS,PRoom.SHOW_TILES, PRoom.SHOW_BACKGROUNDS,PRoom.SHOW_FOREGROUNDS,PRoom.SHOW_VIEWS, PRoom.DELETE_UNDERLYING_OBJECTS,PRoom.DELETE_UNDERLYING_TILES); if (ver2 == 520) in.skip(6 * 4); //tile info in.read4(rm.properties,PRoom.CURRENT_TAB,PRoom.SCROLL_BAR_X,PRoom.SCROLL_BAR_Y); in.endInflate(); } f.resMap.getList(Room.class).lastId = noRooms - 1; } private static void readIncludedFiles(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 430 && ver != 600 && ver != 620 && ver != 800 && ver != 810) throw versionError(f,"BEFORE","GMI",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noIncludes = in.read4(); for (int i = 0; i < noIncludes; i++) { if (ver >= 800) { in.beginInflate(); in.skip(8); //last changed } ver = in.read4(); if (ver != 620 && ver != 800 && ver != 810) throw new GmFormatException(f,Messages.format("ProjectFileReader.ERROR_UNSUPPORTED", //$NON-NLS-1$ Messages.getString("ProjectFileReader.ININCLUDEDFILES"),ver)); //$NON-NLS-1$ Include inc = f.resMap.getList(Include.class).add(); inc.filename = in.readStr(); inc.filepath = in.readStr(); inc.isOriginal = in.readBool(); inc.size = in.read4(); if (in.readBool()) //store in editable? { int s = in.read4(); inc.data = new byte[s]; in.read(inc.data,0,s); } inc.export = in.read4(); inc.exportFolder = in.readStr(); inc.overwriteExisting = in.readBool(); inc.freeMemAfterExport = in.readBool(); inc.removeAtGameEnd = in.readBool(); in.endInflate(); } } private static void readPackages(ProjectFileContext c) throws IOException,GmFormatException { ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 700) throw versionError(f,"BEFORE","EXT",ver); //$NON-NLS-1$ //$NON-NLS-2$ int noPackages = in.read4(); for (int i = 0; i < noPackages; i++) f.packages.add(in.readStr()); //Package name } private static void readGameInformation(ProjectFileContext c) throws IOException, GmFormatException { GmStreamDecoder in = c.in; GameInformation gameInfo = c.f.gameInfo; PropertyMap<PGameInformation> p = gameInfo.properties; int ver = in.read4(); if (ver != 430 && ver != 600 && ver != 620 && ver != 800 && ver != 810) throw versionError(c.f,"BEFORE","GMI",ver); //$NON-NLS-1$ //$NON-NLS-2$ if (ver >= 800) in.beginInflate(); int bc = in.read4(); if (bc >= 0) p.put(PGameInformation.BACKGROUND_COLOR,Util.convertGmColor(bc)); if (ver < 800) in.readBool(p,PGameInformation.EMBED_GAME_WINDOW); else p.put(PGameInformation.EMBED_GAME_WINDOW,!in.readBool()); //Show help in a separate window if (ver > 430) { in.readStr(p,PGameInformation.FORM_CAPTION); in.read4(p,PGameInformation.LEFT,PGameInformation.TOP,PGameInformation.WIDTH, PGameInformation.HEIGHT); in.readBool(p,PGameInformation.SHOW_BORDER,PGameInformation.ALLOW_RESIZE, PGameInformation.STAY_ON_TOP,PGameInformation.PAUSE_GAME); } if (ver >= 800) in.skip(8); //last changed in.readStr(p,PGameInformation.TEXT); in.endInflate(); } private static void readTree(ProjectFileContext c, ResNode root, int ver) throws IOException { ProjectFile f = c.f; GmStreamDecoder in = c.in; Stack<ResNode> path = new Stack<ResNode>(); Stack<Integer> left = new Stack<Integer>(); path.push(root); int rootnodes = (ver > 540) ? 12 : 11; while (rootnodes-- > 0) { byte status = (byte) in.read4(); Class<?> type = ProjectFile.RESOURCE_KIND[in.read4()]; int ind = in.read4(); String name = in.readStr(); boolean hasRef; if (status == ResNode.STATUS_SECONDARY) hasRef = type == Font.class ? ver != 500 : (type == null ? false : InstantiableResource.class.isAssignableFrom(type)); else hasRef = false; ResourceList<?> rl = hasRef ? (ResourceList<?>) f.resMap.get(type) : null; ResNode node = new ResNode(name,status,type,hasRef ? rl.getUnsafe(ind).reference : null); if (ver == 500 && status == ResNode.STATUS_PRIMARY && type == Font.class) path.peek().addChild(Messages.getString("LGM.FNT"),status,type); //$NON-NLS-1$ else path.peek().add(node); int contents = in.read4(); if (contents > 0) { left.push(new Integer(rootnodes)); rootnodes = contents; path.push(node); } while (rootnodes == 0 && !left.isEmpty()) { rootnodes = left.pop().intValue(); path.pop(); } } if (ver <= 540) root.addChild(Messages.getString("LGM.EXT"), //$NON-NLS-1$ ResNode.STATUS_SECONDARY,ExtensionPackages.class); //TODO: This just makes the GMK arrange to the modern version of the IDE ResNode node = new ResNode("Shaders",ResNode.STATUS_PRIMARY,Shader.class); root.insert(node,5); node = new ResNode("Extensions",ResNode.STATUS_PRIMARY,Extension.class); root.insert(node,10); node = new ResNode("Includes",ResNode.STATUS_PRIMARY,Include.class); root.insert(node,10); for (Include inc : f.resMap.getList(Include.class)) { node.add(new ResNode(inc.getName(),ResNode.STATUS_SECONDARY,Include.class)); } node = new ResNode("Constants",ResNode.STATUS_SECONDARY,Constants.class); root.insert(node,12); } private static void readActions(ProjectFileContext c, ActionContainer container, String errorKey, int format1, int format2) throws IOException,GmFormatException { final ProjectFile f = c.f; GmStreamDecoder in = c.in; int ver = in.read4(); if (ver != 400) { throw new GmFormatException(f,Messages.format("ProjectFileReader.ERROR_UNSUPPORTED", //$NON-NLS-1$ Messages.format("ProjectFileReader." + errorKey,format1,format2),ver)); //$NON-NLS-1$ } int noacts = in.read4(); for (int k = 0; k < noacts; k++) { in.skip(4); int libid = in.read4(); int actid = in.read4(); LibAction la = LibManager.getLibAction(libid,actid); boolean unknownLib = la == null; //The libAction will have a null parent, among other things if (unknownLib) { la = new LibAction(); la.id = actid; la.parentId = libid; la.actionKind = (byte) in.read4(); //TODO: Maybe make this more agnostic?" if (la.actionKind == Action.ACT_CODE) { la = LibManager.codeAction; in.skip(16); in.skip(in.read4()); in.skip(in.read4()); } else { la.allowRelative = in.readBool(); la.question = in.readBool(); la.canApplyTo = in.readBool(); la.execType = (byte) in.read4(); if (la.execType == Action.EXEC_FUNCTION) la.execInfo = in.readStr(); else in.skip(in.read4()); if (la.execType == Action.EXEC_CODE) la.execInfo = in.readStr(); else in.skip(in.read4()); } } else { in.skip(20); in.skip(in.read4()); in.skip(in.read4()); } Argument[] args = new Argument[in.read4()]; byte[] argkinds = new byte[in.read4()]; for (int x = 0; x < argkinds.length; x++) argkinds[x] = (byte) in.read4(); if (unknownLib) { la.libArguments = new LibArgument[argkinds.length]; for (int x = 0; x < argkinds.length; x++) { la.libArguments[x] = new LibArgument(); la.libArguments[x].kind = argkinds[x]; } } Action act = container.addAction(la); int appliesTo = in.read4(); switch (appliesTo) { case -1: act.setAppliesTo(GmObject.OBJECT_SELF); break; case -2: act.setAppliesTo(GmObject.OBJECT_OTHER); break; default: act.setAppliesTo(c.objids.get(appliesTo)); } act.setRelative(in.readBool()); int actualnoargs = in.read4(); for (int l = 0; l < actualnoargs; l++) { if (l >= args.length) { in.skip(in.read4()); continue; } args[l] = new Argument(argkinds[l]); String strval = in.readStr(); args[l].setVal(strval); Class<? extends Resource<?,?>> kind = Argument.getResourceKind(argkinds[l]); if (kind != null && Resource.class.isAssignableFrom(kind)) try { final int id = Integer.parseInt(strval); final Argument arg = args[l]; PostponedRef pr = new PostponedRef() { public boolean invoke() { ResourceHolder<?> rh = f.resMap.get(Argument.getResourceKind(arg.kind)); Resource<?,?> temp = null; if (rh instanceof ResourceList<?>) temp = ((ResourceList<?>) rh).getUnsafe(id); else temp = rh.getResource(); if (temp != null) arg.setRes(temp.reference); return temp != null; } }; if (!pr.invoke()) postpone.add(pr); } catch (NumberFormatException e) { //Trying to ref a resource without a valid id number? //Fallback to strval (already set) } /* switch (argkinds[l]) { case Argument.ARG_SPRITE: case Argument.ARG_SOUND: case Argument.ARG_BACKGROUND: case Argument.ARG_PATH: case Argument.ARG_SCRIPT: case Argument.ARG_FONT: res = ((ResourceList<?>) f.resMap.get(Argument.getResourceKind(argkinds[l]))).getUnsafe(Integer.parseInt(strval)); break; case Argument.ARG_GMOBJECT: args[l].setRes(c.objids.get(Integer.parseInt(strval))); break; case Argument.ARG_ROOM: args[l].setRes(c.rmids.get(Integer.parseInt(strval))); break; case Argument.ARG_TIMELINE: args[l].setRes(c.timeids.get(Integer.parseInt(strval))); break; default: args[l].setVal(strval); break; } if (res != null) args[l].setRes(res.reference);*/ act.setArguments(args); } act.setNot(in.readBool()); } } }