├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── crash_report.yml │ ├── docs_improvement.yml │ └── feature_request.yml └── workflows │ └── auto_issue_closer.yml ├── Examples ├── MsgPack.md └── Overview.md ├── Notice.md ├── README.md └── Setup.md /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report to the mono v2-runtime, excluding crashes 3 | labels: ["bug", "triage"] 4 | assignees: 5 | - 6 | 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for taking the time to fill out this bug report. 12 | Only bug related issues are accepted, so please refrain yourself from submitting any other requests, including support requests. 13 | 14 | For crashes that terminate the client or runtime use the [Crash Report](https://github.com/thorium-cfx/mono_v2_get_started/issues/new?assignees=&labels=💀+crash%2Ctriage&projects=&template=crash_report.yml) template. 15 | 16 | \* Issue reports that fail to deliver the proper information may be closed without any feedback. 17 | 18 | - type: textarea 19 | id: what-happened 20 | attributes: 21 | label: What happened? 22 | description: | 23 | Please be clear and concise 24 | placeholder: 25 | validations: 26 | required: true 27 | 28 | - type: input 29 | id: expectation 30 | attributes: 31 | label: Expected result 32 | description: | 33 | What did you expect to happen instead? 34 | validations: 35 | required: true 36 | 37 | - type: textarea 38 | id: repro 39 | attributes: 40 | label: Reproduction steps 41 | description: | 42 | This is important to us. Fill in the exact steps you took, test and remove any steps that aren't relevant. 43 | placeholder: | 44 | 1. 45 | 2. 46 | 3. 47 | 4. 48 | render: bash 49 | validations: 50 | required: true 51 | 52 | - type: dropdown 53 | id: importancy 54 | attributes: 55 | label: Importancy 56 | description: | 57 | To your knowledge how would you describe the importancy of this bug? 58 | options: 59 | - Unknown 60 | - Slight inconvenience 61 | - Prerequisite for my project 62 | - Can't use this feature until fixed 63 | - Fatal (we can't use the runtime without) 64 | validations: 65 | required: true 66 | 67 | - type: input 68 | id: build-number 69 | attributes: 70 | label: Specific version 71 | description: Please fill in the build number on which this issue occured 72 | placeholder: FiveM/RedM 6464, Server 6464 windows/linux 73 | 74 | - type: textarea 75 | id: misc 76 | attributes: 77 | label: Extra 78 | description: | 79 | Anything else you'd like to add? 80 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/crash_report.yml: -------------------------------------------------------------------------------- 1 | name: Crash Report 2 | description: "File a crash report to the mono v2-runtime, result is simple: you crashed" 3 | labels: ["💀 crash", "triage"] 4 | assignees: 5 | - 6 | 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for taking the time to fill out this crash report. 12 | Only crash related issues are accepted, so please refrain yourself from submitting any other requests, including support requests. 13 | 14 | For issues, like exceptions, that don't crash the client or runtime use the [Bug Report](https://github.com/thorium-cfx/mono_v2_get_started/issues/new?assignees=&labels=bug%2Ctriage&projects=&template=bug_report.yml) template. 15 | 16 | \* Issue reports that fail to deliver the proper information may be closed without any feedback. 17 | 18 | - type: textarea 19 | id: result 20 | attributes: 21 | label: Crash results 22 | description: | 23 | What are the results of the crash? e.g.: log files, dumps, errors 24 | placeholder: 25 | validations: 26 | required: true 27 | 28 | - type: textarea 29 | id: repro 30 | attributes: 31 | label: Reproduction steps 32 | description: | 33 | This is important to us. Fill in the exact steps you took, test and remove any steps that aren't relevant. 34 | placeholder: | 35 | 1. 36 | 2. 37 | 3. 38 | 4. 39 | render: bash 40 | validations: 41 | required: true 42 | 43 | - type: input 44 | id: build-number 45 | attributes: 46 | label: Specific version 47 | description: Please fill in the build number on which this issue occured 48 | placeholder: FiveM/RedM 6464, Server 6464 windows/linux 49 | 50 | - type: textarea 51 | id: misc 52 | attributes: 53 | label: Extra 54 | description: | 55 | Anything else you'd like to add? 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/docs_improvement.yml: -------------------------------------------------------------------------------- 1 | name: Documentation Improvement 2 | description: Improve request for mono v2-runtime's documentation 3 | labels: ["documentation", "triage"] 4 | assignees: 5 | - 6 | 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for taking the time to fill out this documentation improvement request. 12 | Only documentation related request are accepted, so please refrain yourself from submitting any other requests, including support requests. 13 | 14 | \* Requests that fail to deliver the proper information may be closed without any feedback. 15 | 16 | - type: input 17 | id: segment 18 | attributes: 19 | label: Segment 20 | description: | 21 | Which segment is this targeting? e.g.: type, method, field, or property 22 | placeholder: 23 | validations: 24 | required: true 25 | 26 | - type: dropdown 27 | id: importancy 28 | attributes: 29 | label: Importancy 30 | description: | 31 | To your knowledge how would you describe the importancy of this feature? 32 | options: 33 | - Unknown 34 | - Nice extra 35 | - Missing details 36 | - Unclear or unintuitive 37 | - Incorrect 38 | validations: 39 | required: true 40 | 41 | - type: textarea 42 | id: improvement 43 | attributes: 44 | label: Improvement request 45 | description: | 46 | Tell us what needs to be changed to make this better, also add suggestions if you have any 47 | validations: 48 | required: true 49 | 50 | - type: textarea 51 | id: misc 52 | attributes: 53 | label: Extra 54 | description: | 55 | Anything else you'd like to add? 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Need the mono v2-runtime to support something? 3 | labels: ["enhancement", "triage"] 4 | assignees: 5 | - 6 | 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thank you for taking the time to fill out this feature request. 12 | Only feature request are accepted, so please refrain yourself from submitting any other requests, including support requests. 13 | 14 | \* Requests that fail to deliver the proper information may be closed without any feedback. 15 | 16 | - type: textarea 17 | id: goal 18 | attributes: 19 | label: Goal 20 | description: | 21 | Please be clear and concise and make sure you focus on the **X** in [XY Problems](https://xyproblem.info/) 22 | placeholder: 23 | validations: 24 | required: true 25 | 26 | - type: dropdown 27 | id: importancy 28 | attributes: 29 | label: Importancy 30 | description: | 31 | To your knowledge how would you describe the importancy of this feature? 32 | options: 33 | - Unknown 34 | - Nice extra 35 | - Quality of Life (QoL) 36 | - Overal quality to the runtime 37 | - Prerequisite for my project 38 | - Fatal (we can't use the runtime without) 39 | 40 | - type: textarea 41 | id: implementation 42 | attributes: 43 | label: API and/or potential implementation 44 | description: | 45 | Tell us what the user interface will look like and maybe a potential implementation 46 | validations: 47 | required: true 48 | 49 | - type: textarea 50 | id: misc 51 | attributes: 52 | label: Extra 53 | description: | 54 | Anything else you'd like to add? 55 | -------------------------------------------------------------------------------- /.github/workflows/auto_issue_closer.yml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | 6 | jobs: 7 | close-issues: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/stale@v5 14 | with: 15 | days-before-issue-stale: 30 16 | days-before-issue-close: 14 17 | exempt-issue-labels: "bug,important,mandatory,critical,fatal,💀 crash" 18 | stale-issue-label: "stale" 19 | stale-issue-message: "This issue is marked as stale because it has been open for 30 days without any activity." 20 | close-issue-message: "This issue was closed because it has been inactive for 14 days since it was marked as stale." 21 | days-before-pr-stale: -1 22 | days-before-pr-close: -1 23 | repo-token: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /Examples/MsgPack.md: -------------------------------------------------------------------------------- 1 | ⚠️ This environment is still in beta, crashes and future changes are to be expected ⚠️ 2 | # Serialization and Deserialization with MsgPack data 3 | 4 | ⚠️ Note: these features will be enabled once [PR 2546](https://github.com/citizenfx/fivem/pull/2546) has been merged. 5 | 6 | ## Implicit parameter conversion 7 | Enjoy automatic and implicit conversion of all incoming data to the parameters that you request, no more need to create a `Player` object from an `int` yourself. This is done by converting the internal MsgPack byte data directly to the requested type, unlike mono v1 who constructs an intermediate object first, packs it in an `object[]` array, who in turn are converted again. 8 | 9 | This approach is at least 3 times faster than the one used in mono v1, that does mean that creating multiple listeners is not advised as the conversion cost will now be per listener, best keep it to 1 or at least 3 or less. 10 | 11 | Example: 12 | ```csharp 13 | [EventHandler("myEvent")] public static async Coroutine GimmeAll(int a) 14 | => Debug.WriteLine($"GimmeAll1 {a}"); 15 | 16 | [EventHandler("myEvent")] public static async Coroutine GimmeAll(string a, int b) 17 | => Debug.WriteLine($"GimmeAll2 {a} {b}"); 18 | 19 | [EventHandler("myEvent")] public static async Coroutine GimmeAll(string a, int b, string c = "Hey") 20 | => Debug.WriteLine($"GimmeAll3 {a} {b} {c}"); 21 | 22 | [EventHandler("myEvent")] public static async Coroutine GimmeAll(int a, string b, string c = "Oh", int d = 678) 23 | => Debug.WriteLine($"GimmeAll4 {a} {b} {c} {d}"); 24 | 25 | [EventHandler("myEvent")] public static async Coroutine GimmeAll(int a, Player b, string c = "Oh", int d = 678) 26 | => Debug.WriteLine($"GimmeAll5 {a} {b} {c} {d}"); 27 | 28 | // Trigger it! 29 | [Command("Gimme")] public async Coroutine Gimme(uint source, object[] objects, string raw) 30 | => Events.TriggerServerEvent("myEvent", 1234, "5678"); 31 | ``` 32 | The above will result in the following output: 33 | ``` 34 | [ script:csharp_v2] GimmeAll1 1234 35 | [ script:csharp_v2] GimmeAll2 1234 5678 36 | [ script:csharp_v2] GimmeAll3 1234 5678 Hey 37 | [ script:csharp_v2] GimmeAll4 1234 5678 Oh 678 38 | [ script:csharp_v2] GimmeAll5 1234 Player(5678) Oh 678 39 | ``` 40 | 41 | 42 | ## Serializable classes/structs 43 | Want to automate your custom type's (de)serialization, then include `using CitizenFX.MsgPack;` and apply the `MsgPackSerializable(Layout)` attribute to your type. 44 | 45 | #### Best practices 46 | Before we jump into how this is done, here's a list of best practices to make your resource more performant and as a result lets your servers run more smoothly. 47 | 1. Reduce packet size: 48 | 1. Only send data that is necessary, e.g.: send update packets with player ids instead of sending the player's name and/or other data you don't need with each request. 49 | 2. Use `Layout.Indexed` over any mapped/keyed based solution, removing unnecessary key strings in your packets. 50 | 3. Send integers (incl. enums) instead of strings. 51 | 4. Don't send strings, unless it's required, mind you: each character takes in 1 byte and we need to store the length. 52 | 5. Send strings only once, e.g.: sending a players name per each name change. 53 | 6. Send `float`s instead of `double`s, this'll reduce byte usage by half: 4B vs 8B. 54 | 7. Check the [MsgPack spec](https://github.com/msgpack/msgpack/blob/master/spec.md) for type sizes. We already store integers in the smallest possible container that can hold the given value. 55 | 8. While networking: stay below or aim for 1KB packets or more wisely: read into and consider maximum packet sizes of MTU and UDP, also consider headers and our network layer overhead, including event names. 56 | 9. Locally: best to keep everything within 1 assembly and limit your use of events, exports, and callbacks (NUI, refFuncs), although size is less of an issue, the serialization + internal redirection logic + deserialization will slow down your resources unnecessarily. 57 | 3. Send packets as little as possible: 58 | 1. Better to send a packet that triggers an event to happen every second than sending an event every second, the more you send the more packet loss can occur. 59 | 2. The less you send the more players you can be of service, both computational and network overhead. 60 | 61 | #### Layouts 62 | You can choose between 3 types of layouts for your types: `Indexed`, `Keyed`, and `Default`, mentioned in the order you should generally consider them. Read below for more information about them. 63 | 64 | Note: classes and structs that aren't marked as `MsgPackSerializable` will default to the `Layout.Default` layout. This may result in errors for some types, generally these are considered to be a user-error, meaning you are responsible for fixing these in your code. 65 | 66 | ##### Layout.Indexed 67 | (De)serializes all fields and properties marked with the `Index` attribute to/from an array. Great to reduce data and increase networking performance. 68 | ```csharp 69 | [MsgPackSerializable(Layout.Indexed)] 70 | public class MyClass 71 | { 72 | [Index(0)] public uint m_id = 0; 73 | public string m_name = "My very long name"; // Let's not send this to reduce packet size, client/server should already know who this is with the given id 74 | [Index(1)] private float m_health = 300.0; 75 | } 76 | ``` 77 | TThe above will result in the following serialized form (visualized): `[ 0, 300.0f ]` // 6 bytes 78 | 79 | \* Concerns: there's a lack of context per field, meaning other scripts who don't know about the array's layout/order may not be able to use them dynamically. 80 | 81 | ##### Layout.Keyed 82 | Maps all fields and properties marked with the `Key` attribute 83 | ```csharp 84 | [MsgPackSerializable(Layout.Keyed)] 85 | public class MyClass 86 | { 87 | [Key("id")] public uint m_id = 0; 88 | [Key("name")] public string m_name = "My very long name"; 89 | 90 | private double m_health = 300.0; 91 | [Key("health")] public double Health 92 | { 93 | get => m_health; 94 | set => m_health = value; 95 | } 96 | } 97 | ``` 98 | The above will result in the following serialized form (visualized): `{ "id": 0, "name": "My very long name", "health": 300.0 }` // 43 bytes 99 | 100 | 101 | \* Concerns: the strings and double values take most room in our packet, consider going for `Layout.Indexed`, remove `name`, and/or (de)serializing floats instead of doubles. 102 | 103 | ##### Layout.Default 104 | Maps all public fields and properties, except those marked with the `Ignore` attribute 105 | ```csharp 106 | [MsgPackSerializable(Layout.Default)] 107 | public class MyClass 108 | { 109 | public uint m_id = 0; 110 | [Ignore] public string m_name = "My very long name"; // Let's not send this to reduce packet size, client/server should already know who this is with the given id 111 | 112 | private double m_health = 300.0; 113 | public double Health 114 | { 115 | get => m_health; 116 | set => m_health = value; 117 | } 118 | } 119 | ``` 120 | The above will result in the following serialized form (visualized): `{ "m_id": 0, "Health": 300.0 }` // 22 bytes 121 | 122 | \* Concerns: the strings and double values take most room in our packet, consider going for `Layout.Indexed` and/or (de)serializing floats instead of doubles. 123 | 124 | #### Constructors 125 | Don't want to open up all fields/properties for write permission? Use a constructor instead. Make sure you match the fields/properties and constructor's parameter types, including their order. 126 | 127 | Note: only incoming arrays and types marked `Layout.Indexed` are considered for this fast form of construction. 128 | 129 | ```csharp 130 | [MsgPackSerializable(Layout.Indexed)] 131 | public class MyClass 132 | { 133 | // Mind the types and order of these fields 134 | [Index(0)] readonly public uint m_id = 0; 135 | [Index(1)] public float m_health = 100.0; 136 | 137 | private float m_armor = 100.0; 138 | [Index(2)] public float Armor => m_armor; 139 | 140 | // Follow above fiels/properties their types and order 141 | public MyClass(uint id, float health, float armor) 142 | { 143 | m_id = id; 144 | m_health = health; 145 | m_armor = armor; 146 | } 147 | } 148 | ``` 149 | -------------------------------------------------------------------------------- /Examples/Overview.md: -------------------------------------------------------------------------------- 1 | ⚠️ This environment is still in beta, crashes and future changes are to be expected ⚠️ 2 | # Examples 3 | 4 | General: 5 | 1. [Natives](#natives) 6 | 2. [Coroutines replace Tasks](#coroutines-replace-tasks) 7 | 3. [Events callable from anywhere](#events-callable-from-anywhere) 8 | 4. [Export invocation](export-invocation) 9 | 5. [Register Events and restrict their accessibility](#register-events-and-restrict-their-accessibility) 10 | 6. [SourceAttribute](#sourceattribute) 11 | 7. [ExportAttribute](#exportattribute) 12 | 8. [Disable & Enable BaseScripts](#disable--enable-basescripts) 13 | 9. [EnableOnLoadAttribute](#enableonloadattribute) 14 | 10. [CString](#cstring) 15 | 16 | Other: 17 | 1. [Implicit parameter conversion with Events, Exports, and callbacks](MsgPack.md) 18 | 19 | 20 | ## Natives 21 | As before, but now they are in the **Natives** class, found in the *CitizenFX.FiveM.Native*, *CitizenFX.RedM.Native*, *CitizenFX.Server.Native*, or *CitizenFX.Shared.Native* namespace 22 | ```csharp 23 | using CitizenFX.FiveM.Native; // client FiveM 24 | //using CitizenFX.RedM.Native; // client RedM 25 | using CitizenFX.Server.Native; // server 26 | using CitizenFX.Shared.Native; // shared (for shared libraries) 27 | ... 28 | int health = Natives.GetEntityHealth(ped); 29 | int health = Natives.Call(Hash.GET_ENTITY_HEALTH, ped); 30 | ``` 31 | 32 | ## Coroutines replace Tasks 33 | Where you used `Task`/`Task` before, you now use `Coroutine`/`Coroutine`, it's as simple as replacing Task with Coroutine. Below you can see that scheduling them as a repeating coroutine is still the same, if you want to schedule a coroutine/action as a non-repeating action then use `Scheduler.Schedule(Action [, int])` 34 | ```csharp 35 | public Constructor() 36 | { 37 | Tick += AsyncFunction; // creates and activates a repeating coroutine 38 | } 39 | 40 | async Coroutine AsyncFunction() 41 | { 42 | // do some stuff here 43 | await WaitUntilNextFrame(); 44 | 45 | // do some more stuff here 46 | await Yield(); // same as WaitUntilNextFrame 47 | 48 | // let's do stuff, then 1 second sleepy sleepy 49 | await Wait(1000); 50 | 51 | // done, though it'll run again next frame as it's registered as a repeating tick 52 | } 53 | ``` 54 | \* *As a side note; although its scheduler is no longer restricted, we do not offer any support for using `Task` in v2 and may be prone to deactivation if required.* 55 | 56 | ## Events callable from anywhere 57 | Events callable from anywhere 58 | ```csharp 59 | Events.TriggerEvent("EventName", ...) 60 | Events.TriggerServerEvent("EventName", ...) 61 | Events.TriggerClientEvent("EventName", Player, ...) 62 | ``` 63 | 64 | ## Export invocation 65 | Export's calling syntax has changed, v1 used dynamic intermediate code that caused seconds of JIT lag, with the following syntax we circumvent that: 66 | ```csharp 67 | Exports["ResourceName", "ExportName"](...); // in BaseScript inherited classes 68 | Exports.Local["ResourceName", "ExportName"](...); // call from anywhere 69 | ``` 70 | 71 | ## Register Events and restrict their accessibility 72 | EventHandlers can now use the `Binding` overload to determine who can call this handler/export. The options are: 73 | 1. **Local** (default): client only accepts client events, server only server events 74 | 2. **Remote**: client only accepts server events, server only accepts client events 75 | 3. **All**: accept events from both client and server 76 | 77 | Mind you, unlike the v1 runtime; v2's `EventHandlers["EventName"] += ` is an indirect call to `EventHandlers["EventName"].Add(DynFunc, Binding.Local)`, local binding is the default for security reasons. You should call `EventHandlers["EventName"].Add(DynFunc, )` to override and/or make your intent clear on who may call the given event listener. 78 | 79 | ```csharp 80 | [EventHandler("EventName", Binding.Local)] 81 | private string EventFunction() 82 | { 83 | return "Remote can't touch this, ..."; 84 | } 85 | ``` 86 | 87 | ### Extra ways to (un)register: 88 | Events no longer pass `List` objects, they are now pure arrays `object[]`. 89 | ```csharp 90 | Constructor() 91 | { 92 | // Add as Binding.Local 93 | EventHandlers["EventName"] += Func.Create(EventFunction1); 94 | EventHandlers["EventName"].Add(Func.Create(EventFunction2)); 95 | EventHandlers["EventName"] += Func.Create(EventFunction3WithReturn); 96 | 97 | // Remove 98 | EventHandlers["EventName"] -= Func.Create(EventFunction1); 99 | EventHandlers["EventName"].Remove(Func.Create(EventFunction2)); 100 | EventHandlers["EventName"] -= Func.Create(EventFunction3WithReturn); 101 | 102 | // Add as Binding.Remote or Binding.All 103 | EventHandlers["EventName"].Add(Func.Create(EventFunction2), Binding.Remote); 104 | EventHandlers["EventName"].Add(Func.Create(EventFunction2), Binding.All); 105 | 106 | // Register from anywhere 107 | Event.RegisterEventHandler("EventName", Func.Create(EventFunction1), Binding.Local); 108 | 109 | // Unregister from anywhere 110 | Event.UnregisterEventHandler("EventName", Func.Create(EventFunction1)); 111 | } 112 | 113 | void EventFunction1(int i, object[] values) { } 114 | void EventFunction2(float f) { } 115 | int EventFunction3WithReturn(float f) { } 116 | ``` 117 | 118 | ## SourceAttribute 119 | Previously `[FromSource]`, now simplified to `[Source]`. It also allows clients to know if the event was called from the server or not. Also note that these parameters don't influence the parameter order when invoked as an event, so if an exception like a `CastException` occurs solve them as if any `[Source]` parameter is absent. 120 | ```csharp 121 | // Server 122 | [EventHandler("EventName", Binding.All)] 123 | private string EventFunction([Source] Player source) { } 124 | 125 | // Client 126 | [EventHandler("EventName", Binding.All)] 127 | private string EventFunction([Source] bool isServer) { } 128 | 129 | // Shared 130 | [EventHandler("EventName", Binding.All)] 131 | private string EventFunction([Source] Remote remote) { } 132 | 133 | [EventHandler("EventName", Binding.All)] 134 | private string EventFunction([Source] bool isRemote) { } 135 | ``` 136 | 137 | 138 | ## ExportAttribute 139 | Previously non-existent, can be used as follows: 140 | ```csharp 141 | [Export("ExportName")] 142 | private string ExportE2() 143 | { 144 | return "yeehaa"; 145 | } 146 | ``` 147 | 148 | ## Disable & Enable BaseScripts 149 | BaseScript's ticks, events, exports, and commands can all be disabled and enabled with ease, allowing you to create and cache something like game modes or anything else you'd like to use it for 150 | ```csharp 151 | class MyScript 152 | { 153 | [Tick] 154 | private async Coroutine MyTick() 155 | { 156 | // tick that'll not be rescheduled when disabled 157 | } 158 | 159 | [Tick] 160 | private async Coroutine MyTickwhileLooped() 161 | { 162 | while (IsEnabled) // run as long as this script is enabled 163 | { 164 | // my things 165 | } 166 | 167 | // only when we get here will this tick be disabled 168 | } 169 | } 170 | 171 | BaseScript script = new MyScript(); 172 | 173 | script.Disable(); 174 | // script is inactive, ticks will come to a halt when they exit their scope 175 | 176 | script.Enable(); 177 | // script is activated, all events, exports, and commands are enabled, ticks are rescheduled or continued 178 | ``` 179 | 180 | ## EnableOnLoadAttribute 181 | Want to make use of the BaseScript functionalities but without activating it on startup? Add `[EnableOnLoad(false)]` to the class and it won't be automatically activated. 182 | ```csharp 183 | [EnableOnLoad(false)] 184 | class MyScript : BaseScript 185 | { } 186 | 187 | ... 188 | 189 | MyScript myScript = new MyScript(); 190 | 191 | void SomeFunctionToActivateMyScript() 192 | { 193 | BaseScript.RegisterScript(myScript); 194 | } 195 | ``` 196 | 197 | 198 | ## CString 199 | A UTF8 encoded string dedicated for interop. Do not use this as a replacement to C#'s `string`, if at all. However it is an interesting storage type for repeated interop usage of data that remains constant. 200 | ```csharp 201 | CString value = "This string is converted to a UTF8 string and doesn't need reconversion on interop!"; 202 | ``` 203 | -------------------------------------------------------------------------------- /Notice.md: -------------------------------------------------------------------------------- 1 | # Mono rt2 prerelease 2 | 3 | If you came in here after reading the `mono_rt2` flag in your fxmanifest, then you might not want to use it at this time. In short: only use these resources in testing environments as it's not fully released and supported yet. 4 | 5 | ## Prerelease notes 6 | The mono rt2 environment is currently in prerelease, crashes and bugs are to be expected, and the runtime may be prone to deactivation after the given dates. Using it in production is highly discouraged and no support nor guarantees are given. 7 | 8 | Want to start developing and testing this new environment, then [start right here](README.md). 9 | 10 | ## Technical issues & reports 11 | If you encounter any technical issues then create your [Minimal Reproducible Example (MRE or repro)](https://stackoverflow.com/help/minimal-reproducible-example) and create an issue by one of the following means: 12 | 1. [On this repository](https://github.com/thorium-cfx/mono_v2_get_started/issues) 13 | 2. [On the FiveM repository](https://github.com/citizenfx/fivem/issues) 14 | 3. Contact thorium directly 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ⚠️ This environment is still in beta, crashes and future changes are to be expected ⚠️ 2 | # Get started with FiveM's mono v2 3 | Straight to the action? [set up your C# solution and resource](Setup.md) or [see examples](Examples/Overview.md) 4 | 5 | ## Major differences to v1 6 | 1. [Performance](#performance) 7 | 2. [Dividing CitizenFX.Core.dll into multiple libraries](#dividing-citizenfxcoredll-into-multiple-libraries) 8 | 3. [Native updates and compatibility](#dividing-citizenfxcoredll-into-multiple-libraries) 9 | 4. [Hello fast Coroutines, bye bye slow Tasks](#native-updates-and-compatibility) 10 | 5. [Tick-less, removing unnecessary per-frame overhead](#tick-less-removing-unnecessary-per-frame-overhead) 11 | 6. [Implicit parameter conversion for events, exports, and callbacks](Examples/MsgPack.md) 12 | 13 | # Performance 14 | | ![](https://user-images.githubusercontent.com/102315529/233750229-141384dd-d36b-4399-b423-fde740a1e542.png) | 15 | |:--:| 16 | | *Get on v2 and be the cyan guy* | 17 | | *\*first mono runtime takes the biggest hit as well* | 18 | 1. **Interop**: all interop between C# and C++ is now done through thunks, a simple intermediate call 19 | 1. Events and Exports are at least **84 times** faster 20 | 2. String recoding is **43~47%** faster, precoding strings is also an option 21 | 3. No unnecessary recoding on strings that aren't used 22 | 4. Implicit parameter conversion on events, exports, and callbacks, decreasing invocation time by another **3 times**. 23 | 2. **Runtime enter/exit cost**: the default 0.04~0.06ms overhead cost in v1 has been eliminated, enjoy your 0.00ms. 24 | 3. **Custom ~~task~~ coroutine scheduler**: no longer uses the .NET scheduler, which brought quite some overhead. 25 | 4. **Natives**: 26 | 1. Client can expect speed increases of **40~84%** and higher 27 | 2. Servers on Windows have a **~10 times** speed increase (WSL **~160 times**) 28 | 3. Custom native invocation can expect speed increases by **10-folds** 29 | 30 | # Dividing CitizenFX.Core.dll into multiple libraries 31 | In v1 everything was included in **CitizenFX.Core.dll**, v2 comes with separated libraries 32 | * **CitizenFX.Core.dll**: Core functionality for client, server, and shared libraries 33 | * **CitizenFX.Server.dll**: Server related types and natives 34 | * **CitizenFX.FiveM.dll**: FiveM (GTA V) related types and functionality 35 | * **CitizenFX.FiveM.Native.dll**: All natives for FiveM (GTA V), make a copy of this one 36 | * **CitizenFX.RedM.dll** RedM (RDR 2) related types and functionality 37 | * **CitizenFX.RedM.Native.dll**: All natives for RedM (RDR 2), make a copy of this one 38 | 39 | [*Make sure to copy the latest **CitizenFX.FiveM.Native.dll** or **CitizenFX.RedM.dll** and supply it with your resource*](#native-updates-and-compatibility) 40 | 41 | # Native updates and compatibility 42 | v2 will allow C# programmers to finally get back on track with the latest natives, allowing them to use the most up-to-date types that are currently known. At some point we'll even be able to add and remove parameters to natives! 43 | 44 | This does come with some extra work for you as you'll need to copy the latest **CitizenFX.FiveM.Native.dll** for FiveM or **CitizenFX.RedM.Native.dll** for RedM and supply it with your resource. Doing this will add backwards compatibility to your C# resource, allowing them to always find the native methods they were compiled against. Failing to do so will result in `MissingMethodException`s in the future, rendering your resource broken. 45 | 46 | # Hello fast Coroutines, bye bye slow Tasks 47 | Task/Task\ are used for the default .NET scheduler and its performance is well... really bad. It's now replaced with a custom scheduler that you can use by using Coroutine/Coroutine\, it's as simple as replacing Task with Coroutine and you are making use of it! 48 | 49 | \* As a side note; although its scheduler is no longer restricted, we do not offer any support for using Task in v2 and may be prone to deactivation if required. 50 | 51 | # Tick-less, removing unnecessary per-frame overhead 52 | v2 got updated to run on the core scheduler, removing any runtime switching cost (that were left) when there's no `Tick` methods scheduled in your resource. 53 | 54 |   55 | 56 | Now go and [set up your C# solution and resource!](Setup.md) 57 | -------------------------------------------------------------------------------- /Setup.md: -------------------------------------------------------------------------------- 1 | ⚠️ This environment is still in beta, crashes and future changes are to be expected ⚠️ 2 | # Set up your C# solution 3 | This guide expects that the reader already knows how to work with Visual Studio and how to [set up and distribute FiveM resources](https://docs.fivem.net/docs/scripting-manual/introduction/). 4 | 5 | 1. Create the solution and projects 6 | * CLI, automatic: 7 | ```cmd 8 | dotnet new sln -o MySolution 9 | chdir MySolution 10 | dotnet new classlib --target-framework-override net452 -o Client 11 | dotnet new classlib --target-framework-override net452 -o Server 12 | dotnet sln add Client Server 13 | xcopy %localappdata%\FiveM\FiveM.app\citizen\clr2\lib\mono\4.5\v2\Native\CitizenFX.FiveM.Native.dll Client\bin\ /Y /I 14 | :: for RedM: remove or comment out the above line and uncomment (remove ::) from below line 15 | ::xcopy %localappdata%\FiveM\FiveM.app\citizen\clr2\lib\mono\4.5\v2\Native\CitizenFX.RedM.Native.dll Client\bin\ /Y /I 16 | pause 17 | ``` 18 | \* Higher Framework versions are possible, but Visual Studio may complain on some systems. 19 | * Manual: 20 | Create a new C# **Class Library (.NET Framework)** and add another project in the solution for the missing server or client, also copy **Native/CitizenFX.FiveM.Native.dll** with your client project. 21 | 2. Go into your \ directory and open the solution 22 | 3. In Visual Studio you right click the project and *Add -> Add Assembly Reference...* 23 | * Client FiveM: 24 | **CitizenFX.FiveM.dll** and **CitizenFX.Core.dll** from `%localappdata%\FiveM\FiveM.app\citizen\clr2\lib\mono\4.5\v2\`, 25 | **CitizenFX.FiveM.Native.dll** from `bin\` or where your copied it to. 26 | * Client RedM: 27 | **CitizenFX.RedM.dll** and **CitizenFX.Core.dll** from `%localappdata%\RedM\RedM.app\citizen\clr2\lib\mono\4.5\v2\`, 28 | **CitizenFX.RedM.Native.dll** from `bin\` or where your copied it to. 29 | * Server: 30 | **CitizenFX.Server.dll** and **CitizenFX.Core.dll** from your server files `\citizen\clr2\lib\mono\4.5\v2\`. 31 | 4. Replace the contents of both **Class.cs** files and preferably rename them as well 32 | ```csharp 33 | using CitizenFX.Core; 34 | //using CitizenFX.FiveM; // FiveM game related types (client only) 35 | //using CitizenFX.FiveM.Native; // FiveM natives (client only) 36 | //using CitizenFX.RedM; // RedM game related types (client only) 37 | //using CitizenFX.RedM.Native; // RedM natives (client only) 38 | //using CitizenFX.Server.Native; // Server natives (server only) 39 | //using CitizenFX.Shared.Native; // Shared natives (there for shared libraries) 40 | 41 | namespace MyLibrary.Client // probably update your default namespace as well 42 | { 43 | public class Class1 : BaseScript 44 | { 45 | 46 | } 47 | } 48 | ``` 49 | 5. Now you should have a solution with 2 projects, targeting .NET Framework 4.5.2 (or higher), and have all references correctly set up. 50 | 6. Edit your **fxmanifest.lua** file and add the following to it: 51 | `mono_rt2 'Prerelease expiring 2023-06-30. See https://aka.cfx.re/mono-rt2-preview for info.'` 52 | \* *rt2 stands for runtime 2, as to not confuse it with a potential v2 of mono itself.* 53 | \* *this flag is considered temporary and will be removed at some point.* 54 | 7. Add your copy of **CitizenFX.FiveM.Native.dll** or **CitizenFX.RedM.Native.dll** (depending on your game) to the resource and also add it in your **fxmanifest.lua** as well, just like any other dll dependency 55 | 56 | [Continue by looking into examples](Examples/Overview.md) 57 | --------------------------------------------------------------------------------