public void SetMaskSlots(Maid maid, PresetData preset) {
     SetMaskSlots(maid, preset.slots);
 }
 public void SetDelNodes(Maid maid, PresetData preset, bool bApply) {
     // if (preset.delNodes == null) return;
     SetDelNodes(maid, preset.delNodes, bApply);
 }
 public void SetMaskSlots(PresetData preset) {
     SetMaskSlots(currentMaid, preset.slots);
 }
 // disable once MemberCanBeMadeStatic.Local
 public void ApplyPresetPartsColor(Maid maid, PresetData preset) {
     foreach(var pc in preset.partsColors) {
         MaidParts.PARTS_COLOR partsColor;
         try {
             partsColor = (MaidParts.PARTS_COLOR)Enum.Parse(typeof(MaidParts.PARTS_COLOR), pc.Key);
             maid.Parts.SetPartsColor(partsColor, pc.Value.toStruct());
         } catch(ArgumentException e) {
             LogUtil.Debug(e);
         }
     }
 }
 public void SetDelNodes(PresetData preset, bool bApply) {
     SetDelNodes(currentMaid, preset.delNodes, bApply);
 }
        /// <summary>
        /// XMLファイルからプリセット情報をロードする
        /// 旧版との互換性用メソッド
        /// </summary>
        /// <param name="fileName">XMLファイル名</param>
        /// <returns>ロードされたプリセット情報</returns>
        public Dictionary<string, PresetData> LoadXML(string fileName) {

            var xdoc = XDocument.Load(fileName);
            var presetNodes = xdoc.Descendants("preset");
            if (!presetNodes.Any()) {
                return null;
            }
            var presets = new Dictionary<string, PresetData>();
            try {
                foreach (var presetNode in presetNodes) {
                    var preset = new PresetData();
                    preset.name = GetAttribute(presetNode, "name");
                    
                    var slotsNode = presetNode.Element("slots");
                    if (slotsNode != null) {
                        var slotNodes = slotsNode.Elements("slot");
                        foreach (var slotNode in slotNodes) {
                            CCSlot slot = null;
                            var slotName = GetAttribute(slotNode, "slotname");
                            try {
                                slot = new CCSlot(slotName);
                            } catch(Exception e) {
                                LogUtil.Log("未対応のスロットをスキップします.", slotName, e);
                                continue;
                            }
                            var materialNodes = slotNode.Elements("material");
                            foreach (var materialNode in materialNodes) {
                                var cmat = new CCMaterial();
                                cmat.name = GetElementVal(materialNode, "name");
                                cmat.shader = GetElementVal(materialNode, "shader");
                                var colorNode = materialNode.Element("color");
                                if (colorNode != null) cmat.color = loadColor(colorNode);
                                colorNode = materialNode.Element("shadowColor");
                                if (colorNode != null) cmat.shadowColor = loadColor(colorNode);
                                colorNode = materialNode.Element("rimColor");
                                if (colorNode != null) cmat.rimColor = loadColor(colorNode);
                                colorNode = materialNode.Element("outlineColor");
                                if (colorNode != null) cmat.outlineColor = loadColor(colorNode);
                                var f = materialNode.Element("shininess");
                                if (f != null) cmat.shininess = (float)f;
                                f = materialNode.Element("outlineWidth");
                                if (f != null)  cmat.outlineWidth = (float)f;
                                f = materialNode.Element("rimPower");
                                if (f != null)  cmat.rimPower = (float)f;
                                f = materialNode.Element("rimShift");
                                if (f != null)  cmat.rimShift = (float)f;
                                f = materialNode.Element("hiRate");
                                if (f != null) cmat.hiRate = (float)f;
                                f = materialNode.Element("hiPow");
                                if (f != null) cmat.hiPow = (float)f;
                                f = materialNode.Element("floatValue1");
                                if (f != null) cmat.floatVal1 = (float)f;
                                f = materialNode.Element("floatValue2");
                                if (f != null) cmat.floatVal2 = (float)f;
                                f = materialNode.Element("floatValue3");
                                if (f != null) cmat.floatVal3 = (float)f;
                                slot.Add(cmat);
                            }
                            //preset.slots.Add(slot.name, slot);
                            preset.slots.Add(slot);
                        }
                    }
                    var mpnsNode = presetNode.Element("mpns");
                    if (mpnsNode != null) {
                        var mpnNodes = mpnsNode.Elements("mpn");
                        foreach (var mpnNode in mpnNodes) {
                            preset.mpns.Add(new CCMPN(GetAttribute(mpnNode, "name"), mpnNode.Value));
                        }
                    }
                    var nodesNode = presetNode.Element("nodes");
                    if (nodesNode != null) {
                        var nodes = nodesNode.Elements("node");
                        if (nodes.Any()) {
                            var delNodes = new Dictionary<string, bool>();
                            foreach (var node in nodes) {
                                var nodeName = GetAttribute(node, "name");
                                if (nodeName != null) {
                                    bool v = GetBoolAttribute(node, "visible");
                                    // 対応するノード名をそのまま使用
                                    if (ACConstants.NodeNames.ContainsKey(nodeName)) {
                                        delNodes.Add(nodeName, v);
                                    }
                                }
                            }
                            preset.delNodes = delNodes;
                        }
                    }
                    
                    presets.Add(preset.name, preset);
                }
            } catch(Exception e) {
                LogUtil.Error("failed to load presets. file=",fileName, ". ", e);
                return null; 
            }
            
            return presets;
        }
 public void ApplyPresetMPNProp(Maid maid, PresetData preset) {
     // 設定プロパティ反映
     foreach (var mpn in preset.mpnvals) {
         var mp = maid.GetProp(mpn.name);
         if (mp != null) {
             mp.value = mpn.value;
             if (mp.min > mpn.min)  {mp.min = mpn.min;}
             if (mp.max < mpn.max)  {mp.max = mpn.max;}
         } else {
             LogUtil.Debug("failed to apply MaidProp. mpn:", mpn.name);
         }
     }
 }
        public void ApplyPresetMaterial(Maid maid, PresetData preset) 
        {
            if (maid == null) maid = holder.currentMaid;
            if (maid == null) return;

            foreach (var ccslot in preset.slots) {
                int slotNo = (int)ccslot.id;
                if (slotNo >= maid.body0.goSlot.Count) continue; // スロットがないケースはスキップ

                // スロット上のマテリアル番号での判断に変更
                TBodySkin slot = maid.body0.GetSlot(slotNo);
                Material[] materials = holder.GetMaterials(slot);
                if (slot.obj == null) {
                    LogUtil.Debug("slot.obj null. name=", ccslot.id);
                }
                if (!materials.Any()) continue; // 未装着スロットはスキップ

                var slotName = ccslot.id.ToString();
                int matNo=-1;
                foreach (CCMaterial cmat in ccslot.materials) {
                    if (++matNo < materials.Length) {
                        Material m = materials[matNo];
                        if (cmat.name != m.name) {
                            LogUtil.DebugF("Material name mismatched. skipping apply preset-slot={0}, matNo={1}, name=({2}<=>{3})", 
                                     ccslot.id, matNo, cmat.name, m.name);
                            continue;
                        }
                        cmat.Apply(m);

                        // テクスチャ適用
                        List<TextureInfo> texes = cmat.texList;
                        if (texes == null) continue;

                        foreach (var texInfo in texes) {
                            var tex = m.GetTexture(texInfo.propName);
                            // テクスチャファイルの変更
                            if (tex == null || tex.name != texInfo.texFile) {
                                var filename = texInfo.texFile;
                                if (filename.LastIndexOf('.') == -1) {
                                    filename += FileConst.EXT_TEXTURE;
                                }
                                // if (!filename.EndsWith(FileConst.EXT_TEXTURE, StringComparison.OrdinalIgnoreCase)) {
                                // ファイルが存在する場合にのみ適用
                                if (fileUtil.Exists(filename)) {
                                    maid.body0.ChangeTex(slotName, matNo, texInfo.propName, filename, null, MaidParts.PARTS_COLOR.NONE);

                                    // ChangeTexは、nameにファイル名が設定されてしまうため、拡張子を除いた名前を再設定
                                    var changedTex = m.GetTexture(texInfo.propName);
                                    if (changedTex != null) {
                                        changedTex.name = texInfo.texFile;
                                    }
                                } else {
                                    LogUtil.Debug("texture file not found. file=", filename);
                                }
                            }

                            // フィルタ適用
                            if (texInfo.filter != null) {
                                var fp = texInfo.filter.ToFilter();
                                texModifier.ApplyFilter(maid, slotName, m, texInfo.propName, fp);
                            }
                        }
                    } else {
                        LogUtil.LogF("マテリアル番号に一致するマテリアルが見つかりません。 slot={0}, matNo={1}, name={2}", 
                                     ccslot.id, matNo, cmat.name);
                        break;
                    }
                }
            }
        }
        public void ApplyPresetMPN(Maid maid, PresetData preset, bool applyBody, bool applyWear, bool castoff) {
            // 衣装チェンジ
            foreach (var mpn in preset.mpns) {
                if (!applyBody) {
                    // bodyのMPNをスキップ
                    if (TypeUtil.IsBody(mpn.name)) continue;
                }
                if (!applyWear) {
                    // wearのMPNをスキップ
                    if (TypeUtil.IsWear(mpn.name)) continue;
                }

                if (mpn.filename.EndsWith("_del.menu", StringComparison.OrdinalIgnoreCase)) {
                    if (castoff) {
                        maid.SetProp(mpn.name, mpn.filename, 0, false);
                    }
                    continue;
                // } else if (mpn.filename.EndsWith(".mod", StringComparison.OrdinalIgnoreCase)) {
                }
                // menuファイルが存在しない場合はスキップ
                if (!fileUtil.Exists(mpn.filename)) continue;

                maid.SetProp(mpn.name, mpn.filename, 0, false);
            }

            if (applyBody) {
                // 設定プロパティ反映
                foreach (var mpn in preset.mpnvals) {
                    var mp = maid.GetProp(mpn.name);
                    if (mp != null) {
                        mp.value = mpn.value;
                        if (mp.min > mpn.min)  {mp.min = mpn.min;}
                        if (mp.max < mpn.max)  {mp.max = mpn.max;}
                    } else {
                        LogUtil.Debug("failed to apply MaidProp. mpn:", mpn.name);
                    }
                }
            }
            //maid.AllProcPropSeqStart();
        }
        public void SavePreset(string fileName, PresetData preset) {
            if (File.Exists(fileName)) {
                File.Delete(fileName);
            }

            // ファイル出力
            var jws = new JsonWriterSettings();
            //jws.Tab = "  ";
            jws.MaxDepth = 200;
            jws.PrettyPrint = true;
            using (FileStream fs = File.OpenWrite(fileName))
            using (var writer = new CustomJsonWriter(fs, jws)) {
                writer.ignoreNull = true;
                writer.Write(preset);
            }
            LogUtil.Debug("preset saved...", fileName);
        }
    // ACCの変更情報を適用する
    private void ApplyPresetProp(Maid targetMaid, PresetData preset) {
        try {
            // 対象メイドが変更された場合はスキップ
            if (holder.currentMaid != targetMaid) return;

            if (bPresetApplyWear) {
                presetMgr.ApplyPresetMaterial(targetMaid, preset);
            }
            if (bPresetApplyNode && preset.delNodes != null) {
                // 表示ノードを反映 (プリセットで未定義のノードは変更されない)
                foreach (var node in preset.delNodes) {
                    dDelNodes[node.Key] = node.Value;
                }
                holder.SetDelNodes(targetMaid, preset, false);
            }
            if (bPresetApplyMask) {
                holder.SetMaskSlots(targetMaid, preset);
            }
            holder.FixFlag(targetMaid);

            // freeColor
            if (bPresetApplyPartsColor && preset.partsColors.Any()) {
                presetMgr.ApplyPresetPartsColor(targetMaid, preset);
            }

        } finally {
            LogUtil.Debug("Preset applyed");
        }
    }
    private void ApplyPreset(PresetData preset) {
        if (preset == null) return;

        var maid = holder.currentMaid;;
        // 衣装チェンジ
        if (preset.mpns.Any()) {
            presetMgr.ApplyPresetMPN(maid, preset, bPresetApplyBody, bPresetApplyWear, bPresetCastoff);
        }
        // 身体設定値
        if (bPresetApplyBodyProp & preset.mpnvals.Any()) {
            presetMgr.ApplyPresetMPNProp(maid, preset);
        }
        
        // 一旦、衣装や身体情報を適用⇒反映待ちをして、Coroutineにて残りを適用
        holder.FixFlag(maid);
        toApplyPresetMaid = maid; 

        // 後で実行 toApplyPresetMaid を指定することでメイド情報のロード完了後に実行
        //ApplyPresetProp(preset);
    }
    private bool ApplyPreset(string presetName1) {
        LogUtil.Debug("Applying Preset. ", presetName1);
        var filename = presetMgr.GetPresetFilepath(presetName1);
        if (!File.Exists(filename)) return false;

        currentPreset = presetMgr.Load(filename);
        if (currentPreset == null) return false;

        ApplyPreset(currentPreset);
        return true;
    }
        public void Save(string fileName,  string presetName, Dictionary<string, bool> dDelNodes) {
            Maid maid = holder.currentMaid;
            // カレントのメイドデータからプリセットデータを抽出
            var preset = new PresetData();
            preset.name = presetName;
            foreach (SlotInfo slotInfo in ACConstants.SlotNames.Values) {
                if (!slotInfo.enable) continue;

                TBodySkin slot = maid.body0.GetSlot((int)slotInfo.Id);
                // マスク情報を抽出
                SlotState maskState;
                if (slot.obj == null) {
                    maskState = SlotState.NotLoaded;
                } else if (!slot.boVisible) {
                    maskState = SlotState.Masked;
                } else {
                    maskState = SlotState.Displayed;
                }

                Material[] materialList = holder.GetMaterials(slot);
                if (materialList.Length == 0) continue;

                var slotItem = new CCSlot(slotInfo.Id);
                slotItem.mask = maskState;

                foreach (Material material in materialList) {
                    var type = ShaderType.Resolve(material.shader.name);
                    if (type == ShaderType.UNKNOWN) continue;
                    var cmat = new CCMaterial(material, type);
                    slotItem.Add(cmat);
                    foreach (var texProp in type.texProps) {
                        var tex2d = material.GetTexture(texProp.propId) as Texture2D;
                        if (tex2d == null || string.IsNullOrEmpty(tex2d.name)) continue;

                        var ti = new TextureInfo();
                        cmat.Add(ti);
                        ti.propName = texProp.keyName;
                        ti.texFile = tex2d.name;
                        var fp = texModifier.GetFilter(maid, slotInfo.Id.ToString(), material.name, tex2d.name);
                        if (fp != null && !fp.hasNotChanged()) ti.filter = new TexFilter(fp);
                    }
                }
                preset.slots.Add(slotItem);
            }

            for (int i = TypeUtil.BODY_START; i <= TypeUtil.BODY_END; i++) {
                var mpn = (MPN)Enum.ToObject(typeof(MPN), i);
                MaidProp mp = maid.GetProp(mpn);
                if (mp != null) {
                    if (!String.IsNullOrEmpty(mp.strFileName)) {
                        preset.mpns.Add(new CCMPN(mpn, mp.strFileName));
                    } else {
                        preset.mpnvals.Add(new CCMPNValue(mpn, mp.value, mp.min, mp.max));
                    }
                }
            }

            for (int i = TypeUtil.WEAR_START; i <= TypeUtil.WEAR_END; i++) {
                var mpn = (MPN)Enum.ToObject(typeof(MPN), i);
                MaidProp mp = maid.GetProp(mpn);
                if (mp != null && !String.IsNullOrEmpty(mp.strFileName)) {
                    preset.mpns.Add(new CCMPN(mpn, mp.strFileName));
                }
            }
//            for (int i = (int)MPN_TYPE_RANGE.FOLDER_BODY_START; i <= (int)MPN_TYPE_RANGE.FOLDER_BODY_END; i++) {
//                var mpn = (MPN)Enum.ToObject(typeof(MPN), i);
//                MaidProp mp = maid.GetProp(mpn);
//                if (mp != null) {
//                    LogUtil.Debug(mpn,":", mp.type, ", value=", mp.value, ", temp=", mp.temp_value, ", file=", mp.strFileName);
//                }
//            }

            // 無限色
            for (int j = TypeUtil.PARTSCOLOR_START; j <= TypeUtil.PARTSCOLOR_END; j++) {
                var pcEnum = (MaidParts.PARTS_COLOR)j;
                MaidParts.PartsColor part = maid.Parts.GetPartsColor(pcEnum);
                preset.partsColors[pcEnum.ToString()] = new CCPartsColor(part);
            }

            // 表示ノード
            preset.delNodes = new Dictionary<string, bool>(dDelNodes);
            
            LogUtil.Debug("create preset...", fileName);
            SavePreset(fileName, preset);
        }