docs(reference): import Dune: Awakening server-manager references
All checks were successful
CI / backend-types (push) Successful in 10s
CI / frontend-build (push) Successful in 15s
CI / agent-tests (push) Successful in 39s
CI / integration (push) Successful in 22s

Phase 2 references for the host-agent Dune adapter, moved out of volatile /tmp
into docs/reference-repos/ (per Commander). Three upstream projects, .git +
node_modules + compiled binaries stripped (16MB source). Nested AI-instruction
files (.claude/, CLAUDE.md) removed so they don't pollute Corrosion sessions.

- icehunter/    dune-admin (Go+React) — 4 control planes; SETUP_DOCKER.md is the
                closest analog to our agent's Dune docker control plane (compose
                lifecycle, docker logs, RabbitMQ-via-exec, dune Postgres schema)
- adainrivers/  Rust/Tauri desktop — SSH+k8s BattleGroup control, maintenance
                daemon, in-game admin console (Rust idiom reference)
- the4rchangel/ Node web UI replacing battlegroup.bat — matches the Commander's
                Hyper-V self-host path + game-config schema

See docs/reference-repos/README.md for the full index + how we use each.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell
2026-06-11 21:08:05 -04:00
parent 0715492ddf
commit 651a35d4be
1334 changed files with 238971 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
-- _character_transfer_allocate_id(kind dune._charactertransferentrykind, data jsonb) -> bigint
-- oid: 58095 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_allocate_id(kind dune._charactertransferentrykind, data jsonb)
RETURNS bigint
LANGUAGE sql
IMMUTABLE
AS $function$
select case
when kind = 'acc' then nextval('encrypted_accounts_id_seq')
when kind = 'act' then nextval('actors_id_seq')
when kind = 'inv' then nextval('inventories_id_seq')
when kind = 'itm' then nextval('items_id_seq')
when kind = 'fgl' then nextval('character_transfer_fgl_entities_entity_id_seq')
when kind = 'bbp' then nextval('building_blueprints_id_seq')
when kind = 'VehicleModule' then nextval('vehicle_modules_id_seq')
when kind = 'Faction' then (select id from factions where "name" = data->>'name')
when kind = 'Tutorial' then (select id from tutorials where "name" = data->>'name')
when kind = 'Keystone' then (select id from specialization_keystones_map where "name" = data->>'name')
when kind = 'BaseBackup' then nextval('base_backups_id_seq')
when kind = 'TaxInvoice' then nextval('tax_invoice_id_seq')
when kind = 'DungeonCompletion' then nextval('dungeon_completion_completion_id_seq')
else null
end;
$function$

View File

@@ -0,0 +1,26 @@
-- _character_transfer_create_data_table() -> void
-- oid: 58096 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_create_data_table()
RETURNS void
LANGUAGE plpgsql
AS $function$
begin
if not exists (
select 1 from pg_catalog.pg_tables
where schemaname=(select nspname from pg_catalog.pg_namespace where oid=pg_my_temp_schema())
and tablename = 'export_data'
) then
create temporary table if not exists pg_temp.export_data (
"id" BigInt DEFAULT NULL,
"transfer_id" BigSerial PRIMARY KEY NOT NULL,
"kind" _CharacterTransferEntryKind NOT NULL,
"data" JsonB NOT NULL
) on commit drop;
create index on pg_temp.export_data("id");
create index on pg_temp.export_data("kind");
end if;
alter sequence pg_temp.export_data_transfer_id_seq restart with 1;
truncate pg_temp.export_data;
end
$function$

View File

@@ -0,0 +1,10 @@
-- _character_transfer_data_filter(id text, removed text[], VARIADIC refs dune._charactertransferdatafilterref[]) -> dune._charactertransferdatafilter
-- oid: 58097 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_data_filter(id text, removed text[], VARIADIC refs dune._charactertransferdatafilterref[] DEFAULT '{}'::dune._charactertransferdatafilterref[])
RETURNS dune._charactertransferdatafilter
LANGUAGE sql
IMMUTABLE
AS $function$
select (id, removed, refs)::_CharacterTransferDataFilter;
$function$

View File

@@ -0,0 +1,20 @@
-- _character_transfer_data_table_load(entries jsonb) -> void
-- oid: 58098 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_data_table_load(entries jsonb)
RETURNS void
LANGUAGE plpgsql
AS $function$
begin
with parsed as (
select
(entry->>'id')::BigInt as transfer_id,
(entry->>'kind')::_CharacterTransferEntryKind as kind,
(entry->'data') as data
from jsonb_array_elements(entries) as entry
)
insert into pg_temp.export_data("id", "transfer_id", "kind", "data")
select _character_transfer_allocate_id(kind, data) as id, transfer_id, kind, data
from parsed;
end
$function$

View File

@@ -0,0 +1,11 @@
-- _character_transfer_data_table_save() -> jsonb
-- oid: 58099 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_data_table_save()
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
begin
return (select jsonb_agg(jsonb_build_object('id', transfer_id, 'kind', kind, 'data', data)) from pg_temp.export_data);
end
$function$

View File

