From 7fb9675fa3ed5eb1827a6b372b32691745c51680 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Mon, 28 Oct 2024 13:18:24 +0100 Subject: [PATCH] Added library file for memory bags --- objects/ChallengeScenarios.9f6801.json | 2 +- objects/ChallengeScenarios.9f6801.ttslua | 494 ---------------------- objects/StandaloneScenarios.77a5f9.json | 2 +- objects/StandaloneScenarios.77a5f9.ttslua | 494 ---------------------- src/MemoryBag.ttslua | 397 +++++++++++++++++ 5 files changed, 399 insertions(+), 990 deletions(-) delete mode 100644 objects/ChallengeScenarios.9f6801.ttslua delete mode 100644 objects/StandaloneScenarios.77a5f9.ttslua create mode 100644 src/MemoryBag.ttslua diff --git a/objects/ChallengeScenarios.9f6801.json b/objects/ChallengeScenarios.9f6801.json index b2709191..6862072d 100644 --- a/objects/ChallengeScenarios.9f6801.json +++ b/objects/ChallengeScenarios.9f6801.json @@ -54,8 +54,8 @@ "IgnoreFoW": false, "LayoutGroupSortIndex": 0, "Locked": false, + "LuaScript": "require(\"MemoryBag\")", "LuaScriptState_path": "ChallengeScenarios.9f6801.luascriptstate", - "LuaScript_path": "ChallengeScenarios.9f6801.ttslua", "MaterialIndex": -1, "MeasureMovement": false, "MeshIndex": -1, diff --git a/objects/ChallengeScenarios.9f6801.ttslua b/objects/ChallengeScenarios.9f6801.ttslua deleted file mode 100644 index 2d63eb65..00000000 --- a/objects/ChallengeScenarios.9f6801.ttslua +++ /dev/null @@ -1,494 +0,0 @@ --- Utility memory bag by Directsun --- Version 2.5.2 --- Fork of Memory Bag 2.0 by MrStump - -function updateSave() - local data_to_save = {["ml"]=memoryList} - saved_data = JSON.encode(data_to_save) - self.script_state = saved_data -end - -function combineMemoryFromBagsWithin() - local bagObjList = self.getObjects() - for _, bagObj in ipairs(bagObjList) do - local data = bagObj.lua_script_state - if data ~= nil then - local j = JSON.decode(data) - if j ~= nil and j.ml ~= nil then - for guid, entry in pairs(j.ml) do - memoryList[guid] = entry - end - end - end - end -end - -function updateMemoryWithMoves() - memoryList = memoryListBackup - --get the first transposed object's coordinates - local obj = getObjectFromGUID(moveGuid or "") - - -- p1 is where needs to go, p2 is where it was - local refObjPos = memoryList[moveGuid].pos - local deltaPos = findOffsetDistance(obj.getPosition(), refObjPos, nil) - for guid, entry in pairs(memoryList) do - memoryList[guid].pos.x = entry.pos.x - deltaPos.x - memoryList[guid].pos.y = entry.pos.y - deltaPos.y - memoryList[guid].pos.z = entry.pos.z - deltaPos.z - end - - moveList = {} -end - -function onload(saved_data) - fresh = true - if saved_data ~= "" then - local loaded_data = JSON.decode(saved_data) - --Set up information off of loaded_data - memoryList = loaded_data.ml - else - --Set up information for if there is no saved saved data - memoryList = {} - end - - moveList = {} - moveGuid = nil - - if next(memoryList) == nil then - createSetupButton() - else - fresh = false - createMemoryActionButtons() - end -end - - ---Beginning Setup - - ---Make setup button -function createSetupButton() - self.createButton({ - label="Setup", click_function="buttonClick_setup", function_owner=self, - position={0,0.1,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) -end - ---Triggered by Transpose button -function buttonClick_transpose() - moveGuid = nil - broadcastToAll("Select one object and move it- all objects will move relative to the new location", {0.75, 0.75, 1}) - memoryListBackup = duplicateTable(memoryList) - memoryList = {} - moveList = {} - self.clearButtons() - createButtonsOnAllObjects(true) - createSetupActionButtons(true) -end - ---Triggered by setup button, -function buttonClick_setup() - memoryListBackup = duplicateTable(memoryList) - memoryList = {} - self.clearButtons() - createButtonsOnAllObjects(false) - createSetupActionButtons(false) -end - -function getAllObjectsInMemory() - local objTable = {} - local curObj = {} - - for guid in pairs(memoryListBackup) do - curObj = getObjectFromGUID(guid) - table.insert(objTable, curObj) - end - - return objTable - -- return getAllObjects() -end - ---Creates selection buttons on objects -function createButtonsOnAllObjects(move) - local howManyButtons = 0 - - local objsToHaveButtons = {} - if move == true then - objsToHaveButtons = getAllObjectsInMemory() - else - objsToHaveButtons = getAllObjects() - end - - for _, obj in ipairs(objsToHaveButtons) do - if obj ~= self then - local dummyIndex = howManyButtons - --On a normal bag, the button positions aren't the same size as the bag. - globalScaleFactor = 1 * 1/self.getScale().x - --Super sweet math to set button positions - local selfPos = self.getPosition() - local objPos = obj.getPosition() - local deltaPos = findOffsetDistance(selfPos, objPos, obj) - local objPos = rotateLocalCoordinates(deltaPos, self) - objPos.x = -objPos.x * globalScaleFactor - objPos.y = objPos.y * globalScaleFactor + 4 - objPos.z = objPos.z * globalScaleFactor - --Offset rotation of bag - local rot = self.getRotation() - rot.y = -rot.y + 180 - --Create function - local funcName = "selectButton_" .. howManyButtons - local func = function() buttonClick_selection(dummyIndex, obj, move) end - local color = {0.75,0.25,0.25,0.6} - local colorMove = {0,0,1,0.6} - if move == true then - color = colorMove - end - self.setVar(funcName, func) - self.createButton({ - click_function=funcName, function_owner=self, - position=objPos, rotation=rot, height=1000, width=1000, - color=color, - }) - howManyButtons = howManyButtons + 1 - end - end -end - ---Creates submit and cancel buttons -function createSetupActionButtons(move) - self.createButton({ - label="Cancel", click_function="buttonClick_cancel", function_owner=self, - position={-1.25,0.1,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - - self.createButton({ - label="Submit", click_function="buttonClick_submit", function_owner=self, - position={-1.25,0.3,-7}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - - if move == false then - self.createButton({ - label="Add", click_function="buttonClick_add", function_owner=self, - position={1.25,0.3,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={0.25,1,0.25} - }) - - if fresh == false then - self.createButton({ - label="Set New", click_function="buttonClick_setNew", function_owner=self, - position={1.25,0.3,-8}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={0.75,0.75,1} - }) - self.createButton({ - label="Remove", click_function="buttonClick_remove", function_owner=self, - position={1.25,0.3,-7}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,0.25,0.25} - }) - end - end - - self.createButton({ - label="Reset", click_function="buttonClick_reset", function_owner=self, - position={-1.25,0.3,-8}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) -end - - ---During Setup - - ---Checks or unchecks buttons -function buttonClick_selection(index, obj, move) - local colorMove = {0,0,1,0.6} - local color = {0,1,0,0.6} - - previousGuid = selectedGuid - selectedGuid = obj.getGUID() - - theList = memoryList - if move == true then - theList = moveList - if previousGuid ~= nil and previousGuid ~= selectedGuid then - local prevObj = getObjectFromGUID(previousGuid) - prevObj.highlightOff() - self.editButton({index=previousIndex, color=colorMove}) - theList[previousGuid] = nil - end - previousIndex = index - end - - if theList[selectedGuid] == nil then - self.editButton({index=index, color=color}) - --Adding pos/rot to memory table - local pos, rot = obj.getPosition(), obj.getRotation() - --I need to add it like this or it won't save due to indexing issue - theList[obj.getGUID()] = { - pos={x=round(pos.x,4), y=round(pos.y,4), z=round(pos.z,4)}, - rot={x=round(rot.x,4), y=round(rot.y,4), z=round(rot.z,4)}, - lock=obj.getLock() - } - obj.highlightOn({0,1,0}) - else - color = {0.75,0.25,0.25,0.6} - if move == true then - color = colorMove - end - self.editButton({index=index, color=color}) - theList[obj.getGUID()] = nil - obj.highlightOff() - end -end - ---Cancels selection process -function buttonClick_cancel() - memoryList = memoryListBackup - moveList = {} - self.clearButtons() - if next(memoryList) == nil then - createSetupButton() - else - createMemoryActionButtons() - end - removeAllHighlights() - broadcastToAll("Selection Canceled", {1,1,1}) - moveGuid = nil -end - ---Saves selections -function buttonClick_submit() - fresh = false - if next(moveList) ~= nil then - for guid in pairs(moveList) do - moveGuid = guid - end - if memoryListBackup[moveGuid] == nil then - broadcastToAll("Item selected for moving is not already in memory", {1, 0.25, 0.25}) - else - broadcastToAll("Moving all items in memory relative to new objects position!", {0.75, 0.75, 1}) - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(moveList) do - moveGuid = guid - count = count + 1 - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - updateMemoryWithMoves() - updateSave() - buttonClick_place() - end - elseif next(memoryList) == nil and moveGuid == nil then - memoryList = memoryListBackup - broadcastToAll("No selections made.", {0.75, 0.25, 0.25}) - end - combineMemoryFromBagsWithin() - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(memoryList) do - count = count + 1 - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - broadcastToAll(count.." Objects Saved", {1,1,1}) - updateSave() - moveGuid = nil -end - -function combineTables(first_table, second_table) - for k,v in pairs(second_table) do first_table[k] = v end -end - -function buttonClick_add() - fresh = false - combineTables(memoryList, memoryListBackup) - broadcastToAll("Adding internal bags and selections to existing memory", {0.25, 0.75, 0.25}) - combineMemoryFromBagsWithin() - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(memoryList) do - count = count + 1 - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - broadcastToAll(count.." Objects Saved", {1,1,1}) - updateSave() -end - -function buttonClick_remove() - broadcastToAll("Removing Selected Entries From Memory", {1.0, 0.25, 0.25}) - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(memoryList) do - count = count + 1 - memoryListBackup[guid] = nil - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - broadcastToAll(count.." Objects Removed", {1,1,1}) - memoryList = memoryListBackup - updateSave() -end - -function buttonClick_setNew() - broadcastToAll("Setting new position relative to items in memory", {0.75, 0.75, 1}) - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for _, obj in ipairs(getAllObjects()) do - guid = obj.guid - if memoryListBackup[guid] ~= nil then - count = count + 1 - memoryListBackup[guid].pos = obj.getPosition() - memoryListBackup[guid].rot = obj.getRotation() - memoryListBackup[guid].lock = obj.getLock() - end - end - broadcastToAll(count.." Objects Saved", {1,1,1}) - memoryList = memoryListBackup - updateSave() -end - ---Resets bag to starting status -function buttonClick_reset() - fresh = true - memoryList = {} - self.clearButtons() - createSetupButton() - removeAllHighlights() - broadcastToAll("Tool Reset", {1,1,1}) - updateSave() -end - - ---After Setup - - ---Creates recall and place buttons -function createMemoryActionButtons() - self.createButton({ - label="Place", click_function="buttonClick_place", function_owner=self, - position={1.35,1,6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - self.createButton({ - label="Recall", click_function="buttonClick_recall", function_owner=self, - position={-1.25,1,6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - self.createButton({ - label="Setup", click_function="buttonClick_setup", function_owner=self, - position={0,0.1,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) ---- self.createButton({ ---- label="Move", click_function="buttonClick_transpose", function_owner=self, ---- position={-2.8,0.3,0}, rotation={0,0,0}, height=350, width=800, ---- font_size=250, color={0,0,0}, font_color={0.75,0.75,1} ---- }) -end - ---Sends objects from bag/table to their saved position/rotation -function buttonClick_place() - local bagObjList = self.getObjects() - for guid, entry in pairs(memoryList) do - local obj = getObjectFromGUID(guid) - --If obj is out on the table, move it to the saved pos/rot - if obj ~= nil then - obj.setPositionSmooth(entry.pos) - obj.setRotationSmooth(entry.rot) - obj.setLock(entry.lock) - else - --If obj is inside of the bag - for _, bagObj in ipairs(bagObjList) do - if bagObj.guid == guid then - local item = self.takeObject({ - guid=guid, position=entry.pos, rotation=entry.rot, smooth=false - }) - item.setLock(entry.lock) - break - end - end - end - end - broadcastToAll("Objects Placed", {1,1,1}) -end - ---Recalls objects to bag from table -function buttonClick_recall() - for guid, entry in pairs(memoryList) do - local obj = getObjectFromGUID(guid) - if obj ~= nil then self.putObject(obj) end - end - broadcastToAll("Objects Recalled", {1,1,1}) -end - - ---Utility functions - - ---Find delta (difference) between 2 x/y/z coordinates -function findOffsetDistance(p1, p2, obj) - local yOffset = 0 - if obj ~= nil then - local bounds = obj.getBounds() - yOffset = (bounds.size.y - bounds.offset.y) - end - local deltaPos = {} - deltaPos.x = (p2.x-p1.x) - deltaPos.y = (p2.y-p1.y) + yOffset - deltaPos.z = (p2.z-p1.z) - return deltaPos -end - ---Used to rotate a set of coordinates by an angle -function rotateLocalCoordinates(desiredPos, obj) - local objPos, objRot = obj.getPosition(), obj.getRotation() - local angle = math.rad(objRot.y) - local x = desiredPos.x * math.cos(angle) - desiredPos.z * math.sin(angle) - local z = desiredPos.x * math.sin(angle) + desiredPos.z * math.cos(angle) - --return {x=objPos.x+x, y=objPos.y+desiredPos.y, z=objPos.z+z} - return {x=x, y=desiredPos.y, z=z} -end - -function rotateMyCoordinates(desiredPos, obj) - local angle = math.rad(obj.getRotation().y) - local x = desiredPos.x * math.sin(angle) - local z = desiredPos.z * math.cos(angle) - return {x=x, y=desiredPos.y, z=z} -end - ---Coroutine delay, in seconds -function wait(time) - local start = os.time() - repeat coroutine.yield(0) until os.time() > start + time -end - ---Duplicates a table (needed to prevent it making reference to the same objects) -function duplicateTable(oldTable) - local newTable = {} - for k, v in pairs(oldTable) do - newTable[k] = v - end - return newTable -end - ---Moves scripted highlight from all objects -function removeAllHighlights() - for _, obj in ipairs(getAllObjects()) do - obj.highlightOff() - end -end - ---Round number (num) to the Nth decimal (dec) -function round(num, dec) - local mult = 10^(dec or 0) - return math.floor(num * mult + 0.5) / mult -end diff --git a/objects/StandaloneScenarios.77a5f9.json b/objects/StandaloneScenarios.77a5f9.json index d0cbba59..59156d6e 100644 --- a/objects/StandaloneScenarios.77a5f9.json +++ b/objects/StandaloneScenarios.77a5f9.json @@ -58,8 +58,8 @@ "IgnoreFoW": false, "LayoutGroupSortIndex": 0, "Locked": false, + "LuaScript": "require(\"MemoryBag\")", "LuaScriptState_path": "StandaloneScenarios.77a5f9.luascriptstate", - "LuaScript_path": "StandaloneScenarios.77a5f9.ttslua", "MaterialIndex": -1, "MeasureMovement": false, "MeshIndex": -1, diff --git a/objects/StandaloneScenarios.77a5f9.ttslua b/objects/StandaloneScenarios.77a5f9.ttslua deleted file mode 100644 index 2d63eb65..00000000 --- a/objects/StandaloneScenarios.77a5f9.ttslua +++ /dev/null @@ -1,494 +0,0 @@ --- Utility memory bag by Directsun --- Version 2.5.2 --- Fork of Memory Bag 2.0 by MrStump - -function updateSave() - local data_to_save = {["ml"]=memoryList} - saved_data = JSON.encode(data_to_save) - self.script_state = saved_data -end - -function combineMemoryFromBagsWithin() - local bagObjList = self.getObjects() - for _, bagObj in ipairs(bagObjList) do - local data = bagObj.lua_script_state - if data ~= nil then - local j = JSON.decode(data) - if j ~= nil and j.ml ~= nil then - for guid, entry in pairs(j.ml) do - memoryList[guid] = entry - end - end - end - end -end - -function updateMemoryWithMoves() - memoryList = memoryListBackup - --get the first transposed object's coordinates - local obj = getObjectFromGUID(moveGuid or "") - - -- p1 is where needs to go, p2 is where it was - local refObjPos = memoryList[moveGuid].pos - local deltaPos = findOffsetDistance(obj.getPosition(), refObjPos, nil) - for guid, entry in pairs(memoryList) do - memoryList[guid].pos.x = entry.pos.x - deltaPos.x - memoryList[guid].pos.y = entry.pos.y - deltaPos.y - memoryList[guid].pos.z = entry.pos.z - deltaPos.z - end - - moveList = {} -end - -function onload(saved_data) - fresh = true - if saved_data ~= "" then - local loaded_data = JSON.decode(saved_data) - --Set up information off of loaded_data - memoryList = loaded_data.ml - else - --Set up information for if there is no saved saved data - memoryList = {} - end - - moveList = {} - moveGuid = nil - - if next(memoryList) == nil then - createSetupButton() - else - fresh = false - createMemoryActionButtons() - end -end - - ---Beginning Setup - - ---Make setup button -function createSetupButton() - self.createButton({ - label="Setup", click_function="buttonClick_setup", function_owner=self, - position={0,0.1,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) -end - ---Triggered by Transpose button -function buttonClick_transpose() - moveGuid = nil - broadcastToAll("Select one object and move it- all objects will move relative to the new location", {0.75, 0.75, 1}) - memoryListBackup = duplicateTable(memoryList) - memoryList = {} - moveList = {} - self.clearButtons() - createButtonsOnAllObjects(true) - createSetupActionButtons(true) -end - ---Triggered by setup button, -function buttonClick_setup() - memoryListBackup = duplicateTable(memoryList) - memoryList = {} - self.clearButtons() - createButtonsOnAllObjects(false) - createSetupActionButtons(false) -end - -function getAllObjectsInMemory() - local objTable = {} - local curObj = {} - - for guid in pairs(memoryListBackup) do - curObj = getObjectFromGUID(guid) - table.insert(objTable, curObj) - end - - return objTable - -- return getAllObjects() -end - ---Creates selection buttons on objects -function createButtonsOnAllObjects(move) - local howManyButtons = 0 - - local objsToHaveButtons = {} - if move == true then - objsToHaveButtons = getAllObjectsInMemory() - else - objsToHaveButtons = getAllObjects() - end - - for _, obj in ipairs(objsToHaveButtons) do - if obj ~= self then - local dummyIndex = howManyButtons - --On a normal bag, the button positions aren't the same size as the bag. - globalScaleFactor = 1 * 1/self.getScale().x - --Super sweet math to set button positions - local selfPos = self.getPosition() - local objPos = obj.getPosition() - local deltaPos = findOffsetDistance(selfPos, objPos, obj) - local objPos = rotateLocalCoordinates(deltaPos, self) - objPos.x = -objPos.x * globalScaleFactor - objPos.y = objPos.y * globalScaleFactor + 4 - objPos.z = objPos.z * globalScaleFactor - --Offset rotation of bag - local rot = self.getRotation() - rot.y = -rot.y + 180 - --Create function - local funcName = "selectButton_" .. howManyButtons - local func = function() buttonClick_selection(dummyIndex, obj, move) end - local color = {0.75,0.25,0.25,0.6} - local colorMove = {0,0,1,0.6} - if move == true then - color = colorMove - end - self.setVar(funcName, func) - self.createButton({ - click_function=funcName, function_owner=self, - position=objPos, rotation=rot, height=1000, width=1000, - color=color, - }) - howManyButtons = howManyButtons + 1 - end - end -end - ---Creates submit and cancel buttons -function createSetupActionButtons(move) - self.createButton({ - label="Cancel", click_function="buttonClick_cancel", function_owner=self, - position={-1.25,0.1,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - - self.createButton({ - label="Submit", click_function="buttonClick_submit", function_owner=self, - position={-1.25,0.3,-7}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - - if move == false then - self.createButton({ - label="Add", click_function="buttonClick_add", function_owner=self, - position={1.25,0.3,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={0.25,1,0.25} - }) - - if fresh == false then - self.createButton({ - label="Set New", click_function="buttonClick_setNew", function_owner=self, - position={1.25,0.3,-8}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={0.75,0.75,1} - }) - self.createButton({ - label="Remove", click_function="buttonClick_remove", function_owner=self, - position={1.25,0.3,-7}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,0.25,0.25} - }) - end - end - - self.createButton({ - label="Reset", click_function="buttonClick_reset", function_owner=self, - position={-1.25,0.3,-8}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) -end - - ---During Setup - - ---Checks or unchecks buttons -function buttonClick_selection(index, obj, move) - local colorMove = {0,0,1,0.6} - local color = {0,1,0,0.6} - - previousGuid = selectedGuid - selectedGuid = obj.getGUID() - - theList = memoryList - if move == true then - theList = moveList - if previousGuid ~= nil and previousGuid ~= selectedGuid then - local prevObj = getObjectFromGUID(previousGuid) - prevObj.highlightOff() - self.editButton({index=previousIndex, color=colorMove}) - theList[previousGuid] = nil - end - previousIndex = index - end - - if theList[selectedGuid] == nil then - self.editButton({index=index, color=color}) - --Adding pos/rot to memory table - local pos, rot = obj.getPosition(), obj.getRotation() - --I need to add it like this or it won't save due to indexing issue - theList[obj.getGUID()] = { - pos={x=round(pos.x,4), y=round(pos.y,4), z=round(pos.z,4)}, - rot={x=round(rot.x,4), y=round(rot.y,4), z=round(rot.z,4)}, - lock=obj.getLock() - } - obj.highlightOn({0,1,0}) - else - color = {0.75,0.25,0.25,0.6} - if move == true then - color = colorMove - end - self.editButton({index=index, color=color}) - theList[obj.getGUID()] = nil - obj.highlightOff() - end -end - ---Cancels selection process -function buttonClick_cancel() - memoryList = memoryListBackup - moveList = {} - self.clearButtons() - if next(memoryList) == nil then - createSetupButton() - else - createMemoryActionButtons() - end - removeAllHighlights() - broadcastToAll("Selection Canceled", {1,1,1}) - moveGuid = nil -end - ---Saves selections -function buttonClick_submit() - fresh = false - if next(moveList) ~= nil then - for guid in pairs(moveList) do - moveGuid = guid - end - if memoryListBackup[moveGuid] == nil then - broadcastToAll("Item selected for moving is not already in memory", {1, 0.25, 0.25}) - else - broadcastToAll("Moving all items in memory relative to new objects position!", {0.75, 0.75, 1}) - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(moveList) do - moveGuid = guid - count = count + 1 - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - updateMemoryWithMoves() - updateSave() - buttonClick_place() - end - elseif next(memoryList) == nil and moveGuid == nil then - memoryList = memoryListBackup - broadcastToAll("No selections made.", {0.75, 0.25, 0.25}) - end - combineMemoryFromBagsWithin() - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(memoryList) do - count = count + 1 - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - broadcastToAll(count.." Objects Saved", {1,1,1}) - updateSave() - moveGuid = nil -end - -function combineTables(first_table, second_table) - for k,v in pairs(second_table) do first_table[k] = v end -end - -function buttonClick_add() - fresh = false - combineTables(memoryList, memoryListBackup) - broadcastToAll("Adding internal bags and selections to existing memory", {0.25, 0.75, 0.25}) - combineMemoryFromBagsWithin() - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(memoryList) do - count = count + 1 - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - broadcastToAll(count.." Objects Saved", {1,1,1}) - updateSave() -end - -function buttonClick_remove() - broadcastToAll("Removing Selected Entries From Memory", {1.0, 0.25, 0.25}) - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for guid in pairs(memoryList) do - count = count + 1 - memoryListBackup[guid] = nil - local obj = getObjectFromGUID(guid) - if obj ~= nil then obj.highlightOff() end - end - broadcastToAll(count.." Objects Removed", {1,1,1}) - memoryList = memoryListBackup - updateSave() -end - -function buttonClick_setNew() - broadcastToAll("Setting new position relative to items in memory", {0.75, 0.75, 1}) - self.clearButtons() - createMemoryActionButtons() - local count = 0 - for _, obj in ipairs(getAllObjects()) do - guid = obj.guid - if memoryListBackup[guid] ~= nil then - count = count + 1 - memoryListBackup[guid].pos = obj.getPosition() - memoryListBackup[guid].rot = obj.getRotation() - memoryListBackup[guid].lock = obj.getLock() - end - end - broadcastToAll(count.." Objects Saved", {1,1,1}) - memoryList = memoryListBackup - updateSave() -end - ---Resets bag to starting status -function buttonClick_reset() - fresh = true - memoryList = {} - self.clearButtons() - createSetupButton() - removeAllHighlights() - broadcastToAll("Tool Reset", {1,1,1}) - updateSave() -end - - ---After Setup - - ---Creates recall and place buttons -function createMemoryActionButtons() - self.createButton({ - label="Place", click_function="buttonClick_place", function_owner=self, - position={1.35,1,6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - self.createButton({ - label="Recall", click_function="buttonClick_recall", function_owner=self, - position={-1.25,1,6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) - self.createButton({ - label="Setup", click_function="buttonClick_setup", function_owner=self, - position={0,0.1,-6}, rotation={0,0,0}, height=500, width=1200, - font_size=350, color={0,0,0}, font_color={1,1,1} - }) ---- self.createButton({ ---- label="Move", click_function="buttonClick_transpose", function_owner=self, ---- position={-2.8,0.3,0}, rotation={0,0,0}, height=350, width=800, ---- font_size=250, color={0,0,0}, font_color={0.75,0.75,1} ---- }) -end - ---Sends objects from bag/table to their saved position/rotation -function buttonClick_place() - local bagObjList = self.getObjects() - for guid, entry in pairs(memoryList) do - local obj = getObjectFromGUID(guid) - --If obj is out on the table, move it to the saved pos/rot - if obj ~= nil then - obj.setPositionSmooth(entry.pos) - obj.setRotationSmooth(entry.rot) - obj.setLock(entry.lock) - else - --If obj is inside of the bag - for _, bagObj in ipairs(bagObjList) do - if bagObj.guid == guid then - local item = self.takeObject({ - guid=guid, position=entry.pos, rotation=entry.rot, smooth=false - }) - item.setLock(entry.lock) - break - end - end - end - end - broadcastToAll("Objects Placed", {1,1,1}) -end - ---Recalls objects to bag from table -function buttonClick_recall() - for guid, entry in pairs(memoryList) do - local obj = getObjectFromGUID(guid) - if obj ~= nil then self.putObject(obj) end - end - broadcastToAll("Objects Recalled", {1,1,1}) -end - - ---Utility functions - - ---Find delta (difference) between 2 x/y/z coordinates -function findOffsetDistance(p1, p2, obj) - local yOffset = 0 - if obj ~= nil then - local bounds = obj.getBounds() - yOffset = (bounds.size.y - bounds.offset.y) - end - local deltaPos = {} - deltaPos.x = (p2.x-p1.x) - deltaPos.y = (p2.y-p1.y) + yOffset - deltaPos.z = (p2.z-p1.z) - return deltaPos -end - ---Used to rotate a set of coordinates by an angle -function rotateLocalCoordinates(desiredPos, obj) - local objPos, objRot = obj.getPosition(), obj.getRotation() - local angle = math.rad(objRot.y) - local x = desiredPos.x * math.cos(angle) - desiredPos.z * math.sin(angle) - local z = desiredPos.x * math.sin(angle) + desiredPos.z * math.cos(angle) - --return {x=objPos.x+x, y=objPos.y+desiredPos.y, z=objPos.z+z} - return {x=x, y=desiredPos.y, z=z} -end - -function rotateMyCoordinates(desiredPos, obj) - local angle = math.rad(obj.getRotation().y) - local x = desiredPos.x * math.sin(angle) - local z = desiredPos.z * math.cos(angle) - return {x=x, y=desiredPos.y, z=z} -end - ---Coroutine delay, in seconds -function wait(time) - local start = os.time() - repeat coroutine.yield(0) until os.time() > start + time -end - ---Duplicates a table (needed to prevent it making reference to the same objects) -function duplicateTable(oldTable) - local newTable = {} - for k, v in pairs(oldTable) do - newTable[k] = v - end - return newTable -end - ---Moves scripted highlight from all objects -function removeAllHighlights() - for _, obj in ipairs(getAllObjects()) do - obj.highlightOff() - end -end - ---Round number (num) to the Nth decimal (dec) -function round(num, dec) - local mult = 10^(dec or 0) - return math.floor(num * mult + 0.5) / mult -end diff --git a/src/MemoryBag.ttslua b/src/MemoryBag.ttslua new file mode 100644 index 00000000..ad8dbaff --- /dev/null +++ b/src/MemoryBag.ttslua @@ -0,0 +1,397 @@ +function updateSave() + self.script_state = JSON.encode({ ml = memoryList, setupButton = setupButton }) +end + +function onLoad(savedData) + if savedData and savedData ~= "" then + local loadedData = JSON.decode(savedData) + memoryList = loadedData.ml + setupButton = loadedData.setupButton + end + + memoryList = memoryList or {} + self.addContextMenuItem("Toggle setup button", toggleSetupButton) + + -- make sure the model is loaded so that we can use the bounds + Wait.condition(function() + Wait.frames(function() + generateButtonData() + createMemoryActionButtons() + end, 5) + end, function() return not self.loading_custom end) +end + +function generateButtonData() + local selfScale = self.getScale() + local selfBounds = self.getBoundsNormalized() + buttonScale = Vector(1 / selfScale.x, 1, 1 / selfScale.z) + + buttonX = math.max(selfBounds.size.x / 5, 1.5) / selfScale.x + buttonY = -(selfBounds.size.y / 2 + selfBounds.offset.y) / selfScale.y + 0.5 + buttonZ = {} + for i = 1, 4 do + buttonZ[i] = (selfBounds.size.z / 2 + i * 1.15 - 0.15) / selfScale.z + end + + local upperButtonMult = 1.1 + buttonData = { + ["Add"] = { + tooltip = "Add highlighted objects to memory", + pos = { buttonX * upperButtonMult, buttonY, -buttonZ[1] }, + fColor = { 0.25, 1, 0.25 } + }, + ["Cancel"] = { + tooltip = "Abort setup mode", + pos = { -buttonX * upperButtonMult, buttonY, -buttonZ[1] }, + }, + ["Internal"] = { + tooltip = "Copy memory from internal bags", + pos = { -buttonX * upperButtonMult, buttonY, -buttonZ[4] }, + }, + ["Place"] = { + pos = { buttonX, buttonY, buttonZ[1] }, + fSize = 350, + w = 1200 + }, + ["Recall"] = { + pos = { -buttonX, buttonY, buttonZ[1] }, + fSize = 350, + w = 1200 + }, + ["Remove"] = { + tooltip = "Remove highlighted objects from memory", + pos = { buttonX * upperButtonMult, buttonY, -buttonZ[2] }, + fColor = { 1, 0.25, 0.25 } + }, + ["Reset"] = { + tooltip = "Completely reset memory", + pos = { -buttonX * upperButtonMult, buttonY, -buttonZ[3] }, + }, + ["Selection"] = { + tooltip = "Add / Remove highlight for selected objects", + pos = { -buttonX * upperButtonMult, buttonY, -buttonZ[2] }, + }, + ["Setup"] = { + pos = { 0, buttonY, -buttonZ[1] }, + fSize = 350 + }, + ["Update"] = { + tooltip = "Update memory for placed objects", + pos = { buttonX * upperButtonMult, buttonY, -buttonZ[3] }, + fColor = { 0.75, 0.75, 1 } + } + } +end + +function createButtonByName(label) + self.createButton({ + label = label, + tooltip = buttonData[label].tooltip or "", + position = buttonData[label].pos, + height = buttonData[label].h or 500, + width = buttonData[label].w or 1500, + font_size = buttonData[label].fSize or 325, + font_color = buttonData[label].fColor or { 1, 1, 1 }, + function_owner = self, + color = { 0, 0, 0 }, + scale = buttonScale, + click_function = "buttonClick_" .. string.lower(string.gsub(label, "%s+", "")) + }) +end + +-- context menu function to toggle the setup button visibility +function toggleSetupButton() + if setupButton then + setupButton = false + broadcastToAll("Setup button disabled") + else + setupButton = true + broadcastToAll("Setup button enabled") + end + updateSave() + removeAllHighlights() + createMemoryActionButtons() +end + +function buttonClick_setup() + tempList = {} + self.clearButtons() + createButtonsOnAllObjects() + createSetupActionButtons() +end + +function createButtonsOnAllObjects() + buttonIndexMap = {} + + local buttonCount = 0 + for _, obj in ipairs(getObjects()) do + if obj ~= self and obj.type ~= "Scripting" and obj.type ~= "Hand" then + local objPos = obj.getPosition() + local objBounds = obj.getBounds() + local offSet = Vector(0, objBounds.size.y / 2 + 1, 0) + local scaleVec = Vector(-1, 1, 1) + local buttonPos = self.positionToLocal(objPos + offSet):scale(scaleVec) + + local fName = "selectButton_" .. buttonCount + _G[fName] = function() buttonClick_selectObject(obj) end + self.createButton({ + click_function = fName, + function_owner = self, + position = buttonPos, + height = 600, + width = 600, + color = { 0.75, 0.25, 0.25, 0.75 }, + scale = buttonScale + }) + buttonIndexMap[obj.getGUID()] = buttonCount + buttonCount = buttonCount + 1 + end + end +end + +function createSetupActionButtons() + createButtonByName("Cancel") + createButtonByName("Selection") + createButtonByName("Reset") + createButtonByName("Internal") + createButtonByName("Add") + + if next(memoryList) then + createButtonByName("Remove") + createButtonByName("Update") + end +end + +function buttonClick_selectObject(obj) + local guid = obj.getGUID() + local index = buttonIndexMap[guid] + if not index then return end + + if tempList[guid] == nil then + self.editButton({ index = index, color = { 0, 1, 0, 0.75 } }) + tempList[guid] = { + pos = roundVector(obj.getPosition(), 3), + rot = roundVector(obj.getRotation(), 0), + lock = obj.getLock() + } + obj.highlightOn({ 0, 1, 0 }) + else + self.editButton({ index = index, color = { 0.75, 0.25, 0.25, 0.75 } }) + tempList[guid] = nil + obj.highlightOff() + end +end + +function buttonClick_cancel() + broadcastToAll("Setup Canceled") + removeAllHighlights() + createMemoryActionButtons() +end + +function buttonClick_selection(_, playerColor) + local objList = Player[playerColor].getSelectedObjects() + + if #objList == 0 then + broadcastToAll("No objects selected!") + else + broadcastToAll("Toggled selection for " .. #objList .. " Object(s)") + for _, obj in ipairs(objList) do + buttonClick_selectObject(obj) + end + end +end + +function buttonClick_add() + local count = 0 + for _ in pairs(tempList) do + count = count + 1 + end + broadcastToAll("Added " .. count .. " Object(s) from selection") + + -- copy data from tempList to memoryList + for guid, entry in pairs(tempList) do + memoryList[guid] = entry + end + + updateSave() + removeAllHighlights() + createMemoryActionButtons() +end + +function buttonClick_update() + local count = 0 + for guid, entry in pairs(memoryList) do + local obj = getObjectFromGUID(guid) + if obj ~= nil then + count = count + 1 + memoryList[guid] = { + pos = roundVector(obj.getPosition(), 3), + rot = roundVector(obj.getRotation(), 0), + lock = obj.getLock() + } + end + end + broadcastToAll("Updated data for " .. count .. " Object(s)") + updateSave() +end + +function buttonClick_remove() + local count = 0 + for guid in pairs(tempList) do + count = count + 1 + memoryList[guid] = nil + end + broadcastToAll(count .. " Object(s) Removed", { 1, 1, 1 }) + + updateSave() + removeAllHighlights() + createMemoryActionButtons() +end + +function buttonClick_setNew() + local count = 0 + for _, obj in ipairs(getObjects()) do + if memoryList[obj.guid] then + count = count + 1 + memoryList[obj.guid].pos = roundVector(obj.getPosition(), 3) + memoryList[obj.guid].rot = roundVector(obj.getRotation(), 0) + memoryList[obj.guid].lock = obj.getLock() + end + end + broadcastToAll("Updated Data for " .. count .. " Object(s)", { 1, 1, 1 }) + updateSave() + createMemoryActionButtons() +end + +function buttonClick_reset() + memoryList = {} + updateSave() + removeAllHighlights() + broadcastToAll("Tool Reset", { 1, 1, 1 }) + self.clearButtons() + + if setupButton then + createButtonByName("Setup") + end +end + +function buttonClick_internal() + local count = 0 + for _, bagObj in ipairs(self.getObjects()) do + local data = bagObj.lua_script_state + if data ~= nil then + local j = JSON.decode(data) + if j ~= nil and j.ml ~= nil then + count = count + 1 + for guid, entry in pairs(j.ml) do + memoryList[guid] = entry + end + end + end + end + + if count > 0 then + broadcastToAll("Added " .. count .. " internal bag(s) to existing memory") + end +end + +function createMemoryActionButtons() + self.clearButtons() + + if next(memoryList) then + createButtonByName("Place") + createButtonByName("Recall") + end + + if setupButton then + createButtonByName("Setup") + end +end + +-- Sends objects from bag/table to their saved position/rotation +function buttonClick_place() + local data = self.getData() + + -- get names of contained objects + local guidToName = {} + for _, bagObjData in ipairs(data.ContainedObjects or {}) do + guidToName[bagObjData["GUID"]] = bagObjData["Nickname"] + end + + local updateGuids = {} + local placeCount = 0 + local moveCount = 0 + for guid, entry in pairs(memoryList) do + local obj = getObjectFromGUID(guid) + if obj ~= nil and (obj.getName() == guidToName[guid] or guidToName[guid] == nil) then + -- If obj is out on the table and has the same name (or there's no contained copy), move it + moveCount = moveCount + 1 + obj.setPositionSmooth(entry.pos) + obj.setRotationSmooth(entry.rot) + obj.setLock(entry.lock) + elseif guidToName[guid] then + -- If obj is inside of the bag + placeCount = placeCount + 1 + local item = self.takeObject({ + guid = guid, + position = entry.pos, + rotation = entry.rot, + smooth = false + }) + item.setLock(entry.lock) + + if obj ~= nil then + updateGuids[guid] = item.getGUID() + end + end + end + + -- update memoryList if we placed an item that got a new GUID + if next(updateGuids) then + for oldGuid, newGuid in pairs(updateGuids) do + memoryList[newGuid] = memoryList[oldGuid] + memoryList[oldGuid] = nil + end + updateSave() + end + + if placeCount > 0 then + broadcastToAll(placeCount .. " Object(s) Placed", { 1, 1, 1 }) + end + + if moveCount > 0 then + broadcastToAll(moveCount .. " Object(s) Moved", { 1, 1, 1 }) + end + + if placeCount == 0 and moveCount == 0 then + broadcastToAll("Bag is empty and no matching objects were found in play", { 1, 1, 1 }) + end +end + +function buttonClick_recall() + local count = 0 + for guid, _ in pairs(memoryList) do + local obj = getObjectFromGUID(guid) + if obj ~= nil then + self.putObject(obj) + count = count + 1 + end + end + broadcastToAll(count .. " Object(s) Recalled", { 1, 1, 1 }) +end + +function removeAllHighlights() + for _, obj in ipairs(getObjects()) do + obj.highlightOff() + end +end + +-- Round vector to the Nth decimal +function roundVector(vec, dec) + local mult = 10 ^ (dec or 0) + local t = {} + for _, k in ipairs({ "x", "y", "z" }) do + t[k] = math.floor(vec[k] * mult + 0.5) / mult + end + return t +end