Archived
0

Раздробили обработчики на каждый State

This commit is contained in:
2018-06-23 15:42:02 +03:00
parent 9b763961bf
commit 9507914fd9
13 changed files with 324 additions and 152 deletions

View File

@@ -18,6 +18,7 @@ import mc.core.network.Server;
import mc.core.network.StartServerException; import mc.core.network.StartServerException;
import mc.core.network.proto_1_12_2.State; import mc.core.network.proto_1_12_2.State;
import mc.core.network.proto_1_12_2.packets.StatusResponsePacket; import mc.core.network.proto_1_12_2.packets.StatusResponsePacket;
import mc.core.player.Player;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@@ -25,7 +26,8 @@ import java.util.Map;
@Slf4j @Slf4j
public class NettyServer implements Server { public class NettyServer implements Server {
static final AttributeKey<State> ATTR_STATE = AttributeKey.newInstance("ATTR_STATE"); public static final AttributeKey<State> ATTR_STATE = AttributeKey.newInstance("ATTR_STATE");
public static final AttributeKey<Player> ATTR_PLAYER = AttributeKey.newInstance("ATTR_PLAYER");
@Autowired @Autowired
private ApplicationContext applicationContext; private ApplicationContext applicationContext;

View File

@@ -4,59 +4,55 @@
*/ */
package mc.core.network.proto_1_12_2.netty; package mc.core.network.proto_1_12_2.netty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import mc.core.Config;
import mc.core.chat.ChatProcessor; import mc.core.chat.ChatProcessor;
import mc.core.network.CSPacket; import mc.core.network.CSPacket;
import mc.core.network.proto_1_12_2.State; import mc.core.network.proto_1_12_2.State;
import mc.core.network.proto_1_12_2.packets.*; import mc.core.network.proto_1_12_2.netty.handlers.*;
import mc.core.player.Look;
import mc.core.player.Player; import mc.core.player.Player;
import mc.core.player.PlayerManager; import mc.core.player.PlayerManager;
import mc.core.player.PlayerMode;
import mc.core.text.Text;
import mc.core.text.TextColor;
import mc.core.world.World;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.lang.reflect.Method; import java.util.Collection;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_PLAYER;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE; import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE;
@Slf4j @Slf4j
@ComponentScan("mc.core.network.proto_1_12_2.netty.handlers")
public class PacketHandler extends SimpleChannelInboundHandler<CSPacket> { public class PacketHandler extends SimpleChannelInboundHandler<CSPacket> {
private static final AttributeKey<Player> ATTR_PLAYER = AttributeKey.newInstance("ATTR_PLAYER");
@Autowired @Autowired
private Config config; private ApplicationContext applicationContext;
@Autowired @Autowired
private PlayerManager playerManager; private PlayerManager playerManager;
@Autowired @Autowired
private World world;
@Autowired
private ChatProcessor chatProcessor; private ChatProcessor chatProcessor;
private ImmutableMap<Class<? /*extends CSPacket*/>, Method> methods = ImmutableMap.of(); private ImmutableMap<State, ImmutableList<StateHandler>> handlersMap = ImmutableMap.of();
@PostConstruct @PostConstruct
public void init() { public void init() {
this.methods = Stream.of(this.getClass().getDeclaredMethods()) ImmutableMap.Builder<State, ImmutableList<StateHandler>> builder = ImmutableMap.builder();
.filter(method -> method.isAnnotationPresent(PacketListener.class)
&& method.getParameterCount() == 2 Collection<HandshakeStateHandler> beans1 = applicationContext.getBeansOfType(HandshakeStateHandler.class).values();
&& method.getParameterTypes()[0].isAssignableFrom(Channel.class) builder.put(State.HANDSHAKE, ImmutableList.copyOf(beans1));
&& CSPacket.class.isAssignableFrom(method.getParameterTypes()[1]))
.collect(ImmutableMap.toImmutableMap( Collection<StatusStateHandler> beans2 = applicationContext.getBeansOfType(StatusStateHandler.class).values();
method -> method.getParameterTypes()[1], builder.put(State.STATUS, ImmutableList.copyOf(beans2));
Function.identity()));
Collection<LoginStateHandler> beans3 = applicationContext.getBeansOfType(LoginStateHandler.class).values();
builder.put(State.LOGIN, ImmutableList.copyOf(beans3));
Collection<PlayStateHandler> beans4 = applicationContext.getBeansOfType(PlayStateHandler.class).values();
builder.put(State.PLAY, ImmutableList.copyOf(beans4));
this.handlersMap = builder.build();
} }
@Override @Override
@@ -72,114 +68,9 @@ public class PacketHandler extends SimpleChannelInboundHandler<CSPacket> {
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, CSPacket packet) throws Exception { protected void channelRead0(ChannelHandlerContext ctx, CSPacket packet) throws Exception {
if (this.methods.containsKey(packet.getClass())) { ImmutableList<StateHandler> stateHandlers = this.handlersMap.get(ctx.channel().attr(ATTR_STATE).get());
this.methods.get(packet.getClass()).invoke(this, ctx.channel(), packet); for (StateHandler handler : stateHandlers) {
} else { handler.handle(ctx.channel(), packet);
log.trace("No def listener of \"{}\"", packet.getClass().getSimpleName());
} }
} }
@PacketListener
private void onHandshake(Channel channel, HandshakePacket packet) {
if (packet.getNextState().equals(State.UNKNOWN)) return;
//FIXME обрати внимание: хацкер может намеренно передать state:03 и тогда может начатся пиздец
log.debug("New state: {}", packet.getNextState());
channel.attr(ATTR_STATE).set(packet.getNextState());
}
@PacketListener
private void onStatusRequest(Channel channel, StatusRequestPacket packet) {
if (!channel.attr(ATTR_STATE).get().equals(State.STATUS)) return;
StatusResponsePacket responsePacket = new StatusResponsePacket();
responsePacket.setMaxOnline(config.getMaxPlayers());
responsePacket.setDescription(config.getDescriptionServer());
responsePacket.setFaviconBase64(config.getFaviconBase64());
responsePacket.setOnline(playerManager.getCountOnlinePlayers());
channel.writeAndFlush(responsePacket);
}
@PacketListener
private void onPing(Channel channel, PingPacket packet) {
if (!channel.attr(ATTR_STATE).get().equals(State.STATUS)) return;
channel.writeAndFlush(packet);
}
@PacketListener
private void onLoginStart(Channel channel, LoginStartPacket packet) {
if (!channel.attr(ATTR_STATE).get().equals(State.LOGIN)) return;
Optional<Player> optPlayer = playerManager.getPlayer(packet.getPlayerName());
if (optPlayer.isPresent() && optPlayer.get().isOnline()) {
channel.writeAndFlush(new DisconnectPacket(
Text.builder("Player \"")
.append(Text.of(packet.getPlayerName(), TextColor.YELLOW))
.append(Text.of("\" is online", TextColor.WHITE))
.build()))
.addListener(ChannelFutureListener.CLOSE);
} else {
Player player = playerManager.getPlayer(packet.getPlayerName())
.orElseGet(() -> playerManager.createPlayer(
packet.getPlayerName(),
world.getSpawn(),
new Look(0f, 0f)));
channel.writeAndFlush(new LoginSuccessPacket(
player.getUUID(),
packet.getPlayerName()));
channel.attr(ATTR_PLAYER).set(player);
channel.attr(ATTR_STATE).set(State.PLAY);
// Join Game
JoinGamePacket pkt1 = new JoinGamePacket();
pkt1.setEntityId(player.getId());
pkt1.setMode(PlayerMode.CREATIVE);
pkt1.setDimension(0/*Overworld*/);
pkt1.setDifficulty(0/*Peaceful*/);
pkt1.setLevelType("flat");
channel.write(pkt1);
// Spawn Position
SpawnPositionPacket pkt2 = new SpawnPositionPacket();
pkt2.setLocation(world.getSpawn());
channel.write(pkt2);
// Player Abilities
PlayerAbilitiesPacket pkt3 = new PlayerAbilitiesPacket();
pkt3.setCanFly(true);
pkt3.setFlying(true);
pkt3.setGodMode(true);
pkt3.setInstantDestroyBlocks(true);
channel.write(pkt2);
channel.flush();
// Player Position And Look
PlayerPositionAndLookPacket pkt4 = new PlayerPositionAndLookPacket();
pkt4.setLocation(player.getLocation());
pkt4.setLook(player.getLook());
channel.writeAndFlush(pkt4);
}
}
@PacketListener
private void onClientSettings(Channel channel, ClientSettingsPacket packet) {
if (!channel.attr(ATTR_STATE).get().equals(State.PLAY)) return;
Player player = channel.attr(ATTR_PLAYER).get();
player.getSettings().setLocate(packet.getLocale());
player.getSettings().setViewDistance(packet.getViewDistance());
player.getSettings().setChatMode(packet.getChatMode());
player.getSettings().setChatColors(packet.isChatColors());
player.getSettings().setCapeEnabled(packet.isCapeEnabled());
player.getSettings().setJacketEnabled(packet.isJacketEnabled());
player.getSettings().setLeftSleeveEnabled(packet.isLeftSleeveEnabled());
player.getSettings().setRightSleeveEnabled(packet.isRightSleeveEnabled());
player.getSettings().setLeftPantsLegEnabled(packet.isLeftPantsLegEnabled());
player.getSettings().setRightPantsLegEnabled(packet.isRightPantsLegEnabled());
player.getSettings().setHatEnabled(packet.isHatEnabled());
player.getSettings().setMainHand(packet.getMainHand());
}
} }

View File

@@ -1,15 +0,0 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-16
*/
package mc.core.network.proto_1_12_2.netty;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PacketListener {
}

View File

@@ -0,0 +1,54 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
import com.google.common.collect.ImmutableMap;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import mc.core.network.CSPacket;
import javax.annotation.PostConstruct;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.function.Function;
import java.util.stream.Stream;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE;
@Slf4j
public abstract class AbstractStateHandler implements StateHandler {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
protected @interface Handler {
}
private ImmutableMap<Class<? /*extends CSPacket*/>, Method> methods = ImmutableMap.of();
@PostConstruct
protected void init() {
this.methods = Stream.of(this.getClass().getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(Handler.class)
&& method.getParameterCount() == 2
&& method.getParameterTypes()[0].isAssignableFrom(Channel.class)
&& CSPacket.class.isAssignableFrom(method.getParameterTypes()[1]))
.collect(ImmutableMap.toImmutableMap(
method -> method.getParameterTypes()[1],
Function.identity()));
}
@Override
public void handle(Channel channel, CSPacket packet) throws Exception {
if (this.methods.containsKey(packet.getClass())) {
this.methods.get(packet.getClass()).invoke(this, channel, packet);
} else {
log.trace("No def listener of {}:{}",
channel.attr(ATTR_STATE).get(),
packet.getClass().getSimpleName());
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import mc.core.network.proto_1_12_2.State;
import mc.core.network.proto_1_12_2.packets.HandshakePacket;
import org.springframework.stereotype.Component;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE;
@Slf4j
@Component
public class HandshakeHandler extends AbstractStateHandler implements HandshakeStateHandler {
@Handler
public void onHandshake(Channel channel, HandshakePacket packet) {
if (packet.getNextState().equals(State.UNKNOWN)) return;
//FIXME обрати внимание: хацкер может намеренно передать state:03 и тогда может начатся пиздец
log.debug("New state: {}", packet.getNextState());
channel.attr(ATTR_STATE).set(packet.getNextState());
}
}

View File

@@ -0,0 +1,11 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
/**
* Marker interface
*/
public interface HandshakeStateHandler extends StateHandler {
}

View File

@@ -0,0 +1,86 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import mc.core.network.proto_1_12_2.State;
import mc.core.network.proto_1_12_2.packets.*;
import mc.core.player.Look;
import mc.core.player.Player;
import mc.core.player.PlayerManager;
import mc.core.player.PlayerMode;
import mc.core.text.Text;
import mc.core.text.TextColor;
import mc.core.world.World;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_PLAYER;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_STATE;
@Component
public class LoginHandler extends AbstractStateHandler implements LoginStateHandler {
@Autowired
private PlayerManager playerManager;
@Autowired
private World world;
@Handler
public void onLoginStart(Channel channel, LoginStartPacket packet) {
Optional<Player> optPlayer = playerManager.getPlayer(packet.getPlayerName());
if (optPlayer.isPresent() && optPlayer.get().isOnline()) {
channel.writeAndFlush(new DisconnectPacket(
Text.builder("Player \"")
.append(Text.of(packet.getPlayerName(), TextColor.YELLOW))
.append(Text.of("\" is online", TextColor.WHITE))
.build()))
.addListener(ChannelFutureListener.CLOSE);
} else {
Player player = playerManager.getPlayer(packet.getPlayerName())
.orElseGet(() -> playerManager.createPlayer(
packet.getPlayerName(),
world.getSpawn(),
new Look(0f, 0f)));
channel.writeAndFlush(new LoginSuccessPacket(
player.getUUID(),
packet.getPlayerName()));
channel.attr(ATTR_PLAYER).set(player);
channel.attr(ATTR_STATE).set(State.PLAY);
// Join Game
JoinGamePacket pkt1 = new JoinGamePacket();
pkt1.setEntityId(player.getId());
pkt1.setMode(PlayerMode.CREATIVE);
pkt1.setDimension(0/*Overworld*/);
pkt1.setDifficulty(0/*Peaceful*/);
pkt1.setLevelType("flat");
channel.write(pkt1);
// Spawn Position
SpawnPositionPacket pkt2 = new SpawnPositionPacket();
pkt2.setLocation(world.getSpawn());
channel.write(pkt2);
// Player Abilities
PlayerAbilitiesPacket pkt3 = new PlayerAbilitiesPacket();
pkt3.setCanFly(true);
pkt3.setFlying(true);
pkt3.setGodMode(true);
pkt3.setInstantDestroyBlocks(true);
channel.write(pkt2);
channel.flush();
// Player Position And Look
PlayerPositionAndLookPacket pkt4 = new PlayerPositionAndLookPacket();
pkt4.setLocation(player.getLocation());
pkt4.setLook(player.getLook());
channel.writeAndFlush(pkt4);
}
}
}

View File

@@ -0,0 +1,11 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
/**
* Marker interface
*/
public interface LoginStateHandler extends StateHandler {
}

View File

@@ -0,0 +1,35 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
import io.netty.channel.Channel;
import mc.core.network.proto_1_12_2.packets.ClientSettingsPacket;
import mc.core.player.Player;
import org.springframework.stereotype.Component;
import static mc.core.network.proto_1_12_2.netty.NettyServer.ATTR_PLAYER;
@Component
public class PlayHandler extends AbstractStateHandler implements PlayStateHandler {
@Handler
public void onClientSettings(Channel channel, ClientSettingsPacket packet) {
Player player = channel.attr(ATTR_PLAYER).get();
player.getSettings().setLocate(packet.getLocale());
player.getSettings().setViewDistance(packet.getViewDistance());
player.getSettings().setChatMode(packet.getChatMode());
player.getSettings().setChatColors(packet.isChatColors());
player.getSettings().setCapeEnabled(packet.isCapeEnabled());
player.getSettings().setJacketEnabled(packet.isJacketEnabled());
player.getSettings().setLeftSleeveEnabled(packet.isLeftSleeveEnabled());
player.getSettings().setRightSleeveEnabled(packet.isRightSleeveEnabled());
player.getSettings().setLeftPantsLegEnabled(packet.isLeftPantsLegEnabled());
player.getSettings().setRightPantsLegEnabled(packet.isRightPantsLegEnabled());
player.getSettings().setHatEnabled(packet.isHatEnabled());
player.getSettings().setMainHand(packet.getMainHand());
}
}

View File

@@ -0,0 +1,11 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
/**
* Marker interface
*/
public interface PlayStateHandler extends StateHandler {
}

View File

@@ -0,0 +1,12 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
import io.netty.channel.Channel;
import mc.core.network.CSPacket;
public interface StateHandler {
void handle(Channel channel, CSPacket packet) throws Exception;
}

View File

@@ -0,0 +1,38 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
import io.netty.channel.Channel;
import mc.core.Config;
import mc.core.network.proto_1_12_2.packets.PingPacket;
import mc.core.network.proto_1_12_2.packets.StatusRequestPacket;
import mc.core.network.proto_1_12_2.packets.StatusResponsePacket;
import mc.core.player.PlayerManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class StatusHandler extends AbstractStateHandler implements StatusStateHandler {
@Autowired
private Config config;
@Autowired
private PlayerManager playerManager;
@Handler
public void onStatusRequest(Channel channel, StatusRequestPacket packet) {
StatusResponsePacket responsePacket = new StatusResponsePacket();
responsePacket.setMaxOnline(config.getMaxPlayers());
responsePacket.setDescription(config.getDescriptionServer());
responsePacket.setFaviconBase64(config.getFaviconBase64());
responsePacket.setOnline(playerManager.getCountOnlinePlayers());
channel.writeAndFlush(responsePacket);
}
@Handler
public void onPing(Channel channel, PingPacket packet) {
channel.writeAndFlush(packet);
}
}

View File

@@ -0,0 +1,11 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-06-23
*/
package mc.core.network.proto_1_12_2.netty.handlers;
/**
* Marker interface
*/
public interface StatusStateHandler extends StateHandler {
}