libnethack pr385

roll parts of pr385 into source tree

This does not take the PR as is.

Unlike the PR, this streamlines and minimizes the integration somewhat:

- use hints/include mechanism instead of creating alternative
  Makefile.dat, Makefile.src, Makefile.top, Makefile.utl in sys/lib;
  those would have been a maintenance nightmare.

- don't have alternative mkmkfile.sh and setup.sh in sys/lib.

- sys/lib/libnethackmain.c differed from sys/unix/unixmain.c by
  very little, so just place a small bit of conditional code at the
  top of sys/unix/unixmain.c instead.

- changed the conditional code bits from __EMSCRIPTEN__ to
  CROSS_TO_WASM.

- You should be able to build the wasm result by:
    cd sys/unix ; sh setup.sh hints/linux.2020 ; cd ../..
    make fetch-lua    (<-one time)
    make WANT_LIBNH all

- You should be able to build LIBNBH by:
    cd sys/unix ; sh setup.sh hints/linux.2020 ; cd ../..
    make fetch-lua    (<-one time)
    make CROSS_TO_WASM=1 all

As it is currently coded, winshim.c requires C99.
This commit is contained in:
Adam Powers
2020-08-26 19:22:00 -07:00
committed by nhmall
parent 741e6fd5b7
commit dc2d757399
28 changed files with 1555 additions and 120 deletions

View File

@@ -0,0 +1,95 @@
NETHACK GENERAL PUBLIC LICENSE
(Copyright 1989 M. Stephenson)
(Based on the BISON general public license,
copyright 1988 Richard M. Stallman)
Everyone is permitted to copy and distribute verbatim copies of this
license, but changing it is not allowed. You can also use this wording to
make the terms for other programs.
The license agreements of most software companies keep you at the mercy of
those companies. By contrast, our general public license is intended to give
everyone the right to share NetHack. To make sure that you get the rights we
want you to have, we need to make restrictions that forbid anyone to deny you
these rights or to ask you to surrender the rights. Hence this license
agreement.
Specifically, we want to make sure that you have the right to give away
copies of NetHack, that you receive source code or else can get it if you
want it, that you can change NetHack or use pieces of it in new free
programs, and that you know you can do these things.
To make sure that everyone has such rights, we have to forbid you to
deprive anyone else of these rights. For example, if you distribute copies
of NetHack, you must give the recipients all the rights that you have. You
must make sure that they, too, receive or can get the source code. And you
must tell them their rights.
Also, for our own protection, we must make certain that everyone finds out
that there is no warranty for NetHack. If NetHack is modified by someone
else and passed on, we want its recipients to know that what they have is
not what we distributed.
Therefore we (Mike Stephenson and other holders of NetHack copyrights) make
the following terms which say what you must do to be allowed to distribute or
change NetHack.
COPYING POLICIES
1. You may copy and distribute verbatim copies of NetHack source code as
you receive it, in any medium, provided that you keep intact the notices on
all files that refer to copyrights, to this License Agreement, and to the
absence of any warranty; and give any other recipients of the NetHack
program a copy of this License Agreement along with the program.
2. You may modify your copy or copies of NetHack or any portion of it, and
copy and distribute such modifications under the terms of Paragraph 1 above
(including distributing this License Agreement), provided that you also do the
following:
a) cause the modified files to carry prominent notices stating that you
changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish, that in
whole or in part contains or is a derivative of NetHack or any part
thereof, to be licensed at no charge to all third parties on terms
identical to those contained in this License Agreement (except that you
may choose to grant more extensive warranty protection to some or all
third parties, at your option)
c) You may charge a distribution fee for the physical act of
transferring a copy, and you may at your option offer warranty protection
in exchange for a fee.
3. You may copy and distribute NetHack (or a portion or derivative of it,
under Paragraph 2) in object code or executable form under the terms of
Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete machine-readable source code, which
must be distributed under the terms of Paragraphs 1 and 2 above; or,
b) accompany it with full information as to how to obtain the complete
machine-readable source code from an appropriate archive site. (This
alternative is allowed only for noncommercial distribution.)
For these purposes, complete source code means either the full source
distribution as originally released over Usenet or updated copies of the
files in this distribution used to create the object code or executable.
4. You may not copy, sublicense, distribute or transfer NetHack except as
expressly provided under this License Agreement. Any attempt otherwise to
copy, sublicense, distribute or transfer NetHack is void and your rights to
use the program under this License agreement shall be automatically
terminated. However, parties who have received computer software programs
from you with this License Agreement will not have their licenses terminated
so long as such parties remain in full compliance.
Stated plainly: You are permitted to modify NetHack, or otherwise use parts
of NetHack, provided that you comply with the conditions specified above;
in particular, your modified NetHack or program containing parts of NetHack
must remain freely available as provided in this License Agreement. In
other words, go ahead and share NetHack, but don't try to stop anyone else
from sharing it farther.

View File

