Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Demigod916 authored Aug 18, 2023
0 parents commit ed197ff
Show file tree
Hide file tree
Showing 26 changed files with 800 additions and 0 deletions.
35 changes: 35 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: Bug Report
about: Create a bug report to help solve an issue
title: 'Bug: TITLE'
labels: New Issue
assignees: ''
---

**Describe the issue**

A clear and concise description of what the bug is.

**Expected behavior**

A clear and concise description of what you expected to happen.

**To Reproduce**

Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error


**Media**

If applicable, add a screenshot or a video to help explain your problem.

**Needed information (please complete the following information):**
- **Client Version:**: [e.g. Canary or Release]
- **Template Version**: [e.g. 3486] Don't know?~~Check the version in your package.json~~

**Additional context**
Add any other context about the issue here.
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Main CI
on: [push, pull_request]
jobs:
build:
name: Build Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: web

steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup node environment
uses: actions/setup-node@v2
with:
node-version: 14.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
- uses: actions/cache@v2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install deps
run: yarn --frozen-lockfile
- name: Try build
run: yarn build

30 changes: 30 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Tagged Release
on:
push:
tags:
- "v*"
jobs:
create-tagged-release:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v2
with:
fetch-depth: 0
ref: ${{ github.ref }}
- name: Get tag
run: echo ::set-output name=VERSION_TAG::${GITHUB_REF/refs\/tags\//}
id: get_tag
- name: 'Setup Node.js'
uses: 'actions/setup-node@v1'
with:
node-version: 14.x
- name: Create release
uses: marvinpinto/action-automatic-releases@latest
with:
title: React/Lua Boilerplate - ${{ steps.get_tag.outputs.VERSION_TAG }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
prerelease: false
id: auto_release

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2021 Project Error

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
216 changes: 216 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
<div align="center">
<img href="https://projecterror.dev" width="150" src="https://i.tasoagc.dev/c1pD" alt="Material-UI logo" />
</div>
<h1 align="center">FiveM React and Lua Boilerplate</h1>

<div align="center">
A simple and extendable React (TypeScript) boilerplate designed around the Lua ScRT
</div>

<div align="center">

[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/project-error/pe-utils/master/LICENSE)
![Discord](https://img.shields.io/discord/791854454760013827?label=Our%20Discord)
![David](https://img.shields.io/david/project-error/fivem-react-boilerplate-lua)
[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=project-error/fivem-react-boilerplate-lua)](https://dependabot.com)
</div>

This repository is a basic boilerplate for getting started
with React in NUI. It contains several helpful utilities and
is bootstrapped using `create-react-app`. It is for both browser
and in-game based development workflows.

For in-game workflows, Utilizing `craco` to override CRA, we can have hot
builds that just require a resource restart instead of a full
production build

This version of the boilerplate is meant for the CfxLua runtime.

## Requirements
* [Node > v10.6](https://nodejs.org/en/)
* [Yarn](https://yarnpkg.com/getting-started/install) (Preferred but not required)

*A basic understanding of the modern web development workflow. If you don't
know this yet, React might not be for you just yet.*

## Getting Started

First clone the repository or use the template option and place
it within your `resources` folder

### Installation

*The boilerplate was made using `yarn` but is still compatible with
`npm`.*

Install dependencies by navigating to the `web` folder within
a terminal of your choice and type `npm i` or `yarn`.

## Features

This boilerplate comes with some utilities and examples to work off of.

### Lua Utils

**SendReactMessage**

This is a small wrapper for dispatching NUI messages. This is designed
to be used with the `useNuiEvent` React hook.

Signature
```lua
---@param action string The action you wish to target
---@param data any The data you wish to send along with this action
SendReactMessage(action, data)
```

Usage
```lua
SendReactMessage('setVisible', true)
```

**debugPrint**

A debug printing utility that is dependent on a convar,
if the convar is set this will print out to the console.

The convar is dependent on the name given to the resource.
It follows this format `YOUR_RESOURCE_NAME-debugMode`

To turn on debugMode add `setr YOUR_RESOURCE_NAME-debugMode 1` to
your server.cfg or use the `setr` console command instead.

Signature (Replicates `print`)
```lua
---@param ... any[] The arguments you wish to send
debugPrint(...)
```

Usage
```lua
debugPrint('wow cool string to print', true, someOtherVar)
```

### React Utils

Signatures are not included for these utilities as the type definitions
are sufficient enough.

**useNuiEvent**

This is a custom React hook that is designed to intercept and handle
messages dispatched by the game scripts. This is the primary
way of creating passive listeners.


*Note: For now handlers can only be registered a single time. I haven't
come across a personal usecase for a cascading event system*

**Usage**
```jsx
const MyComp: React.FC = () => {
const [state, setState] = useState('')

useNuiEvent<string>('myAction', (data) => {
// the first argument to the handler function
// is the data argument sent using SendReactMessage

// do whatever logic u want here
setState(data)
})

return(
<div>
<h1>Some component</h1>
<p>{state}</p>
</div>
)
}

```

**fetchNui**

This is a simple NUI focused wrapper around the standard `fetch` API.
This is the main way to accomplish active NUI data fetching
or to trigger NUI callbacks in the game scripts.

When using this, you must always at least callback using `{}`
in the gamescripts.

*This can be heavily customized to your use case*

**Usage**
```ts
// First argument is the callback event name.
fetchNui<ReturnData>('getClientData').then(retData => {
console.log('Got return data from client scripts:')
console.dir(retData)
setClientData(retData)
}).catch(e => {
console.error('Setting mock data due to error', e)
setClientData({ x: 500, y: 300, z: 200})
})
```

**debugData**

This is a function allowing for mocking dispatched game script
actions in a browser environment. It will trigger `useNuiEvent` handlers
as if they were dispatched by the game scripts. **It will only fire if the current
environment is a regular browser and not CEF**

**Usage**
```ts
// This will target the useNuiEvent hooks registered with `setVisible`
// and pass them the data of `true`
debugData([
{
action: 'setVisible',
data: true,
}
])
```

**Misc Utils**

These are small but useful included utilities.

* `isEnvBrowser()` - Will return a boolean indicating if the current
environment is a regular browser. (Useful for logic in development)

## Development Workflow

This boilerplate was designed with development workflow in mind.
It includes some helpful scripts to accomplish that.

**Hot Builds In-Game**

When developing in-game, you can use the hot build system by
running the `start:game` script. This is essentially the start
script but it writes to disk. Meaning all that is required is a
resource restart to update the game script

**Usage**
```sh
# yarn
yarn start:game
# npm
npm run start:game
```

**Production Builds**

When you are done with development phase for your resource. You
must create a production build that is optimized and minimized.

You can do this by running the following:

```sh
npm run build
yarn build
```

## Additional Notes

Need further support? Join our [Discord](https://discord.com/invite/HYwBjTbAY5)!
25 changes: 25 additions & 0 deletions client/client.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
local function toggleNuiFrame(shouldShow)
SetNuiFocus(shouldShow, shouldShow)
SendReactMessage('setVisible', shouldShow)
end

RegisterCommand('show-nui', function()
toggleNuiFrame(true)
debugPrint('Show NUI frame')
end)

RegisterNUICallback('hideFrame', function(_, cb)
toggleNuiFrame(false)
debugPrint('Hide NUI frame')
cb({})
end)

RegisterNUICallback('getClientData', function(data, cb)
debugPrint('Data sent by React', json.encode(data))

-- Lets send back client coords to the React frame for use
local curCoords = GetEntityCoords(PlayerPedId())

local retData <const> = { x = curCoords.x, y = curCoords.y, z = curCoords.z }
cb(retData)
end)
30 changes: 30 additions & 0 deletions client/utils.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--- A simple wrapper around SendNUIMessage that you can use to
--- dispatch actions to the React frame.
---
---@param action string The action you wish to target
---@param data any The data you wish to send along with this action
function SendReactMessage(action, data)
SendNUIMessage({
action = action,
data = data
})
end

local currentResourceName = GetCurrentResourceName()

local debugIsEnabled = GetConvarInt(('%s-debugMode'):format(currentResourceName), 0) == 1

--- A simple debug print function that is dependent on a convar
--- will output a nice prettfied message if debugMode is on
function debugPrint(...)
if not debugIsEnabled then return end
local args <const> = { ... }

local appendStr = ''
for _, v in ipairs(args) do
appendStr = appendStr .. ' ' .. tostring(v)
end
local msgTemplate = '^3[%s]^0%s'
local finalMsg = msgTemplate:format(currentResourceName, appendStr)
print(finalMsg)
end
Loading

0 comments on commit ed197ff

Please sign in to comment.