NOT FINISHED YET!

More info later...
This commit is contained in:
EntenKoeniq
2021-09-29 14:34:22 +02:00
parent 1320f35f30
commit 05f70a6d04
14 changed files with 499 additions and 88 deletions

View File

@ -1,22 +1,20 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using Lidgren.Network;
namespace CoopClient namespace CoopClient
{ {
public static class Interface public static class Interface
{ {
#region DELEGATES #region DELEGATES
public delegate void ConnectEvent(bool connected, string reason = null); public delegate void ConnectEvent(bool connected, string reason = null);
public delegate void MessageEvent(NetIncomingMessage message);
public delegate void ChatMessage(string from, string message, CancelEventArgs args); public delegate void ChatMessage(string from, string message, CancelEventArgs args);
public delegate void ModEvent(long from, string mod, byte customID, byte[] bytes);
#endregion #endregion
#region EVENTS #region EVENTS
public static event ConnectEvent OnConnection; public static event ConnectEvent OnConnection;
public static event MessageEvent OnMessage;
public static event ChatMessage OnChatMessage; public static event ChatMessage OnChatMessage;
public static event ModEvent OnModPacketReceived;
internal static void Connected() internal static void Connected()
{ {
@ -28,9 +26,9 @@ namespace CoopClient
OnConnection?.Invoke(false, reason); OnConnection?.Invoke(false, reason);
} }
internal static void MessageReceived(NetIncomingMessage message) internal static void ModPacketReceived(long from, string mod, byte customID, byte[] bytes)
{ {
OnMessage?.Invoke(message); OnModPacketReceived?.Invoke(from, mod, customID, bytes);
} }
internal static bool ChatMessageReceived(string from, string message) internal static bool ChatMessageReceived(string from, string message)
@ -51,14 +49,28 @@ namespace CoopClient
Main.MainNetworking.DisConnectFromServer(serverAddress); Main.MainNetworking.DisConnectFromServer(serverAddress);
} }
public static void Disconnect()
{
Main.MainNetworking.DisConnectFromServer(null);
}
public static bool IsOnServer() public static bool IsOnServer()
{ {
return Main.MainNetworking.IsOnServer(); return Main.MainNetworking.IsOnServer();
} }
public static long GetLocalID()
{
return Main.LocalClientID;
}
public static bool IsMenuVisible() public static bool IsMenuVisible()
{ {
#if NON_INTERACTIVE
return false;
#else
return Main.MainMenu.MenuPool.AreAnyVisible; return Main.MainMenu.MenuPool.AreAnyVisible;
#endif
} }
public static bool IsChatFocused() public static bool IsChatFocused()
@ -76,6 +88,12 @@ namespace CoopClient
return Main.CurrentVersion; return Main.CurrentVersion;
} }
// Send bytes to all players
public static void SendDataToAll(string mod, byte customID, byte[] bytes)
{
Main.MainNetworking.SendModData(mod, customID, bytes);
}
public static void Configure(string playerName, bool shareNpcsWithPlayers, int streamedNpcs, bool debug = false) public static void Configure(string playerName, bool shareNpcsWithPlayers, int streamedNpcs, bool debug = false)
{ {
Main.MainSettings.Username = playerName; Main.MainSettings.Username = playerName;

View File

@ -224,6 +224,12 @@ namespace CoopClient
packet.NetIncomingMessageToPacket(message); packet.NetIncomingMessageToPacket(message);
DecodeNativeCall((NativeCallPacket)packet); DecodeNativeCall((NativeCallPacket)packet);
break; break;
case (byte)PacketTypes.ModPacket:
packet = new ModPacket();
packet.NetIncomingMessageToPacket(message);
ModPacket modPacket = (ModPacket)packet;
Interface.ModPacketReceived(modPacket.ID, modPacket.Mod, modPacket.CustomPacketID, modPacket.Bytes);
break;
} }
break; break;
case NetIncomingMessageType.ConnectionLatencyUpdated: case NetIncomingMessageType.ConnectionLatencyUpdated:
@ -238,13 +244,12 @@ namespace CoopClient
break; break;
} }
Interface.MessageReceived(message);
Client.Recycle(message); Client.Recycle(message);
} }
} }
#region -- GET -- #region -- GET --
#region -- PLAYER -- #region -- PLAYER --
private void PlayerConnect(PlayerConnectPacket packet) private void PlayerConnect(PlayerConnectPacket packet)
{ {
EntitiesPlayer player = new EntitiesPlayer() EntitiesPlayer player = new EntitiesPlayer()
@ -445,9 +450,9 @@ namespace CoopClient
Function.Call((Hash)packet.Hash, arguments.ToArray()); Function.Call((Hash)packet.Hash, arguments.ToArray());
} }
#endregion // -- PLAYER -- #endregion // -- PLAYER --
#region -- NPC -- #region -- NPC --
private void FullSyncNpc(FullSyncNpcPacket packet) private void FullSyncNpc(FullSyncNpcPacket packet)
{ {
lock (Main.Npcs) lock (Main.Npcs)
@ -567,10 +572,10 @@ namespace CoopClient
} }
} }
} }
#endregion // -- NPC -- #endregion // -- NPC --
#endregion #endregion
#region -- SEND -- #region -- SEND --
private int LastPlayerFullSync = 0; private int LastPlayerFullSync = 0;
public void SendPlayerData() public void SendPlayerData()
{ {
@ -694,12 +699,12 @@ namespace CoopClient
Client.SendMessage(outgoingMessage, messageType); Client.SendMessage(outgoingMessage, messageType);
Client.FlushSendQueue(); Client.FlushSendQueue();
#if DEBUG #if DEBUG
if (ShowNetworkInfo) if (ShowNetworkInfo)
{ {
BytesSend += outgoingMessage.LengthBytes; BytesSend += outgoingMessage.LengthBytes;
} }
#endif #endif
} }
public void SendNpcData(Ped npc) public void SendNpcData(Ped npc)
@ -763,12 +768,12 @@ namespace CoopClient
Client.SendMessage(outgoingMessage, NetDeliveryMethod.Unreliable); Client.SendMessage(outgoingMessage, NetDeliveryMethod.Unreliable);
Client.FlushSendQueue(); Client.FlushSendQueue();
#if DEBUG #if DEBUG
if (ShowNetworkInfo) if (ShowNetworkInfo)
{ {
BytesSend += outgoingMessage.LengthBytes; BytesSend += outgoingMessage.LengthBytes;
} }
#endif #endif
} }
public void SendChatMessage(string message) public void SendChatMessage(string message)
@ -782,13 +787,34 @@ namespace CoopClient
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered); Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered);
Client.FlushSendQueue(); Client.FlushSendQueue();
#if DEBUG #if DEBUG
if (ShowNetworkInfo) if (ShowNetworkInfo)
{ {
BytesSend += outgoingMessage.LengthBytes; BytesSend += outgoingMessage.LengthBytes;
} }
#endif #endif
} }
#endregion
public void SendModData(string mod, byte customID, byte[] bytes)
{
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new ModPacket()
{
ID = Main.LocalClientID,
Mod = mod,
CustomPacketID = customID,
Bytes = bytes
}.PacketToNetOutGoingMessage(outgoingMessage);
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered);
Client.FlushSendQueue();
#if DEBUG
if (ShowNetworkInfo)
{
BytesSend += outgoingMessage.LengthBytes;
}
#endif
}
#endregion
} }
} }

