Require distinct panorama locations for rounds and captures
Some checks failed
Deploy MineGeo to Dokploy / deploy (push) Failing after 6m30s

This commit is contained in:
2026-10-16 10:09:36 +05:00
parent c9fc9496eb
commit 1a34eb71c2
16 changed files with 367 additions and 3 deletions

View File

@@ -0,0 +1,97 @@
-- Capture IDs are unique, but multiple captures can still share a camera
-- position or the same six image files. Deduplicate before sampling rounds.
create or replace function public.game_viewpoint_pool(p_manifest jsonb, p_root text)
returns jsonb language sql immutable security invoker set search_path = '' as $$
with by_location as (
select distinct on (
floor((p->>'x')::numeric), floor((p->>'y')::numeric), floor((p->>'z')::numeric)
) p, n
from jsonb_array_elements(p_manifest->'viewpoints') with ordinality points(p, n)
order by floor((p->>'x')::numeric), floor((p->>'y')::numeric),
floor((p->>'z')::numeric), n
), by_media as (
select distinct on (
coalesce(p->>'assetRoot', p_root), coalesce(p->>'assetId', p->>'id')
) p, n from by_location
order by coalesce(p->>'assetRoot', p_root), coalesce(p->>'assetId', p->>'id'), n
)
select coalesce(jsonb_agg(p order by n), '[]'::jsonb) from by_media;
$$;
revoke all on function public.game_viewpoint_pool(jsonb, text)
from public, anon, authenticated;
grant execute on function public.game_viewpoint_pool(jsonb, text) to service_role;
create or replace function public.create_game(
p_dataset uuid, p_difficulty text, p_owner uuid, p_access_hash text
) returns uuid language plpgsql security invoker set search_path = '' as $$
declare
sid uuid;
revision uuid;
rev public.revisions;
vp jsonb;
locations jsonb;
n integer := 0;
settings jsonb;
begin
settings := public.resolve_difficulty_preset(p_difficulty);
revision := public.playable_map_revision(p_dataset, p_owner);
select * into rev from public.revisions where id = revision;
if not found then raise exception 'Map unavailable'; end if;
locations := public.game_viewpoint_pool(rev.manifest, rev.asset_root);
if jsonb_array_length(locations) < 5 then
raise exception 'Map needs at least five distinct panorama locations';
end if;
insert into public.game_sessions(
revision_id, owner_id, access_hash, difficulty, difficulty_settings
) values (rev.id, p_owner, p_access_hash, p_difficulty, settings)
returning id into sid;
for vp in select value from jsonb_array_elements(locations) order by random() limit 5
loop
insert into public.game_rounds(session_id, round_number, viewpoint)
values (sid, n, vp);
n := n + 1;
end loop;
return sid;
end;
$$;
create or replace function public.create_map_room(
p_dataset uuid, p_difficulty text, p_name text, p_limit integer,
p_access_hash text, p_owner uuid
) returns uuid language plpgsql security invoker set search_path = '' as $$
declare
rid uuid;
revision uuid;
pid uuid := gen_random_uuid();
rev public.revisions;
vp jsonb;
locations jsonb;
n integer := 0;
settings jsonb;
begin
if p_limit is null or p_limit not between 2 and 16 then
raise exception 'Choose between 2 and 16 players';
end if;
settings := public.resolve_difficulty_preset(p_difficulty);
revision := public.playable_map_revision(p_dataset, p_owner);
select * into rev from public.revisions where id = revision;
if not found then raise exception 'Map unavailable'; end if;
locations := public.game_viewpoint_pool(rev.manifest, rev.asset_root);
if jsonb_array_length(locations) < 5 then
raise exception 'Map needs at least five distinct panorama locations';
end if;
insert into public.multiplayer_rooms(
revision_id, host_player_id, difficulty, difficulty_settings, player_limit
) values (rev.id, pid, p_difficulty, settings, p_limit)
returning id into rid;
insert into public.multiplayer_players(id, room_id, access_hash, display_name)
values (pid, rid, p_access_hash, btrim(p_name));
for vp in select value from jsonb_array_elements(locations) order by random() limit 5
loop
insert into public.multiplayer_rounds(room_id, round_number, viewpoint)
values (rid, n, vp);
n := n + 1;
end loop;
return rid;
end;
$$;