Beispiel #1
0
        /// <summary>
        /// Method to retrieve a list of BoneModifiers from a selected card in the maker, without loading a character.
        /// </summary>
        public static List <BoneModifier> GetBoneModifiersFromCard()
        {
            ChaFile             file      = Utilities.GetSelectedCharacter();
            PluginData          bonedata  = ExtendedSave.GetExtendedDataById(file, "KKABMPlugin.ABMData");
            List <BoneModifier> modifiers = new List <BoneModifier>();

            if (bonedata != null)
            {
                try
                {
                    switch (bonedata.version)
                    {
                    // Only support for version 2
                    case 2:
                        modifiers = LZ4MessagePackSerializer.Deserialize <List <BoneModifier> >((byte[])bonedata.data["boneData"]);
                        break;

                    default:
                        throw new NotSupportedException($"Save version {bonedata.version} is not supported");
                    }
                }
                catch (Exception ex)
                {
                    Logger.Log(LogLevel.Error, "[KK_Archetypes] Failed to load KKABMX extended data - " + ex);
                }
            }
            return(modifiers);
        }
            internal static void ExtendedCardLoad(ChaFile file)
            {
                Sideloader.Logger.LogDebug($"Loading card [{file.charaFileName}]");

                var extData = ExtendedSave.GetExtendedDataById(file, UARExtIDOld) ?? ExtendedSave.GetExtendedDataById(file, UARExtID);
                List <ResolveInfo> extInfo;

                if (extData == null || !extData.data.ContainsKey("info"))
                {
                    Sideloader.Logger.LogDebug("No sideloader marker found");
                    extInfo = null;
                }
                else
                {
                    var tmpExtInfo = (object[])extData.data["info"];
                    extInfo = tmpExtInfo.Select(x => ResolveInfo.Deserialize((byte[])x)).ToList();

                    Sideloader.Logger.LogDebug($"Sideloader marker found, external info count: {extInfo.Count}");

                    if (Sideloader.DebugLogging.Value)
                    {
                        foreach (ResolveInfo info in extInfo)
                        {
                            Sideloader.Logger.LogDebug($"External info: {info.GUID} : {info.Property} : {info.Slot}");
                        }
                    }
                }

                IterateCardPrefixes(ResolveStructure, file, extInfo);
            }
Beispiel #3
0
        public static string GetRegistrationID(this ChaFile chaFile)
        {
            string result = null;

            chaFile.SafeProc(a => result = a.GetHashCode().ToString(CultureInfo.InvariantCulture.NumberFormat));
            return(result);
        }
Beispiel #4
0
        public bool HaveNamesChanged(ChaFile chaFile)
        {
            //return trackedRegistrationIDs.Contains(chaFile.GetRegistrationID());
            var current = HashSetPool <string> .Get();

            try
            {
                foreach (var name in GetNamesToRegister(chaFile))
                {
                    current.Add(name.Key);
                }

                lock (_lock)
                {
                    if (!_regIDtoNamesMap.TryGetValue(chaFile.GetRegistrationID(), out var registered))
                    {
                        registered = new HashSet <string>();
                    }

                    return(!registered.SetEquals(current));
                }
            }
            finally
            {
                HashSetPool <string> .Release(current);
            }
        }
        private static bool SetCoordinateBytes(ChaFile __instance, byte[] data, Version ver)
        {
            List <byte[]> list            = MessagePackSerializer.Deserialize <List <byte[]> >(data);
            int           coordinateCount = list.Count;

            //Ensure the card doesn't have too few coordinates (typically happens converting a KKS card to KK)
#if KK
            if (coordinateCount < 7)
            {
                coordinateCount = 7;
            }
#elif KKS
            if (coordinateCount < 4)
            {
                coordinateCount = 4;
            }
#endif

            //Reinitialize the array with the new length
            __instance.coordinate = new ChaFileCoordinate[coordinateCount];
            for (int i = 0; i < coordinateCount; i++)
            {
                __instance.coordinate[i] = new ChaFileCoordinate();
            }

            //Load all the coordinates
            for (int i = 0; i < list.Count; i++)
            {
                __instance.coordinate[i].LoadBytes(list[i], ver);
            }

            return(false);
        }
Beispiel #6
0
        private static void ExtendedCardLoad(ChaFile file)
        {
            Logger.Log(LogLevel.Debug, $"Loading card [{file.charaFileName}]");

            var extData = ExtendedSave.GetExtendedDataById(file, UniversalAutoResolver.UARExtID);
            List <ResolveInfo> extInfo;

            if (extData == null || !extData.data.ContainsKey("info"))
            {
                Logger.Log(LogLevel.Debug, "No sideloader marker found");
                extInfo = null;
            }
            else
            {
                var tmpExtInfo = (object[])extData.data["info"];
                extInfo = tmpExtInfo.Select(x => ResolveInfo.Unserialize((byte[])x)).ToList();

                Logger.Log(LogLevel.Debug, "Sideloader marker found");
                Logger.Log(LogLevel.Debug, $"External info count: {extInfo.Count}");
                foreach (ResolveInfo info in extInfo)
                {
                    Logger.Log(LogLevel.Debug, $"External info: {info.GUID} : {info.Property} : {info.Slot}");
                }
            }

            IterateCardPrefixes(UniversalAutoResolver.ResolveStructure, file, extInfo);
        }
            public static void ChaFileLoadFileHook(ChaFile file, BlockHeader header, BinaryReader reader)
            {
                var info = header.SearchInfo(Marker);

                if (info != null && info.version == Version.ToString())
                {
                    var originalPosition = reader.BaseStream.Position;
                    try
                    {
                        var basePosition = originalPosition - header.lstInfo.Sum(x => x.size);

                        reader.BaseStream.Position = basePosition + info.pos;

                        var data = reader.ReadBytes((int)info.size);

                        reader.BaseStream.Position = originalPosition;

                        var dictionary = MessagePackDeserialize <Dictionary <string, PluginData> >(data);
                        _internalCharaDictionary.Set(file, dictionary);
                    }
                    catch (Exception e)
                    {
                        _internalCharaDictionary.Set(file, new Dictionary <string, PluginData>());
                        _logger.Log(LogLevel.Warning, $"Invalid or corrupted extended data in card \"{file.charaFileName}\" - {e.Message}");
                        reader.BaseStream.Position = originalPosition;
                    }
                }
                else
                {
                    _internalCharaDictionary.Set(file, new Dictionary <string, PluginData>());
                }

                CardReadEvent(file);
            }
Beispiel #8
0
        internal static void UpdateTreeForChar(ChaFile chaFile, Action <string> callback)
        {
            if (chaFile == null)
            {
                return;
            }
            void Handler(string fullName)
            {
                if (string.IsNullOrEmpty(fullName))
                {
                    return;
                }
                var match = Singleton <IllusionStudio> .Instance.dicInfo
                            .Where(e => e.Value is OCIChar ociChar && ociChar.charInfo.chaFile == chaFile)
                            .Select(e => e.Key).FirstOrDefault();

                if (match == null)
                {
                    return;
                }
                match.textName = fullName;
                callback?.Invoke(fullName);
            }

            chaFile.TranslateFullName(Handler);
        }
Beispiel #9
0
 private static bool ShouldProcess(Component component, ChaFile chaFile)
 {
     return(component != null && chaFile != null &&
            TranslationHelper.Instance.CurrentCardLoadTranslationEnabled &&
            (!chaFile.TryGetTranslationHelperController(out var controller) ||
             (!controller.TranslationInProgress && !controller.IsTranslated)));
 }
Beispiel #10
0
    // rewrite our fake ids to the actual real ones again
    public override void OnCardSave(ChaFile f, BinaryWriter w, List <object> blocks, bool nopng)
    {
        var map = f.dict.Get <GuidMap>("guidmap");

        map.items.Clear();
        map.baseprefix     = null;
        coordRewriter.map  = map;
        customRewriter.map = map;
        foreach (var b in blocks)
        {
            var coords = b as ChaFileCoordinate[];
            if (coords != null)
            {
                for (int i = 0; i < coords.Length; i++)
                {
                    map.baseprefix = "coordinate[" + i + "]";
                    coordRewriter.FromFake(coords[i]);
                }
            }
            else if (b is ChaFileCustom)
            {
                map.baseprefix = "custom";
                customRewriter.FromFake(b);
            }
        }
    }
Beispiel #11
0
 internal void ExtendedSave_CardBeingLoaded(ChaFile file)
 {
     if (file != null && CurrentCardLoadTranslationMode != CardLoadTranslationMode.Disabled)
     {
         file.StartMonitoredCoroutine(CardNameManager.TranslateCardNames(file));
     }
 }