View File

@ -127,7 +127,8 @@ namespace CoopClient
FullSyncNpcPacket, FullSyncNpcPacket,
FullSyncNpcVehPacket, FullSyncNpcVehPacket,
ChatMessagePacket, ChatMessagePacket,
NativeCallPacket NativeCallPacket,
ModPacket
} }
[Flags] [Flags]
@ -195,6 +196,44 @@ namespace CoopClient
public abstract void NetIncomingMessageToPacket(NetIncomingMessage message); public abstract void NetIncomingMessageToPacket(NetIncomingMessage message);
} }
[ProtoContract]
class ModPacket : Packet
{
[ProtoMember(1)]
public long ID { get; set; }
[ProtoMember(2)]
public string Mod { get; set; }
[ProtoMember(3)]
public byte CustomPacketID { get; set; }
[ProtoMember(4)]
public byte[] Bytes { get; set; }
public override void PacketToNetOutGoingMessage(NetOutgoingMessage message)
{
message.Write((byte)PacketTypes.ModPacket);
byte[] result = CoopSerializer.Serialize(this);
message.Write(result.Length);
message.Write(result);
}
public override void NetIncomingMessageToPacket(NetIncomingMessage message)
{
int len = message.ReadInt32();
ModPacket data = CoopSerializer.Deserialize<ModPacket>(message.ReadBytes(len));
ID = data.ID;
Mod = data.Mod;
CustomPacketID = data.CustomPacketID;
Bytes = data.Bytes;
}
}
#region -- PLAYER -- #region -- PLAYER --
[ProtoContract] [ProtoContract]
class HandshakePacket : Packet class HandshakePacket : Packet

