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
|
||||
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
|
||||
checkMemoryUsage(string context) {
|
||||
|
|
@ -201,7 +189,7 @@ doBotRoll(string botName, integer diceMax) {
|
|||
|
||||
default {
|
||||
state_entry() {
|
||||
reportMemoryUsage("🤖 Bot Manager");
|
||||
REPORT_MEMORY();
|
||||
|
||||
initializeChannels();
|
||||
LISTEN_CHANNEL = BOT_COMMAND_CHANNEL;
|
||||
|
|
@ -222,7 +210,7 @@ default {
|
|||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
reportMemoryUsage("🤖 Bot Manager");
|
||||
REPORT_MEMORY();
|
||||
dbg("🤖 [Bot Manager] 🔄 Bot Manager rezzed - reinitializing...");
|
||||
|
||||
// Re-initialize dynamic channels
|
||||
|
|
|
|||
|
|
@ -113,12 +113,17 @@ processMainControllerStats(string statsData) {
|
|||
|
||||
default {
|
||||
state_entry() {
|
||||
REPORT_MEMORY();
|
||||
dbg("📊 [Memory Monitor] Memory Monitor ready!");
|
||||
|
||||
// Start periodic memory monitoring
|
||||
llSetTimerEvent(MEMORY_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
REPORT_MEMORY();
|
||||
}
|
||||
|
||||
timer() {
|
||||
// Periodic memory check
|
||||
checkMemoryUsage("periodic_check");
|
||||
|
|
|
|||
|
|
@ -40,18 +40,6 @@ integer calculateChannel(integer offset) {
|
|||
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() {
|
||||
SCOREBOARD_CHANNEL_1 = calculateChannel(6); // ~-77600 range
|
||||
|
|
@ -326,13 +314,13 @@ handleDialogRequest(string dialogData) {
|
|||
|
||||
default {
|
||||
state_entry() {
|
||||
reportMemoryUsage("📨 Message Handler");
|
||||
REPORT_MEMORY();
|
||||
|
||||
initializeChannels();
|
||||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
reportMemoryUsage("📨 Message Handler");
|
||||
REPORT_MEMORY();
|
||||
initializeChannels();
|
||||
// Reset local state if needed (synced from Main)
|
||||
players = [];
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ default {
|
|||
|
||||
state_entry() {
|
||||
DISCOVER_CORE_LINKS();
|
||||
REPORT_MEMORY();
|
||||
dbg("📋 [Leaderboard] Leaderboard Communication Script ready! (FURWARE Version)");
|
||||
dbg("📋 [Leaderboard] Managing 'Leaderboard' FURWARE box");
|
||||
dbg("📋 [Leaderboard] ✅ Discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ default {
|
|||
}
|
||||
state_entry() {
|
||||
DISCOVER_CORE_LINKS();
|
||||
REPORT_MEMORY();
|
||||
dbg("🎲 [Dice Bridge] Dice Display Bridge ready! (FURWARE Version)");
|
||||
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
|
||||
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)
|
||||
list allPlayerNames = []; // Names in registration order
|
||||
|
|
@ -90,7 +78,7 @@ list getPicksFor(string nameInput) {
|
|||
// Main event handler
|
||||
default {
|
||||
state_entry() {
|
||||
reportMemoryUsage("💬 Floater Manager");
|
||||
REPORT_MEMORY();
|
||||
|
||||
initializeChannels();
|
||||
|
||||
|
|
@ -106,7 +94,7 @@ default {
|
|||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
reportMemoryUsage("💬 Floater Manager");
|
||||
REPORT_MEMORY();
|
||||
dbg("💬 [Floater Manager] 🔄 Floater Manager rezzed - reinitializing...");
|
||||
|
||||
initializeChannels();
|
||||
|
|
@ -133,47 +121,56 @@ default {
|
|||
return;
|
||||
}
|
||||
|
||||
if (num == MSG_REGISTER_PLAYER) {
|
||||
if (llGetListLength(allPlayerNames) >= MAX_PLAYERS) {
|
||||
dbg("💬 [Floater Manager] ⚠️ Game is full (max " + (string)MAX_PLAYERS + ").");
|
||||
return;
|
||||
}
|
||||
list info = llParseString2List(str, ["|"], []);
|
||||
string name = llList2String(info, 0);
|
||||
key avKey = llList2Key(info, 1);
|
||||
// MSG_REGISTER_PLAYER (106) is now handled by Player_RegistrationManager.lsl
|
||||
// which then sends MSG_REZ_FLOAT (105) here. Legacy handler removed to prevent double-rezzing.
|
||||
|
||||
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) {
|
||||
else if (num == MSG_REZ_FLOAT) { // 105
|
||||
string name = str;
|
||||
integer channelIdx = llListFindList(allPlayerNames, [name]);
|
||||
if (channelIdx == -1) return;
|
||||
key avKey = id;
|
||||
|
||||
key avKey = id; // Passed from MSG_REGISTER_PLAYER or MSG_REZ_FLOAT
|
||||
|
||||
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>;
|
||||
// Handle name|key format if sent
|
||||
integer pipeIdx = llSubStringIndex(str, "|");
|
||||
if (pipeIdx != -1) {
|
||||
name = llGetSubString(str, 0, pipeIdx - 1);
|
||||
if (avKey == NULL_KEY) avKey = (key)llGetSubString(str, pipeIdx + 1, -1);
|
||||
}
|
||||
|
||||
integer ch = FLOATER_BASE_CHANNEL + channelIdx;
|
||||
llRezObject("StatFloat", pos, ZERO_VECTOR, ZERO_ROTATION, ch);
|
||||
llSleep(0.2);
|
||||
llRegionSay(ch, "SET_NAME:" + name);
|
||||
llMessageLinked(LINK_SET, MSG_UPDATE_FLOAT, name, avKey);
|
||||
// Ensure player is in our permanent map
|
||||
integer channelIdx = llListFindList(allPlayerNames, [name]);
|
||||
if (channelIdx == -1) {
|
||||
if (llGetListLength(allPlayerNames) >= MAX_PLAYERS) return;
|
||||
|
||||
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) {
|
||||
string name = str;
|
||||
|
|
@ -240,6 +237,12 @@ default {
|
|||
integer foundIdx = ch - FLOATER_BASE_CHANNEL;
|
||||
if (foundIdx >= 0 && foundIdx < llGetListLength(allPlayerNames)) {
|
||||
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]);
|
||||
if (currentIdx != -1) {
|
||||
if (currentIdx < llGetListLength(players)) players = llDeleteSubList(players, currentIdx, currentIdx);
|
||||
|
|
@ -258,6 +261,19 @@ default {
|
|||
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) {
|
||||
list parts = llParseString2List(str, ["~"], []);
|
||||
if (llGetListLength(parts) < 4) return;
|
||||
|
|
@ -278,7 +294,16 @@ default {
|
|||
}
|
||||
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));
|
||||
|
||||
integer idx;
|
||||
|
|
@ -291,11 +316,20 @@ default {
|
|||
}
|
||||
}
|
||||
else if (num == MSG_CLEANUP_ALL_FLOATERS) {
|
||||
dbg("🧹 [Floater Manager] Universal Cleanup Triggered - Clearing all " + (string)MAX_PLAYERS + " possible channels.");
|
||||
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");
|
||||
}
|
||||
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_OFF) DEBUG_PICKS = FALSE;
|
||||
|
|
|
|||
|
|
@ -610,7 +610,12 @@ integer setDirty(integer action, integer first, integer last, integer isConf,
|
|||
////////// STATES //////////////////////////////////////////
|
||||
|
||||
default {
|
||||
on_rez(integer start_param) {
|
||||
REPORT_MEMORY();
|
||||
}
|
||||
|
||||
state_entry() {
|
||||
REPORT_MEMORY();
|
||||
llOwnerSay("FURWARE text is starting...");
|
||||
|
||||
CHARS = llBase64ToString(
|
||||
|
|
|
|||
|
|
@ -5,18 +5,6 @@
|
|||
// This version chooses a dice size based on the number of players,
|
||||
// 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 picksData;
|
||||
|
|
@ -120,7 +108,7 @@ integer showPickManager(string player, key id) {
|
|||
|
||||
default {
|
||||
state_entry() {
|
||||
reportMemoryUsage("🧮 Game Calculator");
|
||||
REPORT_MEMORY();
|
||||
|
||||
// Initialize/reset all state variables
|
||||
lives = [];
|
||||
|
|
@ -132,7 +120,7 @@ default {
|
|||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
reportMemoryUsage("🧮 Game Calculator");
|
||||
REPORT_MEMORY();
|
||||
|
||||
// Reset all state variables on rez
|
||||
lives = [];
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ integer syncStateToMain() {
|
|||
default {
|
||||
state_entry() {
|
||||
DISCOVER_CORE_LINKS();
|
||||
reportMemoryUsage("Game Manager");
|
||||
REPORT_MEMORY();
|
||||
dbg("🎯 Game Manager ready - discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
||||
|
||||
// Initialize/reset all game state variables
|
||||
|
|
@ -422,7 +422,7 @@ default {
|
|||
|
||||
on_rez(integer start_param) {
|
||||
DISCOVER_CORE_LINKS();
|
||||
reportMemoryUsage("Game Manager");
|
||||
REPORT_MEMORY();
|
||||
dbg("🔄 Game Manager reset via rez...");
|
||||
|
||||
// Reset all game state variables on rez
|
||||
|
|
|
|||
|
|
@ -8,20 +8,22 @@
|
|||
integer BACKGROUND_PRIM = -1;
|
||||
integer ACTIONS_PRIM = -1;
|
||||
|
||||
// Link mappings for player grid (Rows 0-4, Columns 0-1)
|
||||
list profileLinks = [0,0,0,0,0,0,0,0,0,0];
|
||||
list heartsLinks = [0,0,0,0,0,0,0,0,0,0];
|
||||
list overlayLinks = [0,0,0,0,0,0,0,0,0,0];
|
||||
// Grid link mappings for player grid (Stride 3: Profile, Hearts, Overlay)
|
||||
list gridLinks = [
|
||||
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,0,0, 0,0,0
|
||||
];
|
||||
|
||||
// Discover all relevant prims by name at startup
|
||||
discoverLinks() {
|
||||
integer i;
|
||||
integer total = llGetNumberOfPrims();
|
||||
|
||||
// Reset lists
|
||||
profileLinks = [0,0,0,0,0,0,0,0,0,0];
|
||||
heartsLinks = [0,0,0,0,0,0,0,0,0,0];
|
||||
overlayLinks = [0,0,0,0,0,0,0,0,0,0];
|
||||
// Reset list (30 elements for 10 slots * 3 prims)
|
||||
gridLinks = [
|
||||
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,0,0, 0,0,0
|
||||
];
|
||||
|
||||
for (i = 1; i <= total; i++) {
|
||||
string name = llGetLinkName(i);
|
||||
|
|
@ -39,16 +41,17 @@ discoverLinks() {
|
|||
integer index = (row * 2) + col;
|
||||
|
||||
if (index >= 0 && index < 10) {
|
||||
if (type == "profile") profileLinks = llListReplaceList(profileLinks, [i], index, index);
|
||||
else if (type == "life") heartsLinks = llListReplaceList(heartsLinks, [i], index, index);
|
||||
else if (type == "overlay") overlayLinks = llListReplaceList(overlayLinks, [i], index, index);
|
||||
integer gridBase = index * 3;
|
||||
if (type == "profile") gridLinks = llListReplaceList(gridLinks, [i], gridBase, gridBase);
|
||||
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!");
|
||||
if (BACKGROUND_PRIM == -1) dbg("⚠️ WARNING: Background prim ('backboard:0:0') not found!");
|
||||
dbg("Discovery done");
|
||||
if (BACKGROUND_PRIM == -1) dbg("No backboard");
|
||||
}
|
||||
|
||||
// --- Leaderboard Configuration ---
|
||||
|
|
@ -80,18 +83,14 @@ discoverLinks() {
|
|||
#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
|
||||
list playerNames = []; // Current game players for display
|
||||
list playerLives = []; // Current game player lives
|
||||
list playerProfiles = []; // Maps to profile texture UUIDs
|
||||
list activePlayers = []; // Current game state (Stride 3: Name, Lives, UUID)
|
||||
|
||||
// Peril player tracking
|
||||
string currentPerilPlayer = ""; // Track current peril player for glow effects
|
||||
string currentWinner = ""; // Track current winner for green glow effects
|
||||
|
||||
// Leaderboard data (persistent - stored in linkset data)
|
||||
list leaderboardNames = []; // Loaded from linkset data at startup
|
||||
list leaderboardWins = []; // Loaded from linkset data at startup
|
||||
list leaderboardLosses = []; // Loaded from linkset data at startup
|
||||
// Leaderboard data (persistent - stored in linkset data) - Stride of 3 [Name, Wins, Losses]
|
||||
list leaderboardData = [];
|
||||
|
||||
// HTTP tracking
|
||||
list profileRequests = []; // Track which profile requests belong to which player
|
||||
|
|
@ -102,25 +101,13 @@ key kvpReadReq;
|
|||
key kvpWriteReq;
|
||||
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
|
||||
string profile_key_prefix = "<meta name=\"imageid\" content=\"";
|
||||
string profile_img_prefix = "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/";
|
||||
integer profile_key_prefix_length;
|
||||
integer profile_img_prefix_length;
|
||||
// Profile picture extraction constants
|
||||
#define PROFILE_KEY_PREFIX "<meta name=\"imageid\" content=\""
|
||||
#define PROFILE_IMG_PREFIX "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/"
|
||||
#define PROFILE_KEY_PREFIX_LENGTH 30
|
||||
#define PROFILE_IMG_PREFIX_LENGTH 59
|
||||
|
||||
// Reset background prim to proper black background
|
||||
integer resetBackgroundPrim() {
|
||||
|
|
@ -131,7 +118,7 @@ integer resetBackgroundPrim() {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +130,7 @@ integer resetManagerCube() {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -184,21 +171,26 @@ integer updateActionsPrim(string status) {
|
|||
// Load leaderboard data from Experience KVP database
|
||||
integer loadLeaderboardData() {
|
||||
kvpReadReq = llReadKeyValue("Peril_LB_Top50");
|
||||
dbg("📈 [Scoreboard Manager] 🔍 Requesting global scoreboard from Experience database...");
|
||||
dbg("LB Requesting");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Save leaderboard data to Experience KVP database
|
||||
integer saveLeaderboardData() {
|
||||
string serialized = "";
|
||||
integer saveCount = llGetListLength(leaderboardNames);
|
||||
if (saveCount > 50) saveCount = 50; // Cap at Top 50 to fit safely in KVP 4Kb limit
|
||||
integer totalEntries = llGetListLength(leaderboardData) / 3;
|
||||
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++) {
|
||||
string save_entry = llList2String(leaderboardNames, saveI) + ":" +
|
||||
(string)llList2Integer(leaderboardWins, saveI) + ":" +
|
||||
(string)llList2Integer(leaderboardLosses, saveI);
|
||||
base = saveI * 3;
|
||||
save_entry = llList2String(leaderboardData, base) + ":" +
|
||||
(string)llList2Integer(leaderboardData, base + 1) + ":" +
|
||||
(string)llList2Integer(leaderboardData, base + 2);
|
||||
if (serialized != "") serialized += "|";
|
||||
serialized += save_entry;
|
||||
}
|
||||
|
|
@ -206,22 +198,20 @@ integer saveLeaderboardData() {
|
|||
pendingSerialize = serialized;
|
||||
kvpWriteReq = llUpdateKeyValue("Peril_LB_Top50", serialized, FALSE, "");
|
||||
|
||||
dbg("📈 [Scoreboard Manager] 💾 Synced " + (string)saveCount + " players to global scoreboard database.");
|
||||
dbg("LB Saving");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle game won - update leaderboard
|
||||
integer handleGameWon(string winnerName) {
|
||||
integer idx = llListFindList(leaderboardNames, [winnerName]);
|
||||
integer idx = llListFindList(leaderboardData, [winnerName]);
|
||||
if (idx == -1) {
|
||||
// New player
|
||||
leaderboardNames += [winnerName];
|
||||
leaderboardWins += [1];
|
||||
leaderboardLosses += [0];
|
||||
leaderboardData += [winnerName, 1, 0];
|
||||
} else {
|
||||
// Existing player
|
||||
integer currentWins = llList2Integer(leaderboardWins, idx);
|
||||
leaderboardWins = llListReplaceList(leaderboardWins, [currentWins + 1], idx, idx);
|
||||
integer currentWins = llList2Integer(leaderboardData, idx + 1);
|
||||
leaderboardData = llListReplaceList(leaderboardData, [currentWins + 1], idx + 1, idx + 1);
|
||||
}
|
||||
|
||||
saveLeaderboardData();
|
||||
|
|
@ -231,16 +221,14 @@ integer handleGameWon(string winnerName) {
|
|||
|
||||
// Handle game lost - update leaderboard
|
||||
integer handleGameLost(string loserName) {
|
||||
integer lostIdx = llListFindList(leaderboardNames, [loserName]);
|
||||
integer lostIdx = llListFindList(leaderboardData, [loserName]);
|
||||
if (lostIdx == -1) {
|
||||
// New player
|
||||
leaderboardNames += [loserName];
|
||||
leaderboardWins += [0];
|
||||
leaderboardLosses += [1];
|
||||
leaderboardData += [loserName, 0, 1];
|
||||
} else {
|
||||
// Existing player
|
||||
integer currentLosses = llList2Integer(leaderboardLosses, lostIdx);
|
||||
leaderboardLosses = llListReplaceList(leaderboardLosses, [currentLosses + 1], lostIdx, lostIdx);
|
||||
integer currentLosses = llList2Integer(leaderboardData, lostIdx + 2);
|
||||
leaderboardData = llListReplaceList(leaderboardData, [currentLosses + 1], lostIdx + 2, lostIdx + 2);
|
||||
}
|
||||
|
||||
saveLeaderboardData();
|
||||
|
|
@ -248,159 +236,112 @@ integer handleGameLost(string loserName) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Get sorted leaderboard data
|
||||
list getSortedLeaderboard() {
|
||||
list sortedLbData = [];
|
||||
integer sortI;
|
||||
string sortName;
|
||||
integer sortWins;
|
||||
integer sortLosses;
|
||||
string paddedWins;
|
||||
string paddedLosses;
|
||||
integer invertedLosses;
|
||||
string sortKey;
|
||||
string sorted_entry;
|
||||
list parts;
|
||||
list cleanedData = [];
|
||||
string winsStr;
|
||||
string lossesStr;
|
||||
list sortList = [];
|
||||
integer i = 0;
|
||||
integer totalEntries = llGetListLength(leaderboardData) / 3;
|
||||
integer base = 0;
|
||||
integer wins = 0;
|
||||
integer losses = 0;
|
||||
integer sortKey = 0;
|
||||
list sortedData = [];
|
||||
integer origIdx = 0;
|
||||
|
||||
// Create combined data for sorting with padded wins and losses for proper multi-level sorting
|
||||
for (sortI = 0; sortI < llGetListLength(leaderboardNames); sortI++) {
|
||||
sortName = llList2String(leaderboardNames, sortI);
|
||||
sortWins = llList2Integer(leaderboardWins, sortI);
|
||||
sortLosses = llList2Integer(leaderboardLosses, sortI);
|
||||
for (i = 0; i < totalEntries; i++) {
|
||||
base = i * 3;
|
||||
wins = llList2Integer(leaderboardData, base + 1);
|
||||
losses = llList2Integer(leaderboardData, base + 2);
|
||||
|
||||
// Pad wins to 4 digits (higher wins = better rank)
|
||||
paddedWins = (string)(10000 + sortWins);
|
||||
paddedWins = llGetSubString(paddedWins, 1, -1); // Remove the "1" prefix
|
||||
if (wins > 65535) wins = 65535;
|
||||
if (losses > 65535) losses = 65535;
|
||||
|
||||
// Pad losses to 4 digits, but INVERTED for tiebreaker (lower losses = better rank)
|
||||
// Use 9999 - losses so lower losses get higher sort value
|
||||
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];
|
||||
sortKey = (wins << 16) | (65535 - losses);
|
||||
sortList += [sortKey, i];
|
||||
}
|
||||
|
||||
// Sort by combined key (wins descending, losses ascending) - FALSE = descending order
|
||||
sortedLbData = llListSort(sortedLbData, 1, FALSE);
|
||||
// 2. Sort by key (stride of 2) in descending order (highest score first)
|
||||
sortList = llListSort(sortList, 2, FALSE);
|
||||
|
||||
// Clean up the format back to "Name:Wins:Losses" (skip padded wins in position 0)
|
||||
cleanedData = [];
|
||||
for (sortI = 0; sortI < llGetListLength(sortedLbData); sortI++) {
|
||||
sorted_entry = llList2String(sortedLbData, sortI);
|
||||
parts = llParseString2List(sorted_entry, [":"], []);
|
||||
if (llGetListLength(parts) >= 4) {
|
||||
// parts[0] = paddedWins (skip), parts[1] = name, parts[2] = actualWins, parts[3] = losses
|
||||
sortName = llList2String(parts, 1);
|
||||
winsStr = llList2String(parts, 2);
|
||||
lossesStr = llList2String(parts, 3);
|
||||
cleanedData += [sortName + ":" + winsStr + ":" + lossesStr];
|
||||
}
|
||||
// 3. Rebuild the leaderboard data in sorted order (Stided list: Name, Wins, Losses)
|
||||
for (i = 0; i < llGetListLength(sortList); i += 2) {
|
||||
origIdx = llList2Integer(sortList, i + 1);
|
||||
base = origIdx * 3;
|
||||
sortedData += [
|
||||
llList2String(leaderboardData, base),
|
||||
llList2Integer(leaderboardData, base + 1),
|
||||
llList2Integer(leaderboardData, base + 2)
|
||||
];
|
||||
}
|
||||
|
||||
return cleanedData;
|
||||
return sortedData;
|
||||
}
|
||||
|
||||
// Generate leaderboard text and send to separate leaderboard object
|
||||
integer generateLeaderboardText() {
|
||||
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)
|
||||
string title = "TOP BATTLE RECORDS";
|
||||
integer titleLen = llStringLength(title);
|
||||
integer titleMargin = (LEADERBOARD_WIDTH - titleLen) / 2;
|
||||
titleMargin = (LEADERBOARD_WIDTH - llStringLength(title)) / 2;
|
||||
if (titleMargin < 0) titleMargin = 0;
|
||||
|
||||
string titleSpaces = "";
|
||||
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;
|
||||
leaderboardText = llGetSubString(SPACES, 0, titleMargin - 1) + title + "\n";
|
||||
|
||||
// Add actual player data (up to MAX_LEADERBOARD_ENTRIES)
|
||||
for (genI = 0; genI < llGetListLength(sortedData) && genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
||||
playerData = llList2String(sortedData, genI);
|
||||
playerParts = llParseString2List(playerData, [":"], []);
|
||||
for (genI = 0; genI < numSorted && genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
||||
base = genI * 3;
|
||||
playerName = llList2String(sortedData, base);
|
||||
genWins = llList2Integer(sortedData, base + 1);
|
||||
genLosses = llList2Integer(sortedData, base + 2);
|
||||
|
||||
if (llGetListLength(playerParts) >= 3) {
|
||||
playerName = llList2String(playerParts, 0);
|
||||
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";
|
||||
if (llStringLength(playerName) > 12) {
|
||||
playerName = llGetSubString(playerName, 0, 9) + "...";
|
||||
}
|
||||
|
||||
// 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
|
||||
actualPlayers = llGetListLength(sortedData);
|
||||
for (genI = actualPlayers; genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
||||
rankNumber = genI + 1;
|
||||
rank = (string)rankNumber + ". ";
|
||||
if (rankNumber < 10) rank = "0" + rank;
|
||||
for (genI = numSorted; genI < MAX_LEADERBOARD_ENTRIES; genI++) {
|
||||
rank = (string)(genI + 1) + ". ";
|
||||
if (genI < 9) rank = "0" + rank;
|
||||
|
||||
// Use EXACT same formatting as players so columns align!
|
||||
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);
|
||||
if (spaceNeeded < 1) spaceNeeded = 1;
|
||||
|
||||
spacer = "";
|
||||
for (s = 0; s < spaceNeeded; s++) spacer += " ";
|
||||
|
||||
line = leftPart + spacer + rightPart;
|
||||
leaderboardText += line + "\n";
|
||||
leaderboardText += leftPart + llGetSubString(SPACES, 0, spaceNeeded - 1) + rightPart + "\n";
|
||||
}
|
||||
|
||||
// Send formatted text to leaderboard bridge
|
||||
|
|
@ -416,9 +357,7 @@ integer resetLeaderboard() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
leaderboardNames = [];
|
||||
leaderboardWins = [];
|
||||
leaderboardLosses = [];
|
||||
leaderboardData = [];
|
||||
pendingSerialize = "";
|
||||
kvpWriteReq = llUpdateKeyValue("Peril_LB_Top50", "", FALSE, "");
|
||||
generateLeaderboardText(); // Send empty leaderboard immediately
|
||||
|
|
@ -427,10 +366,7 @@ integer resetLeaderboard() {
|
|||
|
||||
// Clear all current players from the scoreboard
|
||||
integer clearAllPlayers() {
|
||||
// Clear ONLY current game player data lists (NOT leaderboard data)
|
||||
playerNames = [];
|
||||
playerLives = [];
|
||||
playerProfiles = [];
|
||||
activePlayers = [];
|
||||
|
||||
// Clear any pending HTTP requests
|
||||
httpRequests = [];
|
||||
|
|
@ -444,9 +380,9 @@ integer clearAllPlayers() {
|
|||
|
||||
// Reset all player prims to default state
|
||||
for (clearI = 0; clearI < 10; clearI++) {
|
||||
clearProfilePrimIndex = llList2Integer(profileLinks, clearI);
|
||||
clearHeartsPrimIndex = llList2Integer(heartsLinks, clearI);
|
||||
clearOverlayPrimIndex = llList2Integer(overlayLinks, clearI);
|
||||
clearProfilePrimIndex = getProfilePrimLink(clearI);
|
||||
clearHeartsPrimIndex = getHeartsPrimLink(clearI);
|
||||
clearOverlayPrimIndex = getOverlayPrimLink(clearI);
|
||||
|
||||
// SAFETY CHECK - use if block instead of continue for maximum compatibility
|
||||
if (clearProfilePrimIndex > 0) {
|
||||
|
|
@ -479,24 +415,17 @@ integer clearAllPlayers() {
|
|||
|
||||
// Remove a single player from the scoreboard display
|
||||
integer removePlayer(string playerName) {
|
||||
integer removeIdx = llListFindList(playerNames, [playerName]);
|
||||
if (removeIdx != -1) {
|
||||
// Remove player from internal lists
|
||||
playerNames = llDeleteSubList(playerNames, removeIdx, removeIdx);
|
||||
playerLives = llDeleteSubList(playerLives, removeIdx, removeIdx);
|
||||
playerProfiles = llDeleteSubList(playerProfiles, removeIdx, removeIdx);
|
||||
|
||||
// Refresh the entire display to shift remaining players up
|
||||
integer idx = llListFindList(activePlayers, [playerName]);
|
||||
if (idx != -1) {
|
||||
activePlayers = llDeleteSubList(activePlayers, idx, idx + 2);
|
||||
refreshPlayerDisplay();
|
||||
|
||||
dbg("📈 [Scoreboard Manager] 📊 Removed " + playerName + " from the scoreboard and shifted remaining players.");
|
||||
dbg("📈 Player removed: " + playerName);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Refresh the entire player display - shows all current players in order
|
||||
integer refreshPlayerDisplay() {
|
||||
integer numActivePlayers = llGetListLength(playerNames);
|
||||
integer numActivePlayers = llGetListLength(activePlayers) / 3;
|
||||
integer refreshI;
|
||||
integer refreshProfilePrimIndex = 0;
|
||||
integer refreshHeartsPrimIndex = 0;
|
||||
|
|
@ -512,9 +441,9 @@ integer refreshPlayerDisplay() {
|
|||
|
||||
// Only reset prims for unused slots (avoid flickering for active players)
|
||||
for (refreshI = numActivePlayers; refreshI < 10; refreshI++) {
|
||||
refreshProfilePrimIndex = llList2Integer(profileLinks, refreshI);
|
||||
refreshHeartsPrimIndex = llList2Integer(heartsLinks, refreshI);
|
||||
refreshOverlayPrimIndex = llList2Integer(overlayLinks, refreshI);
|
||||
refreshProfilePrimIndex = getProfilePrimLink(refreshI);
|
||||
refreshHeartsPrimIndex = getHeartsPrimLink(refreshI);
|
||||
refreshOverlayPrimIndex = getOverlayPrimLink(refreshI);
|
||||
|
||||
if (refreshProfilePrimIndex > 0) {
|
||||
// Reset to default only for unused slots
|
||||
|
|
@ -541,14 +470,15 @@ integer refreshPlayerDisplay() {
|
|||
|
||||
// Now display all current players in their new positions
|
||||
for (refreshI = 0; refreshI < numActivePlayers; refreshI++) {
|
||||
r_name = llList2String(playerNames, refreshI);
|
||||
r_lives = llList2Integer(playerLives, refreshI);
|
||||
r_profileTexture = llList2String(playerProfiles, refreshI);
|
||||
integer base = refreshI * 3;
|
||||
r_name = llList2String(activePlayers, base);
|
||||
r_lives = llList2Integer(activePlayers, base + 1);
|
||||
r_profileTexture = llList2String(activePlayers, base + 2);
|
||||
|
||||
// Calculate prim indices for this position
|
||||
r_profileIdx = llList2Integer(profileLinks, refreshI);
|
||||
r_heartsIdx = llList2Integer(heartsLinks, refreshI);
|
||||
r_overlayIdx = llList2Integer(overlayLinks, refreshI);
|
||||
r_profileIdx = getProfilePrimLink(refreshI);
|
||||
r_heartsIdx = getHeartsPrimLink(refreshI);
|
||||
r_overlayIdx = getOverlayPrimLink(refreshI);
|
||||
|
||||
if (r_profileIdx > 0) {
|
||||
// Determine profile texture to use
|
||||
|
|
@ -602,9 +532,9 @@ integer isBot(string playerName) {
|
|||
|
||||
// Map player index to profile prim link number
|
||||
// Functions relocated to avoid hardcoded math
|
||||
integer getProfilePrimLink(integer playerIndex) { return llList2Integer(profileLinks, playerIndex); }
|
||||
integer getHeartsPrimLink(integer playerIndex) { return llList2Integer(heartsLinks, playerIndex); }
|
||||
integer getOverlayPrimLink(integer playerIndex) { return llList2Integer(overlayLinks, playerIndex); }
|
||||
integer getProfilePrimLink(integer playerIndex) { return llList2Integer(gridLinks, playerIndex * 3); }
|
||||
integer getHeartsPrimLink(integer playerIndex) { return llList2Integer(gridLinks, (playerIndex * 3) + 1); }
|
||||
integer getOverlayPrimLink(integer playerIndex) { return llList2Integer(gridLinks, (playerIndex * 3) + 2); }
|
||||
|
||||
string getHeartTexture(integer lives) {
|
||||
if (lives <= 0) return TEXTURE_0_HEARTS;
|
||||
|
|
@ -613,84 +543,37 @@ string getHeartTexture(integer lives) {
|
|||
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)
|
||||
integer updatePlayerGlowEffects() {
|
||||
// First, remove glow and reset tint from all players
|
||||
integer numPlayers = llGetListLength(activePlayers) / 3;
|
||||
integer glowI;
|
||||
integer glowProfilePrimIndex;
|
||||
integer glowHeartsPrimIndex;
|
||||
|
||||
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
|
||||
]);
|
||||
}
|
||||
for (glowI = 0; glowI < numPlayers; glowI++) {
|
||||
setGlow(getProfilePrimLink(glowI), 0.0, <1,1,1>);
|
||||
setGlow(getHeartsPrimLink(glowI), 0.0, <1,1,1>);
|
||||
}
|
||||
|
||||
// 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") {
|
||||
integer winnerIndex = llListFindList(playerNames, [currentWinner]);
|
||||
if (winnerIndex != -1) {
|
||||
integer winnerProfilePrimIndex = getProfilePrimLink(winnerIndex);
|
||||
integer winnerHeartsPrimIndex = getHeartsPrimLink(winnerIndex);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
idx = llListFindList(activePlayers, [currentWinner]);
|
||||
if (idx != -1) { idx = idx / 3; col = <0,1,0>; glow = 0.3; }
|
||||
} else if (currentPerilPlayer != "" && currentPerilPlayer != "NONE") {
|
||||
idx = llListFindList(activePlayers, [currentPerilPlayer]);
|
||||
if (idx != -1) { idx = idx / 3; col = <1,1,0>; glow = 0.2; }
|
||||
}
|
||||
// Priority 2: Yellow glow for peril player (only if not the winner)
|
||||
else if (currentPerilPlayer != "" && currentPerilPlayer != "NONE") {
|
||||
integer perilIndex = llListFindList(playerNames, [currentPerilPlayer]);
|
||||
if (perilIndex != -1) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (idx != -1) {
|
||||
setGlow(getProfilePrimLink(idx), glow, col);
|
||||
setGlow(getHeartsPrimLink(idx), glow, col);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -703,26 +586,19 @@ integer updatePerilPlayerGlow() {
|
|||
|
||||
// Update player display on the grid
|
||||
integer updatePlayerDisplay(string playerName, integer lives, string profileUUID) {
|
||||
// Find existing player or add new one
|
||||
integer playerIndex = llListFindList(playerNames, [playerName]);
|
||||
integer playerIndex = llListFindList(activePlayers, [playerName]);
|
||||
if (playerIndex != -1) playerIndex = playerIndex / 3;
|
||||
|
||||
if (playerIndex == -1) {
|
||||
// New player - find next available slot
|
||||
playerIndex = llGetListLength(playerNames);
|
||||
playerIndex = llGetListLength(activePlayers) / 3;
|
||||
if (playerIndex >= 10) {
|
||||
dbg("📈 [Scoreboard Manager] ⚠️ WARNING: Maximum 10 players supported, ignoring: " + playerName);
|
||||
dbg("📈 MAX players reached: " + playerName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add to tracking lists
|
||||
playerNames += [playerName];
|
||||
playerLives += [lives];
|
||||
// For bots, always store the bot texture UUID to prevent HTTP requests
|
||||
if (isBot(playerName)) {
|
||||
playerProfiles += [TEXTURE_BOT_PROFILE];
|
||||
} else {
|
||||
playerProfiles += [profileUUID];
|
||||
}
|
||||
string activeUUID = profileUUID;
|
||||
if (isBot(playerName)) activeUUID = TEXTURE_BOT_PROFILE;
|
||||
activePlayers += [playerName, lives, activeUUID];
|
||||
|
||||
// DEBUG: Show prim mapping - DISABLED to save memory
|
||||
// if (VERBOSE_LOGGING) {
|
||||
|
|
@ -739,15 +615,13 @@ integer updatePlayerDisplay(string playerName, integer lives, string profileUUID
|
|||
// }
|
||||
|
||||
} else {
|
||||
// Update existing player
|
||||
playerLives = llListReplaceList(playerLives, [lives], playerIndex, playerIndex);
|
||||
// Don't overwrite cached profile texture with original UUID on updates
|
||||
activePlayers = llListReplaceList(activePlayers, [lives], (playerIndex * 3) + 1, (playerIndex * 3) + 1);
|
||||
}
|
||||
|
||||
// Update the physical prims for this player
|
||||
integer updateProfilePrimIndex = llList2Integer(profileLinks, playerIndex);
|
||||
integer updateHeartsPrimIndex = llList2Integer(heartsLinks, playerIndex);
|
||||
integer updateOverlayPrimIndex = llList2Integer(overlayLinks, playerIndex);
|
||||
integer updateProfilePrimIndex = getProfilePrimLink(playerIndex);
|
||||
integer updateHeartsPrimIndex = getHeartsPrimLink(playerIndex);
|
||||
integer updateOverlayPrimIndex = getOverlayPrimLink(playerIndex);
|
||||
|
||||
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
|
||||
if (isBot(playerName)) {
|
||||
updateProfileTexture = TEXTURE_BOT_PROFILE;
|
||||
} else if (playerIndex < llGetListLength(playerProfiles)) {
|
||||
string updateCachedTexture = llList2String(playerProfiles, playerIndex);
|
||||
} else {
|
||||
string updateCachedTexture = llList2String(activePlayers, (playerIndex * 3) + 2);
|
||||
if (updateCachedTexture != "" && updateCachedTexture != profileUUID &&
|
||||
updateCachedTexture != TEXTURE_DEFAULT_PROFILE && updateCachedTexture != TEXTURE_BOT_PROFILE &&
|
||||
updateCachedTexture != TEXTURE_ELIMINATED_X) {
|
||||
// We have a previously fetched profile picture, use it
|
||||
updateProfileTexture = updateCachedTexture;
|
||||
} else {
|
||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
||||
}
|
||||
} else {
|
||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
||||
}
|
||||
} else {
|
||||
// Player is alive - determine profile texture to use
|
||||
updateProfileTexture = profileUUID;
|
||||
|
||||
// Check if we already have a cached profile texture for this player
|
||||
if (playerIndex < llGetListLength(playerProfiles)) {
|
||||
string liveCachedTexture = llList2String(playerProfiles, playerIndex);
|
||||
if (liveCachedTexture != "" && liveCachedTexture != profileUUID &&
|
||||
liveCachedTexture != TEXTURE_DEFAULT_PROFILE && liveCachedTexture != TEXTURE_BOT_PROFILE &&
|
||||
liveCachedTexture != TEXTURE_ELIMINATED_X) {
|
||||
// We have a previously fetched profile picture, use it
|
||||
updateProfileTexture = liveCachedTexture;
|
||||
}
|
||||
string liveCachedTexture = llList2String(activePlayers, (playerIndex * 3) + 2);
|
||||
if (liveCachedTexture != "" && liveCachedTexture != profileUUID &&
|
||||
liveCachedTexture != TEXTURE_DEFAULT_PROFILE && liveCachedTexture != TEXTURE_BOT_PROFILE &&
|
||||
liveCachedTexture != TEXTURE_ELIMINATED_X) {
|
||||
updateProfileTexture = liveCachedTexture;
|
||||
}
|
||||
|
||||
// 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") {
|
||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
||||
dbg("📈 [Scoreboard Manager] ❓ [DEBUG] " + playerName + " has empty/null UUID, using default texture");
|
||||
dbg("Default texture");
|
||||
} else {
|
||||
// CRITICAL: Set default texture FIRST, then request profile picture
|
||||
updateProfileTexture = TEXTURE_DEFAULT_PROFILE;
|
||||
|
|
@ -817,10 +685,6 @@ integer updatePlayerDisplay(string playerName, integer lives, string profileUUID
|
|||
|
||||
// Store the HTTP request mapping: requestID -> 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() {
|
||||
discoverLinks();
|
||||
llListen(1, "", llGetOwner(), "");
|
||||
reportMemoryUsage("Scoreboard Manager");
|
||||
dbg("📈 [Scoreboard Manager] 📈 Managing profile and heart prims via dynamic discovery.");
|
||||
|
||||
// Initialize profile picture extraction constants
|
||||
profile_key_prefix_length = llStringLength(profile_key_prefix);
|
||||
profile_img_prefix_length = llStringLength(profile_img_prefix);
|
||||
REPORT_MEMORY();
|
||||
dbg("Ready");
|
||||
|
||||
// Reset background prim to proper state
|
||||
resetBackgroundPrim();
|
||||
|
|
@ -916,8 +776,7 @@ default {
|
|||
currentWinner = "";
|
||||
updatePlayerGlowEffects();
|
||||
|
||||
dbg("📈 [Scoreboard Manager] ✅ Linkset communication active - no discovery needed!");
|
||||
dbg("📈 [Scoreboard Manager] 📊 Loaded " + (string)llGetListLength(leaderboardNames) + " players from leaderboard data");
|
||||
dbg("Init complete");
|
||||
}
|
||||
|
||||
link_message(integer sender, integer num, string str, key id) {
|
||||
|
|
@ -935,7 +794,7 @@ default {
|
|||
string profileUUID = llList2String(parts, 2);
|
||||
|
||||
// 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);
|
||||
|
|
@ -975,7 +834,7 @@ default {
|
|||
currentPerilPlayer = "";
|
||||
}
|
||||
|
||||
dbg("📈 [Scoreboard Manager] 🎯 Peril player changed from '" + oldPeril + "' to '" + currentPerilPlayer + "'");
|
||||
dbg("Peril: " + currentPerilPlayer);
|
||||
|
||||
// Update glow effects
|
||||
updatePlayerGlowEffects();
|
||||
|
|
@ -988,7 +847,7 @@ default {
|
|||
currentWinner = "";
|
||||
}
|
||||
|
||||
dbg("📈 [Scoreboard Manager] 🏆 Winner changed from '" + oldWinner + "' to '" + currentWinner + "'");
|
||||
dbg("Winner: " + currentWinner);
|
||||
|
||||
// Update glow effects - winner glow overrides peril glow
|
||||
updatePlayerGlowEffects();
|
||||
|
|
@ -1004,14 +863,14 @@ default {
|
|||
// Remove this request from tracking
|
||||
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
|
||||
string profileUUID = "";
|
||||
|
||||
// Try the meta tag method first
|
||||
integer metaStart = llSubStringIndex(body, profile_key_prefix);
|
||||
integer metaStart = llSubStringIndex(body, PROFILE_KEY_PREFIX);
|
||||
if (metaStart != -1) {
|
||||
metaStart += profile_key_prefix_length;
|
||||
metaStart += PROFILE_KEY_PREFIX_LENGTH;
|
||||
string remainingBody = llGetSubString(body, metaStart, -1);
|
||||
integer metaEnd = llSubStringIndex(remainingBody, "\"");
|
||||
if (metaEnd != -1) {
|
||||
|
|
@ -1021,9 +880,9 @@ default {
|
|||
|
||||
// If meta tag failed, try img src method
|
||||
if (profileUUID == "") {
|
||||
integer imgStart = llSubStringIndex(body, profile_img_prefix);
|
||||
integer imgStart = llSubStringIndex(body, PROFILE_IMG_PREFIX);
|
||||
if (imgStart != -1) {
|
||||
imgStart += profile_img_prefix_length;
|
||||
imgStart += PROFILE_IMG_PREFIX_LENGTH;
|
||||
string remainingBody = llGetSubString(body, imgStart, -1);
|
||||
integer imgEnd = llSubStringIndex(remainingBody, "/");
|
||||
if (imgEnd != -1) {
|
||||
|
|
@ -1034,8 +893,8 @@ default {
|
|||
|
||||
// If we got a valid UUID, update the profile prim and cache it
|
||||
if (profileUUID != "" && profileUUID != "00000000-0000-0000-0000-000000000000") {
|
||||
// Update the cached profile texture
|
||||
playerProfiles = llListReplaceList(playerProfiles, [profileUUID], playerIndex, playerIndex);
|
||||
// Update the cached profile texture in stride
|
||||
activePlayers = llListReplaceList(activePlayers, [profileUUID], (playerIndex * 3) + 2, (playerIndex * 3) + 2);
|
||||
|
||||
// Update the physical prim using correct mapping
|
||||
integer profilePrimIndex = getProfilePrimLink(playerIndex);
|
||||
|
|
@ -1055,10 +914,10 @@ default {
|
|||
PRIM_GLOW, ALL_SIDES, 0.0 // Remove glow
|
||||
]);
|
||||
|
||||
string playerName = llList2String(playerNames, playerIndex);
|
||||
dbg("📈 [Scoreboard Manager] 🖼️ Updated profile picture for " + playerName + " on prim " + (string)profilePrimIndex + " with forced refresh");
|
||||
string playerName = llList2String(activePlayers, playerIndex * 3);
|
||||
dbg("Profile updated: " + playerName);
|
||||
} 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);
|
||||
|
||||
if (status == "1") {
|
||||
leaderboardNames = [];
|
||||
leaderboardWins = [];
|
||||
leaderboardLosses = [];
|
||||
leaderboardData = [];
|
||||
|
||||
list entries = llParseString2List(val, ["|"], []);
|
||||
integer i;
|
||||
|
|
@ -1084,19 +941,19 @@ default {
|
|||
string data_entry = llList2String(entries, i);
|
||||
list parts = llParseString2List(data_entry, [":"], []);
|
||||
if (llGetListLength(parts) >= 3) {
|
||||
leaderboardNames += [llList2String(parts, 0)];
|
||||
leaderboardWins += [(integer)llList2String(parts, 1)];
|
||||
leaderboardLosses += [(integer)llList2String(parts, 2)];
|
||||
leaderboardData += [
|
||||
llList2String(parts, 0),
|
||||
(integer)llList2String(parts, 1),
|
||||
(integer)llList2String(parts, 2)
|
||||
];
|
||||
}
|
||||
}
|
||||
dbg("📈 [Scoreboard Manager] ✅ Loaded global scoreboard containing " + (string)llGetListLength(leaderboardNames) + " players!");
|
||||
} else if (status == "3") { // XP_ERROR_KEY_NOT_FOUND
|
||||
leaderboardNames = [];
|
||||
leaderboardWins = [];
|
||||
leaderboardLosses = [];
|
||||
dbg("📈 [Scoreboard Manager] ℹ️ Global scoreboard is currently empty (database fresh).");
|
||||
dbg("LB Loaded");
|
||||
} else if (status == "3") {
|
||||
leaderboardData = [];
|
||||
dbg("LB Empty");
|
||||
} else {
|
||||
dbg("📈 [Scoreboard Manager] ⚠️ Failed to load global scoreboard (Status: " + status + ")");
|
||||
dbg("LB Error: " + status);
|
||||
}
|
||||
}
|
||||
// Generate board with downloaded or empty data
|
||||
|
|
@ -1108,8 +965,8 @@ default {
|
|||
if (status == "3") {
|
||||
// Update failed because key didn't exist yet! Create it.
|
||||
llCreateKeyValue("Peril_LB_Top50", pendingSerialize);
|
||||
} else if (status == "1") {
|
||||
dbg("📈 [Scoreboard Manager] ✅ Global scoreboard synced successfully.");
|
||||
dbg("LB Saved");
|
||||
pendingSerialize = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1117,7 +974,7 @@ default {
|
|||
|
||||
|
||||
timer() {
|
||||
dbg("📈 [Scoreboard Manager] ⏱️ Auto-refreshing Global Scoreboard Data...");
|
||||
dbg("Timer");
|
||||
loadLeaderboardData();
|
||||
}
|
||||
|
||||
|
|
@ -1138,7 +995,6 @@ default {
|
|||
}
|
||||
}
|
||||
else if (msg == "clearx") {
|
||||
dbg("Refreshing display to clear test X overlays...");
|
||||
refreshPlayerDisplay();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ resetGame() {
|
|||
default {
|
||||
state_entry() {
|
||||
DISCOVER_CORE_LINKS();
|
||||
reportMemoryUsage("Main Controller");
|
||||
REPORT_MEMORY();
|
||||
dbg("🎮 Main Controller ready! (Discovery Mode)");
|
||||
|
||||
// Initialize lockout system
|
||||
|
|
@ -317,7 +317,7 @@ default {
|
|||
|
||||
on_rez(integer start_param) {
|
||||
DISCOVER_CORE_LINKS();
|
||||
reportMemoryUsage("Main Controller");
|
||||
REPORT_MEMORY();
|
||||
dbg("🔄 Main Controller reset via rez...");
|
||||
|
||||
// Re-initialize lockout system
|
||||
|
|
@ -473,14 +473,6 @@ default {
|
|||
link_message(integer sender, integer num, string str, key id) {
|
||||
// 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
|
||||
if (num == MSG_UPDATE_MAIN_LISTS) { // MSG_UPDATE_MAIN_LISTS
|
||||
// ULTRA-OPTIMIZED: Player_RegistrationManager now handles all heavy processing
|
||||
|
|
|
|||
|
|
@ -56,18 +56,6 @@ list globallyPickedNumbers = []; // Numbers already picked by other players
|
|||
integer currentPage = 0;
|
||||
#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) {
|
||||
// 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 {
|
||||
state_entry() {
|
||||
reportMemoryUsage("🎮 NumberPicker Dialog");
|
||||
REPORT_MEMORY();
|
||||
|
||||
// Initialize dynamic channels
|
||||
initializeChannels();
|
||||
|
|
@ -203,7 +191,7 @@ default {
|
|||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
reportMemoryUsage("🎮 NumberPicker Dialog");
|
||||
REPORT_MEMORY();
|
||||
|
||||
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"
|
||||
|
||||
// --- 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
|
||||
#define dbg(msg) llOwnerSay(msg)
|
||||
#else
|
||||
|
|
@ -113,6 +113,17 @@ integer LINK_LEADERBOARD_BRIDGE = -1; // "FURWARE text mesh:Leaderboard:0:0"
|
|||
#define MSG_QUERY_OWNER_STATUS 213
|
||||
|
||||
// --- 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_STATS 6002
|
||||
#define MSG_MEMORY_CLEANUP 6003
|
||||
|
|
|
|||
|
|
@ -7,31 +7,18 @@ string displayText;
|
|||
string myName;
|
||||
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 {
|
||||
state_entry() {
|
||||
REPORT_MEMORY();
|
||||
string currentDesc = llGetObjectDesc();
|
||||
if (currentDesc == "" || currentDesc == "(No Description)") currentDesc = "Unknown";
|
||||
|
||||
reportMemoryUsage("📱 Player Float (" + currentDesc + ")");
|
||||
|
||||
llSetText("⏳ Waiting...", <1,1,1>, 1.0);
|
||||
llSetTimerEvent(1.0);
|
||||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
REPORT_MEMORY();
|
||||
if (listenHandle != -1) llListenRemove(listenHandle);
|
||||
listenHandle = llListen(start_param, "", NULL_KEY, "");
|
||||
myName = "";
|
||||
|
|
@ -83,7 +70,6 @@ default {
|
|||
else if (llSubStringIndex(message, "SET_NAME:") == 0) {
|
||||
myName = llGetSubString(message, 9, -1);
|
||||
llSetObjectDesc(myName);
|
||||
reportMemoryUsage("📱 " + myName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,18 +99,6 @@ float pendingMenuTimestamp = 0.0; // Timeout for pending requests
|
|||
integer isLocked = FALSE;
|
||||
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
|
||||
showOwnerMenu(key id) {
|
||||
|
|
@ -313,7 +301,7 @@ showUnregisteredOwnerMenu(key id, integer canStartGame) {
|
|||
|
||||
default {
|
||||
state_entry() {
|
||||
reportMemoryUsage("🎭 Player Dialog");
|
||||
REPORT_MEMORY();
|
||||
|
||||
// Initialize dynamic channels
|
||||
initializeChannels();
|
||||
|
|
@ -356,7 +344,7 @@ default {
|
|||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
reportMemoryUsage("🎭 Player Dialog");
|
||||
REPORT_MEMORY();
|
||||
|
||||
dbg("🔄 Player Dialog Handler rezzed - reinitializing...");
|
||||
|
||||
|
|
|
|||
|
|
@ -10,23 +10,29 @@ list names = [];
|
|||
list lives = [];
|
||||
list readyPlayers = [];
|
||||
#define MAX_PLAYERS 10
|
||||
#define FLOATER_BASE_CHANNEL -86000
|
||||
|
||||
// Dynamic channel system
|
||||
#define CHANNEL_BASE -77000
|
||||
integer FLOATER_BASE_CHANNEL;
|
||||
integer roundStarted = FALSE;
|
||||
integer gameStarting = 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)");
|
||||
integer calculateChannel(integer offset) {
|
||||
string ownerStr = (string)llGetOwner();
|
||||
string objectStr = (string)llGetLinkKey(1);
|
||||
string combinedStr = ownerStr + objectStr;
|
||||
string hashStr = llMD5String(combinedStr, 0);
|
||||
integer hash1 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 0, 0));
|
||||
integer hash2 = llSubStringIndex("0123456789abcdef", llGetSubString(hashStr, 1, 1));
|
||||
integer combinedHash = hash1 * 16 + hash2;
|
||||
return CHANNEL_BASE - (offset * 1000) - combinedHash;
|
||||
}
|
||||
|
||||
initializeChannels() {
|
||||
FLOATER_BASE_CHANNEL = calculateChannel(9);
|
||||
}
|
||||
|
||||
|
||||
// Helper functions
|
||||
string getPlayerName(key id) {
|
||||
string displayName = llGetDisplayName(id);
|
||||
|
|
@ -134,12 +140,12 @@ handlePlayerRegistration(string regData, key requesterId) {
|
|||
syncMessage = livesStr + "~EMPTY~NONE~" + llList2CSV(names);
|
||||
}
|
||||
|
||||
// Send pre-built sync message
|
||||
llMessageLinked(LINK_SET, MSG_SYNC_GAME_STATE, syncMessage, NULL_KEY);
|
||||
|
||||
// CRITICAL FIX: Send floater rez message to Floater Manager
|
||||
// CRITICAL FIX: Send floater rez message to Floater Manager first
|
||||
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
|
||||
string updateData = (string)ch + "~" + newName;
|
||||
llMessageLinked(LINK_SET, MSG_UPDATE_MAIN_LISTS, updateData, newKey);
|
||||
|
|
@ -156,11 +162,15 @@ handlePlayerRegistration(string regData, key requesterId) {
|
|||
default {
|
||||
state_entry() {
|
||||
DISCOVER_CORE_LINKS();
|
||||
initializeChannels();
|
||||
REPORT_MEMORY();
|
||||
dbg("🎯 [RegMgr] Player Registration Manager ready - discovery complete! Scoreboard: " + (string)LINK_SCOREBOARD);
|
||||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
DISCOVER_CORE_LINKS();
|
||||
initializeChannels();
|
||||
REPORT_MEMORY();
|
||||
dbg("🎯 [RegMgr] Player Registration Manager rezzed - resetting state...");
|
||||
// Reset local state
|
||||
players = [];
|
||||
|
|
|
|||
|
|
@ -60,18 +60,6 @@ integer lastRollTime = 0; // Track when last roll happened
|
|||
integer diceTypeProcessed = FALSE; // Confetti particle system for winner celebrations
|
||||
#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) {
|
||||
integer i;
|
||||
|
|
@ -131,9 +119,13 @@ confetti() {
|
|||
default {
|
||||
state_entry() {
|
||||
DISCOVER_CORE_LINKS();
|
||||
reportMemoryUsage("Roll Module");
|
||||
REPORT_MEMORY();
|
||||
dbg("🎲 [Roll Module] ready - discovery complete! Bridge: " + (string)LINK_DICE_BRIDGE);
|
||||
|
||||
// Re-initialize dynamic channels
|
||||
initializeChannels();
|
||||
rollDialogChannel = ROLLDIALOG_CHANNEL;
|
||||
|
||||
// Clean up any existing listeners
|
||||
if (listenHandle != -1) {
|
||||
llListenRemove(listenHandle);
|
||||
|
|
@ -157,7 +149,7 @@ default {
|
|||
|
||||
on_rez(integer start_param) {
|
||||
DISCOVER_CORE_LINKS();
|
||||
reportMemoryUsage("Roll Module");
|
||||
REPORT_MEMORY();
|
||||
dbg("🎲 [Roll Module] reset via rez...");
|
||||
|
||||
// Re-initialize dynamic channels
|
||||
|
|
|
|||
|
|
@ -69,9 +69,14 @@ list validatePicksData(list picksData, list names) {
|
|||
|
||||
default {
|
||||
state_entry() {
|
||||
REPORT_MEMORY();
|
||||
dbg("🔍 [System Debugger] 🔍 System Debugger ready!");
|
||||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
REPORT_MEMORY();
|
||||
}
|
||||
|
||||
link_message(integer sender, integer num, string str, key id) {
|
||||
|
||||
// Handle legacy verbose logging toggle (OBSELETE)
|
||||
|
|
|
|||
Loading…
Reference in a new issue