@@ -0,0 +1,109 @@
-- _character_transfer_get_filter(kind dune._charactertransferentrykind) -> dune._charactertransferdatafilter
-- oid: 58101 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_get_filter(kind dune._charactertransferentrykind)
RETURNS dune._charactertransferdatafilter
LANGUAGE sql
IMMUTABLE
AS $function$
select case
when kind = 'acc' then _character_transfer_data_filter('id', '{user,funcom_id}')
when kind = 'act' then _character_transfer_data_filter('id', '{}', ('owner_account_id', 'acc', false))
when kind = 'inv' then _character_transfer_data_filter(
'id',
'{exchange_id,item_id}',
('actor_id', 'act', false),
('vehicle_module_id', 'VehicleModule', false)
)
when kind = 'itm' then _character_transfer_data_filter(
'id', '{}',
('inventory_id', 'inv', true)
)
when kind = 'fgl' then _character_transfer_data_filter(
'entity_id', '{}',
('actor_id', 'act', true)
)
when kind = 'bbp' then _character_transfer_data_filter(
'id', '{}',
('item_id', 'itm', true),
('player_id', 'act', false)
)
when kind = 'Faction' then _character_transfer_data_filter('id', '{}')
when kind = 'Tutorial' then _character_transfer_data_filter('id', '{}')
when kind = 'Keystone' then _character_transfer_data_filter('id', '{}')
when kind = 'Character' then _character_transfer_data_filter(
null, '{character_name}',
('account_id', 'acc', true),
('player_pawn_id', 'act', true),
('player_controller_id', 'act', true),
('player_state_id', 'act', true)
)
when kind = 'RespawnLocation' then _character_transfer_data_filter(
null, '{}',
('account_id', 'acc', true)
)
when kind = 'PlayerMarker' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true))
when kind = 'Marker' then _character_transfer_data_filter(null, '{}')
when kind = 'DialogueMetNpc' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true))
when kind = 'DialogueTakenNode' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true))
when kind = 'PlayerFaction' then _character_transfer_data_filter(
null, '{}',
('actor_id', 'act', true), ('faction_id', 'Faction', true)
)
when kind = 'PlayerFactionReputation' then _character_transfer_data_filter(
null, '{}',
('actor_id', 'act', true), ('faction_id', 'Faction', true)
)
when kind = 'ConsumedLore' then _character_transfer_data_filter(null, '{}', ('actor_id', 'act', true))
when kind = 'PlayerTutorial' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true), ('tutorial_id', 'Tutorial', true))
when kind = 'PurchasedKeystone' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true), ('keystone_id', 'Keystone', true))
when kind = 'SpecializationTracks' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true))
when kind = 'SpecializationRefund' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true))
when kind = 'BuildingFavorite' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'BuildingProgression' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'CommuninetPlayer' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'CommuninetPlayerChannel' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'JourneyStoryNode' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'MapArea' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'PlayerAccessCode' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'PlayerTag' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true))
when kind = 'ActorInventory' then _character_transfer_data_filter(null, '{}', ('inventory_id', 'inv', true))
when kind = 'Sinkchart' then _character_transfer_data_filter(null, '{}', ('item_id', 'itm', true))
when kind = 'BackupVehicle' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true), ('vehicle_id', 'act', true))
when kind = 'RecoveredVehicle' then _character_transfer_data_filter(null, '{}', ('account_id', 'acc', true), ('vehicle_id', 'act', true))
when kind = 'Vehicle' then _character_transfer_data_filter(null, '{}', ('id', 'act', true))
when kind = 'VehicleModule' then _character_transfer_data_filter('id', '{}', ('vehicle_id', 'act', true))
when kind = 'VehicleModuleInventory' then _character_transfer_data_filter(null, '{}', ('inventory_id', 'inv', true))
when kind = 'ActorState' then _character_transfer_data_filter(null, '{}', ('actor_id', 'act', true))
when kind = 'PermissionActor' then _character_transfer_data_filter(null, '{}', ('actor_id', 'act', true))
when kind = 'PermissionActorRank' then _character_transfer_data_filter(null, '{}', ('permission_actor_id', 'act', true), ('player_id', 'act', true))
when kind = 'BuildingBlueprintInstance' then _character_transfer_data_filter(null, '{}', ('building_blueprint_id', 'bbp', true))
when kind = 'BuildingBlueprintPlaceable' then _character_transfer_data_filter(null, '{}', ('building_blueprint_id', 'bbp', true))
when kind = 'BuildingBlueprintPentashield' then _character_transfer_data_filter(null, '{}', ('building_blueprint_id', 'bbp', true))
when kind = 'Building' then _character_transfer_data_filter(null, '{}', ('id', 'act', true))
when kind = 'BuildingInstance' then _character_transfer_data_filter(null, '{}', ('building_id', 'act', true), ('owner_entity_id', 'fgl', false))
when kind = 'Placeable' then _character_transfer_data_filter(null, '{}', ('id', 'act', true), ('owner_entity_id', 'fgl', false))
when kind = 'BaseBackup' then _character_transfer_data_filter('id', '{}', ('player_id', 'act', true))
when kind = 'BaseBackupLinkedActor' then _character_transfer_data_filter(null, '{}', ('id', 'BaseBackup', true), ('actor_id', 'act', true))
when kind = 'LandclaimSegment' then _character_transfer_data_filter(null, '{}', ('totem_id', 'act', true))
when kind = 'TaxInvoice' then _character_transfer_data_filter('id', '{}', ('totem_id', 'act', true))
when kind = 'PlayerVirtualCurrencyBalance' then _character_transfer_data_filter(null, '{}', ('player_controller_id', 'act', true))
when kind = 'DungeonCompletion' then _character_transfer_data_filter('completion_id', '{}')
when kind = 'DungeonCompletionPlayer' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true), ('completion_id', 'DungeonCompletion', true))
when kind = 'Totem' then _character_transfer_data_filter(null, '{}', ('id', 'act', true))
when kind = 'LandsraadHouseRewards' then _character_transfer_data_filter(null, '{}', ('player_id', 'act', true))
end;
$function$

View File

@@ -0,0 +1,11 @@
-- _character_transfer_get_patches_checksum() -> text
-- oid: 58102 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_get_patches_checksum()
RETURNS text
LANGUAGE plpgsql
AS $function$
begin
return (SELECT md5(coalesce(string_agg("name", ',' ORDER BY "name"), '')) FROM applied_patches);
end
$function$

View File

@@ -0,0 +1,39 @@
-- _character_transfer_pre_export_validation(in_fls_id text) -> TABLE(out_acc_id bigint, out_funcom_id text, out_player_controller_id bigint, out_player_pawn_id bigint)
-- oid: 58103 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_pre_export_validation(in_fls_id text)
RETURNS TABLE(out_acc_id bigint, out_funcom_id text, out_player_controller_id bigint, out_player_pawn_id bigint)
LANGUAGE plpgsql
AS $function$
DECLARE
v_acc_id BigInt;
v_funcom_id Text;
v_player_controller_id BigInt;
v_player_pawn_id BigInt;
BEGIN
if not (select is_player_offline(in_fls_id)) then
raise exception 'sbRF3$ - player_online: Player % must be Offline', in_fls_id;
end if;
v_acc_id := (select id from accounts where "user" = in_fls_id);
IF v_acc_id is null THEN
RAISE EXCEPTION 'sbFV2$ - unknown_fls_id: FLS ID % not found', in_fls_id;
END IF;
v_funcom_id := (select funcom_id from accounts where "user" = in_fls_id);
IF v_funcom_id is null THEN
RAISE EXCEPTION 'sb9X3$ - missing_funcom_id: Player % does not have a funcomId', in_fls_id;
END IF;
select into v_player_controller_id, v_player_pawn_id
player_controller_id, player_pawn_id from player_state where account_id=v_acc_id;
if v_player_controller_id is null then
raise exception 'sbH84$ - missing_controller: Player % does not have a controller', in_fls_id;
end if;
if v_player_pawn_id is null then
raise exception 'sbHF3$ - missing_character: Player % does not have a character', in_fls_id;
end if;
return query select v_acc_id, v_funcom_id, v_player_controller_id, v_player_pawn_id;
END;
$function$

View File

@@ -0,0 +1,22 @@
-- _character_transfer_property_not_exported_is_expected(path text) -> boolean
-- oid: 58104 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_property_not_exported_is_expected(path text)
RETURNS boolean
LANGUAGE sql
IMMUTABLE
AS $function$
select (path = ANY(ARRAY[
'.properties.BP_DunePlayerCharacter_C.m_CurrentVehicleId',
'.properties.WeaponActorComponent.m_FavoriteWeaponItemDatabaseId',
'.properties.ContractsCoordinatorComponent.m_TrackedContractItemUid',
'.components.FItemCraftingComponent.*.RequestsQueue.*.InstigatorActorId',
'.stats.FSinkchartsStats.*.CreatorPlayerId',
'.components.FItemCraftingComponent.*.RequestsQueue.*.IngredientAllocations.*.ItemAllocNodes.*.AllocatedItems.*.ItemUniqueId', -- TODO [DA-4712]: Remove once this item loss is fixed
'.stats.FBuildingBlueprintItemStats.*.PlayerBlueprintId', -- TODO [DA-4721]: Remove once this item loss is fixed
'.properties.BP_TransportOrnithopter_CHOAM_C.m_HarnessedVehicleId',
'.stats.FReferenceItemStats.*.ReferenceDatabaseId', -- These often point to items that no longer exist
'.components.FTotemLandclaimComponent.*.m_PendingStakingUnitsEntityIds.*', -- Staking units are not transferred with the base backup. This is missing a cleanup
'.components.FTotemLandclaimComponent.*.m_PendingVerticalStakingUnitsEntityIds.*' -- Staking units are not transferred with the base backup. This is missing a cleanup
]::text[]));
$function$

