Sistema inmobiliario para FiveM: trabajos de agente y venta de propiedades
Crea una economía inmobiliaria en tu servidor FiveM. Anuncios, jornadas de puertas abiertas, comisiones y los mejores scripts para QBCore y ESX.
Agency Scripts
Fundador y desarrollador principal en Agency Scripts
Arquitectura del sistema inmobiliario
Un sistema inmobiliario transforma tu servidor de FiveM de un conjunto de edificios inaccesibles en un mercado inmobiliario dinámico donde los jugadores compran, venden y alquilan casas, apartamentos y locales comerciales. La arquitectura se centra en una base de datos de propiedades que registra todas las propiedades disponibles en el servidor, con su ubicación, tipo, propietario actual, valor de mercado y configuración del interior. A diferencia de los scripts de vivienda básicos que solo permiten comprar una lista predeterminada de propiedades, un sistema inmobiliario bien diseñado incluye un trabajo de agente inmobiliario que facilita transacciones entre jugadores, con visitas, negociaciones y comisiones. El sistema debe integrarse con el recurso de cerraduras de puertas del servidor para que la propiedad otorgue o revoque automáticamente el acceso al edificio, y con sistemas de carga de interiores, como MLO personalizados o interiores instanciados. Planifica desde el principio tres categorías de propiedades: residenciales para las viviendas de los jugadores, comerciales para los negocios propiedad de jugadores y de alquiler, que generan ingresos pasivos para los propietarios.
Base de datos y anuncios de propiedades
La base de datos de propiedades es la base sobre la que se construyen todos los demás componentes. Cada registro de propiedad necesita metadatos detallados, incluidos el shell o el interior MLO que utiliza, las coordenadas de entrada y salida, la disponibilidad de garaje, la capacidad de almacenamiento y el historial de precios. Mantén una tabla de anuncios independiente que registre qué propiedades están actualmente a la venta, su precio de venta, el agente responsable del anuncio y cuánto tiempo llevan anunciadas. Esta separación te permite llevar un historial del mercado y calcular las tendencias del valor de las propiedades con el paso del tiempo. Este esquema de base de datos permite gestionar todo el ciclo de vida inmobiliario:
CREATE TABLE IF NOT EXISTS properties (
id INT AUTO_INCREMENT PRIMARY KEY,
property_id VARCHAR(50) NOT NULL UNIQUE,
label VARCHAR(100) NOT NULL,
property_type ENUM('house', 'apartment', 'commercial', 'penthouse') NOT NULL,
owner VARCHAR(50) DEFAULT NULL,
price INT NOT NULL,
original_price INT NOT NULL,
interior VARCHAR(50) DEFAULT 'standard_1bed',
enter_coords JSON NOT NULL,
exit_coords JSON DEFAULT NULL,
garage_slots INT DEFAULT 0,
stash_slots INT DEFAULT 50,
has_wardrobe TINYINT DEFAULT 1,
is_furnished TINYINT DEFAULT 1,
neighborhood VARCHAR(50) DEFAULT 'downtown',
purchased_at BIGINT DEFAULT NULL,
INDEX idx_owner (owner),
INDEX idx_type (property_type),
INDEX idx_neighborhood (neighborhood)
);
CREATE TABLE IF NOT EXISTS property_listings (
id INT AUTO_INCREMENT PRIMARY KEY,
property_id VARCHAR(50) NOT NULL,
asking_price INT NOT NULL,
listing_agent VARCHAR(50) DEFAULT NULL,
listed_at BIGINT NOT NULL,
status ENUM('active', 'pending', 'sold', 'cancelled') DEFAULT 'active',
buyer VARCHAR(50) DEFAULT NULL,
sold_at BIGINT DEFAULT NULL,
sold_price INT DEFAULT NULL,
INDEX idx_status (status),
INDEX idx_agent (listing_agent)
);
Rellena la tabla de propiedades con todas las propiedades disponibles en el servidor durante la configuración inicial. Define cuidadosamente las coordenadas de entrada de cada propiedad para que coincidan con la posición de las puertas o las zonas de interacción. El campo original_price conserva el valor base para los cálculos del mercado, mientras que el campo price refleja el valor de mercado actual, que cambia según la demanda del vecindario, las mejoras realizadas por el propietario y la situación económica general del servidor.
Sistema de trabajo de agente inmobiliario
El trabajo de agente inmobiliario es donde el componente humano hace que este sistema destaque. Los agentes actúan como intermediarios entre compradores y vendedores, organizan visitas a propiedades, negocian precios y ganan comisiones por las ventas completadas. Define rangos del trabajo que den acceso progresivo a mejores anuncios: los agentes júnior se ocupan de apartamentos y casas pequeñas, los agentes sénior tienen acceso a propiedades de lujo y locales comerciales, y el propietario de la inmobiliaria administra el equipo y recibe una parte de todas las comisiones. Cuando un jugador interesado en comprar una propiedad se pone en contacto con un agente, este puede iniciar una visita que teletransporta a ambos jugadores al interior de la propiedad para recorrerla. Esta es la lógica de las visitas y las transacciones de venta:
RegisterNetEvent('realestate:server:startShowing', function(propertyId, buyerId)
local src = source
local Agent = QBCore.Functions.GetPlayer(src)
local Buyer = QBCore.Functions.GetPlayer(buyerId)
if not Agent or not Buyer then return end
if Agent.PlayerData.job.name ~= 'realtor' then return end
local property = MySQL.query.await(
'SELECT * FROM properties WHERE property_id = ? AND owner IS NULL',
{propertyId}
)
if not property or not property[1] then
return TriggerClientEvent('QBCore:Notify', src, 'Property not available', 'error')
end
local prop = property[1]
local enterCoords = json.decode(prop.enter_coords)
-- Teleport both to property
TriggerClientEvent('realestate:client:enterShowing', src, prop, enterCoords)
TriggerClientEvent('realestate:client:enterShowing', buyerId, prop, enterCoords)
TriggerClientEvent('QBCore:Notify', buyerId,
'Showing: ' .. prop.label .. ' - $' .. prop.price, 'info')
end)
RegisterNetEvent('realestate:server:purchaseProperty', function(propertyId, buyerId, agreedPrice)
local src = source
local Agent = QBCore.Functions.GetPlayer(src)
local Buyer = QBCore.Functions.GetPlayer(buyerId)
if not Agent or not Buyer then return end
if Agent.PlayerData.job.name ~= 'realtor' then return end
local property = MySQL.query.await(
'SELECT * FROM properties WHERE property_id = ? AND owner IS NULL',
{propertyId}
)
if not property or not property[1] then return end
if not Buyer.Functions.RemoveMoney('bank', agreedPrice, 'property-purchase') then
return TriggerClientEvent('QBCore:Notify', src, 'Buyer cannot afford this', 'error')
end
local commission = math.floor(agreedPrice * 0.05)
Agent.Functions.AddMoney('bank', commission, 'realtor-commission')
MySQL.update(
'UPDATE properties SET owner = ?, price = ?, purchased_at = ? WHERE property_id = ?',
{Buyer.PlayerData.citizenid, agreedPrice, os.time(), propertyId}
)
MySQL.update(
'UPDATE property_listings SET status = "sold", buyer = ?, sold_at = ?, sold_price = ? WHERE property_id = ? AND status = "active"',
{Buyer.PlayerData.citizenid, os.time(), agreedPrice, propertyId}
)
TriggerClientEvent('QBCore:Notify', src,
'Sale complete! Commission: $' .. commission, 'success')
TriggerClientEvent('QBCore:Notify', buyerId,
'Congratulations! You now own ' .. property[1].label, 'success')
TriggerEvent('doorlock:server:updateProperty', propertyId, Buyer.PlayerData.citizenid)
end)
La tasa de comisión debe poder configurarse y, posiblemente, variar según el rango del agente. Los agentes sénior podrían ganar una comisión del 7%, mientras que los júnior solo ganarían un 3%, lo que incentiva la progresión profesional dentro del trabajo inmobiliario. Registra en la base de datos el volumen total de ventas y las comisiones de cada agente para crear clasificaciones de rendimiento y desbloquear bonificaciones para los mejores.
Sistema de hipotecas y financiación
La mayoría de los jugadores no puede pagar de inmediato las propiedades de alto valor, así que un sistema de hipotecas aumenta considerablemente la cantidad de compradores potenciales y facilita el acceso al mercado inmobiliario a los jugadores nuevos. Si un comprador no puede pagar el precio completo, ofrece una opción de hipoteca que requiera un porcentaje configurable de entrada, normalmente del 10-20% del valor de la propiedad. El saldo restante se paga en cuotas periódicas que se descuentan automáticamente de la cuenta bancaria del jugador en cada reinicio del servidor o a intervalos programados. Registra los detalles de la hipoteca, incluidos el importe del principal, la tasa de interés, el saldo restante, el importe de la cuota mensual y el historial de pagos. Si un jugador acumula demasiados pagos consecutivos atrasados, inicia un proceso de ejecución hipotecaria para recuperar la propiedad y volver a ponerla en el mercado con descuento. La tasa de interés hace que pedir dinero prestado tenga un coste real, lo que incentiva a los jugadores a liquidar su hipoteca antes de tiempo cuando sea posible. Además, el sistema genera una reducción constante de la cantidad de dinero en circulación, que ayuda a combatir la inflación en la economía del servidor.
Ingresos por alquiler y sistema de propietarios
Los jugadores que tienen varias propiedades deberían poder alquilarlas para obtener ingresos pasivos y crear una dinámica entre propietarios e inquilinos que genere situaciones de rol continuamente. Cuando el propietario de una propiedad quiere alquilarla, establece el importe del alquiler mensual y la anuncia como disponible a través de la inmobiliaria o mediante un anuncio directo. Los inquilinos obtienen acceso con llave a la propiedad y pueden usar su almacenamiento, armario y garaje durante la vigencia del contrato. El alquiler se cobra automáticamente según un calendario configurable y se deposita en la cuenta bancaria del propietario. Aquí tienes la implementación del sistema de alquileres:
Config.RentalSettings = {
minRentPrice = 100,
maxRentPrice = 50000,
collectionInterval = 86400, -- every 24 hours real time
maxMissedPayments = 3,
depositMultiplier = 2, -- security deposit = 2x monthly rent
}
RegisterNetEvent('realestate:server:listForRent', function(propertyId, rentPrice)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local property = MySQL.query.await(
'SELECT * FROM properties WHERE property_id = ? AND owner = ?',
{propertyId, Player.PlayerData.citizenid}
)
if not property or not property[1] then return end
if rentPrice < Config.RentalSettings.minRentPrice or
rentPrice > Config.RentalSettings.maxRentPrice then
return TriggerClientEvent('QBCore:Notify', src, 'Invalid rent price', 'error')
end
MySQL.insert(
'INSERT INTO property_rentals (property_id, landlord, rent_price, deposit, listed_at) VALUES (?, ?, ?, ?, ?)',
{propertyId, Player.PlayerData.citizenid, rentPrice,
rentPrice * Config.RentalSettings.depositMultiplier, os.time()}
)
TriggerClientEvent('QBCore:Notify', src,
'Property listed for rent at $' .. rentPrice .. '/day', 'success')
end)
-- Automated rent collection thread
CreateThread(function()
while true do
Wait(1000 * 60 * 60) -- Check every hour
local rentals = MySQL.query.await(
'SELECT * FROM property_rentals WHERE tenant IS NOT NULL AND status = "active"'
)
for _, rental in ipairs(rentals or {}) do
if os.time() - rental.last_collected >= Config.RentalSettings.collectionInterval then
local success = ProcessRentPayment(rental)
if not success then
HandleMissedPayment(rental)
end
end
end
end
end)
El depósito de garantía protege a los propietarios si los inquilinos dañan la propiedad o se marchan sin avisar. Cuando un inquilino termina el contrato, se le devuelve el depósito menos cualquier deducción por daños. Implementa un sistema de estado de la propiedad que haga un seguimiento del desgaste y permita a los propietarios retener legítimamente una parte del depósito si el inquilino no cuidó la propiedad. Esto crea situaciones naturales de resolución de conflictos que impulsan el roleplay entre propietarios e inquilinos.
Precios dinámicos del mercado
Un mercado inmobiliario estático pierde rápidamente su atractivo cuando se compran todas las propiedades deseables. Los precios dinámicos mantienen el interés en el mercado al ajustar el valor de las propiedades según la actividad real del servidor. Haz un seguimiento de varios factores que influyen en el valor de un vecindario: el número de ventas recientes en la zona, la proximidad a lugares populares como centros de trabajo y tiendas, las estadísticas de delincuencia del sistema policial y la proporción general de propiedades ocupadas y vacías. Cuando un vecindario tiene una demanda alta y muchas compras recientes, el valor de las propiedades aumenta gradualmente. Esto introduce un componente especulativo en el que los primeros compradores de zonas emergentes obtienen beneficios a medida que se desarrolla el vecindario. Por el contrario, el valor baja en las zonas con mucha delincuencia o muchas propiedades vacías. Ejecuta el ajuste del mercado como una tarea programada del servidor que recalcula semanalmente el valor de todas las propiedades y aplica cambios graduales para evitar alteraciones bruscas del mercado. Muestra las tendencias del mercado en el panel NUI de la inmobiliaria para que los agentes y compradores puedan decidir con conocimiento dónde invertir.
Visitas a propiedades e interfaz NUI
La interfaz NUI es donde los agentes y compradores exploran las propiedades disponibles, consultan sus detalles e inician transacciones. Crea una página de anuncios de propiedades clara y profesional que muestre cada propiedad disponible con su foto o vista previa del interior, ubicación en el mapa, precio, número de habitaciones, capacidad del garaje y valoración del vecindario. Incluye opciones de filtrado y ordenamiento para que los usuarios puedan limitar los resultados por tipo de propiedad, rango de precios y ubicación. Cuando un agente selecciona una propiedad para una visita, el sistema debe mostrar una ruta hasta la entrada de la propiedad y avisar al comprador para que la siga. Dentro de la propiedad, ofrece un modo de visita interactivo en el que el agente pueda destacar características mediante marcadores 3D o anotaciones de texto. Después de la visita, muestra al comprador un panel de confirmación de compra o alquiler con el desglose financiero completo, incluidos el precio, los impuestos, la comisión del agente y las condiciones de la hipoteca, si corresponde. La interfaz también debe incluir una pestaña con el historial de transacciones para que los jugadores puedan consultar sus compras, ventas y pagos de alquiler anteriores con total transparencia financiera.
Personalización de propiedades y revalorización
Permitir que los propietarios personalicen sus propiedades les da un toque personal y crea una economía de mejoras que aumenta el valor de las propiedades con el tiempo. Implementa un sistema de colocación de muebles que permita a los jugadores comprar y colocar muebles dentro del interior de su propiedad, de forma similar a la personalización de apartamentos de GTA Online. Cada mueble comprado aumenta el valor mejorado de la propiedad, de modo que, cuando el propietario finalmente la venda, recupere parte de su inversión en mobiliario. Además de los muebles, ofrece mejoras estructurales como renovaciones de cocina, remodelaciones de baño e instalaciones de sistemas de seguridad que aumenten un porcentaje el valor base de la propiedad. Registra todas las mejoras en una tabla de modificaciones de propiedades para que el anuncio inmobiliario pueda mostrar a los posibles compradores exactamente qué mejoras se han realizado. Las propiedades comerciales deben admitir mejoras específicas para cada negocio, como vitrinas para una tienda, equipos de cocina para un restaurante o bastidores de servidores para una empresa tecnológica, integrando el sistema inmobiliario con el ciclo de juego empresarial en general. La combinación de dinámicas de mercado basadas en la ubicación y mejoras impulsadas por los jugadores crea un ecosistema inmobiliario atractivo en el que los bienes raíces se convierten en una estrategia legítima para generar riqueza, en lugar de ser solo un lugar donde guardar objetos y cambiarse de ropa.