-
-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GitOrigin-RevId: 124562564c369aaf5b61c50e9e2d7d8482643b6f
- Loading branch information
Showing
18 changed files
with
3,839 additions
and
165 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
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
60 changes: 60 additions & 0 deletions
60
docs/content/pages/core-concepts/immutable-data-structures.mdx
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,60 @@ | ||
# Immutable Data Structures | ||
|
||
All game related data structures and algorithms in Athena Crisis are "headless" and can run on the client, server, or during build time. Map and game state is represented using [_immutable persistent data structures_](https://roberterdin.github.io/2017/09/immutable-persistent-data-structures). Immutable means that instead of directly changing the game state, any action like moving or attacking a unit returns a new game state object. Persistent refers to reusing all data that doesn't change between two game states. These two concepts together make it easy to keep many game states around, make it fast to check whether changes happened between two states, and is memory efficient. | ||
|
||
Imagine a basic game state with a map that is three fields wide and one field high. The game state can be represented with an array, where each field either has a unit or not: | ||
|
||
```tsx | ||
const state = [unit, null, null]; | ||
``` | ||
|
||
Many games use an imperative model. When you want to move the unit from one position to another, you might make a change like this: | ||
|
||
```tsx | ||
state[2] = state[0]; | ||
state[0] = null; | ||
``` | ||
|
||
This directly modifies the existing state object. It now becomes hard to know what the game state was before, which can cause problems when other operations still think they are operating on a previous version of the game state. It also makes it harder to compare what changed with a state transition. | ||
|
||
Let's look at the same example with an immutable model: | ||
|
||
```tsx | ||
const state = [unit, null, null]; | ||
const newState = [null, null, unit]; | ||
``` | ||
|
||
At the core, instead of mutating the game state, we create a completely new game state object each time with the immutable model. Note that the unit, assuming its an instance of a `Unit` class, did not change. However, when you are moving a unit in Athena Crisis, it has to be marked as "moved". In the imperative version, it might look like this: | ||
|
||
```tsx | ||
const state = [unit, null, null]; | ||
const unit = state[0]; | ||
unit.moved = true; | ||
state[2] = unit; | ||
state[0] = null; | ||
``` | ||
|
||
The immutable version could look something like this: | ||
|
||
```tsx | ||
class Unit { | ||
move() { | ||
return this.copy({ | ||
moved: true, | ||
}); | ||
} | ||
} | ||
|
||
const state = [unit, null, null]; | ||
const newState = [null, null, unit.move()]; | ||
``` | ||
|
||
The imperative version is faster and memory efficient. However, if another part of the codebase is holding on to the unit, it might not know that the unit has moved, or it might not expect the unit object to be mutated. This can lead to hard to find bugs, especially when there are many variables and state changes involved. The immutable version is slower and uses more memory, especially when many things change at once. The downsides can be limited by using persistent data structures, which re-use as much data as possible between two game states. | ||
|
||
In a real world example, you might be storing unit positions in a [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) data structure which is expensive to copy each time a change is made. The immutable `Map` data structure from [Immutable.js](https://immutable-js.com/), which we released as a standalone package called [`@nkzw/immutable-map`](https://github.com/nkzw-tech/immutable-map), makes use of structral sharing to make copying cheap. It works similar to git commits, where only the changes are stored and the rest is shared between two game states. Due to this, _the immutable model can be more memory efficient and sometimes even faster than the imperative model_. | ||
|
||
_These advantages make immutable state models ideal for turn-based strategy games like Athena Crisis._ | ||
|
||
:::info[Note] | ||
Immutable.js has fallen out of favor in recent years. Its meta-programming and code size slow down app start, and many of its data structures are less relevant today. However, to our knowledge, there is no better and faster alternative of an immutable `Map` data structures in JavaScript. We published our own package that only includes `Map`, and we are welcome to contributions to speed up the package. | ||
::: |
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 @@ | ||
# The `MapData` Class | ||
|
||
[`MapData`](https://github.com/nkzw-tech/athena-crisis/blob/main/athena/MapData.tsx) |
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,7 @@ | ||
# Core Concepts – Overview | ||
|
||
This section dives into the core concepts of the codebase to give you a high-level overview of how Athena Crisis works. The technical walkthroughs primarily cover these three top level folders in the repository: | ||
|
||
- [`athena`](https://github.com/nkzw-tech/athena-crisis/tree/main/athena) → Data structures and algorithms for manipulating _map_ state (_client/server_). | ||
- [`apollo`](https://github.com/nkzw-tech/athena-crisis/tree/main/apollo) → Data structures and algorithms for manipulating _game_ state (_client/server_). | ||
- [`hera`](https://github.com/nkzw-tech/athena-crisis/tree/main/hera) → Game engine and rendering (_client_). |
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,20 @@ | ||
# Getting Started | ||
|
||
Athena Crisis is a modern retro turn-based strategy game developed by [Nakazawa Tech](https://nkzw.tech) and published by [Null](https://null.com). The source code of Athena Crisis is licensed under the [MIT License](https://github.com/nkzw-tech/athena-crisis/blob/main/LICENSE.md) and can be used to improve Athena Crisis, build additional tools, study game development with JavaScript or create entirely new turn-based strategy games. | ||
|
||
This documentation website is aimed at explaining the core architecture and provides playgrounds to try out various parts of the codebase. To get started, you can clone the codebase using `git`: | ||
|
||
```bash | ||
git clone git://github.com/nkzw-tech/athena-crisis.git | ||
``` | ||
|
||
Athena Crisis requires [Node.js](https://nodejs.org/en/download/package-manager) and the latest major version of [`pnpm`](https://pnpm.io/installation). After installing the latest versions, you can get started quickly with these commands: | ||
|
||
```bash | ||
pnpm install && pnpm dev:setup | ||
pnpm dev | ||
``` | ||
|
||
The above commands set up the repository. After they complete, you can visit [localhost:3003](http://localhost:3003/) to run the local version of this documentation website. | ||
|
||
If you prefer video content, check out [How NOT to Build a Video Game](https://www.youtube.com/watch?v=m8SmXOTM8Ec) to get an overview of the tech behind Athena Crisis. If you have questions, feel free to [join us on Discord](https://discord.gg/2VBCCep7Fk). |
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,21 @@ | ||
--- | ||
layout: landing | ||
--- | ||
|
||
import { HomePage } from 'vocs/components'; | ||
|
||
<HomePage.Root> | ||
<img alt="Athena Crisis logo" src="/athena-crisis.svg" /> | ||
<HomePage.Tagline>Open Source Docs & Playground</HomePage.Tagline> | ||
<HomePage.Description> | ||
This is a description of my documentation website. | ||
</HomePage.Description> | ||
<HomePage.Buttons> | ||
<HomePage.Button href="/getting-started" variant="accent"> | ||
Getting Started | ||
</HomePage.Button> | ||
<HomePage.Button href="https://github.com/nkzw-tech/athena-crisis"> | ||
GitHub | ||
</HomePage.Button> | ||
</HomePage.Buttons> | ||
</HomePage.Root> |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
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,25 @@ | ||
{ | ||
"name": "@deities/docs", | ||
"version": "0.0.1", | ||
"private": true, | ||
"description": "Athena Crisis Open Source Docs & Playground", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/nkzw-tech/athena-crisis.git" | ||
}, | ||
"author": "Christoph Nakazawa <[email protected]>", | ||
"type": "module", | ||
"scripts": { | ||
"build": "vocs build", | ||
"dev": "vocs dev --port 3003", | ||
"preview": "vocs preview" | ||
}, | ||
"dependencies": { | ||
"@types/react": "^18.3.1", | ||
"dunkel-theme": "^1.7.1", | ||
"licht-theme": "^1.7.1", | ||
"react": "19.0.0-canary-fd0da3eef-20240404", | ||
"react-dom": "19.0.0-canary-fd0da3eef-20240404", | ||
"vocs": "^1.0.0-alpha.49" | ||
} | ||
} |
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,83 @@ | ||
import { readFileSync } from 'node:fs'; | ||
import React from 'react'; | ||
import { defineConfig } from 'vocs'; | ||
|
||
const Licht = JSON.parse( | ||
readFileSync('./node_modules/licht-theme/licht.json', 'utf8'), | ||
); | ||
const Dunkel = JSON.parse( | ||
readFileSync('./node_modules/dunkel-theme/dunkel.json', 'utf8'), | ||
); | ||
|
||
export default defineConfig({ | ||
basePath: '/open-source', | ||
description: 'Open Source Docs & Playground', | ||
editLink: { | ||
pattern: | ||
'https://github.com/nkzw-tech/athena-crisis/tree/main/docs/content/pages/:path', | ||
text: 'Edit on GitHub', | ||
}, | ||
font: { | ||
mono: { | ||
google: 'Fira Code', | ||
}, | ||
}, | ||
head: ( | ||
<> | ||
<link href="/apple-touch-icon.png" rel="apple-touch-icon" /> | ||
</> | ||
), | ||
iconUrl: '/favicon.png', | ||
markdown: { | ||
code: { | ||
themes: { | ||
dark: Dunkel, | ||
light: Licht, | ||
}, | ||
}, | ||
}, | ||
ogImageUrl: | ||
'https://vocs.dev/api/og?logo=%logo&title=%title&description=%description', | ||
rootDir: './content', | ||
sidebar: [ | ||
{ | ||
link: '/getting-started', | ||
text: 'Getting Started', | ||
}, | ||
{ | ||
items: [ | ||
{ | ||
link: '/core-concepts/overview', | ||
text: 'Overview', | ||
}, | ||
{ | ||
link: '/core-concepts/immutable-data-structures', | ||
text: 'Immutable Data Structures', | ||
}, | ||
{ | ||
link: '/core-concepts/map-data', | ||
text: 'MapData ', | ||
}, | ||
], | ||
text: 'Core Concepts', | ||
}, | ||
], | ||
socials: [ | ||
{ | ||
icon: 'github', | ||
link: 'https://github.com/nkzw-tech/athena-crisis', | ||
}, | ||
{ | ||
icon: 'discord', | ||
link: 'https://discord.gg/2VBCCep7Fk', | ||
}, | ||
{ | ||
icon: 'x', | ||
link: 'https://twitter.com/TheAthenaCrisis', | ||
}, | ||
], | ||
theme: { | ||
accentColor: '#c3217f', | ||
}, | ||
title: 'Athena Crisis', | ||
}); |
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 |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
"private": true, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/nkzw-tech/athena-crisis-universe.git" | ||
"url": "git://github.com/nkzw-tech/athena-crisis.git" | ||
}, | ||
"author": "Christoph Nakazawa <[email protected]>", | ||
"type": "module", | ||
|
@@ -17,10 +17,11 @@ | |
"build:docker-server": "RELEASE_ID=$(git rev-parse --short HEAD) docker buildx build --load -f Dockerfile --platform=linux/amd64 --tag athena-crisis --build-arg RELEASE_ID=$RELEASE_ID .", | ||
"build:offline": "rm -rf ./dist/offline && pnpm vite build --outDir ../dist/offline -c ./offline/vite.config.ts ./offline", | ||
"build:server": "./build-server", | ||
"build:splash": "rm -rf ./dist/deimos && pnpm vite build --outDir ../dist/deimos -c ./deimos/vite.config.ts ./deimos/", | ||
"build:splash": "rm -rf ./dist/deimos && pnpm vite build --outDir ../dist/deimos -c ./deimos/vite.config.ts ./deimos/ && pnpm build:docs", | ||
"build:docs": "cd docs && pnpm build --outDir ../../dist/deimos/open-source", | ||
"build:steam-i18n": "rm -rf ./dist/steami18n && node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./ares/scripts/translateStorepage.js", | ||
"codegen": "node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./codegen/generate-all.tsx", | ||
"dev": "node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./deimos/deimos.tsx", | ||
"dev": "cd docs && pnpm dev", | ||
"dev:setup": "pnpm prisma generate && pnpm relay && pnpm codegen && pnpm fbt", | ||
"dev:update-deps": "rm -rf pnpm-lock.yaml node_modules/ **/node_modules && pnpm dev:setup", | ||
"disable-canvas": "jq '.pnpm.neverBuiltDependencies = [\"canvas\"]' package.json > package-canvas.json && mv package-canvas.json package.json && git restore pnpm-lock.yaml", | ||
|
Oops, something went wrong.