local ScriptENV,NewENV do -- Basically EZConvert, but better :)
--Be warned! Scripts may or may not have a noticable performance issue depending on the senario (unoptimized expensive loops etc)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local _ENV = getfenv()
local Player = _ENV.owner or Players:GetPlayerFromCharacter(script.Parent) or (script.Parent.Parent:IsA("Player") and script.Parent.Parent)
if not Player then
error("Cannot run script : must be ran in a sandbox, inside a character, or inside playergui/backpack")
end
local Remote = Player:FindFirstChild("SyncInput")
if not Remote then
Remote = Instance.new("UnreliableRemoteEvent")
Remote.Name = "SyncInput"
Remote.Parent = Player
end
local Signal = (function() -- GoodSignal module by stravant
local freeRunnerThread = nil
local function acquireRunnerThreadAndCallEventHandler(fn, ...)
local acquiredRunnerThread = freeRunnerThread
freeRunnerThread = nil
fn(...)
freeRunnerThread = acquiredRunnerThread
end
local function runEventHandlerInFreeThread()
while true do
acquireRunnerThreadAndCallEventHandler(coroutine.yield())
end
end
local Connection = {}
Connection.__index = Connection
function Connection.new(signal, fn)
return setmetatable({
_connected = true,
_signal = signal,
_fn = fn,
_next = false,
}, Connection)
end
function Connection:Disconnect()
self._connected = false
if self._signal._handlerListHead == self then
self._signal._handlerListHead = self._next
else
local prev = self._signal._handlerListHead
while prev and prev._next ~= self do
prev = prev._next
end
if prev then
prev._next = self._next
end
end
end
Connection.disconnect = Connection.Disconnect
setmetatable(Connection, {
__index = function(tb, key)
error(("Attempt to get Connection::%s (not a valid member)"):format(tostring(key)), 2)
end,
__newindex = function(tb, key, value)
error(("Attempt to set Connection::%s (not a valid member)"):format(tostring(key)), 2)
end
})
local Signal = {}
Signal.__index = Signal
function Signal.new()
return setmetatable({
_handlerListHead = false,
}, Signal)
end
function Signal:Connect(fn)
local connection = Connection.new(self, fn)
if self._handlerListHead then
connection._next = self._handlerListHead
self._handlerListHead = connection
else
self._handlerListHead = connection
end
return connection
end
function Signal:DisconnectAll()
self._handlerListHead = false
end
function Signal:Fire(...)
local item = self._handlerListHead
while item do
if item._connected then
if not freeRunnerThread then
freeRunnerThread = coroutine.create(runEventHandlerInFreeThread)
-- Get the freeRunnerThread to the first yield
coroutine.resume(freeRunnerThread)
end
task.spawn(freeRunnerThread, item._fn, ...)
end
item = item._next
end
end
function Signal:Wait()
local waitingCoroutine = coroutine.running()
local cn;
cn = self:Connect(function(...)
cn:Disconnect()
task.spawn(waitingCoroutine, ...)
end)
return coroutine.yield()
end
function Signal:Once(fn)
local cn;
cn = self:Connect(function(...)
if cn._connected then
cn:Disconnect()
end
fn(...)
end)
return cn
end
Signal.wait = Signal.Wait
Signal.fire = Signal.Fire
Signal.connect = Signal.Connect
-- Signal.once doesn't exist in luau, so we don't add it here.
setmetatable(Signal, {
__index = function(tb, key)
error(("Attempt to get Signal::%s (not a valid member)"):format(tostring(key)), 2)
end,
__newindex = function(tb, key, value)
error(("Attempt to set Signal::%s (not a valid member)"):format(tostring(key)), 2)
end
})
return Signal
end)()
local NLS = _ENV.NLS
if NLS then -- If NLS doesn't exist, a local script should be parented to this script (with the same code).
NLS([[local Player = game:GetService("Players").LocalPlayer
local Remote = Player:WaitForChild("SyncInput")
local UserInputService = game:GetService("UserInputService")
if not Remote then
error("Cannot run script: Unable to find remote - Client failed to launch")
end
local UpdateInterval = 1 / 40
local Mouse = Player:GetMouse()
Mouse.TargetFilter = Player.Character
local InputObjectProperties = {
"Position",
"KeyCode",
"UserInputType",
"UserInputState",
"Delta",
}
local MouseProperties = {
"Hit",
"Icon",
"Origin",
"Target",
"TargetFilter",
"TargetSurface",
"UnitRay",
"ViewSizeX",
"ViewSizeY",
"X",
"Y",
"hit",
"target",
}
UserInputService.InputBegan:Connect(function(Input, GP)
local Package = {}
for i = 1, #InputObjectProperties do
local Name = InputObjectProperties[i]
Package[Name] = Input[Name]
end
Remote:FireServer(1, Package, GP)
end)
UserInputService.InputChanged:Connect(function(Input, GP)
local Package = {}
for i = 1, #InputObjectProperties do
local Name = InputObjectProperties[i]
Package[Name] = Input[Name]
end
Remote:FireServer(2, Package, GP)
end)
UserInputService.InputEnded:Connect(function(Input, GP)
local Package = {}
for i = 1, #InputObjectProperties do
local Name = InputObjectProperties[i]
Package[Name] = Input[Name]
end
Remote:FireServer(0, Package, GP)
end)
local ReplicateList = {}
Remote.OnClientEvent:Connect(function(Type, Package)
if Type == 0 then
local Object = Package[1]
local Properties = Package[2]
ReplicateList[Object] = Properties
for i = 1, #Properties do
local Name = Properties[i]
Object:GetPropertyChangedSignal(Name):Connect(function()
if table.find(ReplicateList, Name) then return end
table.insert(ReplicateList[Object], Object[Name])
end)
end
end
end)
function Update()
local MousePackage = {}
for i = 1, #MouseProperties do
local Name = MouseProperties[i]
MousePackage[Name] = Mouse[Name]
end
Remote:FireServer(3, {
Mouse = MousePackage,
Replicate = ReplicateList
})
end
Update()
while true do
task.wait(UpdateInterval)
Update()
end]], Player.PlayerGui)
end
task.wait(0.5)
local Mouse = {}
local UserInputService = {}
Mouse.KeyDown = Signal.new()
Mouse.KeyUp = Signal.new()
Mouse.Button1Down = Signal.new()
Mouse.Button1Up = Signal.new()
Mouse.Button2Down = Signal.new()
Mouse.Button2Up = Signal.new()
--TODO: Implement these
Mouse.Move = Signal.new()
Mouse.Idle = Signal.new()
-- TODO: More UserInputService properties.
UserInputService.InputBegan = Signal.new()
UserInputService.InputEnded = Signal.new()
UserInputService.InputChanged = Signal.new()
UserInputService.InputBegan:Connect(function(Input, GP)
if not GP then
if Input.KeyCode ~= Enum.KeyCode.Unknown then
Mouse.KeyDown:Fire(utf8.char(Input.KeyCode.Value))
end
if Input.UserInputType == Enum.UserInputType.MouseButton1 then
Mouse.Button1Down:Fire()
end
if Input.UserInputType == Enum.UserInputType.MouseButton2 then
Mouse.Button2Down:Fire()
end
end
end)
UserInputService.InputEnded:Connect(function(Input, GP)
if not GP then
if Input.KeyCode ~= Enum.KeyCode.Unknown then
Mouse.KeyUp:Fire(utf8.char(Input.KeyCode.Value))
end
if Input.UserInputType == Enum.UserInputType.MouseButton1 then
Mouse.Button1Up:Fire()
end
if Input.UserInputType == Enum.UserInputType.MouseButton2 then
Mouse.Button2Up:Fire()
end
end
end)
local MouseProperties = {
["Hit"] = CFrame.new(),
["Icon"] = "",
["Origin"] = CFrame.new(),
["Target"] = nil,
["TargetFilter"] = nil,
["TargetSurface"] = nil,
["UnitRay"] = nil,
["ViewSizeX"] = 0,
["ViewSizeY"] = 0,
["X"] = 0,
["Y"] = 0,
["hit"] = CFrame.new(),
["target"] = nil
}
for Name, Connection in Mouse do
Mouse[Name:sub(1,1)..Name:sub(2)] = Connection
end
for Name, Connection in UserInputService do
Mouse[Name:sub(1,1)..Name:sub(2)] = Connection
end
local InputTypes = {
[0] = "InputEnded",
[1] = "InputBegan",
[2] = "InputChanged",
-- Number 3 is specially handled
}
local ReplicatedProperties = {
}
Remote.OnServerEvent:Connect(function(Sender, Type, Package, ...)
local UISType = InputTypes[Type]
if UISType then
UserInputService[UISType]:Fire(Package, ...)
end
if Type == 3 then -- Mouse and replication stuff
for k,v in pairs(Package.Mouse) do
MouseProperties[k] = v
end
--MouseProperties = Package.Mouse
for k,v in pairs(Package.Replicate) do
ReplicatedProperties[k] = v
end
--ReplicatedProperties = Package.Replicate
end
end)
function Unsandbox(Value)
if Value and typeof(Value) == "table" then
local Real = Value._Real
if Real then
return Real
end
end
end
function GetReplicated(Object, Property)
if not ReplicatedProperties[Object] then
local Replicate = {
[Property] = 0
}
ReplicatedProperties[Object] = Replicate
Remote:FireClient(Player, 0, {Object, Replicate})
end
local ReplicatedProperty = ReplicatedProperties[Object]
if not ReplicatedProperty[Property] then
ReplicatedProperties[Object][Property] = Object[Property]
end
return ReplicatedProperty[Property]
end
function Sandbox(Object, Custom)
if Object == nil then
return
end
if Unsandbox(Object) then
return Object
end
return setmetatable({}, {
__index = function(self, Property)
if Property == "_Real" then
return Object
end
local CustomValue = (Custom and Custom[Property])
if CustomValue then
return CustomValue
end
local Value = Object[Property]
local Unsandboxed = Unsandbox(Value)
if Property == "PlaybackLoudness" or Property == "playbackLoudness" then
return GetReplicated(Object, "PlaybackLoudness")
end
if Value and typeof(Value) == "function" then
return function(_, ...)
local UnsandboxedArgs = {...}
for i = 1, #UnsandboxedArgs do
UnsandboxedArgs[i] = Unsandbox(UnsandboxedArgs[i]) or UnsandboxedArgs[i]
end
local Result = Value(Object, table.unpack(UnsandboxedArgs))
if Result then
if typeof(Result) == "Instance" then
Result = Sandbox(Result)
end
if typeof(Result) == "table" then
for Index, Object in Result do
if typeof(Object) == "Instance" then
Result[Index] = Sandbox(Object)
end
end
end
end
return Result
end
end
if Value and typeof(Value) == "Instance" then
Value = Sandbox(Value)
end
return Value
end,
__newindex = function(self, Property, Value)
Object[Property] = Unsandbox(Value) or Value
end,
__metatable = "The metatable is locked",
__type = "Instance",
__tostring = function()
return Object.Name
end,
})
end
NewENV = {}
NewENV.typeof = function(Object)
local Unsandboxed = Unsandbox(Object)
return (Unsandboxed and typeof(Unsandboxed) or typeof(Object))
end
NewENV.type = function(Object)
local Unsandboxed = Unsandbox(Object)
return (Unsandboxed and type(Unsandboxed) or type(Object))
end
local FakeMouse = setmetatable({}, {
__index = function(self, Property)
return Mouse[Property] or MouseProperties[Property]
end,
__newindex = function(self, Property, Value)
error("Cant set property of \"Mouse\"", 2)
end,
__metatable = "The metatable is locked",
__type = "Instance",
__tostring = function()
return "Mouse"
end,
})
function GetMouse()
return FakeMouse
end
local FakePlayer = Sandbox(Player, {
GetMouse = GetMouse,
getMouse = GetMouse
})
local FakePlayers = Sandbox(Players, {
LocalPlayer = FakePlayer,
localPlayer = FakePlayer
})
local Services = {
Players = FakePlayers,
players = FakePlayers,
UserInputService = UserInputService,
userInputService = UserInputService,
}
function GetService(_, Name)
return Sandbox(Services[Name] or game:GetService(Name))
end
NewENV.script = Sandbox(script, {
Parent = Player.Character,
parent = Player.Character
})
NewENV.game = Sandbox(game, {
table.unpack(Services),
GetService = GetService,
getService = GetService,
service = GetService,
})
NewENV.Instance = {
new = function(Class, Parent)
return Sandbox(Instance.new(Class, Unsandbox(Parent) or Parent))
end,
}
NewENV.owner = Player
NewENV.mouse = FakeMouse
NewENV.LoadLibrary = function(Library)
if Library == "RbxUtility" then
return {
Create = function(Class)
local Object = NewENV.Instance.new(Class)
return function(Properties)
for Name, Value in Properties do
Object[Name] = Value
end
return Object
end
end
}
end
end
ScriptENV = setmetatable({}, {
__index = function(self, Index)
return NewENV[Index] or _ENV[Index]
end,
__newindex = function(self, Index, Value)
rawset(ScriptENV, Index, Value)
end,
__metatable = "The metatable is locked"
})
end
setfenv(1, ScriptENV)
local STRENGTH = 40
local BRING_SPEED = 10
local UPDATE_RATE = 1 / 60
local VIEWMODEL_LERP_SPEED = 20
local VIEWMODEL_OFFSET = Vector3.xAxis * 0.45 + Vector3.yAxis * -0.8 + Vector3.zAxis * -2.2
local RIGHT_ARM_CFRAME = CFrame.new(0,0.2,1.2) * CFrame.Angles(math.rad(90),0,0)
local LEFT_ARM_CFRAME = CFrame.new(-0.7,-0.3,1.4) * CFrame.Angles(0,math.rad(-30),0) * CFrame.Angles(math.rad(110),0,0)
local _ENV = getfenv()
local NLS = _ENV.NLS
local LoadAssets = _ENV.LoadAssets
local player = _ENV.owner :: Player
local character = player.Character or player.CharacterAdded:Wait()
local mouse = _ENV.mouse or player:GetMouse()
local isGrabbingObject = false
local grabbedObject: BasePart = nil
local grabbedObjectDistance: number = 10
local bringCloser = false
local pushFurther = false
local cameraCFrame = CFrame.new()
local cameraRemote = player:FindFirstChild("CameraRemote") :: UnreliableRemoteEvent
if not cameraRemote then
cameraRemote = Instance.new("UnreliableRemoteEvent")
cameraRemote.Name = "CameraRemote"
cameraRemote.Parent = player
end
local humanoid = character:FindFirstChildWhichIsA("Humanoid") or character:WaitForChild("Humanoid") :: Humanoid
assert(humanoid.RootPart,"No Humanoid, go away.")
assert(humanoid.RigType == Enum.HumanoidRigType.R6,"You ain't R6, go away.")
local function CreateSound(name: string,id: number,volume: number,speed: number,looped: boolean,parent: Instance): Sound
local sound = Instance.new("Sound")
sound.Name = name
sound.SoundId = "rbxassetid://" .. id
sound.Volume = volume
sound.PlaybackSpeed = speed
sound.Looped = looped
sound.Parent = parent
return sound
end
local function PlaySound(sound: Sound)
if sound.IsPlaying then return end
sound:Play()
end
local function StopSound(sound: Sound)
if not sound.IsPlaying then return end
sound:Stop()
end
local function WeldFromMotor6D(motor: Motor6D): Weld
local weld = Instance.new("Weld")
weld.Name = motor.Name .. "Weld"
weld.Part0 = motor.Part0
weld.Part1 = motor.Part1
weld.C0 = motor.C0
weld.C1 = motor.C1
weld.Parent = motor.Parent
return weld
end
local head = character:WaitForChild("Head") :: Part
local torso = character:WaitForChild("Torso") :: Part
local rightShoulderM6D = torso:WaitForChild("Right Shoulder") :: Motor6D
local leftShoulderM6D = torso:WaitForChild("Left Shoulder") :: Motor6D
local rightShoulder = WeldFromMotor6D(rightShoulderM6D)
local leftShoulder = WeldFromMotor6D(leftShoulderM6D)
local cameraPart = Instance.new("Part")
cameraPart.Name = "CamPart"
cameraPart.Size = Vector3.one * 0.5
cameraPart.Transparency = 0.5
cameraPart.Anchored = false
cameraPart.CanCollide = false
cameraPart.CanQuery = false
cameraPart.CanTouch = false
cameraPart.Parent = character
local cameraPartWeld = Instance.new("Motor6D")
cameraPartWeld.Name = "CameraWeld"
cameraPartWeld.Parent = head
cameraPartWeld.Part0 = head
cameraPartWeld.Part1 = cameraPart
local physGunMesh
if LoadAssets then
local assets = LoadAssets(108178658193241)
physGunMesh = assets:Get("PhysGunMesh"):Clone() :: MeshPart
else
physGunMesh = game:GetService("ReplicatedStorage").PhysGunMesh:Clone() :: MeshPart
end
physGunMesh.Parent = character
local beam = physGunMesh:WaitForChild("Beam") :: Beam
local beamEnd = physGunMesh:WaitForChild("BeamEnd") :: Attachment
local physGunLoop1 = CreateSound("Loop1",119960158123039,0.5,1,true,physGunMesh)
local physGunLoop2 = CreateSound("Loop2",85596412341924,1,1,true,physGunMesh)
local physGunWeld = Instance.new("Motor6D")
physGunWeld.Name = "PhysGunWeld"
physGunWeld.Parent = cameraPart
physGunWeld.Part0 = cameraPart
physGunWeld.Part1 = physGunMesh
local rightArmIkPos = physGunMesh:WaitForChild("RightArmIK") :: Attachment
local leftArmIkPos = physGunMesh:WaitForChild("LeftArmIK") :: Attachment
local globalPhysGunTarget = workspace:FindFirstChild("PhysGunTarget") :: Part
if not globalPhysGunTarget then
local globalPhysGunTarget = Instance.new("Part")
globalPhysGunTarget.Name = "PhysGunTarget"
globalPhysGunTarget.Transparency = 1
globalPhysGunTarget.Position = Vector3.yAxis * -10
globalPhysGunTarget.Anchored = true
globalPhysGunTarget.CanCollide = false
globalPhysGunTarget.CanQuery = false
globalPhysGunTarget.CanTouch = false
globalPhysGunTarget.Parent = workspace
end
if NLS then
NLS([[
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local camera = workspace.CurrentCamera
local remote = player:WaitForChild("CameraRemote")
local RenderStepName = "PhysGunUpdate"
local IsBound = true
local physGun = character:WaitForChild("PhysGunMesh")
local rightArm = character:WaitForChild("Right Arm")
local leftArm = character:WaitForChild("Left Arm")
local beam = physGun:WaitForChild("Beam")
physGun:GetPropertyChangedSignal("LocalTransparencyModifier"):Connect(function()
physGun.LocalTransparencyModifier = physGun.Transparency
end)
rightArm:GetPropertyChangedSignal("LocalTransparencyModifier"):Connect(function()
rightArm.LocalTransparencyModifier = rightArm.Transparency
end)
leftArm:GetPropertyChangedSignal("LocalTransparencyModifier"):Connect(function()
leftArm.LocalTransparencyModifier = leftArm.Transparency
end)
beam:GetPropertyChangedSignal("LocalTransparencyModifier"):Connect(function()
beam.LocalTransparencyModifier = 0
end)
local function Update()
remote:FireServer(camera.CFrame)
end
local function UnbindRenderStep()
if not IsBound then return end
game:GetService("RunService"):UnbindFromRenderStep(RenderStepName)
end
game:GetService("RunService"):BindToRenderStep(RenderStepName,Enum.RenderPriority.Camera.Value + 1,function()
Update()
end)
Update()
character.Destroying:Connect(UnbindRenderStep)
]],player.PlayerGui)
end
mouse.Button1Down:Connect(function()
if isGrabbingObject then return end
if mouse.Target ~= nil and mouse.Target.Anchored == false then
local model = mouse.Target:FindFirstAncestorWhichIsA("Model")
if model and model.PrimaryPart ~= nil and model.PrimaryPart.Anchored == false then
grabbedObject = model.PrimaryPart
else
grabbedObject = mouse.Target
end
grabbedObjectDistance = (grabbedObject.CFrame.Position - head.CFrame.Position).Magnitude
isGrabbingObject = true
end
end)
mouse.Button1Up:Connect(function()
if not isGrabbingObject then return end
if grabbedObject then grabbedObject.AssemblyLinearVelocity = Vector3.zero end
isGrabbingObject = false
end)
mouse.KeyDown:Connect(function(key)
if key == "e" then
pushFurther = true
end
if key == "q" then
bringCloser = true
end
end)
mouse.KeyUp:Connect(function(key)
if key == "e" then
pushFurther = false
end
if key == "q" then
bringCloser = false
end
end)
cameraRemote.OnServerEvent:Connect(function(player: Player,cframe: CFrame)
cameraCFrame = cframe
end)
local function Update(dt: number)
local cameraRot = Vector3.new(cameraCFrame:ToOrientation())
cameraPartWeld.C0 = cameraPartWeld.C0:Lerp(CFrame.Angles(cameraRot.X,0,0),1 - math.pow(0.5,dt * VIEWMODEL_LERP_SPEED))
local newCframe = CFrame.new(VIEWMODEL_OFFSET)
physGunWeld.C0 = newCframe
local raCF = rightArmIkPos.WorldCFrame * RIGHT_ARM_CFRAME
rightShoulder.C0 = raCF:ToObjectSpace(rightShoulder.Part0.CFrame):Inverse()
local laCF = leftArmIkPos.WorldCFrame * LEFT_ARM_CFRAME
leftShoulder.C0 = laCF:ToObjectSpace(leftShoulder.Part0.CFrame):Inverse()
if isGrabbingObject and grabbedObject ~= nil then
if pushFurther then
grabbedObjectDistance += BRING_SPEED * dt
end
if bringCloser and grabbedObjectDistance > 3 then
grabbedObjectDistance -= BRING_SPEED * dt
end
local mouseDir = (mouse.Hit.Position - head.CFrame.Position).Unit
local newPos = head.Position + mouseDir * grabbedObjectDistance
local distanceToNewPos = (grabbedObject.Position - newPos).Magnitude
grabbedObject.AssemblyLinearVelocity = (newPos - grabbedObject.CFrame.Position).Unit * distanceToNewPos * STRENGTH * grabbedObject:GetMass()
PlaySound(physGunLoop1)
PlaySound(physGunLoop2)
beamEnd.WorldPosition = grabbedObject.Position
beam.Enabled = true
else
beam.Enabled = false
StopSound(physGunLoop1)
StopSound(physGunLoop2)
end
end
local UpdateConnection = game:GetService("RunService").Heartbeat:Connect(Update)
local function Cleanup()
if beamEnd then
beamEnd:Destroy()
end
if grabbedObject then
grabbedObject.AssemblyLinearVelocity = Vector3.zero
end
if not UpdateConnection or not UpdateConnection.Connected then return end
UpdateConnection:Disconnect()
end
character.Destroying:Connect(Cleanup)
humanoid.Died:Connect(Cleanup)