wow_dbc 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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