I have Filtering Enabled on and I'm doing everything to prevent Exploiting, so I try to make everything exploitable with remotes.

But I'm Troubling with Buying System I have.

I want to have one script in ServerScriptService that will take object clicked by client as an argument and then do things (charge client for price,make client owner of the object etc).

Thing is that I have to deal with the following limitations:

FireServer can only be called from the Client( this is problem cause serverScriptService is only accessible with Local Script, but Local Script can't listen to mouseclick)

FireClient can only be called from the Server(Fire Client is the one that binds both player and arguments, but only local scripts can listen those)

So I can't really use RemoteEvents, So I'm using RemoteFunctions(But it has very similar problems)

So I do the following: I have this script in mouseclick:

script.Parent.MouseClick:Connect(function(plr)
	game:GetService("ReplicatedStorage").RemoteBuy:InvokeClient(plr, object)
end)

I have this local script in starter pack :

local RS = game:GetService("ReplicatedStorage")
local send = require(RS.Buy)
local plr  = game:GetService("Players").LocalPlayer

function RS.RemoteBuy.OnClientInvoke(object)
	send.BuyHouse(plr, object)
end

and I have this moduleScript in remoteStorage(Final destination of this crazy route), but It says that client can't access DataStore

local module = {}

function module.BuyHouse(plr,object)
	if plr ~= nil and house ~= nil then		
		
		
		local serverstorage = game:GetService("ServerStorage")
		local owner = house.CurrentOwner--CurrentOwner is stringValue inserted in model
		local houseprice = house.Price.Value
		local buy = house.Buy --Buy is part they have to click in order to buy it
		
		local ds1 = game:GetService("DataStoreService"):GetDataStore("DTStore123","202")--this returns error
		local p_data = ds1:GetAsync(tostring(plr.UserId))
		local p_money = p_data.Money
		local p_houses = p_data.Houses
		local class = house.Class.Value-- you don't have to worry about that
		local money = plr.leaderstats.Coin
		
		
		if p_houses.class == true and owner.Value == "" then
			----
			local clone = serverstorage.DecalSold:Clone()
			clone.Parent = buy
			buy.BrickColor = BrickColor.Red()
			----
		elseif plr:FindFirstChild("leaderstats") and owner.Value == "" then 
			if money.Value  >= houseprice then
				owner.Value = plr.Name
				owner.Parent.Name = plr.Name.."'s House"
				local p_data = ds1:GetAsync(tostring(plr.UserId))
				print(p_data)
				
				local p_money = p_data.Money
				local p_houses = p_data.Houses 
				
				
				local ownerName = plr.Name
				
				--making averybody aware of house owner--
				print(ownerName, "is the owner of this house")
				
				--taking care of handeling house to plr--
				
				money.Value = money.Value - houseprice
				owner.Value = plr.Name
				owner.Parent.Name = plr.Name.."'s House"
				
				local function Update1(money, luxury, high, middle, standard)
					standard = true
					local new_value = {
						["Money"] = money,
						["Houses"] = {
							["Luxury"] = luxury,
							["High"] = high,
							["Middle"] = middle,
							["Standard"] = standard
							}
						}		
					ds1:SetAsync(tostring(plr.UserId), new_value) 
				end
				Update1(money.Value, p_houses.Luxury, p_houses.High, p_houses.Middle, p_houses.Standard)
				
				
				--everything below is for Ad sign--
				buy.DecalForSale:Remove()
				local clone = serverstorage.DecalSold:Clone()
				clone.Parent = buy
				buy.BrickColor = BrickColor.Red()
				
			end
			
		else
			print("You already own this house")
			buy:Remove()
		
		end
	end
end




return module