导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客
用户在选择了职业之后, 后台接收需要创建用户的数据,这里我们要先把用户在后台的数据存储结构定义出来。
首先一个用户应该会创建多个角色,故而先创建一个用户游戏封装类UserGameWrapper,每个角色也有一个封装类HeroWrapper。
UserGameWrapper
@Data
public class UserGameWrapper {
private String userId;
private String userName;
private Map<String,HeroWrapper> heroWrapperMap;
}
HeroWrapper
@Data
public class HeroWrapper {
/***
* 英雄
*/
private Hero hero;
}
当一个用户登录或者注册成功的时候,要把其game数据查询并放到缓存中。并且要和session绑定起来。
LoginHandler修改
package com.loveprogrammer.handler;
import com.alibaba.fastjson2.JSON;
import com.loveprogrammer.base.bean.session.Session;
import com.loveprogrammer.common.SessionGameContext;
import com.loveprogrammer.base.network.support.SessionManager;
import com.loveprogrammer.command.anotation.TagListener;
import com.loveprogrammer.command.anotation.TopicListener;
import com.loveprogrammer.command.server.ServerLoginOrRegisterTag;
import com.loveprogrammer.command.server.ServerTopic;
import com.loveprogrammer.constants.CommonValue;
import com.loveprogrammer.convert.JobTemplateConvert;
import com.loveprogrammer.dto.job.JobChoose;
import com.loveprogrammer.dto.login.UserLogin;
import com.loveprogrammer.dto.login.UserRegister;
import com.loveprogrammer.domain.User;
import com.loveprogrammer.exception.ServerException;
import com.loveprogrammer.factory.JobFactory;
import com.loveprogrammer.factory.template.JobTemplate;
import com.loveprogrammer.model.game.UserGameWrapper;
import com.loveprogrammer.pojo.StringMessage;
import com.loveprogrammer.service.IUserService;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ClassName LoginHandler
* @Description 登录
* @Author admin
* @Date 2024/2/6 15:49
* @Version 1.0
*/
@Component
@TopicListener(topic = ServerTopic.TOPIC_LOGIN)
public class LoginHandler extends BaseHandler {
public static final Logger log = LoggerFactory.getLogger(LoginHandler.class);
@Autowired
private IUserService userService;
/***
* 注册
* @param ctx
* @param register
*/
@TagListener(tag = ServerLoginOrRegisterTag.TAG_LOGIN_REGISTER,messageClass = UserRegister.class)
public StringMessage register(ChannelHandlerContext ctx, UserRegister register) throws ServerException {
log.info("数据内容:data=" + JSON.toJSONString(register));
User user = userService.findUserByNickname(register.getName());
if(user == null) {
user = new User();
user.setNickName(register.getName());
user.setPassword("111111");
user.setAccount(register.getName());
userService.save(user);
// 登录成功,把user信息放入session中
Session session = SessionManager.getInstance().getSessionByChannel(ctx.channel());
session.setUserId(user.getId().toString());
session.setNickname(user.getNickName());
// 创建用户的游戏数据并写入全局缓存中
UserGameWrapper gameWrapper = UserGameWrapper.create(user);
SessionGameContext.USER_GAME_MAP.put(user.getId(),gameWrapper);
// 跳转到选择职业界面
StringMessage data = StringMessage.create(register.getSuccessCallbackTopic(), register.getSuccessCallbackTag());
data.setStatusCode(CommonValue.MSG_STATUS_CODE_SUCCESS);
// 获得可用的职业
List<JobTemplate> jobTemplates = JobFactory.getTemplates();
JobChoose jobChoose = new JobChoose(data);
jobChoose.setJobList(JobTemplateConvert.INSTANCE.toJobChooseItems(jobTemplates));
data.setBody(JSON.toJSONString(jobChoose));
return data;
}
else{
log.warn("用户已经存在");
throw new ServerException("用户已经存在");
}
}
/***
* 登录
* @param ctx
* @param register
*/
@TagListener(tag = ServerLoginOrRegisterTag.TAG_LOGIN_LOGIN,messageClass = UserLogin.class)
public StringMessage login(ChannelHandlerContext ctx, UserLogin register) throws ServerException {
// 查询用户
User user = userService.findUserByAccount(register.getUserName());
if(user == null) {
throw new ServerException("用户不存在");
}
// 对比密码
if(!register.getPassword().equalsIgnoreCase(user.getPassword())) {
throw new ServerException("用户名密码不匹配");
}
// 登录成功,把user信息放入session中
Session session = SessionManager.getInstance().getSessionByChannel(ctx.channel());
session.setUserId(user.getId().toString());
session.setNickname(user.getNickName());
// TODO 这里应该是先读取用户的数据而不是创建新的
UserGameWrapper gameWrapper = UserGameWrapper.create(user);
SessionGameContext.USER_GAME_MAP.put(user.getId(),gameWrapper);
// 客户端进入选择英雄页面
StringMessage message = StringMessage.create(register.getSuccessCallbackTopic(), register.getSuccessCallbackTag());
message.setStatusCode(CommonValue.MSG_STATUS_CODE_SUCCESS);
// 获得可用的职业
List<JobTemplate> jobTemplates = JobFactory.getTemplates();
JobChoose jobChoose = new JobChoose(message);
jobChoose.setJobList(JobTemplateConvert.INSTANCE.toJobChooseItems(jobTemplates));
message.setBody(JSON.toJSONString(jobChoose));
return message;
}
}
客户端选择创建新英雄后,后端要生成英雄并保存到全局缓存中。
服务端的HeroHandler
package com.loveprogrammer.handler;
import com.alibaba.fastjson2.JSON;
import com.loveprogrammer.base.network.support.BaseHandler;
import com.loveprogrammer.command.anotation.TagListener;
import com.loveprogrammer.command.anotation.TopicListener;
import com.loveprogrammer.command.client.ClientMenuTag;
import com.loveprogrammer.command.client.ClientTopic;
import com.loveprogrammer.command.server.ServerHeroTag;
import com.loveprogrammer.command.server.ServerTopic;
import com.loveprogrammer.common.SessionGameContext;
import com.loveprogrammer.constants.CommonValue;
import com.loveprogrammer.dto.base.StringRequest;
import com.loveprogrammer.dto.job.HeroCreate;
import com.loveprogrammer.factory.JobFactory;
import com.loveprogrammer.model.Hero;
import com.loveprogrammer.model.game.HeroWrapper;
import com.loveprogrammer.model.game.UserGameWrapper;
import com.loveprogrammer.pojo.StringMessage;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @ClassName HeroHandler
* @Description 英雄角色相关的执行类
* @Author admin
* @Date 2024/2/5 15:49
* @Version 1.0
*/
@Component
@TopicListener(topic = ServerTopic.TOPIC_HERO)
public class HeroHandler extends BaseHandler {
public static final Logger log = LoggerFactory.getLogger(HeroHandler.class);
@TagListener(tag = ServerHeroTag.TAG_HERO_CREATE,messageClass = HeroCreate.class)
public StringMessage createHero(ChannelHandlerContext ctx, HeroCreate data) throws Exception {
Integer jobId = data.getId();
Hero hero = JobFactory.createHero(JobFactory.getJobMap().get(jobId), data.getHeroName());
// 创建封装
HeroWrapper wrapper = new HeroWrapper(hero);
// 获取游戏封装
int sessionId = getSessionId(ctx.channel());
UserGameWrapper gameWrapper = SessionGameContext.USER_GAME_MAP.get(sessionId);
// 角色名称作为key
gameWrapper.getHeroWrapperMap().put(data.getHeroName(),wrapper);
// 角色创建成功,返回游戏主菜单
StringMessage message = StringMessage.create(ClientTopic.TOPIC_MENU, ClientMenuTag.TAG_MENU_PORTAL);
message.setStatusCode(CommonValue.MSG_STATUS_CODE_SUCCESS);
StringRequest request = new StringRequest();
request.setContent("英雄创建成功");
message.setBody(JSON.toJSONString(request));
return message;
}
}
客户端的LoginHandler的修改
/***
* 选择职业
* @param ctx
* @param data
*/
@TagListener(tag = ClientLoginTag.TAG_LOGIN_CHOOSE_HERO, messageClass = JobChoose.class)
public void chooseHero(ChannelHandlerContext ctx, JobChoose data) {
//
ConsolePrint.publishMessage("请选择要创建的职业");
List<JobChoose.JobItem> jobList = data.getJobList();
for (int i = 0; i < jobList.size(); i++) {
ConsolePrint.publishMessage((i+1) + ":" + jobList.get(i).toString(), 1);
}
Scanner input = new Scanner(System.in);
int choose = input.nextInt();
while(choose < 0 || choose > jobList.size()){
ConsolePrint.publishMessage("请重新选择", 1);
choose = input.nextInt();
}
JobChoose.JobItem jobItem = jobList.get(choose - 1);
ConsolePrint.publishMessage("选择的职业为" + jobItem.getName());
ConsolePrint.publishMessage("请输入角色的名称:");
String heroName = ScannerInput.inputString();
// 创建角色
StringMessage message = StringMessage.create(ServerTopic.TOPIC_HERO, ServerHeroTag.TAG_HERO_CREATE);
HeroCreate create = new HeroCreate(ClientTopic.TOPIC_MENU, ClientMenuTag.TAG_MENU_JOB_CHOOSE, ClientTopic.TOPIC_LOGIN, ClientLoginTag.TAG_LOGIN_CHOOSE_HERO);
create.setId(jobItem.getId());
create.setHeroName(heroName);
message.setStatusCode(CommonValue.MSG_STATUS_CODE_SUCCESS);
message.setBody(JSON.toJSONString(create));
ChannelUtils.pushToServer(ctx.channel(), message);
}
客户端演示效果如下:
【1.登录已有账户】 【2.注册新账户】 【3.退出】
请选择:
1
请输入账户名:
eric
请输入密码:
11111
用户名密码不匹配
【1.登录已有账户】 【2.注册新账户】 【3.退出】
请选择:
eric
输入有误,请重新输入
1
请输入账户名:
eric
请输入密码:
111111
请选择要创建的职业
1:JobChoose.JobItem(id=1, name=战士, desc=剑类武器, strength=60, armature=5, constitution=80, magic=0, technique=15, speed=130)
1
选择的职业为战士
请输入角色的名称:
death
英雄创建成功
请选择您要进行的操作
【1.打怪】 【2.装备】 【3.战兽】
【4.冒险者工会】 【5.副本】 【6.工会】
【8.配置】 【9.退出】
请选择:
全部源码详见:
gitee : eternity-online: 多人在线mmo游戏 - Gitee.com
分支:step-11
请各位帅哥靓女帮忙去gitee上点个星星,谢谢!