madden-franchise 2.3.2 → 2.3.6

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.
@@ -68,7 +68,7 @@ class FranchiseFileField extends EventEmitter {
68
68
  this.emit('change');
69
69
  };
70
70
 
71
- setUnformattedValueWithoutChangeEvent(unformattedValue) {
71
+ setUnformattedValueWithoutChangeEvent(unformattedValue, suppressErrors) {
72
72
  if (!utilService.isString(unformattedValue)) { throw new Error(`Argument must be of type string. You passed in a ${typeof unformattedValue}.`); }
73
73
  else if (!utilService.stringOnlyContainsBinaryDigits(unformattedValue)) { throw new Error(`Argument must only contain binary digits 1 and 0. If you would like to set the value, please set the 'value' attribute instead.`)}
74
74
  else {
@@ -82,7 +82,7 @@ class FranchiseFileField extends EventEmitter {
82
82
  }
83
83
 
84
84
  // check for 'allowed' error - this will be true if the unformatted value is invalid.
85
- if (this._offset.enum && value === unformattedValue.padStart(this._offset.length, '0')) {
85
+ if (this._offset.enum && value === unformattedValue.padStart(this._offset.length, '0') && !suppressErrors) {
86
86
  throw new Error(`Argument is not a valid unformatted value for this field. You passed in ${value}.`)
87
87
  }
88
88
 
@@ -25,6 +25,27 @@ class FranchiseFileTable extends EventEmitter {
25
25
  };
26
26
 
27
27
  get hexData () {
28
+ this.updateBuffer();
29
+ return this.data;
30
+ };
31
+
32
+ set schema (schema) {
33
+ // console.time('set schema');
34
+ this._schema = schema;
35
+ const modifiedHeaderAttributes = this.strategy.parseHeaderAttributesFromSchema(schema, this.data, this.header);
36
+
37
+ this.header.headerSize = modifiedHeaderAttributes.headerSize;
38
+ this.header.record1Size = modifiedHeaderAttributes.record1Size;
39
+ this.header.table1StartIndex = modifiedHeaderAttributes.table1StartIndex;
40
+ this.header.table2StartIndex = modifiedHeaderAttributes.table2StartIndex;
41
+ // console.timeEnd('set schema');
42
+ };
43
+
44
+ get schema () {
45
+ return this._schema;
46
+ };
47
+
48
+ updateBuffer() {
28
49
  // need to check table2 data first because it may change offsets of the legit records.
29
50
  const table2Data = this.strategy.getTable2BinaryData(this.table2Records, this.data.slice(this.header.table2StartIndex));
30
51
 
@@ -62,23 +83,21 @@ class FranchiseFileTable extends EventEmitter {
62
83
  bufferArrays = bufferArrays.concat(table2Data);
63
84
 
64
85
  this.data = Buffer.concat(bufferArrays);
65
- return this.data;
66
86
  };
67
87
 
68
- set schema (schema) {
69
- // console.time('set schema');
70
- this._schema = schema;
71
- const modifiedHeaderAttributes = this.strategy.parseHeaderAttributesFromSchema(schema, this.data, this.header);
88
+ setNextRecordToUse(index, resetEmptyRecordMap) {
89
+ // We need to update the table header to use this row next
90
+ this.header.nextRecordToUse = index;
72
91
 
73
- this.header.headerSize = modifiedHeaderAttributes.headerSize;
74
- this.header.record1Size = modifiedHeaderAttributes.record1Size;
75
- this.header.table1StartIndex = modifiedHeaderAttributes.table1StartIndex;
76
- this.header.table2StartIndex = modifiedHeaderAttributes.table2StartIndex;
77
- // console.timeEnd('set schema');
78
- };
92
+ // And finally update the buffer to reflect this change
93
+ this.data.writeUInt32BE(index, this.header.headerOffset - 4);
79
94
 
80
- get schema () {
81
- return this._schema;
95
+ // Recalculate the empty record map if the option is set and the
96
+ // records have already been read.
97
+ if (resetEmptyRecordMap && this.recordsRead) {
98
+ this.updateBuffer();
99
+ this.emptyRecords = this._parseEmptyRecords();
100
+ }
82
101
  };
83
102
 
84
103
  // attribsToLoad is an array of attribute names (strings) to load. It is optional - if nothing is provided to the function it will load all attributes.
@@ -154,6 +173,7 @@ class FranchiseFileTable extends EventEmitter {
154
173
  }
155
174
 
156
175
  const that = this;
176
+
157
177
  record.on('change', function (changedOffset) {
158
178
  this.isChanged = true;
159
179
 
@@ -165,55 +185,75 @@ class FranchiseFileTable extends EventEmitter {
165
185
  // If so, we need to consider the record as no longer empty
166
186
  // So we need to adjust the empty records
167
187
 
168
- // Ex: Empty record list looks like this: A -> B -> C
169
- // When B's value is changed, the records need updated to: A -> C
170
- const emptyRecordReference = that.emptyRecords.get(this.index);
171
- const changedRecordWasEmpty = emptyRecordReference !== null && emptyRecordReference !== undefined;
172
-
173
- if (changedRecordWasEmpty) {
174
-
175
- // Delete the empty record entry because it is no longer empty
176
- that.emptyRecords.delete(this.index);
177
-
178
- // Set the isEmpty back to false because it's no longer empty
179
- this.isEmpty = false;
180
-
181
- // Check if there is a previous empty record
182
- const previousEmptyReference = that.emptyRecords.get(emptyRecordReference.previous);
183
-
184
- if (previousEmptyReference) {
185
- // Set the previous empty record to point to the old reference's next node
186
- that.emptyRecords.set(emptyRecordReference.previous, {
187
- previous: that.emptyRecords.get(emptyRecordReference.previous).previous,
188
- next: emptyRecordReference.next
189
- });
190
-
191
- // change the table buffer and record buffer to reflect this change
192
- changeRecordBuffers(emptyRecordReference.previous, emptyRecordReference.next);
193
- }
194
-
195
- // If there is a next empty reference, update the previous value accordingly to now point
196
- // to the current record's previous index.
197
- const nextEmptyReference = that.emptyRecords.get(emptyRecordReference.next);
198
-
199
- if (nextEmptyReference) {
200
- that.emptyRecords.set(emptyRecordReference.next, {
201
- previous: emptyRecordReference.previous,
202
- next: that.emptyRecords.get(emptyRecordReference.next).next
203
- });
204
-
205
- if (!previousEmptyReference) {
206
- // If no previous empty record exists and a next record exists, we need to update the header to
207
- // point to this record as the next record to use.
208
- updateNextRecordToUseHeaderAndBuffer(emptyRecordReference.next);
188
+ // First, check if the record's length is greater than 4 bytes (32 bits)
189
+ // If less than 4 bytes, it can never become empty...probably. :)
190
+ if (that.header.record1Size >= 4) {
191
+
192
+ // Ex: Empty record list looks like this: A -> B -> C
193
+ // When B's value is changed, the records need updated to: A -> C
194
+ const emptyRecordReference = that.emptyRecords.get(this.index);
195
+ const changedRecordWasEmpty = emptyRecordReference !== null && emptyRecordReference !== undefined;
196
+
197
+ if (changedRecordWasEmpty) {
198
+ // Check if the record's first four bytes still have a reference to the 0th table.
199
+ // If so, then the record is still considered empty.
200
+
201
+ // We need to check the buffer because the first field is not always a reference.
202
+ const referenceData = utilService.getReferenceData(this._data.slice(0, 32));
203
+ if (referenceData.tableId !== 0) {
204
+
205
+ // Delete the empty record entry because it is no longer empty
206
+ that.emptyRecords.delete(this.index);
207
+
208
+ // Set the isEmpty back to false because it's no longer empty
209
+ this.isEmpty = false;
210
+
211
+ // Check if there is a previous empty record
212
+ const previousEmptyReference = that.emptyRecords.get(emptyRecordReference.previous);
213
+
214
+ if (previousEmptyReference) {
215
+ // Set the previous empty record to point to the old reference's next node
216
+ that.emptyRecords.set(emptyRecordReference.previous, {
217
+ previous: that.emptyRecords.get(emptyRecordReference.previous).previous,
218
+ next: emptyRecordReference.next
219
+ });
220
+
221
+ // change the table buffer and record buffer to reflect this change
222
+ changeRecordBuffers(emptyRecordReference.previous, emptyRecordReference.next);
223
+ }
224
+
225
+ // If there is a next empty reference, update the previous value accordingly to now point
226
+ // to the current record's previous index.
227
+ const nextEmptyReference = that.emptyRecords.get(emptyRecordReference.next);
228
+
229
+ if (nextEmptyReference) {
230
+ that.emptyRecords.set(emptyRecordReference.next, {
231
+ previous: emptyRecordReference.previous,
232
+ next: that.emptyRecords.get(emptyRecordReference.next).next
233
+ });
234
+
235
+ if (!previousEmptyReference) {
236
+ // If no previous empty record exists and a next record exists, we need to update the header to
237
+ // point to this record as the next record to use.
238
+ that.setNextRecordToUse(emptyRecordReference.next);
239
+ }
240
+ }
241
+
242
+ // If there are no previous or next empty references
243
+ // Then there are no more empty references in the table
244
+ // Update the table header nextRecordToUse back to the table record capacity
245
+ if (!previousEmptyReference && !nextEmptyReference) {
246
+ that.setNextRecordToUse(that.header.recordCapacity);
247
+ }
209
248
  }
210
249
  }
211
-
212
- // If there are no previous or next empty references
213
- // Then there are no more empty references in the table
214
- // Update the table header nextRecordToUse back to the table record capacity
215
- if (!previousEmptyReference && !nextEmptyReference) {
216
- updateNextRecordToUseHeaderAndBuffer(that.header.recordCapacity);
250
+ else {
251
+ // The field was not empty, let's check if it is now
252
+ const referenceData = utilService.getReferenceData(this._data.slice(0, 32));
253
+ if (referenceData.tableId === 0) {
254
+ // In this case, the record is now empty. Add an entry to the empty record map
255
+ // onRecordEmpty(this);
256
+ }
217
257
  }
218
258
  }
219
259
 
@@ -221,10 +261,14 @@ class FranchiseFileTable extends EventEmitter {
221
261
  });
222
262
 
223
263
  record.on('empty', function () {
264
+ onRecordEmpty(this);
265
+ });
266
+
267
+ function onRecordEmpty(record) {
224
268
  // First, check if the record is already empty. If so, don't do anything...
225
269
  // If not empty, then we need to empty it.
226
- if (!this.isEmpty) {
227
- this.isChanged = true;
270
+ if (!record.isEmpty) {
271
+ record.isChanged = true;
228
272
  const lastEmptyRecordMapEntry = Array.from(that.emptyRecords).pop();
229
273
 
230
274
  // When we empty a record, we need to check if another empty record exists in the table.
@@ -236,11 +280,11 @@ class FranchiseFileTable extends EventEmitter {
236
280
 
237
281
  that.emptyRecords.set(lastEmptyRecordIndex, {
238
282
  previous: lastEmptyRecordMapEntry[1].previous,
239
- next: this.index
283
+ next: record.index
240
284
  });
241
285
 
242
286
  // Then we need to update the current record index to point to the record capacity.
243
- that.emptyRecords.set(this.index, {
287
+ that.emptyRecords.set(record.index, {
244
288
  previous: lastEmptyRecordIndex,
245
289
  next: that.header.recordCapacity
246
290
  });
@@ -251,32 +295,24 @@ class FranchiseFileTable extends EventEmitter {
251
295
 
252
296
  // And update both record's data. This will set the unformatted and formatted values
253
297
  // without emitting an event
254
- changeRecordBuffers(lastEmptyRecordIndex, this.index);
255
- changeRecordBuffers(this.index, that.header.recordCapacity);
298
+ changeRecordBuffers(lastEmptyRecordIndex, record.index);
299
+ changeRecordBuffers(record.index, that.header.recordCapacity);
256
300
  }
257
301
  else {
258
302
  // In this case, the record that was emptied is the first empty record in the table
259
- that.emptyRecords.set(this.index, {
303
+ that.emptyRecords.set(record.index, {
260
304
  previous: null,
261
305
  next: that.header.recordCapacity
262
306
  });
263
307
 
264
308
  // Finally update the table header and buffer so that the game uses this new empty
265
309
  // record as the next record to use (or fill)
266
- updateNextRecordToUseHeaderAndBuffer(this.index);
267
- changeRecordBuffers(this.index, that.header.recordCapacity);
310
+ that.setNextRecordToUse(record.index);
311
+ changeRecordBuffers(record.index, that.header.recordCapacity);
268
312
  }
269
313
 
270
314
  that.emit('change');
271
315
  }
272
- });
273
-
274
- function updateNextRecordToUseHeaderAndBuffer(nextRecordToUse) {
275
- // We need to update the table header to use this row next
276
- that.header.nextRecordToUse = nextRecordToUse;
277
-
278
- // And finally update the buffer to reflect this change
279
- that.data.writeUInt32BE(nextRecordToUse, that.header.headerOffset - 4);
280
316
  };
281
317
 
282
318
  function changeRecordBuffers(index, emptyRecordReference) {
@@ -287,7 +323,7 @@ class FranchiseFileTable extends EventEmitter {
287
323
  function setBufferToEmptyRecordReference(index, emptyRecordReference) {
288
324
  const recordStartIndex = that.header.table1StartIndex + (index * that.header.record1Size)
289
325
  that.data.writeUInt32BE(emptyRecordReference, recordStartIndex);
290
- that.data.fill(0, recordStartIndex + 4, recordStartIndex + that.header.record1Size);
326
+ // that.data.fill(0, recordStartIndex + 4, recordStartIndex + that.header.record1Size);
291
327
  };
292
328
 
293
329
  function setRecordInternalBuffer(index, emptyRecordReference) {
@@ -295,7 +331,7 @@ class FranchiseFileTable extends EventEmitter {
295
331
 
296
332
  const recordSizeInBits = that.header.record1Size * 8;
297
333
  if (recordSizeInBits > 32) {
298
- newData += utilService.dec2bin(0, recordSizeInBits - 32);
334
+ newData += that.records[index]._data.slice(32);
299
335
  }
300
336
 
301
337
  that.records[index].data = newData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "madden-franchise",
3
- "version": "2.3.2",
3
+ "version": "2.3.6",
4
4
  "description": "Tools to read a madden franchise file and get data from it",
5
5
  "main": "FranchiseFile.js",
6
6
  "scripts": {