Give darkfrog developer status?

Contrary to what monkeys may think, frogs can be useful creatures and provide to the community to.  To that end I am formally requesting developer status on finally on jME.  I've been here for quite a while and apart from my off-color sense of humor have tried to help in any way I can.  I am to the point where I've amassed a BUNCH of code that I've written as helper classes and such that I'm ready to start contributing back and instead of just filling to forums with thousands of lines of code I thought it would be easier to get developer status and then I can instead fill CVS with thousands of lines of code. :-p



Most of the code I have at this point to contribute back has to do with GameStates and transitions.  In the long-run I think I would also like to add some convenience features for networking, but that's a little bit bigger decision that will have to be discussed at lenght I'm sure. :-p



darkfrog

NO. then instead of polluting the forums you would pollute the cvs.  :wink:

just kidding. somebody just has to check from time to time that the monkey logo doesn't get replaced by the frog logo. i know that that's your long term plan and that you want to take over jme and rule the world.



[actually i have absolutely nothing against you having cvs access. but i just had to formally be against it. couldn't help myself]

lets be serious about this guys

The frog can't even keep JGN free of pollution, do we really trust him with JME?



(but off the record i would like to see darky have developer status… just don't tell him i said that)

shhhhh. keep quiet!

Bwahaha…someday the frog logo will find it's place!!!



…sorry, was that out loud?  :roll:



No, of course I would not do something like that…it would be beyond inappropriate (and really REALLY funny!). :-p



Pollution in JGN…what are you talking about?  JGN is the essence of beautification in API design.  :slight_smile: …oh right…I got ya, because I let you talk on the forums…yeah, but a certain amount of pollution is necessary to truly be free. :o



Uh oh…I've got one negatory vote. :(  I promise I won't just stick JGN into jME. :-p



darkfrog

It might keep him away from the forums a bit, so I voted yes :smiley:

Llama, I just assumed you were one of the negative votes. :-p



I know how much llamas hate frogs.



darkfrog

Ok, one requirement if you gain dev access is enough with the frog jokes. God help me.

give him the cvs only if he agrees to a forum filter which removes the word "frog" from the forums.



(and was a positive vote!)

heck!



I was coming here only to read the froggy nature of his posts and now you want to remove all the fun??



Sure you'd prefer he stays with his frogs, just wait till he starts those neurons to play with the monkeys…monkeys jokes all day…every minute…you'll see that monkey logo everyday with such a pain and suffering…



What is more, you will start change the animal mascot every day, and he will continue adopting it as his new loved type of creature…You can't beat him…he's just more resistant :smiley:



He never abandones his frog soul, he just takes new forms.

mojo, I can promise to cut-back…not sure if I could stop entirely…the others encourage me, so it's not entirely my fault. :-p



snaga, I think you've gone off into the deep end.  :-o



darkfrog

There are a few no votes, as such, I think you should post a couple of the things that you wish to contribute, to show the quality of work you would add. People can then discuss the code itself.

Fair enough.



The following is the ManagedGameState I've been using to offer a bit of extended functionality over the standard GameState:


/*
 * Created on Jan 25, 2006
 */
package com.captiveimagination.jme;

import com.jme.app.*;
import com.jme.input.*;
import com.jme.scene.*;
import com.jme.scene.state.*;
import com.jme.system.*;
import com.jmex.physics.*;

/**
 * @author Matthew D. Hicks
 */
public abstract class ManagedGameState extends GameState {
    private static int gameStatesCounter = 0;
   
    protected Node rootNode;
    protected InputHandler input;
   
    private boolean firstUpdate;
   
    public ManagedGameState() {
        rootNode = new Node("ManagedGameStateRoot" + nextIncrement());
       
        // Create ZBuffer for depth
        ZBufferState zbs = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
        zbs.setEnabled(true);
        zbs.setFunction(ZBufferState.CF_LEQUAL);
        rootNode.setRenderState(zbs);
        input = new InputHandler();
        firstUpdate = true;
    }

    public abstract void managedInit();
   
    public abstract void managedInitMaterial();
   
    public void update(float tpf) {
        if (firstUpdate) {
            managedInit();
            if (isClientMode()) {
                managedInitMaterial();
            }
            rootNode.updateRenderState();
            rootNode.updateWorldBound();
            rootNode.updateGeometricState(0.0f, true);
            firstUpdate = false;
        }
        managedUpdate(tpf);
        input.update(tpf);
        rootNode.updateGeometricState(tpf, true);
    }
   
    public void managedUpdate(float tpf) {
    }

    public void render(float tpf) {
        DisplaySystem.getDisplaySystem().getRenderer().draw(rootNode);
        managedRender(tpf);
    }
   
    public void managedRender(float tpf) {
    }

    public void cleanup() {
        managedCleanup();
    }
   
    public void managedCleanup() {
    }

    public void setActive(boolean active) {
        this.active = active;
        if (active) {
            managedEnable();
        } else {
            managedDisable();
        }
    }
   
    public void managedEnable() {
    }
   
    public void managedDisable() {
    }
   
    public boolean isServerMode() {
        return GameManager.getGameManager().getSettings().isMode(GameSettings.MODE_SERVER);
    }
   
    public boolean isClientMode() {
        return GameManager.getGameManager().getSettings().isMode(GameSettings.MODE_CLIENT);
    }
   
    public InputHandler getInputHandler() {
        return input;
    }
   
    private synchronized static int nextIncrement() {
        return gameStatesCounter++;
    }
}



In addition to that I have a TransitionGameState for transitioning between two states:

/*
 * Created on Jan 25, 2006
 */
package com.captiveimagination.jme;

import java.net.*;

import javax.swing.*;

import com.jme.app.*;
import com.jme.system.*;
import com.jmex.awt.swingui.*;

/**
 * @author Matthew D. Hicks
 */
public class TransitionGameState extends ManagedGameState {
    private GameState start;
    private GameState end;
    private float timeInSeconds;
    private URL image;
       
    private Fader fader;
    private JLabel label;
    private int state;
   
    private boolean exitAfterFinish;
   
    private TransitionGameState(GameState start, GameState end, float timeInSeconds, URL image) {
        this.start = start;
        this.end = end;
        this.timeInSeconds = timeInSeconds;
        this.image = image;
    }
   
    public void managedInit() {
        fader = new Fader("Fader", DisplaySystem.getDisplaySystem().getWidth(), DisplaySystem.getDisplaySystem().getHeight(), timeInSeconds);
        rootNode.attachChild(fader);
    }
   
    public void managedInitMaterial() {
    }
   
    public void setExitAfterFinish(boolean exitAfterFinish) {
        this.exitAfterFinish = exitAfterFinish;
    }
   
    public void managedUpdate(float tpf) {
        if (state == 0) {               // Begin fade-out
            if (start == null) {
                state = 2;
            } else {
                fader.setMode(Fader.FADE_OUT);
                fader.setAlpha(0.0f);
                state = 1;
            }
        } else if (state == 1) {        // After fade-out, disable game 1
            if (fader.getAlpha() == 1.0f) {
                start.setActive(false);
                GameStateManager.getInstance().detachChild(start);
                state = 2;
            }
        } else if (state == 2) {        // Display the image, if there is one
            displayImage();
            state = 3;
        } else if (state == 3) {        // Load game 2 and add to manager
            if (end != null) {
                end.setActive(true);
                GameStateManager.getInstance().attachChild(end);
                state = 4;
            } else {
                fader.setMode(Fader.FADE_IN);
                fader.setAlpha(0.0f);
                state = 6;
            }
        } else if (state == 4) {        //start fade-in
            fader.setMode(Fader.FADE_IN);
            fader.setAlpha(1.0f);
            state = 5;
        } else if (state == 5) {        // Remove image
            removeImage();
            state = 6;
        } else if (state == 6) {        // After fade-in, remove transition game
            if (fader.getAlpha() == 0.0f) {
                setActive(false);
                GameStateManager.getInstance().detachChild(this);
                state = 7;
                if (exitAfterFinish) {
                    GameManager.getGameManager().finish();
                }
            }
        } else {
            System.out.println("Unknown state: " + state);
        }
    }
   
    private void displayImage() {
        if (image != null) {
            JMEDesktop desktop = GameManager.getGameManager().getDesktop();
            label = new JLabel(new ImageIcon(image));
            label.setSize(label.getPreferredSize());
            desktop.getJDesktop().add(label);
            int x = (desktop.getJDesktop().getSize().width / 2) - (label.getSize().width / 2);
            int y = (desktop.getJDesktop().getSize().height / 2) - (label.getSize().height / 2);
            label.setLocation(x, y);
        }
    }
   
    private void removeImage() {
        JMEDesktop desktop = GameManager.getGameManager().getDesktop();
        label.setVisible(false);
        desktop.getJDesktop().remove(label);
        label = null;
    }
   
    public static void transitionGameStates(GameState start, GameState end, float timeInSeconds, URL image) {
        TransitionGameState tgs = new TransitionGameState(start, end, timeInSeconds, image);
        tgs.setActive(true);
        GameStateManager.getInstance().attachChild(tgs);
    }
   
    public static void transitionToExit(GameState start, float timeInSeconds) {
        TransitionGameState tgs = new TransitionGameState(start, null, timeInSeconds, null);
        tgs.setActive(true);
        tgs.setExitAfterFinish(true);
        GameStateManager.getInstance().attachChild(tgs);
    }
}



Now a lot of this still needs to be changed and I have been thinking I would make it fit a little better with jME directly instead of what I currently have which is essentially just an extending API.  There's a lot of other things I have that I plan on introducing, but I've been sort of holding out on the actual integration process to see if I get access. :-p

Also, there is a lot of direct ties to physics that needs to be removed.  This code was designed to work directly with jME and jME-Physics, which obviously would not work well directly in jME.

I'm happy to post more if necessary, just let me know.

darkfrog

Okay, apparently there's a 20,000 character limitation in posting that I tried to exceed, so here's the other piece I tried to post:



Finally, the GameManager that allows a much better handle on the standard game from which all gamestates exist:


/*
 * Created on Jan 25, 2006
 */
package com.captiveimagination.jme;

import java.awt.*;
import java.util.*;

import com.jme.app.*;
import com.jme.image.*;
import com.jme.input.*;
import com.jme.math.*;
import com.jme.renderer.*;
import com.jme.scene.*;
import com.jme.scene.state.*;
import com.jme.system.*;
import com.jme.util.*;
import com.jme.util.Timer;
import com.jmex.awt.swingui.*;
import com.jmex.model.XMLparser.Converters.*;
import com.jmex.physics.*;
import com.jmex.physics.contact.*;
import com.jmex.physics.effects.*;
import com.jmex.sound.openAL.*;

/**
 * This is the foundational root that all games can be built from.
 *
 * @author Matthew D. Hicks
 */
public class GameManager extends AbstractGame implements Runnable {
    private static GameManager instance;
    private static String fontLocation = "/com/jme/app/defaultfont.tga";
   
    public static final int STATUS_STARTUP = 1;
    public static final int STATUS_INIT_SYSTEM = 2;
    public static final int STATUS_INIT_GAME = 3;
    public static final int STATUS_MAIN_LOOP = 4;
    public static final int STATUS_CLEANUP = 5;
    public static final int STATUS_QUIT = 6;
    public static final int STATUS_FINISHED = 7;
   
    private Thread gameThread;
   
    private String title;
    private GameSettings settings;
    private boolean settingsChanged;
    private Timer timer;
    private float tpf;
    private Text fps;
    private Node fpsNode;
    private Node guiNode;
    private JMEDesktop desktop;
    private InputHandler guiInput;
    private boolean mouseCursorVisible;
    private int status;
    private PhysicsCollisionResults collisionResults;
   
    private Camera camera;
   
    public GameManager(String title) {
        this(title, new GameSettings());
    }
   
    public GameManager(String title, GameSettings settings) {
        this.title = title;
        this.settings = settings;
        status = STATUS_STARTUP;
        instance = this;
    }
   
    /**
     * Sets the current visibility of the mouse cursor on the screen.
     *
     * @param mouseCursorVisible
     */
    public void setMouseCursorVisibility(boolean mouseCursorVisible) {
        this.mouseCursorVisible = mouseCursorVisible;
    }
   
    /**
     * The current status of the game
     *
     * @return
     *      STATUS_STARTUP,
     *      STATUS_INIT_SYSTEM,
     *      STATUS_INIT_GAME,
     *      STATUS_MAIN_LOOP,
     *      STATUS_CLEANUP,
     *      STATUS_QUIT,
     *      or STATUS_FINISHED
     */
    public int getStatus() {
        return status;
    }
   
    /**
     * @return
     *      The default ortho JMEDesktop created by default
     */
    public JMEDesktop getDesktop() {
        return desktop;
    }
   
    /**
     * @return
     *      The camera for this game
     */
    public Camera getCamera() {
        return camera;
    }
   
    /**
     * @return
     *      The GameSettings object that contains all the current
     *      game settings.
     */
    public GameSettings getSettings() {
        return settings;
    }
   
    /**
     * @return
     *      The input handler for the default ortho JMEDesktop
     */
    public InputHandler getGUIInput() {
        return guiInput;
    }
   
    /**
     * This simply resets the camera's position
     */
    public void resetCamera() {
        camera.setLocation(new Vector3f(0.0f, 0.0f, 50.0f));
        camera.setUp(new Vector3f(0.0f, 1.0f, 0.0f));
        camera.setLeft(new Vector3f(-1.0f, 0.0f, 0.0f));
        camera.setDirection(new Vector3f(0.0f, 0.0f, -1.0f));
        camera.update();
    }
   
    /**
     * @param name
     * @return
     *      Returns the physics object named <code>name</code>.
     */
    public PhysicsObject getPhysicsObject(String name) {
        ArrayList list = PhysicsWorld.getInstance().getObjects();
        for (int i = 0; i < list.size(); i++) {
            if (((PhysicsObject)list.get(i)).getName().equals(name)) {
                return (PhysicsObject)list.get(i);
            }
        }
        return null;
    }
   
    /**
     * @return
     *      The PhysicsCollisionResults for the current update
     */
    public PhysicsCollisionResults getCollisionResults() {
        return collisionResults;
    }
   
    protected void initSystem() {
        // Add listener to detect when the settings have changed
        settings.addSettingsChangeListener(new SettingsChangeListener() {
            public void settingsChanged() {
                settingsChanged = true;
            }
        });
       
        if (settings.isMode(GameSettings.MODE_CLIENT)) {
            display = DisplaySystem.getDisplaySystem(settings.getRenderer());
            display.setTitle(title);
            display.setMinDepthBits(settings.getMinDepthBits());
            display.setMinStencilBits(settings.getMinStencilBits());
            display.setMinAlphaBits(settings.getMinAlphaBits());
            display.setMinSamples(settings.getMinSamples());
            display.createWindow(settings.getWidth(),
                                 settings.getHeight(),
                                 settings.getDepth(),
                                 settings.getFrequency(),
                                 settings.isFullscreen()
                                );
            display.getRenderer().setBackgroundColor(ColorRGBA.black);
           
            camera = display.getRenderer().createCamera(display.getWidth(), display.getHeight());
            camera.setFrustumPerspective(45.0f, (float)display.getWidth() / (float)display.getHeight(), 1.0f, 1000.0f);
            camera.setParallelProjection(false);
            camera.setFrame(new Vector3f(0.0f, 0.0f, 0.0f),
                    new Vector3f(-1.0f, 0.0f, 0.0f),
                    new Vector3f(0.0f, 1.0f, 0.0f),
                    new Vector3f(0.0f, 0.0f, -1.0f));
            camera.update();
            display.getRenderer().setCamera(camera);
        } else {
            display = new DummyDisplaySystem();
        }
       
        if ((settings.isMusicEnabled()) || (settings.isSoundEnabled())) {
            SoundSystem.init(camera, SoundSystem.OUTPUT_DEFAULT);
        }
    }

    protected void initGame() {
        // Physics initialization
        PhysicsWorld.create();
        PhysicsWorld.getInstance().setUpdateRate(100);
        PhysicsWorld.getInstance().setStepSize(2.0f / 100.0f);
        PhysicsWorld.getInstance().addUpdateAction(RollingFriction.getInstance());
       
        if (settings.isMode(GameSettings.MODE_CLIENT)) {
            // Ortho Desktop
            guiNode = new Node("GUI");
            guiNode.setCullMode(Spatial.CULL_NEVER);
            guiNode.setLightCombineMode(LightState.OFF);
            guiInput = new InputHandler();
            guiInput.setEnabled(false);
            desktop = new JMEDesktop("Desktop", display.getWidth(), display.getHeight(), guiInput);
            desktop.getJDesktop().setName("Desktop");
            desktop.getJDesktop().setBackground(new Color(0.0f, 0.0f, 0.0f, 0.0f));
            desktop.getJDesktop().setOpaque(false);
            guiNode.attachChild(desktop);
            guiNode.getLocalTranslation().set(display.getWidth() / 2, display.getHeight() / 2, 0.0f);
            guiNode.getLocalScale().set(1.0f, 1.0f, 1.0f);
            guiNode.updateRenderState();
            guiNode.updateGeometricState(0.0f, true);
            guiNode.setRenderQueueMode(Renderer.QUEUE_ORTHO);
            guiNode.updateGeometricState(0.0f, true);
            guiNode.updateRenderState();
           
            // Frames Per Second stuff
            AlphaState as = display.getRenderer().createAlphaState();
            as.setBlendEnabled(true);
            as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
            as.setDstFunction(AlphaState.DB_ONE);
            as.setTestEnabled(true);
            as.setTestFunction(AlphaState.TF_GREATER);
            as.setEnabled(true);
            TextureState font = display.getRenderer().createTextureState();
            font.setTexture(
                    TextureManager.loadTexture(GameManager.class.getResource(fontLocation),
                    Texture.MM_LINEAR,
                    Texture.FM_LINEAR));
            font.setEnabled(true);
            fps = new Text("FPS label", "");
            fps.setTextureCombineMode(TextureState.REPLACE);
            fpsNode = new Node("FPS node");
            fpsNode.attachChild(fps);
            fpsNode.setRenderState(font);
            fpsNode.setRenderState(as);
            fpsNode.updateGeometricState(0.0f, true);
            fpsNode.updateRenderState();
        }
       
        GameStateManager.create();
    }

    protected void update(float interpolation) {
        if (settingsChanged) {
            reinit();
            settingsChanged = false;
        }
       
        if (settings.isDebug()) {
            try {
                Thread.sleep(1);
            } catch(InterruptedException exc) {
            }
        }
       
        collisionResults = PhysicsWorld.getInstance().update(interpolation);
       
        GameStateManager.getInstance().update(interpolation);
        if (settings.isMode(GameSettings.MODE_CLIENT)) {
            fps.print(Math.round(timer.getFrameRate()) + " fps");
            guiInput.update(interpolation);
            if ((settings.isMusicEnabled()) || (settings.isSoundEnabled())) {
                SoundSystem.update(interpolation);
            }
            MouseInput.get().setCursorVisible(mouseCursorVisible);
        }
    }

    protected void render(float interpolation) {
        display.getRenderer().clearBuffers();
        GameStateManager.getInstance().render(interpolation);
        display.getRenderer().draw(guiNode);
        display.getRenderer().draw(fpsNode);
    }

    protected void reinit() {
        display.setMinDepthBits(settings.getMinDepthBits());
        display.setMinStencilBits(settings.getMinStencilBits());
        display.setMinAlphaBits(settings.getMinAlphaBits());
        display.setMinSamples(settings.getMinSamples());
        display.recreateWindow(settings.getWidth(),
                               settings.getHeight(),
                               settings.getDepth(),
                               settings.getFrequency(),
                               settings.isFullscreen()
                              );
    }

    protected void cleanup() {
        GameStateManager.getInstance().cleanup();
    }
   
    protected void quit() {
        if (settings.isMode(GameSettings.MODE_CLIENT)) {
            desktop.dispose();
        }
        if (display != null) {
            display.reset();
            display.close();
        }
        // TODO remove this...figure out why MenuDesktopBox is causing it to hang
        System.exit(0);
    }
   
    public void start() {
        gameThread = new Thread(this);
        gameThread.start();
    }
   
    public void run() {
        status = STATUS_INIT_SYSTEM;
        initSystem();
        assertDisplayCreated();
        status = STATUS_INIT_GAME;
        initGame();
       
        if (settings.isMode(GameSettings.MODE_CLIENT)) {
            timer = Timer.getTimer(settings.getRenderer());
        } else {
            timer = new DummyTimer();
        }
        status = STATUS_MAIN_LOOP;
        try {
            while ((!finished) && (!display.isClosing())) {
                timer.update();
                tpf = timer.getTimePerFrame();
               
                if (settings.isMode(GameSettings.MODE_CLIENT)) {
                    InputSystem.update();
                }
                update(tpf);
                render(tpf);
                display.getRenderer().displayBackBuffer();
                Thread.yield();
            }
        } catch(Throwable t) {
            t.printStackTrace();
            System.err.println("Uncaught exception, ending game.");
        }
       
        status = STATUS_CLEANUP;
        cleanup();
        status = STATUS_QUIT;
        quit();
        status = STATUS_FINISHED;
    }
   
    public void waitForStatus(int status) {
        while (this.status < status) {
            try {
                Thread.sleep(1);
            } catch(InterruptedException exc) {
                exc.printStackTrace();
            }
        }
    }
   
    protected void assertDisplayCreated() throws JmeException {
        if (settings.isMode(GameSettings.MODE_CLIENT)) {
            super.assertDisplayCreated();
        }
    }

    public static GameManager getGameManager() {
        return instance;
    }
   
    public static void main(String[] args) throws Exception {
        GameManager gm = new GameManager("Testing");
        gm.start();
        gm.waitForStatus(GameManager.STATUS_MAIN_LOOP);
        GameState menu = new TestGameState();
        menu.setActive(true);
        GameStateManager.getInstance().attachChild(menu);
    }
}

I knew he had a stash he was keeping from us mojo just had to put the squeeze on him to get it out of him.  :smiley:

Fine work you've done.  Could you maybe tell some of things you'd like to go after if you become a developer.

(Don't worry I already voted yes for you)

Darkfrog, if you have self control from updating code on a whim and you have a good working relationship and approval  with the other developers - you have my vote

Patrick, honestly it's more of a convenience thing on both sides I think.  I'm doing game development and as I'm developing if I can add things directly to jME instead of having to create utility classes to supplement the built-in functionality of jME.  It's beneficial to me because it makes my life a little easier, and it's beneficial to the community because I can more easily share my code.



I'm increasing my focus towards game development over the next few months and know I'll have a lot of features that I'd like to contribute.  Obviously developer status doesn't mean I can just cram whatever I want into the project.  I make a lot of jokes but I can be serious on occasion. :-p  I've been a developer on the jME-Physics project for a while and have contributed a few things (such as rolling friction and a lot of javadocs on ODE), but it's generally on an as-needed basis.  I realize one of the obligations of becoming a developer means shared responsibility for bug fixes and releases, but I'm prepared to offer what knowledge I have and it's also a great experience for me to learn more.



I hope that addressed your message as well kidney.



darkfrog

—> my hands up are up  :smiley:

@darkfrog: i don't have anything to object to you getting the developer status. don't get me wrong: i just had to formally be against it :wink: i think it would be great having another active developer. i aplologize if anyone understood that another way.

Sfera, I knew there were at least a few people that couldn't help being against me having developer status purely on principal. :wink:



darkfrog