Advertisement
kalebxo

vr hands ;-;

Sep 9th, 2021
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.61 KB | None | 0 0
  1. local cam = workspace.Camera
  2. local p
  3. local headObject
  4. local events = {}
  5.  
  6. local controls = {
  7. [Enum.UserInputType.MouseButton1] = {"move", "leftHand"},
  8. [Enum.UserInputType.MouseMovement] = {"updateTarget"}, -- do not change
  9. [Enum.UserInputType.MouseWheel] = {"adjustOffset"},
  10. [Enum.UserInputType.MouseButton2] = {"move", "rightHand"},
  11. [Enum.KeyCode.W] = {"move", "head", Vector3.new(0, 1, 0)},
  12. [Enum.KeyCode.A] = {"move", "head", Vector3.new(-1, 0, 0)},
  13. [Enum.KeyCode.S] = {"move", "head", Vector3.new(0, -1, 0)},
  14. [Enum.KeyCode.D] = {"move", "head", Vector3.new(1, 0, 0)},
  15. [Enum.KeyCode.Q] = {"move", "head", Vector3.new(0, 0, -1)},
  16. [Enum.KeyCode.E] = {"move", "head", Vector3.new(0, 0, 1)},
  17. [Enum.KeyCode.LeftShift] = {"gesture", "Fist"},
  18. [Enum.KeyCode.LeftControl] = {"gesture", "Index"},
  19. [Enum.KeyCode.LeftAlt] = {"gesture", "Thumb"},
  20. [Enum.KeyCode.Z] = {"toggle", "canOffset"},
  21. [Enum.KeyCode.R] = {"toggle", "rotationManager"},
  22. [Enum.KeyCode.Tab] = {"selectAxis", "rotationManager"},
  23. [Enum.KeyCode.Left] = {"updateAxisMover", "rotationManager", -1},
  24. [Enum.KeyCode.Right] = {"updateAxisMover", "rotationManager", 1}
  25. }
  26.  
  27. local services = {}
  28.  
  29. setmetatable(services, {
  30. __index = function(t, k)
  31. services[k] = rawget(services, k) or game:GetService(k)
  32. return services[k]
  33. end
  34. })
  35.  
  36. local function angleBetween(vecx, vecy)
  37. return math.acos(vecx:Dot(vecy))
  38. end
  39.  
  40. local hand = {}
  41. hand.__index = hand
  42.  
  43. function hand:gesture(gestureName, keyState)
  44. if keyState ~= 1 then
  45. return
  46. end
  47.  
  48. headObject.realHeadset[self.id .. gestureName] = 1 - headObject.realHeadset[self.id .. gestureName]
  49. end
  50.  
  51. function hand:getMouseRay()
  52. local mousePos = services.UserInputService:GetMouseLocation()
  53. return CFrame.new(cam:ViewportPointToRay(mousePos.x, mousePos.y).Direction * (1.5 + headObject.handOffset))
  54. end
  55.  
  56. function hand:calculateEndRotation()
  57. return CFrame.Angles(cam.CFrame:ToEulerAnglesXYZ()) * CFrame.Angles(self.rotation[1] * (math.pi/6), self.rotation[2] * (math.pi/6), self.rotation[3] * (math.pi/6))
  58. end
  59.  
  60. function hand:updateTarget()
  61.  
  62. local camLook = (cam.CFrame.lookVector * Vector3.new(1,0,1)).unit
  63.  
  64. local theta = angleBetween(Vector3.new(-1, 0, 0), camLook)
  65. theta = camLook.z > 0 and (2 * math.pi) - theta or theta
  66.  
  67. local relativeAngle = (self.id == "l" and -headObject.handAngle or headObject.handAngle)
  68. local startPosition = CFrame.new(-math.cos(theta + relativeAngle), -0.5, -math.sin(theta + relativeAngle)) + (camLook * headObject.handOffset)
  69.  
  70. self.targetPosition = startPosition:Lerp(self:getMouseRay(), self.alpha) * self:calculateEndRotation()
  71.  
  72. self.replicatePosition:Fire()
  73. end
  74.  
  75. function hand:beginMove(minAlpha, maxAlpha)
  76. local distAlpha = (maxAlpha - minAlpha) / 2
  77.  
  78. self.moving = true
  79. repeat
  80. services.RunService.RenderStepped:wait()
  81. self:updateTarget()
  82. self.alpha += self.alphaMultiplier
  83. until math.abs(self.alpha - minAlpha) < 0.05 or math.abs(maxAlpha - self.alpha) < 0.05 or self.alpha ~= self.alpha
  84.  
  85. if self.alpha ~= self.alpha then
  86. self.alpha = 0
  87. end
  88.  
  89. self.moving = false
  90. end
  91.  
  92. function hand:move(keyState)
  93.  
  94. if headObject.rotationManager.active then
  95. if self.id == "l" then
  96. headObject.rotationManager.held = keyState == 1
  97.  
  98. headObject.rotationManager.selectedAxis = 0
  99. end
  100. return
  101. end
  102.  
  103. self.alphaMultiplier = keyState == 1 and 0.05 or -0.05
  104.  
  105. if not self.moving and not (keyState == 1 and self.alpha >= 1) then
  106. if keyState == 1 then
  107. headObject.recentHand = self
  108. end
  109.  
  110. self:beginMove(0, 1)
  111. end
  112. end
  113.  
  114. function hand:new(direction, realHand)
  115. local newHand = setmetatable({direction = direction, realHand = realHand}, hand)
  116. newHand.alpha = 0
  117. newHand.alphaMultiplier = 0.05
  118. newHand.id = direction and "r" or "l"
  119. newHand.targetPosition = CFrame.new()
  120. newHand.moving = false
  121. newHand.rotation = {0, 0, 0}
  122. newHand.replicatePosition = Instance.new("BindableEvent")
  123. newHand.replicatePosition.Event:connect(function()
  124. events.UserCFrameChanged:Fire(newHand.direction and Enum.UserCFrame.RightHand or Enum.UserCFrame.LeftHand, newHand.targetPosition)
  125. end)
  126.  
  127. return newHand
  128. end
  129.  
  130. local head = {}
  131. head.__index = head
  132.  
  133. function head:handleInput(input, keyState)
  134. local bind = controls[input.KeyCode] or controls[input.UserInputType]
  135.  
  136. if bind then
  137. if bind[1] == "updateTarget" and not self.rotationManager.active then
  138. self.leftHand:updateTarget()
  139. self.rightHand:updateTarget()
  140. elseif bind[2] and type(self[bind[2]]) == "table" then
  141. self[bind[2]][bind[1]](self[bind[2]], keyState, bind[3])
  142. elseif bind[3] then
  143. self[bind[1]](self, bind[3], keyState)
  144. elseif bind[2] and self.recentHand[bind[1]] then
  145. self.recentHand[bind[1]](self.recentHand, bind[2], keyState)
  146. else
  147. self[bind[1]](self, bind[2], keyState)
  148. end
  149. end
  150. end
  151.  
  152. function head:adjustOffset(_, keyState)
  153. if self.canOffset then
  154. self.handOffset += keyState * 0.04
  155. self.leftHand:updateTarget()
  156. self.rightHand:updateTarget()
  157. end
  158. end
  159.  
  160. function head:move(vec, keyState)
  161. if vec.z ~= 0 then
  162. self.realHeadset.Stick2 = math.clamp(self.realHeadset.Stick2 + (vec.z * keyState), -1, 1)
  163. else
  164. self.realHeadset.StickPosition += Vector3.new(vec.x, vec.y, 0) * keyState
  165. end
  166. end
  167.  
  168. function head:freezeCam(b)
  169. local dist = (self.realHeadset.Head.PrimaryPart.Position - cam.CFrame.p).magnitude
  170.  
  171. p.CameraMinZoomDistance = b and dist or 0.5
  172. p.CameraMaxZoomDistance = b and dist or 128
  173. end
  174.  
  175. function head:toggle(stat, keyState)
  176. if keyState ~= 1 then
  177. return
  178. end
  179.  
  180. self[stat] = not self[stat]
  181.  
  182. if stat == "canOffset" then
  183. self:freezeCam(self[stat])
  184. end
  185. end
  186.  
  187. local rotation = {}
  188. rotation.__index = rotation
  189.  
  190. function rotation:new()
  191. local newRotation = setmetatable({}, rotation)
  192.  
  193. newRotation.rotationLookup = {{}, {}, {}}
  194. newRotation.lineLookup = {{}, {}, {}}
  195. newRotation.active = false
  196. newRotation.held = false
  197. newRotation.selectedAxis = 0
  198. newRotation.angleLookup = {1, 1, 1}
  199.  
  200. for i=1,3 do
  201. local ref = {}
  202. ref[i] = function() return 0 end
  203. ref[i + 1 > 3 and ((i + 1) % 4) + 1 or i + 1] = math.cos
  204. ref[i + 2 > 3 and ((i + 2) % 4) + 1 or i + 2] = math.sin
  205.  
  206. local color = Color3.fromRGB(i == 1 and 255 or 0, i == 2 and 255 or 0, i == 3 and 255 or 0)
  207.  
  208. for j=1,13 do
  209. if j < 13 then
  210. local step = math.pi * (j/6)
  211. newRotation.rotationLookup[i][j] = Vector3.new(ref[1](step), ref[2](step), ref[3](step))
  212. end
  213.  
  214. local line = Drawing.new("Line")
  215. line.Visible = true
  216. line.Thickness = 5
  217. line.Color = color
  218. newRotation.lineLookup[i][j] = line
  219. end
  220.  
  221. local circle = Drawing.new("Circle")
  222. circle.Visible = true
  223. circle.Color = color
  224. circle.Filled = true
  225. circle.Radius = 10
  226. circle.Position = Vector2.new(-2000, -2000)
  227. newRotation.lineLookup[i][14] = circle
  228.  
  229. local text = Drawing.new("Text")
  230. text.Visible = true
  231. text.Font = Drawing.Fonts.System
  232. text.Size = 18
  233. text.Color = Color3.new():lerp(color, 0.3)
  234. text.Outline = false
  235. newRotation.lineLookup[i][15] = text
  236. end
  237.  
  238. return newRotation
  239. end
  240.  
  241. function rotation:selectAxis(keyState)
  242. self.tabActivated = keyState == 1
  243. if self.tabActivated then
  244. self.selectedAxis = math.clamp((self.selectedAxis + 1) % 4, 1, 3)
  245. end
  246. end
  247.  
  248. function rotation:toggle(keyState)
  249. if keyState == 1 and headObject.recentHand.alpha < 0.05 and not self.held then
  250. self.active = not self.active
  251.  
  252. if not self.active then
  253. self:updateAxes(0)
  254. self.selectedAxis = 0
  255. self.held = false
  256. headObject.recentHand:updateTarget()
  257. end
  258. end
  259. end
  260.  
  261. function rotation:updateAxes(visibleOverride)
  262. local basePos = headObject.recentHand.realHand.Base.Position
  263. local basePoint = cam:WorldToViewportPoint(basePos)
  264.  
  265. for i=1,3 do
  266. for j=1,12 do
  267. local vec, visible = cam:WorldToViewportPoint(basePos + (self.rotationLookup[i][j] * 10))
  268. local vec2, visible2 = cam:WorldToViewportPoint(basePos + ((self.rotationLookup[i][j + 1] or self.rotationLookup[i][1]) * 10))
  269.  
  270. local line = self.lineLookup[i][j]
  271.  
  272. line.Transparency = visibleOverride or ((visible and visible2) and 1 or 0)
  273. line.From = Vector2.new(vec.x, vec.y)
  274. line.To = Vector2.new(vec2.x, vec2.y)
  275. end
  276. local axisRotation = headObject.recentHand.rotation[i]
  277.  
  278. local axisMover = self.lineLookup[i][13]
  279. local axisCircle = self.lineLookup[i][14]
  280. local axisText = self.lineLookup[i][15]
  281.  
  282. axisMover.From = Vector2.new(basePoint.x, basePoint.y)
  283. axisMover.To = self.lineLookup[i][math.clamp(axisRotation < 1 and 12 or axisRotation, 1, 12)].From -- sorry, lazy
  284. axisMover.Transparency = visibleOverride or 1
  285.  
  286. axisCircle.Position = self.lineLookup[i][13].To
  287. axisCircle.Transparency = visibleOverride or 1
  288.  
  289.  
  290.  
  291. axisText.Position = self.lineLookup[2][3].From + axisText.TextBounds
  292. axisText.Text = string.char(87 + self.selectedAxis) .. ": " .. math.deg(axisRotation * (math.pi / 6))
  293. axisText.Transparency = visibleOverride or ((self.held or self.tabActivated) and self.selectedAxis == i and 1 or 0)
  294.  
  295. local mousePos = services.UserInputService:GetMouseLocation()
  296. if self.held and (self.lineLookup[i][14].Position - mousePos).magnitude < 10 and self.selectedAxis == 0 then
  297. self.selectedAxis = i
  298. end
  299. end
  300. end
  301.  
  302. function rotation:updateAxisMover(keyState, direction)
  303. if keyState and direction then
  304. if self.tabActivated and keyState == 1 then
  305. headObject.recentHand.rotation[self.selectedAxis] = (headObject.recentHand.rotation[self.selectedAxis] + direction) % 12
  306. headObject.recentHand:updateTarget()
  307. end
  308. return
  309. end
  310.  
  311. if self.selectedAxis ~= 0 then
  312. local mousePos = services.UserInputService:GetMouseLocation()
  313.  
  314. local circlePos = self.lineLookup[self.selectedAxis][12].From
  315.  
  316. local handPos = self.lineLookup[self.selectedAxis][13].From
  317.  
  318. local mouseDir = self.selectedAxis == 1 and headObject.recentHand.id == "r" and (Vector2.new(-mousePos.x + (handPos.x * 2), mousePos.y) - handPos).unit or (mousePos - handPos).unit
  319. -- mouse angle relating to the red circle is reflected on the right hand, so i "re-reflect" it. bad practice
  320.  
  321. local circleDir = (circlePos - handPos).unit
  322.  
  323. local rotationTheta = angleBetween(mouseDir, circleDir)
  324.  
  325. local direction = mouseDir:Cross(circleDir)
  326.  
  327. rotationTheta = direction > 0 and rotationTheta or (2 * math.pi) - rotationTheta
  328.  
  329. if rotationTheta == rotationTheta then
  330. headObject.recentHand.rotation[self.selectedAxis] = math.floor(6 * rotationTheta / math.pi)
  331.  
  332. local hand = headObject.recentHand
  333.  
  334. hand.targetPosition *= CFrame.Angles(hand.targetPosition:inverse():ToEulerAnglesXYZ()) * hand:calculateEndRotation()
  335. hand.replicatePosition:Fire()
  336. end
  337. end
  338. end
  339.  
  340. function head:new(realHeadset)
  341. local newHead = setmetatable({realHeadset = realHeadset}, head)
  342.  
  343. newHead.leftHand = hand:new(false, realHeadset.lHand)
  344. newHead.rightHand = hand:new(true, realHeadset.rHand)
  345. newHead.canOffset = false
  346. newHead.recentHand = newHead.leftHand
  347. newHead.handOffset = 0
  348. newHead.handAngle = math.pi / 4
  349.  
  350. newHead.rotationManager = rotation:new()
  351.  
  352. newHead.chatRemote = debug.getupvalue(realHeadset.ButtonPressed, 3)
  353.  
  354. cam:GetPropertyChangedSignal("CameraSubject"):connect(function()
  355. if cam.CameraSubject ~= headObject.realHeadset.Head then
  356. cam.CameraType = Enum.CameraType.Custom
  357. end
  358. end)
  359.  
  360. services.UserInputService.WindowFocused:connect(function()
  361. newHead.realHeadset.StickPosition = Vector3.new(0, 0, 0)
  362. newHead.realHeadset.Stick2 = 0
  363. end)
  364.  
  365. return newHead
  366. end
  367.  
  368. local ind, nc, nind
  369.  
  370. local realVrService = game:GetService("VRService")
  371.  
  372. local fakeVrService = setmetatable({
  373. VREnabled = true,
  374. SetTouchpadMode = function()
  375. end,
  376. RecenterUserHeadCFrame = function()
  377. end,
  378. GetUserCFrameEnabled = function(cf)
  379. return true
  380. end,
  381. GetUserCFrame = function(cf)
  382. return CFrame.new()
  383. end
  384.  
  385. }, {
  386. __index = function(t, k)
  387. local real = ind(realVrService, k)
  388. if typeof(real) == "RBXScriptSignal" then
  389. events[k] = events[k] or {
  390. Name = k,
  391. Connect = function(t, f)
  392. t.Function = f
  393.  
  394. if t.Name == "UserCFrameChanged" then
  395. headObject = head:new(debug.getupvalue(t.Function, 1))
  396.  
  397. services.UserInputService.InputBegan:connect(function(i)
  398. headObject:handleInput(i, 1)
  399. end)
  400.  
  401. services.UserInputService.InputChanged:connect(function(i)
  402. headObject:handleInput(i, i.UserInputType == Enum.UserInputType.MouseWheel and i.Position.z or 0)
  403. end)
  404.  
  405. services.UserInputService.InputEnded:connect(function(i)
  406. headObject:handleInput(i, -1)
  407. end)
  408. end
  409.  
  410. end,
  411. Fire = function(t, ...)
  412. return t.Function(...)
  413. end
  414. }
  415.  
  416. return events[k]
  417. end
  418.  
  419. return real
  420. end,
  421. __call = function(t, method, vr, ...)
  422. return t[method](...)
  423. end
  424. })
  425.  
  426. ind = hookmetamethod(game, "__index", function(...)
  427. local t, k = ...
  428.  
  429. local scr = getcallingscript()
  430.  
  431. if t == realVrService and not (scr and ind(scr, "Name") == "CameraModule") then
  432. return fakeVrService[k]
  433. end
  434.  
  435. return ind(...)
  436. end)
  437.  
  438. nc = hookmetamethod(game, "__namecall", function(...)
  439. local t = ...
  440.  
  441. if t == realVrService then
  442. local method = getnamecallmethod()
  443. return fakeVrService(method, ...)
  444. elseif t == game.GetService(game, "StarterGui") and game.IsLoaded(game) then
  445. return
  446. end
  447.  
  448. return nc(...)
  449. end)
  450.  
  451. nind = hookmetamethod(game, "__newindex", function(...)
  452. local t, k, v = ...
  453.  
  454. local scr = getcallingscript()
  455.  
  456. if t == cam and headObject then
  457. if k == "CFrame" and events.UserCFrameChanged then
  458.  
  459. events.UserCFrameChanged:Fire(Enum.UserCFrame.Head, CFrame.Angles(cam.CFrame:ToEulerAnglesXYZ()))
  460.  
  461. if headObject.rotationManager.active then
  462.  
  463. headObject.rotationManager:updateAxes()
  464.  
  465. if headObject.rotationManager.held then
  466. headObject.rotationManager:updateAxisMover()
  467. end
  468. end
  469.  
  470. if headObject.rotationManager.tabActivated and services.UserInputService:IsKeyDown(Enum.KeyCode.Left) or services.UserInputService:IsKeyDown(Enum.KeyCode.Right) then -- prevent controls from messing with camera
  471. return
  472. end
  473. elseif k == "CameraType" then
  474. nind(t, k, Enum.CameraType.Custom)
  475. nind(t, "CameraSubject", headObject.realHeadset.Head)
  476. headObject.leftHand:updateTarget()
  477. headObject.rightHand:updateTarget()
  478. end
  479. if not (scr and scr.Name == "CameraModule") and not checkcaller() then
  480. return
  481. end
  482. end
  483.  
  484. nind(t, k, v)
  485. end)
  486.  
  487. p = services.Players.LocalPlayer or (function()
  488. services.Players:GetPropertyChangedSignal("LocalPlayer"):wait() -- this doesnt return anything for some reason??
  489. return services.Players.LocalPlayer
  490. end)()
  491.  
  492. p.Chatted:connect(function(c)
  493. services.ReplicatedStorage.COM.Chat:FireServer("Chat", c)
  494. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement