Rex Framework | Designed for beginners to intermediate developers

Introduction To The Rex Framework

| GitHub | Model |


The rex framework is a framework inspired by knit (I basically got bored and was really inspired to go out of my way to make this). The framework was named after @EDmaster24 (a friend) and because of how short it is it’s easy to type and remember.

The purpose of the Rex Framework is to provide pre-made resources and to cutdown on manual remote setup. When creating this framework, the main goal in mind was to create this for anime-like games, however, it can be used in any environment. The Rex Framework allows for individuals to create “Modules” for it to be shared and retrievable by any other script. If a module is created on the server, the client will be able to call functions on the client table of the module. If a module is created on the client, all the other client scripts will have access to retrieve the module. For a better understanding and an example, please take a look at Example Use Case.

TIP:

When working with the Rex Framework, in order for other scripts to know when modules are able to be retrieved, you must run Rex:Start() on both a main Client and Server script. Before Rex:Start(), you want to create any custom modules, rewrite any pre-build modules and also create any Databases.


Information

I’ve separated this into multiple categories to be a bit neater. Please do look over the following categories below before asking any questions. I am more than happy to answer them!


Example Use Case

Introduction

I’ll show an example of the Rex Framework in use with one of my own games in production, The Rex Framework is constantly being changed as needed for ease of use as well as clarity and functionality.

Here’s a game I’m working on that you can check out how I’ve set up the Rex Framework:
Square Piecce 2.rbxl (204.6 KB)

The format in the place file is what I find best to work with. It allows me to add new modules and databases with extreme flexibility on both Server and Client sides.

Prebuilt Modules

Introduction


These are prebuilt modules made by mostly by me that I found extremely useful. I did not list every single module and function because that’s too much work. Below is an example on how to retrieved a module:

local Module = Rex:GetModule("ModuleName")

When reading the methods, <> means required, [] means optional.


RayService

RayService

Example:

local Rex = require(game.ReplicatedStorage.Rex)
local RayService = Rex:GetModule("RayService")
local Result = RayService:Cast(Vector3.new(0,0,0), CFrame.new(0,100,0), {}, FilterType, IgnoreWater, CollisionGroup)
RayService:Visualize(CFrame.new(0,0,0), Vector3.new(0,100,0), Color3RGB)

Methods:

local Rex = require(game.ReplicatedStorage.Rex)
local RayService = Rex:GetModule("RayService")

local Result = RayService:Cast(
	<Vector3 or CFrame> StartPoint,
	<Vector3 or CFrame> EndPoint,
	[Array] IgnoreList Or WhiteList,
	[RayFilterType Enumueration] FilterType,
	[Boolean] IgnoreWater,
	[String] CollisionGroup
)

RayService:Visualize(
	<Vector3 or CFrame> StartPoint,
	<Vector3 or CFrame> EndPoint,
	[Color3RGB] RayColor,
)

LerpService

LerpService

Lerp Service is basically an exact replica of TweenService however, it does NOT create a new thread per every new tween. The format maintains the same and everything is automatically garbage collected.

Example:

local Rex = require(game.ReplicatedStorage.Rex)
local LerpService = Rex:GetModule("LerpService")
wait(7)
local Animation = LerpService:Create(game.Workspace.Part, TweenInfo.new(5,Enum.EasingStyle.Linear), {Color = Color3.fromRGB(255,0,0)})
Animation:Play()
wait(5)
Animation:Stop()
wait(5)
Animation:Resume()
wait(10)

Methods

local Rex = require(game.ReplicatedStorage.Rex)
local LerpService = Rex:GetModule("LerpService")

local Tween = LerpService:Create(Object Or List Of Objects, TweenInfo or Dictonary or List, goal) -- Creates The Tween

Tween:Play() --> Plays The Tween
Tween:Stop() --> Stops The Tween
Tween:Resume() --> Continues the tween


HitboxService

HitboxService

The purpose of HitboxService was to introduce an easy way to create Hitboxes for magical skills and bullets. HitboxService can be primarily used for Area Of Effect or Projectile hitboxes.

Hitbox:CastProjectileHitbox({
	Points = {CFrame1, CFrame2},
	Direction = Vector3.new(),
	Velocity = 10,
	Lifetime = 1,
	Iterations = 1,
	Visualize = true,
	Function = function(RaycastResult)
					
	end,
	Ignore = {}
})

