CitizenFX C# templates are fixed

Since the earlier release of the CitizenFX C# templates, people have reported that certain built-in language types did not work, leading to vague errors such as '' is not a type supported by the compiler or such.

It took a while, but these should be fixed as of version 0.2.2 of the C# templates/SDK/framework packages, and these should now be usable for writing client code with compile-time checks for APIs available to the client-side subset framework.

A quick note about OneSync server-side persistence

Starting at server build 2689 (unless backed out in a later build), when using OneSync, there’s a few differences regarding entity lifetime compared to before.

  • Entities that are owned by a script (not marked as no-longer-needed, or re-assigned as mission entity) will now be able to be in an ‘unowned’ state in which the server is the owner of the entity. This happens when no player is having the entity in scope (as in – the entity is out of range of any player), and this state ends when it goes in scope for a player.
  • Script ownership is now correctly synced across the board. No longer does the owning script ID vanish when an entity migrates or is recreated. This should fix a lot of cases of mission entities getting deleted anyway.
  • Faraway entities are no longer controlled by their original owner. This means that any entity that would be out of scope will be culled and migrated/disowned. It might lead to a small number of script compatibility issues, but in return a lot of cases of unenterable vehicles (because the owner is too far and doesn’t know you) especially with Infinity/Beyond modes should be fixed.
  • Entities that aren’t owned by a script get reassigned and, when impossible, culled when out of scope. This is a difference from the old behavior where this was up to the game behavior of the owning client. Typically, the owning client would have cleaned up non-script entities early anyway, so this should not be a significant difference.

In addition to these changes, a number of improvements to ‘entity RPC’ are planned to allow for more robust server-side entity creation/initial configuration of entities by taking advantage of this ‘unowned entity’ state, resolving a large number of issues with current server-side CREATE_VEHICLE/… calls.

Try the new CitizenFX C# templates for FiveM

We’ve recently published the CitizenFX.Templates package on NuGet, which includes a nice template for making a fully C#-based resource using the latest recommendations. The docs will be updated whenever more people confirm this works and report some feedback as to this, but for now here’s the steps to set it up:

dotnet new -i CitizenFX.Templates
mkdir MyResource
cd MyResource
dotnet new cfx-resource

You’ll find helpful instructions afterwards in the generated README.md.

Uploading photos from in-game to the Cfx.re Gallery

Recent builds of FiveM have added backing functionality to the photo gallery feature in the pause menu. This guide shows how to upload your photos to the Cfx.re Snapmatic section on the forums.

  1. Make sure you have a photo camera resource that uses photo commands to save a gallery photo. An example resource would e.g. be Xinerki’s ‘Cellphone Camera‘ resource, instructions for which can be found in the topic.
  2. Sign in and link your Cfx.re forum account in the main menu of FiveM.
  3. Go to the pause menu in a server (or a local game), and go to Gallery, and press Enter/A.
  4. Select a photo to upload, assuming you have a few. You can also press Enter/A to view/confirm and change the title.
  5. Press the ‘Upload to Social Club’ button as marked in the bottom of the screen.
  6. Say ‘Yes’.
  7. Wait a while.
  8. You’ll see your image uploaded on the forums!

Using the new console key bindings

You’re able to define keyboard bindings in a new way, as originally detailed in the 2018 design document “Configuration & Input – Redesigned“.

Here’s a sample snippet of a simple ‘hands up’ binding:

local handsUp = false

CreateThread(function()
    while true do
        Wait(0)

        if handsUp then
            TaskHandsUp(PlayerPedId(), 250, PlayerPedId(), -1, true)
        end
    end
end)

RegisterCommand('+handsup', function()
    handsUp = true
end, false)

RegisterCommand('-handsup', function()
    handsUp = false
end, false)

RegisterKeyMapping('+handsup', 'Hands Up', 'keyboard', 'i')
RegisterKeyMapping('say hi', 'Say hi', 'keyboard', 'o')
User-editable bindings.

These bindings will be editable by the user in the ‘key bindings’ option (only 1 binding per command yet, no secondary binding), and depending on user demand we’ll add a helper for computing the right hashes to use with ~INPUT_~-style display as well for help hints and similar.

In addition to that, a plethora of new console commands are added to the client F8 console, an example is below:

// bind a key to toggle the safe zone to an offscreen size and back
bind KEYBOARD F3 "+vstr hideHud showHud"
seta "hideHud" "profile_safezoneSize 500"
seta "showHud" "profile_safezoneSize 7"

// list all bindings
bind

// bind for a specific resource (similar to RegisterKeyMapping)
rbind runcode keyboard o "say hi"

// unbind
unbind keyboard f3

// set the volume way above the usual max
profile_sfxVolume 50

// ear rape?
profile_sfxVolume 9000

// toggle a variable
toggle strmem

// toggle a variable between two values
toggle con_miniConChannels * minicon:*

// see cmdlist to view all new and existing variables and commands

… and the fxd:/fivem.cfg (%appdata%\citizenfx) file contains a lot of additional user settings now in a readable format.

Optimizing resource downloads using a caching proxy

Server builds starting at pipeline ID 1679 added the ability to configure the fileServer field used for resource downloading using a set of commands:

# Set the file server for the specified resource regex.
# The URL should *not* end with a slash.
fileserver_add ".*" "http://10.10.0.1/files"

# Remove the file server associated with a resource regex.
fileserver_remove ".*"

# List all registered file server patterns.
fileserver_list

# Old command, but **required** to not get corrupted cache entries.
adhesive_cdnKey "someSecurePassphrase"

There’s currently no cache invalidation logic based on hashes (this’ll need yet another server update due to the file server not ignoring query strings + a client update), so make sure to clear your proxy’s cache before you modify/restart a resource.

Here’s an example NGINX configuration for setting this up (but you should, for example, run this behind yet another proxy which offers HTTP/2 over TLS, or otherwise set this up properly – we’re expecting the community to provide fleshed-out examples on the forums):

default.template

proxy_cache_path /srv/cache levels=1:2 keys_zone=assets:48m max_size=10g ;
log_format asset '$remote_addr - [$time_local] "$request" $status $body_bytes_sent $upstream_cache_status';

server {
        listen 80;

        location /files/ {
                access_log /dev/stdout asset;
                add_header X-Cache-Status $upstream_cache_status;
                proxy_cache_lock on;
                proxy_pass $REMOTE$request_uri;
                proxy_cache assets;
                proxy_cache_valid 1y;
                proxy_cache_key $request_uri$is_args$args;
        }
}

Dockerfile

FROM nginx:alpine
COPY default.template /etc/nginx/conf.d/default.template
CMD sh -c "envsubst \"`env | awk -F = '{printf \" \\\\$%s\", $1}'`\" < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"

Start command

docker build -t fxproxy .
docker run -d --name=fxproxy -e REMOTE=http://10.10.0.2:30120 -p 80:80 -v $PWD/cache:/srv/cache fxproxy

OneSync: intercepting game events (such as explosions)

The latest version of the server (1543+) added support for parsing and preventing routing of game events. This currently only supports parsing CExplosionEvent, but this might be a fairly useful one to prevent routing of ‘excessive’ explosions, or explosions that are ‘too close’ to a player and not of the correct weapon type.

Here’s an example:

-- SERVER script, requires OneSync!
AddEventHandler('explosionEvent', function(sender, ev)
    print(GetPlayerName(sender), json.encode(ev))
end)

This’ll show JSON data similar to the following:

{"explosionType":0,"isAudible":true,"posX":742.84313964844,"cameraShake":1.0,"isInvisible":true,"ownerNetId":0,"posY":-1808.2889404297,"damageScale":1.0,"posZ":33.105224609375}

If you want to, say, make an explosion-free zone:

AddEventHandler('explosionEvent', function(sender, ev)
    if ev.posX > 2000.0 and ev.posY > 2000.0 and ev.posX < 3000.0 and ev.posY < 3000.0 then
        CancelEvent()
    end
end)

This can be used in a variety of ways – rate limiting, automatic warning/kicking, disabling routing of bad explosions, etc.

Two new experimental OneSync variables

In the latest Windows server release (1504 or higher), two experimental variables have been added to help troubleshooting problematic behavior and offer a ‘workaround’ for common problems.

onesync_distanceCullVehicles true

This console variable (set it in your config, or in the console at runtime) will lead to player-occupied vehicles also being subject to distance culling – that is, they won’t exist if a player is more than n units away from the entity.

Enabling the variable might help with game performance (FPS), and should help with bandwidth concerns as well as ‘texture loss’/’city bug’ streaming issues caused by loading larger amounts of custom addon player vehicles than usual.

Cons are that player-occupied vehicles will not be known to client scripts unless another player is nearby enough. This might affect ‘teleport into player’s vehicle’ scripts, for instance.

onesync_forceMigration true

This one forces any entity which has not received any clone sync updates for over x seconds to be migrated to any other nearby player. While it doesn’t fix the underlying cause for ‘ghost vehicle/ped’ migration failures, it should make them less painful and not require kicking the alleged owner anymore.

There should not be too many cons, but it’s disabled by default lest it crash players when it’s triggered, or worse.

Useful snippet: getting the top left of the minimap in screen coordinates

SetScriptGfxAlign(string.byte('L'), string.byte('B'))
local minimapTopX, minimapTopY = GetScriptGfxPosition(-0.0045, 0.002 + (-0.188888))
ResetScriptGfxAlign()

local w, h = GetActiveScreenResolution()

return { w * minimapTopX, h * minimapTopY }

This could be useful if you want to align things to NUI or other screen-space draws, and works on pretty much any aspect ratio. The magic numbers here are the minimap position from common:/data/ui/frontend.xml, as seen below:

<data name="minimap"           alignX="L"	alignY="B"	posX="-0.0045"		posY="0.002"		sizeX="0.150"		sizeY="0.188888" /> <!-- WARNING! Feed MUST match posX and PosY -->

This will likely also work for aligning to other positions, assuming you set the right sizes.

Improving script stack traces

In the past, the Citizen framework scripting runtime would print really messy stack traces such as.. this:

Stack traces across runtimes.

This stack trace goes on for around 3-4 times the displayed length, and is generally.. a big mess. You can tell that some resource code is running, like @stest3/sv.lua:20, f.js:8 and @stest1/sv.lua, but everything else that is shown is just noise.

Starting at today’s Windows server (and client, on canary) releases, we’re doing something new and exciting: stack boundary stitching. This is the third attempt at implementing cross-runtime stack tracing, and the first one that actually had the possibility to make it out the door.

To compare, look at the new stack trace output:

A stitched stack.

You’ll see that we’re filtering out only user code, and we’re also showing each error only once: every error down the stack due to failed reference calls simply gets hidden. In addition to that, we now format C# functions using a ‘friendly’ library with support for providing nice method names.

An API and more functionality for stack traces (showing a call boundary, JS source map support) might be offered in the future – for now this is a feature which is generally runtime-internal, and is supported across runtimes: Mono/C#, V8/JS and Lua.

It’d also be really nice if you’d provide some more suggestions regarding developer experience improvements you’d love to see. We think this one will help a lot diagnosing script issues at a glance, however!