function initialization()
USE_ORIGIN_PACKAGE = nil;
USE_CLONING_PACKAGE = nil;
USE_UNAUTHORIZED_PACKAGE = nil;
USE_ORIGIN_VERSION = nil;
USE_HIGHER_VERSION = nil;
USE_UNAUTHORIZED_VERSION = nil;
USE_NO_PROCCESS = nil;
current_informations = gg.getTargetInfo();
informations = {
root_pointer_names = {[2] = "resources"},
value_type = gg.TYPE_DWORD,
memory_regions = gg.REGION_C_ALLOC | gg.REGION_C_HEAP,
count_resource_values = {in_total = 8, per_value = 4},
count_offsets = {},
show_help = true,
version_name = "1.41.2.103600",
version_code = 1041002
};
menus = {
main = {
{"FREEZE RESOURCE VALUES", "OPEN GAMEGUARDIAN", "EXIT"}, {"🌕 FREEZE RESOURCE VALUES", "🌕 OPEN GAMEGUARDIAN", "🌕 EXIT"},
prompt = "Choose menu: "
},
freeze_resource_values = {
{"EXPERIENCE", "SIMOLEON", "SIMCASH", "GOLDEN KEY", "PLATINUM KEY", "VU POINT", "NEOSIMOLEON", "WAR SIMOLEON", "BACK"},
prompt = "Choose resource values you want to freeze: "
}
};
for key, menu in pairs(menus) do
menus[key].handler = true;
menus[key].run = true;
menus[key].count = #menu[1];
end;
if current_informations.x64 then
informations.address_type = gg.TYPE_QWORD;
informations.offsets = {resource_values = {0x58, 0x5c, 0x60, 0x64, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c, 0x140, 0x144, 0x148, 0x14c, 0x150, 0x154, 0x168, 0x16c, 0x170, 0x174, 0x158, 0x15c, 0x160, 0x164, 0x178, 0x17c, 0x180, 0x184, 0x188, 0x18c, 0x190, 0x194}};
root_pointers = {resources = {constant_value = -1447275533, address_pattern = "13C"}};
parent_pointers = {resources = {count = 1}};
pointers = {resources = {position = 1, count = 1}};
else
informations.address_type = gg.TYPE_DWORD;
informations.offsets = {resource_values = {0x40, 0x44, 0x48, 0x4c, 0xb8, 0xbc, 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc, 0xe0, 0xe4, 0xf8, 0xfc, 0x100, 0x104, 0xe8, 0xec, 0xf0, 0xf4, 0x108, 0x10c, 0x110, 0x114, 0x118, 0x11c, 0x120, 0x124}};
root_pointers = {resources = {constant_value = -442551180, address_pattern = "77C"}};
parent_pointers = {resources = {count = 1}};
pointers = {resources = {position = 1, count = 1}};
end;
for key, offset in pairs(informations.offsets) do
informations.count_offsets[key] = #offset;
end;
data = {
is_cached = {
freeze_resource_values = false
},
resources = {
root_pointer = {}, parent_pointers = {}, pointers = {}
},
resource_values = {}
};
cache = {filename = gg.CACHE_DIR .. "/.script_cache"};
load_cache_data();
messages = {
positive = {"OK", "GOT IT"},
resources = {
search_toast = "Finding resources root pointer...",
ambiguous_constant_value = "Warning: Resources root pointer is ambiguous, %d found",
root_pointer_not_found = "Error: Resources root pointer was not found",
parent_pointers_not_found = "Error: Resources parent pointer was not found",
pointers_not_found = {
"Error: Resources pointer was not found"
}
},
no_options_chosen = "Warning: You must choose at least 1 option",
resource_values_frozen = "Succeeded to freeze resource values",
resource_values_frozen_already = "You have already frozen resource values",
file_permission_denied = "Error: Cannot access file '" .. cache.filename .. "': Permission denied",
show_help = "Notice: You are opening GameGuardian user interface. You can do anything here. When you are finished, you can go back by simply clicking on the Sx button (on upper left of the screen)",
use_unauthorized_package = "Error: The script can only be run on SimCity BuildIt application",
use_higher_version = "Warning: You are using SimCity by version " .. current_informations.versionName .. ".\nHowever the script run stably on SimCity " .. informations.version_name .. ", it is possible an error will occur if you keep continuing",
use_unauthorized_version = "Error: The script can only be run on SimCity version " .. informations.version_name .. " or later",
use_no_process = "Error: No process chosen",
exit_code_zero = "Script ended"
};
end;
function new_search(text, flag, encrypted, sign, memoryFrom, memoryTo, limit)
if flag == nil then flag = gg.TYPE_AUTO; end;
if encrypted == nil then encrypted = false; end;
if sign == nil then sign = gg.SIGN_EQUAL; end;
if memoryFrom == nil then memoryFrom = 0; end;
if memoryTo == nil then memoryTo = -1; end;
if limit == nil then limit = 0; end;
gg.setVisible(false);
gg.clearResults();
gg.searchNumber(text, flag, encrypted, sign, memoryFrom, memoryTo, limit);
end;
function get_results(maxCount, skip, addressMin, addressMax, valueMin, valueMax, flag, fractional, pointer)
if maxCount == nil then maxCount = gg.getResultsCount(); end;
if skip == nil then skip = 0; end;
local results = gg.getResults(maxCount, skip, addressMin, addressMax, valueMin, valueMax, flag, fractional, pointer);
gg.clearResults();
return results;
end;
function cache_results()
cache.results = get_results();
end;
function load_results()
gg.loadResults(cache.results);
cache.results = nil;
end;
function file_write(filename, content, append)
if append == nil then append = false; end;
local mode = not append and "w" or "a";
local file_handler = io.open(filename, mode);
if file_handler then
file_handler:write(content);
file_handler:close();
else
gg.alert(messages.file_permission_denied, messages.positive[1]);
os.exit(1);
end;
end;
function serialize(lua_table)
local i, results = 1, {};
for key, value in pairs(lua_table) do
if key == i then
key = "";
elseif type(key) == "string" then
key = "[" .. string.format("%q", key) .. "]=";
else
key = "[" .. key .. "]=";
end;
if type(value) == "boolean" or type(value) == "number" then
results[i] = key .. tostring(value);
elseif type(value) == "string" then
results[i] = key .. string.format("%q", value);
elseif type(value) == "table" then
results[i] = key .. serialize(value);
end;
i = i + 1;
end;
return "{" .. table.concat(results, ",") .. "}";
end;
function load_cache_data()
local file_handler = loadfile(cache.filename);
local is_succeeded, results = pcall(file_handler);
cache.data = {};
if is_succeeded and type(results) == "table" then
cache.data = results;
end;
end;
function save_cache_data()
file_write(cache.filename, "return " .. serialize(cache.data));
end;
function identify_root_pointer(value, name)
new_search(value.address, informations.address_type);
local count_parent_pointers = gg.getResultsCount();
if count_parent_pointers == parent_pointers[name].count then
local parent_pointers = get_results();
new_search(parent_pointers[count_parent_pointers].address, informations.address_type);
if gg.getResultsCount() > 0 then
data[name].root_pointer = value;
data[name].parent_pointers = parent_pointers;
local pointers = get_results();
if name ~= "items" then
data[name].pointers = pointers;
else
data[name].pointers.war_cards = pointers;
end;
return true;
end;
end;
return false;
end;
function find_root_pointer(name)
if not data[name].root_pointer.address then
gg.toast(messages[name].search_toast, true);
new_search(root_pointers[name].constant_value, informations.value_type);
gg.refineAddress(root_pointers[name].address_pattern);
local results = {};
local count_results = gg.getResultsCount();
if count_results >= 1 then
results = get_results();
if type(cache.data[name]) ~= "table" then cache.data[name] = {}; end;
if count_results == 1 then
data[name].root_pointer = results[1];
cache.data[name].position = 1;
else
local root_pointer_not_found = true;
if math.type(cache.data[name].position) == "integer" then
local root_pointer_position = cache.data[name].position;
if root_pointer_position >= 1 and root_pointer_position <= count_results then
if identify_root_pointer(results[root_pointer_position], name) then
root_pointer_not_found = false;
else
results[root_pointer_position] = nil;
end;
end;
end;
if root_pointer_not_found then
gg.alert(string.format(messages[name].ambiguous_constant_value, count_results), messages.positive[1]);
for i, root_pointer in pairs(results) do
if identify_root_pointer(root_pointer, name) then
root_pointer_not_found = false;
cache.data[name].position = i;
break;
end;
end;
if root_pointer_not_found then
gg.clearResults();
gg.alert(messages[name].root_pointer_not_found, messages.positive[1]);
os.exit(2);
end;
end;
end;
save_cache_data();
else
gg.alert(messages[name].root_pointer_not_found, messages.positive[1]);
os.exit(1);
end;
end;
end;
function find_parent_pointers(name)
find_root_pointer(name);
if not data[name].parent_pointers[1] then
new_search(data[name].root_pointer.address, informations.address_type);
if gg.getResultsCount() == parent_pointers[name].count then
data[name].parent_pointers = get_results();
else
gg.clearResults();
gg.alert(messages[name].parent_pointers_not_found, messages.positive[1]);
os.exit(1);
end;
end;
end;
function find_pointers(root_pointer_name, name)
find_parent_pointers(root_pointer_name);
if name == nil then name = 1; end;
local is_items_pointer = name ~= 1;
if is_items_pointer and not data[root_pointer_name].pointers[name][1] or not data[root_pointer_name].pointers[name] then
local position = is_items_pointer and pointers[name].position or pointers[root_pointer_name].position;
new_search(data[root_pointer_name].parent_pointers[position].address, informations.address_type);
if gg.getResultsCount() > 0 then
local results = get_results();
if is_items_pointer then
data[root_pointer_name].pointers[name] = results;
else
data[root_pointer_name].pointers = results;
end;
else
gg.clearResults();
gg.alert(messages[root_pointer_name].pointers_not_found[name]);
os.exit(1);
end;
end;
end;
function count(table)
local count_table = 0;
for i in pairs(table) do
count_table = count_table + 1;
end;
return count_table;
end;
function toboolean(table)
local results = {};
for i in pairs(table) do
if table[i] then
results[i] = true;
else
results[i] = false;
end;
end;
return results;
end;
function is_new_option(previous_options, current_options, count_options)
previous_options[count_options] = nil;
current_options[count_options] = nil;
local count_previous_options = count(previous_options);
local count_current_options = count(current_options);
if count_previous_options == count_current_options then
for previous_option in pairs(previous_options) do
if not current_options[previous_option] then
return true;
end;
end;
return false;
else
return true;
end;
end;
function main_menu()
gg.removeListItems(data.resource_values);
if type(cache.data.freeze_resource_values) ~= "table" then
cache.data.freeze_resource_values = {};
end;
local choices = {};
local default_choice = nil;
if math.type(cache.data.freeze_resource_values.main_menu) == "integer" then
if cache.data.freeze_resource_values.main_menu >= 1 and cache.data.freeze_resource_values.main_menu <= menus.main.count then
default_choice = cache.data.freeze_resource_values.main_menu;
end;
end;
if default_choice then
choices = menus.main[1];
else
choices = menus.main[2];
end;
local choice = gg.choice(choices, default_choice, menus.main.prompt);
if choice then
menus.main.run = true;
if choice < menus.main.count then
menus.freeze_resource_values.handler = true;
menus.freeze_resource_values.run = true;
cache.data.freeze_resource_values.main_menu = choice;
save_cache_data();
end;
else
menus.main.run = false;
gg.addListItems(data.resource_values);
end;
return choice;
end;
function menu()
gg.removeListItems(data.resource_values);
if type(cache.data.freeze_resource_values.menu) ~= "table" then
cache.data.freeze_resource_values.menu = {};
end;
local default_choices = toboolean(cache.data.freeze_resource_values.menu);
menus.freeze_resource_values.previous_choices = default_choices;
local choices = gg.multiChoice(menus.freeze_resource_values[1], default_choices, menus.freeze_resource_values.prompt);
menus.freeze_resource_values.run = false;
if choices then
local count_choices = count(choices);
if count_choices > 0 then
if choices[menus.freeze_resource_values.count] then
menus.freeze_resource_values.handler = false;
menus.main.run = true;
end;
if not choices[menus.freeze_resource_values.count] or count_choices > 1 then
for i = 1, menus.freeze_resource_values.count, 1 do
if choices[i] then
cache.data.freeze_resource_values.menu[i] = true;
else
cache.data.freeze_resource_values.menu[i] = nil;
end;
end;
save_cache_data();
else
cache.data.freeze_resource_values.menu = {};
end;
else
menus.freeze_resource_values.run = true;
end;
else
gg.addListItems(data.resource_values);
end;
return choices;
end;
function freeze_resource_values(choices)
if choices then
local count_choices = count(choices);
if count_choices > 0 then
local no_back_button = not choices[menus.freeze_resource_values.count];
local more_than_one = count_choices > 1;
if not data.is_cached.freeze_resource_values and (no_back_button or more_than_one) then
cache_results();
find_pointers(informations.root_pointer_names[2]);
data.is_cached.freeze_resource_values = true;
load_results();
gg.toast(messages.resource_values_frozen, false);
else
if no_back_button then
if menus.freeze_resource_values.previous_choices[menus.freeze_resource_values.count] or is_new_option(menus.freeze_resource_values.previous_choices, choices, menus.freeze_resource_values.count) then
gg.toast(messages.resource_values_frozen, true);
else
gg.toast(messages.resource_values_frozen_already, true);
end;
elseif more_than_one then
if is_new_option(menus.freeze_resource_values.previous_choices, choices, menus.freeze_resource_values.count) then
gg.toast(messages.resource_values_frozen, true);
end;
end;
end;
data.resource_values = {};
for i = 1, informations.count_resource_values.in_total, 1 do
if choices[i] then
local offset_start = (i - 1) * informations.count_resource_values.per_value + 1;
local offset_ended = i * informations.count_resource_values.per_value;
for i = offset_start, offset_ended, 1 do
data.resource_values[i] = {address = data[informations.root_pointer_names[2]].pointers[1].address + informations.offsets.resource_values[i], flags = informations.value_type};
end;
end;
end;
data.resource_values = gg.getValues(data.resource_values);
for i, resource_value in pairs(data.resource_values) do
resource_value.freeze = true;
end;
gg.addListItems(data.resource_values);
else
gg.toast(messages.no_options_chosen);
end;
end;
end;
function openGameGuardianUi()
gg.setVisible(true);
gg.showUiButton();
if informations.show_help and data[informations.root_pointer_names[2]].pointers[1] then
gg.alert(messages.show_help, messages.positive[2]);
informations.show_help = false;
end;
local run = true;
while run do
gg.removeListItems(data.resource_values);
while gg.isVisible() do
if gg.isClickedUiButton() then
gg.hideUiButton();
gg.setVisible(false);
run = false;
break;
end;
end;
gg.addListItems(data.resource_values);
while run and not gg.isVisible() do end;
end;
end;
function execute()
gg.setVisible(false);
gg.setRanges(informations.memory_regions);
while menus.main.handler do
if menus.main.run or gg.isVisible() then
gg.setVisible(false);
local choice = main_menu();
if choice == 1 then
while menus.freeze_resource_values.handler do
if menus.freeze_resource_values.run or gg.isVisible() then
gg.setVisible(false);
local choices = menu();
freeze_resource_values(choices);
end;
end;
elseif choice == 2 then
openGameGuardianUi();
elseif choice == 3 then
gg.toast(messages.exit_code_zero, true);
os.exit();
end;
end;
end;
end;
function verify()
if current_informations then
local origin_package = "com.ea.game.simcitymobile_row";
local cloning_package_pattern = "^com.ea.game.simcitymobile_[%w_][%w_][%w_]$";
if current_informations.cmdLine == origin_package then
USE_ORIGIN_PACKAGE = true;
elseif current_informations.cmdLine:match(cloning_package_pattern) then
USE_CLONING_PACKAGE = true;
else
USE_UNAUTHORIZED_PACKAGE = true;
return nil;
end;
if current_informations.versionCode == informations.version_code then
USE_ORIGIN_VERSION = true;
elseif current_informations.versionCode > informations.version_code then
USE_ORIGIN_VERSION = true;
USE_HIGHER_VERSION = true;
else
USE_UNAUTHORIZED_VERSION = true;
end;
else
USE_NO_PROCCESS = true;
end;
end;
function main()
initialization();
verify();
if USE_ORIGIN_PACKAGE or USE_CLONING_PACKAGE then
if USE_ORIGIN_VERSION then
if USE_HIGHER_VERSION then
gg.alert(messages.use_higher_version);
end;
if gg.isVisible(true) then
gg.setVisible(false)
end;
execute();
else
gg.alert(messages.use_unauthorized_version, messages.positive[1]);
os.exit(1);
end;
elseif USE_UNAUTHORIZED_PACKAGE then
gg.alert(messages.use_unauthorized_package, messages.positive[1]);
os.exit(1);
else
gg.alert(messages.use_no_process, messages.positive[1]);
os.exit(1);
end;
end;
main();
To embed this program on your website, copy the following code and paste it into your website's HTML: