Commit fa9d703d authored by BaiSugar's avatar BaiSugar Committed by GitHub
Browse files

Merge branch 'Grasscutters:development' into development

parents 6a5d97a3 d1fc8c1f
package emu.grasscutter.game; package emu.grasscutter.game.world;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
...@@ -8,19 +8,20 @@ import java.util.LinkedList; ...@@ -8,19 +8,20 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import emu.grasscutter.game.entity.GenshinEntity; import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.Player.SceneLoadState;
import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.ClimateType;
import emu.grasscutter.game.props.EnterReason; import emu.grasscutter.game.props.EnterReason;
import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.LifeState;
import emu.grasscutter.data.GenshinData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.SceneData; import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.game.GenshinPlayer.SceneLoadState;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.EntityClientGadget; import emu.grasscutter.game.entity.EntityClientGadget;
import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.net.packet.GenshinPacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
...@@ -40,10 +41,10 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; ...@@ -40,10 +41,10 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class World implements Iterable<GenshinPlayer> { public class World implements Iterable<Player> {
private final GenshinPlayer owner; private final Player owner;
private final List<GenshinPlayer> players; private final List<Player> players;
private final Int2ObjectMap<GenshinScene> scenes; private final Int2ObjectMap<Scene> scenes;
private int levelEntityId; private int levelEntityId;
private int nextEntityId = 0; private int nextEntityId = 0;
...@@ -52,11 +53,11 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -52,11 +53,11 @@ public class World implements Iterable<GenshinPlayer> {
private boolean isMultiplayer; private boolean isMultiplayer;
public World(GenshinPlayer player) { public World(Player player) {
this(player, false); this(player, false);
} }
public World(GenshinPlayer player, boolean isMultiplayer) { public World(Player player, boolean isMultiplayer) {
this.owner = player; this.owner = player;
this.players = Collections.synchronizedList(new ArrayList<>()); this.players = Collections.synchronizedList(new ArrayList<>());
this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
...@@ -68,7 +69,7 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -68,7 +69,7 @@ public class World implements Iterable<GenshinPlayer> {
this.owner.getServer().registerWorld(this); this.owner.getServer().registerWorld(this);
} }
public GenshinPlayer getHost() { public Player getHost() {
return owner; return owner;
} }
...@@ -95,25 +96,25 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -95,25 +96,25 @@ public class World implements Iterable<GenshinPlayer> {
this.worldLevel = worldLevel; this.worldLevel = worldLevel;
} }
public List<GenshinPlayer> getPlayers() { public List<Player> getPlayers() {
return players; return players;
} }
public Int2ObjectMap<GenshinScene> getScenes() { public Int2ObjectMap<Scene> getScenes() {
return this.scenes; return this.scenes;
} }
public GenshinScene getSceneById(int sceneId) { public Scene getSceneById(int sceneId) {
// Get scene normally // Get scene normally
GenshinScene scene = getScenes().get(sceneId); Scene scene = getScenes().get(sceneId);
if (scene != null) { if (scene != null) {
return scene; return scene;
} }
// Create scene from scene data if it doesnt exist // Create scene from scene data if it doesnt exist
SceneData sceneData = GenshinData.getSceneDataMap().get(sceneId); SceneData sceneData = GameData.getSceneDataMap().get(sceneId);
if (sceneData != null) { if (sceneData != null) {
scene = new GenshinScene(this, sceneData); scene = new Scene(this, sceneData);
this.registerScene(scene); this.registerScene(scene);
return scene; return scene;
} }
...@@ -133,7 +134,7 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -133,7 +134,7 @@ public class World implements Iterable<GenshinPlayer> {
return (idType.getId() << 24) + ++this.nextEntityId; return (idType.getId() << 24) + ++this.nextEntityId;
} }
public synchronized void addPlayer(GenshinPlayer player) { public synchronized void addPlayer(Player player) {
// Check if player already in // Check if player already in
if (getPlayers().contains(player)) { if (getPlayers().contains(player)) {
return; return;
...@@ -159,7 +160,7 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -159,7 +160,7 @@ public class World implements Iterable<GenshinPlayer> {
} }
// Add to scene // Add to scene
GenshinScene scene = this.getSceneById(player.getSceneId()); Scene scene = this.getSceneById(player.getSceneId());
scene.addPlayer(player); scene.addPlayer(player);
// Info packet for other players // Info packet for other players
...@@ -168,7 +169,7 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -168,7 +169,7 @@ public class World implements Iterable<GenshinPlayer> {
} }
} }
public synchronized void removePlayer(GenshinPlayer player) { public synchronized void removePlayer(Player player) {
// Remove team entities // Remove team entities
player.sendPacket( player.sendPacket(
new PacketDelTeamEntityNotify( new PacketDelTeamEntityNotify(
...@@ -182,7 +183,7 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -182,7 +183,7 @@ public class World implements Iterable<GenshinPlayer> {
player.setWorld(null); player.setWorld(null);
// Remove from scene // Remove from scene
GenshinScene scene = this.getSceneById(player.getSceneId()); Scene scene = this.getSceneById(player.getSceneId());
scene.removePlayer(player); scene.removePlayer(player);
// Info packet for other players // Info packet for other players
...@@ -192,8 +193,8 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -192,8 +193,8 @@ public class World implements Iterable<GenshinPlayer> {
// Disband world if host leaves // Disband world if host leaves
if (getHost() == player) { if (getHost() == player) {
List<GenshinPlayer> kicked = new ArrayList<>(this.getPlayers()); List<Player> kicked = new ArrayList<>(this.getPlayers());
for (GenshinPlayer victim : kicked) { for (Player victim : kicked) {
World world = new World(victim); World world = new World(victim);
world.addPlayer(victim); world.addPlayer(victim);
...@@ -202,20 +203,20 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -202,20 +203,20 @@ public class World implements Iterable<GenshinPlayer> {
} }
} }
public void registerScene(GenshinScene scene) { public void registerScene(Scene scene) {
this.getScenes().put(scene.getId(), scene); this.getScenes().put(scene.getId(), scene);
} }
public void deregisterScene(GenshinScene scene) { public void deregisterScene(Scene scene) {
this.getScenes().remove(scene.getId()); this.getScenes().remove(scene.getId());
} }
public boolean transferPlayerToScene(GenshinPlayer player, int sceneId, Position pos) { public boolean transferPlayerToScene(Player player, int sceneId, Position pos) {
if (GenshinData.getSceneDataMap().get(sceneId) == null) { if (GameData.getSceneDataMap().get(sceneId) == null) {
return false; return false;
} }
GenshinScene oldScene = null; Scene oldScene = null;
if (player.getScene() != null) { if (player.getScene() != null) {
oldScene = player.getScene(); oldScene = player.getScene();
...@@ -228,7 +229,7 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -228,7 +229,7 @@ public class World implements Iterable<GenshinPlayer> {
oldScene.removePlayer(player); oldScene.removePlayer(player);
} }
GenshinScene newScene = this.getSceneById(sceneId); Scene newScene = this.getSceneById(sceneId);
newScene.addPlayer(player); newScene.addPlayer(player);
player.getPos().set(pos); player.getPos().set(pos);
...@@ -245,8 +246,8 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -245,8 +246,8 @@ public class World implements Iterable<GenshinPlayer> {
return true; return true;
} }
private void updatePlayerInfos(GenshinPlayer paramPlayer) { private void updatePlayerInfos(Player paramPlayer) {
for (GenshinPlayer player : getPlayers()) { for (Player player : getPlayers()) {
// Dont send packets if player is loading in and filter out joining player // Dont send packets if player is loading in and filter out joining player
if (!player.hasSentAvatarDataNotify() || player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() || player == paramPlayer) { if (!player.hasSentAvatarDataNotify() || player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() || player == paramPlayer) {
continue; continue;
...@@ -269,15 +270,15 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -269,15 +270,15 @@ public class World implements Iterable<GenshinPlayer> {
} }
} }
public void broadcastPacket(GenshinPacket packet) { public void broadcastPacket(BasePacket packet) {
// Send to all players - might have to check if player has been sent data packets // Send to all players - might have to check if player has been sent data packets
for (GenshinPlayer player : this.getPlayers()) { for (Player player : this.getPlayers()) {
player.getSession().send(packet); player.getSession().send(packet);
} }
} }
public void onTick() { public void onTick() {
for (GenshinScene scene : this.getScenes().values()) { for (Scene scene : this.getScenes().values()) {
scene.onTick(); scene.onTick();
} }
} }
...@@ -287,7 +288,7 @@ public class World implements Iterable<GenshinPlayer> { ...@@ -287,7 +288,7 @@ public class World implements Iterable<GenshinPlayer> {
} }
@Override @Override
public Iterator<GenshinPlayer> iterator() { public Iterator<Player> iterator() {
return getPlayers().iterator(); return getPlayers().iterator();
} }
} }
...@@ -7,7 +7,7 @@ import com.google.protobuf.GeneratedMessageV3; ...@@ -7,7 +7,7 @@ import com.google.protobuf.GeneratedMessageV3;
import emu.grasscutter.net.proto.PacketHeadOuterClass.PacketHead; import emu.grasscutter.net.proto.PacketHeadOuterClass.PacketHead;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
public class GenshinPacket { public class BasePacket {
private static final int const1 = 17767; // 0x4567 private static final int const1 = 17767; // 0x4567
private static final int const2 = -30293; // 0x89ab private static final int const2 = -30293; // 0x89ab
...@@ -21,16 +21,16 @@ public class GenshinPacket { ...@@ -21,16 +21,16 @@ public class GenshinPacket {
private boolean useDispatchKey; private boolean useDispatchKey;
public boolean shouldEncrypt = true; public boolean shouldEncrypt = true;
public GenshinPacket(int opcode) { public BasePacket(int opcode) {
this.opcode = opcode; this.opcode = opcode;
} }
public GenshinPacket(int opcode, int clientSequence) { public BasePacket(int opcode, int clientSequence) {
this.opcode = opcode; this.opcode = opcode;
this.buildHeader(clientSequence); this.buildHeader(clientSequence);
} }
public GenshinPacket(int opcode, boolean buildHeader) { public BasePacket(int opcode, boolean buildHeader) {
this.opcode = opcode; this.opcode = opcode;
this.shouldBuildHeader = buildHeader; this.shouldBuildHeader = buildHeader;
} }
...@@ -80,7 +80,7 @@ public class GenshinPacket { ...@@ -80,7 +80,7 @@ public class GenshinPacket {
this.data = proto.build().toByteArray(); this.data = proto.build().toByteArray();
} }
public GenshinPacket buildHeader(int clientSequence) { public BasePacket buildHeader(int clientSequence) {
if (this.getHeader() != null && clientSequence == 0) { if (this.getHeader() != null && clientSequence == 0) {
return this; return this;
} }
......
...@@ -8,7 +8,7 @@ import io.netty.buffer.Unpooled; ...@@ -8,7 +8,7 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
public abstract class MihoyoKcpChannel extends ChannelInboundHandlerAdapter { public abstract class KcpChannel extends ChannelInboundHandlerAdapter {
private UkcpChannel kcpChannel; private UkcpChannel kcpChannel;
private ChannelHandlerContext ctx; private ChannelHandlerContext ctx;
private boolean isActive; private boolean isActive;
......
...@@ -10,9 +10,9 @@ import io.netty.channel.ChannelMetadata; ...@@ -10,9 +10,9 @@ import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelOutboundBuffer; import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.nio.AbstractNioMessageChannel; import io.netty.channel.nio.AbstractNioMessageChannel;
public class MihoyoKcpHandshaker extends AbstractNioMessageChannel { public class KcpHandshaker extends AbstractNioMessageChannel {
protected MihoyoKcpHandshaker(Channel parent, SelectableChannel ch, int readInterestOp) { protected KcpHandshaker(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent, ch, readInterestOp); super(parent, ch, readInterestOp);
} }
......
...@@ -13,14 +13,14 @@ import io.netty.channel.EventLoopGroup; ...@@ -13,14 +13,14 @@ import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public class MihoyoKcpServer extends Thread { public class KcpServer extends Thread {
private EventLoopGroup group; private EventLoopGroup group;
private UkcpServerBootstrap bootstrap; private UkcpServerBootstrap bootstrap;
private ChannelInitializer serverInitializer; private ChannelInitializer serverInitializer;
private InetSocketAddress address; private InetSocketAddress address;
public MihoyoKcpServer(InetSocketAddress address) { public KcpServer(InetSocketAddress address) {
this.address = address; this.address = address;
this.setName("Netty Server Thread"); this.setName("Netty Server Thread");
} }
...@@ -40,7 +40,7 @@ public class MihoyoKcpServer extends Thread { ...@@ -40,7 +40,7 @@ public class MihoyoKcpServer extends Thread {
@Override @Override
public void run() { public void run() {
if (getServerInitializer() == null) { if (getServerInitializer() == null) {
this.setServerInitializer(new MihoyoKcpServerInitializer()); this.setServerInitializer(new KcpServerInitializer());
} }
try { try {
......
...@@ -5,7 +5,7 @@ import io.netty.channel.ChannelInitializer; ...@@ -5,7 +5,7 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class MihoyoKcpServerInitializer extends ChannelInitializer<UkcpChannel> { public class KcpServerInitializer extends ChannelInitializer<UkcpChannel> {
@Override @Override
protected void initChannel(UkcpChannel ch) throws Exception { protected void initChannel(UkcpChannel ch) throws Exception {
......
package emu.grasscutter.plugin.api; package emu.grasscutter.plugin.api;
import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.EnterReason; import emu.grasscutter.game.props.EnterReason;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.net.packet.GenshinPacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify; import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
...@@ -13,16 +13,16 @@ import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify; ...@@ -13,16 +13,16 @@ import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
/** /**
* Hooks into the {@link GenshinPlayer} class, adding convenient ways to do certain things. * Hooks into the {@link Player} class, adding convenient ways to do certain things.
*/ */
public final class PlayerHook { public final class PlayerHook {
private final GenshinPlayer player; private final Player player;
/** /**
* Hooks into the player. * Hooks into the player.
* @param player The player to hook into. * @param player The player to hook into.
*/ */
public PlayerHook(GenshinPlayer player) { public PlayerHook(Player player) {
this.player = player; this.player = player;
} }
...@@ -53,7 +53,7 @@ public final class PlayerHook { ...@@ -53,7 +53,7 @@ public final class PlayerHook {
* Broadcasts the packet sent to all world players. * Broadcasts the packet sent to all world players.
* @param packet The packet to send. * @param packet The packet to send.
*/ */
public void broadcastPacketToWorld(GenshinPacket packet) { public void broadcastPacketToWorld(BasePacket packet) {
this.player.getWorld().broadcastPacket(packet); this.player.getWorld().broadcastPacket(packet);
} }
...@@ -70,7 +70,7 @@ public final class PlayerHook { ...@@ -70,7 +70,7 @@ public final class PlayerHook {
* Revives the specified avatar. * Revives the specified avatar.
* @param avatar The avatar to revive. * @param avatar The avatar to revive.
*/ */
public void reviveAvatar(GenshinAvatar avatar) { public void reviveAvatar(Avatar avatar) {
this.broadcastPacketToWorld(new PacketAvatarLifeStateChangeNotify(avatar)); this.broadcastPacketToWorld(new PacketAvatarLifeStateChangeNotify(avatar));
} }
...@@ -105,9 +105,9 @@ public final class PlayerHook { ...@@ -105,9 +105,9 @@ public final class PlayerHook {
/** /**
* Gets the currently selected avatar. * Gets the currently selected avatar.
* @return The avatar as an {@link GenshinAvatar}. * @return The avatar as an {@link Avatar}.
*/ */
public GenshinAvatar getCurrentAvatar() { public Avatar getCurrentAvatar() {
return this.getCurrentAvatarEntity().getAvatar(); return this.getCurrentAvatarEntity().getAvatar();
} }
} }
\ No newline at end of file
package emu.grasscutter.plugin.api; package emu.grasscutter.plugin.api;
import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import java.util.LinkedList; import java.util.LinkedList;
...@@ -35,7 +35,7 @@ public final class ServerHook { ...@@ -35,7 +35,7 @@ public final class ServerHook {
* Gets all online players. * Gets all online players.
* @return Players connected to the server. * @return Players connected to the server.
*/ */
public List<GenshinPlayer> getOnlinePlayers() { public List<Player> getOnlinePlayers() {
return new LinkedList<>(this.server.getPlayers().values()); return new LinkedList<>(this.server.getPlayers().values());
} }
} }
\ No newline at end of file
...@@ -55,9 +55,14 @@ public final class DispatchServer { ...@@ -55,9 +55,14 @@ public final class DispatchServer {
this.initRegion(); this.initRegion();
} }
@Deprecated
public HttpServer getServer() { public HttpServer getServer() {
return server; return server;
} }
public HttpServer getHttpServer() {
return server;
}
public InetSocketAddress getAddress() { public InetSocketAddress getAddress() {
return address; return address;
...@@ -203,56 +208,65 @@ public final class DispatchServer { ...@@ -203,56 +208,65 @@ public final class DispatchServer {
} }
return null; return null;
} }
private KeyManagerFactory createKeyManagerFactory(File keystore, String password) throws Exception {
char[] pass = password.toCharArray();
KeyManagerFactory kmf = null;
try (FileInputStream fis = new FileInputStream(keystore)) {
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(fis, pass);
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, pass);
} catch (Exception e) {
throw e;
}
return kmf;
}
public void start() throws Exception { public void start() throws Exception {
if (Grasscutter.getConfig().getDispatchOptions().UseSSL) { if (Grasscutter.getConfig().getDispatchOptions().UseSSL) {
HttpsServer httpsServer = HttpsServer.create(getAddress(), 0); // Keystore
SSLContext sslContext = SSLContext.getInstance("TLS"); SSLContext sslContext = SSLContext.getInstance("TLS");
try (FileInputStream fis = new FileInputStream(Grasscutter.getConfig().getDispatchOptions().KeystorePath)) { KeyManagerFactory kmf = null;
char[] keystorePassword = Grasscutter.getConfig().getDispatchOptions().KeystorePassword.toCharArray(); File keystoreFile = new File(Grasscutter.getConfig().getDispatchOptions().KeystorePath);
KeyManagerFactory _kmf;
if (keystoreFile.exists()) {
try { try {
KeyStore ks = KeyStore.getInstance("PKCS12"); kmf = createKeyManagerFactory(keystoreFile, Grasscutter.getConfig().getDispatchOptions().KeystorePassword);
ks.load(fis, keystorePassword); } catch (Exception e) {
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); Grasscutter.getLogger().warn("[Dispatch] Unable to load keystore. Trying default keystore password...");
_kmf = kmf;
kmf.init(ks, keystorePassword);
} catch (Exception originalEx) {
try { try {
// try to initialize kmf with the default password kmf = createKeyManagerFactory(keystoreFile, "123456");
char[] defaultPassword = "123456".toCharArray();
Grasscutter.getLogger()
.warn("[Dispatch] Unable to load keystore. Trying default keystore password...");
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(fis, defaultPassword);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, defaultPassword);
_kmf = kmf;
Grasscutter.getLogger().warn( Grasscutter.getLogger().warn(
"[Dispatch] The default keystore password was loaded successfully. Please consider setting the password in config.json."); "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json.");
} catch (Exception ignored) { } catch (Exception e2) {
Grasscutter.getLogger().warn("[Dispatch] Error while loading keystore!"); Grasscutter.getLogger().warn("[Dispatch] Error while loading keystore!");
e2.printStackTrace();
// don't care about the exception for the "123456" default password attempt
originalEx.printStackTrace();
throw originalEx;
} }
} }
}
sslContext.init(_kmf.getKeyManagers(), null, null);
if (kmf == null) {
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
server = httpsServer;
} catch (BindException ignored) {
Grasscutter.getLogger().error("Unable to bind to port: " + getAddress().getPort() + " (HTTPS)");
server = this.safelyCreateServer(this.getAddress());
} catch (Exception e) {
Grasscutter.getLogger().warn("[Dispatch] No SSL cert found! Falling back to HTTP server."); Grasscutter.getLogger().warn("[Dispatch] No SSL cert found! Falling back to HTTP server.");
Grasscutter.getConfig().getDispatchOptions().UseSSL = false; Grasscutter.getConfig().getDispatchOptions().UseSSL = false;
server = this.safelyCreateServer(this.getAddress()); server = this.safelyCreateServer(this.getAddress());
} }
HttpsServer httpsServer = null;
try {
httpsServer = HttpsServer.create(getAddress(), 0);
sslContext.init(kmf.getKeyManagers(), null, null);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
server = httpsServer;
} catch (BindException e) {
Grasscutter.getLogger().error("Unable to bind to port: " + getAddress().getPort() + " (HTTPS)");
}
} else { } else {
server = this.safelyCreateServer(this.getAddress()); server = this.safelyCreateServer(this.getAddress());
} }
......
package emu.grasscutter.server.event.game; package emu.grasscutter.server.event.game;
import emu.grasscutter.net.packet.GenshinPacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.server.event.Cancellable; import emu.grasscutter.server.event.Cancellable;
import emu.grasscutter.server.event.ServerEvent; import emu.grasscutter.server.event.ServerEvent;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
public final class SendPacketEvent extends ServerEvent implements Cancellable { public final class SendPacketEvent extends ServerEvent implements Cancellable {
private final GameSession gameSession; private final GameSession gameSession;
private GenshinPacket packet; private BasePacket packet;
public SendPacketEvent(GameSession gameSession, GenshinPacket packet) { public SendPacketEvent(GameSession gameSession, BasePacket packet) {
super(Type.GAME); super(Type.GAME);
this.gameSession = gameSession; this.gameSession = gameSession;
...@@ -20,11 +20,11 @@ public final class SendPacketEvent extends ServerEvent implements Cancellable { ...@@ -20,11 +20,11 @@ public final class SendPacketEvent extends ServerEvent implements Cancellable {
return this.gameSession; return this.gameSession;
} }
public void setPacket(GenshinPacket packet) { public void setPacket(BasePacket packet) {
this.packet = packet; this.packet = packet;
} }
public GenshinPacket getPacket() { public BasePacket getPacket() {
return this.packet; return this.packet;
} }
} }
...@@ -5,33 +5,33 @@ import java.time.OffsetDateTime; ...@@ -5,33 +5,33 @@ import java.time.OffsetDateTime;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import emu.grasscutter.GenshinConstants; import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.CommandMap; import emu.grasscutter.command.CommandMap;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.World;
import emu.grasscutter.game.dungeons.DungeonManager; import emu.grasscutter.game.dungeons.DungeonManager;
import emu.grasscutter.game.gacha.GachaManager; import emu.grasscutter.game.gacha.GachaManager;
import emu.grasscutter.game.managers.ChatManager; import emu.grasscutter.game.managers.ChatManager;
import emu.grasscutter.game.managers.InventoryManager; import emu.grasscutter.game.managers.InventoryManager;
import emu.grasscutter.game.managers.MultiplayerManager; import emu.grasscutter.game.managers.MultiplayerManager;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.shop.ShopManager; import emu.grasscutter.game.shop.ShopManager;
import emu.grasscutter.game.world.World;
import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
import emu.grasscutter.netty.MihoyoKcpServer; import emu.grasscutter.netty.KcpServer;
import emu.grasscutter.server.event.ServerEvent; import emu.grasscutter.server.event.ServerEvent;
import emu.grasscutter.server.event.game.ServerTickEvent; import emu.grasscutter.server.event.game.ServerTickEvent;
import emu.grasscutter.server.event.internal.ServerStartEvent; import emu.grasscutter.server.event.internal.ServerStartEvent;
import emu.grasscutter.server.event.internal.ServerStopEvent; import emu.grasscutter.server.event.internal.ServerStopEvent;
import emu.grasscutter.task.TaskMap; import emu.grasscutter.task.TaskMap;
public final class GameServer extends MihoyoKcpServer { public final class GameServer extends KcpServer {
private final InetSocketAddress address; private final InetSocketAddress address;
private final GameServerPacketHandler packetHandler; private final GameServerPacketHandler packetHandler;
private final Map<Integer, GenshinPlayer> players; private final Map<Integer, Player> players;
private final Set<World> worlds; private final Set<World> worlds;
private final ChatManager chatManager; private final ChatManager chatManager;
...@@ -82,7 +82,7 @@ public final class GameServer extends MihoyoKcpServer { ...@@ -82,7 +82,7 @@ public final class GameServer extends MihoyoKcpServer {
return packetHandler; return packetHandler;
} }
public Map<Integer, GenshinPlayer> getPlayers() { public Map<Integer, Player> getPlayers() {
return players; return players;
} }
...@@ -122,22 +122,22 @@ public final class GameServer extends MihoyoKcpServer { ...@@ -122,22 +122,22 @@ public final class GameServer extends MihoyoKcpServer {
return this.taskMap; return this.taskMap;
} }
public void registerPlayer(GenshinPlayer player) { public void registerPlayer(Player player) {
getPlayers().put(player.getUid(), player); getPlayers().put(player.getUid(), player);
} }
public GenshinPlayer getPlayerByUid(int id) { public Player getPlayerByUid(int id) {
return this.getPlayerByUid(id, false); return this.getPlayerByUid(id, false);
} }
public GenshinPlayer getPlayerByUid(int id, boolean allowOfflinePlayers) { public Player getPlayerByUid(int id, boolean allowOfflinePlayers) {
// Console check // Console check
if (id == GenshinConstants.SERVER_CONSOLE_UID) { if (id == GameConstants.SERVER_CONSOLE_UID) {
return null; return null;
} }
// Get from online players // Get from online players
GenshinPlayer player = this.getPlayers().get(id); Player player = this.getPlayers().get(id);
if (!allowOfflinePlayers) { if (!allowOfflinePlayers) {
return player; return player;
...@@ -153,7 +153,7 @@ public final class GameServer extends MihoyoKcpServer { ...@@ -153,7 +153,7 @@ public final class GameServer extends MihoyoKcpServer {
public SocialDetail.Builder getSocialDetailByUid(int id) { public SocialDetail.Builder getSocialDetailByUid(int id) {
// Get from online players // Get from online players
GenshinPlayer player = this.getPlayerByUid(id, true); Player player = this.getPlayerByUid(id, true);
if (player == null) { if (player == null) {
return null; return null;
...@@ -163,7 +163,7 @@ public final class GameServer extends MihoyoKcpServer { ...@@ -163,7 +163,7 @@ public final class GameServer extends MihoyoKcpServer {
} }
public Account getAccountByName(String username) { public Account getAccountByName(String username) {
Optional<GenshinPlayer> playerOpt = getPlayers().values().stream().filter(player -> player.getAccount().getUsername().equals(username)).findFirst(); Optional<Player> playerOpt = getPlayers().values().stream().filter(player -> player.getAccount().getUsername().equals(username)).findFirst();
if (playerOpt.isPresent()) { if (playerOpt.isPresent()) {
return playerOpt.get().getAccount(); return playerOpt.get().getAccount();
} }
...@@ -204,10 +204,10 @@ public final class GameServer extends MihoyoKcpServer { ...@@ -204,10 +204,10 @@ public final class GameServer extends MihoyoKcpServer {
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call(); ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call();
// Kick and save all players // Kick and save all players
List<GenshinPlayer> list = new ArrayList<>(this.getPlayers().size()); List<Player> list = new ArrayList<>(this.getPlayers().size());
list.addAll(this.getPlayers().values()); list.addAll(this.getPlayers().values());
for (GenshinPlayer player : list) { for (Player player : list) {
player.getSession().close(); player.getSession().close();
} }
} }
......
package emu.grasscutter.server.game; package emu.grasscutter.server.game;
import emu.grasscutter.netty.MihoyoKcpServerInitializer; import emu.grasscutter.netty.KcpServerInitializer;
import io.jpower.kcp.netty.UkcpChannel; import io.jpower.kcp.netty.UkcpChannel;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
public class GameServerInitializer extends MihoyoKcpServerInitializer { public class GameServerInitializer extends KcpServerInitializer {
private GameServer server; private GameServer server;
public GameServerInitializer(GameServer server) { public GameServerInitializer(GameServer server) {
......
...@@ -8,11 +8,11 @@ import java.util.Set; ...@@ -8,11 +8,11 @@ import java.util.Set;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.GenshinPacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.packet.PacketOpcodesUtil; import emu.grasscutter.net.packet.PacketOpcodesUtil;
import emu.grasscutter.netty.MihoyoKcpChannel; import emu.grasscutter.netty.KcpChannel;
import emu.grasscutter.server.event.game.SendPacketEvent; import emu.grasscutter.server.event.game.SendPacketEvent;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.FileUtils;
...@@ -21,11 +21,11 @@ import io.netty.buffer.ByteBuf; ...@@ -21,11 +21,11 @@ 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;
public class GameSession extends MihoyoKcpChannel { public class GameSession extends KcpChannel {
private GameServer server; private GameServer server;
private Account account; private Account account;
private GenshinPlayer player; private Player player;
private boolean useSecretKey; private boolean useSecretKey;
private SessionState state; private SessionState state;
...@@ -67,11 +67,11 @@ public class GameSession extends MihoyoKcpChannel { ...@@ -67,11 +67,11 @@ public class GameSession extends MihoyoKcpChannel {
return this.getAccount().getId(); return this.getAccount().getId();
} }
public GenshinPlayer getPlayer() { public Player getPlayer() {
return player; return player;
} }
public synchronized void setPlayer(GenshinPlayer player) { public synchronized void setPlayer(Player player) {
this.player = player; this.player = player;
this.player.setSession(this); this.player.setSession(this);
this.player.setAccount(this.getAccount()); this.player.setAccount(this.getAccount());
...@@ -144,43 +144,35 @@ public class GameSession extends MihoyoKcpChannel { ...@@ -144,43 +144,35 @@ public class GameSession extends MihoyoKcpChannel {
byte[] packet = FileUtils.read(p); byte[] packet = FileUtils.read(p);
GenshinPacket genshinPacket = new GenshinPacket(opcode); BasePacket basePacket = new BasePacket(opcode);
genshinPacket.setData(packet); basePacket.setData(packet);
// Log send(basePacket);
logPacket(genshinPacket.getOpcode());
send(genshinPacket);
} }
public void send(GenshinPacket genshinPacket) { public void send(BasePacket packet) {
// Test // Test
if (genshinPacket.getOpcode() <= 0) { if (packet.getOpcode() <= 0) {
Grasscutter.getLogger().warn("Tried to send packet with missing cmd id!"); Grasscutter.getLogger().warn("Tried to send packet with missing cmd id!");
return; return;
} }
// Header // Header
if (genshinPacket.shouldBuildHeader()) { if (packet.shouldBuildHeader()) {
genshinPacket.buildHeader(this.getNextClientSequence()); packet.buildHeader(this.getNextClientSequence());
} }
// Log // Log
if (Grasscutter.getConfig().getGameServerOptions().LOG_PACKETS) { if (Grasscutter.getConfig().getGameServerOptions().LOG_PACKETS) {
logPacket(genshinPacket); logPacket(packet);
} }
// Invoke event. // Invoke event.
SendPacketEvent event = new SendPacketEvent(this, genshinPacket); event.call(); SendPacketEvent event = new SendPacketEvent(this, packet); event.call();
if(!event.isCanceled()) // If event is not cancelled, continue. if(!event.isCanceled()) // If event is not cancelled, continue.
this.send(event.getPacket().build()); this.send(event.getPacket().build());
} }
private void logPacket(int opcode) {
//Grasscutter.getLogger().info("SEND: " + PacketOpcodesUtil.getOpcodeName(opcode));
//System.out.println(Utils.bytesToHex(genshinPacket.getData()));
}
private static final Set<Integer> loopPacket = Set.of( private static final Set<Integer> loopPacket = Set.of(
PacketOpcodes.PingReq, PacketOpcodes.PingReq,
PacketOpcodes.PingRsp, PacketOpcodes.PingRsp,
...@@ -189,10 +181,10 @@ public class GameSession extends MihoyoKcpChannel { ...@@ -189,10 +181,10 @@ public class GameSession extends MihoyoKcpChannel {
PacketOpcodes.QueryPathReq PacketOpcodes.QueryPathReq
); );
private void logPacket(GenshinPacket genshinPacket) { private void logPacket(BasePacket packet) {
if (!loopPacket.contains(genshinPacket.getOpcode())) { if (!loopPacket.contains(packet.getOpcode())) {
Grasscutter.getLogger().info("SEND: " + PacketOpcodesUtil.getOpcodeName(genshinPacket.getOpcode()) + " (" + genshinPacket.getOpcode() + ")"); Grasscutter.getLogger().info("SEND: " + PacketOpcodesUtil.getOpcodeName(packet.getOpcode()) + " (" + packet.getOpcode() + ")");
System.out.println(Utils.bytesToHex(genshinPacket.getData())); System.out.println(Utils.bytesToHex(packet.getData()));
} }
} }
......
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GenshinData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.RewardData; import emu.grasscutter.data.def.RewardData;
import emu.grasscutter.game.avatar.GenshinAvatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.inventory.GenshinItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
...@@ -27,14 +27,14 @@ public class HandlerAvatarFetterLevelRewardReq extends PacketHandler { ...@@ -27,14 +27,14 @@ public class HandlerAvatarFetterLevelRewardReq extends PacketHandler {
} else { } else {
long avatarGuid = req.getAvatarGuid(); long avatarGuid = req.getAvatarGuid();
GenshinAvatar avatar = session Avatar avatar = session
.getPlayer() .getPlayer()
.getAvatars() .getAvatars()
.getAvatarByGuid(avatarGuid); .getAvatarByGuid(avatarGuid);
int rewardId = avatar.getNameCardRewardId(); int rewardId = avatar.getNameCardRewardId();
RewardData card = GenshinData.getRewardDataMap().get(rewardId); RewardData card = GameData.getRewardDataMap().get(rewardId);
int cardId = card.getRewardItemList().get(0).getItemId(); int cardId = card.getRewardItemList().get(0).getItemId();
if (session.getPlayer().getNameCardList().contains(cardId)) { if (session.getPlayer().getNameCardList().contains(cardId)) {
...@@ -43,9 +43,8 @@ public class HandlerAvatarFetterLevelRewardReq extends PacketHandler { ...@@ -43,9 +43,8 @@ public class HandlerAvatarFetterLevelRewardReq extends PacketHandler {
return; return;
} }
GenshinItem item = new GenshinItem(cardId); GameItem item = new GameItem(cardId);
session.getPlayer().getInventory().addItem(item); session.getPlayer().getInventory().addItem(item, ActionReason.FetterLevelReward);
session.getPlayer().sendPacket(new PacketItemAddHintNotify(item, ActionReason.FetterLevelReward));
session.getPlayer().sendPacket(new PacketUnlockNameCardNotify(cardId)); session.getPlayer().sendPacket(new PacketUnlockNameCardNotify(cardId));
session.send(new PacketAvatarFetterDataNotify(avatar)); session.send(new PacketAvatarFetterDataNotify(avatar));
session.send(new PacketAvatarDataNotify(avatar.getPlayer())); session.send(new PacketAvatarDataNotify(avatar.getPlayer()));
......
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.ChangeMailStarNotifyOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketMailChangeNotify;
import java.util.ArrayList;
import java.util.List;
@Opcodes(PacketOpcodes.ChangeMailStarNotify)
public class HandlerChangeMailStarNotify extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
ChangeMailStarNotifyOuterClass.ChangeMailStarNotify req = ChangeMailStarNotifyOuterClass.ChangeMailStarNotify.parseFrom(payload);
List<Mail> updatedMail = new ArrayList<>();
for (int mailId : req.getMailIdListList()) {
Mail message = session.getPlayer().getMail(mailId);
message.importance = req.getIsStar() == true ? 1 : 0;
session.getPlayer().replaceMailByIndex(mailId, message);
updatedMail.add(message);
}
session.send(new PacketMailChangeNotify(session.getPlayer(), updatedMail));
}
}
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.entity.GenshinEntity; import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify; import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify;
...@@ -27,7 +27,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { ...@@ -27,7 +27,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
case ENTITY_MOVE: case ENTITY_MOVE:
// Handle movement // Handle movement
EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData()); EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData());
GenshinEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId()); GameEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId());
if (entity != null) { if (entity != null) {
entity.getPosition().set(moveInfo.getMotionInfo().getPos()); entity.getPosition().set(moveInfo.getMotionInfo().getPos());
entity.getRotation().set(moveInfo.getMotionInfo().getRot()); entity.getRotation().set(moveInfo.getMotionInfo().getRot());
......
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.DelMailReqOuterClass;
import emu.grasscutter.net.proto.DeleteFriendReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketDelMailRsp;
@Opcodes(PacketOpcodes.DelMailReq)
public class HandlerDelMailReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
DelMailReqOuterClass.DelMailReq req = DelMailReqOuterClass.DelMailReq.parseFrom(payload);
session.send(new PacketDelMailRsp(session.getPlayer(), req.getMailIdListList()));
}
}
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.GenshinPlayer.SceneLoadState; import emu.grasscutter.game.player.Player.SceneLoadState;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketHandler;
......
...@@ -8,7 +8,7 @@ import emu.grasscutter.server.game.GameSession; ...@@ -8,7 +8,7 @@ import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketEvtAvatarSitDownNotify; import emu.grasscutter.server.packet.send.PacketEvtAvatarSitDownNotify;
@Opcodes(PacketOpcodes.EvtAvatarSitDownNotify) @Opcodes(PacketOpcodes.EvtAvatarSitDownNotify)
public class HandleEvtAvatarSitDownNotify extends PacketHandler { public class HandlerEvtAvatarSitDownNotify extends PacketHandler {
@Override @Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
......
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.proto.GetAllMailReqOuterClass;
import emu.grasscutter.net.proto.GetPlayerTokenReqOuterClass;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketGetAllMailRsp;
import emu.grasscutter.server.packet.send.PacketGetGachaInfoRsp;
@Opcodes(PacketOpcodes.GetAllMailReq)
public class HandlerGetAllMailReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
GetAllMailReqOuterClass.GetAllMailReq req = GetAllMailReqOuterClass.GetAllMailReq.parseFrom(payload);
session.send(new PacketGetAllMailRsp(session.getPlayer(), req.getIsGiftMail()));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment