mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-18 09:54:59 +01:00
Fix unable to save game data occasionally (#1194)
* Fix unable to save game data occasionally * No self-kicking * Game data synchronization * finally * prevent duplicated saving * reverse changing * keep the previous code * Update GameServerInitializer.java * Update GameSession.java * remove sanity check because of try block * a session needs can be created without a pipeline.
This commit is contained in:
@@ -13,8 +13,10 @@ public class GameServerInitializer extends KcpServerInitializer {
|
||||
|
||||
@Override
|
||||
protected void initChannel(UkcpChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
GameSession session = new GameSession(server);
|
||||
pipeline.addLast(session);
|
||||
ChannelPipeline pipeline=null;
|
||||
if(ch!=null){
|
||||
pipeline = ch.pipeline();
|
||||
}
|
||||
new GameSession(server,pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package emu.grasscutter.server.game;
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
@@ -17,9 +19,11 @@ import emu.grasscutter.server.event.game.SendPacketEvent;
|
||||
import emu.grasscutter.utils.Crypto;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import io.jpower.kcp.netty.UkcpChannel;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
@@ -36,11 +40,30 @@ public class GameSession extends KcpChannel {
|
||||
private int clientTime;
|
||||
private long lastPingTime;
|
||||
private int lastClientSeq = 10;
|
||||
|
||||
|
||||
private final ChannelPipeline pipeline;
|
||||
@Override
|
||||
public void close() {
|
||||
setState(SessionState.INACTIVE);
|
||||
//send disconnection pack in case of reconnection
|
||||
try {
|
||||
send(new BasePacket(PacketOpcodes.ServerDisconnectClientNotify));
|
||||
}catch (Throwable ignore){
|
||||
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
public GameSession(GameServer server) {
|
||||
this(server,null);
|
||||
}
|
||||
public GameSession(GameServer server, ChannelPipeline pipeline) {
|
||||
this.server = server;
|
||||
this.state = SessionState.WAITING_FOR_TOKEN;
|
||||
this.lastPingTime = System.currentTimeMillis();
|
||||
this.pipeline = pipeline;
|
||||
if(pipeline!=null) {
|
||||
pipeline.addLast(this);
|
||||
}
|
||||
}
|
||||
|
||||
public GameServer getServer() {
|
||||
@@ -124,13 +147,17 @@ public class GameSession extends KcpChannel {
|
||||
|
||||
// Set state so no more packets can be handled
|
||||
this.setState(SessionState.INACTIVE);
|
||||
|
||||
|
||||
// Save after disconnecting
|
||||
if (this.isLoggedIn()) {
|
||||
Player player = getPlayer();
|
||||
// Call logout event.
|
||||
getPlayer().onLogout();
|
||||
// Remove from server.
|
||||
getServer().getPlayers().remove(getPlayer().getUid());
|
||||
player.onLogout();
|
||||
}
|
||||
try {
|
||||
pipeline.remove(this);
|
||||
} catch (Throwable ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GetPlayerTokenReqOuterClass.GetPlayerTokenReq;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.server.event.game.PlayerCreationEvent;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.game.GameSession.SessionState;
|
||||
import emu.grasscutter.server.packet.send.PacketGetPlayerTokenRsp;
|
||||
@@ -20,28 +21,45 @@ public class HandlerGetPlayerTokenReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
// Max players limit
|
||||
if (ACCOUNT.maxPlayer > -1 && Grasscutter.getGameServer().getPlayers().size() >= ACCOUNT.maxPlayer) {
|
||||
session.close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
GetPlayerTokenReq req = GetPlayerTokenReq.parseFrom(payload);
|
||||
|
||||
// Authenticate
|
||||
Account account = DatabaseHelper.getAccountById(req.getAccountUid());
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check token
|
||||
if (!account.getToken().equals(req.getAccountToken())) {
|
||||
if (account == null || !account.getToken().equals(req.getAccountToken())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set account
|
||||
session.setAccount(account);
|
||||
|
||||
|
||||
|
||||
// Check if player object exists in server
|
||||
// NOTE: CHECKING MUST SITUATED HERE (BEFORE getPlayerByUid)! because to save firstly ,to load secondly !!!
|
||||
// TODO - optimize
|
||||
boolean kicked = false;
|
||||
Player exists = Grasscutter.getGameServer().getPlayerByAccountId(account.getId());
|
||||
if (exists != null) {
|
||||
GameSession existsSession = exists.getSession();
|
||||
if (existsSession != session) {// No self-kicking
|
||||
exists.onLogout();//must save immediately , or the below will load old data
|
||||
existsSession.close();
|
||||
Grasscutter.getLogger().warn("Player {} was kicked due to duplicated login", account.getUsername());
|
||||
kicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: If there are 5 online players, max count of player is 5,
|
||||
// a new client want to login by kicking one of them ,
|
||||
// I think it should be allowed
|
||||
if(!kicked) {
|
||||
// Max players limit
|
||||
if (ACCOUNT.maxPlayer > -1 && Grasscutter.getGameServer().getPlayers().size() >= ACCOUNT.maxPlayer) {
|
||||
session.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get player
|
||||
Player player = DatabaseHelper.getPlayerByAccount(account);
|
||||
|
||||
@@ -57,10 +75,10 @@ public class HandlerGetPlayerTokenReq extends PacketHandler {
|
||||
// Save to db
|
||||
DatabaseHelper.generatePlayerUid(player, nextPlayerUid);
|
||||
}
|
||||
|
||||
|
||||
// Set player object for session
|
||||
session.setPlayer(player);
|
||||
|
||||
|
||||
// Load player from database
|
||||
player.loadFromDatabase();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.inventory.InventoryTab;
|
||||
@@ -45,6 +46,7 @@ public class HandlerQuickUseWidgetReq extends PacketHandler {
|
||||
BasePacket rsp = new BasePacket(PacketOpcodes.QuickUseWidgetRsp);
|
||||
rsp.setData(proto);
|
||||
session.send(rsp);
|
||||
Grasscutter.getLogger().warn("class has no effects in the game, feel free to implement it");
|
||||
// but no effects in the game, feel free to implement it!
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user