diff -r 2e6391f33204 -r 69fb04c8a841 project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Scheme.java --- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Scheme.java Sat Mar 31 20:39:19 2012 +0200 +++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Scheme.java Sun Apr 01 04:27:46 2012 +0200 @@ -18,322 +18,167 @@ package org.hedgewars.hedgeroid.Datastructures; -import java.io.BufferedReader; +import java.util.Map; + import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.TreeMap; import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; +import org.ini4j.Ini; +import org.ini4j.InvalidFileFormatException; +import org.ini4j.Profile.Section; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; public class Scheme implements Parcelable, Comparable{ - public static final String DIRECTORY_SCHEME = "schemes"; + private static final Map basicSettingsMeta = new TreeMap(); + private static final Map gameModsMeta = new TreeMap(); - private String name; - //private ArrayList basic; - private Integer gamemod; - private ArrayList basic;; - private static ArrayList> basicflags = new ArrayList>();//TODO why is it static? - public int health; - - public Scheme(String _name, ArrayList _basic, int _gamemod){ + private final String name; + private final int gamemod; + private final Map basic = new TreeMap(); + + public Scheme(String _name, Map _basic, int _gamemod) { name = _name; gamemod = _gamemod; - basic = _basic; + basic.putAll(_basic); } public Scheme(Parcel in){ - readFromParcel(in); + name = in.readString(); + gamemod = in.readInt(); + in.readMap(basic, Integer.class.getClassLoader()); } - public void sendToEngine(EngineProtocolNetwork epn)throws IOException{ + public int getHealth() { + return basic.get("InitialHealth"); + } + + public void sendToEngine(EngineProtocolNetwork epn) throws IOException{ epn.sendToEngine(String.format("e$gmflags %d", gamemod)); - for(int pos = 0; pos < basic.size(); pos++){ - LinkedHashMap basicflag = basicflags.get(pos); + for(Map.Entry entry : basic.entrySet()) { + BasicSettingMeta basicflag = basicSettingsMeta.get(entry.getKey()); - String command = (String)basicflag.get("command"); - Integer value = basic.get(pos); - - if(command.equals("inithealth")){//Health is a special case, it doesn't need to be send - health = value; //to the engine yet, we'll do that with the other HH info - continue; + //Health is a special case, it doesn't need to be send + //to the engine yet, we'll do that with the other HH info + if(!basicflag.command.equals("inithealth")){ + epn.sendToEngine(String.format("%s %d", basicflag.command, entry.getValue())); } - - Boolean checkOverMax = (Boolean) basicflag.get("checkOverMax"); - Boolean times1000 = (Boolean) basicflag.get("times1000"); - Integer max = (Integer) basicflag.get("max"); - - if(checkOverMax && value >= max) value = max; - if(times1000) value *= 1000; - - epn.sendToEngine(String.format("%s %d", command, value)); } } + public String toString(){ return name; } - - public static final int STATE_START = 0; - public static final int STATE_ROOT = 1; - public static final int STATE_NAME = 2; - public static final int STATE_BASICFLAGS = 3; - public static final int STATE_GAMEMOD = 4; - public static final int STATE_BASICFLAG_INTEGER = 5; - public static final int STATE_GAMEMOD_TRUE = 6; - public static final int STATE_GAMEMOD_FALSE = 7; - - public static ArrayList getSchemes(Context c) throws IllegalArgumentException{ - String dir = c.getFilesDir().getAbsolutePath() + '/' + DIRECTORY_SCHEME + '/'; - String[] files = new File(dir).list(fnf); - if(files == null) files = new String[]{}; + public static List getSchemes(Context c) throws IllegalArgumentException { + File schemeDir = new File(c.getFilesDir(), DIRECTORY_SCHEME); + File[] files = schemeDir.listFiles(new FilenameFilter() { + public boolean accept(File dir, String filename) { + return filename.toLowerCase().startsWith("scheme_"); + } + }); + if(files == null) files = new File[0]; Arrays.sort(files); - ArrayList schemes = new ArrayList(); - - try { - XmlPullParserFactory xmlPullFactory = XmlPullParserFactory.newInstance(); - XmlPullParser xmlPuller = xmlPullFactory.newPullParser(); - - for(String file : files){ - BufferedReader br = new BufferedReader(new FileReader(dir + file), 1024); - xmlPuller.setInput(br); - String name = null; - ArrayList basic = new ArrayList(); - Integer gamemod = 0; - int health = 0; - int mask = 0x000000004; + List schemes = new ArrayList(); - int eventType = xmlPuller.getEventType(); - int state = STATE_START; - while(eventType != XmlPullParser.END_DOCUMENT){ - switch(state){ - case STATE_START: - if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().equals("scheme")) state = STATE_ROOT; - else if(eventType != XmlPullParser.START_DOCUMENT) throwException(file, eventType); - break; - case STATE_ROOT: - if(eventType == XmlPullParser.START_TAG){ - if(xmlPuller.getName().equals("basicflags")) state = STATE_BASICFLAGS; - else if(xmlPuller.getName().toLowerCase().equals("gamemod")) state = STATE_GAMEMOD; - else if(xmlPuller.getName().toLowerCase().equals("name")) state = STATE_NAME; - else throwException(file, eventType); - }else if(eventType == XmlPullParser.END_TAG) state = STATE_START; - else throwException(xmlPuller.getText(), eventType); - break; - case STATE_BASICFLAGS: - if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().toLowerCase().equals("integer")) state = STATE_BASICFLAG_INTEGER; - else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT; - else throwException(file, eventType); - break; - case STATE_GAMEMOD: - if(eventType == XmlPullParser.START_TAG){ - if(xmlPuller.getName().toLowerCase().equals("true")) state = STATE_GAMEMOD_TRUE; - else if(xmlPuller.getName().toLowerCase().equals("false")) state = STATE_GAMEMOD_FALSE; - else throwException(file, eventType); - }else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT; - else throwException(file, eventType); - break; - case STATE_NAME: - if(eventType == XmlPullParser.TEXT) name = xmlPuller.getText().trim(); - else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT; - else throwException(file, eventType); - break; - case STATE_BASICFLAG_INTEGER: - if(eventType == XmlPullParser.TEXT) basic.add(Integer.parseInt(xmlPuller.getText().trim())); - else if(eventType == XmlPullParser.END_TAG) state = STATE_BASICFLAGS; - else throwException(file, eventType); - break; - case STATE_GAMEMOD_FALSE: - if(eventType == XmlPullParser.TEXT) gamemod <<= 1; - else if(eventType == XmlPullParser.END_TAG) state = STATE_GAMEMOD; - else throwException(file, eventType); - break; - case STATE_GAMEMOD_TRUE: - if(eventType == XmlPullParser.TEXT){ - gamemod |= mask; - gamemod <<= 1; - }else if(eventType == XmlPullParser.END_TAG) state = STATE_GAMEMOD; - else throwException(file, eventType); - break; + for(File file : files) { + try { + Ini ini = new Ini(file); + + String name = ini.get("Scheme", "name"); + if(name==null) { + name = file.getName(); + } + Section basicSettingsSection = ini.get("BasicSettings"); + Section gameModsSection = ini.get("GameMods"); + if(basicSettingsSection == null || gameModsSection == null) { + Log.e(Scheme.class.getCanonicalName(), "Scheme file "+file+" is missing the BasicSettings or GameMods section - skipping."); + continue; + } + + Map basicSettings = new TreeMap(); + for(Entry entry : basicSettingsMeta.entrySet()) { + String key = entry.getKey(); + BasicSettingMeta settingMeta = entry.getValue(); + Integer value = null; + if(basicSettingsSection.containsKey(key)) { + try { + value = Integer.valueOf(basicSettingsSection.get(key)); + } catch (NumberFormatException e) { + // ignore + } } - eventType = getEventType(xmlPuller); - }//end while(eventtype != END_DOCUMENT - schemes.add(new Scheme(name, basic, gamemod)); - }//end for(string file : files - return schemes; - } catch (XmlPullParserException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + + if(value==null) { + Log.w(Scheme.class.getCanonicalName(), "Scheme file "+file+" setting "+key+" is missing or invalid, using default."); + value = settingMeta.def; + } + + if(settingMeta.checkOverMax) { + value = Math.min(value, settingMeta.max); + } + if(settingMeta.times1000) { + value *= 1000; + } + + basicSettings.put(key, value); + } + + int gamemods = 0; + for(Entry entry : gameModsMeta.entrySet()) { + String key = entry.getKey(); + GameModMeta modMeta = entry.getValue(); + if(Boolean.parseBoolean(gameModsSection.get(key))) { + gamemods |= (1 << modMeta.bitmaskIndex); + } + } + + schemes.add(new Scheme(name, basicSettings, gamemods)); + } catch (InvalidFileFormatException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } } - return new ArrayList();//TODO handle correctly + return schemes; } - private static FilenameFilter fnf = new FilenameFilter(){ - public boolean accept(File dir, String filename) { - return filename.toLowerCase().startsWith("scheme_"); - } - }; - /** - * This method will parse the basic flags from a prespecified xml file. - * I use a raw xml file rather than one parsed by aatp at compile time - * to keep it generic with other frontends, ie in the future we could - * use one provided by the Data folder. - */ - public static void parseBasicFlags(Context c){ - String filename = String.format("%s/%s/basicflags", c.getFilesDir().getAbsolutePath(), DIRECTORY_SCHEME); - - XmlPullParser xmlPuller = null; - BufferedReader br = null; - try { - XmlPullParserFactory xmlPullFactory = XmlPullParserFactory.newInstance(); - xmlPuller = xmlPullFactory.newPullParser(); - br = new BufferedReader(new FileReader(filename), 1024); - xmlPuller.setInput(br); - - int eventType = getEventType(xmlPuller); - boolean continueParsing = true; - do{ - switch(eventType){ - - case XmlPullParser.START_TAG: - if(xmlPuller.getName().toLowerCase().equals("flag")){ - basicflags.add(parseFlag(xmlPuller)); - }else if(xmlPuller.getName().toLowerCase().equals("basicflags")){ - eventType = getEventType(xmlPuller); - }else{ - skipCurrentTag(xmlPuller); - eventType = getEventType(xmlPuller); - } - break; - case XmlPullParser.START_DOCUMENT://ignore all tags not being "flag" - case XmlPullParser.END_TAG: - case XmlPullParser.TEXT: - default: - continueParsing = true; - case XmlPullParser.END_DOCUMENT: - continueParsing = false; - } - }while(continueParsing); - - }catch(IOException e){ - e.printStackTrace(); - }catch (XmlPullParserException e) { - e.printStackTrace(); - }finally{ - if(br != null) - try { - br.close(); - } catch (IOException e) {} - } - - } - - /* - * * Parses a Tag structure from xml as example we use - * - * - * false - * - * - * - * It returns a LinkedHashMap with key/value pairs + * This method will parse the basic flags from a prespecified ini file. + * In the future we could use one provided by the Data folder. */ - private static LinkedHashMap parseFlag(XmlPullParser xmlPuller)throws XmlPullParserException, IOException{ - LinkedHashMap hash = new LinkedHashMap(); - - int eventType = xmlPuller.getEventType();//Get the event type which triggered this method - if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().toLowerCase().equals("flag")){//valid start of flag tag - String lcKey = null; - String lcType = null; - String value = null; - - eventType = getEventType(xmlPuller);// - while(eventType == XmlPullParser.START_TAG){ - lcKey = xmlPuller.getName();//checkOverMax - if(getEventType(xmlPuller) == XmlPullParser.START_TAG){// - lcType = xmlPuller.getName().toLowerCase(); - if(getEventType(xmlPuller) == XmlPullParser.TEXT){ - value = xmlPuller.getText(); - if(getEventType(xmlPuller) == XmlPullParser.END_TAG && // - getEventType(xmlPuller) == XmlPullParser.END_TAG){// - if(lcType.equals("boolean")) hash.put(lcKey, new Boolean(value)); - else if(lcType.equals("string"))hash.put(lcKey, value); - else if(lcType.equals("integer")){ - try{ - hash.put(lcKey, new Integer(value)); - }catch (NumberFormatException e){ - throw new XmlPullParserException("Wrong integer value in xml file"); - } - }else{ - throwException("basicflags", eventType); - } - }// / - }//if TEXT - }//if boolean - eventType = getEventType(xmlPuller);//start new loop + public static void parseConfiguration(Context c) { + File schemeDir = new File(c.getFilesDir(), DIRECTORY_SCHEME); + File settingsFile = new File(schemeDir, "basicsettings"); + File gameModsFile = new File(schemeDir, "gamemods"); + + try { + Ini ini = new Ini(settingsFile); + for(Entry sectionEntry : ini.entrySet()) { + basicSettingsMeta.put(sectionEntry.getKey(), new BasicSettingMeta(sectionEntry.getValue())); } - eventType = getEventType(xmlPuller);// + + ini = new Ini(gameModsFile); + for(Entry sectionEntry : ini.entrySet()) { + gameModsMeta.put(sectionEntry.getKey(), new GameModMeta(sectionEntry.getValue())); + } + } catch (InvalidFileFormatException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); } - - return hash; - } - - private static void skipCurrentTag(XmlPullParser xmlPuller) throws XmlPullParserException, IOException{ - int eventType = xmlPuller.getEventType(); - if(eventType != XmlPullParser.START_TAG)return; - String tag = xmlPuller.getName().toLowerCase(); - - while(true){ - eventType = getEventType(xmlPuller);//getNext() - switch(eventType){ - case XmlPullParser.START_DOCUMENT://we're inside of a start tag so START_ or END_DOCUMENT is just wrong - case XmlPullParser.END_DOCUMENT: - throw new XmlPullParserException("invalid xml file"); - case XmlPullParser.START_TAG://if we get a new tag recursively handle it - skipCurrentTag(xmlPuller); - break; - case XmlPullParser.TEXT: - break; - case XmlPullParser.END_TAG: - if(!xmlPuller.getName().toLowerCase().equals(tag)){//if the end tag doesn't match the start tag - throw new XmlPullParserException("invalid xml file"); - }else{ - return;//skip completed - } - - } - } - } - - /** - * Skips whitespaces.. - */ - private static int getEventType(XmlPullParser xmlPuller)throws XmlPullParserException, IOException{ - int eventType = xmlPuller.next(); - while(eventType == XmlPullParser.TEXT && xmlPuller.isWhitespace()){ - eventType = xmlPuller.next(); - } - return eventType; - } - private static void throwException(String file, int eventType){ - throw new IllegalArgumentException(String.format("Xml file: %s malformed with error: %d.", file, eventType)); } public int describeContents() { @@ -343,13 +188,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(gamemod); - dest.writeList(basic); - } - - public void readFromParcel(Parcel src){ - name = src.readString(); - gamemod = src.readInt(); - basic = src.readArrayList(ArrayList.class.getClassLoader()); + dest.writeMap(basic); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -366,3 +205,48 @@ return name.compareTo(another.name); } } + +class BasicSettingMeta { + final String command; + final String title; + final int def; + final int min; + final int max; + final boolean times1000; + final boolean checkOverMax; + + public BasicSettingMeta(Ini.Section section) { + command = getRequired(section, "command"); + title = section.get("title", ""); + def = Integer.parseInt(getRequired(section, "default")); + min = Integer.parseInt(getRequired(section, "min")); + max = Integer.parseInt(getRequired(section, "max")); + times1000 = Boolean.parseBoolean(section.get("times1000", "false")); + checkOverMax = Boolean.parseBoolean(section.get("checkOverMax", "false")); + } + + private String getRequired(Ini.Section section, String key) { + String result = section.get(key); + if(result==null) { + throw new IllegalArgumentException("basicsettings.ini, section "+section.getName()+" is missing required setting "+key+"."); + } + return result; + } +} + +// TODO: Extend with additional metadata +class GameModMeta { + final int bitmaskIndex; + + public GameModMeta(Ini.Section section) { + bitmaskIndex = Integer.parseInt(getRequired(section, "bitmaskIndex")); + } + + private String getRequired(Ini.Section section, String key) { + String result = section.get(key); + if(result==null) { + throw new IllegalArgumentException("gamemods.ini, section "+section.getName()+" is missing required setting "+key+"."); + } + return result; + } +} \ No newline at end of file