using GTANetworkAPI; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using ReallifeGamemode.Database.Entities; using ReallifeGamemode.Database.Models; using ReallifeGamemode.Server.Extensions; using ReallifeGamemode.Server.Log; using ReallifeGamemode.Server.Services; using ReallifeGamemode.Server.Util; using ReallifeGamemode.Services; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Timers; namespace ReallifeGamemode.Server.Managers { public class VehicleManager : Script { public static Dictionary> lastDriversInVehicle = new Dictionary>(); private static readonly List _enabledMods = new List() { "ninef", "ninef2", "blista", "asea", "asea2", "boattrailer", "bus", "armytanker", "armytrailer", "armytrailer2", "freighttrailer", "coach", "airbus", "asterope", "airtug", "ambulance", "barracks", "barracks2", "baller", "baller2", "bjxl", "banshee", "benson", "bfinjection", "biff", "blazer", "blazer2", "blazer3", "bison", "bison2", "bison3", "boxville", "boxville2", "boxville3", "bobcatxl", "bodhi2", "buccaneer", "buffalo", "buffalo2", "bulldozer", "bullet", "blimp", "burrito", "burrito2", "burrito3", "burrito4", "burrito5", "cavalcade", "cavalcade2", "policet", "gburrito", "cablecar", "caddy", "caddy2", "camper", "carbonizzare", "cheetah", "comet2", "cogcabrio", "coquette", "cutter", "gresley", "dilettante", "dilettante2", "dune", "dune2", "hotknife", "dloader", "dubsta", "dubsta2", "dump", "rubble", "docktug", "dominator", "emperor", "emperor2", "emperor3", "entityxf", "exemplar", "elegy2", "f620", "fbi", "fbi2", "felon", "felon2", "feltzer2", "firetruk", "flatbed", "forklift", "fq2", "fusilade", "fugitive", "futo", "granger", "gauntlet", "habanero", "hauler", "handler", "infernus", "ingot", "intruder", "issi2", "Jackal", "journey", "jb700", "khamelion", "landstalker", "lguard", "manana", "mesa", "mesa2", "mesa3", "crusader", "minivan", "mixer", "mixer2", "monroe", "mower", "mule", "mule2", "oracle", "oracle2", "packer", "patriot", "pbus", "penumbra", "peyote", "phantom", "phoenix", "picador", "pounder", "police", "police4", "police2", "police3", "policeold1", "policeold2", "pony", "pony2", "prairie", "pranger", "premier", "primo", "proptrailer", "rancherxl", "rancherxl2", "rapidgt", "rapidgt2", "radi", "ratloader", "rebel", "regina", "rebel2", "rentalbus", "ruiner", "rumpo", "rumpo2", "rhino", "riot", "ripley", "rocoto", "romero", "sabregt", "sadler", "sadler2", "sandking", "sandking2", "schafter2", "schwarzer", "scrap", "seminole", "sentinel", "sentinel2", "zion", "zion2", "serrano", "sheriff", "sheriff2", "speedo", "speedo2", "stanier", "stinger", "stingergt", "stockade", "stockade3", "stratum", "sultan", "superd", "surano", "surfer", "surfer2", "surge", "taco", "tailgater", "taxi", "trash", "tractor", "tractor2", "tractor3", "graintrailer", "baletrailer", "tiptruck", "tiptruck2", "tornado", "tornado2", "tornado3", "tornado4", "tourbus", "towtruck", "towtruck2", "utillitruck", "utillitruck2", "utillitruck3", "voodoo2", "washington", "stretch", "youga", "ztype", "sanchez", "sanchez2", "scorcher", "tribike", "tribike2", "tribike3", "fixter", "cruiser", "BMX", "policeb", "akuma", "carbonrs", "bagger", "bati", "bati2", "ruffian", "daemon", "double", "pcj", "vader", "vigero", "faggio2", "hexer", "annihilator", "buzzard", "buzzard2", "cargobob", "cargobob2", "cargobob3", "skylift", "polmav", "maverick", "nemesis", "frogger", "frogger2", "cuban800", "duster", "stunt", "mammatus", "jet", "shamal", "luxor", "titan", "lazer", "cargoplane", "squalo", "marquis", "dinghy", "dinghy2", "jetmax", "predator", "tropic", "seashark", "seashark2", "submersible", "freightcar", "freight", "freightcont1", "freightcont2", "freightgrain", "tankercar", "metrotrain", "docktrailer", "trailers", "trailers2", "trailers3", "tvtrailer", "raketrailer", "tanker", "trailerlogs", "tr2", "tr3", "tr4", "trflat", "trailersmall", "velum", "adder", "voltic", "vacca", "suntrap", "submersible2", "dukes", "dukes2", "buffalo3", "dominator2", "dodo", "marshall", "blimp2", "gauntlet2", "stalion", "stalion2", "blista2", "blista3", "bifta", "speeder", "kalahari", "paradise", "btype", "jester", "turismor", "alpha", "vestra", "zentorno", "massacro", "huntley", "thrust", "rhapsody", "warrener", "blade", "glendale", "panto", "dubsta3", "pigalle", "monster", "sovereign", "innovation", "hakuchou", "furoregt", "miljet", "besra", "coquette2", "swift", "jester2", "massacro2", "ratloader2", "slamvan", "mule3", "velum2", "tanker2", "casco", "boxville4", "hydra", "insurgent", "insurgent2", "gburrito2", "technical", "dinghy3", "savage", "enduro", "guardian", "lectro", "kuruma", "kuruma2", "trash2", "barracks3", "valkyrie", "slamvan2", "swift2", "luxor2", "feltzer3", "osiris", "virgo", "windsor", "coquette3", "vindicator", "t20", "brawler", "toro", "chino", "faction", "faction2", "moonbeam", "moonbeam2", "primo2", "chino2", "buccaneer2", "voodoo", "Lurcher", "btype2", "verlierer2", "nightshade", "mamba", "limo2", "schafter3", "schafter4", "schafter5", "schafter6", "cog55", "cog552", "cognoscenti", "cognoscenti2", "baller3", "baller4", "baller5", "baller6", "toro2", "seashark3", "dinghy4", "tropic2", "speeder2", "cargobob4", "supervolito", "supervolito2", "valkyrie2", "tampa", "sultanrs", "banshee2", "btype3", "faction3", "minivan2", "sabregt2", "slamvan3", "tornado5", "virgo2", "virgo3", "nimbus", "xls", "xls2", "seven70", "fmj", "bestiagts", "pfister811", "brickade", "rumpo3", "volatus", "prototipo", "reaper", "tug", "windsor2", "lynx", "gargoyle", "tyrus", "sheava", "omnis", "le7b", "contender", "trophytruck", "trophytruck2", "rallytruck", "cliffhanger", "bf400", "tropos", "brioso", "tampa2", "tornado6", "faggio3", "faggio", "raptor", "vortex", "avarus", "sanctus", "youga2", "hakuchou2", "nightblade", "chimera", "esskey", "wolfsbane", "zombiea", "zombieb", "defiler", "daemon2", "ratbike", "shotaro", "manchez", "blazer4", "elegy", "tempesta", "italigtb", "italigtb2", "nero", "nero2", "specter", "specter2", "diablous", "diablous2", "blazer5", "ruiner2", "dune4", "dune5", "phantom2", "voltic2", "penetrator", "boxville5", "wastelander", "technical2", "fcr", "fcr2", "comet3", "ruiner3", "turismo2", "infernus2", "gp1", "ruston", "trailers4", "xa21", "caddy3", "vagner", "phantom3", "nightshark", "cheetah2", "torero", "hauler2", "trailerlarge", "technical3", "insurgent3", "apc", "tampa3", "dune3", "trailersmall2", "halftrack", "ardent", "oppressor", "vigilante", "bombushka", "alphaz1", "seabreeze", "tula", "havok", "hunter", "microlight", "rogue", "pyro", "howard", "mogul", "starling", "nokota", "molotok", "rapidgt3", "retinue", "cyclone", "visione", "z190", "viseris", "comet5", "raiden", "riata", "sc1", "autarch", "savestra", "gt500", "comet4", "neon", "sentinel3", "khanjali", "barrage", "volatol", "akula", "deluxo", "stromberg", "chernobog", "riot2", "avenger", "avenger2", "thruster", "yosemite", "hermes", "hustler", "streiter", "revolter", "pariah", "kamacho", "entity2", "cheburek", "jester3", "caracara", "hotring", "seasparrow", "flashgt", "ellie", "michelli", "fagaloa", "dominator3", "tyrant", "tezeract", "gb200", "issi3", "taipan", "blimp3", "mule4", "pounder2", "speedo4", "pbus2", "patriot2", "swinger", "terbyte", "oppressor2", "strikeforce", "menacer", "scramjet", "freecrawler", "stafford", "bruiser", "bruiser2", "bruiser3", "brutus", "brutus2", "brutus3", "cerberus", "cerberus2", "cerberus3", "clique", "deathbike", "deathbike2", "deathbike3", "deveste", "deviant", "dominator4", "dominator5", "dominator6", "impaler", "impaler2", "impaler3", "impaler4", "imperator", "imperator2", "imperator3", "issi4", "issi5", "issi6", "italigto", "monster3", "monster4", "monster5", "rcbandito", "scarab", "scarab2", "scarab3", "schlagen", "slamvan4", "slamvan5", "slamvan6", "toros", "tulip", "vamos", "zr380", "zr3802", "zr3803", "streiter2", //Mod "caracara2", "drafter", "dynasty", "emerus", "gauntlet3", "gauntlet4", "hellion", "issi7", "jugular", "krieger", "locust", "nebula", "neo", "novak", "paragon", "paragon2", "peyote2", "rrocket", "s80", "thrax", "zorrusso", "zion3", "lsfd", //Mod "lsfd2", //Mod "lsfd3", //Mod "lsfd4", //Mod "lsfd5", //Mod "lsfdtruck", //Mod "lsfdtruck2", //Mod "lsfdtruck3", //Mod "polbullet", //Mod "polbullet2", //Mod "sherbullet", //Mod "hwaybullet", //Mod "zhaba", "yosemite2", "vstr", "vagrant", "sultan2", "sugoi", "stryder", "retinue2", "rebla", "outlaw", "minitank", "komoda", "kanjo", "jb7002", "imorgon", "furia", "formula2", "formula", "everon", "asbo", "openwheel1", "openwheel2", "tigon", "landstalker2", "penumbra2", "club", "coquette4", "seminole2", "dukes3", "manana2", "peyote3", "gauntlet5", "yosemite3", "youga3", "glendale2", "alkonost", "annihilator2", "avisa", "brioso2", "dinghy5", "italirsx", "kosatka", "longfin", "manchez2", "patrolboat", "seasparrow2", "seasparrow3", "slamtruck", "squaddie", "toreador", "verus", "vetir", "veto", "veto2", "weevil", "winky", "polamggtr", //mod "newsfrog", //mod "fibn",//mod "fibg",//mod "fibd",//mod "fibs",//mod "fibc",//mod "fibn2",//mod "fibx",//mod "fibg2",//mod "fibd2",//mod "fibj",//mod "fibn3",//mod "fibr",//mod "vicechee", //mod "sheriffcoqm", //mod "polcoquette", //mod "pdrafter", //mod "pdrafter2", //mod }; private static readonly Dictionary _serverVehicles = new Dictionary(); private static readonly Dictionary lastPositions = new Dictionary(); private static DateTime lastSave = DateTime.UtcNow; private static ILogger logger = LogManager.GetLogger(); public static void CheckEnabledMods() { foreach (var name in _enabledMods) { if (_enabledMods.Where(x => x == name).Count() != 1) { NAPI.Util.ConsoleOutput($"{name} double"); } } } public static void VehicleTimerTick() { NAPI.Task.Run(() => { NAPI.Pools.GetAllVehicles().ForEach(v => { if (v.Handle.Value == 0 || v.Handle == default) { return; } Vector3 lastPosition = v.Position; if (lastPositions.ContainsKey(v.Handle)) lastPosition = lastPositions[v.Handle]; lastPositions[v.Handle] = v.Position; double distanceDriven; try { distanceDriven = v.HasSharedData("drivenDistance") ? (double)v.GetSharedData("drivenDistance") : 0D; } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { distanceDriven = 0; } double distance = lastPosition.DistanceTo(v.Position) / 1000.0; if (distance > 0.2) { lastPositions[v.Handle] = v.Position; return; } distanceDriven += distance; v.SetSharedData("drivenDistance", (float)distanceDriven); }); if (DateTime.UtcNow.Subtract(lastSave).Seconds >= 30) { lastSave = DateTime.UtcNow; // save to db using (var dbContext = new DatabaseContext()) { foreach (var key in lastPositions.Keys.ToList()) { Vehicle v = key.Entity(); if (v == null) continue; if (!v.HasSharedData("drivenDistance")) continue; ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(v, dbContext); if (sVeh == null) continue; sVeh.DistanceDriven = (float)v.GetSharedData("drivenDistance"); } dbContext.SaveChanges(); } } }); } public static void AddVehicle(ServerVehicle serverVehicle, Vehicle vehicle) { if (_serverVehicles.ContainsKey(serverVehicle.Id)) { var spawnedHandle = _serverVehicles.Where(s => s.Key == serverVehicle.Id).First().Value; logger.LogCritical("Server Vehicle {Id} already has a spawned vehicle with handle {spawnedHandle}", serverVehicle.Id, spawnedHandle); new NetHandle(_serverVehicles[serverVehicle.Id], EntityType.Vehicle).Entity().Delete(); } if (_serverVehicles.ContainsValue(vehicle.Handle.Value)) { var dbId = _serverVehicles.Where(v => v.Value == vehicle.Handle.Value).First().Key; var dbIdHandle = vehicle.Handle.Value; logger.LogCritical("Vehicle handle {handle} already belongs to server vehicle {dbIdHandle}", dbIdHandle, dbId); return; } var id = serverVehicle.Id; var handle = vehicle.Handle.Value; logger.LogInformation("Mapping server vehicle id {id} to vehicle {handle}", id, handle); _serverVehicles[serverVehicle.Id] = vehicle.Handle.Value; } internal static void DeleteVehicle(Vehicle veh) { ServerVehicle sVeh; if ((sVeh = GetServerVehicleFromVehicle(veh)) != null) { var id = sVeh.Id; var handle = veh.Handle.Value; logger.LogInformation("Deleting server vehicle {id} mapping to spawned veh {handle}", id, handle); _serverVehicles.Remove(sVeh.Id); } veh?.Delete(); } public static Vehicle GetVehicleFromHandle(ushort handle) { return NAPI.Pools.GetAllVehicles().Find(v => v.Handle.Value == handle); } public static Vehicle GetVehicleFromId(int id) { using (var dbcontext = new DatabaseContext()) { ServerVehicle sVeh = dbcontext.ServerVehicles.Where(sV => sV.Id == id).FirstOrDefault(); return GetVehicleFromServerVehicle(sVeh); } } public static Vehicle GetVehicleFromServerVehicle(ServerVehicle serverVehicle) { if (serverVehicle == null) { return null; } if (!_serverVehicles.ContainsKey(serverVehicle.Id)) { return null; } return GetVehicleFromHandle(_serverVehicles[serverVehicle.Id]); } public static ServerVehicle GetServerVehicleFromVehicle(Vehicle veh, DatabaseContext dbContext = null) { if (veh == null) { return null; } dbContext = dbContext ?? new DatabaseContext(); foreach (KeyValuePair pair in _serverVehicles) { if (pair.Value == veh.Handle.Value) { return dbContext.ServerVehicles.Find(pair.Key); } } return null; } public static bool IsValidHash(uint hash) { foreach (VehicleHash vh in Enum.GetValues(typeof(VehicleHash))) { if ((uint)vh == hash) return true; } foreach (string mod in _enabledMods) { if (NAPI.Util.GetHashKey(mod) == hash) return true; } return false; } [ServerEvent(Event.VehicleDeath)] public static void VehicleManagerVehicleDeath(Vehicle vehicle) { /* String rentCarOwner = Rentcar.mapPlayerRentcarBill.FirstOrDefault(x => x.Value.Item1 == vehicle).Key; ChatService.Broadcast("a:" + ""); if (rentCarOwner != null) { Player target = PlayerService.GetPlayerByNameOrId(rentCarOwner); Rentcar.cancelRent(target); } */ ServerVehicle serverVehicle = GetServerVehicleFromVehicle(vehicle); if (serverVehicle == null) { vehicle.Delete(); return; } InventoryManager.RemoveAllItemsfromVehicleInventory(vehicle); serverVehicle.Spawn(vehicle); } [RemoteEvent("CLIENT:setMarkerBehindVehicle")] public void setVectorBehindVehicle(Player player, int id, string jsonX, string jsonY, string jsonZ) { Vehicle vehicle = NAPI.Pools.GetAllVehicles().Find(v => v.Id == id); Vector3 vector3 = new Vector3(Convert.ToSingle((double)JsonConvert.DeserializeObject(jsonX)), Convert.ToSingle((double)JsonConvert.DeserializeObject(jsonY)), Convert.ToSingle((double)JsonConvert.DeserializeObject(jsonZ))); vehicle.AddMarkerBehind(vector3); } } }