diff --git a/.gitignore b/.gitignore index 67bfaf1..08ce423 100644 --- a/.gitignore +++ b/.gitignore @@ -40,13 +40,11 @@ luac.out *.yml *.userprefs -# Annoying files -src/.vs/DispatchSystem/v15/sqlite3/storage.ide - # Build folders src/Client/obj/* src/Server/obj/* src/Common/obj/* +src/DumpUnloader/obj/* src/bin/* .vs/* -src/.vs/* \ No newline at end of file +src/.vs/* diff --git a/README.md b/README.md index 5b7cecb..33c0f7c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ -# Dispatch Systems +# DispatchSystem + +Discord: [![Discord](https://discordapp.com/api/guilds/358081805850640384/widget.png)](https://discord.gg/ZcTayce) -> Dispatch Systems is a CAD/MDT system for ingame FiveM use, this is not a permenant solution, but it works for free. This is an open source free project courtesy of BlockBa5her (the coder). It is free for anyone to use, as long as they do not re-distribute the software under their own name. It does not store data in CouchDB and MySQL so EssentialMode is not needed. It stores all of the player's information in the RAM of the computer, so the next restart of the server clears all of the names that it has stored. It now also comes with database settings for saving Civilian Profiles and Vehicles to 2 files. +## Summary + +Dispatch Systems is a CAD/MDT system for ingame FiveM use, this is not a permenant solution, but it works for free. This is an open source free project courtesy of BlockBa5her (the coder). It is free for anyone to use, as long as they do not re-distribute the software under their own name. It does not store data in CouchDB and MySQL so EssentialMode is not needed. It stores all of the player's information in the RAM of the computer, but saves all of the data once the server is restarted. It now also comes with storage settings for saving Civilian Profiles and Vehicles in a file. ## Uses @@ -14,7 +18,7 @@ * C# with open source code * Availability to everyone, not just people who pay * Open for suggestions and always looking for more to add-on too -* Will always stay non-SQL/CouchDB based for easy use (with included database settings) +* Will always stay non-SQL/CouchDB based for easy use (with included storage settings) ## Pictures @@ -26,18 +30,17 @@ Tickets and Notes Dispatch Main Dispatch BOLO +Civ menu display +Leo menu display ## Commands -### ---Civilian Commands--- - -* `/civ` - Opens the civilian NUI menu In-game - -### ---Police Commands--- - -* `/leo` - Opens the officer NUI menu In-game (Can be used to for other emergency personel) +* `/dsciv` - Opens the civilian NUI menu In-game +* `/dsleo` - Opens the officer NUI menu In-game (Can be used to for other emergency personel) +* `/dsdmp` - Dumps all of the info of DispatchSystem into a file labeled `dispatchsystem.dmp` in the root directory, please only use if DispatchSystem is not working properly. ## In the works 1. Arrest ability - `/arrest {first} {last}` arrests a ped and show it in the system 2. Warrant Types - `/warrant {type}` have different types of bench warrants and also a toggle for outstanding +3. Bug fixes - There seems to be a lot of bugs that popped up in v2.0 of DispatchSystem, I'm hard at working trying to fix all of them diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index 4ade658..0000000 --- a/docs/api.md +++ /dev/null @@ -1,158 +0,0 @@ -# DispatchSystems API - -Dispatchsystems API is sort of new. Because it is in the works there is no set API. While you can use the server.dll included as a reference and use the static methods inside, there really is the way of using Events. - -## Events - -These events will be in the context of C# and **NOT** lua. - -```csharp -// Eventname: dispatchsystem:dsreset - -void TriggerServerEvent("dispatchsystem:dsreset", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:911init - -void TriggerServerEvent("dispatchsystem:911init", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:911msg - -void TriggerServerEvent("dispatchsystem:911msg", String invokerHandle, String message); -``` -*** -```csharp -// Eventname: dispatchsystem:911end - -void TriggerServerEvent("dispatchsystem:911end", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:initOfficer - -void TriggerServerEvent("dispatchsystem:initOfficer", String invokerHandle, String callsign); -``` -*** -```csharp -// Eventname: dispatchsystem:onDuty - -void TriggerServerEvent("dispatchsystem:onDuty", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:offDuty - -void TriggerServerEvent("dispatchsystem:offDuty", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:busy - -void TriggerServerEvent("dispatchsystem:busy", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:displayStatus - -void TriggerServerEvent("dispatchsystem:displayStatus", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:ticketCiv - -void TriggerServerEvent("dispatchsystem:ticketCiv", String invokerHandle, String first, String last, String ticket, Single amount); -``` -*** -```csharp -// Eventname: dispatchsystem:civTickets - -void TriggerServerEvent("dispatchsystem:civTickets", String invokerHandle, String first, String last); -``` -*** -```csharp -// Eventname: dispatchsystem:getCivilian - -void TriggerServerEvent("dispatchsystem:getCivilian", String invokerHandle, String firstName, String lastName); -``` -*** -```csharp -// Eventname: dispatchsystem:getCivilianVeh - -void TriggerServerEvent("dispatchsystem:getCivilianVeh", String invokerHandle, String plate); -``` -*** -```csharp -// Eventname: dispatchsystem:addBolo - -void TriggerServerEvent("dispatchsystem:addBolo", String invokerHandle, String reason); -``` -*** -```csharp -// Eventname: dispatchsystem:viewBolos - -void TriggerServerEvent("dispatchsystem:viewBolos", String invokerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:addCivNote - -void TriggerServerEvent("dispatchsystem:addCivNote", String invokerHandle, String firstName, String lastName, String note); -``` -*** -```csharp -// Eventname: dispatchsystem:displayCivNotes - -void TriggerServerEvent("dispatchsystem:displayCivNotes", String invokerHandle, String firstName, String lastName); -``` -*** -```csharp -// Eventname: dispatchsystem:ticketCiv - -void TriggerServerEvent("dispatchsystem:ticketCiv", String invokerHandle, String firstName, String lastName, String reason, Single amount); -``` -*** -```csharp -// Eventname: dispatchsystem:setName - -void TriggerServerEvent("dispatchsystem:setName", String playerHandle, String firstName, String lastName); -``` -*** -```csharp -// Eventname: dispatchsystem:toggleWarrant - -void TriggerServerEvent("dispatchsystem:toggleWarrant", String playerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:setCitations - -void TriggerServerEvent("dispatchsystem:setCitations", String playerHandle, Int32 citationCount); -``` -*** -```csharp -// Eventname: dispatchsystem:setVehicle - -void TriggerServerEvent("dispatchsystem:setVehicle", String playerHandle, String plate); -``` -*** -```csharp -// Eventname: dispatchsystem:toggleVehStolen - -void TriggerServerEvent("dispatchsystem:toggleVehStolen", String playerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:toggleVehRegi -// And yes, the end does end with "regi" and not "registration" - -void TriggerServerEvent("dispatchsystem:toggleVehRegi", String playerHandle); -``` -*** -```csharp -// Eventname: dispatchsystem:toggleVehInsured - -void TriggerServerEvent("dispatchsystem:toggleVehInsured", String playerHandle); -``` \ No newline at end of file diff --git a/docs/building.md b/docs/building.md index 15b47ff..5ac4b77 100644 --- a/docs/building.md +++ b/docs/building.md @@ -8,6 +8,7 @@ These errors have not occured with anyone, but I just want to make sure that the * Both project file say that there are missing dependencies/references 1. Just add both of the references back to the right project, the references can be found in the `ref` folder in the clone + 2. Sometimes the NuGet packages are weird and don't follow the clone, so just download the package CloNET & MaterialSkin again. > TODO: More to add once more errors popup ## Build location diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..5267176 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,13 @@ +# Installation guide + +## Deciding options +Decide what options you would want to have on your server. The most important things to decide on are the database feature, and the server feature. They are both togglable in the server's `settings.ini` file. The server feature is what allows the client to connect to the server, and the database is where it stores all of your data on restart. + +## Basic installation +To install all of the stuff on the server, you can make a drag and drop the resource folder `dispatchsystem` inside of the download folder inside of your `resources/` folder. From there, you can go inside of the resource folder and change all of the `ini` settings. Now all that's left to do is put the resource inside your `server.cfg` + +## Client installation +To install the client is easy. All you have to do is make sure that the `dispatchsystem` resource has the `server` setting enabled. After that, just make sure that you have port `33333` open to use (If on web hoster or VPS it's already open). Now, you just have to configure your client's settings so that the IP matches with the IP that your FiveM server is run off of. + +## Common issues +A lot of issues have been appearing with DispatchSystem lately. That is why I integrated the `/dsdmp` command to allow you to dump your server information to a file, and delete the rest of the info on the server. The `dispatchsystem.dmp` file that is exported in the dump process is located at the root of your FiveM directory. \ No newline at end of file diff --git a/docs/server.md b/docs/server.md index dd0aa36..3412385 100644 --- a/docs/server.md +++ b/docs/server.md @@ -1,17 +1,17 @@ # Setting up the Server ## Toggling the server - Basically, just open up the `settings.ini` that comes with the server, and change the option under the `[server]` tag that says `enable` to `0` ## Setting up the server - Don't change any settings in the INI, unless you are having problems. All of the settings in there should work with your average joe ## Setting up the client - In the `settings.ini`, change the the IP of the server to the IP of your server, and keep the PORT the same unless you changed it on the server's side +## Toggling the database +In the `settings.ini` of the server, change the `database` option to 0. + ## Ports to have open -If you are running this off a basic home internet, then you will need to open the PORT `33333`, and that is 5 threes just to confirm. If you are running this off a VPS or hosting website then you should be good from opening ports. \ No newline at end of file +If you are running this off a basic home internet, then you will need to open the PORT `33333`, and that is 5 threes just to confirm. If you are running this off a VPS or hosting website then you shouldn't have to open any ports because they are already open for you. diff --git a/src/Client/App.config b/src/Client/App.config index 731f6de..bae5d6d 100644 --- a/src/Client/App.config +++ b/src/Client/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/src/Client/Client.csproj b/src/Client/Client.csproj index 2c00124..af016c9 100644 --- a/src/Client/Client.csproj +++ b/src/Client/Client.csproj @@ -11,6 +11,7 @@ v4.6.1 512 true + AnyCPU @@ -21,6 +22,7 @@ DEBUG;TRACE prompt 4 + false AnyCPU @@ -30,6 +32,7 @@ TRACE prompt 4 + false icon.ico @@ -37,8 +40,7 @@ - False - ..\packages\CloneCommando.CloNET.0.4.2\lib\net461\CloNET.dll + ..\packages\CloneCommando.CloNET.0.5.4\lib\net461\CloNET.dll ..\packages\MaterialSkin.Updated.0.2.2\lib\MaterialSkin.dll @@ -185,7 +187,9 @@ - + + Designer + diff --git a/src/Client/Config.cs b/src/Client/Config.cs index a4b14b4..beecfac 100644 --- a/src/Client/Config.cs +++ b/src/Client/Config.cs @@ -11,12 +11,12 @@ namespace DispatchSystem.cl { public class Config { - public static IPAddress IP { get; private set; } + public static IPAddress Ip { get; private set; } public static int Port { get; private set; } - public static void Create(string FilePath) + public static void Create(string filePath) { - string[] lines = File.ReadAllLines(FilePath); + string[] lines = File.ReadAllLines(filePath); foreach (string[] line in lines.Where(x => !x.StartsWith(";")).Select(x => x.Split('=').Select(y => y.Trim()).ToArray())) switch (line[0]) @@ -24,27 +24,30 @@ public static void Create(string FilePath) case "IP": if (line[1] == "changeme") { - MessageBox.Show("Looks like you forgot to change the config.\nPlease edit your config and then come back ༼ つ ◕_◕ ༽つ", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show( + "Looks like you forgot to change the config.\nPlease edit your config and then come back ༼ つ ◕_◕ ༽つ", + "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(0); } if (!IPAddress.TryParse(line[1], out IPAddress address)) { - MessageBox.Show("The ip address is invalid.", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("The ip address is invalid.", "DispatchSystem", MessageBoxButtons.OK, + MessageBoxIcon.Error); Environment.Exit(0); } - IP = address; + Ip = address; break; - case "Port": - if (!int.TryParse(line[1], out int _Port) || _Port < 1024 || _Port > 65536) + if (!int.TryParse(line[1], out int port) || port < 1024 || port > 65536) { - MessageBox.Show("The port is invalid.\nMake sure it is a positive integer within 1025-65535.", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("The port is invalid.\nMake sure it is a positive integer within 1025-65535.", + "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(0); } - Port = _Port; + Port = port; break; } } diff --git a/src/Client/Program.cs b/src/Client/Program.cs index 4458485..1c28ffd 100644 --- a/src/Client/Program.cs +++ b/src/Client/Program.cs @@ -3,11 +3,12 @@ using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; + using DispatchSystem.cl.Windows; +using DispatchSystem.cl.Windows.Emergency; using CloNET; -using CloNET.Callbacks; -using DispatchSystem.cl.Windows.Emergency; +using CloNET.LocalCallbacks; using DispatchSystem.Common.DataHolders.Storage; namespace DispatchSystem.cl @@ -30,89 +31,105 @@ private static void Main() Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); + Run(); + } + + private static async void Run() + { using (Client = new Client()) { Client.Encryption = new EncryptionOptions { - Encrypt = false, + Encrypt = true, + Overridable = true + }; + Client.Compression = new CompressionOptions + { + Compress = false, Overridable = true }; + Client.LocalCallbacks.Events.Add("911alert", new LocalEvent(new Func(Alert911))); - new Action(async () => + if (!Client.Connect(Config.Ip.ToString(), Config.Port).Result) { - try { await Client.Connect(Config.IP.ToString(), Config.Port); } - catch (SocketException) { MessageBox.Show("Connection refused or failed!\nPlease contact the owner of your server", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(-1); } - })(); + MessageBox.Show("Connection refused or failed!\nPlease contact the owner of your server", + "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); + Environment.Exit(-1); + } - Client.Events.Add("911alert", new NetEvent(async (peer, objects) => + if (Client.Peer != null) // If no perms, peer will be null { - await Task.FromResult(0); - - mainWindow.Invoke((MethodInvoker) delegate + new Thread(async delegate () { - new Accept911((Civilian) objects[0], (EmergencyCall) objects[1]).Show(); - }); - })); - - Client.Connected += delegate - { - new Thread((ThreadStart)async delegate + while (true) { - while (true) - { - Thread.Sleep(100); - if (Client.IsConnected) continue; - if (mainWindow == null) continue; + Thread.Sleep(100); + if (Client.IsConnected) continue; + if (mainWindow == null) continue; - bool executing = true; - new Thread(() => - { - mainWindow.Invoke((MethodInvoker)delegate - { - while (executing) - { - Thread.Sleep(50); - } - }); - }) - { Name = "WindowFreezeThread" }.Start(); - - for (int i = 0; i < RECONNECT_COUNT; i++) + bool[] executing = { true }; + new Thread(() => + { + mainWindow.Invoke((MethodInvoker)delegate { - try - { - await Client.Disconnect(); - await Client.Connect(Config.IP.ToString(), Config.Port); - } - catch (SocketException) + while (executing[0]) { + Thread.Sleep(50); } + }); + }) + { Name = "WindowFreezeThread" }.Start(); - Thread.Sleep(1000); - if (Client.IsConnected) break; - } - - if (Client.IsConnected) + for (int i = 0; i < RECONNECT_COUNT; i++) + { + try { - executing = false; + await Client.Disconnect(); + Client.Connect(Config.Ip.ToString(), Config.Port).Wait(); } - else + catch (SocketException) { - MessageBox.Show($"Failed to connect to the server after {RECONNECT_COUNT} attempts", "DispatchSystem", - MessageBoxButtons.OK, MessageBoxIcon.Error); - Environment.Exit(-1); } - } - }) - { Name = "ConnectionDetection" }.Start(); - }; - Application.Run(mainWindow = new DispatchMain()); + Thread.Sleep(1000); + if (Client.IsConnected) break; + } - new Action(async delegate { await Client.Disconnect(); })(); + if (Client.IsConnected) + { + executing[0] = false; + } + else + { + MessageBox.Show($"Failed to connect to the server after {RECONNECT_COUNT} attempts", + "DispatchSystem", + MessageBoxButtons.OK, MessageBoxIcon.Error); + Environment.Exit(-1); + } + } + }) + { Name = "ConnectionDetection" }.Start(); + + Application.Run(mainWindow = new DispatchMain()); + await Client.Disconnect(); + } + else + MessageBox.Show("You seem to have invalid permissions with the server", "DispatchSystem", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + + Environment.Exit(0); } - Environment.Exit(0); + } + + private static async Task Alert911(ConnectedPeer peer, Civilian civ, EmergencyCall call) + { + await Task.FromResult(0); + + mainWindow.Invoke((MethodInvoker)delegate + { + new Accept911(civ, call).Show(); + }); } } } diff --git a/src/Client/Windows/AddExistingAssignment.cs b/src/Client/Windows/AddExistingAssignment.cs index a39ad05..baeff5c 100644 --- a/src/Client/Windows/AddExistingAssignment.cs +++ b/src/Client/Windows/AddExistingAssignment.cs @@ -38,23 +38,23 @@ public AddExistingAssignment(Officer ofc) public async Task Resync(bool skipTime) { - if (((DateTime.Now - LastSyncTime).Seconds < 15 || IsCurrentlySyncing) && !skipTime) + if (((DateTime.Now - LastSyncTime).Seconds < 5 || IsCurrentlySyncing) && !skipTime) { - MessageBox.Show($"You must wait 15 seconds before the last sync time \nSeconds to wait: {15 - (DateTime.Now - LastSyncTime).Seconds}", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show($"You must wait 5 seconds before the last sync time \nSeconds to wait: {5 - (DateTime.Now - LastSyncTime).Seconds}", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } LastSyncTime = DateTime.Now; IsCurrentlySyncing = true; - Tuple> result = await Program.Client.TryTriggerNetFunction>("GetAssignments"); - if (result.Item2 != null) + IEnumerable result = await Program.Client.Peer.RemoteCallbacks.Properties["Assignments"].Get>(); + if (result != null) { while (!IsHandleCreated) await Task.Delay(50); Invoke((MethodInvoker)delegate { - assignments = result.Item2; + assignments = result; UpdateCurrentInformation(); }); } @@ -82,7 +82,7 @@ private async void OnDoubleClick(object sender, EventArgs e) int index = assignmentsView.Items.IndexOf(assignmentsView.FocusedItem); Assignment assignment = assignments.ToList()[index]; - await Program.Client.TriggerNetEvent("AddOfficerAssignment", assignment.Id, ofc.Id); + await Program.Client.Peer.RemoteCallbacks.Events["AddOfficerAssignment"].Invoke(assignment.Id, ofc.Id); Close(); } diff --git a/src/Client/Windows/AddRemoveView.cs b/src/Client/Windows/AddRemoveView.cs index ab8d137..9a23899 100644 --- a/src/Client/Windows/AddRemoveView.cs +++ b/src/Client/Windows/AddRemoveView.cs @@ -74,7 +74,7 @@ private async void OnBtnClick(object sender, EventArgs e) case Type.AddBolo: { if (!(string.IsNullOrWhiteSpace(line1.Text) || string.IsNullOrWhiteSpace(line2.Text))) - await Program.Client.TryTriggerNetEvent("AddBolo", line2.Text, line1.Text); + await Program.Client.Peer.RemoteCallbacks.Events["AddBolo"].Invoke(line2.Text, line1.Text); line1.ResetText(); line2.ResetText(); break; @@ -82,14 +82,15 @@ private async void OnBtnClick(object sender, EventArgs e) case Type.RemoveBolo: { if (!int.TryParse(line1.Text, out int result)) { MessageBox.Show("The index of the BOLO must be a valid number"); return; } - await Program.Client.TryTriggerNetEvent("RemoveBolo", result); + await Program.Client.Peer.RemoteCallbacks.Events["RemoveBolo"].Invoke(result); line1.ResetText(); break; } case Type.AddNote: { if (!string.IsNullOrEmpty(line1.Text)) - await Program.Client.TryTriggerNetEvent("AddNote", arguments[0], arguments[1], line1.Text); + await Program.Client.Peer.RemoteCallbacks.Events["AddNote"] + .Invoke(arguments[0], line1.Text); line1.ResetText(); break; } @@ -97,8 +98,9 @@ private async void OnBtnClick(object sender, EventArgs e) { if (!string.IsNullOrEmpty(line1.Text)) { - Tuple result = await Program.Client.TryTriggerNetFunction("CreateAssignment", line1.Text); - LastGuid = result.Item2; + Guid result = await Program.Client.Peer.RemoteCallbacks.Functions["CreateAssignment"] + .Invoke(line1.Text); + LastGuid = result; } break; } diff --git a/src/Client/Windows/AssignmentsView.cs b/src/Client/Windows/AssignmentsView.cs index 123b049..9879bdc 100644 --- a/src/Client/Windows/AssignmentsView.cs +++ b/src/Client/Windows/AssignmentsView.cs @@ -9,8 +9,6 @@ using DispatchSystem.Common.DataHolders.Storage; -using CloNET; - namespace DispatchSystem.cl.Windows { public partial class AssignmentsView : MaterialForm, ISyncable @@ -51,12 +49,13 @@ public async Task Resync(bool skipTime) LastSyncTime = DateTime.Now; IsCurrentlySyncing = true; - Tuple> result = await Program.Client.TryTriggerNetFunction>("GetAssignments"); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Properties["Assignments"] + .Get>(); + if (result != null) { Invoke((MethodInvoker)delegate { - assignments = result.Item2; + assignments = result; UpdateCurrentInformation(); }); } @@ -96,12 +95,10 @@ private async void OnResyncClick(object sender, EventArgs e) private void OnAssignmentsClick(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Right) + if (e.Button != MouseButtons.Right) return; + if (theAssignments.FocusedItem.Bounds.Contains(e.Location)) { - if (theAssignments.FocusedItem.Bounds.Contains(e.Location)) - { - rightClickMenu.Show(Cursor.Position); - } + rightClickMenu.Show(Cursor.Position); } } @@ -110,7 +107,7 @@ private async void OnRightClickRemove(object sender, EventArgs e) int index = theAssignments.Items.IndexOf(theAssignments.FocusedItem); Assignment assignment = assignments.ToList()[index]; - await Program.Client.TryTriggerNetEvent("RemoveAssignment", assignment.Id); + await Program.Client.Peer.RemoteCallbacks.Events["RemoveAssignment"].Invoke(assignment.Id); await Resync(true); } diff --git a/src/Client/Windows/BoloView.cs b/src/Client/Windows/BoloView.cs index 3f01047..713b6ee 100644 --- a/src/Client/Windows/BoloView.cs +++ b/src/Client/Windows/BoloView.cs @@ -58,12 +58,13 @@ public async Task Resync(bool skipTime) LastSyncTime = DateTime.Now; IsCurrentlySyncing = true; - Tuple> result = await Program.Client.TryTriggerNetFunction>("GetBolos"); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Properties["Bolos"] + .Get>(); + if (result != null) { Invoke((MethodInvoker)delegate { - bolos = result.Item2; + bolos = result; UpdateCurrentInformation(); }); } @@ -101,7 +102,7 @@ private async void OnRemoveSelectedClick(object sender, EventArgs e) { if (bolosView.SelectedItems.Count > 0) { - await Program.Client.TryTriggerNetEvent("RemoveBolo", 0); + await Program.Client.Peer.RemoteCallbacks.Events["RemoveBolo"].Invoke(bolosView.Items.IndexOf(bolosView.SelectedItems[0])); await Resync(true); } else diff --git a/src/Client/Windows/CivVehView.cs b/src/Client/Windows/CivVehView.cs index b95bcb9..5f9a9ef 100644 --- a/src/Client/Windows/CivVehView.cs +++ b/src/Client/Windows/CivVehView.cs @@ -51,12 +51,13 @@ public async Task Resync(bool skipTime) if (string.IsNullOrWhiteSpace(plateView.Text)) return; - Tuple result = await Program.Client.TryTriggerNetFunction("GetCivilianVeh", data.Plate); - if (result.Item2 != null) + CivilianVeh result = await Program.Client.Peer.RemoteCallbacks.Functions["GetCivilianVeh"] + .Invoke(data.Plate); + if (result != null) { Invoke((MethodInvoker)delegate { - data = result.Item2; + data = result; UpdateCurrentInformation(); }); } diff --git a/src/Client/Windows/CivView.cs b/src/Client/Windows/CivView.cs index bc6ad81..7576ce6 100644 --- a/src/Client/Windows/CivView.cs +++ b/src/Client/Windows/CivView.cs @@ -65,7 +65,7 @@ private void OnAddNoteClick(object sender, EventArgs e) Invoke((MethodInvoker)delegate { AddRemoveView view; - (view = new AddRemoveView(AddRemoveView.Type.AddNote, data.First, data.Last)).Show(); + (view = new AddRemoveView(AddRemoveView.Type.AddNote, data.Id)).Show(); view.FormClosed += async delegate { await Resync(true); @@ -87,12 +87,13 @@ public async Task Resync(bool skipTime) if (string.IsNullOrWhiteSpace(firstNameView.Text) || string.IsNullOrWhiteSpace(lastNameView.Text)) return; - Tuple result = await Program.Client.TryTriggerNetFunction("GetCivilian", data.First, data.Last); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Functions["GetCivilian"] + .Invoke(data.First, data.Last); + if (result != null) { Invoke((MethodInvoker)delegate { - data = result.Item2; + data = result; UpdateCurrentInformation(); }); } diff --git a/src/Client/Windows/DispatchMain.cs b/src/Client/Windows/DispatchMain.cs index ae18fc5..6234395 100644 --- a/src/Client/Windows/DispatchMain.cs +++ b/src/Client/Windows/DispatchMain.cs @@ -8,8 +8,6 @@ using DispatchSystem.Common.DataHolders.Storage; -using CloNET; - namespace DispatchSystem.cl.Windows { public partial class DispatchMain : MaterialForm @@ -32,21 +30,17 @@ public async void OnViewCivClick(object sender, EventArgs e) if (string.IsNullOrWhiteSpace(firstName.Text) || string.IsNullOrWhiteSpace(lastName.Text)) return; - Tuple result = await Program.Client.TryTriggerNetFunction("GetCivilian", firstName.Text, lastName.Text); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Functions["GetCivilian"] + .Invoke(firstName.Text, lastName.Text); + if (result != null) { - if (!(string.IsNullOrEmpty(result.Item2?.First) || string.IsNullOrEmpty(result.Item2?.Last))) // Checking if the civilian is empty bc for some reason == and .Equals are not working for this situation + Invoke((MethodInvoker)delegate { - Invoke((MethodInvoker)delegate - { - new CivView(result.Item2).Show(); - }); - } - else - MessageBox.Show("That name doesn't exist in the system!", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + new CivView(result).Show(); + }); } else - MessageBox.Show("Invalid request", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("That name doesn't exist in the system!", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); firstName.ResetText(); lastName.ResetText(); @@ -57,21 +51,17 @@ private async void OnViewCivVehClick(object sender, EventArgs e) if (string.IsNullOrWhiteSpace(plate.Text)) return; - Tuple result = await Program.Client.TryTriggerNetFunction("GetCivilianVeh", plate.Text); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Functions["GetCivilianVeh"] + .Invoke(plate.Text); + if (result != null) { - if (!(string.IsNullOrEmpty(result.Item2.Plate))) + Invoke((MethodInvoker)delegate { - Invoke((MethodInvoker)delegate - { - new CivVehView(result.Item2).Show(); - }); - } - else - MessageBox.Show("That plate doesn't exist in the system!", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + new CivVehView(result).Show(); + }); } else - MessageBox.Show("Invalid Request", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + MessageBox.Show("That plate doesn't exist in the system!", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); plate.ResetText(); } @@ -85,12 +75,12 @@ private async void OnViewBolosClick(object sender, EventArgs e) return; } - Tuple> result = await Program.Client.TryTriggerNetFunction>("GetBolos"); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Properties["Bolos"].Get>(); + if (result != null) { Invoke((MethodInvoker)delegate { - (boloWindow = new BoloView(result.Item2)).Show(); + (boloWindow = new BoloView(result)).Show(); boloWindow.FormClosed += delegate { boloWindow = null; }; }); } @@ -106,12 +96,12 @@ private async void OnViewOfficersClick(object sender, EventArgs e) return; } - Tuple> result = await Program.Client.TryTriggerNetFunction>("GetOfficers"); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Properties["Officers"].Get>(); + if (result != null) { Invoke((MethodInvoker)delegate { - (officersWindow = new MultiOfficerView(result.Item2)).Show(); + (officersWindow = new MultiOfficerView(result)).Show(); officersWindow.FormClosed += delegate { officersWindow = null; }; }); } @@ -127,12 +117,13 @@ private async void OnViewAssignmentsClick(object sender, EventArgs e) return; } - var result = await Program.Client.TryTriggerNetFunction>("GetAssignments"); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Properties["Assignments"] + .Get>(); + if (result != null) { Invoke((MethodInvoker)delegate { - (assignmentsWindow = new AssignmentsView(result.Item2)).Show(); + (assignmentsWindow = new AssignmentsView(result)).Show(); assignmentsWindow.FormClosed += delegate { assignmentsWindow = null; }; }); } @@ -145,7 +136,7 @@ private void OnFirstNameKeyPress(object sender, KeyPressEventArgs e) if (!char.IsControl(e.KeyChar) && !char.IsLetter(e.KeyChar)) e.Handled = true; if (char.IsLetter(e.KeyChar)) - e.KeyChar = char.ToUpper(e.KeyChar); + e.KeyChar = firstName.Text.Length == 0 ? char.ToUpper(e.KeyChar) : char.ToLower(e.KeyChar); } private void OnLastNameKeyPress(object sender, KeyPressEventArgs e) @@ -153,7 +144,8 @@ private void OnLastNameKeyPress(object sender, KeyPressEventArgs e) if (!char.IsControl(e.KeyChar) && !char.IsLetter(e.KeyChar)) e.Handled = true; if (char.IsLetter(e.KeyChar)) - e.KeyChar = char.ToUpper(e.KeyChar); + e.KeyChar = lastName.Text.Length == 0 ? char.ToUpper(e.KeyChar) : char.ToLower(e.KeyChar); + } private void OnPlateKeyPress(object sender, KeyPressEventArgs e) diff --git a/src/Client/Windows/Emergency/Accept911.cs b/src/Client/Windows/Emergency/Accept911.cs index be5bd65..aa8ea0f 100644 --- a/src/Client/Windows/Emergency/Accept911.cs +++ b/src/Client/Windows/Emergency/Accept911.cs @@ -32,14 +32,14 @@ public Accept911(Civilian requester, EmergencyCall call) private async void OnAcceptClick(object sender, EventArgs e) { - Tuple item = await Program.Client.TryTriggerNetFunction("Accept911", call.Id); - if (item.Item2 == null) + object item = await Program.Client.Peer.RemoteCallbacks.Functions["Accept911"].Invoke(call.Id); + if (item == null) { MessageBox.Show("Invalid request", "DispatchSystem", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - if ((bool) item.Item2) + if ((bool) item) { new Message911(civ, call).Show(); } diff --git a/src/Client/Windows/Emergency/Message911.cs b/src/Client/Windows/Emergency/Message911.cs index b015ec7..1b448a6 100644 --- a/src/Client/Windows/Emergency/Message911.cs +++ b/src/Client/Windows/Emergency/Message911.cs @@ -1,10 +1,12 @@ using System; using System.Drawing; +using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using CloNET; using CloNET.Callbacks; +using CloNET.LocalCallbacks; using DispatchSystem.Common.DataHolders.Storage; using MaterialSkin.Controls; @@ -25,25 +27,25 @@ public Message911(Civilian civ, EmergencyCall call) Text += $"{civ.First} {civ.Last}"; - Program.Client.Events.Add(call.Id.ToString(), new NetEvent(Msg911)); - Program.Client.Events.Add("end" + call.Id, new NetEvent(End911)); + Program.Client.LocalCallbacks.Events.Add(call.Id.ToString(), new LocalEvent(new Func(Msg911))); + Program.Client.LocalCallbacks.Events.Add("end" + call.Id, new LocalEvent(new Func(End911))); Closed += async delegate { - await Program.Client.TryTriggerNetEvent("911End", call.Id); + await Program.Client.Peer.RemoteCallbacks.Events["911End"].Invoke(call.Id); - Program.Client.Events.Remove("end" + call.Id); - Program.Client.Events.Remove(call.Id.ToString()); + Program.Client.LocalCallbacks.Events.Remove("end" + call.Id); + Program.Client.LocalCallbacks.Events.Remove(call.Id.ToString()); }; } - private async Task Msg911(ConnectedPeer peer, object[] data) + private async Task Msg911(ConnectedPeer peer, string incomingMsg) { await Task.FromResult(0); ListViewItem item = new ListViewItem(DateTime.Now.ToString("HH:mm:ss")); item.SubItems.Add($"{civ.First} {civ.Last}"); - item.SubItems.Add((string)data[0]); + item.SubItems.Add(incomingMsg); Invoke((MethodInvoker)delegate { @@ -51,7 +53,7 @@ private async Task Msg911(ConnectedPeer peer, object[] data) }); } - private async Task End911(ConnectedPeer peer, object[] data) + private async Task End911(ConnectedPeer peer) { await Task.FromResult(0); @@ -68,25 +70,26 @@ public sealed override string Text private async void SendMsg(object sender, EventArgs e) { - if (!string.IsNullOrWhiteSpace(msgBox.Text)) + if (string.IsNullOrWhiteSpace(msgBox.Text)) return; + + await Program.Client.Peer.RemoteCallbacks.Events["911Msg"].Invoke(call.Id, msgBox.Text); + + ListViewItem item = new ListViewItem(DateTime.Now.ToString("HH:mm:ss")); + item.SubItems.Add("You"); + item.SubItems.Add(msgBox.Text); + + Invoke((MethodInvoker) delegate { - await Program.Client.TryTriggerNetEvent("911Msg", call.Id, msgBox.Text); - - ListViewItem item = new ListViewItem(DateTime.Now.ToString("HH:mm:ss")); - item.SubItems.Add("You"); - item.SubItems.Add(msgBox.Text); - - Invoke((MethodInvoker) delegate - { - msgs.Items.Add(item); - msgBox.Clear(); - }); - } + msgs.Items.Add(item); + msgBox.Clear(); + }); } private void SendMsg(object sender, KeyEventArgs e) { - if (e.KeyCode == Keys.Enter) - SendMsg(sender, (EventArgs)e); + if (e.KeyCode != Keys.Enter) return; + + e.SuppressKeyPress = true; + SendMsg(sender, (EventArgs)e); } } } diff --git a/src/Client/Windows/MultiOfficerView.cs b/src/Client/Windows/MultiOfficerView.cs index e0e5b3c..6fe0bf3 100644 --- a/src/Client/Windows/MultiOfficerView.cs +++ b/src/Client/Windows/MultiOfficerView.cs @@ -55,12 +55,12 @@ public async Task Resync(bool skipTime) LastSyncTime = DateTime.Now; IsCurrentlySyncing = true; - Tuple> result = await Program.Client.TryTriggerNetFunction>("GetOfficers"); - if (result.Item2 != null) + var result = await Program.Client.Peer.RemoteCallbacks.Properties["Officers"].Get>(); + if (result != null) { Invoke((MethodInvoker)delegate { - data = result.Item2; + data = result; UpdateCurrentInformation(); }); } @@ -101,7 +101,7 @@ private async void OnSelectStatusClick(object sender, EventArgs e) break; } - await Program.Client.TryTriggerNetEvent("SetStatus", ofc, OfficerStatus.OnDuty); + await Program.Client.Peer.RemoteCallbacks.Events["SetStatus"].Invoke(ofc.Id, OfficerStatus.OnDuty); } else if (sender == statusOffDutyStripItem) { @@ -111,7 +111,7 @@ private async void OnSelectStatusClick(object sender, EventArgs e) break; } - await Program.Client.TryTriggerNetEvent("SetStatus", ofc, OfficerStatus.OffDuty); + await Program.Client.Peer.RemoteCallbacks.Events["SetStatus"].Invoke(ofc.Id, OfficerStatus.OffDuty); } else { @@ -121,7 +121,7 @@ private async void OnSelectStatusClick(object sender, EventArgs e) break; } - await Program.Client.TryTriggerNetEvent("SetStatus", ofc, OfficerStatus.Busy); + await Program.Client.Peer.RemoteCallbacks.Events["SetStatus"].Invoke(ofc.Id, OfficerStatus.Busy); } } while (false); @@ -143,7 +143,7 @@ private async void OnRemoveOfficerClick(object sender, EventArgs e) int index = officers.Items.IndexOf(focusesItem); Officer ofc = data[index]; - await Program.Client.TryTriggerNetEvent("RemoveOfficer", ofc.Id); + await Program.Client.Peer.RemoteCallbacks.Events["RemoveOfficer"].Invoke(ofc.Id); await Resync(true); } diff --git a/src/Client/Windows/OfficerView.cs b/src/Client/Windows/OfficerView.cs index 90364e1..a82d28b 100644 --- a/src/Client/Windows/OfficerView.cs +++ b/src/Client/Windows/OfficerView.cs @@ -50,18 +50,17 @@ public void UpdateCurrentInformation() throw new ArgumentOutOfRangeException(); } materialListView1.Items.Clear(); - if (!(assignment is null)) - { - ListViewItem lvi = new ListViewItem(assignment.Creation.ToString("HH:mm:ss")); - lvi.SubItems.Add(assignment.Summary); - materialListView1.Items.Add(lvi); - } + if (assignment is null) return; + + ListViewItem lvi = new ListViewItem(assignment.Creation.ToString("HH:mm:ss")); + lvi.SubItems.Add(assignment.Summary); + materialListView1.Items.Add(lvi); } public async Task SetAssignment() { - Tuple result = await Program.Client.TryTriggerNetFunction("GetOfficerAssignment", ofc.Id); - assignment = result.Item2; + assignment = await Program.Client.Peer.RemoteCallbacks.Functions["GetOfficerAssignment"] + .Invoke(ofc.Id); UpdateCurrentInformation(); } @@ -76,14 +75,14 @@ public async Task Resync(bool skipTime) LastSyncTime = DateTime.Now; IsCurrentlySyncing = true; - Tuple result = await Program.Client.TryTriggerNetFunction("GetOfficer", ofc.Id); - if (result.Item2 != null) + Officer result = await Program.Client.Peer.RemoteCallbacks.Functions["GetOfficer"].Invoke(ofc.Id); + if (result != null) { - if (result.Item2.SourceIP != string.Empty && result.Item2.Callsign != string.Empty) + if (result.SourceIP != string.Empty && result.Callsign != string.Empty) { Invoke((MethodInvoker)async delegate { - ofc = result.Item2; + ofc = result; await SetAssignment(); }); } @@ -108,7 +107,7 @@ private async void StatusClick(object sender, EventArgs e) break; } - await Program.Client.TryTriggerNetEvent("SetStatus", ofc, OfficerStatus.OnDuty); + await Program.Client.Peer.RemoteCallbacks.Events["SetStatus"].Invoke(ofc.Id, OfficerStatus.OnDuty); } else if (sender == radioOffDuty) { @@ -118,7 +117,7 @@ private async void StatusClick(object sender, EventArgs e) break; } - await Program.Client.TryTriggerNetEvent("SetStatus", ofc, OfficerStatus.OffDuty); + await Program.Client.Peer.RemoteCallbacks.Events["SetStatus"].Invoke(ofc.Id, OfficerStatus.OffDuty); } else { @@ -128,7 +127,7 @@ private async void StatusClick(object sender, EventArgs e) break; } - await Program.Client.TryTriggerNetEvent("SetStatus", ofc, OfficerStatus.Busy); + await Program.Client.Peer.RemoteCallbacks.Events["SetStatus"].Invoke(ofc.Id, OfficerStatus.Busy); } } while (false); @@ -148,7 +147,8 @@ private void OnCreateNewAssignment(object sender, EventArgs e) (addBtn = new AddRemoveView(AddRemoveView.Type.AddAssignment)).Show(); addBtn.FormClosed += async delegate { - await Program.Client.TriggerNetEvent("AddOfficerAssignment", addBtn.LastGuid, ofc.Id); + await Program.Client.Peer.RemoteCallbacks.Events["AddOfficerAssignment"] + .Invoke(addBtn.LastGuid, ofc.Id); addBtn = null; await Resync(true); @@ -170,7 +170,7 @@ private async void OnRemoveSelectedClick(object sender, EventArgs e) if (materialListView1.FocusedItem == null) return; - await Program.Client.TryTriggerNetEvent("RemoveOfficerAssignment", ofc.Id); + await Program.Client.Peer.RemoteCallbacks.Events["RemoveOfficerAssignment"].Invoke(ofc.Id); await Resync(true); } diff --git a/src/Client/packages.config b/src/Client/packages.config index 249e14e..3d16f68 100644 --- a/src/Client/packages.config +++ b/src/Client/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/src/Common/Common.csproj b/src/Common/Common.csproj index d76a45d..a6fd2d3 100644 --- a/src/Common/Common.csproj +++ b/src/Common/Common.csproj @@ -40,6 +40,7 @@ + @@ -50,9 +51,8 @@ - - + diff --git a/src/Common/DataHolders/Database.cs b/src/Common/DataHolders/Database.cs new file mode 100644 index 0000000..4c17bfa --- /dev/null +++ b/src/Common/DataHolders/Database.cs @@ -0,0 +1,145 @@ +/* + * Original file made by http://www.github.com/blockba5her + * File OPEN DOMAIN (No license) + * Free for public/private use in applications +*/ + +using System; +using System.IO; +using System.IO.Compression; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; + +namespace EZDatabase +{ + /// + /// Thread safe read and write to a file of serializable objects + /// + public sealed class Database + { + // The file to save the database stuff on + private readonly string file; + + private const int MAX_FAIL = 10; + + /// + /// Initializes the class of + /// + /// The name of the file to save the data in + /// Should the file be created if it doesn't already exist + public Database(string file, bool createFile = true) + { + this.file = file; + if (!createFile) return; + lock (this) // Locking so thread read/write + File.Open(file, (FileMode)4).Dispose(); // Creating the database file (if not already created) + } + + /// + /// Reads the information of the Datafile file, then returns the dynamic value + /// + /// Value of the database file + public dynamic Read() + { + lock (this) // Locking so thread read/write + { + using (var compressed = new FileStream(file, FileMode.Open)) + { + if (!compressed.CanWrite || !compressed.CanRead) + throw new IOException("Invalid permissions to read or write"); // Throw when perms bad + + using (var uncompressed = new MemoryStream()) + { + // while loop to suppress compression errors + int failed = 0; + while (true) + { + try // trying deserialization + { + using (var gzip = new GZipStream(compressed, CompressionMode.Decompress, true) + ) // creating decompresser stream + gzip.CopyTo( + uncompressed); // copy stream to the uncompressed stream for manipulation + uncompressed.Seek(0, SeekOrigin.Begin); // Setting the position to 0 for deserialization + return uncompressed.Length != 0 + ? new BinaryFormatter().Deserialize(uncompressed) + : null; // Deserialization of the bytes given + } + catch (SerializationException) // Catching anything that has to due with serialization + { + failed++; + } + catch (IOException) // Catching anything that has to due with IO streams corrupting + { + failed++; + } + finally // throwing exception if failed too many times + { + if (failed > MAX_FAIL) + throw new SerializationException("Database failed to serialize items after " + MAX_FAIL + " attempts"); + } + } + } + } + } + } + /// + /// Writes the data to the database file, from the starting point + /// + /// The data to write to the database + public void Write(dynamic data) + { + lock (this) // Locking so thread read/write + { + if (!((object)data).GetType().IsSerializable) + throw new SerializationException("The object trying to be serialized is not marked serializable", + new NullReferenceException()); + + using (var fileStream = new FileStream(file, FileMode.Open)) + { + if (!fileStream.CanWrite || !fileStream.CanRead) + throw new IOException("Invalid permissions to read or write"); // Throw when perms bad + + byte[] bytes; + // while loop to supress compression errors + int failed = 0; + while (true) + { + try // trying serialization + { + using (var ms = new MemoryStream()) // Creating a memory stream for the bytes + using (var gzip = new GZipStream(ms, CompressionMode.Compress) + ) // Creating a GZip stream for compression + { + new BinaryFormatter().Serialize(gzip, data); // Serializing the bytes to the gzip stream + + // Closing the streams for read + gzip.Close(); + ms.Close(); + + // Setting the bytes in the class to the memorystream + bytes = ms.ToArray(); + break; + } + } + catch (SerializationException) // Catching anything that has to due with serialization + { + failed++; + } + catch (IOException) // Catching anything that has to due with IO streams corrupting + { + failed++; + } + finally // throwing exception if failed too many times + { + if (failed > MAX_FAIL) + throw new SerializationException("Database failed to serialize items after " + MAX_FAIL + " attempts"); + } + } + + fileStream.Write(bytes, 0, bytes.Length); // Writing the bytes to the stream, starting at 0 + } + } + } + } +} \ No newline at end of file diff --git a/src/Common/DataHolders/Storage/Ticket.cs b/src/Common/DataHolders/Storage/Ticket.cs index 6efddf3..74103b9 100644 --- a/src/Common/DataHolders/Storage/Ticket.cs +++ b/src/Common/DataHolders/Storage/Ticket.cs @@ -9,18 +9,17 @@ namespace DispatchSystem.Common.DataHolders.Storage [Serializable] public class Ticket : IDataHolder { - string _reason; - float _amount; - public string Reason => _reason; - public float Amount => _amount; + public string Reason { get; } + + public float Amount { get; } public DateTime Creation { get; } public Guid Id { get; } public Ticket(string reason, float amount) { - _reason = reason; - _amount = amount; + Reason = reason; + Amount = amount; Creation = DateTime.Now; Id = Guid.NewGuid(); diff --git a/src/Common/DataHolders/StorageVariable.cs b/src/Common/DataHolders/StorageVariable.cs deleted file mode 100644 index 110a675..0000000 --- a/src/Common/DataHolders/StorageVariable.cs +++ /dev/null @@ -1,133 +0,0 @@ -/* - -░▄███▄░████▄░████░████▄░░██░████░▄███▄░░░ -██▀░▀▀░██░██░██▄░░██░▀██░██░░██░░▀█▄▀▀░██ -██▄░▄▄░████▀░██▀░░██░▄██░██░░██░░▄▄▀█▄░░░ -░▀███▀░██░██░████░████▀░░██░░██░░▀███▀░██ -This entire was made by CloneCommando -ps thanks clone my boi -https://www.github.com/CloneCommando -Found in his CloNET repository -*/ - -using System; -using System.IO; -using System.IO.Compression; -using System.Runtime.Serialization.Formatters.Binary; - -namespace DispatchSystem.Common.DataHolders -{ - public struct StorableValue - { - private T value; - public T Value - { - get => value; - set - { - valChanged = true; - this.value = value; - } - } - - public string FilePath { get; set; } - - private byte[] bytes; - private bool valChanged; - public byte[] Bytes - { - set - { - using (var compressedStream = new MemoryStream()) - { - compressedStream.Write(value, 0, value.Length); - compressedStream.Seek(0, SeekOrigin.Begin); - - using (var uncompressedStream = new MemoryStream()) - { - uncompressedStream.Position = 0; - using (var decompress = new GZipStream(compressedStream, CompressionMode.Decompress, true)) - { - decompress.CopyTo(uncompressedStream); - } - uncompressedStream.Position = 0; - Value = (T)new BinaryFormatter().Deserialize(uncompressedStream); - } - } - - valChanged = true; - } - get - { - if (!valChanged) return bytes; - if (Value == null) return null; - if (!Value.GetType().IsSerializable) return null; - using (var ms = new MemoryStream()) - using (var gzip = new GZipStream(ms, CompressionMode.Compress)) - { - new BinaryFormatter().Serialize(gzip, Value); - - gzip.Close(); - ms.Close(); - - bytes = ms.ToArray(); - } - valChanged = false; - return bytes; - } - } - - public StorableValue(T value) : this() - { - Value = value; - valChanged = true; - } - - public StorableValue(string filePath) : this() - { - if (!File.Exists(filePath)) - throw new InvalidOperationException("The file does not exist!"); - - FilePath = filePath; - - Bytes = File.ReadAllBytes(filePath); - - valChanged = true; - } - - public StorableValue(byte[] valueBytes) : this() - { - Bytes = valueBytes; - - valChanged = true; - } - - public override string ToString() => Value.ToString(); - public override bool Equals(object obj) => Value.Equals(obj); - public override int GetHashCode() => Value.GetHashCode(); - - public static bool operator ==(StorableValue obj1, T obj2) - { - return obj1.Value.Equals(obj2); - } - - public static bool operator !=(StorableValue obj1, T obj2) - { - return !obj1.Value.Equals(obj2); - } - - public void Save() - { - if (string.IsNullOrWhiteSpace(FilePath)) - throw new InvalidOperationException("Cannot save to file if " + nameof(FilePath) + " is null or whitespace!"); - - File.WriteAllBytes(FilePath, Bytes); - } - - public static StorableValue operator +(StorableValue storableValue, T value) - { - storableValue.Value = value; - return storableValue; - } - } -} diff --git a/src/Common/Functions.cs b/src/Common/Functions.cs deleted file mode 100644 index 0299386..0000000 --- a/src/Common/Functions.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.IO; - -namespace DispatchSystem.Common -{ - public static class Functions - { - public static string ExceptionHandlerBackend(this Exception e, int exitCode) - { - string errorFile = "error0.dump"; - - { - ushort reiteration = 0; - - while (File.Exists(errorFile)) - errorFile = "error" + ++reiteration + ".dump"; - } - - return errorFile; - } - - public static string ToSplitID(this uint rawValue) - { - try - { - char[] idC = rawValue.ToString().ToCharArray(); - - return new string(new[] - { - idC[0], - idC[1], - idC[2], - '-', - idC[3], - idC[4], - idC[5], - '-', - idC[6], - idC[7], - idC[8] - }); - } - catch - { - return rawValue.ToString(); - } - } - - public static uint ToRawID(this string id) - { - try - { - char[] idC = id.ToCharArray(); - - return uint.Parse(new string(new[] - { - idC[0], - idC[1], - idC[2], - - idC[4], - idC[5], - idC[6], - - idC[8], - idC[9], - idC[10], - })); - } - catch - { - return uint.Parse(id.Replace("-", "")); - } - } - } -} diff --git a/src/Common/Permissions.cs b/src/Common/Permissions.cs new file mode 100644 index 0000000..a4d8fc8 --- /dev/null +++ b/src/Common/Permissions.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; + +namespace DispatchSystem.Common +{ + /// + /// Permission levels + /// + [Serializable] + public enum Permission + { + /// + /// Permission available to everyone + /// + Everyone, + /// + /// Permission available for specific people + /// + Specific, + /// + /// Permission available to nobody + /// + None + } + [Serializable] + public sealed class Permissions + { + #region Singleton + // Threadsafe lock for permission + private static readonly object _lock = new object(); + // Instance of permissions object + private static Permissions obj; + // The data of the files for permissions + private static string _data; + // Void to set the information listed above + public static void SetInformation(string data) + { + _data = data; + } + + /// + /// Property for returning the permissions + /// + public static Permissions Get + { + get + { + if (obj != null) return obj; // Checking if instance is already initiated + lock (_lock) // thread locking when instance null + if (obj == null) // checking if current thread thinks it's still null + obj = new Permissions(_data); // creating instance when everything checks out + return obj; // returns the instance + } + } + #endregion + + /// + /// The key to find when searching for Civilian perms + /// + public const string CIV_KEY = "civilian:"; + /// + /// The key to find when searching for LEO perms + /// + public const string COP_KEY = "leo:"; + /// + /// The key to find when searching for Dispatch perms + /// + public const string DISPATCH_KEY = "dispatcher:"; + + // A list of specific permissions + private readonly List> items = new List>(); + + /// + /// The permission for the Civilian + /// + public Permission CivilianPermission { get; private set; } = Permission.Specific; // default specific + /// + /// The permission for the LEO + /// + public Permission LeoPermission { get; private set; } = Permission.Specific; // default specific + /// + /// The permission for the Dispatcher + /// + public Permission DispatchPermission { get; private set; } = Permission.Specific; + + /// + /// IPs for Civilian specific permissions + /// + public IEnumerable CivilianData + { + get + { + foreach (var item in items) + if (item.Item1 == CIV_KEY) // finding where they key is the civ key + if (IPAddress.TryParse(item.Item2, out IPAddress address)) // checking if the ip can be parsable + yield return address; // yield returns the ip to a enumerable + } + } + /// + /// IPs for the LEO specific permissions + /// + public IEnumerable LeoData + { + get + { + foreach (var item in items) + if (item.Item1 == COP_KEY) // finding where they key is the leo key + if (IPAddress.TryParse(item.Item2, out IPAddress address)) // checking if the ip can be parsable + yield return address; // yield returns the ip to a enumerable + } + } + /// + /// IPs for the Dispatch specific permissions + /// + public IEnumerable DispatchData + { + get + { + foreach (var item in items) + if (item.Item1 == DISPATCH_KEY) // finding where they key is the dispatch key + if (IPAddress.TryParse(item.Item2, out IPAddress address)) // checking if the ip can be parsable + yield return address; // yield returns the ip to a enumerable + } + } + + #region constructor + private Permissions(string fileData) + { + // setting file items + Refresh(fileData); + } + public void Refresh(string data) + { + string current = string.Empty; // current key that the permissions is on + // splitting the lines so that it is only important lines + string[] lines = data.Split('\n').Where(x => !string.IsNullOrWhiteSpace(x)).Where(x => !x.StartsWith("//")) + .Select(x => x.Trim().ToLower()).ToArray(); + + // reading each line in all of the important lines + foreach (string line in lines) + { + // checking for key lines, then continuing + if (line == CIV_KEY || line == COP_KEY || line == DISPATCH_KEY) { current = line; continue; } + // if there is no key so far, then continue + if (current == string.Empty) continue; + + // switch for the current line + switch (line) + { + // checking for permission type of everyone + case "everyone": + // checking on which key it is on + switch (current) + { + case CIV_KEY: + // setting the civilian permission as everyone + CivilianPermission = Permission.Everyone; + break; + case COP_KEY: + // setting the leo permission as everyone + LeoPermission = Permission.Everyone; + break; + case DISPATCH_KEY: + // setting the dispatch permission as everyone + DispatchPermission = Permission.Everyone; + break; + } + break; + // checking for permission type of none + case "none": + switch (current) + { + case CIV_KEY: + // setting the civilian permission as none + CivilianPermission = Permission.None; + break; + case COP_KEY: + // setting the leo permission as none + LeoPermission = Permission.None; + break; + case DISPATCH_KEY: + // setting the dispatch permission as none + DispatchPermission = Permission.None; + break; + } + break; + // if no conditions apply, add the line as an IP to items + default: + items.Add(new Tuple(current, line)); + break; + } + } + } + #endregion + + // ez contains + public bool CivContains(IPAddress address) => CivilianData.Contains(address); + public bool LeoContains(IPAddress address) => LeoData.Contains(address); + public bool DispatchContains(IPAddress address) => DispatchData.Contains(address); + } +} diff --git a/src/DispatchSystem.sln b/src/DispatchSystem.sln index ca34898..4aad076 100644 --- a/src/DispatchSystem.sln +++ b/src/DispatchSystem.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2005 +VisualStudioVersion = 15.0.27004.2009 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{CDEB239A-F6BE-4EE8-B9BD-DB5AE476F8A6}" EndProject @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{98D8A98F-63AF-4CC1-9455-07390B2438A4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DumpUnloader", "DumpUnloader\DumpUnloader.csproj", "{AE90589C-1695-4F62-A408-FFA47938810E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -55,6 +57,18 @@ Global {98D8A98F-63AF-4CC1-9455-07390B2438A4}.Release|x64.Build.0 = Release|Any CPU {98D8A98F-63AF-4CC1-9455-07390B2438A4}.Release|x86.ActiveCfg = Release|Any CPU {98D8A98F-63AF-4CC1-9455-07390B2438A4}.Release|x86.Build.0 = Release|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Debug|x64.ActiveCfg = Debug|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Debug|x64.Build.0 = Debug|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Debug|x86.ActiveCfg = Debug|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Debug|x86.Build.0 = Debug|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Release|Any CPU.Build.0 = Release|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Release|x64.ActiveCfg = Release|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Release|x64.Build.0 = Release|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Release|x86.ActiveCfg = Release|Any CPU + {AE90589C-1695-4F62-A408-FFA47938810E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/DumpUnloader/App.config b/src/DumpUnloader/App.config new file mode 100644 index 0000000..731f6de --- /dev/null +++ b/src/DumpUnloader/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/DumpUnloader/BolosDialogue.Designer.cs b/src/DumpUnloader/BolosDialogue.Designer.cs new file mode 100644 index 0000000..a70b401 --- /dev/null +++ b/src/DumpUnloader/BolosDialogue.Designer.cs @@ -0,0 +1,97 @@ +namespace DumpUnloader +{ + partial class BolosDialogue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listView1 = new System.Windows.Forms.ListView(); + this.boloCreator = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.boloDesc = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.boloId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.boloCreation = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SuspendLayout(); + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.boloId, + this.boloCreation, + this.boloCreator, + this.boloDesc}); + this.listView1.FullRowSelect = true; + this.listView1.GridLines = true; + this.listView1.Location = new System.Drawing.Point(13, 13); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(683, 539); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + // + // boloCreator + // + this.boloCreator.Text = "Creator"; + this.boloCreator.Width = 160; + // + // boloDesc + // + this.boloDesc.Text = "Description"; + this.boloDesc.Width = 888; + // + // boloId + // + this.boloId.Text = "Id"; + this.boloId.Width = 220; + // + // boloCreation + // + this.boloCreation.Text = "Creation Date"; + this.boloCreation.Width = 120; + // + // BolosDialogue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(708, 564); + this.Controls.Add(this.listView1); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(724, 603); + this.MinimumSize = new System.Drawing.Size(724, 603); + this.Name = "BolosDialogue"; + this.Text = "BOLOs"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader boloCreator; + private System.Windows.Forms.ColumnHeader boloDesc; + private System.Windows.Forms.ColumnHeader boloId; + private System.Windows.Forms.ColumnHeader boloCreation; + } +} \ No newline at end of file diff --git a/src/DumpUnloader/BolosDialogue.cs b/src/DumpUnloader/BolosDialogue.cs new file mode 100644 index 0000000..522b3df --- /dev/null +++ b/src/DumpUnloader/BolosDialogue.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Forms; + +using DispatchSystem.Common.DataHolders.Storage; + +namespace DumpUnloader +{ + public partial class BolosDialogue : Form + { + public BolosDialogue(IEnumerable bolos) + { + InitializeComponent(); + + if (bolos == null) + { + MessageBox.Show("ERROR: BOLOs list is null! This is an immediate issue please contact BlockBa5her", + "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + foreach (var bolo in bolos) + { + ListViewItem item = new ListViewItem(bolo?.Id.ToString() ?? "NULL"); + item.SubItems.Add(bolo?.Creation.ToString(CultureInfo.InvariantCulture) ?? "NULL"); + item.SubItems.Add(bolo?.Player ?? "NULL"); + item.SubItems.Add(bolo?.Reason ?? "NULL"); + + listView1.Items.Add(item); + } + } + } +} diff --git a/src/DumpUnloader/BolosDialogue.resx b/src/DumpUnloader/BolosDialogue.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/DumpUnloader/BolosDialogue.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/DumpUnloader/CallDialogue.Designer.cs b/src/DumpUnloader/CallDialogue.Designer.cs new file mode 100644 index 0000000..cc1f881 --- /dev/null +++ b/src/DumpUnloader/CallDialogue.Designer.cs @@ -0,0 +1,102 @@ +namespace DumpUnloader +{ + partial class CallDialogue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listView1 = new System.Windows.Forms.ListView(); + this.callId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.callIp = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.callPlayer = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.callAccepted = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.callDate = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SuspendLayout(); + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.callId, + this.callIp, + this.callDate, + this.callPlayer, + this.callAccepted}); + this.listView1.FullRowSelect = true; + this.listView1.GridLines = true; + this.listView1.Location = new System.Drawing.Point(13, 13); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(796, 543); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + // + // callId + // + this.callId.Text = "Id"; + this.callId.Width = 220; + // + // callIp + // + this.callIp.Text = "Source IP"; + this.callIp.Width = 120; + // + // callPlayer + // + this.callPlayer.Text = "Player"; + this.callPlayer.Width = 120; + // + // callAccepted + // + this.callAccepted.Text = "Accepted"; + this.callAccepted.Width = 80; + // + // callDate + // + this.callDate.Text = "Creation Date"; + this.callDate.Width = 120; + // + // CallDialogue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(821, 568); + this.Controls.Add(this.listView1); + this.Name = "CallDialogue"; + this.Text = "Calls"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader callId; + private System.Windows.Forms.ColumnHeader callIp; + private System.Windows.Forms.ColumnHeader callPlayer; + private System.Windows.Forms.ColumnHeader callAccepted; + private System.Windows.Forms.ColumnHeader callDate; + } +} \ No newline at end of file diff --git a/src/DumpUnloader/CallDialogue.cs b/src/DumpUnloader/CallDialogue.cs new file mode 100644 index 0000000..a341709 --- /dev/null +++ b/src/DumpUnloader/CallDialogue.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Forms; + +using DispatchSystem.Common.DataHolders.Storage; + +namespace DumpUnloader +{ + public partial class CallDialogue : Form + { + public CallDialogue(IEnumerable calls) + { + InitializeComponent(); + + if (calls == null) + { + MessageBox.Show("ERROR: Call list is null! This is an immediate issue please contact BlockBa5her", + "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + foreach (var call in calls) + { + ListViewItem item = new ListViewItem(call?.Id.ToString() ?? "NULL"); + item.SubItems.Add(call?.SourceIP ?? "NULL"); + item.SubItems.Add(call?.PlayerName ?? "NULL"); + item.SubItems.Add(call?.Accepted.ToString() ?? "NULL"); + item.SubItems.Add(call?.Creation.ToString(CultureInfo.InvariantCulture) ?? "NULL"); + + listView1.Items.Add(item); + } + } + } +} diff --git a/src/DumpUnloader/CallDialogue.resx b/src/DumpUnloader/CallDialogue.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/DumpUnloader/CallDialogue.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/DumpUnloader/CivilianDialogue.Designer.cs b/src/DumpUnloader/CivilianDialogue.Designer.cs new file mode 100644 index 0000000..4e5a712 --- /dev/null +++ b/src/DumpUnloader/CivilianDialogue.Designer.cs @@ -0,0 +1,129 @@ +namespace DumpUnloader +{ + partial class CivilianDialogue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.a = new System.Windows.Forms.ListView(); + this.civId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.civIp = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.civFirst = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.civLast = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.civWarrant = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.civCreation = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.civNotes = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.civTickets = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SuspendLayout(); + // + // a + // + this.a.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.civId, + this.civIp, + this.civFirst, + this.civLast, + this.civWarrant, + this.civCreation, + this.civNotes, + this.civTickets}); + this.a.FullRowSelect = true; + this.a.GridLines = true; + this.a.Location = new System.Drawing.Point(13, 13); + this.a.Name = "a"; + this.a.Size = new System.Drawing.Size(785, 464); + this.a.TabIndex = 0; + this.a.UseCompatibleStateImageBehavior = false; + this.a.View = System.Windows.Forms.View.Details; + // + // civId + // + this.civId.Text = "Id"; + this.civId.Width = 220; + // + // civIp + // + this.civIp.Text = "Source IP"; + this.civIp.Width = 120; + // + // civFirst + // + this.civFirst.Text = "First"; + this.civFirst.Width = 90; + // + // civLast + // + this.civLast.Text = "Last"; + this.civLast.Width = 90; + // + // civWarrant + // + this.civWarrant.Text = "Warrant"; + this.civWarrant.Width = 70; + // + // civCreation + // + this.civCreation.Text = "Creation"; + this.civCreation.Width = 120; + // + // civNotes + // + this.civNotes.Text = "Notes"; + this.civNotes.Width = 430; + // + // civTickets + // + this.civTickets.Text = "Tickets"; + this.civTickets.Width = 430; + // + // CivilianDialogue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(810, 489); + this.Controls.Add(this.a); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(826, 528); + this.MinimumSize = new System.Drawing.Size(826, 528); + this.Name = "CivilianDialogue"; + this.Text = "Civilians"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView a; + private System.Windows.Forms.ColumnHeader civId; + private System.Windows.Forms.ColumnHeader civIp; + private System.Windows.Forms.ColumnHeader civFirst; + private System.Windows.Forms.ColumnHeader civLast; + private System.Windows.Forms.ColumnHeader civWarrant; + private System.Windows.Forms.ColumnHeader civCreation; + private System.Windows.Forms.ColumnHeader civNotes; + private System.Windows.Forms.ColumnHeader civTickets; + } +} \ No newline at end of file diff --git a/src/DumpUnloader/CivilianDialogue.cs b/src/DumpUnloader/CivilianDialogue.cs new file mode 100644 index 0000000..7372e6e --- /dev/null +++ b/src/DumpUnloader/CivilianDialogue.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Forms; +using DispatchSystem.Common.DataHolders.Storage; + +namespace DumpUnloader +{ + public partial class CivilianDialogue : Form + { + public CivilianDialogue(IEnumerable civs) + { + InitializeComponent(); + + if (civs == null) + { + MessageBox.Show("ERROR: Civilian list is null! This is an immediate issue please contact BlockBa5her", + "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + foreach (var civ in civs) + { + ListViewItem item = new ListViewItem(civ?.Id.ToString() ?? "NULL"); + item.SubItems.Add(civ?.SourceIP ?? "NULL"); + item.SubItems.Add(civ?.First ?? "NULL"); + item.SubItems.Add(civ?.Last ?? "NULL"); + item.SubItems.Add(civ?.WarrantStatus.ToString() ?? "NULL"); + item.SubItems.Add(civ?.Creation.ToString(CultureInfo.InvariantCulture) ?? "NULL"); + + string notes = string.Empty; + if (civ != null) + for (int i = 0; i < civ.Notes.Count; i++) + notes += (i == 0 ? "" : " ;;; ") + civ.Notes[i]; + else + notes = "NULL"; + item.SubItems.Add(notes); + + string tickets = string.Empty; + if (civ != null) + for (int i = 0; i < civ.Tickets.Count; i++) + tickets += (i == 0 ? "" : " ;;; ") + $"${civ?.Tickets[i].Amount} | {civ?.Tickets[i].Reason}"; + else + tickets = "NULL"; + item.SubItems.Add(tickets); + + a.Items.Add(item); + } + } + } +} diff --git a/src/DumpUnloader/CivilianDialogue.resx b/src/DumpUnloader/CivilianDialogue.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/DumpUnloader/CivilianDialogue.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/DumpUnloader/Dump.cs b/src/DumpUnloader/Dump.cs new file mode 100644 index 0000000..1f9f2f3 --- /dev/null +++ b/src/DumpUnloader/Dump.cs @@ -0,0 +1,15 @@ +using DispatchSystem.Common; +using DispatchSystem.Common.DataHolders.Storage; + +namespace DumpUnloader +{ + public class Dump + { + public StorageManager Civilians { get; set; } + public StorageManager Vehicles { get; set; } + public StorageManager Bolos { get; set; } + public StorageManager EmergencyCalls { get; set; } + public StorageManager Officers { get; set; } + public Permissions Permissions { get; set; } + } +} \ No newline at end of file diff --git a/src/DumpUnloader/DumpDialogue.Designer.cs b/src/DumpUnloader/DumpDialogue.Designer.cs new file mode 100644 index 0000000..b0a7222 --- /dev/null +++ b/src/DumpUnloader/DumpDialogue.Designer.cs @@ -0,0 +1,170 @@ +namespace DumpUnloader +{ + partial class DumpDialogue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.civs = new System.Windows.Forms.Button(); + this.vehs = new System.Windows.Forms.Button(); + this.ofcs = new System.Windows.Forms.Button(); + this.bolos = new System.Windows.Forms.Button(); + this.calls = new System.Windows.Forms.Button(); + this.perms = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // civs + // + this.civs.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.civs.Location = new System.Drawing.Point(6, 15); + this.civs.Name = "civs"; + this.civs.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.civs.Size = new System.Drawing.Size(135, 47); + this.civs.TabIndex = 1; + this.civs.Text = "Civilians"; + this.civs.UseVisualStyleBackColor = true; + this.civs.Click += new System.EventHandler(this.CiviliansClick); + // + // vehs + // + this.vehs.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.vehs.Location = new System.Drawing.Point(6, 68); + this.vehs.Name = "vehs"; + this.vehs.Size = new System.Drawing.Size(133, 47); + this.vehs.TabIndex = 2; + this.vehs.Text = "Vehicles"; + this.vehs.UseVisualStyleBackColor = true; + this.vehs.Click += new System.EventHandler(this.VehiclesClick); + // + // ofcs + // + this.ofcs.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ofcs.Location = new System.Drawing.Point(6, 121); + this.ofcs.Name = "ofcs"; + this.ofcs.Size = new System.Drawing.Size(135, 47); + this.ofcs.TabIndex = 3; + this.ofcs.Text = "Officers"; + this.ofcs.UseVisualStyleBackColor = true; + this.ofcs.Click += new System.EventHandler(this.OfficersClick); + // + // bolos + // + this.bolos.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.bolos.Location = new System.Drawing.Point(6, 174); + this.bolos.Name = "bolos"; + this.bolos.Size = new System.Drawing.Size(136, 47); + this.bolos.TabIndex = 4; + this.bolos.Text = "BOLOs"; + this.bolos.UseVisualStyleBackColor = true; + this.bolos.Click += new System.EventHandler(this.BolosClick); + // + // calls + // + this.calls.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.calls.Location = new System.Drawing.Point(6, 227); + this.calls.Name = "calls"; + this.calls.Size = new System.Drawing.Size(135, 47); + this.calls.TabIndex = 5; + this.calls.Text = "911 Calls"; + this.calls.UseVisualStyleBackColor = true; + this.calls.Click += new System.EventHandler(this.CallsClick); + // + // perms + // + this.perms.Location = new System.Drawing.Point(6, 19); + this.perms.Name = "perms"; + this.perms.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.perms.Size = new System.Drawing.Size(135, 47); + this.perms.TabIndex = 6; + this.perms.Text = "Permissions"; + this.perms.UseVisualStyleBackColor = true; + this.perms.Click += new System.EventHandler(this.PermissionsClick); + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.perms); + this.groupBox1.Location = new System.Drawing.Point(163, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(145, 295); + this.groupBox1.TabIndex = 8; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Other Options"; + // + // groupBox2 + // + this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox2.Controls.Add(this.civs); + this.groupBox2.Controls.Add(this.vehs); + this.groupBox2.Controls.Add(this.calls); + this.groupBox2.Controls.Add(this.ofcs); + this.groupBox2.Controls.Add(this.bolos); + this.groupBox2.Location = new System.Drawing.Point(12, 12); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(145, 295); + this.groupBox2.TabIndex = 9; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "List Options"; + // + // DumpDialogue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(320, 319); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.MinimumSize = new System.Drawing.Size(336, 358); + this.Name = "DumpDialogue"; + this.Text = "Dump Unloader"; + this.groupBox1.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.Button civs; + private System.Windows.Forms.Button vehs; + private System.Windows.Forms.Button ofcs; + private System.Windows.Forms.Button bolos; + private System.Windows.Forms.Button calls; + private System.Windows.Forms.Button perms; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.GroupBox groupBox2; + } +} \ No newline at end of file diff --git a/src/DumpUnloader/DumpDialogue.cs b/src/DumpUnloader/DumpDialogue.cs new file mode 100644 index 0000000..41f1056 --- /dev/null +++ b/src/DumpUnloader/DumpDialogue.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace DumpUnloader +{ + public partial class DumpDialogue : Form + { + private readonly Dump information; + + public DumpDialogue(Dump information) + { + this.information = information; + InitializeComponent(); + } + + private void PermissionsClick(object sender, EventArgs e) + { + new PermissionsDialogue(information.Permissions).Show(); + } + + private void CiviliansClick(object sender, EventArgs e) + { + new CivilianDialogue(information.Civilians).Show(); + } + + private void VehiclesClick(object sender, EventArgs e) + { + new VehicleDialogue(information.Vehicles).Show(); + } + + private void BolosClick(object sender, EventArgs e) + { + new BolosDialogue(information.Bolos).Show(); + } + + private void CallsClick(object sender, EventArgs e) + { + new CallDialogue(information.EmergencyCalls).Show(); + } + + private void OfficersClick(object sender, EventArgs e) + { + new OfficerDialogue(information.Officers).Show(); + } + } +} diff --git a/src/DumpUnloader/DumpDialogue.resx b/src/DumpUnloader/DumpDialogue.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/DumpUnloader/DumpDialogue.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/DumpUnloader/DumpParser.cs b/src/DumpUnloader/DumpParser.cs new file mode 100644 index 0000000..889e41c --- /dev/null +++ b/src/DumpUnloader/DumpParser.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; +using System.Windows.Forms; +using DispatchSystem.Common; +using DispatchSystem.Common.DataHolders.Storage; +using EZDatabase; + +namespace DumpUnloader +{ + internal class DumpParser + { + public Dump DumpInformation { get; } + public DumpResult Result { get; } + + public DumpParser(string file) + { + Tuple, StorageManager, StorageManager, StorageManager, StorageManager, Permissions> parsedInfo; + var database = new Database(file, false); + + try + { + parsedInfo = database.Read(); + Result = DumpResult.Successful; + } + catch (InvalidCastException) + { + MessageBox.Show("DumpParser had a problem parsing the given file!", "DumpUnloader", + MessageBoxButtons.OK, MessageBoxIcon.Error); + Result = DumpResult.Invalid; + return; + } + catch (IOException) + { + MessageBox.Show($"DumpParser couldn't file the file {file}", "DumpUnloader", MessageBoxButtons.OK, + MessageBoxIcon.Error); + Result = DumpResult.FileNotFound; + return; + } + + DumpInformation = new Dump + { + Civilians = parsedInfo?.Item1, + Vehicles = parsedInfo?.Item2, + Bolos = parsedInfo?.Item3, + EmergencyCalls = parsedInfo?.Item4, + Officers = parsedInfo?.Item5, + Permissions = parsedInfo?.Item6 + }; + } + } +} diff --git a/src/DumpUnloader/DumpResult.cs b/src/DumpUnloader/DumpResult.cs new file mode 100644 index 0000000..042d14b --- /dev/null +++ b/src/DumpUnloader/DumpResult.cs @@ -0,0 +1,9 @@ +namespace DumpUnloader +{ + public enum DumpResult + { + Successful, + Invalid, + FileNotFound + } +} \ No newline at end of file diff --git a/src/DumpUnloader/DumpUnloader.csproj b/src/DumpUnloader/DumpUnloader.csproj new file mode 100644 index 0000000..e742db6 --- /dev/null +++ b/src/DumpUnloader/DumpUnloader.csproj @@ -0,0 +1,145 @@ + + + + + Debug + AnyCPU + {AE90589C-1695-4F62-A408-FFA47938810E} + WinExe + DumpUnloader + DumpUnloader + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + ..\bin\DumpUnloader\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\bin\DumpUnloader\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + Form + + + BolosDialogue.cs + + + Form + + + CallDialogue.cs + + + Form + + + CivilianDialogue.cs + + + + + Form + + + DumpDialogue.cs + + + + Form + + + OfficerDialogue.cs + + + Form + + + PermissionsDialogue.cs + + + + + Form + + + VehicleDialogue.cs + + + BolosDialogue.cs + + + CallDialogue.cs + + + CivilianDialogue.cs + + + DumpDialogue.cs + + + OfficerDialogue.cs + + + PermissionsDialogue.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + VehicleDialogue.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + {98d8a98f-63af-4cc1-9455-07390b2438a4} + Common + + + + \ No newline at end of file diff --git a/src/DumpUnloader/OfficerDialogue.Designer.cs b/src/DumpUnloader/OfficerDialogue.Designer.cs new file mode 100644 index 0000000..ac55f32 --- /dev/null +++ b/src/DumpUnloader/OfficerDialogue.Designer.cs @@ -0,0 +1,105 @@ +namespace DumpUnloader +{ + partial class OfficerDialogue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listView1 = new System.Windows.Forms.ListView(); + this.ofcId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ofcIp = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ofcCreation = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ofcCallsign = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ofcStatus = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SuspendLayout(); + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.ofcId, + this.ofcIp, + this.ofcCreation, + this.ofcCallsign, + this.ofcStatus}); + this.listView1.FullRowSelect = true; + this.listView1.GridLines = true; + this.listView1.Location = new System.Drawing.Point(13, 13); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(765, 490); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + // + // ofcId + // + this.ofcId.Text = "Id"; + this.ofcId.Width = 220; + // + // ofcIp + // + this.ofcIp.Text = "Source IP"; + this.ofcIp.Width = 120; + // + // ofcCreation + // + this.ofcCreation.Text = "Creation Date"; + this.ofcCreation.Width = 120; + // + // ofcCallsign + // + this.ofcCallsign.Text = "Callsign"; + this.ofcCallsign.Width = 90; + // + // ofcStatus + // + this.ofcStatus.Text = "Status"; + this.ofcStatus.Width = 120; + // + // OfficerDialogue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(790, 515); + this.Controls.Add(this.listView1); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(806, 554); + this.MinimumSize = new System.Drawing.Size(806, 554); + this.Name = "OfficerDialogue"; + this.Text = "Officers"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader ofcId; + private System.Windows.Forms.ColumnHeader ofcIp; + private System.Windows.Forms.ColumnHeader ofcCreation; + private System.Windows.Forms.ColumnHeader ofcCallsign; + private System.Windows.Forms.ColumnHeader ofcStatus; + } +} \ No newline at end of file diff --git a/src/DumpUnloader/OfficerDialogue.cs b/src/DumpUnloader/OfficerDialogue.cs new file mode 100644 index 0000000..5a3b48b --- /dev/null +++ b/src/DumpUnloader/OfficerDialogue.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using DispatchSystem.Common.DataHolders.Storage; + +namespace DumpUnloader +{ + public partial class OfficerDialogue : Form + { + public OfficerDialogue(IEnumerable officers) + { + InitializeComponent(); + + if (officers == null) + { + MessageBox.Show("ERROR: Officers list is null! This is an immediate issue please contact BlockBa5her", + "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + foreach (var officer in officers) + { + ListViewItem item = new ListViewItem(officer?.Id.ToString() ?? "NULL"); + item.SubItems.Add(officer?.SourceIP ?? "NULL"); + item.SubItems.Add(officer?.Creation.ToString(CultureInfo.InvariantCulture) ?? "NULL"); + item.SubItems.Add(officer?.Callsign ?? "NULL"); + item.SubItems.Add(officer?.Status.ToString() ?? "NULL"); + + listView1.Items.Add(item); + } + } + } +} diff --git a/src/DumpUnloader/OfficerDialogue.resx b/src/DumpUnloader/OfficerDialogue.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/DumpUnloader/OfficerDialogue.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/DumpUnloader/PermissionsDialogue.Designer.cs b/src/DumpUnloader/PermissionsDialogue.Designer.cs new file mode 100644 index 0000000..c1dfa26 --- /dev/null +++ b/src/DumpUnloader/PermissionsDialogue.Designer.cs @@ -0,0 +1,156 @@ +namespace DumpUnloader +{ + partial class PermissionsDialogue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.civs = new System.Windows.Forms.ListView(); + this.leo = new System.Windows.Forms.ListView(); + this.dispatch = new System.Windows.Forms.ListView(); + this.civItems = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.leoItems = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.dispatchItems = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(75, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Civilian Perms:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(257, 13); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(63, 13); + this.label2.TabIndex = 4; + this.label2.Text = "LEO Perms:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(504, 13); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(84, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Dispatch Perms:"; + // + // civs + // + this.civs.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.civItems}); + this.civs.FullRowSelect = true; + this.civs.GridLines = true; + this.civs.Location = new System.Drawing.Point(13, 30); + this.civs.Name = "civs"; + this.civs.Size = new System.Drawing.Size(241, 531); + this.civs.TabIndex = 6; + this.civs.UseCompatibleStateImageBehavior = false; + this.civs.View = System.Windows.Forms.View.Details; + // + // leo + // + this.leo.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.leoItems}); + this.leo.FullRowSelect = true; + this.leo.GridLines = true; + this.leo.Location = new System.Drawing.Point(260, 30); + this.leo.Name = "leo"; + this.leo.Size = new System.Drawing.Size(241, 531); + this.leo.TabIndex = 7; + this.leo.UseCompatibleStateImageBehavior = false; + this.leo.View = System.Windows.Forms.View.Details; + // + // dispatch + // + this.dispatch.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.dispatchItems}); + this.dispatch.FullRowSelect = true; + this.dispatch.GridLines = true; + this.dispatch.Location = new System.Drawing.Point(507, 30); + this.dispatch.Name = "dispatch"; + this.dispatch.Size = new System.Drawing.Size(241, 531); + this.dispatch.TabIndex = 8; + this.dispatch.UseCompatibleStateImageBehavior = false; + this.dispatch.View = System.Windows.Forms.View.Details; + // + // civItems + // + this.civItems.Text = "Items"; + this.civItems.Width = 241; + // + // leoItems + // + this.leoItems.Text = "Items"; + this.leoItems.Width = 241; + // + // dispatchItems + // + this.dispatchItems.Text = "Items"; + this.dispatchItems.Width = 241; + // + // PermissionsDialogue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(759, 573); + this.Controls.Add(this.dispatch); + this.Controls.Add(this.leo); + this.Controls.Add(this.civs); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(775, 612); + this.MinimumSize = new System.Drawing.Size(775, 612); + this.Name = "PermissionsDialogue"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.Text = "Permissions"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.ListView civs; + private System.Windows.Forms.ListView leo; + private System.Windows.Forms.ListView dispatch; + private System.Windows.Forms.ColumnHeader civItems; + private System.Windows.Forms.ColumnHeader leoItems; + private System.Windows.Forms.ColumnHeader dispatchItems; + } +} \ No newline at end of file diff --git a/src/DumpUnloader/PermissionsDialogue.cs b/src/DumpUnloader/PermissionsDialogue.cs new file mode 100644 index 0000000..ae20e70 --- /dev/null +++ b/src/DumpUnloader/PermissionsDialogue.cs @@ -0,0 +1,77 @@ +using System.Windows.Forms; +using DispatchSystem.Common; + +namespace DumpUnloader +{ + public partial class PermissionsDialogue : Form + { + public PermissionsDialogue(Permissions settings) + { + InitializeComponent(); + + if (settings == null) + { + MessageBox.Show("ERROR: Permissions is null! This is an immediate issue please contact BlockBa5her", + "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + switch (settings?.CivilianPermission) + { + case Permission.Everyone: + civs.Items.Add("Everyone"); + break; + case Permission.None: + civs.Items.Add("None"); + break; + case null: + civs.Items.Add("NULL"); + break; + default: + foreach (var item in settings.CivilianData) + { + civs.Items.Add(item?.ToString() ?? "NULL"); + } + break; + } + + switch (settings?.DispatchPermission) + { + case Permission.Everyone: + dispatch.Items.Add("Everyone"); + break; + case Permission.None: + dispatch.Items.Add("None"); + break; + case null: + dispatch.Items.Add("NULL"); + break; + default: + foreach (var item in settings.DispatchData) + { + dispatch.Items.Add(item?.ToString() ?? "NULL"); + } + break; + } + + switch (settings?.LeoPermission) + { + case Permission.Everyone: + leo.Items.Add("Everyone"); + break; + case Permission.None: + leo.Items.Add("None"); + break; + case null: + leo.Items.Add("NULL"); + break; + default: + foreach (var item in settings.LeoData) + { + leo.Items.Add(item?.ToString() ?? "NULL"); + } + break; + } + } + } +} diff --git a/src/DumpUnloader/PermissionsDialogue.resx b/src/DumpUnloader/PermissionsDialogue.resx new file mode 100644 index 0000000..61bc649 --- /dev/null +++ b/src/DumpUnloader/PermissionsDialogue.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/src/DumpUnloader/Program.cs b/src/DumpUnloader/Program.cs new file mode 100644 index 0000000..72c613d --- /dev/null +++ b/src/DumpUnloader/Program.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace DumpUnloader +{ + static class Program + { + private static DumpParser parser; + + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() + { + parser = new DumpParser("dispatchsystem.dmp"); + + if (parser.Result != DumpResult.Successful) + { + MessageBox.Show("Exiting because of unsuccessful dump read", "DumpUnloader", MessageBoxButtons.OK, + MessageBoxIcon.None); + return; + } + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new DumpDialogue(parser.DumpInformation)); + } + } +} diff --git a/src/DumpUnloader/Properties/AssemblyInfo.cs b/src/DumpUnloader/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d320e91 --- /dev/null +++ b/src/DumpUnloader/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DumpUnloader")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DumpUnloader")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ae90589c-1695-4f62-a408-ffa47938810e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/DumpUnloader/Properties/Resources.Designer.cs b/src/DumpUnloader/Properties/Resources.Designer.cs new file mode 100644 index 0000000..3c7b715 --- /dev/null +++ b/src/DumpUnloader/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DumpUnloader.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DumpUnloader.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/src/DumpUnloader/Properties/Resources.resx b/src/DumpUnloader/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/src/DumpUnloader/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/DumpUnloader/Properties/Settings.Designer.cs b/src/DumpUnloader/Properties/Settings.Designer.cs new file mode 100644 index 0000000..561a17c --- /dev/null +++ b/src/DumpUnloader/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DumpUnloader.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/src/DumpUnloader/Properties/Settings.settings b/src/DumpUnloader/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/src/DumpUnloader/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/DumpUnloader/VehicleDialogue.Designer.cs b/src/DumpUnloader/VehicleDialogue.Designer.cs new file mode 100644 index 0000000..2a85e97 --- /dev/null +++ b/src/DumpUnloader/VehicleDialogue.Designer.cs @@ -0,0 +1,129 @@ +namespace DumpUnloader +{ + partial class VehicleDialogue + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listView1 = new System.Windows.Forms.ListView(); + this.vehId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.vehIp = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.vehCreation = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.vehPlate = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.vehOwner = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.vehStolen = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.vehRegi = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.vehInsured = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SuspendLayout(); + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.vehId, + this.vehIp, + this.vehCreation, + this.vehPlate, + this.vehOwner, + this.vehStolen, + this.vehRegi, + this.vehInsured}); + this.listView1.FullRowSelect = true; + this.listView1.GridLines = true; + this.listView1.Location = new System.Drawing.Point(13, 13); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(785, 464); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + // + // vehId + // + this.vehId.Text = "Id"; + this.vehId.Width = 220; + // + // vehIp + // + this.vehIp.Text = "Source IP"; + this.vehIp.Width = 120; + // + // vehCreation + // + this.vehCreation.Text = "Creation Date"; + this.vehCreation.Width = 120; + // + // vehPlate + // + this.vehPlate.Text = "Plate"; + this.vehPlate.Width = 120; + // + // vehOwner + // + this.vehOwner.Text = "Owner Id"; + this.vehOwner.Width = 220; + // + // vehStolen + // + this.vehStolen.Text = "Stolen"; + this.vehStolen.Width = 70; + // + // vehRegi + // + this.vehRegi.Text = "Registered"; + this.vehRegi.Width = 70; + // + // vehInsured + // + this.vehInsured.Text = "Insurance"; + this.vehInsured.Width = 70; + // + // VehicleDialogue + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(810, 489); + this.Controls.Add(this.listView1); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(826, 528); + this.MinimumSize = new System.Drawing.Size(826, 528); + this.Name = "VehicleDialogue"; + this.Text = "Vehicles"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader vehId; + private System.Windows.Forms.ColumnHeader vehIp; + private System.Windows.Forms.ColumnHeader vehPlate; + private System.Windows.Forms.ColumnHeader vehOwner; + private System.Windows.Forms.ColumnHeader vehCreation; + private System.Windows.Forms.ColumnHeader vehStolen; + private System.Windows.Forms.ColumnHeader vehRegi; + private System.Windows.Forms.ColumnHeader vehInsured; + } +} \ No newline at end of file diff --git a/src/DumpUnloader/VehicleDialogue.cs b/src/DumpUnloader/VehicleDialogue.cs new file mode 100644 index 0000000..7259cfb --- /dev/null +++ b/src/DumpUnloader/VehicleDialogue.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Forms; + +using DispatchSystem.Common.DataHolders.Storage; + +namespace DumpUnloader +{ + public partial class VehicleDialogue : Form + { + public VehicleDialogue(IEnumerable vehicles) + { + InitializeComponent(); + + if (vehicles == null) + { + MessageBox.Show("ERROR: Vehicles list is null! This is an immediate issue please contact BlockBa5her", + "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + foreach (var veh in vehicles) + { + ListViewItem item = new ListViewItem(veh?.Id.ToString() ?? "NULL"); + item.SubItems.Add(veh?.SourceIP ?? "NULL"); + item.SubItems.Add(veh?.Creation.ToString(CultureInfo.InvariantCulture) ?? "NULL"); + item.SubItems.Add(veh?.Plate ?? "NULL"); + item.SubItems.Add(veh?.Owner?.Id.ToString() ?? "NULL"); + item.SubItems.Add(veh?.StolenStatus.ToString() ?? "NULL"); + item.SubItems.Add(veh?.Registered.ToString() ?? "NULL"); + item.SubItems.Add(veh?.Insured.ToString() ?? "NULL"); + + listView1.Items.Add(item); + } + } + } +} diff --git a/src/DumpUnloader/VehicleDialogue.resx b/src/DumpUnloader/VehicleDialogue.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/DumpUnloader/VehicleDialogue.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Server/CommandAttribute.cs b/src/Server/CommandAttribute.cs index 89fb9df..8e619cc 100644 --- a/src/Server/CommandAttribute.cs +++ b/src/Server/CommandAttribute.cs @@ -2,19 +2,39 @@ namespace DispatchSystem.sv { - [Flags] + /// + /// The type of command + /// Used for command permissions + /// + [Flags] // Flags used for multiple permissions given public enum CommandType { + /// + /// Permission for LEO use + /// Leo, + /// + /// Permission for Civilian use + /// Civilian } - [AttributeUsage(AttributeTargets.Method)] + /// + /// + /// Command attribute for setting commands in dispatchsystem + /// + [AttributeUsage(AttributeTargets.Method)] // Only supposed to be used on methods public class CommandAttribute : Attribute { + /// + /// Command permissions + /// public CommandType Type { get; } + /// + /// The string for the command given + /// public string Command { get; } - + public CommandAttribute(CommandType type, string command) { Type = type; diff --git a/src/Server/Commands.cs b/src/Server/Commands.cs index 579c370..508cc18 100644 --- a/src/Server/Commands.cs +++ b/src/Server/Commands.cs @@ -1,26 +1,57 @@ -using CitizenFX.Core; +using System; +using CitizenFX.Core; +using DispatchSystem.Common.DataHolders.Storage; +using DispatchSystem.sv.External; using static CitizenFX.Core.BaseScript; +using EZDatabase; + namespace DispatchSystem.sv { public class Commands { + /// + /// Command for reseting the current profiles + /// + /// + /// [Command(CommandType.Civilian | CommandType.Leo, "/dsreset")] public void DispatchSystemReset(Player p, string[] args) { TriggerEvent("dispatchsystem:dsreset", p.Handle); } - [Command(CommandType.Civilian, "/civ")] + /// + /// Command for opening the Civilian NUI + /// + /// + /// + [Command(CommandType.Civilian, "/dsciv")] public void CivilianNuiInit(Player p, string[] args) { TriggerClientEvent(p, "dispatchsystem:toggleCivNUI"); } - [Command(CommandType.Leo, "/leo")] + /// + /// Command for opening the LEO NUI + /// + /// + /// + [Command(CommandType.Leo, "/dsleo")] public void LeoNuiInit(Player p, string[] args) { TriggerClientEvent(p, "dispatchsystem:toggleLeoNUI"); } + + /// + /// Dumps everything into a file, and clears all databases + /// + /// + /// + [Command(CommandType.Leo | CommandType.Civilian, "/dsdmp")] + public void DispatchSystemDump(Player p, string[] args) + { + DispatchSystem.EmergencyDump(p); + } } } \ No newline at end of file diff --git a/src/Server/Common.cs b/src/Server/Common.cs index 756a5b6..7a665ab 100644 --- a/src/Server/Common.cs +++ b/src/Server/Common.cs @@ -18,59 +18,88 @@ public static class Common { public static Civilian GetCivilian(string pHandle) { - return civs.FirstOrDefault(item => GetPlayerByIp(item.SourceIP)?.Handle == pHandle); + return Civs.FirstOrDefault(item => GetPlayerByIp(item.SourceIP)?.Handle == pHandle); // Finding the first civ that has that handle } public static Civilian GetCivilianByName(string first, string last) { - return civs.FirstOrDefault(item => string.Equals(item.First, first, StringComparison.CurrentCultureIgnoreCase) && string.Equals(item.Last, last, StringComparison.CurrentCultureIgnoreCase)); + return Civs.FirstOrDefault(item => + string.Equals(item.First, first, StringComparison.CurrentCultureIgnoreCase) && + string.Equals(item.Last, last, + StringComparison.CurrentCultureIgnoreCase)); // Finding the first civ that has that name } public static CivilianVeh GetCivilianVeh(string pHandle) { - return civVehs.Where(item => GetPlayerByIp(item.SourceIP) != null).FirstOrDefault(item => GetPlayerByIp(item.SourceIP).Handle == pHandle); + return CivVehs.FirstOrDefault(item => GetPlayerByIp(item.SourceIP)?.Handle == pHandle); // Finding the first Civilian Vehicle that has that handle } public static CivilianVeh GetCivilianVehByPlate(string plate) { - return civVehs.FirstOrDefault(item => string.Equals(item.Plate, plate, StringComparison.CurrentCultureIgnoreCase)); + return CivVehs.FirstOrDefault(item => string.Equals(item.Plate, plate, StringComparison.CurrentCultureIgnoreCase)); // Finding the first civilian vehicle that has that plate } public static Officer GetOfficer(string pHandle) { - return officers.Where(item => GetPlayerByIp(item.SourceIP) != null).FirstOrDefault(item => GetPlayerByIp(item.SourceIP).Handle == pHandle); + return Officers.FirstOrDefault(item => GetPlayerByIp(item.SourceIP)?.Handle == pHandle); // Finding the first officer with that handle } public static EmergencyCall GetEmergencyCall(string pHandle) { - return currentCalls.FirstOrDefault(item => GetPlayerByIp(item.SourceIP)?.Handle == pHandle); + return CurrentCalls.FirstOrDefault(item => GetPlayerByIp(item.SourceIP)?.Handle == pHandle); // Finding the first handle with the emergency call } public static Assignment GetOfficerAssignment(Officer ofc) { - return ofcAssignments.ContainsKey(ofc) ? ofcAssignments[ofc] : null; + return OfcAssignments.ContainsKey(ofc) ? OfcAssignments[ofc] : null; // Returning the officer's assignment } internal static void RemoveAllInstancesOfAssignment(Assignment assignment) { - foreach (var item in ofcAssignments) - if (item.Value.Id == assignment.Id) - ofcAssignments.Remove(item.Key); + for (int i = 0; i < OfcAssignments.Count; i++) + if (OfcAssignments.ToList()[i].Value.Id == assignment.Id) + { + var item = OfcAssignments.ToList()[i]; + item.Key.Status = OfficerStatus.OnDuty; // setting the status to onduty + OfcAssignments.Remove(item.Key); // Removing the assignment that has the right id + break; + } - assignments.Remove(assignment); + Assignments.Remove(assignment); // Removing the assignment from the assignments } internal static Player GetPlayerByHandle(string handle) { - return new PlayerList().FirstOrDefault(plr => plr.Handle == handle); + return new PlayerList().FirstOrDefault(plr => plr.Handle == handle); // Finding the first player with the handle } internal static Player GetPlayerByIp(string ip) { - return new PlayerList().FirstOrDefault(plr => plr.Identifiers["ip"] == ip); + return new PlayerList().FirstOrDefault(plr => plr.Identifiers["ip"] == ip); // Finding the first player with the right IP } #region Chat Commands + /// + /// EZ Thing for sending a message + /// + /// + /// + /// + /// internal static void SendMessage(Player p, string title, int[] rgb, string msg) => TriggerClientEvent(p, "chatMessage", title, rgb, msg); + /// + /// EZ Thing for sending a message to all players in the lobby + /// + /// + /// + /// internal static void SendAllMessage(string title, int[] rgb, string msg) => TriggerClientEvent("chatMessage", title, rgb, msg); + /// + /// EZ Thing for sending a "Usage: " message to the player + /// + /// + /// internal static void SendUsage(Player p, string usage) => TriggerClientEvent(p, "chatMessage", "Usage", new[] { 255, 255, 255 }, usage); #endregion + /// + /// Canceled the current event + /// internal static void CancelEvent() => Function.Call(Hash.CANCEL_EVENT); } } diff --git a/src/Server/DispatchSystem/Events.cs b/src/Server/DispatchSystem/Events.cs index 7a43842..c5da985 100644 --- a/src/Server/DispatchSystem/Events.cs +++ b/src/Server/DispatchSystem/Events.cs @@ -1,13 +1,14 @@ using System; +using System.Globalization; using System.Linq; -using System.Linq.Expressions; using System.Net; using System.Reflection; + using CitizenFX.Core; -using CitizenFX.Core.Native; + using CloNET; +using DispatchSystem.Common; using DispatchSystem.Common.DataHolders.Storage; -using DispatchSystem.sv.External; using static DispatchSystem.sv.Common; @@ -22,61 +23,118 @@ public static void DispatchReset(string handle) if (GetCivilian(p.Handle) != null) { - civs.Remove(GetCivilian(p.Handle)); +#if DEBUG + SendMessage(p, "", new [] {0,0,0}, "Removing Civilian Profile..."); +#endif + Civs.Remove(GetCivilian(p.Handle)); // removing instance of civilian } if (GetCivilianVeh(p.Handle) != null) { - civVehs.Remove(GetCivilianVeh(p.Handle)); +#if DEBUG + SendMessage(p, "", new[] { 0, 0, 0 }, "Removing Civilian Vehicle Profile..."); +#endif + CivVehs.Remove(GetCivilianVeh(p.Handle)); // removing instance of vehicle } if (GetOfficer(p.Handle) != null) { - officers.Remove(GetOfficer(p.Handle)); +#if DEBUG + SendMessage(p, "", new[] { 0, 0, 0 }, "Removing Officer Profile..."); +#endif + Officers.Remove(GetOfficer(p.Handle)); // removing instance of officer } - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "All profiles reset"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "All profiles reset"); // displaying the reset message + } + public static void PushbackClientInfo(string handle) + { + Player p = GetPlayerByHandle(handle); // find player from handle + var civ = GetCivilian(handle); // find civ from handle + var civVeh = GetCivilianVeh(handle); // find veh from handle + var ofc = GetOfficer(handle); // find ofc from handle + + // set all of the civ arr for event + string[] civArr = + { + // Civilian information + civ?.First ?? "None", + civ?.Last ?? "None", + civ?.CitationCount.ToString() ?? "None", + civ?.WarrantStatus.ToString() ?? "None", + // Vehicle information + civVeh?.Plate ?? "None", + civVeh?.StolenStatus.ToString() ?? "None", + civVeh?.Registered.ToString() ?? "None", + civVeh?.Insured.ToString() ?? "None" + }; + // set all of the ofc arr for event + string[] ofcArr = + { + ofc?.Callsign ?? "None", + ofc?.Status == null ? "None" : ofc.Status == OfficerStatus.OnDuty ? "On Duty" : ofc.Status == OfficerStatus.OffDuty ? "Off Duty" : "Busy", + ofc == null ? "None" : OfcAssignments.ContainsKey(ofc) ? OfcAssignments[ofc].Summary : "None" + }; + + // passing event of data to client + TriggerClientEvent(p, "dispatchsystem:pushbackData", civArr, ofcArr); } #region Civilian Events + public static void DisplayCurrentCivilian(string handle) + { + Player p = GetPlayerByHandle(handle); + Civilian civ = GetCivilian(handle); + + if (civ != null) + { + SendMessage(p, "", new[] { 255, 255, 255 }, $"First: {civ.First} | Last: {civ.Last}"); + SendMessage(p, "", new[] { 255, 255, 255 }, $"Warrant: {civ.WarrantStatus}"); + SendMessage(p, "", new[] { 255, 255, 255 }, $"Citations: {civ.CitationCount}"); + } + else + SendMessage(p, "DispatchSystem", new [] {0,0,0}, "You don't exist in the system"); + } public static void SetName(string handle, string first, string last) { Player p = GetPlayerByHandle(handle); - if (p == null) return; - if (GetOfficer(handle) != null) + if (GetOfficer(handle) != null) // checking if the civilian has an officer { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You cannot be an officer and a civilian at the same time!"); - return; + return; // return if they do } - if (GetCivilianByName(first, last) != null && GetPlayerByIp(GetCivilianVeh(handle).SourceIP) != p) + if (GetCivilianByName(first, last) != null && GetPlayerByIp(GetCivilianVeh(handle).SourceIP) != p) // checking if the name already exists in the system { - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"That name already exists in the system!"); - return; + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "That name already exists in the system!"); + return; // return if it does } + // checking if the civilian already has a civ in the system if (GetCivilian(handle) != null) { - int index = civs.IndexOf(GetCivilian(handle)); + int index = Civs.IndexOf(GetCivilian(handle)); // finding the index of the existing civ - civs[index] = new Civilian(p.Identifiers["ip"]) { First = first, Last = last }; + Civs[index] = new Civilian(p.Identifiers["ip"]) { First = first, Last = last }; // setting the index to an instance of a new civilian - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New name set to: {civs[index].First} {civs[index].Last}"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New name set to: {Civs[index].First} {Civs[index].Last}"); // saying the new name created } - else + else // if the civ doesn't exist { - civs.Add(new Civilian(p.Identifiers["ip"]) { First = first, Last = last }); - int index = civs.IndexOf(GetCivilian(handle)); + Civs.Add(new Civilian(p.Identifiers["ip"]) { First = first, Last = last }); // add a new civilian to the system + int index = Civs.IndexOf(GetCivilian(handle)); // find the index of the civ - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New name set to: {civs[index].First} {civs[index].Last}"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New name set to: {Civs[index].First} {Civs[index].Last}"); // say the new name was created #if DEBUG SendMessage(p, "", new[] { 0, 0, 0 }, "Creating new civilian profile..."); #endif } if (GetCivilianVeh(handle) != null) { - int index = civVehs.IndexOf(GetCivilianVeh(handle)); + // below basically resets the vehicle if it exists + + int index = CivVehs.IndexOf(GetCivilianVeh(handle)); - civVehs[index] = new CivilianVeh(p.Identifiers["ip"]); + CivVehs[index] = new CivilianVeh(p.Identifiers["ip"]); } } public static void ToggleWarrant(string handle) @@ -85,9 +143,9 @@ public static void ToggleWarrant(string handle) if (GetCivilian(handle) != null) { - int index = civs.IndexOf(GetCivilian(handle)); - civs[index].WarrantStatus = !civs[index].WarrantStatus; - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Warrant status set to {civs[index].WarrantStatus.ToString()}"); + int index = Civs.IndexOf(GetCivilian(handle)); // finding the index + Civs[index].WarrantStatus = !Civs[index].WarrantStatus; // setting the warrant status of the opposite of before + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Warrant status set to {Civs[index].WarrantStatus}"); } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your name before you can toggle your warrant"); @@ -98,10 +156,10 @@ public static void SetCitations(string handle, int count) if (GetCivilian(handle) != null) { - int index = civs.IndexOf(GetCivilian(handle)); - civs[index].CitationCount = count; + int index = Civs.IndexOf(GetCivilian(handle)); // again finding index + Civs[index].CitationCount = count; // setting the count of the citations - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Citation count set to {count.ToString()}"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Citation count set to {count}"); } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your name before you can set your citations"); @@ -110,6 +168,7 @@ public static async void InitializeEmergency(string handle) { Player p = GetPlayerByHandle(handle); + // checking for an existing emergency if (GetEmergencyCall(handle) != null) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You already have a 911 call!"); @@ -118,20 +177,21 @@ public static async void InitializeEmergency(string handle) if (GetCivilian(handle) != null) { - Civilian civ = GetCivilian(handle); - - if (server.ConnectedDispatchers.Length == 0) + Civilian civ = GetCivilian(handle); // finding the civ + + // checking how many active dispatchers there are + if (Server.ConnectedDispatchers.Length == 0) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "It seems like there is no connected dispatchers at this moment!"); return; } EmergencyCall call; - currentCalls.Add(call = new EmergencyCall(p.Identifiers["ip"], $"{civ.First} {civ.Last}")); - SendMessage(p, "Dispatch911", new[] { 255, 0, 0 }, "Please wait for a dispatcher to respond"); - foreach (var peer in server.ConnectedDispatchers) + CurrentCalls.Add(call = new EmergencyCall(p.Identifiers["ip"], $"{civ.First} {civ.Last}")); // adding and creating the instance of the emergency + SendMessage(p, "Dispatch911", new[] { 255, 0, 0 }, "Please wait for a dispatcher to respond"); // msging to wait for a dispatcher + foreach (var peer in Server.ConnectedDispatchers) { - await peer.TriggerNetEvent("911alert", civ, call); + await peer.RemoteCallbacks.Events["911alert"].Invoke(civ, call); // notifying the dispatchers of the 911 call } } else @@ -142,21 +202,22 @@ public static async void MessageEmergency(string handle, string msg) Player p = GetPlayerByHandle(handle); EmergencyCall call = GetEmergencyCall(handle); - if (call?.Accepted ?? true) + if (call?.Accepted ?? true) // checking if null and if accepted in the same check { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You're call must be answered or started first"); return; } - string dispatcherIp = server.Calls[call.Id]; - ConnectedPeer peer = server.ConnectedDispatchers.First(x => x.RemoteIP == dispatcherIp); - await peer.TryTriggerNetEvent(call.Id.ToString(), msg); + string dispatcherIp = Server.Calls[call.Id]; // getting the dispatcher ip from the calls + ConnectedPeer peer = Server.ConnectedDispatchers.First(x => x.RemoteIP == dispatcherIp); // finding the peer from the given IP + await peer.RemoteCallbacks.Events[call.Id.ToString()].Invoke(msg); // invoking the remote event for the message in the peer } - public static void EndEmergency(string handle) + public static async void EndEmergency(string handle) { Player p = GetPlayerByHandle(handle); EmergencyCall call = GetEmergencyCall(handle); + // checking for call null if (call == null) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "There is no 911 call to end!"); @@ -167,80 +228,100 @@ public static void EndEmergency(string handle) SendMessage(p, "", new[] { 0, 0, 0 }, "Ending 911 call..."); #endif - string dispatcherIp = server.Calls[call.Id]; - ConnectedPeer peer = server.ConnectedDispatchers.First(x => x.RemoteIP == dispatcherIp); -#pragma warning disable 4014 - peer.TryTriggerNetEvent("end" + call.Id); -#pragma warning restore 4014 + // finding the dispatcher ip + var dispatcherIp = Server.Calls[call.Id]; + ConnectedPeer peer = Server.ConnectedDispatchers.FirstOrDefault(x => x.RemoteIP == dispatcherIp); // finding the peer from the ip + var task = peer?.RemoteCallbacks.Events?["end" + call.Id].Invoke(); // creating the task from the events - currentCalls.Remove(call); + // removing the call from the calls list + CurrentCalls.Remove(call); SendMessage(p, "Dispatch911", new[] { 255, 0, 0 }, "Ended the 911 call"); + + if (!(task is null)) await task; // await the task } #endregion #region Vehicle Events + public static void DisplayCurrentVehicle(string handle) + { + Player p = GetPlayerByHandle(handle); + CivilianVeh veh = GetCivilianVeh(handle); + + if (veh != null) + { + SendMessage(p, "", new[] { 255, 255, 255 }, $"Plate: {veh.Plate.ToUpper()}"); + SendMessage(p, "", new[] { 255, 255, 255 }, $"Stolen: {veh.StolenStatus}"); + SendMessage(p, "", new[] { 255, 255, 255 }, $"Registered: {veh.Registered}"); + SendMessage(p, "", new[] { 255, 255, 255 }, $"Insured: {veh.Insured}"); + } + else + SendMessage(p, "DispatchSystem", new [] {0,0,0}, "Your vehicle doesn't exist in the system"); + } public static void SetVehicle(string handle, string plate) { Player p = GetPlayerByHandle(handle); + // if no civilian exists if (GetCivilian(handle) == null) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your name before you can set your vehicle"); return; } + // checking if the plate already exists in the system if (GetCivilianVehByPlate(plate) != null && GetPlayerByIp(GetCivilianVeh(handle).SourceIP) != p) { - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"That vehicle already exists in the system!"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "That vehicle already exists in the system!"); return; } + // checking if player already owns a vehicle if (GetCivilianVeh(handle) != null) { - Int32 index = civVehs.IndexOf(GetCivilianVeh(handle)); - - civVehs[index] = new CivilianVeh(p.Identifiers["ip"]) { Plate = plate, Owner = GetCivilian(handle) }; - - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New vehicle set to {civVehs[index].Plate}"); + int index = CivVehs.IndexOf(GetCivilianVeh(handle)); // finding the existing index + CivVehs[index] = new CivilianVeh(p.Identifiers["ip"]) { Plate = plate, Owner = GetCivilian(handle) }; // setting the index to a new vehicle item + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New vehicle set to {CivVehs[index].Plate}"); // msg of creation } else { - civVehs.Add(new CivilianVeh(p.Identifiers["ip"]) { Plate = plate, Owner = GetCivilian(handle) }); + CivilianVeh veh = new CivilianVeh(p.Identifiers["ip"]) { Plate = plate, Owner = GetCivilian(handle) }; // creating the new vehicle + CivVehs.Add(veh); // adding the new vehicle to the list of vehicles - Int32 index = civVehs.IndexOf(GetCivilianVeh(handle)); - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New vehicle set to {civVehs[index].Plate}"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"New vehicle set to {veh.Plate}"); // msg } } public static void ToggleVehicleStolen(string handle) { Player p = GetPlayerByHandle(handle); - + + // checking if player has a name if (GetCivilian(handle) == null) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your name before you can set your vehicle stolen"); return; } + // checking if vehicle exists if (GetCivilianVeh(handle) != null) { - int index = civVehs.IndexOf(GetCivilianVeh(handle)); - civVehs[index].StolenStatus = !civVehs[index].StolenStatus; + int index = CivVehs.IndexOf(GetCivilianVeh(handle)); // finding index of vehicle + CivVehs[index].StolenStatus = !CivVehs[index].StolenStatus; // toggle stolen - if (civVehs[index].StolenStatus) + if (CivVehs[index].StolenStatus) // checking if it is stolen { - Civilian civ = Civilian.CreateRandomCivilian(); - civVehs[index].Owner = civ; - civs.Add(civ); + Civilian civ = Civilian.CreateRandomCivilian(); // creating a new random civ + CivVehs[index].Owner = civ; // setting the vehicle owner to the civ + Civs.Add(civ); // adding the civ to the database } else { - Civilian civ = civVehs[index].Owner; - civs.Remove(civ); - civVehs[index].Owner = GetCivilian(handle); + Civilian civ = CivVehs[index].Owner; // finding the existing civ + Civs.Remove(civ); // removing the civ from the database + CivVehs[index].Owner = GetCivilian(handle); // setting the owner to the person } - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Stolen status set to {civVehs[index].StolenStatus.ToString()}"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Stolen status set to {CivVehs[index].StolenStatus}"); } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your vehicle before you can set your vehicle stolen"); @@ -249,18 +330,20 @@ public static void ToggleVehicleRegistration(string handle) { Player p = GetPlayerByHandle(handle); + // checking for existing civ if (GetCivilian(handle) == null) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your name before you can set your vehicle registration"); return; } + // checking if the vehicle exists if (GetCivilianVeh(handle) != null) { - int index = civVehs.IndexOf(GetCivilianVeh(handle)); - civVehs[index].Registered = !civVehs[index].Registered; + int index = CivVehs.IndexOf(GetCivilianVeh(handle)); // finding the index of the vehicle + CivVehs[index].Registered = !CivVehs[index].Registered; // setting the registration - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Registration status set to {civVehs[index].Registered.ToString()}"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Registration status set to {CivVehs[index].Registered}"); // msg } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your vehicle before you can set your Regisration"); @@ -269,20 +352,20 @@ public static void ToggleVehicleInsurance(string handle) { Player p = GetPlayerByHandle(handle); + // checking for existing civ if (GetCivilian(handle) == null) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your name before you can set your vehicle insurance"); return; } + // checking if the vehicle exists if (GetCivilianVeh(handle) != null) { - int index = civVehs.IndexOf(GetCivilianVeh(handle)); - CivilianVeh last = civVehs[index]; + int index = CivVehs.IndexOf(GetCivilianVeh(handle)); // finding the index + CivVehs[index].Insured = !CivVehs[index].Insured; // toggle insurance - civVehs[index].Insured = !civVehs[index].Insured; - - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Insurance status set to {civVehs[index].Insured.ToString()}"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Insurance status set to {CivVehs[index].Insured}"); // msg } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must set your vehicle before you can set your Insurance"); @@ -294,6 +377,7 @@ public static void AddOfficer(string handle, string callsign) { Player p = GetPlayerByHandle(handle); + // checking if civ exists if (GetCivilian(handle) != null) { SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, @@ -301,30 +385,33 @@ public static void AddOfficer(string handle, string callsign) return; } + // check for officer existing if (GetOfficer(handle) == null) { - officers.Add(new Officer(p.Identifiers["ip"], callsign)); - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Assigning new officer for callsign {callsign}"); + Officers.Add(new Officer(p.Identifiers["ip"], callsign)); // adding new officer + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Assigning new officer for callsign {callsign}"); // msg #if DEBUG SendMessage(p, "", new[] { 0, 0, 0 }, "Creating new Officer profile..."); #endif } else { - int index = officers.IndexOf(GetOfficer(handle)); - officers[index] = new Officer(p.Identifiers["ip"], callsign); - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Changing your callsign to {callsign}"); + int index = Officers.IndexOf(GetOfficer(handle)); // finding the index + Officers[index] = new Officer(p.Identifiers["ip"], callsign); // setting the index to the specified officer + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"Changing your callsign to {callsign}"); // msg } } public static void DisplayStatus(string handle) { Player p = GetPlayerByHandle(handle); + // checking if officer exists if (GetOfficer(handle) != null) { - Officer ofc = GetOfficer(handle); + Officer ofc = GetOfficer(handle); // finding the officer - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, string.Format("Your status is: {0}", ofc.Status == OfficerStatus.OffDuty ? "Off Duty" : ofc.Status == OfficerStatus.OnDuty ? "On Duty" : "Busy")); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, + $"Your status is: {(ofc.Status == OfficerStatus.OffDuty ? "Off Duty" : ofc.Status == OfficerStatus.OnDuty ? "On Duty" : "Busy")}"); // msg (with 2 ?: statements) } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must create an officer first"); @@ -333,18 +420,19 @@ public static void ToggleOnDuty(string handle) { Player p = GetPlayerByHandle(handle); + // checking if the officer exists if (GetOfficer(handle) != null) { - Officer ofc = GetOfficer(handle); + Officer ofc = GetOfficer(handle); // finding the officer if (ofc.Status == OfficerStatus.OnDuty) { - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You are already on duty dummy!"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You are already on duty dummy!"); // msg if already onduty return; } - ofc.Status = OfficerStatus.OnDuty; - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "New officer status set to On Duty"); + ofc.Status = OfficerStatus.OnDuty; // setting status + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "New officer status set to On Duty"); // msg } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must create an officer first"); @@ -353,18 +441,19 @@ public static void ToggleOffDuty(string handle) { Player p = GetPlayerByHandle(handle); + // checking if officer exists if (GetOfficer(handle) != null) { - Officer ofc = GetOfficer(handle); + Officer ofc = GetOfficer(handle); // get the officer if (ofc.Status == OfficerStatus.OffDuty) { - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You are already off duty dummy!"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You are already off duty dummy!"); // msg if already offduty return; } - ofc.Status = OfficerStatus.OffDuty; - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "New officer status set to Off Duty"); + ofc.Status = OfficerStatus.OffDuty; // setting the status + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "New officer status set to Off Duty"); // msg } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must create an officer first"); @@ -373,128 +462,144 @@ public static void ToggleBusy(string handle) { Player p = GetPlayerByHandle(handle); + // trying to find the officer if (GetOfficer(handle) != null) { - Officer ofc = GetOfficer(handle); + Officer ofc = GetOfficer(handle); // finding the officer if (ofc.Status == OfficerStatus.Busy) { - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You are already busy dummy!"); + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You are already busy dummy!"); // msg if already busy return; } - ofc.Status = OfficerStatus.Busy; - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "New officer status set to Busy"); + ofc.Status = OfficerStatus.Busy; // setting the status + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "New officer status set to Busy"); // msg } else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You must create an officer first"); } public static void RequestCivilian(string handle, string first, string last) { - Player invoker = GetPlayerByHandle(handle); - Civilian civ = GetCivilianByName(first, last); + Player invoker = GetPlayerByHandle(handle); // getting the invoker + Civilian civ = GetCivilianByName(first, last); // finding the civ + // checking if the civ is not null if (civ != null) { + // results msg SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "Results: "); SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"First: {civ.First} | Last: {civ.Last}"); - SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Warrant: {civ.WarrantStatus.ToString()}"); - SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Citations: {civ.CitationCount.ToString()}"); + SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Warrant: {civ.WarrantStatus}"); + SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Citations: {civ.CitationCount}"); } else SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "That civilian doesn't exist in the system"); } public static void RequestCivilianVeh(string handle, string plate) { - Player invoker = GetPlayerByHandle(handle); - CivilianVeh civVeh = GetCivilianVehByPlate(plate); + Player invoker = GetPlayerByHandle(handle); // getting the invoker + CivilianVeh civVeh = GetCivilianVehByPlate(plate); // finding the vehicle if (civVeh != null) { + // results msg SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "Results: "); SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Plate: {civVeh.Plate.ToUpper()}"); - SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Stolen: {civVeh.StolenStatus.ToString()}"); - SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Registered: {civVeh.Registered.ToString()}"); - SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Insured: {civVeh.Insured.ToString()}"); - if (civVeh.Registered) SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"R/O: {civVeh.Owner.First} {civVeh.Owner.Last}"); + SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Stolen: {civVeh.StolenStatus}"); + SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Registered: {civVeh.Registered}"); + SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Insured: {civVeh.Insured}"); + // for registration + if (civVeh.Registered) + SendMessage(invoker, "DispatchSystem", new[] {0, 0, 0}, + $"R/O: {civVeh.Owner.First} {civVeh.Owner.Last}"); } else SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "That vehicle doesn't exist in the system"); } public static void AddCivilianNote(string invokerHandle, string first, string last, string note) { - Player invoker = GetPlayerByHandle(invokerHandle); - Civilian civ = GetCivilianByName(first, last); + Player invoker = GetPlayerByHandle(invokerHandle); // getting the invoker + Civilian civ = GetCivilianByName(first, last); // finding the civ + // checking civ if (civ != null) { - int index = civs.IndexOf(civ); - civs[index].Notes.Add(note); - SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Note of \"{note}\" has been added to the Civilian"); + int index = Civs.IndexOf(civ); // finding the index + Civs[index].Notes.Add(note); // adding the note to the civ + SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"Note of \"{note}\" has been added to the Civilian"); // msg } else SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "That name doesn't exist in the system"); } public static void TicketCivilian(string invokerHandle, string first, string last, string reason, float amount) { - Player invoker = GetPlayerByHandle(invokerHandle); - Civilian civ = GetCivilianByName(first, last); + Player invoker = GetPlayerByHandle(invokerHandle); // getting the invoker + Civilian civ = GetCivilianByName(first, last); // finding the civ + // checking for civ if (civ != null) { - int index = civs.IndexOf(civ); - Player p = GetPlayerByIp(civs[index].SourceIP); - civs[index].CitationCount++; - civs[index].Tickets.Add(new Ticket(reason, amount)); + int index = Civs.IndexOf(civ); // finding the index of the civ + Player p = GetPlayerByIp(Civs[index].SourceIP); // finding the player that the civ owns + Civs[index].CitationCount++; // adding 1 to the citations + Civs[index].Tickets.Add(new Ticket(reason, amount)); // adding a ticket to the existing tickets + // msgs for the civs if (p != null) - SendMessage(p, "Ticket", new[] { 255, 0, 0 }, $"{invoker.Name} tickets you for ${amount.ToString()} because of {reason}"); - SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, $"You successfully ticketed {p.Name} for ${amount.ToString()}"); + SendMessage(p, "Ticket", new[] {255, 0, 0}, + $"{invoker.Name} tickets you for ${amount.ToString(CultureInfo.InvariantCulture)} because of {reason}"); + SendMessage(invoker, "DispatchSystem", new[] {0, 0, 0}, + $"You successfully ticketed {p?.Name ?? "NULL"} for ${amount.ToString(CultureInfo.InvariantCulture)}"); } else SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "That name doesn't exist in the system"); } public static void DisplayCivilianTickets(string invokerHandle, string first, string last) { - Player invoker = GetPlayerByHandle(invokerHandle); - Civilian civ = GetCivilianByName(first, last); + Player invoker = GetPlayerByHandle(invokerHandle); // getting the invoker + Civilian civ = GetCivilianByName(first, last); // finding the civ + // checking for civ if (civ != null) { - int index = civs.IndexOf(civ); - if (civs[index].Tickets.Count() == 0) + int index = Civs.IndexOf(civ); // finding the index of the civ + // msgs if any tickets + if (!Civs[index].Tickets.Any()) SendMessage(invoker, "", new[] { 0, 0, 0 }, "^7None"); else - civs[index].Tickets.ForEach(x => SendMessage(invoker, "", new[] { 0, 0, 0 }, $"^7${x.Amount}: {x.Reason}")); + Civs[index].Tickets.ForEach(x => SendMessage(invoker, "", new[] { 0, 0, 0 }, $"^7${x.Amount}: {x.Reason}")); // big msgs } else SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "That name doesn't exist in the system"); } public static void DipslayCivilianNotes(string handle, string first, string last) { - Player invoker = GetPlayerByHandle(handle); - Civilian civ = GetCivilianByName(first, last); + Player invoker = GetPlayerByHandle(handle); // getting the invoker + Civilian civ = GetCivilianByName(first, last); // finding the civ if (civ != null) { - if (civ.Notes.Count == 0) + // sending the msgs + if (!civ.Notes.Any()) SendMessage(invoker, "", new[] { 0, 0, 0 }, "^7None"); else - civ.Notes.ForEach(x => SendMessage(invoker, "", new[] { 0, 0, 0 }, x)); + civ.Notes.ForEach(x => SendMessage(invoker, "", new[] { 0, 0, 0 }, x)); // big msgs } else SendMessage(invoker, "DispatchSystem", new[] { 0, 0, 0 }, "That name doesn't exist in the system"); } public static void AddBolo(string handle, string reason) { - Player p = GetPlayerByHandle(handle); - bolos.Add(new Bolo(p.Name, p.Identifiers["ip"], reason)); - SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"BOLO for \"{reason}\" added"); + Player p = GetPlayerByHandle(handle); // getting the invoker + Bolos.Add(new Bolo(p.Name, p.Identifiers["ip"], reason)); // adding teh bolos + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, $"BOLO for \"{reason}\" added"); // msg } public static void ViewBolos(string handle) { - Player p = GetPlayerByHandle(handle); - if (bolos.Count > 0) - bolos.ToList().ForEach(x => SendMessage(p, "", new[] { 0, 0, 0 }, $"^8{x.Player}^7: ^3{x.Reason}")); + Player p = GetPlayerByHandle(handle); // getting the invoker + // checking for bolos + if (Bolos.Any()) + Bolos.ToList().ForEach(x => SendMessage(p, "", new[] { 0, 0, 0 }, $"^8{x.Player}^7: ^3{x.Reason}")); // big msgs else SendMessage(p, "", new[] { 0, 0, 0 }, "^7None"); } @@ -503,52 +608,62 @@ public static void ViewBolos(string handle) private void OnChatMessage(int source, string n, string msg) { - Player p = this.Players[source]; - var args = msg.Split(' ').ToList(); - var cmd = args[0].ToLower(); - args.RemoveAt(0); + Player p = Players[source]; // finding the player from the source + var args = msg.Split(' ').ToList(); // splitting the message to find the args + var cmd = args[0].ToLower(); // getting the command from the args + args.RemoveAt(0); // removing the command part of the args // Reflection - Commands instance = new Commands(); + Commands instance = new Commands(); // creating the instance to invoke the command's methodinfo in + // finding the command from the given message var command = typeof(Commands).GetMethods().Where(x => x.GetCustomAttributes().Any()) .FirstOrDefault(x => string.Equals(x.GetCustomAttributes().ToArray()[0].Command, cmd, StringComparison.CurrentCultureIgnoreCase)); + // if command is not found then return null if (command == null) return; - CancelEvent(); - CommandAttribute information = command.GetCustomAttributes().ToArray()[0]; + CancelEvent(); // don't display the message + CommandAttribute information = command.GetCustomAttributes().ToArray()[0]; // get the command's information switch (information.Type) { case CommandType.Civilian: - switch (perms.CivilianPermission) + switch (Perms.CivilianPermission) // checking for civilian perms { + // in the case of everyone, invoke case Permission.Everyone: command.Invoke(instance, new object[] {p, args.ToArray()}); break; + // in the case of specific, check for IP then invoke case Permission.Specific: - if (perms.CivContains(IPAddress.Parse(p.Identifiers["ip"]))) + if (Perms.CivContains(IPAddress.Parse(p.Identifiers["ip"]))) command.Invoke(instance, new object[] { p, args.ToArray() }); else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You don't have the permission to do that!"); break; + // in the case of none, send out message saying you don't have permissions case Permission.None: + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You don't have the permission to do that!"); break; default: throw new ArgumentOutOfRangeException(); } break; case CommandType.Leo: - switch (perms.LeoPermission) + switch (Perms.LeoPermission) { + // in the case of everyone, just invoke case Permission.Everyone: command.Invoke(instance, new object[] { p, args.ToArray() }); break; + // in the case of specific, check the ip then invoke case Permission.Specific: - if (perms.LeoContains(IPAddress.Parse(p.Identifiers["ip"]))) + if (Perms.LeoContains(IPAddress.Parse(p.Identifiers["ip"]))) command.Invoke(instance, new object[] { p, args.ToArray() }); else SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You don't have the permission to do that!"); break; + // in the case of none, send a perms msg case Permission.None: + SendMessage(p, "DispatchSystem", new[] { 0, 0, 0 }, "You don't have the permission to do that!"); break; default: throw new ArgumentOutOfRangeException(); diff --git a/src/Server/DispatchSystem/Init.cs b/src/Server/DispatchSystem/Init.cs index 244b0e2..575b449 100644 --- a/src/Server/DispatchSystem/Init.cs +++ b/src/Server/DispatchSystem/Init.cs @@ -1,20 +1,16 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Threading; -using System.Threading.Tasks; using DispatchSystem.sv.External; using DispatchSystem.Common.DataHolders.Storage; using Config.Reader; +using EZDatabase; -using CitizenFX.Core; using CitizenFX.Core.Native; - -using static DispatchSystem.sv.Common; +using DispatchSystem.Common; namespace DispatchSystem.sv { @@ -22,10 +18,14 @@ public partial class DispatchSystem { private void RegisterEvents() { + // adding the main events EventHandlers["chatMessage"] += new Action(OnChatMessage); EventHandlers["dispatchsystem:dsreset"] += new Action(DispatchReset); + EventHandlers["dispatchsystem:requestClientInfo"] += new Action(PushbackClientInfo); + // civilian events #region Civilian Commands + EventHandlers["dispatchsystem:displayCiv"] += new Action(DisplayCurrentCivilian); EventHandlers["dispatchsystem:setName"] += new Action(SetName); EventHandlers["dispatchsystem:toggleWarrant"] += new Action(ToggleWarrant); EventHandlers["dispatchsystem:setCitations"] += new Action(SetCitations); @@ -34,13 +34,16 @@ private void RegisterEvents() EventHandlers["dispatchsystem:911end"] += new Action(EndEmergency); #endregion + // events for vehicles #region Vehicle Commands + EventHandlers["dispatchsystem:displayVeh"] += new Action(DisplayCurrentVehicle); EventHandlers["dispatchsystem:setVehicle"] += new Action(SetVehicle); EventHandlers["dispatchsystem:toggleVehStolen"] += new Action(ToggleVehicleStolen); EventHandlers["dispatchsystem:toggleVehRegi"] += new Action(ToggleVehicleRegistration); EventHandlers["dispatchsystem:toggleVehInsured"] += new Action(ToggleVehicleInsurance); #endregion + // officer specific events #region Police Commands EventHandlers["dispatchsystem:initOfficer"] += new Action(AddOfficer); EventHandlers["dispatchsystem:onDuty"] += new Action(ToggleOnDuty); @@ -57,42 +60,49 @@ private void RegisterEvents() EventHandlers["dispatchsystem:viewBolos"] += new Action(ViewBolos); #endregion } - private void InitializeComponents() + private static void InitializeComponents() { + // creating new instances of objects callbacks = new ConcurrentQueue(); - officers = new StorageManager(); - assignments = new List(); - ofcAssignments = new Dictionary(); - commands = new Dictionary(); - bolos = new StorageManager(); - civs = new StorageManager(); - civVehs = new StorageManager(); - currentCalls = new List(); - - cfg = new iniconfig(Function.Call(Hash.GET_CURRENT_RESOURCE_NAME), "settings.ini"); + Officers = new StorageManager(); + Assignments = new List(); + OfcAssignments = new Dictionary(); + Bolos = new StorageManager(); + Civs = new StorageManager(); + CivVehs = new StorageManager(); + CurrentCalls = new StorageManager(); + Cfg = new ServerConfig(Function.Call(Hash.GET_CURRENT_RESOURCE_NAME), "settings.ini"); - Permissions.SetInformation("permissions.perms", Function.Call(Hash.GET_CURRENT_RESOURCE_NAME)); - perms = Permissions.Get; - perms.Refresh(); + // creating the permissions singleton + Log.WriteLine("Setting permission information"); + Permissions.SetInformation(Function.Call(Hash.LOAD_RESOURCE_FILE, Function.Call(Hash.GET_CURRENT_RESOURCE_NAME), "permissions.perms")); + Log.WriteLine("Parsing permission information"); + Perms = Permissions.Get; + Log.WriteLine("Permissions set!"); - if (cfg.GetIntValue("server", "enable", 0) == 1) + // reading config, then starting the server is config true + if (Cfg.GetIntValue("server", "enable", 0) == 1) { - ThreadPool.QueueUserWorkItem(x => server = new DispatchServer(cfg), null); + ThreadPool.QueueUserWorkItem(x => Server = new DispatchServer(Cfg), null); Log.WriteLine("Starting DISPATCH server"); } else Log.WriteLine("Not starting DISPATCH server"); - if (cfg.GetIntValue("database", "enable", 0) == 1) - { - Log.WriteLine("Reading database..."); - data = new Database(); - civs = data.Read("dsciv.db") ?? new StorageManager(); - civVehs = data.Read("dsveh.db") ?? new StorageManager(); - Log.WriteLine("Read and set database"); - ThreadPool.QueueUserWorkItem(async x => + // reading config, then starting database if config true + if (Cfg.GetIntValue("database", "enable", 0) == 1) + { + // starting the read/write thread for database + async void RunDatabase() { - await Delay(15000); + Log.WriteLine("Reading database..."); + Data = new Database("dispatchsystem.data"); // creating the database instance + Tuple, StorageManager> read = Data.Read(); // reading the serialized tuple from the database + Civs = read?.Item1 ?? new StorageManager(); + CivVehs = read?.Item2 ?? new StorageManager(); + Log.WriteLine("Read and set database"); // logging done + + // starting while loop for writing the database while (true) { #if DEBUG @@ -100,15 +110,20 @@ private void InitializeComponents() #else Log.WriteLineSilent("Writing current information to database"); #endif - data.Write(civs, "dsciv.db"); - data.Write(civVehs, "dsveh.db"); + // creating the tuple to write + var write = new Tuple, StorageManager>(Civs, CivVehs); + // writing the information + Data.Write(write); + // waiting 3 minutes before doing it again await Delay(180 * 1000); } - }); + } + + new Thread(RunDatabase) { Name = "Database Thread"}.Start(); // starting database thread } else { - Log.WriteLine("Not start database"); + Log.WriteLine("Not starting the database"); } } } diff --git a/src/Server/DispatchSystem/Items.cs b/src/Server/DispatchSystem/Items.cs index 8579d8f..97b073a 100644 --- a/src/Server/DispatchSystem/Items.cs +++ b/src/Server/DispatchSystem/Items.cs @@ -1,35 +1,31 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using DispatchSystem.sv.External; using DispatchSystem.Common.DataHolders.Storage; using Config.Reader; +using DispatchSystem.Common; +using EZDatabase; namespace DispatchSystem.sv { public partial class DispatchSystem { - protected static iniconfig cfg; - protected static Permissions perms; - protected static DispatchServer server; - protected static Database data; + protected static ServerConfig Cfg; // config + protected static Permissions Perms; // permissions + protected static DispatchServer Server; // server for client+server transactions + protected static Database Data; // database for saving - internal static StorageManager bolos; - internal static StorageManager civs; - internal static StorageManager civVehs; - internal static StorageManager officers; - internal static List assignments; - internal static Dictionary ofcAssignments; - internal static List currentCalls; - public static ReadOnlyCollection Civilians => new ReadOnlyCollection(civs); - public static ReadOnlyCollection CivilianVehicles => new ReadOnlyCollection(civVehs); - public static StorageManager ActiveBolos => bolos; - - private Dictionary commands; + internal static StorageManager Bolos; // active bolos + internal static StorageManager Civs; // civilians + internal static StorageManager CivVehs; // civilian vehicles + internal static StorageManager Officers; // current officers + internal static List Assignments; // active assignments + internal static Dictionary OfcAssignments; // assignments attached to officers + internal static StorageManager CurrentCalls; // 911 calls + public static ReadOnlyCollection Civilians => new ReadOnlyCollection(Civs); // public version of civilians + public static ReadOnlyCollection CivilianVehicles => new ReadOnlyCollection(CivVehs); // public version of civilian vehicles + public static StorageManager ActiveBolos => Bolos; // public version of bolos } } diff --git a/src/Server/DispatchSystem/Main.cs b/src/Server/DispatchSystem/Main.cs index 8f2d8c0..43e26b8 100644 --- a/src/Server/DispatchSystem/Main.cs +++ b/src/Server/DispatchSystem/Main.cs @@ -4,6 +4,10 @@ using CitizenFX.Core; +using DispatchSystem.Common; +using DispatchSystem.Common.DataHolders.Storage; + +using EZDatabase; using static DispatchSystem.sv.Common; namespace DispatchSystem.sv @@ -14,11 +18,14 @@ public DispatchSystem() { Log.Create("dispatchsystem.log"); + // starting the dispatchsystem InitializeComponents(); RegisterEvents(); + // setting ontick for invocation Tick += OnTick; + // logging and saying that dispatchsystem has been started Log.WriteLine("DispatchSystem.Server by BlockBa5her loaded"); SendAllMessage("DispatchSystem", new[] { 0, 0, 0 }, "DispatchSystem.Server by BlockBa5her loaded"); } @@ -27,15 +34,52 @@ public DispatchSystem() * Below is just for executing something on the main thread */ + /// + /// Queue for action to execute on the main thread + /// private static volatile ConcurrentQueue callbacks; - async Task OnTick() + private static async Task OnTick() { // Executing all of the callback methods available while (callbacks.TryDequeue(out Action queue)) - queue(); + queue(); // executing the queue await Delay(0); } - internal static void Invoke(Action method) => callbacks.Enqueue(method); // Adding method for execution in main thread + internal static void Invoke(Action method) => callbacks.Enqueue(method); // adding method for execution in main thread + + /// + /// An emergency dump to clear all lists and dump everything into a file + /// + public static void EmergencyDump(Player invoker) + { + var write = new Tuple, StorageManager>(new StorageManager(), + new StorageManager()); + Data.Write(write); // writing empty things to database + + var database = new Database("dispatchsystem.dmp"); // create the new database + var write2 = + new Tuple, StorageManager, + StorageManager, StorageManager, StorageManager, Permissions>(Civs, + CivVehs, ActiveBolos, CurrentCalls, Officers, Perms); // create the tuple to write + database.Write(write2); // write info + + // clearing all of the lists + Civs.Clear(); + CivVehs.Clear(); + Officers.Clear(); + Assignments.Clear(); + OfcAssignments.Clear(); + CurrentCalls.Clear(); + Bolos.Clear(); + Server.Calls.Clear(); + + TriggerClientEvent("dispatchsystem:resetNUI"); // turning off the nui for all clients + + // sending a message to all for notifications + SendAllMessage("DispatchSystem", new[] {255, 0, 0}, + $"DispatchSystem has been dumpted! Everything has been deleted and scratched by {invoker.Name} [{invoker.Handle}]. " + + "All previous items have been placed in a file labeled \"dispatchsystem.dmp\""); + } } } \ No newline at end of file diff --git a/src/Server/External/Config.cs b/src/Server/External/Config.cs index 9630844..4b4a051 100644 --- a/src/Server/External/Config.cs +++ b/src/Server/External/Config.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using CitizenFX.Core.Native; using System.IO; @@ -31,7 +30,7 @@ ______ _ __ __ _____ __ _ _____ HOW TO USE --------------------------------------------------------------------------------- 1. ADD THIS CS FILE TO YOUR CLIENT SCRIPT 2. ADD A REFERENCE TO THIS SCRIPT LIKE SO: using Config.Reader; - 3. CREATE INSTANCE LIKE SO: iniconfig config = new iniconfig("resourceName","file"); + 3. CREATE INSTANCE LIKE SO: ServerConfig config = new ServerConfig("resourceName","file"); 4. ACCESS INI VALUES USING GET VALUE FUNCTIONS E.G. config.GetStringValue; NOTES -------------------------------------------------------------------------------------- @@ -50,23 +49,22 @@ 1. ADD THIS CS FILE TO YOUR CLIENT SCRIPT */ // INFORMATION ABOUT THIS SCRIPT CAN BE FOUND BY EXPANDING THIS COMMENT... -#pragma warning disable IDE1006 // Name rule violation - namespace Config { namespace Reader { #region INI CONFIG - public class iniconfig + [Serializable] + public class ServerConfig { - public iniconfig(string resourceName, string file) + public ServerConfig(string resourceName, string file) { // CALLS THE INI READER / PARSER TO MOVE INI DATA INTO A DICTIONARY Read(resourceName, file); } // DICTIONARY TO HOLD THE INI DATA - private Dictionary dict = new Dictionary(); + private readonly Dictionary dict = new Dictionary(); // READS A RESOURCE FILE AND "CONVERTS" THE INI DATA INTO A DICTIONARY: DICT<"[SECTION]KEY","VALUE"> #region INI PARSER @@ -77,71 +75,65 @@ private void Read(string resourceName, string file) string data = Function.Call(Hash.LOAD_RESOURCE_FILE, resourceName, file); // ENSURE THE RESOURCE FILE IS FOUND AND NOT EMPTY - if (data != null && data != "") + if (string.IsNullOrEmpty(data)) return; + + // READS LOADED RESOURCE FILE + using (StringReader reader = new StringReader(data)) { - // READS LOADED RESOURCE FILE - using (StringReader reader = new StringReader(data)) + string line, section = ""; // TEMP STORAGE FOR CURRENT LINE BEING READ AND SECTION FOUND + while ((line = reader.ReadLine()) != null) // LOOP THROUGH INI UNTILL THE END (NULL) { - string line = null, section = ""; // TEMP STORAGE FOR CURRENT LINE BEING READ AND SECTION FOUND - while ((line = reader.ReadLine()) != null) // LOOP THROUGH INI UNTILL THE END (NULL) + // ENSURES LINE IS CLEANED UP AND IS NOT A COMMENT OR IS EMPTY + #region LINE SETUP, COMMENT CHECKER AND EMPTY LINE CHECKER + line = line.Trim(); // REMOVE EMPTY SPACE AROUND THE CURRENT LINE + if (line.Length == 0) continue; // LINE IS EMPTY SO SKIP IT + if (!string.IsNullOrEmpty(";") && line.StartsWith(";")) continue; // LINE IS A COMMENT AS IT CONTAINS ";" SO IGNORE IT + #endregion + + // CHECKS FOR CURRENT SECTION AND STORES IT IN THE TEMP SECTION STRING FOR LATER STORAGE + #region SECTION CHECKER + // CHECK IF THE LINE CONTAINS A [SECTION] + if (line.StartsWith("[") && line.Contains("]")) // [SECTION] FOUND! { - // ENSURES LINE IS CLEANED UP AND IS NOT A COMMENT OR IS EMPTY - #region LINE SETUP, COMMENT CHECKER AND EMPTY LINE CHECKER - line = line.Trim(); // REMOVE EMPTY SPACE AROUND THE CURRENT LINE - if (line.Length == 0) continue; // LINE IS EMPTY SO SKIP IT - if (!string.IsNullOrEmpty(";") && line.StartsWith(";")) continue; // LINE IS A COMMENT AS IT CONTAINS ";" SO IGNORE IT - #endregion - - // CHECKS FOR CURRENT SECTION AND STORES IT IN THE TEMP SECTION STRING FOR LATER STORAGE - #region SECTION CHECKER - // CHECK IF THE LINE CONTAINS A [SECTION] - if (line.StartsWith("[") && line.Contains("]")) // [SECTION] FOUND! - { - section = line.Substring(1, line.IndexOf(']') - 1).Trim(); // STORE SECTION IN THE TEMP STRING - continue; // SKIP TO NEXT LINE NOW THE SECTION HAS BEEN SAVED - } - #endregion + section = line.Substring(1, line.IndexOf(']') - 1).Trim(); // STORE SECTION IN THE TEMP STRING + continue; // SKIP TO NEXT LINE NOW THE SECTION HAS BEEN SAVED + } + #endregion + + // CHECK IF THE LINE CONTAINS A KEY & A VALUE + if (!line.Contains("=")) continue; + + string key = line.Substring(0, line.IndexOf('=')).Trim(); // GET KEY BY GETTING ALL OF THE STRING BEFORE THE EQUALS SIGN THEN REMOVE SPACES + string value = line.Substring(line.IndexOf('=') + 1).Trim(); // GET THE VALUE FROM EVERYTHING AFTER THE EQUALS SIGN THEN REMOVE SPACES + string sectionKey = $"[{section}]{key}".ToLower(); // FORMAT INTO A COMPACT FORM WHERE THE SECTION AND KEY ARE HELD IN THE SAME CONTAINER - // CHECK IF THE LINE CONTAINS A KEY & A VALUE - if (line.Contains("=")) // KEY=VALUE + // SINCE A KEY AND A VALUE HAVE BEEN FOUND STORE THEM IN A DICTIONARY + #region DATA STORAGE AND INDEXING + + // CHECK INI DATA DOESENT ALREADY EXSIST + if (dict.ContainsKey(sectionKey)) + { + // DICTIONARY ALREADY CONTAINS THE SAME SECTION AND KEY SO MODIFY IT TO HAVE AN INDEX ADDED TO IT: + // E.G. [section]key-1 + int index = 1; + + // LOOP UNTIL A CORRECT NAME FOR THE DATA HAS BEEN FOUND + while (true) { - string key = line.Substring(0, line.IndexOf('=')).Trim(); // GET KEY BY GETTING ALL OF THE STRING BEFORE THE EQUALS SIGN THEN REMOVE SPACES - string value = line.Substring(line.IndexOf('=') + 1).Trim(); // GET THE VALUE FROM EVERYTHING AFTER THE EQUALS SIGN THEN REMOVE SPACES - string sectionKey = string.Format("[{0}]{1}", section, key).ToLower(); // FORMAT INTO A COMPACT FORM WHERE THE SECTION AND KEY ARE HELD IN THE SAME CONTAINER - - // SINCE A KEY AND A VALUE HAVE BEEN FOUND STORE THEM IN A DICTIONARY - #region DATA STORAGE AND INDEXING - - // CHECK INI DATA DOESENT ALREADY EXSIST - if (dict.ContainsKey(sectionKey)) - { - // DICTIONARY ALREADY CONTAINS THE SAME SECTION AND KEY SO MODIFY IT TO HAVE AN INDEX ADDED TO IT: - // E.G. [section]key-1 - int index = 1; - string sectionKey2; - - // LOOP UNTIL A CORRECT NAME FOR THE DATA HAS BEEN FOUND - while (true) - { - sectionKey2 = string.Format("{0}-{1}", sectionKey, ++index); // ON EACH LOOP ADD ONE TO THE INDEX TO FIND A NEW NAME - if (!dict.ContainsKey(sectionKey2)) - { - // ADD DATA TO DICTIONARY THEN EXIT OUT OF THE LOOP - dict.Add(sectionKey2, value); - break; - } - } - } - else // STORE INI DATA IN DICTIONARY SINCE IT DOES NOT ALREADT EXSIST - { - dict.Add(sectionKey, value); - } - #endregion + var sectionKey2 = $"{sectionKey}-{++index}"; + if (dict.ContainsKey(sectionKey2)) continue; + // ADD DATA TO DICTIONARY THEN EXIT OUT OF THE LOOP + dict.Add(sectionKey2, value); + break; } } + else // STORE INI DATA IN DICTIONARY SINCE IT DOES NOT ALREADT EXSIST + { + dict.Add(sectionKey, value); + } + #endregion } } - } #endregion @@ -158,11 +150,7 @@ private void Read(string resourceName, string file) /// public string GetStringValue(string section, string key, string fallBack) { - if (dict.ContainsKey("[" + section + "]" + key)) - { - return dict["[" + section + "]" + key]; - } - return fallBack; + return dict.ContainsKey("[" + section + "]" + key) ? dict["[" + section + "]" + key] : fallBack; } /// @@ -175,17 +163,9 @@ public string GetStringValue(string section, string key, string fallBack) /// public double GetDoubleValue(string section, string key, double fallBack) { - if (dict.ContainsKey("[" + section + "]" + key)) - { - // TRYS TO CONVERT A STRING TO AN INT - if (double.TryParse(dict["[" + section + "]" + key], out double result)) - { - // STRING CONVERSION SUCCEEDED - return result; - } - else { return fallBack; } // CONVERSION FAILED: RETURN FALLBACK - } - return fallBack; + if (!dict.ContainsKey("[" + section + "]" + key)) return fallBack; + // TRYS TO CONVERT A STRING TO AN INT + return double.TryParse(dict["[" + section + "]" + key], out double result) ? result : fallBack; } /// @@ -198,17 +178,9 @@ public double GetDoubleValue(string section, string key, double fallBack) /// public float GetFloatValue(string section, string key, float fallBack) { - if (dict.ContainsKey("[" + section + "]" + key)) - { - // TRYS TO CONVERT A STRING TO A FLOAT - if (float.TryParse(dict["[" + section + "]" + key], out float result)) - { - // STRING CONVERSION SUCCEEDED - return result; - } - else { return fallBack; } // CONVERSION FAILED: RETURN FALLBACK - } - return fallBack; + if (!dict.ContainsKey("[" + section + "]" + key)) return fallBack; + // TRYS TO CONVERT A STRING TO A FLOAT + return float.TryParse(dict["[" + section + "]" + key], out float result) ? result : fallBack; } /// @@ -221,17 +193,9 @@ public float GetFloatValue(string section, string key, float fallBack) /// public int GetIntValue(string section, string key, int fallBack) { - if (dict.ContainsKey("[" + section + "]" + key)) - { - // TRYS TO CONVERT A STRING TO AN INT - if (int.TryParse(dict["[" + section + "]" + key], out int result)) - { - // STRING CONVERSION SUCCEEDED - return result; - } - else { return fallBack; } // CONVERSION FAILED: RETURN FALLBACK - } - return fallBack; + if (!dict.ContainsKey("[" + section + "]" + key)) return fallBack; + // TRYS TO CONVERT A STRING TO AN INT + return int.TryParse(dict["[" + section + "]" + key], out int result) ? result : fallBack; } #endregion diff --git a/src/Server/External/Database.cs b/src/Server/External/Database.cs deleted file mode 100644 index 85353f1..0000000 --- a/src/Server/External/Database.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Linq; -using System.IO; -using System.Threading; -using DispatchSystem.Common.DataHolders.Storage; -using DispatchSystem.Common.DataHolders; - -namespace DispatchSystem.sv.External -{ - public sealed class Database - { - private const string CIV_FILE = "dsciv.db"; - private const string VEH_FILE = "dsveh.db"; - - private bool reading; - - internal Database() - { - reading = true; - new FileStream(CIV_FILE, FileMode.OpenOrCreate).Dispose(); // Creating the CIV file - new FileStream(VEH_FILE, FileMode.OpenOrCreate).Dispose(); // Creating the VEH file - reading = false; - } - - public StorageManager Read(string filename) where T : IOwnable - { - while (reading) - Thread.Sleep(50); - reading = true; - if (filename != CIV_FILE && filename != VEH_FILE) - throw new InvalidOperationException("filename cannot be different from set DB files"); - - using (var stream = new FileStream(filename, FileMode.Open)) - { - if (!stream.CanWrite || !stream.CanRead) - throw new IOException("Invalid permissions to read or write"); - - byte[] buffer = new byte[stream.Length]; - stream.Read(buffer, 0, (int)stream.Length); - - reading = false; - return buffer.Length == 0 ? null : new StorableValue>(buffer).Value; - } - } - public void Write(StorageManager data, string filename) where T : IOwnable - { - while (reading) - Thread.Sleep(50); - reading = true; - if (filename != CIV_FILE && filename != VEH_FILE) - throw new InvalidOperationException("filename cannot be different from set DB files"); - - using (var stream = new FileStream(filename, FileMode.Open)) - { - if (!stream.CanWrite || !stream.CanRead) - throw new IOException("Invalid permissions to read or write"); - - byte[] serializedData = new StorableValue>(data).Bytes; - stream.Write(serializedData, 0, serializedData.Length); - reading = false; - } - } - } -} diff --git a/src/Server/External/DispatchServer.cs b/src/Server/External/DispatchServer.cs index e52e85d..6ca35af 100644 --- a/src/Server/External/DispatchServer.cs +++ b/src/Server/External/DispatchServer.cs @@ -2,101 +2,133 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using System.Net; using System.Net.Sockets; -using System.Threading; using Config.Reader; + using DispatchSystem.Common.DataHolders.Storage; using CloNET; using CloNET.Callbacks; -using CloNET.Interfaces; +using CloNET.LocalCallbacks; using CitizenFX.Core; +using DispatchSystem.Common; namespace DispatchSystem.sv.External { public class DispatchServer { - private Server server; - private readonly iniconfig cfg; - private readonly Permissions perms; - private int Port { get; } + private Server server; // server from CloNET + private readonly string ip; // ip of the server + private readonly int port; // port of the server - public ConnectedPeer[] ConnectedDispatchers => server.ConnectedPeers.Where(x => x.IsConnected).ToArray(); + /// + /// of that are currently connected to the server + /// + public ConnectedPeer[] ConnectedDispatchers => server.ConnectedPeers.ToArray(); + // 911calls items, for keeping track of dispatchers connected to which 911 call internal Dictionary Calls; - internal DispatchServer(iniconfig cfg) + /// + /// Initializes the class from a config + /// + /// + internal DispatchServer(ServerConfig cfg) { - Calls = new Dictionary(); - this.cfg = cfg; - perms = Permissions.Get; - Port = this.cfg.GetIntValue("server", "port", 33333); - Log.WriteLine("Setting port to " + Port); - Start(); + Calls = new Dictionary(); // creating the calls item + ip = cfg.GetStringValue("server", "ip", "0.0.0.0"); // setting the ip + Log.WriteLine("Setting ip to " + ip); + port = cfg.GetIntValue("server", "port", 33333); // setting the port + Log.WriteLine("Setting port to " + port); + Start(); // starting the server } private void Start() { - Log.WriteLine("Creating TCP Device"); - server = new Server(cfg.GetStringValue("server", "ip", "0.0.0.0"), Port) + Log.WriteLine("Creating TCP Device"); // moar logs + server = new Server(ip, port) // creating the server from the port ant ip { - Encryption = new EncryptionOptions + Encryption = new EncryptionOptions // setting encryption off { - Encrypt = false, + Encrypt = true, + Overridable = false + }, + Compression = new CompressionOptions // setting compression off + { + Compress = false, Overridable = false } }; + // server events server.Connected += OnConnect; server.Disconnected += OnDisconnect; Log.WriteLine("TCP Created, starting TCP"); - try { server.Start(); } + // starting the server + try { server.Listening = true; } + // catching a port in use exception catch (SocketException) { - Log.WriteLine("The specified port (" + Port + ") is already in use."); + Log.WriteLine("The specified port (" + port + ") is already in use."); return; } Log.WriteLine("TCP Started, Listening for connections..."); - AddCallbacks(); + AddCallbacks(); // adding the callbacks to the server for use from client } private void AddCallbacks() { - server.Functions.Add("GetCivilian", new NetFunction(GetCivilian)); - server.Functions.Add("GetCivilianVeh", new NetFunction(GetCivilianVeh)); - server.Functions.Add("GetBolos", new NetFunction(GetBolos)); - server.Functions.Add("GetOfficers", new NetFunction(GetOfficers)); - server.Functions.Add("GetOfficer", new NetFunction(GetOfficer)); - server.Functions.Add("GetAssignments", new NetFunction(GetAssignments)); - server.Functions.Add("CreateAssignment", new NetFunction(NewAssignment)); - server.Functions.Add("GetOfficerAssignment", new NetFunction(GetOfcAssignment)); - server.Functions.Add("Accept911", new NetFunction(AcceptEmergency)); - server.Events.Add("911End", new NetEvent(EndEmergency)); - server.Events.Add("911Msg", new NetEvent(MessageEmergency)); - server.Events.Add("AddOfficerAssignment", new NetEvent(AddOfcAssignment)); - server.Events.Add("RemoveAssignment", new NetEvent(RemoveAssignment)); - server.Events.Add("RemoveOfficerAssignment", new NetEvent(RemoveOfcAssignment)); - server.Events.Add("SetStatus", new NetEvent(ChangeOfficerStatus)); - server.Events.Add("RemoveOfficer", new NetEvent(RemoveOfficer)); - server.Events.Add("AddBolo", new NetEvent(AddBolo)); - server.Events.Add("RemoveBolo", new NetEvent(RemoveBolo)); - server.Events.Add("AddNote", new NetEvent(AddNote)); + // funcs that return objects from params given + server.LocalCallbacks.Functions = new MemberDictionary + { + {"GetCivilian", new LocalFunction(new Func(GetCivilian))}, + {"GetCivilianVeh", new LocalFunction(new Func(GetCivilianVeh))}, + {"GetOfficer", new LocalFunction(new Func(GetOfficer))}, + {"CreateAssignment", new LocalFunction(new Func(NewAssignment))}, + {"GetOfficerAssignment", new LocalFunction(new Func(GetOfcAssignment))}, + {"Accept911", new LocalFunction(new Func(AcceptEmergency))} + }; + // properties that only have a return, and no set + server.LocalCallbacks.Properties = new MemberDictionary + { + {"Bolos", new LocalProperty(GetBolos, null)}, + {"Officers", new LocalProperty(GetOfficers, null)}, + {"Assignments", new LocalProperty(GetAssignments, null)} + }; + // events that have params but no return + server.LocalCallbacks.Events = new MemberDictionary + { + {"911End", new LocalEvent(new Func(EndEmergency))}, + {"911Msg", new LocalEvent(new Func(MessageEmergency))}, + {"AddOfficerAssignment", new LocalEvent(new Func(AddOfcAssignment))}, + {"RemoveAssignment", new LocalEvent(new Func(RemoveAssignment))}, + {"RemoveOfficerAssignment", new LocalEvent(new Func(RemoveOfcAssignment))}, + {"SetStatus", new LocalEvent(new Func(ChangeOfficerStatus))}, + {"RemoveOfficer", new LocalEvent(new Func(RemoveOfficer))}, + {"AddBolo", new LocalEvent(new Func(AddBolo))}, + {"RemoveBolo", new LocalEvent(new Func(RemoveBolo))}, + {"AddNote", new LocalEvent(new Func(AddNote))} + }; } private static async Task OnConnect(ConnectedPeer user) { await Task.Run(delegate { + // logging the ip connected #if DEBUG Log.WriteLine($"[{user.RemoteIP}] Connected"); #else Log.WriteLineSilent($"[{user.RemoteIP}] Connected"); #endif + + // dispose if the permissions bad + if (_(user)) + user.Dispose(); }); } @@ -104,6 +136,7 @@ private static async Task OnDisconnect(ConnectedPeer user) { await Task.Run(delegate { + // logging the ip disconnected #if DEBUG Log.WriteLine($"[{user.RemoteIP}] Disconnected"); #else @@ -112,190 +145,147 @@ await Task.Run(delegate }); } - private async Task GetCivilian(ConnectedPeer sender, object[] args) + /* + _____ _ _ ____ _____ _ __ _____ + / ____| /\ | | | | | _ \ /\ / ____| | |/ / / ____| _ + | | / \ | | | | | |_) | / \ | | | ' / | (___ (_) + | | / /\ \ | | | | | _ < / /\ \ | | | < \___ \ + | |____ / ____ \ | |____ | |____ | |_) | / ____ \ | |____ | . \ ____) | _ + \_____| /_/ \_\ |______| |______| |____/ /_/ \_\ \_____| |_|\_\ |_____/ (_) + + */ + + private Civilian GetCivilian(ConnectedPeer sender, string first, string last) { - await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Get civilian Request Recieved"); #else Log.WriteLineSilent("[{sender.RemoteIP}] Get civilian Request Recieved"); #endif - string first = (string)args[0]; - string last = (string)args[1]; - + // tryna find civ using common Civilian civ = Common.GetCivilianByName(first, last); - if (civ != null) - { #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Sending Civilian information to Client"); + Log.WriteLine($"[{sender.RemoteIP}] Sending Civilian information to Client"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Sending Civilian information to Client"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Sending Civilian information to Client"); #endif - return civ; - } - else - { -#if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Civilian not found, sending null"); -#else - Log.WriteLineSilent($"[{sender.RemoteIP}] Civilian not found, sending null"); -#endif - return Civilian.Empty; - } + return civ; } - private async Task GetCivilianVeh(ConnectedPeer sender, object[] args) + private CivilianVeh GetCivilianVeh(ConnectedPeer sender, string plate) { - await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Get civilian veh Request Recieved"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Get civilian veh Request Recieved"); #endif - string plate = (string)args[0]; - + // tryna find the vehicle CivilianVeh civVeh = Common.GetCivilianVehByPlate(plate); - if (civVeh != null) - { -#if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Sending Civilian Veh information to Client"); -#else - Log.WriteLineSilent($"[{sender.RemoteIP}] Sending Civilian Veh information to Client"); -#endif - return civVeh; - } #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Civilian Veh not found, sending null"); + Log.WriteLine($"[{sender.RemoteIP}] Sending Civilian Veh information to Client"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Civilian Veh not found, sending null"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Sending Civilian Veh information to Client"); #endif - return CivilianVeh.Empty; + return civVeh; } - private async Task GetBolos(ConnectedPeer sender, object[] args) + private Officer GetOfficer(ConnectedPeer sender, Guid id) { - await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Get bolos Request Recieved"); + Log.WriteLine($"[{sender.RemoteIP}] Get officer Request Received"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Get bolos Request Recieved"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Get officer Request Received"); #endif - return DispatchSystem.ActiveBolos; + // finding the officer from the list + Officer ofc = DispatchSystem.Officers.ToList().Find(x => x.Id == id); + return ofc; } - private async Task GetOfficers(ConnectedPeer sender, object[] args) + private Assignment GetOfcAssignment(ConnectedPeer sender, Guid id) { - await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; - #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Get officers Request Received"); + Log.WriteLine($"[{sender.RemoteIP}] Get officer assignments Request Received"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Get officers Request Received"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Get officer assignments Request Received"); #endif + + // finding the officer in the list + Officer ofc = DispatchSystem.Officers.ToList().Find(x => x.Id == id); - return DispatchSystem.officers; + // finding assignment in common + return Common.GetOfficerAssignment(ofc); } - private async Task GetOfficer(ConnectedPeer sender, object[] args) + private bool AcceptEmergency(ConnectedPeer sender, Guid id) { - await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; - - Guid id = (Guid)args[0]; - #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Get officer Request Received"); + Log.WriteLine($"[{sender.RemoteIP}] Accept emergency Request Received"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Get officer Request Received"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Accept emergency Request Received"); #endif - Officer ofc = DispatchSystem.officers.ToList().Find(x => x.Id == id); - ofc = ofc ?? Officer.Empty; - return ofc; + // finding the call in the current calls + EmergencyCall acceptedCall = DispatchSystem.CurrentCalls.FirstOrDefault(x => x.Id == id); + if (Calls.ContainsKey(id) || acceptedCall == null) return false; // Checking null and accepted in same expression + + Calls.Add(id, sender.RemoteIP); // adding the call and dispatcher to the call list + // setting a message for invocation on the main thread + DispatchSystem.Invoke(delegate + { + Player p = Common.GetPlayerByIp(acceptedCall.SourceIP); + if (p != null) + { + Common.SendMessage(p, "Dispatch911", new [] {255,0,0}, "Your 911 call has been accepted by a Dispatcher"); + } + }); + return true; } - private async Task GetAssignments(ConnectedPeer sender, object[] args) + private async Task GetBolos(ConnectedPeer sender) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; - #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Get assignments Request Received"); + Log.WriteLine($"[{sender.RemoteIP}] Get bolos Request Recieved"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Get assignments Request Received"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Get bolos Request Recieved"); #endif - return DispatchSystem.assignments.AsEnumerable(); + return DispatchSystem.ActiveBolos; } - private async Task GetOfcAssignment(ConnectedPeer sender, object[] args) + private async Task GetOfficers(ConnectedPeer sender) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; - #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Get officer assignments Request Received"); + Log.WriteLine($"[{sender.RemoteIP}] Get officers Request Received"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Get officer assignments Request Received"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Get officers Request Received"); #endif - Guid id = (Guid)args[0]; - Officer ofc = DispatchSystem.officers.ToList().Find(x => x.Id == id); - return Common.GetOfficerAssignment(ofc); + return DispatchSystem.Officers; } - private async Task AcceptEmergency(ConnectedPeer sender, object[] args) + private async Task GetAssignments(ConnectedPeer sender) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; - #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Accept emergency Request Received"); + Log.WriteLine($"[{sender.RemoteIP}] Get assignments Request Received"); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Accept emergency Request Received"); + Log.WriteLineSilent($"[{sender.RemoteIP}] Get assignments Request Received"); #endif - Guid id = (Guid)args[0]; - EmergencyCall acceptedCall = DispatchSystem.currentCalls.Find(x => x.Id == id); - if (Calls.ContainsKey(id) || acceptedCall == null) return false; // Checking null and accepted in same expression - - Calls.Add(id, sender.RemoteIP); - DispatchSystem.Invoke(delegate - { - Player p = Common.GetPlayerByIp(acceptedCall.SourceIP); - if (p != null) - { - Common.SendMessage(p, "Dispatch911", new [] {255,0,0}, "Your 911 call has been accepted by a Dispatcher"); - } - }); - return true; + return DispatchSystem.Assignments; } - private async Task EndEmergency(ConnectedPeer sender, object[] args) + private async Task EndEmergency(ConnectedPeer sender, Guid id) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] End emergency Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] End emergency Request Received"); #endif - Guid id = (Guid) args[0]; - Calls.Remove(id); + Calls.Remove(id); // removing the id from the calls - EmergencyCall call = DispatchSystem.currentCalls.Find(x => x.Id == id); + EmergencyCall call = DispatchSystem.CurrentCalls.FirstOrDefault(x => x.Id == id); // obtaining the call from the civ - if (DispatchSystem.currentCalls.Remove(call)) + if (DispatchSystem.CurrentCalls.Remove(call)) // remove, if successful, then notify { DispatchSystem.Invoke(delegate { @@ -308,26 +298,20 @@ private async Task EndEmergency(ConnectedPeer sender, object[] args) }); } } - private async Task MessageEmergency(ConnectedPeer sender, object[] args) + private async Task MessageEmergency(ConnectedPeer sender, Guid id, string msg) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Message emergency Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Message emergency Request Received"); #endif - Guid id = (Guid) args[0]; - string msg = args[1] as string; - - EmergencyCall call = DispatchSystem.currentCalls.Find(x => x.Id == id); + EmergencyCall call = DispatchSystem.CurrentCalls.FirstOrDefault(x => x.Id == id); // finding the call DispatchSystem.Invoke(() => { - Player p = Common.GetPlayerByIp(call?.SourceIP); + Player p = Common.GetPlayerByIp(call?.SourceIP); // getting the player from the call's ip if (p != null) { @@ -335,32 +319,27 @@ private async Task MessageEmergency(ConnectedPeer sender, object[] args) } }); } - private async Task AddOfcAssignment(ConnectedPeer sender, object[] args) + private async Task AddOfcAssignment(ConnectedPeer sender, Guid id, Guid ofcId) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Add officer assignment Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Add officer assignment Request Received"); #endif - Guid id = (Guid)args[0]; - Guid ofcId = (Guid)args[1]; - - Assignment assignment = DispatchSystem.assignments.Find(x => x.Id == id); - Officer ofc = DispatchSystem.officers.ToList().Find(x => x.Id == ofcId); - if (assignment is null || ofc is null) + Assignment assignment = DispatchSystem.Assignments.Find(x => x.Id == id); // finding assignment from the id + Officer ofc = DispatchSystem.Officers.ToList().Find(x => x.Id == ofcId); // finding the officer from the id + if (assignment is null || ofc is null) // returning if either is null return; - if (DispatchSystem.ofcAssignments.ContainsKey(ofc)) + if (DispatchSystem.OfcAssignments.ContainsKey(ofc)) // returning if the officer already contains the assignment return; - DispatchSystem.ofcAssignments.Add(ofc, assignment); + DispatchSystem.OfcAssignments.Add(ofc, assignment); // adding the assignment to the officer ofc.Status = OfficerStatus.OffDuty; + // notify of assignment DispatchSystem.Invoke(() => { Player p = Common.GetPlayerByIp(ofc.SourceIP); @@ -368,61 +347,47 @@ private async Task AddOfcAssignment(ConnectedPeer sender, object[] args) Common.SendMessage(p, "^8DispatchCAD", new[] { 0, 0, 0 }, $"New assignment added: \"{assignment.Summary}\""); }); } - private async Task NewAssignment(ConnectedPeer sender, object[] args) + private Guid NewAssignment(ConnectedPeer sender, string summary) { - await Task.FromResult(0); - if (CheckAndDispose(sender)) - return null; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] New assignment Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] New assignment Request Received"); #endif - string summary = args[0] as string; - Assignment assignment = new Assignment(summary); - DispatchSystem.assignments.Add(assignment); - return assignment.Id; + DispatchSystem.Assignments.Add(assignment); + return assignment.Id; // returning the assingment id } - private async Task RemoveAssignment(ConnectedPeer sender, object[] args) + private async Task RemoveAssignment(ConnectedPeer sender, Guid id) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Remove assignment Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Remove assignment Request Received"); #endif - Guid item = (Guid) args[0]; - - Assignment item2 = DispatchSystem.assignments.ToList().Find(x => x.Id == item); - Common.RemoveAllInstancesOfAssignment(item2); + Assignment item2 = DispatchSystem.Assignments.Find(x => x.Id == id); // finding the assignment from the id + Common.RemoveAllInstancesOfAssignment(item2); // removing using common } - private async Task RemoveOfcAssignment(ConnectedPeer sender, object[] args) + private async Task RemoveOfcAssignment(ConnectedPeer sender, Guid ofcId) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Remove officer assignment Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Remove officer assignment Request Received"); #endif - Guid ofcId = (Guid)args[0]; - Officer ofc = DispatchSystem.officers.ToList().Find(x => x.Id == ofcId); + // finding the ofc + Officer ofc = DispatchSystem.Officers.FirstOrDefault(x => x.Id == ofcId); if (ofc == null) return; - if (!DispatchSystem.ofcAssignments.ContainsKey(ofc)) return; - DispatchSystem.ofcAssignments.Remove(ofc); + if (!DispatchSystem.OfcAssignments.ContainsKey(ofc)) return; + DispatchSystem.OfcAssignments.Remove(ofc); // removing the assignment from the officer - ofc.Status = OfficerStatus.OnDuty; + ofc.Status = OfficerStatus.OnDuty; // set on duty DispatchSystem.Invoke(() => { @@ -431,40 +396,32 @@ private async Task RemoveOfcAssignment(ConnectedPeer sender, object[] args) Common.SendMessage(p, "^8DispatchCAD", new[] { 0, 0, 0 }, "Your assignment has been removed by a dispatcher"); }); } - private async Task ChangeOfficerStatus(ConnectedPeer sender, object[] args) + private async Task ChangeOfficerStatus(ConnectedPeer sender, Guid id, OfficerStatus status) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Change officer status Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Change officer status Request Received"); #endif - Officer ofc = (Officer)args[0]; - OfficerStatus status = (OfficerStatus)args[1]; - - ofc = DispatchSystem.officers.ToList().Find(x => x.Id == ofc.Id); - var index = DispatchSystem.officers.IndexOf(ofc); - if (index == -1) - return; + // finding the officer + Officer ofc = DispatchSystem.Officers.FirstOrDefault(x => x.Id == id); - Officer ourOfc = DispatchSystem.officers[index]; + if (ofc is null) return; // checking for null - if (ourOfc.Status != status) + if (ofc.Status != status) { - ourOfc.Status = status; + ofc.Status = status; // changing the status #if DEBUG - Log.WriteLine($"[{sender.RemoteIP}] Setting officer status to " + status.ToString()); + Log.WriteLine($"[{sender.RemoteIP}] Setting officer status to " + status); #else - Log.WriteLineSilent($"[{sender.RemoteIP}] Setting officer status to " + status.ToString()); + Log.WriteLineSilent($"[{sender.RemoteIP}] Setting officer status to " + status); #endif DispatchSystem.Invoke(() => { - Player p = Common.GetPlayerByIp(ourOfc.SourceIP); + Player p = Common.GetPlayerByIp(ofc.SourceIP); if (p != null) Common.SendMessage(p, "^8DispatchCAD", new[] { 0, 0, 0 }, $"Dispatcher set status to {(ofc.Status == OfficerStatus.OffDuty ? "Off Duty" : ofc.Status == OfficerStatus.OnDuty ? "On Duty" : "Busy")}"); @@ -479,23 +436,20 @@ private async Task ChangeOfficerStatus(ConnectedPeer sender, object[] args) #endif } } - private async Task RemoveOfficer(ConnectedPeer sender, object[] args) + private async Task RemoveOfficer(ConnectedPeer sender, Guid id) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; - #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Remove officer Request Received"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Add bolo Request Received"); #endif - Guid ofcGiven = (Guid)args[0]; - - Officer ofc = DispatchSystem.officers.ToList().Find(x => x.Id == ofcGiven); + // getting the officer + Officer ofc = DispatchSystem.Officers.FirstOrDefault(x => x.Id == id); if (ofc != null) { + // notify of removing of role DispatchSystem.Invoke(delegate { Player p = Common.GetPlayerByIp(ofc.SourceIP); @@ -504,7 +458,8 @@ private async Task RemoveOfficer(ConnectedPeer sender, object[] args) Common.SendMessage(p, "^8DispatchCAD", new[] { 0, 0, 0 }, "You have been removed from your officer role by a dispatcher"); }); - DispatchSystem.officers.Remove(ofc); + // actually remove the officer from the list + DispatchSystem.Officers.Remove(ofc); #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Removed the officer from the list of officers"); @@ -521,42 +476,32 @@ private async Task RemoveOfficer(ConnectedPeer sender, object[] args) #endif } } - private async Task AddBolo(ConnectedPeer sender, object[] args) + private async Task AddBolo(ConnectedPeer sender, string player, string bolo) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Add bolo Request Recieved"); -#else - Log.WriteLineSilent($"[{sender.RemoteIP}] Add bolo Request Recieved"); -#endif - - string player = (string)args[0]; - string bolo = (string)args[1]; - -#if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Adding new Bolo for \"{bolo}\""); #else + Log.WriteLineSilent($"[{sender.RemoteIP}] Add bolo Request Recieved"); Log.WriteLineSilent($"[{sender.RemoteIP}] Adding new Bolo for \"{bolo}\""); #endif + + // adding bolo DispatchSystem.ActiveBolos.Add(new Bolo(player, string.Empty, bolo)); } - private async Task RemoveBolo(ConnectedPeer sender, object[] args) + private async Task RemoveBolo(ConnectedPeer sender, int parse) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Remove bolo Request Recieved"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Remove bolo Request Recieved"); #endif - int parse = (int)args[0]; - try { + // removing at the specified index DispatchSystem.ActiveBolos.RemoveAt(parse); #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Removed Active BOLO from the List"); @@ -564,6 +509,7 @@ private async Task RemoveBolo(ConnectedPeer sender, object[] args) Log.WriteLineSilent($"[{sender.RemoteIP}] Removed Active BOLO from the List"); #endif } + // thrown when argument is out of range catch (ArgumentOutOfRangeException) { #if DEBUG @@ -573,21 +519,16 @@ private async Task RemoveBolo(ConnectedPeer sender, object[] args) #endif } } - private async Task AddNote(ConnectedPeer sender, object[] args) + private async Task AddNote(ConnectedPeer sender, Guid id, string note) { await Task.FromResult(0); - if (CheckAndDispose(sender)) - return; #if DEBUG Log.WriteLine($"[{sender.RemoteIP}] Add Civilian note Request Recieved"); #else Log.WriteLineSilent($"[{sender.RemoteIP}] Add Civilian note Request Recieved"); #endif - string[] name = { (string)args[0], (string)args[1] }; - string note = (string)args[2]; - - Civilian civ = Common.GetCivilianByName(name[0], name[1]); + Civilian civ = DispatchSystem.Civs.FirstOrDefault(x => x.Id == id); // finding the civ from the id if (civ != null) { @@ -596,7 +537,7 @@ private async Task AddNote(ConnectedPeer sender, object[] args) #else Log.WriteLineSilent($"[{sender.RemoteIP}] Adding the note \"{note}\" to Civilian {civ.First} {civ.Last}"); #endif - civ.Notes.Add(note); + civ.Notes.Add(note); // adding the note for the civilian } else #if DEBUG @@ -606,17 +547,26 @@ private async Task AddNote(ConnectedPeer sender, object[] args) #endif } - private bool CheckAndDispose(IBaseNet sender) + private static bool _(ConnectedPeer sender) { - switch (perms.DispatchPermission) + switch (Permissions.Get.DispatchPermission) { - case Permission.Specific: - if (!perms.DispatchContains(IPAddress.Parse(sender.RemoteIP))) { Log.WriteLine($"[{sender.RemoteIP}] NOT ENOUGH DISPATCH PERMISSIONS"); return true; } + case Permission.Specific: // checking for specific permissions + if (!Permissions.Get.DispatchContains(IPAddress.Parse(sender.RemoteIP))) // checking if the ip is in the perms + { + Log.WriteLine($"[{sender.RemoteIP}] NOT ENOUGH DISPATCH PERMISSIONS"); // log if not + return true; + } break; case Permission.None: - Log.WriteLine($"[{sender.RemoteIP}] NOT ENOUGH DISPATCH PERMISSIONS"); return true; + Log.WriteLine($"[{sender.RemoteIP}] NOT ENOUGH DISPATCH PERMISSIONS"); + return true; // automatically return not + case Permission.Everyone: + break; // continue through + default: + throw new ArgumentOutOfRangeException(); // throw because there is no other options } - return false; + return false; // return false by default } } } diff --git a/src/Server/External/Log.cs b/src/Server/External/Log.cs index a2b8a46..2a0926e 100644 --- a/src/Server/External/Log.cs +++ b/src/Server/External/Log.cs @@ -1,33 +1,50 @@ using CitizenFX.Core; using System; +using System.Globalization; using System.IO; internal static class Log { - static object _lock = new object(); - static StreamWriter writer; + static readonly object _lock = new object(); // lock required for no double-logging + private static StreamWriter writer; // writer for writing the log to lines in the file public static void Create(string fileName) { - writer = new StreamWriter(fileName); + lock (_lock) + { + // creating the writer object for the endpoint + writer = new StreamWriter(fileName); + } } + /// + /// Writes a log to the server console and the file + /// + /// public static void WriteLine(string line) { lock (_lock) { - string formatted = $"[{DateTime.Now.ToString()}]: {line}"; + // creating the string formatted with date + string formatted = $"[{DateTime.Now.ToString("HH:mm:ss.fff")}]: {line}"; + // writing the formatted line to the log writer.WriteLine(formatted); writer.Flush(); - Debug.WriteLine($"(DispatchSystem) {formatted}"); + Debug.WriteLine($"(DispatchSystem) {formatted}"); // writing log to server console too } } + /// + /// Writes a log just to the file + /// + /// public static void WriteLineSilent(string line) { lock (_lock) { - string formatted = $"[{DateTime.Now.ToString()}]: {line}"; + // creating the string formatted with date + string formatted = $"[{DateTime.Now.ToString("HH:mm:ss.fff")}]: {line}"; + // writing the formatted line to the log writer.WriteLine(formatted); writer.Flush(); } diff --git a/src/Server/External/Permissions.cs b/src/Server/External/Permissions.cs deleted file mode 100644 index 6a374ae..0000000 --- a/src/Server/External/Permissions.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using CitizenFX.Core.Native; -using System.IO; -using System.Net; - -namespace DispatchSystem.sv.External -{ - public enum Permission - { - Everyone, - Specific, - None - } - public sealed class Permissions - { - #region Singleton - static object _lock = new object(); - static Permissions obj = null; - static string _fileName; - static string _resourceName; - public static void SetInformation(string fileName, string resourceName) { _fileName = fileName; _resourceName = resourceName; } - - public static Permissions Get - { - get - { - if (obj == null) - lock (_lock) - if (obj == null) - obj = new Permissions(_fileName, _resourceName); - return obj; - } - } - #endregion - - public const string CIV_KEY = "civilian:"; - public const string COP_KEY = "leo:"; - public const string DISPATCH_KEY = "dispatcher:"; - - string fileName; - string resourceName; - - List> items = new List>(); - - public Permission CivilianPermission { get; private set; } = Permission.Specific; - public Permission LeoPermission { get; private set; } = Permission.Specific; - public Permission DispatchPermission { get; private set; } = Permission.Specific; - - public IEnumerable CivilianData - { - get - { - foreach (var item in items) - if (item.Item1 == CIV_KEY) - if (IPAddress.TryParse(item.Item2, out IPAddress address)) - yield return address; - } - } - public IEnumerable LeoData - { - get - { - foreach (var item in items) - if (item.Item1 == COP_KEY) - if (IPAddress.TryParse(item.Item2, out IPAddress address)) - yield return address; - } - } - public IEnumerable DispatchData - { - get - { - foreach (var item in items) - if (item.Item1 == DISPATCH_KEY) - if (IPAddress.TryParse(item.Item2, out IPAddress address)) - yield return address; - } - } - - #region constructor - private Permissions(string fileName, string resourceName) - { - this.fileName = fileName; - this.resourceName = resourceName; - } - public void Refresh() - { - Log.WriteLine("Setting the permissions"); - string data = Function.Call(Hash.LOAD_RESOURCE_FILE, resourceName, fileName); - string current = string.Empty; - string[] lines = data.Split('\n').Where(x => !string.IsNullOrWhiteSpace(x)).Where(x => !x.StartsWith("//")).Select(x => x.Trim().ToLower()).ToArray(); - - for (int i = 0; i < lines.Count(); i++) - { - string line = lines[i]; - - if (line == CIV_KEY || line == COP_KEY || line == DISPATCH_KEY) { current = line; continue; } - if (current == string.Empty) continue; - - if (line == "everyone") - { - if (current == CIV_KEY) - CivilianPermission = Permission.Everyone; - if (current == COP_KEY) - LeoPermission = Permission.Everyone; - if (current == DISPATCH_KEY) - DispatchPermission = Permission.Everyone; - } - else if (line == "none") - { - if (current == CIV_KEY) - CivilianPermission = Permission.None; - if (current == COP_KEY) - LeoPermission = Permission.None; - if (current == DISPATCH_KEY) - DispatchPermission = Permission.None; - } - else - items.Add(new Tuple(current, line)); - } - - Log.WriteLine("Permissions set!"); - } - #endregion - - public bool CivContains(IPAddress address) => CivilianData.Contains(address); - public bool LeoContains(IPAddress address) => LeoData.Contains(address); - public bool DispatchContains(IPAddress address) => DispatchData.Contains(address); - } -} diff --git a/src/Server/Server.csproj b/src/Server/Server.csproj index 1f2f9cd..b12a028 100644 --- a/src/Server/Server.csproj +++ b/src/Server/Server.csproj @@ -36,8 +36,7 @@ ..\..\ref\cfx_server\CitizenFX.Core.dll - False - ..\packages\CloneCommando.CloNET.0.4.2\lib\net461\CloNET.dll + ..\packages\CloneCommando.CloNET.0.5.4\lib\net461\CloNET.dll @@ -58,9 +57,7 @@ - - diff --git a/src/Server/packages.config b/src/Server/packages.config index 351bf48..7072653 100644 --- a/src/Server/packages.config +++ b/src/Server/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/src/packages/CloneCommando.CloNET.0.4.2/CloneCommando.CloNET.0.4.2.nupkg b/src/packages/CloneCommando.CloNET.0.4.2/CloneCommando.CloNET.0.4.2.nupkg deleted file mode 100644 index 06f314c..0000000 Binary files a/src/packages/CloneCommando.CloNET.0.4.2/CloneCommando.CloNET.0.4.2.nupkg and /dev/null differ diff --git a/src/packages/CloneCommando.CloNET.0.5.4/CloneCommando.CloNET.0.5.4.nupkg b/src/packages/CloneCommando.CloNET.0.5.4/CloneCommando.CloNET.0.5.4.nupkg new file mode 100644 index 0000000..cdf9582 Binary files /dev/null and b/src/packages/CloneCommando.CloNET.0.5.4/CloneCommando.CloNET.0.5.4.nupkg differ diff --git a/src/packages/CloneCommando.CloNET.0.5.4/lib/net461/CloNET.dll b/src/packages/CloneCommando.CloNET.0.5.4/lib/net461/CloNET.dll new file mode 100644 index 0000000..2820128 Binary files /dev/null and b/src/packages/CloneCommando.CloNET.0.5.4/lib/net461/CloNET.dll differ diff --git a/src/serverfiles/__resource.lua b/src/serverfiles/__resource.lua index 1cbc90a..f929469 100644 --- a/src/serverfiles/__resource.lua +++ b/src/serverfiles/__resource.lua @@ -3,12 +3,15 @@ ui_page 'nui/index.html' files { 'nui/index.css', 'nui/index.html', - 'nui/nui.js' + 'nui/menu.js' } server_script 'dispatchsystem.server.net.dll' client_scripts { - 'client.lua' + 'callbacks.lua', + 'common.lua', + 'menu.lua', + 'transactions.lua' } file 'settings.ini' file 'permissions.perms' \ No newline at end of file diff --git a/src/serverfiles/callbacks.lua b/src/serverfiles/callbacks.lua new file mode 100644 index 0000000..1492ed4 --- /dev/null +++ b/src/serverfiles/callbacks.lua @@ -0,0 +1,91 @@ +--[[ + NUI +]] + +--[[ADDING CIV CALLBACKS]] +RegisterNUICallback("civ", function(data, cb) + if data[1] == nil then + return + elseif data[1] == "newname" then + createCivilian() + elseif data[1] == "warrant" then + toggleWarrant() + elseif data[1] == "citations" then + civCitations() + elseif data[1] == "911init" then + init911() + elseif data[1] == "911msg" then + msg911() + elseif data[1] == "911end" then + end911() + elseif data[1] == "newveh" then + createCivVehicle() + elseif data[1] == "vehstolen" then + toggleVehStolen() + elseif data[1] == "vehregi" then + toggleVehRegi() + elseif data[1] == "vehinsurance" then + toggleVehInsured() + elseif data[1] == "civdisplay" then + displayCivilian() + elseif data[1] == "vehdisplay" then + displayVeh() + end + + TriggerServerEvent("dispatchsystem:requestClientInfo", getHandle()) + + if cb then cb("OK") end +end) +--[[ADDING LEO CALLBACKS]] +RegisterNUICallback("leo", function(data, cb) + if data[1] == nil then + return + elseif data[1] == "create" then + createOfficer() + elseif data[1] == "displayduty" then + displayStatus() + elseif data[1] == "onduty" or data[1] == "offduty" or data[1] == "busy" then + changeStatus(data[1]) + elseif data[1] == "ncic" then + leoNcic() + elseif data[1] == "note" then + if data[2] == "add" then + leoAddNote() + elseif data[2] == "view" then + leoNcicNotes() + end + elseif data[1] == "ticket" then + if data[2] == "add" then + leoAddTicket() + elseif data[2] == "view" then + leoNcicTickets() + end + elseif data[1] == "plate" then + leoPlate() + elseif data[1] == "bolo" then + if data[2] == "add" then + leoAddBolo() + elseif data[2] == "view" then + leoViewBolos() + end + end + + TriggerServerEvent("dispatchsystem:requestClientInfo", getHandle()) + + if cb then cb("OK") end +end) +--[[ADDING COMMON CALLBACKS]] +RegisterNUICallback("common", function(data, cb) + if data[1] == nil then + return + elseif data[1] == "exit" then + safeExit() + elseif data[1] == "dsreset" then + TriggerServerEvent("dispatchsystem:dsreset", getHandle()) + end + + TriggerServerEvent("dispatchsystem:requestClientInfo", getHandle()) + + if cb then cb("OK") end +end) +--[[ END OF NUI ]] diff --git a/src/serverfiles/client.lua b/src/serverfiles/client.lua deleted file mode 100644 index 11306b5..0000000 --- a/src/serverfiles/client.lua +++ /dev/null @@ -1,436 +0,0 @@ ---[[ - COMMON APPS -]] -function drawNotification(text) - SetNotificationTextEntry("STRING") - AddTextComponentString(text) - DrawNotification(false, false) -end -function KeyboardInput(TextEntry, ExampleText, MaxStringLenght) -- ps thanks @Flatracer - -- TextEntry --> The Text above the typing field in the black square - -- ExampleText --> An Example Text, what it should say in the typing field - -- MaxStringLenght --> Maximum String Lenght - - AddTextEntry('FMMC_KEY_TIP1', TextEntry .. ':') --Sets the Text above the typing field in the black square - DisplayOnscreenKeyboard(1, "FMMC_KEY_TIP1", "", ExampleText, "", "", "", MaxStringLenght) --Actually calls the Keyboard Input - blockinput = true --Blocks new input while typing if **blockinput** is used - - while UpdateOnscreenKeyboard() ~= 1 and UpdateOnscreenKeyboard() ~= 2 do --While typing is not aborted and not finished, this loop waits - Citizen.Wait(0) - end - - if UpdateOnscreenKeyboard() ~= 2 then - local result = GetOnscreenKeyboardResult() --Gets the result of the typing - Citizen.Wait(500) --Little Time Delay, so the Keyboard won't open again if you press enter to finish the typing - blockinput = false --This unblocks new Input when typing is done - return result --Returns the result - else - blockinput = false --This unblocks new Input when typing is done - return nil --Returns nil if the typing got aborted - end -end -function sendMessage(title, rgb, text) - TriggerEvent("chatMessage", title, rgb, text) -end -function stringsplit(inputstr, sep) - if sep == nil then - sep = "%s" - end - local t={} ; i=1 - for str in string.gmatch(inputstr, "([^"..sep.."]+)") do - t[i] = str - i = i + 1 - end - return t -end -function getHandle() - return tostring(GetPlayerServerId(PlayerId())) -end -function tablelength(T) - local count = 0 - for _ in pairs(T) do count = count + 1 end - return count - end ---[[ END OF COMMON ]] - -sendMessage("DispatchSystem", {0,0,0}, "DispatchSystem.Client by BlockBa5her loaded") - ---[[ - SERVER & CLIENT TRANSACTIONS -]] - --- Civ Transactions -local civName = nil -local vehName = nil -function displayCivilian() - Citizen.CreateThread(function() - if civName == nil then - drawNotification("You must set your name first!") - return - end - TriggerServerEvent("dispatchsystem:getCivilian", getHandle(), civName[1], civName[2]) - end) -end -function displayVeh() - Citizen.CreateThread(function() - if vehName == nil then - drawNotification("You must set your vehicle first!") - return - end - TriggerServerEvent("dispatchsystem:getCivilianVeh", getHandle(), vehName) - end) -end -function createCivilian() - Citizen.CreateThread(function() - exitAllMenus() - local nameNotSplit = KeyboardInput("Name", "", 20) - if nameNotSplit == nil then - turnOnCivMenu() - return - end - local name = stringsplit(nameNotSplit, ' ') - if tablelength(name) < 2 then - drawNotification("You must have a first name and a last name") - turnOnCivMenu() - return - end - civName = name - TriggerServerEvent("dispatchsystem:setName", getHandle(), name[1], name[2]) - turnOnCivMenu() - end) -end -function toggleWarrant() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:toggleWarrant", getHandle()) - end) -end -function civCitations() - Citizen.CreateThread(function() - exitAllMenus() - local amount = tonumber(KeyboardInput("Citation Count", "", 3)) - if amount == nil then - turnOnCivMenu() - drawNotification("You must have a valid number") - return - end - TriggerServerEvent("dispatchsystem:setCitations", getHandle(), amount) - turnOnCivMenu() - end) -end -function init911() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:911init", getHandle()) - end) -end -function msg911() - Citizen.CreateThread(function() - exitAllMenus() - local msg = KeyboardInput("Text", "", 100) - if msg == nil then - turnOnCivMenu() - drawNotification("Invalid message") - return - end - TriggerServerEvent("dispatchsystem:911msg", getHandle(), msg) - turnOnCivMenu() - end) -end -function end911() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:911end", getHandle()) - end) -end -function createCivVehicle() - Citizen.CreateThread(function() - exitAllMenus() - local plate = KeyboardInput("Plate", "", 8) - if plate == nil then - turnOnCivMenu() - return - end - vehName = plate - TriggerServerEvent("dispatchsystem:setVehicle", getHandle(), plate) - turnOnCivMenu() - end) -end -function toggleVehStolen() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:toggleVehStolen", getHandle()) - end) -end -function toggleVehRegi() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:toggleVehRegi", getHandle()) - end) -end -function toggleVehInsured() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:toggleVehInsured", getHandle()) - end) -end - --- Leo Transactions -local lastSearchedName = nil - -local function setLastSearchedName() - exitAllMenus() - local nameNotSplit = KeyboardInput("Name", "", 20) - if nameNotSplit == nil then - turnOnLeoMenu() - return - end - local name = stringsplit(nameNotSplit, ' ') - if tablelength(name) < 2 then - drawNotification("You must have a first name and a last name") - return - end - lastSearchedName = name - turnOnLeoMenu() -end -function createOfficer() - Citizen.CreateThread(function() - exitAllMenus() - local callsign = KeyboardInput("Officer Callsign", "", 9) - if callsign == nil then - turnOnLeoMenu() - return - end - TriggerServerEvent("dispatchsystem:initOfficer", getHandle(), callsign) - turnOnLeoMenu() - end) -end -function displayStatus() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:displayStatus", getHandle()) - end) -end -function changeStatus(type) - Citizen.CreateThread(function() - if type == "leo_onduty" then - TriggerServerEvent("dispatchsystem:onDuty", getHandle()) - elseif type == "leo_offduty" then - TriggerServerEvent("dispatchsystem:offDuty", getHandle()) - elseif type == "leo_busy" then - TriggerServerEvent("dispatchsystem:busy", getHandle()) - end - end) -end -function leoNcic() - Citizen.CreateThread(function() - setLastSearchedName() - TriggerServerEvent("dispatchsystem:getCivilian", getHandle(), lastSearchedName[1], lastSearchedName[2]) - end) -end -function leoNcicNotes() - Citizen.CreateThread(function() - if lastSearchedName == nil then - drawNotification("You must have searched a name before") - return - end - TriggerServerEvent("dispatchsystem:displayCivNotes", getHandle(), lastSearchedName[1], lastSearchedName[2]) - end) -end -function leoNcicTickets() - if lastSearchedName == nil then - drawNotification("You must have searched a name before") - return - end - TriggerServerEvent("dispatchsystem:civTickets", getHandle(), lastSearchedName[1], lastSearchedName[2]) -end -function leoPlate() - Citizen.CreateThread(function() - exitAllMenus() - local plate = KeyboardInput("Plate", "", 8) - if plate == nil then - turnOnLeoMenu() - return - end - TriggerServerEvent("dispatchsystem:getCivilianVeh", getHandle(), plate) - turnOnLeoMenu() - end) -end -function leoAddNote() - Citizen.CreateThread(function() - if lastSearchedName == nil then - setLastSearchedName() - else - drawNotification("~r~Default name set to ~w~"..lastSearchedName[1].." "..lastSearchedName[2]) - end - exitAllMenus() - local note = KeyboardInput("Note Text", "", 150) - if note == nil then - turnOnLeoMenu() - return - end - TriggerServerEvent("dispatchsystem:addCivNote", getHandle(), lastSearchedName[1], lastSearchedName[2], note) - turnOnLeoMenu() - end) -end -function leoAddTicket() - Citizen.CreateThread(function() - if lastSearchedName == nil then - setLastSearchedName() - else - drawNotification("~r~Default name set to ~w~"..lastSearchedName[1].." "..lastSearchedName[2]) - end - exitAllMenus() - local amount = tonumber(KeyboardInput("Amount", "", 7)) - if amount == nil then - turnOnLeoMenu() - drawNotification("You must have a valid number") - return - end - if amount > 9999.99 then - turnOnLeoMenu() - drawNotification("Your amount must be below 9999.99") - return - end - local reason = KeyboardInput("Reason", "", 150) - if reason == nil then - turnOnLeoMenu() - return - end - TriggerServerEvent("dispatchsystem:ticketCiv", getHandle(), lastSearchedName[1], lastSearchedName[2], reason, amount) - turnOnLeoMenu() - end) -end -function leoAddBolo() - Citizen.CreateThread(function() - exitAllMenus() - local reason = KeyboardInput("BOLO Reason", "", 250) - if reason == nil then - turnOnLeoMenu() - return - end - TriggerServerEvent("dispatchsystem:addBolo", getHandle(), reason) - turnOnLeoMenu() - end) -end -function leoViewBolos() - Citizen.CreateThread(function() - TriggerServerEvent("dispatchsystem:viewBolos", getHandle()) - end) -end ---[[ END OF TRANSACTIONS ]] - ---[[ - NUI & NUI Callbacks -]] -RegisterNetEvent("dispatchsystem:toggleLeoNUI") -RegisterNetEvent("dispatchsystem:toggleCivNUI") - -local menu = nil -function turnOnCivMenu() - menu = "civ" - SetNuiFocus(true, true) - SendNUIMessage({showcivmenu = true}) -end -function turnOnLeoMenu() - menu = "leo" - SetNuiFocus(true, true) - SendNUIMessage({showleomenu = true}) -end -function exitAllMenus() - menu = nil - SetNuiFocus(false) - SendNUIMessage({hidemenus = true}) -end -function resetMenu() - if menu == "civ" then - SendNUIMessage({hidemenus = true}) - SendNUIMessage({showcivmenu = true}) - elseif menu == "leo" then - SendNUIMessage({hidemenus = true}) - SendNUIMessage({showleomenu = true}) - end -end - --- Adding event handler at the end to use all of the above functions -AddEventHandler("dispatchsystem:toggleCivNUI", function() - if menu == nil then - turnOnCivMenu() - else - exitAllMenus() - end -end) -AddEventHandler("dispatchsystem:toggleLeoNUI", function() - if menu == nil then - turnOnLeoMenu() - else - exitAllMenus() - end -end) - -Citizen.CreateThread(function() - Citizen.Wait(500) - - -- Disabling NUI focus so that people can move in-game again - SetNuiFocus(false, false) -end) - --- Adding callbacks for NUI button presses -RegisterNUICallback("ButtonClick", function(data, cb) - if data == nil then - return - --[[CIV OPTIONS]] - elseif data == "civ_newname" then - createCivilian() - elseif data == "civ_warrant" then - toggleWarrant() - elseif data == "civ_citations" then - civCitations() - elseif data == "civ_911init" then - init911() - elseif data == "civ_911msg" then - msg911() - elseif data == "civ_911end" then - end911() - elseif data == "civ_newveh" then - createCivVehicle() - elseif data == "civ_vehstolen" then - toggleVehStolen() - elseif data == "civ_vehregi" then - toggleVehRegi() - elseif data == "civ_vehinsurance" then - toggleVehInsured() - elseif data == "civ_civdisplay" then - displayCivilian() - elseif data == "civ_vehdisplay" then - displayVeh() - - --[[LEO OPTIONS]] - elseif data == "leo_create" then - createOfficer() - elseif data == "leo_displayduty" then - displayStatus() - elseif data == "leo_onduty" or data == "leo_offduty" or data == "leo_busy" then - changeStatus(data) - elseif data == "leo_ncic" then - leoNcic() - elseif data == "leo_ncic-note" then - leoNcicNotes() - elseif data == "leo_ncic-ticket" then - leoNcicTickets() - elseif data == "leo_plate" then - leoPlate() - elseif data == "leo_add-note" then - leoAddNote() - elseif data == "leo_add-ticket" then - leoAddTicket() - elseif data == "leo_add-bolo" then - leoAddBolo() - elseif data == "leo_view-bolo" then - leoViewBolos() - - --[[COMMON MENU OPTIONS]] - elseif data == "reset_menu" then - resetMenu() - elseif data == "dsreset" then - TriggerServerEvent("dispatchsystem:dsreset", getHandle()) - elseif data == "exit" then - exitAllMenus() - end - - if cb then cb("OK") end -end) ---[[ END OF NUI ]] diff --git a/src/serverfiles/common.lua b/src/serverfiles/common.lua new file mode 100644 index 0000000..929ff70 --- /dev/null +++ b/src/serverfiles/common.lua @@ -0,0 +1,87 @@ +--[[ + COMMON APPS +]] +function drawNotification(text) + SetNotificationTextEntry("STRING") + AddTextComponentString(text) + DrawNotification(false, false) +end +function KeyboardInput(TextEntry, ExampleText, MaxStringLenght) -- ps thanks @Flatracer + -- TextEntry --> The Text above the typing field in the black square + -- ExampleText --> An Example Text, what it should say in the typing field + -- MaxStringLenght --> Maximum String Lenght + + AddTextEntry('FMMC_KEY_TIP1', TextEntry .. ':') --Sets the Text above the typing field in the black square + DisplayOnscreenKeyboard(1, "FMMC_KEY_TIP1", "", ExampleText, "", "", "", MaxStringLenght) --Actually calls the Keyboard Input + blockinput = true --Blocks new input while typing if **blockinput** is used + + while UpdateOnscreenKeyboard() ~= 1 and UpdateOnscreenKeyboard() ~= 2 do --While typing is not aborted and not finished, this loop waits + Citizen.Wait(0) + end + + if UpdateOnscreenKeyboard() ~= 2 then + local result = GetOnscreenKeyboardResult() --Gets the result of the typing + Citizen.Wait(500) --Little Time Delay, so the Keyboard won't open again if you press enter to finish the typing + blockinput = false --This unblocks new Input when typing is done + return result --Returns the result + else + blockinput = false --This unblocks new Input when typing is done + return nil --Returns nil if the typing got aborted + end +end +function sendMessage(title, rgb, text) + TriggerEvent("chatMessage", title, rgb, text) +end +function stringsplit(inputstr, sep) + if sep == nil then + sep = "%s" + end + local t={} ; i=1 + for str in string.gmatch(inputstr, "([^"..sep.."]+)") do + t[i] = str + i = i + 1 + end + return t +end +function getHandle() + return tostring(GetPlayerServerId(PlayerId())) +end +function tablelength(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end +function terminateMenu() + Citizen.CreateThread(function() + Citizen.Wait(500) + turnOnCivMenu = nil + turnOnLeoMenu = nil + turnOnLastMenu = nil + exitAllMenus = nil + resetMenu = nil + safeExit = nil + end) +end +--[[ END OF COMMON ]] + +--[[ + INIT ITEMS +]] +Citizen.CreateThread(function() + Citizen.Wait(500) + local resource = GetCurrentResourceName() + if (resource ~= string.lower(resource)) then + terminateMenu() + + while true do + if DoesEntityExist(PlayerPedId()) then + drawNotification("DispatchSystem:~n~~r~PLEASE CHANGE RESOURCE NAME TO ALL LOWER") + end + Wait(10) + end + return + end + SendNUIMessage({setname = true, metadata = GetCurrentResourceName()}) -- Telling JS of the resource name + sendMessage("DispatchSystem", {0,0,0}, "DispatchSystem.Client by BlockBa5her loaded") +end) +--[[ END OF INIT ]] \ No newline at end of file diff --git a/src/serverfiles/menu.lua b/src/serverfiles/menu.lua new file mode 100644 index 0000000..24e6bee --- /dev/null +++ b/src/serverfiles/menu.lua @@ -0,0 +1,69 @@ +--[[ + MENU stuff +]] +RegisterNetEvent("dispatchsystem:toggleLeoNUI") +RegisterNetEvent("dispatchsystem:toggleCivNUI") +RegisterNetEvent("dispatchsystem:resetNUI") +RegisterNetEvent("dispatchsystem:pushbackData") + +local menu = nil +function turnOnCivMenu() + TriggerServerEvent("dispatchsystem:requestClientInfo", getHandle()) + + menu = "civ" + SetNuiFocus(true, true) + SendNUIMessage({showcivmenu = true}) +end +function turnOnLeoMenu() + TriggerServerEvent("dispatchsystem:requestClientInfo", getHandle()) + + menu = "leo" + SetNuiFocus(true, true) + SendNUIMessage({showleomenu = true}) +end +function turnOnLastMenu() + menu = "unknown" + SetNuiFocus(true, true) + SendNUIMessage({openlastmenu = true}) +end +function exitAllMenus() + menu = nil + SetNuiFocus(false) + SendNUIMessage({hidemenus = true}) +end +function resetMenu() + if menu == "civ" then + SendNUIMessage({hidemenus = true}) + SendNUIMessage({showcivmenu = true}) + elseif menu == "leo" then + SendNUIMessage({hidemenus = true}) + SendNUIMessage({showleomenu = true}) + end +end +function safeExit() + SetNuiFocus(false) + menu = nil +end + +-- Adding event handler at the end to use all of the above functions +AddEventHandler("dispatchsystem:toggleCivNUI", function() + if menu == nil then + turnOnCivMenu() + else + exitAllMenus() + end +end) +AddEventHandler("dispatchsystem:toggleLeoNUI", function() + if menu == nil then + turnOnLeoMenu() + else + exitAllMenus() + end +end) +AddEventHandler("dispatchsystem:resetNUI", function() + exitAllMenus() +end) +AddEventHandler("dispatchsystem:pushbackData", function(civData, ofcData) + SendNUIMessage({pushback = true, data = {civData, ofcData}}) +end) +--[[ END OF MENU STUFF ]] diff --git a/src/serverfiles/nui/index.css b/src/serverfiles/nui/index.css index f16a0d2..7b79a48 100644 --- a/src/serverfiles/nui/index.css +++ b/src/serverfiles/nui/index.css @@ -4,7 +4,7 @@ button.option { background-color: #000000; border: 1px solid #000000; color: white; - font-family: 'Roboto', sans-serif; + font-family: sans-serif; font-size: 16px; padding: 10px 24px; margin: 8px 0px 8px 0px; @@ -41,8 +41,79 @@ button.back:after { content: "<<"; } -div { - position: fixed; /* or absolute */ +.menu { + position: fixed; top: 50%; left: 30%; -} \ No newline at end of file + display: none; +} + +#civinfo, #ofcinfo { + margin: 0; + padding: 0; + position: absolute; + top: 50%; + left: 45%; + background: #000000; + width: 672px; + height: 324px; + display: none; + font-family: 'Lato', sans-serif; + color: white; + border-radius: 10px; +} +#ofcinfo { + width: 384px; + height: 432px; +} + +p { + float: center; + text-align: center; + display: inherit; + padding: 5px 15px; + margin: 0; + background: #bbbbbb; + color: black; + border-radius: 25px; + font-size: 16px; +} + +.wrapper { + display: flex !important; + height: inherit; +} +.wrapper > div { + display: block !important; + padding: 20px 0; + width: 100%; +} +#civinfo .wrapper > div { + width: 50%; +} +.wrapper > div > span { + display: flex; +} +span { + margin: 15px 0; + margin-right: 5px; +} +h1 { + display: block; + text-align: center; + margin: 0; + margin-top: 10px; +} +h2 { + text-align: center; + font-size: 22px; + font-weight: 400; +} +h3 { + margin: 0; + margin-right: 5px; + margin-left: 10px; + + font-weight: 400; + font-size: 18px; +} diff --git a/src/serverfiles/nui/index.html b/src/serverfiles/nui/index.html index ab39606..8b1ba22 100644 --- a/src/serverfiles/nui/index.html +++ b/src/serverfiles/nui/index.html @@ -1,83 +1,98 @@ - - - + + + -