/// <summary> /// Creates a table of offsets with a corresponding data size at each offset. /// </summary> private void GetLookupSizes(SakuraiArchiveHeader *hdr) { //Read lookup offsets first and use them to get entry sizes at each offset. bint *lookup = hdr->LookupEntries; //First add each offset to the dictionary with size of 0. //The dictionary will sort the offsets automatically, in case they aren't already. for (int i = 0; i < hdr->_lookupEntryCount; i++) { int w = *(bint *)Address(lookup[i]); if (!_lookupSizes.ContainsKey(w)) { _lookupSizes.Add(w, 0); } } //Now go through each offset and calculate the size with the offset difference. int prev = 0; bool first = true; int[] t = _lookupSizes.Keys.ToArray(); for (int i = 0; i < t.Length; i++) { int off = t[i]; if (first) { first = false; } else { _lookupSizes[prev] = off - prev; } prev = off; } //The last entry in the moveset file goes right up to the lookup offsets. _lookupSizes[prev] = Offset(lookup) - prev; }
//This calculate data entry sizes. //One array will be initialized with each offset, //then another will be created and sorted using the same temp entries. //This will allow for sorted offsets and easy indexing of the same entries. internal static int[] CalculateSizes(int end, bint *hdr, int count, bool data, params int[] ignore) { Temp[] t = new Temp[count]; for (int i = 0; i < count; i++) { if (Array.IndexOf(ignore, i) < 0) { t[i] = new Temp((int)hdr[i], 0); } else { t[i] = null; } } if (data) { t[2]._offset = 1; } Temp[] sorted = t.Where(x => x != null).OrderBy(x => x._offset).ToArray(); if (data) { t[2]._offset -= 1; } for (int i = 0; i < sorted.Length; i++) { sorted[i]._size = ((i < sorted.Length - 1) ? sorted[i + 1]._offset : end) - sorted[i]._offset; } return(t.Select(x => x._size).ToArray()); }
protected override bool OnInitialize() { base.OnInitialize(); _name = Header.Name; SetSizeInternal((int)DataLength); _indexAddrs = new List <VoidPtr>(); _counts = new List <uint>(); _indices = new List <int> [5]; _indices[1] = new List <int>(); _indices[2] = new List <int>(); _indices[0] = new List <int>(); _indices[4] = new List <int>(); _indices[3] = new List <int>(); if (Offset2 - Offset1 != 0) { _indexAddrs.Add(Base + Offset1); _counts.Add((Offset2 - Offset1) / 4); } if (Offset3 - Offset2 != 0) { _indexAddrs.Add(Base + Offset2); _counts.Add((Offset3 - Offset2) / 4); } if (Offset4 - Offset3 != 0) { _indexAddrs.Add(Base + Offset3); _counts.Add((Offset4 - Offset3) / 4); } if (Offset5 - Offset4 != 0) { _indexAddrs.Add(Base + Offset4); _counts.Add((Offset5 - Offset4) / 4); } if (DataLength - Offset5 != 0) { _indexAddrs.Add(Base + Offset5); _counts.Add((DataLength - Offset5) / 4); } int i = 0; foreach (VoidPtr ptr in _indexAddrs) { bint *addr = (bint *)ptr; for (int x = 0; x < _counts[i]; x++) { if (*addr != -1) { _indices[i].Add(*addr); } addr++; } i++; } return(false); }
public ModelLinker(MDL0Header *pModel) { Header = pModel; Version = pModel->_header._version; NodeCache = new IMatrixNode[pModel->Properties->_numNodes]; bint *offsets = (bint *)((byte *)pModel + 0x10); List <MDLResourceType> iList = IndexBank[Version]; int groupCount = iList.Count; int offset; //Extract resource addresses fixed(ResourceGroup **gList = &Defs) for (int i = 0; i < groupCount; i++) { if ((offset = offsets[i]) != 0 && iList[i] != MR.None) { gList[(int)iList[i]] = (ResourceGroup *)((byte *)pModel + offset); } else if (offset > 0 && iList[i] == MR.None) { MessageBox.Show("Unused data offset " + i + " is not 0!"); } } }
//To do //protected override int OnCalculateSize(bool force) //{ // int size = CLR0.Size + 0x18 + (Children.Count * 0x10); // foreach (PAT0EntryNode n in Children) // size += n.CalculateSize(force); // return size; //} protected internal override void PostProcess(VoidPtr bresAddress, VoidPtr dataAddress, int dataLength, StringTable stringTable) { base.PostProcess(bresAddress, dataAddress, dataLength, stringTable); PAT0 *header = (PAT0 *)dataAddress; header->ResourceStringAddress = stringTable[Name] + 4; ResourceGroup *group = header->Group; group->_first = new ResourceEntry(0xFFFF, 0, 0, 0, 0); ResourceEntry *rEntry = group->First; int index = 1; foreach (PAT0EntryNode n in Children) { dataAddress = (VoidPtr)group + (rEntry++)->_dataOffset; ResourceEntry.Build(group, index++, dataAddress, (BRESString *)stringTable[n.Name]); n.PostProcess(dataAddress, stringTable); } bint *strings = header->StringOffsets1; for (int i = 0; i < _stringList1.Count; i++) { strings[i] = (int)stringTable[_stringList1[i]] + 4 - (int)strings; } strings = header->StringOffsets2; for (int i = 0; i < _stringList2.Count; i++) { strings[i] = (int)stringTable[_stringList2[i]] + 4 - (int)strings; } }
protected internal override void PostProcess(VoidPtr bresAddress, VoidPtr dataAddress, int dataLength, StringTable stringTable) { base.PostProcess(bresAddress, dataAddress, dataLength, stringTable); SHP0v3 *header = (SHP0v3 *)dataAddress; header->ResourceStringAddress = stringTable[Name] + 4; bint *stringPtr = header->StringEntries; for (int i = 0; i < header->_numEntries; i++) { stringPtr[i] = ((int)stringTable[_strings[i]] + 4) - (int)stringPtr; } ResourceGroup *group = header->Group; group->_first = new ResourceEntry(0xFFFF, 0, 0, 0, 0); ResourceEntry *rEntry = group->First; int index = 1; foreach (SHP0EntryNode n in Children) { dataAddress = (VoidPtr)group + (rEntry++)->_dataOffset; ResourceEntry.Build(group, index++, dataAddress, (BRESString *)stringTable[n.Name]); n.PostProcess(dataAddress, stringTable); } }
public override void OnPopulate() { if (DataOffset1 > 0) { new MoveDefRawDataNode("Left") { offsetID = 0 }.Initialize(this, BaseAddress + DataOffset1, 0); } if (DataOffset2 > 0) { new MoveDefRawDataNode("Right") { offsetID = 1 }.Initialize(this, BaseAddress + DataOffset2, 0); } foreach (MoveDefRawDataNode d in Children) { bint *addr = (bint *)d.Header; for (int i = 0; i < d.Size / 4; i++) { new MoveDefRawDataNode(new string((sbyte *)(BaseAddress + addr[i]))).Initialize(d, d.Header + i * 4, 4); } } }
protected override void OnWrite(VoidPtr address) { bint * offsets = (bint *)address; VoidPtr dataAddr = address; if (_entries.Count > 0) { foreach (CollisionDataEntry o in _entries) { if (!o.External) { o.Write(dataAddr); Lookup(o.LookupAddresses); dataAddr += o._calcSize; } } offsets = (bint *)dataAddr; foreach (CollisionDataEntry o in _entries) { Lookup(&offsets); *offsets++ = o.RebuildOffset; } } RebuildAddress = offsets; sListOffset *header = (sListOffset *)offsets; header->_listCount = _entries.Count; if (_entries.Count > 0) { header->_startOffset = Offset(dataAddr); Lookup(header->_startOffset.Address); } }
public unsafe void WriteScriptArray(Script[] scripts, bint *addr) { foreach (Script s in scripts) { *addr++ = WriteScript(s); } }
public override bool OnInitialize() { base.OnInitialize(); _strings.Clear(); byte *floor = (byte *)WorkingUncompressed.Address; int length = WorkingUncompressed.Length; bint *offsets = (bint *)floor; int index, last, current; for (index = 1, last = offsets[0]; last != length; index++) { current = offsets[index]; if (current < last || current > length) { break; } _strings.Add(MSBinDecoder.DecodeString(floor + last, current - last)); last = current; } return(false); }
protected internal override void PostProcess(VoidPtr dataAddress, StringTable stringTable) { base.PostProcess(dataAddress, stringTable); SCN0LightSet *header = (SCN0LightSet *)dataAddress; if (_ambientLight != null) { header->AmbientStringAddress = stringTable[_ambientLight] + 4; } else { header->_ambNameOffset = 0; } int i; bint *strings = header->StringOffsets; for (i = 0; i < _entries.Count; i++) { strings[i] = (int)stringTable[_entries[i]] + 4 - (int)strings; } while (i < 8) { strings[i++] = 0; } }
/// <summary> /// This writes changed data without rewriting the entire file /// </summary> public unsafe void QuickWrite() { VoidPtr origAddr = _rootNode.WorkingUncompressed.Address; SakuraiArchiveHeader *hdr = (SakuraiArchiveHeader *)origAddr; VoidPtr origBase = hdr->BaseAddress; var changed = _rootNode.RebuildEntries; if (changed.Count != 0) { foreach (var entry in changed) { int eOffset = entry._offset; bint *lookup = hdr->LookupEntries; int currentOffset = *(bint *)(origBase + *lookup++); for (int i = 0; i < hdr->_lookupEntryCount - 1; i++, lookup++) { int nextOffset = *(bint *)(origBase + *lookup); if (eOffset >= currentOffset && eOffset < nextOffset) { int newSize = entry._calcSize; int oldSize = entry._initSize; int diff = newSize - oldSize; for (int x = i; x < hdr->_lookupEntryCount; x++) { lookup[x] += diff; } } currentOffset = nextOffset; } } } }
public void Write(VoidPtr address) { LABLHeader *header = (LABLHeader *)address; int count = _labels.Count; VoidPtr dataAddr = address + 12 + count * 4; bint * list = (bint *)(address + 8); LabelItem label; int size; byte * pad; for (int i = 0; i < count;) { label = _labels[i++]; list[i] = (int)dataAddr - (int)list; ((LABLEntry *)dataAddr)->Set(label.Tag, label.String); dataAddr += label.DataLen; } pad = (byte *)dataAddr; for (size = dataAddr - address; (size & 0x1F) != 0; size++) { *pad++ = 0; } header->Set(size, count); }
protected internal override void OnRebuild(VoidPtr address, int length, bool force) { bint *addr = (bint *)address; foreach (MoveDefBoneIndexNode b in Children) { b.Rebuild(addr++, 4, true); } _entryOffset = addr; FDefBoneRef2 *header = (FDefBoneRef2 *)addr; header->_handNBoneIndex1 = HandNBoneIndex1; header->_handNBoneIndex2 = HandNBoneIndex2; header->_handNBoneIndex3 = HandNBoneIndex3; header->_handNBoneIndex4 = HandNBoneIndex4; header->_count = Children.Count; if (Children.Count > 0) { header->_offset = (int)address - (int)_rebuildBase; _lookupOffsets.Add((int)header->_offset.Address - (int)_rebuildBase); } }
protected override void OnWrite(VoidPtr address) { bint *addr = (bint *)address; foreach (BoneIndexValue b in _bones) { b.Write(addr++); } RebuildAddress = addr; sDataBoneRef2 *header = (sDataBoneRef2 *)addr; header->_handNBoneIndex1 = HandNBoneIndex1; header->_handNBoneIndex2 = HandNBoneIndex2; header->_handNBoneIndex3 = HandNBoneIndex3; header->_handNBoneIndex4 = HandNBoneIndex4; header->_count = _bones.Count; if (_bones.Count > 0) { header->_offset = Offset(address); _lookupOffsets.Add(&header->_offset); } }
public override void OnRebuild(VoidPtr address, int length, bool force) { base.OnRebuild(address, length, force); SCN0Camera *header = (SCN0Camera *)address; header->_projType = (int)_projType; header->_flags2 = (ushort)(2 + (int)_type); header->_userDataOffset = 0; int newFlags1 = 0; bint *values = (bint *)&header->_position; for (int i = 0; i < 15; i++) { EncodeFrames(GetKeys(i), ref keyframeAddr, &values[i], ref newFlags1, (int)Ordered[i]); } if (_userEntries.Count > 0) { _userEntries.Write(header->UserData = (VoidPtr)header + SCN0Camera.Size); } header->_flags1 = (ushort)newFlags1; }
protected internal override void PostProcess(VoidPtr scn0Address, VoidPtr dataAddress, StringTable stringTable) { base.PostProcess(scn0Address, dataAddress, stringTable); SCN0LightSet *header = (SCN0LightSet *)dataAddress; if (_ambient != null && !String.IsNullOrEmpty(_ambient.Name)) { header->AmbientStringAddress = stringTable[_ambient.Name] + 4; } else { header->_ambNameOffset = 0; } int i; bint *strings = header->StringOffsets; for (i = 0; i < 8; i++) { if (!String.IsNullOrEmpty(GetLightName(i))) { strings[i] = (int)stringTable[GetLightName(i)] + 4 - (int)strings; } else { break; } } while (i < 8) { strings[i++] = 0; } }
public ModelLinker(MDL0Header *pModel) { Header = pModel; Version = pModel->_header._version; NodeCache = pModel->Properties == null ? new IMatrixNode[0] : new IMatrixNode[pModel->Properties->_numNodes]; BoneCache = new MDL0BoneNode[0]; bint *offsets = (bint *)((byte *)pModel + 0x10); if (Version >= 9 && Version <= 11) { List <MDLResourceType> iList = IndexBank[Version]; int groupCount = iList.Count; int offset; //Extract resource addresses fixed(ResourceGroup **gList = &Defs) for (int i = 0; i < groupCount; i++) { if ((offset = offsets[i]) > 0) { gList[(int)iList[i]] = (ResourceGroup *)((byte *)pModel + offset); } } } }
protected override void OnWrite(VoidPtr address) { *(CollisionType *)address = _type; switch (_type) { case CollisionType.Type0: bint *addr = (bint *)address; foreach (BoneIndexValue b in _bones) { b.Write(addr++); } RebuildAddress = addr; sCollData0 *data1 = (sCollData0 *)addr; data1->unk1 = _length; data1->unk2 = _width; data1->unk3 = _height; if (_bones.Count > 0) { data1->_list._startOffset = Offset(address); Lookup(&data1->_list._startOffset); } data1->_list._listCount = _bones.Count; break; case CollisionType.Type1: RebuildAddress = address; sCollData1 *data2 = (sCollData1 *)address; data2->unk1 = _length; data2->unk2 = _width; data2->unk3 = _height; break; case CollisionType.Type2: RebuildAddress = address; sCollData2 *data3 = (sCollData2 *)address; data3->flags = _flags; data3->unk1 = _length; data3->unk2 = _width; data3->unk3 = _height; if ((_flags & 2) == 2) { data3->unk4 = _unknown; } break; } }
public override bool OnInitialize() { bint *addr = (bint *)Data; dataAddr = addr[0].OffsetAddress; count = addr[1]; return(base.OnInitialize()); }
public Model(MDL0Header *pModel) { int version = pModel->_header._version; bint *offsets = (bint *)((byte *)pModel + 0x10); List <MDLResourceType> iList = ModelLinker.IndexBank[version]; List <Bone> boneList = ExtractBones((ResourceGroup *)((byte *)pModel + offsets[iList.IndexOf(MDLResourceType.Bones)])); }
public static void EncodeSRT0Keyframes(KeyframeCollection kf, VoidPtr entryAddress, VoidPtr dataAddress, SRT0Code code) { SRT0TextureEntry *header = (SRT0TextureEntry *)entryAddress; header->Code = code; bint *pOffset = (bint *)entryAddress + 1; int index = 0; //Write values/offset and encode groups for (int type = 0; type < 3; type++) { bool has = false; switch (type) { case 0: has = !code.NoScale; break; case 1: has = !code.NoRotation; break; case 2: has = !code.NoTranslation; break; } for (int axis = 0; axis < (type == 1 ? 1 : 2); axis++, index++) { if (has) { if (code.ScaleIsotropic && type == 0) { if (axis == 0) { if (code.FixedScaleX) { *(bfloat *)pOffset++ = kf._keyArrays[0]._keyRoot._next._value; } else { *pOffset = (int)dataAddress - (int)pOffset; pOffset++; dataAddress += EncodeEntry(index, AnimDataFormat.I12, kf, dataAddress); } } } else { //This gets the fixed bit. Same order, so it can be indexed if (code._data[5 + index]) { *(bfloat *)pOffset++ = kf._keyArrays[index]._keyRoot._next._value; } else { *pOffset = (int)dataAddress - (int)pOffset; pOffset++; dataAddress += EncodeEntry(index, AnimDataFormat.I12, kf, dataAddress); } } } } } }
public override bool OnInitialize() { base.OnInitialize(); _strings.Clear(); if (_version == 4) { SHP0v4 *header = Header4; if ((_name == null) && (header->_stringOffset != 0)) { _name = header->ResourceString; } _numFrames = header->_numFrames; _loop = header->_loop != 0; bint *stringOffset = header->StringEntries; for (int i = 0; i < header->_numEntries; i++) { _strings.Add(new String((sbyte *)stringOffset + stringOffset[i])); } if (header->_origPathOffset > 0) { _originalPath = header->OrigPath; } (_userEntries = new UserDataCollection()).Read(header->UserData); return(header->Group->_numEntries > 0); } else { SHP0v3 *header = Header3; if ((_name == null) && (header->_stringOffset != 0)) { _name = header->ResourceString; } _numFrames = header->_numFrames; _loop = header->_loop != 0; bint *stringOffset = header->StringEntries; for (int i = 0; i < header->_numEntries; i++) { _strings.Add(new String((sbyte *)stringOffset + stringOffset[i])); } if (header->_origPathOffset > 0) { _originalPath = header->OrigPath; } return(header->Group->_numEntries > 0); } }
protected override void OnParse(VoidPtr address) { hdr = *(DataCommonHeader *)address; bint *v = (bint *)address; int offset = 0; //Calculate the sizes of each section using their offsets, //in order of appearance int[] sizes = SakuraiArchiveNode.CalculateSizes(_root._dataSize, v, 26, false); //Parse all script-related data first ParseScripts(v, sizes); //These ICs need to be sorted into int and float arrays //Right now they're just a mess of values //The indices in the IC variable storage class _globalICs = Parse <RawParamList>(v[0], 188); _globalsseICs = Parse <RawParamList>(v[1], 188); _ICs = Parse <RawParamList>(v[2], 2204); _sseICs = Parse <RawParamList>(v[3], 2204); //Entry action script offsets //Exit action script offsets //Flash overlay script offsets/flags _unk7 = Parse <EntryList <CommonUnk7Entry> >(v[7], 12); _unk8 = Parse <RawParamList>(v[8], 0x1A4); _itemSwingData = Parse <RawParamList>(v[9], 0x64); _unk10 = Parse <RawParamList>(v[10], 0x10); if ((offset = v[11]) > 0) { sListOffset *list = (sListOffset *)Address(offset); _unk11 = Parse <EntryList <Unknown11EntryNode> >(list->_startOffset, 12, (int)list->_listCount); } _unk12 = Parse <RawParamList>(v[12], 0x80); _unk13 = Parse <RawParamList>(v[13], 0x80); _unk14 = Parse <RawParamList>(v[14], 0x40); _unk15 = Parse <RawParamList>(v[15], 0x24); _unk16 = Parse <RawParamList>(v[16], 0x48); _ppMul = Parse <CmnPatternPowerMulNode>(v[17]); _unk18 = Parse <RawParamList>(v[18], 0x10); //Screen tint script offsets _legBones = Parse <CmnLegBonesNode>(v[21]); if ((offset = v[23]) > 0) { _unk23 = Parse <RawParamList>(*(bint *)Address(offset), 0xA8); } _unk24 = Parse <RawParamList>(v[24], 4); //Notes: //Unk12 and Unk13 are copies of the same parameters //with some different values //Unk23 is one value (0) in Global IC-Basics - offset to data at start of section child data //Params24 is one value (32) in IC-Basics }
protected override void OnPopulate() { bint *addr = (bint *)(BaseAddress + EntryOffset); for (int i = 0; i < EntryCount; i++) { new MoveDefBoneIndexNode().Initialize(this, addr++, 4); } }
protected override void OnPopulate() { bint *entry = Start; for (int i = 0; i < Count; i++) { new MoveDefIndexNode().Initialize(this, new DataSource((VoidPtr)(entry++), 0x4)); } }
protected override void OnPopulate() { bint *entry = (bint *)(BaseAddress + DataOffset); for (int i = 0; i < Count; i++) { new MoveDefIndexNode().Initialize(this, new DataSource((VoidPtr)(entry++), 4)); } }
public override void OnPopulate() { bint *entry = Start; for (int i = 0; i < Count; i++) { new MoveDefBoneIndexNode().Initialize(this, new DataSource((VoidPtr)entry++, 0x4)); } }
public override void OnRebuild(VoidPtr address, int length, bool force) { // Update base address for children. BaseAddress = (VoidPtr)address + sizeof(Common2TblHeader); // Initiate header struct Common2TblHeader *Header = (Common2TblHeader *)address; *Header = new Common2TblHeader(); Header->_OffCount = _offCount; Header->_DataTable = Children.Count; Header->_pad0 = Header->_pad1 = Header->_pad2 = Header->_pad3 = 0; Dictionary <ResourceNode, VoidPtr> dataLocations = new Dictionary <ResourceNode, VoidPtr>(); VoidPtr ptr = BaseAddress; foreach (var child in Children) { int size = child.CalculateSize(false); dataLocations.Add(child, ptr); child.Rebuild(ptr, size, false); ptr += size; } Header->_DataLength = (int)(ptr - BaseAddress); bint *dataPointers = (bint *)ptr; bint *stringPointers = dataPointers + 1; byte *strings = (byte *)(dataPointers + Children.Count + Children.Count); byte *currentString = strings; foreach (var child in Children) { *dataPointers = (int)(dataLocations[child] - BaseAddress); dataPointers += 2; *stringPointers = (int)(currentString - strings); stringPointers += 2; byte[] text = Encoding.UTF8.GetBytes(child.Name); fixed(byte *from = text) { Memory.Move(currentString, from, (uint)text.Length); currentString += text.Length; *currentString = 0; currentString++; } } Header->_Length = (int)(currentString - address); if (Header->_Length != length) { throw new Exception("Wrong amount of memory allocated for rebuild of common2 data"); } }
protected override void OnWrite(VoidPtr address) { int leftOffset, rightOffset; List <int> offsets = new List <int>(); sbyte * ptr = (sbyte *)address; foreach (string s in _left) { s.Write(ptr); offsets.Add(Offset(ptr)); ptr += (s.Length + 1).Align(4); } bint *offPtr = (bint *)ptr; leftOffset = Offset(offPtr); foreach (int i in offsets) { Lookup(offPtr); *offPtr++ = i; } offsets.Clear(); ptr = (sbyte *)offPtr; foreach (string s in _right) { s.Write(ptr); offsets.Add(Offset(ptr)); ptr += (s.Length + 1).Align(4); } offPtr = (bint *)ptr; rightOffset = Offset(offPtr); foreach (int i in offsets) { Lookup(offPtr); *offPtr++ = i; } RebuildAddress = offPtr; if (_left.Count > 0) { Lookup(offPtr); } *offPtr++ = _left.Count > 0 ? leftOffset : 0; *offPtr++ = _left.Count; if (_right.Count > 0) { Lookup(offPtr); } *offPtr++ = _right.Count > 0 ? rightOffset : 0; *offPtr++ = _right.Count; }