@@ -0,0 +1,47 @@
# NetHack
This is the ACTUAL NetHack game, originally written in 1982 and one of the longest-standing open source collaborations. This isn't a wrapper around the binary NetHack, but the game itself compiled into [WebAssembly](https://webassembly.org/) (WASM) using [emscripten](https://emscripten.org/). This module should run [anywhere WebAssembly is supported](https://developer.mozilla.org/en-US/docs/WebAssembly#Browser_compatibility) including node.js and modern browsers.
Since NetHack typically uses the [TTY](https://en.wikipedia.org/wiki/Computer_terminal#Text_terminals) to show depictions of the game and that won't work for WebAssembly, you are required to implement the graphics portion of NetHack to make this work. This allows a wide variety of UIs to be created, both text and graphics based as well as using keyboard and mouse to control the game. The API for implementing graphics is described below.
## Install
``` sh
npm install nethack
```
## API
The main module returns a setup function: `startNethack(uiCallback, moduleOptions)`.
* `uiCallback(name, ... args)` - Your callback function that will handle rendering NetHack on the screen of your choice. The `name` argument is one of the UI functions of the [NetHack Window Interface](https://github.com/NetHack/NetHack/blob/NetHack-3.7/doc/window.doc) and the `args` are corresponding to the window interface function that is being called. You are required to return the correct type of data for the function that is implemented. The `uiCallback` may be an `async` function.
* `moduleOptions` - An optional [emscripten Module object](https://emscripten.org/docs/api_reference/module.html) for configuring the WASM that will be run.
* `Module.arguments` - Of note is the [arguments property](https://emscripten.org/docs/api_reference/module.html#Module.arguments) which gets passed to NetHack as its [command line parameters](https://nethackwiki.com/wiki/Options).
## Example
``` js
let nethackStart = require("nethack");
nethackStart(doGraphics);
let winCount = 0;
async function doGraphics(name, ... args) {
console.log(`shim graphics: ${name} [${args}]`);
switch(name) {
case "shim_create_nhwindow":
winCount++;
console.log("creating window", args, "returning", winCount);
return winCount;
case "shim_yn_function":
case "shim_message_menu":
return 121; // return 'y' to all questions
case "shim_nhgetch":
case "shim_nh_poskey":
return 0; // simulates a mouse click on "exit up the stairs"
default:
return 0;
}
}
```
## Other Notes
* This module isn't small -- the WASM code is about 10MB. It may be slow to load over non-broadband connections. There are some emscripten build optimizations that may help with browser builds (such as dynamic loading), but those aren't currently part of this package. Pull requests are always welcome. :)
* This hasn't been tested on browsers. If you get this to work on a browser, please let me know and I will add notes. Or if anyone wants to help setup automated browser testing, that would be supremely appreciated.

View File

@@ -0,0 +1,20 @@
{
"name": "@neth4ck/neth4ck",
"version": "1.0.0",
"description": "The original NetHack rogue-like game built as a WebAssembly module",
"main": "src/nethackShim.js",
"scripts": {
"test": "node test/test.js",
"clean": "rm ./build/nethack.js; rm ./build/nethack.wasm; true",
"build": "cp ../../../src/nethack.js ../../../src/nethack.wasm ./build",
"prepack": "npm run build"
},
"keywords": [
"nethack",
"rogue",
"rogue-like",
"game"
],
"author": "Adam Powers <apowers@ato.ms>",
"license": "SEE LICENSE IN LICENSE.md"
}

View File

@@ -0,0 +1,49 @@
const path = require("path");
let Module;
let userCallback;
let savedOnRuntimeInitialized;
// starts nethack
function nethackStart(cb, inputModule = {}) {
if(typeof cb !== "string" && typeof cb !== "function") throw new TypeError("expected first argument to be 'Function' or 'String' representing global callback function name");
if(typeof inputModule !== "object") throw new TypeError("expected second argument to be object");
let cbName;
if(typeof cb === "function") {
cbName = cb.name;
if (cbName === "") cbName = "__anonymousNetHackCallback";
if (globalThis[cbName] === undefined) globalThis[cbName] = cb;
else if (globalThis[cbName] !== cb) throw new Error (`'globalThis["${cbName}"]' is not the same as specified callback`);
}
/* global globalThis */
userCallback = globalThis[cbName];
if(typeof userCallback !== "function") throw new TypeError(`expected 'globalThis["${cbName}"]' to be a function`);
// if(userCallback.constructor.name !== "AsyncFunction") throw new TypeError(`expected 'globalThis["${cbName}"]' to be an async function`);
// Emscripten Module config
Module = inputModule;
savedOnRuntimeInitialized = Module.onRuntimeInitialized;
Module.onRuntimeInitialized = function (... args) {
// after the WASM is loaded, add the shim graphics callback function
Module.ccall(
"shim_graphics_set_callback", // C function name
null, // return type
["string"], // arg types
[cbName], // arg values
{async: true} // options
);
// if the user had their own onRuntimeInitialized(), call it now
if (savedOnRuntimeInitialized) savedOnRuntimeInitialized(... args);
};
// load and run the module
var factory = require(path.join(__dirname, "../build/nethack.js"));
factory(Module);
}
// TODO: ES6 'import' style module
module.exports = nethackStart;