Beispiel #12
0
        public static void SaveFileHook(ChaFile __instance, bool __result, BinaryWriter bw, bool savePng)
        {
            if (!__result)
            {
                return;
            }

            ExtensibleSaveFormat.writeEvent(__instance);

            Dictionary <string, PluginData> extendedData = ExtensibleSaveFormat.GetAllExtendedData(__instance);

            if (extendedData == null)
            {
                return;
            }

            byte[] bytes = MessagePackSerializer.Serialize(extendedData);

            bw.Write(Marker);
            bw.Write(Version);
            foreach (KeyValuePair <string, PluginData> kv in extendedData)
            {
                PluginData dict = kv.Value as PluginData;
            }

            bw.Write((int)bytes.Length);
            bw.Write(bytes);
        }
Beispiel #13
0
        /// <summary>
        /// Card saving
        /// </summary>
        private void ExtendedCardSave(ChaFile file)
        {
            PluginData ExtendedData = ExtendedSave.GetExtendedDataById(file, "KK_FutaMod");

            if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa"))
            {
                if (Singleton <CustomBase> .IsInstance() && Singleton <CustomBase> .Instance.chaCtrl != null)
                {
                    //Saving card from chara maker, get the status from the character
                    ExtendedData.data["Futa"] = file.status.visibleSonAlways;
                    ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData);
                }
                else
                {
                    //Not in chara maker, keep the existing extended data
                    ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData);
                }
            }
            else
            {
                if (Singleton <CustomBase> .IsInstance() && Singleton <CustomBase> .Instance.chaCtrl != null)
                {
                    //Saving a character in chara maker that doesn't have extended data
                    ExtendedData      = new PluginData();
                    ExtendedData.data = new Dictionary <string, object> {
                        { "Futa", file.status.visibleSonAlways }
                    };
                    ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData);
                }
            }
        }
Beispiel #14
0
        public static bool Prefix_ChaFile_SaveFile(ChaFile __instance, BinaryWriter bw, bool savePng, int lang)
        {
            if (playerController == null)
            {
                return(true);
            }

            if (PlayerDeath.Value == DeathType.PermaDeath && playerController.ChaFileControl == __instance)
            {
                if (playerController["health"] == 0)
                {
                    return(false);
                }
            }
            else if (AgentDeath.Value == DeathType.PermaDeath)
            {
                foreach (var controller in agentControllers.Where(n => n != null))
                {
                    if (controller.ChaFileControl == __instance && controller["health"] == 0)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
            private static void ChaFileSaveFileHook(ChaFile file, BlockHeader header, ref long[] array3)
            {
                Dictionary <string, PluginData> extendedData = GetAllExtendedData(file);

                if (extendedData == null)
                {
                    currentlySavingData = null;
                    return;
                }

                currentlySavingData = MessagePackSerializer.Serialize(extendedData);

                //get offset
                long offset = array3.Sum();
                long length = currentlySavingData.LongLength;

                //insert our custom data length at the end
                Array.Resize(ref array3, array3.Length + 1);
                array3[array3.Length - 1] = length;

                //add info about our data to the block header
                BlockHeader.Info info = new BlockHeader.Info
                {
                    name    = Marker,
                    version = DataVersion.ToString(),
                    pos     = offset,
                    size    = length
                };

                header.lstInfo.Add(info);
            }
            private static void ChaFileLoadFileHook(ChaFile file, BlockHeader header, BinaryReader reader)
            {
                var info = header.SearchInfo(Marker);

                if (info != null && info.version == DataVersion.ToString())
                {
                    long originalPosition = reader.BaseStream.Position;
                    long basePosition     = originalPosition - header.lstInfo.Sum(x => x.size);

                    reader.BaseStream.Position = basePosition + info.pos;

                    byte[] data = reader.ReadBytes((int)info.size);

                    reader.BaseStream.Position = originalPosition;

                    cardReadEventCalled = true;

                    try
                    {
                        var dictionary = MessagePackSerializer.Deserialize <Dictionary <string, PluginData> >(data);
                        internalCharaDictionary.Set(file, dictionary);
                    }
                    catch (Exception e)
                    {
                        internalCharaDictionary.Set(file, new Dictionary <string, PluginData>());
                        Logger.LogWarning($"Invalid or corrupted extended data in card \"{file.charaFileName}\" - {e.Message}");
                    }

                    CardReadEvent(file);
                }
                else
                {
                    internalCharaDictionary.Set(file, new Dictionary <string, PluginData>());
                }
            }
Beispiel #17
0
        /// <summary>
        /// Method to load data from KKATData.
        /// </summary>
        /// <param key>Key to load</param>
        internal static void LoadHairColor(string key = null)
        {
            if (!_toggleHaircolor.Value)
            {
                return;
            }
            if (KK_Archetypes.Data.HaircolorDict.Count == 0)
            {
                return;
            }
            ChaFileHair add;

            if (key == null)
            {
                add = Utilities.GetRandomValue(KK_Archetypes.Data.HaircolorDict);
            }
            else
            {
                add = KK_Archetypes.Data.HaircolorDict[key];
            }
            ChaFile     file = MakerAPI.GetCharacterControl().chaFile;
            ChaFileHair curr = file.custom.hair;

            HairColorWriter(add, curr);
            file.custom.face.eyebrowColor   = Utilities.GetSlightlyDarkerColor(curr.parts[0].baseColor);
            file.custom.body.underhairColor = file.custom.face.eyebrowColor;
        }
Beispiel #18
0
        internal IEnumerator RegisterReplacements(ChaFile file)
        {
            if (file == null)
            {
                yield break;
            }
            //Logger.LogDebug($"RegisterReplacements {file} {file.parameter.fullname}");
            if (!RegistrationGameModes.Contains(CurrentGameMode))
            {
                yield break;
            }

            yield return(CardNameManager.WaitOnCard(file));

            if (RegistrationManager.IsTracked(file))
            {
                if (!RegistrationManager.HaveNamesChanged(file))
                {
                    yield break;
                }
                RegistrationManager.Untrack(file);
            }

            RegistrationManager.Track(file);
        }
Beispiel #19
0
        public static void ChaFileSaveFilePostHook(ChaFile __instance, bool __result, BinaryWriter bw, bool savePng)
        {
            Logger.Log(LogLevel.Debug, $"Reloading card [{__instance.charaFileName}]");

            var extData = ExtendedSave.GetExtendedDataById(__instance, UniversalAutoResolver.UARExtID);

            var tmpExtInfo = (List <byte[]>)extData.data["info"];
            var extInfo    = tmpExtInfo.Select(ResolveInfo.Unserialize).ToList();

            Logger.Log(LogLevel.Debug, $"External info count: {extInfo.Count}");
            foreach (ResolveInfo info in extInfo)
            {
                Logger.Log(LogLevel.Debug, $"External info: {info.GUID} : {info.Property} : {info.Slot}");
            }

            void ResetStructResolveStructure(Dictionary <CategoryProperty, StructValue <int> > propertyDict, object structure, IEnumerable <ResolveInfo> extInfo2, string propertyPrefix = "")
            {
                foreach (var kv in propertyDict)
                {
                    var extResolve = extInfo.FirstOrDefault(x => x.Property == $"{propertyPrefix}{kv.Key.ToString()}");

                    if (extResolve != null)
                    {
                        kv.Value.SetMethod(structure, extResolve.LocalSlot);

                        Logger.Log(LogLevel.Debug, $"[UAR] Resetting {extResolve.GUID}:{extResolve.Property} to internal slot {extResolve.LocalSlot}");
                    }
                }
            }

            IterateCardPrefixes(ResetStructResolveStructure, __instance, extInfo);
        }
Beispiel #20
0
        public static void ChaFileLoadFileHook(ChaFile file, BlockHeader header, BinaryReader reader)
        {
            var info = header.SearchInfo(Marker);

            if (info != null && info.version == Version.ToString())
            {
                long originalPosition = reader.BaseStream.Position;
                long basePosition     = originalPosition - header.lstInfo.Sum(x => x.size);

                reader.BaseStream.Position = basePosition + info.pos;


                byte[] data = reader.ReadBytes((int)info.size);

                reader.BaseStream.Position = originalPosition;


                var dictionary = MessagePackSerializer.Deserialize <Dictionary <string, PluginData> >(data);

                cardReadEventCalled = true;
                ExtendedSave.internalCharaDictionary.Set(file, dictionary);

                ExtendedSave.cardReadEvent(file);
            }
            else
            {
                ExtendedSave.internalCharaDictionary.Set(file, new Dictionary <string, PluginData>());
            }
        }
Beispiel #21
0
 public override void OnCardLoad(ChaFile f, BlockHeader bh, bool nopng, bool nostatus)
 {
     try
     {
         TryImport(f.dict.Get <KKEx>("kkex"), f.dict.Get <FakeID.GuidMap>("guidmap"));
     }
     catch { };
 }
Beispiel #22
0
        public bool CardNeedsTranslation(ChaFile file)
        {
            var sex = file.GetSex();

            return(file.EnumerateNames().Any(name =>
                                             StringUtils.ContainsJapaneseChar(name.Value) &&
                                             !NoTranslate[new NameScope(sex, file.GetNameType(name.Key))].Contains(name.Value)));
        }
Beispiel #23
0
 public bool IsTracked(ChaFile chaFile)
 {
     //return trackedRegistrationIDs.Contains(chaFile.GetRegistrationID());
     lock (_lock)
     {
         return(_regIDtoCardMap.ContainsKey(chaFile.GetRegistrationID()));
     }
 }
Beispiel #24
0
 public override void OnCardSave(ChaFile f, BinaryWriter w, List <object> blocks, bool nopng)
 {
     blocks.Add(f.dict.Get <KKEx>("kkex"));
     try
     {
         Ext.Raise <ExtendedSave>(null, "CardBeingSaved", f);
     }
     catch { };
 }
Beispiel #25
0
        public static void CopyChaFile(ChaFile dst, ChaFile src)
        {
            PluginData ExtendedData = ExtendedSave.GetExtendedDataById(src, "KK_FutaMod");

            if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa"))
            {
                ExtendedSave.SetExtendedDataById(dst, "KK_FutaMod", ExtendedData);
            }
        }
Beispiel #26
0
        public static Coroutine StartMonitoredCoroutine(this ChaFile chaFile, IEnumerator enumerator)
        {
            ChaControl chaControl = null;

            chaFile.SafeProc(cf => chaControl = cf.GetChaControl());
            return(chaControl != null
                ? chaControl.StartMonitoredCoroutine(enumerator)
                : TranslationHelper.Instance.StartCoroutine(enumerator));
        }
Beispiel #27
0
        public static void ChaFileSaveFilePostHook(ChaFile __instance, bool __result, BinaryWriter bw, bool savePng)
        {
            if (!__result || currentlySavingData == null)
            {
                return;
            }

            bw.Write(currentlySavingData);
        }
Beispiel #28
0
        private static void CardBeingSaved(ChaFile file)
        {
            var toRemove =
                ListInfoNameTranslatedMap.Keys.Where(k => System.IO.Path.GetFileName(k) == file.charaFileName).ToList();

            foreach (var path in toRemove)
            {
                ListInfoNameTranslatedMap.Remove(path);
            }
        }
        public static PluginData GetExtendedDataById(ChaFile file, string id)
        {
            PluginData extendedSection = null;

            if (internalDictionary.Get(file).TryGetValue(id, out extendedSection))
            {
                return(extendedSection);
            }
            return(null);
        }
Beispiel #30
0
 internal static void ChaFile_SaveFile_Postfix(ChaFile __instance)
 {
     // ReSharper disable once UseNullPropagation
     if (__instance == null)
     {
         return;
     }
     __instance.GetTranslationHelperController()
     .SafeProcObject(c => c.OnCardSaveComplete(KoikatuAPI.GetCurrentGameMode()));
 }
Beispiel #31
0
    void Start()
    {
        //加载资源
        foreach (Sprite s in heroSprites)
        {
            GameObject go = new GameObject();
            go.name = s.name.Substring(0, s.name.IndexOf('.'));
            SpriteRenderer sr = go.AddComponent<SpriteRenderer>();
            sr.sprite = s;

            go.transform.parent = this.transform;

            //存进字典方便查找
            spriteDic[go.name] = go;

            //加载旋转信息
            SpriteInfo si = go.AddComponent<SpriteInfo>();

            List<SpriteData> sd = PListFile.Parse(Application.dataPath + "/" + resourceFolder + "plist");

            for (int i = 0; i < sd.Count; i++)
            {
                if (sd[i].name.Equals(s.name))
                    if (sd[i].rotated == true)
                    {
                        si.needRotated = true;
                    }
            }

            //load animation file
            string path = Application.dataPath + "/" + resourceFolder + "cha";
            ChaLoader cl = new ChaLoader();
            animation = cl.Parse(path);

            //组织animation到Dic,方便索引 dictionary for fast search
            for (int i = 0; i < animation.animationList.Count; i++)
            {
                animations[animation.animationList[i].name] = animation.animationList[i];
            }
        }
    }
Beispiel #32
0
    public ChaFile Parse(string path)
    {
        FileInfo sourceFile = null;
        sourceFile = new FileInfo(path);
        if (sourceFile == null || !sourceFile.Exists)
        {
            Debug.LogError("File not exist or error:" + path);
            return null;
        }

        BinaryReader reader = new BinaryReader(sourceFile.OpenRead());

        ChaFile cf = new ChaFile();

        #region Read ChaFile

        //1.4 bytes,length of the name
        int cfNameLength = reader.ReadInt32();

        //2.name
        char[] name = new char[cfNameLength];
        reader.Read(name, 0, cfNameLength);
        cf.name = new string(name);
        //3.bone count
        int cfBoneNumber = reader.ReadInt32();

        //4.all bone infomation
        for (int i = 0; i < cfBoneNumber; i++)
        {
            BoneS bs = new BoneS();

            #region Read BoneS

            //4.1 bone name Length
            int boneNameLength = reader.ReadInt32();
            #region 其他方法
            //    reader.Read(boneNameLength, 0, 4);
            //    int nameLength = boneNameLength + (boneNameLength[1] << 8) + (boneNameLength[2] << 16) + (boneNameLength[3] << 24);
            #endregion
            bs.nameLength = boneNameLength;

            //bone name
            char[] boneName = new char[boneNameLength];
            reader.Read(boneName, 0, boneNameLength);
            bs.name = new string(boneName);

            //texture name length
            int textureNameLength = reader.ReadInt32();
            bs.textureNameLength = textureNameLength;

            //texture name
            char[] textureName = new char[textureNameLength];
            reader.Read(textureName, 0, textureNameLength);
            bs.textureName = new string(textureName);

            //bone id
            int id = reader.ReadInt32();
            bs.index = id;
            //add
            cf.boneList.Add(bs);
            #endregion
        }

        int cfAniamtionNumber = reader.ReadInt32();

        for (int i = 0; i < cfAniamtionNumber; i++)
        {
            sAnimation sa = new sAnimation();

            #region Read sAnimation

            cf.animationList.Add(sa);

            //name length
            int nameLength = reader.ReadInt32();

            //name
            char[] animationName = new char[nameLength];
            reader.Read(animationName, 0, nameLength);
            sa.name = new string(animationName);

            //4bytes unknovn.0Xc0
            byte[] c = reader.ReadBytes(4);

            //frame count
            int frameCount = reader.ReadInt32();

            //frame
            for (int index = 0; index < frameCount; index++)
            {
                frame f = new frame();

                #region Read frame

                sa.frames.Add(f);

                //frame type
                int ft = reader.ReadInt32();
                f.type = ft;

                #region 处理掉不需要的数据
                if (ft == 1)
                {
                    int ftTag = reader.ReadInt32();
                    int ftNameLength = reader.ReadInt32();
                    if (ft == 0)
                    {
                        byte[] ftName = reader.ReadBytes(4);
                    }
                    else
                    {
                        byte[] ftName = reader.ReadBytes(ftNameLength);
                    }

                    byte[] ftAudioInfo = reader.ReadBytes(32);

                    if (ft == 1)
                    {
                        ftTag = reader.ReadInt32();
                    }
                }
                #endregion

                //bone data count
                int bc = reader.ReadInt32();

                for (int j = 0; j < bc; j++)
                {
                    boneData bd = new boneData();

                    #region Read boneData

                    f.boneList.Add(bd);

                    //bone index
                    byte[] bIndex = reader.ReadBytes(2);
                    bd.boneIndex = (short)(bIndex[0] + (bIndex[1] << 8));

                    //bone transparent
                    bd.transparent = reader.ReadByte();

                    //bone data(float:6)
                    bd.data[0] = reader.ReadSingle();
                    bd.data[1] = reader.ReadSingle();
                    bd.data[2] = reader.ReadSingle();
                    bd.data[3] = reader.ReadSingle();
                    bd.data[4] = reader.ReadSingle();
                    bd.data[5] = reader.ReadSingle();

                    //offset
                    bd.data[1] *= -1.0f;
                    bd.data[2] *= -1.0f;
                    bd.data[4] *= 0.1f * 4f;
                    bd.data[5] *= -0.1f * 4f;

                    #endregion

                }
                #endregion

            }
            #endregion

        }
        #endregion
        return cf;
    }