This commit is contained in:
2026-06-14 02:20:41 +05:00
commit a153e90c16
6 changed files with 229 additions and 0 deletions

29
.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
# Build results
[Bb]in/
.bin/
[Dd]ebug/
[Rr]elease/
[Rr]eleases/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
[Pp]ublish/
*.log
# IDE files
.vs/
.vscode/
.vshistory/
.idea/
.editorconfig
*.user
*.DotSettings
# temp files
.old*/
old/
tmp/
temp/
*.tmp
*.temp

16
Kamni.sln Normal file
View File

@@ -0,0 +1,16 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kamni", "Kamni\Kamni.csproj", "{FDBA03C5-E5E7-4847-96FA-860C5A496144}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FDBA03C5-E5E7-4847-96FA-860C5A496144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FDBA03C5-E5E7-4847-96FA-860C5A496144}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FDBA03C5-E5E7-4847-96FA-860C5A496144}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDBA03C5-E5E7-4847-96FA-860C5A496144}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

16
Kamni/Kamni.csproj Normal file
View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DTLib" Version="1.7.4" />
<PackageReference Include="Raylib-cs" Version="8.0.0" />
<PackageReference Include="Tomlyn" Version="2.6.0" />
</ItemGroup>
</Project>

14
Kamni/src/PathHelper.cs Normal file
View File

@@ -0,0 +1,14 @@
namespace Kamni;
public static class PathHelper
{
public static readonly IOPath UserDataDir = Path.Concat(
#if DEBUG
"!user_data",
#else
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
#endif
"Kamni");
public static readonly IOPath LogDir = Path.Concat(UserDataDir, "log");
}

108
Kamni/src/Program.cs Normal file
View File

@@ -0,0 +1,108 @@
global using System;
global using System.Numerics;
global using DTLib.Logging;
global using DTLib.Filesystem;
global using File = DTLib.Filesystem.File;
global using Directory = DTLib.Filesystem.Directory;
global using Path = DTLib.Filesystem.Path;
using System.Linq;
using System.Runtime.InteropServices;
using Raylib_cs;
using static Raylib_cs.Raylib;
namespace Kamni;
public static class Program
{
public static readonly Version GameVersion = new(0, 1, 0);
public static Settings Settings { get; private set; } = null!;
public static ILogger Logger { get; private set; } = null!;
public static int Main(string[] args)
{
Settings = Settings.Load();
Logger = new CompositeLogger(
new ConsoleLogger(),
new FileLogger($"{PathHelper.LogDir}engine.log")
);
Logger.DebugLogEnabled = true;
// TODO: add game.log, script.log
// TODO: add /unsafe and other options to CSharpScript.toml
var logger = new ContextLogger("Main", Logger);
logger.LogInfo($"Starting Kamni v{GameVersion}");
unsafe
{
SetTraceLogCallback(&RaylibLogHandler);
SetTraceLogLevel(TraceLogLevel.All);
}
SetTargetFPS(Settings.target_fps);
ConfigFlags windowFlags = 0;
windowFlags |= Settings.WindowMode switch
{
WindowMode.Window => ConfigFlags.ResizableWindow,
WindowMode.Borderless => ConfigFlags.BorderlessWindowMode,
WindowMode.Fullscreen => ConfigFlags.FullscreenMode,
_ => throw new ArgumentOutOfRangeException()
};
SetConfigFlags(windowFlags);
SetWindowMinSize(480, 360);
InitWindow(Settings.WindowMode == WindowMode.Window ? 720 : 0 , Settings.WindowMode == WindowMode.Window ? 480 : 0, $"Kamni v{GameVersion}");
while (!WindowShouldClose())
{
BeginDrawing();
DrawFrame();
EndDrawing();
}
CloseWindow();
return 0;
}
static float[] randomRotations = [];
static float sumT = 999999;
static void DrawFrame()
{
Vector2 center = new(GetRenderWidth() / 2f, GetRenderHeight() / 2f);
float deltaT = GetFrameTime();
sumT += deltaT;
if (sumT > 0.5)
{
sumT = 0;
randomRotations = Enumerable.Range(0, 7).Select(_ => (float)Random.Shared.Next(-30, 30)).ToArray();
}
ClearBackground(Color.DarkBlue);
DrawPoly(new(center.X, center.Y - 100), 5, 32, randomRotations[0], Color.Red);
DrawPoly(new(center.X - 100, center.Y - 50), 5, 32, randomRotations[1], Color.Pink);
DrawPoly(new(center.X + 100, center.Y - 50), 5, 32, randomRotations[2], Color.Orange);
DrawPoly(new(center.X - 150, center.Y + 25), 5, 32, randomRotations[3], Color.Purple);
DrawPoly(new(center.X + 150, center.Y + 25), 5, 32, randomRotations[4], Color.Yellow);
DrawPoly(new(center.X - 60, center.Y + 75), 5, 32, randomRotations[3], Color.SkyBlue);
DrawPoly(new(center.X + 60, center.Y + 75), 5, 32, randomRotations[4], Color.Green);
// DrawPoly(new (center.X + 75, center.Y + 25), 5, 32, 0, Color.Orange);
DrawFPS(5, 5);
}
[UnmanagedCallersOnly(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
private static unsafe void RaylibLogHandler(int logLevel_, sbyte* text_, sbyte* args_)
{
string message = Logging.GetLogMessage(new IntPtr(text_), new IntPtr(args_));
LogSeverity severity = (TraceLogLevel)logLevel_ switch
{
TraceLogLevel.Trace => LogSeverity.Debug,
TraceLogLevel.Debug => LogSeverity.Debug,
TraceLogLevel.Info => LogSeverity.Info,
TraceLogLevel.Warning => LogSeverity.Warn,
TraceLogLevel.Error => LogSeverity.Error,
TraceLogLevel.Fatal => LogSeverity.Error,
_ => throw new ArgumentOutOfRangeException(nameof(logLevel_))
};
Logger.Log("Raylib", severity, message);
}
}

46
Kamni/src/Settings.cs Normal file
View File

@@ -0,0 +1,46 @@
using Tomlyn;
namespace Kamni;
public enum WindowMode
{
Window, Borderless, Fullscreen
}
public class Settings
{
public WindowMode WindowMode { get; set; } = WindowMode.Window;
public int target_fps { get; set; } = 60;
public static Settings Load()
{
Settings s;
if (!File.Exists(SettingsFile))
{
s = new Settings();
s.Save();
return s;
}
s = TomlSerializer.Deserialize<Settings>(File.ReadAllText(SettingsFile), TomlSerializerOptions)
?? throw new Exception($"can't load settings {SettingsFile}");
return s;
}
public void Save()
{
string settingsStr = TomlSerializer.Serialize(this);
File.WriteAllText(SettingsFile, settingsStr);
}
private static readonly TomlSerializerOptions TomlSerializerOptions = new()
{
WriteIndented = true,
IndentSize = 4,
MaxDepth = 64,
DefaultIgnoreCondition = TomlIgnoreCondition.WhenWritingNull,
};
private static readonly IOPath SettingsFile = $"{PathHelper.UserDataDir}/settings.toml";
}