diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fb381229..b76b47a1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,9 +5,12 @@ before_script: - "../gm_database_password.sh" - "dotnet restore" +variables: + GIT_STRATEGY: clone + build: stage: build only: - - develop + - develop@log-gtav/reallife-gamemode script: - "dotnet build -c ServerBuild" diff --git a/Client/Player/keys.js b/Client/Player/keys.js index 3a080e13..91ec623b 100644 --- a/Client/Player/keys.js +++ b/Client/Player/keys.js @@ -10,6 +10,8 @@ var chat = false; var showInventory = false; var showGui = true; +const player = mp.players.local; + //ENTER mp.keys.bind(0x0D, false, function () { if (chat === true) { @@ -74,6 +76,8 @@ mp.keys.bind(0x4C, false, function () { //N //Motor Starten mp.keys.bind(0x4E, false, function () { if (!chat) { + if (!player.vehicle) return; + if (player.vehicle.getSpeed() > 5) return; mp.events.callRemote("keyPress:N"); } }); diff --git a/Client/Tuning/main.js b/Client/Tuning/main.js index 185df4a1..30355d12 100644 --- a/Client/Tuning/main.js +++ b/Client/Tuning/main.js @@ -194,7 +194,7 @@ mp.events.add("showTuningMenu", () => { var menuItem = new UIMenuItem(slotName); - if(localVehicle.getNumMods(modType) !== 0) mainMenu.AddItem(menuItem); + if(localVehicle.getNumMods(modType) !== 0 || modType === 18 || modType === 22) mainMenu.AddItem(menuItem); } }); @@ -217,9 +217,15 @@ mp.events.add("showTuningMenu", () => { } var currentMod = localVehicle.getMod(modSlot); + var oldToggleValue; + if (modSlot === 18 || modSlot === 22) { + oldToggleValue = localVehicle.isToggleModOn(modSlot); + currentMod = oldToggleValue ? 0 : -1; + } var currentModItem; var modNum = localVehicle.getNumMods(modSlot); + if (modSlot === 18 || modSlot === 22) modNum = 1; modMenu = new Menu(item.Text, "Änderung: " + item.Text, new Point(50, 50)); @@ -230,6 +236,10 @@ mp.events.add("showTuningMenu", () => { modItem = new UIMenuItem("Serie", ""); } else { var modName = getModName(localVehicle, modSlot, i); + + if (modSlot === 18) modName = "Turbolader"; + if (modSlot === 22) modName = "Xenon-Licht"; + modItem = new UIMenuItem(modName, ""); } @@ -251,11 +261,21 @@ mp.events.add("showTuningMenu", () => { currentModItem = selectedItem; } mp.events.callRemote("setVehicleMod", modSlot, index); + + if (modSlot === 18 || modSlot === 22) { + oldToggleValue = index === 0 ? false : true; + return; + } + if (index === 0) index = -1; currentMod = index - 1; }); modMenu.IndexChange.on((index) => { + if (modSlot === 18 || modSlot === 22) { + localVehicle.toggleMod(modSlot, index === 0 ? false : true); + return; + } if (index === 0) index = -1; localVehicle.setMod(modSlot, index - 1); }); @@ -269,8 +289,6 @@ mp.events.add("showTuningMenu", () => { localVehicle.setDoorShut(door, false); } - localVehicle.setMod(modSlot, currentMod); - if (closeMenu) { closeMenu = false; return; @@ -278,6 +296,13 @@ mp.events.add("showTuningMenu", () => { mainMenu.Visible = true; modMenu.Visible = false; + + if (modSlot === 18 || modSlot === 22) { + oldToggleValue = (oldToggleValue === false) ? 0 : 1; + localVehicle.toggleMod(modSlot, oldToggleValue === 0 ? false : true); + return; + } + localVehicle.setMod(modSlot, currentMod); }); mainMenu.Visible = false; @@ -292,7 +317,9 @@ mp.events.add("showTuningMenu", () => { }); mp.events.add("playerLeaveVehicle", () => { - mp.events.call("hideTuningInfo", true); + if (keyBound) { + mp.events.call("hideTuningInfo", true); + } }); function getSlotName(slot) { diff --git a/Client/Tuning/sirensilence.js b/Client/Tuning/sirensilence.js new file mode 100644 index 00000000..3d066623 --- /dev/null +++ b/Client/Tuning/sirensilence.js @@ -0,0 +1,15 @@ +mp.keys.bind(0x42, true, _ => { + mp.events.callRemote("keyPress:B:toggleSiren"); +}); + +mp.events.add('toggleVehicleSiren', (vehicle, state) => { + vehicle.setSirenSound(state); +}); + +mp.events.add('entityStreamIn', (entity) => { + if (entity.isAVehicle()) { + var state = entity.getVariable("sirenSound"); + if (state === undefined) return; + entity.setSirenSound(state); + } +}); \ No newline at end of file diff --git a/Client/Tuning/sync.js b/Client/Tuning/sync.js index 24baf472..bee8e5a0 100644 --- a/Client/Tuning/sync.js +++ b/Client/Tuning/sync.js @@ -1,4 +1,18 @@ mp.events.add('entityStreamIn', (entity) => { - mp.gui.chat.push("streamed in:"); - mp.gui.chat.push(entity.Model); + if (entity.isAVehicle()) { + var mod18 = entity.getVariable('mod18'); + var mod22 = entity.getVariable('mod22'); + + if (mod18 !== undefined) { + entity.toggleMod(18, mod18); + } + + if (mod22 !== undefined) { + entity.toggleMod(22, mod22); + } + } +}); + +mp.events.add('vehicleToggleMod', (veh, slot, newval) => { + veh.toggleMod(slot, newval); }); \ No newline at end of file diff --git a/Client/index.js b/Client/index.js index 9aec4035..9d437a43 100644 --- a/Client/index.js +++ b/Client/index.js @@ -30,11 +30,14 @@ require('./Player/keys.js'); require('./Player/quit.js'); require('./Player/freecam.js'); +require('./vehiclesync/vehiclesync.js'); + require('./Save/main.js'); require('./Speedometer/index.js'); require('./Tuning/main.js'); require('./Tuning/sync.js'); +require('./Tuning/sirensilence.js'); require('./Business/main.js'); diff --git a/Client/vehiclesync/vehiclesync.js b/Client/vehiclesync/vehiclesync.js new file mode 100644 index 00000000..d2289dc2 --- /dev/null +++ b/Client/vehiclesync/vehiclesync.js @@ -0,0 +1,532 @@ +//Disapproved by the entire planet +//You don't need to worry about anything here + +mp.events.add("VehStream_SetEngineStatus", (veh, status) => { + if (veh !== undefined) { + if (veh.isSeatFree(-1)) //Turns engine on instantly if no driver, otherwise it will not turn on + { + veh.setEngineOn(status, true, false); + veh.setUndriveable(true); + } + else { + veh.setEngineOn(status, false, true); + veh.setUndriveable(!status); + } + } +}); + +mp.events.add("VehStream_SetLockStatus", (veh, status) => { + if (veh !== undefined) { + if (status) + veh.setDoorsLocked(2); + else + veh.setDoorsLocked(1); + } +}); + +mp.events.add("VehStream_PlayerEnterVehicleAttempt", (entity, seat) => { + if (typeof entity.getVariable("VehicleSyncData") !== 'undefined') { + var toggle = entity.getVariable("VehicleSyncData"); + entity.setEngineOn(toggle.Engine, false, true); + entity.setUndriveable(!toggle.Engine); + } +}); + +mp.events.add("VehStream_PlayerExitVehicleAttempt", (entity) => { + if (entity !== undefined) { + if (typeof entity.getVariable("VehicleSyncData") !== 'undefined') { + var toggle = entity.getVariable("VehicleSyncData"); + entity.setEngineOn(toggle.Engine, true, false); + entity.setUndriveable(!toggle.Engine); + } + + var level = entity.getDirtLevel(); + mp.events.callRemote("VehStream_SetDirtLevel", entity, level); + } +}); + +mp.events.add("VehStream_PlayerExitVehicle", (entity) => { + setTimeout(() => { + var Status = []; + let y = 0; + for (y = 0; y < 8; y++) { + if (entity.isDoorDamaged(y)) { + Status.push(2); + } + else if (entity.getDoorAngleRatio(y) > 0.15) { + Status.push(1); + } + else { + Status.push(0); + } + } + mp.events.callRemote("VehStream_SetDoorData", entity, Status[0], Status[1], Status[2], Status[3], Status[4], Status[5], Status[6], Status[7]); + + Status = []; + if (entity.isWindowIntact(0)) { + if (entity.getBoneIndexByName("window_rf") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + if (entity.isWindowIntact(1)) { + if (entity.getBoneIndexByName("window_lf") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + if (entity.isWindowIntact(2)) { + if (entity.getBoneIndexByName("window_rr") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + if (entity.isWindowIntact(3)) { + if (entity.getBoneIndexByName("window_lr") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + mp.events.callRemote("VehStream_SetWindowData", entity, Status[0], Status[1], Status[2], Status[3]); + + Status = []; + if (!entity.isTyreBurst(0, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(0, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(1, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(1, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(2, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(2, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(3, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(3, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(4, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(4, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(5, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(5, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(6, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(6, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(7, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(7, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(45, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(45, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + if (!entity.isTyreBurst(47, false)) { + Status.push(0); + } + else if (entity.isTyreBurst(47, false)) { + Status.push(1); + } + else { + Status.push(2); + } + + mp.events.callRemote("VehStream_SetWheelData", entity, Status[0], Status[1], Status[2], Status[3], Status[4], Status[5], Status[6], Status[7], Status[8], Status[9]); + }, 2500); +}); + +mp.events.add("VehStream_PlayerEnterVehicleAttempt", (entity, seat) => { + setTimeout(() => { + var Status = []; + let y = 0; + for (y = 0; y < 8; y++) { + if (entity.isDoorDamaged(y)) { + Status.push(2); + } + else if (entity.getDoorAngleRatio(y) > 0.15) { + Status.push(1); + } + else { + Status.push(0); + } + } + //mp.events.callRemote("VehStream_SetDoorData", entity, Status[0], Status[1], Status[2], Status[3], Status[4], Status[5], Status[6], Status[7]); + + Status = []; + if (entity.isWindowIntact(0)) { + if (entity.getBoneIndexByName("window_rf") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + if (entity.isWindowIntact(1)) { + if (entity.getBoneIndexByName("window_lf") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + if (entity.isWindowIntact(2)) { + if (entity.getBoneIndexByName("window_rr") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + if (entity.isWindowIntact(3)) { + if (entity.getBoneIndexByName("window_lr") === -1) { + Status.push(1); + } + else { + Status.push(0); + } + } + else { + Status.push(2); + } + mp.events.callRemote("VehStream_SetWindowData", entity, Status[0], Status[1], Status[2], Status[3]); + }, 3000); +}); + +mp.events.add("VehStream_SetVehicleDirtLevel", (entity, dirt) => { + if (entity !== undefined) { + entity.setDirtLevel(dirt); + } +}); + +mp.events.add("VehStream_SetVehicleDoorStatus_Single", (veh, door, state) => { + if (veh !== undefined) { + if (state === 0) { + veh.setDoorShut(door, false); + } + else if (state === 1) { + veh.setDoorOpen(door, false, false); + } + else { + veh.setDoorBroken(door, true); + } + } +}); + +mp.events.add("VehStream_SetVehicleDoorStatus", (...args) => { + if (args[0] !== undefined) { + let y = 0; + for (y = 1; y < args.length; y++) { + if (args[y] === 0) { + args[0].setDoorShut(y - 1, false); + } + else if (args[y] === 1) { + args[0].setDoorOpen(y - 1, false, false); + } + else { + args[0].setDoorBroken(y - 1, true); + } + } + } +}); + +mp.events.add("VehStream_SetVehicleWindowStatus_Single", (veh, windw, state) => { + if (veh !== undefined) { + if (state === 1) { + veh.rollDownWindow(windw); + } + else if (state === 0) { + veh.fixWindow(windw); + veh.rollUpWindow(windw); + } + else { + veh.smashWindow(windw); + } + } +}); + +mp.events.add("VehStream_SetVehicleWindowStatus", (...args) => { + if (args[0] !== undefined) { + let y = 0; + for (y = 1; y < 4; y++) { + if (args[y] === 1) { + args[0].rollDownWindow(y - 1); + } + else if (args[y] === 0) { + args[0].fixWindow(y - 1); + args[0].rollUpWindow(y - 1); + } + else { + args[0].smashWindow(y - 1); + } + } + } +}); + +mp.events.add("VehStream_SetVehicleWheelStatus_Single", (veh, wheel, state) => { + if (veh !== undefined) { + if (wheel === 9) { + if (state === 1) { + veh.setTyreBurst(45, false, 1000); + } + else if (state === 0) { + veh.setTyreFixed(45); + } + else { + veh.setTyreBurst(45, true, 1000); + } + } + else if (wheel === 10) { + if (state === 1) { + veh.setTyreBurst(47, false, 1000); + } + else if (state === 0) { + veh.setTyreFixed(47); + } + else { + veh.setTyreBurst(47, true, 1000); + } + } + else { + if (state === 1) { + veh.setTyreBurst(wheel, false, 1000); + } + else if (state === 0) { + veh.setTyreFixed(wheel); + } + else { + veh.setTyreBurst(wheel, true, 1000); + } + } + } +}); + +mp.events.add("VehStream_SetVehicleWheelStatus", (...args) => { + if (args[0] !== undefined) { + let y = 0; + for (y = 1; y < args.length; y++) { + if (y === 9) { + if (args[y] === 1) { + args[0].setTyreBurst(45, false, 1000); + } + else if (args[y] === 0) { + args[0].setTyreFixed(45); + } + else { + args[0].setTyreBurst(45, true, 1000); + } + } + else if (y === 10) { + if (args[y] === 1) { + args[0].setTyreBurst(47, false, 1000); + } + else if (args[y] === 0) { + args[0].setTyreFixed(47); + } + else { + args[0].setTyreBurst(47, true, 1000); + } + } + else { + if (args[y] === 1) { + args[0].setTyreBurst(y - 1, false, 1000); + } + else if (args[y] === 0) { + args[0].setTyreFixed(y - 1); + } + else { + args[0].setTyreBurst(y - 1, true, 1000); + } + } + } + } +}); + +//Sync data on stream in +mp.events.add("entityStreamIn", (entity) => { + if (entity.type === "vehicle") { + let typeor = typeof entity.getVariable('VehicleSyncData'); + let actualData = entity.getVariable('VehicleSyncData'); + + //Needed to stop vehicles from freaking out + mp.game.streaming.requestCollisionAtCoord(entity.position.x, entity.position.y, entity.position.z); + //mp.game.invoke('0x199640F55E0F7596', entity.position.x, entity.position.y, entity.position.z); + entity.setLoadCollisionFlag(true); + entity.trackVisibility(); + + if (typeor !== 'undefined' && entity.isSeatFree(-1)) //Only if there is no driver + { + entity.position = actualData.Position; + entity.rotation = actualData.Rotation; + } + + //Set doors unbreakable for a moment + let x = 0; + for (x = 0; x < 8; x++) { + entity.setDoorBreakable(x, false); + } + + //Do it anyway + entity.setUndriveable(true); + + if (typeor !== 'undefined') { + entity.setEngineOn(actualData.Engine, true, false); + entity.setUndriveable(true); + + if (actualData.Locked) + entity.setDoorsLocked(2); + else + entity.setDoorsLocked(1); + + entity.setDirtLevel(actualData.Dirt); + + for (x = 0; x < 8; x++) { + if (actualData.Door[x] === 1) + entity.setDoorOpen(x, false, false); + else if (actualData.Door[x] === 0) + entity.setDoorShut(x, true); + else + entity.setDoorBroken(x, true); + } + + for (x = 0; x < 4; x++) { + if (actualData.Window[x] === 0) { + entity.fixWindow(x); + } + else if (actualData.Window[x] === 1) { + entity.rollDownWindow(x); + } + else { + entity.smashWindow(x); + } + } + + for (x = 0; x < 8; x++) { + if (actualData.Wheel[x] === 0) { + entity.setTyreFixed(x); + } + else if (actualData.Wheel[x] === 1) { + entity.setTyreBurst(x, false, 0); + } + else { + entity.setTyreBurst(x, true, 1000); + } + } + + //For trailer mid wheels + if (actualData.Wheel[8] === 0) { + entity.setTyreFixed(45); + } + else if (actualData.Wheel[8] === 1) { + entity.setTyreBurst(45, false, 0); + } + else { + entity.setTyreBurst(45, true, 1000); + } + + if (actualData.Wheel[9] === 0) { + entity.setTyreFixed(47); + } + else if (actualData.Wheel[9] === 1) { + entity.setTyreBurst(47, false, 0); + } + else { + entity.setTyreBurst(47, true, 1000); + } + } + + //Make doors breakable again + setTimeout(() => { + for (x = 0; x < 8; x++) { + entity.setDoorBreakable(x, true); + } + }, 1500); + } +}); \ No newline at end of file diff --git a/Main.cs b/Main.cs index fd195039..3f03b549 100644 --- a/Main.cs +++ b/Main.cs @@ -35,10 +35,17 @@ namespace reallife_gamemode NAPI.Server.SetAutoRespawnAfterDeath(false); NAPI.Data.SetWorldData("playerCreatorDimension", 0); + InventoryManager.LoadItems(); TuningManager.AddTuningGarage(new Vector3(-341, -134, 38.5)); TuningManager.AddTuningGarage(new Vector3(732, -1088, 21)); TuningManager.AddTuningGarage(new Vector3(-1155, -2006, 12)); + TuningManager.AddTuningGarage(new Vector3(-341, -134, 38.5)); // Downtown LS + TuningManager.AddTuningGarage(new Vector3(732, -1088, 21)); // LS Intersection + TuningManager.AddTuningGarage(new Vector3(-1155, -2006, 12)); // LS Airport + TuningManager.AddTuningGarage(new Vector3(110, 6628, 31)); // Paleto Bay + TuningManager.AddTuningGarage(new Vector3(1175, 2639, 37)); // Route 69 + TimeManager.StartTimeManager(); DatabaseHelper.InitDatabaseFirstTime(); diff --git a/Server/Commands/Admin.cs b/Server/Commands/Admin.cs index 993f2870..1fdf724d 100644 --- a/Server/Commands/Admin.cs +++ b/Server/Commands/Admin.cs @@ -854,6 +854,14 @@ namespace reallife_gamemode.Server.Commands #region ALevel3 + Vehicle testV; + + [Command] + public void Testveh(Client player) + { + player.SendChatMessage(VehicleStreaming.GetEngineState(player.Vehicle).ToString()); + } + [Command("veh", "~m~Benutzung: ~s~/veh [Fahrzeug] (Farbe 1) (Farbe 2)")] public void CmdAdminVeh(Client player, string hash, int color1 = 111, int color2 = 111) { @@ -878,7 +886,9 @@ namespace reallife_gamemode.Server.Commands return; } - Vehicle v = NAPI.Vehicle.CreateVehicle(uHash, player.Position, player.Rotation.Z, color1, color2); + Vehicle v = testV = NAPI.Vehicle.CreateVehicle(uHash, player.Position, player.Rotation.Z, color1, color2, engine: false); + VehicleStreaming.SetEngineState(v, true); + VehicleStreaming.SetLockStatus(v, false); player.SetIntoVehicle(v.Handle, -1); } diff --git a/Server/Entities/ServerVehicle.cs b/Server/Entities/ServerVehicle.cs index ce4ba97f..ae98baa0 100644 --- a/Server/Entities/ServerVehicle.cs +++ b/Server/Entities/ServerVehicle.cs @@ -1,6 +1,8 @@ using GTANetworkAPI; using reallife_gamemode.Model; +using reallife_gamemode.Server.Extensions; using reallife_gamemode.Server.Managers; +using reallife_gamemode.Server.Util; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -34,6 +36,8 @@ namespace reallife_gamemode.Server.Entities { if (currentVeh != null) VehicleManager.DeleteVehicle(currentVeh); Vehicle veh = NAPI.Vehicle.CreateVehicle(this.Model, this.Position, this.Heading, this.PrimaryColor, this.SecondaryColor, this.NumberPlate, locked: this.Locked, engine: false); + VehicleStreaming.SetEngineState(veh, false); + VehicleStreaming.SetLockStatus(veh, false); VehicleManager.AddVehicle(this, veh); string numberplate = $"{this.Id}"; diff --git a/Server/Events/Key.cs b/Server/Events/Key.cs index a7ff73d1..9d881657 100644 --- a/Server/Events/Key.cs +++ b/Server/Events/Key.cs @@ -122,10 +122,12 @@ namespace reallife_gamemode.Server.Events foreach(Client listPlayer in players) { - var lPlayer = new ListPlayer(); - lPlayer.Id = listPlayer.Handle.Value; - lPlayer.Name = listPlayer.Name; - lPlayer.Ping = listPlayer.Ping; + var lPlayer = new ListPlayer + { + Id = listPlayer.Handle.Value, + Name = listPlayer.Name, + Ping = listPlayer.Ping + }; ListPlayers.Add(lPlayer); } @@ -196,7 +198,8 @@ namespace reallife_gamemode.Server.Events if (!player.IsLoggedIn()) return; if (player.IsInVehicle && player.VehicleSeat == -1) { - player.Vehicle.EngineStatus = !player.Vehicle.EngineStatus; + Vehicle v = player.Vehicle; + VehicleStreaming.SetEngineState(v, !VehicleStreaming.GetEngineState(v)); } } [RemoteEvent("keyPress:X")] diff --git a/Server/Events/Siren.cs b/Server/Events/Siren.cs new file mode 100644 index 00000000..7c542eb4 --- /dev/null +++ b/Server/Events/Siren.cs @@ -0,0 +1,26 @@ +using GTANetworkAPI; +using System; +using System.Collections.Generic; +using System.Text; + +namespace reallife_gamemode.Server.Events +{ + class Siren : Script + { + private Dictionary _sirenStates = new Dictionary(); + + [RemoteEvent("keyPress:B:toggleSiren")] + public void ToggleSirenEvent(Client player) + { + if (!player.IsInVehicle || player.VehicleSeat != -1) return; + Vehicle pV = player.Vehicle; + bool oldValue = _sirenStates.ContainsKey(pV.Handle) ? _sirenStates[pV.Handle] : false; + bool newValue = !oldValue; + + _sirenStates[pV.Handle] = newValue; + pV.SetSharedData("sirenSound", newValue); + + NAPI.ClientEvent.TriggerClientEventForAll("toggleVehicleSiren", pV, newValue); + } + } +} diff --git a/Server/Managers/TuningManager.cs b/Server/Managers/TuningManager.cs index 5318d077..7e0a7089 100644 --- a/Server/Managers/TuningManager.cs +++ b/Server/Managers/TuningManager.cs @@ -45,10 +45,18 @@ namespace reallife_gamemode.Server.Managers Vehicle veh = VehicleManager.GetVehicleFromServerVehicle(sVeh); if (veh == null) return; - using(var dbContext = new DatabaseContext()) + + veh.SetSharedData("mod18", false); + veh.SetSharedData("mod22", false); + + using (var dbContext = new DatabaseContext()) { foreach(VehicleMod vMod in dbContext.VehicleMods.ToList().FindAll(vM => vM.ServerVehicleId == sVeh.Id)) { + if(vMod.Slot == 18 || vMod.Slot == 22) + { + veh.SetSharedData("mod" + vMod.Slot, true); + } veh.SetMod(vMod.Slot, vMod.ModId - 1); } } @@ -72,8 +80,19 @@ namespace reallife_gamemode.Server.Managers [RemoteEvent("setVehicleMod")] public void SetVehicleMod(Client player, int slot, int index) { + Vehicle pV = player.Vehicle; if (index == 0) index--; - player.Vehicle.SetMod(slot, index - 1); + + if(slot != 18 && slot != 22) + { + pV.SetMod(slot, index - 1); + } + else + { + bool newVal = index == -1 ? false : true; + pV.SetSharedData("mod" + slot, newVal); + NAPI.ClientEvent.TriggerClientEventForAll("vehicleToggleMod", pV, slot, newVal); + } ServerVehicle sV = player.Vehicle.GetServerVehicle(); if (sV == null) return; diff --git a/Server/Util/VehicleSync.cs b/Server/Util/VehicleSync.cs new file mode 100644 index 00000000..152405d3 --- /dev/null +++ b/Server/Util/VehicleSync.cs @@ -0,0 +1,444 @@ +using GTANetworkAPI; +using Newtonsoft.Json.Linq; + +//Disapproved by god himself + +//Just use the API functions, you have nothing else to worry about + +//Things to note +//More things like vehicle mods will be added in the next version + +/* API FUNCTIONS: +public static void SetVehicleWindowState(Vehicle veh, WindowID window, WindowState state) +public static WindowState GetVehicleWindowState(Vehicle veh, WindowID window) +public static void SetVehicleWheelState(Vehicle veh, WheelID wheel, WheelState state) +public static WheelState GetVehicleWheelState(Vehicle veh, WheelID wheel) +public static void SetVehicleDirt(Vehicle veh, float dirt) +public static float GetVehicleDirt(Vehicle veh) +public static void SetDoorState(Vehicle veh, DoorID door, DoorState state) +public static DoorState GetDoorState(Vehicle veh, DoorID door) +public static void SetEngineState(Vehicle veh, bool status) +public static bool GetEngineState(Vehicle veh) +public static void SetLockStatus(Vehicle veh, bool status) +public static bool GetLockState(Vehicle veh) +*/ + +namespace reallife_gamemode.Server.Util +{ + //Enums for ease of use + public enum WindowID + { + WindowFrontRight, + WindowFrontLeft, + WindowRearRight, + WindowRearLeft + } + + public enum WindowState + { + WindowFixed, + WindowDown, + WindowBroken + } + + public enum DoorID + { + DoorFrontLeft, + DoorFrontRight, + DoorRearLeft, + DoorRearRight, + DoorHood, + DoorTrunk + } + + public enum DoorState + { + DoorClosed, + DoorOpen, + DoorBroken, + } + + public enum WheelID + { + Wheel0, + Wheel1, + Wheel2, + Wheel3, + Wheel4, + Wheel5, + Wheel6, + Wheel7, + Wheel8, + Wheel9 + } + + public enum WheelState + { + WheelFixed, + WheelBurst, + WheelOnRim, + } + + public class VehicleStreaming : Script + { + //This is the data object which will be synced to vehicles + public class VehicleSyncData + { + //Used to bypass some streaming bugs + public Vector3 Position { get; set; } = new Vector3(); + public Vector3 Rotation { get; set; } = new Vector3(); + + //Basics + public float Dirt { get; set; } = 0.0f; + public bool Locked { get; set; } = true; + public bool Engine { get; set; } = false; + + //(Not synced) + public float BodyHealth { get; set; } = 1000.0f; + public float EngineHealth { get; set; } = 1000.0f; + + //Doors 0-7 (0 = closed, 1 = open, 2 = broken) (This uses enums so don't worry about it) + public int[] Door { get; set; } = new int[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; + + //Windows (0 = up, 1 = down, 2 = smashed) (This uses enums so don't worry about it) + public int[] Window { get; set; } = new int[4] { 0, 0, 0, 0 }; + + //Wheels 0-7, 45/47 (0 = fixed, 1 = flat, 2 = missing) (This uses enums so don't worry about it) + public int[] Wheel { get; set; } = new int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + } + + //API functions for people to use + public static void SetVehicleWindowState(Vehicle veh, WindowID window, WindowState state) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) //If data doesn't exist create a new one. This is the process for all API functions + data = new VehicleSyncData(); + + data.Window[(int)window] = (int)state; + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleWindowStatus_Single", veh.Handle, (int)window, (int)state); + } + + public static WindowState GetVehicleWindowState(Vehicle veh, WindowID window) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + { + data = new VehicleSyncData(); + UpdateVehicleSyncData(veh, data); + } + return (WindowState)data.Window[(int)window]; + } + + public static void SetVehicleWheelState(Vehicle veh, WheelID wheel, WheelState state) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Wheel[(int)wheel] = (int)state; + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleWheelStatus_Single", veh.Handle, (int)wheel, (int)state); + } + + public static WheelState GetVehicleWheelState(Vehicle veh, WheelID wheel) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + { + data = new VehicleSyncData(); + UpdateVehicleSyncData(veh, data); + } + return (WheelState)data.Wheel[(int)wheel]; + } + + public static void SetVehicleDirt(Vehicle veh, float dirt) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Dirt = dirt; + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleDirtLevel", veh.Handle, dirt); + } + + public static float GetVehicleDirt(Vehicle veh) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + { + data = new VehicleSyncData(); + UpdateVehicleSyncData(veh, data); + } + return data.Dirt; + } + + public static void SetDoorState(Vehicle veh, DoorID door, DoorState state) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Door[(int)door] = (int)state; + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleDoorStatus_Single", veh, (int)door, (int)state); + } + + public static DoorState GetDoorState(Vehicle veh, DoorID door) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + { + data = new VehicleSyncData(); + UpdateVehicleSyncData(veh, data); + } + return (DoorState)data.Door[(int)door]; + } + + public static void SetEngineState(Vehicle veh, bool status) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Engine = status; + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetEngineStatus", veh, status); + } + + public static bool GetEngineState(Vehicle veh) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + { + data = new VehicleSyncData(); + UpdateVehicleSyncData(veh, data); + } + return data.Engine; + } + + public static void SetLockStatus(Vehicle veh, bool status) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Locked = status; + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetLockStatus", veh, status); + } + + public static bool GetLockState(Vehicle veh) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + { + data = new VehicleSyncData(); + UpdateVehicleSyncData(veh, data); + } + return data.Locked; + } + + //Used internally only but publicly available in case any of you need it + public static VehicleSyncData GetVehicleSyncData(Vehicle veh) + { + if (veh != null) + { + if (NAPI.Entity.DoesEntityExist(veh)) + { + if (NAPI.Data.HasEntitySharedData(veh.Handle, "VehicleSyncData")) + { + //API converts class objects to JObject so we have to change it back + JObject obj = NAPI.Data.GetEntitySharedData(veh.Handle, "VehicleSyncData"); + return obj.ToObject(); + } + } + } + + return default(VehicleSyncData); //null + } + + //Used internally only but publicly available in case any of you need it + public static bool UpdateVehicleSyncData(Vehicle veh, VehicleSyncData data) + { + if (veh != null) + { + if (NAPI.Entity.DoesEntityExist(veh)) + { + if (data != null) + { + data.Position = veh.Position; + data.Rotation = veh.Rotation; + NAPI.Data.SetEntitySharedData(veh, "VehicleSyncData", data); + return true; + } + } + } + return false; + } + + //Called from the client to sync dirt level + [RemoteEvent("VehStream_SetDirtLevel")] + public void VehStreamSetDirtLevel(Client player, Vehicle veh, float dirt) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Dirt = dirt; + + UpdateVehicleSyncData(veh, data); + + //Re-distribute the goods + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleDirtLevel", veh.Handle, dirt); + } + + //Called from the client to sync door data + [RemoteEvent("VehStream_SetDoorData")] + public void VehStreamSetDoorData(Client player, Vehicle veh, int door1state, int door2state, int door3state, int door4state, int door5state, int door6state, int door7state, int door8state) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Door[0] = door1state; + data.Door[1] = door2state; + data.Door[2] = door3state; + data.Door[3] = door4state; + data.Door[4] = door5state; + data.Door[5] = door6state; + data.Door[6] = door7state; + data.Door[7] = door8state; + + UpdateVehicleSyncData(veh, data); + + //Re-distribute the goods + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleDoorStatus", veh.Handle, door1state, door2state, door3state, door4state, door5state, door6state, door7state, door8state); + } + + //Called from the client to sync window data + [RemoteEvent("VehStream_SetWindowData")] + public void VehStreamSetWindowData(Client player, Vehicle veh, int window1state, int window2state, int window3state, int window4state) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Window[0] = window1state; + data.Window[1] = window2state; + data.Window[2] = window3state; + data.Window[3] = window4state; + + UpdateVehicleSyncData(veh, data); + + //Re-distribute the goods + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleWindowStatus", veh.Handle, window1state, window2state, window3state, window4state); + } + + //Called from the client to sync wheel data + [RemoteEvent("VehStream_SetWheelData")] + public void VehStreamSetWheelData(Client player, Vehicle veh, int wheel1state, int wheel2state, int wheel3state, int wheel4state, int wheel5state, int wheel6state, int wheel7state, int wheel8state, int wheel9state, int wheel10state) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Wheel[0] = wheel1state; + data.Wheel[1] = wheel2state; + data.Wheel[2] = wheel3state; + data.Wheel[3] = wheel4state; + data.Wheel[4] = wheel5state; + data.Wheel[5] = wheel6state; + data.Wheel[6] = wheel7state; + data.Wheel[7] = wheel8state; + data.Wheel[8] = wheel9state; + data.Wheel[9] = wheel10state; + UpdateVehicleSyncData(veh, data); + + //Re-distribute the goods + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleWheelStatus", veh.Handle, wheel1state, wheel2state, wheel3state, wheel4state, wheel5state, wheel6state, wheel7state, wheel8state, wheel9state, wheel10state); + } + + //Other events + [ServerEvent(Event.PlayerEnterVehicleAttempt)] + public void VehStreamEnterAttempt(Client player, Vehicle veh, sbyte seat) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEvent(player, "VehStream_PlayerEnterVehicleAttempt", veh, seat); + } + + [ServerEvent(Event.PlayerExitVehicleAttempt)] + public void VehStreamExitAttempt(Client player, Vehicle veh) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Position = veh.Position; + data.Rotation = veh.Rotation; + + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEvent(player, "VehStream_PlayerExitVehicleAttempt", veh); + } + + [ServerEvent(Event.PlayerExitVehicle)] + public void VehStreamExit(Client player, Vehicle veh) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Position = veh.Position; + data.Rotation = veh.Rotation; + + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEvent(player, "VehStream_PlayerExitVehicle", veh); + } + + [ServerEvent(Event.PlayerEnterVehicle)] + public void VehStreamEnter(Client player, Vehicle veh, sbyte seat) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + UpdateVehicleSyncData(veh, data); + NAPI.ClientEvent.TriggerClientEvent(player, "VehStream_PlayerEnterVehicle", veh, seat); + } + + [ServerEvent(Event.VehicleDamage)] + public void VehDamage(Vehicle veh, float bodyHealthLoss, float engineHealthLoss) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.BodyHealth -= bodyHealthLoss; + data.EngineHealth -= engineHealthLoss; + + UpdateVehicleSyncData(veh, data); + + if (NAPI.Vehicle.GetVehicleDriver(veh) != default(Client)) //Doesn't work? + NAPI.ClientEvent.TriggerClientEvent(NAPI.Vehicle.GetVehicleDriver(veh), "VehStream_PlayerExitVehicleAttempt", veh); + } + + [ServerEvent(Event.VehicleDoorBreak)] + public void VehDoorBreak(Vehicle veh, int index) + { + VehicleSyncData data = GetVehicleSyncData(veh); + if (data == default(VehicleSyncData)) + data = new VehicleSyncData(); + + data.Door[index] = 2; + + UpdateVehicleSyncData(veh, data); + + NAPI.ClientEvent.TriggerClientEventInDimension(veh.Dimension, "VehStream_SetVehicleDoorStatus", veh.Handle, data.Door[0], data.Door[1], data.Door[2], data.Door[3], data.Door[4], data.Door[5], data.Door[6], data.Door[7]); + } + } +}