Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ permissions:
jobs:
build:
runs-on: ubuntu-24.04
strategy:
matrix:
abi: [arm64-v8a, armeabi]
steps:
- uses: actions/checkout@v6
- name: Install required packages
Expand All @@ -19,18 +22,18 @@ jobs:
uses: android-actions/setup-android@v3
with:
cmdline-tools-version: 9123335
packages: 'platforms;android-30 ndk;21.4.7075529'
packages: 'platforms;android-30 ndk;27.3.13750724'
- name: Configure path to NDK
run: sed -i -e 's,NDK = .*,NDK = /usr/local/lib/android/sdk/ndk/21.4.7075529,g' sys/android/Makefile.src
run: sed -i -e 's,NDK = .*,NDK = /usr/local/lib/android/sdk/ndk/27.3.13750724,g' sys/android/Makefile.src
- name: Build native Android application
run: cd sys/android && sh ./setup.sh && cd ../.. && make install
run: cd sys/android && sh ./setup.sh && cd ../.. && make install ABI=${{ matrix.abi }}
- name: Build NetHack
run: cd sys/android && sh gradlew build
- uses: actions/upload-artifact@v5
with:
name: nethack-release-unsigned
name: nethack-release-unsigned-${{ matrix.abi }}
path: sys/android/app/build/outputs/apk/release/app-release-unsigned.apk
- uses: actions/upload-artifact@v5
with:
name: nethack-debug
name: nethack-debug-${{ matrix.abi }}
path: sys/android/app/build/outputs/apk/debug/app-debug.apk
4 changes: 2 additions & 2 deletions sys/android/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
bin
libs/*
assets/nethackdir
app/libs/
app/assets/nethackdir/
gen
.gradle
build
Expand Down
25 changes: 11 additions & 14 deletions sys/android/Makefile.src
Original file line number Diff line number Diff line change
Expand Up @@ -87,38 +87,34 @@ SYSOBJ = ioctl.o androidmain.o unixtty.o androidunix.o
# CC = arm-linux-gcc
#
# For cross-compiling with Android NDK
NDK = /path/to/android-ndk-r21e
NDK = /path/to/android-ndk-r27d

NDK_TOOLCHAIN = $(NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin

# Choose an ABI
ABI = armeabi
#ABI = armeabi-v7a
#ABI = arm64-v8a
#ABI = x86
#ABI = x86_64
# Choose an ABI (normally set in the top-level Makefile)
ABI ?= arm64-v8a

CC_armeabi = $(NDK_TOOLCHAIN)/armv7a-linux-androideabi30-clang
LD_armeabi = $(NDK_TOOLCHAIN)/arm-linux-androideabi-ld
CC_armeabi-v7a = $(NDK_TOOLCHAIN)/armv7a-linux-androideabi30-clang
LD_armeabi-v7a = $(NDK_TOOLCHAIN)/arm-linux-androideabi-ld
CC_arm64-v8a = $(NDK_TOOLCHAIN)/aarch64-linux-android30-clang
LD_arm64-v8a = $(NDK_TOOLCHAIN)/aarch64-linux-android-ld
CC_x86 = $(NDK_TOOLCHAIN)/i686-linux-android30-clang
LD_x86 = $(NDK_TOOLCHAIN)/i686-linux-android-ld
CC_x86_64 = $(NDK_TOOLCHAIN)/x86_64-linux-android30-clang
LD_x86_64 = $(NDK_TOOLCHAIN)/x86_64-linux-android-ld

CC_VAR = CC_$(ABI)
LD_VAR = LD_$(ABI)

CC := $($(CC_VAR))
LINK := $(CC)

# Compile normally
CFLAGS = -DANDROID -O2 -g -Wno-format -fsigned-char -fPIC -I../include
#CFLAGS = -DANDROID -DDEBUG -g -Wno-format -fsigned-char -fPIC -I../include
LFLAGS = -shared -Wl,--fix-cortex-a8
LFLAGS_armeabi = -Wl,--fix-cortex-a8
LFLAGS_armeabi-v7a = -Wl,--fix-cortex-a8
# 16 KB page alignment, required by newer 64-bit Android devices
LFLAGS_arm64-v8a = -Wl,-z,max-page-size=16384
LFLAGS_x86_64 = -Wl,-z,max-page-size=16384
LFLAGS_VAR = LFLAGS_$(ABI)
LFLAGS = -shared $($(LFLAGS_VAR))

# LFLAGS = -L/usr/X11R6/lib
# OR compile backwards compatible a.out format
Expand Down Expand Up @@ -408,6 +404,7 @@ Sysunix: $(HOBJ) Makefile

Sysandroid: $(HOBJ) Makefile
@echo "Loading ..."
rm -rf ../sys/android/app/libs
mkdir -p ../sys/android/app/libs/$(ABI)
$(LINK) $(LFLAGS) -o ../sys/android/app/libs/$(ABI)/lib$(GAME).so $(HOBJ) $(LIBS)
@touch Sysandroid
Expand Down
7 changes: 7 additions & 0 deletions sys/android/Makefile.top
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ NHSROOT=.
# make NetHack
#PREFIX = /usr
GAME = nethack

# Target ABI for the native library: arm64-v8a, armeabi, armeabi-v7a, x86
# or x86_64. Override with 'make install ABI=...'. The compiled data files
# depend on the target's word size, so the host utilities are built to match
# and one build of the data files only works with one ABI.
ABI = arm64-v8a
export ABI
# GAME = nethack.prg
#GAMEUID = games
#GAMEGRP = bin
Expand Down
14 changes: 12 additions & 2 deletions sys/android/Makefile.utl
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,18 @@ NHSROOT=..
# flags for debugging:
# CFLAGS = -g -I../include

CFLAGS = -DANDROID -m32 -Wno-format -fsigned-char -I../include
LFLAGS = -m32
# The compiled data files must match the target's word size, so build the
# host utilities as 32-bit for 32-bit ABIs (needs gcc-multilib) and 64-bit
# otherwise.
ABI ?= arm64-v8a
HOSTBITS_armeabi = -m32
HOSTBITS_armeabi-v7a = -m32
HOSTBITS_x86 = -m32
HOSTBITS_VAR = HOSTBITS_$(ABI)
HOSTBITS = $($(HOSTBITS_VAR))

CFLAGS = -DANDROID $(HOSTBITS) -Wno-format -fsigned-char -I../include
LFLAGS = $(HOSTBITS)

LIBS =

Expand Down
12 changes: 11 additions & 1 deletion sys/android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ work. If you're running Windows you're on your own.
1. `cd /path/to/android-sdk/tools/bin`
2. Update the sdk manager: `./sdkmanager --update`. If you get "NoClassDefFoundError" it's because you're not running JDK 8. Make sure the env variable `JAVA_HOME` points to JDK 8.
3. Install the platform tools: `./sdkmanager --install "platforms;android-30"`
4. Install the NDK: `./sdkmanager --install "ndk;21.4.7075529"`
4. Install the NDK: `./sdkmanager --install "ndk;27.3.13750724"`


## Build
Expand All @@ -32,6 +32,16 @@ work. If you're running Windows you're on your own.
4. `cd ../..`
5. `make install`

This builds for `arm64-v8a`, which works on all current devices. Some newer
devices, e.g. the Galaxy Z Fold6 or Pixel 7 and later, can only run 64-bit code.
To build for another ABI, e.g. older 32-bit devices, pass it to make:
`make install ABI=armeabi-v7a`. The 32-bit ABIs need `gcc-multilib`.

The compiled data files depend on the target's word size, so an APK only
supports the one ABI it was built for. Run `make spotless` before switching
ABI. Saved games from a 32-bit build can't be loaded by a 64-bit build, and
the reverse is also true.

### Build the Android application

1. `cd /path/to/NetHack-Android/sys/android`
Expand Down
2 changes: 1 addition & 1 deletion sys/android/app/assets/ver
Original file line number Diff line number Diff line change
@@ -1 +1 @@
106
107
4 changes: 2 additions & 2 deletions sys/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
defaultConfig {
minSdkVersion 7
targetSdkVersion 30
versionName '3.6.7-1'
versionCode 3671
versionName '3.6.7-2'
versionCode 3672
}

compileOptions {
Expand Down
70 changes: 65 additions & 5 deletions sys/android/winandroid.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ static char* msghistory[32];
static int msghistory_idx;
static int msghistory_idx0;

// Menu identifiers are often pointers, which don't fit in the int passed to
// Java on 64-bit devices. Keep them here and pass Java a 1-based index.
struct menu_idents {
winid wid;
anything *ids;
int n, size;
struct menu_idents *next;
};
static struct menu_idents *menu_idents;

extern const char *status_fieldfmt[MAXBLSTATS];
// Need to separate conditions in order to color them properly
enum bl_conditions {
Expand Down Expand Up @@ -632,6 +642,17 @@ void and_display_nhwindow(winid wid, BOOLEAN_P blocking)
// already been dismissed.
void and_destroy_nhwindow(winid wid)
{
struct menu_idents **pm, *m;
for(pm = &menu_idents; (m = *pm) != 0; pm = &m->next)
{
if(m->wid == wid)
{
*pm = m->next;
free(m->ids);
free(m);
break;
}
}
JNICallV(jDestroyWindow, wid);
}

Expand Down Expand Up @@ -1145,8 +1166,24 @@ void and_display_file(const char *name, BOOLEAN_P complain)
// before add_menu(). After calling start_menu() you may not
// putstr() to the window. Only windows of type NHW_MENU may
// be used for menus.
static struct menu_idents *get_menu_idents(winid wid)
{
struct menu_idents *m;
for(m = menu_idents; m; m = m->next)
if(m->wid == wid)
return m;
m = (struct menu_idents*)alloc(sizeof(struct menu_idents));
m->wid = wid;
m->ids = 0;
m->n = m->size = 0;
m->next = menu_idents;
menu_idents = m;
return m;
}

void and_start_menu(winid wid)
{
get_menu_idents(wid)->n = 0;
JNICallV(jStartMenu, wid);
}

Expand Down Expand Up @@ -1185,6 +1222,24 @@ void and_start_menu(winid wid)
void and_add_menu(winid wid, int glyph, const ANY_P *ident, CHAR_P accelerator, CHAR_P groupacc, int attr, const char *str, BOOLEAN_P preselected)
{
int tile, color;
int id = 0; // 0 means not selectable
if(ident->a_void)
{
struct menu_idents *m = get_menu_idents(wid);
if(m->n == m->size)
{
anything *ids;
m->size = m->size ? m->size * 2 : 32;
ids = (anything*)alloc(sizeof(anything) * m->size);
if(m->n)
memcpy(ids, m->ids, sizeof(anything) * m->n);
free(m->ids);
m->ids = ids;
}
m->ids[m->n++] = *ident;
id = m->n;
}

if(glyph == NO_GLYPH)
tile = -1;
else
Expand All @@ -1202,7 +1257,7 @@ void and_add_menu(winid wid, int glyph, const ANY_P *ident, CHAR_P accelerator,
attr = 1<<attr;

jbyteArray jstr = create_bytearray(str);
JNICallV(jAddMenu, wid, tile, ident->a_int, (int)accelerator, (int)groupacc, attr, jstr, (int)preselected, color);
JNICallV(jAddMenu, wid, tile, id, (int)accelerator, (int)groupacc, attr, jstr, (int)preselected, color);
destroy_jobject(jstr);
}

Expand Down Expand Up @@ -1272,11 +1327,16 @@ int and_select_menu_r(winid wid, int how, MENU_ITEM_P **selected, int reentry)
{
n >>= 1;

struct menu_idents *m = get_menu_idents(wid);
q = p = (*jEnv)->GetIntArrayElements(jEnv, a, 0);
*selected = (MENU_ITEM_P*)malloc(sizeof(MENU_ITEM_P) * n);
for(i = 0; i < n; i++)
{
(*selected)[i].item.a_int = *p++;
int id = *p++;
if(id > 0 && id <= m->n)
(*selected)[i].item = m->ids[id - 1];
else
(*selected)[i].item = zeroany;
(*selected)[i].count = *p++;
}
(*jEnv)->ReleaseIntArrayElements(jEnv, a, q, 0);
Expand Down Expand Up @@ -1575,9 +1635,9 @@ char and_yn_function(const char *question, const char *choices, CHAR_P def)
if(choices)
{
nChoices = strlen(choices);
esc = (int)index(choices, '\033');
if(esc)
esc -= (int)choices;
const char *pesc = index(choices, '\033');
if(pesc)
esc = (int)(pesc - choices);
else
esc = -1;
}
Expand Down