[PriProp] Change properties based on priority

New version of the module:


this module would be useful in mostly fighting games, for example when the player is blocking or stunned you can use this module to safely change their WalkSpeed or other properties without interfering with other stuff like sprinting

also for local scripts there are some limitations like they cant change their Health or MaxHealth and they cant modify any object other than their own humanoid

here is an example of how this module works

--// Server
require(MODULE)

--// Local or Server
local PriProp = require(MODULE)

local default = PriProp.New(Humanoid, {["WalkSpeed"] = 16, ["JumpPower"] = 50}, 1) -- Instance | Properties | Priority | Name (it will get a random name if you dont name it)
local sprint = PriProp.New(Humanoid, {["WalkSpeed"] = 24, ["JumpPower"] = 30}, 2, "Sprint")
-- local default = PriProp.Get(Humanoid, default.Name)
-- local sprint = PriProp.Get(Humanoid, "Sprint")

default:Enable()

local function Sprint(bool)
	if bool then
		sprint:Enable()
	else
		sprint:Disable()
	end
end

when sprint is enabled it will change WalkSpeed to 24 because it has the highest priority(2) like how animations priority works

Module's content
--// Service
local RunService = game:GetService("RunService")

--// Config
local output = false
local limitClients = true

--// Variables
local random = Random.new()
local remote = script:WaitForChild("Remote")

--//
local PriProp = {}
PriProp.__index = PriProp

local pripProps = {}

local function GenerateName()
	local letters = {"$", "!", "#", "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","1","2","3","4","5","6","7","8","9","0"}
	local str = ""
	for i=1, random:NextInteger(6, 9) do
		local randomLetter = letters[math.random(1, #letters)]
		str = str .. randomLetter
	end
	return str
end

function PriProp.New(instance: Instance, properties, priority, priPropName)	
	local self = {}
	setmetatable(self, PriProp)
	
	self.Name = priPropName or GenerateName()
	self.Instance = instance
	self.Properties = properties
	self.Priority = priority
	self.Enabled = false
	
	if RunService:IsClient() then
		remote:FireServer("New", instance, properties, priority, self.Name)
	end
	
	if not pripProps[self.Instance] then pripProps[self.Instance] = {} end
	pripProps[self.Instance][self.Name] = self
	
	return self
end

function PriProp.Get(instance: Instance, name)
	if not pripProps[instance] then
		return nil
	end
	
	for name_, self in pripProps[instance] do
		if name_ == name then
			return self
		end
	end
	
	return nil
end

function PriProp.Update(instance: Instance)
	local highestPriority = math.huge
	local appliedProperties = {}
	
	for name, self in pripProps[instance] do
		if self.Enabled then
			if output then
				warn("-------[[")
				warn(name)
				print("Priority: " .. self.Priority)
				warn("]]-------")
			end
			
			for property, value in self.Properties do
				pcall(function()
					if self.Priority >= highestPriority then
						highestPriority = self.Priority
						appliedProperties[property] = self.Priority
						instance[property] = value
					elseif not appliedProperties[property] then
						appliedProperties[property] = self.Priority
						instance[property] = value
					elseif self.Priority >= appliedProperties[property] then
						appliedProperties[property] = self.Priority
						instance[property] = value
					end
				end)
			end
		end
	end
end

function PriProp:Enable()
	if RunService:IsClient() then
		remote:FireServer("Enable", self.Instance, self.Properties, nil, self.Name)
		return
	end
	
	self.Enabled = true
	PriProp.Update(self.Instance)
end

function PriProp:Disable()
	if RunService:IsClient() then
		remote:FireServer("Disable", self.Instance, self.Properties, nil, self.Name)
		return
	end
	
	self.Enabled = false
	PriProp.Update(self.Instance)
end

function PriProp:SetEnable(bool)
	if bool then
		self:Enable()
	else
		self:Disable()
	end
end

local function Warn(name)
	if output then
		if name == "Not Humanoid" then
			warn("Clients can only modify their humanoid")
		elseif name == "Illegal Properties" then
			warn("Clients can't change these properties: Health | MaxHealth")
		end
	end
end

if not RunService:IsClient() then
	remote.OnServerEvent:Connect(function(player, state, instance: Instance, properties, priority, priPropName)
		local priprop
		local character = player.Character
		local humanoid = character:WaitForChild("Humanoid")
		
		if limitClients then
			if instance ~= humanoid then
				Warn("Not Humanoid")return
			elseif properties["Health"] or properties["MaxHealth"] then
				Warn("Illegal Properties")	return
			end
		end
		
		priprop = PriProp.Get(instance, priPropName) or PriProp.New(instance, properties, priority, priPropName)
		
		if limitClients then
			local success, allowed = pcall(function() -- double check
				if not priprop then
					return false
				elseif priprop.Properties["Health"] or priprop.Properties["MaxHealth"] then
					Warn("Illegal Properties")	return false
				end
				return true
			end)

			if not success or not allowed then
				return
			end
		end
		
		if state == "New" then
			-- line 146
		else
			priprop:SetEnable(state == "Enable")
		end
	end)
end

return PriProp

4 Likes

Like a week ago I ended up making my own state management and priority based system for exactly this. If only this was around then, lol. Nice module.

1 Like

A SetEnabled(bool) or similar function would be nice to have.

1 Like

New Update

Changes
  • you can now toggle the “limitClients” variable but its not recommended

  • some small changes

Functions
  • priprop:SetEnable(bool)

instead of using if statemens to disable/enable a priprop you can now use priprop:SetEnable(bool)

before update:

function toggle(bool)
	if bool then
		priprop:Enable()
	else
		priprop:Disable()
	end
end

now:

function toggle(bool)
	priprop:SetEnable(bool)
end
1 Like