Here’s a visual example:

Methods:

local Rex = require(game.ReplicatedStorage.Rex)
local HitboxService = Rex:GetService("HitboxService")

HitboxService:CastProjectileHitbox({ -- Everything is required
	Points = {}, -- Array Of CFrames
	Direction = Vector3.new(), -- Direction
	Velocity = 10, -- Velocity Of Projectile
	Lifetime = 1, -- Total Duration 
	Iterations = 1, -- Amount of times it's splitted,
	Visualize = true, -- Visualizes the hitbox using RayService
	Function = function(RaycastResult) -- Callback

	end,
	Ignore = {} -- Array Of Objects To be Ignored
})

local ValidTargets = HitboxService:GetEntitiesFromPoint(
	<Vector3 or CFrame> Point Of Explosion,
	<List> All Valid Entities,
	<Dictionary> Ignore List Using Object as Index,
	<Number> Radius Of Explosion,
	[Boolean] Raycasts to find obstacles,
) -- Returns an array of valid entities within range

local RadialPoints = HitboxService:GetRadialPoints(
	<CFrame> Orgin,
	<Number> Amount Of Points,
	<Number> Radius 
) -- Returns an array of cframes that form a circle

local SquarePoints = HitboxService:GetSquarePoints(
	<CFrame> Orgin,
	<Number> Width,
	<Number> Height,
) -- Returns an array of cframes that form a square grid


VFXService

VFXService

VFX Service contains a bunch of pre-built special effects.

Example usage:

local VFXService = Rex:GetModule("VFXService")
VFXService.Shake("Explosion") -- If you want only the player

TIP:

VFX Service should only be used on the Client.

Methods

local Rex = require(game.ReplicatedStorage.Rex)
local VFXService = Rex:GetModule("VFXService")

VFXService.Blur(
	<Number> TotalDuration, 
	<Number> Blur Size, 
)

VFXService.Shake(
	<String> Shake Preset, -- Uses Crazyman's camera shake
)

VFXService.FOV(
	<Number> TotalDuration,
	<Number> FOV,
)

TaskScheduler

TaskScheduler

TaskScheduler allows you run callbacks without yielding with accurate delays. This is a replacement for the Roblox delay function, if you need delays often it’s recommended to use this.

Methods

local Rex = require(game.ReplicatedStorage.Rex)
local TaskScheduler = Rex:GetModule("TaskScheduler")

TaskScheduler:AddItem(Time, Callback);
TaskScheduler:AddTask(Time, Callback);

DebrisService

DebrisService

DebrisService was created to allow users to delete items or disconnect connections in replacement of using spawn, delay and even Roblox’s Debris service.

Methods

local Rex = require(game.ReplicatedStorage.Rex)
local DebrisService = Rex:GetService("DebrisService")

DebrisService:AddItem(
	<RBX Object or RBX Connection or Array> Things To Be Cleaned Up,
	[Number] Time Until Destroyed,
	[Function] Callback when cleaned,
)


Documentation

Documentation


Rex:Start()

Initiates the framework allowing other other scripts to safety retrieve custom modules. Prebuilt modules will can be required before hand.


Rex:GetModule([ModuleName])

Retrieves the module with a Module Name. If Module does not exist it will return nil


Rex:GetAllModules()

Retrieves all the modules in a dictionary format


Rex:CreateModule([ModuleName], [ServerFunctions], [ClientFunctions])

Creates a module with a table of Server Functions (to be called from other server scripts), Client Functions to be called from Local Scripts.


Rex:GetDatabase([Database Name])

Retrieves Database with the Database Name. Databases are basically shared tables across the server client boundary, the client can write to the table but can read from it.


Rex:CreateDatabase([Database], [Data])

Creates a database with the name of the Database and with the Data.


Rex:GetAllDatabases()

Retrieves all the available databases in a dictionary format


Rex:Write(DatabaseId, Directory, Value)

Writes to a database (replicating it to the client). Example:

local Rex = require(game.ReplicatedStorage.Rex)
local Database = Rex:CreateDatabase("Hi", {
  Example = {
    SubTable = {Val = 1};
  }
})

