mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-04-28 06:15:07 -06:00
401 lines
12 KiB
C++
401 lines
12 KiB
C++
#include <jni.h>
|
|
#include <android/log.h>
|
|
#include <android/asset_manager.h>
|
|
#include <android/asset_manager_jni.h>
|
|
#include <sys/stat.h>
|
|
#include "game/sdl/hosthelpers.h"
|
|
#include "base/thread.h"
|
|
#include "game/sdl/sdlhttpservice.h"
|
|
#include "androidchatcontroller.h"
|
|
|
|
#define LOG_TAG "HT"
|
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
|
|
|
static JavaVM *g_jvm;
|
|
static JNIEnv *g_env; // Only use this in the SDL/HT thread
|
|
|
|
// Java class and methods that we will call from C++
|
|
static jclass NativeLibClass;
|
|
static jmethodID getDataDirMethod;
|
|
static jmethodID openUrlMethod;
|
|
static jmethodID screenWidthMethod;
|
|
static jmethodID screenHeightMethod;
|
|
static jmethodID screenDPIMethod;
|
|
static jmethodID getAndroidIDMethod;
|
|
static jmethodID initiateAskMethod;
|
|
static jmethodID initiateWebViewMethod;
|
|
static jmethodID getAskStringMethod;
|
|
static jmethodID getPlatformStringMethod;
|
|
static jmethodID getAssetManagerMethod;
|
|
|
|
namespace wi {
|
|
|
|
// char gszMainDataDir[PATH_MAX]; // main data is archived into Android assets
|
|
char gszTempDir[PATH_MAX]; // temp file directory
|
|
char gszMissionPacksDir[PATH_MAX]; // downloaded mission packs
|
|
char gszMissionPackInfosDir[PATH_MAX]; // info about downloaded mission packs
|
|
char gszSaveGamesDir[PATH_MAX]; // saved games
|
|
char gszPrefsFilename[PATH_MAX]; // game prefs
|
|
char gszCompletesDir[PATH_MAX]; // for "mission completed" tracking
|
|
HttpService *gphttp;
|
|
AAssetManager *gassetmgr;
|
|
|
|
IChatController *g_pchat;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
// This gets called from the Java thread when JNI is loaded
|
|
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|
JNIEnv *env;
|
|
if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) >= 0) {
|
|
// LOG() << "Success getting env";
|
|
|
|
// Lets get the vm and save it globally for later
|
|
int status = env->GetJavaVM(&g_jvm);
|
|
if (status != 0) {
|
|
LOG() << "Failed getting JavaVM";
|
|
} else {
|
|
// LOG() << "Success getting JavaVM";
|
|
}
|
|
} else {
|
|
LOG() << "Error getting env";
|
|
}
|
|
|
|
// Make a tmp class then declair the real class as a global reference
|
|
jclass tmp = env->FindClass("com/spiffcode/ht/NativeLib");
|
|
NativeLibClass = (jclass)env->NewGlobalRef(tmp);
|
|
|
|
// Setup the JNI method calls
|
|
getDataDirMethod = env->GetStaticMethodID(NativeLibClass, "getDataDir", "()Ljava/lang/String;");
|
|
screenWidthMethod = env->GetStaticMethodID(NativeLibClass, "screenWidth", "()I");
|
|
screenHeightMethod = env->GetStaticMethodID(NativeLibClass, "screenHeight", "()I");
|
|
screenDPIMethod = env->GetStaticMethodID(NativeLibClass, "screenDPI", "()I");
|
|
getAndroidIDMethod = env->GetStaticMethodID(NativeLibClass, "getAndroidID", "()Ljava/lang/String;");
|
|
openUrlMethod = env->GetStaticMethodID(NativeLibClass, "openUrl", "(Ljava/lang/String;)V");
|
|
initiateWebViewMethod = env->GetStaticMethodID(NativeLibClass, "initiateWebView", "(Ljava/lang/String;)V");
|
|
getAskStringMethod = env->GetStaticMethodID(NativeLibClass, "getAskString", "()Ljava/lang/String;");
|
|
initiateAskMethod = env->GetStaticMethodID(NativeLibClass, "initiateAsk", "(Ljava/lang/String;ILjava/lang/String;II)V");
|
|
getPlatformStringMethod = env->GetStaticMethodID(NativeLibClass, "getPlatformString", "()Ljava/lang/String;");
|
|
getAssetManagerMethod = env->GetStaticMethodID(NativeLibClass, "getAssetManager", "()Landroid/content/res/AssetManager;");
|
|
|
|
return JNI_VERSION_1_4;
|
|
}
|
|
|
|
// This gets called from the Java thread when the user is done with the string input dialog
|
|
JNIEXPORT void JNICALL
|
|
Java_com_spiffcode_ht_NativeLib_nativePostAskStringEvent(JNIEnv* env, jclass cls) {
|
|
// Inform the game thread that it's time to get the string
|
|
HostGetGameThread().Post(wi::kidmAskStringEvent, NULL);
|
|
}
|
|
#ifdef __cplusplus
|
|
} // extern C
|
|
#endif
|
|
|
|
bool HostHelpers::Init() {
|
|
// Get the env for this thread using the global JavaVM
|
|
int getEnvStat = g_jvm->GetEnv((void**)&g_env, JNI_VERSION_1_4);
|
|
if (getEnvStat == JNI_EDETACHED) {
|
|
// This shouldn't happen... SDL should have already atteched this thread
|
|
LOG() << "Env not attached";
|
|
LOG() << "Attempting to attach current thread";
|
|
if (g_jvm->AttachCurrentThread(&g_env, NULL) != 0) {
|
|
LOG() << "Failed attaching current thread";
|
|
return false;
|
|
}
|
|
} else if (getEnvStat == JNI_EVERSION) {
|
|
// Lets hope this doesn't happen
|
|
LOG() << "Env version not supported";
|
|
return false;
|
|
} else if (getEnvStat == JNI_OK) {
|
|
// LOG() << "Success getting env";
|
|
}
|
|
|
|
// Get the app's data path from Java
|
|
jobject path = g_env->CallStaticObjectMethod(NativeLibClass, getDataDirMethod);
|
|
const char* dataDir = g_env->GetStringUTFChars((jstring)path, NULL);
|
|
|
|
// Get the asset manager
|
|
jobject jam = g_env->CallStaticObjectMethod(NativeLibClass, getAssetManagerMethod);
|
|
gassetmgr = AAssetManager_fromJava(g_env, jam);
|
|
|
|
// Set the directory paths
|
|
sprintf(gszTempDir, "%s/tmp", gszMainDataDir);
|
|
sprintf(gszMissionPacksDir, "%s/MissionPacks", gszMainDataDir);
|
|
sprintf(gszMissionPackInfosDir, "%s/MissionPackInfos", gszMainDataDir);
|
|
sprintf(gszSaveGamesDir, "%s/SaveGames", gszMainDataDir);
|
|
sprintf(gszCompletesDir, "%s/Completes", gszMainDataDir);
|
|
sprintf(gszPrefsFilename, "%s/prefs.json", gszMainDataDir);
|
|
|
|
// Make the directories
|
|
mkdir(gszTempDir, 0755);
|
|
mkdir(gszMissionPacksDir, 0755);
|
|
mkdir(gszMissionPackInfosDir, 0755);
|
|
mkdir(gszSaveGamesDir, 0755);
|
|
mkdir(gszCompletesDir, 0755);
|
|
|
|
// SDL HttpService with Curl
|
|
extern HttpService *gphttp;
|
|
gphttp = (HttpService *)new SdlHttpService();
|
|
|
|
// Android specific chat controller
|
|
g_pchat = new wi::AndroidChatController();
|
|
|
|
return true;
|
|
}
|
|
|
|
void HostHelpers::Cleanup() {
|
|
delete gphttp;
|
|
}
|
|
|
|
const char *HostHelpers::GetMainDataDir() {
|
|
return NULL;
|
|
}
|
|
|
|
const char *HostHelpers::GetTempDir() {
|
|
return gszTempDir;
|
|
}
|
|
|
|
const char *HostHelpers::GetMissionPacksDir() {
|
|
return gszMissionPacksDir;
|
|
}
|
|
|
|
const char *HostHelpers::GetMissionPackInfosDir() {
|
|
return gszMissionPackInfosDir;
|
|
}
|
|
|
|
const char *HostHelpers::GetSaveGamesDir() {
|
|
return gszSaveGamesDir;
|
|
}
|
|
|
|
const char *HostHelpers::GetCompletesDir() {
|
|
return gszCompletesDir;
|
|
}
|
|
|
|
const char *HostHelpers::GetPrefsFilename() {
|
|
return gszPrefsFilename;
|
|
}
|
|
|
|
void HostHelpers::OpenUrl(const char *pszUrl) {
|
|
jstring url = g_env->NewStringUTF(pszUrl);
|
|
g_env->CallStaticVoidMethod(NativeLibClass, openUrlMethod, url);
|
|
g_env->DeleteLocalRef(url);
|
|
}
|
|
|
|
void HostHelpers::Log(const char *pszFormat, va_list va)
|
|
{
|
|
#if 0
|
|
LOGX() << base::Log::vFormat(pszFormat, va);
|
|
#endif
|
|
|
|
char sz[512];
|
|
vsnprintf(sz, sizeof(sz), pszFormat, va);
|
|
|
|
LOGD("%s\n", sz);
|
|
}
|
|
|
|
void HostHelpers::Log(const char *pszFormat, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, pszFormat);
|
|
Log(pszFormat, va);
|
|
va_end(va);
|
|
}
|
|
|
|
void HostHelpers::MessageBox(const char *pszFormat, va_list va)
|
|
{
|
|
Log(pszFormat, va);
|
|
}
|
|
|
|
void HostHelpers::Break()
|
|
{
|
|
Log("BREAK!!");
|
|
}
|
|
|
|
void HostHelpers::GetSurfaceProperties(SurfaceProperties *pprops)
|
|
{
|
|
int cxScreen, cyScreen;
|
|
|
|
// Get the screen size from Java
|
|
int screenWidth = g_env->CallStaticIntMethod(NativeLibClass, screenWidthMethod);
|
|
int screenHeight = g_env->CallStaticIntMethod(NativeLibClass, screenHeightMethod);
|
|
int screenDPI = g_env->CallStaticIntMethod(NativeLibClass, screenDPIMethod);
|
|
|
|
// HT wants screen points not screen pixels...
|
|
float density = (float)screenDPI / 160;
|
|
cxScreen = screenWidth / density;
|
|
cyScreen = screenHeight / density;
|
|
|
|
// HT grpahics are whack when the screen width is an odd number of bounds
|
|
// Hack: "increase" the screen width by one pixel if needed
|
|
if (cxScreen % 2)
|
|
cxScreen++;
|
|
|
|
pprops->cxWidth = cxScreen;
|
|
pprops->cyHeight = cyScreen;
|
|
pprops->cbxPitch = 1;
|
|
pprops->cbyPitch = pprops->cxWidth;
|
|
pprops->ffFormat = wi::kfDirect8;
|
|
pprops->density = density;
|
|
}
|
|
|
|
bool HostHelpers::DirExists(char *psz)
|
|
{
|
|
AAssetDir *assetDir = AAssetManager_openDir(gassetmgr, psz);
|
|
bool exists = AAssetDir_getNextFileName(assetDir) != NULL;
|
|
AAssetDir_close(assetDir);
|
|
return exists;
|
|
}
|
|
|
|
bool HostHelpers::EnumFiles(Enum *penm, int key, char *pszFn, int cbFn)
|
|
{
|
|
if (penm->m_pvNext == (void *)kEnmFirst) {
|
|
AAssetDir *assetDir = AAssetManager_openDir(gassetmgr, gpakr.BottomDir());
|
|
penm->m_pvNext = (void *)assetDir;
|
|
penm->m_dwUser = 0;
|
|
}
|
|
|
|
AAssetDir *assetDir = (AAssetDir *)penm->m_pvNext;
|
|
const char *ent = AAssetDir_getNextFileName(assetDir);
|
|
if (ent != NULL) {
|
|
strncpyz(pszFn, ent, cbFn);
|
|
penm->m_dwUser++;
|
|
return true;
|
|
}
|
|
AAssetDir_close(assetDir);
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
void HostHelpers::FrameStart()
|
|
{
|
|
#if 0
|
|
[g_appDelegate frameStart];
|
|
#else
|
|
Log("HostHelpers::FrameStart not implemented yet");
|
|
#endif
|
|
}
|
|
|
|
void HostHelpers::FrameComplete(int cfrmm, UpdateMap **apupd, Rect *arc,
|
|
bool fScrolled)
|
|
{
|
|
#if 0
|
|
[g_appDelegate frameComplete:cfrmm maps:apupd rects:arc scrolled:fScrolled];
|
|
#else
|
|
Log("HostHelpers::FrameComplete not implemented yet");
|
|
#endif
|
|
}
|
|
|
|
void HostHelpers::ResetScrollOffset()
|
|
{
|
|
#if 0
|
|
[g_appDelegate resetScrollOffset];
|
|
#else
|
|
Log("HostHelpers::ResetScrollOffset not implemented yet");
|
|
#endif
|
|
}
|
|
|
|
void HostHelpers::SetFormMgrs(FormMgr *pfrmmSim, FormMgr *pfrmmInput)
|
|
{
|
|
#if 0
|
|
return [g_appDelegate setFormMgrs:pfrmmSim input:pfrmmInput];
|
|
#else
|
|
Log("HostHelpers::SetFormMgrs not implemented yet");
|
|
#endif
|
|
}
|
|
|
|
DibBitmap *HostHelpers::CreateFrontDib(int cx, int cy, int nDegreeOrientation)
|
|
{
|
|
#if 0
|
|
return [g_appDelegate createFrontDibWithOrientation:nDegreeOrientation width:cx height:cy];
|
|
#else
|
|
Log("HostHelpers::CreateFrontDib not implemented yet");
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
void HostHelpers::SetPalette(Palette *ppal)
|
|
{
|
|
#if 0
|
|
[g_appDelegate setPalette:ppal];
|
|
#else
|
|
Log("HostHelpers::SetPalette not implemented yet");
|
|
#endif
|
|
}
|
|
|
|
bool HostHelpers::IsExiting()
|
|
{
|
|
#if 0
|
|
return [g_appDelegate isExiting];
|
|
#else
|
|
Log("HostHelpers::IsExitig not implemented yet");
|
|
return false;
|
|
#endif
|
|
}
|
|
*/
|
|
|
|
const char *HostHelpers::GetUdid()
|
|
{
|
|
jobject androidID = g_env->CallStaticObjectMethod(NativeLibClass, getAndroidIDMethod);
|
|
return g_env->GetStringUTFChars((jstring)androidID, NULL);
|
|
}
|
|
|
|
void HostHelpers::InitiateAsk(const char *title, int max, const char *def,
|
|
int keyboard, bool secure)
|
|
{
|
|
jstring jtitle = g_env->NewStringUTF(title);
|
|
jstring jdef = g_env->NewStringUTF(def);
|
|
|
|
g_env->CallStaticVoidMethod(NativeLibClass, initiateAskMethod, jtitle, (jint)max, jdef, (jint)keyboard, secure ? 1 : 0);
|
|
|
|
g_env->DeleteLocalRef(jtitle);
|
|
g_env->DeleteLocalRef(jdef);
|
|
}
|
|
|
|
void HostHelpers::GetAskString(char *psz, int cb)
|
|
{
|
|
jobject jstr = g_env->CallStaticObjectMethod(NativeLibClass, getAskStringMethod);
|
|
const char* cstr = g_env->GetStringUTFChars((jstring)jstr, NULL);
|
|
wi::strncpyz(psz, cstr, cb);
|
|
}
|
|
|
|
IChatController *HostHelpers::GetChatController()
|
|
{
|
|
if (g_pchat == NULL) {
|
|
g_pchat = new wi::AndroidChatController();
|
|
}
|
|
return g_pchat;
|
|
}
|
|
|
|
void HostHelpers::InitiateWebView(const char *title, const char *url) {
|
|
jstring jstrUrl = g_env->NewStringUTF(url);
|
|
g_env->CallStaticVoidMethod(NativeLibClass, initiateWebViewMethod, jstrUrl);
|
|
}
|
|
|
|
const char *HostHelpers::GetPlatformString() {
|
|
jobject jstr = g_env->CallStaticObjectMethod(NativeLibClass, getPlatformStringMethod);
|
|
return g_env->GetStringUTFChars((jstring)jstr, NULL);
|
|
}
|
|
|
|
/*
|
|
void HostHelpers::GameThreadStart(void *pv) {
|
|
Log("Starting game...");
|
|
wi::GameMain((char *)"");
|
|
}
|
|
|
|
int HostHelpers::main(int argc, char **argv)
|
|
{
|
|
|
|
}
|
|
*/
|
|
|
|
JavaVM *HostHelpers::GetJavaVM() {
|
|
return g_jvm;
|
|
}
|
|
|
|
JNIEnv *HostHelpers::GetJNIEnv() {
|
|
return g_env;
|
|
}
|
|
|
|
} // namespace wi
|