Skip to content

Commit

Permalink
even more stuffs
Browse files Browse the repository at this point in the history
  • Loading branch information
BNTFryingPan committed Aug 8, 2022
1 parent 32fb546 commit f7c1859
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 18 deletions.
40 changes: 33 additions & 7 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
# Cuttlefish
A Minecraft server written in Haxe.
A Minecraft: Java Edition server implementation written in Haxe.

## Currently Supported Features
- Server List Pinging
- can show any data, including text, online/max player count, protocol version, and sample of online players.
- thats literally it for now
- can show any data, including text (including chat components), online/max player count, protocol version, and sample of online players.
- the very start of getting a player to spawn
- the vanilla client will spawn after a few seconds, but technically it shouldnt
- when it does spawn, its just a void
- Chat Components
- there is a chat component builder class that is used to construct and serialize complex formatting in text.
- NBT
- can currently convert NBT tags to bytes, but reading them from bytes appears to be broken for now

## Features Being Worked On
- login success packet (to login to the server)
- protocol encryption
- some other background stuff
- properly spawning the player
- sending a flat world

## Planned Features
- authentication and protocol encryption (Piracy is not supported, but impossible to prevent until both of these are added)
- chat
- configuration files for server list ping info and other stuff
- bungeecord/velocity support?
- MiniMessage-like format for easily using advanced chat component features

## Compiling
Being written in Haxe, Cuttlefish can be compiled to many different targets. Cuttlefish only supports sys targets that have threading support. This means that the supported targets are currently C++, C#, Hashlink, Java (or JVM bytecode directly), Neko, and Python. NodeJS is not supported because `hxnodejs` does not support threads yet. To test without worrying about downloading anything extra, the following should work:
```git clone https://github.com/LeotomasMC/Cuttlefish.git
```
git clone https://github.com/LeotomasMC/Cuttlefish.git
cd Cuttlefish
haxelib install uuid
haxelib install hxp
haxelib run hxp --install-hxp-alias
hxp test neko
```
the last command `hxp test neko` will compile Cuttlefish for the Neko target, and then run the compiled output automatically.
<!-- neko is the "default" target here because a barebones haxe installion will include it, while other targets may require additional setup><-->
If you want to compile for specific targets, use `hxp build`, followed by a list of target flags. The flags for each target are as follows:
| Target Name | Supported Flags |
|---------------|-------------------|
| C++ | `-cpp` `-c++` `-cplusplus` |
| C# | `-csharp` `-cs` |
| Java | `-java` |
| Java Bytecode | `-jvm` |
| Hashlink | `-hl` `-hashlink` |
| Neko | `-neko` |
| Python | `-py` |

note that some targets may require additional setup. see the haxe target details documentation to setup other targets.
17 changes: 16 additions & 1 deletion src/Chat.hx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package;

import entity.Entity;

using StringTools;

/*enum abstract LegacyColor(Int) {
var Black = 0x000000; // &0
var DarkBlue = 0x0000aa; // &1
Expand Down Expand Up @@ -134,8 +136,15 @@ class ChatComponent {
if (this.isStrikethrough != null) json += '"strikethrough":$isStrikethrough,';
if (this.isObfuscated != null) json += '"obfuscated":$isObfuscated,';
if (this.usedColor != null) json += '"color":"${ChatComponent.serializeColor(this.usedColor)}",';
if (this.usedFont != null) json += '"font":"${this.usedFont.toString()}",';
if (this.extras != null) json += '"extra":[${[for (c in this.extras) c.serialize()].join(',')}],';
return json;
}

return json.substr(0, json.length - 2) + '}';
inline function comp(str:String):String {
if (str.startsWith('{"') && str.endsWith(','))
str = str.substr(0, str.length - 1) + '}';
return str;
}

public static function serializeColor(col:Color):String {
Expand Down Expand Up @@ -165,6 +174,12 @@ class ChatComponent {

class StringComponent extends ChatComponent {
public var text:String;

override public function serialize():String {
var s = super.serialize();
s += '"text":"$text",';
return comp(s);
}
}

class TranslationComponent extends ChatComponent {
Expand Down
11 changes: 10 additions & 1 deletion src/Connection.hx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package;

import Chat;
import Chat.ChatComponent;
import packet.clientbound.LoginDisconnectPacket;
import packet.clientbound.PlayLoginPacket;
import haxe.Exception;
import haxe.io.Bytes;
Expand Down Expand Up @@ -111,9 +114,12 @@ class Connection {
var packet = LoginStartPacket.read(this);
var namespace = Bytes.ofString('OfflinePlayer').toHex();
this._player = new Player(Uuid.v3(packet.name, namespace), packet.name);
//new LoginDisconnectPacket(ChatComponent.buildText('kicked').color(Color.Yellow).underline(true).extra(ChatComponent.buildText(' by ').underline(false).strike(true).color(Color.Hex('ff00ff'))).extra(ChatComponent.buildText('haxe!').color(Gold).italic(true)).extra(ChatComponent.buildText(' wow').obfuscate(true).underline(false).color(Hex('40d0e0')).extra(ChatComponent.buildText('trolled').color(LightGreen).obfuscate(false).font(new Identifier('minecraft', 'alt'))))).send(this);
new LoginSuccessPacket().send(this, Uuid.parse(player.uuid), player.name);
state = Play;
//new PlayLoginPacket().send(this);

new PlayLoginPacket().send(this);

packet;
case Play:
null;
Expand All @@ -129,6 +135,9 @@ class Connection {
default:
null;
}
case 0x0C:
trace('plugin msg');
null;
default:
// unknown packet type. we want to handle it though anyways just in case its useful?
ServerboundPacket.readUnknownPacket(input, packetLen, packetId);
Expand Down
4 changes: 4 additions & 0 deletions src/Identifier.hx
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ class Identifier {
namespace = str.substr(0, colonPos);
}
}

public function toString():String {
return '$namespace:$key';
}
}
6 changes: 3 additions & 3 deletions src/NBT.hx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ enum Tag {
class NBT {
public static function writeToStream(out:Output, tag:Tag, inList=false) {
function writeName() {
out.writeInt8(tag.getParameters()[0].length);
out.writeInt16(tag.getParameters()[0].length);
out.writeString(tag.getParameters()[0]);
}
switch tag {
Expand Down Expand Up @@ -65,7 +65,7 @@ class NBT {
case TAG_String(_, data):
if (!inList) out.writeByte(8);
if (!inList) writeName();
out.writeInt8(data.length);
out.writeInt16(data.length);
out.writeString(data);
case TAG_List(_, data, type):
if (!inList) out.writeByte(9);
Expand Down Expand Up @@ -95,7 +95,7 @@ class NBT {
var tagType = input.readByte();
var tagName = '';
if (!inList && tagType != 0) {
var nameLen = input.readInt8();
var nameLen = input.readInt16();
tagName = input.readString(nameLen);
}

Expand Down
25 changes: 24 additions & 1 deletion src/UnitTest.hx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package;

import sys.io.File;
import packet.clientbound.PlayLoginPacket;
import haxe.io.BytesOutput;
import haxe.io.BytesInput;
import NBT;

using StringTools;
using VarIntLong;
Expand All @@ -24,6 +27,8 @@ class UnitTest {
testVarInt(2147483647);
testVarInt(-1);
testVarInt(-2147483648);

testNBT();
}

static function testVarInt(number:Int) {
Expand All @@ -35,4 +40,22 @@ class UnitTest {

trace('${result} == ${number}: ${result == number} ${bytes.toHex()}');
}
}

static var tag = TAG_Compound('hello world', [TAG_String('name', 'bananrama')]);

static function testNBT() {
var output = new BytesOutput();
output.bigEndian = true;
//NBT.writeToStream(output, tag);
NBT.writeToStream(output, PlayLoginPacket.REGISTRY_TAG);
var bytes = output.getBytes();
trace('write: ${bytes.toHex()}');
File.write('./test.nbt', true).write(bytes);
var input = new BytesInput(bytes);
var result = NBT.readFromStream(input);
trace(result);
}
}

// 0a 00 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64 08 00 04 6e 61 6d 65 00 09 42 61 6e 61 6e 72 61 6d 61 00
// 0a 00 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64 08 00 04 6e 61 6d 65 00 09 62 61 6e 61 6e 72 61 6d 61 00
5 changes: 4 additions & 1 deletion src/packet/clientbound/LoginDisconnectPacket.hx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package packet.clientbound;

import Chat.ChatComponent;

using VarIntLong;

class LoginDisconnectPacket extends ClientboundPacket {
public var message:ChatComponent;

Expand All @@ -12,6 +14,7 @@ class LoginDisconnectPacket extends ClientboundPacket {

public function send(to:Connection) {
var out = beginSend(to);
out.writeString(message.serialize());
out.writeVarString(message.serialize());
finishSend();
}
}
2 changes: 1 addition & 1 deletion src/packet/clientbound/PlayLoginPacket.hx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class PlayLoginPacket extends ClientboundPacket {
TAG_Byte('has_ceiling', 0x00),
])])
], 10)]);
static var REGISTRY_TAG = TAG_Compound('', [REG_DIMS, REG_BIOMES]);
public static var REGISTRY_TAG = TAG_Compound('', [REG_DIMS, REG_BIOMES]);

public function send(client:Connection) {
var out = this.beginSend(client);
Expand Down
2 changes: 2 additions & 0 deletions src/packet/clientbound/PlayerPositionPacket.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package packet.clientbound;

5 changes: 5 additions & 0 deletions src/packet/clientbound/PluginMessageToClient.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package packet.clientbound;

class PluginMessageToClient extends ClientboundPacket {

}
5 changes: 2 additions & 3 deletions src/packet/clientbound/StatusResponsePacket.hx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package packet.clientbound;

import Chat.ChatComponent;
import haxe.io.BytesOutput;
import haxe.Json;

Expand All @@ -25,9 +26,7 @@ class StatusResponsePacket extends ClientboundPacket {
}
]
},
description: {
text: "hello from haxe",
},
description: Json.parse(ChatComponent.buildText('hello from haxe!').color(Hex('ff00ff')).serialize()),
previewsChat: false
}

Expand Down
Binary file added test.nbt
Binary file not shown.

0 comments on commit f7c1859

Please sign in to comment.