我的游戏服务器类库 -- 配置表及其搜索算法

配置表

想必所有的游戏服务器都要用到配置表,配置表可能来自于文件(Excel、XML、JSON等)或者数据库,但为了避免频繁访问磁盘文件或数据库,最终都会在服务器启动时读到内存里。配置表一般由很多行组成,每一行有一个唯一ID。在游戏逻辑中,可以根据ID来查找某项配置。由于每一个游戏服务器都要写类似的逻辑,所以我把它们抽象出来,加到了我的GitHub项目里。

配置项

没有对配置表项做更多的假设,只要求它有一个唯一ID

public interface Config {
    public int getId();
}

ConfigBase是Config接口的抽象实现,以方便子类继承:

public abstract class ConfigBase implements Config {

    private final int id;

    public ConfigBase(int id) {
        this.id = id;
    }

    @Override
    public int getId() {
        return id;
    }

}

搜索算法

有时候配置表也可能会比较大(比如几千上万行),所以按照ID快速找到一项配置就比较重要。SearchAlgorithm对配置表搜索算法进行了抽象:

public abstract class SearchAlgorithm {
    public abstract <T extends Config> T search(List<T> cfgs, int id);
}

我目前实现了3种搜索算法:按索引查找、二分查找、遍历查找。如果配置表ID是连续(递增)的,那么最快的搜索算法是按索引搜索:

public final class IndexedSearch extends SearchAlgorithm {

    @Override
    public <T extends Config> T search(List<T> cfgs, int id) {
        int firstId = cfgs.get(0).getId();
        int index = id - firstId;
        return cfgs.get(index);
    }

}

如果ID不连续,但是配置表比较小(比如小于8条),那么遍历整张表也许是最快的搜索算法:

public final class TraverseSearch extends SearchAlgorithm {

    @Override
    public <T extends Config> T search(List<T> cfgs, int id) {
        for (T cfg : cfgs) {
            if (cfg.getId() == id) {
                return cfg;
            }
        }

        throw new ConfigNotFoundException(cfgs, id);
    }

}

否则(配置表ID必须是递增的),使用二分法查找:

public final class BinarySearch extends SearchAlgorithm {

    @Override
    public <T extends Config> T search(List<T> cfgs, int id) {
        int index = indexedBinarySearch(cfgs, id);
        if (index >= 0) {
            return cfgs.get(index);
        } else {
            throw new ConfigNotFoundException(cfgs, id);
        }
    }

    // 代码是从java.util.Collections.indexedBinarySearch()里拷贝过来的,并进行了修改
    private static <T extends Config> int indexedBinarySearch(List<T> list, int id) {
        int low = 0;
        int high = list.size()-1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            T midVal = list.get(mid);
            int cmp = Integer.compare(midVal.getId(), id);

            if (cmp < 0)
                low = mid + 1;
            else if (cmp > 0)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found
    }

}

SearchAlgorithm的static方法selectAlgorithm()根据配置表的上述特点来选择最优的搜索算法,具体的代码就不贴了。

ConfigList

ConfigList将配置表和搜索算法封装在了一起:

public class ConfigList<T extends Config> {

    private final List<T> cfgs; // size > 0
    private final SearchAlgorithm searchAlgorithm;

    public ConfigList(List<T> cfgs) {
        if (cfgs.isEmpty()) {
            throw new IllegalArgumentException("empty list");
        }

        cfgs = new ArrayList<>(cfgs);
        sortCfgs(cfgs);
        checkSameId(cfgs); // ID不能重复

        this.cfgs = Collections.unmodifiableList(cfgs);
        searchAlgorithm = SearchAlgorithm.selectAlgorithm(this.cfgs);
    }

    ...
}

getConfigs()方法返回全部配置,getConfig(int)按ID查找配置:

    public List<T> getConfigs() {
        return cfgs;
    }

    public T getConfig(int id) {
        // todo check id
        return searchAlgorithm.search(cfgs, id);
    }
时间: 2024-11-05 21:46:58

我的游戏服务器类库 -- 配置表及其搜索算法的相关文章

我的游戏服务器类库 -- 加载配置表

GAMMA类库 我在GitHub上面创建了gamma项目,把自己工作(Java游戏服务器编程)中经常用到的代码整理后放了进去. 配置表加载 前一篇文章介绍了如何查找配置表,本篇文章来介绍一下如何把配置表加载到内存. ConfigLoader 由于配置表可能在文件里,也可能在数据库里,或者其他地方,所以一个合理的设计可能会是这样: 不过我目前的项目是用JSON文件存放配置表的,所以我只设计了FileConfigLoader和JsonConfigLoader两个类. FileConfigLoader

我的游戏服务器类库 -- 按权重随机选择1个或n个对象