View File

@ -1,71 +1,42 @@
using System.Linq; using CoopServer;
using CoopServer;
namespace FirstGameMode namespace FirstGameMode
{ {
class Commands class Commands
{ {
[Command("hello")] [Command("set")]
public static void HelloCommand(CommandContext ctx) public static void TimeCommand(CommandContext ctx)
{ {
ctx.Client.SendChatMessage("Hello " + ctx.Client.Player.Username + " :)"); if (ctx.Args.Length < 1)
{
ctx.Client.SendChatMessage("Please use \"/set <OPTION> ...\"");
return;
} }
else if (ctx.Args.Length < 2)
[Command("inrange")]
public static void InRangeCommand(CommandContext ctx)
{ {
if (ctx.Client.Player.IsInRangeOf(new LVector3(0f, 0f, 75f), 7f)) ctx.Client.SendChatMessage($"Please use \"/set {ctx.Args[0]} ...\"");
{
ctx.Client.SendChatMessage("You are in range! :)");
}
else
{
ctx.Client.SendChatMessage("You are not in range! :(");
}
}
[Command("online")]
public static void OnlineCommand(CommandContext ctx)
{
ctx.Client.SendChatMessage(API.GetAllClientsCount() + " player online!");
}
[Command("kick")]
public static void KickCommand(CommandContext ctx)
{
if (ctx.Args.Length < 2)
{
ctx.Client.SendChatMessage("Please use \"/kick <USERNAME> <REASON>\"");
return; return;
} }
ctx.Client.Kick(ctx.Args.Skip(1).ToArray()); switch (ctx.Args[0])
}
[Command("setweather")]
public static void SetWeatherCommand(CommandContext ctx)
{ {
case "time":
int hours, minutes, seconds; int hours, minutes, seconds;
if (ctx.Args.Length < 3) if (ctx.Args.Length < 4)
{ {
ctx.Client.SendChatMessage("Please use \"/setweather <HOURS> <MINUTES> <SECONDS>\""); ctx.Client.SendChatMessage("Please use \"/set time <HOURS> <MINUTES> <SECONDS>\"");
return; return;
} }
else if (!int.TryParse(ctx.Args[0], out hours) || !int.TryParse(ctx.Args[1], out minutes) || !int.TryParse(ctx.Args[2], out seconds)) else if (!int.TryParse(ctx.Args[1], out hours) || !int.TryParse(ctx.Args[2], out minutes) || !int.TryParse(ctx.Args[3], out seconds))
{ {
ctx.Client.SendChatMessage("Please use \"/setweather <NUMBER> <NUMBER> <NUMBER>\""); ctx.Client.SendChatMessage($"Please use \"/set time <NUMBER> <NUMBER> <NUMBER>\"");
return; return;
} }
ctx.Client.SendNativeCall(0x47C3B5848C3E45D8, hours, minutes, seconds); ctx.Client.SendNativeCall(0x47C3B5848C3E45D8, hours, minutes, seconds);
break;
} }
[Command("upp")]
public static void UpdatePlayerPositionCommand(CommandContext ctx)
{
ctx.Client.SetData("ShowPlayerPosition", !ctx.Client.GetData<bool>("ShowPlayerPosition"));
} }
} }
} }