Rex:Write("Hi", {"Example", "SubTable", "Val"}, 5) -- Will set the Val in SubTable to 5


Tips

TIP 1:

Do you hate long scripts? You can utilize modules to create services, databases organizing your code. Here’s an example:

Format:
image

Server Script:

--|| Server ||--
--|| Services ||--
local ReplicatedStorage = game.ReplicatedStorage;

local Rex = require(ReplicatedStorage.Rex);

local Modules = script.Modules:GetChildren()
for i = 1, #Modules do
	local Module = Modules[i];
	local Contents = require(Module);
	Rex:CreateModule(Module.Name, Contents.Server, Contents.Client);
end

local Databases = script.Databases:GetChildren()
for i = 1, #Databases do
	local Database = Databases[i];
	Rex:CreateDatabase(Database.Name, require(Database));
end

Rex:Start();

In InputService:

local ServerStorage = game.ServerStorage;
local Players = game.Players
local ReplicatedStorage = game.ReplicatedStorage;

local Globals = require(ReplicatedStorage.Modules.Globals);

local RecognizedKeybinds = {
	Q = "Dash";
}

local AbilitiesCache = {};
local Abilities = ServerStorage.Abilities:GetDescendants()
for i = 1, #Abilities do
	local Desc = Abilities[i];
	if Desc:IsA("ModuleScript") then
		local Suc, Err = pcall(function()
			AbilitiesCache[Desc] = require(Desc)
		end)
		
		if not Suc then
			warn("An error has occured attempting to require "..Desc.Name, Err);
		end
	end
end

local module = {
	Server = {};
	Client = {
		HotbarEquip = function(Player, Input)
			if not Globals.IsAlive(Player.Character) then return false end;
			local States = Player.States;
			States["Equipped Hotbar Slot"].Value = Input;
			--| Prompt Equip
			return true
		end,
		HotbarUnequip = function(Player)
			if not Globals.IsAlive(Player.Character) then return false end;
			local States = Player.States;
			--| Unequip
			States["Equipped Hotbar Slot"].Value = "None";
			return true
		end,
		ReadInput = function(Player, Input, MouseHit)
			if not Globals.IsAlive(Player.Character) then return false end;
			local States = Player.States;
			local Stats = Player.Stats;
			local Hotbar = Player.Hotbar;
			local EquippedHotbarSlot = States["Equipped Hotbar Slot"].Value
						
			if EquippedHotbarSlot ~= "None" then
				local HotbarEquippedId = Hotbar[EquippedHotbarSlot].Id.Value
				local Type, Data = Globals.GetCategoryFromId(HotbarEquippedId);
				if Data[Input] then
					return AbilitiesCache[ServerStorage.Abilities[Type][HotbarEquippedId][Data[Input].Id]](Player, Data[Input], MouseHit)
				end	
			elseif RecognizedKeybinds[Input] then
				return AbilitiesCache[ServerStorage.Abilities.General[RecognizedKeybinds[Input]]](Player, MouseHit)
			end
		end;
	};
}

return module

In a database:

local module = {}

return module

TIP 2:

Do you have third party modules in your game? Do you hate requiring them to end up like this:

local Datastore = require(game.ServerScriptService.Datastore.Datastore)
local Rex = require(game.ReplicatedStorage.Rex)

Well, you can do this!

--|| Services ||--
local Datastore = require(game.ServerScriptService.Datastore.Datastore)
local Rex = require(game.ReplicatedStorage.Rex)

local Server = Datastore; -- Now the service "Datastore" has access to the Datastore module.
local Client = {};

local Service = Rex:CreateService(script.Name, Server, Client);

return Server

You can also share functions into the Client table (not one’s that handle saving, loading for security reasons but retrieving data.)


Last Updated: 2021-01-28T05:00:00Z


Other Resources

52 Likes

Very cool will might use this in my next project hopefully possibly

4 Likes

Hello everyone, I’m sorry I rushed the post when I first released the framework. I’ve went through the whole post and updated for better clarifications. I’ve also listed all the custom pre-built services and what they provide. Hope this clear things up. I will continue testing using this framework and apply updates accordingly.

2 Likes

Ooh I like the idea of a backup database.

