stuff
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
**/bin
|
**/bin
|
||||||
**/obj
|
**/obj
|
||||||
**/packages
|
**/packages
|
||||||
.vs/*
|
**/.vs
|
@ -143,19 +143,22 @@ namespace CoopClient
|
|||||||
|
|
||||||
if (!characterExist)
|
if (!characterExist)
|
||||||
{
|
{
|
||||||
CreateCharacter(username);
|
if (!CreateCharacter(username))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (LastSyncWasFull)
|
else if (LastSyncWasFull)
|
||||||
{
|
{
|
||||||
if (ModelHash != LastModelHash)
|
if (ModelHash != LastModelHash)
|
||||||
{
|
|
||||||
if (characterExist)
|
|
||||||
{
|
{
|
||||||
Character.Kill();
|
Character.Kill();
|
||||||
Character.Delete();
|
Character.Delete();
|
||||||
}
|
|
||||||
|
|
||||||
CreateCharacter(username);
|
if (!CreateCharacter(username))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (Props != LastProps)
|
else if (Props != LastProps)
|
||||||
{
|
{
|
||||||
@ -231,13 +234,15 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void DisplayInVehicle()
|
private void DisplayInVehicle()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model.Hash != VehicleModelHash)
|
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model.Hash != VehicleModelHash)
|
||||||
{
|
{
|
||||||
List<Vehicle> vehs = World.GetNearbyVehicles(Character, 7f, new Model[] { VehicleModelHash }).OrderBy(v => (v.Position - Character.Position).Length()).Take(3).ToList();
|
|
||||||
|
|
||||||
bool vehFound = false;
|
bool vehFound = false;
|
||||||
|
|
||||||
|
List<Vehicle> vehs = World.GetNearbyVehicles(Character, 7f, new Model[] { VehicleModelHash }).OrderBy(v => (v.Position - Character.Position).Length()).Take(3).ToList();
|
||||||
|
|
||||||
foreach (Vehicle veh in vehs)
|
foreach (Vehicle veh in vehs)
|
||||||
{
|
{
|
||||||
if (veh.IsSeatFree((VehicleSeat)VehicleSeatIndex))
|
if (veh.IsSeatFree((VehicleSeat)VehicleSeatIndex))
|
||||||
@ -250,12 +255,25 @@ namespace CoopClient
|
|||||||
|
|
||||||
if (!vehFound)
|
if (!vehFound)
|
||||||
{
|
{
|
||||||
MainVehicle = World.CreateVehicle(new Model(VehicleModelHash), VehiclePosition);
|
Model vehicleModel = Util.ModelRequest(VehicleModelHash);
|
||||||
|
if (vehicleModel == null)
|
||||||
|
{
|
||||||
|
GTA.UI.Notification.Show($"~r~Model ({VehicleModelHash}) cannot be loaded!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle = World.CreateVehicle(vehicleModel, VehiclePosition);
|
||||||
MainVehicle.Quaternion = VehicleRotation;
|
MainVehicle.Quaternion = VehicleRotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
GTA.UI.Notification.Show("~r~" + e.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Character.IsInVehicle() || (int)Character.SeatIndex != VehicleSeatIndex || Character.CurrentVehicle.Model.Hash != VehicleModelHash)
|
if (!Character.IsInVehicle() || (int)Character.SeatIndex != VehicleSeatIndex || Character.CurrentVehicle?.Model.Hash != VehicleModelHash)
|
||||||
{
|
{
|
||||||
if (VehicleSeatIndex == -1 &&
|
if (VehicleSeatIndex == -1 &&
|
||||||
Game.Player.Character.IsInVehicle() &&
|
Game.Player.Character.IsInVehicle() &&
|
||||||
@ -573,12 +591,20 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateCharacter(string username)
|
private bool CreateCharacter(string username)
|
||||||
{
|
{
|
||||||
LastModelHash = ModelHash;
|
LastModelHash = ModelHash;
|
||||||
LastProps = Props;
|
LastProps = Props;
|
||||||
|
|
||||||
Character = World.CreatePed(new Model(ModelHash), Position, Rotation.Z);
|
Model characterModel = Util.ModelRequest(ModelHash);
|
||||||
|
|
||||||
|
if (characterModel == null)
|
||||||
|
{
|
||||||
|
GTA.UI.Notification.Show($"~r~Model ({ModelHash}) cannot be loaded!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Character = World.CreatePed(characterModel, Position, Rotation.Z);
|
||||||
Character.RelationshipGroup = Main.RelationshipGroup;
|
Character.RelationshipGroup = Main.RelationshipGroup;
|
||||||
if (IsInVehicle)
|
if (IsInVehicle)
|
||||||
{
|
{
|
||||||
@ -606,6 +632,8 @@ namespace CoopClient
|
|||||||
{
|
{
|
||||||
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, Character.Handle, prop.Key, prop.Value, 0, 0);
|
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, Character.Handle, prop.Key, prop.Value, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool LastMoving;
|
private bool LastMoving;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
using CoopClient.Entities;
|
using CoopClient.Entities;
|
||||||
using CoopClient.Menus;
|
using CoopClient.Menus;
|
||||||
@ -20,16 +21,18 @@ namespace CoopClient
|
|||||||
public static readonly string CurrentModVersion = "V0_5_0";
|
public static readonly string CurrentModVersion = "V0_5_0";
|
||||||
|
|
||||||
public static bool ShareNpcsWithPlayers = false;
|
public static bool ShareNpcsWithPlayers = false;
|
||||||
|
public static bool DisableTraffic = false;
|
||||||
public static bool NpcsAllowed = false;
|
public static bool NpcsAllowed = false;
|
||||||
private static bool IsGoingToCar = false;
|
private static bool IsGoingToCar = false;
|
||||||
|
|
||||||
public static Settings MainSettings = Util.ReadSettings();
|
public static Settings MainSettings = Util.ReadSettings();
|
||||||
|
|
||||||
public static MenusMain MainMenu = new MenusMain();
|
|
||||||
public static Chat MainChat = new Chat();
|
|
||||||
|
|
||||||
public static Networking MainNetworking = new Networking();
|
public static Networking MainNetworking = new Networking();
|
||||||
|
|
||||||
|
public static MenusMain MainMenu = new MenusMain();
|
||||||
|
|
||||||
|
public static Chat MainChat = new Chat();
|
||||||
|
|
||||||
public static long LocalPlayerID = 0;
|
public static long LocalPlayerID = 0;
|
||||||
public static readonly Dictionary<long, EntitiesPlayer> Players = new Dictionary<long, EntitiesPlayer>();
|
public static readonly Dictionary<long, EntitiesPlayer> Players = new Dictionary<long, EntitiesPlayer>();
|
||||||
public static readonly Dictionary<long, EntitiesNpc> Npcs = new Dictionary<long, EntitiesNpc>();
|
public static readonly Dictionary<long, EntitiesNpc> Npcs = new Dictionary<long, EntitiesNpc>();
|
||||||
@ -73,6 +76,15 @@ namespace CoopClient
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (MainNetworking.ShowNetworkInfo)
|
||||||
|
{
|
||||||
|
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 0), $"L: {MainNetworking.Latency * 1000:N0}ms", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
|
||||||
|
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 30), $"R: {MainNetworking.BytesReceived} bytes", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
|
||||||
|
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 60), $"S: {MainNetworking.BytesSend} bytes", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
MainChat.Tick();
|
MainChat.Tick();
|
||||||
|
|
||||||
// Display all players
|
// Display all players
|
||||||
@ -81,10 +93,12 @@ namespace CoopClient
|
|||||||
player.Value.DisplayLocally(player.Value.Username);
|
player.Value.DisplayLocally(player.Value.Username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
if (UseDebug)
|
if (UseDebug)
|
||||||
{
|
{
|
||||||
Debug();
|
Debug();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((Environment.TickCount - LastDataSend) >= (1000 / 60))
|
if ((Environment.TickCount - LastDataSend) >= (1000 / 60))
|
||||||
{
|
{
|
||||||
@ -156,25 +170,13 @@ namespace CoopClient
|
|||||||
|
|
||||||
private void OnAbort(object sender, EventArgs e)
|
private void OnAbort(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<long, EntitiesPlayer> player in Players)
|
CleanUp();
|
||||||
{
|
|
||||||
player.Value.Character?.AttachedBlip?.Delete();
|
|
||||||
player.Value.Character?.CurrentVehicle?.Delete();
|
|
||||||
player.Value.Character?.Kill();
|
|
||||||
player.Value.Character?.Delete();
|
|
||||||
player.Value.PedBlip?.Delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (KeyValuePair<long, EntitiesNpc> Npc in Npcs)
|
|
||||||
{
|
|
||||||
Npc.Value.Character?.CurrentVehicle?.Delete();
|
|
||||||
Npc.Value.Character?.Kill();
|
|
||||||
Npc.Value.Character?.Delete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CleanUp()
|
public static void CleanUp()
|
||||||
{
|
{
|
||||||
|
MainChat.Clear();
|
||||||
|
|
||||||
foreach (KeyValuePair<long, EntitiesPlayer> player in Players)
|
foreach (KeyValuePair<long, EntitiesPlayer> player in Players)
|
||||||
{
|
{
|
||||||
player.Value.Character?.AttachedBlip?.Delete();
|
player.Value.Character?.AttachedBlip?.Delete();
|
||||||
@ -193,33 +195,15 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
Npcs.Clear();
|
Npcs.Clear();
|
||||||
|
|
||||||
foreach (Ped entity in World.GetAllPeds())
|
foreach (Ped entity in World.GetAllPeds().Where(p => p.Handle != Game.Player.Character.Handle))
|
||||||
{
|
|
||||||
if (entity.Handle != Game.Player.Character.Handle)
|
|
||||||
{
|
{
|
||||||
entity.Kill();
|
entity.Kill();
|
||||||
entity.Delete();
|
entity.Delete();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!Game.Player.Character.IsInVehicle())
|
foreach (Vehicle veh in World.GetAllVehicles().Where(v => v.Handle != Game.Player.Character.Handle))
|
||||||
{
|
{
|
||||||
foreach (Vehicle vehicle in World.GetAllVehicles())
|
veh.Delete();
|
||||||
{
|
|
||||||
vehicle.Delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int? playerVehicleHandle = Game.Player.Character.CurrentVehicle?.Handle;
|
|
||||||
|
|
||||||
foreach (Vehicle vehicle in World.GetAllVehicles())
|
|
||||||
{
|
|
||||||
if (playerVehicleHandle != vehicle.Handle)
|
|
||||||
{
|
|
||||||
vehicle.Delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,25 +10,31 @@ namespace CoopClient.Menus.Sub
|
|||||||
Alignment = Main.MainSettings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
Alignment = Main.MainSettings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private readonly NativeCheckboxItem DisableTraffic = new NativeCheckboxItem("Disable Traffic", Main.DisableTraffic);
|
||||||
private readonly NativeCheckboxItem ShareNpcsItem = new NativeCheckboxItem("Share Npcs", Main.ShareNpcsWithPlayers) { Enabled = false };
|
private readonly NativeCheckboxItem ShareNpcsItem = new NativeCheckboxItem("Share Npcs", Main.ShareNpcsWithPlayers) { Enabled = false };
|
||||||
private readonly NativeSliderItem StreamedNpcsItem = new NativeSliderItem(string.Format("Streamed Npcs ({0})", Main.MainSettings.StreamedNpc), 20, Main.MainSettings.StreamedNpc);
|
private readonly NativeSliderItem StreamedNpcsItem = new NativeSliderItem(string.Format("Streamed Npcs ({0})", Main.MainSettings.StreamedNpc), 20, Main.MainSettings.StreamedNpc);
|
||||||
private readonly NativeCheckboxItem FlipMenuItem = new NativeCheckboxItem("Flip menu", Main.MainSettings.FlipMenu);
|
private readonly NativeCheckboxItem FlipMenuItem = new NativeCheckboxItem("Flip menu", Main.MainSettings.FlipMenu);
|
||||||
private readonly NativeCheckboxItem UseDebugItem = new NativeCheckboxItem("Debug", Main.UseDebug);
|
private readonly NativeCheckboxItem UseDebugItem = new NativeCheckboxItem("Debug", Main.UseDebug);
|
||||||
|
private readonly NativeCheckboxItem ShowNetworkInfo = new NativeCheckboxItem("Show Network Info", Main.MainNetworking.ShowNetworkInfo);
|
||||||
|
|
||||||
public Settings()
|
public Settings()
|
||||||
{
|
{
|
||||||
|
DisableTraffic.CheckboxChanged += DisableTrafficCheckboxChanged;
|
||||||
ShareNpcsItem.CheckboxChanged += (item, check) => { Main.ShareNpcsWithPlayers = ShareNpcsItem.Checked; };
|
ShareNpcsItem.CheckboxChanged += (item, check) => { Main.ShareNpcsWithPlayers = ShareNpcsItem.Checked; };
|
||||||
StreamedNpcsItem.ValueChanged += StreamedNpcsValueChanged;
|
StreamedNpcsItem.ValueChanged += StreamedNpcsValueChanged;
|
||||||
FlipMenuItem.CheckboxChanged += FlipMenuCheckboxChanged;
|
FlipMenuItem.CheckboxChanged += FlipMenuCheckboxChanged;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
UseDebugItem.CheckboxChanged += UseDebugCheckboxChanged;
|
UseDebugItem.CheckboxChanged += UseDebugCheckboxChanged;
|
||||||
|
ShowNetworkInfo.CheckboxChanged += ShowNetworkInfoCheckboxChanged;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
MainMenu.Add(DisableTraffic);
|
||||||
MainMenu.Add(ShareNpcsItem);
|
MainMenu.Add(ShareNpcsItem);
|
||||||
MainMenu.Add(StreamedNpcsItem);
|
MainMenu.Add(StreamedNpcsItem);
|
||||||
MainMenu.Add(FlipMenuItem);
|
MainMenu.Add(FlipMenuItem);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
MainMenu.Add(UseDebugItem);
|
MainMenu.Add(UseDebugItem);
|
||||||
|
MainMenu.Add(ShowNetworkInfo);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,5 +71,35 @@ namespace CoopClient.Menus.Sub
|
|||||||
Main.Players.Remove(0);
|
Main.Players.Remove(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b)
|
||||||
|
{
|
||||||
|
Main.MainNetworking.ShowNetworkInfo = ShowNetworkInfo.Checked;
|
||||||
|
|
||||||
|
if (!Main.MainNetworking.ShowNetworkInfo)
|
||||||
|
{
|
||||||
|
Main.MainNetworking.BytesReceived = 0;
|
||||||
|
Main.MainNetworking.BytesSend = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||||
|
{
|
||||||
|
Main.DisableTraffic = DisableTraffic.Checked;
|
||||||
|
|
||||||
|
if (DisableTraffic.Checked)
|
||||||
|
{
|
||||||
|
if (ShareNpcsItem.Checked)
|
||||||
|
{
|
||||||
|
ShareNpcsItem.Checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShareNpcsItem.Enabled = false;
|
||||||
|
}
|
||||||
|
else if (Main.NpcsAllowed && !ShareNpcsItem.Enabled)
|
||||||
|
{
|
||||||
|
ShareNpcsItem.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,11 @@ namespace CoopClient
|
|||||||
public NetClient Client;
|
public NetClient Client;
|
||||||
public float Latency;
|
public float Latency;
|
||||||
|
|
||||||
|
public bool ShowNetworkInfo = false;
|
||||||
|
|
||||||
|
public int BytesReceived = 0;
|
||||||
|
public int BytesSend = 0;
|
||||||
|
|
||||||
public void DisConnectFromServer(string address)
|
public void DisConnectFromServer(string address)
|
||||||
{
|
{
|
||||||
if (IsOnServer())
|
if (IsOnServer())
|
||||||
@ -72,6 +77,8 @@ namespace CoopClient
|
|||||||
|
|
||||||
while ((message = Client.ReadMessage()) != null)
|
while ((message = Client.ReadMessage()) != null)
|
||||||
{
|
{
|
||||||
|
BytesReceived += message.LengthBytes;
|
||||||
|
|
||||||
switch (message.MessageType)
|
switch (message.MessageType)
|
||||||
{
|
{
|
||||||
case NetIncomingMessageType.StatusChanged:
|
case NetIncomingMessageType.StatusChanged:
|
||||||
@ -125,7 +132,7 @@ namespace CoopClient
|
|||||||
|
|
||||||
Main.MainMenu.MainMenu.Items[2].Enabled = true;
|
Main.MainMenu.MainMenu.Items[2].Enabled = true;
|
||||||
Main.MainMenu.MainMenu.Items[2].Title = "Disconnect";
|
Main.MainMenu.MainMenu.Items[2].Title = "Disconnect";
|
||||||
Main.MainMenu.SubSettings.MainMenu.Items[0].Enabled = Main.NpcsAllowed;
|
Main.MainMenu.SubSettings.MainMenu.Items[1].Enabled = !Main.DisableTraffic && Main.NpcsAllowed;
|
||||||
|
|
||||||
Main.MainMenu.MainMenu.Visible = false;
|
Main.MainMenu.MainMenu.Visible = false;
|
||||||
Main.MainMenu.MenuPool.RefreshAll();
|
Main.MainMenu.MenuPool.RefreshAll();
|
||||||
@ -144,15 +151,13 @@ namespace CoopClient
|
|||||||
Main.MainChat.Focused = false;
|
Main.MainChat.Focused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Main.MainChat.Clear();
|
|
||||||
|
|
||||||
Main.CleanUp();
|
Main.CleanUp();
|
||||||
|
|
||||||
Main.MainMenu.MainMenu.Items[0].Enabled = true;
|
Main.MainMenu.MainMenu.Items[0].Enabled = true;
|
||||||
Main.MainMenu.MainMenu.Items[1].Enabled = true;
|
Main.MainMenu.MainMenu.Items[1].Enabled = true;
|
||||||
Main.MainMenu.MainMenu.Items[2].Enabled = true;
|
Main.MainMenu.MainMenu.Items[2].Enabled = true;
|
||||||
Main.MainMenu.MainMenu.Items[2].Title = "Connect";
|
Main.MainMenu.MainMenu.Items[2].Title = "Connect";
|
||||||
Main.MainMenu.SubSettings.MainMenu.Items[0].Enabled = false;
|
Main.MainMenu.SubSettings.MainMenu.Items[1].Enabled = false;
|
||||||
|
|
||||||
Main.MainMenu.MenuPool.RefreshAll();
|
Main.MainMenu.MenuPool.RefreshAll();
|
||||||
break;
|
break;
|
||||||
@ -654,6 +659,13 @@ namespace CoopClient
|
|||||||
|
|
||||||
Client.SendMessage(outgoingMessage, messageType);
|
Client.SendMessage(outgoingMessage, messageType);
|
||||||
Client.FlushSendQueue();
|
Client.FlushSendQueue();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (ShowNetworkInfo)
|
||||||
|
{
|
||||||
|
BytesSend += outgoingMessage.LengthBytes;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendNpcData(Ped npc)
|
public void SendNpcData(Ped npc)
|
||||||
@ -710,6 +722,13 @@ namespace CoopClient
|
|||||||
|
|
||||||
Client.SendMessage(outgoingMessage, NetDeliveryMethod.Unreliable);
|
Client.SendMessage(outgoingMessage, NetDeliveryMethod.Unreliable);
|
||||||
Client.FlushSendQueue();
|
Client.FlushSendQueue();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (ShowNetworkInfo)
|
||||||
|
{
|
||||||
|
BytesSend += outgoingMessage.LengthBytes;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendChatMessage(string message)
|
public void SendChatMessage(string message)
|
||||||
@ -722,6 +741,13 @@ namespace CoopClient
|
|||||||
}.PacketToNetOutGoingMessage(outgoingMessage);
|
}.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered);
|
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered);
|
||||||
Client.FlushSendQueue();
|
Client.FlushSendQueue();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (ShowNetworkInfo)
|
||||||
|
{
|
||||||
|
BytesSend += outgoingMessage.LengthBytes;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,26 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public static Model ModelRequest(int hash)
|
||||||
|
{
|
||||||
|
Model model = new Model(hash);
|
||||||
|
short counter = 0;
|
||||||
|
|
||||||
|
while (counter++ < 1000)
|
||||||
|
{
|
||||||
|
model.Request();
|
||||||
|
|
||||||
|
Script.Yield();
|
||||||
|
|
||||||
|
if (model.IsLoaded)
|
||||||
|
{
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsBetween<T>(this T item, T start, T end)
|
public static bool IsBetween<T>(this T item, T start, T end)
|
||||||
{
|
{
|
||||||
return Comparer<T>.Default.Compare(item, start) >= 0 && Comparer<T>.Default.Compare(item, end) <= 0;
|
return Comparer<T>.Default.Compare(item, start) >= 0 && Comparer<T>.Default.Compare(item, end) <= 0;
|
||||||
@ -438,7 +458,7 @@ namespace CoopClient
|
|||||||
dir.Normalize();
|
dir.Normalize();
|
||||||
RaycastResult raycastResults = World.Raycast(source3D + dir * raycastFromDist,
|
RaycastResult raycastResults = World.Raycast(source3D + dir * raycastFromDist,
|
||||||
source3D + dir * raycastToDist,
|
source3D + dir * raycastToDist,
|
||||||
(IntersectFlags)(1 | 16 | 256 | 2 | 4 | 8), // | peds + vehicles
|
IntersectFlags.Everything,
|
||||||
ignoreEntity);
|
ignoreEntity);
|
||||||
|
|
||||||
if (raycastResults.DidHit)
|
if (raycastResults.DidHit)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
@ -7,10 +8,19 @@ namespace CoopClient
|
|||||||
{
|
{
|
||||||
public class WorldThread : Script
|
public class WorldThread : Script
|
||||||
{
|
{
|
||||||
|
private static bool LastDisableTraffic = false;
|
||||||
|
|
||||||
public WorldThread()
|
public WorldThread()
|
||||||
{
|
{
|
||||||
Tick += OnTick;
|
Tick += OnTick;
|
||||||
Interval = 1000 / 60;
|
Interval = 1000 / 60;
|
||||||
|
Aborted += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (LastDisableTraffic)
|
||||||
|
{
|
||||||
|
Traffic(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnTick(object sender, EventArgs e)
|
public static void OnTick(object sender, EventArgs e)
|
||||||
@ -24,6 +34,75 @@ namespace CoopClient
|
|||||||
|
|
||||||
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Game.Player.Character.Handle, true, false);
|
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Game.Player.Character.Handle, true, false);
|
||||||
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED, Game.Player.Character.Handle, true);
|
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED, Game.Player.Character.Handle, true);
|
||||||
|
|
||||||
|
if (Main.DisableTraffic)
|
||||||
|
{
|
||||||
|
if (!LastDisableTraffic)
|
||||||
|
{
|
||||||
|
Traffic(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
|
||||||
|
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||||
|
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||||
|
Function.Call(Hash.SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||||
|
Function.Call(Hash.SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||||
|
Function.Call((Hash)0x2F9A292AD0A3BD89);
|
||||||
|
Function.Call((Hash)0x5F3B7749C112D552);
|
||||||
|
}
|
||||||
|
else if (LastDisableTraffic)
|
||||||
|
{
|
||||||
|
Traffic(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastDisableTraffic = Main.DisableTraffic;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Traffic(bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.REMOVE_SCENARIO_BLOCKING_AREAS);
|
||||||
|
Function.Call(Hash.SET_CREATE_RANDOM_COPS, true);
|
||||||
|
Function.Call(Hash.SET_RANDOM_TRAINS, true);
|
||||||
|
Function.Call(Hash.SET_RANDOM_BOATS, true);
|
||||||
|
Function.Call(Hash.SET_GARBAGE_TRUCKS, true);
|
||||||
|
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3); // 0 - 3
|
||||||
|
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3); // 0 - 3
|
||||||
|
Function.Call(Hash.SET_ALL_VEHICLE_GENERATORS_ACTIVE);
|
||||||
|
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, true);
|
||||||
|
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, -1);
|
||||||
|
Function.Call((Hash)0xF796359A959DF65D, true); // Display distant vehicles
|
||||||
|
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Function.Call(Hash.ADD_SCENARIO_BLOCKING_AREA, -10000.0f, -10000.0f, -1000.0f, 10000.0f, 10000.0f, 1000.0f, 0, 1, 1, 1);
|
||||||
|
Function.Call(Hash.SET_CREATE_RANDOM_COPS, false);
|
||||||
|
Function.Call(Hash.SET_RANDOM_TRAINS, false);
|
||||||
|
Function.Call(Hash.SET_RANDOM_BOATS, false);
|
||||||
|
Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
|
||||||
|
Function.Call(Hash.DELETE_ALL_TRAINS);
|
||||||
|
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||||
|
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
|
||||||
|
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
|
||||||
|
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
|
||||||
|
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
|
||||||
|
Function.Call((Hash)0xF796359A959DF65D, false); //Display distant vehicles
|
||||||
|
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, true);
|
||||||
|
|
||||||
|
foreach (Ped ped in World.GetAllPeds().Where(p => p.RelationshipGroup != "SYNCPED"))
|
||||||
|
{
|
||||||
|
ped.CurrentVehicle?.Delete();
|
||||||
|
ped.Kill();
|
||||||
|
ped.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Vehicle veh in World.GetAllVehicles().Where(v => v.IsSeatFree(VehicleSeat.Driver) && v.PassengerCount == 0))
|
||||||
|
{
|
||||||
|
veh.Delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
FirstGameMod/FirstGameMode.sln
Normal file
25
FirstGameMod/FirstGameMode.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.31605.320
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FirstGameMode", "FirstGameMode\FirstGameMode.csproj", "{212B1A61-0C03-4B0E-A53C-2CC6B667E0DA}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{212B1A61-0C03-4B0E-A53C-2CC6B667E0DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{212B1A61-0C03-4B0E-A53C-2CC6B667E0DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{212B1A61-0C03-4B0E-A53C-2CC6B667E0DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{212B1A61-0C03-4B0E-A53C-2CC6B667E0DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {3C329584-BE48-469B-85D8-FD24F47BD033}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
46
FirstGameMod/FirstGameMode/Commands.cs
Normal file
46
FirstGameMod/FirstGameMode/Commands.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using CoopServer;
|
||||||
|
|
||||||
|
namespace FirstGameMode
|
||||||
|
{
|
||||||
|
class Commands
|
||||||
|
{
|
||||||
|
[Command("hello")]
|
||||||
|
public static void HelloCommand(CommandContext ctx)
|
||||||
|
{
|
||||||
|
ServerScript.SendChatMessageToPlayer(ctx.Player.Username, "Hello " + ctx.Player.Username + " :)");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("inrange")]
|
||||||
|
public static void InRangeCommand(CommandContext ctx)
|
||||||
|
{
|
||||||
|
if (ctx.Player.Ped.IsInRangeOf(new LVector3(0f, 0f, 75f), 7f))
|
||||||
|
{
|
||||||
|
ServerScript.SendChatMessageToPlayer(ctx.Player.Username, "You are in range! :)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ServerScript.SendChatMessageToPlayer(ctx.Player.Username, "You are not in range! :(");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("online")]
|
||||||
|
public static void OnlineCommand(CommandContext ctx)
|
||||||
|
{
|
||||||
|
ServerScript.SendChatMessageToPlayer(ctx.Player.Username, ServerScript.GetAllPlayersCount() + " player online!");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("kick")]
|
||||||
|
public static void KickCommand(CommandContext ctx)
|
||||||
|
{
|
||||||
|
if (ctx.Args.Length < 2)
|
||||||
|
{
|
||||||
|
ServerScript.SendChatMessageToPlayer(ctx.Player.Username, "Please use \"/kick <USERNAME> <REASON>\"");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerScript.KickPlayerByUsername(ctx.Args[0], ctx.Args.Skip(1).ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
FirstGameMod/FirstGameMode/FirstGameMode.csproj
Normal file
13
FirstGameMod/FirstGameMode/FirstGameMode.csproj
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="CoopServer">
|
||||||
|
<HintPath>..\..\Server\bin\Debug\net5.0\CoopServer.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
47
FirstGameMod/FirstGameMode/Main.cs
Normal file
47
FirstGameMod/FirstGameMode/Main.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using CoopServer;
|
||||||
|
using CoopServer.Entities;
|
||||||
|
using System.Timers;
|
||||||
|
|
||||||
|
namespace FirstGameMode
|
||||||
|
{
|
||||||
|
public class Main : ServerScript
|
||||||
|
{
|
||||||
|
private static readonly Timer RunningSinceTimer = new() { Interval = 1000 };
|
||||||
|
private static int RunningSince = 0;
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
RunningSinceTimer.Start();
|
||||||
|
RunningSinceTimer.Elapsed += new ElapsedEventHandler((sender, e) => RunningSince += 1);
|
||||||
|
|
||||||
|
RegisterCommand("running", RunningCommand);
|
||||||
|
RegisterCommands<Commands>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RunningCommand(CommandContext ctx)
|
||||||
|
{
|
||||||
|
SendChatMessageToPlayer(ctx.Player.Username, "Server has been running for: " + RunningSince + " seconds!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnPlayerConnect(EntitiesPlayer client)
|
||||||
|
{
|
||||||
|
SendChatMessageToAll("Player " + client.Username + " connected!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnPlayerDisconnect(EntitiesPlayer player, string reason)
|
||||||
|
{
|
||||||
|
SendChatMessageToAll(player.Username + " left the server, reason: " + reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnChatMessage(string username, string message)
|
||||||
|
{
|
||||||
|
if (message.StartsWith("EASTEREGG"))
|
||||||
|
{
|
||||||
|
SendChatMessageToPlayer(username, "You found the EASTEREGG! *-*");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
Server/Server.cs
114
Server/Server.cs
@ -32,6 +32,7 @@ namespace CoopServer
|
|||||||
public static readonly Dictionary<long, EntitiesPlayer> Players = new();
|
public static readonly Dictionary<long, EntitiesPlayer> Players = new();
|
||||||
|
|
||||||
private static ServerScript GameMode;
|
private static ServerScript GameMode;
|
||||||
|
public static readonly Dictionary<Command, Action<CommandContext>> Commands = new Dictionary<Command, Action<CommandContext>>();
|
||||||
|
|
||||||
public Server()
|
public Server()
|
||||||
{
|
{
|
||||||
@ -127,12 +128,7 @@ namespace CoopServer
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MainSettings.DefaultGameMode)
|
if (!string.IsNullOrEmpty(MainSettings.GameMode))
|
||||||
{
|
|
||||||
GameMode = new DefaultScript();
|
|
||||||
GameMode.Start();
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrEmpty(MainSettings.GameMode))
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -381,27 +377,6 @@ namespace CoopServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a list of all connections but not the local connection
|
|
||||||
private static List<NetConnection> FilterAllLocal(NetConnection local)
|
|
||||||
{
|
|
||||||
return new(MainNetServer.Connections.Where(e => e != local));
|
|
||||||
}
|
|
||||||
private static List<NetConnection> FilterAllLocal(long local)
|
|
||||||
{
|
|
||||||
return new(MainNetServer.Connections.Where(e => e.RemoteUniqueIdentifier != local));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a list of players within range of ...
|
|
||||||
private static List<NetConnection> GetAllInRange(LVector3 position, float range)
|
|
||||||
{
|
|
||||||
return new(MainNetServer.Connections.FindAll(e => Players[e.RemoteUniqueIdentifier].Ped.IsInRangeOf(position, range)));
|
|
||||||
}
|
|
||||||
// Return a list of players within range of ... but not the local one
|
|
||||||
private static List<NetConnection> GetAllInRange(LVector3 position, float range, NetConnection local)
|
|
||||||
{
|
|
||||||
return new(MainNetServer.Connections.Where(e => e != local && Players[e.RemoteUniqueIdentifier].Ped.IsInRangeOf(position, range)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#region -- PLAYER --
|
#region -- PLAYER --
|
||||||
// Before we approve the connection, we must shake hands
|
// Before we approve the connection, we must shake hands
|
||||||
private void GetHandshake(NetConnection local, HandshakePacket packet)
|
private void GetHandshake(NetConnection local, HandshakePacket packet)
|
||||||
@ -504,7 +479,7 @@ namespace CoopServer
|
|||||||
GameMode.OnPlayerConnect(Players[packet.Player]);
|
GameMode.OnPlayerConnect(Players[packet.Player]);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<NetConnection> playerList = FilterAllLocal(local);
|
List<NetConnection> playerList = Util.FilterAllLocal(local);
|
||||||
if (playerList.Count == 0)
|
if (playerList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -546,7 +521,7 @@ namespace CoopServer
|
|||||||
GameMode.OnPlayerDisconnect(Players[packet.Player], reason);
|
GameMode.OnPlayerDisconnect(Players[packet.Player], reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<NetConnection> playerList = FilterAllLocal(packet.Player);
|
List<NetConnection> playerList = Util.FilterAllLocal(packet.Player);
|
||||||
if (playerList.Count != 0)
|
if (playerList.Count != 0)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||||
@ -563,7 +538,7 @@ namespace CoopServer
|
|||||||
|
|
||||||
player.Ped.Position = packet.Extra.Position;
|
player.Ped.Position = packet.Extra.Position;
|
||||||
|
|
||||||
List<NetConnection> playerList = FilterAllLocal(packet.Extra.Player);
|
List<NetConnection> playerList = Util.FilterAllLocal(packet.Extra.Player);
|
||||||
if (playerList.Count == 0)
|
if (playerList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -585,7 +560,7 @@ namespace CoopServer
|
|||||||
|
|
||||||
player.Ped.Position = packet.Extra.Position;
|
player.Ped.Position = packet.Extra.Position;
|
||||||
|
|
||||||
List<NetConnection> playerList = FilterAllLocal(packet.Extra.Player);
|
List<NetConnection> playerList = Util.FilterAllLocal(packet.Extra.Player);
|
||||||
if (playerList.Count == 0)
|
if (playerList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -607,7 +582,7 @@ namespace CoopServer
|
|||||||
|
|
||||||
player.Ped.Position = packet.Extra.Position;
|
player.Ped.Position = packet.Extra.Position;
|
||||||
|
|
||||||
List<NetConnection> playerList = FilterAllLocal(packet.Extra.Player);
|
List<NetConnection> playerList = Util.FilterAllLocal(packet.Extra.Player);
|
||||||
if (playerList.Count == 0)
|
if (playerList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -629,7 +604,7 @@ namespace CoopServer
|
|||||||
|
|
||||||
player.Ped.Position = packet.Extra.Position;
|
player.Ped.Position = packet.Extra.Position;
|
||||||
|
|
||||||
List<NetConnection> playerList = FilterAllLocal(packet.Extra.Player);
|
List<NetConnection> playerList = Util.FilterAllLocal(packet.Extra.Player);
|
||||||
if (playerList.Count == 0)
|
if (playerList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -648,25 +623,62 @@ namespace CoopServer
|
|||||||
// Send a message to targets or all players
|
// Send a message to targets or all players
|
||||||
private static void SendChatMessage(ChatMessagePacket packet, List<NetConnection> targets = null)
|
private static void SendChatMessage(ChatMessagePacket packet, List<NetConnection> targets = null)
|
||||||
{
|
{
|
||||||
if (GameMode != null && GameMode.OnChatMessage(packet.Username, packet.Message))
|
NetOutgoingMessage outgoingMessage;
|
||||||
|
|
||||||
|
if (GameMode != null)
|
||||||
|
{
|
||||||
|
if (packet.Message.StartsWith("/"))
|
||||||
|
{
|
||||||
|
string[] cmdArgs = packet.Message.Split(" ");
|
||||||
|
string cmdName = cmdArgs[0].Remove(0, 1);
|
||||||
|
if (Commands.Any(x => x.Key.Name == cmdName))
|
||||||
|
{
|
||||||
|
CommandContext ctx = new()
|
||||||
|
{
|
||||||
|
Player = Players.First(x => x.Value.Username == packet.Username).Value,
|
||||||
|
Args = cmdArgs.Skip(1).ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyValuePair<Command, Action<CommandContext>> command = Commands.First(x => x.Key.Name == cmdName);
|
||||||
|
command.Value.Invoke(ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string username = packet.Username;
|
||||||
|
|
||||||
|
packet = new()
|
||||||
|
{
|
||||||
|
Username = "Server",
|
||||||
|
Message = "Command not found!"
|
||||||
|
};
|
||||||
|
|
||||||
|
outgoingMessage = MainNetServer.CreateMessage();
|
||||||
|
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
|
MainNetServer.SendMessage(outgoingMessage, MainNetServer.Connections.Find(con => con.RemoteUniqueIdentifier == Players.First(x => x.Value.Username == username).Key), NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (GameMode.OnChatMessage(packet.Username, packet.Message))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
packet.Message = packet.Message.Replace("~", "");
|
packet.Message = packet.Message.Replace("~", "");
|
||||||
|
|
||||||
Logging.Info(packet.Username + ": " + packet.Message);
|
outgoingMessage = MainNetServer.CreateMessage();
|
||||||
|
|
||||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
|
||||||
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
MainNetServer.SendMessage(outgoingMessage, targets ?? MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
|
MainNetServer.SendMessage(outgoingMessage, targets ?? MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
|
|
||||||
|
Logging.Info(packet.Username + ": " + packet.Message);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region -- NPC --
|
#region -- NPC --
|
||||||
private static void FullSyncNpc(NetConnection local, FullSyncNpcPacket packet)
|
private static void FullSyncNpc(NetConnection local, FullSyncNpcPacket packet)
|
||||||
{
|
{
|
||||||
List<NetConnection> playerList = GetAllInRange(packet.Position, 300f, local);
|
List<NetConnection> playerList = Util.GetAllInRange(packet.Position, 300f, local);
|
||||||
if (playerList.Count == 0)
|
if (playerList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -679,7 +691,7 @@ namespace CoopServer
|
|||||||
|
|
||||||
private static void FullSyncNpcVeh(NetConnection local, FullSyncNpcVehPacket packet)
|
private static void FullSyncNpcVeh(NetConnection local, FullSyncNpcVehPacket packet)
|
||||||
{
|
{
|
||||||
List<NetConnection> playerList = GetAllInRange(packet.Position, 300f, local);
|
List<NetConnection> playerList = Util.GetAllInRange(packet.Position, 300f, local);
|
||||||
if (playerList.Count == 0)
|
if (playerList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -690,5 +702,29 @@ namespace CoopServer
|
|||||||
MainNetServer.SendMessage(outgoingMessage, playerList, NetDeliveryMethod.UnreliableSequenced, 0);
|
MainNetServer.SendMessage(outgoingMessage, playerList, NetDeliveryMethod.UnreliableSequenced, 0);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public static void RegisterCommand(string name, Action<CommandContext> callback)
|
||||||
|
{
|
||||||
|
Command command = new() { Name = name };
|
||||||
|
|
||||||
|
if (Commands.ContainsKey(command))
|
||||||
|
{
|
||||||
|
throw new Exception("Command \"" + command.Name + "\" was already been registered!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Commands.Add(command, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterCommands<T>()
|
||||||
|
{
|
||||||
|
IEnumerable<MethodInfo> commands = typeof(T).GetMethods().Where(method => method.GetCustomAttributes(typeof(CommandAttribute), false).Any());
|
||||||
|
|
||||||
|
foreach (MethodInfo method in commands)
|
||||||
|
{
|
||||||
|
CommandAttribute attribute = method.GetCustomAttribute<CommandAttribute>(true);
|
||||||
|
|
||||||
|
RegisterCommand(attribute.Name, (Action<CommandContext>)Delegate.CreateDelegate(typeof(Action<CommandContext>), method));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,100 +5,9 @@ using Lidgren.Network;
|
|||||||
|
|
||||||
namespace CoopServer
|
namespace CoopServer
|
||||||
{
|
{
|
||||||
class DefaultScript : ServerScript
|
|
||||||
{
|
|
||||||
private List<string> Admins = new();
|
|
||||||
private string AdminPassword = "test123";
|
|
||||||
|
|
||||||
public override void OnPlayerConnect(Entities.EntitiesPlayer client)
|
|
||||||
{
|
|
||||||
SendChatMessageToAll("Say hello to " + client.Username);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPlayerDisconnect(Entities.EntitiesPlayer player, string reason)
|
|
||||||
{
|
|
||||||
Logging.Info(player.Username + " left the server, reason: " + reason);
|
|
||||||
|
|
||||||
if (Admins.Contains(player.Username))
|
|
||||||
{
|
|
||||||
Admins.Remove(player.Username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnChatMessage(string username, string message)
|
|
||||||
{
|
|
||||||
if (!message.StartsWith("/"))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] messageSplitted = message.Split(" ");
|
|
||||||
int messageSplittedLength = messageSplitted.Length;
|
|
||||||
|
|
||||||
if (messageSplittedLength == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Admins.Contains(username))
|
|
||||||
{
|
|
||||||
if (messageSplitted[0] != "/rcon")
|
|
||||||
{
|
|
||||||
SendChatMessageToPlayer(username, "Please login with \"/rcon <PASSWORD>\"!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageSplitted.Length < 2)
|
|
||||||
{
|
|
||||||
SendChatMessageToPlayer(username, "Password missing!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageSplitted[1] != AdminPassword)
|
|
||||||
{
|
|
||||||
SendChatMessageToPlayer(username, "Wrong password!");
|
|
||||||
Logging.Warning("Player [" + username + "] tried to login rcon with [" + messageSplitted[1] + "]");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Admins.Add(username);
|
|
||||||
|
|
||||||
SendChatMessageToPlayer(username, "Login successfully!");
|
|
||||||
Logging.Info("Login successfully! [RCON][" + username + "]");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messageSplitted[0] == "/kick")
|
|
||||||
{
|
|
||||||
if (messageSplittedLength < 3)
|
|
||||||
{
|
|
||||||
SendChatMessageToPlayer(username, "Please use \"/kick <USERNAME> <REASON>\"");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
KickPlayerByUsername(messageSplitted[1], messageSplittedLength >= 3 ? messageSplitted[2] : "Kicked by " + username + "!");
|
|
||||||
SendChatMessageToPlayer(username, "Player [" + messageSplitted[1] + "] kicked!");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
SendChatMessageToPlayer(username, e.Message);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SendChatMessageToPlayer(username, "Command \"" + messageSplitted[0] + "\" not found!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ServerScript
|
public class ServerScript
|
||||||
{
|
{
|
||||||
public virtual void Start()
|
public virtual void Start() { }
|
||||||
{
|
|
||||||
Logging.Info("Gamemode loaded successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void OnPlayerConnect(Entities.EntitiesPlayer player)
|
public virtual void OnPlayerConnect(Entities.EntitiesPlayer player)
|
||||||
{
|
{
|
||||||
@ -110,41 +19,59 @@ namespace CoopServer
|
|||||||
Logging.Info(player.Username + " left the server, reason: " + reason);
|
Logging.Info(player.Username + " left the server, reason: " + reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool OnChatMessage(string username, string message) { return false; }
|
public virtual bool OnChatMessage(string username, string message)
|
||||||
|
|
||||||
protected static List<string> GetAllConnections()
|
|
||||||
{
|
{
|
||||||
List<string> result = new();
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<long> GetAllConnections()
|
||||||
|
{
|
||||||
|
List<long> result = new();
|
||||||
|
|
||||||
lock (Server.MainNetServer.Connections)
|
lock (Server.MainNetServer.Connections)
|
||||||
{
|
{
|
||||||
Server.MainNetServer.Connections.ForEach(con => result.Add(NetUtility.ToHexString(con.RemoteUniqueIdentifier)));
|
Server.MainNetServer.Connections.ForEach(x => result.Add(x.RemoteUniqueIdentifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int GetAllPlayersCount() { lock (Server.Players) return Server.Players.Count; }
|
public static int GetAllPlayersCount()
|
||||||
protected static Dictionary<long, Entities.EntitiesPlayer> GetAllPlayers() { lock (Server.Players) return Server.Players; }
|
|
||||||
|
|
||||||
protected static void KickPlayerByUsername(string username, string reason)
|
|
||||||
{
|
{
|
||||||
lock (Server.Players)
|
lock (Server.Players)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<long, Entities.EntitiesPlayer> player in Server.Players)
|
return Server.Players.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<long, Entities.EntitiesPlayer> GetAllPlayers()
|
||||||
{
|
{
|
||||||
if (player.Value.Username == username)
|
lock (Server.Players)
|
||||||
{
|
{
|
||||||
Server.MainNetServer.Connections.Find(e => e.RemoteUniqueIdentifier == player.Key).Disconnect(reason);
|
return Server.Players;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void KickPlayerByUsername(string username, string[] reason)
|
||||||
|
{
|
||||||
|
lock (Server.MainNetServer.Connections)
|
||||||
|
{
|
||||||
|
NetConnection userConnection = Util.GetConnectionByUsername(username);
|
||||||
|
if (userConnection == null)
|
||||||
|
{
|
||||||
|
Logging.Warning("[ServerScript->KickPlayerByUsername(\"" + username + "\", \"" + string.Join(" ", reason) + "\")]: User not found!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userConnection.Disconnect(string.Join(" ", reason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception("Player [" + username + "] not found!");
|
public static void SendChatMessageToAll(string message, string username = "Server")
|
||||||
}
|
{
|
||||||
|
List<NetConnection> connections = Server.MainNetServer.Connections;
|
||||||
|
|
||||||
protected static void SendChatMessageToAll(string message, string username = "Server")
|
if (connections.Count != 0)
|
||||||
{
|
{
|
||||||
ChatMessagePacket packet = new()
|
ChatMessagePacket packet = new()
|
||||||
{
|
{
|
||||||
@ -152,36 +79,79 @@ namespace CoopServer
|
|||||||
Message = message
|
Message = message
|
||||||
};
|
};
|
||||||
|
|
||||||
Logging.Info(username + ": " + packet.Message);
|
|
||||||
|
|
||||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||||
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
|
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void SendChatMessageToPlayer(string username, string message, string from = "Server")
|
Logging.Info(username + ": " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendChatMessageToPlayer(string username, string message, string from = "Server")
|
||||||
{
|
{
|
||||||
lock (Server.Players)
|
lock (Server.MainNetServer.Connections)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<long, Entities.EntitiesPlayer> player in Server.Players)
|
NetConnection userConnection = Util.GetConnectionByUsername(username);
|
||||||
{
|
if (userConnection == null)
|
||||||
if (player.Value.Username == username)
|
|
||||||
{
|
{
|
||||||
|
Logging.Warning("[ServerScript->SendChatMessageToPlayer(\"" + username + "\", \"" + message + "\", \"" + from + "\")]: User not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatMessagePacket packet = new()
|
ChatMessagePacket packet = new()
|
||||||
{
|
{
|
||||||
Username = from,
|
Username = from,
|
||||||
Message = message
|
Message = message
|
||||||
};
|
};
|
||||||
|
|
||||||
Logging.Info(from + ": " + packet.Message);
|
|
||||||
|
|
||||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||||
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
packet.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections.Find(con => con.RemoteUniqueIdentifier == player.Key), NetDeliveryMethod.ReliableOrdered, 0);
|
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
Logging.Info(from + ": " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterCommand(string name, Action<CommandContext> callback)
|
||||||
|
{
|
||||||
|
Server.RegisterCommand(name, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterCommands<T>()
|
||||||
|
{
|
||||||
|
Server.RegisterCommands<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Command
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
public class CommandAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sets name of the command
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public CommandAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CommandContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the client which executed the command
|
||||||
|
/// </summary>
|
||||||
|
public Entities.EntitiesPlayer Player { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the chatdata associated with the command
|
||||||
|
/// </summary>
|
||||||
|
public string[] Args { get; internal set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
public int MaxPlayers { get; set; } = 16;
|
public int MaxPlayers { get; set; } = 16;
|
||||||
public string ServerName { get; set; } = "GTACoop:R server";
|
public string ServerName { get; set; } = "GTACoop:R server";
|
||||||
public string WelcomeMessage { get; set; } = "Welcome on this server :)";
|
public string WelcomeMessage { get; set; } = "Welcome on this server :)";
|
||||||
public bool DefaultGameMode { get; set; } = true;
|
|
||||||
public string GameMode { get; set; } = "";
|
public string GameMode { get; set; } = "";
|
||||||
public bool Allowlist { get; set; } = false;
|
public bool Allowlist { get; set; } = false;
|
||||||
public bool NpcsAllowed { get; set; } = true;
|
public bool NpcsAllowed { get; set; } = true;
|
||||||
|
@ -1,11 +1,52 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
namespace CoopServer
|
namespace CoopServer
|
||||||
{
|
{
|
||||||
class Util
|
class Util
|
||||||
{
|
{
|
||||||
|
public static NetConnection GetConnectionByUsername(string username)
|
||||||
|
{
|
||||||
|
long? userID = GetIdByUsername(username);
|
||||||
|
if (userID == null || !Server.MainNetServer.Connections.Any(x => x.RemoteUniqueIdentifier == userID))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Server.MainNetServer.Connections.First(x => x.RemoteUniqueIdentifier == userID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long? GetIdByUsername(string username)
|
||||||
|
{
|
||||||
|
return Server.Players.Any(x => x.Value.Username == username) ? Server.Players.First(x => x.Value.Username == username).Key : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a list of all connections but not the local connection
|
||||||
|
public static List<NetConnection> FilterAllLocal(NetConnection local)
|
||||||
|
{
|
||||||
|
return new(Server.MainNetServer.Connections.Where(e => e != local));
|
||||||
|
}
|
||||||
|
public static List<NetConnection> FilterAllLocal(long local)
|
||||||
|
{
|
||||||
|
return new(Server.MainNetServer.Connections.Where(e => e.RemoteUniqueIdentifier != local));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a list of players within range of ...
|
||||||
|
public static List<NetConnection> GetAllInRange(LVector3 position, float range)
|
||||||
|
{
|
||||||
|
return new(Server.MainNetServer.Connections.FindAll(e => Server.Players[e.RemoteUniqueIdentifier].Ped.IsInRangeOf(position, range)));
|
||||||
|
}
|
||||||
|
// Return a list of players within range of ... but not the local one
|
||||||
|
public static List<NetConnection> GetAllInRange(LVector3 position, float range, NetConnection local)
|
||||||
|
{
|
||||||
|
return new(Server.MainNetServer.Connections.Where(e => e != local && Server.Players[e.RemoteUniqueIdentifier].Ped.IsInRangeOf(position, range)));
|
||||||
|
}
|
||||||
|
|
||||||
public static T Read<T>(string file) where T : new()
|
public static T Read<T>(string file) where T : new()
|
||||||
{
|
{
|
||||||
XmlSerializer ser = new(typeof(T));
|
XmlSerializer ser = new(typeof(T));
|
||||||
|
Reference in New Issue
Block a user