Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions building/libs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" ref="old" skipDeps="true" />
<lib name="funkin-modchart" skipDeps="true" />
<lib name="hxvlc" version="1.9.3" skipDeps="true" />
<lib name="hxWebSockets" />

<!-- Documentation and other features -->
<git name="away3d" url="https://github.com/CodenameCrew/away3d" />
Expand Down
2 changes: 2 additions & 0 deletions project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
<haxelib name="flixel" />
<haxelib name="flixel-addons" />

<haxelib name="hxWebSockets" />

<haxelib name="hxvlc" if="VIDEO_CUTSCENES" />
<haxelib name="away3d" if="THREE_D_SUPPORT" />
<haxelib name="format" />
Expand Down
65 changes: 65 additions & 0 deletions source/funkin/backend/system/net/FunkinPacket.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package funkin.backend.system.net;

import flixel.util.typeLimit.OneOfTwo;

import haxe.io.Bytes;
import haxe.io.BytesOutput;

class FunkinPacket implements haxe.Constraints.IMap<String, Dynamic> {
// Status of the packet. 200 is an OK response.
public var status:Int = -1;

// The JSON fields of the packet, as a Map.
private var fields:Map<String, Dynamic> = [];

// If the recieved data is binary or contains binary, this will contain the raw bytes.
public var bytes:Bytes = null;

public function new() { }

public static function fromJson(json:OneOfTwo<String, haxe.DynamicAccess<Dynamic>>):Null<FunkinPacket> {
var packet = new FunkinPacket();
packet.appendJson(json);
return packet;
}

public function appendJson(json:OneOfTwo<String, haxe.DynamicAccess<Dynamic>>):Void {
var parsedJson:haxe.DynamicAccess<Dynamic> = (json is String) ? haxe.Json.parse(json) : json;
if (parsedJson == null) return;

for (key => value in parsedJson) this.set(key, value);
}

public function toJson():haxe.DynamicAccess<Dynamic> {
var json:haxe.DynamicAccess<Dynamic> = {};
for (key => value in fields) json[key] = value;
return json;
}

inline public function stringify():String { return haxe.Json.stringify(toJson()); }

public function toBytes():Bytes {
var output = new BytesOutput();
output.writeString(haxe.Json.stringify(toJson()));
return output.getBytes();
}

inline public function get(key:String):Null<Dynamic> { return fields.get(key); }
inline public function set(key:String, value:Dynamic):Void { fields.set(key, value); }
inline public function exists(key:String):Bool { return fields.exists(key); }
inline public function remove(key:String):Bool { return fields.remove(key); }

inline public function keys():Iterator<String> { return fields.keys(); }
inline public function iterator():Iterator<Dynamic> { return fields.iterator(); }
inline public function keyValueIterator():KeyValueIterator<String, Dynamic> { return fields.keyValueIterator(); }

public function copy():FunkinPacket {
var copy = new FunkinPacket();
copy.fields = this.fields.copy();
copy.status = this.status;
return copy;
}

inline public function clear():Void { fields.clear(); }
inline public function toString():String { return 'FunkinPacket (Status: $status)'; }
}
129 changes: 129 additions & 0 deletions source/funkin/backend/system/net/FunkinSocket.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package funkin.backend.system.net;

#if sys
import sys.net.Host;
import sys.net.Socket as SysSocket;
import haxe.io.Bytes;

@:keep
class FunkinSocket implements IFlxDestroyable {
public var socket:SysSocket = new SysSocket();

public var metrics:Metrics = new Metrics();

public var FAST_SEND(default, set):Bool = true;
private function set_FAST_SEND(value:Bool):Bool {
FAST_SEND = value;
socket.setFastSend(value);
return value;
}
public var BLOCKING(default, set):Bool = false;
private function set_BLOCKING(value:Bool):Bool {
BLOCKING = value;
socket.setBlocking(value);
return value;
}

public var host:Host;
public var port:Int;

public function new(?_host:String = "127.0.0.1", ?_port:Int = 5000) {
FAST_SEND = true;
BLOCKING = false;
this.host = new Host(_host);
this.port = _port;
}

// Reading Area
public function readAll():Null<Bytes> {
try {
var bytes = this.socket.input.readAll();
if (bytes == null) return null;
metrics.updateBytesReceived(bytes.length);
return bytes;
} catch(e) { }
return null;
}
public function readLine():Null<String> {
try {
var bytes = this.socket.input.readLine();
if (bytes == null) return null;
metrics.updateBytesReceived(bytes.length);
return bytes;
} catch(e) { }
return null;
}
public function read(nBytes:Int):Null<Bytes> {
try {
var bytes = this.socket.input.read(nBytes);
if (bytes == null) return null;
metrics.updateBytesReceived(bytes.length);
return bytes;
} catch(e) { }
return null;
}
public function readBytes(bytes:Bytes):Int {
try {
var length = this.socket.input.readBytes(bytes, 0, bytes.length);
metrics.updateBytesReceived(length);
return length;
} catch(e) { }
return 0;
}

// Writing Area
public function prepare(nbytes:Int):Void { socket.output.prepare(nbytes); }
public function write(bytes:Bytes):Bool {
try {
this.socket.output.write(bytes);
metrics.updateBytesSent(bytes.length);
return true;
} catch (e) { }
return false;
}
public function writeString(str:String):Bool {
try {
this.socket.output.writeString(str);
metrics.updateBytesSent(Bytes.ofString(str).length);
return true;
} catch(e) { }
return false;
}

public function bind(?expectingConnections:Int = 1):FunkinSocket {
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Binding to ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
]);
socket.bind(host, port);
socket.listen(expectingConnections);
return this;
}

public function connect():FunkinSocket {
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Connecting to ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
]);
socket.connect(host, port);
return this;
}

public function close() {
try {
if (socket != null) socket.close();
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Closing socket from ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
]);
} catch(e) {
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Failed to close socket: ${e}', NONE),
]);
}
}

public function destroy() { close(); }
}
#end
Loading