fix bug
This commit is contained in:
parent
abb4fe34c7
commit
bc15d84b55
4 changed files with 265 additions and 560 deletions
|
|
@ -1,49 +1,66 @@
|
|||
// ====================================================================
|
||||
// Peril Dice GitHub Updater - External Updater Box
|
||||
// Peril Dice Updater - External Update Box
|
||||
// ====================================================================
|
||||
// This script goes in a separate updater box object that users rez temporarily.
|
||||
// Downloads scripts directly from GitHub and installs them automatically
|
||||
// in target Peril Dice games via llRemoteLoadScriptPin().
|
||||
//
|
||||
// USAGE:
|
||||
// 1. User rezzes this updater box near their Peril Dice game
|
||||
// 2. User touches their game -> "Check for Updates" -> "Install Update"
|
||||
// 3. Game communicates with this updater box for automatic installation
|
||||
// 4. User deletes updater box when finished
|
||||
// This script goes in a standalone object (the "Updater Box")
|
||||
// It downloads scripts from GitHub and installs them into the game
|
||||
// ====================================================================
|
||||
|
||||
string GITHUB_MANIFEST_URL = "https://raw.githubusercontent.com/RebeccaNod1/Peril/main/peril-dice-manifest.json";
|
||||
string UPDATER_VERSION = "2.8.8";
|
||||
string CURRENT_VERSION = "2.8.8";
|
||||
string GITHUB_API_URL = "https://api.github.com/repos/RebeccaNod1/Peril/releases/latest";
|
||||
string GITHUB_RAW_URL = "https://raw.githubusercontent.com/RebeccaNod1/Peril/main/";
|
||||
|
||||
// Communication channels
|
||||
integer UPDATER_CHANNEL = -7723847; // Unique channel for updater communication
|
||||
integer RESPONSE_TIMEOUT = 30; // seconds
|
||||
integer UPDATER_CHANNEL = -7723847; // Must match Update_Receiver.lsl
|
||||
|
||||
// Current operation state
|
||||
string currentOperation = "";
|
||||
key targetGameKey = NULL_KEY;
|
||||
integer updatePin = 0;
|
||||
list scriptQueue = [];
|
||||
integer currentScriptIndex = 0;
|
||||
string manifestData = "";
|
||||
// State tracking
|
||||
key targetGame = NULL_KEY;
|
||||
integer targetPin = 0;
|
||||
list downloadQueue = [];
|
||||
string currentFile = "";
|
||||
integer installIndex = 0;
|
||||
integer isBusy = FALSE;
|
||||
|
||||
// HTTP tracking
|
||||
key currentHttpRequest = NULL_KEY;
|
||||
string downloadingScript = "";
|
||||
string currentOperation = "";
|
||||
|
||||
// UI and status
|
||||
integer isListening = FALSE;
|
||||
// Script manifest - List of all scripts to update
|
||||
// Format: "ScriptName.lsl|LinkNumber"
|
||||
// Note: Link numbers will be verified via UUID request
|
||||
list SCRIPT_MANIFEST = [
|
||||
"Main_Controller_Linkset.lsl|1",
|
||||
"Game_Manager.lsl|1",
|
||||
"Controller_Memory.lsl|1",
|
||||
"Controller_MessageHandler.lsl|1",
|
||||
"Player_RegistrationManager.lsl|1",
|
||||
"Player_DialogHandler.lsl|1",
|
||||
"NumberPicker_DialogHandler.lsl|1",
|
||||
"Floater_Manager.lsl|1",
|
||||
"Roll_ConfettiModule.lsl|1",
|
||||
"Bot_Manager.lsl|1",
|
||||
"Game_Calculator.lsl|1",
|
||||
"Verbose_Logger.lsl|1",
|
||||
"System_Debugger.lsl|1",
|
||||
"Update_Receiver.lsl|1", // Updates the receiver itself!
|
||||
"Game_Scoreboard_Manager_Linkset.lsl|12",
|
||||
"Leaderboard_Communication_Linkset.lsl|35",
|
||||
"XyzzyText_Dice_Bridge_Linkset.lsl|83",
|
||||
"xyzzy_Master_script.lsl|XYZZY" // Special handling for xyzzy
|
||||
];
|
||||
|
||||
// Memory usage reporting
|
||||
reportMemoryUsage(string scriptName) {
|
||||
integer memory = llGetUsedMemory();
|
||||
integer freeMemory = llGetFreeMemory();
|
||||
float memoryPercent = (float)memory / (memory + freeMemory) * 100.0;
|
||||
llOwnerSay("📊 " + scriptName + ": " + (string)memory + " bytes used (" +
|
||||
llGetSubString((string)memoryPercent, 0, 4) + "% memory)");
|
||||
// Map of Link Number -> UUID (populated by game response)
|
||||
list linkUUIDs = []; // Format: [LinkNum, UUID, LinkNum, UUID...]
|
||||
|
||||
// Helper to get UUID for a link number
|
||||
key getLinkUUID(integer linkNum) {
|
||||
integer idx = llListFindList(linkUUIDs, [linkNum]);
|
||||
if (idx != -1) {
|
||||
return llList2Key(linkUUIDs, idx + 1);
|
||||
}
|
||||
return NULL_KEY;
|
||||
}
|
||||
|
||||
// Extract JSON value manually (works around LSL 2048-char limit)
|
||||
// Manual JSON parsing (same as receiver)
|
||||
string extractJsonValue(string json, string keyName) {
|
||||
string quote = "\"";
|
||||
string searchPattern = quote + keyName + quote + ":" + quote;
|
||||
|
|
@ -57,221 +74,208 @@ string extractJsonValue(string json, string keyName) {
|
|||
return llGetSubString(json, valueStart, valueStart + valueEnd - 1);
|
||||
}
|
||||
|
||||
// Parse script list from manifest (simplified for LSL limitations)
|
||||
list parseScriptList(string manifest) {
|
||||
list scripts = [];
|
||||
// This is a simplified parser - in production might need more robust parsing
|
||||
// For now, we'll use the script URLs directly
|
||||
|
||||
// Add all essential scripts in priority order (URLs keep .lsl, but script names don't)
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Main_Controller_Linkset.lsl|1|Main_Controller_Linkset"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Game_Manager.lsl|1|Game_Manager"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Controller_Memory.lsl|1|Controller_Memory"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Controller_MessageHandler.lsl|1|Controller_MessageHandler"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Player_RegistrationManager.lsl|1|Player_RegistrationManager"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Player_DialogHandler.lsl|1|Player_DialogHandler"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/NumberPicker_DialogHandler.lsl|1|NumberPicker_DialogHandler"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Floater_Manager.lsl|1|Floater_Manager"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Roll_ConfettiModule.lsl|1|Roll_ConfettiModule"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Bot_Manager.lsl|1|Bot_Manager"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Game_Calculator.lsl|1|Game_Calculator"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Verbose_Logger.lsl|1|Verbose_Logger"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/System_Debugger.lsl|1|System_Debugger"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Update_Receiver.lsl|1|Update_Receiver"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Game_Scoreboard_Manager_Linkset.lsl|12|Game_Scoreboard_Manager_Linkset"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/Leaderboard_Communication_Linkset.lsl|35|Leaderboard_Communication_Linkset"];
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/XyzzyText_Dice_Bridge_Linkset.lsl|83|XyzzyText_Dice_Bridge_Linkset"];
|
||||
|
||||
// Add XyzzyText script for links 35-82 (48 prims)
|
||||
integer i;
|
||||
for (i = 35; i <= 82; i++) {
|
||||
scripts += ["https://raw.githubusercontent.com/RebeccaNod1/Peril/main/xyzzy_Master_script.lsl|" + (string)i + "|xyzzy_Master_script"];
|
||||
}
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
// Start update process
|
||||
startUpdate(key gameKey, integer pin) {
|
||||
targetGameKey = gameKey;
|
||||
updatePin = pin;
|
||||
currentOperation = "updating";
|
||||
currentScriptIndex = 0;
|
||||
|
||||
// Get script list (simplified - using hardcoded list for now)
|
||||
scriptQueue = parseScriptList("");
|
||||
|
||||
llOwnerSay("🔄 Starting update process...");
|
||||
llOwnerSay("📊 Installing " + (string)llGetListLength(scriptQueue) + " scripts");
|
||||
|
||||
// Start with first script
|
||||
downloadNextScript();
|
||||
}
|
||||
|
||||
// Download next script in queue
|
||||
downloadNextScript() {
|
||||
if (currentScriptIndex >= llGetListLength(scriptQueue)) {
|
||||
// Update complete!
|
||||
completeUpdate();
|
||||
// Start the update process for a specific game
|
||||
startUpdate(key gameId, string version, integer pin) {
|
||||
if (isBusy) {
|
||||
llRegionSayTo(gameId, UPDATER_CHANNEL, "UPDATE_BUSY");
|
||||
return;
|
||||
}
|
||||
|
||||
string scriptEntry = llList2String(scriptQueue, currentScriptIndex);
|
||||
list parts = llParseString2List(scriptEntry, ["|"], []);
|
||||
string url = llList2String(parts, 0);
|
||||
string linkNum = llList2String(parts, 1);
|
||||
string scriptName = llList2String(parts, 2); // Now using explicit script name
|
||||
isBusy = TRUE;
|
||||
targetGame = gameId;
|
||||
targetPin = pin;
|
||||
|
||||
downloadingScript = scriptName;
|
||||
llOwnerSay("🚀 Starting update for game " + (string)gameId);
|
||||
llRegionSayTo(targetGame, UPDATER_CHANNEL, "UPDATE_STARTING|" + version);
|
||||
|
||||
llOwnerSay("📥 Downloading " + scriptName + " for link " + linkNum +
|
||||
" (" + (string)(currentScriptIndex + 1) + "/" + (string)llGetListLength(scriptQueue) + ")");
|
||||
// Step 1: Request Link UUIDs from the game
|
||||
// We need these to install scripts to specific links
|
||||
llRegionSayTo(targetGame, UPDATER_CHANNEL, "REQUEST_LINK_UUIDS");
|
||||
|
||||
// Set timeout for UUID response
|
||||
llSetTimerEvent(10.0);
|
||||
}
|
||||
|
||||
// Continue update after getting UUIDs
|
||||
startDownloadSequence() {
|
||||
installIndex = 0;
|
||||
downloadNextScript();
|
||||
}
|
||||
|
||||
downloadNextScript() {
|
||||
if (installIndex >= llGetListLength(SCRIPT_MANIFEST)) {
|
||||
// All done!
|
||||
finishUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
string entry = llList2String(SCRIPT_MANIFEST, installIndex);
|
||||
list parts = llParseString2List(entry, ["|"], []);
|
||||
currentFile = llList2String(parts, 0);
|
||||
string linkTarget = llList2String(parts, 1);
|
||||
|
||||
llOwnerSay("📥 Downloading " + currentFile + "...");
|
||||
|
||||
string url = GITHUB_RAW_URL + currentFile;
|
||||
currentOperation = "download_script";
|
||||
currentHttpRequest = llHTTPRequest(url, [HTTP_METHOD, "GET"], "");
|
||||
}
|
||||
|
||||
// EMERGENCY SAFE MODE - Only add new scripts, don't delete anything
|
||||
installScript(string scriptContent, string scriptName, integer linkNumber) {
|
||||
llOwnerSay("🆘 SAFE MODE: Adding " + scriptName + " as new script");
|
||||
llOwnerSay("📊 Size: " + (string)llStringLength(scriptContent) + " characters");
|
||||
installScript(string content) {
|
||||
string scriptEntry = llList2String(SCRIPT_MANIFEST, installIndex);
|
||||
list scriptParts = llParseString2List(scriptEntry, ["|"], []);
|
||||
string filename = llList2String(scriptParts, 0);
|
||||
string linkTargetStr = llList2String(scriptParts, 1);
|
||||
|
||||
// Only create new script - DO NOT DELETE ANYTHING
|
||||
// This creates a script with auto-generated name containing the new content
|
||||
llRemoteLoadScriptPin(targetGameKey, scriptContent, updatePin, TRUE, 0);
|
||||
llOwnerSay("💾 Installing " + filename + "...");
|
||||
|
||||
llOwnerSay("✅ Added new script with updated content");
|
||||
llOwnerSay("📝 You can now copy content from the new script to replace your old " + scriptName);
|
||||
// Determine target UUIDs
|
||||
list targets = [];
|
||||
key targetUUID;
|
||||
|
||||
// Move to next script
|
||||
currentScriptIndex++;
|
||||
llSetTimerEvent(2.0);
|
||||
}
|
||||
|
||||
// Complete the update process
|
||||
completeUpdate() {
|
||||
llOwnerSay("🎉 Update installation complete!");
|
||||
llOwnerSay("📊 Installed " + (string)llGetListLength(scriptQueue) + " scripts successfully");
|
||||
|
||||
// Notify target game
|
||||
if (targetGameKey != NULL_KEY) {
|
||||
llRegionSayTo(targetGameKey, UPDATER_CHANNEL, "UPDATE_COMPLETE|" + UPDATER_VERSION);
|
||||
if (linkTargetStr == "XYZZY") {
|
||||
// Install to all xyzzy prims (links 35-82)
|
||||
integer i;
|
||||
for (i = 35; i <= 82; i++) {
|
||||
targetUUID = getLinkUUID(i);
|
||||
if (targetUUID != NULL_KEY) targets += [targetUUID];
|
||||
}
|
||||
} else {
|
||||
integer linkNum = (integer)linkTargetStr;
|
||||
if (linkNum == 1) {
|
||||
targets = [targetGame]; // Root prim is the game object itself
|
||||
} else {
|
||||
targetUUID = getLinkUUID(linkNum);
|
||||
if (targetUUID != NULL_KEY) targets += [targetUUID];
|
||||
}
|
||||
}
|
||||
|
||||
// Reset state
|
||||
currentOperation = "";
|
||||
targetGameKey = NULL_KEY;
|
||||
updatePin = 0;
|
||||
scriptQueue = [];
|
||||
currentScriptIndex = 0;
|
||||
|
||||
llOwnerSay("💡 Update complete! You can now delete this updater box.");
|
||||
}
|
||||
|
||||
// Handle update errors
|
||||
handleUpdateError(string error) {
|
||||
llOwnerSay("❌ Update failed: " + error);
|
||||
|
||||
// Notify target game of failure
|
||||
if (targetGameKey != NULL_KEY) {
|
||||
llRegionSayTo(targetGameKey, UPDATER_CHANNEL, "UPDATE_FAILED|" + error);
|
||||
if (llGetListLength(targets) == 0) {
|
||||
llOwnerSay("⚠️ No valid targets found for " + filename + " (Target: " + linkTargetStr + ")");
|
||||
// Skip but continue
|
||||
installIndex++;
|
||||
downloadNextScript();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset state
|
||||
currentOperation = "";
|
||||
targetGameKey = NULL_KEY;
|
||||
updatePin = 0;
|
||||
scriptQueue = [];
|
||||
currentScriptIndex = 0;
|
||||
// Install to all targets
|
||||
integer t;
|
||||
for (t = 0; t < llGetListLength(targets); t++) {
|
||||
key target = llList2Key(targets, t);
|
||||
llRemoteLoadScriptPin(target, filename, targetPin, TRUE, 0);
|
||||
}
|
||||
|
||||
// Move to next
|
||||
installIndex++;
|
||||
downloadNextScript();
|
||||
}
|
||||
|
||||
finishUpdate() {
|
||||
llOwnerSay("✅ Update sequence complete!");
|
||||
llRegionSayTo(targetGame, UPDATER_CHANNEL, "UPDATE_COMPLETE|" + CURRENT_VERSION);
|
||||
|
||||
isBusy = FALSE;
|
||||
targetGame = NULL_KEY;
|
||||
targetPin = 0;
|
||||
linkUUIDs = [];
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
reportMemoryUsage("Peril Dice GitHub Updater");
|
||||
llOwnerSay("🔄 Peril Dice GitHub Updater v" + UPDATER_VERSION);
|
||||
llOwnerSay("📍 Ready to update nearby Peril Dice games");
|
||||
llOwnerSay("👆 Touch your Peril Dice game and select 'Check for Updates'");
|
||||
|
||||
// Listen for update requests from games
|
||||
if (!isListening) {
|
||||
llSetText("📦 Peril Dice Updater\nv" + CURRENT_VERSION + "\nTouch to check version", <0,1,0>, 1.0);
|
||||
llListen(UPDATER_CHANNEL, "", NULL_KEY, "");
|
||||
isListening = TRUE;
|
||||
}
|
||||
|
||||
// Set text to show status
|
||||
llSetText("🔄 Peril Dice GitHub Updater v" + UPDATER_VERSION + "\\n" +
|
||||
"Ready to install updates from GitHub\\n" +
|
||||
"Touch your game to begin", <0.2, 1.0, 0.2>, 1.0);
|
||||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
llResetScript();
|
||||
touch_start(integer num) {
|
||||
llOwnerSay("🔍 Checking GitHub for latest version...");
|
||||
currentOperation = "version_check";
|
||||
currentHttpRequest = llHTTPRequest(GITHUB_API_URL, [HTTP_METHOD, "GET"], "");
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string message) {
|
||||
if (channel != UPDATER_CHANNEL) return;
|
||||
|
||||
if (channel == UPDATER_CHANNEL) {
|
||||
list parts = llParseString2List(message, ["|"], []);
|
||||
string command = llList2String(parts, 0);
|
||||
|
||||
if (command == "UPDATE_REQUEST") {
|
||||
string version = llList2String(parts, 1);
|
||||
if (command == "PING_UPDATER") {
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "UPDATER_AVAILABLE|" + CURRENT_VERSION);
|
||||
}
|
||||
else if (command == "UPDATE_REQUEST") {
|
||||
string version = llList2String(parts, 1); // Version requested (not used currently, we install latest)
|
||||
integer pin = (integer)llList2String(parts, 2);
|
||||
startUpdate(id, version, pin);
|
||||
}
|
||||
else if (command == "LINK_UUIDS_RESPONSE") {
|
||||
if (id != targetGame) return;
|
||||
|
||||
llOwnerSay("📨 Update request from " + name + " (current: " + version + ")");
|
||||
// Parse UUIDs: "12:uuid,35:uuid,..."
|
||||
string payload = llList2String(parts, 1);
|
||||
list pairs = llParseString2List(payload, [","], []);
|
||||
|
||||
if (currentOperation != "") {
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "UPDATE_BUSY|Another update in progress");
|
||||
return;
|
||||
integer i;
|
||||
for (i = 0; i < llGetListLength(pairs); i++) {
|
||||
string pair = llList2String(pairs, i);
|
||||
list kv = llParseString2List(pair, [":"], []);
|
||||
if (llGetListLength(kv) == 2) {
|
||||
integer ln = (integer)llList2String(kv, 0);
|
||||
key uid = (key)llList2String(kv, 1);
|
||||
|
||||
// Update or add
|
||||
integer idx = llListFindList(linkUUIDs, [ln]);
|
||||
if (idx != -1) {
|
||||
linkUUIDs = llListReplaceList(linkUUIDs, [uid], idx+1, idx+1);
|
||||
} else {
|
||||
linkUUIDs += [ln, uid];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start the update process
|
||||
startUpdate(id, pin);
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "UPDATE_STARTING|" + UPDATER_VERSION);
|
||||
// Reset timer as we got data
|
||||
llSetTimerEvent(5.0); // Wait a bit more for other chunks if any
|
||||
|
||||
// If we have enough critical data, we can start
|
||||
// For now, let's just wait for the timer to trigger the start
|
||||
// This allows multiple chunks to arrive
|
||||
}
|
||||
else if (command == "PING_UPDATER") {
|
||||
// Respond to updater detection pings
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "UPDATER_AVAILABLE|" + UPDATER_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
// Continue with next script installation
|
||||
if (currentOperation == "updating") {
|
||||
downloadNextScript();
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
|
||||
if (isBusy && installIndex == 0) {
|
||||
// Timer fired while waiting for UUIDs
|
||||
if (llGetListLength(linkUUIDs) > 0) {
|
||||
llOwnerSay("✅ Received link data. Starting installation...");
|
||||
startDownloadSequence();
|
||||
} else {
|
||||
llOwnerSay("❌ Timed out waiting for Link UUIDs.");
|
||||
llRegionSayTo(targetGame, UPDATER_CHANNEL, "UPDATE_FAILED|Timeout waiting for link data");
|
||||
isBusy = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http_response(key request_id, integer status, list metadata, string body) {
|
||||
if (request_id != currentHttpRequest) return;
|
||||
|
||||
currentHttpRequest = NULL_KEY;
|
||||
|
||||
if (currentOperation == "version_check") {
|
||||
if (status == 200) {
|
||||
// Successfully downloaded script
|
||||
string scriptEntry = llList2String(scriptQueue, currentScriptIndex);
|
||||
list parts = llParseString2List(scriptEntry, ["|"], []);
|
||||
integer linkNum = (integer)llList2String(parts, 1);
|
||||
|
||||
// Install the script
|
||||
installScript(body, downloadingScript, linkNum);
|
||||
string latestVersion = extractJsonValue(body, "tag_name");
|
||||
llOwnerSay("📊 Latest GitHub Version: " + latestVersion);
|
||||
llOwnerSay("📦 Updater Version: v" + CURRENT_VERSION);
|
||||
} else {
|
||||
handleUpdateError("Failed to download " + downloadingScript + " (HTTP " + (string)status + ")");
|
||||
llOwnerSay("❌ GitHub check failed: " + (string)status);
|
||||
}
|
||||
}
|
||||
|
||||
touch_start(integer total_number) {
|
||||
key toucher = llDetectedKey(0);
|
||||
|
||||
if (currentOperation == "updating") {
|
||||
llOwnerSay("⏳ Update in progress - please wait...");
|
||||
llOwnerSay("📊 Installing script " + (string)(currentScriptIndex + 1) +
|
||||
" of " + (string)llGetListLength(scriptQueue));
|
||||
else if (currentOperation == "download_script") {
|
||||
if (status == 200) {
|
||||
installScript(body);
|
||||
} else {
|
||||
llOwnerSay("🔄 Peril Dice GitHub Updater v" + UPDATER_VERSION);
|
||||
llOwnerSay("📍 Ready to update Peril Dice games from GitHub");
|
||||
llOwnerSay("👆 Touch your Peril Dice game (not this updater) and select 'Check for Updates'");
|
||||
llOwnerSay("💡 This updater will automatically download and install scripts");
|
||||
llOwnerSay("❌ Failed to download " + currentFile + ": " + (string)status);
|
||||
llRegionSayTo(targetGame, UPDATER_CHANNEL, "UPDATE_FAILED|Download failed for " + currentFile);
|
||||
isBusy = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,351 +0,0 @@
|
|||
// ====================================================================
|
||||
// Traditional Peril Dice Updater - Inventory-Based Script Copying
|
||||
// ====================================================================
|
||||
// This script goes in an updater box that contains all the updated scripts
|
||||
// in its inventory. It copies scripts from its inventory to the target game.
|
||||
//
|
||||
// SETUP:
|
||||
// 1. Copy all updated LSL scripts into this updater box's inventory
|
||||
// 2. User rezzes updater box near their Peril Dice game
|
||||
// 3. User touches their game -> "Check for Updates" -> "Install Update"
|
||||
// 4. Updater copies scripts from its inventory to their game
|
||||
// 5. User deletes updater box when finished
|
||||
// ====================================================================
|
||||
|
||||
string UPDATER_VERSION = "2.8.8";
|
||||
integer UPDATER_CHANNEL = -7723847;
|
||||
|
||||
// Update state
|
||||
key targetGameKey = NULL_KEY;
|
||||
integer updatePin = 0;
|
||||
list scriptList = [];
|
||||
integer currentScriptIndex = 0;
|
||||
string currentOperation = "";
|
||||
|
||||
// Script to link mapping - each script knows where it belongs
|
||||
list SCRIPT_LINK_MAP = [
|
||||
// Root prim scripts (Link 1)
|
||||
"Main_Controller_Linkset", "1",
|
||||
"Game_Manager", "1",
|
||||
"Controller_Memory", "1",
|
||||
"Controller_MessageHandler", "1",
|
||||
"Player_RegistrationManager", "1",
|
||||
"Player_DialogHandler", "1",
|
||||
"NumberPicker_DialogHandler", "1",
|
||||
"Floater_Manager", "1",
|
||||
"Roll_ConfettiModule", "1",
|
||||
"Bot_Manager", "1",
|
||||
"Game_Calculator", "1",
|
||||
"Verbose_Logger", "1",
|
||||
"System_Debugger", "1",
|
||||
"Update_Receiver", "1",
|
||||
// Other link scripts
|
||||
"Game_Scoreboard_Manager_Linkset", "12",
|
||||
"Leaderboard_Communication_Linkset", "35",
|
||||
"XyzzyText_Dice_Bridge_Linkset", "83",
|
||||
"xyzzy_Master_script", "35-82" // Special case - multiple links
|
||||
];
|
||||
|
||||
// Extract unique script names for inventory checking
|
||||
// NOTE: Update_Receiver is listed LAST to avoid interrupting the update process
|
||||
list REQUIRED_SCRIPTS = [
|
||||
"Main_Controller_Linkset",
|
||||
"Game_Manager",
|
||||
"Controller_Memory",
|
||||
"Controller_MessageHandler",
|
||||
"Player_RegistrationManager",
|
||||
"Player_DialogHandler",
|
||||
"NumberPicker_DialogHandler",
|
||||
"Floater_Manager",
|
||||
"Roll_ConfettiModule",
|
||||
"Bot_Manager",
|
||||
"Game_Calculator",
|
||||
"Verbose_Logger",
|
||||
"System_Debugger",
|
||||
"Game_Scoreboard_Manager_Linkset",
|
||||
"Leaderboard_Communication_Linkset",
|
||||
"XyzzyText_Dice_Bridge_Linkset",
|
||||
"xyzzy_Master_script",
|
||||
"Update_Receiver" // ALWAYS LAST - don't interrupt update process!
|
||||
];
|
||||
|
||||
// Required objects that should be in updater inventory
|
||||
list REQUIRED_OBJECTS = [
|
||||
"StatFloat" // Player status floater object
|
||||
];
|
||||
|
||||
// Memory reporting
|
||||
reportMemoryUsage(string scriptName) {
|
||||
integer memory = llGetUsedMemory();
|
||||
integer freeMemory = llGetFreeMemory();
|
||||
float memoryPercent = (float)memory / (memory + freeMemory) * 100.0;
|
||||
llOwnerSay("📊 " + scriptName + ": " + (string)memory + " bytes used (" +
|
||||
llGetSubString((string)memoryPercent, 0, 4) + "% memory)");
|
||||
}
|
||||
|
||||
// Get target link number for a script
|
||||
string getTargetLink(string scriptName) {
|
||||
integer i;
|
||||
for (i = 0; i < llGetListLength(SCRIPT_LINK_MAP); i += 2) {
|
||||
if (llList2String(SCRIPT_LINK_MAP, i) == scriptName) {
|
||||
return llList2String(SCRIPT_LINK_MAP, i + 1);
|
||||
}
|
||||
}
|
||||
return "1"; // Default to root prim if not found
|
||||
}
|
||||
|
||||
// Install script to specific link using llRemoteLoadScriptPin
|
||||
installScriptToLink(string scriptName, string targetLink) {
|
||||
if (targetLink == "35-82") {
|
||||
// Special case: install xyzzy_Master_script to multiple links
|
||||
llOwnerSay("🔄 Installing " + scriptName + " to links 35-82 (48 copies)...");
|
||||
integer i;
|
||||
for (i = 35; i <= 82; i++) {
|
||||
// Use link number as start_param to target specific link
|
||||
llRemoteLoadScriptPin(targetGameKey, scriptName, updatePin, TRUE, i);
|
||||
llOwnerSay("✅ Installed " + scriptName + " to link " + (string)i);
|
||||
llSleep(0.1); // Brief pause between installations
|
||||
}
|
||||
} else {
|
||||
// Regular installation to single link
|
||||
integer linkNum = (integer)targetLink;
|
||||
llOwnerSay("📝 Installing " + scriptName + " to link " + targetLink);
|
||||
llRemoteLoadScriptPin(targetGameKey, scriptName, updatePin, TRUE, linkNum);
|
||||
llOwnerSay("✅ Installed " + scriptName + " to link " + targetLink);
|
||||
}
|
||||
}
|
||||
|
||||
// Check which scripts and objects are available in inventory
|
||||
checkInventory() {
|
||||
integer totalItems = 0;
|
||||
integer availableItems = 0;
|
||||
|
||||
llOwnerSay("📋 Checking updater inventory with link mapping...");
|
||||
|
||||
// Check scripts
|
||||
integer i;
|
||||
for (i = 0; i < llGetListLength(REQUIRED_SCRIPTS); i++) {
|
||||
string scriptName = llList2String(REQUIRED_SCRIPTS, i);
|
||||
string targetLink = getTargetLink(scriptName);
|
||||
totalItems++;
|
||||
|
||||
if (llGetInventoryType(scriptName) == INVENTORY_SCRIPT) {
|
||||
availableItems++;
|
||||
llOwnerSay("✅ [SCRIPT] " + scriptName + " → Link " + targetLink + " - Ready");
|
||||
} else {
|
||||
llOwnerSay("❌ [SCRIPT] " + scriptName + " → Link " + targetLink + " - MISSING");
|
||||
}
|
||||
}
|
||||
|
||||
// Check objects
|
||||
for (i = 0; i < llGetListLength(REQUIRED_OBJECTS); i++) {
|
||||
string objectName = llList2String(REQUIRED_OBJECTS, i);
|
||||
totalItems++;
|
||||
|
||||
if (llGetInventoryType(objectName) == INVENTORY_OBJECT) {
|
||||
availableItems++;
|
||||
llOwnerSay("✅ [OBJECT] " + objectName + " - Ready");
|
||||
} else {
|
||||
llOwnerSay("❌ [OBJECT] " + objectName + " - MISSING");
|
||||
}
|
||||
}
|
||||
|
||||
llOwnerSay("📊 Inventory Status: " + (string)availableItems + "/" + (string)totalItems + " items available");
|
||||
|
||||
if (availableItems == totalItems) {
|
||||
llOwnerSay("✅ All required scripts and objects present - updater ready!");
|
||||
llOwnerSay("🔗 Scripts will be installed to their correct links automatically");
|
||||
llOwnerSay("📦 Objects will be given to target game inventory");
|
||||
} else {
|
||||
llOwnerSay("⚠️ Missing items - please add them to updater inventory");
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer all objects to target game first
|
||||
transferObjects() {
|
||||
llOwnerSay("📦 Transferring objects to target game...");
|
||||
|
||||
integer i;
|
||||
for (i = 0; i < llGetListLength(REQUIRED_OBJECTS); i++) {
|
||||
string objectName = llList2String(REQUIRED_OBJECTS, i);
|
||||
if (llGetInventoryType(objectName) == INVENTORY_OBJECT) {
|
||||
llGiveInventory(targetGameKey, objectName);
|
||||
llOwnerSay("✅ Transferred " + objectName + " to target game");
|
||||
}
|
||||
}
|
||||
|
||||
llOwnerSay("📦 Object transfer complete - starting script installation...");
|
||||
}
|
||||
|
||||
// Start the update process
|
||||
startUpdate(key gameKey, integer pin) {
|
||||
targetGameKey = gameKey;
|
||||
updatePin = pin;
|
||||
currentOperation = "updating";
|
||||
currentScriptIndex = 0;
|
||||
|
||||
// Build script list for this specific update
|
||||
scriptList = [];
|
||||
|
||||
// Add all available scripts
|
||||
integer i;
|
||||
for (i = 0; i < llGetListLength(REQUIRED_SCRIPTS); i++) {
|
||||
string scriptName = llList2String(REQUIRED_SCRIPTS, i);
|
||||
if (llGetInventoryType(scriptName) == INVENTORY_SCRIPT) {
|
||||
scriptList += [scriptName];
|
||||
}
|
||||
}
|
||||
|
||||
llOwnerSay("🔄 Starting update process...");
|
||||
llOwnerSay("📊 Installing " + (string)llGetListLength(scriptList) + " scripts");
|
||||
|
||||
// Transfer objects first, then install scripts
|
||||
transferObjects();
|
||||
llSetTimerEvent(2.0); // Brief pause before starting script installation
|
||||
}
|
||||
|
||||
// Install next script in the queue
|
||||
installNextScript() {
|
||||
if (currentScriptIndex >= llGetListLength(scriptList)) {
|
||||
// Update complete!
|
||||
completeUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
string scriptName = llList2String(scriptList, currentScriptIndex);
|
||||
string targetLink = getTargetLink(scriptName);
|
||||
|
||||
llOwnerSay("🚀 Progress: " + (string)(currentScriptIndex + 1) + "/" + (string)llGetListLength(scriptList));
|
||||
|
||||
// Install script to correct link(s)
|
||||
installScriptToLink(scriptName, targetLink);
|
||||
|
||||
// Move to next script
|
||||
currentScriptIndex++;
|
||||
|
||||
// Longer pause for xyzzy_Master_script (48 installations)
|
||||
if (targetLink == "35-82") {
|
||||
llSetTimerEvent(10.0); // Extra time for multiple installations
|
||||
} else {
|
||||
llSetTimerEvent(2.0); // Normal pause
|
||||
}
|
||||
}
|
||||
|
||||
// Complete the update process
|
||||
completeUpdate() {
|
||||
llOwnerSay("🎉 Update installation complete!");
|
||||
llOwnerSay("📊 Successfully installed " + (string)llGetListLength(scriptList) + " scripts");
|
||||
|
||||
// Notify target game
|
||||
if (targetGameKey != NULL_KEY) {
|
||||
llRegionSayTo(targetGameKey, UPDATER_CHANNEL, "UPDATE_COMPLETE|" + UPDATER_VERSION);
|
||||
}
|
||||
|
||||
// Reset state and stop timer
|
||||
currentOperation = "";
|
||||
targetGameKey = NULL_KEY;
|
||||
updatePin = 0;
|
||||
scriptList = [];
|
||||
currentScriptIndex = 0;
|
||||
llSetTimerEvent(0.0); // Stop the timer
|
||||
|
||||
llOwnerSay("💡 Update complete! You can now delete this updater box.");
|
||||
llSetText("🎉 Update Complete!\nYou can delete this updater box\nThank you for updating!",
|
||||
<0.2, 1.0, 0.2>, 1.0);
|
||||
}
|
||||
|
||||
// Handle update errors
|
||||
handleUpdateError(string error) {
|
||||
llOwnerSay("❌ Update failed: " + error);
|
||||
|
||||
// Notify target game of failure
|
||||
if (targetGameKey != NULL_KEY) {
|
||||
llRegionSayTo(targetGameKey, UPDATER_CHANNEL, "UPDATE_FAILED|" + error);
|
||||
}
|
||||
|
||||
// Reset state and stop timer
|
||||
currentOperation = "";
|
||||
targetGameKey = NULL_KEY;
|
||||
updatePin = 0;
|
||||
scriptList = [];
|
||||
currentScriptIndex = 0;
|
||||
llSetTimerEvent(0.0); // Stop the timer
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
reportMemoryUsage("Traditional Peril Dice Updater");
|
||||
llOwnerSay("🔄 Traditional Peril Dice Updater v" + UPDATER_VERSION);
|
||||
llOwnerSay("📦 Inventory-based script copying system");
|
||||
llOwnerSay("👆 Touch your Peril Dice game and select 'Check for Updates'");
|
||||
|
||||
// Check our inventory
|
||||
checkInventory();
|
||||
|
||||
// Listen for update requests
|
||||
llListen(UPDATER_CHANNEL, "", NULL_KEY, "");
|
||||
|
||||
// Set helpful text
|
||||
llSetText("🔄 Peril Dice Updater v" + UPDATER_VERSION + "\n" +
|
||||
"Traditional inventory-based system\n" +
|
||||
"Touch your game, not this updater", <0.2, 1.0, 0.2>, 1.0);
|
||||
}
|
||||
|
||||
on_rez(integer start_param) {
|
||||
llResetScript();
|
||||
}
|
||||
|
||||
listen(integer channel, string name, key id, string message) {
|
||||
if (channel != UPDATER_CHANNEL) return;
|
||||
|
||||
list parts = llParseString2List(message, ["|"], []);
|
||||
string command = llList2String(parts, 0);
|
||||
|
||||
if (command == "UPDATE_REQUEST") {
|
||||
string version = llList2String(parts, 1);
|
||||
integer pin = (integer)llList2String(parts, 2);
|
||||
|
||||
llOwnerSay("📨 Update request from " + name + " (current: " + version + ", PIN: " + (string)pin + ")");
|
||||
|
||||
if (currentOperation != "") {
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "UPDATE_BUSY|Another update in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the update process
|
||||
startUpdate(id, pin);
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "UPDATE_STARTING|" + UPDATER_VERSION);
|
||||
}
|
||||
else if (command == "PING_UPDATER") {
|
||||
// Respond to updater detection pings
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "UPDATER_AVAILABLE|" + UPDATER_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
// Continue with next script installation
|
||||
if (currentOperation == "updating") {
|
||||
installNextScript();
|
||||
// Don't turn off timer - installNextScript() will manage timing
|
||||
} else {
|
||||
// Only turn off timer if we're not updating
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
touch_start(integer total_number) {
|
||||
key toucher = llDetectedKey(0);
|
||||
|
||||
if (currentOperation == "updating") {
|
||||
llOwnerSay("⏳ Update in progress for " + llKey2Name(targetGameKey));
|
||||
llOwnerSay("📊 Installing script " + (string)(currentScriptIndex + 1) +
|
||||
" of " + (string)llGetListLength(scriptList));
|
||||
} else {
|
||||
llOwnerSay("🔄 Traditional Peril Dice Updater v" + UPDATER_VERSION);
|
||||
llOwnerSay("📦 Ready to update Peril Dice games using inventory scripts");
|
||||
llOwnerSay("👆 Touch your Peril Dice game (not this updater) and select 'Check for Updates'");
|
||||
llOwnerSay("📋 Checking inventory...");
|
||||
checkInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -316,6 +316,53 @@ default {
|
|||
else if (command == "UPDATE_BUSY") {
|
||||
llOwnerSay("⏳ Updater is busy with another installation");
|
||||
}
|
||||
else if (command == "REQUEST_LINK_UUIDS") {
|
||||
// Updater is requesting our link UUIDs for proper script installation
|
||||
llOwnerSay("📡 Updater requesting link UUIDs for linkset script installation...");
|
||||
|
||||
integer linkCount = llGetNumberOfPrims();
|
||||
|
||||
// Send critical links first
|
||||
list criticalLinks = [12, 35, 83]; // Scoreboard, Leaderboard, Dice Bridge
|
||||
string criticalPayload = "";
|
||||
|
||||
integer i;
|
||||
for (i = 0; i < llGetListLength(criticalLinks); i++) {
|
||||
integer linkNum = llList2Integer(criticalLinks, i);
|
||||
if (linkNum <= linkCount) {
|
||||
key linkUUID = llGetLinkKey(linkNum);
|
||||
if (criticalPayload != "") criticalPayload += ",";
|
||||
criticalPayload += (string)linkNum + ":" + (string)linkUUID;
|
||||
}
|
||||
}
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "LINK_UUIDS_RESPONSE|" + criticalPayload);
|
||||
llOwnerSay("✅ Sent critical link UUIDs (" + (string)llGetListLength(criticalLinks) + " links)");
|
||||
if (VERBOSE_LOGGING) llOwnerSay("📊 Critical UUID Data: " + criticalPayload);
|
||||
|
||||
// Now send all xyzzy links (35-82) in safe-sized chunks as additional LINK_UUIDS_RESPONSE messages
|
||||
if (linkCount >= 82) {
|
||||
string chunk = "";
|
||||
integer countInChunk = 0;
|
||||
integer j;
|
||||
for (j = 35; j <= 82; j++) {
|
||||
key luuid = llGetLinkKey(j);
|
||||
string piece = (string)j + ":" + (string)luuid;
|
||||
// Flush if adding would exceed ~900 chars or ~20 entries
|
||||
if ((llStringLength(chunk) + 1 + llStringLength(piece)) > 900 || countInChunk >= 20) {
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "LINK_UUIDS_RESPONSE|" + chunk);
|
||||
chunk = "";
|
||||
countInChunk = 0;
|
||||
}
|
||||
if (chunk != "") chunk += ",";
|
||||
chunk += piece;
|
||||
countInChunk++;
|
||||
}
|
||||
if (chunk != "") {
|
||||
llRegionSayTo(id, UPDATER_CHANNEL, "LINK_UUIDS_RESPONSE|" + chunk);
|
||||
}
|
||||
llOwnerSay("✅ Sent xyzzy UUIDs (links 35-82) in chunks");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ class LSLValidator:
|
|||
# Events
|
||||
'touch_start', 'touch_end', 'listen', 'timer', 'link_message',
|
||||
'collision_start', 'collision', 'collision_end', 'http_response',
|
||||
'sensor', 'no_sensor', 'control', 'land_collision_start', 'land_collision',
|
||||
'land_collision_end', 'at_target', 'not_at_target', 'at_rot_target',
|
||||
'not_at_rot_target', 'money', 'email', 'run_time_permissions', 'changed',
|
||||
'attach', 'dataserver', 'moving_start', 'moving_end', 'transaction_result',
|
||||
'path_update', 'remote_data',
|
||||
# String functions
|
||||
'llStringLength', 'llGetSubString', 'llSubStringIndex', 'llToUpper', 'llToLower',
|
||||
'llMD5String', 'llSHA1String', 'llEscapeURL', 'llUnescapeURL',
|
||||
|
|
|
|||
Loading…
Reference in a new issue