Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V4.2.0 #276

Merged
merged 17 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ docs/others/*
!docs/api/readme.md
!docs/others/readme.md
cache
packages/**/browser
packages/**/browser
vitest.config.ts.timestamp*
32 changes: 30 additions & 2 deletions docs/.vitepress/config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
const apiMenu = [
{
text: 'Functions',
collapsed: false,
sidebarDepth: 2,
items: [
{ text: "inject()", link: "/functions/inject" },
]

},
{
text: 'Classes Server-Side',
collapsed: false,
Expand Down Expand Up @@ -29,11 +38,27 @@ const apiMenu = [
{ text: "GUI Class", link: "/classes/gui" },
{ text: "Sound Class", link: "/classes/sound" },
{ text: "Resource Class", link: "/classes/resource" },
{ text: "Keyboard Class", link: "/classes/keyboard" },
{ text: "Vue Inject Class", link: "/classes/vue-inject" }
{ text: "Keyboard Class", link: "/classes/keyboard" }
]

},
{
text: 'VueJS',
collapsed: false,
sidebarDepth: 2,
items: [
{ text: "Vue Inject Class", link: "/classes/vue-inject" },
{ text: "Vue directives", link: "/api-gui/vue-directive" }
]
},
{
text: 'React',
collapsed: false,
sidebarDepth: 2,
items: [
{ text: "React Hooks", link: "/api-gui/react" }
]
},
{
text: 'Testing',
collapsed: false,
Expand Down Expand Up @@ -168,6 +193,7 @@ const guideMenu = [{
text: 'Advanced',
collapsed: false,
items: [
{ text: "Create Authentication System", link: "/advanced/auth" },
{ text: "Synchronization between Server and Client", link: "/guide/synchronization" },
{ text: "Creating a plugin", link: "/advanced/create-plugin" },
{ text: "Using Agones for Game Server Hosting", link: "/advanced/agones" },
Expand Down Expand Up @@ -237,10 +263,12 @@ module.exports = {
}
],
sidebar: {
'/functions/': apiMenu,
'/classes/': apiMenu,
'/commands/': apiMenu,
'/database/': apiMenu,
'/api/': apiMenu,
'/api-gui/': apiMenu,
'/guide/': guideMenu,
'/gui/': guideMenu,
'/advanced/': guideMenu,
Expand Down
119 changes: 119 additions & 0 deletions docs/advanced/auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# `auth` Hook Documentation

## Overview

The `auth` hook in RPGJS is a authenticating players in your game. This document provides a comprehensive guide on how to implement and use the `auth` hook in the RPGJS project.

::: tip Info
Authentication in RPGJS is agnostic, in the sense that you can make it work with any authentication system. It's not tied to any database or third-party system. You're free to implement your own logic. This is useful for MMORPGs.
Below is an example with a JWT.
:::

## Implementation

In your `main/server.ts` file, follow these steps to set up the `auth` hook:

### Step 1: Import Required Modules

Import the necessary modules from `@rpgjs/server`:

```typescript
import { RpgServerEngineHooks, RpgServerEngine } from '@rpgjs/server';
```

### Step 2: Define the `auth` Hook

Implement the `auth` hook within the `RpgServerEngineHooks`:

```typescript
const server: RpgServerEngineHooks = {
auth(server: RpgServerEngine, socket) {
// Authentication logic goes here
}
};

export default server;
```

#### Functionality

- The `auth` hook must return a `Promise<string>`, a `string`, or throw an error.
- If a `string` is returned, and the ID **public** matches, the player is considered connected.
- If the hook throws an error, it indicates that the player is not authenticated.

#### Parameters

- `server`: An instance of `RpgServerEngine`.
- `socket`: The `socket.io` object. You can access various request headers using `socket.handshake.headers`.

## Client-Side Error Handling

To handle errors on the client side, such as those thrown during the authentication process, implement the `onConnectError` hook in your `main/client.ts` file.

### Step 1: Import Required Modules

Import the necessary modules from `@rpgjs/client`:

```typescript
import { RpgClientEngineHooks, RpgClientEngine } from "@rpgjs/client";
```

### Step 2: Define the `onConnectError` Hook

Implement the `onConnectError` hook within the `RpgClientEngineHooks` to handle connection errors:

```typescript
const client: RpgClientEngineHooks = {
onConnectError(engine: RpgClientEngine, err: Error) {
console.log("Connection Error:", err.message);
}
};

export default client;
```

## JWT Example

### Step 1: Import Required Modules

Import necessary modules from `@rpgjs/server` and any other required libraries (like `jsonwebtoken` for decoding JWT):

```typescript
import { RpgServerEngineHooks, RpgServerEngine } from '@rpgjs/server';
import jwt from 'jsonwebtoken';
```

> Install `jsonwebtoken` using `npm install jsonwebtoken`.
### Step 2: Define the `auth` Hook with JWT Logic

Implement the `auth` hook to handle JWT verification:

```typescript
const server: RpgServerEngineHooks = {
auth(server: RpgServerEngine, socket) {
const token = socket.handshake.headers.authorization;
if (!token) {
throw 'No token provided';
}

// Replace 'YOUR_SECRET_KEY' with your actual secret key used to sign the JWT
const decoded = jwt.verify(token, 'YOUR_SECRET_KEY');
if (!decoded) {
throw 'Invalid token';
}

// Assuming 'decoded' contains a property 'id' representing the user ID
return decoded.id;
}
};

export default server;
```

::: tip Notes
- Ensure you replace `'YOUR_SECRET_KEY'` with the secret key you used to sign your JWTs.
- The JWT is expected to be in the `authorization` header of the socket handshake. Make sure this aligns with how your client is sending the token.
- The example assumes the JWT contains an `id` field representing the user ID. Adjust this according to your JWT structure.
- Proper error handling is crucial to inform the client about authentication failures.
:::
67 changes: 67 additions & 0 deletions docs/api-gui/react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# React Hooks

## Introduction

React hooks are a powerful feature in React that allow you to use state and other React features without writing a class. In the context of RPGJS, a framework for creating RPG games, React hooks can be particularly useful for managing game state and interactions.

## 1. `useEventPropagator()`

This hook is used to propagate events within the canvas element of your RPGJS game.

### Importing

```javascript
import { useEventPropagator } from '@rpgjs/client/react';
```

### Usage

```javascript
export default function Test() {
const propagate = useEventPropagator();

return <div ref={propagate}>test</div>;
}
```

In this example, the `useEventPropagator` hook is used to create a `propagate` function. This function is then passed to a `div` element as a reference (`ref`). This setup allows events within the `div` to be propagated through the RPGJS game canvas.

---

## 2. `RpgReactContext`

This hook provides access to the RPGJS context, allowing you to interact with various game states like the current player's health points (HP).

### Importing

```javascript
import { RpgReactContext } from '@rpgjs/client/react';
import { useContext, useEffect, useState } from 'react';
```

### Usage

```javascript
export default function MyGUI({ foo }) {
const { rpgCurrentPlayer } = useContext(RpgReactContext);
const [hp, setHp] = useState(0);

useEffect(() => {
const subscription = rpgCurrentPlayer.subscribe(({ object }) => {
setHp(object.hp);
});

return () => {
subscription.unsubscribe();
};
}, []);

return (
<div>
<h1>{hp}</h1>
</div>
);
}
```

In this example, `RpgReactContext` is used to access the current player's state. The `useContext` hook retrieves the `rpgCurrentPlayer` from `RpgReactContext`. We then use `useState` to manage the player's HP locally. The `useEffect` hook is used to subscribe to changes in the player's HP, updating the local state accordingly. When the component unmounts, the subscription is unsubscribed.
17 changes: 17 additions & 0 deletions docs/api-gui/vue-directive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Directive for VueJS

## `v-propagate`

The `v-propagate` directive is straightforward to use. Simply add it to any element in your VueJS template to enable event propagation for that element within the RPGJS canvas.

### Example

```vue
<template>
<div v-propagate>
Test
</div>
</template>
```

In this example, the `v-propagate` directive is attached to a `div` element. Any events that occur within this `div` will be propagated through the RPGJS game canvas. This is particularly useful for integrating VueJS-based GUI elements with the RPGJS game canvas, allowing for seamless interaction between the GUI and the game.
40 changes: 40 additions & 0 deletions docs/functions/inject.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Using `inject` in RPGJS

The `inject` function in RPGJS is a powerful feature for dependency injection, allowing you to retrieve instances of various classes in both client and server environments.

## Client-Side Injection

To use `inject` on the client side, import it from `@rpgjs/client`. This allows you to retrieve singleton instances of classes such as `RpgClientEngine`, `KeyboardControls`, and `RpgRenderer`.

### Retrieving the `RpgClientEngine`

```typescript
import { inject, RpgClientEngine } from '@rpgjs/client'

const client = inject(RpgClientEngine)
```

This code imports `inject` and `RpgClientEngine` from `@rpgjs/client` and then uses `inject` to retrieve the `RpgClientEngine` instance.

### Injecting Other Classes

Similarly, you can inject other classes like `KeyboardControls` and `RpgRenderer`:

```typescript
import { inject, KeyboardControls, RpgRenderer } from '@rpgjs/client'

const controls = inject(KeyboardControls)
const renderer = inject(RpgRenderer)
```

## Server-Side Injection

For server-side injection, import `inject` from `@rpgjs/server`. This is typically used to retrieve the `RpgServerEngine`.

### Retrieving the `RpgServerEngine`

```typescript
import { inject, RpgServerEngine } from '@rpgjs/server'

const server = inject(RpgServerEngine)
```
9 changes: 7 additions & 2 deletions docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ Configuration properties related to the compiler.
[vite]
logLevel = "silent"
```
You can insert this section after the `vite` section in your `readme.md`.
> Please note that RPGJS contains configurations. You will therefore overwrite configurations ([the basic file is in the sources]([https://github.com/RSamaium/RPG-JS/blob/v4/packages/compiler/src/build/client-config.ts#L335])).

> Please note that RPGJS contains certain configurations. You will therefore overwrite certain configurations ([the basic file is in the sources]([https://github.com/RSamaium/RPG-JS/blob/v4/packages/compiler/src/build/client-config.ts#L335])).
- `vitest`: (*object*) All [Vitest configuration](https://vitest.dev/config/). Example:
```toml
[vitest]
silent = true
```
> You will therefore overwrite configurations ([the basic file is in the sources]([https://github.com/RSamaium/RPG-JS/blob/v4/packages/compiler/src/test/vitest.config.ts#L36])).

- `express`

Expand Down
16 changes: 15 additions & 1 deletion docs/guide/inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,18 @@ The key corresponds to the type of control (used by the keyboard, the mouse, or

You have information here: [Set Inputs](/classes/keyboard.html#set-inputs)

> If you want to use keyboard numbers, don't use "1" but "n1", etc.
::: tip Keyboard numbers
If you want to use keyboard numbers, don't use "1" but "n1", etc.
:::

::: tip Mouse Events
Since v4.2.0, you can use mouse events.

Example:

```toml
[inputs.action]
name = "action"
bind = ["space", "enter", "click"],
```
:::
Loading
Loading