public void *GetResource(MDLResourceType type, int entryId) { if (entryId < 0) { return(null); } int groupId = ModelLinker.IndexBank[_header._version].IndexOf(type); if (groupId < 0) { return(null); } byte *addr; fixed(void *p = &this) addr = (byte *)p; int offset = *((bint *)addr + 4 + groupId); if (offset > 0) { ResourceGroup *pGroup = (ResourceGroup *)(addr + offset); return((byte *)pGroup + (&pGroup->_first)[entryId + 1]._dataOffset); } return(null); }
protected internal virtual void PostProcess(VoidPtr mdlAddress, VoidPtr dataAddress, StringTable stringTable) { ResourceGroup *pGroup = (ResourceGroup *)dataAddress; ResourceEntry *rEntry = &pGroup->_first; int index = 1; (*rEntry++) = new ResourceEntry(0xFFFF, 0, 0, 0, 0); if (_name == "Bones") { foreach (MDL0EntryNode n in _children) { PostProcessBone(mdlAddress, n, pGroup, ref index, stringTable); } } else { foreach (MDL0EntryNode n in _children) { dataAddress = (VoidPtr)pGroup + (rEntry++)->_dataOffset; ResourceEntry.Build(pGroup, index++, dataAddress, (BRESString *)stringTable[n.Name]); n.PostProcess(mdlAddress, dataAddress, stringTable); } } }
protected internal virtual void PostProcess(VoidPtr mdlAddress, VoidPtr dataAddress, StringTable stringTable) { if (dataAddress <= mdlAddress) { return; } ResourceGroup *pGroup = (ResourceGroup *)dataAddress; ResourceEntry *rEntry = &pGroup->_first; int index = 1; (*rEntry++) = new ResourceEntry(0xFFFF, 0, 0, 0, 0); if (_name == "Definitions") { return; } List <ResourceNode> entries = _name == "Bones" ? ((MDL0Node)Parent)._linker.BoneCache.Select(x => x as ResourceNode).ToList() : Children; foreach (MDL0EntryNode n in entries) { dataAddress = (VoidPtr)pGroup + (rEntry++)->_dataOffset; ResourceEntry.Build(pGroup, index++, dataAddress, (BRESString *)stringTable[n.Name]); if (dataAddress > mdlAddress) { n.PostProcess(mdlAddress, dataAddress, stringTable); } } }
protected internal override void OnRebuild(VoidPtr address, int length, bool force) { ResourceGroup *group = (ResourceGroup *)address; *group = new ResourceGroup(UsedChildren.Count); int nodeIndex = 0; ResourceEntry *entry = group->First; foreach (SCN0EntryNode n in Children) { if (n.Name != "<null>") { (entry++)->_dataOffset = (int)_dataAddr - (int)group; n._nodeIndex = nodeIndex++; n._realIndex = n.Index; } else { n._nodeIndex = n._realIndex = -1; } n.keyframeAddr = keyframeAddress; n.lightAddr = (RGBAPixel *)lightArrayAddress; n.Rebuild(_dataAddr, n._calcSize, true); _dataAddr += n._calcSize; keyframeAddress += n.keyLen; lightArrayAddress += n.lightLen; } }
protected internal override void PostProcess(VoidPtr bresAddress, VoidPtr dataAddress, int dataLength, StringTable stringTable) { base.PostProcess(bresAddress, dataAddress, dataLength, stringTable); VIS0v3 *header = (VIS0v3 *)dataAddress; if (_version == 4) { ((VIS0v4 *)dataAddress)->ResourceStringAddress = stringTable[Name] + 4; } else { 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 (VIS0EntryNode n in Children) { dataAddress = (VoidPtr)group + (rEntry++)->_dataOffset; ResourceEntry.Build(group, index++, dataAddress, (BRESString *)stringTable[n.Name]); n.PostProcess(dataAddress, stringTable); } }
//Initialize should only be called from parent group during parse. //Bones need not be imported/exported anyways protected override bool OnInitialize() { MDL0Bone *header = Header; SetSizeInternal(header->_headerLen); //Assign true parent using parent header offset int offset = header->_parentOffset; //Offsets are always < 0, because parent entries are listed before children if (offset < 0) { //Get address of parent header MDL0Bone *pHeader = (MDL0Bone *)((byte *)header + offset); //Search bone list for matching header foreach (MDL0BoneNode bone in _parent._children) { if (pHeader == bone.Header) { _parent = bone; break; } //Assign parent and break } } //Conditional name assignment if ((_name == null) && (header->_stringOffset != 0)) { _name = header->ResourceString; } //Assign fields _flags = (BoneFlags)(uint)header->_flags; _nodeIndex = header->_nodeId; _boneIndex = header->_index; _permanentID = header->_index; _bindState = _frameState = new FrameState(header->_scale, header->_rotation, header->_translation); (_bindState._quaternion = new Quaternion()).FromEuler(header->_rotation); _bindMatrix = _frameMatrix = header->_transform; _inverseBindMatrix = _inverseFrameMatrix = header->_transformInv; _bMin = header->_boxMin; _bMax = header->_boxMax; if (header->_part2Offset != 0) { Part2Data * part2 = (Part2Data *)((byte *)header + header->_part2Offset); ResourceGroup *group = part2->Group; ResourceEntry *pEntry = &group->_first + 1; int count = group->_numEntries; for (int i = 0; i < count; i++) { _entries.Add(new String((sbyte *)group + (pEntry++)->_stringOffset)); } } //We don't want to process children because not all have been parsed yet. //Child assigning will be handled by the parent group. return(false); }
public void PostProcess(VoidPtr userDataAddr, StringTable stringTable) { if (Count == 0 || userDataAddr == null) { return; } UserData *data = (UserData *)userDataAddr; ResourceGroup *pGroup = data->Group; ResourceEntry *pEntry = &pGroup->_first; int count = pGroup->_numEntries; (*pEntry++) = new ResourceEntry(0xFFFF, 0, 0, 0, 0); for (int i = 0; i < count; i++) { UserDataEntry *entry = (UserDataEntry *)((byte *)pGroup + (pEntry++)->_dataOffset); if (entry->Type == UserValueType.String && entry->_entryCount > 0) { entry->_dataOffset = (int)((VoidPtr)(stringTable[this[i]._entries[0]] + 4) - (VoidPtr)entry); } ResourceEntry.Build(pGroup, i + 1, entry, (BRESString *)stringTable[this[i]._name]); entry->ResourceStringAddress = stringTable[this[i]._name] + 4; } }
public ResourceEnumerator(ResourceGroup *group) { pGroup = group; count = pGroup->_numEntries; index = 0; pEntry = &pGroup->_first; }
//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); } }
protected internal override void OnRebuild(VoidPtr address, int length, bool force) { CHR0 *header = (CHR0 *)address; *header = new CHR0(length, _numFrames, Children.Count, _unk1, _unk2, _unk3); ResourceGroup *group = header->Group; *group = new ResourceGroup(Children.Count); VoidPtr entryAddress = group->EndAddress; VoidPtr dataAddress = entryAddress; foreach (CHR0EntryNode n in Children) { dataAddress += n._entryLen; } //VoidPtr dataAddr = group->EndAddress; //CHR0Entry* entry = (CHR0Entry*)group->EndAddress; ResourceEntry *rEntry = group->First; foreach (CHR0EntryNode n in Children) { rEntry->_dataOffset = (int)entryAddress - (int)group; rEntry++; n._dataAddr = dataAddress; n.Rebuild(entryAddress, n._entryLen, true); entryAddress += n._entryLen; dataAddress += n._dataLen; } }
protected internal override void OnRebuild(VoidPtr address, int length, bool force) { int count = Children.Count; VIS0 *header = (VIS0 *)address; *header = new VIS0(length, _frameCount, count, _unk1, _unk2); ResourceGroup *group = header->Group; *group = new ResourceGroup(count); ResourceEntry *entry = group->First; VoidPtr dataAddress = group->EndAddress; foreach (ResourceNode n in Children) { entry->_dataOffset = (int)dataAddress - (int)group; entry++; int len = n._calcSize; n.Rebuild(dataAddress, len, force); dataAddress += len; } }
public void Write(VoidPtr userDataAddr) { if (Count == 0 || userDataAddr == null) { return; } UserData *data = (UserData *)userDataAddr; ResourceGroup *pGroup = data->Group; ResourceEntry *pEntry = &pGroup->_first + 1; *pGroup = new ResourceGroup(Count); byte *pData = (byte *)pGroup + pGroup->_totalSize; int id = 0; foreach (UserDataClass s in this) { (pEntry++)->_dataOffset = (int)pData - (int)pGroup; UserDataEntry *p = (UserDataEntry *)pData; *p = new UserDataEntry( s.DataType != UserValueType.String ? s._entries.Count : s._entries.Count > 0 ? 1 : 0, s._type, id++); pData += 0x18; if (s.DataType != UserValueType.String) { for (int i = 0; i < s._entries.Count; i++) { if (s.DataType == UserValueType.Float) { if (!float.TryParse(s._entries[i], out float x)) { x = 0; } *(bfloat *)pData = x; pData += 4; } else if (s.DataType == UserValueType.Int) { if (!int.TryParse(s._entries[i], out int x)) { x = 0; } *(bint *)pData = x; pData += 4; } } } p->_totalLen = (int)pData - (int)p; } data->_totalLen = (int)pData - (int)userDataAddr; }
protected override void OnPopulate() { ResourceGroup *group = Header->Group; for (int i = 0; i < group->_numEntries; i++) { new SCN0GroupNode(group->First[i].GetName()).Initialize(this, new DataSource(group->First[i].DataAddress, 0)); } }
protected override void OnPopulate() { ResourceGroup *group = Header3->Group; for (int i = 0; i < group->_numEntries; i++) { new VIS0EntryNode().Initialize(this, new DataSource((VoidPtr)group + group->First[i]._dataOffset, 0)); } }
public override void OnPopulate() { ResourceGroup *group = Header3->Group; for (int i = 0; i < group->_numEntries; i++) { new PAT0EntryNode().Initialize(this, new DataSource(group->First[i].DataAddress, PAT0Pattern.Size)); } }
protected internal override void PostProcess(VoidPtr bresAddress, VoidPtr dataAddress, int dataLength, StringTable stringTable) { base.PostProcess(bresAddress, dataAddress, dataLength, stringTable); SCN0v4 *header = (SCN0v4 *)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; int[] indices = new int[] { -1, -1, -1, -1, -1 }; foreach (SCN0GroupNode g in Children) { if (g._name == "LightSet(NW4R)") { indices[0] = g.Index; } else if (g._name == "AmbLights(NW4R)") { indices[1] = g.Index; } else if (g._name == "Lights(NW4R)") { indices[2] = g.Index; } else if (g._name == "Fogs(NW4R)") { indices[3] = g.Index; } else if (g._name == "Cameras(NW4R)") { indices[4] = g.Index; } } for (int i = 0; i < 5; i++) { SCN0GroupNode n = indices[i] >= 0 ? Children[indices[i]] as SCN0GroupNode : null; if (n != null) { dataAddress = (VoidPtr)group + (rEntry++)->_dataOffset; ResourceEntry.Build(group, index++, dataAddress, (BRESString *)stringTable[n.Name]); n.PostProcess(header, dataAddress, stringTable); } } if (_version == 5) { _userEntries.PostProcess(((SCN0v5 *)dataAddress)->UserData, stringTable); } }
public override void OnPopulate() { ResourceGroup *group = Group; for (int i = 0; i < group->_numEntries; i++) { new BRESGroupNode(new String((sbyte *)group + group->First[i]._stringOffset)).Initialize(this, (VoidPtr)group + group->First[i]._dataOffset, 0); } }
public override void OnPopulate() { VoidPtr addr; ResourceGroup *group = Header4->Group; for (int i = 0; i < group->_numEntries; i++) { new SRT0EntryNode().Initialize(this, new DataSource(addr = (VoidPtr)group + group->First[i]._dataOffset, ((SRT0Entry *)addr)->DataSize())); } }
protected internal virtual void PostProcess(VoidPtr mdlAddress, VoidPtr dataAddress, StringTable stringTable) { ResourceGroup *pGroup = (ResourceGroup *)dataAddress; ResourceEntry *rEntry = &pGroup->_first; int index = 1; (*rEntry++) = new ResourceEntry(0xFFFF, 0, 0, 0, 0); if (_name == "Bones") { foreach (MDL0EntryNode n in _children) { PostProcessBone(mdlAddress, n, pGroup, ref index, stringTable); } } else if (_name == "Textures") { //ResourceGroup* dGroup = (ResourceGroup*)((byte*)pGroup + pGroup->_totalSize); bool hasDec = false; foreach (MDL0TextureNode n in _children) { if (n._texRefs.Count > 0) { ResourceEntry.Build(pGroup, index++, (byte *)pGroup + (rEntry++)->_dataOffset, (BRESString *)stringTable[n._name]); } if (n._decRefs.Count > 0) { hasDec = true; } } if (hasDec) { pGroup = (ResourceGroup *)((byte *)pGroup + pGroup->_totalSize); rEntry = &pGroup->_first; (*rEntry++) = new ResourceEntry(0xFFFF, 0, 0, 0, 0); index = 1; foreach (MDL0TextureNode n in _children) { if (n._decRefs.Count > 0) { ResourceEntry.Build(pGroup, index++, (byte *)pGroup + (rEntry++)->_dataOffset, (BRESString *)stringTable[n._name]); } } } } else { foreach (MDL0EntryNode n in _children) { dataAddress = (VoidPtr)pGroup + (rEntry++)->_dataOffset; ResourceEntry.Build(pGroup, index++, dataAddress, (BRESString *)stringTable[n.Name]); n.PostProcess(mdlAddress, dataAddress, stringTable); } } }
private void PostProcessBone(VoidPtr mdlAddress, MDL0EntryNode node, ResourceGroup *group, ref int index, StringTable stringTable) { VoidPtr dataAddress = (VoidPtr)group + (&group->_first)[index]._dataOffset; ResourceEntry.Build(group, index++, dataAddress, (BRESString *)stringTable[node.Name]); node.PostProcess(mdlAddress, dataAddress, stringTable); foreach (MDL0EntryNode n in node.Children) { PostProcessBone(mdlAddress, n, group, ref index, stringTable); } }
protected override void OnPopulate() { ResourceGroup *group = Group; for (int i = 0; i < group->_numEntries; i++) { BRESCommonHeader *hdr = (BRESCommonHeader *)group->First[i].DataAddress; if (NodeFactory.FromAddress(this, hdr, hdr->_size) == null) { new BRESEntryNode().Initialize(this, hdr, hdr->_size); } } }
private static List <Bone> ExtractBones(ResourceGroup *pGroup) { int count = pGroup->_numEntries; List <Bone> list = new List <Bone>(count); ResourceEntry *pEntry = &pGroup->_first + 1; for (int i = 0; i < count; i++) { list.Add(new Bone((MDL0Bone *)((byte *)pGroup + pEntry->_dataOffset))); } return(list); }
public override void OnRebuild(VoidPtr address, int size, bool force) { BRESHeader *header = (BRESHeader *)address; *header = new BRESHeader(size, _numEntries + 1); ROOTHeader *rootHeader = header->First; *rootHeader = new ROOTHeader(_rootSize, Children.Count); ResourceGroup *pMaster = &rootHeader->_master; ResourceGroup *rGroup = (ResourceGroup *)pMaster->EndAddress; //Write string table _stringTable.WriteTable(address + _strOffset); VoidPtr dataAddr = (VoidPtr)rootHeader + _rootSize; int gIndex = 1; foreach (BRESGroupNode g in Children) { ResourceEntry.Build(pMaster, gIndex++, rGroup, (BRESString *)_stringTable[g.Name]); *rGroup = new ResourceGroup(g.Children.Count); ResourceEntry *nEntry = rGroup->First; int rIndex = 1; foreach (BRESEntryNode n in g.Children) { //Align data dataAddr = ((int)dataAddr).Align(n.DataAlign); ResourceEntry.Build(rGroup, rIndex++, dataAddr, (BRESString *)_stringTable[n.Name]); //Rebuild entry int len = n._calcSize; n.Rebuild(dataAddr, len, force); n.PostProcess(address, dataAddr, len, _stringTable); dataAddr += len; } g._changed = false; //Advance to next group rGroup = (ResourceGroup *)rGroup->EndAddress; } _stringTable.Clear(); }
protected internal override void PostProcess(VoidPtr bresAddress, VoidPtr dataAddress, int dataLength, StringTable stringTable) { base.PostProcess(bresAddress, dataAddress, dataLength, stringTable); PAT0v3 *header = (PAT0v3 *)dataAddress; if (_version == 4) { ((PAT0v4 *)dataAddress)->ResourceStringAddress = stringTable[Name] + 4; } else { 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); } int i = 0; bint *strings = header->TexFile; for (i = 0; i < _textureFiles.Count; i++) { if (!String.IsNullOrEmpty(_textureFiles[i])) { strings[i] = (int)stringTable[_textureFiles[i]] + 4 - (int)strings; } } strings = header->PltFile; for (i = 0; i < _paletteFiles.Count; i++) { if (!String.IsNullOrEmpty(_paletteFiles[i])) { strings[i] = (int)stringTable[_paletteFiles[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; if (_version == 4) { ((SHP0v4 *)dataAddress)->ResourceStringAddress = stringTable[Name] + 4; if (!String.IsNullOrEmpty(_originalPath)) { ((SHP0v4 *)dataAddress)->OrigPathAddress = stringTable[_originalPath] + 4; } } else { header->ResourceStringAddress = stringTable[Name] + 4; if (!String.IsNullOrEmpty(_originalPath)) { header->OrigPathAddress = stringTable[_originalPath] + 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); } if (_version == 4) { _userEntries.PostProcess(((SHP0v4 *)dataAddress)->UserData, stringTable); } }
public void Write(VoidPtr address) { ResourceGroup *group = (ResourceGroup *)address; group->_numEntries = _entries.Count - 1; group->_totalSize = (_entries.Count * 0x10) + 8; ResourceEntry *pEntry = &group->_first; foreach (BinaryStringEntry e in _entries) { *pEntry++ = e.GetEntry(); } }
protected internal virtual void PostProcess(VoidPtr scn0Address, VoidPtr dataAddress, StringTable stringTable) { ResourceGroup *group = (ResourceGroup *)dataAddress; group->_first = new ResourceEntry(0xFFFF, 0, 0, 0, 0); ResourceEntry *rEntry = group->First; int index = 1; foreach (SCN0EntryNode n in UsedChildren) { dataAddress = (VoidPtr)group + (rEntry++)->_dataOffset; ResourceEntry.Build(group, index++, dataAddress, (BRESString *)stringTable[n.Name]); //n.PostProcess(scn0Address, dataAddress, stringTable); } int len = 0; switch (_type) { case GroupType.LightSet: len = SCN0LightSet.Size; break; case GroupType.AmbientLight: len = SCN0AmbientLight.Size; break; case GroupType.Light: len = SCN0Light.Size; break; case GroupType.Fog: len = SCN0Fog.Size; break; case GroupType.Camera: len = SCN0Camera.Size; break; } bint * hdr = (bint *)scn0Address + 5; VoidPtr entries = scn0Address + hdr[(int)_type]; foreach (SCN0EntryNode n in Children) { n.PostProcess(scn0Address, entries, stringTable); entries += len; } }
//Extracts resources from a group, using the specified type private void ExtractGroup(ResourceGroup *pGroup, Type t) { //If using shaders, cache results instead of unique entries //This is because shaders can appear multiple times, but with different names bool useCache = t == typeof(MDL0ShaderNode); MDL0CommonHeader *pHeader; ResourceNode node; VoidPtr * offsetCache = stackalloc VoidPtr[128]; VoidPtr offsetCount = 0, offset, x; foreach (ResourcePair p in *pGroup) { //Get data offset offset = p.Data; if (useCache) { //search for entry within offset cache for (x = 0; x < offsetCount && offsetCache[x] != offset; x++) { ; } //If found, skip to next entry if (x < offsetCount) { continue; } //Otherwise, store offset offsetCache[offsetCount++] = offset; } //Create resource instance pHeader = (MDL0CommonHeader *)p.Data; node = Activator.CreateInstance(t) as ResourceNode; //Initialize node.Initialize(this, pHeader, pHeader->_size); //Set the name of the node. This is necessary for defs. //Make sure we're not naming the shaders, //or it will name it the name of the first material it's linked to. if (t != typeof(MDL0ShaderNode)) { node._name = (string)p.Name; } } }
public void Read(VoidPtr userDataAddr) { if (userDataAddr == null) { return; } UserData * data = (UserData *)userDataAddr; ResourceGroup *group = data->Group; ResourceEntry *pEntry = &group->_first + 1; int count = group->_numEntries; for (int i = 0; i < count; i++, pEntry++) { UserDataEntry *entry = (UserDataEntry *)((VoidPtr)group + pEntry->_dataOffset); UserDataClass d = new UserDataClass() { _name = new string((sbyte *)group + pEntry->_stringOffset) }; VoidPtr addr = (VoidPtr)entry + entry->_dataOffset; d._type = entry->Type; if (d._type != UserValueType.String) { for (int x = 0; x < entry->_entryCount; x++) { switch (entry->Type) { case UserValueType.Float: d._entries.Add(((float)*(bfloat *)addr).ToString()); addr += 4; break; case UserValueType.Int: d._entries.Add(((int)*(bint *)addr).ToString()); addr += 4; break; } } } else { d._entries.Add(new string((sbyte *)addr)); } Add(d); } }