【Unity】Excel配置工具
1、功能介绍
通过Excel表配置表数据,一键生成对应Excel配置表的数据结构类、数据容器类、已经二进制数据文件,加载二进制数据文件获取所有表数据
需要使用Excel读取的dll包
2、关键代码
2.1 ExcelTool类
实现一键生成Excel配置表的数据结构类、数据容器类、已经二进制数据文件
using Excel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;public class ExcelTool
{/// <summary>/// excel文件存放路径/// </summary>public static string EXCEL_PATH = Application.dataPath + "/ArtRes/Excel/";/// <summary>/// 数据结构类脚本存储路径/// </summary>public static string DATA_CLASS_PATH = Application.dataPath + "/Scripts/ExcelData/DataClass/";/// <summary>/// 容器类脚本存储路径/// </summary>public static string DATA_CONTAINER_PATH = Application.dataPath + "/Scripts/ExcelData/Container/";/// <summary>/// 二进制数据存储路径/// </summary>//public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Bianry/";/// <summary>/// 真正内容开始行号/// </summary>public static int BEGIN_INDEX = 4;[MenuItem("GameTool/GenerateExcelInfo")]private static void GenerateExcelInfo(){//加载指定路径中的所有Excel文件 用于生成对应的3个文件DirectoryInfo dInfo = Directory.CreateDirectory(EXCEL_PATH);//得到指定路径中的所有文件信息 相当于就是得到所有的Exce1表FileInfo[] files = dInfo.GetFiles();//数据容器DataTableCollection tableCollection;for (int i = 0; i < files.Length; i++){//如果不是Excel文件就不要处理if (files[i].Extension != ".xlsx" && files[i].Extension != ".xls")continue;//打开一个excel文件得到其中所有表的数据using(FileStream fs = files[i].Open(FileMode.Open, FileAccess.Read)){IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);tableCollection = excelReader.AsDataSet().Tables;fs.Close();}//遍历文件中的所有表的信息foreach (DataTable table in tableCollection){Debug.Log(table.TableName);//生成数据结构类GenerateExcelDataClass(table);//生成容器类GenerateExcelContainer(table);//生成2进制数据GenerateExcelBinary(table);}}}/// <summary>/// 生成Excel表对应的数据结构类/// </summary>/// <param name="table"></param>private static void GenerateExcelDataClass(DataTable table){//字段名行DataRow rowName = GetVariableNameRow(table);//字段类型行DataRow rowType = GetVariableTypeRow(table);//判断路径是否存在 没有的话 就创建文件夹if (!Directory.Exists(DATA_CLASS_PATH))Directory.CreateDirectory(DATA_CLASS_PATH);//如果我们要生成对应的数据结构类脚本 其实就是通过代码进行字符串拼接 然后存进文件就行了string str = "public class " + table.TableName + "\n{\n";//变量进行字符串拼接for (int i = 0; i < table.Columns.Count; i++){str += "\tpublic " + rowType[i].ToString() + " " + rowName[i].ToString() + ";\n";}str += "}\n";//把拼接好的字符串存进占地文件中File.WriteAllText(DATA_CLASS_PATH + table.TableName + ".cs", str);//刷新Project窗口AssetDatabase.Refresh();}/// <summary>/// 生成Excel表对应的数据容器类/// </summary>/// <param name="table"></param>private static void GenerateExcelContainer(DataTable table){//得到主键索引int keyIndex = GetKeyIndex(table);//得到字段类型行DataRow rowType = GetVariableTypeRow(table);//没有路径就创建路径if (!Directory.Exists(DATA_CONTAINER_PATH)) Directory.CreateDirectory (DATA_CONTAINER_PATH);string str = "using System.Collections.Generic;\n\n";str += "public class " + table.TableName + "Container" + "\n{\n";str += "\tpublic Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + ">";str += "dataDic = new Dictionary<" + rowType[keyIndex].ToString() + ", " + table.TableName + ">();\n";str += "}";File.WriteAllText(DATA_CONTAINER_PATH + table.TableName + "Container.cs", str);//刷新Project窗口AssetDatabase.Refresh();}/// <summary>/// 生成Excel 2进制数据/// </summary>/// <param name="table"></param>private static void GenerateExcelBinary(DataTable table){//没有路径创建路径if(!Directory.Exists(BinaryDataMgr.DATA_BINARY_PATH)) Directory.CreateDirectory(BinaryDataMgr.DATA_BINARY_PATH);//创建一个2进制文件进行写入using(FileStream fs = new FileStream(BinaryDataMgr.DATA_BINARY_PATH + table.TableName + ".zhou", FileMode.OpenOrCreate, FileAccess.Write)){//存储具体的Excel对应的2进制信息//1.先要存储需要写的行数//-4 因为前面4行是配置规则 不是需要记录的数据内容fs.Write(BitConverter.GetBytes(table.Rows.Count - 4), 0, 4);//2.存储主键的变量名string keyName = GetVariableNameRow(table)[GetKeyIndex(table)].ToString();byte[] bytes = Encoding.UTF8.GetBytes(keyName);//存储字符串字节数据的长度fs.Write(BitConverter.GetBytes(keyName.Length), 0, 4);//存储字符串字节数组fs.Write(bytes, 0, bytes.Length);//遍历所有内容的行 进行2进制的写入DataRow row;//得到类型行 根据类型来决定应该如何写入DataRow rowType = GetVariableTypeRow(table);for (int i = BEGIN_INDEX; i < table.Rows.Count; i++){//得到一行的数据row = table.Rows[i];for (int j = 0; j < table.Columns.Count; j++){switch(rowType[j].ToString()){case "int":fs.Write(BitConverter.GetBytes(int.Parse(row[j].ToString())), 0, 4);break;case "float":fs.Write(BitConverter.GetBytes(float.Parse(row[j].ToString())), 0, 4);break;case "bool":fs.Write(BitConverter.GetBytes(bool.Parse(row[j].ToString())), 0, 1);break;case "string":bytes = Encoding.UTF8.GetBytes(row[j].ToString());//写入字节数据的长度fs.Write(BitConverter.GetBytes(bytes.Length), 0, 4);//写入字符串字节数组fs.Write(bytes, 0, bytes.Length);break;}}}fs.Close();}AssetDatabase.Refresh();}/// <summary>/// 获取变量名所在行/// </summary>/// <param name="table"></param>/// <returns></returns>private static DataRow GetVariableNameRow(DataTable table){return table.Rows[0];}/// <summary>/// 获取变量类型所在行/// </summary>/// <param name="table"></param>/// <returns></returns>private static DataRow GetVariableTypeRow(DataTable table){return table.Rows[1];}/// <summary>/// 获取主键索引/// </summary>/// <param name="table"></param>/// <returns></returns>private static int GetKeyIndex(DataTable table){DataRow row = table.Rows[2];for (int i = 0;i < table.Columns.Count; i++){if (row[i].ToString() == "key")return i;}return 0;}}
2.2 BinaryDataMgr
保存数据,读取数据
读取Excel表生成的二进制文件,加载到内容中以供使用
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEngine;/// <summary>
/// 2进制数据管理器
/// </summary>
public class BinaryDataMgr
{private static BinaryDataMgr instance = new BinaryDataMgr();public static BinaryDataMgr Instance => instance;private BinaryDataMgr() { }/// <summary>/// 用于存储所有Excel表数据的容器/// </summary>private Dictionary<string, object> tableDic = new Dictionary<string, object>();/// <summary>/// 数据存储路径/// </summary>private static string SAVE_PATH = Application.persistentDataPath + "/Data/";/// <summary>/// 二进制数据存储路径/// </summary>public static string DATA_BINARY_PATH = Application.streamingAssetsPath + "/Bianry/";public void InitData(){//加载自己的表到内存//LoadTable<TowerInfoContainer, TowerInfo>();//LoadTable<PlayerInfo1Container, PlayerInfo1>();//LoadTable<TestInfoContainer, TestInfo>();}/// <summary>/// 加载Excel表的2进制数据到内存中/// </summary>/// <typeparam name="T">容器类名</typeparam>/// <typeparam name="K">数据结构体类名</typeparam>public void LoadTable<T, K>(){//读取Excel表对应的2进制文件 来进行解析using (FileStream fs = File.Open(DATA_BINARY_PATH + typeof(K).Name + ".zhou", FileMode.Open, FileAccess.Read)){byte[] bytes = new byte[fs.Length];fs.Read(bytes, 0, bytes.Length);fs.Close();//用于记录当前读取了多少字节int index = 0;//读取多少行数据int count = BitConverter.ToInt32 (bytes, index);index += 4;//读取主键的名字int keyNameLength = BitConverter.ToInt32 (bytes, index);index += 4;string keyName = Encoding.UTF8.GetString(bytes, index, keyNameLength);index += keyNameLength;//创建容器类对象Type contaninerType = typeof (T);object contaninerObj = Activator.CreateInstance(contaninerType);//得到数据结构类TypeType classType = typeof(K);//通过反射得到数据结构类 所有字段的信息FieldInfo[] infos = classType.GetFields();//读取每一行的信息for (int i = 0; i < count; i++){//实例化一个结构对象类 对象object dataObj = Activator.CreateInstance(classType);foreach (FieldInfo info in infos){if(info.FieldType == typeof(int)){//相当于将2进制数据转为int 然后赋值给对应字段info.SetValue(dataObj, BitConverter.ToInt32(bytes, index));index += 4;}else if (info.FieldType == typeof(float)){info.SetValue(dataObj, BitConverter.ToSingle(bytes, index));index += 4;}else if (info.FieldType == typeof(bool)){info.SetValue(dataObj, BitConverter.ToBoolean(bytes, index));index += 1;}else if (info.FieldType == typeof(string)){//读取字符串字节数组长度int length = BitConverter.ToInt32(bytes, index);index += 4;info.SetValue(dataObj, Encoding.UTF8.GetString(bytes, index, length));index += length;}}//读取完一行的数据后 将这个数据存到容器对象中object dicObj = contaninerType.GetField("dataDic").GetValue(contaninerObj);//得到容器字段对象MethodInfo mInfo = dicObj.GetType().GetMethod("Add");//得到数据结构类对象中 指定主键字段的值object keyValue = classType.GetField(keyName).GetValue(dataObj);mInfo.Invoke(dicObj, new object[] { keyValue, dataObj });}//把读取完的表记录下来tableDic.Add(typeof(T).Name, contaninerObj);fs.Close();}}/// <summary>/// 得到一张表的信息/// </summary>/// <typeparam name="T">容器类名</typeparam>/// <returns></returns>public T GetTable<T>() where T : class{string tableName = typeof(T).Name;if(tableDic.ContainsKey(tableName)){return tableDic[tableName] as T;}return null;}/// <summary>/// 存储类对象数据/// </summary>/// <param name="data"></param>/// <param name="fileName"></param>public void Save(object data, string fileName){if(!Directory.Exists(SAVE_PATH)){Directory.CreateDirectory(SAVE_PATH);}using(FileStream fs = new FileStream(SAVE_PATH + fileName + ".zhou", FileMode.OpenOrCreate, FileAccess.Write)){BinaryFormatter bf = new BinaryFormatter();bf.Serialize(fs, data);fs.Flush();fs.Close();}}/// <summary>/// 读取2进制数据转换成对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="fileName"></param>/// <returns></returns>public T Load<T>(string fileName) where T : class{if(!File.Exists(SAVE_PATH + fileName + ".zhou")){return default(T);}T data;using(FileStream fs = new FileStream(SAVE_PATH + fileName + ".zhou", FileMode.Open, FileAccess.Read)){BinaryFormatter bf = new BinaryFormatter();data = bf.Deserialize(fs) as T;fs.Close();}return data;}}
3、使用步骤
3.1 根据规则创建Excel配置表
创建的Excel表需要放置到ArtRes/Excel路径下
Excel配置规则
- 第一行:字段名
- 第二行:字段类型(字段类型一定不要配置错误,字段类型目前只支持int float bool string)如果想要在添加类型,需要ExcelTool的GenerateExcelBianary和BianryDataMgr的LoadTable方法当中对应添加读写的逻辑
- 第三行:主键是哪一个字段 需要通过key来标识主键
- 第四行:描述信息(只是给别人看,不会有别的作用)
- 第五行~第n行:就是具体数据信息
- 下方的表名决定类数据结构类,容器类,2进制文件的文件名


3.2 点击按钮GenerateExcelInfo
生成所有Excel表的数据结构类、数据结构容器类和二进制数据文件

3.3 完善BinaryDataMgr的InitData()方法,将自己创建的表进行加载
public void InitData(){//加载自己的表到内存//LoadTable<TowerInfoContainer, TowerInfo>();//LoadTable<PlayerInfo1Container, PlayerInfo1>();//LoadTable<TestInfoContainer, TestInfo>();LoadTable<WeaponItemContainer, WeaponItem>();}
3.4 初始化数据,加载数据到内存
BinaryDataMgr.Instance.InitData() 加载二进制数据到内存当中
BinaryDataMgr.Instance.GetTable<TowerInfoContainer>() 获取需要使用的表的数据
BinaryDataMgr.Instance.InitData();WeaponItemContainer data = BinaryDataMgr.Instance.GetTable<WeaponItemContainer>();foreach (var item in data.dataDic.Values){Debug.Log($"id:{item.id}-name:{item.name}-des:{item.des}-money:{item.money}-ATK:{item.atk}");}

相关文章:
【Unity】Excel配置工具
1、功能介绍 通过Excel表配置表数据,一键生成对应Excel配置表的数据结构类、数据容器类、已经二进制数据文件,加载二进制数据文件获取所有表数据 需要使用Excel读取的dll包 2、关键代码 2.1 ExcelTool类 实现一键生成Excel配置表的数据结构类、数据…...
001 线性查找(lua)
文章目录 迭代器主程序 迭代器 -- 定义一个名为 linearSearch 的函数,它接受两个参数:data(一个数组)和 target(一个目标值) function linearSearch(data, target) -- 使用 for 循环遍历数组 data&…...
数据结构之链表
储备知识: 线性表 :一对一的数据所组成的关系称为线性表。 线性表是一种数据内部的逻辑关系,与存储形式无关线性表既可以采用连续的顺序存储(数组),也可以采用离散的链式存储(链表)顺序表和链表都称为线性表 顺序存储就是将数据存…...
【小工具】 Unity相机宽度适配
相机默认是根据高度适配的,但是在部分游戏中需要根据宽度进行适配 实现步骤 定义标准屏幕宽、高判断标准屏幕宽高比与当前的是否相等通过**(标准宽度/当前宽度) (标准高度 / 当前高度)**计算缩放调整相机fieldOfView即…...
centos误删yum和python
在下载pkdg时,因为yum报错坏的解释器,然后误删了yum和python。 在下载各种版本,创建各种软连接,修改yum文件都不好使后,发现了这样一个方法:Centos: 完美解决python升级导致的yum报错问题(相信…...
WP黑格导航主题BlackCandy
BlackCandy-V2.0全新升级!首推专题区(推荐分类)更多自定义颜色!选择自己喜欢的色系,焕然一新的UI设计,更加扁平和现代化! WP黑格导航主题BlackCandy...
elasticsearch底层核心组件
Elasticsearch是一个高度可扩展的开源全文搜索和分析引擎,它基于Apache Lucene构建,并添加了分布式特性。以下是Elasticsearch的一些底层核心组件: 1. **Lucene**: - Elasticsearch基于Apache Lucene,一个高性能的…...
EasyExcel数据导入
前言: 我先讲一种网上信息的获取方式把,虽然我感觉和后面的EasyExcel没有什么关系,可能是因为这个项目这个操作很难实现,不过也可以在此记录一下,如果需要再拆出来也行。 看上了网页信息,怎么抓到&#x…...
20240630 每日AI必读资讯
📚全美TOP 5机器学习博士发帖吐槽:实验室H100数量为0! - 普林斯顿、哈佛「GPU豪门」,手上的H100至少三四百块,然而绝大多数ML博士一块H100都用不上 - 年轻的研究者们纷纷自曝自己所在学校或公司的GPU情况:…...
第十一章 Qt的模型视图
目录 一、模型/视图的原理 1、原理分析 2、模型(数据模型) 3、视图 4、代理 二、文件系统模型 1、项目练习 2、UI 设计 3、代码实现 三、字符串链表模型 QStringListModel 1、项目效果 2、项目实现 四、标准项模型(QStandardItemModel) 1、模型分析 2、项目效…...
力扣 单词规律
所用数据结构 哈希表 核心方法 判断字符串pattern 和字符串s 是否存在一对一的映射关系,按照题意,双向连接的对应规律。 思路以及实现步骤 1.字符串s带有空格,因此需要转换成字符数组进行更方便的操作,将字符串s拆分成单词列表…...
10款好用不火的PC软件,真的超好用!
AI视频生成:小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/市场上有很多软件,除了那些常见的大众化软件,还有很多不为人知的小众软件,它们的作用非常强大,简洁…...
Windows怎么实现虚拟IP
在做高可用架构时,往往需要用到虚拟IP,在linux上面有keepalived来实现虚拟ip的设置。在windows上面该怎么弄,keepalived好像也没有windows版本,我推荐一款浮动IP软件PanguVip,它可以实现windows上面虚拟ip的漂移。设置…...
【计算机网络】HTTP——基于HTTP的功能追加协议(个人笔记)
学习日期:2024.6.29 内容摘要:基于HTTP的功能追加协议和HTTP/2.0 HTTP的瓶颈与各功能追加协议 需求的产生 在Facebook、推特、微博等平台,每分每秒都会有人更新内容,我们作为用户当然希望时刻都能收到最新的消息,为…...
【多媒体】Java实现MP4视频播放器【JavaFX】【音视频播放】
在Java中播放视频可以使用多种方案,最常见的是通过Swing组件JFrame和JLabel来嵌入JMF(Java Media Framework)或Xuggler。不过,JMF已经不再被推荐使用,而Xuggler是基于DirectX的,不适用于跨平台。而且上述方案都需要使用第三方库。…...
2024 Parallels Desktop for Mac 功能介绍
Parallels Desktop的简介 Parallels Desktop是一款由Parallels公司开发的桌面虚拟化软件,它允许用户在Mac上运行Windows和其他操作系统。通过强大的技术支持,用户无需重新启动电脑即可在Mac上运行Windows应用程序,实现了真正的无缝切换。 二…...
颍川韩氏,来自战国七雄韩国的豪族
颍川是战国七雄韩国故土,韩国被秦国灭国后,王公贵族们除了坚决反秦的被杀了外,大部分都留存了下来。这些人在楚、汉反秦战争中,成为反秦统一战线的重要力量,其中两人先后被封为重新恢复的韩国的国王。 一个是横阳君韩…...
Spring boot中如何使用Thymeleaf模板
大家好,我是 网创有方。今天给大家分享下Spring boot中如何使用Thymeleaf模板。 在 IntelliJ IDEA 中使用 Thymeleaf 模板引擎来开发 Spring Boot 应用程序是相对简单的。以下是一些基本步骤,帮助你在 IDEA 中设置和使用 Thymeleaf: 创建一个…...
单片机学习(14)--DS18B20温度传感器
DS18B20温度传感器 13.1DS18B20温度传感器基础知识1.DS18B20介绍2.引脚及应用电路3.内部结构框图4.存储器框图5.单总线介绍6.单总线电路规范7.单总线时序结构8.DS18B20操作流程9.DS18B20数据帧 13.2DS18B20温度读取和温度报警器代码1.DS18B20温度读取(1)…...
ue 材质贴图Tiling repeat
材质问题,如下 贴图显然不符合逻辑,太大,并且是一次性贴图 换一个红砖纹理,就看清了,砖太大了 修改: 拖出一个TexCoord,代表坐标,拖出一个参数,代表次数,如…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
