local A=require(script.Parent.Parent.Signal)local U=(game:GetService("\082\117\110\083\101\114\118\105\099\101")):IsServer()local l={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 d={}d.__index=d function d.Is(A)return type(A)=="\116\097\098\108\101"and getmetatable(A)==d end function d.new(Y,K)assert(U,"\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 K~=nil then assert(type(K)=="\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(K))assert(K: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 "..K)end local h=typeof(Y)local H=K or l[h]assert(H,"\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 \""..(h.."\""))local V=setmetatable({_value=Y;_type=h;_isTable=h=="\116\097\098\108\101";_object=Instance.new(H)},d)if V._isTable then local U=Instance.new("\082\101\109\111\116\101\070\117\110\099\116\105\111\110")U.Name="\084\097\098\108\101\082\101\113\117\101\115\116"U.Parent=V._object function U.OnServerInvoke(A)return V._value end V.Changed=A.new()else V.Changed=V._object.Changed end V:Set(Y)return V end function d.Replicate(A)if A._isTable then A:Set(A._value)end end function d.Set(U,A)if U._isTable then U._object:FireAllClients(A)U.Changed:Fire(A)else U._object.Value=A end U._value=A end function d.Get(A)return A._value end function d.Destroy(A)A._object:Destroy()end return d



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
