wow_dbc 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfaf18639315c2569395c416447ee1eb2d647497de512b0e717585b02678264d
4
- data.tar.gz: 4d51845c28b8724a3d4ff3f672b499f727f5ad65bd3e3c9d116c4962d239691f
3
+ metadata.gz: daa39b72eec7d417d3777f459f768921622f1a0977eb4a2482c5115088b1bff7
4
+ data.tar.gz: e7ed2d3250a931ba99285ef60b7b793ef1ca322f5002b677f7a2de80ae8d4eab
5
5
  SHA512:
6
- metadata.gz: 72da2052394e199fc40bd3a1aae3b54bbe1eb008c3431ce512dfd560230d2b42d7169e6ec68343efe5c7aad9d36a343205e18539a08e26b8b2df850e6c1e6146
7
- data.tar.gz: a5bb33a31ca06b09775309fcd3f56ecc509f4ce08475bcd0df40a7d9aa9d0075e1194fbda498db3143cb7ae61a3ac5c7170608f84de2278ebb9f42b26abd725d
6
+ metadata.gz: 94eeb6ab0fcde158aada012a60fc0450cae3bd52763a964d044d3b2218fb59cbc23f6923be89e9d5252f1d33ec90459d72bae7960def2dff01ebb3842c2571ef
7
+ data.tar.gz: 83178273b7310b5f1fc0abbb435f07402ecbdfff288676b61f31a1c307d9b975e829a0060f8ff6daadecddf60767bc9cfd430168ae319bfbb6a6b25d38826b92
data/README.md CHANGED
@@ -37,7 +37,16 @@ Here's a quick example of how to use WowDBC:
37
37
  require 'wow_dbc'
38
38
 
39
39
  # Correct field names for the Item.dbc file
40
- field_names = [:id, :class, :subclass, :sound_override_subclass, :material, :displayid, :inventory_type, :sheath_type]
40
+ field_names = {
41
+ id: :uint32,
42
+ class: :uint32,
43
+ subclass: :uint32,
44
+ sound_override_subclass: :int32,
45
+ material: :uint32,
46
+ displayid: :uint32,
47
+ inventory_type: :uint32,
48
+ sheath_type: :uint32
49
+ }
41
50
 
42
51
  # Open the Item.dbc file
43
52
  dbc = WowDBC::DBCFile.new('path/to/your/Item.dbc', field_names)
@@ -3,6 +3,23 @@
3
3
  #include <stdint.h>
4
4
  #include <string.h>
5
5
 
6
+ typedef enum {
7
+ TYPE_UINT32,
8
+ TYPE_INT32,
9
+ TYPE_FLOAT,
10
+ TYPE_STRING
11
+ } FieldType;
12
+
13
+ typedef struct {
14
+ FieldType type;
15
+ union {
16
+ uint32_t uint32_value;
17
+ int32_t int32_value;
18
+ float float_value;
19
+ uint32_t string_offset;
20
+ } value;
21
+ } FieldValue;
22
+
6
23
  typedef struct {
7
24
  char magic[4];
8
25
  uint32_t record_count;
@@ -13,9 +30,9 @@ typedef struct {
13
30
 
14
31
  typedef struct {
15
32
  DBCHeader header;
16
- uint32_t **records;
33
+ FieldValue **records;
17
34
  char *string_block;
18
- VALUE field_names; // Ruby array of field names
35
+ VALUE field_definitions; // Ruby hash of field names and types
19
36
  } DBCFile;
20
37
 
21
38
  static VALUE rb_mWowDBC;
@@ -38,8 +55,8 @@ static void dbc_free(void *ptr) {
38
55
  static size_t dbc_memsize(const void *ptr) {
39
56
  const DBCFile *dbc = (const DBCFile *)ptr;
40
57
  return sizeof(DBCFile) +
41
- (dbc->header.record_count * sizeof(uint32_t *)) +
42
- (dbc->header.record_count * dbc->header.field_count * sizeof(uint32_t)) +
58
+ (dbc->header.record_count * sizeof(FieldValue *)) +
59
+ (dbc->header.record_count * dbc->header.field_count * sizeof(FieldValue)) +
43
60
  dbc->header.string_block_size;
44
61
  }
45
62
 
@@ -56,13 +73,32 @@ static VALUE dbc_alloc(VALUE klass) {
56
73
  return TypedData_Wrap_Struct(klass, &dbc_data_type, dbc);
57
74
  }
58
75
 
59
- static VALUE dbc_initialize(VALUE self, VALUE filepath, VALUE field_names) {
76
+ static FieldType ruby_to_field_type(VALUE type_value) {
77
+ ID type_id;
78
+
79
+ if (RB_TYPE_P(type_value, T_SYMBOL)) {
80
+ type_id = SYM2ID(type_value);
81
+ } else if (RB_TYPE_P(type_value, T_STRING)) {
82
+ type_id = rb_intern(StringValueCStr(type_value));
83
+ } else {
84
+ rb_raise(rb_eTypeError, "Field type must be a symbol or string, got %s", rb_obj_classname(type_value));
85
+ }
86
+
87
+ if (type_id == rb_intern("uint32")) return TYPE_UINT32;
88
+ if (type_id == rb_intern("int32")) return TYPE_INT32;
89
+ if (type_id == rb_intern("float")) return TYPE_FLOAT;
90
+ if (type_id == rb_intern("string")) return TYPE_STRING;
91
+
92
+ rb_raise(rb_eArgError, "Invalid field type: %s", rb_id2name(type_id));
93
+ }
94
+
95
+ static VALUE dbc_initialize(VALUE self, VALUE filepath, VALUE field_definitions) {
60
96
  DBCFile *dbc;
61
97
  TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
62
98
 
63
99
  rb_iv_set(self, "@filepath", filepath);
64
- dbc->field_names = rb_ary_dup(field_names);
65
- rb_iv_set(self, "@field_names", dbc->field_names);
100
+ dbc->field_definitions = rb_hash_dup(field_definitions);
101
+ rb_iv_set(self, "@field_definitions", dbc->field_definitions);
66
102
 
67
103
  return self;
68
104
  }
@@ -82,7 +118,6 @@ static VALUE dbc_read(VALUE self) {
82
118
  rb_raise(rb_eIOError, "Failed to read DBC header");
83
119
  }
84
120
 
85
- // Free existing records if any
86
121
  if (dbc->records) {
87
122
  for (uint32_t i = 0; i < dbc->header.record_count; i++) {
88
123
  free(dbc->records[i]);
@@ -90,16 +125,42 @@ static VALUE dbc_read(VALUE self) {
90
125
  free(dbc->records);
91
126
  }
92
127
 
93
- dbc->records = ALLOC_N(uint32_t *, dbc->header.record_count);
128
+ dbc->records = ALLOC_N(FieldValue *, dbc->header.record_count);
129
+ VALUE field_definitions = rb_iv_get(self, "@field_definitions");
130
+ VALUE field_names = rb_funcall(field_definitions, rb_intern("keys"), 0);
131
+
94
132
  for (uint32_t i = 0; i < dbc->header.record_count; i++) {
95
- dbc->records[i] = ALLOC_N(uint32_t, dbc->header.field_count);
96
- if (fread(dbc->records[i], sizeof(uint32_t), dbc->header.field_count, file) != dbc->header.field_count) {
97
- fclose(file);
98
- rb_raise(rb_eIOError, "Failed to read DBC record");
133
+ dbc->records[i] = ALLOC_N(FieldValue, dbc->header.field_count);
134
+ for (uint32_t j = 0; j < dbc->header.field_count; j++) {
135
+ VALUE field_name = rb_ary_entry(field_names, j);
136
+ VALUE field_type = rb_hash_aref(field_definitions, field_name);
137
+
138
+ FieldType type;
139
+ if (NIL_P(field_type)) {
140
+ type = TYPE_UINT32; // Default to UINT32 if type is nil
141
+ } else {
142
+ type = ruby_to_field_type(field_type);
143
+ }
144
+ dbc->records[i][j].type = type;
145
+
146
+ if (fread(&dbc->records[i][j].value, sizeof(uint32_t), 1, file) != 1) {
147
+ fclose(file);
148
+ rb_raise(rb_eIOError, "Failed to read DBC record field");
149
+ }
150
+
151
+ switch (type) {
152
+ case TYPE_UINT32:
153
+ break;
154
+ case TYPE_INT32:
155
+ break;
156
+ case TYPE_FLOAT:
157
+ break;
158
+ case TYPE_STRING:
159
+ break;
160
+ }
99
161
  }
100
162
  }
101
163
 
102
- // Free existing string block if any
103
164
  if (dbc->string_block) {
104
165
  free(dbc->string_block);
105
166
  }
@@ -111,6 +172,7 @@ static VALUE dbc_read(VALUE self) {
111
172
  }
112
173
 
113
174
  fclose(file);
175
+
114
176
  return self;
115
177
  }
116
178
 
@@ -130,9 +192,11 @@ static VALUE dbc_write(VALUE self) {
130
192
  }
131
193
 
132
194
  for (uint32_t i = 0; i < dbc->header.record_count; i++) {
133
- if (fwrite(dbc->records[i], sizeof(uint32_t), dbc->header.field_count, file) != dbc->header.field_count) {
134
- fclose(file);
135
- rb_raise(rb_eIOError, "Failed to write DBC record");
195
+ for (uint32_t j = 0; j < dbc->header.field_count; j++) {
196
+ if (fwrite(&dbc->records[i][j].value, sizeof(uint32_t), 1, file) != 1) {
197
+ fclose(file);
198
+ rb_raise(rb_eIOError, "Failed to write DBC record field");
199
+ }
136
200
  }
137
201
  }
138
202
 
@@ -145,30 +209,62 @@ static VALUE dbc_write(VALUE self) {
145
209
  return self;
146
210
  }
147
211
 
212
+ static VALUE field_value_to_ruby(FieldValue *value, char *string_block) {
213
+ switch (value->type) {
214
+ case TYPE_UINT32:
215
+ return UINT2NUM(value->value.uint32_value);
216
+ case TYPE_INT32:
217
+ return INT2NUM(value->value.int32_value);
218
+ case TYPE_FLOAT:
219
+ return DBL2NUM(value->value.float_value);
220
+ case TYPE_STRING:
221
+ return rb_str_new2(&string_block[value->value.string_offset]);
222
+ }
223
+ return Qnil;
224
+ }
225
+
226
+ static void ruby_to_field_value(VALUE ruby_value, FieldType type, FieldValue *field_value) {
227
+ field_value->type = type;
228
+ switch (type) {
229
+ case TYPE_UINT32:
230
+ field_value->value.uint32_value = NUM2UINT(ruby_value);
231
+ break;
232
+ case TYPE_INT32:
233
+ field_value->value.int32_value = NUM2INT(ruby_value);
234
+ break;
235
+ case TYPE_FLOAT:
236
+ field_value->value.float_value = (float)NUM2DBL(ruby_value);
237
+ break;
238
+ case TYPE_STRING:
239
+ field_value->value.string_offset = NUM2UINT(ruby_value);
240
+ break;
241
+ }
242
+ }
243
+
148
244
  static VALUE dbc_create_record(VALUE self) {
149
245
  DBCFile *dbc;
150
246
  TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
151
247
 
152
248
  uint32_t new_count = dbc->header.record_count + 1;
153
- REALLOC_N(dbc->records, uint32_t *, new_count);
154
- dbc->records[new_count - 1] = ALLOC_N(uint32_t, dbc->header.field_count);
155
- memset(dbc->records[new_count - 1], 0, dbc->header.field_count * sizeof(uint32_t));
249
+ REALLOC_N(dbc->records, FieldValue *, new_count);
250
+ dbc->records[new_count - 1] = ALLOC_N(FieldValue, dbc->header.field_count);
251
+ memset(dbc->records[new_count - 1], 0, dbc->header.field_count * sizeof(FieldValue));
156
252
 
157
253
  dbc->header.record_count = new_count;
158
254
 
159
255
  return INT2FIX(new_count - 1);
160
256
  }
161
257
 
162
- static VALUE dbc_update_record(VALUE self, VALUE index, VALUE field_name, VALUE value) {
258
+ static VALUE dbc_update_record(VALUE self, VALUE index, VALUE field, VALUE value) {
163
259
  DBCFile *dbc;
164
260
  TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
165
261
 
166
262
  long idx = FIX2LONG(index);
167
263
  long field_idx = -1;
168
264
 
169
- // Find the index of the field name
170
- for (long i = 0; i < RARRAY_LEN(dbc->field_names); i++) {
171
- if (rb_eql(rb_ary_entry(dbc->field_names, i), field_name)) {
265
+ VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
266
+ for (long i = 0; i < RARRAY_LEN(field_names); i++) {
267
+ if (rb_eql(rb_ary_entry(field_names, i), field)) {
172
268
  field_idx = i;
173
269
  break;
174
270
  }
@@ -178,25 +274,25 @@ static VALUE dbc_update_record(VALUE self, VALUE index, VALUE field_name, VALUE
178
274
  rb_raise(rb_eArgError, "Invalid record or field index");
179
275
  }
180
276
 
181
- dbc->records[idx][field_idx] = NUM2UINT(value);
182
-
183
- return Qnil;
184
- }
277
+ VALUE field_type = rb_hash_aref(dbc->field_definitions, field);
278
+ FieldType type = ruby_to_field_type(field_type);
185
279
 
186
- static VALUE dbc_delete_record(VALUE self, VALUE index) {
187
- DBCFile *dbc;
188
- TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
280
+ if (type == TYPE_STRING) {
281
+ // For string fields, we need to update the string block
282
+ char *str = StringValueCStr(value);
283
+ uint32_t offset = dbc->header.string_block_size;
284
+ uint32_t str_len = strlen(str) + 1;
189
285
 
190
- long idx = FIX2LONG(index);
286
+ dbc->string_block = realloc(dbc->string_block, dbc->header.string_block_size + str_len);
287
+ memcpy(dbc->string_block + offset, str, str_len);
288
+ dbc->header.string_block_size += str_len;
191
289
 
192
- if (idx < 0 || (uint32_t)idx >= dbc->header.record_count) {
193
- rb_raise(rb_eArgError, "Invalid record index");
290
+ dbc->records[idx][field_idx].type = TYPE_STRING;
291
+ dbc->records[idx][field_idx].value.string_offset = offset;
292
+ } else {
293
+ ruby_to_field_value(value, type, &dbc->records[idx][field_idx]);
194
294
  }
195
295
 
196
- free(dbc->records[idx]);
197
- memmove(&dbc->records[idx], &dbc->records[idx + 1], (dbc->header.record_count - idx - 1) * sizeof(uint32_t *));
198
- dbc->header.record_count--;
199
-
200
296
  return Qnil;
201
297
  }
202
298
 
@@ -211,9 +307,10 @@ static VALUE dbc_get_record(VALUE self, VALUE index) {
211
307
  }
212
308
 
213
309
  VALUE record = rb_hash_new();
310
+ VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
214
311
  for (uint32_t i = 0; i < dbc->header.field_count; i++) {
215
- VALUE field_name = rb_ary_entry(dbc->field_names, i);
216
- rb_hash_aset(record, field_name, UINT2NUM(dbc->records[idx][i]));
312
+ VALUE field_name = rb_ary_entry(field_names, i);
313
+ rb_hash_aset(record, field_name, field_value_to_ruby(&dbc->records[idx][i], dbc->string_block));
217
314
  }
218
315
 
219
316
  return record;
@@ -233,47 +330,47 @@ static VALUE dbc_get_header(VALUE self) {
233
330
  return header;
234
331
  }
235
332
 
236
- static VALUE dbc_create_record_with_values(VALUE self, VALUE initial_values) {
333
+ static VALUE dbc_update_record_multi(VALUE self, VALUE index, VALUE updates) {
237
334
  DBCFile *dbc;
238
335
  TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
239
336
 
240
- uint32_t new_count = dbc->header.record_count + 1;
241
- REALLOC_N(dbc->records, uint32_t *, new_count);
242
- dbc->records[new_count - 1] = ALLOC_N(uint32_t, dbc->header.field_count);
243
- memset(dbc->records[new_count - 1], 0, dbc->header.field_count * sizeof(uint32_t));
337
+ long idx = FIX2LONG(index);
244
338
 
245
- // Set initial values
246
- if (RB_TYPE_P(initial_values, T_HASH)) {
247
- VALUE keys = rb_funcall(initial_values, rb_intern("keys"), 0);
339
+ if (idx < 0 || (uint32_t)idx >= dbc->header.record_count) {
340
+ rb_raise(rb_eArgError, "Invalid record index");
341
+ }
342
+
343
+ if (RB_TYPE_P(updates, T_HASH)) {
344
+ VALUE keys = rb_funcall(updates, rb_intern("keys"), 0);
248
345
  for (long i = 0; i < RARRAY_LEN(keys); i++) {
249
346
  VALUE key = rb_ary_entry(keys, i);
250
- VALUE value = rb_hash_aref(initial_values, key);
347
+ VALUE value = rb_hash_aref(updates, key);
251
348
  long field_idx = -1;
252
349
 
253
- for (long j = 0; j < RARRAY_LEN(dbc->field_names); j++) {
254
- if (rb_eql(rb_ary_entry(dbc->field_names, j), key)) {
350
+ VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
351
+ for (long j = 0; j < RARRAY_LEN(field_names); j++) {
352
+ if (rb_eql(rb_ary_entry(field_names, j), key)) {
255
353
  field_idx = j;
256
354
  break;
257
355
  }
258
356
  }
259
357
 
260
358
  if (field_idx >= 0 && (uint32_t)field_idx < dbc->header.field_count) {
261
- dbc->records[new_count - 1][field_idx] = NUM2UINT(value);
359
+ VALUE field_type = rb_hash_aref(dbc->field_definitions, key);
360
+ FieldType type = ruby_to_field_type(field_type);
361
+ ruby_to_field_value(value, type, &dbc->records[idx][field_idx]);
262
362
  } else {
263
- // Free the allocated memory before raising the error
264
- free(dbc->records[new_count - 1]);
265
- REALLOC_N(dbc->records, uint32_t *, dbc->header.record_count);
266
- rb_raise(rb_eArgError, "Invalid field name: %s", rb_id2name(SYM2ID(key)));
363
+ rb_raise(rb_eArgError, "Invalid field name: %"PRIsVALUE, key);
267
364
  }
268
365
  }
366
+ } else {
367
+ rb_raise(rb_eArgError, "Updates must be a hash");
269
368
  }
270
369
 
271
- dbc->header.record_count = new_count;
272
-
273
- return INT2FIX(new_count - 1);
370
+ return Qnil;
274
371
  }
275
372
 
276
- static VALUE dbc_update_record_multi(VALUE self, VALUE index, VALUE updates) {
373
+ static VALUE dbc_delete_record(VALUE self, VALUE index) {
277
374
  DBCFile *dbc;
278
375
  TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
279
376
 
@@ -283,29 +380,9 @@ static VALUE dbc_update_record_multi(VALUE self, VALUE index, VALUE updates) {
283
380
  rb_raise(rb_eArgError, "Invalid record index");
284
381
  }
285
382
 
286
- if (RB_TYPE_P(updates, T_HASH)) {
287
- VALUE keys = rb_funcall(updates, rb_intern("keys"), 0);
288
- for (long i = 0; i < RARRAY_LEN(keys); i++) {
289
- VALUE key = rb_ary_entry(keys, i);
290
- VALUE value = rb_hash_aref(updates, key);
291
- long field_idx = -1;
292
-
293
- for (long j = 0; j < RARRAY_LEN(dbc->field_names); j++) {
294
- if (rb_eql(rb_ary_entry(dbc->field_names, j), key)) {
295
- field_idx = j;
296
- break;
297
- }
298
- }
299
-
300
- if (field_idx >= 0 && (uint32_t)field_idx < dbc->header.field_count) {
301
- dbc->records[idx][field_idx] = NUM2UINT(value);
302
- } else {
303
- rb_raise(rb_eArgError, "Invalid field name: %s", rb_id2name(SYM2ID(key)));
304
- }
305
- }
306
- } else {
307
- rb_raise(rb_eArgError, "Updates must be a hash");
308
- }
383
+ free(dbc->records[idx]);
384
+ memmove(&dbc->records[idx], &dbc->records[idx + 1], (dbc->header.record_count - idx - 1) * sizeof(FieldValue *));
385
+ dbc->header.record_count--;
309
386
 
310
387
  return Qnil;
311
388
  }
@@ -315,10 +392,10 @@ static VALUE dbc_find_by(VALUE self, VALUE field, VALUE value) {
315
392
  TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
316
393
 
317
394
  long field_idx = -1;
395
+ VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
318
396
 
319
- // Find the index of the field name
320
- for (long i = 0; i < RARRAY_LEN(dbc->field_names); i++) {
321
- if (rb_eql(rb_ary_entry(dbc->field_names, i), field)) {
397
+ for (long i = 0; i < RARRAY_LEN(field_names); i++) {
398
+ if (rb_eql(rb_ary_entry(field_names, i), field)) {
322
399
  field_idx = i;
323
400
  break;
324
401
  }
@@ -331,11 +408,12 @@ static VALUE dbc_find_by(VALUE self, VALUE field, VALUE value) {
331
408
  VALUE result = rb_ary_new();
332
409
 
333
410
  for (uint32_t i = 0; i < dbc->header.record_count; i++) {
334
- if (dbc->records[i][field_idx] == NUM2UINT(value)) {
411
+ VALUE field_value = field_value_to_ruby(&dbc->records[i][field_idx], dbc->string_block);
412
+ if (rb_eql(field_value, value)) {
335
413
  VALUE record = rb_hash_new();
336
414
  for (uint32_t j = 0; j < dbc->header.field_count; j++) {
337
- VALUE field_name = rb_ary_entry(dbc->field_names, j);
338
- rb_hash_aset(record, field_name, UINT2NUM(dbc->records[i][j]));
415
+ VALUE field_name = rb_ary_entry(field_names, j);
416
+ rb_hash_aset(record, field_name, field_value_to_ruby(&dbc->records[i][j], dbc->string_block));
339
417
  }
340
418
  rb_ary_push(result, record);
341
419
  }
@@ -362,9 +440,11 @@ static VALUE dbc_write_to(VALUE self, VALUE new_filepath) {
362
440
  }
363
441
 
364
442
  for (uint32_t i = 0; i < dbc->header.record_count; i++) {
365
- if (fwrite(dbc->records[i], sizeof(uint32_t), dbc->header.field_count, file) != dbc->header.field_count) {
366
- fclose(file);
367
- rb_raise(rb_eIOError, "Failed to write DBC record");
443
+ for (uint32_t j = 0; j < dbc->header.field_count; j++) {
444
+ if (fwrite(&dbc->records[i][j].value, sizeof(uint32_t), 1, file) != 1) {
445
+ fclose(file);
446
+ rb_raise(rb_eIOError, "Failed to write DBC record");
447
+ }
368
448
  }
369
449
  }
370
450
 
@@ -377,6 +457,72 @@ static VALUE dbc_write_to(VALUE self, VALUE new_filepath) {
377
457
  return self;
378
458
  }
379
459
 
460
+ static VALUE dbc_create_record_with_values(VALUE self, VALUE values) {
461
+ DBCFile *dbc;
462
+ TypedData_Get_Struct(self, DBCFile, &dbc_data_type, dbc);
463
+
464
+ if (!RB_TYPE_P(values, T_HASH)) {
465
+ rb_raise(rb_eArgError, "Values must be a hash");
466
+ }
467
+
468
+ // Check for invalid field names
469
+ VALUE keys = rb_funcall(values, rb_intern("keys"), 0);
470
+ for (long i = 0; i < RARRAY_LEN(keys); i++) {
471
+ VALUE key = rb_ary_entry(keys, i);
472
+ if (NIL_P(rb_hash_aref(dbc->field_definitions, key))) {
473
+ rb_raise(rb_eArgError, "Invalid field name: %"PRIsVALUE, key);
474
+ }
475
+ }
476
+
477
+ uint32_t new_count = dbc->header.record_count + 1;
478
+ REALLOC_N(dbc->records, FieldValue *, new_count);
479
+ dbc->records[new_count - 1] = ALLOC_N(FieldValue, dbc->header.field_count);
480
+
481
+ VALUE field_names = rb_funcall(dbc->field_definitions, rb_intern("keys"), 0);
482
+ for (uint32_t i = 0; i < dbc->header.field_count; i++) {
483
+ VALUE field_name = rb_ary_entry(field_names, i);
484
+ VALUE value = rb_hash_aref(values, field_name);
485
+ VALUE field_type = rb_hash_aref(dbc->field_definitions, field_name);
486
+ FieldType type = ruby_to_field_type(field_type);
487
+
488
+ if (NIL_P(value)) {
489
+ // Set default values for missing fields
490
+ switch (type) {
491
+ case TYPE_UINT32:
492
+ case TYPE_INT32:
493
+ dbc->records[new_count - 1][i].value.uint32_value = 0;
494
+ break;
495
+ case TYPE_FLOAT:
496
+ dbc->records[new_count - 1][i].value.float_value = 0.0f;
497
+ break;
498
+ case TYPE_STRING:
499
+ dbc->records[new_count - 1][i].value.string_offset = 0; // Empty string
500
+ break;
501
+ }
502
+ } else {
503
+ if (type == TYPE_STRING) {
504
+ char *str = StringValueCStr(value);
505
+ uint32_t offset = dbc->header.string_block_size;
506
+ uint32_t str_len = strlen(str) + 1;
507
+
508
+ dbc->string_block = realloc(dbc->string_block, dbc->header.string_block_size + str_len);
509
+ memcpy(dbc->string_block + offset, str, str_len);
510
+ dbc->header.string_block_size += str_len;
511
+
512
+ dbc->records[new_count - 1][i].type = TYPE_STRING;
513
+ dbc->records[new_count - 1][i].value.string_offset = offset;
514
+ } else {
515
+ ruby_to_field_value(value, type, &dbc->records[new_count - 1][i]);
516
+ }
517
+ }
518
+ dbc->records[new_count - 1][i].type = type;
519
+ }
520
+
521
+ dbc->header.record_count = new_count;
522
+
523
+ return INT2FIX(new_count - 1);
524
+ }
525
+
380
526
  void Init_wow_dbc(void) {
381
527
  rb_mWowDBC = rb_define_module("WowDBC");
382
528
  rb_cDBCFile = rb_define_class_under(rb_mWowDBC, "DBCFile", rb_cObject);
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WowDBC
4
- VERSION = '1.0.3'
4
+ VERSION = '1.1.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wow_dbc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sebi