From 789d0c1e2f6744bd28ec109dd58a6054b6680c27 Mon Sep 17 00:00:00 2001 From: Jakub Date: Sun, 7 Dec 2025 11:30:49 +0800 Subject: [PATCH] Initial commit --- .editorconfig | 4 +++ .gitattributes | 2 ++ .gitignore | 21 +++++++++++++++ README.org | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ icon.svg | 1 + icon.svg.import | 43 +++++++++++++++++++++++++++++ project.godot | 15 +++++++++++ 7 files changed, 158 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 README.org create mode 100644 icon.svg create mode 100644 icon.svg.import create mode 100644 project.godot diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ca6142 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Godot 4+ specific ignores +.godot/ +/android/ + +# Emacs junk +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* diff --git a/README.org b/README.org new file mode 100644 index 0000000..c9d3d0e --- /dev/null +++ b/README.org @@ -0,0 +1,72 @@ +#+title: Open Heavens + +Open Heavens is a semi-realistic and deterministic star system generator, based on [[https://github.com/BirDt/stardate-legacy][Stardate Legacy]]. Open Heavens provides the "controller" part of your average MVC, so it does not provide any visualisation or interaction logic with the system (except for whatever is needed for testing). + +* Dependencies & Credits +- [[https://github.com/BirDt/markov-machine][Markov Machine]] is used for name generation. + +* Generation Process +Open Heavens generates systems by their mass, age (which is sparingly used), and elemental abundance, both of which are configurable when passed to the system generator. This process outline assumes you leave all settings as random, and only provide a seed. Most rates are configurable. + +We start by randomly generating the solar mass of the overall system. 80% of the time, we use a random distribution of a 1.1 solar mass mean with a 0.5 solar mass deviation, and we clamp this to 0.5 and 20 on the lower and upper end. 20% of the time, we just randomly generate anywhere from 0.5 to 20 solar masses. We also generate the age of the system, in gigayears - 80% of the time this is a normal distribution with a mean of 5 and deviation of 1, otherwise it's a random value between 1 and 13. The reason for these values is that they provide 80% (this is configurable) odds of generating an interesting system with a good number of exoplanets. + +We next generate abundances. The [[https://en.wikipedia.org/wiki/Abundance_of_the_chemical_elements#Universe][top ten most common elements]] are normally distributed around their mass fraction with small (0.05 - 0.00005) deviations. For the remaining natural elements, they are completely random but always add up to 100%. This is not a particularly realistic way of generating the abundance, but it leads to some fun results like thorium worlds and the like. + +We generate the star of the system by removing a random portion of the total system mass - between 20% and 99%. This mass makes up the star and is used to generate it. + +** Star Generation +We start by calculating the stellar class - since we only have main sequence stars this is fairly simple as we just look at the mass of the star and assign the class based on the range: +| Mass (Solar Masses) | Class | +|---------------------+-------| +| x < 0.45 | M | +| 0.45 < x < 0.8 | K | +| 0.8 < x < 1.04 | G | +| 1.04 < x < 1.4 | F | +| 1.4 < x < 2.1 | A | +| 2.1 < x < 16 | B | +| x > 16 | O | + +We use a curve to determine the temperature (in Kelvin) from the mass, and color (RGB) from the temperature. These curves used known stars as sample points. + +For luminosity, the following DISGUSTING formula is used. +~14341850000 + ((78.43685-14341850000)/(1 + pow(temperature/145852.2,7.237745)))-78.46~ +This gives the luminosity in solar luminosity, so 1 = 3.75×10^28 lumen. + +To calculate the radius (in solar radii), we first calculate a best guess: ~pow((3.0 * mass)/4.0*PI, 1.0/3.0)~. +The output of this is ~0.62035~ for 1 solar mass, and so we normalise the value so that 1 solar mass = 1 solar radius: ~(best guess/0.62035) - 1.14503109452965~ + +From the radius we calculate the density, which is used for habitable zone and Roche limit calculations. We do this by calculating the projected volume - ~(4.0/3.0) * PI * pow(solar_radii * SOLAR_RADIUS, 3)~ - and real mass (in Kg) - ~mass * 1.9885~ - which gives us a simple formula for the kg/m^3 density: ~(r_mass/projected_volume) * 1000 * 1000~. + +We calculate the inner and outer radius of the star's habitable zone as the square root of the luminosity divided by 1.1, and the square root of the luminosity divided by 0.53 respectively. These values are in AU. + +We also determine the composition of the star, however we assume it is only composed of hydrogen and helium. Hydrogen can be any percent between 65 and 85, while helium is the remainder to bring the composition to 100. This prevents too much hydrogen and helium from being used in planet generation, which prevents too many gas giants from being generated. + +** Planet Generation +We always generate a minimum of 1 planetoid, which can be forced to be habitable. We continue generating planets up until all the system mass is used up - that being when only 0.05 Earth masses are remaining, which is considered as the mass for non-planet system features such as asteroids or comets. + +Each time we generate a planet, we generate a mass for it (in Earth masses) and subtract that from the remaining system mass. If the planet should be forced as habitable, the mass is always between 0.107 and 9.44 Earth masses, otherwise it is either between 0.05 and 1000, or 0.05 and 15, where we select the former a third of the time. This prevents too many gas giants from showing up. + +To determine the radius of the planet (in Earth radii), for most planets we sample the planet mass to radius curve (which is constructed based on real known planet mass and radius values), adding some normally distributed deviation (mean of 0, deviation of 0.15). For planets with forced habitable generation, we start with a random radius between 0.5 and 2.49. We then incrementally subtract and add from this radius until we can get an estimated surface gravity between 0.4 and 1.7. We calculate the density after the radius, similarly to the star density calculation: +1. We get a projected volume: ~(4.0/3.0) * PI * pow(planet_radius * 6378 * 1000, 3)~ +2. We get the real mass in kilograms: ~mass * 5.98 * pow(10, 24)~ +3. We divide the latter by the former to get the density + +Surface gravity is calculated from the kilogram mass (~mass * 5.98 * pow(10, 24)~) and meter radius (~planet_radius * 6378 * 1000~). This gives a gravity of ~G * (real_mass / pow(real_rad, 2))~ meters/second^2, and ~m/s^2 * 0.10197162129779~ + g's. + +We calculate each planet's orbit. If the planet is forced habitable, we set the orbit distance to a random value within the star's habitable zone range. Otherwise, we calculate the roche limit based on the radius, mass, and density. If the parent body of this planet is a star (the system root) then we randomise the orbit between 0.05 AU + the roche limit and 50 AU + the outer habitable zone radius. If the parent body is a planet, we randomise it between the roche limit and 0.1 AU. + +We calculate the orbit speed as ~sqrt((G * parent_mass)/distance_at_apoapsis_m) / 1000~, using real values. The orbital period follows as ~(2 * PI * orbit_distance)/orbit_speed~, and we turn that into an "Earth days" measurement with ~abs(orbital_period / 0.211 * 365)~. + +We also calculate a rotation period - for forced habitable worlds, this value is a normal distribution with a mean of 1 day and a deviation of 0.2. For every other world, this is a normal distribution with a mean of 1 divided by the mass of the planet, and a deviation of 1. The rotation period has a 50% chance of being reversed. For forced habitable worlds, the axial tilt is random between 0 and 35 degrees, otherwise it's random between 0 and 90 degrees. If the rotation period and orbital period are approximately equal, we also keep track of the planet being tidally locked. + +** Limitations +- Elemental abundances are fully random beyond the top 10. +- Non-unary system generation is not implemented because I don't want to write the orbit math for it. +- Only main sequence stars are currently generated. + + +* FAQ +** What does "semi-realistic" mean? +I am not an astrophysicist, geologist, or any other qualified position. I am just a computer programmer who wants to recreate Elite: Dangerous' galaxy generation logic. "Semi-realistic", in the context of this project, means "close enough" to realistic for simulation purposes or for the meta-setting this is inspired by (see the Stardate Legacy repo for more details). I am open to pull requests to correct any incorrect calculations or information, particularly from people with credentials in the field of whatever you are trying to correct. + diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..a7329d2 --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://caimx0c6fshux" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..bf36830 --- /dev/null +++ b/project.godot @@ -0,0 +1,15 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="Open Heavens" +config/features=PackedStringArray("4.5", "Forward Plus") +config/icon="res://icon.svg"