KspGonogo.Kerbcast.API.Testing
1.5.0
dotnet add package KspGonogo.Kerbcast.API.Testing --version 1.5.0
NuGet\Install-Package KspGonogo.Kerbcast.API.Testing -Version 1.5.0
<PackageReference Include="KspGonogo.Kerbcast.API.Testing" Version="1.5.0" />
<PackageVersion Include="KspGonogo.Kerbcast.API.Testing" Version="1.5.0" />
<PackageReference Include="KspGonogo.Kerbcast.API.Testing" />
paket add KspGonogo.Kerbcast.API.Testing --version 1.5.0
#r "nuget: KspGonogo.Kerbcast.API.Testing, 1.5.0"
#:package KspGonogo.Kerbcast.API.Testing@1.5.0
#addin nuget:?package=KspGonogo.Kerbcast.API.Testing&version=1.5.0
#tool nuget:?package=KspGonogo.Kerbcast.API.Testing&version=1.5.0
Kerbcast.API
The public interface to Kerbcast, the Kerbal Space Program mod that streams camera feeds to browsers. Build your mod against the KspGonogo.Kerbcast.API package and Kerbcast's own Kerbcast.API.dll, shipped in GameData/Kerbcast/Plugins/, answers at runtime.
It references nothing but the base class library: no UnityEngine, no Assembly-CSharp. The package carries a net48 build, the one KSP loads, and a netstandard2.0 build so test projects on modern .NET restore it cleanly. Vectors are its own Vec3d and Quatd, bodies are flightGlobalsIndex, craft and parts are persistentIds.
Referencing it
- Reference the package as
<PackageReference Include="KspGonogo.Kerbcast.API" Version="..." PrivateAssets="all" ExcludeAssets="runtime" />(orPrivate="false"on a plain reference) and never ship a copy ofKerbcast.API.dllwith your mod. Kerbcast ships the one KSP loads.PrivateAssetsalone still copies the DLL into your build output - A hard dependency declares
[assembly: KSPAssemblyDependency("KerbcastAPI", 1, 0)] - A soft dependency checks that
"KerbcastAPI"is inAssemblyLoader.loadedAssembliesbefore touching any API type, and keeps API-typed calls in their own[MethodImpl(MethodImplOptions.NoInlining)]methods so the JIT never resolves them when Kerbcast is absent
Using it
using Kerbcast.Api;
var kerbcast = KerbcastApi.Instance; // null outside flight and the Space Center, or without Kerbcast
if (kerbcast != null && KerbcastApi.Supports(ApiFeature.CraftIdentity))
{
foreach (var cam in kerbcast.Cameras.CamerasFor(vessel.persistentId))
if (cam.HasDockingNode == true)
kerbcast.Cameras.SetFov(cam.FlightId, 20);
}
KerbcastApi.Instance,ApiMinorandSupportsare safe on any thread. So areIKerbcast's own membersICamerasandICommandare main thread only; every member throwsInvalidOperationExceptionon another threadIWorldModelPublisheris safe on any threadICamerascontrols part cameras.Viewalso shows command feeds (Kind == CameraKind.Command), which onlyICommandcontrols- A command feed's view says whether its target is occluded (
Occluded), since when in game time (OccludedSinceUt, NaN while clear) and by what (Occluder, a body's name). It is the raw reading with no smoothing, so ease it yourself. Part cameras always read as clear. Added in 1.2 ICommand.SetOpticsoverrides how blurred a command feed's far planets and craft look (OpticsSettings: the lens's blur, the air's blur and the rest, NaN keeping Kerbcast's own value), and null returns the feed to its own. The lock applies as forSetAim. It takes effect only while the player'sDeepSpaceOpticssetting is on, which it is by default from Kerbcast 1.12.1, and the game can draw it. Added in 1.5, behindApiFeature.OpticsICommand.CreateNetworkCameramakes a camera network camera: one command feed that follows its craft through the vantages you list (ground stations, launch sites, surface points or craft,NetworkVantage;LaunchSite(null)takes the launch site of the active craft in flight, or of the watched craft at the Space Center, and the stock pad when that craft has none) and cuts to whichever has the clearest view. A cut is hard, and the feed's label (every frame'ssiteLabel) changes on the cut frame. After a cut it holds forNetworkOptions.MinHoldUtgame seconds andMinHoldRealSecondsreal seconds, then moves only for a vantageMarginStopsclearer; a vantage about to lose sight of the craft is left early. With no vantage able to see it, the camera stays where it is, or moves to the vantage you markedAsFallback(). There is no default list: you pass every vantage, and an empty list is refused withNoVantages. Each vantage keeps the lens it would have alone, may carry your ownLabel(up to 64 characters), and under a world model is judged only on what its own site knows.SetNetworkVantagesreplaces the list,NetworkStatusreads each vantage's state, score and, while it readsoccluded, theOccluder, andDestroyNetworkCameraremoves the camera. Like any created camera it ends with the scene, a revert or quickload included, so make it again in the next one. Under a world model an aim is accepted when any vantage's site knows the craft. The lock applies as forSetAim, and only the mod that made a network may replace its vantages or remove it (one made under no name is anyone's). Added in 1.5, behindApiFeature.NetworkCameras- On a network camera,
CommandFeed.SiteKeynames the vantage it shows now and changes on every cut, so key a network camera by its FlightId.CommandFeed.Networkmarks one ICommand.GroundStationslists every ground station in the scene a command camera can stand at (GroundStationInfo: the node name aNetworkVantage.Stationtakes, the game's name for it, its body, place and ground altitude, and whether the game has it switched on, with itsDisabledReasonwhile off), so you can build your own vantage list. Added in 1.5, behindApiFeature.GroundStationsCommandFeed.FollowsActiveVesselsays a feed has no aim of its own and so watches the default craft (the active vessel in flight); any aim, the active vessel's included, makes it false until cleared. Added in 1.5ICommand.LineOfSightanswers whether a lens at aNetworkVantagecould see a point you give, at one game time you give, with the vantage, every body and the vantage's skyline placed at that instant and tested as command cameras draw (LineOfSightResult:Known,Visible,Occluder,BelowHorizon,RangeM, andDisabledfor a ground station the game has switched off).Knownis false rather than a guess when the vantage cannot be placed or its skyline is not yet measured where the line needs it. A craft vantage is placed on its current orbit patch. The point is in the world model's state vector frame. It has no light time or delay in it, so pick the instant and the point yourself. A read for the host alone: no lock, never shown to viewers, used by no camera. Added in 1.5, behindApiFeature.LineOfSightLineOfSightResult.ResolutionRadis the smallest angle a command camera at the vantage resolves toward the point at its tightest zoom: one pixel there, or, with deep-space optics drawn, the lens and air blur toward that point if wider. Multiply byRangeMfor the smallest size it could tell apart there, and by your own factor for what counts as seen. A feed'sSetOpticsoverride is not in it. NaN when notKnown. Added in 1.5, behindApiFeature.VantageResolutionICommand.VantageResolutiongives the parts for oneNetworkVantage, by the rules a camera there would have (VantageResolution:FovMinDeg, the tightest vertical field of view;FrameWidthPxandFrameHeightPx, the frame at full quality;PixelRad, one pixel at that zoom, which isFovMinDegover the frame's height;OpticsOn;LensArcsec, the lens's own blur now;BestResolutionRad, the finest it resolves with no air in the way; and which lens it is:LensSource(TrackingStation,LaunchSiteorSpaceLens),LensLevel(the Tracking Station level, or the space-lens step) andLensName, a name a player would recognise). They follow the Tracking Station level and research, so read them again rather than keeping them. A read for the host alone, no lock. Added in 1.5, behindApiFeature.VantageResolution- A command feed zooms itself: a
Vessel,OrbitorPositionAtaim frames its subject, aSurfaceaim frames its margin about the point (the widest view with none) and aDirectionaim opens to the widest view, no longer sized by the default craft. No viewer or mod sets its field of view:ICameras.SetFovreturns false for it, as for a part camera without zoom. Added in 1.5 - With deep-space optics drawn, a command camera stops zooming where its optics blur toward the aim spans about 2 pixels: the lens sets the zoom limit, as in a telescope (near 1.2 degrees for the level 1 lens, near 0.1 from the ground at level 3). Its framing stops there, and the camera's live
fovMinreports it.VantageResolution.FovMinDegandPixelRadgive the best case, the lens alone with no air;ResolutionRadis unchanged, since at that zoom one pixel is half the blur. Added in 1.5 - A command camera on a craft outside any atmosphere has a space lens that improves as research unlocks tech nodes (Scanning Tech 0.5 arcseconds, Advanced Science Tech 0.2, Experimental Science 0.05; sandbox has the last), and takes it when it is sharper than the Tracking Station's. Ground stations, launch sites and surface points keep the Tracking Station lens, as does a craft inside an atmosphere. With deep-space optics drawn, a space lens zooms past the usual 0.02 degree limit, to where its blur spans about 2 pixels (about 0.004 degrees for the top step).
VantageResolutionandLineOfSightResult.ResolutionRadreport it, so a host's visibility ranges follow. A player's settings can retarget each step's node and lens. Added in 1.5 NetworkVantageStatuscarries each vantage'sSiteKindandVantagePersistentId(0 unless it is a craft), so a host that binds sites can bind every vantage of a network, not only the one on air. Added in 1.5- Players can save camera networks with the game from Kerbcast's page. Each runs as a command camera with a flightId that stays the same in every scene and through reloads (from 0xFFFF0000 up, a range no other camera uses), and shows in
FeedswithCommandFeed.Savedset. It is the player's:SetNetworkVantages,DestroyNetworkCameraandDestroyCommandCamerarefuse it (NotCommandFeed, false), whileSetAimworks on it under the lock rules. Taking or releasing the lock returns it to its saved watch. Added in 1.5 KerbcastApi.Identityreports merges, splits, destructions, recoveries and renumbers. A subscription lasts for the whole process, whatever the scene and whether or notInstanceis setICameras.TryVesselandTryPersistentIdtranslate between a craft's persistentId and Vessel.id, even after KSP has dropped the craftKerbcastApi.LockLostsays when the command lock left its holder without aReleaseLock: the scene is ending, or the player released it in game. Take the lock again once the next scene starts; the dying scene refuses a take from the handler. LikeIdentity, a subscription lasts for the whole process- A reserved scene whose owner makes no call within 30 s of real time lapses: the lock stays held and the feeds stay blank, never the truth, but browser clients may create and remove command cameras. The owner's next call ends the lapse; only the player's in-game release returns the scene to truth
TakeLock,SetAimandPublishreturnNotRunningwhen Kerbcast is not running in the scene, as through an object kept from an earlier one- Every result enum (
LockResult,AimResult,PublishResult) hasUnknown = 0, which Kerbcast never returns, so a result nobody set never reads as success - A member whose
ApiFeatureis unsupported still exists and throwsNotSupportedException. CheckSupportswhen you were built against a newer minor than the Kerbcast you run with - A member added without its own
ApiFeature(such asWorldModelBuilder.Accelerationin 1.1, orCameraView's occlusion in 1.2) is guarded byKerbcastApi.ApiMinor, notSupports - Built against a newer minor, keep each call to a member that minor added in its own
[MethodImpl(MethodImplOptions.NoInlining)]method too. The JIT resolves every member a method names when it compiles that method, so an older Kerbcast throwsMissingMethodExceptioneven when the call sits behind aSupportscheck that returns false
Versioning
AssemblyVersion stays 1.0.0.0 for the whole 1.x line, so a mod built against any 1.x binds to any other. The minor is KerbcastApi.ApiMinor, the KSPAssembly version and the file version. The package version is the API's own version, not Kerbcast's: it moves only when the API does, so its minor is the KSPAssemblyDependency minor to declare. Within a major, changes are additive: members and enum values are added, never removed or renumbered. Only Kerbcast implements the interfaces, so new interface members are not breaking.
Testing without Kerbcast
The KspGonogo.Kerbcast.API.Testing package (Kerbcast.Api.Testing.RecordingKerbcast) is a headless implementation for your unit tests. It needs no Kerbcast.dll, Unity or KSP, and never ships in GameData, so reference it from test projects only:
using (var kc = RecordingKerbcast.Install()) // now KerbcastApi.Instance
{
kc.Cameras.Add(new CameraView { FlightId = 7, Kind = CameraKind.Part, VesselPersistentId = 42 });
kc.Command.AddFeed(new CommandFeed { FlightId = 500, SiteKey = "KSC" });
RunCodeUnderTest();
Assert.Equal("my-mod", kc.Command.LockOwner);
Assert.Single(kc.Command.Published);
}
It keeps the threading contract against the thread that installed it, applies the documented lock, aim, network and publishing rules, records every call (Calls), and lets a test raise identity events, change scene or turn features off (SetSupported).
Licence
MIT. Kerbcast itself is licensed separately; see its repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.8
- KspGonogo.Kerbcast.API (= 1.5.0)
-
.NETStandard 2.0
- KspGonogo.Kerbcast.API (= 1.5.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.5.0 | 67 | 11/11/2026 |
| 1.5.0-rc.128 | 53 | 11/10/2026 |
| 1.5.0-rc.127 | 45 | 11/10/2026 |
| 1.5.0-rc.126 | 50 | 11/10/2026 |
| 1.5.0-rc.125 | 44 | 11/10/2026 |
| 1.5.0-rc.124 | 48 | 11/10/2026 |
| 1.5.0-rc.123 | 50 | 11/10/2026 |
| 1.5.0-rc.122 | 57 | 11/9/2026 |
| 1.5.0-rc.121 | 50 | 11/9/2026 |
| 1.5.0-rc.120 | 51 | 11/9/2026 |
| 1.5.0-rc.119 | 54 | 11/9/2026 |
| 1.5.0-rc.118 | 52 | 11/9/2026 |
| 1.5.0-rc.117 | 51 | 11/9/2026 |
| 1.5.0-rc.116 | 51 | 11/9/2026 |
| 1.5.0-rc.115 | 67 | 11/9/2026 |
| 1.5.0-rc.114 | 50 | 11/9/2026 |
| 1.5.0-rc.113 | 55 | 11/9/2026 |
| 1.5.0-rc.112 | 55 | 11/9/2026 |
| 1.5.0-rc.111 | 53 | 11/9/2026 |
| 1.5.0-rc.110 | 55 | 11/9/2026 |