Skip to content

Commit

Permalink
Start rework of orbits
Browse files Browse the repository at this point in the history
  • Loading branch information
Seggan committed Feb 22, 2024
1 parent 5355175 commit 3438c95
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 66 deletions.
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ repositories {
dependencies {
library(kotlin("stdlib"))
library("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0-RC2")
library("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")

library(kotlin("scripting-common"))
library(kotlin("scripting-jvm"))
Expand All @@ -34,6 +35,8 @@ dependencies {
testImplementation(kotlin("test"))
testImplementation("io.kotest:kotest-assertions-core:5.8.0")
testImplementation("com.github.seeseemelk:MockBukkit-v1.20:3.9.0")

testImplementation("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")
}

group = "io.github.addoncommunity.galactifun"
Expand Down
4 changes: 0 additions & 4 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
/*
* This file was generated by the Gradle 'init' task.
*/

rootProject.name = "Galactifun2"
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import io.github.addoncommunity.galactifun.scripting.evalScript
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.au
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.kilometers
import io.github.addoncommunity.galactifun.util.units.Mass.Companion.kilograms
import io.github.addoncommunity.galactifun.util.years
import io.github.addoncommunity.galactifun.util.units.years
import io.github.seggan.kfun.AbstractAddon
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.github.addoncommunity.galactifun.api.objects
import io.github.addoncommunity.galactifun.api.objects.properties.Orbit
import io.github.addoncommunity.galactifun.util.units.Distance
import io.github.addoncommunity.galactifun.util.units.Mass
import kotlinx.datetime.Instant
import org.bukkit.Material
import org.bukkit.inventory.ItemStack

Expand All @@ -14,13 +15,13 @@ class StarSystem(
override val radius: Distance
) : UniversalObject(name, ItemStack(Material.SUNFLOWER)) {

override fun distanceTo(other: UniversalObject): Distance {
override fun distanceTo(other: UniversalObject, time: Instant): Distance {
return if (orbitLevel > other.orbitLevel) {
other.orbit.semimajorAxis + distanceTo(other.orbiting!!)
other.orbit.semimajorAxis + distanceTo(other.orbiting!!, time)
} else if (orbitLevel == other.orbitLevel) {
this.orbit.semimajorAxis - other.orbit.semimajorAxis
} else {
super.distanceTo(other)
super.distanceTo(other, time)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ package io.github.addoncommunity.galactifun.api.objects

import io.github.addoncommunity.galactifun.api.objects.properties.Orbit
import io.github.addoncommunity.galactifun.util.units.Distance
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.lightYears
import io.github.addoncommunity.galactifun.util.units.Mass
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
import kotlin.time.Duration.Companion.days

object TheUniverse : UniversalObject("The Universe", ItemStack(Material.NETHER_STAR)) {
override val orbiting = null
override val orbit = Orbit(0.lightYears, 0.days)
override val orbit: Orbit
get() = error("The Universe does not have an orbit")
override val mass: Mass
get() = error("The Universe does nto have a defined mass")
get() = error("The Universe does not have a defined mass")
override val radius: Distance
get() = error("The Universe does not have a defined radius")
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package io.github.addoncommunity.galactifun.api.objects

import io.github.addoncommunity.galactifun.api.objects.properties.Orbit
import io.github.addoncommunity.galactifun.util.Constants
import io.github.addoncommunity.galactifun.util.LazyDouble
import io.github.addoncommunity.galactifun.util.units.Distance
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.lightYears
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.meters
import io.github.addoncommunity.galactifun.util.units.Mass
import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils
import kotlinx.datetime.Instant
import org.bukkit.inventory.ItemStack
import kotlin.math.cos
import kotlin.math.sqrt
Expand All @@ -18,20 +20,24 @@ abstract class UniversalObject protected constructor(name: String, baseItem: Ite

val item = CustomItemStack(baseItem, name)

abstract val orbiting: UniversalObject?
abstract val orbit: Orbit
abstract val mass: Mass
abstract val radius: Distance

val mu: Double
get() = Constants.GRAVITATIONAL_CONSTANT * mass.kilograms
val escapeVelocity: Double
get() = sqrt(2 * Constants.GRAVITATIONAL_CONSTANT * mass.kilograms / radius.kilometers)
val parkingOrbit: Distance
get() = radius / 10
val gravitationalParameter by LazyDouble { Constants.GRAVITATIONAL_CONSTANT * mass.kilograms }
val escapeVelocity by LazyDouble { sqrt(2 * Constants.GRAVITATIONAL_CONSTANT * mass.kilograms / radius.kilometers) }
val parkingOrbit: Orbit by lazy {
Orbit(
parent = this,
semimajorAxis = radius / 10,
eccentricity = 0.0,
argumentOfPeriapsis = 0.0,
timeOfPeriapsis = Instant.fromEpochMilliseconds(0)
)
}

val orbitLevel: Int
get() = if (orbiting == null) 0 else orbiting!!.orbitLevel + 1
get() = if (this is TheUniverse) 0 else orbit.parent.orbitLevel + 1

private val _orbiters = mutableListOf<UniversalObject>()
val orbiters: List<UniversalObject> = _orbiters
Expand All @@ -40,17 +46,17 @@ abstract class UniversalObject protected constructor(name: String, baseItem: Ite
_orbiters.add(orbiter)
}

open fun distanceTo(other: UniversalObject): Distance {
open fun distanceTo(other: UniversalObject, time: Instant): Distance {
if (orbitLevel == 0 || orbitLevel < other.orbitLevel) {
return other.orbit.semimajorAxis + distanceTo(other.orbiting!!)
return other.orbit.semimajorAxis + distanceTo(other.orbit.parent, time)
}
if (orbiting == other.orbiting) {
val thisDist = orbit.semimajorAxis.lightYears
val otherDist = other.orbit.semimajorAxis.lightYears
val cosAngle = cos(orbit.trueAnomaly - other.orbit.trueAnomaly)
return sqrt(thisDist * thisDist + otherDist * otherDist - 2 * thisDist * otherDist * cosAngle).lightYears
if (orbit.parent == other.orbit.parent) {
val thisDist = orbit.radius(time).meters
val otherDist = other.orbit.radius(time).meters
val cosAngle = cos(orbit.trueAnomaly(time) - other.orbit.trueAnomaly(time))
return sqrt(thisDist * thisDist + otherDist * otherDist - 2 * thisDist * otherDist * cosAngle).meters
}
return orbit.semimajorAxis + orbiting!!.distanceTo(other)
return orbit.semimajorAxis + orbit.parent.distanceTo(other, time)
}

override fun equals(other: Any?): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package io.github.addoncommunity.galactifun.api.objects.planet

import io.github.addoncommunity.galactifun.api.objects.UniversalObject
import io.github.addoncommunity.galactifun.api.objects.properties.DayCycle
import io.github.addoncommunity.galactifun.api.objects.properties.Orbit
import io.github.addoncommunity.galactifun.api.objects.properties.OrbitPosition
import io.github.addoncommunity.galactifun.api.objects.properties.atmosphere.Atmosphere
import io.github.addoncommunity.galactifun.core.managers.PlanetManager
import io.github.addoncommunity.galactifun.util.Constants
import io.github.addoncommunity.galactifun.util.units.Distance
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.meters
import io.github.seggan.kfun.location.plus
import kotlinx.datetime.Instant
import org.bukkit.Location
import org.bukkit.inventory.ItemStack
import kotlin.math.abs
Expand All @@ -30,22 +32,26 @@ abstract class PlanetaryObject(name: String, baseItem: ItemStack) : UniversalObj
return orbitPosition.centerLocation + location
}

fun getDeltaVForTransferTo(other: PlanetaryObject): Double {
fun getDeltaVForTransferTo(other: PlanetaryObject, time: Instant): Double {
if (this == other) return 0.0
val thisParents = generateSequence(this as UniversalObject) { it.orbiting }.toList()
val thisParents = generateSequence(this as UniversalObject) {
if (it.orbitLevel == 0) null else it.orbit.parent
}.toList()
if (other in thisParents) {
return other.getDeltaVForTransferTo(this)
return other.getDeltaVForTransferTo(this, time)
}
val otherParents = generateSequence(other as UniversalObject) { it.orbiting }.toList()
val otherParents = generateSequence(other as UniversalObject) {
if (it.orbitLevel == 0) null else it.orbit.parent
}.toList()
if (this in otherParents) {
var height = other.parkingOrbit
var dV = 0.0
for (obj in otherParents) {
if (obj == this) break
dV += abs(obj.escapeVelocity - visViva(obj.mu, height, height))
height = obj.orbit.semimajorAxis
dV += abs(obj.escapeVelocity - visViva(obj.gravitationalParameter, height.radius(time), height.semimajorAxis))
height = obj.orbit
}
dV += hohmannTransfer(mass.kilograms * Constants.GRAVITATIONAL_CONSTANT, height, parkingOrbit)
dV += hohmannTransfer(height, parkingOrbit, time)
return dV
} else {
val closestParent = thisParents.first { it in otherParents }
Expand All @@ -64,10 +70,13 @@ abstract class PlanetaryObject(name: String, baseItem: ItemStack) : UniversalObj
private fun visViva(mu: Double, r: Distance, a: Distance): Double =
sqrt(mu * (2 / r.meters - 1 / a.meters))

private fun hohmannTransfer(mu: Double, parkingR: Distance, targetR: Distance): Double {
private fun hohmannTransfer(parking: Orbit, target: Orbit, time: Instant): Double {
val parkingR = parking.radius(time)
val targetR = target.radius(time)
val transferA = (parkingR + targetR) / 2
val firstManeuver = abs(visViva(mu, parkingR, transferA) - visViva(mu, parkingR, parkingR))
val secondManeuver = abs(visViva(mu, targetR, targetR) - visViva(mu, targetR, transferA))
val mu = parking.parent.gravitationalParameter
val firstManeuver = abs(visViva(mu, parkingR, transferA) - visViva(mu, parkingR, parking.semimajorAxis))
val secondManeuver = abs(visViva(mu, targetR, target.semimajorAxis) - visViva(mu, targetR, transferA))
return firstManeuver + secondManeuver
}

Expand Down Expand Up @@ -102,7 +111,7 @@ private fun brachistochroneTransfer(
return BrachistochroneTransfer(dV, time.seconds)
}

data class BrachistochroneTransfer(
private data class BrachistochroneTransfer(
val deltaV: Double,
val time: Duration
)
Original file line number Diff line number Diff line change
@@ -1,23 +1,55 @@
package io.github.addoncommunity.galactifun.api.objects.properties

import io.github.addoncommunity.galactifun.api.objects.UniversalObject
import io.github.addoncommunity.galactifun.util.Constants
import io.github.addoncommunity.galactifun.util.LazyDouble
import io.github.addoncommunity.galactifun.util.units.Distance
import kotlin.math.PI
import kotlin.time.Duration
import kotlin.time.DurationUnit
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.meters
import io.github.addoncommunity.galactifun.util.units.doubleSeconds
import kotlinx.datetime.Instant
import java.util.*
import kotlin.math.acos
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.sqrt

class Orbit(val semimajorAxis: Distance, year: Duration) {
data class Orbit(
val parent: UniversalObject,
val semimajorAxis: Distance,
val eccentricity: Double,
// Our orbits are always flat, so inclination is always 0, and we don't need to store it
val argumentOfPeriapsis: Double,
val timeOfPeriapsis: Instant
) {
val meanMotion by LazyDouble {
val a = semimajorAxis.meters
sqrt(parent.gravitationalParameter / (a * a * a))
}

private val year =
EARTH_YEAR * year.toDouble(DurationUnit.DAYS) / 365.25 * 1200000 // why 1200000? it was in the original code
fun meanAnomaly(time: Instant): Double {
val t = (time - timeOfPeriapsis) / Constants.ORBIT_TIME_SCALE
return meanMotion * t.doubleSeconds
}

val trueAnomaly: Double
get() {
if (year == 0.0) return 0.0
return (System.currentTimeMillis() % year) * PI * 2 / year
}
private val eccentricAnomalyCache = WeakHashMap<Instant, Double>()

fun eccentricAnomaly(time: Instant): Double {
return eccentricAnomalyCache.getOrPut(time) { kelpersEquation(meanAnomaly(time), eccentricity) }
}

fun trueAnomaly(time: Instant): Double {
val cosE = cos(eccentricAnomaly(time))
return acos((cosE - eccentricity) / (1 - eccentricity * cosE))
}

fun radius(time: Instant): Distance {
val e = eccentricAnomaly(time)
val a = semimajorAxis.meters
return (a * (1 - eccentricity * cos(e))).meters
}
}

/**
* The number of Minecraft days in an Earth year
*/
private const val EARTH_YEAR = 30
tailrec fun kelpersEquation(m: Double, e: Double, guessE: Double = m): Double {
val nextGuess = m + e * sin(guessE)
return if (nextGuess == guessE) nextGuess else kelpersEquation(m, e, nextGuess)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import io.github.addoncommunity.galactifun.base.objects.earth.Moon
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.kilometers
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.lightYears
import io.github.addoncommunity.galactifun.util.units.Mass.Companion.kilograms
import io.github.addoncommunity.galactifun.util.years
import io.github.addoncommunity.galactifun.util.units.years
import org.bukkit.Material
import org.bukkit.inventory.ItemStack

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import io.github.addoncommunity.galactifun.base.BaseUniverse
import io.github.addoncommunity.galactifun.pluginInstance
import io.github.addoncommunity.galactifun.util.units.Distance.Companion.kilometers
import io.github.addoncommunity.galactifun.util.units.Mass.Companion.kilograms
import io.github.addoncommunity.galactifun.util.years
import io.github.addoncommunity.galactifun.util.units.years
import org.bukkit.Material
import org.bukkit.World
import org.bukkit.WorldCreator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,16 @@ object Constants {
const val GRAVITATIONAL_CONSTANT = 6.674e-11
const val EARTH_GRAVITY = 9.81

/**
* The maximum radix for the [Int.toString] and [String.toInt] functions.
*/
const val MAX_RADIX = 36

/**
* How much faster time is concerning orbital mechanics than in real life.
*/
const val ORBIT_TIME_SCALE = 12.0

fun locationZero(world: World?): Location {
return Location(world, 0.0, 0.0, 0.0)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.addoncommunity.galactifun.util

import kotlin.reflect.KProperty

class LazyDouble(private val supplier: () -> Double) {

private var value = Double.NaN
private var initialized = false
operator fun getValue(thisRef: Any?, property: KProperty<*>): Double {
if (!initialized) {
value = supplier()
initialized = true
}
return value
}

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Double) {
this.value = value
initialized = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import org.bukkit.event.player.PlayerTeleportEvent
import org.bukkit.metadata.FixedMetadataValue
import java.util.*
import java.util.concurrent.CompletableFuture
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days

fun String.key(): NamespacedKey = NamespacedKey(pluginInstance, this)

Expand Down Expand Up @@ -90,9 +88,3 @@ inline fun <K, V> Map<K, V>.mergeMaps(other: Map<K, V>, merge: (V, V) -> V): Map
}

operator fun TextColor.plus(s: String): TextComponent = Component.text().color(this).content(s).build()

val Double.years: Duration
get() = (this * 365.25).days

val Int.years: Duration
get() = (this * 365.25).days
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.addoncommunity.galactifun.util.units

import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
import kotlin.time.DurationUnit

inline val Double.years: Duration
get() = (this * 365.25).days

inline val Int.years: Duration
get() = this.toDouble().years

inline val Duration.doubleSeconds: Double
get() = toDouble(DurationUnit.SECONDS)

0 comments on commit 3438c95

Please sign in to comment.