Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Built-In Support for Command Blocks #891

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

nmaster
Copy link

@nmaster nmaster commented Sep 22, 2019

Adds built-in support for command blocks.

  • supports all three command block types
  • differentiates needs redstone vs. always active
  • differentiates conditional vs. unconditional
  • resolves @a and @p in commands
  • form window for command block configuration
  • command block entity including NBT representation
  • command execution yields output signal 0 < s < 15 instead of boolean
    • two commands modified to become signal-aware (say: input length, list: number of online users)
    • backport for other commands: false -> 0, true -> 15
  • propagates output signal to redstone comparator

Implementation introduces an extension of PluginManager, allowing to register built-in event listeners. This modification is a hack necessary to enable the registration of listeners not being part of a plug-in, but rather being built-in. A particular new listener was introduced to realize callbacks to PlayerFormRespondedEvent caused by command block configuration form updates.

Command Blocks including data and NBT are in general enabled for copy/paste/schematic operations in FAWE. However, a small patch for FAWE is necessary for this to work. This patch already exists, a pull request is on the way: boy0001/FastAsyncWorldedit#1332

import cn.nukkit.network.protocol.TextPacket;
import cn.nukkit.network.protocol.TransferPacket;
import cn.nukkit.network.protocol.UpdateAttributesPacket;
import cn.nukkit.network.protocol.UpdateBlockPacket;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you revert this? Maybe change your formatting settings.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I totally see the point... sorry, my IDE's auto-formatting screwed it up. Will see what I can do.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted old commit, pushed new one without formatting issues. Looking forward to your reviews... ;)

@PetteriM1
Copy link
Member

Could this with any chance be done without reformatting the files?

@Creeperface01
Copy link
Contributor

Why not to use vanilla UI?

@nmaster
Copy link
Author

nmaster commented Sep 28, 2019

I'll have to admit that there are still things to improve, and I'm committed to continue work on it. Command output, control for first tick and rate, etc. Any hints to how to do two-column layout in UI?

@nmaster
Copy link
Author

nmaster commented Sep 28, 2019

How do we proceed with this PR?

@Creeperface01
Copy link
Contributor

Try using proxypass you can easily find what packets are used for command blocks with BDS

@nmaster
Copy link
Author

nmaster commented Oct 2, 2019

Try using proxypass you can easily find what packets are used for command blocks with BDS

Had a look to ProxyPass lately. It's throwing a load of exceptions for me, if I proxy a connection between vanilla 1.12.1 server on Ubuntu 18.04 and Win 10 client to find out what I need - to extract packets regarding command blocks. Maybe I'll post an issue, maybe I'm doing something wrong on my side.

@nmaster nmaster closed this Oct 2, 2019
@nmaster nmaster reopened this Oct 2, 2019
@SupremeMortal
Copy link
Member

It's possible the encoding/decoding methods on the packet could be wrong as I only took a short amount of time reverse engineering the packet since it's not game critical. Could you post the exceptions thrown by ProxyPass here?

@nmaster
Copy link
Author

nmaster commented Oct 2, 2019

@SupremeMortal, sure, here we go.

My goal is to find packets related to any interaction with command blocks. However, I face these problems:

On the instant of interacting with a command block I find no visible occurrence of corresponding entries in the log. Actually, I see no information on decoded packets at all (...and this is where I think I'm doing something wrong, maybe configuration issue, maybe wrong log level?). From the logs I merely get messages like this....

2019-10-02 21:18:08.258 [Network Listener - #2] DEBUG com.nukkitx.protocol.bedrock.v361.BedrockUtils - Unknown metadata: 106 type BYTE value 1
2019-10-02 21:18:08.258 [Network Listener - #2] DEBUG com.nukkitx.protocol.bedrock.v361.BedrockUtils - Unknown metadata: 107 type FLOAT value 8.0
2019-10-02 21:18:08.258 [Network Listener - #2] DEBUG com.nukkitx.protocol.bedrock.v361.BedrockUtils - Unknown metadata: 108 type FLOAT value 16.0
2019-10-02 21:18:08.258 [Network Listener - #2] DEBUG com.nukkitx.protocol.bedrock.v361.BedrockUtils - Unknown metadata: 109 type STRING value ambient

...and exceptions like this...

2019-10-02 21:18:08.550 [Network Listener - #2] DEBUG com.nukkitx.protocol.bedrock.compressionhandler.DefaultBedrockCompressionHandler - Error occurred whilst decoding packet
com.nukkitx.protocol.bedrock.exception.PacketSerializeException: Error whilst deserializing LevelEventGenericPacket
        at com.nukkitx.protocol.bedrock.BedrockPacketCodec.tryDecode(BedrockPacketCodec.java:58) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.protocol.bedrock.compressionhandler.DefaultBedrockCompressionHandler.decompressPackets(DefaultBedrockCompressionHandler.java:75) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.protocol.bedrock.compressionhandler.DefaultBedrockCompressionHandler.decompressPackets(DefaultBedrockCompressionHandler.java:19) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.protocol.bedrock.BedrockSession.onWrappedPacket(BedrockSession.java:277) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.protocol.bedrock.BedrockRakNetSessionListener.onEncapsulated(BedrockRakNetSessionListener.java:32) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.network.raknet.RakNetSession.onEncapsulatedInternal(RakNetSession.java:315) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.network.raknet.RakNetSession.onOrderedReceived(RakNetSession.java:442) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.network.raknet.RakNetSession.checkForOrdered(RakNetSession.java:420) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.network.raknet.RakNetSession.onRakNetDatagram(RakNetSession.java:413) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.network.raknet.RakNetSession.onDatagram(RakNetSession.java:287) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.network.raknet.RakNetClient$ClientDatagramHandler.channelRead(RakNetClient.java:151) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.epoll.EpollDatagramChannel$EpollDatagramChannelUnsafe.epollInReady(EpollDatagramChannel.java:513) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:432) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:333) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:906) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [proxypass-1.0.0-SNAPSHOT.jar:?]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_201]
Caused by: java.lang.ClassCastException: com.nukkitx.nbt.tag.IntTag cannot be cast to com.nukkitx.nbt.tag.CompoundTag
        at com.nukkitx.protocol.bedrock.v361.serializer.LevelEventGenericSerializer_v361.deserialize(LevelEventGenericSerializer_v361.java:36) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.protocol.bedrock.v361.serializer.LevelEventGenericSerializer_v361.deserialize(LevelEventGenericSerializer_v361.java:18) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
        at com.nukkitx.protocol.bedrock.BedrockPacketCodec.tryDecode(BedrockPacketCodec.java:56) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
        ... 23 more

This one here pops up on startup, though I think it's rather a warning. The real errors pop up later.

[21:14:25 DEBUG]: Unable to load the library 'netty_transport_native_epoll_x86_64', trying other loading mechanism.
java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867) ~[?:1.8.0_201]
	at java.lang.Runtime.loadLibrary0(Runtime.java:870) ~[?:1.8.0_201]
	at java.lang.System.loadLibrary(System.java:1122) ~[?:1.8.0_201]
	at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
	at io.netty.util.internal.NativeLibraryLoader$1.run(NativeLibraryLoader.java:369) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
	at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_201]
	at io.netty.util.internal.NativeLibraryLoader.loadLibraryByHelper(NativeLibraryLoader.java:361) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:339) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.util.internal.NativeLibraryLoader.load(NativeLibraryLoader.java:136) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:198) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.channel.epoll.Native.<clinit>(Native.java:61) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:38) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.network.util.EventLoops.<clinit>(EventLoops.java:29) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.protocol.bedrock.BedrockServer.<init>(BedrockServer.java:29) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.protocol.bedrock.BedrockServer.<init>(BedrockServer.java:25) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.proxypass.ProxyPass.boot(ProxyPass.java:93) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.proxypass.ProxyPass.main(ProxyPass.java:68) [proxypass-1.0.0-SNAPSHOT.jar:?]
