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

news2024/9/23 5:28:28

背景:

        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集合框架完美结合。 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1468050.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文是怎么一回事

最近找到女朋友了&#xff0c;她还挺关心我毕业和论文的事情&#xff0c;我开始着手弄论文了~ 说来惭愧&#xff0c;我一直以为读研就是做东西当作工作来完成&#xff0c;结果一直陷入如何实现的问题&#xff0c;结果要论文时不知道怎么弄创新点&#xff0c;这才转过头来弄论文…

学生个性化成长平台搭建随笔记

1.Vue的自定义指令 在 Vue.js 中&#xff0c;我们可以通过 Vue.directive() 方法来定义自定义指令。具体来说&#xff0c;我们需要传递两个参数&#xff1a; 指令名称&#xff1a;表示我们要定义的指令名称&#xff0c;可以是一个字符串值&#xff0c;例如&#xff1a;has-rol…

【深度学习目标检测】十八、基于深度学习的人脸检测系统-含GUI和源码(python,yolov8)

人脸检测是计算机视觉中的一个重要方向&#xff0c;也是一个和人们生活息息相关的研究方向&#xff0c;因为人脸是人最重要的外貌特征。人脸检测技术的重要性主要体现在以下几个方面&#xff1a; 人脸识别与安全&#xff1a;人脸检测是人脸识别系统的一个关键部分&#xff0c;是…

详解 CSS 的背景属性

详解 CSS 的背景属性 背景颜色 语法&#xff1a; background-color: [指定颜色]; 注&#xff1a;默认是 transparent (透明) 的&#xff0c;可以通过设置颜色的方式修改 示例代码: 运行效果: 背景图片 语法&#xff1a;background-image: url(...); url 可以是绝对路径 也可…

uni-app 经验分享,从入门到离职(五)——由浅入深 uni-app 数据缓存

文章目录 &#x1f4cb;前言⏬关于专栏 &#x1f3af;什么是数据存储&#x1f9e9;数据存储——存储&#x1f4cc; uni.setStorage(OBJECT)&#x1f4cc; uni.setStorageSync(KEY,DATA) &#x1f9e9;数据存储——获取&#x1f4cc; uni.getStorage(OBJECT)&#x1f4cc; uni.g…

【前端素材】推荐优质后台管理系统Start Admin平台模板(附源码)

一、需求分析 后台管理系统是一种用于管理网站、应用程序或系统的工具&#xff0c;它通常作为一个独立的后台界面存在&#xff0c;供管理员或特定用户使用。下面详细分析后台管理系统的定义和功能&#xff1a; 1. 定义 后台管理系统是一个用于管理和控制网站、应用程序或系统…

【论文阅读】ICCV 2023 计算和数据高效后门攻击

文章目录 一.论文信息二.论文内容1.摘要2.引言3.主要图表4.结论 一.论文信息 论文题目&#xff1a; Computation and Data Efficient Backdoor Attacks&#xff08;计算和数据高效后门攻击&#xff09; 论文来源&#xff1a; 2023-ICCV&#xff08;CCF-A&#xff09; 论文团…

Leetcoder Day20| 二叉树 part09+总结

语言&#xff1a;Java/Go 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移…

一些不得不知道的概念!吴恩达deeplearning.ai:人工智能的导论

文章目录 强人工智能 AGI人工智能的分类深度学习AGI可能实现的一些证据一种学习算法的假设具体的例子 为什么人工智能如此高效 以下内容有任何不理解可以翻看我之前的博客哦 强人工智能 AGI 强人工智能也叫做通用人工智能&#xff0c;是人工智能学科发展的一个重要目标。 人…

Bean的声明周期

1.创建Bean对象&#xff08;调用无参数构造&#xff09; 2.给bean对象设置相关属性&#xff08;依赖注入&#xff09; 3.bean后置处理器&#xff08;初始化前执行&#xff0c;类似于过滤器和拦截器&#xff09; 首先要定义一个类MyBeanPost&#xff0c;实现BeanPostProcessor…

