Language finished.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: us\n"
|
||||
"Language: en_US\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
@@ -100,7 +100,7 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
||||
.zipFile = file,
|
||||
.output = output
|
||||
};
|
||||
errorChain(def->custom(&customData));
|
||||
errorChain(def->custom(customData));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -35,7 +35,7 @@ typedef struct {
|
||||
const assetloadstrat_t loadStrategy;
|
||||
union {
|
||||
errorret_t (*entire)(void *data, void *output);
|
||||
errorret_t (*custom)(assetcustom_t *custom);
|
||||
errorret_t (*custom)(assetcustom_t custom);
|
||||
};
|
||||
} assettypedef_t;
|
||||
|
||||
@@ -61,6 +61,6 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
||||
[ASSET_TYPE_LANGUAGE] = {
|
||||
.header = "DLF",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
.custom = assetLanguageInit
|
||||
.custom = assetLanguageHandler
|
||||
}
|
||||
};
|
||||
@@ -6,9 +6,108 @@
|
||||
*/
|
||||
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
#include "locale/localemanager.h"
|
||||
|
||||
errorret_t assetLanguageInit(assetcustom_t *custom) {
|
||||
zip_fclose(custom->zipFile);
|
||||
errorret_t assetLanguageHandler(assetcustom_t custom) {
|
||||
assertNotNull(custom.zipFile, "Custom asset zip file cannot be NULL");
|
||||
assertNotNull(custom.output, "Custom asset output cannot be NULL");
|
||||
|
||||
assetlanguage_t *lang = (assetlanguage_t *)custom.output;
|
||||
errorChain(assetLanguageInit(lang, custom.zipFile));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetLanguageInit(
|
||||
assetlanguage_t *lang,
|
||||
zip_file_t *zipFile
|
||||
) {
|
||||
assertNotNull(lang, "Language asset cannot be NULL");
|
||||
assertNotNull(zipFile, "Zip file cannot be NULL");
|
||||
assertNull(lang->zip, "Language asset zip file must be NULL.");
|
||||
assertTrue(zip_file_is_seekable(zipFile), "Language file must be seekable.");
|
||||
|
||||
// We now own the zip file handle.
|
||||
lang->zip = zipFile;
|
||||
printf("Initialized language asset.\n");
|
||||
|
||||
// Read in the header.
|
||||
zip_int64_t bytesRead = zip_fread(
|
||||
lang->zip,
|
||||
&lang->header,
|
||||
sizeof(assetlanguageheader_t)
|
||||
);
|
||||
if(bytesRead != sizeof(assetlanguageheader_t)) {
|
||||
zip_fclose(lang->zip);
|
||||
errorThrow("Failed to read language asset header.");
|
||||
}
|
||||
|
||||
lang->chunksOffset = zip_ftell(lang->zip);
|
||||
if(lang->chunksOffset <= 0) {
|
||||
zip_fclose(lang->zip);
|
||||
errorThrow("Failed to get language asset chunks offset.");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetLanguageRead(
|
||||
assetlanguage_t *lang,
|
||||
const uint32_t key,
|
||||
char_t *buffer,
|
||||
const uint32_t bufferSize,
|
||||
uint32_t *outLength
|
||||
) {
|
||||
assertNotNull(lang, "Language asset cannot be NULL");
|
||||
assertNotNull(lang->zip, "Language asset zip file cannot be NULL");
|
||||
assertTrue(key < LANG_KEY_COUNT, "Language key out of bounds.");
|
||||
|
||||
// Find the string entry
|
||||
assetlanguagestring_t *str = &lang->header.strings[LANG_MAP_TEST];
|
||||
|
||||
// If buffer is NULL, return the string length
|
||||
if(buffer == NULL) {
|
||||
assertNotNull(outLength, "Output length pointer cannot be NULL.");
|
||||
*outLength = str->length;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Ensure buffer is large enough
|
||||
assertTrue(
|
||||
bufferSize >= str->length + 1,
|
||||
"Provided buffer is too small for language string."
|
||||
);
|
||||
|
||||
// Determine the file position
|
||||
zip_int64_t seekTo = lang->chunksOffset + (
|
||||
(str->chunk * ASSET_LANG_CHUNK_CHAR_COUNT) + str->offset
|
||||
);
|
||||
|
||||
// Seek
|
||||
zip_int64_t result = zip_fseek(lang->zip, seekTo, SEEK_SET);
|
||||
if(result != 0) {
|
||||
errorThrow("Failed to seek to language string in asset.");
|
||||
}
|
||||
|
||||
// Read
|
||||
zip_int64_t readTest = zip_fread(lang->zip, buffer, str->length);
|
||||
if(readTest != str->length) {
|
||||
errorThrow("Failed to read test string from language asset.");
|
||||
}
|
||||
buffer[str->length] = '\0';
|
||||
|
||||
// Set str length if requested
|
||||
if(outLength != NULL) *outLength = str->length;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void assetLanguageDispose(assetlanguage_t *lang) {
|
||||
assertNotNull(lang, "Language asset cannot be NULL");
|
||||
|
||||
if(lang->zip) {
|
||||
zip_fclose(lang->zip);
|
||||
}
|
||||
|
||||
printf("Disposed language asset.\n");
|
||||
}
|
||||
@@ -6,10 +6,12 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "locale/language/keys.h"
|
||||
#include "error/error.h"
|
||||
#include <zip.h>
|
||||
|
||||
#define ASSET_LANG_CHUNK_CHAR_COUNT 6 * 1024 // 6 KB per chunk
|
||||
#define ASSET_LANG_CHUNK_CACHE 4 // Number of chunks to cache in memory
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef char assetlanguagechunk_t[ASSET_LANG_CHUNK_CHAR_COUNT];
|
||||
@@ -29,12 +31,57 @@ typedef struct {
|
||||
} assetlanguageheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
zip_file_t *zip;
|
||||
assetlanguageheader_t header;
|
||||
zip_int64_t chunksOffset;
|
||||
|
||||
// Chunk cache
|
||||
assetlanguagechunk_t chunks[ASSET_LANG_CHUNK_CACHE];
|
||||
uint32_t chunkIndices[ASSET_LANG_CHUNK_CACHE];
|
||||
} assetlanguage_t;
|
||||
|
||||
typedef struct assetcustom_s assetcustom_t;
|
||||
|
||||
/**
|
||||
* Receiving function from the asset manager to initialize language assets.
|
||||
* Receiving function from the asset manager to handle language assets.
|
||||
*
|
||||
* @param custom Pointer to custom asset loading data.
|
||||
* @param custom Custom asset loading data.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetLanguageInit(assetcustom_t *custom);
|
||||
errorret_t assetLanguageHandler(assetcustom_t custom);
|
||||
|
||||
/**
|
||||
* Initializes a language asset and loads the header data into memory.
|
||||
*
|
||||
* @param lang Language asset to initialize.
|
||||
* @param zipFile Zip file handle for the language asset.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetLanguageInit(assetlanguage_t *lang, zip_file_t *zipFile);
|
||||
|
||||
/**
|
||||
* Reads a string from the language asset into the provided buffer.
|
||||
*
|
||||
* @param lang Language asset to read from.
|
||||
* @param key Language key to read.
|
||||
* @param buffer Buffer to read the string into.
|
||||
* @param bufferSize Size of the provided buffer.
|
||||
* @param outLength Pointer to store the length of the string read.
|
||||
* @return Error code.
|
||||
*/
|
||||
errorret_t assetLanguageRead(
|
||||
assetlanguage_t *lang,
|
||||
const uint32_t key,
|
||||
char_t *buffer,
|
||||
const uint32_t bufferSize,
|
||||
uint32_t *outLength
|
||||
);
|
||||
|
||||
/**
|
||||
* Disposes of language asset resources.
|
||||
*
|
||||
* @param custom Custom asset loading data.
|
||||
* @return Error code.
|
||||
*/
|
||||
void assetLanguageDispose(assetlanguage_t *lang);
|
||||
@@ -54,6 +54,7 @@ void engineExit(void) {
|
||||
}
|
||||
|
||||
errorret_t engineDispose(void) {
|
||||
localeManagerDispose();
|
||||
sceneManagerDispose();
|
||||
rpgDispose();
|
||||
uiDispose();
|
||||
|
||||
@@ -8,12 +8,29 @@
|
||||
#include "localemanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
localemanager_t LOCALE;
|
||||
|
||||
errorret_t localeManagerInit() {
|
||||
memoryZero(&LOCALE, sizeof(localemanager_t));
|
||||
|
||||
errorChain(assetLoad("language/us.dlf", &LOCALE));
|
||||
errorChain(localeManagerSetLocale(DUSK_LOCALE_EN_US));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t localeManagerSetLocale(const dusklocale_t locale) {
|
||||
assertTrue(locale < DUSK_LOCALE_COUNT, "Invalid locale.");
|
||||
LOCALE.locale = locale;
|
||||
char_t languageFile[FILENAME_MAX];
|
||||
snprintf(
|
||||
languageFile, FILENAME_MAX, "language/%s.dlf", LOCALE_INFOS[locale].file
|
||||
);
|
||||
assetLanguageDispose(&LOCALE.language);
|
||||
memoryZero(&LOCALE.language, sizeof(assetlanguage_t));
|
||||
errorChain(assetLoad(languageFile, &LOCALE.language));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void localeManagerDispose() {
|
||||
assetLanguageDispose(&LOCALE.language);
|
||||
}
|
||||
@@ -6,12 +6,30 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "asset/asset.h"
|
||||
|
||||
typedef enum {
|
||||
DUSK_LOCALE_EN_US,
|
||||
|
||||
DUSK_LOCALE_COUNT
|
||||
} dusklocale_t;
|
||||
|
||||
typedef struct {
|
||||
void *nothing;
|
||||
dusklocale_t locale;
|
||||
assetlanguage_t language;
|
||||
} localemanager_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char_t *file;
|
||||
} localeinfo_t;
|
||||
|
||||
static const localeinfo_t LOCALE_INFOS[DUSK_LOCALE_COUNT] = {
|
||||
[DUSK_LOCALE_EN_US] = {
|
||||
.file = "en_US"
|
||||
}
|
||||
};
|
||||
|
||||
extern localemanager_t LOCALE;
|
||||
|
||||
/**
|
||||
@@ -19,4 +37,17 @@ extern localemanager_t LOCALE;
|
||||
*
|
||||
* @return An error code if a failure occurs.
|
||||
*/
|
||||
errorret_t localeManagerInit();
|
||||
errorret_t localeManagerInit();
|
||||
|
||||
/**
|
||||
* Set the current locale.
|
||||
*
|
||||
* @param locale The locale to set.
|
||||
* @return An error code if a failure occurs.
|
||||
*/
|
||||
errorret_t localeManagerSetLocale(const dusklocale_t locale);
|
||||
|
||||
/**
|
||||
* Dispose of the locale system.
|
||||
*/
|
||||
void localeManagerDispose();
|
||||
@@ -60,6 +60,8 @@ def processLanguageList():
|
||||
|
||||
# Now we can generate the language string chunks.
|
||||
nextChunkIndex = max(desiredChunkGroups.values()) + 1
|
||||
files = []
|
||||
|
||||
for lang in LANGUAGE_DATA:
|
||||
langData = LANGUAGE_DATA[lang]
|
||||
|
||||
@@ -102,7 +104,6 @@ def processLanguageList():
|
||||
|
||||
# We have now chunked all the keys for this language!
|
||||
langBuffer = b""
|
||||
files = []
|
||||
|
||||
# Write header info
|
||||
langBuffer += b'DLF' # Dusk Language File
|
||||
@@ -127,6 +128,12 @@ def processLanguageList():
|
||||
strData = langData[key].encode('utf-8')
|
||||
langBuffer += strData
|
||||
|
||||
# Now pad the chunk to full size
|
||||
curLen = chunkInfo['len']
|
||||
if curLen < LANGUAGE_CHUNK_CHAR_COUNT:
|
||||
padSize = LANGUAGE_CHUNK_CHAR_COUNT - curLen
|
||||
langBuffer += b'\0' * padSize
|
||||
|
||||
# Write out the language data file
|
||||
outputFile = os.path.join(args.output_assets, "language", f"{lang}.dlf")
|
||||
files.append(outputFile)
|
||||
|
||||
Reference in New Issue
Block a user