Netty游戏服务器实战开发(13):游戏中的配表规则

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_23086307/article/details/87516444

在一个游戏开发过程中,少不了和策划,客户端等同学打交道。应为一个完整的游戏开发团队,有如下人员组成:

  • 1:服务器开发人员
  • 2:客户端开发人员
  • 3:策划
  • 4:美术
  • 5:其他

其中还会分很多细节,比如策划可以分为场景策划,数值策划,玩法策划等等,但是作为一个策划人员不仅能够有好的游戏思想,最重要的是学会游戏中的配表。这是一个策划的基本功。

规则很重要,游戏中的配表规则其实大部分主要是用来配合程序完成功能,也就是所谓的游戏中的数据字典,每个团队有每个团队的功能。常见的配表方式又:

  1. Excel文档格式
  2. xml文档格式

不管哪种方式都有它的优缺点,Excel文档个可以直观的看出数据,但是程序读写的时候需要将Excel转为别的文件,例如xml或者json等数据格式,而直接xml文档结构上可以更清晰,但是程序需要花大量的逻辑来读写xml,所以适合自己的才是最重要的,在这我们主要是介绍将Excel文档的策划配表转为json,然后给开发人员直接读取json来获得配表数据。

当然,我们可以用python可以完成上面的操作。也可以用java来完成。下面就来几点的介绍一下我写的用java生成的模板文件。
先看看Excel文档的模板
在这里插入图片描述

说明:第一行是版本号,第二行是作用域,第三行是字段类型,第四行是字段名,第五行是描述,下面的就是数据。当数据没有描述和类型的时候,此列不作为读取。

直接上代码:
首先我们在maven项目中添加所需要的库

  <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.15-beta2</version>
        </dependency>

定义资源类型:

package com.twjitm.jump.gm.excel;

/**
 * @author by twjitm on 2019/1/24/18:06
 */
public enum ScopeType {
    /**
     * 无法识别
     */
    NOTKNOW(0, "n"),
    /**
     * 客户端专用字段
     */
    CLIENT(1, "c"),
    /**
     * 服务器专用字段
     */
    SERVER(2, "s"),
    /**
     * 服务器和客户端共同使用字段
     */
    COMMON(3, "sc");


    private int code;
    private String explain;

    ScopeType(int code, String explain) {
        this.code = code;
        this.explain = explain;
    }


    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getExplain() {
        return explain;
    }

    public void setExplain(String explain) {
        this.explain = explain;
    }


    public static ScopeType getScope(String explain) {
        ScopeType scopeType = null;
        switch (explain) {
            case "n":
                scopeType = ScopeType.NOTKNOW;
                break;
            case "c":
                scopeType = ScopeType.CLIENT;
                break;
            case "s":
                scopeType = ScopeType.SERVER;
                break;
            case "sc":
                scopeType = ScopeType.COMMON;
                break;
            default:
                scopeType = ScopeType.NOTKNOW;
        }
        return scopeType;
    }
}

定义资源类型:

package com.twjitm.jump.gm.excel;

/**
 * 资源类型
 *
 * @author by twjitm on 2019/1/24/18:24
 */
public enum ResourceType {
    CLIENT(0),
    SERVER(1),
    ;

    private int code;

    ResourceType(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }

    public static ResourceType getResourceType(int code) {
        if (code == CLIENT.code) {
            return CLIENT;
        }
        if (code == SERVER.code) {
            return SERVER;
        }
        return SERVER;

    }
}

定义字段类型:

package com.twjitm.jump.gm.excel;

import com.twjitm.jump.common.utils.zutils.ZStringUtil;


/**
 * 字段类型
 *
 * @author by twjitm on 2019/1/24/18:47
 */
public enum FieldType {
    /**
     * 无法识别的类型
     */
    NOTKNOW("", "", ""),
    /**
     * byte类型
     */
    BYTE("", "", "byte"),
    /**
     * float类型
     */
    FLOAT("", "", "float"),

    /**
     * short类型
     */
    SHORT("", "", "short"),
    /**
     * int类型
     */
    INT("", "", "int"),
    /**
     * double类型
     */
    DOUBLE("", "", "double"),
    /**
     * long类型
     */
    LONG("", "", "long"),
    /**
     * 字符串类型
     */
    STRING("", "", "string"),
    /**
     * id数量类型
     */
    IDCOUNT("|", ";", "IdCount[]"),
    /**
     * 数组类型
     */
    ARRAY(",", "", "[]"),
    /**
     * 布尔类型
     */
    BOOLEAN("", "", ""),
    ;

    private String outerSplit;
    private String innerSplit;

    private String name;

    FieldType(String outerSplit, String innerSplit, String name) {
        this.outerSplit = outerSplit;
        this.innerSplit = innerSplit;
        this.name = name;
    }


    public String getInnerSplit() {
        return innerSplit;
    }

    public String getOuterSplit() {
        return outerSplit;
    }

