-
Notifications
You must be signed in to change notification settings - Fork 6
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
ffd21a7
commit 6fc9768
Showing
13 changed files
with
308 additions
and
11 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
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
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,13 @@ | ||
local ReplicatedStorage = game:GetService("ReplicatedStorage") | ||
|
||
local Red = require(ReplicatedStorage.Packages.Red) | ||
local Guard = require(ReplicatedStorage.Packages.Guard) | ||
|
||
local ValueCheck = | ||
Guard.Optional(Guard.Map(Guard.String, Guard.List(Guard.Or(Guard.Literal("String Literal"), Guard.Number)))) | ||
|
||
return Red.Function("ComplexFunction", function(Value1, Value2, Value3) | ||
return ValueCheck(Value1), Guard.String(Value2), Guard.Number(Value3) | ||
end, function(Value1, Value2, Value3) | ||
return ValueCheck(Value1), Guard.String(Value2), Guard.Number(Value3) | ||
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,9 @@ | ||
local ReplicatedStorage = game:GetService("ReplicatedStorage") | ||
|
||
local Red = require(ReplicatedStorage.Packages.Red) | ||
|
||
return Red.Function("EmptyFunction", function() | ||
return | ||
end, function() | ||
return | ||
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,10 @@ | ||
local ReplicatedStorage = game:GetService("ReplicatedStorage") | ||
|
||
local Red = require(ReplicatedStorage.Packages.Red) | ||
local Guard = require(ReplicatedStorage.Packages.Guard) | ||
|
||
return Red.Function("SimpleFunction", function(Value) | ||
return Guard.Number(Value) | ||
end, function(Value) | ||
return Guard.String(Value) | ||
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
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,45 @@ | ||
# Function | ||
|
||
Functions allow RemoteFunction-like behavior in Red for calling client -> server. | ||
|
||
## SetCallback | ||
|
||
Sets the function's callback. | ||
|
||
```lua | ||
<A..., R...>( | ||
Callback: (Player, A...) -> R... -- The callback to set. | ||
) | ||
``` | ||
|
||
A singular callback must be set on the server to allow clients to call the function. This callback is given the arguments and must return the expected return values. This callback may only be set on the server, attempting to set it on the client will result in an error. | ||
|
||
```lua | ||
local Function = require(Path.To.Function) | ||
|
||
Function:SetCallback(function(Player, Arg1, Arg2, Arg3) | ||
return Arg1, Arg2, Arg3 | ||
end) | ||
``` | ||
|
||
::: danger | ||
If the callback errors the client will never recieve any value and will yield forever. **Doing this is a memory leak!** Do not rely on erroring not sending back values. | ||
::: | ||
|
||
## Call | ||
|
||
Calls the function on the server. | ||
|
||
```lua | ||
<A..., R...>( | ||
...A: any -- The arguments to pass to the function. | ||
): Future<R...> | ||
``` | ||
|
||
A function is called on the client to call the function on the server. This method returns a [Future](https://util.redblox.dev/future) which can be used to await the return values or connect a function to be called when the return values are received. | ||
|
||
```lua | ||
local Function = require(Path.To.Function) | ||
|
||
local Ret1, Ret2, Ret3 = Function:Call(Arg1, Arg2, Arg3):Await() | ||
``` |
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
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,83 @@ | ||
# Functions | ||
|
||
Functions are Red's version of RemoteFunctions. If you don't know what they are, it's a way to call code on the server from the client and get return values. Red only allows clients to call the server, not the server to call clients. | ||
|
||
## Declaring | ||
|
||
Functions are declared similarly to events, they take two validation callbacks: one for the arguments and one for the return value. | ||
|
||
```lua | ||
local Red = require(Path.To.Red) | ||
|
||
return Red.Function("FunctionName", function(Arg1, Arg2, Arg3) | ||
assert(type(Arg1) == "string") | ||
assert(type(Arg2) == "number") | ||
assert(type(Arg3) == "boolean") | ||
|
||
return Arg1, Arg2, Arg3 | ||
end, function(Ret1, Ret2, Ret3) | ||
assert(type(Ret1) == "string") | ||
assert(type(Ret2) == "number") | ||
assert(type(Ret3) == "boolean") | ||
|
||
return Ret1, Ret2, Ret3 | ||
end) | ||
``` | ||
|
||
These callbacks must follow the same three rules that event validation callbacks do: | ||
|
||
1. The callback returns the arguments in the same order they were passed in. | ||
2. The callback must error if the arguments are invalid. | ||
3. The callback must narrow the types of the arguments. | ||
|
||
These callbacks are only called in specific circumstances. Do not use these callbacks as middleware, logging, or other side effects. | ||
|
||
::: tip | ||
I once again suggest using [Guard](https://util.redblox.dev/guard) to both narrow and check types at the same time. | ||
|
||
```lua | ||
local Red = require(Path.To.Red) | ||
local Guard = require(Path.To.Guard) | ||
|
||
local CheckArg1 = Guard.Map(Guard.String, Guard.Number) | ||
local CheckArg2 = Guard.List(Guard.Vector3) | ||
local CheckArg3 = Guard.Boolean | ||
|
||
local CheckRet1 = Guard.String | ||
local CheckRet2 = Guard.Number | ||
local CheckRet3 = Guard.Set(Guard.String) | ||
|
||
return Red.Function("FunctionName", function(Arg1, Arg2, Arg3) | ||
return CheckArg1(Arg1), CheckArg2(Arg2), CheckArg3(Arg3) | ||
end, function(Ret1, Ret2, Ret3) | ||
return CheckRet1(Ret1), CheckRet2(Ret2), CheckRet3(Ret3) | ||
end) | ||
``` | ||
|
||
::: | ||
|
||
## Set Callback | ||
|
||
A singular callback must be set on the server to allow clients to call the event. This callback is given the arguments and must return the expected return values. | ||
|
||
```lua | ||
local Function = require(Path.To.Function) | ||
|
||
Function:SetCallback(function(Player, Arg1, Arg2, Arg3) | ||
return Arg1, Arg2, Arg3 | ||
end) | ||
``` | ||
|
||
::: danger | ||
If the callback errors then the client will never recieve any value and will yield forever. **Doing this is a memory leak!** Do not rely on erroring not sending back values. | ||
::: | ||
|
||
## Calling | ||
|
||
Functions can only be called from the client. The client must pass valid arguments to the function, and will be given back a [Future](https://util.redblox.dev/future) that completes with the returned values. | ||
|
||
```lua | ||
local Function = require(Path.To.Function) | ||
|
||
local Ret1, Ret2, Ret3 = Function:Call("Hello", 1, true):Await() | ||
``` |
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
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,55 @@ | ||
local RunService = game:GetService("RunService") | ||
|
||
local Future = require(script.Parent.Parent.Future) | ||
|
||
local ServerEvent = require(script.Parent.ServerEvent) | ||
local ClientEvent = require(script.Parent.ClientEvent) | ||
local Identifier = require(script.Parent.Identifier) | ||
|
||
local function PackArgs(...: any) | ||
return { ... } | ||
end | ||
|
||
export type Function<A..., R...> = { | ||
Id: string, | ||
Validate: (...unknown) -> A..., | ||
Listening: boolean, | ||
|
||
SetCallback: (self: Function<A..., R...>, Callback: (Player, A...) -> R...) -> (), | ||
Call: (self: Function<A..., R...>, A...) -> typeof(Future.new(function(): R... end)), | ||
} | ||
|
||
local function SetCallback<A..., R...>(self: Function<A..., R...>, Callback: (Player, A...) -> R...) | ||
assert(RunService:IsServer(), "Cannot set callback to function on client") | ||
assert(not self.Listening, "Cannot set callback to function multiple times") | ||
|
||
self.Listening = true | ||
ServerEvent.Listen(self.Id, function(Player, ...) | ||
if pcall(self.Validate, ...) then | ||
return Callback(Player, ...) | ||
end | ||
end) | ||
end | ||
|
||
local function Call<A..., R...>(self: Function<A..., R...>, ...: A...) | ||
return ClientEvent.Call(self.Id, PackArgs(...)) | ||
end | ||
|
||
local function Function<A..., R...>( | ||
Name: string, | ||
ValidateArg: (...unknown) -> A..., | ||
ValidateRet: (...unknown) -> R... | ||
): Function<A..., R...> | ||
assert(not Identifier.Exists(Name), "Cannot use same name twice") | ||
|
||
return { | ||
Id = Identifier.Shared(Name):Await(), | ||
Validate = ValidateArg, | ||
Listening = false, | ||
|
||
SetCallback = SetCallback, | ||
Call = Call, | ||
} :: any | ||
end | ||
|
||
return Function |
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 |
---|---|---|
|
@@ -40,4 +40,5 @@ end | |
|
||
return { | ||
Event = require(script.Event), | ||
Function = require(script.Function), | ||
} |
Oops, something went wrong.