Rework avatars.
Now we have a concept of an avatar at the server, realm, and scene level
and we have the groundwork for a realm store. New uesrs no longer props,
they get a default avatar. New system supports gender
{male,female,neutral} and {child,adult}.
This commit is contained in:
parent
e4abdb183f
commit
6fb90e42c3
55 changed files with 7392 additions and 512 deletions
|
|
@ -24,6 +24,11 @@ CREATE TABLE auth.users (
|
|||
bio TEXT,
|
||||
avatar_url public.url,
|
||||
|
||||
-- User preferences for default avatar selection
|
||||
birthday DATE,
|
||||
gender_preference auth.gender_preference NOT NULL DEFAULT 'gender_neutral',
|
||||
age_category auth.age_category NOT NULL DEFAULT 'adult',
|
||||
|
||||
reputation_tier server.reputation_tier NOT NULL DEFAULT 'member',
|
||||
reputation_promoted_at TIMESTAMPTZ,
|
||||
|
||||
|
|
@ -634,9 +639,13 @@ CREATE INDEX idx_auth_avatars_default ON auth.avatars (user_id, is_default) WHER
|
|||
CREATE TABLE auth.active_avatars (
|
||||
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
realm_id UUID NOT NULL, -- FK added in 030_realm.sql after realm.realms exists
|
||||
avatar_id UUID NOT NULL REFERENCES auth.avatars(id) ON DELETE CASCADE,
|
||||
avatar_id UUID REFERENCES auth.avatars(id) ON DELETE SET NULL,
|
||||
|
||||
current_emotion SMALLINT NOT NULL DEFAULT 0 CHECK (current_emotion >= 0 AND current_emotion <= 11),
|
||||
-- User-selected avatars from avatar stores (lower priority than custom avatar)
|
||||
selected_server_avatar_id UUID, -- FK added in 025_server_avatars.sql
|
||||
selected_realm_avatar_id UUID, -- FK added in 035_realm_avatars.sql
|
||||
|
||||
current_emotion server.emotion_state NOT NULL DEFAULT 'happy',
|
||||
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
|
|
@ -644,6 +653,12 @@ CREATE TABLE auth.active_avatars (
|
|||
);
|
||||
|
||||
COMMENT ON TABLE auth.active_avatars IS 'Current avatar per user per realm';
|
||||
COMMENT ON COLUMN auth.active_avatars.avatar_id IS
|
||||
'User custom avatar (highest priority, nullable for users without custom avatars)';
|
||||
COMMENT ON COLUMN auth.active_avatars.selected_server_avatar_id IS
|
||||
'User-selected server avatar (from avatar store), lower priority than custom avatar';
|
||||
COMMENT ON COLUMN auth.active_avatars.selected_realm_avatar_id IS
|
||||
'User-selected realm avatar (from avatar store), higher priority than server selection';
|
||||
|
||||
-- =============================================================================
|
||||
-- Server-Level Moderation: IP Bans
|
||||
|
|
|
|||
222
db/schema/tables/025_server_avatars.sql
Normal file
222
db/schema/tables/025_server_avatars.sql
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
-- =============================================================================
|
||||
-- Server Avatars
|
||||
-- =============================================================================
|
||||
-- Pre-configured avatar configurations available globally across all realms.
|
||||
-- These reference server.props directly (not inventory items).
|
||||
--
|
||||
-- Loaded after 020_auth.sql (server.props must exist)
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE server.avatars (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
||||
slug public.slug NOT NULL,
|
||||
name public.nonempty_text NOT NULL,
|
||||
description TEXT,
|
||||
|
||||
is_public BOOLEAN NOT NULL DEFAULT false,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
thumbnail_path public.asset_path,
|
||||
|
||||
-- Content layers: 3 layers x 9 positions = 27 slots
|
||||
-- All reference server.props(id) directly
|
||||
l_skin_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_skin_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
l_clothes_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_clothes_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
l_accessories_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
l_accessories_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
-- Emotion layers: 12 emotions x 9 positions = 108 slots
|
||||
e_neutral_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_neutral_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_happy_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_happy_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_sad_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sad_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_angry_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_angry_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_surprised_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_surprised_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_thinking_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_thinking_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_laughing_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_laughing_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_crying_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_crying_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_love_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_love_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_confused_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_confused_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_sleeping_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_wink_0 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_1 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_2 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_3 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_4 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_5 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_6 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_7 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
e_wink_8 UUID REFERENCES server.props(id) ON DELETE SET NULL,
|
||||
|
||||
created_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT uq_server_avatars_slug UNIQUE (slug)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE server.avatars IS 'Pre-configured avatar configurations available globally (references server.props)';
|
||||
|
||||
CREATE INDEX idx_server_avatars_active ON server.avatars (is_active) WHERE is_active = true;
|
||||
CREATE INDEX idx_server_avatars_public ON server.avatars (is_public) WHERE is_public = true;
|
||||
|
||||
COMMENT ON COLUMN server.avatars.is_public IS
|
||||
'When true, avatar appears in the public avatar selection. Uses filtered index.';
|
||||
|
||||
-- =============================================================================
|
||||
-- Add Default Avatar Columns to server.config
|
||||
-- =============================================================================
|
||||
-- These columns reference server.avatars for gender/age-based default avatars.
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE server.config
|
||||
ADD COLUMN default_avatar_neutral_child UUID REFERENCES server.avatars(id) ON DELETE SET NULL,
|
||||
ADD COLUMN default_avatar_neutral_adult UUID REFERENCES server.avatars(id) ON DELETE SET NULL,
|
||||
ADD COLUMN default_avatar_male_child UUID REFERENCES server.avatars(id) ON DELETE SET NULL,
|
||||
ADD COLUMN default_avatar_male_adult UUID REFERENCES server.avatars(id) ON DELETE SET NULL,
|
||||
ADD COLUMN default_avatar_female_child UUID REFERENCES server.avatars(id) ON DELETE SET NULL,
|
||||
ADD COLUMN default_avatar_female_adult UUID REFERENCES server.avatars(id) ON DELETE SET NULL;
|
||||
|
||||
COMMENT ON COLUMN server.config.default_avatar_neutral_child IS
|
||||
'Default server avatar for gender-neutral child users';
|
||||
COMMENT ON COLUMN server.config.default_avatar_neutral_adult IS
|
||||
'Default server avatar for gender-neutral adult users';
|
||||
COMMENT ON COLUMN server.config.default_avatar_male_child IS
|
||||
'Default server avatar for male child users';
|
||||
COMMENT ON COLUMN server.config.default_avatar_male_adult IS
|
||||
'Default server avatar for male adult users';
|
||||
COMMENT ON COLUMN server.config.default_avatar_female_child IS
|
||||
'Default server avatar for female child users';
|
||||
COMMENT ON COLUMN server.config.default_avatar_female_adult IS
|
||||
'Default server avatar for female adult users';
|
||||
|
||||
-- =============================================================================
|
||||
-- Add FK for auth.active_avatars.selected_server_avatar_id
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE auth.active_avatars
|
||||
ADD CONSTRAINT fk_auth_active_avatars_selected_server_avatar
|
||||
FOREIGN KEY (selected_server_avatar_id) REFERENCES server.avatars(id) ON DELETE SET NULL;
|
||||
|
|
@ -35,6 +35,15 @@ CREATE TABLE realm.realms (
|
|||
|
||||
default_scene_id UUID,
|
||||
|
||||
-- Default avatars for this realm (optional, override server defaults)
|
||||
-- FK constraints added in 035_realm_avatars.sql after realm.avatars exists
|
||||
default_avatar_neutral_child UUID,
|
||||
default_avatar_neutral_adult UUID,
|
||||
default_avatar_male_child UUID,
|
||||
default_avatar_male_adult UUID,
|
||||
default_avatar_female_child UUID,
|
||||
default_avatar_female_adult UUID,
|
||||
|
||||
member_count INTEGER NOT NULL DEFAULT 0 CHECK (member_count >= 0),
|
||||
current_user_count INTEGER NOT NULL DEFAULT 0 CHECK (current_user_count >= 0),
|
||||
|
||||
|
|
|
|||
288
db/schema/tables/035_realm_avatars.sql
Normal file
288
db/schema/tables/035_realm_avatars.sql
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
-- =============================================================================
|
||||
-- Realm Avatars and Forced Avatar Support
|
||||
-- =============================================================================
|
||||
-- Pre-configured avatar configurations specific to a realm.
|
||||
-- These reference realm.props directly (not inventory items).
|
||||
--
|
||||
-- Also adds forced avatar support to auth.active_avatars and realm.scenes.
|
||||
--
|
||||
-- Loaded after 030_realm.sql (realm.props must exist)
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- Realm Avatars Table
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE realm.avatars (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
||||
realm_id UUID NOT NULL REFERENCES realm.realms(id) ON DELETE CASCADE,
|
||||
|
||||
slug public.slug NOT NULL,
|
||||
name public.nonempty_text NOT NULL,
|
||||
description TEXT,
|
||||
|
||||
is_public BOOLEAN NOT NULL DEFAULT false,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
thumbnail_path public.asset_path,
|
||||
|
||||
-- Content layers: 3 layers x 9 positions = 27 slots
|
||||
-- All reference realm.props(id) directly (realm props only, no server props)
|
||||
l_skin_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_skin_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
l_clothes_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_clothes_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
l_accessories_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
l_accessories_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
-- Emotion layers: 12 emotions x 9 positions = 108 slots
|
||||
e_neutral_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_neutral_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_happy_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_happy_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_sad_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sad_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_angry_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_angry_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_surprised_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_surprised_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_thinking_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_thinking_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_laughing_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_laughing_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_crying_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_crying_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_love_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_love_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_confused_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_confused_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_sleeping_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_sleeping_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
e_wink_0 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_1 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_2 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_3 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_4 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_5 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_6 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_7 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
e_wink_8 UUID REFERENCES realm.props(id) ON DELETE SET NULL,
|
||||
|
||||
created_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
CONSTRAINT uq_realm_avatars_slug UNIQUE (realm_id, slug)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE realm.avatars IS 'Pre-configured avatar configurations specific to a realm (references realm.props only)';
|
||||
|
||||
CREATE INDEX idx_realm_avatars_realm ON realm.avatars (realm_id);
|
||||
CREATE INDEX idx_realm_avatars_active ON realm.avatars (realm_id, is_active) WHERE is_active = true;
|
||||
CREATE INDEX idx_realm_avatars_public ON realm.avatars (realm_id, is_public) WHERE is_public = true;
|
||||
|
||||
COMMENT ON COLUMN realm.avatars.is_public IS
|
||||
'When true, avatar appears in the public avatar selection for this realm. Uses filtered index.';
|
||||
|
||||
-- =============================================================================
|
||||
-- Add Default Avatar FK Constraints to realm.realms
|
||||
-- =============================================================================
|
||||
-- Now that realm.avatars exists, add the FK constraints for default avatars.
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE realm.realms
|
||||
ADD CONSTRAINT fk_realm_default_avatar_neutral_child
|
||||
FOREIGN KEY (default_avatar_neutral_child) REFERENCES realm.avatars(id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT fk_realm_default_avatar_neutral_adult
|
||||
FOREIGN KEY (default_avatar_neutral_adult) REFERENCES realm.avatars(id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT fk_realm_default_avatar_male_child
|
||||
FOREIGN KEY (default_avatar_male_child) REFERENCES realm.avatars(id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT fk_realm_default_avatar_male_adult
|
||||
FOREIGN KEY (default_avatar_male_adult) REFERENCES realm.avatars(id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT fk_realm_default_avatar_female_child
|
||||
FOREIGN KEY (default_avatar_female_child) REFERENCES realm.avatars(id) ON DELETE SET NULL,
|
||||
ADD CONSTRAINT fk_realm_default_avatar_female_adult
|
||||
FOREIGN KEY (default_avatar_female_adult) REFERENCES realm.avatars(id) ON DELETE SET NULL;
|
||||
|
||||
COMMENT ON COLUMN realm.realms.default_avatar_neutral_child IS
|
||||
'Default realm avatar for gender-neutral child users (overrides server default)';
|
||||
COMMENT ON COLUMN realm.realms.default_avatar_neutral_adult IS
|
||||
'Default realm avatar for gender-neutral adult users (overrides server default)';
|
||||
COMMENT ON COLUMN realm.realms.default_avatar_male_child IS
|
||||
'Default realm avatar for male child users (overrides server default)';
|
||||
COMMENT ON COLUMN realm.realms.default_avatar_male_adult IS
|
||||
'Default realm avatar for male adult users (overrides server default)';
|
||||
COMMENT ON COLUMN realm.realms.default_avatar_female_child IS
|
||||
'Default realm avatar for female child users (overrides server default)';
|
||||
COMMENT ON COLUMN realm.realms.default_avatar_female_adult IS
|
||||
'Default realm avatar for female adult users (overrides server default)';
|
||||
|
||||
-- =============================================================================
|
||||
-- Add FK for auth.active_avatars.selected_realm_avatar_id
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TABLE auth.active_avatars
|
||||
ADD CONSTRAINT fk_auth_active_avatars_selected_realm_avatar
|
||||
FOREIGN KEY (selected_realm_avatar_id) REFERENCES realm.avatars(id) ON DELETE SET NULL;
|
||||
|
||||
-- =============================================================================
|
||||
-- Add Forced Avatar Columns to auth.active_avatars
|
||||
-- =============================================================================
|
||||
-- Tracks when a user has a forced avatar (from mod command or scene entry)
|
||||
|
||||
ALTER TABLE auth.active_avatars
|
||||
ADD COLUMN forced_avatar_id UUID,
|
||||
ADD COLUMN forced_avatar_source TEXT
|
||||
CHECK (forced_avatar_source IS NULL OR forced_avatar_source IN ('server', 'realm', 'scene')),
|
||||
ADD COLUMN forced_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
ADD COLUMN forced_until TIMESTAMPTZ;
|
||||
|
||||
COMMENT ON COLUMN auth.active_avatars.forced_avatar_id IS
|
||||
'UUID of the forced avatar (from server.avatars or realm.avatars depending on source)';
|
||||
COMMENT ON COLUMN auth.active_avatars.forced_avatar_source IS
|
||||
'Source of forced avatar: server (server.avatars), realm (realm.avatars), or scene (from scene setting)';
|
||||
COMMENT ON COLUMN auth.active_avatars.forced_by IS
|
||||
'User who forced this avatar (moderator), NULL for scene-forced';
|
||||
COMMENT ON COLUMN auth.active_avatars.forced_until IS
|
||||
'When the forced avatar expires, NULL for permanent/until manually cleared';
|
||||
|
||||
-- Index for finding expired forced avatars
|
||||
CREATE INDEX idx_auth_active_avatars_forced_expires
|
||||
ON auth.active_avatars (forced_until)
|
||||
WHERE forced_until IS NOT NULL;
|
||||
|
||||
-- =============================================================================
|
||||
-- Add Forced Avatar Columns to realm.scenes
|
||||
-- =============================================================================
|
||||
-- Allows scenes to force all users to wear a specific avatar
|
||||
|
||||
ALTER TABLE realm.scenes
|
||||
ADD COLUMN forced_avatar_id UUID,
|
||||
ADD COLUMN forced_avatar_source TEXT
|
||||
CHECK (forced_avatar_source IS NULL OR forced_avatar_source IN ('server', 'realm'));
|
||||
|
||||
COMMENT ON COLUMN realm.scenes.forced_avatar_id IS
|
||||
'UUID of avatar all users must wear in this scene (from server.avatars or realm.avatars)';
|
||||
COMMENT ON COLUMN realm.scenes.forced_avatar_source IS
|
||||
'Source of forced avatar: server (server.avatars) or realm (realm.avatars)';
|
||||
|
||||
-- =============================================================================
|
||||
-- Add New Moderation Action Types
|
||||
-- =============================================================================
|
||||
|
||||
ALTER TYPE server.action_type ADD VALUE 'dress_user';
|
||||
ALTER TYPE server.action_type ADD VALUE 'undress_user';
|
||||
ALTER TYPE server.action_type ADD VALUE 'teleport';
|
||||
|
||||
COMMENT ON TYPE server.action_type IS 'Type of moderation action taken (includes dress_user, undress_user, teleport)';
|
||||
Loading…
Add table
Add a link
Reference in a new issue