--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Sun Aug 12 22:37:57 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Sun Aug 12 22:46:23 2012 +0200
@@ -1,4 +1,5 @@
package org.hedgewars.hedgeroid.frontlib;
+import java.io.UnsupportedEncodingException;
import java.nio.Buffer;
import java.util.ArrayList;
import java.util.HashMap;
@@ -6,15 +7,17 @@
import java.util.Map;
import org.hedgewars.hedgeroid.Datastructures.Hog;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
import org.hedgewars.hedgeroid.Datastructures.MetaScheme;
import org.hedgewars.hedgeroid.Datastructures.MetaScheme.Mod;
import org.hedgewars.hedgeroid.Datastructures.MetaScheme.Setting;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
import org.hedgewars.hedgeroid.Datastructures.RoomlistRoom;
import org.hedgewars.hedgeroid.Datastructures.Scheme;
import org.hedgewars.hedgeroid.Datastructures.Team;
import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
-import org.hedgewars.hedgeroid.EngineProtocol.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
import com.sun.jna.Callback;
import com.sun.jna.Library;
@@ -23,56 +26,126 @@
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.Structure;
+import com.sun.jna.ptr.IntByReference;
+/**
+ * Here is an introduction to the most important aspects of the JNA code.
+ *
+ * This interface permits access to the Hedgewars frontend library (frontlib)
+ * from Java. Each function directly contained in the Frontlib interface
+ * represents a mapped C function. The Structure classes (ending in -Struct) are
+ * mappings of C structs, and the PointerType classes (ending in -Ptr) represent
+ * pointers to structs.
+ *
+ * Quick notes for USING these classes from outside this package:
+ *
+ * Usage should be fairly straightforward, but there are a few surprising
+ * gotchas. First, when you implement callbacks, YOU are responsible for
+ * ensuring that the callback objects are not garbage-collected while they might
+ * still be called! So make sure you keep them in member variables or similar,
+ * because Java will not know if there are still native references to them.
+ *
+ * When using Frontlib from outside its package, you only interact with structs
+ * via the PointerType classes. They allow you to get at the data of the struct
+ * with a function called deref(), which creates a plain normal Java object
+ * representing the data (e.g. SchemePtr.deref() will give you a Scheme object).
+ *
+ * Remember that you usually have to destroy structs that you receive from the
+ * library, because they are owned by the native code, not Java. For example, if
+ * you obtain a {@link MetaschemePtr} metaPtr using flib_metascheme_from_ini,
+ * you have to call flib_metascheme_release(metaPtr) after you are done using
+ * it. The recommended pattern for most cases is to call deref() on the pointer
+ * to get a Java object (that you can keep as long as you like), and then
+ * immediately destroy the struct if it needs destroying. To find out whether
+ * and how the struct needs to be destroyed, see the library's documentation of
+ * the function that you got the struct from.
+ *
+ * To pass new structs to the library, you can use the static createJavaOwned()
+ * function in each PointerType, which creates a new struct from the Java object
+ * you provide, and returns a pointer to that struct that you can pass to
+ * library functions. This new structure's memory is owned and managed by Java
+ * code, so do not destroy it with frontlib functions!
+ *
+ * There is a slight mismatch between the data model for the game setup. The
+ * frontlib supports setting initial health and weaponset per-hog, because the
+ * engine allows for that, but currently neither the networking protocol nor the
+ * PC frontend support this feature, so the Android version does not take
+ * advantage of it either and treats both as per-game settings. The initial
+ * health is contained in the game scheme, the weaponset is explicitly part of
+ * the GameConfig. When converting GameConfig to a native flib_gamesetup, both
+ * are automatically copied to all hogs in the game, and for the reverse
+ * conversion the weaponset of the first hog of the first team is used as the
+ * GameConfig weaponset. This means that GameConfig.weaponset will be null if
+ * there are no teams in the game.
+ *
+ * When starting a network game, you only need to query the GameSetupPtr from
+ * the netconn and use it to create the gameconn - this is preferable to using
+ * your own recreation of the game setup, because that way the same piece of
+ * code is used to determine the game setup on all platforms.
+ *
+ * The "context" parameter of the callbacks is never needed here because JNA
+ * generates function code for each callback object. Don't worry about it, just
+ * pass null for context and ignore the context parameter in the callbacks.
+ *
+ * Finally, the library functions are documented in the actual library, not
+ * here, so check the docs there to find out what exactly each function does!
+ *
+ * Notes about the structure of this class (for the next one who has to touch
+ * this...):
+ *
+ * Java/C interop is quite fiddly and error-prone, so as long as things work,
+ * try to stick to the established patterns.
+ *
+ * Structure types should always be hidden from the outside world, because they
+ * can be misused too easily. For example, if you get a Structure from the
+ * library, change a String value in there and pass it back, JNA will re-write
+ * that string using Java-owned memory without freeing the old native-owned
+ * string, which causes a memory leak and possibly a double-free or other Bad
+ * Things (tm). To avoid problems like this, Structure types are only used
+ * internally, to map existing structures to Java types (without modifying them)
+ * or to create brand-new, Java-owned structures. Both operations are exposed to
+ * the outside through the PointerType classes corresponding to the structures
+ * in question.
+ *
+ * Since all of the struct mapping happens in Java, it is never checked against
+ * the actual struct declarations in the library. That means strange things can
+ * start happening at runtime if the frontlib structs are modified without
+ * changing the mappings here to match. This also applies to the function
+ * signatures: JNA checks whether the functions actually exist when loading the
+ * library, but it has no way of knowing whether the signatures are correct. If
+ * the signatures here deviate from those in the frontlib, you might get stack
+ * corruption.
+ *
+ * In order to check at least the function signatures, take a look at the file
+ * extra/jnacontrol.c in the frontlib sources. You can validate whether the
+ * function signatures are still correct by copy-pasting them into jnaControl.c
+ * and compiling it against the frontlib headers. The typedefs and #defines in
+ * that file will make the compiler see the Java method signatures as C function
+ * declarations. Since the same functions are already declared in the frontlib
+ * headers, the compiler will give you errors if the signatures don't match.
+ */
public interface Frontlib extends Library {
static final int NATIVE_INT_SIZE = 4;
static final int NATIVE_BOOL_SIZE = 1;
- static final int NETCONN_STATE_CONNECTING = 0;
- static final int NETCONN_STATE_LOBBY = 1;
- static final int NETCONN_STATE_ROOM = 2;
- static final int NETCONN_STATE_INGAME = 3;
- static final int NETCONN_STATE_DISCONNECTED = 10;
-
- static final int NETCONN_DISCONNECT_NORMAL = 0;
- static final int NETCONN_DISCONNECT_SERVER_TOO_OLD = 1;
- static final int NETCONN_DISCONNECT_AUTH_FAILED = 2;
- static final int NETCONN_DISCONNECT_CONNLOST = 3;
- static final int NETCONN_DISCONNECT_INTERNAL_ERROR = 100;
-
- static final int NETCONN_ROOMLEAVE_ABANDONED = 0;
- static final int NETCONN_ROOMLEAVE_KICKED = 1;
-
- static final int NETCONN_MSG_TYPE_PLAYERINFO = 0;
- static final int NETCONN_MSG_TYPE_SERVERMESSAGE = 1;
- static final int NETCONN_MSG_TYPE_WARNING = 2;
- static final int NETCONN_MSG_TYPE_ERROR = 3;
-
- static final int NETCONN_MAPCHANGE_FULL = 0;
- static final int NETCONN_MAPCHANGE_MAP = 1;
- static final int NETCONN_MAPCHANGE_MAPGEN = 2;
- static final int NETCONN_MAPCHANGE_DRAWNMAP = 3;
- static final int NETCONN_MAPCHANGE_MAZE_SIZE = 4;
- static final int NETCONN_MAPCHANGE_TEMPLATE = 5;
- static final int NETCONN_MAPCHANGE_THEME = 6;
- static final int NETCONN_MAPCHANGE_SEED = 7;
-
- static final int GAME_END_FINISHED = 0;
- static final int GAME_END_INTERRUPTED = 1;
- static final int GAME_END_HALTED = 2;
- static final int GAME_END_ERROR = 3;
-
- static final int HEDGEHOGS_PER_TEAM = 8;
-
public static class NetconnPtr extends PointerType { }
public static class MapconnPtr extends PointerType { }
public static class GameconnPtr extends PointerType { }
- public static class MetaschemePtr extends PointerType { }
+
+ // TODO avoid code duplication in the pointer types
+ public static class MetaschemePtr extends PointerType {
+ public MetaScheme deref() {
+ return deref(getPointer());
+ }
+
+ public static MetaScheme deref(Pointer p) {
+ MetaschemeStruct struct = new MetaschemeStruct(p);
+ struct.read();
+ return struct.toMetaScheme();
+ }
+ }
public static class RoomArrayPtr extends PointerType {
- /**
- * Returns the (native-owned) rooms in this list
- */
public RoomlistRoom[] getRooms(int count) {
Pointer ptr = getPointer();
if(ptr == null) {
@@ -88,65 +161,123 @@
}
public static class RoomPtr extends PointerType {
- public RoomPtr() { super(); }
- public RoomPtr(Pointer ptr) { super(ptr); }
-
public RoomlistRoom deref() {
return deref(getPointer());
}
public static RoomlistRoom deref(Pointer p) {
- RoomStruct r = new RoomStruct(p);
- r.read();
- return new RoomlistRoom(r.name, r.map, r.scheme, r.weapons, r.owner, r.playerCount, r.teamCount, r.inProgress);
+ RoomStruct struct = new RoomStruct(p);
+ struct.read();
+ return struct.toRoomlistRoom();
}
}
public static class TeamPtr extends PointerType {
+ private TeamStruct javaOwnedInstance;
+
public TeamInGame deref() {
- return deref(getPointer());
+ TeamStruct struct = new TeamStruct(getPointer());
+ struct.read();
+ return struct.toTeamInGame();
}
- public static TeamInGame deref(Pointer p) {
- TeamStruct ts = new TeamStruct(p);
- ts.read();
- List<Hog> hogs = new ArrayList<Hog>();
- for(int i=0; i<ts.hogs.length; i++) {
- HogStruct hog = ts.hogs[i];
- hogs.add(new Hog(hog.name, hog.hat, hog.difficulty));
- }
- Team team = new Team(ts.name, ts.grave, ts.flag, ts.voicepack, ts.fort, hogs);
- TeamIngameAttributes attrs = new TeamIngameAttributes(ts.ownerName, ts.colorIndex, ts.hogsInGame, ts.remoteDriven);
- return new TeamInGame(team, attrs);
- }
-
public static TeamPtr createJavaOwned(Team t) {
return createJavaOwned(new TeamInGame(t, null));
}
public static TeamPtr createJavaOwned(TeamInGame ingameTeam) {
- TeamStruct ts = TeamStruct.from(ingameTeam.team, ingameTeam.ingameAttribs);
- ts.write();
TeamPtr result = new TeamPtr();
- result.setPointer(ts.getPointer());
+ result.javaOwnedInstance = new TeamStruct();
+ result.javaOwnedInstance.fillFrom(ingameTeam.team, ingameTeam.ingameAttribs);
+ result.javaOwnedInstance.autoWrite();
+ result.setPointer(result.javaOwnedInstance.getPointer());
+ return result;
+ }
+ }
+
+ public static class WeaponsetPtr extends PointerType {
+ private WeaponsetStruct javaOwnedInstance;
+
+ public Weaponset deref() {
+ WeaponsetStruct struct = new WeaponsetStruct(getPointer());
+ struct.read();
+ return struct.toWeaponset();
+ }
+
+ public static WeaponsetPtr createJavaOwned(Weaponset weaponset) {
+ WeaponsetPtr result = new WeaponsetPtr();
+ result.javaOwnedInstance = new WeaponsetStruct();
+ result.javaOwnedInstance.fillFrom(weaponset);
+ result.javaOwnedInstance.autoWrite();
+ result.setPointer(result.javaOwnedInstance.getPointer());
return result;
}
}
- public static class WeaponsetPtr extends PointerType { }
- public static class MapRecipePtr extends PointerType { }
- public static class SchemePtr extends PointerType { }
+ public static class WeaponsetListPtr extends PointerType {
+ private WeaponsetListStruct javaOwnedInstance;
+
+ public List<Weaponset> deref() {
+ WeaponsetListStruct struct = new WeaponsetListStruct(getPointer());
+ struct.read();
+ return struct.toWeaponsetList();
+ }
+
+ public static WeaponsetListPtr createJavaOwned(List<Weaponset> list) {
+ WeaponsetListPtr result = new WeaponsetListPtr();
+ result.javaOwnedInstance = new WeaponsetListStruct();
+ result.javaOwnedInstance.fillFrom(list);
+ result.javaOwnedInstance.autoWrite();
+ result.setPointer(result.javaOwnedInstance.getPointer());
+ return result;
+ }
+ }
+
+ public static class MapRecipePtr extends PointerType {
+ private MapRecipeStruct javaOwnedInstance;
+
+ public MapRecipe deref() {
+ MapRecipeStruct struct = new MapRecipeStruct(getPointer());
+ struct.read();
+ return struct.toMapRecipe();
+ }
+
+ public static MapRecipePtr createJavaOwned(MapRecipe recipe) {
+ MapRecipePtr result = new MapRecipePtr();
+ result.javaOwnedInstance = new MapRecipeStruct();
+ result.javaOwnedInstance.fillFrom(recipe);
+ result.javaOwnedInstance.autoWrite();
+ result.setPointer(result.javaOwnedInstance.getPointer());
+ return result;
+ }
+ }
+
+ public static class SchemePtr extends PointerType {
+ private SchemeStruct javaOwnedInstance;
+
+ public Scheme deref() {
+ SchemeStruct struct = new SchemeStruct(getPointer());
+ struct.read();
+ return struct.toScheme();
+ }
+
+ public static SchemePtr createJavaOwned(Scheme scheme) {
+ SchemePtr result = new SchemePtr();
+ result.javaOwnedInstance = new SchemeStruct();
+ result.javaOwnedInstance.fillFrom(scheme);
+ result.javaOwnedInstance.autoWrite();
+ result.setPointer(result.javaOwnedInstance.getPointer());
+ return result;
+ }
+ }
+
public static class SchemelistPtr extends PointerType {
private SchemelistStruct javaOwnedInstance;
public List<Scheme> deref() {
- return deref(getPointer());
- }
-
- public static List<Scheme> deref(Pointer p) {
- SchemelistStruct sls = new SchemelistStruct(p);
- sls.read();
- return sls.toSchemeList();
+ SchemelistStruct struct = new SchemelistStruct(getPointer());
+ struct.read();
+ return struct.toSchemeList();
}
public static SchemelistPtr createJavaOwned(List<Scheme> schemes) {
@@ -160,11 +291,20 @@
}
public static class GameSetupPtr extends PointerType {
+ private GameSetupStruct javaOwnedInstance;
+
+ public GameConfig deref() {
+ GameSetupStruct struct = new GameSetupStruct(getPointer());
+ struct.read();
+ return struct.toGameConfig();
+ }
+
public static GameSetupPtr createJavaOwned(GameConfig conf) {
- GameSetupStruct gss = GameSetupStruct.from(conf);
- gss.write();
GameSetupPtr result = new GameSetupPtr();
- result.setPointer(gss.getPointer());
+ result.javaOwnedInstance = new GameSetupStruct();
+ result.javaOwnedInstance.fillFrom(conf);
+ result.javaOwnedInstance.autoWrite();
+ result.setPointer(result.javaOwnedInstance.getPointer());
return result;
}
}
@@ -177,14 +317,14 @@
public HogStruct() { super(); setFieldOrder(FIELD_ORDER); }
public HogStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
- public static HogStruct from(Hog hog) {
- HogStruct hs = new HogStruct();
- hs.difficulty = hog.level;
- hs.hat = hog.hat;
- hs.name = hog.name;
- // TODO weaponset
- // TODO initialHealth
- return hs;
+ public void fillFrom(Hog hog) {
+ difficulty = hog.level;
+ hat = hog.hat;
+ name = hog.name;
+ }
+
+ public Hog toHog() {
+ return new Hog(name, hat, difficulty);
}
public String name;
@@ -198,7 +338,7 @@
public int difficulty;
public int initialHealth;
- public WeaponsetPtr weaponset;
+ public WeaponsetStruct.ByRef weaponset;
}
static class TeamStruct extends Structure {
@@ -209,32 +349,55 @@
public TeamStruct() { super(); setFieldOrder(FIELD_ORDER); }
public TeamStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
- public static TeamStruct from(Team team, TeamIngameAttributes attrs) {
- TeamStruct ts = new TeamStruct();
+ public void fillFrom(Team team, TeamIngameAttributes attrs) {
if(team != null) {
- ts.name = team.name;
- ts.grave = team.grave;
- ts.flag = team.flag;
- ts.voicepack = team.voice;
- ts.fort = team.fort;
- if(team.hogs.size() != HEDGEHOGS_PER_TEAM) {
+ name = team.name;
+ grave = team.grave;
+ flag = team.flag;
+ voicepack = team.voice;
+ fort = team.fort;
+ if(team.hogs.size() != Team.HEDGEHOGS_PER_TEAM) {
throw new IllegalArgumentException();
}
- for(int i=0; i<ts.hogs.length; i++) {
- ts.hogs[i] = HogStruct.from(team.hogs.get(i));
+ for(int i=0; i<hogs.length; i++) {
+ hogs[i] = new HogStruct();
+ hogs[i].fillFrom(team.hogs.get(i));
}
}
if(attrs != null) {
- ts.hogsInGame = attrs.hogCount;
- ts.ownerName = attrs.ownerName;
- ts.colorIndex = attrs.colorIndex;
- ts.remoteDriven = attrs.remoteDriven;
+ hogsInGame = attrs.hogCount;
+ ownerName = attrs.ownerName;
+ colorIndex = attrs.colorIndex;
+ remoteDriven = attrs.remoteDriven;
}
- return ts;
+ }
+
+ public void fillFrom(TeamInGame team, WeaponsetStruct.ByRef weaponset, int initialHealth) {
+ fillFrom(team.team, team.ingameAttribs);
+ for(int i=0; i<hogs.length; i++) {
+ hogs[i].initialHealth = initialHealth;
+ hogs[i].weaponset = weaponset;
+ }
}
- public HogStruct[] hogs = new HogStruct[HEDGEHOGS_PER_TEAM];
+ public Team toTeam() {
+ List<Hog> hogList = new ArrayList<Hog>();
+ for(int i=0; i<hogs.length; i++) {
+ hogList.add(hogs[i].toHog());
+ }
+ return new Team(name, grave, flag, voicepack, fort, hogList);
+ }
+
+ public TeamIngameAttributes toTeamIngameAttributes() {
+ return new TeamIngameAttributes(ownerName, colorIndex, hogsInGame, remoteDriven);
+ }
+
+ public TeamInGame toTeamInGame() {
+ return new TeamInGame(toTeam(), toTeamIngameAttributes());
+ }
+
+ public HogStruct[] hogs = new HogStruct[Team.HEDGEHOGS_PER_TEAM];
public String name;
public String grave;
public String fort;
@@ -254,6 +417,106 @@
public String ownerName;
}
+ static class WeaponsetStruct extends Structure {
+ public static class ByVal extends WeaponsetStruct implements Structure.ByValue {}
+ public static class ByRef extends WeaponsetStruct implements Structure.ByReference {}
+ private static String[] FIELD_ORDER = new String[] {"_referenceCount", "loadout", "crateprob", "crateammo", "delay", "name"};
+
+ public WeaponsetStruct() { super(); setFieldOrder(FIELD_ORDER); }
+ public WeaponsetStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+
+ public void fillFrom(Weaponset weaponset) {
+ _referenceCount = 0;
+ fillWeaponInfo(loadout, weaponset.loadout);
+ fillWeaponInfo(crateprob, weaponset.crateProb);
+ fillWeaponInfo(crateammo, weaponset.crateAmmo);
+ fillWeaponInfo(delay, weaponset.delay);
+ name = weaponset.name;
+ }
+
+ private static void fillWeaponInfo(byte[] array, String str) {
+ for(int i=0; i<array.length-1; i++) {
+ array[i] = (byte) (i<str.length() ? str.charAt(i) : '0');
+ }
+ array[array.length-1] = (byte)0;
+ }
+
+ public Weaponset toWeaponset() {
+ return new Weaponset(name, weaponInfoToString(loadout), weaponInfoToString(crateprob), weaponInfoToString(crateammo), weaponInfoToString(delay));
+ }
+
+ private static String weaponInfoToString(byte[] array) {
+ try {
+ return new String(array, 0, array.length-1, "ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new AssertionError();
+ }
+ }
+
+ public int _referenceCount;
+ public byte[] loadout = new byte[Weaponset.WEAPONS_COUNT+1];
+ public byte[] crateprob = new byte[Weaponset.WEAPONS_COUNT+1];
+ public byte[] crateammo = new byte[Weaponset.WEAPONS_COUNT+1];
+ public byte[] delay = new byte[Weaponset.WEAPONS_COUNT+1];
+ public String name;
+ }
+
+ /**
+ * Represents a flib_weaponset*, for use as part of a flib_weaponset**
+ */
+ static class WeaponsetPointerByReference extends Structure implements Structure.ByReference {
+ private static String[] FIELD_ORDER = new String[] {"weaponset"};
+
+ public WeaponsetPointerByReference() { super(); setFieldOrder(FIELD_ORDER); }
+ public WeaponsetPointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+
+ public WeaponsetStruct.ByRef weaponset;
+ }
+
+ static class WeaponsetListStruct extends Structure {
+ public static class ByVal extends WeaponsetListStruct implements Structure.ByValue {}
+ public static class ByRef extends WeaponsetListStruct implements Structure.ByReference {}
+ private static String[] FIELD_ORDER = new String[] {"weaponsetCount", "weaponsets"};
+
+ public WeaponsetListStruct() { super(); setFieldOrder(FIELD_ORDER); }
+ public WeaponsetListStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+
+ public void fillFrom(List<Weaponset> list) {
+ weaponsetCount = list.size();
+ weaponsets = new WeaponsetPointerByReference();
+ Structure[] structs = weaponsets.toArray(weaponsetCount);
+
+ for(int i=0; i<weaponsetCount; i++) {
+ WeaponsetPointerByReference pstruct = (WeaponsetPointerByReference)structs[i];
+ pstruct.weaponset = new WeaponsetStruct.ByRef();
+ pstruct.weaponset.fillFrom(list.get(i));
+ }
+ }
+
+ /**
+ * Only use on native-owned structs!
+ * Calling this method on a Java-owned struct could cause garbage collection of referenced
+ * structures.
+ */
+ public List<Weaponset> toWeaponsetList() {
+ if(weaponsetCount<=0) {
+ return new ArrayList<Weaponset>();
+ } else {
+ List<Weaponset> list = new ArrayList<Weaponset>(weaponsetCount);
+ Structure[] structs = weaponsets.toArray(weaponsetCount);
+
+ for(int i=0; i<weaponsetCount; i++) {
+ WeaponsetPointerByReference pstruct = (WeaponsetPointerByReference)structs[i];
+ list.add(pstruct.weaponset.toWeaponset());
+ }
+ return list;
+ }
+ }
+
+ public int weaponsetCount;
+ public WeaponsetPointerByReference weaponsets;
+ }
+
static class RoomStruct extends Structure {
public static class ByVal extends RoomStruct implements Structure.ByValue {}
public static class ByRef extends RoomStruct implements Structure.ByReference {}
@@ -261,6 +524,10 @@
public RoomStruct() { super(); setFieldOrder(FIELD_ORDER); }
public RoomStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+
+ public RoomlistRoom toRoomlistRoom() {
+ return new RoomlistRoom(name, map, scheme, weapons, owner, playerCount, teamCount, inProgress);
+ }
public boolean inProgress;
public String name;
@@ -275,18 +542,44 @@
static class MapRecipeStruct extends Structure {
public static class ByVal extends MapRecipeStruct implements Structure.ByValue {}
public static class ByRef extends MapRecipeStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"_referenceCount", "mapgen", "name", "seed", "theme", "drawData", "drawDataSize", "templateFilter", "mazeSize"};
+ private static String[] FIELD_ORDER = new String[] {"mapgen", "name", "seed", "theme", "drawData", "drawDataSize", "templateFilter", "mazeSize"};
public MapRecipeStruct() { super(); setFieldOrder(FIELD_ORDER); }
public MapRecipeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
- public int _referenceCount;
+ public void fillFrom(MapRecipe map) {
+ mapgen = map.mapgen;
+ name = map.name;
+ seed = map.seed;
+ theme = map.theme;
+ byte[] buf = map.getDrawData();
+ if(buf != null) {
+ drawData = new Memory(buf.length);
+ drawData.write(0, buf, 0, buf.length);
+ drawDataSize = new NativeLong(buf.length);
+ } else {
+ drawData = null;
+ drawDataSize = new NativeLong(0);
+ }
+ templateFilter = map.templateFilter;
+ mazeSize = map.mazeSize;
+ }
+
+ public MapRecipe toMapRecipe() {
+ byte[] buf = null;
+ if(drawData != null && drawDataSize.intValue()>0) {
+ buf = new byte[drawDataSize.intValue()];
+ drawData.read(0, buf, 0, drawDataSize.intValue());
+ }
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, buf);
+ }
+
public int mapgen;
public String name;
public String seed;
public String theme;
public Pointer drawData;
- public int drawDataSize;
+ public NativeLong drawDataSize;
public int templateFilter;
public int mazeSize;
}
@@ -408,7 +701,7 @@
static class SchemeStruct extends Structure {
public static class ByVal extends SchemeStruct implements Structure.ByValue {}
public static class ByRef extends SchemeStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"_referenceCount", "meta", "name", "settings", "mod"};
+ private static String[] FIELD_ORDER = new String[] {"meta", "name", "settings", "mod"};
public SchemeStruct() { super(); setFieldOrder(FIELD_ORDER); }
public SchemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
@@ -442,7 +735,6 @@
return new Scheme(metaScheme, name, settingsMap, modsMap);
}
- public int _referenceCount;
public MetaschemeStruct.ByRef meta;
public String name;
public Pointer settings;
@@ -469,6 +761,18 @@
public SchemelistStruct() { super(); setFieldOrder(FIELD_ORDER); }
public SchemelistStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ public void fillFrom(List<Scheme> schemeList) {
+ schemeCount = schemeList.size();
+ schemes = new SchemePointerByReference();
+ Structure[] schemePtrStructs = schemes.toArray(schemeCount);
+
+ for(int i=0; i<this.schemeCount; i++) {
+ SchemePointerByReference spbr = (SchemePointerByReference)schemePtrStructs[i];
+ spbr.scheme = new SchemeStruct.ByRef();
+ spbr.scheme.fillFrom(schemeList.get(i));
+ }
+ }
+
/**
* Only use on native-owned structs!
* Calling this method on a Java-owned struct could cause garbage collection of referenced
@@ -490,32 +794,60 @@
}
}
- public void fillFrom(List<Scheme> schemeList) {
- schemeCount = schemeList.size();
- schemes = new SchemePointerByReference();
- Structure[] schemePtrStructs = schemes.toArray(schemeCount);
-
- for(int i=0; i<this.schemeCount; i++) {
- SchemePointerByReference spbr = (SchemePointerByReference)schemePtrStructs[i];
- spbr.scheme = new SchemeStruct.ByRef();
- spbr.scheme.fillFrom(schemeList.get(i));
- }
- }
-
public int schemeCount;
public SchemePointerByReference schemes;
}
+ /**
+ * Represents a flib_team*, for use as part of a flib_team**
+ */
+ static class TeamPointerByReference extends Structure implements Structure.ByReference {
+ private static String[] FIELD_ORDER = new String[] {"team"};
+
+ public TeamPointerByReference() { super(); setFieldOrder(FIELD_ORDER); }
+ public TeamPointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+
+ public TeamStruct.ByRef team;
+ }
+
static class TeamlistStruct extends Structure {
public static class ByVal extends TeamlistStruct implements Structure.ByValue {}
public static class ByRef extends TeamlistStruct implements Structure.ByReference {}
+
private static String[] FIELD_ORDER = new String[] {"teamCount", "teams"};
public TeamlistStruct() { super(); setFieldOrder(FIELD_ORDER); }
public TeamlistStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+ public void fillFrom(List<TeamInGame> teamList, WeaponsetStruct.ByRef weaponset, int initialHealth) {
+ teamCount = teamList.size();
+ teams = new TeamPointerByReference();
+ Structure[] teamPtrStructs = teams.toArray(teamCount);
+
+ for(int i=0; i<this.teamCount; i++) {
+ TeamPointerByReference tpbr = (TeamPointerByReference)teamPtrStructs[i];
+ tpbr.team = new TeamStruct.ByRef();
+ tpbr.team.fillFrom(teamList.get(i), weaponset, initialHealth);
+ }
+ }
+
+ public List<TeamInGame> toTeamInGameList() {
+ if(teamCount<=0) {
+ return new ArrayList<TeamInGame>();
+ } else {
+ List<TeamInGame> result = new ArrayList<TeamInGame>(teamCount);
+ Structure[] structs = teams.toArray(teamCount);
+
+ for(int i=0; i<teamCount; i++) {
+ TeamPointerByReference struct = (TeamPointerByReference)structs[i];
+ result.add(struct.team.toTeamInGame());
+ }
+ return result;
+ }
+ }
+
public int teamCount;
- public Pointer teams;
+ public TeamPointerByReference teams;
}
static class GameSetupStruct extends Structure {
@@ -526,16 +858,35 @@
public GameSetupStruct() { super(); setFieldOrder(FIELD_ORDER); }
public GameSetupStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
- public static GameSetupStruct from(GameConfig conf) {
- GameSetupStruct gss = new GameSetupStruct();
- gss.gamescheme = new SchemeStruct.ByRef();
- gss.gamescheme.fillFrom(conf.scheme);
- gss.map = new MapRecipeStruct.ByRef();
- // TODO gss.map.fillFrom(conf.map, conf.seed, conf.theme);
- gss.script = conf.style;
- gss.teamlist = new TeamlistStruct.ByRef();
- // TODO gss.teamlist.fillFrom(conf.teams, conf.weapon);
- return gss;
+ public void fillFrom(GameConfig conf) {
+ script = conf.style;
+ gamescheme = new SchemeStruct.ByRef();
+ gamescheme.fillFrom(conf.scheme);
+ map = new MapRecipeStruct.ByRef();
+ map.fillFrom(conf.map);
+
+ /*
+ * At this point we deviate from the usual copying pattern because the frontlib
+ * expects per-hog weapons and initial health, but the UI models them as per-
+ * game, so we extract them from the config here and pass them on to be included
+ * in each hog.
+ */
+ WeaponsetStruct.ByRef wss = new WeaponsetStruct.ByRef();
+ wss.fillFrom(conf.weaponset);
+ int initialHealth = conf.scheme.getHealth();
+
+ teamlist = new TeamlistStruct.ByRef();
+ teamlist.fillFrom(conf.teams, wss, initialHealth);
+ }
+
+ public GameConfig toGameConfig() {
+ Scheme scheme = gamescheme != null ? gamescheme.toScheme() : null;
+ MapRecipe mapRecipe = map != null ? map.toMapRecipe() : null;
+ List<TeamInGame> teams = teamlist != null ? teamlist.toTeamInGameList() : null;
+
+ WeaponsetStruct weaponsetStruct = teamlist != null && teamlist.teamCount>0 ? teamlist.teams.team.hogs[0].weaponset : null;
+ Weaponset weaponset = weaponsetStruct != null ? weaponsetStruct.toWeaponset() : null;
+ return new GameConfig(script, scheme, mapRecipe, teams, weaponset);
}
public String script;
@@ -544,6 +895,12 @@
public TeamlistStruct.ByRef teamlist;
}
+ /*
+ * Callback interfaces. The context parameter is never needed here and
+ * should always be ignored. Be sure to keep a reference to each callback
+ * for as long as they might be called by native code, to avoid premature
+ * garbage collection.
+ */
public static interface VoidCallback extends Callback {
void callback(Pointer context);
}
@@ -620,15 +977,50 @@
void callback(int level, String logMessage);
}
+ // frontlib.h
int flib_init();
void flib_quit();
+ // hwconsts.h
+ int flib_get_teamcolor(int colorIndex);
+ int flib_get_teamcolor_count();
+ int flib_get_hedgehogs_per_team();
+ int flib_get_weapons_count();
+
+ // net/netconn.h
+ static final int NETCONN_STATE_CONNECTING = 0;
+ static final int NETCONN_STATE_LOBBY = 1;
+ static final int NETCONN_STATE_ROOM = 2;
+ static final int NETCONN_STATE_DISCONNECTED = 10;
+
+ static final int NETCONN_DISCONNECT_NORMAL = 0;
+ static final int NETCONN_DISCONNECT_SERVER_TOO_OLD = 1;
+ static final int NETCONN_DISCONNECT_AUTH_FAILED = 2;
+ static final int NETCONN_DISCONNECT_CONNLOST = 3;
+ static final int NETCONN_DISCONNECT_INTERNAL_ERROR = 100;
+
+ static final int NETCONN_ROOMLEAVE_ABANDONED = 0;
+ static final int NETCONN_ROOMLEAVE_KICKED = 1;
+
+ static final int NETCONN_MSG_TYPE_PLAYERINFO = 0;
+ static final int NETCONN_MSG_TYPE_SERVERMESSAGE = 1;
+ static final int NETCONN_MSG_TYPE_WARNING = 2;
+ static final int NETCONN_MSG_TYPE_ERROR = 3;
+
+ static final int NETCONN_MAPCHANGE_FULL = 0;
+ static final int NETCONN_MAPCHANGE_MAP = 1;
+ static final int NETCONN_MAPCHANGE_MAPGEN = 2;
+ static final int NETCONN_MAPCHANGE_DRAWNMAP = 3;
+ static final int NETCONN_MAPCHANGE_MAZE_SIZE = 4;
+ static final int NETCONN_MAPCHANGE_TEMPLATE = 5;
+ static final int NETCONN_MAPCHANGE_THEME = 6;
+ static final int NETCONN_MAPCHANGE_SEED = 7;
+
NetconnPtr flib_netconn_create(String playerName, MetaschemePtr meta, String dataDirPath, String host, int port);
void flib_netconn_destroy(NetconnPtr conn);
void flib_netconn_tick(NetconnPtr conn);
boolean flib_netconn_is_chief(NetconnPtr conn);
- boolean flib_netconn_is_in_room_context(NetconnPtr conn);
String flib_netconn_get_playername(NetconnPtr conn);
GameSetupPtr flib_netconn_create_gamesetup(NetconnPtr conn);
int flib_netconn_send_quit(NetconnPtr conn, String quitmsg);
@@ -644,7 +1036,7 @@
int flib_netconn_send_toggleReady(NetconnPtr conn);
int flib_netconn_send_addTeam(NetconnPtr conn, TeamPtr team);
int flib_netconn_send_removeTeam(NetconnPtr conn, String teamname);
- int flib_netconn_send_engineMessage(NetconnPtr conn, Buffer message, NativeLong size); // TODO check if NativeLong==size_t
+ int flib_netconn_send_engineMessage(NetconnPtr conn, Buffer message, NativeLong size);
int flib_netconn_send_teamHogCount(NetconnPtr conn, String teamname, int hogcount);
int flib_netconn_send_teamColor(NetconnPtr conn, String teamname, int colorIndex);
int flib_netconn_send_weaponset(NetconnPtr conn, WeaponsetPtr weaponset);
@@ -702,7 +1094,12 @@
void flib_netconn_onAdminAccess(NetconnPtr conn, VoidCallback callback, Pointer context);
void flib_netconn_onServerVar(NetconnPtr conn, StrStrCallback callback, Pointer context);
- // Gameconn
+ // ipc/gameconn.h
+ static final int GAME_END_FINISHED = 0;
+ static final int GAME_END_INTERRUPTED = 1;
+ static final int GAME_END_HALTED = 2;
+ static final int GAME_END_ERROR = 3;
+
GameconnPtr flib_gameconn_create(String playerName, GameSetupPtr setup, boolean netgame);
GameconnPtr flib_gameconn_create_playdemo(Buffer demo, NativeLong size);
GameconnPtr flib_gameconn_create_loadgame(String playerName, Buffer save, NativeLong size);
@@ -715,6 +1112,7 @@
int flib_gameconn_send_enginemsg(GameconnPtr conn, Buffer data, NativeLong len);
int flib_gameconn_send_textmsg(GameconnPtr conn, int msgtype, String msg);
int flib_gameconn_send_chatmsg(GameconnPtr conn, String playername, String msg);
+ int flib_gameconn_send_quit(GameconnPtr conn);
void flib_gameconn_onConnect(GameconnPtr conn, VoidCallback callback, Pointer context);
void flib_gameconn_onDisconnect(GameconnPtr conn, IntCallback callback, Pointer context);
@@ -723,7 +1121,7 @@
void flib_gameconn_onGameRecorded(GameconnPtr conn, BytesBoolCallback callback, Pointer context);
void flib_gameconn_onEngineMessage(GameconnPtr conn, BytesCallback callback, Pointer context);
- // MapConn
+ // ipc/mapconn.h
MapconnPtr flib_mapconn_create(MapRecipePtr mapdesc);
void flib_mapconn_destroy(MapconnPtr conn);
int flib_mapconn_getport(MapconnPtr conn);
@@ -731,11 +1129,7 @@
void flib_mapconn_onFailure(MapconnPtr conn, StrCallback callback, Pointer context);
void flib_mapconn_tick(MapconnPtr conn);
- // GameSetup
- void flib_gamesetup_destroy(GameSetupPtr gamesetup);
- GameSetupPtr flib_gamesetup_copy(GameSetupPtr gamesetup);
-
- // MapRecipe
+ // model/map.h
public static final int MAPGEN_REGULAR = 0;
public static final int MAPGEN_MAZE = 1;
public static final int MAPGEN_DRAWN = 2;
@@ -754,33 +1148,28 @@
public static final int MAZE_SIZE_SMALL_ISLANDS = 3;
public static final int MAZE_SIZE_MEDIUM_ISLANDS = 4;
public static final int MAZE_SIZE_LARGE_ISLANDS = 5;
-
- MapRecipePtr flib_map_create_regular(String seed, String theme, int templateFilter);
- MapRecipePtr flib_map_create_maze(String seed, String theme, int mazeSize);
- MapRecipePtr flib_map_create_named(String seed, String name);
- MapRecipePtr flib_map_create_drawn(String seed, String theme, Buffer drawData, NativeLong drawDataSize);
- MapRecipePtr flib_map_copy(MapRecipePtr map);
- MapRecipePtr flib_map_retain(MapRecipePtr map);
- void flib_map_release(MapRecipePtr map);
-
- // Metascheme
+
+ // model/scheme.h
MetaschemePtr flib_metascheme_from_ini(String filename);
MetaschemePtr flib_metascheme_retain(MetaschemePtr metainfo);
void flib_metascheme_release(MetaschemePtr metainfo);
- // Scheme lists
+ // model/schemelist.h
SchemelistPtr flib_schemelist_from_ini(MetaschemePtr meta, String filename);
int flib_schemelist_to_ini(String filename, SchemelistPtr list);
void flib_schemelist_destroy(SchemelistPtr list);
- // Team
- void flib_team_destroy(TeamPtr team);
+ // model/team.h
TeamPtr flib_team_from_ini(String filename);
int flib_team_to_ini(String filename, TeamPtr team);
- void flib_team_set_weaponset(TeamPtr team, WeaponsetPtr set);
- void flib_team_set_health(TeamPtr team, int health);
+ void flib_team_destroy(TeamPtr team);
- // Logging
+ // model/weapon.h
+ WeaponsetListPtr flib_weaponsetlist_from_ini(String filename);
+ int flib_weaponsetlist_to_ini(String filename, WeaponsetListPtr weaponsets);
+ void flib_weaponsetlist_destroy(WeaponsetListPtr list);
+
+ // util/logging.h
public static final int FLIB_LOGLEVEL_ALL = -100;
public static final int FLIB_LOGLEVEL_DEBUG = -1;
public static final int FLIB_LOGLEVEL_INFO = 0;