package okj.easy.core;
import okj.easy.core.Timer.Task;
import okj.easy.core.utils.Bridge;
import okj.easy.core.utils.BridgePool;
import okj.easy.graphics.graphics2d.NWorld;
import okj.easy.screen.LoadingScreen;
import org.ege.utils.E;
import org.ege.utils.EasyNativeLoader;
import org.ege.utils.IActivityHandler;
import org.ege.utils.IDesktopHandler;
import org.ege.utils.exception.EasyGEngineRuntimeException;
import org.ege.widget.Dialog;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.PauseableThread;
/**
* @FileName: GameCore.java
* @CreateOn: Sep 15, 2012 - 11:05:26 AM
* @Author: TrungNT
*/
public abstract class GameCore implements ApplicationListener
{
// ============= Screen mangage =============
/** This screen is the main screen which is visible all time */
protected Screen screen;
/** when the game is call onPause from activity core save it current screen to this reference */
private Screen mSavedScreen;
/** The main loading screen use to load and reload openGL context */
private LoadingScreen mStartScreen;
/**
* This flag show that the game core is come back from pause and now it is resume
* <p>
*
* @True if is on from running turn to onPause
* @False if is on from onPause back to onResume
*/
private boolean isStarted = false;
/** Flag show that the game is pause */
private boolean isPause = false;
private Class<? extends SafeLoader> mDefaultLoader;
// ============= Utils manage =============
private final BridgePool bridgePool;
final IActivityHandler mActivity;
// ============= Schedule code =============
final Timer mSchedulerTimer;
final ThreadManager mThreadManager;
// ============= Runnable for synchoronize schedule =============
final Array<Runnable> runnables = new Array();
final Array<Runnable> executedRunnables = new Array();
/*********************************************************** Constructors ***********************************************************/
public GameCore(IActivityHandler activity)
{
this.mActivity = activity;
bridgePool = new BridgePool(13);
Bridge.registerRecyleListener(bridgePool);
mSchedulerTimer = new Timer();
mThreadManager = new ThreadManager();
}
public GameCore()
{
this(new IDesktopHandler());
}
// ============= default loader method =============
/**
* The safe loader is use to change screen in safe mode when you not sure all contexts are
* loaded
*
* @param yourSafeLoader
*/
public void setDefaultSafeLoader (Class<? extends SafeLoader> yourSafeLoader)
{
mDefaultLoader = yourSafeLoader;
}
/************************************************************** ApplicationListener methods **************************************************************/
@Override
public void create ()
{
eAdmin.egame = GameCore.this;
eAdmin.einput = new eInput();
eAdmin.egraphics = new eGraphics();
eAdmin.eaudio = new eAudio();
eAdmin.econtext = new eContext();
Screen.setCoreProcessor(this);
Screen.batch = new SpriteBatch();
Screen.layout = null;
EasyNativeLoader.load();
mSchedulerTimer.reset();
Gdx.input.setInputProcessor(eAdmin.einput);
Dialog.DIALOG_NUMBER = 0;
onGameConfig();
}
protected void CreateNativeWorld (int size_of_NSprite, int size_of_NSpriteA)
{
eAdmin.eworld = new NWorld(size_of_NSprite, size_of_NSpriteA);
}
@Override
public void resize (int width, int height)
{
eAdmin.egraphics.resolve(width, height);
if (screen != null)
screen.resize(width, height);
onGameChanged(width, height);
}
private float delta;
@Override
public void render ()
{
if (isPause)
return;
// ============= Start schedule =============
synchronized (runnables) {
executedRunnables.clear();
executedRunnables.addAll(runnables);
runnables.clear();
for (int i = 0; i < executedRunnables.size; i++) {
try {
executedRunnables.get(i).run();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
// ============= Update screen =============
delta = Gdx.graphics.getDeltaTime();
if (screen != null) {
screen.onRender(delta);
screen.update(delta);
}
onGameRender(delta);
}
@Override
public void pause ()
{
isPause = true;
onGamePause();
// stop scheduler
mSchedulerTimer.stop();
// save context if you want to reload
isStarted = false;
mSavedScreen = screen;
// call pause
if (screen != null)
screen.pause();
}
@Override
public void resume ()
{
isPause = false;
onGameResume();
// reload context
if (!isStarted) {
screen = mStartScreen;
mStartScreen.setChangedScreenListener(new LoadingScreen.OnChangedScreen()
{
@Override
public Screen screenChanged ()
{
// re-start schedule
mSchedulerTimer.start();
return mSavedScreen;
}
});
mStartScreen.show();
mStartScreen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
isStarted = true;
return;
}
}
@Override
public void dispose ()
{
if (screen != null)
screen.destroy(E.screen.RELEASE);
isStarted = false;
onGameDestroy();
this.bridgePool.clear();
runnables.clear();
executedRunnables.clear();
eAdmin.eworld.dispose();
}
/************************************************************** Main GameCore methods **************************************************************/
/** Config all game components */
protected abstract void onGameConfig ();
/**
* Listen to surface size
*
* @param width
* the screen width
* @param height
* the screen height
*/
protected abstract void onGameChanged (int width, int height);
/**
* Render all stuff here
*
* @param DeltaTime
* the time each frame repeat
*/
protected abstract void onGameRender (float delta);
/** Your pause stuff here ,such as: save your preferences */
public abstract void onGamePause ();
/** This method do the same function as resume */
protected abstract void onGameResume ();
/** This method will release memory */
protected abstract void onGameDestroy ();
/********************************************** Screen changing methods **********************************************/
private boolean isLoading = false;
protected void setStartScreen (LoadingScreen loadScreen)
{
if (isStarted)
throw new EasyGEngineRuntimeException("One GameCore cant set start screen twice");
this.mStartScreen = loadScreen;
setScreen(loadScreen, E.screen.RELEASE);
isStarted = true;
}
/**
* Set the current screen to the new screen
*
* @param screen
* new Screen
* @param destroyMode
* destroyMode of old Screen
*/
void setScreen (Screen screen, int destroyMode)
{
/*
* check if the current screen is the loading screen , if is the loading screen the show of
* next screen method only call for
* the first time load
*/
isLoading = (this.screen instanceof LoadingScreen);
if (isLoading)
isLoading = isLoading & !((LoadingScreen) this.screen).isFirstTimeLoad();
if (this.screen != null)
this.screen.destroy(destroyMode);
this.screen = screen;
if (this.screen != null) {
if (!isLoading)
screen.show();
else
mSavedScreen.resume();
screen.resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
}
void setScreen (Screen screen, ResourceContext... contexts)
{
final ResourcePack pack = new ResourcePack(SafeLoader.name, contexts);
pack.setRefStoreMode(false);
if (pack.isTotallyLoaded()) {
setScreen(screen, E.screen.RELEASE);
return;
}
if (mDefaultLoader == null)
throw new EasyGEngineRuntimeException("The default safe loader is null");
SafeLoader loader;
try {
loader = mDefaultLoader.newInstance();
loader.enableSafeMode(screen, pack);
setScreen(loader, E.screen.RELEASE);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
void setScreen (Screen screen, ResourcePack pack)
{
pack.setRefStoreMode(false);
if (pack.isTotallyLoaded()) {
setScreen(screen, E.screen.RELEASE);
return;
}
if (mDefaultLoader == null)
throw new EasyGEngineRuntimeException("The default safe loader is null");
SafeLoader loader;
try {
loader = mDefaultLoader.newInstance();
loader.enableSafeMode(screen, pack);
setScreen(loader, E.screen.RELEASE);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public Screen getCurrentScreen ()
{
return screen;
}
/************************************************************** Bridge Manage method **************************************************************/
public Bridge newBridge (Class<?> firstClass, Class<?> secondClass)
{
Bridge tmp = getBridge(firstClass, secondClass);
if (tmp == null)
return this.bridgePool.obtain(firstClass, secondClass);
return tmp;
}
public Bridge newBridge (String name)
{
Bridge tmp = getBridge(name);
if (tmp == null)
return this.bridgePool.obtain(name);
return tmp;
}
private Bridge getBridge (Class<?> firstClass, Class<?> secondClass)
{
return bridgePool.getUsingBridges().get(firstClass.getName() + secondClass.getName());
}
private Bridge getBridge (String name)
{
return bridgePool.getUsingBridges().get(name);
}
/************************************************************** Activity handler methods **************************************************************/
public IActivityHandler getActivity ()
{
return mActivity;
}
public boolean isBindActivity ()
{
return mActivity == null;
}
/************************************************************** Schedule method for timer **************************************************************/
public void postTask (Task task)
{
mSchedulerTimer.postTask(task);
}
public void schedule (Task task)
{
mSchedulerTimer.scheduleTask(task);
}
public void schedule (Task task, float delaySeconds)
{
mSchedulerTimer.scheduleTask(task, delaySeconds);
}
public void schedule (Task task, float delaySeconds, float intervalSeconds)
{
mSchedulerTimer.scheduleTask(task, delaySeconds, intervalSeconds);
}
public void schedule (Task task, float delaySeconds, float intervalSeconds, int repeatCount)
{
mSchedulerTimer.scheduleTask(task, delaySeconds, intervalSeconds, repeatCount);
}
public void stopScheduler ()
{
mSchedulerTimer.stop();
}
public void startScheduler ()
{
mSchedulerTimer.start();
}
public void clearScheduler ()
{
mSchedulerTimer.clear();
}
public void removeTask (Task task)
{
mSchedulerTimer.removeTask(task);
}
public void postRunnable (Runnable runnable)
{
synchronized (runnables) {
runnables.add(runnable);
Gdx.graphics.requestRendering();
}
}
/************************************************************** Thread manager **************************************************************/
public int newThreadId (Runnable runnable)
{
return mThreadManager.obtainForID(runnable);
}
public PauseableThread newThread (Runnable runnable)
{
return mThreadManager.obtainForThread(runnable);
}
public boolean startThread (int id)
{
return mThreadManager.startThread(id);
}
public boolean stopThread (int id)
{
return mThreadManager.stopThread(id);
}
/**
* Pause a given thread which have your id
*
* @param id
* @return true if successful pause , otherwise false
*/
public boolean pauseThread (int id)
{
return mThreadManager.pauseThread(id);
}
/**
* Resume a given thread which have your id
*
* @param id
* @return true if successful resume , otherwise false
*/
public boolean resumeThread (int id)
{
return mThreadManager.resumeThread(id);
}
public boolean containThread (int id)
{
return mThreadManager.containThread(id);
}
public boolean containThread (PauseableThread thread)
{
return mThreadManager.containThread(thread);
}
public int sizeOfThread ()
{
return mThreadManager.size();
}
public int sizeOfRunningThread ()
{
return mThreadManager.sizeOfAlive();
}
}