View File

@ -1,4 +1,6 @@
using System.Collections.Generic; using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.ComponentModel; using System.ComponentModel;
using System.Timers; using System.Timers;
@ -6,11 +8,18 @@ using CoopServer;
namespace FirstGameMode namespace FirstGameMode
{ {
[Serializable]
public class SetPlayerTime
{
public int Hours { get; set; }
public int Minutes { get; set; }
public int Seconds { get; set; }
}
public class Main : ServerScript public class Main : ServerScript
{ {
private static readonly Timer RunningSinceTimer = new() { Interval = 1000 }; private static readonly Timer RunningSinceTimer = new() { Interval = 1000 };
private static int RunningSince = 0; private static int RunningSince = 0;
private static readonly List<string> SecretLocation = new();
public Main() public Main()
{ {
@ -20,12 +29,26 @@ namespace FirstGameMode
API.OnPlayerConnected += OnPlayerConnected; API.OnPlayerConnected += OnPlayerConnected;
API.OnPlayerDisconnected += OnPlayerDisconnected; API.OnPlayerDisconnected += OnPlayerDisconnected;
API.OnChatMessage += OnChatMessage; API.OnChatMessage += OnChatMessage;
API.OnPlayerPositionUpdate += OnPlayerPositionUpdate; API.OnModPacketReceived += OnModPacketReceived;
API.RegisterCommand("running", RunningCommand); API.RegisterCommand("running", RunningCommand);
API.RegisterCommands<Commands>(); API.RegisterCommands<Commands>();
} }
private void OnModPacketReceived(long from, string mod, byte customID, byte[] bytes, CancelEventArgs args)
{
if (mod == "FirstScript" && customID == 1)
{
args.Cancel = true;
// Get data from bytes
SetPlayerTime setPlayerTime = bytes.Deserialize<SetPlayerTime>();
// Find the client by 'from' and send the time back as a nativecall
API.GetAllClients().Find(x => x.ID == from).SendNativeCall(0x47C3B5848C3E45D8, setPlayerTime.Hours, setPlayerTime.Minutes, setPlayerTime.Seconds);
}
}
public static void RunningCommand(CommandContext ctx) public static void RunningCommand(CommandContext ctx)
{ {
ctx.Client.SendChatMessage("Server has been running for: " + RunningSince + " seconds!"); ctx.Client.SendChatMessage("Server has been running for: " + RunningSince + " seconds!");
@ -57,17 +80,39 @@ namespace FirstGameMode
API.SendChatMessageToAll(message, username); API.SendChatMessageToAll(message, username);
} }
public static void OnPlayerPositionUpdate(Client client)
{
if (client.HasData("ShowPlayerPosition") && client.GetData<bool>("ShowPlayerPosition"))
{
if (!SecretLocation.Contains(client.Player.Username) && client.Player.IsInRangeOf(new LVector3(0, 0, 75), 7f))
{
client.SendChatMessage("Hey! you find this secret location!");
SecretLocation.Add(client.Player.Username);
return;
} }
public static class CustomSerializer
{
public static byte[] SerializeToByteArray(this object obj)
{
if (obj == null)
{
return null;
}
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
public static T Deserialize<T>(this byte[] byteArray) where T : class
{
if (byteArray == null)
{
return null;
}
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(byteArray, 0, byteArray.Length);
memStream.Seek(0, SeekOrigin.Begin);
T obj = (T)binForm.Deserialize(memStream);
return obj;
} }
} }
} }

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31717.71
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FirstScript", "FirstScript\FirstScript.csproj", "{9524435E-24F3-4BDB-B7AA-351A00C2D209}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9524435E-24F3-4BDB-B7AA-351A00C2D209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9524435E-24F3-4BDB-B7AA-351A00C2D209}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9524435E-24F3-4BDB-B7AA-351A00C2D209}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9524435E-24F3-4BDB-B7AA-351A00C2D209}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {398E3E84-30E0-408E-89E5-91CB0F001E14}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{9524435E-24F3-4BDB-B7AA-351A00C2D209}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FirstScript</RootNamespace>
<AssemblyName>FirstScript</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="CoopClient">
<HintPath>..\..\Client\bin\Debug\CoopClient.dll</HintPath>
</Reference>
<Reference Include="ScriptHookVDotNet3">
<HintPath>..\..\Libs\Release\ScriptHookVDotNet3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,116 @@
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using GTA;
namespace FirstScript
{
[Serializable]
public class TestPacketClass
{
public int A { get; set; }
public int B { get; set; }
}
[Serializable]
public class SetPlayerTimePacket
{
public int Hours { get; set; }
public int Minutes { get; set; }
public int Seconds { get; set; }
}
public class Main : Script
{
public Main()
{
Tick += OnTick;
Interval += 3000;
CoopClient.Interface.OnModPacketReceived += OnModPacketReceived;
CoopClient.Interface.OnConnection += OnConnection;
}
private void OnConnection(bool connected, string reason = null)
{
if (connected)
{
CoopClient.Interface.SendChatMessage("Mod", "Welcome!");
}
else
{
GTA.UI.Notification.Show("~r~Mod~s~: ~b~C(°-°)D");
}
}
private void OnTick(object sender, EventArgs e)
{
if (!CoopClient.Interface.IsOnServer())
{
return;
}
CoopClient.Interface.SendDataToAll("FirstScript", 0, new TestPacketClass() { A = 5, B = 15 }.SerializeToByteArray());
CoopClient.Interface.SendDataToAll("FirstScript", 1, new SetPlayerTimePacket() { Hours = 0, Minutes = 0, Seconds = 0 }.SerializeToByteArray());
}
private void OnModPacketReceived(long from, string mod, byte customID, byte[] bytes)
{
if (mod != "FirstScript")
{
return;
}
switch (customID)
{
case 0:
TestPacketClass testPacketClass = bytes.Deserialize<TestPacketClass>();
GTA.UI.Notification.Show($"ModPacket(0)({from}): A[{testPacketClass.A}] B[{testPacketClass.B}]");
break;
case 1:
GTA.UI.Notification.Show($"ModPacket(0)({from}): Nice!");
break;
default:
GTA.UI.Notification.Show($"ModPacket({from}): ~r~Unknown customID!");
break;
}
}
}
public static class CustomSerializer
{
public static byte[] SerializeToByteArray(this object obj)
{
if (obj == null)
{
return null;
}
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
public static T Deserialize<T>(this byte[] byteArray) where T : class
{
if (byteArray == null)
{
return null;
}
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(byteArray, 0, byteArray.Length);
memStream.Seek(0, SeekOrigin.Begin);
T obj = (T)binForm.Deserialize(memStream);
return obj;
}
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("FirstScript")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FirstScript")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("9524435e-24f3-4bdb-b7aa-351a00c2d209")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// indem Sie "*" wie unten gezeigt eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>1.0.0.0</AssemblyVersion> <AssemblyVersion>1.1.0.0001</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion> <FileVersion>1.0.0.0</FileVersion>
</PropertyGroup> </PropertyGroup>

View File

@ -70,7 +70,8 @@ namespace CoopServer
FullSyncNpcPacket, FullSyncNpcPacket,
FullSyncNpcVehPacket, FullSyncNpcVehPacket,
ChatMessagePacket, ChatMessagePacket,
NativeCallPacket NativeCallPacket,
ModPacket
} }
[Flags] [Flags]
@ -128,6 +129,44 @@ namespace CoopServer
public abstract void NetIncomingMessageToPacket(NetIncomingMessage message); public abstract void NetIncomingMessageToPacket(NetIncomingMessage message);
} }
[ProtoContract]
class ModPacket : Packet
{
[ProtoMember(1)]
public long ID { get; set; }
[ProtoMember(2)]
public string Mod { get; set; }
[ProtoMember(3)]
public byte CustomPacketID { get; set; }
[ProtoMember(4)]
public byte[] Bytes { get; set; }
public override void PacketToNetOutGoingMessage(NetOutgoingMessage message)
{
message.Write((byte)PacketTypes.ModPacket);
byte[] result = CoopSerializer.Serialize(this);
message.Write(result.Length);
message.Write(result);
}
public override void NetIncomingMessageToPacket(NetIncomingMessage message)
{
int len = message.ReadInt32();
ModPacket data = CoopSerializer.Deserialize<ModPacket>(message.ReadBytes(len));
ID = data.ID;
Mod = data.Mod;
CustomPacketID = data.CustomPacketID;
Bytes = data.Bytes;
}
}
#region -- PLAYER -- #region -- PLAYER --
[ProtoContract] [ProtoContract]
class HandshakePacket : Packet class HandshakePacket : Packet

View File

@ -280,6 +280,38 @@ namespace CoopServer
message.SenderConnection.Disconnect("Npcs are not allowed!"); message.SenderConnection.Disconnect("Npcs are not allowed!");
} }
break; break;
case (byte)PacketTypes.ModPacket:
if (MainSettings.ModsAllowed)
{
try
{
packet = new ModPacket();
packet.NetIncomingMessageToPacket(message);
ModPacket modPacket = (ModPacket)packet;
if (GameMode != null)
{
if (GameMode.API.InvokeModPacketReceived(modPacket.ID, modPacket.Mod, modPacket.CustomPacketID, modPacket.Bytes))
{
break;
}
}
// Send back to all players
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
modPacket.PacketToNetOutGoingMessage(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, 0);
}
catch (Exception e)
{
message.SenderConnection.Disconnect(e.Message);
}
}
else
{
message.SenderConnection.Disconnect("Mods are not allowed!");
}
break;
default: default:
Logging.Error("Unhandled Data / Packet type"); Logging.Error("Unhandled Data / Packet type");
break; break;

View File

@ -17,6 +17,7 @@ namespace CoopServer
#region DELEGATES #region DELEGATES
public delegate void ChatEvent(string username, string message, CancelEventArgs cancel); public delegate void ChatEvent(string username, string message, CancelEventArgs cancel);
public delegate void PlayerEvent(Client client); public delegate void PlayerEvent(Client client);
public delegate void ModEvent(long from, string mod, byte customID, byte[] bytes, CancelEventArgs args);
#endregion #endregion
#region EVENTS #region EVENTS
@ -25,6 +26,7 @@ namespace CoopServer
public event PlayerEvent OnPlayerConnected; public event PlayerEvent OnPlayerConnected;
public event PlayerEvent OnPlayerDisconnected; public event PlayerEvent OnPlayerDisconnected;
public event PlayerEvent OnPlayerPositionUpdate; public event PlayerEvent OnPlayerPositionUpdate;
public event ModEvent OnModPacketReceived;
internal void InvokeStart() internal void InvokeStart()
{ {
@ -52,6 +54,13 @@ namespace CoopServer
{ {
OnPlayerPositionUpdate?.Invoke(Server.Clients.First(x => x.Player.Username == playerData.Username)); OnPlayerPositionUpdate?.Invoke(Server.Clients.First(x => x.Player.Username == playerData.Username));
} }
internal bool InvokeModPacketReceived(long from, string mod, byte customID, byte[] bytes)
{
CancelEventArgs args = new(false);
OnModPacketReceived?.Invoke(from, mod, customID, bytes, args);
return args.Cancel;
}
#endregion #endregion
#region FUNCTIONS #region FUNCTIONS

View File

@ -9,6 +9,7 @@
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;
public bool ModsAllowed { get; set; } = false;
public bool UPnP { get; set; } = true; public bool UPnP { get; set; } = true;
public bool DebugMode { get; set; } = false; public bool DebugMode { get; set; } = false;
} }