-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Created a lite variant - use case: plugin dev
- Loading branch information
1 parent
74eb7c8
commit b0e9ed8
Showing
2 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
--[=[ | ||
@Author: Gavin "Mullets" Rosenthal | ||
@Desc: Lighter, a lite variant of Loader, a Roblox Luau Library Loader by Mullet Mafia Dev | ||
@Notes: Lighter has the bare basics for requiring modules with a lazy-load string method | ||
]=] | ||
|
||
--[=[ | ||
[DOCUMENTATION]: | ||
https://github.com/Mullets-Gavin/Loader | ||
Listed below is a quick glance on the API, visit the link above for proper documentation. | ||
Lighter(module) | ||
Lighter.require(module) | ||
Lighter.VERSION() | ||
[OUTLINE]: | ||
Lighter | ||
├─ .__require(module,requirer) | ||
│ ├─ if instance, requires the module & caches it | ||
│ └─ if string, searches the following: | ||
│ └─ deep search the parent container | ||
├─ Lighter(module) | .require(module) | ||
│ └─ Redirects & returns __require() | ||
├─ .__version() and .VERSION Returns the current version | ||
└─ :__call redirects to .require | ||
[LICENSE]: | ||
MIT License | ||
Copyright (c) 2020 Mullet Mafia Dev | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
]=] | ||
|
||
local RunService = game:GetService('RunService') | ||
|
||
local IsStudio = RunService:IsStudio() and 'Studio' | ||
local IsServer = RunService:IsServer() and 'Server' | ||
local IsClient = RunService:IsClient() and 'Client' | ||
|
||
local Lighter = {} | ||
Lighter.__index = Lighter | ||
Lighter._ModuleCache = {} | ||
Lighter._Initialized = false | ||
Lighter._Name = string.upper(script.Name) | ||
Lighter._Container = script.Parent | ||
Lighter._Version = { | ||
['MAJOR'] = 1; | ||
['MINOR'] = 0; | ||
['PATCH'] = 0; | ||
} | ||
|
||
--[=[ | ||
Lighters settings | ||
Defaults: | ||
Lighter.MaxRetryTime = 5 | ||
Lighter.Timeout = 5 | ||
Lighter.Filter = false | ||
]=] | ||
Lighter.MaxRetryTime = 5 | ||
Lighter.Timeout = 5 | ||
Lighter.Filter = false | ||
|
||
--[=[ | ||
Safely require a module like the Roblox require function works | ||
@param module Instance -- required module | ||
@param requirer Instance -- the source script requiring this | ||
@return table? | ||
@private | ||
]=] | ||
local function SafeRequire(module: ModuleScript, requirer: Script): table? | ||
local time = os.clock() | ||
local event; event = RunService.Stepped:Connect(function() | ||
if os.clock() >= time + Lighter.Timeout then | ||
warn(string.format('%s -> %s is taking too long',tostring(requirer),tostring(module))) | ||
if event then | ||
event:Disconnect() | ||
event = nil | ||
end | ||
end | ||
end) | ||
|
||
local loaded | ||
local success,response = pcall(function() | ||
loaded = require(module) | ||
end) | ||
|
||
if not success then | ||
if type(loaded) == 'nil' and string.find(response,'exactly one value') then | ||
error("Module did not return exactly one value: " .. module:GetFullName(), 3) | ||
else | ||
error("Module " .. module:GetFullName() .. " experienced an error while loading: " .. response, 3) | ||
end | ||
end | ||
|
||
if event then | ||
event:Disconnect() | ||
event = nil | ||
end | ||
|
||
return loaded | ||
end | ||
|
||
--[=[ | ||
Deep search a list for a specific name | ||
@param name string -- the name of the module | ||
@param list table -- the list of instances to filter | ||
@return ModuleScript? | ||
@private | ||
]=] | ||
local function DeepSearch(name: string, list: table): ModuleScript? | ||
for count,asset in ipairs(list) do | ||
if not asset:IsA('ModuleScript') then continue end | ||
if Lighter.Filter and asset.Parent:IsA('ModuleScript') then continue end | ||
|
||
if string.lower(asset.Name) == name then | ||
return asset | ||
end | ||
end | ||
|
||
return nil | ||
end | ||
|
||
--[=[ | ||
The internal require function which searches the built-in library & all containers per-environment | ||
@param module string | number | ModuleScript -- the module to require | ||
@param requirer Script -- the script that required this function to simulate require() | ||
@return table? | ||
@private | ||
]=] | ||
function Lighter.__require(module: ModuleScript, requirer: Script): table? | ||
local clock = os.clock() | ||
local name = string.lower(typeof(module) == 'Instance' and module.Name or module) | ||
|
||
if Lighter._ModuleCache[name] then | ||
return Lighter._ModuleCache[name] | ||
end | ||
|
||
if typeof(module) == 'number' or typeof(module) == 'Instance' then | ||
Lighter._ModuleCache[name] = require(module) | ||
return Lighter._ModuleCache[name] | ||
end | ||
|
||
while not Lighter._ModuleCache[name] and os.clock() - clock < Lighter.MaxRetryTime do | ||
local asset = DeepSearch(name,Lighter._Container:GetDescendants()) | ||
if asset then | ||
Lighter._ModuleCache[name] = SafeRequire(asset,requirer) | ||
return Lighter._ModuleCache[name] | ||
end | ||
|
||
RunService.Heartbeat:Wait() | ||
end | ||
|
||
assert(Lighter._ModuleCache[name],"attempted to require a non-existant module: '"..name.."'") | ||
return Lighter._ModuleCache[name] | ||
end | ||
|
||
--[=[ | ||
Require a module instance or search containers for a module with a string | ||
@param module string | number | Instance -- the module type to require | ||
@return RequiredModule? | ||
]=] | ||
function Lighter.require(module: ModuleScript | string | number): table? | ||
local requirer = getfenv(2).script | ||
return Lighter.__require(module,requirer) | ||
end | ||
|
||
--[=[ | ||
Replace the require function by Roblox | ||
@param module string | number | Instance -- the module type to require | ||
@return table? | ||
]=] | ||
function Lighter:__call(module: ModuleScript | string | number): table? | ||
local requirer = getfenv(2).script | ||
return Lighter.__require(module,requirer) | ||
end | ||
|
||
--[=[ | ||
Provides the Lighter version when called tostring() | ||
@return FormattedVersion | ||
]=] | ||
function Lighter:__tostring(): string | ||
return 'Lighter '..Lighter.__version() | ||
end | ||
|
||
--[=[ | ||
Returns the current version of Lighter | ||
@return FormattedVersion | ||
]=] | ||
function Lighter.__version(): string | ||
return string.format('v%d.%d.%d', | ||
Lighter._Version.MAJOR, | ||
Lighter._Version.MINOR, | ||
Lighter._Version.PATCH | ||
) | ||
end | ||
Lighter.VERSION = Lighter.__version() | ||
|
||
do | ||
if not Lighter._Initialized and (not IsStudio or (IsStudio and IsServer)) then | ||
Lighter._Initialized = true | ||
print('Lighter by Mullet Mafia Dev initialized','|',Lighter.VERSION) | ||
end | ||
|
||
if IsClient and not IsStudio then | ||
while not game:IsLoaded() do | ||
game.Loaded:Wait() | ||
end | ||
end | ||
end | ||
|
||
return setmetatable(Lighter,Lighter) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<div align="center"> | ||
<h1>Lighter</h1> | ||
|
||
[![version](https://img.shields.io/badge/version-v1.0.0-red)](https://github.com/Mullets-Gavin/Loader/releases) | ||
|
||
Lighter, a lite variant of Loader, a Roblox Luau Library Loader | ||
</div> | ||
|
||
## What's Different? | ||
Lighter is a lite variant of Loader, which includes no libraries & you only deep search the parented container. This means you can now have a blazing fast lazy-loader for localized modules without having to worry about any dependencies or conflicting names. This is an excellent choice for plugin development, seen in an example below. | ||
|
||
## Hierarchy | ||
``` | ||
ReplicatedStorage | ||
└─ Folder | ||
├─ Lighter | ||
└─ Modules | ||
``` | ||
|
||
## Example | ||
```lua | ||
---------------- | ||
-- Initialize -- | ||
---------------- | ||
|
||
-- recommended | ||
local require = require(Folder:WaitForChild('Lighter')) | ||
|
||
-- optional | ||
local Lighter = require(Folder:WaitForChild('Lighter')) | ||
|
||
--------------------- | ||
-- Require Example -- | ||
--------------------- | ||
|
||
local SomeModule = require('SomeModule') -- Lighter('SomeModule') | ||
local SomeModule = require.require('SomeModule') -- Lighter.require('SomeModule') | ||
|
||
-------------------- | ||
-- Plugin Example -- | ||
-------------------- | ||
|
||
local plugin = script:FindFirstAncestorWhichIsA('Plugin') | ||
local require = require(plugin:FindFirstChild('Lighter',true)) | ||
local SomeModule = require('SomeModule') | ||
|
||
-- Hierarchy | ||
plugin | ||
├─ Lighter | ||
└─ Modules | ||
└─ SomeModule | ||
``` |