Add MineGeo gameplay systems and interface

This commit is contained in:
2026-10-10 10:27:47 +05:00
parent bf01d9801d
commit 9af71c85c2
47 changed files with 9954 additions and 93 deletions

View File

@@ -43,6 +43,13 @@ export type Database = {
};
public: {
Tables: {
discord_announcements: {
Row: import("./discord").DiscordAnnouncement;
Insert: Partial<import("./discord").DiscordAnnouncement> &
Pick<import("./discord").DiscordAnnouncement, "kind" | "target_id">;
Update: Partial<import("./discord").DiscordAnnouncement>;
Relationships: [];
};
bug_reports: {
Row: import("./bug-reports").BugReportRecord;
Insert: Partial<import("./bug-reports").BugReportRecord> &
@@ -695,6 +702,38 @@ export type Database = {
[_ in never]: never;
};
Functions: {
claim_discord_cleanup: {
Args: { p_worker: string; p_target?: string | null };
Returns: import("./discord").DiscordAnnouncement[];
SetofOptions: {
from: "*";
to: "discord_announcements";
isOneToOne: false;
isSetofReturn: true;
};
};
mark_discord_party_closed: {
Args: { p_event: string };
Returns: string;
};
publish_discord_party: {
Args: { p_room: string; p_access_hash: string };
Returns: string;
};
claim_discord_announcements: {
Args: { p_worker: string; p_kinds: string[]; p_target?: string | null };
Returns: import("./discord").DiscordAnnouncement[];
SetofOptions: {
from: "*";
to: "discord_announcements";
isOneToOne: false;
isSetofReturn: true;
};
};
retry_discord_announcements: {
Args: { p_reviewer: string };
Returns: number;
};
set_user_prefix: {
Args: {
p_reviewer: string;

35
shared/discord.ts Normal file
View File

@@ -0,0 +1,35 @@
export type DiscordKind = "map" | "party";
export type DiscordAnnouncement = {
id: string;
kind: DiscordKind;
target_id: string;
state: "pending" | "sending" | "sent" | "skipped" | "failed";
attempts: number;
next_attempt_at: string;
lease_owner: string | null;
lease_until: string | null;
channel_id: string | null;
message_id: string | null;
last_error: string | null;
created_at: string;
sent_at: string | null;
closed_at?: string | null;
delete_after?: string | null;
deleted_at?: string | null;
cleanup_run_id?: string | null;
cleanup_lease_until?: string | null;
cleanup_error?: string | null;
};
export type PartyAnnouncement = {
available: boolean;
state: DiscordAnnouncement["state"] | null;
};
export type DiscordStatus = {
botConfigured: boolean;
publicUrlConfigured: boolean;
mapsConfigured: boolean;
partiesConfigured: boolean;
pending: number;
failed: number;
sent: number;
};

View File

@@ -609,7 +609,7 @@
"Game mode": "Режим игры",
"Solo": "Одиночная игра",
"Multiplayer": "Мультиплеер",
"Your player name": "Ваше игровое имя",
"Your player name": "Ваше имя игрока",
"Enter a player name": "Введите игровое имя",
"Player limit (including you)": "Лимит игроков (включая вас)",
"Create a room, share the invite link, and start when your friends arrive.": "Создайте комнату, поделитесь ссылкой и начните игру, когда друзья присоединятся.",
@@ -751,15 +751,12 @@
"Tell us what happened. We’ll reply here.": "Расскажите, что произошло. Мы ответим здесь.",
"Guest reports stay in this browser. Sign in to keep your conversation in your account.": "Обращения гостей сохраняются в этом браузере. Войдите, чтобы сохранить переписку в аккаунте.",
"Bug reporting is temporarily unavailable. Please try again later.": "Отправка обращений временно недоступна. Попробуйте позже.",
"Your player name": "Ваше имя игрока",
"Bug title": "Название ошибки",
"What happened?": "Что произошло?",
"What did you do, what did you expect, and what happened instead?": "Что вы сделали, чего ожидали и что произошло вместо этого?",
"Screenshot (optional)": "Скриншот (необязательно)",
"PNG, JPG, or WebP, up to 5 MB. Shared privately with support.": "PNG, JPG или WebP, до 5 МБ. Доступен только вам и поддержке.",
"Your bug reports": "Ваши обращения",
"Your reports and support replies will appear here.": "Здесь появятся ваши обращения и ответы поддержки.",
"Draft": "Черновик",
"Waiting for support": "Ожидает поддержки",
"← Your bug reports": "← Ваши обращения",
"Your report is saved. We’re connecting it to support.": "Обращение сохранено. Передаём его поддержке.",
@@ -767,7 +764,6 @@
"Finish sending report": "Завершить отправку",
"Keep this report in my account": "Сохранить обращение в аккаунте",
"Support awarded you a username glow.": "Поддержка подарила вам свечение имени.",
"Account settings": "Настройки аккаунта",
"For guest reports, sign in and link this report to receive your reward.": "Если вы отправили обращение как гость, войдите и привяжите его к аккаунту, чтобы получить награду.",
"Attached bug screenshot": "Прикреплённый скриншот ошибки",
"Support conversation": "Переписка с поддержкой",
@@ -788,5 +784,51 @@
"Sign in to link this report": "Войдите, чтобы привязать обращение",
"Remove hidden control characters": "Удалите скрытые управляющие символы",
"Turn on light mode": "Включить светлую тему",
"Turn on dark mode": "Включить тёмную тему"
"Turn on dark mode": "Включить тёмную тему",
"Community": "Сообщество",
"Join us on Discord": "Присоединиться к Discord",
"Follow us on Telegram": "Мы в Telegram",
"Admin": "Администратор",
"Admin permission required": "Требуются права администратора",
"Moderators can inspect and review pending maps and updates. Other controls require Admin permission.": "Модераторы могут проверять ожидающие рассмотрения карты и обновления. Для остальных действий нужны права администратора.",
"Changes apply to every player. Only admins can edit these settings.": "Изменения применяются ко всем игрокам. Менять эти настройки могут только администраторы.",
"Map is not awaiting review": "Карта не ожидает проверки",
"Discord integration": "Интеграция с Discord",
"New approved maps are announced automatically. Hosts can publish an open party to the shared Discord channel.": "Новые одобренные карты публикуются автоматически. Хозяева открытых лобби могут поделиться приглашением в общем канале Discord.",
"Discord bot configured": "Бот Discord настроен",
"Discord setup required in Vercel environment variables": "Настройте Discord через переменные окружения Vercel",
"Map announcements: {state}": "Объявления о картах: {state}",
"Party announcements: {state}": "Объявления о лобби: {state}",
"Configured": "Настроено",
"Not configured": "Не настроено",
"{pending} pending · {failed} need attention · {sent} sent": "{pending} ожидают · {failed} требуют проверки · {sent} отправлено",
"Check Discord setup": "Проверить настройку Discord",
"Retry saved announcements": "Повторить отправку объявлений",
"Refresh status": "Обновить статус",
"Discord bot and channel access checked. Send Messages and Embed Links are also required.": "Бот и доступ к каналам проверены. Также нужны права на отправку сообщений и вставку ссылок.",
"Saved Discord announcements will retry.": "Сохранённые объявления Discord будут отправлены повторно.",
"Publish party to Discord": "Опубликовать лобби в Discord",
"Publishing…": "Публикация…",
"Publishing shares this invite with everyone in the community Discord channel.": "После публикации это приглашение увидят все участники общего канала Discord.",
"Party posted to Discord.": "Лобби опубликовано в Discord.",
"Party announcement is waiting for Discord delivery.": "Объявление о лобби ожидает отправки в Discord.",
"Discord delivery needs an administrator to check the bot setup and retry.": "Администратору нужно проверить настройку бота и повторить отправку.",
"This party announcement expired or the lobby is no longer available.": "Объявление устарело или лобби больше недоступно.",
"Party announcement queued. Anyone in the Discord channel can open the invite and join.": "Объявление добавлено в очередь. Любой участник канала Discord сможет открыть приглашение и присоединиться.",
"Only the room owner can publish this party": "Только хозяин лобби может опубликовать его",
"Discord party sharing is not configured yet": "Публикация лобби в Discord пока не настроена",
"Only open lobbies can be published": "Можно публиковать только открытые лобби",
"Only parties on published maps can be shared on Discord": "В Discord можно публиковать только лобби с общедоступными картами",
"Configure the Discord bot token, public site URL, and at least one channel ID.": "Настройте токен бота Discord, публичный адрес сайта и хотя бы один ID канала.",
"Discord bot token is invalid. Update it in Vercel.": "Токен бота Discord недействителен. Обновите его в Vercel.",
"Discord bot needs View Channel, Send Messages, and Embed Links in the configured channel.": "Боту Discord нужны права View Channel, Send Messages и Embed Links в выбранном канале.",
"Discord channel was not found. Check the channel ID and bot access.": "Канал Discord не найден. Проверьте ID канала и доступ бота.",
"Discord channel ID is invalid.": "Неверный ID канала Discord.",
"Choose a Discord server text or announcement channel.": "Выберите текстовый канал или канал объявлений на сервере Discord.",
"Use a Discord bot token.": "Используйте токен бота Discord.",
"Discord could not be reached. Delivery will retry.": "Discord недоступен. Отправка будет повторена.",
"Discord rate limit. Delivery will retry.": "Discord ограничил частоту запросов. Отправка будет повторена.",
"Discord rejected this notification.": "Discord отклонил это объявление.",
"Discord did not confirm delivery.": "Discord не подтвердил отправку.",
"Discord delivery could not be confirmed. Delivery will retry.": "Не удалось подтвердить отправку в Discord. Она будет повторена."
}

View File

@@ -48,6 +48,7 @@ export type RoomResult = {
guess: { x: number; z: number } | null;
};
export type RoomView = {
discord?: import("./discord").PartyAnnouncement;
id: string;
datasetId: string;
name: string;

10
shared/permissions.ts Normal file
View File

@@ -0,0 +1,10 @@
export type AccountRole = "contributor" | "moderator" | "admin";
export type StaffRole = Exclude<AccountRole, "contributor">;
export function canReviewMaps(role: string | undefined): role is StaffRole {
return role === "moderator" || role === "admin";
}
export function isAdministrator(role: string | undefined) {
return role === "admin";
}