fix: delegate memory-heavy string operations to Controller_MessageHandler
CRITICAL MEMORY FIX: Reduce Main Controller memory usage by delegating string operations CONTROLLER_MESSAGEHANDLER ENHANCEMENTS: - Added MSG_OWNER_MESSAGE, MSG_PUBLIC_MESSAGE, MSG_REGION_MESSAGE handlers - New handleOwnerMessage(), handlePublicMessage(), handleRegionMessage() functions - Memory-efficient message formatting with type-based templates - Moved all heavy string concatenation operations out of Main Controller MAIN CONTROLLER CHANGES: - Added ownerMsg(), publicMsg(), regionMsg() helper functions - Replaced memory-heavy llOwnerSay() calls with delegated message functions - Reduced string concatenation operations in critical paths - Kept simple direct calls for essential messages only This architectural change should significantly reduce Main Controller memory pressure and resolve the persistent Stack-Heap Collision errors.
This commit is contained in:
parent
b613452db1
commit
00ad7453bd
2 changed files with 132 additions and 5 deletions
|
|
@ -13,6 +13,10 @@ integer MSG_REQUEST_LIFE_DATA = 8003;
|
|||
integer MSG_PICK_ACTION = 8004;
|
||||
integer MSG_DICE_TYPE_REQUEST = 8005;
|
||||
integer MSG_LEAVE_GAME_REQUEST = 8006;
|
||||
integer MSG_OWNER_MESSAGE = 9030; // Send formatted owner message
|
||||
integer MSG_PUBLIC_MESSAGE = 9031; // Send formatted public message
|
||||
integer MSG_REGION_MESSAGE = 9032; // Send formatted region message
|
||||
integer MSG_DIALOG_REQUEST = 9033; // Send formatted dialog
|
||||
|
||||
// Game state data synchronized from Main Controller
|
||||
list players = [];
|
||||
|
|
@ -277,6 +281,89 @@ syncGameState(string stateData) {
|
|||
}
|
||||
}
|
||||
|
||||
// Memory-efficient message handling functions
|
||||
|
||||
// Handle owner messages
|
||||
handleOwnerMessage(string messageData) {
|
||||
// Format: "simple_message" or "type|param1|param2"
|
||||
list parts = llParseString2List(messageData, ["|"], []);
|
||||
if (llGetListLength(parts) == 1) {
|
||||
// Simple message
|
||||
llOwnerSay(messageData);
|
||||
} else {
|
||||
// Formatted message
|
||||
string msgType = llList2String(parts, 0);
|
||||
if (msgType == "JOIN") {
|
||||
string playerName = llList2String(parts, 1);
|
||||
llOwnerSay("👋 " + playerName + " joined the game!");
|
||||
} else if (msgType == "LEAVE") {
|
||||
string playerName = llList2String(parts, 1);
|
||||
llOwnerSay("👋 " + playerName + " left the game.");
|
||||
} else if (msgType == "ERROR") {
|
||||
string error = llList2String(parts, 1);
|
||||
llOwnerSay("⚠️ " + error);
|
||||
} else if (msgType == "SUCCESS") {
|
||||
string msg = llList2String(parts, 1);
|
||||
llOwnerSay("✅ " + msg);
|
||||
} else if (msgType == "DEBUG") {
|
||||
string component = llList2String(parts, 1);
|
||||
string msg = llList2String(parts, 2);
|
||||
llOwnerSay("🔧 [" + component + "] " + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle public messages
|
||||
handlePublicMessage(string messageData) {
|
||||
list parts = llParseString2List(messageData, ["|"], []);
|
||||
if (llGetListLength(parts) == 1) {
|
||||
llSay(0, messageData);
|
||||
} else {
|
||||
string msgType = llList2String(parts, 0);
|
||||
if (msgType == "GAME") {
|
||||
string state = llList2String(parts, 1);
|
||||
llSay(0, "🎮 " + state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle region messages to specific players
|
||||
handleRegionMessage(string messageData) {
|
||||
// Format: "player_key|message" or "player_key|type|param1|param2"
|
||||
list parts = llParseString2List(messageData, ["|"], []);
|
||||
if (llGetListLength(parts) >= 2) {
|
||||
key playerKey = llList2Key(parts, 0);
|
||||
string message = llList2String(parts, 1);
|
||||
|
||||
if (llGetListLength(parts) == 2) {
|
||||
// Simple message
|
||||
llRegionSayTo(playerKey, 0, message);
|
||||
} else {
|
||||
// Formatted message
|
||||
string msgType = llList2String(parts, 1);
|
||||
if (msgType == "WELCOME") {
|
||||
string msg = llList2String(parts, 2);
|
||||
llRegionSayTo(playerKey, 0, "🔄 " + msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle dialog requests
|
||||
handleDialogRequest(string dialogData) {
|
||||
// Format: "player_key|dialog_text|option1,option2,option3|channel"
|
||||
list parts = llParseString2List(dialogData, ["|"], []);
|
||||
if (llGetListLength(parts) >= 4) {
|
||||
key playerKey = llList2Key(parts, 0);
|
||||
string dialogText = llList2String(parts, 1);
|
||||
string optionsStr = llList2String(parts, 2);
|
||||
integer channel = llList2Integer(parts, 3);
|
||||
|
||||
list options = llParseString2List(optionsStr, [","], []);
|
||||
llDialog(playerKey, dialogText, options, channel);
|
||||
}
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
llOwnerSay("📨 [Message Handler] Helper script ready!");
|
||||
|
|
@ -358,6 +445,27 @@ default {
|
|||
return;
|
||||
}
|
||||
|
||||
// Handle memory-heavy message operations
|
||||
if (num == MSG_OWNER_MESSAGE) {
|
||||
handleOwnerMessage(str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == MSG_PUBLIC_MESSAGE) {
|
||||
handlePublicMessage(str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == MSG_REGION_MESSAGE) {
|
||||
handleRegionMessage(str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num == MSG_DIALOG_REQUEST) {
|
||||
handleDialogRequest(str);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle full reset
|
||||
if (num == -99999 && str == "FULL_RESET") {
|
||||
players = [];
|
||||
|
|
|
|||
|
|
@ -88,12 +88,33 @@ integer MSG_VERBOSE_TOGGLE = 9010;
|
|||
// Script ID for Main Controller (used by Verbose_Logger for prefixes)
|
||||
integer SCRIPT_ID_MAIN = 0;
|
||||
|
||||
// Message handling constants (delegate to Controller_MessageHandler)
|
||||
integer MSG_OWNER_MESSAGE = 9030;
|
||||
integer MSG_PUBLIC_MESSAGE = 9031;
|
||||
integer MSG_REGION_MESSAGE = 9032;
|
||||
integer MSG_DIALOG_REQUEST = 9033;
|
||||
|
||||
// Memory-safe debug function - forwards to dedicated logger
|
||||
debugMsg(string msg) {
|
||||
// Forward to dedicated verbose logger to save memory in Main Controller
|
||||
llMessageLinked(LINK_SET, MSG_VERBOSE_LOG, (string)SCRIPT_ID_MAIN + "|" + msg, NULL_KEY);
|
||||
}
|
||||
|
||||
// Memory-safe owner message function
|
||||
ownerMsg(string msg) {
|
||||
llMessageLinked(LINK_SET, MSG_OWNER_MESSAGE, msg, NULL_KEY);
|
||||
}
|
||||
|
||||
// Memory-safe public message function
|
||||
publicMsg(string msg) {
|
||||
llMessageLinked(LINK_SET, MSG_PUBLIC_MESSAGE, msg, NULL_KEY);
|
||||
}
|
||||
|
||||
// Memory-safe region message function
|
||||
regionMsg(key player, string msg) {
|
||||
llMessageLinked(LINK_SET, MSG_REGION_MESSAGE, (string)player + "|" + msg, NULL_KEY);
|
||||
}
|
||||
|
||||
// Status message timing
|
||||
float STATUS_DISPLAY_TIME = 8.0; // How long to show status messages on scoreboard
|
||||
integer statusTimer = 0; // Track when status messages were sent
|
||||
|
|
@ -475,8 +496,7 @@ default {
|
|||
shouldBePicking = TRUE;
|
||||
// Fix corrupted currentPicker state
|
||||
if (currentPicker != toucher) {
|
||||
llOwnerSay("🔄 [Disconnect Recovery] Fixing currentPicker for returning player: " + playerName);
|
||||
llOwnerSay("🔄 [Disconnect Recovery] Old currentPicker: " + (string)currentPicker + " -> New: " + (string)toucher);
|
||||
ownerMsg("DEBUG|Recovery|Fixing currentPicker for " + playerName);
|
||||
currentPicker = toucher;
|
||||
}
|
||||
}
|
||||
|
|
@ -488,9 +508,8 @@ default {
|
|||
// let any registered player attempt to resume (with owner confirmation)
|
||||
if (!shouldBePicking && currentPicker == NULL_KEY && currentPickerIdx < llGetListLength(pickQueue)) {
|
||||
if (toucher == llGetOwner()) {
|
||||
llOwnerSay("⚠️ [Recovery] Game appears stuck - no current picker set!");
|
||||
llOwnerSay("⚠️ [Recovery] Expected picker: " + llList2String(pickQueue, currentPickerIdx));
|
||||
llOwnerSay("⚠️ [Recovery] You (owner) touched - fixing by assigning you as current picker");
|
||||
ownerMsg("ERROR|Game stuck - no current picker set");
|
||||
ownerMsg("DEBUG|Recovery|Owner touched - fixing picker");
|
||||
currentPicker = toucher;
|
||||
shouldBePicking = TRUE;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue