Quick answer: Use buffer_string (null-terminated UTF-8). Or write a length-prefixed format: 4-byte length then raw bytes. Don’t mix buffer_write_text with reads expecting termination.

Player saves the name “Pál”. Loads “Pæl”. The non-ASCII byte was split across a read that assumed fixed-width. UTF-8 in buffers needs the right type.

The Symptom

Saved strings with non-ASCII characters come back garbled. ASCII works fine. Or strings get truncated at unexpected positions.

The Fix

Pattern 1: buffer_string for null-terminated UTF-8.

/// Write
var buf = buffer_create(1024, buffer_grow, 1);
buffer_write(buf, buffer_string, "Pál");

/// Read
buffer_seek(buf, buffer_seek_start, 0);
var name = buffer_read(buf, buffer_string);

buffer_string is null-terminated UTF-8. Safe for any text without embedded NULs.

Pattern 2: Length-prefixed.

/// Write
var bytes = string_byte_length(name);
buffer_write(buf, buffer_u32, bytes);
buffer_write(buf, buffer_text, name);

/// Read
var bytes = buffer_read(buf, buffer_u32);
var name = "";
repeat (bytes) name += chr(buffer_read(buf, buffer_u8));

This works even if the string contains a NUL. Slightly more code; perfectly portable.

buffer_text vs buffer_string

Verifying

Save and reload a non-ASCII test string (Greek, Japanese, accented Latin). Bytes match. show_debug_message can print before/after to confirm equality.

“buffer_string for safe text. Length-prefixed for binary-safe. UTF-8 round-trips.”

Related Issues

For surface lost, see surface lost. For instance deactivate, see deactivate.

buffer_string or length-prefix. UTF-8 survives.