EDIT: In fact, once I learn HTML/JS/CSS I’ve been planning to make a ‘developer tool’ site, so this would be a cool thing to have on it. :slight_smile:

1 Like

After some thought, I’ve decided it’s best not to implement a built in datastore. I want people to have as much control as possible. The issue with firebase is that not everyone has a firebase account and it can be a hassle to set one up.

I’m currently using the framework for production to see what is used and what doesn’t to look for improvements.

Looks good!

Mabye you could add a plugin that installs the framework automatically? That could a little more convenient.

2 Likes

The plugin seems like an overkill. The framework is one object that you put into replicated storage and it’s done! No need to hog your plugin space with something that inserts one object. If it required multiple objects in multiple services or places I’d consider because it may be harder to setup. I update the model regularly so worry not. If you start a new project it’ll most likely be updated.


I do want to re-iterate something since I am replying; I’m currently using this framework for game production as a experiment. This experiment will help me figure out what features are useful, what features need to be removed and what features do I need to improve the framework.

I also want to mention that when I was constructing this framework, the ideal goal was to be able to stick on the server as much as possible. As I’ve tested the framework I’ve noticed one issue that may or may not be problematic.

  1. GetService, GetDatabase, GetClass

I’ve noticed that creating services, databases and classes at run time can be fairly problematic. The reason for it being problematic is because within your class or service you may want to have reference to another class or service and utilize that. The first solution to this issue is to do GetService, GetDatabase and GetClass within the function like so:

local ControlsHandler = Rex:CreateClass("ControlsHandler", {}, {
	Sprint = function(Player)
        local StatesDatabase = Rex:GetDatabase("States") -- You'll notice I did it in here
		local Character = Player.Character
		local Humanoid = Character and Character.PrimaryPart and Character:FindFirstChild"Humanoid"
		if Humanoid then
			StatesDatabase[Player.Name].Sprinting = not StatesDatabase[Player.Name].Sprinting
			Humanoid.WalkSpeed = (StatesDatabase[Player.Name].Sprinting and 24 or 16)
			Rex:ReplicateDatabase()
		end
	end,
}) 

Now this can get really annoying having to do that within every function. GetService, GetDatabase and GetClass are methods that will yield until Rex:Start() is called.

The other solution is the use of metatables. If I were to require a module and it had Rex:GetService() at the top, it’ll yield and result in a infinite yield. The solution is to not require all the modules and cache them at once, rather cache them and require them when you need them. Chances are the functions won’t be called at runtime.

local StandAbilities = {}

for _, Stand in ipairs(ServerStorage["Stand Abilties"]:GetChildren()) do
	StandAbilities[Stand.Name] = {}
	setmetatable(StandAbilities[Stand.Name], {
		__index = function(ot, index)
			ot[index] = require(Stand[index])
			return ot[index]
		end
	})
end

These issues I’ve considered as minor for the time being. If I can come up with a solution to make it even easier I will do so. At the moment, I’m looking at prebuilt services to help people stick on the server. I’m considering: SoundService, and ParticleService (you’ll notice most of these are special effects related that should be done on the client which is why I did AnimateService).

EDIT: There was an issue previously with :GetService, :GetClass, :GetDatabase. Where it would yield even though it already existed (was prebuilt). I’ve fixed this in a newer version of the Rex framework allowing you to call those functions before Rex:Start().

I understand
It could be nice as a option tho.

Looking forward to more updates on this framework!

1 Like

I submitted a pull request in the repo for some changes I think would streamline the module.

I took a look and when making the framework I did have that in mind. The thing is I want to keep my habits more towards Lua.

I’ll go ahead and remove the localisation.

EDIT: To anyone notified by this, after working with the framework I haven’t found any major issues. I’ll continue using the framework and experimenting. I’ve also added another service and the post will be updated.

Just a heads up, it is generally more polite to merge pull requests that you want to implement into your project rather than closing the pull request and then commiting the changes under your name.

Very sorry, this is my first time using GitHub with pull requests (I’m still not sure what they are exactly). I hope I did not offend you in anyway.


Update: 2020-10-30T04:00:00Z

