[SpringDataMongodb开发游戏服务器实战]

背景:

xdb其实足够完美了,现在回想一下,觉得有点复杂,我们不应该绑定语言,最好有自己的架构思路。

七号堡垒作为成功的商业项目,告诉我:其实数据是多读少写的,有修改的时候直接改库也是没问题的,这样子有个好处就是rpc获取到的数据足够的准确。

跨服这块结合redis,我们可以轻松获取其它服的数据。

华珺的Player数据管理思路,将所有的数据都存放Role上,这样子获取是十分的简单。

因此,我决定写一个简单而又足够上线的框架,思路:

技术栈: SpringBoot+netty+mongo+pb 。

是按照模块划分成多线程的,也就是: 尽量单进程多线程去完成任务。

pom.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jn</groupId>
    <artifactId>mongodemo</artifactId>
    <version>1.0</version>
    <name>mongodemo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>21</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

MongoConfig.java

复制代码
package com.jn.framework.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@Configuration
public class MongoConfig {

    @SuppressWarnings("all")
    @Bean
    public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDatabaseFactory, MongoMappingContext mongoMappingContext) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDatabaseFactory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
        //去掉_class字段
        mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return new MongoTemplate(mongoDatabaseFactory, mappingConverter);
    }
}

SpringBeanUtil.java

复制代码
package com.jn.framework.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 普通的Java类中获取spring中的bean通用类
 */
@Component
public class SpringBeanUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringBeanUtil.applicationContext == null) {
            SpringBeanUtil.applicationContext = applicationContext;
        }
    }


    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

}

IEntity.java

复制代码
package com.jn.framework;

public interface IEntity {
    void save();
}

IProcedure.java

复制代码
package com.jn.framework;

public interface IProcedure {
    void call();
}

PlayerEntity.java

复制代码
package com.jn.mongodemo.account.entity;

import com.jn.framework.IEntity;
import com.jn.framework.utils.SpringBeanUtil;
import com.jn.mongodemo.bag.entity.BagEntityRepository;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@Document("PlayerEntity")
public class PlayerEntity implements IEntity {
    @Id
    @Indexed
    private Long roleId;

    @Override
    public void save() {
        SpringBeanUtil.getBean(PlayerEntityRepository.class).save(this);
    }
}

PlayerEntityRepository.java

复制代码
package com.jn.mongodemo.account.entity;

import org.springframework.data.mongodb.repository.MongoRepository;

public interface PlayerEntityRepository extends MongoRepository<PlayerEntity, Long> {

}

PLogin.java

复制代码
package com.jn.mongodemo.account.procedure;

import com.jn.framework.IProcedure;
import com.jn.framework.utils.SpringBeanUtil;
import com.jn.mongodemo.account.entity.PlayerEntity;
import com.jn.mongodemo.account.entity.PlayerEntityRepository;
import com.jn.mongodemo.bag.entity.BagEntity;
import com.jn.mongodemo.bag.entity.BagEntityRepository;
import com.jn.mongodemo.role.Role;

public class PLogin implements IProcedure {
    private long roleId;

    public PLogin(long roleId) {
        this.roleId = roleId;
    }

    @Override
    public void call() {

        // 加载玩家信息
        PlayerEntityRepository playerEntityRepository = SpringBeanUtil.getBean(PlayerEntityRepository.class);
        PlayerEntity playerEntity = playerEntityRepository.findById(roleId).orElse(null);
        if (playerEntity == null) {
            playerEntity = new PlayerEntity();
            playerEntity.setRoleId(roleId);
            playerEntityRepository.save(playerEntity);
        }
        Role.inst().setPlayerEntity(playerEntity);

        // 背包信息
        BagEntityRepository bagEntityRepository = SpringBeanUtil.getBean(BagEntityRepository.class);
        BagEntity bagEntity = bagEntityRepository.findById(roleId).orElse(null);
        if (bagEntity == null) {
            bagEntity = new BagEntity();
            bagEntity.setRoleId(roleId);
            bagEntity.setNum(100);
            bagEntityRepository.save(bagEntity);
        }
        Role.inst().setBagEntity(bagEntity);

        // 测试修改
        Role.inst().getBagEntity().setNum(Role.inst().getBagEntity().getNum() + 100);
        Integer num = Role.inst().getBagEntity().getItemMap().getOrDefault(1, 0);
        Role.inst().getBagEntity().getItemMap().put(1, num+1);

        Role.inst().getBagEntity().save();
    }
}

AccountMsgHandler.java

复制代码
package com.jn.mongodemo.account;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jn.mongodemo.account.procedure.PLogin;

@RestController
@RequestMapping("/account")
public class AccountMsgHandler {

    /*
    http://localhost:8080/account/login?roleId=3
     */
    @RequestMapping("/login")
    public void login(Long roleId) {
        new PLogin(roleId).call();
    }
}

BagEntity.java

复制代码
package com.jn.mongodemo.bag.entity;

import com.jn.framework.IEntity;
import com.jn.framework.utils.SpringBeanUtil;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.HashMap;
import java.util.Map;

@Data
@Document("BagEntity")
public class BagEntity implements IEntity {
    @Id
    @Indexed
    private Long roleId;

    private Integer num;

    private Map<Integer, Integer> itemMap = new HashMap<>();

    @Override
    public void save() {
        SpringBeanUtil.getBean(BagEntityRepository.class).save(this);
    }
}

BagEntityRepository.java

复制代码
package com.jn.mongodemo.bag.entity;

import org.springframework.data.mongodb.repository.MongoRepository;

public interface BagEntityRepository extends MongoRepository<BagEntity, Long> {

}

Role.java

复制代码
package com.jn.mongodemo.role;

import com.jn.mongodemo.account.entity.PlayerEntity;
import com.jn.mongodemo.bag.entity.BagEntity;
import lombok.Data;

@Data
public class Role {
    private static Role instance = new Role();

    public static Role inst() {
        return instance;
    }

    private PlayerEntity playerEntity;
    private BagEntity bagEntity;
}

MongodemoApplication.java

复制代码
package com.jn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MongodemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MongodemoApplication.class, args);
    }

}

application.yml

复制代码
spring:
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017
      database: mongodemo

效果:

总结:

可见游戏服使用mongo是十分合适的,轻松面对复杂的数据结构,并且和java集合框架完美结合。

其实,修改数据这块,我们可以登录时是: 同步记载,保存时,可以异步。

相关推荐
AA陈超6 分钟前
虚幻引擎5 GAS开发俯视角RPG游戏 P07-08 点击移动
c++·游戏·ue5·游戏引擎·虚幻
csd7982 小时前
从原理到实操:ddraw.dll是什么?为何游戏启动时频繁提示“找不到ddraw.dll”?解决思路全解析
游戏·dll修复工具·dll修复·dll丢失·dll缺失
星释2 小时前
Rust 练习册 :Pig Latin与语言游戏
游戏·rust·c#
Nebula_g3 小时前
C语言应用实例:硕鼠游戏,田忌赛马,搬桌子,活动选择(贪心算法)
c语言·开发语言·学习·算法·游戏·贪心算法·初学者
棉猴4 小时前
《pygame中Sprite类实现多帧动画》注-通过多张序列帧显示动画2-1
python·游戏·pygame·游戏编程
mm-q29152227296 小时前
【天野学院5期】 第5期易语言半内存辅助培训班,主讲游戏——手游:仙剑奇侠传4,端游:神魔大陆2
人工智能·算法·游戏
MoRanzhi12036 小时前
Python 实现:从数学模型到完整控制台版《2048》游戏
数据结构·python·算法·游戏·数学建模·矩阵·2048
wanhengidc7 小时前
海外云手机是指什么
运维·服务器·游戏·智能手机·云计算
武陵悭臾9 小时前
Python应用开发学习: Pygame 中实现数字水平靠右对齐和垂直靠底对齐
python·学习·程序人生·游戏·个人开发·学习方法·pygame
顾安r10 小时前
11.8 脚本网页 塔防游戏
服务器·前端·javascript·游戏·html