Compare commits
75 Commits
64f4304626
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
c665401fd8
|
|||
|
2799a0be3d
|
|||
|
e527dd5b6a
|
|||
|
fe17b4fd67
|
|||
|
90b4015ba1
|
|||
|
2dd85c2b26
|
|||
|
1d60e13792
|
|||
|
9d6e8a366b
|
|||
|
5167533c6d
|
|||
|
aac527ae89
|
|||
|
af6a4c840b
|
|||
|
afbd1dfd68
|
|||
|
b305594ea4
|
|||
|
df7991763d
|
|||
|
e0f8d274e7
|
|||
|
08f41ccb0b
|
|||
|
28ec48cc85
|
|||
|
4f2b6e7c53
|
|||
|
2e0bda7a6e
|
|||
|
87c93f3ae0
|
|||
|
628aef06e3
|
|||
|
2603527b67
|
|||
|
39a7da716c
|
|||
|
afc0309222
|
|||
|
0d9ce5d6b1
|
|||
|
be58ed1c05
|
|||
|
fe16799bbb
|
|||
|
5f5e899f6e
|
|||
|
8546659ae0
|
|||
|
249a48807a
|
|||
|
be405887e2
|
|||
|
73e2ccdcb8
|
|||
|
b05dae958d
|
|||
|
3e993b84eb
|
|||
|
09fef78f9a
|
|||
|
7d30d9d971
|
|||
|
29285641a4
|
|||
|
37eab6f8e2
|
|||
|
f95c262c57
|
|||
|
5f42941d76
|
|||
|
1108eab403
|
|||
|
e5b990ae61
|
|||
|
5925f851c4
|
|||
|
d13831f213
|
|||
|
a9f6adcd9d
|
|||
|
757d7098cf
|
|||
|
4e69bda3c8
|
|||
|
755e5ff6b4
|
|||
|
9353ccba8a
|
|||
|
5c71ab1c30
|
|||
|
36f97f09d5
|
|||
|
e04021425a
|
|||
|
d89956a626
|
|||
|
dd146d1caf
|
|||
|
adb758bd53
|
|||
|
baae1428bd
|
|||
|
7bd18c1a4c
|
|||
|
99489e37df
|
|||
|
86f6dbf302
|
|||
|
4836cae3fa
|
|||
|
69ca3f3282
|
|||
|
3484503ba1
|
|||
|
1efa8fa212
|
|||
|
9541b653b5
|
|||
|
4ab3d868c1
|
|||
|
2ab5a38894
|
|||
|
e3875f76f6
|
|||
|
fdcb81b565
|
|||
|
72654b1036
|
|||
|
fe85c33d64
|
|||
|
1d9e08641e
|
|||
|
638d1acbe0
|
|||
|
815ccdaab9
|
|||
|
c0741c48aa
|
|||
|
e2ab296e79
|
47
Makefile
47
Makefile
@@ -1,32 +1,57 @@
|
|||||||
BUNDLE_NAME = bundle.lua
|
BUNDLE_NAME = bundle.lua
|
||||||
HAXE_NAME = haxe.lua
|
HAXE_NAME = haxe.lua
|
||||||
MINIFYD_NAME = bundle.min.lua
|
MINIFYD_NAME = bundle.min.lua
|
||||||
|
HAXE_ZIP_NAME = "haxe.zip"
|
||||||
|
UNPACK_NAME = unpack.lua
|
||||||
|
UNPACK_POLYFILLED_NAME = unpack.polyfill.lua
|
||||||
|
UNPACK_MINIFYD_NAME = unpack.min.lua
|
||||||
BUILD_DIR = build
|
BUILD_DIR = build
|
||||||
HAXE_FLAGS =
|
HAXE_FLAGS = -D message.reporting=pretty
|
||||||
POLYFILLED_NAME = bundle.polyfill.lua
|
POLYFILLED_NAME = bundle.polyfill.lua
|
||||||
POLYFILL_SRC = src/polyfill.lua
|
POLYFILL_SRC = src/polyfill.lua
|
||||||
CREAFTOS_PATH = craftos
|
CREAFTOS_PATH = craftos
|
||||||
|
BUILD_HXML = build.hxml
|
||||||
|
|
||||||
HAXE_PATH := $(BUILD_DIR)/$(HAXE_NAME)
|
HAXE_PATH := $(BUILD_DIR)/$(HAXE_NAME)
|
||||||
MIN_PATH := $(BUILD_DIR)/$(MINIFYD_NAME)
|
MIN_PATH := $(BUILD_DIR)/$(MINIFYD_NAME)
|
||||||
POLYFILL_PATH := $(BUILD_DIR)/$(POLYFILLED_NAME)
|
POLYFILL_PATH := $(BUILD_DIR)/$(POLYFILLED_NAME)
|
||||||
|
UNPACK_PATH := $(BUILD_DIR)/$(UNPACK_NAME)
|
||||||
|
UNPACK_MINIFYD_PATH := $(BUILD_DIR)/$(UNPACK_MINIFYD_NAME)
|
||||||
|
HAXE_ZIP_PATH := $(BUILD_DIR)/$(HAXE_ZIP_NAME)
|
||||||
|
UNPACK_POLYFILLED_PATH := $(BUILD_DIR)/$(UNPACK_POLYFILLED_NAME)
|
||||||
|
|
||||||
all: clean build
|
all: clean build unpack
|
||||||
|
|
||||||
build: HAXE_FLAGS += --main kernel.Entrypoint -D analyzer-optimize
|
build: HAXE_FLAGS += -D analyzer-optimize -D no-traces
|
||||||
build: $(MIN_PATH)
|
build: $(MIN_PATH)
|
||||||
|
|
||||||
debug: HAXE_FLAGS += -D webconsole -D error_stack --debug
|
debug: HAXE_FLAGS += -D webconsole -D error_stack --debug
|
||||||
debug: build
|
debug: $(MIN_PATH)
|
||||||
|
|
||||||
|
unpack: $(UNPACK_MINIFYD_PATH) $(HAXE_ZIP_PATH)
|
||||||
|
|
||||||
|
$(HAXE_PATH): HAXE_FLAGS += --main kernel.Entrypoint --lua $(HAXE_PATH)
|
||||||
$(HAXE_PATH): $(shell find src -name '*.hx')
|
$(HAXE_PATH): $(shell find src -name '*.hx')
|
||||||
haxe build.hxml $(HAXE_FLAGS)
|
haxe $(BUILD_HXML) $(HAXE_FLAGS)
|
||||||
|
|
||||||
$(POLYFILL_PATH): $(POLYFILL_SRC) $(HAXE_PATH)
|
$(POLYFILL_PATH): $(POLYFILL_SRC) $(HAXE_PATH)
|
||||||
cat $(POLYFILL_SRC) $(HAXE_PATH) > $@
|
cat $(POLYFILL_SRC) $(HAXE_PATH) > $@
|
||||||
|
|
||||||
$(MIN_PATH): $(POLYFILL_PATH)
|
$(MIN_PATH): $(POLYFILL_PATH)
|
||||||
node minify.js $(POLYFILL_PATH) $@
|
node tools/minify.js < $(POLYFILL_PATH) > $@
|
||||||
|
|
||||||
|
$(HAXE_ZIP_PATH): $(MIN_PATH)
|
||||||
|
node tools/zlibDeflate.js < $(MIN_PATH) > $@
|
||||||
|
|
||||||
|
$(UNPACK_PATH): HAXE_FLAGS += --main Unpack -D analyzer-optimize --lua $(UNPACK_PATH)
|
||||||
|
$(UNPACK_PATH): $(shell find src -name '*.hx')
|
||||||
|
haxe $(BUILD_HXML) $(HAXE_FLAGS)
|
||||||
|
|
||||||
|
$(UNPACK_POLYFILLED_PATH): $(UNPACK_PATH)
|
||||||
|
cat $(POLYFILL_SRC) $(UNPACK_PATH) > $@
|
||||||
|
|
||||||
|
$(UNPACK_MINIFYD_PATH): $(UNPACK_POLYFILLED_PATH)
|
||||||
|
node tools/minify.js < $(UNPACK_POLYFILLED_PATH) > $@
|
||||||
|
|
||||||
.PHONY: deps
|
.PHONY: deps
|
||||||
deps: deps-hx deps-node
|
deps: deps-hx deps-node
|
||||||
@@ -37,7 +62,7 @@ deps-hx:
|
|||||||
|
|
||||||
.PHONY: deps-node
|
.PHONY: deps-node
|
||||||
deps-node:
|
deps-node:
|
||||||
yarn install
|
npm install
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@@ -54,8 +79,12 @@ emulator:
|
|||||||
|
|
||||||
.PHONY: webconsole
|
.PHONY: webconsole
|
||||||
webconsole:
|
webconsole:
|
||||||
node console.js
|
node tools/console.js
|
||||||
|
|
||||||
.PHONY: format
|
.PHONY: format
|
||||||
format:
|
format:
|
||||||
haxelib run formatter -s src
|
haxelib run formatter -s src
|
||||||
|
|
||||||
|
.PHONY: format-deps
|
||||||
|
format-deps:
|
||||||
|
haxelib install formatter
|
||||||
@@ -10,5 +10,3 @@
|
|||||||
-D lua-ver 5.1
|
-D lua-ver 5.1
|
||||||
|
|
||||||
--macro include("bin")
|
--macro include("bin")
|
||||||
|
|
||||||
--lua build/haxe.lua
|
|
||||||
|
|||||||
32
console.js
32
console.js
@@ -1,32 +0,0 @@
|
|||||||
const http = require('http');
|
|
||||||
|
|
||||||
function time() {
|
|
||||||
let now = new Date();
|
|
||||||
|
|
||||||
return `${now.getHours().toString().padStart(2, "0")}:${now.getMinutes().toString().padStart(2, 0)}:${now.getSeconds().toString().padStart(2, 0)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const server = http.createServer((req, res) => {
|
|
||||||
|
|
||||||
if (req.method != "POST") {
|
|
||||||
res.writeHead(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var id = req.url.substring(1);
|
|
||||||
|
|
||||||
let data = "";
|
|
||||||
|
|
||||||
req.on('data', chunk => {
|
|
||||||
data += chunk;
|
|
||||||
})
|
|
||||||
|
|
||||||
req.on('end', () => {
|
|
||||||
console.log(`[${time()}][${id}]${data}`);
|
|
||||||
res.writeHead(200);
|
|
||||||
res.end();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Listening on port 8080")
|
|
||||||
server.listen(8080);
|
|
||||||
103
doc/Concepts.md
103
doc/Concepts.md
@@ -57,7 +57,7 @@ Also peripherals can be made accessible via the network. More on that later.
|
|||||||
var back = Peripheral.getRedstone("back");
|
var back = Peripheral.getRedstone("back");
|
||||||
back.setOutput(true);
|
back.setOutput(true);
|
||||||
|
|
||||||
var drive Peripheral.getDrive("drive_0");
|
var drive = Peripheral.getDrive("drive_0");
|
||||||
drive.eject();
|
drive.eject();
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -111,10 +111,9 @@ A collection of `Pixel` is called a `Canvas` which is nothing more than a 2D arr
|
|||||||
The concept of processes tryes to encapsulate programs. A process is basically an interface with the `run(handle: ProcessHandle)` method.
|
The concept of processes tryes to encapsulate programs. A process is basically an interface with the `run(handle: ProcessHandle)` method.
|
||||||
The idea is that you can register all you disposable resources in the handle and they will be disposed when the process is killed or crashes.
|
The idea is that you can register all you disposable resources in the handle and they will be disposed when the process is killed or crashes.
|
||||||
|
|
||||||
A process can be used as a command on the terminal or as a service. See [bin/HelloWorld.hx](../src/bin/HelloWorld.hx) for an example.
|
A process can be used as a command on the terminal or as a service. Basically everything that runs and is not part of the kernel is a process.
|
||||||
Basically everything that runs and is not part of the kernel is a process.
|
|
||||||
|
|
||||||
In order for you program to be used it needs to be registered in the `BinStore` and the `DCEHack` manually.
|
More on that at [Applications](#applications).
|
||||||
|
|
||||||
# EndOfLoop
|
# EndOfLoop
|
||||||
|
|
||||||
@@ -156,3 +155,99 @@ TurtleMutex.runInTThread(() -> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# RPC
|
||||||
|
|
||||||
|
With the help of dark and badly documented magic also known as "macros", we can create quickly create remote procedure call Classes to call functions on other
|
||||||
|
computers. A problem that arises is that since all data gets send over the network that we kinda lose the type safty. We cloud trust ourself to cast
|
||||||
|
the result of the request to the right type or we cloud just make use of macros. The RPC macro will create a RPC class that implements all functions of an
|
||||||
|
interface just that the return type is wrapped in a Promise. Now if we call a function of that RPC class it fires a request to the other computer and waits
|
||||||
|
for a response. On the other side the service makes use of that generated package handle function for the RPC class.
|
||||||
|
|
||||||
|
A simple example:
|
||||||
|
|
||||||
|
```haxe
|
||||||
|
interface IExampleRPC {
|
||||||
|
function addNumber(a:Int, b:Int):Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:build(macros.rpc.RPC.buildRPC(IExampleRPC))
|
||||||
|
class ExampleRPC extends RPCBase {}
|
||||||
|
|
||||||
|
|
||||||
|
@:build(macros.Binstore.includeBin("Example SRV", ["example-srv"]))
|
||||||
|
class ExampleService implements IProcess implements IExampleRPC {
|
||||||
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function run(handle:ProcessHandle) {
|
||||||
|
this.handle = handle;
|
||||||
|
|
||||||
|
kernel.net.Net.registerProto("example", (pack) -> {
|
||||||
|
ExampleRPC.handlePackage(this, pack);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addNumber(a:Int, b:Int):Int {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
var rpc = new ExampleRPC(12,"example");
|
||||||
|
|
||||||
|
rpc.addNumber(3,7).handle((p)->{
|
||||||
|
switch p {
|
||||||
|
case Success(r):
|
||||||
|
Log.info('3+7=$r');
|
||||||
|
case Failure(err):
|
||||||
|
Log.error('Error: $err');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
# Build system and flags
|
||||||
|
|
||||||
|
We use `make` to build the project. If you want a prod build just run `make` and if you want the debug build run `make debug`.
|
||||||
|
The `build` directory should contain all needed files.
|
||||||
|
|
||||||
|
- `bundle.min.lua`: The minified final file
|
||||||
|
- `bundle.polyfill.lua`: The same as above just not minified. use this when debugging.
|
||||||
|
- `haxe.lua`: Intermediate file. Polyfill not yet added.
|
||||||
|
- `haxe.zip`: The compressed `bundle.min.lua`.
|
||||||
|
- `unpack.*`: Same as the bundle files. Used to unpack and run the `haxe.zip` file.
|
||||||
|
|
||||||
|
The follwing haxe flags can be used in the code or can be set in the makefile.
|
||||||
|
|
||||||
|
- `debug`: Is set when debug
|
||||||
|
- `kv_use_native`: If set use the native CC serialize and unserialize functions instead of the Haxe ones. See [KVStore.hx](../src/lib/KVStore.hx) for more.
|
||||||
|
|
||||||
|
# Applications
|
||||||
|
|
||||||
|
If you want to make an application you just need to create a class that implements IProcess and and has no arguments in the constructor.
|
||||||
|
In order to have the programm available from the terminal you need to add the `Binstore.includeBin` macro for the class. Here is an example:
|
||||||
|
|
||||||
|
```haxe
|
||||||
|
@:build(macros.Binstore.includeBin("HelloWorld", ["hello", "helloworld"]))
|
||||||
|
class HelloWorld implements IProcess {
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function run(handle:ProcessHandle) {
|
||||||
|
handle.writeLine("Hello World");
|
||||||
|
handle.close(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's break this down:
|
||||||
|
|
||||||
|
- The `includeBin` macro is required to automaticly inlcude the app and to defeat the DCE optimisation. In early versions refections were used but DCE did not like that
|
||||||
|
- The first argument on `includeBin` is the name of the app. Only ever used in displaying.
|
||||||
|
- The second argument are the aliases. These are used to call the app from the terminal and other places
|
||||||
|
- The constructor can't have any arguments. It's also recommended to not do any major setup stuff in there.
|
||||||
|
- The `run` method is the entry point in the app.
|
||||||
|
- The handle is used to interact with the outside world. (theoretically at least)
|
||||||
|
- The `handle.close(true)` call is required to end a process. The app does not end when the run function is finished. The first arguments represents if the app was successfull.
|
||||||
|
|
||||||
|
|||||||
10
minify.js
10
minify.js
@@ -1,10 +0,0 @@
|
|||||||
const fs = require("fs");
|
|
||||||
const luamin = require("luamin");
|
|
||||||
|
|
||||||
const haxeOutput = fs.readFileSync(process.argv[2] ?? "build/Haxe.min.lua",{encoding:"utf8"});
|
|
||||||
|
|
||||||
const minified = luamin.minify(haxeOutput);
|
|
||||||
|
|
||||||
fs.writeFileSync(process.argv[3] ?? "build/Haxe.min.lua",minified);
|
|
||||||
|
|
||||||
console.log("minified lua");
|
|
||||||
35
package-lock.json
generated
Normal file
35
package-lock.json
generated
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "haxe",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "haxe",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"luamin": "^1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/luamin": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/luamin/-/luamin-1.0.4.tgz",
|
||||||
|
"integrity": "sha1-lEUptY/G+k0x6s4uA1PUEhDw49M= sha512-z1h0bclRD/QGsS/Dz4Skp9z0qPTmmm+IKcrCapGmdTczPWVdN9f9jk6WqkNrcifQr8+n9Pzsm9WkwpOH1JBUAQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"luaparse": "^0.2.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"luamin": "bin/luamin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/luaparse": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/luaparse/-/luaparse-0.2.1.tgz",
|
||||||
|
"integrity": "sha1-qo9WEysN6X0388mRqd9C4OF/ZWw= sha512-VKBcryd5nJte4ZNR29NOk8F/UkMipjeb4yoxcSS51z6QAzg9DXUC2WsfLniS0J1eh3pr/ZL3e9ha6V8fhoLbBQ==",
|
||||||
|
"bin": {
|
||||||
|
"luaparse": "bin/luaparse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,14 @@ import lib.HomeContext;
|
|||||||
|
|
||||||
class Startup {
|
class Startup {
|
||||||
public static function main() {
|
public static function main() {
|
||||||
|
#if debug
|
||||||
|
var term = BinStore.instantiate("terminal");
|
||||||
|
var pid = ProcessManager.run(term, {
|
||||||
|
// args: ["debug"]
|
||||||
|
});
|
||||||
|
var ctx = WindowManager.getContextByPID(pid);
|
||||||
|
WindowManager.focusContextToOutput(ctx[0], "main");
|
||||||
|
#else
|
||||||
if (MainTerm.instance.isColor()) {
|
if (MainTerm.instance.isColor()) {
|
||||||
var main = new HomeContext();
|
var main = new HomeContext();
|
||||||
|
|
||||||
@@ -16,5 +24,6 @@ class Startup {
|
|||||||
var ctx = WindowManager.getContextByPID(pid);
|
var ctx = WindowManager.getContextByPID(pid);
|
||||||
WindowManager.focusContextToOutput(ctx[0], "main");
|
WindowManager.focusContextToOutput(ctx[0], "main");
|
||||||
}
|
}
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/Unpack.hx
Normal file
29
src/Unpack.hx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import lua.Lua;
|
||||||
|
import haxe.io.Bytes;
|
||||||
|
import kernel.fs.FS;
|
||||||
|
import haxe.zip.Uncompress;
|
||||||
|
|
||||||
|
class Unpack {
|
||||||
|
public static function main() {
|
||||||
|
var filename = "/haxe.zip";
|
||||||
|
var handle = FS.openReadBinary(filename);
|
||||||
|
var size = FS.attributes(filename).size;
|
||||||
|
var data = Bytes.alloc(size);
|
||||||
|
|
||||||
|
for (i in 0...size) {
|
||||||
|
data.set(i, handle.readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
var uncompressed = Uncompress.run(data);
|
||||||
|
|
||||||
|
var res = Lua.load(uncompressed.toString()); // FIXME: Haxe is missing some parameters. This does not work.
|
||||||
|
|
||||||
|
var f = res.func; // Required for silly haxe bug.
|
||||||
|
|
||||||
|
if (res.message == null) {
|
||||||
|
f();
|
||||||
|
} else {
|
||||||
|
trace('Failed: ${res.message}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import kernel.peripherals.Drive;
|
||||||
import lib.CLIAppBase;
|
import lib.CLIAppBase;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
|
|
||||||
@@ -30,37 +31,17 @@ class Disk extends CLIAppBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
registerSyncSubcommand("play", (args) -> {
|
registerSyncSubcommand("play", (args) -> {
|
||||||
if (args.length < 1) {
|
return audioDiskPlayPause(args.getString("addr"), true);
|
||||||
handle.writeLine("Missing drive address");
|
}, [Peripheral("addr", Drive.TYPE_NAME)]);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return audioDiskPlayPause(args[0], true);
|
|
||||||
}, "<drive>");
|
|
||||||
|
|
||||||
registerSyncSubcommand("stop", (args) -> {
|
registerSyncSubcommand("stop", (args) -> {
|
||||||
if (args.length < 1) {
|
return audioDiskPlayPause(args.getString("addr"), false);
|
||||||
handle.writeLine("Missing drive address");
|
}, [Peripheral("addr", Drive.TYPE_NAME)]);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return audioDiskPlayPause(args[0], false);
|
|
||||||
}, "<drive>");
|
|
||||||
|
|
||||||
registerSyncSubcommand("eject", (args) -> {
|
registerSyncSubcommand("eject", (args) -> {
|
||||||
if (args.length < 1) {
|
var driveAddr = args.getString("addr");
|
||||||
handle.writeLine("Missing drive address");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var driveAddr = args[0];
|
|
||||||
var drive = Peripheral.getDrive(driveAddr);
|
var drive = Peripheral.getDrive(driveAddr);
|
||||||
|
|
||||||
if (drive == null) {
|
|
||||||
handle.writeLine("Drive not found: " + driveAddr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drive.isDiskPresent()) {
|
if (!drive.isDiskPresent()) {
|
||||||
handle.writeLine("No disk in drive: " + driveAddr);
|
handle.writeLine("No disk in drive: " + driveAddr);
|
||||||
return false;
|
return false;
|
||||||
@@ -68,21 +49,12 @@ class Disk extends CLIAppBase {
|
|||||||
|
|
||||||
drive.ejectDisk();
|
drive.ejectDisk();
|
||||||
return true;
|
return true;
|
||||||
}, "<drive>");
|
}, [Peripheral("addr", Drive.TYPE_NAME)]);
|
||||||
|
|
||||||
registerSyncSubcommand("lable", (args) -> {
|
registerSyncSubcommand("label", (args) -> {
|
||||||
if (args.length < 1) {
|
var driveAddr = args.getString("addr");
|
||||||
handle.writeLine("Missing drive address");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var driveAddr = args[0];
|
|
||||||
var drive = Peripheral.getDrive(driveAddr);
|
var drive = Peripheral.getDrive(driveAddr);
|
||||||
var label:String = args[1];
|
var label:Null<String> = args.getString("label");
|
||||||
|
|
||||||
if (drive == null) {
|
|
||||||
handle.writeLine("Drive not found: " + driveAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drive.isDiskPresent()) {
|
if (!drive.isDiskPresent()) {
|
||||||
handle.writeLine("No disk in drive: " + driveAddr);
|
handle.writeLine("No disk in drive: " + driveAddr);
|
||||||
@@ -99,7 +71,7 @@ class Disk extends CLIAppBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, "<drive> [label]");
|
}, [Peripheral("addr", Drive.TYPE_NAME), Optional(String("label"))]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function audioDiskPlayPause(driveAddr:String, play:Bool):Bool {
|
private function audioDiskPlayPause(driveAddr:String, play:Bool):Bool {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package bin;
|
|||||||
|
|
||||||
import lib.CLIAppBase;
|
import lib.CLIAppBase;
|
||||||
import kernel.gps.INS;
|
import kernel.gps.INS;
|
||||||
import lib.Pos3;
|
import lib.WorldPos;
|
||||||
import lib.Vec.Vec3;
|
import lib.Vec.Vec3;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
@@ -11,16 +11,16 @@ using tink.CoreApi;
|
|||||||
class GPS extends CLIAppBase {
|
class GPS extends CLIAppBase {
|
||||||
public function new() {
|
public function new() {
|
||||||
registerSyncSubcommand("set", (args) -> {
|
registerSyncSubcommand("set", (args) -> {
|
||||||
var x:Float = Std.parseFloat(args[0]);
|
var x:Float = args.getFloat("x");
|
||||||
var y:Float = Std.parseFloat(args[1]);
|
var y:Float = args.getFloat("y");
|
||||||
var z:Float = Std.parseFloat(args[2]);
|
var z:Float = args.getFloat("z");
|
||||||
|
|
||||||
var pos:Pos3 = new Vec3<Float>(x, y, z);
|
var pos:WorldPos = new Vec3<Float>(x, y, z);
|
||||||
|
|
||||||
kernel.gps.GPS.setManualPosition(pos);
|
kernel.gps.GPS.setManualPosition(pos);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, "<x> <y> <z>");
|
}, [Float("x"), Float("y"), Float("z")]);
|
||||||
|
|
||||||
registerSyncSubcommand("status", (args) -> {
|
registerSyncSubcommand("status", (args) -> {
|
||||||
var pos = kernel.gps.GPS.getPosition();
|
var pos = kernel.gps.GPS.getPosition();
|
||||||
@@ -51,11 +51,12 @@ class GPS extends CLIAppBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
registerAsyncSubcommand("locate", (args) -> {
|
registerAsyncSubcommand("locate", (args) -> {
|
||||||
return kernel.gps.GPS.locate().map((pos) -> {
|
return kernel.gps.GPS.locate().map((result) -> {
|
||||||
if (pos != null) {
|
switch result {
|
||||||
handle.writeLine('Position x:${pos.x} y:${pos.y} z:${pos.z}');
|
case Success(pos):
|
||||||
} else {
|
handle.writeLine('Position x:${pos.x} y:${pos.y} z:${pos.z}');
|
||||||
handle.writeLine("Position not available");
|
case Failure(err):
|
||||||
|
handle.writeLine("Position not available: " + err);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
package bin;
|
|
||||||
|
|
||||||
import kernel.log.Log;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("Hello world", ["hello"]))
|
|
||||||
class HelloWorld implements Process {
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
handle.write("Hello World!");
|
|
||||||
|
|
||||||
handle.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
package bin;
|
|
||||||
|
|
||||||
import kernel.log.Log;
|
|
||||||
import lib.ui.elements.TextElement;
|
|
||||||
import lib.Pos;
|
|
||||||
import lib.ui.elements.UIElement;
|
|
||||||
import lib.ui.elements.LayerdRootElement;
|
|
||||||
import kernel.ui.WindowContext;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("HelloWorld-GUI", ["hello-gui"]))
|
|
||||||
class HelloWorldGUI implements Process {
|
|
||||||
private var handle:ProcessHandle;
|
|
||||||
private var ctx:WindowContext;
|
|
||||||
private var requestRender:Void->Void;
|
|
||||||
private var root:LayerdRootElement;
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
this.handle = handle;
|
|
||||||
|
|
||||||
var stateless = handle.createStatelessWindowContext();
|
|
||||||
this.ctx = stateless.ctx;
|
|
||||||
this.requestRender = stateless.requestRender;
|
|
||||||
|
|
||||||
stateless.setRenderFunc(this.render);
|
|
||||||
|
|
||||||
this.root = new LayerdRootElement();
|
|
||||||
|
|
||||||
this.ctx.delegateEvents(this.root);
|
|
||||||
|
|
||||||
this.requestRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function render() {
|
|
||||||
var children:Array<{element:UIElement, offset:Pos}> = [
|
|
||||||
{
|
|
||||||
element: new TextElement("Hello World", {
|
|
||||||
uiEvents: {
|
|
||||||
onClick: () -> {
|
|
||||||
Log.debug("Hello World");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
offset: new Pos({x: 0, y: 0})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: new TextElement("Holla Mundo", {
|
|
||||||
uiEvents: {
|
|
||||||
onClick: () -> {
|
|
||||||
Log.debug("Holla Mundo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
offset: new Pos({x: 0, y: 1})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: new TextElement("Ayyy", {
|
|
||||||
uiEvents: {
|
|
||||||
onClick: () -> {
|
|
||||||
Log.debug("Ayy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
offset: new Pos({x: 4, y: 1})
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
this.root.setChildren(children);
|
|
||||||
this.root.render(ctx.getSize()).renderToContext(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package bin;
|
|
||||||
|
|
||||||
import kernel.log.Log;
|
|
||||||
import macros.rpc.RPC;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
@:build(macros.rpc.RPC.buildRPC())
|
|
||||||
class HelloWorldService implements Process {
|
|
||||||
private var handle:ProcessHandle;
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
this.handle = handle;
|
|
||||||
|
|
||||||
RPC.generateRPCPackageHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
@rpc
|
|
||||||
public function getNumber(arg1:Int, arg2:Int):Int {
|
|
||||||
Log.debug(arg1);
|
|
||||||
Log.debug(arg2);
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
import kernel.ps.ProcessHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("ID", ["id"]))
|
@:build(macros.Binstore.includeBin("ID", ["id"]))
|
||||||
class ID implements Process {
|
class ID implements IProcess {
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
public function run(handle:ProcessHandle) {
|
||||||
|
|||||||
@@ -7,18 +7,13 @@ import lib.CLIAppBase;
|
|||||||
class KSettings extends CLIAppBase {
|
class KSettings extends CLIAppBase {
|
||||||
public function new() {
|
public function new() {
|
||||||
registerSyncSubcommand("get", (args) -> {
|
registerSyncSubcommand("get", (args) -> {
|
||||||
var key = args[0];
|
var key = args.getString("key");
|
||||||
|
|
||||||
if (key == null) {
|
|
||||||
handle.writeLine("Key not specified");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = switch (key) {
|
var value = switch (key) {
|
||||||
case "hostname":
|
case "hostname":
|
||||||
KernelSettings.hostname;
|
KernelSettings.hostname;
|
||||||
case "sitecontroller":
|
case "nameServer":
|
||||||
Std.string(KernelSettings.siteController);
|
Std.string(KernelSettings.nameServer);
|
||||||
default:
|
default:
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
@@ -30,17 +25,17 @@ class KSettings extends CLIAppBase {
|
|||||||
|
|
||||||
handle.writeLine(value);
|
handle.writeLine(value);
|
||||||
return true;
|
return true;
|
||||||
}, " <key>");
|
}, [String("key")]);
|
||||||
|
|
||||||
registerSyncSubcommand("set", (args) -> {
|
registerSyncSubcommand("set", (args) -> {
|
||||||
var key = args[0];
|
var key = args.getString("key");
|
||||||
|
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
handle.writeLine("Key not specified");
|
handle.writeLine("Key not specified");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = args[1];
|
var value = args.getString("value");
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
handle.writeLine("Value not specified");
|
handle.writeLine("Value not specified");
|
||||||
@@ -50,18 +45,18 @@ class KSettings extends CLIAppBase {
|
|||||||
switch (key) {
|
switch (key) {
|
||||||
case "hostname":
|
case "hostname":
|
||||||
KernelSettings.hostname = value;
|
KernelSettings.hostname = value;
|
||||||
case "sitecontroller":
|
case "nameServer":
|
||||||
KernelSettings.siteController = Std.parseInt(value);
|
KernelSettings.nameServer = Std.parseInt(value);
|
||||||
default:
|
default:
|
||||||
handle.writeLine("Key not found");
|
handle.writeLine("Key not found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}, " <key> <value>");
|
}, [String("key"), String("value")]);
|
||||||
|
|
||||||
registerSyncSubcommand("list", (args) -> {
|
registerSyncSubcommand("list", (args) -> {
|
||||||
handle.writeLine("hostname");
|
handle.writeLine("hostname");
|
||||||
handle.writeLine("sitecontroller");
|
handle.writeLine("nameServer");
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
import kernel.ps.ProcessHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import lib.MathI;
|
import lib.MathI;
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
import kernel.ui.WindowContext;
|
import kernel.ui.WindowContext;
|
||||||
import lib.ui.UIApp;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("Log", ["log"]))
|
@:build(macros.Binstore.includeBin("Log", ["log"]))
|
||||||
class KernelLog implements Process {
|
class KernelLog implements IProcess {
|
||||||
private var handle:ProcessHandle;
|
private var handle:ProcessHandle;
|
||||||
private var ctx:WindowContext;
|
private var ctx:WindowContext;
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package bin;
|
|||||||
|
|
||||||
import kernel.ps.ProcessManager;
|
import kernel.ps.ProcessManager;
|
||||||
import kernel.ps.ProcessHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("LSPS", ["lsps"]))
|
@:build(macros.Binstore.includeBin("LSPS", ["lsps"]))
|
||||||
class LSPS implements Process {
|
class LSPS implements IProcess {
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
public function run(handle:ProcessHandle) {
|
||||||
|
|||||||
@@ -40,16 +40,7 @@ class Net extends CLIAppBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
registerAsyncSubcommand("ping", (args) -> {
|
registerAsyncSubcommand("ping", (args) -> {
|
||||||
if (args.length < 1) {
|
var toID:Int = args.getInt("id");
|
||||||
return Future.sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var toID:Null<Int> = Std.parseInt(args[0]);
|
|
||||||
|
|
||||||
if (toID == null) {
|
|
||||||
handle.write("Invalid ID");
|
|
||||||
return Future.sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return kernel.net.Net.ping(toID).map(result -> {
|
return kernel.net.Net.ping(toID).map(result -> {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
@@ -61,6 +52,6 @@ class Net extends CLIAppBase {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}, "<id>");
|
}, [Int("id")]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,11 @@ import kernel.peripherals.Peripherals.Peripheral;
|
|||||||
import lib.CLIAppBase;
|
import lib.CLIAppBase;
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("Peripheral", ["ph", "peripheral"]))
|
@:build(macros.Binstore.includeBin("Peripheral", ["ph", "peripheral"]))
|
||||||
class Perf extends CLIAppBase {
|
class Peri extends CLIAppBase {
|
||||||
public function new() {
|
public function new() {
|
||||||
registerSyncSubcommand("inspect", (args) -> {
|
registerSyncSubcommand("inspect", (args) -> {
|
||||||
if (args.length < 1)
|
var addr = args.getString("addr");
|
||||||
return false;
|
var result = Peripheral.inspect(addr);
|
||||||
|
|
||||||
var result = Peripheral.inspect(args[0]);
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
handle.writeLine("No peripheral found on side " + args[0]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle.writeLine("Types:");
|
handle.writeLine("Types:");
|
||||||
for (type in result.types) {
|
for (type in result.types) {
|
||||||
@@ -28,7 +21,7 @@ class Perf extends CLIAppBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, "<side>");
|
}, [Addr("addr")]);
|
||||||
|
|
||||||
registerSyncSubcommand("list", (args) -> {
|
registerSyncSubcommand("list", (args) -> {
|
||||||
for (addr in Peripheral.getAllAddresses()) {
|
for (addr in Peripheral.getAllAddresses()) {
|
||||||
@@ -9,19 +9,19 @@ using tink.CoreApi;
|
|||||||
class Redstone extends CLIAppBase {
|
class Redstone extends CLIAppBase {
|
||||||
public function new() {
|
public function new() {
|
||||||
registerSyncSubcommand("on", (args) -> {
|
registerSyncSubcommand("on", (args) -> {
|
||||||
Peripheral.getRedstone(args[0]).setOutput(true);
|
Peripheral.getRedstone(args.getString("side")).setOutput(true);
|
||||||
return true;
|
return true;
|
||||||
}, "<side>");
|
}, [Side("side")]);
|
||||||
|
|
||||||
registerSyncSubcommand("off", (args) -> {
|
registerSyncSubcommand("off", (args) -> {
|
||||||
Peripheral.getRedstone(args[0]).setOutput(false);
|
Peripheral.getRedstone(args.getString("side")).setOutput(false);
|
||||||
return true;
|
return true;
|
||||||
}, "<side>");
|
}, [Side("side")]);
|
||||||
|
|
||||||
registerSyncSubcommand("get", (args) -> {
|
registerSyncSubcommand("get", (args) -> {
|
||||||
var value = Peripheral.getRedstone(args[0]).getAnalogInput();
|
var value = Peripheral.getRedstone(args.getString("side")).getAnalogInput();
|
||||||
handle.write("Analog input: " + value);
|
handle.write("Analog input: " + value);
|
||||||
return true;
|
return true;
|
||||||
}, "<side>");
|
}, [Side("side")]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,50 +9,28 @@ using tink.CoreApi;
|
|||||||
class Service extends CLIAppBase {
|
class Service extends CLIAppBase {
|
||||||
public function new() {
|
public function new() {
|
||||||
registerSyncSubcommand("start", (args) -> {
|
registerSyncSubcommand("start", (args) -> {
|
||||||
if (args.length < 1) {
|
var result = ServiceManager.start(args.getString("name"));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var name = args[0];
|
|
||||||
|
|
||||||
var result = ServiceManager.start(name);
|
|
||||||
return handleResult(result);
|
return handleResult(result);
|
||||||
}, "<name>");
|
}, [String("name")]);
|
||||||
|
|
||||||
registerSyncSubcommand("stop", (args) -> {
|
registerSyncSubcommand("stop", (args) -> {
|
||||||
if (args.length < 1) {
|
var result = ServiceManager.stop(args.getString("name"));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var name = args[0];
|
|
||||||
|
|
||||||
var result = ServiceManager.stop(name);
|
|
||||||
return handleResult(result);
|
return handleResult(result);
|
||||||
}, "<name>");
|
}, [String("name")]);
|
||||||
|
|
||||||
registerSyncSubcommand("register", (args) -> {
|
registerSyncSubcommand("register", (args) -> {
|
||||||
if (args.length < 2) {
|
var name = args.getString("name");
|
||||||
return false;
|
var binName = args.getString("binary");
|
||||||
}
|
var rest = args.getRest();
|
||||||
|
|
||||||
var name = args[0];
|
|
||||||
var binName = args[1];
|
|
||||||
var rest = args.slice(2);
|
|
||||||
|
|
||||||
var result = ServiceManager.register(name, binName, rest);
|
var result = ServiceManager.register(name, binName, rest);
|
||||||
return handleResult(result);
|
return handleResult(result);
|
||||||
}, "<name> <binary> [args...]");
|
}, [String("name"), String("binary"), Rest("args")]);
|
||||||
|
|
||||||
registerSyncSubcommand("unregister", (args) -> {
|
registerSyncSubcommand("unregister", (args) -> {
|
||||||
if (args.length < 2) {
|
var result = ServiceManager.unregister(args.getString("name"));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var name = args[0];
|
|
||||||
|
|
||||||
var result = ServiceManager.unregister(name);
|
|
||||||
return handleResult(result);
|
return handleResult(result);
|
||||||
}, "<name>");
|
}, [String("name")]);
|
||||||
|
|
||||||
registerSyncSubcommand("list", (args) -> {
|
registerSyncSubcommand("list", (args) -> {
|
||||||
var list = ServiceManager.listRunning();
|
var list = ServiceManager.listRunning();
|
||||||
@@ -65,13 +43,9 @@ class Service extends CLIAppBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
registerSyncSubcommand("enable", (args) -> {
|
registerSyncSubcommand("enable", (args) -> {
|
||||||
if (args.length < 1) {
|
ServiceManager.enable(args.getString("name"));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceManager.enable(args[0]);
|
|
||||||
return true;
|
return true;
|
||||||
}, "<name>");
|
}, [String("name")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handleResult(res:Outcome<Noise, String>):Bool {
|
private function handleResult(res:Outcome<Noise, String>):Bool {
|
||||||
|
|||||||
71
src/bin/Speaker.hx
Normal file
71
src/bin/Speaker.hx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package bin;
|
||||||
|
|
||||||
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
|
import lib.CLIAppBase;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
@:build(macros.Binstore.includeBin("Speaker", ["speaker", "sp"]))
|
||||||
|
class Speaker extends CLIAppBase {
|
||||||
|
public function new() {
|
||||||
|
registerSyncSubcommand("note", (args) -> {
|
||||||
|
var sp = Peripheral.getSpeaker(args.getString("addr"));
|
||||||
|
|
||||||
|
var note = args.getString("note");
|
||||||
|
var r;
|
||||||
|
|
||||||
|
if (args.hasArg("pitch")) {
|
||||||
|
if (args.hasArg("volume")) {
|
||||||
|
r = sp.playNote(note, args.getFloat("volume"), args.getInt("pitch"));
|
||||||
|
} else {
|
||||||
|
r = sp.playNote(note, args.getFloat("volume"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = sp.playNote(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r {
|
||||||
|
case Failure(failure):
|
||||||
|
handle.writeLine(failure);
|
||||||
|
return false;
|
||||||
|
case Success(_):
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
Peripheral("addr", kernel.peripherals.Speaker.TYPE_NAME),
|
||||||
|
String("note"),
|
||||||
|
Optional(Int("pitch")),
|
||||||
|
Optional(Float("volume"))
|
||||||
|
]);
|
||||||
|
|
||||||
|
registerSyncSubcommand("sound", (args) -> {
|
||||||
|
var sp = Peripheral.getSpeaker(args.getString("addr"));
|
||||||
|
|
||||||
|
var sound = args.getString("sound");
|
||||||
|
var r;
|
||||||
|
|
||||||
|
if (args.hasArg("volume")) {
|
||||||
|
if (args.hasArg("pitch")) {
|
||||||
|
r = sp.playSound(sound, args.getFloat("volume"), args.getFloat("pitch"));
|
||||||
|
} else {
|
||||||
|
r = sp.playSound(sound, args.getFloat("volume"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
r = sp.playSound(sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r {
|
||||||
|
case Failure(failure):
|
||||||
|
handle.writeLine(failure);
|
||||||
|
return false;
|
||||||
|
case Success(_):
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
Peripheral("addr", kernel.peripherals.Speaker.TYPE_NAME),
|
||||||
|
String("sound"),
|
||||||
|
Optional(Float("pitch")),
|
||||||
|
Optional(Float("volume"))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import lib.MathI;
|
||||||
|
import kernel.EndOfLoop;
|
||||||
import lua.NativeStringTools;
|
import lua.NativeStringTools;
|
||||||
import kernel.binstore.BinStore;
|
import kernel.binstore.BinStore;
|
||||||
import kernel.ps.ProcessHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
import kernel.ps.ProcessManager;
|
import kernel.ps.ProcessManager;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import kernel.ui.WindowContext;
|
import kernel.ui.WindowContext;
|
||||||
@@ -11,7 +13,7 @@ import kernel.ui.WindowContext;
|
|||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("Terminal", ["terminal"]))
|
@:build(macros.Binstore.includeBin("Terminal", ["terminal"]))
|
||||||
class Terminal implements Process {
|
class Terminal implements IProcess {
|
||||||
private static inline final MAX_BACKLOG:Int = 100;
|
private static inline final MAX_BACKLOG:Int = 100;
|
||||||
|
|
||||||
private var handle:ProcessHandle;
|
private var handle:ProcessHandle;
|
||||||
@@ -24,6 +26,8 @@ class Terminal implements Process {
|
|||||||
private var history:Array<String> = [];
|
private var history:Array<String> = [];
|
||||||
private var historyIndex:Int = 0;
|
private var historyIndex:Int = 0;
|
||||||
|
|
||||||
|
private var scrollBack = 0;
|
||||||
|
|
||||||
private var runningPID:PID = -1;
|
private var runningPID:PID = -1;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
@@ -58,8 +62,11 @@ class Terminal implements Process {
|
|||||||
if (this.runningPID > 0)
|
if (this.runningPID > 0)
|
||||||
return;
|
return;
|
||||||
this.backlog.push("> " + this.input);
|
this.backlog.push("> " + this.input);
|
||||||
|
this.backlog.push("");
|
||||||
|
|
||||||
var command = this.input;
|
var command = this.input;
|
||||||
this.input = "";
|
this.input = "";
|
||||||
|
this.scrollBack = 0;
|
||||||
this.requestRender();
|
this.requestRender();
|
||||||
this.historyIndex = 0;
|
this.historyIndex = 0;
|
||||||
this.invokeCommand(command);
|
this.invokeCommand(command);
|
||||||
@@ -71,10 +78,27 @@ class Terminal implements Process {
|
|||||||
this.input = this.history[this.history.length - this.historyIndex];
|
this.input = this.history[this.history.length - this.historyIndex];
|
||||||
this.requestRender();
|
this.requestRender();
|
||||||
}
|
}
|
||||||
|
case 266: // PAGE UP
|
||||||
|
this.scrollBack = MathI.min(scrollBack + 1, this.backlog.length - 1);
|
||||||
|
this.requestRender();
|
||||||
|
case 267: // PAGE DOWN
|
||||||
|
this.scrollBack = MathI.max(scrollBack - 1, 0);
|
||||||
|
this.requestRender();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.requestRender();
|
this.requestRender();
|
||||||
|
|
||||||
|
if (handle.args.length > 0) {
|
||||||
|
var arg1 = handle.args[0];
|
||||||
|
|
||||||
|
this.backlog.push("> " + arg1);
|
||||||
|
this.backlog.push("");
|
||||||
|
|
||||||
|
EndOfLoop.endOfLoop(() -> {
|
||||||
|
this.invokeCommand(arg1);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function stopCurrentPS() {
|
private function stopCurrentPS() {
|
||||||
@@ -89,7 +113,8 @@ class Terminal implements Process {
|
|||||||
var size = this.ctx.getSize();
|
var size = this.ctx.getSize();
|
||||||
var linesAvailable = size.y - 1;
|
var linesAvailable = size.y - 1;
|
||||||
|
|
||||||
var start:Int = this.backlog.length - linesAvailable;
|
var withoutScrollBack = (this.backlog.length - linesAvailable);
|
||||||
|
var start:Int = withoutScrollBack - scrollBack;
|
||||||
|
|
||||||
for (i in 0...linesAvailable) {
|
for (i in 0...linesAvailable) {
|
||||||
var line = this.backlog[start + i];
|
var line = this.backlog[start + i];
|
||||||
@@ -156,24 +181,13 @@ class Terminal implements Process {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mfunc = NativeStringTools.gmatch(s, "(.-)(\n)");
|
var splits = s.split("\n");
|
||||||
|
|
||||||
while (true) {
|
for (i => split in splits) {
|
||||||
var found = mfunc();
|
if (i == 0) {
|
||||||
|
this.backlog[this.backlog.length - 1] += split;
|
||||||
if (found == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found == "\n") {
|
|
||||||
this.backlog.push("");
|
|
||||||
} else {
|
} else {
|
||||||
this.backlog.push(found);
|
this.backlog.push(split);
|
||||||
}
|
|
||||||
|
|
||||||
// Trim the backlog if it's too long
|
|
||||||
if (this.backlog.length > MAX_BACKLOG) {
|
|
||||||
this.backlog.shift();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
package bin;
|
|
||||||
|
|
||||||
import lib.CLIAppBase;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
@:build(macros.Binstore.includeBin("Turtle", ["turtle", "t"]))
|
|
||||||
class Turtle extends CLIAppBase {
|
|
||||||
public function new() {
|
|
||||||
registerSyncSubcommand("forward", (args) -> {
|
|
||||||
return checkAvailable() && perform(kernel.turtle.Turtle.forward());
|
|
||||||
});
|
|
||||||
|
|
||||||
registerSyncSubcommand("back", (args) -> {
|
|
||||||
return checkAvailable() && perform(kernel.turtle.Turtle.back());
|
|
||||||
});
|
|
||||||
|
|
||||||
registerSyncSubcommand("left", (args) -> {
|
|
||||||
return checkAvailable() && perform(kernel.turtle.Turtle.turnLeft());
|
|
||||||
});
|
|
||||||
|
|
||||||
registerSyncSubcommand("right", (args) -> {
|
|
||||||
return checkAvailable() && perform(kernel.turtle.Turtle.turnRight());
|
|
||||||
});
|
|
||||||
|
|
||||||
registerSyncSubcommand("up", (args) -> {
|
|
||||||
return checkAvailable() && perform(kernel.turtle.Turtle.up());
|
|
||||||
});
|
|
||||||
|
|
||||||
registerSyncSubcommand("down", (args) -> {
|
|
||||||
return checkAvailable() && perform(kernel.turtle.Turtle.down());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkAvailable():Bool {
|
|
||||||
if (!kernel.turtle.Turtle.isTurtle()) {
|
|
||||||
handle.write("This is not a turtle!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function perform(outcome:Outcome<Noise, String>):Bool {
|
|
||||||
switch outcome {
|
|
||||||
case Success(_):
|
|
||||||
return true;
|
|
||||||
case Failure(error):
|
|
||||||
handle.write(error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
180
src/bin/TurtleCtl.hx
Normal file
180
src/bin/TurtleCtl.hx
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
package bin;
|
||||||
|
|
||||||
|
import kernel.turtle.Types.ToolSide;
|
||||||
|
import lib.turtle.Helper;
|
||||||
|
import kernel.turtle.TurtleMutex;
|
||||||
|
import kernel.turtle.Turtle;
|
||||||
|
import lib.turtle.InvManager;
|
||||||
|
import lib.CLIAppBase;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
@:build(macros.Binstore.includeBin("Turtle", ["turtle", "t"]))
|
||||||
|
class TurtleCtl extends CLIAppBase {
|
||||||
|
public function new() {
|
||||||
|
registerAsyncSubcommand("f", (args) -> {
|
||||||
|
return asynPerform(Turtle.forward, args.getInt("times") ?? 1);
|
||||||
|
}, [Optional(Int("times"))]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("b", (args) -> {
|
||||||
|
return asynPerform(Turtle.back, args.getInt("times") ?? 1);
|
||||||
|
}, [Optional(Int("times"))]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("l", (args) -> {
|
||||||
|
return asynPerform(Turtle.turnLeft, args.getInt("times") ?? 1);
|
||||||
|
}, [Optional(Int("times"))]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("r", (args) -> {
|
||||||
|
return asynPerform(Turtle.turnRight, args.getInt("times") ?? 1);
|
||||||
|
}, [Optional(Int("times"))]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("u", (args) -> {
|
||||||
|
return asynPerform(Turtle.up, args.getInt("times") ?? 1);
|
||||||
|
}, [Optional(Int("times"))]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("d", (args) -> {
|
||||||
|
return asynPerform(Turtle.down, args.getInt("times") ?? 1);
|
||||||
|
}, [Optional(Int("times"))]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("defrag", (args) -> {
|
||||||
|
return asynPerform(() -> {
|
||||||
|
// TODO: when defrag can fail return that error
|
||||||
|
InvManager.defrag();
|
||||||
|
return Success(null);
|
||||||
|
}, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
registerSyncSubcommand("fuel", (args) -> {
|
||||||
|
var lvl = Turtle.getFuelLevel();
|
||||||
|
var limit = Turtle.getFuelLimit();
|
||||||
|
handle.writeLine('${lvl}/${limit} (${(lvl / limit) * 100}%)');
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
registerAsyncSubcommand("fuel-sources", (args) -> {
|
||||||
|
return asynPerform(() -> {
|
||||||
|
var items = InvManager.getCombustableItems();
|
||||||
|
|
||||||
|
for (i in items) {
|
||||||
|
handle.writeLine(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Success(null);
|
||||||
|
}, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
registerAsyncSubcommand("refuel", (args) -> {
|
||||||
|
var refuelTo = Turtle.getFuelLimit();
|
||||||
|
var arg = args.getString("to");
|
||||||
|
if (arg != null) {
|
||||||
|
var split = arg.split("%");
|
||||||
|
|
||||||
|
if (split.length > 1) {
|
||||||
|
// Is percentage
|
||||||
|
var parsed = Std.parseFloat(split[0]);
|
||||||
|
|
||||||
|
if (parsed == null) {
|
||||||
|
handle.writeLine("Failed to parse ammount");
|
||||||
|
return Future.sync(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
refuelTo = Math.round(refuelTo * (parsed / 100));
|
||||||
|
} else {
|
||||||
|
// Is absolute
|
||||||
|
var parsed = Std.parseInt(arg);
|
||||||
|
|
||||||
|
if (parsed == null) {
|
||||||
|
handle.writeLine("Failed to parse ammount");
|
||||||
|
return Future.sync(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
refuelTo = parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return asynPerform(() -> {
|
||||||
|
InvManager.refuel(refuelTo, []);
|
||||||
|
|
||||||
|
return Success(null);
|
||||||
|
}, 1);
|
||||||
|
}, [Optional(String("to"))]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("dig", (args) -> {
|
||||||
|
var direction = args.getString("direction");
|
||||||
|
switch (direction) {
|
||||||
|
case "front" | "f":
|
||||||
|
return asynPerform(() -> Turtle.dig(Front), 1);
|
||||||
|
case "top" | "t" | "up" | "u":
|
||||||
|
return asynPerform(() -> Turtle.dig(Up), 1);
|
||||||
|
case "bot" | "bottom" | "b" | "down" | "d":
|
||||||
|
return asynPerform(() -> Turtle.dig(Down), 1);
|
||||||
|
default:
|
||||||
|
return Future.sync(false);
|
||||||
|
}
|
||||||
|
}, [String("direction")]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("tunnel", (args) -> {
|
||||||
|
var len = args.getInt("length");
|
||||||
|
return asynPerform(Helper.combine.bind([Turtle.digEmpty.bind(Front), Turtle.forward, Turtle.digEmpty.bind(Up)]), len);
|
||||||
|
}, [Int("length")]);
|
||||||
|
|
||||||
|
registerSyncSubcommand("inspect", (args) -> {
|
||||||
|
var res = Turtle.inspect(Front);
|
||||||
|
|
||||||
|
switch res {
|
||||||
|
case Failure(err):
|
||||||
|
handle.writeLine("Failed: " + err);
|
||||||
|
return false;
|
||||||
|
case Success(data):
|
||||||
|
handle.writeLine('Name: ${data.name}');
|
||||||
|
handle.writeLine("Tags:");
|
||||||
|
|
||||||
|
for (tag in data.tags.sortByName()) {
|
||||||
|
handle.writeLine(' ${tag}');
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.writeLine("State:");
|
||||||
|
handle.writeLine(data.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function asynPerform(op:Void->Outcome<Noise, String>, times:Int):Future<Bool> {
|
||||||
|
return new Future<Bool>((wakeup) -> {
|
||||||
|
if (times == 0) {
|
||||||
|
wakeup(false);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Turtle.isTurtle()) {
|
||||||
|
handle.write("This is not a turtle!");
|
||||||
|
wakeup(false);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handle.claimTurtleMutex()) {
|
||||||
|
handle.writeLine("Failed to claim mutex");
|
||||||
|
wakeup(false);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
TurtleMutex.runInTThread(() -> {
|
||||||
|
for (i in 0...times) {
|
||||||
|
switch op() {
|
||||||
|
case Success(_):
|
||||||
|
case Failure(failure):
|
||||||
|
handle.writeLine('Failed: $failure');
|
||||||
|
wakeup(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wakeup(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/bin/debug/Debug.hx
Normal file
41
src/bin/debug/Debug.hx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package bin.debug;
|
||||||
|
|
||||||
|
import kernel.log.Log;
|
||||||
|
import lib.turtle.InvManager;
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Use this to test whatever you are working on. It will also print debug statements.
|
||||||
|
IDK if you commit changes in this file. It will not be included in non debug build.
|
||||||
|
**/
|
||||||
|
#if debug
|
||||||
|
@:build(macros.Binstore.includeBin("Debug", ["dbg", "debug"]))
|
||||||
|
#end
|
||||||
|
class Debug implements IProcess {
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function run(handle:ProcessHandle) {
|
||||||
|
var link = Log.onLog.handle((line) -> {
|
||||||
|
handle.writeLine('[${line.level}] ${line.message}');
|
||||||
|
});
|
||||||
|
|
||||||
|
handle.addDeferFunc(() -> {
|
||||||
|
link.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add your stuff here
|
||||||
|
// -----
|
||||||
|
|
||||||
|
var rpc = new bin.debug.DebugRPC.DebugRPCImpl(1, "debug");
|
||||||
|
|
||||||
|
var a = rpc.addNumber(1, 2);
|
||||||
|
|
||||||
|
// rpc.addNumber(1,2).handle((e)->{
|
||||||
|
// Log.debug(e);
|
||||||
|
// handle.close();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// -----
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/bin/debug/DebugRPC.hx
Normal file
10
src/bin/debug/DebugRPC.hx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package bin.debug;
|
||||||
|
|
||||||
|
import macros.rpc.RPCBase;
|
||||||
|
|
||||||
|
interface DebugRPC {
|
||||||
|
function addNumber(a:Int, b:Int):Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:build(macros.rpc.RPC.buildRPC(DebugRPC))
|
||||||
|
class DebugRPCImpl extends RPCBase {}
|
||||||
27
src/bin/debug/DebugService.hx
Normal file
27
src/bin/debug/DebugService.hx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package bin.debug;
|
||||||
|
|
||||||
|
import bin.debug.DebugRPC.DebugRPCImpl;
|
||||||
|
import macros.rpc.RPC;
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
|
#if debug
|
||||||
|
@:build(macros.Binstore.includeBin("Debug SRV", ["dbg-srv", "debug-srv"]))
|
||||||
|
#end
|
||||||
|
class DebugService implements IProcess implements DebugRPC {
|
||||||
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function run(handle:ProcessHandle) {
|
||||||
|
this.handle = handle;
|
||||||
|
|
||||||
|
kernel.net.Net.registerProto("debug", (pack) -> {
|
||||||
|
DebugRPCImpl.handlePackage(this, pack);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addNumber(a:Int, b:Int):Int {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/bin/exporter/Exporter.hx
Normal file
67
src/bin/exporter/Exporter.hx
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package bin.exporter;
|
||||||
|
|
||||||
|
import kernel.net.Package.GenericPackage;
|
||||||
|
import kernel.peripherals.exports.RedstoneExport;
|
||||||
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
A service to expose local peripherals to the network.
|
||||||
|
**/
|
||||||
|
@:build(macros.Binstore.includeBin("Exporter", ["exporter"]))
|
||||||
|
class Exporter implements IProcess {
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function run(handle:ProcessHandle) {
|
||||||
|
if (handle.args.length < 2) {
|
||||||
|
handle.writeLine("Not enough args: <addr> <type>");
|
||||||
|
handle.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var addr = handle.args[0];
|
||||||
|
var expectedType = handle.args[1];
|
||||||
|
|
||||||
|
// Check if peripheral is present. Not the case for redstone.
|
||||||
|
if (expectedType != kernel.peripherals.Redstone.TYPE_NAME && !Peripheral.isPresent(addr)) {
|
||||||
|
handle.writeLine('Address: $addr not present');
|
||||||
|
handle.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var types = Peripheral.getTypes(addr);
|
||||||
|
|
||||||
|
// Check if the correct type is present. Not the case for redstone.
|
||||||
|
if (expectedType != kernel.peripherals.Redstone.TYPE_NAME && !types.contains(expectedType)) {
|
||||||
|
handle.writeLine('Expected type not machted on address: $addr. Wanted $expectedType got $types');
|
||||||
|
handle.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var peri = Peripheral.getFromType(addr, expectedType);
|
||||||
|
|
||||||
|
if (peri == null) {
|
||||||
|
handle.writeLine('Failed to create peripheral for address: $addr');
|
||||||
|
handle.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var handePackFunc:(GenericPackage) -> Bool = null;
|
||||||
|
|
||||||
|
// Cast to RPC class
|
||||||
|
// TODO: There must be a smarter way to do this.
|
||||||
|
switch expectedType {
|
||||||
|
case kernel.peripherals.Redstone.TYPE_NAME:
|
||||||
|
handePackFunc = (p) -> {
|
||||||
|
return RedstoneExport.handlePackage(cast peri, p);
|
||||||
|
};
|
||||||
|
// TODO: More peripherals
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.writeLine('Listening on export:$addr with type $expectedType');
|
||||||
|
|
||||||
|
// Listen for packages
|
||||||
|
kernel.net.Net.registerProto('export:$addr', (p) -> {
|
||||||
|
if (!handePackFunc(p)) {
|
||||||
|
handle.writeLine("Failed handle package on export");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
package bin.exporter;
|
|
||||||
|
|
||||||
import lib.exporter.Export;
|
|
||||||
import lib.exporter.IExportable;
|
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
|
||||||
import kernel.service.ServiceManager;
|
|
||||||
import lib.exporter.Import;
|
|
||||||
import lib.CLIAppBase;
|
|
||||||
|
|
||||||
class Res extends CLIAppBase {
|
|
||||||
public function new() {
|
|
||||||
registerAsyncSubcommand("get", (args) -> {
|
|
||||||
var url = args[0];
|
|
||||||
|
|
||||||
return Import.get(url).map((res) -> {
|
|
||||||
switch (res) {
|
|
||||||
case Success(data):
|
|
||||||
handle.writeLine(Std.string(data));
|
|
||||||
case Failure(err):
|
|
||||||
handle.writeLine("Error: ");
|
|
||||||
handle.writeLine(Std.string(err));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}, "<url>");
|
|
||||||
|
|
||||||
registerAsyncSubcommand("register", (args) -> {
|
|
||||||
var srv:Null<ResManager> = ServiceManager.get("resmgr");
|
|
||||||
|
|
||||||
var addr = args[0];
|
|
||||||
var name = args[1];
|
|
||||||
|
|
||||||
if (srv == null) {
|
|
||||||
handle.writeLine("Error: resmgr not found");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var perf:kernel.peripherals.Redstone = Peripheral.getRedstone(addr);
|
|
||||||
|
|
||||||
if (perf == null) {
|
|
||||||
handle.writeLine("Error: peripheral not found");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return srv.register(name, new Export(perf)).map((res) -> {
|
|
||||||
switch (res) {
|
|
||||||
case Success(_):
|
|
||||||
handle.writeLine("Success");
|
|
||||||
return true;
|
|
||||||
case Failure(err):
|
|
||||||
handle.writeLine("Error: ");
|
|
||||||
handle.writeLine(Std.string(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, "<addr> <name>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package bin.exporter;
|
|
||||||
|
|
||||||
import kernel.KernelSettings;
|
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
|
||||||
import lib.KVStore;
|
|
||||||
import lib.exporter.Request;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import lib.exporter.Export;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
import kernel.net.Package;
|
|
||||||
import kernel.net.Net;
|
|
||||||
import kernel.net.Package.GenericPackage;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
class ResManager implements Process {
|
|
||||||
private var handle:ProcessHandle;
|
|
||||||
private var exports:Map<String, Export> = [];
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
this.handle = handle;
|
|
||||||
Net.registerProto("res", handlePackage);
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function register(id:String, export:Export):Promise<Noise> {
|
|
||||||
if (exports.exists(id)) {
|
|
||||||
return Promise.reject(new Error("Ressource already exists: " + id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return registerName(id).next((success) -> {
|
|
||||||
exports.set(id, export);
|
|
||||||
persist();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handlePackage(pack:GenericPackage) {
|
|
||||||
var requestPack:Package<Request> = cast pack;
|
|
||||||
var id = requestPack.data.id;
|
|
||||||
|
|
||||||
if (!exports.exists(id)) {
|
|
||||||
requestPack.respond(lib.exporter.Response.NotFound);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var export = exports.get(id);
|
|
||||||
var response = export.handleRequest(requestPack.data);
|
|
||||||
|
|
||||||
requestPack.respond(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function registerName(id:String) {
|
|
||||||
var rpc = new SiteRessourceControllerRPC(KernelSettings.siteController);
|
|
||||||
return rpc.register(id, Net.networkID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function persist() {
|
|
||||||
var store = new KVStore("export");
|
|
||||||
|
|
||||||
var saveExports:Array<{name:String, addr:String, type:String}> = [for (k => v in this.exports) {name: k, addr: v.getAddr(), type: v.getType()}];
|
|
||||||
|
|
||||||
store.set("exports", saveExports);
|
|
||||||
|
|
||||||
store.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function load() {
|
|
||||||
var store = new KVStore("export");
|
|
||||||
|
|
||||||
var savedExports:Array<{name:String, addr:String, type:String}> = store.get("exports", []);
|
|
||||||
|
|
||||||
for (export in savedExports) {
|
|
||||||
var perph = Peripheral.getFromType(export.addr, export.type);
|
|
||||||
|
|
||||||
if (perph == null) {
|
|
||||||
handle.writeLine('Could not load export: ${export.name} on ${export.addr}');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// I dont know if cast is the best way to do this
|
|
||||||
// But since we know that this is a IExportable we can do this (I think)
|
|
||||||
exports.set(export.name, new Export(cast perph));
|
|
||||||
|
|
||||||
handle.writeLine('Loaded export: ${export.name} on ${export.addr}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
71
src/bin/ns/NameSystem.hx
Normal file
71
src/bin/ns/NameSystem.hx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package bin.ns;
|
||||||
|
|
||||||
|
import lib.KVStore;
|
||||||
|
import haxe.ds.StringMap;
|
||||||
|
import kernel.net.Package.NetworkID;
|
||||||
|
import bin.ns.NameSystemRPC.INameSystemRPC;
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
@:build(macros.Binstore.includeBin("NameSystem", ["ns", "namesystem"]))
|
||||||
|
class NameSystem implements IProcess implements INameSystemRPC {
|
||||||
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
|
private var idRecords:StringMap<NetworkID> = new StringMap();
|
||||||
|
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function run(handle:ProcessHandle) {
|
||||||
|
this.handle = handle;
|
||||||
|
|
||||||
|
this.load();
|
||||||
|
|
||||||
|
kernel.net.Net.registerProto("ns", (p) -> {
|
||||||
|
NameSystemRPC.handlePackage(this, p);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function load() {
|
||||||
|
var kv = new KVStore("NameSystem");
|
||||||
|
kv.load();
|
||||||
|
|
||||||
|
this.idRecords = kv.get("idRecords", new StringMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function save() {
|
||||||
|
var kv = new KVStore("NameSystem");
|
||||||
|
|
||||||
|
kv.set("idRecords", this.idRecords);
|
||||||
|
|
||||||
|
kv.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIDRecord(name:String, id:NetworkID):Noise {
|
||||||
|
this.idRecords.set(name, id);
|
||||||
|
this.save();
|
||||||
|
return Noise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIDRecord(name:String):Null<NetworkID> {
|
||||||
|
return this.idRecords.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeIDRecord(name:String):Noise {
|
||||||
|
this.idRecords.remove(name);
|
||||||
|
this.save();
|
||||||
|
return Noise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listIDRecords():Array<{name:String, id:NetworkID}> {
|
||||||
|
var rtn = [];
|
||||||
|
|
||||||
|
for (k => v in this.idRecords) {
|
||||||
|
rtn.push({name: k, id: v});
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/bin/ns/NameSystemCLI.hx
Normal file
71
src/bin/ns/NameSystemCLI.hx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package bin.ns;
|
||||||
|
|
||||||
|
import lib.CLIAppBase;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
@:build(macros.Binstore.includeBin("NameSystemCLI", ["ns-cli"]))
|
||||||
|
class NameSystemCLI extends CLIAppBase {
|
||||||
|
public function new() {
|
||||||
|
registerAsyncSubcommand("get", (args) -> {
|
||||||
|
var ns = NameSystemRPC.getDefault();
|
||||||
|
|
||||||
|
return ns.getIDRecord(args.getString("name")).map((r) -> {
|
||||||
|
switch r {
|
||||||
|
case Success(data):
|
||||||
|
handle.writeLine('Resolved: $data');
|
||||||
|
case Failure(failure):
|
||||||
|
handle.writeLine('Failed: $failure');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}, [String("name")]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("register", (args) -> {
|
||||||
|
var id = args.getInt("id");
|
||||||
|
var ns = NameSystemRPC.getDefault();
|
||||||
|
|
||||||
|
return ns.setIDRecord(args.getString("name"), id).map((r) -> {
|
||||||
|
switch r {
|
||||||
|
case Success(_):
|
||||||
|
handle.writeLine('Set');
|
||||||
|
case Failure(failure):
|
||||||
|
handle.writeLine('Failed: $failure');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}, [String("name"), Int("id")]);
|
||||||
|
|
||||||
|
registerAsyncSubcommand("list", (args) -> {
|
||||||
|
var ns = NameSystemRPC.getDefault();
|
||||||
|
|
||||||
|
return ns.listIDRecords().map((r) -> {
|
||||||
|
switch r {
|
||||||
|
case Success(data):
|
||||||
|
handle.writeLine('List: $data');
|
||||||
|
case Failure(failure):
|
||||||
|
handle.writeLine('Failed: $failure');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
registerAsyncSubcommand("unregister", (args) -> {
|
||||||
|
var ns = NameSystemRPC.getDefault();
|
||||||
|
|
||||||
|
return ns.removeIDRecord(args.getString("name")).map((r) -> {
|
||||||
|
switch r {
|
||||||
|
case Success(_):
|
||||||
|
handle.writeLine('Unregisterd');
|
||||||
|
case Failure(failure):
|
||||||
|
handle.writeLine('Failed: $failure');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}, [String("name")]);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/bin/ns/NameSystemRPC.hx
Normal file
31
src/bin/ns/NameSystemRPC.hx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package bin.ns;
|
||||||
|
|
||||||
|
import kernel.KernelSettings;
|
||||||
|
import macros.rpc.RPCBase;
|
||||||
|
import kernel.net.Package.NetworkID;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
interface INameSystemRPC {
|
||||||
|
function setIDRecord(name:String, id:NetworkID):Noise;
|
||||||
|
function getIDRecord(name:String):Null<NetworkID>;
|
||||||
|
function removeIDRecord(name:String):Noise;
|
||||||
|
function listIDRecords():Array<{name:String, id:NetworkID}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:build(macros.rpc.RPC.buildRPC(INameSystemRPC))
|
||||||
|
class NameSystemRPC extends RPCBase {
|
||||||
|
public static function getDefault():NameSystemRPC {
|
||||||
|
return new NameSystemRPC(KernelSettings.nameServer, "ns");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function resolve(input:String):Promise<Null<NetworkID>> {
|
||||||
|
if (input == "12345") {
|
||||||
|
return Promise.resolve(Std.parseInt(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ns = getDefault();
|
||||||
|
|
||||||
|
return ns.getIDRecord(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package bin.pathfinder;
|
package bin.pathfinder;
|
||||||
|
|
||||||
import lib.Pos3;
|
import lib.WorldPos;
|
||||||
import lib.ui.elements.UIElement;
|
import lib.ui.elements.IUIElement;
|
||||||
import lib.ui.elements.TextElement;
|
import lib.ui.elements.TextElement;
|
||||||
import lib.ui.elements.RootElement;
|
import lib.ui.elements.RootElement;
|
||||||
import kernel.ui.WindowContext;
|
import kernel.ui.WindowContext;
|
||||||
import kernel.ps.ProcessHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
class PFClient implements Process {
|
class PFClient implements IProcess {
|
||||||
private var handle:ProcessHandle;
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
private var ctx:WindowContext;
|
private var ctx:WindowContext;
|
||||||
@@ -36,9 +36,9 @@ class PFClient implements Process {
|
|||||||
|
|
||||||
private function render() {
|
private function render() {
|
||||||
var acc = kernel.gps.GPS.getAccuracy();
|
var acc = kernel.gps.GPS.getAccuracy();
|
||||||
var pos:Pos3 = kernel.gps.GPS.getPosition() ?? {x: 0, y: 0, z: 0};
|
var pos:WorldPos = kernel.gps.GPS.getPosition() ?? {x: 0, y: 0, z: 0};
|
||||||
|
|
||||||
var childre:Array<UIElement> = [
|
var childre:Array<IUIElement> = [
|
||||||
new TextElement('Acc: ${acc}'),
|
new TextElement('Acc: ${acc}'),
|
||||||
new TextElement('Pos: X:${pos.x} Y:${pos.y} Z:${pos.z}'),
|
new TextElement('Pos: X:${pos.x} Y:${pos.y} Z:${pos.z}'),
|
||||||
new TextElement('UPDATE', {
|
new TextElement('UPDATE', {
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
package bin.srsc;
|
|
||||||
|
|
||||||
import kernel.KernelSettings;
|
|
||||||
import kernel.net.Package.NetworkID;
|
|
||||||
import lib.CLIAppBase;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
class CLI extends CLIAppBase {
|
|
||||||
public function new() {
|
|
||||||
registerAsyncSubcommand("get", (args) -> {
|
|
||||||
if (args.length < 1) {
|
|
||||||
handle.writeLine("Not enough arguments");
|
|
||||||
return Future.sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpc = new SiteRessourceControllerRPC(KernelSettings.siteController);
|
|
||||||
|
|
||||||
return rpc.get(args[0]).map((res) -> {
|
|
||||||
switch (res) {
|
|
||||||
case Success(data):
|
|
||||||
if (data == null) {
|
|
||||||
handle.writeLine("Not found");
|
|
||||||
} else {
|
|
||||||
handle.writeLine("Found: " + data);
|
|
||||||
}
|
|
||||||
case Failure(error):
|
|
||||||
handle.writeLine("Error: " + error);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}, "<name>");
|
|
||||||
|
|
||||||
registerAsyncSubcommand("register", (args) -> {
|
|
||||||
if (args.length < 2) {
|
|
||||||
handle.writeLine("Not enough arguments");
|
|
||||||
return Future.sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var id:NetworkID = Std.parseInt(args[1]);
|
|
||||||
if (id == null) {
|
|
||||||
handle.writeLine("Invalid id");
|
|
||||||
return Future.sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpc = new SiteRessourceControllerRPC(KernelSettings.siteController);
|
|
||||||
|
|
||||||
return rpc.register(args[0], id).map((res) -> {
|
|
||||||
switch (res) {
|
|
||||||
case Success(data):
|
|
||||||
handle.writeLine("Success");
|
|
||||||
case Failure(error):
|
|
||||||
handle.writeLine("Error: " + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}, "<name> <id>");
|
|
||||||
|
|
||||||
registerAsyncSubcommand("unregister", (args) -> {
|
|
||||||
if (args.length < 1) {
|
|
||||||
handle.writeLine("Not enough arguments");
|
|
||||||
return Future.sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpc = new SiteRessourceControllerRPC(KernelSettings.siteController);
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
return Future.sync(true);
|
|
||||||
// return rpc.unregister(args[0]).map((res) -> {
|
|
||||||
// switch (res) {
|
|
||||||
// case Success(_):
|
|
||||||
// handle.writeLine("Success");
|
|
||||||
// case Failure(error):
|
|
||||||
// handle.writeLine("Error: " + error);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return true;
|
|
||||||
// });
|
|
||||||
}, "<name>");
|
|
||||||
|
|
||||||
registerAsyncSubcommand("list", (args) -> {
|
|
||||||
var rpc = new SiteRessourceControllerRPC(KernelSettings.siteController);
|
|
||||||
|
|
||||||
return rpc.list().map((res) -> {
|
|
||||||
switch (res) {
|
|
||||||
case Success(data):
|
|
||||||
for (name in data) {
|
|
||||||
handle.writeLine(name);
|
|
||||||
}
|
|
||||||
case Failure(error):
|
|
||||||
handle.writeLine("Error: " + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package bin.srsc;
|
|
||||||
|
|
||||||
import macros.rpc.RPC;
|
|
||||||
import lib.KVStore;
|
|
||||||
import kernel.net.Package;
|
|
||||||
import kernel.ps.ProcessHandle;
|
|
||||||
import kernel.ps.Process;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The SiteRessourceController is responsible for the management of ressources on the site.
|
|
||||||
It makes sure that ressources are have a unique id and that they are not duplicated.
|
|
||||||
It also keeps track of the responsible NetID for each ressource. Kinda like a DNS.
|
|
||||||
**/
|
|
||||||
@:build(macros.rpc.RPC.buildRPC())
|
|
||||||
class SiteRessourceController implements Process {
|
|
||||||
private var handle:ProcessHandle;
|
|
||||||
private var ressources:Map<String, NetworkID>;
|
|
||||||
|
|
||||||
public function new() {}
|
|
||||||
|
|
||||||
public function run(handle:ProcessHandle) {
|
|
||||||
this.handle = handle;
|
|
||||||
|
|
||||||
load();
|
|
||||||
|
|
||||||
RPC.generateRPCPackageHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
@rpc
|
|
||||||
public function register(name:String, netID:NetworkID):Bool {
|
|
||||||
if (ressources.exists(name) && ressources.get(name) != netID) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ressources.set(name, netID);
|
|
||||||
save();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@rpc
|
|
||||||
public function unregister(name:String):Void {
|
|
||||||
if (ressources.exists(name)) {
|
|
||||||
ressources.remove(name);
|
|
||||||
}
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@rpc
|
|
||||||
public function get(name:String):Null<NetworkID> {
|
|
||||||
return ressources.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@rpc
|
|
||||||
public function list():Array<String> {
|
|
||||||
return [for (k in ressources.keys()) k];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function load() {
|
|
||||||
var store = KVStore.getStoreForClass();
|
|
||||||
var data:Null<Map<String, NetworkID>> = store.get("ressources");
|
|
||||||
|
|
||||||
if (data != null) {
|
|
||||||
this.ressources = data;
|
|
||||||
} else {
|
|
||||||
this.ressources = new Map<String, NetworkID>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function save() {
|
|
||||||
var store = KVStore.getStoreForClass();
|
|
||||||
store.set("ressources", this.ressources);
|
|
||||||
store.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
158
src/bin/turtle/CircleMine.hx
Normal file
158
src/bin/turtle/CircleMine.hx
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
package bin.turtle;
|
||||||
|
|
||||||
|
import kernel.turtle.Turtle;
|
||||||
|
import lib.turtle.TurtleAppBase;
|
||||||
|
|
||||||
|
@:build(macros.Binstore.includeBin("Circle Mine", ["circle-mine", "cm"]))
|
||||||
|
class CircleMine extends TurtleAppBase {
|
||||||
|
private var rings:Int;
|
||||||
|
private var skip:Int = 0;
|
||||||
|
private var depth:Int = 0;
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
super(initFunc, turtleFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initFunc() {
|
||||||
|
if (handle.args.length < 1) {
|
||||||
|
handle.writeLine("Not enough args");
|
||||||
|
handle.close(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rings = Std.parseInt(handle.args[0]);
|
||||||
|
if (this.rings == null) {
|
||||||
|
handle.writeLine("Failed to parse args");
|
||||||
|
handle.close(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle.args.length > 1) {
|
||||||
|
this.skip = Std.parseInt(handle.args[1]);
|
||||||
|
if (this.skip == null) {
|
||||||
|
handle.writeLine("Failed to parse args");
|
||||||
|
handle.close(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function turtleFunc() {
|
||||||
|
// Go down 1 layer
|
||||||
|
if (skip == 0) {
|
||||||
|
Turtle.dig(Down);
|
||||||
|
Turtle.down();
|
||||||
|
Turtle.dig(Down);
|
||||||
|
} else {
|
||||||
|
// Move to outer ring
|
||||||
|
for (i in 0...(skip * 3) - 1) {
|
||||||
|
Turtle.forward();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start mining
|
||||||
|
for (i in skip...(rings + skip)) {
|
||||||
|
if (i == 0) {
|
||||||
|
center();
|
||||||
|
handle.writeLine("Center done");
|
||||||
|
} else {
|
||||||
|
circle(i * 3 + 1);
|
||||||
|
handle.writeLine('Ring $i done');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go back to starting pos.
|
||||||
|
for (i in 0...((rings + skip) * 3 - 1)) {
|
||||||
|
Turtle.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function circle(radius:Int) {
|
||||||
|
step();
|
||||||
|
step();
|
||||||
|
frontDig();
|
||||||
|
|
||||||
|
// Do a 1/2 of a side of a ring
|
||||||
|
Turtle.turnRight();
|
||||||
|
for (i in 0...radius) {
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the other 2 sides
|
||||||
|
for (s in 0...3) {
|
||||||
|
Turtle.turnRight();
|
||||||
|
for (i in 0...radius) {
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
middle();
|
||||||
|
|
||||||
|
for (i in 0...radius) {
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete the 1/2 of the first side
|
||||||
|
Turtle.turnRight();
|
||||||
|
for (i in 0...radius) {
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
Turtle.turnLeft();
|
||||||
|
Turtle.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function middle() {
|
||||||
|
Turtle.turnRight();
|
||||||
|
|
||||||
|
Turtle.dig(Front);
|
||||||
|
Turtle.down();
|
||||||
|
Turtle.dig(Front);
|
||||||
|
|
||||||
|
Turtle.turnLeft();
|
||||||
|
Turtle.turnLeft();
|
||||||
|
|
||||||
|
Turtle.dig(Front);
|
||||||
|
Turtle.up();
|
||||||
|
Turtle.dig(Front);
|
||||||
|
|
||||||
|
Turtle.turnRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function step() {
|
||||||
|
Turtle.dig(Front);
|
||||||
|
Turtle.forward();
|
||||||
|
Turtle.dig(Down);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function frontDig() {
|
||||||
|
Turtle.dig(Front);
|
||||||
|
Turtle.down();
|
||||||
|
Turtle.dig(Front);
|
||||||
|
Turtle.up();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function center() {
|
||||||
|
Turtle.dig(Down);
|
||||||
|
step();
|
||||||
|
frontDig();
|
||||||
|
Turtle.turnRight();
|
||||||
|
|
||||||
|
for (i in 0...3) {
|
||||||
|
step();
|
||||||
|
Turtle.turnRight();
|
||||||
|
step();
|
||||||
|
Turtle.turnLeft();
|
||||||
|
frontDig();
|
||||||
|
Turtle.turnRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
step();
|
||||||
|
Turtle.turnRight();
|
||||||
|
Turtle.forward();
|
||||||
|
Turtle.turnLeft();
|
||||||
|
Turtle.forward();
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/bin/turtle/CircleMinePlan.hx
Normal file
56
src/bin/turtle/CircleMinePlan.hx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package bin.turtle;
|
||||||
|
|
||||||
|
import lib.turtle.planner.Plan;
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
|
@:build(macros.Binstore.includeBin("Circle Mine Plan", ["cmp"]))
|
||||||
|
class CircleMinePlan implements IProcess {
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function run(handle:ProcessHandle) {
|
||||||
|
var rings:Int = 3;
|
||||||
|
var skip:Int = 0;
|
||||||
|
|
||||||
|
var p = Plan.newPlan();
|
||||||
|
|
||||||
|
p = p.repeat([Forward], (skip * 3) - 1); // Move to outer ring or stay if none skiped
|
||||||
|
|
||||||
|
for (i in skip...(rings + skip)) {
|
||||||
|
if (i == 0) {
|
||||||
|
p = p.act([Clear(Down), Down, Clear(Down)]) // Move down a layer
|
||||||
|
.subplan(center());
|
||||||
|
} else {
|
||||||
|
p = p.subplan(circle(i * 3 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.repeat([Back], (rings + skip) * 3 - 1);
|
||||||
|
|
||||||
|
p.begin(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function circle(radius:Int):Plan {
|
||||||
|
return Plan.newPlan()
|
||||||
|
.act([FullTunnel, FullTunnel, HalfTunnel])
|
||||||
|
.act([TurnRight])
|
||||||
|
.repeat([FullTunnel], radius)
|
||||||
|
.repateSubplan(Plan.newPlan().act([TurnRight]).repeat([FullTunnel], radius).act([
|
||||||
|
TurnRight, Clear(Front), Down, Clear(Front), TurnLeft, TurnLeft, Clear(Front), Up, Clear(Front), TurnRight
|
||||||
|
]).repeat([FullTunnel], radius), 3)
|
||||||
|
.act([TurnRight])
|
||||||
|
.repeat([FullTunnel], radius)
|
||||||
|
.act([TurnLeft, Forward]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function center():Plan {
|
||||||
|
return Plan.newPlan()
|
||||||
|
.act([Clear(Down)])
|
||||||
|
.act([FullTunnel])
|
||||||
|
.act([Clear(Front), Down, Clear(Front), Up])
|
||||||
|
.act([TurnRight])
|
||||||
|
.repeat([FullTunnel, TurnRight, FullTunnel, TurnLeft, HalfTunnel, TurnRight], 3)
|
||||||
|
.act([FullTunnel])
|
||||||
|
.act([TurnRight, Forward, TurnLeft, Forward]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,9 @@ package bin.turtle;
|
|||||||
|
|
||||||
import kernel.turtle.TurtleMutex;
|
import kernel.turtle.TurtleMutex;
|
||||||
import kernel.ps.ProcessHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
class Patrol implements Process {
|
class Patrol implements IProcess {
|
||||||
private var handle:ProcessHandle;
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package kernel;
|
package kernel;
|
||||||
|
|
||||||
|
#if debug
|
||||||
|
import lib.Debug;
|
||||||
|
#end
|
||||||
import kernel.service.ServiceManager;
|
import kernel.service.ServiceManager;
|
||||||
import kernel.fs.FS;
|
import kernel.fs.FS;
|
||||||
import kernel.gps.GPS;
|
import kernel.gps.GPS;
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
import kernel.net.Routing;
|
import kernel.net.Routing;
|
||||||
import lib.Debug;
|
|
||||||
import kernel.ui.WindowManager;
|
import kernel.ui.WindowManager;
|
||||||
import kernel.net.Net;
|
import kernel.net.Net;
|
||||||
|
|
||||||
@@ -29,7 +31,9 @@ class Init {
|
|||||||
KernelEvents.shutdown();
|
KernelEvents.shutdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if debug
|
||||||
Debug.printBuildInfo();
|
Debug.printBuildInfo();
|
||||||
|
#end
|
||||||
|
|
||||||
if (!FS.exists("/var/ns")) {
|
if (!FS.exists("/var/ns")) {
|
||||||
FS.makeDir("/var/ns");
|
FS.makeDir("/var/ns");
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import kernel.turtle.TurtleMutex;
|
|||||||
import kernel.turtle.Turtle;
|
import kernel.turtle.Turtle;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import cc.HTTP.HTTPResponse;
|
import cc.HTTP.HTTPResponse;
|
||||||
import lua.TableTools;
|
import lua.TableTools;
|
||||||
import lua.Coroutine;
|
import lua.Coroutine;
|
||||||
@@ -38,11 +38,11 @@ class KernelEvents {
|
|||||||
distance:Null<Float>
|
distance:Null<Float>
|
||||||
}>;
|
}>;
|
||||||
public static var onMonitorResize(default, null):Signal<String>;
|
public static var onMonitorResize(default, null):Signal<String>;
|
||||||
public static var onMonitorTouch(default, null):Signal<{addr:String, pos:Pos}>;
|
public static var onMonitorTouch(default, null):Signal<{addr:String, pos:ScreenPos}>;
|
||||||
public static var onMouseClick(default, null):Signal<{button:ButtonType, pos:Pos}>;
|
public static var onMouseClick(default, null):Signal<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public static var onMouseDrag(default, null):Signal<{button:ButtonType, pos:Pos}>;
|
public static var onMouseDrag(default, null):Signal<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public static var onMouseScroll(default, null):Signal<{dir:Int, pos:Pos}>;
|
public static var onMouseScroll(default, null):Signal<{dir:Int, pos:ScreenPos}>;
|
||||||
public static var onMouseUp(default, null):Signal<{button:ButtonType, pos:Pos}>;
|
public static var onMouseUp(default, null):Signal<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public static var onPaste(default, null):Signal<String>;
|
public static var onPaste(default, null):Signal<String>;
|
||||||
public static var onPeripheral(default, null):Signal<String>;
|
public static var onPeripheral(default, null):Signal<String>;
|
||||||
public static var onPeripheralDetach(default, null):Signal<String>;
|
public static var onPeripheralDetach(default, null):Signal<String>;
|
||||||
@@ -75,11 +75,11 @@ class KernelEvents {
|
|||||||
distance:Null<Float>
|
distance:Null<Float>
|
||||||
}> = Signal.trigger();
|
}> = Signal.trigger();
|
||||||
private static final onMonitorResizeTrigger:SignalTrigger<String> = Signal.trigger();
|
private static final onMonitorResizeTrigger:SignalTrigger<String> = Signal.trigger();
|
||||||
private static final onMonitorTouchTrigger:SignalTrigger<{addr:String, pos:Pos}> = Signal.trigger();
|
private static final onMonitorTouchTrigger:SignalTrigger<{addr:String, pos:ScreenPos}> = Signal.trigger();
|
||||||
private static final onMouseClickTrigger:SignalTrigger<{button:ButtonType, pos:Pos}> = Signal.trigger();
|
private static final onMouseClickTrigger:SignalTrigger<{button:ButtonType, pos:ScreenPos}> = Signal.trigger();
|
||||||
private static final onMouseDragTrigger:SignalTrigger<{button:ButtonType, pos:Pos}> = Signal.trigger();
|
private static final onMouseDragTrigger:SignalTrigger<{button:ButtonType, pos:ScreenPos}> = Signal.trigger();
|
||||||
private static final onMouseScrollTrigger:SignalTrigger<{dir:Int, pos:Pos}> = Signal.trigger();
|
private static final onMouseScrollTrigger:SignalTrigger<{dir:Int, pos:ScreenPos}> = Signal.trigger();
|
||||||
private static final onMouseUpTrigger:SignalTrigger<{button:ButtonType, pos:Pos}> = Signal.trigger();
|
private static final onMouseUpTrigger:SignalTrigger<{button:ButtonType, pos:ScreenPos}> = Signal.trigger();
|
||||||
private static final onPasteTrigger:SignalTrigger<String> = Signal.trigger();
|
private static final onPasteTrigger:SignalTrigger<String> = Signal.trigger();
|
||||||
private static final onPeripheralTrigger:SignalTrigger<String> = Signal.trigger();
|
private static final onPeripheralTrigger:SignalTrigger<String> = Signal.trigger();
|
||||||
private static final onPeripheralDetachTrigger:SignalTrigger<String> = Signal.trigger();
|
private static final onPeripheralDetachTrigger:SignalTrigger<String> = Signal.trigger();
|
||||||
|
|||||||
@@ -39,20 +39,20 @@ class KernelSettings {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var siteController(get, set):NetworkID;
|
public static var nameServer(get, set):NetworkID;
|
||||||
private static var _siteController:NetworkID = get("siteController");
|
private static var _nameServer:NetworkID = get("nameServer");
|
||||||
|
|
||||||
private static function get_siteController():NetworkID {
|
private static function get_nameServer():NetworkID {
|
||||||
return _siteController;
|
return _nameServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function set_siteController(value:NetworkID):NetworkID {
|
private static function set_nameServer(value:NetworkID):NetworkID {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return get_siteController();
|
return get_nameServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
set("siteController", value);
|
set("nameServer", value);
|
||||||
_siteController = value;
|
_nameServer = value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package kernel;
|
package kernel;
|
||||||
|
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import kernel.ui.TermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
import cc.Term;
|
import cc.Term;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
@@ -11,7 +11,7 @@ using tink.CoreApi;
|
|||||||
/**
|
/**
|
||||||
Represents the main computer screen.
|
Represents the main computer screen.
|
||||||
**/
|
**/
|
||||||
class MainTerm implements TermWriteable {
|
class MainTerm implements ITermWriteable {
|
||||||
/**
|
/**
|
||||||
Depends on: KernelEvents,
|
Depends on: KernelEvents,
|
||||||
**/
|
**/
|
||||||
@@ -39,7 +39,7 @@ class MainTerm implements TermWriteable {
|
|||||||
Term.scroll(y);
|
Term.scroll(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCursorPos():Pos {
|
public function getCursorPos():ScreenPos {
|
||||||
var rtn = Term.getCursorPos();
|
var rtn = Term.getCursorPos();
|
||||||
return {
|
return {
|
||||||
x: rtn.x - 1,
|
x: rtn.x - 1,
|
||||||
@@ -60,7 +60,7 @@ class MainTerm implements TermWriteable {
|
|||||||
Term.setCursorBlink(blink);
|
Term.setCursorBlink(blink);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSize():Pos {
|
public function getSize():ScreenPos {
|
||||||
var rtn = Term.getSize();
|
var rtn = Term.getSize();
|
||||||
return {
|
return {
|
||||||
x: rtn.width,
|
x: rtn.width,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package kernel.binstore;
|
package kernel.binstore;
|
||||||
|
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Represents a callable program.
|
Represents a callable program.
|
||||||
**/
|
**/
|
||||||
typedef Bin = {
|
typedef Bin = {
|
||||||
c:Void->Process,
|
c:Void->IProcess,
|
||||||
name:String,
|
name:String,
|
||||||
aliases:Array<String>,
|
aliases:Array<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package kernel.binstore;
|
package kernel.binstore;
|
||||||
|
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
import macros.Binstore;
|
import macros.Binstore;
|
||||||
|
|
||||||
class BinStore {
|
class BinStore {
|
||||||
@@ -13,7 +13,7 @@ class BinStore {
|
|||||||
return bins;
|
return bins;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function instantiate(alias:String):Null<Process> {
|
public static function instantiate(alias:String):Null<IProcess> {
|
||||||
for (bin in bins) {
|
for (bin in bins) {
|
||||||
for (a in bin.aliases) {
|
for (a in bin.aliases) {
|
||||||
if (a == alias) {
|
if (a == alias) {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package kernel.gps;
|
package kernel.gps;
|
||||||
|
|
||||||
|
import lib.SingleTimeoutPromise;
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
import lib.KVStore;
|
import lib.KVStore;
|
||||||
import kernel.net.Net;
|
import kernel.net.Net;
|
||||||
import kernel.net.INetworkInterface;
|
import kernel.net.INetworkInterface;
|
||||||
import kernel.net.Package;
|
import kernel.net.Package;
|
||||||
import lib.Pos3;
|
import lib.WorldPos;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
@@ -15,20 +16,22 @@ using tink.CoreApi;
|
|||||||
You need at least 3 computers that know their position to determine the position of the computer.
|
You need at least 3 computers that know their position to determine the position of the computer.
|
||||||
**/
|
**/
|
||||||
class GPS {
|
class GPS {
|
||||||
|
private static inline final TIMEOUT:Int = 1;
|
||||||
|
|
||||||
private static var shouldRespond = true;
|
private static var shouldRespond = true;
|
||||||
private static var shouldDoWholeNumberCheck = true;
|
private static var shouldDoWholeNumberCheck = true;
|
||||||
private static var posAccuracy = 0; // 0 = unkown, 1 = (ins,best guess), 2 = (stored/manual,should be right), 3 = (gps,confirmed)
|
private static var posAccuracy = 0; // 0 = unkown, 1 = (ins,best guess), 2 = (stored/manual,should be right), 3 = (gps,confirmed)
|
||||||
private static var cachedPosition:Pos3;
|
private static var cachedPosition:WorldPos;
|
||||||
private static var lastPositionResponse:Array<{pos:Pos3, dist:Float}> = [];
|
private static var lastPositionResponse:Array<{pos:WorldPos, dist:Float}> = [];
|
||||||
|
|
||||||
private static var futureResolve:(pos:Null<Pos3>) -> Void = null;
|
private static final locatePromise:SingleTimeoutPromise<WorldPos> = new SingleTimeoutPromise(TIMEOUT, brodcastPositionRequest);
|
||||||
|
|
||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
private static function init() {
|
private static function init() {
|
||||||
loadCachedPosition();
|
loadCachedPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setManualPosition(pos:Pos3) {
|
public static function setManualPosition(pos:WorldPos) {
|
||||||
var kvstore = new KVStore("gps");
|
var kvstore = new KVStore("gps");
|
||||||
kvstore.set("mpos", pos);
|
kvstore.set("mpos", pos);
|
||||||
kvstore.save();
|
kvstore.save();
|
||||||
@@ -40,12 +43,12 @@ class GPS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@:allow(kernel.gps.INS)
|
@:allow(kernel.gps.INS)
|
||||||
private static function setINSPosition(pos:Pos3) {
|
private static function setINSPosition(pos:WorldPos) {
|
||||||
cachedPosition = pos;
|
cachedPosition = pos;
|
||||||
posAccuracy = 1;
|
posAccuracy = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getPosition():Null<Pos3> {
|
public static function getPosition():Null<WorldPos> {
|
||||||
return cachedPosition;
|
return cachedPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,18 +61,8 @@ class GPS {
|
|||||||
posAccuracy = 0;
|
posAccuracy = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function locate():Future<Null<Pos3>> {
|
public static function locate():Promise<WorldPos> {
|
||||||
// TODO: implenet a timeout
|
return locatePromise.request();
|
||||||
// TODO: dont send a request twice if the last one is still pending or we moved
|
|
||||||
return new Future<Null<Pos3>>((resolve) -> {
|
|
||||||
futureResolve = resolve;
|
|
||||||
sendPositionRequest();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function resolveFuture(pos:Null<Pos3>) {
|
|
||||||
futureResolve(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function persistCachedPositon() {
|
private static function persistCachedPositon() {
|
||||||
@@ -85,8 +78,8 @@ class GPS {
|
|||||||
var kvstore = new KVStore("gps");
|
var kvstore = new KVStore("gps");
|
||||||
kvstore.load();
|
kvstore.load();
|
||||||
|
|
||||||
var mPos:Null<Pos3> = kvstore.get("mpos"); // Manual set position
|
var mPos:Null<WorldPos> = kvstore.get("mpos"); // Manual set position
|
||||||
var cPos:Null<Pos3> = kvstore.get("cpos"); // Cached position
|
var cPos:Null<WorldPos> = kvstore.get("cpos"); // Cached position
|
||||||
|
|
||||||
if (mPos != null && cPos != null && mPos == cPos) {
|
if (mPos != null && cPos != null && mPos == cPos) {
|
||||||
// Both are the same, so we can use the cached position
|
// Both are the same, so we can use the cached position
|
||||||
@@ -117,12 +110,17 @@ class GPS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function sendPositionRequest() {
|
private static function brodcastPositionRequest() {
|
||||||
Net.brodcastGPSRequest();
|
Net.brodcastGPSRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@:allow(kernel.net.Net)
|
@:allow(kernel.net.Net)
|
||||||
private static function handlePackage(pack:Package<Noise>, dist:Float, iface:INetworkInterface) {
|
private static function handlePackage(pack:Package<Noise>, dist:Null<Float>, iface:INetworkInterface) {
|
||||||
|
if (dist == null) {
|
||||||
|
// Message comes from another dimension and has no distance.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (pack.type) {
|
switch (pack.type) {
|
||||||
case GPSRequest:
|
case GPSRequest:
|
||||||
if (!shouldRespond)
|
if (!shouldRespond)
|
||||||
@@ -132,13 +130,13 @@ class GPS {
|
|||||||
if (cachedPosition == null)
|
if (cachedPosition == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var response = new Package(Net.networkID, pack.fromID, pack.msgID, GPSResponse(cachedPosition), null, 0);
|
var response = new Package(Net.networkID, pack.fromID, pack.msgID, GPSResponse(cachedPosition.x, cachedPosition.y, cachedPosition.z,), null, 0);
|
||||||
iface.send(pack.fromID, Net.networkID, response);
|
iface.send(pack.fromID, Net.networkID, response);
|
||||||
case GPSResponse(pos):
|
case GPSResponse(x, y, z):
|
||||||
if (lastPositionResponse.contains({pos: pos, dist: dist}))
|
if (lastPositionResponse.contains({pos: {x: x, y: y, z: z}, dist: dist}))
|
||||||
return; // Ignore duplicate responses
|
return; // Ignore duplicate responses
|
||||||
|
|
||||||
lastPositionResponse.push({pos: pos, dist: dist});
|
lastPositionResponse.push({pos: {x: x, y: y, z: z}, dist: dist});
|
||||||
|
|
||||||
// TODO: wait for a few seconds before calculating the position, so we can get more responses
|
// TODO: wait for a few seconds before calculating the position, so we can get more responses
|
||||||
|
|
||||||
@@ -158,12 +156,12 @@ class GPS {
|
|||||||
cachedPosition = calculatedPosition;
|
cachedPosition = calculatedPosition;
|
||||||
posAccuracy = 3;
|
posAccuracy = 3;
|
||||||
|
|
||||||
resolveFuture(calculatedPosition);
|
locatePromise.resolve(calculatedPosition);
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function calculatePosition():Null<Pos3> {
|
private static function calculatePosition():Null<WorldPos> {
|
||||||
if (lastPositionResponse.length < 3)
|
if (lastPositionResponse.length < 3)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -219,7 +217,7 @@ class GPS {
|
|||||||
/**
|
/**
|
||||||
Determines the position(s) of a point given 3 other points and the distance to each of them.
|
Determines the position(s) of a point given 3 other points and the distance to each of them.
|
||||||
**/
|
**/
|
||||||
private static function trilateration(p1:Pos3, p2:Pos3, p3:Pos3, r1:Float, r2:Float, r3:Float):Pair<Pos3, Pos3> {
|
private static function trilateration(p1:WorldPos, p2:WorldPos, p3:WorldPos, r1:Float, r2:Float, r3:Float):Pair<WorldPos, WorldPos> {
|
||||||
var a2b = p2 - p1;
|
var a2b = p2 - p1;
|
||||||
var a2c = p3 - p1;
|
var a2c = p3 - p1;
|
||||||
|
|
||||||
@@ -228,7 +226,7 @@ class GPS {
|
|||||||
var i = ex.dot(a2c);
|
var i = ex.dot(a2c);
|
||||||
var ey = (a2c - ex * i).normalize();
|
var ey = (a2c - ex * i).normalize();
|
||||||
var j = ey.dot(a2c);
|
var j = ey.dot(a2c);
|
||||||
var ez = ex.cross(ey);
|
var ez:WorldPos = ex.cross(ey);
|
||||||
|
|
||||||
var x = (r1 * r1 - r2 * r2 + d * d) / (2 * d);
|
var x = (r1 * r1 - r2 * r2 + d * d) / (2 * d);
|
||||||
var y = (r1 * r1 - r3 * r3 - x * x + (x - i) * (x - i) + j * j) / (2 * j);
|
var y = (r1 * r1 - r3 * r3 - x * x + (x - i) * (x - i) + j * j) / (2 * j);
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package kernel.gps;
|
package kernel.gps;
|
||||||
|
|
||||||
import kernel.log.Log;
|
import lib.SinglePromise;
|
||||||
import kernel.turtle.Turtle;
|
import kernel.turtle.Turtle;
|
||||||
import lib.Pos3;
|
import lib.WorldPos;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class INS {
|
class INS {
|
||||||
private static var heading:Null<Pos3> = null;
|
private static var heading:Null<WorldPos> = null;
|
||||||
private static var alingment:Int = 1; // 0 = degraded, 1 = not aligned, 2 = aligned
|
private static var alingment:Int = 1; // 0 = degraded, 1 = not aligned, 2 = aligned
|
||||||
|
private static final alignPromise:SinglePromise<Noise> = new SinglePromise(startAlign);
|
||||||
|
|
||||||
@:allow(kernel.turtle.Turtle)
|
@:allow(kernel.turtle.Turtle)
|
||||||
private static function moveForward() {
|
private static function moveForward() {
|
||||||
@@ -68,7 +69,10 @@ class INS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function move(dir:Null<Pos3>) {
|
private static function move(dir:Null<WorldPos>) {
|
||||||
|
if (alignPromise.isRunning()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var pos = GPS.getPosition();
|
var pos = GPS.getPosition();
|
||||||
if (pos == null || dir == null)
|
if (pos == null || dir == null)
|
||||||
return;
|
return;
|
||||||
@@ -76,58 +80,53 @@ class INS {
|
|||||||
GPS.setINSPosition(newPos);
|
GPS.setINSPosition(newPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getHeading():Null<Pos3> {
|
public static function getHeading():Null<WorldPos> {
|
||||||
return heading;
|
return heading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function align():Promise<Noise> {
|
public static function align():Promise<Noise> {
|
||||||
Log.info("Aligning INS");
|
return alignPromise.request();
|
||||||
return new Promise<Noise>((resolve, reject) -> {
|
}
|
||||||
if (Turtle.getFuelLevel() < 2) {
|
|
||||||
Log.warn("Not enough fuel to align");
|
public static function startAlign():Void {
|
||||||
reject(new Error("Not enough fuel to align"));
|
if (Turtle.getFuelLevel() < 2) {
|
||||||
return null;
|
alignPromise.reject(new Error("Not enough fuel to align"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPS.locate().handle((result) -> {
|
||||||
|
switch result {
|
||||||
|
case Failure(err):
|
||||||
|
alignPromise.reject(new Error("Failed to locate 1st positon: " + err));
|
||||||
|
return;
|
||||||
|
case Success(pos1):
|
||||||
|
var moved = tryMoving();
|
||||||
|
|
||||||
|
if (moved == -1) {
|
||||||
|
alignPromise.reject(new Error("Can't move"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPS.locate().handle((result2) -> {
|
||||||
|
switch result2 {
|
||||||
|
case Failure(err):
|
||||||
|
alignPromise.reject(new Error("GPS not available for 2nd position: " + err));
|
||||||
|
return;
|
||||||
|
case Success(pos2):
|
||||||
|
var cHeading = calcHeading(pos1, pos2, moved);
|
||||||
|
if (cHeading == null) {
|
||||||
|
alignPromise.reject(new Error("Can't calculate heading"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
heading = cHeading;
|
||||||
|
moveBack(moved);
|
||||||
|
GPS.setINSPosition(pos1);
|
||||||
|
|
||||||
|
alignPromise.resolve(Noise);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
GPS.locate().handle((pos1) -> {
|
|
||||||
Log.debug('pos1: $pos1');
|
|
||||||
if (pos1 == null) {
|
|
||||||
Log.warn("GPS not available for 1st position");
|
|
||||||
reject(new Error("GPS not available"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var moved = tryMoving();
|
|
||||||
|
|
||||||
if (moved == -1) {
|
|
||||||
Log.warn("Can't move");
|
|
||||||
reject(new Error("Can't move"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPS.locate().handle((pos2) -> {
|
|
||||||
Log.debug('pos2: $pos2');
|
|
||||||
if (pos2 == null) {
|
|
||||||
Log.warn("GPS not available for 2nd position");
|
|
||||||
reject(new Error("GPS not available for 2nd position"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cHeading = calcHeading(pos1, pos2, moved);
|
|
||||||
if (cHeading == null) {
|
|
||||||
Log.error("Can't calculate heading");
|
|
||||||
reject(new Error("Can't calculate heading"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
heading = cHeading;
|
|
||||||
moveBack(moved);
|
|
||||||
GPS.setINSPosition(pos1);
|
|
||||||
|
|
||||||
resolve(Noise);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +149,7 @@ class INS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function calcHeading(pos1:Pos3, pos2:Pos3, moved:Int):Null<Pos3> {
|
private static function calcHeading(pos1:WorldPos, pos2:WorldPos, moved:Int):Null<WorldPos> {
|
||||||
if (moved == 0) {
|
if (moved == 0) {
|
||||||
return pos1 - pos2;
|
return pos1 - pos2;
|
||||||
} else if (moved == 1) {
|
} else if (moved == 1) {
|
||||||
@@ -167,24 +166,18 @@ class INS {
|
|||||||
private static function moveBack(moved:Int) {
|
private static function moveBack(moved:Int) {
|
||||||
if (moved == 0) {
|
if (moved == 0) {
|
||||||
Turtle.forward();
|
Turtle.forward();
|
||||||
// cc.Turtle.forward();
|
|
||||||
} else if (moved == 1) {
|
} else if (moved == 1) {
|
||||||
Turtle.back();
|
Turtle.back();
|
||||||
// cc.Turtle.back();
|
|
||||||
} else if (moved == 2) {
|
} else if (moved == 2) {
|
||||||
Turtle.back();
|
Turtle.back();
|
||||||
// cc.Turtle.back();
|
|
||||||
Turtle.turnRight();
|
Turtle.turnRight();
|
||||||
// cc.Turtle.turnRight();
|
|
||||||
} else if (moved == 3) {
|
} else if (moved == 3) {
|
||||||
Turtle.forward();
|
Turtle.forward();
|
||||||
// cc.Turtle.forward();
|
|
||||||
Turtle.turnRight();
|
Turtle.turnRight();
|
||||||
// cc.Turtle.turnRight();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function rotatePos3ToRight(pos:Pos3):Pos3 {
|
private static function rotatePos3ToRight(pos:WorldPos):WorldPos {
|
||||||
if (pos.x == 0 && pos.z == -1) {
|
if (pos.x == 0 && pos.z == -1) {
|
||||||
return {x: 1, y: 0, z: 0};
|
return {x: 1, y: 0, z: 0};
|
||||||
} else if (pos.x == -1 && pos.z == 0) {
|
} else if (pos.x == -1 && pos.z == 0) {
|
||||||
@@ -198,7 +191,7 @@ class INS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function rotatePos3ToLeft(pos3:Pos3):Pos3 {
|
private static function rotatePos3ToLeft(pos3:WorldPos):WorldPos {
|
||||||
return rotatePos3ToRight(rotatePos3ToRight(rotatePos3ToRight(pos3)));
|
return rotatePos3ToRight(rotatePos3ToRight(rotatePos3ToRight(pos3)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package kernel.log;
|
package kernel.log;
|
||||||
|
|
||||||
import haxe.ds.ReadOnlyArray;
|
import haxe.ds.ReadOnlyArray;
|
||||||
#if webconsole
|
import haxe.macro.Context;
|
||||||
|
#if (webconsole && !macro)
|
||||||
import lib.Debug;
|
import lib.Debug;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
@@ -21,32 +22,62 @@ class Log {
|
|||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
private static function init() {
|
private static function init() {
|
||||||
onLog = onLogTrigger.asSignal();
|
onLog = onLogTrigger.asSignal();
|
||||||
}
|
|
||||||
|
|
||||||
public static function info(msg:Dynamic, ?pos:haxe.PosInfos) {
|
|
||||||
log({level: Info, message: Std.string(msg), time: 0}, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function warn(msg:Dynamic, ?pos:haxe.PosInfos) {
|
|
||||||
log({level: Warn, message: Std.string(msg), time: 0}, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function error(msg:Dynamic, ?pos:haxe.PosInfos) {
|
|
||||||
log({level: Error, message: Std.string(msg), time: 0}, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function debug(msg:Dynamic, ?pos:haxe.PosInfos) {
|
|
||||||
#if debug
|
#if debug
|
||||||
log({level: Debug, message: Std.string(msg), time: 0}, pos);
|
haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) {
|
||||||
|
Log._debug(v, infos.className);
|
||||||
|
}
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function silly(msg:Dynamic, ?pos:haxe.PosInfos) {
|
public static function _info(msg:Dynamic, ?origin:String) {
|
||||||
log({level: Silly, message: Std.string(msg), time: 0}, pos);
|
log({
|
||||||
|
level: Info,
|
||||||
|
message: Std.string(msg),
|
||||||
|
time: 0,
|
||||||
|
origin: origin
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function log(line:LogLine, ?pos:haxe.PosInfos) {
|
public static function _warn(msg:Dynamic, ?origin:String) {
|
||||||
line.origin = pos.className;
|
log({
|
||||||
|
level: Warn,
|
||||||
|
message: Std.string(msg),
|
||||||
|
time: 0,
|
||||||
|
origin: origin
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function _error(msg:Dynamic, ?origin:String) {
|
||||||
|
log({
|
||||||
|
level: Error,
|
||||||
|
message: Std.string(msg),
|
||||||
|
time: 0,
|
||||||
|
origin: origin
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function _debug(msg:Dynamic, ?origin:String) {
|
||||||
|
#if debug
|
||||||
|
log({
|
||||||
|
level: Debug,
|
||||||
|
message: Std.string(msg),
|
||||||
|
time: 0,
|
||||||
|
origin: origin
|
||||||
|
});
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function _silly(msg:Dynamic, ?origin:String) {
|
||||||
|
log({
|
||||||
|
level: Silly,
|
||||||
|
message: Std.string(msg),
|
||||||
|
time: 0,
|
||||||
|
origin: origin
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function log(line:LogLine) {
|
||||||
logLines.push(line);
|
logLines.push(line);
|
||||||
|
|
||||||
if (logLines.length > MAX_LINES) {
|
if (logLines.length > MAX_LINES) {
|
||||||
@@ -54,12 +85,49 @@ class Log {
|
|||||||
}
|
}
|
||||||
onLogTrigger.trigger(line);
|
onLogTrigger.trigger(line);
|
||||||
|
|
||||||
#if webconsole
|
#if (webconsole && !macro)
|
||||||
Debug.printWeb('[${Std.string(line.level)}][${line.origin}] ${line.message}');
|
Debug.logToWebconsole(line);
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getLines():ReadOnlyArray<LogLine> {
|
public static function getLines():ReadOnlyArray<LogLine> {
|
||||||
return logLines;
|
return logLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
private static function getOrigin():String {
|
||||||
|
var localClass = Context.getLocalClass().get();
|
||||||
|
return localClass.name;
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
public macro static function info(msg:ExprOf<Dynamic>) {
|
||||||
|
return macro {
|
||||||
|
Log._info(${msg}, $v{getOrigin()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public macro static function warn(msg:ExprOf<Dynamic>) {
|
||||||
|
return macro {
|
||||||
|
Log._warn(${msg}, $v{getOrigin()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public macro static function error(msg:ExprOf<Dynamic>) {
|
||||||
|
return macro {
|
||||||
|
Log._error(${msg}, $v{getOrigin()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public macro static function debug(msg:ExprOf<Dynamic>) {
|
||||||
|
return macro {
|
||||||
|
Log._debug(${msg}, $v{getOrigin()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public macro static function silly(msg:ExprOf<Dynamic>) {
|
||||||
|
return macro {
|
||||||
|
Log._silly(${msg}, $v{getOrigin()});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,35 @@ class Net {
|
|||||||
setupInterf(interf);
|
setupInterf(interf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle when a modem has been removed
|
||||||
|
KernelEvents.onPeripheralDetach.handle((addr) -> {
|
||||||
|
var idx = interfaces.findIndex((i) -> {
|
||||||
|
return i.name() == addr;
|
||||||
|
});
|
||||||
|
if (idx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.debug('Removed modem on addr: $addr');
|
||||||
|
|
||||||
|
interfaces.splice(idx, 1);
|
||||||
|
Routing.removeInterface(addr);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle when a new modem is connected
|
||||||
|
KernelEvents.onPeripheral.handle((addr) -> {
|
||||||
|
if (!Peripheral.getTypes(addr).contains("modem")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.debug('Added modem on addr: $addr');
|
||||||
|
|
||||||
|
var modem = Peripheral.getModem(addr);
|
||||||
|
interfaces.push(modem);
|
||||||
|
setupInterf(modem);
|
||||||
|
Routing.addInterface(modem);
|
||||||
|
});
|
||||||
|
|
||||||
setupPingHandle();
|
setupPingHandle();
|
||||||
|
|
||||||
Routing.setup();
|
Routing.setup();
|
||||||
@@ -62,6 +91,9 @@ class Net {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Enables the interface to receive messages.
|
||||||
|
**/
|
||||||
private static function setupInterf(interf:INetworkInterface) {
|
private static function setupInterf(interf:INetworkInterface) {
|
||||||
interf.onMessage.handle(e -> handle(e.pack, interf, e.dist));
|
interf.onMessage.handle(e -> handle(e.pack, interf, e.dist));
|
||||||
interf.listen(networkID);
|
interf.listen(networkID);
|
||||||
@@ -135,12 +167,13 @@ class Net {
|
|||||||
|
|
||||||
if (!sendRaw(pack)) {
|
if (!sendRaw(pack)) {
|
||||||
// Cant forward
|
// Cant forward
|
||||||
|
Log.silly('Received a message that could not be forwarded to ${pack.toID}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function respondTo(pack:GenericPackage, data:Dynamic) {
|
public static function respondTo(pack:GenericPackage, data:Dynamic) {
|
||||||
if (pack.type.match(DataNoResponse(_))) {
|
if (!pack.type.match(Data(_))) {
|
||||||
Log.warn("Responed to a no response package. Ignoring");
|
Log.warn("Responding to a package that does require responding. Ignoring.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +245,8 @@ class Net {
|
|||||||
if (timeout != null) {
|
if (timeout != null) {
|
||||||
timeout.cancle();
|
timeout.cancle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
responseBus.remove(pack.msgID);
|
||||||
});
|
});
|
||||||
|
|
||||||
timeout = new Timer(MESSAGE_TIMEOUT, () -> {
|
timeout = new Timer(MESSAGE_TIMEOUT, () -> {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package kernel.net;
|
package kernel.net;
|
||||||
|
|
||||||
import lib.Pos3;
|
|
||||||
|
|
||||||
typedef NetworkID = Int;
|
typedef NetworkID = Int;
|
||||||
typedef GenericPackage = Package<Dynamic>;
|
typedef GenericPackage = Package<Dynamic>;
|
||||||
|
|
||||||
@@ -12,7 +10,7 @@ enum PackageTypes {
|
|||||||
RouteDiscover(reachableIDs:Array<{id:NetworkID, cost:Int}>);
|
RouteDiscover(reachableIDs:Array<{id:NetworkID, cost:Int}>);
|
||||||
RouteDiscoverResponse(reachableIDs:Array<{id:NetworkID, cost:Int}>);
|
RouteDiscoverResponse(reachableIDs:Array<{id:NetworkID, cost:Int}>);
|
||||||
RouteDiscoverUpdate(reachableIDs:Array<{id:NetworkID, cost:Int}>);
|
RouteDiscoverUpdate(reachableIDs:Array<{id:NetworkID, cost:Int}>);
|
||||||
GPSResponse(pos:Pos3);
|
GPSResponse(x:Float, y:Float, z:Float);
|
||||||
GPSRequest();
|
GPSRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,42 +74,37 @@ class Routing {
|
|||||||
private static function handleRoutePackage(pack:Package<Noise>, interf:INetworkInterface):Void {
|
private static function handleRoutePackage(pack:Package<Noise>, interf:INetworkInterface):Void {
|
||||||
addPossibleRoute(pack.fromID, interf, 0, pack.fromID);
|
addPossibleRoute(pack.fromID, interf, 0, pack.fromID);
|
||||||
|
|
||||||
var shouldRespond:Bool = switch pack.type {
|
switch pack.type {
|
||||||
case RouteDiscoverResponse(routes):
|
case RouteDiscoverResponse(routes):
|
||||||
|
// A request for routes has been answerd
|
||||||
for (route in routes) {
|
for (route in routes) {
|
||||||
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
||||||
}
|
}
|
||||||
false;
|
|
||||||
case RouteDiscover(routes):
|
case RouteDiscover(routes):
|
||||||
|
// Received a request for available routes
|
||||||
for (route in routes) {
|
for (route in routes) {
|
||||||
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
||||||
}
|
}
|
||||||
true;
|
|
||||||
|
// Respond to peer
|
||||||
|
var response:Package<Noise> = {
|
||||||
|
toID: pack.fromID,
|
||||||
|
fromID: Net.networkID,
|
||||||
|
msgID: null,
|
||||||
|
type: RouteDiscoverResponse(genRouteList()),
|
||||||
|
data: null,
|
||||||
|
ttl: 0, // Prevent forwarding
|
||||||
|
}
|
||||||
|
|
||||||
|
interf.send(response.toID, Net.networkID, response);
|
||||||
case RouteDiscoverUpdate(routes):
|
case RouteDiscoverUpdate(routes):
|
||||||
|
// Received an update of routes
|
||||||
for (route in routes) {
|
for (route in routes) {
|
||||||
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
||||||
}
|
}
|
||||||
false;
|
|
||||||
default:
|
default:
|
||||||
Log.error("Expected package to be a Route discover package");
|
Log.silly("Expected package to be a Route discover package");
|
||||||
false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!shouldRespond) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Respond to peer
|
|
||||||
var response:Package<Noise> = {
|
|
||||||
toID: pack.fromID,
|
|
||||||
fromID: Net.networkID,
|
|
||||||
msgID: null,
|
|
||||||
type: RouteDiscoverResponse(genRouteList()),
|
|
||||||
data: null,
|
|
||||||
ttl: 0, // Prevent forwarding
|
|
||||||
}
|
|
||||||
|
|
||||||
interf.send(response.toID, Net.networkID, response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,6 +121,9 @@ class Routing {
|
|||||||
return routes;
|
return routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create a new packate to brodcast our routes.
|
||||||
|
**/
|
||||||
private static function newRoutDiscoverPackage():Package<Noise> {
|
private static function newRoutDiscoverPackage():Package<Noise> {
|
||||||
var pack:Package<Noise> = {
|
var pack:Package<Noise> = {
|
||||||
type: RouteDiscover(genRouteList()),
|
type: RouteDiscover(genRouteList()),
|
||||||
@@ -179,4 +177,28 @@ class Routing {
|
|||||||
public static function getRouteTable():Map<NetworkID, Route> {
|
public static function getRouteTable():Map<NetworkID, Route> {
|
||||||
return routingTable;
|
return routingTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Call when an interface is no longer available.
|
||||||
|
Will rebrodcast routing requests.
|
||||||
|
**/
|
||||||
|
@:allow(kernel.net.Net)
|
||||||
|
private static function removeInterface(addr:String) {
|
||||||
|
// Remove the interface from the routing table
|
||||||
|
for (to => modem in routingTable) {
|
||||||
|
if (modem.interf.name() == addr) {
|
||||||
|
routingTable.remove(to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since some routes to some host could be lost
|
||||||
|
// we rebrodcast on all interfaces again
|
||||||
|
brodcastRoutingTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.net.Net)
|
||||||
|
private static function addInterface(iface:INetworkInterface) {
|
||||||
|
var pack = newRoutDiscoverPackage();
|
||||||
|
iface.send(Net.BRODCAST_PORT, Net.networkID, pack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
491
src/kernel/peripherals/DroneInterface.hx
Normal file
491
src/kernel/peripherals/DroneInterface.hx
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
package kernel.peripherals;
|
||||||
|
|
||||||
|
import lib.Item;
|
||||||
|
import haxe.exceptions.NotImplementedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
See https://github.com/MineMaarten/PneumaticCraft/blob/master/resources/assets/pneumaticcraft/wiki/en_US/block/droneInterface.txt
|
||||||
|
**/
|
||||||
|
class DroneInterface implements IPeripheral {
|
||||||
|
public static inline final TYPE_NAME:String = "drone_interface";
|
||||||
|
|
||||||
|
private final addr:String;
|
||||||
|
|
||||||
|
@:allow(kernel.peripherals)
|
||||||
|
private function new(addr:String) {
|
||||||
|
this.addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddr():String {
|
||||||
|
return this.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType():String {
|
||||||
|
return DroneInterface.TYPE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if a Drone has connected with this Drone Interface
|
||||||
|
(when the Drone's program has arrived at the ComputerCraft piece and made a connection).
|
||||||
|
**/
|
||||||
|
public function isConnectedToDrone():Bool {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the pressure of the connected Drone.
|
||||||
|
**/
|
||||||
|
public function getDronePressure() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a table of 3 double values containing the x,y and z position respectively of the Drone.
|
||||||
|
**/
|
||||||
|
public function getDronePosition() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Stops the ComputerCraft piece in the Drone, and allows the Drone's program to proceed to the next puzzle piece.
|
||||||
|
**/
|
||||||
|
public function exitPiece() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a table of all the current selectable actions (like 'dig' or 'place').
|
||||||
|
**/
|
||||||
|
public function getAllActions() {
|
||||||
|
/*
|
||||||
|
pneumaticcraft:entity_attack
|
||||||
|
pneumaticcraft:dig
|
||||||
|
pneumaticcraft:harvest
|
||||||
|
pneumaticcraft:place
|
||||||
|
pneumaticcraft:block_right_click
|
||||||
|
pneumaticcraft:entity_right_click
|
||||||
|
pneumaticcraft:pickup_item
|
||||||
|
pneumaticcraft:drop_item
|
||||||
|
pneumaticcraft:void_item
|
||||||
|
pneumaticcraft:void_liquid
|
||||||
|
pneumaticcraft:inventory_export
|
||||||
|
pneumaticcraft:inventory_import
|
||||||
|
pneumaticcraft:liquid_export
|
||||||
|
pneumaticcraft:liquid_import
|
||||||
|
pneumaticcraft:entity_export
|
||||||
|
pneumaticcraft:entity_import
|
||||||
|
pneumaticcraft:rf_import
|
||||||
|
pneumaticcraft:rf_export
|
||||||
|
pneumaticcraft:goto
|
||||||
|
pneumaticcraft:teleport
|
||||||
|
pneumaticcraft:emit_redstone
|
||||||
|
pneumaticcraft:rename
|
||||||
|
pneumaticcraft:suicide
|
||||||
|
pneumaticcraft:crafting
|
||||||
|
pneumaticcraft:standby
|
||||||
|
pneumaticcraft:logistics
|
||||||
|
pneumaticcraft:edit_sign
|
||||||
|
pneumaticcraft:condition_redstone
|
||||||
|
pneumaticcraft:condition_light
|
||||||
|
pneumaticcraft:condition_item_inventory
|
||||||
|
pneumaticcraft:condition_block
|
||||||
|
pneumaticcraft:condition_liquid_inventory
|
||||||
|
pneumaticcraft:condition_pressure
|
||||||
|
pneumaticcraft:drone_condition_item
|
||||||
|
pneumaticcraft:drone_condition_liquid
|
||||||
|
pneumaticcraft:drone_condition_entity
|
||||||
|
pneumaticcraft:drone_condition_pressure
|
||||||
|
pneumaticcraft:drone_condition_upgrades
|
||||||
|
pneumaticcraft:condition_rf
|
||||||
|
pneumaticcraft:drone_condition_rf
|
||||||
|
pneumaticcraft:computer_control
|
||||||
|
*/
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the place/dig order of the Drone.
|
||||||
|
**/
|
||||||
|
public function setBlockOrder(order:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a table of all the possible area types (filled, frame, sphere, ..).
|
||||||
|
**/
|
||||||
|
public function getAreaTypes() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds an area to the current stored area of the Drone. When using the latter method, x1, y1, and z1, represent
|
||||||
|
the first point (which would be the first GPS Tool normally), and x2, y2, and z2 represent the second point.
|
||||||
|
**/
|
||||||
|
public function addArea(x:Int, y:Int, z:Int) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Removes an area from the current stored area (like blacklisting).
|
||||||
|
**/
|
||||||
|
public function removeArea(x:Int, y:Int, z:Int) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clears the current stored area.
|
||||||
|
**/
|
||||||
|
public function clearArea() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Will show the current stored area using the area renderer you are used to.
|
||||||
|
**/
|
||||||
|
public function showArea() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Will stop showing the area stored in the Drone.
|
||||||
|
**/
|
||||||
|
public function hideArea() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Acts as you've put a Item Filter piece on the right of a piece (making it whitelisting).
|
||||||
|
The item/block name is in Minecraft format, i.e. "minecraft:stone", or "pneumaticcraft:pressureTube".
|
||||||
|
The 'useXXX' are all booleans that determine what filters will be used (same functionality as the check boxes in the Item Filter puzzle piece).
|
||||||
|
**/
|
||||||
|
public function addWhitelistItemFilter(item:Item, metadata:String, useMetadata:Bool, useNBT:Bool, useOreDictionary:Bool, useModSimilarity:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Like the addWhitelistItemFilter(...), but to blacklist items.
|
||||||
|
**/
|
||||||
|
public function addBlacklistItemFilter(item:Item, metadata:String, useMetadata:Bool, useNBT:Bool, useOreDictionary:Bool, useModSimilarity:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clears all the whitelisted item filters stored.
|
||||||
|
**/
|
||||||
|
public function clearWhitelistItemFilter() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clears all the blacklisted item filters stored.
|
||||||
|
**/
|
||||||
|
public function clearBlacklistItemFilter() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds a text to the whitelisted texts. Used to specify a filter for the Entity Attack action for example.
|
||||||
|
**/
|
||||||
|
public function addWhitelistText(text:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds a text to the blacklisted texts. Used to specify a filter for the Entity Attack action for example.
|
||||||
|
**/
|
||||||
|
public function addBlacklistText(text:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clears the stored whitelisted texts.
|
||||||
|
**/
|
||||||
|
public function clearWhitelistText() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clears the stored blacklisted texts.
|
||||||
|
**/
|
||||||
|
public function clearBlacklistText() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Acts as you've put a Liquid Filter piece on the right of a piece (making it whitelisting).
|
||||||
|
You can either give it the 'registry name', or the localized name.
|
||||||
|
**/
|
||||||
|
public function addWhitelistLiquidFilter(liquidName:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Like the addWhitelistLiquidFilter(...), but to blacklist liquids.
|
||||||
|
**/
|
||||||
|
public function addBlacklistLiquidFilter(liquidName:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clears all the whitelisted liquid filters stored.
|
||||||
|
**/
|
||||||
|
public function clearWhitelistLiquidFilter() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clears all the blacklisted liquid filters stored.
|
||||||
|
**/
|
||||||
|
public function clearBlacklistLiquidFilter() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the strength the redstone will be emitting when the "emitRedstone" action would be set.
|
||||||
|
**/
|
||||||
|
public function setEmittingRedstone(strength:Int) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the name the Drone will be named to when the "rename" action would be set.
|
||||||
|
**/
|
||||||
|
public function setRenameString(name:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
When the "dropItem" action would be set, this determines whether or not
|
||||||
|
the item will be dropped with a random velocity, or straight down.
|
||||||
|
**/
|
||||||
|
public function setDropStraight(to:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This says whether or not the Drone has a maximum of imported/exported/dropped pieces.
|
||||||
|
If true, also use setCount().
|
||||||
|
**/
|
||||||
|
public function setUseCount(count:Int) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This configures the maximum amount of imported/exported/dropped items, and also is the amount that's checked when doing a condition check.
|
||||||
|
**/
|
||||||
|
public function setCount(count:Int) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Used in conditions only. When true, all checked blocks need to satisfy the condition requirements (>=10 etcetera).
|
||||||
|
**/
|
||||||
|
public function setIsAndFunction(to:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Used in conditions only.
|
||||||
|
Says whether or not the condition is checking for an equal amount (=) or equal and higher than amount (>=).
|
||||||
|
The amount can be set using setCount().
|
||||||
|
**/
|
||||||
|
public function setOperator(op:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true/false. Used in conditions only.
|
||||||
|
Will return true/false depending on whether or not the condition is satisfied.
|
||||||
|
Drone Conditions can be checked right after setting 'setAction()'.
|
||||||
|
Note that you need to wait until 'isActionDone' if you're dealing with a non Drone Condition.
|
||||||
|
**/
|
||||||
|
public function evaluateCondition():Bool {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the specific side to be accessible or not.
|
||||||
|
Used in the Inventory Im- and Export actions to set which side of the inventory the Drone can access.
|
||||||
|
It is also used for the Place action to determine how to place the block.
|
||||||
|
**/
|
||||||
|
public function setSide(side:String, accessible:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Same as setSide(side: String, accessible: Bool), now in one function to set all sides at once (6x boolean).
|
||||||
|
**/
|
||||||
|
public function setSides(down:Bool, up:Bool, north:Bool, south:Bool, east:Bool, west:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This says whether or not the Drone has a maximum actions performed on a block at a time before the command is considered 'done'.
|
||||||
|
Applies to the Place, Dig and Right-Click block program. If true, also use setMaxActions().
|
||||||
|
**/
|
||||||
|
public function setUseMaxActions(to:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This configures the maximum amount of actions performed on blocks before the command is considered 'done'.
|
||||||
|
This applies to the Place, Dig an Right-Click block program. Be sure to also call setUseMaxActions(true) to enable usage of this.
|
||||||
|
**/
|
||||||
|
public function setMaxActions(max:Int) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets up the crafting grid so when the Crafting instruction is called, this recipe will be used.
|
||||||
|
You need to specify all 9 items making up the recipe.
|
||||||
|
For empty spaces supply nil. The naming format is the same as for supplying item filters.
|
||||||
|
|
||||||
|
TODO: args: <item/block name>, <item/block name>, ...(9x)
|
||||||
|
**/
|
||||||
|
public function setCraftingGrid() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Only used in the right click command, this will set whether or not the fake player is sneaking while right clicking.
|
||||||
|
**/
|
||||||
|
public function setSneaking(sneaking:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Only used in the Liquid Export command, when set to true the Drone will be allowed to place down fluid blocks.
|
||||||
|
**/
|
||||||
|
public function setPlaceFluidBlocks(to:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the[link{pneumaticcraft:progwidget/coordinateOperator}] variable[link{}] of this Drone.
|
||||||
|
When passing 'true', the coordinate will be set to (1,0,0).
|
||||||
|
Alternatively, false will be setting it to (0,0,0).
|
||||||
|
It is possible to set global variables (#) as well.
|
||||||
|
|
||||||
|
TODO: args
|
||||||
|
setVariable(<variable name>, <true/false>)
|
||||||
|
setVariable(<variable name>, <x>)
|
||||||
|
setVariable(<variable name>, <x>, <y>, <z>)
|
||||||
|
**/
|
||||||
|
public function setVariable(name:String, to:Dynamic) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the value of the variable from this Drone (x, y and z).
|
||||||
|
It is possible to get global (#) and special variables ($) as well.
|
||||||
|
**/
|
||||||
|
public function getVariable(name:String):Dynamic {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the text that's going to be set to Signs using the Edit Sign command.
|
||||||
|
|
||||||
|
TODO: args <line1>, <line2>, ..., <lineN>
|
||||||
|
**/
|
||||||
|
public function setSignText(lines:Array<String>) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
String that represents the action. This should be one of the actions returned by getAllActions().
|
||||||
|
**/
|
||||||
|
public function setAction(action:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a string that represents the last action set by 'setAction'.
|
||||||
|
Will return nil when no action is set.
|
||||||
|
Can be used to make sure to only call 'isActionDone()' when this method does not return nil.
|
||||||
|
**/
|
||||||
|
public function getAction():String {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Stops the current running action.
|
||||||
|
**/
|
||||||
|
public function abortAction() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the current action is done (goto has arrived at the target location,
|
||||||
|
inventory import can't import anymore, dig has dug every possible block, ..).
|
||||||
|
**/
|
||||||
|
public function isActionDone():Bool {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
When the Drone was targeting an Entity (in the Entity Attack program), this will stop attacking that target.
|
||||||
|
**/
|
||||||
|
public function forgetTarget() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Will get the amount of inserted upgrades of the given type.
|
||||||
|
This type is the index of the upgrade (in creative, or NEI), starting with 0.
|
||||||
|
Or the metadata value when you use NEI.
|
||||||
|
A Speed upgrade for example has an index of 5.
|
||||||
|
**/
|
||||||
|
public function getUpgrades(upgrade:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unkown. Showed up in the inspect.
|
||||||
|
**/
|
||||||
|
public function setCanSteal(canSteal:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unkown. Showed up in the inspect.
|
||||||
|
**/
|
||||||
|
public function setRequiresTool(requiresTool:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unkown. Showed up in the inspect.
|
||||||
|
**/
|
||||||
|
public function setCheckLineOfSight(check:Bool) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unkown. Showed up in the inspect.
|
||||||
|
**/
|
||||||
|
public function setRightClickType(to:String) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unkown. Showed up in the inspect.
|
||||||
|
**/
|
||||||
|
public function getDronePositionVec() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unkown. Showed up in the inspect.
|
||||||
|
**/
|
||||||
|
public function getOwnerID() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unkown. Showed up in the inspect.
|
||||||
|
**/
|
||||||
|
public function getOwnerName():String {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
import lib.exporter.ExportConfig;
|
class EnergyStorage implements IPeripheral {
|
||||||
import lib.exporter.IExportable;
|
|
||||||
|
|
||||||
class EnergyStorage implements IPeripheral implements IExportable {
|
|
||||||
public static inline final TYPE_NAME:String = "energyCell";
|
public static inline final TYPE_NAME:String = "energyCell";
|
||||||
|
|
||||||
private final addr:String;
|
private final addr:String;
|
||||||
@@ -29,13 +26,4 @@ class EnergyStorage implements IPeripheral implements IExportable {
|
|||||||
public function getType():String {
|
public function getType():String {
|
||||||
return TYPE_NAME;
|
return TYPE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function export():ExportConfig {
|
|
||||||
return {
|
|
||||||
getDelegates: [
|
|
||||||
"energy" => _ -> Number(this.getEnergy()),
|
|
||||||
"capacity" => _ -> Number(this.getEnergyCapacity()),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
76
src/kernel/peripherals/GeoScanner.hx
Normal file
76
src/kernel/peripherals/GeoScanner.hx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package kernel.peripherals;
|
||||||
|
|
||||||
|
import lib.BlockPos;
|
||||||
|
import lib.Tags;
|
||||||
|
import cc.Peripheral;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
using lua.Table;
|
||||||
|
|
||||||
|
@:structInit typedef ScanBlock = {
|
||||||
|
name:String,
|
||||||
|
tags:Tags,
|
||||||
|
pos:BlockPos
|
||||||
|
}
|
||||||
|
|
||||||
|
class GeoScanner implements IPeripheral {
|
||||||
|
public static inline final TYPE_NAME:String = "geoScanner";
|
||||||
|
|
||||||
|
private final addr:String;
|
||||||
|
|
||||||
|
public function new(addr:String) {
|
||||||
|
this.addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddr():String {
|
||||||
|
return this.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType():String {
|
||||||
|
return TYPE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the current time remaining until then next scan() can be ran.
|
||||||
|
**/
|
||||||
|
public function getScanCooldown():Int {
|
||||||
|
return Peripheral.call(this.addr, "getScanCooldown");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the cost in FE for a scan with the given radius.
|
||||||
|
Returns null of scan of this radius is not posible.
|
||||||
|
**/
|
||||||
|
public function cost(radius:Int):Null<Int> {
|
||||||
|
return Peripheral.call(this.addr, "cost", radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of data about all blocks in the radius.
|
||||||
|
X,Y,Z are relative to the geoscanner block.
|
||||||
|
Air blocks are not included.
|
||||||
|
List is unsorted.
|
||||||
|
**/
|
||||||
|
public function scan(radius:Int):Outcome<Array<ScanBlock>, String> {
|
||||||
|
// TODO: Handel fail state
|
||||||
|
var result:lua.Table<Int, {
|
||||||
|
x:Int,
|
||||||
|
y:Int,
|
||||||
|
z:Int,
|
||||||
|
name:String,
|
||||||
|
tags:lua.Table<Int, String>
|
||||||
|
}> = Peripheral.call(this.addr, "scan", radius);
|
||||||
|
|
||||||
|
return Success(result.toArray().map((e) -> {
|
||||||
|
name: e.name,
|
||||||
|
tags: Tags.fromIntTable(e.tags),
|
||||||
|
pos: new BlockPos(e.x, e.y, e.z)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function chunkAnalyze():Outcome<Map<String, Int>, String> {
|
||||||
|
var result:lua.Table<String, Int> = Peripheral.call(this.addr, "chunkAnalyze");
|
||||||
|
|
||||||
|
return Success(result.toMap());
|
||||||
|
}
|
||||||
|
}
|
||||||
123
src/kernel/peripherals/Inventory.hx
Normal file
123
src/kernel/peripherals/Inventory.hx
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package kernel.peripherals;
|
||||||
|
|
||||||
|
import kernel.log.Log;
|
||||||
|
import lib.Debug;
|
||||||
|
import cc.Peripheral;
|
||||||
|
import lib.Tags;
|
||||||
|
import lib.Item;
|
||||||
|
import cc.periphs.ItemStorage.ReducedItemInfo;
|
||||||
|
import lua.Table;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
|
||||||
|
class ItemInfo {
|
||||||
|
public final count:Int;
|
||||||
|
public final name:Item;
|
||||||
|
public final nbt:Null<String>;
|
||||||
|
|
||||||
|
@:allow(kernel.peripherals.Inventory)
|
||||||
|
private function new(from:ReducedItemInfo) {
|
||||||
|
this.count = from.count;
|
||||||
|
this.name = from.name;
|
||||||
|
this.nbt = from.nbt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DetailedItemInfo extends ItemInfo {
|
||||||
|
public final displayName:String;
|
||||||
|
public final maxCount:Int;
|
||||||
|
public final tags:Tags;
|
||||||
|
public final durability:Null<Float>;
|
||||||
|
public final damage:Null<Int>;
|
||||||
|
public final maxDamage:Null<Int>;
|
||||||
|
public final enchantments:Array<{displayName:String, level:Int, name:String}>;
|
||||||
|
|
||||||
|
@:allow(kernel.peripherals.Inventory)
|
||||||
|
private function new(from:cc.periphs.ItemStorage.DetailedItemInfo) {
|
||||||
|
super(from);
|
||||||
|
|
||||||
|
this.tags = Tags.fromBoolTable(from.tags);
|
||||||
|
|
||||||
|
this.displayName = from.displayName;
|
||||||
|
this.maxCount = from.maxCount;
|
||||||
|
this.durability = from.durability;
|
||||||
|
this.damage = from.damage;
|
||||||
|
this.maxDamage = from.maxDamage;
|
||||||
|
|
||||||
|
if (from.enchantments != null) {
|
||||||
|
this.enchantments = from.enchantments;
|
||||||
|
} else {
|
||||||
|
this.enchantments = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Inventory implements IPeripheral {
|
||||||
|
public static inline final TYPE_NAME:String = "inventory";
|
||||||
|
|
||||||
|
private final addr:String;
|
||||||
|
|
||||||
|
public function new(addr:String) {
|
||||||
|
this.addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddr():String {
|
||||||
|
return this.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType():String {
|
||||||
|
return TYPE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the size of this inventory.
|
||||||
|
**/
|
||||||
|
public function size():Int {
|
||||||
|
return Peripheral.call(this.addr, "size");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
List all items in this inventory.
|
||||||
|
**/
|
||||||
|
public function list():Map<Int, ItemInfo> {
|
||||||
|
var list:Map<Int, ReducedItemInfo> = Table.toMap(Peripheral.call(this.addr, "list"));
|
||||||
|
var rtn:Map<Int, ItemInfo> = new Map();
|
||||||
|
|
||||||
|
for (k => v in list) {
|
||||||
|
rtn.set(k - 1, new ItemInfo(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get detailed information about an item.
|
||||||
|
**/
|
||||||
|
public function getItemDetail(slot:Int):DetailedItemInfo {
|
||||||
|
return new DetailedItemInfo(Peripheral.call(this.addr, "getItemDetail", slot + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the maximum number of items which can be stored in this slot.
|
||||||
|
Typically this will be limited to 64 items.
|
||||||
|
However, some inventorwies (such as barrels or caches) can store hundreds or thousands of items in one slot.
|
||||||
|
Keep in mind that this does not depend on that item stored in this slot.
|
||||||
|
**/
|
||||||
|
public function getItemLimit(slot:Int):Int {
|
||||||
|
return Peripheral.call(this.addr, "getItemLimit", slot + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Push items from one inventory to another connected one. Needs to be on the same wired network.
|
||||||
|
**/
|
||||||
|
public function pushItems(to:String, fromSlot:Int, ?limit:Int, ?toSlot:Int):Int {
|
||||||
|
return Peripheral.call(this.addr, "pushItems", to, fromSlot + 1, limit, toSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Pull items from a connected inventory into this one. Needs to be on the same wired network.
|
||||||
|
**/
|
||||||
|
public function pullItems(from:String, fromSlot:Int, ?limit:Int, ?toSlot:Int):Int {
|
||||||
|
return Peripheral.call(this.addr, "pullItems", from, fromSlot + 1, limit, toSlot);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,12 +50,7 @@ class Peripheral {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var types = getTypes(addr);
|
var types = getTypes(addr);
|
||||||
var methodsMap = cc.Peripheral.getMethods(addr).toMap();
|
var methods = cc.Peripheral.getMethods(addr).toArray();
|
||||||
var methods:Array<String> = [];
|
|
||||||
|
|
||||||
for (k => v in methodsMap) {
|
|
||||||
methods.push(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
types: types,
|
types: types,
|
||||||
@@ -81,8 +76,14 @@ class Peripheral {
|
|||||||
return getModem(addr);
|
return getModem(addr);
|
||||||
case Printer.TYPE_NAME:
|
case Printer.TYPE_NAME:
|
||||||
return getPrinter(addr);
|
return getPrinter(addr);
|
||||||
case "redstone":
|
case Speaker.TYPE_NAME:
|
||||||
|
return getSpeaker(addr);
|
||||||
|
case Redstone.TYPE_NAME:
|
||||||
return getRedstone(addr);
|
return getRedstone(addr);
|
||||||
|
case Inventory.TYPE_NAME:
|
||||||
|
return getInventory(addr);
|
||||||
|
case GeoScanner.TYPE_NAME:
|
||||||
|
return getGeoScanner(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -158,4 +159,37 @@ class Peripheral {
|
|||||||
public static function getAllComputers():Array<Computer> {
|
public static function getAllComputers():Array<Computer> {
|
||||||
return [for (addr in findAddrByType(Computer.TYPE_NAME)) new Computer(addr)];
|
return [for (addr in findAddrByType(Computer.TYPE_NAME)) new Computer(addr)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getSpeaker(addr:String):Null<Speaker> {
|
||||||
|
var addr = safeGetAddr(addr, Speaker.TYPE_NAME);
|
||||||
|
if (addr == null)
|
||||||
|
return null;
|
||||||
|
return new Speaker(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAllSpeakers():Array<Speaker> {
|
||||||
|
return [for (addr in findAddrByType(Speaker.TYPE_NAME)) new Speaker(addr)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getInventory(addr:String):Null<Inventory> {
|
||||||
|
var addr = safeGetAddr(addr, Inventory.TYPE_NAME);
|
||||||
|
if (addr == null)
|
||||||
|
return null;
|
||||||
|
return new Inventory(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAllInventorys():Array<Inventory> {
|
||||||
|
return [for (addr in findAddrByType(Inventory.TYPE_NAME)) new Inventory(addr)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getGeoScanner(addr:String):Null<GeoScanner> {
|
||||||
|
var addr = safeGetAddr(addr, GeoScanner.TYPE_NAME);
|
||||||
|
if (addr == null)
|
||||||
|
return null;
|
||||||
|
return new GeoScanner(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAllGeoScanners():Array<GeoScanner> {
|
||||||
|
return [for (addr in findAddrByType(GeoScanner.TYPE_NAME)) new GeoScanner(addr)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package kernel.peripherals;
|
|||||||
|
|
||||||
import cc.Peripheral;
|
import cc.Peripheral;
|
||||||
import lib.Rect;
|
import lib.Rect;
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
|
|
||||||
class Printer implements IPeripheral {
|
class Printer implements IPeripheral {
|
||||||
public static inline final TYPE_NAME:String = "printer";
|
public static inline final TYPE_NAME:String = "printer";
|
||||||
@@ -25,11 +25,11 @@ class Printer implements IPeripheral {
|
|||||||
|
|
||||||
public function write(text:String) {}
|
public function write(text:String) {}
|
||||||
|
|
||||||
public function getCurserPos():Pos {
|
public function getCurserPos():ScreenPos {
|
||||||
return new Pos({x: 0, y: 0});
|
return new ScreenPos({x: 0, y: 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCurserPos(pos:Pos) {
|
public function setCurserPos(pos:ScreenPos) {
|
||||||
this.native.setCursorPos(pos.x, pos.y);
|
this.native.setCursorPos(pos.x, pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
import lib.exporter.ExportConfig;
|
import kernel.peripherals.interfaces.IRedstone;
|
||||||
import lib.exporter.IExportable;
|
|
||||||
import haxe.ds.ReadOnlyArray;
|
import haxe.ds.ReadOnlyArray;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
|
|
||||||
@@ -43,8 +42,7 @@ abstract BundleMask(Int) from cc.Colors.Color to cc.Colors.Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@:build(macros.Exporter.buildExport())
|
class Redstone implements IPeripheral implements IRedstone {
|
||||||
class Redstone implements IPeripheral implements IExportable {
|
|
||||||
public static inline final TYPE_NAME:String = "redstone"; // TODO: there is technically not a type for redstone.
|
public static inline final TYPE_NAME:String = "redstone"; // TODO: there is technically not a type for redstone.
|
||||||
|
|
||||||
public final onChange:Signal<Noise>;
|
public final onChange:Signal<Noise>;
|
||||||
@@ -89,12 +87,10 @@ class Redstone implements IPeripheral implements IExportable {
|
|||||||
cc.Redstone.setOutput(this.addr, on);
|
cc.Redstone.setOutput(this.addr, on);
|
||||||
}
|
}
|
||||||
|
|
||||||
@export("output")
|
|
||||||
public inline function getOutput():Bool {
|
public inline function getOutput():Bool {
|
||||||
return cc.Redstone.getOutput(this.addr);
|
return cc.Redstone.getOutput(this.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@export("input")
|
|
||||||
public inline function getInput():Bool {
|
public inline function getInput():Bool {
|
||||||
return cc.Redstone.getInput(this.addr);
|
return cc.Redstone.getInput(this.addr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
import cc.Peripheral;
|
import cc.Peripheral;
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import cc.Term.TerminalSize;
|
import cc.Term.TerminalSize;
|
||||||
import kernel.ui.TermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class Screen implements TermWriteable implements IPeripheral {
|
class Screen implements ITermWriteable implements IPeripheral {
|
||||||
public static inline final TYPE_NAME:String = "monitor";
|
public static inline final TYPE_NAME:String = "monitor";
|
||||||
|
|
||||||
private final nativ:cc.periphs.Monitor.Monitor;
|
private final nativ:cc.periphs.Monitor.Monitor;
|
||||||
@@ -59,7 +59,7 @@ class Screen implements TermWriteable implements IPeripheral {
|
|||||||
nativ.scroll(y);
|
nativ.scroll(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCursorPos():Pos {
|
public function getCursorPos():ScreenPos {
|
||||||
var rtn = nativ.getCursorPos();
|
var rtn = nativ.getCursorPos();
|
||||||
return {
|
return {
|
||||||
x: rtn.x - 1,
|
x: rtn.x - 1,
|
||||||
|
|||||||
61
src/kernel/peripherals/Speaker.hx
Normal file
61
src/kernel/peripherals/Speaker.hx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package kernel.peripherals;
|
||||||
|
|
||||||
|
import cc.Peripheral;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
class Speaker implements IPeripheral {
|
||||||
|
public static inline final TYPE_NAME:String = "speaker";
|
||||||
|
|
||||||
|
private final addr:String;
|
||||||
|
|
||||||
|
public function new(addr:String) {
|
||||||
|
this.addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType():String {
|
||||||
|
return Speaker.TYPE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddr():String {
|
||||||
|
return this.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Plays a note block note through the speaker.
|
||||||
|
The pitch argument uses semitones as the unit. This directly maps to the number of clicks on a note block.
|
||||||
|
For reference, 0, 12, and 24 map to F#, and 6 and 18 map to C.
|
||||||
|
A maximum of 8 notes can be played in a single tick. If this limit is hit, this function will return an error.
|
||||||
|
**/
|
||||||
|
public function playNote(instrument:String, ?volume:Float = 1.0, ?pitch:Int = 12):Outcome<Noise, String> {
|
||||||
|
if (Peripheral.call(addr, "playNote", instrument, volume, pitch)) {
|
||||||
|
return Success(null);
|
||||||
|
} else {
|
||||||
|
return Failure("maximum reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function playSound(sound:String, ?volume:Float = 1.0, ?pitch:Float = 1.0):Outcome<Noise, String> {
|
||||||
|
try {
|
||||||
|
if (Peripheral.call(addr, "playSound", sound, volume, pitch)) {
|
||||||
|
return Success(null);
|
||||||
|
} else {
|
||||||
|
return Failure("Sound still playing");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return Failure("Sound does not exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function playAudio(buffer:Array<Int>, ?volume:Float = 1.0):Outcome<Noise, String> {
|
||||||
|
try {
|
||||||
|
if (Peripheral.call(addr, "playAudio", buffer, volume)) {
|
||||||
|
return Success(null);
|
||||||
|
} else {
|
||||||
|
return Failure("Buffer full");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return Failure("Buffer malformed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/kernel/peripherals/exports/RedstoneExport.hx
Normal file
7
src/kernel/peripherals/exports/RedstoneExport.hx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package kernel.peripherals.exports;
|
||||||
|
|
||||||
|
import macros.rpc.RPCBase;
|
||||||
|
import kernel.peripherals.interfaces.IRedstone;
|
||||||
|
|
||||||
|
@:build(macros.rpc.RPC.buildRPC(IRedstone))
|
||||||
|
class RedstoneExport extends RPCBase {}
|
||||||
17
src/kernel/peripherals/interfaces/IRedstone.hx
Normal file
17
src/kernel/peripherals/interfaces/IRedstone.hx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package kernel.peripherals.interfaces;
|
||||||
|
|
||||||
|
import cc.Colors.Color;
|
||||||
|
import kernel.peripherals.Redstone.BundleMask;
|
||||||
|
|
||||||
|
interface IRedstone {
|
||||||
|
function setOutput(on:Bool):Void;
|
||||||
|
function getOutput():Bool;
|
||||||
|
function getInput():Bool;
|
||||||
|
function setAnalogOutput(strength:Int):Void;
|
||||||
|
function getAnalogOutput():Int;
|
||||||
|
function getAnalogInput():Int;
|
||||||
|
function setBundledOutput(output:BundleMask):Void;
|
||||||
|
function getBundledOutput():BundleMask;
|
||||||
|
function getBundledInput():BundleMask;
|
||||||
|
function testBundledInput(mask:Color):Bool;
|
||||||
|
}
|
||||||
34
src/kernel/pocket/Pocket.hx
Normal file
34
src/kernel/pocket/Pocket.hx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package kernel.pocket;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
class Pocket {
|
||||||
|
public static function isPocket():Bool {
|
||||||
|
return cc.Pocket != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Search the player's inventory for another upgrade, replacing the existing one with that item if found.
|
||||||
|
This inventory search starts from the player's currently selected slot, allowing you to prioritise upgrades.
|
||||||
|
**/
|
||||||
|
public static function equipBack():Outcome<Noise, String> {
|
||||||
|
var r = cc.Pocket.equipBack();
|
||||||
|
if (r.successful) {
|
||||||
|
return Success(Noise);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Failure(r.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Remove the pocket computer's current upgrade.
|
||||||
|
**/
|
||||||
|
public static function unequipBack():Outcome<Noise, String> {
|
||||||
|
var r = cc.Pocket.unequipBack();
|
||||||
|
if (r.successful) {
|
||||||
|
return Success(Noise);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Failure(r.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,6 @@ package kernel.ps;
|
|||||||
/**
|
/**
|
||||||
Defines an independent process that can be run by the kernel.
|
Defines an independent process that can be run by the kernel.
|
||||||
**/
|
**/
|
||||||
interface Process {
|
interface IProcess {
|
||||||
public function run(handle:ProcessHandle):Void;
|
public function run(handle:ProcessHandle):Void;
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ class ProcessHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function get_args():ReadOnlyArray<String> {
|
public function get_args():ReadOnlyArray<String> {
|
||||||
return this.config.args;
|
return this.config.args != null ? this.config.args : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function claimTurtleMutex():Bool {
|
public function claimTurtleMutex():Bool {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ typedef PID = Int;
|
|||||||
class ProcessManager {
|
class ProcessManager {
|
||||||
private static final processList = new Map<PID, ProcessHandle>();
|
private static final processList = new Map<PID, ProcessHandle>();
|
||||||
|
|
||||||
public static function run(process:Process, config:HandleConfig):PID {
|
public static function run(process:IProcess, config:HandleConfig):PID {
|
||||||
var pid = createPID();
|
var pid = createPID();
|
||||||
var handle = new ProcessHandle(config, pid);
|
var handle = new ProcessHandle(config, pid);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package kernel.service;
|
package kernel.service;
|
||||||
|
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
import kernel.ps.ProcessManager;
|
import kernel.ps.ProcessManager;
|
||||||
import kernel.binstore.BinStore;
|
import kernel.binstore.BinStore;
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ class Service {
|
|||||||
public final name:String;
|
public final name:String;
|
||||||
public final args:Array<String>;
|
public final args:Array<String>;
|
||||||
public var pid:PID;
|
public var pid:PID;
|
||||||
public var ps:Process;
|
public var ps:IProcess;
|
||||||
|
|
||||||
@:allow(kernel.service.ServiceManager)
|
@:allow(kernel.service.ServiceManager)
|
||||||
private function new(binName:String, name:String, ?args:Array<String>) {
|
private function new(binName:String, name:String, ?args:Array<String>) {
|
||||||
|
|||||||
@@ -17,37 +17,46 @@ class ServiceManager {
|
|||||||
/**
|
/**
|
||||||
Add a service to be automatically started.
|
Add a service to be automatically started.
|
||||||
**/
|
**/
|
||||||
public static function enable(name:String) {
|
public static function enable(name:String):Outcome<Noise, String> {
|
||||||
if (!services.exists(name)) {
|
if (!services.exists(name)) {
|
||||||
return; // Service must be started
|
return Failure("Service must be started before enable");
|
||||||
}
|
}
|
||||||
|
|
||||||
var store = KVStore.getStoreForClass();
|
var store = KVStore.getStoreForClass();
|
||||||
|
store.load();
|
||||||
|
|
||||||
var enabled = store.get("enabled", []);
|
var enabled = store.get("enabled", []);
|
||||||
enabled.push(name);
|
enabled.push(name);
|
||||||
store.set("enabled", enabled);
|
store.set("enabled", enabled);
|
||||||
|
|
||||||
store.save();
|
store.save();
|
||||||
|
|
||||||
|
return Success(Noise);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove a service from being automatically started.
|
Remove a service from being automatically started.
|
||||||
**/
|
**/
|
||||||
private static function disable(name:String) {
|
private static function disable(name:String):Outcome<Noise, String> {
|
||||||
var store = KVStore.getStoreForClass();
|
var store = KVStore.getStoreForClass();
|
||||||
|
store.load();
|
||||||
|
|
||||||
var enabled:Array<String> = store.get("enabled");
|
var enabled:Array<String> = store.get("enabled");
|
||||||
var index = enabled.indexOf(name);
|
var index = enabled.indexOf(name);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return;
|
return Failure("Service not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
enabled.splice(index, 1);
|
enabled.splice(index, 1);
|
||||||
store.save();
|
store.save();
|
||||||
|
|
||||||
|
return Success(Noise);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function startAllEnabled() {
|
private static function startAllEnabled() {
|
||||||
var store = KVStore.getStoreForClass();
|
var store = KVStore.getStoreForClass();
|
||||||
|
store.load();
|
||||||
|
|
||||||
var enabled:Array<String> = store.get("enabled", []);
|
var enabled:Array<String> = store.get("enabled", []);
|
||||||
for (name in enabled) {
|
for (name in enabled) {
|
||||||
start(name);
|
start(name);
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ class Turtle {
|
|||||||
return r2;
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Dig in the provided direction.
|
||||||
|
Keep in mind that digging on a empty space is considerd a failure.
|
||||||
|
Also see `digEmpty`.
|
||||||
|
**/
|
||||||
public static function dig(dir:InteractDirections, ?toolSide:ToolSide):Outcome<Noise, String> {
|
public static function dig(dir:InteractDirections, ?toolSide:ToolSide):Outcome<Noise, String> {
|
||||||
var r:cc.Turtle.TurtleActionResult;
|
var r:cc.Turtle.TurtleActionResult;
|
||||||
|
|
||||||
@@ -87,6 +92,36 @@ class Turtle {
|
|||||||
return conterToOutcome(r);
|
return conterToOutcome(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Dig in the provided direction.
|
||||||
|
Does not fail if there is nothing to dig.
|
||||||
|
Also see `dig`.
|
||||||
|
**/
|
||||||
|
public static function digEmpty(dir:InteractDirections, ?toolSide:ToolSide):Outcome<Noise, String> {
|
||||||
|
var r:cc.Turtle.TurtleActionResult;
|
||||||
|
|
||||||
|
// FIXME: upstream needs to be fixed to accept ToolSide
|
||||||
|
switch dir {
|
||||||
|
case Front:
|
||||||
|
r = cc.Turtle.dig();
|
||||||
|
case Up:
|
||||||
|
r = cc.Turtle.digUp();
|
||||||
|
case Down:
|
||||||
|
r = cc.Turtle.digDown();
|
||||||
|
}
|
||||||
|
var result = conterToOutcome(r);
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case Success(_):
|
||||||
|
return result;
|
||||||
|
case Failure(failure):
|
||||||
|
if (failure == "Nothing to dig here") {
|
||||||
|
return Success(null);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function place(dir:InteractDirections):Outcome<Noise, String> {
|
public static function place(dir:InteractDirections):Outcome<Noise, String> {
|
||||||
var r:cc.Turtle.TurtleActionResult;
|
var r:cc.Turtle.TurtleActionResult;
|
||||||
switch dir {
|
switch dir {
|
||||||
@@ -119,23 +154,17 @@ class Turtle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function selectSlot(slot:TurtleSlot):Outcome<Noise, Noise> {
|
public static function selectSlot(slot:TurtleSlot):Outcome<Noise, Noise> {
|
||||||
// TODO: slot in bounds?
|
var r = cc.Turtle.select(slot.toCCSlot());
|
||||||
|
|
||||||
var r = cc.Turtle.select(slot + 1);
|
|
||||||
|
|
||||||
return (r) ? Outcome.Success(null) : Outcome.Failure("Slot out of bounds");
|
return (r) ? Outcome.Success(null) : Outcome.Failure("Slot out of bounds");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getItemCount(?slot:TurtleSlot):Int {
|
public static function getItemCount(?slot:TurtleSlot):Int {
|
||||||
// TODO: slot in bounds?
|
return cc.Turtle.getItemCount(slot.toCCSlot());
|
||||||
|
|
||||||
return cc.Turtle.getItemCount(slot + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getItemSpace(?slot:TurtleSlot):Int {
|
public static function getItemSpace(?slot:TurtleSlot):Int {
|
||||||
// TODO: slot in bounds?
|
return cc.Turtle.getItemSpace(slot.toCCSlot());
|
||||||
|
|
||||||
return cc.Turtle.getItemSpace(slot + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function detect(dir:InteractDirections):Bool {
|
public static function detect(dir:InteractDirections):Bool {
|
||||||
@@ -208,12 +237,12 @@ class Turtle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function compareSlot(otherSlot:TurtleSlot):Bool {
|
public static function compareSlot(otherSlot:TurtleSlot):Bool {
|
||||||
return cc.Turtle.compareTo(otherSlot + 1);
|
return cc.Turtle.compareTo(otherSlot.toCCSlot());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function transfer(from:TurtleSlot, to:TurtleSlot, ?count:Int):Outcome<Noise, Noise> {
|
public static function transfer(from:TurtleSlot, to:TurtleSlot, ?count:Int):Outcome<Noise, Noise> {
|
||||||
selectSlot(from);
|
selectSlot(from);
|
||||||
var r = cc.Turtle.transferTo(to + 1, count);
|
var r = cc.Turtle.transferTo(to.toCCSlot(), count);
|
||||||
return r ? Outcome.Success(null) : Outcome.Failure(null);
|
return r ? Outcome.Success(null) : Outcome.Failure(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +287,7 @@ class Turtle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function getItemDetail(slot:TurtleSlot, ?detailed:Bool = false):Option<ItemInspect> {
|
public static function getItemDetail(slot:TurtleSlot, ?detailed:Bool = false):Option<ItemInspect> {
|
||||||
var r = cc.Turtle.getItemDetail(slot + 1); // FIXME: can take detailed as flag. Has to be fixed upstream
|
var r = cc.Turtle.getItemDetail(slot.toCCSlot()); // FIXME: can take detailed as flag. Has to be fixed upstream
|
||||||
|
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return None;
|
return None;
|
||||||
|
|||||||
26
src/kernel/turtle/TurtleSlot.hx
Normal file
26
src/kernel/turtle/TurtleSlot.hx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package kernel.turtle;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The slot nummber for turtle inventory. 0 based. Assured to be in range.
|
||||||
|
**/
|
||||||
|
abstract TurtleSlot(Int) to Int {
|
||||||
|
public function new(i:Int) {
|
||||||
|
if (i >= 0 && i < Turtle.MAX_SLOTS) {
|
||||||
|
this = i;
|
||||||
|
} else {
|
||||||
|
throw new Error("Slot not in range: " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@:from
|
||||||
|
public static function fromInt(i:Int) {
|
||||||
|
return new TurtleSlot(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.turtle)
|
||||||
|
private inline function toCCSlot():Int {
|
||||||
|
return this + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,8 +22,3 @@ typedef ItemInspect = {
|
|||||||
public var damage:Int;
|
public var damage:Int;
|
||||||
public var count:Int;
|
public var count:Int;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
The slot nummber for turtle inventory. 0 based.
|
|
||||||
**/
|
|
||||||
typedef TurtleSlot = Int;
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package kernel.ui;
|
package kernel.ui;
|
||||||
|
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import kernel.ui.TermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
@@ -11,15 +11,15 @@ using tink.CoreApi;
|
|||||||
A term writer that can switch beetween its internal buffer and another termwriter.
|
A term writer that can switch beetween its internal buffer and another termwriter.
|
||||||
The other target is most of the time a real screen
|
The other target is most of the time a real screen
|
||||||
**/
|
**/
|
||||||
class BufferedVirtualTermWriter implements VirtualTermWriter extends TermBuffer {
|
class BufferedVirtualTermWriter implements IVirtualTermWriter extends TermBuffer {
|
||||||
private static final defaultSize:Vec2<Int> = {x: 50, y: 50};
|
private static final defaultSize:Vec2<Int> = {x: 50, y: 50};
|
||||||
|
|
||||||
private var target:TermWriteable;
|
private var target:ITermWriteable;
|
||||||
private var enabled:Bool = false;
|
private var enabled:Bool = false;
|
||||||
private var onResizeLink:CallbackLink;
|
private var onResizeLink:CallbackLink;
|
||||||
|
|
||||||
@:allow(kernel.ui)
|
@:allow(kernel.ui)
|
||||||
private function new(?target:TermWriteable) {
|
private function new(?target:ITermWriteable) {
|
||||||
setTarget(target);
|
setTarget(target);
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@@ -44,7 +44,7 @@ class BufferedVirtualTermWriter implements VirtualTermWriter extends TermBuffer
|
|||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTarget(newTarget:TermWriteable) {
|
public function setTarget(newTarget:ITermWriteable) {
|
||||||
if (newTarget != null) {
|
if (newTarget != null) {
|
||||||
super.setSize(newTarget.getSize());
|
super.setSize(newTarget.getSize());
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ class BufferedVirtualTermWriter implements VirtualTermWriter extends TermBuffer
|
|||||||
super.scroll(y);
|
super.scroll(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function getCursorPos():Pos {
|
public override function getCursorPos():ScreenPos {
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
return target.getCursorPos();
|
return target.getCursorPos();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package kernel.ui;
|
package kernel.ui;
|
||||||
|
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ using tink.CoreApi;
|
|||||||
/**
|
/**
|
||||||
Interface describing a terminal. E.g. the main computer screen or a external screen.
|
Interface describing a terminal. E.g. the main computer screen or a external screen.
|
||||||
**/
|
**/
|
||||||
interface TermWriteable {
|
interface ITermWriteable {
|
||||||
public var onResize(default, null):Signal<Vec2<Int>>;
|
public var onResize(default, null):Signal<Vec2<Int>>;
|
||||||
|
|
||||||
public function write(text:String):Void;
|
public function write(text:String):Void;
|
||||||
@@ -18,7 +18,7 @@ interface TermWriteable {
|
|||||||
/**
|
/**
|
||||||
Even though CC is 1 based we use a 0 based index.
|
Even though CC is 1 based we use a 0 based index.
|
||||||
**/
|
**/
|
||||||
public function getCursorPos():Pos;
|
public function getCursorPos():ScreenPos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Even though CC is 1 based we use a 0 based index.
|
Even though CC is 1 based we use a 0 based index.
|
||||||
@@ -4,9 +4,9 @@ package kernel.ui;
|
|||||||
A VirtualTermWriter is a TermWriteable that can be enabled or disabled.
|
A VirtualTermWriter is a TermWriteable that can be enabled or disabled.
|
||||||
When disabled, it will not write to its target. When enabled, it will.
|
When disabled, it will not write to its target. When enabled, it will.
|
||||||
**/
|
**/
|
||||||
interface VirtualTermWriter extends TermWriteable {
|
interface IVirtualTermWriter extends ITermWriteable {
|
||||||
public function enable():Void;
|
public function enable():Void;
|
||||||
public function disable():Void;
|
public function disable():Void;
|
||||||
public function isEnabled():Bool;
|
public function isEnabled():Bool;
|
||||||
public function setTarget(newTarget:TermWriteable):Void;
|
public function setTarget(newTarget:ITermWriteable):Void;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package kernel.ui;
|
package kernel.ui;
|
||||||
|
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
|
|
||||||
@@ -13,18 +13,18 @@ using tink.CoreApi;
|
|||||||
The render function is only called when needed.
|
The render function is only called when needed.
|
||||||
You can also request a re-render by calling `requestRender`.
|
You can also request a re-render by calling `requestRender`.
|
||||||
**/
|
**/
|
||||||
class StatelessVirtualTermWriter implements VirtualTermWriter {
|
class StatelessVirtualTermWriter implements IVirtualTermWriter {
|
||||||
public var onResize(default, null):Signal<Vec2<Int>>;
|
public var onResize(default, null):Signal<Vec2<Int>>;
|
||||||
|
|
||||||
private var onResizeTrigger:SignalTrigger<Vec2<Int>> = Signal.trigger();
|
private var onResizeTrigger:SignalTrigger<Vec2<Int>> = Signal.trigger();
|
||||||
private var target:TermWriteable;
|
private var target:ITermWriteable;
|
||||||
private var enabled:Bool = false;
|
private var enabled:Bool = false;
|
||||||
private var renderFunc:Null<Void->Void> = null;
|
private var renderFunc:Null<Void->Void> = null;
|
||||||
private var renderRequested:Bool = false;
|
private var renderRequested:Bool = false;
|
||||||
private var onResizeLink:CallbackLink;
|
private var onResizeLink:CallbackLink;
|
||||||
|
|
||||||
@:allow(kernel.ui)
|
@:allow(kernel.ui)
|
||||||
private function new(?target:TermWriteable) {
|
private function new(?target:ITermWriteable) {
|
||||||
onResize = onResizeTrigger.asSignal();
|
onResize = onResizeTrigger.asSignal();
|
||||||
setTarget(target);
|
setTarget(target);
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ class StatelessVirtualTermWriter implements VirtualTermWriter {
|
|||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTarget(newTarget:TermWriteable) {
|
public function setTarget(newTarget:ITermWriteable) {
|
||||||
if (newTarget == null) {
|
if (newTarget == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -110,8 +110,8 @@ class StatelessVirtualTermWriter implements VirtualTermWriter {
|
|||||||
target.scroll(y);
|
target.scroll(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function getCursorPos():Pos {
|
public inline function getCursorPos():ScreenPos {
|
||||||
return enabled ? target.getCursorPos() : new Pos({x: 0, y: 0});
|
return enabled ? target.getCursorPos() : new ScreenPos({x: 0, y: 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function setCursorPos(x:Int, y:Int) {
|
public inline function setCursorPos(x:Int, y:Int) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package kernel.ui;
|
package kernel.ui;
|
||||||
|
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import kernel.ui.TermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
@@ -12,13 +12,13 @@ using tink.CoreApi;
|
|||||||
even if its not displayed right now. When the GUI gets displayed again
|
even if its not displayed right now. When the GUI gets displayed again
|
||||||
this buffer will be written to the screen.
|
this buffer will be written to the screen.
|
||||||
**/
|
**/
|
||||||
class TermBuffer implements TermWriteable {
|
class TermBuffer implements ITermWriteable {
|
||||||
/**
|
/**
|
||||||
format [y][x]. First index is the line. Second index the char in the line.
|
format [y][x]. First index is the line. Second index the char in the line.
|
||||||
**/
|
**/
|
||||||
private var screenBuffer:Array<Array<Pixel>>;
|
private var screenBuffer:Array<Array<Pixel>>;
|
||||||
|
|
||||||
private var cursorPos:Pos = {x: 0, y: 0};
|
private var cursorPos:ScreenPos = {x: 0, y: 0};
|
||||||
private var currentTextColor:Color = White;
|
private var currentTextColor:Color = White;
|
||||||
private var currentBgColor:Color = Black;
|
private var currentBgColor:Color = Black;
|
||||||
private var cursorBlink:Bool = false;
|
private var cursorBlink:Bool = false;
|
||||||
@@ -60,7 +60,7 @@ class TermBuffer implements TermWriteable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function copyBufferToTarget(target:TermWriteable) {
|
private function copyBufferToTarget(target:ITermWriteable) {
|
||||||
target.setCursorPos(0, 0);
|
target.setCursorPos(0, 0);
|
||||||
target.setBackgroundColor(Black);
|
target.setBackgroundColor(Black);
|
||||||
target.setTextColor(White);
|
target.setTextColor(White);
|
||||||
@@ -91,7 +91,7 @@ class TermBuffer implements TermWriteable {
|
|||||||
target.setCursorBlink(cursorBlink);
|
target.setCursorBlink(cursorBlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function safeWriteScreenBuffer(pos:Pos, char:String) {
|
private function safeWriteScreenBuffer(pos:ScreenPos, char:String) {
|
||||||
if (screenBuffer.length > pos.y && screenBuffer[pos.y].length > pos.x) {
|
if (screenBuffer.length > pos.y && screenBuffer[pos.y].length > pos.x) {
|
||||||
screenBuffer[pos.y][pos.x].char = char;
|
screenBuffer[pos.y][pos.x].char = char;
|
||||||
screenBuffer[pos.y][pos.x].bg = currentBgColor;
|
screenBuffer[pos.y][pos.x].bg = currentBgColor;
|
||||||
@@ -121,7 +121,7 @@ class TermBuffer implements TermWriteable {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCursorPos():Pos {
|
public function getCursorPos():ScreenPos {
|
||||||
return cursorPos;
|
return cursorPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
package kernel.ui;
|
package kernel.ui;
|
||||||
|
|
||||||
import lib.ui.rendere.UIEventDelegate;
|
import lib.ui.rendere.IUIEventDelegate;
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import kernel.ButtonType;
|
import kernel.ButtonType;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
import kernel.ui.TermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The main object you interact with when writing anything to the screen.
|
The main object you interact with when writing anything to the screen.
|
||||||
**/
|
**/
|
||||||
class WindowContext implements TermWriteable {
|
class WindowContext implements ITermWriteable {
|
||||||
private final writer:VirtualTermWriter;
|
private final writer:IVirtualTermWriter;
|
||||||
|
|
||||||
@:allow(kernel.ui.WindowManager) private var eventDelegate:Null<UIEventDelegate>;
|
@:allow(kernel.ui.WindowManager) private var eventDelegate:Null<IUIEventDelegate>;
|
||||||
|
|
||||||
public var onClick(default, null):Signal<{button:ButtonType, pos:Pos}>;
|
public var onClick(default, null):Signal<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public var onKey(default, null):Signal<{keyCode:Int, isHeld:Bool}>;
|
public var onKey(default, null):Signal<{keyCode:Int, isHeld:Bool}>;
|
||||||
public var onKeyUp(default, null):Signal<Int>;
|
public var onKeyUp(default, null):Signal<Int>;
|
||||||
public var onMouseDrag(default, null):Signal<{button:ButtonType, pos:Pos}>;
|
public var onMouseDrag(default, null):Signal<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public var onMouseScroll(default, null):Signal<{dir:Int, pos:Pos}>;
|
public var onMouseScroll(default, null):Signal<{dir:Int, pos:ScreenPos}>;
|
||||||
public var onMouseUp(default, null):Signal<{button:ButtonType, pos:Pos}>;
|
public var onMouseUp(default, null):Signal<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public var onPaste(default, null):Signal<String>;
|
public var onPaste(default, null):Signal<String>;
|
||||||
public var onChar(default, null):Signal<String>;
|
public var onChar(default, null):Signal<String>;
|
||||||
|
|
||||||
@:allow(kernel.ui.WindowManager) private final onClickTrigger:SignalTrigger<{button:ButtonType, pos:Pos}>;
|
@:allow(kernel.ui.WindowManager) private final onClickTrigger:SignalTrigger<{button:ButtonType, pos:ScreenPos}>;
|
||||||
@:allow(kernel.ui.WindowManager) private final onKeyTrigger:SignalTrigger<{keyCode:Int, isHeld:Bool}>;
|
@:allow(kernel.ui.WindowManager) private final onKeyTrigger:SignalTrigger<{keyCode:Int, isHeld:Bool}>;
|
||||||
@:allow(kernel.ui.WindowManager) private final onKeyUpTrigger:SignalTrigger<Int>;
|
@:allow(kernel.ui.WindowManager) private final onKeyUpTrigger:SignalTrigger<Int>;
|
||||||
@:allow(kernel.ui.WindowManager) private final onMouseDragTrigger:SignalTrigger<{button:ButtonType, pos:Pos}>;
|
@:allow(kernel.ui.WindowManager) private final onMouseDragTrigger:SignalTrigger<{button:ButtonType, pos:ScreenPos}>;
|
||||||
@:allow(kernel.ui.WindowManager) private final onMouseScrollTrigger:SignalTrigger<{dir:Int, pos:Pos}>;
|
@:allow(kernel.ui.WindowManager) private final onMouseScrollTrigger:SignalTrigger<{dir:Int, pos:ScreenPos}>;
|
||||||
@:allow(kernel.ui.WindowManager) private final onMouseUpTrigger:SignalTrigger<{button:ButtonType, pos:Pos}>;
|
@:allow(kernel.ui.WindowManager) private final onMouseUpTrigger:SignalTrigger<{button:ButtonType, pos:ScreenPos}>;
|
||||||
@:allow(kernel.ui.WindowManager) private final onPasteTrigger:SignalTrigger<String>;
|
@:allow(kernel.ui.WindowManager) private final onPasteTrigger:SignalTrigger<String>;
|
||||||
@:allow(kernel.ui.WindowManager) private final onCharTrigger:SignalTrigger<String>;
|
@:allow(kernel.ui.WindowManager) private final onCharTrigger:SignalTrigger<String>;
|
||||||
|
|
||||||
@:allow(kernel.ui.WindowManager)
|
@:allow(kernel.ui.WindowManager)
|
||||||
private function new(writer:VirtualTermWriter) {
|
private function new(writer:IVirtualTermWriter) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.onResize = writer.onResize;
|
this.onResize = writer.onResize;
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ class WindowContext implements TermWriteable {
|
|||||||
public var onResize(default, null):Signal<Vec2<Int>>;
|
public var onResize(default, null):Signal<Vec2<Int>>;
|
||||||
|
|
||||||
@:allow(kernel.ui)
|
@:allow(kernel.ui)
|
||||||
private inline function setTarget(target:TermWriteable) {
|
private inline function setTarget(target:ITermWriteable) {
|
||||||
writer.setTarget(target);
|
writer.setTarget(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ class WindowContext implements TermWriteable {
|
|||||||
writer.scroll(y);
|
writer.scroll(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function getCursorPos():Pos {
|
public inline function getCursorPos():ScreenPos {
|
||||||
return writer.getCursorPos();
|
return writer.getCursorPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ class WindowContext implements TermWriteable {
|
|||||||
Delegate events to an UIEventDelegate.
|
Delegate events to an UIEventDelegate.
|
||||||
Set to null to stop delegating events.
|
Set to null to stop delegating events.
|
||||||
**/
|
**/
|
||||||
public inline function delegateEvents(delegate:Null<UIEventDelegate>) {
|
public inline function delegateEvents(delegate:Null<IUIEventDelegate>) {
|
||||||
this.eventDelegate = delegate;
|
this.eventDelegate = delegate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package kernel.ui;
|
|||||||
import kernel.ps.ProcessManager;
|
import kernel.ps.ProcessManager;
|
||||||
import kernel.ps.ProcessManager.PID;
|
import kernel.ps.ProcessManager.PID;
|
||||||
import haxe.ds.ReadOnlyArray;
|
import haxe.ds.ReadOnlyArray;
|
||||||
import kernel.ui.TermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,7 +143,7 @@ class WindowManager {
|
|||||||
Move context to output. If output is "main", context will be moved to main screen.
|
Move context to output. If output is "main", context will be moved to main screen.
|
||||||
**/
|
**/
|
||||||
public static function focusContextToOutput(context:WindowContext, output:String) {
|
public static function focusContextToOutput(context:WindowContext, output:String) {
|
||||||
var target:TermWriteable;
|
var target:ITermWriteable;
|
||||||
if (output == "main") {
|
if (output == "main") {
|
||||||
target = MainTerm.instance;
|
target = MainTerm.instance;
|
||||||
currentMainContext = context;
|
currentMainContext = context;
|
||||||
|
|||||||
12
src/lib/Block.hx
Normal file
12
src/lib/Block.hx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
class Block {
|
||||||
|
public final name:PaN;
|
||||||
|
public final tags:Tags;
|
||||||
|
|
||||||
|
public function new(name:String, tags:Tags) {
|
||||||
|
this.name = name;
|
||||||
|
this.tags = tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/lib/BlockBlockMap.hx
Normal file
114
src/lib/BlockBlockMap.hx
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import kernel.peripherals.GeoScanner.ScanBlock;
|
||||||
|
import lib.BlockMap;
|
||||||
|
|
||||||
|
@:forward
|
||||||
|
abstract BlockBlockMap(BlockMap<Block>) {
|
||||||
|
public inline function new() {
|
||||||
|
this = new BlockMap<Block>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromScan(scan:Array<ScanBlock>):BlockBlockMap {
|
||||||
|
var map:BlockBlockMap = new BlockBlockMap();
|
||||||
|
|
||||||
|
for (block in scan) {
|
||||||
|
map.set(block.pos, new Block(block.name, block.tags));
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Navigate from one point into another.
|
||||||
|
Returns the path to take.
|
||||||
|
Based on A*
|
||||||
|
**/
|
||||||
|
public function nav(from:BlockPos, to:BlockPos):Array<BlockPos> {
|
||||||
|
if (!canPass(to)) {
|
||||||
|
trace("End is blocked");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var openSet = new PriorityQueue();
|
||||||
|
openSet.insert(from, 0);
|
||||||
|
|
||||||
|
var cameFrom:BlockMap<BlockPos> = new BlockMap();
|
||||||
|
|
||||||
|
var gCost:BlockMap<Int> = new BlockMap(); // G cost is the distance from start
|
||||||
|
gCost.set(from, 0);
|
||||||
|
|
||||||
|
var fCost:BlockMap<Float> = new BlockMap(); // F cost is the combines cost of moving to this pos (G cost) + the distnace to the end
|
||||||
|
fCost.set(from, from.distance(to));
|
||||||
|
|
||||||
|
while (!openSet.isEmpty()) {
|
||||||
|
var current = openSet.extractMin(); // Check the pos with the lowest F cost
|
||||||
|
|
||||||
|
if (current.equals(to)) {
|
||||||
|
var totalPath = [];
|
||||||
|
var currentPathPos = to;
|
||||||
|
|
||||||
|
while (cameFrom.exists(currentPathPos)) {
|
||||||
|
totalPath.unshift(currentPathPos);
|
||||||
|
currentPathPos = cameFrom.get(currentPathPos);
|
||||||
|
}
|
||||||
|
totalPath.unshift(from);
|
||||||
|
|
||||||
|
return totalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (neighbor in current.neighbors()) {
|
||||||
|
if (!canPass(neighbor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newGCost = gCost.get(current) + 1; // Movment cost to neighbor is always 1 as we can't move diagonally
|
||||||
|
|
||||||
|
if (newGCost < (gCost.get(neighbor) ?? 9999)) {
|
||||||
|
cameFrom.set(neighbor, current);
|
||||||
|
gCost.set(neighbor, newGCost);
|
||||||
|
fCost.set(neighbor, newGCost + neighbor.distance(to));
|
||||||
|
|
||||||
|
if (!openSet.containsElement(neighbor)) {
|
||||||
|
openSet.insert(neighbor, fCost.get(neighbor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Some block can be passed by the turtle.
|
||||||
|
Some blocks get destroyed by it.
|
||||||
|
**/
|
||||||
|
public function canPass(k:BlockPos):Bool {
|
||||||
|
var block = this.get(k);
|
||||||
|
if (block == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch block.name {
|
||||||
|
case "minecraft:water":
|
||||||
|
return true;
|
||||||
|
case "minecaft:lava":
|
||||||
|
case "mimecraft:grass":
|
||||||
|
case "minecraft:hanging_roots":
|
||||||
|
case "minecraft:warped_roots":
|
||||||
|
case "minecraft:dead_bush":
|
||||||
|
case "minecraft:fern":
|
||||||
|
case "minecraft:vine":
|
||||||
|
case "minecraft:glow_lichen":
|
||||||
|
case "minecraft:seagrass":
|
||||||
|
case "minecraft:crimson_roots":
|
||||||
|
case "minecraft:nether_sprouts":
|
||||||
|
case "minecraft:snow":
|
||||||
|
case "minecraft:rose_bush":
|
||||||
|
case "minecraft:fire":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/lib/BlockMap.hx
Normal file
48
src/lib/BlockMap.hx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import haxe.ds.IntMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Map values to positions in 3D space. For representing blocks from a scan see `BlockBlockMap`.
|
||||||
|
|
||||||
|
The only reason this exsists is that the abstract class for BlockPos does not
|
||||||
|
satisfy the constraint of HashMap. The hashCode function needs to be on a real class and not on
|
||||||
|
an abstract class. Thanks Obama.
|
||||||
|
**/
|
||||||
|
@:forward(iterator, clear)
|
||||||
|
abstract BlockMap<T>(IntMap<T>) {
|
||||||
|
/**
|
||||||
|
Creates a new HashMap.
|
||||||
|
**/
|
||||||
|
public inline function new() {
|
||||||
|
this = new IntMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
See `Map.set`
|
||||||
|
**/
|
||||||
|
@:arrayAccess public inline function set(k:BlockPos, v:T) {
|
||||||
|
this.set(k.hashCode(), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
See `Map.get`
|
||||||
|
**/
|
||||||
|
@:arrayAccess public inline function get(k:BlockPos) {
|
||||||
|
return this.get(k.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
See `Map.exists`
|
||||||
|
**/
|
||||||
|
public inline function exists(k:BlockPos) {
|
||||||
|
return this.exists(k.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
See `Map.remove`
|
||||||
|
**/
|
||||||
|
public inline function remove(k:BlockPos) {
|
||||||
|
return this.remove(k.hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/lib/BlockPos.hx
Normal file
78
src/lib/BlockPos.hx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import lib.Vec.Vec2;
|
||||||
|
import lib.Vec.Vec3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Represents a Point in a 3D `Int` System.
|
||||||
|
Basicly a wrapper for Vec3<Int> with some extra functions.
|
||||||
|
`Y` represents the height of the point.
|
||||||
|
**/
|
||||||
|
@:forward
|
||||||
|
abstract BlockPos(Vec3<Int>) from Vec3<Int> to Vec3<Int> {
|
||||||
|
public inline function new(x:Int, y:Int, z:Int) {
|
||||||
|
this = new Vec3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A + B)
|
||||||
|
public inline function add(rhs:BlockPos):BlockPos {
|
||||||
|
return this.add(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A - B)
|
||||||
|
public inline function sub(rhs:BlockPos):BlockPos {
|
||||||
|
return this.sub(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A * B)
|
||||||
|
public inline function multiplyScalar(rhs:Int):BlockPos {
|
||||||
|
return this.multiplyScalar(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(-A)
|
||||||
|
public inline function negate():BlockPos {
|
||||||
|
return this.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A == B)
|
||||||
|
public function equals(rhs:BlockPos):Bool {
|
||||||
|
return this.x == rhs.x && this.y == rhs.y && this.z == rhs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A != B)
|
||||||
|
public function notEquals(rhs:BlockPos):Bool {
|
||||||
|
return !equals(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hashCode():Int {
|
||||||
|
return (this.x * 73856093) ^ (this.y * 19349663) ^ (this.z * 83492791);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString():String {
|
||||||
|
return 'BlockPos(${this.x}, ${this.y}, ${this.z})';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the chunk the position is in.
|
||||||
|
**/
|
||||||
|
public function chunk():Vec2<Int> {
|
||||||
|
var x = Math.floor(this.x / 16);
|
||||||
|
var z = Math.floor(this.z / 16);
|
||||||
|
|
||||||
|
return new Vec2(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of positions neighboring the block. No Diagonal.
|
||||||
|
**/
|
||||||
|
public function neighbors():Array<BlockPos> {
|
||||||
|
return [
|
||||||
|
new BlockPos(this.x + 1, this.y + 0, this.z + 0), // Front
|
||||||
|
new BlockPos(this.x - 1, this.y + 0, this.z + 0), // Back
|
||||||
|
new BlockPos(this.x + 0, this.y + 0, this.z - 1), // Left
|
||||||
|
new BlockPos(this.x + 0, this.y + 0, this.z + 1), // Right
|
||||||
|
new BlockPos(this.x + 0, this.y - 1, this.z + 0), // Bot
|
||||||
|
new BlockPos(this.x + 0, this.y + 1, this.z + 0), // Top
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
package lib;
|
package lib;
|
||||||
|
|
||||||
import kernel.ps.Process;
|
import lib.args.CLIArgs;
|
||||||
|
import lib.args.ArgType;
|
||||||
|
import kernel.ps.IProcess;
|
||||||
import kernel.ps.ProcessHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
abstract class CLIAppBase implements Process {
|
abstract class CLIAppBase implements IProcess {
|
||||||
private var handle:ProcessHandle;
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
private final _subcommandsSync:Map<String, (Array<String>) -> Bool> = [];
|
private final _subcommandsSync:Map<String, (CLIArgs) -> Bool> = [];
|
||||||
private final _subcommandsAsync:Map<String, (Array<String>) -> Future<Bool>> = [];
|
private final _subcommandsAsync:Map<String, (CLIArgs) -> Future<Bool>> = [];
|
||||||
private final _subcommandsSynopsis:Array<String> = [];
|
private final _subcommandsArgs:Map<String, Array<ArgType>> = [];
|
||||||
|
|
||||||
public final function run(handle:ProcessHandle) {
|
public final function run(handle:ProcessHandle) {
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
@@ -26,10 +28,19 @@ abstract class CLIAppBase implements Process {
|
|||||||
var args = handle.args.slice(1);
|
var args = handle.args.slice(1);
|
||||||
|
|
||||||
if (_subcommandsSync.exists(subcommand)) {
|
if (_subcommandsSync.exists(subcommand)) {
|
||||||
var result = _subcommandsSync[subcommand](args);
|
var argParser = new CLIArgs(_subcommandsArgs.get(subcommand));
|
||||||
return handle.close(result);
|
if (!argParser.parse(args)) {
|
||||||
|
handle.writeLine(argParser.getError());
|
||||||
|
return handle.close(false);
|
||||||
|
}
|
||||||
|
return handle.close(_subcommandsSync[subcommand](argParser));
|
||||||
} else if (_subcommandsAsync.exists(subcommand)) {
|
} else if (_subcommandsAsync.exists(subcommand)) {
|
||||||
_subcommandsAsync[subcommand](args).handle(handle.close);
|
var argParser = new CLIArgs(_subcommandsArgs.get(subcommand));
|
||||||
|
if (!argParser.parse(args)) {
|
||||||
|
handle.writeLine(argParser.getError());
|
||||||
|
return handle.close(false);
|
||||||
|
}
|
||||||
|
_subcommandsAsync[subcommand](argParser).handle(handle.close);
|
||||||
} else {
|
} else {
|
||||||
handle.writeLine("Unknown subcommand: " + subcommand);
|
handle.writeLine("Unknown subcommand: " + subcommand);
|
||||||
printHelp();
|
printHelp();
|
||||||
@@ -37,21 +48,21 @@ abstract class CLIAppBase implements Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function registerSyncSubcommand(command:String, callback:(Array<String>) -> Bool, synopsis:String = null) {
|
private function registerSyncSubcommand(command:String, callback:(CLIArgs) -> Bool, args:Array<ArgType> = null) {
|
||||||
_subcommandsSync.set(command, callback);
|
_subcommandsSync.set(command, callback);
|
||||||
_subcommandsSynopsis.push(command + " " + (synopsis ?? ""));
|
_subcommandsArgs.set(command, args ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function registerAsyncSubcommand(command:String, callback:(Array<String>) -> Future<Bool>, synopsis:String = null) {
|
private function registerAsyncSubcommand(command:String, callback:(CLIArgs) -> Future<Bool>, args:Array<ArgType> = null) {
|
||||||
_subcommandsAsync.set(command, callback);
|
_subcommandsAsync.set(command, callback);
|
||||||
_subcommandsSynopsis.push(command + " " + (synopsis ?? ""));
|
_subcommandsArgs.set(command, args ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function printHelp() {
|
private function printHelp() {
|
||||||
handle.writeLine("Usage: <subcommand> [args]");
|
handle.writeLine("Usage: <subcommand> [args]");
|
||||||
handle.writeLine("Subcommands:");
|
handle.writeLine("Subcommands:");
|
||||||
for (subcommand in _subcommandsSynopsis) {
|
for (k => v in this._subcommandsArgs) {
|
||||||
handle.writeLine(" " + subcommand);
|
handle.writeLine(' $k ${CLIArgs.getSynopsis(v)}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package lib;
|
package lib;
|
||||||
|
|
||||||
|
import kernel.http.HTTPRequest.Http;
|
||||||
import lua.TableTools;
|
import lua.TableTools;
|
||||||
import kernel.KernelEvents;
|
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
import lua.NativeStringTools;
|
import lua.NativeStringTools;
|
||||||
import lib.ui.Canvas;
|
import lib.ui.Canvas;
|
||||||
@@ -9,6 +9,7 @@ import cc.ComputerCraft;
|
|||||||
#if webconsole
|
#if webconsole
|
||||||
import cc.HTTP;
|
import cc.HTTP;
|
||||||
import kernel.net.Net;
|
import kernel.net.Net;
|
||||||
|
import kernel.log.LogLine;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
class Debug {
|
class Debug {
|
||||||
@@ -66,8 +67,8 @@ class Debug {
|
|||||||
#end
|
#end
|
||||||
|
|
||||||
#if webconsole
|
#if webconsole
|
||||||
public static function printWeb(msg:String) {
|
public static function logToWebconsole(line:LogLine) {
|
||||||
HTTP.request("http://127.0.0.1:8080/" + Net.networkID, msg);
|
Http.request('http://127.0.0.1:8080/log/${Net.networkID}/${line.level.getIndex()}', '[${line.origin}] ${line.message}').eager();
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
package lib;
|
|
||||||
|
|
||||||
import haxe.Exception;
|
|
||||||
|
|
||||||
class LambdaExtender {
|
|
||||||
/**
|
|
||||||
Returns the first element if there are exectly one element present.
|
|
||||||
Throws exception if not.
|
|
||||||
**/
|
|
||||||
static public function single<T>(it:Iterable<T>):T {
|
|
||||||
var elem:T = null;
|
|
||||||
for (t in it) {
|
|
||||||
if (elem != null) {
|
|
||||||
throw new Exception("Multiple elements found");
|
|
||||||
}
|
|
||||||
elem = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elem == null) {
|
|
||||||
throw new Exception("No element found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Like `single` but when no element was found return the default value.
|
|
||||||
**/
|
|
||||||
static public function singleOrDefault<T>(it:Iterable<T>, defaultValue:T):T {
|
|
||||||
var elem:T = null;
|
|
||||||
for (t in it) {
|
|
||||||
if (elem != null) {
|
|
||||||
throw new Exception("Multiple elements found");
|
|
||||||
}
|
|
||||||
elem = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elem == null) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the first element.
|
|
||||||
Throws execption if no first element found.
|
|
||||||
**/
|
|
||||||
static public function first<T>(it:Iterable<T>):T {
|
|
||||||
for (t in it) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("No element found");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Like `first` only if no first element was found it returns the defalt value.
|
|
||||||
**/
|
|
||||||
static public function firstOrDefault<T>(it:Iterable<T>, defaultValue:T):T {
|
|
||||||
var iter = it.iterator();
|
|
||||||
|
|
||||||
if (iter.hasNext()) {
|
|
||||||
return iter.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,10 +4,10 @@ import kernel.log.Log;
|
|||||||
import kernel.binstore.BinStore;
|
import kernel.binstore.BinStore;
|
||||||
import kernel.peripherals.Screen;
|
import kernel.peripherals.Screen;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
import kernel.ps.Process;
|
import kernel.ps.IProcess;
|
||||||
import kernel.ps.ProcessManager;
|
import kernel.ps.ProcessManager;
|
||||||
import bin.KernelLog;
|
import bin.KernelLog;
|
||||||
import lib.ui.elements.UIElement;
|
import lib.ui.elements.IUIElement;
|
||||||
import lib.ui.elements.TextElement;
|
import lib.ui.elements.TextElement;
|
||||||
import lib.ui.elements.RootElement;
|
import lib.ui.elements.RootElement;
|
||||||
import kernel.KernelEvents;
|
import kernel.KernelEvents;
|
||||||
@@ -148,7 +148,7 @@ class HomeContext {
|
|||||||
var workspaceIDs:Array<Int> = [for (k => v in workspaces) k];
|
var workspaceIDs:Array<Int> = [for (k => v in workspaces) k];
|
||||||
workspaceIDs.sort((a, b) -> a - b);
|
workspaceIDs.sort((a, b) -> a - b);
|
||||||
|
|
||||||
var children:Array<UIElement> = [
|
var children:Array<IUIElement> = [
|
||||||
for (i in workspaceIDs)
|
for (i in workspaceIDs)
|
||||||
new TextElement('Switch to ${i + 1}', {uiEvents: {onClick: this.handleSelectContext.bind(i)}})
|
new TextElement('Switch to ${i + 1}', {uiEvents: {onClick: this.handleSelectContext.bind(i)}})
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package lib;
|
|||||||
/**
|
/**
|
||||||
Represents an item in the game.
|
Represents an item in the game.
|
||||||
**/
|
**/
|
||||||
abstract Item(String) to String {
|
@:forward
|
||||||
|
enum abstract Item(PaN) to String {
|
||||||
public inline function new(name:String) {
|
public inline function new(name:String) {
|
||||||
// Check if the name is valid. in the format `mod:item_name` e.g. `minecraft:apple`
|
// Check if the name is valid. in the format `mod:item_name` e.g. `minecraft:apple`
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
@@ -16,7 +17,6 @@ abstract Item(String) to String {
|
|||||||
return new Item(s);
|
return new Item(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBase():String {
|
var Coal = "minecraft:coal";
|
||||||
return this.split(":")[0];
|
var Charcoal = "minecraft:charcoal";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
package lib;
|
package lib;
|
||||||
|
|
||||||
import haxe.Serializer;
|
|
||||||
import haxe.Unserializer;
|
|
||||||
import kernel.fs.FS;
|
import kernel.fs.FS;
|
||||||
import haxe.ds.StringMap;
|
import haxe.ds.StringMap;
|
||||||
|
#if kv_use_native
|
||||||
|
import cc.TextUtils;
|
||||||
|
#else
|
||||||
|
import haxe.Unserializer;
|
||||||
|
import haxe.Serializer;
|
||||||
|
#end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Key value store with persistence.
|
Key value store with persistence.
|
||||||
|
Use flag kv_use_native to use the cc serialization.
|
||||||
**/
|
**/
|
||||||
class KVStore {
|
class KVStore {
|
||||||
private var kvStore:StringMap<Dynamic> = new StringMap();
|
private var kvStore:StringMap<Dynamic> = new StringMap();
|
||||||
@@ -43,14 +48,21 @@ class KVStore {
|
|||||||
public function save() {
|
public function save() {
|
||||||
var handle = FS.openWrite(getNamespaceFile(this.namespace));
|
var handle = FS.openWrite(getNamespaceFile(this.namespace));
|
||||||
|
|
||||||
|
#if kv_use_native
|
||||||
|
handle.write(TextUtils.serialize(this.kvStore));
|
||||||
|
#else
|
||||||
handle.write(Serializer.run(this.kvStore));
|
handle.write(Serializer.run(this.kvStore));
|
||||||
|
#end
|
||||||
handle.close();
|
handle.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseFile(content:String) {
|
private function parseFile(content:String) {
|
||||||
|
#if kv_use_native
|
||||||
|
this.kvStore = TextUtils.unserialize(content);
|
||||||
|
#else
|
||||||
var unserializer = new Unserializer(content);
|
var unserializer = new Unserializer(content);
|
||||||
this.kvStore = unserializer.unserialize();
|
this.kvStore = unserializer.unserialize();
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function set(key:String, value:Dynamic) {
|
public inline function set(key:String, value:Dynamic) {
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package lib;
|
|
||||||
|
|
||||||
class ObjMerge {
|
|
||||||
public static function merge<T>(obj1:T, obj2:T):T {
|
|
||||||
if (obj1 == null) {
|
|
||||||
return obj2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj2 == null) {
|
|
||||||
return obj1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rtn:T = Reflect.copy(obj1);
|
|
||||||
var fields = Reflect.fields(obj2);
|
|
||||||
|
|
||||||
for (field in fields) {
|
|
||||||
if (Reflect.getProperty(obj1, field) == null) {
|
|
||||||
Reflect.setProperty(rtn, field, Reflect.getProperty(obj2, field));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (rtn : T);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
18
src/lib/PaN.hx
Normal file
18
src/lib/PaN.hx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Provider and name. e.g. "minecraft:dirt", "mod:item", "minecraft:overworld"
|
||||||
|
**/
|
||||||
|
abstract PaN(String) to String from String {
|
||||||
|
public inline function new(pan:String) {
|
||||||
|
this = pan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProvider():String {
|
||||||
|
return this.split(":")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName():String {
|
||||||
|
return this.split(":")[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package lib;
|
|
||||||
|
|
||||||
import lib.Vec.Vec2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Reporesents a Point in a 2D `Int` System.
|
|
||||||
Basicly a wrapper for Vec2<Int> with some extra functions.
|
|
||||||
**/
|
|
||||||
@:forward(x, y)
|
|
||||||
abstract Pos(Vec2<Int>) from Vec2<Int> to Vec2<Int> {
|
|
||||||
inline public function new(i:Vec2<Int>) {
|
|
||||||
this = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A + B)
|
|
||||||
public function add(rhs:Vec2<Int>):Pos {
|
|
||||||
return new Pos({
|
|
||||||
y: this.y + rhs.y,
|
|
||||||
x: this.x + rhs.x,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A - B)
|
|
||||||
public function sub(rhs:Vec2<Int>):Pos {
|
|
||||||
return new Pos({
|
|
||||||
y: this.y - rhs.y,
|
|
||||||
x: this.x - rhs.x,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A * B)
|
|
||||||
public function multiply(rhs:Vec2<Int>):Pos {
|
|
||||||
return new Pos({
|
|
||||||
y: this.y * rhs.y,
|
|
||||||
x: this.x * rhs.x,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(-A)
|
|
||||||
public function negate():Pos {
|
|
||||||
return new Pos({
|
|
||||||
y: -this.y,
|
|
||||||
x: -this.x,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
111
src/lib/Pos3.hx
111
src/lib/Pos3.hx
@@ -1,111 +0,0 @@
|
|||||||
package lib;
|
|
||||||
|
|
||||||
import lib.Vec.Vec3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Reporesents a Point in a 3D `Float` System.
|
|
||||||
Basicly a wrapper for Vec3<Float> with some extra functions.
|
|
||||||
`Y` represents the height of the point.
|
|
||||||
**/
|
|
||||||
@:forward(x, y, z)
|
|
||||||
abstract Pos3(Vec3<Float>) from Vec3<Float> to Vec3<Float> {
|
|
||||||
inline public function new(i:Vec3<Float>) {
|
|
||||||
this = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A + B)
|
|
||||||
public function add(rhs:Vec3<Float>):Pos3 {
|
|
||||||
return new Pos3({
|
|
||||||
y: this.y + rhs.y,
|
|
||||||
x: this.x + rhs.x,
|
|
||||||
z: this.z + rhs.z
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A - B)
|
|
||||||
public function sub(rhs:Vec3<Float>):Pos3 {
|
|
||||||
return new Pos3({
|
|
||||||
y: this.y - rhs.y,
|
|
||||||
x: this.x - rhs.x,
|
|
||||||
z: this.z - rhs.z
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A * B)
|
|
||||||
public function multiplyScalar(rhs:Float):Pos3 {
|
|
||||||
return new Pos3({
|
|
||||||
y: this.y * rhs,
|
|
||||||
x: this.x * rhs,
|
|
||||||
z: this.z * rhs
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A / B)
|
|
||||||
public function divideScalar(rhs:Float):Pos3 {
|
|
||||||
return new Pos3({
|
|
||||||
y: this.y / rhs,
|
|
||||||
x: this.x / rhs,
|
|
||||||
z: this.z / rhs
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(-A)
|
|
||||||
public function negate():Pos3 {
|
|
||||||
return new Pos3({
|
|
||||||
y: -this.y,
|
|
||||||
x: -this.x,
|
|
||||||
z: -this.z
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function dot(rhs:Vec3<Float>):Float {
|
|
||||||
return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cross(rhs:Vec3<Float>):Pos3 {
|
|
||||||
return new Pos3({
|
|
||||||
x: this.y * rhs.z - this.z * rhs.y,
|
|
||||||
y: this.z * rhs.x - this.x * rhs.z,
|
|
||||||
z: this.x * rhs.y - this.y * rhs.x
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function normalize():Pos3 {
|
|
||||||
var l = length();
|
|
||||||
return multiplyScalar(1 / l);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function length():Float {
|
|
||||||
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A == B)
|
|
||||||
public function equals(rhs:Pos3):Bool {
|
|
||||||
return close(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@:op(A != B)
|
|
||||||
public function notEquals(rhs:Pos3):Bool {
|
|
||||||
return !close(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close(rhs:Pos3, epsilon:Float = 0.001):Bool {
|
|
||||||
return Math.abs(this.x - rhs.x) < epsilon && Math.abs(this.y - rhs.y) < epsilon && Math.abs(this.z - rhs.z) < epsilon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toString():String {
|
|
||||||
return 'Pos3(${this.x}, ${this.y}, ${this.z})';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function round():Pos3 {
|
|
||||||
return new Pos3({
|
|
||||||
x: Math.fround(this.x),
|
|
||||||
y: Math.fround(this.y),
|
|
||||||
z: Math.fround(this.z)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function distance(rhs:Pos3):Float {
|
|
||||||
return Math.sqrt(Math.pow(this.x - rhs.x, 2) + Math.pow(this.y - rhs.y, 2) + Math.pow(this.z - rhs.z, 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
69
src/lib/PriorityQueue.hx
Normal file
69
src/lib/PriorityQueue.hx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
|
||||||
|
abstract PriorityQueue<T>(Array<{prio:Float, val:T}>) {
|
||||||
|
public inline function new() {
|
||||||
|
this = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function containsElement(element:T):Bool {
|
||||||
|
return this.exists((e) -> e.val == element);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmpty():Bool {
|
||||||
|
return this.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insert(e:T, prio:Float) {
|
||||||
|
this.push({prio: prio, val: e});
|
||||||
|
bubbleUp(this.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extractMin():Null<T> {
|
||||||
|
if (this.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(0, this.length - 1);
|
||||||
|
var minElement = this.pop();
|
||||||
|
|
||||||
|
bubbleDown(0);
|
||||||
|
|
||||||
|
return minElement.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function bubbleUp(index:Int) {
|
||||||
|
var parentIndex:Int = Math.floor((index - 1) / 2);
|
||||||
|
|
||||||
|
if (index > 0 && this[index].prio < this[parentIndex].prio) {
|
||||||
|
swap(index, parentIndex);
|
||||||
|
bubbleUp(parentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function bubbleDown(index:Int) {
|
||||||
|
var leftIndex = 2 * index + 1;
|
||||||
|
var rightIndex = 2 * index + 2;
|
||||||
|
var smallest = index;
|
||||||
|
|
||||||
|
if (leftIndex < this.length && this[leftIndex].prio < this[smallest].prio) {
|
||||||
|
smallest = leftIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightIndex < this.length && this[rightIndex].prio < this[smallest].prio) {
|
||||||
|
smallest = rightIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smallest != index) {
|
||||||
|
swap(index, smallest);
|
||||||
|
bubbleDown(smallest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function swap(i:Int, j:Int) {
|
||||||
|
var tmp = this[i];
|
||||||
|
this[i] = this[j];
|
||||||
|
this[j] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package lib;
|
package lib;
|
||||||
|
|
||||||
class Rect {
|
import kernel.peripherals.Screen;
|
||||||
private final tl:Pos;
|
|
||||||
private final br:Pos;
|
|
||||||
|
|
||||||
public function new(p1:Pos, p2:Pos) {
|
class Rect {
|
||||||
|
public final tl:ScreenPos;
|
||||||
|
public final br:ScreenPos;
|
||||||
|
|
||||||
|
public function new(p1:ScreenPos, p2:ScreenPos) {
|
||||||
this.tl = {
|
this.tl = {
|
||||||
x: MathI.min(p1.x, p2.x),
|
x: MathI.min(p1.x, p2.x),
|
||||||
y: MathI.min(p1.y, p2.y)
|
y: MathI.min(p1.y, p2.y)
|
||||||
@@ -20,11 +22,11 @@ class Rect {
|
|||||||
return getWidth() * getHight();
|
return getWidth() * getHight();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isInside(p:Pos):Bool {
|
public function isInside(p:ScreenPos):Bool {
|
||||||
return (p.x >= tl.x && p.x <= br.x) && (p.y >= tl.y && p.y <= br.y);
|
return (p.x >= tl.x && p.x <= br.x) && (p.y >= tl.y && p.y <= br.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isOutside(p:Pos):Bool {
|
public function isOutside(p:ScreenPos):Bool {
|
||||||
return !this.isInside(p);
|
return !this.isInside(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +38,7 @@ class Rect {
|
|||||||
return br.x - tl.x;
|
return br.x - tl.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offset(pos:Pos) {
|
public function offset(pos:ScreenPos) {
|
||||||
tl.x += pos.x;
|
tl.x += pos.x;
|
||||||
tl.y += pos.y;
|
tl.y += pos.y;
|
||||||
br.x += pos.x;
|
br.x += pos.x;
|
||||||
|
|||||||
34
src/lib/ScreenPos.hx
Normal file
34
src/lib/ScreenPos.hx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import lib.Vec.Vec2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reporesents a Point in a 2D `Int` System.
|
||||||
|
Basicly a wrapper for Vec2<Int> with some extra functions.
|
||||||
|
**/
|
||||||
|
@:forward(x, y)
|
||||||
|
abstract ScreenPos(Vec2<Int>) from Vec2<Int> to Vec2<Int> {
|
||||||
|
inline public function new(i:Vec2<Int>) {
|
||||||
|
this = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A + B)
|
||||||
|
public inline function add(rhs:Vec2<Int>):ScreenPos {
|
||||||
|
return this.add(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A - B)
|
||||||
|
public inline function sub(rhs:Vec2<Int>):ScreenPos {
|
||||||
|
return this.sub(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A * B)
|
||||||
|
public inline function multiply(rhs:Vec2<Int>):ScreenPos {
|
||||||
|
return this.multiply(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(-A)
|
||||||
|
public inline function negate():ScreenPos {
|
||||||
|
return this.negate();
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/lib/SinglePromise.hx
Normal file
55
src/lib/SinglePromise.hx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import kernel.EndOfLoop;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
class SinglePromise<T> {
|
||||||
|
private var inProgress:Bool = false;
|
||||||
|
private var interalPromise:Promise<T> = null;
|
||||||
|
private var interalResolve:T->Void = null;
|
||||||
|
private var interalReject:(Error->Void) = null;
|
||||||
|
private final activate:Void->Void;
|
||||||
|
|
||||||
|
public function new(activate:Void->Void) {
|
||||||
|
this.activate = activate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function request():Promise<T> {
|
||||||
|
if (this.inProgress) {
|
||||||
|
trace("Is progress");
|
||||||
|
return this.interalPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inProgress = true;
|
||||||
|
|
||||||
|
this.interalPromise = new Promise((resolve, reject) -> {
|
||||||
|
this.interalResolve = resolve;
|
||||||
|
this.interalReject = reject;
|
||||||
|
|
||||||
|
this.activate();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.interalPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRunning():Bool {
|
||||||
|
return this.inProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolve(val:T) {
|
||||||
|
if (this.inProgress) {
|
||||||
|
this.inProgress = false;
|
||||||
|
this.interalResolve(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reject(err:Error) {
|
||||||
|
if (this.inProgress) {
|
||||||
|
this.inProgress = false;
|
||||||
|
this.interalReject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/lib/SingleTimeoutPromise.hx
Normal file
64
src/lib/SingleTimeoutPromise.hx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import kernel.Timer;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
class SingleTimeoutPromise<T> {
|
||||||
|
private var inProgress:Bool = false;
|
||||||
|
private var interalPromise:Promise<T> = null;
|
||||||
|
private var interalResolve:T->Void = null;
|
||||||
|
private var interalReject:(Error->Void) = null;
|
||||||
|
private var timer:Timer = null;
|
||||||
|
|
||||||
|
private final activate:Void->Void;
|
||||||
|
private final timeout:Int;
|
||||||
|
|
||||||
|
public function new(timeout:Int, activate:Void->Void) {
|
||||||
|
this.activate = activate;
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function request():Promise<T> {
|
||||||
|
if (this.inProgress) {
|
||||||
|
return this.interalPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inProgress = true;
|
||||||
|
|
||||||
|
this.interalPromise = new Promise((resolve, reject) -> {
|
||||||
|
this.interalResolve = resolve;
|
||||||
|
this.interalReject = reject;
|
||||||
|
|
||||||
|
this.activate();
|
||||||
|
|
||||||
|
this.timer = new Timer(this.timeout, () -> {
|
||||||
|
this.reject(new Error("Timeout"));
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.interalPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRunning():Bool {
|
||||||
|
return this.inProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolve(val:T) {
|
||||||
|
if (this.inProgress) {
|
||||||
|
this.inProgress = false;
|
||||||
|
this.timer.cancle();
|
||||||
|
this.interalResolve(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reject(err:Error) {
|
||||||
|
if (this.inProgress) {
|
||||||
|
this.inProgress = false;
|
||||||
|
this.timer.cancle();
|
||||||
|
this.interalReject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/lib/Tags.hx
Normal file
49
src/lib/Tags.hx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import lib.PaN;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
using lua.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Represents a list a minecraft tags.
|
||||||
|
|
||||||
|
Needed because tags are SOMETIMES retuned not as arrays.
|
||||||
|
**/
|
||||||
|
@:forward
|
||||||
|
enum abstract Tags(Array<PaN>) from Array<PaN> to Array<PaN> {
|
||||||
|
inline public function new(arr:Array<String>) {
|
||||||
|
this = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
From values that are object with the tag as the filed and the value set to true.
|
||||||
|
**/
|
||||||
|
@:from
|
||||||
|
public static function fromBoolTable(from:Table<String, Bool>) {
|
||||||
|
var rtn = [];
|
||||||
|
for (k => _ in Table.toMap(from)) {
|
||||||
|
rtn.push(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tags(rtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
From values that are lua arrays.
|
||||||
|
**/
|
||||||
|
@:from
|
||||||
|
public static function fromIntTable(from:Table<Int, String>) {
|
||||||
|
return new Tags(from.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sortByName():Tags {
|
||||||
|
var copy = this.copy();
|
||||||
|
|
||||||
|
copy.sort((a:String, b:String) -> {
|
||||||
|
return if (a < b) -1 else 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package lib;
|
package lib;
|
||||||
|
|
||||||
@:structInit class Vec2<T> {
|
@:structInit class Vec2<T:Float> {
|
||||||
public var x:T;
|
public var x:T;
|
||||||
public var y:T;
|
public var y:T;
|
||||||
|
|
||||||
@@ -8,16 +8,96 @@ package lib;
|
|||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function add(rhs:Vec2<T>):Vec2<T> {
|
||||||
|
return {
|
||||||
|
y: this.y + rhs.y,
|
||||||
|
x: this.x + rhs.x,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sub(rhs:Vec2<T>):Vec2<T> {
|
||||||
|
return {
|
||||||
|
y: this.y - rhs.y,
|
||||||
|
x: this.x - rhs.x,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function multiply(rhs:Vec2<T>):Vec2<T> {
|
||||||
|
return {
|
||||||
|
y: this.y * rhs.y,
|
||||||
|
x: this.x * rhs.x,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function negate():Vec2<T> {
|
||||||
|
return {
|
||||||
|
y: -this.y,
|
||||||
|
x: -this.x,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@:structInit class Vec3<T> {
|
@:structInit class Vec3<T:Float> {
|
||||||
public var x:T;
|
public final x:T;
|
||||||
public var y:T;
|
public final y:T;
|
||||||
public var z:T;
|
public final z:T;
|
||||||
|
|
||||||
public function new(x:T, y:T, z:T) {
|
public function new(x:T, y:T, z:T) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function add(rhs:Vec3<T>):Vec3<T> {
|
||||||
|
return {
|
||||||
|
x: this.x + rhs.x,
|
||||||
|
y: this.y + rhs.y,
|
||||||
|
z: this.z + rhs.z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sub(rhs:Vec3<T>):Vec3<T> {
|
||||||
|
return {
|
||||||
|
x: this.x - rhs.x,
|
||||||
|
y: this.y - rhs.y,
|
||||||
|
z: this.z - rhs.z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function multiplyScalar(rhs:T):Vec3<T> {
|
||||||
|
return {
|
||||||
|
x: this.x * rhs,
|
||||||
|
y: this.y * rhs,
|
||||||
|
z: this.z * rhs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function negate():Vec3<T> {
|
||||||
|
return {
|
||||||
|
x: -this.x,
|
||||||
|
y: -this.y,
|
||||||
|
z: -this.z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dot(rhs:Vec3<T>):Float {
|
||||||
|
return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cross(rhs:Vec3<T>):Vec3<T> {
|
||||||
|
return {
|
||||||
|
x: this.y * rhs.z - this.z * rhs.y,
|
||||||
|
y: this.z * rhs.x - this.x * rhs.z,
|
||||||
|
z: this.x * rhs.y - this.y * rhs.x
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function length():Float {
|
||||||
|
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function distance(rhs:Vec3<T>):Float {
|
||||||
|
return Math.sqrt(Math.pow(this.x - rhs.x, 2) + Math.pow(this.y - rhs.y, 2) + Math.pow(this.z - rhs.z, 2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user