Planck v0.2.0-rc.1
Caution
Planck v0.2.0-rc.1 contains a lot of breaking changes from v0.1.0. If you're currently using v0.1.0, read the Breaking Changes section before installing this version so you can migrate your code.
New and Improved Documentation
The Documentation Site now contains a well detailed Getting Started guide for learning all the core concepts of Planck, a Design Guide for designing games with Planck for more advanced users, and Setup Guides for Jecs and Matter.
Built-in Common Conditions
Planck now provides built-in conditions for use within your Systems or as Run Conditions. These common conditions are functions which generate closures to check if a condition is true or false, some of them provide additional uses that you can use within your systems as well.
OnEvent
The onEvent
condition checks for new events each time the conditional function is called. It also provides an additional function to collect the new events.
This can be used in your systems similarly to the Matter.useEvent()
hook or a simple collect
function.
local onEvent = Planck.onEvent
local hasNewEvent, collectEvents = onEvent(Players.PlayerAdded)
local function handlePlayers()
for _, player in collectEvents() do
-- ...
end
end
return {
system = handlePlayers,
runConditions = { hasNewEvent },
-- This also works, if you don't want to collect the events
runConditions = { onEvent(Players.PlayerAdded) },
}
TimePassed (Throttle)
The timePassed
or throttle condition checks if the given time has passed. This is similar to the Matter.useThrottle()
hook or a simple interval
function.
local timePassed = Planck.timePassed
local hasTimePassed = timePassed(10)
local function throttled()
if hasTimePassed() then
-- We can use this function in our systems
end
-- Only runs after 10 seconds because of our condition
end
return {
system = throttled,
runConditions = { hasTimePassed },
-- Or if we don't want to use it in systems
runConditions = { timePassed(10) },
}
RunOnce
The runOnce
condition will only return true
once, and then always false
afterwards. This is useful for when you need to create startup logic. It is important to note that while Startup Phases use this internally, the Scheduler ensures they always run before other systems.
local runOnce = Planck.runOnce
local hasRanOnce = runOnce()
local function someSystem()
if not hasRanOnce()
-- Some startup logic
end
-- Or we just want the whole system to run only once
end
return {
system = someSystem,
runConditions = { hasRanOnce },
-- If you only want a 'startup' system
runConditions = { runOnce() },
}
IsNot
The isNot
condition inverses other conditions.
RunService Plugin
This Plugin replaces the built-in Phases from v0.1.0 in an effort to also make Planck runtime agnostic. In the future, any feature which interacts with the Roblox Engine will be a separate Plugin instead of apart of the core library.
Pipelines
Each RunService Event is now it's own Pipeline,
- PreRender
- PreAnimation
- PreSimulation
- PostSimulation
- Heartbeat
Phases
And it's own Phase, with the exception of Heartbeat
which has many Phases.
Event | Phase |
---|---|
PreRender | PreRender |
PreAnimation | PreAnimation |
PreSimulation | PreSimulation |
PostSimulation | PostSimulation |
Heartbeat | Update |
Heartbeat Phases
- First
- PreUpdate
- Update
- PostUpdate
- Last
Installation
With Wally,
[dependencies]
PlanckRunService = "yetanotherclown/planck-runservice@v0.2.0-rc.1"
Better Scheduling w/ Dependency Management
The library has been refactored to now create and manage dependencies between Pipelines and Phases using Adjacency Matrices, and it will now use these dependencies in addition to order of insertion to determine the order in which Pipelines and Phases run in Planck,
You can learn more about the new behavior under the breaking changes section.
Scheduler:insertBefore()
and Pipeline:insertBefore()
These two new methods now exist for creating dependencies between two phases. :insertBefore()
will make the first Phase/Pipeline depend on the other, meaning it cannot run until the other does.
Breaking Changes
Ordering Priorities
Ordering is no longer determinant on a fixed position assigned to each Phase or Pipeline with :insert()
or :insertAfter
within an ordered list. Instead, the Scheduler will now order Phases and Pipelines based on their dependencies.
To explain how the ordering now works,
A dependency is any Phase/Pipeline another Phase/Pipeline depends on. A dependent if the Phase/Pipeline that depends on another Phase/Pipeline.
This looks like, insertAfter(dependent, dependency)
or insertBefore(dependent, dependency)
.
- Start with the first Phase/Pipeline inserted
- If this Phase/Pipeline has any dependency, skip it and move onto the next one.
- Add this Phase/Pipeline to the order
- If this Phase/Pipeline has any dependents, repeat this process in order of insertion for each dependent Phase/Pipeline.
- Move onto the next node.
insert(dependent)
also now works by setting the last added Phase/Pipeline as a dependency of dependent
.
Breaking insertAfter
This change affects Scheduler:insertAfter()
and Pipeline:insertAfter()
. Because Phases/Pipelines no longer have fixed positions in the order of execution, insertAfter
no longer inserts a dependent to be immediately after dependency.
To better demonstrate this, consider this code example:
local myScheduler = Scheduler.new()
:insert(PhaseOne)
:insert(PhaseThree)
:insertAfter(PhaseTwo, PhaseOne)
-- Old Behavior:
-- PhaseOne -> PhaseTwo -> PhaseThree
-- New Behavior:
-- PhaseOne -> PhaseThree -> PhaseTwo
This change is desirable because:
PhaseThree
is not dependent onPhaseTwo
(dependencies are defined with:insertAfter()
)PhaseThree
is inserted beforePhaseTwo
, so we respect the implicit order of insertion
If you find your systems breaking because of this change, you should use insertAfter
and insertBefore
to explicitly define the dependencies of your Phases/Pipelines. You should not rely on insert to manage dependencies.
Built-in RunService Phases Removed
The following RunService Phases are no longer included in the core library, instead they are now available as a plugin.
Event | Phase(s) |
---|---|
PreRender | PreRender |
PreAnimation | PreAnimation |
PreSimulation | PreSimulation |
PostSimulation | PostSimulation |
Heartbeat | First, PreUpdate, Update, PostUpdate, Last |
When the Plugin is added, the default Phase will be set to Update
.
[dependencies]
PlanckRunService = "yetanotherclown/planck-runservice@v0.2.0-rc.1"
Replacement of Scheduler:setRunCondition
The method Scheduler:setRunCondition
has been replaced with a new method Scheduler:addRunCondition
which allows for the addition of multiple run conditions.
With this new method, it is no longer possible to overwrite previous run conditions. Run Conditions should ideally be added upon creation of the Scheduler, and not modified afterwards.
Replacement of SystemTable.runCondition
Now that you can add multiple Run Conditions, a System Table now will take SystemTable.runConditions
instead which is an array of run conditions.
local function system()
-- ...
end
local function runIf()
-- ...
end
return {
system = system,
runConditions = { throttle(10), runIf }
}
Changes
Added
Scheduler:insertBefore()
Pipeline:insertBefore()
- Conditions (isNot, runOnce, timePassed, onEvent)
Scheduler:addRunCondition()
for adding multiple run conditionsPlanckRunService
Plugin which adds built-in Pipelines and Phases for RunService events
Changed
- Refactored internals to use Adjacency Matrices for managing ordering and dependencies of Phases/Pipelines
- Breaking: The following methods now create an ordering dependency instead of setting the fixed order of Phases/Pipelines
Scheduler:insert()
Scheduler:insertAfter()
Pipeline:insert()
Pipeline:insertAfter()
- Breaking:
Scheduler:runAll()
will no longer run in the exact order that Phases were inserted for Phases bound to events. They will be grouped together, and ran together in order of insertion. - Breaking:
Scheduler:setRunCondition()
has been replaced withScheduler:addRunCondition()
- Breaking:
SystemTable.runCondition
has been replaced withSystemTable.runConditions
- Refactored internals to reuse event logic
- Replaced
Phase.Update
as default phase withDefault
Removed
- Built-in RunService Pipelines/Phases, these will be available as a separate plugin
Fixed
- Fallback System name does not contain the line of the system