Compare commits
16 Commits
28ec48cc85
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
c665401fd8
|
|||
|
2799a0be3d
|
|||
|
e527dd5b6a
|
|||
|
fe17b4fd67
|
|||
|
90b4015ba1
|
|||
|
2dd85c2b26
|
|||
|
1d60e13792
|
|||
|
9d6e8a366b
|
|||
|
5167533c6d
|
|||
|
aac527ae89
|
|||
|
af6a4c840b
|
|||
|
afbd1dfd68
|
|||
|
b305594ea4
|
|||
|
df7991763d
|
|||
|
e0f8d274e7
|
|||
|
08f41ccb0b
|
@@ -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;
|
||||||
@@ -15,7 +15,7 @@ class GPS extends CLIAppBase {
|
|||||||
var y:Float = args.getFloat("y");
|
var y:Float = args.getFloat("y");
|
||||||
var z:Float = args.getFloat("z");
|
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);
|
||||||
|
|
||||||
@@ -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 {
|
||||||
|
case Success(pos):
|
||||||
handle.writeLine('Position x:${pos.x} y:${pos.y} z:${pos.z}');
|
handle.writeLine('Position x:${pos.x} y:${pos.y} z:${pos.z}');
|
||||||
} else {
|
case Failure(err):
|
||||||
handle.writeLine("Position not available");
|
handle.writeLine("Position not available: " + err);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import kernel.turtle.Types.ToolSide;
|
||||||
import lib.turtle.Helper;
|
import lib.turtle.Helper;
|
||||||
import kernel.turtle.TurtleMutex;
|
import kernel.turtle.TurtleMutex;
|
||||||
import kernel.turtle.Turtle;
|
import kernel.turtle.Turtle;
|
||||||
@@ -116,6 +117,28 @@ class TurtleCtl extends CLIAppBase {
|
|||||||
var len = args.getInt("length");
|
var len = args.getInt("length");
|
||||||
return asynPerform(Helper.combine.bind([Turtle.digEmpty.bind(Front), Turtle.forward, Turtle.digEmpty.bind(Up)]), len);
|
return asynPerform(Helper.combine.bind([Turtle.digEmpty.bind(Front), Turtle.forward, Turtle.digEmpty.bind(Up)]), len);
|
||||||
}, [Int("length")]);
|
}, [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> {
|
private function asynPerform(op:Void->Outcome<Noise, String>, times:Int):Future<Bool> {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package bin.pathfinder;
|
package bin.pathfinder;
|
||||||
|
|
||||||
import lib.Pos3;
|
import lib.WorldPos;
|
||||||
import lib.ui.elements.IUIElement;
|
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;
|
||||||
@@ -36,7 +36,7 @@ class PFClient implements IProcess {
|
|||||||
|
|
||||||
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<IUIElement> = [
|
var childre:Array<IUIElement> = [
|
||||||
new TextElement('Acc: ${acc}'),
|
new TextElement('Acc: ${acc}'),
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package kernel;
|
package kernel;
|
||||||
|
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import kernel.ui.ITermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
import cc.Term;
|
import cc.Term;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
@@ -39,7 +39,7 @@ class MainTerm implements ITermWriteable {
|
|||||||
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 ITermWriteable {
|
|||||||
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,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,47 +80,42 @@ 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");
|
|
||||||
reject(new Error("Not enough fuel to align"));
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPS.locate().handle((pos1) -> {
|
public static function startAlign():Void {
|
||||||
Log.debug('pos1: $pos1');
|
if (Turtle.getFuelLevel() < 2) {
|
||||||
if (pos1 == null) {
|
alignPromise.reject(new Error("Not enough fuel to align"));
|
||||||
Log.warn("GPS not available for 1st position");
|
|
||||||
reject(new Error("GPS not available"));
|
|
||||||
return;
|
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();
|
var moved = tryMoving();
|
||||||
|
|
||||||
if (moved == -1) {
|
if (moved == -1) {
|
||||||
Log.warn("Can't move");
|
alignPromise.reject(new Error("Can't move"));
|
||||||
reject(new Error("Can't move"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPS.locate().handle((pos2) -> {
|
GPS.locate().handle((result2) -> {
|
||||||
Log.debug('pos2: $pos2');
|
switch result2 {
|
||||||
if (pos2 == null) {
|
case Failure(err):
|
||||||
Log.warn("GPS not available for 2nd position");
|
alignPromise.reject(new Error("GPS not available for 2nd position: " + err));
|
||||||
reject(new Error("GPS not available for 2nd position"));
|
|
||||||
return;
|
return;
|
||||||
}
|
case Success(pos2):
|
||||||
|
|
||||||
var cHeading = calcHeading(pos1, pos2, moved);
|
var cHeading = calcHeading(pos1, pos2, moved);
|
||||||
if (cHeading == null) {
|
if (cHeading == null) {
|
||||||
Log.error("Can't calculate heading");
|
alignPromise.reject(new Error("Can't calculate heading"));
|
||||||
reject(new Error("Can't calculate heading"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,10 +123,10 @@ class INS {
|
|||||||
moveBack(moved);
|
moveBack(moved);
|
||||||
GPS.setINSPosition(pos1);
|
GPS.setINSPosition(pos1);
|
||||||
|
|
||||||
resolve(Noise);
|
alignPromise.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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,30 +74,17 @@ 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;
|
|
||||||
case RouteDiscoverUpdate(routes):
|
|
||||||
for (route in routes) {
|
|
||||||
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
|
||||||
}
|
|
||||||
false;
|
|
||||||
default:
|
|
||||||
Log.error("Expected package to be a Route discover package");
|
|
||||||
false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!shouldRespond) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Respond to peer
|
// Respond to peer
|
||||||
var response:Package<Noise> = {
|
var response:Package<Noise> = {
|
||||||
@@ -110,6 +97,14 @@ class Routing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interf.send(response.toID, Net.networkID, response);
|
interf.send(response.toID, Net.networkID, response);
|
||||||
|
case RouteDiscoverUpdate(routes):
|
||||||
|
// Received an update of routes
|
||||||
|
for (route in routes) {
|
||||||
|
addPossibleRoute(route.id, interf, route.cost, pack.fromID);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Log.silly("Expected package to be a Route discover package");
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
|
import kernel.log.Log;
|
||||||
|
import lib.Debug;
|
||||||
|
import cc.Peripheral;
|
||||||
|
import lib.Tags;
|
||||||
import lib.Item;
|
import lib.Item;
|
||||||
import cc.periphs.ItemStorage.ReducedItemInfo;
|
import cc.periphs.ItemStorage.ReducedItemInfo;
|
||||||
import lua.Table;
|
import lua.Table;
|
||||||
@@ -22,7 +26,7 @@ class ItemInfo {
|
|||||||
class DetailedItemInfo extends ItemInfo {
|
class DetailedItemInfo extends ItemInfo {
|
||||||
public final displayName:String;
|
public final displayName:String;
|
||||||
public final maxCount:Int;
|
public final maxCount:Int;
|
||||||
public final tags:Array<String>;
|
public final tags:Tags;
|
||||||
public final durability:Null<Float>;
|
public final durability:Null<Float>;
|
||||||
public final damage:Null<Int>;
|
public final damage:Null<Int>;
|
||||||
public final maxDamage:Null<Int>;
|
public final maxDamage:Null<Int>;
|
||||||
@@ -32,10 +36,7 @@ class DetailedItemInfo extends ItemInfo {
|
|||||||
private function new(from:cc.periphs.ItemStorage.DetailedItemInfo) {
|
private function new(from:cc.periphs.ItemStorage.DetailedItemInfo) {
|
||||||
super(from);
|
super(from);
|
||||||
|
|
||||||
this.tags = [];
|
this.tags = Tags.fromBoolTable(from.tags);
|
||||||
for (k => _ in Table.toMap(from.tags)) {
|
|
||||||
this.tags.push(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.displayName = from.displayName;
|
this.displayName = from.displayName;
|
||||||
this.maxCount = from.maxCount;
|
this.maxCount = from.maxCount;
|
||||||
@@ -55,11 +56,9 @@ class Inventory implements IPeripheral {
|
|||||||
public static inline final TYPE_NAME:String = "inventory";
|
public static inline final TYPE_NAME:String = "inventory";
|
||||||
|
|
||||||
private final addr:String;
|
private final addr:String;
|
||||||
private final native:cc.periphs.ItemStorage;
|
|
||||||
|
|
||||||
public function new(addr:String) {
|
public function new(addr:String) {
|
||||||
this.addr = addr;
|
this.addr = addr;
|
||||||
this.native = cc.Peripheral.wrap(addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAddr():String {
|
public function getAddr():String {
|
||||||
@@ -74,18 +73,18 @@ class Inventory implements IPeripheral {
|
|||||||
Get the size of this inventory.
|
Get the size of this inventory.
|
||||||
**/
|
**/
|
||||||
public function size():Int {
|
public function size():Int {
|
||||||
return this.native.size();
|
return Peripheral.call(this.addr, "size");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
List all items in this inventory.
|
List all items in this inventory.
|
||||||
**/
|
**/
|
||||||
public function list():Map<Int, ItemInfo> {
|
public function list():Map<Int, ItemInfo> {
|
||||||
var list = Table.toArray(this.native.list());
|
var list:Map<Int, ReducedItemInfo> = Table.toMap(Peripheral.call(this.addr, "list"));
|
||||||
var rtn:Map<Int, ItemInfo> = new Map();
|
var rtn:Map<Int, ItemInfo> = new Map();
|
||||||
|
|
||||||
for (k => v in list) {
|
for (k => v in list) {
|
||||||
rtn.set(k, new ItemInfo(v));
|
rtn.set(k - 1, new ItemInfo(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtn;
|
return rtn;
|
||||||
@@ -95,7 +94,7 @@ class Inventory implements IPeripheral {
|
|||||||
Get detailed information about an item.
|
Get detailed information about an item.
|
||||||
**/
|
**/
|
||||||
public function getItemDetail(slot:Int):DetailedItemInfo {
|
public function getItemDetail(slot:Int):DetailedItemInfo {
|
||||||
return new DetailedItemInfo(this.native.getItemDetail(slot));
|
return new DetailedItemInfo(Peripheral.call(this.addr, "getItemDetail", slot + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,20 +104,20 @@ class Inventory implements IPeripheral {
|
|||||||
Keep in mind that this does not depend on that item stored in this slot.
|
Keep in mind that this does not depend on that item stored in this slot.
|
||||||
**/
|
**/
|
||||||
public function getItemLimit(slot:Int):Int {
|
public function getItemLimit(slot:Int):Int {
|
||||||
return this.native.getItemLimit(slot);
|
return Peripheral.call(this.addr, "getItemLimit", slot + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Push items from one inventory to another connected one.
|
Push items from one inventory to another connected one. Needs to be on the same wired network.
|
||||||
**/
|
**/
|
||||||
public function pushItems(toSlot:Int, to:String, ?limit:Int, ?toSlot:Int):Int {
|
public function pushItems(to:String, fromSlot:Int, ?limit:Int, ?toSlot:Int):Int {
|
||||||
return this.native.pushItems(to, toSlot, limit, toSlot);
|
return Peripheral.call(this.addr, "pushItems", to, fromSlot + 1, limit, toSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Pull items from a connected inventory into this one.
|
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 {
|
public function pullItems(from:String, fromSlot:Int, ?limit:Int, ?toSlot:Int):Int {
|
||||||
return this.native.pullItems(from, fromSlot, limit, toSlot);
|
return Peripheral.call(this.addr, "pullItems", from, fromSlot + 1, limit, toSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package kernel.peripherals;
|
package kernel.peripherals;
|
||||||
|
|
||||||
import kernel.log.Log;
|
|
||||||
import kernel.peripherals.Modem;
|
import kernel.peripherals.Modem;
|
||||||
import kernel.peripherals.Screen;
|
import kernel.peripherals.Screen;
|
||||||
|
|
||||||
@@ -83,6 +82,8 @@ class Peripheral {
|
|||||||
return getRedstone(addr);
|
return getRedstone(addr);
|
||||||
case Inventory.TYPE_NAME:
|
case Inventory.TYPE_NAME:
|
||||||
return getInventory(addr);
|
return getInventory(addr);
|
||||||
|
case GeoScanner.TYPE_NAME:
|
||||||
|
return getGeoScanner(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -180,4 +181,15 @@ class Peripheral {
|
|||||||
public static function getAllInventorys():Array<Inventory> {
|
public static function getAllInventorys():Array<Inventory> {
|
||||||
return [for (addr in findAddrByType(Inventory.TYPE_NAME)) new Inventory(addr)];
|
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,7 @@
|
|||||||
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.ITermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
import lib.Vec.Vec2;
|
import lib.Vec.Vec2;
|
||||||
@@ -59,7 +59,7 @@ class Screen implements ITermWriteable 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,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
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.ITermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
@@ -86,7 +86,7 @@ class BufferedVirtualTermWriter implements IVirtualTermWriter 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;
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ interface ITermWriteable {
|
|||||||
/**
|
/**
|
||||||
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.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -110,8 +110,8 @@ class StatelessVirtualTermWriter implements IVirtualTermWriter {
|
|||||||
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,6 +1,6 @@
|
|||||||
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.ITermWriteable;
|
import kernel.ui.ITermWriteable;
|
||||||
@@ -18,7 +18,7 @@ class TermBuffer implements ITermWriteable {
|
|||||||
**/
|
**/
|
||||||
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;
|
||||||
@@ -91,7 +91,7 @@ class TermBuffer implements ITermWriteable {
|
|||||||
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 ITermWriteable {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCursorPos():Pos {
|
public function getCursorPos():ScreenPos {
|
||||||
return cursorPos;
|
return cursorPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package kernel.ui;
|
package kernel.ui;
|
||||||
|
|
||||||
import lib.ui.rendere.IUIEventDelegate;
|
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;
|
||||||
@@ -17,21 +17,21 @@ class WindowContext implements ITermWriteable {
|
|||||||
|
|
||||||
@:allow(kernel.ui.WindowManager) private var eventDelegate:Null<IUIEventDelegate>;
|
@: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>;
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ class WindowContext implements ITermWriteable {
|
|||||||
writer.scroll(y);
|
writer.scroll(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function getCursorPos():Pos {
|
public inline function getCursorPos():ScreenPos {
|
||||||
return writer.getCursorPos();
|
return writer.getCursorPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,8 @@ package lib;
|
|||||||
/**
|
/**
|
||||||
Represents an item in the game.
|
Represents an item in the game.
|
||||||
**/
|
**/
|
||||||
enum 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,10 +17,6 @@ enum abstract Item(String) to String {
|
|||||||
return new Item(s);
|
return new Item(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBase():String {
|
|
||||||
return this.split(":")[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
var Coal = "minecraft:coal";
|
var Coal = "minecraft:coal";
|
||||||
var Charcoal = "minecraft:charcoal";
|
var Charcoal = "minecraft:charcoal";
|
||||||
}
|
}
|
||||||
|
|||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
86
src/lib/WorldPos.hx
Normal file
86
src/lib/WorldPos.hx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import lib.Vec.Vec2;
|
||||||
|
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
|
||||||
|
abstract WorldPos(Vec3<Float>) from Vec3<Float> to Vec3<Float> {
|
||||||
|
public inline function new(v:Vec3<Float>) {
|
||||||
|
this = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A + B)
|
||||||
|
public inline function add(rhs:WorldPos):WorldPos {
|
||||||
|
return this.add(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A - B)
|
||||||
|
public inline function sub(rhs:Vec3<Float>):WorldPos {
|
||||||
|
return this.sub(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A * B)
|
||||||
|
public inline function multiplyScalar(rhs:Float):WorldPos {
|
||||||
|
return this.multiplyScalar(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A / B)
|
||||||
|
public function divideScalar(rhs:Float):WorldPos {
|
||||||
|
return {
|
||||||
|
y: this.y / rhs,
|
||||||
|
x: this.x / rhs,
|
||||||
|
z: this.z / rhs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(-A)
|
||||||
|
public function negate():WorldPos {
|
||||||
|
return this.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function normalize():WorldPos {
|
||||||
|
var l = this.length();
|
||||||
|
return multiplyScalar(1 / l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A == B)
|
||||||
|
public function equals(rhs:WorldPos):Bool {
|
||||||
|
return close(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:op(A != B)
|
||||||
|
public function notEquals(rhs:WorldPos):Bool {
|
||||||
|
return !close(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close(rhs:WorldPos, 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 'WorldPos(${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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function round():WorldPos {
|
||||||
|
return new WorldPos({
|
||||||
|
x: Math.fround(this.x),
|
||||||
|
y: Math.fround(this.y),
|
||||||
|
z: Math.fround(this.z)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package lib.ui;
|
package lib.ui;
|
||||||
|
|
||||||
import kernel.ui.WindowContext;
|
import kernel.ui.WindowContext;
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import lib.Rect;
|
import lib.Rect;
|
||||||
import kernel.ui.Pixel;
|
import kernel.ui.Pixel;
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> from Array<Array<Pix
|
|||||||
this = [[]];
|
this = [[]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function set(i:Pos, pixel:Pixel) {
|
public inline function set(i:ScreenPos, pixel:Pixel) {
|
||||||
if (this[i.y] == null) {
|
if (this[i.y] == null) {
|
||||||
this[i.y] = [];
|
this[i.y] = [];
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> from Array<Array<Pix
|
|||||||
this[i.y][i.x] = pixel;
|
this[i.y][i.x] = pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function get(i:Pos):Null<Pixel> {
|
public inline function get(i:ScreenPos):Null<Pixel> {
|
||||||
if (this[i.y] == null) {
|
if (this[i.y] == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -26,11 +26,11 @@ abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> from Array<Array<Pix
|
|||||||
return this[i.y][i.x];
|
return this[i.y][i.x];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function keyValueIterator():KeyValueIterator<Pos, Pixel> {
|
public function keyValueIterator():KeyValueIterator<ScreenPos, Pixel> {
|
||||||
return new CanvasKeyValueIterator(this);
|
return new CanvasKeyValueIterator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function combine(other:Canvas, offset:Pos) {
|
public function combine(other:Canvas, offset:ScreenPos) {
|
||||||
for (key => value in other) {
|
for (key => value in other) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -127,8 +127,8 @@ abstract Canvas(Array<Array<Pixel>>) to Array<Array<Pixel>> from Array<Array<Pix
|
|||||||
|
|
||||||
class CanvasKeyValueIterator {
|
class CanvasKeyValueIterator {
|
||||||
private final canvas:Array<Array<Pixel>>;
|
private final canvas:Array<Array<Pixel>>;
|
||||||
private var index:Null<Pos> = {x: 0, y: 0};
|
private var index:Null<ScreenPos> = {x: 0, y: 0};
|
||||||
private var nextIndex:Null<Pos> = null;
|
private var nextIndex:Null<ScreenPos> = null;
|
||||||
|
|
||||||
@:allow(lib.ui.Canvas)
|
@:allow(lib.ui.Canvas)
|
||||||
private function new(canvas:Array<Array<Pixel>>) {
|
private function new(canvas:Array<Array<Pixel>>) {
|
||||||
@@ -141,7 +141,7 @@ class CanvasKeyValueIterator {
|
|||||||
this.nextIndex = nextValidPixel();
|
this.nextIndex = nextValidPixel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isValidPos(pos:Pos):Bool {
|
private function isValidPos(pos:ScreenPos):Bool {
|
||||||
if (this.canvas[pos.y] == null) {
|
if (this.canvas[pos.y] == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ class CanvasKeyValueIterator {
|
|||||||
return this.index != null;
|
return this.index != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function nextValidPixel():Null<Pos> {
|
private function nextValidPixel():Null<ScreenPos> {
|
||||||
if (this.index == null) {
|
if (this.index == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ class CanvasKeyValueIterator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function next():{key:Pos, value:Pixel} {
|
public function next():{key:ScreenPos, value:Pixel} {
|
||||||
var rtn = {
|
var rtn = {
|
||||||
key: this.index,
|
key: this.index,
|
||||||
value: this.canvas[this.index.y][this.index.x]
|
value: this.canvas[this.index.y][this.index.x]
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package lib.ui;
|
package lib.ui;
|
||||||
|
|
||||||
import lib.Pos;
|
import lib.ScreenPos;
|
||||||
import kernel.ButtonType;
|
import kernel.ButtonType;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
typedef UIEvents = {
|
typedef UIEvents = {
|
||||||
public var ?onClick:Callback<{button:ButtonType, pos:Pos}>;
|
public var ?onClick:Callback<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public var ?onKey:Callback<{keyCode:Int, isHeld:Bool}>;
|
public var ?onKey:Callback<{keyCode:Int, isHeld:Bool}>;
|
||||||
public var ?onKeyUp:Callback<Int>;
|
public var ?onKeyUp:Callback<Int>;
|
||||||
public var ?onMouseDrag:Callback<{button:ButtonType, pos:Pos}>;
|
public var ?onMouseDrag:Callback<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public var ?onMouseScroll:Callback<{dir:Int, pos:Pos}>;
|
public var ?onMouseScroll:Callback<{dir:Int, pos:ScreenPos}>;
|
||||||
public var ?onMouseUp:Callback<{button:ButtonType, pos:Pos}>;
|
public var ?onMouseUp:Callback<{button:ButtonType, pos:ScreenPos}>;
|
||||||
public var ?onPaste:Callback<String>;
|
public var ?onPaste:Callback<String>;
|
||||||
public var ?onChar:Callback<String>;
|
public var ?onChar:Callback<String>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ abstract EventMap(Array<{bound:Rect, delegate:IUIEventDelegate}>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findResponseableDelegate(pos:Pos):IUIEventDelegate {
|
public function findResponseableDelegate(pos:ScreenPos):IUIEventDelegate {
|
||||||
for (i in 0...this.length) {
|
for (i in 0...this.length) {
|
||||||
var newi = (this.length - 1) - i;
|
var newi = (this.length - 1) - i;
|
||||||
var element = this[newi];
|
var element = this[newi];
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ package lib.ui.elements;
|
|||||||
import lib.ui.rendere.IUIEventDelegate;
|
import lib.ui.rendere.IUIEventDelegate;
|
||||||
|
|
||||||
interface IUIElement extends IUIEventDelegate {
|
interface IUIElement extends IUIEventDelegate {
|
||||||
public function render(bounds:Pos):Canvas;
|
public function render(bounds:ScreenPos):Canvas;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ class RootElement implements IUIElement {
|
|||||||
this.children = children;
|
this.children = children;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bounds:Pos):Canvas {
|
public function render(bounds:ScreenPos):Canvas {
|
||||||
var canvas = new Canvas();
|
var canvas = new Canvas();
|
||||||
var offset = new Pos({x: 0, y: 0});
|
var offset = new ScreenPos({x: 0, y: 0});
|
||||||
|
|
||||||
if (hasTitle()) {
|
if (hasTitle()) {
|
||||||
var title = new TextElement(this.title);
|
var title = new TextElement(this.title);
|
||||||
var halfWidth = Math.floor(bounds.x / 2) - Math.floor(this.title.length / 2);
|
var halfWidth = Math.floor(bounds.x / 2) - Math.floor(this.title.length / 2);
|
||||||
canvas.combine(title.render(bounds), {x: halfWidth, y: offset.y});
|
canvas.combine(title.render(bounds), {x: halfWidth, y: offset.y});
|
||||||
offset = new Pos({x: 0, y: 1});
|
offset = new ScreenPos({x: 0, y: 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.eventManager.clearMap();
|
this.eventManager.clearMap();
|
||||||
@@ -42,7 +42,7 @@ class RootElement implements IUIElement {
|
|||||||
this.eventManager.addMapElement(child, bounds);
|
this.eventManager.addMapElement(child, bounds);
|
||||||
canvas.combine(childCanvas, offset);
|
canvas.combine(childCanvas, offset);
|
||||||
|
|
||||||
offset = new Pos({x: 0, y: offset.y + bounds.getHight() + 1});
|
offset = new ScreenPos({x: 0, y: offset.y + bounds.getHight() + 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class TextElement implements IUIElement {
|
|||||||
return uiEvents;
|
return uiEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(bounds:Pos):Canvas {
|
public function render(bounds:ScreenPos):Canvas {
|
||||||
var canvas = new Canvas();
|
var canvas = new Canvas();
|
||||||
|
|
||||||
var x = 0;
|
var x = 0;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class UIEventManager implements IUIEventDelegate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handleClickEvent(params:{button:ButtonType, pos:Pos}) {
|
private function handleClickEvent(params:{button:ButtonType, pos:ScreenPos}) {
|
||||||
var element = this.map.findResponseableDelegate(params.pos);
|
var element = this.map.findResponseableDelegate(params.pos);
|
||||||
if (element == null) {
|
if (element == null) {
|
||||||
return;
|
return;
|
||||||
@@ -48,11 +48,11 @@ class UIEventManager implements IUIEventDelegate {
|
|||||||
|
|
||||||
private function handlePasteEvent(text:String) {}
|
private function handlePasteEvent(text:String) {}
|
||||||
|
|
||||||
private function handleMouseUpEvent(params:{button:ButtonType, pos:Pos}) {}
|
private function handleMouseUpEvent(params:{button:ButtonType, pos:ScreenPos}) {}
|
||||||
|
|
||||||
private function handleMouseScrollEvent(params:{dir:Int, pos:Pos}) {}
|
private function handleMouseScrollEvent(params:{dir:Int, pos:ScreenPos}) {}
|
||||||
|
|
||||||
private function handleMouseDragEvent(params:{button:ButtonType, pos:Pos}) {}
|
private function handleMouseDragEvent(params:{button:ButtonType, pos:ScreenPos}) {}
|
||||||
|
|
||||||
private function handleKeyEvent(params:{keyCode:Int, isHeld:Bool}) {}
|
private function handleKeyEvent(params:{keyCode:Int, isHeld:Bool}) {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user