You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-24 15:26:15 +00:00
Node: make _generate_serial_child_name manipulate numbers as String
The conversion from an String to int can overflow int and int64 so it is safer to manipulate strings when we try to find the next available name for a Node.
This commit is contained in:
@@ -1008,6 +1008,32 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return s + 1 as if it were an integer
|
||||||
|
String increase_numeric_string(const String &s) {
|
||||||
|
|
||||||
|
String res = s;
|
||||||
|
bool carry = res.length() > 0;
|
||||||
|
|
||||||
|
for (int i = res.length() - 1; i >= 0; i--) {
|
||||||
|
if (!carry) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CharType n = s[i];
|
||||||
|
if (n == '9') { // keep carry as true: 9 + 1
|
||||||
|
res[i] = '0';
|
||||||
|
} else {
|
||||||
|
res[i] = s[i] + 1;
|
||||||
|
carry = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (carry) {
|
||||||
|
res = "1" + res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
String Node::_generate_serial_child_name(Node *p_child) {
|
String Node::_generate_serial_child_name(Node *p_child) {
|
||||||
|
|
||||||
String name = p_child->data.name;
|
String name = p_child->data.name;
|
||||||
@@ -1040,42 +1066,38 @@ String Node::_generate_serial_child_name(Node *p_child) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String nnsep = _get_name_num_separator();
|
String nnsep = _get_name_num_separator();
|
||||||
int num = 0;
|
int name_last_index = name.length() - nnsep.length() - nums.length();
|
||||||
bool explicit_zero = false;
|
|
||||||
if (nums.length() > 0 && name.substr(name.length() - nnsep.length() - nums.length(), nnsep.length()) == nnsep) {
|
// Assign the base name + separator to name if we have numbers preceded by a separator
|
||||||
// Base name + Separator + Number
|
if (nums.length() > 0 && name.substr(name_last_index, nnsep.length()) == nnsep) {
|
||||||
num = nums.to_int();
|
name = name.substr(0, name_last_index + nnsep.length()).strip_edges();
|
||||||
name = name.substr(0, name.length() - nnsep.length() - nums.length()); // Keep base name
|
} else {
|
||||||
if (num == 0) {
|
nums = "";
|
||||||
explicit_zero = true;
|
}
|
||||||
|
|
||||||
|
Vector<String> children_names;
|
||||||
|
|
||||||
|
for (int i = 0; i < data.children.size(); i++) {
|
||||||
|
String child_name = data.children[i]->data.name;
|
||||||
|
if (data.children[i] == p_child)
|
||||||
|
continue;
|
||||||
|
if (child_name.begins_with(name)) {
|
||||||
|
children_names.push_back(child_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_places = nums.length();
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
String attempt = (name + (num > 0 || explicit_zero ? nnsep + itos(num).pad_zeros(num_places) : "")).strip_edges();
|
String attempt = name + nums;
|
||||||
bool found = false;
|
|
||||||
for (int i = 0; i < data.children.size(); i++) {
|
if (children_names.find(attempt) == -1) {
|
||||||
if (data.children[i] == p_child)
|
|
||||||
continue;
|
|
||||||
if (data.children[i]->data.name == attempt) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
return attempt;
|
return attempt;
|
||||||
} else {
|
} else {
|
||||||
if (num == 0) {
|
if (nums.length() == 0) {
|
||||||
if (explicit_zero) {
|
|
||||||
// Name ended in separator + 0; user expects to get to separator + 1
|
|
||||||
num = 1;
|
|
||||||
} else {
|
|
||||||
// Name was undecorated so skip to 2 for a more natural result
|
// Name was undecorated so skip to 2 for a more natural result
|
||||||
num = 2;
|
nums = "2";
|
||||||
}
|
name += nnsep; // Add separator because nums.length() > 0 was false
|
||||||
} else {
|
} else {
|
||||||
num++;
|
nums = increase_numeric_string(nums);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user