Linux基础 7:自定义shell的编写

自定义shell的编写 一.自定义shell的编写。1.打印命令行提示符。2.获取用户输入字符串进行字符串分割保存。3.调用系统调用接口执行命令&#xff08;使用子进程&#xff09;4.对于内建命令的特殊处理。1.cd2.cd 特殊符号识别&#xff1a; 5.export和echo作为内建命令&#xff1…

动态规划3,地下城游戏

思路&#xff1a; 经验题目要求 a.以某个位置为结尾… dp[i][j]表示&#xff1a;走到【i&#xff0c;j】位置的时候&#xff0c;所需要的最初最低血量。 b.以某个位置为起点 dp[i][j]表示&#xff0c;从【i&#xff0c;j】出发&#xff0c;到达终点&#xff0c;所需要的最低初…

微信小程序云开发入门

写在前面&#xff1a; 参考的课程是咸虾米老师在b站的课&#xff1a;2.2.在页面展现云数据库的内容_哔哩哔哩_bilibili 云开发官方文档&#xff1a;微信开放文档 1、什么是云开发&#xff1f; 用自己的话来说就是把服务器和后台都搭在腾讯开发的服务器上。 2、如何开通云开发…

HCIA-HarmonyOS设备开发认证V2.0-IOT硬件子系统-WatchDog

目录 一、 WATCHDOG 概述功能简介基本概念 二、WATCHDOG 模块相关API三、WATCHDOG HDF驱动开发3.1、开发步骤(待续...) 坚持就有收获 一、 WATCHDOG 概述 功能简介 看门狗&#xff08;Watchdog&#xff09;&#xff0c;又称看门狗计时器&#xff08;Watchdog timer&#xff0…

【AI数字人-论文】RAD-NeRF论文

文章目录 前言模型框架动态的NeRF前处理头部模型音频特征眼部控制头部总体表示 躯干模型loss 结果参考 【AI数字人-论文】AD-NeRF论文 前言 本篇论文有三个主要贡献点&#xff1a; 提出一种分解的音频空间编码模块&#xff0c;该模块使用两个低维特征网格有效地建模固有高维音…

关于Kinect 互动沙盘 深度图 Shader Graph 分层

把Kinect的深度图穿给Shader Graph using com.rfilkov.kinect; using UnityEngine; using UnityEngine.UI; public class GetDepthTex : MonoBehaviour { public Material Mat_SandTable; void Update() { Mat_SandTable.SetTexture("_MainTex"…

LabVIEW串口通信的激光器模块智能控制

LabVIEW串口通信的激光器模块智能控制 介绍了通过于LabVIEW的VISA串口通信技术在激光器模块控制中的应用。通过研究VISA串口通信的方法和流程&#xff0c;实现了对激光器模块的有效控制&#xff0c;解决了数据发送格式的匹配问题&#xff0c;为激光器模块的智能控制提供了一种…

Open CASCADE学习|几何数据结构

在几何引擎内一般把数据分成两类&#xff1a;几何信息与拓扑信息。二者可以完整地表达出实体模型&#xff0c;彼此相互独立、又互相关联。几何信息是指构成几何实体的各几何元素在欧式空间中的位置、大小、尺寸和形状信息。例如一条空间的直线&#xff0c;可以用两端点的位置矢…

019—pandas 计算实验仪器正常运行周期时长

需求&#xff1a; 对指定两个状态作为一个周期&#xff0c;并计算出周期内的差值&#xff0c;写到周期结束所在的行上。pandas 非常适合实现此类有着较为复杂逻辑的问题。 思路&#xff1a; 这个问题的难点是状态的不规律性&#xff0c;如何才能准确找出所有 T 和 C 的周期。…

python 打包 apk

转换之前python代码需要使用指定的框架才能转换&#xff0c;列如&#xff1a;kivy from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Buttonimport time import pyautogui import threadingstatus False# 这是一个将被线程执…