FastValue a library that replaces Value Instances and makes sure they don't get removed

As far as I can tell there’s little optimization whatsoever, so I wouldn’t say it’s better than native remotes & bindables. This is all constructive so don’t take this the wrong way.

But if you’re going say it’s faster and better than this or that, please provide evidence & benchmarks like @Artzified said.

2 Likes

this does not replace fastsignal like you said lmao

It does, with the .Changed function

I think that roblox uses something like metatables for the Value Instance because it doesn’t have methods to change the value so the only option for the changed event is metatables.

You have the question of the above.

Where did you even get this? I’m pretty sure the engineers there has better tooling than just metatables, they don’t just do Luau, they also do lower level languages for more optimizations. Just because something uses a key-value property for read and write, it doesn’t mean it uses metatables. Lower level & higher level languages has native getter and setters that behaves the same way, but better.

TL;DR: I’m confident that your claim is false

It still wouldn’t answer why this is a better alternative to FastSignal, you’re just making stuff up now. I’m pretty sure FastSignal is just bindable but faster, you’re just using ValueBase Instances, which is completely different and you don’t provide benchmark as proof that this can replace FastSignal.

I don’t know what’s special about this ValueBase module, it doesn’t seem authentic and as advertised. What makes this different than making my own replication module using ValueBase instances, as the only superior feature you’ve written is just type annotation. What’s so safe about using this? Can some “ex-ploiters” just change the value in the client and the server would flag it as legit?

There a compilers for Lua U to machine code, even if it still wouldn’t be faster than C++ it has other advantages like that you can change the code to your likings.

You only need to keep an eye on two remotes, that means you can implement your security features easier.

Can you provide benchmarks versus Value Instances?

1 Like

I will try to do the benchmarks.

I don’t know how to benchmark Value Instance, I have tried and it prints nan out here is the code:

-- Server
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local FastValue = require(ReplicatedStorage.FastValue)
local value = ReplicatedStorage.Value
local valueInstanceBenchmarks = ReplicatedStorage.ValueInstanceBenchmarks

local ValueInstanceServerTicks = {}
local ValueInstanceTicks = {}
local valueInstanceAverageTick = 0

for i = 1, 10, 1 do
	task.wait(1)
	value.Value = i
	table.insert(ValueInstanceServerTicks, tick())
end

valueInstanceBenchmarks.OnServerEvent:Connect(function(player, ValueInstanceClientTicks)
	for i, clientTick in ipairs(ValueInstanceClientTicks) do
		table.insert(ValueInstanceTicks, clientTick - ValueInstanceServerTicks[i])
	end
end)

for i, tick in ipairs(ValueInstanceTicks) do
	valueInstanceAverageTick += tick
end

valueInstanceAverageTick /= #ValueInstanceTicks

print(valueInstanceAverageTick)

-- Client
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local FastValue = require(ReplicatedStorage.FastValue)
local value = ReplicatedStorage.Value
local valueInstanceBenchmarks = ReplicatedStorage.ValueInstanceBenchmarks

local ValueInstanceClientTicks = {}

value.Changed:Connect(function(value)
	table.insert(ValueInstanceClientTicks, tick())
end)

valueInstanceBenchmarks:FireServer(ValueInstanceClientTicks)

Here is the ReplicatedStorage
image

Hi birb, I did my own benchmark test!

These are my individual benchmarking tests by getting the median percentile of each result.

Now before taking a look at the results I just want to address that these tests were done with 65535 iterations, using a string generated by HttpService:GenerateGUID() & StringValue object.

Other tests may differ from the one shown here.

Set

We see that FastValue is a few nanoseconds slower after looking at the 50% percentile.

Now this makes sense because after taking a quick look at FastValue’s source code it makes a lot of table accesses. (an unneeded amount of)

While regular values use metatables to point to C++ code, where memory accesses are made to get your value.

We can see an issue with the Set function in the attached image below too

Get

After benchmarking the median result of how long receiving values take:

Well that’s a little faster, but the StringValue is still showing a consistent 1.50~ nanosecond speed.

Other than that -not saying this is a bad resource or anything- I would suggest just using regular ValueBase instances provided by the engine.

  • You get free type-check
  • Replication to client is throttled at 60hz

Here is a highlight of the RDC 2020 presentation, Quenty showing why ValueBases shouldn’t be avoided:

P.S. This is not to attack the author in any form or means. I love community resources provided to other developers for no cost!!

2 Likes

So wouldn’t it just be faster to use attributes with the same functionality?

1 Like

Actually, yes. Depends on your use case.

1 Like

FastValue supports tables but how much faster is it when setting up Attributes with json?

1 Like

Also could you provide the code you used for benchmarking?

1 Like

Very slow, you could use FastValue in that case.

Alternative Approaches:

ModuleScripts

ModuleScripts provide globally accessible tables within the entire datamodel, you can write your own code to replicate these states into the client or using FastValue.

Values Objects (yes again!)

If you are using simple values (numbers, strings, booleans) you can attempt to distribute these values into ValueBases stored in a folder. This method allows you to directly store key-value pairs in the Roblox hierarchy.

You can still go with the JSON method tho, which will be slower and more complex to debug. : /

1 Like

Sure, wrote this in a hurry so the code runs with hopes & prayers (and a little duct tape)

local function calculateMedian(arr)
	local n = #arr

	table.sort(arr)

	if n % 2 == 1 then
		return arr[math.ceil(n / 2)]
	else
		local mid1 = arr[n / 2]
		local mid2 = arr[n / 2 + 1]
		return (mid1 + mid2) / 2
	end
end

local function convert_seconds(seconds)
	local milliseconds = seconds * 1000
	local microseconds = milliseconds * 1000

	if milliseconds < 1 then
		return ("%.2f"):format(microseconds), "microseconds"
	elseif milliseconds < 1000 then
		return ("%.2f"):format(milliseconds), "milliseconds"
	else
		return ("%.2f"):format(seconds), "seconds"
	end
end


local FastValue = require(workspace.FastValue)
local FastValue_Get = FastValue.Get
local FastValue_Set = FastValue.Set

local StringValue = workspace.StringValue

local FASTVALUE_Results = {}
local STRINGVALUE_Results = {}

local Value = game:GetService("HttpService"):GenerateGUID(false)

for FastValue_i = 1, 2 ^ 16 do
	local t = os.clock()

	FastValue_Set("Key", Value)

	FASTVALUE_Results[#FASTVALUE_Results + 1] = os.clock() - t
end

for StringValue_i = 1, 2 ^ 16 do
	local t = os.clock()

	StringValue.Value = Value

	STRINGVALUE_Results[#STRINGVALUE_Results + 1] = os.clock() - t
end

print("The 50th percentile (median) of StringValue (SETTING NEW .Value): ", convert_seconds(calculateMedian(STRINGVALUE_Results)))
print("The 50th percentile (median) of FastValue (USING THE SET FN): ", convert_seconds(calculateMedian(FASTVALUE_Results)))
  1. Add a StringValue object in the workspace named “StringValue”
  2. Add the FastValue module in the workspace
4 Likes