Merge pull request #229 from Liriosha/dev

Add Doxygen
This commit is contained in:
Tropical 2026-03-15 00:26:57 -05:00 committed by GitHub
commit e197fbcde6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 434 additions and 107 deletions

50
.github/workflows/build-doxygen.yml vendored Normal file
View file

@ -0,0 +1,50 @@
name: CI
on:
push:
branches: ["dev"]
paths:
- "4J.Input/**"
- "4J.Profile/**"
- "4J.Render/**"
- "4J.Storage/**"
- "Minecraft.Assets/**"
- "Minecraft.Client/**"
- "Minecraft.World/**"
- "docs/**"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Doxygen
run: sudo apt-get update && sudo apt-get install -y doxygen graphviz build-essential libsdl2-dev libgl-dev libglu1-mesa-dev libpthread-stubs0-dev
- name: Update doxygen-awesome
run: git submodule update --init --recursive
- name: Generate Docs
run: cd docs && doxygen
- name: Configure Pages
uses: actions/configure-pages@v4
- name: Upload Pages Artifacts
uses: actions/upload-pages-artifact@v4
with:
path: ./docs/html
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy Github Pages
uses: actions/deploy-pages@v4
id: deployment

3
.gitignore vendored
View file

@ -46,3 +46,6 @@ oldimpl/
*.swp
*.swo
*~
# ----- Documentation -----
docs/

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "docs/doxygen-awesome-css"]
path = docs/doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git

View file

@ -1,4 +1,4 @@
# Minecraft.Client asset structure
# Minecraft.Client Asset Structure
This is the minimum asset structure needed for the game to function.
```
AssetStructure
@ -26,7 +26,7 @@ AssetStructure
└── *.binka
```
## Windows64Media.arc contents
The potential contents of the the arc file can be seen in the `.txt` files in this folder (`movies.txt`, `media.txt`, etc...).
The contents of the the arc file can be seen in the `.txt` files in this folder (`movies.txt`, `media.txt`, etc...).
- `languages.loc` is built from `Platform/Windows64Media/loc`
- `HTMLColours.col` is built from `HTMLColours.xml`
```
@ -44,12 +44,12 @@ MediaWindows64.arc
```
## Asset locations
### Generic assets should be contained inside this folder:
- `movies/` - Flash swf files for UI
- `graphics/` - contains images used by the client (only `SaveChest.png` `MinecraftIcon.png`, `TexturePackIcon.png` are packed into the arc)
- `font/` - fonts, duh
- `res/` - actual minecraft textures and other data
- `music/` - contains background music as well as music discs
- `levels/` - contains some premade worlds (`Tutorial` is unused as we pull it from somewhere else, atleast on Windows64 asset base)
- `movies/` - Flash SWF files for Iggy
- `graphics/` - Contains images used by the client (only `SaveChest.png` `MinecraftIcon.png`, `TexturePackIcon.png` are packed into the arc)
- `font/` - Fonts, duh
- `res/` - Textures and other miscellaneous data
- `music/` - Contains background music as well as music discs
- `levels/` - Contains some premade worlds (`Tutorial` is unused as we pull it from somewhere else, atleast on Windows64 asset base)
### Platform assets are contained in Minecraft.Client/Platform/
- `Windows64Media/loc/` - Localisation/language data that we use as a source to build the languages.loc (this file gets included in arc)
- `Windows64Media/Media/` - Contains a bunch of Windows64 customised swfs and also the tutorial level (`Tutorial.pck`), these should be included in arc

View file

@ -0,0 +1,48 @@
# Network Code Implementation Notes
## Overview
The networking classes are organized as follows:
```
Game \
^ |
| |
+-----------------------------+-----------------------------+ |
| | |
v v |
Game Network Manager <--------------------------------> Network Player Interface |- platform independent layers
^ ^ |
| | |
v | |
Platform Network Manager Interface | |
^ | /
| |
v v \
Platform Network Manager Implementation(1) <------> Network Player Implementation (3) |
^ ^ |_ platform specific layers
| | |
v v |
Platform specific network code(2) Platform specific player code (4) /
```
### Notes
- In general the game should **only communicate with the `GameNetworkManager` and `NetworkPlayerInterface` APIs**, which provide a platform independent interface for networking functionality. The `GameNetworkManager` may in general have code which is aware of the game itself, but it *shouldn't have any platform-specific networking code*. It communicates with a platform specific implementation of a `PlatformNetworkManagerInterface` to achieve this.
- The platform specific layers shouldn't contain any general game code, as this is much better placed in the platform independent layers to avoid duplicating effort.
- Platform specific files for each platform for the numbered classes in the previous diagram are currently:
## Platform-Specific Files
The platform-specific implementations for each numbered class in the diagram:
| Class | Xbox 360 | Sony | Other |
|-------|---------------------------------|----------------------------|-----------------------|
| (1) | PlatformNetworkManagerXbox | PlatformNetworkManagerSony | PlatformNetworkManagerStub |
| (2) | Provided by QNET | SQRNetworkManager | Qnet stub* |
| (3) | NetworkPlayerXbox | NetworkPlayerSony | NetworkPlayerXbox |
| (4) | Provided by QNET | SQRNetworkPlayer | Qnet stub* |
\*Temporarily provided by `extra64.h`

View file

@ -1,45 +0,0 @@
NETWORK CODE IMPLEMENTATION NOTES
---------------------------------
The networking classes are organised as follows:
Game \
^ |
| |
+-----------------------------+-----------------------------+ |
| | |
v v |
Game Network Manager <--------------------------------> Network Player Interface |- platform independent layers
^ ^ |
| | |
v | |
Platform Network Manager Interface | |
^ | /
| |
v v \
Platform Network Manager Implementation(1) <------> Network Player Implementation (3) |
^ ^ |_ platform specific layers
| | |
v v |
Platform specific network code(2) Platform specific player code (4) /
In general the game should only communicate with the GameNetworkManager and NetworkPlayerInterface APIs, which provide a platform independent
interface for networking functionality. The GameNetworkManager may in general have code which is aware of the game itself, but it shouldn't have
any platform-specific networking code. It communicates with a platform specific implementation of a PlatformNetworkManagerInterface to achieve this.
The platform specific layers shouldn't contain any general game code, as this is much better placed in the platform independent layers to avoid
duplicating effort.
Platform specific files for each platform for the numbered classes in the previous diagram are currently:
Xbox 360 Sony Other
(1) PlatformNetworkManagerXbox PlatformNetworkManagerSony PlatformNetworkManagerStub
(2) Provided by QNET SQRNetworkManager Qnet stub*
(3) NetworkPlayerXbox NetworkPlayerSony NetworkPlayerXbox
(4) Provided by QNET SQRNetworkPlayer Qnet stub*
*temporarily provided by extra64.h

View file