View File

@@ -0,0 +1,43 @@
-- _character_transfer_replace_local_id_with_transfer_id(data text, path text) -> text
-- oid: 58105 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_replace_local_id_with_transfer_id(data text, path text)
RETURNS text
LANGUAGE plpgsql
AS $function$
declare
v_kind _CharacterTransferEntryKind;
v_raw_kind Text;
v_id BigInt;
v_transfer_id BigInt;
begin
v_raw_kind = substring(data from 3 for 3);
begin
v_kind := v_raw_kind::_CharacterTransferEntryKind;
exception
when invalid_text_representation then
raise exception 'sbPH2$ - Invalid transfer id in data "%" at "%", unknown kind: %', data, path, v_raw_kind;
end;
v_id := (substring(data from 7))::BigInt;
if v_id = 0 then
return format('!!%s@0', v_kind::text);
end if;
if v_id < 0 and v_id >= -2147483648 then
v_id := v_id + 4294967296;
end if;
v_transfer_id := (select transfer_id from pg_temp.export_data where id=v_id and kind=v_kind);
if v_transfer_id is null then
if _character_transfer_property_not_exported_is_expected(path) then
return format('!!%s@0', v_kind::text);
else
raise exception 'sbQ73$ - Id % by % was not exported', data, path;
end if;
end if;
return format('!!%s@%s', v_kind::text, v_transfer_id::text);
end
$function$

View File

