-- this code LOOKS scary, but its actually pretty simple and fast
local items = {}
local is_server = not game.Players.LocalPlayer
local userid
if not is_server then
	userid = game.Players.LocalPlayer.UserId
end

-- to stop allocating new variables each time (threading doesn't work anyways)
local position
local velocity
local delta1
local delta2
local delta
local difference
local vp
local this_root

local function round(n)
	return math.round(n*1000)/1000
end

local common_delta = 1/120
local common_drag_resistance = 0.967
local common_float_resistance = 0.8
local float_terminal = 1
local decay = 10
local complement = -11.5
local idecay = 1/decay
local anti_gravity = Vector3.new(0,196,0)
local floating_velocity = 10
local run = game:GetService("RunService")
local global_drag_resistance = 0
local global_float_resistance = 0
local global_delta = 0

run.PreSimulation:Connect(function(delta)
	global_float_resistance = math.pow(common_float_resistance,delta/common_delta)-1
	global_drag_resistance = math.pow(common_drag_resistance,delta/common_delta)-1
	global_delta = delta
end)
local water_height = -4
local decay_complement = -water_height+decay+complement
local template_instance = _G.Storage.Idol
local impulse = template_instance.ApplyImpulseAtPosition
local angular_impulse = template_instance.ApplyAngularImpulse
local network_owner_check_success, network_owner
local get_network_owner_real = template_instance.GetNetworkOwner
local get_network_owner = function(instance)
	network_owner_check_success,network_owner = pcall(function() get_network_owner_real(instance) end)
	return ((not network_owner_check_success) or network_owner)
end
local root_part = template_instance.GetRootPart
local new_vec3 = Vector3.new
local counter = 0

local root_reduction = {}

local function reduce_root_part(root)
	root.Velocity = root.Velocity * 0.99
	root.AssemblyAngularVelocity = root.AssemblyAngularVelocity * 0.99
end
local math_clamp = math.clamp
local local_disconnect_all = true
local function register_part(instance)
	if not instance:IsA("BasePart") then return end
	if not instance.Parent then return end
	local size = instance.Size
	local volume = size.X*size.Y*size.Z
	local mass = instance.Mass
	local event
	local operate = true
	local splash = instance:FindFirstChild("Splash")
	if splash and not splash:IsA("ParticleEmitter") then splash = nil end
	if is_server and get_network_owner(instance) then return end
	if instance.Massless then return end
	instance.AncestryChanged:Connect(function() if not instance.Parent then operate = false event:Disconnect() end end)
	--instance.Destroying:Connect(function() print("disconnect") event:Disconnect() end)
	event = run.PreSimulation:Connect(function(delta)
		--if not operate then event:Disconnect() end
		
		if is_server and get_network_owner(instance) then wait(0.2) return end
		vp = instance.Position
		position = vp.Y+decay_complement
		if position < 0 then
			--if splash then splash.Enabled = true splash.Rate = math_clamp(10*instance.AssemblyLinearVelocity.Magnitude,0,100) end -- PLEASE OPTIMISE
			position = math.abs(position*idecay)
			--instance.Transparency = 0.5
			if position > 1 then position = 1 end
			velocity = instance.Velocity
			--local angular = instance.AssemblyAngularVelocity -- implement later...
			difference = velocity*global_drag_resistance + new_vec3(0,velocity.Y-floating_velocity,0)*global_float_resistance
			impulse(instance,difference*volume*position+anti_gravity*delta,vp)
		else
			--if splash then splash.Enabled = false end -- PLEASE OPTIMISE
			--velocity = instance.Velocity
			wait(0.1) -- to stop checking too many times in air (saving frames)
		end
	end)
	return event
end
if is_server then
	game.Workspace.Objects.DescendantAdded:Connect(function(instance)
		local owner = instance:GetAttribute("NetworkOwner")
		if not owner and is_server then 
			--register_part(instance) 
			for _,child in pairs(instance:GetChildren()) do
				--register_part(child)
			end		
		end
	end)
else
	game.Workspace.Objects.DescendantAdded:Connect(function(instance)
		local owner = instance:GetAttribute("NetworkOwner")
		if owner == userid then 
			--register_part(instance) 
			for _,child in pairs(instance:GetChildren()) do
				--register_part(child)
			end	
		end
	end)
end


local module = {}
module.register_part = register_part
return module