├── .devcontainer └── devcontainer.json ├── .github ├── ISSUE_TEMPLATE │ ├── blank.md │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── publish.yml │ └── tests.yml ├── .gitignore ├── .vscode └── launch.json ├── GeometryDashAPI.Benchmarks ├── BenchmarkSources │ └── SampleLevel.txt ├── Benchmarks │ ├── DisassemblyBenchmark.cs │ ├── GDParserBenchmark.cs │ ├── GameDataBenchmark.cs │ ├── LLParserBenchmark.cs │ ├── LevelLoadBenchmark.cs │ ├── ObjectParserBenchmark.cs │ └── ReflectionVsExpression.cs ├── GeometryDashAPI.Benchmarks.csproj └── Program.cs ├── GeometryDashAPI.Tests ├── BlockParseTest.cs ├── BlockTests.cs ├── Documentation │ └── BlocksDocumentation.cs ├── GameConvertTest.cs ├── GameDataTests.cs ├── GameResourcesTests.cs ├── GameServerTests.cs ├── GeometryDashAPI.Tests.csproj ├── GuidelinesTest.cs ├── Integration │ └── Levels │ │ ├── LevelResponseDefinedTest.cs │ │ ├── LevelResponseFromStreamTest.cs │ │ └── LevelResponseTestBase.cs ├── LLParserTests.cs ├── LevelDurationTests.cs ├── MessageTests.cs ├── ObjectParserTests.cs ├── PaginationTests.cs ├── Sources.cs ├── StructParserTests.cs ├── TestExtensions.cs ├── TypeDescriptorTests.cs └── data │ ├── levels │ ├── 116631_XmasParty │ ├── 12034598_Conclusion │ └── 28755513_TheFinalLair │ └── saves │ ├── CCGameManager1.dat │ ├── CCGameManagerEmpty.dat │ ├── CCLocalLevels1.dat │ └── CCLocalLevelsEmpty.dat ├── GeometryDashAPI.sln ├── GeometryDashAPI.sln.DotSettings ├── GeometryDashAPI ├── Attributes │ ├── ArraySeparatorAttribute.cs │ ├── AsStructAttribute.cs │ ├── GamePropertyAttribute.cs │ ├── OriginalNameAttribute.cs │ └── SenseAttribute.cs ├── Crypt.cs ├── Culture.cs ├── Data │ ├── DatFileFormat.cs │ ├── Enums │ │ ├── GameDataType.cs │ │ └── TextureQuality.cs │ ├── GameData.cs │ ├── GameManager.cs │ ├── GameResources.cs │ ├── LocalLevels.cs │ └── Models │ │ ├── GdResolution.cs │ │ └── LevelCreatorModel.cs ├── Exceptions │ ├── BlockLoadException.cs │ ├── ConstructorNotFoundException.cs │ ├── NotImplementIBlockException.cs │ ├── PropertyNotSupportedException.cs │ └── UnableSetException.cs ├── Extensions.cs ├── Factories │ ├── DefaultHttpClientFactory.cs │ └── IFactory.cs ├── GameConvert.cs ├── GameObject.cs ├── GameType.cs ├── GeometryDashAPI.csproj ├── GeometryDashApi.cs ├── IGameObject.cs ├── Levels │ ├── BlockGroup.cs │ ├── BlockList.cs │ ├── Color.cs │ ├── ColorList.cs │ ├── Enums │ │ ├── ColorType.cs │ │ ├── ConditionType.cs │ │ ├── Easing.cs │ │ ├── GameMode.cs │ │ ├── GuidelineColors.cs │ │ ├── Layer.cs │ │ ├── PulseModeType.cs │ │ ├── SpeedType.cs │ │ ├── TargetPosGroupType.cs │ │ ├── TargetType.cs │ │ └── ToggleMode.cs │ ├── GameBlockAttribute.cs │ ├── GameObjects │ │ ├── Default │ │ │ ├── BaseBlock.cs │ │ │ ├── Block.cs │ │ │ ├── ColorBlock.cs │ │ │ ├── DetailBlock.cs │ │ │ ├── Portal.cs │ │ │ ├── TargetingTrigger.cs │ │ │ └── Trigger.cs │ │ ├── IBlock.cs │ │ ├── ITrigger.cs │ │ ├── Specific │ │ │ ├── CircleParticle.cs │ │ │ ├── Coin.cs │ │ │ ├── JumpPlate.cs │ │ │ ├── JumpSphere.cs │ │ │ ├── SpeedBlock.cs │ │ │ ├── SquareParticle.cs │ │ │ ├── StartPos.cs │ │ │ └── TextBlock.cs │ │ └── Triggers │ │ │ ├── AlphaTrigger.cs │ │ │ ├── AnimateTrigger.cs │ │ │ ├── CollisionBlockTrigger.cs │ │ │ ├── CollisionTrigger.cs │ │ │ ├── ColorTrigger.cs │ │ │ ├── CountTrigger.cs │ │ │ ├── DisableBgEffectTrigger.cs │ │ │ ├── DisablePlayerTrailTrigger.cs │ │ │ ├── EditSfxTrigger.cs │ │ │ ├── EditSongTrigger.cs │ │ │ ├── EnableBgEffectTrigger.cs │ │ │ ├── EnablePlayerTrailTrigger.cs │ │ │ ├── FollowPlayerYTrigger.cs │ │ │ ├── FollowTrigger.cs │ │ │ ├── HidePlayerIconTrigger.cs │ │ │ ├── InstantCountTrigger.cs │ │ │ ├── MoveTrigger.cs │ │ │ ├── OnDeathTrigger.cs │ │ │ ├── PickupTrigger.cs │ │ │ ├── PulseTrigger.cs │ │ │ ├── RotateTrigger.cs │ │ │ ├── SfxTrigger.cs │ │ │ ├── ShakeTrigger.cs │ │ │ ├── ShowPlayerIconTrigger.cs │ │ │ ├── SongTrigger.cs │ │ │ ├── SpawnTrigger.cs │ │ │ ├── StopTrigger.cs │ │ │ ├── ToggleTrigger.cs │ │ │ └── TouchTrigger.cs │ ├── Guideline.cs │ ├── Guidelines.cs │ ├── Hsv.cs │ ├── Level.cs │ ├── LevelDuration.cs │ ├── LevelOptions.cs │ ├── LevelSpeed.cs │ └── Structures │ │ └── RgbColor.cs ├── Memory │ ├── Access.cs │ └── GameProcess.cs ├── OfficialLevel.cs ├── Property.cs ├── Serialization │ ├── IDescriptor.cs │ ├── IGameSerializer.cs │ ├── LLParserSpan.cs │ ├── MemberDescription.cs │ ├── ObjectSerializer.cs │ ├── Parsers.cs │ ├── Plist.cs │ ├── PrinterInfo.cs │ ├── Printers.cs │ ├── SetterInfo.cs │ ├── TypeDescriptor.cs │ └── TypeDescriptorExtensions.cs └── Server │ ├── Dtos │ ├── Account.cs │ ├── AccountComment.cs │ ├── AuthorIds.cs │ ├── LevelInfo.cs │ ├── LevelPreview.cs │ ├── Message.cs │ ├── MessageContent.cs │ ├── MessagePreview.cs │ ├── MusicInfo.cs │ └── UserPreview.cs │ ├── Enums │ ├── AllowMessagesFrom.cs │ ├── DataType.cs │ ├── DemonDifficulty.cs │ ├── Difficulty.cs │ ├── DifficultyIcon.cs │ ├── GameModeratorType.cs │ ├── LengthType.cs │ ├── OfficialSong.cs │ ├── SearchDemonDifficulty.cs │ ├── SearchDifficulty.cs │ ├── SearchType.cs │ └── TopType.cs │ ├── GameClient.cs │ ├── IGameClient.cs │ ├── IQuery.cs │ ├── Network.cs │ ├── Pagination.cs │ ├── Parameters.cs │ ├── Queries │ ├── FlexibleQuery.cs │ ├── GetLevelsQuery.cs │ ├── IdentifierQuery.cs │ ├── OnlineQuery.cs │ ├── PasswordQuery.cs │ └── RandomSeedQuery.cs │ ├── Responses │ ├── AccountCommentPageResponse.cs │ ├── AccountInfoResponse.cs │ ├── LevelPageResponse.cs │ ├── LevelResponse.cs │ ├── LoginResponse.cs │ ├── MessagesPageResponse.cs │ ├── NoneResponse.cs │ ├── TopResponse.cs │ └── UserResponse.cs │ ├── ServerResponse.cs │ └── ServerResponseHelper.cs ├── Images ├── LevelResultInReadme.png ├── banner.png ├── logo.png └── wave.png ├── LICENSE ├── Playground ├── CustomBlockType.cs ├── Playground.csproj └── Program.cs ├── README.md ├── TestObjects ├── AllTypes.cs ├── ComplexParserObjects.cs ├── InheritFieldFrom.cs ├── LargeObject.cs ├── MultipleSense.cs ├── ObjectSample.cs ├── ObjectWithEnum.cs ├── SampleContainer.cs ├── SimpleEnum.cs ├── StructSample.cs ├── TestObjects.csproj └── WithNullable.cs ├── data └── .gitignore └── docs └── colorMapping.txt /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GeometryDashAPI", 3 | "image": "mcr.microsoft.com/devcontainers/base:bullseye", 4 | 5 | "features": { 6 | "ghcr.io/devcontainers/features/dotnet": { 7 | "version": "8.0", 8 | "additionalVersions": "2.2" 9 | } 10 | }, 11 | 12 | "customizations": { 13 | "vscode": { 14 | "extensions": [ 15 | "ms-dotnettools.csdevkit", 16 | "mhutchie.git-graph" 17 | ] 18 | }, 19 | "codespaces": { 20 | "openFiles": [ 21 | "/Playground/Program.cs" 22 | ] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/blank.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Blank 3 | about: Just blank issue 4 | title: '' 5 | labels: '' 6 | assignees: Folleach 7 | 8 | --- 9 | 10 | Write whatever you want ;) 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: Folleach 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Use property '...' 16 | 2. Call function '....' 17 | 3. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Additional context** 23 | Add any other context about the problem here. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: Folleach 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: [ created ] 6 | 7 | jobs: 8 | tests: 9 | runs-on: windows-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Setup .NET 13 | uses: actions/setup-dotnet@v3 14 | with: 15 | dotnet-version: | 16 | 2.2.x 17 | 6.0.x 18 | 8.0.x 19 | - name: Restore dependencies 20 | run: dotnet restore ./GeometryDashAPI.sln 21 | - name: Build 22 | run: dotnet build --no-restore ./GeometryDashAPI.sln 23 | - name: Test 24 | run: dotnet test --no-build --verbosity normal ./GeometryDashAPI.sln 25 | publish: 26 | needs: tests 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v3 30 | - name: Setup .NET 31 | uses: actions/setup-dotnet@v2 32 | with: 33 | dotnet-version: 8.0.x 34 | - name: Set Version 35 | run: echo ${{ github.ref_name }} | sed -r "s/^v/GDAPI_VERSION=/" >> $GITHUB_ENV 36 | - name: Restore dependencies 37 | run: dotnet restore ./GeometryDashAPI.sln 38 | - name: Release build 39 | run: dotnet build -c Release ./GeometryDashAPI/GeometryDashAPI.csproj 40 | - name: Pack 41 | run: dotnet pack -c Release -o ./pack/ /p:PackageVersion=$GDAPI_VERSION ./GeometryDashAPI/GeometryDashAPI.csproj 42 | - name: Push to NuGet 43 | run: dotnet nuget push ./pack/GeometryDashAPI*.nupkg -k ${{secrets.NUGET_API_KEY}} -s https://api.nuget.org/v3/index.json --skip-duplicate 44 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - '**' 7 | pull_request: 8 | branches: 9 | - '**' 10 | 11 | jobs: 12 | tests: 13 | runs-on: windows-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: | 20 | 2.2.x 21 | 6.0.x 22 | 8.0.x 23 | - name: Restore dependencies 24 | run: dotnet restore ./GeometryDashAPI.sln 25 | - name: Build 26 | run: dotnet build --no-restore ./GeometryDashAPI.sln 27 | - name: Test 28 | run: dotnet test --no-build --verbosity normal ./GeometryDashAPI.sln 29 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "playground", 6 | "type": "coreclr", 7 | "preLaunchTask": "dotnet: build", 8 | "request": "launch", 9 | "program": "${workspaceFolder}/Playground/bin/Debug/net8.0/Playground.dll", 10 | "env": { 11 | "DOTNET_WORKING_DIRECTORY": "${workspaceFolder}" 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/Benchmarks/DisassemblyBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using GeometryDashAPI.Serialization; 3 | using TestObjects; 4 | 5 | namespace GeometryDashAPI.Benchmarks.Benchmarks; 6 | 7 | [DisassemblyDiagnoser(maxDepth: 16)] 8 | public class DisassemblyBenchmark 9 | { 10 | [Benchmark] 11 | public ObjectSample CreateByDescriptor() 12 | { 13 | var descriptor = new TypeDescriptor(); 14 | return descriptor.Create("33:2"); 15 | } 16 | } -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/Benchmarks/GDParserBenchmark.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BenchmarkDotNet.Attributes; 3 | using GeometryDashAPI.Serialization; 4 | using TestObjects; 5 | 6 | namespace GeometryDashAPI.Benchmarks.Benchmarks 7 | { 8 | [DisassemblyDiagnoser] 9 | public class GdParserBenchmark 10 | { 11 | private string largeRaw; 12 | private static ObjectSerializer serializer; 13 | 14 | [Params(typeof(ObjectSerializer))] 15 | public Type ParserParam; 16 | 17 | [GlobalSetup] 18 | public void Setup() 19 | { 20 | throw new NotImplementedException(); 21 | // largeRaw = parser.Encode(new LargeObject()); 22 | serializer = (ObjectSerializer)Activator.CreateInstance(ParserParam); 23 | GeometryDashApi.Serializer = serializer; 24 | } 25 | 26 | [Benchmark] 27 | public void Encode() 28 | { 29 | throw new NotImplementedException(); 30 | // parser.Encode(new LargeObject()); 31 | } 32 | 33 | [Benchmark] 34 | public void Decode() 35 | { 36 | serializer.Decode(largeRaw); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/Benchmarks/GameDataBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using GeometryDashAPI.Data; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace GeometryDashAPI.Benchmarks.Benchmarks 10 | { 11 | [MemoryDiagnoser] 12 | public class GameDataBenchmark 13 | { 14 | private GameManager manager; 15 | 16 | [Benchmark] 17 | public void ParseSplit() 18 | { 19 | manager = GameManager.LoadFile(null); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/Benchmarks/LLParserBenchmark.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using BenchmarkDotNet.Attributes; 3 | using GeometryDashAPI.Serialization; 4 | 5 | namespace GeometryDashAPI.Benchmarks.Benchmarks 6 | { 7 | [DisassemblyDiagnoser] 8 | [MemoryDiagnoser] 9 | public class LLParserBenchmark 10 | { 11 | private string input; 12 | private string separator = "."; 13 | 14 | [Params(10000)] 15 | public int ItemsCount; 16 | 17 | [Params(1, 5, 20)] 18 | public int ValueLength; 19 | 20 | [GlobalSetup] 21 | public void SetUp() 22 | { 23 | input = string.Join(separator, Enumerable.Range(0, ItemsCount).Select(x => new string('x', ValueLength))); 24 | } 25 | 26 | [Benchmark] 27 | public void LLParserSpan_EnumerateValues() 28 | { 29 | var parser = new LLParserSpan(separator, input); 30 | while (true) 31 | { 32 | var token = parser.Next(); 33 | if (token == null) 34 | break; 35 | } 36 | } 37 | 38 | [Benchmark] 39 | public void Split_EnumerateValues() 40 | { 41 | foreach (var token in input.Split(separator)) 42 | { 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/Benchmarks/LevelLoadBenchmark.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Net; 3 | using BenchmarkDotNet.Attributes; 4 | using GeometryDashAPI.Levels; 5 | using GeometryDashAPI.Serialization; 6 | using GeometryDashAPI.Server; 7 | using GeometryDashAPI.Server.Responses; 8 | 9 | namespace GeometryDashAPI.Benchmarks.Benchmarks 10 | { 11 | [DisassemblyDiagnoser] 12 | [MemoryDiagnoser] 13 | public class LevelLoadBenchmark 14 | { 15 | private string levelRaw; 16 | 17 | [GlobalSetup] 18 | public void SetUp() 19 | { 20 | levelRaw = File.ReadAllText(@"C:\Users\Andrey\Documents\GitHub\GeometryDashAPI\cromulent.txt"); 21 | Level.Serializer = new ObjectSerializer(); 22 | } 23 | 24 | [Benchmark] 25 | public Level LoadNew() 26 | { 27 | var response = new ServerResponse(HttpStatusCode.OK, levelRaw); 28 | return new Level(response.GetResultOrDefault().Level.LevelString, true); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/Benchmarks/ObjectParserBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using GeometryDashAPI.Serialization; 3 | 4 | namespace GeometryDashAPI.Benchmarks.Benchmarks; 5 | 6 | [DisassemblyDiagnoser] 7 | [MemoryDiagnoser] 8 | public class ObjectParserBenchmark 9 | { 10 | private static IGameSerializer serializer = new ObjectSerializer(); 11 | 12 | [Benchmark] 13 | public int[] GetArray() 14 | { 15 | return serializer.GetArray("33,1,33,2,33,3,33,4,33,5,33,6,33,7,33,8,33,9", ",", Parsers.GetOrDefault_Int32__); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/GeometryDashAPI.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /GeometryDashAPI.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Running; 4 | 5 | BenchmarkSwitcher.FromAssembly(Assembly.GetAssembly(typeof(Program))).Run(args, 6 | ManualConfig.Create(DefaultConfig.Instance) 7 | .With(ConfigOptions.DisableOptimizationsValidator)); 8 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/BlockParseTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | using GeometryDashAPI.Serialization; 4 | using NUnit.Framework; 5 | 6 | namespace GeometryDashAPI.Tests; 7 | 8 | [TestFixture] 9 | public class BlockParseTest 10 | { 11 | private IGameSerializer serializer = new ObjectSerializer(); 12 | 13 | [Test] 14 | public void DecodeBlock_BaseBlock() 15 | { 16 | var input = "1,1,2,3,3,6"; 17 | 18 | var actual = (Block)serializer.DecodeBlock(input.AsSpan()); 19 | 20 | Assert.AreEqual(1, actual.Id); 21 | Assert.AreEqual(3, actual.PositionX); 22 | Assert.AreEqual(6, actual.PositionY); 23 | } 24 | 25 | [Test] 26 | public void EncodeBlock_BaseBlock() 27 | { 28 | var input = new BaseBlock(1) 29 | { 30 | PositionX = 44, 31 | PositionY = 77 32 | }; 33 | var expected = "1,1,2,44,3,77"; 34 | 35 | var actual = serializer.Encode(input).ToString(); 36 | 37 | Assert.AreEqual(expected, actual); 38 | } 39 | 40 | [Test] 41 | public void DecodeBlock_FullBaseBlock() 42 | { 43 | var input = "1,1,2,713,3,97,96,1,20,6,61,6,103,1,57,5.7.12,64,1,67,1,25,8,6,-90,21,9,24,-1,32,1.17,34,1,41,1,43,72a0.48a-0.64a1a1"; 44 | 45 | var decoded = serializer.DecodeBlock(input.AsSpan()); 46 | 47 | Assert.Pass("ok"); 48 | } 49 | } -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/BlockTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using GeometryDashAPI.Levels.GameObjects.Triggers; 4 | using GeometryDashAPI.Serialization; 5 | using NUnit.Framework; 6 | 7 | namespace GeometryDashAPI.Tests; 8 | 9 | [TestFixture] 10 | public class BlockTests 11 | { 12 | [Test] 13 | public void TouchTrigger_MultiTrigger_ShouldReturnTrueAfterSet() 14 | { 15 | var trigger = new TouchTrigger(); 16 | var descriptor = new TypeDescriptor(); 17 | 18 | trigger.MultiTrigger = true; 19 | 20 | trigger.MultiTrigger.Should().Be(true); 21 | 22 | var raw = descriptor.AsString(trigger); 23 | raw.Should().NotContain("87"); 24 | } 25 | 26 | [Test] 27 | public void TouchTrigger_MultiTrigger_ShouldReturnFalseAfterSet() 28 | { 29 | var trigger = new TouchTrigger(); 30 | var descriptor = new TypeDescriptor(); 31 | 32 | trigger.MultiTrigger = false; 33 | 34 | trigger.MultiTrigger.Should().Be(false); 35 | 36 | var raw = descriptor.AsString(trigger); 37 | raw.Should().Contain("87,1"); 38 | } 39 | 40 | [Test] 41 | public void TouchTrigger_MultiTrigger_ShouldTrueIfNotSet() 42 | { 43 | var raw = "1,999,2,0,3,0"; 44 | var descriptor = new TypeDescriptor(); 45 | 46 | var trigger = descriptor.Create(raw.AsSpan()); 47 | 48 | trigger.MultiTrigger.Should().BeTrue(); 49 | } 50 | 51 | [Test] 52 | public void TouchTrigger_MultiTrigger_ShouldTrueIfSetToZero() 53 | { 54 | var raw = "1,999,2,0,3,0,87,0"; 55 | var descriptor = new TypeDescriptor(); 56 | 57 | var trigger = descriptor.Create(raw.AsSpan()); 58 | 59 | trigger.MultiTrigger.Should().BeTrue(); 60 | } 61 | 62 | [Test] 63 | public void TouchTrigger_MultiTrigger_ShouldFalseIfSet() 64 | { 65 | var raw = "1,999,2,0,3,0,87,1"; 66 | var descriptor = new TypeDescriptor(); 67 | 68 | var trigger = descriptor.Create(raw.AsSpan()); 69 | 70 | trigger.MultiTrigger.Should().BeFalse(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/Documentation/BlocksDocumentation.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Levels.GameObjects; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using GeometryDashAPI.Attributes; 10 | 11 | namespace GeometryDashAPI.Tests.Documentation 12 | { 13 | public class BlocksDocumentation 14 | { 15 | private static readonly Type ObjectType = typeof(object); 16 | private static readonly string LineBreak = new string('-', 16); 17 | 18 | public bool IncludeBaseTypes = false; 19 | public bool TitleIsFullName = false; 20 | public bool ShowProperties = true; 21 | 22 | public void WriteAllSupportedBlockTo(Assembly fromAssembly, TextWriter writer) 23 | { 24 | Type blockInterface = typeof(IBlock); 25 | var blocks = fromAssembly.GetTypes().Where(type => type.GetInterfaces().Contains(blockInterface)); 26 | foreach (var item in blocks) 27 | { 28 | writer.WriteLine(TitleIsFullName ? item.FullName : item.Name); 29 | if (ShowProperties) 30 | { 31 | writer.WriteLine($"\tid\tdefault\talways\tname"); 32 | PropertyWrite(item, writer); 33 | } 34 | } 35 | } 36 | 37 | public void PropertyWrite(Type type, TextWriter writer) 38 | { 39 | PropertyInfo[] properties = type.GetProperties(); 40 | if (!IncludeBaseTypes) 41 | properties = properties.Where(x => x.DeclaringType == type).ToArray(); 42 | foreach (var property in properties) 43 | { 44 | GamePropertyAttribute defaultProperty = property.GetCustomAttribute(); 45 | if (defaultProperty != null) 46 | writer.Write($"\t{defaultProperty.Key}\t{defaultProperty.DefaultValue?.ToString() ?? "null"}\t{defaultProperty.AlwaysSet}"); 47 | else 48 | writer.Write($"ALERT!\t\t\t"); 49 | writer.WriteLine($"\t{property.Name}"); 50 | } 51 | writer.WriteLine(LineBreak); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/GameConvertTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace GeometryDashAPI.Tests 5 | { 6 | [TestFixture] 7 | public class GameConvertTest 8 | { 9 | [TestCase("1", true, false)] 10 | [TestCase("0", false, false)] 11 | [TestCase("0", true, true)] 12 | [TestCase("1", false, true)] 13 | public void BoolToString(string expected, bool value, bool isReverse) 14 | { 15 | Assert.AreEqual(expected, GameConvert.BoolToString(value, isReverse)); 16 | } 17 | 18 | [TestCase(true, "1", false)] 19 | [TestCase(false, "0", false)] 20 | [TestCase(false, "1", true)] 21 | [TestCase(true, "0", true)] 22 | public void StringToBool(bool expected, string value, bool isReverse) 23 | { 24 | Assert.AreEqual(expected, GameConvert.StringToBool(value, isReverse)); 25 | } 26 | 27 | [TestCase(true, "1", false)] 28 | [TestCase(false, "0", false)] 29 | [TestCase(false, "1", true)] 30 | [TestCase(true, "0", true)] 31 | public void StringToBool_Span(bool expected, string value, bool isReverse) 32 | { 33 | Assert.AreEqual(expected, GameConvert.StringToBool(value.AsSpan(), isReverse)); 34 | } 35 | 36 | [TestCase("1", 1f)] 37 | [TestCase("1.33", 1.33f)] 38 | public void SingleToString(string expected, float value) 39 | { 40 | Assert.AreEqual(expected, GameConvert.SingleToString(value)); 41 | } 42 | 43 | [TestCase(1f, "1")] 44 | [TestCase(1.33f, "1.33")] 45 | public void StringToSingle(float expected, string value) 46 | { 47 | Assert.AreEqual(expected, GameConvert.StringToSingle(value.AsSpan())); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/GameResourcesTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using FluentAssertions; 4 | using GeometryDashAPI.Data; 5 | using GeometryDashAPI.Levels; 6 | using NUnit.Framework; 7 | 8 | namespace GeometryDashAPI.Tests; 9 | 10 | [TestFixture(Explicit = true, Reason = "it needs a game resources")] 11 | public class GameResourcesTests 12 | { 13 | private const string ResourcesDataPathEnv = "GDAPI_TESTS_RESOURCES"; 14 | 15 | private string path; 16 | 17 | [SetUp] 18 | public void SetUp() 19 | { 20 | path = Environment.GetEnvironmentVariable(ResourcesDataPathEnv) 21 | ?? Environment.GetEnvironmentVariable(ResourcesDataPathEnv, EnvironmentVariableTarget.User); 22 | if (path == null) 23 | throw new InvalidOperationException($"Please set env variable '{ResourcesDataPathEnv}' pointing to the game resource files"); 24 | } 25 | 26 | [TestCase(OfficialLevel.StereoMadness)] 27 | [TestCase(OfficialLevel.BackOnTrack)] 28 | [TestCase(OfficialLevel.Polargeist)] 29 | [TestCase(OfficialLevel.DryOut)] 30 | [TestCase(OfficialLevel.BaseAfterBase)] 31 | [TestCase(OfficialLevel.CantLetGo)] 32 | [TestCase(OfficialLevel.Jumper)] 33 | [TestCase(OfficialLevel.TimeMachine)] 34 | [TestCase(OfficialLevel.Cycles)] 35 | [TestCase(OfficialLevel.xStep)] 36 | [TestCase(OfficialLevel.Clutterfunk)] 37 | [TestCase(OfficialLevel.TheoryOfEverything)] 38 | [TestCase(OfficialLevel.ElectromanAdventures)] 39 | [TestCase(OfficialLevel.Clubstep)] 40 | [TestCase(OfficialLevel.Electrodynamix)] 41 | [TestCase(OfficialLevel.HexagonForce)] 42 | [TestCase(OfficialLevel.BlastProcessing)] 43 | [TestCase(OfficialLevel.TheoryOfEverything2)] 44 | [TestCase(OfficialLevel.GeometricalDominator)] 45 | [TestCase(OfficialLevel.Deadlocked)] 46 | [TestCase(OfficialLevel.Fingerdash)] 47 | 48 | [TestCase(OfficialLevel.TheChallenge)] 49 | 50 | // meltdown levels is not supported, we have problems with unzipping 51 | // [TestCase(OfficialLevel.TheSevenSeas)] 52 | // [TestCase(OfficialLevel.VikingArena)] 53 | // [TestCase(OfficialLevel.AirborneRobots)] 54 | 55 | [TestCase(OfficialLevel.Payload)] 56 | [TestCase(OfficialLevel.BeastMode)] 57 | [TestCase(OfficialLevel.Machina)] 58 | [TestCase(OfficialLevel.Years)] 59 | [TestCase(OfficialLevel.Frontlines)] 60 | [TestCase(OfficialLevel.SpacePirates)] 61 | [TestCase(OfficialLevel.Striker)] 62 | [TestCase(OfficialLevel.Embers)] 63 | [TestCase(OfficialLevel.Round1)] 64 | [TestCase(OfficialLevel.MonsterDanceOff)] 65 | public async Task GetLevel_ShouldParseCorrect(OfficialLevel officialLevel) 66 | { 67 | var resources = new GameResources(path); 68 | 69 | Level level = null; 70 | Assert.DoesNotThrow(() => level = resources.GetLevelAsync(officialLevel).GetAwaiter().GetResult()); 71 | 72 | level.Should().NotBeNull(); 73 | level.Blocks.Should().HaveCountGreaterThan(0); 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/GameServerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Threading.Tasks; 3 | using FluentAssertions; 4 | using GeometryDashAPI.Server; 5 | using GeometryDashAPI.Server.Enums; 6 | using GeometryDashAPI.Server.Queries; 7 | using NUnit.Framework; 8 | 9 | namespace GeometryDashAPI.Tests; 10 | 11 | [TestFixture(Explicit = true, Reason = "Geometry Dash does not allow to do request from github action workers")] 12 | public class GameServerTests 13 | { 14 | [Test] 15 | public async Task GetFeatured() 16 | { 17 | var server = new GameClient(); 18 | var response = await server.SearchLevelsAsync(new GetLevelsQuery(SearchType.Featured)); 19 | var result = response.GetResultOrDefault(); 20 | 21 | response.HttpStatusCode.Should().Be(HttpStatusCode.OK); 22 | result.Should().NotBeNull(); 23 | result.Page.TotalCount.Should().BeGreaterThan(28000); // approximate number of featured levels 24 | result.Page.CountOnPage.Should().Be(10); 25 | result.Page.RangeIn.Should().Be(0); 26 | result.Page.RangeOut.Should().Be(10); 27 | result.Levels.Count.Should().Be(10); 28 | result.WithoutLoaded.Should().HaveCount(0); 29 | } 30 | 31 | [Test] 32 | public async Task SearchAccount() 33 | { 34 | var server = new GameClient(); 35 | var response = await server.SearchUserAsync("Folleach"); 36 | var result = response.GetResultOrDefault(); 37 | 38 | response.HttpStatusCode.Should().Be(HttpStatusCode.OK); 39 | result.Should().NotBeNull(); 40 | result.User.Name.Should().Be("Folleach"); 41 | result.WithoutLoaded.Should().HaveCount(0); 42 | result.User.WithoutLoaded.Should().HaveCount(0); 43 | 44 | var accountResponse = await server.GetAccountAsync(result.User.AccountId); 45 | var accountResult = accountResponse.GetResultOrDefault(); 46 | 47 | accountResponse.HttpStatusCode.Should().Be(HttpStatusCode.OK); 48 | accountResult.Should().NotBeNull(); 49 | accountResult.Account.AccountId.Should().Be(result.User.AccountId); 50 | accountResult.Account.Name.Should().Be(result.User.Name); 51 | accountResult.WithoutLoaded.Should().HaveCount(0); 52 | accountResult.Account.WithoutLoaded.Should().HaveCount(0); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/GeometryDashAPI.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Library 5 | netcoreapp2.2;net8.0;net48 6 | latest 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | PreserveNewest 41 | 42 | 43 | PreserveNewest 44 | 45 | 46 | PreserveNewest 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/GuidelinesTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using GeometryDashAPI.Levels; 4 | using GeometryDashAPI.Levels.Enums; 5 | using NUnit.Framework; 6 | 7 | namespace GeometryDashAPI.Tests 8 | { 9 | [TestFixture] 10 | public class GuidelinesTest 11 | { 12 | [Test] 13 | public void DecodeGuidelines() 14 | { 15 | var input = "1.000~0.9~1.255~1~4.525~0.8~6.665~0~"; 16 | 17 | Guidelines actual = Guidelines.Parse(input.AsSpan()); 18 | 19 | actual.Should().BeEquivalentTo(new Guidelines() 20 | { 21 | new Guideline() 22 | { 23 | Timestamp = 1.000, 24 | Color = GuidelineColor.Yellow 25 | }, 26 | new Guideline() 27 | { 28 | Timestamp = 1.255, 29 | Color = GuidelineColor.Green 30 | }, 31 | new Guideline() 32 | { 33 | Timestamp = 4.525, 34 | Color = GuidelineColor.Orange 35 | }, 36 | new Guideline() 37 | { 38 | Timestamp = 6.665, 39 | Color = GuidelineColor.Orange 40 | }, 41 | }); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/Integration/Levels/LevelResponseDefinedTest.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using NUnit.Framework; 3 | 4 | namespace GeometryDashAPI.Tests.Integration.Levels; 5 | 6 | [TestFixture(Explicit = true, Reason = "too sensitive")] 7 | public class LevelResponseDefinedTest : LevelResponseTestBase 8 | { 9 | [TestCase("12034598_Conclusion")] 10 | [TestCase("28755513_TheFinalLair")] 11 | [TestCase("116631_XmasParty")] 12 | public void LoadAndSaveLevel(string fileName) 13 | { 14 | var responseBody = File.ReadAllText(Path.Combine("data", "levels", fileName)); 15 | Test(responseBody); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/Integration/Levels/LevelResponseFromStreamTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using NUnit.Framework; 6 | 7 | namespace GeometryDashAPI.Tests.Integration.Levels; 8 | 9 | [TestFixture(Explicit = true, Reason = "use a lot of levels to compare compability with Geometry Dash")] 10 | [Category("Integration")] 11 | [Parallelizable(ParallelScope.All)] 12 | public class LevelResponseFromStreamTest : LevelResponseTestBase 13 | { 14 | private const string ProcessDataPathEnv = "GDAPI_TESTS_CONTENTS"; 15 | private const string ProcessLevelcontentFilename = "levels"; 16 | 17 | public static IEnumerable Source 18 | = File.ReadLines( 19 | Path.Combine( 20 | GetContentPath(), 21 | ProcessLevelcontentFilename) 22 | ) 23 | .Select(x => new TestCaseData(x) 24 | { 25 | TestName = x.Substring(0, 30) 26 | }); 27 | 28 | private static string GetContentPath() 29 | => Environment.GetEnvironmentVariable(ProcessDataPathEnv) 30 | ?? Environment.GetEnvironmentVariable(ProcessDataPathEnv, EnvironmentVariableTarget.User) 31 | ?? throw new InvalidOperationException($"'{ProcessDataPathEnv}' is not set"); 32 | 33 | [TestCaseSource(nameof(Source))] 34 | public void LoadAndSaveLevel(string responseBody) 35 | { 36 | Test(responseBody); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/LLParserTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FluentAssertions; 4 | using GeometryDashAPI.Serialization; 5 | using NUnit.Framework; 6 | 7 | namespace GeometryDashAPI.Tests 8 | { 9 | [TestFixture] 10 | public class LLParserTests 11 | { 12 | [TestCase("", 0)] 13 | [TestCase("abc", 1)] 14 | [TestCase("1.1", 2)] 15 | [TestCase("1.2.3.4", 4)] 16 | [TestCase("1.2.3.", 3)] 17 | [TestCase("..", 2)] 18 | public void Next_CallNumbers(string input, int expectedCallNumber) 19 | { 20 | var parser = new LLParserSpan(".".AsSpan(), input.AsSpan()); 21 | 22 | var calls = 0; 23 | while (parser.Next() != null) 24 | calls++; 25 | 26 | Assert.AreEqual(expectedCallNumber, calls); 27 | } 28 | 29 | [TestCase("")] 30 | [TestCase(".", "")] 31 | [TestCase("1", "1")] 32 | [TestCase("1.2", "1", "2")] 33 | public void Next_ValidResult(string input, params string[] expected) 34 | { 35 | var parser = new LLParserSpan(".".AsSpan(), input.AsSpan()); 36 | 37 | var result = new List(); 38 | 39 | ReadOnlySpan next = null; 40 | while ((next = parser.Next()) != null) 41 | result.Add(next.ToString()); 42 | 43 | Assert.AreEqual(expected.Length, result.Count); 44 | result.ToArray().Should().Equal(expected); 45 | } 46 | 47 | [TestCase("", 0)] 48 | [TestCase(".", 1)] 49 | [TestCase("a.", 1)] 50 | [TestCase("a.a", 2)] 51 | [TestCase("..", 2)] 52 | [TestCase("a.a.a", 3)] 53 | [TestCase(".a.a", 3)] 54 | [TestCase("a.a.", 2)] 55 | [TestCase("a...", 3)] 56 | public void CountOfSense(string input, int expected) 57 | { 58 | var parser = new LLParserSpan(".".AsSpan(), input.AsSpan()); 59 | 60 | var actual = parser.GetCountOfValues(); 61 | 62 | Assert.AreEqual(expected, actual); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/LevelDurationTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Net; 3 | using FluentAssertions; 4 | using GeometryDashAPI.Levels; 5 | using GeometryDashAPI.Server; 6 | using GeometryDashAPI.Server.Responses; 7 | using NUnit.Framework; 8 | 9 | namespace GeometryDashAPI.Tests; 10 | 11 | [TestFixture] 12 | public class LevelDurationTests 13 | { 14 | [TestCase("12034598_Conclusion", 57)] 15 | [TestCase("28755513_TheFinalLair", 154)] 16 | [TestCase("116631_XmasParty", 87)] 17 | public void Test(string fileName, int expectedSeconds) 18 | { 19 | var responseBody = File.ReadAllText(Path.Combine("data", "levels", fileName)); 20 | var response = new ServerResponse(HttpStatusCode.OK, responseBody); 21 | var level = new Level(response.GetResultOrDefault().Level.LevelString, compressed: true); 22 | level.Duration.TotalSeconds.Should().BeApproximately(expectedSeconds, precision: 1); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/MessageTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using FluentAssertions; 3 | using GeometryDashAPI.Server.Dtos; 4 | using NUnit.Framework; 5 | 6 | namespace GeometryDashAPI.Tests; 7 | 8 | [TestFixture] 9 | public class MessageTests 10 | { 11 | [Test] 12 | public void DecryptMessage() 13 | { 14 | var message = Message.FromRaw("SGVsbG8sIGl0J3MgbGlicmFyeSB0ZXN0IHRpbWU=", "eBNEUBFbQUFBEUddV0IRX1FGQl5DXxJFUFJfV0FCHRRWWl8WQBJeVFREEkxeRBRfXF9V"); 15 | 16 | message.Should().BeEquivalentTo(new Message() 17 | { 18 | Subject = "Hello, it's library test time", 19 | Body = "I've just view network packets, don't keep you mind" 20 | }); 21 | } 22 | 23 | [Test] 24 | public void EncryptMessage() 25 | { 26 | var message = new Message() 27 | { 28 | Subject = "Hello, it's library test time", 29 | Body = "I've just view network packets, don't keep you mind" 30 | }; 31 | 32 | var parameters = message.BuildQuery(); 33 | 34 | parameters.FirstOrDefault(x => x.Key == "subject").Value.Should().BeEquivalentTo("SGVsbG8sIGl0J3MgbGlicmFyeSB0ZXN0IHRpbWU="); 35 | parameters.FirstOrDefault(x => x.Key == "body").Value.Should().BeEquivalentTo("eBNEUBFbQUFBEUddV0IRX1FGQl5DXxJFUFJfV0FCHRRWWl8WQBJeVFREEkxeRBRfXF9V"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/PaginationTests.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Server; 2 | using NUnit.Framework; 3 | 4 | namespace GeometryDashAPI.Tests 5 | { 6 | [TestFixture] 7 | public class PaginationTests 8 | { 9 | [TestCase(1, 0, 10, 0, true)] 10 | [TestCase(1, 0, 10, 1, false)] 11 | 12 | [TestCase(10, 0, 10, 0, true)] 13 | [TestCase(10, 0, 10, 1, false)] 14 | 15 | [TestCase(7, 0, 5, 0, true)] 16 | [TestCase(7, 0, 5, 1, true)] 17 | [TestCase(7, 0, 5, 2, false)] 18 | 19 | [TestCase(3, 0, 10, 0, true)] 20 | [TestCase(20, 10, 20, 1, true)] 21 | [TestCase(20, 10, 20, 2, false)] 22 | [TestCase(0, 0, 0, 0, false)] 23 | public void Pagination_HasPage(int total, int rangeIn, int rangeOut, int page, bool has) 24 | { 25 | Assert.AreEqual(has, new Pagination(total, rangeIn, rangeOut).HasPage(page)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/Sources.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Tests 2 | { 3 | public static class Sources 4 | { 5 | public static string GetLevelOptions() 6 | { 7 | return 8 | "kS38,1_0_2_102_3_255_11_255_12_255_13_255_4_-1_6_1000_5_1_7_1_15_1_18_0_8_1|1_0_2_0_3_0_11_255_12_255_13_255_4_-1_6_1001_7_1_15_1_18_0_8_1|1_0_2_102_3_255_11_255_12_255_13_255_4_-1_6_1009_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_1002_5_1_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_1005_5_1_7_1_15_1_18_0_8_1|1_135_2_135_3_135_11_255_12_255_13_255_4_-1_6_1006_5_1_7_1_15_1_18_0_8_1|1_255_2_216_3_73_11_255_12_255_13_255_4_-1_6_7_5_1_7_1_15_1_18_0_8_1|1_193_2_46_3_46_11_255_12_255_13_255_4_-1_6_2_5_1_7_1_15_1_18_0_8_1|1_0_2_0_3_0_11_255_12_255_13_255_4_-1_6_6_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_3_7_0.35_15_1_18_0_8_1|1_187_2_82_3_26_11_255_12_255_13_255_4_-1_6_4_7_1_15_1_18_0_8_1|1_0_2_0_3_0_11_255_12_255_13_255_4_-1_6_8_7_0.3_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_9_5_1_7_1_15_1_18_0_8_1|1_0_2_62_3_255_11_255_12_255_13_255_4_-1_6_10_5_1_7_1_15_1_18_0_8_1|1_9_2_214_3_255_11_255_12_255_13_255_4_-1_6_11_5_1_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_12_5_1_7_1_15_1_18_0_8_1|1_0_2_0_3_0_11_255_12_255_13_255_4_-1_6_13_7_0.5_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_5_7_0.62_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_14_7_0.41_15_1_18_0_8_1|1_0_2_255_3_10_11_255_12_255_13_255_4_-1_6_15_7_1_15_1_18_0_8_1|1_153_2_255_3_44_11_255_12_255_13_255_4_-1_6_16_7_1_15_1_18_0_8_1|1_255_2_192_3_0_11_255_12_255_13_255_4_-1_6_17_7_1_15_1_18_0_8_1|1_255_2_167_3_0_11_255_12_255_13_255_4_-1_6_18_7_1_15_1_18_0_8_1|1_193_2_46_3_46_11_255_12_255_13_255_4_-1_6_19_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_1003_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_1004_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_1010_7_1_15_1_18_0_8_1|,kA13,85.8,kA15,0,kA16,0,kA14,,kA6,0,kA7,0,kA17,0,kA18,0,kS39,0,kA2,0,kA3,0,kA8,0,kA4,0,kA9,0,kA10,0,kA11,0"; 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/StructParserTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using GeometryDashAPI.Serialization; 4 | using NUnit.Framework; 5 | using TestObjects; 6 | 7 | namespace GeometryDashAPI.Tests; 8 | 9 | [TestFixture] 10 | public class StructParserTests 11 | { 12 | private static ObjectSerializer serializer = new(); 13 | 14 | [Test] 15 | public void Decode_SampleStruct_ShouldBeCorrect() 16 | { 17 | var input = "33:1~8:444"; 18 | 19 | var actual = serializer.Decode(input.AsSpan()); 20 | 21 | var expected = new StructSample() 22 | { 23 | FirstObject = new ObjectSample() 24 | { 25 | X = 1 26 | }, 27 | SecondObject = new LargeObject() 28 | { 29 | x8 = 444 30 | } 31 | }; 32 | 33 | actual.Should().BeEquivalentTo(expected); 34 | } 35 | 36 | [Test] 37 | public void Decode_ComplexParserObject_ShouldBeCorrect() 38 | { 39 | var input = ComplexParserObject.ExampleInput; 40 | var expected = ComplexParserObject.ExampleExpected; 41 | 42 | var actual = serializer.Decode(input.AsSpan()); 43 | 44 | actual.Should().BeEquivalentTo(expected); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/TestExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Tests; 2 | 3 | public static class TestExtensions 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/data/saves/CCGameManager1.dat: -------------------------------------------------------------------------------- 1 | C?xBJJJJJJJJH8\\R\&iFIHLT;z^\N|NgheIlQA9}TTRHZA_=A[Es[?h=m[fY{B8by__yQ}eisTQY;T\}~&_JiZQ{M><{nHbACGXfQEXM=\sb|iDx^CldzNT^f@F_^RjLo_{giC]x}2rTz]gSyneRIiii:oXeChx?L{8z}zhi>hTALMD2FTQgTe?3fhllA^N{bD~TBBZd{OMJ`lYINMLXsOHhe}R=&9hsGf}|QlzMT]YnQ2]e>]3c:}eFAaBRYi?@{rH}EHjjm|\==g\3`iSd9}M^m{AH@aIB:Q9eMbylY]=2<_QxIBe]@rYXy[zh[mJo|OxIyN~|jJB3lLDJCJq|HyIM\M}|xsNbdoH}XT[E?gGQ|}T2=n9&qidzTG{8Gf33TSHL=?c9_2sdmX^d|lJJJ66 -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/data/saves/CCGameManagerEmpty.dat: -------------------------------------------------------------------------------- 1 | C?xBJJJJJJJJH8\\S9&iFI_M};z^2|9~OZZ`Xy\DiQz=iE[Z3cdY?bX^[;j9`D?z;~{oGd?}}_=R^e=T>E?SsRzbj}``oe2xsRs;_x]O;m?[Lro]9SaNJfNOr{fHaAGOXgQ]XL=\caSy\xQ>eddq}&Eq\}@l9&[^}eFNxqgGs>xm~cY^z|\^YHLF~rqe9oTqj]fQTIrI>e?\E8@qfd3>S]E;zss{{G{_]&F]88D>`SifmSb~9[}@jHqAQ]A&gIFxyn|j\z2De|?N]~@IlCYn@<_3^{>Ao\FEjAnT8OE3?e~Jj|In`&O^JClN|ZJTLDJYRB||z~IeB]yQo_{3GT{eTTq;C=Y]grm&A&[hQ9GzyTHY;E8i2xhTL9~]8yiD&D}l~Z}ezy3qqBBJJJ6 o -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/data/saves/CCLocalLevels1.dat: -------------------------------------------------------------------------------- 1 | C?xBJJJJJJJJH9\_i\&bZIHJT?ys&>SoQS`sZYz@n@sB_r&\J&q@AO&zR_yyae\xS|qYf?dAd2Dab9oB9b]cL[~lhx&&?Rl}|mFj>XJoI^OCmLCc?=M=x`x8\ADM?S}I:aiG9My^rSjT;j>}m9ByJ>{a_@}RDF>[GcN9=&olQh[ZLTjLCh2Hy_CYizlIcsOO[FLQRRMc`\LARQeaN:}DaZGQH9H&Yn<2moI2Zm3Ohi]f?oze^T3YX|L{sJ|JJ -------------------------------------------------------------------------------- /GeometryDashAPI.Tests/data/saves/CCLocalLevelsEmpty.dat: -------------------------------------------------------------------------------- 1 | C?xBJJJJJJJJH{hd=E}Q=@mJ]YfIY_[aN:2OEIFfJa2FM\9ZNJfBLIr?hJJJJ6 -------------------------------------------------------------------------------- /GeometryDashAPI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29215.179 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeometryDashAPI", "GeometryDashAPI\GeometryDashAPI.csproj", "{E1137CDE-1E78-4763-A7EB-0588188AC462}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeometryDashAPI.Tests", "GeometryDashAPI.Tests\GeometryDashAPI.Tests.csproj", "{ADD42DF9-2846-451D-90B4-F7DD82CE1195}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeometryDashAPI.Benchmarks", "GeometryDashAPI.Benchmarks\GeometryDashAPI.Benchmarks.csproj", "{E574D681-F12C-4DED-9691-C4CA82CB69AA}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestObjects", "TestObjects\TestObjects.csproj", "{7DF2D7F7-7348-43F1-A1B2-431942FBB797}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Playground", "Playground\Playground.csproj", "{D3012AD9-9E1F-4ED7-9162-940E85EAE908}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {E1137CDE-1E78-4763-A7EB-0588188AC462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {E1137CDE-1E78-4763-A7EB-0588188AC462}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {E1137CDE-1E78-4763-A7EB-0588188AC462}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {E1137CDE-1E78-4763-A7EB-0588188AC462}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {ADD42DF9-2846-451D-90B4-F7DD82CE1195}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {ADD42DF9-2846-451D-90B4-F7DD82CE1195}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {ADD42DF9-2846-451D-90B4-F7DD82CE1195}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {ADD42DF9-2846-451D-90B4-F7DD82CE1195}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {E574D681-F12C-4DED-9691-C4CA82CB69AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {E574D681-F12C-4DED-9691-C4CA82CB69AA}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {E574D681-F12C-4DED-9691-C4CA82CB69AA}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {E574D681-F12C-4DED-9691-C4CA82CB69AA}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {7DF2D7F7-7348-43F1-A1B2-431942FBB797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {7DF2D7F7-7348-43F1-A1B2-431942FBB797}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {7DF2D7F7-7348-43F1-A1B2-431942FBB797}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {7DF2D7F7-7348-43F1-A1B2-431942FBB797}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {D3012AD9-9E1F-4ED7-9162-940E85EAE908}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {D3012AD9-9E1F-4ED7-9162-940E85EAE908}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {D3012AD9-9E1F-4ED7-9162-940E85EAE908}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {D3012AD9-9E1F-4ED7-9162-940E85EAE908}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {C03FE77C-C5B9-424F-9850-847678DDB335} 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /GeometryDashAPI.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True -------------------------------------------------------------------------------- /GeometryDashAPI/Attributes/ArraySeparatorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Attributes 4 | { 5 | public class ArraySeparatorAttribute : Attribute 6 | { 7 | public readonly string Separator; 8 | public bool SeparatorAtTheEnd { get; set; } 9 | 10 | public ArraySeparatorAttribute(string separator) 11 | { 12 | Separator = separator; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /GeometryDashAPI/Attributes/AsStructAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Attributes 4 | { 5 | public class AsStructAttribute : Attribute 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /GeometryDashAPI/Attributes/GamePropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 6 | public class GamePropertyAttribute : Attribute 7 | { 8 | public string Key { get; } 9 | public object? DefaultValue { get; } 10 | public bool AlwaysSet { get; } 11 | public int KeyOverride { get; set; } 12 | public int Order { get; set; } = int.MaxValue; 13 | 14 | public GamePropertyAttribute(string key, object? defaultValue = null, bool alwaysSet = false) 15 | { 16 | Key = key; 17 | DefaultValue = defaultValue; 18 | AlwaysSet = alwaysSet; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /GeometryDashAPI/Attributes/OriginalNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Attributes 4 | { 5 | public class OriginalNameAttribute : Attribute 6 | { 7 | public string OriginalName { get; set; } 8 | 9 | public OriginalNameAttribute(string originalName) 10 | { 11 | OriginalName = originalName; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /GeometryDashAPI/Attributes/SenseAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Attributes 4 | { 5 | public class SenseAttribute : Attribute 6 | { 7 | public readonly string Sense; 8 | 9 | public SenseAttribute(string sense) 10 | { 11 | Sense = sense; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /GeometryDashAPI/Culture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace GeometryDashAPI 5 | { 6 | public static class Culture 7 | { 8 | private static CultureInfo cultureInfo; 9 | 10 | static Culture() 11 | { 12 | cultureInfo = (CultureInfo)CultureInfo.InvariantCulture.Clone(); 13 | cultureInfo.NumberFormat.CurrencyDecimalSeparator = "."; 14 | cultureInfo.NumberFormat.NumberDecimalSeparator = "."; 15 | } 16 | 17 | public static IFormatProvider FormatProvider 18 | { 19 | get => cultureInfo; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /GeometryDashAPI/Data/DatFileFormat.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Data; 2 | 3 | public enum DatFileFormat 4 | { 5 | Windows, 6 | Mac 7 | } 8 | -------------------------------------------------------------------------------- /GeometryDashAPI/Data/Enums/GameDataType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Data.Enums 2 | { 3 | public enum GameDataType : byte 4 | { 5 | GameManager, LocalLevels 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /GeometryDashAPI/Data/Enums/TextureQuality.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Data.Enums 2 | { 3 | public enum TextureQuality : byte 4 | { 5 | Auto, 6 | Low, 7 | Medium, 8 | High 9 | } 10 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Data/GameResources.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using GeometryDashAPI.Levels; 7 | using GeometryDashAPI.Serialization; 8 | 9 | namespace GeometryDashAPI.Data; 10 | 11 | public class GameResources 12 | { 13 | private readonly string path; 14 | private Dictionary levels = new(); 15 | 16 | public GameResources(string path) 17 | { 18 | this.path = path; 19 | } 20 | 21 | public async Task GetLevelAsync(OfficialLevel officialLevel) 22 | { 23 | var gameType = officialLevel.GetGameType(); 24 | if (gameType == GameType.Meltdown) 25 | throw new InvalidEnumArgumentException("meltdown levels is not supported"); 26 | if (!levels.TryGetValue(gameType, out var plist)) 27 | { 28 | #if NETSTANDARD2_1 29 | var bytes = await File.ReadAllBytesAsync(Path.Combine(path, GetLevelDataPath(gameType))); 30 | levels.TryAdd(gameType, plist = new Plist(bytes)); 31 | #else 32 | var bytes = File.ReadAllBytes(Path.Combine(path, GetLevelDataPath(gameType))); 33 | levels.Add(gameType, plist = new Plist(bytes)); 34 | #endif 35 | } 36 | 37 | var content = plist[((int)officialLevel).ToString()].ToString(); 38 | if (gameType == GameType.Default) 39 | return new Level($"H4sIAAAAAAAAC{content}", compressed: true); 40 | return new Level(content, compressed: true); 41 | } 42 | 43 | private static string GetLevelDataPath(GameType type) 44 | { 45 | return type switch 46 | { 47 | GameType.Default => "LevelData.plist", 48 | GameType.World => "LevelDataWorld.plist", 49 | GameType.Meltdown => "LevelDataMeltdown.plist", 50 | _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /GeometryDashAPI/Data/Models/GdResolution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Data.Models 4 | { 5 | public sealed class GdResolution 6 | { 7 | public int Width { get; } 8 | public int Height { get; } 9 | 10 | public GdResolution(int width, int height) 11 | { 12 | Width = width; 13 | Height = height; 14 | } 15 | 16 | public static GdResolution ToGdResolution(int gdResFormat) 17 | { 18 | return gdResFormat switch 19 | { 20 | 25 => new(2560, 1440), 21 | 24 => new(2560, 1200), // NOT TESTED. 2560x1200 IS A GUESSING. TESTER HAD NO VALUE AT THIS SPOT. RECHECK IF YOU HAVE ABILITY TO! 22 | 23 => new(1920, 1440), 23 | 22 => new(1920, 1200), 24 | 21 => new(1920, 1080), 25 | 20 => new(1768, 1050), 26 | 19 => new(1680, 992), 27 | 18 => new(1600, 1200), 28 | 17 => new(1600, 1024), 29 | 16 => new(1600, 900), 30 | 15 => new(1440, 900), 31 | 14 => new(1366, 768), 32 | 13 => new(1360, 768), 33 | 12 => new(1280, 1024), 34 | 11 => new(1280, 960), 35 | 10 => new(1280, 800), 36 | 9 => new(1280, 768), 37 | 8 => new(1280, 720), 38 | 7 => new(1176, 664), 39 | 6 => new(1152, 864), 40 | 5 => new(1024, 768), 41 | 4 => new(800, 600), 42 | 3 => new(720, 576), 43 | 2 => new(720, 480), 44 | 1 => new(640, 480), 45 | _ => throw new InvalidOperationException(nameof(gdResFormat)) 46 | }; 47 | } 48 | 49 | public static int FromGdResolution(GdResolution res) 50 | { 51 | return (res.Width, res.Height) switch 52 | { 53 | (2560, 1440) => 25, 54 | (2560, 1200) => 24, 55 | (1920, 1440) => 23, 56 | (1920, 1200) => 22, 57 | (1920, 1080) => 21, 58 | (1768, 1050) => 20, 59 | (1680, 992) => 19, 60 | (1600, 1200) => 18, 61 | (1600, 1024) => 17, 62 | (1600, 900) => 16, 63 | (1440, 900) => 15, 64 | (1366, 768) => 14, 65 | (1360, 768) => 13, 66 | (1280, 1024) => 12, 67 | (1280, 960) => 11, 68 | (1280, 800) => 10, 69 | (1280, 768) => 9, 70 | (1280, 720) => 8, 71 | (1176, 664) => 7, 72 | (1152, 864) => 6, 73 | (1024, 768) => 5, 74 | (800, 600) => 4, 75 | (720, 576) => 3, 76 | (720, 480) => 2, 77 | (640, 480) => 1, 78 | _ => throw new InvalidOperationException("Invalid resolutions' values") 79 | }; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /GeometryDashAPI/Exceptions/BlockLoadException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GeometryDashAPI.Exceptions 5 | { 6 | [Serializable] 7 | internal class BlockLoadException : Exception 8 | { 9 | public string[] BlockData; 10 | 11 | public BlockLoadException(int id, string[] data) 12 | : base($"Load block with ID {id} not support in this version API") 13 | { 14 | this.BlockData = data; 15 | } 16 | 17 | public BlockLoadException(string message) : base(message) 18 | { 19 | } 20 | 21 | public BlockLoadException(string message, Exception innerException) : base(message, innerException) 22 | { 23 | } 24 | 25 | protected BlockLoadException(SerializationInfo info, StreamingContext context) : base(info, context) 26 | { 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /GeometryDashAPI/Exceptions/ConstructorNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GeometryDashAPI.Exceptions 5 | { 6 | [Serializable] 7 | internal class ConstructorNotFoundException : Exception 8 | { 9 | public ConstructorNotFoundException(Type type) 10 | : base($"The class \"{type.FullName}\" does not have a constructor accepting an array of strings.") 11 | { 12 | } 13 | 14 | public ConstructorNotFoundException(string message) : base(message) 15 | { 16 | } 17 | 18 | public ConstructorNotFoundException(string message, Exception innerException) : base(message, innerException) 19 | { 20 | } 21 | 22 | protected ConstructorNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) 23 | { 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /GeometryDashAPI/Exceptions/NotImplementIBlockException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GeometryDashAPI.Exceptions 5 | { 6 | [Serializable] 7 | internal class NotImplementIBlockException : Exception 8 | { 9 | public NotImplementIBlockException(Type type) 10 | : base($"Class \"{type.FullName}\" does not implement IBlock interface.") 11 | { 12 | } 13 | 14 | internal NotImplementIBlockException(string message) : base(message) 15 | { 16 | } 17 | 18 | public NotImplementIBlockException(string message, Exception innerException) : base(message, innerException) 19 | { 20 | } 21 | 22 | protected NotImplementIBlockException(SerializationInfo info, StreamingContext context) : base(info, context) 23 | { 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /GeometryDashAPI/Exceptions/PropertyNotSupportedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GeometryDashAPI.Exceptions 5 | { 6 | [Serializable] 7 | internal class PropertyNotSupportedException : Exception 8 | { 9 | public PropertyNotSupportedException(string key, string value = null) 10 | : base(value == null ? $"Property '{key}' not supported." : $"Property '{key}' not supported. Value: {value}") 11 | { 12 | } 13 | 14 | internal PropertyNotSupportedException(string message) : base(message) 15 | { 16 | } 17 | 18 | public PropertyNotSupportedException(string message, Exception innerException) : base(message, innerException) 19 | { 20 | } 21 | 22 | protected PropertyNotSupportedException(SerializationInfo info, StreamingContext context) : base(info, context) 23 | { 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /GeometryDashAPI/Exceptions/UnableSetException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Serialization; 3 | 4 | namespace GeometryDashAPI.Exceptions 5 | { 6 | [Serializable] 7 | internal class UnableSetException : Exception 8 | { 9 | public UnableSetException() 10 | { 11 | } 12 | 13 | public UnableSetException(string message) : base(message) 14 | { 15 | } 16 | 17 | public UnableSetException(string message, Exception innerException) : base(message, innerException) 18 | { 19 | } 20 | 21 | protected UnableSetException(SerializationInfo info, StreamingContext context) : base(info, context) 22 | { 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GeometryDashAPI/Factories/DefaultHttpClientFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | 3 | namespace GeometryDashAPI.Factories 4 | { 5 | public class DefaultHttpClientFactory : IFactory 6 | { 7 | public HttpClient Create() 8 | { 9 | return new HttpClient(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Factories/IFactory.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Factories 2 | { 3 | public interface IFactory 4 | { 5 | T Create(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /GeometryDashAPI/GameConvert.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Runtime.CompilerServices; 4 | using System.Text; 5 | using csFastFloat; 6 | using NeoSmart.Utils; 7 | 8 | namespace GeometryDashAPI 9 | { 10 | public static class GameConvert 11 | { 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | public static string BoolToString(bool value, bool isReverse = false) 14 | { 15 | return value ^ isReverse ? "1" : "0"; 16 | } 17 | 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public static bool StringToBool(ReadOnlySpan value, bool isReverse = false) 20 | { 21 | return (value.CompareTo("1".AsSpan(), StringComparison.Ordinal) == 0) ^ isReverse; 22 | } 23 | 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static bool StringToBool(string value, bool isReverse = false) 26 | { 27 | return value == "1" ^ isReverse; 28 | } 29 | 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public static string SingleToString(float value) 32 | { 33 | return value.ToString(Culture.FormatProvider); 34 | } 35 | 36 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 37 | public static float StringToSingle(ReadOnlySpan value) 38 | { 39 | return FastFloatParser.ParseFloat(value, NumberStyles.Any); 40 | } 41 | 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static string DoubleToString(double value) 44 | { 45 | return value.ToString(Culture.FormatProvider); 46 | } 47 | 48 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 49 | public static double StringToDouble(ReadOnlySpan value) 50 | { 51 | return FastDoubleParser.ParseDouble(value, NumberStyles.Any); 52 | } 53 | 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public static string ToBase64(byte[] value) 56 | { 57 | return UrlBase64.Encode(value, PaddingPolicy.Preserve); 58 | } 59 | 60 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 61 | public static byte[] FromBase64(string base64) 62 | { 63 | if (base64 == null) 64 | return null; 65 | return UrlBase64.Decode(base64); 66 | } 67 | 68 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 69 | public static string ToBase64String(string value) 70 | { 71 | return UrlBase64.Encode(Encoding.ASCII.GetBytes(value), PaddingPolicy.Preserve); 72 | } 73 | 74 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 75 | public static string FromBase64String(string base64) 76 | { 77 | if (base64 == null) 78 | return null; 79 | return Encoding.ASCII.GetString(UrlBase64.Decode(base64)); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /GeometryDashAPI/GameObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GeometryDashAPI 4 | { 5 | public abstract class GameObject : IGameObject 6 | { 7 | public List WithoutLoaded { get; set; } = new(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /GeometryDashAPI/GameType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI; 2 | 3 | public enum GameType 4 | { 5 | Default = 0, 6 | World, 7 | Meltdown 8 | } 9 | -------------------------------------------------------------------------------- /GeometryDashAPI/GeometryDashAPI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1;netstandard2.0 5 | true 6 | Folleach 7 | en 8 | API for game Geometry Dash 9 | LICENSE 10 | https://github.com/Folleach/GeometryDashAPI 11 | git 12 | api, geometry, dash 13 | latest 14 | true 15 | enable 16 | logo.png 17 | 18 | 19 | 20 | bin\Debug\ 21 | 22 | 23 | 24 | bin\Release\ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | True 37 | 38 | logo.png 39 | 40 | 41 | True 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /GeometryDashAPI/GeometryDashApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using GeometryDashAPI.Levels; 6 | using GeometryDashAPI.Levels.GameObjects.Default; 7 | using GeometryDashAPI.Serialization; 8 | 9 | [assembly: InternalsVisibleTo("GeometryDashAPI.Tests")] 10 | [assembly: InternalsVisibleTo("GeometryDashAPI.Benchmarks")] 11 | [assembly: InternalsVisibleTo("Examples")] 12 | 13 | namespace GeometryDashAPI 14 | { 15 | public class GeometryDashApi 16 | { 17 | public static readonly int BinaryVersion = 35; 18 | 19 | internal static ObjectSerializer Serializer = new(); 20 | 21 | private static readonly Dictionary BlockTypes = new(); 22 | 23 | static GeometryDashApi() 24 | { 25 | RegisterBlockTypes(typeof(GeometryDashApi).Assembly, false); 26 | } 27 | 28 | public static void RegisterBlockTypes(Assembly assembly, bool overrideTypes) 29 | { 30 | foreach (var type in assembly.GetTypes()) 31 | RegisterBlockType(type, overrideTypes); 32 | } 33 | 34 | public static void RegisterBlockType(Type type, bool overrideType) 35 | { 36 | foreach (var item in type.GetCustomAttributes(false)) 37 | { 38 | if (item is not GameBlockAttribute attribute) 39 | continue; 40 | foreach (var id in attribute.Ids) 41 | { 42 | if (overrideType) 43 | BlockTypes[id] = type; 44 | else 45 | BlockTypes.Add(id, type); 46 | } 47 | } 48 | } 49 | 50 | public static Type GetBlockType(int blockId) 51 | { 52 | return BlockTypes.TryGetValue(blockId, out var type) ? type : typeof(Block); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /GeometryDashAPI/IGameObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GeometryDashAPI 4 | { 5 | public interface IGameObject 6 | { 7 | List WithoutLoaded { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/BlockGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using GeometryDashAPI.Serialization; 5 | 6 | namespace GeometryDashAPI.Levels 7 | { 8 | public class BlockGroup : List 9 | { 10 | public bool IsEmpty => Count == 0; 11 | 12 | public override string ToString() 13 | { 14 | var builder = new StringBuilder(); 15 | var first = true; 16 | foreach (var id in this) 17 | { 18 | if (first) 19 | { 20 | builder.Append(id); 21 | first = false; 22 | } 23 | else 24 | builder.Append($".{id}"); 25 | } 26 | return builder.ToString(); 27 | } 28 | 29 | public static BlockGroup Parse(ReadOnlySpan data) 30 | { 31 | var result = new BlockGroup(); 32 | var parser = new LLParserSpan(".".AsSpan(), data); 33 | while (true) 34 | { 35 | var idRaw = parser.Next(); 36 | if (idRaw == null) 37 | break; 38 | #if NETSTANDARD2_1 39 | if (!int.TryParse(idRaw, out var id)) 40 | #else 41 | if (!int.TryParse(idRaw.ToString(), out var id)) 42 | #endif 43 | throw new Exception($"Can't parse group id in: {data.ToString()}"); 44 | result.Add(id); 45 | } 46 | 47 | return result; 48 | } 49 | 50 | public static BlockGroup Parse(string data) 51 | { 52 | var result = new BlockGroup(); 53 | var parser = new LLParserSpan(".".AsSpan(), data.AsSpan()); 54 | while (true) 55 | { 56 | var idRaw = parser.Next(); 57 | if (idRaw == null) 58 | break; 59 | #if NETSTANDARD2_1 60 | if (!int.TryParse(idRaw, out var id)) 61 | #else 62 | if (!int.TryParse(idRaw.ToString(), out var id)) 63 | #endif 64 | throw new Exception($"Can't parse group id in: {data}"); 65 | result.Add(id); 66 | } 67 | 68 | return result; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/BlockList.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.GameObjects; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | using GeometryDashAPI.Levels.GameObjects.Triggers; 4 | using System.Collections.Generic; 5 | 6 | namespace GeometryDashAPI.Levels 7 | { 8 | public class BlockList : List 9 | { 10 | public Block[] GetBlocks() 11 | { 12 | return (Block[])FindAll(x => x is Block).ToArray(); 13 | } 14 | 15 | public MoveTrigger[] GetMoveTriggers() 16 | { 17 | return (MoveTrigger[])FindAll(x => x is MoveTrigger).ToArray(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Color.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Structures; 3 | 4 | namespace GeometryDashAPI.Levels 5 | { 6 | [Sense("_")] 7 | public class Color : GameObject 8 | { 9 | [GameProperty("1", 255, true, Order = 1)] public byte Red { get; set; } = 255; 10 | [GameProperty("2", 255, true, Order = 2)] public byte Green { get; set; } = 255; 11 | [GameProperty("3", 255, true, Order = 3)] public byte Blue { get; set; } = 255; 12 | [GameProperty("11", 255, Order = 4)] public byte Red2 { get; set; } = 255; 13 | [GameProperty("12", 255, Order = 5)] public byte Green2 { get; set; } = 255; 14 | [GameProperty("13", 255, Order = 6)] public byte Blue2 { get; set; } = 255; 15 | 16 | /// 17 | /// -1 - none, 0 - none, 1 - PlayerColor1, 2 - PlayerColor2 18 | /// 19 | [GameProperty("4", Order = 10)] public sbyte PlayerColor { get; set; } 20 | 21 | [GameProperty("6", 0, true, Order = 12)] public int Id { get; set; } 22 | [GameProperty("5", Order = 13)] public bool Blending { get; set; } 23 | [GameProperty("7", 1f, true, Order = 14)] public float Opacity { get; set; } = 1f; 24 | [GameProperty("15", 1, true, Order = 15)] public int K15 { get; set; } = 1; 25 | [GameProperty("18", 0, Order = 16)] public int K18 { get; set; } 26 | [GameProperty("8", 1, true, Order = 17)] public int K8 { get; set; } = 1; 27 | 28 | [GameProperty("17")] public bool CopyOpacity { get; set; } 29 | [GameProperty("10")] public Hsv? ColorHsv { get; set; } 30 | [GameProperty("9")] public int TargetChannelId { get; set; } 31 | 32 | public RgbColor Rgb 33 | { 34 | get => new(Red, Green, Blue); 35 | set 36 | { 37 | Red = value.Red; 38 | Green = value.Green; 39 | Blue = value.Blue; 40 | } 41 | } 42 | 43 | public Color() 44 | { 45 | } 46 | 47 | public Color(int id) 48 | { 49 | Id = id; 50 | } 51 | 52 | public void SetColor(byte r, byte g, byte b) 53 | { 54 | Red = r; 55 | Green = g; 56 | Blue = b; 57 | } 58 | 59 | public override string ToString() 60 | { 61 | return $"(id = {Id}, color = {Rgb})"; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/ColorList.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Exceptions; 2 | using GeometryDashAPI.Levels.Enums; 3 | using System.Collections.Generic; 4 | 5 | namespace GeometryDashAPI.Levels 6 | { 7 | public class ColorList : GameObject 8 | { 9 | private readonly Dictionary colors = new Dictionary(); 10 | 11 | public Color this[int id] 12 | { 13 | get 14 | { 15 | if (!colors.TryGetValue(id, out var color)) 16 | colors.Add(id, color = new Color(id)); 17 | return color; 18 | } 19 | set 20 | { 21 | if (value.Id != id) 22 | value.Id = id; 23 | colors[id] = value; 24 | } 25 | } 26 | 27 | public Color this[ColorType type] 28 | { 29 | get => this[(int)type]; 30 | set => this[(int)type] = value; 31 | } 32 | 33 | public int Count => colors.Count; 34 | 35 | public void SetId(int target, int to) 36 | { 37 | if (!colors.ContainsKey(target)) 38 | throw new UnableSetException($"Unable set. Target color '{target}' not found."); 39 | if (colors.ContainsKey(to)) 40 | throw new UnableSetException($"Unable set. Color '{to}' exists."); 41 | var col = colors[target]; 42 | colors.Remove(target); 43 | col.Id = to; 44 | colors.Add(to, col); 45 | } 46 | 47 | public void SetId(ColorType target, ColorType to) => SetId((int)target, (int)to); 48 | 49 | public void Remove(int id) => colors.Remove(id); 50 | 51 | public void Remove(ColorType type) => Remove((short)type); 52 | 53 | public int AddColor(Color color) 54 | { 55 | colors[color.Id] = color; 56 | return color.Id; 57 | } 58 | 59 | public List ToList() 60 | { 61 | var list = new List(colors.Count); 62 | foreach (var element in colors) 63 | list.Add(element.Value); 64 | return list; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/ColorType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum ColorType : short 4 | { 5 | Background = 1000, 6 | Ground = 1001, 7 | Ground2 = 1009, 8 | Line = 1002, 9 | Obj = 1004, 10 | ThreeDL = 1003 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/ConditionType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum ConditionType : byte 4 | { 5 | Equals, Larger, Smaller 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/Easing.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum Easing : byte 4 | { 5 | None = 0, 6 | EaseInOut, 7 | EaseIn, 8 | EaseOut, 9 | ElasticInOut, 10 | ElasticIn, 11 | ElasticOut, 12 | BounceInOut, 13 | BounceIn, 14 | BounceOut, 15 | ExponentialInOut, 16 | ExponentialIn, 17 | ExponentialOut, 18 | SineInOut, 19 | SineIn, 20 | SineOut, 21 | BackInOut, 22 | BackIn, 23 | BackOut 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/GameMode.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum GameMode 4 | { 5 | Cube = 0, 6 | Ship, 7 | Ball, 8 | Bird, 9 | Dart, 10 | Robot, 11 | Spider 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/GuidelineColors.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace GeometryDashAPI.Levels.Enums 3 | { 4 | public enum GuidelineColor 5 | { 6 | Orange, 7 | Yellow, 8 | Green 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/Layer.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum Layer : short 4 | { 5 | B4 = -3, 6 | B3 = -1, 7 | B2 = 1, 8 | B1 = 3, 9 | T1 = 5, 10 | T2 = 7, 11 | T3 = 9 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/PulseModeType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum PulseModeType : byte 4 | { 5 | Color, Hsv 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/SpeedType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum SpeedType : byte 4 | { 5 | Half = 1, 6 | Default = 0, 7 | X2 = 2, 8 | X3 = 3, 9 | X4 = 4 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/TargetPosGroupType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace GeometryDashAPI.Levels.Enums 6 | { 7 | public enum TargetPosGroupType : byte 8 | { 9 | All, XOnly, YOnly 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/TargetType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum TargetType : byte 4 | { 5 | Channel, Group 6 | } 7 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Enums/ToggleMode.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.Enums 2 | { 3 | public enum ToggleMode : byte 4 | { 5 | None, On, Off 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameBlockAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GeometryDashAPI.Levels.Enums; 3 | 4 | namespace GeometryDashAPI.Levels 5 | { 6 | public class GameBlockAttribute : Attribute 7 | { 8 | public readonly int[] Ids; 9 | 10 | public GameBlockAttribute(params int[] ids) 11 | { 12 | Ids = ids; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Default/BaseBlock.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Default 5 | { 6 | [GameBlock(1, 8)] 7 | public class BaseBlock : Block 8 | { 9 | [GameProperty("21", (short)ColorType.Obj)] 10 | public virtual short ColorBase { get; set; } = (short)ColorType.Obj; 11 | 12 | public BaseBlock() 13 | { 14 | } 15 | 16 | public BaseBlock(int id) : base(id) 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Default/Block.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Default 5 | { 6 | [GameBlock()] 7 | [Sense(",")] 8 | public class Block : GameObject, IBlock 9 | { 10 | [GameProperty("1", 0, true, Order = 1)] public int Id { get; set; } 11 | [GameProperty("2", 0f, true, Order = 2)] public float PositionX { get; set; } 12 | [GameProperty("3", 0f, true, Order = 3)] public float PositionY { get; set; } 13 | 14 | [GameProperty("4", false, Order = 4)] public bool HorizontalReflection { get; set; } 15 | [GameProperty("5", false, Order = 5)] public bool VerticalReflection { get; set; } 16 | 17 | [GameProperty("64", false, Order = 50)] public bool DontFade { get; set; } 18 | 19 | [GameProperty("36", false, Order = Trigger.OrderTriggerBase)] public bool IsTrigger { get; set; } 20 | 21 | [GameProperty("6", 0)] public int Rotation { get; set; } 22 | 23 | public bool Glow 24 | { 25 | get => !glow; 26 | set => glow = !value; 27 | } 28 | 29 | [GameProperty("96", true)] private bool glow = true; 30 | [GameProperty("108", 0)] public int LinkControl { get; set; } 31 | [GameProperty("20", (short)0)] public short EditorL { get; set; } 32 | [GameProperty("61", (short)0)] public short EditorL2 { get; set; } 33 | [GameProperty("103", false)] public bool HighDetail { get; set; } 34 | [GameProperty("57")] [ArraySeparator(".")] public int[] Groups { get; set; } 35 | [GameProperty("67", false)] public bool DontEnter { get; set; } 36 | [GameProperty("25", 2)] public virtual int ZOrder { get; set; } = 2; 37 | 38 | public Layer ZLayer 39 | { 40 | get => (Layer)zLayer; 41 | set => zLayer = (short)value; 42 | } 43 | 44 | [GameProperty("24", (short)Layer.T1)] protected virtual short zLayer { get; set; } = (int)Layer.T1; 45 | [GameProperty("32", 1f)] public float Scale { get; set; } = 1f; 46 | [GameProperty("34", false)] public bool GroupParent { get; set; } 47 | 48 | [GameProperty("43", null)] 49 | private Hsv? hsv; 50 | 51 | [GameProperty("44", null)] 52 | private Hsv? additionalHsv; 53 | 54 | [GameProperty("41", false)] 55 | public bool HasHsv { get; protected set; } 56 | 57 | [GameProperty("42", false)] 58 | public bool HasAdditionalHsv { get; protected set; } 59 | 60 | /// 61 | public Hsv? Hsv 62 | { 63 | get => hsv; 64 | set 65 | { 66 | hsv = value; 67 | HasHsv = value != null; 68 | } 69 | } 70 | 71 | /// 72 | public Hsv? AdditionalHsv 73 | { 74 | get => additionalHsv; 75 | set 76 | { 77 | additionalHsv = value; 78 | HasAdditionalHsv = value != null; 79 | } 80 | } 81 | 82 | public Block() 83 | { 84 | } 85 | 86 | public Block(int id) 87 | { 88 | Id = id; 89 | } 90 | 91 | public override string ToString() => $"Type: {GetType().Name}, ID: {Id}, Position: (x: {PositionX}, y: {PositionY})"; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Default/ColorBlock.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Default 5 | { 6 | public class ColorBlock : Block 7 | { 8 | [GameProperty("21", (short)ColorType.Obj)] 9 | public virtual short ColorBase { get; set; } = (short)ColorType.Obj; 10 | [GameProperty("22", (short)1)] 11 | public virtual short ColorDetail { get; set; } = 1; 12 | 13 | public ColorBlock() 14 | { 15 | } 16 | 17 | public ColorBlock(int id) : base(id) 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Default/DetailBlock.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Default 4 | { 5 | [GameBlock(1658, 1888)] 6 | public class DetailBlock : Block 7 | { 8 | [GameProperty("22", (short)1)] 9 | public short ColorDetail { get; set; } = 1; 10 | 11 | public DetailBlock() 12 | { 13 | } 14 | 15 | public DetailBlock(int id) : base(id) 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Default/Portal.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Default 4 | { 5 | public class Portal : Block 6 | { 7 | [GameProperty("13", true, true)] public bool Checked { get; set; } 8 | 9 | public Portal() 10 | { 11 | } 12 | 13 | public Portal(int id) : base(id) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Default/TargetingTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Default 4 | { 5 | public abstract class TargetingTrigger : Trigger 6 | { 7 | internal const int OrderTargetingTriggerBase = 107; 8 | 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | [GameProperty("80", 0, true, Order = OrderTriggerBase + 2)] public int ItemId { get; set; } 11 | [GameProperty("77", 0, Order = OrderTriggerBase + 3)] public int TargetCount { get; set; } 12 | [GameProperty("56", false, Order = OrderTriggerBase + 4)] public bool ActivateGroup { get; set; } 13 | 14 | protected TargetingTrigger(int id) : base(id) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Default/Trigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Default 4 | { 5 | public abstract class Trigger : Block, ITrigger 6 | { 7 | internal const int OrderTriggerBase = 103; 8 | 9 | [GameProperty("11", false, Order = 100)] public bool TouchTrigger { get; set; } = false; 10 | [GameProperty("62", false, Order = 101)] public bool SpawnTrigger { get; set; } = false; 11 | [GameProperty("87", false, Order = 102)] protected bool multiTrigger; 12 | 13 | public virtual bool MultiTrigger 14 | { 15 | get => multiTrigger; 16 | set => multiTrigger = value; 17 | } 18 | 19 | public Trigger() 20 | { 21 | IsTrigger = true; 22 | } 23 | 24 | public Trigger(int id) : base(id) 25 | { 26 | IsTrigger = true; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/IBlock.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.Enums; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects; 4 | 5 | public interface IBlock : IGameObject 6 | { 7 | int Id { get; set; } 8 | float PositionX { get; set; } 9 | float PositionY { get; set; } 10 | bool HorizontalReflection { get; set; } 11 | bool VerticalReflection { get; set; } 12 | int Rotation { get; set; } 13 | bool Glow { get; set; } 14 | int LinkControl { get; set; } 15 | short EditorL { get; set; } 16 | short EditorL2 { get; set; } 17 | bool HighDetail { get; set; } 18 | int[] Groups { get; set; } 19 | bool DontFade { get; set; } 20 | bool DontEnter { get; set; } 21 | int ZOrder { get; set; } 22 | Layer ZLayer { get; set; } 23 | float Scale { get; set; } 24 | bool GroupParent { get; set; } 25 | bool IsTrigger { get; set; } 26 | 27 | bool HasHsv { get; } 28 | bool HasAdditionalHsv { get; } 29 | 30 | /// 31 | /// If block has 1 color: base or detail
32 | /// The value takes either base or detail

33 | /// If block has 2 colors, is base 34 | ///
35 | Hsv? Hsv { get; set; } 36 | 37 | /// 38 | /// If block has 2 colors: base and detail
39 | /// is detail, otherwise null 40 | ///
41 | Hsv? AdditionalHsv { get; set; } 42 | } 43 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/ITrigger.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Levels.GameObjects 2 | { 3 | public interface ITrigger 4 | { 5 | bool TouchTrigger { get; set; } 6 | bool SpawnTrigger { get; set; } 7 | bool MultiTrigger { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/CircleParticle.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Specific 6 | { 7 | [GameBlock(1700)] 8 | public class CircleParticle : ColorBlock 9 | { 10 | [GameProperty("24", (short)Layer.B1)] protected override short zLayer { get; set; } = (short)Layer.B1; 11 | [GameProperty("25", 0)] public override int ZOrder { get; set; } = 0; 12 | 13 | public CircleParticle() : base(1700) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/Coin.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Specific 5 | { 6 | [GameBlock(1329)] 7 | public class Coin : Block 8 | { 9 | [GameProperty("25", 9)] public override int ZOrder { get; set; } = 9; 10 | 11 | public Coin() : base(1329) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/JumpPlate.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Specific 6 | { 7 | public enum JumpPlateId 8 | { 9 | Yellow = 35, 10 | Purple = 140, 11 | Red = 1332, 12 | LightBlue = 67 13 | } 14 | 15 | [GameBlock(35, 140, 1332, 67)] 16 | public class JumpPlate : Block 17 | { 18 | [GameProperty("24", (short)Layer.B1)] protected override short zLayer { get; set; } = (short)Layer.B1; 19 | [GameProperty("25", 12)] public override int ZOrder { get; set; } = 12; 20 | 21 | public JumpPlateId BlockType 22 | { 23 | get => (JumpPlateId)Id; 24 | set => Id = (int)value; 25 | } 26 | 27 | public JumpPlate() : base(35) 28 | { 29 | } 30 | 31 | public JumpPlate(JumpPlateId type) : base((int)type) 32 | { 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/JumpSphere.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Specific 6 | { 7 | public enum JumpSphereId 8 | { 9 | Yellow = 36, 10 | Purple = 141, 11 | Red = 1333, 12 | LightBlue = 84, 13 | Green = 1022, 14 | Dark = 1330, 15 | ArrowGreen = 1704, 16 | ArrowPurple = 1751 17 | } 18 | 19 | [GameBlock(36, 141, 1333, 84, 1022, 1330, 1704, 1751)] 20 | public class JumpSphere : Block 21 | { 22 | [GameProperty("24", (short)Layer.B1)] protected override short zLayer { get; set; } = (short)Layer.B1; 23 | [GameProperty("25", 12)] public override int ZOrder { get; set; } = 12; 24 | 25 | [GameProperty("99", false)] 26 | public bool MultiActivate { get; set; } 27 | 28 | public JumpSphereId BlockType 29 | { 30 | get => (JumpSphereId)Id; 31 | set => Id = (int)value; 32 | } 33 | 34 | public JumpSphere() : base(36) 35 | { 36 | } 37 | 38 | public JumpSphere(JumpSphereId type) : base((int)type) 39 | { 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/SpeedBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Levels.Enums; 4 | using GeometryDashAPI.Levels.GameObjects.Default; 5 | 6 | namespace GeometryDashAPI.Levels.GameObjects.Specific 7 | { 8 | /// 9 | /// Represents the id of the speed block.

10 | /// Not to be confused with .
11 | /// Because it is responsible for a specific speed, instead of a specific block id 12 | ///
13 | public enum SpeedBlockId 14 | { 15 | Orange = 200, 16 | Default = 201, 17 | Green = 202, 18 | Purple = 203, 19 | Red = 1334 20 | } 21 | 22 | [GameBlock(200, 201, 202, 203, 1334)] 23 | public class SpeedBlock : Portal 24 | { 25 | [GameProperty("24", (short)Layer.B2)] protected override short zLayer { get; set; } = (short)Layer.B2; 26 | [GameProperty("25", -6)] public override int ZOrder { get; set; } = -6; 27 | 28 | public SpeedBlockId BlockType 29 | { 30 | get => (SpeedBlockId)Id; 31 | set => Id = (int)value; 32 | } 33 | 34 | public SpeedType SpeedType 35 | { 36 | get => FromBlockIdToSpeedType(BlockType); 37 | set => BlockType = FromSpeedTypeToBlockId(value); 38 | } 39 | 40 | public SpeedBlock() : base(201) 41 | { 42 | } 43 | 44 | public SpeedBlock(SpeedBlockId type) : base((int)type) 45 | { 46 | } 47 | 48 | public SpeedBlock(SpeedType type) : base((int)FromSpeedTypeToBlockId(type)) 49 | { 50 | } 51 | 52 | public static SpeedType FromBlockIdToSpeedType(SpeedBlockId id) 53 | { 54 | return id switch 55 | { 56 | SpeedBlockId.Orange => SpeedType.Half, 57 | SpeedBlockId.Default => SpeedType.Default, 58 | SpeedBlockId.Green => SpeedType.X2, 59 | SpeedBlockId.Purple => SpeedType.X3, 60 | SpeedBlockId.Red => SpeedType.X4, 61 | _ => throw new ArgumentOutOfRangeException(nameof(id), id, null) 62 | }; 63 | } 64 | 65 | public static SpeedBlockId FromSpeedTypeToBlockId(SpeedType speedType) 66 | { 67 | return speedType switch 68 | { 69 | SpeedType.Half => SpeedBlockId.Orange, 70 | SpeedType.Default => SpeedBlockId.Default, 71 | SpeedType.X2 => SpeedBlockId.Green, 72 | SpeedType.X3 => SpeedBlockId.Purple, 73 | SpeedType.X4 => SpeedBlockId.Red, 74 | _ => throw new ArgumentOutOfRangeException(nameof(speedType), speedType, null) 75 | }; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/SquareParticle.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Specific 6 | { 7 | [GameBlock(1586)] 8 | public class SquareParticle : ColorBlock 9 | { 10 | [GameProperty("24", (short)Layer.B2)] protected override short zLayer { get; set; } = (short)Layer.B2; 11 | [GameProperty("25", 0)] public override int ZOrder { get; set; } = 0; 12 | 13 | public SquareParticle() : base(1586) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/StartPos.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Specific 6 | { 7 | [GameBlock(31)] 8 | public class StartPos : Block 9 | { 10 | [GameProperty("kA2", GameMode.Cube, true, KeyOverride = 0)] public GameMode GameMode { get; set; } = GameMode.Cube; 11 | [GameProperty("kA3", false, true, KeyOverride = 1)] public bool IsMini { get; set; } 12 | [GameProperty("kA8", false, true, KeyOverride = 2)] public bool IsDual { get; set; } 13 | [GameProperty("kA4", SpeedType.Default, true, KeyOverride = 3)] public SpeedType PlayerSpeed { get; set; } = SpeedType.Default; 14 | [GameProperty("kA11", false, true, KeyOverride = 4)] public bool IsFlippedGravity { get; set; } 15 | [GameProperty("kA10", 0, true, KeyOverride = 5)] public int Ka10 { get; set; } 16 | 17 | public StartPos() : base(31) 18 | { } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Specific/TextBlock.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Specific 5 | { 6 | [GameBlock(914)] 7 | public class TextBlock : DetailBlock 8 | { 9 | [GameProperty("25", 1)] public override int ZOrder { get; set; } = 1; 10 | 11 | public string Text 12 | { 13 | get => GameConvert.FromBase64String(text); 14 | set => text = GameConvert.ToBase64String(value); 15 | } 16 | [GameProperty("31", "A", true)] private string text = "A"; 17 | 18 | public TextBlock() : base(914) 19 | { 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/AlphaTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1007)] 7 | public class AlphaTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupID { get; set; } 10 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 2)] public float FadeTime { get; set; } = 0.5f; 11 | [GameProperty("35", 1f, true, Order = OrderTriggerBase + 3)] public float Opacity { get; set; } = 1f; 12 | 13 | public AlphaTrigger() : base(1007) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/AnimateTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1585)] 7 | public class AnimateTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | [GameProperty("76", 0, true, Order = OrderTriggerBase + 2)] public int AnimateGroupId { get; set; } 11 | 12 | public AnimateTrigger() : base(1585) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/CollisionBlockTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1816)] 7 | public class CollisionBlockTrigger : Trigger 8 | { 9 | [GameProperty("80", 0, true, Order = OrderTriggerBase + 1)] public int BlockId { get; set; } 10 | [GameProperty("94", false, false, Order = OrderTriggerBase + 2)] public bool DynamicBlock { get; set; } 11 | 12 | public CollisionBlockTrigger() : base(1816) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/CollisionTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | using System; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 6 | { 7 | [GameBlock(1815)] 8 | public class CollisionTrigger : Trigger 9 | { 10 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 11 | 12 | [Obsolete("This value can't be changed in the game, it just exists in this trigger, but absolutely doesn't interact with the game itself")] 13 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 2)] public float MoveTime { get; set; } = 0.5f; 14 | [GameProperty("56", false, Order = OrderTriggerBase + 3)] public bool ActivateGroup { get; set; } 15 | [GameProperty("80", 0, Order = OrderTriggerBase + 4)] public int ABlockId { get; set; } 16 | [GameProperty("95", 0, Order = OrderTriggerBase + 5)] public int BBlockId { get; set; } 17 | [GameProperty("93", false, Order = OrderTriggerBase + 6)] public bool TriggerOnExit { get; set; } 18 | 19 | public CollisionTrigger() : base(1815) 20 | { 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/ColorTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(899)] 7 | public class ColorTrigger : Trigger 8 | { 9 | [GameProperty("7", (byte)255, true, Order = OrderTriggerBase + 1)] public byte Red { get; set; } = 255; 10 | [GameProperty("8", (byte)255, true, Order = OrderTriggerBase + 2)] public byte Green { get; set; } = 255; 11 | [GameProperty("9", (byte)255, true, Order = OrderTriggerBase + 3)] public byte Blue { get; set; } = 255; 12 | 13 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 4)] public float FadeTime { get; set; } = 0.5f; 14 | [GameProperty("35", 1f, true, Order = OrderTriggerBase + 5)] public float Opacity { get; set; } = 1f; 15 | 16 | [GameProperty("17", false, Order = OrderTriggerBase + 7)] public bool Blending { get; set; } = false; 17 | 18 | [GameProperty("23", 1, Order = OrderTriggerBase + 9)] public int ColorId { get; set; } = 1; 19 | 20 | [GameProperty("15", false, Order = OrderTriggerBase + 6)] public bool PlayerColor1 { get; set; } 21 | [GameProperty("16", false, Order = OrderTriggerBase + 6)] public bool PlayerColor2 { get; set; } 22 | [GameProperty("60", false, Order = OrderTriggerBase + 8)] public bool CopyOpacity { get; set; } 23 | 24 | [GameProperty("49", Order = OrderTriggerBase + 11)] public Hsv ColorHsv { get; set; } 25 | [GameProperty("50", 0, Order = OrderTriggerBase + 10)] public int TargetChannelId { get; set; } 26 | 27 | public ColorTrigger() : base(899) 28 | { 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/CountTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1611)] 7 | public class CountTrigger : TargetingTrigger 8 | { 9 | [GameProperty("104", false, Order = OrderTargetingTriggerBase + 1)] public bool MultiActivate { get; set; } 10 | 11 | public CountTrigger() : base(1611) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/DisableBgEffectTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.GameObjects.Default; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 4 | { 5 | [GameBlock(1819)] 6 | public class DisableBgEffectTrigger : Trigger 7 | { 8 | public DisableBgEffectTrigger() : base(1819) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/DisablePlayerTrailTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.GameObjects.Default; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 4 | { 5 | [GameBlock(33)] 6 | public class DisablePlayerTrailTrigger : Trigger 7 | { 8 | public DisablePlayerTrailTrigger() : base(33) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/EditSfxTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers; 5 | 6 | [GameBlock(3603)] 7 | public class EditSfxTrigger : Trigger 8 | { 9 | [GameProperty("10", 0.5f)] 10 | public float Duration { get; set; } = 0.5f; 11 | 12 | [GameProperty("51", 0)] 13 | public int GroupId1 { get; set; } 14 | 15 | [GameProperty("71", 0)] 16 | public int GroupId2 { get; set; } 17 | 18 | [GameProperty("138", false)] 19 | public bool P1 { get; set; } 20 | 21 | [GameProperty("200", false)] 22 | public bool P2 { get; set; } 23 | 24 | [GameProperty("404", 0)] 25 | public int Speed { get; set; } 26 | 27 | [GameProperty("406", 1f, alwaysSet: true)] 28 | public float Volume { get; set; } = 1f; 29 | 30 | [GameProperty("414", false)] 31 | public bool StopLoop { get; set; } 32 | 33 | [GameProperty("416", 0)] 34 | public int UniqueId { get; set; } 35 | 36 | [GameProperty("417", false)] 37 | public bool Stop { get; set; } 38 | 39 | [GameProperty("418", false)] 40 | public bool ChangeVolume { get; set; } 41 | 42 | [GameProperty("419", false)] 43 | public bool ChangeSpeed { get; set; } 44 | 45 | [GameProperty("421", 1f)] 46 | public float VolNear { get; set; } = 1f; 47 | 48 | [GameProperty("422", 0.5f)] 49 | public float VolMed { get; set; } = 0.5f; 50 | 51 | [GameProperty("423", 0f)] 52 | public float VolFar { get; set; } 53 | 54 | [GameProperty("424", 0f)] 55 | public int MinDist { get; set; } 56 | 57 | [GameProperty("425", 0f)] 58 | public int Dist2 { get; set; } 59 | 60 | [GameProperty("426", 0f)] 61 | public int Dist3 { get; set; } 62 | 63 | [GameProperty("428", false)] 64 | public bool Cam { get; set; } 65 | 66 | [GameProperty("455", 0)] 67 | public int SfxGroup { get; set; } 68 | 69 | [GameProperty("458", SoundPropagationDirection.All)] 70 | public SoundPropagationDirection Propagation { get; set; } 71 | 72 | [GameProperty("457", 0)] 73 | public int GroupId { get; set; } 74 | 75 | public EditSfxTrigger() : base(3603) 76 | { 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/EditSongTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers; 5 | 6 | [GameBlock(3605)] 7 | public class EditSongTrigger : Trigger 8 | { 9 | [GameProperty("10", 0.5f)] 10 | public float Duration { get; set; } = 0.5f; 11 | 12 | [GameProperty("51", 0)] 13 | public int GroupId1 { get; set; } 14 | 15 | [GameProperty("71", 0)] 16 | public int GroupId2 { get; set; } 17 | 18 | [GameProperty("138", false)] 19 | public bool P1 { get; set; } 20 | 21 | [GameProperty("200", false)] 22 | public bool P2 { get; set; } 23 | 24 | [GameProperty("404", 0)] 25 | public int Speed { get; set; } 26 | 27 | [GameProperty("406", 1f, alwaysSet: true)] 28 | public float Volume { get; set; } = 1f; 29 | 30 | [GameProperty("414", false)] 31 | public bool StopLoop { get; set; } 32 | 33 | [GameProperty("417", false)] 34 | public bool Stop { get; set; } 35 | 36 | [GameProperty("418", false)] 37 | public bool ChangeVolume { get; set; } 38 | 39 | [GameProperty("419", false)] 40 | public bool ChangeSpeed { get; set; } 41 | 42 | [GameProperty("421", 1f)] 43 | public float VolNear { get; set; } = 1f; 44 | 45 | [GameProperty("422", 0.5f)] 46 | public float VolMed { get; set; } = 0.5f; 47 | 48 | [GameProperty("423", 0f)] 49 | public float VolFar { get; set; } 50 | 51 | [GameProperty("424", 0f)] 52 | public int MinDist { get; set; } 53 | 54 | [GameProperty("425", 0f)] 55 | public int Dist2 { get; set; } 56 | 57 | [GameProperty("426", 0f)] 58 | public int Dist3 { get; set; } 59 | 60 | [GameProperty("428", false)] 61 | public bool Cam { get; set; } 62 | 63 | [GameProperty("432", 0)] 64 | public int Channel { get; set; } 65 | 66 | [GameProperty("458", SoundPropagationDirection.All)] 67 | public SoundPropagationDirection Propagation { get; set; } 68 | 69 | public EditSongTrigger() : base(3605) 70 | { 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/EnableBgEffectTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.GameObjects.Default; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 4 | { 5 | [GameBlock(1818)] 6 | public class EnableBgEffectTrigger : Trigger 7 | { 8 | public EnableBgEffectTrigger() : base(1818) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/EnablePlayerTrailTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.GameObjects.Default; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 4 | { 5 | [GameBlock(32)] 6 | public class EnablePlayerTrailTrigger : Trigger 7 | { 8 | public EnablePlayerTrailTrigger() : base(32) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/FollowPlayerYTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1814)] 7 | public class FollowPlayerYTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 2)] public float MoveTime { get; set; } = 0.5f; 11 | [GameProperty("90", 1f, true, Order = OrderTriggerBase + 3)] public float Speed { get; set; } = 1f; 12 | [GameProperty("91", 0, false, Order = OrderTriggerBase + 4)] public float Delay { get; set; } 13 | [GameProperty("92", 0, false, Order = OrderTriggerBase + 5)] public float Offset { get; set; } 14 | [GameProperty("105", 0, false, Order = OrderTriggerBase + 6)] public float MaxSpeed { get; set; } 15 | 16 | public FollowPlayerYTrigger() : base(1814) 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/FollowTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1347)] 7 | public class FollowTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | [GameProperty("71", 0, true, Order = OrderTriggerBase + 2)] public int FollowGroupId { get; set; } 11 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 3)] public float MoveTime { get; set; } = 0.5f; 12 | [GameProperty("72", 1f, true, Order = OrderTriggerBase + 4)] public float XMod { get; set; } = 1f; 13 | [GameProperty("73", 1f, true, Order = OrderTriggerBase + 5)] public float YMod { get; set; } = 1f; 14 | [GameProperty("74", 0, true, Order = OrderTriggerBase + 6)] public int K74 { get; set; } 15 | 16 | public FollowTrigger() : base(1347) 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/HidePlayerIconTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.GameObjects.Default; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 4 | { 5 | [GameBlock(1612)] 6 | public class HidePlayerIconTrigger : Trigger 7 | { 8 | public HidePlayerIconTrigger() : base(1612) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/InstantCountTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 6 | { 7 | [GameBlock(1811)] 8 | public class InstantCountTrigger : TargetingTrigger 9 | { 10 | [GameProperty("88", ConditionType.Equals, Order = OrderTargetingTriggerBase + 1)] public ConditionType Condition { get; set; } = ConditionType.Equals; 11 | 12 | public InstantCountTrigger() : base(1811) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/MoveTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 6 | { 7 | [GameBlock(901)] 8 | public class MoveTrigger : Trigger 9 | { 10 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 11 | 12 | [GameProperty("28", 0f, true, Order = OrderTriggerBase + 2)] public float MoveX { get; set; } = 0f; 13 | [GameProperty("29", 0f, true, Order = OrderTriggerBase + 3)] public float MoveY { get; set; } = 0f; 14 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 4)] public float MoveTime { get; set; } = 0.5f; 15 | 16 | [GameProperty("30", Easing.None, true, Order = OrderTriggerBase + 5)] public Easing EasingMode { get; set; } = Easing.None; 17 | [GameProperty("85", 2f, true, Order = OrderTriggerBase + 6)] public float EasingTime { get; set; } = 2f; 18 | 19 | [GameProperty("58", false, Order = OrderTriggerBase + 7)] public bool LockPlayerX { get; set; } 20 | [GameProperty("59", false, Order = OrderTriggerBase + 7)] public bool LockPlayerY { get; set; } 21 | 22 | [GameProperty("71", 0, Order = OrderTriggerBase + 7)] public int TargetPosGroupId { get; set; } 23 | [GameProperty("100", false, Order = OrderTriggerBase + 8)] public bool UseTarget { get; set; } 24 | [GameProperty("101", TargetPosGroupType.All, Order = OrderTriggerBase + 8)] public TargetPosGroupType TargetPosGroup { get; set; } = TargetPosGroupType.All; 25 | 26 | public MoveTrigger() : base(901) 27 | { 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/OnDeathTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1812)] 7 | public class OnDeathTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | [GameProperty("56", false, false, Order = OrderTriggerBase + 1)] public bool ActivateGroup { get; set; } 11 | 12 | public OnDeathTrigger() : base(1812) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/PickupTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1817)] 7 | public class PickupTrigger : Trigger 8 | { 9 | [GameProperty("80", 0, true, Order = OrderTriggerBase + 1)] public int ItemId { get; set; } 10 | [GameProperty("77", 0, false, Order = OrderTriggerBase + 2)] public int Count { get; set; } 11 | 12 | public PickupTrigger() : base(1817) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/PulseTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 6 | { 7 | [GameBlock(1006)] 8 | public class PulseTrigger : Trigger 9 | { 10 | [GameProperty("7", (byte)255, Order = OrderTriggerBase + 9)] public byte Red { get; set; } = 255; 11 | [GameProperty("8", (byte)255, Order = OrderTriggerBase + 10)] public byte Green { get; set; } = 255; 12 | [GameProperty("9", (byte)255, Order = OrderTriggerBase + 11)] public byte Blue { get; set; } = 255; 13 | 14 | [GameProperty("45", 0f, Order = OrderTriggerBase + 2)] public float FadeIn { get; set; } 15 | [GameProperty("46", 0f, Order = OrderTriggerBase + 3)] public float Hold { get; set; } 16 | [GameProperty("47", 0f, Order = OrderTriggerBase + 4)] public float FadeOut { get; set; } 17 | 18 | [GameProperty("48", PulseModeType.Color, Order = OrderTriggerBase + 5)] public PulseModeType PulseMode { get; set; } = PulseModeType.Color; 19 | [GameProperty("49", Order = OrderTriggerBase + 9)] public Hsv HsvValue { get; set; } 20 | 21 | [GameProperty("50", Order = OrderTriggerBase + 12)] public int ColorId { get; set; } 22 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } = 0; 23 | 24 | [GameProperty("52", TargetType.Channel, Order = OrderTriggerBase + 6)] public TargetType TargetType { get; set; } = TargetType.Channel; 25 | 26 | [GameProperty("65", false, Order = OrderTriggerBase + 7)] public bool MainOnly { get; set; } 27 | [GameProperty("66", false, Order = OrderTriggerBase + 7)] public bool DetailOnly { get; set; } 28 | 29 | [GameProperty("86", false, Order = OrderTriggerBase + 8)] public bool Exclusive { get; set; } 30 | 31 | public PulseTrigger() : base(1006) 32 | { 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/RotateTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 6 | { 7 | [GameBlock(1346)] 8 | public class RotateTrigger : Trigger 9 | { 10 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 11 | [GameProperty("71", 0, true, Order = OrderTriggerBase + 2)] public int CenterGroupId { get; set; } 12 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 3)] public float MoveTime { get; set; } = 0.5f; 13 | [GameProperty("30", Easing.None, true, Order = OrderTriggerBase + 4)] public Easing Easing { get; set; } = Easing.None; 14 | [GameProperty("85", 2f, true, Order = OrderTriggerBase + 5)] public float EasingTime { get; set; } = 2f; 15 | [GameProperty("68", 0, true, Order = OrderTriggerBase + 6)] public int Degrees { get; set; } 16 | [GameProperty("69", 0, true, Order = OrderTriggerBase + 7)] public int Times360 { get; set; } 17 | [GameProperty("70", false, true, Order = OrderTriggerBase + 8)] public bool LockObjectRotation { get; set; } 18 | 19 | public RotateTrigger() : base(1346) 20 | { 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/SfxTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers; 5 | 6 | public enum SoundPropagationDirection 7 | { 8 | All, 9 | Horizontal, 10 | Left, 11 | Right, 12 | Vertical, 13 | Down, 14 | Up 15 | } 16 | 17 | public enum ReverbTypes 18 | { 19 | Generic, 20 | PaddedCell, 21 | Room, 22 | BathRoom, 23 | LivingRoom, 24 | StoneRoom, 25 | Auditorium, 26 | ConcertHall, 27 | Cave, 28 | Arena, 29 | Hangar, 30 | CarpetedHallway, 31 | Hallway, 32 | StoneCorridor, 33 | Alley, 34 | Forest, 35 | City, 36 | Mountains, 37 | Quarry, 38 | Plain, 39 | ParkingLot, 40 | SewerPipe, 41 | Underwater 42 | } 43 | 44 | [GameBlock(3602)] 45 | public class SfxTrigger : Trigger 46 | { 47 | [GameProperty("51", 0)] 48 | public int GroupId1 { get; set; } 49 | 50 | [GameProperty("71", 0)] 51 | public int GroupId2 { get; set; } 52 | 53 | [GameProperty("138", false)] 54 | public bool P1 { get; set; } 55 | 56 | [GameProperty("200", false)] 57 | public bool P2 { get; set; } 58 | 59 | [GameProperty("392", 0)] 60 | public int SongId { get; set; } 61 | 62 | [GameProperty("404", 0)] 63 | public int Speed { get; set; } 64 | 65 | [GameProperty("405", 0)] 66 | public int Pitch { get; set; } 67 | 68 | [GameProperty("406", 1f, alwaysSet: true)] 69 | public float Volume { get; set; } = 1f; 70 | 71 | [GameProperty("407", false)] 72 | public bool Reverb { get; set; } 73 | 74 | [GameProperty("408", 0)] 75 | public int Start { get; set; } 76 | 77 | [GameProperty("409", 0)] 78 | public int FadeIn { get; set; } 79 | 80 | [GameProperty("410", 0)] 81 | public int End { get; set; } 82 | 83 | [GameProperty("411", 0)] 84 | public int FadeOut { get; set; } 85 | 86 | [GameProperty("412", false)] 87 | public bool Fft { get; set; } 88 | 89 | [GameProperty("413", false)] 90 | public bool Loop { get; set; } 91 | 92 | [GameProperty("415", false)] 93 | public bool IsUnique { get; set; } 94 | 95 | [GameProperty("416", 0)] 96 | public int UniqueId { get; set; } 97 | 98 | [GameProperty("420", false)] 99 | public bool Override { get; set; } 100 | 101 | [GameProperty("421", 1f)] 102 | public float VolNear { get; set; } = 1f; 103 | 104 | [GameProperty("422", 0.5f)] 105 | public float VolMed { get; set; } = 0.5f; 106 | 107 | [GameProperty("423", 0f)] 108 | public float VolFar { get; set; } 109 | 110 | [GameProperty("424", 0f)] 111 | public int MinDist { get; set; } 112 | 113 | [GameProperty("425", 0f)] 114 | public int Dist2 { get; set; } 115 | 116 | [GameProperty("426", 0f)] 117 | public int Dist3 { get; set; } 118 | 119 | [GameProperty("428", false)] 120 | public bool Cam { get; set; } 121 | 122 | [GameProperty("433", false)] 123 | public bool PreLoad { get; set; } 124 | 125 | [GameProperty("434", 0f)] 126 | public float MinInterval { get; set; } 127 | 128 | [GameProperty("455", 0)] 129 | public int SfxGroup { get; set; } 130 | 131 | [GameProperty("458", SoundPropagationDirection.All)] 132 | public SoundPropagationDirection Propagation { get; set; } 133 | 134 | [GameProperty("489", false)] 135 | public bool IgnoreVolumeTest { get; set; } 136 | 137 | [GameProperty("490", false)] 138 | public float Duration { get; set; } 139 | 140 | [GameProperty("502", ReverbTypes.Generic)] 141 | public ReverbTypes ReverbType { get; set; } 142 | 143 | [GameProperty("503", false)] 144 | public bool EnableReverb { get; set; } 145 | 146 | public SfxTrigger() : base(3602) 147 | { 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/ShakeTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1520)] 7 | public class ShakeTrigger : Trigger 8 | { 9 | [GameProperty("10", 0.5f, true, Order = OrderTriggerBase + 1)] public float Duration { get; set; } = 0.5f; 10 | [GameProperty("75", 0f, false, Order = OrderTriggerBase + 2)] public float Strength { get; set; } 11 | [GameProperty("84", 0f, false, Order = OrderTriggerBase + 3)] public float Interval { get; set; } 12 | 13 | public override bool MultiTrigger 14 | { 15 | get => !multiTrigger; 16 | set => multiTrigger = !value; 17 | } 18 | 19 | public ShakeTrigger() : base(1520) 20 | { 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/ShowPlayerIconTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.GameObjects.Default; 2 | 3 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 4 | { 5 | [GameBlock(1613)] 6 | public class ShowPlayerIconTrigger : Trigger 7 | { 8 | public ShowPlayerIconTrigger() : base(1613) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/SongTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers; 5 | 6 | [GameBlock(1934)] 7 | public class SongTrigger : Trigger 8 | { 9 | [GameProperty("392", 0)] 10 | public int SongId { get; set; } 11 | 12 | [GameProperty("399", false)] 13 | public bool Prep { get; set; } 14 | 15 | [GameProperty("400", false)] 16 | public bool LoadPrep { get; set; } 17 | 18 | [GameProperty("404", 0)] 19 | public int Speed { get; set; } 20 | 21 | [GameProperty("406", 1f, alwaysSet: true)] 22 | public float Volume { get; set; } = 1f; 23 | 24 | [GameProperty("408", 0)] 25 | public int Start { get; set; } 26 | 27 | [GameProperty("409", 0)] 28 | public int FadeIn { get; set; } 29 | 30 | [GameProperty("410", 0)] 31 | public int End { get; set; } 32 | 33 | [GameProperty("411", 0)] 34 | public int FadeOut { get; set; } 35 | 36 | [GameProperty("413", false)] 37 | public bool Loop { get; set; } 38 | 39 | [GameProperty("432", 0)] 40 | public int Channel { get; set; } 41 | 42 | public SongTrigger() : base(1934) 43 | { 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/SpawnTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1268)] 7 | public class SpawnTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | [GameProperty("102", false, false, Order = OrderTriggerBase + 3)] public float EditorDisable { get; set; } 11 | 12 | public SpawnTrigger() : base(1268) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/StopTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1616)] 7 | public class StopTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | 11 | public StopTrigger() : base(1616) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/ToggleTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.GameObjects.Default; 3 | 4 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 5 | { 6 | [GameBlock(1049)] 7 | public class ToggleTrigger : Trigger 8 | { 9 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 10 | [GameProperty("56", false, false, Order = OrderTriggerBase + 2)] public bool ActivateGroup { get; set; } 11 | 12 | public ToggleTrigger() : base(1049) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/GameObjects/Triggers/TouchTrigger.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Levels.Enums; 3 | using GeometryDashAPI.Levels.GameObjects.Default; 4 | 5 | namespace GeometryDashAPI.Levels.GameObjects.Triggers 6 | { 7 | [GameBlock(1595)] 8 | public class TouchTrigger : Trigger 9 | { 10 | [GameProperty("51", 0, true, Order = OrderTriggerBase + 1)] public int TargetGroupId { get; set; } 11 | [GameProperty("81", false, false, Order = OrderTriggerBase + 2)] public bool HoldMode { get; set; } = false; 12 | [GameProperty("82", ToggleMode.None, false, Order = OrderTriggerBase + 3)] public ToggleMode ToggleMode { get; set; } = ToggleMode.None; 13 | [GameProperty("89", false, false, Order = OrderTriggerBase + 4)] public bool DualMode { get; set; } = false; 14 | 15 | public override bool MultiTrigger 16 | { 17 | get => !multiTrigger; 18 | set => multiTrigger = !value; 19 | } 20 | 21 | public TouchTrigger() : base(1595) 22 | { 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Guideline.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.Enums; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace GeometryDashAPI.Levels 7 | { 8 | public struct Guideline 9 | { 10 | public double Timestamp { get; set; } 11 | public GuidelineColor Color { get; set; } 12 | 13 | public override string ToString() 14 | { 15 | return $"TimeStamp: {GameConvert.DoubleToString(Timestamp)}, " + 16 | $"Color: {Color}"; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Guidelines.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.Enums; 2 | using GeometryDashAPI.Serialization; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace GeometryDashAPI.Levels 8 | { 9 | public class Guidelines : List 10 | { 11 | const string SEPERATOR = "~"; 12 | 13 | public static string Parse(Guidelines guidelines) 14 | { 15 | StringBuilder builder = new(); 16 | guidelines.ForEach(x => builder.Append(GameConvert.DoubleToString(x.Timestamp)).Append(SEPERATOR).Append(GetStringFromGuidelineColor(x.Color)).Append(SEPERATOR)); 17 | return builder.ToString(); 18 | } 19 | 20 | public static Guidelines Parse(ReadOnlySpan raw) 21 | { 22 | var guidelines = new Guidelines(); 23 | 24 | ReadOnlySpan value; 25 | var parser = new LLParserSpan(SEPERATOR.AsSpan(), raw); 26 | 27 | int index = 0; 28 | double timestamp = 0; 29 | while ((value = parser.Next()) != null) 30 | { 31 | index++; 32 | 33 | if (index % 2 == 0) 34 | { 35 | guidelines.Add(new() 36 | { 37 | Timestamp = timestamp, 38 | Color = GetGuidelineColorFromString(value) 39 | }); 40 | } 41 | else 42 | timestamp = GameConvert.StringToDouble(value); 43 | } 44 | 45 | return guidelines; 46 | } 47 | 48 | public static string GetStringFromGuidelineColor(GuidelineColor color) 49 | { 50 | return color switch 51 | { 52 | GuidelineColor.Orange => "0.8", 53 | GuidelineColor.Yellow => "0.9", 54 | GuidelineColor.Green => "1", 55 | _ => throw new IndexOutOfRangeException("undefined color") 56 | }; 57 | } 58 | 59 | public static GuidelineColor GetGuidelineColorFromString(ReadOnlySpan color) 60 | { 61 | return 62 | color.CompareTo("0".AsSpan(), StringComparison.Ordinal) == 0 ? GuidelineColor.Orange : 63 | color.CompareTo("0.8".AsSpan(), StringComparison.Ordinal) == 0 ? GuidelineColor.Orange : 64 | color.CompareTo("0.9".AsSpan(), StringComparison.Ordinal) == 0 ? GuidelineColor.Yellow : 65 | color.CompareTo("1".AsSpan(), StringComparison.Ordinal) == 0 ? GuidelineColor.Green : throw new IndexOutOfRangeException("unknown color"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Hsv.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Levels 4 | { 5 | public class Hsv 6 | { 7 | const char SEPARATOR = 'a'; 8 | 9 | public float Hue { get; set; } 10 | public float Saturation { get; set; } = 1; 11 | public float Brightness { get; set; } = 1; 12 | public bool DeltaSaturation { get; set; } 13 | public bool DeltaBrightness { get; set; } 14 | 15 | public bool IsDefault => Hue == 0 && Saturation == 1f && Brightness == 1f && !DeltaSaturation && !DeltaBrightness; 16 | 17 | public static string Parse(Hsv hsv) 18 | { 19 | return 20 | $"{hsv.Hue}{SEPARATOR}" + 21 | $"{GameConvert.SingleToString(hsv.Saturation)}{SEPARATOR}" + 22 | $"{GameConvert.SingleToString(hsv.Brightness)}{SEPARATOR}" + 23 | $"{GameConvert.BoolToString(hsv.DeltaSaturation)}{SEPARATOR}" + 24 | $"{GameConvert.BoolToString(hsv.DeltaBrightness)}"; 25 | } 26 | 27 | public static Hsv Parse(ReadOnlySpan data) => Parse(data.ToString()); 28 | 29 | public static Hsv Parse(string raw) 30 | { 31 | var result = new Hsv(); 32 | var dataArray = raw.Split(SEPARATOR); 33 | result.Hue = GameConvert.StringToSingle(dataArray[0].AsSpan()); 34 | result.Saturation = GameConvert.StringToSingle(dataArray[1].AsSpan()); 35 | result.Brightness = GameConvert.StringToSingle(dataArray[2].AsSpan()); 36 | result.DeltaSaturation = GameConvert.StringToBool(dataArray[3].AsSpan()); 37 | result.DeltaBrightness = GameConvert.StringToBool(dataArray[4]); 38 | 39 | return result; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/LevelDuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using GeometryDashAPI.Levels.GameObjects.Specific; 4 | 5 | namespace GeometryDashAPI.Levels 6 | { 7 | public static class LevelDuration 8 | { 9 | public static TimeSpan Measure(Level level) 10 | { 11 | var maxX = level.Blocks.Max(x => x.PositionX); 12 | var portals = GetSpeedBlocks(level); 13 | 14 | var seconds = 0d; 15 | var i = 1; 16 | for (; i < portals.Length; i++) 17 | seconds += (portals[i].PositionX - portals[i - 1].PositionX) / portals[i - 1].SpeedType.GetSpeed(); 18 | 19 | var final = Math.Min(i, portals.Length - 1); 20 | var total = seconds + (maxX - portals[final].PositionX) / portals[final].SpeedType.GetSpeed(); 21 | 22 | return TimeSpan.FromSeconds(total); 23 | } 24 | 25 | private static SpeedBlock[] GetSpeedBlocks(Level level) 26 | { 27 | return new[] { new SpeedBlock(level.Options.PlayerSpeed) } 28 | .Concat(level.Blocks.OfType() 29 | .Where(x => x.Checked) 30 | .OrderBy(x => x.PositionX) 31 | ).ToArray(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/LevelOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Levels.Enums; 4 | 5 | namespace GeometryDashAPI.Levels 6 | { 7 | [Sense(",")] 8 | public class LevelOptions : GameObject 9 | { 10 | [GameProperty("kS38", KeyOverride = 0)] 11 | [ArraySeparator("|", SeparatorAtTheEnd = true)] 12 | public List Colors { get; set; } 13 | 14 | [GameProperty("kA13", alwaysSet: true, KeyOverride = 1)] 15 | public float MusicOffset { get; set; } 16 | 17 | [GameProperty("kA15", alwaysSet: true, KeyOverride = 2)] 18 | public int Ka15 { get; set; } 19 | 20 | [GameProperty("kA16", alwaysSet: true, KeyOverride = 3)] 21 | public int Ka16 { get; set; } 22 | 23 | [GameProperty("kA14", KeyOverride = 4)] 24 | public Guidelines Guidelines { get; set; } 25 | 26 | [GameProperty("kA6", alwaysSet: true, KeyOverride = 5)] 27 | public short Background { get; set; } 28 | 29 | [GameProperty("kA7", alwaysSet: true, KeyOverride = 6)] 30 | public short Ground { get; set; } 31 | 32 | [GameProperty("kA17", alwaysSet: true, KeyOverride = 7)] 33 | public int Ka17 { get; set; } 34 | 35 | [GameProperty("kA18", alwaysSet: true, KeyOverride = 8)] 36 | public short Font { get; set; } 37 | 38 | [GameProperty("kS39", alwaysSet: true, KeyOverride = 9)] 39 | public int Ks39 { get; set; } 40 | 41 | [GameProperty("kA2", alwaysSet: true, KeyOverride = 10)] 42 | public GameMode GameMode { get; set; } 43 | 44 | [GameProperty("kA3", alwaysSet: true, KeyOverride = 11)] 45 | public bool IsMini { get; set; } 46 | 47 | [GameProperty("kA8", alwaysSet: true, KeyOverride = 12)] 48 | public bool IsDual { get; set; } 49 | 50 | [GameProperty("kA4", alwaysSet: true, KeyOverride = 13)] 51 | public SpeedType PlayerSpeed { get; set; } 52 | 53 | [GameProperty("kA9", alwaysSet: true, KeyOverride = 14)] 54 | public int Ka9 { get; set; } 55 | 56 | [GameProperty("kA10", alwaysSet: true, KeyOverride = 15)] 57 | public bool IsTwoPlayerMode { get; set; } 58 | 59 | [GameProperty("kA11", alwaysSet: true, KeyOverride = 16)] 60 | public bool IsFlippedGravity { get; set; } 61 | 62 | [GameProperty("kA1", KeyOverride = 17)] 63 | public int Ka1 { get; set; } 64 | 65 | [GameProperty("kS1", KeyOverride = 18)] 66 | public int Ks1 { get; set; } 67 | 68 | [GameProperty("kS2", KeyOverride = 19)] 69 | public int Ks2 { get; set; } 70 | 71 | [GameProperty("kS3", KeyOverride = 20)] 72 | public int Ks3 { get; set; } 73 | 74 | [GameProperty("kS4", KeyOverride = 21)] 75 | public int Ks4 { get; set; } 76 | 77 | [GameProperty("kS5", KeyOverride = 22)] 78 | public int Ks5 { get; set; } 79 | 80 | [GameProperty("kS6", KeyOverride = 23)] 81 | public int Ks6 { get; set; } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/LevelSpeed.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Levels.Enums; 2 | 3 | namespace GeometryDashAPI.Levels 4 | { 5 | public static class LevelSpeed 6 | { 7 | public const double Half = 251.16; 8 | public const double Default = 311.58; 9 | public const double X2 = 387.42; 10 | public const double X3 = 468; 11 | public const double X4 = 576; 12 | 13 | public static double GetSpeed(this SpeedType speedType) 14 | { 15 | return speedType switch 16 | { 17 | SpeedType.Half => Half, 18 | SpeedType.Default => Default, 19 | SpeedType.X2 => X2, 20 | SpeedType.X3 => X3, 21 | SpeedType.X4 => X4 22 | }; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GeometryDashAPI/Levels/Structures/RgbColor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace GeometryDashAPI.Levels.Structures 5 | { 6 | public struct RgbColor 7 | { 8 | public byte Red { get; set; } 9 | public byte Green { get; set; } 10 | public byte Blue { get; set; } 11 | 12 | public RgbColor(byte red, byte green, byte blue) 13 | { 14 | Red = red; 15 | Green = green; 16 | Blue = blue; 17 | } 18 | 19 | public override string ToString() => $"#{ToHex(this)}"; 20 | 21 | public static string ToHex(RgbColor rgb) => $"{rgb.Red:X2}{rgb.Green:X2}{rgb.Blue:X2}"; 22 | 23 | public static bool TryFromHex(ReadOnlySpan hex, out RgbColor rgb) 24 | { 25 | rgb = new RgbColor(); 26 | if (hex.Length != 6 && hex.Length != 7) 27 | return false; 28 | 29 | var baseIndex = hex[0] == '#' ? 1 : 0; 30 | if (!byte.TryParse(Slice(hex, baseIndex, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var r)) 31 | return false; 32 | if (!byte.TryParse(Slice(hex, baseIndex + 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var g)) 33 | return false; 34 | if (!byte.TryParse(Slice(hex, baseIndex + 4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var b)) 35 | return false; 36 | rgb.Red = r; 37 | rgb.Green = g; 38 | rgb.Blue = b; 39 | return true; 40 | } 41 | 42 | public static RgbColor FromHex(ReadOnlySpan hex) 43 | { 44 | if (TryFromHex(hex, out var rgb)) 45 | return rgb; 46 | throw new ArgumentException($"color '{hex.ToString()}' isn't looking as hex"); 47 | } 48 | 49 | #if NETSTANDARD2_1 50 | private static ReadOnlySpan Slice(ReadOnlySpan span, int start, int length) => span.Slice(start, length); 51 | #else 52 | private static string Slice(ReadOnlySpan span, int start, int length) => span.Slice(start, length).ToString(); 53 | #endif 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /GeometryDashAPI/Memory/Access.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Memory 2 | { 3 | public static class Access 4 | { 5 | public const int PROCESS_CREATE_PROCESS = 0x0080; 6 | public const int PROCESS_CREATE_THREAD = 0x0002; 7 | public const int PROCESS_DUP_HANDLE = 0x0040; 8 | public const int PROCESS_QUERY_INFORMATION = 0x0400; 9 | public const int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000; 10 | public const int PROCESS_SET_INFORMATION = 0x0200; 11 | public const int PROCESS_SET_QUOTA = 0x0100; 12 | public const int PROCESS_SUSPEND_RESUME = 0x0800; 13 | public const int PROCESS_TERMINATE = 0x0001; 14 | public const int PROCESS_VM_OPERATION = 0x0008; 15 | public const int PROCESS_VM_READ = 0x0010; 16 | public const int PROCESS_VM_WRITE = 0x0020; 17 | public const long SYNCHRONIZE = 0x00100000L; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /GeometryDashAPI/OfficialLevel.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI; 2 | 3 | public enum OfficialLevel 4 | { 5 | StereoMadness = 1, 6 | BackOnTrack = 2, 7 | Polargeist = 3, 8 | DryOut = 4, 9 | BaseAfterBase = 5, 10 | CantLetGo = 6, 11 | Jumper = 7, 12 | TimeMachine = 8, 13 | Cycles = 9, 14 | xStep = 10, 15 | Clutterfunk = 11, 16 | TheoryOfEverything = 12, 17 | ElectromanAdventures = 13, 18 | Clubstep = 14, 19 | Electrodynamix = 15, 20 | HexagonForce = 16, 21 | BlastProcessing = 17, 22 | TheoryOfEverything2 = 18, 23 | GeometricalDominator = 19, 24 | Deadlocked = 20, 25 | Fingerdash = 21, 26 | 27 | TheChallenge = 3001, 28 | 29 | TheSevenSeas = 1001, 30 | VikingArena = 1002, 31 | AirborneRobots = 1003, 32 | 33 | Payload = 2001, 34 | BeastMode = 2002, 35 | Machina = 2003, 36 | Years = 2004, 37 | Frontlines = 2005, 38 | SpacePirates = 2006, 39 | Striker = 2007, 40 | Embers = 2008, 41 | Round1 = 2009, 42 | MonsterDanceOff = 2010 43 | } 44 | -------------------------------------------------------------------------------- /GeometryDashAPI/Property.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI 2 | { 3 | public readonly struct Property 4 | { 5 | public readonly string Key; 6 | public readonly string Value; 7 | 8 | public Property(object key, object value) 9 | { 10 | Key = key.ToString(); 11 | Value = value.ToString(); 12 | } 13 | 14 | public override string ToString() 15 | { 16 | return $"{Key} - {Value}"; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/IDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace GeometryDashAPI.Serialization 5 | { 6 | public interface IDescriptor where T : IGameObject 7 | { 8 | T Create(); 9 | T Create(ReadOnlySpan raw); 10 | } 11 | 12 | public interface ICopyDescriptor where T : IGameObject 13 | { 14 | void CopyTo(T instance, StringBuilder destination); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/IGameSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace GeometryDashAPI.Serialization 6 | { 7 | public interface IGameSerializer 8 | { 9 | delegate T Parser(ReadOnlySpan data); 10 | 11 | T Decode(ReadOnlySpan raw) where T : IGameObject; 12 | ReadOnlySpan Encode(T value) where T : IGameObject; 13 | 14 | Action GetCopier(Type type); 15 | 16 | List DecodeList(ReadOnlySpan raw, string separator) where T : IGameObject; 17 | T[] GetArray(ReadOnlySpan raw, string separator, Parser getValue); 18 | 19 | IGameObject DecodeBlock(ReadOnlySpan raw); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/MemberDescription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using GeometryDashAPI.Attributes; 5 | 6 | namespace GeometryDashAPI.Serialization 7 | { 8 | public class MemberDescription 9 | { 10 | public readonly MemberInfo Member; 11 | public readonly TAttribute Attribute; 12 | public readonly bool IsProperty; 13 | public readonly ArraySeparatorAttribute ArraySeparatorAttribute; 14 | 15 | public Type MemberType => IsProperty ? ((PropertyInfo) Member).PropertyType : ((FieldInfo) Member).FieldType; 16 | 17 | public MemberDescription(MemberInfo member, TAttribute attribute) 18 | { 19 | Member = member; 20 | IsProperty = member is PropertyInfo; 21 | Attribute = attribute; 22 | 23 | if (MemberType!.IsGenericType && 24 | MemberType.GetGenericTypeDefinition() == typeof(List<>)) 25 | ArraySeparatorAttribute = member.GetCustomAttribute(); 26 | } 27 | 28 | public void SetValue(object instance, object value) 29 | { 30 | if (IsProperty) 31 | { 32 | ((PropertyInfo) Member).SetValue(instance, value); 33 | return; 34 | } 35 | ((FieldInfo) Member).SetValue(instance, value); 36 | } 37 | 38 | public object GetValue(object instance) 39 | { 40 | if (IsProperty) 41 | return ((PropertyInfo) Member).GetValue(instance); 42 | return ((FieldInfo) Member).GetValue(instance); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/Parsers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GeometryDashAPI.Levels; 3 | using GeometryDashAPI.Server; 4 | 5 | // ReSharper disable UnusedMember.Local 6 | 7 | namespace GeometryDashAPI.Serialization 8 | { 9 | // note: The names are dependent! 10 | // Used for TypeDescriptor 11 | // name pattern: __ 12 | // options: Behavior on boundary cases 13 | // GetOrDefault, ... 14 | // type: Name of member type 15 | // is nullable: 16 | // Y - is enable nullable 17 | // _ - is disable 18 | internal class Parsers 19 | { 20 | public static bool GetOrDefault_Boolean__(ReadOnlySpan data) => GameConvert.StringToBool(data); 21 | #if NETSTANDARD2_1 22 | public static byte GetOrDefault_Byte__(ReadOnlySpan data) => byte.TryParse(data, out var value) ? value : default; 23 | public static sbyte GetOrDefault_SByte__(ReadOnlySpan data) => sbyte.TryParse(data, out var value) ? value : default; 24 | public static short GetOrDefault_Int16__(ReadOnlySpan data) => short.TryParse(data, out var value) ? value : default; 25 | public static int GetOrDefault_Int32__(ReadOnlySpan data) => int.TryParse(data, out var value) ? value : default; 26 | public static int? GetOrDefault_Int32_Y(ReadOnlySpan data) => int.TryParse(data, out var value) ? value : default; 27 | public static long GetOrDefault_Int64__(ReadOnlySpan data) => long.TryParse(data, out var value) ? value : default; 28 | #else 29 | public static byte GetOrDefault_Byte__(ReadOnlySpan data) => byte.TryParse(data.ToString(), out var value) ? value : default; 30 | public static sbyte GetOrDefault_SByte__(ReadOnlySpan data) => sbyte.TryParse(data.ToString(), out var value) ? value : default; 31 | public static short GetOrDefault_Int16__(ReadOnlySpan data) => short.TryParse(data.ToString(), out var value) ? value : default; 32 | public static int GetOrDefault_Int32__(ReadOnlySpan data) => int.TryParse(data.ToString(), out var value) ? value : default; 33 | public static int? GetOrDefault_Int32_Y(ReadOnlySpan data) => int.TryParse(data.ToString(), out var value) ? value : default; 34 | public static long GetOrDefault_Int64__(ReadOnlySpan data) => long.TryParse(data.ToString(), out var value) ? value : default; 35 | #endif 36 | public static double GetOrDefault_Double__(ReadOnlySpan data) => GameConvert.StringToDouble(data); 37 | public static float GetOrDefault_Single__(ReadOnlySpan data) => GameConvert.StringToSingle(data); 38 | public static string GetOrDefault_String__(ReadOnlySpan data) => data.ToString(); 39 | public static BlockGroup GetOrDefault_BlockGroup__(ReadOnlySpan data) => BlockGroup.Parse(data); 40 | public static Hsv GetOrDefault_Hsv__(ReadOnlySpan data) => Hsv.Parse(data); 41 | public static Pagination GetOrDefault_Pagination__(ReadOnlySpan data) => Pagination.Parse(data); 42 | public static Guidelines GetOrDefault_Guidelines__(ReadOnlySpan data) => Guidelines.Parse(data); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/PrinterInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace GeometryDashAPI.Serialization 5 | { 6 | internal class PrinterInfo 7 | { 8 | public TypeDescriptorHelper.Printer Printer { get; } 9 | public TypeDescriptorHelper.Getter IsDefault { get; } 10 | public GamePropertyAttribute Attribute { get; } 11 | 12 | #if DEBUG 13 | public Expression> PrinterExp { get; set; } 14 | public Expression> IsDefaultExp { get; set; } 15 | public string Name { get; set; } 16 | #endif 17 | 18 | public PrinterInfo( 19 | TypeDescriptorHelper.Printer printer, 20 | TypeDescriptorHelper.Getter isDefault, 21 | GamePropertyAttribute attribute) 22 | { 23 | Printer = printer; 24 | IsDefault = isDefault; 25 | Attribute = attribute; 26 | } 27 | 28 | #if DEBUG 29 | public override string ToString() => Name; 30 | #endif 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/Printers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using GeometryDashAPI.Levels; 4 | using GeometryDashAPI.Server; 5 | 6 | namespace GeometryDashAPI.Serialization 7 | { 8 | // note: The names are dependent! 9 | // Used for TypeDescriptor 10 | internal class Printers 11 | { 12 | public static ReadOnlySpan GetOrDefault_Boolean__(bool value) => GameConvert.BoolToString(value).AsSpan(); 13 | public static ReadOnlySpan GetOrDefault_Byte__(byte value) => value.ToString().AsSpan(); 14 | public static ReadOnlySpan GetOrDefault_SByte__(sbyte value) => value.ToString().AsSpan(); 15 | public static ReadOnlySpan GetOrDefault_Int16__(short value) => value.ToString().AsSpan(); 16 | public static ReadOnlySpan GetOrDefault_Int32__(int value) => value.ToString().AsSpan(); 17 | public static ReadOnlySpan GetOrDefault_Int32_Y(int? value) => value.ToString().AsSpan(); 18 | public static ReadOnlySpan GetOrDefault_Int64__(long value) => value.ToString().AsSpan(); 19 | public static ReadOnlySpan GetOrDefault_Double__(double value) => GameConvert.DoubleToString(value).AsSpan(); 20 | public static ReadOnlySpan GetOrDefault_Single__(float value) => GameConvert.SingleToString(value).AsSpan(); 21 | public static ReadOnlySpan GetOrDefault_String__(string value) => value.AsSpan(); 22 | public static ReadOnlySpan GetOrDefault_BlockGroup__(BlockGroup value) => value.ToString().AsSpan(); 23 | public static ReadOnlySpan GetOrDefault_Hsv__(Hsv value) => Hsv.Parse(value).AsSpan(); 24 | public static ReadOnlySpan GetOrDefault_Pagination__(Pagination value) => Pagination.Serialize(value).AsSpan(); 25 | public static ReadOnlySpan GetOrDefault_Guidelines__(Guidelines value) => Guidelines.Parse(value).AsSpan(); 26 | 27 | public delegate void PrinterAppend(TInstance instance, StringBuilder destination); 28 | public static void PrintArray(T[] array, string separator, StringBuilder destination, PrinterAppend append) 29 | { 30 | var shouldIncludeSeparator = false; 31 | if (array == null) 32 | return; 33 | foreach (var item in array) 34 | { 35 | if (shouldIncludeSeparator) 36 | destination.Append(separator); 37 | shouldIncludeSeparator = true; 38 | append(item, destination); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/SetterInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace GeometryDashAPI.Serialization; 5 | 6 | internal readonly struct SetterInfo 7 | { 8 | public readonly TypeDescriptorHelper.Setter Setter; 9 | private readonly GamePropertyAttribute attribute; 10 | private readonly MemberInfo member; 11 | 12 | public SetterInfo(TypeDescriptorHelper.Setter setter, GamePropertyAttribute attribute, MemberInfo member) 13 | { 14 | Setter = setter; 15 | this.attribute = attribute; 16 | this.member = member; 17 | } 18 | 19 | public override string ToString() => $"setter for: {attribute.Key} ({member.Name}) [{(member is PropertyInfo ? "property" : "field")}], from: {member.DeclaringType}"; 20 | } 21 | -------------------------------------------------------------------------------- /GeometryDashAPI/Serialization/TypeDescriptorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace GeometryDashAPI.Serialization; 4 | 5 | public static class TypeDescriptorExtensions 6 | { 7 | public static string AsString(this TypeDescriptor descriptor, T value) where T : IGameObject 8 | { 9 | var builder = new StringBuilder(); 10 | descriptor.CopyTo(value, builder); 11 | return builder.ToString(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/Account.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using GeometryDashAPI.Attributes; 4 | using GeometryDashAPI.Server.Enums; 5 | 6 | namespace GeometryDashAPI.Server.Dtos 7 | { 8 | [Sense(":")] 9 | public class Account : GameObject 10 | { 11 | [GameProperty("1")] public string Name { get; set; } 12 | [GameProperty("2")] public int UserId { get; set; } 13 | [GameProperty("3")] public int Stars { get; set; } 14 | [GameProperty("4")] public int Demons { get; set; } 15 | [GameProperty("6")] public int Rank { get; set; } 16 | [GameProperty("7")] public int Highlight { get; set; } 17 | [GameProperty("8")] public int CreatorPoints { get; set; } 18 | [GameProperty("9")] public int IconPrev { get; set; } 19 | [GameProperty("10")] public int Color1 { get; set; } 20 | [GameProperty("11")] public int Color2 { get; set; } 21 | [GameProperty("13")] public int SecretCoins { get; set; } 22 | [GameProperty("14")] public int IconType { get; set; } 23 | [GameProperty("15")] public int Special { get; set; } 24 | [GameProperty("16")] public int AccountId { get; set; } 25 | [GameProperty("17")] public int UserCoins { get; set; } 26 | [GameProperty("18")] public AllowMessagesFrom MessageState { get; set; } 27 | [GameProperty("19")] public int FriendsState { get; set; } 28 | [GameProperty("20")] public string YouTubeId { get; set; } 29 | [GameProperty("21")] public int CubeId { get; set; } 30 | [GameProperty("22")] public int ShipId { get; set; } 31 | [GameProperty("23")] public int BallId { get; set; } 32 | [GameProperty("24")] public int BirdId { get; set; } 33 | [GameProperty("25")] public int WaveId { get; set; } 34 | [GameProperty("26")] public int RobotId { get; set; } 35 | [GameProperty("27")] public int StreakId { get; set; } 36 | [GameProperty("28")] public int GlowId { get; set; } 37 | [GameProperty("29")] public bool IsRegistered { get; set; } 38 | [GameProperty("30")] public int GlobalRank { get; set; } 39 | [GameProperty("31")] public int UsFriendState { get; set; } 40 | [GameProperty("38")] public int Messages { get; set; } 41 | [GameProperty("39")] public int FriendRequests { get; set; } 42 | [GameProperty("40")] public bool NewFriends { get; set; } 43 | [GameProperty("41")] public int NewFriendRequests { get; set; } 44 | [GameProperty("42")] public int TimeSinceSubmittedLevel { get; set; } 45 | [GameProperty("43")] public int SpiderId { get; set; } 46 | [GameProperty("44")] public string TwitterId { get; set; } 47 | [GameProperty("45")] public string TwitchId { get; set; } 48 | [GameProperty("46")] public int Diamonds { get; set; } 49 | [GameProperty("48")] public int ExplosionId { get; set; } 50 | [GameProperty("49")] public GameModeratorType ModeratorType { get; set; } 51 | 52 | [Obsolete("Use ModeratorType instead.")] 53 | public int Moderator 54 | { 55 | get => (int)ModeratorType; 56 | set => ModeratorType = (GameModeratorType)value; 57 | } 58 | 59 | [GameProperty("50")] public int CommentHistoryState { get; set; } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/AccountComment.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Dtos 4 | { 5 | [Sense("~")] 6 | public class AccountComment : GameObject 7 | { 8 | [GameProperty("2")] private string comment; 9 | public string Comment 10 | { 11 | get => GameConvert.FromBase64String(comment); 12 | set => comment = GameConvert.ToBase64String(value); 13 | } 14 | [GameProperty("4")] public int Likes { get; set; } 15 | [GameProperty("6")] public int Id { get; set; } 16 | [GameProperty("9")] public string Date { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/AuthorIds.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Dtos 4 | { 5 | [AsStruct] 6 | [Sense(":")] 7 | public class AuthorIds : GameObject 8 | { 9 | [GameProperty("0")] public int UserId { get; set; } 10 | [GameProperty("1")] public string UserName { get; set; } 11 | [GameProperty("2")] public int AccountId { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/LevelInfo.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Dtos 4 | { 5 | [Sense(":")] 6 | public class LevelInfo : LevelPreview 7 | { 8 | [GameProperty("4")] 9 | public string LevelString { get; set; } 10 | 11 | [GameProperty("27")] 12 | private string rawPassword; 13 | public string RawPassword // Are you need decrypt? I can do it later. On the clock 12:25 am 14 | { 15 | get => rawPassword; 16 | set => rawPassword = value; 17 | } 18 | 19 | [GameProperty("28")] 20 | public string UploadDateTime { get; set; } 21 | 22 | [GameProperty("29")] 23 | public string SecondDateTime { get; set; } 24 | 25 | [GameProperty("36")] 26 | public string ExtraString { get; set; } 27 | 28 | [GameProperty("40")] 29 | public bool LowDetail { get; set; } 30 | } 31 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/LevelPreview.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Server.Enums; 4 | 5 | namespace GeometryDashAPI.Server.Dtos 6 | { 7 | [Sense(":")] 8 | public class LevelPreview : GameObject 9 | { 10 | [GameProperty("1")] 11 | public int Id { get; set; } 12 | 13 | [GameProperty("2")] 14 | public string Name { get; set; } 15 | 16 | [GameProperty("3")] 17 | private string description; 18 | 19 | public string Description 20 | { 21 | get 22 | { 23 | var value = description; 24 | if ((value.Length % 4) != 0) 25 | value = $"{value}{new string('=', 4 - value.Length % 4)}"; 26 | return GameConvert.FromBase64String(value); 27 | } 28 | set 29 | { 30 | var base64 = GameConvert.ToBase64String(value); 31 | description = base64.Length > 255 ? base64.Remove(255, base64.Length - 255) : base64; 32 | } 33 | } 34 | 35 | [GameProperty("5")] 36 | public int Version { get; set; } 37 | 38 | [GameProperty("6")] 39 | public int AuthorUserId { get; set; } 40 | 41 | [GameProperty("8")] 42 | public Difficulty Difficulty { get; set; } 43 | 44 | [GameProperty("9")] 45 | public DifficultyIcon DifficultyIcon { get; set; } 46 | 47 | [GameProperty("10")] 48 | public int Downloads { get; set; } 49 | 50 | [Obsolete] 51 | [GameProperty("11")] 52 | public int Completes { get; set; } 53 | 54 | [GameProperty("12")] 55 | public int OfficialSong { get; set; } 56 | 57 | [GameProperty("13")] 58 | public int GameVersion { get; set; } 59 | 60 | [GameProperty("14")] 61 | public int Likes { get; set; } 62 | 63 | [GameProperty("15")] 64 | public LengthType Length { get; set; } 65 | 66 | [GameProperty("17")] 67 | public bool Demon { get; set; } 68 | 69 | [GameProperty("18")] 70 | public int Stars { get; set; } 71 | 72 | [GameProperty("19")] 73 | public int FeatureScore { get; set; } 74 | 75 | [GameProperty("25")] 76 | public bool Auto { get; set; } 77 | 78 | [GameProperty("30")] 79 | public int CopiedId { get; set; } 80 | 81 | [GameProperty("31")] 82 | public bool TwoPlayer { get; set; } 83 | 84 | [GameProperty("35")] 85 | public int MusicId { get; set; } 86 | 87 | [GameProperty("37")] 88 | public int Coins { get; set; } 89 | 90 | [GameProperty("38")] 91 | public bool CoinsVerified { get; set; } 92 | 93 | [GameProperty("39")] 94 | public int StarsRequested { get; set; } 95 | 96 | [GameProperty("42")] 97 | public bool Epic { get; set; } 98 | 99 | [GameProperty("43")] 100 | public DemonDifficulty DemonDifficulty { get; set; } 101 | 102 | [GameProperty("45")] 103 | public int Objects { get; set; } 104 | 105 | [GameProperty("46")] 106 | public int? EditorTime { get; set; } 107 | 108 | [GameProperty("47")] 109 | public int? EditorTimeCopies { get; set; } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/Message.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace GeometryDashAPI.Server.Dtos; 5 | 6 | public class Message : IQuery 7 | { 8 | private static readonly string BodyXorKey = "14251"; 9 | 10 | public string Subject { get; set; } 11 | public string Body { get; set; } 12 | 13 | public static Message FromRaw(string subject, string body) 14 | { 15 | return new Message() 16 | { 17 | Subject = DeserializeSubject(subject), 18 | Body = DeserializeBody(body) 19 | }; 20 | } 21 | 22 | public Parameters BuildQuery() 23 | { 24 | var parameters = new Parameters(); 25 | BuildQuery(parameters); 26 | return parameters; 27 | } 28 | 29 | public void BuildQuery(Parameters parameters) 30 | { 31 | parameters.Add(new Property("subject", SerializeSubject(Subject))); 32 | parameters.Add(new Property("body", SerializeBody(Body))); 33 | } 34 | 35 | internal static string DeserializeSubject(string raw) => Encoding.UTF8.GetString(Convert.FromBase64String(raw)); 36 | internal static string SerializeSubject(string subject) => Convert.ToBase64String(Encoding.ASCII.GetBytes(subject)); 37 | 38 | internal static string DeserializeBody(string raw) => Crypt.XOR(Encoding.UTF8.GetString(Convert.FromBase64String(raw)), BodyXorKey); 39 | internal static string SerializeBody(string body) => Convert.ToBase64String(Encoding.ASCII.GetBytes(Crypt.XOR(body, BodyXorKey))); 40 | } 41 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/MessageContent.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Dtos; 4 | 5 | [Sense(":")] 6 | public class MessageContent : MessagePreview 7 | { 8 | [GameProperty("5")] 9 | private string body; 10 | 11 | public string Body 12 | { 13 | get => Message.DeserializeBody(body); 14 | set => Message.SerializeBody(value); 15 | } 16 | 17 | public Message Message => new() 18 | { 19 | Body = Message.DeserializeBody(body), 20 | Subject = Subject 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/MessagePreview.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Dtos; 4 | 5 | [Sense(":")] 6 | public class MessagePreview : GameObject 7 | { 8 | [GameProperty("1")] 9 | public int MessageId { get; set; } 10 | 11 | [GameProperty("2")] 12 | public int SenderAccountId { get; set; } 13 | 14 | [GameProperty("3")] 15 | public int SenderUserId { get; set; } 16 | 17 | [GameProperty("4")] 18 | private string subject; 19 | 20 | public string Subject 21 | { 22 | get => Message.DeserializeSubject(subject); 23 | set => Message.SerializeSubject(value); 24 | } 25 | 26 | [GameProperty("6")] 27 | public string SenderUserName { get; set; } 28 | 29 | [GameProperty("7")] 30 | public string Time { get; set; } 31 | 32 | [GameProperty("8")] 33 | public bool HasBeenRead { get; set; } 34 | 35 | public override string ToString() 36 | { 37 | return $"Letter '{Subject}' from {SenderUserName}({SenderAccountId})"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/MusicInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace GeometryDashAPI.Server.Dtos 5 | { 6 | [Sense("~|~")] 7 | public class MusicInfo : GameObject 8 | { 9 | [GameProperty("1")] public int MusicId { get; set; } 10 | [GameProperty("2")] public string MusicName { get; set; } 11 | [GameProperty("4")] public string AuthorName { get; set; } 12 | [GameProperty("5")] public double SizeInMb { get; set; } 13 | [GameProperty("10")] private string url; 14 | public string Url 15 | { 16 | get => Uri.UnescapeDataString(url); 17 | set => url = Uri.EscapeDataString(value); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Dtos/UserPreview.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Dtos 4 | { 5 | [Sense(":")] 6 | public class UserPreview : GameObject 7 | { 8 | [GameProperty("1")] public string Name { get; set; } 9 | [GameProperty("2")] public int UserId { get; set; } 10 | [GameProperty("3")] public int Stars { get; set; } 11 | [GameProperty("4")] public int Demons { get; set; } 12 | [GameProperty("6")] public string K6 { get; set; } 13 | [GameProperty("8")] public int CreatorPoints { get; set; } 14 | [GameProperty("9")] public int IconPreview { get; set; } 15 | [GameProperty("10")] public int Color1 { get; set; } 16 | [GameProperty("11")] public int Color2 { get; set; } 17 | [GameProperty("13")] public int SecretCoins { get; set; } 18 | [GameProperty("14")] public int IconType { get; set; } 19 | [GameProperty("15")] public int Special { get; set; } 20 | [GameProperty("16")] public int AccountId { get; set; } 21 | [GameProperty("17")] public int UserCoins { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/AllowMessagesFrom.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums; 2 | 3 | public enum AllowMessagesFrom 4 | { 5 | All = 0, 6 | Friends = 1, 7 | None = 2 8 | } 9 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/DataType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums 2 | { 3 | public enum DataType 4 | { 5 | LevelTitle, 6 | CreatorName 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/DemonDifficulty.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums; 2 | 3 | public enum DemonDifficulty 4 | { 5 | Hard = 0, 6 | Easy = 3, 7 | Medium = 4, 8 | Insane = 5, 9 | Extreme = 6 10 | } 11 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/Difficulty.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums; 2 | 3 | public enum Difficulty 4 | { 5 | Hard = 0, 6 | Easy = 3, 7 | Normal = 4, 8 | Harder = 5, 9 | Insane = 6, 10 | } 11 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/DifficultyIcon.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums; 2 | 3 | public enum DifficultyIcon 4 | { 5 | Auto = 10, 6 | Normal = 20, 7 | Hard = 30, 8 | Harder = 40, 9 | Insane = 50 10 | } 11 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/GameModeratorType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums; 2 | 3 | public enum GameModeratorType 4 | { 5 | Player, 6 | Moderator, 7 | EldedModerator 8 | } 9 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/LengthType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums 2 | { 3 | public enum LengthType 4 | { 5 | Tiny = 0, 6 | Short = 1, 7 | Medium = 2, 8 | Long = 3, 9 | XL = 4, 10 | Platformer 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/OfficialSong.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums 2 | { 3 | public enum OfficialSong 4 | { 5 | NotChoosen, 6 | StereoMadness, 7 | BackOnTrack, 8 | Polargeist, 9 | DryOut, 10 | BaseAfterBase, 11 | CantLetGo, 12 | Jumper, 13 | TimeMachine, 14 | Cycles, 15 | xStep, 16 | ClutterFunk, 17 | TheoryOfEverything, 18 | ElectromanAdventures, 19 | Clubstep, 20 | Electrodynamix, 21 | HexagonForce, 22 | BlastProcces, 23 | TheoryOfEverything2, 24 | GeometricalDominator, 25 | DeadLocked, 26 | FingerBang 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/SearchDemonDifficulty.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums 2 | { 3 | public enum SearchDemonDifficulty 4 | { 5 | Easy = 1, 6 | Medium, 7 | Hard, 8 | Insane, 9 | Extreme 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/SearchDifficulty.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums 2 | { 3 | public enum SearchDifficulty 4 | { 5 | Auto = -3, 6 | Demon, 7 | NA, 8 | NoFilter, 9 | Easy, 10 | Normal, 11 | Hard, 12 | Harder, 13 | Insane, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/SearchType.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Enums 2 | { 3 | public enum SearchType 4 | { 5 | ByString, 6 | MostDownloaded, 7 | MostLiked, 8 | Trending, 9 | Recent, 10 | OnAccaunt = 5, 11 | Featured = 6, 12 | Magic, 13 | MapPack = 10, 14 | Awarded, 15 | Followed, 16 | Friends, 17 | HallOfFame = 16 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Enums/TopType.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Enums 4 | { 5 | public enum TopType 6 | { 7 | [OriginalName("top")] Top, 8 | [OriginalName("friends")] Friends, 9 | [OriginalName("relative")] Global, 10 | [OriginalName("creators")] Creators 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/IGameClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using GeometryDashAPI.Server.Dtos; 3 | using GeometryDashAPI.Server.Enums; 4 | using GeometryDashAPI.Server.Queries; 5 | using GeometryDashAPI.Server.Responses; 6 | 7 | namespace GeometryDashAPI.Server; 8 | 9 | public interface IGameClient 10 | { 11 | Task> GetTopAsync(TopType type, int count); 12 | Task> SearchLevelsAsync(GetLevelsQuery getLevelsQuery); 13 | Task> GetFeaturedLevelsAsync(int page); 14 | Task> LoginAsync(string username, string password); 15 | Task> GetAccountCommentsAsync(int accountId, int page); 16 | Task> SearchUserAsync(string name); 17 | Task> DownloadLevelAsync(int id); 18 | Task> GetAccountAsync(int accountId); 19 | Task> GetMyLevelsAsync(PasswordQuery account, int userId, int page); 20 | Task> SendMessageAsync(PasswordQuery fromAccount, int toAccountId, Message message); 21 | Task> GetMessagesAsync(PasswordQuery account, int page); 22 | Task> ReadMessageAsync(PasswordQuery account, int messageId); 23 | } 24 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/IQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace GeometryDashAPI.Server 6 | { 7 | public interface IQuery 8 | { 9 | Parameters BuildQuery(); 10 | void BuildQuery(Parameters parameters); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Network.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using GeometryDashAPI.Factories; 7 | 8 | namespace GeometryDashAPI.Server 9 | { 10 | public class Network 11 | { 12 | private readonly IFactory httpClientFactory; 13 | private readonly string server; 14 | private readonly Func responseFilter; 15 | public int Timeout { get; set; } = 30_000; 16 | 17 | public Network(string server = "http://www.boomlings.com/database", IFactory httpClientFactory = null, Func responseFilter = null) 18 | { 19 | this.httpClientFactory = httpClientFactory ?? new DefaultHttpClientFactory(); 20 | this.server = server; 21 | this.responseFilter = responseFilter; 22 | } 23 | 24 | public async Task<(HttpStatusCode statusCode, string body)> GetAsync(string path, IQuery query) 25 | { 26 | return await GetUseHttpClient(path, query.BuildQuery()); 27 | } 28 | 29 | private async Task<(HttpStatusCode statusCode, string body)> GetUseHttpClient(string path, Parameters properties) 30 | { 31 | using var httpClient = httpClientFactory.Create(); 32 | httpClient.Timeout = TimeSpan.FromMilliseconds(Timeout); 33 | 34 | using var response = await httpClient.PostAsync($"{server}{path}", 35 | new StringContent(properties.ToString(), Encoding.UTF8, "application/x-www-form-urlencoded")); 36 | 37 | var result = await response.Content.ReadAsStringAsync(); 38 | if (responseFilter != null && !responseFilter(result)) 39 | throw new Exception("Invalid data by response filter"); 40 | var statusCode = response.StatusCode; 41 | return (statusCode, result); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Pagination.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | using GeometryDashAPI.Serialization; 4 | 5 | namespace GeometryDashAPI.Server 6 | { 7 | public class Pagination 8 | { 9 | public int TotalCount { get; private set; } 10 | public int RangeIn { get; private set; } 11 | public int RangeOut { get; private set; } 12 | public int CountOnPage => RangeOut - RangeIn; 13 | 14 | public Pagination() 15 | { 16 | } 17 | 18 | public Pagination(int total, int rangeIn, int rangeOut) 19 | { 20 | TotalCount = total; 21 | RangeIn = rangeIn; 22 | RangeOut = rangeOut; 23 | } 24 | 25 | public bool HasPage(int page) 26 | { 27 | return page * CountOnPage < TotalCount; 28 | } 29 | 30 | public static Pagination Parse(ReadOnlySpan data) => Parse(data.ToString()); 31 | 32 | public static Pagination Parse(string raw) 33 | { 34 | var parser = new LLParserSpan(":".AsSpan(), raw.AsSpan()); 35 | var result = new Pagination(); 36 | #if NETSTANDARD2_1 37 | result.TotalCount = int.TryParse(parser.Next(), out var total) ? total : 0; 38 | result.RangeIn = int.Parse(parser.Next()); 39 | result.RangeOut = int.Parse(parser.Next()); 40 | #else 41 | result.TotalCount = int.TryParse(parser.Next().ToString(), out var total) ? total : 0; 42 | result.RangeIn = int.Parse(parser.Next().ToString()); 43 | result.RangeOut = int.Parse(parser.Next().ToString()); 44 | #endif 45 | return result; 46 | } 47 | 48 | public static string Serialize(Pagination pagination) 49 | { 50 | return $"{pagination.TotalCount}:{pagination.RangeIn}:{pagination.RangeOut}"; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Parameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace GeometryDashAPI.Server 6 | { 7 | public class Parameters : List 8 | { 9 | public override string ToString() 10 | { 11 | var requestContent = new StringBuilder(); 12 | var first = true; 13 | foreach (var property in this) 14 | { 15 | if (!first) 16 | requestContent.Append('&'); 17 | AppendProperty(requestContent, property); 18 | first = false; 19 | } 20 | 21 | return requestContent.ToString(); 22 | } 23 | 24 | private void AppendProperty(StringBuilder builder, Property property) 25 | { 26 | builder.Append(property.Key); 27 | builder.Append('='); 28 | builder.Append(property.Value); 29 | } 30 | 31 | public static Parameters FromString(string data) 32 | { 33 | throw new NotImplementedException(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Queries/FlexibleQuery.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace GeometryDashAPI.Server.Queries 4 | { 5 | public class FlexibleQuery : IQuery 6 | { 7 | private LinkedList queriesChain = new LinkedList(); 8 | private LinkedList additionalProperties = new LinkedList(); 9 | 10 | public Parameters BuildQuery() 11 | { 12 | Parameters result = new Parameters(); 13 | BuildQuery(result); 14 | return result; 15 | } 16 | 17 | public void BuildQuery(Parameters parameters) 18 | { 19 | foreach (var query in queriesChain) 20 | query.BuildQuery(parameters); 21 | parameters.AddRange(additionalProperties); 22 | } 23 | 24 | public FlexibleQuery AddToChain(IQuery query) 25 | { 26 | queriesChain.AddLast(query); 27 | return this; 28 | } 29 | 30 | public FlexibleQuery AddProperty(Property property) 31 | { 32 | additionalProperties.AddLast(property); 33 | return this; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Queries/GetLevelsQuery.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GeometryDashAPI.Server.Enums; 3 | 4 | namespace GeometryDashAPI.Server.Queries 5 | { 6 | public class GetLevelsQuery : IQuery 7 | { 8 | public string QueryString { get; set; } = "-"; 9 | public bool IsOfficialSong { get; private set; } 10 | public int SongId { get; private set; } 11 | public SearchType SearchType { get; set; } = SearchType.MostLiked; 12 | public List Lengths { get; set; } = new List(); 13 | public List Difficults { get; set; } = new List(); 14 | public SearchDemonDifficulty SearchDemonDifficulty { get; set; } 15 | public int Page { get; set; } = 0; 16 | public int Total { get; set; } = 0; 17 | public int Feautured { get; set; } = -1; 18 | public bool Uncomplited { get; set; } = false; 19 | public bool Complited { get; set; } = false; 20 | public bool Original { get; set; } = false; 21 | public bool Epic { get; set; } = false; 22 | public bool TwoPlayer { get; set; } = false; 23 | public bool HasCoins { get; set; } = false; 24 | 25 | public GetLevelsQuery(SearchType searchType) 26 | { 27 | SearchType = searchType; 28 | } 29 | 30 | public void SetSong(int id) 31 | { 32 | IsOfficialSong = false; 33 | SongId = id; 34 | } 35 | 36 | public void SetSong(OfficialSong song) 37 | { 38 | IsOfficialSong = true; 39 | SongId = (int)song; 40 | } 41 | 42 | public Parameters BuildQuery() 43 | { 44 | Parameters result = new Parameters(); 45 | BuildQuery(result); 46 | return result; 47 | } 48 | 49 | public void BuildQuery(Parameters parameters) 50 | { 51 | string difficultsString = ""; 52 | if (Difficults.Count > 0) 53 | { 54 | foreach (SearchDifficulty diff in Difficults) 55 | difficultsString += ((int)diff).ToString(); 56 | } 57 | else 58 | difficultsString = "-"; 59 | 60 | string lengthsString = ""; 61 | if (Lengths.Count > 0) 62 | { 63 | foreach (LengthType len in Lengths) 64 | lengthsString += ((int)len).ToString(); 65 | } 66 | else 67 | lengthsString = "-"; 68 | 69 | parameters.Add(new Property("str", QueryString)); 70 | parameters.Add(new Property("diff", difficultsString)); 71 | parameters.Add(new Property("len", lengthsString)); 72 | parameters.Add(new Property("page", Page)); 73 | parameters.Add(new Property("type", (int)SearchType)); 74 | parameters.Add(new Property("uncomplited", GameConvert.BoolToString(Uncomplited))); 75 | parameters.Add(new Property("onlyComplited", GameConvert.BoolToString(Complited))); 76 | parameters.Add(new Property("total", Total)); 77 | parameters.Add(new Property("original", GameConvert.BoolToString(Original))); 78 | parameters.Add(new Property("twoPlayer", GameConvert.BoolToString(TwoPlayer))); 79 | parameters.Add(new Property("coins", GameConvert.BoolToString(HasCoins))); 80 | parameters.Add(new Property("epic", GameConvert.BoolToString(Epic))); 81 | 82 | foreach (SearchDifficulty diff in Difficults) 83 | { 84 | if (diff == SearchDifficulty.Demon) 85 | parameters.Add(new Property("demonFilter", (int)SearchDemonDifficulty)); 86 | } 87 | if (Feautured >= 0) 88 | parameters.Add(new Property("featured", Feautured)); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Queries/IdentifierQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GeometryDashAPI.Server.Queries 4 | { 5 | public class IdentifierQuery : IQuery 6 | { 7 | private readonly Guid udid; 8 | private readonly int uuid; 9 | 10 | private readonly Property udidProperty; 11 | private readonly Property uuidProperty; 12 | 13 | public IdentifierQuery(Guid udid, int uuid) 14 | { 15 | this.udid = udid; 16 | this.uuid = uuid; 17 | 18 | udidProperty = new Property("udid", udid); 19 | uuidProperty = new Property("uuid", uuid); 20 | } 21 | 22 | public Parameters BuildQuery() 23 | { 24 | var result = new Parameters(); 25 | BuildQuery(result); 26 | return result; 27 | } 28 | 29 | public void BuildQuery(Parameters parameters) 30 | { 31 | parameters.Add(udidProperty); 32 | parameters.Add(uuidProperty); 33 | } 34 | 35 | public static IdentifierQuery Default => new(Guid.Parse("00000000-ffff-dddd-5555-123456789abc"), 1); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Queries/OnlineQuery.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Queries 2 | { 3 | public class OnlineQuery : IQuery 4 | { 5 | private readonly int gameVersion; 6 | private readonly int binaryVersion; 7 | private readonly int gdw; 8 | private readonly string secret; 9 | 10 | public OnlineQuery(int gameVersion, int binaryVersion, int gdw, string secret) 11 | { 12 | this.gameVersion = gameVersion; 13 | this.binaryVersion = binaryVersion; 14 | this.gdw = gdw; 15 | this.secret = secret; 16 | } 17 | 18 | public virtual Parameters BuildQuery() 19 | { 20 | var result = new Parameters(); 21 | BuildQuery(result); 22 | return result; 23 | } 24 | 25 | public void BuildQuery(Parameters parameters) 26 | { 27 | parameters.Add(new Property("gameVersion", gameVersion)); 28 | parameters.Add(new Property("binaryVersion", binaryVersion)); 29 | parameters.Add(new Property("gdw", gdw)); 30 | parameters.Add(new Property("secret", secret)); 31 | } 32 | 33 | public static OnlineQuery Default { get; } = new(21, 35, 0, "Wmfd2893gb7"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Queries/PasswordQuery.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace GeometryDashAPI.Server.Queries 4 | { 5 | public class PasswordQuery : IQuery 6 | { 7 | private int accountId; 8 | private string password; 9 | 10 | public PasswordQuery(int accountId, string password) 11 | { 12 | this.accountId = accountId; 13 | this.password = password; 14 | } 15 | 16 | public Parameters BuildQuery() 17 | { 18 | Parameters result = new Parameters(); 19 | BuildQuery(result); 20 | return result; 21 | } 22 | 23 | public void BuildQuery(Parameters parameters) 24 | { 25 | parameters.Add(new Property("gdw", 0)); 26 | parameters.Add(new Property("accountID", accountId)); 27 | parameters.Add(new Property("gjp", GameConvert.ToBase64(Encoding.ASCII.GetBytes(Crypt.XOR(password, "37526"))))); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Queries/RandomSeedQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace GeometryDashAPI.Server.Queries 5 | { 6 | public class RandomSeedQuery : IQuery 7 | { 8 | private readonly int length; 9 | private readonly Random random = new(); 10 | 11 | private readonly char[] alphabet = { 12 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 13 | 'A', 'B', 'C', 'D', 'E', 'F', 'H', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 14 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 15 | }; 16 | 17 | public RandomSeedQuery(int length) 18 | { 19 | this.length = length; 20 | } 21 | 22 | public Parameters BuildQuery() 23 | { 24 | var result = new Parameters(); 25 | BuildQuery(result); 26 | return result; 27 | } 28 | 29 | public void BuildQuery(Parameters parameters) 30 | { 31 | parameters.Add(new Property("rs", Generate())); 32 | } 33 | 34 | private string Generate() 35 | { 36 | var builder = new StringBuilder(); 37 | for (var i = 0; i < length; i++) 38 | builder.Append(alphabet[random.Next(alphabet.Length)]); 39 | return builder.ToString(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/AccountCommentPageResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Server.Dtos; 4 | 5 | namespace GeometryDashAPI.Server.Responses 6 | { 7 | [Sense("#")] 8 | [AsStruct] 9 | public class AccountCommentPageResponse : GameObject 10 | { 11 | [GameProperty("0")] 12 | [ArraySeparator("|")] 13 | public List Comments { get; set; } 14 | 15 | [GameProperty("1")] 16 | public Pagination Page { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/AccountInfoResponse.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Server.Dtos; 3 | 4 | namespace GeometryDashAPI.Server.Responses 5 | { 6 | [Sense("||")] 7 | [AsStruct] 8 | public class AccountInfoResponse : GameObject 9 | { 10 | [GameProperty("0")] public Account Account { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/LevelPageResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Server.Dtos; 4 | 5 | namespace GeometryDashAPI.Server.Responses 6 | { 7 | [Sense("#")] 8 | [AsStruct] 9 | public class LevelPageResponse : GameObject 10 | { 11 | [GameProperty("0")] 12 | [ArraySeparator("|")] 13 | public List Levels { get; set; } 14 | 15 | [GameProperty("1")] 16 | [ArraySeparator("|")] 17 | public List Authors { get; set; } 18 | 19 | [GameProperty("2")] 20 | [ArraySeparator("~:~")] 21 | public List Musics { get; set; } 22 | 23 | [GameProperty("3")] 24 | public Pagination Page { get; set; } 25 | 26 | [GameProperty("4")] 27 | public string Hash { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/LevelResponse.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Server.Dtos; 3 | 4 | namespace GeometryDashAPI.Server.Responses 5 | { 6 | [Sense("#")] 7 | [AsStruct] 8 | public class LevelResponse : GameObject 9 | { 10 | [GameProperty("0")] public LevelInfo Level { get; set; } 11 | [GameProperty("1")] public string Hash1 { get; set; } 12 | [GameProperty("2")] public string Hash2 { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/LoginResponse.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | 3 | namespace GeometryDashAPI.Server.Responses 4 | { 5 | [Sense(",")] 6 | [AsStruct] 7 | public class LoginResponse : GameObject 8 | { 9 | [GameProperty("0")] public int AccountId { get; set; } 10 | [GameProperty("1")] public int UserId { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/MessagesPageResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Server.Dtos; 4 | 5 | namespace GeometryDashAPI.Server.Responses; 6 | 7 | [AsStruct] 8 | [Sense("#")] 9 | public class MessagesPageResponse : GameObject 10 | { 11 | [GameProperty("0")] 12 | [ArraySeparator("|")] 13 | public List Messages { get; set; } 14 | 15 | [GameProperty("1")] 16 | public Pagination Page { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/NoneResponse.cs: -------------------------------------------------------------------------------- 1 | namespace GeometryDashAPI.Server.Responses; 2 | 3 | public class NoneResponse : GameObject 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/TopResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Server.Dtos; 4 | 5 | namespace GeometryDashAPI.Server.Responses 6 | { 7 | [Sense("||")] 8 | public class TopResponse : GameObject 9 | { 10 | [GameProperty("0")] 11 | [ArraySeparator("|")] 12 | public List Users { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /GeometryDashAPI/Server/Responses/UserResponse.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI.Attributes; 2 | using GeometryDashAPI.Server.Dtos; 3 | 4 | namespace GeometryDashAPI.Server.Responses 5 | { 6 | [Sense("#")] 7 | [AsStruct] 8 | public class UserResponse : GameObject 9 | { 10 | [GameProperty("0")] 11 | public UserPreview User { get; set; } 12 | 13 | [GameProperty("1")] public Pagination Page { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/ServerResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace GeometryDashAPI.Server 5 | { 6 | public class ServerResponse where T : IGameObject 7 | { 8 | public HttpStatusCode HttpStatusCode { get; } 9 | 10 | /// 11 | /// 0 by success 12 | /// 13 | public int GeometryDashStatusCode { get; } 14 | 15 | private readonly T value; 16 | private readonly string raw; 17 | 18 | public ServerResponse(HttpStatusCode statusCode, string body) 19 | { 20 | HttpStatusCode = statusCode; 21 | raw = body; 22 | if (HttpStatusCode != HttpStatusCode.OK && ServerResponseHelper.ErrorCodeRegex.Match(body).Success) 23 | { 24 | GeometryDashStatusCode = -1; // because "error code" looks like error from cloudflare (GeometryDash uses cloudflare as a proxy) 25 | return; 26 | } 27 | var match = ServerResponseHelper.StatusCodeRegex.Match(body); 28 | if (match.Success) 29 | { 30 | GeometryDashStatusCode = int.Parse(match.Value); 31 | return; 32 | } 33 | value = GeometryDashApi.Serializer.Decode(body.AsSpan()); 34 | } 35 | 36 | public T GetResultOrDefault() 37 | { 38 | return value; 39 | } 40 | 41 | public string GetRawOrDefault() 42 | { 43 | return raw; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /GeometryDashAPI/Server/ServerResponseHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace GeometryDashAPI.Server; 4 | 5 | internal class ServerResponseHelper 6 | { 7 | internal static readonly Regex StatusCodeRegex = new(@"^(-|)\d+$"); 8 | internal static readonly Regex ErrorCodeRegex = new(@"^error\scode:\s\d+$"); 9 | } 10 | -------------------------------------------------------------------------------- /Images/LevelResultInReadme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Folleach/GeometryDashAPI/8497f5589fc0d8bb764a03333d85853add6f4fad/Images/LevelResultInReadme.png -------------------------------------------------------------------------------- /Images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Folleach/GeometryDashAPI/8497f5589fc0d8bb764a03333d85853add6f4fad/Images/banner.png -------------------------------------------------------------------------------- /Images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Folleach/GeometryDashAPI/8497f5589fc0d8bb764a03333d85853add6f4fad/Images/logo.png -------------------------------------------------------------------------------- /Images/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Folleach/GeometryDashAPI/8497f5589fc0d8bb764a03333d85853add6f4fad/Images/wave.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Folleach 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Playground/CustomBlockType.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | using GeometryDashAPI.Data; 4 | using GeometryDashAPI.Levels; 5 | using GeometryDashAPI.Levels.Enums; 6 | using GeometryDashAPI.Levels.GameObjects.Default; 7 | 8 | namespace Playground; 9 | 10 | // an example of creating your own classes for blocks. 11 | [GameBlock(1520)] 12 | class MyShakeTrigger : Trigger 13 | { 14 | [GameProperty("24", (short)Layer.T2)] protected override short zLayer { get; set; } = (short)Layer.T2; 15 | [GameProperty("25", 99)] public override int ZOrder { get; set; } = 99; 16 | 17 | [GameProperty("9999", 2)] public int MySuperVelocity { get; set; } = 2; 18 | } 19 | 20 | class CustomBlockType 21 | { 22 | public static void Invoke() 23 | { 24 | GeometryDashApi.RegisterBlockType(typeof(MyShakeTrigger), true); 25 | var levels = LocalLevels.LoadFile(); 26 | var level = new Level(levels.GetLevel("Temp")); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Playground/Playground.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Playground/Program.cs: -------------------------------------------------------------------------------- 1 | // Hello! This is Geometry Dash API playground 2 | // Here you can try your own code. 3 | // 4 | // See the wiki to learn how to use the library: 5 | // https://github.com/Folleach/GeometryDashAPI/wiki 6 | // 7 | // Unfortunately, the RobTop server isn't working from GitHub 8 | // Therefore, you cannot use GameClient. 9 | // 10 | // Press F5 to run this code 11 | 12 | using GeometryDashAPI.Data; 13 | using GeometryDashAPI.Levels.GameObjects.Specific; 14 | 15 | var local = await LocalLevels.LoadFileAsync("GeometryDashAPI.Tests/data/saves/CCLocalLevels1.dat"); 16 | 17 | Console.WriteLine("this file contain levels:"); 18 | foreach (var item in local) 19 | Console.WriteLine($"\t{item.Name}"); 20 | 21 | var levelInfo = local.GetLevel("test1"); 22 | var level = levelInfo.LoadLevel(); 23 | 24 | Console.WriteLine($"level {levelInfo.Name} has {level.Blocks.Count} total blocks"); 25 | 26 | level.AddBlock(new JumpSphere(JumpSphereId.Yellow) 27 | { 28 | PositionX = 100, 29 | PositionY = 100 30 | }); 31 | 32 | levelInfo.SaveLevel(level); 33 | await local.SaveAsync("data/CCLocalLevels.dat"); 34 | 35 | Console.WriteLine("level saved to data/CCLocalLevels.dat"); 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![image](https://raw.githubusercontent.com/Folleach/GeometryDashAPI/master/Images/banner.png) 3 | 4 | [![Tests](https://img.shields.io/github/actions/workflow/status/Folleach/GeometryDashAPI/tests.yml?label=tests&logo=github&style=flat-square)](https://github.com/Folleach/GeometryDashAPI/actions/workflows/tests.yml) 5 | [![Version](https://img.shields.io/nuget/v/GeometryDashAPI?label=version&logo=nuget&style=flat-square)](https://www.nuget.org/packages/GeometryDashAPI) 6 | [![Downloads](https://img.shields.io/nuget/dt/GeometryDashAPI?logo=nuget&style=flat-square)](https://www.nuget.org/packages/GeometryDashAPI) 7 | 8 | So, **GeometryDashAPI** is the library for edit _everything_ that you imagine 9 | Amooong things... 10 | 11 | ## Levels 12 | Edit your own level from the stored data, or download from the server and... edit it! 13 | 14 | ```cs 15 | var local = await LocalLevels.LoadFileAsync(); 16 | var level = local.GetLevel("MyLevel", revision: 0).LoadLevel(); 17 | 18 | level.AddColor(new Color(11) 19 | { 20 | Rgb = RgbColor.FromHex("#ffa500") // orange 21 | }); 22 | for (var x = 0; x < 1024; x += 4) 23 | { 24 | level.AddBlock(new ColorBlock(1887) 25 | { 26 | PositionX = x, 27 | PositionY = (float)Math.Sin(x / 100f) * 120, 28 | ColorBase = 11 29 | }); 30 | } 31 | 32 | local.GetLevel("MyLevel", revision: 0).SaveLevel(level); 33 | await local.SaveAsync(); 34 | ``` 35 | 36 | ![](/Images/wave.png) 37 | 38 | [learn more](https://github.com/Folleach/GeometryDashAPI/wiki/Levels) 39 | 40 | ## Stored data 41 | Open `.dat`/`.plist` file for explore your own statistics, creation, downloads, achievements and more 42 | 43 | ```cs 44 | var manager = GameManager.LoadFile(); 45 | manager.PlayerName = "your name :>"; 46 | manager.Save(); 47 | ``` 48 | 49 | [learn more](https://github.com/Folleach/GeometryDashAPI/wiki/Game-saves) 50 | 51 | For editing `.dat` files with a text editor, you can use [CLI tool](https://github.com/Folleach/GeometryDash.Console) for unpacking them 52 | 53 | 54 | ## Network 55 | 56 | Don't think about communicates with the server. 57 | Ready-made methods are at your disposal for 58 | 59 | - search 60 | - account 61 | - ... ~~to be honest there are few methods.~~ todo: add a new items when make more methods ;) 62 | 63 | ```cs 64 | var client = new GameClient(); 65 | var user = await client.SearchUserAsync("Folleach"); 66 | ``` 67 | 68 | You can even interact with unofficial servers too 69 | 70 | [learn more](https://github.com/Folleach/GeometryDashAPI/wiki/Network) 71 | 72 | ## How to use 73 | 1. Install [`GeometryDashAPI`](https://www.nuget.org/packages/GeometryDashAPI/) from Nuget 74 | 2. The end. You can use it :) 75 | 76 | See [wiki](https://github.com/Folleach/GeometryDashAPI/wiki) for learn more information 77 | 78 | ## Tested on 79 | 80 | - .NET 6 81 | - .NET Core 2.2 82 | - .NET Framework 4.8 83 | 84 | [learn more](https://github.com/Folleach/GeometryDashAPI/blob/master/GeometryDashAPI.Tests/GeometryDashAPI.Tests.csproj#L5) 85 | 86 | ## Versions convention 87 | 88 | The main version pattern is `0.x.y` 89 | Where `x` is this some new feature or a big rework 90 | Where `y` is this a small fix [bug] 91 | 92 | Sometimes there are `-alpha` suffix appears. 93 | This is means experiment release for include this library to other projects 94 | 95 | Major 0 will be change to 1 when library will support most features of game 96 | 97 | Every version should contains a tag, with prefix `v`. 98 | Example: `v1.2.3-alpha` 99 | 100 | ## Used libraries 101 | | Name | Link | 102 | |-------------|------------------------------------------------------| 103 | | SharpZipLib | [GitHub](https://github.com/icsharpcode/SharpZipLib) | 104 | | csFastFloat | [GitHub](https://github.com/CarlVerret/csFastFloat) | 105 | | UrlBase64 | [GitHub](https://github.com/neosmart/UrlBase64) | 106 | 107 | 108 | -------------------------------------------------------------------------------- /TestObjects/AllTypes.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects 5 | { 6 | [Sense(",")] 7 | public class AllTypes : GameObject 8 | { 9 | [GameProperty("1")] 10 | public string String { get; set; } 11 | [GameProperty("2")] 12 | public byte Byte { get; set; } 13 | [GameProperty("3")] 14 | public short Short { get; set; } 15 | [GameProperty("4")] 16 | public int Int { get; set; } 17 | [GameProperty("5")] 18 | public long Long { get; set; } 19 | [GameProperty("6")] 20 | public double Double { get; set; } 21 | [GameProperty("7")] 22 | public bool Bool { get; set; } 23 | } 24 | } -------------------------------------------------------------------------------- /TestObjects/ComplexParserObjects.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | using GeometryDashAPI; 3 | using GeometryDashAPI.Attributes; 4 | 5 | namespace TestObjects 6 | { 7 | [Sense("#")] 8 | [AsStruct] 9 | public class ComplexParserObject : GameObject 10 | { 11 | [GameProperty("0")] 12 | public ComplexObject Object { get; set; } 13 | 14 | [GameProperty("1")] public ComplexStruct Struct { get; set; } 15 | 16 | [GameProperty("2")] 17 | [ArraySeparator("~")] 18 | public List ObjectArray { get; set; } 19 | 20 | [GameProperty("3")] 21 | [ArraySeparator("~")] 22 | public List StructArray { get; set; } 23 | 24 | public static readonly string ExampleInput = "A:2:1:31:B:23#10:12#A:1~A:3~A:5#1:2~3:4"; // Give from this string 25 | 26 | // this object 27 | public static readonly ComplexParserObject ExampleExpected = new ComplexParserObject() 28 | { 29 | Object = new ComplexObject() 30 | { 31 | A = 2, 32 | X = 31, 33 | B = 23 34 | }, 35 | Struct = new ComplexStruct() 36 | { 37 | X = 10, Y = 12 38 | }, 39 | ObjectArray = new List() 40 | { 41 | new ComplexObject() { A = 1 }, 42 | new ComplexObject() { A = 3 }, 43 | new ComplexObject() { A = 5 } 44 | }, 45 | StructArray = new List() 46 | { 47 | new ComplexStruct() { X = 1, Y = 2}, 48 | new ComplexStruct() { X = 3, Y = 4} 49 | } 50 | }; 51 | } 52 | 53 | [AsStruct] 54 | [Sense(":")] 55 | public class ComplexStruct : GameObject 56 | { 57 | [GameProperty("0")] public int X { get; set; } 58 | [GameProperty("1")] public int Y { get; set; } 59 | } 60 | 61 | [Sense(":")] 62 | public class ComplexObject : GameObject 63 | { 64 | [GameProperty("1")] 65 | public int X { get; set; } 66 | [GameProperty("A", KeyOverride = 0)] 67 | public int A { get; set; } 68 | [GameProperty("B", KeyOverride = 1)] 69 | public int B { get; set; } 70 | } 71 | } -------------------------------------------------------------------------------- /TestObjects/InheritFieldFrom.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects; 5 | 6 | [Sense(",")] 7 | public class InheritFieldFrom : GameObject 8 | { 9 | [GameProperty("1")] 10 | private int x; 11 | 12 | [GameProperty("3")] 13 | protected int Id; 14 | 15 | public int X => x; 16 | } 17 | 18 | [Sense(",")] 19 | public class InheritField : InheritFieldFrom 20 | { 21 | [GameProperty("2")] 22 | private int y; 23 | 24 | public int Y => y; 25 | } 26 | -------------------------------------------------------------------------------- /TestObjects/MultipleSense.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects 5 | { 6 | [Sense("~|~")] 7 | public class MultipleSense : GameObject 8 | { 9 | [GameProperty("1")] public int X1 { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /TestObjects/ObjectSample.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects 5 | { 6 | [Sense(":")] 7 | public class ObjectSample : GameObject 8 | { 9 | [GameProperty("33")] public double X { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /TestObjects/ObjectWithEnum.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects; 5 | 6 | [Sense(":")] 7 | public class ObjectWithEnum : GameObject 8 | { 9 | [GameProperty("1")] 10 | public SimpleEnum Value { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /TestObjects/SampleContainer.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects 5 | { 6 | [Sense("~")] 7 | public class SampleContainer : GameObject 8 | { 9 | [GameProperty("1")] public ObjectSample Sample1 { get; set; } 10 | [GameProperty("2")] public ObjectSample Sample2 { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /TestObjects/SimpleEnum.cs: -------------------------------------------------------------------------------- 1 | namespace TestObjects; 2 | 3 | public enum SimpleEnum 4 | { 5 | A, B, C, X = 33, Y 6 | } 7 | -------------------------------------------------------------------------------- /TestObjects/StructSample.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects 5 | { 6 | [AsStruct] 7 | [Sense("~")] 8 | public class StructSample : GameObject 9 | { 10 | [GameProperty("0")] public ObjectSample FirstObject { get; set; } 11 | [GameProperty("1")] public LargeObject SecondObject { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /TestObjects/TestObjects.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2;netstandard2.1;net48 5 | enable 6 | enable 7 | latest 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /TestObjects/WithNullable.cs: -------------------------------------------------------------------------------- 1 | using GeometryDashAPI; 2 | using GeometryDashAPI.Attributes; 3 | 4 | namespace TestObjects; 5 | 6 | [Sense(":")] 7 | public class WithNullable : GameObject 8 | { 9 | [GameProperty("3")] 10 | public int? Value { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /docs/colorMapping.txt: -------------------------------------------------------------------------------- 1 | id;r;g;b 2 | 0;125;255;0 3 | 1;0;255;0 4 | 2;0;255;125 5 | 3;0;255;255 6 | 16;0;200;255 7 | 4;0;125;255 8 | 5;0;0;255 9 | 6;125;0;255 10 | 13;185;0;255 11 | 7;255;0;255 12 | 8;255;0;125 13 | 9;255;0;0 14 | 29;255;75;0 15 | 10;255;125;0 16 | 14;255;185;0 17 | 11;255;255;0 18 | 12;255;255;255 19 | 17;175;175;175 20 | 18;90;90;90 21 | 15;0;0;0 22 | 27;125;125;0 23 | 32;100;150;0 24 | 28;75;175;0 25 | 38;0;150;0 26 | 20;0;175;75 27 | 33;0;150;100 28 | 21;0;125;125 29 | 34;0;100;150 30 | 22;0;75;175 31 | 39;0;0;150 32 | 23;75;0;175 33 | 35;100;0;150 34 | 24;125;0;125 35 | 36;150;0;100 36 | 25;175;0;75 37 | 37;150;0;0 38 | 30;150;50;0 39 | 26;175;75;0 40 | 31;150;100;0 41 | 19;255;125;125 42 | 40;125;255;175 43 | 41;125;125;255 --------------------------------------------------------------------------------