@@ -0,0 +1,24 @@
-- _character_transfer_replace_local_id_with_transfer_id_in_json(data jsonb, path text) -> jsonb
-- oid: 58106 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_replace_local_id_with_transfer_id_in_json(data jsonb, path text)
RETURNS jsonb
LANGUAGE sql
AS $function$
select case
when data is json array then
(select coalesce(jsonb_agg(_character_transfer_replace_local_id_with_transfer_id_in_json(
element, path || '.*'
)), '[]'::jsonb) from jsonb_array_elements(data) as element)
when data is json object then
(select coalesce(jsonb_object_agg(key, _character_transfer_replace_local_id_with_transfer_id_in_json(
value, path || '.' || key
)), '{}'::jsonb) from jsonb_each(data))
when data is json scalar and jsonb_typeof(data) = 'string' and (data #>> '{}') like '!!___#%' then
(select to_jsonb(_character_transfer_replace_local_id_with_transfer_id(
data #>> '{}', path
)))
else
data
end;
$function$

View File

@@ -0,0 +1,31 @@
-- _character_transfer_replace_transfer_id_with_local_id(data text, path text) -> text
-- oid: 58107 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_replace_transfer_id_with_local_id(data text, path text)
RETURNS text
LANGUAGE plpgsql
AS $function$
declare
v_kind _CharacterTransferEntryKind;
v_id BigInt;
v_transfer_id BigInt;
begin
if substring(data from 6 for 1) != '@' then
raise exception 'sbFM3$ - Invalid transfer id % at %: expected @ separator', data, path;
end if;
v_kind := substring(data from 3 for 3)::_CharacterTransferEntryKind;
v_transfer_id := (substring(data from 7))::BigInt;
if v_transfer_id = 0 then
return format('!!%s#0', v_kind::text);
end if;
v_id := (select id from pg_temp.export_data where transfer_id=v_transfer_id and kind=v_kind);
if v_id is null then
raise exception 'sbQ64$ - Transfer id % at % was not imported', data, path;
end if;
return format('!!%s#%s', v_kind::text, v_id::text);
end
$function$

View File

@@ -0,0 +1,47 @@
-- _character_transfer_replace_transfer_id_with_local_id_in_json(data jsonb, path text) -> jsonb
-- oid: 58108 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_replace_transfer_id_with_local_id_in_json(data jsonb, path text)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
declare
v_id_str Text;
begin
if data is json array then
return (
select coalesce(jsonb_agg(_character_transfer_replace_transfer_id_with_local_id_in_json(
element, path || '.*'
)), '[]'::jsonb) from jsonb_array_elements(data) as element
);
end if;
if data is json object then
return (
select coalesce(jsonb_object_agg(key, _character_transfer_replace_transfer_id_with_local_id_in_json(
value, path || '.' || key
)), '{}'::jsonb) from jsonb_each(data)
);
end if;
if data is json scalar then
if jsonb_typeof(data) = 'string' then
v_id_str := (data #>> '{}');
if v_id_str like '!!___#%' then
raise exception 'sbJ34$ - Non-transfer id % is found at %', v_id_str, path;
end if;
if v_id_str like '!!___@%' then
return (select to_jsonb(_character_transfer_replace_transfer_id_with_local_id(v_id_str, path)));
end if;
if v_id_str = '!!@0' then
raise exception 'sb5G3$ - Transfer id missing kind marker at %: %', path, v_id_str;
end if;
end if;
end if;
return data;
end
$function$

View File

@@ -0,0 +1,40 @@
-- _character_transfer_top_level_export(in_kind dune._charactertransferentrykind, data jsonb) -> jsonb
-- oid: 58110 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_top_level_export(in_kind dune._charactertransferentrykind, data jsonb)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
declare
v_id BigInt;
v_transfer_id BigInt;
v_ref _CharacterTransferDataFilterRef;
v_filter _CharacterTransferDataFilter;
begin
v_filter := _character_transfer_get_filter(in_kind);
data := data - (v_filter).removed;
if (v_filter).id is not null then
data := data - (v_filter).id;
end if;
foreach v_ref in array (v_filter).refs loop
v_id := (data->>((v_ref).key))::BigInt;
if v_id is null then
if (v_ref).required then
raise exception 'sbP23$ - Required reference % not found in %', v_ref, data;
else
continue;
end if;
end if;
v_transfer_id := (select transfer_id from pg_temp.export_data where kind=(v_ref).kind and id=v_id);
if v_transfer_id is null then
raise exception 'sbJG2$ - Id % in % not mapped into transfer id of kind %. Id exists as kind: %',
v_id, data, (v_ref).kind, (select kind from pg_temp.export_data where id=v_id);
end if;
data := jsonb_set(data, array[(v_ref).key], to_jsonb(v_transfer_id));
end loop;
return data;
end
$function$

View File

@@ -0,0 +1,44 @@
-- _character_transfer_top_level_import(in_kind dune._charactertransferentrykind, data jsonb, in_id bigint) -> jsonb
-- oid: 58111 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune._character_transfer_top_level_import(in_kind dune._charactertransferentrykind, data jsonb, in_id bigint)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
declare
v_ref_transfer_id BigInt;
v_ref_id BigInt;
v_ref _CharacterTransferDataFilterRef;
v_filter _CharacterTransferDataFilter;
begin
v_filter := _character_transfer_get_filter(in_kind);
if (v_filter).id is null then
if in_id is not null then
raise exception 'sbGM2$ - Transfer logic error: not-null in_id for secondary kind: %, data: %', in_kind, data;
end if;
else
if in_id is null then
raise exception 'sb8V2$ - Transfer logic error: null in_id for primary kind: %, data: %', in_kind, data;
end if;
data := data || jsonb_build_object((v_filter).id, in_id);
end if;
foreach v_ref in array (v_filter).refs loop
v_ref_transfer_id := (data->>((v_ref).key))::BigInt;
if v_ref_transfer_id is null then
if (v_ref).required then
raise exception 'sb2C2$ - Missing reference % in import of kind %: %', (v_ref).key, in_kind, data;
else
continue;
end if;
end if;
v_ref_id := (select to_jsonb(id) from pg_temp.export_data where kind=(v_ref).kind and transfer_id=v_ref_transfer_id);
if v_ref_id is null then
raise exception 'sb3W3$ - Unknown reference %s with transfer id % in import for kind %, reference id %: %', (v_ref).key, v_ref_transfer_id, in_kind, v_ref_id, data;
end if;
data := jsonb_set(data, array[(v_ref).key], to_jsonb(v_ref_id));
end loop;
return data;
end
$function$

View File

@@ -0,0 +1,9 @@
-- can_takeover_account(in_user_id text) -> boolean
-- oid: 58156 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.can_takeover_account(in_user_id text)
RETURNS boolean
LANGUAGE sql
AS $function$
select takeoverable from accounts WHERE "user" = in_user_id;
$function$

View File

@@ -0,0 +1,21 @@
-- character_migration_export(in_fls_id text) -> jsonb
-- oid: 58158 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.character_migration_export(in_fls_id text)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
DECLARE
v_player_controller_id BigInt;
BEGIN
select out_player_controller_id
into v_player_controller_id
from _character_transfer_pre_export_validation(in_fls_id);
perform _character_transfer_store_in_world_owned_vehicles_into_recovery(v_player_controller_id);
perform base_backup_save_all_totems_from_player_owner(v_player_controller_id);
-- Add any other migration-specific actions here before the export call
return character_transfer_export(in_fls_id);
END;
$function$

View File

@@ -0,0 +1,12 @@
-- character_migration_import(in_data jsonb, in_fls_id text, in_character_name text) -> bigint
-- oid: 58159 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.character_migration_import(in_data jsonb, in_fls_id text, in_character_name text)
RETURNS bigint
LANGUAGE plpgsql
AS $function$
BEGIN
-- Add any migration-specific actions here before the import call
RETURN character_transfer_import(in_data, in_fls_id, in_character_name);
END
$function$

View File

@@ -0,0 +1,304 @@
-- character_transfer_export(in_fls_id text) -> jsonb
-- oid: 58160 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.character_transfer_export(in_fls_id text)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
DECLARE
v_acc_id BigInt;
v_funcom_id Text;
v_player_controller_id BigInt;
v_player_pawn_id BigInt;
v_vehicle_ids BigInt[];
BEGIN
select out_acc_id, out_funcom_id, out_player_controller_id, out_player_pawn_id
into v_acc_id, v_funcom_id, v_player_controller_id, v_player_pawn_id
from _character_transfer_pre_export_validation(in_fls_id);
perform _character_transfer_create_data_table();
-- accounts
insert into pg_temp.export_data("id", "kind", "data")
select id, 'acc', _character_transfer_top_level_export('acc', to_jsonb(accounts))
from accounts where accounts.id=v_acc_id;
-- Vehicle and player actors
insert into pg_temp.export_data("id", "kind", "data")
select id, 'act', _character_transfer_top_level_export('act', to_jsonb(actors) - 'partition_id' #- '{properties,LandsraadCharacterComponent,m_NextContractAbandonUniverseTimeLimit}')
from actors where id IN (
-- player actors
select unnest(array[player_controller_id, player_state_id, player_pawn_id]) as id
from player_state where account_id=v_acc_id
union
-- backup vehicles
select vehicle_id as id from backup_vehicles where account_id=v_acc_id
union
-- recovered vehicles
select vehicle_id as id from recovered_vehicles where account_id=v_acc_id
union
-- base backup actors
select actor_id as id from base_backup_linked_actors where id IN (
select id from base_backups where player_id=v_player_controller_id
)
);
insert into pg_temp.export_data("id", "kind", "data")
select entity_id, 'fgl', _character_transfer_top_level_export(
'fgl', to_jsonb(fgl_entities) || to_jsonb(actor_fgl_entities)
) from actor_fgl_entities join fgl_entities using (entity_id) where actor_id IN (
select id from pg_temp.export_data where kind='act'
);
-- Actor state entries tied to actors we export
insert into pg_temp.export_data("id", "kind", "data")
select actor_id, 'ActorState', _character_transfer_top_level_export('ActorState', to_jsonb(actor_state))
from actor_state where
actor_id IN (select id from pg_temp.export_data where kind = 'act');
-- Permission data for the transferred actors
insert into pg_temp.export_data("id", "kind", "data")
select actor_id, 'PermissionActor', _character_transfer_top_level_export('PermissionActor', to_jsonb(permission_actor))
from permission_actor where actor_id IN (select id from pg_temp.export_data where kind = 'act');
insert into pg_temp.export_data("id", "kind", "data")
select permission_actor_id, 'PermissionActorRank', _character_transfer_top_level_export('PermissionActorRank', to_jsonb(permission_actor_rank))
from permission_actor_rank where
permission_actor_id IN (select id from pg_temp.export_data where kind = 'act')
and player_id IN (select id from pg_temp.export_data where kind = 'act');
-- vehicles and vehicle modules
insert into pg_temp.export_data("kind", "data")
select 'Vehicle', _character_transfer_top_level_export('Vehicle', to_jsonb(vehicles))
-- vehicle ids are aliases for actor ids
from vehicles where id IN (select id from pg_temp.export_data where kind = 'act');
insert into pg_temp.export_data("id", "kind", "data")
select id, 'VehicleModule', _character_transfer_top_level_export('VehicleModule', to_jsonb(vehicle_modules))
-- vehicle ids are aliases for actor ids
from vehicle_modules where vehicle_id IN (select id from pg_temp.export_data where kind = 'act');
insert into pg_temp.export_data("kind", "data")
select 'BackupVehicle', _character_transfer_top_level_export('BackupVehicle', to_jsonb(backup_vehicles))
from backup_vehicles where account_id=v_acc_id;
insert into pg_temp.export_data("kind", "data")
select 'RecoveredVehicle', _character_transfer_top_level_export('RecoveredVehicle', to_jsonb(recovered_vehicles))
from recovered_vehicles where account_id=v_acc_id;
-- inventories and items
insert into pg_temp.export_data("id", "kind", "data")
select id, 'inv', _character_transfer_top_level_export('inv', to_jsonb(inventories))
from inventories where
actor_id IN (select id from pg_temp.export_data where kind = 'act')
or vehicle_module_id IN (select id from pg_temp.export_data where kind = 'VehicleModule');
insert into pg_temp.export_data("id", "kind", "data")
select id, 'itm', _character_transfer_top_level_export('itm', to_jsonb(items))
from items where inventory_id IN (select id from pg_temp.export_data where kind = 'inv');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'ActorInventory', _character_transfer_top_level_export('ActorInventory', to_jsonb(actor_inventories))
from actor_inventories where inventory_id IN (select id from pg_temp.export_data where kind = 'inv');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'VehicleModuleInventory',
_character_transfer_top_level_export('VehicleModuleInventory', to_jsonb(vehicle_module_inventories))
from vehicle_module_inventories where inventory_id IN (select id from pg_temp.export_data where kind = 'inv');
-- Base backups (related actors are already added in the actors section)
insert into pg_temp.export_data("id", "kind", "data")
select null, 'Building', _character_transfer_top_level_export('Building', to_jsonb(buildings))
from buildings where id in (select id from pg_temp.export_data where kind = 'act');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'BuildingInstance', _character_transfer_top_level_export('BuildingInstance', to_jsonb(building_instances))
from building_instances where building_id in (select id from pg_temp.export_data where kind = 'act');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'Placeable', _character_transfer_top_level_export('Placeable', to_jsonb(placeables))
from placeables where id in (select id from pg_temp.export_data where kind = 'act');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'Totem', _character_transfer_top_level_export('Totem', to_jsonb(totems))
from totems where id in (select id from pg_temp.export_data where kind = 'act');
insert into pg_temp.export_data("id", "kind", "data")
select id, 'BaseBackup', _character_transfer_top_level_export('BaseBackup', to_jsonb(base_backups))
from base_backups where player_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select id, 'BaseBackupLinkedActor', _character_transfer_top_level_export('BaseBackupLinkedActor', to_jsonb(base_backup_linked_actors))
from base_backup_linked_actors where id IN (
select id from pg_temp.export_data where kind='BaseBackup'
);
insert into pg_temp.export_data("id", "kind", "data")
select null, 'LandclaimSegment', _character_transfer_top_level_export('LandclaimSegment', to_jsonb(landclaim_segments))
from landclaim_segments where totem_id IN (
select id from pg_temp.export_data where kind='act'
);
insert into pg_temp.export_data("id", "kind", "data")
select id, 'TaxInvoice', _character_transfer_top_level_export('TaxInvoice', to_jsonb(tax_invoice))
from tax_invoice where totem_id IN (
select id from pg_temp.export_data where kind='act'
);
-- Other stuff
insert into pg_temp.export_data("id", "kind", "data")
select id, 'Faction', _character_transfer_top_level_export('Faction', to_jsonb(factions))
from factions;
insert into pg_temp.export_data("id", "kind", "data")
select id, 'Tutorial', _character_transfer_top_level_export('Tutorial', to_jsonb(tutorials))
from tutorials where id IN (select distinct tutorial_id from tutorial_per_player where player_id=v_player_controller_id);
insert into pg_temp.export_data("id", "kind", "data")
select id, 'Keystone', _character_transfer_top_level_export('Keystone', to_jsonb(specialization_keystones_map))
from specialization_keystones_map where id IN (select distinct keystone_id from purchased_specialization_keystones where player_id=v_player_controller_id);
insert into pg_temp.export_data("id", "kind", "data")
select null, 'RespawnLocation',
_character_transfer_top_level_export('RespawnLocation', to_jsonb(player_respawn_locations))
|| jsonb_build_object('id', gen_random_uuid())
-- TODO: add default to id and just delete it by filter
from player_respawn_locations
where account_id=v_acc_id and "group" = ANY('{PlayerStart,Checkpoint,CheckpointSafe}');
insert into pg_temp.export_data("kind", "data")
select 'Character', _character_transfer_top_level_export('Character', to_jsonb(player_state) - 'last_avatar_activity' - 'reconnect_grace_period_end' - 'previous_server_partition_id')
from player_state where player_state.account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'PlayerMarker', _character_transfer_top_level_export('PlayerMarker', to_jsonb(player_markers))
from player_markers join markers using (marker_hash_id, dimension_index, map_name_id) join map_names using (map_name_id)
where dimension_index=-1 and player_id=v_player_controller_id and map_name <> 'DeepDesert'
and ((marker).payload_type <> 'EMarkerPayloadType::Default' or ((marker).payload_type = 'EMarkerPayloadType::Default' and (marker).marker_type like 'FlourSand%'));
insert into pg_temp.export_data("id", "kind", "data")
select null, 'Marker', _character_transfer_top_level_export('Marker', to_jsonb(markers))
from markers join player_markers using (marker_hash_id, dimension_index, map_name_id) join map_names using (map_name_id)
where dimension_index=-1 and player_id=v_player_controller_id and map_name <> 'DeepDesert'
and ((marker).payload_type <> 'EMarkerPayloadType::Default' or ((marker).payload_type = 'EMarkerPayloadType::Default' and (marker).marker_type like 'FlourSand%'));
insert into pg_temp.export_data("id", "kind", "data")
select null, 'DialogueMetNpc', _character_transfer_top_level_export('DialogueMetNpc', to_jsonb(dialogue_met_npcs))
from dialogue_met_npcs where player_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'DialogueTakenNode', _character_transfer_top_level_export('DialogueTakenNode', to_jsonb(dialogue_taken_nodes))
from dialogue_taken_nodes where player_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'PlayerFaction', _character_transfer_top_level_export('PlayerFaction', to_jsonb(player_faction))
from player_faction where actor_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'PlayerFactionReputation', _character_transfer_top_level_export('PlayerFactionReputation', to_jsonb(player_faction_reputation))
from player_faction_reputation where actor_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'ConsumedLore', _character_transfer_top_level_export('ConsumedLore', to_jsonb(consumed_per_player_lore))
from consumed_per_player_lore where actor_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'PlayerTutorial', _character_transfer_top_level_export('PlayerTutorial', to_jsonb(tutorial_per_player))
from tutorial_per_player where player_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'PurchasedKeystone', _character_transfer_top_level_export('PurchasedKeystone', to_jsonb(purchased_specialization_keystones))
from purchased_specialization_keystones where player_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'SpecializationTracks', _character_transfer_top_level_export('SpecializationTracks', to_jsonb(specialization_tracks))
from specialization_tracks where player_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'SpecializationRefund', _character_transfer_top_level_export('SpecializationRefund', to_jsonb(specialization_refund_id))
from specialization_refund_id where player_id=v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'BuildingFavorite', _character_transfer_top_level_export('BuildingFavorite', to_jsonb(building_favorites))
from building_favorites where account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'BuildingProgression', _character_transfer_top_level_export('BuildingProgression', to_jsonb(building_progression))
from building_progression where account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'CommuninetPlayer', _character_transfer_top_level_export('CommuninetPlayer', to_jsonb(communinet_player))
from communinet_player where account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'CommuninetPlayerChannel', _character_transfer_top_level_export('CommuninetPlayerChannel', to_jsonb(communinet_player_channels))
from communinet_player_channels where account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'JourneyStoryNode', _character_transfer_top_level_export('JourneyStoryNode', to_jsonb(journey_story_node))
from journey_story_node where account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'MapArea', _character_transfer_top_level_export('MapArea', to_jsonb(map_areas))
from map_areas where account_id=v_acc_id and map_name <> 'DeepDesert';
insert into pg_temp.export_data("id", "kind", "data")
select null, 'PlayerAccessCode', _character_transfer_top_level_export('PlayerAccessCode', to_jsonb(player_access_codes))
from player_access_codes where account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'PlayerTag', _character_transfer_top_level_export('PlayerTag', to_jsonb(player_tags))
from player_tags where account_id=v_acc_id;
insert into pg_temp.export_data("id", "kind", "data")
select null, 'Sinkchart', _character_transfer_top_level_export('Sinkchart', to_jsonb(sinkcharts))
from sinkcharts where item_id IN (select id from pg_temp.export_data where kind='itm');
insert into pg_temp.export_data("id", "kind", "data")
select id, 'bbp', _character_transfer_top_level_export('bbp', to_jsonb(building_blueprints))
from building_blueprints where item_id IN (select id from pg_temp.export_data where kind='itm');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'BuildingBlueprintInstance', _character_transfer_top_level_export('BuildingBlueprintInstance', to_jsonb(building_blueprint_instances))
from building_blueprint_instances where building_blueprint_id IN (select id from pg_temp.export_data where kind='bbp');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'BuildingBlueprintPlaceable', _character_transfer_top_level_export('BuildingBlueprintPlaceable', to_jsonb(building_blueprint_placeables))
from building_blueprint_placeables where building_blueprint_id IN (select id from pg_temp.export_data where kind='bbp');
insert into pg_temp.export_data("id", "kind", "data")
select null, 'BuildingBlueprintPentashield', _character_transfer_top_level_export('BuildingBlueprintPentashield', to_jsonb(building_blueprint_pentashields))
from building_blueprint_pentashields where building_blueprint_id IN (select id from pg_temp.export_data where kind='bbp');
insert into pg_temp.export_data("id", "kind", "data")
select player_controller_id, 'PlayerVirtualCurrencyBalance', _character_transfer_top_level_export('PlayerVirtualCurrencyBalance', to_jsonb(player_virtual_currency_balances))
from player_virtual_currency_balances where player_controller_id = v_player_controller_id;
insert into pg_temp.export_data("id", "kind", "data")
select completion_id, 'DungeonCompletion', _character_transfer_top_level_export('DungeonCompletion', to_jsonb(dungeon_completion))
from dungeon_completion where completion_id IN (select completion_id from dungeon_completion_players where player_id = v_player_controller_id);
insert into pg_temp.export_data("id", "kind", "data")
select completion_id, 'DungeonCompletionPlayer', _character_transfer_top_level_export('DungeonCompletionPlayer', to_jsonb(dungeon_completion_players))
from dungeon_completion_players where player_id = v_player_controller_id;
insert into pg_temp.export_data("id","kind","data")
select null, 'LandsraadHouseRewards', _character_transfer_top_level_export('LandsraadHouseRewards', to_jsonb(landsraad_house_rewards))
from landsraad_house_rewards where player_id = v_player_controller_id;
update pg_temp.export_data set data=_character_transfer_replace_local_id_with_transfer_id_in_json(data, '');
return (select jsonb_build_object(
'_patches_checksum', (_character_transfer_get_patches_checksum()),
'funcom_id', (v_funcom_id),
'player_controller_id', (v_player_controller_id),
'entries', (_character_transfer_data_table_save())
));
END;
$function$

View File

@@ -0,0 +1,27 @@
-- character_transfer_get_unsaved_counts(in_fls_id text) -> TABLE(unsaved_bases_count bigint, unsaved_vehicles_count bigint)
-- oid: 58162 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.character_transfer_get_unsaved_counts(in_fls_id text)
RETURNS TABLE(unsaved_bases_count bigint, unsaved_vehicles_count bigint)
LANGUAGE plpgsql
AS $function$
DECLARE
v_acc_id BIGINT;
BEGIN
v_acc_id := (SELECT acc.id FROM encrypted_accounts acc WHERE acc.user = in_fls_id);
RETURN QUERY
WITH unbacked_bases AS (
SELECT COUNT(*) AS count
FROM get_unsaved_base_totem_ids_for_account(v_acc_id)
),
unsaved_vehicles AS (
SELECT COUNT(*) AS count
FROM get_unbacked_up_vehicle_ids_for_account(v_acc_id)
)
SELECT
ub.count AS unsaved_bases_count,
uv.count AS unsaved_vehicles_count
FROM unbacked_bases ub, unsaved_vehicles uv;
END
$function$

View File

@@ -0,0 +1,393 @@
-- character_transfer_import(in_data jsonb, in_fls_id text, in_character_name text) -> bigint
-- oid: 58163 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.character_transfer_import(in_data jsonb, in_fls_id text, in_character_name text)
RETURNS bigint
LANGUAGE plpgsql
AS $function$
DECLARE
v_checksum TEXT;
v_coriolis_seed BigInt;
v_transfer_coriolis_seed BigInt;
v_id BigInt;
v_kind _CharacterTransferEntryKind;
v_new_player_controller_id BigInt;
v_vehicle_ids BigInt[];
BEGIN
if not (select is_player_offline(in_fls_id)) then
raise exception 'sbRP2$ - Player must be Offline';
end if;
PERFORM delete_account(in_fls_id, 'incoming char transfer');
v_checksum := (select _character_transfer_get_patches_checksum());
IF NOT in_data->>'_patches_checksum' = v_checksum THEN
raise exception 'sb9R2$ - Patches checksum mismatch, expected: %, got: %', v_checksum, in_data->>'_patches_checksum';
END IF;
perform _character_transfer_create_data_table();
perform _character_transfer_data_table_load(in_data->'entries');
update pg_temp.export_data set data=_character_transfer_replace_transfer_id_with_local_id_in_json(data, '');
-- accounts
insert into encrypted_accounts
select (jsonb_populate_record(
null::encrypted_accounts,
_character_transfer_top_level_import(kind, data, id)
|| jsonb_build_object(
'encrypted_funcom_id', encrypt_user_data(in_data->>'funcom_id'),
'user', in_fls_id
)
)).*
from pg_temp.export_data
where kind = 'acc';
-- player and vehicle actors
insert into actors
select (jsonb_populate_record(null::actors, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'act';
insert into fgl_entities
select (jsonb_populate_record(null::fgl_entities, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'fgl';
insert into actor_fgl_entities
select (jsonb_populate_record(null::actor_fgl_entities, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'fgl';
insert into actor_state
select (jsonb_populate_record(null::actor_state, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'ActorState';
insert into permission_actor
select (jsonb_populate_record(null::permission_actor, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'PermissionActor';
insert into permission_actor_rank
select (jsonb_populate_record(null::permission_actor_rank, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'PermissionActorRank';
-- vehicle and vehicle modules
insert into vehicles
select (jsonb_populate_record(null::vehicles, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'Vehicle';
insert into vehicle_modules
select (jsonb_populate_record(null::vehicle_modules, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'VehicleModule';
-- You can VBT as co-owner, but then there will be no owner in target BG. This is a state that permission system doesn't support.
-- So for backed up vehicles we also update the players ownership so they are now set as owner.
WITH inserted_backup_vehicles AS (
INSERT INTO backup_vehicles
SELECT (jsonb_populate_record(null::backup_vehicles, _character_transfer_top_level_import(kind, data, id))).*
FROM pg_temp.export_data
WHERE kind = 'BackupVehicle'
RETURNING vehicle_id
)
SELECT array_agg(vehicle_id) INTO v_vehicle_ids FROM inserted_backup_vehicles;
perform _character_transfer_ensure_player_is_owner_of_vbt_vehicle(v_vehicle_ids);
insert into recovered_vehicles
select (jsonb_populate_record(null::recovered_vehicles, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'RecoveredVehicle';
-- inventories and items
insert into inventories
select (jsonb_populate_record(null::inventories, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data e
where kind = 'inv';
insert into items
select (jsonb_populate_record(null::items, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'itm';
insert into actor_inventories
select (jsonb_populate_record(null::actor_inventories, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'ActorInventory';
insert into vehicle_module_inventories
select (jsonb_populate_record(null::vehicle_module_inventories, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'VehicleModuleInventory';
-- Base backups
insert into buildings
select (jsonb_populate_record(null::buildings, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'Building';
insert into building_instances
select (jsonb_populate_record(null::building_instances, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'BuildingInstance';
insert into placeables
select (jsonb_populate_record(null::placeables, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'Placeable';
insert into totems
select (jsonb_populate_record(null::totems, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'Totem';
insert into base_backups
select (jsonb_populate_record(null::base_backups, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'BaseBackup';
insert into base_backup_linked_actors
select (jsonb_populate_record(null::base_backup_linked_actors, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'BaseBackupLinkedActor';
insert into landclaim_segments
select (jsonb_populate_record(null::landclaim_segments, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'LandclaimSegment';
insert into tax_invoice
select (jsonb_populate_record(null::tax_invoice, _character_transfer_top_level_import(kind, data, id))).*
from pg_temp.export_data
where kind = 'TaxInvoice';
-- other stuff
insert into encrypted_player_state
select (jsonb_populate_record(
null::encrypted_player_state,
_character_transfer_top_level_import(kind, data, id)
|| jsonb_build_object(
'encrypted_character_name', encrypt_user_data(in_character_name)
)
)).*
from pg_temp.export_data
where kind = 'Character'
returning player_controller_id into v_new_player_controller_id;
insert into player_respawn_locations
select (
jsonb_populate_record(null::player_respawn_locations, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'RespawnLocation';
insert into markers
select (
jsonb_populate_record(null::markers, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'Marker'
on conflict ("marker_hash_id", "dimension_index", "map_name_id") do nothing;
insert into player_markers
select (
jsonb_populate_record(null::player_markers, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PlayerMarker';
insert into dialogue_met_npcs
select (
jsonb_populate_record(null::dialogue_met_npcs, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'DialogueMetNpc';
insert into dialogue_taken_nodes
select (
jsonb_populate_record(null::dialogue_taken_nodes, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'DialogueTakenNode';
insert into player_faction
select (
jsonb_populate_record(null::player_faction, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PlayerFaction';
insert into player_faction_reputation
select (
jsonb_populate_record(null::player_faction_reputation, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PlayerFactionReputation';
insert into consumed_per_player_lore
select (
jsonb_populate_record(null::consumed_per_player_lore, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'ConsumedLore';
insert into tutorial_per_player
select (
jsonb_populate_record(null::tutorial_per_player, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PlayerTutorial';
insert into purchased_specialization_keystones
select (
jsonb_populate_record(null::purchased_specialization_keystones, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PurchasedKeystone';
insert into specialization_tracks
select (
jsonb_populate_record(null::specialization_tracks, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'SpecializationTracks';
insert into specialization_refund_id
select (
jsonb_populate_record(null::specialization_refund_id, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'SpecializationRefund';
insert into building_favorites
select (
jsonb_populate_record(null::building_favorites, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'BuildingFavorite';
insert into building_progression
select (
jsonb_populate_record(null::building_progression, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'BuildingProgression';
insert into communinet_player
select (
jsonb_populate_record(null::communinet_player, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'CommuninetPlayer';
insert into communinet_player_channels
select (
jsonb_populate_record(null::communinet_player_channels, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'CommuninetPlayerChannel';
insert into journey_story_node
select (
jsonb_populate_record(null::journey_story_node, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'JourneyStoryNode';
insert into map_areas
select (
jsonb_populate_record(null::map_areas, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'MapArea';
insert into player_access_codes
select (
jsonb_populate_record(null::player_access_codes, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PlayerAccessCode';
insert into player_tags
select (
jsonb_populate_record(null::player_tags, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PlayerTag';
insert into sinkcharts
select (
jsonb_populate_record(null::sinkcharts, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'Sinkchart';
insert into building_blueprints
select (
jsonb_populate_record(null::building_blueprints, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'bbp';
insert into building_blueprint_instances
select (
jsonb_populate_record(null::building_blueprint_instances, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'BuildingBlueprintInstance';
insert into building_blueprint_placeables
select (
jsonb_populate_record(null::building_blueprint_placeables, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'BuildingBlueprintPlaceable';
insert into building_blueprint_pentashields
select (
jsonb_populate_record(null::building_blueprint_pentashields, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'BuildingBlueprintPentashield';
insert into player_virtual_currency_balances
select (
jsonb_populate_record(null::player_virtual_currency_balances, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'PlayerVirtualCurrencyBalance';
insert into dungeon_completion
select (
jsonb_populate_record(null::dungeon_completion, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'DungeonCompletion';
insert into dungeon_completion_players
select (
jsonb_populate_record(null::dungeon_completion_players, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'DungeonCompletionPlayer';
insert into landsraad_house_rewards
select (
jsonb_populate_record(null::landsraad_house_rewards, _character_transfer_top_level_import(kind, data, id))
).*
from pg_temp.export_data
where kind = 'LandsraadHouseRewards';
PERFORM set_character_import_state(in_fls_id, 'Complete'::TransferImportState);
return v_new_player_controller_id;
END;
$function$

View File

@@ -0,0 +1,16 @@
-- cleanup_account_log_and_orphaned_actors() -> void
-- oid: 58171 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.cleanup_account_log_and_orphaned_actors()
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
delete from actors
WHERE
-- not is null instead of is not null to match the index expression
not owner_account_id is null
AND NOT EXISTS(select 1 from accounts where id=owner_account_id);
truncate account_removal_log;
END
$function$

View File

@@ -0,0 +1,11 @@
-- cleanup_accounts_marked_for_deletion_in_fls(in_account_ids text[]) -> void
-- oid: 58172 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.cleanup_accounts_marked_for_deletion_in_fls(in_account_ids text[])
RETURNS void
LANGUAGE plpgsql
AS $function$
begin
perform delete_account(id, 'deleted in fls') from unnest(in_account_ids) as id;
end
$function$

View File

@@ -0,0 +1,48 @@
-- delete_account(in_user_id text, in_reason text) -> boolean
-- oid: 58198 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.delete_account(in_user_id text, in_reason text)
RETURNS boolean
LANGUAGE plpgsql
AS $function$
DECLARE
was_found Boolean;
BEGIN
WITH referenced_actor_ids as (
SELECT ARRAY[player_controller_id, player_pawn_id, player_state_id] as ids
FROM player_state ps JOIN accounts a ON (ps.account_id = a.id)
WHERE a.user = in_user_id
),
deleted_actors AS
(
DELETE FROM actors USING referenced_actor_ids WHERE id IN (SELECT id FROM actors WHERE id = ANY(referenced_actor_ids.ids) ORDER BY id FOR UPDATE) returning id
),
selected_respawn_beacons AS
(
SELECT player_respawn_locations.locator_actor_id FROM player_respawn_locations
INNER JOIN accounts ON accounts.id = player_respawn_locations.account_id
WHERE accounts.user = in_user_id AND player_respawn_locations.group = 'RespawnBeacon'
),
delete_respawn_beacons AS
(
DELETE FROM actors
WHERE actors.id IN (SELECT * FROM selected_respawn_beacons)
),
delete_accounts as (
DELETE FROM accounts WHERE accounts.user = in_user_id returning id as account_id
),
insert_into_removal_log as (
insert into account_removal_log("fls_id", "account_id", "reason") select in_user_id, account_id, in_reason from delete_accounts
),
delete_from_cascades as (
SELECT referenced_actor_ids.ids[1] as id,
guild_handle_actor_delete(referenced_actor_ids.ids[1]),
remove_party_member(referenced_actor_ids.ids[1], 0::SMALLINT),
ownership_handle_actor_delete(referenced_actor_ids.ids[1]),
perform_notify_on_character_delete(in_user_id)
FROM referenced_actor_ids
)
SELECT count(*) > 0 INTO was_found FROM delete_from_cascades;
return was_found;
END;
$function$

View File

@@ -0,0 +1,44 @@
-- get_character_transfer_related_items(in_fls_id text) -> jsonb
-- oid: 58293 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.get_character_transfer_related_items(in_fls_id text)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
BEGIN
RETURN (
WITH acct AS (
SELECT id
FROM accounts
WHERE "user" = in_FLS_ID
LIMIT 1
)
SELECT jsonb_build_object(
'items', COALESCE((
SELECT jsonb_agg(jsonb_build_object('name', sub.template_id, 'amount', sub.amount))
FROM (
SELECT i.template_id, SUM(i.stack_size) AS amount
FROM inventories inv
JOIN items i ON i.inventory_id = inv.id
JOIN player_state ps ON inv.actor_id = ps.player_pawn_id
WHERE ps.account_id = acct.id AND (
(inv.inventory_type = 0 AND i.template_id = 'SolarisCoin') OR
(i.template_id IN ('BaseBackupTool', 'VehicleBackupTool'))
)
GROUP BY i.template_id
) sub
), '[]'::jsonb),
'coin_balance', COALESCE((
SELECT vc.balance from player_virtual_currency_balances vc
JOIN player_state ps ON ps.account_id = acct.id
WHERE vc.currency_id = get_solaris_id()
AND vc.player_controller_id = ps.player_controller_id
LIMIT 1
), 0)
)
FROM acct
);
END
$function$

View File

@@ -0,0 +1,18 @@
-- get_unsaved_base_totem_ids_for_account(in_account_id bigint) -> TABLE(totem_id bigint)
-- oid: 58363 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.get_unsaved_base_totem_ids_for_account(in_account_id bigint)
RETURNS TABLE(totem_id bigint)
LANGUAGE plpgsql
AS $function$
BEGIN
RETURN QUERY
SELECT t.id
FROM totems t
JOIN permission_actor_rank par ON t.id = par.permission_actor_id
JOIN player_state ps ON par.player_id = ps.player_controller_id
LEFT JOIN base_backup_linked_actors bbla ON t.id = bbla.actor_id
WHERE ps.account_id = in_account_id
AND bbla.actor_id IS NULL;
END
$function$

View File

@@ -0,0 +1,26 @@
-- migrate_character(in_account_id bigint, home_dimension integer, max_solaris_allowed bigint) -> void
-- oid: 58476 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.migrate_character(in_account_id bigint, home_dimension integer, max_solaris_allowed bigint)
RETURNS void
LANGUAGE plpgsql
AS $function$
DECLARE
controller_id BIGINT;
pawn_id BIGINT;
BEGIN
SELECT player_controller_id, player_pawn_id into controller_id, pawn_id
FROM player_state ps
WHERE ps.account_id = in_account_id;
UPDATE encrypted_player_state SET home_dimension_index = home_dimension WHERE account_id = in_account_id;
UPDATE demo_users
SET demo_state = 'DbMigratedToRetail'::DemoState, demo_playtime_seconds = NULL
WHERE fls_id = (
SELECT acc.user FROM accounts AS acc WHERE acc.id = in_account_id
);
PERFORM migrate_clamp_max_allow_solaris(pawn_id, max_solaris_allowed);
END
$function$

View File

@@ -0,0 +1,29 @@
-- migrate_clamp_max_allow_solaris(in_pawn_id bigint, max_solaris_allowed bigint) -> void
-- oid: 58477 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.migrate_clamp_max_allow_solaris(in_pawn_id bigint, max_solaris_allowed bigint)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
with all_solaris_items as (
SELECT row_number() over (), i.id, i.stack_size FROM inventories inv
JOIN items i on i.inventory_id = inv.id
WHERE inv.actor_id = in_pawn_id AND inv.inventory_type = 0 AND i.template_id = 'SolarisCoin' -- inventory_type 0 is backpack
), total_solaris as (
SELECT sum(all_solaris_items.stack_size) as total
from all_solaris_items
), items_to_delete AS (
SELECT array_agg(id) AS item_ids
FROM all_solaris_items
WHERE row_number > 1
), deleted_items AS (
SELECT delete_items(item_ids)
FROM items_to_delete
)
UPDATE items
SET stack_size = LEAST(max_solaris_allowed, total_solaris.total)
FROM all_solaris_items, total_solaris, deleted_items
WHERE items.id = all_solaris_items.id AND all_solaris_items.row_number = 1;
END
$function$

View File

@@ -0,0 +1,11 @@
-- remove_character_transfer_state(in_fls_id text) -> void
-- oid: 58516 kind: FUNCTION category: transfer
CREATE OR REPLACE FUNCTION dune.remove_character_transfer_state(in_fls_id text)
RETURNS void
LANGUAGE plpgsql
AS $function$
BEGIN
DELETE FROM character_transfer_imports WHERE fls_id = in_fls_id;
END;
$function$