summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.txt18
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.txt14
-rw-r--r--bowshock-small.svg2
-rw-r--r--bowshock.svg2
-rw-r--r--bowshock/CMakeLists.txt103
-rw-r--r--bowshock/include/bow/application.hxx68
-rw-r--r--bowshock/include/bow/base.hxx181
-rw-r--r--bowshock/include/bow/client.hxx156
-rw-r--r--bowshock/include/bow/logic.hxx200
-rw-r--r--bowshock/include/bow/runtime.hxx18
-rw-r--r--bowshock/include/bow/save.hxx70
-rw-r--r--bowshock/include/bow/server.hxx58
-rw-r--r--bowshock/shader/main.frag.glsl2
-rw-r--r--bowshock/shader/main.vert.glsl2
-rw-r--r--bowshock/source/application/Application/constructor.cxx44
-rw-r--r--bowshock/source/application/Application/destructor.cxx16
-rw-r--r--bowshock/source/application/Application/get_quote.cxx (renamed from bowshock/source/application/bow/get_quote.cxx)80
-rw-r--r--bowshock/source/application/Application/initialise_signal.cxx (renamed from bowshock/source/application/bow/initialise_signal.cxx)21
-rw-r--r--bowshock/source/application/Application/parse_parameters.cxx64
-rw-r--r--bowshock/source/application/Application/print_credits.cxx (renamed from bowshock/source/application/bow/print_credits.cxx)11
-rw-r--r--bowshock/source/application/Application/print_help.cxx (renamed from bowshock/source/application/bow/print_help.cxx)9
-rw-r--r--bowshock/source/application/Application/run.cxx55
-rw-r--r--bowshock/source/application/bow/configure.cxx44
-rw-r--r--bowshock/source/application/bow/destructor.cxx19
-rw-r--r--bowshock/source/application/bow/initialise_graphics.cxx56
-rw-r--r--bowshock/source/application/bow/initialise_random.cxx14
-rw-r--r--bowshock/source/application/bow/loop.cxx124
-rw-r--r--bowshock/source/application/bow/poll_events.cxx20
-rw-r--r--bowshock/source/application/bow/print_quote.cxx22
-rw-r--r--bowshock/source/application/bow/run.cxx64
-rw-r--r--bowshock/source/base/home_directory.cxx9
-rw-r--r--bowshock/source/base/object_type_string.cxx29
-rw-r--r--bowshock/source/base/random.cxx21
-rw-r--r--bowshock/source/base/save_path.cxx26
-rw-r--r--bowshock/source/client/Client/constructor.cxx29
-rw-r--r--bowshock/source/client/Client/destructor.cxx11
-rw-r--r--bowshock/source/client/Client/poll_events.cxx20
-rw-r--r--bowshock/source/client/Client/run.cxx64
-rw-r--r--bowshock/source/client/Client/save_path.cxx13
-rw-r--r--bowshock/source/client/Client/start_sequence.cxx (renamed from bowshock/source/application/bow/start_sequence.cxx)14
-rw-r--r--bowshock/source/client/PlayerData/constructor.cxx24
-rw-r--r--bowshock/source/client/PlayerData/decode_save.cxx89
-rw-r--r--bowshock/source/client/PlayerData/encode_save.cxx60
-rw-r--r--bowshock/source/client/PlayerData/load.cxx26
-rw-r--r--bowshock/source/client/PlayerData/read_file.cxx31
-rw-r--r--bowshock/source/client/PlayerData/save.cxx20
-rw-r--r--bowshock/source/client/PlayerData/write_file.cxx23
-rw-r--r--bowshock/source/client/Renderer/constructor.cxx59
-rw-r--r--bowshock/source/client/Renderer/destructor.cxx13
-rw-r--r--bowshock/source/client/Renderer/render.cxx23
-rw-r--r--bowshock/source/client/ShaderProgram/compile_shader.cxx (renamed from bowshock/source/application/bow/compile_shader_program.cxx)82
-rw-r--r--bowshock/source/client/ShaderProgram/constructor.cxx32
-rw-r--r--bowshock/source/client/ShaderProgram/destructor.cxx9
-rw-r--r--bowshock/source/logic/Canister/constructor.cxx25
-rw-r--r--bowshock/source/logic/Canister/object_type_string.cxx12
-rw-r--r--bowshock/source/logic/Object/object_type_string.cxx12
-rw-r--r--bowshock/source/logic/Ship/constructor.cxx25
-rw-r--r--bowshock/source/logic/Ship/net_mass.cxx9
-rw-r--r--bowshock/source/logic/Ship/object_type_string.cxx12
-rw-r--r--bowshock/source/logic/Star/constructor.cxx23
-rw-r--r--bowshock/source/logic/Star/object_type_string.cxx12
-rw-r--r--bowshock/source/logic/Station/constructor.cxx23
-rw-r--r--bowshock/source/logic/Station/object_type_string.cxx12
-rw-r--r--bowshock/source/logic/World/constructor.cxx23
-rw-r--r--bowshock/source/logic/World/object_type_string.cxx12
-rw-r--r--bowshock/source/logic/ship_mass.cxx10
-rw-r--r--bowshock/source/logic/simulate.cxx17
-rw-r--r--bowshock/source/logic/ware_mass.cxx9
-rw-r--r--bowshock/source/main.cxx9
-rw-r--r--bowshock/source/runtime/add_object.cxx18
-rw-r--r--bowshock/source/runtime/delete_objects.cxx20
-rw-r--r--bowshock/source/runtime/generate_system.cxx74
-rw-r--r--bowshock/source/save/continue_save.cxx90
-rw-r--r--bowshock/source/save/decode_save.cxx35
-rw-r--r--bowshock/source/save/encode_save.cxx35
-rw-r--r--bowshock/source/save/new_save.cxx46
-rw-r--r--bowshock/source/save/save.cxx53
-rw-r--r--bowshock/source/server/Server/destructor.cxx21
-rw-r--r--bowshock/source/server/Server/start.cxx28
-rw-r--r--bowshock/source/server/ServerInstance/add_object.cxx25
-rw-r--r--bowshock/source/server/ServerInstance/constructor.cxx9
-rw-r--r--bowshock/source/server/ServerInstance/delete_objects.cxx21
-rw-r--r--bowshock/source/server/ServerInstance/generate_system.cxx43
-rw-r--r--bowshock/source/server/ServerInstance/gravitate.cxx (renamed from bowshock/source/logic/gravitate.cxx)5
-rw-r--r--bowshock/source/server/ServerInstance/loop.cxx48
-rw-r--r--bowshock/source/server/ServerInstance/move.cxx (renamed from bowshock/source/logic/move.cxx)3
-rw-r--r--bowshock/source/server/ServerInstance/run.cxx18
-rw-r--r--bowshock/source/server/ServerInstance/simulate.cxx17
89 files changed, 1855 insertions, 1285 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index a6b7a72..87d9cc6 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -47,6 +47,24 @@
* Fix logs;
* Fix save loader;
+* Update readme
+* Split program into client-side and server-side
+* Use inheritance for objects (instead of using unions) and rework them
+* Rework application structure
+* Remove 'random' facilities
+* Improve commenting
+* Update and fix quotes
+* Use OpenGL 3.2
+* Allow sixteen characters in commander names (was 14).
+* Update save format (bump format version)
+* Update default name: Caelum => Corneille
+* Create app-specific directory (save files in a subdirectory here)
+* Rework save path setting
+* Rework terminal parameters
+* Update help print
+* Add copyright symbol to startup notice
+* Bump version specified in CMake
+
# 0.B.2
* Fix data directory not being set correctly by CMake;
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a90814f..d90ad33 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.21)
project(
bowshock
- VERSION 0.11.2
+ VERSION 0.12.0
HOMEPAGE_URL "https://mandelbrot.dk/bowshock"
LANGUAGES C CXX
)
diff --git a/README.txt b/README.txt
index 643c145..6bacdea 100644
--- a/README.txt
+++ b/README.txt
@@ -9,16 +9,17 @@ Read: "CHANGELOG.txt"
Bowshock uses CMake as its build system. The standard option CMAKE_BUILD_TYPE
may be set to either "Release" or "Debug", depending on the build type.
-The program is written in C++20, and a conforming compiler is therefore
-required.
+The main program is written in C++20, and a conforming compiler is therefore
+required. OpenGL 3.2 is used for rendering, and the shaders are therefore
+written in GLSL 1.50.
Before compilation, an appropriate GLAD loader must be downloaded from a web
instance. I use the one on dav1d.de, with the following settings:
-<https://glad.dav1d.de/#language=c&specification=gl&api=gl%3D4.0&api=gles1%3Dnone&api=gles2%3Dnone&api=glsc2%3Dnone&profile=core&loader=on>
+<https://glad.dav1d.de/#language=c&specification=gl&api=gl%3D3.2&api=gles1%3Dnone&api=gles2%3Dnone&api=glsc2%3Dnone&profile=core&loader=on>
The script "extractGlad.sh" will extract "glad.zip" (or any other archive - if
-specified) to "glad". It also copies a CMAKE lists file to the directory, and
+specified) to "glad". It also copies a CMake lists file to the directory, and
CMake will automatically include this and build GLAD.
Before running - however - the data directory must be installed. This can be
@@ -37,11 +38,12 @@ rm -fr datdir && \
cmake -Bbuild -DBOW_DATA_DIRECTORY="${PWD}/datdir" -DCMAKE_BUILD_TYPE=Debug . && \
./install.sh data "${PWD}/datdir"
-... and from there just use the following to rebuild the project:
+... and from there just use the following to build the project:
clear && \
./validateShaders.py && \
-cmake --build build && build/bowshock/bowshock --skip
+cmake --build build && \
+build/bowshock/bowshock --skip
## SHADER VALIDATION
diff --git a/bowshock-small.svg b/bowshock-small.svg
index bf33e9a..e7b1a69 100644
--- a/bowshock-small.svg
+++ b/bowshock-small.svg
@@ -1,4 +1,4 @@
-<!-- Copyright 2023 Gabriel Jensen. -->
+<!-- Copyright 2023 Gabriel Bjørnager Jensen. -->
<svg height="96" width="96" xmlns="http://www.w3.org/2000/svg">
<!-- background -->
<circle cx="48" cy="54" fill="#B61833" r="36" />
diff --git a/bowshock.svg b/bowshock.svg
index 26f8460..f4cef4b 100644
--- a/bowshock.svg
+++ b/bowshock.svg
@@ -1,4 +1,4 @@
-<!-- Copyright 2023 Gabriel Jensen. -->
+<!-- Copyright 2023 Gabriel Bjørnager Jensen. -->
<svg height="120" width="120" xmlns="http://www.w3.org/2000/svg">
<!-- background -->
<rect fill="#FFEEE0" height="120" width="120" x="0" y="0" />
diff --git a/bowshock/CMakeLists.txt b/bowshock/CMakeLists.txt
index 30c19a0..cd09057 100644
--- a/bowshock/CMakeLists.txt
+++ b/bowshock/CMakeLists.txt
@@ -12,40 +12,64 @@ set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(
bowshock
- "source/application/bow/compile_shader_program.cxx"
- "source/application/bow/configure.cxx"
- "source/application/bow/destructor.cxx"
- "source/application/bow/get_quote.cxx"
- "source/application/bow/initialise_graphics.cxx"
- "source/application/bow/initialise_random.cxx"
- "source/application/bow/initialise_signal.cxx"
- "source/application/bow/loop.cxx"
- "source/application/bow/poll_events.cxx"
- "source/application/bow/print_credits.cxx"
- "source/application/bow/print_help.cxx"
- "source/application/bow/print_quote.cxx"
- "source/application/bow/run.cxx"
- "source/application/bow/start_sequence.cxx"
+ "source/main.cxx"
+
+ "source/application/Application/constructor.cxx"
+ "source/application/Application/destructor.cxx"
+ "source/application/Application/get_quote.cxx"
+ "source/application/Application/initialise_signal.cxx"
+ "source/application/Application/parse_parameters.cxx"
+ "source/application/Application/print_credits.cxx"
+ "source/application/Application/print_help.cxx"
+ "source/application/Application/run.cxx"
+
+ "source/client/Client/constructor.cxx"
+ "source/client/Client/destructor.cxx"
+ "source/client/Client/poll_events.cxx"
+ "source/client/Client/run.cxx"
+ "source/client/Client/save_path.cxx"
+ "source/client/Client/start_sequence.cxx"
+ "source/client/PlayerData/constructor.cxx"
+ "source/client/PlayerData/decode_save.cxx"
+ "source/client/PlayerData/encode_save.cxx"
+ "source/client/PlayerData/load.cxx"
+ "source/client/PlayerData/read_file.cxx"
+ "source/client/PlayerData/save.cxx"
+ "source/client/PlayerData/write_file.cxx"
+ "source/client/Renderer/constructor.cxx"
+ "source/client/Renderer/destructor.cxx"
+ "source/client/Renderer/render.cxx"
+ "source/client/ShaderProgram/compile_shader.cxx"
+ "source/client/ShaderProgram/constructor.cxx"
+ "source/client/ShaderProgram/destructor.cxx"
"source/base/home_directory.cxx"
- "source/base/object_type_string.cxx"
- "source/base/random.cxx"
- "source/base/save_path.cxx"
-
- "source/logic/gravitate.cxx"
- "source/logic/move.cxx"
- "source/logic/ship_mass.cxx"
- "source/logic/simulate.cxx"
-
- "source/runtime/add_object.cxx"
- "source/runtime/generate_system.cxx"
- "source/runtime/delete_objects.cxx"
-
- "source/save/continue_save.cxx"
- "source/save/decode_save.cxx"
- "source/save/encode_save.cxx"
- "source/save/new_save.cxx"
- "source/save/save.cxx"
+
+ "source/logic/Canister/constructor.cxx"
+ "source/logic/Canister/object_type_string.cxx"
+ "source/logic/Object/object_type_string.cxx"
+ "source/logic/Ship/constructor.cxx"
+ "source/logic/Ship/net_mass.cxx"
+ "source/logic/Ship/object_type_string.cxx"
+ "source/logic/Star/constructor.cxx"
+ "source/logic/Star/object_type_string.cxx"
+ "source/logic/Station/constructor.cxx"
+ "source/logic/Station/object_type_string.cxx"
+ "source/logic/ware_mass.cxx"
+ "source/logic/World/constructor.cxx"
+ "source/logic/World/object_type_string.cxx"
+
+ "source/server/Server/destructor.cxx"
+ "source/server/Server/start.cxx"
+ "source/server/ServerInstance/add_object.cxx"
+ "source/server/ServerInstance/constructor.cxx"
+ "source/server/ServerInstance/delete_objects.cxx"
+ "source/server/ServerInstance/generate_system.cxx"
+ "source/server/ServerInstance/gravitate.cxx"
+ "source/server/ServerInstance/loop.cxx"
+ "source/server/ServerInstance/move.cxx"
+ "source/server/ServerInstance/run.cxx"
+ "source/server/ServerInstance/simulate.cxx"
)
add_dependencies(
@@ -72,13 +96,20 @@ target_link_libraries(
target_compile_definitions(
bowshock PRIVATE
- _FORTIFY_SOURCE=$<IF:$<STREQUAL:"${CMAKE_BUILD_TYPE}","Debug">,0x0,0x2>
- _POSIX_C_SOURCE=200112l
GLFW_INCLUDE_NONE
- bow_dataDirectory="${BOW_DATA_DIRECTORY}"
- bow_debug=$<IF:$<STREQUAL:"${CMAKE_BUILD_TYPE}","Debug">,true,false>
+ BOW_DATA_DIRECTORY="${BOW_DATA_DIRECTORY}"
+ BOW_DEBUG=$<IF:$<STREQUAL:"${CMAKE_BUILD_TYPE}","Debug">,true,false>
)
+if(UNIX)
+ target_compile_definitions(
+ bowshock PRIVATE
+
+ _FORTIFY_SOURCE=$<IF:$<STREQUAL:"${CMAKE_BUILD_TYPE}","Debug">,0x0,0x2>
+ _POSIX_C_SOURCE=200112l
+ )
+endif()
+
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|GNU")
target_compile_options(
bowshock PRIVATE
diff --git a/bowshock/include/bow/application.hxx b/bowshock/include/bow/application.hxx
index 4b61bca..ebbeb10 100644
--- a/bowshock/include/bow/application.hxx
+++ b/bowshock/include/bow/application.hxx
@@ -2,15 +2,12 @@
#pragma once
-#include <bow/runtime.hxx>
+#include <bow/client.hxx>
+#include <bow/server.hxx>
-#include <csignal>
-#include <cstdint>
-#include <cstdio>
-#include <fmt/core.h>
-#include <glad/glad.h>
-#include <GLFW/glfw3.h>
#include <string>
+#include <tuple>
+#include <vector>
namespace bow {
template<typename T> struct VersionType {
@@ -19,61 +16,34 @@ namespace bow {
T patch;
};
- constexpr ::std::string SHADER_FILE_SUFFIX("glsl");
-
- struct GraphicsData {
- ::GLFWwindow* window;
- ::GLuint shader_program;
- };
-
- struct Configuration {
- ::std::string save_path;
- bool has_save_path:0x1;
- bool new_save:0x1;
- bool skip_intro:0x1;
+ constexpr ::bow::VersionType<::std::uint64_t> VERSION = {
+ .major = 0x0u,
+ .minor = 0xCu,
+ .patch = 0x0u,
};
class Application {
public:
- Application() noexcept = default;
-
- auto run(int argc, char const* const* argv) noexcept -> void;
+ explicit Application(int argc, char const* const* argv) noexcept;
~Application() noexcept;
- private:
- constexpr static ::bow::VersionType<::std::uint64_t> VERSION = {
- .major = 0x0u,
- .minor = 0xCu,
- .patch = 0x0u,
- };
-
- ::bow::Configuration configuration;
- ::bow::PlayerData player_data;
- ::bow::GraphicsData graphics_data;
+ auto run() -> int;
- auto get_quote(::std::string& quote, ::std::string& source, ::std::uint8_t code) noexcept -> void;
-
- auto print_quote() noexcept -> void;
-
- [[noreturn]] auto print_credits() noexcept -> void;
-
- [[noreturn]] auto print_help(::std::string program_name) noexcept -> void;
+ private:
+ ::bow::ClientConfiguration client_configuration;
- auto configure(Configuration& configuration, int argc, char const* const* argv) noexcept -> void;
+ ::bow::Client* client;
+ ::bow::Server* server;
- auto compile_shader_program(::GLuint& shader_program, ::std::string name) noexcept -> void;
+ [[noreturn]] static auto print_credits() noexcept -> void;
- auto initialise_graphics() noexcept -> void;
- auto initialise_random() noexcept -> void;
- auto initialise_signal() noexcept -> void;
+ [[noreturn]] static auto print_help(::std::string const& program_name) noexcept -> void;
- auto poll_events() noexcept -> bool;
+ [[nodiscard]] static auto get_quote(::std::uint8_t identifier) -> ::std::tuple<::std::string, ::std::string>;
- auto start_sequence() noexcept -> bool;
+ auto parse_parameters(::std::string const& program_name, ::std::vector<char const*> const& parameters) -> void;
- auto loop() noexcept -> void;
+ auto initialise_signal() -> void;
};
-
- extern ::std::sig_atomic_t volatile GOT_INTERRUPT;
}
diff --git a/bowshock/include/bow/base.hxx b/bowshock/include/bow/base.hxx
index 1f418bf..a7e3c6b 100644
--- a/bowshock/include/bow/base.hxx
+++ b/bowshock/include/bow/base.hxx
@@ -2,189 +2,38 @@
#pragma once
-#ifndef bow_dataDirectory
+#ifndef BOW_DATA_DIRECTORY
#error data directory not specified!
#endif
+#include <atomic>
#include <climits>
#include <cstdint>
-#include <cstdio>
#include <string>
static_assert(CHAR_BIT == 0x8, "bytes must contain exactly eight bits.");
namespace bow {
- inline ::std::string DATA_DIRECTORY(bow_dataDirectory);
+ inline ::std::string DATA_DIRECTORY(BOW_DATA_DIRECTORY);
- constexpr bool DEBUG = bow_debug;
+ constexpr bool DEBUG = BOW_DEBUG;
- constexpr ::std::size_t COMMANDER_NAME_LENGTH = 0xEu;
+ constexpr ::std::size_t COMMANDER_NAME_LENGTH = 0x10u;
constexpr ::std::uint8_t NUMBER_OF_QUOTE_IDENTIFIERS = UINT8_C(0x24);
- enum struct ObjectType : ::std::uint8_t {
- Canister,
- Player,
- Ship,
- Star,
- Station,
- World, // planet/moon
+ template<typename T> struct Xyz {
+ T x;
+ T y;
+ T z;
};
- enum struct Ship : ::std::uint8_t {
- Aquila,
- Cassiopeia,
- Centaurus,
- Corvus,
- Cursor,
- Eridanus,
- Falco,
- Lyra,
- Taurus,
- Ursa,
- Vipera,
- _max,
- };
-
- enum struct Star : ::std::uint8_t {
- A, // Main sequence
- B, // Main sequence
- C, // Carbon
- F, // Main sequence
- G, // Main sequence
- K, // Main sequence
- L, // Brown dwarf
- M, // Main sequence
- N, // Neutron star
- O, // Main sequence
- S, // Carbon
- T, // Brown dwarf
- W, // Worm hole
- X, // Black hole
- Y, // Brown dwarf
- Z, // White hole
- };
-
- enum struct Station : ::std::uint8_t {
- Globus,
- Orbis,
- };
-
- enum struct Ware : ::std::uint8_t {
- Air,
- Aluminium,
- AncientArtefacts,
- AnimalFurs,
- AnimalMeat,
- AnimalSkins,
- Atomics,
- BattleWeapons,
- Beer,
- Biowaste,
- Cheese,
- ChemicalWaste,
- Cobalt,
- Coffee,
- ComputerParts,
- Computers,
- Copper,
- Cuttlery,
- Dairy,
- Explosives,
- FruitsAndVegetables,
- Gemstones,
- Gold,
- HandWeapons,
- HullParts,
- HydrogenFuel,
- Iron,
- Ivory,
- Lasers,
- Leather,
- Liquor,
- Lithium,
- LiveAnimals,
- LuxuryGoods,
- Magnets,
- Medicine,
- Minerals,
- Monitors,
- NerveAgents,
- OrganicDyes,
- Paper,
- Pearls,
- Pesticides,
- Platinum,
- Plutonium,
- Radioactives,
- Robots,
- Rockets,
- Rubbish,
- Silver,
- Slaves,
- StorageDevices,
- Superconductors,
- SyntheticMeat,
- Tea,
- Titanium,
- Tobacco,
- TritiumFuel,
- Uranium,
- Water,
- Wine,
- XenoRelics,
- };
-
- enum struct World : ::std::uint8_t {
- AmmoniumWorld,
- GasGiant,
- IceWorld,
- LavaWorld,
- RockyWorld,
- WaterWorld,
- };
-
- struct Xyz {
- double x;
- double y;
- double z;
- };
-
- struct Object {
- ::bow::ObjectType type;
- union {
- ::bow::Ware canister_content;
- ::bow::Ship ship_type;
- ::bow::Star star_type;
- ::bow::Station station_type;
- ::bow::World world_type;
- };
-
- ::bow::Xyz position; // astronomical units
- ::bow::Xyz rotation; // radians
- ::bow::Xyz positional_velocity; // astronomical units per second
- ::bow::Xyz rotational_velocity; // radians per second
- double mass; // kilograms
-
- ::bow::Object* next;
- };
-
- struct ObjectRoot {
- ::bow::Object* objects;
- };
-
- struct PlayerData {
- char name[::bow::COMMANDER_NAME_LENGTH + 0x1u];
- ::std::uint64_t time;
- ::std::uint64_t system_identifier;
- ::bow::Object ship;
- float zoom;
- };
-
- auto object_type_string(::bow::ObjectType type) noexcept -> ::std::string;
-
- auto random() noexcept -> ::std::uint64_t;
+ // UB to use this from an asynchronous signal
+ // handler? ISO requires ::std::atomic or
+ // ::std::sig_atomic_t, but the former is not
+ // lock-free, and the latter is not even truly
+ // atomic.
+ extern ::std::atomic_flag GOT_INTERRUPT;
auto home_directory() noexcept -> ::std::string;
- auto save_path() noexcept -> ::std::string;
}
diff --git a/bowshock/include/bow/client.hxx b/bowshock/include/bow/client.hxx
new file mode 100644
index 0000000..2e2a15d
--- /dev/null
+++ b/bowshock/include/bow/client.hxx
@@ -0,0 +1,156 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#pragma once
+
+#include <bow/logic.hxx>
+
+#include <array>
+#include <csignal>
+#include <cstdint>
+#include <glad/glad.h>
+#include <GLFW/glfw3.h>
+#include <string>
+
+namespace bow {
+ constexpr ::std::uint64_t SAVE_FORMAT_VERSION = 0x7u;
+
+ constexpr ::std::size_t SAVE_LENGTH = 0x79u + ::bow::COMMANDER_NAME_LENGTH;
+
+ constexpr ::std::string SHADER_FILE_SUFFIX("glsl");
+
+ /*
+ Save format:
+
+ offset: identifier: size: format:
+
+ 0x00 format_version 8 unsigned
+ 0x08 commander_name E UTF-8
+ 0x16 time 8 unsigned
+ 0x1E system_identifier 8 unsigned
+ 0x1F ship_type 1 unsigned
+ 0x27 ship_position_x 8 binary64
+ 0x2F ship_position_y 8 binary64
+ 0x37 ship_position_z 8 binary64
+ 0x3F ship_rotation_x 8 binary64
+ 0x47 ship_rotation_y 8 binary64
+ 0x4F ship_rotation_z 8 binary64
+ 0x57 ship_positional_velocity_x 8 binary64
+ 0x5F ship_positional_velocity_y 8 binary64
+ 0x67 ship_positional_velocity_z 8 binary64
+ 0x6F ship_rotational_velocity_x 8 binary64
+ 0x77 ship_rotational_velocity_y 8 binary64
+ 0x7F ship_rotational_velocity_z 8 binary64
+ */
+
+ struct ClientConfiguration {
+ ::std::string directory;
+ ::std::string save_name;
+ bool new_save: 0x1;
+ bool skip_start_sequence: 0x1;
+ };
+
+ class PlayerData {
+ public:
+ ::std::string name;
+ ::std::uint64_t time;
+ ::std::uint64_t system_identifier;
+ ::bow::Ship ship;
+ float zoom;
+
+ PlayerData() noexcept;
+ PlayerData(::std::string const& path);
+
+ auto save(::std::string const& path) -> void;
+ auto load(::std::string const& path) -> void;
+
+ private:
+ struct SaveData {
+ ::std::uint64_t format_version;
+ char8_t commander_name[::bow::COMMANDER_NAME_LENGTH];
+ ::std::uint64_t time;
+ ::std::uint64_t system_identifier;
+ ::std::uint8_t ship_type;
+ double ship_position_x;
+ double ship_position_y;
+ double ship_position_z;
+ double ship_rotation_x;
+ double ship_rotation_y;
+ double ship_rotation_z;
+ double ship_positional_velocity_x;
+ double ship_positional_velocity_y;
+ double ship_positional_velocity_z;
+ double ship_rotational_velocity_x;
+ double ship_rotational_velocity_y;
+ double ship_rotational_velocity_z;
+ };
+
+ auto encode_save(::std::array<::std::uint8_t, ::bow::SAVE_LENGTH>& buffer, ::bow::PlayerData const& source) noexcept -> void;
+
+ auto decode_save(::bow::PlayerData & buffer, ::std::array<::std::uint8_t, ::bow::SAVE_LENGTH> const& source) -> void;
+
+ auto write_file(::std::string const& path, ::std::array<::std::uint8_t, ::bow::SAVE_LENGTH> const& buffer) -> void;
+
+ auto read_file(::std::array<::std::uint8_t, ::bow::SAVE_LENGTH>& buffer, ::std::string const& path) -> bool;
+ };
+
+ enum struct ShaderType {
+ Fragment,
+ Geometry,
+ TesselationControl,
+ TesselationEvaluation,
+ Vertex,
+ };
+
+ class ShaderProgram {
+ public:
+ ::GLuint handle;
+
+ ShaderProgram() noexcept = default;
+
+ explicit ShaderProgram(::std::string const& name);
+
+ ~ShaderProgram() noexcept;
+
+ private:
+ static auto compile_shader(::std::string const& name, ::bow::ShaderType type) -> ::GLuint;
+ };
+
+ class Renderer {
+ public:
+ ::GLFWwindow* window;
+ ::bow::ShaderProgram* shader_program;
+ ::GLuint vao;
+ ::GLuint vbo;
+
+ Renderer();
+
+ ~Renderer() noexcept;
+
+ auto render(::GLfloat const vertices[], ::std::size_t size) -> void;
+ };
+
+ class Client {
+ public:
+ explicit Client(::bow::ClientConfiguration const& configuration);
+
+ ~Client() noexcept;
+
+ static auto save_path(::std::string const& directory, ::std::string const& name) noexcept -> ::std::string;
+
+
+ auto run() noexcept -> void;
+
+ private:
+ ::bow::ClientConfiguration configuration;
+
+ ::bow::PlayerData player_data;
+
+ ::bow::Renderer renderer;
+
+ auto poll_events() noexcept -> bool;
+
+ auto start_sequence() noexcept -> bool;
+
+ auto loop() noexcept -> void;
+ };
+}
diff --git a/bowshock/include/bow/logic.hxx b/bowshock/include/bow/logic.hxx
index 9b7b9e3..b5fec0b 100644
--- a/bowshock/include/bow/logic.hxx
+++ b/bowshock/include/bow/logic.hxx
@@ -5,6 +5,8 @@
#include <bow/base.hxx>
#include <cstdint>
+#include <string>
+#include <type_traits>
namespace bow {
constexpr double DISTANCE_MODIFIER = 0x1.16A5D2D360000000p037; // 1 astronomical unit
@@ -15,12 +17,200 @@ namespace bow {
constexpr double GRAVITY_VALUE = 0x1.258688101B4BB16Dp-34 * ::bow::GRAVITY_FACTOR; // gravitational constant (s^2*m*t^2)
- [[nodiscard]] auto ship_mass(::bow::Ship identifier) noexcept -> double;
+ enum struct Ware: ::std::uint8_t {
+ Air,
+ Aluminium,
+ AncientArtefacts,
+ AnimalFurs,
+ AnimalMeat,
+ AnimalSkins,
+ Atomics,
+ BattleWeapons,
+ Beer,
+ Biowaste,
+ Cheese,
+ ChemicalWaste,
+ Cobalt,
+ Coffee,
+ ComputerParts,
+ Computers,
+ Copper,
+ Cuttlery,
+ Dairy,
+ Explosives,
+ FruitsAndVegetables,
+ Gemstones,
+ Gold,
+ HandWeapons,
+ HullParts,
+ HydrogenFuel,
+ Iron,
+ Ivory,
+ Lasers,
+ Leather,
+ Liquor,
+ Lithium,
+ LiveAnimals,
+ LuxuryGoods,
+ Magnets,
+ Medicine,
+ Minerals,
+ Monitors,
+ NerveAgents,
+ OrganicDyes,
+ Paper,
+ Pearls,
+ Pesticides,
+ Platinum,
+ Plutonium,
+ Radioactives,
+ Robots,
+ Rockets,
+ Rubbish,
+ Silver,
+ Slaves,
+ StorageDevices,
+ Superconductors,
+ SyntheticMeat,
+ Tea,
+ Titanium,
+ Tobacco,
+ TritiumFuel,
+ Uranium,
+ Water,
+ Wine,
+ XenoRelics,
+ };
- auto gravitate(::bow::ObjectRoot& system) noexcept -> void;
- auto gravitate(::bow::ObjectRoot& objects, ::bow::ObjectRoot const& system) noexcept -> void;
+ enum struct ObjectType : ::std::uint8_t {
+ Canister,
+ Ship,
+ Star,
+ Station,
+ World,
+ };
- auto move(::bow::ObjectRoot& root) noexcept -> void;
+ class Object {
+ public:
+ ::bow::ObjectType object_type;
- auto simulate(::bow::ObjectRoot& system, ::std::uint64_t duration) noexcept -> void;
+ ::bow::Xyz<double> position; // astronomical units
+ ::bow::Xyz<double> rotation; // radians
+ ::bow::Xyz<double> positional_velocity; // astronomical units per second
+ ::bow::Xyz<double> rotational_velocity; // radians per second
+ double mass; // kilograms
+
+ ::bow::Object* next;
+
+ virtual ~Object() noexcept = default;
+
+ [[nodiscard]] virtual auto object_type_string() const noexcept -> ::std::string;
+
+ protected:
+ Object() noexcept = default;
+ };
+
+ template<typename T>
+ concept ObjectLike = ::std::is_base_of_v<::bow::Object, T>;
+
+ class Canister final: public ::bow::Object {
+ public:
+ ::bow::Ware content;
+
+ Canister() noexcept;
+
+ [[nodiscard]] virtual auto object_type_string() const noexcept -> ::std::string;
+ };
+
+ class Ship final: public ::bow::Object {
+ public:
+ enum struct Type: ::std::uint8_t {
+ Aquila,
+ Cassiopeia,
+ Centaurus,
+ Corvus,
+ Cursor,
+ Eridanus,
+ Falco,
+ Lyra,
+ Taurus,
+ Ursa,
+ Vipera,
+ };
+
+ ::bow::Ship::Type type;
+
+ Ship() noexcept;
+
+ [[nodiscard]] virtual auto object_type_string() const noexcept -> ::std::string;
+
+ [[nodiscard]] auto net_mass() noexcept -> double;
+ };
+ constexpr ::std::uint8_t MAXIMUM_SHIP_IDENTIFIER = static_cast<::std::uint8_t>(bow::Ship::Type::Vipera);
+
+ class Star final: public ::bow::Object {
+ public:
+ enum struct Type: ::std::uint8_t {
+ A, // Main sequence
+ B, // Main sequence
+ C, // Carbon
+ F, // Main sequence
+ G, // Main sequence
+ K, // Main sequence
+ L, // Brown dwarf
+ M, // Main sequence
+ N, // Neutron star
+ O, // Main sequence
+ S, // Carbon
+ T, // Brown dwarf
+ W, // Worm hole
+ X, // Black hole
+ Y, // Brown dwarf
+ Z, // White hole
+ };
+
+ ::bow::Star::Type type;
+
+ Star() noexcept;
+
+ [[nodiscard]] virtual auto object_type_string() const noexcept -> ::std::string;
+ };
+
+ class Station final: public ::bow::Object {
+ public:
+ enum struct Type: ::std::uint8_t {
+ Globus,
+ Orbis,
+ };
+
+ ::bow::Station::Type type;
+
+ Station() noexcept;
+
+ [[nodiscard]] virtual auto object_type_string() const noexcept -> ::std::string;
+ };
+
+ class World final: public ::bow::Object {
+ public:
+ enum struct Type: ::std::uint8_t {
+ AmmoniumWorld,
+ GasGiant,
+ IceWorld,
+ LavaWorld,
+ RockyWorld,
+ WaterWorld,
+ };
+
+ ::bow::World::Type type;
+
+ World() noexcept;
+
+ [[nodiscard]] virtual auto object_type_string() const noexcept -> ::std::string;
+ };
+
+ struct ObjectRoot {
+ ::bow::Object* objects;
+ };
+
+ [[nodiscard]] auto ware_mass(::bow::Ware const ware) noexcept -> double;
}
diff --git a/bowshock/include/bow/runtime.hxx b/bowshock/include/bow/runtime.hxx
deleted file mode 100644
index de6a0b8..0000000
--- a/bowshock/include/bow/runtime.hxx
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#pragma once
-
-#include <bow/base.hxx>
-
-#include <cstdint>
-#include <source_location>
-
-namespace bow {
- [[noreturn]] auto abort(::std::source_location source_location = ::std::source_location::current()) noexcept -> void;
-
- auto add_object(::bow::ObjectRoot& root, ::bow::Object const& object) -> void;
-
- auto delete_objects(::bow::ObjectRoot const& root) noexcept -> void;
-
- auto generate_system(::bow::ObjectRoot& system, ::std::uint64_t identifier, ::std::uint64_t time) -> void;
-}
diff --git a/bowshock/include/bow/save.hxx b/bowshock/include/bow/save.hxx
deleted file mode 100644
index f4a5642..0000000
--- a/bowshock/include/bow/save.hxx
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#pragma once
-
-#include <bow/base.hxx>
-
-#include <cstddef>
-#include <cstdint>
-#include <string>
-
-namespace bow {
- constexpr ::std::uint64_t SAVE_VERSION = 0x6u;
-
- constexpr ::std::size_t SAVE_LENGTH = 0x79u + ::bow::COMMANDER_NAME_LENGTH;
-
- constexpr ::std::uint8_t MAX_SHIP_IDENTIFIER = static_cast<::std::uint8_t>(::bow::Ship::_max);
-
- /*
- Save format:
-
- offset: identifier: size: format:
-
- 0x00 format_version 8 unsigned
- 0x08 commander_name E UTF-8
- 0x16 time 8 unsigned
- 0x1E system_identifier 8 unsigned
- 0x1F ship_type 1 unsigned
- 0x27 ship_position_x 8 binary64
- 0x2F ship_position_y 8 binary64
- 0x37 ship_position_z 8 binary64
- 0x3F ship_rotation_x 8 binary64
- 0x47 ship_rotation_y 8 binary64
- 0x4F ship_rotation_z 8 binary64
- 0x57 ship_positional_velocity_x 8 binary64
- 0x5F ship_positional_velocity_y 8 binary64
- 0x67 ship_positional_velocity_z 8 binary64
- 0x6F ship_rotational_velocity_x 8 binary64
- 0x77 ship_rotational_velocity_y 8 binary64
- 0x7F ship_rotational_velocity_z 8 binary64
- */
-
- struct SaveData {
- ::std::uint64_t format_version;
- char8_t commander_name[::bow::COMMANDER_NAME_LENGTH];
- ::std::uint64_t time;
- ::std::uint64_t system_identifier;
- ::std::uint8_t ship_type;
- double ship_position_x;
- double ship_position_y;
- double ship_position_z;
- double ship_rotation_x;
- double ship_rotation_y;
- double ship_rotation_z;
- double ship_positional_velocity_x;
- double ship_positional_velocity_y;
- double ship_positional_velocity_z;
- double ship_rotational_velocity_x;
- double ship_rotational_velocity_y;
- double ship_rotational_velocity_z;
- };
-
- auto decode_save(::bow::SaveData& buf, void const* data) noexcept -> void;
- auto encode_save(void* buf, ::bow::SaveData const& data) noexcept -> void;
-
- auto new_save(::bow::PlayerData& data) noexcept -> void;
-
- auto continue_save(::bow::PlayerData& data, ::std::string file) -> bool;
-
- auto save(::std::string file, ::bow::PlayerData const& data) noexcept -> void;
-}
diff --git a/bowshock/include/bow/server.hxx b/bowshock/include/bow/server.hxx
new file mode 100644
index 0000000..c1f44f2
--- /dev/null
+++ b/bowshock/include/bow/server.hxx
@@ -0,0 +1,58 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#pragma once
+
+#include <bow/logic.hxx>
+
+#include <atomic>
+#include <cstdint>
+#include <thread>
+
+namespace bow {
+ class ServerInstance {
+ public:
+ explicit ServerInstance(::std::atomic_flag* stop_flag) noexcept;
+
+ static auto run(::bow::ServerInstance* server) noexcept -> void;
+
+ private:
+ ::std::atomic_flag* stop_flag;
+
+ template<::bow::ObjectLike T>
+ auto add_object(::bow::ObjectRoot& root, T const& object) -> void;
+
+ auto delete_objects(::bow::ObjectRoot const& root) noexcept -> void;
+
+ auto generate_system(::bow::ObjectRoot& system, ::std::uint64_t identifier, ::std::uint64_t time) -> void;
+
+ auto gravitate(::bow::ObjectRoot& system) noexcept -> void;
+ auto gravitate(::bow::ObjectRoot& objects, ::bow::ObjectRoot const& system) noexcept -> void;
+
+ auto move(::bow::ObjectRoot& root) noexcept -> void;
+
+ auto simulate(::bow::ObjectRoot& system, ::std::uint64_t duration) noexcept -> void;
+
+ auto loop() -> void;
+ };
+
+ class Server {
+ public:
+ static auto start() -> ::bow::Server*;
+
+ ~Server() noexcept;
+
+ private:
+ ::std::thread* thread;
+
+ ::bow::ServerInstance* instance;
+
+ ::std::atomic_flag* stop_flag;
+ };
+
+ auto start_server() -> ::bow::Server;
+
+ auto stop_server(::bow::ServerInstance& server) -> void;
+}
+
+template<>
+auto bow::ServerInstance::add_object<::bow::Object>(::bow::ObjectRoot& root, ::bow::Object const& object_value) -> void = delete;
diff --git a/bowshock/shader/main.frag.glsl b/bowshock/shader/main.frag.glsl
index 243dd29..e539ab5 100644
--- a/bowshock/shader/main.frag.glsl
+++ b/bowshock/shader/main.frag.glsl
@@ -1,4 +1,4 @@
-#version 410 core
+#version 150 core
out vec4 colour;
diff --git a/bowshock/shader/main.vert.glsl b/bowshock/shader/main.vert.glsl
index 7d2c88d..d96415c 100644
--- a/bowshock/shader/main.vert.glsl
+++ b/bowshock/shader/main.vert.glsl
@@ -1,4 +1,4 @@
-#version 410 core
+#version 150 core
layout (location = 0x0) in vec3 position;
diff --git a/bowshock/source/application/Application/constructor.cxx b/bowshock/source/application/Application/constructor.cxx
new file mode 100644
index 0000000..a0a900a
--- /dev/null
+++ b/bowshock/source/application/Application/constructor.cxx
@@ -0,0 +1,44 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/application.hxx>
+#include <bow/client.hxx>
+
+#include <cstdio>
+#include <cstdlib>
+#include <fmt/core.h>
+#include <string>
+#include <vector>
+
+using namespace ::std::literals::string_literals;
+
+bow::Application::Application(int const argc, char const* const* const argv) noexcept {
+ ::fmt::print(stderr, "[app] configuring application\n");
+
+ auto const program_name = [&argc, argv]() -> ::std::string {
+ if (argc < 0x1) [[unlikely]] {
+ ::fmt::print(stderr, "[app] program name not provided\n");
+ ::std::abort();
+ } else {
+ return ::std::string(*argv);
+ }
+ }();
+
+ this->client_configuration = ::bow::ClientConfiguration {
+ .directory = ""s,
+ .new_save = false,
+ .skip_start_sequence = false,
+ };
+
+ ::std::vector<char const*> parameters(argv + 0x1u, argv + static_cast<::std::size_t>(argc));
+
+ this->parse_parameters(program_name, parameters);
+
+ if (this->client_configuration.directory.empty()) [[likely]] {
+ auto const base_directory = ::bow::home_directory();
+
+ this->client_configuration.directory = base_directory + "/.bowshock"s;
+ }
+
+ this->client = nullptr;
+ this->server = nullptr;
+}
diff --git a/bowshock/source/application/Application/destructor.cxx b/bowshock/source/application/Application/destructor.cxx
new file mode 100644
index 0000000..73a2bf0
--- /dev/null
+++ b/bowshock/source/application/Application/destructor.cxx
@@ -0,0 +1,16 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/application.hxx>
+
+#include <cstdio>
+#include <fmt/core.h>
+
+bow::Application::~Application() noexcept {
+ ::fmt::print(stderr, "[app] quitting\n");
+
+ delete this->client;
+
+ delete this->server;
+
+ ::fmt::print(stderr, "\nGoodbye!\n");
+}
diff --git a/bowshock/source/application/bow/get_quote.cxx b/bowshock/source/application/Application/get_quote.cxx
index 610c21a..f614ccd 100644
--- a/bowshock/source/application/bow/get_quote.cxx
+++ b/bowshock/source/application/Application/get_quote.cxx
@@ -3,159 +3,203 @@
#include <bow/application.hxx>
#include <cstdint>
+#include <cstdio>
#include <fmt/core.h>
#include <string>
+#include <tuple>
using namespace ::std::literals::string_literals;
-auto ::bow::Application::get_quote(::std::string& quote, ::std::string& source, ::std::uint8_t const identifier) noexcept -> void {
+auto bow::Application::get_quote(::std::uint8_t const identifier) -> ::std::tuple<::std::string, ::std::string> {
+ ::std::string quote = ""s;
+ ::std::string source = ""s;
+
switch (identifier) {
default:
- ::fmt::print(stderr, "invalid quote identifier ({})\n", identifier);
- [[fallthrough]];
+ ::fmt::print(stderr, "[app] invalid quote identifier ({})\n", identifier);
+
+ throw ::std::invalid_argument("invalid quote identifier");
+
case 0x0u:
quote = "You gotta be heaven to see heaven.";
source = "Jim Carrey";
break;
+
case 0x1u:
quote = "Though it's the end of the world, don't blame yourself, now.";
source = "Porter Robinson";
break;
+
case 0x2u:
quote = "The future will be better tomorrow.";
source = "Dan Quayle";
break;
+
case 0x3u:
quote = "Sir, an equation has no meaning for me unless it expresses a thought of god.";
source = "Srinivasa Ramanujan Aiyangar";
break;
+
case 0x4u:
quote = "Amīcus Platō amīcus Aristotelēs magis amīca vēritās.";
source = "Isaac Newton";
break;
+
case 0x5u:
quote = "I have studied these things \u2013 you have not.";
source = "Isaac Newton";
break;
+
case 0x6u:
- quote = "La construction d'une machine propre à exprimer tous les sons de nos paroles, avec toutes les articulations, serait sans doute une décourverte bien importante.\n... La chose ne me paraît pas impossible.";
+ quote = "La construction d'une machine propre à exprimer tous les sons de nos paroles,\n avec toutes les articulations, serait sans doute une décourverte bien\n importante.\n\u2026 La chose ne me paraît pas impossible.";
source = "Leonhard Euler";
break;
+
case 0x7u:
quote = "In mathematics, you don't understand things, you just get used to them.";
source = "John von Neumann";
break;
+
case 0x8u:
- quote = "Being a language, mathematics may be used not only to inform, but also \u2013 among other things \u2013 to seduce.";
+ quote = "Being a language, mathematics may be used not only to inform, but also \u2013 among\n other things \u2013 to seduce.";
source = "Benoît B. Mandelbrot";
break;
+
case 0x9u:
quote = "The real question is not whether machines think, but whether men do.";
source = "Burrhus Frederic Skinner";
break;
+
case 0xAu:
- quote = "Those who are not shocked when they first come across quantum theory cannot possibly have understood it.";
+ quote = "Those who are not shocked when they first come across quantum theory cannot\n possibly have understood it.";
source = "Niels Henrik David Bohr";
break;
+
case 0xBu:
- quote = "Every sentence I utter must be understood not as an affirmation, but as a question.";
+ quote = "Every sentence I utter must be understood not as an affirmation, but as a\n question.";
source = "Niels Henrik David Bohr";
break;
+
case 0xCu:
quote = "We will now discuss in a little more detail the struggle for existence.";
source = "Charles Robert Darwin";
break;
+
case 0xDu:
- quote = "name et ipsa scientia potestas est.";
+ quote = "Nam et ipsa scientia potestas est.";
source = "Francis Bacon";
break;
+
case 0xEu:
quote = "We don't know a millionth of one percent about anything.";
source = "Thomas Alva Edison";
break;
+
case 0xFu:
- quote = "My goal is simple. It is a complete understanding of the universe, why it is as it is, and why it exists at all.";
+ quote = "My goal is simple. It is a complete understanding of the universe, why it is as\n it is, and why it exists at all.";
source = "Stephen William Hawking";
break;
+
case 0x10u:
- quote = "Equipped with his five senses, man explores the universe around him and calls the adventure Science.";
+ quote = "Equipped with his five senses, man explores the universe around him and calls\n the adventure Science.";
source = "Edwin Powell Hubble";
break;
+
case 0x11u:
- quote = "I canister say this: I believe that the human mind, or even the mind of a cat, is more interesting in its complexity than an entire galaxy if it is devoid of life.";
+ quote = "I can say this: I believe that the human mind, or even the mind of a cat, is\n more interesting in its complexity than an entire galaxy if it is devoid of\n life.";
source = "Martin Gardner";
break;
+
case 0x12u:
quote = "I'm always right. This time I'm just more right than usual.";
source = "Linus Benedict Torvalds";
break;
+
case 0x13u:
quote = "I'm an instant star. Just add water and stir.";
source = "David Robert Jones";
break;
+
case 0x14u:
quote = "Don't waste the Earth \u2013 it is our jewel!";
source = "Buzz Eugene Aldrin";
break;
+
case 0x15u:
- quote = "I think we're going to the moon because it's in the nature of the human being to face challenges.";
+ quote = "I think we're going to the moon because it's in the nature of the human being to\n face challenges.";
source = "Neil Alden Armstrong";
break;
+
case 0x16u:
- quote = "A hacker is someone who enjoys playful cleverness \u2013 not necessarily with computers.";
+ quote = "A hacker is someone who enjoys playful cleverness \u2013 not necessarily with\n computers.";
source = "Richard Matthew Stallman";
break;
+
case 0x17u:
- quote = "So Einstein was wrong when he said \"God noes not play dice.\". Consideration of black holes suggests, not only that God does play dice, but that he sometimes confuses us by throwing them where they canister't be seen.";
+ quote = "So Einstein was wrong when he said \"God does not play dice.\". Consideration of\n black holes suggests, not only that God does play dice, but that he sometimes\n confuses us by throwing them where they can't be seen.";
source = "Stephen William Hawking";
break;
+
case 0x18u:
- quote = "I'm a blacktar.";
+ quote = "I'm a blackstar.";
source = "David Robert Jones";
break;
+
case 0x19u:
- quote = "Sooner or later, we must expand life beyond our little blue mud ball\u2014or go extinct.";
+ quote = "Sooner or later, we must expand life beyond our little blue mud ball\u2014or go\n extinct.";
source = "Elon Reeve Musk";
break;
+
case 0x1Au:
quote = "I would like to die on Mars \u2013 just not on impact.";
source = "Elon Reeve Musk";
break;
+
case 0x1Bu:
quote = "The web does not just connect computers; it connects people.";
source = "Timothy John Berners-Lee";
break;
+
case 0x1Cu:
- quote = "canister digital computers think?";
+ quote = "Can digital computers think?";
source = "Alan Mathison Turing";
break;
+
case 0x1Du:
quote = "That's one small step for a man, one giant leap for mankind.";
source = "Neil Alden Armstrong";
break;
+
case 0x1Eu:
quote = "If you think it's simple, then you have misunderstood the problem.";
source = "Bjarne Stroustrup";
break;
+
case 0x1Fu:
quote = "Controlling complexity is the essence of computer programming.";
source = "Brian Wilson Kerningham";
break;
+
case 0x20u:
- quote = "I have always wished for my computer to be as easy to use as my telephone.\nMy wish has come true because I canister no longer figure out how to use my telephone.";
+ quote = "I have always wished for my computer to be as easy to use as my telephone.\n My wish has come true because I can no longer figure out how to use my\n telephone.";
source = "Bjarne Stroustrup";
break;
+
case 0x21u:
quote = "There is no mathematical substitute for philosophy.";
source = "Saul Aaron Kripke";
break;
+
case 0x22u:
quote = "Biology is engineering.";
source = "Daniel Clement Dennett III";
break;
+
case 0x23u:
quote = "The universe is under no obligation to make sense to you.";
source = "Neil deGrasse Tyson";
break;
}
+
+ return ::std::make_tuple(quote, source);
}
diff --git a/bowshock/source/application/bow/initialise_signal.cxx b/bowshock/source/application/Application/initialise_signal.cxx
index 40996ce..e77e9ca 100644
--- a/bowshock/source/application/bow/initialise_signal.cxx
+++ b/bowshock/source/application/Application/initialise_signal.cxx
@@ -2,34 +2,37 @@
#include <bow/application.hxx>
+#include <atomic>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <fmt/core.h>
+#include <stdexcept>
-::std::sig_atomic_t volatile ::bow::GOT_INTERRUPT;
+// 31.10.4.
+// constexpr atomic_flag::atomic_flag() noexcept;
+// Effects: Initializes *this to the clear state.
+::std::atomic_flag bow::GOT_INTERRUPT;
namespace bow {
static auto interrupt_handler(int const signal) -> void;
}
-static auto ::bow::interrupt_handler(int const signal) -> void {
+static auto bow::interrupt_handler(int const signal) -> void {
// Ignore the return value: We canister't do anything (meaningful) about it anyways.
::std::signal(signal, ::bow::interrupt_handler);
- ::bow::GOT_INTERRUPT = 0x1;
+ ::bow::GOT_INTERRUPT.test_and_set();
};
-auto ::bow::Application::initialise_signal() noexcept -> void {
- ::fmt::print(stderr, "initialising signal handlers\n");
-
- ::bow::GOT_INTERRUPT = 0x0;
+auto bow::Application::initialise_signal() -> void {
+ ::fmt::print(stderr, "[app] initialising signal handlers\n");
auto const set_handler = []<typename Handler>(int const signal, Handler const& handler) -> void {
if (::std::signal(signal, static_cast<auto (*)(int) -> void>(handler)) == SIG_ERR) [[unlikely]] {
- ::fmt::print(stderr, "unable to set signal handler for {}\n", signal);
+ ::fmt::print(stderr, "[app] unable to set signal handler for {}\n", signal);
- ::std::abort();
+ throw ::std::runtime_error("unable to set signal handler");
}
};
diff --git a/bowshock/source/application/Application/parse_parameters.cxx b/bowshock/source/application/Application/parse_parameters.cxx
new file mode 100644
index 0000000..1993eba
--- /dev/null
+++ b/bowshock/source/application/Application/parse_parameters.cxx
@@ -0,0 +1,64 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/application.hxx>
+#include <bow/client.hxx>
+
+#include <cstdio>
+#include <fmt/core.h>
+#include <stdexcept>
+#include <string>
+#include <string_view>
+#include <vector>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::Application::parse_parameters(::std::string const& program_name, ::std::vector<char const*> const& parameters) -> void {
+ ::fmt::print(stderr, "[app] parsing parameters\n");
+
+ if (parameters.size() >= 0x1u) [[unlikely]] {
+ auto const parse = [&program_name](::bow::ClientConfiguration& client_configuration, ::std::string const& parameter) -> void {
+ if (auto const offset = parameter.find("="); offset != ::std::string::npos) {
+ auto const field = ::std::string_view(parameter.begin(), parameter.begin() + offset);
+ auto const value = ::std::string_view(parameter.begin() + offset + 0x1u, parameter.end());
+
+ if (field == "directory") {
+ ::fmt::print(stderr, "[app] setting directory to \"{}\"\n", value);
+
+ client_configuration.directory = value;
+ } else if (field == "name") {
+ ::fmt::print(stderr, "[app] setting save name to \"{}\"\n", value);
+
+ client_configuration.save_name = value;
+ } else {
+ ::fmt::print(stderr, "[app] invalid field name \"{}\"\n", field);
+
+ throw ::std::logic_error("invalid field name");
+ }
+ } else {
+ auto const setting = ::std::string_view(parameter.begin(), parameter.end());
+
+ if (setting == "credits") {
+ ::bow::Application::print_credits();
+ } else if (setting == "help") {
+ ::bow::Application::print_help(program_name);
+ } else if (setting == "new") {
+ ::fmt::print(stderr, "[app] using default save file\n");
+
+ client_configuration.new_save = true;
+ } else if (setting == "skip") {
+ ::fmt::print(stderr, "[app] skipping start sequence\n");
+
+ client_configuration.skip_start_sequence = true;
+ } else {
+ ::fmt::print(stderr, "[app] invalid setting\"{}\"\n", setting);
+
+ throw ::std::logic_error("invalid setting");
+ }
+ }
+ };
+
+ for (auto const parameter : parameters) {
+ parse(this->client_configuration, parameter);
+ }
+ }
+}
diff --git a/bowshock/source/application/bow/print_credits.cxx b/bowshock/source/application/Application/print_credits.cxx
index 312048e..4a67dfb 100644
--- a/bowshock/source/application/bow/print_credits.cxx
+++ b/bowshock/source/application/Application/print_credits.cxx
@@ -8,7 +8,7 @@
#include <fmt/core.h>
#include <stdexcept>
-auto ::bow::Application::print_credits() noexcept -> void {
+auto bow::Application::print_credits() noexcept -> void {
::std::string path = ::bow::DATA_DIRECTORY + "/CREDITS.txt";
::std::size_t const file_size = ::std::filesystem::file_size(path);
@@ -16,16 +16,17 @@ auto ::bow::Application::print_credits() noexcept -> void {
::std::FILE* file = ::std::fopen(path.c_str(), "r");
if (file == nullptr) [[unlikely]] {
- ::fmt::print(stderr, "unable to open credits file\n");
+ ::fmt::print(stderr, "[app] unable to open credits file\n");
::std::exit(EXIT_FAILURE);
}
::std::string credits;
- try { credits.reserve(file_size); }
- catch (...) {
- ::fmt::print(stderr, "unable to allocate memory for credits\n");
+ try {
+ credits.reserve(file_size);
+ } catch (...) {
+ ::fmt::print(stderr, "[app] unable to allocate memory for credits\n");
::std::exit(EXIT_FAILURE);
}
diff --git a/bowshock/source/application/bow/print_help.cxx b/bowshock/source/application/Application/print_help.cxx
index 07cc267..f2e1788 100644
--- a/bowshock/source/application/bow/print_help.cxx
+++ b/bowshock/source/application/Application/print_help.cxx
@@ -5,10 +5,10 @@
#include <cstdlib>
#include <fmt/core.h>
-auto ::bow::Application::print_help(::std::string const program_name) noexcept -> void {
+auto bow::Application::print_help(::std::string const& program_name) noexcept -> void {
::fmt::print(
"\n"
- "\x1B[1mBowshock\x1B[0m {:X}.{:X}.{:X}\n"
+ "\x1B[1mBowshock\x1B[0m {:x}.{:x}.{:x}\n"
"Copyright 2022-2023 Gabriel Bj\u00F8rnager Jensen.\n"
"\n"
"Usage: \"{}\" <configuration> [savefile]\n"
@@ -17,9 +17,10 @@ auto ::bow::Application::print_help(::std::string const program_name) noexcept -
" --credits Print the game \x1B[1mcredits\x1B[0m\n"
" --print_help Print the\x1B[1mhelp\x1B[0m screen\n"
" --new Start a \x1B[1mnew\x1B[0m save file\n"
- " --skip_intro \x1B[1mskip\x1B[0m the intro\n"
+ " --skip_start_sequence \x1B[1mskip\x1B[0m the intro\n"
"\n",
- ::bow::Application::VERSION.major, ::bow::Application::VERSION.minor, ::bow::Application::VERSION.patch, program_name);
+ ::bow::VERSION.major, ::bow::VERSION.minor, ::bow::VERSION.patch, program_name
+ );
::std::exit(EXIT_SUCCESS);
}
diff --git a/bowshock/source/application/Application/run.cxx b/bowshock/source/application/Application/run.cxx
new file mode 100644
index 0000000..ebbd7c8
--- /dev/null
+++ b/bowshock/source/application/Application/run.cxx
@@ -0,0 +1,55 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/application.hxx>
+#include <bow/client.hxx>
+#include <bow/server.hxx>
+
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <fmt/core.h>
+#include <stdexcept>
+#include <string>
+#include <tuple>
+
+auto bow::Application::run() -> int {
+ ::std::srand(static_cast<int unsigned>(::std::time(nullptr)));
+
+ auto const quote_identifier = static_cast<::std::uint8_t>(::std::rand()) % ::bow::NUMBER_OF_QUOTE_IDENTIFIERS;
+
+ // Print quote:
+ {
+ auto const quote_source = this->get_quote(quote_identifier);
+
+ auto const quote = ::std::get<0x0>(quote_source);
+ auto const source = ::std::get<0x1>(quote_source);
+
+ ::fmt::print("\n{}\n\u2014{}\n\n", quote, source);
+ }
+
+ ::fmt::print(
+ stderr,
+ "\x1B[0m\x1B[1mBowshock\x1B[0m {:X}.{:X}.{:X} \u2013 Copyright \u00A9 2022\u20102023 \x1B[1mGabriel Bj\u00F8rnager Jensen\x1B[0m.\n\n",
+ ::bow::VERSION.major, ::bow::VERSION.minor, ::bow::VERSION.patch
+ );
+
+ if constexpr (::bow::DEBUG) {
+ ::fmt::print("[app] debug mode is enabled\n");
+ }
+
+ ::fmt::print(stderr, "[app] data directory at \"{}\"\n", ::bow::DATA_DIRECTORY);
+
+ this->initialise_signal();
+
+ // The server handles all of its exceptions.
+ this->server = ::bow::Server::start();
+
+ this->client = new ::bow::Client(this->client_configuration);
+
+ // The client handles all of its exceptions.
+ this->client->run();
+
+ return 0x0;
+}
diff --git a/bowshock/source/application/bow/configure.cxx b/bowshock/source/application/bow/configure.cxx
deleted file mode 100644
index 41793c5..0000000
--- a/bowshock/source/application/bow/configure.cxx
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-
-#include <cstdio>
-#include <cstring>
-#include <fmt/core.h>
-#include <string>
-#include <vector>
-
-using namespace ::std::literals::string_literals;
-
-auto ::bow::Application::configure(::bow::Configuration& configuration, int const argc, char const* const* argv) noexcept -> void {
- ::std::string const program_name = *argv;
-
- configuration = ::bow::Configuration {
- .save_path = ""s,
- .has_save_path = false,
- .new_save = false,
- .skip_intro = false,
- };
-
- if (argc >= 0x2) [[unlikely]] {
- ::std::vector<char const*> parameters(argv + 0x1u, argv + static_cast<::std::size_t>(argc));
-
- for (auto parameter : parameters) {
- if (parameter[0x0u] == '-' && parameter[0x1u] == '-') {
- parameter += 0x2u;
-
- if (!::std::strcmp(parameter, "credits")) { print_credits(); }
- else if (!::std::strcmp(parameter, "print_help")) { print_help(program_name); }
- else if (!::std::strcmp(parameter, "new")) { configuration.new_save = true; }
- else if (!::std::strcmp(parameter, "skip")) { configuration.skip_intro = true; }
- else { ::fmt::print(stderr, "invalid pareter \"{}\"\n", parameter); }
-
- continue;
- }
-
- // Else: Interpret it as a save path.
- configuration.save_path = parameter;
- configuration.has_save_path = true;
- }
- }
-}
diff --git a/bowshock/source/application/bow/destructor.cxx b/bowshock/source/application/bow/destructor.cxx
deleted file mode 100644
index 7df50ab..0000000
--- a/bowshock/source/application/bow/destructor.cxx
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-
-#include <cstdio>
-#include <cstdlib>
-#include <fmt/core.h>
-#include <GLFW/glfw3.h>
-
-::bow::Application::~Application() noexcept {
- ::fmt::print(stderr, "quitting\n");
-
- glDeleteProgram(graphics_data.shader_program);
-
- ::glfwDestroyWindow(graphics_data.window);
- ::glfwTerminate();
-
- ::fmt::print(stderr, "Goodbye!\n");
-}
diff --git a/bowshock/source/application/bow/initialise_graphics.cxx b/bowshock/source/application/bow/initialise_graphics.cxx
deleted file mode 100644
index 83cc624..0000000
--- a/bowshock/source/application/bow/initialise_graphics.cxx
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-
-#include <cstdio>
-#include <cstdlib>
-#include <fmt/core.h>
-#include <glad/glad.h>
-#include <GLFW/glfw3.h>
-
-auto ::bow::Application::initialise_graphics() noexcept -> void {
- ::fmt::print(stderr, "initialising graphics\n");
-
- ::fmt::print(stderr, "initialising glfw\n");
-
- if (!::glfwInit()) [[unlikely]] {
- ::fmt::print(stderr, "unable to initialise glfw\n");
-
- ::std::abort();
- }
-
- ::fmt::print(stderr, "initialising window\n");
-
- ::glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 0x4);
- ::glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0x1);
- ::glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
- ::glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- ::glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
- ::glfwWindowHint(GLFW_SAMPLES, 0x8);
-
- graphics_data.window = ::glfwCreateWindow(0x400, 0x240, "Bowshock", ::glfwGetPrimaryMonitor(), nullptr);
-
- if (graphics_data.window == nullptr) [[unlikely]] {
- ::fmt::print(stderr, "unable to open window");
-
- ::std::abort();
- }
-
- ::fmt::print(stderr, "initialising context\n");
-
- ::glfwMakeContextCurrent(graphics_data.window);
- ::gladLoadGL();
-
- glEnable(GL_MULTISAMPLE);
-
- ::GLFWvidmode const* const video_mode = ::glfwGetVideoMode(::glfwGetPrimaryMonitor());
-
- glViewport(0x0, 0x0, video_mode->width, video_mode->height);
- glClearColor(0x0p0, 0x0p0, 0x0p0, 0x1p0);
- glClear(GL_COLOR_BUFFER_BIT);
-
- ::glfwSwapBuffers(graphics_data.window);
- ::glfwSwapInterval(0x1);
-
- this->compile_shader_program(graphics_data.shader_program, "main");
-}
diff --git a/bowshock/source/application/bow/initialise_random.cxx b/bowshock/source/application/bow/initialise_random.cxx
deleted file mode 100644
index 9ea6644..0000000
--- a/bowshock/source/application/bow/initialise_random.cxx
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-
-#include <cstdio>
-#include <cstdlib>
-#include <ctime>
-#include <fmt/core.h>
-
-auto ::bow::Application::initialise_random() noexcept -> void {
- ::fmt::print(stderr, "initialising random number generator\n");
-
- ::std::srand(static_cast<unsigned int>(::std::time(nullptr)));
-}
diff --git a/bowshock/source/application/bow/loop.cxx b/bowshock/source/application/bow/loop.cxx
deleted file mode 100644
index 99e22d8..0000000
--- a/bowshock/source/application/bow/loop.cxx
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-#include <bow/logic.hxx>
-
-#include <cmath>
-#include <cstdio>
-#include <fmt/core.h>
-#include <glad/glad.h>
-#include <GLFW/glfw3.h>
-#include <stdexcept>
-
-auto ::bow::Application::loop() noexcept -> void {
- ::fmt::print(stderr, "entering main loop\n");
-
- ::GLfloat vertices[] = {
- -0x1.0000p0f, +0x1.0000p0f, 0x0p0f,
- +0x1.0000p0f, +0x1.0000p0f, 0x0p0f,
- +0x0.0000p0f, +0x0.0000p0f, 0x0p0f,
- };
-
- ::GLuint vao;
- ::GLuint vbo;
- glGenVertexArrays(0x1, &vao);
- glGenBuffers(0x1, &vbo);
-
- glBindVertexArray(vao);
-
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STREAM_DRAW);
-
- glVertexAttribPointer(0x0, 0x3, GL_FLOAT, GL_FALSE, 0x3* sizeof (::GLfloat), nullptr);
- glEnableVertexAttribArray(0x0);
-
- // For stellar bodies:
- ::bow::ObjectRoot system_root;
- // For miscellaneous objects (canisters, shps...):
- ::bow::ObjectRoot objects_root = {
- .objects = nullptr,
- };
-
- try {::bow::generate_system(system_root, player_data.system_identifier, player_data.time); }
- catch (::std::bad_alloc const&) {
- ::fmt::print(stderr, "unable to allocate memory for object\n");
-
- ::std::abort();
- }
-
- ::bow::Object object_temporary = {
- .type = ::bow::ObjectType::Canister,
- .canister_content = ::bow::Ware::Biowaste,
- .position = {
- .x = 0x0p0,
- .y = -0x2p0,
- .z = 0x0p0,
- },
- .rotation = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .positional_velocity = {
- .x = -0x1p-12,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .rotational_velocity = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .mass = 0x1p0,
- .next = nullptr,
- };
- ::bow::add_object(objects_root, object_temporary);
-
- auto const scroll_handler = [](::GLFWwindow* const window, [[maybe_unused]] double const x_offset, double const y_offset) -> void {
- ::bow::PlayerData* data = static_cast<::bow::PlayerData*>(::glfwGetWindowUserPointer(window));
-
- data->zoom *= ::std::pow(0x1.04p0f, 0x0p0f-static_cast<float>(y_offset));
- };
-
- ::glfwSetWindowUserPointer(graphics_data.window, &player_data);
- ::glfwSetScrollCallback(graphics_data.window, scroll_handler);
-
- for (;; ++player_data.time) {
- if (this->poll_events()) [[unlikely]] break;
-
- ::bow::gravitate(system_root);
- ::bow::gravitate(objects_root, system_root);
-
- ::bow::move(system_root);
- ::bow::move(objects_root);
-
- ::GLfloat const frame = 0x1p0f*player_data.zoom;
-
- vertices[0x0u] = static_cast<::GLfloat>(system_root.objects->next->position.x) / frame;
- vertices[0x1u] = static_cast<::GLfloat>(system_root.objects->next->position.y) / frame;
- vertices[0x3u] = static_cast<::GLfloat>(system_root.objects->position.x) / frame;
- vertices[0x4u] = static_cast<::GLfloat>(system_root.objects->position.y) / frame;
- vertices[0x6u] = static_cast<::GLfloat>(objects_root.objects->position.x) / frame;
- vertices[0x7u] = static_cast<::GLfloat>(objects_root.objects->position.y) / frame;
-
- glClearColor(0x0p0f, 0x0p0f, 0x0p0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
-
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferSubData(GL_ARRAY_BUFFER, 0x0, sizeof (vertices), vertices);
-
- glUseProgram(graphics_data.shader_program);
- glBindVertexArray(vao);
- glDrawArrays(GL_TRIANGLES, 0x0, 0x3* 0x1);
-
- ::glfwSwapBuffers(graphics_data.window);
- }
-
- ::bow::delete_objects(objects_root);
- ::bow::delete_objects(system_root);
-
- ::glfwSetScrollCallback(graphics_data.window, nullptr);
-
- glDeleteVertexArrays(0x1, &vao);
- glDeleteBuffers(0x1, &vbo);
-}
diff --git a/bowshock/source/application/bow/poll_events.cxx b/bowshock/source/application/bow/poll_events.cxx
deleted file mode 100644
index 355c906..0000000
--- a/bowshock/source/application/bow/poll_events.cxx
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-
-#include <cstdio>
-#include <fmt/core.h>
-#include <GLFW/glfw3.h>
-
-auto ::bow::Application::poll_events() noexcept -> bool {
- ::glfwPollEvents();
-
- if (::bow::GOT_INTERRUPT) [[unlikely]] {
- ::fmt::print(stderr, "got interrupt\n");
- ::glfwSetWindowShouldClose(graphics_data.window, GLFW_TRUE);
- }
-
- if (::glfwWindowShouldClose(graphics_data.window)) [[unlikely]] { return true; }
-
- return false;
-}
diff --git a/bowshock/source/application/bow/print_quote.cxx b/bowshock/source/application/bow/print_quote.cxx
deleted file mode 100644
index bfa83eb..0000000
--- a/bowshock/source/application/bow/print_quote.cxx
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <ctime>
-#include <fmt/core.h>
-#include <string>
-
-auto ::bow::Application::print_quote() noexcept -> void {
- ::std::srand(static_cast<unsigned int>(::std::time(nullptr)));
-
- auto const identifier = static_cast<::std::uint8_t>(rand()) % ::bow::NUMBER_OF_QUOTE_IDENTIFIERS;
-
- ::std::string quote;
- ::std::string source;
- get_quote(quote, source, identifier);
-
- ::fmt::print(stderr, "{}\n\u2014{}\n\n", quote, source);
-}
diff --git a/bowshock/source/application/bow/run.cxx b/bowshock/source/application/bow/run.cxx
deleted file mode 100644
index d661b03..0000000
--- a/bowshock/source/application/bow/run.cxx
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-#include <bow/logic.hxx>
-#include <bow/runtime.hxx>
-#include <bow/save.hxx>
-
-#include <cstdio>
-#include <fmt/core.h>
-
-auto ::bow::Application::run(int const argc, char const* const* const argv) noexcept -> void {
- configure(this->configuration, argc, argv);
-
- if (!this->configuration.has_save_path) { this->configuration.save_path = ::bow::save_path(); }
-
- print_quote();
-
- ::fmt::print(
- stderr,
- "\x1B[0m\x1B[1mBowshock\x1B[0m {:X}.{:X}.{:X} \u2013 Copyright 2022\u20102023 \x1B[1mGabriel Bj\u00F8rnager Jensen\x1B[0m.\n\n",
- ::bow::Application::VERSION.major, ::bow::Application::VERSION.minor, ::bow::Application::VERSION.patch
- );
-
- ::fmt::print(stderr, "initialising\n");
-
- if constexpr (::bow::DEBUG) { ::fmt::print(stderr, "debug mode is enabled\n"); }
-
- ::fmt::print(stderr, "data directory at \"{}\"\n", ::bow::DATA_DIRECTORY);
-
- ::fmt::print(stderr, "angle unit: {:.3f} radians\n", 0x1p0);
- ::fmt::print(stderr, "distance unit: {:.3f} metres\n", ::bow::DISTANCE_MODIFIER);
- ::fmt::print(stderr, "mass unit: {:.3f} kilograms\n", ::bow::MASS_MODIFIER);
- ::fmt::print(stderr, "time unit: {:.3f} seconds\n", ::bow::TIME_MODIFIER);
- ::fmt::print(stderr, "gravitational constant: {:.3f} (factor: {:.3f}))\n", ::bow::GRAVITY_VALUE, ::bow::GRAVITY_FACTOR);
-
- this->initialise_random();
- this->initialise_signal();
- this->initialise_graphics();
-
- auto invalid_save = false;
-
- if (this->configuration.new_save) { ::bow::new_save(player_data); }
- else { invalid_save = ::bow::continue_save(player_data, this->configuration.save_path); }
-
- if (invalid_save) {
- ::fmt::print(stderr, "aborting due to invalid save file\n");
-
- return;
- }
-
- if (this->configuration.skip_intro || !start_sequence()) [[likely]] {
- if (!this->configuration.has_save_path) { this->configuration.save_path = ::bow::save_path(); }
-
- this->loop();
-
- ::bow::save(this->configuration.save_path, player_data);
- }
-}
-
-int main(int const argc, char const* const* argv) {
- ::bow::Application bow;
-
- bow.run(argc, argv);
-}
diff --git a/bowshock/source/base/home_directory.cxx b/bowshock/source/base/home_directory.cxx
index 2ba854b..2e68917 100644
--- a/bowshock/source/base/home_directory.cxx
+++ b/bowshock/source/base/home_directory.cxx
@@ -2,15 +2,20 @@
#include <bow/logic.hxx>
+#include <cstdio>
#include <cstdlib>
+#include <fmt/core.h>
#include <string>
using namespace ::std::literals::string_literals;
-auto ::bow::home_directory() noexcept -> ::std::string {
+auto bow::home_directory() noexcept -> ::std::string {
auto const pointer = ::std::getenv("HOME");
- if (pointer == nullptr) [[unlikely]] { return ""s; }
+ if (pointer == nullptr) [[unlikely]] {
+ ::fmt::print(stderr, "unable to get home directory, using current directory\n");
+ return "."s;
+ }
return ::std::string(pointer);
}
diff --git a/bowshock/source/base/object_type_string.cxx b/bowshock/source/base/object_type_string.cxx
deleted file mode 100644
index 2a52152..0000000
--- a/bowshock/source/base/object_type_string.cxx
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/base.hxx>
-
-#include <string>
-
-using namespace ::std::literals::string_literals;
-
-auto ::bow::object_type_string(::bow::ObjectType const type) noexcept -> ::std::string {
- switch (type) {
- case ::bow::ObjectType::Canister:
- return "canister"s;
-
- case ::bow::ObjectType::Player:
- return "player"s;
-
- case ::bow::ObjectType::Ship:
- return "ship"s;
-
- case ::bow::ObjectType::Star:
- return "star"s;
-
- case ::bow::ObjectType::Station:
- return "station"s;
-
- case ::bow::ObjectType::World:
- return "world"s;
- }
-}
diff --git a/bowshock/source/base/random.cxx b/bowshock/source/base/random.cxx
deleted file mode 100644
index 503a31c..0000000
--- a/bowshock/source/base/random.cxx
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/base.hxx>
-
-#include <cstdint>
-#include <cstdlib>
-#include <limits>
-
-static_assert(sizeof (int) == sizeof (::std::uint32_t));
-
-static_assert(RAND_MAX == ::std::numeric_limits<int>::max());
-
-auto ::bow::random() noexcept -> ::std::uint64_t {
- // TO-DO: Improve.
-
- ::std::uint32_t const rnd0 = (::std::uint32_t)::std::rand();
- ::std::uint32_t const rnd1 = (::std::uint32_t)::std::rand();
- ::std::uint64_t const random = static_cast<::std::uint64_t>(rnd0) | static_cast<::std::uint64_t>(rnd1) >> 0x4u;
-
- return random;
-}
diff --git a/bowshock/source/base/save_path.cxx b/bowshock/source/base/save_path.cxx
deleted file mode 100644
index aeddcbc..0000000
--- a/bowshock/source/base/save_path.cxx
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/application.hxx>
-
-#include <cstdio>
-#include <cstdlib>
-#include <fmt/core.h>
-#include <string>
-
-using namespace ::std::literals::string_literals;
-
-namespace { constexpr ::std::string file_name(".save_bowshock"); }
-
-auto ::bow::save_path() noexcept -> ::std::string {
- auto base_directory = ::bow::home_directory();
-
- if (base_directory.empty()) [[unlikely]] {
- ::fmt::print(stderr, "unable to get home directory, using current directory\n");
-
- base_directory = "."s;
- }
-
- auto const path = base_directory + "/"s + ::file_name;
-
- return path;
-}
diff --git a/bowshock/source/client/Client/constructor.cxx b/bowshock/source/client/Client/constructor.cxx
new file mode 100644
index 0000000..64407ea
--- /dev/null
+++ b/bowshock/source/client/Client/constructor.cxx
@@ -0,0 +1,29 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+#include <bow/logic.hxx>
+
+#include <cstdio>
+#include <filesystem>
+#include <fmt/core.h>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+bow::Client::Client(::bow::ClientConfiguration const& configuration) {
+ ::fmt::print(stderr, "[client] initialising\n");
+
+ this->configuration = configuration;
+
+ ::fmt::print(stderr, "[client] creating configuration directory at {}\n", this->configuration.directory);
+ ::std::filesystem::create_directory(this->configuration.directory);
+ ::std::filesystem::create_directory(this->configuration.directory + "/save"s);
+
+ if (this->configuration.new_save) {
+ ::fmt::print(stderr, "[client] using default save\n");
+ } else {
+ this->player_data.load(::bow::Client::save_path(this->configuration.directory, this->configuration.save_name));;
+ }
+
+ ::fmt::print(stderr, "[client] welcome, CMDR {}\n", this->player_data.name);
+}
diff --git a/bowshock/source/client/Client/destructor.cxx b/bowshock/source/client/Client/destructor.cxx
new file mode 100644
index 0000000..a4224bc
--- /dev/null
+++ b/bowshock/source/client/Client/destructor.cxx
@@ -0,0 +1,11 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <cstdio>
+#include <cstdlib>
+#include <fmt/core.h>
+#include <GLFW/glfw3.h>
+
+::bow::Client::~Client() noexcept {
+}
diff --git a/bowshock/source/client/Client/poll_events.cxx b/bowshock/source/client/Client/poll_events.cxx
new file mode 100644
index 0000000..8d3aac0
--- /dev/null
+++ b/bowshock/source/client/Client/poll_events.cxx
@@ -0,0 +1,20 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <cstdio>
+#include <fmt/core.h>
+#include <GLFW/glfw3.h>
+
+auto bow::Client::poll_events() noexcept -> bool {
+ ::glfwPollEvents();
+
+ if (::bow::GOT_INTERRUPT.test()) [[unlikely]] {
+ ::fmt::print(stderr, "got interrupt\n");
+ ::glfwSetWindowShouldClose(renderer.window, GLFW_TRUE);
+ }
+
+ if (::glfwWindowShouldClose(renderer.window)) [[unlikely]] { return true; }
+
+ return false;
+}
diff --git a/bowshock/source/client/Client/run.cxx b/bowshock/source/client/Client/run.cxx
new file mode 100644
index 0000000..4256046
--- /dev/null
+++ b/bowshock/source/client/Client/run.cxx
@@ -0,0 +1,64 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+#include <bow/logic.hxx>
+
+#include <cmath>
+#include <cstdio>
+#include <fmt/core.h>
+#include <glad/glad.h>
+#include <GLFW/glfw3.h>
+
+auto bow::Client::run() noexcept -> void {
+ ::fmt::print(stderr, "[client] running\n");
+
+ if (!this->configuration.skip_start_sequence && start_sequence()) [[unlikely]] { return; }
+
+ ::fmt::print(stderr, "[client] entering main loop\n");
+
+ ::GLfloat vertices[] = {
+ -0x1.0000p0f, +0x1.0000p0f, 0x0p0f,
+ +0x1.0000p0f, +0x1.0000p0f, 0x0p0f,
+ +0x0.0000p0f, +0x0.0000p0f, 0x0p0f,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STREAM_DRAW);
+
+ glVertexAttribPointer(0x0, 0x3, GL_FLOAT, GL_FALSE, 0x3* sizeof (::GLfloat), nullptr);
+ glEnableVertexAttribArray(0x0);
+
+ auto const scroll_handler = [](::GLFWwindow* const window, [[maybe_unused]] double const horizontal_offset, double const vertical_offset) -> void {
+ auto const data = static_cast<::bow::PlayerData*>(::glfwGetWindowUserPointer(window));
+
+ data->zoom *= ::std::pow(0x1.04p0f, -static_cast<float>(vertical_offset));
+ };
+
+ ::glfwSetWindowUserPointer(this->renderer.window, &player_data);
+ ::glfwSetScrollCallback(this->renderer.window, scroll_handler);
+
+ for (;;) {
+ if (this->poll_events()) [[unlikely]] { break; }
+
+ ::GLfloat const frame = 0x1p0f * player_data.zoom;
+
+ // Currently, we don't recieve any information from
+ // the server.
+
+ //vertices[0x0] = static_cast<::GLfloat>(system_root.objects->next->position.x) / frame;
+ //vertices[0x1] = static_cast<::GLfloat>(system_root.objects->next->position.y) / frame;
+ //vertices[0x3] = static_cast<::GLfloat>(system_root.objects->position.x) / frame;
+ //vertices[0x4] = static_cast<::GLfloat>(system_root.objects->position.y) / frame;
+ //vertices[0x6] = static_cast<::GLfloat>(objects_root.objects->position.x) / frame;
+ //vertices[0x7] = static_cast<::GLfloat>(objects_root.objects->position.y) / frame;
+
+ this->renderer.render(vertices, sizeof (vertices));
+ }
+
+ ::glfwSetScrollCallback(this->renderer.window, nullptr);
+
+ glDeleteVertexArrays(0x1, &this->renderer.vao);
+ glDeleteBuffers(0x1, &this->renderer.vbo);
+
+ this->player_data.save(::bow::Client::save_path(this->configuration.directory, this->configuration.save_name));
+
+}
diff --git a/bowshock/source/client/Client/save_path.cxx b/bowshock/source/client/Client/save_path.cxx
new file mode 100644
index 0000000..bf5f8b2
--- /dev/null
+++ b/bowshock/source/client/Client/save_path.cxx
@@ -0,0 +1,13 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::Client::save_path(::std::string const& directory, ::std::string const& name) noexcept -> ::std::string {
+ auto const path = directory + "/save/"s + name + ".bowshock"s;
+
+ return path;
+}
diff --git a/bowshock/source/application/bow/start_sequence.cxx b/bowshock/source/client/Client/start_sequence.cxx
index 7998e86..48e246c 100644
--- a/bowshock/source/application/bow/start_sequence.cxx
+++ b/bowshock/source/client/Client/start_sequence.cxx
@@ -1,13 +1,13 @@
// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-#include <bow/application.hxx>
+#include <bow/client.hxx>
#include <cstdio>
#include <fmt/core.h>
#include <GLFW/glfw3.h>
-auto ::bow::Application::start_sequence() noexcept -> bool {
- ::fmt::print(stderr, "starting start sequence\n");
+auto bow::Client::start_sequence() noexcept -> bool {
+ ::fmt::print(stderr, "[client] starting start sequence\n");
auto exit = false;
@@ -21,7 +21,7 @@ auto ::bow::Application::start_sequence() noexcept -> bool {
glClearColor(bowshock_red, bowshock_green, bowshock_blue, 0x1p0);
glClear(GL_COLOR_BUFFER_BIT);
- ::glfwSwapBuffers(graphics_data.window);
+ ::glfwSwapBuffers(renderer.window);
}
double const fade_duration = 0x1p0;
@@ -35,14 +35,14 @@ auto ::bow::Application::start_sequence() noexcept -> bool {
glClearColor(red, green, blue, 0x1p0);
glClear(GL_COLOR_BUFFER_BIT);
- ::glfwSwapBuffers(graphics_data.window);
+ ::glfwSwapBuffers(renderer.window);
}
glClearColor(0x0p0f, 0x0p0f, 0x0p0f, 0x1p0f);
glClear(GL_COLOR_BUFFER_BIT);
- ::glfwSwapBuffers(graphics_data.window);
+ ::glfwSwapBuffers(renderer.window);
- if (::glfwWindowShouldClose(graphics_data.window)) [[unlikely]] { exit = true; }
+ if (::glfwWindowShouldClose(renderer.window)) [[unlikely]] { exit = true; }
return exit;
}
diff --git a/bowshock/source/client/PlayerData/constructor.cxx b/bowshock/source/client/PlayerData/constructor.cxx
new file mode 100644
index 0000000..695799a
--- /dev/null
+++ b/bowshock/source/client/PlayerData/constructor.cxx
@@ -0,0 +1,24 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+#include <bow/logic.hxx>
+
+#include <array>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <fmt/core.h>
+#include <stdexcept>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+bow::PlayerData::PlayerData() noexcept {
+ ::fmt::print(stderr, "[client] generating player data\n");
+
+ this->name = "Corneille"s;
+ this->time = UINT64_C(0x0); // 256 julian years after the Unix Epoch.
+ this->system_identifier = UINT64_C(0x0);
+ this->ship = ::bow::Ship();
+ this->zoom = 0x4p0;
+}
diff --git a/bowshock/source/client/PlayerData/decode_save.cxx b/bowshock/source/client/PlayerData/decode_save.cxx
new file mode 100644
index 0000000..307f01f
--- /dev/null
+++ b/bowshock/source/client/PlayerData/decode_save.cxx
@@ -0,0 +1,89 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <array>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <fmt/core.h>
+#include <stdexcept>
+
+auto bow::PlayerData::decode_save(::bow::PlayerData & buffer, ::std::array<::std::uint8_t, ::bow::SAVE_LENGTH> const& source) -> void {
+ auto data = ::bow::PlayerData::SaveData {
+ .format_version = UINT64_C(0x0),
+ .commander_name = u8"\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+ .time = UINT64_C(0x0),
+ .system_identifier = UINT64_C(0x0),
+ .ship_type = UINT8_C(0x0),
+ .ship_position_x = 0x0p0,
+ .ship_position_y = 0x0p0,
+ .ship_position_z = 0x0p0,
+ .ship_rotation_x = 0x0p0,
+ .ship_rotation_y = 0x0p0,
+ .ship_rotation_z = 0x0p0,
+ .ship_positional_velocity_x = 0x0p0,
+ .ship_positional_velocity_y = 0x0p0,
+ .ship_positional_velocity_z = 0x0p0,
+ .ship_rotational_velocity_x = 0x0p0,
+ .ship_rotational_velocity_y = 0x0p0,
+ .ship_rotational_velocity_z = 0x0p0,
+ };
+
+ ::std::size_t index = 0x0u;
+
+ auto const decode_value = [&index, &source]<typename T>(T& buffer) {
+ constexpr auto size = sizeof (T);
+
+ ::std::memcpy(&buffer, &source[index], size);
+ index += size;
+ };
+
+ decode_value(data.format_version);
+ decode_value(data.commander_name);
+ decode_value(data.time);
+ decode_value(data.system_identifier);
+ decode_value(data.ship_type);
+ decode_value(data.ship_position_x);
+ decode_value(data.ship_position_y);
+ decode_value(data.ship_position_z);
+ decode_value(data.ship_rotation_x);
+ decode_value(data.ship_rotation_y);
+ decode_value(data.ship_rotation_z);
+ decode_value(data.ship_positional_velocity_x);
+ decode_value(data.ship_positional_velocity_y);
+ decode_value(data.ship_positional_velocity_z);
+ decode_value(data.ship_rotational_velocity_x);
+ decode_value(data.ship_rotational_velocity_y);
+ decode_value(data.ship_rotational_velocity_z);
+
+ if (data.format_version != ::bow::SAVE_FORMAT_VERSION) [[unlikely]] {
+ ::fmt::print(stderr, "[client] invalid format ({:#04x}) of save file\n", data.format_version);
+
+ throw ::std::logic_error("invalid format of save file");
+ }
+
+ if (data.ship_type > ::bow::MAXIMUM_SHIP_IDENTIFIER) [[unlikely]] {
+ ::fmt::print(stderr, "[client] invalid ship type ({:#04x})\n", data.ship_type);
+
+ throw ::std::logic_error("invalid ship type");
+ }
+
+ buffer.time = data.time,
+ buffer.system_identifier = data.system_identifier,
+ buffer.ship.type = static_cast<::bow::Ship::Type>(data.ship_type),
+ buffer.ship.position.x = data.ship_position_x,
+ buffer.ship.position.y = data.ship_position_y,
+ buffer.ship.position.z = data.ship_position_z,
+ buffer.ship.rotation.x = data.ship_rotation_x,
+ buffer.ship.rotation.y = data.ship_rotation_y,
+ buffer.ship.rotation.z = data.ship_rotation_z,
+ buffer.ship.positional_velocity.x = data.ship_positional_velocity_x,
+ buffer.ship.positional_velocity.y = data.ship_positional_velocity_y,
+ buffer.ship.positional_velocity.z = data.ship_positional_velocity_z,
+ buffer.ship.rotational_velocity.x = data.ship_rotational_velocity_x,
+ buffer.ship.rotational_velocity.y = data.ship_rotational_velocity_y,
+ buffer.ship.rotational_velocity.z = data.ship_rotational_velocity_z,
+
+ buffer.name = ::std::string(reinterpret_cast<char *>(data.commander_name), ::bow::COMMANDER_NAME_LENGTH);
+}
diff --git a/bowshock/source/client/PlayerData/encode_save.cxx b/bowshock/source/client/PlayerData/encode_save.cxx
new file mode 100644
index 0000000..9b0f121
--- /dev/null
+++ b/bowshock/source/client/PlayerData/encode_save.cxx
@@ -0,0 +1,60 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <array>
+#include <cstdint>
+#include <cstring>
+
+#include <fmt/core.h>
+
+auto bow::PlayerData::encode_save(::std::array<::std::uint8_t, ::bow::SAVE_LENGTH>& buffer, ::bow::PlayerData const& source) noexcept -> void {
+ auto data = ::bow::PlayerData::SaveData {
+ .format_version = ::bow::SAVE_FORMAT_VERSION,
+ .commander_name = u8"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+ .time = source.time,
+ .system_identifier = source.system_identifier,
+ .ship_type = static_cast<::std::uint8_t>(source.ship.type),
+ .ship_position_x = source.ship.position.x,
+ .ship_position_y = source.ship.position.y,
+ .ship_position_z = source.ship.position.z,
+ .ship_rotation_x = source.ship.rotation.x,
+ .ship_rotation_y = source.ship.rotation.y,
+ .ship_rotation_z = source.ship.rotation.z,
+ .ship_positional_velocity_x = source.ship.positional_velocity.x,
+ .ship_positional_velocity_y = source.ship.positional_velocity.y,
+ .ship_positional_velocity_z = source.ship.positional_velocity.z,
+ .ship_rotational_velocity_x = source.ship.rotational_velocity.x,
+ .ship_rotational_velocity_y = source.ship.rotational_velocity.y,
+ .ship_rotational_velocity_z = source.ship.rotational_velocity.z,
+ };
+
+ ::std::memcpy(&data.commander_name, source.name.data(), ::bow::COMMANDER_NAME_LENGTH);
+
+ ::std::size_t index = 0x0u;
+
+ auto const encode_value = [&buffer, &index]<typename T>(T const& value) {
+ constexpr auto size = sizeof (T);
+
+ ::std::memcpy(&buffer[index], &value, size);
+ index += size;
+ };
+
+ encode_value(data.format_version);
+ encode_value(data.commander_name);
+ encode_value(data.time);
+ encode_value(data.system_identifier);
+ encode_value(data.ship_type);
+ encode_value(data.ship_position_x);
+ encode_value(data.ship_position_y);
+ encode_value(data.ship_position_z);
+ encode_value(data.ship_rotation_x);
+ encode_value(data.ship_rotation_y);
+ encode_value(data.ship_rotation_z);
+ encode_value(data.ship_positional_velocity_x);
+ encode_value(data.ship_positional_velocity_y);
+ encode_value(data.ship_positional_velocity_z);
+ encode_value(data.ship_rotational_velocity_x);
+ encode_value(data.ship_rotational_velocity_y);
+ encode_value(data.ship_rotational_velocity_z);
+}
diff --git a/bowshock/source/client/PlayerData/load.cxx b/bowshock/source/client/PlayerData/load.cxx
new file mode 100644
index 0000000..f120ffc
--- /dev/null
+++ b/bowshock/source/client/PlayerData/load.cxx
@@ -0,0 +1,26 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+#include <bow/logic.hxx>
+
+#include <array>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <fmt/core.h>
+#include <stdexcept>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::PlayerData::load(::std::string const& path) -> void {
+ ::fmt::print(stderr, "[client] loading save file at \"{}\"\n", path);
+
+ ::std::array<::std::uint8_t, ::bow::SAVE_LENGTH> raw;
+
+ if (!this->read_file(raw, path)) [[likely]] {
+ this->decode_save(*this, raw);
+
+ this->ship.mass = this->ship.net_mass();
+ }
+}
diff --git a/bowshock/source/client/PlayerData/read_file.cxx b/bowshock/source/client/PlayerData/read_file.cxx
new file mode 100644
index 0000000..c076d85
--- /dev/null
+++ b/bowshock/source/client/PlayerData/read_file.cxx
@@ -0,0 +1,31 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+#include <bow/logic.hxx>
+
+#include <array>
+#include <cstdint>
+#include <cstdio>
+#include <fmt/core.h>
+#include <stdexcept>
+#include <string>
+
+auto bow::PlayerData::read_file(::std::array<::std::uint8_t, ::bow::SAVE_LENGTH>& buffer, ::std::string const& path) -> bool {
+ using ::bow::SAVE_LENGTH;
+
+ auto const file = ::std::fopen(path.c_str(), "rb");
+
+ if (file == nullptr) [[unlikely]] {
+ ::fmt::print(stderr, "[client] unable to open save file, using default\n");
+
+ return true;
+ }
+
+ if (::std::fread(buffer.data(), sizeof (::std::uint8_t), SAVE_LENGTH, file) < SAVE_LENGTH) [[unlikely]] {
+ throw ::std::runtime_error("unable to read save file");
+ }
+
+ ::std::fclose(file);
+
+ return false;
+}
diff --git a/bowshock/source/client/PlayerData/save.cxx b/bowshock/source/client/PlayerData/save.cxx
new file mode 100644
index 0000000..b18313a
--- /dev/null
+++ b/bowshock/source/client/PlayerData/save.cxx
@@ -0,0 +1,20 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <array>
+#include <cstdint>
+#include <cstdio>
+#include <fmt/core.h>
+
+auto bow::PlayerData::save(::std::string const& path) -> void {
+ using ::bow::SAVE_LENGTH;
+
+ ::fmt::print(stderr, "[client] saving CMDR {} at \"{}\"\n", this->name.data(), path);
+
+ ::std::array<::std::uint8_t, SAVE_LENGTH> data;
+
+ ::bow::PlayerData::encode_save(data, *this);
+
+ this->write_file(path, data);
+}
diff --git a/bowshock/source/client/PlayerData/write_file.cxx b/bowshock/source/client/PlayerData/write_file.cxx
new file mode 100644
index 0000000..2a01e60
--- /dev/null
+++ b/bowshock/source/client/PlayerData/write_file.cxx
@@ -0,0 +1,23 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <array>
+#include <cstdint>
+#include <cstdio>
+#include <stdexcept>
+
+auto bow::PlayerData::write_file(::std::string const& path, ::std::array<::std::uint8_t, ::bow::SAVE_LENGTH> const& data) -> void {
+ using ::bow::SAVE_LENGTH;
+
+ auto const file = ::std::fopen(path.c_str(), "wb");
+ if (file == nullptr) [[unlikely]] {
+ throw ::std::runtime_error("unable to create save file");
+ }
+
+ if (::std::fwrite(data.data(), 0x1u, SAVE_LENGTH, file) < SAVE_LENGTH) [[unlikely]] {
+ throw ::std::runtime_error("unable to write save file");
+ }
+
+ ::std::fclose(file);
+}
diff --git a/bowshock/source/client/Renderer/constructor.cxx b/bowshock/source/client/Renderer/constructor.cxx
new file mode 100644
index 0000000..247a18e
--- /dev/null
+++ b/bowshock/source/client/Renderer/constructor.cxx
@@ -0,0 +1,59 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <cstdio>
+#include <cstdlib>
+#include <fmt/core.h>
+#include <glad/glad.h>
+#include <GLFW/glfw3.h>
+#include <stdexcept>
+
+bow::Renderer::Renderer() {
+ ::fmt::print(stderr, "[client] initialising graphics\n");
+
+ ::fmt::print(stderr, "[client] initialising glfw\n");
+
+ if (!::glfwInit()) [[unlikely]] {
+ throw ::std::runtime_error("[client] unable to initialise glfw");
+ }
+
+ ::fmt::print(stderr, "[client] initialising window\n");
+
+ ::glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 0x4);
+ ::glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0x1);
+ ::glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
+ ::glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ ::glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
+ ::glfwWindowHint(GLFW_SAMPLES, 0x8);
+
+ this->window = ::glfwCreateWindow(0x400, 0x240, "Bowshock", ::glfwGetPrimaryMonitor(), nullptr);
+
+ if (this->window == nullptr) [[unlikely]] {
+ throw ::std::runtime_error("unable to open window");
+ }
+
+ ::fmt::print(stderr, "[client] initialising context\n");
+
+ ::glfwMakeContextCurrent(this->window);
+ ::gladLoadGL();
+
+ glEnable(GL_MULTISAMPLE);
+
+ auto const video_mode = ::glfwGetVideoMode(::glfwGetPrimaryMonitor());
+
+ glViewport(0x0, 0x0, video_mode->width, video_mode->height);
+ glClearColor(0x0p0, 0x0p0, 0x0p0, 0x1p0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ ::glfwSwapBuffers(this->window);
+ ::glfwSwapInterval(0x1);
+
+ this->shader_program = new ::bow::ShaderProgram("main");
+
+ glGenVertexArrays(0x1, &this->vao);
+ glGenBuffers(0x1, &this->vbo);
+
+ glBindVertexArray(this->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+}
diff --git a/bowshock/source/client/Renderer/destructor.cxx b/bowshock/source/client/Renderer/destructor.cxx
new file mode 100644
index 0000000..5d3aa8e
--- /dev/null
+++ b/bowshock/source/client/Renderer/destructor.cxx
@@ -0,0 +1,13 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <glad/glad.h>
+#include <GLFW/glfw3.h>
+
+bow::Renderer::~Renderer() noexcept {
+ delete this->shader_program;
+
+ ::glfwDestroyWindow(this->window);
+ ::glfwTerminate();
+}
diff --git a/bowshock/source/client/Renderer/render.cxx b/bowshock/source/client/Renderer/render.cxx
new file mode 100644
index 0000000..16ff4d4
--- /dev/null
+++ b/bowshock/source/client/Renderer/render.cxx
@@ -0,0 +1,23 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+#include <bow/logic.hxx>
+
+#include <glad/glad.h>
+#include <GLFW/glfw3.h>
+#include <stdexcept>
+
+auto bow::Renderer::render(::GLfloat const vertices[], ::std::size_t const size) -> void {
+ glClearColor(0x0p0f, 0x0p0f, 0x0p0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
+ glBufferSubData(GL_ARRAY_BUFFER, 0x0, size, vertices);
+
+ glUseProgram(this->shader_program->handle);
+
+ glBindVertexArray(this->vao);
+ glDrawArrays(GL_TRIANGLES, 0x0, 0x3 * 0x1);
+
+ ::glfwSwapBuffers(this->window);
+}
diff --git a/bowshock/source/application/bow/compile_shader_program.cxx b/bowshock/source/client/ShaderProgram/compile_shader.cxx
index 57ad978..591faf5 100644
--- a/bowshock/source/application/bow/compile_shader_program.cxx
+++ b/bowshock/source/client/ShaderProgram/compile_shader.cxx
@@ -1,31 +1,44 @@
// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-#include <bow/application.hxx>
+#include <bow/client.hxx>
#include <cstdio>
-#include <cstdlib>
-#include <cstring>
#include <filesystem>
#include <fmt/core.h>
#include <glad/glad.h>
#include <stdexcept>
#include <string>
-#include <type_traits>
#include <vector>
-namespace bow {
- static auto compile_shader(::GLuint& shader, ::std::string name, ::GLenum type) -> void;
-}
-
using namespace ::std::literals::string_literals;
-static auto ::bow::compile_shader(::GLuint& shader, ::std::string const name, ::GLenum const type) -> void {
+auto bow::ShaderProgram::compile_shader(::std::string const& name, ::bow::ShaderType const pretty_type) -> ::GLuint {
+ auto const type = [pretty_type]() -> ::GLuint {
+ using ::bow::ShaderType;
+
+ switch (pretty_type) {
+ case ShaderType::Fragment:
+ return GL_FRAGMENT_SHADER;
+
+ case ShaderType::Geometry:
+ return GL_GEOMETRY_SHADER;
+
+ case ShaderType::TesselationControl:
+ return GL_TESS_CONTROL_SHADER;
+
+ case ShaderType::TesselationEvaluation:
+ return GL_TESS_EVALUATION_SHADER;
+
+ case ShaderType::Vertex:
+ return GL_VERTEX_SHADER;
+ }
+ }();
+
auto const type_suffix = [type]() -> ::std::string {
switch (type) {
- default: [[unlikely]]
- ::fmt::print(stderr, "bad shader type {}\n", static_cast<unsigned int>(type));
-
- ::std::abort();
+ default:
+ // Until C++23:
+ ::__builtin_unreachable();
case GL_FRAGMENT_SHADER:
return "frag"s;
@@ -46,8 +59,8 @@ static auto ::bow::compile_shader(::GLuint& shader, ::std::string const name, ::
auto const type_string = [type]() -> ::std::string {
switch (type) {
- default: [[unlikely]]
- ::std::abort();
+ default:
+ ::__builtin_unreachable();
case GL_FRAGMENT_SHADER:
return "fragment"s;
@@ -68,28 +81,26 @@ static auto ::bow::compile_shader(::GLuint& shader, ::std::string const name, ::
using ::bow::DATA_DIRECTORY;
- auto path = DATA_DIRECTORY + "/shaders/" + name + "." + type_suffix + "." + ::bow::SHADER_FILE_SUFFIX;
+ auto const path = DATA_DIRECTORY + "/shaders/" + name + "." + type_suffix + "." + ::bow::SHADER_FILE_SUFFIX;
- ::fmt::print(stderr, "compiling {} shader at \"{}\"\n", type_string, path);
+ ::fmt::print(stderr, "[client] compiling {} shader at \"{}\"\n", type_string, path);
::std::FILE* file = ::std::fopen(path.c_str(), "r");
- if (file == nullptr) [[unlikely]] { throw ::std::runtime_error {"unable to open shader source"}; }
-
auto const file_size = ::std::filesystem::file_size(path);
- static_assert(sizeof (GLchar) == sizeof (char));
- auto source = ::std::vector<GLchar>(file_size + 0x1u);
+ static_assert(sizeof (::GLchar) == sizeof (char));
+ auto source = ::std::vector<::GLchar>(file_size + 0x1u);
- if (::std::fread(source.data(), 0x1u, file_size, file) < file_size) [[unlikely]] {
- throw ::std::runtime_error {"unable to read shader source"};
+ if (::std::fread(source.data(), sizeof (::GLchar), file_size, file) < file_size) [[unlikely]] {
+ throw ::std::runtime_error("unable to read shader source");
}
source.push_back('\x00');
auto const source_pointer = source.data();
- shader = glCreateShader(type);
+ auto shader = glCreateShader(type);
glShaderSource(shader, 0x1, const_cast<::GLchar const* const*>(&source_pointer), nullptr);
glCompileShader(shader);
@@ -105,7 +116,7 @@ static auto ::bow::compile_shader(::GLuint& shader, ::std::string const name, ::
glGetShaderInfoLog(shader, log_length, nullptr, log);
- ::fmt::print(stderr, "unable to compiler shader:\n");
+ ::fmt::print(stderr, "[client] unable to compiler shader:\n");
::std::fwrite(log, 0x1u, static_cast<::std::size_t>(log_length), stderr);
@@ -113,25 +124,6 @@ static auto ::bow::compile_shader(::GLuint& shader, ::std::string const name, ::
throw ::std::runtime_error {"unable to compile shader"};
}
-}
-
-auto ::bow::Application::compile_shader_program(::GLuint& shader_program, ::std::string const name) noexcept -> void {
- ::fmt::print(stderr, "compiling shader program \"{}\"\n", name);
-
- ::GLuint vertex_shader;
- ::GLuint fragment_shader;
-
- using ::bow::compile_shader;
-
- // Ignore exceptions:
- compile_shader(vertex_shader, name, GL_VERTEX_SHADER);
- compile_shader(fragment_shader, name, GL_FRAGMENT_SHADER);
-
- shader_program = glCreateProgram();
- glAttachShader(shader_program, vertex_shader);
- glAttachShader(shader_program, fragment_shader);
- glLinkProgram(shader_program);
- glDeleteShader(vertex_shader);
- glDeleteShader(fragment_shader);
+ return shader;
}
diff --git a/bowshock/source/client/ShaderProgram/constructor.cxx b/bowshock/source/client/ShaderProgram/constructor.cxx
new file mode 100644
index 0000000..043d017
--- /dev/null
+++ b/bowshock/source/client/ShaderProgram/constructor.cxx
@@ -0,0 +1,32 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <filesystem>
+#include <fmt/core.h>
+#include <glad/glad.h>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+using namespace ::std::literals::string_literals;
+
+bow::ShaderProgram::ShaderProgram(::std::string const& name) {
+ ::fmt::print(stderr, "[client] compiling shader program \"{}\"\n", name);
+
+ // Ignore exceptions:
+ auto const vertex_shader = ::bow::ShaderProgram::compile_shader(name, ::bow::ShaderType::Vertex);
+ auto const fragment_shader = ::bow::ShaderProgram::compile_shader(name, ::bow::ShaderType::Fragment);
+
+ this->handle = glCreateProgram();
+ glAttachShader(handle, vertex_shader);
+ glAttachShader(handle, fragment_shader);
+ glLinkProgram(handle);
+
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+}
diff --git a/bowshock/source/client/ShaderProgram/destructor.cxx b/bowshock/source/client/ShaderProgram/destructor.cxx
new file mode 100644
index 0000000..f1356fa
--- /dev/null
+++ b/bowshock/source/client/ShaderProgram/destructor.cxx
@@ -0,0 +1,9 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/client.hxx>
+
+#include <glad/glad.h>
+
+::bow::ShaderProgram::~ShaderProgram() noexcept {
+ glDeleteProgram(this->handle);
+}
diff --git a/bowshock/source/logic/Canister/constructor.cxx b/bowshock/source/logic/Canister/constructor.cxx
new file mode 100644
index 0000000..4607b4c
--- /dev/null
+++ b/bowshock/source/logic/Canister/constructor.cxx
@@ -0,0 +1,25 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+bow::Canister::Canister() noexcept {
+ this->object_type = ::bow::ObjectType::Canister;
+
+ this->position.x = 0x0p0;
+ this->position.y = 0x0p0;
+ this->position.z = 0x0p0;
+ this->rotation.x = 0x0p0;
+ this->rotation.y = 0x0p0;
+ this->rotation.z = 0x0p0;
+ this->positional_velocity.x = 0x0p0;
+ this->positional_velocity.y = 0x0p0;
+ this->positional_velocity.z = 0x0p0;
+ this->rotational_velocity.x = 0x0p0;
+ this->rotational_velocity.y = 0x0p0;
+ this->rotational_velocity.z = 0x0p0;
+ this->mass = 0x0p0;
+ this->next = nullptr;
+ this->content = ::bow::Ware::Biowaste;
+
+ this->mass = ::bow::ware_mass(this->content) * 0x1p0;
+}
diff --git a/bowshock/source/logic/Canister/object_type_string.cxx b/bowshock/source/logic/Canister/object_type_string.cxx
new file mode 100644
index 0000000..ef8b8b4
--- /dev/null
+++ b/bowshock/source/logic/Canister/object_type_string.cxx
@@ -0,0 +1,12 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+#include <cstddef>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::Canister::object_type_string() const noexcept -> ::std::string {
+ return "canister"s;
+}
diff --git a/bowshock/source/logic/Object/object_type_string.cxx b/bowshock/source/logic/Object/object_type_string.cxx
new file mode 100644
index 0000000..8318f25
--- /dev/null
+++ b/bowshock/source/logic/Object/object_type_string.cxx
@@ -0,0 +1,12 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+#include <cstddef>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::Object::object_type_string() const noexcept -> ::std::string {
+ return "object"s;
+}
diff --git a/bowshock/source/logic/Ship/constructor.cxx b/bowshock/source/logic/Ship/constructor.cxx
new file mode 100644
index 0000000..f3c35f0
--- /dev/null
+++ b/bowshock/source/logic/Ship/constructor.cxx
@@ -0,0 +1,25 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+bow::Ship::Ship() noexcept {
+ this->object_type = ::bow::ObjectType::Ship;
+
+ this->position.x = 0x0p0;
+ this->position.y = 0x0p0;
+ this->position.z = 0x0p0;
+ this->rotation.x = 0x0p0;
+ this->rotation.y = 0x0p0;
+ this->rotation.z = 0x0p0;
+ this->positional_velocity.x = 0x0p0;
+ this->positional_velocity.y = 0x0p0;
+ this->positional_velocity.z = 0x0p0;
+ this->rotational_velocity.x = 0x0p0;
+ this->rotational_velocity.y = 0x0p0;
+ this->rotational_velocity.z = 0x0p0;
+ this->mass = 0x0p0;
+ this->next = nullptr;
+ this->type = ::bow::Ship::Type::Aquila;
+
+ this->mass = this->net_mass();
+}
diff --git a/bowshock/source/logic/Ship/net_mass.cxx b/bowshock/source/logic/Ship/net_mass.cxx
new file mode 100644
index 0000000..bfe941d
--- /dev/null
+++ b/bowshock/source/logic/Ship/net_mass.cxx
@@ -0,0 +1,9 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+auto bow::Ship::net_mass() noexcept -> double {
+ double mass = 0x1p0 / ::bow::MASS_MODIFIER;
+
+ return mass;
+}
diff --git a/bowshock/source/logic/Ship/object_type_string.cxx b/bowshock/source/logic/Ship/object_type_string.cxx
new file mode 100644
index 0000000..c38f9fd
--- /dev/null
+++ b/bowshock/source/logic/Ship/object_type_string.cxx
@@ -0,0 +1,12 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+#include <cstddef>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::Ship::object_type_string() const noexcept -> ::std::string {
+ return "ship"s;
+}
diff --git a/bowshock/source/logic/Star/constructor.cxx b/bowshock/source/logic/Star/constructor.cxx
new file mode 100644
index 0000000..60449e1
--- /dev/null
+++ b/bowshock/source/logic/Star/constructor.cxx
@@ -0,0 +1,23 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+bow::Star::Star() noexcept {
+ this->object_type = ::bow::ObjectType::Star;
+
+ this->position.x = 0x0p0;
+ this->position.y = 0x0p0;
+ this->position.z = 0x0p0;
+ this->rotation.x = 0x0p0;
+ this->rotation.y = 0x0p0;
+ this->rotation.z = 0x0p0;
+ this->positional_velocity.x = 0x0p0;
+ this->positional_velocity.y = 0x0p0;
+ this->positional_velocity.z = 0x0p0;
+ this->rotational_velocity.x = 0x0p0;
+ this->rotational_velocity.y = 0x0p0;
+ this->rotational_velocity.z = 0x0p0;
+ this->mass = 0x1p0;
+ this->next = nullptr;
+ this->type = ::bow::Star::Type::G;
+}
diff --git a/bowshock/source/logic/Star/object_type_string.cxx b/bowshock/source/logic/Star/object_type_string.cxx
new file mode 100644
index 0000000..167a9ed
--- /dev/null
+++ b/bowshock/source/logic/Star/object_type_string.cxx
@@ -0,0 +1,12 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+#include <cstddef>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::Star::object_type_string() const noexcept -> ::std::string {
+ return "star"s;
+}
diff --git a/bowshock/source/logic/Station/constructor.cxx b/bowshock/source/logic/Station/constructor.cxx
new file mode 100644
index 0000000..9e80db4
--- /dev/null
+++ b/bowshock/source/logic/Station/constructor.cxx
@@ -0,0 +1,23 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+bow::Station::Station() noexcept {
+ this->object_type = ::bow::ObjectType::Station;
+
+ this->position.x = 0x0p0;
+ this->position.y = 0x0p0;
+ this->position.z = 0x0p0;
+ this->rotation.x = 0x0p0;
+ this->rotation.y = 0x0p0;
+ this->rotation.z = 0x0p0;
+ this->positional_velocity.x = 0x0p0;
+ this->positional_velocity.y = 0x0p0;
+ this->positional_velocity.z = 0x0p0;
+ this->rotational_velocity.x = 0x0p0;
+ this->rotational_velocity.y = 0x0p0;
+ this->rotational_velocity.z = 0x0p0;
+ this->mass = 0x0p0;
+ this->next = nullptr;
+ this->type = ::bow::Station::Type::Orbis;
+}
diff --git a/bowshock/source/logic/Station/object_type_string.cxx b/bowshock/source/logic/Station/object_type_string.cxx
new file mode 100644
index 0000000..9991b41
--- /dev/null
+++ b/bowshock/source/logic/Station/object_type_string.cxx
@@ -0,0 +1,12 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+#include <cstddef>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::Station::object_type_string() const noexcept -> ::std::string {
+ return "station"s;
+}
diff --git a/bowshock/source/logic/World/constructor.cxx b/bowshock/source/logic/World/constructor.cxx
new file mode 100644
index 0000000..316ca95
--- /dev/null
+++ b/bowshock/source/logic/World/constructor.cxx
@@ -0,0 +1,23 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+bow::World::World() noexcept {
+ this->object_type = ::bow::ObjectType::World;
+
+ this->position.x = 0x0p0;
+ this->position.y = 0x0p0;
+ this->position.z = 0x0p0;
+ this->rotation.x = 0x0p0;
+ this->rotation.y = 0x0p0;
+ this->rotation.z = 0x0p0;
+ this->positional_velocity.x = 0x0p0;
+ this->positional_velocity.y = 0x0p0;
+ this->positional_velocity.z = 0x0p0;
+ this->rotational_velocity.x = 0x0p0;
+ this->rotational_velocity.y = 0x0p0;
+ this->rotational_velocity.z = 0x0p0;
+ this->mass = 0x1p0;
+ this->next = nullptr;
+ this->type = ::bow::World::Type::RockyWorld;
+}
diff --git a/bowshock/source/logic/World/object_type_string.cxx b/bowshock/source/logic/World/object_type_string.cxx
new file mode 100644
index 0000000..db05042
--- /dev/null
+++ b/bowshock/source/logic/World/object_type_string.cxx
@@ -0,0 +1,12 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+#include <cstddef>
+#include <string>
+
+using namespace ::std::literals::string_literals;
+
+auto bow::World::object_type_string() const noexcept -> ::std::string {
+ return "world"s;
+}
diff --git a/bowshock/source/logic/ship_mass.cxx b/bowshock/source/logic/ship_mass.cxx
deleted file mode 100644
index cd9dfac..0000000
--- a/bowshock/source/logic/ship_mass.cxx
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/logic.hxx>
-
-auto ::bow::ship_mass([[maybe_unused]] ::bow::Ship const identifier) noexcept -> double {
- double mass = 0x100p0;
- mass /= ::bow::MASS_MODIFIER;
-
- return mass;
-}
diff --git a/bowshock/source/logic/simulate.cxx b/bowshock/source/logic/simulate.cxx
deleted file mode 100644
index 18633c8..0000000
--- a/bowshock/source/logic/simulate.cxx
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/logic.hxx>
-
-#include <bow/runtime.hxx>
-
-#include <cstdio>
-#include <fmt/core.h>
-
-auto ::bow::simulate(::bow::ObjectRoot& system, ::std::uint64_t const duration) noexcept -> void {
- ::fmt::print(stderr, "simulating for ({}) time units\n", duration);
-
- for (::std::uint64_t i = 0x0u; i <= duration; ++i) {
- ::bow::gravitate(system);
- ::bow::move(system);
- }
-}
diff --git a/bowshock/source/logic/ware_mass.cxx b/bowshock/source/logic/ware_mass.cxx
new file mode 100644
index 0000000..58afc2d
--- /dev/null
+++ b/bowshock/source/logic/ware_mass.cxx
@@ -0,0 +1,9 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+
+auto bow::ware_mass([[maybe_unused]] ::bow::Ware const ware) noexcept -> double {
+ double mass = 0x1p0 / ::bow::MASS_MODIFIER;
+
+ return mass;
+}
diff --git a/bowshock/source/main.cxx b/bowshock/source/main.cxx
new file mode 100644
index 0000000..3105864
--- /dev/null
+++ b/bowshock/source/main.cxx
@@ -0,0 +1,9 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/application.hxx>
+
+int main(int const argc, char const* const* argv) {
+ auto application = ::bow::Application(argc, argv);
+
+ return application.run();
+}
diff --git a/bowshock/source/runtime/add_object.cxx b/bowshock/source/runtime/add_object.cxx
deleted file mode 100644
index 1ce1001..0000000
--- a/bowshock/source/runtime/add_object.cxx
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/runtime.hxx>
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <fmt/core.h>
-
-auto ::bow::add_object(::bow::ObjectRoot& root, ::bow::Object const& object_value) -> void {
- ::fmt::print(stderr, "adding object of type {}\n", ::bow::object_type_string(object_value.type));
-
- ::bow::Object* const object = new ::bow::Object;
- ::std::memcpy(object, &object_value, sizeof (object_value));
-
- object->next = root.objects;
- root.objects = object;
-}
diff --git a/bowshock/source/runtime/delete_objects.cxx b/bowshock/source/runtime/delete_objects.cxx
deleted file mode 100644
index 11550b5..0000000
--- a/bowshock/source/runtime/delete_objects.cxx
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/runtime.hxx>
-
-#include <cstdio>
-#include <fmt/core.h>
-
-auto ::bow::delete_objects(::bow::ObjectRoot const& root) noexcept -> void {
- ::fmt::print(stderr, "freeing objects\n");
-
- ::bow::Object* object;
- ::bow::Object* next;
-
- for (object = root.objects; object != nullptr; object = next) {
- ::fmt::print(stderr, "freeing object of type {}\n", ::bow::object_type_string(object->type));
-
- next = object->next;
- delete object;
- }
-}
diff --git a/bowshock/source/runtime/generate_system.cxx b/bowshock/source/runtime/generate_system.cxx
deleted file mode 100644
index 73bd1e3..0000000
--- a/bowshock/source/runtime/generate_system.cxx
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/logic.hxx>
-#include <bow/runtime.hxx>
-
-#include <cstdint>
-#include <cstdio>
-#include <fmt/core.h>
-
-auto ::bow::generate_system(::bow::ObjectRoot& system, ::std::uint64_t const identifier, ::std::uint64_t const time) -> void {
- ::fmt::print(stderr, "generating system ({:X})\n", identifier);
-
- // Note: The following code is only temporary;
- system.objects = nullptr;
- ::bow::Object objTmp;
- objTmp = ::bow::Object {
- .type = ::bow::ObjectType::Star,
- .star_type = ::bow::Star::G,
- .position = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .rotation = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .positional_velocity = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .rotational_velocity = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .mass = 0x1p0,
- // Will be overwritten anyways:
- .next = nullptr,
- };
- ::bow::add_object(system, objTmp);
-
- objTmp = ::bow::Object {
- .type = ::bow::ObjectType::World,
- .world_type = ::bow::World::RockyWorld,
- .position = {
- .x = 0x0p0,
- .y = 0x1.F76F144Dp-1,
- .z = 0x0p0,
- },
- .rotation = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .positional_velocity = {
- .x = 0x1.B2D06FF3p-23*::bow::TIME_MODIFIER,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .rotational_velocity = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x1.31DB66BBp-15,
- },
- .mass = 0x1.931AFC649369998Fp-19,
- .next = nullptr,
- };
- ::bow::add_object(system, objTmp);
-
- ::bow::simulate(system, time);
-}
diff --git a/bowshock/source/save/continue_save.cxx b/bowshock/source/save/continue_save.cxx
deleted file mode 100644
index 8bd56f5..0000000
--- a/bowshock/source/save/continue_save.cxx
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/logic.hxx>
-#include <bow/save.hxx>
-
-#include <array>
-#include <cstdint>
-#include <cstdio>
-#include <fmt/core.h>
-#include <stdexcept>
-#include <string>
-
-auto ::bow::continue_save(::bow::PlayerData& player_data, ::std::string path) -> bool {
- // Return true if save is invalid.
-
- ::fmt::print(stderr, "loading save file at \"{}\"\n", path);
-
- ::std::FILE* file = ::std::fopen(path.c_str(), "r");
-
- if (file == nullptr) [[unlikely]] {
- ::fmt::print(stderr, "unable to open save file\n");
-
- ::bow::new_save(player_data);
- return false;
- }
-
- ::std::array<::std::uint8_t, ::bow::SAVE_LENGTH> raw;
-
- if (::std::fread(raw.data(), 0x1u, ::bow::SAVE_LENGTH, file) < ::bow::SAVE_LENGTH) [[unlikely]] {
- throw ::std::runtime_error {"unable to read save file"};
- }
-
- ::std::fclose(file);
-
- ::bow::SaveData data;
-
- ::bow::decode_save(data, raw.data());
-
- if (data.format_version != ::bow::SAVE_VERSION) [[unlikely]] {
- ::fmt::print(stderr, "invalid format ({:#04X}) of save file\n", data.format_version);
-
- return true;
- }
- if (data.ship_type > ::bow::MAX_SHIP_IDENTIFIER) [[unlikely]] {
- ::fmt::print(stderr, "invalid ship type ({:#04X})\n", data.ship_type);
-
- return true;
- }
-
- player_data = ::bow::PlayerData {
- // Null-terminator is included:
- .name = "\000\000\000\000\000\000\000\000\000\000\000\000\000",
- .time = data.time,
- .system_identifier = data.system_identifier,
- .ship = {
- .type = ::bow::ObjectType::Ship,
- .ship_type = static_cast<::bow::Ship>(data.ship_type),
- .position = {
- .x = data.ship_position_x,
- .y = data.ship_position_y,
- .z = data.ship_position_z,
- },
- .rotation = {
- .x = data.ship_rotation_x,
- .y = data.ship_rotation_y,
- .z = data.ship_rotation_z,
- },
- .positional_velocity = {
- .x = data.ship_positional_velocity_x,
- .y = data.ship_positional_velocity_y,
- .z = data.ship_positional_velocity_z,
- },
- .rotational_velocity = {
- .x = data.ship_rotational_velocity_x,
- .y = data.ship_rotational_velocity_y,
- .z = data.ship_rotational_velocity_z,
- },
- .mass = ::bow::ship_mass(static_cast<::bow::Ship>(data.ship_type)),
- .next = nullptr,
- },
- .zoom = 0x4p0,
- };
-
- ::std::memcpy(player_data.name, data.commander_name, ::bow::COMMANDER_NAME_LENGTH);
- player_data.name[::bow::COMMANDER_NAME_LENGTH] = '\000';
-
- ::fmt::print(stderr, "welcome back, CMDR {}\n", player_data.name);
-
- return false;
-}
diff --git a/bowshock/source/save/decode_save.cxx b/bowshock/source/save/decode_save.cxx
deleted file mode 100644
index c2e3725..0000000
--- a/bowshock/source/save/decode_save.cxx
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/save.hxx>
-
-#include <cstdint>
-#include <cstring>
-
-auto ::bow::decode_save(::bow::SaveData& buffer, void const* data_pointer) noexcept -> void {
- auto data = reinterpret_cast<::std::uint8_t const*>(data_pointer);
-
- auto const decode_value = [&data]<typename T>(T& buffer) {
- constexpr ::std::size_t size = sizeof (buffer);
-
- ::std::memcpy(&buffer, data, size);
- data += size;
- };
-
- decode_value(buffer.format_version);
- decode_value(buffer.commander_name);
- decode_value(buffer.time);
- decode_value(buffer.system_identifier);
- decode_value(buffer.ship_type);
- decode_value(buffer.ship_position_x);
- decode_value(buffer.ship_position_y);
- decode_value(buffer.ship_position_z);
- decode_value(buffer.ship_rotation_x);
- decode_value(buffer.ship_rotation_y);
- decode_value(buffer.ship_rotation_z);
- decode_value(buffer.ship_positional_velocity_x);
- decode_value(buffer.ship_positional_velocity_y);
- decode_value(buffer.ship_positional_velocity_z);
- decode_value(buffer.ship_rotational_velocity_x);
- decode_value(buffer.ship_rotational_velocity_y);
- decode_value(buffer.ship_rotational_velocity_z);
-}
diff --git a/bowshock/source/save/encode_save.cxx b/bowshock/source/save/encode_save.cxx
deleted file mode 100644
index db45bfe..0000000
--- a/bowshock/source/save/encode_save.cxx
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/save.hxx>
-
-#include <cstdint>
-#include <cstring>
-
-auto ::bow::encode_save(void* const buffer_pointer, ::bow::SaveData const& data) noexcept -> void {
- auto buffer = reinterpret_cast<::std::uint8_t*>(buffer_pointer);
-
- auto const encode_value = [&buffer]<typename T>(T const& val) {
- constexpr ::std::size_t size = sizeof (val);
-
- ::std::memcpy(buffer, &val, size);
- buffer += size;
- };
-
- encode_value(data.format_version);
- encode_value(data.commander_name);
- encode_value(data.time);
- encode_value(data.system_identifier);
- encode_value(data.ship_type);
- encode_value(data.ship_position_x);
- encode_value(data.ship_position_y);
- encode_value(data.ship_position_z);
- encode_value(data.ship_rotation_x);
- encode_value(data.ship_rotation_y);
- encode_value(data.ship_rotation_z);
- encode_value(data.ship_positional_velocity_x);
- encode_value(data.ship_positional_velocity_y);
- encode_value(data.ship_positional_velocity_z);
- encode_value(data.ship_rotational_velocity_x);
- encode_value(data.ship_rotational_velocity_y);
- encode_value(data.ship_rotational_velocity_z);
-}
diff --git a/bowshock/source/save/new_save.cxx b/bowshock/source/save/new_save.cxx
deleted file mode 100644
index 8d8b11d..0000000
--- a/bowshock/source/save/new_save.cxx
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/logic.hxx>
-#include <bow/save.hxx>
-
-#include <cstdio>
-#include <fmt/core.h>
-
-auto ::bow::new_save(::bow::PlayerData& buffer) noexcept -> void {
- ::fmt::print(stderr, "generating new save file\n");
-
- buffer = ::bow::PlayerData {
- .name = "Caelum\000\000\000\000\000\000\000\000",
- .time = 0x0u, // 256 julian years after the Unix Epoch.
- .system_identifier = 0x45u,
- .ship = {
- .type = ::bow::ObjectType::Ship,
- .ship_type = ::bow::Ship::Aquila,
- .position = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .rotation = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .positional_velocity = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .rotational_velocity = {
- .x = 0x0p0,
- .y = 0x0p0,
- .z = 0x0p0,
- },
- .mass = ::bow::ship_mass(::bow::Ship::Aquila),
- .next = nullptr,
- },
- .zoom = 0x4p0,
- };
-
- ::fmt::print(stderr, "welcome, CMDR {}\n", buffer.name);
-}
diff --git a/bowshock/source/save/save.cxx b/bowshock/source/save/save.cxx
deleted file mode 100644
index f38c9ab..0000000
--- a/bowshock/source/save/save.cxx
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2022-2023 Gabriel Bjørnager Jensen.
-
-#include <bow/runtime.hxx>
-#include <bow/save.hxx>
-
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <fmt/core.h>
-
-auto ::bow::save(::std::string const path, ::bow::PlayerData const& player_data) noexcept -> void {
- using ::bow::SAVE_LENGTH;
-
- ::fmt::print(stderr, "saving CMDR {} at \"{}\"\n", player_data.name, path);
-
- ::std::FILE* file = ::std::fopen(path.c_str(), "w");
-
- if (file == nullptr) [[unlikely]] {
- ::fmt::print(stderr, "unable to open save file\n");
-
- ::std::abort();
- }
-
- ::bow::SaveData save_data = {
- .format_version = ::bow::SAVE_VERSION,
- // Null-terminator is included:
- .commander_name = u8"\000\000\000\000\000\000\000\000\000\000\000\000\000",
- .time = player_data.time,
- .system_identifier = player_data.system_identifier,
- .ship_type = static_cast<::std::uint8_t>(player_data.ship.ship_type),
- .ship_position_x = player_data.ship.position.x,
- .ship_position_y = player_data.ship.position.y,
- .ship_position_z = player_data.ship.position.z,
- .ship_rotation_x = player_data.ship.rotation.x,
- .ship_rotation_y = player_data.ship.rotation.y,
- .ship_rotation_z = player_data.ship.rotation.z,
- .ship_positional_velocity_x = player_data.ship.positional_velocity.x,
- .ship_positional_velocity_y = player_data.ship.positional_velocity.y,
- .ship_positional_velocity_z = player_data.ship.positional_velocity.z,
- .ship_rotational_velocity_x = player_data.ship.rotational_velocity.x,
- .ship_rotational_velocity_y = player_data.ship.rotational_velocity.y,
- .ship_rotational_velocity_z = player_data.ship.rotational_velocity.z,
- };
- ::std::memcpy(save_data.commander_name, player_data.name, sizeof (save_data.commander_name));
-
- ::std::uint8_t data[SAVE_LENGTH];
-
- ::bow::encode_save(data, save_data);
-
- ::std::fwrite(data, 0x1u, SAVE_LENGTH, file);
- ::std::fclose(file);
-}
diff --git a/bowshock/source/server/Server/destructor.cxx b/bowshock/source/server/Server/destructor.cxx
new file mode 100644
index 0000000..30b34b3
--- /dev/null
+++ b/bowshock/source/server/Server/destructor.cxx
@@ -0,0 +1,21 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/server.hxx>
+
+#include <cstdio>
+#include <fmt/core.h>
+
+::bow::Server::~Server() noexcept {
+ ::fmt::print(stderr, "[app] stopping server\n");
+
+ this->stop_flag->test_and_set();
+
+ // Wait for the server to submit.
+ this->thread->join();
+
+ delete this->stop_flag;
+
+ delete this->instance;
+
+ delete this->thread;
+}
diff --git a/bowshock/source/server/Server/start.cxx b/bowshock/source/server/Server/start.cxx
new file mode 100644
index 0000000..d5b7bd5
--- /dev/null
+++ b/bowshock/source/server/Server/start.cxx
@@ -0,0 +1,28 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+#include <bow/server.hxx>
+
+#include <atomic>
+#include <cstdio>
+#include <fmt/core.h>
+#include <thread>
+#include <utility>
+
+auto bow::Server::start() -> ::bow::Server* {
+ ::fmt::print(stderr, "[app] starting server\n");
+
+ auto stop_flag = new ::std::atomic_flag();
+
+ auto server = new ::bow::ServerInstance(stop_flag);
+
+ auto thread = new ::std::thread(::bow::ServerInstance::run, server);
+
+ auto const instance = new ::bow::Server;
+
+ instance->thread = ::std::move(thread);
+ instance->instance = ::std::move(server);
+ instance->stop_flag = ::std::move(stop_flag);
+
+ return instance;
+}
diff --git a/bowshock/source/server/ServerInstance/add_object.cxx b/bowshock/source/server/ServerInstance/add_object.cxx
new file mode 100644
index 0000000..3e5126b
--- /dev/null
+++ b/bowshock/source/server/ServerInstance/add_object.cxx
@@ -0,0 +1,25 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/server.hxx>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fmt/core.h>
+
+template<::bow::ObjectLike T>
+auto bow::ServerInstance::add_object(::bow::ObjectRoot& root, T const& object_value) -> void {
+ ::fmt::print(stderr, "[server] adding object of type {}\n", object_value.object_type_string());
+
+ auto const object = new T;
+ *object = object_value;
+
+ object->next = root.objects;
+ root.objects = object;
+}
+
+template auto ::bow::ServerInstance::add_object<::bow::Canister>(::bow::ObjectRoot& root, ::bow::Canister const& object_value) -> void;
+template auto ::bow::ServerInstance::add_object<::bow::Ship>( ::bow::ObjectRoot& root, ::bow::Ship const& object_value) -> void;
+template auto ::bow::ServerInstance::add_object<::bow::Star>( ::bow::ObjectRoot& root, ::bow::Star const& object_value) -> void;
+template auto ::bow::ServerInstance::add_object<::bow::Station>( ::bow::ObjectRoot& root, ::bow::Station const& object_value) -> void;
+template auto ::bow::ServerInstance::add_object<::bow::World>( ::bow::ObjectRoot& root, ::bow::World const& object_value) -> void;
diff --git a/bowshock/source/server/ServerInstance/constructor.cxx b/bowshock/source/server/ServerInstance/constructor.cxx
new file mode 100644
index 0000000..7ac0cec
--- /dev/null
+++ b/bowshock/source/server/ServerInstance/constructor.cxx
@@ -0,0 +1,9 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/server.hxx>
+
+#include <atomic>
+
+::bow::ServerInstance::ServerInstance(::std::atomic_flag* stop_flag) noexcept {
+ this->stop_flag = stop_flag;
+}
diff --git a/bowshock/source/server/ServerInstance/delete_objects.cxx b/bowshock/source/server/ServerInstance/delete_objects.cxx
new file mode 100644
index 0000000..bd8a970
--- /dev/null
+++ b/bowshock/source/server/ServerInstance/delete_objects.cxx
@@ -0,0 +1,21 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/server.hxx>
+
+#include <cstdio>
+#include <fmt/core.h>
+#include <type_traits>
+
+auto bow::ServerInstance::delete_objects(::bow::ObjectRoot const& root) noexcept -> void {
+ ::fmt::print(stderr, "[server] deleting objects\n");
+
+ ::bow::Object* object;
+ ::bow::Object* next;
+
+ for (object = root.objects; object != nullptr; object = next) {
+ ::fmt::print(stderr, "[server] deleting object of type {}\n", object->object_type_string());
+
+ next = object->next;
+ delete object;
+ }
+}
diff --git a/bowshock/source/server/ServerInstance/generate_system.cxx b/bowshock/source/server/ServerInstance/generate_system.cxx
new file mode 100644
index 0000000..a3188f1
--- /dev/null
+++ b/bowshock/source/server/ServerInstance/generate_system.cxx
@@ -0,0 +1,43 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+#include <bow/server.hxx>
+
+#include <cstdint>
+#include <cstdio>
+#include <fmt/core.h>
+
+auto bow::ServerInstance::generate_system(::bow::ObjectRoot& system, ::std::uint64_t const identifier, ::std::uint64_t const time) -> void {
+ ::fmt::print(stderr, "[server] generating system ({:x})\n", identifier);
+
+ if (system.objects != nullptr) [[likely]] {
+ this->delete_objects(system);
+ }
+
+ // Note: The following code is only temporary;
+
+ auto const star = []() -> ::bow::Star {
+ auto star = ::bow::Star();
+
+ star.mass = 0x1p0,
+ star.type = ::bow::Star::Type::G;
+
+ return star;
+ }();
+ this->add_object(system, star);
+
+ auto const world = []() -> ::bow::World {
+ auto world = ::bow::World();
+
+ world.position.y = 0x1.F76F144Dp-1;
+ world.positional_velocity.x = 0x1.B2D06FF3p-23 * ::bow::TIME_MODIFIER;
+ world.rotational_velocity.z = 0x1.31DB66BBp-15;
+ world.mass = 0x1.931AFC649369998Fp-19,
+ world.type = ::bow::World::Type::RockyWorld;
+
+ return world;
+ }();
+ this->add_object(system, world);
+
+ this->simulate(system, time);
+}
diff --git a/bowshock/source/logic/gravitate.cxx b/bowshock/source/server/ServerInstance/gravitate.cxx
index 2e06001..0a390de 100644
--- a/bowshock/source/logic/gravitate.cxx
+++ b/bowshock/source/server/ServerInstance/gravitate.cxx
@@ -1,5 +1,6 @@
// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+#include <bow/server.hxx>
#include <bow/logic.hxx>
#include <cmath>
@@ -58,7 +59,7 @@ namespace bow {
}
}
-auto ::bow::gravitate(::bow::ObjectRoot& system) noexcept -> void {
+auto bow::ServerInstance::gravitate(::bow::ObjectRoot& system) noexcept -> void {
for (::bow::Object* obj0 = system.objects; obj0 != nullptr; obj0 = obj0->next) {
for (::bow::Object* obj1 = obj0->next; obj1 != nullptr; obj1 = obj1->next) {
::bow::gravitate_pair(*obj0, *obj1);
@@ -66,7 +67,7 @@ auto ::bow::gravitate(::bow::ObjectRoot& system) noexcept -> void {
}
}
-auto ::bow::gravitate(::bow::ObjectRoot& objects, ::bow::ObjectRoot const& system) noexcept -> void {
+auto bow::ServerInstance::gravitate(::bow::ObjectRoot& objects, ::bow::ObjectRoot const& system) noexcept -> void {
for (::bow::Object* object = objects.objects; object != nullptr; object = object->next) {
for (::bow::Object* par = system.objects; par != nullptr; par = par->next) {
::bow::gravitate_single(*object, *par);
diff --git a/bowshock/source/server/ServerInstance/loop.cxx b/bowshock/source/server/ServerInstance/loop.cxx
new file mode 100644
index 0000000..b7854e0
--- /dev/null
+++ b/bowshock/source/server/ServerInstance/loop.cxx
@@ -0,0 +1,48 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/server.hxx>
+#include <bow/logic.hxx>
+
+#include <cmath>
+#include <cstdio>
+#include <fmt/core.h>
+#include <stdexcept>
+
+auto bow::ServerInstance::loop() -> void {
+ ::fmt::print(stderr, "[server] entering main loop\n");
+
+ // For stellar bodies:
+ ::bow::ObjectRoot system_root = {
+ .objects = nullptr,
+ };
+
+ // For miscellaneous objects (canisters, shps...):
+ ::bow::ObjectRoot objects_root = {
+ .objects = nullptr,
+ };
+
+ this->generate_system(system_root, 0x0u, 0x0u);
+
+ auto const canister = []() -> ::bow::Canister {
+ auto canister = ::bow::Canister();
+
+ canister.position.y = -0x2p0;
+ canister.positional_velocity.x = -0x1p-12;
+
+ return canister;
+ }();
+ this->add_object(objects_root, canister);
+
+ while (!this->stop_flag->test() && !::bow::GOT_INTERRUPT.test()) {
+ this->gravitate(system_root);
+ this->gravitate(objects_root, system_root);
+
+ this->move(system_root);
+ this->move(objects_root);
+ }
+
+ ::fmt::print(stderr, "[server] submitting\n");
+
+ this->delete_objects(objects_root);
+ this->delete_objects(system_root);
+}
diff --git a/bowshock/source/logic/move.cxx b/bowshock/source/server/ServerInstance/move.cxx
index 321bcfa..03a4210 100644
--- a/bowshock/source/logic/move.cxx
+++ b/bowshock/source/server/ServerInstance/move.cxx
@@ -1,8 +1,9 @@
// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+#include <bow/server.hxx>
#include <bow/logic.hxx>
-auto ::bow::move(::bow::ObjectRoot& root) noexcept -> void {
+auto bow::ServerInstance::move(::bow::ObjectRoot& root) noexcept -> void {
auto const move = [](::bow::Object& object) -> void {
object.position.x += object.positional_velocity.x;
object.position.y += object.positional_velocity.y;
diff --git a/bowshock/source/server/ServerInstance/run.cxx b/bowshock/source/server/ServerInstance/run.cxx
new file mode 100644
index 0000000..2275190
--- /dev/null
+++ b/bowshock/source/server/ServerInstance/run.cxx
@@ -0,0 +1,18 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/server.hxx>
+
+#include <cstdio>
+#include <fmt/core.h>
+#include <stdexcept>
+
+auto bow::ServerInstance::run(::bow::ServerInstance* server) noexcept -> void {
+ ::fmt::print(stderr, "[server] angle unit: {:.3f} rad\n", 0x1p0);
+ ::fmt::print(stderr, "[server] distance unit: {:.3f} m\n", ::bow::DISTANCE_MODIFIER);
+ ::fmt::print(stderr, "[server] mass unit: {:.3f} kg\n", ::bow::MASS_MODIFIER);
+ ::fmt::print(stderr, "[server] time unit: {:.3f} s\n", ::bow::TIME_MODIFIER);
+ ::fmt::print(stderr, "[server] gravitational constant: {:.9f} (factor: {:.3f}))\n", ::bow::GRAVITY_VALUE, ::bow::GRAVITY_FACTOR);
+
+ // We ignore exceptions for debug purposes.
+ server->loop();
+}
diff --git a/bowshock/source/server/ServerInstance/simulate.cxx b/bowshock/source/server/ServerInstance/simulate.cxx
new file mode 100644
index 0000000..2dcf85c
--- /dev/null
+++ b/bowshock/source/server/ServerInstance/simulate.cxx
@@ -0,0 +1,17 @@
+// Copyright 2022-2023 Gabriel Bjørnager Jensen.
+
+#include <bow/logic.hxx>
+#include <bow/server.hxx>
+
+#include <cstdint>
+#include <cstdio>
+#include <fmt/core.h>
+
+auto bow::ServerInstance::simulate(::bow::ObjectRoot& system, ::std::uint64_t const duration) noexcept -> void {
+ ::fmt::print(stderr, "[server] simulating for ({}) time units\n", duration);
+
+ for (auto i = UINT64_C(0x0); i <= duration; ++i) {
+ this->gravitate(system);
+ this->move(system);
+ }
+}