游戏跨服开发笔记
服务器管理入口
@Component
@SocketClass
public class ServerFacade {
// 所有游戏服连接时,合服事件
@ReceiverAnno
public void onAllGameServerConnected(EventMergeServer eventMergeServer) {
serverGroupManager.mergeServerExitGroup(eventMergeServer.getGameServer(), eventMergeServer.getChildServerIds());
}
// 所有游戏服连接时,所有游戏服连接事件
@ReceiverAnno
public void onAllGameServerConnected() {
serverGroupManager.forceRefresh();
}
// 注册
@SocketMethod
public void register(Wsession wsessoin, G2cGameServerRegister g2cGameServerRegister) {
gameServerManager.register(wsession, g2cGameServerRegister);
}
// 游戏服心跳事件
@SocketMethod
public void register(GameSerever gameServer, G2cGameServerRegist g2cGameServerHeartbeat) {
gameServerManager.register(wsession, g2cGameServerHeartbeat);
}
// 战斗服心跳事件
@SocketMethod
public void transferHeartbeat(Wsession wsession, T2cTeansferHeartbeat) {
transferServerManger.heartbeat(wsession, heartbeat);
}
// 接受分组参数
@SocketMethod
public void receiveGroupParam(GameServer gameServer, G2cGroupParamUpload paramUpload) {
serverGroupManager.uploadGroupParam(gameServer, paramUpload);
}
// 重新分组
@SocketMethod
public void reServerGroup(GameServer gameServer, G2cCommandReServerGroup commandReServerGroup) {
serverGroupManager.commandReGroup();
}
// 接受分组
@SocketMethod
public void assignServerGroup(GameServer gameServer, G2cCommandAssignServerGroupResp cCommandAssignServerGroupResp) {
serverGroupManager.commandAssignGroup(gameServer.getEntity(), cCommandAssignServerGroupResp.getGroupType());
}
}
// 游戏服 - 跨服处理相关入口
// 注意:Wsession不是玩家会话,是游戏服与中心服的会话
```java
@Componet
@SocketClass
public class GameServerFacade {
// 开服连接
@ReceiverAnno
public void onGameServerOpen(ServerOpenEvent event) {
if(serverManager.getOpenDay().isOpen()) {
centerManager.connect();
}
}
// 开服了,注册到中心服
@ReceiverAnno
public void onServerDayBegin(ServerDayBeginEvent event) {
centerManager.connect();
}
// 连接成功了,尝试注册,如果这时候服务器未达成开服条件,不注册
@ReceiverAnno
public void onConnerctCenter(EventCenterC) {
if(ServerType.isGameServer()) {
gameServerService.tryRegisterGameServer2Center();
}
}
// 玩家断开连接,检测是否需要退出跨服
@ReceiverAnno
public void onPlayerLogout(LogoutEvent event) {
Player player = event.getPlayer();
gameServerService.onPlayerOffine(player);
}
// 收到门票,开始前往跨服
@SocketMethod
public void receiverTicketFormCenter() {
gamServerService.beginEnter(ticketResp.getPlayerId(), ticketResp.getTransferIp(),
ticketResp.getTransferPort(), ticketResp.getTicket());
}
// 确认退出跨服
@SocketMethod
public void confirmExitTransfer(Player player, T2gTransferExitConfirmResp resp) {
gameServerService.exitTransferConfirm(player, resp);
}
// 中心服发送给玩家的通知信息
@SocketMethod
public void sendMessage(Wsession wsession, C2GMessagePacket, c2GMessagePacket) {
gameServerService.sendMessagePacket(c2GMessagePacket);
}
// 确认进入跨服
@SocketMethod
public void enterTransfer(Player player, T2gTransferEnteredResp resp) {
player.submitEvent(TeansgerEnteredEvent.valueOf(resp.getTransferType()));
}
// 收到中心返回的所有跨服地图门票信息
// 中心服会在启动完成初始化之后,主动推送到游戏服
@SocketMethod
public void receiveTransportTicketFromCenter(Wsesion wsession, C2gTransportTicketsResp c2TransportTicketsResp) {
}
// 收到中心服返回的分组信息
@SocketMethod
public void receiveServerGroupInfoFromCneter(Wsession wsession, C2gServerGroupType2ServerIds c2gServerGroupType2ServerIds) {
}
// 收到战斗服回传的玩家事件
@SocketMethod(coustomPacketId = CrossPacketId.GLOBAL_EVENT_RESP)
@IRunInNioThread
public void transferPlayerEvent(Wsession wsession, IEvent eventPacket) {
// 异步提交事件
String simpleName = eventPacket.getClass().getSimpleName();
EventBusManager.getInstance().sumbmit(eventPacket, "globalEvent_"+SimpleName, simpleName.hashCode());
}
// 跨服发奖
@SocketMethod
public void gainReward(Player player, T2gGainRewardResp t2gGainRewardResp) {
palyer.gainReward(t2gGainRewardResp.getReward(), t2gGainRewardResp.getModuleInfo());
}
// 战斗服 -> 游戏服 跨服事务
@SocketMethod
public T2gTransactionResp transaction(Player player, T2gTransactioReq) {
}
// 分组销毁
@SocketMethod
public void receiveServerGroupDestroy(Wsession wsession, C2gTicketsDetroyPacket c2gTicketsDestroyPacket) {
centerManger.onServerGroupDestroy(c2gTicketDestroyPacket.getServerGroupType());
}
}
服务器管理逻辑处理
跨服类型
@Desc("跨服3V3")
transfer_t3v3,
@Desc("跨服地图")
transfer_land,
@Desc("跨服灭神塔")
transfer_godKillTower,
@Desc("跨服灭神塔全服")
transfer_godKillTowerServer,
@Desc("跨服沙巴克")
shabake,
// ...
服务器分组类型
@Desc("服务器哦分组类型")
public enum ServerGroupType {
@Desc("3v3")
t3v3(false, false),
@Desc("第四大陆")
land4(true, true),
@Desc("第五大陆")
land5(true, true),
@Desc("公会秘境争霸")
secretArea(false,false)
// 该战区是否预分配战斗服
private boolean groupOnServerOpen;
// 预分配战斗服之后,是否通知战斗服,检测该战区下面的地图是否需要预创建地图, ps:只判断是否发送检测通知
// 具体某一张地图是否预创建,是检测地图配置MapType枚举里面的initTrandferMap字段
private boolean initMapAfterGroupTransfer;
}
跨服门票
@ProtobufClass
public class Ticket {
@Protobuf(description = "跨服类型")
private TransferType type;
@Protobuf(description = "门票id,同一")
private long ticketId;
@Protobuf(description = "分组类型(战区)")
private ServerGroupType groupType;
@Protobuf(description = "组号")
private int groupIndex;
// 其他额外信息
@Protobuf(description = "阵营类型")
private CampType campType;
@Protobuf(description = "前往的跨服地图ID")
private int mapId;
@Protobuf(description = "x")
private int x;
@Protobuf(description = "y")
private int y;
// 创建一张门票 ...
}
中心服通用业务处理
@Component
public class CenterManager {
// ...
// 创建一个唯一的门票id
public long createTicketId() {
return idGen.getAndIncrement();
}
1
// 发送门票到游戏服
public void sendTicket(TransferType transferType, long playerId, int gameServerId, TransferServer transferServer, Ticket ticket) {
GameServer gameServer = gameServerManager.getSreverIfRegister(gameServerId);
if(gameServer == null) {
return;
}
C2gTransferTicketResp resp = C2gTransferTicketResp.valueOf(
transferServer.getIp(),
transferServer.getPort(),
playerId,
ticket
);
// 通知游戏服
gameServer.send(resp);
}
}