Skip to content

Commit

Permalink
merge 3.0.0 into master (#27)
Browse files Browse the repository at this point in the history
* remove old license

* removed unused class

* Added FxEvent attribute event registration

* RegisterEvent instead of AddEventHandler

* New events dictionary to handle events like in FiveM BaseScript env

* new shared classes handling

* removed debug print

* ops. removed debug print

* new handling of attributes and new signature options

* feat: updates
- Enhanced encryption with private keys internally
- Removed signature as no longer needed due to private encryption

* Goodbye EventDispatcher, welcome EventHub

* update readme

* forgot attribute

* english

* fix: Make sure to check only non void return types for attribute

* Add a warning for missing secret

* Feat: enhanced the deserialization conversion system for different types from the sent ones

* Throw in case of missing conversion.

* fix typo

* Enhance markdown language

* Revert "Throw in case of missing conversion."

This reverts commit 9c76a5a.

* ToString is not more dynamic

* Register events with sha-256 hash

* Make Sha-256 encryption API available publicly

* Update readme with GenerateHash method

* code cleanup

* rename methods with correct naming

* Remove unused NetworkEvent

* Added native support for ValueTuple clientside
- Serverside is already included in .Net Standard 2.0.. if you're using .net framework serverside.. what are you waiting for?? convert it!!

* Added support for native ValueTuple serialization

* sadly these are not usable :(

* fastened tuple serialization

* extract type converson

* Update README.md

* tuples resolvers are useless :(

* Added Fivem-related resolvers

* removed old legacy code

* remove debug

* handle fivem related deserialization

* fixes and tweaks

* code cleanup

* enhance Gateway conversion

* remove unused val

* Added warning for Tuples (Damn you tuples!!!)

* Inherit correct BaseScript

* Added Matrix3x3 resolver

* Added Matrix resolver

* Removed unused deserialization method

* Don't send if target is not online

* Don't send latent if player is not online

* Add an initial anti tamper system for events and signatures.

* feat: handle objects as they are.. and only convert basic types.

* fix globbing

* fix defaults

* remove debug print

* update deserialization with V2 emulation

* enhanced and perfected deserialization / convertion between types

* Added method binding
- attributes and mounted events want a binding specification (default to All for attributes)
- Added SendLocal and GetLocal for same side events

* fix resolvers conversions and added checks in parameter types

* use tryparse (if fails returns 0)

* Ignore and Force attributes are a no go with this msgpack.. shame!

* removed description

* removed unused resolvers and enhanced deserialization

* Deserialize as object added for... objects

* fix callback missing parameter

* fix Gateway routing

* More accurate time frames for client stopwatch

* fix missing parameter sending events

* make IsServer internally global

* do not wait, warn

* Fixed binding All and added PrepareAsync serverside

* no need to send warns as we now await via prepare async

* remove warning for get internal

* if waiting takes up to 1 second.. the player disconnected or is not connected yet.. break the event

* Update README.md
  • Loading branch information
manups4e authored Jul 7, 2024
1 parent 1d610ed commit b07d0f8
Show file tree
Hide file tree
Showing 54 changed files with 6,824 additions and 1,283 deletions.
297 changes: 220 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,129 +1,272 @@
# FxEvents an advanced event subsystem for FiveM
# FxEvents: An Advanced Event Subsystem for FiveM

With FxEvents you can send and get values between client and server using an advanced event handling process.
Signatures are encrypted per each client and using the provided MsgPack binary serialization you can hide contents from malicious clients!
To work you only need to add `FXEvents.Client.dll` or `FXEvents.Server.dll` and `Newtonsoft.Json.dll` (In case of json serialization) to your resource.
No need of any external library for MsgPack, the event system uses the internal MsgPack dll provided with fivem itself!!
FxEvents provides a robust and secure framework for event handling in FiveM, equipped with powerful serialization, encryption, and anti-tampering features. With its easy integration and extensive functionality, FxEvents is a valuable tool for developers seeking efficient and secure client-server communication in their FiveM projects. It incorporates encrypted signatures and MsgPack binary serialization to safeguard against malicious client actions. To integrate FxEvents into your project, simply include `FxEvents.Client.dll` or `FxEvents.Server.dll` along with `Newtonsoft.Json.dll` (if you opt for JSON serialization). The MsgPack functionality is inherently supported by FiveM, so no additional libraries are required!

Starting from Version 3.0.0, the library eliminates the need for manual event initialization, as internal events are now SHA-256 generated based on the resource name combined with a random seed. This update streamlines the process, with initialization primarily used to register events marked with the `[FxEvent]` attribute that would otherwise require a mandatory call from the requesting script.

For more details and support, [join our Discord server](https://discord.gg/KKN7kRT2vM).

[Discord Server Invite](https://discord.gg/KKN7kRT2vM)
---

### Support
**Support**

If you like my work please consider supporting me via PayPal.
You can [buy me a coffee or donut, some banana, a shirt, BMW i4 or Taycan, the stars or whatever you want here](https://www.paypal.com/donate/?hosted_button_id=A5FJK5M94EFQE).
If you like my work, please consider supporting me via PayPal. You can [buy me a coffee or donut, some banana, a shirt, BMW i4, Taycan, Tesla, the stars, or whatever you want here](https://ko-fi.com/manups4e).

---
### Usage examples:

## Initialization
- Encryption key **CANNOT** remain empty or null, you can generate encryption keys, passphrases, passwords online or use the provided serverside command `generagekey` to let the library generate a random passphrase both literal and encrtypted to be copied and stored in a safe place. __PLEASE NOTE__: FXEvents won't store nor save any passkey anywhere for security reasons, do not lose the key or your data won't be recovered.
```c#
## Usage Examples:

### Initialization

To initialize the FxEvents library, include the following in your script:

```csharp
public class Main : BaseScript
{
public Main()
{
// The Event Dispatcher can now be initialized with your own inbound, outbound, and signatures.
// This allows you to use FxEvents in more than one resource on the server without having signature collisions.
EventDispatcher.Initalize("inbound", "outbound", "signature", "encryption key");
}
public Main()
{
// Initialize the FxEvents library. Call this once at script start to enable EventHub usage anywhere.
EventHub.Initialize();
}
}
```

## To mount an event:
- Events can be mounted like normal events, this example is made to show an event mounted in-line.
```c#
EventDispatcher.Mount("eventName", new Action<ISource, type1, type2>(([FromSource] source, val1, val2) =>

---

### Mounting an Event

Events can be mounted similarly to standard events. Below is an example of mounting an event in both lambda style and classic method:

- The `FromSource` attribute enables you to retrieve the source as in standard events, allowing requests for Player, the ISource inheriting class, source as Int32 or as String.

```csharp
EventHub.Mount("eventName", Binding.All, new Action<ISource, type1, type2>(([FromSource] source, val1, val2) =>
{
// code to be used inside the event.
// ISource is the optional insider class that handles clients triggering the event.. is like the "[FromSource] Player player" parameter but can be derived and handled as you want!!
// Clientside is the same thing without the ClientId parameter
// Code to execute inside the event.
// ISource is an optional class handling clients triggering the event, similar to the "[FromSource] Player player" parameter but customizable.
// On the client-side, the same principle applies without the ClientId parameter.
}));

EventHub.Mount("eventName", Binding.All, new Action<ISource, type1, type2>(MyMethod));
private void MyMethod(([FromSource] ISource source, type1 val1, type2 val2)
{
// Code to execute inside the event.
// ISource is an optional class handling clients triggering the event, similar to the "[FromSource] Player player" parameter but customizable.
// On the client-side, the same principle applies without the ClientId parameter.
}
```

## To trigger an event
The library only works in client <--> server communication.. for the moment same side events are not working but the feature will be added in the future!
```c#
// clientside
EventDispatcher.Send("eventName", params);
- **Q: Must the returning method mounted with `Func` be `async Task`?**
- **A: Not necessarily. If you don't need it to be a task, return the required type. The `Get` method is awaitable because it waits for a response from the other side.**

- Events can also be mounted using the `[FxEvent("EventName")]` attribute or by `EventHub.Events["EventName"] += new Action / new Func`.

⚠️ Note: Only one method per attribute can be registered for callbacks.

---

### Event Handling Enhancements

From version 3.0.0, events are managed similarly to Mono V2 (thanks to @Thorium for ongoing support), allowing for type conversions across sides. Events are no longer bound to specific parameters, enabling casting from one type to another. ⚠️ Generic objects (object or dynamic) are not allowed due to MsgPack restrictions.

// serverside
EventDispatcher.Send(Player, "eventName", params);
EventDispatcher.Send(List<Player>, "eventName", params);
EventDispatcher.Send(ISource, "eventName", params);
EventDispatcher.Send(List<ISource>, "eventName", params);
EventDispatcher.Send("eventName", params); // For all Connected Players
Example:

```csharp
[FxEvent("myEvent")]
public static async void GimmeAll(int a, string b)
=> Logger.Info($"GimmeAll1 {a} {b}");

[FxEvent("myEvent")]
public static async void GimmeAll(int a)
=> Logger.Info($"GimmeAll1 {a}");

[FxEvent("myEvent")]
public static async void GimmeAll(string a, int b)
=> Logger.Info($"GimmeAll2 {a} {b}");

[FxEvent("myEvent")]
public static async void GimmeAll(string a, int b, string c = "Hey")
=> Logger.Info($"GimmeAll3 {a} {b} {c}");

[FxEvent("myEvent")]
public static async void GimmeAll(int a, string b, string c = "Oh", int d = 678)
=> Logger.Info($"GimmeAll4 {a} {b} {c} {d}");

[FxEvent("myEvent")]
public static async void GimmeAll(int a, PlayerClient b, string c = "Oh", int d = 678)
=> Logger.Info($"GimmeAll5 {a} {b.Player.Name} {c} {d}");

// Trigger the event
EventHub.Send("myEvent", 1234, 1);
```

## To trigger a callback
### Mounting it
```c#
EventDispatcher.Mount("eventName", new Func<ISource, type1, type2, Task<returnType>>(async ([FromSource] source, val1, val2) =>
Outputs:

![image](https://github.com/manups4e/fx-events/assets/4005518/4e42a6b8-e3eb-4337-99a0-22be5b5211b6)
⚠️ Attributed methods MUST be static.

### Triggering an Event

Events can be triggered from both client and server sides:

```csharp
// Client-side
EventHub.Send("eventName", params);

// Server-side
EventHub.Send(Player, "eventName", params);
EventHub.Send(List<Player>, "eventName", params);
EventHub.Send(ISource, "eventName", params);
EventHub.Send(List<ISource>, "eventName", params);
EventHub.Send("eventName", params); // For all connected players
```

### Triggering a Callback

#### Mounting a Callback

```csharp
EventHub.Mount("eventName", Binding.All, new Func<ISource, type1, type2, Task<returnType>>(async ([FromSource] source, val1, val2) =>
{
// code to be used inside the event.
// ISource is the optional insider class that handles clients triggering the event.. is like the "[FromSource] Player player" parameter but can be derived and handled as you want!!
// Clientside is the same thing without the ISource parameter
return val3
// Code to execute inside the event.
// ISource is an optional class handling clients triggering the event, similar to the "[FromSource] Player player" parameter but customizable.
// On the client-side, the same principle applies without the ISource parameter.
return val3;
}));
```
### Calling it
```c#
// clientside
type param = await EventDispatcher.Get<type>("eventName", params);

// serverside
type param = await EventDispatcher.Get<type>(ClientId, "eventName", params);
type param = await EventDispatcher.Get<type>(Player, "eventName", params);
Callbacks can also be mounted using the `[FxEvent("EventName")]` attribute. ⚠️ Only one per endpoint. Example:

```csharp
[FxEvent("myEvent")]
public static string GimmeAll(int a, string b)
=> "This is a test";
```
Callbacks can be called serverside too because it might happen that the server needs info from certain clients and this will help you doing it.

The library comes with some goodies to help with customization and debugging serialization printing.
#### Calling a Callback

## ToJson()
![image](https://user-images.githubusercontent.com/4005518/188593550-48891947-fb41-4ec1-894c-b429ca890361.png)
```csharp
// Client-side
type param = await EventHub.Get<type>("eventName", params);

⚠️ You need Newtonsoft.Json to make this work!!
```c#
// Server-side
type param = await EventHub.Get<type>(ClientId, "eventName", params);
type param = await EventHub.Get<type>(Player, "eventName", params);
```

Callbacks can also be triggered server-side when the server needs information from specific clients.

Both sides have a new `SendLocal` and `GetLocal` (method requires binding as All or Local) to trigger local events. FxEvents is required in both scripts to work.

---

### Native ValueTuple Support

Starting from version 3.0.0, FxEvents offers native ValueTuple support for client-side (server-side using .Net Standard 2.0 already supports it natively). This provides an alternative to non-fixable Tuples that can't be included in collections or as members/fields inside classes and structs. ValueTuple is dynamic, easy to use, supports the latest C# versions, and being natively supported means no need for external NuGet packages or imported libraries to use it with FxEvents and FiveM.

---

### FiveM Types Support

FxEvents supports FiveM internal types, allowing you to send Vectors, Quaternions, Matrices, and Entities.

- **Player support:** You can send a Player object (or an int32/string) and receive a Player object on the other side.
- **Entities support:** You can send a Ped, Vehicle, Prop, or Entity type as long as they're networked. FxEvents handles them using their NetworkID.
- **Vectors and Math structs:** These are handled as float arrays, making them lightweight and fast.

---

### Event Binding

Starting from 3.0.0, all events are handled like in Mono V2 update (thanks @thorium) and require a binding to be specified when mounted. There are 4 types of binding:

- **None:** The event will be ignored and never triggered.
- **Local:** The event is triggered ONLY when called using `SendLocal` / `GetLocal`.
- **Remote:** The event will trigger only for Client/Server events (classic FxEvents way).
- **All:** The event will trigger both with same-side or client/server calls.

This allows better handling of communications between sides. Legacy EventDispatcher automatically mounts as Remote and `[FxEvent]` attribute binds automatically to All if no binding is specified.

---

### Anti-Tamper

In version 3.0.0, a basic Anti-Tamper system is introduced, which uses a server event (`EventHandlers[fxevents:tamperingprotection] += anyMethodYouWant`) with parameters [source, endpoint, TamperType]:

- **source:** The player handle that triggered the Anti-Tamper.
- **endpoint:** The event that has been flagged as tampered.
- **TamperType:** The type of tamper applied. It can be:
- **TamperType:** The type of tamper applied. It can be:
- **REPEATED_MESSAGE_ID:** Indicates someone tried to send the same event or a new event with a used ID.
- **EDITED_ENCRYPTED_DATA:** Indicates someone altered the encrypted data trying to change values, making it impossible to decrypt.
- **REQUESTED_NEW_PUBLIC_KEY:** Indicates a client tried to request a new ID to change the encryption, potentially attempting to edit the encryption.

---

### Additional Features for Customization and Debugging

FxEvents includes several additional features for customization and debugging, especially regarding serialization:

#### ToJson()

Requires Newtonsoft.Json:
```csharp
string text = param.ToJson();
```

## FromJson()
⚠️ You need Newtonsoft.Json to make this work!!
```c#
#### FromJson()

Requires Newtonsoft.Json:
```csharp
type value = jsonText.FromJson<type>();
```

## ToBytes()
![image](https://user-images.githubusercontent.com/4005518/188594841-3ea787d0-37f3-4b23-9ff7-cdb999d0d101.png)
```c#
#### ToBytes()

```csharp
byte[] bytes = param.ToBytes();
```

## FromBytes()
```c#
#### FromBytes()

```csharp
type value = bytes.FromBytes<type>();
```

# EncryptObject(string passkey)
- Binary serialization performed internally.
```c#
#### EncryptObject(string passkey)

Binary serialization is performed internally. ⚠️ Same key for encryption and decryption:
```csharp
byte[] bytes = param.EncryptObject("passkey");
```

# DecryptObject(string passkey)
- Binary deserialization performed internally.
```c#
#### DecryptObject(string passkey)

Binary deserialization is performed internally. ⚠️ Same key for encryption and decryption:
```csharp
T object = bytes.DecryptObject<T>("passkey");
```

## BytesToString
```c#
#### GenerateHash(string input)

Generates the SHA-256 hash of the given input string:
```csharp
byte[] hash = Encryption.GenerateHash(string input)
```

#### BytesToString

Converts a byte array to a string:
```csharp
byte[] bytes = param.ToBytes();
string txt = bytes.BytesToString();
```

## StringToBytes
```c#
#### StringToBytes

Converts a string back to a byte array:
```csharp
byte[] bytes = txt.StringToBytes();
type value = bytes.FromBytes<type>();
```
Loading

0 comments on commit b07d0f8

Please sign in to comment.