按权重选择 在编写游戏服务器的时候,经常会遇到类似的需求:从列表中随机选出1个或多个条目,且条目是有权重的(权重越大,选中它的可能性就越大).比如说,砍死一个怪物可以从一个装备列表里掉一个装备.这种需求,和现实生活中的幸运大转盘很类似: 算法实现 因为这种需求很常见,所以我想把它写的通用一点.首先,接口Weighted表示有权重值的对象,getWeight()方法返回权重值: public interface Weighted { public int getWeight(); } Weight

(转载) 游戏策划的excel配置表转成json文件(一)

游戏客户端里一般无法读取策划写的excel配置表,需要先转成可以用的格式,例如json,xml格式. 我用到的工具是python脚本,python脚本的强大就在这不提啦,各种牛X的成熟库... 执行脚本如下: [cpp] view plaincopy import os import sys import codecs import json from xlrd import open_workbook # "<type 'unicode'>" # "<ty

游戏服务器背包设计与实现

在游戏开发中,背包是一个非常重要的功能.几乎每个复杂点的游戏都会有背包的功能.不管是手游戏还是网页游戏,不管是SLG游戏,还是ARPG游戏,背包是必不可少的.背包的功能根据策划的要求,有的简单,有的复杂.以下我们就讨论一下几种游戏服务器背包的实现. 1,简单的游戏背包设计 简单的游戏背包到底简单到什么程度呢?那么这个游戏背包只是用来存放物品,不需要记录物品在背包中的位置,只需要记录物品的id和物品的数量即可.这样的游戏背包设计起来非常方便,在数据库中一个物品占一行即可,例如: 当获得物品的时候,

手机游戏服务器引擎Scut免费开源

scut 官网:http://www.scutgame.com/ Scut是一个开源.免费.稳定.快速开发的手机游戏服务器引擎,支持开发人员使用Python脚本语言或C#语言开发:底层采用C#编写,基于MVC框架思想设计, 开发人员只需要关注如何定义数据实体类及属性,不再需要关注多据库(MSSQL.MySql等)及表设计,Scut会帮助你自动检测生成相应数据库的表结构:它还提供了丰富的AIP和成熟的游戏模块中间件,快速开发你的游戏服务器应用,和Cocos2d-x完美结合,提供基于Cocos2d-

大型多人在线游戏服务器架构设计

由于大型多人在线游戏服务器理论上需要支持无限多的玩家,所以对服务器端是一个非常大的考验.服务器必须是安全的,可维护性高的,可伸缩性高的,可负载均衡的,支持高并发请求的.面对这些需求,我们在设计服务器的时候就需要慎重考虑,特别是架构的设计,如果前期设计不好,最后面临的很可能是重构. 一款游戏服务器的架构都是慢慢从小变大的,不可能一下子就上来一个完善的服务器构架,目前流行的说法是游戏先上线,再扩展.所以说我们在做架构的时候,一定要把底层的基础组件做好,方便以后扩展,但是刚开始的时候留出一些接口,并不

教你从头写游戏服务器框架

本文由云+社区发表 作者:韩伟 前言 大概已经有差不多一年没写技术文章了,原因是今年投入了一些具体游戏项目的开发.这些新的游戏项目,比较接近独立游戏的开发方式.我觉得公司的"祖传"服务器框架技术不太适合,所以从头写了一个游戏服务器端的框架,以便获得更好的开发效率和灵活性.现在项目将近上线,有时间就想总结一下,这样一个游戏服务器框架的设计和实现过程. 这个框架的基本运行环境是 Linux ,采用 C++ 编写.为了能在各种环境上运行和使用,所以采用了 gcc 4.8 这个"古老

游戏服务器解决的3个问题

写游戏服务器有一段时间了,在我看来一个游戏服务器设计得好不好,可以从以下三个方面: 1.配置读取问题 配置读取直接决定了策划改表是否方便. 2.消息处理问题 消息处理决定了服务器业务逻辑处理是否方便 3.数据落地 数据落地为最关键的一条,游戏数据最终是否能落地. 原文地址:https://www.cnblogs.com/LittleLee/p/11334942.html

使用GoWorld游戏服务器引擎轻松实现分布式聊天服务器

GoWorld游戏服务器引擎简介 GoWorld是一款开源的分布式可扩展的游戏服务器引擎,使用Go语言(Golang)编写.它采用类似BigWorld的结构,使用了简化的场景-对象框架.以一个典型的MMORPG为例,每个服务器上会有多个场景,每个场景里可以包含多个对象,这些对象包括玩家.NPC.怪物等.GoWorld服务器可以将场景分配到在不同的进程甚至不同的机器上,从而使得游戏服务器的负载是可扩展的. 开源分布式游戏服务器引擎:https://github.com/xiaonanln/gowo