diff options
48 files changed, 535 insertions, 291 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.md index c91dd27..3d50c6f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.md @@ -68,6 +68,26 @@ * Fix shader validation script * Fix shader +* Fix CMake not complaining about data directory not being specified +* Find packages in CMake +* Update exception specifiers +* Add terminal parameter for specifying the port number +* Update help screen +* Rename terminal paramaeter 'name' to 'save' +* Add server configuration structure +* Clean up code +* Improve commenting +* Update ware list +* Add linked-list class for object roots +* Fix gravitate in the case of overlaping objects +* Add our own terminate functions for unrecoverable errors +* Improve error handling +* Add new header for network formats +* Fix save path +* Make readme Markdown +* Make changelog Markdown +* Rename home_directory to base_directory + # 0.B.2 * Fix data directory not being set correctly by CMake; diff --git a/bowshock/CMakeLists.txt b/bowshock/CMakeLists.txt index cd09057..9826336 100644 --- a/bowshock/CMakeLists.txt +++ b/bowshock/CMakeLists.txt @@ -2,10 +2,14 @@ cmake_minimum_required(VERSION 3.21) option(BOW_DATA_DIRECTORY "Directory for storing run-time data (assets, shaders...)." "") -if("${BOW_DATA_DIRECTORY}" STREQUAL "") +if(NOT DEFINED BOW_DATA_DIRECTORY) message(FATAL_ERROR "Data directory (BOW_DATA_DIRECTORY) not specified") endif() +find_package( + glfw3 REQUIRED +) + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) @@ -25,6 +29,7 @@ add_executable( "source/client/Client/constructor.cxx" "source/client/Client/destructor.cxx" + "source/client/Client/loop.cxx" "source/client/Client/poll_events.cxx" "source/client/Client/run.cxx" "source/client/Client/save_path.cxx" @@ -43,7 +48,8 @@ add_executable( "source/client/ShaderProgram/constructor.cxx" "source/client/ShaderProgram/destructor.cxx" - "source/base/home_directory.cxx" + "source/base/base_directory.cxx" + "source/base/terminate.cxx" "source/logic/Canister/constructor.cxx" "source/logic/Canister/object_type_string.cxx" @@ -59,11 +65,17 @@ add_executable( "source/logic/World/constructor.cxx" "source/logic/World/object_type_string.cxx" + "source/server/ObjectIterator/constructor.cxx" + "source/server/ObjectIterator/operator_equality.cxx" + "source/server/ObjectIterator/operator_increment.cxx" + "source/server/ObjectRoot/add.cxx" + "source/server/ObjectRoot/begin.cxx" + "source/server/ObjectRoot/constructor.cxx" + "source/server/ObjectRoot/destructor.cxx" + "source/server/ObjectRoot/end.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" @@ -76,6 +88,7 @@ add_dependencies( bowshock glad + glfw ) target_include_directories( @@ -97,8 +110,8 @@ target_compile_definitions( bowshock PRIVATE GLFW_INCLUDE_NONE - BOW_DATA_DIRECTORY="${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) @@ -118,7 +131,6 @@ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|GNU") -Wall -Wdouble-promotion -Wextra - -Wfloat-equal -Wformat=2 -Winvalid-utf8 -Wmissing-declarations diff --git a/bowshock/include/bow/application.hxx b/bowshock/include/bow/application.hxx index ebbeb10..0965730 100644 --- a/bowshock/include/bow/application.hxx +++ b/bowshock/include/bow/application.hxx @@ -32,8 +32,9 @@ namespace bow { private: ::bow::ClientConfiguration client_configuration; + ::bow::ServerConfiguration server_configuration; - ::bow::Client* client; + ::bow::Client* client; ::bow::Server* server; [[noreturn]] static auto print_credits() noexcept -> void; diff --git a/bowshock/include/bow/base.hxx b/bowshock/include/bow/base.hxx index a7e3c6b..3691019 100644 --- a/bowshock/include/bow/base.hxx +++ b/bowshock/include/bow/base.hxx @@ -2,25 +2,27 @@ #pragma once -#ifndef BOW_DATA_DIRECTORY -#error data directory not specified! +#ifndef bow_DATA_DIRECTORY +#error data directory not specified #endif #include <atomic> #include <climits> #include <cstdint> +#include <exception> +#include <source_location> #include <string> -static_assert(CHAR_BIT == 0x8, "bytes must contain exactly eight bits."); +static_assert(CHAR_BIT == 0x8, "bytes must contain exactly eight bits"); namespace bow { - inline ::std::string DATA_DIRECTORY(BOW_DATA_DIRECTORY); + 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 = 0x10u; - constexpr ::std::uint8_t NUMBER_OF_QUOTE_IDENTIFIERS = UINT8_C(0x24); + constexpr ::std::uint_least8_t NUMBER_OF_QUOTE_IDENTIFIERS = UINT8_C(0x24); template<typename T> struct Xyz { T x; @@ -35,5 +37,10 @@ namespace bow { // atomic. extern ::std::atomic_flag GOT_INTERRUPT; - auto home_directory() noexcept -> ::std::string; + [[noreturn]] auto terminate(::std::string const& location, ::std::string const& message) noexcept -> void; + + // Returns the path to the user's home directory. + // If we are unable to determine its path, we + // instead use the current directory ".". + auto base_directory() noexcept -> ::std::string; } diff --git a/bowshock/include/bow/client.hxx b/bowshock/include/bow/client.hxx index 2e2a15d..cc71528 100644 --- a/bowshock/include/bow/client.hxx +++ b/bowshock/include/bow/client.hxx @@ -43,10 +43,11 @@ namespace bow { */ struct ClientConfiguration { - ::std::string directory; - ::std::string save_name; - bool new_save: 0x1; - bool skip_start_sequence: 0x1; + ::std::string directory; + ::std::string save_name; + ::std::uint_least16_t network_port; + bool new_save: 0x1; + bool skip_start_sequence: 0x1; }; class PlayerData { @@ -96,8 +97,6 @@ namespace bow { enum struct ShaderType { Fragment, Geometry, - TesselationControl, - TesselationEvaluation, Vertex, }; @@ -137,7 +136,6 @@ namespace bow { static auto save_path(::std::string const& directory, ::std::string const& name) noexcept -> ::std::string; - auto run() noexcept -> void; private: @@ -149,8 +147,8 @@ namespace bow { auto poll_events() noexcept -> bool; - auto start_sequence() noexcept -> bool; + auto start_sequence() -> bool; - auto loop() noexcept -> void; + auto loop() -> void; }; } diff --git a/bowshock/include/bow/logic.hxx b/bowshock/include/bow/logic.hxx index b5fec0b..ba9c6a1 100644 --- a/bowshock/include/bow/logic.hxx +++ b/bowshock/include/bow/logic.hxx @@ -18,71 +18,85 @@ namespace bow { constexpr double GRAVITY_VALUE = 0x1.258688101B4BB16Dp-34 * ::bow::GRAVITY_FACTOR; // gravitational constant (s^2*m*t^2) enum struct Ware: ::std::uint8_t { + AcidsAndBases, Air, - Aluminium, + AlcoholicBeverages, AncientArtefacts, - AnimalFurs, - AnimalMeat, - AnimalSkins, + AnimalMeats, Atomics, + Batteries, BattleWeapons, Beer, Biowaste, - Cheese, + Cameras, + Cannabis, ChemicalWaste, - Cobalt, - Coffee, + Clothing, + CoffeeAndTea, ComputerParts, Computers, - Copper, + ComputerSoftware, Cuttlery, Dairy, + Drones, + ElectronicComponents, + EncryptedData, + EnergyGenerators, Explosives, + Films, FruitsAndVegetables, Gemstones, - Gold, HandWeapons, HullParts, - HydrogenFuel, - Iron, + Hypnotics, Ivory, + Jewellry, Lasers, - Leather, - Liquor, - Lithium, LiveAnimals, LuxuryGoods, + Machinery, Magnets, Medicine, Minerals, + Money, Monitors, + Music, + Narcotics, NerveAgents, + NobleGases, + NobleMetals, OrganicDyes, Paper, Pearls, Pesticides, - Platinum, - Plutonium, + Petroleums, + Pharmaceuticals, + Pornography, + Probes, + ProtiumFuel, Radioactives, + Recyclables, Robots, Rockets, Rubbish, - Silver, + ScientificInstruments, + SkinsAndFurs, Slaves, + Soils, + Spirits, StorageDevices, Superconductors, + SyntheticDyes, SyntheticMeat, - Tea, - Titanium, Tobacco, TritiumFuel, - Uranium, + VirtualIntelligences, Water, Wine, XenoRelics, }; - enum struct ObjectType : ::std::uint8_t { + enum struct ObjectType: ::std::uint8_t { Canister, Ship, Star, @@ -100,8 +114,6 @@ namespace bow { ::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; @@ -208,9 +220,5 @@ namespace bow { [[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/network.hxx b/bowshock/include/bow/network.hxx new file mode 100644 index 0000000..0cad935 --- /dev/null +++ b/bowshock/include/bow/network.hxx @@ -0,0 +1,14 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#pragma once + +#include <bow/logic.hxx> + +namespace bow { + // I chose the default port number (37279) as it's + // the index number of Proycon in the Hipparcos + // Catalogue. + constexpr ::std::uint_least16_t DEFAULT_NETWORK_PORT = UINT16_C(0x919F); + constexpr ::std::uint_least16_t MINIMUM_NETWORK_PORT = UINT16_C(0x0001); + constexpr ::std::uint_least16_t MAXIMUM_NETWORK_PORT = UINT16_C(0xFFFF); +} diff --git a/bowshock/include/bow/server.hxx b/bowshock/include/bow/server.hxx index c1f44f2..71136a4 100644 --- a/bowshock/include/bow/server.hxx +++ b/bowshock/include/bow/server.hxx @@ -5,23 +5,70 @@ #include <bow/logic.hxx> #include <atomic> +#include <cstddef> #include <cstdint> #include <thread> namespace bow { - class ServerInstance { + struct ServerConfiguration { + ::std::uint_least16_t network_port; + }; + + struct ObjectElement { + ::bow::Object* object; + ::bow::ObjectElement* next; + }; + + class ObjectRoot; + + class ObjectIterator { public: - explicit ServerInstance(::std::atomic_flag* stop_flag) noexcept; + ObjectIterator(::bow::ObjectRoot const& root) noexcept; - static auto run(::bow::ServerInstance* server) noexcept -> void; + ~ObjectIterator() noexcept = default; + + inline auto operator *() noexcept -> ::bow::Object& { return *this->element->object; } + inline auto operator *() const noexcept -> ::bow::Object const& { return *this->element->object; } + + auto operator ==(::bow::ObjectIterator const& other) const noexcept -> bool; + auto operator ==(::std::nullptr_t) const noexcept -> bool; + + auto operator ++() noexcept -> ::bow::ObjectIterator&; private: - ::std::atomic_flag* stop_flag; + ::bow::ObjectElement* element; + }; + + class ObjectRoot { + public: + ObjectRoot() noexcept; + + ~ObjectRoot() noexcept; + + auto begin() const noexcept -> ::bow::ObjectIterator; + auto end() const noexcept -> ::bow::ObjectIterator; + + inline auto has_objects() const noexcept -> bool { return this->elements != nullptr; } template<::bow::ObjectLike T> - auto add_object(::bow::ObjectRoot& root, T const& object) -> void; + auto add(T const& value) -> T*; + + private: + friend ::bow::ObjectIterator; - auto delete_objects(::bow::ObjectRoot const& root) noexcept -> void; + ::bow::ObjectElement* elements; + }; + + class ServerInstance { + public: + explicit ServerInstance(::bow::ServerConfiguration const& configuration, ::std::atomic_flag* stop_flag) noexcept; + + static auto run(::bow::ServerInstance* server) noexcept -> void; + + private: + ::bow::ServerConfiguration configuration; + + ::std::atomic_flag* stop_flag; auto generate_system(::bow::ObjectRoot& system, ::std::uint64_t identifier, ::std::uint64_t time) -> void; @@ -37,11 +84,13 @@ namespace bow { class Server { public: - static auto start() -> ::bow::Server*; + static auto start(::bow::ServerConfiguration const& configuration) -> ::bow::Server*; ~Server() noexcept; private: + Server() noexcept = default; + ::std::thread* thread; ::bow::ServerInstance* instance; @@ -55,4 +104,4 @@ namespace bow { } template<> -auto bow::ServerInstance::add_object<::bow::Object>(::bow::ObjectRoot& root, ::bow::Object const& object_value) -> void = delete; +auto bow::ObjectRoot::add<::bow::Object>(::bow::Object const& object_value) -> ::bow::Object* = delete; diff --git a/bowshock/source/application/Application/constructor.cxx b/bowshock/source/application/Application/constructor.cxx index a0a900a..7644720 100644 --- a/bowshock/source/application/Application/constructor.cxx +++ b/bowshock/source/application/Application/constructor.cxx @@ -2,6 +2,7 @@ #include <bow/application.hxx> #include <bow/client.hxx> +#include <bow/network.hxx> #include <cstdio> #include <cstdlib> @@ -16,8 +17,7 @@ bow::Application::Application(int const argc, char const* const* const argv) noe auto const program_name = [&argc, argv]() -> ::std::string { if (argc < 0x1) [[unlikely]] { - ::fmt::print(stderr, "[app] program name not provided\n"); - ::std::abort(); + ::bow::terminate("app", "program not provided"); } else { return ::std::string(*argv); } @@ -25,20 +25,26 @@ bow::Application::Application(int const argc, char const* const* const argv) noe this->client_configuration = ::bow::ClientConfiguration { .directory = ""s, + .save_name = "save"s, + .network_port = ::bow::DEFAULT_NETWORK_PORT, .new_save = false, .skip_start_sequence = false, }; + this->server_configuration = ::bow::ServerConfiguration { + .network_port = ::bow::DEFAULT_NETWORK_PORT, + }; + + this->client =nullptr; + this->server =nullptr; + ::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(); + auto const base_directory = ::bow::base_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 index 73a2bf0..51fdec5 100644 --- a/bowshock/source/application/Application/destructor.cxx +++ b/bowshock/source/application/Application/destructor.cxx @@ -9,8 +9,7 @@ bow::Application::~Application() noexcept { ::fmt::print(stderr, "[app] quitting\n"); delete this->client; - delete this->server; - ::fmt::print(stderr, "\nGoodbye!\n"); + ::fmt::print(stderr, "\nGoodbye! \u2764\n"); } diff --git a/bowshock/source/application/Application/get_quote.cxx b/bowshock/source/application/Application/get_quote.cxx index f614ccd..ac4494c 100644 --- a/bowshock/source/application/Application/get_quote.cxx +++ b/bowshock/source/application/Application/get_quote.cxx @@ -3,8 +3,8 @@ #include <bow/application.hxx> #include <cstdint> -#include <cstdio> -#include <fmt/core.h> +#include <format> +#include <stdexcept> #include <string> #include <tuple> @@ -16,9 +16,7 @@ auto bow::Application::get_quote(::std::uint8_t const identifier) -> ::std::tupl switch (identifier) { default: - ::fmt::print(stderr, "[app] invalid quote identifier ({})\n", identifier); - - throw ::std::invalid_argument("invalid quote identifier"); + throw ::std::invalid_argument(::std::format("invalid quote identifier ({})", identifier)); case 0x0u: quote = "You gotta be heaven to see heaven."; diff --git a/bowshock/source/application/Application/initialise_signal.cxx b/bowshock/source/application/Application/initialise_signal.cxx index e77e9ca..c2ebd4a 100644 --- a/bowshock/source/application/Application/initialise_signal.cxx +++ b/bowshock/source/application/Application/initialise_signal.cxx @@ -7,6 +7,7 @@ #include <cstdio> #include <cstdlib> #include <fmt/core.h> +#include <format> #include <stdexcept> // 31.10.4. @@ -30,9 +31,7 @@ auto bow::Application::initialise_signal() -> void { 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, "[app] unable to set signal handler for {}\n", signal); - - throw ::std::runtime_error("unable to set signal handler"); + throw ::std::runtime_error(::std::format("unable to set signal handler for {}", signal)); } }; diff --git a/bowshock/source/application/Application/parse_parameters.cxx b/bowshock/source/application/Application/parse_parameters.cxx index 1993eba..26b353f 100644 --- a/bowshock/source/application/Application/parse_parameters.cxx +++ b/bowshock/source/application/Application/parse_parameters.cxx @@ -2,12 +2,16 @@ #include <bow/application.hxx> #include <bow/client.hxx> +#include <bow/network.hxx> +#include <charconv> #include <cstdio> #include <fmt/core.h> +#include <format> #include <stdexcept> #include <string> #include <string_view> +#include <system_error> #include <vector> using namespace ::std::literals::string_literals; @@ -16,23 +20,46 @@ auto bow::Application::parse_parameters(::std::string const& program_name, ::std ::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 { + auto const parse = [&program_name, this](::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); + this->client_configuration.directory = value; + } else if (field == "port") { + auto const numeric_value = [&field, &value]() -> ::std::uint16_t { + ::std::uint_least16_t numeric_value = UINT16_C(0x0); - client_configuration.directory = value; - } else if (field == "name") { - ::fmt::print(stderr, "[app] setting save name to \"{}\"\n", value); + auto const result = ::std::from_chars(value.begin(), value.end(), numeric_value); - client_configuration.save_name = value; - } else { - ::fmt::print(stderr, "[app] invalid field name \"{}\"\n", field); + bool const out_of_range = + result.ec == ::std::errc::result_out_of_range + || numeric_value < ::bow::MINIMUM_NETWORK_PORT + || numeric_value > ::bow::MAXIMUM_NETWORK_PORT; + + if (out_of_range) [[unlikely]] { + ::fmt::print(stderr, "[app] value ({}) for {} is out of range (min. is {}, max. is {})\n", value, field, ::bow::MINIMUM_NETWORK_PORT, ::bow::MAXIMUM_NETWORK_PORT); + throw ::std::invalid_argument("value out of range"); + } + + if (result.ec != ::std::errc()) [[unlikely]] { + ::fmt::print(stderr, "[app] invalid value ({}) for {}\n", value, field); + throw ::std::invalid_argument("invalid value"); + } + + return numeric_value; + }(); - throw ::std::logic_error("invalid field name"); + ::fmt::print(stderr, "[app] setting the port number to {}\n", numeric_value); + this->client_configuration.network_port = numeric_value; + this->server_configuration.network_port = numeric_value; + } else if (field == "save") { + ::fmt::print(stderr, "[app] setting save name to \"{}\"\n", value); + this->client_configuration.save_name = value; + } else { + throw ::std::invalid_argument(::std::format("invalid field name \"{}\"", field)); } } else { auto const setting = ::std::string_view(parameter.begin(), parameter.end()); @@ -43,22 +70,19 @@ auto bow::Application::parse_parameters(::std::string const& program_name, ::std ::bow::Application::print_help(program_name); } else if (setting == "new") { ::fmt::print(stderr, "[app] using default save file\n"); - - client_configuration.new_save = true; + this->client_configuration.new_save = true; } else if (setting == "skip") { ::fmt::print(stderr, "[app] skipping start sequence\n"); - - client_configuration.skip_start_sequence = true; + this->client_configuration.skip_start_sequence = true; } else { ::fmt::print(stderr, "[app] invalid setting\"{}\"\n", setting); - - throw ::std::logic_error("invalid setting"); + throw ::std::invalid_argument("invalid setting"); } } }; - for (auto const parameter : parameters) { - parse(this->client_configuration, parameter); + for (auto const parameter: parameters) { + parse(parameter); } } } diff --git a/bowshock/source/application/Application/print_credits.cxx b/bowshock/source/application/Application/print_credits.cxx index 4a67dfb..1136e05 100644 --- a/bowshock/source/application/Application/print_credits.cxx +++ b/bowshock/source/application/Application/print_credits.cxx @@ -7,6 +7,7 @@ #include <filesystem> #include <fmt/core.h> #include <stdexcept> +#include <vector> auto bow::Application::print_credits() noexcept -> void { ::std::string path = ::bow::DATA_DIRECTORY + "/CREDITS.txt"; @@ -21,24 +22,28 @@ auto bow::Application::print_credits() noexcept -> void { ::std::exit(EXIT_FAILURE); } - ::std::string credits; - - try { - credits.reserve(file_size); - } catch (...) { - ::fmt::print(stderr, "[app] unable to allocate memory for credits\n"); - + auto credits = [file_size]() noexcept -> ::std::vector<char> { + try { + return ::std::vector<char>(file_size + 0x2u); + } catch (...) { + ::fmt::print(stderr, "[app] unable to allocate memory for credits\n"); + ::std::exit(EXIT_FAILURE); + } + }(); + + if (::std::fread(&credits.data()[0x1], sizeof (char), file_size, file) < file_size) [[unlikely]] { + ::fmt::print(stderr, "[app] unable to read credits file\n"); ::std::exit(EXIT_FAILURE); } - ::std::fread(credits.data(), 0x1u, file_size, file); ::std::fclose(file); - credits.append("\n"); + credits.front() = '\n'; + credits.back() = '\n'; - ::std::fputs(credits.c_str(), stdout); + ::std::fwrite(credits.data(), sizeof (char), file_size + 0x2u, stdout); - credits.~basic_string(); + credits.~vector(); ::std::exit(EXIT_SUCCESS); } diff --git a/bowshock/source/application/Application/print_help.cxx b/bowshock/source/application/Application/print_help.cxx index f2e1788..9b4f68f 100644 --- a/bowshock/source/application/Application/print_help.cxx +++ b/bowshock/source/application/Application/print_help.cxx @@ -8,16 +8,21 @@ auto bow::Application::print_help(::std::string const& program_name) noexcept -> void { ::fmt::print( "\n" - "\x1B[1mBowshock\x1B[0m {:x}.{:x}.{:x}\n" - "Copyright 2022-2023 Gabriel Bj\u00F8rnager Jensen.\n" + "\x1B[1mBowshock\x1B[0m {:X}.{:X}.{:X}\n" + "Copyright \u00A9 2022\u20102023 \x1B[1mGabriel Bj\u00F8rnager Jensen\x1B[0m.\n" "\n" - "Usage: \"{}\" <configuration> [savefile]\n" + "Usage: \"{}\" <parameters> <flags>\n" "\n" - "configuration:\n" - " --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_start_sequence \x1B[1mskip\x1B[0m the intro\n" + "Parameters:\n" + " directory Set the application \x1B[1mdirectory\x1B[0m to be used\n" + " port Set the (decimal) \x1B[1mport\x1B[0m number used to connect to the server\n" + " save Set the \x1B[1mname\x1B[0m of the save file\n" + "\n" + "Flags:\n" + " credits Print the game \x1B[1mcredits\x1B[0m\n" + " help Print the \x1B[1mhelp\x1B[0m screen\n" + " new Start a \x1B[1mnew\x1B[0m save file\n" + " skip \x1B[1mskip\x1B[0m the intro\n" "\n", ::bow::VERSION.major, ::bow::VERSION.minor, ::bow::VERSION.patch, program_name ); diff --git a/bowshock/source/application/Application/run.cxx b/bowshock/source/application/Application/run.cxx index ebbd7c8..ddbfed8 100644 --- a/bowshock/source/application/Application/run.cxx +++ b/bowshock/source/application/Application/run.cxx @@ -14,6 +14,8 @@ #include <string> #include <tuple> +#include <format> + auto bow::Application::run() -> int { ::std::srand(static_cast<int unsigned>(::std::time(nullptr))); @@ -44,7 +46,7 @@ auto bow::Application::run() -> int { this->initialise_signal(); // The server handles all of its exceptions. - this->server = ::bow::Server::start(); + this->server = ::bow::Server::start(this->server_configuration); this->client = new ::bow::Client(this->client_configuration); diff --git a/bowshock/source/base/home_directory.cxx b/bowshock/source/base/base_directory.cxx index 2e68917..4d86ce4 100644 --- a/bowshock/source/base/home_directory.cxx +++ b/bowshock/source/base/base_directory.cxx @@ -9,11 +9,11 @@ using namespace ::std::literals::string_literals; -auto bow::home_directory() noexcept -> ::std::string { +auto bow::base_directory() noexcept -> ::std::string { auto const pointer = ::std::getenv("HOME"); if (pointer == nullptr) [[unlikely]] { - ::fmt::print(stderr, "unable to get home directory, using current directory\n"); + ::fmt::print(stderr, "unable to get home directory - using current directory\n"); return "."s; } diff --git a/bowshock/source/base/terminate.cxx b/bowshock/source/base/terminate.cxx new file mode 100644 index 0000000..94e1ed6 --- /dev/null +++ b/bowshock/source/base/terminate.cxx @@ -0,0 +1,14 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/base.hxx> + +#include <cstdlib> +#include <cstdio> +#include <fmt/core.h> +#include <string> + +auto bow::terminate(::std::string const& location, ::std::string const& message) noexcept -> void { + ::fmt::print(stderr, "[{}] terminate due to: {}\n", location, message); + + ::std::abort(); +} diff --git a/bowshock/source/client/Client/loop.cxx b/bowshock/source/client/Client/loop.cxx new file mode 100644 index 0000000..04df684 --- /dev/null +++ b/bowshock/source/client/Client/loop.cxx @@ -0,0 +1,60 @@ +// 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::loop() -> void { + ::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/run.cxx b/bowshock/source/client/Client/run.cxx index 4256046..f5327c2 100644 --- a/bowshock/source/client/Client/run.cxx +++ b/bowshock/source/client/Client/run.cxx @@ -5,60 +5,38 @@ #include <cmath> #include <cstdio> +#include <exception> #include <fmt/core.h> +#include <format> #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; } + if (!this->configuration.skip_start_sequence) [[likely]] { + auto stop = false; - ::fmt::print(stderr, "[client] entering main loop\n"); + if constexpr (!::bow::DEBUG) { + try { + stop = this->start_sequence(); + } catch (::std::exception const& exception) { + ::bow::terminate("client", ::std::format("got uncaught exception: {}", exception.what())); + } + } else { + stop = this->start_sequence(); + } - ::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)); + if (stop) [[unlikely]] { return; } } - ::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)); - + if constexpr (!::bow::DEBUG) { + try { + this->loop(); + } catch (::std::exception const& exception) { + ::bow::terminate("client", ::std::format("got uncaught exception: {}", exception.what())); + } + } else { + this->loop(); + } } diff --git a/bowshock/source/client/Client/start_sequence.cxx b/bowshock/source/client/Client/start_sequence.cxx index 48e246c..c1007a5 100644 --- a/bowshock/source/client/Client/start_sequence.cxx +++ b/bowshock/source/client/Client/start_sequence.cxx @@ -6,7 +6,7 @@ #include <fmt/core.h> #include <GLFW/glfw3.h> -auto bow::Client::start_sequence() noexcept -> bool { +auto bow::Client::start_sequence() -> bool { ::fmt::print(stderr, "[client] starting start sequence\n"); auto exit = false; @@ -16,7 +16,7 @@ auto bow::Client::start_sequence() noexcept -> bool { constexpr ::GLfloat bowshock_blue = 0x1.9999999Ap-3f; ::glfwSetTime(0x0p0); - for (double duration = 0x0p0;duration <= 0x3p0;duration = ::glfwGetTime()) { + for (double duration = 0x0p0; duration <= 0x3p0; duration = ::glfwGetTime()) { if (poll_events()) [[unlikely]] break; glClearColor(bowshock_red, bowshock_green, bowshock_blue, 0x1p0); diff --git a/bowshock/source/client/PlayerData/decode_save.cxx b/bowshock/source/client/PlayerData/decode_save.cxx index 307f01f..626fce3 100644 --- a/bowshock/source/client/PlayerData/decode_save.cxx +++ b/bowshock/source/client/PlayerData/decode_save.cxx @@ -4,9 +4,8 @@ #include <array> #include <cstdint> -#include <cstdio> #include <cstring> -#include <fmt/core.h> +#include <format> #include <stdexcept> auto bow::PlayerData::decode_save(::bow::PlayerData & buffer, ::std::array<::std::uint8_t, ::bow::SAVE_LENGTH> const& source) -> void { @@ -58,15 +57,11 @@ auto bow::PlayerData::decode_save(::bow::PlayerData & buffer, ::std::array<::std 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"); + throw ::std::invalid_argument(::std::format("invalid format ({:#04x}) of save file", data.format_version)); } 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"); + throw ::std::invalid_argument(::std::format("invalid ship type ({:#04x})\n", data.ship_type)); } buffer.time = data.time, diff --git a/bowshock/source/client/Renderer/constructor.cxx b/bowshock/source/client/Renderer/constructor.cxx index 247a18e..287dd3c 100644 --- a/bowshock/source/client/Renderer/constructor.cxx +++ b/bowshock/source/client/Renderer/constructor.cxx @@ -15,7 +15,7 @@ bow::Renderer::Renderer() { ::fmt::print(stderr, "[client] initialising glfw\n"); if (!::glfwInit()) [[unlikely]] { - throw ::std::runtime_error("[client] unable to initialise glfw"); + throw ::std::runtime_error("unable to initialise glfw"); } ::fmt::print(stderr, "[client] initialising window\n"); diff --git a/bowshock/source/client/ShaderProgram/compile_shader.cxx b/bowshock/source/client/ShaderProgram/compile_shader.cxx index 591faf5..f736868 100644 --- a/bowshock/source/client/ShaderProgram/compile_shader.cxx +++ b/bowshock/source/client/ShaderProgram/compile_shader.cxx @@ -23,12 +23,6 @@ auto bow::ShaderProgram::compile_shader(::std::string const& name, ::bow::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; } @@ -46,12 +40,6 @@ auto bow::ShaderProgram::compile_shader(::std::string const& name, ::bow::Shader case GL_GEOMETRY_SHADER: return "geom"s; - case GL_TESS_CONTROL_SHADER: - return "tesc"s; - - case GL_TESS_EVALUATION_SHADER: - return "tese"s; - case GL_VERTEX_SHADER: return "vert"s; } @@ -68,12 +56,6 @@ auto bow::ShaderProgram::compile_shader(::std::string const& name, ::bow::Shader case GL_GEOMETRY_SHADER: return "geometry"s; - case GL_TESS_CONTROL_SHADER: - return "tesselation control"s; - - case GL_TESS_EVALUATION_SHADER: - return "tesselation evaluation"s; - case GL_VERTEX_SHADER: return "vertex"s; } @@ -122,7 +104,7 @@ auto bow::ShaderProgram::compile_shader(::std::string const& name, ::bow::Shader delete[] log; - throw ::std::runtime_error {"unable to compile shader"}; + throw ::std::runtime_error("unable to compile shader"); } return shader; diff --git a/bowshock/source/logic/Canister/constructor.cxx b/bowshock/source/logic/Canister/constructor.cxx index 4607b4c..0067623 100644 --- a/bowshock/source/logic/Canister/constructor.cxx +++ b/bowshock/source/logic/Canister/constructor.cxx @@ -18,7 +18,6 @@ bow::Canister::Canister() noexcept { 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/Ship/constructor.cxx b/bowshock/source/logic/Ship/constructor.cxx index f3c35f0..50d46a7 100644 --- a/bowshock/source/logic/Ship/constructor.cxx +++ b/bowshock/source/logic/Ship/constructor.cxx @@ -18,7 +18,6 @@ bow::Ship::Ship() noexcept { 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/Star/constructor.cxx b/bowshock/source/logic/Star/constructor.cxx index 60449e1..8db89f2 100644 --- a/bowshock/source/logic/Star/constructor.cxx +++ b/bowshock/source/logic/Star/constructor.cxx @@ -18,6 +18,5 @@ bow::Star::Star() noexcept { 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/Station/constructor.cxx b/bowshock/source/logic/Station/constructor.cxx index 9e80db4..df6eecf 100644 --- a/bowshock/source/logic/Station/constructor.cxx +++ b/bowshock/source/logic/Station/constructor.cxx @@ -18,6 +18,5 @@ bow::Station::Station() noexcept { 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/World/constructor.cxx b/bowshock/source/logic/World/constructor.cxx index 316ca95..57d1cd1 100644 --- a/bowshock/source/logic/World/constructor.cxx +++ b/bowshock/source/logic/World/constructor.cxx @@ -18,6 +18,5 @@ bow::World::World() noexcept { 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/server/ObjectIterator/constructor.cxx b/bowshock/source/server/ObjectIterator/constructor.cxx new file mode 100644 index 0000000..0a9a88c --- /dev/null +++ b/bowshock/source/server/ObjectIterator/constructor.cxx @@ -0,0 +1,7 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/server.hxx> + +bow::ObjectIterator::ObjectIterator(::bow::ObjectRoot const& root) noexcept { + this->element = root.elements; +} diff --git a/bowshock/source/server/ObjectIterator/operator_equality.cxx b/bowshock/source/server/ObjectIterator/operator_equality.cxx new file mode 100644 index 0000000..ca86aca --- /dev/null +++ b/bowshock/source/server/ObjectIterator/operator_equality.cxx @@ -0,0 +1,13 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/server.hxx> + +#include <cstddef> + +auto bow::ObjectIterator::operator ==(::bow::ObjectIterator const& other) const noexcept -> bool { + return this->element == other.element; +} + +auto bow::ObjectIterator::operator ==(::std::nullptr_t) const noexcept -> bool { + return this->element == nullptr; +} diff --git a/bowshock/source/server/ObjectIterator/operator_increment.cxx b/bowshock/source/server/ObjectIterator/operator_increment.cxx new file mode 100644 index 0000000..deab4ff --- /dev/null +++ b/bowshock/source/server/ObjectIterator/operator_increment.cxx @@ -0,0 +1,9 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/server.hxx> + +auto bow::ObjectIterator::operator ++() noexcept -> ::bow::ObjectIterator& { + this->element = this->element->next; + + return *this; +} diff --git a/bowshock/source/server/ObjectRoot/add.cxx b/bowshock/source/server/ObjectRoot/add.cxx new file mode 100644 index 0000000..15778bf --- /dev/null +++ b/bowshock/source/server/ObjectRoot/add.cxx @@ -0,0 +1,29 @@ +// 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::ObjectRoot::add(T const& object_value) -> T* { + ::fmt::print(stderr, "[server] adding object of type {}\n", object_value.object_type_string()); + + // Ignore exceptions: + auto const element = new ::bow::ObjectElement; + element->object = new T; + *element->object = object_value; + + element->next = this->elements; + this->elements = element; + + return static_cast<T*>(element->object); +} + +template auto ::bow::ObjectRoot::add<::bow::Canister>(::bow::Canister const& object_value) -> ::bow::Canister*; +template auto ::bow::ObjectRoot::add<::bow::Ship>( ::bow::Ship const& object_value) -> ::bow::Ship*; +template auto ::bow::ObjectRoot::add<::bow::Star>( ::bow::Star const& object_value) -> ::bow::Star*; +template auto ::bow::ObjectRoot::add<::bow::Station>( ::bow::Station const& object_value) -> ::bow::Station*; +template auto ::bow::ObjectRoot::add<::bow::World>( ::bow::World const& object_value) -> ::bow::World*; diff --git a/bowshock/source/server/ObjectRoot/begin.cxx b/bowshock/source/server/ObjectRoot/begin.cxx new file mode 100644 index 0000000..3810f5d --- /dev/null +++ b/bowshock/source/server/ObjectRoot/begin.cxx @@ -0,0 +1,7 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/server.hxx> + +auto bow::ObjectRoot::begin() const noexcept -> ::bow::ObjectIterator { + return ::bow::ObjectIterator(*this); +} diff --git a/bowshock/source/server/ObjectRoot/constructor.cxx b/bowshock/source/server/ObjectRoot/constructor.cxx new file mode 100644 index 0000000..50755c3 --- /dev/null +++ b/bowshock/source/server/ObjectRoot/constructor.cxx @@ -0,0 +1,7 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/server.hxx> + +bow::ObjectRoot::ObjectRoot() noexcept { + this->elements = nullptr; +} diff --git a/bowshock/source/server/ObjectRoot/destructor.cxx b/bowshock/source/server/ObjectRoot/destructor.cxx new file mode 100644 index 0000000..dd1b4d3 --- /dev/null +++ b/bowshock/source/server/ObjectRoot/destructor.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> + +bow::ObjectRoot::~ObjectRoot() noexcept { + ::fmt::print(stderr, "[server] deleting objects\n"); + + ::bow::ObjectElement* element; + ::bow::ObjectElement* next; + + for (element = this->elements; element != nullptr; element = next) { + ::fmt::print(stderr, "[server] deleting object of type {}\n", element->object->object_type_string()); + + next = element->next; + delete element; + } +} diff --git a/bowshock/source/server/ObjectRoot/end.cxx b/bowshock/source/server/ObjectRoot/end.cxx new file mode 100644 index 0000000..b461626 --- /dev/null +++ b/bowshock/source/server/ObjectRoot/end.cxx @@ -0,0 +1,11 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/server.hxx> + +auto bow::ObjectRoot::end() const noexcept -> ::bow::ObjectIterator { + auto iterator = ::bow::ObjectIterator(*this); + + while (++iterator != nullptr) {} + + return iterator; +} diff --git a/bowshock/source/server/ObjectRoot/operator_increment.cxx b/bowshock/source/server/ObjectRoot/operator_increment.cxx new file mode 100644 index 0000000..a9ab381 --- /dev/null +++ b/bowshock/source/server/ObjectRoot/operator_increment.cxx @@ -0,0 +1,9 @@ +// Copyright 2022-2023 Gabriel Bjørnager Jensen. + +#include <bow/server.hxx> + +auto bow::ObjectIterator::operator ++() noexcept -> T& { + this->object = this->object->next; + + return *this; +} diff --git a/bowshock/source/server/Server/start.cxx b/bowshock/source/server/Server/start.cxx index d5b7bd5..7647261 100644 --- a/bowshock/source/server/Server/start.cxx +++ b/bowshock/source/server/Server/start.cxx @@ -9,12 +9,12 @@ #include <thread> #include <utility> -auto bow::Server::start() -> ::bow::Server* { +auto bow::Server::start(::bow::ServerConfiguration const& configuration) -> ::bow::Server* { ::fmt::print(stderr, "[app] starting server\n"); auto stop_flag = new ::std::atomic_flag(); - auto server = new ::bow::ServerInstance(stop_flag); + auto server = new ::bow::ServerInstance(configuration, stop_flag); auto thread = new ::std::thread(::bow::ServerInstance::run, server); diff --git a/bowshock/source/server/ServerInstance/add_object.cxx b/bowshock/source/server/ServerInstance/add_object.cxx deleted file mode 100644 index 3e5126b..0000000 --- a/bowshock/source/server/ServerInstance/add_object.cxx +++ /dev/null @@ -1,25 +0,0 @@ -// 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 index 7ac0cec..0ca263f 100644 --- a/bowshock/source/server/ServerInstance/constructor.cxx +++ b/bowshock/source/server/ServerInstance/constructor.cxx @@ -4,6 +4,8 @@ #include <atomic> -::bow::ServerInstance::ServerInstance(::std::atomic_flag* stop_flag) noexcept { +::bow::ServerInstance::ServerInstance(::bow::ServerConfiguration const& configuration, ::std::atomic_flag* stop_flag) noexcept { + this->configuration = configuration; + this->stop_flag = stop_flag; } diff --git a/bowshock/source/server/ServerInstance/delete_objects.cxx b/bowshock/source/server/ServerInstance/delete_objects.cxx deleted file mode 100644 index bd8a970..0000000 --- a/bowshock/source/server/ServerInstance/delete_objects.cxx +++ /dev/null @@ -1,21 +0,0 @@ -// 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 index a3188f1..9b97300 100644 --- a/bowshock/source/server/ServerInstance/generate_system.cxx +++ b/bowshock/source/server/ServerInstance/generate_system.cxx @@ -10,23 +10,22 @@ 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); + if (system.has_objects()) [[likely]] { + system.~ObjectRoot(); } // Note: The following code is only temporary; - auto const star = []() -> ::bow::Star { + system.add([]() -> ::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 { + system.add([]() -> ::bow::World { auto world = ::bow::World(); world.position.y = 0x1.F76F144Dp-1; @@ -36,8 +35,7 @@ auto bow::ServerInstance::generate_system(::bow::ObjectRoot& system, ::std::uint world.type = ::bow::World::Type::RockyWorld; return world; - }(); - this->add_object(system, world); + }()); this->simulate(system, time); } diff --git a/bowshock/source/server/ServerInstance/gravitate.cxx b/bowshock/source/server/ServerInstance/gravitate.cxx index 0a390de..6dbad5d 100644 --- a/bowshock/source/server/ServerInstance/gravitate.cxx +++ b/bowshock/source/server/ServerInstance/gravitate.cxx @@ -15,11 +15,17 @@ namespace bow { auto const angle_y = ::std::atan2(distance_y, distance_x); auto const angle_z = ::std::atan2(distance_z, distance_x); - auto const acceleration = par.mass/(distance*distance)*::bow::GRAVITY_VALUE; + // If two objects overlap - that is, they have a + // absolute spacing of zero, then we discard the + // accelerations. We use a value as it makes these + // function branchless. + auto const no_overlap = ::std::abs(distance) != 0x0p0; - auto const velocity_x = ::std::cos(angle_y)*acceleration; - auto const velocity_y = ::std::sin(angle_y)*acceleration; - auto const velocity_z = ::std::sin(angle_z)*acceleration; + auto const acceleration = par.mass/(distance * distance) * ::bow::GRAVITY_VALUE * static_cast<double>(no_overlap); + + auto const velocity_x = ::std::cos(angle_y) * acceleration; + auto const velocity_y = ::std::sin(angle_y) * acceleration; + auto const velocity_z = ::std::sin(angle_z) * acceleration; object.positional_velocity.x += velocity_x; object.positional_velocity.y += velocity_y; @@ -27,24 +33,26 @@ namespace bow { } static void gravitate_pair(::bow::Object& obj0, ::bow::Object& obj1) noexcept { - auto const distance_x = obj1.position.x-obj0.position.x; - auto const distance_y = obj1.position.y-obj0.position.y; - auto const distance_z = obj1.position.z-obj0.position.z; - auto const distance = ::std::sqrt(distance_x*distance_x+distance_y*distance_y+distance_z*distance_z); + auto const distance_x = obj1.position.x - obj0.position.x; + auto const distance_y = obj1.position.y - obj0.position.y; + auto const distance_z = obj1.position.z - obj0.position.z; + auto const distance = ::std::sqrt(distance_x * distance_x + distance_y * distance_y + distance_z * distance_z); auto const angle_y = ::std::atan2(distance_y, distance_x); auto const angle_z = ::std::atan2(distance_z, distance_x); - auto acceleration0 = ::bow::GRAVITY_VALUE/(distance*distance); - auto const acceleration1 = acceleration0*obj0.mass; // This is negative. - acceleration0 *= obj1.mass; + auto const no_overlap = ::std::abs(distance) != 0x0p0; + + auto acceleration0 = ::bow::GRAVITY_VALUE / (distance * distance); + auto const acceleration1 = acceleration0 * obj0.mass * static_cast<double>(no_overlap); // This is negative. + acceleration0 *= obj1.mass * static_cast<double>(no_overlap); auto velocity_x0 = ::std::cos(angle_y); auto velocity_y0 = ::std::sin(angle_y); auto velocity_z0 = ::std::sin(angle_z); - auto const velocity_x1 = velocity_x0*acceleration1; - auto const velocity_y1 = velocity_y0*acceleration1; - auto const velocity_z1 = velocity_z0*acceleration1; + auto const velocity_x1 = velocity_x0 * acceleration1; + auto const velocity_y1 = velocity_y0 * acceleration1; + auto const velocity_z1 = velocity_z0 * acceleration1; velocity_x0 *= acceleration0; velocity_y0 *= acceleration0; velocity_z0 *= acceleration0; @@ -60,17 +68,17 @@ namespace bow { } 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); + for (auto& object0: system) { + for (auto& object1: system) { + ::bow::gravitate_pair(object0, object1); } } } 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); + for (auto& object0: objects) { + for (auto const& object1: system) { + ::bow::gravitate_single(object0, object1); } } } diff --git a/bowshock/source/server/ServerInstance/loop.cxx b/bowshock/source/server/ServerInstance/loop.cxx index b7854e0..06fc267 100644 --- a/bowshock/source/server/ServerInstance/loop.cxx +++ b/bowshock/source/server/ServerInstance/loop.cxx @@ -12,26 +12,21 @@ auto bow::ServerInstance::loop() -> void { ::fmt::print(stderr, "[server] entering main loop\n"); // For stellar bodies: - ::bow::ObjectRoot system_root = { - .objects = nullptr, - }; + auto system_root = ::bow::ObjectRoot(); - // For miscellaneous objects (canisters, shps...): - ::bow::ObjectRoot objects_root = { - .objects = nullptr, - }; + // For miscellaneous objects (canisters, ships, etc.): + auto objects_root = ::bow::ObjectRoot(); this->generate_system(system_root, 0x0u, 0x0u); - auto const canister = []() -> ::bow::Canister { + objects_root.add([]() -> ::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); @@ -42,7 +37,4 @@ auto bow::ServerInstance::loop() -> void { } ::fmt::print(stderr, "[server] submitting\n"); - - this->delete_objects(objects_root); - this->delete_objects(system_root); } diff --git a/bowshock/source/server/ServerInstance/move.cxx b/bowshock/source/server/ServerInstance/move.cxx index 03a4210..ee16b0e 100644 --- a/bowshock/source/server/ServerInstance/move.cxx +++ b/bowshock/source/server/ServerInstance/move.cxx @@ -4,16 +4,12 @@ #include <bow/logic.hxx> auto bow::ServerInstance::move(::bow::ObjectRoot& root) noexcept -> void { - auto const move = [](::bow::Object& object) -> void { + for (auto& object: root) { object.position.x += object.positional_velocity.x; object.position.y += object.positional_velocity.y; object.position.z += object.positional_velocity.z; object.rotation.x += object.rotational_velocity.x; object.rotation.y += object.rotational_velocity.y; object.rotation.z += object.rotational_velocity.z; - }; - - for (::bow::Object* object = root.objects; object != nullptr; object = object->next) { - move(*object); } } diff --git a/bowshock/source/server/ServerInstance/run.cxx b/bowshock/source/server/ServerInstance/run.cxx index 2275190..0460ddb 100644 --- a/bowshock/source/server/ServerInstance/run.cxx +++ b/bowshock/source/server/ServerInstance/run.cxx @@ -3,8 +3,9 @@ #include <bow/server.hxx> #include <cstdio> +#include <exception> #include <fmt/core.h> -#include <stdexcept> +#include <format> auto bow::ServerInstance::run(::bow::ServerInstance* server) noexcept -> void { ::fmt::print(stderr, "[server] angle unit: {:.3f} rad\n", 0x1p0); @@ -13,6 +14,15 @@ auto bow::ServerInstance::run(::bow::ServerInstance* server) noexcept -> void { ::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(); + if constexpr (!::bow::DEBUG) { + try { + server->loop(); + } catch (::std::exception const& exception) { + ::bow::terminate("server", ::std::format("got uncaught exception: {}", exception.what())); + } catch (...) { + ::bow::terminate("server", "got uncaught exception"); + } + } else { + server->loop(); + } } |