added memmory toggle in peril_constants.lsl, added new memory macro script in constants, added macro to all files, optimised scoreboard manager, bug fixes in mulitible scripts
This commit is contained in:
parent
915c079a7a
commit
a225244241
18 changed files with 386 additions and 548 deletions
|
|
@ -57,18 +57,6 @@ list processedBotCommands = [];
|
||||||
// Track sent BOT_PICKED messages to prevent duplicate sending
|
// Track sent BOT_PICKED messages to prevent duplicate sending
|
||||||
list sentBotMessages = [];
|
list sentBotMessages = [];
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to check and report memory usage
|
// Helper function to check and report memory usage
|
||||||
checkMemoryUsage(string context) {
|
checkMemoryUsage(string context) {
|
||||||
|
|
@ -201,7 +189,7 @@ doBotRoll(string botName, integer diceMax) {
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
reportMemoryUsage("🤖 Bot Manager");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
initializeChannels();
|
initializeChannels();
|
||||||
LISTEN_CHANNEL = BOT_COMMAND_CHANNEL;
|
LISTEN_CHANNEL = BOT_COMMAND_CHANNEL;
|
||||||
|
|
@ -222,7 +210,7 @@ default {
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
reportMemoryUsage("🤖 Bot Manager");
|
REPORT_MEMORY();
|
||||||
dbg("🤖 [Bot Manager] 🔄 Bot Manager rezzed - reinitializing...");
|
dbg("🤖 [Bot Manager] 🔄 Bot Manager rezzed - reinitializing...");
|
||||||
|
|
||||||
// Re-initialize dynamic channels
|
// Re-initialize dynamic channels
|
||||||
|
|
|
||||||
|
|
@ -113,12 +113,17 @@ processMainControllerStats(string statsData) {
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
|
REPORT_MEMORY();
|
||||||
dbg("📊 [Memory Monitor] Memory Monitor ready!");
|
dbg("📊 [Memory Monitor] Memory Monitor ready!");
|
||||||
|
|
||||||
// Start periodic memory monitoring
|
// Start periodic memory monitoring
|
||||||
llSetTimerEvent(MEMORY_CHECK_INTERVAL);
|
llSetTimerEvent(MEMORY_CHECK_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
on_rez(integer start_param) {
|
||||||
|
REPORT_MEMORY();
|
||||||
|
}
|
||||||
|
|
||||||
timer() {
|
timer() {
|
||||||
// Periodic memory check
|
// Periodic memory check
|
||||||
checkMemoryUsage("periodic_check");
|
checkMemoryUsage("periodic_check");
|
||||||
|
|
|
||||||
|
|
@ -40,18 +40,6 @@ integer calculateChannel(integer offset) {
|
||||||
return CHANNEL_BASE - (offset * 1000) - combinedHash;
|
return CHANNEL_BASE - (offset * 1000) - combinedHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeChannels() {
|
initializeChannels() {
|
||||||
SCOREBOARD_CHANNEL_1 = calculateChannel(6); // ~-77600 range
|
SCOREBOARD_CHANNEL_1 = calculateChannel(6); // ~-77600 range
|
||||||
|
|
@ -326,13 +314,13 @@ handleDialogRequest(string dialogData) {
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
reportMemoryUsage("📨 Message Handler");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
initializeChannels();
|
initializeChannels();
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
reportMemoryUsage("📨 Message Handler");
|
REPORT_MEMORY();
|
||||||
initializeChannels();
|
initializeChannels();
|
||||||
// Reset local state if needed (synced from Main)
|
// Reset local state if needed (synced from Main)
|
||||||
players = [];
|
players = [];
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ default {
|
||||||
|
|
||||||
state_entry() {
|
state_entry() {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
|
REPORT_MEMORY();
|
||||||
dbg("📋 [Leaderboard] Leaderboard Communication Script ready! (FURWARE Version)");
|
dbg("📋 [Leaderboard] Leaderboard Communication Script ready! (FURWARE Version)");
|
||||||
dbg("📋 [Leaderboard] Managing 'Leaderboard' FURWARE box");
|
dbg("📋 [Leaderboard] Managing 'Leaderboard' FURWARE box");
|
||||||
dbg("📋 [Leaderboard] ✅ Discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
dbg("📋 [Leaderboard] ✅ Discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ default {
|
||||||
}
|
}
|
||||||
state_entry() {
|
state_entry() {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
|
REPORT_MEMORY();
|
||||||
dbg("🎲 [Dice Bridge] Dice Display Bridge ready! (FURWARE Version)");
|
dbg("🎲 [Dice Bridge] Dice Display Bridge ready! (FURWARE Version)");
|
||||||
dbg("🎲 [Dice Bridge] ✅ Discovery complete! Controller: " + (string)LINK_CONTROLLER);
|
dbg("🎲 [Dice Bridge] ✅ Discovery complete! Controller: " + (string)LINK_CONTROLLER);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,18 +41,6 @@ initializeChannels() {
|
||||||
// Debug control - set to TRUE for verbose pick debugging, FALSE for normal operation
|
// Debug control - set to TRUE for verbose pick debugging, FALSE for normal operation
|
||||||
integer DEBUG_PICKS = FALSE;
|
integer DEBUG_PICKS = FALSE;
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ALL REGISTERED PLAYERS (for channel mapping - order never changes)
|
// ALL REGISTERED PLAYERS (for channel mapping - order never changes)
|
||||||
list allPlayerNames = []; // Names in registration order
|
list allPlayerNames = []; // Names in registration order
|
||||||
|
|
@ -90,7 +78,7 @@ list getPicksFor(string nameInput) {
|
||||||
// Main event handler
|
// Main event handler
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
reportMemoryUsage("💬 Floater Manager");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
initializeChannels();
|
initializeChannels();
|
||||||
|
|
||||||
|
|
@ -106,7 +94,7 @@ default {
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
reportMemoryUsage("💬 Floater Manager");
|
REPORT_MEMORY();
|
||||||
dbg("💬 [Floater Manager] 🔄 Floater Manager rezzed - reinitializing...");
|
dbg("💬 [Floater Manager] 🔄 Floater Manager rezzed - reinitializing...");
|
||||||
|
|
||||||
initializeChannels();
|
initializeChannels();
|
||||||
|
|
@ -133,47 +121,56 @@ default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num == MSG_REGISTER_PLAYER) {
|
// MSG_REGISTER_PLAYER (106) is now handled by Player_RegistrationManager.lsl
|
||||||
if (llGetListLength(allPlayerNames) >= MAX_PLAYERS) {
|
// which then sends MSG_REZ_FLOAT (105) here. Legacy handler removed to prevent double-rezzing.
|
||||||
dbg("💬 [Floater Manager] ⚠️ Game is full (max " + (string)MAX_PLAYERS + ").");
|
|
||||||
return;
|
else if (num == MSG_REZ_FLOAT) { // 105
|
||||||
}
|
|
||||||
list info = llParseString2List(str, ["|"], []);
|
|
||||||
string name = llList2String(info, 0);
|
|
||||||
key avKey = llList2Key(info, 1);
|
|
||||||
|
|
||||||
if (llListFindList(allPlayerNames, [name]) != -1) return;
|
|
||||||
|
|
||||||
allPlayerNames += [name]; // Permanent map
|
|
||||||
llSay(0, "💀 " + name + " has entered the deadly game! 💀");
|
|
||||||
llMessageLinked(LINK_SET, MSG_REZ_FLOAT, name, avKey);
|
|
||||||
}
|
|
||||||
else if (num == MSG_REZ_FLOAT) {
|
|
||||||
string name = str;
|
string name = str;
|
||||||
integer channelIdx = llListFindList(allPlayerNames, [name]);
|
key avKey = id;
|
||||||
if (channelIdx == -1) return;
|
|
||||||
|
|
||||||
key avKey = id; // Passed from MSG_REGISTER_PLAYER or MSG_REZ_FLOAT
|
// Handle name|key format if sent
|
||||||
|
integer pipeIdx = llSubStringIndex(str, "|");
|
||||||
list details = llGetObjectDetails(avKey, [OBJECT_POS]);
|
if (pipeIdx != -1) {
|
||||||
vector basePos = llGetPos();
|
name = llGetSubString(str, 0, pipeIdx - 1);
|
||||||
if (llGetListLength(details) > 0) basePos = llList2Vector(details, 0);
|
if (avKey == NULL_KEY) avKey = (key)llGetSubString(str, pipeIdx + 1, -1);
|
||||||
|
|
||||||
vector pos;
|
|
||||||
if (llGetListLength(details) > 0) {
|
|
||||||
pos = basePos + <1, 0, 1>; // Avatar relative
|
|
||||||
} else {
|
|
||||||
// Test players: grid layout
|
|
||||||
integer row = channelIdx / 5;
|
|
||||||
integer col = channelIdx % 5;
|
|
||||||
pos = basePos + <-3.0 - (float)col * 1.5, 2.0 + (float)row * 2.0, 1>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
integer ch = FLOATER_BASE_CHANNEL + channelIdx;
|
// Ensure player is in our permanent map
|
||||||
llRezObject("StatFloat", pos, ZERO_VECTOR, ZERO_ROTATION, ch);
|
integer channelIdx = llListFindList(allPlayerNames, [name]);
|
||||||
llSleep(0.2);
|
if (channelIdx == -1) {
|
||||||
llRegionSay(ch, "SET_NAME:" + name);
|
if (llGetListLength(allPlayerNames) >= MAX_PLAYERS) return;
|
||||||
llMessageLinked(LINK_SET, MSG_UPDATE_FLOAT, name, avKey);
|
|
||||||
|
allPlayerNames += [name];
|
||||||
|
channelIdx = llGetListLength(allPlayerNames) - 1;
|
||||||
|
|
||||||
|
// --- AUTHENTIC REZ BLOCK ---
|
||||||
|
// Only rez if we had to add them to the list (first time seeing them)
|
||||||
|
list details = llGetObjectDetails(avKey, [OBJECT_POS]);
|
||||||
|
vector basePos = llGetPos();
|
||||||
|
if (llGetListLength(details) > 0) basePos = llList2Vector(details, 0);
|
||||||
|
|
||||||
|
vector pos;
|
||||||
|
if (llGetListLength(details) > 0) {
|
||||||
|
pos = basePos + <1, 0, 1>; // Avatar relative
|
||||||
|
} else {
|
||||||
|
// Test players: grid layout
|
||||||
|
integer row = channelIdx / 5;
|
||||||
|
integer col = channelIdx % 5;
|
||||||
|
pos = basePos + <-3.0 - (float)col * 1.5, 2.0 + (float)row * 2.0, 1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
integer ch = FLOATER_BASE_CHANNEL + channelIdx;
|
||||||
|
llRezObject("StatFloat", pos, ZERO_VECTOR, ZERO_ROTATION, ch);
|
||||||
|
llSleep(0.2);
|
||||||
|
llRegionSay(ch, "SET_NAME:" + name);
|
||||||
|
|
||||||
|
// Initial update to populate text/life display
|
||||||
|
llMessageLinked(LINK_SET, MSG_UPDATE_FLOAT, name, avKey);
|
||||||
|
} else {
|
||||||
|
// Already in list - just trigger an update in case it was a re-registration
|
||||||
|
dbg("🛡️ [Rez Guard] " + name + " is already rezzed. Skipping redundant creation.");
|
||||||
|
llMessageLinked(LINK_SET, MSG_UPDATE_FLOAT, name, avKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (num == MSG_UPDATE_FLOAT) {
|
else if (num == MSG_UPDATE_FLOAT) {
|
||||||
string name = str;
|
string name = str;
|
||||||
|
|
@ -240,6 +237,12 @@ default {
|
||||||
integer foundIdx = ch - FLOATER_BASE_CHANNEL;
|
integer foundIdx = ch - FLOATER_BASE_CHANNEL;
|
||||||
if (foundIdx >= 0 && foundIdx < llGetListLength(allPlayerNames)) {
|
if (foundIdx >= 0 && foundIdx < llGetListLength(allPlayerNames)) {
|
||||||
string removedPlayer = llList2String(allPlayerNames, foundIdx);
|
string removedPlayer = llList2String(allPlayerNames, foundIdx);
|
||||||
|
|
||||||
|
// --- CRITICAL FIX: Clear from Rez Guard registry ---
|
||||||
|
// We don't remove from allPlayerNames (to maintain channel indices)
|
||||||
|
// BUT we replace it with an empty string so the slot is 'available' again
|
||||||
|
allPlayerNames = llListReplaceList(allPlayerNames, [""], foundIdx, foundIdx);
|
||||||
|
|
||||||
integer currentIdx = llListFindList(names, [removedPlayer]);
|
integer currentIdx = llListFindList(names, [removedPlayer]);
|
||||||
if (currentIdx != -1) {
|
if (currentIdx != -1) {
|
||||||
if (currentIdx < llGetListLength(players)) players = llDeleteSubList(players, currentIdx, currentIdx);
|
if (currentIdx < llGetListLength(players)) players = llDeleteSubList(players, currentIdx, currentIdx);
|
||||||
|
|
@ -258,6 +261,19 @@ default {
|
||||||
if (pickIdx != -1) picksData = llDeleteSubList(picksData, pickIdx, pickIdx);
|
if (pickIdx != -1) picksData = llDeleteSubList(picksData, pickIdx, pickIdx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (num == MSG_LEAVE_GAME) { // 8007
|
||||||
|
// Format: LEAVE_GAME|NAME|KEY
|
||||||
|
list parts = llParseString2List(str, ["|"], []);
|
||||||
|
string leaveName = llList2String(parts, 1);
|
||||||
|
integer chanIdx = llListFindList(allPlayerNames, [leaveName]);
|
||||||
|
|
||||||
|
if (chanIdx != -1) {
|
||||||
|
// Remove their floater and clear the slot for re-entry
|
||||||
|
dbg("🚮 [Floater Manager] Player " + leaveName + " left - cleaning up floater.");
|
||||||
|
llRegionSay(FLOATER_BASE_CHANNEL + chanIdx, "CLEANUP");
|
||||||
|
allPlayerNames = llListReplaceList(allPlayerNames, [""], chanIdx, chanIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (num == MSG_SYNC_GAME_STATE) {
|
else if (num == MSG_SYNC_GAME_STATE) {
|
||||||
list parts = llParseString2List(str, ["~"], []);
|
list parts = llParseString2List(str, ["~"], []);
|
||||||
if (llGetListLength(parts) < 4) return;
|
if (llGetListLength(parts) < 4) return;
|
||||||
|
|
@ -278,7 +294,16 @@ default {
|
||||||
}
|
}
|
||||||
names = llCSV2List(llList2String(parts, 3));
|
names = llCSV2List(llList2String(parts, 3));
|
||||||
|
|
||||||
if (llGetListLength(allPlayerNames) == 0 && llGetListLength(names) > 0) allPlayerNames = names;
|
// Robustly update permanent map from sync names
|
||||||
|
integer nIdx;
|
||||||
|
for (nIdx = 0; nIdx < llGetListLength(names); nIdx++) {
|
||||||
|
string nName = llList2String(names, nIdx);
|
||||||
|
if (llListFindList(allPlayerNames, [nName]) == -1) {
|
||||||
|
if (llGetListLength(allPlayerNames) < MAX_PLAYERS) {
|
||||||
|
allPlayerNames += [nName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (llGetListLength(parts) >= 5) players = llCSV2List(llList2String(parts, 4));
|
if (llGetListLength(parts) >= 5) players = llCSV2List(llList2String(parts, 4));
|
||||||
|
|
||||||
integer idx;
|
integer idx;
|
||||||
|
|
@ -291,11 +316,20 @@ default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (num == MSG_CLEANUP_ALL_FLOATERS) {
|
else if (num == MSG_CLEANUP_ALL_FLOATERS) {
|
||||||
|
dbg("🧹 [Floater Manager] Universal Cleanup Triggered - Clearing all " + (string)MAX_PLAYERS + " possible channels.");
|
||||||
integer i;
|
integer i;
|
||||||
for (i = 0; i < llGetListLength(allPlayerNames); i++) {
|
for (i = 0; i < MAX_PLAYERS; i++) {
|
||||||
|
// Ensure we hit EVERY possible channel, even if they aren't in our current memory
|
||||||
llRegionSay(FLOATER_BASE_CHANNEL + i, "CLEANUP");
|
llRegionSay(FLOATER_BASE_CHANNEL + i, "CLEANUP");
|
||||||
}
|
}
|
||||||
players = []; names = []; lives = []; picksData = []; perilPlayer = "";
|
// Clear ALL registries to allow fresh re-registration via Rez Guard
|
||||||
|
allPlayerNames = [];
|
||||||
|
players = [];
|
||||||
|
names = [];
|
||||||
|
lives = [];
|
||||||
|
picksData = [];
|
||||||
|
perilPlayer = "";
|
||||||
|
dbg("✅ [Floater Manager] All player registries wiped.");
|
||||||
}
|
}
|
||||||
else if (num == MSG_DEBUG_PICKS_ON) DEBUG_PICKS = TRUE;
|
else if (num == MSG_DEBUG_PICKS_ON) DEBUG_PICKS = TRUE;
|
||||||
else if (num == MSG_DEBUG_PICKS_OFF) DEBUG_PICKS = FALSE;
|
else if (num == MSG_DEBUG_PICKS_OFF) DEBUG_PICKS = FALSE;
|
||||||
|
|
|
||||||
|
|
@ -610,7 +610,12 @@ integer setDirty(integer action, integer first, integer last, integer isConf,
|
||||||
////////// STATES //////////////////////////////////////////
|
////////// STATES //////////////////////////////////////////
|
||||||
|
|
||||||
default {
|
default {
|
||||||
|
on_rez(integer start_param) {
|
||||||
|
REPORT_MEMORY();
|
||||||
|
}
|
||||||
|
|
||||||
state_entry() {
|
state_entry() {
|
||||||
|
REPORT_MEMORY();
|
||||||
llOwnerSay("FURWARE text is starting...");
|
llOwnerSay("FURWARE text is starting...");
|
||||||
|
|
||||||
CHARS = llBase64ToString(
|
CHARS = llBase64ToString(
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,6 @@
|
||||||
// This version chooses a dice size based on the number of players,
|
// This version chooses a dice size based on the number of players,
|
||||||
// ensuring at least three numbers are available per player.
|
// ensuring at least three numbers are available per player.
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
list lives;
|
list lives;
|
||||||
list picksData;
|
list picksData;
|
||||||
|
|
@ -120,7 +108,7 @@ integer showPickManager(string player, key id) {
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
reportMemoryUsage("🧮 Game Calculator");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
// Initialize/reset all state variables
|
// Initialize/reset all state variables
|
||||||
lives = [];
|
lives = [];
|
||||||
|
|
@ -132,7 +120,7 @@ default {
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
reportMemoryUsage("🧮 Game Calculator");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
// Reset all state variables on rez
|
// Reset all state variables on rez
|
||||||
lives = [];
|
lives = [];
|
||||||
|
|
|
||||||
|
|
@ -395,7 +395,7 @@ integer syncStateToMain() {
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
reportMemoryUsage("Game Manager");
|
REPORT_MEMORY();
|
||||||
dbg("🎯 Game Manager ready - discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
dbg("🎯 Game Manager ready - discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
||||||
|
|
||||||
// Initialize/reset all game state variables
|
// Initialize/reset all game state variables
|
||||||
|
|
@ -422,7 +422,7 @@ default {
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
reportMemoryUsage("Game Manager");
|
REPORT_MEMORY();
|
||||||
dbg("🔄 Game Manager reset via rez...");
|
dbg("🔄 Game Manager reset via rez...");
|
||||||
|
|
||||||
// Reset all game state variables on rez
|
// Reset all game state variables on rez
|
||||||
|
|
|
||||||
|
|
@ -8,20 +8,22 @@
|
||||||
integer BACKGROUND_PRIM = -1;
|
integer BACKGROUND_PRIM = -1;
|
||||||
integer ACTIONS_PRIM = -1;
|
integer ACTIONS_PRIM = -1;
|
||||||
|
|
||||||
// Link mappings for player grid (Rows 0-4, Columns 0-1)
|
// Grid link mappings for player grid (Stride 3: Profile, Hearts, Overlay)
|
||||||
list profileLinks = [0,0,0,0,0,0,0,0,0,0];
|
list gridLinks = [
|
||||||
list heartsLinks = [0,0,0,0,0,0,0,0,0,0];
|
0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0,
|
||||||
list overlayLinks = [0,0,0,0,0,0,0,0,0,0];
|
0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0
|
||||||
|
];
|
||||||
|
|
||||||
// Discover all relevant prims by name at startup
|
// Discover all relevant prims by name at startup
|
||||||
discoverLinks() {
|
discoverLinks() {
|
||||||
integer i;
|
integer i;
|
||||||
integer total = llGetNumberOfPrims();
|
integer total = llGetNumberOfPrims();
|
||||||
|
|
||||||
// Reset lists
|
// Reset list (30 elements for 10 slots * 3 prims)
|
||||||
profileLinks = [0,0,0,0,0,0,0,0,0,0];
|
gridLinks = [
|
||||||
heartsLinks = [0,0,0,0,0,0,0,0,0,0];
|
0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0,
|
||||||
overlayLinks = [0,0,0,0,0,0,0,0,0,0];
|
0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0
|
||||||
|
];
|
||||||
|
|
||||||
for (i = 1; i <= total; i++) {
|
for (i = 1; i <= total; i++) {
|
||||||
string name = llGetLinkName(i);
|
string name = llGetLinkName(i);
|
||||||
|
|
@ -39,16 +41,17 @@ discoverLinks() {
|
||||||
integer index = (row * 2) + col;
|
integer index = (row * 2) + col;
|
||||||
|
|
||||||
if (index >= 0 && index < 10) {
|
if (index >= 0 && index < 10) {
|
||||||
if (type == "profile") profileLinks = llListReplaceList(profileLinks, [i], index, index);
|
integer gridBase = index * 3;
|
||||||
else if (type == "life") heartsLinks = llListReplaceList(heartsLinks, [i], index, index);
|
if (type == "profile") gridLinks = llListReplaceList(gridLinks, [i], gridBase, gridBase);
|
||||||
else if (type == "overlay") overlayLinks = llListReplaceList(overlayLinks, [i], index, index);
|
else if (type == "life") gridLinks = llListReplaceList(gridLinks, [i], gridBase + 1, gridBase + 1);
|
||||||
|
else if (type == "overlay") gridLinks = llListReplaceList(gridLinks, [i], gridBase + 2, gridBase + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] 🔍 Dynamic Discovery complete!");
|
dbg("Discovery done");
|
||||||
if (BACKGROUND_PRIM == -1) dbg("⚠️ WARNING: Background prim ('backboard:0:0') not found!");
|
if (BACKGROUND_PRIM == -1) dbg("No backboard");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Leaderboard Configuration ---
|
// --- Leaderboard Configuration ---
|
||||||
|
|
@ -80,18 +83,14 @@ discoverLinks() {
|
||||||
#define TEXTURE_ELIMINATED_X "90524092-03b0-1b3c-bcea-3ea5118c6dba" // Red X overlay for eliminated players
|
#define TEXTURE_ELIMINATED_X "90524092-03b0-1b3c-bcea-3ea5118c6dba" // Red X overlay for eliminated players
|
||||||
|
|
||||||
// Player data - used for BOTH current game display AND leaderboard
|
// Player data - used for BOTH current game display AND leaderboard
|
||||||
list playerNames = []; // Current game players for display
|
list activePlayers = []; // Current game state (Stride 3: Name, Lives, UUID)
|
||||||
list playerLives = []; // Current game player lives
|
|
||||||
list playerProfiles = []; // Maps to profile texture UUIDs
|
|
||||||
|
|
||||||
// Peril player tracking
|
// Peril player tracking
|
||||||
string currentPerilPlayer = ""; // Track current peril player for glow effects
|
string currentPerilPlayer = ""; // Track current peril player for glow effects
|
||||||
string currentWinner = ""; // Track current winner for green glow effects
|
string currentWinner = ""; // Track current winner for green glow effects
|
||||||
|
|
||||||
// Leaderboard data (persistent - stored in linkset data)
|
// Leaderboard data (persistent - stored in linkset data) - Stride of 3 [Name, Wins, Losses]
|
||||||
list leaderboardNames = []; // Loaded from linkset data at startup
|
list leaderboardData = [];
|
||||||
list leaderboardWins = []; // Loaded from linkset data at startup
|
|
||||||
list leaderboardLosses = []; // Loaded from linkset data at startup
|
|
||||||
|
|
||||||
// HTTP tracking
|
// HTTP tracking
|
||||||
list profileRequests = []; // Track which profile requests belong to which player
|
list profileRequests = []; // Track which profile requests belong to which player
|
||||||
|
|
@ -102,25 +101,13 @@ key kvpReadReq;
|
||||||
key kvpWriteReq;
|
key kvpWriteReq;
|
||||||
string pendingSerialize;
|
string pendingSerialize;
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
integer reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Profile picture extraction constants
|
// Profile picture extraction constants
|
||||||
string profile_key_prefix = "<meta name=\"imageid\" content=\"";
|
// Profile picture extraction constants
|
||||||
string profile_img_prefix = "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/";
|
#define PROFILE_KEY_PREFIX "<meta name=\"imageid\" content=\""
|
||||||
integer profile_key_prefix_length;
|
#define PROFILE_IMG_PREFIX "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/"
|
||||||
integer profile_img_prefix_length;
|
#define PROFILE_KEY_PREFIX_LENGTH 30
|
||||||
|
#define PROFILE_IMG_PREFIX_LENGTH 59
|
||||||
|
|
||||||
// Reset background prim to proper black background
|
// Reset background prim to proper black background
|
||||||
integer resetBackgroundPrim() {
|
integer resetBackgroundPrim() {
|
||||||
|
|
@ -131,7 +118,7 @@ integer resetBackgroundPrim() {
|
||||||
PRIM_TEXT, "", <0,0,0>, 0.0 // Remove any text
|
PRIM_TEXT, "", <0,0,0>, 0.0 // Remove any text
|
||||||
]);
|
]);
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] 🖤 Reset background prim " + (string)BACKGROUND_PRIM + " to black");
|
dbg("Backboard Reset");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +130,7 @@ integer resetManagerCube() {
|
||||||
PRIM_TEXT, "", <0,0,0>, 0.0 // Remove any text
|
PRIM_TEXT, "", <0,0,0>, 0.0 // Remove any text
|
||||||
]);
|
]);
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] 📦 Reset manager cube (link 12) to black");
|
dbg("Manager Reset");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,21 +171,26 @@ integer updateActionsPrim(string status) {
|
||||||
// Load leaderboard data from Experience KVP database
|
// Load leaderboard data from Experience KVP database
|
||||||
integer loadLeaderboardData() {
|
integer loadLeaderboardData() {
|
||||||
kvpReadReq = llReadKeyValue("Peril_LB_Top50");
|
kvpReadReq = llReadKeyValue("Peril_LB_Top50");
|
||||||
dbg("📈 [Scoreboard Manager] 🔍 Requesting global scoreboard from Experience database...");
|
dbg("LB Requesting");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save leaderboard data to Experience KVP database
|
// Save leaderboard data to Experience KVP database
|
||||||
integer saveLeaderboardData() {
|
integer saveLeaderboardData() {
|
||||||
string serialized = "";
|
string serialized = "";
|
||||||
integer saveCount = llGetListLength(leaderboardNames);
|
integer totalEntries = llGetListLength(leaderboardData) / 3;
|
||||||
if (saveCount > 50) saveCount = 50; // Cap at Top 50 to fit safely in KVP 4Kb limit
|
integer saveCount = totalEntries;
|
||||||
|
integer saveI = 0;
|
||||||
|
integer base = 0;
|
||||||
|
string save_entry = "";
|
||||||
|
|
||||||
|
if (saveCount > 50) saveCount = 50; // Cap at Top 50
|
||||||
|
|
||||||
integer saveI;
|
|
||||||
for (saveI = 0; saveI < saveCount; saveI++) {
|
for (saveI = 0; saveI < saveCount; saveI++) {
|
||||||
string save_entry = llList2String(leaderboardNames, saveI) + ":" +
|
base = saveI * 3;
|
||||||
(string)llList2Integer(leaderboardWins, saveI) + ":" +
|
save_entry = llList2String(leaderboardData, base) + ":" +
|
||||||
(string)llList2Integer(leaderboardLosses, saveI);
|
(string)llList2Integer(leaderboardData, base + 1) + ":" +
|
||||||
|
(string)llList2Integer(leaderboardData, base + 2);
|
||||||
if (serialized != "") serialized += "|";
|
if (serialized != "") serialized += "|";
|
||||||
serialized += save_entry;
|
serialized += save_entry;
|
||||||
}
|
}
|
||||||
|
|
@ -206,22 +198,20 @@ integer saveLeaderboardData() {
|
||||||
pendingSerialize = serialized;
|
pendingSerialize = serialized;
|
||||||
kvpWriteReq = llUpdateKeyValue("Peril_LB_Top50", serialized, FALSE, "");
|
kvpWriteReq = llUpdateKeyValue("Peril_LB_Top50", serialized, FALSE, "");
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] 💾 Synced " + (string)saveCount + " players to global scoreboard database.");
|
dbg("LB Saving");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle game won - update leaderboard
|
// Handle game won - update leaderboard
|
||||||
integer handleGameWon(string winnerName) {
|
integer handleGameWon(string winnerName) {
|
||||||
integer idx = llListFindList(leaderboardNames, [winnerName]);
|
integer idx = llListFindList(leaderboardData, [winnerName]);
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
// New player
|
// New player
|
||||||
leaderboardNames += [winnerName];
|
leaderboardData += [winnerName, 1, 0];
|
||||||
leaderboardWins += [1];
|
|
||||||
leaderboardLosses += [0];
|
|
||||||
} else {
|
} else {
|
||||||
// Existing player
|
// Existing player
|
||||||
integer currentWins = llList2Integer(leaderboardWins, idx);
|
integer currentWins = llList2Integer(leaderboardData, idx + 1);
|
||||||
leaderboardWins = llListReplaceList(leaderboardWins, [currentWins + 1], idx, idx);
|
leaderboardData = llListReplaceList(leaderboardData, [currentWins + 1], idx + 1, idx + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveLeaderboardData();
|
saveLeaderboardData();
|
||||||
|
|
@ -231,16 +221,14 @@ integer handleGameWon(string winnerName) {
|
||||||
|
|
||||||
// Handle game lost - update leaderboard
|
// Handle game lost - update leaderboard
|
||||||
integer handleGameLost(string loserName) {
|
integer handleGameLost(string loserName) {
|
||||||
integer lostIdx = llListFindList(leaderboardNames, [loserName]);
|
integer lostIdx = llListFindList(leaderboardData, [loserName]);
|
||||||
if (lostIdx == -1) {
|
if (lostIdx == -1) {
|
||||||
// New player
|
// New player
|
||||||
leaderboardNames += [loserName];
|
leaderboardData += [loserName, 0, 1];
|
||||||
leaderboardWins += [0];
|
|
||||||
leaderboardLosses += [1];
|
|
||||||
} else {
|
} else {
|
||||||
// Existing player
|
// Existing player
|
||||||
integer currentLosses = llList2Integer(leaderboardLosses, lostIdx);
|
integer currentLosses = llList2Integer(leaderboardData, lostIdx + 2);
|
||||||
leaderboardLosses = llListReplaceList(leaderboardLosses, [currentLosses + 1], lostIdx, lostIdx);
|
leaderboardData = llListReplaceList(leaderboardData, [currentLosses + 1], lostIdx + 2, lostIdx + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveLeaderboardData();
|
saveLeaderboardData();
|
||||||
|
|
@ -248,159 +236,112 @@ integer handleGameLost(string loserName) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get sorted leaderboard data
|
|
||||||
list getSortedLeaderboard() {
|
list getSortedLeaderboard() {
|
||||||
list sortedLbData = [];
|
list sortList = [];
|
||||||
integer sortI;
|
integer i = 0;
|
||||||
string sortName;
|
integer totalEntries = llGetListLength(leaderboardData) / 3;
|
||||||
integer sortWins;
|
integer base = 0;
|
||||||
integer sortLosses;
|
integer wins = 0;
|
||||||
string paddedWins;
|
integer losses = 0;
|
||||||
string paddedLosses;
|
integer sortKey = 0;
|
||||||
integer invertedLosses;
|
list sortedData = [];
|
||||||
string sortKey;
|
integer origIdx = 0;
|
||||||
string sorted_entry;
|
|
||||||
list parts;
|
|
||||||
list cleanedData = [];
|
|
||||||
string winsStr;
|
|
||||||
string lossesStr;
|
|
||||||
|
|
||||||
// Create combined data for sorting with padded wins and losses for proper multi-level sorting
|
for (i = 0; i < totalEntries; i++) {
|
||||||
for (sortI = 0; sortI < llGetListLength(leaderboardNames); sortI++) {
|
base = i * 3;
|
||||||
sortName = llList2String(leaderboardNames, sortI);
|
wins = llList2Integer(leaderboardData, base + 1);
|
||||||
sortWins = llList2Integer(leaderboardWins, sortI);
|
losses = llList2Integer(leaderboardData, base + 2);
|
||||||
sortLosses = llList2Integer(leaderboardLosses, sortI);
|
|
||||||
|
|
||||||
// Pad wins to 4 digits (higher wins = better rank)
|
if (wins > 65535) wins = 65535;
|
||||||
paddedWins = (string)(10000 + sortWins);
|
if (losses > 65535) losses = 65535;
|
||||||
paddedWins = llGetSubString(paddedWins, 1, -1); // Remove the "1" prefix
|
|
||||||
|
|
||||||
// Pad losses to 4 digits, but INVERTED for tiebreaker (lower losses = better rank)
|
sortKey = (wins << 16) | (65535 - losses);
|
||||||
// Use 9999 - losses so lower losses get higher sort value
|
sortList += [sortKey, i];
|
||||||
invertedLosses = 9999 - sortLosses;
|
|
||||||
paddedLosses = (string)(10000 + invertedLosses);
|
|
||||||
paddedLosses = llGetSubString(paddedLosses, 1, -1); // Remove the "1" prefix
|
|
||||||
|
|
||||||
// Format: "PaddedWins-PaddedInvertedLosses:Name:ActualWins:ActualLosses"
|
|
||||||
// This sorts first by wins (descending), then by losses (ascending) for tiebreaker
|
|
||||||
sortKey = paddedWins + "-" + paddedLosses;
|
|
||||||
sorted_entry = sortKey + ":" + sortName + ":" + (string)sortWins + ":" + (string)sortLosses;
|
|
||||||
sortedLbData += [sorted_entry];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by combined key (wins descending, losses ascending) - FALSE = descending order
|
// 2. Sort by key (stride of 2) in descending order (highest score first)
|
||||||
sortedLbData = llListSort(sortedLbData, 1, FALSE);
|
sortList = llListSort(sortList, 2, FALSE);
|
||||||
|
|
||||||
// Clean up the format back to "Name:Wins:Losses" (skip padded wins in position 0)
|
// 3. Rebuild the leaderboard data in sorted order (Stided list: Name, Wins, Losses)
|
||||||
cleanedData = [];
|
for (i = 0; i < llGetListLength(sortList); i += 2) {
|
||||||
for (sortI = 0; sortI < llGetListLength(sortedLbData); sortI++) {
|
origIdx = llList2Integer(sortList, i + 1);
|
||||||
sorted_entry = llList2String(sortedLbData, sortI);
|
base = origIdx * 3;
|
||||||
parts = llParseString2List(sorted_entry, [":"], []);
|
sortedData += [
|
||||||
if (llGetListLength(parts) >= 4) {
|
llList2String(leaderboardData, base),
|
||||||
// parts[0] = paddedWins (skip), parts[1] = name, parts[2] = actualWins, parts[3] = losses
|
llList2Integer(leaderboardData, base + 1),
|
||||||
sortName = llList2String(parts, 1);
|
llList2Integer(leaderboardData, base + 2)
|
||||||
winsStr = llList2String(parts, 2);
|
];
|
||||||
lossesStr = llList2String(parts, 3);
|
|
||||||
cleanedData += [sortName + ":" + winsStr + ":" + lossesStr];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cleanedData;
|
return sortedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate leaderboard text and send to separate leaderboard object
|
// Generate leaderboard text and send to separate leaderboard object
|
||||||
integer generateLeaderboardText() {
|
integer generateLeaderboardText() {
|
||||||
list sortedData = getSortedLeaderboard();
|
list sortedData = getSortedLeaderboard();
|
||||||
|
string SPACES = " ";
|
||||||
|
string title = "TOP BATTLE RECORDS";
|
||||||
|
integer titleMargin = 0;
|
||||||
|
string leaderboardText = "";
|
||||||
|
integer genI = 0;
|
||||||
|
string playerName = "";
|
||||||
|
integer genWins = 0;
|
||||||
|
integer genLosses = 0;
|
||||||
|
string rank = "";
|
||||||
|
string leftPart = "";
|
||||||
|
string rightPart = "";
|
||||||
|
integer spaceNeeded = 0;
|
||||||
|
integer numSorted = llGetListLength(sortedData) / 3;
|
||||||
|
integer base = 0;
|
||||||
|
string sWins = "";
|
||||||
|
string sLosses = "";
|
||||||
|
|
||||||
// 1. Build Title Row (Centered)
|
// 1. Build Title Row (Centered)
|
||||||
string title = "TOP BATTLE RECORDS";
|
titleMargin = (LEADERBOARD_WIDTH - llStringLength(title)) / 2;
|
||||||
integer titleLen = llStringLength(title);
|
|
||||||
integer titleMargin = (LEADERBOARD_WIDTH - titleLen) / 2;
|
|
||||||
if (titleMargin < 0) titleMargin = 0;
|
if (titleMargin < 0) titleMargin = 0;
|
||||||
|
|
||||||
string titleSpaces = "";
|
leaderboardText = llGetSubString(SPACES, 0, titleMargin - 1) + title + "\n";
|
||||||
integer ts;
|
|
||||||
for (ts = 0; ts < titleMargin; ts++) titleSpaces += " ";
|
|
||||||
|
|
||||||
string leaderboardText = titleSpaces + title + "\n";
|
|
||||||
|
|
||||||
integer genI;
|
|
||||||
string playerData;
|
|
||||||
list playerParts;
|
|
||||||
string playerName;
|
|
||||||
string genWins;
|
|
||||||
string genLosses;
|
|
||||||
integer rankNumber;
|
|
||||||
string rank;
|
|
||||||
string leftPart;
|
|
||||||
string rightPart;
|
|
||||||
integer spaceNeeded;
|
|
||||||
string spacer;
|
|
||||||
integer s;
|
|
||||||
string line;
|
|
||||||
integer actualPlayers;
|
|
||||||
|
|
||||||
// Add actual player data (up to MAX_LEADERBOARD_ENTRIES)
|
// Add actual player data (up to MAX_LEADERBOARD_ENTRIES)
|
||||||
for (genI = 0; genI < llGetListLength(sortedData) && genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
for (genI = 0; genI < numSorted && genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
||||||
playerData = llList2String(sortedData, genI);
|
base = genI * 3;
|
||||||
playerParts = llParseString2List(playerData, [":"], []);
|
playerName = llList2String(sortedData, base);
|
||||||
|
genWins = llList2Integer(sortedData, base + 1);
|
||||||
|
genLosses = llList2Integer(sortedData, base + 2);
|
||||||
|
|
||||||
if (llGetListLength(playerParts) >= 3) {
|
if (llStringLength(playerName) > 12) {
|
||||||
playerName = llList2String(playerParts, 0);
|
playerName = llGetSubString(playerName, 0, 9) + "...";
|
||||||
genWins = llList2String(playerParts, 1);
|
|
||||||
genLosses = llList2String(playerParts, 2);
|
|
||||||
|
|
||||||
// [Rank(4) + Name(14) + Gaps + Stats(10) = 32 chars total]
|
|
||||||
if (llStringLength(playerName) > 12) {
|
|
||||||
playerName = llGetSubString(playerName, 0, 9) + "...";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format rank string: "01. " through "10. " (always 4 chars)
|
|
||||||
rankNumber = genI + 1;
|
|
||||||
rank = (string)rankNumber + ". ";
|
|
||||||
if (rankNumber < 10) rank = "0" + rank;
|
|
||||||
|
|
||||||
// Format stats with fixed-width padding to align columns
|
|
||||||
// Standardizing to 10 characters: "W: 99/L: 9"
|
|
||||||
string sWins = (string)genWins;
|
|
||||||
while (llStringLength(sWins) < 3) sWins = " " + sWins;
|
|
||||||
string sLosses = (string)genLosses;
|
|
||||||
while (llStringLength(sLosses) < 2) sLosses = " " + sLosses;
|
|
||||||
|
|
||||||
leftPart = rank + playerName;
|
|
||||||
rightPart = "W:" + sWins + "/L:" + sLosses; // Exactly 10 characters
|
|
||||||
|
|
||||||
// Push rightPart to column 32
|
|
||||||
spaceNeeded = LEADERBOARD_WIDTH - llStringLength(leftPart) - llStringLength(rightPart);
|
|
||||||
if (spaceNeeded < 1) spaceNeeded = 1;
|
|
||||||
|
|
||||||
spacer = "";
|
|
||||||
for (s = 0; s < spaceNeeded; s++) spacer += " ";
|
|
||||||
|
|
||||||
line = leftPart + spacer + rightPart;
|
|
||||||
leaderboardText += line + "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format rank: "01. " through "10. "
|
||||||
|
rank = (string)(genI + 1) + ". ";
|
||||||
|
if (genI < 9) rank = "0" + rank;
|
||||||
|
|
||||||
|
// Format stats 10-char width: "W: 99/L: 9"
|
||||||
|
sWins = (string)genWins;
|
||||||
|
if (llStringLength(sWins) < 3) sWins = llGetSubString(" ", 0, 2 - llStringLength(sWins)) + sWins;
|
||||||
|
sLosses = (string)genLosses;
|
||||||
|
if (llStringLength(sLosses) < 2) sLosses = llGetSubString(" ", 0, 1 - llStringLength(sLosses)) + sLosses;
|
||||||
|
|
||||||
|
leftPart = rank + playerName;
|
||||||
|
rightPart = "W:" + sWins + "/L:" + sLosses;
|
||||||
|
|
||||||
|
spaceNeeded = LEADERBOARD_WIDTH - llStringLength(leftPart) - 10;
|
||||||
|
if (spaceNeeded < 1) spaceNeeded = 1;
|
||||||
|
|
||||||
|
leaderboardText += leftPart + llGetSubString(SPACES, 0, spaceNeeded - 1) + rightPart + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill remaining positions with placeholders
|
// Fill remaining positions with placeholders
|
||||||
actualPlayers = llGetListLength(sortedData);
|
for (genI = numSorted; genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
||||||
for (genI = actualPlayers; genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
rank = (string)(genI + 1) + ". ";
|
||||||
rankNumber = genI + 1;
|
if (genI < 9) rank = "0" + rank;
|
||||||
rank = (string)rankNumber + ". ";
|
|
||||||
if (rankNumber < 10) rank = "0" + rank;
|
|
||||||
|
|
||||||
// Use EXACT same formatting as players so columns align!
|
|
||||||
leftPart = rank + "----------";
|
leftPart = rank + "----------";
|
||||||
rightPart = "W: 0/L: 0"; // Matches 10-char fixed width
|
rightPart = "W: 0/L: 0";
|
||||||
|
spaceNeeded = LEADERBOARD_WIDTH - llStringLength(leftPart) - 10;
|
||||||
|
|
||||||
spaceNeeded = LEADERBOARD_WIDTH - llStringLength(leftPart) - llStringLength(rightPart);
|
leaderboardText += leftPart + llGetSubString(SPACES, 0, spaceNeeded - 1) + rightPart + "\n";
|
||||||
if (spaceNeeded < 1) spaceNeeded = 1;
|
|
||||||
|
|
||||||
spacer = "";
|
|
||||||
for (s = 0; s < spaceNeeded; s++) spacer += " ";
|
|
||||||
|
|
||||||
line = leftPart + spacer + rightPart;
|
|
||||||
leaderboardText += line + "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send formatted text to leaderboard bridge
|
// Send formatted text to leaderboard bridge
|
||||||
|
|
@ -416,9 +357,7 @@ integer resetLeaderboard() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
leaderboardNames = [];
|
leaderboardData = [];
|
||||||
leaderboardWins = [];
|
|
||||||
leaderboardLosses = [];
|
|
||||||
pendingSerialize = "";
|
pendingSerialize = "";
|
||||||
kvpWriteReq = llUpdateKeyValue("Peril_LB_Top50", "", FALSE, "");
|
kvpWriteReq = llUpdateKeyValue("Peril_LB_Top50", "", FALSE, "");
|
||||||
generateLeaderboardText(); // Send empty leaderboard immediately
|
generateLeaderboardText(); // Send empty leaderboard immediately
|
||||||
|
|
@ -427,10 +366,7 @@ integer resetLeaderboard() {
|
||||||
|
|
||||||
// Clear all current players from the scoreboard
|
// Clear all current players from the scoreboard
|
||||||
integer clearAllPlayers() {
|
integer clearAllPlayers() {
|
||||||
// Clear ONLY current game player data lists (NOT leaderboard data)
|
activePlayers = [];
|
||||||
playerNames = [];
|
|
||||||
playerLives = [];
|
|
||||||
playerProfiles = [];
|
|
||||||
|
|
||||||
// Clear any pending HTTP requests
|
// Clear any pending HTTP requests
|
||||||
httpRequests = [];
|
httpRequests = [];
|
||||||
|
|
@ -444,9 +380,9 @@ integer clearAllPlayers() {
|
||||||
|
|
||||||
// Reset all player prims to default state
|
// Reset all player prims to default state
|
||||||
for (clearI = 0; clearI < 10; clearI++) {
|
for (clearI = 0; clearI < 10; clearI++) {
|
||||||
clearProfilePrimIndex = llList2Integer(profileLinks, clearI);
|
clearProfilePrimIndex = getProfilePrimLink(clearI);
|
||||||
clearHeartsPrimIndex = llList2Integer(heartsLinks, clearI);
|
clearHeartsPrimIndex = getHeartsPrimLink(clearI);
|
||||||
clearOverlayPrimIndex = llList2Integer(overlayLinks, clearI);
|
clearOverlayPrimIndex = getOverlayPrimLink(clearI);
|
||||||
|
|
||||||
// SAFETY CHECK - use if block instead of continue for maximum compatibility
|
// SAFETY CHECK - use if block instead of continue for maximum compatibility
|
||||||
if (clearProfilePrimIndex > 0) {
|
if (clearProfilePrimIndex > 0) {
|
||||||
|
|
@ -479,24 +415,17 @@ integer clearAllPlayers() {
|
||||||
|
|
||||||
// Remove a single player from the scoreboard display
|
// Remove a single player from the scoreboard display
|
||||||
integer removePlayer(string playerName) {
|
integer removePlayer(string playerName) {
|
||||||
integer removeIdx = llListFindList(playerNames, [playerName]);
|
integer idx = llListFindList(activePlayers, [playerName]);
|
||||||
if (removeIdx != -1) {
|
if (idx != -1) {
|
||||||
// Remove player from internal lists
|
activePlayers = llDeleteSubList(activePlayers, idx, idx + 2);
|
||||||
playerNames = llDeleteSubList(playerNames, removeIdx, removeIdx);
|
|
||||||
playerLives = llDeleteSubList(playerLives, removeIdx, removeIdx);
|
|
||||||
playerProfiles = llDeleteSubList(playerProfiles, removeIdx, removeIdx);
|
|
||||||
|
|
||||||
// Refresh the entire display to shift remaining players up
|
|
||||||
refreshPlayerDisplay();
|
refreshPlayerDisplay();
|
||||||
|
dbg("📈 Player removed: " + playerName);
|
||||||
dbg("📈 [Scoreboard Manager] 📊 Removed " + playerName + " from the scoreboard and shifted remaining players.");
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the entire player display - shows all current players in order
|
|
||||||
integer refreshPlayerDisplay() {
|
integer refreshPlayerDisplay() {
|
||||||
integer numActivePlayers = llGetListLength(playerNames);
|
integer numActivePlayers = llGetListLength(activePlayers) / 3;
|
||||||
integer refreshI;
|
integer refreshI;
|
||||||
integer refreshProfilePrimIndex = 0;
|
integer refreshProfilePrimIndex = 0;
|
||||||
integer refreshHeartsPrimIndex = 0;
|
integer refreshHeartsPrimIndex = 0;
|
||||||
|
|
@ -512,9 +441,9 @@ integer refreshPlayerDisplay() {
|
||||||
|
|
||||||
// Only reset prims for unused slots (avoid flickering for active players)
|
// Only reset prims for unused slots (avoid flickering for active players)
|
||||||
for (refreshI = numActivePlayers; refreshI < 10; refreshI++) {
|
for (refreshI = numActivePlayers; refreshI < 10; refreshI++) {
|
||||||
refreshProfilePrimIndex = llList2Integer(profileLinks, refreshI);
|
refreshProfilePrimIndex = getProfilePrimLink(refreshI);
|
||||||
refreshHeartsPrimIndex = llList2Integer(heartsLinks, refreshI);
|
refreshHeartsPrimIndex = getHeartsPrimLink(refreshI);
|
||||||
refreshOverlayPrimIndex = llList2Integer(overlayLinks, refreshI);
|
refreshOverlayPrimIndex = getOverlayPrimLink(refreshI);
|
||||||
|
|
||||||
if (refreshProfilePrimIndex > 0) {
|
if (refreshProfilePrimIndex > 0) {
|
||||||
// Reset to default only for unused slots
|
// Reset to default only for unused slots
|
||||||
|
|
@ -541,14 +470,15 @@ integer refreshPlayerDisplay() {
|
||||||
|
|
||||||
// Now display all current players in their new positions
|
// Now display all current players in their new positions
|
||||||
for (refreshI = 0; refreshI < numActivePlayers; refreshI++) {
|
for (refreshI = 0; refreshI < numActivePlayers; refreshI++) {
|
||||||
r_name = llList2String(playerNames, refreshI);
|
integer base = refreshI * 3;
|
||||||
r_lives = llList2Integer(playerLives, refreshI);
|
r_name = llList2String(activePlayers, base);
|
||||||
r_profileTexture = llList2String(playerProfiles, refreshI);
|
r_lives = llList2Integer(activePlayers, base + 1);
|
||||||
|
r_profileTexture = llList2String(activePlayers, base + 2);
|
||||||
|
|
||||||
// Calculate prim indices for this position
|
// Calculate prim indices for this position
|
||||||
r_profileIdx = llList2Integer(profileLinks, refreshI);
|
r_profileIdx = getProfilePrimLink(refreshI);
|
||||||
r_heartsIdx = llList2Integer(heartsLinks, refreshI);
|
r_heartsIdx = getHeartsPrimLink(refreshI);
|
||||||
r_overlayIdx = llList2Integer(overlayLinks, refreshI);
|
r_overlayIdx = getOverlayPrimLink(refreshI);
|
||||||
|
|
||||||
if (r_profileIdx > 0) {
|
if (r_profileIdx > 0) {
|
||||||
// Determine profile texture to use
|
// Determine profile texture to use
|
||||||
|
|
@ -602,9 +532,9 @@ integer isBot(string playerName) {
|
||||||
|
|
||||||
// Map player index to profile prim link number
|
// Map player index to profile prim link number
|
||||||
// Functions relocated to avoid hardcoded math
|
// Functions relocated to avoid hardcoded math
|
||||||
integer getProfilePrimLink(integer playerIndex) { return llList2Integer(profileLinks, playerIndex); }
|
integer getProfilePrimLink(integer playerIndex) { return llList2Integer(gridLinks, playerIndex * 3); }
|
||||||
integer getHeartsPrimLink(integer playerIndex) { return llList2Integer(heartsLinks, playerIndex); }
|
integer getHeartsPrimLink(integer playerIndex) { return llList2Integer(gridLinks, (playerIndex * 3) + 1); }
|
||||||
integer getOverlayPrimLink(integer playerIndex) { return llList2Integer(overlayLinks, playerIndex); }
|
integer getOverlayPrimLink(integer playerIndex) { return llList2Integer(gridLinks, (playerIndex * 3) + 2); }
|
||||||
|
|
||||||
string getHeartTexture(integer lives) {
|
string getHeartTexture(integer lives) {
|
||||||
if (lives <= 0) return TEXTURE_0_HEARTS;
|
if (lives <= 0) return TEXTURE_0_HEARTS;
|
||||||
|
|
@ -613,84 +543,37 @@ string getHeartTexture(integer lives) {
|
||||||
else return TEXTURE_3_HEARTS; // 3 or more
|
else return TEXTURE_3_HEARTS; // 3 or more
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to set glow and color on a prim
|
||||||
|
setGlow(integer link, float glow, vector color) {
|
||||||
|
if (link > 0) {
|
||||||
|
llSetLinkPrimitiveParamsFast(link, [PRIM_GLOW, ALL_SIDES, glow, PRIM_COLOR, ALL_SIDES, color, 1.0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update all glow effects (peril and winner)
|
// Update all glow effects (peril and winner)
|
||||||
integer updatePlayerGlowEffects() {
|
integer updatePlayerGlowEffects() {
|
||||||
// First, remove glow and reset tint from all players
|
integer numPlayers = llGetListLength(activePlayers) / 3;
|
||||||
integer glowI;
|
integer glowI;
|
||||||
integer glowProfilePrimIndex;
|
for (glowI = 0; glowI < numPlayers; glowI++) {
|
||||||
integer glowHeartsPrimIndex;
|
setGlow(getProfilePrimLink(glowI), 0.0, <1,1,1>);
|
||||||
|
setGlow(getHeartsPrimLink(glowI), 0.0, <1,1,1>);
|
||||||
for (glowI = 0; glowI < llGetListLength(playerNames); glowI++) {
|
|
||||||
glowProfilePrimIndex = llList2Integer(profileLinks, glowI);
|
|
||||||
glowHeartsPrimIndex = llList2Integer(heartsLinks, glowI);
|
|
||||||
|
|
||||||
if (glowProfilePrimIndex > 0) {
|
|
||||||
llSetLinkPrimitiveParamsFast(glowProfilePrimIndex, [
|
|
||||||
PRIM_GLOW, ALL_SIDES, 0.0,
|
|
||||||
PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
if (glowHeartsPrimIndex > 0) {
|
|
||||||
llSetLinkPrimitiveParamsFast(glowHeartsPrimIndex, [
|
|
||||||
PRIM_GLOW, ALL_SIDES, 0.0,
|
|
||||||
PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 1.0>, 1.0
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priority 1: Green glow for winner (overrides peril glow)
|
integer idx = -1;
|
||||||
|
vector col = <1,1,1>;
|
||||||
|
float glow = 0.0;
|
||||||
|
|
||||||
if (currentWinner != "" && currentWinner != "NONE") {
|
if (currentWinner != "" && currentWinner != "NONE") {
|
||||||
integer winnerIndex = llListFindList(playerNames, [currentWinner]);
|
idx = llListFindList(activePlayers, [currentWinner]);
|
||||||
if (winnerIndex != -1) {
|
if (idx != -1) { idx = idx / 3; col = <0,1,0>; glow = 0.3; }
|
||||||
integer winnerProfilePrimIndex = getProfilePrimLink(winnerIndex);
|
} else if (currentPerilPlayer != "" && currentPerilPlayer != "NONE") {
|
||||||
integer winnerHeartsPrimIndex = getHeartsPrimLink(winnerIndex);
|
idx = llListFindList(activePlayers, [currentPerilPlayer]);
|
||||||
|
if (idx != -1) { idx = idx / 3; col = <1,1,0>; glow = 0.2; }
|
||||||
// Check if the prim exists (discovered index > 0)
|
|
||||||
if (winnerProfilePrimIndex > 0) {
|
|
||||||
// Add green glow + green tint to winner
|
|
||||||
llSetLinkPrimitiveParamsFast(winnerProfilePrimIndex, [
|
|
||||||
PRIM_GLOW, ALL_SIDES, 0.3,
|
|
||||||
PRIM_COLOR, ALL_SIDES, <0.0, 1.0, 0.0>, 1.0
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Also add glow to hearts if found
|
|
||||||
if (winnerHeartsPrimIndex > 0) {
|
|
||||||
llSetLinkPrimitiveParamsFast(winnerHeartsPrimIndex, [
|
|
||||||
PRIM_GLOW, ALL_SIDES, 0.3,
|
|
||||||
PRIM_COLOR, ALL_SIDES, <0.0, 1.0, 0.0>, 1.0
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] 🏆 Added green glow to winner: " + currentWinner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Priority 2: Yellow glow for peril player (only if not the winner)
|
|
||||||
else if (currentPerilPlayer != "" && currentPerilPlayer != "NONE") {
|
if (idx != -1) {
|
||||||
integer perilIndex = llListFindList(playerNames, [currentPerilPlayer]);
|
setGlow(getProfilePrimLink(idx), glow, col);
|
||||||
if (perilIndex != -1) {
|
setGlow(getHeartsPrimLink(idx), glow, col);
|
||||||
integer perilProfilePrimIndex = getProfilePrimLink(perilIndex);
|
|
||||||
integer perilHeartsPrimIndex = getHeartsPrimLink(perilIndex);
|
|
||||||
|
|
||||||
// Check if the prim exists (discovered index > 0)
|
|
||||||
if (perilProfilePrimIndex > 0) {
|
|
||||||
// Add yellow glow + yellow tint to peril player
|
|
||||||
llSetLinkPrimitiveParamsFast(perilProfilePrimIndex, [
|
|
||||||
PRIM_GLOW, ALL_SIDES, 0.2,
|
|
||||||
PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 0.0>, 1.0
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Also add glow to hearts if found
|
|
||||||
if (perilHeartsPrimIndex > 0) {
|
|
||||||
llSetLinkPrimitiveParamsFast(perilHeartsPrimIndex, [
|
|
||||||
PRIM_GLOW, ALL_SIDES, 0.2,
|
|
||||||
PRIM_COLOR, ALL_SIDES, <1.0, 1.0, 0.0>, 1.0
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] ✨ Added yellow glow to peril player: " + currentPerilPlayer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -703,26 +586,19 @@ integer updatePerilPlayerGlow() {
|
||||||
|
|
||||||
// Update player display on the grid
|
// Update player display on the grid
|
||||||
integer updatePlayerDisplay(string playerName, integer lives, string profileUUID) {
|
integer updatePlayerDisplay(string playerName, integer lives, string profileUUID) {
|
||||||
// Find existing player or add new one
|
integer playerIndex = llListFindList(activePlayers, [playerName]);
|
||||||
integer playerIndex = llListFindList(playerNames, [playerName]);
|
if (playerIndex != -1) playerIndex = playerIndex / 3;
|
||||||
|
|
||||||
if (playerIndex == -1) {
|
if (playerIndex == -1) {
|
||||||
// New player - find next available slot
|
playerIndex = llGetListLength(activePlayers) / 3;
|
||||||
playerIndex = llGetListLength(playerNames);
|
|
||||||
if (playerIndex >= 10) {
|
if (playerIndex >= 10) {
|
||||||
dbg("📈 [Scoreboard Manager] ⚠️ WARNING: Maximum 10 players supported, ignoring: " + playerName);
|
dbg("📈 MAX players reached: " + playerName);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to tracking lists
|
string activeUUID = profileUUID;
|
||||||
playerNames += [playerName];
|
if (isBot(playerName)) activeUUID = TEXTURE_BOT_PROFILE;
|
||||||
playerLives += [lives];
|
activePlayers += [playerName, lives, activeUUID];
|
||||||
// For bots, always store the bot texture UUID to prevent HTTP requests
|
|
||||||
if (isBot(playerName)) {
|
|
||||||
playerProfiles += [TEXTURE_BOT_PROFILE];
|
|
||||||
} else {
|
|
||||||
playerProfiles += [profileUUID];
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEBUG: Show prim mapping - DISABLED to save memory
|
// DEBUG: Show prim mapping - DISABLED to save memory
|
||||||
// if (VERBOSE_LOGGING) {
|
// if (VERBOSE_LOGGING) {
|
||||||
|
|
@ -739,15 +615,13 @@ integer updatePlayerDisplay(string playerName, integer lives, string profileUUID
|
||||||
// }
|
// }
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Update existing player
|
activePlayers = llListReplaceList(activePlayers, [lives], (playerIndex * 3) + 1, (playerIndex * 3) + 1);
|
||||||
playerLives = llListReplaceList(playerLives, [lives], playerIndex, playerIndex);
|
|
||||||
// Don't overwrite cached profile texture with original UUID on updates
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the physical prims for this player
|
// Update the physical prims for this player
|
||||||
integer updateProfilePrimIndex = llList2Integer(profileLinks, playerIndex);
|
integer updateProfilePrimIndex = getProfilePrimLink(playerIndex);
|
||||||
integer updateHeartsPrimIndex = llList2Integer(heartsLinks, playerIndex);
|
integer updateHeartsPrimIndex = getHeartsPrimLink(playerIndex);
|
||||||
integer updateOverlayPrimIndex = llList2Integer(overlayLinks, playerIndex);
|
integer updateOverlayPrimIndex = getOverlayPrimLink(playerIndex);
|
||||||
|
|
||||||
if (updateProfilePrimIndex <= 0) return 0;
|
if (updateProfilePrimIndex <= 0) return 0;
|
||||||
|
|
||||||
|
|
@ -761,32 +635,26 @@ integer updatePlayerDisplay(string playerName, integer lives, string profileUUID
|
||||||
// CRITICAL: Still need to set updateProfileTexture for eliminated players
|
// CRITICAL: Still need to set updateProfileTexture for eliminated players
|
||||||
if (isBot(playerName)) {
|
if (isBot(playerName)) {
|
||||||
updateProfileTexture = TEXTURE_BOT_PROFILE;
|
updateProfileTexture = TEXTURE_BOT_PROFILE;
|
||||||
} else if (playerIndex < llGetListLength(playerProfiles)) {
|
} else {
|
||||||
string updateCachedTexture = llList2String(playerProfiles, playerIndex);
|
string updateCachedTexture = llList2String(activePlayers, (playerIndex * 3) + 2);
|
||||||
if (updateCachedTexture != "" && updateCachedTexture != profileUUID &&
|
if (updateCachedTexture != "" && updateCachedTexture != profileUUID &&
|
||||||
updateCachedTexture != TEXTURE_DEFAULT_PROFILE && updateCachedTexture != TEXTURE_BOT_PROFILE &&
|
updateCachedTexture != TEXTURE_DEFAULT_PROFILE && updateCachedTexture != TEXTURE_BOT_PROFILE &&
|
||||||
updateCachedTexture != TEXTURE_ELIMINATED_X) {
|
updateCachedTexture != TEXTURE_ELIMINATED_X) {
|
||||||
// We have a previously fetched profile picture, use it
|
|
||||||
updateProfileTexture = updateCachedTexture;
|
updateProfileTexture = updateCachedTexture;
|
||||||
} else {
|
} else {
|
||||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Player is alive - determine profile texture to use
|
// Player is alive - determine profile texture to use
|
||||||
updateProfileTexture = profileUUID;
|
updateProfileTexture = profileUUID;
|
||||||
|
|
||||||
// Check if we already have a cached profile texture for this player
|
// Check if we already have a cached profile texture for this player
|
||||||
if (playerIndex < llGetListLength(playerProfiles)) {
|
string liveCachedTexture = llList2String(activePlayers, (playerIndex * 3) + 2);
|
||||||
string liveCachedTexture = llList2String(playerProfiles, playerIndex);
|
if (liveCachedTexture != "" && liveCachedTexture != profileUUID &&
|
||||||
if (liveCachedTexture != "" && liveCachedTexture != profileUUID &&
|
liveCachedTexture != TEXTURE_DEFAULT_PROFILE && liveCachedTexture != TEXTURE_BOT_PROFILE &&
|
||||||
liveCachedTexture != TEXTURE_DEFAULT_PROFILE && liveCachedTexture != TEXTURE_BOT_PROFILE &&
|
liveCachedTexture != TEXTURE_ELIMINATED_X) {
|
||||||
liveCachedTexture != TEXTURE_ELIMINATED_X) {
|
updateProfileTexture = liveCachedTexture;
|
||||||
// We have a previously fetched profile picture, use it
|
|
||||||
updateProfileTexture = liveCachedTexture;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no cached texture or using original UUID, determine what to use
|
// If no cached texture or using original UUID, determine what to use
|
||||||
|
|
@ -802,7 +670,7 @@ integer updatePlayerDisplay(string playerName, integer lives, string profileUUID
|
||||||
// }
|
// }
|
||||||
} else if (updateProfileTexture == "" || updateProfileTexture == "00000000-0000-0000-0000-000000000000") {
|
} else if (updateProfileTexture == "" || updateProfileTexture == "00000000-0000-0000-0000-000000000000") {
|
||||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
||||||
dbg("📈 [Scoreboard Manager] ❓ [DEBUG] " + playerName + " has empty/null UUID, using default texture");
|
dbg("Default texture");
|
||||||
} else {
|
} else {
|
||||||
// CRITICAL: Set default texture FIRST, then request profile picture
|
// CRITICAL: Set default texture FIRST, then request profile picture
|
||||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
||||||
|
|
@ -817,10 +685,6 @@ integer updatePlayerDisplay(string playerName, integer lives, string profileUUID
|
||||||
|
|
||||||
// Store the HTTP request mapping: requestID -> playerIndex
|
// Store the HTTP request mapping: requestID -> playerIndex
|
||||||
httpRequests += [httpRequestID, playerIndex];
|
httpRequests += [httpRequestID, playerIndex];
|
||||||
|
|
||||||
// if (VERBOSE_LOGGING) {
|
|
||||||
// llOwnerSay("🔄 [Scoreboard] Requesting profile pic for " + playerName + ", showing default for now");
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -891,12 +755,8 @@ default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
discoverLinks();
|
discoverLinks();
|
||||||
llListen(1, "", llGetOwner(), "");
|
llListen(1, "", llGetOwner(), "");
|
||||||
reportMemoryUsage("Scoreboard Manager");
|
REPORT_MEMORY();
|
||||||
dbg("📈 [Scoreboard Manager] 📈 Managing profile and heart prims via dynamic discovery.");
|
dbg("Ready");
|
||||||
|
|
||||||
// Initialize profile picture extraction constants
|
|
||||||
profile_key_prefix_length = llStringLength(profile_key_prefix);
|
|
||||||
profile_img_prefix_length = llStringLength(profile_img_prefix);
|
|
||||||
|
|
||||||
// Reset background prim to proper state
|
// Reset background prim to proper state
|
||||||
resetBackgroundPrim();
|
resetBackgroundPrim();
|
||||||
|
|
@ -916,8 +776,7 @@ default {
|
||||||
currentWinner = "";
|
currentWinner = "";
|
||||||
updatePlayerGlowEffects();
|
updatePlayerGlowEffects();
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] ✅ Linkset communication active - no discovery needed!");
|
dbg("Init complete");
|
||||||
dbg("📈 [Scoreboard Manager] 📊 Loaded " + (string)llGetListLength(leaderboardNames) + " players from leaderboard data");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
link_message(integer sender, integer num, string str, key id) {
|
link_message(integer sender, integer num, string str, key id) {
|
||||||
|
|
@ -935,7 +794,7 @@ default {
|
||||||
string profileUUID = llList2String(parts, 2);
|
string profileUUID = llList2String(parts, 2);
|
||||||
|
|
||||||
// Debug: Show what data scoreboard received - DISABLED to save memory
|
// Debug: Show what data scoreboard received - DISABLED to save memory
|
||||||
dbg("📈 Scoreboard received update: " + playerName + " has " + (string)lives + " hearts");
|
dbg("Update: " + playerName);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
updatePlayerDisplay(playerName, lives, profileUUID);
|
updatePlayerDisplay(playerName, lives, profileUUID);
|
||||||
|
|
@ -975,7 +834,7 @@ default {
|
||||||
currentPerilPlayer = "";
|
currentPerilPlayer = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] 🎯 Peril player changed from '" + oldPeril + "' to '" + currentPerilPlayer + "'");
|
dbg("Peril: " + currentPerilPlayer);
|
||||||
|
|
||||||
// Update glow effects
|
// Update glow effects
|
||||||
updatePlayerGlowEffects();
|
updatePlayerGlowEffects();
|
||||||
|
|
@ -988,7 +847,7 @@ default {
|
||||||
currentWinner = "";
|
currentWinner = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("📈 [Scoreboard Manager] 🏆 Winner changed from '" + oldWinner + "' to '" + currentWinner + "'");
|
dbg("Winner: " + currentWinner);
|
||||||
|
|
||||||
// Update glow effects - winner glow overrides peril glow
|
// Update glow effects - winner glow overrides peril glow
|
||||||
updatePlayerGlowEffects();
|
updatePlayerGlowEffects();
|
||||||
|
|
@ -1004,14 +863,14 @@ default {
|
||||||
// Remove this request from tracking
|
// Remove this request from tracking
|
||||||
httpRequests = llDeleteSubList(httpRequests, requestIndex, requestIndex + 1);
|
httpRequests = llDeleteSubList(httpRequests, requestIndex, requestIndex + 1);
|
||||||
|
|
||||||
if (status == 200 && playerIndex < llGetListLength(playerNames)) {
|
if (status == 200 && playerIndex < llGetListLength(activePlayers) / 3) {
|
||||||
// Parse the HTML to extract profile image UUID
|
// Parse the HTML to extract profile image UUID
|
||||||
string profileUUID = "";
|
string profileUUID = "";
|
||||||
|
|
||||||
// Try the meta tag method first
|
// Try the meta tag method first
|
||||||
integer metaStart = llSubStringIndex(body, profile_key_prefix);
|
integer metaStart = llSubStringIndex(body, PROFILE_KEY_PREFIX);
|
||||||
if (metaStart != -1) {
|
if (metaStart != -1) {
|
||||||
metaStart += profile_key_prefix_length;
|
metaStart += PROFILE_KEY_PREFIX_LENGTH;
|
||||||
string remainingBody = llGetSubString(body, metaStart, -1);
|
string remainingBody = llGetSubString(body, metaStart, -1);
|
||||||
integer metaEnd = llSubStringIndex(remainingBody, "\"");
|
integer metaEnd = llSubStringIndex(remainingBody, "\"");
|
||||||
if (metaEnd != -1) {
|
if (metaEnd != -1) {
|
||||||
|
|
@ -1021,9 +880,9 @@ default {
|
||||||
|
|
||||||
// If meta tag failed, try img src method
|
// If meta tag failed, try img src method
|
||||||
if (profileUUID == "") {
|
if (profileUUID == "") {
|
||||||
integer imgStart = llSubStringIndex(body, profile_img_prefix);
|
integer imgStart = llSubStringIndex(body, PROFILE_IMG_PREFIX);
|
||||||
if (imgStart != -1) {
|
if (imgStart != -1) {
|
||||||
imgStart += profile_img_prefix_length;
|
imgStart += PROFILE_IMG_PREFIX_LENGTH;
|
||||||
string remainingBody = llGetSubString(body, imgStart, -1);
|
string remainingBody = llGetSubString(body, imgStart, -1);
|
||||||
integer imgEnd = llSubStringIndex(remainingBody, "/");
|
integer imgEnd = llSubStringIndex(remainingBody, "/");
|
||||||
if (imgEnd != -1) {
|
if (imgEnd != -1) {
|
||||||
|
|
@ -1034,8 +893,8 @@ default {
|
||||||
|
|
||||||
// If we got a valid UUID, update the profile prim and cache it
|
// If we got a valid UUID, update the profile prim and cache it
|
||||||
if (profileUUID != "" && profileUUID != "00000000-0000-0000-0000-000000000000") {
|
if (profileUUID != "" && profileUUID != "00000000-0000-0000-0000-000000000000") {
|
||||||
// Update the cached profile texture
|
// Update the cached profile texture in stride
|
||||||
playerProfiles = llListReplaceList(playerProfiles, [profileUUID], playerIndex, playerIndex);
|
activePlayers = llListReplaceList(activePlayers, [profileUUID], (playerIndex * 3) + 2, (playerIndex * 3) + 2);
|
||||||
|
|
||||||
// Update the physical prim using correct mapping
|
// Update the physical prim using correct mapping
|
||||||
integer profilePrimIndex = getProfilePrimLink(playerIndex);
|
integer profilePrimIndex = getProfilePrimLink(playerIndex);
|
||||||
|
|
@ -1055,10 +914,10 @@ default {
|
||||||
PRIM_GLOW, ALL_SIDES, 0.0 // Remove glow
|
PRIM_GLOW, ALL_SIDES, 0.0 // Remove glow
|
||||||
]);
|
]);
|
||||||
|
|
||||||
string playerName = llList2String(playerNames, playerIndex);
|
string playerName = llList2String(activePlayers, playerIndex * 3);
|
||||||
dbg("📈 [Scoreboard Manager] 🖼️ Updated profile picture for " + playerName + " on prim " + (string)profilePrimIndex + " with forced refresh");
|
dbg("Profile updated: " + playerName);
|
||||||
} else {
|
} else {
|
||||||
dbg("📈 [Scoreboard Manager] ❌ ERROR: HTTP response tried to update invalid prim " + (string)profilePrimIndex + " for player " + (string)playerIndex);
|
dbg("Invalid prim: " + (string)profilePrimIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1074,9 +933,7 @@ default {
|
||||||
string val = llGetSubString(data, comma + 1, -1);
|
string val = llGetSubString(data, comma + 1, -1);
|
||||||
|
|
||||||
if (status == "1") {
|
if (status == "1") {
|
||||||
leaderboardNames = [];
|
leaderboardData = [];
|
||||||
leaderboardWins = [];
|
|
||||||
leaderboardLosses = [];
|
|
||||||
|
|
||||||
list entries = llParseString2List(val, ["|"], []);
|
list entries = llParseString2List(val, ["|"], []);
|
||||||
integer i;
|
integer i;
|
||||||
|
|
@ -1084,19 +941,19 @@ default {
|
||||||
string data_entry = llList2String(entries, i);
|
string data_entry = llList2String(entries, i);
|
||||||
list parts = llParseString2List(data_entry, [":"], []);
|
list parts = llParseString2List(data_entry, [":"], []);
|
||||||
if (llGetListLength(parts) >= 3) {
|
if (llGetListLength(parts) >= 3) {
|
||||||
leaderboardNames += [llList2String(parts, 0)];
|
leaderboardData += [
|
||||||
leaderboardWins += [(integer)llList2String(parts, 1)];
|
llList2String(parts, 0),
|
||||||
leaderboardLosses += [(integer)llList2String(parts, 2)];
|
(integer)llList2String(parts, 1),
|
||||||
|
(integer)llList2String(parts, 2)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbg("📈 [Scoreboard Manager] ✅ Loaded global scoreboard containing " + (string)llGetListLength(leaderboardNames) + " players!");
|
dbg("LB Loaded");
|
||||||
} else if (status == "3") { // XP_ERROR_KEY_NOT_FOUND
|
} else if (status == "3") {
|
||||||
leaderboardNames = [];
|
leaderboardData = [];
|
||||||
leaderboardWins = [];
|
dbg("LB Empty");
|
||||||
leaderboardLosses = [];
|
|
||||||
dbg("📈 [Scoreboard Manager] ℹ️ Global scoreboard is currently empty (database fresh).");
|
|
||||||
} else {
|
} else {
|
||||||
dbg("📈 [Scoreboard Manager] ⚠️ Failed to load global scoreboard (Status: " + status + ")");
|
dbg("LB Error: " + status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Generate board with downloaded or empty data
|
// Generate board with downloaded or empty data
|
||||||
|
|
@ -1108,8 +965,8 @@ default {
|
||||||
if (status == "3") {
|
if (status == "3") {
|
||||||
// Update failed because key didn't exist yet! Create it.
|
// Update failed because key didn't exist yet! Create it.
|
||||||
llCreateKeyValue("Peril_LB_Top50", pendingSerialize);
|
llCreateKeyValue("Peril_LB_Top50", pendingSerialize);
|
||||||
} else if (status == "1") {
|
dbg("LB Saved");
|
||||||
dbg("📈 [Scoreboard Manager] ✅ Global scoreboard synced successfully.");
|
pendingSerialize = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1117,7 +974,7 @@ default {
|
||||||
|
|
||||||
|
|
||||||
timer() {
|
timer() {
|
||||||
dbg("📈 [Scoreboard Manager] ⏱️ Auto-refreshing Global Scoreboard Data...");
|
dbg("Timer");
|
||||||
loadLeaderboardData();
|
loadLeaderboardData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1138,7 +995,6 @@ default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (msg == "clearx") {
|
else if (msg == "clearx") {
|
||||||
dbg("Refreshing display to clear test X overlays...");
|
|
||||||
refreshPlayerDisplay();
|
refreshPlayerDisplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ resetGame() {
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
reportMemoryUsage("Main Controller");
|
REPORT_MEMORY();
|
||||||
dbg("🎮 Main Controller ready! (Discovery Mode)");
|
dbg("🎮 Main Controller ready! (Discovery Mode)");
|
||||||
|
|
||||||
// Initialize lockout system
|
// Initialize lockout system
|
||||||
|
|
@ -317,7 +317,7 @@ default {
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
reportMemoryUsage("Main Controller");
|
REPORT_MEMORY();
|
||||||
dbg("🔄 Main Controller reset via rez...");
|
dbg("🔄 Main Controller reset via rez...");
|
||||||
|
|
||||||
// Re-initialize lockout system
|
// Re-initialize lockout system
|
||||||
|
|
@ -473,14 +473,6 @@ default {
|
||||||
link_message(integer sender, integer num, string str, key id) {
|
link_message(integer sender, integer num, string str, key id) {
|
||||||
// Dialog forwarding now handled by Player_RegistrationManager
|
// Dialog forwarding now handled by Player_RegistrationManager
|
||||||
|
|
||||||
// Handle player registration from other scripts (NOT delegated, this is for other internal communication)
|
|
||||||
if (num == MSG_REGISTER_PLAYER) {
|
|
||||||
// This is for other scripts that might still use the old MSG_REGISTER_PLAYER message
|
|
||||||
// Convert it to the new message for the Player_RegistrationManager
|
|
||||||
llMessageLinked(LINK_SET, MSG_REGISTER_PLAYER_REQUEST, str, id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle registration updates from Player_RegistrationManager
|
// Handle registration updates from Player_RegistrationManager
|
||||||
if (num == MSG_UPDATE_MAIN_LISTS) { // MSG_UPDATE_MAIN_LISTS
|
if (num == MSG_UPDATE_MAIN_LISTS) { // MSG_UPDATE_MAIN_LISTS
|
||||||
// ULTRA-OPTIMIZED: Player_RegistrationManager now handles all heavy processing
|
// ULTRA-OPTIMIZED: Player_RegistrationManager now handles all heavy processing
|
||||||
|
|
|
||||||
|
|
@ -56,18 +56,6 @@ list globallyPickedNumbers = []; // Numbers already picked by other players
|
||||||
integer currentPage = 0;
|
integer currentPage = 0;
|
||||||
#define NUMBERS_PER_PAGE 9 // Leave room for navigation buttons
|
#define NUMBERS_PER_PAGE 9 // Leave room for navigation buttons
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
list getNumbersForPage(integer page, integer diceType) {
|
list getNumbersForPage(integer page, integer diceType) {
|
||||||
// Build list of available numbers (not picked by others OR by current player)
|
// Build list of available numbers (not picked by others OR by current player)
|
||||||
|
|
@ -177,7 +165,7 @@ showPickDialog(string name, key id, integer diceType, integer picks) {
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
reportMemoryUsage("🎮 NumberPicker Dialog");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
// Initialize dynamic channels
|
// Initialize dynamic channels
|
||||||
initializeChannels();
|
initializeChannels();
|
||||||
|
|
@ -203,7 +191,7 @@ default {
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
reportMemoryUsage("🎮 NumberPicker Dialog");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
dbg("🎮 [NumberPicker] 🔄 Number Picker rezzed - reinitializing...");
|
dbg("🎮 [NumberPicker] 🔄 Number Picker rezzed - reinitializing...");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ integer LINK_LEADERBOARD_BRIDGE = -1; // "FURWARE text mesh:Leaderboard:0:0"
|
||||||
#define FW_DONE "fw_done"
|
#define FW_DONE "fw_done"
|
||||||
|
|
||||||
// --- System/Debug (9000-9999) ---
|
// --- System/Debug (9000-9999) ---
|
||||||
#define DEBUG_LOGS 1 // GLOBAL MASTER SWITCH - Set to 1 for dev feedback, 0 to STRIP from memory
|
#define DEBUG_LOGS 0 // GLOBAL MASTER SWITCH - Set to 1 for dev feedback, 0 to STRIP from memory
|
||||||
#if DEBUG_LOGS
|
#if DEBUG_LOGS
|
||||||
#define dbg(msg) llOwnerSay(msg)
|
#define dbg(msg) llOwnerSay(msg)
|
||||||
#else
|
#else
|
||||||
|
|
@ -113,6 +113,17 @@ integer LINK_LEADERBOARD_BRIDGE = -1; // "FURWARE text mesh:Leaderboard:0:0"
|
||||||
#define MSG_QUERY_OWNER_STATUS 213
|
#define MSG_QUERY_OWNER_STATUS 213
|
||||||
|
|
||||||
// --- Memory Management (6000-6099) ---
|
// --- Memory Management (6000-6099) ---
|
||||||
|
#define SHOW_MEMORY 1 // Toggle this to 1 to see memory usage on rez/reset
|
||||||
|
|
||||||
|
#define REPORT_MEMORY() { \
|
||||||
|
if (SHOW_MEMORY) { \
|
||||||
|
integer used = llGetUsedMemory(); \
|
||||||
|
integer free = llGetFreeMemory(); \
|
||||||
|
float percent = ((float)used / (float)(used + free)) * 100.0; \
|
||||||
|
llOwnerSay("🧠 [" + llGetScriptName() + "] Memory: " + (string)used + " used, " + (string)free + " free (" + llGetSubString((string)percent, 0, 4) + "% used)."); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#define MSG_MEMORY_CHECK 6001
|
#define MSG_MEMORY_CHECK 6001
|
||||||
#define MSG_MEMORY_STATS 6002
|
#define MSG_MEMORY_STATS 6002
|
||||||
#define MSG_MEMORY_CLEANUP 6003
|
#define MSG_MEMORY_CLEANUP 6003
|
||||||
|
|
|
||||||
|
|
@ -7,31 +7,18 @@ string displayText;
|
||||||
string myName;
|
string myName;
|
||||||
integer listenHandle = -1;
|
integer listenHandle = -1;
|
||||||
|
|
||||||
// Memory reporting function - defined before use
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
|
REPORT_MEMORY();
|
||||||
string currentDesc = llGetObjectDesc();
|
string currentDesc = llGetObjectDesc();
|
||||||
if (currentDesc == "" || currentDesc == "(No Description)") currentDesc = "Unknown";
|
|
||||||
|
|
||||||
reportMemoryUsage("📱 Player Float (" + currentDesc + ")");
|
|
||||||
|
|
||||||
llSetText("⏳ Waiting...", <1,1,1>, 1.0);
|
llSetText("⏳ Waiting...", <1,1,1>, 1.0);
|
||||||
llSetTimerEvent(1.0);
|
llSetTimerEvent(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
|
REPORT_MEMORY();
|
||||||
if (listenHandle != -1) llListenRemove(listenHandle);
|
if (listenHandle != -1) llListenRemove(listenHandle);
|
||||||
listenHandle = llListen(start_param, "", NULL_KEY, "");
|
listenHandle = llListen(start_param, "", NULL_KEY, "");
|
||||||
myName = "";
|
myName = "";
|
||||||
|
|
@ -83,7 +70,6 @@ default {
|
||||||
else if (llSubStringIndex(message, "SET_NAME:") == 0) {
|
else if (llSubStringIndex(message, "SET_NAME:") == 0) {
|
||||||
myName = llGetSubString(message, 9, -1);
|
myName = llGetSubString(message, 9, -1);
|
||||||
llSetObjectDesc(myName);
|
llSetObjectDesc(myName);
|
||||||
reportMemoryUsage("📱 " + myName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,18 +99,6 @@ float pendingMenuTimestamp = 0.0; // Timeout for pending requests
|
||||||
integer isLocked = FALSE;
|
integer isLocked = FALSE;
|
||||||
key gameOwner;
|
key gameOwner;
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display the main categorized owner menu with lock/unlock controls
|
// Display the main categorized owner menu with lock/unlock controls
|
||||||
showOwnerMenu(key id) {
|
showOwnerMenu(key id) {
|
||||||
|
|
@ -313,7 +301,7 @@ showUnregisteredOwnerMenu(key id, integer canStartGame) {
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
reportMemoryUsage("🎭 Player Dialog");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
// Initialize dynamic channels
|
// Initialize dynamic channels
|
||||||
initializeChannels();
|
initializeChannels();
|
||||||
|
|
@ -356,7 +344,7 @@ default {
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
reportMemoryUsage("🎭 Player Dialog");
|
REPORT_MEMORY();
|
||||||
|
|
||||||
dbg("🔄 Player Dialog Handler rezzed - reinitializing...");
|
dbg("🔄 Player Dialog Handler rezzed - reinitializing...");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,23 +10,29 @@ list names = [];
|
||||||
list lives = [];
|
list lives = [];
|
||||||
list readyPlayers = [];
|
list readyPlayers = [];
|
||||||
#define MAX_PLAYERS 10
|
#define MAX_PLAYERS 10
|
||||||
#define FLOATER_BASE_CHANNEL -86000
|
|
||||||
|
// Dynamic channel system
|
||||||
|
#define CHANNEL_BASE -77000
|
||||||
|
integer FLOATER_BASE_CHANNEL;
|
||||||
integer roundStarted = FALSE;
|
integer roundStarted = FALSE;
|
||||||
integer gameStarting = FALSE;
|
integer gameStarting = FALSE;
|
||||||
|
|
||||||
// Memory reporting function
|
integer calculateChannel(integer offset) {
|
||||||
reportMemoryUsage(string scriptName) {
|
string ownerStr = (string)llGetOwner();
|
||||||
integer used = llGetUsedMemory();
|
string objectStr = (string)llGetLinkKey(1);
|
||||||
integer free = llGetFreeMemory();
|
string combinedStr = ownerStr + objectStr;
|
||||||
integer total = used + free;
|
string hashStr = llMD5String(combinedStr, 0);
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
integer hash1 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 0, 0));
|
||||||
|
integer hash2 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 1, 1));
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
integer combinedHash = hash1 * 16 + hash2;
|
||||||
(string)used + " used, " +
|
return CHANNEL_BASE - (offset * 1000) - combinedHash;
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeChannels() {
|
||||||
|
FLOATER_BASE_CHANNEL = calculateChannel(9);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
string getPlayerName(key id) {
|
string getPlayerName(key id) {
|
||||||
string displayName = llGetDisplayName(id);
|
string displayName = llGetDisplayName(id);
|
||||||
|
|
@ -134,12 +140,12 @@ handlePlayerRegistration(string regData, key requesterId) {
|
||||||
syncMessage = livesStr + "~EMPTY~NONE~" + llList2CSV(names);
|
syncMessage = livesStr + "~EMPTY~NONE~" + llList2CSV(names);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send pre-built sync message
|
// CRITICAL FIX: Send floater rez message to Floater Manager first
|
||||||
llMessageLinked(LINK_SET, MSG_SYNC_GAME_STATE, syncMessage, NULL_KEY);
|
|
||||||
|
|
||||||
// CRITICAL FIX: Send floater rez message to Floater Manager
|
|
||||||
llMessageLinked(LINK_SET, MSG_REZ_FLOATER, newName + "|" + (string)newKey, newKey);
|
llMessageLinked(LINK_SET, MSG_REZ_FLOATER, newName + "|" + (string)newKey, newKey);
|
||||||
|
|
||||||
|
// Then send the sync message to update everyone on the new state
|
||||||
|
llMessageLinked(LINK_SET, MSG_SYNC_GAME_STATE, syncMessage, NULL_KEY);
|
||||||
|
|
||||||
// Send minimal update to Main Controller - just the essential data it needs
|
// Send minimal update to Main Controller - just the essential data it needs
|
||||||
string updateData = (string)ch + "~" + newName;
|
string updateData = (string)ch + "~" + newName;
|
||||||
llMessageLinked(LINK_SET, MSG_UPDATE_MAIN_LISTS, updateData, newKey);
|
llMessageLinked(LINK_SET, MSG_UPDATE_MAIN_LISTS, updateData, newKey);
|
||||||
|
|
@ -156,11 +162,15 @@ handlePlayerRegistration(string regData, key requesterId) {
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
|
initializeChannels();
|
||||||
|
REPORT_MEMORY();
|
||||||
dbg("🎯 [RegMgr] Player Registration Manager ready - discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
dbg("🎯 [RegMgr] Player Registration Manager ready - discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
|
initializeChannels();
|
||||||
|
REPORT_MEMORY();
|
||||||
dbg("🎯 [RegMgr] Player Registration Manager rezzed - resetting state...");
|
dbg("🎯 [RegMgr] Player Registration Manager rezzed - resetting state...");
|
||||||
// Reset local state
|
// Reset local state
|
||||||
players = [];
|
players = [];
|
||||||
|
|
|
||||||
|
|
@ -60,18 +60,6 @@ integer lastRollTime = 0; // Track when last roll happened
|
||||||
integer diceTypeProcessed = FALSE; // Confetti particle system for winner celebrations
|
integer diceTypeProcessed = FALSE; // Confetti particle system for winner celebrations
|
||||||
#define PARTICLE_TEXTURE "7d8ae121-e171-12ae-f5b6-7cc3c0395c7b"
|
#define PARTICLE_TEXTURE "7d8ae121-e171-12ae-f5b6-7cc3c0395c7b"
|
||||||
|
|
||||||
// Memory reporting function
|
|
||||||
reportMemoryUsage(string scriptName) {
|
|
||||||
integer used = llGetUsedMemory();
|
|
||||||
integer free = llGetFreeMemory();
|
|
||||||
integer total = used + free;
|
|
||||||
float percentUsed = ((float)used / (float)total) * 100.0;
|
|
||||||
|
|
||||||
dbg("🧠 [" + scriptName + "] Memory: " +
|
|
||||||
(string)used + " used, " +
|
|
||||||
(string)free + " free (" +
|
|
||||||
llGetSubString((string)percentUsed, 0, 4) + "% used)");
|
|
||||||
}
|
|
||||||
|
|
||||||
list getPicksFor(string nameInput) {
|
list getPicksFor(string nameInput) {
|
||||||
integer i;
|
integer i;
|
||||||
|
|
@ -131,9 +119,13 @@ confetti() {
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
reportMemoryUsage("Roll Module");
|
REPORT_MEMORY();
|
||||||
dbg("🎲 [Roll Module] ready - discovery complete! Bridge: " + (string)LINK_DICE_BRIDGE);
|
dbg("🎲 [Roll Module] ready - discovery complete! Bridge: " + (string)LINK_DICE_BRIDGE);
|
||||||
|
|
||||||
|
// Re-initialize dynamic channels
|
||||||
|
initializeChannels();
|
||||||
|
rollDialogChannel = ROLLDIALOG_CHANNEL;
|
||||||
|
|
||||||
// Clean up any existing listeners
|
// Clean up any existing listeners
|
||||||
if (listenHandle != -1) {
|
if (listenHandle != -1) {
|
||||||
llListenRemove(listenHandle);
|
llListenRemove(listenHandle);
|
||||||
|
|
@ -157,7 +149,7 @@ default {
|
||||||
|
|
||||||
on_rez(integer start_param) {
|
on_rez(integer start_param) {
|
||||||
DISCOVER_CORE_LINKS();
|
DISCOVER_CORE_LINKS();
|
||||||
reportMemoryUsage("Roll Module");
|
REPORT_MEMORY();
|
||||||
dbg("🎲 [Roll Module] reset via rez...");
|
dbg("🎲 [Roll Module] reset via rez...");
|
||||||
|
|
||||||
// Re-initialize dynamic channels
|
// Re-initialize dynamic channels
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,14 @@ list validatePicksData(list picksData, list names) {
|
||||||
|
|
||||||
default {
|
default {
|
||||||
state_entry() {
|
state_entry() {
|
||||||
|
REPORT_MEMORY();
|
||||||
dbg("🔍 [System Debugger] 🔍 System Debugger ready!");
|
dbg("🔍 [System Debugger] 🔍 System Debugger ready!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
on_rez(integer start_param) {
|
||||||
|
REPORT_MEMORY();
|
||||||
|
}
|
||||||
|
|
||||||
link_message(integer sender, integer num, string str, key id) {
|
link_message(integer sender, integer num, string str, key id) {
|
||||||
|
|
||||||
// Handle legacy verbose logging toggle (OBSELETE)
|
// Handle legacy verbose logging toggle (OBSELETE)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue