-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
6,182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# M2RS | ||
|
||
M2RS is an experimental projet which targets to entierly rewrite the game [Metin2](https://fr.wikipedia.org/wiki/Metin2) (an old Korean MMORPG) using pure Rust and [wgpu](https://github.com/gfx-rs/wgpu). | ||
|
||
## Why I'm doing this | ||
|
||
- I love Metin2, Rust, Web, graphics programming and performance critical things | ||
- I was looking for a challenging project | ||
- Because I can and you've probably already heard « L'impossible n'est pas Français 🇫🇷 » | ||
|
||
## Features | ||
- `WASM` support | ||
- [x] std::time replaced by [web_time](https://docs.rs/web-time/latest/web_time/) | ||
- [x] assets loading using [reqwest](https://docs.rs/reqwest/latest/reqwest/) | ||
- `GLTF` support | ||
- [x] material | ||
- [x] mesh | ||
- [x] skeleton | ||
- [x] animation clip | ||
- `AnimationMixer` | ||
- [x] frames interpolation | ||
- [x] blend two clips when playing a new clip | ||
- `Character` | ||
- [x] allow characters to control it's own animation mixer (pc/npc basically have more than one "wait" animation, we must play them randomly) | ||
- [ ] dynamic `Object3DInstance` loading using (main) character position | ||
- [ ] create character controller | ||
- [ ] basic collisions (using 2d algorithms for performance reasons) | ||
- `ThirdPersonCamera` | ||
- [ ] third person camera | ||
- `BoneAttachement` | ||
- [ ] allow `Object3D` to be attached to a skeleton bone (hairs, weapons) | ||
- `Terrain` | ||
- [x] parse and generate terrain chunks | ||
- [x] shader | ||
- [ ] shadows | ||
- [-] raycast to make characters walk above the ground | ||
- [-] objects | ||
- [ ] trees | ||
- [x] water geometry | ||
- [x] water shader | ||
- `Environment` | ||
- [ ] sun light that follow a realistic path between day and night | ||
- [ ] environment colors | ||
- [ ] fog | ||
- [ ] clouds | ||
- [ ] skybox | ||
- `Particle system` | ||
- [ ] ??? | ||
|
||
- `CLI` | ||
- [x] textureset.txt | ||
- [ ] setting.txt | ||
- [ ] areaambiencedata.txt | ||
- [x] areadata.txt | ||
- [ ] areaproperty.txt | ||
- [ ] property | ||
|
||
## Optimization track | ||
- `GLTF` loader currently produces 4 skeletons if there is 4 skinned mesh linked to the same skeleton. | ||
- Water generation is currently slow due to vertices height comparaison between two planes without being equal in vertices count (HashMap set/get overhead) | ||
|
||
## Start | ||
|
||
To start the game, run the following command and Vulkan or Metal will be used for rendering depending on the platform (Windows, Linux or macOS). | ||
|
||
```bash | ||
cargo run --bin m2rs --release | ||
``` | ||
|
||
## Export in the browser (WASM) | ||
|
||
In order to export both WASM and JS glue code, you will need to install [wasm-pack](https://github.com/rustwasm/wasm-pack). | ||
|
||
```bash | ||
cargo install wasm-pack | ||
``` | ||
|
||
Then, you can use `wasm-pack` command to export the game. | ||
|
||
```bash | ||
wasm-pack build --target web | ||
``` | ||
|
||
Finally, use a live server to serve the content and open index.html on the selected port. I personnally use [Live Server VSCode extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer). | ||
|
||
|
||
## CLI | ||
|
||
A CLI is available if assets need conversion. Currently supported conversions are: | ||
- `textureset.txt` -> `textureset.json` | ||
|
||
In the future, this CLI will be used to optimize + encrypt assets. | ||
|
||
```bash | ||
cargo run --bin cli --release | ||
``` | ||
|
||
## DDS to PNG | ||
All DDS files should be converted to PNG files. I usually do this with [imagemagick](https://imagemagick.org/): | ||
```bash | ||
find . -type f -name "*.dds" -exec mogrify -format png {} + | ||
``` | ||
|
||
## FBX to GLTF | ||
To convert FBX files to GLTF: | ||
- [w/ skinning](https://github.com/BabylonJS/Exporters/releases) | ||
- [w/o skinning](https://github.com/facebookincubator/FBX2glTF/releases) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
|
||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; | ||
|
||
export interface InitOutput { | ||
readonly memory: WebAssembly.Memory; | ||
} | ||
|
||
export type SyncInitInput = BufferSource | WebAssembly.Module; | ||
/** | ||
* Instantiates the given `module`, which can either be bytes or | ||
* a precompiled `WebAssembly.Module`. | ||
* | ||
* @param {SyncInitInput} module | ||
* | ||
* @returns {InitOutput} | ||
*/ | ||
export function initSync(module: SyncInitInput): InitOutput; | ||
|
||
/** | ||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and | ||
* for everything else, calls `WebAssembly.instantiate` directly. | ||
* | ||
* @param {InitInput | Promise<InitInput>} module_or_path | ||
* | ||
* @returns {Promise<InitOutput>} | ||
*/ | ||
export default function __wbg_init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
let wasm; | ||
|
||
async function __wbg_load(module, imports) { | ||
if (typeof Response === 'function' && module instanceof Response) { | ||
if (typeof WebAssembly.instantiateStreaming === 'function') { | ||
try { | ||
return await WebAssembly.instantiateStreaming(module, imports); | ||
|
||
} catch (e) { | ||
if (module.headers.get('Content-Type') != 'application/wasm') { | ||
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); | ||
|
||
} else { | ||
throw e; | ||
} | ||
} | ||
} | ||
|
||
const bytes = await module.arrayBuffer(); | ||
return await WebAssembly.instantiate(bytes, imports); | ||
|
||
} else { | ||
const instance = await WebAssembly.instantiate(module, imports); | ||
|
||
if (instance instanceof WebAssembly.Instance) { | ||
return { instance, module }; | ||
|
||
} else { | ||
return instance; | ||
} | ||
} | ||
} | ||
|
||
function __wbg_get_imports() { | ||
const imports = {}; | ||
imports.wbg = {}; | ||
|
||
return imports; | ||
} | ||
|
||
function __wbg_init_memory(imports, maybe_memory) { | ||
|
||
} | ||
|
||
function __wbg_finalize_init(instance, module) { | ||
wasm = instance.exports; | ||
__wbg_init.__wbindgen_wasm_module = module; | ||
|
||
|
||
return wasm; | ||
} | ||
|
||
function initSync(module) { | ||
if (wasm !== undefined) return wasm; | ||
|
||
const imports = __wbg_get_imports(); | ||
|
||
__wbg_init_memory(imports); | ||
|
||
if (!(module instanceof WebAssembly.Module)) { | ||
module = new WebAssembly.Module(module); | ||
} | ||
|
||
const instance = new WebAssembly.Instance(module, imports); | ||
|
||
return __wbg_finalize_init(instance, module); | ||
} | ||
|
||
async function __wbg_init(input) { | ||
if (wasm !== undefined) return wasm; | ||
|
||
if (typeof input === 'undefined') { | ||
input = new URL('game_bg.wasm', import.meta.url); | ||
} | ||
const imports = __wbg_get_imports(); | ||
|
||
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { | ||
input = fetch(input); | ||
} | ||
|
||
__wbg_init_memory(imports); | ||
|
||
const { instance, module } = await __wbg_load(await input, imports); | ||
|
||
return __wbg_finalize_init(instance, module); | ||
} | ||
|
||
export { initSync } | ||
export default __wbg_init; |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
export const memory: WebAssembly.Memory; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
/** | ||
* @returns {Promise<void>} | ||
*/ | ||
export function run(): Promise<void>; | ||
|
||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; | ||
|
||
export interface InitOutput { | ||
readonly memory: WebAssembly.Memory; | ||
readonly run: () => void; | ||
readonly wgpu_compute_pass_set_pipeline: (a: number, b: number) => void; | ||
readonly wgpu_compute_pass_set_bind_group: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_compute_pass_set_push_constant: (a: number, b: number, c: number, d: number) => void; | ||
readonly wgpu_compute_pass_insert_debug_marker: (a: number, b: number, c: number) => void; | ||
readonly wgpu_compute_pass_push_debug_group: (a: number, b: number, c: number) => void; | ||
readonly wgpu_compute_pass_pop_debug_group: (a: number) => void; | ||
readonly wgpu_compute_pass_write_timestamp: (a: number, b: number, c: number) => void; | ||
readonly wgpu_compute_pass_begin_pipeline_statistics_query: (a: number, b: number, c: number) => void; | ||
readonly wgpu_compute_pass_end_pipeline_statistics_query: (a: number) => void; | ||
readonly wgpu_compute_pass_dispatch_workgroups: (a: number, b: number, c: number, d: number) => void; | ||
readonly wgpu_compute_pass_dispatch_workgroups_indirect: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_bundle_set_pipeline: (a: number, b: number) => void; | ||
readonly wgpu_render_bundle_set_bind_group: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_bundle_set_vertex_buffer: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_bundle_set_push_constants: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_bundle_draw: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_bundle_draw_indexed: (a: number, b: number, c: number, d: number, e: number, f: number) => void; | ||
readonly wgpu_render_bundle_draw_indirect: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_bundle_draw_indexed_indirect: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_pass_set_pipeline: (a: number, b: number) => void; | ||
readonly wgpu_render_pass_set_bind_group: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_pass_set_vertex_buffer: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_pass_set_push_constants: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_pass_draw: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_pass_draw_indexed: (a: number, b: number, c: number, d: number, e: number, f: number) => void; | ||
readonly wgpu_render_pass_draw_indirect: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_pass_draw_indexed_indirect: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_pass_multi_draw_indirect: (a: number, b: number, c: number, d: number) => void; | ||
readonly wgpu_render_pass_multi_draw_indexed_indirect: (a: number, b: number, c: number, d: number) => void; | ||
readonly wgpu_render_pass_multi_draw_indirect_count: (a: number, b: number, c: number, d: number, e: number, f: number) => void; | ||
readonly wgpu_render_pass_multi_draw_indexed_indirect_count: (a: number, b: number, c: number, d: number, e: number, f: number) => void; | ||
readonly wgpu_render_pass_set_blend_constant: (a: number, b: number) => void; | ||
readonly wgpu_render_pass_set_scissor_rect: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_pass_set_viewport: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; | ||
readonly wgpu_render_pass_set_stencil_reference: (a: number, b: number) => void; | ||
readonly wgpu_render_pass_insert_debug_marker: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_pass_push_debug_group: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_pass_pop_debug_group: (a: number) => void; | ||
readonly wgpu_render_pass_write_timestamp: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_pass_begin_occlusion_query: (a: number, b: number) => void; | ||
readonly wgpu_render_pass_end_occlusion_query: (a: number) => void; | ||
readonly wgpu_render_pass_begin_pipeline_statistics_query: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_pass_end_pipeline_statistics_query: (a: number) => void; | ||
readonly wgpu_render_pass_execute_bundles: (a: number, b: number, c: number) => void; | ||
readonly wgpu_render_bundle_set_index_buffer: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_bundle_pop_debug_group: (a: number) => void; | ||
readonly wgpu_render_bundle_insert_debug_marker: (a: number, b: number) => void; | ||
readonly wgpu_render_pass_set_index_buffer: (a: number, b: number, c: number, d: number, e: number) => void; | ||
readonly wgpu_render_bundle_push_debug_group: (a: number, b: number) => void; | ||
readonly __wbindgen_malloc: (a: number, b: number) => number; | ||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; | ||
readonly __wbindgen_export_2: WebAssembly.Table; | ||
readonly wasm_bindgen__convert__closures__invoke1_mut__h965d7cf806862447: (a: number, b: number, c: number) => void; | ||
readonly wasm_bindgen__convert__closures__invoke0_mut__hc43470411bc3d8ac: (a: number, b: number) => void; | ||
readonly wasm_bindgen__convert__closures__invoke2_mut__h3fd7c17d84333042: (a: number, b: number, c: number, d: number) => void; | ||
readonly wasm_bindgen__convert__closures__invoke1_mut__h1b18c64b843c17a3: (a: number, b: number, c: number) => void; | ||
readonly wasm_bindgen__convert__closures__invoke0_mut__h789244e6b087238b: (a: number, b: number) => void; | ||
readonly wasm_bindgen__convert__closures__invoke1_mut__haea07ce96dffa68d: (a: number, b: number, c: number) => void; | ||
readonly wasm_bindgen__convert__closures__invoke1_mut__h60027181182f5300: (a: number, b: number, c: number) => void; | ||
readonly __wbindgen_free: (a: number, b: number, c: number) => void; | ||
readonly __wbindgen_exn_store: (a: number) => void; | ||
readonly __wbindgen_start: () => void; | ||
} | ||
|
||
export type SyncInitInput = BufferSource | WebAssembly.Module; | ||
/** | ||
* Instantiates the given `module`, which can either be bytes or | ||
* a precompiled `WebAssembly.Module`. | ||
* | ||
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated. | ||
* | ||
* @returns {InitOutput} | ||
*/ | ||
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput; | ||
|
||
/** | ||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and | ||
* for everything else, calls `WebAssembly.instantiate` directly. | ||
* | ||
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated. | ||
* | ||
* @returns {Promise<InitOutput>} | ||
*/ | ||
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>; |
Oops, something went wrong.