local X=(require(script.Parent.loader)).load(script)local I=game:GetService("\080\108\097\121\101\114\115")local d=X("\066\097\115\101\079\098\106\101\099\116")local T=X("\067\104\097\114\097\099\116\101\114\085\116\105\108\115")local Q=X("\086\082\072\097\110\100\067\111\110\116\114\111\108\115")local v=X("\086\082\069\110\097\098\108\101\100\072\117\109\097\110\111\105\100\067\111\110\115\116\097\110\116\115")local D=X("\086\082\069\110\097\098\108\101\100\072\117\109\097\110\111\105\100\085\116\105\108\115")local M=X("\084\104\114\111\116\116\108\101\100\070\117\110\099\116\105\111\110")local J=X("\082\120\086\097\108\117\101\066\097\115\101\085\116\105\108\115")local y=X("\086\097\108\117\101\066\097\115\101\085\116\105\108\115")local H=X("\086\082\066\105\110\100\101\114\071\114\111\117\112\115\067\108\105\101\110\116")local A=setmetatable({},d)A.ClassName="\086\082\069\110\097\098\108\101\100\072\117\109\097\110\111\105\100\067\108\105\101\110\116"A.__index=A;(X("\080\114\111\109\105\115\101\082\101\109\111\116\101\069\118\101\110\116\077\105\120\105\110")):Add(A,v.REMOTE_EVENT_NAME)function A.new(X,T)local Q=setmetatable(d.new(X),A)Q._serviceBag=assert(T,"\078\111 \115\101\114\118\105\099\101\066\097\103")Q._vrBinderGroupsClient=Q._serviceBag:GetService(H)if Q:_getPlayer()==I.LocalPlayer then Q:_setupLocal()end return Q end function A.RequestHold(I,X)(I:PromiseRemoteEvent()):Then(function(I)I:FireServer(v.REQUEST_GRIP,X)end)end function A.RequestDrop(I,X)(I:PromiseRemoteEvent()):Then(function(I)I:FireServer(v.REQUEST_DROP,X)end)end function A.GetHumanoid(X)return X._obj end function A.FindHoldable(I,X)local d=I:_getGripAttachment(X)if not d then warn("\078\111 \103\114\105\112\065\116\116\097\099\104\109\101\110\116 \102\111\114 ",X)return nil end local T=D.findHoldable(d.WorldPosition)return T end function A.SetGripCFrame(T,X,d)assert(T:_getPlayer()==I.LocalPlayer,"\067\097\110\110\111\116 \115\101\116 \103\114\105\112 \102\111\114 \110\111\110-\108\111\099\097\108 \112\108\097\121\101\114")assert(X=="\076\101\102\116"or X=="\082\105\103\104\116","\066\097\100 \115\105\100\101\078\097\109\101")local Q=T:_getGripAttachment(X)if not Q then warn("\078\111 \103\114\105\112\065\116\116\097\099\104\109\101\110\116")return end Q.WorldCFrame=d local v=Q.CFrame if X=="\076\101\102\116"then T._throttleLeftReplicate:Call(v)elseif X=="\082\105\103\104\116"then T._throttleRightReplicate:Call(v)else error("\066\097\100 \115\105\100\101\078\097\109\101")end end function A._getGripAttachment(I,X)local d=I._obj.RootPart if not d then return nil end local T=D.getGripAttachmentName(X)local Q=d:FindFirstChild(T)return Q end function A.GetHoldingAdornee(I,X)return y.getValue(I._obj,"\079\098\106\101\099\116\086\097\108\117\101",D.getHoldingValueName(X))end function A.ObserveHoldingAdorneeBrio(I,X)assert(X=="\076\101\102\116"or X=="\082\105\103\104\116","\066\097\100 \115\105\100\101\078\097\109\101")return J.observeBrio(I._obj,"\079\098\106\101\099\116\086\097\108\117\101",D.getHoldingValueName(X))end function A._setupLocal(X)X._throttleLeftReplicate=M.new(.1,function(I)(X:PromiseRemoteEvent()):Then(function(X)X:FireServer(v.REQUEST_SET_GRIP_CFRAME,"\076\101\102\116",I)end)end,{leading=true;trailing=true})X._maid:GiveTask(X._throttleLeftReplicate)X._throttleRightReplicate=M.new(.1,function(I)(X:PromiseRemoteEvent()):Then(function(X)X:FireServer(v.REQUEST_SET_GRIP_CFRAME,"\082\105\103\104\116",I)end)end,{leading=true;trailing=true})X._maid:GiveTask(X._throttleRightReplicate)X._controls=Q.new(X._serviceBag,X)X._maid:GiveTask(X._controls)X._maid:GiveTask((X:ObserveHoldingAdorneeBrio("\082\105\103\104\116")):Subscribe(function(I)X:_handleHoldingActivation(I)end))X._maid:GiveTask((X:ObserveHoldingAdorneeBrio("\076\101\102\116")):Subscribe(function(I)X:_handleHoldingActivation(I)end))end function A._getPlayer(X)return T.getPlayerFromCharacter(X._obj)end function A._handleHoldingActivation(I,X)if X:IsDead()then return end local d=X:ToMaid()local T=X:GetValue()if T then for X,I in pairs(I._vrBinderGroupsClient.VRHoldable:GetBinders())do local Q=I:Get(T)if Q then Q:OnVRHandHold(d)end end end end return A
--[=[
	@class VREnabledHumanoidClient
]=]

local require = require(script.Parent.loader).load(script)

local Players = game:GetService("Players")

