Suggested name: BukkitSpheres (I know it's bad) A bit about me: I write a bit of code in my spare time, mostly C++. I've tried starting a server before, unsuccesfully, but this idea has gotten a lot of good feedback, so I'm going to try again, making a Hardcore Factions Biosphere server, which is why I need that plugin! What I want: I'm making a server based around this (scroll to the bottom), so that mod ported to Bukkit? Ideas for commands: No commands needed for this plugin. Ideas for permissions: None needed. When I'd like it by: A few days from now, maybe a week or so? Similar plugin requests: http://forums.bukkit.org/threads/in...ld-v0-5-creates-a-world-of-spheres-953.18557/ That was made, but became very out of date. Devs who might be interested in this: New here, no idea. NOTE: I'm happy to give $5 for the creation of this plugin, if that's any incentive
Yeah, it appears to be the same mod that we're talking about. It would be a great help if someone could port it over here, though! Thank you!
Good luck! A few tips: You should format your post. You should also add [WGEN] to your title, and if you formatted it, [FORMATTED].
Heck, if not a plugin, a server mod to permanently change the world gen would do. I really need this world.
1st of all, plugin and server mod are basically synonymous unless you want to port SSP mods to SMP. Just by the way. This is a biosphere generation mod that is horribly outdated. Just in case someone wants to update it instead of starting from scratch. This is a link to a updated similar map generator along the lines of planetoids. Hope one or both of these is helpful to you .
Well, I opened the Biosphere generator in eclipse, and I didn't find any errors. Is there a tutorial somewhere to fix it? In the past I've usually relied on errors. Thank you very much for the links!
Kezz - I saw that, but I don't think that Biospheres would work in that, unless there was an option to write the raw code. Is there something of the like for that, or am I missing something there? And, as for everyone saying about pre-creating the world, it's going to be 10,000 X 10,000 blocks. Although I have tried doing it in SP, it just takes too long. Thanks anyways! For those who may wish, the raw code for Biospheres generation : Code: package net.minecraft.src; import java.io.*; import java.util.*; import net.minecraft.client.Minecraft; import net.minecraft.server.MinecraftServer; public class BiosphereGen implements IChunkProvider { private static final File cfgfile; public final Random rndSphere; public final Random rndNoise; public final World world; public final boolean features; private MapGenBase caveGen; private NoiseGeneratorOctaves noiseGen; public static final int GRID_SIZE; private static final int BRIDGE_SIZE; public static final int SPECIAL_RADIUS; public static final int LAVA_LEVEL; public static final byte DOME_TYPE; public static final byte BRIDGE_SUPPORT; public static final byte BRIDGE_RAIL; public static final boolean NOISE; public static final boolean ENABLED; public static final boolean TALLGRASS; public static final boolean WATERWORLD; public static final boolean EXPLOITBUG; public int midX; public int midY; public int midZ; public int oreMidX; public int oreMidY; public int oreMidZ; public int lakeMidY; public double sphereRadius; public double lakeRadius; public double lakeEdgeRadius; public double noiseMin; public double noiseMax; public BiomeGenBase biome; public boolean hasLake; public boolean lavaLake; public final float scale = 1.0F; public final int scaledGrid; public final int scaledSpecial; public double noise[]; public static final int heightShift = 7; public static final int xShift = 11; public static final int worldHeight = 128; public static final int worldMaxY = 127; public static final int seaLevel = 63; public BiosphereGen(World world1, long l, boolean flag) { caveGen = new BiosphereCaveGen(); noiseMin = Double.MAX_VALUE; noiseMax = 4.9406564584124654E-324D; noise = new double[256]; rndSphere = new Random(l); world = world1; features = flag; scaledGrid = (int)((float)GRID_SIZE * scale); scaledSpecial = (int)((float)SPECIAL_RADIUS * scale); if (NOISE) { rndNoise = new Random(l); noiseGen = new NoiseGeneratorOctaves(rndNoise, 4); } else { rndNoise = null; } } public void setRand(int i, int j) { midX = (i - (int)Math.floor(Math.IEEEremainder(i, scaledGrid)) << 4) + 8; midZ = (j - (int)Math.floor(Math.IEEEremainder(j, scaledGrid)) << 4) + 8; oreMidX = (midX + (scaledGrid / 2) * 16) - scaledSpecial; oreMidZ = (midZ + (scaledGrid / 2) * 16) - scaledSpecial; rndSphere.setSeed(world.getSeed()); long l = (rndSphere.nextLong() / 2L) * 2L + 1L; long l1 = (rndSphere.nextLong() / 2L) * 2L + 1L; long l2 = ((long)midX * l + (long)midZ * l1) * 0x2656c0L ^ world.getSeed(); rndSphere.setSeed(l2); sphereRadius = (float)Math.round(16D + rndSphere.nextDouble() * 32D + rndSphere.nextDouble() * 16D) * scale; lakeRadius = Math.round(sphereRadius / 4D); lakeEdgeRadius = lakeRadius + 2D; biome = world.getWorldChunkManager().getBiomeGenAt(i << 4, j << 4); lavaLake = biome == BiomeGenBase.hell || biome != BiomeGenBase.swampland && biome != BiomeGenBase.taiga && biome != BiomeGenBase.icePlains && biome != BiomeGenBase.sky && rndSphere.nextInt(10) == 0; hasLake = biome == BiomeGenBase.swampland || biome != BiomeGenBase.sky && rndSphere.nextInt(2) == 0; oreMidY = scaledSpecial + 1 + rndSphere.nextInt(127 - (scaledSpecial + 1)); if (NOISE) { setNoise(midX >> 4, midZ >> 4); noiseMin = Double.MAX_VALUE; for (int k = 0; k < noise.length; k++) { if (noise[k] < noiseMin) { noiseMin = noise[k]; } } lakeMidY = (int)Math.round(63D + noiseMin * 8D * (double)scale); setNoise(i, j); } else { lakeMidY = midY; } } public void setNoise(int i, int j) { if (NOISE) { double d = 0.0078125D; noise = noiseGen.generateNoiseOctaves(noise, i * 16, 128, j * 16, 16, 1, 16, d, 1.0D, d); } } public double getMainDistance(int i, int j, int k) { return (double)Math.round(getDistance(i, j, k, midX, midY, midZ)); } public double getOreDistance(int i, int j, int k) { return (double)Math.round(getDistance(i, j, k, oreMidX, oreMidY, oreMidZ)); } public int getSurfaceLevel(int i, int j) { if (NOISE) { return (int)Math.round(63D + noise[j + i * 16] * 8D * (double)scale); } else { return 63; } } public void preGenerateChunk(int i, int j, byte abyte0[]) { int k = i << 4; int l = j << 4; for (int i1 = 0; i1 < 16; i1++) { for (int j1 = 0; j1 < 16; j1++) { midY = getSurfaceLevel(j1, i1); for (int k1 = 127; k1 >= 0; k1--) { double d = getMainDistance(k + j1, k1, l + i1); double d1 = getOreDistance(k + j1, k1, l + i1); int l1 = j1 << 11 | i1 << 7 | k1; byte byte0 = 0; if (k1 > midY) { if (d == sphereRadius) { if (k1 >= midY + 4 || Math.abs((k + j1) - midX) > BRIDGE_SIZE && Math.abs((l + i1) - midZ) > BRIDGE_SIZE) { byte0 = DOME_TYPE; } } else if (hasLake && NOISE && biome != BiomeGenBase.desert && (d == lakeRadius + 1.0D || d == lakeRadius + 2D)) { if (k1 == lakeMidY) { byte0 = biome.topBlock; } else if (k1 < lakeMidY) { byte0 = biome.fillerBlock; } } else if (hasLake && NOISE && biome != BiomeGenBase.desert && d <= lakeRadius) { if (k1 == lakeMidY && biome == BiomeGenBase.icePlains) { byte0 = (byte)Block.ice.blockID; } else if (k1 <= lakeMidY) { byte0 = (byte)(lavaLake ? Block.lavaMoving.blockID : Block.waterMoving.blockID); } } else if (WATERWORLD && k1 <= midY + 4 && d > sphereRadius && (Math.abs((k + j1) - midX) == BRIDGE_SIZE || Math.abs((l + i1) - midZ) == BRIDGE_SIZE)) { byte0 = DOME_TYPE; } else if (WATERWORLD && k1 == midY + 4 && d > sphereRadius && (Math.abs((k + j1) - midX) < BRIDGE_SIZE || Math.abs((l + i1) - midZ) < BRIDGE_SIZE)) { byte0 = DOME_TYPE; } else if (WATERWORLD && k1 < midY + 4 && d > sphereRadius && (Math.abs((k + j1) - midX) < BRIDGE_SIZE || Math.abs((l + i1) - midZ) < BRIDGE_SIZE)) { byte0 = 0; } else if (WATERWORLD && d > sphereRadius) { byte0 = (byte)Block.waterStill.blockID; } else if (k1 == midY + 1 && d > sphereRadius && (Math.abs((k + j1) - midX) == BRIDGE_SIZE || Math.abs((l + i1) - midZ) == BRIDGE_SIZE)) { byte0 = BRIDGE_RAIL; } } else if (d == sphereRadius) { byte0 = (byte)Block.stone.blockID; } else if (hasLake && biome != BiomeGenBase.desert && d <= lakeRadius) { if (k1 == lakeMidY && biome == BiomeGenBase.icePlains) { byte0 = (byte)Block.ice.blockID; } else if (k1 <= lakeMidY) { byte0 = (byte)(lavaLake ? Block.lavaMoving.blockID : Block.waterMoving.blockID); } } else if (hasLake && k1 < lakeMidY - 1 && biome != BiomeGenBase.desert && d <= lakeEdgeRadius) { byte0 = (byte)(lavaLake ? Block.gravel.blockID : Block.sand.blockID); } else if (d < sphereRadius) { if (k1 == midY) { byte0 = biome.topBlock; } else if (k1 == midY - 1) { byte0 = biome.fillerBlock; } else { byte0 = (byte)Block.stone.blockID; } } else if (k1 == midY && d > sphereRadius && (Math.abs((k + j1) - midX) < BRIDGE_SIZE + 1 || Math.abs((l + i1) - midZ) < BRIDGE_SIZE + 1)) { byte0 = BRIDGE_SUPPORT; } else if (WATERWORLD && d > sphereRadius) { byte0 = (byte)Block.waterStill.blockID; } if (d1 <= (double)scaledSpecial) { int i2 = rndSphere.nextInt(200); int j2 = Block.stone.blockID; if (i2 < 1) { j2 = Block.oreDiamond.blockID; } else if (i2 < 2) { j2 = Block.oreLapis.blockID; } byte0 = (byte)j2; } abyte0[l1] = byte0; } } } } public static final double getInverseDistance(double d, double d1, double d2, double d3, double d4, double d5) { return Math.sqrt(-Math.pow(d4 - d1, 2D) + Math.pow(d3 - d, 2D) + Math.pow(d5 - d2, 2D)); } public static final double getDistance(double d, double d1, double d2, double d3, double d4, double d5) { return Math.sqrt(Math.pow(d4 - d1, 2D) + Math.pow(d3 - d, 2D) + Math.pow(d5 - d2, 2D)); } /** * loads or generates the chunk at the chunk location specified */ public Chunk loadChunk(int i, int j) { return provideChunk(i, j); } /** * Will return back a chunk, if it doesn't exist and its not a MP client it will generates all the blocks for the * specified chunk from the map seed and chunk seed */ public Chunk provideChunk(int i, int j) { setRand(i, j); byte abyte0[] = new byte[32768 * (EXPLOITBUG ? 2 : 1)]; preGenerateChunk(i, j, abyte0); caveGen.generate(this, world, i, j, abyte0); Chunk chunk = new Chunk(world, abyte0, i, j); chunk.generateSkylightMap(); return chunk; } /** * Checks to see if a chunk exists at x, y */ public boolean chunkExists(int i, int j) { return true; } /** * Populates chunk with ores etc etc */ public void populate(IChunkProvider ichunkprovider, int i, int j) { BlockSand.fallInstantly = true; int k = i << 4; int l = j << 4; biome = world.getWorldChunkManager().getBiomeGenAt(k, l); rndSphere.setSeed(world.getSeed()); long l1 = (rndSphere.nextLong() / 2L) * 2L + 1L; long l2 = (rndSphere.nextLong() / 2L) * 2L + 1L; rndSphere.setSeed((long)i * l1 + (long)j * l2 ^ world.getSeed()); for (int i1 = 0; i1 < 10; i1++) { int i5 = k + rndSphere.nextInt(16); int l9 = rndSphere.nextInt(128); int i14 = l + rndSphere.nextInt(16); (new WorldGenClay(4)).generate(world, rndSphere, i5, l9, i14); } for (int j1 = 0; j1 < 20; j1++) { int j5 = k + rndSphere.nextInt(16); int i10 = rndSphere.nextInt(128); int j14 = l + rndSphere.nextInt(16); (new WorldGenMinable(Block.oreCoal.blockID, 16)).generate(world, rndSphere, j5, i10, j14); } for (int k1 = 0; k1 < 20; k1++) { int k5 = k + rndSphere.nextInt(16); int j10 = rndSphere.nextInt(128); int k14 = l + rndSphere.nextInt(16); (new WorldGenMinable(Block.oreIron.blockID, 8)).generate(world, rndSphere, k5, j10, k14); } for (int i2 = 0; i2 < 2; i2++) { int l5 = k + rndSphere.nextInt(16); int k10 = rndSphere.nextInt(128); int l14 = l + rndSphere.nextInt(16); (new WorldGenMinable(Block.oreGold.blockID, 8)).generate(world, rndSphere, l5, k10, l14); } for (int j2 = 0; j2 < 8; j2++) { int i6 = k + rndSphere.nextInt(16); int l10 = rndSphere.nextInt(128); int i15 = l + rndSphere.nextInt(16); (new WorldGenMinable(Block.oreRedstone.blockID, 7)).generate(world, rndSphere, i6, l10, i15); } int k4 = biome.biomeDecorator.treesPerChunk; if (rndSphere.nextInt(10) == 0) { k4++; } for (int k2 = 0; k2 < k4; k2++) { int j6 = k + rndSphere.nextInt(16) + 8; int j15 = l + rndSphere.nextInt(16) + 8; WorldGenerator worldgenerator = biome.getRandomWorldGenForTrees(rndSphere); worldgenerator.setScale(1.0D, 1.0D, 1.0D); worldgenerator.generate(world, rndSphere, j6, world.getHeightValue(j6, j15), j15); } for (int i3 = 0; i3 < 2; i3++) { int k6 = k + rndSphere.nextInt(16) + 8; int i11 = rndSphere.nextInt(128); int k15 = l + rndSphere.nextInt(16) + 8; (new WorldGenFlowers(Block.plantYellow.blockID)).generate(world, rndSphere, k6, i11, k15); } if (rndSphere.nextInt(2) == 0) { int l6 = k + rndSphere.nextInt(16) + 8; int j11 = rndSphere.nextInt(128); int l15 = l + rndSphere.nextInt(16) + 8; (new WorldGenFlowers(Block.plantRed.blockID)).generate(world, rndSphere, l6, j11, l15); } if (rndSphere.nextInt(4) == 0) { int i7 = k + rndSphere.nextInt(16) + 8; int k11 = rndSphere.nextInt(128); int i16 = l + rndSphere.nextInt(16) + 8; (new WorldGenFlowers(Block.mushroomBrown.blockID)).generate(world, rndSphere, i7, k11, i16); } if (rndSphere.nextInt(8) == 0) { int j7 = k + rndSphere.nextInt(16) + 8; int l11 = rndSphere.nextInt(128); int j16 = l + rndSphere.nextInt(16) + 8; (new WorldGenFlowers(Block.mushroomRed.blockID)).generate(world, rndSphere, j7, l11, j16); } if (TALLGRASS) { int l4 = biome.biomeDecorator.grassPerChunk; for (int j3 = 0; j3 < l4; j3++) { byte byte0 = 1; if (biome == BiomeGenBase.desert && rndSphere.nextInt(3) != 0) { byte0 = 2; } int k7 = k + rndSphere.nextInt(16) + 8; int i12 = rndSphere.nextInt(128); int k16 = l + rndSphere.nextInt(16) + 8; (new WorldGenTallGrass(Block.tallGrass.blockID, byte0)).generate(world, rndSphere, k7, i12, k16); } } for (int k3 = 0; k3 < 20; k3++) { int l7 = k + rndSphere.nextInt(16) + 8; int j12 = rndSphere.nextInt(128); int l16 = l + rndSphere.nextInt(16) + 8; (new WorldGenReed()).generate(world, rndSphere, l7, j12, l16); } if (rndSphere.nextInt(32) == 0) { int i8 = k + rndSphere.nextInt(16) + 8; int k12 = rndSphere.nextInt(128); int i17 = l + rndSphere.nextInt(16) + 8; (new WorldGenPumpkin()).generate(world, rndSphere, i8, k12, i17); } if (biome == BiomeGenBase.desert) { for (int l3 = 0; l3 < rndSphere.nextInt(5); l3++) { int j8 = k + rndSphere.nextInt(16) + 8; int l12 = midY; int j17 = l + rndSphere.nextInt(16) + 8; (new WorldGenCactus()).generate(world, rndSphere, j8, l12, j17); } } else if (biome == BiomeGenBase.hell) { if (rndSphere.nextBoolean()) { int k8 = k + rndSphere.nextInt(16) + 8; int i13 = midY; int k17 = l + rndSphere.nextInt(16) + 8; (new WorldGenFire()).generate(world, rndSphere, k8, i13, k17); } } else if (biome == BiomeGenBase.mushroomIsland) { for (int i4 = 0; i4 < 2; i4++) { int l8 = k + rndSphere.nextInt(16) + 8; int l17 = l + rndSphere.nextInt(16) + 8; (new WorldGenBigMushroom()).generate(world, rndSphere, l8, world.getHeightValue(l8, l17), l17); } for (int j4 = 0; j4 < 1; j4++) { if (rndSphere.nextInt(4) == 0) { int i9 = k + rndSphere.nextInt(16) + 8; int i18 = l + rndSphere.nextInt(16) + 8; int j13 = world.getHeightValue(i9, i18); (new WorldGenFlowers(Block.plantYellow.blockID)).generate(world, rndSphere, i9, j13, i18); } if (rndSphere.nextInt(8) == 0) { int j9 = k + rndSphere.nextInt(16) + 8; int j18 = l + rndSphere.nextInt(16) + 8; int k13 = rndSphere.nextInt(128); (new WorldGenFlowers(Block.plantRed.blockID)).generate(world, rndSphere, j9, k13, j18); } } } else if (biome == BiomeGenBase.taiga || biome == BiomeGenBase.icePlains) { setNoise(i, j); for (int k18 = 0; k18 < 16; k18++) { for (int k9 = 0; k9 < 16; k9++) { midY = getSurfaceLevel(k9, k18); int l18 = k9 + k; int i19 = k18 + l; int l13 = midY + 1; double d = getMainDistance(l18, midY, i19); if (d <= sphereRadius && world.isBlockHydratedDirectly(l18, l13, i19)) { world.setBlockAndMetadata(l18, l13, i19, Block.blockSnow.blockID, 0); } } } } if (!EXPLOITBUG) { SpawnerAnimals.performWorldGenSpawning(world, biome, k + 8, l + 8, 16, 16, rndSphere); } BlockSand.fallInstantly = false; } /** * Two modes of operation: if passed true, save all Chunks in one go. If passed false, save up to two chunks. * Return true if all chunks have been saved. */ public boolean saveChunks(boolean flag, IProgressUpdate iprogressupdate) { return true; } /** * Unloads the 100 oldest chunks from memory, due to a bug with chunkSet.add() never being called it thinks the list * is always empty and will not remove any chunks. */ public boolean unload100OldestChunks() { return false; } /** * Returns if the IChunkProvider supports saving. */ public boolean canSave() { return true; } /** * Converts the instance data to a readable string. */ public String makeString() { return "RandomLevelSource"; } /** * Returns a list of creatures of the specified type that can spawn at the given location. */ public List getPossibleCreatures(EnumCreatureType enumcreaturetype, int i, int j, int k) { BiomeGenBase biomegenbase = world.getBiomeGenForCoords(i, k); if (biomegenbase == null) { return null; } else { return biomegenbase.getSpawnableList(enumcreaturetype); } } /** * Returns the location of the closest structure of the specified type. If not found returns null. */ public ChunkPosition findClosestStructure(World world1, String s, int i, int j, int k) { return null; } static { BiomeGenBase.hell.topBlock = BiomeGenBase.hell.fillerBlock = (byte)Block.netherrack.blockID; BiomeGenBase.sky.topBlock = BiomeGenBase.sky.fillerBlock = (byte)Block.whiteStone.blockID; byte byte0 = 20; boolean flag = true; boolean flag1 = true; boolean flag2 = true; boolean flag3 = false; boolean flag4 = false; int i = 9; int j = 7; int k = 24; int l = 2; byte byte1 = 5; byte byte2 = 85; try { cfgfile.getParentFile().mkdirs(); if (cfgfile.exists() || cfgfile.createNewFile()) { Properties properties = new Properties(); if (cfgfile.canRead()) { FileInputStream fileinputstream = new FileInputStream(cfgfile); properties.load(fileinputstream); byte0 = Byte.parseByte(properties.getProperty("dome", "20")); flag = Boolean.parseBoolean(properties.getProperty("noise", "true")); flag1 = Boolean.parseBoolean(properties.getProperty("enabled", "true")); flag2 = Boolean.parseBoolean(properties.getProperty("tall_grass", "true")); flag3 = Boolean.parseBoolean(properties.getProperty("water_world", "false")); flag4 = Boolean.parseBoolean(properties.getProperty("exploit_bug", "false")); i = Integer.parseInt(properties.getProperty("grid", "9")); j = Integer.parseInt(properties.getProperty("special", "7")); k = Integer.parseInt(properties.getProperty("lavaLevel", "24")); l = Integer.parseInt(properties.getProperty("bridge_size", "2")); byte1 = Byte.parseByte(properties.getProperty("bridge_support", "5")); byte2 = Byte.parseByte(properties.getProperty("bridge_rail", "85")); for (Iterator iterator = BiosphereWeather.biomeList.iterator(); iterator.hasNext();) { BiomeEntry biomeentry = (BiomeEntry)iterator.next(); biomeentry.itemWeight = Integer.parseInt(properties.getProperty((new StringBuilder("weight_")).append(biomeentry.biome.biomeName).toString(), Integer.toString(biomeentry.itemWeight))); } fileinputstream.close(); } if (cfgfile.canWrite()) { FileOutputStream fileoutputstream = new FileOutputStream(cfgfile); properties.setProperty("dome", Byte.toString(byte0)); properties.setProperty("noise", Boolean.toString(flag)); properties.setProperty("enabled", Boolean.toString(flag1)); properties.setProperty("tall_grass", Boolean.toString(flag2)); properties.setProperty("water_world", Boolean.toString(flag3)); properties.setProperty("exploit_bug", Boolean.toString(flag4)); properties.setProperty("grid", Integer.toString(i)); properties.setProperty("special", Integer.toString(j)); properties.setProperty("lavaLevel", Integer.toString(k)); properties.setProperty("bridge_size", Integer.toString(l)); properties.setProperty("bridge_support", Byte.toString(byte1)); properties.setProperty("bridge_rail", Byte.toString(byte2)); BiomeEntry biomeentry1; for (Iterator iterator1 = BiosphereWeather.biomeList.iterator(); iterator1.hasNext(); properties.setProperty((new StringBuilder("weight_")).append(biomeentry1.biome.biomeName).toString(), Integer.toString(biomeentry1.itemWeight))) { biomeentry1 = (BiomeEntry)iterator1.next(); } properties.store(fileoutputstream, "Biosphere Config"); fileoutputstream.close(); } } } catch (Throwable throwable) { } DOME_TYPE = byte0; NOISE = flag; ENABLED = flag1; TALLGRASS = flag2; WATERWORLD = flag3; EXPLOITBUG = flag4; GRID_SIZE = i; SPECIAL_RADIUS = j; LAVA_LEVEL = k; BRIDGE_SIZE = l; BRIDGE_SUPPORT = byte1; BRIDGE_RAIL = byte2; if (WATERWORLD) { Block.lightOpacity[8] = 0; Block.lightOpacity[9] = 0; } } } I know it doesn't have the population/ore sphere blocks, but it's a general idea of how complicated it is. Thanks!
God how I miss this. http://forums.bukkit.org/threads/inactive-wgen-sphereworld-v0-5-creates-a-world-of-spheres-953.18557/
It is possible. Using the BOB2 plugins you create each sphere and add them into a biome. Change that to the only biome generated and huzzah
OK, sounds great! Don't suppose you could do a tutorial on it...? That looks perfect! Only problem is that it is extremely outdated (and lacks a bridge)- do you think you might be able to pull off those changes? If not, any idea who could? Thanks!
Heck, I'm getting desperate. I know it isn't much, but would $5 upon completion be a good reward? I'd of course give all credit to you.
The code is already written, just need someone to port it over. I already have it open in Eclipse, and all files can be provided if requested...