    public static FieldType getType(String fieldStr) {
        for (FieldType type : FieldType.values()) {
            if (type.name.equals(fieldStr)) {
                return type;
            }
            if (fieldStr.indexOf("[]") > 0) {
                String[] splits = fieldStr.split("\\[]");
                FieldType subType = getType(splits[0]);
                if (subType != NOTKNOW) {
                    return ARRAY;
                } else {
                    return IDCOUNT;
                }
            }
        }
        return NOTKNOW;
    }

    public boolean isArray(String fieldStr) {
        if (ZStringUtil.isEmptyStr(fieldStr)) {
            return false;
        }
        if (fieldStr.indexOf("\\[]") > 0) {
            return true;
        }
        return false;
    }


}

定义这些字段类型表示每个字段的数据类型,在生成json的时候有作用于数据的取向。

最后我们给出核心操作算法:

package com.twjitm.jump.gm.excel;

import com.alibaba.fastjson.JSON;
import com.twjitm.jump.common.utils.zutils.ZStringUtil;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 将Excel文件转化为json文件的工具类,后期做成可视化界面操作。
 *
 * @author by twjitm on 2018/12/10/18:11
 */
public class ExcelToJsonUtils {
    private Logger logger = LoggerFactory.getLogger(ExcelToJsonUtils.class);

    private static String EXCEL_PACKAGE = "e:\\json\\";

    private static String JSON_PACKAGE = "e:\\data\\json\\";
    private FieldType fieldType;


    public static void main(String[] args) {
        EXCEL_PACKAGE = "e:" + "\\data";
        ExcelToJsonUtils excelHelper = getExcel2JSONHelper();

        File directory = new File(EXCEL_PACKAGE);
        if (!directory.isDirectory()) {
            return;
        } else {
            //首先将第一层目录扫描一遍
            File[] files = directory.listFiles();
            for (File file : files) {
                //dir文件,3第三列开始以,模板需求,2代表资源类型,
                // 1打客户端资源,
                // 2打服务器资源,
                excelHelper.readExcel(file, ResourceType.SERVER);
            }
        }
    }

    /**
     * 获取一个实例
     */
    private static ExcelToJsonUtils getExcel2JSONHelper() {
        return new ExcelToJsonUtils();
    }

    /**
     * 文件过滤
     */
    private boolean fileNameFilter(File file) {
        boolean endsWith = false;
        if (file != null) {
            String fileName = file.getName();
            endsWith = fileName.endsWith(".xls") || fileName.endsWith(".xlsx");
        }
        return endsWith;
    }

    /**
     * 获取表头行
     *
     * @return: Row
     */
    private Row getRow(Sheet sheet, int index) {
        Row headerRow = null;
        if (sheet != null) {
            headerRow = sheet.getRow(index);
        }
        return headerRow;
    }

