Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/wizcorp/megadata
Smart messaging for games
https://github.com/wizcorp/megadata
game game-development messaging nodejs typescript webpack
Last synced: 27 days ago
JSON representation
Smart messaging for games
- Host: GitHub
- URL: https://github.com/wizcorp/megadata
- Owner: Wizcorp
- Created: 2018-03-23T12:24:41.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2020-06-02T21:43:41.000Z (over 4 years ago)
- Last Synced: 2024-08-09T21:11:42.487Z (5 months ago)
- Topics: game, game-development, messaging, nodejs, typescript, webpack
- Language: TypeScript
- Size: 3.96 MB
- Stars: 8
- Watchers: 4
- Forks: 2
- Open Issues: 46
-
Metadata Files:
- Readme: Readme.md
Awesome Lists containing this project
README
# ![Megadata](./images/logo.png)
[![GitHub tag](https://img.shields.io/github/tag/Wizcorp/megadata.svg?style=flat-square)](https://github.com/Wizcorp/megadata/releases/latest)
[![npm](https://img.shields.io/npm/v/megadata.svg?style=flat-square)](https://www.npmjs.com/package/megadata)
[![npm](https://img.shields.io/npm/dt/megadata.svg?style=flat-square)](https://www.npmjs.com/package/megadata)
[![Gitter](https://img.shields.io/gitter/room/Wizcorp/megadata-typescript.svg?style=flat-square)](https://gitter.im/megadata-typescript/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)[![Greenkeeper badge](https://badges.greenkeeper.io/Wizcorp/megadata.svg?style=flat-square)](https://greenkeeper.io/)
[![Build Status: Linux & macOS](https://img.shields.io/travis/Wizcorp/megadata.svg?style=flat-square&label=ci%20linux%2Fmacos)](https://travis-ci.org/Wizcorp/megadata)
[![Build Status: Windows](https://img.shields.io/appveyor/ci/mage/megadata/master.svg?style=flat-square&label=ci%20windows)](https://ci.appveyor.com/project/mage/megadata/branch/master)
[![Coveralls branch](https://img.shields.io/coveralls/Wizcorp/megadata/master.svg?style=flat-square)](https://coveralls.io/github/Wizcorp/megadata)Megadata is a library you can use to serialize/deserialize network game
data.This library will help you deal with:
1. Defining type IDs and type classes
2. Definining the serialization/deserialization format to use
3. Re-using messages object, by creating and maintaining a message pool
4. Sharing message libraries between client (JavaScript) and server (Node.js)
5. TypeScript type checks## Requirements
- Node.js 8.0 or higher
## Installation
```shell
npm install --save megadata
```You will also need to make sure that the following configuration is set in your tsconfig.json:
```json
{
"compilerOptions": {
"experimentalDecorators": true
}
}
```## Usage
### Defining message types
> shared/messages/index.ts
```typescript
import megadata, { TypeDecorator } from 'megadata'export enum TypeIds {
Join,
Leave
}export const Type: TypeDecorator = megadata(module)
```We first create a list of message types as a `const enum` and
list the messages we will send and receive in our game. We then
generate a `@Type` decorator> shared/messages/types/Join.ts
```typescript
import { Type, TypeIds } from '../'
import MessageType from 'megadata/classes/MessageType'
import Binary, { Uint32 } from 'megadata/classes/BinarySerializationFormat'@Type(TypeIds.Join, Binary)
export default class Join extends MessageType {
@Uint32
public time: number
}
```> shared/messages/types/Leave.ts
```typescript
import { Type, TypeIds } from '../'
import MessageType from 'megadata/classes/MessageType'
import Json from 'megadata/classes/JsonSerializationFormat'@Type(TypeIds.Leave, Json)
export default class Leave extends MessageType {
public time: number
}
```Next, we define what our `Join` and `Leave` messages type will look like, and
how we should serialize and deserialize it.Megadata ships with two serialization formats:
1. **binary**: deals only with messages containing numbers, but is blazing fast
2. **json**: deals with any kind of data, but is slowerYou may notice that the `Binary` serialization format requires additional annotations
this is required to define (and optimized) the size and speed of serialization and
deserialization.### Sending and receiving messages
> server/classes/Player.ts
```typescript
import Connection from '...'
import MessageEmitter from 'megadata/classes/MessageType'
import MessageType, { IMessageType, MessageTypeData } from 'megadata/classes/MessageType'export class Player extends MessageEmitter {
constructor(private connection: Connection) {
connection.on('message', async (buffer: ArrayBuffer) => {
const message = MessageType.parse(buffer)
await this.emitAsync(message)
message.release()
})
}public async function send(type: IMessageType, data: MessageTypeData) {
const message = type.create(data)
const buffer = message.pack()
await this.connection.write(buffer)
message.release()
}
}
```Messages are recycled from an object pool to reduce the impact of garbage collection; therefore,
it is important to remember to release messages back into the object pool once you are done with them.> server/classes/Game.ts
```typescript
import Player from './Player'import Join from 'shared/messages/types/Join.ts'
export default class Game {
// ...public addPlayer(player: Player) {
player.on(Join, ({ time }) => console.log('Join time:', time))
player.on(Leave, ({ time }) => console.log('Leave time:', time))
}
}
```### Messages and events auto-loading
#### Running a Node.js server with auto-loading
Auto-loading uses `require.context`, which is a webpack-specific
API. When using Megadata with auto-loading in Node.js, you will
therefore need to load the mock provided by the library.```shell
ts-node -r megadata/register index.ts
```#### Setting types auto-loading
> shared/messages/index.ts
```typescript
import megadata, { TypeDecorator } from 'megadata'const types = require.context('./types/')
export enum TypeIds {
Join,
[...]
}export const Type: TypeDecorator = megadata(module, types)
```The following code will dynamically load type classes on demand from
the `shared/messages/types` folder. If no listeners were ever set to
listen for messages of this type, an `Event.Unknown` event will be
emitted (see below).#### Setting event handlers auto-loading for a class inheriting MessageEmitter
> server/classes/Player.ts
```typescript
import MessageEmitter, { AutoloadEvents } from 'megadata/classes/MessageEmitter'const events = require.context('../events/')
@AutoloadEvents(events)
export default class Player extends MessageEmitter {}
```A given message emitter may end up handling a large number or events. Event
handlers auto-loading provides a mechanism for breaking event handling
down into event handler files that are auto-loaded on demand. In this
case, we will auto-load all events under `server/events`.> server/events/Join.ts
```typescript
import Player from '../classes/Player'
import Join from 'shared/messages/types/Join'export default function (player: Player) {
player.on(Join, (message) => console.log('Received join event', message))
}
```Event handler files export a single default function which will receive
a message emitter instance; you may then set the even listeners according to
your needs.### Custom serialization
> shared/messages/classes/CustomSerializationFormat.ts
```typescript
import MessageType from './MessageType'
import SerializationFormat, { ISerializerFunctions } from './SerializationFormat'export default class CustomSerializationFormat extends SerializationFormat {
public create(id: I, size: number, attributes: any) {
return {
create: (...),
pack: (...),
unpack: (...),
} as ISerializerFunctions
}
}
```You can create your own custom serialization format. Above is a quick stub, but
you should have a look at the [default serialization formats](./classes) provided
by megadata.## Acknowledgements
- Initial code and implementation (JavaScript): @ronkorving
- Logo customizations: @lzubiaur## License
MIT License. Copyright (c) Wizcorp Inc.