NOT FINISHED YET!
More info later...
This commit is contained in:
@ -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;
|
||||||
|
@ -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,7 +244,6 @@ namespace CoopClient
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Interface.MessageReceived(message);
|
|
||||||
Client.Recycle(message);
|
Client.Recycle(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -789,6 +794,27 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
public static class CustomSerializer
|
||||||
{
|
{
|
||||||
if (client.HasData("ShowPlayerPosition") && client.GetData<bool>("ShowPlayerPosition"))
|
public static byte[] SerializeToByteArray(this object obj)
|
||||||
{
|
{
|
||||||
if (!SecretLocation.Contains(client.Player.Username) && client.Player.IsInRangeOf(new LVector3(0, 0, 75), 7f))
|
if (obj == null)
|
||||||
{
|
{
|
||||||
client.SendChatMessage("Hey! you find this secret location!");
|
return null;
|
||||||
SecretLocation.Add(client.Player.Username);
|
}
|
||||||
return;
|
|
||||||
}
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
FirstScript/FirstScript.sln
Normal file
25
FirstScript/FirstScript.sln
Normal 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
|
54
FirstScript/FirstScript/FirstScript.csproj
Normal file
54
FirstScript/FirstScript/FirstScript.csproj
Normal 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>
|
116
FirstScript/FirstScript/Main.cs
Normal file
116
FirstScript/FirstScript/Main.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
FirstScript/FirstScript/Properties/AssemblyInfo.cs
Normal file
36
FirstScript/FirstScript/Properties/AssemblyInfo.cs
Normal 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")]
|
@ -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>
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user