Skip to content

Commit

Permalink
Multiple project serve
Browse files Browse the repository at this point in the history
  • Loading branch information
hoontee committed Dec 27, 2023
1 parent eee597c commit 3f56e6e
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 109 deletions.
Binary file modified Lync/Plugin.rbxm
Binary file not shown.
89 changes: 48 additions & 41 deletions Lync/RobloxPluginSource/Plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
]]
local VERSION = "Alpha 27"
local VERSION = "Alpha 28"

if not plugin or game:GetService("RunService"):IsRunning() and game:GetService("RunService"):IsClient() then return end

Expand All @@ -28,7 +28,6 @@ if not plugin or game:GetService("RunService"):IsRunning() and game:GetService("
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

local ChangeHistoryService = game:GetService("ChangeHistoryService")
local CollectionService = game:GetService("CollectionService")
local CoreGui = game:GetService("CoreGui")
local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")
Expand All @@ -53,6 +52,7 @@ local SUPPRESSED_CLASSES = {
}

-- Defines
local contentRoot = ""
local debugPrints = false
local theme: StudioTheme = settings().Studio.Theme :: StudioTheme
local connected = false
Expand Down Expand Up @@ -278,8 +278,8 @@ local function setTheme()
updateChangedModelUi()
end

local function getPort(): string
return portTextBox.Text ~= "" and portTextBox.Text or portTextBox.PlaceholderText
local function getHost(): string
return "http://localhost:" .. (portTextBox.Text ~= "" and portTextBox.Text or portTextBox.PlaceholderText)
end

local function terminate(errorMessage: string)
Expand Down Expand Up @@ -364,6 +364,28 @@ local function listenForChanges(object: Instance)
end
end

local function setScriptSourceLive(container: LuaSourceContainer, lua: string)
local document = ScriptEditorService:FindScriptDocument(container)
local cursorLine: number, cursorChar: number, anchorLine: number, anchorChar: number;
if document then
cursorLine, cursorChar, anchorLine, anchorChar = document:GetSelection()
end
ScriptEditorService:UpdateSourceAsync(container, function(_oldContent: string)
return ({lua:gsub("\r", "")})[1]
end)
if document then
local maxLine = document:GetLineCount()
local maxCursorChar = document:GetLine(math.min(cursorLine, maxLine)):len() + 1
local maxAnchorChar = document:GetLine(math.min(anchorLine, maxLine)):len() + 1
document:ForceSetSelectionAsync(
math.min(cursorLine, maxLine),
math.min(cursorChar, maxCursorChar),
math.min(anchorLine, maxLine),
math.min(anchorChar, maxAnchorChar)
)
end
end

--offline-start

local function trim6(s: string): string
Expand Down Expand Up @@ -454,7 +476,7 @@ local function setDetails(target: any, data: any)
end)
end
if data.Properties then
local warning = if serverKey ~= "BuildScript" and (target.Parent == game or table.find(SUPPRESSED_CLASSES, target.ClassName)) then true else false
local warning = if target.Parent == game or table.find(SUPPRESSED_CLASSES, target.ClassName) then true else false
for property, value in data.Properties do
lpcall("Set Property " .. property, warning, function()
if serverKey ~= "BuildScript" and target:IsA("Model") and property == "Scale" then
Expand All @@ -475,34 +497,12 @@ local function setDetails(target: any, data: any)
if data.Tags then
for _, tag in data.Tags do
lpcall("Set Tag", false, function()
CollectionService:AddTag(target, tag)
game:GetService("CollectionService"):AddTag(target, tag)
end)
end
end
end

local function setScriptSourceLive(container: LuaSourceContainer, lua: string)
local document = ScriptEditorService:FindScriptDocument(container)
local cursorLine: number, cursorChar: number, anchorLine: number, anchorChar: number;
if document then
cursorLine, cursorChar, anchorLine, anchorChar = document:GetSelection()
end
ScriptEditorService:UpdateSourceAsync(container, function(_oldContent: string)
return ({lua:gsub("\r", "")})[1]
end)
if document then
local maxLine = document:GetLineCount()
local maxCursorChar = document:GetLine(math.min(cursorLine, maxLine)):len() + 1
local maxAnchorChar = document:GetLine(math.min(anchorLine, maxLine)):len() + 1
document:ForceSetSelectionAsync(
math.min(cursorLine, maxLine),
math.min(cursorChar, maxCursorChar),
math.min(anchorLine, maxLine),
math.min(anchorChar, maxAnchorChar)
)
end
end

local function buildJsonModel(target: any, data: any)
data.Properties = data.properties
data.Attributes = data.attributes
Expand Down Expand Up @@ -600,7 +600,7 @@ local function buildPath(path: string)
task.spawn(function()
activeSourceRequests += 1
local success, result = pcall(function()
return HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Source", Path = data.Path})
return HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Source", Path = data.Path})
end)
activeSourceRequests -= 1
if success then
Expand All @@ -614,7 +614,7 @@ local function buildPath(path: string)
end
end)
elseif data.Type == "Model" then
local objects = getObjects("rbxasset://lync/" .. data.Path)
local objects = getObjects("rbxasset://" .. contentRoot .. data.Path)
if objects then
if #objects == 1 then
objects[1].Name = name
Expand All @@ -634,7 +634,7 @@ local function buildPath(path: string)
task.spawn(function()
activeSourceRequests += 1
local success, result = pcall(function()
return HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Source", Path = data.Path, DataType = data.Type})
return HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Source", Path = data.Path, DataType = data.Type})
end)
activeSourceRequests -= 1
if success then
Expand All @@ -651,7 +651,7 @@ local function buildPath(path: string)
task.spawn(function()
activeSourceRequests += 1
local success, result = pcall(function()
return HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Source", Path = data.Path})
return HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Source", Path = data.Path})
end)
activeSourceRequests -= 1
if success then
Expand Down Expand Up @@ -679,7 +679,7 @@ local function buildPath(path: string)
task.spawn(function()
activeSourceRequests += 1
local success, result = pcall(function()
return HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Source", Path = data.Path})
return HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Source", Path = data.Path})
end)
activeSourceRequests -= 1
if success then
Expand All @@ -698,7 +698,7 @@ local function buildPath(path: string)
task.spawn(function()
activeSourceRequests += 1
local success, result = pcall(function()
return HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Source", Path = data.Path, DataType = "Localization"})
return HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Source", Path = data.Path, DataType = "Localization"})
end)
activeSourceRequests -= 1
if success then
Expand All @@ -718,7 +718,7 @@ local function buildPath(path: string)
setDetails(target, data)
if data.TerrainRegion then
if target == workspace.Terrain then
local objects = getObjects("rbxasset://lync/" .. data.TerrainRegion[1])
local objects = getObjects("rbxasset://" .. contentRoot .. data.TerrainRegion[1])
if objects then
if #objects == 1 then
lpcall("Set Terrain Region", false, function()
Expand Down Expand Up @@ -787,13 +787,15 @@ local function setConnected(newConnected: boolean)
if newConnected then
if not map then
local success, result = pcall(function()
local get = HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Map", Playtest = IS_PLAYTEST_SERVER})
local get = HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Map", Playtest = IS_PLAYTEST_SERVER})
return get ~= "{}" and HttpService:JSONDecode(get) or nil
end)
if success then
if result.Version == VERSION then
debugPrints = result.Debug
contentRoot = result.ContentRoot
result.Debug = nil
result.ContentRoot = nil
map = result
if not IS_PLAYTEST_SERVER then
if debugPrints then warn("[Lync] - Map:", result) end
Expand Down Expand Up @@ -824,7 +826,7 @@ local function setConnected(newConnected: boolean)
end
else
local success, result = pcall(function()
HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Resume"})
HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Resume"})
end)
if not success then
task.spawn(error, "[Lync] - " .. result)
Expand Down Expand Up @@ -881,7 +883,7 @@ if not IS_PLAYTEST_SERVER then
-- Port

portTextBox.MouseEnter:Connect(function()
if portTextBox:IsFocused() then return end
if not portTextBox.Active or portTextBox:IsFocused() then return end
mainWidgetFrame.Frame.UIStroke.Color = mainWidgetFrame.Frame:GetAttribute("BorderHover")
end)

Expand All @@ -891,6 +893,7 @@ if not IS_PLAYTEST_SERVER then
end)

portTextBox.Focused:Connect(function()
if not portTextBox.Active then return end
mainWidgetFrame.Frame.UIStroke.Color = mainWidgetFrame.Frame:GetAttribute("BorderSelected")
end)

Expand All @@ -915,7 +918,7 @@ if not IS_PLAYTEST_SERVER then
for _, data in map do
if data.Instance == StudioService.ActiveScript then
local success, result = pcall(function()
HttpService:PostAsync("http://localhost:" .. getPort(), ScriptEditorService:GetEditorSource(StudioService.ActiveScript :: LuaSourceContainer), Enum.HttpContentType.TextPlain, false, {Key = serverKey, Type = "ReverseSync", Path = data.Path})
HttpService:PostAsync(getHost(), ScriptEditorService:GetEditorSource(StudioService.ActiveScript :: LuaSourceContainer), Enum.HttpContentType.TextPlain, false, {Key = serverKey, Type = "ReverseSync", Path = data.Path})
end)
if success then
print("[Lync] - Saved script:", data.Path)
Expand Down Expand Up @@ -965,7 +968,7 @@ if not IS_PLAYTEST_SERVER then
for _, data in map do
if data.Instance == StudioService.ActiveScript then
local success, result = pcall(function()
local source = HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Source", Path = data.Path})
local source = HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Source", Path = data.Path})
setScriptSourceLive(data.Instance, source)
end)
if success then
Expand Down Expand Up @@ -1079,13 +1082,17 @@ end

if workspace:GetAttribute("__lyncbuildfile") and not IS_PLAYTEST_SERVER or syncDuringTest and IS_PLAYTEST_SERVER and workspace:GetAttribute("__lyncactive") then
if syncDuringTest and IS_PLAYTEST_SERVER then warn("[Lync] - Playtest Sync is active.") end
portTextBox.Text = ""
portTextBox.PlaceholderText = workspace:GetAttribute("__lyncbuildfile")
portTextBox.TextEditable = false
portTextBox.Active = false
setConnected(true)
end

while task.wait(0.5) do
if connected then
local success, result = pcall(function()
local get = HttpService:GetAsync("http://localhost:" .. getPort(), false, {Key = serverKey, Type = "Modified", Playtest = IS_PLAYTEST_SERVER})
local get = HttpService:GetAsync(getHost(), false, {Key = serverKey, Type = "Modified", Playtest = IS_PLAYTEST_SERVER})
return get ~= "{}" and HttpService:JSONDecode(get) or nil
end)
if success then
Expand Down
69 changes: 39 additions & 30 deletions Lync/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/
const VERSION = 'Alpha 27'
const VERSION = 'Alpha 28'

const { spawn, spawnSync } = require('child_process')
const crypto = require('crypto')
const fs = require('fs')
const os = require('os')
const path = require('path')
Expand Down Expand Up @@ -193,33 +194,40 @@ function localPathIsIgnored(localPath) {
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/**
* @param {string} existingPath
* @param {string} hardLinkPath
* @param {string} sourcePath
* @param {string} hardLinkRootPath
*/
function hardLinkRecursive(existingPath, hardLinkPath) {
if (localPathIsIgnored(existingPath)) return
const stats = fs.statSync(existingPath)
const newPath = path.resolve(hardLinkPath, path.relative(process.cwd(), existingPath))
function hardLinkRecursive(sourcePath, hardLinkRootPath) {
if (localPathIsIgnored(sourcePath)) return
const hardLinkPath = path.resolve(hardLinkRootPath, path.parse(process.cwd()).name, PROJECT_JSON, path.relative(process.cwd(), sourcePath))
if (process.cwd() == sourcePath) {
try {
fs.rmSync(hardLinkPath, { force: true, recursive: true })
} catch (err) {
console.error(red('Hard link error:'), yellow(err))
}
}
const stats = fs.statSync(sourcePath)
const parentPath = path.resolve(hardLinkPath, '..')
try {
const parentPath = path.resolve(newPath, '..')
if (!fs.existsSync(parentPath)) {
fs.mkdirSync(parentPath)
fs.mkdirSync(parentPath, { recursive: true })
}
if (stats.isDirectory()) {
if (!fs.existsSync(newPath)) {
fs.mkdirSync(newPath)
if (!fs.existsSync(hardLinkPath)) {
fs.mkdirSync(hardLinkPath)
}
fs.readdirSync(existingPath).forEach((dirNext) => {
hardLinkRecursive(path.resolve(existingPath, dirNext), hardLinkPath)
fs.readdirSync(sourcePath).forEach((dirNext) => {
hardLinkRecursive(path.resolve(sourcePath, dirNext), hardLinkRootPath)
})
} else {
if (fs.existsSync(newPath)) {
fs.unlinkSync(newPath)
if (fs.existsSync(hardLinkPath)) {
fs.unlinkSync(hardLinkPath)
}
fs.linkSync(existingPath, newPath)
fs.linkSync(sourcePath, hardLinkPath)
}
} catch (err) {
if (DEBUG) console.error(red('Hard link error:'), yellow(err))
console.error(red('Hard link error:'), yellow(err))
}
}

Expand Down Expand Up @@ -1023,14 +1031,11 @@ function runJobs(event, localPath) {
// Write build script
if (DEBUG) console.log('Writing build script . . .')
let buildScript = fs.readFileSync(path.resolve(__dirname, 'luneBuildTemplate.luau'))
buildScript += `local game = Instance.new("DataModel")\n`
buildScript += 'local workspace = game:GetService("Workspace")\n'
buildScript += 'workspace:SetAttribute("__lyncbuildfile", true)\n'
buildScript += `${pluginSource}\n`
buildScript += `port = "${projectJson.port}"\n`
buildScript += `map = net.jsonDecode("${toEscapeSequence(JSON.stringify(map, null, '\t'))}")\n`
buildScript += `buildAll()\n`
buildScript += `fs.writeFile("${projectJson.build}", roblox.serializePlace(game))\n`
+ `\nworkspace:SetAttribute("__lyncbuildfile", ${projectJson.port})\n`
+ `${pluginSource}\n`
+ `map = net.jsonDecode("${toEscapeSequence(JSON.stringify(map, null, '\t'))}")\n`
+ `buildAll()\n`
+ `fs.writeFile("${projectJson.build}", roblox.serializePlace(game))\n`
if (fs.existsSync(buildScriptPath))
fs.rmSync(buildScriptPath)
fs.writeFileSync(buildScriptPath, buildScript)
Expand Down Expand Up @@ -1097,8 +1102,13 @@ function runJobs(event, localPath) {
if (DEBUG) console.log('Creating folder', cyan(pluginsPath))
fs.mkdirSync(pluginsPath)
}
if (DEBUG) console.log('Copying', cyan(path.resolve(__dirname, 'Plugin.rbxm')), '->', cyan(path.resolve(pluginsPath, 'Lync.rbxm')))
fs.copyFileSync(path.resolve(__dirname, 'Plugin.rbxm'), path.resolve(pluginsPath, 'Lync.rbxm'))
const pluginPath = path.resolve(pluginsPath, 'Lync.rbxm')
const currentHash = fs.existsSync(pluginPath) && crypto.createHash('md5').update(fs.readFileSync(pluginPath)).digest('hex')
const newHash = crypto.createHash('md5').update(fs.readFileSync(path.resolve(__dirname, 'Plugin.rbxm'))).digest('hex')
if (currentHash != newHash) {
if (DEBUG) console.log('Copying', cyan(path.resolve(__dirname, 'Plugin.rbxm')), '->', cyan(pluginPath))
fs.copyFileSync(path.resolve(__dirname, 'Plugin.rbxm'), pluginPath)
}

// Sync file changes
chokidar.watch('.', {
Expand Down Expand Up @@ -1286,19 +1296,18 @@ function runJobs(event, localPath) {
hardLinkPaths.push(hardLinkPath)
}
for (const hardLinkPath of hardLinkPaths) {
try {
fs.rmSync(hardLinkPath, { force: true, recursive: true })
} catch (err) {}
hardLinkRecursive(process.cwd(), hardLinkPath)
}

// Send map
map.Version = VERSION
map.Debug = DEBUG
map.ContentRoot = path.join('lync', path.parse(process.cwd()).name, PROJECT_JSON).replaceAll('\\', '/') + '/'
map.ServePlaceIds = projectJson.servePlaceIds
const mapJsonString = JSON.stringify(map)
delete map['Version']
delete map['Debug']
delete map['ContentRoot']
delete map['ServePlaceIds']
if ('playtest' in req.headers) {
modified_playtest = {}
Expand Down
Loading

0 comments on commit 3f56e6e

Please sign in to comment.