Compare commits
72 Commits
dev/scoreb
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
7046cd5f92
|
|||
|
df6e6d7be2
|
|||
|
6c51d8ee30
|
|||
|
31d795e0d9
|
|||
|
376a5264e3
|
|||
|
a1d3cf5825
|
|||
|
bbdd2bc280
|
|||
|
90f223160c
|
|||
|
ee82930426
|
|||
|
f280e9beaa
|
|||
|
b0bb86f215
|
|||
|
910ed30360
|
|||
|
ee394bf183
|
|||
|
9c9523d629
|
|||
|
51f01f84cf
|
|||
|
c1854c8f73
|
|||
|
f149019b88
|
|||
|
ee8c9e4a3e
|
|||
|
84b4069f7b
|
|||
|
41acf32cb8
|
|||
|
9ed6db2484
|
|||
|
fd074ae690
|
|||
|
a348689b37
|
|||
|
c189472244
|
|||
|
0a5eeb9e86
|
|||
|
f9ca87cfc4
|
|||
|
b9af693a34
|
|||
|
eda9219ea0
|
|||
|
3424830d95
|
|||
|
72b7b22e32
|
|||
|
06be69f3e4
|
|||
|
bb3f0bbdcb
|
|||
|
b1307442e1
|
|||
|
4b587c55e9
|
|||
|
bbf6fde3a1
|
|||
|
696d18cf41
|
|||
|
e7f7b9654e
|
|||
|
e7b5120661
|
|||
|
475f1a28ca
|
|||
|
222f2dba61
|
|||
|
e76f7ff375
|
|||
|
95474a32c4
|
|||
|
59b374e623
|
|||
|
2b9f021419
|
|||
|
3e9649a8e0
|
|||
|
c63f5ce3eb
|
|||
|
dbb476bf11
|
|||
|
a5f68e76e5
|
|||
|
38918f5eaf
|
|||
|
f9a71250b1
|
|||
|
70d8efe421
|
|||
|
a3fcfcf65a
|
|||
|
3165eca0ca
|
|||
|
50fc39e924
|
|||
|
7f7fefdc98
|
|||
|
72b06bca7b
|
|||
|
74fc258834
|
|||
|
325546a76d
|
|||
|
4215b5615e
|
|||
|
10af38e102
|
|||
|
b049352fe3
|
|||
|
c4767bd240
|
|||
|
2d4895fef0
|
|||
|
04316d9cbd
|
|||
|
20791ed881
|
|||
|
2b0ad9895b
|
|||
|
ab17160f9d
|
|||
|
8a6f37924e
|
|||
|
f10fb46d23
|
|||
|
c6669af651
|
|||
|
3984ab3fca
|
|||
|
bc2d5a7e75
|
@@ -1,12 +1,13 @@
|
|||||||
# MC-SERVER
|
# MC-SERVER
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
Написанный с нуля сервер **Minecraft 1.12.2**.
|
Написанный с нуля сервер **Minecraft 1.12.2**.
|
||||||
|
|
||||||
На данный момент может только показывать информацию о себе. Подключение к серверу не возможно.
|
На данный момент сервер может показывать о себе информацию в списке серверов (motd, онлайн, иконка) и позволять
|
||||||
|
игрокам подключиться к себе. Загружается пустой мир.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
2
cli-parser/build.gradle
Normal file
2
cli-parser/build.gradle
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
//file:noinspection GrUnresolvedAccess
|
||||||
|
apply from: rootDir.toPath().resolve('logic.gradle').toFile()
|
||||||
2
cli-parser/gradle.properties
Normal file
2
cli-parser/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# suppress inspection "UnusedProperty" for whole file
|
||||||
|
module.name=cli-parser
|
||||||
17
cli-parser/src/main/java/mc/cliparser/CommandLine.java
Normal file
17
cli-parser/src/main/java/mc/cliparser/CommandLine.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package mc.cliparser;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ToString
|
||||||
|
public class CommandLine {
|
||||||
|
|
||||||
|
private final Set<Option> options;
|
||||||
|
|
||||||
|
public boolean has(Option option) {
|
||||||
|
return options.contains(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
cli-parser/src/main/java/mc/cliparser/CommandLineParser.java
Normal file
52
cli-parser/src/main/java/mc/cliparser/CommandLineParser.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package mc.cliparser;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
public class CommandLineParser {
|
||||||
|
|
||||||
|
private final Set<Option> options = new HashSet<>();
|
||||||
|
|
||||||
|
public void addOption(Option option) {
|
||||||
|
options.add(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandLine parse(String[] args) {
|
||||||
|
|
||||||
|
Set<Option> foundOptions = new HashSet<>();
|
||||||
|
AtomicReference<Option> refCurrentOption = new AtomicReference<>(null);
|
||||||
|
|
||||||
|
for (String arg : args) {
|
||||||
|
if (refCurrentOption.get() != null) {
|
||||||
|
refCurrentOption.get().value(arg);
|
||||||
|
foundOptions.add(refCurrentOption.get());
|
||||||
|
refCurrentOption.set(null);
|
||||||
|
} else {
|
||||||
|
parseOptArgs(arg, foundOptions, refCurrentOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandLine(foundOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("java:S125")
|
||||||
|
private void parseOptArgs(String arg, Set<Option> foundOptions, AtomicReference<Option> refCurrentOption) {
|
||||||
|
String optName;
|
||||||
|
if (arg.startsWith("--")) {
|
||||||
|
optName = arg.substring(2);
|
||||||
|
} else /*if (args[i].startsWith("-"))*/ {
|
||||||
|
optName = arg.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Option option : options) {
|
||||||
|
if (optName.equals(option.shortName()) || optName.equals(option.longName())) {
|
||||||
|
if (option.hasArgs()) {
|
||||||
|
refCurrentOption.set(option);
|
||||||
|
} else {
|
||||||
|
foundOptions.add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
cli-parser/src/main/java/mc/cliparser/Option.java
Normal file
25
cli-parser/src/main/java/mc/cliparser/Option.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package mc.cliparser;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
@Accessors(fluent = true)
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
public class Option {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String shortName;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String longName;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final boolean hasArgs;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private String value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package mc.cliparser;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class CommandLineParserTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void optionTest() {
|
||||||
|
Option option = Option.builder().shortName("v").build();
|
||||||
|
assertNull(option.longName());
|
||||||
|
assertFalse(option.hasArgs());
|
||||||
|
|
||||||
|
option = Option.builder().longName("version").build();
|
||||||
|
assertNull(option.shortName());
|
||||||
|
assertFalse(option.hasArgs());
|
||||||
|
|
||||||
|
option = Option.builder().shortName("v").longName("value1").hasArgs(true).build();
|
||||||
|
assertNotNull(option.shortName());
|
||||||
|
assertNotNull(option.longName());
|
||||||
|
assertTrue(option.hasArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shortOptionFlag() {
|
||||||
|
Option option = Option.builder().shortName("v").build();
|
||||||
|
|
||||||
|
var parser = new CommandLineParser();
|
||||||
|
parser.addOption(option);
|
||||||
|
|
||||||
|
CommandLine commandLine = parser.parse(new String[]{ "-v" });
|
||||||
|
assertTrue(commandLine.has(option));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void longOptionFlag() {
|
||||||
|
Option option = Option.builder().longName("version").build();
|
||||||
|
|
||||||
|
var parser = new CommandLineParser();
|
||||||
|
parser.addOption(option);
|
||||||
|
|
||||||
|
CommandLine commandLine = parser.parse(new String[]{ "--version" });
|
||||||
|
assertTrue(commandLine.has(option));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void argsOption() {
|
||||||
|
Option option1 = Option.builder().shortName("v").longName("value1").hasArgs(true).build();
|
||||||
|
Option option2 = Option.builder().shortName("a").longName("value2").hasArgs(true).build();
|
||||||
|
|
||||||
|
var parser = new CommandLineParser();
|
||||||
|
parser.addOption(option1);
|
||||||
|
parser.addOption(option2);
|
||||||
|
|
||||||
|
CommandLine commandLine = parser.parse(new String[]{ "--value1", "arg1", "-a", "arg2" });
|
||||||
|
assertTrue(commandLine.has(option1));
|
||||||
|
assertEquals("arg1", option1.value());
|
||||||
|
assertTrue(commandLine.has(option2));
|
||||||
|
assertEquals("arg2", option2.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void noPassOption() {
|
||||||
|
Option option = Option.builder().longName("version").build();
|
||||||
|
|
||||||
|
var parser = new CommandLineParser();
|
||||||
|
parser.addOption(option);
|
||||||
|
|
||||||
|
CommandLine commandLine = parser.parse(new String[]{ "--any-opt" });
|
||||||
|
assertFalse(commandLine.has(option));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
project.group=mc-project
|
prj.group=mc-project
|
||||||
project.name=mc-server
|
prj.name=mc-server
|
||||||
project.version=1.1-SNAPSHOT
|
prj.version=1.1
|
||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
10
libs.gradle
10
libs.gradle
@@ -13,16 +13,20 @@ ext {
|
|||||||
lombok : 'org.projectlombok:lombok:1.18.12',
|
lombok : 'org.projectlombok:lombok:1.18.12',
|
||||||
annotations: 'com.google.code.findbugs:jsr305:3.0.2',
|
annotations: 'com.google.code.findbugs:jsr305:3.0.2',
|
||||||
lang3 : 'org.apache.commons:commons-lang3:3.11',
|
lang3 : 'org.apache.commons:commons-lang3:3.11',
|
||||||
netty : ["io.netty:netty-transport:${netty_version}",
|
|
||||||
"io.netty:netty-handler:${netty_version}"],
|
|
||||||
reactor : 'io.projectreactor:reactor-core:3.4.5',
|
reactor : 'io.projectreactor:reactor-core:3.4.5',
|
||||||
yaml : 'org.yaml:snakeyaml:1.28',
|
hocon : 'com.typesafe:config:1.4.1',
|
||||||
json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5',
|
json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5',
|
||||||
ioutils : 'commons-io:commons-io:2.6',
|
ioutils : 'commons-io:commons-io:2.6',
|
||||||
jopt : 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3',
|
jopt : 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3',
|
||||||
objpool : 'org.apache.commons:commons-pool2:2.9.0'
|
objpool : 'org.apache.commons:commons-pool2:2.9.0'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
libs.netty = [
|
||||||
|
transport: "io.netty:netty-transport:${netty_version}",
|
||||||
|
codec : "io.netty:netty-codec:${netty_version}",
|
||||||
|
handler : "io.netty:netty-handler:${netty_version}"
|
||||||
|
]
|
||||||
|
|
||||||
libs.logger = [
|
libs.logger = [
|
||||||
slf4j : ["org.slf4j:slf4j-api:${slf4j_version}",
|
slf4j : ["org.slf4j:slf4j-api:${slf4j_version}",
|
||||||
"org.slf4j:jcl-over-slf4j:${slf4j_version}"],
|
"org.slf4j:jcl-over-slf4j:${slf4j_version}"],
|
||||||
|
|||||||
22
logic.gradle
22
logic.gradle
@@ -1,21 +1,28 @@
|
|||||||
//file:noinspection GrUnresolvedAccess
|
//file:noinspection GrUnresolvedAccess
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'java-library'
|
apply plugin: 'java-library'
|
||||||
|
apply plugin: 'jacoco'
|
||||||
apply from: rootDir.toPath().resolve('libs.gradle').toFile()
|
apply from: rootDir.toPath().resolve('libs.gradle').toFile()
|
||||||
|
|
||||||
String getProperty1(String propertyName1, String propertyName2) {
|
String getProperty1(String propertyName1, String propertyName2) {
|
||||||
return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2))
|
return (String) (project.hasProperty(propertyName1) ? project.property(propertyName1) : project.property(propertyName2))
|
||||||
}
|
}
|
||||||
|
|
||||||
project.group = getProperty1('module.group', 'project.group')
|
project.group = getProperty1('module.group', 'prj.group')
|
||||||
project.version = getProperty1('module.version', 'project.version')
|
project.version = getProperty1('module.version', 'prj.version')
|
||||||
jar.archiveBaseName.set(getProperty1('module.name', 'project.name'))
|
jar.archiveBaseName.set(getProperty1('module.name', 'prj.name'))
|
||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_11
|
||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gradle.projectsEvaluated {
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -31,13 +38,18 @@ dependencies {
|
|||||||
implementation libs.dagger2.implementation
|
implementation libs.dagger2.implementation
|
||||||
annotationProcessor libs.dagger2.annotationProcessor
|
annotationProcessor libs.dagger2.annotationProcessor
|
||||||
|
|
||||||
|
testAnnotationProcessor libs.lombok
|
||||||
|
testCompileOnly libs.lombok
|
||||||
|
|
||||||
testImplementation libs.test.junit5.api
|
testImplementation libs.test.junit5.api
|
||||||
testImplementation libs.test.junit5.params
|
testImplementation libs.test.junit5.params
|
||||||
testRuntimeOnly libs.test.junit5.engine
|
testRuntimeOnly libs.test.junit5.engine
|
||||||
|
|
||||||
testRuntimeOnly libs.test.logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jacoco {
|
||||||
|
toolVersion = '0.8.7'
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
apply from: rootDir.toPath().resolve('logic.gradle').toFile()
|
apply from: rootDir.toPath().resolve('logic.gradle').toFile()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation libs.netty
|
api project(':utils')
|
||||||
|
|
||||||
|
implementation libs.netty.transport
|
||||||
|
implementation libs.netty.codec
|
||||||
implementation libs.json
|
implementation libs.json
|
||||||
implementation libs.objpool
|
|
||||||
|
|
||||||
testImplementation libs.lang3
|
testImplementation libs.lang3
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
package mc.protocol;
|
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
import mc.protocol.api.ConnectionContext;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
|
||||||
import mc.protocol.pool.Passivable;
|
|
||||||
|
|
||||||
@EqualsAndHashCode
|
|
||||||
public class NettyConnectionContext implements ConnectionContext, Passivable {
|
|
||||||
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@Setter
|
|
||||||
private ChannelHandlerContext ctx;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public State getState() {
|
|
||||||
return ctx.channel().attr(NetworkAttributes.STATE).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setState(State state) {
|
|
||||||
ctx.channel().attr(NetworkAttributes.STATE).set(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void send(ServerSidePacket packet) {
|
|
||||||
ctx.write(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendNow(ServerSidePacket packet) {
|
|
||||||
ctx.writeAndFlush(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flushSending() {
|
|
||||||
ctx.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disconnect() {
|
|
||||||
ctx.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void passivate() {
|
|
||||||
this.ctx = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
package mc.protocol;
|
|
||||||
|
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
|
||||||
import io.netty.channel.ChannelHandler;
|
|
||||||
import io.netty.channel.ChannelInitializer;
|
|
||||||
import io.netty.channel.ChannelPipeline;
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
|
||||||
import io.netty.channel.socket.SocketChannel;
|
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
|
||||||
import io.netty.handler.logging.LogLevel;
|
|
||||||
import io.netty.handler.logging.LoggingHandler;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import mc.protocol.api.ConnectionContext;
|
|
||||||
import mc.protocol.api.Server;
|
|
||||||
import mc.protocol.event.EventBus;
|
|
||||||
import mc.protocol.io.codec.ProtocolDecoder;
|
|
||||||
import mc.protocol.io.codec.ProtocolEncoder;
|
|
||||||
import mc.protocol.io.codec.ProtocolSplitter;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.inject.Provider;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class NettyServer implements Server {
|
|
||||||
|
|
||||||
private final Provider<ProtocolDecoder> protocolDecoderProvider;
|
|
||||||
private final Provider<PacketInboundHandler> packetInboundHandlerProvider;
|
|
||||||
private final EventBus eventBus;
|
|
||||||
private Consumer<ConnectionContext> consumerNewConnection;
|
|
||||||
private Consumer<ConnectionContext> consumerDisconnect;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bind(String host, int port) {
|
|
||||||
log.info("Network starting: {}:{}", host, port);
|
|
||||||
|
|
||||||
try {
|
|
||||||
createServerBootstrap().bind(host, port).sync().channel().closeFuture().sync();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
if (log.isTraceEnabled()) {
|
|
||||||
log.trace("{}: {}", e.getClass().getSimpleName(), e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNewConnect(Consumer<ConnectionContext> consumer) {
|
|
||||||
this.consumerNewConnection = consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisonnect(Consumer<ConnectionContext> consumer) {
|
|
||||||
this.consumerDisconnect = consumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("java:S2326") // Сонар, ты бредишь
|
|
||||||
public <P extends ClientSidePacket> void listenPacket(State state, Class<P> packetClass, EventBus.EventHandler<P> eventHandler) {
|
|
||||||
this.eventBus.subscribe(state, packetClass, eventHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ServerBootstrap createServerBootstrap() {
|
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
|
||||||
|
|
||||||
bootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup())
|
|
||||||
.channel(NioServerSocketChannel.class)
|
|
||||||
.childHandler(createChannelChannelInitializer());
|
|
||||||
|
|
||||||
return bootstrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChannelInitializer<SocketChannel> createChannelChannelInitializer() {
|
|
||||||
return new ChannelInitializer<>() {
|
|
||||||
@Override
|
|
||||||
protected void initChannel(@Nonnull SocketChannel socketChannel) {
|
|
||||||
ChannelPipeline pipeline = socketChannel.pipeline();
|
|
||||||
createChannelHandlerMap().forEach(pipeline::addLast);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, ChannelHandler> createChannelHandlerMap() {
|
|
||||||
Map<String, ChannelHandler> map = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
map.put("packet_splitter", new ProtocolSplitter());
|
|
||||||
map.put("logger", new LoggingHandler(LogLevel.DEBUG));
|
|
||||||
|
|
||||||
ProtocolDecoder protocolDecoder = protocolDecoderProvider.get();
|
|
||||||
protocolDecoder.setConsumerNewConnection(consumerNewConnection);
|
|
||||||
protocolDecoder.setConsumerDisconnect(consumerDisconnect);
|
|
||||||
map.put("packet_decoder", protocolDecoder);
|
|
||||||
|
|
||||||
map.put("packet_encoder", new ProtocolEncoder());
|
|
||||||
map.put("packet_handler", packetInboundHandlerProvider.get());
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package mc.protocol;
|
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
import mc.protocol.event.EventBus;
|
|
||||||
import mc.protocol.pool.PacketPool;
|
|
||||||
import org.apache.commons.pool2.ObjectPool;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PacketInboundHandler extends SimpleChannelInboundHandler<ClientSidePacket> {
|
|
||||||
|
|
||||||
private final ObjectPool<NettyConnectionContext> poolNettyConnectionContext;
|
|
||||||
private final PacketPool poolPackets;
|
|
||||||
private final EventBus eventBus;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, ClientSidePacket packet) throws Exception {
|
|
||||||
State state = ctx.channel().attr(NetworkAttributes.STATE).get();
|
|
||||||
|
|
||||||
NettyConnectionContext context = poolNettyConnectionContext.borrowObject().setCtx(ctx);
|
|
||||||
eventBus.emit(state, context, packet);
|
|
||||||
|
|
||||||
poolNettyConnectionContext.returnObject(context);
|
|
||||||
poolPackets.returnObject(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ import io.netty.util.AttributeKey;
|
|||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class NetworkAttributes {
|
public class ProtocolAttributes {
|
||||||
|
|
||||||
public static final AttributeKey<State> STATE = AttributeKey.newInstance("STATE");
|
public static final AttributeKey<State> STATE = AttributeKey.newInstance("STATE");
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,6 @@ import lombok.experimental.UtilityClass;
|
|||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class ProtocolConstant {
|
public class ProtocolConstant {
|
||||||
|
|
||||||
public static final String PROTOCOL_NAME = "1.12.2";
|
public final String PROTOCOL_NAME = "1.12.2";
|
||||||
public static final int PROTOCOL_NUMBER = 340;
|
public final int PROTOCOL_NUMBER = 340;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,16 @@ package mc.protocol;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
import mc.protocol.packets.Packet;
|
import mc.protocol.packets.KeepAlivePacket;
|
||||||
import mc.protocol.packets.PingPacket;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
import mc.protocol.packets.client.*;
|
import mc.protocol.packets.handshaking.client.HandshakePacket;
|
||||||
import mc.protocol.packets.server.*;
|
import mc.protocol.packets.login.client.LoginStartPacket;
|
||||||
|
import mc.protocol.packets.login.server.DisconnectPacket;
|
||||||
|
import mc.protocol.packets.login.server.LoginSuccessPacket;
|
||||||
|
import mc.protocol.packets.play.client.*;
|
||||||
|
import mc.protocol.packets.play.server.*;
|
||||||
|
import mc.protocol.packets.status.client.StatusServerRequestPacket;
|
||||||
|
import mc.protocol.packets.status.server.StatusServerResponse;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -16,88 +21,87 @@ import java.util.Map;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public enum State {
|
public enum State {
|
||||||
|
|
||||||
HANDSHAKING(-1,
|
HANDSHAKING(0,
|
||||||
// client side
|
// client side
|
||||||
Map.of(0x00, HandshakePacket.class)
|
Map.of(0x00, HandshakePacket.class),
|
||||||
|
// server side
|
||||||
|
Collections.emptyMap()
|
||||||
),
|
),
|
||||||
|
|
||||||
STATUS(1,
|
STATUS(1,
|
||||||
// client side
|
// client side
|
||||||
Map.of(
|
Map.of(
|
||||||
0x00, StatusServerRequestPacket.class,
|
0x00, StatusServerRequestPacket.class,
|
||||||
0x01, PingPacket.class
|
0x01, KeepAlivePacket.class
|
||||||
),
|
),
|
||||||
// server side
|
// server side
|
||||||
Map.of(
|
Map.of(
|
||||||
StatusServerResponse.class, 0x00,
|
StatusServerResponse.class, 0x00,
|
||||||
PingPacket.class, 0x01
|
KeepAlivePacket.class, 0x01
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
LOGIN(2,
|
LOGIN(2,
|
||||||
// server bound
|
// client side
|
||||||
Map.of(0x00, LoginStartPacket.class),
|
Map.of(0x00, LoginStartPacket.class),
|
||||||
// client bound
|
// server side
|
||||||
Map.of(
|
Map.of(
|
||||||
DisconnectPacket.class, 0x00,
|
DisconnectPacket.class, 0x00,
|
||||||
LoginSuccessPacket.class, 0x02
|
LoginSuccessPacket.class, 0x02
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
PLAY(3,
|
PLAY(3,
|
||||||
// server bound
|
// client side
|
||||||
Map.of(
|
Map.ofEntries(
|
||||||
0x00, TeleportConfirmPacket.class,
|
Map.entry(0x00, TeleportConfirmPacket.class),
|
||||||
0x04, ClientSettingsPacket.class,
|
Map.entry(0x04, ClientSettingsPacket.class),
|
||||||
0x09, PluginMessagePacket.class,
|
Map.entry(0x09, PluginMessagePacket.class),
|
||||||
0x0B, PingPacket.class,
|
Map.entry(0x0B, KeepAlivePacket.class),
|
||||||
0x0D, PlayerPositionPacket.class,
|
Map.entry(0x0C, PlayerOnGroundPacket.class),
|
||||||
0x0E, CPlayerPositionAndLookPacket.class,
|
Map.entry(0x0D, PlayerPositionPacket.class),
|
||||||
0x0F, PlayerLookPacket.class
|
Map.entry(0x0E, CPlayerPositionAndLookPacket.class),
|
||||||
|
Map.entry(0x0F, PlayerLookPacket.class),
|
||||||
|
Map.entry(0x13, CPlayerAbilitiesPacket.class),
|
||||||
|
Map.entry(0x14, PlayerDiggingAndMorePacket.class),
|
||||||
|
Map.entry(0x15, EntityActionPacket.class),
|
||||||
|
Map.entry(0x1D, HandAnimationPacket.class),
|
||||||
|
Map.entry(0x1F, PlayerBlockPlacementPacket.class)
|
||||||
),
|
),
|
||||||
// client bound
|
// server side
|
||||||
Map.of(
|
Map.of(
|
||||||
PingPacket.class, 0x1F,
|
KeepAlivePacket.class, 0x1F,
|
||||||
JoinGamePacket.class, 0x23,
|
|
||||||
ScoreboardDisplayPacket.class, 0x3B,
|
|
||||||
ScoreboardObjectivePacket.class, 0x42,
|
|
||||||
TeamsPacket.class, 0x44,
|
|
||||||
ScoreboardUpdateScorePacket.class, 0x45,
|
|
||||||
SpawnPositionPacket.class, 0x46,
|
|
||||||
ChunkDataPacket.class, 0x20,
|
ChunkDataPacket.class, 0x20,
|
||||||
PlayerAbilitiesPacket.class,0x2C,
|
JoinGamePacket.class, 0x23,
|
||||||
SPlayerPositionAndLookPacket.class, 0x2F
|
SPlayerAbilitiesPacket.class,0x2C,
|
||||||
|
SPlayerPositionAndLookPacket.class, 0x2F,
|
||||||
|
SpawnPositionPacket.class, 0x46
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static State getById(int id) {
|
public static State getById(int id) {
|
||||||
for (State state : State.values()) {
|
// а зачем усложнять?
|
||||||
if (state.id == id) {
|
//@formatter:off
|
||||||
return state;
|
if (id == 1) return STATUS;
|
||||||
}
|
else if (id == 2) return LOGIN;
|
||||||
}
|
else if (id == 3) return PLAY;
|
||||||
|
else return HANDSHAKING;
|
||||||
return null;
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final Map<Integer, Class<? extends ClientSidePacket>> clientSidePackets;
|
private final Map<Integer, Class<? extends ClientSidePacket>> clientSidePackets;
|
||||||
private final Map<Class<? extends ServerSidePacket>, Integer> serverSidePackets;
|
private final Map<Class<? extends ServerSidePacket>, Integer> serverSidePackets;
|
||||||
|
|
||||||
State(int id, Map<Integer, Class<? extends ClientSidePacket>> clientSidePackets) {
|
|
||||||
this.id = id;
|
|
||||||
this.clientSidePackets = clientSidePackets;
|
|
||||||
this.serverSidePackets = Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Class<? extends ClientSidePacket> getClientSidePacketById(int id) {
|
public Class<? extends ClientSidePacket> getClientSidePacketById(int id) {
|
||||||
return clientSidePackets == null ? null : clientSidePackets.get(id);
|
return clientSidePackets == null ? null : clientSidePackets.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Integer getServerSidePacketId(Class<? extends Packet> clazz) {
|
public Integer getServerSidePacketId(Class<? extends ServerSidePacket> clazz) {
|
||||||
return serverSidePackets == null ? null : serverSidePackets.get(clazz);
|
return serverSidePackets == null ? null : serverSidePackets.get(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package mc.protocol.api;
|
|
||||||
|
|
||||||
import mc.protocol.State;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
|
||||||
|
|
||||||
public interface ConnectionContext {
|
|
||||||
|
|
||||||
State getState();
|
|
||||||
void setState(State state);
|
|
||||||
|
|
||||||
void send(ServerSidePacket packet);
|
|
||||||
void sendNow(ServerSidePacket packet);
|
|
||||||
void flushSending();
|
|
||||||
|
|
||||||
void disconnect();
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package mc.protocol.api;
|
|
||||||
|
|
||||||
import mc.protocol.State;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
import mc.protocol.event.EventBus;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public interface Server {
|
|
||||||
|
|
||||||
void bind(String host, int port);
|
|
||||||
|
|
||||||
void onNewConnect(Consumer<ConnectionContext> consumer);
|
|
||||||
void onDisonnect(Consumer<ConnectionContext> consumer);
|
|
||||||
|
|
||||||
@SuppressWarnings("java:S2326") // Сонар, ты бредишь
|
|
||||||
<P extends ClientSidePacket> void listenPacket(State state, Class<P> packetClass, EventBus.EventHandler<P> eventHandler);
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package mc.protocol.io;
|
package mc.protocol.buffer;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@@ -6,6 +6,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.experimental.Delegate;
|
import lombok.experimental.Delegate;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.protocol.model.text.Text;
|
||||||
|
import mc.protocol.model.text.TextSerializer;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -32,29 +34,33 @@ import java.util.UUID;
|
|||||||
* | | | | этого числа). |
|
* | | | | этого числа). |
|
||||||
* | VarInt | >= 1 ; <= 5 | Число от -2147483648 и 2147483647 | 32-bit число с плавающей размерностью от 1 до 5 байт |
|
* | VarInt | >= 1 ; <= 5 | Число от -2147483648 и 2147483647 | 32-bit число с плавающей размерностью от 1 до 5 байт |
|
||||||
* | VarLong | >= 1 ; <= 10 | Число от -9223372036854775808 и 9223372036854775807 | 64-bit число с плавающей размерностью от 1 до 10 байт |
|
* | VarLong | >= 1 ; <= 10 | Число от -9223372036854775808 и 9223372036854775807 | 64-bit число с плавающей размерностью от 1 до 10 байт |
|
||||||
* | Position | 8 | 64-bit число разделённое на три части: x, y, z | Кодируется формулой: |
|
* | Text | | JSON | По файту является String (n), который имеет формат JSON |
|
||||||
* | | | | ((x & 0x3FFFFFF) << 38) | ((y & 0xFFF) << 26) | (z & 0x3FFFFFF) |
|
|
||||||
*
|
*
|
||||||
* [1] - <a href="https://en.wikipedia.org/wiki/Single-precision_floating-point_format">Single-precision floating-point format</a>
|
* [1] - <a href="https://en.wikipedia.org/wiki/Single-precision_floating-point_format">Single-precision floating-point format</a>
|
||||||
* [2] - <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">Double-precision floating-point format</a>
|
* [2] - <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">Double-precision floating-point format</a>
|
||||||
* [3] - <a href="http://unicode.org/glossary/#unicode_scalar_value">Unicode Scalar Value</a>
|
* [3] - <a href="http://unicode.org/glossary/#unicode_scalar_value">Unicode Scalar Value</a>
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Data_types">Data types</a>
|
* @see <a href="https://wiki.vg/index.php?title=Data_types&oldid=14345#Definitions">Data types</a>
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Chat&oldid=14272">Chat</a>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@ToString
|
@ToString
|
||||||
public class NetByteBuf extends ByteBuf {
|
public abstract class NetByteBuf extends ByteBuf {
|
||||||
|
|
||||||
@Delegate
|
@Delegate
|
||||||
private final ByteBuf byteBuf;
|
protected ByteBuf byteBuf;
|
||||||
|
|
||||||
public void writeUnsignedByte(int value) {
|
public void writeUnsignedByte(int value) {
|
||||||
byteBuf.writeByte((byte)(value & 0xFF));
|
byteBuf.writeByte((byte)(value & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeText(Text text) {
|
||||||
|
writeString(TextSerializer.toStringPlain(text));
|
||||||
|
}
|
||||||
|
|
||||||
//region String
|
//region String
|
||||||
public String readString() {
|
public String readString() {
|
||||||
return readString(Short.MAX_VALUE);
|
return readString(Short.MAX_VALUE);
|
||||||
@@ -67,9 +73,9 @@ public class NetByteBuf extends ByteBuf {
|
|||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return "";
|
return "";
|
||||||
} else if (length > maxLength) {
|
} else if (length > maxLength) {
|
||||||
throw new DecoderException("String length exceeds maximum length: " + length + " > " + maxLength);
|
throw new NetIOException("String length exceeds maximum length: " + length + " > " + maxLength);
|
||||||
} else if (length < 0) {
|
} else if (length < 0) {
|
||||||
throw new DecoderException("String length less zero!");
|
throw new NetIOException("String length less zero!");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bytes = new byte[length * 4];
|
byte[] bytes = new byte[length * 4];
|
||||||
@@ -99,11 +105,6 @@ public class NetByteBuf extends ByteBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeString(String string) {
|
public void writeString(String string) {
|
||||||
if (string == null) {
|
|
||||||
writeVarInt(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] buf = string.getBytes(StandardCharsets.UTF_8);
|
byte[] buf = string.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
if (buf.length > Short.MAX_VALUE) {
|
if (buf.length > Short.MAX_VALUE) {
|
||||||
@@ -119,22 +120,7 @@ public class NetByteBuf extends ByteBuf {
|
|||||||
|
|
||||||
//region VarInt
|
//region VarInt
|
||||||
public int readVarInt() {
|
public int readVarInt() {
|
||||||
int numRead = 0;
|
return readVarInt(this.byteBuf);
|
||||||
int result = 0;
|
|
||||||
byte read;
|
|
||||||
do {
|
|
||||||
if ((numRead + 1) > 5) {
|
|
||||||
log.warn("VarInt is too big");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
read = readByte();
|
|
||||||
int value = (read & 0b01111111);
|
|
||||||
result |= (value << (7 * numRead));
|
|
||||||
|
|
||||||
numRead++;
|
|
||||||
} while ((read & 0b10000000) != 0);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeVarInt(int value) {
|
public void writeVarInt(int value) {
|
||||||
@@ -188,4 +174,23 @@ public class NetByteBuf extends ByteBuf {
|
|||||||
writeLong(uuid.getLeastSignificantBits());
|
writeLong(uuid.getLeastSignificantBits());
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
public static int readVarInt(ByteBuf byteBuf) {
|
||||||
|
int numRead = 0;
|
||||||
|
int result = 0;
|
||||||
|
byte read;
|
||||||
|
do {
|
||||||
|
if ((numRead + 1) > 5) {
|
||||||
|
log.warn("VarInt is too big");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read = byteBuf.readByte();
|
||||||
|
int value = (read & 0b01111111);
|
||||||
|
result |= (value << (7 * numRead));
|
||||||
|
|
||||||
|
numRead++;
|
||||||
|
} while ((read & 0b10000000) != 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package mc.protocol.buffer;
|
||||||
|
|
||||||
|
public class NetIOException extends RuntimeException {
|
||||||
|
|
||||||
|
public NetIOException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package mc.protocol.di;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
import mc.protocol.NettyConnectionContext;
|
|
||||||
import mc.protocol.State;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
import mc.protocol.packets.UnknownPacket;
|
|
||||||
import mc.protocol.pool.NettyConnectionContextFactory;
|
|
||||||
import mc.protocol.pool.PacketFactory;
|
|
||||||
import mc.protocol.pool.PacketPool;
|
|
||||||
import org.apache.commons.pool2.ObjectPool;
|
|
||||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class PoolModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@ServerScope
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
||||||
PacketPool providePacketPool() {
|
|
||||||
Map<Class<? extends ClientSidePacket>, ObjectPool> map = Stream.of(State.values())
|
|
||||||
.flatMap(state -> state.getClientSidePackets().values().stream())
|
|
||||||
.distinct()
|
|
||||||
.collect(Collectors.toMap(
|
|
||||||
packetClass -> packetClass,
|
|
||||||
packetClass -> new GenericObjectPool(new PacketFactory<>(packetClass))));
|
|
||||||
map.put(UnknownPacket.class, new GenericObjectPool(new PacketFactory<>(UnknownPacket.class)));
|
|
||||||
|
|
||||||
return new PacketPool(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@ServerScope
|
|
||||||
ObjectPool<NettyConnectionContext> providePoolNettyConnectionContext() {
|
|
||||||
return new GenericObjectPool<>(new NettyConnectionContextFactory());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package mc.protocol.di;
|
|
||||||
|
|
||||||
import dagger.Component;
|
|
||||||
import mc.protocol.api.Server;
|
|
||||||
|
|
||||||
@Component(modules = {
|
|
||||||
ProtocolModule.class,
|
|
||||||
PoolModule.class
|
|
||||||
})
|
|
||||||
@ServerScope
|
|
||||||
public interface ProtocolComponent {
|
|
||||||
|
|
||||||
Server getServer();
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package mc.protocol.di;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import mc.protocol.NettyConnectionContext;
|
|
||||||
import mc.protocol.NettyServer;
|
|
||||||
import mc.protocol.PacketInboundHandler;
|
|
||||||
import mc.protocol.api.Server;
|
|
||||||
import mc.protocol.event.EventBus;
|
|
||||||
import mc.protocol.event.SimpleEventBus;
|
|
||||||
import mc.protocol.io.codec.ProtocolDecoder;
|
|
||||||
import mc.protocol.pool.PacketPool;
|
|
||||||
import org.apache.commons.pool2.ObjectPool;
|
|
||||||
|
|
||||||
import javax.inject.Provider;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ProtocolModule {
|
|
||||||
|
|
||||||
private final boolean readUnknownPackets;
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@ServerScope
|
|
||||||
Server provideServer(
|
|
||||||
Provider<ProtocolDecoder> protocolDecoderProvider,
|
|
||||||
Provider<PacketInboundHandler> packetInboundHandlerProvider,
|
|
||||||
EventBus eventBus
|
|
||||||
) {
|
|
||||||
return new NettyServer(protocolDecoderProvider, packetInboundHandlerProvider, eventBus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
ProtocolDecoder provideProtocolDecoder(
|
|
||||||
ObjectPool<NettyConnectionContext> poolNettyConnectionContext,
|
|
||||||
PacketPool poolPackets
|
|
||||||
) {
|
|
||||||
return new ProtocolDecoder(readUnknownPackets, poolNettyConnectionContext, poolPackets);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
PacketInboundHandler providePacketInboundHandler(
|
|
||||||
ObjectPool<NettyConnectionContext> poolNettyConnectionContext,
|
|
||||||
PacketPool packetPool,
|
|
||||||
EventBus eventBus
|
|
||||||
) {
|
|
||||||
return new PacketInboundHandler(poolNettyConnectionContext, packetPool, eventBus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@ServerScope
|
|
||||||
EventBus provideEventBus() {
|
|
||||||
return new SimpleEventBus();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package mc.protocol.di;
|
|
||||||
|
|
||||||
import javax.inject.Scope;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
|
|
||||||
@Scope
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface ServerScope {
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package mc.protocol.event;
|
|
||||||
|
|
||||||
import mc.protocol.State;
|
|
||||||
import mc.protocol.api.ConnectionContext;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
|
|
||||||
public interface EventBus {
|
|
||||||
|
|
||||||
<P extends ClientSidePacket> void subscribe(State state, Class<P> packetClass, EventHandler<P> eventHandler);
|
|
||||||
|
|
||||||
<P extends ClientSidePacket> void emit(State state, ConnectionContext channelContext, P packet);
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
interface EventHandler<P extends ClientSidePacket> {
|
|
||||||
void handle(ConnectionContext channelContext, P packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package mc.protocol.event;
|
|
||||||
|
|
||||||
import mc.protocol.State;
|
|
||||||
import mc.protocol.api.ConnectionContext;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
import mc.protocol.utils.Table;
|
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
||||||
public class SimpleEventBus implements EventBus {
|
|
||||||
|
|
||||||
private final Table<State, Class<? extends ClientSidePacket>, EventHandler> table = new Table<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <P extends ClientSidePacket> void subscribe(State state, Class<P> packetClass, EventHandler<P> eventHandler) {
|
|
||||||
table.put(state, packetClass, eventHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <P extends ClientSidePacket> void emit(State state, ConnectionContext channelContext, P packet) {
|
|
||||||
EventHandler eventHandler = table.getColumnAndRow(state, packet.getClass());
|
|
||||||
|
|
||||||
if (eventHandler != null) {
|
|
||||||
eventHandler.handle(channelContext, packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package mc.protocol.handler;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import mc.protocol.State;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.utils.Table;
|
||||||
|
|
||||||
|
public class ProtocolHandlersBus {
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private final Table<State, Class<? extends ClientSidePacket>, Handler> table = new Table<>();
|
||||||
|
|
||||||
|
public <P extends ClientSidePacket> ProtocolHandlersBus addHandler(State state, Class<P> packetClass, Handler<P> handler) {
|
||||||
|
table.put(state, packetClass, handler);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
public <P extends ClientSidePacket> void process(State state, ChannelHandlerContext ctx, P packet) {
|
||||||
|
Handler handler = table.getColumnAndRow(state, packet.getClass());
|
||||||
|
|
||||||
|
if (handler != null) {
|
||||||
|
handler.handle(ctx, packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Handler<P extends ClientSidePacket> {
|
||||||
|
void handle(ChannelHandlerContext ctx, P packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package mc.protocol.handler;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.protocol.ProtocolAttributes;
|
||||||
|
import mc.protocol.State;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ProtocolInboundHandler extends SimpleChannelInboundHandler<ClientSidePacket> {
|
||||||
|
|
||||||
|
private static final String CLIENT_FORCE_DISCONNECTED_IOEXCEPTION_MESSAGE_RU = "Программа на вашем хост-компьютере разорвала установленное подключение";
|
||||||
|
|
||||||
|
private final ProtocolHandlersBus protocolHandlersBus;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void channelRead0(ChannelHandlerContext ctx, ClientSidePacket packet) {
|
||||||
|
State state = Objects.requireNonNull(ctx.channel().attr(ProtocolAttributes.STATE).get());
|
||||||
|
protocolHandlersBus.process(state, ctx, packet);
|
||||||
|
|
||||||
|
ProtocolObjectPool.packet().returnObject(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
|
if (cause instanceof IOException && cause.getLocalizedMessage().equalsIgnoreCase(CLIENT_FORCE_DISCONNECTED_IOEXCEPTION_MESSAGE_RU)) {
|
||||||
|
log.warn("Client '{}' force disconnected", ctx.channel().remoteAddress());
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace("{}", cause.getMessage(), cause);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("{}", cause.getMessage(), cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package mc.protocol.handler.codec;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.protocol.ProtocolAttributes;
|
||||||
|
import mc.protocol.State;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.packets.UnknownPacket;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ProtocolDecoder extends ByteToMessageDecoder {
|
||||||
|
|
||||||
|
private final boolean readUnknownPackets;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) {
|
||||||
|
ctx.channel().attr(ProtocolAttributes.STATE).set(State.HANDSHAKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||||
|
State state = Objects.requireNonNull(ctx.channel().attr(ProtocolAttributes.STATE).get());
|
||||||
|
NetByteBuf netByteBuf = ProtocolObjectPool.netByteBuf().borrowObject(in);
|
||||||
|
|
||||||
|
int packetId = netByteBuf.readVarInt();
|
||||||
|
Class<? extends ClientSidePacket> packetClass = state.getClientSidePacketById(packetId);
|
||||||
|
if (packetClass == null) {
|
||||||
|
log.warn("Unknown packet: State {} ; Id 0x{}", state, packetIdAsHexcode(packetId));
|
||||||
|
|
||||||
|
if (readUnknownPackets) {
|
||||||
|
UnknownPacket unknownPacket = ProtocolObjectPool.packet().borrowObject(UnknownPacket.class);
|
||||||
|
unknownPacket.setState(state);
|
||||||
|
unknownPacket.setId(packetId);
|
||||||
|
unknownPacket.setDataSize(netByteBuf.readableBytes());
|
||||||
|
unknownPacket.readSelf(netByteBuf);
|
||||||
|
out.add(unknownPacket);
|
||||||
|
} else {
|
||||||
|
netByteBuf.skipBytes(netByteBuf.readableBytes());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ClientSidePacket packet = ProtocolObjectPool.packet().borrowObject(packetClass);
|
||||||
|
packet.readSelf(netByteBuf);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("IN: {}:{}", state, packet);
|
||||||
|
}
|
||||||
|
out.add(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolObjectPool.netByteBuf().returnObject(netByteBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String packetIdAsHexcode(int packetId) {
|
||||||
|
String hexPacketId = Integer.toHexString(packetId).toUpperCase();
|
||||||
|
if (hexPacketId.length() == 1) hexPacketId = "0" + hexPacketId;
|
||||||
|
|
||||||
|
return hexPacketId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,35 +1,42 @@
|
|||||||
package mc.protocol.io.codec;
|
package mc.protocol.handler.codec;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import mc.protocol.NetworkAttributes;
|
import mc.protocol.ProtocolAttributes;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ProtocolEncoder extends MessageToByteEncoder<ServerSidePacket> {
|
public class ProtocolEncoder extends MessageToByteEncoder<ServerSidePacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(ChannelHandlerContext ctx, ServerSidePacket packet, ByteBuf out) {
|
protected void encode(ChannelHandlerContext ctx, ServerSidePacket packet, ByteBuf out) {
|
||||||
State state = ctx.channel().attr(NetworkAttributes.STATE).get();
|
State state = Objects.requireNonNull(ctx.channel().attr(ProtocolAttributes.STATE).get());
|
||||||
Integer packetId = state.getServerSidePacketId(packet.getClass());
|
Integer packetId = state.getServerSidePacketId(packet.getClass());
|
||||||
if (packetId == null) {
|
if (packetId == null) {
|
||||||
log.error("Unknown send packet: State {} ; Class {}", state, packet.getClass());
|
log.error("Unknown send packet: State {} ; Class {}", state, packet.getClass());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("OUT: {}:{}", state, packet);
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("OUT: {}:{}", state, packet);
|
||||||
|
}
|
||||||
|
|
||||||
NetByteBuf buffer = new NetByteBuf(Unpooled.buffer());
|
NetByteBuf buffer = ProtocolObjectPool.netByteBuf().borrowObject();
|
||||||
buffer.writeVarInt(packetId);
|
buffer.writeVarInt(packetId);
|
||||||
packet.writeSelf(buffer);
|
packet.writeSelf(buffer);
|
||||||
|
|
||||||
NetByteBuf netByteBuf = new NetByteBuf(out);
|
NetByteBuf netByteBuf = ProtocolObjectPool.netByteBuf().borrowObject(out);
|
||||||
netByteBuf.writeVarInt(buffer.readableBytes());
|
netByteBuf.writeVarInt(buffer.readableBytes());
|
||||||
netByteBuf.writeBytes(buffer);
|
netByteBuf.writeBytes(buffer);
|
||||||
|
|
||||||
|
ProtocolObjectPool.netByteBuf().returnObject(netByteBuf);
|
||||||
|
ProtocolObjectPool.netByteBuf().returnObject(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package mc.protocol.io.codec;
|
package mc.protocol.handler.codec;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ public class ProtocolSplitter extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||||
NetByteBuf netByteBuf = new NetByteBuf(in);
|
NetByteBuf netByteBuf = ProtocolObjectPool.netByteBuf().borrowObject(in);
|
||||||
netByteBuf.markReaderIndex();
|
netByteBuf.markReaderIndex();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -25,7 +26,7 @@ public class ProtocolSplitter extends ByteToMessageDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sizePacket = new NetByteBuf(Unpooled.wrappedBuffer(sizePacketRaw)).readVarInt();
|
int sizePacket = NetByteBuf.readVarInt(Unpooled.wrappedBuffer(sizePacketRaw));
|
||||||
|
|
||||||
if (netByteBuf.readableBytes() >= sizePacket) {
|
if (netByteBuf.readableBytes() >= sizePacket) {
|
||||||
byte[] bytes = new byte[sizePacket];
|
byte[] bytes = new byte[sizePacket];
|
||||||
@@ -36,5 +37,7 @@ public class ProtocolSplitter extends ByteToMessageDecoder {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (netByteBuf.readableBytes() > 0);
|
} while (netByteBuf.readableBytes() > 0);
|
||||||
|
|
||||||
|
ProtocolObjectPool.netByteBuf().returnObject(netByteBuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package mc.protocol.io;
|
|
||||||
|
|
||||||
public class DecoderException extends RuntimeException {
|
|
||||||
|
|
||||||
public DecoderException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package mc.protocol.io.codec;
|
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import mc.protocol.NettyConnectionContext;
|
|
||||||
import mc.protocol.NetworkAttributes;
|
|
||||||
import mc.protocol.State;
|
|
||||||
import mc.protocol.api.ConnectionContext;
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
import mc.protocol.packets.UnknownPacket;
|
|
||||||
import mc.protocol.pool.PacketPool;
|
|
||||||
import org.apache.commons.pool2.ObjectPool;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Slf4j
|
|
||||||
public class ProtocolDecoder extends ByteToMessageDecoder {
|
|
||||||
|
|
||||||
private final boolean readUnknownPackets;
|
|
||||||
private final ObjectPool<NettyConnectionContext> poolNettyConnectionContext;
|
|
||||||
private final PacketPool poolPackets;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private Consumer<ConnectionContext> consumerNewConnection;
|
|
||||||
@Setter
|
|
||||||
private Consumer<ConnectionContext> consumerDisconnect;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelActive(@Nonnull ChannelHandlerContext ctx) throws Exception {
|
|
||||||
NettyConnectionContext context = poolNettyConnectionContext.borrowObject().setCtx(ctx);
|
|
||||||
consumerNewConnection.accept(context);
|
|
||||||
|
|
||||||
poolNettyConnectionContext.returnObject(context);
|
|
||||||
super.channelActive(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelInactive(@Nonnull ChannelHandlerContext ctx) throws Exception {
|
|
||||||
NettyConnectionContext context = poolNettyConnectionContext.borrowObject().setCtx(ctx);
|
|
||||||
consumerDisconnect.accept(context);
|
|
||||||
|
|
||||||
poolNettyConnectionContext.returnObject(context);
|
|
||||||
super.channelInactive(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
|
||||||
State state = Objects.requireNonNull(ctx.channel().attr(NetworkAttributes.STATE).get());
|
|
||||||
NetByteBuf netByteBuf = new NetByteBuf(in);
|
|
||||||
|
|
||||||
int packetId = netByteBuf.readVarInt();
|
|
||||||
Class<? extends ClientSidePacket> packetClass = state.getClientSidePacketById(packetId);
|
|
||||||
if (packetClass == null) {
|
|
||||||
log.warn("Unknown packet: State {} ; Id 0x{}", state, packetIdAsHexcode(packetId));
|
|
||||||
|
|
||||||
if (readUnknownPackets) {
|
|
||||||
UnknownPacket unknownPacket = poolPackets.borrowObject(UnknownPacket.class);
|
|
||||||
unknownPacket.setState(state);
|
|
||||||
unknownPacket.setId(packetId);
|
|
||||||
unknownPacket.setDataSize(netByteBuf.readableBytes());
|
|
||||||
unknownPacket.readSelf(netByteBuf);
|
|
||||||
out.add(unknownPacket);
|
|
||||||
} else {
|
|
||||||
netByteBuf.skipBytes(netByteBuf.readableBytes());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ClientSidePacket packet = poolPackets.borrowObject(packetClass);
|
|
||||||
packet.readSelf(netByteBuf);
|
|
||||||
log.debug("IN: {}:{}", state, packet);
|
|
||||||
out.add(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String packetIdAsHexcode(int packetId) {
|
|
||||||
String hexPacketId = Integer.toHexString(packetId).toUpperCase();
|
|
||||||
if (hexPacketId.length() == 1) hexPacketId = "0" + hexPacketId;
|
|
||||||
|
|
||||||
return hexPacketId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
11
protocol/src/main/java/mc/protocol/model/BlockLocation.java
Normal file
11
protocol/src/main/java/mc/protocol/model/BlockLocation.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package mc.protocol.model;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.utils.vector.Vector3i;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class BlockLocation extends Vector3i {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package mc.protocol.model;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.utils.vector.Vector3i;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class ChunkSectionLocation extends Vector3i {
|
||||||
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
package mc.protocol.model;
|
package mc.protocol.model;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Data;
|
import lombok.ToString;
|
||||||
|
import mc.utils.vector.Vector3d;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@ToString(callSuper = true)
|
||||||
public class Location {
|
public class Location extends Vector3d {
|
||||||
private double x;
|
|
||||||
private double y;
|
|
||||||
private double z;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,26 @@
|
|||||||
package mc.protocol.model;
|
package mc.protocol.model;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Data;
|
import lombok.ToString;
|
||||||
|
import mc.utils.vector.Vector2f;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@ToString(callSuper = true)
|
||||||
public class Look {
|
public class Look extends Vector2f {
|
||||||
private float yaw;
|
|
||||||
private float pitch;
|
/**
|
||||||
|
* Equal X
|
||||||
|
* @return X
|
||||||
|
*/
|
||||||
|
public float getYaw() {
|
||||||
|
return this.getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equal Y
|
||||||
|
* @return Y
|
||||||
|
*/
|
||||||
|
public float getPitch() {
|
||||||
|
return this.getY();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package mc.protocol.serializer;
|
package mc.protocol.model;
|
||||||
|
|
||||||
import com.eclipsesource.json.Json;
|
import com.eclipsesource.json.Json;
|
||||||
import com.eclipsesource.json.JsonArray;
|
import com.eclipsesource.json.JsonArray;
|
||||||
import com.eclipsesource.json.JsonObject;
|
import com.eclipsesource.json.JsonObject;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import mc.protocol.model.ServerInfo;
|
import mc.protocol.model.text.TextSerializer;
|
||||||
|
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.Spliterators;
|
import java.util.Spliterators;
|
||||||
@@ -14,7 +14,11 @@ import java.util.stream.StreamSupport;
|
|||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class ServerInfoSerializer {
|
public class ServerInfoSerializer {
|
||||||
|
|
||||||
public JsonObject toJsonObject(ServerInfo info) {
|
public String toStringPlain(ServerInfo info) {
|
||||||
|
return toJsonObject(info).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject toJsonObject(ServerInfo info) {
|
||||||
JsonObject jsonObject = Json.object()
|
JsonObject jsonObject = Json.object()
|
||||||
.add("version", createVersionObj(info))
|
.add("version", createVersionObj(info))
|
||||||
.add("players", createPlayersObj(info))
|
.add("players", createPlayersObj(info))
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
package mc.protocol.serializer;
|
package mc.protocol.model.text;
|
||||||
|
|
||||||
import com.eclipsesource.json.Json;
|
import com.eclipsesource.json.Json;
|
||||||
import com.eclipsesource.json.JsonArray;
|
import com.eclipsesource.json.JsonArray;
|
||||||
import com.eclipsesource.json.JsonObject;
|
import com.eclipsesource.json.JsonObject;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
import mc.protocol.model.text.Text;
|
|
||||||
import mc.protocol.model.text.TextColor;
|
|
||||||
import mc.protocol.model.text.TextStyle;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -16,6 +13,10 @@ public class TextSerializer {
|
|||||||
private static final Map<Character, TextStyle> legacyStyleCodes;
|
private static final Map<Character, TextStyle> legacyStyleCodes;
|
||||||
private static final Map<Character, TextColor> legacyColorCodes;
|
private static final Map<Character, TextColor> legacyColorCodes;
|
||||||
|
|
||||||
|
public String toStringPlain(Text text) {
|
||||||
|
return toJsonObject(text).toString();
|
||||||
|
}
|
||||||
|
|
||||||
public JsonObject toJsonObject(Text text) {
|
public JsonObject toJsonObject(Text text) {
|
||||||
JsonObject jsonObject = Json.object();
|
JsonObject jsonObject = Json.object();
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package mc.protocol.packets;
|
package mc.protocol.packets;
|
||||||
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.pool.Passivable;
|
import mc.utils.pool.Passivable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Пакеты отправляемые клиентом.
|
* Пакеты отправляемые клиентом.
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package mc.protocol.packets;
|
|
||||||
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
|
||||||
|
|
||||||
public abstract class EmptyPacket implements ClientSidePacket, ServerSidePacket {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readSelf(NetByteBuf netByteBuf) {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void passivate() {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,13 @@
|
|||||||
package mc.protocol.packets;
|
package mc.protocol.packets;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Пинг-пакет.
|
* Пинг-пакет.
|
||||||
*
|
*
|
||||||
* <p>Эхо-пакет, которым проверяется качество соединения между <b>Клиентом</b> и <b>Сервером</b>.</p>
|
* <p>Эхо-пакет, которым проверяется качество соединения между <b>Клиентом</b> и <b>Сервером</b>.</p>
|
||||||
*
|
*
|
||||||
* <p>По спецификации:</p>
|
|
||||||
* <oi>
|
|
||||||
* <li>если <b>Сервер</b> не ответил <b>Клиенту</b> в течении 20 секунд, <b>Клиент</b> отключается
|
|
||||||
* и выдаёт ошибку <i>"Timed out"</i>.</li>
|
|
||||||
* <li>если <b>Клиент</b> не отвечает <b>Серверу</b> в течении 30 секунд, <b>Сервер</b> отключает <b>Клиента</b>.</li>
|
|
||||||
* </oi>
|
|
||||||
*
|
|
||||||
* <p>Структура пакета</p>
|
* <p>Структура пакета</p>
|
||||||
* <pre>
|
* <pre>
|
||||||
* | FIELD | TYPE | NOTES |
|
* | FIELD | TYPE | NOTES |
|
||||||
@@ -22,25 +15,32 @@ import mc.protocol.io.NetByteBuf;
|
|||||||
* | Payload | Long | Любое уникальное число |
|
* | Payload | Long | Любое уникальное число |
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Keep_Alive">Keep Alive</a>
|
* <p>По спецификации:</p>
|
||||||
|
* <oi>
|
||||||
|
* <li>если Сервер не ответил Клиенту в течении 20 секунд, Клиент отключается и выдаёт ошибку "Timed out";</li>
|
||||||
|
* <li>если Клиент не отвечает Серверу в течении 30 секунд, Сервер отключает Клиента.</li>
|
||||||
|
* </oi>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Keep_Alive_.28clientbound.29">Keep Alive (clientbound)</a>
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Keep_Alive_.28serverbound.29">Keep Alive (serverbound)</a>
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class PingPacket implements ClientSidePacket, ServerSidePacket {
|
public class KeepAlivePacket implements ClientSidePacket, ServerSidePacket {
|
||||||
|
|
||||||
private Long payload;
|
private long payload;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSelf(NetByteBuf netByteBuf) {
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
payload = netByteBuf.readLong();
|
payload = netByteBuf.readLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void passivate() {
|
|
||||||
this.payload = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
netByteBuf.writeLong(payload);
|
netByteBuf.writeLong(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.payload = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package mc.protocol.packets;
|
package mc.protocol.packets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Пакет.
|
* Сетевой пакет.
|
||||||
*
|
*
|
||||||
* <p>Структура пакета</p>
|
* <p>Структура</p>
|
||||||
* <pre>
|
* <pre>
|
||||||
* | FIELD | TYPE | NOTES |
|
* | FIELD | TYPE | NOTES |
|
||||||
* |-------------|--------|-------------------------------------------|
|
* |-------------|--------|-------------------------------------------|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package mc.protocol.packets;
|
package mc.protocol.packets;
|
||||||
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Пакеты отправляемые сервером.
|
* Пакеты отправляемые сервером.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
package mc.protocol.packets.client;
|
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.ToString;
|
|
||||||
import mc.protocol.packets.EmptyPacket;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status server packet, request.
|
|
||||||
*
|
|
||||||
* <p>Клиент запрашивает получение информации о сервере</p>
|
|
||||||
*/
|
|
||||||
@NoArgsConstructor
|
|
||||||
@EqualsAndHashCode(callSuper = false)
|
|
||||||
@ToString
|
|
||||||
public class StatusServerRequestPacket extends EmptyPacket {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.handshaking.client;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,14 +18,14 @@ import mc.protocol.packets.ClientSidePacket;
|
|||||||
* | FIELD | TYPE | NOTES |
|
* | FIELD | TYPE | NOTES |
|
||||||
* |------------------|----------------|----------------------------------------------|
|
* |------------------|----------------|----------------------------------------------|
|
||||||
* | Protocol version | VarInt | Версия протокола [1] |
|
* | Protocol version | VarInt | Версия протокола [1] |
|
||||||
* | Server address | Stirng | Hostname или IP |
|
* | Server address | Stirng (255) | Hostname или IP |
|
||||||
* | Server port | Unsigned Short | Порт сервера |
|
* | Server port | Unsigned Short | Порт сервера |
|
||||||
* | Next stage | VarInt | ID State на который необходимо переключиться |
|
* | Next state | VarInt | ID State на который необходимо переключиться |
|
||||||
*
|
*
|
||||||
* [1] - <a href="https://wiki.vg/Protocol_version_numbers" target="_top">Protocol version numbers</a>
|
* [1] - <a href="https://wiki.vg/Protocol_version_numbers">Protocol version numbers</a>
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Handshake" target="_top">Handshake</a>
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Handshake">Handshake</a>
|
||||||
* @see State
|
* @see State
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@@ -41,10 +41,10 @@ public class HandshakePacket implements ClientSidePacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSelf(NetByteBuf netByteBuf) {
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
protocolVersion = netByteBuf.readVarInt();
|
this.protocolVersion = netByteBuf.readVarInt();
|
||||||
host = netByteBuf.readString(255);
|
this.host = netByteBuf.readString(255);
|
||||||
port = netByteBuf.readUnsignedShort();
|
this.port = netByteBuf.readUnsignedShort();
|
||||||
nextState = State.getById(netByteBuf.readVarInt());
|
this.nextState = State.getById(netByteBuf.readVarInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -54,5 +54,4 @@ public class HandshakePacket implements ClientSidePacket {
|
|||||||
this.port = 0;
|
this.port = 0;
|
||||||
this.nextState = null;
|
this.nextState = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.login.client;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,7 +19,7 @@ import mc.protocol.packets.ClientSidePacket;
|
|||||||
* | Name | String | Имя/Логин игрока |
|
* | Name | String | Имя/Логин игрока |
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Login_Start" target="_top">Login start</a>
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Login_Start">Login start</a>
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
package mc.protocol.packets.server;
|
package mc.protocol.packets.login.server;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.model.text.Text;
|
import mc.protocol.model.text.Text;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
import mc.protocol.serializer.TextSerializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Diconnect packet.
|
* Diconnect packet.
|
||||||
@@ -16,7 +15,7 @@ import mc.protocol.serializer.TextSerializer;
|
|||||||
* <pre>
|
* <pre>
|
||||||
* | FIELD | TYPE | NOTES |
|
* | FIELD | TYPE | NOTES |
|
||||||
* |-------------|--------|----------------------------------|
|
* |-------------|--------|----------------------------------|
|
||||||
* | JSON Reason | String | Причина отключения. Опционально. |
|
* | JSON Reason | Text | Причина отключения. Опционально. |
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* <p>Пример JSON Reason</p>
|
* <p>Пример JSON Reason</p>
|
||||||
@@ -26,7 +25,7 @@ import mc.protocol.serializer.TextSerializer;
|
|||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=7368#Disconnect_2" target="_top">Disconnect</a>
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Disconnect_.28login.29">Disconnect (login)</a>
|
||||||
* @see State
|
* @see State
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@@ -39,6 +38,6 @@ public class DisconnectPacket implements ServerSidePacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
netByteBuf.writeString(TextSerializer.toJsonObject(reason).toString());
|
netByteBuf.writeText(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package mc.protocol.packets.server;
|
package mc.protocol.packets.login.server;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -27,7 +27,7 @@ public class LoginSuccessPacket implements ServerSidePacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
netByteBuf.writeString(uuid.toString());
|
netByteBuf.writeString(this.uuid.toString());
|
||||||
netByteBuf.writeString(name);
|
netByteBuf.writeString(this.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Характеристики игрока.
|
||||||
|
*
|
||||||
|
* <p>Структура пакета</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |------------------------------|----------|-----------------------------------------|
|
||||||
|
* | Flags | Byte | Битовая маска флагов. См. ниже значения |
|
||||||
|
* | Flying Speed | Float | Скорость полёта |
|
||||||
|
* | Field of View (FOV) Modifier | Float | Поле зрения |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>Флаги "Flags"</p>
|
||||||
|
* <pre>
|
||||||
|
* Bit 0x01 - Неуязвимость (Invulnerable)
|
||||||
|
* Bit 0x02 - В полёте (Flying)
|
||||||
|
* Bit 0x04 - Может летать (Allow Flying)
|
||||||
|
* Bit 0x08 - Creative Mode (Instant Break)
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Abilities_(serverbound)">Player Abilities</a>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CPlayerAbilitiesPacket implements ClientSidePacket {
|
||||||
|
|
||||||
|
@SuppressWarnings("java:S116")
|
||||||
|
private byte $flags = 0;
|
||||||
|
private float flyingSpeed;
|
||||||
|
private float fieldOfView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
|
this.$flags = netByteBuf.readByte();
|
||||||
|
this.flyingSpeed = netByteBuf.readFloat();
|
||||||
|
this.fieldOfView = netByteBuf.readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME использование value значений
|
||||||
|
public void setInvulnerable(boolean value) {
|
||||||
|
this.$flags = (byte) (this.$flags | 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlying(boolean value) {
|
||||||
|
this.$flags = (byte) (this.$flags | 0x02);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCatFly(boolean value) {
|
||||||
|
this.$flags = (byte) (this.$flags | 0x04);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreativeMode(boolean value) {
|
||||||
|
this.$flags = (byte) (this.$flags | 0x08);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
$flags = 0;
|
||||||
|
flyingSpeed = 0;
|
||||||
|
fieldOfView = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.model.Location;
|
import mc.protocol.model.Location;
|
||||||
import mc.protocol.model.Look;
|
import mc.protocol.model.Look;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Клиент сообщает о движении и повороте головы Игрока.
|
* Клиент сообщает о движении и повороте головы Игрока.
|
||||||
@@ -42,19 +43,27 @@ public class CPlayerPositionAndLookPacket implements ClientSidePacket {
|
|||||||
double x = netByteBuf.readDouble();
|
double x = netByteBuf.readDouble();
|
||||||
double y = netByteBuf.readDouble();
|
double y = netByteBuf.readDouble();
|
||||||
double z = netByteBuf.readDouble();
|
double z = netByteBuf.readDouble();
|
||||||
this.position = new Location(x, y, z);
|
this.position = ProtocolObjectPool.location().borrowObject();
|
||||||
|
position.set(x, y, z);
|
||||||
|
|
||||||
float yaw = netByteBuf.readFloat();
|
float yaw = netByteBuf.readFloat();
|
||||||
float pitch = netByteBuf.readFloat();
|
float pitch = netByteBuf.readFloat();
|
||||||
this.look = new Look(yaw, pitch);
|
this.look = ProtocolObjectPool.look().borrowObject();
|
||||||
|
this.look.set(yaw, pitch);
|
||||||
|
|
||||||
this.onGround = netByteBuf.readBoolean();
|
this.onGround = netByteBuf.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void passivate() {
|
public void passivate() {
|
||||||
|
this.position.set(0, 0, 0);
|
||||||
|
ProtocolObjectPool.location().returnObject(this.position);
|
||||||
this.position = null;
|
this.position = null;
|
||||||
|
|
||||||
|
this.look.set(0, 0);
|
||||||
|
ProtocolObjectPool.look().returnObject(this.look);
|
||||||
this.look = null;
|
this.look = null;
|
||||||
|
|
||||||
this.onGround = false;
|
this.onGround = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import mc.protocol.utils.ChatMode;
|
import mc.protocol.utils.ChatMode;
|
||||||
import mc.protocol.utils.MainHand;
|
import mc.protocol.utils.Hand;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +52,7 @@ public class ClientSettingsPacket implements ClientSidePacket {
|
|||||||
private boolean chatColors;
|
private boolean chatColors;
|
||||||
@SuppressWarnings("java:S116")
|
@SuppressWarnings("java:S116")
|
||||||
private int $displayedSkinPartsBitMask;
|
private int $displayedSkinPartsBitMask;
|
||||||
private MainHand mainHand;
|
private Hand mainHand;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSelf(NetByteBuf netByteBuf) {
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
@@ -61,7 +61,7 @@ public class ClientSettingsPacket implements ClientSidePacket {
|
|||||||
this.chatMode = ChatMode.valueById(netByteBuf.readVarInt());
|
this.chatMode = ChatMode.valueById(netByteBuf.readVarInt());
|
||||||
this.chatColors = netByteBuf.readBoolean();
|
this.chatColors = netByteBuf.readBoolean();
|
||||||
this.$displayedSkinPartsBitMask = netByteBuf.readUnsignedByte();
|
this.$displayedSkinPartsBitMask = netByteBuf.readUnsignedByte();
|
||||||
this.mainHand = MainHand.valueById(netByteBuf.readVarInt());
|
this.mainHand = Hand.valueById(netByteBuf.readVarInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity Action packet.
|
||||||
|
*
|
||||||
|
* <p>Структура пакета</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |------------|--------|-------------------------------------------|
|
||||||
|
* | Entity ID | VarInt | ID игрока |
|
||||||
|
* | Action ID | VarInt | ID действия |
|
||||||
|
* | Jump Boost | VarInt | Используется только при "Action ID" = 5. |
|
||||||
|
* | | | В этом случае значение будет от 0 до 100. |
|
||||||
|
* | | | В остальных случаях значение 0. |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Entity_Action" target="_top">Entity Action</a>
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
public class EntityActionPacket implements ClientSidePacket {
|
||||||
|
|
||||||
|
private Integer entityId;
|
||||||
|
private Action action;
|
||||||
|
private Integer jumpBoost;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
|
this.entityId = netByteBuf.readVarInt();
|
||||||
|
int actionId = netByteBuf.readVarInt();
|
||||||
|
this.jumpBoost = netByteBuf.readVarInt();
|
||||||
|
|
||||||
|
this.action = Action.valueOfCode(actionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.entityId = null;
|
||||||
|
this.action = null;
|
||||||
|
this.jumpBoost = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum Action {
|
||||||
|
START_SNEAKING(0),
|
||||||
|
STOP_SNEAKING(1),
|
||||||
|
LEAVE_BED(2),
|
||||||
|
START_SPRINTING(3),
|
||||||
|
STOP_SPRINTING(4),
|
||||||
|
START_JUMP_WITH_HORSE(5),
|
||||||
|
STOP_JUMP_WITH_HORSE(6),
|
||||||
|
OPEN_HORSE_INVENTORY(7),
|
||||||
|
START_FLYING_WITH_ELYTRA(8);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Action valueOfCode(int code) {
|
||||||
|
for (Action action : Action.values()) {
|
||||||
|
if (action.code == code) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.utils.Hand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Отправляется, когда Игрок взмахивает рукой.
|
||||||
|
*
|
||||||
|
* <p>Структура пакета</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |-------|---------|------------------------------|
|
||||||
|
* | Hand | VarInt | Используемая рука в анимации |
|
||||||
|
* | | | - 0: основная рука |
|
||||||
|
* | | | - 1: левая рука |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Animation_.28serverbound.29">Animation (serverbound)</a>
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
public class HandAnimationPacket implements ClientSidePacket {
|
||||||
|
|
||||||
|
private Hand hand;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
|
this.hand = Hand.valueById(netByteBuf.readVarInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.hand = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.model.BlockLocation;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.utils.Face;
|
||||||
|
import mc.protocol.utils.Hand;
|
||||||
|
import mc.protocol.utils.SerializeUtil;
|
||||||
|
import mc.utils.vector.Vector3f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Игрок размещает блок.
|
||||||
|
*
|
||||||
|
* <p>Структура пакета</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |-------------------|----------|---------------------------------------------------------------------------|
|
||||||
|
* | Location | Position | Позиция блока |
|
||||||
|
* | Face | VarInt | Сторона блока, к которому ставится новый блок |
|
||||||
|
* | Hand | VarInt | Используемая рука |
|
||||||
|
* | | | - 0: основная рука |
|
||||||
|
* | | | - 1: левая рука |
|
||||||
|
* | Cursor Position X | Float | Положение перекрестия на блоке, от 0 до 1 с увеличением с West на East. |
|
||||||
|
* | Cursor Position Y | Float | Положение перекрестия на блоке, от 0 до 1 с увеличением с Bottom на Top. |
|
||||||
|
* | Cursor Position Z | Float | Положение перекрестия на блоке, от 0 до 1 с увеличением с North на South. |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>Значения Стороны блока</p>
|
||||||
|
* <pre>
|
||||||
|
* | VALUE | OFFCET | FACE |
|
||||||
|
* |-------|--------|--------|
|
||||||
|
* | 0 | -Y | Bottom |
|
||||||
|
* | 1 | +Y | Top |
|
||||||
|
* | 2 | -Z | North |
|
||||||
|
* | 3 | +Z | South |
|
||||||
|
* | 4 | -X | West |
|
||||||
|
* | 5 | +X | East |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Block_Placement">Player Block Placement</a>
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
public class PlayerBlockPlacementPacket implements ClientSidePacket {
|
||||||
|
|
||||||
|
private BlockLocation location;
|
||||||
|
private Face face;
|
||||||
|
private Hand hand;
|
||||||
|
private Vector3f cursorPosition;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
|
this.location = SerializeUtil.long2location(netByteBuf.readLong());
|
||||||
|
this.face = Face.valueById(netByteBuf.readVarInt());
|
||||||
|
this.hand = Hand.valueById(netByteBuf.readVarInt());
|
||||||
|
|
||||||
|
this.cursorPosition = new Vector3f();
|
||||||
|
this.cursorPosition.set(
|
||||||
|
netByteBuf.readFloat(),
|
||||||
|
netByteBuf.readFloat(),
|
||||||
|
netByteBuf.readFloat()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.location = null;
|
||||||
|
this.face = null;
|
||||||
|
this.hand = null;
|
||||||
|
this.cursorPosition = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.model.BlockLocation;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.utils.DiggingStatus;
|
||||||
|
import mc.protocol.utils.Face;
|
||||||
|
import mc.protocol.utils.SerializeUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Клиент копает, ломает блок (и не только).
|
||||||
|
*
|
||||||
|
* <p>Структура пакета</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |----------|----------|------------------------------------------|
|
||||||
|
* | Status | VarInt | Действие Игрока к блоку |
|
||||||
|
* | Location | Position | Позиция блока |
|
||||||
|
* | Face | Byte | Сторона блока, с которой взаимодействуют |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>Возможные действия Игрока к блоку</p>
|
||||||
|
* <pre>
|
||||||
|
* | VALUE | DESCRIPTION | NOTES |
|
||||||
|
* |--------- |-------------------------|---------------------------------------------------------------------------------------|
|
||||||
|
* | 0 | Начал ломать | |
|
||||||
|
* | 1 | Прекратил ломать | Отправляется, когда Игрок отпустил клавишу "копания" |
|
||||||
|
* | 2 | Закончил ломать | Отправляется, когда Игрок закончил ломать блок. Т.е. блок готов сломаться |
|
||||||
|
* | 3 | Бросает стек предметов | Отправляется, когда Игрок с помощью клавиши "Выкинуть предмет"(Q) |
|
||||||
|
* | | | с модификатором(??) для выкидывания полного стека. |
|
||||||
|
* | | | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||||
|
* | 4 | Бросает предмет | Отправляется, когда Игрок выкидывает предмет. |
|
||||||
|
* | | | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||||
|
* | 5 | Стреляет стрелой / | Указывает, что текущего состояние удерживаемого предмета должно |
|
||||||
|
* | | Заканчивает есть / | быть обновлено. Например, поедание еды, натягивание луков, использование ведер и т.д. |
|
||||||
|
* | | и т.д. | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||||
|
* | 6 | Поменять предмет в руке | Отправляется когда Игрок меняет предмет предмет во второй руке через "свап". |
|
||||||
|
* | | | Поле Location всегда будет 0/0/0, а Face всегда -Y. |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>Значения Стороны блока</p>
|
||||||
|
* <pre>
|
||||||
|
* | VALUE | OFFCET | FACE |
|
||||||
|
* |-------|--------|--------|
|
||||||
|
* | 0 | -Y | Bottom |
|
||||||
|
* | 1 | +Y | Top |
|
||||||
|
* | 2 | -Z | North |
|
||||||
|
* | 3 | +Z | South |
|
||||||
|
* | 4 | -X | West |
|
||||||
|
* | 5 | +X | East |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Digging">Player Digging</a>
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
public class PlayerDiggingAndMorePacket implements ClientSidePacket {
|
||||||
|
|
||||||
|
private DiggingStatus status;
|
||||||
|
private BlockLocation location;
|
||||||
|
private Face face;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
|
this.status = DiggingStatus.valueById(netByteBuf.readVarInt());
|
||||||
|
this.location = SerializeUtil.long2location(netByteBuf.readLong());
|
||||||
|
this.face = Face.valueById(netByteBuf.readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.status = null;
|
||||||
|
this.location = null;
|
||||||
|
this.face = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.model.Look;
|
import mc.protocol.model.Look;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Клиент сообщает о повороте головы Игрока.
|
* Клиент сообщает о повороте головы Игрока.
|
||||||
@@ -35,14 +36,18 @@ public class PlayerLookPacket implements ClientSidePacket {
|
|||||||
public void readSelf(NetByteBuf netByteBuf) {
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
float yaw = netByteBuf.readFloat();
|
float yaw = netByteBuf.readFloat();
|
||||||
float pitch = netByteBuf.readFloat();
|
float pitch = netByteBuf.readFloat();
|
||||||
this.look = new Look(yaw, pitch);
|
this.look = ProtocolObjectPool.look().borrowObject();
|
||||||
|
this.look.set(yaw, pitch);
|
||||||
|
|
||||||
this.onGround = netByteBuf.readBoolean();
|
this.onGround = netByteBuf.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void passivate() {
|
public void passivate() {
|
||||||
|
this.look.set(0, 0);
|
||||||
|
ProtocolObjectPool.look().returnObject(this.look);
|
||||||
this.look = null;
|
this.look = null;
|
||||||
|
|
||||||
this.onGround = false;
|
this.onGround = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Клиент сообщает: на земле ли он.
|
||||||
|
*
|
||||||
|
* <p>Структура пакета</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |-----------|---------|---------------------------------------------|
|
||||||
|
* | On Ground | Boolean | true, если Игрок находится на земле |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player">Player</a>
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
public class PlayerOnGroundPacket implements ClientSidePacket {
|
||||||
|
|
||||||
|
private boolean onGround;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
|
this.onGround = netByteBuf.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
onGround = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.model.Location;
|
import mc.protocol.model.Location;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Клиент сообщает о движении Игрока.
|
* Клиент сообщает о движении Игрока.
|
||||||
@@ -38,14 +39,18 @@ public class PlayerPositionPacket implements ClientSidePacket {
|
|||||||
double x = netByteBuf.readDouble();
|
double x = netByteBuf.readDouble();
|
||||||
double y = netByteBuf.readDouble();
|
double y = netByteBuf.readDouble();
|
||||||
double z = netByteBuf.readDouble();
|
double z = netByteBuf.readDouble();
|
||||||
this.position = new Location(x, y, z);
|
this.position = ProtocolObjectPool.location().borrowObject();
|
||||||
|
this.position.set(x, y, z);
|
||||||
|
|
||||||
this.onGround = netByteBuf.readBoolean();
|
this.onGround = netByteBuf.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void passivate() {
|
public void passivate() {
|
||||||
|
this.position.set(0, 0, 0);
|
||||||
|
ProtocolObjectPool.location().returnObject(this.position);
|
||||||
this.position = null;
|
this.position = null;
|
||||||
|
|
||||||
this.onGround = false;
|
this.onGround = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
package mc.protocol.packets.client;
|
package mc.protocol.packets.play.client;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
import mc.protocol.packets.server.SPlayerPositionAndLookPacket;
|
import mc.protocol.packets.play.server.SPlayerPositionAndLookPacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Teleport сonfirm packet.
|
* Teleport сonfirm packet.
|
||||||
*
|
*
|
||||||
* <p>Структура пакета</p>
|
* <p>Структура пакета</p>
|
||||||
* <pre>
|
* <pre>
|
||||||
* | FIELD | TYPE | NOTES |
|
* | FIELD | TYPE | NOTES |
|
||||||
* |-------------|--------|-----------------------------------------------------------|
|
* |-------------|--------|------------------------------------------------------------|
|
||||||
* | Teleport ID | VarInt | ID, который был выдан пакетом {@link SPlayerPositionAndLookPacket} |
|
* | Teleport ID | VarInt | ID, который был выдан пакетом {@link SPlayerPositionAndLookPacket} |
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package mc.protocol.packets.play.server;
|
||||||
|
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import lombok.Data;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
import mc.protocol.utils.SerializeUtil;
|
||||||
|
import mc.protocol.world.Chunk;
|
||||||
|
import mc.protocol.world.ChunkSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Данные чанка.
|
||||||
|
*
|
||||||
|
* <h2>Структура пакета</h2>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |--------------------------|------------- |------------------------------------------------------------------------------------|
|
||||||
|
* | Chunk X | Integer | Координаты чанка (координата блока, делённая на 16, округленная в меньшую сторону) |
|
||||||
|
* | Chunk Z | Integer | Координаты чанка (координата блока, делённая на 16, округленная в меньшую сторону) |
|
||||||
|
* | Is Full chunk | Boolean | См. Chunk Format |
|
||||||
|
* | Available Sections | VarInt | Битовая маска, где каждый бит - это часть чанка (0-15) |
|
||||||
|
* | Size of Data | VarInt | Размер поля "Data" |
|
||||||
|
* | Data | Byte array | Данные чанка. См. Data Structure |
|
||||||
|
* | Number of block entities | VarInt | Количество элементов в поле "Block entities" |
|
||||||
|
* | Block entities | Array of NBT | Все сущности в чанке |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <h2>Data Structure</h2>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |--------|------------------------|------------------------------------------------------------|
|
||||||
|
* | Data | Array of Chunk Section | См. Chunk Section Structure |
|
||||||
|
* | Biomes | Byte array | Optional. Отправляются только если "Is Full chunk" == true |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <h2>Chunk Section Structure</h2>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |-------------------|---------------|---------------------------------------------------------------------|
|
||||||
|
* | Bits Per Block | Unsigned Byte | Определяет, сколько битов используется для кодирования блока |
|
||||||
|
* | Palette | Byte array | См. Palette Structure |
|
||||||
|
* | Data Array Length | VarInt | |
|
||||||
|
* | Data Array | Array of Long | |
|
||||||
|
* | Block Light | Byte array | Половина байна на блок |
|
||||||
|
* | Sky Light | Byte array | Optional. Только для LevelType == Overworld. Половина байна на блок |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <h2>Palette Structure</h2>
|
||||||
|
* <p>Есть два типа: Indirect и Direct.</p>
|
||||||
|
* <p>
|
||||||
|
* Indirect используется, если "Bits Per Block" < 9. При этом, если "Bits Per Block" <= 4,
|
||||||
|
* то должно использоваться значение 4.
|
||||||
|
* </p>
|
||||||
|
* <p>Для Indirect формат следующий</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |----------------|-----------------|--------------------------------|
|
||||||
|
* | Palette Length | VarInt | Количество элементов в массиве |
|
||||||
|
* | Palette | Array of VarInt | Идентификаторы блоков |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* <p>Direct используется, если "Bits Per Block" >= 9</p>
|
||||||
|
* <p>Для Direct формат следующий</p>
|
||||||
|
* <pre>
|
||||||
|
* | FIELD | TYPE | NOTES |
|
||||||
|
* |----------------------|--------|-------------|
|
||||||
|
* | Dummy Palette Length | VarInt | Всегда == 0 |
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Chunk_Data">Chunk Data</a>
|
||||||
|
* @see <a href="https://wiki.vg/index.php?title=Chunk_Format&oldid=14135">Chunk Format</a>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ChunkDataPacket implements ServerSidePacket {
|
||||||
|
|
||||||
|
private static final int FULL_BIT_MASK = 0b11111111_11111111;
|
||||||
|
|
||||||
|
private Chunk chunk;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
|
netByteBuf.writeInt(chunk.getX()); // Chunk X
|
||||||
|
netByteBuf.writeInt(chunk.getZ()); // Chunk Z
|
||||||
|
|
||||||
|
netByteBuf.writeBoolean(true); // Is Full chunk
|
||||||
|
netByteBuf.writeVarInt(FULL_BIT_MASK); // Available Sections
|
||||||
|
|
||||||
|
NetByteBuf data = createDataStructure();
|
||||||
|
netByteBuf.writeVarInt(data.readableBytes()); // Size of Data
|
||||||
|
netByteBuf.writeBytes(data); // Data
|
||||||
|
|
||||||
|
netByteBuf.writeVarInt(0); // Number of block entities
|
||||||
|
// Block entities (NBT's)
|
||||||
|
|
||||||
|
ProtocolObjectPool.netByteBuf().returnObject(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetByteBuf createDataStructure() {
|
||||||
|
NetByteBuf dataStructure = ProtocolObjectPool.netByteBuf().borrowObject(Unpooled.buffer());
|
||||||
|
|
||||||
|
for (int h = 0; h < 16; h++) {
|
||||||
|
ChunkSection section = chunk.getSection(h);
|
||||||
|
NetByteBuf data = SerializeUtil.serializeChunkSection(section);
|
||||||
|
dataStructure.writeBytes(data); // Data
|
||||||
|
ProtocolObjectPool.netByteBuf().returnObject(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <Biomes>
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
dataStructure.writeByte(chunk.getBiome(
|
||||||
|
(chunk.getX() << 4) + x,
|
||||||
|
(chunk.getZ() << 4) + z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// </Biomes>
|
||||||
|
|
||||||
|
return dataStructure;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package mc.protocol.packets.server;
|
package mc.protocol.packets.play.server;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.utils.Difficulty;
|
import mc.protocol.utils.Difficulty;
|
||||||
import mc.protocol.utils.GameMode;
|
import mc.protocol.utils.GameMode;
|
||||||
import mc.protocol.utils.LevelType;
|
import mc.protocol.utils.LevelType;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package mc.protocol.packets.server;
|
package mc.protocol.packets.play.server;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,7 +27,7 @@ import mc.protocol.packets.ServerSidePacket;
|
|||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Abilities_.28clientbound.29">Player Abilities</a>
|
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Player_Abilities_.28clientbound.29">Player Abilities</a>
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class PlayerAbilitiesPacket implements ServerSidePacket {
|
public class SPlayerAbilitiesPacket implements ServerSidePacket {
|
||||||
|
|
||||||
@SuppressWarnings("java:S116")
|
@SuppressWarnings("java:S116")
|
||||||
private byte $flags = 0;
|
private byte $flags = 0;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package mc.protocol.packets.server;
|
package mc.protocol.packets.play.server;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.model.Location;
|
import mc.protocol.model.Location;
|
||||||
import mc.protocol.model.Look;
|
import mc.protocol.model.Look;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
import mc.protocol.packets.client.TeleportConfirmPacket;
|
import mc.protocol.packets.play.client.TeleportConfirmPacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Установка позиции и угла осмотра Игрока.
|
* Установка позиции и угла осмотра Игрока.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package mc.protocol.packets.server;
|
package mc.protocol.packets.play.server;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.model.Location;
|
import mc.protocol.model.Location;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package mc.protocol.packets.server;
|
|
||||||
|
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import lombok.Data;
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Данные чанка.
|
|
||||||
*
|
|
||||||
* <p>Структура пакета</p>
|
|
||||||
* <pre>
|
|
||||||
* | FIELD | TYPE | NOTES |
|
|
||||||
* |--------------------------|------------- |------------------------------------------------------------------------------------|
|
|
||||||
* | Chunk X | Integer | Координаты чанка (координата блока, делённая на 16, округленная в меньшую сторону) |
|
|
||||||
* | Chunk Z | Integer | Координаты чанка (координата блока, делённая на 16, округленная в меньшую сторону) |
|
|
||||||
* | Is Full chunk | Boolean | См. Chunk Format |
|
|
||||||
* | Available Sections | VarInt | Битовая маска, где каждый бит - это часть чанка (0-15) |
|
|
||||||
* | Size of Data | VarInt | Размер поля "Data" |
|
|
||||||
* | Data | Byte array | Данные чанка. См. Chunk Format |
|
|
||||||
* | Number of block entities | VarInt | Количество элементов в поле "Block entities" |
|
|
||||||
* | Block entities | Array of NBT | Все сущности в чанке |
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Chunk_Data">Chunk Data</a>
|
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Chunk_Format&oldid=14135">Chunk Format</a>
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ChunkDataPacket implements ServerSidePacket {
|
|
||||||
|
|
||||||
private int x;
|
|
||||||
private int z;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
|
||||||
netByteBuf.writeInt(x);
|
|
||||||
netByteBuf.writeInt(z);
|
|
||||||
netByteBuf.writeBoolean(true); // Is Full chunk
|
|
||||||
netByteBuf.writeVarInt(0b11111111); // Available Sections
|
|
||||||
|
|
||||||
NetByteBuf data = new NetByteBuf(Unpooled.buffer());
|
|
||||||
// <Data>
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
NetByteBuf dataBuff = new NetByteBuf(Unpooled.wrappedBuffer(new byte[4096]));
|
|
||||||
NetByteBuf blockLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048]));
|
|
||||||
NetByteBuf skyLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048]));
|
|
||||||
NetByteBuf biomes = new NetByteBuf(Unpooled.wrappedBuffer(new byte[256]));
|
|
||||||
|
|
||||||
// <Chunk Section>
|
|
||||||
data.writeUnsignedByte(13); // Bits Per Block
|
|
||||||
// <Palette>
|
|
||||||
data.writeUnsignedByte(0); // Palette Length (for direct)
|
|
||||||
// <Palette Data/>
|
|
||||||
// </Palette>
|
|
||||||
data.writeVarInt(dataBuff.readableBytes()); // Data Array Length
|
|
||||||
data.writeBytes(dataBuff); // Data Array
|
|
||||||
data.writeBytes(blockLight); // Block Light
|
|
||||||
data.writeBytes(skyLight); // Sky Light
|
|
||||||
// </Chunk Section>
|
|
||||||
data.writeBytes(biomes); // Biomes
|
|
||||||
}
|
|
||||||
// </Data>
|
|
||||||
|
|
||||||
netByteBuf.writeVarInt(data.readableBytes()); // Size of Data
|
|
||||||
netByteBuf.writeBytes(data); // Data
|
|
||||||
netByteBuf.writeVarInt(0); // Number of block entities
|
|
||||||
/* write NBT's */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package mc.protocol.packets.server;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Отображение Scoreboard.
|
|
||||||
*
|
|
||||||
* <p>Структура пакета</p>
|
|
||||||
* <pre>
|
|
||||||
* | FIELD | TYPE | NOTES |
|
|
||||||
* |------------|-------------|--------------------------------|
|
|
||||||
* | Position | Byte | Положение: |
|
|
||||||
* | | | 0 - list |
|
|
||||||
* | | | 1 - sidebar |
|
|
||||||
* | | | 2 - below name |
|
|
||||||
* | | | 3-18 - team specific sidebar |
|
|
||||||
* | Score Name | String (16) | Уникальное название Scoreboard |
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Display_Scoreboard" target="_top">Display Scoreboard</a>
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ScoreboardDisplayPacket implements ServerSidePacket {
|
|
||||||
|
|
||||||
private int position;
|
|
||||||
private String scoreName;
|
|
||||||
|
|
||||||
public void setPosition(int position) {
|
|
||||||
this.position = (position < 0) ? 0 : (Math.min(position, 18));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
|
||||||
netByteBuf.writeByte(this.position);
|
|
||||||
netByteBuf.writeString(this.scoreName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package mc.protocol.packets.server;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
|
||||||
import mc.protocol.utils.ScoreboardObjectiveMode;
|
|
||||||
import mc.protocol.utils.ScoreboardObjectiveType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scoreboard objective packet.
|
|
||||||
*
|
|
||||||
* <p>Структура пакета</p>
|
|
||||||
* <pre>
|
|
||||||
* | FIELD | TYPE | NOTES |
|
|
||||||
* |-----------------|-------------|---------------------------------------------------|
|
|
||||||
* | Objective Name | String (16) | Уникальное наименование цели (objective) |
|
|
||||||
* | Mode | Byte | 0 - создание Scoreboard |
|
|
||||||
* | | | 1 - удаление Scoreboard |
|
|
||||||
* | | | 2 - обновление Scoreboard |
|
|
||||||
* | Objective Value | String (32) | Если "Mode" равен 0 или 2. Отображаемый текст |
|
|
||||||
* | Type | String (16) | Если "Mode" равен 0 или 2. "integer" или "hearts" |
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Scoreboard_Objective" target="_top">Scoreboard Objective</a>
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ScoreboardObjectivePacket implements ServerSidePacket {
|
|
||||||
|
|
||||||
private String objectiveName;
|
|
||||||
private ScoreboardObjectiveMode mode;
|
|
||||||
private String objectiveValue;
|
|
||||||
private ScoreboardObjectiveType type;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
|
||||||
netByteBuf.writeString(this.objectiveName);
|
|
||||||
netByteBuf.writeByte(this.mode.getCode());
|
|
||||||
|
|
||||||
if (ScoreboardObjectiveMode.CREATE.equals(this.mode) || ScoreboardObjectiveMode.UPDATE.equals(this.mode)) {
|
|
||||||
netByteBuf.writeString(this.objectiveValue);
|
|
||||||
netByteBuf.writeString(this.type.name().toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package mc.protocol.packets.server;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
|
||||||
import mc.protocol.utils.ScoreboardUpdateScoreAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update score packet.
|
|
||||||
*
|
|
||||||
* <p>Структура пакета</p>
|
|
||||||
* <pre>
|
|
||||||
* | FIELD | TYPE | NOTES |
|
|
||||||
* |-----------------|-------------|--------------------------------------------------- |
|
|
||||||
* | Entity Name | String (40) | Сущность, которой принадлежит счет (score). |
|
|
||||||
* | | | Для Игроков - это ник |
|
|
||||||
* | | | Для других сущностей - это UUID |
|
|
||||||
* | Action | Byte | 0 - создать или обновить счет (score); 1 - удалить |
|
|
||||||
* | Objective Name | String (16) | Имя сущности, которой принадлежит счет (score) |
|
|
||||||
* | Value | VarInt | Если "Action" = 0. Значение счета (score) |
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Update_Score" target="_top">Update Score</a>
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ScoreboardUpdateScorePacket implements ServerSidePacket {
|
|
||||||
|
|
||||||
private String entityName;
|
|
||||||
private ScoreboardUpdateScoreAction action;
|
|
||||||
private String objective;
|
|
||||||
private int value;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
|
||||||
netByteBuf.writeString(this.entityName);
|
|
||||||
netByteBuf.writeByte(this.action.getCode());
|
|
||||||
netByteBuf.writeString(this.objective);
|
|
||||||
|
|
||||||
if (ScoreboardUpdateScoreAction.CREATE_OR_UPDATE.equals(this.action)) {
|
|
||||||
netByteBuf.writeVarInt(this.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
package mc.protocol.packets.server;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import mc.protocol.io.NetByteBuf;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
|
||||||
import mc.protocol.utils.TeamsCollisionRule;
|
|
||||||
import mc.protocol.utils.TeamsMode;
|
|
||||||
import mc.protocol.utils.TeamsNameTagVisibility;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Teams packet.
|
|
||||||
*
|
|
||||||
* <p>Структура пакета</p>
|
|
||||||
* <pre>
|
|
||||||
* | FIELD | TYPE | NOTES |
|
|
||||||
* |------------ |-------------|-------------------------------------------------------|
|
|
||||||
* | Team Name | String (16) | Уникальное название команды (совместно со scoreboard) |
|
|
||||||
* | Mode | Byte | Режим. Определяет остальые поля пакета |
|
|
||||||
* | Data Fields | - | Определяется "Mode" |
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>Варианты "Mode"</p>
|
|
||||||
* <pre>
|
|
||||||
* | MODE | DATA FIELD | TYPE | NOTES |
|
|
||||||
* | VALUE | DESCRIPTION | | | |
|
|
||||||
* |-------|--------------------------|---------------------|----------------------|---------------------------------------------------|
|
|
||||||
* | 0 | create team | Team Display Name | String (32) | |
|
|
||||||
* | | | Team Prefix | String (16) | Отображается перед именем игроков текущей команды |
|
|
||||||
* | | | Team Suffix | String (16) | Отображается после имени игроков текущей команды |
|
|
||||||
* | | | Friendly Flags | Byte | Битовая маска: |
|
|
||||||
* | | | | | 0x01 - разрешён friendly fire |
|
|
||||||
* | | | | | 0x02 - могут видеть невидимок своей команды |
|
|
||||||
* | | | Name Tag Visibility | String (32) | фиксированные значения: |
|
|
||||||
* | | | | | - always |
|
|
||||||
* | | | | | - hideForOtherTeams |
|
|
||||||
* | | | | | - hideForOwnTeam |
|
|
||||||
* | | | | | - never |
|
|
||||||
* | | | Collision Rule | String (32) | фиксированные значения: |
|
|
||||||
* | | | | | - always |
|
|
||||||
* | | | | | - pushOtherTeams |
|
|
||||||
* | | | | | - pushOwnTeam |
|
|
||||||
* | | | | | - never |
|
|
||||||
* | | | Color | Byte | For colors, the same Chat colors (0-15). |
|
|
||||||
* | | | | | -1 indicates RESET/no color. |
|
|
||||||
* | | | Entity Count | VarInt | Количество элементов в поле "Entities" |
|
|
||||||
* | | | Entities | Array of String (40) | Уникальные идентификаторы участников команды. |
|
|
||||||
* | | | | | Для Игроков - это Имена |
|
|
||||||
* | | | | | Для любых других сущностей - это UUID |
|
|
||||||
* | 1 | remove team | - | - | удаление текущей команды |
|
|
||||||
* | 2 | update team info | Team Display Name | String (32) | |
|
|
||||||
* | | | Team Prefix | String (16) | (см. выше) |
|
|
||||||
* | | | Team Suffix | String (16) | (см. выше) |
|
|
||||||
* | | | Friendly Flags | Byte | (см. выше) |
|
|
||||||
* | | | Name Tag Visibility | String (32) | (см. выше) |
|
|
||||||
* | | | Collision Rule | String (32) | (см. выше) |
|
|
||||||
* | | | Color | Byte | (см. выше) |
|
|
||||||
* | 3 | add players to team | Entity Count | VarInt | (см. выше) |
|
|
||||||
* | | | Entities | Array of String (40) | (см. выше) |
|
|
||||||
* | 4 | remove players from team | Entity Count | VarInt | (см. выше) |
|
|
||||||
* | | | Entities | Array of String (40) | (см. выше) |
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see <a href="https://wiki.vg/index.php?title=Protocol&oldid=14204#Teams" target="_top">Teams</a>
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class TeamsPacket implements ServerSidePacket {
|
|
||||||
|
|
||||||
private final List<String> members = new ArrayList<>();
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
private TeamsMode mode;
|
|
||||||
|
|
||||||
private String displayName;
|
|
||||||
private String prefix;
|
|
||||||
private String suffix;
|
|
||||||
private TeamsNameTagVisibility nameTagVisibility;
|
|
||||||
private TeamsCollisionRule collisionRule;
|
|
||||||
private int color;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
|
||||||
netByteBuf.writeString(this.name);
|
|
||||||
netByteBuf.writeByte(this.mode.getCode());
|
|
||||||
|
|
||||||
switch (this.mode) {
|
|
||||||
case CREATE:
|
|
||||||
netByteBuf.writeString(this.displayName);
|
|
||||||
netByteBuf.writeString(this.prefix);
|
|
||||||
netByteBuf.writeString(this.suffix);
|
|
||||||
netByteBuf.writeByte(0); // Friendly Flags
|
|
||||||
netByteBuf.writeString(this.nameTagVisibility.getCode());
|
|
||||||
netByteBuf.writeString(this.collisionRule.getCode());
|
|
||||||
netByteBuf.writeByte(this.color);
|
|
||||||
netByteBuf.writeVarInt(this.members.size());
|
|
||||||
this.members.forEach(netByteBuf::writeString);
|
|
||||||
break;
|
|
||||||
case UPDATE:
|
|
||||||
netByteBuf.writeString(this.displayName);
|
|
||||||
netByteBuf.writeString(this.prefix);
|
|
||||||
netByteBuf.writeString(this.suffix);
|
|
||||||
netByteBuf.writeByte(0); // Friendly Flags
|
|
||||||
netByteBuf.writeString(this.nameTagVisibility.getCode());
|
|
||||||
netByteBuf.writeString(this.collisionRule.getCode());
|
|
||||||
netByteBuf.writeByte(this.color);
|
|
||||||
break;
|
|
||||||
case ADD_MEMBER:
|
|
||||||
case REMOVE_MEMBER:
|
|
||||||
netByteBuf.writeVarInt(this.members.size());
|
|
||||||
this.members.forEach(netByteBuf::writeString);
|
|
||||||
break;
|
|
||||||
case REMOVE:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package mc.protocol.packets.status.client;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status server packet, request.
|
||||||
|
*
|
||||||
|
* <p>Клиент запрашивает получение информации о сервере</p>
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@ToString
|
||||||
|
public class StatusServerRequestPacket implements ClientSidePacket, ServerSidePacket {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
package mc.protocol.packets.server;
|
package mc.protocol.packets.status.server;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.model.ServerInfo;
|
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
import mc.protocol.serializer.ServerInfoSerializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status server packet, response.
|
* Status server packet, response.
|
||||||
@@ -52,10 +50,10 @@ public class StatusServerResponse implements ServerSidePacket {
|
|||||||
/**
|
/**
|
||||||
* Информация о серере.
|
* Информация о серере.
|
||||||
*/
|
*/
|
||||||
private ServerInfo info;
|
private String info;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
netByteBuf.writeString(ServerInfoSerializer.toJsonObject(info).toString());
|
netByteBuf.writeString(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package mc.protocol.pool;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.utils.pool.ObjectPool;
|
||||||
|
import mc.utils.pool.PassivablePooledObjectFactory;
|
||||||
|
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
public class NetByteBufObjectPool implements ObjectPool<NetByteBuf> {
|
||||||
|
|
||||||
|
private final org.apache.commons.pool2.ObjectPool apacheObjectPool;
|
||||||
|
|
||||||
|
NetByteBufObjectPool() {
|
||||||
|
this.apacheObjectPool = new GenericObjectPool<>(new PassivablePooledObjectFactory<>(PooledNetByteBuf.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetByteBuf borrowObject() {
|
||||||
|
return borrowObject(PooledByteBufAllocator.DEFAULT.directBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public NetByteBuf borrowObject(ByteBuf byteBuf) {
|
||||||
|
PooledNetByteBuf pooledNetByteBuf = (PooledNetByteBuf) apacheObjectPool.borrowObject();
|
||||||
|
pooledNetByteBuf.init(byteBuf);
|
||||||
|
return pooledNetByteBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public void returnObject(NetByteBuf netByteBuf) {
|
||||||
|
if (netByteBuf instanceof PooledNetByteBuf) {
|
||||||
|
apacheObjectPool.returnObject(netByteBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package mc.protocol.pool;
|
|
||||||
|
|
||||||
import mc.protocol.NettyConnectionContext;
|
|
||||||
import org.apache.commons.pool2.BasePooledObjectFactory;
|
|
||||||
import org.apache.commons.pool2.PooledObject;
|
|
||||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
|
||||||
|
|
||||||
public class NettyConnectionContextFactory extends BasePooledObjectFactory<NettyConnectionContext> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public NettyConnectionContext create() throws Exception {
|
|
||||||
return new NettyConnectionContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PooledObject<NettyConnectionContext> wrap(NettyConnectionContext context) {
|
|
||||||
return new DefaultPooledObject<>(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void passivateObject(PooledObject<NettyConnectionContext> pooledObj) {
|
|
||||||
pooledObj.getObject().passivate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package mc.protocol.pool;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
import org.apache.commons.pool2.BasePooledObjectFactory;
|
|
||||||
import org.apache.commons.pool2.PooledObject;
|
|
||||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PacketFactory<P extends ClientSidePacket> extends BasePooledObjectFactory<P> {
|
|
||||||
|
|
||||||
private final Class<P> clazz;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public P create() throws Exception {
|
|
||||||
return clazz.getDeclaredConstructor().newInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PooledObject<P> wrap(P packet) {
|
|
||||||
return new DefaultPooledObject<>(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void passivateObject(PooledObject<P> pooledPacket) {
|
|
||||||
pooledPacket.getObject().passivate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package mc.protocol.pool;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
|
||||||
import org.apache.commons.pool2.ObjectPool;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PacketPool {
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private final Map<Class<? extends ClientSidePacket>, ObjectPool> mapPoolPackets;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <P extends ClientSidePacket> P borrowObject(Class<P> packetClass) throws Exception {
|
|
||||||
return (P) mapPoolPackets.get(packetClass).borrowObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <P extends ClientSidePacket> void returnObject(P packet) throws Exception {
|
|
||||||
mapPoolPackets.get(packet.getClass()).returnObject(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package mc.protocol.pool;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.utils.pool.Passivable;
|
||||||
|
|
||||||
|
public class PooledNetByteBuf extends NetByteBuf implements Passivable {
|
||||||
|
|
||||||
|
void init(ByteBuf byteBuf) {
|
||||||
|
this.byteBuf = byteBuf.retain();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.byteBuf.release();
|
||||||
|
this.byteBuf = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package mc.protocol.pool;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import mc.protocol.model.ChunkSectionLocation;
|
||||||
|
import mc.protocol.model.Location;
|
||||||
|
import mc.protocol.model.Look;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.utils.pool.MultiObjectPool;
|
||||||
|
import mc.utils.pool.ObjectPool;
|
||||||
|
import mc.utils.pool.PassivableMultiObjectPool;
|
||||||
|
import mc.utils.pool.SimpleObjectPool;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class ProtocolObjectPool {
|
||||||
|
|
||||||
|
private static final ObjectPool<Location> LOCATION_POOL = new SimpleObjectPool<>(Location.class);
|
||||||
|
private static final ObjectPool<ChunkSectionLocation> CHUNK_SECTION_LOCATION_POOL = new SimpleObjectPool<>(ChunkSectionLocation.class);
|
||||||
|
private static final ObjectPool<Look> LOOK_POOL = new SimpleObjectPool<>(Look.class);
|
||||||
|
private static final NetByteBufObjectPool NETBYTEBUF_POOL = new NetByteBufObjectPool();
|
||||||
|
private static final MultiObjectPool<ClientSidePacket> PACKET_POOL = new PassivableMultiObjectPool<>();
|
||||||
|
|
||||||
|
public static ObjectPool<Location> location() {
|
||||||
|
return LOCATION_POOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectPool<ChunkSectionLocation> chunkSectionLocation() {
|
||||||
|
return CHUNK_SECTION_LOCATION_POOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectPool<Look> look() {
|
||||||
|
return LOOK_POOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetByteBufObjectPool netByteBuf() {
|
||||||
|
return NETBYTEBUF_POOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MultiObjectPool<ClientSidePacket> packet() {
|
||||||
|
return PACKET_POOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package mc.protocol.pool;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
|
||||||
|
public class UnpooledNetByteBuf extends NetByteBuf {
|
||||||
|
|
||||||
|
public UnpooledNetByteBuf(ByteBuf byteBuf) {
|
||||||
|
this.byteBuf = byteBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,10 +11,10 @@ public enum ChatMode {
|
|||||||
public static ChatMode valueById(int id) {
|
public static ChatMode valueById(int id) {
|
||||||
// а зачем усложнять?
|
// а зачем усложнять?
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
if (id == 1) return FULL;
|
if (id == 1) return FULL;
|
||||||
else if (id == 2) return COMMANDS_ONLY;
|
else if (id == 2) return COMMANDS_ONLY;
|
||||||
else if (id == 3) return HIDDEN;
|
else if (id == 3) return HIDDEN;
|
||||||
else return null;
|
else return null;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
32
protocol/src/main/java/mc/protocol/utils/DiggingStatus.java
Normal file
32
protocol/src/main/java/mc/protocol/utils/DiggingStatus.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package mc.protocol.utils;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum DiggingStatus {
|
||||||
|
|
||||||
|
STARTED(0),
|
||||||
|
CANCELLED(1),
|
||||||
|
FINISHED(2),
|
||||||
|
DROP_ITEM_STACK(3),
|
||||||
|
DROP_ITEM(4),
|
||||||
|
HELT_UPDATE_STATE(5),
|
||||||
|
SWAP_HAND(6);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static DiggingStatus valueById(int id) {
|
||||||
|
for (DiggingStatus diggingStatus : DiggingStatus.values()) {
|
||||||
|
if (diggingStatus.getId() == id) {
|
||||||
|
return diggingStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int id;
|
||||||
|
}
|
||||||
31
protocol/src/main/java/mc/protocol/utils/Face.java
Normal file
31
protocol/src/main/java/mc/protocol/utils/Face.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package mc.protocol.utils;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum Face {
|
||||||
|
|
||||||
|
BOTTOM(0),
|
||||||
|
TOP(1),
|
||||||
|
NORTH(2),
|
||||||
|
SOUTH(3),
|
||||||
|
WEST(4),
|
||||||
|
EAST(5);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Face valueById(int id) {
|
||||||
|
for (Face face : Face.values()) {
|
||||||
|
if (face.getId() == id) {
|
||||||
|
return face;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int id;
|
||||||
|
}
|
||||||
@@ -2,17 +2,17 @@ package mc.protocol.utils;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public enum MainHand {
|
public enum Hand {
|
||||||
LEFT,
|
LEFT,
|
||||||
RIGHT;
|
RIGHT;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static MainHand valueById(int id) {
|
public static Hand valueById(int id) {
|
||||||
// а зачем усложнять?
|
// а зачем усложнять?
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
if (id == 0) return LEFT;
|
if (id == 0) return LEFT;
|
||||||
else if (id == 1) return RIGHT;
|
else if (id == 1) return RIGHT;
|
||||||
else return null;
|
else return null;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
52
protocol/src/main/java/mc/protocol/utils/LocationUtils.java
Normal file
52
protocol/src/main/java/mc/protocol/utils/LocationUtils.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package mc.protocol.utils;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import mc.protocol.model.BlockLocation;
|
||||||
|
import mc.protocol.model.ChunkSectionLocation;
|
||||||
|
import mc.protocol.model.Location;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class LocationUtils {
|
||||||
|
|
||||||
|
//region Unpooled
|
||||||
|
public static ChunkSectionLocation location2chunk(Location location) {
|
||||||
|
var chunkSectionLocation = new ChunkSectionLocation();
|
||||||
|
chunkSectionLocation.set(
|
||||||
|
(int) location.getX() >> 4,
|
||||||
|
(int) location.getY() >> 4,
|
||||||
|
(int) location.getZ() >> 4);
|
||||||
|
return chunkSectionLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChunkSectionLocation location2chunk(BlockLocation blockLocation) {
|
||||||
|
var chunkSectionLocation = new ChunkSectionLocation();
|
||||||
|
chunkSectionLocation.set(
|
||||||
|
blockLocation.getX() >> 4,
|
||||||
|
blockLocation.getY() >> 4,
|
||||||
|
blockLocation.getZ() >> 4);
|
||||||
|
return chunkSectionLocation;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Pooled
|
||||||
|
public static ChunkSectionLocation location2chunkPooled(Location location) {
|
||||||
|
ChunkSectionLocation chunkSectionLocation = ProtocolObjectPool.chunkSectionLocation().borrowObject();
|
||||||
|
chunkSectionLocation.set(
|
||||||
|
(int) location.getX() >> 4,
|
||||||
|
(int) location.getY() >> 4,
|
||||||
|
(int) location.getZ() >> 4);
|
||||||
|
return chunkSectionLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChunkSectionLocation location2chunkPooled(BlockLocation blockLocation) {
|
||||||
|
ChunkSectionLocation chunkSectionLocation = ProtocolObjectPool.chunkSectionLocation().borrowObject();
|
||||||
|
chunkSectionLocation.set(
|
||||||
|
blockLocation.getX() >> 4,
|
||||||
|
blockLocation.getY() >> 4,
|
||||||
|
blockLocation.getZ() >> 4);
|
||||||
|
return chunkSectionLocation;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package mc.protocol.utils;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public enum ScoreboardObjectiveMode {
|
|
||||||
CREATE(0),
|
|
||||||
REMOVE(1),
|
|
||||||
UPDATE(2);
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final int code;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package mc.protocol.utils;
|
|
||||||
|
|
||||||
public enum ScoreboardObjectiveType {
|
|
||||||
INTEGER,
|
|
||||||
HEARTS
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package mc.protocol.utils;
|
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class ScoreboardPosition {
|
|
||||||
public final int LIST = 0;
|
|
||||||
public final int SIDEBAR = 1;
|
|
||||||
public final int BELOW_NAME = 2;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package mc.protocol.utils;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public enum ScoreboardUpdateScoreAction {
|
|
||||||
CREATE_OR_UPDATE(0),
|
|
||||||
REMOVE(1);
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final int code;
|
|
||||||
}
|
|
||||||
77
protocol/src/main/java/mc/protocol/utils/SerializeUtil.java
Normal file
77
protocol/src/main/java/mc/protocol/utils/SerializeUtil.java
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package mc.protocol.utils;
|
||||||
|
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
|
import mc.protocol.model.BlockLocation;
|
||||||
|
import mc.protocol.pool.ProtocolObjectPool;
|
||||||
|
import mc.protocol.world.Block;
|
||||||
|
import mc.protocol.world.ChunkSection;
|
||||||
|
import mc.utils.array.BitArray;
|
||||||
|
import mc.utils.array.BitByteArray;
|
||||||
|
import mc.utils.array.BitLongArray;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public final class SerializeUtil {
|
||||||
|
|
||||||
|
private static final int BITS_PER_BLOCK = 13;
|
||||||
|
private static final int ALL_BLOCKS = 16 * 16 * 16;
|
||||||
|
|
||||||
|
public static NetByteBuf serializeChunkSection(ChunkSection section) {
|
||||||
|
BitArray blockArray = new BitLongArray(BITS_PER_BLOCK, ALL_BLOCKS);
|
||||||
|
BitArray blockLight = new BitByteArray(4, ALL_BLOCKS);
|
||||||
|
BitArray skyLight = new BitByteArray(4, ALL_BLOCKS);
|
||||||
|
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
Block block = section.getBlock(x, y, z);
|
||||||
|
int blockState = blockIdMetaSerialize(block.getId(), block.getMeta());
|
||||||
|
|
||||||
|
blockArray.put(blockState);
|
||||||
|
blockLight.put(block.getLight());
|
||||||
|
skyLight.put(section.getSkyLight(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetByteBuf result = ProtocolObjectPool.netByteBuf().borrowObject(Unpooled.buffer());
|
||||||
|
result.writeUnsignedByte(BITS_PER_BLOCK); // Bits Per Block
|
||||||
|
result.writeVarInt(0); // Palette, Direct mode
|
||||||
|
result.writeVarInt(blockArray.size()); // Data Array Length
|
||||||
|
result.writeBytes(blockArray.byteBuffer()); // Data Array
|
||||||
|
result.writeBytes(blockLight.byteBuffer()); // Block Light
|
||||||
|
result.writeBytes(skyLight.byteBuffer()); // Sky Light
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int blockIdMetaSerialize(int id, int meta) {
|
||||||
|
return (id << 4) | meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] blockIdMetaDeserialize(int blockState) {
|
||||||
|
return new int[]{
|
||||||
|
blockState >> 4,
|
||||||
|
blockState & 0b1111
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long location2long(BlockLocation blockLocation) {
|
||||||
|
return ((long) (blockLocation.getX() & 0x3FFFFFF) << 38)
|
||||||
|
| ((long) (blockLocation.getZ() & 0x3FFFFFF) << 12)
|
||||||
|
| (blockLocation.getY() & 0xFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockLocation long2location(long value) {
|
||||||
|
BlockLocation blockLocation = new BlockLocation();
|
||||||
|
blockLocation.set(
|
||||||
|
(int) (value >> 38),
|
||||||
|
(int) (value & 0xFFF),
|
||||||
|
(int) (value << 26 >> 38)
|
||||||
|
);
|
||||||
|
|
||||||
|
return blockLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package mc.protocol.utils;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public enum TeamsCollisionRule {
|
|
||||||
ALWAYS("always"),
|
|
||||||
PUSH_OTHER_TEAMS("pushOtherTeams"),
|
|
||||||
PUSH_OWN_TEAM("pushOwnTeam"),
|
|
||||||
NEVER("never");
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final String code;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package mc.protocol.utils;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public enum TeamsMode {
|
|
||||||
CREATE(0),
|
|
||||||
REMOVE(1),
|
|
||||||
UPDATE(2),
|
|
||||||
ADD_MEMBER(3),
|
|
||||||
REMOVE_MEMBER(4);
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final int code;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package mc.protocol.utils;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public enum TeamsNameTagVisibility {
|
|
||||||
ALWAYS("always"),
|
|
||||||
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
|
|
||||||
HIDE_FOR_OWN_TEAM("hideForOwnTeam"),
|
|
||||||
NEVER("never");
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final String code;
|
|
||||||
}
|
|
||||||
14
protocol/src/main/java/mc/protocol/world/Block.java
Normal file
14
protocol/src/main/java/mc/protocol/world/Block.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package mc.protocol.world;
|
||||||
|
|
||||||
|
import mc.protocol.model.BlockLocation;
|
||||||
|
|
||||||
|
public interface Block {
|
||||||
|
|
||||||
|
int getId();
|
||||||
|
int getMeta();
|
||||||
|
|
||||||
|
BlockLocation getLocation();
|
||||||
|
|
||||||
|
int getLight();
|
||||||
|
void setLight(int value);
|
||||||
|
}
|
||||||
10
protocol/src/main/java/mc/protocol/world/Chunk.java
Normal file
10
protocol/src/main/java/mc/protocol/world/Chunk.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package mc.protocol.world;
|
||||||
|
|
||||||
|
public interface Chunk {
|
||||||
|
|
||||||
|
int getX();
|
||||||
|
int getZ();
|
||||||
|
|
||||||
|
ChunkSection getSection(int height);
|
||||||
|
byte getBiome(int x, int z);
|
||||||
|
}
|
||||||
14
protocol/src/main/java/mc/protocol/world/ChunkSection.java
Normal file
14
protocol/src/main/java/mc/protocol/world/ChunkSection.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package mc.protocol.world;
|
||||||
|
|
||||||
|
import mc.protocol.model.BlockLocation;
|
||||||
|
|
||||||
|
public interface ChunkSection {
|
||||||
|
|
||||||
|
int getY();
|
||||||
|
|
||||||
|
Block getBlock(int x, int y, int z);
|
||||||
|
Block getBlock(BlockLocation blockLocation);
|
||||||
|
|
||||||
|
int getSkyLight(int x, int y, int z);
|
||||||
|
int getSkyLight(BlockLocation blockLocation);
|
||||||
|
}
|
||||||
15
protocol/src/main/java/mc/protocol/world/World.java
Normal file
15
protocol/src/main/java/mc/protocol/world/World.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package mc.protocol.world;
|
||||||
|
|
||||||
|
import mc.protocol.model.ChunkSectionLocation;
|
||||||
|
import mc.protocol.model.Location;
|
||||||
|
import mc.protocol.utils.LevelType;
|
||||||
|
|
||||||
|
public interface World {
|
||||||
|
|
||||||
|
LevelType getLevelType();
|
||||||
|
|
||||||
|
Location getSpawn();
|
||||||
|
|
||||||
|
Chunk getChunk(int x, int z);
|
||||||
|
Chunk getChunk(ChunkSectionLocation chunkSectionLocation);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user