[21:14:25 DEBUG]: netty_transport_native_epoll_x86_64 cannot be loaded from java.library.path, now trying export to -Dio.netty.native.workdir: /tmp
java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867) ~[?:1.8.0_201]
	at java.lang.Runtime.loadLibrary0(Runtime.java:870) ~[?:1.8.0_201]
	at java.lang.System.loadLibrary(System.java:1122) ~[?:1.8.0_201]
	at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:349) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.util.internal.NativeLibraryLoader.load(NativeLibraryLoader.java:136) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:198) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.channel.epoll.Native.<clinit>(Native.java:61) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:38) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.network.util.EventLoops.<clinit>(EventLoops.java:29) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.protocol.bedrock.BedrockServer.<init>(BedrockServer.java:29) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.protocol.bedrock.BedrockServer.<init>(BedrockServer.java:25) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.proxypass.ProxyPass.boot(ProxyPass.java:93) [proxypass-1.0.0-SNAPSHOT.jar:?]
	at com.nukkitx.proxypass.ProxyPass.main(ProxyPass.java:68) [proxypass-1.0.0-SNAPSHOT.jar:?]
	Suppressed: java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
		at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867) ~[?:1.8.0_201]
		at java.lang.Runtime.loadLibrary0(Runtime.java:870) ~[?:1.8.0_201]
		at java.lang.System.loadLibrary(System.java:1122) ~[?:1.8.0_201]
		at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
		at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
		at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
		at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
		at io.netty.util.internal.NativeLibraryLoader$1.run(NativeLibraryLoader.java:369) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
		at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_201]
		at io.netty.util.internal.NativeLibraryLoader.loadLibraryByHelper(NativeLibraryLoader.java:361) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
		at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:339) ~[proxypass-1.0.0-SNAPSHOT.jar:?]
		at io.netty.util.internal.NativeLibraryLoader.load(NativeLibraryLoader.java:136) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:198) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at io.netty.channel.epoll.Native.<clinit>(Native.java:61) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:38) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at com.nukkitx.network.util.EventLoops.<clinit>(EventLoops.java:29) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at com.nukkitx.protocol.bedrock.BedrockServer.<init>(BedrockServer.java:29) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at com.nukkitx.protocol.bedrock.BedrockServer.<init>(BedrockServer.java:25) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at com.nukkitx.proxypass.ProxyPass.boot(ProxyPass.java:93) [proxypass-1.0.0-SNAPSHOT.jar:?]
		at com.nukkitx.proxypass.ProxyPass.main(ProxyPass.java:68) [proxypass-1.0.0-SNAPSHOT.jar:?]

@nmaster
Copy link
Author

nmaster commented Oct 3, 2019

(...and this is where I think I'm doing something wrong, maybe configuration issue, maybe wrong log level?).

Darn... just had a look into the generated session folder to find the desired packet.log...

@SupremeMortal
Copy link
Member

SupremeMortal commented Oct 3, 2019

I fixed the first exception you in the latest version of ProxyPass. The netty exception is normal because it's trying multiple mechanisms to load the native library.
It's possible to get the packets logged into the console by editing the log4j2.xml root log level to TRACE

@nmaster
Copy link
Author

nmaster commented Oct 3, 2019

Thanks a lot! Meanwhile I'm finding my way into the relevant protocol parts.

@nmaster
Copy link
Author

nmaster commented Oct 4, 2019

Ok, thanks to ProxyPass I managed to study packet sequences how to trigger opening Vanilla UI for command blocks on client side and handle command block update packets on server side. I'll wire this up with the code I had before - effectively I'll rewrite most stuff, but that's worth it. First try was a dirty hack, but a good learning experience... Thanks for helping with reviews and hints, @Creeperface01 @SupremeMortal @PetteriM1. Will take a while though, since my wife is currently delivering our first child... ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants