This repository has been archived by the owner on Sep 22, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ba861f2
commit fc8a501
Showing
7 changed files
with
635 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,206 @@ | ||
# Basic Fragment | ||
|
||
Lets go into a basic fragment, and explain how the model works. | ||
|
||
## Importing Catwork | ||
|
||
Each Fragment should first import Catwork. | ||
|
||
```lua | ||
local ReplicatedFirst = game:GetService("ReplicatedFirst") | ||
local Catwork = require(ReplicatedFirst.Catwork) | ||
``` | ||
|
||
!!! note | ||
This tutorial expects Catwork to be in `ReplicatedFirst`, make sure its | ||
there before following this tutorial | ||
|
||
Future tutorials will assume you're importing this. | ||
|
||
## A clock counter | ||
|
||
For this tutorial, we're going to slowly build an API for interfacing with a | ||
simple real-time clock system. | ||
|
||
Add `Lighting` as an import after your `Catwork` import: | ||
|
||
```lua | ||
local Lighting = game:GetService("Lighting") -- required for this tutorial | ||
``` | ||
|
||
### Adding Basic Logic | ||
|
||
Lets create a basic Fragment that iterates the current Lighting time. To do | ||
this, we call the `Catwork.Fragment` constructor: | ||
|
||
```lua | ||
return Catwork.Fragment { | ||
Name = "LightingClockTime", | ||
|
||
Init = function(self) | ||
while true do | ||
task.wait(1) | ||
Lighting.ClockTime += 1/60 | ||
end | ||
end, | ||
} | ||
``` | ||
|
||
If you run this script, you'll notice the clock slowly ticks forward. | ||
|
||
??? bug "Not Working?" | ||
Here's some possible reasons for your code not working. | ||
|
||
1. You've not imported Catwork, Lighting or ReplicatedFirst. | ||
2. You didn't include a Runtime, refer to Installation for that. | ||
3. There's a typo in your script. | ||
|
||
Lets explain how this constructor works. | ||
|
||
First, we give it the name `LightingClockTime`, this doesn't do much internally | ||
as Fragments use a different method for being uniquely identified, however, it | ||
helps us identify which Fragment we're working with. | ||
|
||
```lua | ||
Name = "LightingClockTime | ||
``` | ||
|
||
After that, we add an Init callback, which indicates what should happen when the | ||
Fragment is ready to go. | ||
|
||
```lua | ||
Init = function(self) | ||
while true do | ||
task.wait(1) | ||
Lighting.ClockTime += 1/60 | ||
end | ||
end, | ||
``` | ||
|
||
### Adding an API | ||
|
||
The `Catwork.Fragment` constructor lets you define any logic you want to on the | ||
object, and have it passed to other code using it. | ||
|
||
Lets add a API to get the current clock time, and set a timezone offset. To do | ||
this, add two new methods directly to the constructor | ||
|
||
```lua hl_lines="11-17" | ||
return Catwork.Fragment { | ||
Name = "LightingClockTime", | ||
|
||
Init = function(self) | ||
while true do | ||
task.wait(1) | ||
Lighting.ClockTime += 1/60 | ||
end | ||
end, | ||
|
||
GetClockTime = function(self) | ||
|
||
end, | ||
|
||
SetTimeZoneOffset = function(self, offset) | ||
|
||
end | ||
} | ||
``` | ||
|
||
We're also going to add an in-built timer, and offset, to the fragment as a property: | ||
|
||
```lua hl_lines="4 5" | ||
return Catwork.Fragment { | ||
Name = "LightingClockTime", | ||
|
||
Time = os.time(), | ||
TimeZoneOffset = 0 | ||
``` | ||
|
||
Now, lets implement our two new methods, firstly, `GetClockTime`. This method | ||
should just return `self.Time`: | ||
|
||
```lua | ||
GetClockTime = function(self) | ||
return self.Time | ||
end | ||
``` | ||
|
||
And, for `SetTimeZoneOffset`, this should change `self.TimeZoneOffset` | ||
|
||
```lua | ||
SetTimeZoneOffset = function(self, offset) | ||
self.TimeZoneOffset = offset | ||
end | ||
``` | ||
|
||
### Updating Init | ||
|
||
If you run the project, and interface with the Fragment, you may notice that nothing | ||
happens. This is because we haven't updated our `Init` callback. | ||
|
||
Here's the updated Init callback: | ||
```lua | ||
Init = function(self) | ||
while true do | ||
Lighting.ClockTime = ((self.Time / 3600) % 24) + self.TimeZoneOffset | ||
task.wait(1) | ||
end | ||
end | ||
``` | ||
|
||
If you run the game now, the time in-game should match near to your local | ||
computer time. (If you computer is set to UTC.). | ||
|
||
## Using the API | ||
|
||
If you used a ModuleScript, you can now require your script within *another* script, | ||
and interface with the clock counter. Here's a script that requires in the ClockCounter | ||
script, and prints out the clock time every second: | ||
|
||
```lua | ||
local ClockCounter = require(path.to.ClockCounter) | ||
|
||
while true do | ||
print(ClockCounter:GetClockTime()) | ||
task.wait(1) | ||
end | ||
``` | ||
|
||
## Asynchronous design | ||
|
||
Catwork utilises a simple asynchronous dependency system, through `Fragment:Await` | ||
and `Fragment:HandleAsync`. | ||
|
||
This works by waiting until a Fragment's `Init` function completes (returns) then | ||
resumes any code waiting for it complete. You may notice an issue with our | ||
`Init` callback, in that it **never** returns, and so any code waiting on it will | ||
also never resume. | ||
|
||
Lets fix our Init callback to address this. We're going to use `task.spawn` to | ||
create a new thread within our `Init` callback, that runs independently of any | ||
code waiting upon it. | ||
|
||
```lua | ||
Init = function(self) | ||
task.spawn(function() | ||
while true do | ||
Lighting.ClockTime = ((self.Time / 3600) % 24) + self.TimeZoneOffset | ||
task.wait(1) | ||
end | ||
end) | ||
end | ||
``` | ||
|
||
You should always `Await`/`HandleAsync` on Fragments, because you cannot guarantee | ||
that they are ready. The Service tutorial explains the Fragment:Spawn lifecycle | ||
more in depth. | ||
|
||
```lua hl_lines="2" | ||
local ClockCounter = require(path.to.ClockCounter) | ||
ClockCounter:Await() | ||
|
||
while true do | ||
print(ClockCounter:GetClockTime()) | ||
task.wait(1) | ||
end | ||
``` |
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,110 @@ | ||
# Installation | ||
|
||
Catwork can be installed either as a Roblox model, or within a larger project | ||
inside your editor of choice. | ||
|
||
|
||
--- | ||
|
||
The following guide is different for within Roblox Studio, and within external editors. | ||
|
||
=== "Roblox Studio" | ||
|
||
The RBXM can be obtained below. Its best to drag the module into `ReplicatedFirst`, | ||
unless you intend to use the tool as a plugin (which has its own section.) | ||
|
||
The tutorials expect Catwork to be placed in `ReplicatedFirst`. | ||
|
||
[:fontawesome-solid-cat: Download Catwork](https://github.com/metatablecatgames/catwork/releases/download/v0.4.4/catwork.rbxm){ .md-button .md-button--primary} | ||
|
||
=== "External" | ||
|
||
If you intend to use Catwork externally, the sourcecode can be found on the | ||
Releases page on the GitHub repository | ||
|
||
[GitHub Releases](https://github.com/metatablecatgames/catwork/releases/){ .md-button .md-button--primary} | ||
|
||
!!! info "Expected for Studio" | ||
The tutorials expect you to use Catwork within Studio, but can somewhat | ||
be followed in your editor of choice, if you setup the project correctly. | ||
|
||
## Obtaining a Runtime | ||
|
||
Catwork does not come bundled with a Runtime, which is an intentional choice for the time being. | ||
|
||
!!! abstract "CollectionService Runtime (RECOMENDED)" | ||
This runtime loads ModuleScripts with a given tag based on the context it is running | ||
in. | ||
|
||
=== "Game Context" | ||
|
||
```lua | ||
local CollectionService = game:GetService("CollectionService") | ||
local RunService = game:GetService("RunService") | ||
|
||
local TAG_SHARED = "SharedFragment" | ||
local TAG_LOCAL = if RunService:IsClient() then "ClientFragment" else "ServerFragment" | ||
local passed, failed = 0, 0 | ||
|
||
local function safeRequire(module) | ||
local success, result = pcall(require, module) | ||
if success then | ||
passed += 1 | ||
return result | ||
else | ||
warn("Error when requiring", module, ":", result) | ||
failed += 1 | ||
return nil | ||
end | ||
end | ||
|
||
local function loadGroup(tag) | ||
local m = CollectionService:GetTagged(tag) | ||
for _, mod in m do | ||
if mod:IsA("ModuleScript") then | ||
safeRequire(mod) | ||
end | ||
end | ||
end | ||
local t = os.clock() | ||
loadGroup(TAG_LOCAL) | ||
loadGroup(TAG_SHARED) | ||
local f = os.clock() - t | ||
|
||
print(`🐈 CatworkRun. {passed} modules required, {failed} modules failed. Load time: {math.round(f * 1000)}ms`) | ||
``` | ||
|
||
=== "Plugin Context" | ||
|
||
```lua | ||
local CollectionService = game:GetService("CollectionService") | ||
if not plugin then return end | ||
|
||
local TAG = "PluginFragment" | ||
|
||
local function safeRequire(module) | ||
local success, result = pcall(require, module) | ||
if success then | ||
return result | ||
else | ||
warn("Error when requiring", module, ":", result) | ||
return nil | ||
end | ||
end | ||
|
||
local function loadGroup(tag) | ||
local m = CollectionService:GetTagged(tag) | ||
for _, mod in m do | ||
if mod:IsDescendentOf(plugin) and mod:IsA("ModuleScript") then | ||
safeRequire(mod) | ||
end | ||
end | ||
end | ||
|
||
loadGroup(TAG) | ||
``` | ||
|
||
You should generally use this runtime where possible as it's configured from CollectionService tags, and doesn't | ||
require you to fiddle with the script. | ||
|
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,12 @@ | ||
# Tutorials | ||
|
||
The following section introduces Catwork in an easy-to-digest and learn manner. | ||
|
||
!!! note | ||
These tutorials are designed so you can jump around as you need to for different | ||
concepts, but build on ideas learnt in previous sections. | ||
|
||
If you get stuck, feel free to send me a | ||
[message on the DevForum](https://devforum.roblox.com/u/metatablecatmaid), or | ||
get help from the [Roblox Open Source community](https://discord.gg/Qm3JNyEc32) | ||
discord server! |
Oops, something went wrong.