Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
37aceba
peak incoming
ItsLJcool Oct 27, 2025
b0f321e
FUCKING HELL I GIVE UP FUCK IT USE hxWebSocket BRUHH
ItsLJcool Oct 27, 2025
86cd114
it just works :trollface:
ItsLJcool Oct 27, 2025
26c7930
Merge branch 'CodenameCrew:main' into internet-utils-better
ItsLJcool Oct 27, 2025
0d4ea8b
Implementing a way to addon to the Handshake Header
ItsLJcool Nov 6, 2025
c61d69c
Merge branch 'CodenameCrew:main' into internet-utils-better
ItsLJcool Nov 6, 2025
d0c94d6
so guys, i am the smart, trust :trollface:
ItsLJcool Nov 6, 2025
59a0901
Properly converts the message from the server into either String, Byt…
ItsLJcool Nov 8, 2025
8b3cd65
Documentation on `FunkinWebSocket` and added `Metrics` to it :)
ItsLJcool Nov 8, 2025
01431fc
Merge branch 'CodenameCrew:main' into internet-utils-better
ItsLJcool Mar 30, 2026
04e514f
whoop
ItsLJcool Mar 30, 2026
3493235
Merge branch 'internet-utils-better' of https://github.com/ItsLJcool/…
ItsLJcool Mar 30, 2026
55cd6e2
Merge branch 'CodenameCrew:main' into internet-utils-better
ItsLJcool Apr 21, 2026
68364fb
Reformatted how `FunkinPacket` is managed, and fixed some issues in `…
ItsLJcool Apr 21, 2026
7ef7b00
Merge branch 'internet-utils-better' of https://github.com/ItsLJcool/…
ItsLJcool Apr 21, 2026
5f12461
Small fixes and small features I forgor to implement
ItsLJcool Apr 24, 2026
f984fa2
ocd bro I can't leave this chilling in changes bro im sorry
ItsLJcool May 2, 2026
5ef3d48
Merge branch 'CodenameCrew:main' into internet-utils-better
ItsLJcool May 16, 2026
45041b8
fix to ensure that `fromJson` and `appendJson` in `FunkinPacket` will…
ItsLJcool May 19, 2026
83576f1
Merge branches 'internet-utils-better' and 'internet-utils-better' of…
ItsLJcool May 19, 2026
ad9fd53
Fixed an issue where the client would crash if the server sent a raw …
ItsLJcool May 19, 2026
ccd7ba6
QOL implementation to actually use `FunkinPacket.status` inside `Funk…
ItsLJcool May 19, 2026
85bbe07
Merge branch 'CodenameCrew:main' into internet-utils-better
ItsLJcool Jul 6, 2026
2b776cc
implement `send_bytes` in source with Threading, so you can send larg…
ItsLJcool Jul 6, 2026
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
70 changes: 70 additions & 0 deletions source/funkin/backend/system/net/FunkinPacket.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
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>>):FunkinPacket { return (new FunkinPacket().appendJson(json)); }

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

} catch(e) {
this.set("message", json);
return this;
}
} else parsedJson = json;
for (key => value in parsedJson) this.set(key, value);
return this;
}

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