using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using ReallifeGamemode.Database.Entities; using ReallifeGamemode.Server.Core.API; using ReallifeGamemode.Server.Types; using ReallifeGamemode.Server.Core.Extensions; using System.Linq; using ReallifeGamemode.Database.Models; using ReallifeGamemode.Server.Common; namespace ReallifeGamemode.Server.Core.Managers { public class HouseManager : Script { public static readonly Dictionary houseMarkers = new Dictionary(); private readonly Dictionary houseLabels = new Dictionary(); private readonly Dictionary houseColShapes = new Dictionary(); private readonly Dictionary houseBlips = new Dictionary(); private readonly Dictionary> playerInColShape = new Dictionary>(); public HouseManager() { EventHandler.RegisterClientEvent("House_BuyHouse", HouseManagerBuyHouseEvent); EventHandler.RegisterClientEvent("House_SetRentalFee", HouseManagerSetRentalFeeEvent); EventHandler.RegisterClientEvent("House_CancelUserRental", HouseManagerCancelUserRentalEvent); EventHandler.RegisterClientEvent("House_RentInHouse", HouseManagerRentInHouseEvent); EventHandler.RegisterClientEvent("House_CancelOwnRental", HouseManagerCancelOwnRentalEvent); EventHandler.RegisterClientEvent("House_SellHouse", HouseManagerSellHouseEvent); EventHandler.RegisterClientEvent("House_WithdrawMoney", HouseManagerWithdrawMoneyEvent); LoadHouses(); } private void LoadHouses() { using var dbContext = GetDbContext(); var houses = dbContext.Houses.Include(h => h.Owner).Include(h => h.BankAccount); foreach (House house in houses) { LoadHouse(house); } dbContext.SaveChanges(); } public void LoadHouse(House house) { Position housePos = new Position(house.X, house.Y, house.Z); playerInColShape[house.Id] = new List(); houseMarkers[house.Id] = Api.Marker.CreateMarker(MarkerType.VerticalCylinder, housePos.Subtract(new Position(0, 0, 1.7)), new Position(), new Position(), 1.6f, Color.White); string text = $"~g~Zum Verkauf~s~(ID: {house.Id})\n~s~{house.Type}\nPreis: ~y~{(house.Price == 0 ? "~r~Nicht verkäuflich" : house.Price.ToMoneyString())}"; if (house.OwnerId != null) { text = $"{house.Type}~s~ (ID: {house.Id})\n~s~Besitzer: ~y~{house.Owner.Name}"; if (house.RentalFee != 0) { text += $"\n~s~Mietpreis: ~g~{house.RentalFee.ToMoneyString()}"; } } else { //houseBlips[house.Id] = NAPI.Blip.CreateBlip(40, house.Position, 0.7f, 11, "Haus", shortRange: true); too many blips houseBlips[house.Id] = Api.Blip.CreateBlip(40, house.Position, "Haus", 11, 0.7f, shortRange: true); } houseLabels[house.Id] = Api.TextLabel.CreateTextLabel(text, housePos, 10f, 1f, 0, new Color(255, 255, 255)); if (house.Price != 0 || house.RentalFee != 0) { houseColShapes[house.Id] = Api.ColShape.CreateCyclinder(housePos.Subtract(new Position(0, 0, 2)), 4.0f, 2f); houseColShapes[house.Id].OnEntityEnter += HouseManager_OnEntityEnterColShape; houseColShapes[house.Id].OnEntityExit += HouseManager_OnEntityExitColShape; } if (house.BankAccount == null) { house.BankAccount = new HouseBankAccount(); } } private void HouseManager_OnEntityExitColShape(IColShape colShape, IPlayer client) { if (!client.IsLoggedIn() || client.IsInVehicle) return; if (!houseColShapes.ContainsValue(colShape)) { return; } int houseId = houseColShapes.Where(p => p.Value.Handle == colShape.Handle).FirstOrDefault().Key; playerInColShape[houseId].Remove(client); client.TriggerEvent("CloseHouseMenu"); } private void HouseManager_OnEntityEnterColShape(IColShape colShape, IPlayer client) { if (!client.IsLoggedIn() || client.IsInVehicle) return; if (!houseColShapes.ContainsValue(colShape)) { return; } using (var dbContext = GetDbContext()) { int houseId = houseColShapes.Where(p => p.Value.Handle == colShape.Handle).FirstOrDefault().Key; playerInColShape[houseId].Add(client); House house = GetHouseById(houseId, dbContext); User user = client.GetUser(dbContext); client.TriggerEvent("ShowHouseMenu"); SendPlayerHouseData(client, house); } } public House GetHouseById(int id, DatabaseContext dbContext) { return dbContext.Houses.Where(h => h.Id == id) .Include(h => h.Owner) .Include(h => h.Rentals) .ThenInclude(hR => hR.User) .Include(h => h.BankAccount) .FirstOrDefault(); } private void SendPlayerHouseData(IPlayer player, House house) { using var dbContext = GetDbContext(); User user = player.GetUser(dbContext); var userHouseStatus = -1; if (house.OwnerId == null) userHouseStatus = 0; else if (house.OwnerId == user?.Id) userHouseStatus = 1; else if (house.Rentals.Where(h => h.UserId == user.Id).Any()) userHouseStatus = 2; var rentals = house.Rentals; var newHouse = new { OwnerName = house.Owner?.Name, house.RentalFee, house.Price, house.Type, Rentals = rentals.Select(r => r.User.Name), house.BankAccount.Balance }; player.TriggerEvent("SetHouseData", newHouse.SerializeJson(), userHouseStatus); } public void RemoveHouse(House house) { if (houseMarkers.ContainsKey(house.Id)) { houseMarkers[house.Id].Remove(); houseMarkers.Remove(house.Id); } if (houseLabels.ContainsKey(house.Id)) { houseLabels[house.Id].Remove(); houseLabels.Remove(house.Id); } if (houseColShapes.ContainsKey(house.Id)) { houseColShapes[house.Id].Remove(); houseColShapes.Remove(house.Id); } if (houseBlips.ContainsKey(house.Id)) { houseBlips[house.Id].Remove(); houseBlips.Remove(house.Id); } foreach (IPlayer client in playerInColShape[house.Id]) { client.TriggerEvent("CloseHouseMenu"); } } public House GetNearHouse(Position position, DatabaseContext dbContext) { return dbContext.Houses .Include(h => h.Owner) .Include(h => h.BankAccount) .Include(h => h.Rentals) .ToList() .Where(h => h.Position.DistanceTo(position) < 5) .OrderBy(h => h.Position.DistanceTo(position)) .FirstOrDefault(); } public void ReloadAllHouses() { using var dbContext = GetDbContext(); foreach (House house in dbContext.Houses.Include(h => h.Owner).Include(h => h.BankAccount)) { RemoveHouse(house); LoadHouse(house); } } private void HouseManagerBuyHouseEvent(IPlayer player, params object[] args) { using var dbContext = GetDbContext(); User user = player.GetUser(dbContext, bankAccount: true); if (user.HouseId != null) { player.SendMessage("Du kann nicht mehrere Häuser besitzen", ChatPrefix.Error); return; } House house = GetNearHouse(player.Position, dbContext); var userBank = user.BankAccount; if (userBank.Balance < house.Price) { player.SendMessage($"Du hast nicht genug Geld für das Haus ({house.Price.ToMoneyString()})", ChatPrefix.Error); return; } house.Owner = user; user.House = house; userBank.Balance -= house.Price; dbContext.SaveChanges(); RemoveHouse(house); LoadHouse(house); } private void HouseManagerSetRentalFeeEvent(IPlayer player, params object[] args) { var rentalFee = args[0].ToInt(); using var dbContext = GetDbContext(); User user = player.GetUser(dbContext); if (user.HouseId == null) { player.SendMessage("Du besitzt kein Haus", ChatPrefix.Error); return; } House house = GetHouseById(user.HouseId.Value, dbContext); if (DateTime.Now - house.LastRentSetTime < TimeSpan.FromDays(7)) { DateTime newPossibility = house.LastRentSetTime.AddDays(7); string dateStr = newPossibility.ToLongDateString(); string timeStr = newPossibility.ToShortTimeString(); player.SendMessage( $"Die Miete wurde in den letzten 7 Tagen schon verändert. Die Miete kann am ~y~{dateStr} um {timeStr}~s~ Uhr wieder geändert werden.", ChatPrefix.Info); return; } if (rentalFee < 0) { player.SendNotification("~r~Die Miete darf kein negativer Betrag sein!"); return; } if (rentalFee > 5000) { player.SendNotification($"~r~Die Miete darf einen Preis von {5000.ToMoneyString()} nicht überschreiten!"); return; } house.LastRentSetTime = DateTime.Now; house.RentalFee = rentalFee; dbContext.SaveChanges(); player.SendNotification($"Der Mietpreis wurde auf ~g~{rentalFee.ToMoneyString()}~s~ gesetzt"); RemoveHouse(house); LoadHouse(house); } private void HouseManagerCancelUserRentalEvent(IPlayer player, params object[] args) { string userName = args[0] as string; using var dbContext = GetDbContext(); User user = player.GetUser(dbContext); if (user.HouseId == null) { player.SendMessage("Du besitzt kein Haus", ChatPrefix.Error); return; } User target = dbContext.Users.Where(u => u.Name == userName).FirstOrDefault(); if (target == null) { player.SendNotification("~r~Dieser Spieler wurde nicht gefunden."); return; } House house = GetHouseById(user.HouseId.Value, dbContext); HouseRental rental = house.Rentals.Where(h => h.UserId == target.Id).FirstOrDefault(); if (rental == null) { player.SendNotification("~r~Der Spieler ist nicht in deinem Haus eingemietet"); return; } house.Rentals.Remove(rental); dbContext.SaveChanges(); target.NewPlayer?.SendNotification($"~y~{player.Name}~s~ hat deinen Mietvertrag ~g~gekündigt~s~."); player.SendNotification("Du hast dem Spieler ~y~" + target.Name + "~s~ den Mietvertrag gekündigt."); SendPlayerHouseData(player, house); } private void HouseManagerRentInHouseEvent(IPlayer player, params object[] args) { using var dbContext = GetDbContext(); User user = player.GetUser(dbContext); House house = GetNearHouse(player.Position, dbContext); if (house == null) { player.SendMessage("In deiner Nähe ist kein Haus", ChatPrefix.Error); return; } if (house.RentalFee == 0) { player.SendMessage("Dieses Haus hat keinen Platz für Mieter", ChatPrefix.Error); return; } HouseRental newRental = new HouseRental { HouseId = house.Id, UserId = user.Id }; house.Rentals.Add(newRental); dbContext.SaveChanges(); player.SendNotification("~g~Du hast dich in das Haus eingemietet"); house.Owner?.NewPlayer?.SendNotification($"~y~{player.Name}~s~ hat sich in dein Haus eingemietet."); SendPlayerHouseData(player, house); } private void HouseManagerCancelOwnRentalEvent(IPlayer player, params object[] args) { using var dbContext = GetDbContext(); User user = player.GetUser(dbContext); House house = GetNearHouse(player.Position, dbContext); if (house == null) { player.SendMessage("In deiner Nähe ist kein Haus", ChatPrefix.Error); return; } HouseRental rental = house.Rentals.Where(h => h.UserId == user.Id).FirstOrDefault(); if (rental == null) { player.SendNotification("~r~Du bist nin diesem Haus nicht eingemietet"); return; } house.Rentals.Remove(rental); dbContext.SaveChanges(); player.SendNotification("~g~Du hast den Mietvertrag gekündigt."); house.Owner?.NewPlayer?.SendNotification($"~y~{player.Name}~s~ hat seinen Mietvertrag gekündigt."); RemoveHouse(house); LoadHouse(house); SendPlayerHouseData(player, house); } private void HouseManagerSellHouseEvent(IPlayer player, params object[] args) { using var dbContext = GetDbContext(); User user = player.GetUser(dbContext, bankAccount: true); if (user.HouseId == null) { player.SendMessage("Du besitzt kein Haus", ChatPrefix.Error); return; } House house = GetHouseById(user.HouseId.Value, dbContext); house.OwnerId = null; user.HouseId = null; house.LastRentSetTime = DateTime.Now.Subtract(TimeSpan.FromDays(7)); house.BankAccount.Balance = 0; var backMoney = (int)(house.Price * 0.4); player.SendMessage("Du bekommst vom Hausverkauf ~g~" + backMoney.ToMoneyString() + "~s~ zurück."); user.BankAccount.Balance += backMoney; dbContext.HouseRentals.RemoveRange(house.Rentals); dbContext.SaveChanges(); player.SendMessage("!{#81F7BE}* Du hast dein Haus verkauft."); RemoveHouse(house); LoadHouse(house); SendPlayerHouseData(player, house); } private void HouseManagerWithdrawMoneyEvent(IPlayer player, object[] args) { var amount = args[0].ToInt(); if (amount <= 0) { player.SendMessage("Du musst mindestens 1$ abheben", ChatPrefix.Error); return; } using var dbContext = GetDbContext(); User user = player.GetUser(dbContext, bankAccount: true); if (user.HouseId == null) { player.SendMessage("Du besitzt kein Haus", ChatPrefix.Error); return; } House house = GetHouseById(user.HouseId.Value, dbContext); if (house.BankAccount.Balance < amount) { player.SendMessage("Auf dem Konto deines Hauses ist nicht genug Geld", ChatPrefix.Error); return; } user.BankAccount.Balance += amount; house.BankAccount.Balance -= amount; dbContext.SaveChanges(); player.SendMessage($"Du hast {amount.ToMoneyString()} von dem Konto deines Hauses abgehoben", ChatPrefix.Info); SendPlayerHouseData(player, house); } } }