How to translate this script to server?

Hello, I was wondering how I could translate this local script to be server based (the rng and moving of the hook) as I want other players to see when someone else is fishing.

I know I have to use remote events/functions, but whatever I tried simply didn’t work or produced some horrible/completely off result.

I know the script is quite long, so if you don’t wish to read the whole thing please at least drop a comment with a way I could do this, even if it’s not specific.

local FishModule = require(script.FishModule)

local Player = game:GetService('Players').LocalPlayer
local Backpack = Player:WaitForChild("Backpack", 10)
local Character = Player.Character or Player.CharacterAdded:Wait()

local Mouse = Player:GetMouse()
local TweenService = game:GetService("TweenService")

local FishingRod = Backpack:WaitForChild("Fishing Rod Normal", 5) or Character:WaitForChild("Fishing Rod Normal", 5)
local Hook = FishingRod:WaitForChild('Hook', 20)
local RopeConstraint = FishingRod.RodTip:FindFirstChild("RopeConstraint")

if not FishingRod then
	warn("Fishing rod not found!")
end

local FishCaughtGui = Player.PlayerGui:WaitForChild('FishCaughtGui')
local FishCaughtText = FishCaughtGui.FCGFrame.FishCaughtText

local OnCooldown = false
local Cooldown = 1

local function AdjustRopeLength(TargetHookPosition)
	-- Calculate the distance between the rod tip and the hook
	local RodTipPosition = FishingRod.RodTip.Position
	local hookPosition = Hook.Position
	local Distance = (RodTipPosition - TargetHookPosition).Magnitude

	-- Set the rope constraint's length dynamically
	if RopeConstraint then
		RopeConstraint.Length = Distance * 1.06
	end
end

local function CastFishingHook(TargetHookPosition)
	local HookStartPosition = Hook.Position

	local tweenInfo = TweenInfo.new(
		2,
		Enum.EasingStyle.Sine,
		Enum.EasingDirection.Out
	)

	-- Tween to the target position
	local TweenToTarget = TweenService:Create(Hook, tweenInfo, {Position = TargetHookPosition})
	
	-- Adjust the rope length dynamically as the hook moves
	TweenToTarget:GetPropertyChangedSignal("PlaybackState"):Connect(function()
		if TweenToTarget.PlaybackState == Enum.PlaybackState.Playing then
			AdjustRopeLength(TargetHookPosition)
		end
	end)

	TweenToTarget:Play()
end

local function GetRarityColor(ChosenRarity)
	local RarityColors = {
		Common = "#a9a9a9", -- Grey
		Uncommon = "#00FF00", -- Green
		Rare = "#0080ff", -- Blue
		Epic = "#cd00cd", -- Purple
		Legendary = "#FFFF00", -- Yellow
		Mythical = "#ff0000", -- Red
		Godly = "#00FFFF" -- Bright Blue (Cyan)
	}
	
	local RarityColor = RarityColors[ChosenRarity]
	return RarityColor
end

local function IsWater(part)
	-- Check if the part is a descendant of any "Water" models
	while part do
		if part.Name == "Water" then
			return true
		end
		part = part.Parent
	end
	return false
end

local function CloseEnough()
	local Distance = (FishingRod.RodTip.Position - Mouse.Hit.Position).Magnitude
	if Distance <= 90 then return true
	else return false
	end
end


FishingRod.Activated:Connect(function()
	if not OnCooldown then
		OnCooldown = true
		
		FishCaughtText.Text = 'Fishing..'
		
		FishingRod.String.Transparency = 1
		FishingRod.RodTip.RopeConstraint.Visible = true
		FishingRod.Handle["Handle-Hook"].Enabled = false
		
		local MouseTarget = Mouse.Target -- Get the target part of the mouse
		if MouseTarget and IsWater(MouseTarget) then
			if CloseEnough() then
				local TargetHookPosition = Mouse.Hit.Position
				CastFishingHook(TargetHookPosition)

				task.wait(2)
				local ChosenFish, ChosenNumRarity, ChosenRarity = FishModule.GetRandomFish()
				local RarityColorChosen = GetRarityColor(ChosenRarity) or "#f300ff"

				print(tostring(ChosenNumRarity))
				print('You caught: ' .. ChosenFish .. ' (' .. ChosenRarity .. ').')

				FishCaughtText.Text = 'You caught: ' .. ChosenFish .. ' (<font color="' .. RarityColorChosen .. '">' .. ChosenRarity .. '</font>).'
				
			else
				FishCaughtText.Text = 'Too far away to catch fish!'
			end
		else
			FishCaughtText.Text = "You can only fish in water!"
		end
		
		Hook.CFrame = FishingRod.InvisHook.CFrame
		
		FishingRod.String.Transparency = 0
		FishingRod.RodTip.RopeConstraint.Visible = false
		Hook.CFrame = FishingRod.InvisHook.CFrame
		FishingRod.Handle["Handle-Hook"].Enabled = true
		
		task.wait(1.5)
		
		FishCaughtText.Text = ''
		
		task.wait(Cooldown)
		OnCooldown = false
	else
		print('On cooldown.')
	end
end)

Your doing the right thing by leaving actions and tween service on the client since they could be performance heavy on the server. What you want to do is use 1 or 2 remote events. 1st remote event: When this client starts fishing by by an input service event it fires an event to the server. Then when the server gets the signal from that event it fires to all clients using the second remote event. When all clients receive that signal then you can put the stuff from this to their script.

Client whos fishing → Server
RemoteEvent:FireServerRemoteEvent.OnServerEvent

Server → All clients connected to the server
RemoteEvent:FireAllClients()RemoteEvent.OnClientEvent

Hopefully this should make it clear enough, let me know if you need me to give a better example.

so in most games that handle well there is a module that handles a client based vfx system.
why client sided vfx? because doing a lot of vfx on the server is very taxing on the server.
(im going to be referring to the action of casting your fishing bob, and a fish coming out to vfx)

this is going to be a bit difficult to explain properly, so bear with me…
this vfx module is essentially a glorified data transmitter.
all it does is send a table of information to a client (through a remote event), with the necessary information in order to produce something on the clients screen.

an example could be vfxModule.sendVFXData(player, {vfx = “paycheck” reward_amount = 55, reward_type = “money”})

the client then receives this information, in this case the reward amount, and reward type, and does something with it.
such as displaying a GUI saying “congratulations, you’ve earned your first paycheck of 55 dollars!”

this can also applied to multiple clients
an example being a magical stone wall appearing
vfxModule.sendVFXData(player, {vfx = “stone wall”, position = Vector3.new(x, y, z)})

just like before, except we can send this data to multiple clients
the clients then receive this data, and do something with it, in this case making a magical stone wall appearing at the specified position

here’s some pipelines to further your understanding (NOTE: this is my way of doing it, not necessarily the correct way)
PLAYER STARTS FISHING
1 - CLIENT: player gets input to fish
2 - CLIENT: sends request for server to start fishing
3 - SERVER: recognizes player wants to fish
4 - SERVER: does server sided checks to check distance and whether they can fish (check security notes)
5 - SERVER: sends signal to all nearby players
6 - CLIENT: receives fishing signal
7 - CLIENT: applies vfx near fishing player

PLAYER CATCHES FISH
1 - CLIENT: player finishes the local mini-game, granting the reward
2 - CLIENT: sends signal to server saying “i finished the mini-game give me your prize”
3 - SERVER: receives signal, does some sanity checks to make sure the player isn’t exploiting
4 - SERVER: after sanity checks, randomizes reward
5 - SERVER: sends signal to specific client, saying “ok we’ve checked you’re legitimate, here is your reward”
6 - CLIENT: receives signal, and reward data
7 - CLIENT: displays message congratulating and showing reward

security notes:
(im going to assume you know about the client-server architecture and pros + cons faced with this)
you want any “precious logic” to be on the server
ANYTHING that the client runs can and probably will be exploited
this includes the rng, and how close the player is to water
if there is a check that verifies if the player is close enough to water, and its being run on client, there is nothing stopping the exploiter from simply commenting this code out and fishing 100 miles away from water

this also means the vfx can be exploited

weigh your options to see if the logic you’re executing on the client would have any major impacts to gameplay
i recommend searching up “Server Authoritative Software Engineering”
server authoritative tl;dr - client should only send requests to the server, not tell the server what to do

there are many ways to do something in coding, so find what works for you and what keeps you coding tomorrow