//takes a CraftData craft and creates a ConfigNode that contains all of it's public properties, ConfigNodes is held in
        //a <string, ConfigNode> dict with the full path as the key.
        internal void write(CraftData craft)
        {
            ConfigNode node = new ConfigNode();

            foreach (var prop in craft.GetType().GetProperties())
            {
                if (!ignore_fields.Contains(prop.Name))
                {
                    var value = prop.GetValue(craft, null);
                    if (value != null)
                    {
                        node.AddValue(prop.Name, value);
                    }
                }
            }
            string path = sanitize_path(craft.path);

            if (craft_data.ContainsKey(path))
            {
                craft_data[path] = node;
            }
            else
            {
                craft_data.Add(path, node);
            }
            save();
        }
        //Takes a CraftData craft object and if the cached data contains a matching path AND the checksum value matches
        //then the craft's properties are populated from the ConfigNode in the cache.  Returns true if matching data was
        //found, otherwise returns false, in which case the data will have to be interpreted from the .craft file.
        internal bool try_fetch(CraftData craft)
        {
            string path = sanitize_path(craft.path);

            if (craft_data.ContainsKey(path) && craft_data[path].GetValue("checksum") == craft.checksum && craft_data[path].GetValue("part_sig") == installed_part_sig)
            {
                try{
//                    CraftManager.log("loading from CACHE: " + Path.GetFileNameWithoutExtension(path));
                    CraftData.cache_load_count += 1; //increment count of craft loaded from cache
                    ConfigNode node = craft_data[path];
                    foreach (var prop in craft.GetType().GetProperties())
                    {
                        if (prop.CanWrite)
                        {
                            var node_value = node.GetValue(prop.Name);
                            if (!String.IsNullOrEmpty(node_value))
                            {
                                var type = prop.GetValue(craft, null);
                                if (type is float)
                                {
                                    prop.SetValue(craft, float.Parse(node_value), null);
                                }
                                else if (type is int)
                                {
                                    prop.SetValue(craft, int.Parse(node_value), null);
                                }
                                else if (type is bool)
                                {
                                    prop.SetValue(craft, bool.Parse(node_value), null);
                                }
                                else
                                {
                                    prop.SetValue(craft, node_value, null);
                                }
                            }
                        }
                    }
                    if (node.HasValue("locked_parts"))
                    {
                        craft.locked_parts_checked = true;
                    }
                    return(true);
                }
                catch (Exception e) {
                    CraftManager.log("try_fetch failed: " + e.Message + "\n" + e.StackTrace);
                    return(false);
                }
            }
            else
            {
                return(false);
            }
        }