-
Notifications
You must be signed in to change notification settings - Fork 69
Interface for other KSP mods
This is a draft of the API documentation. The API is not yet implemented.
Principia provides an API that allows other mods to take its effects into account.
Mods should use the interface by reflection.
The interface consists of instance methods of the class
principia.ksp_plugin_adapter.ExternalInterface
.
An instance of this class can be obtained by calling the static method
principia.ksp_plugin_adapter.ExternalInterface.Get()
which:
- returns an object of type
ExternalInterface
if the PrincipiaScenarioModule
and the Principia native DLLs are loaded; - returns
null
if the PrincipiaScenarioModule
is not loaded, for instance in the editor scene, where Principia does not run; - throws
DllNotFoundException
if the Principia native DLL could not be loaded; this indicates an incorrect Principia installation.
The interface types are declared in namespace principia.ksp_plugin_adapter
.
We give sample declarations with fields below, however, it is unspecified whether the members are fields or properties; interfacing mods should accept either by reflection.
struct XY {
double x;
double y;
}
The example usages of the interface functions given in this section make use of some utilities to limit the reflection boilerplate at the call site. See the appendix for their definition.
The types of the exceptions thrown by erroneous interface calls are unspecified. When an exception is thrown, additional information may be found in the Principia logs.
public XY GeopotentialGetCoefficient(
int body_index,
int degree,
int order);
Returns the normalized geopotential coefficient of the given degree
and order
of the body whose flightGlobalsIndex
is body_index
.
For degree 𝑛 and order 𝑚, the x
member of the result is 𝐶𝑛𝑚 and the y
member is 𝑆𝑛𝑚.
Throws an exception if:
- the Principia plugin is not started;
- there is no
CelestialBody
whoseflightGlobalsIndex
isbody_index
; - the relation
0
≤order
≤degree
is not satisfied.
The coefficients 𝐶𝑛𝑚 and 𝑆𝑛𝑚 may be given as normalized or unnormalized coefficients (most often the former). See the IERS conventions (2010), chapter 6 for definition of the normalized and unnormalized coefficients. While the IERS conventions use an overline to denote normalization, the normalized coefficients are often referred to as 𝐶𝑛𝑚 as well.
Callers should check the convention for their usage, and unnormalize the result of GeopotentialGetCoefficient
as needed.
For Earth, the normalized value of 𝐶32 is about 9.0476×10-07, while the unnormalized value is 3.0904×10-07.
The zonal harmonics 𝐶𝑛0 are often given as 𝐽𝑛. 𝐽𝑛 is always given unnormalized, 𝐽𝑛 = −𝐶𝑛0 with the unnormalized value of 𝐶𝑛0.
With the normalized value of 𝐶𝑛0, this becomes 𝐽𝑛 = −𝐶𝑛0 √(2𝑛 + 1).
var principia = Principia.Get();
CelestialBody earth = FlightGlobals.GetHomeBody();
var c20_s20 = principia.Call("GeopotentialGetCoefficient")(earth.flightGlobalsIndex, 2, 0);
double c20 = c20_s20.GetValue<double>("x");
double j2 = -c20 * Math.Sqrt(5);
public XY GeopotentialReferenceRadius(
int body_index);
Returns the value in metres of the reference radius of the geopotential model for the body whose flightGlobalsIndex
is body_index
.
Throws an exception if:
- the Principia plugin is not started;
- there is no
CelestialBody
whoseflightGlobalsIndex
isbody_index
.
double J2NodalPrecession(Orbit orbit) {
var principia = Principia.Get();
var c20_s20 = principia.Call("GeopotentialGetCoefficient")(
orbit.referenceBody.flightGlobalsIndex, 2, 0);
double c20 = c20_s20.GetValue<double>("x");
double j2 = -c20 * Math.Sqrt(5);
double reference_radius = principia.Call<double>("GeopotentialGetReferenceRadius")(
orbit.referenceBody.flightGlobalsIndex);
double μ = orbit.referenceBody.gravParameter;
return -3.0 / 2.0 * orbit.meanMotion *
Math.Pow(referenceRadius / orbit.semiLatusRectum, 2) * Math.Cos(orbit.inclination);
}
// Principia-specific utilities.
public static class Principia {
public static string AssemblyName() {
foreach (var loaded_assembly in AssemblyLoader.loadedAssemblies) {
if (loaded_assembly.assembly.GetName().Name == "ksp_plugin_adapter") {
return loaded_assembly.assembly.FullName;
}
}
throw new DllNotFoundException(
"ksp_plugin_adapter not in AssemblyLoader.loadedAssemblies");
}
public static Type GetType(string name) {
return Type.GetType(
$"principia.ksp_plugin_adapter.{name}, {AssemblyName()}");
}
// principia.ksp_plugin_adapter.ExternalInterface.Get().
public static object Get() {
return GetType("ExternalInterface")
.GetMethod("Get")
.Invoke(null, null);
}
}
// This class provides the following extension methods on all objects:
// — obj.Call("name")(args);
// — obj.GetValue("name");
// — obj.SetValue("name", value).
// The following generics are equivalent to casting the result of the
// non-generic versions, with better error messages:
// — obj.Call<T>("name")(args);
// — obj.GetValue<T>("name").
public static class Reflection {
// Returns the value of the property or field of |obj| with the given name.
public static T GetValue<T>(this object obj, string name) {
if (obj == null) {
throw new NullReferenceException(
$"Cannot access {typeof(T).FullName} {name} on null object");
}
Type type = obj.GetType();
object result = null;
FieldInfo field = type.GetField(name, public_instance);
PropertyInfo property = type.GetProperty(name, public_instance);
if (field != null) {
result = field.GetValue(obj);
} else if (property != null) {
result = property.GetValue(obj, index : null);
} else {
throw new MissingMemberException(
$"No public instance field or property {name} in {type.FullName}");
}
try {
return (T)result;
} catch (Exception exception) {
throw new InvalidCastException(
$@"Could not convert the value of {
(field == null ? "property" : "field")} {
(field?.FieldType ?? property.PropertyType).FullName} {
type.FullName}.{name}, {result}, to {typeof(T).FullName}",
exception);
}
}
public static void SetValue<T>(this object obj, string name, T value) {
if (obj == null) {
throw new NullReferenceException(
$"Cannot set {typeof(T).FullName} {name} on null object");
}
Type type = obj.GetType();
FieldInfo field = type.GetField(name, public_instance);
PropertyInfo property = type.GetProperty(name, public_instance);
if (field == null && property == null) {
throw new MissingMemberException(
$"No public instance field or property {name} in {type.FullName}");
}
try {
field?.SetValue(obj, value);
property?.SetValue(obj, value, index : null);
} catch (Exception exception) {
throw new ArgumentException(
$@"Could not set {
(field == null ? "property" : "field")} {
(field?.FieldType ?? property.PropertyType).FullName} {
type.FullName}.{name} to {typeof(T).FullName} {
value?.GetType().FullName ?? "null"} {value}",
exception);
}
}
public static object GetValue(this object obj, string name) {
return obj.GetValue<object>(name);
}
public delegate T BoundMethod<T>(params object[] args);
public static BoundMethod<T> Call<T>(this object obj, string name) {
if (obj == null) {
throw new NullReferenceException($"Cannot call {name} on null object");
}
Type type = obj.GetType();
MethodInfo method = type.GetMethod(name, public_instance);
if (method == null) {
throw new KeyNotFoundException(
$"No public instance method {name} in {type.FullName}");
}
return args => {
object result = method.Invoke(obj, args);
try {
return (T)result;
} catch (Exception exception) {
throw new InvalidCastException(
$@"Could not convert the result of {
method.ReturnType.FullName} {
type.FullName}.{name}(), {result}, to {typeof(T).FullName}",
exception);
}
};
}
public static BoundMethod<object> Call(this object obj, string name) {
return obj.Call<object>(name);
}
private const BindingFlags public_instance =
BindingFlags.Public | BindingFlags.Instance;
}
- Крылов
- Kronecker
- Колмогоров
- von Koch
- Klein
- Kleene
- 𒁹𒆠𒁷𒉡
- کاشانی
- Καραθεοδωρή
- Канторович
- 掛谷
- Julia
- Jordan
- 賈憲
- 𓇹𓄟𓋴𓏲
- Jensen
- Jacobi
- 岩澤
- 伊藤
- ابن الهيثم
- Ὑπατία
- Hurwitz
- Householder
- Horner
- l’Hôpital
- Ἱπποκράτης
- Ἱππίας
- Ἵππασος
- Ἵππαρχος
- Hilbert
- Hesse
- Ἥρων
- Hermite
- Heine
- Hausdorff
- हरीश चंद्र
- Hardy
- Hamilton
- Halley
- Hadamard
- Haar
- Grothendieck
- Grossmann
- Gröbner
- Green
- Grassmann
- Goldbach
- Gödel
- Germain
- Гельфонд
- Гельфанд
- Gauss
- Gateaux
- Galois
- Gallai
- Galileo
- Fuchs
- Fubini
- Frobenius
- Frenet
- Frege
- Fréchet
- פרנקל
- Fourier
- Fibonacci
- del Ferro
- Ferrari
- Fermat
- Fatou
- Fáry
- Fano
- Euler
- Εὐκλείδης
- Εὔδοξος
- Erdős
- Ἐρατοσθένης
- Διόφαντος
- Descartes
- Desargues
- Δημόκριτος
- Dedekind
- Darboux
- Cramer
- Coxeter
- Cohen
- Clifford
- Christoffel
- 陈景润
- Chasles
- Cesàro
- Чебышёв
- Cayley
- Cauchy
- Catalan
- Cartan
- Cardano
- Cantor
- بوژگانی
- Burnside
- Буняковский
- Buffon
- Brouwer
- Bourbaki
- Borel
- Bolzano
- Bessel
- Бернштейн
- Bernoulli
- Banach
- Agnesi
- Ackermann
- Abel