游戏资源及代码生成
一、资源及c++代码生成
这里使用c#.net读写Excel及生成c++代码。
1.Excel读写及生成资源
需要添加Excel组件,暂时没有关闭excel进程的方法。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using System.IO; 8 9 using Excel = Microsoft.Office.Interop.Excel; 10 using Forms = System.Windows.Forms; 11 12 namespace ResHelper 13 { 14 class ExcelHelper 15 { 16 private string _filepath; 17 private Excel.Application _app; // excel app 18 private Excel.Workbook _workbook; 19 private Excel.Worksheet _worksheet; 20 21 public bool Open(string filepath) 22 { 23 try 24 { 25 _filepath = filepath; 26 27 _app = new Excel.Application(); 28 _workbook = _app.Workbooks.Open(filepath, Type.Missing, Type.Missing, Type.Missing 29 , Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing 30 , Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); 31 _worksheet = (Excel.Worksheet)_workbook.Worksheets[1]; 32 33 } 34 catch (System.Exception) 35 { 36 Forms.MessageBox.Show("打开Excel文件失败!"); 37 return false; 38 } 39 finally 40 { 41 } 42 return true; 43 } 44 45 public bool Create(string filepath) 46 { 47 try 48 { 49 _filepath = filepath; 50 _app = new Excel.Application(); 51 _workbook = _app.Workbooks.Open(filepath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 52 Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 53 Type.Missing, Type.Missing, Type.Missing); 54 } 55 catch (System.Exception) 56 { 57 58 } 59 finally 60 { 61 } 62 63 return true; 64 } 65 66 public string Cells(int row, int col) 67 { 68 if (row < 0 || col < 0) 69 { 70 Forms.MessageBox.Show("请输入正确的Excel某项的行号与列号,不能为负数!"); 71 } 72 return ((Excel.Range)_worksheet.Cells[row][col]).Text.ToString(); 73 } 74 75 public void Cells(int row, int col, string content) 76 { 77 if (row < 0 || col < 0) 78 { 79 Forms.MessageBox.Show("请输入正确的Excel某项的行号与列号,不能为负数!"); 80 } 81 _worksheet.Cells[row, col] = content; 82 } 83 84 public void Save(string filepath) 85 { 86 try 87 { 88 _worksheet.SaveAs(filepath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 89 Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); 90 91 } 92 catch (System.Exception) 93 { 94 95 } 96 finally 97 { 98 } 99 100 } 101 102 public void Close() 103 { 104 try 105 { 106 _app.Workbooks.Close(); 107 108 } 109 catch (System.Exception) 110 { 111 112 } 113 finally 114 { 115 _workbook = null; 116 _worksheet = null; 117 _app = null; 118 GC.Collect(); 119 } 120 121 } 122 123 public void ToRes() 124 { 125 if (string.IsNullOrEmpty(_filepath)) 126 { 127 Forms.MessageBox.Show("没有载入Excel文件!"); 128 return; 129 } 130 string txtpath = _filepath; 131 txtpath = txtpath.Substring(txtpath.LastIndexOf('\\') + 1); 132 txtpath = txtpath.Substring(0,txtpath.LastIndexOf('.') + 1); 133 txtpath += "res"; 134 txtpath = "./res/" + txtpath; 135 136 FileStream file = new FileStream(txtpath, FileMode.Create, FileAccess.Write); 137 try 138 { 139 int colnum = 0; 140 string text; 141 for (int i = 1; i < 100; ++i) 142 { 143 text = Cells(i, 1); 144 if (string.IsNullOrEmpty(text)) break; 145 colnum += 1; 146 } 147 if(colnum<1) 148 { 149 Forms.MessageBox.Show("没有列头,数据格式有误!"); 150 return; 151 } 152 string line, space = ""; 153 for(int i = 0; i<colnum; ++i) 154 { 155 space += "\t"; 156 } 157 158 159 using (StreamWriter writer = new StreamWriter(file)) 160 { 161 // 从3行开始才是数据 1.是表头 2.是备注 162 for (int row = 3; row < 10000; ++row) 163 { 164 line = ""; 165 for (int col = 1; col <= colnum; ++col) 166 { 167 text = Cells(col, row); 168 if (text.IndexOf('\t', 0) > 0) 169 { 170 Forms.MessageBox.Show("内容中不能含有tab表格符!"); 171 break; 172 } 173 text = text.Replace("\t", ",,"); 174 line += text + "\t"; 175 } 176 // 从该项开始没有数据 177 if (line == space) break; 178 line = line.Substring(0,line.LastIndexOf('\t')); 179 line += "\n"; 180 int len = line.Length; 181 writer.Write(line); 182 } 183 184 writer.Flush(); 185 writer.Dispose(); 186 writer.Close(); 187 } 188 } 189 catch (System.Exception e) 190 { 191 Forms.MessageBox.Show(e.Message); 192 return; 193 } 194 finally 195 { 196 file.Dispose(); 197 file.Close(); 198 } 199 } 200 } 201 }
2.c++代码生成
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using System.IO; 8 using System.Windows.Forms; 9 10 struct ADTType 11 { 12 public enum EType { i = 0, l, d, c, s, S, t }; 13 private EType _valueType; 14 private string _valueName; 15 16 public EType ValueType 17 { 18 set { _valueType = value; } 19 get { return _valueType; } 20 } 21 22 public string ValueName 23 { 24 set { _valueName = value; } 25 get { return _valueName; } 26 } 27 } 28 29 30 namespace ResHelper 31 { 32 class CppHelper 33 { 34 FileStream _file; 35 List<ADTType> _lstValue = new List<ADTType>(); 36 37 // 将text解释成类型及变量名 38 private string GetTypeAndValueName(string text) 39 { 40 if (string.IsNullOrEmpty(text)) return null; 41 string type, name; 42 43 if (text[0] == 'i') 44 { 45 type = "int"; 46 name = text.Substring(1); 47 48 ADTType adttype = new ADTType(); 49 adttype.ValueType = ADTType.EType.i; 50 adttype.ValueName = name; 51 _lstValue.Add(adttype); 52 53 return "\t" + type + "\t" + name + ";"; 54 } 55 else if (text[0] == 'l') 56 { 57 type = "long"; 58 name = text.Substring(1); 59 60 ADTType adttype = new ADTType(); 61 adttype.ValueType = ADTType.EType.l; 62 adttype.ValueName = name; 63 _lstValue.Add(adttype); 64 65 return "\t" + type + "\t" + name + ";"; 66 } 67 else if (text[0] == 'd') 68 { 69 type = "double"; 70 name = text.Substring(1); 71 72 ADTType adttype = new ADTType(); 73 adttype.ValueType = ADTType.EType.d; 74 adttype.ValueName = name; 75 _lstValue.Add(adttype); 76 77 return "\t" + type + "\t" + name + ";"; 78 } 79 else if (text[0] == 'c') 80 { 81 type = "char"; 82 name = text.Substring(1); 83 84 ADTType adttype = new ADTType(); 85 adttype.ValueType = ADTType.EType.c; 86 adttype.ValueName = name; 87 _lstValue.Add(adttype); 88 89 return "\t" + type + "\t" + name + ";"; 90 } 91 else if (text[0] == 's') 92 { 93 type = "char"; 94 name = text.Substring(1); 95 96 ADTType adttype = new ADTType(); 97 adttype.ValueType = ADTType.EType.s; 98 adttype.ValueName = name; 99 _lstValue.Add(adttype); 100 101 return "\t" + type + "\t" + name + "[32];"; 102 } 103 else if (text[0] == 'S') 104 { 105 type = "char"; 106 name = text.Substring(1); 107 108 ADTType adttype = new ADTType(); 109 adttype.ValueType = ADTType.EType.S; 110 adttype.ValueName = name; 111 _lstValue.Add(adttype); 112 113 return "\t" + type + "\t" + name + "[64];"; 114 } 115 else if (text[0] == 't') 116 { 117 type = "char"; 118 name = text.Substring(1); 119 120 ADTType adttype = new ADTType(); 121 adttype.ValueType = ADTType.EType.t; 122 adttype.ValueName = name; 123 _lstValue.Add(adttype); 124 125 return "\t" + type + "\t" + name + "[512];"; 126 } 127 else 128 { 129 string msg = "无法识别的列名:" + text + ",是否没有前缀!"; 130 MessageBox.Show(msg); 131 } 132 return null; 133 } 134 135 public bool CreateADT(string ADT, string ExcelName) 136 { 137 bool ret = true; 138 _lstValue.Clear(); 139 _file = new FileStream("./cpp/"+ADT+".h", FileMode.Create, FileAccess.Write); 140 try 141 { 142 List<string> lstName = new List<string>(); 143 ExcelHelper helper = new ExcelHelper(); 144 if (!helper.Open(ExcelName)) return false; 145 using (StreamWriter writer = new StreamWriter(_file)) 146 { 147 string text, name; 148 text = "#pragma once"; 149 writer.WriteLine(""); 150 writer.WriteLine(text); 151 text = "struct " + ADT; 152 writer.WriteLine(text); 153 writer.WriteLine("{"); 154 for (int i = 1; i < 100; ++i) 155 { 156 name = helper.Cells(i, 1); 157 foreach (string e in lstName) 158 { 159 if (e == name) 160 { 161 string msg = "变量名:" + name + "已存在,不能重复!"; 162 MessageBox.Show(msg); 163 return false; 164 } 165 } 166 lstName.Add(name); 167 text = GetTypeAndValueName(name); 168 if (string.IsNullOrEmpty(text)) break; 169 writer.WriteLine(text); 170 } 171 172 text = "public:"; 173 writer.WriteLine(text); 174 text = "\tbool operator == (const " + ADT +"& rhs) { return Id == rhs.Id; }"; 175 writer.WriteLine(text); 176 text = "\texplicit " + ADT + "(int id) { Id = id; }"; 177 writer.WriteLine(text); 178 text = "\texplicit " + ADT + "(const char* line);"; 179 writer.WriteLine(text); 180 writer.WriteLine("};"); 181 writer.Flush(); 182 writer.Dispose(); 183 writer.Close(); 184 helper.Close(); 185 } 186 bool islive = false; 187 foreach (string e in lstName) 188 { 189 if (e == "iId") 190 { 191 islive = true; 192 break; 193 } 194 } 195 if (!islive) 196 { 197 string msg = "必须有一个列名为:iId!" ; 198 MessageBox.Show(msg); 199 return false; 200 } 201 202 } 203 catch (System.Exception e) 204 { 205 ret = false; 206 MessageBox.Show(e.Message); 207 } 208 finally 209 { 210 _file.Dispose(); 211 _file.Close(); 212 } 213 return ret; 214 } 215 216 public bool CreateADTCpp(string ADT, string ExcelName) 217 { 218 bool ret = true; 219 _file = new FileStream("./cpp/" + ADT + ".cpp", FileMode.Create, FileAccess.Write); 220 try 221 { 222 List<string> lstName = new List<string>(); 223 using (StreamWriter writer = new StreamWriter(_file)) 224 { 225 string text; 226 text = "#include \"stdafx.h\""; 227 writer.WriteLine(text); 228 text = "#include \"" + ADT + ".h\""; 229 writer.WriteLine(text); 230 text = "#include <cstring>"; 231 writer.WriteLine(text); 232 text = "#include <stdlib.h>"; 233 writer.WriteLine(text); 234 text = "#include <cassert>"; 235 writer.WriteLine(text); 236 text = "#include \"../convertion.hpp\""; 237 writer.WriteLine(text); 238 text = "static const char split_token_define = '\t';"; 239 writer.WriteLine(text); 240 text = ADT + "::" + ADT + "(const char* liuxb_line)"; 241 writer.WriteLine(text); 242 writer.WriteLine("{"); 243 244 writer.WriteLine(" int liuxb_max_len = strlen(liuxb_line);"); 245 writer.WriteLine(" memset(this, 0 ,sizeof(*this));"); 246 writer.WriteLine(" char liuxb_tmp[512];"); 247 writer.WriteLine(" char* liuxb_text = (char*)liuxb_line;"); 248 249 foreach (ADTType e in _lstValue) 250 { 251 writer.WriteLine(" memset(liuxb_tmp, 0, sizeof(liuxb_tmp));"); 252 writer.WriteLine(" liuxb_text = string_helper::split(liuxb_text, strlen(liuxb_text), split_token_define, liuxb_tmp);"); 253 text = " " + e.ValueName + " = string_helper::"; 254 if (e.ValueType == ADTType.EType.i) 255 { 256 text += "to_int(liuxb_tmp);"; 257 writer.WriteLine(text); 258 } 259 else if (e.ValueType == ADTType.EType.l) 260 { 261 text += "to_long(liuxb_tmp);"; 262 writer.WriteLine(text); 263 } 264 else if (e.ValueType == ADTType.EType.d) 265 { 266 text += "to_double(liuxb_tmp);"; 267 writer.WriteLine(text); 268 } 269 else 270 { 271 text = " memcpy(&" + e.ValueName + ", liuxb_tmp, sizeof(" + e.ValueName + "));"; 272 writer.WriteLine(text); 273 } 274 275 } 276 writer.WriteLine("};"); 277 writer.Flush(); 278 writer.Dispose(); 279 writer.Close(); 280 } 281 } 282 catch (System.Exception e) 283 { 284 ret = false; 285 MessageBox.Show(e.Message); 286 } 287 finally 288 { 289 _file.Dispose(); 290 _file.Close(); 291 } 292 return ret; 293 } 294 } 295 }
二、装载资源的dll
有了上述工具生成res资源及c++数据结构后,再写一个通用的res资源读取的c++ dll工程即可。
1.字符串转换
1 /*------------------------------------------------------------------ 2 // 著作版权:Copyright (C) liuxb 3 // 创建时间:[liuxb|20130920] 4 // 功能描述:字符串转换 5 // 6 // 修改时间: 7 // 修改描述: 8 // 9 //----------------------------------------------------------------*/ 10 11 #pragma once 12 13 #include <stdlib.h> 14 15 // 字符串转换 16 struct string_helper 17 { 18 static int to_int(const char* value) { return atoi(value); } 19 20 static int to_long(const char* value) { return atol(value); } 21 22 static double to_double(const char* value) { return atof(value); } 23 24 // 从text中获取以c分隔的前半段字符串并写入buffer 25 // 返回src_text后半段字符串 26 static char* split(char* text, int text_len, char c, char* buffer); 27 };
1 #include "stdafx.h" 2 #include "convertion.hpp" 3 4 #include <string.h> 5 #include <stdio.h> 6 7 char* string_helper::split(char* text, int text_len, char c, char* buffer) 8 { 9 char* end = text; 10 for(int i = 0; i<text_len; ++i, ++end) 11 { 12 if(end[0] == c) 13 { 14 memcpy(buffer, text, end-text); 15 return end + 1; 16 } 17 } 18 memcpy(buffer, text, text_len); 19 return 0; 20 }
2.资源容器模板
1 /*------------------------------------------------------------------ 2 // 著作版权:Copyright (C) liuxb 3 // 创建时间:[liuxb|20130920] 4 // 功能描述:读入res资源转换成对象数组 5 // 6 // 修改时间: 7 // 修改描述: 8 // 9 //----------------------------------------------------------------*/ 10 11 #pragma once 12 13 #include <vector> 14 #include <string> 15 #include <algorithm> 16 #include <fstream> 17 18 using std::vector; 19 using std::string; 20 21 // 资源集 22 template<typename Data> 23 class resource_set 24 { 25 typedef vector<Data> vdata; 26 public: 27 typedef typename vdata::value_type value_type; 28 typedef typename vdata::iterator iterator; 29 public: 30 resource_set() 31 { 32 m_vdata = new vdata; 33 } 34 35 ~resource_set() 36 { 37 delete m_vdata; 38 } 39 40 public: 41 // 加载资源 42 bool load_resource(const char* resource_path) 43 { 44 std::ifstream file(resource_path, std::ios::binary); 45 if(!file) return false; 46 string line; 47 while (getline(file, line)) 48 { 49 value_type data(line.c_str()); 50 m_vdata->push_back(data); 51 } 52 return true; 53 } 54 55 // 查找资源 56 value_type* find(int id) 57 { 58 value_type data(id); 59 vdata::iterator it = std::find(m_vdata->begin(), m_vdata->end(), data); 60 if(it == m_vdata->end()) return 0; 61 return &(*it); 62 } 63 64 vdata& datas() { return *m_vdata; } 65 iterator begin() { return m_vdata->begin(); } 66 iterator end() { return m_vdata->end(); } 67 68 private: 69 vdata* m_vdata; 70 };
3.根据资源数据结构声明具体的资源容器导出类
1 // 下列 ifdef 块是创建使从 DLL 导出更简单的 2 // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 RES_EXPORTS 3 // 符号编译的。在使用此 DLL 的 4 // 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将 5 // RES_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的 6 // 符号视为是被导出的。 7 8 #pragma once 9 10 #ifdef RES_EXPORTS 11 #define RES_API __declspec(dllexport) 12 #else 13 #define RES_API __declspec(dllimport) 14 #endif 15 16 #include "resource_set.hpp" 17 18 #include "adt\npc_talk_dt.h" 19 #include "adt\task_dt.h" 20 21 22 class RES_API npc_talk_sc : public resource_set<npc_talk_dt> {}; 23 24 class RES_API task_sc : public resource_set<task_dt> {};
记得在dllmain.cpp中添加res.h头文件。