local X=(require(script.Parent.loader)).load(script)local I=X("\065\100\111\114\110\101\101\085\116\105\108\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("\073\075\066\105\110\100\101\114\115\083\101\114\118\101\114")local v=X("\073\075\071\114\105\112\085\116\105\108\115")local D=X("\077\097\105\100")local M=X("\078\101\116\119\111\114\107\079\119\110\101\114\083\101\114\118\105\099\101")local J=X("\078\101\116\119\111\114\107\082\111\112\101\085\116\105\108\115")local y=X("\082\111\111\116\080\097\114\116\085\116\105\108\115")local H=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 A=X("\086\082\069\110\097\098\108\101\100\072\117\109\097\110\111\105\100\085\116\105\108\115")local t=setmetatable({},d)t.ClassName="\086\082\069\110\097\098\108\101\100\072\117\109\097\110\111\105\100"t.__index=t function t.new(X,I)local T=setmetatable(d.new(X),t)T._serviceBag=assert(I,"\078\111 \115\101\114\118\105\099\101\066\097\103")T._ikBindersServer=T._serviceBag:GetService(Q)T._networkOwnerService=T._serviceBag:GetService(M)T._remoteEvent=Instance.new("\082\101\109\111\116\101\069\118\101\110\116")T._remoteEvent.Name=H.REMOTE_EVENT_NAME T._remoteEvent.Archivable=false T._remoteEvent.Parent=T._obj T._maid:GiveTask(T._remoteEvent)T._maid:GiveTask(T._remoteEvent.OnServerEvent:Connect(function(...)T:_handleServerEvent(...)end))T._leftGripAttachment=Instance.new("\065\116\116\097\099\104\109\101\110\116")T._leftGripAttachment.Name=A.getGripAttachmentName("\076\101\102\116")T._maid:GiveTask(T._leftGripAttachment)T._rightGripAttachment=Instance.new("\065\116\116\097\099\104\109\101\110\116")T._rightGripAttachment.Name=A.getGripAttachmentName("\082\105\103\104\116")T._maid:GiveTask(T._rightGripAttachment)T._leftGrip=v.create(T._ikBindersServer.IKLeftGrip,X)T._maid:GiveTask(T._leftGrip)T._rightGrip=v.create(T._ikBindersServer.IKRightGrip,X)T._maid:GiveTask(T._rightGrip);(T._maid:GivePromise(y.promiseRootPart(T._obj))):Then(function(X)T._leftGripAttachment.Parent=X T._rightGripAttachment.Parent=X end)T._leftHolding=Instance.new("\079\098\106\101\099\116\086\097\108\117\101")T._leftHolding.Name=A.getHoldingValueName("\076\101\102\116")T._leftHolding.Value=nil T._leftHolding.Parent=T._obj T._maid:GiveTask(T._leftHolding)T._rightHolding=Instance.new("\079\098\106\101\099\116\086\097\108\117\101")T._rightHolding.Name=A.getHoldingValueName("\082\105\103\104\116")T._rightHolding.Value=nil T._rightHolding.Parent=T._obj T._maid:GiveTask(T._rightHolding)T._maid:GiveTask(T:_setupHoldingValue(T._leftHolding,T._leftGripAttachment))T._maid:GiveTask(T:_setupHoldingValue(T._rightHolding,T._rightGripAttachment))return T end function t._getPlayer(X)return T.getPlayerFromCharacter(X._obj)end function t._setupHoldingValue(T,X,d)local Q=D.new()Q:GiveTask(X.Changed:Connect(function(X)Q._current=nil if not X then return end local v=I.getPart(X)if not v then warn("\078\111 \112\097\114\116")return end local M=D.new()local y=I.getParts(X)local H={}for X,I in pairs(y)do H[I]=I.CanCollide I.CanCollide=false end M:GiveTask(function()for X,I in pairs(y)do I.CanCollide=H[v]end end)M:GiveTask(J.hintSharedMechanism(T._obj.RootPart,v))local A=T:_getPlayer()if A then M:GiveTask(T._networkOwnerService:AddSetNetworkOwnerHandle(v,A))end local t=Instance.new("\065\116\116\097\099\104\109\101\110\116")t.Name="\080\097\114\116\072\111\108\100\105\110\103\065\116\116\097\099\104\109\101\110\116"t.CFrame=CFrame.Angles(math.pi,0,0)t.Archivable=false t.Parent=v M:GiveTask(t)local V=Instance.new("\065\108\105\103\110\080\111\115\105\116\105\111\110")V.Name="\072\111\108\100\105\110\103\065\108\105\103\110\080\111\115\105\116\105\111\110"V.Responsiveness=50 V.Attachment0=t V.Attachment1=d V.Parent=t M:GiveTask(V)local F=Instance.new("\065\108\105\103\110\079\114\105\101\110\116\097\116\105\111\110")F.Name="\072\111\108\100\105\110\103\065\108\105\103\110\079\114\105\101\110\116\097\116\105\111\110"F.Responsiveness=50 F.Attachment0=t F.Attachment1=d F.Parent=t M:GiveTask(F)Q._current=M end))return Q end function t._handleServerEvent(d,X,I,...)assert(d:_getPlayer()==X,"\066\097\100 \112\108\097\121\101\114")if I==H.REQUEST_SET_GRIP_CFRAME then d:_setGripCFrame(...)elseif I==H.REQUEST_GRIP then d:_handleGrip(...)elseif I==H.REQUEST_DROP then d:_handleDrop(...)else error(("\066\097\100 \114\101\113\117\101\115\116 \037\113"):format(tostring(I)))end end function t._getGripAttachment(I,X)local d=I._obj.RootPart if not d then return nil end local T=A.getGripAttachmentName(X)local Q=d:FindFirstChild(T)return Q end function t._handleDrop(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")local d=I:_getGripAttachment(X)if not d then return end if X=="\076\101\102\116"then I._leftHolding.Value=nil elseif X=="\082\105\103\104\116"then I._rightHolding.Value=nil else error("\066\097\100 \115\105\100\101\078\097\109\101")end end function t.GetHoldingValueObject(I,X)if X=="\076\101\102\116"then return I._leftHolding elseif X=="\082\105\103\104\116"then return I._rightHolding else error("\066\097\100 \115\105\100\101\078\097\109\101")end end function t._handleGrip(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")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 end local T=I:GetHoldingValueObject(X)local Q=A.findHoldable(d.WorldPosition)if Q then T.Value=Q else T.Value=nil end end function t._setGripCFrame(d,X,I)assert(typeof(I)=="\067\070\114\097\109\101"or I==nil,"\066\097\100 \067\070\114\097\109\101")assert(X=="\076\101\102\116"or X=="\082\105\103\104\116","\066\097\100 \115\105\100\101\078\097\109\101")if X=="\076\101\102\116"then if I then d._leftGripAttachment.CFrame=I d._leftGrip.Parent=d._leftGripAttachment else d._leftGrip.Parent=nil end elseif X=="\082\105\103\104\116"then if I then d._rightGripAttachment.CFrame=I d._rightGrip.Parent=d._rightGripAttachment else d._rightGrip.Parent=nil end else error("\066\097\100 \115\105\100\101\078\097\109\101")end end return t
--[=[
	@class VREnabledHumanoid
]=]

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

local AdorneeUtils = require("AdorneeUtils")
local BaseObject = require("BaseObject")
local CharacterUtils = require("CharacterUtils")
local IKBindersServer = require("IKBindersServer")
local IKGripUtils = require("IKGripUtils")
local Maid = require("Maid")
local NetworkOwnerService = require("NetworkOwnerService")
local NetworkRopeUtils = require("NetworkRopeUtils")
local RootPartUtils = require("RootPartUtils")
local VREnabledHumanoidConstants = require("VREnabledHumanoidConstants")
local VREnabledHumanoidUtils = require("VREnabledHumanoidUtils")

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

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

	self._serviceBag = assert(serviceBag, "No serviceBag")
	self._ikBindersServer = self._serviceBag:GetService(IKBindersServer)
	self._networkOwnerService = self._serviceBag:GetService(NetworkOwnerService)

	self._remoteEvent = Instance.new("RemoteEvent")
	self._remoteEvent.Name = VREnabledHumanoidConstants.REMOTE_EVENT_NAME
	self._remoteEvent.Archivable = false
	self._remoteEvent.Parent = self._obj
	self._maid:GiveTask(self._remoteEvent)

	self._maid:GiveTask(self._remoteEvent.OnServerEvent:Connect(function(...)
		self:_handleServerEvent(...)
	end))

	self._leftGripAttachment = Instance.new("Attachment")
	self._leftGripAttachment.Name = VREnabledHumanoidUtils.getGripAttachmentName("Left")
	self._maid:GiveTask(self._leftGripAttachment)

	self._rightGripAttachment = Instance.new("Attachment")
	self._rightGripAttachment.Name = VREnabledHumanoidUtils.getGripAttachmentName("Right")
	self._maid:GiveTask(self._rightGripAttachment)

	self._leftGrip = IKGripUtils.create(self._ikBindersServer.IKLeftGrip, humanoid)
	self._maid:GiveTask(self._leftGrip)

	self._rightGrip = IKGripUtils.create(self._ikBindersServer.IKRightGrip, humanoid)
	self._maid:GiveTask(self._rightGrip)

	self._maid:GivePromise(RootPartUtils.promiseRootPart(self._obj)):Then(function(rootPart)
		self._leftGripAttachment.Parent = rootPart
		self._rightGripAttachment.Parent = rootPart
	end)

	self._leftHolding = Instance.new("ObjectValue")
	self._leftHolding.Name = VREnabledHumanoidUtils.getHoldingValueName("Left")
	self._leftHolding.Value = nil
	self._leftHolding.Parent = self._obj
	self._maid:GiveTask(self._leftHolding)

	self._rightHolding = Instance.new("ObjectValue")
	self._rightHolding.Name = VREnabledHumanoidUtils.getHoldingValueName("Right")
	self._rightHolding.Value = nil
	self._rightHolding.Parent = self._obj
	self._maid:GiveTask(self._rightHolding)

	self._maid:GiveTask(self:_setupHoldingValue(self._leftHolding, self._leftGripAttachment))
	self._maid:GiveTask(self:_setupHoldingValue(self._rightHolding, self._rightGripAttachment))

	return self
end

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

function VREnabledHumanoid:_setupHoldingValue(holdingValue, holdingAttachment)
	local topMaid = Maid.new()

	topMaid:GiveTask(holdingValue.Changed:Connect(function(adornee)
		topMaid._current = nil

		if not adornee then
			return
		end

		local part = AdorneeUtils.getPart(adornee)
		if not part then
			warn("No part")
			return
		end

		local maid = Maid.new()

		local parts = AdorneeUtils.getParts(adornee)

		-- todo: could also create can collision constraint between all parts
		local couldCollide = {}
		for _, item in pairs(parts) do
			couldCollide[item] = item.CanCollide
			item.CanCollide = false
		end

		maid:GiveTask(function()
			for _, item in pairs(parts) do
				item.CanCollide = couldCollide[part]
			end
		end)

		-- hackily hint ownership
		maid:GiveTask(NetworkRopeUtils.hintSharedMechanism(self._obj.RootPart, part))

		local player = self:_getPlayer()
		if player then
			maid:GiveTask(self._networkOwnerService:AddSetNetworkOwnerHandle(part, player))
		end

		local attachment = Instance.new("Attachment")
		attachment.Name = "PartHoldingAttachment"
		attachment.CFrame = CFrame.Angles(math.pi, 0, 0)
		attachment.Archivable = false
		attachment.Parent = part
		maid:GiveTask(attachment)

		local alignPosition = Instance.new("AlignPosition")
		alignPosition.Name = "HoldingAlignPosition"
		alignPosition.Responsiveness = 50
		alignPosition.Attachment0 = attachment
		alignPosition.Attachment1 = holdingAttachment
		alignPosition.Parent = attachment
		maid:GiveTask(alignPosition)

		local alignOrientation = Instance.new("AlignOrientation")
		alignOrientation.Name = "HoldingAlignOrientation"
		alignOrientation.Responsiveness = 50
		alignOrientation.Attachment0 = attachment
		alignOrientation.Attachment1 = holdingAttachment
		alignOrientation.Parent = attachment
		maid:GiveTask(alignOrientation)

		topMaid._current = maid
	end))

	return topMaid
end
function VREnabledHumanoid:_handleServerEvent(player, request, ...)
	assert(self:_getPlayer() == player, "Bad player")

	if request == VREnabledHumanoidConstants.REQUEST_SET_GRIP_CFRAME then
		self:_setGripCFrame(...)
	elseif request == VREnabledHumanoidConstants.REQUEST_GRIP then
		self:_handleGrip(...)
	elseif request == VREnabledHumanoidConstants.REQUEST_DROP then
		self:_handleDrop(...)
	else
		error(("Bad request %q"):format(tostring(request)))
	end
end

function VREnabledHumanoid:_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 VREnabledHumanoid:_handleDrop(sideName)
	assert(sideName == "Left" or sideName == "Right", "Bad sideName")

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

	if sideName == "Left" then
		self._leftHolding.Value = nil
	elseif sideName == "Right" then
		self._rightHolding.Value = nil
	else
		error("Bad sideName")
	end
end

function VREnabledHumanoid:GetHoldingValueObject(sideName)
	if sideName == "Left" then
		return self._leftHolding
	elseif sideName == "Right" then
		return self._rightHolding
	else
		error("Bad sideName")
	end
end


function VREnabledHumanoid:_handleGrip(sideName)
	assert(sideName == "Left" or sideName == "Right", "Bad sideName")

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

	local object = self:GetHoldingValueObject(sideName)

	local holdable = VREnabledHumanoidUtils.findHoldable(gripAttachment.WorldPosition)
	if holdable then
		object.Value = holdable
	else
		-- Stop holding
		object.Value = nil
	end
end

function VREnabledHumanoid:_setGripCFrame(sideName, relCFrame)
	assert(typeof(relCFrame) == "CFrame" or relCFrame == nil, "Bad CFrame")
	assert(sideName == "Left" or sideName == "Right", "Bad sideName")

	if sideName == "Left" then
		if relCFrame  then
			self._leftGripAttachment.CFrame = relCFrame
			self._leftGrip.Parent = self._leftGripAttachment
		else
			self._leftGrip.Parent = nil
		end
	elseif sideName == "Right" then
		if relCFrame  then
			self._rightGripAttachment.CFrame = relCFrame
			self._rightGrip.Parent = self._rightGripAttachment
		else
			self._rightGrip.Parent = nil
		end
	else
		error("Bad sideName")
	end
end

return VREnabledHumanoid