Global Framework

if you set the scripts runcontext to legacy it wont run in server storage but if you set the runcontext to server or client it will run everywhere

this is just how roblox currently works has no relation to the framework

1 Like

the reason is that when you dont follow these rules, your code becomes janky very quickly and easily breaks. that’s something that might happen while using this. also, thanks for loving my argument, i would say it is pretty crafty myself

1 Like

You are still not elaborating on why it makes your code janky, stop playing dumb and explain already, I need to know. Prove me wrong or something already.

1 Like

This is extremely inefficient for something simple

2 Likes

what do you mean by eliminating cyclic modules?

1 Like

To just clear up any confusion

  1. The Global Module, Plugin and Library does not have any circular dependencies within them

  2. The Global Framework does not force you to have circular dependencies but gives you the freedom to choose if you want them or not


For anyone that does not know what a circular dependency is here is a example

lets Imagen your making a minecraft style game and you have 2 objects/classes world and block

-- WorldModule
local Block = require(BlockModule)
local World = {}
local blocks = {} 

function World:SetBlock(blockType, x, y, z)
    blocks[x][y][z] = Block.new(blockType, x, y, z)
end

return World
-- BlockModule
local Block = {}

function Block.new(blockType, x, y, z)
    local block = {}
    block.Type = blockType
    block.X = x
    block.Y = y
    block.Z = z
    return block
end

return Block

Now at this time World requires Block but Block does not require World so there currently not cyclic but you might notice that even though we have no cyclic dependencies these 2 modules are highly coupled together World does not work without Block and Block does nothing without World ok lets now for example add a explode function for blocks and do it in a way that makes it cyclic

-- BlockModule
-- this is a cyclic require
local World = require(WorldModule)
local Block = {}

function Block.new(blockType, x, y, z)
    local block = {}
    block.Type = blockType
    block.X = x
    block.Y = y
    block.Z = z
    return block
end

function Block:Explode()
    for x = -1, 1 do
        for y = -1, 1 do
            for z = -1, 1 do
                World:SetBlock("Air", self.X + x, self.Y + y, self.Z + z)
            end
        end
    end
end

return Block

Now world and block are cyclic they require each other

Some people might say this is bad some might not but the good thing about this framework it gives you the freedom to choose

2 Likes

Would you mind sharing what parts are inefficient so that i can improve them

Any tips on making them efficient would be greatly appreciated

also this framework is open source and if anyone wants to contribute any code towards the project id be happy to review any changes anyone puts forward

2 Likes

Global Library 1.1 published

Bug fix on the Thread script

no longer uses Tail Recursion because tail calls was removed from luau more information can be found here: Luau - Proper Tail Calls / Recursion - Not Working

2 Likes

Might be another dumb question by me, but is it possible to implement this framework onto the client not exclusively to the server? I’m very satisfied by the way on how this feels, it honestly just makes me write cleaner code lol and I was wondering if this could be ported onto the client along side working on the server as well.

1 Like

Yes it works the same on the client side simply make a modulescript and require it the same way you do on the server side

In the video in the game section it shows you how to do it

if your using the global library simply select the script you want and change the run context to client

1 Like

One more thing, I’m kindof confused how Global.Initialize() and Global.Start() works? I’ve always thought these are used to yield scripts so that every script is loaded first before they continue working. I’m asking this because some times there will be an error stating that Global.something is nil while sometimes it works as it is intended to. Can you provide some clarification?

1 Like

its a 3 stage system script stage, init stage and finally the start stage

-- script stage

Global.Initialize()

-- init stage

Global.Start()

-- start stage

In the script stage its never safe to access other globals

In the init stage it safe to access globals that where inserted during the script stage

And finally during the start stage its safe to access globals inserted during the script stage or init stage

as a side note scripts in replicated first should not share a global with scripts outside of replicated first

1 Like

This is how I currently do it, is there something wrong with what I script or what? Because from time to time it still errors

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
	local Global = require(ReplicatedStorage:WaitForChild("Global"))
		local InventoryManager = Global.InventoryManager

Global.Initialize()
Global.Start()

In the script where InventoryManager is created

