@chrrxs/robloxstudio-mcp 2.23.1 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1688 -4547
- package/package.json +7 -5
- package/studio-plugin/MCPPlugin.rbxmx +489 -1965
- package/studio-plugin/.Carbon.rbxm.lock +0 -0
- package/studio-plugin/Carbon.rbxm +0 -0
- package/studio-plugin/INSTALLATION.md +0 -170
- package/studio-plugin/MCPInspectorPlugin.rbxmx +0 -171527
- package/studio-plugin/default.project.json +0 -19
- package/studio-plugin/dev.project.json +0 -23
- package/studio-plugin/include/LibMP.lua +0 -156378
- package/studio-plugin/inspector-icon.png +0 -0
- package/studio-plugin/package-lock.json +0 -706
- package/studio-plugin/package.json +0 -19
- package/studio-plugin/plugin.json +0 -10
- package/studio-plugin/src/modules/AssetSanitizationPolicy.ts +0 -127
- package/studio-plugin/src/modules/ClientBroker.ts +0 -450
- package/studio-plugin/src/modules/Communication.ts +0 -632
- package/studio-plugin/src/modules/EvalBridges.ts +0 -255
- package/studio-plugin/src/modules/HttpDiagnostics.ts +0 -50
- package/studio-plugin/src/modules/LuauExec.ts +0 -403
- package/studio-plugin/src/modules/Recording.ts +0 -28
- package/studio-plugin/src/modules/RenderMonitor.ts +0 -60
- package/studio-plugin/src/modules/RuntimeLogBuffer.ts +0 -210
- package/studio-plugin/src/modules/ServerUrlSettings.ts +0 -117
- package/studio-plugin/src/modules/State.ts +0 -39
- package/studio-plugin/src/modules/StopPlayMonitor.ts +0 -267
- package/studio-plugin/src/modules/UI.ts +0 -597
- package/studio-plugin/src/modules/Utils.ts +0 -469
- package/studio-plugin/src/modules/handlers/AssetHandlers.ts +0 -391
- package/studio-plugin/src/modules/handlers/BreakpointHandlers.ts +0 -460
- package/studio-plugin/src/modules/handlers/BuildHandlers.ts +0 -481
- package/studio-plugin/src/modules/handlers/CaptureHandlers.ts +0 -170
- package/studio-plugin/src/modules/handlers/EvalRuntimeHandlers.ts +0 -149
- package/studio-plugin/src/modules/handlers/GenerateModelHandlers.ts +0 -168
- package/studio-plugin/src/modules/handlers/InputHandlers.ts +0 -163
- package/studio-plugin/src/modules/handlers/InstanceHandlers.ts +0 -380
- package/studio-plugin/src/modules/handlers/LogHandlers.ts +0 -14
- package/studio-plugin/src/modules/handlers/MemoryHandlers.ts +0 -44
- package/studio-plugin/src/modules/handlers/MetadataHandlers.ts +0 -354
- package/studio-plugin/src/modules/handlers/MicroProfilerHandlers.ts +0 -1263
- package/studio-plugin/src/modules/handlers/PropertyHandlers.ts +0 -191
- package/studio-plugin/src/modules/handlers/QueryHandlers.ts +0 -874
- package/studio-plugin/src/modules/handlers/SceneAnalysisHandlers.ts +0 -216
- package/studio-plugin/src/modules/handlers/ScriptHandlers.ts +0 -530
- package/studio-plugin/src/modules/handlers/ScriptProfilerHandlers.ts +0 -386
- package/studio-plugin/src/modules/handlers/SerializationHandlers.ts +0 -172
- package/studio-plugin/src/modules/handlers/TestHandlers.ts +0 -350
- package/studio-plugin/src/server/index.server.ts +0 -135
- package/studio-plugin/src/types/index.d.ts +0 -57
- package/studio-plugin/tsconfig.json +0 -20
|
@@ -271,6 +271,7 @@ local MemoryHandlers = TS.import(script, script.Parent, "handlers", "MemoryHandl
|
|
|
271
271
|
local SceneAnalysisHandlers = TS.import(script, script.Parent, "handlers", "SceneAnalysisHandlers")
|
|
272
272
|
local CaptureHandlers = TS.import(script, script.Parent, "handlers", "CaptureHandlers")
|
|
273
273
|
local InputHandlers = TS.import(script, script.Parent, "handlers", "InputHandlers")
|
|
274
|
+
local MetadataHandlers = TS.import(script, script.Parent, "handlers", "MetadataHandlers")
|
|
274
275
|
local EvalRuntimeHandlers = TS.import(script, script.Parent, "handlers", "EvalRuntimeHandlers")
|
|
275
276
|
local BreakpointHandlers = TS.import(script, script.Parent, "handlers", "BreakpointHandlers")
|
|
276
277
|
local ScriptProfilerHandlers = TS.import(script, script.Parent, "handlers", "ScriptProfilerHandlers")
|
|
@@ -351,6 +352,7 @@ local CLIENT_BROKER_ALLOWED_ENDPOINTS = {
|
|
|
351
352
|
["/api/capture-begin"] = true,
|
|
352
353
|
["/api/simulate-mouse-input"] = true,
|
|
353
354
|
["/api/simulate-keyboard-input"] = true,
|
|
355
|
+
["/api/focus-viewport"] = true,
|
|
354
356
|
}
|
|
355
357
|
-- Throttle re-ready calls per proxyId so a brief window of unknownInstance
|
|
356
358
|
-- polls doesn't cause a re-register stampede.
|
|
@@ -559,6 +561,9 @@ local function setupClientBroker()
|
|
|
559
561
|
if payload and payload.endpoint == "/api/simulate-keyboard-input" then
|
|
560
562
|
return InputHandlers.simulateKeyboardInput(payload.data or {})
|
|
561
563
|
end
|
|
564
|
+
if payload and payload.endpoint == "/api/focus-viewport" then
|
|
565
|
+
return MetadataHandlers.focusViewport(payload.data or {})
|
|
566
|
+
end
|
|
562
567
|
if payload and payload.endpoint == "/api/execute-luau" then
|
|
563
568
|
return handleExecuteLuau(payload.data)
|
|
564
569
|
end
|
|
@@ -778,11 +783,9 @@ local UI = TS.import(script, script.Parent, "UI")
|
|
|
778
783
|
local cleanupLegacyEditBridges = TS.import(script, script.Parent, "EvalBridges").cleanupLegacyEditBridges
|
|
779
784
|
local QueryHandlers = TS.import(script, script.Parent, "handlers", "QueryHandlers")
|
|
780
785
|
local PropertyHandlers = TS.import(script, script.Parent, "handlers", "PropertyHandlers")
|
|
781
|
-
local InstanceHandlers = TS.import(script, script.Parent, "handlers", "InstanceHandlers")
|
|
782
786
|
local ScriptHandlers = TS.import(script, script.Parent, "handlers", "ScriptHandlers")
|
|
783
787
|
local MetadataHandlers = TS.import(script, script.Parent, "handlers", "MetadataHandlers")
|
|
784
788
|
local TestHandlers = TS.import(script, script.Parent, "handlers", "TestHandlers")
|
|
785
|
-
local BuildHandlers = TS.import(script, script.Parent, "handlers", "BuildHandlers")
|
|
786
789
|
local AssetHandlers = TS.import(script, script.Parent, "handlers", "AssetHandlers")
|
|
787
790
|
local CaptureHandlers = TS.import(script, script.Parent, "handlers", "CaptureHandlers")
|
|
788
791
|
local InputHandlers = TS.import(script, script.Parent, "handlers", "InputHandlers")
|
|
@@ -873,45 +876,24 @@ local routeMap = {
|
|
|
873
876
|
["/api/file-tree"] = QueryHandlers.getFileTree,
|
|
874
877
|
["/api/search-files"] = QueryHandlers.searchFiles,
|
|
875
878
|
["/api/place-info"] = QueryHandlers.getPlaceInfo,
|
|
876
|
-
["/api/services"] = QueryHandlers.getServices,
|
|
877
879
|
["/api/search-objects"] = QueryHandlers.searchObjects,
|
|
878
880
|
["/api/instance-properties"] = QueryHandlers.getInstanceProperties,
|
|
879
|
-
["/api/instance-children"] = QueryHandlers.getInstanceChildren,
|
|
880
881
|
["/api/search-by-property"] = QueryHandlers.searchByProperty,
|
|
881
882
|
["/api/class-info"] = QueryHandlers.getClassInfo,
|
|
882
883
|
["/api/project-structure"] = QueryHandlers.getProjectStructure,
|
|
883
884
|
["/api/grep-scripts"] = QueryHandlers.grepScripts,
|
|
884
|
-
["/api/get-descendants"] = QueryHandlers.getDescendants,
|
|
885
|
-
["/api/compare-instances"] = QueryHandlers.compareInstances,
|
|
886
|
-
["/api/set-property"] = PropertyHandlers.setProperty,
|
|
887
885
|
["/api/set-properties"] = PropertyHandlers.setProperties,
|
|
888
|
-
["/api/mass-set-property"] = PropertyHandlers.massSetProperty,
|
|
889
|
-
["/api/mass-get-property"] = PropertyHandlers.massGetProperty,
|
|
890
|
-
["/api/create-object"] = InstanceHandlers.createObject,
|
|
891
|
-
["/api/mass-create-objects"] = InstanceHandlers.massCreateObjects,
|
|
892
|
-
["/api/mass-create-objects-with-properties"] = InstanceHandlers.massCreateObjects,
|
|
893
|
-
["/api/delete-object"] = InstanceHandlers.deleteObject,
|
|
894
|
-
["/api/smart-duplicate"] = InstanceHandlers.smartDuplicate,
|
|
895
|
-
["/api/mass-duplicate"] = InstanceHandlers.massDuplicate,
|
|
896
|
-
["/api/clone-object"] = InstanceHandlers.cloneObject,
|
|
897
886
|
["/api/get-script-source"] = ScriptHandlers.getScriptSource,
|
|
898
887
|
["/api/set-script-source"] = ScriptHandlers.setScriptSource,
|
|
899
888
|
["/api/edit-script-lines"] = ScriptHandlers.editScriptLines,
|
|
900
889
|
["/api/insert-script-lines"] = ScriptHandlers.insertScriptLines,
|
|
901
890
|
["/api/delete-script-lines"] = ScriptHandlers.deleteScriptLines,
|
|
902
|
-
["/api/set-attribute"] = MetadataHandlers.setAttribute,
|
|
903
891
|
["/api/get-attributes"] = MetadataHandlers.getAttributes,
|
|
904
|
-
["/api/delete-attribute"] = MetadataHandlers.deleteAttribute,
|
|
905
|
-
["/api/get-tags"] = MetadataHandlers.getTags,
|
|
906
|
-
["/api/add-tag"] = MetadataHandlers.addTag,
|
|
907
|
-
["/api/remove-tag"] = MetadataHandlers.removeTag,
|
|
908
|
-
["/api/get-tagged"] = MetadataHandlers.getTagged,
|
|
909
892
|
["/api/get-selection"] = MetadataHandlers.getSelection,
|
|
893
|
+
["/api/set-selection"] = MetadataHandlers.setSelection,
|
|
894
|
+
["/api/focus-viewport"] = MetadataHandlers.focusViewport,
|
|
910
895
|
["/api/execute-luau"] = MetadataHandlers.executeLuau,
|
|
911
896
|
["/api/eval-runtime"] = EvalRuntimeHandlers.evalRuntime,
|
|
912
|
-
["/api/undo"] = MetadataHandlers.undo,
|
|
913
|
-
["/api/redo"] = MetadataHandlers.redo,
|
|
914
|
-
["/api/bulk-set-attributes"] = MetadataHandlers.bulkSetAttributes,
|
|
915
897
|
["/api/start-playtest"] = TestHandlers.startPlaytest,
|
|
916
898
|
["/api/stop-playtest"] = TestHandlers.stopPlaytest,
|
|
917
899
|
["/api/multiplayer-test-start"] = TestHandlers.multiplayerTestStart,
|
|
@@ -919,10 +901,6 @@ local routeMap = {
|
|
|
919
901
|
["/api/multiplayer-test-add-players"] = TestHandlers.multiplayerTestAddPlayers,
|
|
920
902
|
["/api/multiplayer-test-leave-client"] = TestHandlers.multiplayerTestLeaveClient,
|
|
921
903
|
["/api/multiplayer-test-end"] = TestHandlers.multiplayerTestEnd,
|
|
922
|
-
["/api/export-build"] = BuildHandlers.exportBuild,
|
|
923
|
-
["/api/import-build"] = BuildHandlers.importBuild,
|
|
924
|
-
["/api/import-scene"] = BuildHandlers.importScene,
|
|
925
|
-
["/api/search-materials"] = BuildHandlers.searchMaterials,
|
|
926
904
|
["/api/insert-asset"] = AssetHandlers.insertAsset,
|
|
927
905
|
["/api/preview-asset"] = AssetHandlers.previewAsset,
|
|
928
906
|
["/api/capture-screenshot"] = CaptureHandlers.captureScreenshot,
|
|
@@ -1550,9 +1528,9 @@ local function computeBridgeStamp()
|
|
|
1550
1528
|
for i = 1, #combined do
|
|
1551
1529
|
h = (h * 33 + (string.byte(combined, i))) % 2147483647
|
|
1552
1530
|
end
|
|
1553
|
-
-- "
|
|
1531
|
+
-- "3.0.1" is replaced with the package version at package time
|
|
1554
1532
|
-- (scripts/build-plugin.mjs injectVersion), so a release bump also restamps.
|
|
1555
|
-
return `{tostring(h)}-
|
|
1533
|
+
return `{tostring(h)}-3.0.1`
|
|
1556
1534
|
end
|
|
1557
1535
|
local BRIDGE_STAMP = computeBridgeStamp()
|
|
1558
1536
|
local function setSource(scriptInst, source)
|
|
@@ -2669,571 +2647,6 @@ return {
|
|
|
2669
2647
|
</Properties>
|
|
2670
2648
|
</Item>
|
|
2671
2649
|
<Item class="ModuleScript" referent="9">
|
|
2672
|
-
<Properties>
|
|
2673
|
-
<string name="Name">BuildHandlers</string>
|
|
2674
|
-
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
2675
|
-
local TS = require(script.Parent.Parent.Parent.include.RuntimeLib)
|
|
2676
|
-
local Utils = TS.import(script, script.Parent.Parent, "Utils")
|
|
2677
|
-
local Recording = TS.import(script, script.Parent.Parent, "Recording")
|
|
2678
|
-
local MaterialService = game:GetService("MaterialService")
|
|
2679
|
-
local _binding = Utils
|
|
2680
|
-
local getInstancePath = _binding.getInstancePath
|
|
2681
|
-
local getInstanceByPath = _binding.getInstanceByPath
|
|
2682
|
-
local _binding_1 = Recording
|
|
2683
|
-
local beginRecording = _binding_1.beginRecording
|
|
2684
|
-
local finishRecording = _binding_1.finishRecording
|
|
2685
|
-
local MATERIAL_BY_NAME = {}
|
|
2686
|
-
for _, enumItem in Enum.Material:GetEnumItems() do
|
|
2687
|
-
local _name = enumItem.Name
|
|
2688
|
-
MATERIAL_BY_NAME[_name] = enumItem
|
|
2689
|
-
end
|
|
2690
|
-
-- Shape class mapping
|
|
2691
|
-
local SHAPE_CLASSES = {
|
|
2692
|
-
Block = "Part",
|
|
2693
|
-
Wedge = "WedgePart",
|
|
2694
|
-
Cylinder = "Part",
|
|
2695
|
-
Ball = "Part",
|
|
2696
|
-
CornerWedge = "CornerWedgePart",
|
|
2697
|
-
}
|
|
2698
|
-
local PALETTE_KEYS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
2699
|
-
local function roundTo(n, decimals)
|
|
2700
|
-
local mult = 10 ^ decimals
|
|
2701
|
-
return math.round(n * mult) / mult
|
|
2702
|
-
end
|
|
2703
|
-
local function encodePaletteKey(index)
|
|
2704
|
-
local base = #PALETTE_KEYS
|
|
2705
|
-
local value = math.floor(index) + 1
|
|
2706
|
-
local encoded = ""
|
|
2707
|
-
while value > 0 do
|
|
2708
|
-
value -= 1
|
|
2709
|
-
local digit = value % base
|
|
2710
|
-
local _arg0 = digit + 1
|
|
2711
|
-
local _arg1 = digit + 1
|
|
2712
|
-
encoded = string.sub(PALETTE_KEYS, _arg0, _arg1) .. encoded
|
|
2713
|
-
value = math.floor(value / base)
|
|
2714
|
-
end
|
|
2715
|
-
return encoded
|
|
2716
|
-
end
|
|
2717
|
-
local function getVariantName(part)
|
|
2718
|
-
local variantName = part.MaterialVariant
|
|
2719
|
-
if variantName == "" then
|
|
2720
|
-
local ok, variantAttr = pcall(function()
|
|
2721
|
-
return part:GetAttribute("MaterialVariant")
|
|
2722
|
-
end)
|
|
2723
|
-
if ok and type(variantAttr) == "string" then
|
|
2724
|
-
variantName = variantAttr
|
|
2725
|
-
end
|
|
2726
|
-
end
|
|
2727
|
-
return variantName
|
|
2728
|
-
end
|
|
2729
|
-
local function exportBuild(requestData)
|
|
2730
|
-
local instancePath = requestData.instancePath
|
|
2731
|
-
local outputId = requestData.outputId
|
|
2732
|
-
local _condition = (requestData.style)
|
|
2733
|
-
if _condition == nil then
|
|
2734
|
-
_condition = "misc"
|
|
2735
|
-
end
|
|
2736
|
-
local style = _condition
|
|
2737
|
-
if not (instancePath ~= "" and instancePath) then
|
|
2738
|
-
return {
|
|
2739
|
-
error = "Instance path is required",
|
|
2740
|
-
}
|
|
2741
|
-
end
|
|
2742
|
-
local instance = getInstanceByPath(instancePath)
|
|
2743
|
-
if not instance then
|
|
2744
|
-
return {
|
|
2745
|
-
error = `Instance not found: {instancePath}`,
|
|
2746
|
-
}
|
|
2747
|
-
end
|
|
2748
|
-
if not instance:IsA("Model") and not instance:IsA("Folder") then
|
|
2749
|
-
return {
|
|
2750
|
-
error = "Instance must be a Model or Folder",
|
|
2751
|
-
}
|
|
2752
|
-
end
|
|
2753
|
-
local success, result = pcall(function()
|
|
2754
|
-
local descendants = instance:GetDescendants()
|
|
2755
|
-
local baseParts = {}
|
|
2756
|
-
for _, desc in descendants do
|
|
2757
|
-
if desc:IsA("BasePart") then
|
|
2758
|
-
table.insert(baseParts, desc)
|
|
2759
|
-
end
|
|
2760
|
-
end
|
|
2761
|
-
if #baseParts == 0 then
|
|
2762
|
-
return {
|
|
2763
|
-
error = "No BaseParts found in instance",
|
|
2764
|
-
}
|
|
2765
|
-
end
|
|
2766
|
-
-- Compute bounding box center
|
|
2767
|
-
local minX = math.huge
|
|
2768
|
-
local minY = math.huge
|
|
2769
|
-
local minZ = math.huge
|
|
2770
|
-
local maxX = -math.huge
|
|
2771
|
-
local maxY = -math.huge
|
|
2772
|
-
local maxZ = -math.huge
|
|
2773
|
-
for _, part in baseParts do
|
|
2774
|
-
local pos = part.Position
|
|
2775
|
-
local sz = part.Size
|
|
2776
|
-
local halfX = sz.X / 2
|
|
2777
|
-
local halfY = sz.Y / 2
|
|
2778
|
-
local halfZ = sz.Z / 2
|
|
2779
|
-
minX = math.min(minX, pos.X - halfX)
|
|
2780
|
-
minY = math.min(minY, pos.Y - halfY)
|
|
2781
|
-
minZ = math.min(minZ, pos.Z - halfZ)
|
|
2782
|
-
maxX = math.max(maxX, pos.X + halfX)
|
|
2783
|
-
maxY = math.max(maxY, pos.Y + halfY)
|
|
2784
|
-
maxZ = math.max(maxZ, pos.Z + halfZ)
|
|
2785
|
-
end
|
|
2786
|
-
local centerX = (minX + maxX) / 2
|
|
2787
|
-
local centerY = minY
|
|
2788
|
-
local centerZ = (minZ + maxZ) / 2
|
|
2789
|
-
local boundsX = roundTo(maxX - minX, 1)
|
|
2790
|
-
local boundsY = roundTo(maxY - minY, 1)
|
|
2791
|
-
local boundsZ = roundTo(maxZ - minZ, 1)
|
|
2792
|
-
-- Build palette from unique (BrickColor, Material, MaterialVariant?) combos
|
|
2793
|
-
local paletteMap = {}
|
|
2794
|
-
local palette = {}
|
|
2795
|
-
local keyIndex = 0
|
|
2796
|
-
for _, part in baseParts do
|
|
2797
|
-
local colorName = part.BrickColor.Name
|
|
2798
|
-
local materialName = part.Material.Name
|
|
2799
|
-
local variantName = getVariantName(part)
|
|
2800
|
-
local combo = if variantName ~= "" then `{colorName}|{materialName}|{variantName}` else `{colorName}|{materialName}`
|
|
2801
|
-
if not (paletteMap[combo] ~= nil) then
|
|
2802
|
-
local key = encodePaletteKey(keyIndex)
|
|
2803
|
-
keyIndex += 1
|
|
2804
|
-
paletteMap[combo] = key
|
|
2805
|
-
if variantName ~= "" then
|
|
2806
|
-
palette[key] = { colorName, materialName, variantName }
|
|
2807
|
-
else
|
|
2808
|
-
palette[key] = { colorName, materialName }
|
|
2809
|
-
end
|
|
2810
|
-
end
|
|
2811
|
-
end
|
|
2812
|
-
-- Build compact part arrays
|
|
2813
|
-
local parts = {}
|
|
2814
|
-
for _, part in baseParts do
|
|
2815
|
-
local pos = part.Position
|
|
2816
|
-
local orient = part.Orientation
|
|
2817
|
-
local sz = part.Size
|
|
2818
|
-
local colorName = part.BrickColor.Name
|
|
2819
|
-
local materialName = part.Material.Name
|
|
2820
|
-
local variantName = getVariantName(part)
|
|
2821
|
-
local combo = if variantName ~= "" then `{colorName}|{materialName}|{variantName}` else `{colorName}|{materialName}`
|
|
2822
|
-
local _condition_1 = paletteMap[combo]
|
|
2823
|
-
if _condition_1 == nil then
|
|
2824
|
-
_condition_1 = "a"
|
|
2825
|
-
end
|
|
2826
|
-
local paletteKey = _condition_1
|
|
2827
|
-
-- Relative position to center
|
|
2828
|
-
local relX = roundTo(pos.X - centerX, 1)
|
|
2829
|
-
local relY = roundTo(pos.Y - centerY, 1)
|
|
2830
|
-
local relZ = roundTo(pos.Z - centerZ, 1)
|
|
2831
|
-
local sizeX = roundTo(sz.X, 1)
|
|
2832
|
-
local sizeY = roundTo(sz.Y, 1)
|
|
2833
|
-
local sizeZ = roundTo(sz.Z, 1)
|
|
2834
|
-
local rotX = roundTo(orient.X, 1)
|
|
2835
|
-
local rotY = roundTo(orient.Y, 1)
|
|
2836
|
-
local rotZ = roundTo(orient.Z, 1)
|
|
2837
|
-
-- Determine shape
|
|
2838
|
-
local shape = "Block"
|
|
2839
|
-
if part:IsA("WedgePart") then
|
|
2840
|
-
shape = "Wedge"
|
|
2841
|
-
elseif part:IsA("CornerWedgePart") then
|
|
2842
|
-
shape = "CornerWedge"
|
|
2843
|
-
elseif part:IsA("Part") then
|
|
2844
|
-
local p = part
|
|
2845
|
-
if p.Shape == Enum.PartType.Cylinder then
|
|
2846
|
-
shape = "Cylinder"
|
|
2847
|
-
elseif p.Shape == Enum.PartType.Ball then
|
|
2848
|
-
shape = "Ball"
|
|
2849
|
-
end
|
|
2850
|
-
end
|
|
2851
|
-
-- Build part array with optional trailing fields
|
|
2852
|
-
local hasTransparency = part.Transparency > 0
|
|
2853
|
-
local hasShape = shape ~= "Block"
|
|
2854
|
-
local partArr
|
|
2855
|
-
if hasTransparency then
|
|
2856
|
-
partArr = { relX, relY, relZ, sizeX, sizeY, sizeZ, rotX, rotY, rotZ, paletteKey, if hasShape then shape else "Block", roundTo(part.Transparency, 2) }
|
|
2857
|
-
elseif hasShape then
|
|
2858
|
-
partArr = { relX, relY, relZ, sizeX, sizeY, sizeZ, rotX, rotY, rotZ, paletteKey, shape }
|
|
2859
|
-
else
|
|
2860
|
-
partArr = { relX, relY, relZ, sizeX, sizeY, sizeZ, rotX, rotY, rotZ, paletteKey }
|
|
2861
|
-
end
|
|
2862
|
-
local _partArr = partArr
|
|
2863
|
-
table.insert(parts, _partArr)
|
|
2864
|
-
end
|
|
2865
|
-
local _condition_1 = outputId
|
|
2866
|
-
if _condition_1 == nil then
|
|
2867
|
-
_condition_1 = `{style}/{(string.gsub(string.lower(instance.Name), " ", "_"))}`
|
|
2868
|
-
end
|
|
2869
|
-
local buildId = _condition_1
|
|
2870
|
-
return {
|
|
2871
|
-
success = true,
|
|
2872
|
-
buildData = {
|
|
2873
|
-
id = buildId,
|
|
2874
|
-
style = style,
|
|
2875
|
-
bounds = { boundsX, boundsY, boundsZ },
|
|
2876
|
-
palette = palette,
|
|
2877
|
-
parts = parts,
|
|
2878
|
-
},
|
|
2879
|
-
}
|
|
2880
|
-
end)
|
|
2881
|
-
if success and result then
|
|
2882
|
-
return result
|
|
2883
|
-
else
|
|
2884
|
-
return {
|
|
2885
|
-
error = `Failed to export build: {result}`,
|
|
2886
|
-
}
|
|
2887
|
-
end
|
|
2888
|
-
end
|
|
2889
|
-
local function importBuild(requestData)
|
|
2890
|
-
local buildData = requestData.buildData
|
|
2891
|
-
local targetPath = requestData.targetPath
|
|
2892
|
-
local positionOffset = (requestData.position) or { 0, 0, 0 }
|
|
2893
|
-
if not buildData or not (targetPath ~= "" and targetPath) then
|
|
2894
|
-
return {
|
|
2895
|
-
error = "buildData and targetPath are required",
|
|
2896
|
-
}
|
|
2897
|
-
end
|
|
2898
|
-
local parentInstance = getInstanceByPath(targetPath)
|
|
2899
|
-
if not parentInstance then
|
|
2900
|
-
return {
|
|
2901
|
-
error = `Target not found: {targetPath}`,
|
|
2902
|
-
}
|
|
2903
|
-
end
|
|
2904
|
-
local recordingId = beginRecording("Import build")
|
|
2905
|
-
local success, result = pcall(function()
|
|
2906
|
-
local palette = buildData.palette
|
|
2907
|
-
local parts = buildData.parts
|
|
2908
|
-
local _condition = (buildData.id)
|
|
2909
|
-
if _condition == nil then
|
|
2910
|
-
_condition = "imported_build"
|
|
2911
|
-
end
|
|
2912
|
-
local buildId = _condition
|
|
2913
|
-
-- Create model container
|
|
2914
|
-
local model = Instance.new("Model")
|
|
2915
|
-
local _condition_1 = (string.match(buildId, "[^/]+$"))
|
|
2916
|
-
if _condition_1 == nil then
|
|
2917
|
-
_condition_1 = buildId
|
|
2918
|
-
end
|
|
2919
|
-
model.Name = _condition_1
|
|
2920
|
-
local partCount = 0
|
|
2921
|
-
for _, partArr in parts do
|
|
2922
|
-
local _exp = (partArr[1])
|
|
2923
|
-
local _condition_2 = positionOffset[1]
|
|
2924
|
-
if _condition_2 == nil then
|
|
2925
|
-
_condition_2 = 0
|
|
2926
|
-
end
|
|
2927
|
-
local posX = _exp + _condition_2
|
|
2928
|
-
local _exp_1 = (partArr[2])
|
|
2929
|
-
local _condition_3 = positionOffset[2]
|
|
2930
|
-
if _condition_3 == nil then
|
|
2931
|
-
_condition_3 = 0
|
|
2932
|
-
end
|
|
2933
|
-
local posY = _exp_1 + _condition_3
|
|
2934
|
-
local _exp_2 = (partArr[3])
|
|
2935
|
-
local _condition_4 = positionOffset[3]
|
|
2936
|
-
if _condition_4 == nil then
|
|
2937
|
-
_condition_4 = 0
|
|
2938
|
-
end
|
|
2939
|
-
local posZ = _exp_2 + _condition_4
|
|
2940
|
-
local sizeX = partArr[4]
|
|
2941
|
-
local sizeY = partArr[5]
|
|
2942
|
-
local sizeZ = partArr[6]
|
|
2943
|
-
local rotX = partArr[7]
|
|
2944
|
-
local rotY = partArr[8]
|
|
2945
|
-
local rotZ = partArr[9]
|
|
2946
|
-
local paletteKey = partArr[10]
|
|
2947
|
-
local _condition_5 = (partArr[11])
|
|
2948
|
-
if _condition_5 == nil then
|
|
2949
|
-
_condition_5 = "Block"
|
|
2950
|
-
end
|
|
2951
|
-
local shape = _condition_5
|
|
2952
|
-
local _condition_6 = (partArr[12])
|
|
2953
|
-
if _condition_6 == nil then
|
|
2954
|
-
_condition_6 = 0
|
|
2955
|
-
end
|
|
2956
|
-
local transparency = _condition_6
|
|
2957
|
-
-- Determine class from shape
|
|
2958
|
-
local _condition_7 = SHAPE_CLASSES[shape]
|
|
2959
|
-
if _condition_7 == nil then
|
|
2960
|
-
_condition_7 = "Part"
|
|
2961
|
-
end
|
|
2962
|
-
local className = _condition_7
|
|
2963
|
-
local part = Instance.new(className)
|
|
2964
|
-
-- Set shape for Part instances with non-Block shapes
|
|
2965
|
-
if className == "Part" and shape ~= "Block" then
|
|
2966
|
-
if shape == "Cylinder" then
|
|
2967
|
-
part.Shape = Enum.PartType.Cylinder
|
|
2968
|
-
elseif shape == "Ball" then
|
|
2969
|
-
part.Shape = Enum.PartType.Ball
|
|
2970
|
-
end
|
|
2971
|
-
end
|
|
2972
|
-
part.Size = Vector3.new(sizeX, sizeY, sizeZ)
|
|
2973
|
-
part.Position = Vector3.new(posX, posY, posZ)
|
|
2974
|
-
part.Orientation = Vector3.new(rotX, rotY, rotZ)
|
|
2975
|
-
part.Anchored = true
|
|
2976
|
-
if transparency > 0 then
|
|
2977
|
-
part.Transparency = transparency
|
|
2978
|
-
end
|
|
2979
|
-
-- Apply palette
|
|
2980
|
-
local paletteEntry = palette[paletteKey]
|
|
2981
|
-
if paletteEntry then
|
|
2982
|
-
local _binding_2 = paletteEntry
|
|
2983
|
-
local colorName = _binding_2[1]
|
|
2984
|
-
local materialName = _binding_2[2]
|
|
2985
|
-
local variantName = _binding_2[3]
|
|
2986
|
-
pcall(function()
|
|
2987
|
-
part.BrickColor = BrickColor.new(colorName)
|
|
2988
|
-
end)
|
|
2989
|
-
pcall(function()
|
|
2990
|
-
local mat = MATERIAL_BY_NAME[materialName]
|
|
2991
|
-
if mat ~= nil then
|
|
2992
|
-
part.Material = mat
|
|
2993
|
-
end
|
|
2994
|
-
end)
|
|
2995
|
-
-- Apply MaterialVariant if specified
|
|
2996
|
-
if variantName ~= nil and variantName ~= "" then
|
|
2997
|
-
pcall(function()
|
|
2998
|
-
part.MaterialVariant = variantName
|
|
2999
|
-
end)
|
|
3000
|
-
end
|
|
3001
|
-
end
|
|
3002
|
-
part.Parent = model
|
|
3003
|
-
partCount += 1
|
|
3004
|
-
end
|
|
3005
|
-
model.Parent = parentInstance
|
|
3006
|
-
return {
|
|
3007
|
-
success = true,
|
|
3008
|
-
partCount = partCount,
|
|
3009
|
-
modelPath = getInstancePath(model),
|
|
3010
|
-
}
|
|
3011
|
-
end)
|
|
3012
|
-
if success and result then
|
|
3013
|
-
finishRecording(recordingId, true)
|
|
3014
|
-
return result
|
|
3015
|
-
else
|
|
3016
|
-
finishRecording(recordingId, false)
|
|
3017
|
-
return {
|
|
3018
|
-
error = `Failed to import build: {result}`,
|
|
3019
|
-
}
|
|
3020
|
-
end
|
|
3021
|
-
end
|
|
3022
|
-
local function importScene(requestData)
|
|
3023
|
-
local expandedBuilds = requestData.expandedBuilds
|
|
3024
|
-
local _condition = (requestData.targetPath)
|
|
3025
|
-
if _condition == nil then
|
|
3026
|
-
_condition = "game.Workspace"
|
|
3027
|
-
end
|
|
3028
|
-
local targetPath = _condition
|
|
3029
|
-
if not expandedBuilds or not (type(expandedBuilds) == "table") or #expandedBuilds == 0 then
|
|
3030
|
-
return {
|
|
3031
|
-
error = "expandedBuilds array is required",
|
|
3032
|
-
}
|
|
3033
|
-
end
|
|
3034
|
-
local parentInstance = getInstanceByPath(targetPath)
|
|
3035
|
-
if not parentInstance then
|
|
3036
|
-
return {
|
|
3037
|
-
error = `Target not found: {targetPath}`,
|
|
3038
|
-
}
|
|
3039
|
-
end
|
|
3040
|
-
local recordingId = beginRecording("Import scene")
|
|
3041
|
-
local success, result = pcall(function()
|
|
3042
|
-
local modelCount = 0
|
|
3043
|
-
local totalParts = 0
|
|
3044
|
-
local models = {}
|
|
3045
|
-
for _, entry in expandedBuilds do
|
|
3046
|
-
local buildData = entry.buildData
|
|
3047
|
-
local position = (entry.position) or { 0, 0, 0 }
|
|
3048
|
-
local rotation = (entry.rotation) or { 0, 0, 0 }
|
|
3049
|
-
local _condition_1 = (entry.name)
|
|
3050
|
-
if _condition_1 == nil then
|
|
3051
|
-
_condition_1 = "SceneModel"
|
|
3052
|
-
end
|
|
3053
|
-
local name = _condition_1
|
|
3054
|
-
local palette = buildData.palette
|
|
3055
|
-
local parts = buildData.parts
|
|
3056
|
-
local model = Instance.new("Model")
|
|
3057
|
-
model.Name = name
|
|
3058
|
-
local _condition_2 = rotation[1]
|
|
3059
|
-
if _condition_2 == nil then
|
|
3060
|
-
_condition_2 = 0
|
|
3061
|
-
end
|
|
3062
|
-
local _exp = math.rad(_condition_2)
|
|
3063
|
-
local _condition_3 = rotation[2]
|
|
3064
|
-
if _condition_3 == nil then
|
|
3065
|
-
_condition_3 = 0
|
|
3066
|
-
end
|
|
3067
|
-
local _exp_1 = math.rad(_condition_3)
|
|
3068
|
-
local _condition_4 = rotation[3]
|
|
3069
|
-
if _condition_4 == nil then
|
|
3070
|
-
_condition_4 = 0
|
|
3071
|
-
end
|
|
3072
|
-
local rotCF = CFrame.Angles(_exp, _exp_1, math.rad(_condition_4))
|
|
3073
|
-
local _condition_5 = position[1]
|
|
3074
|
-
if _condition_5 == nil then
|
|
3075
|
-
_condition_5 = 0
|
|
3076
|
-
end
|
|
3077
|
-
local _condition_6 = position[2]
|
|
3078
|
-
if _condition_6 == nil then
|
|
3079
|
-
_condition_6 = 0
|
|
3080
|
-
end
|
|
3081
|
-
local _condition_7 = position[3]
|
|
3082
|
-
if _condition_7 == nil then
|
|
3083
|
-
_condition_7 = 0
|
|
3084
|
-
end
|
|
3085
|
-
local originCF = CFrame.new(_condition_5, _condition_6, _condition_7) * rotCF
|
|
3086
|
-
local partCount = 0
|
|
3087
|
-
for _1, partArr in parts do
|
|
3088
|
-
local localX = partArr[1]
|
|
3089
|
-
local localY = partArr[2]
|
|
3090
|
-
local localZ = partArr[3]
|
|
3091
|
-
local sizeX = partArr[4]
|
|
3092
|
-
local sizeY = partArr[5]
|
|
3093
|
-
local sizeZ = partArr[6]
|
|
3094
|
-
local rotX = partArr[7]
|
|
3095
|
-
local rotY = partArr[8]
|
|
3096
|
-
local rotZ = partArr[9]
|
|
3097
|
-
local paletteKey = partArr[10]
|
|
3098
|
-
local _condition_8 = (partArr[11])
|
|
3099
|
-
if _condition_8 == nil then
|
|
3100
|
-
_condition_8 = "Block"
|
|
3101
|
-
end
|
|
3102
|
-
local shape = _condition_8
|
|
3103
|
-
local _condition_9 = (partArr[12])
|
|
3104
|
-
if _condition_9 == nil then
|
|
3105
|
-
_condition_9 = 0
|
|
3106
|
-
end
|
|
3107
|
-
local transparency = _condition_9
|
|
3108
|
-
local _condition_10 = SHAPE_CLASSES[shape]
|
|
3109
|
-
if _condition_10 == nil then
|
|
3110
|
-
_condition_10 = "Part"
|
|
3111
|
-
end
|
|
3112
|
-
local className = _condition_10
|
|
3113
|
-
local part = Instance.new(className)
|
|
3114
|
-
if className == "Part" and shape ~= "Block" then
|
|
3115
|
-
if shape == "Cylinder" then
|
|
3116
|
-
part.Shape = Enum.PartType.Cylinder
|
|
3117
|
-
elseif shape == "Ball" then
|
|
3118
|
-
part.Shape = Enum.PartType.Ball
|
|
3119
|
-
end
|
|
3120
|
-
end
|
|
3121
|
-
part.Size = Vector3.new(sizeX, sizeY, sizeZ)
|
|
3122
|
-
-- Apply local rotation then world transform
|
|
3123
|
-
local localRotCF = CFrame.Angles(math.rad(rotX), math.rad(rotY), math.rad(rotZ))
|
|
3124
|
-
local localPosCF = CFrame.new(localX, localY, localZ) * localRotCF
|
|
3125
|
-
local worldCF = originCF * localPosCF
|
|
3126
|
-
part.CFrame = worldCF
|
|
3127
|
-
part.Anchored = true
|
|
3128
|
-
if transparency > 0 then
|
|
3129
|
-
part.Transparency = transparency
|
|
3130
|
-
end
|
|
3131
|
-
local paletteEntry = palette[paletteKey]
|
|
3132
|
-
if paletteEntry then
|
|
3133
|
-
local _binding_2 = paletteEntry
|
|
3134
|
-
local colorName = _binding_2[1]
|
|
3135
|
-
local materialName = _binding_2[2]
|
|
3136
|
-
local variantName = _binding_2[3]
|
|
3137
|
-
pcall(function()
|
|
3138
|
-
part.BrickColor = BrickColor.new(colorName)
|
|
3139
|
-
end)
|
|
3140
|
-
pcall(function()
|
|
3141
|
-
local mat = MATERIAL_BY_NAME[materialName]
|
|
3142
|
-
if mat ~= nil then
|
|
3143
|
-
part.Material = mat
|
|
3144
|
-
end
|
|
3145
|
-
end)
|
|
3146
|
-
if variantName ~= nil and variantName ~= "" then
|
|
3147
|
-
pcall(function()
|
|
3148
|
-
part.MaterialVariant = variantName
|
|
3149
|
-
end)
|
|
3150
|
-
end
|
|
3151
|
-
end
|
|
3152
|
-
part.Parent = model
|
|
3153
|
-
partCount += 1
|
|
3154
|
-
end
|
|
3155
|
-
model.Parent = parentInstance
|
|
3156
|
-
modelCount += 1
|
|
3157
|
-
totalParts += partCount
|
|
3158
|
-
local _arg0 = {
|
|
3159
|
-
name = name,
|
|
3160
|
-
partCount = partCount,
|
|
3161
|
-
modelPath = getInstancePath(model),
|
|
3162
|
-
}
|
|
3163
|
-
table.insert(models, _arg0)
|
|
3164
|
-
end
|
|
3165
|
-
return {
|
|
3166
|
-
success = true,
|
|
3167
|
-
modelCount = modelCount,
|
|
3168
|
-
totalParts = totalParts,
|
|
3169
|
-
models = models,
|
|
3170
|
-
}
|
|
3171
|
-
end)
|
|
3172
|
-
if success and result then
|
|
3173
|
-
finishRecording(recordingId, true)
|
|
3174
|
-
return result
|
|
3175
|
-
else
|
|
3176
|
-
finishRecording(recordingId, false)
|
|
3177
|
-
return {
|
|
3178
|
-
error = `Failed to import scene: {result}`,
|
|
3179
|
-
}
|
|
3180
|
-
end
|
|
3181
|
-
end
|
|
3182
|
-
local function searchMaterials(requestData)
|
|
3183
|
-
local _condition = (requestData.query)
|
|
3184
|
-
if _condition == nil then
|
|
3185
|
-
_condition = ""
|
|
3186
|
-
end
|
|
3187
|
-
local query = string.lower(_condition)
|
|
3188
|
-
local _condition_1 = (requestData.maxResults)
|
|
3189
|
-
if _condition_1 == nil then
|
|
3190
|
-
_condition_1 = 50
|
|
3191
|
-
end
|
|
3192
|
-
local maxResults = _condition_1
|
|
3193
|
-
local success, result = pcall(function()
|
|
3194
|
-
local children = MaterialService:GetChildren()
|
|
3195
|
-
local materials = {}
|
|
3196
|
-
for _, child in children do
|
|
3197
|
-
if not child:IsA("MaterialVariant") then
|
|
3198
|
-
continue
|
|
3199
|
-
end
|
|
3200
|
-
local nameMatch = query == "" or (string.find(string.lower(child.Name), query)) ~= nil
|
|
3201
|
-
if not nameMatch then
|
|
3202
|
-
continue
|
|
3203
|
-
end
|
|
3204
|
-
local _arg0 = {
|
|
3205
|
-
name = child.Name,
|
|
3206
|
-
baseMaterial = child.BaseMaterial.Name,
|
|
3207
|
-
}
|
|
3208
|
-
table.insert(materials, _arg0)
|
|
3209
|
-
if #materials >= maxResults then
|
|
3210
|
-
break
|
|
3211
|
-
end
|
|
3212
|
-
end
|
|
3213
|
-
return {
|
|
3214
|
-
success = true,
|
|
3215
|
-
materials = materials,
|
|
3216
|
-
total = #materials,
|
|
3217
|
-
}
|
|
3218
|
-
end)
|
|
3219
|
-
if success and result then
|
|
3220
|
-
return result
|
|
3221
|
-
else
|
|
3222
|
-
return {
|
|
3223
|
-
error = `Failed to search materials: {result}`,
|
|
3224
|
-
}
|
|
3225
|
-
end
|
|
3226
|
-
end
|
|
3227
|
-
return {
|
|
3228
|
-
exportBuild = exportBuild,
|
|
3229
|
-
importBuild = importBuild,
|
|
3230
|
-
importScene = importScene,
|
|
3231
|
-
searchMaterials = searchMaterials,
|
|
3232
|
-
}
|
|
3233
|
-
]]></string>
|
|
3234
|
-
</Properties>
|
|
3235
|
-
</Item>
|
|
3236
|
-
<Item class="ModuleScript" referent="10">
|
|
3237
2650
|
<Properties>
|
|
3238
2651
|
<string name="Name">CaptureHandlers</string>
|
|
3239
2652
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -3448,7 +2861,7 @@ return {
|
|
|
3448
2861
|
]]></string>
|
|
3449
2862
|
</Properties>
|
|
3450
2863
|
</Item>
|
|
3451
|
-
<Item class="ModuleScript" referent="
|
|
2864
|
+
<Item class="ModuleScript" referent="10">
|
|
3452
2865
|
<Properties>
|
|
3453
2866
|
<string name="Name">EvalRuntimeHandlers</string>
|
|
3454
2867
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -3602,7 +3015,7 @@ return {
|
|
|
3602
3015
|
]]></string>
|
|
3603
3016
|
</Properties>
|
|
3604
3017
|
</Item>
|
|
3605
|
-
<Item class="ModuleScript" referent="
|
|
3018
|
+
<Item class="ModuleScript" referent="11">
|
|
3606
3019
|
<Properties>
|
|
3607
3020
|
<string name="Name">GenerateModelHandlers</string>
|
|
3608
3021
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -3807,7 +3220,7 @@ return {
|
|
|
3807
3220
|
]]></string>
|
|
3808
3221
|
</Properties>
|
|
3809
3222
|
</Item>
|
|
3810
|
-
<Item class="ModuleScript" referent="
|
|
3223
|
+
<Item class="ModuleScript" referent="12">
|
|
3811
3224
|
<Properties>
|
|
3812
3225
|
<string name="Name">InputHandlers</string>
|
|
3813
3226
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -4007,514 +3420,7 @@ return {
|
|
|
4007
3420
|
]]></string>
|
|
4008
3421
|
</Properties>
|
|
4009
3422
|
</Item>
|
|
4010
|
-
<Item class="ModuleScript" referent="
|
|
4011
|
-
<Properties>
|
|
4012
|
-
<string name="Name">InstanceHandlers</string>
|
|
4013
|
-
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
4014
|
-
local TS = require(script.Parent.Parent.Parent.include.RuntimeLib)
|
|
4015
|
-
local Utils = TS.import(script, script.Parent.Parent, "Utils")
|
|
4016
|
-
local Recording = TS.import(script, script.Parent.Parent, "Recording")
|
|
4017
|
-
local _binding = Utils
|
|
4018
|
-
local getInstancePath = _binding.getInstancePath
|
|
4019
|
-
local getInstanceByPath = _binding.getInstanceByPath
|
|
4020
|
-
local convertPropertyValue = _binding.convertPropertyValue
|
|
4021
|
-
local _binding_1 = Recording
|
|
4022
|
-
local beginRecording = _binding_1.beginRecording
|
|
4023
|
-
local finishRecording = _binding_1.finishRecording
|
|
4024
|
-
local function processObjectEntries(objects, createFn)
|
|
4025
|
-
local results = {}
|
|
4026
|
-
local successCount = 0
|
|
4027
|
-
local failureCount = 0
|
|
4028
|
-
local loopSuccess, loopError = pcall(function()
|
|
4029
|
-
for _, entry in objects do
|
|
4030
|
-
if not (type(entry) == "table") then
|
|
4031
|
-
failureCount += 1
|
|
4032
|
-
table.insert(results, {
|
|
4033
|
-
success = false,
|
|
4034
|
-
error = "Each object entry must be a table",
|
|
4035
|
-
})
|
|
4036
|
-
continue
|
|
4037
|
-
end
|
|
4038
|
-
local objData = entry
|
|
4039
|
-
local className = objData.className
|
|
4040
|
-
local parentPath = objData.parent
|
|
4041
|
-
if not (className ~= "" and className) or not (parentPath ~= "" and parentPath) then
|
|
4042
|
-
failureCount += 1
|
|
4043
|
-
table.insert(results, {
|
|
4044
|
-
success = false,
|
|
4045
|
-
error = "Class name and parent are required",
|
|
4046
|
-
})
|
|
4047
|
-
continue
|
|
4048
|
-
end
|
|
4049
|
-
local entrySuccess, entryResult = pcall(function()
|
|
4050
|
-
return createFn(objData)
|
|
4051
|
-
end)
|
|
4052
|
-
if not entrySuccess then
|
|
4053
|
-
failureCount += 1
|
|
4054
|
-
local _arg0 = {
|
|
4055
|
-
success = false,
|
|
4056
|
-
className = className,
|
|
4057
|
-
parent = parentPath,
|
|
4058
|
-
error = tostring(entryResult),
|
|
4059
|
-
}
|
|
4060
|
-
table.insert(results, _arg0)
|
|
4061
|
-
continue
|
|
4062
|
-
end
|
|
4063
|
-
if entryResult.instance ~= nil then
|
|
4064
|
-
successCount += 1
|
|
4065
|
-
local _arg0 = {
|
|
4066
|
-
success = true,
|
|
4067
|
-
className = entryResult.className,
|
|
4068
|
-
parent = entryResult.parentPath,
|
|
4069
|
-
instancePath = getInstancePath(entryResult.instance),
|
|
4070
|
-
name = entryResult.instance.Name,
|
|
4071
|
-
}
|
|
4072
|
-
table.insert(results, _arg0)
|
|
4073
|
-
else
|
|
4074
|
-
failureCount += 1
|
|
4075
|
-
local _object = {
|
|
4076
|
-
success = false,
|
|
4077
|
-
}
|
|
4078
|
-
local _left = "className"
|
|
4079
|
-
local _condition = entryResult.className
|
|
4080
|
-
if _condition == nil then
|
|
4081
|
-
_condition = className
|
|
4082
|
-
end
|
|
4083
|
-
_object[_left] = _condition
|
|
4084
|
-
local _left_1 = "parent"
|
|
4085
|
-
local _condition_1 = entryResult.parentPath
|
|
4086
|
-
if _condition_1 == nil then
|
|
4087
|
-
_condition_1 = parentPath
|
|
4088
|
-
end
|
|
4089
|
-
_object[_left_1] = _condition_1
|
|
4090
|
-
_object.error = entryResult.error
|
|
4091
|
-
table.insert(results, _object)
|
|
4092
|
-
end
|
|
4093
|
-
end
|
|
4094
|
-
end)
|
|
4095
|
-
if not loopSuccess then
|
|
4096
|
-
failureCount += 1
|
|
4097
|
-
local _arg0 = {
|
|
4098
|
-
success = false,
|
|
4099
|
-
error = `Unexpected mass create failure: {tostring(loopError)}`,
|
|
4100
|
-
}
|
|
4101
|
-
table.insert(results, _arg0)
|
|
4102
|
-
end
|
|
4103
|
-
return {
|
|
4104
|
-
results = results,
|
|
4105
|
-
successCount = successCount,
|
|
4106
|
-
failureCount = failureCount,
|
|
4107
|
-
}
|
|
4108
|
-
end
|
|
4109
|
-
local function createObject(requestData)
|
|
4110
|
-
local className = requestData.className
|
|
4111
|
-
local parentPath = requestData.parent
|
|
4112
|
-
local name = requestData.name
|
|
4113
|
-
local properties = (requestData.properties) or {}
|
|
4114
|
-
if not (className ~= "" and className) or not (parentPath ~= "" and parentPath) then
|
|
4115
|
-
return {
|
|
4116
|
-
error = "Class name and parent are required",
|
|
4117
|
-
}
|
|
4118
|
-
end
|
|
4119
|
-
local parentInstance = getInstanceByPath(parentPath)
|
|
4120
|
-
if not parentInstance then
|
|
4121
|
-
return {
|
|
4122
|
-
error = `Parent instance not found: {parentPath}`,
|
|
4123
|
-
}
|
|
4124
|
-
end
|
|
4125
|
-
local recordingId = beginRecording(`Create {className}`)
|
|
4126
|
-
local success, newInstance = pcall(function()
|
|
4127
|
-
local instance = Instance.new(className)
|
|
4128
|
-
if name ~= "" and name then
|
|
4129
|
-
instance.Name = name
|
|
4130
|
-
end
|
|
4131
|
-
for propertyName, propertyValue in pairs(properties) do
|
|
4132
|
-
pcall(function()
|
|
4133
|
-
local converted = convertPropertyValue(instance, propertyName, propertyValue)
|
|
4134
|
-
instance[propertyName] = if converted ~= nil then converted else propertyValue
|
|
4135
|
-
end)
|
|
4136
|
-
end
|
|
4137
|
-
instance.Parent = parentInstance
|
|
4138
|
-
return instance
|
|
4139
|
-
end)
|
|
4140
|
-
if success and newInstance then
|
|
4141
|
-
finishRecording(recordingId, true)
|
|
4142
|
-
return {
|
|
4143
|
-
success = true,
|
|
4144
|
-
className = className,
|
|
4145
|
-
parent = parentPath,
|
|
4146
|
-
instancePath = getInstancePath(newInstance),
|
|
4147
|
-
name = newInstance.Name,
|
|
4148
|
-
message = "Object created successfully",
|
|
4149
|
-
}
|
|
4150
|
-
else
|
|
4151
|
-
finishRecording(recordingId, false)
|
|
4152
|
-
return {
|
|
4153
|
-
error = `Failed to create object: {newInstance}`,
|
|
4154
|
-
className = className,
|
|
4155
|
-
parent = parentPath,
|
|
4156
|
-
}
|
|
4157
|
-
end
|
|
4158
|
-
end
|
|
4159
|
-
local function deleteObject(requestData)
|
|
4160
|
-
local instancePath = requestData.instancePath
|
|
4161
|
-
if not (instancePath ~= "" and instancePath) then
|
|
4162
|
-
return {
|
|
4163
|
-
error = "Instance path is required",
|
|
4164
|
-
}
|
|
4165
|
-
end
|
|
4166
|
-
local instance = getInstanceByPath(instancePath)
|
|
4167
|
-
if not instance then
|
|
4168
|
-
return {
|
|
4169
|
-
error = `Instance not found: {instancePath}`,
|
|
4170
|
-
}
|
|
4171
|
-
end
|
|
4172
|
-
if instance == game then
|
|
4173
|
-
return {
|
|
4174
|
-
error = "Cannot delete the game instance",
|
|
4175
|
-
}
|
|
4176
|
-
end
|
|
4177
|
-
local recordingId = beginRecording(`Delete {instance.ClassName} ({instance.Name})`)
|
|
4178
|
-
local success, result = pcall(function()
|
|
4179
|
-
instance:Destroy()
|
|
4180
|
-
return true
|
|
4181
|
-
end)
|
|
4182
|
-
if success then
|
|
4183
|
-
finishRecording(recordingId, true)
|
|
4184
|
-
return {
|
|
4185
|
-
success = true,
|
|
4186
|
-
instancePath = instancePath,
|
|
4187
|
-
message = "Object deleted successfully",
|
|
4188
|
-
}
|
|
4189
|
-
else
|
|
4190
|
-
finishRecording(recordingId, false)
|
|
4191
|
-
return {
|
|
4192
|
-
error = `Failed to delete object: {result}`,
|
|
4193
|
-
instancePath = instancePath,
|
|
4194
|
-
}
|
|
4195
|
-
end
|
|
4196
|
-
end
|
|
4197
|
-
local function massCreateObjects(requestData)
|
|
4198
|
-
local objects = requestData.objects
|
|
4199
|
-
if not objects or not (type(objects) == "table") or #objects == 0 then
|
|
4200
|
-
return {
|
|
4201
|
-
error = "Objects array is required",
|
|
4202
|
-
}
|
|
4203
|
-
end
|
|
4204
|
-
local recordingId = beginRecording("Mass create objects")
|
|
4205
|
-
local _binding_2 = processObjectEntries(objects, function(objData)
|
|
4206
|
-
local className = objData.className
|
|
4207
|
-
local parentPath = objData.parent
|
|
4208
|
-
local name = objData.name
|
|
4209
|
-
local properties = (objData.properties) or {}
|
|
4210
|
-
local parentInstance = getInstanceByPath(parentPath)
|
|
4211
|
-
if not parentInstance then
|
|
4212
|
-
return {
|
|
4213
|
-
error = "Parent instance not found",
|
|
4214
|
-
className = className,
|
|
4215
|
-
parentPath = parentPath,
|
|
4216
|
-
}
|
|
4217
|
-
end
|
|
4218
|
-
local success, newInstance = pcall(function()
|
|
4219
|
-
local instance = Instance.new(className)
|
|
4220
|
-
if name ~= "" and name then
|
|
4221
|
-
instance.Name = name
|
|
4222
|
-
end
|
|
4223
|
-
for propertyName, propertyValue in pairs(properties) do
|
|
4224
|
-
pcall(function()
|
|
4225
|
-
local converted = convertPropertyValue(instance, propertyName, propertyValue)
|
|
4226
|
-
instance[propertyName] = if converted ~= nil then converted else propertyValue
|
|
4227
|
-
end)
|
|
4228
|
-
end
|
|
4229
|
-
instance.Parent = parentInstance
|
|
4230
|
-
return instance
|
|
4231
|
-
end)
|
|
4232
|
-
if not success or not newInstance then
|
|
4233
|
-
return {
|
|
4234
|
-
error = tostring(newInstance),
|
|
4235
|
-
className = className,
|
|
4236
|
-
parentPath = parentPath,
|
|
4237
|
-
}
|
|
4238
|
-
end
|
|
4239
|
-
return {
|
|
4240
|
-
instance = newInstance,
|
|
4241
|
-
className = className,
|
|
4242
|
-
parentPath = parentPath,
|
|
4243
|
-
}
|
|
4244
|
-
end)
|
|
4245
|
-
local results = _binding_2.results
|
|
4246
|
-
local successCount = _binding_2.successCount
|
|
4247
|
-
local failureCount = _binding_2.failureCount
|
|
4248
|
-
finishRecording(recordingId, successCount > 0)
|
|
4249
|
-
return {
|
|
4250
|
-
results = results,
|
|
4251
|
-
summary = {
|
|
4252
|
-
total = #objects,
|
|
4253
|
-
succeeded = successCount,
|
|
4254
|
-
failed = failureCount,
|
|
4255
|
-
},
|
|
4256
|
-
}
|
|
4257
|
-
end
|
|
4258
|
-
local function performSmartDuplicate(requestData, useRecording)
|
|
4259
|
-
if useRecording == nil then
|
|
4260
|
-
useRecording = true
|
|
4261
|
-
end
|
|
4262
|
-
local instancePath = requestData.instancePath
|
|
4263
|
-
local count = requestData.count
|
|
4264
|
-
local options = (requestData.options) or {}
|
|
4265
|
-
if not (instancePath ~= "" and instancePath) or not (count ~= 0 and count == count and count) or count < 1 then
|
|
4266
|
-
return {
|
|
4267
|
-
error = "Instance path and count > 0 are required",
|
|
4268
|
-
}
|
|
4269
|
-
end
|
|
4270
|
-
local instance = getInstanceByPath(instancePath)
|
|
4271
|
-
if not instance then
|
|
4272
|
-
return {
|
|
4273
|
-
error = `Instance not found: {instancePath}`,
|
|
4274
|
-
}
|
|
4275
|
-
end
|
|
4276
|
-
local recordingId = if useRecording then beginRecording(`Smart duplicate {instance.Name}`) else nil
|
|
4277
|
-
local results = {}
|
|
4278
|
-
local successCount = 0
|
|
4279
|
-
local failureCount = 0
|
|
4280
|
-
do
|
|
4281
|
-
local _i = 1
|
|
4282
|
-
local _shouldIncrement = false
|
|
4283
|
-
while true do
|
|
4284
|
-
local i = _i
|
|
4285
|
-
if _shouldIncrement then
|
|
4286
|
-
i += 1
|
|
4287
|
-
else
|
|
4288
|
-
_shouldIncrement = true
|
|
4289
|
-
end
|
|
4290
|
-
if not (i <= count) then
|
|
4291
|
-
break
|
|
4292
|
-
end
|
|
4293
|
-
local success, newInstance = pcall(function()
|
|
4294
|
-
local clone = instance:Clone()
|
|
4295
|
-
local _value = options.namePattern
|
|
4296
|
-
if _value ~= 0 and _value == _value and _value ~= "" and _value then
|
|
4297
|
-
local _exp = (options.namePattern)
|
|
4298
|
-
local _arg1 = tostring(i)
|
|
4299
|
-
clone.Name = (string.gsub(_exp, "{n}", _arg1))
|
|
4300
|
-
else
|
|
4301
|
-
clone.Name = instance.Name .. tostring(i)
|
|
4302
|
-
end
|
|
4303
|
-
local _condition = options.positionOffset
|
|
4304
|
-
if _condition ~= 0 and _condition == _condition and _condition ~= "" and _condition then
|
|
4305
|
-
_condition = clone:IsA("BasePart")
|
|
4306
|
-
end
|
|
4307
|
-
if _condition ~= 0 and _condition == _condition and _condition ~= "" and _condition then
|
|
4308
|
-
local offset = options.positionOffset
|
|
4309
|
-
local currentPos = clone.Position
|
|
4310
|
-
local _exp = currentPos.X
|
|
4311
|
-
local _condition_1 = offset[1]
|
|
4312
|
-
if _condition_1 == nil then
|
|
4313
|
-
_condition_1 = 0
|
|
4314
|
-
end
|
|
4315
|
-
local _exp_1 = _exp + _condition_1 * i
|
|
4316
|
-
local _exp_2 = currentPos.Y
|
|
4317
|
-
local _condition_2 = offset[2]
|
|
4318
|
-
if _condition_2 == nil then
|
|
4319
|
-
_condition_2 = 0
|
|
4320
|
-
end
|
|
4321
|
-
local _exp_3 = _exp_2 + _condition_2 * i
|
|
4322
|
-
local _exp_4 = currentPos.Z
|
|
4323
|
-
local _condition_3 = offset[3]
|
|
4324
|
-
if _condition_3 == nil then
|
|
4325
|
-
_condition_3 = 0
|
|
4326
|
-
end
|
|
4327
|
-
clone.Position = Vector3.new(_exp_1, _exp_3, _exp_4 + _condition_3 * i)
|
|
4328
|
-
end
|
|
4329
|
-
local _condition_1 = options.rotationOffset
|
|
4330
|
-
if _condition_1 ~= 0 and _condition_1 == _condition_1 and _condition_1 ~= "" and _condition_1 then
|
|
4331
|
-
_condition_1 = clone:IsA("BasePart")
|
|
4332
|
-
end
|
|
4333
|
-
if _condition_1 ~= 0 and _condition_1 == _condition_1 and _condition_1 ~= "" and _condition_1 then
|
|
4334
|
-
local offset = options.rotationOffset
|
|
4335
|
-
local _cFrame = clone.CFrame
|
|
4336
|
-
local _condition_2 = offset[1]
|
|
4337
|
-
if _condition_2 == nil then
|
|
4338
|
-
_condition_2 = 0
|
|
4339
|
-
end
|
|
4340
|
-
local _exp = math.rad(_condition_2 * i)
|
|
4341
|
-
local _condition_3 = offset[2]
|
|
4342
|
-
if _condition_3 == nil then
|
|
4343
|
-
_condition_3 = 0
|
|
4344
|
-
end
|
|
4345
|
-
local _exp_1 = math.rad(_condition_3 * i)
|
|
4346
|
-
local _condition_4 = offset[3]
|
|
4347
|
-
if _condition_4 == nil then
|
|
4348
|
-
_condition_4 = 0
|
|
4349
|
-
end
|
|
4350
|
-
local _arg0 = CFrame.Angles(_exp, _exp_1, math.rad(_condition_4 * i))
|
|
4351
|
-
clone.CFrame = _cFrame * _arg0
|
|
4352
|
-
end
|
|
4353
|
-
local _condition_2 = options.scaleOffset
|
|
4354
|
-
if _condition_2 ~= 0 and _condition_2 == _condition_2 and _condition_2 ~= "" and _condition_2 then
|
|
4355
|
-
_condition_2 = clone:IsA("BasePart")
|
|
4356
|
-
end
|
|
4357
|
-
if _condition_2 ~= 0 and _condition_2 == _condition_2 and _condition_2 ~= "" and _condition_2 then
|
|
4358
|
-
local offset = options.scaleOffset
|
|
4359
|
-
local currentSize = clone.Size
|
|
4360
|
-
local _exp = currentSize.X
|
|
4361
|
-
local _condition_3 = offset[1]
|
|
4362
|
-
if _condition_3 == nil then
|
|
4363
|
-
_condition_3 = 1
|
|
4364
|
-
end
|
|
4365
|
-
local _exp_1 = _exp * (_condition_3 ^ i)
|
|
4366
|
-
local _exp_2 = currentSize.Y
|
|
4367
|
-
local _condition_4 = offset[2]
|
|
4368
|
-
if _condition_4 == nil then
|
|
4369
|
-
_condition_4 = 1
|
|
4370
|
-
end
|
|
4371
|
-
local _exp_3 = _exp_2 * (_condition_4 ^ i)
|
|
4372
|
-
local _exp_4 = currentSize.Z
|
|
4373
|
-
local _condition_5 = offset[3]
|
|
4374
|
-
if _condition_5 == nil then
|
|
4375
|
-
_condition_5 = 1
|
|
4376
|
-
end
|
|
4377
|
-
clone.Size = Vector3.new(_exp_1, _exp_3, _exp_4 * (_condition_5 ^ i))
|
|
4378
|
-
end
|
|
4379
|
-
local _value_1 = options.propertyVariations
|
|
4380
|
-
if _value_1 ~= 0 and _value_1 == _value_1 and _value_1 ~= "" and _value_1 then
|
|
4381
|
-
for propName, values in pairs(options.propertyVariations) do
|
|
4382
|
-
if values and #values > 0 then
|
|
4383
|
-
local valueIndex = ((i - 1) % #values)
|
|
4384
|
-
pcall(function()
|
|
4385
|
-
clone[propName] = values[valueIndex + 1]
|
|
4386
|
-
end)
|
|
4387
|
-
end
|
|
4388
|
-
end
|
|
4389
|
-
end
|
|
4390
|
-
local targetParents = options.targetParents
|
|
4391
|
-
local _value_2 = targetParents and targetParents[i]
|
|
4392
|
-
if _value_2 ~= "" and _value_2 then
|
|
4393
|
-
local targetParent = getInstanceByPath(targetParents[i])
|
|
4394
|
-
clone.Parent = targetParent or instance.Parent
|
|
4395
|
-
else
|
|
4396
|
-
clone.Parent = instance.Parent
|
|
4397
|
-
end
|
|
4398
|
-
return clone
|
|
4399
|
-
end)
|
|
4400
|
-
if success and newInstance then
|
|
4401
|
-
successCount += 1
|
|
4402
|
-
local _arg0 = {
|
|
4403
|
-
success = true,
|
|
4404
|
-
instancePath = getInstancePath(newInstance),
|
|
4405
|
-
name = newInstance.Name,
|
|
4406
|
-
index = i,
|
|
4407
|
-
}
|
|
4408
|
-
table.insert(results, _arg0)
|
|
4409
|
-
else
|
|
4410
|
-
failureCount += 1
|
|
4411
|
-
local _arg0 = {
|
|
4412
|
-
success = false,
|
|
4413
|
-
index = i,
|
|
4414
|
-
error = tostring(newInstance),
|
|
4415
|
-
}
|
|
4416
|
-
table.insert(results, _arg0)
|
|
4417
|
-
end
|
|
4418
|
-
_i = i
|
|
4419
|
-
end
|
|
4420
|
-
end
|
|
4421
|
-
finishRecording(recordingId, successCount > 0)
|
|
4422
|
-
return {
|
|
4423
|
-
results = results,
|
|
4424
|
-
summary = {
|
|
4425
|
-
total = count,
|
|
4426
|
-
succeeded = successCount,
|
|
4427
|
-
failed = failureCount,
|
|
4428
|
-
},
|
|
4429
|
-
sourceInstance = instancePath,
|
|
4430
|
-
}
|
|
4431
|
-
end
|
|
4432
|
-
local function smartDuplicate(requestData)
|
|
4433
|
-
return performSmartDuplicate(requestData, true)
|
|
4434
|
-
end
|
|
4435
|
-
local function massDuplicate(requestData)
|
|
4436
|
-
local duplications = requestData.duplications
|
|
4437
|
-
if not duplications or not (type(duplications) == "table") or #duplications == 0 then
|
|
4438
|
-
return {
|
|
4439
|
-
error = "Duplications array is required",
|
|
4440
|
-
}
|
|
4441
|
-
end
|
|
4442
|
-
local allResults = {}
|
|
4443
|
-
local totalSuccess = 0
|
|
4444
|
-
local totalFailures = 0
|
|
4445
|
-
local recordingId = beginRecording("Mass duplicate operations")
|
|
4446
|
-
for _, duplication in duplications do
|
|
4447
|
-
local result = performSmartDuplicate(duplication, false)
|
|
4448
|
-
table.insert(allResults, result)
|
|
4449
|
-
if result.summary then
|
|
4450
|
-
totalSuccess += result.summary.succeeded
|
|
4451
|
-
totalFailures += result.summary.failed
|
|
4452
|
-
end
|
|
4453
|
-
end
|
|
4454
|
-
finishRecording(recordingId, totalSuccess > 0)
|
|
4455
|
-
return {
|
|
4456
|
-
results = allResults,
|
|
4457
|
-
summary = {
|
|
4458
|
-
total = totalSuccess + totalFailures,
|
|
4459
|
-
succeeded = totalSuccess,
|
|
4460
|
-
failed = totalFailures,
|
|
4461
|
-
},
|
|
4462
|
-
}
|
|
4463
|
-
end
|
|
4464
|
-
local function cloneObject(requestData)
|
|
4465
|
-
local instancePath = requestData.instancePath
|
|
4466
|
-
local targetParentPath = requestData.targetParentPath
|
|
4467
|
-
if not (instancePath ~= "" and instancePath) or not (targetParentPath ~= "" and targetParentPath) then
|
|
4468
|
-
return {
|
|
4469
|
-
error = "Instance path and target parent path are required",
|
|
4470
|
-
}
|
|
4471
|
-
end
|
|
4472
|
-
local instance = getInstanceByPath(instancePath)
|
|
4473
|
-
if not instance then
|
|
4474
|
-
return {
|
|
4475
|
-
error = `Instance not found: {instancePath}`,
|
|
4476
|
-
}
|
|
4477
|
-
end
|
|
4478
|
-
local targetParent = getInstanceByPath(targetParentPath)
|
|
4479
|
-
if not targetParent then
|
|
4480
|
-
return {
|
|
4481
|
-
error = `Target parent not found: {targetParentPath}`,
|
|
4482
|
-
}
|
|
4483
|
-
end
|
|
4484
|
-
local recordingId = beginRecording(`Clone {instance.Name}`)
|
|
4485
|
-
local success, clone = pcall(function()
|
|
4486
|
-
local cloned = instance:Clone()
|
|
4487
|
-
cloned.Parent = targetParent
|
|
4488
|
-
return cloned
|
|
4489
|
-
end)
|
|
4490
|
-
if success and clone then
|
|
4491
|
-
finishRecording(recordingId, true)
|
|
4492
|
-
return {
|
|
4493
|
-
success = true,
|
|
4494
|
-
instancePath = getInstancePath(clone),
|
|
4495
|
-
name = clone.Name,
|
|
4496
|
-
className = clone.ClassName,
|
|
4497
|
-
parent = targetParentPath,
|
|
4498
|
-
message = "Object cloned successfully",
|
|
4499
|
-
}
|
|
4500
|
-
end
|
|
4501
|
-
finishRecording(recordingId, false)
|
|
4502
|
-
return {
|
|
4503
|
-
error = `Failed to clone object: {clone}`,
|
|
4504
|
-
}
|
|
4505
|
-
end
|
|
4506
|
-
return {
|
|
4507
|
-
createObject = createObject,
|
|
4508
|
-
deleteObject = deleteObject,
|
|
4509
|
-
massCreateObjects = massCreateObjects,
|
|
4510
|
-
smartDuplicate = smartDuplicate,
|
|
4511
|
-
massDuplicate = massDuplicate,
|
|
4512
|
-
cloneObject = cloneObject,
|
|
4513
|
-
}
|
|
4514
|
-
]]></string>
|
|
4515
|
-
</Properties>
|
|
4516
|
-
</Item>
|
|
4517
|
-
<Item class="ModuleScript" referent="15">
|
|
3423
|
+
<Item class="ModuleScript" referent="13">
|
|
4518
3424
|
<Properties>
|
|
4519
3425
|
<string name="Name">LogHandlers</string>
|
|
4520
3426
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -4540,7 +3446,7 @@ return {
|
|
|
4540
3446
|
]]></string>
|
|
4541
3447
|
</Properties>
|
|
4542
3448
|
</Item>
|
|
4543
|
-
<Item class="ModuleScript" referent="
|
|
3449
|
+
<Item class="ModuleScript" referent="14">
|
|
4544
3450
|
<Properties>
|
|
4545
3451
|
<string name="Name">MemoryHandlers</string>
|
|
4546
3452
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -4608,23 +3514,17 @@ return {
|
|
|
4608
3514
|
]]></string>
|
|
4609
3515
|
</Properties>
|
|
4610
3516
|
</Item>
|
|
4611
|
-
<Item class="ModuleScript" referent="
|
|
3517
|
+
<Item class="ModuleScript" referent="15">
|
|
4612
3518
|
<Properties>
|
|
4613
3519
|
<string name="Name">MetadataHandlers</string>
|
|
4614
3520
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
4615
3521
|
local TS = require(script.Parent.Parent.Parent.include.RuntimeLib)
|
|
4616
|
-
local CollectionService = TS.import(script, script.Parent.Parent.Parent, "node_modules", "@rbxts", "services").CollectionService
|
|
4617
3522
|
local Utils = TS.import(script, script.Parent.Parent, "Utils")
|
|
4618
|
-
local Recording = TS.import(script, script.Parent.Parent, "Recording")
|
|
4619
3523
|
local LuauExec = TS.import(script, script.Parent.Parent, "LuauExec")
|
|
4620
|
-
local ChangeHistoryService = game:GetService("ChangeHistoryService")
|
|
4621
3524
|
local Selection = game:GetService("Selection")
|
|
4622
3525
|
local _binding = Utils
|
|
4623
3526
|
local getInstancePath = _binding.getInstancePath
|
|
4624
3527
|
local getInstanceByPath = _binding.getInstanceByPath
|
|
4625
|
-
local _binding_1 = Recording
|
|
4626
|
-
local beginRecording = _binding_1.beginRecording
|
|
4627
|
-
local finishRecording = _binding_1.finishRecording
|
|
4628
3528
|
local function serializeValue(value)
|
|
4629
3529
|
local _value = value
|
|
4630
3530
|
local vType = typeof(_value)
|
|
@@ -4676,127 +3576,6 @@ local function serializeValue(value)
|
|
|
4676
3576
|
end
|
|
4677
3577
|
return value
|
|
4678
3578
|
end
|
|
4679
|
-
local function deserializeValue(attributeValue, valueType)
|
|
4680
|
-
local _attributeValue = attributeValue
|
|
4681
|
-
if not (type(_attributeValue) == "table") then
|
|
4682
|
-
return attributeValue
|
|
4683
|
-
end
|
|
4684
|
-
local tbl = attributeValue
|
|
4685
|
-
local _condition = (tbl._type)
|
|
4686
|
-
if _condition == nil then
|
|
4687
|
-
_condition = valueType
|
|
4688
|
-
end
|
|
4689
|
-
local t = _condition
|
|
4690
|
-
if t == "Vector3" then
|
|
4691
|
-
local _condition_1 = (tbl.X)
|
|
4692
|
-
if _condition_1 == nil then
|
|
4693
|
-
_condition_1 = 0
|
|
4694
|
-
end
|
|
4695
|
-
local _condition_2 = (tbl.Y)
|
|
4696
|
-
if _condition_2 == nil then
|
|
4697
|
-
_condition_2 = 0
|
|
4698
|
-
end
|
|
4699
|
-
local _condition_3 = (tbl.Z)
|
|
4700
|
-
if _condition_3 == nil then
|
|
4701
|
-
_condition_3 = 0
|
|
4702
|
-
end
|
|
4703
|
-
return Vector3.new(_condition_1, _condition_2, _condition_3)
|
|
4704
|
-
elseif t == "Color3" then
|
|
4705
|
-
local _condition_1 = (tbl.R)
|
|
4706
|
-
if _condition_1 == nil then
|
|
4707
|
-
_condition_1 = 0
|
|
4708
|
-
end
|
|
4709
|
-
local _condition_2 = (tbl.G)
|
|
4710
|
-
if _condition_2 == nil then
|
|
4711
|
-
_condition_2 = 0
|
|
4712
|
-
end
|
|
4713
|
-
local _condition_3 = (tbl.B)
|
|
4714
|
-
if _condition_3 == nil then
|
|
4715
|
-
_condition_3 = 0
|
|
4716
|
-
end
|
|
4717
|
-
return Color3.new(_condition_1, _condition_2, _condition_3)
|
|
4718
|
-
elseif t == "UDim2" then
|
|
4719
|
-
local x = tbl.X
|
|
4720
|
-
local y = tbl.Y
|
|
4721
|
-
local _result = x
|
|
4722
|
-
if _result ~= nil then
|
|
4723
|
-
_result = _result.Scale
|
|
4724
|
-
end
|
|
4725
|
-
local _condition_1 = _result
|
|
4726
|
-
if _condition_1 == nil then
|
|
4727
|
-
_condition_1 = 0
|
|
4728
|
-
end
|
|
4729
|
-
local _result_1 = x
|
|
4730
|
-
if _result_1 ~= nil then
|
|
4731
|
-
_result_1 = _result_1.Offset
|
|
4732
|
-
end
|
|
4733
|
-
local _condition_2 = _result_1
|
|
4734
|
-
if _condition_2 == nil then
|
|
4735
|
-
_condition_2 = 0
|
|
4736
|
-
end
|
|
4737
|
-
local _result_2 = y
|
|
4738
|
-
if _result_2 ~= nil then
|
|
4739
|
-
_result_2 = _result_2.Scale
|
|
4740
|
-
end
|
|
4741
|
-
local _condition_3 = _result_2
|
|
4742
|
-
if _condition_3 == nil then
|
|
4743
|
-
_condition_3 = 0
|
|
4744
|
-
end
|
|
4745
|
-
local _result_3 = y
|
|
4746
|
-
if _result_3 ~= nil then
|
|
4747
|
-
_result_3 = _result_3.Offset
|
|
4748
|
-
end
|
|
4749
|
-
local _condition_4 = _result_3
|
|
4750
|
-
if _condition_4 == nil then
|
|
4751
|
-
_condition_4 = 0
|
|
4752
|
-
end
|
|
4753
|
-
return UDim2.new(_condition_1, _condition_2, _condition_3, _condition_4)
|
|
4754
|
-
elseif t == "BrickColor" then
|
|
4755
|
-
local _condition_1 = (tbl.Name)
|
|
4756
|
-
if _condition_1 == nil then
|
|
4757
|
-
_condition_1 = "Medium stone grey"
|
|
4758
|
-
end
|
|
4759
|
-
return BrickColor.new(_condition_1)
|
|
4760
|
-
end
|
|
4761
|
-
return attributeValue
|
|
4762
|
-
end
|
|
4763
|
-
local function setAttribute(requestData)
|
|
4764
|
-
local instancePath = requestData.instancePath
|
|
4765
|
-
local attributeName = requestData.attributeName
|
|
4766
|
-
local attributeValue = requestData.attributeValue
|
|
4767
|
-
local valueType = requestData.valueType
|
|
4768
|
-
if not (instancePath ~= "" and instancePath) or not (attributeName ~= "" and attributeName) then
|
|
4769
|
-
return {
|
|
4770
|
-
error = "Instance path and attribute name are required",
|
|
4771
|
-
}
|
|
4772
|
-
end
|
|
4773
|
-
local instance = getInstanceByPath(instancePath)
|
|
4774
|
-
if not instance then
|
|
4775
|
-
return {
|
|
4776
|
-
error = `Instance not found: {instancePath}`,
|
|
4777
|
-
}
|
|
4778
|
-
end
|
|
4779
|
-
local recordingId = beginRecording(`Set attribute {attributeName} on {instance.Name}`)
|
|
4780
|
-
local success, result = pcall(function()
|
|
4781
|
-
local value = deserializeValue(attributeValue, valueType)
|
|
4782
|
-
instance:SetAttribute(attributeName, value)
|
|
4783
|
-
return {
|
|
4784
|
-
success = true,
|
|
4785
|
-
instancePath = instancePath,
|
|
4786
|
-
attributeName = attributeName,
|
|
4787
|
-
value = attributeValue,
|
|
4788
|
-
message = "Attribute set successfully",
|
|
4789
|
-
}
|
|
4790
|
-
end)
|
|
4791
|
-
if success then
|
|
4792
|
-
finishRecording(recordingId, true)
|
|
4793
|
-
return result
|
|
4794
|
-
end
|
|
4795
|
-
finishRecording(recordingId, false)
|
|
4796
|
-
return {
|
|
4797
|
-
error = `Failed to set attribute: {result}`,
|
|
4798
|
-
}
|
|
4799
|
-
end
|
|
4800
3579
|
local function getAttributes(requestData)
|
|
4801
3580
|
local instancePath = requestData.instancePath
|
|
4802
3581
|
if not (instancePath ~= "" and instancePath) then
|
|
@@ -4834,110 +3613,117 @@ local function getAttributes(requestData)
|
|
|
4834
3613
|
error = `Failed to get attributes: {result}`,
|
|
4835
3614
|
}
|
|
4836
3615
|
end
|
|
4837
|
-
local function
|
|
4838
|
-
local
|
|
4839
|
-
|
|
4840
|
-
if not (instancePath ~= "" and instancePath) or not (attributeName ~= "" and attributeName) then
|
|
3616
|
+
local function getSelection(_requestData)
|
|
3617
|
+
local selection = Selection:Get()
|
|
3618
|
+
if #selection == 0 then
|
|
4841
3619
|
return {
|
|
4842
|
-
|
|
3620
|
+
success = true,
|
|
3621
|
+
selection = {},
|
|
3622
|
+
count = 0,
|
|
3623
|
+
message = "No objects selected",
|
|
4843
3624
|
}
|
|
4844
3625
|
end
|
|
4845
|
-
|
|
4846
|
-
|
|
3626
|
+
-- ▼ ReadonlyArray.map ▼
|
|
3627
|
+
local _newValue = table.create(#selection)
|
|
3628
|
+
local _callback = function(instance)
|
|
4847
3629
|
return {
|
|
4848
|
-
|
|
3630
|
+
name = instance.Name,
|
|
3631
|
+
className = instance.ClassName,
|
|
3632
|
+
path = getInstancePath(instance),
|
|
3633
|
+
parent = if instance.Parent then getInstancePath(instance.Parent) else nil,
|
|
4849
3634
|
}
|
|
4850
3635
|
end
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
local existed = instance:GetAttribute(attributeName) ~= nil
|
|
4854
|
-
instance:SetAttribute(attributeName, nil)
|
|
4855
|
-
return {
|
|
4856
|
-
success = true,
|
|
4857
|
-
instancePath = instancePath,
|
|
4858
|
-
attributeName = attributeName,
|
|
4859
|
-
existed = existed,
|
|
4860
|
-
message = if existed then "Attribute deleted successfully" else "Attribute did not exist",
|
|
4861
|
-
}
|
|
4862
|
-
end)
|
|
4863
|
-
if success then
|
|
4864
|
-
finishRecording(recordingId, true)
|
|
4865
|
-
return result
|
|
3636
|
+
for _k, _v in selection do
|
|
3637
|
+
_newValue[_k] = _callback(_v, _k - 1, selection)
|
|
4866
3638
|
end
|
|
4867
|
-
|
|
3639
|
+
-- ▲ ReadonlyArray.map ▲
|
|
3640
|
+
local selectedObjects = _newValue
|
|
4868
3641
|
return {
|
|
4869
|
-
|
|
3642
|
+
success = true,
|
|
3643
|
+
selection = selectedObjects,
|
|
3644
|
+
count = #selection,
|
|
3645
|
+
message = `{#selection} object(s) selected`,
|
|
4870
3646
|
}
|
|
4871
3647
|
end
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
3648
|
+
-- The counterpart to getSelection: this sets it. Selecting what the agent just
|
|
3649
|
+
-- built shows the user the result and puts the instance under Studio's own
|
|
3650
|
+
-- move/scale handles, which is why it is a tool and not left to execute_luau.
|
|
3651
|
+
local function setSelection(requestData)
|
|
3652
|
+
local rawPaths = requestData.paths
|
|
3653
|
+
if not (type(rawPaths) == "table") then
|
|
4875
3654
|
return {
|
|
4876
|
-
error = "
|
|
3655
|
+
error = "paths is required (an empty array clears in set mode)",
|
|
4877
3656
|
}
|
|
4878
3657
|
end
|
|
4879
|
-
local
|
|
4880
|
-
if
|
|
4881
|
-
|
|
4882
|
-
error = `Instance not found: {instancePath}`,
|
|
4883
|
-
}
|
|
3658
|
+
local _condition = (requestData.mode)
|
|
3659
|
+
if _condition == nil then
|
|
3660
|
+
_condition = "set"
|
|
4884
3661
|
end
|
|
4885
|
-
local
|
|
4886
|
-
|
|
3662
|
+
local mode = _condition
|
|
3663
|
+
if mode ~= "set" and mode ~= "add" and mode ~= "remove" then
|
|
4887
3664
|
return {
|
|
4888
|
-
|
|
4889
|
-
tags = tags,
|
|
4890
|
-
count = #tags,
|
|
3665
|
+
error = `mode must be "set", "add" or "remove" (got: {mode})`,
|
|
4891
3666
|
}
|
|
4892
|
-
end)
|
|
4893
|
-
if success then
|
|
4894
|
-
return result
|
|
4895
3667
|
end
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
}
|
|
4899
|
-
end
|
|
4900
|
-
local function addTag(requestData)
|
|
4901
|
-
local instancePath = requestData.instancePath
|
|
4902
|
-
local tagName = requestData.tagName
|
|
4903
|
-
if not (instancePath ~= "" and instancePath) or not (tagName ~= "" and tagName) then
|
|
3668
|
+
local paths = rawPaths
|
|
3669
|
+
if #paths == 0 and mode ~= "set" then
|
|
4904
3670
|
return {
|
|
4905
|
-
error =
|
|
3671
|
+
error = `paths cannot be empty in {mode} mode`,
|
|
4906
3672
|
}
|
|
4907
3673
|
end
|
|
4908
|
-
local
|
|
4909
|
-
|
|
3674
|
+
local targets = {}
|
|
3675
|
+
local missing = {}
|
|
3676
|
+
for _, entry in paths do
|
|
3677
|
+
if not (type(entry) == "string") or entry == "" then
|
|
3678
|
+
return {
|
|
3679
|
+
error = "paths must contain non-empty instance path strings",
|
|
3680
|
+
}
|
|
3681
|
+
end
|
|
3682
|
+
local instance = getInstanceByPath(entry)
|
|
3683
|
+
if instance then
|
|
3684
|
+
table.insert(targets, instance)
|
|
3685
|
+
else
|
|
3686
|
+
table.insert(missing, entry)
|
|
3687
|
+
end
|
|
3688
|
+
end
|
|
3689
|
+
local clearsSelection = mode == "set" and #paths == 0
|
|
3690
|
+
if #targets == 0 and not clearsSelection then
|
|
4910
3691
|
return {
|
|
4911
|
-
error =
|
|
3692
|
+
error = "No matching instances found for any path",
|
|
3693
|
+
missingPaths = missing,
|
|
4912
3694
|
}
|
|
4913
3695
|
end
|
|
4914
|
-
local
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
3696
|
+
local ok, err = pcall(function()
|
|
3697
|
+
if mode == "add" then
|
|
3698
|
+
Selection:Add(targets)
|
|
3699
|
+
elseif mode == "remove" then
|
|
3700
|
+
Selection:Remove(targets)
|
|
3701
|
+
else
|
|
3702
|
+
Selection:Set(targets)
|
|
3703
|
+
end
|
|
3704
|
+
end)
|
|
3705
|
+
if not ok then
|
|
4918
3706
|
return {
|
|
4919
|
-
|
|
4920
|
-
instancePath = instancePath,
|
|
4921
|
-
tagName = tagName,
|
|
4922
|
-
alreadyHad = alreadyHad,
|
|
4923
|
-
message = if alreadyHad then "Instance already had this tag" else "Tag added successfully",
|
|
3707
|
+
error = `Selection.{mode} failed: {tostring(err)}`,
|
|
4924
3708
|
}
|
|
4925
|
-
end)
|
|
4926
|
-
if success then
|
|
4927
|
-
finishRecording(recordingId, true)
|
|
4928
|
-
return result
|
|
4929
3709
|
end
|
|
4930
|
-
finishRecording(recordingId, false)
|
|
4931
3710
|
return {
|
|
4932
|
-
|
|
3711
|
+
success = true,
|
|
3712
|
+
mode = mode,
|
|
3713
|
+
selected = #targets,
|
|
3714
|
+
missingPaths = missing,
|
|
3715
|
+
message = if clearsSelection then "Selection cleared" elseif mode == "remove" then `Deselected {#targets} object(s)` else `{#targets} object(s) {if mode == "add" then "added to" else "in"} the selection`,
|
|
4933
3716
|
}
|
|
4934
3717
|
end
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
3718
|
+
-- Aims the Studio camera at an instance and frames it from a sensible angle.
|
|
3719
|
+
-- This completes the screenshot loop capture_screenshot documents: build,
|
|
3720
|
+
-- focus, screenshot. Framing distance comes from the bounding box and the
|
|
3721
|
+
-- camera's own field of view so any subject fills a similar share of frame.
|
|
3722
|
+
local function focusViewport(requestData)
|
|
3723
|
+
local instancePath = requestData.path
|
|
3724
|
+
if not (instancePath ~= "" and instancePath) then
|
|
4939
3725
|
return {
|
|
4940
|
-
error = "
|
|
3726
|
+
error = "path is required (the instance to frame)",
|
|
4941
3727
|
}
|
|
4942
3728
|
end
|
|
4943
3729
|
local instance = getInstanceByPath(instancePath)
|
|
@@ -4946,93 +3732,91 @@ local function removeTag(requestData)
|
|
|
4946
3732
|
error = `Instance not found: {instancePath}`,
|
|
4947
3733
|
}
|
|
4948
3734
|
end
|
|
4949
|
-
local
|
|
4950
|
-
local
|
|
4951
|
-
|
|
4952
|
-
CollectionService:RemoveTag(instance, tagName)
|
|
3735
|
+
local workspace = game:GetService("Workspace")
|
|
3736
|
+
local camera = workspace.CurrentCamera
|
|
3737
|
+
if not camera then
|
|
4953
3738
|
return {
|
|
4954
|
-
|
|
4955
|
-
instancePath = instancePath,
|
|
4956
|
-
tagName = tagName,
|
|
4957
|
-
hadTag = hadTag,
|
|
4958
|
-
message = if hadTag then "Tag removed successfully" else "Instance did not have this tag",
|
|
3739
|
+
error = "Workspace.CurrentCamera is unavailable right now",
|
|
4959
3740
|
}
|
|
4960
|
-
end)
|
|
4961
|
-
if success then
|
|
4962
|
-
finishRecording(recordingId, true)
|
|
4963
|
-
return result
|
|
4964
3741
|
end
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
local tagName = requestData.tagName
|
|
4972
|
-
if not (tagName ~= "" and tagName) then
|
|
3742
|
+
local _condition = tonumber(requestData.padding)
|
|
3743
|
+
if _condition == nil then
|
|
3744
|
+
_condition = 1
|
|
3745
|
+
end
|
|
3746
|
+
local padding = _condition
|
|
3747
|
+
if padding <= 0 or padding > 10 then
|
|
4973
3748
|
return {
|
|
4974
|
-
error = "
|
|
3749
|
+
error = "padding must be greater than 0 and at most 10",
|
|
4975
3750
|
}
|
|
4976
3751
|
end
|
|
4977
|
-
local
|
|
4978
|
-
|
|
4979
|
-
-- ▼ ReadonlyArray.map ▼
|
|
4980
|
-
local _newValue = table.create(#taggedInstances)
|
|
4981
|
-
local _callback = function(instance)
|
|
4982
|
-
return {
|
|
4983
|
-
name = instance.Name,
|
|
4984
|
-
className = instance.ClassName,
|
|
4985
|
-
path = getInstancePath(instance),
|
|
4986
|
-
}
|
|
4987
|
-
end
|
|
4988
|
-
for _k, _v in taggedInstances do
|
|
4989
|
-
_newValue[_k] = _callback(_v, _k - 1, taggedInstances)
|
|
4990
|
-
end
|
|
4991
|
-
-- ▲ ReadonlyArray.map ▲
|
|
4992
|
-
local instances = _newValue
|
|
3752
|
+
local compassOverride = if requestData.from == nil then nil else tonumber(requestData.from)
|
|
3753
|
+
if requestData.from ~= nil and compassOverride == nil then
|
|
4993
3754
|
return {
|
|
4994
|
-
|
|
4995
|
-
instances = instances,
|
|
4996
|
-
count = #instances,
|
|
3755
|
+
error = "from must be a compass angle in degrees",
|
|
4997
3756
|
}
|
|
4998
|
-
end)
|
|
4999
|
-
if success then
|
|
5000
|
-
return result
|
|
5001
3757
|
end
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
}
|
|
5005
|
-
end
|
|
5006
|
-
local function getSelection(_requestData)
|
|
5007
|
-
local selection = Selection:Get()
|
|
5008
|
-
if #selection == 0 then
|
|
3758
|
+
local elevationOverride = if requestData.angleY == nil then nil else tonumber(requestData.angleY)
|
|
3759
|
+
if requestData.angleY ~= nil and (elevationOverride == nil or elevationOverride < -89 or elevationOverride > 89) then
|
|
5009
3760
|
return {
|
|
5010
|
-
|
|
5011
|
-
selection = {},
|
|
5012
|
-
count = 0,
|
|
5013
|
-
message = "No objects selected",
|
|
3761
|
+
error = "angleY must be between -89 and 89",
|
|
5014
3762
|
}
|
|
5015
3763
|
end
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
3764
|
+
local ok, err = pcall(function()
|
|
3765
|
+
local boundsCF
|
|
3766
|
+
local boundsSize
|
|
3767
|
+
if instance:IsA("Model") then
|
|
3768
|
+
boundsCF, boundsSize = instance:GetBoundingBox()
|
|
3769
|
+
elseif instance:IsA("BasePart") then
|
|
3770
|
+
boundsCF = instance.CFrame
|
|
3771
|
+
boundsSize = instance.Size
|
|
3772
|
+
else
|
|
3773
|
+
return error(`Cannot frame a {instance.ClassName}: it has no 3D bounding box. Frame a part or model instead.`)
|
|
3774
|
+
end
|
|
3775
|
+
local center = boundsCF.Position
|
|
3776
|
+
local direction = camera.CFrame.LookVector * (-1)
|
|
3777
|
+
local currentHorizontal = Vector3.new(direction.X, 0, direction.Z)
|
|
3778
|
+
local horizontalDirection = if currentHorizontal.Magnitude < 0.001 then Vector3.new(1, 0, 0) else currentHorizontal.Unit
|
|
3779
|
+
if compassOverride ~= nil then
|
|
3780
|
+
local yaw = math.rad(compassOverride)
|
|
3781
|
+
horizontalDirection = Vector3.new(math.cos(yaw), 0, math.sin(yaw))
|
|
3782
|
+
end
|
|
3783
|
+
local vertical = direction.Y
|
|
3784
|
+
local horizontalMagnitude = math.sqrt(math.max(0, 1 - vertical * vertical))
|
|
3785
|
+
if elevationOverride ~= nil then
|
|
3786
|
+
local pitch = math.rad(elevationOverride)
|
|
3787
|
+
vertical = math.sin(pitch)
|
|
3788
|
+
horizontalMagnitude = math.cos(pitch)
|
|
3789
|
+
end
|
|
3790
|
+
local _horizontalDirection = horizontalDirection
|
|
3791
|
+
local _horizontalMagnitude = horizontalMagnitude
|
|
3792
|
+
local _vector3 = Vector3.new(0, vertical, 0)
|
|
3793
|
+
direction = (_horizontalDirection * _horizontalMagnitude + _vector3).Unit
|
|
3794
|
+
camera.CameraType = Enum.CameraType.Scriptable
|
|
3795
|
+
local _direction = direction
|
|
3796
|
+
local _arg0 = math.max(boundsSize.Magnitude, 1)
|
|
3797
|
+
camera.CFrame = CFrame.lookAt(center + (_direction * _arg0), center)
|
|
3798
|
+
camera.Focus = CFrame.new(center)
|
|
3799
|
+
camera:ZoomToExtents(boundsCF, boundsSize)
|
|
3800
|
+
if padding ~= 1 then
|
|
3801
|
+
local fittedOffset = camera.CFrame.Position - center
|
|
3802
|
+
local _arg0_1 = fittedOffset * padding
|
|
3803
|
+
camera.CFrame = CFrame.lookAt(center + _arg0_1, center)
|
|
3804
|
+
end
|
|
3805
|
+
camera.Focus = CFrame.new(center)
|
|
3806
|
+
end)
|
|
3807
|
+
if not ok then
|
|
5019
3808
|
return {
|
|
5020
|
-
|
|
5021
|
-
className = instance.ClassName,
|
|
5022
|
-
path = getInstancePath(instance),
|
|
5023
|
-
parent = if instance.Parent then getInstancePath(instance.Parent) else nil,
|
|
3809
|
+
error = `focus failed: {tostring(err)}`,
|
|
5024
3810
|
}
|
|
5025
3811
|
end
|
|
5026
|
-
for _k, _v in selection do
|
|
5027
|
-
_newValue[_k] = _callback(_v, _k - 1, selection)
|
|
5028
|
-
end
|
|
5029
|
-
-- ▲ ReadonlyArray.map ▲
|
|
5030
|
-
local selectedObjects = _newValue
|
|
5031
3812
|
return {
|
|
5032
3813
|
success = true,
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
3814
|
+
path = getInstancePath(instance),
|
|
3815
|
+
cameraPosition = {
|
|
3816
|
+
X = camera.CFrame.Position.X,
|
|
3817
|
+
Y = camera.CFrame.Position.Y,
|
|
3818
|
+
Z = camera.CFrame.Position.Z,
|
|
3819
|
+
},
|
|
5036
3820
|
}
|
|
5037
3821
|
end
|
|
5038
3822
|
local function executeLuau(requestData)
|
|
@@ -5048,106 +3832,17 @@ local function executeLuau(requestData)
|
|
|
5048
3832
|
-- the same code path and produce identical output shapes.
|
|
5049
3833
|
return LuauExec.execute(code)
|
|
5050
3834
|
end
|
|
5051
|
-
local function undo(_requestData)
|
|
5052
|
-
local success, result = pcall(function()
|
|
5053
|
-
ChangeHistoryService:Undo()
|
|
5054
|
-
return {
|
|
5055
|
-
success = true,
|
|
5056
|
-
message = "Undo executed successfully",
|
|
5057
|
-
}
|
|
5058
|
-
end)
|
|
5059
|
-
if success then
|
|
5060
|
-
return result
|
|
5061
|
-
end
|
|
5062
|
-
return {
|
|
5063
|
-
error = `Failed to undo: {result}`,
|
|
5064
|
-
}
|
|
5065
|
-
end
|
|
5066
|
-
local function redo(_requestData)
|
|
5067
|
-
local success, result = pcall(function()
|
|
5068
|
-
ChangeHistoryService:Redo()
|
|
5069
|
-
return {
|
|
5070
|
-
success = true,
|
|
5071
|
-
message = "Redo executed successfully",
|
|
5072
|
-
}
|
|
5073
|
-
end)
|
|
5074
|
-
if success then
|
|
5075
|
-
return result
|
|
5076
|
-
end
|
|
5077
|
-
return {
|
|
5078
|
-
error = `Failed to redo: {result}`,
|
|
5079
|
-
}
|
|
5080
|
-
end
|
|
5081
|
-
local function bulkSetAttributes(requestData)
|
|
5082
|
-
local instancePath = requestData.instancePath
|
|
5083
|
-
local attributes = requestData.attributes
|
|
5084
|
-
if not (instancePath ~= "" and instancePath) or not attributes then
|
|
5085
|
-
return {
|
|
5086
|
-
error = "Instance path and attributes are required",
|
|
5087
|
-
}
|
|
5088
|
-
end
|
|
5089
|
-
local instance = getInstanceByPath(instancePath)
|
|
5090
|
-
if not instance then
|
|
5091
|
-
return {
|
|
5092
|
-
error = `Instance not found: {instancePath}`,
|
|
5093
|
-
}
|
|
5094
|
-
end
|
|
5095
|
-
local recordingId = beginRecording(`Bulk set attributes on {instance.Name}`)
|
|
5096
|
-
local results = {}
|
|
5097
|
-
local successCount = 0
|
|
5098
|
-
local failureCount = 0
|
|
5099
|
-
for name, rawValue in pairs(attributes) do
|
|
5100
|
-
local attrName = name
|
|
5101
|
-
local ok, err = pcall(function()
|
|
5102
|
-
local value = deserializeValue(rawValue)
|
|
5103
|
-
instance:SetAttribute(attrName, value)
|
|
5104
|
-
end)
|
|
5105
|
-
if ok then
|
|
5106
|
-
successCount += 1
|
|
5107
|
-
local _arg0 = {
|
|
5108
|
-
attributeName = attrName,
|
|
5109
|
-
success = true,
|
|
5110
|
-
}
|
|
5111
|
-
table.insert(results, _arg0)
|
|
5112
|
-
else
|
|
5113
|
-
failureCount += 1
|
|
5114
|
-
local _arg0 = {
|
|
5115
|
-
attributeName = attrName,
|
|
5116
|
-
success = false,
|
|
5117
|
-
error = tostring(err),
|
|
5118
|
-
}
|
|
5119
|
-
table.insert(results, _arg0)
|
|
5120
|
-
end
|
|
5121
|
-
end
|
|
5122
|
-
finishRecording(recordingId, successCount > 0)
|
|
5123
|
-
return {
|
|
5124
|
-
instancePath = instancePath,
|
|
5125
|
-
results = results,
|
|
5126
|
-
summary = {
|
|
5127
|
-
total = successCount + failureCount,
|
|
5128
|
-
succeeded = successCount,
|
|
5129
|
-
failed = failureCount,
|
|
5130
|
-
},
|
|
5131
|
-
}
|
|
5132
|
-
end
|
|
5133
3835
|
return {
|
|
5134
|
-
setAttribute = setAttribute,
|
|
5135
3836
|
getAttributes = getAttributes,
|
|
5136
|
-
deleteAttribute = deleteAttribute,
|
|
5137
|
-
getTags = getTags,
|
|
5138
|
-
addTag = addTag,
|
|
5139
|
-
removeTag = removeTag,
|
|
5140
|
-
getTagged = getTagged,
|
|
5141
3837
|
getSelection = getSelection,
|
|
3838
|
+
setSelection = setSelection,
|
|
3839
|
+
focusViewport = focusViewport,
|
|
5142
3840
|
executeLuau = executeLuau,
|
|
5143
|
-
undo = undo,
|
|
5144
|
-
redo = redo,
|
|
5145
|
-
bulkSetAttributes = bulkSetAttributes,
|
|
5146
3841
|
}
|
|
5147
3842
|
]]></string>
|
|
5148
3843
|
</Properties>
|
|
5149
3844
|
</Item>
|
|
5150
|
-
<Item class="ModuleScript" referent="
|
|
3845
|
+
<Item class="ModuleScript" referent="16">
|
|
5151
3846
|
<Properties>
|
|
5152
3847
|
<string name="Name">MicroProfilerHandlers</string>
|
|
5153
3848
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -5162,6 +3857,8 @@ local DEFAULT_MAX_TIMERS_PER_GROUP = 5
|
|
|
5162
3857
|
local DEFAULT_MAX_RELATED_TIMERS = 3
|
|
5163
3858
|
local DEFAULT_MAX_EVENTS = 250000
|
|
5164
3859
|
local MAX_EVENTS = 1000000
|
|
3860
|
+
local COOPERATIVE_CLOCK_CHECK_INTERVAL = 128
|
|
3861
|
+
local MAX_COOPERATIVE_SLICE_SECONDS = 0.008
|
|
5165
3862
|
local DEFAULT_FRAME_WINDOW = 240
|
|
5166
3863
|
local BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
5167
3864
|
local PAD_BYTE = (string.byte("="))
|
|
@@ -5178,6 +3875,87 @@ local FOCUS_GROUP_MASKS = {
|
|
|
5178
3875
|
jobs = { "Jobs" },
|
|
5179
3876
|
}
|
|
5180
3877
|
local cachedLibMP
|
|
3878
|
+
-- Sampling the clock avoids a timing call for every event while still bounding
|
|
3879
|
+
-- each VM resumption. Sorting uses the same checkpoint so no full sort is atomic.
|
|
3880
|
+
local function createCooperativeCheckpoint()
|
|
3881
|
+
local operationsSinceClockCheck = 0
|
|
3882
|
+
local sliceStartedAt = os.clock()
|
|
3883
|
+
return function()
|
|
3884
|
+
operationsSinceClockCheck += 1
|
|
3885
|
+
if operationsSinceClockCheck < COOPERATIVE_CLOCK_CHECK_INTERVAL then
|
|
3886
|
+
return nil
|
|
3887
|
+
end
|
|
3888
|
+
operationsSinceClockCheck = 0
|
|
3889
|
+
if os.clock() - sliceStartedAt < MAX_COOPERATIVE_SLICE_SECONDS then
|
|
3890
|
+
return nil
|
|
3891
|
+
end
|
|
3892
|
+
task.wait()
|
|
3893
|
+
sliceStartedAt = os.clock()
|
|
3894
|
+
end
|
|
3895
|
+
end
|
|
3896
|
+
local function cooperativeSort(values, comesBefore, checkpoint)
|
|
3897
|
+
local count = #values
|
|
3898
|
+
if count < 2 then
|
|
3899
|
+
return nil
|
|
3900
|
+
end
|
|
3901
|
+
local function siftDown(start, lastIndex)
|
|
3902
|
+
local root = start
|
|
3903
|
+
while root * 2 + 1 <= lastIndex do
|
|
3904
|
+
checkpoint()
|
|
3905
|
+
local candidate = root
|
|
3906
|
+
local left = root * 2 + 1
|
|
3907
|
+
if comesBefore(values[candidate + 1], values[left + 1]) then
|
|
3908
|
+
candidate = left
|
|
3909
|
+
end
|
|
3910
|
+
local right = left + 1
|
|
3911
|
+
if right <= lastIndex and comesBefore(values[candidate + 1], values[right + 1]) then
|
|
3912
|
+
candidate = right
|
|
3913
|
+
end
|
|
3914
|
+
if candidate == root then
|
|
3915
|
+
return nil
|
|
3916
|
+
end
|
|
3917
|
+
local value = values[root + 1]
|
|
3918
|
+
values[root + 1] = values[candidate + 1]
|
|
3919
|
+
values[candidate + 1] = value
|
|
3920
|
+
root = candidate
|
|
3921
|
+
end
|
|
3922
|
+
end
|
|
3923
|
+
do
|
|
3924
|
+
local start = math.floor((count - 2) / 2)
|
|
3925
|
+
local _shouldIncrement = false
|
|
3926
|
+
while true do
|
|
3927
|
+
if _shouldIncrement then
|
|
3928
|
+
start -= 1
|
|
3929
|
+
else
|
|
3930
|
+
_shouldIncrement = true
|
|
3931
|
+
end
|
|
3932
|
+
if not (start >= 0) then
|
|
3933
|
+
break
|
|
3934
|
+
end
|
|
3935
|
+
siftDown(start, count - 1)
|
|
3936
|
+
checkpoint()
|
|
3937
|
+
end
|
|
3938
|
+
end
|
|
3939
|
+
do
|
|
3940
|
+
local lastIndex = count - 1
|
|
3941
|
+
local _shouldIncrement = false
|
|
3942
|
+
while true do
|
|
3943
|
+
if _shouldIncrement then
|
|
3944
|
+
lastIndex -= 1
|
|
3945
|
+
else
|
|
3946
|
+
_shouldIncrement = true
|
|
3947
|
+
end
|
|
3948
|
+
if not (lastIndex > 0) then
|
|
3949
|
+
break
|
|
3950
|
+
end
|
|
3951
|
+
local value = values[1]
|
|
3952
|
+
values[1] = values[lastIndex + 1]
|
|
3953
|
+
values[lastIndex + 1] = value
|
|
3954
|
+
checkpoint()
|
|
3955
|
+
siftDown(0, lastIndex - 1)
|
|
3956
|
+
end
|
|
3957
|
+
end
|
|
3958
|
+
end
|
|
5181
3959
|
local function normalizeDurationMs(value)
|
|
5182
3960
|
local _value = value
|
|
5183
3961
|
if not (type(_value) == "number") then
|
|
@@ -5305,7 +4083,7 @@ local function addFrameRaw(map, frameId, raw)
|
|
|
5305
4083
|
local _arg1 = _condition + raw
|
|
5306
4084
|
_map[_exp] = _arg1
|
|
5307
4085
|
end
|
|
5308
|
-
local function summarizeFrameImpact(frameRawById, analyzedFrames)
|
|
4086
|
+
local function summarizeFrameImpact(frameRawById, analyzedFrames, checkpoint)
|
|
5309
4087
|
local _condition = frameRawById == nil
|
|
5310
4088
|
if not _condition then
|
|
5311
4089
|
-- ▼ ReadonlyMap.size ▼
|
|
@@ -5330,6 +4108,7 @@ local function summarizeFrameImpact(frameRawById, analyzedFrames)
|
|
|
5330
4108
|
local maxUs = 0
|
|
5331
4109
|
local maxFrameId = 0
|
|
5332
4110
|
for frameId, raw in frameRawById do
|
|
4111
|
+
checkpoint()
|
|
5333
4112
|
local us = rawToUs(raw)
|
|
5334
4113
|
table.insert(values, us)
|
|
5335
4114
|
totalUs += us
|
|
@@ -5338,9 +4117,9 @@ local function summarizeFrameImpact(frameRawById, analyzedFrames)
|
|
|
5338
4117
|
maxFrameId = frameId
|
|
5339
4118
|
end
|
|
5340
4119
|
end
|
|
5341
|
-
|
|
4120
|
+
cooperativeSort(values, function(a, b)
|
|
5342
4121
|
return a < b
|
|
5343
|
-
end)
|
|
4122
|
+
end, checkpoint)
|
|
5344
4123
|
return {
|
|
5345
4124
|
active_frame_count = #values,
|
|
5346
4125
|
active_frame_pct = percent(#values, analyzedFrames),
|
|
@@ -5351,7 +4130,7 @@ local function summarizeFrameImpact(frameRawById, analyzedFrames)
|
|
|
5351
4130
|
max_frame_id = maxFrameId,
|
|
5352
4131
|
}
|
|
5353
4132
|
end
|
|
5354
|
-
local function encodeBase64(buf)
|
|
4133
|
+
local function encodeBase64(buf, checkpoint)
|
|
5355
4134
|
local len = buffer.len(buf)
|
|
5356
4135
|
local fullTriples = math.floor(len / 3)
|
|
5357
4136
|
local remaining = len - fullTriples * 3
|
|
@@ -5380,6 +4159,7 @@ local function encodeBase64(buf)
|
|
|
5380
4159
|
buffer.writeu8(out, di + 3, B64[bit32.band(b2, 63) + 1])
|
|
5381
4160
|
si += 3
|
|
5382
4161
|
di += 4
|
|
4162
|
+
checkpoint()
|
|
5383
4163
|
end
|
|
5384
4164
|
end
|
|
5385
4165
|
if remaining == 2 then
|
|
@@ -5490,7 +4270,7 @@ local function recommendedToolsForGroups(groups, targetRole)
|
|
|
5490
4270
|
end
|
|
5491
4271
|
return tools
|
|
5492
4272
|
end
|
|
5493
|
-
local function collectFrameSummary(session, startFrame, frameMax)
|
|
4273
|
+
local function collectFrameSummary(session, startFrame, frameMax, checkpoint)
|
|
5494
4274
|
local frameRows = {}
|
|
5495
4275
|
local durations = {}
|
|
5496
4276
|
local incompleteFrames = 0
|
|
@@ -5508,6 +4288,7 @@ local function collectFrameSummary(session, startFrame, frameMax)
|
|
|
5508
4288
|
if not (frameId <= frameMax) then
|
|
5509
4289
|
break
|
|
5510
4290
|
end
|
|
4291
|
+
checkpoint()
|
|
5511
4292
|
local ok, descOrErr = safeCall(function()
|
|
5512
4293
|
return session:GetFrameDesc(frameId)
|
|
5513
4294
|
end)
|
|
@@ -5547,15 +4328,16 @@ local function collectFrameSummary(session, startFrame, frameMax)
|
|
|
5547
4328
|
_frameId = frameId
|
|
5548
4329
|
end
|
|
5549
4330
|
end
|
|
5550
|
-
|
|
4331
|
+
cooperativeSort(durations, function(a, b)
|
|
5551
4332
|
return a < b
|
|
5552
|
-
end)
|
|
5553
|
-
|
|
4333
|
+
end, checkpoint)
|
|
4334
|
+
cooperativeSort(frameRows, function(a, b)
|
|
5554
4335
|
return (a.duration_us) > (b.duration_us)
|
|
5555
|
-
end)
|
|
4336
|
+
end, checkpoint)
|
|
5556
4337
|
local totalUs = 0
|
|
5557
4338
|
for _, duration in durations do
|
|
5558
4339
|
totalUs += duration
|
|
4340
|
+
checkpoint()
|
|
5559
4341
|
end
|
|
5560
4342
|
local topFrames = {}
|
|
5561
4343
|
do
|
|
@@ -5869,6 +4651,7 @@ local function captureMicroProfiler(requestData)
|
|
|
5869
4651
|
backend = backend,
|
|
5870
4652
|
}
|
|
5871
4653
|
end
|
|
4654
|
+
local checkpoint = createCooperativeCheckpoint()
|
|
5872
4655
|
local stacks = {}
|
|
5873
4656
|
local aggregates = {}
|
|
5874
4657
|
local timerThreadAggregates = {}
|
|
@@ -5884,7 +4667,11 @@ local function captureMicroProfiler(requestData)
|
|
|
5884
4667
|
local sampledFrameMax
|
|
5885
4668
|
local lastProcessedFrameId
|
|
5886
4669
|
local lastProcessedTimestampRaw
|
|
5887
|
-
while eventsSampled < maxEvents
|
|
4670
|
+
while eventsSampled < maxEvents do
|
|
4671
|
+
checkpoint()
|
|
4672
|
+
if not iterator:Step() then
|
|
4673
|
+
break
|
|
4674
|
+
end
|
|
5888
4675
|
eventsSampled += 1
|
|
5889
4676
|
local state = iterator:GetState()
|
|
5890
4677
|
if not state then
|
|
@@ -5925,6 +4712,7 @@ local function captureMicroProfiler(requestData)
|
|
|
5925
4712
|
exitEvents += 1
|
|
5926
4713
|
local entry
|
|
5927
4714
|
while #stack > 0 do
|
|
4715
|
+
checkpoint()
|
|
5928
4716
|
-- ▼ Array.pop ▼
|
|
5929
4717
|
local _length = #stack
|
|
5930
4718
|
local _result = stack[_length]
|
|
@@ -6002,7 +4790,7 @@ local function captureMicroProfiler(requestData)
|
|
|
6002
4790
|
_condition_2 = frameMax
|
|
6003
4791
|
end
|
|
6004
4792
|
local analysisFrameMax = _condition_2
|
|
6005
|
-
local frameSummary = collectFrameSummary(session, analysisFrameMin, analysisFrameMax)
|
|
4793
|
+
local frameSummary = collectFrameSummary(session, analysisFrameMin, analysisFrameMax, checkpoint)
|
|
6006
4794
|
local _frames = frameSummary.frames
|
|
6007
4795
|
local _condition_3 = type(_frames) == "number"
|
|
6008
4796
|
if _condition_3 then
|
|
@@ -6051,6 +4839,7 @@ local function captureMicroProfiler(requestData)
|
|
|
6051
4839
|
local omittedBelowThreshold = 0
|
|
6052
4840
|
local omittedByFilter = 0
|
|
6053
4841
|
for timerId, aggregate in aggregates do
|
|
4842
|
+
checkpoint()
|
|
6054
4843
|
local info = getTimerInfo(timerId)
|
|
6055
4844
|
local totalUs = rawToUs(aggregate.inclusive_raw)
|
|
6056
4845
|
if not includeIdle and isIdleTimer(info) then
|
|
@@ -6115,7 +4904,7 @@ local function captureMicroProfiler(requestData)
|
|
|
6115
4904
|
if maxToAvg ~= nil then
|
|
6116
4905
|
row.max_to_avg = maxToAvg
|
|
6117
4906
|
end
|
|
6118
|
-
local timerFrameImpact = summarizeFrameImpact(timerFrameAggregates[timerId], analysisFrameCount)
|
|
4907
|
+
local timerFrameImpact = summarizeFrameImpact(timerFrameAggregates[timerId], analysisFrameCount, checkpoint)
|
|
6119
4908
|
for key, value in pairs(timerFrameImpact) do
|
|
6120
4909
|
row[key] = value
|
|
6121
4910
|
end
|
|
@@ -6141,12 +4930,14 @@ local function captureMicroProfiler(requestData)
|
|
|
6141
4930
|
end
|
|
6142
4931
|
for frameId, raw in timerFrames do
|
|
6143
4932
|
addFrameRaw(groupFrames, frameId, raw)
|
|
4933
|
+
checkpoint()
|
|
6144
4934
|
end
|
|
6145
4935
|
end
|
|
6146
4936
|
local perThread = timerThreadAggregates[timerId]
|
|
6147
4937
|
if perThread ~= nil then
|
|
6148
4938
|
local timerThreadSummaryRows = {}
|
|
6149
4939
|
for threadId, threadAggregate in perThread do
|
|
4940
|
+
checkpoint()
|
|
6150
4941
|
local threadAggregateRow = threadAggregates[threadId]
|
|
6151
4942
|
if threadAggregateRow == nil then
|
|
6152
4943
|
threadAggregateRow = {
|
|
@@ -6205,9 +4996,9 @@ local function captureMicroProfiler(requestData)
|
|
|
6205
4996
|
}
|
|
6206
4997
|
table.insert(timerThreadSummaryRows, _arg0)
|
|
6207
4998
|
end
|
|
6208
|
-
|
|
4999
|
+
cooperativeSort(timerThreadSummaryRows, function(a, b)
|
|
6209
5000
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6210
|
-
end)
|
|
5001
|
+
end, checkpoint)
|
|
6211
5002
|
if maxRelatedTimers > 0 and #timerThreadSummaryRows > 0 then
|
|
6212
5003
|
local topTimerThreads = {}
|
|
6213
5004
|
do
|
|
@@ -6230,13 +5021,14 @@ local function captureMicroProfiler(requestData)
|
|
|
6230
5021
|
end
|
|
6231
5022
|
end
|
|
6232
5023
|
end
|
|
6233
|
-
|
|
5024
|
+
cooperativeSort(rows, function(a, b)
|
|
6234
5025
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6235
|
-
end)
|
|
5026
|
+
end, checkpoint)
|
|
6236
5027
|
local edgeRows = {}
|
|
6237
5028
|
local parentRelationsByChild = {}
|
|
6238
5029
|
local childRelationsByParent = {}
|
|
6239
5030
|
for _, edge in edgeAggregates do
|
|
5031
|
+
checkpoint()
|
|
6240
5032
|
local _parent_timer_id = edge.parent_timer_id
|
|
6241
5033
|
local parentRow = rowsByTimerId[_parent_timer_id]
|
|
6242
5034
|
local _child_timer_id = edge.child_timer_id
|
|
@@ -6307,21 +5099,24 @@ local function captureMicroProfiler(requestData)
|
|
|
6307
5099
|
}
|
|
6308
5100
|
table.insert(_childRelations, _arg0_1)
|
|
6309
5101
|
end
|
|
6310
|
-
|
|
5102
|
+
cooperativeSort(edgeRows, function(a, b)
|
|
6311
5103
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6312
|
-
end)
|
|
5104
|
+
end, checkpoint)
|
|
6313
5105
|
if maxRelatedTimers > 0 then
|
|
6314
5106
|
for _, relationRows in parentRelationsByChild do
|
|
6315
|
-
|
|
5107
|
+
checkpoint()
|
|
5108
|
+
cooperativeSort(relationRows, function(a, b)
|
|
6316
5109
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6317
|
-
end)
|
|
5110
|
+
end, checkpoint)
|
|
6318
5111
|
end
|
|
6319
5112
|
for _, relationRows in childRelationsByParent do
|
|
6320
|
-
|
|
5113
|
+
checkpoint()
|
|
5114
|
+
cooperativeSort(relationRows, function(a, b)
|
|
6321
5115
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6322
|
-
end)
|
|
5116
|
+
end, checkpoint)
|
|
6323
5117
|
end
|
|
6324
5118
|
for _, row in rows do
|
|
5119
|
+
checkpoint()
|
|
6325
5120
|
local timerId = row.timer_id
|
|
6326
5121
|
local parents = parentRelationsByChild[timerId]
|
|
6327
5122
|
local children = childRelationsByParent[timerId]
|
|
@@ -6388,10 +5183,11 @@ local function captureMicroProfiler(requestData)
|
|
|
6388
5183
|
local rowsByExclusive = {}
|
|
6389
5184
|
for _, row in rows do
|
|
6390
5185
|
table.insert(rowsByExclusive, row)
|
|
5186
|
+
checkpoint()
|
|
6391
5187
|
end
|
|
6392
|
-
|
|
5188
|
+
cooperativeSort(rowsByExclusive, function(a, b)
|
|
6393
5189
|
return (a.exclusive_us) > (b.exclusive_us)
|
|
6394
|
-
end)
|
|
5190
|
+
end, checkpoint)
|
|
6395
5191
|
local topTimersByExclusive = {}
|
|
6396
5192
|
do
|
|
6397
5193
|
local i = 0
|
|
@@ -6430,6 +5226,7 @@ local function captureMicroProfiler(requestData)
|
|
|
6430
5226
|
end
|
|
6431
5227
|
local threadRows = {}
|
|
6432
5228
|
for threadId, aggregate in threadAggregates do
|
|
5229
|
+
checkpoint()
|
|
6433
5230
|
local info = getThreadInfo(threadId)
|
|
6434
5231
|
local inclusiveUs = rawToUs(aggregate.inclusive_raw)
|
|
6435
5232
|
local exclusiveUs = rawToUs(aggregate.exclusive_raw)
|
|
@@ -6447,9 +5244,9 @@ local function captureMicroProfiler(requestData)
|
|
|
6447
5244
|
pct_of_analyzed_wall = percent(inclusiveUs, analysisDurationUs),
|
|
6448
5245
|
}
|
|
6449
5246
|
local timerRows = threadTimerRows[threadId] or {}
|
|
6450
|
-
|
|
5247
|
+
cooperativeSort(timerRows, function(a, b)
|
|
6451
5248
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6452
|
-
end)
|
|
5249
|
+
end, checkpoint)
|
|
6453
5250
|
local topThreadTimers = {}
|
|
6454
5251
|
do
|
|
6455
5252
|
local i = 0
|
|
@@ -6472,9 +5269,9 @@ local function captureMicroProfiler(requestData)
|
|
|
6472
5269
|
end
|
|
6473
5270
|
table.insert(threadRows, row)
|
|
6474
5271
|
end
|
|
6475
|
-
|
|
5272
|
+
cooperativeSort(threadRows, function(a, b)
|
|
6476
5273
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6477
|
-
end)
|
|
5274
|
+
end, checkpoint)
|
|
6478
5275
|
local topThreads = {}
|
|
6479
5276
|
do
|
|
6480
5277
|
local i = 0
|
|
@@ -6495,15 +5292,16 @@ local function captureMicroProfiler(requestData)
|
|
|
6495
5292
|
end
|
|
6496
5293
|
local groupRows = {}
|
|
6497
5294
|
for _, aggregate in groupAggregates do
|
|
5295
|
+
checkpoint()
|
|
6498
5296
|
local _group = aggregate.group
|
|
6499
5297
|
local _condition_5 = groupTimerRows[_group]
|
|
6500
5298
|
if _condition_5 == nil then
|
|
6501
5299
|
_condition_5 = {}
|
|
6502
5300
|
end
|
|
6503
5301
|
local timerRows = _condition_5
|
|
6504
|
-
|
|
5302
|
+
cooperativeSort(timerRows, function(a, b)
|
|
6505
5303
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6506
|
-
end)
|
|
5304
|
+
end, checkpoint)
|
|
6507
5305
|
local topGroupTimers = {}
|
|
6508
5306
|
do
|
|
6509
5307
|
local i = 0
|
|
@@ -6546,7 +5344,7 @@ local function captureMicroProfiler(requestData)
|
|
|
6546
5344
|
pct_of_analyzed_wall = percent(inclusiveUs, analysisDurationUs),
|
|
6547
5345
|
}
|
|
6548
5346
|
local _group_1 = aggregate.group
|
|
6549
|
-
local groupFrameImpact = summarizeFrameImpact(groupFrameAggregates[_group_1], analysisFrameCount)
|
|
5347
|
+
local groupFrameImpact = summarizeFrameImpact(groupFrameAggregates[_group_1], analysisFrameCount, checkpoint)
|
|
6550
5348
|
for key, value in pairs(groupFrameImpact) do
|
|
6551
5349
|
groupRow[key] = value
|
|
6552
5350
|
end
|
|
@@ -6555,9 +5353,9 @@ local function captureMicroProfiler(requestData)
|
|
|
6555
5353
|
end
|
|
6556
5354
|
table.insert(groupRows, groupRow)
|
|
6557
5355
|
end
|
|
6558
|
-
|
|
5356
|
+
cooperativeSort(groupRows, function(a, b)
|
|
6559
5357
|
return (a.inclusive_us) > (b.inclusive_us)
|
|
6560
|
-
end)
|
|
5358
|
+
end, checkpoint)
|
|
6561
5359
|
local topGroups = {}
|
|
6562
5360
|
do
|
|
6563
5361
|
local i = 0
|
|
@@ -6579,10 +5377,11 @@ local function captureMicroProfiler(requestData)
|
|
|
6579
5377
|
local groupRowsByExclusive = {}
|
|
6580
5378
|
for _, row in groupRows do
|
|
6581
5379
|
table.insert(groupRowsByExclusive, row)
|
|
5380
|
+
checkpoint()
|
|
6582
5381
|
end
|
|
6583
|
-
|
|
5382
|
+
cooperativeSort(groupRowsByExclusive, function(a, b)
|
|
6584
5383
|
return (a.exclusive_us) > (b.exclusive_us)
|
|
6585
|
-
end)
|
|
5384
|
+
end, checkpoint)
|
|
6586
5385
|
local topGroupsByExclusive = {}
|
|
6587
5386
|
do
|
|
6588
5387
|
local i = 0
|
|
@@ -6614,6 +5413,7 @@ local function captureMicroProfiler(requestData)
|
|
|
6614
5413
|
local openStackEntriesAtEnd = 0
|
|
6615
5414
|
for _, stack in stacks do
|
|
6616
5415
|
openStackEntriesAtEnd += #stack
|
|
5416
|
+
checkpoint()
|
|
6617
5417
|
end
|
|
6618
5418
|
local iteratorFinished = eventsSampled < maxEvents
|
|
6619
5419
|
local partialReasons = {}
|
|
@@ -6636,21 +5436,25 @@ local function captureMicroProfiler(requestData)
|
|
|
6636
5436
|
for _, row in rows do
|
|
6637
5437
|
local _arg0 = pickFields(row, timerFields)
|
|
6638
5438
|
table.insert(timerIndex, _arg0)
|
|
5439
|
+
checkpoint()
|
|
6639
5440
|
end
|
|
6640
5441
|
local groupIndex = {}
|
|
6641
5442
|
for _, row in groupRows do
|
|
6642
5443
|
local _arg0 = pickFields(row, groupFields)
|
|
6643
5444
|
table.insert(groupIndex, _arg0)
|
|
5445
|
+
checkpoint()
|
|
6644
5446
|
end
|
|
6645
5447
|
local threadIndex = {}
|
|
6646
5448
|
for _, row in threadRows do
|
|
6647
5449
|
local _arg0 = pickFields(row, threadFields)
|
|
6648
5450
|
table.insert(threadIndex, _arg0)
|
|
5451
|
+
checkpoint()
|
|
6649
5452
|
end
|
|
6650
5453
|
local edgeIndex = {}
|
|
6651
5454
|
for _, row in edgeRows do
|
|
6652
5455
|
local _arg0 = pickFields(row, edgeFields)
|
|
6653
5456
|
table.insert(edgeIndex, _arg0)
|
|
5457
|
+
checkpoint()
|
|
6654
5458
|
end
|
|
6655
5459
|
comparisonIndex = {
|
|
6656
5460
|
timers = timerIndex,
|
|
@@ -6779,7 +5583,7 @@ local function captureMicroProfiler(requestData)
|
|
|
6779
5583
|
result.snapshot_object_size_bytes = session:GetObjSize()
|
|
6780
5584
|
end
|
|
6781
5585
|
if includeRawBuffer then
|
|
6782
|
-
result.raw_snapshot_base64 = encodeBase64(snapshot)
|
|
5586
|
+
result.raw_snapshot_base64 = encodeBase64(snapshot, checkpoint)
|
|
6783
5587
|
end
|
|
6784
5588
|
iterator:Dispose()
|
|
6785
5589
|
session:Dispose()
|
|
@@ -6791,7 +5595,7 @@ return {
|
|
|
6791
5595
|
]]></string>
|
|
6792
5596
|
</Properties>
|
|
6793
5597
|
</Item>
|
|
6794
|
-
<Item class="ModuleScript" referent="
|
|
5598
|
+
<Item class="ModuleScript" referent="17">
|
|
6795
5599
|
<Properties>
|
|
6796
5600
|
<string name="Name">PropertyHandlers</string>
|
|
6797
5601
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -6804,170 +5608,6 @@ local convertPropertyValue = _binding.convertPropertyValue
|
|
|
6804
5608
|
local _binding_1 = Recording
|
|
6805
5609
|
local beginRecording = _binding_1.beginRecording
|
|
6806
5610
|
local finishRecording = _binding_1.finishRecording
|
|
6807
|
-
local function setProperty(requestData)
|
|
6808
|
-
local instancePath = requestData.instancePath
|
|
6809
|
-
local propertyName = requestData.propertyName
|
|
6810
|
-
local propertyValue = requestData.propertyValue
|
|
6811
|
-
if not (instancePath ~= "" and instancePath) or not (propertyName ~= "" and propertyName) then
|
|
6812
|
-
return {
|
|
6813
|
-
error = "Instance path and property name are required",
|
|
6814
|
-
}
|
|
6815
|
-
end
|
|
6816
|
-
local instance = getInstanceByPath(instancePath)
|
|
6817
|
-
if not instance then
|
|
6818
|
-
return {
|
|
6819
|
-
error = `Instance not found: {instancePath}`,
|
|
6820
|
-
}
|
|
6821
|
-
end
|
|
6822
|
-
local recordingId = beginRecording(`Set {propertyName} property`)
|
|
6823
|
-
local inst = instance
|
|
6824
|
-
local success, result = pcall(function()
|
|
6825
|
-
if propertyName == "Parent" or propertyName == "PrimaryPart" then
|
|
6826
|
-
if type(propertyValue) == "string" then
|
|
6827
|
-
local refInstance = getInstanceByPath(propertyValue)
|
|
6828
|
-
if refInstance then
|
|
6829
|
-
inst[propertyName] = refInstance
|
|
6830
|
-
else
|
|
6831
|
-
return {
|
|
6832
|
-
error = `{propertyName} instance not found: {propertyValue}`,
|
|
6833
|
-
}
|
|
6834
|
-
end
|
|
6835
|
-
end
|
|
6836
|
-
elseif propertyName == "Name" then
|
|
6837
|
-
instance.Name = tostring(propertyValue)
|
|
6838
|
-
elseif propertyName == "Source" and instance:IsA("LuaSourceContainer") then
|
|
6839
|
-
instance.Source = tostring(propertyValue)
|
|
6840
|
-
else
|
|
6841
|
-
local convertedValue = convertPropertyValue(instance, propertyName, propertyValue)
|
|
6842
|
-
if convertedValue ~= nil then
|
|
6843
|
-
inst[propertyName] = convertedValue
|
|
6844
|
-
else
|
|
6845
|
-
inst[propertyName] = propertyValue
|
|
6846
|
-
end
|
|
6847
|
-
end
|
|
6848
|
-
return true
|
|
6849
|
-
end)
|
|
6850
|
-
if success then
|
|
6851
|
-
finishRecording(recordingId, true)
|
|
6852
|
-
return {
|
|
6853
|
-
success = true,
|
|
6854
|
-
instancePath = instancePath,
|
|
6855
|
-
propertyName = propertyName,
|
|
6856
|
-
propertyValue = propertyValue,
|
|
6857
|
-
message = "Property set successfully",
|
|
6858
|
-
}
|
|
6859
|
-
else
|
|
6860
|
-
finishRecording(recordingId, false)
|
|
6861
|
-
return {
|
|
6862
|
-
error = `Failed to set property: {result}`,
|
|
6863
|
-
instancePath = instancePath,
|
|
6864
|
-
propertyName = propertyName,
|
|
6865
|
-
}
|
|
6866
|
-
end
|
|
6867
|
-
end
|
|
6868
|
-
local function massSetProperty(requestData)
|
|
6869
|
-
local paths = requestData.paths
|
|
6870
|
-
local propertyName = requestData.propertyName
|
|
6871
|
-
local propertyValue = requestData.propertyValue
|
|
6872
|
-
if not paths or not (type(paths) == "table") or #paths == 0 or not (propertyName ~= "" and propertyName) then
|
|
6873
|
-
return {
|
|
6874
|
-
error = "Paths array and property name are required",
|
|
6875
|
-
}
|
|
6876
|
-
end
|
|
6877
|
-
local results = {}
|
|
6878
|
-
local successCount = 0
|
|
6879
|
-
local failureCount = 0
|
|
6880
|
-
local recordingId = beginRecording(`Mass set {propertyName} property`)
|
|
6881
|
-
for _, path in paths do
|
|
6882
|
-
local instance = getInstanceByPath(path)
|
|
6883
|
-
if instance then
|
|
6884
|
-
local success, err = pcall(function()
|
|
6885
|
-
local converted = convertPropertyValue(instance, propertyName, propertyValue)
|
|
6886
|
-
instance[propertyName] = if converted ~= nil then converted else propertyValue
|
|
6887
|
-
end)
|
|
6888
|
-
if success then
|
|
6889
|
-
successCount += 1
|
|
6890
|
-
local _arg0 = {
|
|
6891
|
-
path = path,
|
|
6892
|
-
success = true,
|
|
6893
|
-
propertyName = propertyName,
|
|
6894
|
-
propertyValue = propertyValue,
|
|
6895
|
-
}
|
|
6896
|
-
table.insert(results, _arg0)
|
|
6897
|
-
else
|
|
6898
|
-
failureCount += 1
|
|
6899
|
-
local _arg0 = {
|
|
6900
|
-
path = path,
|
|
6901
|
-
success = false,
|
|
6902
|
-
error = tostring(err),
|
|
6903
|
-
}
|
|
6904
|
-
table.insert(results, _arg0)
|
|
6905
|
-
end
|
|
6906
|
-
else
|
|
6907
|
-
failureCount += 1
|
|
6908
|
-
local _arg0 = {
|
|
6909
|
-
path = path,
|
|
6910
|
-
success = false,
|
|
6911
|
-
error = "Instance not found",
|
|
6912
|
-
}
|
|
6913
|
-
table.insert(results, _arg0)
|
|
6914
|
-
end
|
|
6915
|
-
end
|
|
6916
|
-
finishRecording(recordingId, successCount > 0)
|
|
6917
|
-
return {
|
|
6918
|
-
results = results,
|
|
6919
|
-
summary = {
|
|
6920
|
-
total = #paths,
|
|
6921
|
-
succeeded = successCount,
|
|
6922
|
-
failed = failureCount,
|
|
6923
|
-
},
|
|
6924
|
-
}
|
|
6925
|
-
end
|
|
6926
|
-
local function massGetProperty(requestData)
|
|
6927
|
-
local paths = requestData.paths
|
|
6928
|
-
local propertyName = requestData.propertyName
|
|
6929
|
-
if not paths or not (type(paths) == "table") or #paths == 0 or not (propertyName ~= "" and propertyName) then
|
|
6930
|
-
return {
|
|
6931
|
-
error = "Paths array and property name are required",
|
|
6932
|
-
}
|
|
6933
|
-
end
|
|
6934
|
-
local results = {}
|
|
6935
|
-
for _, path in paths do
|
|
6936
|
-
local instance = getInstanceByPath(path)
|
|
6937
|
-
if instance then
|
|
6938
|
-
local success, value = pcall(function()
|
|
6939
|
-
return instance[propertyName]
|
|
6940
|
-
end)
|
|
6941
|
-
if success then
|
|
6942
|
-
local _arg0 = {
|
|
6943
|
-
path = path,
|
|
6944
|
-
success = true,
|
|
6945
|
-
propertyName = propertyName,
|
|
6946
|
-
propertyValue = value,
|
|
6947
|
-
}
|
|
6948
|
-
table.insert(results, _arg0)
|
|
6949
|
-
else
|
|
6950
|
-
local _arg0 = {
|
|
6951
|
-
path = path,
|
|
6952
|
-
success = false,
|
|
6953
|
-
error = tostring(value),
|
|
6954
|
-
}
|
|
6955
|
-
table.insert(results, _arg0)
|
|
6956
|
-
end
|
|
6957
|
-
else
|
|
6958
|
-
local _arg0 = {
|
|
6959
|
-
path = path,
|
|
6960
|
-
success = false,
|
|
6961
|
-
error = "Instance not found",
|
|
6962
|
-
}
|
|
6963
|
-
table.insert(results, _arg0)
|
|
6964
|
-
end
|
|
6965
|
-
end
|
|
6966
|
-
return {
|
|
6967
|
-
results = results,
|
|
6968
|
-
propertyName = propertyName,
|
|
6969
|
-
}
|
|
6970
|
-
end
|
|
6971
5611
|
local function setProperties(requestData)
|
|
6972
5612
|
local instancePath = requestData.instancePath
|
|
6973
5613
|
local properties = requestData.properties
|
|
@@ -7035,15 +5675,12 @@ local function setProperties(requestData)
|
|
|
7035
5675
|
}
|
|
7036
5676
|
end
|
|
7037
5677
|
return {
|
|
7038
|
-
setProperty = setProperty,
|
|
7039
|
-
massSetProperty = massSetProperty,
|
|
7040
|
-
massGetProperty = massGetProperty,
|
|
7041
5678
|
setProperties = setProperties,
|
|
7042
5679
|
}
|
|
7043
5680
|
]]></string>
|
|
7044
5681
|
</Properties>
|
|
7045
5682
|
</Item>
|
|
7046
|
-
<Item class="ModuleScript" referent="
|
|
5683
|
+
<Item class="ModuleScript" referent="18">
|
|
7047
5684
|
<Properties>
|
|
7048
5685
|
<string name="Name">QueryHandlers</string>
|
|
7049
5686
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -7177,48 +5814,6 @@ local function getPlaceInfo(_requestData)
|
|
|
7177
5814
|
},
|
|
7178
5815
|
}
|
|
7179
5816
|
end
|
|
7180
|
-
local function getServices(requestData)
|
|
7181
|
-
local serviceName = requestData.serviceName
|
|
7182
|
-
if serviceName ~= "" and serviceName then
|
|
7183
|
-
local ok, service = pcall(function()
|
|
7184
|
-
return game:GetService(serviceName)
|
|
7185
|
-
end)
|
|
7186
|
-
if ok and service then
|
|
7187
|
-
return {
|
|
7188
|
-
service = {
|
|
7189
|
-
name = service.Name,
|
|
7190
|
-
className = service.ClassName,
|
|
7191
|
-
path = getInstancePath(service),
|
|
7192
|
-
childCount = #service:GetChildren(),
|
|
7193
|
-
},
|
|
7194
|
-
}
|
|
7195
|
-
else
|
|
7196
|
-
return {
|
|
7197
|
-
error = `Service not found: {serviceName}`,
|
|
7198
|
-
}
|
|
7199
|
-
end
|
|
7200
|
-
else
|
|
7201
|
-
local services = {}
|
|
7202
|
-
local commonServices = { "Workspace", "Players", "StarterGui", "StarterPack", "StarterPlayer", "ReplicatedStorage", "ServerStorage", "ServerScriptService", "HttpService", "TeleportService", "DataStoreService" }
|
|
7203
|
-
for _, svcName in commonServices do
|
|
7204
|
-
local ok, service = pcall(function()
|
|
7205
|
-
return game:GetService(svcName)
|
|
7206
|
-
end)
|
|
7207
|
-
if ok and service then
|
|
7208
|
-
local _arg0 = {
|
|
7209
|
-
name = service.Name,
|
|
7210
|
-
className = service.ClassName,
|
|
7211
|
-
path = getInstancePath(service),
|
|
7212
|
-
childCount = #service:GetChildren(),
|
|
7213
|
-
}
|
|
7214
|
-
table.insert(services, _arg0)
|
|
7215
|
-
end
|
|
7216
|
-
end
|
|
7217
|
-
return {
|
|
7218
|
-
services = services,
|
|
7219
|
-
}
|
|
7220
|
-
end
|
|
7221
|
-
end
|
|
7222
5817
|
local function searchObjects(requestData)
|
|
7223
5818
|
local query = requestData.query
|
|
7224
5819
|
local _condition = (requestData.searchType)
|
|
@@ -7397,39 +5992,6 @@ local function getInstanceProperties(requestData)
|
|
|
7397
5992
|
}
|
|
7398
5993
|
end
|
|
7399
5994
|
end
|
|
7400
|
-
local function getInstanceChildren(requestData)
|
|
7401
|
-
local instancePath = requestData.instancePath
|
|
7402
|
-
if not (instancePath ~= "" and instancePath) then
|
|
7403
|
-
return {
|
|
7404
|
-
error = "Instance path is required",
|
|
7405
|
-
}
|
|
7406
|
-
end
|
|
7407
|
-
local instance = getInstanceByPath(instancePath)
|
|
7408
|
-
if not instance then
|
|
7409
|
-
return {
|
|
7410
|
-
error = `Instance not found: {instancePath}`,
|
|
7411
|
-
}
|
|
7412
|
-
end
|
|
7413
|
-
local children = {}
|
|
7414
|
-
for _, child in instance:GetChildren() do
|
|
7415
|
-
local entry = {
|
|
7416
|
-
name = child.Name,
|
|
7417
|
-
className = child.ClassName,
|
|
7418
|
-
path = getInstancePath(child),
|
|
7419
|
-
hasChildren = #child:GetChildren() > 0,
|
|
7420
|
-
hasSource = child:IsA("LuaSourceContainer"),
|
|
7421
|
-
}
|
|
7422
|
-
if child:IsA("BaseScript") then
|
|
7423
|
-
entry.enabled = child.Enabled
|
|
7424
|
-
end
|
|
7425
|
-
table.insert(children, entry)
|
|
7426
|
-
end
|
|
7427
|
-
return {
|
|
7428
|
-
instancePath = instancePath,
|
|
7429
|
-
children = children,
|
|
7430
|
-
count = #children,
|
|
7431
|
-
}
|
|
7432
|
-
end
|
|
7433
5995
|
local function searchByProperty(requestData)
|
|
7434
5996
|
local propertyName = requestData.propertyName
|
|
7435
5997
|
local propertyValue = requestData.propertyValue
|
|
@@ -7974,133 +6536,21 @@ local function grepScripts(requestData)
|
|
|
7974
6536
|
},
|
|
7975
6537
|
}
|
|
7976
6538
|
end
|
|
7977
|
-
local function getDescendants(requestData)
|
|
7978
|
-
local instancePath = requestData.instancePath
|
|
7979
|
-
if not (instancePath ~= "" and instancePath) then
|
|
7980
|
-
return {
|
|
7981
|
-
error = "Instance path is required",
|
|
7982
|
-
}
|
|
7983
|
-
end
|
|
7984
|
-
local _condition = (requestData.maxDepth)
|
|
7985
|
-
if _condition == nil then
|
|
7986
|
-
_condition = 10
|
|
7987
|
-
end
|
|
7988
|
-
local maxDepth = _condition
|
|
7989
|
-
local classFilter = requestData.classFilter
|
|
7990
|
-
local instance = getInstanceByPath(instancePath)
|
|
7991
|
-
if not instance then
|
|
7992
|
-
return {
|
|
7993
|
-
error = `Instance not found: {instancePath}`,
|
|
7994
|
-
}
|
|
7995
|
-
end
|
|
7996
|
-
local descendants = {}
|
|
7997
|
-
local function collect(inst, depth)
|
|
7998
|
-
if depth > maxDepth then
|
|
7999
|
-
return nil
|
|
8000
|
-
end
|
|
8001
|
-
for _, child in inst:GetChildren() do
|
|
8002
|
-
local _condition_1 = classFilter
|
|
8003
|
-
if _condition_1 ~= "" and _condition_1 then
|
|
8004
|
-
_condition_1 = not child:IsA(classFilter)
|
|
8005
|
-
end
|
|
8006
|
-
if _condition_1 ~= "" and _condition_1 then
|
|
8007
|
-
continue
|
|
8008
|
-
end
|
|
8009
|
-
local _arg0 = {
|
|
8010
|
-
name = child.Name,
|
|
8011
|
-
className = child.ClassName,
|
|
8012
|
-
path = getInstancePath(child),
|
|
8013
|
-
depth = depth,
|
|
8014
|
-
}
|
|
8015
|
-
table.insert(descendants, _arg0)
|
|
8016
|
-
collect(child, depth + 1)
|
|
8017
|
-
end
|
|
8018
|
-
end
|
|
8019
|
-
collect(instance, 1)
|
|
8020
|
-
return {
|
|
8021
|
-
instancePath = instancePath,
|
|
8022
|
-
descendants = descendants,
|
|
8023
|
-
count = #descendants,
|
|
8024
|
-
maxDepth = maxDepth,
|
|
8025
|
-
}
|
|
8026
|
-
end
|
|
8027
|
-
local function compareInstances(requestData)
|
|
8028
|
-
local instancePathA = requestData.instancePathA
|
|
8029
|
-
local instancePathB = requestData.instancePathB
|
|
8030
|
-
if not (instancePathA ~= "" and instancePathA) or not (instancePathB ~= "" and instancePathB) then
|
|
8031
|
-
return {
|
|
8032
|
-
error = "Both instancePathA and instancePathB are required",
|
|
8033
|
-
}
|
|
8034
|
-
end
|
|
8035
|
-
local instA = getInstanceByPath(instancePathA)
|
|
8036
|
-
if not instA then
|
|
8037
|
-
return {
|
|
8038
|
-
error = `Instance not found: {instancePathA}`,
|
|
8039
|
-
}
|
|
8040
|
-
end
|
|
8041
|
-
local instB = getInstanceByPath(instancePathB)
|
|
8042
|
-
if not instB then
|
|
8043
|
-
return {
|
|
8044
|
-
error = `Instance not found: {instancePathB}`,
|
|
8045
|
-
}
|
|
8046
|
-
end
|
|
8047
|
-
local commonProps = { "Name", "ClassName", "Size", "Position", "Rotation", "CFrame", "Anchored", "CanCollide", "Transparency", "BrickColor", "Material", "Color", "Text", "TextColor3", "BackgroundColor3", "Image", "ImageColor3", "Visible", "Active", "ZIndex", "BorderSizePixel", "BackgroundTransparency", "ImageTransparency", "TextTransparency", "Value", "Enabled", "Brightness", "Range", "Shadows" }
|
|
8048
|
-
local matching = {}
|
|
8049
|
-
local differing = {}
|
|
8050
|
-
local onlyA = {}
|
|
8051
|
-
local onlyB = {}
|
|
8052
|
-
for _, prop in commonProps do
|
|
8053
|
-
local okA, valA = pcall(function()
|
|
8054
|
-
return tostring(instA[prop])
|
|
8055
|
-
end)
|
|
8056
|
-
local okB, valB = pcall(function()
|
|
8057
|
-
return tostring(instB[prop])
|
|
8058
|
-
end)
|
|
8059
|
-
if okA and okB then
|
|
8060
|
-
if valA == valB then
|
|
8061
|
-
matching[prop] = valA
|
|
8062
|
-
else
|
|
8063
|
-
differing[prop] = {
|
|
8064
|
-
a = valA,
|
|
8065
|
-
b = valB,
|
|
8066
|
-
}
|
|
8067
|
-
end
|
|
8068
|
-
elseif okA then
|
|
8069
|
-
table.insert(onlyA, prop)
|
|
8070
|
-
elseif okB then
|
|
8071
|
-
table.insert(onlyB, prop)
|
|
8072
|
-
end
|
|
8073
|
-
end
|
|
8074
|
-
return {
|
|
8075
|
-
instancePathA = instancePathA,
|
|
8076
|
-
instancePathB = instancePathB,
|
|
8077
|
-
classNameA = instA.ClassName,
|
|
8078
|
-
classNameB = instB.ClassName,
|
|
8079
|
-
matching = matching,
|
|
8080
|
-
differing = differing,
|
|
8081
|
-
onlyA = onlyA,
|
|
8082
|
-
onlyB = onlyB,
|
|
8083
|
-
}
|
|
8084
|
-
end
|
|
8085
6539
|
return {
|
|
8086
6540
|
getFileTree = getFileTree,
|
|
8087
6541
|
searchFiles = searchFiles,
|
|
8088
6542
|
getPlaceInfo = getPlaceInfo,
|
|
8089
|
-
getServices = getServices,
|
|
8090
6543
|
searchObjects = searchObjects,
|
|
8091
6544
|
getInstanceProperties = getInstanceProperties,
|
|
8092
|
-
getInstanceChildren = getInstanceChildren,
|
|
8093
6545
|
searchByProperty = searchByProperty,
|
|
8094
6546
|
getClassInfo = getClassInfo,
|
|
8095
6547
|
getProjectStructure = getProjectStructure,
|
|
8096
6548
|
grepScripts = grepScripts,
|
|
8097
|
-
getDescendants = getDescendants,
|
|
8098
|
-
compareInstances = compareInstances,
|
|
8099
6549
|
}
|
|
8100
6550
|
]]></string>
|
|
8101
6551
|
</Properties>
|
|
8102
6552
|
</Item>
|
|
8103
|
-
<Item class="ModuleScript" referent="
|
|
6553
|
+
<Item class="ModuleScript" referent="19">
|
|
8104
6554
|
<Properties>
|
|
8105
6555
|
<string name="Name">SceneAnalysisHandlers</string>
|
|
8106
6556
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -8349,18 +6799,18 @@ return {
|
|
|
8349
6799
|
]]></string>
|
|
8350
6800
|
</Properties>
|
|
8351
6801
|
</Item>
|
|
8352
|
-
<Item class="ModuleScript" referent="
|
|
6802
|
+
<Item class="ModuleScript" referent="20">
|
|
8353
6803
|
<Properties>
|
|
8354
6804
|
<string name="Name">ScriptHandlers</string>
|
|
8355
6805
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
8356
6806
|
local TS = require(script.Parent.Parent.Parent.include.RuntimeLib)
|
|
8357
6807
|
local Utils = TS.import(script, script.Parent.Parent, "Utils")
|
|
8358
6808
|
local Recording = TS.import(script, script.Parent.Parent, "Recording")
|
|
8359
|
-
local ScriptEditorService = game:GetService("ScriptEditorService")
|
|
8360
6809
|
local _binding = Utils
|
|
8361
6810
|
local getInstancePath = _binding.getInstancePath
|
|
8362
6811
|
local getInstanceByPath = _binding.getInstanceByPath
|
|
8363
6812
|
local readScriptSource = _binding.readScriptSource
|
|
6813
|
+
local applyScriptSource = _binding.applyScriptSource
|
|
8364
6814
|
local splitLines = _binding.splitLines
|
|
8365
6815
|
local joinLines = _binding.joinLines
|
|
8366
6816
|
local _binding_1 = Recording
|
|
@@ -8506,7 +6956,7 @@ end
|
|
|
8506
6956
|
local function setScriptSource(requestData)
|
|
8507
6957
|
local instancePath = requestData.instancePath
|
|
8508
6958
|
local newSource = requestData.source
|
|
8509
|
-
if not (instancePath ~= "" and instancePath) or not (newSource
|
|
6959
|
+
if not (instancePath ~= "" and instancePath) or not (type(newSource) == "string") then
|
|
8510
6960
|
return {
|
|
8511
6961
|
error = "Instance path and source are required",
|
|
8512
6962
|
}
|
|
@@ -8524,42 +6974,27 @@ local function setScriptSource(requestData)
|
|
|
8524
6974
|
end
|
|
8525
6975
|
local sourceToSet = normalizeEscapes(newSource)
|
|
8526
6976
|
local recordingId = beginRecording(`Set script source: {instance.Name}`)
|
|
8527
|
-
local
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
if readScriptSource(instance) ~= sourceToSet then
|
|
8533
|
-
error("UpdateSourceAsync completed without updating the script source")
|
|
8534
|
-
end
|
|
6977
|
+
local readSuccess, readResult = pcall(function()
|
|
6978
|
+
return #readScriptSource(instance)
|
|
6979
|
+
end)
|
|
6980
|
+
if not readSuccess then
|
|
6981
|
+
finishRecording(recordingId, false)
|
|
8535
6982
|
return {
|
|
8536
|
-
|
|
8537
|
-
instancePath = instancePath,
|
|
8538
|
-
oldSourceLength = oldSourceLength,
|
|
8539
|
-
newSourceLength = #sourceToSet,
|
|
8540
|
-
method = "UpdateSourceAsync",
|
|
8541
|
-
message = "Script source updated successfully (editor-safe)",
|
|
6983
|
+
error = `Failed to read script source before updating: {readResult}`,
|
|
8542
6984
|
}
|
|
8543
|
-
end)
|
|
8544
|
-
if updateSuccess then
|
|
8545
|
-
finishRecording(recordingId, true)
|
|
8546
|
-
return updateResult
|
|
8547
6985
|
end
|
|
8548
|
-
local
|
|
8549
|
-
|
|
8550
|
-
|
|
6986
|
+
local oldSourceLength = readResult
|
|
6987
|
+
local applyResult = applyScriptSource(instance, sourceToSet)
|
|
6988
|
+
if applyResult.success then
|
|
6989
|
+
finishRecording(recordingId, true)
|
|
8551
6990
|
return {
|
|
8552
6991
|
success = true,
|
|
8553
6992
|
instancePath = instancePath,
|
|
8554
|
-
oldSourceLength =
|
|
6993
|
+
oldSourceLength = oldSourceLength,
|
|
8555
6994
|
newSourceLength = #sourceToSet,
|
|
8556
|
-
method =
|
|
8557
|
-
message =
|
|
6995
|
+
method = applyResult.method,
|
|
6996
|
+
message = `Script source updated successfully ({if applyResult.method == "UpdateSourceAsync" then "editor-safe" else "direct assignment"})`,
|
|
8558
6997
|
}
|
|
8559
|
-
end)
|
|
8560
|
-
if directSuccess then
|
|
8561
|
-
finishRecording(recordingId, true)
|
|
8562
|
-
return directResult
|
|
8563
6998
|
end
|
|
8564
6999
|
local replaceSuccess, replaceResult = pcall(function()
|
|
8565
7000
|
local parent = instance.Parent
|
|
@@ -8569,9 +7004,15 @@ local function setScriptSource(requestData)
|
|
|
8569
7004
|
local enabled = if wasBaseScript then instance.Enabled else nil
|
|
8570
7005
|
local newScript = Instance.new(className)
|
|
8571
7006
|
newScript.Name = name
|
|
8572
|
-
|
|
7007
|
+
-- @rbxts/types does not expose PluginSecurity Source writes.
|
|
7008
|
+
local writableNewScript = newScript
|
|
7009
|
+
writableNewScript.Source = sourceToSet
|
|
7010
|
+
if readScriptSource(newScript) ~= sourceToSet then
|
|
7011
|
+
error("Replacement script source did not match the requested source")
|
|
7012
|
+
end
|
|
8573
7013
|
if wasBaseScript and enabled ~= nil then
|
|
8574
|
-
|
|
7014
|
+
local newBaseScript = newScript
|
|
7015
|
+
newBaseScript.Enabled = enabled
|
|
8575
7016
|
end
|
|
8576
7017
|
newScript.Parent = parent
|
|
8577
7018
|
instance:Destroy()
|
|
@@ -8588,7 +7029,7 @@ local function setScriptSource(requestData)
|
|
|
8588
7029
|
end
|
|
8589
7030
|
finishRecording(recordingId, false)
|
|
8590
7031
|
return {
|
|
8591
|
-
error = `Failed to set script source.
|
|
7032
|
+
error = `Failed to set script source. {applyResult.error} Replace method failed: {replaceResult}`,
|
|
8592
7033
|
}
|
|
8593
7034
|
end
|
|
8594
7035
|
local function editScriptLines(requestData)
|
|
@@ -8666,12 +7107,14 @@ local function editScriptLines(requestData)
|
|
|
8666
7107
|
end
|
|
8667
7108
|
-- Byte-slice replacement avoids Lua pattern escaping (safe for multi-byte chars like em dashes).
|
|
8668
7109
|
local newSource = string.sub(source, 1, matchStart - 1) .. newString .. string.sub(source, matchStart + searchLen)
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
7110
|
+
local applyResult = applyScriptSource(instance, newSource, source)
|
|
7111
|
+
if not applyResult.success then
|
|
7112
|
+
error(applyResult.error)
|
|
7113
|
+
end
|
|
8672
7114
|
return {
|
|
8673
7115
|
success = true,
|
|
8674
7116
|
instancePath = instancePath,
|
|
7117
|
+
method = applyResult.method,
|
|
8675
7118
|
message = "Script edited successfully",
|
|
8676
7119
|
}
|
|
8677
7120
|
end)
|
|
@@ -8711,7 +7154,8 @@ local function insertScriptLines(requestData)
|
|
|
8711
7154
|
end
|
|
8712
7155
|
local recordingId = beginRecording(`Insert script lines after line {afterLine}: {instance.Name}`)
|
|
8713
7156
|
local success, result = pcall(function()
|
|
8714
|
-
local
|
|
7157
|
+
local source = readScriptSource(instance)
|
|
7158
|
+
local lines, hadTrailingNewline = splitLines(source)
|
|
8715
7159
|
local totalLines = #lines
|
|
8716
7160
|
if afterLine < 0 or afterLine > totalLines then
|
|
8717
7161
|
error(`afterLine out of range (0-{totalLines})`)
|
|
@@ -8754,15 +7198,17 @@ local function insertScriptLines(requestData)
|
|
|
8754
7198
|
end
|
|
8755
7199
|
end
|
|
8756
7200
|
local newSource = joinLines(resultLines, hadTrailingNewline)
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
7201
|
+
local applyResult = applyScriptSource(instance, newSource, source)
|
|
7202
|
+
if not applyResult.success then
|
|
7203
|
+
error(applyResult.error)
|
|
7204
|
+
end
|
|
8760
7205
|
return {
|
|
8761
7206
|
success = true,
|
|
8762
7207
|
instancePath = instancePath,
|
|
8763
7208
|
insertedAfterLine = afterLine,
|
|
8764
7209
|
linesInserted = #newLines,
|
|
8765
7210
|
newLineCount = #resultLines,
|
|
7211
|
+
method = applyResult.method,
|
|
8766
7212
|
message = "Script lines inserted successfully",
|
|
8767
7213
|
}
|
|
8768
7214
|
end)
|
|
@@ -8797,7 +7243,8 @@ local function deleteScriptLines(requestData)
|
|
|
8797
7243
|
end
|
|
8798
7244
|
local recordingId = beginRecording(`Delete script lines {startLine}-{endLine}: {instance.Name}`)
|
|
8799
7245
|
local success, result = pcall(function()
|
|
8800
|
-
local
|
|
7246
|
+
local source = readScriptSource(instance)
|
|
7247
|
+
local lines, hadTrailingNewline = splitLines(source)
|
|
8801
7248
|
local totalLines = #lines
|
|
8802
7249
|
if startLine < 1 or startLine > totalLines then
|
|
8803
7250
|
error(`startLine out of range (1-{totalLines})`)
|
|
@@ -8839,9 +7286,10 @@ local function deleteScriptLines(requestData)
|
|
|
8839
7286
|
end
|
|
8840
7287
|
end
|
|
8841
7288
|
local newSource = joinLines(resultLines, hadTrailingNewline)
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
7289
|
+
local applyResult = applyScriptSource(instance, newSource, source)
|
|
7290
|
+
if not applyResult.success then
|
|
7291
|
+
error(applyResult.error)
|
|
7292
|
+
end
|
|
8845
7293
|
return {
|
|
8846
7294
|
success = true,
|
|
8847
7295
|
instancePath = instancePath,
|
|
@@ -8851,6 +7299,7 @@ local function deleteScriptLines(requestData)
|
|
|
8851
7299
|
},
|
|
8852
7300
|
linesDeleted = endLine - startLine + 1,
|
|
8853
7301
|
newLineCount = #resultLines,
|
|
7302
|
+
method = applyResult.method,
|
|
8854
7303
|
message = "Script lines deleted successfully",
|
|
8855
7304
|
}
|
|
8856
7305
|
end)
|
|
@@ -8953,17 +7402,14 @@ local function findAndReplaceInScripts(requestData)
|
|
|
8953
7402
|
if hitLimit then
|
|
8954
7403
|
return nil
|
|
8955
7404
|
end
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
if _condition_5 ~= "" and _condition_5 then
|
|
8965
|
-
return nil
|
|
8966
|
-
end
|
|
7405
|
+
local _condition_5 = classFilter == nil
|
|
7406
|
+
if not _condition_5 then
|
|
7407
|
+
local _exp = string.lower(instance.ClassName)
|
|
7408
|
+
local _arg0 = string.lower(classFilter)
|
|
7409
|
+
_condition_5 = (string.find(_exp, _arg0)) ~= nil
|
|
7410
|
+
end
|
|
7411
|
+
local matchesClass = _condition_5
|
|
7412
|
+
if instance:IsA("LuaSourceContainer") and matchesClass then
|
|
8967
7413
|
scriptsSearched += 1
|
|
8968
7414
|
local source = readScriptSource(instance)
|
|
8969
7415
|
local newSource
|
|
@@ -8988,24 +7434,31 @@ local function findAndReplaceInScripts(requestData)
|
|
|
8988
7434
|
hitLimit = true
|
|
8989
7435
|
return nil
|
|
8990
7436
|
end
|
|
8991
|
-
|
|
8992
|
-
if not
|
|
8993
|
-
local
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
7437
|
+
local applyResult = if dryRun then nil else applyScriptSource(instance, newSource, source)
|
|
7438
|
+
if applyResult ~= nil and not applyResult.success then
|
|
7439
|
+
local _object = {
|
|
7440
|
+
instancePath = getInstancePath(instance),
|
|
7441
|
+
name = instance.Name,
|
|
7442
|
+
className = instance.ClassName,
|
|
7443
|
+
replacements = 0,
|
|
7444
|
+
}
|
|
7445
|
+
local _left = "error"
|
|
7446
|
+
local _condition_6 = applyResult.error
|
|
7447
|
+
if _condition_6 == nil then
|
|
7448
|
+
_condition_6 = "Script write failed verification"
|
|
9000
7449
|
end
|
|
7450
|
+
_object[_left] = _condition_6
|
|
7451
|
+
table.insert(changes, _object)
|
|
7452
|
+
else
|
|
7453
|
+
totalReplacements += replCount
|
|
7454
|
+
local _arg0 = {
|
|
7455
|
+
instancePath = getInstancePath(instance),
|
|
7456
|
+
name = instance.Name,
|
|
7457
|
+
className = instance.ClassName,
|
|
7458
|
+
replacements = replCount,
|
|
7459
|
+
}
|
|
7460
|
+
table.insert(changes, _arg0)
|
|
9001
7461
|
end
|
|
9002
|
-
local _arg0 = {
|
|
9003
|
-
instancePath = getInstancePath(instance),
|
|
9004
|
-
name = instance.Name,
|
|
9005
|
-
className = instance.ClassName,
|
|
9006
|
-
replacements = replCount,
|
|
9007
|
-
}
|
|
9008
|
-
table.insert(changes, _arg0)
|
|
9009
7462
|
end
|
|
9010
7463
|
end
|
|
9011
7464
|
for _, child in instance:GetChildren() do
|
|
@@ -9015,18 +7468,37 @@ local function findAndReplaceInScripts(requestData)
|
|
|
9015
7468
|
processInstance(child)
|
|
9016
7469
|
end
|
|
9017
7470
|
end
|
|
9018
|
-
|
|
7471
|
+
local traversalSuccess, traversalResult = pcall(function()
|
|
7472
|
+
return processInstance(startInstance)
|
|
7473
|
+
end)
|
|
7474
|
+
-- ▼ ReadonlyArray.filter ▼
|
|
7475
|
+
local _newValue = {}
|
|
7476
|
+
local _callback = function(change)
|
|
7477
|
+
return change.error ~= nil
|
|
7478
|
+
end
|
|
7479
|
+
local _length = 0
|
|
7480
|
+
for _k, _v in changes do
|
|
7481
|
+
if _callback(_v, _k - 1, changes) == true then
|
|
7482
|
+
_length += 1
|
|
7483
|
+
_newValue[_length] = _v
|
|
7484
|
+
end
|
|
7485
|
+
end
|
|
7486
|
+
-- ▲ ReadonlyArray.filter ▲
|
|
7487
|
+
local failedScripts = #_newValue
|
|
7488
|
+
local scriptsModified = #changes - failedScripts
|
|
9019
7489
|
if recordingId ~= nil then
|
|
9020
|
-
finishRecording(recordingId,
|
|
7490
|
+
finishRecording(recordingId, scriptsModified > 0)
|
|
9021
7491
|
end
|
|
9022
7492
|
return {
|
|
9023
|
-
success =
|
|
7493
|
+
success = traversalSuccess and failedScripts == 0,
|
|
7494
|
+
error = if traversalSuccess then nil else `Script traversal failed: {traversalResult}`,
|
|
9024
7495
|
dryRun = dryRun,
|
|
9025
7496
|
pattern = searchPattern,
|
|
9026
7497
|
replacement = replacement,
|
|
9027
7498
|
totalReplacements = totalReplacements,
|
|
9028
7499
|
scriptsSearched = scriptsSearched,
|
|
9029
|
-
scriptsModified =
|
|
7500
|
+
scriptsModified = scriptsModified,
|
|
7501
|
+
scriptsFailed = failedScripts,
|
|
9030
7502
|
changes = changes,
|
|
9031
7503
|
truncated = hitLimit,
|
|
9032
7504
|
}
|
|
@@ -9042,7 +7514,7 @@ return {
|
|
|
9042
7514
|
]]></string>
|
|
9043
7515
|
</Properties>
|
|
9044
7516
|
</Item>
|
|
9045
|
-
<Item class="ModuleScript" referent="
|
|
7517
|
+
<Item class="ModuleScript" referent="21">
|
|
9046
7518
|
<Properties>
|
|
9047
7519
|
<string name="Name">ScriptProfilerHandlers</string>
|
|
9048
7520
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -9505,7 +7977,7 @@ return {
|
|
|
9505
7977
|
]]></string>
|
|
9506
7978
|
</Properties>
|
|
9507
7979
|
</Item>
|
|
9508
|
-
<Item class="ModuleScript" referent="
|
|
7980
|
+
<Item class="ModuleScript" referent="22">
|
|
9509
7981
|
<Properties>
|
|
9510
7982
|
<string name="Name">SerializationHandlers</string>
|
|
9511
7983
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -9691,7 +8163,7 @@ return {
|
|
|
9691
8163
|
]]></string>
|
|
9692
8164
|
</Properties>
|
|
9693
8165
|
</Item>
|
|
9694
|
-
<Item class="ModuleScript" referent="
|
|
8166
|
+
<Item class="ModuleScript" referent="23">
|
|
9695
8167
|
<Properties>
|
|
9696
8168
|
<string name="Name">TestHandlers</string>
|
|
9697
8169
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -10070,7 +8542,7 @@ return {
|
|
|
10070
8542
|
</Properties>
|
|
10071
8543
|
</Item>
|
|
10072
8544
|
</Item>
|
|
10073
|
-
<Item class="ModuleScript" referent="
|
|
8545
|
+
<Item class="ModuleScript" referent="24">
|
|
10074
8546
|
<Properties>
|
|
10075
8547
|
<string name="Name">HttpDiagnostics</string>
|
|
10076
8548
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -10151,7 +8623,7 @@ return {
|
|
|
10151
8623
|
]]></string>
|
|
10152
8624
|
</Properties>
|
|
10153
8625
|
</Item>
|
|
10154
|
-
<Item class="ModuleScript" referent="
|
|
8626
|
+
<Item class="ModuleScript" referent="25">
|
|
10155
8627
|
<Properties>
|
|
10156
8628
|
<string name="Name">LuauExec</string>
|
|
10157
8629
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -10585,7 +9057,7 @@ return {
|
|
|
10585
9057
|
]]></string>
|
|
10586
9058
|
</Properties>
|
|
10587
9059
|
</Item>
|
|
10588
|
-
<Item class="ModuleScript" referent="
|
|
9060
|
+
<Item class="ModuleScript" referent="26">
|
|
10589
9061
|
<Properties>
|
|
10590
9062
|
<string name="Name">Recording</string>
|
|
10591
9063
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -10615,7 +9087,7 @@ return {
|
|
|
10615
9087
|
]]></string>
|
|
10616
9088
|
</Properties>
|
|
10617
9089
|
</Item>
|
|
10618
|
-
<Item class="ModuleScript" referent="
|
|
9090
|
+
<Item class="ModuleScript" referent="27">
|
|
10619
9091
|
<Properties>
|
|
10620
9092
|
<string name="Name">RenderMonitor</string>
|
|
10621
9093
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -10683,7 +9155,7 @@ return {
|
|
|
10683
9155
|
]]></string>
|
|
10684
9156
|
</Properties>
|
|
10685
9157
|
</Item>
|
|
10686
|
-
<Item class="ModuleScript" referent="
|
|
9158
|
+
<Item class="ModuleScript" referent="28">
|
|
10687
9159
|
<Properties>
|
|
10688
9160
|
<string name="Name">RuntimeLogBuffer</string>
|
|
10689
9161
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -10938,7 +9410,7 @@ return {
|
|
|
10938
9410
|
]]></string>
|
|
10939
9411
|
</Properties>
|
|
10940
9412
|
</Item>
|
|
10941
|
-
<Item class="ModuleScript" referent="
|
|
9413
|
+
<Item class="ModuleScript" referent="29">
|
|
10942
9414
|
<Properties>
|
|
10943
9415
|
<string name="Name">ServerUrlSettings</string>
|
|
10944
9416
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -11088,11 +9560,11 @@ return {
|
|
|
11088
9560
|
]]></string>
|
|
11089
9561
|
</Properties>
|
|
11090
9562
|
</Item>
|
|
11091
|
-
<Item class="ModuleScript" referent="
|
|
9563
|
+
<Item class="ModuleScript" referent="30">
|
|
11092
9564
|
<Properties>
|
|
11093
9565
|
<string name="Name">State</string>
|
|
11094
9566
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
11095
|
-
local CURRENT_VERSION = "
|
|
9567
|
+
local CURRENT_VERSION = "3.0.1"
|
|
11096
9568
|
local PLUGIN_VARIANT = "main"
|
|
11097
9569
|
local BASE_PORT = 58741
|
|
11098
9570
|
local function createConnection(port)
|
|
@@ -11128,7 +9600,7 @@ return {
|
|
|
11128
9600
|
]]></string>
|
|
11129
9601
|
</Properties>
|
|
11130
9602
|
</Item>
|
|
11131
|
-
<Item class="ModuleScript" referent="
|
|
9603
|
+
<Item class="ModuleScript" referent="31">
|
|
11132
9604
|
<Properties>
|
|
11133
9605
|
<string name="Name">StopPlayMonitor</string>
|
|
11134
9606
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -11426,7 +9898,7 @@ return {
|
|
|
11426
9898
|
]]></string>
|
|
11427
9899
|
</Properties>
|
|
11428
9900
|
</Item>
|
|
11429
|
-
<Item class="ModuleScript" referent="
|
|
9901
|
+
<Item class="ModuleScript" referent="32">
|
|
11430
9902
|
<Properties>
|
|
11431
9903
|
<string name="Name">UI</string>
|
|
11432
9904
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -11978,7 +10450,7 @@ return {
|
|
|
11978
10450
|
]]></string>
|
|
11979
10451
|
</Properties>
|
|
11980
10452
|
</Item>
|
|
11981
|
-
<Item class="ModuleScript" referent="
|
|
10453
|
+
<Item class="ModuleScript" referent="33">
|
|
11982
10454
|
<Properties>
|
|
11983
10455
|
<string name="Name">Utils</string>
|
|
11984
10456
|
<string name="Source"><![CDATA[-- Compiled with roblox-ts v3.0.0
|
|
@@ -12298,11 +10770,62 @@ local function readScriptSource(instance)
|
|
|
12298
10770
|
end
|
|
12299
10771
|
return nil
|
|
12300
10772
|
end)
|
|
12301
|
-
|
|
12302
|
-
if _value ~= "" and _value then
|
|
10773
|
+
if ok and result ~= nil then
|
|
12303
10774
|
return result
|
|
12304
10775
|
end
|
|
12305
|
-
|
|
10776
|
+
-- @rbxts/types does not expose PluginSecurity Source reads.
|
|
10777
|
+
local readableScript = instance
|
|
10778
|
+
return readableScript.Source
|
|
10779
|
+
end
|
|
10780
|
+
--[[
|
|
10781
|
+
*
|
|
10782
|
+
* Writes newSource to instance and verifies the live editor text before
|
|
10783
|
+
* reporting success. expectedSource turns line-based edits into a
|
|
10784
|
+
* compare-and-set operation: if the document changes while
|
|
10785
|
+
* UpdateSourceAsync yields or before the direct fallback runs, the write is
|
|
10786
|
+
* rejected instead of overwriting the newer draft.
|
|
10787
|
+
|
|
10788
|
+
]]
|
|
10789
|
+
local function applyScriptSource(instance, newSource, expectedSource)
|
|
10790
|
+
local updateSuccess, updateResult = pcall(function()
|
|
10791
|
+
ScriptEditorService:UpdateSourceAsync(instance, function(currentSource)
|
|
10792
|
+
if expectedSource ~= nil and currentSource ~= expectedSource then
|
|
10793
|
+
error("Script source changed while the edit was being applied; read the script again and retry")
|
|
10794
|
+
end
|
|
10795
|
+
return newSource
|
|
10796
|
+
end)
|
|
10797
|
+
if readScriptSource(instance) ~= newSource then
|
|
10798
|
+
error("UpdateSourceAsync completed without updating the live script source")
|
|
10799
|
+
end
|
|
10800
|
+
end)
|
|
10801
|
+
if updateSuccess then
|
|
10802
|
+
return {
|
|
10803
|
+
success = true,
|
|
10804
|
+
method = "UpdateSourceAsync",
|
|
10805
|
+
}
|
|
10806
|
+
end
|
|
10807
|
+
local directSuccess, directResult = pcall(function()
|
|
10808
|
+
if expectedSource ~= nil and readScriptSource(instance) ~= expectedSource then
|
|
10809
|
+
error("Script source changed before direct assignment; read the script again and retry")
|
|
10810
|
+
end
|
|
10811
|
+
-- @rbxts/types does not expose PluginSecurity Source writes.
|
|
10812
|
+
local writableScript = instance
|
|
10813
|
+
writableScript.Source = newSource
|
|
10814
|
+
if readScriptSource(instance) ~= newSource then
|
|
10815
|
+
error("Direct assignment completed without updating the live script source")
|
|
10816
|
+
end
|
|
10817
|
+
end)
|
|
10818
|
+
if directSuccess then
|
|
10819
|
+
return {
|
|
10820
|
+
success = true,
|
|
10821
|
+
method = "direct",
|
|
10822
|
+
}
|
|
10823
|
+
end
|
|
10824
|
+
return {
|
|
10825
|
+
success = false,
|
|
10826
|
+
method = "direct",
|
|
10827
|
+
error = `UpdateSourceAsync failed: {updateResult}. Direct assignment failed: {directResult}`,
|
|
10828
|
+
}
|
|
12306
10829
|
end
|
|
12307
10830
|
local function convertPropertyValue(instance, propertyName, propertyValue)
|
|
12308
10831
|
if propertyValue == nil then
|
|
@@ -12763,6 +11286,7 @@ return {
|
|
|
12763
11286
|
splitLines = splitLines,
|
|
12764
11287
|
joinLines = joinLines,
|
|
12765
11288
|
readScriptSource = readScriptSource,
|
|
11289
|
+
applyScriptSource = applyScriptSource,
|
|
12766
11290
|
convertPropertyValue = convertPropertyValue,
|
|
12767
11291
|
evaluateFormula = evaluateFormula,
|
|
12768
11292
|
compareVersions = compareVersions,
|
|
@@ -12771,11 +11295,11 @@ return {
|
|
|
12771
11295
|
</Properties>
|
|
12772
11296
|
</Item>
|
|
12773
11297
|
</Item>
|
|
12774
|
-
<Item class="Folder" referent="
|
|
11298
|
+
<Item class="Folder" referent="38">
|
|
12775
11299
|
<Properties>
|
|
12776
11300
|
<string name="Name">include</string>
|
|
12777
11301
|
</Properties>
|
|
12778
|
-
<Item class="ModuleScript" referent="
|
|
11302
|
+
<Item class="ModuleScript" referent="34">
|
|
12779
11303
|
<Properties>
|
|
12780
11304
|
<string name="Name">LibMP</string>
|
|
12781
11305
|
<string name="Source"><![CDATA[-- =============================================================================
|
|
@@ -169159,7 +167683,7 @@ return LibMP
|
|
|
169159
167683
|
]]></string>
|
|
169160
167684
|
</Properties>
|
|
169161
167685
|
</Item>
|
|
169162
|
-
<Item class="ModuleScript" referent="
|
|
167686
|
+
<Item class="ModuleScript" referent="35">
|
|
169163
167687
|
<Properties>
|
|
169164
167688
|
<string name="Name">Promise</string>
|
|
169165
167689
|
<string name="Source"><![CDATA[--[[
|
|
@@ -171233,7 +169757,7 @@ return Promise
|
|
|
171233
169757
|
]]></string>
|
|
171234
169758
|
</Properties>
|
|
171235
169759
|
</Item>
|
|
171236
|
-
<Item class="ModuleScript" referent="
|
|
169760
|
+
<Item class="ModuleScript" referent="36">
|
|
171237
169761
|
<Properties>
|
|
171238
169762
|
<string name="Name">RuntimeLib</string>
|
|
171239
169763
|
<string name="Source"><![CDATA[local Promise = require(script.Parent.Promise)
|
|
@@ -171500,15 +170024,15 @@ return TS
|
|
|
171500
170024
|
</Properties>
|
|
171501
170025
|
</Item>
|
|
171502
170026
|
</Item>
|
|
171503
|
-
<Item class="Folder" referent="
|
|
170027
|
+
<Item class="Folder" referent="39">
|
|
171504
170028
|
<Properties>
|
|
171505
170029
|
<string name="Name">node_modules</string>
|
|
171506
170030
|
</Properties>
|
|
171507
|
-
<Item class="Folder" referent="
|
|
170031
|
+
<Item class="Folder" referent="40">
|
|
171508
170032
|
<Properties>
|
|
171509
170033
|
<string name="Name">@rbxts</string>
|
|
171510
170034
|
</Properties>
|
|
171511
|
-
<Item class="ModuleScript" referent="
|
|
170035
|
+
<Item class="ModuleScript" referent="37">
|
|
171512
170036
|
<Properties>
|
|
171513
170037
|
<string name="Name">services</string>
|
|
171514
170038
|
<string name="Source"><![CDATA[return setmetatable({}, {
|