roport 1.3.1 → 1.3.2
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/package.json
CHANGED
|
@@ -602,7 +602,7 @@ local function pullChanges()
|
|
|
602
602
|
if data.changes and #data.changes > 0 then
|
|
603
603
|
print("Roport: Pulling " .. #data.changes .. " files...")
|
|
604
604
|
for _, change in ipairs(data.changes) do
|
|
605
|
-
applyUpdate(change.filePath, change.content)
|
|
605
|
+
applyUpdate(change.filePath, change.content, change.absolutePath)
|
|
606
606
|
end
|
|
607
607
|
showToast("Updated " .. #data.changes .. " files", "success")
|
|
608
608
|
else
|
|
@@ -746,7 +746,7 @@ end
|
|
|
746
746
|
-- Two-Way Sync Logic
|
|
747
747
|
local function findInstanceByPath(path)
|
|
748
748
|
-- Remove extension
|
|
749
|
-
local cleanPath = path:gsub("%.server%.luau$", ""):gsub("%.client%.luau$", ""):gsub("%.luau$", ""):gsub("/init%.meta%.json$", "")
|
|
749
|
+
local cleanPath = path:gsub("%.server%.luau$", ""):gsub("%.client%.luau$", ""):gsub("%.luau$", ""):gsub("%.server%.lua$", ""):gsub("%.client%.lua$", ""):gsub("%.lua$", ""):gsub("/init%.meta%.json$", "")
|
|
750
750
|
|
|
751
751
|
local parts = cleanPath:split("/")
|
|
752
752
|
if parts[1] ~= "src" then return nil end
|
|
@@ -779,7 +779,7 @@ local function findInstanceByPath(path)
|
|
|
779
779
|
end
|
|
780
780
|
|
|
781
781
|
local function createInstanceByPath(path, content)
|
|
782
|
-
local cleanPath = path:gsub("%.server%.luau$", ""):gsub("%.client%.luau$", ""):gsub("%.luau$", ""):gsub("/init%.meta%.json$", "")
|
|
782
|
+
local cleanPath = path:gsub("%.server%.luau$", ""):gsub("%.client%.luau$", ""):gsub("%.luau$", ""):gsub("%.server%.lua$", ""):gsub("%.client%.lua$", ""):gsub("%.lua$", ""):gsub("/init%.meta%.json$", "")
|
|
783
783
|
local parts = cleanPath:split("/")
|
|
784
784
|
if parts[1] ~= "src" then return nil end
|
|
785
785
|
|
|
@@ -807,9 +807,9 @@ local function createInstanceByPath(path, content)
|
|
|
807
807
|
local className = "Folder"
|
|
808
808
|
|
|
809
809
|
if isLast then
|
|
810
|
-
if path:match("%.server%.luau$") then className = "Script"
|
|
811
|
-
elseif path:match("%.client%.luau$") then className = "LocalScript"
|
|
812
|
-
elseif path:match("%.luau$") then className = "ModuleScript"
|
|
810
|
+
if path:match("%.server%.luau$") or path:match("%.server%.lua$") then className = "Script"
|
|
811
|
+
elseif path:match("%.client%.luau$") or path:match("%.client%.lua$") then className = "LocalScript"
|
|
812
|
+
elseif path:match("%.luau$") or path:match("%.lua$") then className = "ModuleScript"
|
|
813
813
|
elseif path:match("%.json$") then
|
|
814
814
|
-- Try to peek className from content
|
|
815
815
|
local success, data = pcall(function() return HttpService:JSONDecode(content) end)
|
|
@@ -834,7 +834,47 @@ local function createInstanceByPath(path, content)
|
|
|
834
834
|
return current
|
|
835
835
|
end
|
|
836
836
|
|
|
837
|
-
local function applyUpdate(filePath, content)
|
|
837
|
+
local function applyUpdate(filePath, content, absolutePath)
|
|
838
|
+
-- Handle RBXMX
|
|
839
|
+
if filePath:match("%.rbxmx$") and absolutePath then
|
|
840
|
+
local success, model = pcall(function()
|
|
841
|
+
return game:GetService("InsertService"):LoadLocalAsset(absolutePath)
|
|
842
|
+
end)
|
|
843
|
+
|
|
844
|
+
if success and model then
|
|
845
|
+
local parentPath = filePath:match("(.+)/[^/]+$")
|
|
846
|
+
local parentInst = findInstanceByPath(parentPath or "")
|
|
847
|
+
|
|
848
|
+
if not parentInst and parentPath then
|
|
849
|
+
parentInst = createInstanceByPath(parentPath, "")
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
if parentInst then
|
|
853
|
+
local children = model:GetChildren()
|
|
854
|
+
if #children > 0 then
|
|
855
|
+
local newObj = children[1]
|
|
856
|
+
local name = filePath:match("([^/]+)%.rbxmx$")
|
|
857
|
+
local existing = parentInst:FindFirstChild(name)
|
|
858
|
+
|
|
859
|
+
if existing then
|
|
860
|
+
newObj.Name = existing.Name
|
|
861
|
+
newObj.Parent = existing.Parent
|
|
862
|
+
existing:Destroy()
|
|
863
|
+
else
|
|
864
|
+
newObj.Name = name
|
|
865
|
+
newObj.Parent = parentInst
|
|
866
|
+
end
|
|
867
|
+
print("Roport: Imported " .. newObj.Name .. " from " .. filePath)
|
|
868
|
+
end
|
|
869
|
+
else
|
|
870
|
+
warn("Roport: Could not find parent for " .. filePath)
|
|
871
|
+
end
|
|
872
|
+
else
|
|
873
|
+
warn("Roport: Failed to load RBXMX: " .. tostring(model))
|
|
874
|
+
end
|
|
875
|
+
return
|
|
876
|
+
end
|
|
877
|
+
|
|
838
878
|
local inst = findInstanceByPath(filePath)
|
|
839
879
|
if not inst then
|
|
840
880
|
inst = createInstanceByPath(filePath, content)
|
|
@@ -894,7 +934,7 @@ task.spawn(function()
|
|
|
894
934
|
if data.changes and #data.changes > 0 then
|
|
895
935
|
print("Roport: Received " .. #data.changes .. " updates from VS Code")
|
|
896
936
|
for _, change in ipairs(data.changes) do
|
|
897
|
-
applyUpdate(change.filePath, change.content)
|
|
937
|
+
applyUpdate(change.filePath, change.content, change.absolutePath)
|
|
898
938
|
end
|
|
899
939
|
end
|
|
900
940
|
else
|
package/src/server.js
CHANGED
|
@@ -195,9 +195,9 @@ function startServer(port) {
|
|
|
195
195
|
const stat = await fs.stat(fullPath);
|
|
196
196
|
if (stat.isFile()) {
|
|
197
197
|
const content = await fs.readFile(fullPath, 'utf8');
|
|
198
|
-
response.changes.push({ filePath, content });
|
|
198
|
+
response.changes.push({ filePath, absolutePath: fullPath, content });
|
|
199
199
|
} else if (stat.isDirectory()) {
|
|
200
|
-
response.changes.push({ filePath, isDirectory: true });
|
|
200
|
+
response.changes.push({ filePath, absolutePath: fullPath, isDirectory: true });
|
|
201
201
|
}
|
|
202
202
|
} else {
|
|
203
203
|
// File Does Not Exist -> Deletion
|
|
@@ -12,7 +12,7 @@ local RunService = game:GetService("RunService")
|
|
|
12
12
|
local TweenService = game:GetService("TweenService")
|
|
13
13
|
local ScriptEditorService = game:GetService("ScriptEditorService")
|
|
14
14
|
|
|
15
|
-
print("Roport Plugin v1.3.
|
|
15
|
+
print("Roport Plugin v1.3.2 Loaded (Project Config Support)")
|
|
16
16
|
|
|
17
17
|
-- Prevent running as a normal script
|
|
18
18
|
if not plugin then return end
|
|
@@ -685,7 +685,7 @@ local function pullChanges()
|
|
|
685
685
|
if data.changes and #data.changes > 0 then
|
|
686
686
|
print("Roport: Pulling " .. #data.changes .. " files...")
|
|
687
687
|
for _, change in ipairs(data.changes) do
|
|
688
|
-
applyUpdate(change.filePath, change.content)
|
|
688
|
+
applyUpdate(change.filePath, change.content, change.absolutePath)
|
|
689
689
|
end
|
|
690
690
|
showToast("Updated " .. #data.changes .. " files", "success")
|
|
691
691
|
else
|
|
@@ -960,97 +960,8 @@ local function findInstanceByPath(path)
|
|
|
960
960
|
return nil
|
|
961
961
|
end
|
|
962
962
|
|
|
963
|
-
-- XML Parser for .rbxmx support
|
|
964
|
-
local function parseRbxmx(content)
|
|
965
|
-
local roots = {}
|
|
966
|
-
local stack = {}
|
|
967
|
-
local current = nil
|
|
968
|
-
|
|
969
|
-
-- Helper to decode entities
|
|
970
|
-
local function decode(s)
|
|
971
|
-
return s:gsub("<", "<"):gsub(">", ">"):gsub(""", '"'):gsub("'", "'"):gsub("&", "&")
|
|
972
|
-
end
|
|
973
|
-
|
|
974
|
-
-- 1. Extract Items
|
|
975
|
-
-- We iterate through the string finding <Item ...> and </Item>
|
|
976
|
-
-- This is a simplified parser that assumes well-formed Roblox XML
|
|
977
|
-
|
|
978
|
-
local pos = 1
|
|
979
|
-
while true do
|
|
980
|
-
local s, e, tag, attrs = content:find("<Item%s+([^>]+)>", pos)
|
|
981
|
-
local sEnd, eEnd = content:find("</Item>", pos)
|
|
982
|
-
|
|
983
|
-
if not s and not sEnd then break end
|
|
984
|
-
|
|
985
|
-
if s and (not sEnd or s < sEnd) then
|
|
986
|
-
-- Found start tag
|
|
987
|
-
local class = attrs:match('class="([^"]+)"')
|
|
988
|
-
local inst = Instance.new(class or "Folder")
|
|
989
|
-
|
|
990
|
-
-- Parse Properties immediately following
|
|
991
|
-
local propStart, propEnd = content:find("<Properties>", e)
|
|
992
|
-
if propStart then
|
|
993
|
-
local propContentEnd = content:find("</Properties>", propEnd)
|
|
994
|
-
if propContentEnd then
|
|
995
|
-
local propBlock = content:sub(propEnd + 1, propContentEnd - 1)
|
|
996
|
-
|
|
997
|
-
-- Parse properties
|
|
998
|
-
for pType, pName, pVal in propBlock:gmatch("<(%w+)%s+name=\"([^\"]+)\">([^<]*)</%1>") do
|
|
999
|
-
pcall(function()
|
|
1000
|
-
if pType == "string" then inst[pName] = decode(pVal)
|
|
1001
|
-
elseif pType == "bool" then inst[pName] = (pVal == "true")
|
|
1002
|
-
elseif pType == "float" or pType == "double" or pType == "int" or pType == "int64" then inst[pName] = tonumber(pVal)
|
|
1003
|
-
elseif pType == "Color3" or pType == "Color3uint8" then
|
|
1004
|
-
-- Complex types usually have nested tags in newer format, or text in older
|
|
1005
|
-
-- This simple parser handles basic types. Complex types need more logic.
|
|
1006
|
-
end
|
|
1007
|
-
end)
|
|
1008
|
-
end
|
|
1009
|
-
|
|
1010
|
-
-- Handle nested tags for complex properties (Vector3, Color3, etc)
|
|
1011
|
-
-- <Vector3 name="Position"><X>0</X><Y>10</Y><Z>0</Z></Vector3>
|
|
1012
|
-
for pType, pName, pInner in propBlock:gmatch("<(%w+)%s+name=\"([^\"]+)\">([%s%S]-)</%1>") do
|
|
1013
|
-
pcall(function()
|
|
1014
|
-
if pType == "Vector3" then
|
|
1015
|
-
local x = tonumber(pInner:match("<X>(.-)</X>"))
|
|
1016
|
-
local y = tonumber(pInner:match("<Y>(.-)</Y>"))
|
|
1017
|
-
local z = tonumber(pInner:match("<Z>(.-)</Z>"))
|
|
1018
|
-
inst[pName] = Vector3.new(x, y, z)
|
|
1019
|
-
elseif pType == "Color3" then
|
|
1020
|
-
local r = tonumber(pInner:match("<R>(.-)</R>"))
|
|
1021
|
-
local g = tonumber(pInner:match("<G>(.-)</G>"))
|
|
1022
|
-
local b = tonumber(pInner:match("<B>(.-)</B>"))
|
|
1023
|
-
inst[pName] = Color3.new(r, g, b)
|
|
1024
|
-
elseif pType == "UDim2" then
|
|
1025
|
-
local xs = tonumber(pInner:match("<XS>(.-)</XS>"))
|
|
1026
|
-
local xo = tonumber(pInner:match("<XO>(.-)</XO>"))
|
|
1027
|
-
local ys = tonumber(pInner:match("<YS>(.-)</YS>"))
|
|
1028
|
-
local yo = tonumber(pInner:match("<YO>(.-)</YO>"))
|
|
1029
|
-
inst[pName] = UDim2.new(xs, xo, ys, yo)
|
|
1030
|
-
end
|
|
1031
|
-
end)
|
|
1032
|
-
end
|
|
1033
|
-
end
|
|
1034
|
-
end
|
|
1035
|
-
|
|
1036
|
-
if current then
|
|
1037
|
-
inst.Parent = current
|
|
1038
|
-
else
|
|
1039
|
-
table.insert(roots, inst)
|
|
1040
|
-
end
|
|
1041
|
-
|
|
1042
|
-
table.insert(stack, current)
|
|
1043
|
-
current = inst
|
|
1044
|
-
pos = e + 1
|
|
1045
|
-
else
|
|
1046
|
-
-- Found end tag
|
|
1047
|
-
current = table.remove(stack)
|
|
1048
|
-
pos = eEnd + 1
|
|
1049
|
-
end
|
|
1050
|
-
end
|
|
1051
|
-
|
|
1052
|
-
return roots
|
|
1053
|
-
end
|
|
963
|
+
-- XML Parser for .rbxmx support (Deprecated/Unused - using InsertService instead)
|
|
964
|
+
-- local function parseRbxmx(content) ... end
|
|
1054
965
|
|
|
1055
966
|
local function createInstanceByPath(path, content)
|
|
1056
967
|
local isInit = path:match("/init%.luau$") or path:match("/init%.server%.luau$") or path:match("/init%.client%.luau$") or path:match("/init%.lua$") or path:match("/init%.server%.lua$") or path:match("/init%.client%.lua$")
|
|
@@ -1135,7 +1046,7 @@ local function createInstanceByPath(path, content)
|
|
|
1135
1046
|
return nil
|
|
1136
1047
|
end
|
|
1137
1048
|
|
|
1138
|
-
local function applyUpdate(filePath, content)
|
|
1049
|
+
local function applyUpdate(filePath, content, absolutePath)
|
|
1139
1050
|
local inst = findInstanceByPath(filePath)
|
|
1140
1051
|
if not inst then
|
|
1141
1052
|
inst = createInstanceByPath(filePath, content)
|
|
@@ -1146,21 +1057,24 @@ local function applyUpdate(filePath, content)
|
|
|
1146
1057
|
inst.Value = content
|
|
1147
1058
|
elseif filePath:match("%.json$") and not filePath:match("%.meta%.json$") and not filePath:match("%.model%.json$") and inst:IsA("ModuleScript") then
|
|
1148
1059
|
inst.Source = "return " .. content
|
|
1149
|
-
elseif filePath:match("%.rbxmx$") then
|
|
1150
|
-
-- Handle Model Update
|
|
1151
|
-
local
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1060
|
+
elseif filePath:match("%.rbxmx$") and absolutePath then
|
|
1061
|
+
-- Handle Model Update via InsertService
|
|
1062
|
+
local success, model = pcall(function()
|
|
1063
|
+
return game:GetService("InsertService"):LoadLocalAsset(absolutePath)
|
|
1064
|
+
end)
|
|
1065
|
+
|
|
1066
|
+
if success and model then
|
|
1067
|
+
local children = model:GetChildren()
|
|
1068
|
+
if #children > 0 then
|
|
1069
|
+
local newObj = children[1]
|
|
1070
|
+
newObj.Name = inst.Name
|
|
1071
|
+
newObj.Parent = inst.Parent
|
|
1072
|
+
inst:Destroy()
|
|
1073
|
+
inst = newObj
|
|
1074
|
+
print("Roport: Imported " .. newObj.Name .. " from " .. filePath)
|
|
1075
|
+
end
|
|
1076
|
+
else
|
|
1077
|
+
warn("Roport: Failed to load RBXMX: " .. tostring(model))
|
|
1164
1078
|
end
|
|
1165
1079
|
elseif filePath:match("%.model%.json$") or filePath:match("%.meta%.json$") then
|
|
1166
1080
|
local success, data = pcall(function() return HttpService:JSONDecode(content) end)
|
|
@@ -1290,7 +1204,7 @@ task.spawn(function()
|
|
|
1290
1204
|
if data.changes and #data.changes > 0 then
|
|
1291
1205
|
print("Roport: Received " .. #data.changes .. " updates from VS Code")
|
|
1292
1206
|
for _, change in ipairs(data.changes) do
|
|
1293
|
-
applyUpdate(change.filePath, change.content)
|
|
1207
|
+
applyUpdate(change.filePath, change.content, change.absolutePath)
|
|
1294
1208
|
end
|
|
1295
1209
|
end
|
|
1296
1210
|
else
|