Skip to content
Andrey edited this page Sep 24, 2023 · 8 revisions

Introduce

There is a class Level that contains everything related to the editor.
Such as colors, blocks, background, guidelines and others

Getting a Level instance

From local saves

var local = await LocalLevels.LoadFileAsync();
var level = local.GetLevel("MyLevel", revision: 0).LoadLevel();

revision is the number for levels with the same names.
In the game, it's written as "rev."

From destination server (aka download)

var response = await client.DownloadLevelAsync(id: 49395494);
if (response.GeometryDashStatusCode != 0)
    throw new InvalidOperationException($"server return an error: {response.GeometryDashStatusCode}");

var levelString = response.GetResultOrDefault()?.Level?.LevelString;
if (string.IsNullOrEmpty(levelString))
    throw new InvalidOperationException("malformed level string");

var level = new Level(levelString, compressed: true);

Create an empty level

var level = new Level();

Interacts

Colors

Add color

level.AddColor(new Color(10)
{
    Rgb = RgbColor.FromHex("#ffa500") // orange
});

Blocks

Concept

The concept of blocks is such that there is an IBlock, this is an interface that contains all the basic properties, and then new properties are added by inheritance.
For MoveTrigger it's looks this: MoveTrigger -> Trigger -> Block -> IBlock

IBlock
└ Block
   ├ Trigger
   │  ├ MoveTrigger
   │  ├ AlphaTrigger
   │  ├ AnimateTrigger
   │  ├ PickupTrigger
   │  └ and more, see all triggers in "GeometryDashAPI/Levels/GameObjects/Triggers"
   ├ BaseBlock
   │  └ there is any blocks that contain BaseColor
   ├ DetailBlock
   │  └ there is any blocks that contain DetailColor
   ├ ColorBlock (both of BaseBlock and DetailBlock)
   ├ StartPos
   ├ JumpSphere
   ├ Coin
   └ and more special blocks. You can find it in "GeometryDashAPI/Levels/GameObjects/Specific"

Add blocks

level.AddBlock(new BaseBlock(id: 1)
{
    PositionX = 120,
    PositionY = 120,
    Groups = new[] { 1, 2 },
    DontFade = true
    // and more
});

Note that BaseBlock does not contain all possible properties!
For example, if you create a MoveTrigger instead of BaseBlock, you can specify TargetGroupId and MoveTime additionally

level.AddBlock(new MoveTrigger()
{
    PositionX = 120,
    PositionY = 120,
    Groups = new[] { 1, 2 },
    DontFade = true,
    TargetGroupId = 51,
    MoveTime = 0.5f
});

Array of all blocks

level.Blocks is an array (List<IBlock>) with all blocks.

By default, IBlock is inside. This means that the most basic properties will be available to you.
But you can use casts to find more properties.
For example: find all alpha triggers

foreach (var block in level.Blocks)
{
    if (block is AlphaTrigger alpha)
        Console.WriteLine($"alpha at ({alpha.PositionX}, {alpha.PositionY}) with group {alpha.TargetGroupID}");
}

Or using linq for simplify

foreach (var alpha in level.Blocks.Cast<AlphaTrigger>())
    Console.WriteLine($"alpha at ({alpha.PositionX}, {alpha.PositionY}) with group {alpha.TargetGroupID}");

Note
Not all game blocks contain their own classes.
So, sometimes you will have to use the block id to find what you need

foreach (var alpha in level.Blocks.Where(x => x.Id == 1887))
    Console.WriteLine($"soft sphere at ({alpha.PositionX}, {alpha.PositionY})");

Id = 1887 is
image

I've made a level with all ids in 2.1, you can see this level on the server with id = 49395494
image

Saving a Level instance

To current level in editor

local.GetLevel("MyLevel", revision: 0).SaveLevel(level);
await local.SaveAsync();

To new level in editor

var levelInfo = LevelCreatorModel.CreateNew(name: "MyLevel", authorName: "Folleach");
levelInfo.SaveLevel(level);

local.AddLevel(levelInfo);
await local.SaveAsync();