Making a claimable house system (issue with module script)

Hi,

I’m working on a claimable house system where players can buy a house. Each house will have a sign with a proximity prompt that says "Buy House." Once purchased, the player will own the house and be able to lock/unlock the door. The sign will also display their avatar and username.

However, nothing works. The coins do not deduct from my leaderboard, and the info on the sign doesn’t update either.

I would really appreciate any help with this! :slight_smile:

Sign Script.

local ProximityPrompt = script.Parent.ProximityPrompt
local SurfaceGui = script.Parent.SurfaceGui
local ProfileService = require(game.ServerScriptService.Modules.ProfileService)
local COST = 400

ProximityPrompt.Triggered:Connect(function(player)
	if not ProfileService or not ProfileService.GetProfileAsync then
		warn("ProfileService is not loaded or missing GetProfileAsync function!")
		return
	end

	local profile = ProfileService.GetProfileAsync(player.UserId) 
	if not profile then
		warn("Failed to retrieve profile for player: " .. player.UserId)
		return
	end


	if profile.Coins < COST then
		game:GetService("StarterGui"):SetCore("SendNotification", {
			Title = "Insufficient Coins";
			Text = "You do not have enough coins to purchase this.";
			Duration = 3;
		})
		return
	end


	profile.Coins = profile.Coins - COST
	SurfaceGui.NameLabel.Text = player.Name
	SurfaceGui.AvatarImage.Image = "rbxthumb://type=AvatarHeadShot&id=" .. player.UserId .. "&w=100&h=100"

	ProximityPrompt.Enabled = false
	script.Parent:SetAttribute("Owner", player.UserId)
end)

Door Script:

local ProximityPrompt = script.Parent.ProximityPrompt
local ownerID = script.Parent.Parent.BuyHouseSign:GetAttribute("Owner")
local doorLocked = false

local function updateDoor(locked)
	doorLocked = locked
	ProximityPrompt.ActionText = locked and "Unlock" or "Lock"
	script.Parent.Transparency = locked and 0 or 0.7
	script.Parent.CanCollide = locked
end

ProximityPrompt.Triggered:Connect(function(player)
	if player.UserId ~= ownerID then
		player:warn("Only the house owner can lock/unlock this door.")
		return
	end

	updateDoor(not doorLocked) 
end)

image

1 Like

If the issue lies with the profile service then this is what I have:

image

DataManagerScript

local Players = game:GetService("Players")
local serverScriptService = game:GetService("ServerScriptService")
local modules = serverScriptService:WaitForChild("Modules")

local ProfileService = require(modules:WaitForChild("ProfileService"))
local template = require(script:WaitForChild("Template"))
local leaderstats = require(script:WaitForChild("Leaderstats"))

local datakey = "_DataStore"
local profileStore = ProfileService.GetProfileStore(datakey, template).Mock

local dataManager = {}
dataManager.Profiles = {}

local function PlayerAdded(player: Player)
	local profile = profileStore:LoadProfileAsync("Player_"..player.UserId)
	
	if profile ~= nil then
		profile:AddUserId(player.UserId)
		profile:Reconcile()
		
		profile:ListenToRelease(function()
			dataManager.Profiles[player] = nil
			player:Kick()
		end)
		
		if player:IsDescendantOf(Players) then
			dataManager.Profiles[player] = profile
			leaderstats:Create(player, profile)
		else
			profile:Release()
		end
	else
		player:Kick()
	end 
end

local function PlayerRemoving(player: Player)
	local profile = dataManager.Profiles[player]
	
	if profile ~= nil then
		profile:Release()
	end
end

for _, player in Players:GetPlayers() do
	task.spawn	(PlayerAdded, player)
	
end

Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(PlayerRemoving) 

return dataManager

Does the output gives some information like warnings? Or it’s clear as the sky?

It throws this error in the output and it’s from the script in BuyHouseSign

ProfileService is not loaded or missing GetProfileAsync function!  -  Server - BuyHouseSign:8

Can you share ProfileService script if you don’t mind anything? It would be useful and probably the core cause of the issue.

Instead of grabbing the player’s profile directly from the ProfileService module, why don’t you just get it from your cached table of profiles inside dataManager?

function dataManager.GetProfile(player)
	if not player:IsDescendantOf(Players) then return end
	
	local profile = dataManager.Profiles[player]
	while profile == nil do
		profile = dataManager.Profiles[player]
		task.wait()
	end
	return profile
end

Put this function inside your dataManager module, require the dataManager module instead of ProfileService and get the player’s profile from there

It’s the exact same one I got online :slight_smile:

I must be doing something wrong. Where do I put this line of code in the datamanager?

Anywhere. It’s a function. It just needs to be before you call it.

Update: I got it working, but the issue is the money doesn’t deduct when buying the house.

Door Script:

local ProximityPrompt = script.Parent.ProximityPrompt
local SurfaceGui = script.Parent.SurfaceGui
local dataManager = require(game.ServerScriptService.Modules.DataManager) 
local COST = 400

ProximityPrompt.Triggered:Connect(function(player)

	local profile = dataManager.GetProfile(player) 
	if not profile then
		warn("Failed to retrieve profile for player: " .. player.UserId)
		return
	end


	if profile.Data.Coin < COST then
		game:GetService("StarterGui"):SetCore("SendNotification", {
			Title = "Insufficient Coin",
			Text = "You do not have enough Coin to purchase this.",
			Duration = 3,
		})
		return
	end
	

	profile.Data.Coin = profile.Data.Coin - COST
	print(player.Name .. " has " .. profile.Data.Coin .. " Coin(s) remaining.")  -- Debug
	SurfaceGui.OwnerName.Text = player.Name
	SurfaceGui.PlayerImage.Image = "rbxthumb://type=AvatarHeadShot&id=" .. player.UserId .. "&w=100&h=100"


	ProximityPrompt.Enabled = false
	script.Parent:SetAttribute("Owner", player.UserId)
end)

1 Like

Does it print the (player.Name .. " has " .. profile.Data.Coin .. " Coin(s) remaining.") -- Debug

Yes, it says "username has 0 Coin(s) remaining. "

Have you got the required amount of money? Did you check the right data?

Yea. For example if I have 800 coins then it will show “400 coins remaining” after buying the house.

The other thing that shows up in output as well is
Infinite yield possible on 'Players.User.PlayerScripts:WaitForChild("ProximityPrompt")

Which script is this reffering to?

EDIT: I realised one of the problems. (maybe) Is this code on the client or the server?

The script of the sign and the door are both client, but the Profileservice is all in ServerScriptService
image

The infinite yield of the proximity prompt comes from StarterPlayerScripts which has this script:

local ProximityPrompt = script.Parent:WaitForChild("ProximityPrompt") 
local doorOwnerId = script.Parent.Parent:GetAttribute("Owner") 

ProximityPrompt.Triggered:Connect(function(player)
	if player.UserId == doorOwnerId then
		if ProximityPrompt.ActionText == "Lock House" then
			-- Lock the door: only the owner can enter
			script.Parent.CanCollide = true
			script.Parent.Transparency = 0
			ProximityPrompt.ActionText = "Unlock House"
		else
			script.Parent.CanCollide = false
			script.Parent.Transparency = 0.7
			ProximityPrompt.ActionText = "Lock House"
		end
	end
end)

The proximity prompt isn’t being found, that is why it is giving that error. Try checking if it is in the right place.

Try this code, I didn’t check if it works because I wrote this on my phone, it just adds a save feature right after you purchase the house

local ProximityPrompt = script.Parent.ProximityPrompt
local SurfaceGui = script.Parent.SurfaceGui
local dataManager = require(game.ServerScriptService.Modules.DataManager) 
local COST = 400

ProximityPrompt.Triggered:Connect(function(player)

	local profile = dataManager.GetProfile(player) 
	if not profile then
		warn("Failed to retrieve profile for player: " .. player.UserId)
		return
	end


	if profile.Data.Coin < COST then
		game:GetService("StarterGui"):SetCore("SendNotification", {
			Title = "Insufficient Coin",
			Text = "You do not have enough Coin to purchase this.",
			Duration = 3,
		})
		return
	end


	profile.Data.Coin = profile.Data.Coin - COST
	print(player.Name .. " has " .. profile.Data.Coin .. " Coin(s) remaining.")  -- Debug
	dataManager.SaveProfile(player, profile)
	SurfaceGui.OwnerName.Text = player.Name
	SurfaceGui.PlayerImage.Image = "rbxthumb://type=AvatarHeadShot&id=" .. player.UserId .. "&w=100&h=100"


	ProximityPrompt.Enabled = false
	script.Parent:SetAttribute("Owner", player.UserId)
end)
1 Like

Forgive me for my late reply. I’ve had a hectic week. I attempted your code, and this is what I got in the output.

[ProfileService]: Roblox API services available - data will be saved  -  Server - ProfileService:2307
User has 0 Coin(s) remaining.  -  Server - Script:25
Infinite yield possible on 'Players.User.PlayerScripts:WaitForChild("ProximityPrompt")'  -  Studio
Stack Begin  -  Studio
Script 'Players.User.PlayerScripts.HousePurchaseClient', Line 1  -  Studio - HousePurchaseClient:1
Stack End  -  Studio

The money still doesn’t deduct in leader stats.

1 Like

The proximity prompt isn’t being found, that is why it is giving that error. Try checking if it is in the right place.

That script is in Starterplayerscripts. Perhaps I should specify it more where the prompt can be found initially? That proximity prompt is actually in workspace → Houses (folder) → Door (part) → Proximityprompt

image

Then the proximity prompt needs to be directed to that.

So it would be:

local ProximityPrompt = workspace.Houses.Door.ProximityPrompt

(change that over the line of code that says local ProximityPrompt = script.Parent:WaitForChild("ProximityPrompt")