Mercurial > projects > mde
view mde/content/ValueCache.d @ 156:36df0ffe34d2
Fix to reload translations.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sat, 18 Apr 2009 21:51:03 +0200 |
parents | 9f035cd139c6 |
children |
line wrap: on
line source
/* LICENSE BLOCK Part of mde: a Modular D game-oriented Engine Copyright © 2007-2008 Diggory Hardy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /****************************************************************************** * This module is used to load and save content values to/from a struct. *****************************************************************************/ module mde.content.ValueCache; import mde.file.paths; import mde.file.mergetag.MTTagReader; import mde.file.mergetag.MTTagWriter; import mde.file.serialize; import tango.util.log.Log : Log, Logger; private Logger logger; static this () { logger = Log.getLogger ("mde.gui.content.ValueCache"); } typedef char[] enumVal; // use a char[] to save enum values (it's more resiliant to change of the enum type) struct ValueCache { //BEGIN Templates package static { // All supported content types for generic saving and loading: template store(A...) { alias A store; } alias store!(bool, int, double, char[], enumVal) TYPES; // Get name of a type. Basically just stringof, but special handling for arrays. // Use TName!(T) for a valid symbol name, and T.stringof for a type. template TName(T : T[]) { const char[] TName = TName!(T) ~ "A"; } template TName(T) { const char[] TName = T.stringof; } template Vars(A...) { static if (A.length) { static if (is (A[0] == enumVal)) const char[] Vars = `char[][char[]] `~TName!(A[0])~`Data;` ~ Vars!(A[1..$]); else const char[] Vars = A[0].stringof~`[char[]] `~TName!(A[0])~`Data;` ~ Vars!(A[1..$]); } else const char[] Vars = ``; } // For reading tags template readTagMixin(T, A...) { const char[] ifBlock = `if (reader.tagType == "`~T.stringof~`") { auto p = symBuf[0..symEnd] in `~TName!(T)~`Data; if (p is null) `~TName!(T)~`Data[symBuf[0..symEnd].dup] = deserialize!(typeof(`~TName!(T)~`Data.values[0])) (reader.tagData); }`; static if (A.length) const char[] readTagMixin = ifBlock~` else `~readTagMixin!(A).readTagMixin; else const char[] readTagMixin = ifBlock; } // For writing tags template writeTagMixin(A...) { static if (A.length) const char[] writeTagMixin = `typeStr = "`~A[0].stringof~`"; foreach (sym,val; `~TName!(A[0])~`Data) { MTTagStrings tag; tag.type = typeStr; tag.data = serialize (val); // Take section prefix as MT section size_t dot; while (dot < sym.length && sym[dot] != '.') ++dot; if (dot == sym.length) { // no prefix; use "" dot = 0; tag.id = sym; } else tag.id = sym[dot+1..$]; secs[sym[0..dot]] ~= tag; }` ~ writeTagMixin!(A[1..$]); else const char[] writeTagMixin = ``; } } //END Templates mixin (Vars!(TYPES)); // variable associative arrays // Load content values from mergetag file(s) conf/options.mt[tb] // Use HIGH_LOW priority to load all data, HIGH_ONLY for just user data void loadData (PRIORITY priority) { try { MTTagReader reader = confDir.makeMTTagReader ("options", priority); bool isSecTag; while (reader.readTag (isSecTag) && !isSecTag) {} // skip header char[] symBuf = new char[64]; size_t sym2, symEnd; // start of second symbol in symBuf, end of symbol do { //debug logger.trace ("tag: <{}|{}={}> sec: {} ({})", reader.tagType, reader.tagID, reader.tagData, reader.section, isSecTag); if (isSecTag) { sym2 = reader.section.length; if (sym2 > 0) { // named section; prefix symbol by "section." if (symBuf.length <= sym2) symBuf.length = sym2 * 2; symBuf[0..sym2] = reader.section; symBuf[sym2++] = '.'; } } else { symEnd = reader.tagID.length; if (symBuf.length - sym2 < symEnd) symBuf.length = symBuf.length + symEnd * 2; symEnd += sym2; symBuf[sym2..symEnd] = reader.tagID; mixin (readTagMixin!(TYPES).readTagMixin); } } while (reader.readTag (isSecTag)) } catch (NoFileException e) { // Just return. Options file will be created on exit. } catch (Exception e) { logger.warn ("Loading options failed: "~e.msg); logger.warn ("If warning persists, delete the offending file."); } } // Save stored values to the user file void saveData () { try { MTTagWriter writer = confDir.makeMTTagWriter ("options.mtt"); // First sort tags by section: struct MTTagStrings { char[] type, id, data; } MTTagStrings[][char[]] secs; char[] typeStr; mixin (writeTagMixin!(TYPES)); // Now write sections: foreach (secName,sec; secs) { writer.sectionTag (secName); foreach (tag; sec) writer.dataTag (tag.type, tag.id, tag.data); } writer.close; } catch (Exception e) { logger.error ("Saving options failed: "~e.msg); } } }