local BaseObject = require("BaseObject")
local CharacterUtils = require("CharacterUtils")
local VRHandControls = require("VRHandControls")
local VREnabledHumanoidConstants = require("VREnabledHumanoidConstants")
local VREnabledHumanoidUtils = require("VREnabledHumanoidUtils")
local ThrottledFunction = require("ThrottledFunction")
local RxValueBaseUtils = require("RxValueBaseUtils")
local ValueBaseUtils = require("ValueBaseUtils")
local VRBinderGroupsClient = require("VRBinderGroupsClient")

local VREnabledHumanoidClient = setmetatable({}, BaseObject)
VREnabledHumanoidClient.ClassName = "VREnabledHumanoidClient"
VREnabledHumanoidClient.__index = VREnabledHumanoidClient

require("PromiseRemoteEventMixin"):Add(VREnabledHumanoidClient, VREnabledHumanoidConstants.REMOTE_EVENT_NAME)

function VREnabledHumanoidClient.new(humanoid, serviceBag)
	local self = setmetatable(BaseObject.new(humanoid), VREnabledHumanoidClient)

	self._serviceBag = assert(serviceBag, "No serviceBag")
	self._vrBinderGroupsClient = self._serviceBag:GetService(VRBinderGroupsClient)

	if self:_getPlayer() == Players.LocalPlayer then
		self:_setupLocal()
	end

	return self
end

function VREnabledHumanoidClient:RequestHold(sideName)
	self:PromiseRemoteEvent():Then(function(remoteEvent)
		remoteEvent:FireServer(VREnabledHumanoidConstants.REQUEST_GRIP, sideName)
	end)
end

function VREnabledHumanoidClient:RequestDrop(sideName)
	self:PromiseRemoteEvent():Then(function(remoteEvent)
		remoteEvent:FireServer(VREnabledHumanoidConstants.REQUEST_DROP, sideName)
	end)
end

function VREnabledHumanoidClient:GetHumanoid()
	return self._obj
end

function VREnabledHumanoidClient:FindHoldable(sideName)
	local gripAttachment = self:_getGripAttachment(sideName)
	if not gripAttachment then
		warn("No gripAttachment for ", sideName)
		return nil
	end

	local holdable = VREnabledHumanoidUtils.findHoldable(gripAttachment.WorldPosition)
	return holdable
end

function VREnabledHumanoidClient:SetGripCFrame(sideName, worldCFrame)
	assert(self:_getPlayer() == Players.LocalPlayer, "Cannot set grip for non-local player")
	assert(sideName == "Left" or sideName == "Right", "Bad sideName")

	local gripAttachment = self:_getGripAttachment(sideName)
	if not gripAttachment then
		warn("No gripAttachment")
		return
	end

	gripAttachment.WorldCFrame = worldCFrame

	local cframe = gripAttachment.CFrame
	if sideName == "Left" then
		self._throttleLeftReplicate:Call(cframe)
	elseif sideName == "Right" then
		self._throttleRightReplicate:Call(cframe)
	else
		error("Bad sideName")
	end
end

function VREnabledHumanoidClient:_getGripAttachment(sideName)
	local rootPart = self._obj.RootPart
	if not rootPart then
		return nil
	end

	local attachmentName = VREnabledHumanoidUtils.getGripAttachmentName(sideName)
	local attachment = rootPart:FindFirstChild(attachmentName)

	return attachment
end

function VREnabledHumanoidClient:GetHoldingAdornee(sideName)
	return ValueBaseUtils.getValue(self._obj, "ObjectValue", VREnabledHumanoidUtils.getHoldingValueName(sideName))
end

function VREnabledHumanoidClient:ObserveHoldingAdorneeBrio(sideName)
	assert(sideName == "Left" or sideName == "Right", "Bad sideName")

	return RxValueBaseUtils.observeBrio(self._obj, "ObjectValue", VREnabledHumanoidUtils.getHoldingValueName(sideName))
end

function VREnabledHumanoidClient:_setupLocal()
	self._throttleLeftReplicate = ThrottledFunction.new(0.1, function(cframe)
		self:PromiseRemoteEvent():Then(function(remoteEvent)
			remoteEvent:FireServer(VREnabledHumanoidConstants.REQUEST_SET_GRIP_CFRAME, "Left", cframe)
		end)
	end, {
		leading = true;
		trailing = true;
	})
	self._maid:GiveTask(self._throttleLeftReplicate)

	self._throttleRightReplicate = ThrottledFunction.new(0.1, function(cframe)
		self:PromiseRemoteEvent():Then(function(remoteEvent)
			remoteEvent:FireServer(VREnabledHumanoidConstants.REQUEST_SET_GRIP_CFRAME, "Right", cframe)
		end)
	end, {
		leading = true;
		trailing = true;
	})
	self._maid:GiveTask(self._throttleRightReplicate)

	self._controls = VRHandControls.new(self._serviceBag, self)
	self._maid:GiveTask(self._controls)

	self._maid:GiveTask(self:ObserveHoldingAdorneeBrio("Right"):Subscribe(function(brio)
		self:_handleHoldingActivation(brio)
	end))

	self._maid:GiveTask(self:ObserveHoldingAdorneeBrio("Left"):Subscribe(function(brio)
		self:_handleHoldingActivation(brio)
	end))
end

function VREnabledHumanoidClient:_getPlayer()
	return CharacterUtils.getPlayerFromCharacter(self._obj)
end


function VREnabledHumanoidClient:_handleHoldingActivation(brio)
	if brio:IsDead() then
		return
	end

	local maid = brio:ToMaid()
	local adornee = brio:GetValue()

	if adornee then
		for _, binder in pairs(self._vrBinderGroupsClient.VRHoldable:GetBinders()) do
			local value = binder:Get(adornee)
			if value then
				value:OnVRHandHold(maid)
			end
		end
	end
end

return VREnabledHumanoidClient