madden-franchise 2.5.6 → 3.0.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.
@@ -0,0 +1,17 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "type": "pwa-node",
9
+ "request": "launch",
10
+ "name": "Launch Program",
11
+ "skipFiles": [
12
+ "<node_internals>/**"
13
+ ],
14
+ "program": "${file}"
15
+ }
16
+ ]
17
+ }
package/FranchiseEnum.js CHANGED
@@ -45,7 +45,11 @@ class FranchiseEnum {
45
45
  };
46
46
 
47
47
  getMemberByValue(value) {
48
- return this._members.find((member) => { return member.name !== 'First_' && member.name !== 'Last_' && member.value === value; });
48
+ const matches = this._members.filter((member) => { return member.name !== 'First_' && member.name !== 'Last_' && member.value === value; });
49
+ if (matches.length === 0) { throw new Error(`Argument is not a valid enum value for this field. You passed in ${value}. Field name: ${this.name}`); }
50
+
51
+ const matchesNoUnderscore = matches.find((member) => { return member.name[member.name.length - 1] !== '_'});
52
+ return matchesNoUnderscore ? matchesNoUnderscore : matches[0];
49
53
  };
50
54
 
51
55
  getMemberByUnformattedValue(value) {
@@ -1,22 +1,19 @@
1
- const EventEmitter = require('events').EventEmitter;
1
+ const { BitView } = require('bit-buffer');
2
+
2
3
  const utilService = require('./services/utilService');
3
4
  const FranchiseFileTable2Field = require('./FranchiseFileTable2Field');
4
5
 
5
- class FranchiseFileField extends EventEmitter {
6
- constructor(key, value, offset) {
7
- super();
6
+ class FranchiseFileField {
7
+ constructor(key, value, offset, parent) {
8
8
  this._key = key;
9
- this._unformattedValue = value;
10
- this._value = parseFieldValue(value, offset);
9
+ this._recordBuffer = value;
10
+ this._unformattedValue = null;
11
11
  this._offset = offset;
12
+ this._parent = parent;
12
13
 
13
14
  if (offset.valueInSecondTable) {
14
- this.secondTableField = new FranchiseFileTable2Field(value, offset.maxLength);
15
+ this.secondTableField = new FranchiseFileTable2Field(this._recordBuffer.readUInt32BE(offset.offset / 8), offset.maxLength);
15
16
  this.secondTableField.fieldReference = this;
16
-
17
- this.secondTableField.on('change', function () {
18
- this._value = this.secondTableField.value;
19
- }.bind(this));
20
17
  }
21
18
  };
22
19
 
@@ -29,6 +26,14 @@ class FranchiseFileField extends EventEmitter {
29
26
  };
30
27
 
31
28
  get value () {
29
+ if (this._unformattedValue === null) {
30
+ this._setUnformattedValueIfEmpty();
31
+ }
32
+
33
+ if (this._value === null) {
34
+ this._value = this._parseFieldValue(this._unformattedValue, this._offset);
35
+ }
36
+
32
37
  return this._value;
33
38
  };
34
39
 
@@ -37,193 +42,213 @@ class FranchiseFileField extends EventEmitter {
37
42
  };
38
43
 
39
44
  get referenceData () {
45
+ if (this._unformattedValue === null) {
46
+ this._setUnformattedValueIfEmpty();
47
+ }
48
+
40
49
  if (this.isReference) {
41
- return utilService.getReferenceData(this.value);
50
+ return utilService.getReferenceDataFromBitview(this._unformattedValue, this.offset.offset);
42
51
  }
43
52
 
44
53
  return null;
45
54
  };
46
55
 
47
- set value (value) {
56
+ set value (value) {
57
+ if (this._unformattedValue === null) {
58
+ this._setUnformattedValueIfEmpty();
59
+ }
60
+
61
+ this._value = value;
62
+
48
63
  if (this.offset.valueInSecondTable) {
49
64
  this.secondTableField.value = value.toString();
50
65
  } else {
66
+ let actualValue;
67
+
51
68
  if (this.offset.isReference) {
52
69
  if (!utilService.isString(value)) { throw new Error(`Argument must be of type string. You passed in a ${typeof unformattedValue}.`); }
53
70
  else if (!utilService.stringOnlyContainsBinaryDigits(value)) { 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.`)}
71
+ const referenceData = utilService.getReferenceData(value);
72
+ this._unformattedValue.setBits(this.offset.offset, referenceData.tableId, 15);
73
+ this._unformattedValue.setBits((this.offset.offset + 15), referenceData.rowNumber, 17);
74
+ }
75
+ else if (this.offset.enum) {
76
+ try {
77
+ let theEnum = this._getEnumFromValue(value);
78
+
79
+ // Enums can have negative values and Madden negative numbers are not standard. We need to convert it here.
80
+ // Ex: In Madden, binary "1000" = -1 for an enum with a max length of 4. But for everything else, "1000" = 8, so we need to get the "real" value here.
81
+ const decimalEquivalent = utilService.bin2dec(theEnum.unformattedValue);
82
+ this._unformattedValue.setBits(this.offset.offset, decimalEquivalent, this.offset.length);
83
+ this._value = theEnum.name;
84
+ }
85
+ catch (err) {
86
+ this._value = null;
87
+ throw err;
88
+ }
54
89
  }
90
+ else {
91
+ switch (this.offset.type) {
92
+ case 's_int':
93
+ actualValue = parseInt(value);
94
+ this._value = actualValue;
95
+ this._unformattedValue.setBits(this.offset.offset, actualValue - this.offset.minValue, this.offset.length);
96
+ break;
97
+ default:
98
+ case 'int':
99
+ actualValue = parseInt(value);
100
+ this._value = actualValue;
101
+
102
+ if (this.offset.minValue || this.offset.maxValue) {
103
+ // return utilService.dec2bin(formatted, offset.length);
104
+ this._unformattedValue.setBits(this.offset.offset, actualValue, this.offset.length);
105
+ }
106
+ else {
107
+ const maxValueBinary = getMaxValueBinary(this.offset);
108
+ const maxValue = utilService.bin2dec(maxValueBinary);
109
+ // return utilService.dec2bin(formatted + maxValue, offset.length);
110
+ this._unformattedValue.setBits(this.offset.offset, actualValue + maxValue, this.offset.length);
111
+ }
112
+ break;
113
+ case 'bool':
114
+ // return (formatted == 1 || (formatted.toString().toLowerCase() == 'true')) ? '1' : '0';
115
+ actualValue = (value == 1 || (value.toString().toLowerCase() == 'true'));
116
+ this._value = actualValue;
117
+ this._unformattedValue.setBits(this.offset.offset, actualValue, 1);
118
+ break;
119
+ case 'float':
120
+ actualValue = parseFloat(value);
121
+ this._value = actualValue;
122
+ // return utilService.float2Bin(formatted);
123
+ // this._unformattedValue.setBits(this.offset.offset, value, this.offset.length);
124
+ this._unformattedValue.setFloat32(this.offset.offset, actualValue);
125
+ break;
126
+ }
127
+ }
128
+
129
+ // this._value = setFormattedValue(value, this._offset);
130
+ // this._unformattedValue = parseFormattedValue(value, this._offset);
131
+
55
132
 
56
- this._value = setFormattedValue(value, this._offset);
57
- this._unformattedValue = parseFormattedValue(value, this._offset);
58
- this.emit('change');
133
+ // this.emit('change');
134
+ this._parent.onEvent('change', this);
59
135
  }
60
136
  };
61
137
 
62
138
  get unformattedValue () {
139
+ if (this._unformattedValue === null) {
140
+ this._setUnformattedValueIfEmpty();
141
+ }
142
+
63
143
  return this._unformattedValue;
64
144
  };
65
145
 
66
146
  set unformattedValue (unformattedValue) {
67
147
  this.setUnformattedValueWithoutChangeEvent(unformattedValue);
68
- this.emit('change');
148
+ this._value = null;
149
+ this._parent.onEvent('change', this);
150
+ };
151
+
152
+ _setUnformattedValueIfEmpty() {
153
+ this._value = null;
154
+ this._unformattedValue = new BitView(this._recordBuffer, this._recordBuffer.byteOffset);
155
+ this._unformattedValue.bigEndian = true;
69
156
  };
70
157
 
71
158
  setUnformattedValueWithoutChangeEvent(unformattedValue, suppressErrors) {
72
- if (!utilService.isString(unformattedValue)) { throw new Error(`Argument must be of type string. You passed in a ${typeof unformattedValue}.`); }
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.`)}
159
+ if (!(unformattedValue instanceof BitView)) { throw new Error(`Argument must be of type BitView. You passed in a(n) ${typeof unformattedValue}.`); }
74
160
  else {
75
- let value;
76
-
77
- if (this.offset.valueInSecondTable) {
78
- value = this.secondTableField.value;
79
- }
80
- else {
81
- value = parseFieldValue(unformattedValue.padStart(this._offset.length, '0'), this._offset);
82
- }
83
-
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') && !suppressErrors) {
86
- throw new Error(`Argument is not a valid unformatted value for this field. You passed in ${value}.`)
87
- }
88
-
89
- this._value = value;
90
-
91
- if (this._offset.enum) {
92
- this._unformattedValue = this._offset.enum.getMemberByName(this._value).unformattedValue.padStart(this._offset.length, '0');
93
- }
94
- else {
95
- this._unformattedValue = unformattedValue;
96
- }
97
- }
98
- }
99
- };
100
-
101
- module.exports = FranchiseFileField;
102
-
103
- function setFormattedValue(value, offset) {
104
- if (offset.enum) {
105
- const theEnum = offset.enum.getMemberByName(value);
106
- if (!theEnum) {
107
- const theEnumByValue = offset.enum.getMemberByValue(value);
108
-
109
- if (!theEnumByValue) {
110
- throw new Error(`Argument is not a valid enum value for this field. You passed in ${value}.`);
111
- }
112
- else {
113
- return theEnumByValue.name;
114
- }
115
- } else {
116
- return theEnum.name;
161
+ this._unformattedValue = unformattedValue;
162
+ this._value = null;
117
163
  }
118
164
  }
119
165
 
120
- switch (offset.type) {
121
- case 's_int':
122
- case 'int':
123
- return parseInt(value);
124
- case 'bool':
125
- return value == 1 || (value.toString().toLowerCase() == 'true');
126
- case 'float':
127
- return parseFloat(value);
128
- default:
129
- return value.toString();
130
- }
131
- };
132
-
133
- function parseFieldValue(unformatted, offset) {
134
- if (offset.enum) {
135
- try {
136
- const theEnum = offset.enum.getMemberByUnformattedValue(unformatted);
137
-
138
- if (theEnum) {
139
- return theEnum.name;
140
- }
141
- }
142
- catch (err) {
143
- // console.log(err);
144
- }
166
+ _getEnumFromValue(value) {
167
+ const enumName = this.offset.enum.getMemberByName(value);
145
168
 
146
- return unformatted;
147
- }
148
- else {
149
- switch (offset.type) {
150
- case 's_int':
151
- return utilService.bin2dec(unformatted) + offset.minValue;
152
- case 'int':
153
- if (offset.minValue || offset.maxValue) {
154
- return utilService.bin2dec(unformatted);
155
- }
156
- else {
157
- const maxValueBinary = getMaxValueBinary(offset);
158
- const maxValue = utilService.bin2dec(maxValueBinary);
159
- const newValue = utilService.bin2dec(unformatted);
160
-
161
- if (newValue === 0) {
162
- return 0;
163
- }
164
- else {
165
- return newValue - maxValue;
166
- }
167
- }
168
- case 'bool':
169
- return unformatted[0] === '1' ? true : false;
170
- case 'float':
171
- return utilService.bin2Float(unformatted);
172
- default:
173
- return unformatted;
174
- }
175
- }
176
- };
177
-
178
- function parseFormattedValue(formatted, offset) {
179
- if (offset.enum) {
180
- const enumName = offset.enum.getMemberByName(formatted);
181
-
182
169
  if (enumName) {
183
- return enumName.unformattedValue.padStart(offset.length, '0');
170
+ return enumName;
184
171
  }
185
172
  else {
186
- const formattedEnum = offset.enum.getMemberByValue(formatted)
173
+ const formattedEnum = this.offset.enum.getMemberByValue(value)
187
174
 
188
175
  if (formattedEnum) {
189
- return formattedEnum.unformattedValue.padStart(offset.length, '0');
176
+ return formattedEnum;
190
177
  }
191
178
  else {
192
- const unformattedEnum = offset.enum.getMemberByUnformattedValue(formatted);
179
+ const unformattedEnum = this.offset.enum.getMemberByUnformattedValue(value);
193
180
 
194
181
  if (unformattedEnum) {
195
- return unformattedEnum.unformattedValue.padStart(offset.length, '0');
182
+ return unformattedEnum;
196
183
  }
197
184
  else {
198
- return offset.enum.members[0].unformattedValue.padStart(offset.length, '0');
185
+ return this.offset.enum.members[0];
199
186
  }
200
187
  }
201
188
  }
202
- }
203
- else {
204
- switch (offset.type) {
205
- case 's_int':
206
- const actualValue = parseInt(formatted);
207
- return utilService.dec2bin(actualValue - offset.minValue, offset.length);
208
- case 'int':
209
- if (offset.minValue || offset.maxValue) {
210
- return utilService.dec2bin(formatted, offset.length);
211
- }
212
- else {
213
- const maxValueBinary = getMaxValueBinary(offset);
214
- const maxValue = utilService.bin2dec(maxValueBinary);
215
- return utilService.dec2bin(formatted + maxValue, offset.length);
189
+ };
190
+
191
+ _parseFieldValue(unformatted, offset) {
192
+ if (offset.valueInSecondTable) {
193
+ return this.secondTableField.value;
194
+ }
195
+ else if (offset.enum) {
196
+ const enumUnformattedValue = utilService.dec2bin(this.unformattedValue.getBits(this.offset.offset, this.offset.length), offset.enum._maxLength);
197
+
198
+ try {
199
+ const theEnum = offset.enum.getMemberByUnformattedValue(enumUnformattedValue);
200
+
201
+ if (theEnum) {
202
+ return theEnum.name;
216
203
  }
217
- case 'bool':
218
- return (formatted == 1 || (formatted.toString().toLowerCase() == 'true')) ? '1' : '0';
219
- case 'float':
220
- return utilService.float2Bin(formatted);
221
- default:
222
- return formatted;
204
+ }
205
+ catch (err) {
206
+ // console.log(err);
207
+ }
208
+
209
+ return enumUnformattedValue;
223
210
  }
224
- }
211
+ else if (offset.isReference) {
212
+ const referenceData = utilService.getReferenceDataFromBitview(this._unformattedValue, this.offset.offset);
213
+ return utilService.getBinaryReferenceData(referenceData.tableId, referenceData.rowNumber);
214
+ }
215
+ else {
216
+ switch (offset.type) {
217
+ case 's_int':
218
+ // return utilService.bin2dec(unformatted) + offset.minValue;
219
+ return unformatted.getBits(offset.offset, offset.length) + offset.minValue;
220
+ case 'int':
221
+ if (offset.minValue || offset.maxValue) {
222
+ return unformatted.getBits(offset.offset, offset.length);
223
+ }
224
+ else {
225
+ // This is for int[] tables.
226
+
227
+ const maxValueBinary = getMaxValueBinary(offset);
228
+ const maxValue = utilService.bin2dec(maxValueBinary);
229
+ const newValue = unformatted.getBits(offset.offset, offset.length);
230
+
231
+ if (newValue === 0) {
232
+ return 0;
233
+ }
234
+ else {
235
+ return newValue - maxValue;
236
+ }
237
+ }
238
+ case 'bool':
239
+ return unformatted.getBits(offset.offset, 1) ? true : false;
240
+ case 'float':
241
+ // return utilService.bin2Float(unformatted);
242
+ return unformatted.getFloat32(offset.offset, offset.length);
243
+ default:
244
+ return unformatted;
245
+ }
246
+ }
247
+ };
225
248
  };
226
249
 
250
+ module.exports = FranchiseFileField;
251
+
227
252
  function getMaxValueBinary(offset) {
228
253
  let maxValue = '1';
229
254
  for (let j = 0; j < (offset.length - 1); j++) {
@@ -1,79 +1,62 @@
1
- const EventEmitter = require('events').EventEmitter;
2
1
  const utilService = require('./services/utilService');
3
2
  const FranchiseFileField = require('./FranchiseFileField');
4
3
 
5
- class FranchiseFileRecord extends EventEmitter {
6
- constructor(data, index, offsetTable) {
7
- super();
4
+ class FranchiseFileRecord {
5
+ constructor(data, index, offsetTable, parent) {
8
6
  this._data = data;
9
7
  this._offsetTable = offsetTable;
10
8
  this.index = index;
11
- this._fields = parseRecordFields(data, offsetTable);
9
+ this._fieldsArray = [];
10
+ this._fields = this.parseRecordFields(data, offsetTable, this);
12
11
  this.isChanged = false;
13
12
  this.arraySize = null;
14
13
  this.isEmpty = false;
15
-
16
- const that = this;
17
- this._fields.forEach((field) => {
18
- Object.defineProperty(this, field.key, {
19
- set: function (value) {
20
- field.value = value;
21
- },
22
- get: function () {
23
- return field.value;
14
+ this._parent = parent;
15
+
16
+ return new Proxy(this, {
17
+ get: function (target, prop, receiver) {
18
+ return target.fields[prop] !== undefined ? target.fields[prop].value : target[prop] !== undefined ? target[prop] : null;
19
+ },
20
+ set: function (target, prop, receiver) {
21
+ if (target.fields[prop] !== undefined) {
22
+ target.fields[prop].value = receiver;
24
23
  }
25
- });
26
-
27
- field.on('change', function () {
28
- that._data = utilService.replaceAt(that._data, this.offset.offset, this.unformattedValue);
29
-
30
- // NOTE: At this time, we can only change the size of arrays of references.
31
- // I'm not sure how to change the size of non-reference arrays, or if it's even possible.
32
- if (that.arraySize !== null && that.arraySize !== undefined) {
33
- const referenceData = this.referenceData;
34
-
35
- // If the field is outside of the previous array size and was edited to a valid reference,
36
- // then reset the array size
37
- if (this.offset.index >= that.arraySize) {
38
- if (this.isReference) {
39
- if (referenceData.tableId !== 0 || referenceData.rowNumber !== 0) {
40
- that.arraySize = this.offset.index + 1;
41
- }
42
- }
43
- }
44
-
45
- // If the value was changed to 0s, then shrink the array size to this index.
46
- else if (this.isReference) {
47
- if (referenceData.tableId === 0 && referenceData.rowNumber === 0) {
48
- that.arraySize = this.offset.index;
49
- }
50
- }
24
+ else {
25
+ target[prop] = receiver;
51
26
  }
52
27
 
53
- that.emit('change', this.offset);
54
- });
55
- });
28
+ return true;
29
+ }
30
+ })
56
31
  };
57
32
 
58
33
  get hexData () {
59
- return Buffer.from(utilService.binaryBlockToDecimalBlock(this._data));
34
+ return this._data;
60
35
  };
61
36
 
62
37
  get fields () {
63
38
  return this._fields;
64
39
  };
65
40
 
41
+ get fieldsArray () {
42
+ return this._fieldsArray;
43
+ };
44
+
45
+ get data() {
46
+ return this._data;
47
+ };
48
+
66
49
  set data (data) {
67
50
  this._data = data;
68
51
 
69
- this._fields.forEach((field) => {
52
+ this._fieldsArray.forEach((field) => {
70
53
  const unformattedValue = data.slice(field.offset.offset, field.offset.offset + field.offset.length);
71
54
  field.setUnformattedValueWithoutChangeEvent(unformattedValue);
72
55
  });
73
56
  };
74
57
 
75
58
  getFieldByKey(key) {
76
- return this._fields.find((field) => { return field.key === key; });
59
+ return this._fields[key];
77
60
  };
78
61
 
79
62
  getValueByKey(key) {
@@ -86,22 +69,57 @@ class FranchiseFileRecord extends EventEmitter {
86
69
  return field ? field.referenceData : null;
87
70
  };
88
71
 
72
+ parseRecordFields(data, offsetTable, record) {
73
+ let fields = {};
74
+
75
+ for (let j = 0; j < offsetTable.length; j++) {
76
+ const offset = offsetTable[j];
77
+
78
+ // Push the entire record buffer to the field. No need to perform a calculation
79
+ // to subarray the buffer, BitView will take care of it in the Field.
80
+ fields[offset.name] = new FranchiseFileField(offset.name, data, offset, record);
81
+
82
+ this._fieldsArray.push(fields[offset.name]);
83
+ }
84
+
85
+ return fields;
86
+ };
87
+
89
88
  empty() {
90
- this.emit('empty');
89
+ this._parent.onEvent('empty', this);
91
90
  this.isEmpty = true;
92
91
  };
93
- };
94
92
 
95
- module.exports = FranchiseFileRecord;
96
-
97
- function parseRecordFields (data, offsetTable) {
98
- let fields = [];
93
+ onEvent(name, field) {
94
+ if (name === 'change') {
95
+ // this._data = utilService.replaceAt(this._data, field.offset.offset, field.unformattedValue);
96
+
97
+ // NOTE: At field time, we can only change the size of arrays of references.
98
+ // I'm not sure how to change the size of non-reference arrays, or if it's even possible.
99
+ if (this.arraySize !== null && this.arraySize !== undefined) {
100
+ const referenceData = field.referenceData;
101
+
102
+ // If the field is outside of the previous array size and was edited to a valid reference,
103
+ // then reset the array size
104
+ if (field.offset.index >= this.arraySize) {
105
+ if (field.isReference) {
106
+ if (referenceData.tableId !== 0 || referenceData.rowNumber !== 0) {
107
+ this.arraySize = field.offset.index + 1;
108
+ }
109
+ }
110
+ }
111
+
112
+ // If the value was changed to 0s, then shrink the array size to field index.
113
+ else if (field.isReference) {
114
+ if (referenceData.tableId === 0 && referenceData.rowNumber === 0) {
115
+ this.arraySize = field.offset.index;
116
+ }
117
+ }
118
+ }
99
119
 
100
- for (let j = 0; j < offsetTable.length; j++) {
101
- const offset = offsetTable[j];
102
- const unformattedValue = data.slice(offset.offset, offset.offset + offset.length);
103
- fields.push(new FranchiseFileField(offset.name, unformattedValue, offset));
104
- }
120
+ this._parent.onEvent('change', this);
121
+ }
122
+ };
123
+ };
105
124
 
106
- return fields;
107
- };
125
+ module.exports = FranchiseFileRecord;
@@ -1,6 +1,7 @@
1
1
  const EventEmitter = require('events').EventEmitter;
2
2
  const utilService = require('./services/utilService');
3
3
  const FranchiseFileRecord = require('./FranchiseFileRecord');
4
+ const FranchiseFileTable2Field = require('./FranchiseFileTable2Field');
4
5
 
5
6
  class FranchiseFileTable extends EventEmitter {
6
7
  constructor(data, offset, gameYear, strategy) {
@@ -135,7 +136,7 @@ class FranchiseFileTable extends EventEmitter {
135
136
 
136
137
  this.records.forEach((record) => {
137
138
  let isEmptyReference = false;
138
- const firstFourBytesReference = utilService.getReferenceData(record._data.slice(0, 32));
139
+ const firstFourBytesReference = utilService.getReferenceDataFromBuffer(record.data.slice(0, 4));
139
140
 
140
141
  if (firstFourBytesReference.tableId === 0 && firstFourBytesReference.rowNumber !== 0) {
141
142
  // Could be a an empty record reference or a table2 field.
@@ -246,7 +247,6 @@ class FranchiseFileTable extends EventEmitter {
246
247
  reject('Cannot read records: Schema is not defined.');
247
248
  }
248
249
 
249
-
250
250
  let offsetTableToUse = this.offsetTable;
251
251
  const mandatoryOffsetsToLoad = this.strategy.getMandatoryOffsets(this.offsetTable);
252
252
 
@@ -260,7 +260,8 @@ class FranchiseFileTable extends EventEmitter {
260
260
  }
261
261
 
262
262
  this.loadedOffsets = offsetTableToUse;
263
- this.records = readRecords(this.data, this.header, offsetTableToUse);
263
+
264
+ this.records = readRecords(this.data, this.header, offsetTableToUse, this);
264
265
 
265
266
  if (this.header.hasSecondTable) {
266
267
  this._parseTable2Values(this.data, this.header, this.records);
@@ -276,172 +277,6 @@ class FranchiseFileTable extends EventEmitter {
276
277
  if (this.emptyRecords.get(index)) {
277
278
  record.isEmpty = true;
278
279
  }
279
-
280
- const that = this;
281
-
282
- record.on('change', function (changedOffset) {
283
- this.isChanged = true;
284
-
285
- if (that.isArray) {
286
- that.arraySizes[index] = this.arraySize;
287
- }
288
-
289
- // When a record changes, we need to check if it was previously empty
290
- // If so, we need to consider the record as no longer empty
291
- // So we need to adjust the empty records
292
-
293
- // First, check if the record's length is greater than 4 bytes (32 bits)
294
- // If less than 4 bytes, it can never become empty...probably. :)
295
- if (that.header.record1Size >= 4) {
296
-
297
- // Ex: Empty record list looks like this: A -> B -> C
298
- // When B's value is changed, the records need updated to: A -> C
299
- const emptyRecordReference = that.emptyRecords.get(this.index);
300
- const changedRecordWasEmpty = emptyRecordReference !== null && emptyRecordReference !== undefined;
301
-
302
- if (changedRecordWasEmpty) {
303
- // Check if the record's first four bytes still have a reference to the 0th table.
304
- // If so, then the record is still considered empty.
305
-
306
- // We need to check the buffer because the first field is not always a reference.
307
- const referenceData = utilService.getReferenceData(this._data.slice(0, 32));
308
- if (referenceData.tableId !== 0) {
309
-
310
- // Delete the empty record entry because it is no longer empty
311
- that.emptyRecords.delete(this.index);
312
-
313
- // Set the isEmpty back to false because it's no longer empty
314
- this.isEmpty = false;
315
-
316
- // Check if there is a previous empty record
317
- const previousEmptyReference = that.emptyRecords.get(emptyRecordReference.previous);
318
-
319
- if (previousEmptyReference) {
320
- // Set the previous empty record to point to the old reference's next node
321
- that.emptyRecords.set(emptyRecordReference.previous, {
322
- previous: that.emptyRecords.get(emptyRecordReference.previous).previous,
323
- next: emptyRecordReference.next
324
- });
325
-
326
- // change the table buffer and record buffer to reflect this change
327
- changeRecordBuffers(emptyRecordReference.previous, emptyRecordReference.next);
328
- }
329
-
330
- // If there is a next empty reference, update the previous value accordingly to now point
331
- // to the current record's previous index.
332
- const nextEmptyReference = that.emptyRecords.get(emptyRecordReference.next);
333
-
334
- if (nextEmptyReference) {
335
- that.emptyRecords.set(emptyRecordReference.next, {
336
- previous: emptyRecordReference.previous,
337
- next: that.emptyRecords.get(emptyRecordReference.next).next
338
- });
339
-
340
- if (!previousEmptyReference) {
341
- // If no previous empty record exists and a next record exists, we need to update the header to
342
- // point to this record as the next record to use.
343
- that.setNextRecordToUse(emptyRecordReference.next);
344
- }
345
- }
346
-
347
- // If there are no previous or next empty references
348
- // Then there are no more empty references in the table
349
- // Update the table header nextRecordToUse back to the table record capacity
350
- if (!previousEmptyReference && !nextEmptyReference) {
351
- that.setNextRecordToUse(that.header.recordCapacity);
352
- }
353
- }
354
- }
355
- }
356
-
357
- that.emit('change');
358
- });
359
-
360
- record.on('empty', function () {
361
- onRecordEmpty(this);
362
- });
363
-
364
- function onRecordEmpty(record) {
365
- // First, check if the record is already empty. If so, don't do anything...
366
- // If not empty, then we need to empty it.
367
- if (!record.isEmpty) {
368
- record.isChanged = true;
369
- const lastEmptyRecordMapEntry = Array.from(that.emptyRecords).pop();
370
-
371
- // When we empty a record, we need to check if another empty record exists in the table.
372
- if (lastEmptyRecordMapEntry !== null && lastEmptyRecordMapEntry !== undefined) {
373
-
374
- // If an empty record already exists, we just need to get the last empty record
375
- // and update its index to point to the current record that we want to empty.
376
- const lastEmptyRecordIndex = lastEmptyRecordMapEntry[0];
377
-
378
- that.emptyRecords.set(lastEmptyRecordIndex, {
379
- previous: lastEmptyRecordMapEntry[1].previous,
380
- next: record.index
381
- });
382
-
383
- // Then we need to update the current record index to point to the record capacity.
384
- that.emptyRecords.set(record.index, {
385
- previous: lastEmptyRecordIndex,
386
- next: that.header.recordCapacity
387
- });
388
-
389
- // Finally, we need to update the buffers to reflect this data.
390
- // First, place the new referenced index (will be the first 4 bytes)
391
- // Next, fill the rest of the record with 0s (the last bytes of the record)
392
-
393
- // And update both record's data. This will set the unformatted and formatted values
394
- // without emitting an event
395
- changeRecordBuffers(lastEmptyRecordIndex, record.index);
396
- changeRecordBuffers(record.index, that.header.recordCapacity);
397
- }
398
- else {
399
- // In this case, the record that was emptied is the first empty record in the table
400
- that.emptyRecords.set(record.index, {
401
- previous: null,
402
- next: that.header.recordCapacity
403
- });
404
-
405
- // Finally update the table header and buffer so that the game uses this new empty
406
- // record as the next record to use (or fill)
407
- that.setNextRecordToUse(record.index);
408
- changeRecordBuffers(record.index, that.header.recordCapacity);
409
- }
410
-
411
- that.emit('change');
412
- }
413
- };
414
-
415
- function changeRecordBuffers(index, emptyRecordReference) {
416
- setBufferToEmptyRecordReference(index, emptyRecordReference);
417
- setRecordInternalBuffer(index, emptyRecordReference);
418
- };
419
-
420
- function setBufferToEmptyRecordReference(index, emptyRecordReference) {
421
- const recordStartIndex = that.header.table1StartIndex + (index * that.header.record1Size)
422
- that.data.writeUInt32BE(emptyRecordReference, recordStartIndex);
423
- // that.data.fill(0, recordStartIndex + 4, recordStartIndex + that.header.record1Size);
424
- };
425
-
426
- function setRecordInternalBuffer(index, emptyRecordReference) {
427
- let newData = utilService.dec2bin(emptyRecordReference, 32);
428
-
429
- const recordSizeInBits = that.header.record1Size * 8;
430
- if (recordSizeInBits > 32) {
431
- newData += that.records[index]._data.slice(32);
432
- }
433
-
434
- that.records[index].data = newData;
435
- };
436
- });
437
-
438
- this.table2Records.forEach((record, index) => {
439
- const that = this;
440
-
441
- record.on('change', function (secondTableField) {
442
- this.isChanged = true;
443
- that.emit('change');
444
- });
445
280
  });
446
281
 
447
282
  this.recordsRead = true;
@@ -453,10 +288,8 @@ class FranchiseFileTable extends EventEmitter {
453
288
  };
454
289
 
455
290
  _parseEmptyRecords() {
456
- const firstEmptyRecord = this.header.nextRecordToUse;
457
- const sizeOfEachRecord = this.header.record1Size;
458
-
459
291
  let emptyRecords = new Map();
292
+ const firstEmptyRecord = this.header.nextRecordToUse;
460
293
 
461
294
  let previousEmptyRecordIndex = null;
462
295
  let currentEmptyRecordIndex = firstEmptyRecord;
@@ -464,7 +297,7 @@ class FranchiseFileTable extends EventEmitter {
464
297
  if (firstEmptyRecord !== this.header.recordCapacity) {
465
298
  while (currentEmptyRecordIndex !== this.header.recordCapacity) {
466
299
  // let nextEmptyRecordIndex = this.data.readUInt32BE(this.header.table1StartIndex + (currentEmptyRecordIndex * sizeOfEachRecord));
467
- let nextEmptyRecordIndex = utilService.getReferenceData(this.records[currentEmptyRecordIndex]._data.slice(0, 32)).rowNumber;
300
+ let nextEmptyRecordIndex = this.records[currentEmptyRecordIndex].data.readUInt32BE(0);
468
301
 
469
302
  emptyRecords.set(currentEmptyRecordIndex, {
470
303
  previous: previousEmptyRecordIndex,
@@ -479,21 +312,186 @@ class FranchiseFileTable extends EventEmitter {
479
312
  return emptyRecords;
480
313
  };
481
314
 
315
+ _onRecordEmpty(record) {
316
+ // First, check if the record is already empty. If so, don't do anything...
317
+ // If not empty, then we need to empty it.
318
+ if (!record.isEmpty) {
319
+ record.isChanged = true;
320
+ const lastEmptyRecordMapEntry = Array.from(this.emptyRecords).pop();
321
+
322
+ // When we empty a record, we need to check if another empty record exists in the table.
323
+ if (lastEmptyRecordMapEntry !== null && lastEmptyRecordMapEntry !== undefined) {
324
+
325
+ // If an empty record already exists, we just need to get the last empty record
326
+ // and update its index to point to the current record that we want to empty.
327
+ const lastEmptyRecordIndex = lastEmptyRecordMapEntry[0];
328
+
329
+ this.emptyRecords.set(lastEmptyRecordIndex, {
330
+ previous: lastEmptyRecordMapEntry[1].previous,
331
+ next: record.index
332
+ });
333
+
334
+ // Then we need to update the current record index to point to the record capacity.
335
+ this.emptyRecords.set(record.index, {
336
+ previous: lastEmptyRecordIndex,
337
+ next: this.header.recordCapacity
338
+ });
339
+
340
+ // Finally, we need to update the buffers to reflect this data.
341
+ // First, place the new referenced index (will be the first 4 bytes)
342
+ // Next, fill the rest of the record with 0s (the last bytes of the record)
343
+
344
+ // And update both record's data. This will set the unformatted and formatted values
345
+ // without emitting an event
346
+ this._changeRecordBuffers(lastEmptyRecordIndex, record.index);
347
+ this._changeRecordBuffers(record.index, this.header.recordCapacity);
348
+ }
349
+ else {
350
+ // In this case, the record that was emptied is the first empty record in the table
351
+ this.emptyRecords.set(record.index, {
352
+ previous: null,
353
+ next: this.header.recordCapacity
354
+ });
355
+
356
+ // Finally update the table header and buffer so that the game uses this new empty
357
+ // record as the next record to use (or fill)
358
+ this.setNextRecordToUse(record.index);
359
+ this._changeRecordBuffers(record.index, this.header.recordCapacity);
360
+ }
361
+
362
+ this.emit('change');
363
+ }
364
+ };
482
365
 
483
366
  _parseTable2Values(data, header, records) {
484
367
  const that = this;
485
368
  const secondTableData = data.slice(header.table2StartIndex);
486
369
 
487
370
  records.forEach((record) => {
488
- const fieldsReferencingSecondTable = record._fields.filter((field) => { return field.secondTableField; });
371
+ const fieldsReferencingSecondTable = record.fieldsArray.filter((field) => { return field.secondTableField; });
489
372
 
490
373
  fieldsReferencingSecondTable.forEach((field) => {
491
374
  field.secondTableField.unformattedValue = that.strategyBase.table2Field.getInitialUnformattedValue(field, secondTableData);
492
375
  field.secondTableField.strategy = that.strategyBase.table2Field;
493
376
  that.table2Records.push(field.secondTableField);
377
+ field.secondTableField.parent = that;
494
378
  });
495
379
  });
496
380
  };
381
+
382
+ _changeRecordBuffers(index, emptyRecordReference) {
383
+ this._setBufferToEmptyRecordReference(index, emptyRecordReference);
384
+ this._setRecordInternalBuffer(index, emptyRecordReference);
385
+ };
386
+
387
+ _setBufferToEmptyRecordReference(index, emptyRecordReference) {
388
+ const recordStartIndex = this.header.table1StartIndex + (index * this.header.record1Size)
389
+ this.data.writeUInt32BE(emptyRecordReference, recordStartIndex);
390
+ // that.data.fill(0, recordStartIndex + 4, recordStartIndex + that.header.record1Size);
391
+ };
392
+
393
+ _setRecordInternalBuffer(index, emptyRecordReference) {
394
+ // let newData = utilService.dec2bin(emptyRecordReference, 32);
395
+
396
+ // const recordSizeInBits = this.header.record1Size * 8;
397
+ // if (recordSizeInBits > 32) {
398
+ // newData += this.records[index]._data.slice(32);
399
+ // }
400
+
401
+ // console.log(newData);
402
+
403
+ this.records[index]._data.writeUInt32BE(emptyRecordReference, 0);
404
+ };
405
+
406
+ onEvent(name, object) {
407
+ if (object instanceof FranchiseFileRecord) {
408
+ if (name === 'change') {
409
+ object.isChanged = true;
410
+
411
+ if (this.isArray) {
412
+ this.arraySizes[object.index] = object.arraySize;
413
+ }
414
+
415
+ // When a record changes, we need to check if it was previously empty
416
+ // If so, we need to consider the record as no longer empty
417
+ // So we need to adjust the empty records
418
+
419
+ // First, check if the record's length is greater than 4 bytes (32 bits)
420
+ // If less than 4 bytes, it can never become empty...probably. :)
421
+ if (this.header.record1Size >= 4) {
422
+
423
+ // Ex: Empty record list looks like object: A -> B -> C
424
+ // When B's value is changed, the records need updated to: A -> C
425
+ const emptyRecordReference = this.emptyRecords.get(object.index);
426
+ const changedRecordWasEmpty = emptyRecordReference !== null && emptyRecordReference !== undefined;
427
+
428
+ if (changedRecordWasEmpty) {
429
+ // Check if the record's first four bytes still have a reference to the 0th table.
430
+ // If so, then the record is still considered empty.
431
+
432
+ // We need to check the buffer because the first field is not always a reference.
433
+ const referenceData = utilService.getReferenceDataFromBuffer(object.data.slice(0, 4));
434
+ if (referenceData.tableId !== 0) {
435
+
436
+ // Delete the empty record entry because it is no longer empty
437
+ this.emptyRecords.delete(object.index);
438
+
439
+ // Set the isEmpty back to false because it's no longer empty
440
+ object.isEmpty = false;
441
+
442
+ // Check if there is a previous empty record
443
+ const previousEmptyReference = this.emptyRecords.get(emptyRecordReference.previous);
444
+
445
+ if (previousEmptyReference) {
446
+ // Set the previous empty record to point to the old reference's next node
447
+ this.emptyRecords.set(emptyRecordReference.previous, {
448
+ previous: this.emptyRecords.get(emptyRecordReference.previous).previous,
449
+ next: emptyRecordReference.next
450
+ });
451
+
452
+ // change the table buffer and record buffer to reflect object change
453
+ this._changeRecordBuffers(emptyRecordReference.previous, emptyRecordReference.next);
454
+ }
455
+
456
+ // If there is a next empty reference, update the previous value accordingly to now point
457
+ // to the current record's previous index.
458
+ const nextEmptyReference = this.emptyRecords.get(emptyRecordReference.next);
459
+
460
+ if (nextEmptyReference) {
461
+ this.emptyRecords.set(emptyRecordReference.next, {
462
+ previous: emptyRecordReference.previous,
463
+ next: this.emptyRecords.get(emptyRecordReference.next).next
464
+ });
465
+
466
+ if (!previousEmptyReference) {
467
+ // If no previous empty record exists and a next record exists, we need to update the header to
468
+ // point to object record as the next record to use.
469
+ this.setNextRecordToUse(emptyRecordReference.next);
470
+ }
471
+ }
472
+
473
+ // If there are no previous or next empty references
474
+ // Then there are no more empty references in the table
475
+ // Update the table header nextRecordToUse back to the table record capacity
476
+ if (!previousEmptyReference && !nextEmptyReference) {
477
+ this.setNextRecordToUse(this.header.recordCapacity);
478
+ }
479
+ }
480
+ }
481
+ }
482
+
483
+ this.emit('change');
484
+ }
485
+ else if (name === 'empty') {
486
+ this._onRecordEmpty(object);
487
+ this.emit('change');
488
+ }
489
+ }
490
+ else if (object instanceof FranchiseFileTable2Field) {
491
+ object.isChanged = true;
492
+ this.emit('change');
493
+ }
494
+ };
497
495
  };
498
496
 
499
497
  module.exports = FranchiseFileTable;
@@ -504,13 +502,17 @@ function readOffsetTable(data, schema, header) {
504
502
  // console.log(offsetTable.sort((a,b) => { return a.indexOffset - b.indexOffset}))
505
503
  sortOffsetTableByIndexOffset();
506
504
 
505
+ function isSkippedOffset(offset) {
506
+ return offset.final || offset.const || offset.type.indexOf('()') >= 0 || offset.type === 'ITransaction_Sleep';
507
+ };
508
+
507
509
  for(let i = 0; i < offsetTable.length; i++) {
508
510
  let curOffset = offsetTable[i];
509
511
  let nextOffset = offsetTable.length > i + 1 ? offsetTable[i+1] : null;
510
512
 
511
513
  if (nextOffset) {
512
514
  let curIndex = i+2;
513
- while(nextOffset && (nextOffset.final || nextOffset.const || nextOffset.type.indexOf('()') >= 0)) {
515
+ while(nextOffset && isSkippedOffset(nextOffset)) {
514
516
  nextOffset = offsetTable[curIndex];
515
517
  curIndex += 1;
516
518
  }
@@ -541,7 +543,7 @@ function readOffsetTable(data, schema, header) {
541
543
  const currentOffset = offsetTable[currentOffsetIndex];
542
544
 
543
545
  if (currentOffset) {
544
- if (currentOffset.final || currentOffset.const || currentOffset.type.indexOf('()') >= 0) {
546
+ if (isSkippedOffset(currentOffset)) {
545
547
  currentOffsetIndex += 1;
546
548
  continue;
547
549
  }
@@ -571,7 +573,7 @@ function readOffsetTable(data, schema, header) {
571
573
  }
572
574
  });
573
575
 
574
- offsetTable = offsetTable.filter((offset) => { return !offset.final && !offset.const && offset.type.indexOf('()') === -1; });
576
+ offsetTable = offsetTable.filter((offset) => { return !(isSkippedOffset(offset)) });
575
577
  offsetTable.sort((a,b) => { return a.offset - b.offset; });
576
578
 
577
579
  for (let i = 0; i < offsetTable.length; i++) {
@@ -614,15 +616,19 @@ function readOffsetTable(data, schema, header) {
614
616
  };
615
617
  };
616
618
 
617
- function readRecords(data, header, offsetTable) {
618
- const binaryData = utilService.getBitArray(data.slice(header.table1StartIndex, header.table2StartIndex));
619
-
619
+ function readRecords(data, header, offsetTable, table) {
620
+ // const binaryData = utilService.getBitArray(data.slice(header.table1StartIndex, header.table2StartIndex));
620
621
  let records = [];
621
622
 
622
- if (binaryData) {
623
- for (let i = 0; i < binaryData.length; i += (header.record1Size * 8)) {
624
- const recordBinary = binaryData.slice(i, i + (header.record1Size * 8));
625
- records.push(new FranchiseFileRecord(recordBinary, (i / (header.record1Size * 8)), offsetTable));
623
+ if (data) {
624
+ let index = 0;
625
+
626
+ for (let i = header.table1StartIndex; i < header.table2StartIndex; i += header.record1Size) {
627
+ // const recordBinary = binaryData.slice(i, i + (header.record1Size * 8));
628
+ let record = new FranchiseFileRecord(data.slice(i, i + header.record1Size), index, offsetTable, table);
629
+ records.push(record);
630
+
631
+ index += 1;
626
632
  }
627
633
  }
628
634
 
@@ -1,9 +1,8 @@
1
1
  const EventEmitter = require('events').EventEmitter;
2
2
  const utilService = require('./services/utilService');
3
3
 
4
- class FranchiseFileTable2Field extends EventEmitter {
5
- constructor (index, maxLength) {
6
- super();
4
+ class FranchiseFileTable2Field {
5
+ constructor (index, maxLength, parent) {
7
6
  this._value = '';
8
7
  this.rawIndex = index;
9
8
  this.isChanged = false;
@@ -11,8 +10,9 @@ class FranchiseFileTable2Field extends EventEmitter {
11
10
  this.fieldReference = null;
12
11
  this.lengthAtLastSave = null;
13
12
  this._unformattedValue = null;
14
- this.index = utilService.bin2dec(index);
13
+ this.index = index;
15
14
  this._offset = this.index;
15
+ this._parent = parent;
16
16
  };
17
17
 
18
18
  get unformattedValue () {
@@ -25,38 +25,39 @@ class FranchiseFileTable2Field extends EventEmitter {
25
25
  if (this.lengthAtLastSave === null) {
26
26
  this.lengthAtLastSave = getLengthOfUnformattedValue(this._unformattedValue);
27
27
  }
28
-
29
- let formattedValue = '';
30
- const chunked = utilService.chunk(this._unformattedValue, 8);
31
- chunked.forEach((chunk) => {
32
- formattedValue += String.fromCharCode(parseInt(chunk,2));
33
- });
34
-
35
- this._value = formattedValue.replace(/\0.*$/g,'');
36
- this.emit('change');
28
+
29
+ this._value = null;
30
+ if (this._parent) {
31
+ this._parent.onEvent('change', this);
32
+ }
37
33
  };
38
34
 
39
35
  get value () {
36
+ if (this._value === null) {
37
+ this._value = this._unformattedValue.toString().replace(/\0.*$/g,'');
38
+ }
39
+
40
40
  return this._value;
41
41
  };
42
42
 
43
43
  set value (value) {
44
+ this._value = value;
45
+
44
46
  if (value.length > this.maxLength) {
45
47
  value = value.substring(0, this.maxLength);
46
48
  }
47
49
 
48
- this._value = value;
49
50
  this._unformattedValue = this._strategy.setUnformattedValueFromFormatted(value, this.maxLength);
50
51
 
51
52
  if (this.lengthAtLastSave === null) {
52
53
  this.lengthAtLastSave = getLengthOfUnformattedValue(this._unformattedValue);
53
54
  }
54
55
 
55
- this.emit('change');
56
+ this._parent.onEvent('change', this);
56
57
  };
57
58
 
58
59
  get hexData () {
59
- return Buffer.from(utilService.binaryBlockToDecimalBlock(this.unformattedValue));
60
+ return this._unformattedValue;
60
61
  };
61
62
 
62
63
  get strategy () {
@@ -76,13 +77,21 @@ class FranchiseFileTable2Field extends EventEmitter {
76
77
  this.index = offset;
77
78
 
78
79
  if (this.fieldReference) {
79
- this.fieldReference.unformattedValue = utilService.dec2bin(offset, 32);
80
+ this.fieldReference.unformattedValue.setBits(this.fieldReference.offset.offset, offset, 32);
80
81
  }
81
82
  };
83
+
84
+ get parent() {
85
+ return this._parent;
86
+ };
87
+
88
+ set parent(parent) {
89
+ this._parent = parent;
90
+ };
82
91
  };
83
92
 
84
93
  module.exports = FranchiseFileTable2Field;
85
94
 
86
95
  function getLengthOfUnformattedValue(value) {
87
- return value.length / 8;
96
+ return value.length;
88
97
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "madden-franchise",
3
- "version": "2.5.6",
3
+ "version": "3.0.0",
4
4
  "description": "Tools to read a madden franchise file and get data from it",
5
5
  "main": "FranchiseFile.js",
6
6
  "scripts": {
@@ -13,6 +13,7 @@
13
13
  "author": "matthewpanetta",
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
+ "bit-buffer": "^0.2.5",
16
17
  "node-xml-stream-parser": "^1.0.12"
17
18
  },
18
19
  "repository": {
@@ -2,8 +2,17 @@ const FranchiseFile = require('../FranchiseFile');
2
2
 
3
3
  const franchisePath = 'C:\\Users\\Matt\\Documents\\Madden NFL 20\\settings\\CAREER-M03TEST_MOD';
4
4
 
5
- const file = new FranchiseFile(franchisePath);
6
- file.on('ready', () => {
7
- const tableToFind = file.getTableById(7391);
8
- console.log(tableToFind);
9
- });
5
+ (async () => {
6
+ const file = new FranchiseFile(franchisePath);
7
+ file.on('ready', async () => {
8
+ const tableToFind = file.getTableById(7391);
9
+ console.log(tableToFind);
10
+
11
+ const user = file.getTableByName('FranchiseUser');
12
+ await user.readRecords();
13
+ const row = user.records.filter(record => !record.isEmpty).length;
14
+ console.log(row);
15
+ const teamSetting = user.records[row].getFieldByKey('TeamSetting');
16
+ console.log(teamSetting);
17
+ });
18
+ })();
@@ -1,3 +1,5 @@
1
+ const { BitView } = require("bit-buffer");
2
+
1
3
  let utilService = {};
2
4
 
3
5
  utilService.intersection = function (arrayOfArrays) {
@@ -223,6 +225,19 @@ utilService.getReferenceData = function (value) {
223
225
  }
224
226
  };
225
227
 
228
+ utilService.getReferenceDataFromBuffer = (buf) => {
229
+ let bv = new BitView(buf, buf.byteOffset);
230
+ bv.bigEndian = true;
231
+ return utilService.getReferenceDataFromBitview(bv);
232
+ };
233
+
234
+ utilService.getReferenceDataFromBitview = (bv, start = 0) => {
235
+ return {
236
+ tableId: bv.getBits(start, 15),
237
+ rowNumber: bv.getBits(start+15, 17)
238
+ };
239
+ };
240
+
226
241
  utilService.getBinaryReferenceData = function (tableId, rowNumber) {
227
242
  const referenceBinary = utilService.dec2bin(tableId, 15);
228
243
  const recordIndexBinary = utilService.dec2bin(rowNumber, 17);
@@ -12,7 +12,7 @@ FTCTable2FieldStrategy.getInitialUnformattedValue = (field, data) => {
12
12
  fieldData = fieldData.slice(0, endOfFieldIndex + 1);
13
13
  }
14
14
 
15
- return utilService.getBitArray(fieldData);
15
+ return fieldData;
16
16
  };
17
17
 
18
18
  FTCTable2FieldStrategy.setUnformattedValueFromFormatted = (formattedValue, maxLength) => {
@@ -20,10 +20,8 @@ FTCTable2FieldStrategy.setUnformattedValueFromFormatted = (formattedValue, maxLe
20
20
  // FTC strings cannot equal max length because the last character must be the null character.
21
21
  formattedValue = formattedValue.substring(0, maxLength - 1);
22
22
  }
23
-
24
- return formattedValue.split('').map((char) => {
25
- return char.charCodeAt(0).toString(2).padStart(8, '0');
26
- }).join('') + '00000000';
23
+
24
+ return Buffer.from(formattedValue + '\u0000');
27
25
  };
28
26
 
29
27
  module.exports = FTCTable2FieldStrategy;
@@ -3,7 +3,7 @@ const utilService = require('../../../services/utilService');
3
3
  let FranchiseTable2FieldStrategy = {};
4
4
 
5
5
  FranchiseTable2FieldStrategy.getInitialUnformattedValue = (field, data) => {
6
- return utilService.getBitArray(data.slice(field.secondTableField.index, (field.secondTableField.index + field.offset.maxLength)));
6
+ return data.slice(field.secondTableField.index, (field.secondTableField.index + field.offset.maxLength));
7
7
  };
8
8
 
9
9
  FranchiseTable2FieldStrategy.setUnformattedValueFromFormatted = (formattedValue, maxLength) => {
@@ -18,10 +18,8 @@ FranchiseTable2FieldStrategy.setUnformattedValueFromFormatted = (formattedValue,
18
18
  for (let i = 0; i < numberOfNullCharactersToAdd; i++) {
19
19
  valuePadded += String.fromCharCode(0);
20
20
  }
21
-
22
- return valuePadded.split('').map((char) => {
23
- return char.charCodeAt(0).toString(2).padStart(8, '0');
24
- }).join('');
21
+
22
+ return Buffer.from(valuePadded);
25
23
  };
26
24
 
27
25
  module.exports = FranchiseTable2FieldStrategy;