After working with the framework for a while, it’s serving its attended purpose keeping most of the scripting on the Server. I’ve updated the post by re-formatting it and fixing a few grammar mistakes. I’ve also included documentation on HitboxService which can be actively used for AOE or Projectile Based special abilities and skills.


Update: 2020-11-01T04:00:00Z

Over the duration of me working front end (skills, magic, abilities), I’ve decided to introduce VFXService. VFXService has 2 main functions as of right now, :Shake() and :Blur(). This is to again help users stay server sided. The :Shake() function uses Crazyman’s Camera shake.

To use:

local VFXService = Rex:GetService("VFXService")

VFXService:Shake(ShakePreset, TargetPlayer)
VFXService:Blur(TotalDuration, BlurSize, TargetPlayer)

If TargetPlayer is nil, it will affect every single player.

Here’s what I made using these functions:


Update: 2020-11-07T05:00:00Z

Updates

  • Improved HitboxService :CastProjectileHitbox() function for more accurate for progressive raycasts.
  • Fixed minor bugs with AnimateService
    Here’s a gif using a combination of AnimateService and the HitboxService:

https://gyazo.com/b624266855b141891cd421a330f18371


Update: 2020-11-10T05:00:00Z

Updates

  • Fixed a bug with replication for AnimateService

After using AnimateService frequently, I’ve noticed a bug which was with the auto replication. Here’s a visualization of the unfixed version vs the fixed version:

Here’s the code:

local Rex = require(game.ReplicatedStorage.Rex)
wait(5)
local AnimateService = Rex:GetService("AnimateService")

local Tween1 = AnimateService:Create({
	{script.Parent, 10, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0, {Transparency = 1}}
})
Tween1:Play()
print("YESR")
wait(6)
local Tween1 = AnimateService:Create({
	{script.Parent, 2, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0, {Transparency = 0}}
})
Tween1:Play()
print("YO WHAT ISS UP DUDE")
wait(4)
print("THIS FINSIHED BBRO")

As you can see the first one is the unfixed version, this is because previously, replication was based on time of the tween. You can see that 6 seconds into the first tween, I re-tween the same property, however, the replication takes priority in the first tween due to length of the tween.

The second part of the video shows wanted behavior in Roblox’s normal TweenService. Even though it’s the same code, the second one takes replication priority simply because it overlaps the first one.

The model has been updated to the date above, no forms of methods or functions were changed, just an internal fix on the TweenService wrapper.


Update: 2020-11-15T05:00:00Z

Updates

  • Added ClientService
  • Added Automatic Clean Up To AnimateService (You no longer need :Destroy())
  • Added :PauseAllAnimations() and :PlayAllAnimations() to AnimateService
  • Added DebrisService
  • Update Documentations

Update: 2020-11-16T05:00:00Z

Updates

  • Fixed caching issue with AnimateService, :PauseAllAnimations() and :PlayAllAnimations() should function properly now
  • Added the ability to reuse tweens even after they are dead, this will internally create a new tween with the same data
  • Added VFXService:FOV() to have an animated FOV effect

Example Of Using New Updates:

Hey, I see this framework is outdated. Is it still usable?

Hey there. there only thing outdated is the documentation, the framework has been updated for it to be simplified and for it to have more useful functionality.


I will update the documentation right now and let you know when it’s up to date.

1 Like

Thanks! I am going to use it for my game.

The post has been updated, I’ve also provided a place example under “Example Use Case”. I was unable to add every single function and module as it was too overwhelming, I’m sure everyone can find a use case for the other modules.


The module will still be actively updated. I will update the documentation and needed. Feel free to let me know if you need any form of help whatsoever. You can also let me know if you want to know if there are any specific modules for your use case.

1 Like

this is sooooooooooooooooooooooooooooo awesome and useful aaaaaaaaaaaah u just saved me 4 months of scripting tbh too good but uuh might i reccommend changing the names of funcs around a lil bit like changing the vfx to camerafx cuz it is a lil bit confusing with some things

That’s great to hear, you’re more than free to change the function names yourself but it may break certain functions if it relies on it.


In general, the framework is still being worked on and is being tested with live production. There are a few optimization updates thanks to @Prexxo .

1 Like

by any chance u didnt mean to say client cant write to the table but can read from it right?

got 2 questions-
a) can i write/read via server
b) can i put a function in the database and call it??