local M=require(script.Parent.Parent.Signal)local n=(game:GetService("\082\117\110\083\101\114\118\105\099\101")):IsServer()local e={boolean="\066\111\111\108\086\097\108\117\101",string="\083\116\114\105\110\103\086\097\108\117\101",table="\082\101\109\111\116\101\069\118\101\110\116",CFrame="\067\070\114\097\109\101\086\097\108\117\101";Color3="\067\111\108\111\114\051\086\097\108\117\101";BrickColor="\066\114\105\099\107\067\111\108\111\114\086\097\108\117\101";number="\078\117\109\098\101\114\086\097\108\117\101";Instance="\079\098\106\101\099\116\086\097\108\117\101";Ray="\082\097\121\086\097\108\117\101",Vector3="\086\101\099\116\111\114\051\086\097\108\117\101";["\110\105\108"]="\079\098\106\101\099\116\086\097\108\117\101"}local a={}a.__index=a function a.Is(M)return type(M)=="\116\097\098\108\101"and getmetatable(M)==a end function a.new(F,Y)assert(n,"\082\101\109\111\116\101\080\114\111\112\101\114\116\121 \099\097\110 \111\110\108\121 \098\101 \099\114\101\097\116\101\100 \111\110 \116\104\101 \115\101\114\118\101\114")if Y~=nil then assert(type(Y)=="\115\116\114\105\110\103","\079\118\101\114\114\105\100\101\067\108\097\115\115 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103\059 \103\111\116 "..type(Y))assert(Y:match("\086\097\108\117\101\036"),"\079\118\101\114\114\105\100\101\067\108\097\115\115 \109\117\115\116 \098\101 \111\102 \115\117\112\101\114 \116\121\112\101 \086\097\108\117\101\066\097\115\101 \040\101\046\103\046 \073\110\116\086\097\108\117\101\041\059 \103\111\116 "..Y)end local t=typeof(F)local P=Y or e[t]assert(P,"\082\101\109\111\116\101\080\114\111\112\101\114\116\121 \100\111\101\115 \110\111\116 \115\117\112\112\111\114\116 \116\121\112\101 \""..(t.."\""))local p=setmetatable({_value=F;_type=t;_isTable=t=="\116\097\098\108\101";_object=Instance.new(P)},a)if p._isTable then local n=Instance.new("\082\101\109\111\116\101\070\117\110\099\116\105\111\110")n.Name="\084\097\098\108\101\082\101\113\117\101\115\116"n.Parent=p._object function n.OnServerInvoke(M)return p._value end p.Changed=M.new()else p.Changed=p._object.Changed end p:Set(F)return p end function a.Replicate(M)if M._isTable then M:Set(M._value)end end function a.Set(n,M)if n._isTable then n._object:FireAllClients(M)n.Changed:Fire(M)else n._object.Value=M end n._value=M end function a.Get(M)return M._value end function a.Destroy(M)M._object:Destroy()end return a
--[[

	remoteProperty = RemoteProperty.new(value: any [, overrideClass: string])

	remoteProperty:Get(): any
	remoteProperty:Set(value: any): void
	remoteProperty:Replicate(): void   [Only for table values]
	remoteProperty:Destroy(): void

	remoteProperty.Changed(newValue: any): Connection

--]]

local Signal = require(script.Parent.Parent.Signal)

local IS_SERVER = game:GetService("RunService"):IsServer()

local typeClassMap = {
	boolean = "BoolValue",
	string = "StringValue",
	table = "RemoteEvent",
	CFrame = "CFrameValue",
	Color3 = "Color3Value",
	BrickColor = "BrickColorValue",
	number = "NumberValue",
	Instance = "ObjectValue",
	Ray = "RayValue",
	Vector3 = "Vector3Value",
	["nil"] = "ObjectValue",
}

local RemoteProperty = {}
RemoteProperty.__index = RemoteProperty

function RemoteProperty.Is(object)
	return (type(object) == "table" and getmetatable(object) == RemoteProperty)
end

function RemoteProperty.new(value, overrideClass)
	assert(IS_SERVER, "RemoteProperty can only be created on the server")

	if overrideClass ~= nil then
		assert(type(overrideClass) == "string", "OverrideClass must be a string; got " .. type(overrideClass))
		assert(
			overrideClass:match("Value$"),
			"OverrideClass must be of super type ValueBase (e.g. IntValue); got " .. overrideClass
		)
	end

	local t = typeof(value)
	local class = overrideClass or typeClassMap[t]
	assert(class, 'RemoteProperty does not support type "' .. t .. '"')

	local self = setmetatable({
		_value = value,
		_type = t,
		_isTable = (t == "table"),
		_object = Instance.new(class),
	}, RemoteProperty)

	if self._isTable then
		local req = Instance.new("RemoteFunction")
		req.Name = "TableRequest"
		req.Parent = self._object
		function req.OnServerInvoke(_player)
			return self._value
		end
		self.Changed = Signal.new()
	else
		self.Changed = self._object.Changed
	end

	self:Set(value)

	return self
end

function RemoteProperty:Replicate()
	if self._isTable then
		self:Set(self._value)
	end
end

function RemoteProperty:Set(value)
	if self._isTable then
		self._object:FireAllClients(value)
		self.Changed:Fire(value)
	else
		self._object.Value = value
	end
	self._value = value
end

function RemoteProperty:Get()
	return self._value
end

function RemoteProperty:Destroy()
	self._object:Destroy()
end

return RemoteProperty
