@quenty/loader 5.0.1 → 5.0.2-canary.d7ea97f.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [5.0.2-canary.d7ea97f.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/loader@5.0.1...@quenty/loader@5.0.2-canary.d7ea97f.0) (2022-09-27)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * Add untested hot reloading loader replication logic ([384a8f1](https://github.com/Quenty/NevermoreEngine/commit/384a8f166c781a6d67485d8cee1269915ba2a5ad))
12
+
13
+
14
+ ### Features
15
+
16
+ * Support hiding server code behind the camera ([afc0e0a](https://github.com/Quenty/NevermoreEngine/commit/afc0e0a35592f68397d6db8108e7955b737ecfe0))
17
+
18
+
19
+
20
+
21
+
6
22
  ## [5.0.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/loader@5.0.0...@quenty/loader@5.0.1) (2022-08-16)
7
23
 
8
24
  **Note:** Version bump only for package @quenty/loader
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/loader",
3
- "version": "5.0.1",
3
+ "version": "5.0.2-canary.d7ea97f.0",
4
4
  "description": "A simple module loader for Roblox",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -26,5 +26,5 @@
26
26
  "publishConfig": {
27
27
  "access": "public"
28
28
  },
29
- "gitHead": "340ac324c03fb3b844bbbe7ca57ee88874a724c9"
29
+ "gitHead": "d7ea97f676c9246d2350b7582d5ab3ff6c44e42f"
30
30
  }
@@ -87,7 +87,7 @@ function LoaderUtils.isPackage(folder)
87
87
  assert(typeof(folder) == "Instance", "Bad instance")
88
88
 
89
89
  for _, item in pairs(folder:GetChildren()) do
90
- if item:IsA("Folder") then
90
+ if item:IsA("Folder") or item:IsA("Camera") then
91
91
  if item.Name == "Server"
92
92
  or item.Name == "Client"
93
93
  or item.Name == "Shared"
@@ -126,7 +126,7 @@ function LoaderUtils.discoverTopLevelPackages(packages, instance)
126
126
  else
127
127
  -- Loop through all folders
128
128
  for _, item in pairs(instance:GetChildren()) do
129
- if item:IsA("Folder") then
129
+ if item:IsA("Folder") or item:IsA("Camera") then
130
130
  LoaderUtils.discoverTopLevelPackages(packages, item)
131
131
  elseif item:IsA("ObjectValue") then
132
132
  local linkedValue = item.Value
@@ -212,7 +212,7 @@ function PackageInfoUtils.fillExplicitPackageDependencySet(
212
212
  assert(defaultReplicationType, "No defaultReplicationType")
213
213
 
214
214
  for _, item in pairs(packageFolder:GetChildren()) do
215
- if item:IsA("Folder") and item.Name == ScriptInfoUtils.DEPENDENCY_FOLDER_NAME then
215
+ if (item:IsA("Folder") or item:IsA("Camera")) and item.Name == ScriptInfoUtils.DEPENDENCY_FOLDER_NAME then
216
216
  local packageInfoList = PackageInfoUtils.getPackageInfoListFromDependencyFolder(
217
217
  item,
218
218
  packageInfoMap,
@@ -54,12 +54,12 @@ function ScriptInfoUtils.populateScriptInfoLookup(instance, scriptInfoLookup, la
54
54
  assert(type(scriptInfoLookup) == "table", "Bad scriptInfoLookup")
55
55
  assert(type(lastReplicationMode) == "string", "Bad lastReplicationMode")
56
56
 
57
- if instance:IsA("Folder") then
57
+ if instance:IsA("Folder") or instance:IsA("Camera") then
58
58
  local replicationMode = ScriptInfoUtils.getFolderReplicationMode(instance.Name, lastReplicationMode)
59
59
  if replicationMode ~= ScriptInfoUtils.ModuleReplicationTypes.IGNORE then
60
60
  for _, item in pairs(instance:GetChildren()) do
61
61
  if not BounceTemplateUtils.isBounceTemplate(item) then
62
- if item:IsA("Folder") then
62
+ if item:IsA("Folder") or item:IsA("Camera") then
63
63
  ScriptInfoUtils.populateScriptInfoLookup(item, scriptInfoLookup, replicationMode)
64
64
  elseif item:IsA("ModuleScript") then
65
65
  ScriptInfoUtils.addToInfoMap(scriptInfoLookup,
@@ -109,7 +109,7 @@ function StaticLegacyLoader:_getPackageFolderLookup(instance)
109
109
  warn("[StaticLegacyLoader] - Bad link in packageFolder")
110
110
  return {}
111
111
  end
112
- elseif instance:IsA("Folder") then
112
+ elseif instance:IsA("Folder") or instance:IsA("Camera") then
113
113
  return self:_getOrCreateLookup(instance)
114
114
  elseif instance:IsA("ModuleScript") then
115
115
  return self:_getOrCreateLookup(instance)
@@ -136,7 +136,7 @@ function StaticLegacyLoader:_getOrCreateLookup(packageFolderOrModuleScript)
136
136
  end
137
137
 
138
138
  function StaticLegacyLoader:_buildLookup(lookup, instance)
139
- if instance:IsA("Folder") then
139
+ if instance:IsA("Folder") or instance:IsA("Camera") then
140
140
  if instance.Name ~= ScriptInfoUtils.DEPENDENCY_FOLDER_NAME then
141
141
  for _, item in pairs(instance:GetChildren()) do
142
142
  self:_buildLookup(lookup, item)
@@ -0,0 +1,17 @@
1
+ --[=[
2
+ Bounces the current named script to the expected version of this module
3
+
4
+ @private
5
+ @class BounceTemplate
6
+ ]=]
7
+
8
+ local function waitForValue(objectValue)
9
+ local value = objectValue.Value
10
+ if value then
11
+ return value
12
+ end
13
+
14
+ return objectValue.Changed:Wait()
15
+ end
16
+
17
+ return require(waitForValue(script:WaitForChild("BounceTarget")))
@@ -0,0 +1,51 @@
1
+ --[=[
2
+ @class BounceTemplateUtils
3
+ @private
4
+ ]=]
5
+
6
+ local BounceTemplate = script.Parent.BounceTemplate
7
+
8
+ local BounceTemplateUtils = {}
9
+
10
+ function BounceTemplateUtils.isBounceTemplate(instance)
11
+ return instance:GetAttribute("IsBounceTemplate", true) == true
12
+ end
13
+
14
+ function BounceTemplateUtils.getTarget(instance)
15
+ if not BounceTemplateUtils.isBounceTemplate(instance) then
16
+ return nil
17
+ end
18
+
19
+ if instance:IsA("ObjectValue") then
20
+ return instance.Value
21
+ else
22
+ local found = instance:FindFirstChild("BounceTarget")
23
+ if found then
24
+ return found.Value
25
+ else
26
+ warn("[BounceTemplateUtils.getTarget] - Bounce template without BounceTarget")
27
+ return nil
28
+ end
29
+ end
30
+ end
31
+
32
+ function BounceTemplateUtils.create(target, linkName)
33
+ assert(typeof(target) == "Instance", "Bad target")
34
+ assert(type(linkName) == "string", "Bad linkName")
35
+
36
+
37
+ local copy = BounceTemplate:Clone()
38
+ copy:SetAttribute("IsBounceTemplate", true)
39
+ copy.Name = linkName
40
+ copy.Archivable = false
41
+
42
+ local objectValue = Instance.new("ObjectValue")
43
+ objectValue.Name = "BounceTarget"
44
+ objectValue.Value = target
45
+ objectValue.Parent = copy
46
+ objectValue.Archivable = false
47
+
48
+ return copy
49
+ end
50
+
51
+ return BounceTemplateUtils
@@ -0,0 +1,133 @@
1
+ --[=[
2
+ Very inefficient search utility function to find dependencies
3
+ organized in node_modules structure.
4
+
5
+ @class DependencyUtils
6
+ ]=]
7
+
8
+ local DependencyUtils = {}
9
+
10
+ --[=[
11
+ Iteratively searches for a dependency based upon packages and current modules using the node_modules
12
+ dependency resolution algorithm.
13
+
14
+ @param requester Instance
15
+ @param moduleName string
16
+ @return ModuleScript?
17
+ ]=]
18
+ function DependencyUtils.findDependency(requester, moduleName)
19
+ assert(typeof(requester) == "Instance", "Bad requester")
20
+ assert(type(moduleName) == "string", "Bad moduleName")
21
+
22
+ for packageInst in DependencyUtils.iterPackages(requester) do
23
+ for module in DependencyUtils.iterModules(packageInst) do
24
+ if module.Name == moduleName then
25
+ return module
26
+ end
27
+ end
28
+ end
29
+
30
+ return nil
31
+ end
32
+
33
+ function DependencyUtils.iterModules(packageInst)
34
+ assert(typeof(packageInst) == "Instance", "Bad packageInst")
35
+
36
+ return coroutine.wrap(function()
37
+ if packageInst:IsA("ModuleScript") then
38
+ coroutine.yield(packageInst)
39
+ return
40
+ end
41
+
42
+ -- Iterate over the package contents
43
+ for _, item in pairs(packageInst:GetChildren()) do
44
+ if item.Name ~= "node_modules" then
45
+ for result in DependencyUtils.iterModules(item) do
46
+ coroutine.yield(result)
47
+ end
48
+ end
49
+ end
50
+ end)
51
+ end
52
+
53
+ function DependencyUtils.iterPackages(requester)
54
+ assert(typeof(requester) == "Instance", "Bad requester")
55
+
56
+ return coroutine.wrap(function()
57
+ for nodeModules in DependencyUtils.iterNodeModules(requester) do
58
+ coroutine.yield(nodeModules.Parent)
59
+
60
+ for packageInst in DependencyUtils.iterPackagesInModuleModules(nodeModules) do
61
+ coroutine.yield(packageInst)
62
+ end
63
+ end
64
+ end)
65
+ end
66
+
67
+ function DependencyUtils.iterNodeModules(module)
68
+ assert(typeof(module) == "Instance", "Bad module")
69
+
70
+ return coroutine.wrap(function()
71
+ local found = module:FindFirstChild("node_modules")
72
+ if found and found:IsA("Folder") then
73
+ coroutine.yield(found)
74
+ end
75
+
76
+ local current = module.Parent
77
+ while current do
78
+ found = current:FindFirstChild("node_modules")
79
+ if found and found:IsA("Folder") then
80
+ coroutine.yield(found)
81
+ end
82
+ current = current.Parent
83
+ end
84
+ end)
85
+ end
86
+
87
+ function DependencyUtils.iterPackagesInModuleModules(nodeModules)
88
+ return coroutine.wrap(function()
89
+ for _, item in pairs(nodeModules:GetChildren()) do
90
+ if item:IsA("Folder") then
91
+ if DependencyUtils.isPackageGroup(item.Name) then
92
+ for _, child in pairs(item:GetChildren()) do
93
+ if child:IsA("ModuleScript") or child:IsA("Folder") then
94
+ coroutine.yield(child)
95
+ elseif child:IsA("ObjectValue") then
96
+ local linked = child.Value
97
+ if linked then
98
+ if linked:IsA("ModuleScript") or linked:IsA("Folder") then
99
+ coroutine.yield(linked)
100
+ else
101
+ warn("Bad link value type")
102
+ end
103
+ else
104
+ warn("Nothing linked")
105
+ end
106
+ end
107
+ end
108
+ else
109
+ coroutine.yield(item)
110
+ end
111
+ elseif item:IsA("ModuleScript") then
112
+ coroutine.yield(item)
113
+ elseif item:IsA("ObjectValue") then
114
+ local linked = item.Value
115
+ if linked then
116
+ if linked:IsA("ModuleScript") or linked:IsA("Folder") then
117
+ coroutine.yield(linked)
118
+ else
119
+ warn("Bad link value type")
120
+ end
121
+ else
122
+ warn("Nothing linked")
123
+ end
124
+ end
125
+ end
126
+ end)
127
+ end
128
+
129
+ function DependencyUtils.isPackageGroup(itemName)
130
+ return itemName:sub(1, 1) == "@"
131
+ end
132
+
133
+ return DependencyUtils
@@ -0,0 +1,181 @@
1
+ --[=[
2
+ Adds the loader instance so script.Parent.loader works.
3
+ @class LoaderAdder
4
+ ]=]
5
+
6
+ local loader = script.Parent.Parent
7
+ local BounceTemplateUtils = require(script.Parent.Parent.Bounce.BounceTemplateUtils)
8
+ local ReplicatorReferences = require(script.Parent.Parent.Replication.ReplicatorReferences)
9
+ local Maid = require(script.Parent.Parent.Maid)
10
+ local ReplicationType = require(script.Parent.Parent.Replication.ReplicationType)
11
+ local ReplicationTypeUtils = require(script.Parent.Parent.Replication.ReplicationTypeUtils)
12
+
13
+ local LoaderAdder = {}
14
+ LoaderAdder.ClassName = "LoaderAdder"
15
+ LoaderAdder.__index = LoaderAdder
16
+
17
+ function LoaderAdder.new(references, root, replicationType)
18
+ local self = setmetatable({}, LoaderAdder)
19
+
20
+ assert(typeof(root) == "Instance", "Bad root")
21
+ assert(ReplicatorReferences.isReplicatorReferences(references), "Bad references")
22
+ assert(ReplicationTypeUtils.isReplicationType(replicationType), "Bad replicationType")
23
+
24
+ self._references = references
25
+ self._root = root
26
+ self._replicationType = replicationType
27
+
28
+ self._maid = Maid.new()
29
+
30
+ self._needsLoaderCount = Instance.new("IntValue")
31
+ self._needsLoaderCount.Value = 0
32
+ self._maid:GiveTask(self._needsLoaderCount)
33
+
34
+ self._hasLoaderCount = Instance.new("IntValue")
35
+ self._hasLoaderCount.Value = 0
36
+ self._maid:GiveTask(self._hasLoaderCount)
37
+
38
+ self._needsLoader = Instance.new("BoolValue")
39
+ self._needsLoader.Value = false
40
+ self._maid:GiveTask(self._needsLoader)
41
+
42
+ self._maid:GiveTask(self._needsLoaderCount.Changed:Connect(function()
43
+ self:_updateNeedsLoader()
44
+ end))
45
+ self._maid:GiveTask(self._hasLoaderCount.Changed:Connect(function()
46
+ self:_updateNeedsLoader()
47
+ end))
48
+
49
+ self._maid:GiveTask(self._needsLoader.Changed:Connect(function()
50
+ if self._needsLoader.Value then
51
+ self._maid._loader = self:_renderLoader()
52
+ else
53
+ self._maid._loader = nil
54
+ end
55
+ end))
56
+
57
+ self:_updateNeedsLoader()
58
+
59
+ if self._replicationType ~= ReplicationType.SERVER then
60
+ self._maid:GiveTask(self._references:ObserveReferenceChanged(loader, function(value)
61
+ if value and value ~= loader then
62
+ self._maid._trackFakeLoader = self:_trackLoaderReference(value)
63
+ else
64
+ self._maid._trackFakeLoader = nil
65
+ end
66
+ end))
67
+ end
68
+ self._maid:GiveTask(self:_trackLoaderReference(loader))
69
+
70
+ -- Do actual setup
71
+ self._maid:GiveTask(root.ChildAdded:Connect(function(child)
72
+ self:_handleChildAdded(child)
73
+ end))
74
+ self._maid:GiveTask(root.ChildRemoved:Connect(function(child)
75
+ self:_handleChildRemoved(child)
76
+ end))
77
+ for _, child in pairs(root:GetChildren()) do
78
+ self:_handleChildAdded(child)
79
+ end
80
+
81
+ return self
82
+ end
83
+
84
+ function LoaderAdder:_updateNeedsLoader()
85
+ self._needsLoader.Value = (self._needsLoaderCount.Value > 0) and self._hasLoaderCount.Value <= 0
86
+ end
87
+
88
+ function LoaderAdder:_handleChildRemoved(child)
89
+ self._maid[child] = nil
90
+ end
91
+
92
+ function LoaderAdder:_handleChildAdded(child)
93
+ assert(typeof(child) == "Instance", "Bad child")
94
+
95
+ local maid = Maid.new()
96
+
97
+
98
+ if child:IsA("ModuleScript") then
99
+ self:_setupNeedsLoaderCountAdd(maid, 1)
100
+ else
101
+ -- TODO: Maybe add to children with node_modules explicitly in its list.
102
+ local loaderAdder = LoaderAdder.new(self._references, child, self._replicationType)
103
+ maid:GiveTask(loaderAdder)
104
+ end
105
+
106
+ self._maid[child] = maid
107
+ end
108
+
109
+ function LoaderAdder:_renderLoader()
110
+ local maid = Maid.new()
111
+
112
+ if self._replicationType == ReplicationType.SERVER then
113
+ maid._current = self:_doLoaderRender(loader)
114
+ else
115
+ maid:GiveTask(self._references:ObserveReferenceChanged(loader, function(value)
116
+ if value then
117
+ maid._current = self:_doLoaderRender(value)
118
+ else
119
+ maid._current = nil
120
+ end
121
+ end))
122
+ end
123
+
124
+ return maid
125
+ end
126
+
127
+ function LoaderAdder:_doLoaderRender(value)
128
+ local loaderLink = BounceTemplateUtils.create(value, loader.Name)
129
+ loaderLink.Parent = self._root
130
+
131
+ return loaderLink
132
+ end
133
+
134
+ function LoaderAdder:_setupNeedsLoaderCountAdd(maid, amount)
135
+ assert(Maid.isMaid(maid), "Bad maid")
136
+ assert(type(amount) == "number", "Bad amount")
137
+
138
+ self._needsLoaderCount.Value = self._needsLoaderCount.Value + amount
139
+ maid:GiveTask(function()
140
+ self._needsLoaderCount.Value = self._needsLoaderCount.Value - amount
141
+ end)
142
+ end
143
+
144
+ function LoaderAdder:_addToLoaderCount(amount)
145
+ assert(type(amount) == "number", "Bad amount")
146
+
147
+ self._hasLoaderCount.Value = self._hasLoaderCount.Value + amount
148
+ return function()
149
+ self._hasLoaderCount.Value = self._hasLoaderCount.Value - amount
150
+ end
151
+ end
152
+
153
+ function LoaderAdder:_trackLoaderReference(ref)
154
+ local maid = Maid.new()
155
+
156
+ -- TODO: Maybe handle loader reparenting more elegantly? this seems deeply unlikely.
157
+ if ref.Parent == self._root then
158
+ maid._current = self:_addToLoaderCount(1)
159
+ end
160
+
161
+ maid:GiveTask(ref:GetPropertyChangedSignal("Parent"):Connect(function()
162
+ if ref.Parent == self._root then
163
+ maid._current = self:_addToLoaderCount(1)
164
+ else
165
+ maid._current = nil
166
+ end
167
+ end))
168
+
169
+ return maid
170
+ end
171
+
172
+ --[=[
173
+ Cleans up the replicator disconnecting all events and cleaning up
174
+ created instances.
175
+ ]=]
176
+ function LoaderAdder:Destroy()
177
+ self._maid:DoCleaning()
178
+ setmetatable(self, nil)
179
+ end
180
+
181
+ return LoaderAdder
File without changes