Flattiverse.Connector is the C# reference connector for Flattiverse galaxies. It mirrors the current galaxy state locally, exposes an event-driven API, and lets players or admins call commands against a galaxy endpoint.
If you want to implement your own connector, see IMPLEMENTERS.md.
If you want to build a map editor against the connector, see MAPEDITORS.md.
.NET 10- a Flattiverse API key for player or admin access
- a full galaxy endpoint URI such as
wss://www.flattiverse.com/galaxies/0/api
- Register an account at the Flattiverse homepage.
- Create an API key.
- Add the
Flattiverse.ConnectorNuGet package to your project. - Connect to a galaxy endpoint with
Galaxy.Connect(...). - Process events with
await galaxy.NextEvent().
Minimal example:
using Flattiverse.Connector.Events;
using Flattiverse.Connector.GalaxyHierarchy;
Galaxy galaxy = await Galaxy.Connect(
"wss://www.flattiverse.com/galaxies/0/api",
"<api-key>",
"Pink");
await galaxy.Chat("Hello world.");
while (galaxy.Active)
{
FlattiverseEvent @event = await galaxy.NextEvent();
Console.WriteLine(@event);
}auth == null connects as spectator. team == null lets the server auto-select the least populated non-spectator team for normal players unless an active tournament assigns the account to a configured team. runtimeDisclosure and buildDisclosure are optional extra arguments on Galaxy.Connect(...); galaxies may require them. The server sends periodic ping challenges and disconnects sessions whose replies stay stale for too long. The reference connector replies to those ping challenges automatically, so long-lived clients do not need a separate heartbeat loop.
- connect to a galaxy and keep a local mirror of galaxy settings, teams, clusters, players, controllables and visible units
- receive strongly typed events for settings changes, compile profile announcement, login MOTD and system messages, score changes, team and cluster lifecycle, player lifecycle, visible unit lifecycle,
ControllableInfolifecycle, owner-side subsystem runtime, player chat, objective system chat including mission-target hits, and connection termination - receive owner-only
CollectedPowerUpEventpackets withPowerUpName,PowerUpKind, configuredAmount, and actualAppliedAmount - inspect
Galaxy.Tournamentand receiveCreatedTournamentEvent,UpdatedTournamentEvent,RemovedTournamentEvent, andTournamentMessageEvent - observe respawning power-ups through the normal visible-unit create/delete lifecycle; the connector does not use a dedicated respawn packet
- inspect
Player.ScoreandTeam.Score, and react toUpdatedPlayerScoreEventandUpdatedTeamScoreEvent - create and control classic ships
- create and control modern ships
- create classic ships with up to three equipped crystal names
- create modern ships with up to three equipped crystal names
- request, create, rename and destroy account-wide crystals through
Galaxy.RequestCrystals(),Galaxy.ProduceCrystal(...),Galaxy.RenameCrystal(...)andGalaxy.DestroyCrystal(...) - inspect and control the
ClassicShipControllable.Enginesubsystem - inspect and control
ModernShipControllable.EngineN..EngineNW - inspect owner-side integrity runtime via
Controllable.HullandControllable.Shield - inspect owner-side nebula cargo via
Controllable.Cargo.MaximumNebula,CurrentNebulaandNebulaHue - inspect owner-side derived flight values via
Controllable.EffectiveStructureLoad,Size,Gravity,SpeedLimitandEngineEfficiency - inspect and control
ClassicShipControllable.NebulaCollector - inspect and control
ModernShipControllable.ScannerN..ScannerNW - inspect and use
ModernShipControllable.ShotLauncherN..ShotLauncherNW, the matching magazines and shot fabricators - inspect and use
ModernShipControllable.InterceptorLauncherE/InterceptorLauncherW, the matching magazines and interceptor fabricators - inspect and use
ModernShipControllable.RailgunN..RailgunNW - inspect and use the
ClassicShipControllable.ShotLauncher,ClassicShipControllable.ShotMagazine, andClassicShipControllable.ShotFabricatorsubsystems - inspect and use the
ClassicShipControllable.InterceptorLauncher,ClassicShipControllable.InterceptorMagazine, andClassicShipControllable.InterceptorFabricatorsubsystems - inspect and use
ClassicShipControllable.RailgunviaFireFront()/FireBack() - inspect owner-side controllable battery runtime via
Controllable.EnergyBattery,Controllable.IonBatteryandControllable.NeutrinoBattery - inspect controllable battery capacities and energy-cell efficiencies via the corresponding subsystem objects
- inspect per-tick battery consumption via
BatterySubsystem.ConsumedThisTick - inspect per-tick collected energy via
EnergyCellSubsystem.CollectedThisTick - inspect owner-side ClassicShip scanner runtime via
ClassicShipControllable.MainScannerandClassicShipControllable.SecondaryScanner - send galaxy, team and private chat messages
- use admin functions to configure galaxy metadata, teams and clusters
- use admin functions to edit regions and editable map units
- use admin functions to query accounts and configure, commence, start, or cancel tournaments
- inspect
CurrentFieldmap units including directional flow and relative radial or tangential force configuration - inspect
Stormmap units and the visible lifecycle ofStormCommencingWhirlandStormActiveWhirl
The connector currently materializes these unit kinds as visible units or own controllables:
SunBlackHoleCurrentFieldNebulaStormStormCommencingWhirlStormActiveWhirlPlanetMoonMeteoroidBuoyWormHoleMissionTargetFlagDominationPointEnergyChargePowerUpIonChargePowerUpNeutrinoChargePowerUpMetalCargoPowerUpCarbonCargoPowerUpHydrogenCargoPowerUpSiliconCargoPowerUpShieldChargePowerUpHullRepairPowerUpShotChargePowerUpSwitchGateShotInterceptorRailClassicShipPlayerUnitModernShipPlayerUnitInterceptorExplosionExplosion
Connection and local state:
Galaxy.Connect(...)Galaxy.NextEvent()Galaxy.TournamentGalaxy.TeamsGalaxy.ClustersGalaxy.PlayersGalaxy.ControllablesGalaxy.CompiledWithMaxPlayersSupportedGalaxy.CompiledWithSymbol
Player-facing commands:
Galaxy.Chat(...)Galaxy.CreateClassicShip(...)Galaxy.CreateModernShip(...)Galaxy.RequestCrystals()Galaxy.ProduceCrystal(...)Galaxy.RenameCrystal(...)Galaxy.DestroyCrystal(...)Team.Chat(...)Player.Chat(...)for private text chat and private binary chatPlayer.DownloadSmallAvatar(...)Player.DownloadBigAvatar(...)Galaxy.CreateClassicShip(...)ClassicShipControllable.MainScannerClassicShipControllable.SecondaryScannerClassicShipControllable.EngineModernShipControllableControllable.HullControllable.ShieldClassicShipControllable.ShotLauncherClassicShipControllable.ShotMagazineClassicShipControllable.ShotFabricatorClassicShipControllable.InterceptorLauncherClassicShipControllable.InterceptorMagazineClassicShipControllable.InterceptorFabricatorClassicShipControllable.Railgun
Admin-facing commands:
Galaxy.Configure(...)Galaxy.QueryAccounts(...)Galaxy.ConfigureTournament(...)Galaxy.CommenceTournament()Galaxy.StartTournament()Galaxy.CancelTournament()Cluster.SetRegion(...)Cluster.RemoveRegion(...)Cluster.QueryRegions()Cluster.QueryEditableUnits(...)Cluster.SetUnit(...)Cluster.RemoveUnit(...)Cluster.QueryUnitXml(...)
NextEvent()must not be awaited concurrently. Parallel calls fail withCantCallThisConcurrentGameException.- The
Developmentproject is a regression and experimentation client, not a minimal beginner sample. - The private scripted tooling (
CliShip,AdminRunner) now lives in the sibling repository../fv-clishipand is intentionally no longer part of the public connector solution. - Map-edit XML rules, examples, and server-side validation behavior are documented in MAPEDITORS.md.
- The server keeps sessions alive with periodic ping challenges. The reference connector answers them automatically, so client code only needs to keep consuming events and issuing its normal commands.
Galaxy.Tournamentisnullif no tournament is configured. Tournament state changes are mirrored through tournament events and can additionally surface asTournamentMessageEventsystem-chat packets.ControllableInfolifecycle is event-driven. Owner-sideControllableobjects are mirrored locally on0x80/0x81/0x8F, but the connector currently does not raise separate lifecycle events for them.0x8Fis the final close, not the initial close request.Player.HasAvatartells you whetherDownloadSmallAvatar(...)/DownloadBigAvatar(...)are valid for that player. The reference connector throws immediately if no avatar is available.DownloadSmallAvatar(...)/DownloadBigAvatar(...)and the matching account avatar download methods accept an optionalProgressStatethat can be polled while the connector fetches internal chunks.Galaxy.QueryAccounts(...)returns alluser/reoptinconnectorAccountsnapshots for tournament tooling in one logical result and accepts an optionalProgressStatefor chunked transfer progress.Cluster.QueryEditableUnits(...)returns(Name, Kind)summaries for all editable units of the cluster, including currently invisible ones such as inactive power-ups.- Battery maxima, cell efficiencies, hull and shield maxima, cargo capacities, and similar owner-side static subsystem capabilities are initialized from
0x80 Controllable Create. Controllable.EffectiveStructureLoadmirrors the owner-authoritative value sent on0x80 Controllable Createrefreshes. Upgrade previews should still useControllable.CalculateProjectedEffectiveStructureLoad(...)together with the static helper formulas onSubsystemTierInfo.- Scanner subsystems are server-authoritative runtime objects.
Set(...),On(), andOff()send player commands;Current*,Target*, andActiveare mirrored back via0x82. Controllable.Angle/AngularVelocityand visiblePlayerUnit.Angle/AngularVelocityare authoritative wire values. They are no longer derived from movement.- Visible projectile
Unit.SpeedLimitis derived locally:Shot = 10,Interceptor = 10,Rail = 15. Those caps are runtime rules, not additional wire payload. - Worm holes are visible units. Their destination is intentionally absent in reduced visibility and only appears once the unit reaches full visibility. Triggering a jump is an explicit owner command through
JumpDrive.Jump(), not an automatic collision effect. CurrentFieldis a non-solid visible map unit.Mode=Directionalexposes a fixed world-spaceFlow, whileMode=RelativeexposesRadialForceandTangentialForce.Stormis an editable non-solid map unit that spawns mobile storm whirls.StormCommencingWhirlis visible early and only exposes its remaining announcement ticks in full visibility, whileStormActiveWhirlis masking and additionally exposesDamage.- Scanner angles are absolute world angles.
scan:90x300x0therefore points east on the world axis, independent of ship movement. - The current scanner cost preview is surface-based and matches the current server-side scanner formula.
Shield.Set(...)/On()/Off()manage shield loading. The referenceClassicShipshield hasMaximum=20,MaximumRate=0.125, and tick cost1600 * rate^2, so the maximum rate costs25energy per tick.Armoris a passive flat reduction before hull damage.Repair.Set(rate)manages hull-only repair withrate in [0; 0.1]and tick cost1600 * rate^2;rate == 0means off, and the server clears the rate when ship movement reaches>= 0.1.- Passive sun effects now also surface as owner-only
EnvironmentDamageEvent: heat drains15energy per point, unpaid heat overflows into radiation, and radiation damage is reduced by armor before reaching hull. ShotLauncher.Shoot(...)andInterceptorLauncher.Shoot(...)use the same configurable projectile launch profile.ShotFabricator.Set(...)/On()/Off()andInterceptorFabricator.Set(...)/On()/Off()manage the two magazines separately.Railgun.FireFront()/FireBack()request a fixed rail shot withEnergyCost=300,MetalCost=1, projectile speed4, and lifetime250. At zero ship movement the rail direction falls back to world angle0.ShotMagazine.CurrentShotsandInterceptorMagazine.CurrentShotsare owner-visible through0x82and visible on foreign ships through their richerUnitUpdatedsnapshots.- The owner's own ship must be read from
Controllable/0x80/0x82, not from visible-unit events. Those owner packets now also carry the authoritativeclusterId, so cluster jumps must be tracked there instead of inferred from visible scans.