    /**
     * 获取表格中单元格的value
     *
     * @return: Object
     */
    private Object getCellValue(Row row, int cellIndex, FormulaEvaluator formula) {
        Cell cell = row.getCell(cellIndex);
        if (cell != null) {
            switch (cell.getCellType()) {
                //String类型
                case Cell.CELL_TYPE_STRING:
                    return cell.getRichStringCellValue().getString();

                //number类型
                case Cell.CELL_TYPE_NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) {
                        return cell.getDateCellValue().getTime();
                    } else {
                        return cell.getNumericCellValue();
                    }
                    //boolean类型
                case Cell.CELL_TYPE_BOOLEAN:
                    return cell.getBooleanCellValue();
                //公式    
                case Cell.CELL_TYPE_FORMULA:
                    return formula.evaluate(cell).getNumberValue();
                case Cell.CELL_TYPE_ERROR:
                    break;
                default:
                    return null;
            }
        }
        return null;
    }

    /**
     * 获取表头value
     *
     * @throws
     * @Title: getHeaderCellValue
     */
    private String getHeaderCellValue(Row headerRow, int cellIndex) {
        Cell cell = headerRow.getCell(cellIndex);
        String headerValue = null;
        if (cell != null) {
            headerValue = cell.getRichStringCellValue().getString();
        }
        System.out.println(headerValue);
        return headerValue;
    }

    /**
     * 获取字段作用于
     *
     * @return
     */
    public ScopeType getScope(Row scopeRow, int cellIndex) {

        Cell cell = scopeRow.getCell(cellIndex);
        String scopeStr = "";
        if (cell != null) {
            scopeStr = cell.getRichStringCellValue().getString();
        }
        if (ZStringUtil.isEmptyStr(scopeStr)) {
            return ScopeType.NOTKNOW;
        }
        return ScopeType.getScope(scopeStr);

    }

    /**
     * 获取字段类型
     */
    private FieldType getFieldType(String fieldStr) {
        if (ZStringUtil.isEmptyStr(fieldStr)) {
            return FieldType.NOTKNOW;
        }
        return FieldType.getType(fieldStr);
    }


    /**
     * 字段类型值
     */
    private String getFieldTypeStr(Row fieldRow, int cellIndex) {
        Cell cell = fieldRow.getCell(cellIndex);
        String fieldStr = "";
        if (cell != null) {
            fieldStr = cell.getRichStringCellValue().getString();
        }

        return fieldStr;
    }

    /**
     * 读取excel表格
     */
    public void readExcel(File file, ResourceType resourceType) {

        if (!fileNameFilter(file)) {
            return;
        } else {
            try {
                //加载excel表格
                Workbook wb = WorkbookFactory.create(file);
                //读取第一个sheet页
                logger.debug("excel file sheet num={}", wb.getNumberOfSheets());
                for (int page = 0; page < wb.getNumberOfSheets(); page++) {
                    List<Map<String, Object>> lists = new ArrayList<>();
                    Sheet sheet = wb.getSheetAt(page);
                    String pageName = sheet.getSheetName().split("\\|")[1];
                    //作用区域
                    Row scopeRow = getRow(sheet, 1);
                    //字段类型
                    Row filedRow = getRow(sheet, 2);
                    //读取表头行
                    Row headerRow = getRow(sheet, 3);
                    //读取数据
                    FormulaEvaluator formula = wb.getCreationHelper().createFormulaEvaluator();
                    //跳过说明
                    for (int r = 5; r <= sheet.getLastRowNum(); r++) {
                        Row dataRow = sheet.getRow(r);
                        Map<String, Object> map = new HashMap<>(16);
                        for (int h = 0; h < dataRow.getLastCellNum(); h++) {
                            //表头为key
                            ScopeType scope = getScope(scopeRow, h);
                            //检测头
                            String headerName = getHeaderCellValue(headerRow, h);
                            if (headerName == null || "".equals(headerName)) {
                                continue;
                            }
                            //检测作用域
                            if (ScopeType.NOTKNOW == scope) {
                                continue;
                            }
                            if (resourceType == ResourceType.CLIENT) {
                                if (scope != ScopeType.CLIENT && scope != ScopeType.COMMON) {
                                    continue;
                                }
                            } else if (resourceType == ResourceType.SERVER) {
                                if (scope != ScopeType.SERVER && scope != ScopeType.COMMON) {
                                    continue;
                                }
                            }
                            //检测字段类型
                            String fieldTypeStr = getFieldTypeStr(filedRow, h);
                            if (ZStringUtil.isEmptyStr(fieldTypeStr)) {
                                continue;
                            }
                            FieldType fieldType = getFieldType(fieldTypeStr);
                            if (fieldType == FieldType.NOTKNOW) {
                                continue;
                            }
                            //数据为value
                            Object value = getCellValue(dataRow, h, formula);

                            if (fieldType == FieldType.ARRAY) {
                                FieldType subFieldType = getFieldType(fieldTypeStr.split("\\[]")[0]);
                                if (value != null) {
                                    //把值转化为数组类型
                                    String valueStr = value.toString();
                                    //整形
                                    if (subFieldType == FieldType.BYTE ||
                                            subFieldType == FieldType.SHORT ||
                                            subFieldType == FieldType.INT ||
                                            subFieldType == FieldType.LONG) {
                                        value = ZStringUtil.splitToLongArray(valueStr, fieldType.getOuterSplit());
                                    } else //浮点型
                                        if (subFieldType == FieldType.FLOAT || subFieldType == FieldType.DOUBLE) {
                                            value = ZStringUtil.splitToDoubleArray(valueStr, fieldType.getOuterSplit());
                                        }
                                        //boolean类型
                                        else if (subFieldType == FieldType.BOOLEAN) {
                                            value = Boolean.parseBoolean(valueStr);
                                        }
                                    //字符串类型
                                    if (subFieldType == FieldType.STRING) {
                                        value = ZStringUtil.split(valueStr, fieldType.getOuterSplit());
                                    }
                                }
                            }
                            //把值转化为map类型
                            if (fieldType == FieldType.IDCOUNT) {
                                if (value != null) {
                                    String valueStr = value.toString();
                                    value = ZStringUtil.splitToIntMap(valueStr, fieldType.getOuterSplit(), fieldType.getInnerSplit());
                                }
                            }
                            map.put(headerName, value);
                        }
                        lists.add(map);
                    }

                    String jsonArrayStr = JSON.toJSONString(lists, true);
                    File jsonFile = new File(JSON_PACKAGE + "\\" + pageName + ".json");
                    if (!jsonFile.exists()) {
                        jsonFile.getParentFile().mkdirs();
                        jsonFile.createNewFile();
                    }
                    BufferedWriter writer = new BufferedWriter(new FileWriter(jsonFile));

                    writer.write(jsonArrayStr);
                    writer.flush();
                    writer.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

算法首先吧Excel读取出来之后,根据表头字段信息分配不同的数据类型,和作用规则。然后数据保存到集合中,最后通过写入到文件中生成json文件。

展开阅读全文

没有更多推荐了,返回首页