public void NewType() { RSARPlayerInfoNode node = new RSARPlayerInfoNode(); node.Name = _resource.FindName("NewPlayerInfo"); RSARFolderNode folder = _resource as RSARFolderNode; RSARNode rsar = folder.RSARNode; if (rsar != null) { node._infoIndex = rsar._infoCache[2].Count; rsar._infoCache[2].Add(node); } _resource.AddChild(node); }
public void NewSound() { RSARSoundNode node = new RSARSoundNode { Name = _resource.FindName("NewSound") }; RSARFolderNode folder = _resource as RSARFolderNode; RSARNode rsar = folder.RSARNode; if (rsar != null) { node._infoIndex = rsar._infoCache[0].Count; rsar._infoCache[0].Add(node); } _resource.AddChild(node); }
private static int EncodeMaskGroup(SYMBHeader *symb, SYMBMaskHeader *header, List <RSAREntryNode> gList, RSARNode n, int grp) { int[] stringIds = gList.Select(x => x._rebuildStringId).Where(x => x >= 0).ToArray(); SYMBMaskEntry.Build(stringIds, symb, header, header->Entries); return(SYMBMaskHeader.Size + (stringIds.Length * 2 - 1) * SYMBMaskEntry.Size); }
internal int EncodeFILEBlock(FILEHeader *header, VoidPtr baseAddress, RSAREntryList entries, RSARNode node) { int len = 0; VoidPtr baseAddr = (VoidPtr)header + 0x20; VoidPtr addr = baseAddr; //Build files - order by groups foreach (RSARGroupNode g in entries._groups) { int headerLen = 0, audioLen = 0; int i = 0; INFOGroupEntry *e = (INFOGroupEntry *)((VoidPtr)g._headerAddr + INFOGroupHeader.Size + 4 + g._files.Count * 8); g._headerAddr->_headerOffset = (int)(addr - baseAddress); foreach (RSARFileNode f in g._files) { e[i]._headerLength = f._headerLen; e[i]._headerOffset = headerLen; headerLen += f._headerLen; ++i; } i = 0; VoidPtr wave = addr + headerLen; g._headerAddr->_waveDataOffset = (int)(wave - baseAddress); foreach (RSARFileNode f in g._files) { f._rebuildAudioAddr = wave + audioLen; f.Rebuild(addr, f._headerLen, true); e[i]._dataOffset = f._audioLen == 0 ? 0 : audioLen; e[i]._dataLength = f._audioLen; addr += f._headerLen; audioLen += f._audioLen; ++i; } addr += audioLen; g._headerAddr->_headerLength = headerLen; g._headerAddr->_waveDataLength = audioLen; } len = ((int)addr - (int)(VoidPtr)header).Align(0x20); //Set header header->_header._tag = FILEHeader.Tag; header->_header._length = len; return(len); }
internal int EncodeINFOBlock(INFOHeader *header, RSAREntryList entries, RSARNode node) { int len = 0; VoidPtr baseAddr = header->_collection.Address; ruint * values = (ruint *)baseAddr; VoidPtr dataAddr = baseAddr + 0x30; RuintList *entryList; int index = 0; //Set up sound ruint list values[0] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList *)dataAddr; entryList->_numEntries = entries._sounds.Count; dataAddr += entries._sounds.Count * 8 + 4; //Write sound entries foreach (RSAREntryNode r in entries._sounds) { r._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r.Rebuild(dataAddr, r._calcSize, true); dataAddr += r._calcSize; } index = 0; //Set up bank ruint list values[1] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList *)dataAddr; entryList->_numEntries = entries._banks.Count; dataAddr += entries._banks.Count * 8 + 4; //Write bank entries foreach (RSAREntryNode r in entries._banks) { r._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r.Rebuild(dataAddr, r._calcSize, true); dataAddr += r._calcSize; } index = 0; //Set up playerInfo ruint list values[2] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList *)dataAddr; entryList->_numEntries = entries._playerInfo.Count; dataAddr += entries._playerInfo.Count * 8 + 4; //Write playerInfo entries foreach (RSAREntryNode r in entries._playerInfo) { r._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r.Rebuild(dataAddr, r._calcSize, true); dataAddr += r._calcSize; } index = 0; //Set up file ruint list values[3] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList *)dataAddr; entryList->_numEntries = entries._files.Count; dataAddr += entries._files.Count * 8 + 4; //Write file entries foreach (RSARFileNode file in entries._files) { //if (file._groupRefs.Count == 0 && !(file is RSARExtFileNode)) // continue; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; INFOFileHeader *fileHdr = (INFOFileHeader *)dataAddr; dataAddr += INFOFileHeader.Size; RuintList *list = (RuintList *)dataAddr; fileHdr->_entryNumber = -1; if (file is RSARExtFileNode) { uint extFileSize = 0; //Make an attempt to get current file size if (file.ExternalFileInfo.Exists) { extFileSize = (uint)file.ExternalFileInfo.Length; } if (file._extFileSize != extFileSize && extFileSize != 0) { file._extFileSize = extFileSize; } //Shouldn't matter if 0 fileHdr->_headerLen = file._extFileSize; fileHdr->_dataLen = 0; fileHdr->_stringOffset = (uint)((VoidPtr)list - (VoidPtr)baseAddr); sbyte *dPtr = (sbyte *)list; file._extPath.Write(ref dPtr); dataAddr += ((int)((VoidPtr)dPtr - (VoidPtr)dataAddr)).Align(4); fileHdr->_listOffset = (uint)((VoidPtr)dataAddr - (VoidPtr)baseAddr); dataAddr += 4; //Empty list } else { fileHdr->_headerLen = (uint)file._headerLen; fileHdr->_dataLen = (uint)file._audioLen; //fileHdr->_stringOffset = 0; fileHdr->_listOffset = (uint)((VoidPtr)list - (VoidPtr)baseAddr); list->_numEntries = file._groupRefs.Count; INFOFileEntry *fileEntries = (INFOFileEntry *)((VoidPtr)list + 4 + file._groupRefs.Count * 8); int z = 0; List <int> used = new List <int>(); foreach (RSARGroupNode g in file._groupRefs) { list->Entries[z] = (uint)((VoidPtr)(&fileEntries[z]) - baseAddr); fileEntries[z]._groupId = g._rebuildIndex; int[] all = g._files.FindAllOccurences(file); bool done = false; foreach (int i in all) { if (!used.Contains(i)) { fileEntries[z]._index = i; used.Add(i); done = true; break; } } if (!done) { fileEntries[z]._index = g._files.IndexOf(file); } z++; } dataAddr = (VoidPtr)fileEntries + file._groupRefs.Count * INFOFileEntry.Size; } } index = 0; //Set up group ruint list values[4] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList *)dataAddr; entryList->_numEntries = entries._groups.Count; dataAddr += entries._groups.Count * 8 + 4; //Write group entries foreach (RSAREntryNode r in entries._groups) { r._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r.Rebuild(dataAddr, r._calcSize, true); dataAddr += r._calcSize; } //Write footer values[5] = (uint)dataAddr - (uint)baseAddr; *(INFOFooter *)dataAddr = node._ftr; //Set header header->_header._tag = INFOHeader.Tag; header->_header._length = len = ((int)((dataAddr + INFOFooter.Size) - (baseAddr - 8))).Align(0x20); return(len); }
internal int CalculateSize(RSAREntryList entries, RSARNode node) { //Header _headerLen = 0x40; //SYMB, INFO, FILE Headers _symbLen = 0x20; _infoLen = 0x8; _fileLen = 0x20; #region SYMB //String offsets _symbLen += entries._strings.Count * 4; //Strings are packed tightly with no trailing pad _symbLen += entries._stringLength; //Mask entries _symbLen += 32; //Headers _symbLen += (entries._strings.Count * 2 - 4) * 20; //Entries //Align _symbLen = _symbLen.Align(0x20); #endregion #region Info //Info ruint collection and ruint list counts _infoLen += 0x30; int sounds = 4, playerInfo = 4, banks = 4, groups = 4, files = 4; //ruint sizes sounds += entries._sounds.Count * 8; playerInfo += entries._playerInfo.Count * 8; groups += entries._groups.Count * 8; banks += entries._banks.Count * 8 + 8; files += entries._files.Count * 8; //Evaluate entries with child offsets foreach (RSAREntryNode s in entries._sounds) { sounds += s.CalculateSize(true); } foreach (RSAREntryNode s in entries._playerInfo) { playerInfo += s.CalculateSize(true); } foreach (RSAREntryNode s in entries._banks) { banks += s.CalculateSize(true); } foreach (RSAREntryNode s in entries._groups) { groups += s.CalculateSize(true); } foreach (RSARFileNode s in entries._files) { if (s._groupRefs.Count == 0 && !(s is RSARExtFileNode)) { Console.WriteLine(s.Name); } files += INFOFileHeader.Size + 4 + (!(s is RSARExtFileNode) ? (s._groupRefs.Count * (8 + INFOFileEntry.Size)) : (s._extPath.Length + 1).Align(4)); } //Footer and Align _infoLen = ((_infoLen += (sounds + banks + playerInfo + files + groups)) + 0x10).Align(0x20); #endregion #region File foreach (RSARGroupNode g in entries._groups) { foreach (RSARFileNode f in g._files) { _fileLen += f.CalculateSize(true); } } //Align _fileLen = _fileLen.Align(0x20); #endregion return(_headerLen + _symbLen + _infoLen + _fileLen); }
//Failed attempts at generating symb ids commented out below, enjoy //static void GenIds(SYMBHeader* symb, SYMBMaskHeader* header, int index, ushort allowedBit) //{ // SYMBMaskEntry* first = &header->Entries[index]; // string mainName = symb->GetStringEntry(first->_stringId); // for (int i = 1; i < header->_numEntries; i += 2) // { // SYMBMaskEntry* secName = &header->Entries[i]; // SYMBMaskEntry* secBit = &header->Entries[i + 1]; // if (i == index || secBit->_bit != allowedBit) // continue; // string compName = symb->GetStringEntry(secName->_stringId); // int bitIndex = mainName.CompareBits(compName); // if (bitIndex >= 0) // { // //Set the bit index // secBit->_bit = (ushort)bitIndex; // int bit = bitIndex % 8; // int byteIndex = (bitIndex - bit) / 8; // bool leftFound = false, rightFound = false; // mainName = compName; // //Keeping looking down the list for the left and right entries // for (int x = i + 2; x < header->_numEntries; x += 2) // { // SYMBMaskEntry* lrName = &header->Entries[x]; // SYMBMaskEntry* lrBit = &header->Entries[x + 1]; // compName = symb->GetStringEntry(lrName->_stringId); // if (x == index || lrBit->_bit != allowedBit) // continue; // bool forceLeft = false; // if (byteIndex >= Math.Min(mainName.Length, compName.Length)) // forceLeft = true; // if (forceLeft || mainName.AtBit(bitIndex) != compName.AtBit(bitIndex)) // { // if (leftFound) // continue; // leftFound = true; // secBit->_leftId = x + 1; // GenIds(symb, header, x, lrBit->_bit); // } // else // { // if (rightFound) // continue; // rightFound = true; // secBit->_rightId = x + 1; // GenIds(symb, header, x, lrBit->_bit); // } // } // if (!leftFound) //No strings matched // secBit->_leftId = i; // else if (!rightFound) //All strings matched // secBit->_rightId = i; // break; // } // } //} //String Table to convert to a tree //string[] stringTable = new string[] { "SDPLAYER_BGM", "SDPLAYER_SE", "SDPLAYER_VOICE", "SDPLAYER_SYSTEM", "SDPLAYER_LOOP", "SDPLAYER_VOICE2", "SDPLAYER_SE_NOEFFECT" }; //public class TEntry //{ // public string _string; // public string _binary; // public int _bit = -1; // public int _leftID = -1; // public int _rightID = -1; // public int _stringID; // public int _id; // public TEntry(RSAREntryState s) // { // _binary = (_string = s._node._fullPath).ToBinaryArray(); // _stringID = s._stringId; // _id = s._index; // } //} //Making the output table to save me buttloads of time >.> //public void convertToBinary(string): // ''' Converts a text string to a string representation of itself in binary. ''' // return ''.join(['%08d'%int(bin(ord(i))[2:]) for i in string]) //Populating an empty table for my own convenience. //I assume the stringlist is ordered by ID, and is the first and only segment in the symb. //Cause I'm a lazy bastard. //Normal String, String (in binary), bit, LeftID, RightID, StringID, ID //outputTable = [{'string':stringTable[x], 'binary':convertToBinary(stringTable[x]), // 'bit':-1, 'LeftID':-1, 'RightID':-1, 'StringID':x, 'ID':x} for x in xrange(len(stringTable))] //private static void WriteData(List<TEntry> Left, List<TEntry> Right, int bit) //{ // //Writes all the necessary information to the node // TEntry currentNode = Right[0]; // //Write Position // currentNode._bit = bit; // //Write the left branch (matching) This is a bit fugly, because of how I handle the output table. // //I basically determine the 'line' based off the ID. // if (Left.Count > 1) // currentNode._leftID = Left[0]._id * 2; // else // { // currentNode._leftID = Left[0]._id * 2 - 1; // //Edge case for the first node, who has no -1 line. // if (currentNode._leftID < 0) // currentNode._leftID = 0; // } // if (Right.Count > 1) // currentNode._rightID = Right[1]._id * 2; // else // { // currentNode._rightID = Right[0]._id * 2 - 1; // //Edge case for the first node, who has no -1 line. // if (currentNode._rightID < 0) // currentNode._rightID = 0; // } //} //private static void SplitTable(List<TEntry> outputTable, out List<TEntry> Left, out List<TEntry> Right) //{ // //Splits the table in two and writes the data // TEntry originalNode = outputTable[0]; // List<TEntry> Temp; // //Iterate bit by bit // int bit = 0, entry = 0; // for (bit = 0; bit < originalNode._binary.Length; bit++) // { // char compareBit = originalNode._binary[bit]; // //Go over the table // for (entry = 0; entry < outputTable.Count; entry++) // { // //F*****g Ugly edge case - initial string is too long to compare // if (bit >= outputTable[entry]._binary.Length) // { // //Python stuff to change the 'start' of the table to the current position // Temp = outputTable.ShiftFirst(entry); // //Split the ordered table there into Left (matching) and right (non-matching) // Left = new List<TEntry> { outputTable[entry] }; // Right = new List<TEntry>(); // foreach (TEntry t in Temp) // if (t._id != outputTable[entry]._id) // Right.Add(t); // WriteData(Left, Right, bit); // //It splits! // return; // } // //This is the normal case - applies 90% of the time, I find. // if (outputTable[entry]._binary[bit] != compareBit) // { // //Python stuff to change the 'start' of the table to the current position // Temp = outputTable.ShiftFirst(entry); // //Split the ordered table there into Left (matching) and right (non-matching) // Left = new List<TEntry>(); // foreach (TEntry t in Temp) // if (t._binary[bit] == '0') // Left.Add(t); // Right = new List<TEntry>(); // foreach (TEntry t in Temp) // if (t._binary[bit] == '1') // Right.Add(t); // WriteData(Left, Right, bit); // //It splits! // return; // } // } // } // //If it got this far, then it ran out of bits. // //So now we gotta // //Split the ordered table there into Left (matching) and right (non-matching) // Left = new List<TEntry> { originalNode }; // Right = new List<TEntry>(); // foreach (TEntry t in outputTable) // if (t._id != originalNode._id) // Right.Add(t); // WriteData(Left, Right, bit); // //It splits! // return; //} //public static void CalcMatch(List<TEntry> outputTable) //{ // //Split the Table by node // List<TEntry> Left, Right; // SplitTable(outputTable, out Left, out Right); // //foreach (TEntry t in Left) // // Console.WriteLine(String.Format("Left: {0} {1} {2} {3} ", t._string, t._bit, t._leftID, t._rightID)); // //Console.WriteLine("-------------------------------------------------"); // //foreach (TEntry t in Right) // // Console.WriteLine(String.Format("Right: {0} {1} {2} {3} ", t._string, t._bit, t._leftID, t._rightID)); // if (Left.Count > 1) // CalcMatch(Left); // if (Right.Count > 1) // CalcMatch(Right); //} //public class PatriciaTree //{ // public string[] strings; // public string[] bin_strings; // public int out_node_idx = 0; // public PatriciaTree(string[] str) // { // strings = str; // bin_strings = strings.Select(x => x.ToBinaryArray()).ToArray(); // } // public int[] partition_tree(List<int> idx_list, int position) // { // List<int> left = new List<int>(), right = new List<int>(); // for (int i = 0; i < idx_list.Count; i++ ) // { // string bstr = bin_strings[i]; // if (position >= bstr.Length || position < 0) // left.Add(i); // else // { // char ch = bstr[position]; // if (ch == '1') // right.Add(i); // else // left.Add(i); // } // } // int total = left.Count + right.Count; // if (total == 1) // { // //This is a leaf, woo // int pos = -1, t; // if (left.Count > 0) // t = left[0]; // else // t = right[0]; // return new int[] { pos, t }; // } // else if (left.Count == 0 || right.Count == 0) // //This is not a branch, let's try the next bit // if (left.Count > 0) // return partition_tree(left, position + 1); // else // return partition_tree(right, position + 1); // else // { // int[] l = partition_tree(left, position + 1); // int[] r = partition_tree(right, position + 1); // return new int[] { position }.Append(l).Append(r); // } // } // public int tree_size(int[] node) // { // //Node is the return from partition_tree() // if (node[0] == -1) // return 1; // else // return 1 + tree_size(new int[] { node[1] }) + tree_size(new int[] { node[2] }); // } // public void dump_tree(int[] tree) // { // out_node_idx = 0; // _dump_node(tree); // } // public void _dump_node(int[] node) // { // //Node is the return from partition_tree() // int bit_id = node[0]; // if (bit_id == -1) // { // //We're packing a leaf // Console.WriteLine(String.Format("{0} leaf : {1}", out_node_idx, strings[node[1]])); // out_node_idx += 1; // } // else // { // //We're packing a branch // int left_size = tree_size(new int[] { node[1] }); // int left_idx = out_node_idx + 1; // int right_idx = left_idx + left_size; // Console.WriteLine(String.Format("{0} branch: bit={1} left={2} right={3}", out_node_idx, bit_id, left_idx, right_idx)); // out_node_idx += 1; // dump_tree(new int[] { node[1] }); // dump_tree(new int[] { node[2] }); // } // } //} //tree = PatriciaTree(('BANK_HOMEBUTTON','BANK_SYSTEM_SE','BANK_BGM','BANK_SOFTWARE_KEYBOARD_SE')) //print(tree.partition_tree()) //tree.dump_tree(tree.partition_tree()) private static int EncodeMaskGroup(SYMBHeader *symb, SYMBMaskHeader *header, List <RSAREntryState> group, RSARNode n, int grp) { SYMBMaskEntry *entry = header->Entries; //List<TEntry> outputTable = new List<TEntry>(); int i = 0; foreach (RSAREntryState s in group) { entry[i++] = new SYMBMaskEntry(1, -1, -1, -1, s._stringId, s._index); if (s._index != 0) { //entry[i++] = new SYMBMaskEntry(0, 0, 0, 0, -1, -1); entry[i] = n._symbCache[grp][i++]; } //outputTable.Add(new TEntry(s)); } header->_numEntries = group.Count * 2 - 1; header->_rootId = n._rootIds[grp]; //GenIds(symb, header, 0, 0); //CalcMatch(outputTable); //foreach (TEntry t in outputTable) //{ // *entry++ = new SYMBMaskEntry(1, -1, -1, -1, t._stringID, t._id); // if (t._id != 0) // *entry++ = new SYMBMaskEntry(0, (short)t._bit, t._leftID, t._rightID, -1, -1); //} //PatriciaTree t = new PatriciaTree(group.Select(x => x._node._fullPath).ToArray()); //int[] p = t.partition_tree(new List<int>(t.strings.Length), 0); //t.dump_tree(p); int len = 8 + i * SYMBMaskEntry.Size; //int rootId = 0; //int lowestBit = int.MaxValue; //entry = header->Entries; //for (int i = 2; i < header->_numEntries; i += 2) //{ // if (entry[i]._bit < lowestBit) // { // lowestBit = entry[i]._bit; // rootId = i; // } //} //header->_rootId = rootId; return(len); }
public void RunEvent(int eventIndex) { //Get the current event and its id e = this[eventIndex]; //Run event only if allowed or if an exception if (e == null || !_runEvents && !_runExceptions.Contains(eventId >> 16)) { return; } uint eventIdTemp = eventId & 0xFFFFFF00; //Cut out unk value //if (_events.ContainsKey(eventIdTemp)) // _events[eventIdTemp].Invoke(this, null); //Variables that are used often int id; Script script; Event ev; int index; ArticleInfo articleInfo; HitBox hitbox; RequirementInfo reqInfo; ActionChangeInfo aChangeInfo; SubActionChangeInfo sChangeInfo; //Code what to do for each event here! switch (eventIdTemp) { case 0x01000000: //Loop Rest 1 for Goto Application.DoEvents(); break; case 0x00010100: //Synchronous Timer _waitFrames = (int)(e[0].RealValue + 0.5f); break; case 0x00020000: //No Operation break; case 0x00020100: //Asynchronous Timer _waitFrames = Math.Max((int)(e[0].RealValue + 0.5f) - _frameIndex, 0); break; case 0x00040100: //Set loop data _loopCount = e[0]; _loopStartIndex = e.Index + 1; _runEvents = false; break; case 0x00050000: //Start looping _looping = true; _loopEndIndex = e.Index; _eventIndex = _loopStartIndex; _runEvents = true; break; case 0x000A0100: //If case 0x000A0200: //If Value case 0x000A0300: //If Unk case 0x000A0400: //If Comparison if (_runEvents) { _currentIf = _ifIndex++; _runEvents = false; _ifInfo = new IfInfo(); index = eventIndex + 1; while (true) { if (index < Count) { ev = this[index]; id = (int)ev.EventID; if (id == 0x000B0100 || id == 0x000B0200 || id == 0x000B0300 || id == 0x000B0400) { index++; } else { break; } } else { break; } } _ifInfo._reqIndices = new List <int>(); _ifInfo._reqIndices.Add(index); _ifEndIndices.Add(0); reqInfo = new RequirementInfo(e[0]); for (int i = 1; i < ((eventId >> 8) & 0xFF); i++) { reqInfo._values.Add(e[i]); } _ifInfo._requirements = new List <List <RequirementInfo> >(); _ifInfo._requirements.Add(new List <RequirementInfo>()); _ifInfo._requirements[0].Add(reqInfo); } else { _ifIndex++; } break; case 0x000E0000: //Else if (!_runEvents) { if (_ifIndex == _currentIf) { _ifInfo._elseIndex = eventIndex; } } else { if (_ifIndex == _currentIf + 1) { _eventIndex = _ifInfo._endIndex; } } break; case 0x000D0100: //Else If (req) case 0x000D0200: //Else If Value (req val) case 0x000D0300: //Else If Unk (req val unk) case 0x000D0400: //Else If Comparison (req var val var) if (!_runEvents) { if (_ifIndex == _currentIf) { index = eventIndex + 1; while (true) { if (index < Count) { ev = this[index]; id = (int)ev.EventID; if (id == 0x000B0100 || id == 0x000B0200 || id == 0x000B0300 || id == 0x000B0400) { index++; } else { break; } } else { break; } } _ifInfo._reqIndices.Add(index); } } else { if (_ifIndex == _currentIf + 1) { _eventIndex = _ifInfo._endIndex; } } if (!_runEvents && _ifIndex == _currentIf + 1) { reqInfo = new RequirementInfo(e[0]); for (int i = 1; i < eCount; i++) { reqInfo._values.Add(e[i]); } _ifInfo._requirements.Add(new List <RequirementInfo>()); _ifInfo._requirements[0].Add(reqInfo); } break; case 0x000B0100: //And If case 0x000B0200: //And If Value case 0x000B0300: //And If Unk case 0x000B0400: //And If Comparison if (!_runEvents && _ifIndex == _currentIf + 1) { reqInfo = new RequirementInfo(e[0]); for (int i = 1; i < eCount; i++) { reqInfo._values.Add(e[i]); } _ifInfo._requirements.Add(new List <RequirementInfo>()); _ifInfo._requirements[0].Add(reqInfo); } break; case 0x000F0000: //End if _ifIndex--; if (!_runEvents) { if (_ifIndex == _currentIf) { _ifInfo._endIndex = _ifEndIndices[_currentIf] = eventIndex + 1; _eventIndex = _ifInfo.Run(); _runEvents = true; } } break; case 0x00100200: //Switch _cases = new List <Parameter>(); _caseIndices = new List <int>(); //Turn off events to examine them until end switch //Then the examined data will be evaluated _runEvents = false; _switchStartIndex = eventIndex; break; case 0x00110100: //Case if (!_runEvents) { if (_cases != null && _caseIndices != null) { _cases.Add(e[0]); _caseIndices.Add(e.Index); } } else { _eventIndex = _switchEndIndex + 1; _switchEndIndex = -1; } break; case 0x00120000: //Default Case _defaultCaseIndex = e.Index; break; case 0x00130000: //End Switch _runEvents = true; _switchEndIndex = e.Index; //Apply cases index = 0; if (_switchStartIndex >= 0 && _switchStartIndex < Count) { Parameter Switch = this[_switchStartIndex][1]; foreach (Parameter param in _cases) { if (Switch.Compare(param, 2)) { _eventIndex = _caseIndices[index] + 1; break; } index++; } } if (_cases != null && index == _cases.Count && _defaultCaseIndex != -1) { _eventIndex = _defaultCaseIndex + 1; } _defaultCaseIndex = -1; _switchStartIndex = -1; _cases = null; break; case 0x00180000: //Break _eventIndex = _switchEndIndex + 1; _switchEndIndex = -1; break; case 0x10050200: //Article Visiblity id = e[0]; if (id < 0 || id >= RunTime._articles.Length) { break; } articleInfo = RunTime._articles[id]; if (articleInfo != null && articleInfo._model != null) { articleInfo._model.IsRendering = e[1] != 0; } break; case 0x01010000: //Loop Rest _waitFrames = 1; break; case 0x06000D00: //Offensive Collison case 0x062B0D00: //Thrown Collision hitbox = new HitBox(e, Article != null ? Article.Index : -1); hitbox.HitboxID = (int)(e[0] & 0xFFFF); hitbox.HitboxSize = e[5]; RunTime._hitBoxes.Add(hitbox); break; case 0x06050100: //Body Collision _hurtBoxType = e[0]; break; case 0x06080200: //Bone Collision id = e[0]; if (Root.Model != null && Root.Model._linker.BoneCache.Length > id && id >= 0) { MDL0BoneNode bone = Root.Model._linker.BoneCache[id] as MDL0BoneNode; switch ((int)e[1]) { case 0: bone._nodeColor = Color.Transparent; bone._boneColor = Color.Transparent; break; case 1: bone._nodeColor = bone._boneColor = Color.FromArgb(255, 255, 0); break; default: bone._nodeColor = bone._boneColor = Color.FromArgb(0, 0, 255); break; } _boneCollisions.Add(bone); } break; case 0x06060100: //Undo Bone Collision foreach (MDL0BoneNode bone in _boneCollisions) { bone._nodeColor = bone._boneColor = Color.Transparent; } _boneCollisions = new List <MDL0BoneNode>(); break; case 0x060A0800: //Catch Collision 1 case 0x060A0900: //Catch Collision 2 case 0x060A0A00: //Catch Collision 3 hitbox = new HitBox(e, Article != null ? Article.Index : -1); hitbox.HitboxID = e[0]; hitbox.HitboxSize = e[2]; RunTime._hitBoxes.Add(hitbox); break; case 0x060D0000: //Terminate Catch Collisions for (int i = 0; i < RunTime._hitBoxes.Count; i++) { if (RunTime._hitBoxes[i].IsCatch()) { RunTime._hitBoxes.RemoveAt(i--); } } break; case 0x00060000: //Loop break _looping = false; _eventIndex = _loopEndIndex + 1; _loopTime = 0; break; case 0x06150F00: //Special Offensive Collison hitbox = new HitBox(e, Article != null ? Article.Index : -1); hitbox.HitboxID = (int)(e[0] & 0xFFFF); hitbox.HitboxSize = e[5]; RunTime._hitBoxes.Add(hitbox); break; case 0x06040000: //Terminate Collisions for (int i = 0; i < RunTime._hitBoxes.Count; i++) { if (RunTime._hitBoxes[i].IsOffensive(true)) { RunTime._hitBoxes.RemoveAt(i--); } } break; case 0x06030100: //Delete hitbox for (int i = 0; i < RunTime._hitBoxes.Count; i++) { HitBox hbox = RunTime._hitBoxes[i]; if (hbox.HitboxID == e[0] && hbox.IsOffensive(true)) { RunTime._hitBoxes.RemoveAt(i--); break; } } break; case 0x060C0100: //Delete Catch Collision for (int i = 0; i < RunTime._hitBoxes.Count; i++) { HitBox hbox = RunTime._hitBoxes[i]; if (hbox.HitboxID == e[0] && hbox.IsCatch()) { RunTime._hitBoxes.RemoveAt(i--); break; } } break; case 0x061B0500: //Move hitbox foreach (HitBox hbox in RunTime._hitBoxes) { if (hbox.HitboxID == e[0] && hbox.IsOffensive(true)) { hbox._parameters[1] = e[1]; hbox._parameters[6] = e[2]; hbox._parameters[7] = e[3]; hbox._parameters[8] = e[4]; break; } } break; case 0x04060100: //Set animation frame //if (Article == null) // RunTime.SetFrame((int)(e[0].RealValue + 0.05f)); //else // RunTime._articles[Article.Index].SetFrame((int)(e[0].RealValue + 0.05f)); break; case 0x00070100: //Subroutine script = (e[0] as EventOffset)._script; if (script != null && script != _script) { script.Reset(); RunTime._runningScripts.Add(script); script.SetFrame(0); } break; case 0x00080000: //Return _return = true; _eventIndex = Count; if (RunTime._runningScripts.Contains(_script)) { RunTime._runningScripts.Remove(_script); } break; case 0x00090100: //Go to script = (e[0] as EventOffset)._script; if (script != null && script != _script) { RunTime._runningScripts.Remove(_script); script.Reset(); RunTime._runningScripts.Add(script); script.SetFrame(0); } break; case 0x0A030100: //Stop sound id = e[0]; if (RunTime._playingSounds.ContainsKey(id)) { List <AudioInfo> aList = RunTime._playingSounds[id]; foreach (AudioInfo aInfo in aList) { if (aInfo._buffer != null) { aInfo._buffer.Stop(); aInfo._buffer.Dispose(); aInfo._stream.Dispose(); } } RunTime._playingSounds.Remove(id); } break; case 0x0A000100: //Play sound case 0x0A010100: case 0x0A020100: case 0x0A040100: case 0x0A050100: case 0x0A060100: case 0x0A070100: case 0x0A080100: case 0x0A090100: case 0x0A0A0100: case 0x0A0B0100: case 0x0A0C0100: case 0x0A0D0100: case 0x0A0E0100: case 0x0A0F0100: if (RunTime._muteSFX) { break; } if (Manager.SoundArchive != null) { RSARNode node = Manager.SoundArchive; List <RSAREntryNode> sounds = node._infoCache[0]; id = e[0]; if (sounds != null && id >= 0 && id < sounds.Count) { RSARSoundNode s = sounds[id] as RSARSoundNode; if (s != null) { IAudioStream stream = s.CreateStreams()[0]; AudioBuffer b = Manager._audioProvider.CreateBuffer(stream); AudioInfo info = new AudioInfo(b, stream); if (RunTime._playingSounds.ContainsKey(id)) { RunTime._playingSounds[id].Add(info); } else { RunTime._playingSounds[id] = new List <AudioInfo>() { info } }; b.Reset(); b.Seek(0); b.Play(); } } } break; case 0x0B000200: //Model Changer 1 case 0x0B010200: //Model Changer 2 ModelVisibility visNode = null; if (Article != null) { //Check if we have data to work with articleInfo = RunTime._articles[Article.Index]; if (articleInfo == null || articleInfo._model == null || articleInfo._model._objList == null || articleInfo._article._mdlVis == null || articleInfo._article._mdlVis.Count == 0) { break; } visNode = articleInfo._article._mdlVis; } else { //Check if we have data to work with if (Root.Model == null || Root.Model._objList == null || Root.Data._modelVis.Count == 0) { break; } visNode = Root.Data._modelVis; } if (visNode != null) { int refId = ((int)((eventId >> 16) & 0xFF)); int switchId = e[0]; int groupId = e[1]; visNode.ApplyVisibility(refId, switchId, groupId); } break; case 0x0B020100: //Model visibility if (Article == null) { Root.Model.IsRendering = e[0] != 0; } else if (Article.Index < RunTime._articles.Length && RunTime._articles[Article.Index]._model != null) { RunTime._articles[Article.Index]._model.IsRendering = e[0] != 0; } break; case 0x0D000200: //Concurrent Infinite Loop index = e[0]; EventOffset off = (e[1] as EventOffset); if (off._script != null) { if (RunTime._concurrentLoopScripts.ContainsKey(index)) { RunTime._concurrentLoopScripts.Remove(index); } RunTime._concurrentLoopScripts.Add(index, off._script); } break; case 0x0D010100: //Terminate Concurrent Infinite Loop index = e[0]; if (RunTime._concurrentLoopScripts.ContainsKey(index)) { RunTime._concurrentLoopScripts.Remove(index); } break; case 0x0E000100: //Set Air/Ground RunTime._location = (RunTime.Location)((int)e[0]); break; case 0x10000100: //Generate Article case 0x10000200: //Generate Article case 0x10030100: //Remove Article //These events do a similar job! bool removeArticle = eID == 3; //Make sure we have all the data we need available MainControl main = MainForm.Instance._mainControl; MovesetNode mNode = Manager.Moveset; if (mNode == null) { break; } DataSection d = mNode.Data; if (d == null) { break; } //Get the id of the article to be called and check it int aId2 = e[0]; if (aId2 < 0 || aId2 >= RunTime._articles.Length) { break; } //Get the called article from the article list articleInfo = RunTime._articles[aId2]; if (articleInfo == null) { return; } articleInfo.Running = !removeArticle; break; case 0x10040200: //Set Anchored Article SubAction case 0x10070200: //Set Remote Article SubAction id = e[0]; int sId = e[1]; if (id < 0 || id >= RunTime._articles.Length) { break; } //Get the called article from the article list articleInfo = RunTime._articles[id]; if (articleInfo != null) { articleInfo.SubactionIndex = sId; articleInfo._setAt = _frameIndex; } break; case 0x10010200: //Set Ex-Anchored Article Action break; case 0x12000200: //Basic Var Set case 0x12060200: //Float Var Set e[1].RealValue = e[0].RealValue; break; case 0x12010200: //Basic Var Add case 0x12070200: //Float Var Add e[1].RealValue = e[1].RealValue + e[0].RealValue; break; case 0x12020200: //Basic Var Sub case 0x12080200: //Float Var Sub e[1].RealValue = e[1].RealValue - e[0].RealValue; break; case 0x12030100: //Basic Var Inc e[0].RealValue = e[0].RealValue + 1.0f; break; case 0x12040100: //Basic Var Dec e[0].RealValue = e[0].RealValue - 1.0f; break; case 0x120A0100: //Bit Variable Set e[0].RealValue = 1.0f; break; case 0x120B0100: //Bit Variable Clear e[0].RealValue = 0.0f; break; case 0x120F0200: //Float Variable Multiply e[1].RealValue = e[1].RealValue * e[0].RealValue; break; case 0x12100200: //Float Variable Divide if (e[0].RealValue != 0) { e[1].RealValue = e[1].RealValue / e[0].RealValue; } break; case 0x64000000: //Allow Interrupt RunTime._allowInterrupt = true; break; case 0x02000300: //Change Action Status case 0x02000400: case 0x02000500: case 0x02000600: break; case 0x02010200: //Change Action case 0x02010300: case 0x02010400: case 0x02010500: aChangeInfo = new ActionChangeInfo(e[0]); reqInfo = new RequirementInfo(e[1]); for (int i = 2; i < Count; i++) { reqInfo._values.Add(e[i]); } aChangeInfo._requirements.Add(reqInfo); RunTime.AddActionChangeInfo(aChangeInfo); break; case 0x02040100: //Additional Change Action Requirement case 0x02040200: case 0x02040300: case 0x02040400: break; case 0x02060100: //Enable Action Status ID break; case 0x02080100: //Disable Action Status ID break; case 0x02090200: //Invert Action Status ID break; case 0x020A0100: //Allow Specific Interrupt break; case 0x020B0100: //Disallow Specific Interrupt break; case 0x020C0100: //Unregister Interrupt break; case 0x04000100: //Change Subaction case 0x04000200: sChangeInfo = new SubActionChangeInfo(e[0], eCount == 2 && e[1] != 0); RunTime.AddSubActionChangeInfo(sChangeInfo); break; case 0x04010200: //Change Subaction sChangeInfo = new SubActionChangeInfo(e[0], false); sChangeInfo._requirements.Add(new RequirementInfo(e[1])); RunTime.AddSubActionChangeInfo(sChangeInfo); break; case 0x11010A00: //External Graphic Effect case 0x11001000: //Same as prev but with random offset and rotation bool random = ((eventId >> 16) & 0xFF) == 0; break; case 0x111A1000: //Graphic Effect; no file break; } }
internal int EncodeINFOBlock(INFOHeader* header, RSAREntryList entries, RSARNode node) { int len = 0; VoidPtr baseAddr = header->_collection.Address; ruint* values = (ruint*)baseAddr; VoidPtr dataAddr = baseAddr + 0x30; RuintList* entryList; int index = 0; //Set up sound ruint list values[0] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList*)dataAddr; entryList->_numEntries = entries._sounds.Count; dataAddr += entries._sounds.Count * 8 + 4; //Write sound entries foreach (RSAREntryState r in entries._sounds) { r._node._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r._node.Rebuild(dataAddr, r._node._calcSize, true); dataAddr += r._node._calcSize; } index = 0; //Set up bank ruint list values[1] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList*)dataAddr; entryList->_numEntries = entries._banks.Count; dataAddr += entries._banks.Count * 8 + 4; //Write bank entries foreach (RSAREntryState r in entries._banks) { r._node._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r._node.Rebuild(dataAddr, r._node._calcSize, true); dataAddr += r._node._calcSize; } index = 0; //Set up playerInfo ruint list values[2] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList*)dataAddr; entryList->_numEntries = entries._playerInfo.Count; dataAddr += entries._playerInfo.Count * 8 + 4; //Write playerInfo entries foreach (RSAREntryState r in entries._playerInfo) { r._node._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r._node.Rebuild(dataAddr, r._node._calcSize, true); dataAddr += r._node._calcSize; } index = 0; //Set up file ruint list values[3] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList*)dataAddr; entryList->_numEntries = entries._files.Count; dataAddr += entries._files.Count * 8 + 4; //Write file entries foreach (RSARFileNode file in entries._files) { entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; INFOFileHeader* fileHdr = (INFOFileHeader*)dataAddr; dataAddr += INFOFileHeader.Size; RuintList* list = (RuintList*)dataAddr; fileHdr->_entryNumber = -1; if (file is RSARExtFileNode) { //Make an attempt to get current file size uint s = 0; if (file.ExternalFileInfo.Exists) s = (uint)file.ExternalFileInfo.Length; if (file._extFileSize != s && s != 0) file._extFileSize = s; //Shouldn't matter if 0 fileHdr->_headerLen = file._extFileSize; fileHdr->_dataLen = 0; fileHdr->_stringOffset = (uint)((VoidPtr)list - (VoidPtr)baseAddr); sbyte* dPtr = (sbyte*)list; file._extPath.Write(ref dPtr); dataAddr += ((int)((VoidPtr)dPtr - (VoidPtr)dataAddr)).Align(4); fileHdr->_listOffset = (uint)((VoidPtr)dataAddr - (VoidPtr)baseAddr); dataAddr += 4; //Empty list } else { fileHdr->_headerLen = (uint)file._headerLen; fileHdr->_dataLen = (uint)file._audioLen; //fileHdr->_stringOffset = 0; fileHdr->_listOffset = (uint)((VoidPtr)list - (VoidPtr)baseAddr); list->_numEntries = file._groups.Count; INFOFileEntry* fileEntries = (INFOFileEntry*)((VoidPtr)list + 4 + file._groups.Count * 8); int z = 0; List<int> used = new List<int>(); foreach (RSARGroupNode g in file._groups) { list->Entries[z] = (uint)((VoidPtr)(&fileEntries[z]) - baseAddr); fileEntries[z]._groupId = g._rebuildIndex; int[] all = g._files.FindAllOccurences(file); bool done = false; foreach (int i in all) if (!used.Contains(i)) { fileEntries[z]._index = i; used.Add(i); done = true; break; } if (!done) fileEntries[z]._index = g._files.IndexOf(file); z++; } dataAddr = (VoidPtr)fileEntries + file._groups.Count * INFOFileEntry.Size; } } index = 0; //Set up group ruint list values[4] = (uint)dataAddr - (uint)baseAddr; entryList = (RuintList*)dataAddr; entryList->_numEntries = entries._groups.Count + 1; dataAddr += (entries._groups.Count + 1) * 8 + 4; //Write group entries foreach (RSAREntryState r in entries._groups) { r._node._rebuildBase = baseAddr; entryList->Entries[index++] = (uint)dataAddr - (uint)baseAddr; r._node.Rebuild(dataAddr, r._node._calcSize, true); dataAddr += r._node._calcSize; } //Null group at the end entryList->Entries[entries._groups.Count] = (uint)dataAddr - (uint)baseAddr; INFOGroupHeader* grp = (INFOGroupHeader*)dataAddr; node._nullGroup._rebuildAddr = grp; node._nullGroup._rebuildBase = baseAddr; *(bint*)(dataAddr + INFOGroupHeader.Size) = 0; grp->_entryNum = -1; grp->_stringId = -1; //grp->_extFilePathRef = 0; //grp->_extFilePathRef._dataType = 0; grp->_headerLength = 0; grp->_waveDataLength = 0; grp->_headerOffset = grp->_waveDataOffset = _headerLen + _symbLen + _infoLen + _fileLen; grp->_listOffset = (uint)((VoidPtr)(dataAddr + INFOGroupHeader.Size) - baseAddr); dataAddr += INFOGroupHeader.Size; RuintList* l = (RuintList*)dataAddr; INFOGroupEntry* e = (INFOGroupEntry*)((VoidPtr)l + 4 + node._nullGroup.Files.Count * 8); l->_numEntries = node._nullGroup.Files.Count; int y = 0; foreach (RSARFileNode file in node._nullGroup.Files) { l->Entries[y] = (uint)((VoidPtr)(&e[y]) - baseAddr); e[y++]._fileId = file._fileIndex; //entries[i]._dataLength = 0; //entries[i]._dataOffset = 0; //entries[i]._headerLength = 0; //entries[i]._headerOffset = 0; } dataAddr = (VoidPtr)e + node._nullGroup.Files.Count * 0x18; //Write footer values[5] = (uint)dataAddr - (uint)baseAddr; *(INFOFooter*)dataAddr = node.ftr; //Set header header->_header._tag = INFOHeader.Tag; header->_header._length = len = ((int)((dataAddr + INFOFooter.Size) - (baseAddr - 8))).Align(0x20); return len; }
internal int CalculateSize(RSAREntryList entries, RSARNode node) { //Header _headerLen = 0x40; //SYMB, INFO, FILE Headers _symbLen = 0x20; _infoLen = 0x8; _fileLen = 0x20; #region SYMB //String offsets _symbLen += entries._strings.Count * 4; //Strings are packed tightly with no trailing pad _symbLen += entries._stringLength; //Mask entries _symbLen += 32; //Headers _symbLen += (entries._strings.Count * 2 - 4) * 20; //Entries //Align _symbLen = _symbLen.Align(0x20); #endregion #region Info //Info ruint collection and ruint list counts _infoLen += 0x30; int sounds = 4, playerInfo = 4, banks = 4, groups = 4, files = 4; //ruint sizes sounds += entries._sounds.Count * 8; playerInfo += entries._playerInfo.Count * 8; groups += entries._groups.Count * 8; banks += entries._banks.Count * 8 + 8; files += entries._files.Count * 8; //Evaluate entries with child offsets foreach (RSAREntryState s in entries._sounds) sounds += s._node.CalculateSize(true); foreach (RSAREntryState s in entries._playerInfo) playerInfo += s._node.CalculateSize(true); foreach (RSAREntryState s in entries._banks) banks += s._node.CalculateSize(true); foreach (RSAREntryState s in entries._groups) groups += s._node.CalculateSize(true); groups += INFOGroupHeader.Size + 4; //Null group at the end groups += node._nullGroup.Files.Count * 32; foreach (RSARFileNode s in entries._files) { files += INFOFileHeader.Size + 4; if (!(s is RSARExtFileNode)) files += s._groups.Count * (8 + INFOFileEntry.Size); else files += (s._extPath.Length + 1).Align(4); } //Footer and Align _infoLen = ((_infoLen += (sounds + banks + playerInfo + files + groups)) + 0x10).Align(0x20); #endregion #region File foreach (RSAREntryState r in entries._groups) { RSARGroupNode g = r._node as RSARGroupNode; foreach (RSARFileNode f in g.Files) _fileLen += f.CalculateSize(true); } foreach (RSARFileNode f in node._nullGroup.Files) _fileLen += f.CalculateSize(true); //Align _fileLen = _fileLen.Align(0x20); #endregion return _headerLen + _symbLen + _infoLen + _fileLen; }