-- Variables
local Global = require(game.ReplicatedStorage.Global)

local class = Global("InventoryManager",Global.Metatable()) :: Global.InventoryManager

...

Global.Initialize()
Global.Start()

Edit:
Oh, why didn’t I get it for the first time lol. I just reread what you said and just understanding right now. Thanks!!! (Don’t judge by stupidity lol)

Another Edit:
So base from what you said, from I understand this should fix it?

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
	local Global = require(ReplicatedStorage:WaitForChild("Global"))

Global.Initialize()
Global.Start()

local InventoryManager = Global.InventoryManager
1 Like

Yes your edit will fix the problem before you was trying to access the global in the script stage that’s not safe

but now your accessing it in the start stage and that’s safe because the start stage will only take place once all the script and init stages have finished

local Global = require(game.ReplicatedStorage.Global)

Global.Start() -- this will wait for the script & init stages to end

print(Global.InventoryManager) -- will never be nil
local Global = require(game.ReplicatedStorage.Global)

-- InventoryManager gets inserted into global during the script stage
local class = Global("InventoryManager", Global.Metatable()) :: Global.InventoryManager
2 Likes

Global Library Updated 1.2

image

Added UnreliableServerEvent & UnreliableClientEvent
Changed ParameterEvent, ParameterTimer and added ParameterCollection


Before you would need to define the parameter type when creating the event

But now you no longer define the parameter type when creating the event

This allows us to use any type we like for the parameter and the type engine can automatically workout what it is

If you prefer how the old version works you can still find it in the Legacy folder

2 Likes

Hello! In your video tutorial at around (1:21:30) you show that Timer needs a generic type of ‘PlayerObject’
image

Does this new update mean that you no longer put anything there?

That is correct it should just be Timer: ParameterTimer<>, with nothing inside it

1 Like

Hello again! I ran into an issue where if I try to use the Global __call function within a module and require it, the Global.Initialization and Global.Start functions doesn’t work anymore. Did I do something wrong here?

Script

local ServerStorage = game:GetService("ServerStorage")
local Global = require(ServerStorage.Global)

local Module = require(script.ModuleScript)

Global.Initialize(function()
	print("Init") -- doesn't run
end)

Global.Start(function()
	print("Start") -- doesn't run
end)

Module

local ServerStorage = game:GetService("ServerStorage")
local Global = require(ServerStorage.Global)

local new = Global("Something") :: any

local module = {}

return module

Place file:
Issue.rbxl (68.1 KB)

This happens because ModuleScript threads never die they stay suspended forever
this causes the Global module to wait forever there are a few ways we can solve this problem

Option 1

When calling Global in a ModuleScript place it in a new thread that will die


Option 2

Call the Global.Start() function at the bottom of your ModuleScript this will unregister the thread and allow the Global module to stop waiting

but if you add Global.Start() at the bottom of your ModuleScript this will cause the script that required the module to also wait until the ModuleScript returns if you don’t want the script to wait you can do this

local Module = task.spawn(require, ServerStorage.ModuleScript)

Option 3

Don’t use ModuleScripts like this

You could just change your ModuleScript into a script and it should all work fine


Option 4

Make a new function that unregisters the thread without yielding

1 Like

Global Library Updated 1.3

image

Added SignalManager & Table
bug fix Thread


Fixed typo in Thread and functions now return the correct type

Table provides two commonly used functions Clone & Reconcile

SignalManager is used to help manage signal connections

function Character.new(instance)
	local self = Global.Metatable(Character) :: Global.Character
	-- Create a SignalManager and connect two signals
	self.Signals = Global.SignalManager()
	self.Signals:Connect(instance.AttributeChanged, Character.AttributeChanged, self)
	self.Signals:Connect(instance.AnimationController.Animator.AnimationPlayed, Character.AnimationPlayed, self)
	return self
end

function Character:AttributeChanged(attribute)
	print(attribute)
end

function Character:AnimationPlayed(animationTrack)
	print(animationTrack)
end

function Character:Destroy()
	-- Disconnect all signals from the SignalManager
	self.Signals:DisconnectAll()
end
2 Likes