Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Custom LUA type

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
vesperpallens
How do I cheat?
Reputation: 0

Joined: 02 Sep 2024
Posts: 3

PostPosted: Sun Aug 24, 2025 12:33 pm    Post subject: Custom LUA type Reply with quote

I wanted to create a custom lua type to interpret UTF-32LE strings, but as of now I'm stuck at valuetobytes function.

The issue seems to be on CE side and how it handles writing bytes

For reference:

Code:
function UTF8Codepoints(str)
...
end

function gd4string_valuetobytes(str,address)
    local idx = 0
    for codePoint in UTF8Codepoints( str ) do
        if codePoint < 0 or codePoint > 0x10FFFF or codePoint >= 0xD800 and codePoint <= 0xDFFF then codePoint = 0xFFFD end

        writeInteger( address + idx * 0x4, codePoint )
        idx = idx + 1
    end

    -- null terminator
    writeInteger(address + idx * 4, 0x0)

    return readByte( address ) or 0x0
end
-- and for reference:
registerCustomTypeLua('GD4 String', 1, gd4string_bytestovalue, gd4string_valuetobytes, false, true)


So let's say I have a XYZ123 string and replace it with ABCDEF where I get AYCDEF. Everything would work fine unless CE would restore the original bytes after the 'callback' (from what I suggest, it keeps a 8byte-ish buffer which then is restored taking return bytes into account). I tried changing the type's bytecount to 8/16 - I still get the old char somewhere.

Before passing that to Dark Byte directly, I just wanted to make sure I'm not retarded. How do I achieve the intended result?
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 152

Joined: 06 Jul 2014
Posts: 4690

PostPosted: Mon Aug 25, 2025 3:00 am    Post subject: Reply with quote

You shouldn't write to `address` in the `_valuetobytes` function. As the template indicates, you should return the bytes you want to write. The template shows them returning as multiple values, but it seems you can also return it as a Lua array too. There might be subtle differences, like how trying to write fewer bytes than necessary should leave the remaining bytes unchanged when returning multiple values but should zero the rest when returning a table (if I'm reading the source correctly).

Make sure the `bytecount` is big enough to write whatever string you want.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
vesperpallens
How do I cheat?
Reputation: 0

Joined: 02 Sep 2024
Posts: 3

PostPosted: Tue Aug 26, 2025 3:52 pm    Post subject: Reply with quote

I wish strings were more flexible Sad from my perspective, it would be even better.

If I use the function to write bytes manually, it seems more safe, because I have no idea what's gonna happen if memory is not initialized or used by something else when bytecount is huge. So either try that or have no valuetobytes feature for that type at all.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25763
Location: The netherlands

PostPosted: Tue Aug 26, 2025 5:12 pm    Post subject: Reply with quote

Right now when you return less than the number of strings it writes 0 to the bytes, and there's an issue with the lua stack with huge types which will cause CE to panic/crash

(fixed in next version)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25763
Location: The netherlands

PostPosted: Tue Aug 26, 2025 6:03 pm    Post subject: This post has 1 review(s) Reply with quote

But instead of lua, you can also use an auto assembler script for custom type

here's a script that might be of interest to you:
Code:

{$c}

char TypeName[]="My 32-bit string type";
int ByteSize=200;
char usedFloat=0;
char usesString=1;
char CallMethod=1;
unsigned short MaxStringSize=200;


#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

// Decode UTF-8 string into UTF-32LE buffer (preallocated)
// Returns number of codepoints written
size_t utf8_to_utf32le(const char *input, uint32_t *output, size_t max_output) {
    if (!input || !output || max_output == 0) return 0;

    size_t i = 0;
    const unsigned char *p = (const unsigned char *)input;

    while (*p && i < max_output - 1) { // reserve space for terminator
        uint32_t cp;
        if (*p < 0x80) {
            cp = *p++;
        } else if ((*p & 0xE0) == 0xC0) {
            cp = (*p++ & 0x1F) << 6;
            if ((*p & 0xC0) == 0x80) cp |= (*p++ & 0x3F);
        } else if ((*p & 0xF0) == 0xE0) {
            cp = (*p++ & 0x0F) << 12;
            if ((*p & 0xC0) == 0x80) cp |= (*p++ & 0x3F) << 6;
            if ((*p & 0xC0) == 0x80) cp |= (*p++ & 0x3F);
        } else if ((*p & 0xF8) == 0xF0) {
            cp = (*p++ & 0x07) << 18;
            if ((*p & 0xC0) == 0x80) cp |= (*p++ & 0x3F) << 12;
            if ((*p & 0xC0) == 0x80) cp |= (*p++ & 0x3F) << 6;
            if ((*p & 0xC0) == 0x80) cp |= (*p++ & 0x3F);
        } else {
            cp = 0xFFFD; // invalid
            p++;
        }
        output[i++] = cp;
    }

    output[i] = 0; // null terminate
    return i;
}


// UTF-8 encoding of UTF-32 codepoints into preallocated buffer
// Returns number of bytes written (excluding terminator)
size_t utf32le_to_utf8(const uint32_t *input, char *output, size_t max_output) {
    if (!input || !output || max_output == 0) return 0;

    size_t o = 0;
    for (size_t i = 0; input[i] != 0; i++) {
        uint32_t cp = input[i];

        // replace invalid codepoints
        if (cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) {
            cp = 0xFFFD;
        }

        if (cp < 0x80) {
            if (o + 1 >= max_output) break;
            output[o++] = (char)cp;
        } else if (cp < 0x800) {
            if (o + 2 >= max_output) break;
            output[o++] = 0xC0 | (cp >> 6);
            output[o++] = 0x80 | (cp & 0x3F);
        } else if (cp < 0x10000) {
            if (o + 3 >= max_output) break;
            output[o++] = 0xE0 | (cp >> 12);
            output[o++] = 0x80 | ((cp >> 6) & 0x3F);
            output[o++] = 0x80 | (cp & 0x3F);
        } else {
            if (o + 4 >= max_output) break;
            output[o++] = 0xF0 | (cp >> 18);
            output[o++] = 0x80 | ((cp >> 12) & 0x3F);
            output[o++] = 0x80 | ((cp >> 6) & 0x3F);
            output[o++] = 0x80 | (cp & 0x3F);
        }
    }

    output[o] = '\0';
    return o;
}


//The convert routine should hold a routine that converts the data to a string
//input is a pointer to the data (max buffersize long)
//output is utf8
__cdecl int ConvertRoutine(unsigned char *data, unsigned long long address, unsigned char *output)
{
  utf32le_to_utf8(data, output, 100);
}

//The convert back routine should hold a routine that converts the given integer back to a row of bytes (e.g when the user wats to write a new value)
__cdecl void ConvertBackRoutine(unsigned char *input, unsigned long long address, unsigned char *output) //
{
  utf8_to_utf32le(input, output, 100);
}

{$asm}


and yes, I just blindly copied chatgpt for the conversion routines. You may need to adjust that as I suck at string conversions
(maybe also a max input size as well)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites