feat: 项目初始化 + 3D方块世界原型 + AI助搭系统
CI / Go Backend (push) Canceled after 0s

初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器

HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块

Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚

AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
This commit is contained in:
xyou
2026-08-08 14:07:56 +08:00
parent 9500c4c80a
commit f70b061d1a
1972 changed files with 159760 additions and 6 deletions
@@ -0,0 +1,35 @@
using System.Threading;
using System.Threading.Tasks;
namespace PCL.Core.App.Tasks;
/// <summary>
/// 任务状态改变事件
/// <param name="state">当前状态,将影响日志和 UI 显示效果</param>
/// <param name="message">状态消息</param>
/// </summary>
public delegate void TaskStateEvent(TaskState state, string message);
/// <summary>
/// 响应式任务接口<br/>
/// <b>NOTE</b>: 为确保运行时响应式模型的 hash 映射正常工作,若无特殊需求,请勿重写对象相等性实现如
/// <see cref="object.GetHashCode"/> 与 <see cref="object.Equals(object)"/>
/// </summary>
public interface ITask
{
/// <summary>
/// 任务标题
/// </summary>
public string Title { get; }
/// <summary>
/// 运行任务
/// </summary>
/// <param name="cancelToken">取消令牌</param>
public Task ExecuteAsync(CancellationToken cancelToken = default);
/// <summary>
/// 任务状态改变事件
/// </summary>
public event TaskStateEvent StateChanged;
}
@@ -0,0 +1,9 @@
namespace PCL.Core.App.Tasks;
/// <summary>
/// 用于取消实现的接口
/// </summary>
public interface ITaskCancelable
{
public void Cancel();
}
@@ -0,0 +1,9 @@
namespace PCL.Core.App.Tasks;
public delegate void TaskGroupEvent(ITask task);
public interface ITaskGroup : ITask
{
public event TaskGroupEvent AddTask;
public event TaskGroupEvent RemoveTask;
}
@@ -0,0 +1,9 @@
namespace PCL.Core.App.Tasks;
/// <summary>
/// 用于暂停实现的接口
/// </summary>
public interface ITaskPausable
{
public void Pause();
}
@@ -0,0 +1,18 @@
namespace PCL.Core.App.Tasks;
/// <summary>
/// 任务进度改变事件
/// </summary>
/// <param name="progress">0.0 ~ 1.0 之间的浮点数,表示任务进度</param>
public delegate void TaskProgressEvent(double progress);
/// <summary>
/// 可观察进度的任务模型
/// </summary>
public interface ITaskProgressive
{
/// <summary>
/// 任务进度改变事件
/// </summary>
public event TaskProgressEvent ProgressChanged;
}
@@ -0,0 +1,107 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using PCL.Core.Logging;
namespace PCL.Core.App.Tasks;
/// <summary>
/// 任务中心,用于管理任务
/// </summary>
public static class TaskCenter
{
/// <summary>
/// 可观察的任务模型集合
/// </summary>
public static ObservableCollection<TaskModel> Tasks { get; } = [];
private static readonly ConditionalWeakTable<ITask, TaskModel> _ModelMap = [];
private static TaskModel _InitModel(ITask instance)
{
// ReSharper disable SuspiciousTypeConversion.Global
var cancelable = instance as ITaskCancelable;
var pausable = instance as ITaskPausable;
var progressive = instance as ITaskProgressive;
// ReSharper restore SuspiciousTypeConversion.Global
var model = new TaskModel
{
Title = instance.Title,
SupportProgress = progressive is not null,
OnCancel = cancelable is null ? null : (() => cancelable.Cancel()),
OnPause = pausable is null ? null : (() => pausable.Pause()),
};
// state event
instance.StateChanged += (state, message) =>
{
LogWrapper.Trace("TaskCenter", $"{instance.Title}: state changed ({state}): {message}");
model.State = state;
model.StateMessage = message;
};
// progress event
if (progressive is not null)
{
progressive.ProgressChanged += progress =>
{
model.Progress = Math.Clamp(progress, 0.0, 1.0);
};
}
// group events
if (instance is ITaskGroup group)
{
group.AddTask += task =>
{
var taskModel = _InitModel(task);
_ModelMap.Add(task, taskModel);
model.Children.Add(taskModel);
};
group.RemoveTask += task =>
{
if (_ModelMap.TryGetValue(task, out var taskModel)) model.Children.Remove(taskModel);
};
}
return model;
}
/// <summary>
/// 注册响应式任务实例
/// </summary>
/// <param name="instance">任务实例</param>
/// <param name="start">是否立即启动该实例</param>
public static void Register(ITask instance, bool start = true)
{
var model = _InitModel(instance);
Tasks.Add(model);
if (start)
{
_ = Task.Run(async () =>
{
try { await instance.ExecuteAsync(); }
catch (OperationCanceledException) { /* ignoring */ }
catch (Exception ex)
{
LogWrapper.Warn(ex, "TaskCenter", $"{instance.Title}: exception thrown");
model.State = TaskState.Failed;
model.StateMessage = ex.Message;
}
});
}
}
/// <summary>
/// 移除所有已结束的任务
/// </summary>
public static void RemoveFinished()
{
foreach (var model in Tasks.Where(x => x.State > TaskState.Running).ToList())
Tasks.Remove(model);
}
}
@@ -0,0 +1,84 @@
using System;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace PCL.Core.App.Tasks;
/// <summary>
/// 可观察的任务模型<br/>
/// <b>NOTE</b>: 请勿自行修改任何 observable 属性
/// </summary>
public partial class TaskModel : ObservableObject
{
/// <summary>
/// 任务标题
/// </summary>
public required string Title { get; init; }
/// <summary>
/// 任务是否支持进度
/// </summary>
public required bool SupportProgress { get; init; }
/// <summary>
/// 任务当前状态
/// </summary>
[ObservableProperty] private TaskState _state = TaskState.Waiting;
/// <summary>
/// 任务当前状态信息
/// </summary>
[ObservableProperty] private string _stateMessage = string.Empty;
/// <summary>
/// 任务当前进度,<see cref="SupportProgress"/> 为 <see langword="true"/> 时有效
/// </summary>
[ObservableProperty] private double _progress = 0.0;
private static readonly Action _EmptyAction = (static () => {});
/// <summary>
/// 取消任务时触发的事件,值为 <see langword="null"/> 表示不支持取消
/// </summary>
public required Action? OnCancel { private get; init; }
/// <summary>
/// 取消任务命令
/// </summary>
public RelayCommand Cancel
{
get => field ??= new RelayCommand(OnCancel ?? _EmptyAction, () => OnCancel is not null);
} = null!;
/// <summary>
/// 暂停任务时触发的事件,值为 <see langword="null"/> 表示不支持暂停
/// </summary>
public required Action? OnPause { private get; init; }
/// <summary>
/// 暂停任务命令
/// </summary>
public RelayCommand Pause
{
get => field ??= new RelayCommand(OnPause ?? _EmptyAction, () => OnPause is not null);
} = null!;
/// <summary>
/// 任务是否为任务组,即是否存在子任务
/// </summary>
[ObservableProperty] private bool _isGroup;
/// <summary>
/// 子任务模型
/// </summary>
public ObservableCollection<TaskModel> Children { get; } = [];
public TaskModel()
{
Children.CollectionChanged += (sender, _) =>
{
if (sender is ObservableCollection<TaskModel> c) IsGroup = c.Count > 0;
};
}
}
@@ -0,0 +1,10 @@
namespace PCL.Core.App.Tasks;
public enum TaskState
{
Waiting,
Running,
Success,
Canceled,
Failed
}