@ -5,6 +5,24 @@
#include "../Util/DescFormatter.h"
#include "Achievement.h"
/**
* @class Achievement
* @brief Represents a Minecraft achievement.
*
* Achievements are stat objects that can be unlocked by the player.
* Each achievement has a position in the achievement tree
* a description and an optional icon and prerequisite.
*
* Use postConstruct() to register the achievement globally.
*/
/**
* @brief Performs internal initialization for the achievement.
*
* Updates the global achievement grid bounds.
* These bounds are used for rendering the
* achievement UI.
*/
void Achievement::_init() {
isGoldenVar = false;
@ -14,6 +32,16 @@ void Achievement::_init() {
if (y > Achievements::yMax) Achievements::yMax = y;
}
/**
* @brief Creates an achievement with an item icon.
*
* @param id Local achievement ID
* @param name Internal achievement name used for localization
* @param x X position in the achievement tree
* @param y Y position in the achievement tree
* @param icon Item used as the achievement icon
* @param requires Achievement object that is required to unlock this one
*/
Achievement::Achievement(int id, const std::wstring& name, int x, int y,
Item* icon, Achievement* requires)
: Stat(Achievements::ACHIEVEMENT_OFFSET + id,
@ -48,16 +76,53 @@ Achievement::Achievement(int id, const std::wstring& name, int x, int y,
y(y),
requires(requires) {}
/**
* @brief Sets the decription formatter (DescFormatter)
* @param descFormatter Pointer to the DescFormatter formatting the
* description text.
* @return self
**/
Achievement
* Achievement::setAwardLocallyOnly() {
* Achievement::setDescFormatter(DescFormatter * descFormatter) {
this->descFormatter = descFormatter;
return this;
}
/**
* @brief Returns whether the Achivement is golden
* @return boolean
*/
bool Achievement::isGolden() { return isGoldenVar; }
int Achievement::getAchievementID() {
return id - Achievements::ACHIEVEMENT_OFFSET;
}
/**
* @brief Marks the achievement as locally awarded only.
* @return self
*/
Achievement* Achievement::setAwardLocallyOnly() {
awardLocallyOnly = true;
return this;
}
/**
* @brief Marks the achievement as a golden achievement.
*
* Golden achievements are rendered differently
* in the achievement UI.
*
* @return self
*/
Achievement* Achievement::setGolden() {
isGoldenVar = true;
return this;
}
/**
* @brief Adds the achievement to the global achievement registry.
* @return self
*/
Achievement* Achievement::postConstruct() {
Stat::postConstruct();
@ -67,22 +132,20 @@ Achievement* Achievement::postConstruct() {
return this;
}
/**
* @brief Indicates that this stat represents an achievement.
*
* @return Always true
*/
bool Achievement::isAchievement() { return true; }
/**
* @brief Gets the description of an Achivement according to it's DescFormatter'
* @return wstring
**/
std::wstring Achievement::getDescription() {
if (descFormatter != NULL) {
return descFormatter->format(desc);
}
return desc;
}
Achievement* Achievement::setDescFormatter(DescFormatter* descFormatter) {
this->descFormatter = descFormatter;
return this;
}
bool Achievement::isGolden() { return isGoldenVar; }
int Achievement::getAchievementID() {
return id - Achievements::ACHIEVEMENT_OFFSET;
}

View file

@ -2,6 +2,14 @@
#include "../../Util/Arrays.h"
#include "FixedBiomeSource.h"
/**
* @brief Constructs a FixedBiomeSource with a single biome, temperature, and
* downfall.
*
* @param fixed Biome to use for the entire source
* @param temperature Temperature value for all blocks
* @param downfall Downfall value for all blocks
*/
FixedBiomeSource::FixedBiomeSource(Biome* fixed, float temperature,
float downfall) {
this->biome = fixed;
@ -9,22 +17,62 @@ FixedBiomeSource::FixedBiomeSource(Biome* fixed, float temperature,
this->downfall = downfall;
}
/**
* @brief Returns the biome at a given ChunkPos.
*
* @param cp Target chunk position
* @return Biome* Always returns the fixed biome
*/
Biome* FixedBiomeSource::getBiome(ChunkPos* cp) { return biome; }
/**
* @brief Returns the biome at specific coordinates.
*
* @param x X coordinate
* @param z Z coordinate
* @return Biome* Always returns the fixed biome
*/
Biome* FixedBiomeSource::getBiome(int x, int z) { return biome; }
/**
* @brief Returns the temperature at specific coordinates.
*
* @param x X coordinate
* @param z Z coordinate
* @return float The fixed temperature
*/
float FixedBiomeSource::getTemperature(int x, int z) { return temperature; }
/**
* @brief Fills a float array with temperature values for a rectangular region.
*
* If the array is null or too small, it will be reallocated.
*
* @param temperatures Array to fill with temperature values
* @param x Starting X coordinate
* @param z Starting Z coordinate
* @param w Width of the region
* @param h Height of the region
*/
void FixedBiomeSource::getTemperatureBlock(floatArray& temperatures, int x,
int z, int w, int h) const {
if (temperatures.data == NULL || temperatures.length < w * h) {
if (temperatures.data != NULL) delete[] temperatures.data;
if (!temperatures.data || temperatures.length < w * h) {
if (temperatures.data) delete[] temperatures.data;
temperatures = floatArray(w * h);
}
Arrays::fill(temperatures, 0, w * h, temperature);
}
/**
* @brief Returns a floatArray filled with temperatures.
*
* @param x Starting X coordinate
* @param z Starting Z coordinate
* @param w Width of the region
* @param h Height of the region
* @note 4J - Caller is responsible for deleting returned array.
* @note 4J - Temperatures array is for output only
* @return floatArray Filled with temperature values
*/
floatArray FixedBiomeSource::getTemperatureBlock(int x, int z, int w,
int h) const {
floatArray temps(w * h);
@ -32,15 +80,24 @@ floatArray FixedBiomeSource::getTemperatureBlock(int x, int z, int w,
return temps;
}
// 4J - note that caller is responsible for deleting returned array.
// temperatures array is for output only.
/**
* @brief Fills a double array with temperature values.
*
* @param temperatures Array to fill (memory allocated inside)
* @param x Starting X coordinate
* @param z Starting Z coordinate
* @param w Width of the region
* @param h Height of the region
*/
void FixedBiomeSource::getTemperatureBlock(doubleArray& temperatures, int x,
int z, int w, int h) const {
temperatures = doubleArray(w * h);
Arrays::fill(temperatures, 0, w * h, (double)temperature);
Arrays::fill(temperatures, 0, w * h, static_cast<double>(temperature));
}
/**
* @brief Fills a float array with downfall values for a rectangular region.
*/
void FixedBiomeSource::getDownfallBlock(floatArray& downfalls, int x, int z,
int w, int h) const {
if (downfalls.data == NULL || downfalls.length < w * h) {
@ -49,7 +106,9 @@ void FixedBiomeSource::getDownfallBlock(floatArray& downfalls, int x, int z,
}
Arrays::fill(downfalls, 0, w * h, downfall);
}
/**
* @brief Returns a floatArray filled with downfall values.
*/
floatArray FixedBiomeSource::getDownfallBlock(int x, int z, int w,
int h) const {
floatArray downfalls(w * h);
@ -57,30 +116,37 @@ floatArray FixedBiomeSource::getDownfallBlock(int x, int z, int w,
return downfalls;
}
/**
* @brief Returns the fixed downfall value at given coordinates.
*/
float FixedBiomeSource::getDownfall(int x, int z) const { return downfall; }
void FixedBiomeSource::getDownfallBlock(doubleArray downfalls, int x, int z,
/**
* @brief Fills a double array with downfall values.
*/
void FixedBiomeSource::getDownfallBlock(doubleArray& downfalls, int x, int z,
int w, int h) {
if (downfalls.data == NULL || downfalls.length < w * h) {
if (downfalls.data != NULL) delete[] downfalls.data;
if (!downfalls.data || downfalls.length < w * h) {
if (downfalls.data) delete[] downfalls.data;
downfalls = doubleArray(w * h);
}
Arrays::fill(downfalls, 0, w * h, (double)downfall);
Arrays::fill(downfalls, 0, w * h, static_cast<double>(downfall));
}
// 4J - caller is responsible for deleting biomes array, plus any optional
// arrays output if pointers are passed in (_temperatures, _downfalls)
/**
* @brief Fills a BiomeArray with the fixed biome for a region.
*/
void FixedBiomeSource::getBiomeBlock(BiomeArray& biomes, int x, int z, int w,
int h, bool useCache) const {
MemSect(36);
biomes = BiomeArray(w * h);
MemSect(0);
Arrays::fill(biomes, 0, w * h, biome);
}
// 4J - caller is responsible for deleting biomes array, plus any optional
// arrays output if pointers are passed in (_temperatures, _downfalls)
/**
* @brief Fills a byteArray with the biome index for a region.
*/
void FixedBiomeSource::getBiomeIndexBlock(byteArray& biomeIndices, int x, int z,
int w, int h, bool useCache) const {
MemSect(36);
@ -90,21 +156,27 @@ void FixedBiomeSource::getBiomeIndexBlock(byteArray& biomeIndices, int x, int z,
Arrays::fill(biomeIndices, 0, w * h, biomeIndex);
}
// 4J-PB added in from beyond 1.8.2
// 4J - caller is responsible for deleting biomes array, plus any optional
// arrays output if pointers are passed in (_temperatures, _downfalls)
/**
* @brief Fills a BiomeArray with the fixed biome for a region (raw version).
* @note 4J-PB Added in beyond 1.8.2
* @note 4J - Caller is responsible for deleting biomes array, plus any optional
* arrays output if pointers are passed in (_temperatures, _downfalls)
*/
void FixedBiomeSource::getRawBiomeBlock(BiomeArray& biomes, int x, int z, int w,
int h) const {
MemSect(36);
biomes = BiomeArray(w * h);
MemSect(0);
Arrays::fill(biomes, 0, w * h, biome);
}
// 4J-PB added in from beyond 1.8.2
// 4J - caller is responsible for deleting biomes array, plus any optional
// arrays output if pointers are passed in (_temperatures, _downfalls)
/**
* @brief Returns a raw BiomeArray.
* @note 4J-PB Added in beyond 1.8.2
* @note 4J - caller is responsible for deleting biomes array, plus any
* optional arrays output if pointers are passed in (_temperatures,
* _downfalls)
*/
BiomeArray FixedBiomeSource::getRawBiomeBlock(int x, int z, int w,
int h) const {
BiomeArray biomes;
@ -112,32 +184,42 @@ BiomeArray FixedBiomeSource::getRawBiomeBlock(int x, int z, int w,
return biomes;
}
/**
* @brief Finds a biome within a radius randomly.
*/
TilePos* FixedBiomeSource::findBiome(int x, int z, int r, Biome* toFind,
Random* random) {
if (toFind == biome) {
return new TilePos(x - r + random->nextInt(r * 2 + 1), 0,
z - r + random->nextInt(r * 2 + 1));
}
return NULL;
return nullptr;
}
/**
* @brief Finds a biome from a list of allowed biomes randomly.
*/
TilePos* FixedBiomeSource::findBiome(int x, int z, int r,
std::vector<Biome*> allowed,
const std::vector<Biome*>& allowed,
Random* random) {
if (find(allowed.begin(), allowed.end(), biome) != allowed.end()) {
return new TilePos(x - r + random->nextInt(r * 2 + 1), 0,
z - r + random->nextInt(r * 2 + 1));
}
return NULL;
return nullptr;
}
/**
* @brief Checks if the allowed biome matches the fixed biome.
*/
bool FixedBiomeSource::containsOnly(int x, int z, int r, Biome* allowed) {
return allowed == biome;
}
/**
* @brief Checks if the fixed biome is in the allowed list.
*/
bool FixedBiomeSource::containsOnly(int x, int z, int r,
std::vector<Biome*> allowed) {
const std::vector<Biome*>& allowed) {
return find(allowed.begin(), allowed.end(), biome) != allowed.end();
}
}

View file

@ -1,16 +1,16 @@
#pragma once
#include <vector>
#include "BiomeSource.h"
class FixedBiomeSource : public BiomeSource {
private:
private:
Biome* biome;
float temperature, downfall;
public:
public:
using BiomeSource::getTemperature;
FixedBiomeSource(Biome* fixed, float temperature, float downfall);
virtual Biome* getBiome(ChunkPos* cp);
virtual Biome* getBiome(int x, int z);
virtual float getTemperature(int x, int z);
@ -23,23 +23,23 @@ public:
int h) const;
virtual floatArray getDownfallBlock(int x, int z, int w, int h) const;
virtual float getDownfall(int x, int z) const;
virtual void getDownfallBlock(doubleArray downfalls, int x, int z, int w,
virtual void getDownfallBlock(doubleArray& downfalls, int x, int z, int w,
int h);
virtual void getBiomeBlock(BiomeArray& biomes, int x, int z, int w, int h,
bool useCache) const;
virtual void getBiomeIndexBlock(byteArray& biomeIndices, int x, int z,
int w, int h, bool useCache) const;
// 4J-PB added in from beyond 1.8.2
virtual BiomeArray getRawBiomeBlock(int x, int z, int w, int h) const;
virtual void getRawBiomeBlock(BiomeArray& biomes, int x, int z, int w,
int h) const;
////////////////////////////////////
virtual TilePos* findBiome(int x, int z, int r, Biome* toFind,
Random* random);
virtual TilePos* findBiome(int x, int z, int r, std::vector<Biome*> allowed,
virtual TilePos* findBiome(int x, int z, int r,
const std::vector<Biome*>& allowed,
Random* random);
virtual bool containsOnly(int x, int z, int r, Biome* allowed);
virtual bool containsOnly(int x, int z, int r, std::vector<Biome*> allowed);
virtual bool containsOnly(
int x, int z, int r,
const std::vector<Biome*>& allowed);
};

57
docs/Doxyfile Normal file
View file

@ -0,0 +1,57 @@
#---------------------------------------------------------------------------
# File Config
#---------------------------------------------------------------------------
PROJECT_NAME = "4JCraft"
INPUT = ../4J.Input \
../4J.Profile \
../4J.Render \
../4J.Storage \
../Minecraft.Assets \
../Minecraft.Client \
../Minecraft.World \
./doxymain.md
RECURSIVE = YES
EXCLUDE_PATTERNS = \
*_test.cpp \
*/tests/* \
*/d3d*.h \
*/dxgi*.h \
*/dinput*.h \
*/xaudio*.h \
*/xinput*.h \
*/boost/* \
*/Platform/Durango/* \
*/Platform/Orbis/* \
*/Platform/PS3/* \
*/Platform/PSVita/* \
*/Platform/Windows64/* \
*/Platform/Xbox/*
# Excluding all platform specific code except for Linux since the doc compiler runs on it so it wont shit itself
#---------------------------------------------------------------------------
# HTML Config shit
#---------------------------------------------------------------------------
HTML_EXTRA_STYLESHEET = \
doxygen-awesome-css/doxygen-awesome.css \
doxygen-awesome-css/doxygen-awesome-sidebar-only.css \
doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css
HTML_EXTRA_FILES = \
doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js \
doxygen-awesome-css/doxygen-awesome-interactive-toc.js \
doxygen-awesome-css/doxygen-awesome-tabs.js \
doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js \
doxygen-awesome-css/doxygen-awesome-paragraph-link.js
USE_MDFILE_AS_MAINPAGE = doxymain.md
HTML_HEADER = header.html
HTML_COLORSTYLE = LIGHT
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# Misc
#---------------------------------------------------------------------------
# Disable LaTEX output since we literally dont care
GENERATE_LATEX = FALSE
GENERATE_TREEVIEW = YES

@ -0,0 +1 @@
Subproject commit 1f3620084ff75734ed192101acf40e9dff01d848

28
docs/doxymain.md Normal file
View file

@ -0,0 +1,28 @@
# Welcome to the 4JCraft Docs!
[![Build (Linux, x86_64)](https://github.com/Liriosha/4jcraft/actions/workflows/build-linux.yml/badge.svg)](https://github.com/Liriosha/4jcraft/actions/workflows/build-linux.yml) [![GitHub latest commit](https://badgen.net/github/last-commit/4jcraft/4jcraft)](https://GitHub.com/4jcraft/4jcraft/commit/) [![GitHub commits](https://badgen.net/github/commits/4jcraft/4jcraft)](https://GitHub.com/4jcraft/4jcraft/commit/)
> A cross-platform port of \htmlonly Minecraft\endhtmlonly Legacy Console Edition
4JCraft is a modified version of the \htmlonly Minecraft\endhtmlonly Console Legacy Edition aimed on porting old \htmlonly Minecraft\endhtmlonly to different platforms (such as Linux, Android, Emscripten, etc.) and refactoring the codebase to improve organization and use modern C++ features.
For more info please read the [README](https://github.com/4jcraft/4jcraft/blob/dev/README.md)
Join our community!
\htmlonly
<style>
html.dark-mode a.invert-dark img {
filter: invert(1) brightness(1.1);
transition: filter 0.3s ease;
}
html.light-mode a.invert-dark img {
filter: invert(0);
}
</style>
<br>
\endhtmlonly
<a href="https://discord.gg/zFCwRWkkUg" class="invert-dark" style="margin-right:16px; display:inline-block;">
<img src="https://raw.githubusercontent.com/simple-icons/simple-icons/f89e1dfeb23652c02af7d3400fa16452b04c10f5/icons/discord.svg" width="64" height="64">
</a>
<a href="https://steamcommunity.com/groups/4JCraft" class="invert-dark" style="margin-right:10px; display:inline-block;">
<img src="https://raw.githubusercontent.com/simple-icons/simple-icons/f89e1dfeb23652c02af7d3400fa16452b04c10f5/icons/steam.svg" width="64" height="64">
</a>

37
docs/header.html Normal file
View file

@ -0,0 +1,37 @@
<head>
<meta content="$projectname Documentation - $title" property="og:title" />
<meta content="The documentation for the $projectname Project" property="og:description" />
<meta content="https://raw.githubusercontent.com/4jcraft/4jcraft/dev/.github-assets/logo.jpg"" property="og:image" />
<meta content="#983E3C" data-react-helmet="true" name="theme-color" />
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.16.1"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<title>$projectname - $title</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<script type="text/javascript" src="clipboard.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript">
DoxygenAwesomeDarkModeToggle.init()
</script>
<link rel="icon" href="https://raw.githubusercontent.com/4jcraft/4jcraft/refs/heads/dev/.github-assets/logo.jpg" type="image/x-icon">
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript" src="cookie.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen-awesome.css" rel="stylesheet" type="text/css"/>
<link href="doxygen-awesome-sidebar-only.css" rel="stylesheet" type="text/css"/>
<link href="doxygen-awesome-sidebar-only-darkmode-toggle.css" rel="stylesheet" type="text/css"/>
<div style="display: flex; align-items: center; padding: 10px 0 10px 20px;">
<img src="https://raw.githubusercontent.com/4jcraft/4jcraft/dev/.github-assets/logo.jpg"
alt="$projectname logo"
style="height:60px; margin-right:10px;">
<span style="font-size: 1.8em; font-weight: bold;">$projectname</span>
</div>
</head>